token-goat 2.9.29 → 2.9.30
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 +34 -40
- package/SECURITY.md +28 -10
- package/THIRD_PARTY_NOTICES.md +40 -3
- package/dist/native/linux-arm64/tg-hook +0 -0
- package/dist/native/linux-x64/tg-hook +0 -0
- package/dist/ort-wasm-simd-threaded.mjs +59 -0
- package/dist/token-goat-chunk-3CHUNJ2O.mjs +53 -0
- package/dist/token-goat-chunk-3Z5S4KGM.mjs +918 -0
- package/dist/token-goat-chunk-4FVIAHSI.mjs +211 -0
- package/dist/{token-goat-chunk-PGTH2U4C.mjs → token-goat-chunk-4JJS54TR.mjs} +4 -3
- package/dist/token-goat-chunk-4LCCNRTG.mjs +313 -0
- package/dist/{token-goat-chunk-L7H3U27L.mjs → token-goat-chunk-54K3EUV3.mjs} +1 -1
- package/dist/token-goat-chunk-56EIMS3E.mjs +159 -0
- package/dist/token-goat-chunk-5BCIJXMO.mjs +609 -0
- package/dist/token-goat-chunk-5KDMCMF2.mjs +362 -0
- package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
- package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
- package/dist/{token-goat-chunk-GLXRTTLE.mjs → token-goat-chunk-64FBPDTK.mjs} +12 -8
- package/dist/{token-goat-chunk-G23DWHV4.mjs → token-goat-chunk-664RTTUV.mjs} +28 -15
- package/dist/token-goat-chunk-67TQJ76B.mjs +57 -0
- package/dist/token-goat-chunk-6QMAS7AB.mjs +42 -0
- package/dist/token-goat-chunk-7BXSNBY5.mjs +253 -0
- package/dist/{token-goat-chunk-IVWI2OCK.mjs → token-goat-chunk-7F2UBPD3.mjs} +40 -11
- package/dist/{token-goat-chunk-TGOXNAHW.mjs → token-goat-chunk-7IN2MKDS.mjs} +682 -501
- package/dist/token-goat-chunk-7NADEDKJ.mjs +124 -0
- package/dist/{token-goat-chunk-KOPIR3KZ.mjs → token-goat-chunk-A3CK6N5Z.mjs} +618 -72
- package/dist/{token-goat-chunk-O6I2XU4P.mjs → token-goat-chunk-AFLYLHDH.mjs} +44 -31
- package/dist/{token-goat-chunk-TCQANXYC.mjs → token-goat-chunk-AM5V6GSX.mjs} +18 -2
- package/dist/{token-goat-chunk-E4ZOJIZK.mjs → token-goat-chunk-APGZXSPS.mjs} +39 -146
- package/dist/{token-goat-chunk-D4ETHJD6.mjs → token-goat-chunk-ARDNEC2U.mjs} +9 -7
- package/dist/token-goat-chunk-ATCPY7EQ.mjs +134 -0
- package/dist/token-goat-chunk-B2RZZCSS.mjs +354 -0
- package/dist/{token-goat-chunk-BGYOZ6DO.mjs → token-goat-chunk-B45VMIIH.mjs} +6 -7
- package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
- package/dist/{token-goat-chunk-TDUT2CL6.mjs → token-goat-chunk-C63JQV5K.mjs} +45 -6
- package/dist/{token-goat-chunk-ZER6EAXZ.mjs → token-goat-chunk-COBQGL5S.mjs} +2661 -2440
- package/dist/token-goat-chunk-COTXZHTS.mjs +39 -0
- package/dist/{token-goat-chunk-RQGGMPCR.mjs → token-goat-chunk-CYCEYAEO.mjs} +76 -16
- package/dist/token-goat-chunk-CZ3LUXYZ.mjs +4115 -0
- package/dist/{token-goat-chunk-ASLWOQ3I.mjs → token-goat-chunk-DZX2YDPT.mjs} +2 -1
- package/dist/token-goat-chunk-E3OQX2XT.mjs +824 -0
- package/dist/token-goat-chunk-EFHMMIGP.mjs +68 -0
- package/dist/token-goat-chunk-ETBHVDB6.mjs +328 -0
- package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
- package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
- package/dist/{token-goat-chunk-RTMVLHWX.mjs → token-goat-chunk-FBNQNSJK.mjs} +2555 -5127
- package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
- package/dist/{token-goat-chunk-RLP6J7WR.mjs → token-goat-chunk-FZ3NEW5O.mjs} +33 -19
- package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
- package/dist/{token-goat-chunk-DNRPXHYH.mjs → token-goat-chunk-GFBSN7BD.mjs} +29 -401
- package/dist/{token-goat-chunk-XYWPOSCN.mjs → token-goat-chunk-GOLEOXZP.mjs} +763 -211
- package/dist/token-goat-chunk-H2K3QP6H.mjs +24 -0
- package/dist/token-goat-chunk-H2PHHGM5.mjs +188 -0
- package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
- package/dist/token-goat-chunk-HG45AF2B.mjs +2228 -0
- package/dist/{token-goat-chunk-HUYUHODZ.mjs → token-goat-chunk-HOJLCGDP.mjs} +12965 -11748
- package/dist/{token-goat-chunk-435UQTKD.mjs → token-goat-chunk-HYBFA5X3.mjs} +118 -19
- package/dist/token-goat-chunk-IVALLT3S.mjs +48 -0
- package/dist/{token-goat-chunk-UXSXQQIY.mjs → token-goat-chunk-IVKIZWAB.mjs} +3 -3
- package/dist/{token-goat-chunk-52NSDWYY.mjs → token-goat-chunk-JB6QN6VF.mjs} +6 -4
- package/dist/{token-goat-chunk-HNFZZHFW.mjs → token-goat-chunk-JDHE26RP.mjs} +10 -3
- package/dist/{token-goat-chunk-FTP4U4QA.mjs → token-goat-chunk-JDU3EXSU.mjs} +12 -11
- package/dist/token-goat-chunk-JDWCRD6M.mjs +253 -0
- package/dist/{token-goat-chunk-6AK46ZT7.mjs → token-goat-chunk-JN4XMLSD.mjs} +5 -1
- package/dist/token-goat-chunk-JTQQGXZH.mjs +733 -0
- package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
- package/dist/token-goat-chunk-KQNZDCBD.mjs +47 -0
- package/dist/{token-goat-chunk-2WOUYWLM.mjs → token-goat-chunk-KWPNJBDH.mjs} +27 -3
- package/dist/{token-goat-chunk-DPNLUJWB.mjs → token-goat-chunk-LOBGHXPB.mjs} +30 -8
- package/dist/token-goat-chunk-MKPF4CL5.mjs +37 -0
- package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
- package/dist/{token-goat-chunk-DNSPXQXQ.mjs → token-goat-chunk-N2NMER56.mjs} +25 -15
- package/dist/token-goat-chunk-NYKZLXMK.mjs +218 -0
- package/dist/token-goat-chunk-OJBNYTJP.mjs +3087 -0
- package/dist/token-goat-chunk-P4QMM4WK.mjs +295 -0
- package/dist/token-goat-chunk-PD5VKH46.mjs +184 -0
- package/dist/token-goat-chunk-PEPTHRFF.mjs +129 -0
- package/dist/{token-goat-chunk-NMBWLRHW.mjs → token-goat-chunk-PU7V3FD6.mjs} +8721 -11104
- package/dist/token-goat-chunk-PY533T7F.mjs +46 -0
- package/dist/token-goat-chunk-Q5VTGRH7.mjs +761 -0
- package/dist/{token-goat-chunk-67BNIKKO.mjs → token-goat-chunk-QCLDAQTS.mjs} +31 -20
- package/dist/{token-goat-chunk-SE6E4BKJ.mjs → token-goat-chunk-QSBRTGM2.mjs} +9 -2
- package/dist/{token-goat-chunk-VZQEWRVH.mjs → token-goat-chunk-RC35RBUL.mjs} +4 -4
- package/dist/{token-goat-chunk-VMFWNHGR.mjs → token-goat-chunk-RHXKCZX3.mjs} +873 -504
- package/dist/{token-goat-chunk-PYSUADX4.mjs → token-goat-chunk-RZRTDST7.mjs} +17 -7
- package/dist/{token-goat-chunk-ONXH6NZ5.mjs → token-goat-chunk-SJHWVNDQ.mjs} +15 -21
- package/dist/token-goat-chunk-SMVRN2HU.mjs +188 -0
- package/dist/{token-goat-chunk-QO3LXVVR.mjs → token-goat-chunk-SQSSNQPE.mjs} +2295 -1718
- package/dist/{token-goat-chunk-2AWQ2R5X.mjs → token-goat-chunk-T4FK7VOV.mjs} +2 -2
- package/dist/token-goat-chunk-U4N3BN2W.mjs +92 -0
- package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
- package/dist/{token-goat-chunk-UA5BKWWQ.mjs → token-goat-chunk-UQ5UK2T7.mjs} +15 -4
- package/dist/token-goat-chunk-USILZ3T3.mjs +53 -0
- package/dist/{token-goat-chunk-MELOKFDJ.mjs → token-goat-chunk-VES7EL7O.mjs} +7 -1
- package/dist/{token-goat-chunk-7CPMDFGB.mjs → token-goat-chunk-VL3YIFHZ.mjs} +389 -14
- package/dist/{token-goat-chunk-E5TK5DNO.mjs → token-goat-chunk-VPBBTSJR.mjs} +356 -129
- package/dist/{token-goat-chunk-YOOVFPTP.mjs → token-goat-chunk-W3QCJS6G.mjs} +10 -2
- package/dist/{token-goat-chunk-LZNBQTDK.mjs → token-goat-chunk-WY3L4DVT.mjs} +11 -7
- package/dist/token-goat-chunk-XKI4SEMX.mjs +66 -0
- package/dist/token-goat-chunk-XU4P6Z24.mjs +133 -0
- package/dist/{token-goat-chunk-H5J3C56Q.mjs → token-goat-chunk-Y776AENC.mjs} +112 -26
- package/dist/token-goat-chunk-YARZFCZS.mjs +359 -0
- package/dist/{token-goat-chunk-S4VSXURL.mjs → token-goat-chunk-Z44YO3QZ.mjs} +4 -0
- package/dist/token-goat-chunk-Z57YODA2.mjs +35 -0
- package/dist/{token-goat-chunk-PQ53BSCF.mjs → token-goat-chunk-ZCDTCVIS.mjs} +48 -29
- package/dist/token-goat-chunk-ZEJVMUQH.mjs +48 -0
- package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
- package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
- package/dist/{token-goat-chunk-PKRWMHVP.mjs → token-goat-chunk-ZQSJMO2R.mjs} +338 -170
- package/dist/token-goat-hook-client.cjs +87 -23
- package/dist/token-goat-hook-client.mjs +3 -3
- package/dist/token-goat-hook.mjs +46 -30
- package/dist/token-goat.core.mjs +6 -6
- package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
- package/docs/cli.md +80 -46
- package/docs/install.md +47 -14
- package/docs/security.md +7 -7
- package/package.json +17 -7
- package/scripts/verify-native-dist.mjs +386 -0
- package/dist/token-goat-chunk-2NNUA2LR.mjs +0 -143
- package/dist/token-goat-chunk-44BM7DDQ.mjs +0 -294
- package/dist/token-goat-chunk-C5YPNZKQ.mjs +0 -318
- package/dist/token-goat-chunk-CIQ2FTY3.mjs +0 -1990
- package/dist/token-goat-chunk-EUSDXRXU.mjs +0 -1429
- package/dist/token-goat-chunk-G7IWXCFF.mjs +0 -456
- package/dist/token-goat-chunk-JTKCQMQA.mjs +0 -418
- package/dist/token-goat-chunk-ORNFMIER.mjs +0 -295
- package/dist/token-goat-chunk-VQ6F6T7X.mjs +0 -36
- package/dist/token-goat-chunk-YAGLESS3.mjs +0 -23
- package/dist/token-goat-chunk-YKSRAWUU.mjs +0 -33
- package/dist/token-goat-chunk-Z6KBMOBI.mjs +0 -53
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
fenceUntrusted,
|
|
5
|
+
scanAndRecord
|
|
6
|
+
} from "./token-goat-chunk-67TQJ76B.mjs";
|
|
7
|
+
import {
|
|
8
|
+
enqueueDirtyPathSafe
|
|
9
|
+
} from "./token-goat-chunk-H2PHHGM5.mjs";
|
|
10
|
+
import {
|
|
11
|
+
extractCatFile,
|
|
12
|
+
extractHeadFile,
|
|
13
|
+
extractLineRangeRead,
|
|
14
|
+
extractLineRangeReadsCompound,
|
|
15
|
+
extractTailFile,
|
|
16
|
+
isTscCommand,
|
|
17
|
+
splitShellSegments,
|
|
18
|
+
stripLeadingAssignments
|
|
19
|
+
} from "./token-goat-chunk-APGZXSPS.mjs";
|
|
20
|
+
import {
|
|
21
|
+
detectFromCommand,
|
|
22
|
+
filterByName
|
|
23
|
+
} from "./token-goat-chunk-COBQGL5S.mjs";
|
|
24
|
+
import {
|
|
25
|
+
RECALL_DEFAULT_LIMIT,
|
|
26
|
+
isBuildCommand,
|
|
27
|
+
isTestRunnerCommand,
|
|
28
|
+
listRecentRecall,
|
|
29
|
+
searchRecall
|
|
30
|
+
} from "./token-goat-chunk-AFLYLHDH.mjs";
|
|
31
|
+
import {
|
|
32
|
+
shortFingerprint
|
|
33
|
+
} from "./token-goat-chunk-7IN2MKDS.mjs";
|
|
34
|
+
import {
|
|
35
|
+
pad,
|
|
36
|
+
runGit
|
|
37
|
+
} from "./token-goat-chunk-GOLEOXZP.mjs";
|
|
38
|
+
import {
|
|
39
|
+
UNTRUSTED_TOOL_TAG,
|
|
40
|
+
UNTRUSTED_WEB_TAG,
|
|
41
|
+
displaySafeJson,
|
|
42
|
+
fenceUntrustedContent,
|
|
43
|
+
normalizePath,
|
|
44
|
+
resolveIndexPath
|
|
45
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
46
|
+
import {
|
|
47
|
+
hasBareBackgroundOrNewline,
|
|
48
|
+
hasUnquotedOperator,
|
|
49
|
+
maskQuotedSpans,
|
|
50
|
+
shlexSplit
|
|
51
|
+
} from "./token-goat-chunk-KWPNJBDH.mjs";
|
|
52
|
+
import {
|
|
53
|
+
init_define_import_meta_env
|
|
54
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
55
|
+
|
|
56
|
+
// src/hooks_bash_commands.ts
|
|
57
|
+
init_define_import_meta_env();
|
|
58
|
+
import { statSync } from "node:fs";
|
|
59
|
+
import { homedir } from "node:os";
|
|
60
|
+
import * as path from "node:path";
|
|
61
|
+
|
|
62
|
+
// src/cli_recall.ts
|
|
63
|
+
init_define_import_meta_env();
|
|
64
|
+
var RECALL_COMMAND = {
|
|
65
|
+
bash: "bash-output",
|
|
66
|
+
web: "web-output",
|
|
67
|
+
mcp: "mcp-output"
|
|
68
|
+
};
|
|
69
|
+
function fenceTagForCacheType(cacheType) {
|
|
70
|
+
return cacheType === "web" ? UNTRUSTED_WEB_TAG : UNTRUSTED_TOOL_TAG;
|
|
71
|
+
}
|
|
72
|
+
function fenceRecallListing(text, hits) {
|
|
73
|
+
const tags = new Set(hits.map((hit) => fenceTagForCacheType(hit.cacheType)));
|
|
74
|
+
const tag = tags.size === 1 ? [...tags][0] ?? UNTRUSTED_TOOL_TAG : UNTRUSTED_TOOL_TAG;
|
|
75
|
+
return fenceUntrusted(text, tag);
|
|
76
|
+
}
|
|
77
|
+
function fenceSnippetIfMatched(hit) {
|
|
78
|
+
const matches = scanAndRecord(hit.snippet);
|
|
79
|
+
if (matches.length === 0) return hit.snippet;
|
|
80
|
+
return fenceUntrustedContent(hit.snippet, matches, fenceTagForCacheType(hit.cacheType));
|
|
81
|
+
}
|
|
82
|
+
function printHits(query, hits) {
|
|
83
|
+
const w = (text) => {
|
|
84
|
+
process.stdout.write(text);
|
|
85
|
+
};
|
|
86
|
+
if (hits.length === 0) {
|
|
87
|
+
w(query === void 0 ? "No cache entries yet.\n" : `No cache entries match: ${query}
|
|
88
|
+
`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const body = hits.map((hit) => {
|
|
92
|
+
const label = hit.label.length > 80 ? hit.label.slice(0, 77) + "..." : hit.label;
|
|
93
|
+
const pointer = hit.blobPresent ? ` (token-goat ${RECALL_COMMAND[hit.cacheType]} ${hit.id})` : " (blob expired -- content below is all that remains)";
|
|
94
|
+
return `[${pad(hit.cacheType, 4)}] ${hit.id}
|
|
95
|
+
${pointer}
|
|
96
|
+
${label}
|
|
97
|
+
${hit.snippet}
|
|
98
|
+
`;
|
|
99
|
+
}).join("\n");
|
|
100
|
+
w(`${fenceRecallListing(body, hits)}
|
|
101
|
+
`);
|
|
102
|
+
}
|
|
103
|
+
function runRecallCommand(query, opts = {}) {
|
|
104
|
+
const browse = query === void 0 || query.trim() === "";
|
|
105
|
+
const scope = {
|
|
106
|
+
...opts.type !== void 0 ? { type: opts.type } : {},
|
|
107
|
+
...opts.limit !== void 0 ? { limit: opts.limit } : {}
|
|
108
|
+
};
|
|
109
|
+
const effectiveLimit = opts.limit ?? RECALL_DEFAULT_LIMIT;
|
|
110
|
+
const fetched = browse ? listRecentRecall({ ...scope, limit: effectiveLimit + 1 }) : searchRecall(query, { ...scope, limit: effectiveLimit + 1 });
|
|
111
|
+
const hits = fetched.slice(0, effectiveLimit);
|
|
112
|
+
if (fetched.length > hits.length) {
|
|
113
|
+
process.stderr.write(`Showing ${hits.length} entries; more are available (raise --limit to see them).
|
|
114
|
+
`);
|
|
115
|
+
}
|
|
116
|
+
if (opts.json === true) {
|
|
117
|
+
const fenced = hits.map((hit) => ({ ...hit, snippet: fenceSnippetIfMatched(hit) }));
|
|
118
|
+
process.stdout.write(`${displaySafeJson(fenced, 0)}
|
|
119
|
+
`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
printHits(browse ? void 0 : query, hits);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/hooks_bash_commands.ts
|
|
126
|
+
var CD_PREFIX_RE = /^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)[ \t]*(?:&&|;|\r?\n)\s*)+/;
|
|
127
|
+
function stripCdPrefix(cmd) {
|
|
128
|
+
const stripped = cmd.replace(CD_PREFIX_RE, "");
|
|
129
|
+
return stripped.trim() || cmd;
|
|
130
|
+
}
|
|
131
|
+
function stripSubshellGroup(cmd) {
|
|
132
|
+
const t = cmd.trim();
|
|
133
|
+
if (!t.startsWith("(") || t.startsWith("((") || !t.endsWith(")")) return cmd;
|
|
134
|
+
const masked = maskQuotedSpans(t);
|
|
135
|
+
let depth = 0;
|
|
136
|
+
for (let i = 0; i < masked.length; i++) {
|
|
137
|
+
if (masked[i] === "(") depth++;
|
|
138
|
+
else if (masked[i] === ")" && --depth === 0) return i === masked.length - 1 ? t.slice(1, -1).trim() || cmd : cmd;
|
|
139
|
+
}
|
|
140
|
+
return cmd;
|
|
141
|
+
}
|
|
142
|
+
function stripCommandPrefix(rawCmd) {
|
|
143
|
+
return stripLeadingAssignments(stripCdPrefix(stripSubshellGroup(rawCmd)));
|
|
144
|
+
}
|
|
145
|
+
function stripTrailingStderrRedirect(cmd) {
|
|
146
|
+
const stripped = cmd.replace(/\s*2>&1\s*$/, "");
|
|
147
|
+
return stripped.trim() || cmd;
|
|
148
|
+
}
|
|
149
|
+
function hasTestRunScopeOrBudget(cmd) {
|
|
150
|
+
const hasTimeout = /(?:^|\s)(?:timeout(?:\.exe)?\s+\S+|--(?:test)?timeout(?:=|\s)\S+)/i.test(cmd);
|
|
151
|
+
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);
|
|
152
|
+
return hasTimeout || hasSelector;
|
|
153
|
+
}
|
|
154
|
+
function isDirectTestRunnerCommand(cmd) {
|
|
155
|
+
return /^(?:pytest|(?:npx\s+)?(?:jest|vitest)|go\s+test|cargo\s+test)\b/i.test(cmd);
|
|
156
|
+
}
|
|
157
|
+
function extractCdPrefixDirs(rawCmd) {
|
|
158
|
+
const prefixMatch = stripSubshellGroup(rawCmd).match(CD_PREFIX_RE);
|
|
159
|
+
if (prefixMatch === null) return [];
|
|
160
|
+
const dirs = [];
|
|
161
|
+
const segmentPattern = /cd\s+(?:"([^"]*)"|'([^']*)'|(\S+))[ \t]*(?:&&|;|\r?\n)/g;
|
|
162
|
+
let match;
|
|
163
|
+
while ((match = segmentPattern.exec(prefixMatch[0])) !== null) {
|
|
164
|
+
const dir = match[1] ?? match[2] ?? (match[3] === void 0 ? void 0 : expandHomePrefix(match[3]));
|
|
165
|
+
if (dir !== void 0) dirs.push(dir);
|
|
166
|
+
}
|
|
167
|
+
return dirs;
|
|
168
|
+
}
|
|
169
|
+
function expandHomePrefix(word) {
|
|
170
|
+
return word === "~" || word.startsWith("~/") ? path.join(homedir(), word.slice(1)) : word;
|
|
171
|
+
}
|
|
172
|
+
function resolveCdHintPath(rawCmd, filePath, cwd) {
|
|
173
|
+
if (extractCdPrefixDirs(rawCmd).length === 0) return filePath;
|
|
174
|
+
return resolveIndexPath(filePath, cdPrefixCwd(rawCmd, cwd));
|
|
175
|
+
}
|
|
176
|
+
function cdPrefixCwd(rawCmd, cwd) {
|
|
177
|
+
let dir = cwd;
|
|
178
|
+
for (const target of extractCdPrefixDirs(rawCmd)) dir = resolveIndexPath(target, dir);
|
|
179
|
+
return dir;
|
|
180
|
+
}
|
|
181
|
+
function commandRunDir(rawCmd, cwd) {
|
|
182
|
+
return cwd === null && extractCdPrefixDirs(rawCmd).length === 0 ? null : cdPrefixCwd(rawCmd, cwd ?? process.cwd());
|
|
183
|
+
}
|
|
184
|
+
function bashRecallKey(cmd, runDir) {
|
|
185
|
+
const base = stripOutputPipeline(cmd);
|
|
186
|
+
return shortFingerprint(runDir === null ? base : `${normalizePath(runDir)}\0${base}`);
|
|
187
|
+
}
|
|
188
|
+
function resolveBashCall(reported, startCwd) {
|
|
189
|
+
const rawCmd = unwrapCompressCommand(reported) ?? reported;
|
|
190
|
+
return { rawCmd, cmd: stripCommandPrefix(rawCmd), runDir: commandRunDir(rawCmd, startCwd) };
|
|
191
|
+
}
|
|
192
|
+
function stripOutputPipeline(cmd) {
|
|
193
|
+
let base = cmd.slice(0, firstTopLevelPipe(cmd));
|
|
194
|
+
let prev;
|
|
195
|
+
do {
|
|
196
|
+
prev = base;
|
|
197
|
+
const masked = base.replace(/"((?:[^"\\]|\\.)*)"/g, (_m, inner) => '"' + " ".repeat(inner.length) + '"').replace(/'([^']*)'/g, (_m, inner) => "'" + " ".repeat(inner.length) + "'");
|
|
198
|
+
const newMasked = masked.replace(/\s*(?:[0-9]*>&[0-9]+|[0-9&]*>>?\s*(?:"[^"]*"|'[^']*'|[^\s|]+))\s*$/, "");
|
|
199
|
+
if (newMasked.length < masked.length) {
|
|
200
|
+
base = base.slice(0, newMasked.length);
|
|
201
|
+
}
|
|
202
|
+
} while (base !== prev);
|
|
203
|
+
return base.trim();
|
|
204
|
+
}
|
|
205
|
+
function firstTopLevelPipe(cmd) {
|
|
206
|
+
let inSingle = false;
|
|
207
|
+
let inDouble = false;
|
|
208
|
+
let cut = cmd.length;
|
|
209
|
+
let backslashes = 0;
|
|
210
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
211
|
+
const ch = cmd[i];
|
|
212
|
+
if (ch === "\\") {
|
|
213
|
+
backslashes++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const escaped = backslashes % 2 === 1;
|
|
217
|
+
backslashes = 0;
|
|
218
|
+
if (ch === "'" && !inDouble) {
|
|
219
|
+
if (!escaped) inSingle = !inSingle;
|
|
220
|
+
} else if (ch === '"' && !inSingle) {
|
|
221
|
+
if (!escaped) inDouble = !inDouble;
|
|
222
|
+
} else if (ch === "|" && !inSingle && !inDouble) {
|
|
223
|
+
if (cmd[i + 1] === "|") {
|
|
224
|
+
i++;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
cut = i;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return cut;
|
|
232
|
+
}
|
|
233
|
+
function pipelineDivergenceNote(cmd, entryCommand) {
|
|
234
|
+
if (entryCommand === cmd) return "";
|
|
235
|
+
const preview = entryCommand.length > 60 ? entryCommand.slice(0, 57).trimEnd() + "..." : entryCommand;
|
|
236
|
+
return " (cached from a differently-piped run, `" + preview + "` \u2014 verify it covers what you need before trusting it)";
|
|
237
|
+
}
|
|
238
|
+
function outputSlice(cmd) {
|
|
239
|
+
const pipe = firstTopLevelPipe(cmd);
|
|
240
|
+
if (pipe >= cmd.length) return { kind: "none" };
|
|
241
|
+
const tail = cmd.slice(pipe + 1).replace(/\s*[0-9]*>&[0-9]+\s*$/, "").trim();
|
|
242
|
+
const head = /^head\s+(?:-n\s*|-)(\d+)$/.exec(tail);
|
|
243
|
+
if (head?.[1] !== void 0) return { kind: "head", n: Number(head[1]) };
|
|
244
|
+
const last = /^tail\s+(?:-n\s*|-)(\d+)$/.exec(tail);
|
|
245
|
+
if (last?.[1] !== void 0) return { kind: "tail", n: Number(last[1]) };
|
|
246
|
+
const sed = /^sed\s+-n\s+'?(\d+),(\d+)p'?$/.exec(tail);
|
|
247
|
+
if (sed?.[1] !== void 0 && sed[2] !== void 0) return { kind: "sed", from: Number(sed[1]), to: Number(sed[2]) };
|
|
248
|
+
return { kind: "unknown" };
|
|
249
|
+
}
|
|
250
|
+
function cachedRunCoversCommand(cachedCommand, cmd) {
|
|
251
|
+
const cached = outputSlice(cachedCommand);
|
|
252
|
+
const wanted = outputSlice(cmd);
|
|
253
|
+
if (cached.kind === "unknown" || wanted.kind === "unknown") return false;
|
|
254
|
+
if (cached.kind === "none") return true;
|
|
255
|
+
if (wanted.kind === "none") return false;
|
|
256
|
+
if (cached.kind === "tail") return wanted.kind === "tail" && wanted.n === cached.n;
|
|
257
|
+
const cachedFrom = cached.kind === "head" ? 1 : cached.from;
|
|
258
|
+
const cachedTo = cached.kind === "head" ? cached.n : cached.to;
|
|
259
|
+
if (wanted.kind === "tail") return false;
|
|
260
|
+
const wantedFrom = wanted.kind === "head" ? 1 : wanted.from;
|
|
261
|
+
const wantedTo = wanted.kind === "head" ? wanted.n : wanted.to;
|
|
262
|
+
return cachedFrom <= wantedFrom && wantedTo <= cachedTo;
|
|
263
|
+
}
|
|
264
|
+
function extractCommand(event) {
|
|
265
|
+
const cmd = event.toolInput["command"];
|
|
266
|
+
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
267
|
+
}
|
|
268
|
+
var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick)\b/i;
|
|
269
|
+
var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:\S.*?\s)?--(?:\s|$)/i;
|
|
270
|
+
function isHeadMovingGitCommand(cmd) {
|
|
271
|
+
if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
|
|
272
|
+
if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
|
|
276
|
+
var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
|
|
277
|
+
var GIT_RESTORE_RE = /^\s*git\s+restore\b/i;
|
|
278
|
+
var GIT_RESTORE_STAGED_ONLY_RE = /(?:^|\s)(?:--staged|-S)(?:\s|$)/;
|
|
279
|
+
var GIT_STASH_APPLY_RE = /^\s*git\s+stash\s+(?:pop|apply)\b/i;
|
|
280
|
+
var PATCH_APPLY_SEGMENT_RE = /^\s*(?:\S*[/\\])?(?:git\s+apply|patch)\b/i;
|
|
281
|
+
var PATCH_APPLY_INSPECT_ONLY_RE = /(?:^|\s)--(?:check|stat|numstat|summary|dry-run)(?:\s|=|$)/i;
|
|
282
|
+
function isFormatterWriteSegment(segment) {
|
|
283
|
+
return /(?:^|\s|[/\\])(?:prettier|eslint)\b/i.test(segment) && /(?:^|\s)--(?:write|fix)(?:\s|$)/i.test(segment);
|
|
284
|
+
}
|
|
285
|
+
function safeShlexSplit(segment) {
|
|
286
|
+
try {
|
|
287
|
+
return shlexSplit(segment);
|
|
288
|
+
} catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function segmentCommandIs(segment, name) {
|
|
293
|
+
return new RegExp("^\\s*(?:\\S*[/\\\\])?" + name + "(?:\\.exe)?\\b", "i").test(segment);
|
|
294
|
+
}
|
|
295
|
+
function extractSedInPlaceFiles(segment) {
|
|
296
|
+
if (!segmentCommandIs(segment, "sed")) return [];
|
|
297
|
+
const tokens = safeShlexSplit(segment);
|
|
298
|
+
if (tokens === null) return [];
|
|
299
|
+
const rest = tokens.slice(1);
|
|
300
|
+
const inPlaceIdx = rest.findIndex((t) => t === "--in-place" || t.startsWith("--in-place=") || /^-[a-zA-Z]*i/.test(t));
|
|
301
|
+
if (inPlaceIdx === -1) return [];
|
|
302
|
+
const files = [];
|
|
303
|
+
let scriptTaken = rest.some((t) => t === "-e" || t === "-f" || t.startsWith("--expression") || t.startsWith("--file"));
|
|
304
|
+
for (let i = 0; i < rest.length; i++) {
|
|
305
|
+
const t = rest[i];
|
|
306
|
+
if (i === inPlaceIdx) {
|
|
307
|
+
if (t === "-i" && rest[i + 1] === "") i++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (t === "-e" || t === "-f" || t === "--expression" || t === "--file") {
|
|
311
|
+
i++;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (t.length > 1 && t.startsWith("-")) continue;
|
|
315
|
+
if (!scriptTaken) {
|
|
316
|
+
scriptTaken = true;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
files.push(t);
|
|
320
|
+
}
|
|
321
|
+
return files;
|
|
322
|
+
}
|
|
323
|
+
function extractTeeFiles(segment) {
|
|
324
|
+
if (!segmentCommandIs(segment, "tee")) return [];
|
|
325
|
+
const tokens = safeShlexSplit(segment);
|
|
326
|
+
if (tokens === null) return [];
|
|
327
|
+
return tokens.slice(1).filter((t) => t.length > 0 && !t.startsWith("-"));
|
|
328
|
+
}
|
|
329
|
+
function extractRedirectTargets(segment) {
|
|
330
|
+
const targets = [];
|
|
331
|
+
const re = /(?:^|\s)[0-9]?>>?\s*("[^"]*"|'[^']*'|[^\s|&<>]+)/g;
|
|
332
|
+
let m;
|
|
333
|
+
while ((m = re.exec(segment)) !== null) {
|
|
334
|
+
const raw = m[1];
|
|
335
|
+
targets.push(raw.length >= 2 && (raw[0] === '"' || raw[0] === "'") ? raw.slice(1, -1) : raw);
|
|
336
|
+
}
|
|
337
|
+
return targets;
|
|
338
|
+
}
|
|
339
|
+
function extractGitRestorePathspecs(cmd) {
|
|
340
|
+
const m = /^\s*git\s+restore\b(.*)$/i.exec(cmd);
|
|
341
|
+
if (m === null) return [];
|
|
342
|
+
const tokens = safeShlexSplit(m[1] ?? "");
|
|
343
|
+
if (tokens === null) return [];
|
|
344
|
+
const dashDash = tokens.indexOf("--");
|
|
345
|
+
if (dashDash !== -1) return tokens.slice(dashDash + 1);
|
|
346
|
+
const specs = [];
|
|
347
|
+
let skipNext = false;
|
|
348
|
+
for (const t of tokens) {
|
|
349
|
+
if (skipNext) {
|
|
350
|
+
skipNext = false;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (t === "-s" || t === "--source") {
|
|
354
|
+
skipNext = true;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (t.startsWith("-")) continue;
|
|
358
|
+
specs.push(t);
|
|
359
|
+
}
|
|
360
|
+
return specs;
|
|
361
|
+
}
|
|
362
|
+
function gitRepoRoot(gitDir) {
|
|
363
|
+
const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
364
|
+
return toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : gitDir;
|
|
365
|
+
}
|
|
366
|
+
function expandGitPathspecs(specs, gitDir) {
|
|
367
|
+
if (specs.length === 0) return [];
|
|
368
|
+
const listed = runGit(["ls-files", "--full-name", "--", ...specs], { cwd: gitDir, timeoutMs: 5e3 });
|
|
369
|
+
if (listed.exitCode !== 0) return [];
|
|
370
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
371
|
+
return listed.stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((rel) => resolveIndexPath(rel, repoRoot));
|
|
372
|
+
}
|
|
373
|
+
function workingTreeStatusPaths(gitDir) {
|
|
374
|
+
const status = runGit(["status", "--porcelain"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
375
|
+
if (status.exitCode !== 0) return [];
|
|
376
|
+
const repoRoot = gitRepoRoot(gitDir);
|
|
377
|
+
const out = [];
|
|
378
|
+
for (const line of status.stdout.split("\n")) {
|
|
379
|
+
if (line.length < 4) continue;
|
|
380
|
+
let rel = line.slice(3).trim();
|
|
381
|
+
if (rel.length === 0) continue;
|
|
382
|
+
const arrow = rel.lastIndexOf(" -> ");
|
|
383
|
+
if (arrow !== -1) rel = rel.slice(arrow + 4);
|
|
384
|
+
if (rel.startsWith('"')) {
|
|
385
|
+
try {
|
|
386
|
+
rel = JSON.parse(rel);
|
|
387
|
+
} catch {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
out.push(resolveIndexPath(rel, repoRoot));
|
|
392
|
+
}
|
|
393
|
+
return out;
|
|
394
|
+
}
|
|
395
|
+
function enqueueRewrittenPath(absPath) {
|
|
396
|
+
if (/(?:^|[/\\])(?:NUL|nul)$/.test(absPath) || absPath.replace(/\\/g, "/").endsWith("/dev/null")) return;
|
|
397
|
+
try {
|
|
398
|
+
if (!statSync(absPath).isFile()) return;
|
|
399
|
+
} catch {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
|
|
403
|
+
}
|
|
404
|
+
function enqueueNonHeadMovingRewrites(cmd, runDir) {
|
|
405
|
+
const atRunDir = (f) => resolveIndexPath(f, runDir);
|
|
406
|
+
const paths = [];
|
|
407
|
+
let needsStatusSweep = GIT_STASH_APPLY_RE.test(cmd);
|
|
408
|
+
if (GIT_RESTORE_RE.test(cmd) && !GIT_RESTORE_STAGED_ONLY_RE.test(cmd)) {
|
|
409
|
+
paths.push(...expandGitPathspecs(extractGitRestorePathspecs(cmd), runDir));
|
|
410
|
+
}
|
|
411
|
+
for (const segment of splitShellSegments(cmd)) {
|
|
412
|
+
if (PATCH_APPLY_SEGMENT_RE.test(segment) && !PATCH_APPLY_INSPECT_ONLY_RE.test(segment)) needsStatusSweep = true;
|
|
413
|
+
if (isFormatterWriteSegment(segment)) needsStatusSweep = true;
|
|
414
|
+
for (const f of extractSedInPlaceFiles(segment)) paths.push(atRunDir(f));
|
|
415
|
+
for (const f of extractTeeFiles(segment)) paths.push(atRunDir(f));
|
|
416
|
+
for (const f of extractRedirectTargets(segment)) paths.push(atRunDir(f));
|
|
417
|
+
}
|
|
418
|
+
if (needsStatusSweep) paths.push(...workingTreeStatusPaths(runDir));
|
|
419
|
+
for (const p of paths) enqueueRewrittenPath(p);
|
|
420
|
+
}
|
|
421
|
+
var PIPELINE_PASSTHROUGH_HEADS = /* @__PURE__ */ new Set(["head", "tail", "cat", "tee", "less", "more"]);
|
|
422
|
+
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)$/;
|
|
423
|
+
function isCiBuildTestSegment(cleaned, cwd) {
|
|
424
|
+
if (isTestRunnerCommand(cleaned) || isBuildCommand(cleaned) || isTscCommand(cleaned)) return true;
|
|
425
|
+
if (/^\s*(npm|pnpm|yarn|bun)\s+(run\s+)?(test|build|lint|typecheck|check|ci|guards)\b/i.test(cleaned)) return true;
|
|
426
|
+
if (/^\s*(cargo|go|dotnet|make|gradle|mvn|pytest|vitest|jest|eslint|ruff)\b/i.test(cleaned)) return true;
|
|
427
|
+
const detected = detectFromCommand(cleaned, cwd ?? void 0);
|
|
428
|
+
if (detected !== null && CI_FILTER_NAMES.test(detected.filter.name)) return true;
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
function pipelineShapeFilter(cmd, cwd) {
|
|
432
|
+
if (hasUnquotedOperator(cmd, ["&&", "||", ";"])) {
|
|
433
|
+
const forSplit2 = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
434
|
+
if (hasBareBackgroundOrNewline(forSplit2)) return null;
|
|
435
|
+
const segments2 = splitShellSegments(forSplit2);
|
|
436
|
+
if (segments2.length >= 2) {
|
|
437
|
+
let recognizedCiCount = 0;
|
|
438
|
+
for (const segment of segments2) {
|
|
439
|
+
const cleaned = stripOutputPipeline(segment.trim());
|
|
440
|
+
if (cleaned.length === 0) continue;
|
|
441
|
+
if (isCiBuildTestSegment(cleaned, cwd)) {
|
|
442
|
+
recognizedCiCount++;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (recognizedCiCount > 0) {
|
|
446
|
+
const ci = filterByName("generic-ci");
|
|
447
|
+
return ci === null ? null : { filter: ci, argv: [] };
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
453
|
+
if (hasBareBackgroundOrNewline(forSplit)) return null;
|
|
454
|
+
const segments = splitShellSegments(forSplit);
|
|
455
|
+
if (segments.length < 2) return null;
|
|
456
|
+
for (const segment of segments.slice(1)) {
|
|
457
|
+
const head = safeShlexSplit(segment)?.[0];
|
|
458
|
+
if (head === void 0) return null;
|
|
459
|
+
if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
|
|
460
|
+
}
|
|
461
|
+
const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
|
|
462
|
+
return detected === null ? null : { filter: detected.filter, argv: detected.argv };
|
|
463
|
+
}
|
|
464
|
+
function recallStageTokens(cmd) {
|
|
465
|
+
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
466
|
+
if (hasBareBackgroundOrNewline(forSplit)) return null;
|
|
467
|
+
const first = splitShellSegments(forSplit)[0];
|
|
468
|
+
if (first === void 0) return null;
|
|
469
|
+
const args = tokenGoatInvocation(stripOutputPipeline(first));
|
|
470
|
+
if (args === null) return null;
|
|
471
|
+
return Object.values(RECALL_COMMAND).includes(args[0] ?? "") ? ["token-goat", ...args] : null;
|
|
472
|
+
}
|
|
473
|
+
function tokenGoatInvocation(segment) {
|
|
474
|
+
const tokens = safeShlexSplit(segment);
|
|
475
|
+
if (tokens === null || tokens.length === 0) return null;
|
|
476
|
+
const base = (t) => t.replace(/^.*[/\\]/, "").replace(/\.exe$/i, "").toLowerCase();
|
|
477
|
+
const head = base(tokens[0] ?? "");
|
|
478
|
+
if (head === "token-goat" || head === "tg") return tokens.slice(1);
|
|
479
|
+
if (head === "node") {
|
|
480
|
+
const script = tokens[1];
|
|
481
|
+
return script !== void 0 && /(?:^|[/\\:])token-goat(?:\.core)?\.mjs$/i.test(script) ? tokens.slice(2) : null;
|
|
482
|
+
}
|
|
483
|
+
if (head === "npx") {
|
|
484
|
+
let i = 1;
|
|
485
|
+
while (tokens[i] === "-y" || tokens[i] === "--yes") i++;
|
|
486
|
+
return /^token-goat(?:@\S+)?$/.test(tokens[i] ?? "") ? tokens.slice(i + 1) : null;
|
|
487
|
+
}
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
function isTokenGoatOwnCommand(cmd) {
|
|
491
|
+
const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
|
|
492
|
+
if (hasBareBackgroundOrNewline(forSplit)) return false;
|
|
493
|
+
const first = splitShellSegments(forSplit)[0];
|
|
494
|
+
return first !== void 0 && tokenGoatInvocation(stripOutputPipeline(first)) !== null;
|
|
495
|
+
}
|
|
496
|
+
function isRecallCommand(cmd) {
|
|
497
|
+
return recallStageTokens(cmd) !== null;
|
|
498
|
+
}
|
|
499
|
+
function isFullRecallCommand(cmd) {
|
|
500
|
+
return recallStageTokens(cmd)?.includes("--full") === true;
|
|
501
|
+
}
|
|
502
|
+
function pureFileReadPath(cmd) {
|
|
503
|
+
const single = extractCatFile(cmd)?.filePath ?? extractHeadFile(cmd)?.filePath ?? extractTailFile(cmd)?.filePath ?? extractLineRangeRead(cmd)?.filePath;
|
|
504
|
+
if (single !== void 0) return single;
|
|
505
|
+
return singleFileCompoundReadPath(cmd);
|
|
506
|
+
}
|
|
507
|
+
function singleFileCompoundReadPath(cmd) {
|
|
508
|
+
const reads = extractLineRangeReadsCompound(cmd);
|
|
509
|
+
if (reads === null || reads.length !== 1) return null;
|
|
510
|
+
return reads[0]?.filePath ?? null;
|
|
511
|
+
}
|
|
512
|
+
function deliveredLineNumbers(cmd, lineCount) {
|
|
513
|
+
const ranged = extractLineRangeRead(cmd);
|
|
514
|
+
if (ranged !== null) {
|
|
515
|
+
const nums = [];
|
|
516
|
+
for (const [lo, hi] of ranged.ranges) for (let n = lo; n <= hi; n++) nums.push(n);
|
|
517
|
+
if (nums.length === 0) return null;
|
|
518
|
+
while (nums.length < lineCount) nums.push((nums[nums.length - 1] ?? 0) + 1);
|
|
519
|
+
return nums;
|
|
520
|
+
}
|
|
521
|
+
if (extractCatFile(cmd) !== null || extractHeadFile(cmd) !== null) return Array.from({ length: lineCount }, (_, i) => i + 1);
|
|
522
|
+
if (singleFileCompoundReadPath(cmd) !== null) return Array.from({ length: lineCount }, () => null);
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
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;
|
|
526
|
+
function isWholeFileDump(cmd, extractedPath) {
|
|
527
|
+
const m = WHOLE_FILE_DUMP_RE.exec(cmd);
|
|
528
|
+
if (m === null) return false;
|
|
529
|
+
const shaped = m[1] ?? m[2] ?? m[3];
|
|
530
|
+
return shaped !== void 0 && shaped === extractedPath;
|
|
531
|
+
}
|
|
532
|
+
function unwrapCompressCommand(executed) {
|
|
533
|
+
const t = executed.trim();
|
|
534
|
+
if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
|
|
535
|
+
let argv;
|
|
536
|
+
try {
|
|
537
|
+
argv = shlexSplit(t);
|
|
538
|
+
} catch {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
for (let i = 0; i + 1 < argv.length; i++) {
|
|
542
|
+
const tok = argv[i];
|
|
543
|
+
if (tok === "-c" || tok === "--cmd") return argv[i + 1] ?? null;
|
|
544
|
+
if (tok === "--cmd-b64") {
|
|
545
|
+
try {
|
|
546
|
+
return Buffer.from(argv[i + 1] ?? "", "base64").toString("utf8");
|
|
547
|
+
} catch {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
function detectUnbalancedShellSyntax(cmd) {
|
|
555
|
+
let inSingle = false;
|
|
556
|
+
let inDouble = false;
|
|
557
|
+
let i = 0;
|
|
558
|
+
while (i < cmd.length) {
|
|
559
|
+
const ch = cmd[i];
|
|
560
|
+
if (inSingle) {
|
|
561
|
+
if (ch === "'") {
|
|
562
|
+
inSingle = false;
|
|
563
|
+
}
|
|
564
|
+
i++;
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
if (inDouble) {
|
|
568
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
569
|
+
i += 2;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (ch === '"') {
|
|
573
|
+
inDouble = false;
|
|
574
|
+
}
|
|
575
|
+
i++;
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
579
|
+
i += 2;
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
if (ch === "$" && cmd[i + 1] === "(" && cmd[i + 2] === "(") {
|
|
583
|
+
let depth = 2;
|
|
584
|
+
let j = i + 3;
|
|
585
|
+
while (j < cmd.length && depth > 0) {
|
|
586
|
+
if (cmd[j] === "(") depth++;
|
|
587
|
+
else if (cmd[j] === ")") depth--;
|
|
588
|
+
j++;
|
|
589
|
+
}
|
|
590
|
+
i = j;
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (ch === "$" && cmd[i + 1] === "'") {
|
|
594
|
+
let j = i + 2;
|
|
595
|
+
let closed = false;
|
|
596
|
+
while (j < cmd.length) {
|
|
597
|
+
if (cmd[j] === "\\") {
|
|
598
|
+
j += 2;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (cmd[j] === "'") {
|
|
602
|
+
j++;
|
|
603
|
+
closed = true;
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
j++;
|
|
607
|
+
}
|
|
608
|
+
if (!closed) {
|
|
609
|
+
inSingle = true;
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
i = j;
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
|
|
616
|
+
const nl = cmd.indexOf("\n", i);
|
|
617
|
+
i = nl === -1 ? cmd.length : nl + 1;
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (ch === "'") {
|
|
621
|
+
inSingle = true;
|
|
622
|
+
i++;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (ch === '"') {
|
|
626
|
+
inDouble = true;
|
|
627
|
+
i++;
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
if (ch === "<" && i + 1 < cmd.length && cmd[i + 1] === "<") {
|
|
631
|
+
if (i + 2 < cmd.length && cmd[i + 2] === "<") {
|
|
632
|
+
i += 3;
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
let j = i + 2;
|
|
636
|
+
let hasIndentModifier = false;
|
|
637
|
+
if (j < cmd.length && (cmd[j] === "-" || cmd[j] === "~")) {
|
|
638
|
+
hasIndentModifier = true;
|
|
639
|
+
j++;
|
|
640
|
+
}
|
|
641
|
+
while (j < cmd.length && cmd[j] === " ") {
|
|
642
|
+
j++;
|
|
643
|
+
}
|
|
644
|
+
if (j < cmd.length) {
|
|
645
|
+
let delimStart = j;
|
|
646
|
+
if (cmd[j] === '"' || cmd[j] === "'") {
|
|
647
|
+
delimStart = j + 1;
|
|
648
|
+
const quoteChar = cmd[j];
|
|
649
|
+
let delimEnd = delimStart;
|
|
650
|
+
while (delimEnd < cmd.length && cmd[delimEnd] !== quoteChar) {
|
|
651
|
+
delimEnd++;
|
|
652
|
+
}
|
|
653
|
+
if (delimEnd >= cmd.length) {
|
|
654
|
+
return "an unclosed quote in a heredoc opener";
|
|
655
|
+
}
|
|
656
|
+
j = delimEnd + 1;
|
|
657
|
+
} else {
|
|
658
|
+
let delimEnd = delimStart;
|
|
659
|
+
while (delimEnd < cmd.length && /\w/.test(cmd.charAt(delimEnd))) {
|
|
660
|
+
delimEnd++;
|
|
661
|
+
}
|
|
662
|
+
j = delimEnd;
|
|
663
|
+
}
|
|
664
|
+
const delimiter = cmd.slice(delimStart, j).replace(/["']/g, "");
|
|
665
|
+
if (delimiter) {
|
|
666
|
+
let scanPos = j;
|
|
667
|
+
let terminatorEnd = -1;
|
|
668
|
+
while (scanPos <= cmd.length) {
|
|
669
|
+
const nl = cmd.indexOf("\n", scanPos);
|
|
670
|
+
const lineEnd = nl === -1 ? cmd.length : nl;
|
|
671
|
+
let line = cmd.slice(scanPos, lineEnd);
|
|
672
|
+
if (line.endsWith("\r")) {
|
|
673
|
+
line = line.slice(0, -1);
|
|
674
|
+
}
|
|
675
|
+
const isMatch = hasIndentModifier ? line.trim() === delimiter : line === delimiter;
|
|
676
|
+
if (isMatch) {
|
|
677
|
+
terminatorEnd = nl === -1 ? cmd.length : nl + 1;
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
if (nl === -1) break;
|
|
681
|
+
scanPos = nl + 1;
|
|
682
|
+
}
|
|
683
|
+
if (terminatorEnd === -1) {
|
|
684
|
+
return `an unterminated heredoc (${delimiter} never appears on its own line)`;
|
|
685
|
+
}
|
|
686
|
+
i = terminatorEnd;
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
i++;
|
|
692
|
+
}
|
|
693
|
+
if (inSingle) {
|
|
694
|
+
return "an unclosed single quote";
|
|
695
|
+
}
|
|
696
|
+
if (inDouble) {
|
|
697
|
+
return "an unclosed double quote";
|
|
698
|
+
}
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
export {
|
|
703
|
+
runRecallCommand,
|
|
704
|
+
stripCdPrefix,
|
|
705
|
+
stripSubshellGroup,
|
|
706
|
+
stripCommandPrefix,
|
|
707
|
+
stripTrailingStderrRedirect,
|
|
708
|
+
hasTestRunScopeOrBudget,
|
|
709
|
+
isDirectTestRunnerCommand,
|
|
710
|
+
resolveCdHintPath,
|
|
711
|
+
cdPrefixCwd,
|
|
712
|
+
commandRunDir,
|
|
713
|
+
bashRecallKey,
|
|
714
|
+
resolveBashCall,
|
|
715
|
+
pipelineDivergenceNote,
|
|
716
|
+
cachedRunCoversCommand,
|
|
717
|
+
extractCommand,
|
|
718
|
+
isHeadMovingGitCommand,
|
|
719
|
+
ORIG_HEAD_ELIGIBLE_GIT_RE,
|
|
720
|
+
ORIG_HEAD_REFLOG_MSG_RE,
|
|
721
|
+
gitRepoRoot,
|
|
722
|
+
enqueueNonHeadMovingRewrites,
|
|
723
|
+
PIPELINE_PASSTHROUGH_HEADS,
|
|
724
|
+
pipelineShapeFilter,
|
|
725
|
+
isTokenGoatOwnCommand,
|
|
726
|
+
isRecallCommand,
|
|
727
|
+
isFullRecallCommand,
|
|
728
|
+
pureFileReadPath,
|
|
729
|
+
deliveredLineNumbers,
|
|
730
|
+
isWholeFileDump,
|
|
731
|
+
unwrapCompressCommand,
|
|
732
|
+
detectUnbalancedShellSyntax
|
|
733
|
+
};
|