token-goat 2.9.13 → 2.9.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -1
- package/dist/token-goat-chunk-2X2EBBC6.mjs +277 -0
- package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
- package/dist/token-goat-chunk-3NSDDTGL.mjs +34 -0
- package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
- package/dist/token-goat-chunk-5V7DAC7V.mjs +123 -0
- package/dist/token-goat-chunk-6DLVZDB6.mjs +34 -0
- package/dist/token-goat-chunk-7ZYK25AO.mjs +24 -0
- package/dist/token-goat-chunk-A4JYKD5H.mjs +144 -0
- package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
- package/dist/token-goat-chunk-ASYEPR3S.mjs +212 -0
- package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-ATIFTMRC.mjs} +31 -13
- package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-BL5LNGBG.mjs} +3935 -11949
- package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-C5JIO6HK.mjs} +8 -4
- package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-DQ4J5AFF.mjs} +50 -18
- package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
- package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-GIIHUSZX.mjs} +142 -21
- package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
- package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-GMQQA7E4.mjs} +12576 -12326
- package/dist/token-goat-chunk-IVUQLQWN.mjs +2046 -0
- package/dist/token-goat-chunk-K7F2BFIK.mjs +2430 -0
- package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-LCZBPOIN.mjs} +10197 -9717
- package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
- package/dist/token-goat-chunk-LT7JRU6K.mjs +22 -0
- package/dist/token-goat-chunk-MZDIJJ3R.mjs +420 -0
- package/dist/token-goat-chunk-NDPO7GAH.mjs +177 -0
- package/dist/token-goat-chunk-NDRP4KJQ.mjs +4371 -0
- package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
- package/dist/token-goat-chunk-NU7TLMQK.mjs +585 -0
- package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
- package/dist/token-goat-chunk-OUGNPMDA.mjs +959 -0
- package/dist/token-goat-chunk-PM76YS22.mjs +1341 -0
- package/dist/token-goat-chunk-S4XRY446.mjs +2637 -0
- package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-SFAS46RE.mjs} +5 -3
- package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-SZWYESBS.mjs} +793 -650
- package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-XEPXYDPI.mjs} +3 -2
- package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
- package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
- package/dist/token-goat-chunk-YKG35VHC.mjs +228 -0
- package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-YQ7WI2CO.mjs} +990 -106
- package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-YZX7EFG4.mjs} +1 -1
- package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
- package/dist/token-goat-hook.mjs +16 -8
- package/dist/token-goat.core.mjs +27 -10
- package/docs/cli.md +9 -6
- package/package.json +4 -2
- package/dist/token-goat-chunk-FQCNJV4V.mjs +0 -693
- package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
- package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
- package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
- package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
- package/dist/token-goat-chunk-UMXJN7DI.mjs +0 -5521
|
@@ -4,31 +4,26 @@ import {
|
|
|
4
4
|
canRunWrappedShell,
|
|
5
5
|
clipToDeliveryCap,
|
|
6
6
|
deliveredOutputBytes
|
|
7
|
-
} from "./token-goat-chunk-
|
|
7
|
+
} from "./token-goat-chunk-YZX7EFG4.mjs";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_RECONCILE_BUDGET_MS,
|
|
10
10
|
HOOK_EVENTS,
|
|
11
|
-
accumulateResidentLines,
|
|
12
11
|
buildCommandManifest,
|
|
13
12
|
checkSymbolBodySize,
|
|
13
|
+
diagnoseSqlFailure,
|
|
14
14
|
flattenCommandNames,
|
|
15
15
|
getWebOutput,
|
|
16
16
|
isReconcileClean,
|
|
17
|
-
lineMayCarryResidentSignal,
|
|
18
17
|
readStdinJson,
|
|
19
|
-
readTranscriptTail,
|
|
20
18
|
reconcileProject,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
summarizeResidentContext,
|
|
24
|
-
taskListPruneHint
|
|
25
|
-
} from "./token-goat-chunk-FQCNJV4V.mjs";
|
|
19
|
+
storeWebOutput
|
|
20
|
+
} from "./token-goat-chunk-OUGNPMDA.mjs";
|
|
26
21
|
import {
|
|
27
|
-
BASH_OUTPUT_SUBDIR,
|
|
28
22
|
GENERIC_SERVED_OUTPUT_KEY,
|
|
29
23
|
OUTLINE_MAX_REPLACEMENT_RATIO,
|
|
30
24
|
OUTLINE_MIN_HEADINGS,
|
|
31
25
|
WEB_FETCH_KEY_SEP,
|
|
26
|
+
accumulateResidentLines,
|
|
32
27
|
appendDirtyPath,
|
|
33
28
|
applyHintTracking,
|
|
34
29
|
buildDeltaCapsule,
|
|
@@ -36,24 +31,19 @@ import {
|
|
|
36
31
|
classifyBashHint,
|
|
37
32
|
classifyEditHint,
|
|
38
33
|
clearCurlDownload,
|
|
39
|
-
commandHash,
|
|
40
34
|
compactPathFor,
|
|
41
35
|
computeAdaptiveBudget,
|
|
42
|
-
countSymbols,
|
|
43
36
|
enqueueDirtyPathSafe,
|
|
44
37
|
ensureWorkerAlive,
|
|
45
38
|
extractCompactFromMarker,
|
|
46
|
-
extractMarkdownHeadings,
|
|
47
39
|
fenceUntrusted,
|
|
48
40
|
fenceUntrustedSpans,
|
|
49
41
|
fenceWithMatches,
|
|
50
42
|
foldDelivery,
|
|
51
43
|
foldDetail,
|
|
52
44
|
foldingEnabled,
|
|
53
|
-
formatHeadingTreeParts,
|
|
54
45
|
formatProjectMap,
|
|
55
46
|
formatShrinkSummary,
|
|
56
|
-
getBashOutput,
|
|
57
47
|
getBashOutputId,
|
|
58
48
|
getContextPressure,
|
|
59
49
|
getCurlDownloadPath,
|
|
@@ -61,7 +51,6 @@ import {
|
|
|
61
51
|
getFileServedOutputs,
|
|
62
52
|
getGlobMatchCount,
|
|
63
53
|
getGrepMatchCount,
|
|
64
|
-
getMonitoringRecallHint,
|
|
65
54
|
getOutstandingAgentSpawns,
|
|
66
55
|
getSessionBashOutputs,
|
|
67
56
|
getSessionBashReruns,
|
|
@@ -71,15 +60,11 @@ import {
|
|
|
71
60
|
hasSessionOutput,
|
|
72
61
|
imageQualifiesForShrink,
|
|
73
62
|
incrementSkillHit,
|
|
74
|
-
indexRecallEntry,
|
|
75
63
|
indexServedBody,
|
|
76
64
|
installedSkillPath,
|
|
77
|
-
isBashEntryStale,
|
|
78
|
-
isBuildCommand,
|
|
79
|
-
isScopedGitStatusOrDiffStatCommand,
|
|
80
65
|
isStructuralRewriteAccepted,
|
|
81
|
-
isTestRunnerCommand,
|
|
82
66
|
lastTabContextMatches,
|
|
67
|
+
lineMayCarryResidentSignal,
|
|
83
68
|
listSiblingSessionStates,
|
|
84
69
|
loadSessionCache,
|
|
85
70
|
loadSessionState,
|
|
@@ -96,6 +81,7 @@ import {
|
|
|
96
81
|
planSourceSkeleton,
|
|
97
82
|
preToolPathDeclined,
|
|
98
83
|
probeImageMeta,
|
|
84
|
+
readTranscriptTail,
|
|
99
85
|
recordBashOutput,
|
|
100
86
|
recordBashRerun,
|
|
101
87
|
recordCliRead,
|
|
@@ -113,27 +99,31 @@ import {
|
|
|
113
99
|
recordSymbolRead,
|
|
114
100
|
recordWebFetch,
|
|
115
101
|
removeOutstandingAgentSpawn,
|
|
102
|
+
repeatedSkillBodyHint,
|
|
116
103
|
saveSessionState,
|
|
117
104
|
scanAndRecord,
|
|
118
105
|
servedRunNotice,
|
|
119
106
|
sessionOutputBodyBytes,
|
|
120
107
|
sessionSidecarPath,
|
|
121
108
|
setLastTabContext,
|
|
109
|
+
setTranscriptPath,
|
|
122
110
|
shrinkImage,
|
|
123
|
-
storeBashOutput,
|
|
124
111
|
storeOutput,
|
|
125
|
-
|
|
112
|
+
summarizeResidentContext,
|
|
126
113
|
takePendingLargeFileHint,
|
|
114
|
+
taskListPruneHint,
|
|
127
115
|
visionTokens,
|
|
128
116
|
visionTokensSaved,
|
|
129
117
|
vscodePathAllowed,
|
|
130
118
|
wasCliReadThisSession,
|
|
131
119
|
wasFileReadThisSession,
|
|
132
120
|
wasHintShown
|
|
133
|
-
} from "./token-goat-chunk-
|
|
121
|
+
} from "./token-goat-chunk-BL5LNGBG.mjs";
|
|
134
122
|
import {
|
|
123
|
+
BASH_OUTPUT_SUBDIR,
|
|
135
124
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
136
125
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
126
|
+
commandHash,
|
|
137
127
|
compressOutput,
|
|
138
128
|
contextOutput,
|
|
139
129
|
dedupeConsecutive,
|
|
@@ -145,14 +135,22 @@ import {
|
|
|
145
135
|
extractToolResponseField,
|
|
146
136
|
extractToolResultText,
|
|
147
137
|
filterByName,
|
|
138
|
+
getBashOutput,
|
|
148
139
|
getCwd,
|
|
149
140
|
getFilePath,
|
|
141
|
+
getMonitoringRecallHint,
|
|
150
142
|
getToolInput,
|
|
151
143
|
getToolName,
|
|
144
|
+
getTranscriptPath,
|
|
152
145
|
hasBareBackgroundOrNewline,
|
|
153
146
|
hasUnquotedOperator,
|
|
147
|
+
indexRecallEntry,
|
|
148
|
+
isBashEntryStale,
|
|
149
|
+
isBuildCommand,
|
|
154
150
|
isMcpErrorResponse,
|
|
155
151
|
isRewriteWorthwhile,
|
|
152
|
+
isScopedGitStatusOrDiffStatCommand,
|
|
153
|
+
isTestRunnerCommand,
|
|
156
154
|
isTextualContentBlock,
|
|
157
155
|
makeDedupHintHandlers,
|
|
158
156
|
mcpContentBlocks,
|
|
@@ -166,55 +164,68 @@ import {
|
|
|
166
164
|
sessionStateKey,
|
|
167
165
|
shlexSplit,
|
|
168
166
|
splitOwnTrailingNotices,
|
|
167
|
+
storeBashOutput,
|
|
168
|
+
summarizeOutputDelta,
|
|
169
169
|
withPreservedBlocks
|
|
170
|
-
} from "./token-goat-chunk-
|
|
170
|
+
} from "./token-goat-chunk-YQ7WI2CO.mjs";
|
|
171
|
+
import {
|
|
172
|
+
extractMarkdownHeadings,
|
|
173
|
+
formatHeadingTreeParts
|
|
174
|
+
} from "./token-goat-chunk-NDRP4KJQ.mjs";
|
|
171
175
|
import {
|
|
172
|
-
|
|
173
|
-
} from "./token-goat-chunk-
|
|
176
|
+
countSymbols
|
|
177
|
+
} from "./token-goat-chunk-2X2EBBC6.mjs";
|
|
178
|
+
import {
|
|
179
|
+
recordStat,
|
|
180
|
+
redactSecrets,
|
|
181
|
+
savedTokensFromBytes,
|
|
182
|
+
storeBlob,
|
|
183
|
+
stripAnsiEscapes
|
|
184
|
+
} from "./token-goat-chunk-IVUQLQWN.mjs";
|
|
174
185
|
import {
|
|
175
|
-
detectHarness,
|
|
176
186
|
detectLanguage,
|
|
187
|
+
getDb,
|
|
188
|
+
languageHasFlag
|
|
189
|
+
} from "./token-goat-chunk-K7F2BFIK.mjs";
|
|
190
|
+
import {
|
|
191
|
+
detectHarness,
|
|
177
192
|
envBool,
|
|
178
193
|
envInt,
|
|
179
194
|
findProject,
|
|
180
|
-
getDb,
|
|
181
195
|
getHarnessName,
|
|
182
196
|
isUnderSystemTemp,
|
|
183
|
-
languageHasFlag,
|
|
184
197
|
loadConfig,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
savedTokensFromBytes,
|
|
188
|
-
shortFingerprint,
|
|
189
|
-
stripAnsiEscapes
|
|
190
|
-
} from "./token-goat-chunk-UMXJN7DI.mjs";
|
|
198
|
+
shortFingerprint
|
|
199
|
+
} from "./token-goat-chunk-S4XRY446.mjs";
|
|
191
200
|
import {
|
|
192
201
|
ENV_KEYS,
|
|
193
202
|
IDENTICAL_READ_MIN_BODY_BYTES,
|
|
194
203
|
PER_FILE_COUNTERFACTUAL_CEILING,
|
|
195
|
-
UNTRUSTED_TOOL_TAG,
|
|
196
204
|
VERSION,
|
|
197
205
|
atomicWriteText,
|
|
198
206
|
containsLineRun,
|
|
199
207
|
countNoun,
|
|
200
208
|
dataDir,
|
|
201
|
-
displaySafePath,
|
|
202
|
-
displaySafeText,
|
|
203
209
|
ensureDirSync,
|
|
204
210
|
escapesOntoNetworkThroughLinks,
|
|
205
211
|
extractErrorMessage,
|
|
206
|
-
fenceUntrustedFileContent,
|
|
207
212
|
foldPath,
|
|
208
213
|
globalDbPath,
|
|
209
214
|
hasCreatedConfig,
|
|
210
215
|
isInsideRoot,
|
|
216
|
+
runGit,
|
|
217
|
+
toKB
|
|
218
|
+
} from "./token-goat-chunk-PM76YS22.mjs";
|
|
219
|
+
import {
|
|
220
|
+
UNTRUSTED_TOOL_TAG,
|
|
221
|
+
displaySafePath,
|
|
222
|
+
displaySafeText,
|
|
223
|
+
fenceUntrustedFileContent,
|
|
211
224
|
neutralizeSpokenMarkers,
|
|
212
225
|
normalizePath,
|
|
213
226
|
resolveIndexPath,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
toKB
|
|
217
|
-
} from "./token-goat-chunk-QKXBGBQR.mjs";
|
|
227
|
+
toDisplayPath
|
|
228
|
+
} from "./token-goat-chunk-ERTXEKB6.mjs";
|
|
218
229
|
import {
|
|
219
230
|
init_define_import_meta_env
|
|
220
231
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -747,7 +758,7 @@ function mergeManifestFiles(parent, siblingFiles) {
|
|
|
747
758
|
}
|
|
748
759
|
return Array.from(byPath.values());
|
|
749
760
|
}
|
|
750
|
-
function buildManifest(sessionId, cwd) {
|
|
761
|
+
function buildManifest(sessionId, cwd, transcriptPath) {
|
|
751
762
|
const ownFiles = [...getSessionFiles().values()];
|
|
752
763
|
const siblingFiles = sessionId !== void 0 ? listSiblingSessionStates(sessionId).flatMap((s) => s.files) : [];
|
|
753
764
|
const files = siblingFiles.length > 0 ? mergeManifestFiles(ownFiles, siblingFiles) : ownFiles;
|
|
@@ -779,7 +790,7 @@ function buildManifest(sessionId, cwd) {
|
|
|
779
790
|
);
|
|
780
791
|
lines.push(...buildSafeToDiscardSection(files));
|
|
781
792
|
lines.push(...buildMemEpochSection());
|
|
782
|
-
return capManifestChars(lines.join("\n"), sessionId, cwd);
|
|
793
|
+
return capManifestChars(lines.join("\n"), sessionId, cwd, transcriptPath);
|
|
783
794
|
}
|
|
784
795
|
function gitDirtySignals(cwd) {
|
|
785
796
|
const timeoutMs = loadConfig().hints.git_hint_max_ms;
|
|
@@ -797,11 +808,11 @@ function gitDirtySignals(cwd) {
|
|
|
797
808
|
}
|
|
798
809
|
return { hasPendingDiff, hasUncommittedChanges };
|
|
799
810
|
}
|
|
800
|
-
function adaptiveCharBonus(sessionId, cwd) {
|
|
811
|
+
function adaptiveCharBonus(sessionId, cwd, transcriptPath) {
|
|
801
812
|
if (!cwd) return 0;
|
|
802
813
|
const cache = loadSessionCache(sessionId ?? "") ?? {};
|
|
803
814
|
const ageSecs = cache.created_ts !== void 0 ? Math.max(0, Date.now() / 1e3 - cache.created_ts) : 0;
|
|
804
|
-
const contextPressure = getContextPressure(cache);
|
|
815
|
+
const contextPressure = getContextPressure(cache, transcriptPath);
|
|
805
816
|
const { hasPendingDiff, hasUncommittedChanges } = gitDirtySignals(cwd);
|
|
806
817
|
if (!hasPendingDiff && !hasUncommittedChanges) return 0;
|
|
807
818
|
const baseline = computeAdaptiveBudget(cache, ageSecs, { contextPressure });
|
|
@@ -809,11 +820,11 @@ function adaptiveCharBonus(sessionId, cwd) {
|
|
|
809
820
|
const deltaTokens = Math.max(0, withGitSignal - baseline);
|
|
810
821
|
return deltaTokens * 3;
|
|
811
822
|
}
|
|
812
|
-
function capManifestChars(manifest, sessionId, cwd) {
|
|
823
|
+
function capManifestChars(manifest, sessionId, cwd, transcriptPath) {
|
|
813
824
|
const cap = loadConfig().compact_assist.max_manifest_chars;
|
|
814
825
|
if (cap <= 0) return manifest;
|
|
815
826
|
if (manifest.length <= cap) return manifest;
|
|
816
|
-
const effectiveCap = cap + adaptiveCharBonus(sessionId, cwd);
|
|
827
|
+
const effectiveCap = cap + adaptiveCharBonus(sessionId, cwd, transcriptPath);
|
|
817
828
|
if (manifest.length <= effectiveCap) return manifest;
|
|
818
829
|
const omitted = manifest.length - effectiveCap;
|
|
819
830
|
return manifest.slice(0, effectiveCap) + `
|
|
@@ -886,7 +897,7 @@ function summaryBudgetDirective(budgetChars) {
|
|
|
886
897
|
function preCompactHandler(event) {
|
|
887
898
|
const out = loadConfig().compact_assist.enabled ? contextOutput(`${MANIFEST_PREAMBLE}${summaryBudgetDirective(loadConfig().compact_assist.summary_budget_chars)}
|
|
888
899
|
|
|
889
|
-
${buildManifest(event.sessionId, getCwd(event))}`) : passOutput();
|
|
900
|
+
${buildManifest(event.sessionId, getCwd(event), getTranscriptPath(event))}`) : passOutput();
|
|
890
901
|
markCompacted();
|
|
891
902
|
return out;
|
|
892
903
|
}
|
|
@@ -934,7 +945,7 @@ init_define_import_meta_env();
|
|
|
934
945
|
var TRACKED_SKILL = "token-goat";
|
|
935
946
|
var MAX_COMMANDS_SHOWN = 8;
|
|
936
947
|
async function currentCommandNames() {
|
|
937
|
-
const { buildProgram } = await import("./token-goat-chunk-
|
|
948
|
+
const { buildProgram } = await import("./token-goat-chunk-NDPO7GAH.mjs");
|
|
938
949
|
return flattenCommandNames(buildCommandManifest(buildProgram()));
|
|
939
950
|
}
|
|
940
951
|
async function recordSkillVersionSnapshot(sessionId, skillName) {
|
|
@@ -7645,114 +7656,20 @@ registerHook("post_tool_use", postSkillHandler, { toolName: "Skill" });
|
|
|
7645
7656
|
|
|
7646
7657
|
// src/hooks_bash.ts
|
|
7647
7658
|
init_define_import_meta_env();
|
|
7648
|
-
import { statSync as
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
function
|
|
7659
|
-
const hasTimeout = /(?:^|\s)(?:timeout(?:\.exe)?\s+\S+|--(?:test)?timeout(?:=|\s)\S+)/i.test(cmd);
|
|
7660
|
-
const hasSelector = /(?:\s::\S+|\s(?:-k|-t|-run|--(?:testNamePattern|last-failed|test|project))(?:=|\s)|\b(?:tests?|spec)\S*\.(?:[cm]?[jt]sx?|py|go|rs)\b|(?:^|\s)\.\/\S+)/i.test(cmd);
|
|
7661
|
-
return hasTimeout || hasSelector;
|
|
7662
|
-
}
|
|
7663
|
-
function isDirectTestRunnerCommand(cmd) {
|
|
7664
|
-
return /^(?:pytest|(?:npx\s+)?(?:jest|vitest)|go\s+test|cargo\s+test)\b/i.test(cmd);
|
|
7665
|
-
}
|
|
7666
|
-
function extractCdPrefixDirs(rawCmd) {
|
|
7667
|
-
const prefixMatch = rawCmd.match(CD_PREFIX_RE);
|
|
7668
|
-
if (prefixMatch === null) return [];
|
|
7669
|
-
const dirs = [];
|
|
7670
|
-
const segmentPattern = /cd\s+(?:"([^"]*)"|'([^']*)'|(\S+))[ \t]*(?:&&|;|\r?\n)/g;
|
|
7671
|
-
let match;
|
|
7672
|
-
while ((match = segmentPattern.exec(prefixMatch[0])) !== null) {
|
|
7673
|
-
const dir = match[1] ?? match[2] ?? match[3];
|
|
7674
|
-
if (dir !== void 0) dirs.push(dir);
|
|
7675
|
-
}
|
|
7676
|
-
return dirs;
|
|
7677
|
-
}
|
|
7678
|
-
function resolveCdHintPath(rawCmd, filePath, cwd) {
|
|
7679
|
-
if (extractCdPrefixDirs(rawCmd).length === 0) return filePath;
|
|
7680
|
-
return resolveIndexPath(filePath, cdPrefixCwd(rawCmd, cwd));
|
|
7681
|
-
}
|
|
7682
|
-
function cdPrefixCwd(rawCmd, cwd) {
|
|
7683
|
-
let dir = cwd;
|
|
7684
|
-
for (const target of extractCdPrefixDirs(rawCmd)) dir = resolveIndexPath(target, dir);
|
|
7685
|
-
return dir;
|
|
7686
|
-
}
|
|
7687
|
-
function surgicalHintFor(hintPath, isEnv, isConfig, isDoc) {
|
|
7688
|
-
return isEnv ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to read one function or class.';
|
|
7689
|
-
}
|
|
7690
|
-
function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql) {
|
|
7691
|
-
return isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isSql ? 'Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
7692
|
-
}
|
|
7693
|
-
function stripOutputPipeline(cmd) {
|
|
7694
|
-
let inSingle = false;
|
|
7695
|
-
let inDouble = false;
|
|
7696
|
-
let cut = cmd.length;
|
|
7697
|
-
let backslashes = 0;
|
|
7698
|
-
for (let i = 0; i < cmd.length; i++) {
|
|
7699
|
-
const ch = cmd[i];
|
|
7700
|
-
if (ch === "\\") {
|
|
7701
|
-
backslashes++;
|
|
7702
|
-
continue;
|
|
7703
|
-
}
|
|
7704
|
-
const escaped = backslashes % 2 === 1;
|
|
7705
|
-
backslashes = 0;
|
|
7706
|
-
if (ch === "'" && !inDouble) {
|
|
7707
|
-
if (!escaped) inSingle = !inSingle;
|
|
7708
|
-
} else if (ch === '"' && !inSingle) {
|
|
7709
|
-
if (!escaped) inDouble = !inDouble;
|
|
7710
|
-
} else if (ch === "|" && !inSingle && !inDouble) {
|
|
7711
|
-
if (cmd[i + 1] === "|") {
|
|
7712
|
-
i++;
|
|
7713
|
-
continue;
|
|
7714
|
-
}
|
|
7715
|
-
cut = i;
|
|
7716
|
-
break;
|
|
7717
|
-
}
|
|
7718
|
-
}
|
|
7719
|
-
let base = cmd.slice(0, cut);
|
|
7720
|
-
let prev;
|
|
7721
|
-
do {
|
|
7722
|
-
prev = base;
|
|
7723
|
-
const masked = base.replace(/"((?:[^"\\]|\\.)*)"/g, (_m, inner) => '"' + " ".repeat(inner.length) + '"').replace(/'([^']*)'/g, (_m, inner) => "'" + " ".repeat(inner.length) + "'");
|
|
7724
|
-
const newMasked = masked.replace(/\s*(?:[0-9]*>&[0-9]+|[0-9&]*>>?\s*(?:"[^"]*"|'[^']*'|[^\s|]+))\s*$/, "");
|
|
7725
|
-
if (newMasked.length < masked.length) {
|
|
7726
|
-
base = base.slice(0, newMasked.length);
|
|
7727
|
-
}
|
|
7728
|
-
} while (base !== prev);
|
|
7729
|
-
return base.trim();
|
|
7730
|
-
}
|
|
7731
|
-
function pipelineDivergenceNote(cmd, entryCommand) {
|
|
7732
|
-
if (entryCommand === cmd) return "";
|
|
7733
|
-
const preview = entryCommand.length > 60 ? entryCommand.slice(0, 57) + "..." : entryCommand;
|
|
7734
|
-
return " (cached from a differently-piped run, `" + preview + "` \u2014 verify it covers what you need before trusting it)";
|
|
7735
|
-
}
|
|
7736
|
-
function extractCommand(event) {
|
|
7737
|
-
const cmd = event.toolInput["command"];
|
|
7738
|
-
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
7739
|
-
}
|
|
7740
|
-
var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick)\b/i;
|
|
7741
|
-
var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:.*\s)?--(?:\s|$)/i;
|
|
7742
|
-
function isHeadMovingGitCommand(cmd) {
|
|
7743
|
-
if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
|
|
7744
|
-
if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
|
|
7745
|
-
return true;
|
|
7659
|
+
import { statSync as statSync6, existsSync } from "node:fs";
|
|
7660
|
+
|
|
7661
|
+
// src/hooks_bash_commands.ts
|
|
7662
|
+
init_define_import_meta_env();
|
|
7663
|
+
import { statSync as statSync5 } from "node:fs";
|
|
7664
|
+
|
|
7665
|
+
// src/bash_extractors.ts
|
|
7666
|
+
init_define_import_meta_env();
|
|
7667
|
+
import { statSync as statSync4, openSync as openSync2, readSync, closeSync as closeSync2 } from "node:fs";
|
|
7668
|
+
function surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml = false) {
|
|
7669
|
+
return isXml ? 'Use `token-goat xml-outline "' + hintPath + '"` to inspect structure, or `token-goat xml-query "' + hintPath + '" "<selector>"` to query specific nodes.' : isEnv ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to read one function or class.';
|
|
7746
7670
|
}
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
var GIT_RESTORE_RE = /^\s*git\s+restore\b/i;
|
|
7750
|
-
var GIT_RESTORE_STAGED_ONLY_RE = /(?:^|\s)(?:--staged|-S)(?:\s|$)/;
|
|
7751
|
-
var GIT_STASH_APPLY_RE = /^\s*git\s+stash\s+(?:pop|apply)\b/i;
|
|
7752
|
-
var PATCH_APPLY_SEGMENT_RE = /^\s*(?:\S*[/\\])?(?:git\s+apply|patch)\b/i;
|
|
7753
|
-
var PATCH_APPLY_INSPECT_ONLY_RE = /(?:^|\s)--(?:check|stat|numstat|summary|dry-run)(?:\s|=|$)/i;
|
|
7754
|
-
function isFormatterWriteSegment(segment) {
|
|
7755
|
-
return /(?:^|\s|[/\\])(?:prettier|eslint)\b/i.test(segment) && /(?:^|\s)--(?:write|fix)(?:\s|$)/i.test(segment);
|
|
7671
|
+
function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql, isXml = false) {
|
|
7672
|
+
return isXml ? 'Use `token-goat xml-outline "' + filePath + '"` to inspect structure, or `token-goat xml-query "' + filePath + '" "<selector>"` to query specific nodes.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isSql ? 'Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
7756
7673
|
}
|
|
7757
7674
|
function splitShellSegments(cmd) {
|
|
7758
7675
|
const segments = [];
|
|
@@ -7786,174 +7703,40 @@ function splitShellSegments(cmd) {
|
|
|
7786
7703
|
segments.push(cur);
|
|
7787
7704
|
return segments.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
7788
7705
|
}
|
|
7789
|
-
function
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7706
|
+
function isTempPath(fp) {
|
|
7707
|
+
const norm = fp.replace(/\\/g, "/");
|
|
7708
|
+
return /^\/tmp\//i.test(norm) || /\/var\/folders\//i.test(norm) || // Anchored to a local drive root on purpose. Unanchored, this clause said yes to
|
|
7709
|
+
// `//host/share/AppData/Local/Temp/x.md`, and the caller's answer to yes is to stat the path --
|
|
7710
|
+
// which on Windows opens an SMB session to whatever host a command named. A temp directory is
|
|
7711
|
+
// somewhere on a local volume; nothing that starts with two separators is one.
|
|
7712
|
+
/^[a-z]:\/(?:[^/]+\/)*AppData\/Local\/Temp\//i.test(norm) || norm.startsWith("/c/Users/") && norm.includes("/AppData/Local/Temp/") || isUnderSystemTemp(fp);
|
|
7795
7713
|
}
|
|
7796
|
-
function
|
|
7797
|
-
|
|
7714
|
+
function isOrchestratorStateFile(filePath) {
|
|
7715
|
+
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7716
|
+
return /^\.improve-state-/.test(basename3);
|
|
7798
7717
|
}
|
|
7799
|
-
function
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
if (tokens === null) return [];
|
|
7803
|
-
const rest = tokens.slice(1);
|
|
7804
|
-
const inPlaceIdx = rest.findIndex((t) => t === "--in-place" || t.startsWith("--in-place=") || /^-[a-zA-Z]*i/.test(t));
|
|
7805
|
-
if (inPlaceIdx === -1) return [];
|
|
7806
|
-
const files = [];
|
|
7807
|
-
let scriptTaken = rest.some((t) => t === "-e" || t === "-f" || t.startsWith("--expression") || t.startsWith("--file"));
|
|
7808
|
-
for (let i = 0; i < rest.length; i++) {
|
|
7809
|
-
const t = rest[i];
|
|
7810
|
-
if (i === inPlaceIdx) {
|
|
7811
|
-
if (t === "-i" && rest[i + 1] === "") i++;
|
|
7812
|
-
continue;
|
|
7813
|
-
}
|
|
7814
|
-
if (t === "-e" || t === "-f" || t === "--expression" || t === "--file") {
|
|
7815
|
-
i++;
|
|
7816
|
-
continue;
|
|
7817
|
-
}
|
|
7818
|
-
if (t.length > 1 && t.startsWith("-")) continue;
|
|
7819
|
-
if (!scriptTaken) {
|
|
7820
|
-
scriptTaken = true;
|
|
7821
|
-
continue;
|
|
7822
|
-
}
|
|
7823
|
-
files.push(t);
|
|
7824
|
-
}
|
|
7825
|
-
return files;
|
|
7718
|
+
function extractCatSourceFile(cmd) {
|
|
7719
|
+
const m = /^cat\s+(\S+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less))\s*$/.exec(cmd);
|
|
7720
|
+
return m?.[1] ?? null;
|
|
7826
7721
|
}
|
|
7827
|
-
function
|
|
7828
|
-
|
|
7829
|
-
const
|
|
7830
|
-
|
|
7831
|
-
|
|
7722
|
+
function classifyFileExtensions(filePath) {
|
|
7723
|
+
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7724
|
+
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename3);
|
|
7725
|
+
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|dtsx|ampkg|xaml|conf|cfg|ini|properties|sql|ps1|psm1|env)$/i.test(filePath);
|
|
7726
|
+
if (!hasKnownExt && !isEnvFile) return null;
|
|
7727
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
7728
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7729
|
+
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
7730
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7731
|
+
const isXml = /\.(?:xml|dtsx|ampkg|xaml)$/i.test(filePath);
|
|
7732
|
+
return { isDoc, isEnv, isConfig, isSql, isXml };
|
|
7832
7733
|
}
|
|
7833
|
-
function
|
|
7834
|
-
const
|
|
7835
|
-
const
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
targets.push(raw.length >= 2 && (raw[0] === '"' || raw[0] === "'") ? raw.slice(1, -1) : raw);
|
|
7840
|
-
}
|
|
7841
|
-
return targets;
|
|
7842
|
-
}
|
|
7843
|
-
function extractGitRestorePathspecs(cmd) {
|
|
7844
|
-
const m = /^\s*git\s+restore\b(.*)$/i.exec(cmd);
|
|
7845
|
-
if (m === null) return [];
|
|
7846
|
-
const tokens = safeShlexSplit(m[1] ?? "");
|
|
7847
|
-
if (tokens === null) return [];
|
|
7848
|
-
const dashDash = tokens.indexOf("--");
|
|
7849
|
-
if (dashDash !== -1) return tokens.slice(dashDash + 1);
|
|
7850
|
-
const specs = [];
|
|
7851
|
-
let skipNext = false;
|
|
7852
|
-
for (const t of tokens) {
|
|
7853
|
-
if (skipNext) {
|
|
7854
|
-
skipNext = false;
|
|
7855
|
-
continue;
|
|
7856
|
-
}
|
|
7857
|
-
if (t === "-s" || t === "--source") {
|
|
7858
|
-
skipNext = true;
|
|
7859
|
-
continue;
|
|
7860
|
-
}
|
|
7861
|
-
if (t.startsWith("-")) continue;
|
|
7862
|
-
specs.push(t);
|
|
7863
|
-
}
|
|
7864
|
-
return specs;
|
|
7865
|
-
}
|
|
7866
|
-
function gitRepoRoot(gitDir) {
|
|
7867
|
-
const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
7868
|
-
return toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : gitDir;
|
|
7869
|
-
}
|
|
7870
|
-
function expandGitPathspecs(specs, gitDir) {
|
|
7871
|
-
if (specs.length === 0) return [];
|
|
7872
|
-
const listed = runGit(["ls-files", "--full-name", "--", ...specs], { cwd: gitDir, timeoutMs: 5e3 });
|
|
7873
|
-
if (listed.exitCode !== 0) return [];
|
|
7874
|
-
const repoRoot = gitRepoRoot(gitDir);
|
|
7875
|
-
return listed.stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((rel) => resolveIndexPath(rel, repoRoot));
|
|
7876
|
-
}
|
|
7877
|
-
function workingTreeStatusPaths(gitDir) {
|
|
7878
|
-
const status = runGit(["status", "--porcelain"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
7879
|
-
if (status.exitCode !== 0) return [];
|
|
7880
|
-
const repoRoot = gitRepoRoot(gitDir);
|
|
7881
|
-
const out = [];
|
|
7882
|
-
for (const line of status.stdout.split("\n")) {
|
|
7883
|
-
if (line.length < 4) continue;
|
|
7884
|
-
let rel = line.slice(3).trim();
|
|
7885
|
-
if (rel.length === 0) continue;
|
|
7886
|
-
const arrow = rel.lastIndexOf(" -> ");
|
|
7887
|
-
if (arrow !== -1) rel = rel.slice(arrow + 4);
|
|
7888
|
-
if (rel.startsWith('"')) {
|
|
7889
|
-
try {
|
|
7890
|
-
rel = JSON.parse(rel);
|
|
7891
|
-
} catch {
|
|
7892
|
-
continue;
|
|
7893
|
-
}
|
|
7894
|
-
}
|
|
7895
|
-
out.push(resolveIndexPath(rel, repoRoot));
|
|
7896
|
-
}
|
|
7897
|
-
return out;
|
|
7898
|
-
}
|
|
7899
|
-
function enqueueRewrittenPath(absPath) {
|
|
7900
|
-
if (/(?:^|[/\\])(?:NUL|nul)$/.test(absPath) || absPath.replace(/\\/g, "/").endsWith("/dev/null")) return;
|
|
7901
|
-
try {
|
|
7902
|
-
if (!statSync4(absPath).isFile()) return;
|
|
7903
|
-
} catch {
|
|
7904
|
-
return;
|
|
7905
|
-
}
|
|
7906
|
-
enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
|
|
7907
|
-
}
|
|
7908
|
-
function enqueueNonHeadMovingRewrites(cmd, rawCmd, cwd) {
|
|
7909
|
-
const atCwd = (f) => resolveIndexPath(resolveCdHintPath(rawCmd, f, cwd), cwd);
|
|
7910
|
-
const paths = [];
|
|
7911
|
-
let needsStatusSweep = GIT_STASH_APPLY_RE.test(cmd);
|
|
7912
|
-
if (GIT_RESTORE_RE.test(cmd) && !GIT_RESTORE_STAGED_ONLY_RE.test(cmd)) {
|
|
7913
|
-
paths.push(...expandGitPathspecs(extractGitRestorePathspecs(cmd), cwd));
|
|
7914
|
-
}
|
|
7915
|
-
for (const segment of splitShellSegments(cmd)) {
|
|
7916
|
-
if (PATCH_APPLY_SEGMENT_RE.test(segment) && !PATCH_APPLY_INSPECT_ONLY_RE.test(segment)) needsStatusSweep = true;
|
|
7917
|
-
if (isFormatterWriteSegment(segment)) needsStatusSweep = true;
|
|
7918
|
-
for (const f of extractSedInPlaceFiles(segment)) paths.push(atCwd(f));
|
|
7919
|
-
for (const f of extractTeeFiles(segment)) paths.push(atCwd(f));
|
|
7920
|
-
for (const f of extractRedirectTargets(segment)) paths.push(atCwd(f));
|
|
7921
|
-
}
|
|
7922
|
-
if (needsStatusSweep) paths.push(...workingTreeStatusPaths(cwd));
|
|
7923
|
-
for (const p of paths) enqueueRewrittenPath(p);
|
|
7924
|
-
}
|
|
7925
|
-
function isTempPath(fp) {
|
|
7926
|
-
const norm = fp.replace(/\\/g, "/");
|
|
7927
|
-
return /^\/tmp\//i.test(norm) || /\/var\/folders\//i.test(norm) || // Anchored to a local drive root on purpose. Unanchored, this clause said yes to
|
|
7928
|
-
// `//host/share/AppData/Local/Temp/x.md`, and the caller's answer to yes is to stat the path --
|
|
7929
|
-
// which on Windows opens an SMB session to whatever host a command named. A temp directory is
|
|
7930
|
-
// somewhere on a local volume; nothing that starts with two separators is one.
|
|
7931
|
-
/^[a-z]:\/(?:[^/]+\/)*AppData\/Local\/Temp\//i.test(norm) || norm.startsWith("/c/Users/") && norm.includes("/AppData/Local/Temp/") || isUnderSystemTemp(fp);
|
|
7932
|
-
}
|
|
7933
|
-
function isOrchestratorStateFile(filePath) {
|
|
7934
|
-
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7935
|
-
return /^\.improve-state-/.test(basename3);
|
|
7936
|
-
}
|
|
7937
|
-
function extractCatSourceFile(cmd) {
|
|
7938
|
-
const m = /^cat\s+(\S+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less))\s*$/.exec(cmd);
|
|
7939
|
-
return m?.[1] ?? null;
|
|
7940
|
-
}
|
|
7941
|
-
function classifyFileExtensions(filePath) {
|
|
7942
|
-
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7943
|
-
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename3);
|
|
7944
|
-
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|ps1|psm1|env)$/i.test(filePath);
|
|
7945
|
-
if (!hasKnownExt && !isEnvFile) return null;
|
|
7946
|
-
const isSql = /\.sql$/i.test(filePath);
|
|
7947
|
-
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7948
|
-
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
7949
|
-
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7950
|
-
return { isDoc, isEnv, isConfig, isSql };
|
|
7951
|
-
}
|
|
7952
|
-
function classifyDocConfig(filePath) {
|
|
7953
|
-
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7954
|
-
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7955
|
-
const isSql = /\.sql$/i.test(filePath);
|
|
7956
|
-
return { isDoc, isConfig, isSql };
|
|
7734
|
+
function classifyDocConfig(filePath) {
|
|
7735
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7736
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7737
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
7738
|
+
const isXml = /\.(?:xml|dtsx|ampkg|xaml)$/i.test(filePath);
|
|
7739
|
+
return { isDoc, isConfig, isSql, isXml };
|
|
7957
7740
|
}
|
|
7958
7741
|
function classifyCatPath(filePath, cmd0) {
|
|
7959
7742
|
if (isTempPath(filePath)) return null;
|
|
@@ -8030,10 +7813,10 @@ function extractPowerShellFileMethodRead(cmd, event) {
|
|
|
8030
7813
|
}
|
|
8031
7814
|
const flags = classifyFileExtensions(filePath);
|
|
8032
7815
|
if (flags === null) {
|
|
8033
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8034
|
-
return { filePath, isDoc, isEnv: false, isConfig, isSql };
|
|
7816
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
7817
|
+
return { filePath, isDoc, isEnv: false, isConfig, isSql, isXml };
|
|
8035
7818
|
}
|
|
8036
|
-
return { filePath, isDoc: flags.isDoc, isEnv: flags.isEnv, isConfig: flags.isConfig, isSql: flags.isSql };
|
|
7819
|
+
return { filePath, isDoc: flags.isDoc, isEnv: flags.isEnv, isConfig: flags.isConfig, isSql: flags.isSql, isXml: flags.isXml };
|
|
8037
7820
|
}
|
|
8038
7821
|
function extractRgSymbolSearch(cmd) {
|
|
8039
7822
|
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
@@ -8188,7 +7971,7 @@ function pythonOpenPathsAreAllLiteral(text) {
|
|
|
8188
7971
|
const calls = pythonOpenCalls(text);
|
|
8189
7972
|
return calls.length > 0 && calls.every((call) => call.pathLiteral !== null);
|
|
8190
7973
|
}
|
|
8191
|
-
var KNOWN_PYTHON_EXT_STR = "java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|html|htm|conf|cfg|ini|properties|sql|ps1|psm1|env";
|
|
7974
|
+
var KNOWN_PYTHON_EXT_STR = "java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|dtsx|ampkg|xaml|html|htm|conf|cfg|ini|properties|sql|ps1|psm1|env";
|
|
8192
7975
|
var OPEN_EXT = new RegExp(`\\.(?:${KNOWN_PYTHON_EXT_STR})$`, "i");
|
|
8193
7976
|
function extractPythonFileRead(cmd) {
|
|
8194
7977
|
let inner = cmd.trim();
|
|
@@ -8214,11 +7997,11 @@ function extractPythonFileRead(cmd) {
|
|
|
8214
7997
|
const classifyResult = (filePath) => {
|
|
8215
7998
|
const flags = classifyFileExtensions(filePath);
|
|
8216
7999
|
if (flags !== null) {
|
|
8217
|
-
return { filePath, isDoc: flags.isDoc, isConfig: flags.isConfig, isEnv: flags.isEnv, isSql: flags.isSql, isOutputFile: false };
|
|
8000
|
+
return { filePath, isDoc: flags.isDoc, isConfig: flags.isConfig, isEnv: flags.isEnv, isSql: flags.isSql, isXml: flags.isXml, isOutputFile: false };
|
|
8218
8001
|
}
|
|
8219
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8002
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8220
8003
|
const isEnv = /\.env(\.\w+)?$/i.test(filePath);
|
|
8221
|
-
return { filePath, isDoc, isConfig, isEnv, isSql, isOutputFile: false };
|
|
8004
|
+
return { filePath, isDoc, isConfig, isEnv, isSql, isXml, isOutputFile: false };
|
|
8222
8005
|
};
|
|
8223
8006
|
const heredocMatch = /^python3?\s+-\s+<<\s*'?(\w+)'?\s*\n([\s\S]*?)\n\1\s*$/.exec(pythonBody);
|
|
8224
8007
|
if (heredocMatch) {
|
|
@@ -8272,9 +8055,9 @@ function extractHeadFile(cmd) {
|
|
|
8272
8055
|
const filePath = direct !== null ? direct[3] ?? direct[4] ?? direct[5] : piped[1] ?? piped[2] ?? piped[3];
|
|
8273
8056
|
if (filePath === void 0) return null;
|
|
8274
8057
|
if (isTempPath(filePath)) return null;
|
|
8275
|
-
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
8276
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8277
|
-
return { filePath, isDoc, isConfig, isSql, n };
|
|
8058
|
+
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
|
|
8059
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8060
|
+
return { filePath, isDoc, isConfig, isSql, isXml, n };
|
|
8278
8061
|
}
|
|
8279
8062
|
function extractSedRange(cmd) {
|
|
8280
8063
|
const m = /^sed\s+-n\s+(?:['"]((?:\d+,\d+p)(?:;\d+,\d+p)*)['"]|(\d+,\d+p))\s+(?:"([^"]+)"|'([^']+)'|(\S+))(?:\s+2>(?:\/dev\/null|&1))?\s*$/.exec(cmd);
|
|
@@ -8376,7 +8159,7 @@ function leadingLinesHint(lead, hintPath, start, end, flags, preHookCwd) {
|
|
|
8376
8159
|
const key = resolveIndexPath(hintPath, preHookCwd ?? process.cwd());
|
|
8377
8160
|
const prior = findRangeOverlap(getFileLineRanges(key), start, end);
|
|
8378
8161
|
if (prior !== null) return sedOverlapHint(hintPath, prior, start, end);
|
|
8379
|
-
return lead + surgicalHintForConfigDoc(hintPath, flags.isConfig, flags.isDoc, flags.isSql);
|
|
8162
|
+
return lead + surgicalHintForConfigDoc(hintPath, flags.isConfig, flags.isDoc, flags.isSql, flags.isXml ?? false);
|
|
8380
8163
|
}
|
|
8381
8164
|
function findRangeOverlap(prior, start, end) {
|
|
8382
8165
|
let best = null;
|
|
@@ -8433,9 +8216,9 @@ function extractTailFile(cmd) {
|
|
|
8433
8216
|
const filePath = direct !== null ? direct[3] ?? direct[4] ?? direct[5] : piped[1] ?? piped[2] ?? piped[3];
|
|
8434
8217
|
if (!filePath) return null;
|
|
8435
8218
|
if (isTempPath(filePath)) return null;
|
|
8436
|
-
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
8437
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8438
|
-
return { filePath, isDoc, isConfig, isSql };
|
|
8219
|
+
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
|
|
8220
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8221
|
+
return { filePath, isDoc, isConfig, isSql, isXml };
|
|
8439
8222
|
}
|
|
8440
8223
|
function extractGetContentTail(cmd) {
|
|
8441
8224
|
const tailMatch = /-Tail\s+(\d+)/i.exec(cmd);
|
|
@@ -8450,9 +8233,9 @@ function extractGetContentTail(cmd) {
|
|
|
8450
8233
|
const filePath = (beforeTail || afterTail).replace(/^["']|["']$/g, "");
|
|
8451
8234
|
if (!filePath) return null;
|
|
8452
8235
|
if (isTempPath(filePath)) return null;
|
|
8453
|
-
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
|
|
8454
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8455
|
-
return { filePath, isDoc, isConfig, isSql };
|
|
8236
|
+
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;
|
|
8237
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8238
|
+
return { filePath, isDoc, isConfig, isSql, isXml };
|
|
8456
8239
|
}
|
|
8457
8240
|
function extractGetContentSelectFirst(cmd) {
|
|
8458
8241
|
const m = /^(Get-Content|gc)\s+([^|]+)\s*\|\s*(Select-Object|select)\s+(-First\s+(\d+))/i.exec(cmd);
|
|
@@ -8462,9 +8245,9 @@ function extractGetContentSelectFirst(cmd) {
|
|
|
8462
8245
|
if (n <= 10) return null;
|
|
8463
8246
|
if (!filePath) return null;
|
|
8464
8247
|
if (isTempPath(filePath)) return null;
|
|
8465
|
-
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
|
|
8466
|
-
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
8467
|
-
return { filePath, isDoc, isConfig, isSql, n };
|
|
8248
|
+
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;
|
|
8249
|
+
const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
|
|
8250
|
+
return { filePath, isDoc, isConfig, isSql, isXml, n };
|
|
8468
8251
|
}
|
|
8469
8252
|
function taskOutputIsJsonlTranscript(outPath) {
|
|
8470
8253
|
let fd = null;
|
|
@@ -8839,120 +8622,549 @@ function isCompressibleSingleCommand(cmd) {
|
|
|
8839
8622
|
if (hasBareBackgroundOrNewline(cmd)) return false;
|
|
8840
8623
|
return true;
|
|
8841
8624
|
}
|
|
8842
|
-
function
|
|
8843
|
-
|
|
8844
|
-
if (
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
return
|
|
8625
|
+
function extractTerminalXmlParsing(cmd) {
|
|
8626
|
+
const trimmed = cmd.trim();
|
|
8627
|
+
if (!trimmed) return null;
|
|
8628
|
+
const selectXmlM = /\bSelect-Xml\b(?:\s+(?:-Path\s+)?["']?([^"'\s|;]+(?:\.xml|\.dtsx|\.ampkg|\.xaml))["']?)?/i.exec(trimmed);
|
|
8629
|
+
if (selectXmlM) {
|
|
8630
|
+
const rawPath = selectXmlM[1];
|
|
8631
|
+
const filePath = rawPath && !rawPath.startsWith("-") ? rawPath : void 0;
|
|
8632
|
+
return { filePath, toolOrScript: "Select-Xml" };
|
|
8633
|
+
}
|
|
8634
|
+
const psXmlCastM = /\[(?:xml|System\.Xml\.XmlDocument)\]/i.exec(trimmed);
|
|
8635
|
+
if (psXmlCastM) {
|
|
8636
|
+
const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed) || /(?:Get-Content|gc|ReadAllText)\s+["']?([^"'\s|;)]+\.(?:xml|dtsx|ampkg|xaml))["']?/i.exec(trimmed);
|
|
8637
|
+
const filePath = fileM?.[1];
|
|
8638
|
+
return { filePath, toolOrScript: psXmlCastM[0] };
|
|
8639
|
+
}
|
|
8640
|
+
const inspectScriptM = /(?:powershell|pwsh|&|\.)?\s*["']?(\.?[/\\]?inspect_[^"'\s|;]+\.ps1)["']/i.exec(trimmed) || /\b(inspect_[^"'\s|;]+\.ps1)\b/i.exec(trimmed);
|
|
8641
|
+
if (inspectScriptM) {
|
|
8642
|
+
const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed);
|
|
8643
|
+
const filePath = fileM?.[1];
|
|
8644
|
+
return { filePath, toolOrScript: inspectScriptM[1] ?? "inspect script" };
|
|
8645
|
+
}
|
|
8646
|
+
const pyXmlM = /\bpython(?:\d+(?:\.\d+)?)?(?:\.exe)?\b.*-c\s+["'].*?\b(xml\.etree|BeautifulSoup|minidom|lxml)\b/i.exec(trimmed);
|
|
8647
|
+
if (pyXmlM) {
|
|
8648
|
+
const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed);
|
|
8649
|
+
const filePath = fileM?.[1];
|
|
8650
|
+
return { filePath, toolOrScript: `python ${pyXmlM[1]}` };
|
|
8651
|
+
}
|
|
8652
|
+
const cliXmlM = /\b(xmllint|xmlstarlet|xidel)\b/i.exec(trimmed);
|
|
8653
|
+
if (cliXmlM) {
|
|
8654
|
+
const fileM = /["']?([^"'\s|;]+\.(?:xml|dtsx|ampkg|xaml))["']?/i.exec(trimmed);
|
|
8655
|
+
const rawPath = fileM?.[1];
|
|
8656
|
+
const filePath = rawPath && !rawPath.startsWith("-") ? rawPath : void 0;
|
|
8657
|
+
return { filePath, toolOrScript: cliXmlM[1] };
|
|
8850
8658
|
}
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8659
|
+
return null;
|
|
8660
|
+
}
|
|
8661
|
+
|
|
8662
|
+
// src/hooks_bash_commands.ts
|
|
8663
|
+
var CD_PREFIX_RE = /^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)[ \t]*(?:&&|;|\r?\n)\s*)+/;
|
|
8664
|
+
function stripCdPrefix(cmd) {
|
|
8665
|
+
const stripped = cmd.replace(CD_PREFIX_RE, "");
|
|
8666
|
+
return stripped.trim() || cmd;
|
|
8667
|
+
}
|
|
8668
|
+
function stripTrailingStderrRedirect(cmd) {
|
|
8669
|
+
const stripped = cmd.replace(/\s*2>&1\s*$/, "");
|
|
8670
|
+
return stripped.trim() || cmd;
|
|
8671
|
+
}
|
|
8672
|
+
function hasTestRunScopeOrBudget(cmd) {
|
|
8673
|
+
const hasTimeout = /(?:^|\s)(?:timeout(?:\.exe)?\s+\S+|--(?:test)?timeout(?:=|\s)\S+)/i.test(cmd);
|
|
8674
|
+
const hasSelector = /(?:\s::\S+|\s(?:-k|-t|-run|--(?:testNamePattern|last-failed|test|project))(?:=|\s)|\b(?:tests?|spec)\S*\.(?:[cm]?[jt]sx?|py|go|rs)\b|(?:^|\s)\.\/\S+)/i.test(cmd);
|
|
8675
|
+
return hasTimeout || hasSelector;
|
|
8676
|
+
}
|
|
8677
|
+
function isDirectTestRunnerCommand(cmd) {
|
|
8678
|
+
return /^(?:pytest|(?:npx\s+)?(?:jest|vitest)|go\s+test|cargo\s+test)\b/i.test(cmd);
|
|
8679
|
+
}
|
|
8680
|
+
function extractCdPrefixDirs(rawCmd) {
|
|
8681
|
+
const prefixMatch = rawCmd.match(CD_PREFIX_RE);
|
|
8682
|
+
if (prefixMatch === null) return [];
|
|
8683
|
+
const dirs = [];
|
|
8684
|
+
const segmentPattern = /cd\s+(?:"([^"]*)"|'([^']*)'|(\S+))[ \t]*(?:&&|;|\r?\n)/g;
|
|
8685
|
+
let match;
|
|
8686
|
+
while ((match = segmentPattern.exec(prefixMatch[0])) !== null) {
|
|
8687
|
+
const dir = match[1] ?? match[2] ?? match[3];
|
|
8688
|
+
if (dir !== void 0) dirs.push(dir);
|
|
8862
8689
|
}
|
|
8863
|
-
|
|
8864
|
-
const wrapped = `token-goat compress -f ${filterName} --timeout ${cfg.timeout_seconds} -c ${shellQuoteSingle(rawCmd)}`;
|
|
8865
|
-
return { hookType: "rewriteInput", updatedInput: { ...event.toolInput, command: wrapped } };
|
|
8690
|
+
return dirs;
|
|
8866
8691
|
}
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
"jest",
|
|
8871
|
-
"vitest",
|
|
8872
|
-
"pytest",
|
|
8873
|
-
"go_test",
|
|
8874
|
-
"cargo_test",
|
|
8875
|
-
"cargo",
|
|
8876
|
-
"go",
|
|
8877
|
-
"make",
|
|
8878
|
-
"cmake",
|
|
8879
|
-
"gradle",
|
|
8880
|
-
"maven",
|
|
8881
|
-
"dotnet",
|
|
8882
|
-
"turbo",
|
|
8883
|
-
"nx",
|
|
8884
|
-
"lerna",
|
|
8885
|
-
"webpack",
|
|
8886
|
-
"eslint",
|
|
8887
|
-
"ruff",
|
|
8888
|
-
"clippy",
|
|
8889
|
-
"flake8",
|
|
8890
|
-
"mypy",
|
|
8891
|
-
"prettier",
|
|
8892
|
-
"tsc"
|
|
8893
|
-
]);
|
|
8894
|
-
function isCiBuildTestSegment(cleaned, cwd) {
|
|
8895
|
-
if (isTestRunnerCommand(cleaned) || isBuildCommand(cleaned) || isTscCommand(cleaned)) return true;
|
|
8896
|
-
if (/^\s*(npm|pnpm|yarn|bun)\s+(run\s+)?(test|build|lint|typecheck|check|ci|guards)\b/i.test(cleaned)) return true;
|
|
8897
|
-
if (/^\s*(cargo|go|dotnet|make|gradle|mvn|pytest|vitest|jest|eslint|ruff)\b/i.test(cleaned)) return true;
|
|
8898
|
-
const detected = detectFromCommand(cleaned, cwd ?? void 0);
|
|
8899
|
-
if (detected !== null && CI_BUILD_TEST_FILTER_NAMES.has(detected.filter.name)) return true;
|
|
8900
|
-
return false;
|
|
8692
|
+
function resolveCdHintPath(rawCmd, filePath, cwd) {
|
|
8693
|
+
if (extractCdPrefixDirs(rawCmd).length === 0) return filePath;
|
|
8694
|
+
return resolveIndexPath(filePath, cdPrefixCwd(rawCmd, cwd));
|
|
8901
8695
|
}
|
|
8902
|
-
function
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8696
|
+
function cdPrefixCwd(rawCmd, cwd) {
|
|
8697
|
+
let dir = cwd;
|
|
8698
|
+
for (const target of extractCdPrefixDirs(rawCmd)) dir = resolveIndexPath(target, dir);
|
|
8699
|
+
return dir;
|
|
8700
|
+
}
|
|
8701
|
+
function stripOutputPipeline(cmd) {
|
|
8702
|
+
let inSingle = false;
|
|
8703
|
+
let inDouble = false;
|
|
8704
|
+
let cut = cmd.length;
|
|
8705
|
+
let backslashes = 0;
|
|
8706
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
8707
|
+
const ch = cmd[i];
|
|
8708
|
+
if (ch === "\\") {
|
|
8709
|
+
backslashes++;
|
|
8710
|
+
continue;
|
|
8711
|
+
}
|
|
8712
|
+
const escaped = backslashes % 2 === 1;
|
|
8713
|
+
backslashes = 0;
|
|
8714
|
+
if (ch === "'" && !inDouble) {
|
|
8715
|
+
if (!escaped) inSingle = !inSingle;
|
|
8716
|
+
} else if (ch === '"' && !inSingle) {
|
|
8717
|
+
if (!escaped) inDouble = !inDouble;
|
|
8718
|
+
} else if (ch === "|" && !inSingle && !inDouble) {
|
|
8719
|
+
if (cmd[i + 1] === "|") {
|
|
8720
|
+
i++;
|
|
8721
|
+
continue;
|
|
8918
8722
|
}
|
|
8723
|
+
cut = i;
|
|
8724
|
+
break;
|
|
8725
|
+
}
|
|
8726
|
+
}
|
|
8727
|
+
let base = cmd.slice(0, cut);
|
|
8728
|
+
let prev;
|
|
8729
|
+
do {
|
|
8730
|
+
prev = base;
|
|
8731
|
+
const masked = base.replace(/"((?:[^"\\]|\\.)*)"/g, (_m, inner) => '"' + " ".repeat(inner.length) + '"').replace(/'([^']*)'/g, (_m, inner) => "'" + " ".repeat(inner.length) + "'");
|
|
8732
|
+
const newMasked = masked.replace(/\s*(?:[0-9]*>&[0-9]+|[0-9&]*>>?\s*(?:"[^"]*"|'[^']*'|[^\s|]+))\s*$/, "");
|
|
8733
|
+
if (newMasked.length < masked.length) {
|
|
8734
|
+
base = base.slice(0, newMasked.length);
|
|
8919
8735
|
}
|
|
8736
|
+
} while (base !== prev);
|
|
8737
|
+
return base.trim();
|
|
8738
|
+
}
|
|
8739
|
+
function pipelineDivergenceNote(cmd, entryCommand) {
|
|
8740
|
+
if (entryCommand === cmd) return "";
|
|
8741
|
+
const preview = entryCommand.length > 60 ? entryCommand.slice(0, 57) + "..." : entryCommand;
|
|
8742
|
+
return " (cached from a differently-piped run, `" + preview + "` \u2014 verify it covers what you need before trusting it)";
|
|
8743
|
+
}
|
|
8744
|
+
function extractCommand(event) {
|
|
8745
|
+
const cmd = event.toolInput["command"];
|
|
8746
|
+
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
8747
|
+
}
|
|
8748
|
+
var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick)\b/i;
|
|
8749
|
+
var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:\S.*?\s)?--(?:\s|$)/i;
|
|
8750
|
+
function isHeadMovingGitCommand(cmd) {
|
|
8751
|
+
if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
|
|
8752
|
+
if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
|
|
8753
|
+
return true;
|
|
8754
|
+
}
|
|
8755
|
+
var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
|
|
8756
|
+
var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
|
|
8757
|
+
var GIT_RESTORE_RE = /^\s*git\s+restore\b/i;
|
|
8758
|
+
var GIT_RESTORE_STAGED_ONLY_RE = /(?:^|\s)(?:--staged|-S)(?:\s|$)/;
|
|
8759
|
+
var GIT_STASH_APPLY_RE = /^\s*git\s+stash\s+(?:pop|apply)\b/i;
|
|
8760
|
+
var PATCH_APPLY_SEGMENT_RE = /^\s*(?:\S*[/\\])?(?:git\s+apply|patch)\b/i;
|
|
8761
|
+
var PATCH_APPLY_INSPECT_ONLY_RE = /(?:^|\s)--(?:check|stat|numstat|summary|dry-run)(?:\s|=|$)/i;
|
|
8762
|
+
function isFormatterWriteSegment(segment) {
|
|
8763
|
+
return /(?:^|\s|[/\\])(?:prettier|eslint)\b/i.test(segment) && /(?:^|\s)--(?:write|fix)(?:\s|$)/i.test(segment);
|
|
8764
|
+
}
|
|
8765
|
+
function safeShlexSplit(segment) {
|
|
8766
|
+
try {
|
|
8767
|
+
return shlexSplit(segment);
|
|
8768
|
+
} catch {
|
|
8920
8769
|
return null;
|
|
8921
8770
|
}
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8771
|
+
}
|
|
8772
|
+
function segmentCommandIs(segment, name2) {
|
|
8773
|
+
return new RegExp("^\\s*(?:\\S*[/\\\\])?" + name2 + "(?:\\.exe)?\\b", "i").test(segment);
|
|
8774
|
+
}
|
|
8775
|
+
function extractSedInPlaceFiles(segment) {
|
|
8776
|
+
if (!segmentCommandIs(segment, "sed")) return [];
|
|
8777
|
+
const tokens = safeShlexSplit(segment);
|
|
8778
|
+
if (tokens === null) return [];
|
|
8779
|
+
const rest = tokens.slice(1);
|
|
8780
|
+
const inPlaceIdx = rest.findIndex((t) => t === "--in-place" || t.startsWith("--in-place=") || /^-[a-zA-Z]*i/.test(t));
|
|
8781
|
+
if (inPlaceIdx === -1) return [];
|
|
8782
|
+
const files = [];
|
|
8783
|
+
let scriptTaken = rest.some((t) => t === "-e" || t === "-f" || t.startsWith("--expression") || t.startsWith("--file"));
|
|
8784
|
+
for (let i = 0; i < rest.length; i++) {
|
|
8785
|
+
const t = rest[i];
|
|
8786
|
+
if (i === inPlaceIdx) {
|
|
8787
|
+
if (t === "-i" && rest[i + 1] === "") i++;
|
|
8788
|
+
continue;
|
|
8789
|
+
}
|
|
8790
|
+
if (t === "-e" || t === "-f" || t === "--expression" || t === "--file") {
|
|
8791
|
+
i++;
|
|
8792
|
+
continue;
|
|
8793
|
+
}
|
|
8794
|
+
if (t.length > 1 && t.startsWith("-")) continue;
|
|
8795
|
+
if (!scriptTaken) {
|
|
8796
|
+
scriptTaken = true;
|
|
8797
|
+
continue;
|
|
8798
|
+
}
|
|
8799
|
+
files.push(t);
|
|
8800
|
+
}
|
|
8801
|
+
return files;
|
|
8802
|
+
}
|
|
8803
|
+
function extractTeeFiles(segment) {
|
|
8804
|
+
if (!segmentCommandIs(segment, "tee")) return [];
|
|
8805
|
+
const tokens = safeShlexSplit(segment);
|
|
8806
|
+
if (tokens === null) return [];
|
|
8807
|
+
return tokens.slice(1).filter((t) => t.length > 0 && !t.startsWith("-"));
|
|
8808
|
+
}
|
|
8809
|
+
function extractRedirectTargets(segment) {
|
|
8810
|
+
const targets = [];
|
|
8811
|
+
const re = /(?:^|\s)[0-9]?>>?\s*("[^"]*"|'[^']*'|[^\s|&<>]+)/g;
|
|
8812
|
+
let m;
|
|
8813
|
+
while ((m = re.exec(segment)) !== null) {
|
|
8814
|
+
const raw = m[1];
|
|
8815
|
+
targets.push(raw.length >= 2 && (raw[0] === '"' || raw[0] === "'") ? raw.slice(1, -1) : raw);
|
|
8816
|
+
}
|
|
8817
|
+
return targets;
|
|
8818
|
+
}
|
|
8819
|
+
function extractGitRestorePathspecs(cmd) {
|
|
8820
|
+
const m = /^\s*git\s+restore\b(.*)$/i.exec(cmd);
|
|
8821
|
+
if (m === null) return [];
|
|
8822
|
+
const tokens = safeShlexSplit(m[1] ?? "");
|
|
8823
|
+
if (tokens === null) return [];
|
|
8824
|
+
const dashDash = tokens.indexOf("--");
|
|
8825
|
+
if (dashDash !== -1) return tokens.slice(dashDash + 1);
|
|
8826
|
+
const specs = [];
|
|
8827
|
+
let skipNext = false;
|
|
8828
|
+
for (const t of tokens) {
|
|
8829
|
+
if (skipNext) {
|
|
8830
|
+
skipNext = false;
|
|
8831
|
+
continue;
|
|
8832
|
+
}
|
|
8833
|
+
if (t === "-s" || t === "--source") {
|
|
8834
|
+
skipNext = true;
|
|
8835
|
+
continue;
|
|
8836
|
+
}
|
|
8837
|
+
if (t.startsWith("-")) continue;
|
|
8838
|
+
specs.push(t);
|
|
8839
|
+
}
|
|
8840
|
+
return specs;
|
|
8841
|
+
}
|
|
8842
|
+
function gitRepoRoot(gitDir) {
|
|
8843
|
+
const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8844
|
+
return toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : gitDir;
|
|
8845
|
+
}
|
|
8846
|
+
function expandGitPathspecs(specs, gitDir) {
|
|
8847
|
+
if (specs.length === 0) return [];
|
|
8848
|
+
const listed = runGit(["ls-files", "--full-name", "--", ...specs], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8849
|
+
if (listed.exitCode !== 0) return [];
|
|
8850
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
8851
|
+
return listed.stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((rel) => resolveIndexPath(rel, repoRoot));
|
|
8852
|
+
}
|
|
8853
|
+
function workingTreeStatusPaths(gitDir) {
|
|
8854
|
+
const status = runGit(["status", "--porcelain"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8855
|
+
if (status.exitCode !== 0) return [];
|
|
8856
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
8857
|
+
const out = [];
|
|
8858
|
+
for (const line of status.stdout.split("\n")) {
|
|
8859
|
+
if (line.length < 4) continue;
|
|
8860
|
+
let rel = line.slice(3).trim();
|
|
8861
|
+
if (rel.length === 0) continue;
|
|
8862
|
+
const arrow = rel.lastIndexOf(" -> ");
|
|
8863
|
+
if (arrow !== -1) rel = rel.slice(arrow + 4);
|
|
8864
|
+
if (rel.startsWith('"')) {
|
|
8865
|
+
try {
|
|
8866
|
+
rel = JSON.parse(rel);
|
|
8867
|
+
} catch {
|
|
8868
|
+
continue;
|
|
8869
|
+
}
|
|
8870
|
+
}
|
|
8871
|
+
out.push(resolveIndexPath(rel, repoRoot));
|
|
8872
|
+
}
|
|
8873
|
+
return out;
|
|
8874
|
+
}
|
|
8875
|
+
function enqueueRewrittenPath(absPath) {
|
|
8876
|
+
if (/(?:^|[/\\])(?:NUL|nul)$/.test(absPath) || absPath.replace(/\\/g, "/").endsWith("/dev/null")) return;
|
|
8877
|
+
try {
|
|
8878
|
+
if (!statSync5(absPath).isFile()) return;
|
|
8879
|
+
} catch {
|
|
8880
|
+
return;
|
|
8881
|
+
}
|
|
8882
|
+
enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
|
|
8883
|
+
}
|
|
8884
|
+
function enqueueNonHeadMovingRewrites(cmd, rawCmd, cwd) {
|
|
8885
|
+
const atCwd = (f) => resolveIndexPath(resolveCdHintPath(rawCmd, f, cwd), cwd);
|
|
8886
|
+
const paths = [];
|
|
8887
|
+
let needsStatusSweep = GIT_STASH_APPLY_RE.test(cmd);
|
|
8888
|
+
if (GIT_RESTORE_RE.test(cmd) && !GIT_RESTORE_STAGED_ONLY_RE.test(cmd)) {
|
|
8889
|
+
paths.push(...expandGitPathspecs(extractGitRestorePathspecs(cmd), cwd));
|
|
8890
|
+
}
|
|
8891
|
+
for (const segment of splitShellSegments(cmd)) {
|
|
8892
|
+
if (PATCH_APPLY_SEGMENT_RE.test(segment) && !PATCH_APPLY_INSPECT_ONLY_RE.test(segment)) needsStatusSweep = true;
|
|
8893
|
+
if (isFormatterWriteSegment(segment)) needsStatusSweep = true;
|
|
8894
|
+
for (const f of extractSedInPlaceFiles(segment)) paths.push(atCwd(f));
|
|
8895
|
+
for (const f of extractTeeFiles(segment)) paths.push(atCwd(f));
|
|
8896
|
+
for (const f of extractRedirectTargets(segment)) paths.push(atCwd(f));
|
|
8897
|
+
}
|
|
8898
|
+
if (needsStatusSweep) paths.push(...workingTreeStatusPaths(cwd));
|
|
8899
|
+
for (const p of paths) enqueueRewrittenPath(p);
|
|
8900
|
+
}
|
|
8901
|
+
var PIPELINE_PASSTHROUGH_HEADS = /* @__PURE__ */ new Set(["head", "tail", "cat", "tee", "less", "more"]);
|
|
8902
|
+
var CI_FILTER_NAMES = /^(?:generic-ci|jest|vitest|pytest|go_test|cargo_test|cargo|go|make|cmake|gradle|maven|dotnet|turbo|nx|lerna|webpack|eslint|ruff|clippy|flake8|mypy|prettier|tsc)$/;
|
|
8903
|
+
function isCiBuildTestSegment(cleaned, cwd) {
|
|
8904
|
+
if (isTestRunnerCommand(cleaned) || isBuildCommand(cleaned) || isTscCommand(cleaned)) return true;
|
|
8905
|
+
if (/^\s*(npm|pnpm|yarn|bun)\s+(run\s+)?(test|build|lint|typecheck|check|ci|guards)\b/i.test(cleaned)) return true;
|
|
8906
|
+
if (/^\s*(cargo|go|dotnet|make|gradle|mvn|pytest|vitest|jest|eslint|ruff)\b/i.test(cleaned)) return true;
|
|
8907
|
+
const detected = detectFromCommand(cleaned, cwd ?? void 0);
|
|
8908
|
+
if (detected !== null && CI_FILTER_NAMES.test(detected.filter.name)) return true;
|
|
8909
|
+
return false;
|
|
8910
|
+
}
|
|
8911
|
+
function pipelineShapeFilter(cmd, cwd) {
|
|
8912
|
+
if (hasUnquotedOperator(cmd, ["&&", "||", ";"])) {
|
|
8913
|
+
const forSplit2 = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8914
|
+
if (hasBareBackgroundOrNewline(forSplit2)) return null;
|
|
8915
|
+
const segments2 = splitShellSegments(forSplit2);
|
|
8916
|
+
if (segments2.length >= 2) {
|
|
8917
|
+
let recognizedCiCount = 0;
|
|
8918
|
+
for (const segment of segments2) {
|
|
8919
|
+
const cleaned = stripOutputPipeline(segment.trim());
|
|
8920
|
+
if (cleaned.length === 0) continue;
|
|
8921
|
+
if (isCiBuildTestSegment(cleaned, cwd)) {
|
|
8922
|
+
recognizedCiCount++;
|
|
8923
|
+
}
|
|
8924
|
+
}
|
|
8925
|
+
if (recognizedCiCount > 0) {
|
|
8926
|
+
return filterByName("generic-ci");
|
|
8927
|
+
}
|
|
8928
|
+
}
|
|
8929
|
+
return null;
|
|
8930
|
+
}
|
|
8931
|
+
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8932
|
+
if (hasBareBackgroundOrNewline(forSplit)) return null;
|
|
8933
|
+
const segments = splitShellSegments(forSplit);
|
|
8934
|
+
if (segments.length < 2) return null;
|
|
8935
|
+
for (const segment of segments.slice(1)) {
|
|
8936
|
+
const head = safeShlexSplit(segment)?.[0];
|
|
8937
|
+
if (head === void 0) return null;
|
|
8938
|
+
if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
|
|
8939
|
+
}
|
|
8940
|
+
const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
|
|
8941
|
+
return detected === null ? null : detected.filter;
|
|
8942
|
+
}
|
|
8943
|
+
function pureFileReadPath(cmd) {
|
|
8944
|
+
const single = extractCatFile(cmd)?.filePath ?? extractHeadFile(cmd)?.filePath ?? extractTailFile(cmd)?.filePath ?? extractLineRangeRead(cmd)?.filePath;
|
|
8945
|
+
if (single !== void 0) return single;
|
|
8946
|
+
return singleFileCompoundReadPath(cmd);
|
|
8947
|
+
}
|
|
8948
|
+
function singleFileCompoundReadPath(cmd) {
|
|
8949
|
+
const reads = extractLineRangeReadsCompound(cmd);
|
|
8950
|
+
if (reads === null || reads.length !== 1) return null;
|
|
8951
|
+
return reads[0]?.filePath ?? null;
|
|
8952
|
+
}
|
|
8953
|
+
function deliveredLineNumbers(cmd, lineCount) {
|
|
8954
|
+
const ranged = extractLineRangeRead(cmd);
|
|
8955
|
+
if (ranged !== null) {
|
|
8956
|
+
const nums = [];
|
|
8957
|
+
for (const [lo, hi] of ranged.ranges) for (let n = lo; n <= hi; n++) nums.push(n);
|
|
8958
|
+
if (nums.length === 0) return null;
|
|
8959
|
+
while (nums.length < lineCount) nums.push((nums[nums.length - 1] ?? 0) + 1);
|
|
8960
|
+
return nums;
|
|
8961
|
+
}
|
|
8962
|
+
if (extractCatFile(cmd) !== null || extractHeadFile(cmd) !== null) return Array.from({ length: lineCount }, (_, i) => i + 1);
|
|
8963
|
+
if (singleFileCompoundReadPath(cmd) !== null) return Array.from({ length: lineCount }, () => null);
|
|
8964
|
+
return null;
|
|
8965
|
+
}
|
|
8966
|
+
var WHOLE_FILE_DUMP_RE = /^(?:(?:cat|type|Get-Content|gc)|(?:head|tail)[ \t]+-n[ \t]+\d+)[ \t]+(?:"([A-Za-z0-9._\-/\\:+@ ]+)"|'([A-Za-z0-9._\-/\\:+@ ]+)'|([A-Za-z0-9._\-/\\:+@]+))(?:[ \t]+2>(?:&1|\/dev\/null))?[ \t]*$/i;
|
|
8967
|
+
function isWholeFileDump(cmd, extractedPath) {
|
|
8968
|
+
const m = WHOLE_FILE_DUMP_RE.exec(cmd);
|
|
8969
|
+
if (m === null) return false;
|
|
8970
|
+
const shaped = m[1] ?? m[2] ?? m[3];
|
|
8971
|
+
return shaped !== void 0 && shaped === extractedPath;
|
|
8972
|
+
}
|
|
8973
|
+
function unwrapCompressCommand(executed) {
|
|
8974
|
+
const t = executed.trim();
|
|
8975
|
+
if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
|
|
8976
|
+
let argv;
|
|
8977
|
+
try {
|
|
8978
|
+
argv = shlexSplit(t);
|
|
8979
|
+
} catch {
|
|
8980
|
+
return null;
|
|
8981
|
+
}
|
|
8982
|
+
for (let i = 0; i + 1 < argv.length; i++) {
|
|
8983
|
+
const tok = argv[i];
|
|
8984
|
+
if (tok === "-c" || tok === "--cmd") return argv[i + 1] ?? null;
|
|
8985
|
+
if (tok === "--cmd-b64") {
|
|
8986
|
+
try {
|
|
8987
|
+
return Buffer.from(argv[i + 1] ?? "", "base64").toString("utf8");
|
|
8988
|
+
} catch {
|
|
8989
|
+
return null;
|
|
8990
|
+
}
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
return null;
|
|
8994
|
+
}
|
|
8995
|
+
function detectUnbalancedShellSyntax(cmd) {
|
|
8996
|
+
let inSingle = false;
|
|
8997
|
+
let inDouble = false;
|
|
8998
|
+
let i = 0;
|
|
8999
|
+
while (i < cmd.length) {
|
|
9000
|
+
const ch = cmd[i];
|
|
9001
|
+
if (inSingle) {
|
|
9002
|
+
if (ch === "'") {
|
|
9003
|
+
inSingle = false;
|
|
9004
|
+
}
|
|
9005
|
+
i++;
|
|
9006
|
+
continue;
|
|
9007
|
+
}
|
|
9008
|
+
if (inDouble) {
|
|
9009
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
9010
|
+
i += 2;
|
|
9011
|
+
continue;
|
|
9012
|
+
}
|
|
9013
|
+
if (ch === '"') {
|
|
9014
|
+
inDouble = false;
|
|
9015
|
+
}
|
|
9016
|
+
i++;
|
|
9017
|
+
continue;
|
|
9018
|
+
}
|
|
9019
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
9020
|
+
i += 2;
|
|
9021
|
+
continue;
|
|
9022
|
+
}
|
|
9023
|
+
if (ch === "$" && cmd[i + 1] === "(" && cmd[i + 2] === "(") {
|
|
9024
|
+
let depth = 2;
|
|
9025
|
+
let j = i + 3;
|
|
9026
|
+
while (j < cmd.length && depth > 0) {
|
|
9027
|
+
if (cmd[j] === "(") depth++;
|
|
9028
|
+
else if (cmd[j] === ")") depth--;
|
|
9029
|
+
j++;
|
|
9030
|
+
}
|
|
9031
|
+
i = j;
|
|
9032
|
+
continue;
|
|
9033
|
+
}
|
|
9034
|
+
if (ch === "$" && cmd[i + 1] === "'") {
|
|
9035
|
+
let j = i + 2;
|
|
9036
|
+
let closed = false;
|
|
9037
|
+
while (j < cmd.length) {
|
|
9038
|
+
if (cmd[j] === "\\") {
|
|
9039
|
+
j += 2;
|
|
9040
|
+
continue;
|
|
9041
|
+
}
|
|
9042
|
+
if (cmd[j] === "'") {
|
|
9043
|
+
j++;
|
|
9044
|
+
closed = true;
|
|
9045
|
+
break;
|
|
9046
|
+
}
|
|
9047
|
+
j++;
|
|
9048
|
+
}
|
|
9049
|
+
if (!closed) {
|
|
9050
|
+
inSingle = true;
|
|
9051
|
+
break;
|
|
9052
|
+
}
|
|
9053
|
+
i = j;
|
|
9054
|
+
continue;
|
|
9055
|
+
}
|
|
9056
|
+
if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
|
|
9057
|
+
const nl2 = cmd.indexOf("\n", i);
|
|
9058
|
+
i = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9059
|
+
continue;
|
|
9060
|
+
}
|
|
9061
|
+
if (ch === "'") {
|
|
9062
|
+
inSingle = true;
|
|
9063
|
+
i++;
|
|
9064
|
+
continue;
|
|
9065
|
+
}
|
|
9066
|
+
if (ch === '"') {
|
|
9067
|
+
inDouble = true;
|
|
9068
|
+
i++;
|
|
9069
|
+
continue;
|
|
9070
|
+
}
|
|
9071
|
+
if (ch === "<" && i + 1 < cmd.length && cmd[i + 1] === "<") {
|
|
9072
|
+
if (i + 2 < cmd.length && cmd[i + 2] === "<") {
|
|
9073
|
+
i += 3;
|
|
9074
|
+
continue;
|
|
9075
|
+
}
|
|
9076
|
+
let j = i + 2;
|
|
9077
|
+
let hasIndentModifier = false;
|
|
9078
|
+
if (j < cmd.length && (cmd[j] === "-" || cmd[j] === "~")) {
|
|
9079
|
+
hasIndentModifier = true;
|
|
9080
|
+
j++;
|
|
9081
|
+
}
|
|
9082
|
+
while (j < cmd.length && cmd[j] === " ") {
|
|
9083
|
+
j++;
|
|
9084
|
+
}
|
|
9085
|
+
if (j < cmd.length) {
|
|
9086
|
+
let delimStart = j;
|
|
9087
|
+
if (cmd[j] === '"' || cmd[j] === "'") {
|
|
9088
|
+
delimStart = j + 1;
|
|
9089
|
+
const quoteChar = cmd[j];
|
|
9090
|
+
let delimEnd = delimStart;
|
|
9091
|
+
while (delimEnd < cmd.length && cmd[delimEnd] !== quoteChar) {
|
|
9092
|
+
delimEnd++;
|
|
9093
|
+
}
|
|
9094
|
+
if (delimEnd >= cmd.length) {
|
|
9095
|
+
return "an unclosed quote in a heredoc opener";
|
|
9096
|
+
}
|
|
9097
|
+
j = delimEnd + 1;
|
|
9098
|
+
} else {
|
|
9099
|
+
let delimEnd = delimStart;
|
|
9100
|
+
while (delimEnd < cmd.length && /\w/.test(cmd.charAt(delimEnd))) {
|
|
9101
|
+
delimEnd++;
|
|
9102
|
+
}
|
|
9103
|
+
j = delimEnd;
|
|
9104
|
+
}
|
|
9105
|
+
const delimiter = cmd.slice(delimStart, j).replace(/["']/g, "");
|
|
9106
|
+
if (delimiter) {
|
|
9107
|
+
let scanPos = j;
|
|
9108
|
+
let terminatorEnd = -1;
|
|
9109
|
+
while (scanPos <= cmd.length) {
|
|
9110
|
+
const nl2 = cmd.indexOf("\n", scanPos);
|
|
9111
|
+
const lineEnd = nl2 === -1 ? cmd.length : nl2;
|
|
9112
|
+
let line = cmd.slice(scanPos, lineEnd);
|
|
9113
|
+
if (line.endsWith("\r")) {
|
|
9114
|
+
line = line.slice(0, -1);
|
|
9115
|
+
}
|
|
9116
|
+
const isMatch = hasIndentModifier ? line.trim() === delimiter : line === delimiter;
|
|
9117
|
+
if (isMatch) {
|
|
9118
|
+
terminatorEnd = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9119
|
+
break;
|
|
9120
|
+
}
|
|
9121
|
+
if (nl2 === -1) break;
|
|
9122
|
+
scanPos = nl2 + 1;
|
|
9123
|
+
}
|
|
9124
|
+
if (terminatorEnd === -1) {
|
|
9125
|
+
return `an unterminated heredoc (${delimiter} never appears on its own line)`;
|
|
9126
|
+
}
|
|
9127
|
+
i = terminatorEnd;
|
|
9128
|
+
continue;
|
|
9129
|
+
}
|
|
9130
|
+
}
|
|
9131
|
+
}
|
|
9132
|
+
i++;
|
|
9133
|
+
}
|
|
9134
|
+
if (inSingle) {
|
|
9135
|
+
return "an unclosed single quote";
|
|
9136
|
+
}
|
|
9137
|
+
if (inDouble) {
|
|
9138
|
+
return "an unclosed double quote";
|
|
8930
9139
|
}
|
|
8931
|
-
|
|
8932
|
-
return detected === null ? null : detected.filter;
|
|
8933
|
-
}
|
|
8934
|
-
function pureFileReadPath(cmd) {
|
|
8935
|
-
const single = extractCatFile(cmd)?.filePath ?? extractHeadFile(cmd)?.filePath ?? extractTailFile(cmd)?.filePath ?? extractLineRangeRead(cmd)?.filePath;
|
|
8936
|
-
if (single !== void 0) return single;
|
|
8937
|
-
return singleFileCompoundReadPath(cmd);
|
|
8938
|
-
}
|
|
8939
|
-
function singleFileCompoundReadPath(cmd) {
|
|
8940
|
-
const reads = extractLineRangeReadsCompound(cmd);
|
|
8941
|
-
if (reads === null || reads.length !== 1) return null;
|
|
8942
|
-
return reads[0]?.filePath ?? null;
|
|
9140
|
+
return null;
|
|
8943
9141
|
}
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
9142
|
+
|
|
9143
|
+
// src/hooks_bash.ts
|
|
9144
|
+
function maybeCompressRewrite(event, rawCmd, cmd) {
|
|
9145
|
+
if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
|
|
9146
|
+
if (event.raw["_tg_harness"] === "vscode") return null;
|
|
9147
|
+
let cfg;
|
|
9148
|
+
try {
|
|
9149
|
+
cfg = loadConfig().bash_compress;
|
|
9150
|
+
} catch {
|
|
9151
|
+
return null;
|
|
8952
9152
|
}
|
|
8953
|
-
if (
|
|
8954
|
-
if (
|
|
8955
|
-
|
|
9153
|
+
if (!cfg.enabled) return null;
|
|
9154
|
+
if (!canRunWrappedShell()) return null;
|
|
9155
|
+
const gateCmd = stripTrailingStderrRedirect(cmd);
|
|
9156
|
+
const detected = detectFromCommand(gateCmd, getCwd(event));
|
|
9157
|
+
let filterName;
|
|
9158
|
+
if (detected !== null) {
|
|
9159
|
+
filterName = detected.filter.name;
|
|
9160
|
+
} else if (isCompressibleSingleCommand(gateCmd)) {
|
|
9161
|
+
filterName = "generic";
|
|
9162
|
+
} else {
|
|
9163
|
+
return null;
|
|
9164
|
+
}
|
|
9165
|
+
if (cfg.disabled_filters.includes(filterName)) return null;
|
|
9166
|
+
const wrapped = `token-goat compress -f ${filterName} --timeout ${cfg.timeout_seconds} -c ${shellQuoteSingle(rawCmd)}`;
|
|
9167
|
+
return { hookType: "rewriteInput", updatedInput: { ...event.toolInput, command: wrapped } };
|
|
8956
9168
|
}
|
|
8957
9169
|
function elideServedShellLines(cmd, output, priorIds, unknownLineNumbers = false) {
|
|
8958
9170
|
if (priorIds.length === 0) return null;
|
|
@@ -9006,19 +9218,12 @@ function foldShellReadBodies(cmd, output, fileKey, cwd) {
|
|
|
9006
9218
|
if (folded === null) return null;
|
|
9007
9219
|
return { text: folded.numbered.join("\n"), folds: folded.folds };
|
|
9008
9220
|
}
|
|
9009
|
-
var WHOLE_FILE_DUMP_RE = /^(?:(?:cat|type|Get-Content|gc)|(?:head|tail)[ \t]+-n[ \t]+\d+)[ \t]+(?:"([A-Za-z0-9._\-/\\:+@ ]+)"|'([A-Za-z0-9._\-/\\:+@ ]+)'|([A-Za-z0-9._\-/\\:+@]+))(?:[ \t]+2>(?:&1|\/dev\/null))?[ \t]*$/i;
|
|
9010
|
-
function isWholeFileDump(cmd, extractedPath) {
|
|
9011
|
-
const m = WHOLE_FILE_DUMP_RE.exec(cmd);
|
|
9012
|
-
if (m === null) return false;
|
|
9013
|
-
const shaped = m[1] ?? m[2] ?? m[3];
|
|
9014
|
-
return shaped !== void 0 && shaped === extractedPath;
|
|
9015
|
-
}
|
|
9016
9221
|
function foldShellReadStructure(cmd, filePath, output, fileKey, cwd) {
|
|
9017
9222
|
if (!isWholeFileDump(cmd, filePath)) return null;
|
|
9018
9223
|
const originalBytes = Buffer.byteLength(output, "utf-8");
|
|
9019
9224
|
let onDisk;
|
|
9020
9225
|
try {
|
|
9021
|
-
onDisk =
|
|
9226
|
+
onDisk = statSync6(fileKey).size;
|
|
9022
9227
|
} catch {
|
|
9023
9228
|
return null;
|
|
9024
9229
|
}
|
|
@@ -9123,9 +9328,9 @@ async function maybeElideServedGenericOutput(cmd, output, exitCode, cwd, cacheMi
|
|
|
9123
9328
|
if (rewrittenText === null) return null;
|
|
9124
9329
|
return emitRewrite(rewrittenText, "already-served shell output collapsed", { kind: "bash_compress:generic-served-elision", originalBytes: deliveredOutputBytes(originalBytes) });
|
|
9125
9330
|
}
|
|
9126
|
-
async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes) {
|
|
9331
|
+
async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped = false) {
|
|
9127
9332
|
if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
|
|
9128
|
-
if (isCompressibleSingleCommand(cmd)) return null;
|
|
9333
|
+
if (!isUnwrapped && isCompressibleSingleCommand(cmd)) return null;
|
|
9129
9334
|
if (exitCode !== null && exitCode !== 0) return null;
|
|
9130
9335
|
let cfg;
|
|
9131
9336
|
try {
|
|
@@ -9135,7 +9340,7 @@ async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinB
|
|
|
9135
9340
|
}
|
|
9136
9341
|
if (!cfg.enabled || cfg.disabled_filters.includes("generic")) return null;
|
|
9137
9342
|
if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return null;
|
|
9138
|
-
const shaped = pipelineShapeFilter(cmd, cwd);
|
|
9343
|
+
const shaped = pipelineShapeFilter(cmd, cwd) ?? (isUnwrapped ? detectFromCommand(cmd, cwd ?? void 0)?.filter ?? null : null);
|
|
9139
9344
|
const filter3 = shaped !== null && !cfg.disabled_filters.includes(shaped.name) ? shaped : filterByName("generic");
|
|
9140
9345
|
if (filter3 === null) return null;
|
|
9141
9346
|
const compressed = compressOutput(filter3, output, "", exitCode ?? 0, [], {
|
|
@@ -9216,168 +9421,6 @@ function maybeFoldCurlHtml(cmd, output, id) {
|
|
|
9216
9421
|
}
|
|
9217
9422
|
return emitRewrite(notice + fenced, "curl HTML body cleaned", { kind: "bash_compress:curl-html", originalBytes: deliveredOutputBytes(originalBytes) });
|
|
9218
9423
|
}
|
|
9219
|
-
function unwrapCompressCommand(executed) {
|
|
9220
|
-
const t = executed.trim();
|
|
9221
|
-
if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
|
|
9222
|
-
let argv;
|
|
9223
|
-
try {
|
|
9224
|
-
argv = shlexSplit(t);
|
|
9225
|
-
} catch {
|
|
9226
|
-
return null;
|
|
9227
|
-
}
|
|
9228
|
-
for (let i = 0; i + 1 < argv.length; i++) {
|
|
9229
|
-
const tok = argv[i];
|
|
9230
|
-
if (tok === "-c" || tok === "--cmd") return argv[i + 1] ?? null;
|
|
9231
|
-
}
|
|
9232
|
-
return null;
|
|
9233
|
-
}
|
|
9234
|
-
function detectUnbalancedShellSyntax(cmd) {
|
|
9235
|
-
let inSingle = false;
|
|
9236
|
-
let inDouble = false;
|
|
9237
|
-
let i = 0;
|
|
9238
|
-
while (i < cmd.length) {
|
|
9239
|
-
const ch = cmd[i];
|
|
9240
|
-
if (inSingle) {
|
|
9241
|
-
if (ch === "'") {
|
|
9242
|
-
inSingle = false;
|
|
9243
|
-
}
|
|
9244
|
-
i++;
|
|
9245
|
-
continue;
|
|
9246
|
-
}
|
|
9247
|
-
if (inDouble) {
|
|
9248
|
-
if (ch === "\\" && i + 1 < cmd.length) {
|
|
9249
|
-
i += 2;
|
|
9250
|
-
continue;
|
|
9251
|
-
}
|
|
9252
|
-
if (ch === '"') {
|
|
9253
|
-
inDouble = false;
|
|
9254
|
-
}
|
|
9255
|
-
i++;
|
|
9256
|
-
continue;
|
|
9257
|
-
}
|
|
9258
|
-
if (ch === "\\" && i + 1 < cmd.length) {
|
|
9259
|
-
i += 2;
|
|
9260
|
-
continue;
|
|
9261
|
-
}
|
|
9262
|
-
if (ch === "$" && cmd[i + 1] === "(" && cmd[i + 2] === "(") {
|
|
9263
|
-
let depth = 2;
|
|
9264
|
-
let j = i + 3;
|
|
9265
|
-
while (j < cmd.length && depth > 0) {
|
|
9266
|
-
if (cmd[j] === "(") depth++;
|
|
9267
|
-
else if (cmd[j] === ")") depth--;
|
|
9268
|
-
j++;
|
|
9269
|
-
}
|
|
9270
|
-
i = j;
|
|
9271
|
-
continue;
|
|
9272
|
-
}
|
|
9273
|
-
if (ch === "$" && cmd[i + 1] === "'") {
|
|
9274
|
-
let j = i + 2;
|
|
9275
|
-
let closed = false;
|
|
9276
|
-
while (j < cmd.length) {
|
|
9277
|
-
if (cmd[j] === "\\") {
|
|
9278
|
-
j += 2;
|
|
9279
|
-
continue;
|
|
9280
|
-
}
|
|
9281
|
-
if (cmd[j] === "'") {
|
|
9282
|
-
j++;
|
|
9283
|
-
closed = true;
|
|
9284
|
-
break;
|
|
9285
|
-
}
|
|
9286
|
-
j++;
|
|
9287
|
-
}
|
|
9288
|
-
if (!closed) {
|
|
9289
|
-
inSingle = true;
|
|
9290
|
-
break;
|
|
9291
|
-
}
|
|
9292
|
-
i = j;
|
|
9293
|
-
continue;
|
|
9294
|
-
}
|
|
9295
|
-
if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
|
|
9296
|
-
const nl2 = cmd.indexOf("\n", i);
|
|
9297
|
-
i = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9298
|
-
continue;
|
|
9299
|
-
}
|
|
9300
|
-
if (ch === "'") {
|
|
9301
|
-
inSingle = true;
|
|
9302
|
-
i++;
|
|
9303
|
-
continue;
|
|
9304
|
-
}
|
|
9305
|
-
if (ch === '"') {
|
|
9306
|
-
inDouble = true;
|
|
9307
|
-
i++;
|
|
9308
|
-
continue;
|
|
9309
|
-
}
|
|
9310
|
-
if (ch === "<" && i + 1 < cmd.length && cmd[i + 1] === "<") {
|
|
9311
|
-
if (i + 2 < cmd.length && cmd[i + 2] === "<") {
|
|
9312
|
-
i += 3;
|
|
9313
|
-
continue;
|
|
9314
|
-
}
|
|
9315
|
-
let j = i + 2;
|
|
9316
|
-
let hasIndentModifier = false;
|
|
9317
|
-
if (j < cmd.length && (cmd[j] === "-" || cmd[j] === "~")) {
|
|
9318
|
-
hasIndentModifier = true;
|
|
9319
|
-
j++;
|
|
9320
|
-
}
|
|
9321
|
-
while (j < cmd.length && cmd[j] === " ") {
|
|
9322
|
-
j++;
|
|
9323
|
-
}
|
|
9324
|
-
if (j < cmd.length) {
|
|
9325
|
-
let delimStart = j;
|
|
9326
|
-
if (cmd[j] === '"' || cmd[j] === "'") {
|
|
9327
|
-
delimStart = j + 1;
|
|
9328
|
-
const quoteChar = cmd[j];
|
|
9329
|
-
let delimEnd = delimStart;
|
|
9330
|
-
while (delimEnd < cmd.length && cmd[delimEnd] !== quoteChar) {
|
|
9331
|
-
delimEnd++;
|
|
9332
|
-
}
|
|
9333
|
-
if (delimEnd >= cmd.length) {
|
|
9334
|
-
return "an unclosed quote in a heredoc opener";
|
|
9335
|
-
}
|
|
9336
|
-
j = delimEnd + 1;
|
|
9337
|
-
} else {
|
|
9338
|
-
let delimEnd = delimStart;
|
|
9339
|
-
while (delimEnd < cmd.length && /\w/.test(cmd.charAt(delimEnd))) {
|
|
9340
|
-
delimEnd++;
|
|
9341
|
-
}
|
|
9342
|
-
j = delimEnd;
|
|
9343
|
-
}
|
|
9344
|
-
const delimiter = cmd.slice(delimStart, j).replace(/["']/g, "");
|
|
9345
|
-
if (delimiter) {
|
|
9346
|
-
let scanPos = j;
|
|
9347
|
-
let terminatorEnd = -1;
|
|
9348
|
-
while (scanPos <= cmd.length) {
|
|
9349
|
-
const nl2 = cmd.indexOf("\n", scanPos);
|
|
9350
|
-
const lineEnd = nl2 === -1 ? cmd.length : nl2;
|
|
9351
|
-
let line = cmd.slice(scanPos, lineEnd);
|
|
9352
|
-
if (line.endsWith("\r")) {
|
|
9353
|
-
line = line.slice(0, -1);
|
|
9354
|
-
}
|
|
9355
|
-
const isMatch = hasIndentModifier ? line.trim() === delimiter : line === delimiter;
|
|
9356
|
-
if (isMatch) {
|
|
9357
|
-
terminatorEnd = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9358
|
-
break;
|
|
9359
|
-
}
|
|
9360
|
-
if (nl2 === -1) break;
|
|
9361
|
-
scanPos = nl2 + 1;
|
|
9362
|
-
}
|
|
9363
|
-
if (terminatorEnd === -1) {
|
|
9364
|
-
return `an unterminated heredoc (${delimiter} never appears on its own line)`;
|
|
9365
|
-
}
|
|
9366
|
-
i = terminatorEnd;
|
|
9367
|
-
continue;
|
|
9368
|
-
}
|
|
9369
|
-
}
|
|
9370
|
-
}
|
|
9371
|
-
i++;
|
|
9372
|
-
}
|
|
9373
|
-
if (inSingle) {
|
|
9374
|
-
return "an unclosed single quote";
|
|
9375
|
-
}
|
|
9376
|
-
if (inDouble) {
|
|
9377
|
-
return "an unclosed double quote";
|
|
9378
|
-
}
|
|
9379
|
-
return null;
|
|
9380
|
-
}
|
|
9381
9424
|
function preBashHandlerInner(event) {
|
|
9382
9425
|
const rawCmd = extractCommand(event);
|
|
9383
9426
|
if (rawCmd === void 0) return passOutput();
|
|
@@ -9408,7 +9451,7 @@ function preBashHandlerInner(event) {
|
|
|
9408
9451
|
}
|
|
9409
9452
|
const toolResults = extractToolResultsFile(cmd);
|
|
9410
9453
|
if (toolResults !== null) {
|
|
9411
|
-
const
|
|
9454
|
+
const outPath = displaySafePath(toolResults.path);
|
|
9412
9455
|
recordStat("session_hint", 0, 0);
|
|
9413
9456
|
return contextOutput(
|
|
9414
9457
|
"Tool output " + outPath + ' is a plain-text artifact. Use `token-goat bash-output --file "' + outPath + '"` to read it with surgical narrowing via `--grep PATTERN` or `--tail N`, instead of reading the whole file.'
|
|
@@ -9440,6 +9483,15 @@ function preBashHandlerInner(event) {
|
|
|
9440
9483
|
"Use `token-goat outline <file>` to see symbol names and line counts without loading files."
|
|
9441
9484
|
);
|
|
9442
9485
|
}
|
|
9486
|
+
const terminalXml = extractTerminalXmlParsing(cmd);
|
|
9487
|
+
if (terminalXml !== null) {
|
|
9488
|
+
const { filePath, toolOrScript } = terminalXml;
|
|
9489
|
+
recordStat("session_hint", 0, 0);
|
|
9490
|
+
const target = filePath ? displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath) : "<file>";
|
|
9491
|
+
return contextOutput(
|
|
9492
|
+
`token-goat available for this file type, consider 'token-goat xml-query "${target}" "<xpath>"' or 'token-goat xml-outline "${target}"' first instead of terminal XML parsing (${toolOrScript}).`
|
|
9493
|
+
);
|
|
9494
|
+
}
|
|
9443
9495
|
const singleLineRangeRead = extractLineRangeRead(cmd);
|
|
9444
9496
|
const sedReads = singleLineRangeRead !== null ? [singleLineRangeRead] : extractLineRangeReadsCompound(cmd);
|
|
9445
9497
|
if (sedReads !== null) {
|
|
@@ -9466,17 +9518,17 @@ function preBashHandlerInner(event) {
|
|
|
9466
9518
|
}
|
|
9467
9519
|
const gcTailResult = extractGetContentTail(cmd);
|
|
9468
9520
|
if (gcTailResult !== null) {
|
|
9469
|
-
const { filePath, isDoc, isConfig, isSql } = gcTailResult;
|
|
9521
|
+
const { filePath, isDoc, isConfig, isSql, isXml } = gcTailResult;
|
|
9470
9522
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9471
9523
|
recordStat("session_hint", 0, 0);
|
|
9472
|
-
return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
9524
|
+
return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql, isXml));
|
|
9473
9525
|
}
|
|
9474
9526
|
const gcSelectResult = extractGetContentSelectFirst(cmd);
|
|
9475
9527
|
if (gcSelectResult !== null) {
|
|
9476
|
-
const { filePath, isDoc, isConfig, isSql, n } = gcSelectResult;
|
|
9528
|
+
const { filePath, isDoc, isConfig, isSql, isXml, n } = gcSelectResult;
|
|
9477
9529
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9478
9530
|
recordStat("session_hint", 0, 0);
|
|
9479
|
-
return contextOutput(leadingLinesHint("`Select-Object -First` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql }, preHookCwd));
|
|
9531
|
+
return contextOutput(leadingLinesHint("`Select-Object -First` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql, isXml }, preHookCwd));
|
|
9480
9532
|
}
|
|
9481
9533
|
const catJsonPipe = extractCatJsonPipe(cmd);
|
|
9482
9534
|
if (catJsonPipe !== null) {
|
|
@@ -9489,7 +9541,7 @@ function preBashHandlerInner(event) {
|
|
|
9489
9541
|
}
|
|
9490
9542
|
const catResult = extractCatFile(cmd);
|
|
9491
9543
|
if (catResult !== null) {
|
|
9492
|
-
const { filePath, isDoc, isEnv, isConfig, isSql, cmd0, advisoryOnly } = catResult;
|
|
9544
|
+
const { filePath, isDoc, isEnv, isConfig, isSql, isXml, cmd0, advisoryOnly } = catResult;
|
|
9493
9545
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9494
9546
|
recordStat("session_hint", 0, 0);
|
|
9495
9547
|
if (isSql) {
|
|
@@ -9497,16 +9549,16 @@ function preBashHandlerInner(event) {
|
|
|
9497
9549
|
"`" + cmd0 + '` loads the entire file into context. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
9498
9550
|
);
|
|
9499
9551
|
}
|
|
9500
|
-
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
9552
|
+
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
|
|
9501
9553
|
return cdStripped || advisoryOnly ? contextOutput("`" + cmd0 + "` loads the entire file into context. " + hint) : denyOutput("`" + cmd0 + "` loads the entire file into context. " + hint);
|
|
9502
9554
|
}
|
|
9503
9555
|
const catMulti = extractCatFilesMulti(cmd);
|
|
9504
9556
|
if (catMulti !== null) {
|
|
9505
9557
|
recordStat("session_hint", 0, 0);
|
|
9506
9558
|
const cmd0 = catMulti[0].cmd0;
|
|
9507
|
-
const perPath = catMulti.map(({ filePath, isDoc, isEnv, isConfig, isSql }) => {
|
|
9559
|
+
const perPath = catMulti.map(({ filePath, isDoc, isEnv, isConfig, isSql, isXml }) => {
|
|
9508
9560
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9509
|
-
const how = isSql ? 'token-goat section "' + hintPath + '::table_name"' : isEnv || isConfig ? 'token-goat config-get "' + hintPath + '" KEY_NAME' : isDoc ? 'token-goat section "' + hintPath + '::SectionHeading"' : 'token-goat read "' + hintPath + '::SymbolName"';
|
|
9561
|
+
const how = isXml ? 'token-goat xml-outline "' + hintPath + '" or token-goat xml-query "' + hintPath + '" "<selector>"' : isSql ? 'token-goat section "' + hintPath + '::table_name"' : isEnv || isConfig ? 'token-goat config-get "' + hintPath + '" KEY_NAME' : isDoc ? 'token-goat section "' + hintPath + '::SectionHeading"' : 'token-goat read "' + hintPath + '::SymbolName"';
|
|
9510
9562
|
return " " + hintPath + " -> `" + how + "`";
|
|
9511
9563
|
});
|
|
9512
9564
|
const msg = "`" + cmd0 + "` on multiple files loads them all into context. Read each surgically instead:\n" + perPath.join("\n");
|
|
@@ -9514,19 +9566,19 @@ function preBashHandlerInner(event) {
|
|
|
9514
9566
|
}
|
|
9515
9567
|
const psGetContentResult = extractPowerShellWrappedGetContent(cmd, event);
|
|
9516
9568
|
if (psGetContentResult !== null) {
|
|
9517
|
-
const { filePath, isDoc, isEnv, isConfig, isSql } = psGetContentResult;
|
|
9569
|
+
const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = psGetContentResult;
|
|
9518
9570
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9519
9571
|
recordStat("session_hint", 0, 0);
|
|
9520
9572
|
const lead = "`Get-Content` via a `powershell -Command` wrapper bypasses read hooks and loads the entire file into context. ";
|
|
9521
9573
|
if (isSql) {
|
|
9522
9574
|
return contextOutput(lead + 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.');
|
|
9523
9575
|
}
|
|
9524
|
-
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
9576
|
+
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
|
|
9525
9577
|
return cdStripped ? contextOutput(lead + hint) : denyOutput(lead + hint);
|
|
9526
9578
|
}
|
|
9527
9579
|
const wslCatResult = extractWslCatFile(cmd);
|
|
9528
9580
|
if (wslCatResult !== null) {
|
|
9529
|
-
const { filePath, isDoc, isEnv, isConfig, isSql } = wslCatResult;
|
|
9581
|
+
const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = wslCatResult;
|
|
9530
9582
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9531
9583
|
recordStat("session_hint", 0, 0);
|
|
9532
9584
|
if (isSql) {
|
|
@@ -9534,12 +9586,12 @@ function preBashHandlerInner(event) {
|
|
|
9534
9586
|
'`cat` loads the entire file into context. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
9535
9587
|
);
|
|
9536
9588
|
}
|
|
9537
|
-
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
9589
|
+
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
|
|
9538
9590
|
return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
|
|
9539
9591
|
}
|
|
9540
9592
|
const pyRead = extractPythonFileRead(cmd);
|
|
9541
9593
|
if (pyRead !== null) {
|
|
9542
|
-
const { filePath, isDoc, isConfig, isEnv, isSql, isOutputFile } = pyRead;
|
|
9594
|
+
const { filePath, isDoc, isConfig, isEnv, isSql, isXml, isOutputFile } = pyRead;
|
|
9543
9595
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9544
9596
|
recordStat("session_hint", 0, 0);
|
|
9545
9597
|
if (isOutputFile) {
|
|
@@ -9556,22 +9608,22 @@ function preBashHandlerInner(event) {
|
|
|
9556
9608
|
'Python `open()` file reads bypass read hooks. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
9557
9609
|
);
|
|
9558
9610
|
}
|
|
9559
|
-
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
9611
|
+
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
|
|
9560
9612
|
return cdStripped ? contextOutput("Python `open()` file reads bypass read hooks. " + hint) : denyOutput("Python `open()` file reads bypass read hooks. " + hint);
|
|
9561
9613
|
}
|
|
9562
9614
|
const tailResult = extractTailFile(cmd);
|
|
9563
9615
|
if (tailResult !== null) {
|
|
9564
|
-
const { filePath, isDoc, isConfig, isSql } = tailResult;
|
|
9616
|
+
const { filePath, isDoc, isConfig, isSql, isXml } = tailResult;
|
|
9565
9617
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9566
9618
|
recordStat("session_hint", 0, 0);
|
|
9567
|
-
return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
9619
|
+
return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql, isXml));
|
|
9568
9620
|
}
|
|
9569
9621
|
const headResult = extractHeadFile(cmd);
|
|
9570
9622
|
if (headResult !== null) {
|
|
9571
|
-
const { filePath, isDoc, isConfig, isSql, n } = headResult;
|
|
9623
|
+
const { filePath, isDoc, isConfig, isSql, isXml, n } = headResult;
|
|
9572
9624
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9573
9625
|
recordStat("session_hint", 0, 0);
|
|
9574
|
-
return contextOutput(leadingLinesHint("`head` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql }, preHookCwd));
|
|
9626
|
+
return contextOutput(leadingLinesHint("`head` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql, isXml }, preHookCwd));
|
|
9575
9627
|
}
|
|
9576
9628
|
const nodeRead = extractNodeFileRead(cmd);
|
|
9577
9629
|
if (nodeRead !== null) {
|
|
@@ -9588,14 +9640,14 @@ function preBashHandlerInner(event) {
|
|
|
9588
9640
|
}
|
|
9589
9641
|
const psMethodRead = extractPowerShellFileMethodRead(cmd, event);
|
|
9590
9642
|
if (psMethodRead !== null) {
|
|
9591
|
-
const { filePath, isDoc, isEnv, isConfig, isSql } = psMethodRead;
|
|
9643
|
+
const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = psMethodRead;
|
|
9592
9644
|
const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
|
|
9593
9645
|
const lead = "PowerShell `[IO.File]::ReadAllText()` bypasses read hooks. ";
|
|
9594
9646
|
if (isSql) {
|
|
9595
9647
|
recordStat("session_hint", 0, 0);
|
|
9596
9648
|
return contextOutput(lead + 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.');
|
|
9597
9649
|
}
|
|
9598
|
-
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
9650
|
+
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
|
|
9599
9651
|
recordStat("session_hint", 0, 0);
|
|
9600
9652
|
return cdStripped ? contextOutput(lead + hint) : denyOutput(lead + hint);
|
|
9601
9653
|
}
|
|
@@ -9659,7 +9711,7 @@ function preBashHandlerInner(event) {
|
|
|
9659
9711
|
const prevResolvedPath = prevPath !== null && commandPathIsTouchable(prevPath, event) ? resolveIndexPath(prevPath, preHookCwd ?? process.cwd()) : null;
|
|
9660
9712
|
if (prevPath !== null && prevResolvedPath !== null && !existsSync(prevResolvedPath)) {
|
|
9661
9713
|
clearCurlDownload(curlDl.url);
|
|
9662
|
-
} else if (prevPath !== null && prevResolvedPath !== null &&
|
|
9714
|
+
} else if (prevPath !== null && prevResolvedPath !== null && statSync6(prevResolvedPath).size >= loadConfig().hints.bash_dedup_min_bytes) {
|
|
9663
9715
|
recordStat("session_hint", 0, 0);
|
|
9664
9716
|
return denyOutput(
|
|
9665
9717
|
"Already downloaded to " + prevPath + " earlier this session. Use `rg '<pattern>' " + prevPath + '` to search it, or `token-goat read "' + prevPath + '::SectionName"` to read a part of it.'
|
|
@@ -9767,15 +9819,25 @@ function extractExitCode(raw) {
|
|
|
9767
9819
|
return null;
|
|
9768
9820
|
}
|
|
9769
9821
|
var GH_SECURITY_PATHS = ["/security_advisories", "/advisories", "security_events"];
|
|
9770
|
-
var GH_SCOPE_PHRASES = [
|
|
9822
|
+
var GH_SCOPE_PHRASES = [
|
|
9823
|
+
"Must have push access",
|
|
9824
|
+
"Resource not accessible by integration",
|
|
9825
|
+
"Must be an admin",
|
|
9826
|
+
"You are not authorized to perform this operation"
|
|
9827
|
+
];
|
|
9828
|
+
var GH_NOT_FOUND = /^gh: .*\(HTTP 404\)|"status":\s*"404"/m;
|
|
9771
9829
|
function buildGhApiHint(cmd, stdout, exitCode) {
|
|
9772
9830
|
if (stdout === "" || !cmd.startsWith("gh api")) return null;
|
|
9773
9831
|
const hints = [];
|
|
9774
9832
|
const isSecurityPath = GH_SECURITY_PATHS.some((p) => cmd.includes(p));
|
|
9775
9833
|
const hasScopePhrase = GH_SCOPE_PHRASES.some((p) => stdout.includes(p));
|
|
9776
|
-
const
|
|
9777
|
-
if (hasScopePhrase
|
|
9834
|
+
const ambiguousSecurity404 = exitCode !== null && exitCode !== 0 && isSecurityPath && GH_NOT_FOUND.test(stdout);
|
|
9835
|
+
if (hasScopePhrase) {
|
|
9778
9836
|
hints.push("[token-goat] GitHub API scope issue: try gh auth refresh -s security_events");
|
|
9837
|
+
} else if (ambiguousSecurity404) {
|
|
9838
|
+
hints.push(
|
|
9839
|
+
"[token-goat] GitHub answers 404 both for a resource that does not exist and for one your token cannot see: check the owner/repo spelling, then gh auth status for the security_events scope."
|
|
9840
|
+
);
|
|
9779
9841
|
}
|
|
9780
9842
|
const trimmed = stdout.trimStart();
|
|
9781
9843
|
if (trimmed.startsWith("{")) {
|
|
@@ -9849,6 +9911,7 @@ async function postBashHandler(event) {
|
|
|
9849
9911
|
try {
|
|
9850
9912
|
const rawCmdRaw = extractCommand(event);
|
|
9851
9913
|
if (rawCmdRaw === void 0) return passOutput();
|
|
9914
|
+
const isUnwrapped = unwrapCompressCommand(rawCmdRaw) === null;
|
|
9852
9915
|
const rawCmd = unwrapCompressCommand(rawCmdRaw) ?? rawCmdRaw;
|
|
9853
9916
|
const cmd = stripCdPrefix(rawCmd);
|
|
9854
9917
|
const output = extractBashOutput(event.raw);
|
|
@@ -9932,13 +9995,19 @@ async function postBashHandler(event) {
|
|
|
9932
9995
|
const gitScopedCacheId = await storeBashOutput(cmd, output, exitCode ?? 0, cwd);
|
|
9933
9996
|
recordBashOutput(gitScopedCacheHash, gitScopedCacheId, Buffer.byteLength(output, "utf-8"));
|
|
9934
9997
|
}
|
|
9998
|
+
if (isUnwrapped && /^git(?:\s+-[^\s]+|\s+--[^\s]+)*\s+diff\b/i.test(cmd)) {
|
|
9999
|
+
const unwrappedCompressed = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped);
|
|
10000
|
+
if (unwrappedCompressed !== null) return unwrappedCompressed;
|
|
10001
|
+
}
|
|
9935
10002
|
const isMonitoring = getMonitoringRecallHint(cmd) !== null;
|
|
9936
10003
|
const isFileRead = pureFileReadPath(cmd) !== null;
|
|
9937
10004
|
if (isFileRead || !isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) {
|
|
9938
10005
|
const identical = await maybeCollapseIdenticalRead(cmd, rawCmd, output, exitCode, cwd, cacheMinBytes);
|
|
9939
10006
|
if (identical !== null) return identical;
|
|
9940
|
-
|
|
9941
|
-
|
|
10007
|
+
if (!isFileRead && (!isUnwrapped || !isCompressibleSingleCommand(cmd))) {
|
|
10008
|
+
const compound = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped);
|
|
10009
|
+
if (compound !== null) return compound;
|
|
10010
|
+
}
|
|
9942
10011
|
if (!isFileRead && extractLineRangeReadsCompound(cmd) === null) {
|
|
9943
10012
|
const genericElision = await maybeElideServedGenericOutput(cmd, output, exitCode, cwd, cacheMinBytes);
|
|
9944
10013
|
if (genericElision !== null) return genericElision;
|
|
@@ -10151,7 +10220,7 @@ registerHook("post_tool_use", postTaskOutputHandler, { toolName: "TaskOutput" })
|
|
|
10151
10220
|
|
|
10152
10221
|
// src/hooks_tool_failure.ts
|
|
10153
10222
|
init_define_import_meta_env();
|
|
10154
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, statSync as
|
|
10223
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, statSync as statSync7, writeFileSync as writeFileSync2 } from "node:fs";
|
|
10155
10224
|
import { dirname as dirname2, relative } from "node:path";
|
|
10156
10225
|
var FAILURE_SUFFIX = ".tool-failures.json";
|
|
10157
10226
|
var MAX_TRACKED_FAILURES = 64;
|
|
@@ -10220,7 +10289,7 @@ function diagnoseEditFailure(event, errorText) {
|
|
|
10220
10289
|
const absPath = normalizePath(filePath);
|
|
10221
10290
|
if (!existsSync2(absPath)) return null;
|
|
10222
10291
|
try {
|
|
10223
|
-
const stat =
|
|
10292
|
+
const stat = statSync7(absPath);
|
|
10224
10293
|
if (stat.size > MAX_EDIT_DIAGNOSE_BYTES) return null;
|
|
10225
10294
|
const fileContent = readFileSync3(absPath, "utf8");
|
|
10226
10295
|
const relDisplay = displaySafeText(relative(process.cwd(), absPath).replace(/\\/g, "/") || absPath);
|
|
@@ -10279,6 +10348,7 @@ function postToolUseFailureHandler(event) {
|
|
|
10279
10348
|
const ledger = readLedger(target);
|
|
10280
10349
|
const priorState = ledger.seen[signature];
|
|
10281
10350
|
const editDiagnostic = diagnoseEditFailure(event, errorText);
|
|
10351
|
+
const sqlDiagnostic = diagnoseSqlFailure(event, errorText);
|
|
10282
10352
|
if (priorState === void 0) {
|
|
10283
10353
|
ledger.seen[signature] = false;
|
|
10284
10354
|
ledger.order.push(signature);
|
|
@@ -10292,6 +10362,11 @@ function postToolUseFailureHandler(event) {
|
|
|
10292
10362
|
writeLedger(target, ledger);
|
|
10293
10363
|
return contextOutput(editDiagnostic);
|
|
10294
10364
|
}
|
|
10365
|
+
if (sqlDiagnostic !== null) {
|
|
10366
|
+
ledger.seen[signature] = true;
|
|
10367
|
+
writeLedger(target, ledger);
|
|
10368
|
+
return contextOutput(sqlDiagnostic);
|
|
10369
|
+
}
|
|
10295
10370
|
return passOutput();
|
|
10296
10371
|
}
|
|
10297
10372
|
if (priorState) return passOutput();
|
|
@@ -10300,6 +10375,9 @@ function postToolUseFailureHandler(event) {
|
|
|
10300
10375
|
if (editDiagnostic !== null) {
|
|
10301
10376
|
return contextOutput(editDiagnostic);
|
|
10302
10377
|
}
|
|
10378
|
+
if (sqlDiagnostic !== null) {
|
|
10379
|
+
return contextOutput(sqlDiagnostic);
|
|
10380
|
+
}
|
|
10303
10381
|
return contextOutput(repeatFailureNotice(toolName));
|
|
10304
10382
|
} catch {
|
|
10305
10383
|
return passOutput();
|
|
@@ -10576,6 +10654,37 @@ function compressGithubMcpResult(toolName, resultText) {
|
|
|
10576
10654
|
const stripped = deepStrip(parsed, githubShouldStrip);
|
|
10577
10655
|
return finishWithGenericPass(resultText, stripped);
|
|
10578
10656
|
}
|
|
10657
|
+
var ATLASSIAN_TOOL_RE = /(?:jira|confluence|atlassian)/i;
|
|
10658
|
+
var ATLASSIAN_STRIP_EXACT_KEYS = /* @__PURE__ */ new Set([
|
|
10659
|
+
"avatarUrls",
|
|
10660
|
+
"avatarUrl",
|
|
10661
|
+
"iconUrl",
|
|
10662
|
+
"iconUrls",
|
|
10663
|
+
"self",
|
|
10664
|
+
"expand",
|
|
10665
|
+
"schema",
|
|
10666
|
+
"operations",
|
|
10667
|
+
"editmeta",
|
|
10668
|
+
"names",
|
|
10669
|
+
"_links",
|
|
10670
|
+
"_expandable",
|
|
10671
|
+
"extensions",
|
|
10672
|
+
"timeZone"
|
|
10673
|
+
]);
|
|
10674
|
+
function atlassianShouldStrip(key) {
|
|
10675
|
+
return ATLASSIAN_STRIP_EXACT_KEYS.has(key);
|
|
10676
|
+
}
|
|
10677
|
+
function compressAtlassianMcpResult(toolName, resultText) {
|
|
10678
|
+
if (!ATLASSIAN_TOOL_RE.test(toolName)) return null;
|
|
10679
|
+
let parsed;
|
|
10680
|
+
try {
|
|
10681
|
+
parsed = JSON.parse(resultText);
|
|
10682
|
+
} catch {
|
|
10683
|
+
return null;
|
|
10684
|
+
}
|
|
10685
|
+
const stripped = deepStrip(parsed, atlassianShouldStrip);
|
|
10686
|
+
return finishWithGenericPass(resultText, stripped);
|
|
10687
|
+
}
|
|
10579
10688
|
var BROWSER_TOOL_RE = /^mcp__.*(?:chrome-devtools|claude-in-chrome|playwright).*__/i;
|
|
10580
10689
|
var BROWSER_CONSOLE_METHOD_RE = /(?:^|_)(?:read|list)_console_messages$/i;
|
|
10581
10690
|
var BROWSER_NETWORK_METHOD_RE = /(?:^|_)(?:read|list)_network_requests$/i;
|
|
@@ -10726,10 +10835,11 @@ function stripBase64DataUrls(resultText) {
|
|
|
10726
10835
|
function compressMcpResultWithPacks(toolName, resultText) {
|
|
10727
10836
|
const base64Stripped = stripBase64DataUrls(resultText);
|
|
10728
10837
|
const text = base64Stripped ?? resultText;
|
|
10729
|
-
return compressGithubMcpResult(toolName, text) ?? compressBrowserMcpResult(toolName, text) ?? compressGWorkspaceMcpResult(toolName, text) ?? base64Stripped;
|
|
10838
|
+
return compressGithubMcpResult(toolName, text) ?? compressAtlassianMcpResult(toolName, text) ?? compressBrowserMcpResult(toolName, text) ?? compressGWorkspaceMcpResult(toolName, text) ?? base64Stripped;
|
|
10730
10839
|
}
|
|
10731
10840
|
|
|
10732
10841
|
// src/hooks_mcp.ts
|
|
10842
|
+
var MCP_OVERSIZED_THRESHOLD_BYTES = 25e3;
|
|
10733
10843
|
function preMcpHandler(event) {
|
|
10734
10844
|
const toolName = getToolName(event);
|
|
10735
10845
|
if (!toolName || !event.sessionId) return passOutput();
|
|
@@ -10787,9 +10897,15 @@ function postMcpHandler(event) {
|
|
|
10787
10897
|
minNetSavingsBytes: resolveMinNetSavingsBytes()
|
|
10788
10898
|
});
|
|
10789
10899
|
if (worthwhile) {
|
|
10900
|
+
const bodyBytes = Buffer.byteLength(redactedBody, "utf-8");
|
|
10901
|
+
let finalBody = redactedBody;
|
|
10902
|
+
if (bodyBytes >= MCP_OVERSIZED_THRESHOLD_BYTES) {
|
|
10903
|
+
const preview = clipToDeliveryCap(redactedBody, Buffer.byteLength(notice, "utf-8") + 500);
|
|
10904
|
+
finalBody = preview.text + (preview.clipped ? "\n\n...[preview truncated by token-goat; use mcp-output above to query full payload]..." : "");
|
|
10905
|
+
}
|
|
10790
10906
|
return preserve(
|
|
10791
10907
|
emitRewrite(
|
|
10792
|
-
`${notice}${fenceWithMatches(
|
|
10908
|
+
`${notice}${fenceWithMatches(finalBody, injectionMatches, UNTRUSTED_TOOL_TAG)}`,
|
|
10793
10909
|
"mcp",
|
|
10794
10910
|
{ kind: "mcp:compress", originalBytes }
|
|
10795
10911
|
)
|
|
@@ -10798,6 +10914,29 @@ function postMcpHandler(event) {
|
|
|
10798
10914
|
}
|
|
10799
10915
|
}
|
|
10800
10916
|
}
|
|
10917
|
+
const rawBytes = Buffer.byteLength(resultText, "utf-8");
|
|
10918
|
+
if (rawBytes >= MCP_OVERSIZED_THRESHOLD_BYTES && process.env["TOKEN_GOAT_MCP_COMPRESS"] !== "0") {
|
|
10919
|
+
if (id === null) id = storeMcpOutput(event.sessionId, toolName, toolInput, resultText);
|
|
10920
|
+
if (id !== null) {
|
|
10921
|
+
const notice = `[token-goat: oversized MCP result (${rawBytes} bytes) cached as ${id}]
|
|
10922
|
+
The full payload was cached to prevent harness context spill. Slicing commands:
|
|
10923
|
+
token-goat mcp-output ${id} --json-query '<path>' (e.g. 'issues[*].key', 'values[*].id')
|
|
10924
|
+
token-goat mcp-output ${id} --section '<heading>'
|
|
10925
|
+
token-goat mcp-output ${id} --grep '<regex>' --max-matches 20
|
|
10926
|
+
token-goat mcp-output ${id} --head 50
|
|
10927
|
+
|
|
10928
|
+
`;
|
|
10929
|
+
const preview = clipToDeliveryCap(redactedResult.text, Buffer.byteLength(notice, "utf-8") + 500);
|
|
10930
|
+
const previewBody = preview.text + (preview.clipped ? "\n\n...[preview truncated by token-goat; use mcp-output above to query full payload]..." : "");
|
|
10931
|
+
return preserve(
|
|
10932
|
+
emitRewrite(
|
|
10933
|
+
`${notice}${fenceWithMatches(previewBody, injectionMatches, UNTRUSTED_TOOL_TAG)}`,
|
|
10934
|
+
"mcp",
|
|
10935
|
+
{ kind: "mcp:oversized", originalBytes: rawBytes }
|
|
10936
|
+
)
|
|
10937
|
+
);
|
|
10938
|
+
}
|
|
10939
|
+
}
|
|
10801
10940
|
return passOrFence();
|
|
10802
10941
|
}
|
|
10803
10942
|
registerHook("pre_tool_use", preMcpHandler, { toolPattern: "^mcp__" });
|
|
@@ -11419,6 +11558,10 @@ async function relayInProcess(eventName, rawPayload) {
|
|
|
11419
11558
|
if (!process.env["CLAUDE_CODE_SESSION_ID"] && event.sessionId) {
|
|
11420
11559
|
process.env["CLAUDE_CODE_SESSION_ID"] = event.sessionId;
|
|
11421
11560
|
}
|
|
11561
|
+
const rawTranscriptPath = event.raw["transcript_path"];
|
|
11562
|
+
if (typeof rawTranscriptPath === "string" && rawTranscriptPath !== "") {
|
|
11563
|
+
setTranscriptPath(rawTranscriptPath, event.sessionId ?? "");
|
|
11564
|
+
}
|
|
11422
11565
|
if (!process.env["TRACEPARENT"] && event.traceparent) {
|
|
11423
11566
|
process.env["TRACEPARENT"] = event.traceparent;
|
|
11424
11567
|
}
|