token-goat 2.9.13 → 2.9.14
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 +13 -0
- package/dist/token-goat-chunk-2ESBO4IN.mjs +209 -0
- package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
- package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-3XQPEJMV.mjs} +1 -1
- package/dist/token-goat-chunk-4SDX3QP3.mjs +122 -0
- package/dist/token-goat-chunk-7OGKZ7AP.mjs +142 -0
- package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
- package/dist/token-goat-chunk-AMYCQJX4.mjs +1548 -0
- package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-ASVVF4JV.mjs} +10 -7
- package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-DAMXYVIW.mjs} +12026 -11796
- package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-DBNY4RLN.mjs} +2 -2
- package/dist/token-goat-chunk-EG3663UT.mjs +226 -0
- package/dist/token-goat-chunk-EZNVAIR3.mjs +21 -0
- package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
- package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-HF6H7RNK.mjs} +1 -1
- package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-IT6O3PNN.mjs} +2874 -7088
- package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
- package/dist/token-goat-chunk-O5WAMISC.mjs +167 -0
- package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-PGGDW7DZ.mjs} +28 -13
- package/dist/token-goat-chunk-POBYR64E.mjs +1632 -0
- package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-PRJVGIC5.mjs} +6 -4
- package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-RUDOKYPJ.mjs} +10160 -10053
- package/dist/token-goat-chunk-SAQ5PG4L.mjs +2634 -0
- package/dist/{token-goat-chunk-UMXJN7DI.mjs → token-goat-chunk-T2IWWTHB.mjs} +288 -2654
- package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-VZYD4OZB.mjs} +1164 -92
- package/dist/token-goat-chunk-XEH6KBWW.mjs +23 -0
- package/dist/token-goat-chunk-XQF5J25J.mjs +33 -0
- package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
- package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-XVZ4MNQC.mjs} +587 -587
- package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
- package/dist/token-goat-chunk-YHGTGG6K.mjs +396 -0
- package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-YTQHZJXW.mjs} +20 -11
- package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
- package/dist/token-goat-chunk-ZD4EM4LR.mjs +30 -0
- package/dist/token-goat-chunk-ZFM4PWXL.mjs +585 -0
- package/dist/{token-goat-chunk-FQCNJV4V.mjs → token-goat-chunk-ZYNNQ36L.mjs} +116 -330
- package/dist/token-goat-hook.mjs +12 -8
- package/dist/token-goat.core.mjs +22 -10
- package/docs/cli.md +1 -0
- package/package.json +4 -2
- 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
|
@@ -4,31 +4,25 @@ import {
|
|
|
4
4
|
canRunWrappedShell,
|
|
5
5
|
clipToDeliveryCap,
|
|
6
6
|
deliveredOutputBytes
|
|
7
|
-
} from "./token-goat-chunk-
|
|
7
|
+
} from "./token-goat-chunk-3XQPEJMV.mjs";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_RECONCILE_BUDGET_MS,
|
|
10
10
|
HOOK_EVENTS,
|
|
11
|
-
accumulateResidentLines,
|
|
12
11
|
buildCommandManifest,
|
|
13
12
|
checkSymbolBodySize,
|
|
14
13
|
flattenCommandNames,
|
|
15
14
|
getWebOutput,
|
|
16
15
|
isReconcileClean,
|
|
17
|
-
lineMayCarryResidentSignal,
|
|
18
16
|
readStdinJson,
|
|
19
|
-
readTranscriptTail,
|
|
20
17
|
reconcileProject,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
summarizeResidentContext,
|
|
24
|
-
taskListPruneHint
|
|
25
|
-
} from "./token-goat-chunk-FQCNJV4V.mjs";
|
|
18
|
+
storeWebOutput
|
|
19
|
+
} from "./token-goat-chunk-ZYNNQ36L.mjs";
|
|
26
20
|
import {
|
|
27
|
-
BASH_OUTPUT_SUBDIR,
|
|
28
21
|
GENERIC_SERVED_OUTPUT_KEY,
|
|
29
22
|
OUTLINE_MAX_REPLACEMENT_RATIO,
|
|
30
23
|
OUTLINE_MIN_HEADINGS,
|
|
31
24
|
WEB_FETCH_KEY_SEP,
|
|
25
|
+
accumulateResidentLines,
|
|
32
26
|
appendDirtyPath,
|
|
33
27
|
applyHintTracking,
|
|
34
28
|
buildDeltaCapsule,
|
|
@@ -36,10 +30,8 @@ import {
|
|
|
36
30
|
classifyBashHint,
|
|
37
31
|
classifyEditHint,
|
|
38
32
|
clearCurlDownload,
|
|
39
|
-
commandHash,
|
|
40
33
|
compactPathFor,
|
|
41
34
|
computeAdaptiveBudget,
|
|
42
|
-
countSymbols,
|
|
43
35
|
enqueueDirtyPathSafe,
|
|
44
36
|
ensureWorkerAlive,
|
|
45
37
|
extractCompactFromMarker,
|
|
@@ -53,7 +45,6 @@ import {
|
|
|
53
45
|
formatHeadingTreeParts,
|
|
54
46
|
formatProjectMap,
|
|
55
47
|
formatShrinkSummary,
|
|
56
|
-
getBashOutput,
|
|
57
48
|
getBashOutputId,
|
|
58
49
|
getContextPressure,
|
|
59
50
|
getCurlDownloadPath,
|
|
@@ -61,7 +52,6 @@ import {
|
|
|
61
52
|
getFileServedOutputs,
|
|
62
53
|
getGlobMatchCount,
|
|
63
54
|
getGrepMatchCount,
|
|
64
|
-
getMonitoringRecallHint,
|
|
65
55
|
getOutstandingAgentSpawns,
|
|
66
56
|
getSessionBashOutputs,
|
|
67
57
|
getSessionBashReruns,
|
|
@@ -71,15 +61,11 @@ import {
|
|
|
71
61
|
hasSessionOutput,
|
|
72
62
|
imageQualifiesForShrink,
|
|
73
63
|
incrementSkillHit,
|
|
74
|
-
indexRecallEntry,
|
|
75
64
|
indexServedBody,
|
|
76
65
|
installedSkillPath,
|
|
77
|
-
isBashEntryStale,
|
|
78
|
-
isBuildCommand,
|
|
79
|
-
isScopedGitStatusOrDiffStatCommand,
|
|
80
66
|
isStructuralRewriteAccepted,
|
|
81
|
-
isTestRunnerCommand,
|
|
82
67
|
lastTabContextMatches,
|
|
68
|
+
lineMayCarryResidentSignal,
|
|
83
69
|
listSiblingSessionStates,
|
|
84
70
|
loadSessionCache,
|
|
85
71
|
loadSessionState,
|
|
@@ -96,6 +82,7 @@ import {
|
|
|
96
82
|
planSourceSkeleton,
|
|
97
83
|
preToolPathDeclined,
|
|
98
84
|
probeImageMeta,
|
|
85
|
+
readTranscriptTail,
|
|
99
86
|
recordBashOutput,
|
|
100
87
|
recordBashRerun,
|
|
101
88
|
recordCliRead,
|
|
@@ -113,29 +100,34 @@ import {
|
|
|
113
100
|
recordSymbolRead,
|
|
114
101
|
recordWebFetch,
|
|
115
102
|
removeOutstandingAgentSpawn,
|
|
103
|
+
repeatedSkillBodyHint,
|
|
116
104
|
saveSessionState,
|
|
117
105
|
scanAndRecord,
|
|
118
106
|
servedRunNotice,
|
|
119
107
|
sessionOutputBodyBytes,
|
|
120
108
|
sessionSidecarPath,
|
|
121
109
|
setLastTabContext,
|
|
110
|
+
setTranscriptPath,
|
|
122
111
|
shrinkImage,
|
|
123
|
-
storeBashOutput,
|
|
124
112
|
storeOutput,
|
|
125
|
-
|
|
113
|
+
summarizeResidentContext,
|
|
126
114
|
takePendingLargeFileHint,
|
|
115
|
+
taskListPruneHint,
|
|
127
116
|
visionTokens,
|
|
128
117
|
visionTokensSaved,
|
|
129
118
|
vscodePathAllowed,
|
|
130
119
|
wasCliReadThisSession,
|
|
131
120
|
wasFileReadThisSession,
|
|
132
121
|
wasHintShown
|
|
133
|
-
} from "./token-goat-chunk-
|
|
122
|
+
} from "./token-goat-chunk-IT6O3PNN.mjs";
|
|
134
123
|
import {
|
|
124
|
+
BASH_OUTPUT_SUBDIR,
|
|
135
125
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
136
126
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
127
|
+
commandHash,
|
|
137
128
|
compressOutput,
|
|
138
129
|
contextOutput,
|
|
130
|
+
countSymbols,
|
|
139
131
|
dedupeConsecutive,
|
|
140
132
|
denyOutput,
|
|
141
133
|
detectFromCommand,
|
|
@@ -145,14 +137,22 @@ import {
|
|
|
145
137
|
extractToolResponseField,
|
|
146
138
|
extractToolResultText,
|
|
147
139
|
filterByName,
|
|
140
|
+
getBashOutput,
|
|
148
141
|
getCwd,
|
|
149
142
|
getFilePath,
|
|
143
|
+
getMonitoringRecallHint,
|
|
150
144
|
getToolInput,
|
|
151
145
|
getToolName,
|
|
146
|
+
getTranscriptPath,
|
|
152
147
|
hasBareBackgroundOrNewline,
|
|
153
148
|
hasUnquotedOperator,
|
|
149
|
+
indexRecallEntry,
|
|
150
|
+
isBashEntryStale,
|
|
151
|
+
isBuildCommand,
|
|
154
152
|
isMcpErrorResponse,
|
|
155
153
|
isRewriteWorthwhile,
|
|
154
|
+
isScopedGitStatusOrDiffStatCommand,
|
|
155
|
+
isTestRunnerCommand,
|
|
156
156
|
isTextualContentBlock,
|
|
157
157
|
makeDedupHintHandlers,
|
|
158
158
|
mcpContentBlocks,
|
|
@@ -166,28 +166,30 @@ import {
|
|
|
166
166
|
sessionStateKey,
|
|
167
167
|
shlexSplit,
|
|
168
168
|
splitOwnTrailingNotices,
|
|
169
|
+
storeBashOutput,
|
|
170
|
+
summarizeOutputDelta,
|
|
169
171
|
withPreservedBlocks
|
|
170
|
-
} from "./token-goat-chunk-
|
|
172
|
+
} from "./token-goat-chunk-VZYD4OZB.mjs";
|
|
171
173
|
import {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
detectLanguage,
|
|
175
|
+
getDb,
|
|
176
|
+
languageHasFlag,
|
|
177
|
+
recordStat,
|
|
178
|
+
redactSecrets,
|
|
179
|
+
savedTokensFromBytes,
|
|
180
|
+
storeBlob,
|
|
181
|
+
stripAnsiEscapes
|
|
182
|
+
} from "./token-goat-chunk-T2IWWTHB.mjs";
|
|
174
183
|
import {
|
|
175
184
|
detectHarness,
|
|
176
|
-
detectLanguage,
|
|
177
185
|
envBool,
|
|
178
186
|
envInt,
|
|
179
187
|
findProject,
|
|
180
|
-
getDb,
|
|
181
188
|
getHarnessName,
|
|
182
189
|
isUnderSystemTemp,
|
|
183
|
-
languageHasFlag,
|
|
184
190
|
loadConfig,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
savedTokensFromBytes,
|
|
188
|
-
shortFingerprint,
|
|
189
|
-
stripAnsiEscapes
|
|
190
|
-
} from "./token-goat-chunk-UMXJN7DI.mjs";
|
|
191
|
+
shortFingerprint
|
|
192
|
+
} from "./token-goat-chunk-SAQ5PG4L.mjs";
|
|
191
193
|
import {
|
|
192
194
|
ENV_KEYS,
|
|
193
195
|
IDENTICAL_READ_MIN_BODY_BYTES,
|
|
@@ -214,7 +216,7 @@ import {
|
|
|
214
216
|
runGit,
|
|
215
217
|
toDisplayPath,
|
|
216
218
|
toKB
|
|
217
|
-
} from "./token-goat-chunk-
|
|
219
|
+
} from "./token-goat-chunk-AMYCQJX4.mjs";
|
|
218
220
|
import {
|
|
219
221
|
init_define_import_meta_env
|
|
220
222
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -747,7 +749,7 @@ function mergeManifestFiles(parent, siblingFiles) {
|
|
|
747
749
|
}
|
|
748
750
|
return Array.from(byPath.values());
|
|
749
751
|
}
|
|
750
|
-
function buildManifest(sessionId, cwd) {
|
|
752
|
+
function buildManifest(sessionId, cwd, transcriptPath) {
|
|
751
753
|
const ownFiles = [...getSessionFiles().values()];
|
|
752
754
|
const siblingFiles = sessionId !== void 0 ? listSiblingSessionStates(sessionId).flatMap((s) => s.files) : [];
|
|
753
755
|
const files = siblingFiles.length > 0 ? mergeManifestFiles(ownFiles, siblingFiles) : ownFiles;
|
|
@@ -779,7 +781,7 @@ function buildManifest(sessionId, cwd) {
|
|
|
779
781
|
);
|
|
780
782
|
lines.push(...buildSafeToDiscardSection(files));
|
|
781
783
|
lines.push(...buildMemEpochSection());
|
|
782
|
-
return capManifestChars(lines.join("\n"), sessionId, cwd);
|
|
784
|
+
return capManifestChars(lines.join("\n"), sessionId, cwd, transcriptPath);
|
|
783
785
|
}
|
|
784
786
|
function gitDirtySignals(cwd) {
|
|
785
787
|
const timeoutMs = loadConfig().hints.git_hint_max_ms;
|
|
@@ -797,11 +799,11 @@ function gitDirtySignals(cwd) {
|
|
|
797
799
|
}
|
|
798
800
|
return { hasPendingDiff, hasUncommittedChanges };
|
|
799
801
|
}
|
|
800
|
-
function adaptiveCharBonus(sessionId, cwd) {
|
|
802
|
+
function adaptiveCharBonus(sessionId, cwd, transcriptPath) {
|
|
801
803
|
if (!cwd) return 0;
|
|
802
804
|
const cache = loadSessionCache(sessionId ?? "") ?? {};
|
|
803
805
|
const ageSecs = cache.created_ts !== void 0 ? Math.max(0, Date.now() / 1e3 - cache.created_ts) : 0;
|
|
804
|
-
const contextPressure = getContextPressure(cache);
|
|
806
|
+
const contextPressure = getContextPressure(cache, transcriptPath);
|
|
805
807
|
const { hasPendingDiff, hasUncommittedChanges } = gitDirtySignals(cwd);
|
|
806
808
|
if (!hasPendingDiff && !hasUncommittedChanges) return 0;
|
|
807
809
|
const baseline = computeAdaptiveBudget(cache, ageSecs, { contextPressure });
|
|
@@ -809,11 +811,11 @@ function adaptiveCharBonus(sessionId, cwd) {
|
|
|
809
811
|
const deltaTokens = Math.max(0, withGitSignal - baseline);
|
|
810
812
|
return deltaTokens * 3;
|
|
811
813
|
}
|
|
812
|
-
function capManifestChars(manifest, sessionId, cwd) {
|
|
814
|
+
function capManifestChars(manifest, sessionId, cwd, transcriptPath) {
|
|
813
815
|
const cap = loadConfig().compact_assist.max_manifest_chars;
|
|
814
816
|
if (cap <= 0) return manifest;
|
|
815
817
|
if (manifest.length <= cap) return manifest;
|
|
816
|
-
const effectiveCap = cap + adaptiveCharBonus(sessionId, cwd);
|
|
818
|
+
const effectiveCap = cap + adaptiveCharBonus(sessionId, cwd, transcriptPath);
|
|
817
819
|
if (manifest.length <= effectiveCap) return manifest;
|
|
818
820
|
const omitted = manifest.length - effectiveCap;
|
|
819
821
|
return manifest.slice(0, effectiveCap) + `
|
|
@@ -886,7 +888,7 @@ function summaryBudgetDirective(budgetChars) {
|
|
|
886
888
|
function preCompactHandler(event) {
|
|
887
889
|
const out = loadConfig().compact_assist.enabled ? contextOutput(`${MANIFEST_PREAMBLE}${summaryBudgetDirective(loadConfig().compact_assist.summary_budget_chars)}
|
|
888
890
|
|
|
889
|
-
${buildManifest(event.sessionId, getCwd(event))}`) : passOutput();
|
|
891
|
+
${buildManifest(event.sessionId, getCwd(event), getTranscriptPath(event))}`) : passOutput();
|
|
890
892
|
markCompacted();
|
|
891
893
|
return out;
|
|
892
894
|
}
|
|
@@ -934,7 +936,7 @@ init_define_import_meta_env();
|
|
|
934
936
|
var TRACKED_SKILL = "token-goat";
|
|
935
937
|
var MAX_COMMANDS_SHOWN = 8;
|
|
936
938
|
async function currentCommandNames() {
|
|
937
|
-
const { buildProgram } = await import("./token-goat-chunk-
|
|
939
|
+
const { buildProgram } = await import("./token-goat-chunk-O5WAMISC.mjs");
|
|
938
940
|
return flattenCommandNames(buildCommandManifest(buildProgram()));
|
|
939
941
|
}
|
|
940
942
|
async function recordSkillVersionSnapshot(sessionId, skillName) {
|
|
@@ -7645,115 +7647,21 @@ registerHook("post_tool_use", postSkillHandler, { toolName: "Skill" });
|
|
|
7645
7647
|
|
|
7646
7648
|
// src/hooks_bash.ts
|
|
7647
7649
|
init_define_import_meta_env();
|
|
7648
|
-
import { statSync as
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
}
|
|
7658
|
-
function hasTestRunScopeOrBudget(cmd) {
|
|
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
|
-
}
|
|
7650
|
+
import { statSync as statSync6, existsSync } from "node:fs";
|
|
7651
|
+
|
|
7652
|
+
// src/hooks_bash_commands.ts
|
|
7653
|
+
init_define_import_meta_env();
|
|
7654
|
+
import { statSync as statSync5 } from "node:fs";
|
|
7655
|
+
|
|
7656
|
+
// src/bash_extractors.ts
|
|
7657
|
+
init_define_import_meta_env();
|
|
7658
|
+
import { statSync as statSync4, openSync as openSync2, readSync, closeSync as closeSync2 } from "node:fs";
|
|
7687
7659
|
function surgicalHintFor(hintPath, isEnv, isConfig, isDoc) {
|
|
7688
7660
|
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
7661
|
}
|
|
7690
7662
|
function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql) {
|
|
7691
7663
|
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
7664
|
}
|
|
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;
|
|
7746
|
-
}
|
|
7747
|
-
var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
|
|
7748
|
-
var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
|
|
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);
|
|
7756
|
-
}
|
|
7757
7665
|
function splitShellSegments(cmd) {
|
|
7758
7666
|
const segments = [];
|
|
7759
7667
|
let cur = "";
|
|
@@ -7786,174 +7694,38 @@ function splitShellSegments(cmd) {
|
|
|
7786
7694
|
segments.push(cur);
|
|
7787
7695
|
return segments.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
7788
7696
|
}
|
|
7789
|
-
function
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
function segmentCommandIs(segment, name2) {
|
|
7797
|
-
return new RegExp("^\\s*(?:\\S*[/\\\\])?" + name2 + "(?:\\.exe)?\\b", "i").test(segment);
|
|
7697
|
+
function isTempPath(fp) {
|
|
7698
|
+
const norm = fp.replace(/\\/g, "/");
|
|
7699
|
+
return /^\/tmp\//i.test(norm) || /\/var\/folders\//i.test(norm) || // Anchored to a local drive root on purpose. Unanchored, this clause said yes to
|
|
7700
|
+
// `//host/share/AppData/Local/Temp/x.md`, and the caller's answer to yes is to stat the path --
|
|
7701
|
+
// which on Windows opens an SMB session to whatever host a command named. A temp directory is
|
|
7702
|
+
// somewhere on a local volume; nothing that starts with two separators is one.
|
|
7703
|
+
/^[a-z]:\/(?:[^/]+\/)*AppData\/Local\/Temp\//i.test(norm) || norm.startsWith("/c/Users/") && norm.includes("/AppData/Local/Temp/") || isUnderSystemTemp(fp);
|
|
7798
7704
|
}
|
|
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;
|
|
7705
|
+
function isOrchestratorStateFile(filePath) {
|
|
7706
|
+
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7707
|
+
return /^\.improve-state-/.test(basename3);
|
|
7826
7708
|
}
|
|
7827
|
-
function
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
if (tokens === null) return [];
|
|
7831
|
-
return tokens.slice(1).filter((t) => t.length > 0 && !t.startsWith("-"));
|
|
7709
|
+
function extractCatSourceFile(cmd) {
|
|
7710
|
+
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);
|
|
7711
|
+
return m?.[1] ?? null;
|
|
7832
7712
|
}
|
|
7833
|
-
function
|
|
7834
|
-
const
|
|
7835
|
-
const
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7713
|
+
function classifyFileExtensions(filePath) {
|
|
7714
|
+
const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
7715
|
+
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename3);
|
|
7716
|
+
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);
|
|
7717
|
+
if (!hasKnownExt && !isEnvFile) return null;
|
|
7718
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
7719
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7720
|
+
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
7721
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7722
|
+
return { isDoc, isEnv, isConfig, isSql };
|
|
7842
7723
|
}
|
|
7843
|
-
function
|
|
7844
|
-
const
|
|
7845
|
-
|
|
7846
|
-
const
|
|
7847
|
-
|
|
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 };
|
|
7724
|
+
function classifyDocConfig(filePath) {
|
|
7725
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
7726
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
7727
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
7728
|
+
return { isDoc, isConfig, isSql };
|
|
7957
7729
|
}
|
|
7958
7730
|
function classifyCatPath(filePath, cmd0) {
|
|
7959
7731
|
if (isTempPath(filePath)) return null;
|
|
@@ -8824,21 +8596,504 @@ function buildRecallHint(cmd, outputId) {
|
|
|
8824
8596
|
if (isTscCommand(cmd)) {
|
|
8825
8597
|
return "Output from a prior `" + cmdPreview + "` run is cached. Use `token-goat bash-output " + outputId + ' --grep "error TS"` to filter TypeScript errors, or `--grep "Cannot find"` for missing module errors.';
|
|
8826
8598
|
}
|
|
8827
|
-
if (isDevServerCommand(cmd)) {
|
|
8828
|
-
return "Dev server output cached (`" + cmdPreview + "`). Use `token-goat bash-output " + outputId + ' --tail 20` to see the latest output, or `--grep "error\\|warn"` to filter issues.';
|
|
8599
|
+
if (isDevServerCommand(cmd)) {
|
|
8600
|
+
return "Dev server output cached (`" + cmdPreview + "`). Use `token-goat bash-output " + outputId + ' --tail 20` to see the latest output, or `--grep "error\\|warn"` to filter issues.';
|
|
8601
|
+
}
|
|
8602
|
+
return "Output from a prior `" + cmdPreview + "` run is cached. Use `token-goat bash-output " + outputId + "` (or `--tail 50`, `--grep ERROR`) to re-inspect it without re-running.";
|
|
8603
|
+
}
|
|
8604
|
+
function shellQuoteSingle(s) {
|
|
8605
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
8606
|
+
}
|
|
8607
|
+
function isCompressibleSingleCommand(cmd) {
|
|
8608
|
+
if (!cmd || cmd.length > 65536) return false;
|
|
8609
|
+
if (["$(", "`"].some((op) => cmd.includes(op))) return false;
|
|
8610
|
+
if (hasUnquotedOperator(cmd, ["&&", "||", "|", ";", "<", ">"])) return false;
|
|
8611
|
+
if (hasBareBackgroundOrNewline(cmd)) return false;
|
|
8612
|
+
return true;
|
|
8613
|
+
}
|
|
8614
|
+
|
|
8615
|
+
// src/hooks_bash_commands.ts
|
|
8616
|
+
var CD_PREFIX_RE = /^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)[ \t]*(?:&&|;|\r?\n)\s*)+/;
|
|
8617
|
+
function stripCdPrefix(cmd) {
|
|
8618
|
+
const stripped = cmd.replace(CD_PREFIX_RE, "");
|
|
8619
|
+
return stripped.trim() || cmd;
|
|
8620
|
+
}
|
|
8621
|
+
function stripTrailingStderrRedirect(cmd) {
|
|
8622
|
+
const stripped = cmd.replace(/\s*2>&1\s*$/, "");
|
|
8623
|
+
return stripped.trim() || cmd;
|
|
8624
|
+
}
|
|
8625
|
+
function hasTestRunScopeOrBudget(cmd) {
|
|
8626
|
+
const hasTimeout = /(?:^|\s)(?:timeout(?:\.exe)?\s+\S+|--(?:test)?timeout(?:=|\s)\S+)/i.test(cmd);
|
|
8627
|
+
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);
|
|
8628
|
+
return hasTimeout || hasSelector;
|
|
8629
|
+
}
|
|
8630
|
+
function isDirectTestRunnerCommand(cmd) {
|
|
8631
|
+
return /^(?:pytest|(?:npx\s+)?(?:jest|vitest)|go\s+test|cargo\s+test)\b/i.test(cmd);
|
|
8632
|
+
}
|
|
8633
|
+
function extractCdPrefixDirs(rawCmd) {
|
|
8634
|
+
const prefixMatch = rawCmd.match(CD_PREFIX_RE);
|
|
8635
|
+
if (prefixMatch === null) return [];
|
|
8636
|
+
const dirs = [];
|
|
8637
|
+
const segmentPattern = /cd\s+(?:"([^"]*)"|'([^']*)'|(\S+))[ \t]*(?:&&|;|\r?\n)/g;
|
|
8638
|
+
let match;
|
|
8639
|
+
while ((match = segmentPattern.exec(prefixMatch[0])) !== null) {
|
|
8640
|
+
const dir = match[1] ?? match[2] ?? match[3];
|
|
8641
|
+
if (dir !== void 0) dirs.push(dir);
|
|
8642
|
+
}
|
|
8643
|
+
return dirs;
|
|
8644
|
+
}
|
|
8645
|
+
function resolveCdHintPath(rawCmd, filePath, cwd) {
|
|
8646
|
+
if (extractCdPrefixDirs(rawCmd).length === 0) return filePath;
|
|
8647
|
+
return resolveIndexPath(filePath, cdPrefixCwd(rawCmd, cwd));
|
|
8648
|
+
}
|
|
8649
|
+
function cdPrefixCwd(rawCmd, cwd) {
|
|
8650
|
+
let dir = cwd;
|
|
8651
|
+
for (const target of extractCdPrefixDirs(rawCmd)) dir = resolveIndexPath(target, dir);
|
|
8652
|
+
return dir;
|
|
8653
|
+
}
|
|
8654
|
+
function stripOutputPipeline(cmd) {
|
|
8655
|
+
let inSingle = false;
|
|
8656
|
+
let inDouble = false;
|
|
8657
|
+
let cut = cmd.length;
|
|
8658
|
+
let backslashes = 0;
|
|
8659
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
8660
|
+
const ch = cmd[i];
|
|
8661
|
+
if (ch === "\\") {
|
|
8662
|
+
backslashes++;
|
|
8663
|
+
continue;
|
|
8664
|
+
}
|
|
8665
|
+
const escaped = backslashes % 2 === 1;
|
|
8666
|
+
backslashes = 0;
|
|
8667
|
+
if (ch === "'" && !inDouble) {
|
|
8668
|
+
if (!escaped) inSingle = !inSingle;
|
|
8669
|
+
} else if (ch === '"' && !inSingle) {
|
|
8670
|
+
if (!escaped) inDouble = !inDouble;
|
|
8671
|
+
} else if (ch === "|" && !inSingle && !inDouble) {
|
|
8672
|
+
if (cmd[i + 1] === "|") {
|
|
8673
|
+
i++;
|
|
8674
|
+
continue;
|
|
8675
|
+
}
|
|
8676
|
+
cut = i;
|
|
8677
|
+
break;
|
|
8678
|
+
}
|
|
8679
|
+
}
|
|
8680
|
+
let base = cmd.slice(0, cut);
|
|
8681
|
+
let prev;
|
|
8682
|
+
do {
|
|
8683
|
+
prev = base;
|
|
8684
|
+
const masked = base.replace(/"((?:[^"\\]|\\.)*)"/g, (_m, inner) => '"' + " ".repeat(inner.length) + '"').replace(/'([^']*)'/g, (_m, inner) => "'" + " ".repeat(inner.length) + "'");
|
|
8685
|
+
const newMasked = masked.replace(/\s*(?:[0-9]*>&[0-9]+|[0-9&]*>>?\s*(?:"[^"]*"|'[^']*'|[^\s|]+))\s*$/, "");
|
|
8686
|
+
if (newMasked.length < masked.length) {
|
|
8687
|
+
base = base.slice(0, newMasked.length);
|
|
8688
|
+
}
|
|
8689
|
+
} while (base !== prev);
|
|
8690
|
+
return base.trim();
|
|
8691
|
+
}
|
|
8692
|
+
function pipelineDivergenceNote(cmd, entryCommand) {
|
|
8693
|
+
if (entryCommand === cmd) return "";
|
|
8694
|
+
const preview = entryCommand.length > 60 ? entryCommand.slice(0, 57) + "..." : entryCommand;
|
|
8695
|
+
return " (cached from a differently-piped run, `" + preview + "` \u2014 verify it covers what you need before trusting it)";
|
|
8696
|
+
}
|
|
8697
|
+
function extractCommand(event) {
|
|
8698
|
+
const cmd = event.toolInput["command"];
|
|
8699
|
+
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
8700
|
+
}
|
|
8701
|
+
var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick)\b/i;
|
|
8702
|
+
var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:\S.*?\s)?--(?:\s|$)/i;
|
|
8703
|
+
function isHeadMovingGitCommand(cmd) {
|
|
8704
|
+
if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
|
|
8705
|
+
if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
|
|
8706
|
+
return true;
|
|
8707
|
+
}
|
|
8708
|
+
var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
|
|
8709
|
+
var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
|
|
8710
|
+
var GIT_RESTORE_RE = /^\s*git\s+restore\b/i;
|
|
8711
|
+
var GIT_RESTORE_STAGED_ONLY_RE = /(?:^|\s)(?:--staged|-S)(?:\s|$)/;
|
|
8712
|
+
var GIT_STASH_APPLY_RE = /^\s*git\s+stash\s+(?:pop|apply)\b/i;
|
|
8713
|
+
var PATCH_APPLY_SEGMENT_RE = /^\s*(?:\S*[/\\])?(?:git\s+apply|patch)\b/i;
|
|
8714
|
+
var PATCH_APPLY_INSPECT_ONLY_RE = /(?:^|\s)--(?:check|stat|numstat|summary|dry-run)(?:\s|=|$)/i;
|
|
8715
|
+
function isFormatterWriteSegment(segment) {
|
|
8716
|
+
return /(?:^|\s|[/\\])(?:prettier|eslint)\b/i.test(segment) && /(?:^|\s)--(?:write|fix)(?:\s|$)/i.test(segment);
|
|
8717
|
+
}
|
|
8718
|
+
function safeShlexSplit(segment) {
|
|
8719
|
+
try {
|
|
8720
|
+
return shlexSplit(segment);
|
|
8721
|
+
} catch {
|
|
8722
|
+
return null;
|
|
8723
|
+
}
|
|
8724
|
+
}
|
|
8725
|
+
function segmentCommandIs(segment, name2) {
|
|
8726
|
+
return new RegExp("^\\s*(?:\\S*[/\\\\])?" + name2 + "(?:\\.exe)?\\b", "i").test(segment);
|
|
8727
|
+
}
|
|
8728
|
+
function extractSedInPlaceFiles(segment) {
|
|
8729
|
+
if (!segmentCommandIs(segment, "sed")) return [];
|
|
8730
|
+
const tokens = safeShlexSplit(segment);
|
|
8731
|
+
if (tokens === null) return [];
|
|
8732
|
+
const rest = tokens.slice(1);
|
|
8733
|
+
const inPlaceIdx = rest.findIndex((t) => t === "--in-place" || t.startsWith("--in-place=") || /^-[a-zA-Z]*i/.test(t));
|
|
8734
|
+
if (inPlaceIdx === -1) return [];
|
|
8735
|
+
const files = [];
|
|
8736
|
+
let scriptTaken = rest.some((t) => t === "-e" || t === "-f" || t.startsWith("--expression") || t.startsWith("--file"));
|
|
8737
|
+
for (let i = 0; i < rest.length; i++) {
|
|
8738
|
+
const t = rest[i];
|
|
8739
|
+
if (i === inPlaceIdx) {
|
|
8740
|
+
if (t === "-i" && rest[i + 1] === "") i++;
|
|
8741
|
+
continue;
|
|
8742
|
+
}
|
|
8743
|
+
if (t === "-e" || t === "-f" || t === "--expression" || t === "--file") {
|
|
8744
|
+
i++;
|
|
8745
|
+
continue;
|
|
8746
|
+
}
|
|
8747
|
+
if (t.length > 1 && t.startsWith("-")) continue;
|
|
8748
|
+
if (!scriptTaken) {
|
|
8749
|
+
scriptTaken = true;
|
|
8750
|
+
continue;
|
|
8751
|
+
}
|
|
8752
|
+
files.push(t);
|
|
8753
|
+
}
|
|
8754
|
+
return files;
|
|
8755
|
+
}
|
|
8756
|
+
function extractTeeFiles(segment) {
|
|
8757
|
+
if (!segmentCommandIs(segment, "tee")) return [];
|
|
8758
|
+
const tokens = safeShlexSplit(segment);
|
|
8759
|
+
if (tokens === null) return [];
|
|
8760
|
+
return tokens.slice(1).filter((t) => t.length > 0 && !t.startsWith("-"));
|
|
8761
|
+
}
|
|
8762
|
+
function extractRedirectTargets(segment) {
|
|
8763
|
+
const targets = [];
|
|
8764
|
+
const re = /(?:^|\s)[0-9]?>>?\s*("[^"]*"|'[^']*'|[^\s|&<>]+)/g;
|
|
8765
|
+
let m;
|
|
8766
|
+
while ((m = re.exec(segment)) !== null) {
|
|
8767
|
+
const raw = m[1];
|
|
8768
|
+
targets.push(raw.length >= 2 && (raw[0] === '"' || raw[0] === "'") ? raw.slice(1, -1) : raw);
|
|
8769
|
+
}
|
|
8770
|
+
return targets;
|
|
8771
|
+
}
|
|
8772
|
+
function extractGitRestorePathspecs(cmd) {
|
|
8773
|
+
const m = /^\s*git\s+restore\b(.*)$/i.exec(cmd);
|
|
8774
|
+
if (m === null) return [];
|
|
8775
|
+
const tokens = safeShlexSplit(m[1] ?? "");
|
|
8776
|
+
if (tokens === null) return [];
|
|
8777
|
+
const dashDash = tokens.indexOf("--");
|
|
8778
|
+
if (dashDash !== -1) return tokens.slice(dashDash + 1);
|
|
8779
|
+
const specs = [];
|
|
8780
|
+
let skipNext = false;
|
|
8781
|
+
for (const t of tokens) {
|
|
8782
|
+
if (skipNext) {
|
|
8783
|
+
skipNext = false;
|
|
8784
|
+
continue;
|
|
8785
|
+
}
|
|
8786
|
+
if (t === "-s" || t === "--source") {
|
|
8787
|
+
skipNext = true;
|
|
8788
|
+
continue;
|
|
8789
|
+
}
|
|
8790
|
+
if (t.startsWith("-")) continue;
|
|
8791
|
+
specs.push(t);
|
|
8792
|
+
}
|
|
8793
|
+
return specs;
|
|
8794
|
+
}
|
|
8795
|
+
function gitRepoRoot(gitDir) {
|
|
8796
|
+
const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8797
|
+
return toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : gitDir;
|
|
8798
|
+
}
|
|
8799
|
+
function expandGitPathspecs(specs, gitDir) {
|
|
8800
|
+
if (specs.length === 0) return [];
|
|
8801
|
+
const listed = runGit(["ls-files", "--full-name", "--", ...specs], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8802
|
+
if (listed.exitCode !== 0) return [];
|
|
8803
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
8804
|
+
return listed.stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((rel) => resolveIndexPath(rel, repoRoot));
|
|
8805
|
+
}
|
|
8806
|
+
function workingTreeStatusPaths(gitDir) {
|
|
8807
|
+
const status = runGit(["status", "--porcelain"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
8808
|
+
if (status.exitCode !== 0) return [];
|
|
8809
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
8810
|
+
const out = [];
|
|
8811
|
+
for (const line of status.stdout.split("\n")) {
|
|
8812
|
+
if (line.length < 4) continue;
|
|
8813
|
+
let rel = line.slice(3).trim();
|
|
8814
|
+
if (rel.length === 0) continue;
|
|
8815
|
+
const arrow = rel.lastIndexOf(" -> ");
|
|
8816
|
+
if (arrow !== -1) rel = rel.slice(arrow + 4);
|
|
8817
|
+
if (rel.startsWith('"')) {
|
|
8818
|
+
try {
|
|
8819
|
+
rel = JSON.parse(rel);
|
|
8820
|
+
} catch {
|
|
8821
|
+
continue;
|
|
8822
|
+
}
|
|
8823
|
+
}
|
|
8824
|
+
out.push(resolveIndexPath(rel, repoRoot));
|
|
8825
|
+
}
|
|
8826
|
+
return out;
|
|
8827
|
+
}
|
|
8828
|
+
function enqueueRewrittenPath(absPath) {
|
|
8829
|
+
if (/(?:^|[/\\])(?:NUL|nul)$/.test(absPath) || absPath.replace(/\\/g, "/").endsWith("/dev/null")) return;
|
|
8830
|
+
try {
|
|
8831
|
+
if (!statSync5(absPath).isFile()) return;
|
|
8832
|
+
} catch {
|
|
8833
|
+
return;
|
|
8834
|
+
}
|
|
8835
|
+
enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
|
|
8836
|
+
}
|
|
8837
|
+
function enqueueNonHeadMovingRewrites(cmd, rawCmd, cwd) {
|
|
8838
|
+
const atCwd = (f) => resolveIndexPath(resolveCdHintPath(rawCmd, f, cwd), cwd);
|
|
8839
|
+
const paths = [];
|
|
8840
|
+
let needsStatusSweep = GIT_STASH_APPLY_RE.test(cmd);
|
|
8841
|
+
if (GIT_RESTORE_RE.test(cmd) && !GIT_RESTORE_STAGED_ONLY_RE.test(cmd)) {
|
|
8842
|
+
paths.push(...expandGitPathspecs(extractGitRestorePathspecs(cmd), cwd));
|
|
8843
|
+
}
|
|
8844
|
+
for (const segment of splitShellSegments(cmd)) {
|
|
8845
|
+
if (PATCH_APPLY_SEGMENT_RE.test(segment) && !PATCH_APPLY_INSPECT_ONLY_RE.test(segment)) needsStatusSweep = true;
|
|
8846
|
+
if (isFormatterWriteSegment(segment)) needsStatusSweep = true;
|
|
8847
|
+
for (const f of extractSedInPlaceFiles(segment)) paths.push(atCwd(f));
|
|
8848
|
+
for (const f of extractTeeFiles(segment)) paths.push(atCwd(f));
|
|
8849
|
+
for (const f of extractRedirectTargets(segment)) paths.push(atCwd(f));
|
|
8850
|
+
}
|
|
8851
|
+
if (needsStatusSweep) paths.push(...workingTreeStatusPaths(cwd));
|
|
8852
|
+
for (const p of paths) enqueueRewrittenPath(p);
|
|
8853
|
+
}
|
|
8854
|
+
var PIPELINE_PASSTHROUGH_HEADS = /* @__PURE__ */ new Set(["head", "tail", "cat", "tee", "less", "more"]);
|
|
8855
|
+
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)$/;
|
|
8856
|
+
function isCiBuildTestSegment(cleaned, cwd) {
|
|
8857
|
+
if (isTestRunnerCommand(cleaned) || isBuildCommand(cleaned) || isTscCommand(cleaned)) return true;
|
|
8858
|
+
if (/^\s*(npm|pnpm|yarn|bun)\s+(run\s+)?(test|build|lint|typecheck|check|ci|guards)\b/i.test(cleaned)) return true;
|
|
8859
|
+
if (/^\s*(cargo|go|dotnet|make|gradle|mvn|pytest|vitest|jest|eslint|ruff)\b/i.test(cleaned)) return true;
|
|
8860
|
+
const detected = detectFromCommand(cleaned, cwd ?? void 0);
|
|
8861
|
+
if (detected !== null && CI_FILTER_NAMES.test(detected.filter.name)) return true;
|
|
8862
|
+
return false;
|
|
8863
|
+
}
|
|
8864
|
+
function pipelineShapeFilter(cmd, cwd) {
|
|
8865
|
+
if (hasUnquotedOperator(cmd, ["&&", "||", ";"])) {
|
|
8866
|
+
const forSplit2 = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8867
|
+
if (hasBareBackgroundOrNewline(forSplit2)) return null;
|
|
8868
|
+
const segments2 = splitShellSegments(forSplit2);
|
|
8869
|
+
if (segments2.length >= 2) {
|
|
8870
|
+
let recognizedCiCount = 0;
|
|
8871
|
+
for (const segment of segments2) {
|
|
8872
|
+
const cleaned = stripOutputPipeline(segment.trim());
|
|
8873
|
+
if (cleaned.length === 0) continue;
|
|
8874
|
+
if (isCiBuildTestSegment(cleaned, cwd)) {
|
|
8875
|
+
recognizedCiCount++;
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8878
|
+
if (recognizedCiCount > 0) {
|
|
8879
|
+
return filterByName("generic-ci");
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8882
|
+
return null;
|
|
8883
|
+
}
|
|
8884
|
+
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8885
|
+
if (hasBareBackgroundOrNewline(forSplit)) return null;
|
|
8886
|
+
const segments = splitShellSegments(forSplit);
|
|
8887
|
+
if (segments.length < 2) return null;
|
|
8888
|
+
for (const segment of segments.slice(1)) {
|
|
8889
|
+
const head = safeShlexSplit(segment)?.[0];
|
|
8890
|
+
if (head === void 0) return null;
|
|
8891
|
+
if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
|
|
8892
|
+
}
|
|
8893
|
+
const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
|
|
8894
|
+
return detected === null ? null : detected.filter;
|
|
8895
|
+
}
|
|
8896
|
+
function pureFileReadPath(cmd) {
|
|
8897
|
+
const single = extractCatFile(cmd)?.filePath ?? extractHeadFile(cmd)?.filePath ?? extractTailFile(cmd)?.filePath ?? extractLineRangeRead(cmd)?.filePath;
|
|
8898
|
+
if (single !== void 0) return single;
|
|
8899
|
+
return singleFileCompoundReadPath(cmd);
|
|
8900
|
+
}
|
|
8901
|
+
function singleFileCompoundReadPath(cmd) {
|
|
8902
|
+
const reads = extractLineRangeReadsCompound(cmd);
|
|
8903
|
+
if (reads === null || reads.length !== 1) return null;
|
|
8904
|
+
return reads[0]?.filePath ?? null;
|
|
8905
|
+
}
|
|
8906
|
+
function deliveredLineNumbers(cmd, lineCount) {
|
|
8907
|
+
const ranged = extractLineRangeRead(cmd);
|
|
8908
|
+
if (ranged !== null) {
|
|
8909
|
+
const nums = [];
|
|
8910
|
+
for (const [lo, hi] of ranged.ranges) for (let n = lo; n <= hi; n++) nums.push(n);
|
|
8911
|
+
if (nums.length === 0) return null;
|
|
8912
|
+
while (nums.length < lineCount) nums.push((nums[nums.length - 1] ?? 0) + 1);
|
|
8913
|
+
return nums;
|
|
8914
|
+
}
|
|
8915
|
+
if (extractCatFile(cmd) !== null || extractHeadFile(cmd) !== null) return Array.from({ length: lineCount }, (_, i) => i + 1);
|
|
8916
|
+
if (singleFileCompoundReadPath(cmd) !== null) return Array.from({ length: lineCount }, () => null);
|
|
8917
|
+
return null;
|
|
8918
|
+
}
|
|
8919
|
+
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;
|
|
8920
|
+
function isWholeFileDump(cmd, extractedPath) {
|
|
8921
|
+
const m = WHOLE_FILE_DUMP_RE.exec(cmd);
|
|
8922
|
+
if (m === null) return false;
|
|
8923
|
+
const shaped = m[1] ?? m[2] ?? m[3];
|
|
8924
|
+
return shaped !== void 0 && shaped === extractedPath;
|
|
8925
|
+
}
|
|
8926
|
+
function unwrapCompressCommand(executed) {
|
|
8927
|
+
const t = executed.trim();
|
|
8928
|
+
if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
|
|
8929
|
+
let argv;
|
|
8930
|
+
try {
|
|
8931
|
+
argv = shlexSplit(t);
|
|
8932
|
+
} catch {
|
|
8933
|
+
return null;
|
|
8934
|
+
}
|
|
8935
|
+
for (let i = 0; i + 1 < argv.length; i++) {
|
|
8936
|
+
const tok = argv[i];
|
|
8937
|
+
if (tok === "-c" || tok === "--cmd") return argv[i + 1] ?? null;
|
|
8938
|
+
if (tok === "--cmd-b64") {
|
|
8939
|
+
try {
|
|
8940
|
+
return Buffer.from(argv[i + 1] ?? "", "base64").toString("utf8");
|
|
8941
|
+
} catch {
|
|
8942
|
+
return null;
|
|
8943
|
+
}
|
|
8944
|
+
}
|
|
8945
|
+
}
|
|
8946
|
+
return null;
|
|
8947
|
+
}
|
|
8948
|
+
function detectUnbalancedShellSyntax(cmd) {
|
|
8949
|
+
let inSingle = false;
|
|
8950
|
+
let inDouble = false;
|
|
8951
|
+
let i = 0;
|
|
8952
|
+
while (i < cmd.length) {
|
|
8953
|
+
const ch = cmd[i];
|
|
8954
|
+
if (inSingle) {
|
|
8955
|
+
if (ch === "'") {
|
|
8956
|
+
inSingle = false;
|
|
8957
|
+
}
|
|
8958
|
+
i++;
|
|
8959
|
+
continue;
|
|
8960
|
+
}
|
|
8961
|
+
if (inDouble) {
|
|
8962
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
8963
|
+
i += 2;
|
|
8964
|
+
continue;
|
|
8965
|
+
}
|
|
8966
|
+
if (ch === '"') {
|
|
8967
|
+
inDouble = false;
|
|
8968
|
+
}
|
|
8969
|
+
i++;
|
|
8970
|
+
continue;
|
|
8971
|
+
}
|
|
8972
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
8973
|
+
i += 2;
|
|
8974
|
+
continue;
|
|
8975
|
+
}
|
|
8976
|
+
if (ch === "$" && cmd[i + 1] === "(" && cmd[i + 2] === "(") {
|
|
8977
|
+
let depth = 2;
|
|
8978
|
+
let j = i + 3;
|
|
8979
|
+
while (j < cmd.length && depth > 0) {
|
|
8980
|
+
if (cmd[j] === "(") depth++;
|
|
8981
|
+
else if (cmd[j] === ")") depth--;
|
|
8982
|
+
j++;
|
|
8983
|
+
}
|
|
8984
|
+
i = j;
|
|
8985
|
+
continue;
|
|
8986
|
+
}
|
|
8987
|
+
if (ch === "$" && cmd[i + 1] === "'") {
|
|
8988
|
+
let j = i + 2;
|
|
8989
|
+
let closed = false;
|
|
8990
|
+
while (j < cmd.length) {
|
|
8991
|
+
if (cmd[j] === "\\") {
|
|
8992
|
+
j += 2;
|
|
8993
|
+
continue;
|
|
8994
|
+
}
|
|
8995
|
+
if (cmd[j] === "'") {
|
|
8996
|
+
j++;
|
|
8997
|
+
closed = true;
|
|
8998
|
+
break;
|
|
8999
|
+
}
|
|
9000
|
+
j++;
|
|
9001
|
+
}
|
|
9002
|
+
if (!closed) {
|
|
9003
|
+
inSingle = true;
|
|
9004
|
+
break;
|
|
9005
|
+
}
|
|
9006
|
+
i = j;
|
|
9007
|
+
continue;
|
|
9008
|
+
}
|
|
9009
|
+
if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
|
|
9010
|
+
const nl2 = cmd.indexOf("\n", i);
|
|
9011
|
+
i = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9012
|
+
continue;
|
|
9013
|
+
}
|
|
9014
|
+
if (ch === "'") {
|
|
9015
|
+
inSingle = true;
|
|
9016
|
+
i++;
|
|
9017
|
+
continue;
|
|
9018
|
+
}
|
|
9019
|
+
if (ch === '"') {
|
|
9020
|
+
inDouble = true;
|
|
9021
|
+
i++;
|
|
9022
|
+
continue;
|
|
9023
|
+
}
|
|
9024
|
+
if (ch === "<" && i + 1 < cmd.length && cmd[i + 1] === "<") {
|
|
9025
|
+
if (i + 2 < cmd.length && cmd[i + 2] === "<") {
|
|
9026
|
+
i += 3;
|
|
9027
|
+
continue;
|
|
9028
|
+
}
|
|
9029
|
+
let j = i + 2;
|
|
9030
|
+
let hasIndentModifier = false;
|
|
9031
|
+
if (j < cmd.length && (cmd[j] === "-" || cmd[j] === "~")) {
|
|
9032
|
+
hasIndentModifier = true;
|
|
9033
|
+
j++;
|
|
9034
|
+
}
|
|
9035
|
+
while (j < cmd.length && cmd[j] === " ") {
|
|
9036
|
+
j++;
|
|
9037
|
+
}
|
|
9038
|
+
if (j < cmd.length) {
|
|
9039
|
+
let delimStart = j;
|
|
9040
|
+
if (cmd[j] === '"' || cmd[j] === "'") {
|
|
9041
|
+
delimStart = j + 1;
|
|
9042
|
+
const quoteChar = cmd[j];
|
|
9043
|
+
let delimEnd = delimStart;
|
|
9044
|
+
while (delimEnd < cmd.length && cmd[delimEnd] !== quoteChar) {
|
|
9045
|
+
delimEnd++;
|
|
9046
|
+
}
|
|
9047
|
+
if (delimEnd >= cmd.length) {
|
|
9048
|
+
return "an unclosed quote in a heredoc opener";
|
|
9049
|
+
}
|
|
9050
|
+
j = delimEnd + 1;
|
|
9051
|
+
} else {
|
|
9052
|
+
let delimEnd = delimStart;
|
|
9053
|
+
while (delimEnd < cmd.length && /\w/.test(cmd.charAt(delimEnd))) {
|
|
9054
|
+
delimEnd++;
|
|
9055
|
+
}
|
|
9056
|
+
j = delimEnd;
|
|
9057
|
+
}
|
|
9058
|
+
const delimiter = cmd.slice(delimStart, j).replace(/["']/g, "");
|
|
9059
|
+
if (delimiter) {
|
|
9060
|
+
let scanPos = j;
|
|
9061
|
+
let terminatorEnd = -1;
|
|
9062
|
+
while (scanPos <= cmd.length) {
|
|
9063
|
+
const nl2 = cmd.indexOf("\n", scanPos);
|
|
9064
|
+
const lineEnd = nl2 === -1 ? cmd.length : nl2;
|
|
9065
|
+
let line = cmd.slice(scanPos, lineEnd);
|
|
9066
|
+
if (line.endsWith("\r")) {
|
|
9067
|
+
line = line.slice(0, -1);
|
|
9068
|
+
}
|
|
9069
|
+
const isMatch = hasIndentModifier ? line.trim() === delimiter : line === delimiter;
|
|
9070
|
+
if (isMatch) {
|
|
9071
|
+
terminatorEnd = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
9072
|
+
break;
|
|
9073
|
+
}
|
|
9074
|
+
if (nl2 === -1) break;
|
|
9075
|
+
scanPos = nl2 + 1;
|
|
9076
|
+
}
|
|
9077
|
+
if (terminatorEnd === -1) {
|
|
9078
|
+
return `an unterminated heredoc (${delimiter} never appears on its own line)`;
|
|
9079
|
+
}
|
|
9080
|
+
i = terminatorEnd;
|
|
9081
|
+
continue;
|
|
9082
|
+
}
|
|
9083
|
+
}
|
|
9084
|
+
}
|
|
9085
|
+
i++;
|
|
9086
|
+
}
|
|
9087
|
+
if (inSingle) {
|
|
9088
|
+
return "an unclosed single quote";
|
|
8829
9089
|
}
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
return
|
|
8834
|
-
}
|
|
8835
|
-
function isCompressibleSingleCommand(cmd) {
|
|
8836
|
-
if (!cmd || cmd.length > 65536) return false;
|
|
8837
|
-
if (["$(", "`"].some((op) => cmd.includes(op))) return false;
|
|
8838
|
-
if (hasUnquotedOperator(cmd, ["&&", "||", "|", ";", "<", ">"])) return false;
|
|
8839
|
-
if (hasBareBackgroundOrNewline(cmd)) return false;
|
|
8840
|
-
return true;
|
|
9090
|
+
if (inDouble) {
|
|
9091
|
+
return "an unclosed double quote";
|
|
9092
|
+
}
|
|
9093
|
+
return null;
|
|
8841
9094
|
}
|
|
9095
|
+
|
|
9096
|
+
// src/hooks_bash.ts
|
|
8842
9097
|
function maybeCompressRewrite(event, rawCmd, cmd) {
|
|
8843
9098
|
if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
|
|
8844
9099
|
if (event.raw["_tg_harness"] === "vscode") return null;
|
|
@@ -8864,96 +9119,6 @@ function maybeCompressRewrite(event, rawCmd, cmd) {
|
|
|
8864
9119
|
const wrapped = `token-goat compress -f ${filterName} --timeout ${cfg.timeout_seconds} -c ${shellQuoteSingle(rawCmd)}`;
|
|
8865
9120
|
return { hookType: "rewriteInput", updatedInput: { ...event.toolInput, command: wrapped } };
|
|
8866
9121
|
}
|
|
8867
|
-
var PIPELINE_PASSTHROUGH_HEADS = /* @__PURE__ */ new Set(["head", "tail", "cat", "tee", "less", "more"]);
|
|
8868
|
-
var CI_BUILD_TEST_FILTER_NAMES = /* @__PURE__ */ new Set([
|
|
8869
|
-
"generic-ci",
|
|
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;
|
|
8901
|
-
}
|
|
8902
|
-
function pipelineShapeFilter(cmd, cwd) {
|
|
8903
|
-
if (hasUnquotedOperator(cmd, ["&&", "||", ";"])) {
|
|
8904
|
-
const forSplit2 = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8905
|
-
if (hasBareBackgroundOrNewline(forSplit2)) return null;
|
|
8906
|
-
const segments2 = splitShellSegments(forSplit2);
|
|
8907
|
-
if (segments2.length >= 2) {
|
|
8908
|
-
let recognizedCiCount = 0;
|
|
8909
|
-
for (const segment of segments2) {
|
|
8910
|
-
const cleaned = stripOutputPipeline(segment.trim());
|
|
8911
|
-
if (cleaned.length === 0) continue;
|
|
8912
|
-
if (isCiBuildTestSegment(cleaned, cwd)) {
|
|
8913
|
-
recognizedCiCount++;
|
|
8914
|
-
}
|
|
8915
|
-
}
|
|
8916
|
-
if (recognizedCiCount > 0) {
|
|
8917
|
-
return filterByName("generic-ci");
|
|
8918
|
-
}
|
|
8919
|
-
}
|
|
8920
|
-
return null;
|
|
8921
|
-
}
|
|
8922
|
-
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
8923
|
-
if (hasBareBackgroundOrNewline(forSplit)) return null;
|
|
8924
|
-
const segments = splitShellSegments(forSplit);
|
|
8925
|
-
if (segments.length < 2) return null;
|
|
8926
|
-
for (const segment of segments.slice(1)) {
|
|
8927
|
-
const head = safeShlexSplit(segment)?.[0];
|
|
8928
|
-
if (head === void 0) return null;
|
|
8929
|
-
if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
|
|
8930
|
-
}
|
|
8931
|
-
const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
|
|
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;
|
|
8943
|
-
}
|
|
8944
|
-
function deliveredLineNumbers(cmd, lineCount) {
|
|
8945
|
-
const ranged = extractLineRangeRead(cmd);
|
|
8946
|
-
if (ranged !== null) {
|
|
8947
|
-
const nums = [];
|
|
8948
|
-
for (const [lo, hi] of ranged.ranges) for (let n = lo; n <= hi; n++) nums.push(n);
|
|
8949
|
-
if (nums.length === 0) return null;
|
|
8950
|
-
while (nums.length < lineCount) nums.push((nums[nums.length - 1] ?? 0) + 1);
|
|
8951
|
-
return nums;
|
|
8952
|
-
}
|
|
8953
|
-
if (extractCatFile(cmd) !== null || extractHeadFile(cmd) !== null) return Array.from({ length: lineCount }, (_, i) => i + 1);
|
|
8954
|
-
if (singleFileCompoundReadPath(cmd) !== null) return Array.from({ length: lineCount }, () => null);
|
|
8955
|
-
return null;
|
|
8956
|
-
}
|
|
8957
9122
|
function elideServedShellLines(cmd, output, priorIds, unknownLineNumbers = false) {
|
|
8958
9123
|
if (priorIds.length === 0) return null;
|
|
8959
9124
|
const lines = output.split("\n");
|
|
@@ -9006,19 +9171,12 @@ function foldShellReadBodies(cmd, output, fileKey, cwd) {
|
|
|
9006
9171
|
if (folded === null) return null;
|
|
9007
9172
|
return { text: folded.numbered.join("\n"), folds: folded.folds };
|
|
9008
9173
|
}
|
|
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
9174
|
function foldShellReadStructure(cmd, filePath, output, fileKey, cwd) {
|
|
9017
9175
|
if (!isWholeFileDump(cmd, filePath)) return null;
|
|
9018
9176
|
const originalBytes = Buffer.byteLength(output, "utf-8");
|
|
9019
9177
|
let onDisk;
|
|
9020
9178
|
try {
|
|
9021
|
-
onDisk =
|
|
9179
|
+
onDisk = statSync6(fileKey).size;
|
|
9022
9180
|
} catch {
|
|
9023
9181
|
return null;
|
|
9024
9182
|
}
|
|
@@ -9216,168 +9374,6 @@ function maybeFoldCurlHtml(cmd, output, id) {
|
|
|
9216
9374
|
}
|
|
9217
9375
|
return emitRewrite(notice + fenced, "curl HTML body cleaned", { kind: "bash_compress:curl-html", originalBytes: deliveredOutputBytes(originalBytes) });
|
|
9218
9376
|
}
|
|
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
9377
|
function preBashHandlerInner(event) {
|
|
9382
9378
|
const rawCmd = extractCommand(event);
|
|
9383
9379
|
if (rawCmd === void 0) return passOutput();
|
|
@@ -9408,7 +9404,7 @@ function preBashHandlerInner(event) {
|
|
|
9408
9404
|
}
|
|
9409
9405
|
const toolResults = extractToolResultsFile(cmd);
|
|
9410
9406
|
if (toolResults !== null) {
|
|
9411
|
-
const
|
|
9407
|
+
const outPath = displaySafePath(toolResults.path);
|
|
9412
9408
|
recordStat("session_hint", 0, 0);
|
|
9413
9409
|
return contextOutput(
|
|
9414
9410
|
"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.'
|
|
@@ -9659,7 +9655,7 @@ function preBashHandlerInner(event) {
|
|
|
9659
9655
|
const prevResolvedPath = prevPath !== null && commandPathIsTouchable(prevPath, event) ? resolveIndexPath(prevPath, preHookCwd ?? process.cwd()) : null;
|
|
9660
9656
|
if (prevPath !== null && prevResolvedPath !== null && !existsSync(prevResolvedPath)) {
|
|
9661
9657
|
clearCurlDownload(curlDl.url);
|
|
9662
|
-
} else if (prevPath !== null && prevResolvedPath !== null &&
|
|
9658
|
+
} else if (prevPath !== null && prevResolvedPath !== null && statSync6(prevResolvedPath).size >= loadConfig().hints.bash_dedup_min_bytes) {
|
|
9663
9659
|
recordStat("session_hint", 0, 0);
|
|
9664
9660
|
return denyOutput(
|
|
9665
9661
|
"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.'
|
|
@@ -10151,7 +10147,7 @@ registerHook("post_tool_use", postTaskOutputHandler, { toolName: "TaskOutput" })
|
|
|
10151
10147
|
|
|
10152
10148
|
// src/hooks_tool_failure.ts
|
|
10153
10149
|
init_define_import_meta_env();
|
|
10154
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, statSync as
|
|
10150
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, statSync as statSync7, writeFileSync as writeFileSync2 } from "node:fs";
|
|
10155
10151
|
import { dirname as dirname2, relative } from "node:path";
|
|
10156
10152
|
var FAILURE_SUFFIX = ".tool-failures.json";
|
|
10157
10153
|
var MAX_TRACKED_FAILURES = 64;
|
|
@@ -10220,7 +10216,7 @@ function diagnoseEditFailure(event, errorText) {
|
|
|
10220
10216
|
const absPath = normalizePath(filePath);
|
|
10221
10217
|
if (!existsSync2(absPath)) return null;
|
|
10222
10218
|
try {
|
|
10223
|
-
const stat =
|
|
10219
|
+
const stat = statSync7(absPath);
|
|
10224
10220
|
if (stat.size > MAX_EDIT_DIAGNOSE_BYTES) return null;
|
|
10225
10221
|
const fileContent = readFileSync3(absPath, "utf8");
|
|
10226
10222
|
const relDisplay = displaySafeText(relative(process.cwd(), absPath).replace(/\\/g, "/") || absPath);
|
|
@@ -11419,6 +11415,10 @@ async function relayInProcess(eventName, rawPayload) {
|
|
|
11419
11415
|
if (!process.env["CLAUDE_CODE_SESSION_ID"] && event.sessionId) {
|
|
11420
11416
|
process.env["CLAUDE_CODE_SESSION_ID"] = event.sessionId;
|
|
11421
11417
|
}
|
|
11418
|
+
const rawTranscriptPath = event.raw["transcript_path"];
|
|
11419
|
+
if (typeof rawTranscriptPath === "string" && rawTranscriptPath !== "") {
|
|
11420
|
+
setTranscriptPath(rawTranscriptPath, event.sessionId ?? "");
|
|
11421
|
+
}
|
|
11422
11422
|
if (!process.env["TRACEPARENT"] && event.traceparent) {
|
|
11423
11423
|
process.env["TRACEPARENT"] = event.traceparent;
|
|
11424
11424
|
}
|