token-goat 2.9.19 → 2.9.21
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 +3 -1
- package/dist/{token-goat-chunk-JNIFSVWM.mjs → token-goat-chunk-2ZHD3XCD.mjs} +5 -1
- package/dist/{token-goat-chunk-P46RTOAQ.mjs → token-goat-chunk-4IIU3GNS.mjs} +10 -7
- package/dist/{token-goat-chunk-2GTB5RBZ.mjs → token-goat-chunk-4V4OZHHV.mjs} +11 -271
- package/dist/token-goat-chunk-64OEF3UN.mjs +128 -0
- package/dist/{token-goat-chunk-AVRD7SBO.mjs → token-goat-chunk-6AQLZMCO.mjs} +270 -29
- package/dist/{token-goat-chunk-LACH3WKS.mjs → token-goat-chunk-BIEDTF6V.mjs} +3 -3
- package/dist/{token-goat-chunk-PIAESKVU.mjs → token-goat-chunk-BKHJRFDE.mjs} +568 -429
- package/dist/token-goat-chunk-CAHN4QU7.mjs +26 -0
- package/dist/{token-goat-chunk-MU6I4IDI.mjs → token-goat-chunk-CMAJGP3E.mjs} +11 -7
- package/dist/token-goat-chunk-CMHBTXMY.mjs +41 -0
- package/dist/{token-goat-chunk-HPMMLV37.mjs → token-goat-chunk-CZ5ZFJSN.mjs} +256 -341
- package/dist/{token-goat-chunk-7DGTVBWP.mjs → token-goat-chunk-DDP64XR7.mjs} +159 -1863
- package/dist/{token-goat-chunk-FX5DHKGF.mjs → token-goat-chunk-DISVHOW6.mjs} +4 -4
- package/dist/{token-goat-chunk-L2UOJBV4.mjs → token-goat-chunk-FZN77SZD.mjs} +27 -19
- package/dist/{token-goat-chunk-DA6TIDLI.mjs → token-goat-chunk-GO7OWONJ.mjs} +18 -13
- package/dist/{token-goat-chunk-EP7TCWHM.mjs → token-goat-chunk-IAMIQLCV.mjs} +83 -66
- package/dist/{token-goat-chunk-NJKNAC37.mjs → token-goat-chunk-IJUHQX2M.mjs} +1 -1
- package/dist/token-goat-chunk-KQI24O4B.mjs +292 -0
- package/dist/{token-goat-chunk-GYC34EGE.mjs → token-goat-chunk-KRPJIXCT.mjs} +2 -2
- package/dist/token-goat-chunk-KVAXTA2W.mjs +198 -0
- package/dist/{token-goat-chunk-FJZ5MZK7.mjs → token-goat-chunk-LK3YOKDF.mjs} +2 -2
- package/dist/token-goat-chunk-M43UJVYQ.mjs +1816 -0
- package/dist/{token-goat-chunk-SOKAPOOC.mjs → token-goat-chunk-M6CDVASA.mjs} +46 -47
- package/dist/token-goat-chunk-MECDAPXB.mjs +1989 -0
- package/dist/token-goat-chunk-MEKVJZUN.mjs +324 -0
- package/dist/token-goat-chunk-MQACN7VG.mjs +1379 -0
- package/dist/{token-goat-chunk-3W5P673V.mjs → token-goat-chunk-MZQORUX5.mjs} +1 -1
- package/dist/{token-goat-chunk-DHIXE6GV.mjs → token-goat-chunk-ORRDWKLA.mjs} +1 -1
- package/dist/{token-goat-chunk-F24NE3FO.mjs → token-goat-chunk-PCR43MCM.mjs} +2 -2
- package/dist/token-goat-chunk-PDYQA3AP.mjs +248 -0
- package/dist/{token-goat-chunk-S7RFIX4Y.mjs → token-goat-chunk-PHDNWISV.mjs} +45 -14
- package/dist/token-goat-chunk-PPYZS7TI.mjs +304 -0
- package/dist/{token-goat-chunk-BTKDZW7F.mjs → token-goat-chunk-QTIRVK3M.mjs} +1 -1
- package/dist/{token-goat-chunk-62VJ47WN.mjs → token-goat-chunk-QUM3UNWS.mjs} +5 -5
- package/dist/{token-goat-chunk-KWM6KBPA.mjs → token-goat-chunk-SHV6QQAS.mjs} +1 -1
- package/dist/{token-goat-chunk-FQYMZASI.mjs → token-goat-chunk-SMUYPBF5.mjs} +796 -4464
- package/dist/{token-goat-chunk-ZGQXRYKE.mjs → token-goat-chunk-TGBSMHPM.mjs} +1 -1
- package/dist/{token-goat-chunk-EXLLLIC3.mjs → token-goat-chunk-VXKT3W4C.mjs} +3 -3
- package/dist/{token-goat-chunk-WKO5TVNA.mjs → token-goat-chunk-XJUPKJF5.mjs} +544 -576
- package/dist/{token-goat-chunk-IBTFGZBX.mjs → token-goat-chunk-XQSSPX3X.mjs} +2 -2
- package/dist/{token-goat-chunk-VJQBYSXG.mjs → token-goat-chunk-ZJWPJL7O.mjs} +3 -3
- package/dist/token-goat-hook.mjs +17 -11
- package/dist/token-goat.core.mjs +27 -19
- package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
- package/docs/cli.md +13 -12
- package/docs/install.md +1 -1
- package/docs/security.md +2 -2
- package/package.json +3 -2
- package/dist/token-goat-chunk-NYFYIRG3.mjs +0 -35
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
canRunWrappedShell,
|
|
6
6
|
clipToDeliveryCap,
|
|
7
7
|
deliveredOutputBytes
|
|
8
|
-
} from "./token-goat-chunk-
|
|
8
|
+
} from "./token-goat-chunk-CMAJGP3E.mjs";
|
|
9
9
|
import {
|
|
10
10
|
DEFAULT_RECONCILE_BUDGET_MS,
|
|
11
11
|
HOOK_EVENTS,
|
|
@@ -17,29 +17,33 @@ import {
|
|
|
17
17
|
flattenCommandNames,
|
|
18
18
|
getWebOutput,
|
|
19
19
|
isReconcileClean,
|
|
20
|
-
projectTranscriptsDir,
|
|
21
20
|
readStdinJson,
|
|
22
21
|
reconcileProject,
|
|
23
22
|
storeWebOutput
|
|
24
|
-
} from "./token-goat-chunk-
|
|
23
|
+
} from "./token-goat-chunk-4V4OZHHV.mjs";
|
|
24
|
+
import {
|
|
25
|
+
projectTranscriptsDir
|
|
26
|
+
} from "./token-goat-chunk-KQI24O4B.mjs";
|
|
27
|
+
import {
|
|
28
|
+
BUDGET_ESCALATION_MARKER,
|
|
29
|
+
MANIFEST_PREAMBLE,
|
|
30
|
+
MANIFEST_RECOVERY_PREAMBLE,
|
|
31
|
+
buildManifest,
|
|
32
|
+
manifestPrintedPaths,
|
|
33
|
+
summaryBudgetDirective
|
|
34
|
+
} from "./token-goat-chunk-PDYQA3AP.mjs";
|
|
25
35
|
import {
|
|
26
36
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
27
|
-
GENERIC_SERVED_OUTPUT_KEY,
|
|
28
37
|
OUTLINE_MAX_REPLACEMENT_RATIO,
|
|
29
38
|
OUTLINE_MIN_HEADINGS,
|
|
30
39
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
31
|
-
WEB_FETCH_KEY_SEP,
|
|
32
|
-
accumulateResidentLines,
|
|
33
40
|
appendDirtyPath,
|
|
34
41
|
applyHintTracking,
|
|
35
42
|
buildDeltaCapsule,
|
|
36
43
|
buildProjectMap,
|
|
37
44
|
classifyBashHint,
|
|
38
45
|
classifyEditHint,
|
|
39
|
-
claudeConfigDir,
|
|
40
|
-
clearCurlDownload,
|
|
41
46
|
compactPathFor,
|
|
42
|
-
computeAdaptiveBudget,
|
|
43
47
|
contextOutput,
|
|
44
48
|
denyOutput,
|
|
45
49
|
emitRewrite,
|
|
@@ -47,8 +51,6 @@ import {
|
|
|
47
51
|
enqueueDirtyPathSafe,
|
|
48
52
|
ensureWorkerAlive,
|
|
49
53
|
escapeHintName,
|
|
50
|
-
estimateTokens,
|
|
51
|
-
extractCompactFromMarker,
|
|
52
54
|
extractToolResponseField,
|
|
53
55
|
extractToolResultText,
|
|
54
56
|
fenceUntrusted,
|
|
@@ -59,43 +61,19 @@ import {
|
|
|
59
61
|
foldingEnabled,
|
|
60
62
|
formatProjectMap,
|
|
61
63
|
formatShrinkSummary,
|
|
62
|
-
getBashOutputId,
|
|
63
|
-
getContextPressure,
|
|
64
|
-
getCurlDownloadPath,
|
|
65
64
|
getCwd,
|
|
66
|
-
getFileLineRanges,
|
|
67
65
|
getFilePath,
|
|
68
|
-
getFileServedOutputs,
|
|
69
|
-
getGlobMatchCount,
|
|
70
|
-
getGrepMatchCount,
|
|
71
|
-
getOutstandingAgentSpawns,
|
|
72
|
-
getSessionBashOutputs,
|
|
73
|
-
getSessionBashReruns,
|
|
74
|
-
getSessionFiles,
|
|
75
|
-
getSessionWebFetches,
|
|
76
66
|
getToolInput,
|
|
77
67
|
getToolName,
|
|
78
68
|
getTranscriptPath,
|
|
79
|
-
hasSeenImage,
|
|
80
|
-
hasSessionOutput,
|
|
81
69
|
imageQualifiesForShrink,
|
|
82
|
-
incrementSkillHit,
|
|
83
70
|
indexServedBody,
|
|
84
|
-
installedSkillPath,
|
|
85
71
|
isMcpErrorResponse,
|
|
86
72
|
isStructuralRewriteAccepted,
|
|
87
73
|
isTextualContentBlock,
|
|
88
|
-
lastTabContextMatches,
|
|
89
|
-
lineMayCarryResidentSignal,
|
|
90
|
-
listSiblingSessionStates,
|
|
91
|
-
loadSessionCache,
|
|
92
|
-
loadSessionState,
|
|
93
74
|
logSuppressedDetection,
|
|
94
75
|
makeDedupHintHandlers,
|
|
95
76
|
markCompactStale,
|
|
96
|
-
markCompacted,
|
|
97
|
-
markFileTruncated,
|
|
98
|
-
markHintShown,
|
|
99
77
|
matchesAllowPattern,
|
|
100
78
|
matchesDenyPattern,
|
|
101
79
|
mcpContentBlocks,
|
|
@@ -108,8 +86,53 @@ import {
|
|
|
108
86
|
planSourceSkeleton,
|
|
109
87
|
preToolPathDeclined,
|
|
110
88
|
probeImageMeta,
|
|
111
|
-
|
|
112
|
-
|
|
89
|
+
recordKnownRootThrottled,
|
|
90
|
+
registerHook,
|
|
91
|
+
resolveLineRegions,
|
|
92
|
+
runHook,
|
|
93
|
+
scanAndRecord,
|
|
94
|
+
serializeOutput,
|
|
95
|
+
servedRunNotice,
|
|
96
|
+
sessionStateKey,
|
|
97
|
+
shrinkImage,
|
|
98
|
+
visionTokens,
|
|
99
|
+
visionTokensSaved,
|
|
100
|
+
vscodePathAllowed,
|
|
101
|
+
withPreservedBlocks
|
|
102
|
+
} from "./token-goat-chunk-SMUYPBF5.mjs";
|
|
103
|
+
import {
|
|
104
|
+
compressOutput,
|
|
105
|
+
detectFromCommand,
|
|
106
|
+
filterByName,
|
|
107
|
+
isRewriteWorthwhile,
|
|
108
|
+
looksLikePytestOutput,
|
|
109
|
+
pytestFilter,
|
|
110
|
+
resolveMinNetSavingsBytes
|
|
111
|
+
} from "./token-goat-chunk-DDP64XR7.mjs";
|
|
112
|
+
import {
|
|
113
|
+
readCopilotHooksOwners
|
|
114
|
+
} from "./token-goat-chunk-MQACN7VG.mjs";
|
|
115
|
+
import {
|
|
116
|
+
GENERIC_SERVED_OUTPUT_KEY,
|
|
117
|
+
clearCurlDownload,
|
|
118
|
+
extractCompactFromMarker,
|
|
119
|
+
getBashOutputId,
|
|
120
|
+
getCurlDownloadPath,
|
|
121
|
+
getFileLineRanges,
|
|
122
|
+
getFileServedOutputs,
|
|
123
|
+
getGlobMatchCount,
|
|
124
|
+
getGrepMatchCount,
|
|
125
|
+
getOutstandingAgentSpawns,
|
|
126
|
+
getSessionBashOutputs,
|
|
127
|
+
hasSeenImage,
|
|
128
|
+
hasSessionOutput,
|
|
129
|
+
incrementSkillHit,
|
|
130
|
+
installedSkillPath,
|
|
131
|
+
lastTabContextMatches,
|
|
132
|
+
loadSessionState,
|
|
133
|
+
markCompacted,
|
|
134
|
+
markFileTruncated,
|
|
135
|
+
markHintShown,
|
|
113
136
|
recordBashOutput,
|
|
114
137
|
recordBashRerun,
|
|
115
138
|
recordCliRead,
|
|
@@ -120,47 +143,38 @@ import {
|
|
|
120
143
|
recordFileServedOutput,
|
|
121
144
|
recordGlobQuery,
|
|
122
145
|
recordGrepQuery,
|
|
123
|
-
recordKnownRootThrottled,
|
|
124
146
|
recordOutstandingAgentSpawn,
|
|
125
147
|
recordScheduledPrompt,
|
|
126
148
|
recordSeenImage,
|
|
127
149
|
recordSymbolRead,
|
|
128
150
|
recordWebFetch,
|
|
129
|
-
registerHook,
|
|
130
151
|
removeOutstandingAgentSpawn,
|
|
131
|
-
repeatedSkillBodyHint,
|
|
132
|
-
resolveLineRegions,
|
|
133
|
-
runHook,
|
|
134
152
|
saveSessionState,
|
|
135
|
-
scanAndRecord,
|
|
136
|
-
serializeOutput,
|
|
137
|
-
servedRunNotice,
|
|
138
153
|
sessionOutputBodyBytes,
|
|
139
154
|
sessionSidecarPath,
|
|
140
|
-
sessionStateKey,
|
|
141
155
|
setLastTabContext,
|
|
142
156
|
setTranscriptPath,
|
|
143
|
-
shrinkImage,
|
|
144
157
|
storeOutput,
|
|
145
|
-
summarizeResidentContext,
|
|
146
158
|
takePendingLargeFileHint,
|
|
147
|
-
taskListPruneHint,
|
|
148
|
-
visionTokens,
|
|
149
|
-
visionTokensSaved,
|
|
150
|
-
vscodePathAllowed,
|
|
151
159
|
wasCliReadThisSession,
|
|
152
160
|
wasFileReadThisSession,
|
|
153
|
-
wasHintShown
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
wasHintShown
|
|
162
|
+
} from "./token-goat-chunk-MECDAPXB.mjs";
|
|
163
|
+
import {
|
|
164
|
+
accumulateResidentLines,
|
|
165
|
+
claudeConfigDir,
|
|
166
|
+
estimateTokens,
|
|
167
|
+
lineMayCarryResidentSignal,
|
|
168
|
+
readTranscriptTail,
|
|
169
|
+
repeatedSkillBodyHint,
|
|
170
|
+
summarizeResidentContext,
|
|
171
|
+
taskListPruneHint
|
|
172
|
+
} from "./token-goat-chunk-MEKVJZUN.mjs";
|
|
156
173
|
import {
|
|
157
174
|
BASH_OUTPUT_SUBDIR,
|
|
158
175
|
bashOutputIdSync,
|
|
159
176
|
commandHash,
|
|
160
|
-
compressOutput,
|
|
161
177
|
dedupeConsecutive,
|
|
162
|
-
detectFromCommand,
|
|
163
|
-
filterByName,
|
|
164
178
|
getBashOutput,
|
|
165
179
|
getMonitoringRecallHint,
|
|
166
180
|
hasBareBackgroundOrNewline,
|
|
@@ -168,39 +182,36 @@ import {
|
|
|
168
182
|
indexRecallEntry,
|
|
169
183
|
isBashEntryStale,
|
|
170
184
|
isBuildCommand,
|
|
171
|
-
|
|
185
|
+
isRedirectAmpersand,
|
|
172
186
|
isScopedGitStatusOrDiffStatCommand,
|
|
173
187
|
isTestRunnerCommand,
|
|
174
|
-
looksLikePytestOutput,
|
|
175
188
|
pathStem,
|
|
176
|
-
pytestFilter,
|
|
177
|
-
resolveMinNetSavingsBytes,
|
|
178
189
|
shlexSplit,
|
|
179
190
|
splitOwnTrailingNotices,
|
|
180
191
|
storeBashOutput,
|
|
181
192
|
summarizeOutputDelta
|
|
182
|
-
} from "./token-goat-chunk-
|
|
193
|
+
} from "./token-goat-chunk-M43UJVYQ.mjs";
|
|
183
194
|
import {
|
|
184
195
|
recordStat,
|
|
185
196
|
redactSecrets,
|
|
186
197
|
savedTokensFromBytes,
|
|
187
198
|
storeBlob,
|
|
188
199
|
stripAnsiEscapes
|
|
189
|
-
} from "./token-goat-chunk-
|
|
200
|
+
} from "./token-goat-chunk-PHDNWISV.mjs";
|
|
190
201
|
import {
|
|
191
202
|
extractMarkdownHeadings,
|
|
192
203
|
formatHeadingTreeParts
|
|
193
|
-
} from "./token-goat-chunk-
|
|
204
|
+
} from "./token-goat-chunk-IAMIQLCV.mjs";
|
|
194
205
|
import {
|
|
195
206
|
countSymbols,
|
|
196
207
|
getFileEntry,
|
|
197
208
|
querySymbols
|
|
198
|
-
} from "./token-goat-chunk-
|
|
209
|
+
} from "./token-goat-chunk-XQSSPX3X.mjs";
|
|
199
210
|
import {
|
|
200
211
|
detectLanguage,
|
|
201
212
|
getDb,
|
|
202
213
|
languageHasFlag
|
|
203
|
-
} from "./token-goat-chunk-
|
|
214
|
+
} from "./token-goat-chunk-2ZHD3XCD.mjs";
|
|
204
215
|
import {
|
|
205
216
|
detectHarness,
|
|
206
217
|
envBool,
|
|
@@ -211,7 +222,7 @@ import {
|
|
|
211
222
|
isUnderSystemTemp,
|
|
212
223
|
loadConfig,
|
|
213
224
|
shortFingerprint
|
|
214
|
-
} from "./token-goat-chunk-
|
|
225
|
+
} from "./token-goat-chunk-M6CDVASA.mjs";
|
|
215
226
|
import {
|
|
216
227
|
ENV_KEYS,
|
|
217
228
|
IDENTICAL_READ_MIN_BODY_BYTES,
|
|
@@ -231,7 +242,7 @@ import {
|
|
|
231
242
|
isInsideRoot,
|
|
232
243
|
runGit,
|
|
233
244
|
toKB
|
|
234
|
-
} from "./token-goat-chunk-
|
|
245
|
+
} from "./token-goat-chunk-TGBSMHPM.mjs";
|
|
235
246
|
import {
|
|
236
247
|
TOOL_RESULTS_ID_CHARS,
|
|
237
248
|
UNTRUSTED_TOOL_TAG,
|
|
@@ -292,6 +303,52 @@ function stripUnsafeSuggestions(text) {
|
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
305
|
|
|
306
|
+
// src/pending_context.ts
|
|
307
|
+
init_define_import_meta_env();
|
|
308
|
+
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
309
|
+
import { dirname } from "node:path";
|
|
310
|
+
var PENDING_SUFFIX = ".pending-context.txt";
|
|
311
|
+
var MAX_PENDING_CONTEXT_BYTES = 4096;
|
|
312
|
+
function queuePendingContext(stateKey, text) {
|
|
313
|
+
const trimmed = text.trim();
|
|
314
|
+
if (trimmed === "") return;
|
|
315
|
+
const target = sessionSidecarPath(stateKey, PENDING_SUFFIX);
|
|
316
|
+
if (target === null) return;
|
|
317
|
+
try {
|
|
318
|
+
const existing = readPending(target);
|
|
319
|
+
const merged = existing === null ? trimmed : `${existing}
|
|
320
|
+
${trimmed}`;
|
|
321
|
+
const capped = merged.length <= MAX_PENDING_CONTEXT_BYTES ? merged : merged.slice(merged.length - MAX_PENDING_CONTEXT_BYTES);
|
|
322
|
+
ensureDirSync(dirname(target));
|
|
323
|
+
writeFileSync(target, capped, "utf8");
|
|
324
|
+
} catch {
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function peekPendingContext(stateKey) {
|
|
328
|
+
const target = sessionSidecarPath(stateKey, PENDING_SUFFIX);
|
|
329
|
+
return target === null ? null : readPending(target);
|
|
330
|
+
}
|
|
331
|
+
function commitPendingContext(stateKey, delivered) {
|
|
332
|
+
if (delivered === null || delivered === "") return;
|
|
333
|
+
const target = sessionSidecarPath(stateKey, PENDING_SUFFIX);
|
|
334
|
+
if (target === null) return;
|
|
335
|
+
const queued = readPending(target);
|
|
336
|
+
if (queued === null) return;
|
|
337
|
+
if (!delivered.includes(queued) && !delivered.includes(stripUnsafeSuggestions(queued))) return;
|
|
338
|
+
try {
|
|
339
|
+
rmSync(target, { force: true });
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function readPending(target) {
|
|
344
|
+
try {
|
|
345
|
+
const raw = readFileSync(target, "utf8").trim();
|
|
346
|
+
return raw === "" ? null : raw;
|
|
347
|
+
} catch {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
295
352
|
// src/vscode_duplicate.ts
|
|
296
353
|
init_define_import_meta_env();
|
|
297
354
|
import * as fs from "node:fs";
|
|
@@ -647,7 +704,9 @@ function postEditHandlerInner(event) {
|
|
|
647
704
|
editedSize = statSync2(normalized).size;
|
|
648
705
|
} catch {
|
|
649
706
|
}
|
|
650
|
-
if (meetsSavingsFloor(editedSize)) {
|
|
707
|
+
if (!meetsSavingsFloor(editedSize)) {
|
|
708
|
+
logSuppressedDetection("edit_reread_suggest", event.sessionId, normalized);
|
|
709
|
+
} else {
|
|
651
710
|
const escapedPath = displaySafePath(normalized).replace(/`/g, "\\`").replace(/"/g, '\\"');
|
|
652
711
|
return contextOutput(
|
|
653
712
|
displaySafePath(editedBasename) + ' was edited. Use `token-goat section "' + escapedPath + '::HeadingName"` to re-read a specific section rather than the full file.'
|
|
@@ -666,7 +725,7 @@ registerHook("post_tool_use", postEditHandler, { toolName: "NotebookEdit" });
|
|
|
666
725
|
|
|
667
726
|
// src/hooks_write.ts
|
|
668
727
|
init_define_import_meta_env();
|
|
669
|
-
import { readFileSync, statSync as statSync3 } from "node:fs";
|
|
728
|
+
import { readFileSync as readFileSync2, statSync as statSync3 } from "node:fs";
|
|
670
729
|
var MAX_LINES_FOR_DIFF = 4e3;
|
|
671
730
|
var MAX_OLD_FILE_BYTES_FOR_DIFF = 4 * 1024 * 1024;
|
|
672
731
|
function splitLines(text) {
|
|
@@ -707,7 +766,7 @@ function preWriteRewriteHandler(event) {
|
|
|
707
766
|
if (stat.size > MAX_OLD_FILE_BYTES_FOR_DIFF) return passOutput();
|
|
708
767
|
let oldContent;
|
|
709
768
|
try {
|
|
710
|
-
oldContent =
|
|
769
|
+
oldContent = readFileSync2(filePath, "utf-8");
|
|
711
770
|
} catch {
|
|
712
771
|
return passOutput();
|
|
713
772
|
}
|
|
@@ -733,210 +792,48 @@ registerHook("pre_tool_use", preWriteRewriteHandler, { toolName: "Write" });
|
|
|
733
792
|
|
|
734
793
|
// src/hooks_compact.ts
|
|
735
794
|
init_define_import_meta_env();
|
|
736
|
-
import { spawnSync } from "node:child_process";
|
|
737
795
|
import * as path3 from "node:path";
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
for (const row of rows.slice(0, cap)) lines.push(row);
|
|
745
|
-
if (rows.length > cap) lines.push(`- ...and ${rows.length - cap} more`);
|
|
746
|
-
}
|
|
747
|
-
function renderReadRow(entry) {
|
|
748
|
-
const kb = Math.max(1, toKB(entry.sizeBytes));
|
|
749
|
-
const plural = entry.readCount === 1 ? "read" : "reads";
|
|
750
|
-
const edited = entry.wasEdited ? ", edited" : "";
|
|
751
|
-
return `- ${displaySafePath(entry.path)} (${kb}kb, ${entry.readCount} ${plural}${edited})`;
|
|
752
|
-
}
|
|
753
|
-
function renderSymbolReadRow(entry) {
|
|
754
|
-
return `- ${displaySafePath(entry.path)} (symbols: ${(entry.symbols_read ?? []).map(displaySafeText).join(", ")})`;
|
|
755
|
-
}
|
|
756
|
-
function mergeManifestFiles(parent, siblingFiles) {
|
|
757
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
758
|
-
for (const f of parent) byPath.set(foldPath(f.path), f);
|
|
759
|
-
for (const f of siblingFiles) {
|
|
760
|
-
const key = foldPath(f.path);
|
|
761
|
-
const prev = byPath.get(key);
|
|
762
|
-
if (prev === void 0) {
|
|
763
|
-
byPath.set(key, f);
|
|
764
|
-
continue;
|
|
765
|
-
}
|
|
766
|
-
const mergedSymbols = [.../* @__PURE__ */ new Set([...prev.symbols_read ?? [], ...f.symbols_read ?? []])];
|
|
767
|
-
byPath.set(key, {
|
|
768
|
-
path: prev.path,
|
|
769
|
-
readCount: Math.max(prev.readCount, f.readCount),
|
|
770
|
-
lastReadAt: Math.max(prev.lastReadAt, f.lastReadAt),
|
|
771
|
-
wasEdited: prev.wasEdited || f.wasEdited,
|
|
772
|
-
sizeBytes: f.lastReadAt >= prev.lastReadAt ? f.sizeBytes : prev.sizeBytes,
|
|
773
|
-
...prev.wasTruncated || f.wasTruncated ? { wasTruncated: true } : {},
|
|
774
|
-
...mergedSymbols.length > 0 ? { symbols_read: mergedSymbols } : {}
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
return Array.from(byPath.values());
|
|
778
|
-
}
|
|
779
|
-
function buildManifest(sessionId, cwd, transcriptPath) {
|
|
780
|
-
const ownFiles = [...getSessionFiles().values()];
|
|
781
|
-
const siblingFiles = sessionId !== void 0 ? listSiblingSessionStates(sessionId).flatMap((s) => s.files) : [];
|
|
782
|
-
const files = siblingFiles.length > 0 ? mergeManifestFiles(ownFiles, siblingFiles) : ownFiles;
|
|
783
|
-
const editedFiles = files.filter((f) => f.wasEdited);
|
|
784
|
-
const readFiles = files.filter((f) => f.readCount > 0 && !f.wasEdited);
|
|
785
|
-
const symbolOnlyFiles = files.filter((f) => f.readCount === 0 && !f.wasEdited && (f.symbols_read?.length ?? 0) > 0);
|
|
786
|
-
const webFetches = [...getSessionWebFetches().entries()];
|
|
787
|
-
const lines = [];
|
|
788
|
-
lines.push("## Session context");
|
|
789
|
-
lines.push(`Files read: ${readFiles.length}`);
|
|
790
|
-
lines.push(`Files edited: ${editedFiles.length}`);
|
|
791
|
-
appendCappedSection(lines, "### Read files", readFiles.map(renderReadRow), MAX_ROWS);
|
|
792
|
-
appendCappedSection(
|
|
793
|
-
lines,
|
|
794
|
-
"### Edited files",
|
|
795
|
-
editedFiles.map((entry) => `- ${displaySafePath(entry.path)}`),
|
|
796
|
-
MAX_ROWS
|
|
797
|
-
);
|
|
798
|
-
appendCappedSection(lines, "### Surgically read files (symbol/section reads, never read whole)", symbolOnlyFiles.map(renderSymbolReadRow), MAX_ROWS);
|
|
799
|
-
appendCappedSection(
|
|
800
|
-
lines,
|
|
801
|
-
"### Web URLs fetched",
|
|
802
|
-
webFetches.map(([key, cacheId]) => {
|
|
803
|
-
const [url = key, prompt = ""] = key.split(WEB_FETCH_KEY_SEP);
|
|
804
|
-
const promptSuffix = prompt ? `, prompt: ${neutralizeSpokenMarkers(JSON.stringify(prompt))}` : "";
|
|
805
|
-
return `- ${displaySafeText(url)} (cacheId: ${cacheId}${promptSuffix})`;
|
|
806
|
-
}),
|
|
807
|
-
MAX_ROWS
|
|
808
|
-
);
|
|
809
|
-
lines.push(...buildSafeToDiscardSection(files));
|
|
810
|
-
lines.push(...buildMemEpochSection());
|
|
811
|
-
return capManifestChars(lines.join("\n"), sessionId, cwd, transcriptPath);
|
|
812
|
-
}
|
|
813
|
-
function gitDirtySignals(cwd) {
|
|
814
|
-
const timeoutMs = loadConfig().hints.git_hint_max_ms;
|
|
815
|
-
let hasPendingDiff = false;
|
|
816
|
-
try {
|
|
817
|
-
const diffResult = runGit(["diff", "--no-color", "--stat", "HEAD"], { cwd, timeoutMs });
|
|
818
|
-
hasPendingDiff = diffResult.exitCode === 0 && diffResult.stdout.trim() !== "";
|
|
819
|
-
} catch {
|
|
820
|
-
}
|
|
821
|
-
let hasUncommittedChanges = false;
|
|
822
|
-
try {
|
|
823
|
-
const statusResult = runGit(["status", "--porcelain"], { cwd, timeoutMs });
|
|
824
|
-
hasUncommittedChanges = statusResult.exitCode === 0 && statusResult.stdout.trim() !== "";
|
|
825
|
-
} catch {
|
|
826
|
-
}
|
|
827
|
-
return { hasPendingDiff, hasUncommittedChanges };
|
|
828
|
-
}
|
|
829
|
-
function adaptiveCharBonus(sessionId, cwd, transcriptPath) {
|
|
830
|
-
if (!cwd) return 0;
|
|
831
|
-
const cache = loadSessionCache(sessionId ?? "") ?? {};
|
|
832
|
-
const ageSecs = cache.created_ts !== void 0 ? Math.max(0, Date.now() / 1e3 - cache.created_ts) : 0;
|
|
833
|
-
const contextPressure = getContextPressure(cache, transcriptPath);
|
|
834
|
-
const { hasPendingDiff, hasUncommittedChanges } = gitDirtySignals(cwd);
|
|
835
|
-
if (!hasPendingDiff && !hasUncommittedChanges) return 0;
|
|
836
|
-
const baseline = computeAdaptiveBudget(cache, ageSecs, { contextPressure });
|
|
837
|
-
const withGitSignal = computeAdaptiveBudget(cache, ageSecs, { hasPendingDiff, hasUncommittedChanges, contextPressure });
|
|
838
|
-
const deltaTokens = Math.max(0, withGitSignal - baseline);
|
|
839
|
-
return deltaTokens * 3;
|
|
840
|
-
}
|
|
841
|
-
function capManifestChars(manifest, sessionId, cwd, transcriptPath) {
|
|
842
|
-
const cap = loadConfig().compact_assist.max_manifest_chars;
|
|
843
|
-
if (cap <= 0) return manifest;
|
|
844
|
-
if (manifest.length <= cap) return manifest;
|
|
845
|
-
const effectiveCap = cap + adaptiveCharBonus(sessionId, cwd, transcriptPath);
|
|
846
|
-
if (manifest.length <= effectiveCap) return manifest;
|
|
847
|
-
const omitted = manifest.length - effectiveCap;
|
|
848
|
-
return manifest.slice(0, effectiveCap) + `
|
|
849
|
-
...(manifest truncated at ${effectiveCap} chars; ${omitted} chars omitted)`;
|
|
850
|
-
}
|
|
851
|
-
function buildSafeToDiscardSection(files) {
|
|
852
|
-
const rerunHashes = getSessionBashReruns();
|
|
853
|
-
const bashOutputs = getSessionBashOutputs();
|
|
854
|
-
const rerunHashSet = new Set(rerunHashes);
|
|
855
|
-
const rerunRows = [];
|
|
856
|
-
for (const hash of rerunHashes) {
|
|
857
|
-
const id = bashOutputs.find(([h]) => h === hash)?.[1];
|
|
858
|
-
if (id === void 0) continue;
|
|
859
|
-
const entry = getBashOutput(id);
|
|
860
|
-
if (entry === null) continue;
|
|
861
|
-
const flatCommand = neutralizeSpokenMarkers(entry.command.replace(/[\t\r\n]+/g, " "));
|
|
862
|
-
rerunRows.push("- `" + flatCommand + "` \u2014 an older run of this exact command was superseded; recall the surviving copy with `bash-output " + id + " --full`");
|
|
863
|
-
}
|
|
864
|
-
const supersededReadRows = [];
|
|
865
|
-
for (const f of files) {
|
|
866
|
-
if (f.readCount > 1 || f.wasEdited) {
|
|
867
|
-
const reason = f.wasEdited ? "edited after being read" : "re-read " + f.readCount + "x";
|
|
868
|
-
supersededReadRows.push("- " + displaySafePath(f.path) + " (" + reason + " \u2014 only the latest content already in context is current)");
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
const cachedOutputRows = [];
|
|
872
|
-
for (const [hash, id] of bashOutputs) {
|
|
873
|
-
if (rerunHashSet.has(hash)) continue;
|
|
874
|
-
const entry = getBashOutput(id);
|
|
875
|
-
if (entry === null) continue;
|
|
876
|
-
const flatCommand = neutralizeSpokenMarkers(entry.command.replace(/[\t\r\n]+/g, " "));
|
|
877
|
-
cachedOutputRows.push("- `" + flatCommand + "` \u2014 recallable via `bash-output " + id + " --full`");
|
|
878
|
-
}
|
|
879
|
-
const total = rerunRows.length + supersededReadRows.length + cachedOutputRows.length;
|
|
880
|
-
if (total === 0) return [];
|
|
881
|
-
const lines = [];
|
|
882
|
-
lines.push("");
|
|
883
|
-
lines.push("### SAFE_TO_DISCARD (" + total + " items \u2014 provably inert; each is recallable, not gone)");
|
|
884
|
-
appendCappedSection(lines, "Superseded reruns (" + rerunRows.length + "):", rerunRows, MAX_ROWS);
|
|
885
|
-
appendCappedSection(lines, "Superseded file reads (" + supersededReadRows.length + "):", supersededReadRows, MAX_ROWS);
|
|
886
|
-
appendCappedSection(lines, "Other cached bash outputs (" + cachedOutputRows.length + "):", cachedOutputRows, MAX_ROWS);
|
|
887
|
-
return lines;
|
|
796
|
+
|
|
797
|
+
// src/harness_channels.ts
|
|
798
|
+
init_define_import_meta_env();
|
|
799
|
+
var PROMPT_SUBMIT_CONTEXT_DROPPED = /* @__PURE__ */ new Set([]);
|
|
800
|
+
function dropsPromptSubmitContext() {
|
|
801
|
+
return PROMPT_SUBMIT_CONTEXT_DROPPED.has(getHarnessName());
|
|
888
802
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
result = spawnSync("mem", ["epoch"], {
|
|
893
|
-
encoding: "utf-8",
|
|
894
|
-
timeout: MEM_EPOCH_TIMEOUT_MS,
|
|
895
|
-
windowsHide: true
|
|
896
|
-
});
|
|
897
|
-
} catch {
|
|
898
|
-
return [];
|
|
899
|
-
}
|
|
900
|
-
if (result.error !== void 0 || result.status !== 0) return [];
|
|
901
|
-
const stdout = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
902
|
-
if (!/^\d+$/.test(stdout)) return [];
|
|
903
|
-
return [
|
|
904
|
-
"",
|
|
905
|
-
"### mem epoch",
|
|
906
|
-
`mem epoch: ${stdout} (no live TGMEM block is tracked in this session -- only the epoch counter is folded in; see buildMemEpochSection's doc comment)`
|
|
907
|
-
];
|
|
908
|
-
}
|
|
909
|
-
var MANIFEST_PREAMBLE = "When summarizing this session, keep the file paths and symbol names below exactly as written -- they are the handles the next turn needs to resume work. Do not paraphrase them into prose.";
|
|
910
|
-
var BUDGET_ESCALATION_MARKER = "TG-BUDGET-ESCALATION:";
|
|
911
|
-
function summaryBudgetDirective(budgetChars) {
|
|
912
|
-
if (budgetChars <= 0) return "";
|
|
913
|
-
return ` Aim for at most ${budgetChars} characters. Prefer a shorter summary that keeps every path, symbol, command and decision over a longer one that reproduces tool output verbatim: cite the recall id (\`token-goat bash-output <id> --full\`) rather than quoting the output again. If this session genuinely cannot be summarized within that target without losing state the next turn needs, exceed it and open the summary with a single line reading \`${BUDGET_ESCALATION_MARKER} <one-sentence reason>\`.`;
|
|
803
|
+
var PRE_COMPACT_CONTEXT_DROPPED = /* @__PURE__ */ new Set(["copilot_cli", "codex"]);
|
|
804
|
+
function dropsPreCompactContext() {
|
|
805
|
+
return PRE_COMPACT_CONTEXT_DROPPED.has(getHarnessName());
|
|
914
806
|
}
|
|
807
|
+
|
|
808
|
+
// src/hooks_compact.ts
|
|
915
809
|
function preCompactHandler(event) {
|
|
916
|
-
const
|
|
810
|
+
const cfg = loadConfig().compact_assist;
|
|
811
|
+
let out = passOutput();
|
|
812
|
+
if (cfg.enabled) {
|
|
813
|
+
const manifest = buildManifest(event.sessionId, getCwd(event), getTranscriptPath(event));
|
|
814
|
+
if (!dropsPreCompactContext()) {
|
|
815
|
+
out = contextOutput(`${MANIFEST_PREAMBLE}${summaryBudgetDirective(cfg.summary_budget_chars)}
|
|
816
|
+
|
|
817
|
+
${manifest}`);
|
|
818
|
+
} else if (event.sessionId) {
|
|
819
|
+
queuePendingContext(sessionStateKey(event), `${MANIFEST_RECOVERY_PREAMBLE}
|
|
917
820
|
|
|
918
|
-
${
|
|
821
|
+
${manifest.slice(0, MAX_PENDING_CONTEXT_BYTES - MANIFEST_RECOVERY_PREAMBLE.length - 2)}`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
919
824
|
markCompacted();
|
|
920
825
|
return out;
|
|
921
826
|
}
|
|
922
827
|
registerHook("pre_compact", preCompactHandler);
|
|
923
828
|
var MANIFEST_SURVIVAL_SAMPLE = 64;
|
|
924
|
-
function manifestPathSample(
|
|
925
|
-
|
|
926
|
-
const siblingFiles = sessionId !== void 0 ? listSiblingSessionStates(sessionId).flatMap((s) => s.files) : [];
|
|
927
|
-
const files = siblingFiles.length > 0 ? mergeManifestFiles(ownFiles, siblingFiles) : ownFiles;
|
|
928
|
-
const seen = /* @__PURE__ */ new Set();
|
|
929
|
-
for (const entry of files) {
|
|
930
|
-
if (entry.path) seen.add(entry.path);
|
|
931
|
-
if (seen.size >= MANIFEST_SURVIVAL_SAMPLE) break;
|
|
932
|
-
}
|
|
933
|
-
return [...seen];
|
|
829
|
+
function manifestPathSample(event) {
|
|
830
|
+
return manifestPrintedPaths(event.sessionId, MANIFEST_SURVIVAL_SAMPLE, getCwd(event), getTranscriptPath(event));
|
|
934
831
|
}
|
|
935
832
|
function postCompactHandler(event) {
|
|
936
833
|
const raw = event.raw["compact_summary"];
|
|
937
834
|
const summary = typeof raw === "string" ? raw : "";
|
|
938
835
|
const bytes = Buffer.byteLength(summary, "utf-8");
|
|
939
|
-
const sample = manifestPathSample(event
|
|
836
|
+
const sample = typeof raw === "string" ? manifestPathSample(event) : [];
|
|
940
837
|
const cwd = normalizePath(getCwd(event) ?? process.cwd());
|
|
941
838
|
const spell = (p) => foldPath(p.replaceAll("\\", "/"));
|
|
942
839
|
const haystack = spell(summary);
|
|
@@ -969,7 +866,7 @@ init_define_import_meta_env();
|
|
|
969
866
|
var TRACKED_SKILL = "token-goat";
|
|
970
867
|
var MAX_COMMANDS_SHOWN = 8;
|
|
971
868
|
async function currentCommandNames() {
|
|
972
|
-
const { buildProgram } = await import("./token-goat-chunk-
|
|
869
|
+
const { buildProgram } = await import("./token-goat-chunk-FZN77SZD.mjs");
|
|
973
870
|
return flattenCommandNames(buildCommandManifest(buildProgram()));
|
|
974
871
|
}
|
|
975
872
|
async function recordSkillVersionSnapshot(sessionId, skillName) {
|
|
@@ -1021,55 +918,11 @@ async function checkSkillVersionDrift(sessionId) {
|
|
|
1021
918
|
}
|
|
1022
919
|
}
|
|
1023
920
|
|
|
1024
|
-
// src/pending_context.ts
|
|
1025
|
-
init_define_import_meta_env();
|
|
1026
|
-
import { readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync } from "node:fs";
|
|
1027
|
-
import { dirname } from "node:path";
|
|
1028
|
-
var PENDING_SUFFIX = ".pending-context.txt";
|
|
1029
|
-
var MAX_PENDING_CONTEXT_BYTES = 4096;
|
|
1030
|
-
function queuePendingContext(sessionId, text) {
|
|
1031
|
-
const trimmed = text.trim();
|
|
1032
|
-
if (trimmed === "") return;
|
|
1033
|
-
const target = sessionSidecarPath(sessionId, PENDING_SUFFIX);
|
|
1034
|
-
if (target === null) return;
|
|
1035
|
-
try {
|
|
1036
|
-
const existing = readPending(target);
|
|
1037
|
-
const merged = existing === null ? trimmed : `${existing}
|
|
1038
|
-
${trimmed}`;
|
|
1039
|
-
const capped = merged.length <= MAX_PENDING_CONTEXT_BYTES ? merged : merged.slice(merged.length - MAX_PENDING_CONTEXT_BYTES);
|
|
1040
|
-
ensureDirSync(dirname(target));
|
|
1041
|
-
writeFileSync(target, capped, "utf8");
|
|
1042
|
-
} catch {
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
function drainPendingContext(sessionId) {
|
|
1046
|
-
const target = sessionSidecarPath(sessionId, PENDING_SUFFIX);
|
|
1047
|
-
if (target === null) return null;
|
|
1048
|
-
const text = readPending(target);
|
|
1049
|
-
try {
|
|
1050
|
-
rmSync2(target, { force: true });
|
|
1051
|
-
} catch {
|
|
1052
|
-
}
|
|
1053
|
-
return text;
|
|
1054
|
-
}
|
|
1055
|
-
function readPending(target) {
|
|
1056
|
-
try {
|
|
1057
|
-
const raw = readFileSync2(target, "utf8").trim();
|
|
1058
|
-
return raw === "" ? null : raw;
|
|
1059
|
-
} catch {
|
|
1060
|
-
return null;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
921
|
// src/hooks_session.ts
|
|
1065
|
-
var PROMPT_SUBMIT_CONTEXT_DROPPED = /* @__PURE__ */ new Set([]);
|
|
1066
|
-
function dropsPromptSubmitContext() {
|
|
1067
|
-
return PROMPT_SUBMIT_CONTEXT_DROPPED.has(getHarnessName());
|
|
1068
|
-
}
|
|
1069
922
|
function pendingContextHandler(event) {
|
|
1070
923
|
try {
|
|
1071
|
-
if (!event.sessionId || !dropsPromptSubmitContext()) return passOutput();
|
|
1072
|
-
const pending =
|
|
924
|
+
if (!event.sessionId || !dropsPromptSubmitContext() && !dropsPreCompactContext()) return passOutput();
|
|
925
|
+
const pending = peekPendingContext(sessionStateKey(event));
|
|
1073
926
|
return pending === null ? passOutput() : contextOutput(pending);
|
|
1074
927
|
} catch {
|
|
1075
928
|
return passOutput();
|
|
@@ -1177,7 +1030,7 @@ async function userPromptSubmitHandler(event) {
|
|
|
1177
1030
|
}
|
|
1178
1031
|
const text = lines.join("\n");
|
|
1179
1032
|
if (dropsPromptSubmitContext()) {
|
|
1180
|
-
queuePendingContext(event
|
|
1033
|
+
queuePendingContext(sessionStateKey(event), text);
|
|
1181
1034
|
return passOutput();
|
|
1182
1035
|
}
|
|
1183
1036
|
return contextOutput(text);
|
|
@@ -1280,9 +1133,20 @@ function reconcileNote(cwd, indexed) {
|
|
|
1280
1133
|
return null;
|
|
1281
1134
|
}
|
|
1282
1135
|
}
|
|
1283
|
-
function
|
|
1136
|
+
async function postCompactRecovery(event) {
|
|
1137
|
+
if (event.raw["source"] !== "compact" || event.sessionId === void 0) return null;
|
|
1138
|
+
if (!loadConfig().compact_assist.enabled) return null;
|
|
1284
1139
|
try {
|
|
1285
|
-
|
|
1140
|
+
const { buildResumePacket } = await import("./token-goat-chunk-CAHN4QU7.mjs");
|
|
1141
|
+
return await buildResumePacket(event.sessionId);
|
|
1142
|
+
} catch {
|
|
1143
|
+
return null;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async function sessionStartHandler(event) {
|
|
1147
|
+
const recovery = await postCompactRecovery(event);
|
|
1148
|
+
try {
|
|
1149
|
+
if (!loadConfig().hints.session_start_reminder) return recovery === null ? passOutput() : contextOutput(recovery);
|
|
1286
1150
|
const cwd = getCwd(event);
|
|
1287
1151
|
const indexed = isIndexedProject(cwd);
|
|
1288
1152
|
let context = buildReminder(indexed);
|
|
@@ -1303,9 +1167,12 @@ ${capsule}`;
|
|
|
1303
1167
|
}
|
|
1304
1168
|
} catch {
|
|
1305
1169
|
}
|
|
1170
|
+
if (recovery !== null) context += `
|
|
1171
|
+
|
|
1172
|
+
${recovery}`;
|
|
1306
1173
|
return contextOutput(context);
|
|
1307
1174
|
} catch {
|
|
1308
|
-
return passOutput();
|
|
1175
|
+
return recovery === null ? passOutput() : contextOutput(recovery);
|
|
1309
1176
|
}
|
|
1310
1177
|
}
|
|
1311
1178
|
registerHook("session_start", sessionStartHandler);
|
|
@@ -7690,6 +7557,18 @@ init_define_import_meta_env();
|
|
|
7690
7557
|
|
|
7691
7558
|
// src/bash_structural_index.ts
|
|
7692
7559
|
init_define_import_meta_env();
|
|
7560
|
+
|
|
7561
|
+
// src/index_freshness.ts
|
|
7562
|
+
init_define_import_meta_env();
|
|
7563
|
+
function indexMatchesDisk(resolved) {
|
|
7564
|
+
const entry = getFileEntry(resolved);
|
|
7565
|
+
if (entry === null) return false;
|
|
7566
|
+
if (entry.sha === "") return true;
|
|
7567
|
+
const diskSha = fingerprintFile(resolved);
|
|
7568
|
+
return diskSha !== null && diskSha === entry.sha;
|
|
7569
|
+
}
|
|
7570
|
+
|
|
7571
|
+
// src/bash_structural_index.ts
|
|
7693
7572
|
import { statSync as statSync4 } from "node:fs";
|
|
7694
7573
|
var ALLOWED_BINARIES = /* @__PURE__ */ new Set(["rg", "grep", "egrep", "fgrep"]);
|
|
7695
7574
|
var PY_DEF_RE = /^\^?(?:async\s+)?def\b(?:\s+([A-Za-z_]\w*))?$/;
|
|
@@ -7720,12 +7599,7 @@ function detectStructuralIndexRewrite(rawCmd, cwd) {
|
|
|
7720
7599
|
return null;
|
|
7721
7600
|
}
|
|
7722
7601
|
if (!stat.isFile()) return null;
|
|
7723
|
-
|
|
7724
|
-
if (entry === null) return null;
|
|
7725
|
-
if (entry.sha !== "") {
|
|
7726
|
-
const diskSha = fingerprintFile(resolved);
|
|
7727
|
-
if (diskSha === null || diskSha !== entry.sha) return null;
|
|
7728
|
-
}
|
|
7602
|
+
if (!indexMatchesDisk(resolved)) return null;
|
|
7729
7603
|
const pathArg = dualShellArg(rawPath);
|
|
7730
7604
|
if (pathArg === null) return null;
|
|
7731
7605
|
let target = null;
|
|
@@ -7773,12 +7647,7 @@ function rangeSubstituteFor(hintPath, cwd, ranges) {
|
|
|
7773
7647
|
try {
|
|
7774
7648
|
const resolved = resolveIndexPath(hintPath, cwd);
|
|
7775
7649
|
if (!statSync5(resolved).isFile()) return null;
|
|
7776
|
-
|
|
7777
|
-
if (entry === null) return null;
|
|
7778
|
-
if (entry.sha !== "") {
|
|
7779
|
-
const diskSha = fingerprintFile(resolved);
|
|
7780
|
-
if (diskSha === null || diskSha !== entry.sha) return null;
|
|
7781
|
-
}
|
|
7650
|
+
if (!indexMatchesDisk(resolved)) return null;
|
|
7782
7651
|
const lines = readFileSync3(resolved, "utf8").split("\n");
|
|
7783
7652
|
const symbols = querySymbols({ filePath: resolved, limit: ALL_SYMBOLS_IN_FILE });
|
|
7784
7653
|
if (symbols.length === 0) return null;
|
|
@@ -7850,6 +7719,10 @@ function splitShellSegments(cmd) {
|
|
|
7850
7719
|
i++;
|
|
7851
7720
|
continue;
|
|
7852
7721
|
}
|
|
7722
|
+
if (ch === "&" && isRedirectAmpersand(cmd, i)) {
|
|
7723
|
+
cur += ch;
|
|
7724
|
+
continue;
|
|
7725
|
+
}
|
|
7853
7726
|
if (ch === "|" || ch === ";" || ch === "\n" || ch === "&") {
|
|
7854
7727
|
segments.push(cur);
|
|
7855
7728
|
cur = "";
|
|
@@ -7900,6 +7773,7 @@ function classifyCatPath(filePath, cmd0) {
|
|
|
7900
7773
|
return { filePath, ...flags, cmd0 };
|
|
7901
7774
|
}
|
|
7902
7775
|
function extractCatFile(cmd) {
|
|
7776
|
+
if (/-(?:TotalCount|Head|First|Tail)\b/i.test(cmd)) return null;
|
|
7903
7777
|
const m = /^(cat|bat|type|Get-Content|gc)(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+(?:"([^"]+)"|'([^']+)'|(\S+?))(?:\s+-[a-zA-Z].*?)?(?:\s+2>(&1|\/dev\/null))?\s*$/i.exec(cmd);
|
|
7904
7778
|
if (!m) return null;
|
|
7905
7779
|
const cmd0 = m[1];
|
|
@@ -7940,6 +7814,7 @@ function extractPowerShellWrappedGetContent(cmd, event) {
|
|
|
7940
7814
|
if (!w) return null;
|
|
7941
7815
|
const inner = (w[1] ?? w[2] ?? "").trim();
|
|
7942
7816
|
if (!inner) return null;
|
|
7817
|
+
if (/-(?:TotalCount|Head|First|Tail)\b/i.test(inner)) return null;
|
|
7943
7818
|
const m = PS_GETCONTENT_INNER_RE.exec(inner);
|
|
7944
7819
|
if (!m) return null;
|
|
7945
7820
|
const filePath = m[1] ?? m[2] ?? m[3];
|
|
@@ -8464,6 +8339,25 @@ function extractGetContentSelectFirst(cmd) {
|
|
|
8464
8339
|
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8465
8340
|
return { filePath, isDoc, isConfig, isSql, isXml, n };
|
|
8466
8341
|
}
|
|
8342
|
+
function extractGetContentHead(cmd) {
|
|
8343
|
+
const headMatch = /-(?:TotalCount|Head|First)\s+(\d+)/i.exec(cmd);
|
|
8344
|
+
if (!headMatch) return null;
|
|
8345
|
+
const n = parseInt(headMatch[1], 10);
|
|
8346
|
+
if (n <= 10) return null;
|
|
8347
|
+
const getnMatch = /^(Get-Content|gc)\s+/i.exec(cmd);
|
|
8348
|
+
if (!getnMatch) return null;
|
|
8349
|
+
const afterCmd = cmd.slice(getnMatch[0].length).replace(/-Path\s+/i, "");
|
|
8350
|
+
const beforeHead = afterCmd.split(/-(?:TotalCount|Head|First)/i)[0]?.trim() ?? "";
|
|
8351
|
+
const afterHead = afterCmd.split(/-(?:TotalCount|Head|First)\s+\d+/i)[1]?.trim() ?? "";
|
|
8352
|
+
const cleanedBefore = beforeHead.replace(/-(?:Encoding|Delimiter|Wait)\s+\S+/gi, "").replace(/-[a-zA-Z]+/g, "").trim();
|
|
8353
|
+
const cleanedAfter = afterHead.replace(/-(?:Encoding|Delimiter|Wait)\s+\S+/gi, "").replace(/-[a-zA-Z]+/g, "").trim();
|
|
8354
|
+
const filePath = (cleanedBefore || cleanedAfter).replace(/^["']|["']$/g, "");
|
|
8355
|
+
if (!filePath) return null;
|
|
8356
|
+
if (isTempPath(filePath)) return null;
|
|
8357
|
+
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
|
|
8358
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8359
|
+
return { filePath, isDoc, isConfig, isSql, isXml, n };
|
|
8360
|
+
}
|
|
8467
8361
|
function taskOutputIsJsonlTranscript(outPath) {
|
|
8468
8362
|
let fd = null;
|
|
8469
8363
|
try {
|
|
@@ -8882,12 +8776,7 @@ function runnableTargetFor(hintPath, cwd, event) {
|
|
|
8882
8776
|
if (!commandPathIsTouchable(hintPath, event)) return null;
|
|
8883
8777
|
const resolved = resolveIndexPath(hintPath, cwd);
|
|
8884
8778
|
if (!statSync7(resolved).isFile()) return null;
|
|
8885
|
-
|
|
8886
|
-
if (entry === null) return null;
|
|
8887
|
-
if (entry.sha !== "") {
|
|
8888
|
-
const diskSha = fingerprintFile(resolved);
|
|
8889
|
-
if (diskSha === null || diskSha !== entry.sha) return null;
|
|
8890
|
-
}
|
|
8779
|
+
if (!indexMatchesDisk(resolved)) return null;
|
|
8891
8780
|
const symbols = querySymbols({ filePath: resolved, limit: ALL_SYMBOLS_IN_FILE2 });
|
|
8892
8781
|
if (symbols.length === 0) return null;
|
|
8893
8782
|
const inLineOrder = [...symbols].sort((a, b) => a.lineStart - b.lineStart);
|
|
@@ -9171,7 +9060,8 @@ function pipelineShapeFilter(cmd, cwd) {
|
|
|
9171
9060
|
}
|
|
9172
9061
|
}
|
|
9173
9062
|
if (recognizedCiCount > 0) {
|
|
9174
|
-
|
|
9063
|
+
const ci = filterByName("generic-ci");
|
|
9064
|
+
return ci === null ? null : { filter: ci, argv: [] };
|
|
9175
9065
|
}
|
|
9176
9066
|
}
|
|
9177
9067
|
return null;
|
|
@@ -9186,7 +9076,7 @@ function pipelineShapeFilter(cmd, cwd) {
|
|
|
9186
9076
|
if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
|
|
9187
9077
|
}
|
|
9188
9078
|
const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
|
|
9189
|
-
return detected === null ? null : detected.filter;
|
|
9079
|
+
return detected === null ? null : { filter: detected.filter, argv: detected.argv };
|
|
9190
9080
|
}
|
|
9191
9081
|
function isFullRecallCommand(cmd) {
|
|
9192
9082
|
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
@@ -9470,7 +9360,7 @@ function foldShellReadBodies(cmd, output, fileKey, cwd) {
|
|
|
9470
9360
|
if (no === void 0 || no === null) return null;
|
|
9471
9361
|
rows.push({ no, text: lines[i] ?? "", raw: lines[i] ?? "" });
|
|
9472
9362
|
}
|
|
9473
|
-
const headRead = extractHeadFile(cmd);
|
|
9363
|
+
const headRead = extractHeadFile(cmd) ?? extractGetContentHead(cmd);
|
|
9474
9364
|
const windowed = extractLineRangeRead(cmd) !== null || headRead !== null && lines.length >= headRead.n;
|
|
9475
9365
|
const folded = foldDelivery(rows, fileKey, displaySafePath(toDisplayPath(findProject(cwd ?? process.cwd())?.root, fileKey)), windowed);
|
|
9476
9366
|
if (folded === null) return null;
|
|
@@ -9599,10 +9489,12 @@ async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinB
|
|
|
9599
9489
|
}
|
|
9600
9490
|
if (!cfg.enabled || cfg.disabled_filters.includes("generic")) return null;
|
|
9601
9491
|
if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return null;
|
|
9602
|
-
const shaped = pipelineShapeFilter(cmd, cwd) ?? (isUnwrapped ? detectFromCommand(cmd, cwd ?? void 0)
|
|
9603
|
-
const
|
|
9492
|
+
const shaped = pipelineShapeFilter(cmd, cwd) ?? (isUnwrapped ? detectFromCommand(cmd, cwd ?? void 0) ?? null : null);
|
|
9493
|
+
const useShaped = shaped !== null && !cfg.disabled_filters.includes(shaped.filter.name);
|
|
9494
|
+
const filter3 = useShaped ? shaped.filter : filterByName("generic");
|
|
9604
9495
|
if (filter3 === null) return null;
|
|
9605
|
-
const
|
|
9496
|
+
const filterArgv = useShaped ? shaped.argv : [];
|
|
9497
|
+
const compressed = compressOutput(filter3, output, "", exitCode ?? 0, filterArgv, {
|
|
9606
9498
|
maxLines: cfg.max_lines,
|
|
9607
9499
|
maxBytes: cfg.max_bytes
|
|
9608
9500
|
});
|
|
@@ -9696,6 +9588,12 @@ function preBashHandlerInner(event) {
|
|
|
9696
9588
|
for (const p of typeof paths === "string" ? [paths] : paths) logSuppressedDetection("bash_redirect", event.sessionId, p);
|
|
9697
9589
|
return passOutput();
|
|
9698
9590
|
};
|
|
9591
|
+
const recallWorthShowing = (outputId2, entry2) => {
|
|
9592
|
+
if (entry2.sizeBytes < loadConfig().hints.bash_dedup_min_bytes) return false;
|
|
9593
|
+
if (meetsSavingsFloor(entry2.sizeBytes)) return true;
|
|
9594
|
+
logSuppressedDetection("bash_recall", event.sessionId, outputId2);
|
|
9595
|
+
return false;
|
|
9596
|
+
};
|
|
9699
9597
|
const cfg = loadConfig();
|
|
9700
9598
|
if (cfg.hints.warn_unbalanced_shell_quoting) {
|
|
9701
9599
|
const quoteError = detectUnbalancedShellSyntax(cmd);
|
|
@@ -9807,6 +9705,15 @@ function preBashHandlerInner(event) {
|
|
|
9807
9705
|
recordStat("session_hint", 0, 0);
|
|
9808
9706
|
return pathHint(hintPath, gcSelectHint);
|
|
9809
9707
|
}
|
|
9708
|
+
const gcHeadResult = extractGetContentHead(cmd);
|
|
9709
|
+
if (gcHeadResult !== null) {
|
|
9710
|
+
const { filePath, n } = gcHeadResult;
|
|
9711
|
+
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9712
|
+
const gcHeadHint = leadingLinesHint("`Get-Content -TotalCount` bypasses read hooks. ", hintPath, 1, n, preHookCwd, pricedSubstitute(hintPath, 1, n));
|
|
9713
|
+
if (gcHeadHint === null) return declineUnpriced(hintPath);
|
|
9714
|
+
recordStat("session_hint", 0, 0);
|
|
9715
|
+
return pathHint(hintPath, gcHeadHint);
|
|
9716
|
+
}
|
|
9810
9717
|
const catJsonPipe = extractCatJsonPipe(cmd);
|
|
9811
9718
|
if (catJsonPipe !== null) {
|
|
9812
9719
|
const { filePath, isDirectJq } = catJsonPipe;
|
|
@@ -9995,7 +9902,7 @@ function preBashHandlerInner(event) {
|
|
|
9995
9902
|
const monOutputId = getBashOutputId(monCmdHash);
|
|
9996
9903
|
const monEntryRaw = monOutputId !== null ? getBashOutput(monOutputId) : null;
|
|
9997
9904
|
const monEntry = monEntryRaw !== null && !isBashEntryStale(monEntryRaw, cmd, preHookCwd) ? monEntryRaw : null;
|
|
9998
|
-
if (monOutputId !== null && monEntry !== null &&
|
|
9905
|
+
if (monOutputId !== null && monEntry !== null && recallWorthShowing(monOutputId, monEntry)) {
|
|
9999
9906
|
const monBytes = monEntry.sizeBytes;
|
|
10000
9907
|
const catFile = extractCatSourceFile(cmd);
|
|
10001
9908
|
if (catFile !== null) {
|
|
@@ -10030,7 +9937,7 @@ function preBashHandlerInner(event) {
|
|
|
10030
9937
|
const curlOutputId = getBashOutputId(curlHash);
|
|
10031
9938
|
const curlEntryRaw = curlOutputId !== null ? getBashOutput(curlOutputId) : null;
|
|
10032
9939
|
const curlEntry = curlEntryRaw !== null && !isBashEntryStale(curlEntryRaw, cmd, preHookCwd) ? curlEntryRaw : null;
|
|
10033
|
-
if (curlOutputId !== null && curlEntry !== null &&
|
|
9940
|
+
if (curlOutputId !== null && curlEntry !== null && recallWorthShowing(curlOutputId, curlEntry)) {
|
|
10034
9941
|
const curlBytes = curlEntry.sizeBytes;
|
|
10035
9942
|
recordStat("bash_compress:recall", curlBytes, savedTokensFromBytes(curlBytes));
|
|
10036
9943
|
const curlPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
@@ -10044,7 +9951,7 @@ function preBashHandlerInner(event) {
|
|
|
10044
9951
|
const ghOutputId = getBashOutputId(ghHash);
|
|
10045
9952
|
const ghEntryRaw = ghOutputId !== null ? getBashOutput(ghOutputId) : null;
|
|
10046
9953
|
const ghEntry = ghEntryRaw !== null && !isBashEntryStale(ghEntryRaw, cmd, preHookCwd) ? ghEntryRaw : null;
|
|
10047
|
-
if (ghOutputId !== null && ghEntry !== null &&
|
|
9954
|
+
if (ghOutputId !== null && ghEntry !== null && recallWorthShowing(ghOutputId, ghEntry)) {
|
|
10048
9955
|
const ghBytes = ghEntry.sizeBytes;
|
|
10049
9956
|
recordStat("bash_compress:recall", ghBytes, savedTokensFromBytes(ghBytes));
|
|
10050
9957
|
const ghPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
@@ -10058,7 +9965,7 @@ function preBashHandlerInner(event) {
|
|
|
10058
9965
|
const gitScopedOutputId = getBashOutputId(gitScopedHash);
|
|
10059
9966
|
const gitScopedEntryRaw = gitScopedOutputId !== null ? getBashOutput(gitScopedOutputId) : null;
|
|
10060
9967
|
const gitScopedEntry = gitScopedEntryRaw !== null && !isBashEntryStale(gitScopedEntryRaw, cmd, preHookCwd) ? gitScopedEntryRaw : null;
|
|
10061
|
-
if (gitScopedOutputId !== null && gitScopedEntry !== null &&
|
|
9968
|
+
if (gitScopedOutputId !== null && gitScopedEntry !== null && recallWorthShowing(gitScopedOutputId, gitScopedEntry)) {
|
|
10062
9969
|
const gitScopedBytes = gitScopedEntry.sizeBytes;
|
|
10063
9970
|
recordStat("bash_compress:recall", gitScopedBytes, savedTokensFromBytes(gitScopedBytes));
|
|
10064
9971
|
const gitScopedPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
@@ -10100,7 +10007,7 @@ function preBashHandlerInner(event) {
|
|
|
10100
10007
|
const outputId = getBashOutputId(cmdHash);
|
|
10101
10008
|
const entryRaw = outputId !== null ? getBashOutput(outputId) : null;
|
|
10102
10009
|
const entry = entryRaw !== null && !isBashEntryStale(entryRaw, cmd, preHookCwd) ? entryRaw : null;
|
|
10103
|
-
if (outputId !== null && entry !== null &&
|
|
10010
|
+
if (outputId !== null && entry !== null && recallWorthShowing(outputId, entry)) {
|
|
10104
10011
|
const bytes = entry.sizeBytes;
|
|
10105
10012
|
recordStat("bash_compress:recall", bytes, savedTokensFromBytes(bytes));
|
|
10106
10013
|
return contextOutput(buildRecallHint(cmd, outputId));
|
|
@@ -10198,6 +10105,11 @@ function recordBashFileReadsForSessionCache(cmd, cwd) {
|
|
|
10198
10105
|
recordFileLineRange(resolve2(gcSelect.filePath), 1, gcSelect.n);
|
|
10199
10106
|
return;
|
|
10200
10107
|
}
|
|
10108
|
+
const gcHead = extractGetContentHead(cmd);
|
|
10109
|
+
if (gcHead !== null) {
|
|
10110
|
+
recordFileLineRange(resolve2(gcHead.filePath), 1, gcHead.n);
|
|
10111
|
+
return;
|
|
10112
|
+
}
|
|
10201
10113
|
const head = extractHeadFile(cmd);
|
|
10202
10114
|
if (head !== null) {
|
|
10203
10115
|
recordFileLineRange(resolve2(head.filePath), 1, head.n);
|
|
@@ -11926,6 +11838,9 @@ async function relayInProcess(eventName, rawPayload, harnessWaitMs) {
|
|
|
11926
11838
|
} catch {
|
|
11927
11839
|
}
|
|
11928
11840
|
const output = safeSuggestions(await runHook(event));
|
|
11841
|
+
if (event.sessionId) {
|
|
11842
|
+
commitPendingContext(stateKey, output.hookType === "context" ? output.context : null);
|
|
11843
|
+
}
|
|
11929
11844
|
try {
|
|
11930
11845
|
saveSessionState(stateKey);
|
|
11931
11846
|
} catch {
|