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
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
DEFAULT_MAX_AGE_MS,
|
|
5
|
+
blobPath,
|
|
4
6
|
countRedactionPlaceholders,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
getDb,
|
|
8
|
+
isBlobStale,
|
|
9
|
+
loadBlob,
|
|
8
10
|
recordStat,
|
|
9
11
|
recordUnmappedTool,
|
|
10
12
|
redactSecrets,
|
|
11
13
|
savedTokensFromBytes,
|
|
12
|
-
|
|
14
|
+
storeBlob,
|
|
13
15
|
stripAnsiEscapes
|
|
14
|
-
} from "./token-goat-chunk-
|
|
16
|
+
} from "./token-goat-chunk-T2IWWTHB.mjs";
|
|
17
|
+
import {
|
|
18
|
+
detectHarness,
|
|
19
|
+
loadConfig,
|
|
20
|
+
parse,
|
|
21
|
+
shortFingerprint,
|
|
22
|
+
stringify
|
|
23
|
+
} from "./token-goat-chunk-SAQ5PG4L.mjs";
|
|
15
24
|
import {
|
|
16
25
|
registerReset
|
|
17
26
|
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
@@ -24,16 +33,21 @@ import {
|
|
|
24
33
|
ensureDirSync,
|
|
25
34
|
escapeRegExp,
|
|
26
35
|
extractErrorMessage,
|
|
36
|
+
foldPath,
|
|
37
|
+
globalDbPath,
|
|
27
38
|
hookCommandFor,
|
|
28
39
|
hookPowershellCommand,
|
|
40
|
+
isCaseInsensitiveFs,
|
|
29
41
|
neutralizeOutsideFences,
|
|
30
42
|
normalizeDarwinSystemAlias,
|
|
43
|
+
normalizePath,
|
|
31
44
|
projectPathIsConsultable,
|
|
32
45
|
projectScopeRoot,
|
|
33
46
|
recordCreatedConfig,
|
|
34
47
|
removeCreatedBackups,
|
|
35
48
|
removeFileInScope,
|
|
36
49
|
resolveIndexPath,
|
|
50
|
+
runGit,
|
|
37
51
|
safeSlice,
|
|
38
52
|
stripDelimitedBlock,
|
|
39
53
|
stripOwnHooksFromMap,
|
|
@@ -43,7 +57,7 @@ import {
|
|
|
43
57
|
withInstallScope,
|
|
44
58
|
writeIfDifferent,
|
|
45
59
|
writeJsonSettings
|
|
46
|
-
} from "./token-goat-chunk-
|
|
60
|
+
} from "./token-goat-chunk-AMYCQJX4.mjs";
|
|
47
61
|
import {
|
|
48
62
|
init_define_import_meta_env
|
|
49
63
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -842,12 +856,12 @@ async function main() {
|
|
|
842
856
|
return
|
|
843
857
|
}
|
|
844
858
|
|
|
845
|
-
process.stdout.write(JSON.stringify(translate(copilotEvent, resp, toolName, originalToolArgs)))
|
|
859
|
+
process.stdout.write(JSON.stringify(translate(copilotEvent, resp, toolName, originalToolArgs, payload)))
|
|
846
860
|
}
|
|
847
861
|
|
|
848
862
|
${MATERIALIZE_SHRUNK_IMAGE_JS}
|
|
849
863
|
|
|
850
|
-
function translate(copilotEvent, resp, toolName, originalToolArgs) {
|
|
864
|
+
function translate(copilotEvent, resp, toolName, originalToolArgs, payload) {
|
|
851
865
|
if (copilotEvent === 'preToolUse') {
|
|
852
866
|
const hso = resp && resp.hookSpecificOutput
|
|
853
867
|
const denied = resp && (resp.decision === 'block' || (hso && hso.permissionDecision === 'deny'))
|
|
@@ -869,52 +883,20 @@ function translate(copilotEvent, resp, toolName, originalToolArgs) {
|
|
|
869
883
|
}
|
|
870
884
|
|
|
871
885
|
if (copilotEvent === 'postToolUse') {
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
// toolResult.resultType === "success", then does n.toolResultJson && CSr(e.toolResult,
|
|
875
|
-
// n.toolResultJson), where CSr (offset 2032350) is an in-place Object.assign; the mutated
|
|
876
|
-
// object is re-serialized back to native in the postTool callback at offset 1793926. So
|
|
877
|
-
// modifiedResult IS honored on this event, and token-goat's rewriteOutput producers
|
|
878
|
-
// (compression, injection fencing, image shrink) really do reach the model. resultType is
|
|
879
|
-
// hardcoded 'success' because success is the only branch this event ever runs on.
|
|
880
|
-
//
|
|
881
|
-
// additionalContext on THIS event is dropped on the JS path. grep -abo "onAdditionalContext:"
|
|
882
|
-
// app.js returns nothing, so the callback is never supplied, and the two "onAdditionalContext?"
|
|
883
|
-
// call sites (offsets 2041896 and 2043300) are both no-ops. preToolsExecution (offset 2041832)
|
|
884
|
-
// additionally pushes each context into an array that IS drained into the native return
|
|
885
|
-
// payload (additional_contexts, offset 1791950); postToolExecution has no such push and its
|
|
886
|
-
// native return payload (offset 1793926) has no additional_contexts key. Residual, stated
|
|
887
|
-
// honestly: the native hookProcessorPostToolUse might fold additionalContext into the
|
|
888
|
-
// toolResultJson it returns, and that was NOT verified. The evidence leans against it, since
|
|
889
|
-
// the failure sibling path appends its context explicitly in JS via
|
|
890
|
-
// hookAppendPostToolUseFailureContext and there is no success-path counterpart. The
|
|
891
|
-
// out.additionalContext below is kept as cheap best-effort, not as a channel anything should
|
|
892
|
-
// depend on -- see src/pending_context.ts, whose whole design depended on it.
|
|
893
|
-
//
|
|
894
|
-
// Failed tool calls never reach this event. postToolUse and postToolUseFailure are two
|
|
895
|
-
// distinct hook events (both listed in the runtime.node hook-event enum at offset 101618150),
|
|
896
|
-
// and the shipped copilot-sdk/types.d.ts says onPostToolUse "does not fire for non-success
|
|
897
|
-
// results". The failure event cannot carry a fence either: PostToolUseFailureHookInput carries
|
|
898
|
-
// only a stringified error message, not the tool result, and PostToolUseFailureHookOutput
|
|
899
|
-
// consumes only additionalContext -- "modifiedResult or suppressOutput are not honored for
|
|
900
|
-
// failure hooks". rejected/denied/timeout results trigger no post hook at all. So on Copilot,
|
|
901
|
-
// the output of a failed tool call reaches the model unfenced, uncompressed and unshrunk, and
|
|
902
|
-
// no response shape this shim could emit changes that. That gap is real and still open. What
|
|
903
|
-
// is now wired is the narrower thing that IS possible there: the postToolUseFailure branch
|
|
904
|
-
// below carries advisory text alongside the failure, and never rewrites it.
|
|
905
|
-
//
|
|
906
|
-
// Emitted camelCase-only. The inbound side around line 247 also tolerates a snake_case "VS
|
|
907
|
-
// Code compatible" shape, and this comment used to justify the camelCase choice by claiming
|
|
908
|
-
// PascalCase event registration selects the snake_case response format. That reasoning is
|
|
909
|
-
// UNVERIFIED in 1.0.80: every hook-response field in the native string tables is camelCase,
|
|
910
|
-
// and the snake_case hits in the bundle are unrelated internal Rust identifiers. camelCase
|
|
911
|
-
// stays because it is what the bundle reads; the old justification is no longer asserted.
|
|
886
|
+
// modifiedResult is honored on success: rewriteOutput (compression, fencing, image shrink) reaches LLM.
|
|
887
|
+
// additionalContext is dropped on Copilot CLI JS path; we fold context into modifiedResult.textResultForLlm.
|
|
912
888
|
const hso = resp && resp.hookSpecificOutput
|
|
913
889
|
const updatedToolOutput = hso && hso.updatedToolOutput
|
|
914
890
|
const context = extractContext(resp)
|
|
915
891
|
const out = {}
|
|
916
892
|
if (typeof updatedToolOutput === 'string') {
|
|
917
893
|
out.modifiedResult = { resultType: 'success', textResultForLlm: updatedToolOutput }
|
|
894
|
+
} else if (context) {
|
|
895
|
+
const rawResult = payload && payload.toolResult
|
|
896
|
+
const originalText = rawResult && (typeof rawResult.textResultForLlm === 'string' ? rawResult.textResultForLlm : typeof rawResult.text_result_for_llm === 'string' ? rawResult.text_result_for_llm : undefined)
|
|
897
|
+
if (typeof originalText === 'string') {
|
|
898
|
+
out.modifiedResult = { resultType: 'success', textResultForLlm: originalText + '\\n\\n[token-goat: ' + context + ']' }
|
|
899
|
+
}
|
|
918
900
|
}
|
|
919
901
|
if (context) out.additionalContext = context
|
|
920
902
|
return out
|
|
@@ -1747,6 +1729,10 @@ function getCwd(event) {
|
|
|
1747
1729
|
const value = event.raw && typeof event.raw === "object" ? event.raw["cwd"] : void 0;
|
|
1748
1730
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1749
1731
|
}
|
|
1732
|
+
function getTranscriptPath(event) {
|
|
1733
|
+
const value = event.raw && typeof event.raw === "object" ? event.raw["transcript_path"] : void 0;
|
|
1734
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1735
|
+
}
|
|
1750
1736
|
function extractToolResponseField(raw, keys) {
|
|
1751
1737
|
const resp = raw["tool_response"];
|
|
1752
1738
|
if (typeof resp === "string") return resp;
|
|
@@ -2954,9 +2940,1032 @@ function byteLength(s) {
|
|
|
2954
2940
|
return utf8Len(s);
|
|
2955
2941
|
}
|
|
2956
2942
|
|
|
2957
|
-
// src/
|
|
2943
|
+
// src/index_reader.ts
|
|
2944
|
+
init_define_import_meta_env();
|
|
2945
|
+
|
|
2946
|
+
// src/sql_path.ts
|
|
2947
|
+
init_define_import_meta_env();
|
|
2948
|
+
function pathEqClause(column) {
|
|
2949
|
+
return isCaseInsensitiveFs() ? `TG_LOWER(${column}) = ?` : `${column} = ?`;
|
|
2950
|
+
}
|
|
2951
|
+
function pathSuffixClause(column) {
|
|
2952
|
+
const col = isCaseInsensitiveFs() ? `TG_LOWER(${column})` : column;
|
|
2953
|
+
return {
|
|
2954
|
+
// Both separators are accepted because not every writer into `symbols` stores a normalizePath'd (forward-slash) file_path, and the JS-side path-boundary test this narrowing feeds treats `/` and `\` alike.
|
|
2955
|
+
clause: `(${col} = ? OR substr(${col}, -length(?)) = ? OR substr(${col}, -length(?)) = ?)`,
|
|
2956
|
+
params: (baseName) => {
|
|
2957
|
+
const folded = foldPath(baseName);
|
|
2958
|
+
return [folded, `/${folded}`, `/${folded}`, `\\${folded}`, `\\${folded}`];
|
|
2959
|
+
}
|
|
2960
|
+
};
|
|
2961
|
+
}
|
|
2962
|
+
function projectScopeClause(column) {
|
|
2963
|
+
const caseInsensitive = isCaseInsensitiveFs();
|
|
2964
|
+
const col = caseInsensitive ? `TG_LOWER(${column})` : column;
|
|
2965
|
+
return {
|
|
2966
|
+
// Parenthesised so an OR anywhere in the surrounding WHERE cannot bind tighter than the pair.
|
|
2967
|
+
clause: `(${col} >= ? AND ${col} < ?)`,
|
|
2968
|
+
params: (root) => {
|
|
2969
|
+
const folded = caseInsensitive ? foldPath(normalizePath(root)) : normalizePath(root);
|
|
2970
|
+
const lower = folded.endsWith("/") ? folded : `${folded}/`;
|
|
2971
|
+
const upper = `${lower.slice(0, -1)}0`;
|
|
2972
|
+
return [lower, upper];
|
|
2973
|
+
}
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
// src/index_reader.ts
|
|
2978
|
+
function toSymbolEntry(row) {
|
|
2979
|
+
return {
|
|
2980
|
+
filePath: row.file_path,
|
|
2981
|
+
name: row.name,
|
|
2982
|
+
kind: row.kind,
|
|
2983
|
+
lineStart: row.line_start,
|
|
2984
|
+
lineEnd: row.line_end,
|
|
2985
|
+
body: row.body ?? "",
|
|
2986
|
+
docstring: row.docstring ?? "",
|
|
2987
|
+
parent: row.parent ?? ""
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
function toRefEntry(row) {
|
|
2991
|
+
return {
|
|
2992
|
+
filePath: row.file_path,
|
|
2993
|
+
name: row.name,
|
|
2994
|
+
line: row.line,
|
|
2995
|
+
col: row.col,
|
|
2996
|
+
context: row.context ?? ""
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
function applyRootDirScope(rootDir, column, where, params) {
|
|
3000
|
+
if (rootDir === void 0) return;
|
|
3001
|
+
const { clause, params: bounds } = projectScopeClause(column);
|
|
3002
|
+
where.push(clause);
|
|
3003
|
+
params.push(...bounds(rootDir));
|
|
3004
|
+
}
|
|
3005
|
+
function buildSymbolWhere(opts) {
|
|
3006
|
+
const where = [];
|
|
3007
|
+
const params = [];
|
|
3008
|
+
if (opts.name !== void 0) {
|
|
3009
|
+
where.push("name = ?");
|
|
3010
|
+
params.push(opts.name);
|
|
3011
|
+
}
|
|
3012
|
+
if (opts.filePath !== void 0) {
|
|
3013
|
+
where.push(pathEqClause("file_path"));
|
|
3014
|
+
params.push(foldPath(opts.filePath));
|
|
3015
|
+
}
|
|
3016
|
+
if (opts.kind !== void 0) {
|
|
3017
|
+
where.push("kind = ?");
|
|
3018
|
+
params.push(opts.kind);
|
|
3019
|
+
}
|
|
3020
|
+
if (opts.fileBaseName !== void 0) {
|
|
3021
|
+
const { clause: suffixClause, params: suffixParams } = pathSuffixClause("file_path");
|
|
3022
|
+
where.push(suffixClause);
|
|
3023
|
+
params.push(...suffixParams(opts.fileBaseName));
|
|
3024
|
+
}
|
|
3025
|
+
if (opts.enclosingLine !== void 0) {
|
|
3026
|
+
where.push("line_start <= ? AND ? <= line_end");
|
|
3027
|
+
params.push(opts.enclosingLine, opts.enclosingLine);
|
|
3028
|
+
}
|
|
3029
|
+
applyRootDirScope(opts.rootDir, "file_path", where, params);
|
|
3030
|
+
return { clause: where.length > 0 ? `WHERE ${where.join(" AND ")}` : "", params };
|
|
3031
|
+
}
|
|
3032
|
+
var DEFAULT_QUERY_LIMIT = 100;
|
|
3033
|
+
function querySymbols(opts = {}, dbPath = globalDbPath()) {
|
|
3034
|
+
const { clause, params } = buildSymbolWhere(opts);
|
|
3035
|
+
const limit = opts.limit ?? DEFAULT_QUERY_LIMIT;
|
|
3036
|
+
const offset = opts.offset ?? 0;
|
|
3037
|
+
const sql = `SELECT file_path, name, kind, line_start, line_end, body, docstring, parent FROM symbols ${clause} ORDER BY file_path, line_start, rowid LIMIT ? OFFSET ?`;
|
|
3038
|
+
const db = getDb(dbPath);
|
|
3039
|
+
const rows = db.prepare(sql).all(...params, limit, offset);
|
|
3040
|
+
return rows.map(toSymbolEntry);
|
|
3041
|
+
}
|
|
3042
|
+
function distinctSymbolKinds(rootDir, dbPath = globalDbPath()) {
|
|
3043
|
+
const where = [];
|
|
3044
|
+
const params = [];
|
|
3045
|
+
applyRootDirScope(rootDir, "file_path", where, params);
|
|
3046
|
+
const clause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
|
|
3047
|
+
const db = getDb(dbPath);
|
|
3048
|
+
const rows = db.prepare(`SELECT DISTINCT kind FROM symbols ${clause} ORDER BY kind`).all(...params);
|
|
3049
|
+
return rows.map((r) => r.kind);
|
|
3050
|
+
}
|
|
3051
|
+
function countSymbols(opts = {}, dbPath = globalDbPath()) {
|
|
3052
|
+
const { clause, params } = buildSymbolWhere(opts);
|
|
3053
|
+
const sql = `SELECT COUNT(*) as cnt FROM symbols ${clause}`;
|
|
3054
|
+
const db = getDb(dbPath);
|
|
3055
|
+
const row = db.prepare(sql).get(...params);
|
|
3056
|
+
return row.cnt;
|
|
3057
|
+
}
|
|
3058
|
+
function buildRefsWhere(opts) {
|
|
3059
|
+
const where = ["name = ?"];
|
|
3060
|
+
const params = [opts.name];
|
|
3061
|
+
if (opts.filePath !== void 0) {
|
|
3062
|
+
where.push(pathEqClause("file_path"));
|
|
3063
|
+
params.push(foldPath(opts.filePath));
|
|
3064
|
+
}
|
|
3065
|
+
applyRootDirScope(opts.rootDir, "file_path", where, params);
|
|
3066
|
+
return { clause: `WHERE ${where.join(" AND ")}`, params };
|
|
3067
|
+
}
|
|
3068
|
+
function queryRefs(opts, dbPath = globalDbPath()) {
|
|
3069
|
+
const { clause, params } = buildRefsWhere(opts);
|
|
3070
|
+
const limit = opts.limit ?? DEFAULT_QUERY_LIMIT;
|
|
3071
|
+
const sql = `SELECT file_path, name, line, col, context FROM refs ${clause} ORDER BY file_path, line LIMIT ?`;
|
|
3072
|
+
const db = getDb(dbPath);
|
|
3073
|
+
const rows = db.prepare(sql).all(...params, limit);
|
|
3074
|
+
return rows.map(toRefEntry);
|
|
3075
|
+
}
|
|
3076
|
+
function countRefs(opts, dbPath = globalDbPath()) {
|
|
3077
|
+
const { clause, params } = buildRefsWhere(opts);
|
|
3078
|
+
const sql = `SELECT COUNT(*) as cnt FROM refs ${clause}`;
|
|
3079
|
+
const db = getDb(dbPath);
|
|
3080
|
+
const row = db.prepare(sql).get(...params);
|
|
3081
|
+
return row.cnt;
|
|
3082
|
+
}
|
|
3083
|
+
function queryRefsByContext(context, filePath, dbPath = globalDbPath()) {
|
|
3084
|
+
const sql = `SELECT file_path, name, line, col, context FROM refs WHERE context = ? AND ${pathEqClause("file_path")} ORDER BY line LIMIT 20`;
|
|
3085
|
+
const db = getDb(dbPath);
|
|
3086
|
+
const rows = db.prepare(sql).all(context, foldPath(filePath));
|
|
3087
|
+
return rows.map(toRefEntry);
|
|
3088
|
+
}
|
|
3089
|
+
var REF_COUNT_BATCH = 900;
|
|
3090
|
+
function queryRefCounts(names, dbPath = globalDbPath(), rootDir) {
|
|
3091
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3092
|
+
if (names.length === 0) return counts;
|
|
3093
|
+
const db = getDb(dbPath);
|
|
3094
|
+
const scopeWhere = [];
|
|
3095
|
+
const scopeParams = [];
|
|
3096
|
+
applyRootDirScope(rootDir, "file_path", scopeWhere, scopeParams);
|
|
3097
|
+
const scopeSql = scopeWhere.length > 0 ? ` AND ${scopeWhere.join(" AND ")}` : "";
|
|
3098
|
+
const sqlFor = (width) => `SELECT name, COUNT(*) as c FROM refs WHERE name IN (${Array.from({ length: width }, () => "?").join(", ")})${scopeSql} GROUP BY name`;
|
|
3099
|
+
const full = names.length >= REF_COUNT_BATCH ? db.prepare(sqlFor(REF_COUNT_BATCH)) : void 0;
|
|
3100
|
+
db.transaction(() => {
|
|
3101
|
+
for (let start = 0; start < names.length; start += REF_COUNT_BATCH) {
|
|
3102
|
+
const batch = names.slice(start, start + REF_COUNT_BATCH);
|
|
3103
|
+
const stmt = batch.length === REF_COUNT_BATCH && full !== void 0 ? full : db.prepare(sqlFor(batch.length));
|
|
3104
|
+
for (const row of stmt.all(...batch, ...scopeParams)) {
|
|
3105
|
+
counts.set(row.name, row.c);
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
})();
|
|
3109
|
+
return counts;
|
|
3110
|
+
}
|
|
3111
|
+
function getProjectFileEntries(rootDir, dbPath = globalDbPath()) {
|
|
3112
|
+
const db = getDb(dbPath);
|
|
3113
|
+
const { clause, params } = projectScopeClause("path");
|
|
3114
|
+
const rows = db.prepare(`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${clause}`).all(...params(rootDir));
|
|
3115
|
+
const out = /* @__PURE__ */ new Map();
|
|
3116
|
+
for (const row of rows) {
|
|
3117
|
+
out.set(foldPath(row.path), {
|
|
3118
|
+
filePath: row.path,
|
|
3119
|
+
sha: row.sha ?? "",
|
|
3120
|
+
mtime: row.mtime ?? 0,
|
|
3121
|
+
language: row.language ?? "unknown",
|
|
3122
|
+
indexedAt: row.indexed_at ?? 0,
|
|
3123
|
+
embedSha: row.embed_sha ?? "",
|
|
3124
|
+
parserSha: row.parser_sha ?? ""
|
|
3125
|
+
});
|
|
3126
|
+
}
|
|
3127
|
+
return out;
|
|
3128
|
+
}
|
|
3129
|
+
function getFileEntry(filePath, dbPath = globalDbPath()) {
|
|
3130
|
+
const db = getDb(dbPath);
|
|
3131
|
+
const row = db.prepare(
|
|
3132
|
+
`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${pathEqClause("path")}`
|
|
3133
|
+
).get(foldPath(filePath));
|
|
3134
|
+
if (row === void 0) return null;
|
|
3135
|
+
return {
|
|
3136
|
+
filePath: row.path,
|
|
3137
|
+
sha: row.sha ?? "",
|
|
3138
|
+
mtime: row.mtime ?? 0,
|
|
3139
|
+
language: row.language ?? "unknown",
|
|
3140
|
+
indexedAt: row.indexed_at ?? 0,
|
|
3141
|
+
embedSha: row.embed_sha ?? "",
|
|
3142
|
+
parserSha: row.parser_sha ?? ""
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
3145
|
+
function sanitizeFtsQuery(query, join11 = "AND") {
|
|
3146
|
+
const terms = query.split(/\s+/).filter((t) => t.length > 0).map((t) => '"' + t.replace(/"/g, '""') + '"');
|
|
3147
|
+
return terms.join(join11 === "OR" ? " OR " : " ");
|
|
3148
|
+
}
|
|
3149
|
+
function runFtsQuery(db, match, limit, scope, rootDir) {
|
|
3150
|
+
const sql = `SELECT s.file_path, s.name, s.kind, s.line_start, s.line_end, s.body, s.docstring, s.parent FROM symbols_fts JOIN symbols s ON s.id = symbols_fts.rowid WHERE symbols_fts MATCH ?${scope !== void 0 ? ` AND ${scope.clause}` : ""} ORDER BY bm25(symbols_fts) LIMIT ?`;
|
|
3151
|
+
const params = [match];
|
|
3152
|
+
if (scope !== void 0 && rootDir !== void 0) {
|
|
3153
|
+
params.push(...scope.params(rootDir));
|
|
3154
|
+
}
|
|
3155
|
+
params.push(limit);
|
|
3156
|
+
const rows = db.prepare(sql).all(...params);
|
|
3157
|
+
return rows.map(toSymbolEntry);
|
|
3158
|
+
}
|
|
3159
|
+
function searchSymbolsFts(query, limit = 50, dbPath = globalDbPath(), rootDir) {
|
|
3160
|
+
const andMatch = sanitizeFtsQuery(query, "AND");
|
|
3161
|
+
if (andMatch === "") return [];
|
|
3162
|
+
const db = getDb(dbPath);
|
|
3163
|
+
const scope = rootDir !== void 0 ? projectScopeClause("s.file_path") : void 0;
|
|
3164
|
+
try {
|
|
3165
|
+
const andResults = runFtsQuery(db, andMatch, limit, scope, rootDir);
|
|
3166
|
+
if (andResults.length > 0) return andResults;
|
|
3167
|
+
const orMatch = sanitizeFtsQuery(query, "OR");
|
|
3168
|
+
if (orMatch === andMatch) return andResults;
|
|
3169
|
+
return runFtsQuery(db, orMatch, limit, scope, rootDir);
|
|
3170
|
+
} catch {
|
|
3171
|
+
return [];
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
// src/bash_output_cache.ts
|
|
3176
|
+
init_define_import_meta_env();
|
|
3177
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
3178
|
+
import { resolve as resolve4 } from "path";
|
|
3179
|
+
|
|
3180
|
+
// src/hints/lang_patterns.ts
|
|
3181
|
+
init_define_import_meta_env();
|
|
3182
|
+
var LOCK_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
3183
|
+
"package-lock.json",
|
|
3184
|
+
"yarn.lock",
|
|
3185
|
+
"pnpm-lock.yaml",
|
|
3186
|
+
"cargo.lock",
|
|
3187
|
+
"poetry.lock",
|
|
3188
|
+
"pipfile.lock",
|
|
3189
|
+
"uv.lock",
|
|
3190
|
+
"gemfile.lock",
|
|
3191
|
+
"go.sum",
|
|
3192
|
+
"composer.lock",
|
|
3193
|
+
"mix.lock",
|
|
3194
|
+
"pubspec.lock",
|
|
3195
|
+
"package.resolved"
|
|
3196
|
+
]);
|
|
3197
|
+
var MANIFEST_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
3198
|
+
"package.json",
|
|
3199
|
+
"pyproject.toml",
|
|
3200
|
+
"cargo.toml",
|
|
3201
|
+
"go.mod",
|
|
3202
|
+
"go.work",
|
|
3203
|
+
"pom.xml",
|
|
3204
|
+
"build.gradle",
|
|
3205
|
+
"build.gradle.kts",
|
|
3206
|
+
"settings.gradle",
|
|
3207
|
+
"composer.json",
|
|
3208
|
+
"gemfile",
|
|
3209
|
+
"mix.exs",
|
|
3210
|
+
"pubspec.yaml",
|
|
3211
|
+
"cmakelists.txt",
|
|
3212
|
+
"makefile",
|
|
3213
|
+
"project.clj",
|
|
3214
|
+
// TypeScript / JavaScript project configs
|
|
3215
|
+
"tsconfig.json",
|
|
3216
|
+
"jsconfig.json",
|
|
3217
|
+
// Bundler / framework configs
|
|
3218
|
+
"vite.config.ts",
|
|
3219
|
+
"vite.config.js",
|
|
3220
|
+
"webpack.config.js",
|
|
3221
|
+
"webpack.config.ts",
|
|
3222
|
+
"rollup.config.js",
|
|
3223
|
+
"rollup.config.ts",
|
|
3224
|
+
"esbuild.config.js",
|
|
3225
|
+
"next.config.js",
|
|
3226
|
+
"next.config.ts",
|
|
3227
|
+
"nuxt.config.ts"
|
|
3228
|
+
]);
|
|
3229
|
+
var MANIFEST_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3230
|
+
".cabal"
|
|
3231
|
+
]);
|
|
3232
|
+
var MANIFEST_BASENAME_PATTERNS = [
|
|
3233
|
+
/^tsconfig(\..+)?\.json$/i
|
|
3234
|
+
];
|
|
3235
|
+
var BUILD_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
3236
|
+
"dist",
|
|
3237
|
+
"target",
|
|
3238
|
+
"build",
|
|
3239
|
+
"out",
|
|
3240
|
+
"__pycache__",
|
|
3241
|
+
".next",
|
|
3242
|
+
".nuxt",
|
|
3243
|
+
".output",
|
|
3244
|
+
".gradle",
|
|
3245
|
+
"_build",
|
|
3246
|
+
".build",
|
|
3247
|
+
"pkg",
|
|
3248
|
+
"obj"
|
|
3249
|
+
]);
|
|
3250
|
+
var ALWAYS_GENERATED_EXTS = /* @__PURE__ */ new Set([
|
|
3251
|
+
".pyc",
|
|
3252
|
+
".pyo",
|
|
3253
|
+
".pyd",
|
|
3254
|
+
".class",
|
|
3255
|
+
".o",
|
|
3256
|
+
".a",
|
|
3257
|
+
".so",
|
|
3258
|
+
".dylib",
|
|
3259
|
+
".dll",
|
|
3260
|
+
".tsbuildinfo"
|
|
3261
|
+
]);
|
|
3262
|
+
var CONDITIONALLY_GENERATED_EXTS = /* @__PURE__ */ new Set([
|
|
3263
|
+
".map",
|
|
3264
|
+
".d.ts"
|
|
3265
|
+
]);
|
|
3266
|
+
var BUILD_COMMAND_PATTERNS = [
|
|
3267
|
+
// Rust / Cargo
|
|
3268
|
+
/^\s*cargo\s+(build|test|run|check|clippy)\b/i,
|
|
3269
|
+
// Go
|
|
3270
|
+
/^\s*go\s+(build|test|run|vet)\b/i,
|
|
3271
|
+
// Maven
|
|
3272
|
+
/^\s*mvn\b/i,
|
|
3273
|
+
// Gradle (direct or wrapper)
|
|
3274
|
+
/^\s*(?:gradle|\.\/gradlew|gradlew)\b/i,
|
|
3275
|
+
// Python / pip
|
|
3276
|
+
/^\s*pip\s+(install|freeze)\b/i,
|
|
3277
|
+
// npm audit / npm outdated — read-only reporting commands with no side effects, safe to cache/recall. Each resolves a `lockfile`-scoped fingerprint via bash_output_cache.ts's isNpmAuditCommand/isNpmOutdatedCommand, but that fingerprinting never actually ran outside their own unit tests until this entry, since neither subcommand was recognized by isBuildCommand (the generic cache-reachability gate in hooks_bash.ts). `npm install`/`npm ci`/`npm list`/`npm ls` are deliberately left out — see the negative-case test in lang_patterns.test.ts.
|
|
3278
|
+
/^\s*npm\s+(audit|outdated)\b/i,
|
|
3279
|
+
// Poetry
|
|
3280
|
+
/^\s*poetry\s+(install|update)\b/i,
|
|
3281
|
+
// uv
|
|
3282
|
+
/^\s*uv\s+(sync|pip\s+install)\b/i,
|
|
3283
|
+
// Bundler (Ruby)
|
|
3284
|
+
/^\s*bundle\s+(install|update)\b/i,
|
|
3285
|
+
// Mix (Elixir)
|
|
3286
|
+
/^\s*mix\s+(deps\.get|compile|test)\b/i,
|
|
3287
|
+
// dotnet
|
|
3288
|
+
/^\s*dotnet\s+(build|test|restore)\b/i,
|
|
3289
|
+
// Make
|
|
3290
|
+
/^\s*make\b/i,
|
|
3291
|
+
// CMake build
|
|
3292
|
+
/^\s*cmake\s+--build\b/i,
|
|
3293
|
+
// Rake (Ruby)
|
|
3294
|
+
/^\s*rake\b/i,
|
|
3295
|
+
// TypeScript compiler (direct and via npx)
|
|
3296
|
+
/^\s*tsc(?:\s|$)/i,
|
|
3297
|
+
/^\s*npx\s+tsc(?:\s|$)/i,
|
|
3298
|
+
// Vite
|
|
3299
|
+
/^\s*vite\s+(build|dev|preview)\b/i,
|
|
3300
|
+
// Next.js
|
|
3301
|
+
/^\s*next\s+(build|dev|start)\b/i,
|
|
3302
|
+
// Nuxt
|
|
3303
|
+
/^\s*nuxt\s+(build|dev)\b/i,
|
|
3304
|
+
// Webpack
|
|
3305
|
+
/^\s*webpack\b/i,
|
|
3306
|
+
// esbuild
|
|
3307
|
+
/^\s*esbuild\b/i,
|
|
3308
|
+
// Rollup
|
|
3309
|
+
/^\s*rollup\b/i,
|
|
3310
|
+
// Turbo
|
|
3311
|
+
/^\s*turbo\s+(build|dev)\b/i
|
|
3312
|
+
];
|
|
3313
|
+
var LOCK_FILE_COUNT = LOCK_FILE_NAMES.size;
|
|
3314
|
+
var MANIFEST_FILE_COUNT = MANIFEST_FILE_NAMES.size + MANIFEST_EXTENSIONS.size + MANIFEST_BASENAME_PATTERNS.length;
|
|
3315
|
+
var BUILD_DIR_COUNT = BUILD_DIR_NAMES.size;
|
|
3316
|
+
var GENERATED_EXT_COUNT = ALWAYS_GENERATED_EXTS.size + CONDITIONALLY_GENERATED_EXTS.size;
|
|
3317
|
+
function isLockFile(basename2) {
|
|
3318
|
+
return LOCK_FILE_NAMES.has(basename2.toLowerCase());
|
|
3319
|
+
}
|
|
3320
|
+
function isManifestFile(basename2) {
|
|
3321
|
+
const lower = basename2.toLowerCase();
|
|
3322
|
+
if (MANIFEST_FILE_NAMES.has(lower)) return true;
|
|
3323
|
+
const dot = lower.lastIndexOf(".");
|
|
3324
|
+
if (dot !== -1 && MANIFEST_EXTENSIONS.has(lower.slice(dot))) return true;
|
|
3325
|
+
if (MANIFEST_BASENAME_PATTERNS.some((re) => re.test(basename2))) return true;
|
|
3326
|
+
return false;
|
|
3327
|
+
}
|
|
3328
|
+
function pathSegments(filePath) {
|
|
3329
|
+
return filePath.split(/[/\\]/).filter((s) => s.length > 0);
|
|
3330
|
+
}
|
|
3331
|
+
function isInBuildDir(filePath) {
|
|
3332
|
+
const segments = pathSegments(filePath);
|
|
3333
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
3334
|
+
const seg = segments[i];
|
|
3335
|
+
if (seg !== void 0 && BUILD_DIR_NAMES.has(seg.toLowerCase())) return true;
|
|
3336
|
+
}
|
|
3337
|
+
return false;
|
|
3338
|
+
}
|
|
3339
|
+
function isGeneratedFile(filePath) {
|
|
3340
|
+
const lower = filePath.toLowerCase();
|
|
3341
|
+
for (const ext of ALWAYS_GENERATED_EXTS) {
|
|
3342
|
+
if (lower.endsWith(ext)) return true;
|
|
3343
|
+
}
|
|
3344
|
+
for (const ext of CONDITIONALLY_GENERATED_EXTS) {
|
|
3345
|
+
if (lower.endsWith(ext) && isInBuildDir(filePath)) return true;
|
|
3346
|
+
}
|
|
3347
|
+
return false;
|
|
3348
|
+
}
|
|
3349
|
+
function isBuildCommand(cmd) {
|
|
3350
|
+
return BUILD_COMMAND_PATTERNS.some((re) => re.test(cmd));
|
|
3351
|
+
}
|
|
3352
|
+
var TEST_RUNNER_COMMAND_PATTERNS = [
|
|
3353
|
+
// pytest (Python)
|
|
3354
|
+
/^pytest(?:\s|$)/i,
|
|
3355
|
+
// Jest / Vitest (direct or via npx)
|
|
3356
|
+
/^(?:npx\s+)?jest(?:\s|$)/i,
|
|
3357
|
+
/^(?:npx\s+)?vitest(?:\s+run|\s+watch)?(?:\s|$)/i,
|
|
3358
|
+
// Go
|
|
3359
|
+
/^go test(?:\s|$)/i,
|
|
3360
|
+
// Rust / Cargo
|
|
3361
|
+
/^cargo test(?:\s|$)/i,
|
|
3362
|
+
// npm test / npm run test
|
|
3363
|
+
/^npm (?:test|run test)(?:\s|$)/i,
|
|
3364
|
+
// yarn test / yarn run test / pnpm test / pnpm run test
|
|
3365
|
+
/^(?:yarn|pnpm)(?:\s+run)? test(?:\s|$)/i
|
|
3366
|
+
];
|
|
3367
|
+
function isTestRunnerCommand(cmd) {
|
|
3368
|
+
return TEST_RUNNER_COMMAND_PATTERNS.some((re) => re.test(cmd));
|
|
3369
|
+
}
|
|
3370
|
+
var MONITORING_COMMAND_PATTERNS = [
|
|
3371
|
+
// GitHub CI
|
|
3372
|
+
{ pattern: /^gh run (?:watch|view|list)/, recallHint: '--grep "fail|error|pass|\u2713|\u2717|conclusion"' },
|
|
3373
|
+
{ pattern: /^gh run view.*--log/, recallHint: '--tail 100 --grep "Error|FAIL|error"' },
|
|
3374
|
+
{ pattern: /^gh pr checks/, recallHint: '--grep "fail|error|pass|pending"' },
|
|
3375
|
+
{ pattern: /^gh pr view/, recallHint: '--grep "state|title|mergeable|review|OPEN|CLOSED|MERGED"' },
|
|
3376
|
+
{ pattern: /^gh pr list/, recallHint: '--grep "OPEN|DRAFT|MERGED|#"' },
|
|
3377
|
+
{ pattern: /^gh issue view/, recallHint: '--grep "state|title|label|OPEN|CLOSED"' },
|
|
3378
|
+
{ pattern: /^gh workflow (?:run|list|view)/, recallHint: '--grep "completed|failed|in_progress"' },
|
|
3379
|
+
// Dev servers (Next, Vite, Nuxt, Remix, Astro)
|
|
3380
|
+
{ pattern: /^(?:npx\s+)?next dev/, recallHint: '--tail 30 --grep "error|warn|ready|compiled"' },
|
|
3381
|
+
{ pattern: /^(?:npx\s+)?next build/, recallHint: '--grep "error|warn|Failed|\u2713"' },
|
|
3382
|
+
{ pattern: /^(?:npx\s+)?vite\b(?:\s+dev|\s+build|\s+preview)?/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
3383
|
+
{ pattern: /^(?:npx\s+)?nuxt dev/, recallHint: '--tail 30 --grep "error|warn|ready"' },
|
|
3384
|
+
{ pattern: /^(?:npx\s+)?remix dev/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
3385
|
+
{ pattern: /^(?:npx\s+)?astro dev/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
3386
|
+
// Test watchers
|
|
3387
|
+
{ pattern: /^(?:npx\s+)?vitest(?:\s+run|\s+watch)?/, recallHint: '--grep "FAIL|PASS|Error|\u2713|\u2717"' },
|
|
3388
|
+
{ pattern: /^(?:npx\s+)?jest(?:\s+--watch)?/, recallHint: '--grep "FAIL|PASS|Error|Tests:"' },
|
|
3389
|
+
{ pattern: /^pytest(?:\s|$)/, recallHint: '--grep "FAILED|PASSED|ERROR|passed|failed"' },
|
|
3390
|
+
{ pattern: /^(?:cargo\s+test|cargo\s+watch)/, recallHint: '--grep "FAILED|ok|error\\["' },
|
|
3391
|
+
{ pattern: /^go test/, recallHint: '--grep "FAIL|ok|---"' },
|
|
3392
|
+
// Docker / compose
|
|
3393
|
+
{ pattern: /^docker(?:\s+compose)?\s+logs/, recallHint: '--tail 50 --grep "error|warn|Error|WARN"' },
|
|
3394
|
+
{ pattern: /^docker-compose\s+logs/, recallHint: '--tail 50 --grep "error|warn|Error|WARN"' },
|
|
3395
|
+
// File watchers / hot-reload
|
|
3396
|
+
{ pattern: /^nodemon/, recallHint: '--tail 20 --grep "error|crash|restart"' },
|
|
3397
|
+
{ pattern: /^air(?:\s|$)/, recallHint: '--tail 20 --grep "error|build failed"' },
|
|
3398
|
+
{ pattern: /^cargo watch/, recallHint: '--tail 20 --grep "error\\[|warning\\["' },
|
|
3399
|
+
{ pattern: /^watchexec/, recallHint: '--tail 20 --grep "error|warn"' },
|
|
3400
|
+
// Linters / formatters run repeatedly
|
|
3401
|
+
{ pattern: /^(?:npx\s+)?eslint(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
|
|
3402
|
+
{ pattern: /^(?:npx\s+)?prettier(?:\s|$)/, recallHint: '--grep "unchanged|reformatted|error"' },
|
|
3403
|
+
{ pattern: /^npx\s+tsc(?:\s|$)/, recallHint: '--grep "error TS|Cannot find|Type "' },
|
|
3404
|
+
{ pattern: /^ruff(?:\s|$)/, recallHint: '--grep "error|warning|Found"' },
|
|
3405
|
+
{ pattern: /^(?:cargo\s+)?clippy/, recallHint: '--grep "error\\[|warning\\["' },
|
|
3406
|
+
// git diff (full diff output — can be very large; excludes --stat which is small)
|
|
3407
|
+
{ pattern: /^git diff(?!\s+--stat)(?:\s+HEAD)?(?:\s|$)/, recallHint: '--grep "@@|\\+\\+\\+|---|diff --git"' },
|
|
3408
|
+
{ pattern: /^git diff\s+--cached(?!\s+--stat)/, recallHint: '--grep "@@|\\+\\+\\+|---|diff --git"' },
|
|
3409
|
+
// git push — output is dominated by the pre-push hook (full test suite, often 10K+); cache it so failures/rejections are recallable without re-pushing
|
|
3410
|
+
{ pattern: /^git push(?:\s|$)/, recallHint: '--tail 100 --grep "error|fail|FAIL|rejected|To "' },
|
|
3411
|
+
// npm run * wrappers (npm test is excluded — too generic; npm run test is explicit)
|
|
3412
|
+
{ pattern: /^npm run (?:test|spec)(?:\s|$)/, recallHint: '--grep "FAIL|PASS|Error|Tests:|\u2713|\u2717"' },
|
|
3413
|
+
{ pattern: /^npm run build(?:\s|$)/, recallHint: '--grep "error|Built|Failed|\u2713|\u2717"' },
|
|
3414
|
+
{ pattern: /^npm run (?:lint|typecheck|check|type-check)(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
|
|
3415
|
+
// node scripts (migration runners, seed generators, etc. run repeatedly)
|
|
3416
|
+
{ pattern: /^node\s+(?:scripts|src\/scripts)\/\S+\.m?js\b/, recallHint: '--tail 50 --grep "error|Error|done|complete|inserted|migrated"' },
|
|
3417
|
+
// External AI peer-review CLI tools (produce large outputs, run repeatedly per session)
|
|
3418
|
+
{ pattern: /^codex(?:\s|$)/, recallHint: '--tail 100 --grep "error|suggestion|verdict|conclusion"' },
|
|
3419
|
+
{ pattern: /^(?:~\/\.claude\/bin\/|\.claude\/bin\/)?glm\.sh(?:\s|$)/, recallHint: '--tail 100 --grep "error|verdict|conclusion|suggestion"' },
|
|
3420
|
+
// cat of a single source file — output is the full file; pre-bash emits a token-goat read suggestion
|
|
3421
|
+
{ pattern: /^cat\s+\S+\.(java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj)\s*$/, recallHint: "--tail 50" },
|
|
3422
|
+
// PowerShell read-only system-state queries (stable over 60-120s)
|
|
3423
|
+
{
|
|
3424
|
+
pattern: /^(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\s+(?:-\w+\s+)*-Command\s+["']?Get-(?:CimInstance|Process|Counter|Service|PSDrive|WmiObject)\b/i,
|
|
3425
|
+
recallHint: "--tail 50"
|
|
3426
|
+
},
|
|
3427
|
+
// token-goat section/outline/symbol repeat calls — output is stable until the file changes
|
|
3428
|
+
{ pattern: /^(?:token-goat|tg)\s+section\s+["'][^"']+["']/, recallHint: "" },
|
|
3429
|
+
{ pattern: /^(?:token-goat|tg)\s+outline\s+\S+/, recallHint: "" },
|
|
3430
|
+
{ pattern: /^(?:token-goat|tg)\s+symbol\s+\S+/, recallHint: "" }
|
|
3431
|
+
];
|
|
3432
|
+
function isPsMultilineSystemQuery(cmd) {
|
|
3433
|
+
if (!/^(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\s+/i.test(cmd)) return false;
|
|
3434
|
+
const cmdIdx = cmd.search(/-Command\b/i);
|
|
3435
|
+
if (cmdIdx === -1) return false;
|
|
3436
|
+
const afterCmd = cmd.slice(cmdIdx + "-Command".length).trimStart();
|
|
3437
|
+
if (!/^["']/.test(afterCmd)) return false;
|
|
3438
|
+
const body = afterCmd.slice(1);
|
|
3439
|
+
if (!body.includes("\n")) return false;
|
|
3440
|
+
if (!/\bGet-(?:CimInstance|Process|Counter|Service|PSDrive|WmiObject)\b/i.test(body)) return false;
|
|
3441
|
+
if (/\b(?:Remove|Set|New|Restart|Install|Uninstall|Enable|Disable|Grant|Revoke|Register|Unregister)-/i.test(body)) return false;
|
|
3442
|
+
if (/\b(?:Stop-(?:Process|Service|Computer)|Invoke-(?:Expression|Command)|Clear-(?:Content|EventLog|Item))\b/i.test(body)) return false;
|
|
3443
|
+
return true;
|
|
3444
|
+
}
|
|
3445
|
+
function getMonitoringRecallHint(cmd) {
|
|
3446
|
+
const trimmed = cmd.trim();
|
|
3447
|
+
if (hasUnquotedOperator(trimmed, ["&&", "||", ";"])) return null;
|
|
3448
|
+
for (const { pattern, recallHint } of MONITORING_COMMAND_PATTERNS) {
|
|
3449
|
+
if (pattern.test(trimmed)) return recallHint;
|
|
3450
|
+
}
|
|
3451
|
+
if (isPsMultilineSystemQuery(trimmed)) return "--tail 50";
|
|
3452
|
+
return null;
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3455
|
+
// src/recall_index.ts
|
|
2958
3456
|
init_define_import_meta_env();
|
|
2959
3457
|
import * as fs7 from "node:fs";
|
|
3458
|
+
function subdirForCacheType(cacheType) {
|
|
3459
|
+
return cacheType === "web" ? "web_outputs" : "bash_outputs";
|
|
3460
|
+
}
|
|
3461
|
+
function blobStillExists(cacheType, id) {
|
|
3462
|
+
try {
|
|
3463
|
+
const p = blobPath(subdirForCacheType(cacheType), id);
|
|
3464
|
+
return p !== null && fs7.existsSync(p);
|
|
3465
|
+
} catch {
|
|
3466
|
+
return false;
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
var VALID_TYPES = ["bash", "web", "mcp"];
|
|
3470
|
+
var RECALL_DEFAULT_LIMIT = 10;
|
|
3471
|
+
function isRecallCacheType(value) {
|
|
3472
|
+
return VALID_TYPES.includes(value);
|
|
3473
|
+
}
|
|
3474
|
+
function indexRecallEntry(cacheType, id, label, content, storedAt) {
|
|
3475
|
+
try {
|
|
3476
|
+
const db = getDb(globalDbPath());
|
|
3477
|
+
db.prepare(
|
|
3478
|
+
`INSERT INTO cache_recall (cache_type, entry_id, label, content, stored_at)
|
|
3479
|
+
VALUES (@cacheType, @id, @label, @content, @storedAt)
|
|
3480
|
+
ON CONFLICT(cache_type, entry_id) DO UPDATE SET
|
|
3481
|
+
label = excluded.label,
|
|
3482
|
+
content = excluded.content,
|
|
3483
|
+
stored_at = excluded.stored_at`
|
|
3484
|
+
).run({ cacheType, id, label, content, storedAt });
|
|
3485
|
+
} catch {
|
|
3486
|
+
}
|
|
3487
|
+
pruneCacheRecallRows();
|
|
3488
|
+
}
|
|
3489
|
+
function pruneCacheRecallRows(maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
3490
|
+
try {
|
|
3491
|
+
const db = getDb(globalDbPath());
|
|
3492
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
3493
|
+
db.prepare(`DELETE FROM cache_recall WHERE stored_at < ?`).run(cutoff);
|
|
3494
|
+
} catch {
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
var _ftsAvailable = null;
|
|
3498
|
+
function hasFtsTable() {
|
|
3499
|
+
if (_ftsAvailable !== null) return _ftsAvailable;
|
|
3500
|
+
try {
|
|
3501
|
+
const db = getDb(globalDbPath());
|
|
3502
|
+
const row = db.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'cache_recall_fts'`).get();
|
|
3503
|
+
_ftsAvailable = row !== void 0;
|
|
3504
|
+
} catch {
|
|
3505
|
+
_ftsAvailable = false;
|
|
3506
|
+
}
|
|
3507
|
+
return _ftsAvailable;
|
|
3508
|
+
}
|
|
3509
|
+
function buildSnippet(content, query, maxLen = 160) {
|
|
3510
|
+
const flat = content.replace(/\s+/g, " ").trim();
|
|
3511
|
+
const tokens = query.split(/\s+/).filter(Boolean);
|
|
3512
|
+
let idx = -1;
|
|
3513
|
+
const lowerFlat = flat.toLowerCase();
|
|
3514
|
+
for (const token of tokens) {
|
|
3515
|
+
const at = lowerFlat.indexOf(token.toLowerCase());
|
|
3516
|
+
if (at !== -1) {
|
|
3517
|
+
idx = at;
|
|
3518
|
+
break;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
if (idx === -1) {
|
|
3522
|
+
return flat.length > maxLen ? flat.slice(0, maxLen) + "..." : flat;
|
|
3523
|
+
}
|
|
3524
|
+
const start = Math.max(0, idx - Math.floor(maxLen / 3));
|
|
3525
|
+
const end = Math.min(flat.length, start + maxLen);
|
|
3526
|
+
const prefix = start > 0 ? "..." : "";
|
|
3527
|
+
const suffix = end < flat.length ? "..." : "";
|
|
3528
|
+
return prefix + flat.slice(start, end) + suffix;
|
|
3529
|
+
}
|
|
3530
|
+
function toFtsMatchExpr(query) {
|
|
3531
|
+
if (query.trim().length === 0) return null;
|
|
3532
|
+
return sanitizeFtsQuery(query);
|
|
3533
|
+
}
|
|
3534
|
+
function mapRowsToHits(rows, snippetQuery) {
|
|
3535
|
+
return rows.filter((r) => isRecallCacheType(r.cacheType)).map((r) => ({
|
|
3536
|
+
id: r.id,
|
|
3537
|
+
cacheType: r.cacheType,
|
|
3538
|
+
label: r.label ?? "",
|
|
3539
|
+
snippet: buildSnippet(r.content ?? "", snippetQuery),
|
|
3540
|
+
storedAt: r.storedAt ?? 0,
|
|
3541
|
+
blobPresent: blobStillExists(r.cacheType, r.id)
|
|
3542
|
+
}));
|
|
3543
|
+
}
|
|
3544
|
+
function ftsSearch(query, type, limit) {
|
|
3545
|
+
const matchExpr = toFtsMatchExpr(query);
|
|
3546
|
+
if (matchExpr === null) return [];
|
|
3547
|
+
const db = getDb(globalDbPath());
|
|
3548
|
+
const rows = type !== void 0 ? db.prepare(
|
|
3549
|
+
`SELECT c.entry_id AS id, c.cache_type AS cacheType, c.label AS label, c.content AS content, c.stored_at AS storedAt
|
|
3550
|
+
FROM cache_recall_fts
|
|
3551
|
+
JOIN cache_recall c ON c.row_id = cache_recall_fts.rowid
|
|
3552
|
+
WHERE cache_recall_fts MATCH ? AND c.cache_type = ?
|
|
3553
|
+
ORDER BY bm25(cache_recall_fts)
|
|
3554
|
+
LIMIT ?`
|
|
3555
|
+
).all(matchExpr, type, limit) : db.prepare(
|
|
3556
|
+
`SELECT c.entry_id AS id, c.cache_type AS cacheType, c.label AS label, c.content AS content, c.stored_at AS storedAt
|
|
3557
|
+
FROM cache_recall_fts
|
|
3558
|
+
JOIN cache_recall c ON c.row_id = cache_recall_fts.rowid
|
|
3559
|
+
WHERE cache_recall_fts MATCH ?
|
|
3560
|
+
ORDER BY bm25(cache_recall_fts)
|
|
3561
|
+
LIMIT ?`
|
|
3562
|
+
).all(matchExpr, limit);
|
|
3563
|
+
return mapRowsToHits(rows, query);
|
|
3564
|
+
}
|
|
3565
|
+
function likeSearch(query, type, limit) {
|
|
3566
|
+
const trimmed = query.trim();
|
|
3567
|
+
if (!trimmed) return [];
|
|
3568
|
+
const db = getDb(globalDbPath());
|
|
3569
|
+
const needle = `%${trimmed.replace(/\\/g, "\\\\").replace(/[%_]/g, (c) => `\\${c}`)}%`;
|
|
3570
|
+
const rows = type !== void 0 ? db.prepare(
|
|
3571
|
+
`SELECT entry_id AS id, cache_type AS cacheType, label, content, stored_at AS storedAt
|
|
3572
|
+
FROM cache_recall
|
|
3573
|
+
WHERE cache_type = ? AND (label LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\')
|
|
3574
|
+
ORDER BY stored_at DESC
|
|
3575
|
+
LIMIT ?`
|
|
3576
|
+
).all(type, needle, needle, limit) : db.prepare(
|
|
3577
|
+
`SELECT entry_id AS id, cache_type AS cacheType, label, content, stored_at AS storedAt
|
|
3578
|
+
FROM cache_recall
|
|
3579
|
+
WHERE label LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\'
|
|
3580
|
+
ORDER BY stored_at DESC
|
|
3581
|
+
LIMIT ?`
|
|
3582
|
+
).all(needle, needle, limit);
|
|
3583
|
+
return mapRowsToHits(rows, trimmed);
|
|
3584
|
+
}
|
|
3585
|
+
function listRecentRecall(opts = {}) {
|
|
3586
|
+
const limit = opts.limit ?? RECALL_DEFAULT_LIMIT;
|
|
3587
|
+
const columns = `SELECT entry_id AS id, cache_type AS cacheType, label, content, stored_at AS storedAt FROM cache_recall`;
|
|
3588
|
+
try {
|
|
3589
|
+
const db = getDb(globalDbPath());
|
|
3590
|
+
const rows = opts.type !== void 0 ? db.prepare(`${columns} WHERE cache_type = ? ORDER BY stored_at DESC LIMIT ?`).all(opts.type, limit) : db.prepare(`${columns} ORDER BY stored_at DESC LIMIT ?`).all(limit);
|
|
3591
|
+
return mapRowsToHits(rows, "");
|
|
3592
|
+
} catch {
|
|
3593
|
+
return [];
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
function searchRecall(query, opts = {}) {
|
|
3597
|
+
const limit = opts.limit ?? RECALL_DEFAULT_LIMIT;
|
|
3598
|
+
if (query.trim() === "") return [];
|
|
3599
|
+
try {
|
|
3600
|
+
if (hasFtsTable()) {
|
|
3601
|
+
return ftsSearch(query, opts.type, limit);
|
|
3602
|
+
}
|
|
3603
|
+
return likeSearch(query, opts.type, limit);
|
|
3604
|
+
} catch {
|
|
3605
|
+
try {
|
|
3606
|
+
return likeSearch(query, opts.type, limit);
|
|
3607
|
+
} catch {
|
|
3608
|
+
return [];
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
// src/bash_output_cache.ts
|
|
3614
|
+
var BASH_OUTPUT_SUBDIR = "bash_outputs";
|
|
3615
|
+
var _byId = /* @__PURE__ */ new Map();
|
|
3616
|
+
var COMMAND_PATTERNS = {
|
|
3617
|
+
gitMutable: /^\s*git\s+(diff|status)\b/i,
|
|
3618
|
+
gitImmutable: /^\s*git\s+show\s+[0-9a-f]{40}\b/i,
|
|
3619
|
+
gitDiffScoped: /\s--\s+\S/,
|
|
3620
|
+
dirListing: /^\s*(?:ls|eza|exa|dir|Get-ChildItem|gci)\b/i,
|
|
3621
|
+
depList: /^\s*(?:npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:ls|list)\b|pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|uv\s+pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|pnpm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|ls)\b|yarn\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list)\b|cargo\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*tree\b|bundle\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|show)\b|composer\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*show\b)/i,
|
|
3622
|
+
npmInstall: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:install|ci)\b/i,
|
|
3623
|
+
npmAudit: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*audit\b(?!.*(?:--fix|fix)\b)/i,
|
|
3624
|
+
npmOutdated: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*outdated\b/i,
|
|
3625
|
+
envProbe: /^\s*(?:node\s+(?:-v|--version)|npm\s+(?:-v|--version)|python3?\s+(?:(?:-V)\b|--?version)|git\s+--version|uv\s+--version|go\s+version|rustc\s+--version|cargo\s+--version|java\s+--version|ruby\s+--version|gem\s+--version|php\s+--version|which\b|where\b)/i,
|
|
3626
|
+
npx: /^(?!.*\b(?:install|add|remove|uninstall|i|rm|update|upgrade|set|get|publish|link|ci|audit|shrinkwrap|dedupe|prune|rebuild)\b)\s*npx\s+(?:--?yes\s+)?/i,
|
|
3627
|
+
gitPush: /^\s*git\s+push\b/i,
|
|
3628
|
+
testRunner: /^\s*(?:npx\s+)?(?:pytest|vitest|jest|go\s+test)\b/i,
|
|
3629
|
+
lintCommand: /^\s*(?:(?:npx\s+)?eslint|(?:uv\s+run\s+)?ruff)\b/i,
|
|
3630
|
+
npmRunScript: /^\s*npm\s+run(?:-script)?\b/i,
|
|
3631
|
+
catCommand: /^\s*cat\b/i
|
|
3632
|
+
};
|
|
3633
|
+
var DEP_LOCKFILES = {
|
|
3634
|
+
npm: ["package-lock.json", "yarn.lock"],
|
|
3635
|
+
pip: ["requirements.txt"],
|
|
3636
|
+
uv: ["uv.lock", "requirements.txt"],
|
|
3637
|
+
pnpm: ["pnpm-lock.yaml"],
|
|
3638
|
+
yarn: ["yarn.lock"],
|
|
3639
|
+
cargo: ["Cargo.lock"],
|
|
3640
|
+
bundle: ["Gemfile.lock"],
|
|
3641
|
+
composer: ["composer.lock"]
|
|
3642
|
+
};
|
|
3643
|
+
function isCommandOfType(cmd, type) {
|
|
3644
|
+
const pattern = COMMAND_PATTERNS[type];
|
|
3645
|
+
return pattern?.test(cmd) ?? false;
|
|
3646
|
+
}
|
|
3647
|
+
var isGitMutableCommand = (cmd) => isCommandOfType(cmd, "gitMutable");
|
|
3648
|
+
var isDirListingCommand = (cmd) => isCommandOfType(cmd, "dirListing");
|
|
3649
|
+
var isDepListCommand = (cmd) => isCommandOfType(cmd, "depList");
|
|
3650
|
+
var isNpmInstallCommand = (cmd) => isCommandOfType(cmd, "npmInstall");
|
|
3651
|
+
var isNpmAuditCommand = (cmd) => isCommandOfType(cmd, "npmAudit");
|
|
3652
|
+
var isNpmOutdatedCommand = (cmd) => isCommandOfType(cmd, "npmOutdated");
|
|
3653
|
+
var isGitPushCommand = (cmd) => isCommandOfType(cmd, "gitPush");
|
|
3654
|
+
var isTestRunnerCommand2 = (cmd) => isCommandOfType(cmd, "testRunner");
|
|
3655
|
+
var isLintCommand = (cmd) => isCommandOfType(cmd, "lintCommand");
|
|
3656
|
+
var isNpmRunScriptCommand = (cmd) => isCommandOfType(cmd, "npmRunScript");
|
|
3657
|
+
var isCatCommand = (cmd) => isCommandOfType(cmd, "catCommand");
|
|
3658
|
+
function isScopedGitStatusOrDiffStatCommand(cmd) {
|
|
3659
|
+
if (!isCommandOfType(cmd, "gitMutable")) return false;
|
|
3660
|
+
if (!isCommandOfType(cmd, "gitDiffScoped")) return false;
|
|
3661
|
+
if (/^\s*git\s+diff\b/i.test(cmd) && !/--stat\b/.test(cmd)) return false;
|
|
3662
|
+
return true;
|
|
3663
|
+
}
|
|
3664
|
+
function gitStateFingerprintSync(cwd) {
|
|
3665
|
+
try {
|
|
3666
|
+
const headResult = runGit(["rev-parse", "HEAD"], { cwd });
|
|
3667
|
+
if (headResult.exitCode !== 0) return null;
|
|
3668
|
+
const headSha = headResult.stdout.trim();
|
|
3669
|
+
let statusHash = "";
|
|
3670
|
+
const statusResult = runGit(["status", "--porcelain"], { cwd });
|
|
3671
|
+
if (statusResult.exitCode === 0) {
|
|
3672
|
+
statusHash = shortFingerprint(statusResult.stdout);
|
|
3673
|
+
}
|
|
3674
|
+
const key = `${headSha}\0${statusHash}`;
|
|
3675
|
+
return shortFingerprint(key);
|
|
3676
|
+
} catch {
|
|
3677
|
+
return null;
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
var DIR_FINGERPRINT_LISTING_CAP_ENTRIES = 1e4;
|
|
3681
|
+
function dirStateFingerprintSync(path12) {
|
|
3682
|
+
try {
|
|
3683
|
+
const stat = statSync3(path12);
|
|
3684
|
+
if (!stat.isDirectory()) return null;
|
|
3685
|
+
const entries = readdirSync2(path12);
|
|
3686
|
+
if (entries.length <= DIR_FINGERPRINT_LISTING_CAP_ENTRIES) {
|
|
3687
|
+
return shortFingerprint(entries.slice().sort().join("\0"));
|
|
3688
|
+
}
|
|
3689
|
+
return shortFingerprint(stat.mtimeMs.toString());
|
|
3690
|
+
} catch {
|
|
3691
|
+
return null;
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
var FILE_FINGERPRINT_CONTENT_CAP_BYTES = 2 * 1024 * 1024;
|
|
3695
|
+
function fileStateFingerprintSync(path12) {
|
|
3696
|
+
try {
|
|
3697
|
+
const stat = statSync3(path12);
|
|
3698
|
+
if (!stat.isFile()) return null;
|
|
3699
|
+
if (stat.size <= FILE_FINGERPRINT_CONTENT_CAP_BYTES) {
|
|
3700
|
+
return shortFingerprint(readFileSync5(path12));
|
|
3701
|
+
}
|
|
3702
|
+
return shortFingerprint(`${stat.mtimeMs}\0${stat.size}`);
|
|
3703
|
+
} catch {
|
|
3704
|
+
return null;
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
function depLockfileFingerprintSync(cmd, cwd) {
|
|
3708
|
+
if (!cwd) return null;
|
|
3709
|
+
const stripped = cmd.trim();
|
|
3710
|
+
const firstToken = stripped.split(/\s+/)[0]?.toLowerCase() || "";
|
|
3711
|
+
if (!firstToken) return null;
|
|
3712
|
+
const candidates = firstToken === "uv" ? DEP_LOCKFILES["uv"] : DEP_LOCKFILES[firstToken];
|
|
3713
|
+
if (!candidates) return null;
|
|
3714
|
+
for (const lockfile of candidates) {
|
|
3715
|
+
try {
|
|
3716
|
+
const content = readFileSync5(resolve4(cwd, lockfile));
|
|
3717
|
+
return shortFingerprint(content);
|
|
3718
|
+
} catch {
|
|
3719
|
+
continue;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
return null;
|
|
3723
|
+
}
|
|
3724
|
+
function normalizeCommandForCacheKey(cmd) {
|
|
3725
|
+
const trimmed = cmd.trim();
|
|
3726
|
+
const tokens = [];
|
|
3727
|
+
let current = "";
|
|
3728
|
+
let quoteChar = null;
|
|
3729
|
+
const flush = () => {
|
|
3730
|
+
if (current.length > 0) {
|
|
3731
|
+
tokens.push(current);
|
|
3732
|
+
current = "";
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
3736
|
+
const ch = trimmed[i];
|
|
3737
|
+
if (quoteChar !== null) {
|
|
3738
|
+
current += ch;
|
|
3739
|
+
if (ch === quoteChar) quoteChar = null;
|
|
3740
|
+
continue;
|
|
3741
|
+
}
|
|
3742
|
+
if (ch === '"' || ch === "'") {
|
|
3743
|
+
quoteChar = ch;
|
|
3744
|
+
current += ch;
|
|
3745
|
+
continue;
|
|
3746
|
+
}
|
|
3747
|
+
if (/\s/.test(ch)) {
|
|
3748
|
+
flush();
|
|
3749
|
+
continue;
|
|
3750
|
+
}
|
|
3751
|
+
current += ch === "\\" ? "/" : ch;
|
|
3752
|
+
}
|
|
3753
|
+
flush();
|
|
3754
|
+
const normalized_tokens = tokens.map((token) => {
|
|
3755
|
+
if (token.startsWith("-") || ["&&", "||", "|", ">", ">>", ";", "&"].includes(token)) {
|
|
3756
|
+
return token;
|
|
3757
|
+
}
|
|
3758
|
+
if (token.startsWith("./") && !token.startsWith("../")) {
|
|
3759
|
+
token = token.slice(2);
|
|
3760
|
+
}
|
|
3761
|
+
if (token.endsWith("/") && token !== "/") {
|
|
3762
|
+
token = token.slice(0, -1);
|
|
3763
|
+
}
|
|
3764
|
+
return token || ".";
|
|
3765
|
+
});
|
|
3766
|
+
return normalized_tokens.join(" ");
|
|
3767
|
+
}
|
|
3768
|
+
function commandHashSync(command, cwd = null) {
|
|
3769
|
+
const normalized = normalizeCommandForCacheKey(command);
|
|
3770
|
+
let key = cwd ? `${normalizePath(cwd)}\0${normalized}` : normalized;
|
|
3771
|
+
if (cwd && isGitMutableCommand(command)) {
|
|
3772
|
+
const fp = gitStateFingerprintSync(cwd);
|
|
3773
|
+
if (fp) key = `${key}\0git:${fp}`;
|
|
3774
|
+
}
|
|
3775
|
+
if (cwd && isDirListingCommand(command)) {
|
|
3776
|
+
const target = extractFirstPathArg(command, cwd, cwd);
|
|
3777
|
+
if (target) {
|
|
3778
|
+
const fp = dirStateFingerprintSync(target);
|
|
3779
|
+
if (fp) key = `${key}\0dir:${fp}`;
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
if (isDepListCommand(command)) {
|
|
3783
|
+
const fp = depLockfileFingerprintSync(command, cwd);
|
|
3784
|
+
if (fp) key = `${key}\0lockfile:${fp}`;
|
|
3785
|
+
}
|
|
3786
|
+
if (cwd && (isNpmInstallCommand(command) || isNpmAuditCommand(command) || isNpmOutdatedCommand(command))) {
|
|
3787
|
+
const fp = depLockfileFingerprintSync(command, cwd);
|
|
3788
|
+
if (fp) key = `${key}\0npm-install:${fp}`;
|
|
3789
|
+
}
|
|
3790
|
+
return shortFingerprint(key);
|
|
3791
|
+
}
|
|
3792
|
+
function commandHash(command, cwd = null) {
|
|
3793
|
+
return Promise.resolve(commandHashSync(command, cwd));
|
|
3794
|
+
}
|
|
3795
|
+
function computeBashFingerprints(command, cwd) {
|
|
3796
|
+
const fingerprints = {};
|
|
3797
|
+
if (cwd && (isGitMutableCommand(command) || isGitPushCommand(command) || isTestRunnerCommand2(command) || isLintCommand(command) || isBuildCommand(command) || isNpmRunScriptCommand(command))) {
|
|
3798
|
+
const fp = gitStateFingerprintSync(cwd);
|
|
3799
|
+
if (fp) fingerprints.git = fp;
|
|
3800
|
+
}
|
|
3801
|
+
if (cwd && isDirListingCommand(command)) {
|
|
3802
|
+
const target = extractFirstPathArg(command, cwd, cwd);
|
|
3803
|
+
if (target) {
|
|
3804
|
+
const fp = dirStateFingerprintSync(target);
|
|
3805
|
+
if (fp) fingerprints.dir = fp;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
if (isDepListCommand(command) || cwd && (isNpmInstallCommand(command) || isNpmAuditCommand(command) || isNpmOutdatedCommand(command))) {
|
|
3809
|
+
const fp = depLockfileFingerprintSync(command, cwd);
|
|
3810
|
+
if (fp) fingerprints.lockfile = fp;
|
|
3811
|
+
}
|
|
3812
|
+
if (cwd && isCatCommand(command)) {
|
|
3813
|
+
const target = extractFirstPathArg(command, cwd, null);
|
|
3814
|
+
if (target) {
|
|
3815
|
+
const fp = fileStateFingerprintSync(target);
|
|
3816
|
+
if (fp) fingerprints.file = fp;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
return Object.keys(fingerprints).length > 0 ? fingerprints : void 0;
|
|
3820
|
+
}
|
|
3821
|
+
function isBashEntryStale(entry, command, cwd) {
|
|
3822
|
+
const stored = entry.fingerprints;
|
|
3823
|
+
if (!stored) return false;
|
|
3824
|
+
const current = computeBashFingerprints(command, cwd);
|
|
3825
|
+
if (stored.git !== void 0 && stored.git !== current?.git) return true;
|
|
3826
|
+
if (stored.dir !== void 0 && stored.dir !== current?.dir) return true;
|
|
3827
|
+
if (stored.lockfile !== void 0 && stored.lockfile !== current?.lockfile) return true;
|
|
3828
|
+
if (stored.file !== void 0 && stored.file !== current?.file) return true;
|
|
3829
|
+
return false;
|
|
3830
|
+
}
|
|
3831
|
+
function tokenizeShellArgs(cmd) {
|
|
3832
|
+
const trimmed = cmd.trim();
|
|
3833
|
+
const tokens = [];
|
|
3834
|
+
let current = "";
|
|
3835
|
+
let quoteChar = null;
|
|
3836
|
+
let hasToken = false;
|
|
3837
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
3838
|
+
const ch = trimmed[i];
|
|
3839
|
+
if (quoteChar !== null) {
|
|
3840
|
+
if (ch === quoteChar) {
|
|
3841
|
+
quoteChar = null;
|
|
3842
|
+
} else {
|
|
3843
|
+
current += ch;
|
|
3844
|
+
}
|
|
3845
|
+
continue;
|
|
3846
|
+
}
|
|
3847
|
+
if (ch === '"' || ch === "'") {
|
|
3848
|
+
quoteChar = ch;
|
|
3849
|
+
hasToken = true;
|
|
3850
|
+
continue;
|
|
3851
|
+
}
|
|
3852
|
+
if (/\s/.test(ch)) {
|
|
3853
|
+
if (hasToken) {
|
|
3854
|
+
tokens.push(current);
|
|
3855
|
+
current = "";
|
|
3856
|
+
hasToken = false;
|
|
3857
|
+
}
|
|
3858
|
+
continue;
|
|
3859
|
+
}
|
|
3860
|
+
current += ch;
|
|
3861
|
+
hasToken = true;
|
|
3862
|
+
}
|
|
3863
|
+
if (hasToken) tokens.push(current);
|
|
3864
|
+
return tokens;
|
|
3865
|
+
}
|
|
3866
|
+
function extractFirstPathArg(cmd, cwd, fallback) {
|
|
3867
|
+
const tokens = tokenizeShellArgs(cmd);
|
|
3868
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
3869
|
+
const token = tokens[i];
|
|
3870
|
+
if (!token.startsWith("-")) {
|
|
3871
|
+
if (!token.startsWith("/")) {
|
|
3872
|
+
return resolve4(cwd, token);
|
|
3873
|
+
}
|
|
3874
|
+
return token;
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3877
|
+
return fallback;
|
|
3878
|
+
}
|
|
3879
|
+
var ISSUE_LINE_PATTERN = /\b(?:error|fail(?:ed|ure)?|warning)\b/i;
|
|
3880
|
+
function summarizeOutputDelta(oldOutput, newOutput) {
|
|
3881
|
+
if (oldOutput === newOutput) return null;
|
|
3882
|
+
const oldLines = oldOutput.split("\n");
|
|
3883
|
+
const newLines = newOutput.split("\n");
|
|
3884
|
+
const oldIssueLines = oldLines.filter((l) => ISSUE_LINE_PATTERN.test(l));
|
|
3885
|
+
if (oldIssueLines.length > 0) {
|
|
3886
|
+
const newIssueLines = newLines.filter((l) => ISSUE_LINE_PATTERN.test(l));
|
|
3887
|
+
const priorTotal = oldIssueLines.length;
|
|
3888
|
+
const availableCounts = /* @__PURE__ */ new Map();
|
|
3889
|
+
for (const l of newIssueLines) availableCounts.set(l, (availableCounts.get(l) ?? 0) + 1);
|
|
3890
|
+
let resolved = 0;
|
|
3891
|
+
for (const l of oldIssueLines) {
|
|
3892
|
+
const avail = availableCounts.get(l) ?? 0;
|
|
3893
|
+
if (avail > 0) {
|
|
3894
|
+
availableCounts.set(l, avail - 1);
|
|
3895
|
+
} else {
|
|
3896
|
+
resolved++;
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
const remaining = newIssueLines.length;
|
|
3900
|
+
return `[token-goat: delta] ${resolved} of ${priorTotal} prior issues resolved; remaining: ${remaining}`;
|
|
3901
|
+
}
|
|
3902
|
+
return `[token-goat: delta] output changed: ${oldLines.length} -> ${newLines.length} lines`;
|
|
3903
|
+
}
|
|
3904
|
+
function storeBashOutputSync(command, output, exitCode, cwd = null) {
|
|
3905
|
+
const id = commandHashSync(command, cwd);
|
|
3906
|
+
const fingerprints = computeBashFingerprints(command, cwd);
|
|
3907
|
+
const redactedOutput = redactSecrets(output).text;
|
|
3908
|
+
const redactedCommand = redactSecrets(command).text;
|
|
3909
|
+
const entry = {
|
|
3910
|
+
id,
|
|
3911
|
+
command: redactedCommand,
|
|
3912
|
+
output: redactedOutput,
|
|
3913
|
+
exitCode,
|
|
3914
|
+
storedAt: Date.now(),
|
|
3915
|
+
sizeBytes: Buffer.byteLength(redactedOutput, "utf-8"),
|
|
3916
|
+
...fingerprints ? { fingerprints } : {}
|
|
3917
|
+
};
|
|
3918
|
+
_byId.set(id, entry);
|
|
3919
|
+
storeBlob(BASH_OUTPUT_SUBDIR, id, entry);
|
|
3920
|
+
indexRecallEntry("bash", id, redactedCommand, `${redactedCommand}
|
|
3921
|
+
${redactedOutput}`, entry.storedAt);
|
|
3922
|
+
return id;
|
|
3923
|
+
}
|
|
3924
|
+
function storeBashOutput(command, output, exitCode, cwd = null) {
|
|
3925
|
+
return Promise.resolve(storeBashOutputSync(command, output, exitCode, cwd));
|
|
3926
|
+
}
|
|
3927
|
+
function coerceBashEntry(raw) {
|
|
3928
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
3929
|
+
const o = raw;
|
|
3930
|
+
if (typeof o["id"] !== "string" || typeof o["command"] !== "string" || typeof o["output"] !== "string" || typeof o["exitCode"] !== "number" || typeof o["storedAt"] !== "number" || typeof o["sizeBytes"] !== "number") {
|
|
3931
|
+
return null;
|
|
3932
|
+
}
|
|
3933
|
+
const entry = {
|
|
3934
|
+
id: o["id"],
|
|
3935
|
+
command: o["command"],
|
|
3936
|
+
output: o["output"],
|
|
3937
|
+
exitCode: o["exitCode"],
|
|
3938
|
+
storedAt: o["storedAt"],
|
|
3939
|
+
sizeBytes: o["sizeBytes"]
|
|
3940
|
+
};
|
|
3941
|
+
const rawFingerprints = o["fingerprints"];
|
|
3942
|
+
if (rawFingerprints !== null && typeof rawFingerprints === "object") {
|
|
3943
|
+
const f = rawFingerprints;
|
|
3944
|
+
const fingerprints = {};
|
|
3945
|
+
if (typeof f["git"] === "string") fingerprints.git = f["git"];
|
|
3946
|
+
if (typeof f["dir"] === "string") fingerprints.dir = f["dir"];
|
|
3947
|
+
if (typeof f["lockfile"] === "string") fingerprints.lockfile = f["lockfile"];
|
|
3948
|
+
if (typeof f["file"] === "string") fingerprints.file = f["file"];
|
|
3949
|
+
if (Object.keys(fingerprints).length > 0) return { ...entry, fingerprints };
|
|
3950
|
+
}
|
|
3951
|
+
return entry;
|
|
3952
|
+
}
|
|
3953
|
+
function getBashOutput(id) {
|
|
3954
|
+
const hit = _byId.get(id);
|
|
3955
|
+
if (hit !== void 0) return hit;
|
|
3956
|
+
if (isBlobStale(BASH_OUTPUT_SUBDIR, id)) return null;
|
|
3957
|
+
const entry = coerceBashEntry(loadBlob(BASH_OUTPUT_SUBDIR, id));
|
|
3958
|
+
if (entry === null) return null;
|
|
3959
|
+
_byId.set(id, entry);
|
|
3960
|
+
return entry;
|
|
3961
|
+
}
|
|
3962
|
+
registerReset(() => {
|
|
3963
|
+
_byId = /* @__PURE__ */ new Map();
|
|
3964
|
+
});
|
|
3965
|
+
|
|
3966
|
+
// src/install.ts
|
|
3967
|
+
init_define_import_meta_env();
|
|
3968
|
+
import * as fs8 from "node:fs";
|
|
2960
3969
|
import * as os4 from "node:os";
|
|
2961
3970
|
import * as path7 from "node:path";
|
|
2962
3971
|
|
|
@@ -3140,7 +4149,7 @@ var SettingsParseError = class extends Error {
|
|
|
3140
4149
|
function readSettings(p, opts = {}) {
|
|
3141
4150
|
let raw;
|
|
3142
4151
|
try {
|
|
3143
|
-
raw =
|
|
4152
|
+
raw = fs8.readFileSync(p, "utf8");
|
|
3144
4153
|
} catch {
|
|
3145
4154
|
return {};
|
|
3146
4155
|
}
|
|
@@ -3272,7 +4281,7 @@ function isInstalled(scope = "user") {
|
|
|
3272
4281
|
const hooks = settings.hooks;
|
|
3273
4282
|
if (hooks === void 0) return false;
|
|
3274
4283
|
const scriptPath = claudeHookScriptPath();
|
|
3275
|
-
if (!
|
|
4284
|
+
if (!fs8.existsSync(scriptPath)) return false;
|
|
3276
4285
|
for (const [eventKey, eventArg] of HOOK_EVENT_MAP) {
|
|
3277
4286
|
const expectedCommand = hookCommandFor(scriptPath, eventArg);
|
|
3278
4287
|
if (!groupHasTokenGoat(hooks[eventKey], (c) => c === expectedCommand)) return false;
|
|
@@ -3310,7 +4319,7 @@ function findStrayClaudeMdBlocks(searchRoot) {
|
|
|
3310
4319
|
const root = searchRoot ?? path7.join(os4.homedir(), ".claude");
|
|
3311
4320
|
const canonical = path7.resolve(claudeMdPath());
|
|
3312
4321
|
const found = [];
|
|
3313
|
-
if (!
|
|
4322
|
+
if (!fs8.existsSync(root)) return found;
|
|
3314
4323
|
const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
3315
4324
|
const MAX_DEPTH = 6;
|
|
3316
4325
|
const hasRealBlock = (text) => {
|
|
@@ -3326,7 +4335,7 @@ function findStrayClaudeMdBlocks(searchRoot) {
|
|
|
3326
4335
|
if (depth > MAX_DEPTH) return;
|
|
3327
4336
|
let entries;
|
|
3328
4337
|
try {
|
|
3329
|
-
entries =
|
|
4338
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
3330
4339
|
} catch {
|
|
3331
4340
|
return;
|
|
3332
4341
|
}
|
|
@@ -3340,7 +4349,7 @@ function findStrayClaudeMdBlocks(searchRoot) {
|
|
|
3340
4349
|
if (path7.resolve(full) === canonical) continue;
|
|
3341
4350
|
let text;
|
|
3342
4351
|
try {
|
|
3343
|
-
text =
|
|
4352
|
+
text = fs8.readFileSync(full, "utf8");
|
|
3344
4353
|
} catch {
|
|
3345
4354
|
continue;
|
|
3346
4355
|
}
|
|
@@ -3378,7 +4387,7 @@ function installSkill() {
|
|
|
3378
4387
|
const p = skillPath();
|
|
3379
4388
|
let existing = null;
|
|
3380
4389
|
try {
|
|
3381
|
-
existing =
|
|
4390
|
+
existing = fs8.readFileSync(p, "utf8");
|
|
3382
4391
|
} catch {
|
|
3383
4392
|
}
|
|
3384
4393
|
const skillContent = skillMdContent();
|
|
@@ -3390,17 +4399,17 @@ function installSkill() {
|
|
|
3390
4399
|
}
|
|
3391
4400
|
function uninstallSkill() {
|
|
3392
4401
|
const dir = skillDir();
|
|
3393
|
-
if (!
|
|
4402
|
+
if (!fs8.existsSync(dir)) return false;
|
|
3394
4403
|
removeCreatedBackups(skillPath());
|
|
3395
4404
|
assertWriteInScope(dir);
|
|
3396
|
-
|
|
4405
|
+
fs8.rmSync(dir, { recursive: true, force: true });
|
|
3397
4406
|
return true;
|
|
3398
4407
|
}
|
|
3399
4408
|
|
|
3400
4409
|
// src/bridges/codex_install.ts
|
|
3401
4410
|
init_define_import_meta_env();
|
|
3402
4411
|
import * as crypto2 from "node:crypto";
|
|
3403
|
-
import * as
|
|
4412
|
+
import * as fs9 from "node:fs";
|
|
3404
4413
|
import * as os5 from "node:os";
|
|
3405
4414
|
import * as path8 from "node:path";
|
|
3406
4415
|
|
|
@@ -3567,7 +4576,7 @@ function codexHookScriptPath() {
|
|
|
3567
4576
|
function readCodexConfig(p, opts = {}) {
|
|
3568
4577
|
let raw;
|
|
3569
4578
|
try {
|
|
3570
|
-
raw =
|
|
4579
|
+
raw = fs9.readFileSync(p, "utf8");
|
|
3571
4580
|
} catch {
|
|
3572
4581
|
return {};
|
|
3573
4582
|
}
|
|
@@ -3773,7 +4782,7 @@ function uninstallCodex() {
|
|
|
3773
4782
|
removedAny = true;
|
|
3774
4783
|
}
|
|
3775
4784
|
try {
|
|
3776
|
-
|
|
4785
|
+
fs9.unlinkSync(scriptPath);
|
|
3777
4786
|
removedAny = true;
|
|
3778
4787
|
} catch {
|
|
3779
4788
|
}
|
|
@@ -3809,10 +4818,10 @@ function isCodexInstalled() {
|
|
|
3809
4818
|
const expectedHash = computeCodexHookHash(eventArg, expectedCommand);
|
|
3810
4819
|
if (hooksState[stateKey]?.trusted_hash !== expectedHash) return false;
|
|
3811
4820
|
}
|
|
3812
|
-
if (!
|
|
4821
|
+
if (!fs9.existsSync(scriptPath)) return false;
|
|
3813
4822
|
let agents;
|
|
3814
4823
|
try {
|
|
3815
|
-
agents =
|
|
4824
|
+
agents = fs9.readFileSync(codexAgentsPath(), "utf8");
|
|
3816
4825
|
} catch {
|
|
3817
4826
|
return false;
|
|
3818
4827
|
}
|
|
@@ -3837,7 +4846,7 @@ function stripAgentsBlock(p) {
|
|
|
3837
4846
|
|
|
3838
4847
|
// src/bridges/kimi_install.ts
|
|
3839
4848
|
init_define_import_meta_env();
|
|
3840
|
-
import * as
|
|
4849
|
+
import * as fs10 from "node:fs";
|
|
3841
4850
|
import * as os6 from "node:os";
|
|
3842
4851
|
import * as path9 from "node:path";
|
|
3843
4852
|
|
|
@@ -3967,7 +4976,7 @@ function kimiSkillPath() {
|
|
|
3967
4976
|
function readKimiConfig(p, opts = {}) {
|
|
3968
4977
|
let raw;
|
|
3969
4978
|
try {
|
|
3970
|
-
raw =
|
|
4979
|
+
raw = fs10.readFileSync(p, "utf8");
|
|
3971
4980
|
} catch {
|
|
3972
4981
|
return {};
|
|
3973
4982
|
}
|
|
@@ -4070,16 +5079,16 @@ function uninstallKimi() {
|
|
|
4070
5079
|
}
|
|
4071
5080
|
if (stripKimiAgentsBlock(kimiAgentsPath())) removed = true;
|
|
4072
5081
|
try {
|
|
4073
|
-
if (
|
|
5082
|
+
if (fs10.existsSync(kimiSkillDir())) {
|
|
4074
5083
|
removeCreatedBackups(kimiSkillPath());
|
|
4075
|
-
|
|
5084
|
+
fs10.rmSync(kimiSkillDir(), { recursive: true, force: true });
|
|
4076
5085
|
removed = true;
|
|
4077
5086
|
}
|
|
4078
5087
|
} catch {
|
|
4079
5088
|
}
|
|
4080
5089
|
try {
|
|
4081
|
-
if (
|
|
4082
|
-
|
|
5090
|
+
if (fs10.existsSync(kimiHookScriptPath())) {
|
|
5091
|
+
fs10.rmSync(kimiHookScriptPath(), { force: true });
|
|
4083
5092
|
removed = true;
|
|
4084
5093
|
}
|
|
4085
5094
|
} catch {
|
|
@@ -4100,7 +5109,7 @@ function isKimiInstalled() {
|
|
|
4100
5109
|
|
|
4101
5110
|
// src/bridges/grok_install.ts
|
|
4102
5111
|
init_define_import_meta_env();
|
|
4103
|
-
import * as
|
|
5112
|
+
import * as fs11 from "node:fs";
|
|
4104
5113
|
import * as os7 from "node:os";
|
|
4105
5114
|
import * as path10 from "node:path";
|
|
4106
5115
|
|
|
@@ -4244,12 +5253,12 @@ function uninstallGrok() {
|
|
|
4244
5253
|
const scriptPath = grokHookScriptPath();
|
|
4245
5254
|
let removedAny = false;
|
|
4246
5255
|
try {
|
|
4247
|
-
|
|
5256
|
+
fs11.unlinkSync(configPath);
|
|
4248
5257
|
removedAny = true;
|
|
4249
5258
|
} catch {
|
|
4250
5259
|
}
|
|
4251
5260
|
try {
|
|
4252
|
-
|
|
5261
|
+
fs11.unlinkSync(scriptPath);
|
|
4253
5262
|
removedAny = true;
|
|
4254
5263
|
} catch {
|
|
4255
5264
|
}
|
|
@@ -4257,12 +5266,12 @@ function uninstallGrok() {
|
|
|
4257
5266
|
return removedAny;
|
|
4258
5267
|
}
|
|
4259
5268
|
function isGrokInstalled() {
|
|
4260
|
-
return
|
|
5269
|
+
return fs11.existsSync(grokConfigPath()) && fs11.existsSync(grokHookScriptPath());
|
|
4261
5270
|
}
|
|
4262
5271
|
|
|
4263
5272
|
// src/bridges/vscode_install.ts
|
|
4264
5273
|
init_define_import_meta_env();
|
|
4265
|
-
import * as
|
|
5274
|
+
import * as fs12 from "node:fs";
|
|
4266
5275
|
import * as os8 from "node:os";
|
|
4267
5276
|
import * as path11 from "node:path";
|
|
4268
5277
|
var VSCODE_GUIDANCE_BEGIN = "<!-- token-goat-vscode-begin -->";
|
|
@@ -4311,7 +5320,7 @@ function vscodeUserSettingsPath() {
|
|
|
4311
5320
|
function vscodeUsesClaudeHooks(settingsPath2 = vscodeUserSettingsPath()) {
|
|
4312
5321
|
let text;
|
|
4313
5322
|
try {
|
|
4314
|
-
text =
|
|
5323
|
+
text = fs12.readFileSync(settingsPath2, "utf8");
|
|
4315
5324
|
} catch {
|
|
4316
5325
|
return false;
|
|
4317
5326
|
}
|
|
@@ -4326,7 +5335,7 @@ var updateConfig = setTokenGoatServer;
|
|
|
4326
5335
|
function otherScopeHasManagedServer(opts) {
|
|
4327
5336
|
const otherPath = otherScopeMcpPath2(opts);
|
|
4328
5337
|
if (opts.project !== true && !projectPathIsConsultable(otherPath, path11.resolve(opts.projectRoot ?? process.cwd()))) return false;
|
|
4329
|
-
if (!
|
|
5338
|
+
if (!fs12.existsSync(otherPath)) return false;
|
|
4330
5339
|
try {
|
|
4331
5340
|
const config = readConfig(otherPath);
|
|
4332
5341
|
const servers = config.value["servers"];
|
|
@@ -4343,7 +5352,7 @@ function vscodeDecoderConfigured(opts = {}) {
|
|
|
4343
5352
|
if (projectPathIsConsultable(projectPath, path11.resolve(opts.projectRoot))) checkedPaths.push(projectPath);
|
|
4344
5353
|
}
|
|
4345
5354
|
for (const candidate of checkedPaths) {
|
|
4346
|
-
if (!
|
|
5355
|
+
if (!fs12.existsSync(candidate)) continue;
|
|
4347
5356
|
try {
|
|
4348
5357
|
const config = readConfig(candidate);
|
|
4349
5358
|
const servers = config.value["servers"];
|
|
@@ -4358,7 +5367,7 @@ function vscodeDecoderConfigured(opts = {}) {
|
|
|
4358
5367
|
}
|
|
4359
5368
|
function writeGuidance2(filePath, userScope) {
|
|
4360
5369
|
let created = false;
|
|
4361
|
-
if (userScope && !
|
|
5370
|
+
if (userScope && !fs12.existsSync(filePath)) {
|
|
4362
5371
|
ensureDirSync(path11.dirname(filePath));
|
|
4363
5372
|
atomicWriteText(filePath, USER_INSTRUCTIONS_FRONTMATTER);
|
|
4364
5373
|
created = true;
|
|
@@ -4409,7 +5418,7 @@ function installVscodeScoped(opts) {
|
|
|
4409
5418
|
throw new Error(`VS Code MCP JSON at ${mcpPath} already has a non-token-goat-managed server named "token-goat"`);
|
|
4410
5419
|
}
|
|
4411
5420
|
const next = updateConfig(config.text, managedServer());
|
|
4412
|
-
const mcpExisted =
|
|
5421
|
+
const mcpExisted = fs12.existsSync(mcpPath);
|
|
4413
5422
|
ensureDirSync(path11.dirname(mcpPath));
|
|
4414
5423
|
if (config.text !== next) {
|
|
4415
5424
|
backupFile(mcpPath);
|
|
@@ -4435,7 +5444,7 @@ function uninstallVscodeScoped(opts) {
|
|
|
4435
5444
|
assertProjectTargetsAreInTheProject(opts);
|
|
4436
5445
|
const mcpPath = vscodeMcpPath(opts);
|
|
4437
5446
|
let removed = false;
|
|
4438
|
-
if (
|
|
5447
|
+
if (fs12.existsSync(mcpPath)) {
|
|
4439
5448
|
const config = readConfig(mcpPath);
|
|
4440
5449
|
const servers = config.value["servers"];
|
|
4441
5450
|
if (servers !== void 0 && (servers === null || typeof servers !== "object" || Array.isArray(servers))) {
|
|
@@ -4455,7 +5464,7 @@ function uninstallVscodeScoped(opts) {
|
|
|
4455
5464
|
const instructionsPath = vscodeInstructionsPath(opts);
|
|
4456
5465
|
if (stripDelimitedBlock(instructionsPath, BEGIN, END, opts.keepBackups === true)) {
|
|
4457
5466
|
removed = true;
|
|
4458
|
-
if (opts.project !== true &&
|
|
5467
|
+
if (opts.project !== true && fs12.readFileSync(instructionsPath, "utf8").trim() === USER_INSTRUCTIONS_FRONTMATTER.trim()) removeFileInScope(instructionsPath);
|
|
4459
5468
|
}
|
|
4460
5469
|
if (opts.project === true) syncVisualStudioProjectGuidance(instructionsPath);
|
|
4461
5470
|
if (releaseCopilotHooksFile(vscodeHooksDir(opts), "vscode", opts.keepBackups === true)) removed = true;
|
|
@@ -5318,25 +6327,25 @@ function makeLanguageFilter(cfg) {
|
|
|
5318
6327
|
// src/tool_filters/ai_clis.ts
|
|
5319
6328
|
var _GH_COPILOT_SPINNER_RE = /^\s*(?:Asking GitHub Copilot|Generating|Thinking|Fetching)\s*(?:\.{1,3}\s*)?$/i;
|
|
5320
6329
|
var _GH_COPILOT_BANNER_RE = /^\s*(?:Welcome to GitHub Copilot|Using GitHub Copilot|Authenticated as|GitHub Copilot\s+v\d+)/i;
|
|
5321
|
-
var _GH_COPILOT_DISCLAIMER_RE = /^\s*(?:Disclaimer:|This response was|GitHub Copilot|The commands?\s+(?:above|below)|Please review|Always review|Remember to
|
|
6330
|
+
var _GH_COPILOT_DISCLAIMER_RE = /^\s*(?:Disclaimer:|This response was|GitHub Copilot|The commands?\s+(?:above|below)|Please review|Always review|Remember to)/i;
|
|
5322
6331
|
var _AIDER_APPLYING_RE = /^\s*(?:Applying\s+edits?(?:\s+to\s+\S+)?|Applied\s+edit\s+to\s+\S+)\s*(?:\.{1,3}\s*)?$/i;
|
|
5323
6332
|
var _AIDER_TOKENS_RE = /^\s*Tokens:\s+\d[\d,]*\s+sent,\s+\d[\d,]*\s+received/i;
|
|
5324
6333
|
var _AIDER_COST_RE = /^\s*Cost:\s+\$[\d.]+\s+message,\s+\$[\d.]+\s+session/i;
|
|
5325
6334
|
var _AIDER_REPOMAP_RE = /^\s*(?:Repo-map:|Added\s+\S+\s+to\s+the\s+chat|Removed\s+\S+\s+from\s+the\s+chat|Loading\s+repo\s+map|Updating\s+repo\s+map|Scanning\s+repo\s+contents|Using\s+\d+\s+tokens\s+of\s+repo\s+map)/i;
|
|
5326
6335
|
var _AIDER_BANNER_RE = /^\s*aider\s+v\d+\.\d+/i;
|
|
5327
|
-
var _AIDER_FOOTER_NOISE_RE = /^\s*(?:Use\s+ctrl-c|Run\s+with\s+--help|You\s+can\s+skip\s+this
|
|
6336
|
+
var _AIDER_FOOTER_NOISE_RE = /^\s*(?:Use\s+ctrl-c|Run\s+with\s+--help|You\s+can\s+skip\s+this)/i;
|
|
5328
6337
|
var _COPILOT_WORKSPACE_NOISE_RE = /^\s*(?:Starting\s+Copilot\s+workspace|Loading\s+model:|Copilot\s+workspace\s+(?:starting|loaded|ready)|Streaming\.\.\.|▌\s*$|Turn\s+\d+\s*:)/i;
|
|
5329
6338
|
var _COPILOT_COMPLETION_STATS_RE = /^\s*(?:Completion\s+tokens:|Prompt\s+tokens:|Total\s+tokens:|Input\s+tokens:|Output\s+tokens:)\s*\d/i;
|
|
5330
6339
|
var _GEMINI_STARTUP_RE = /^\s*(?:[✓✗►]|>)\s*(?:Model:|Theme:|Tools:|Sandbox:|Checkpointing:|Context(?:\s+limit)?:|Version:|Authenticated(?:\s+as)?:|Connecting)/i;
|
|
5331
6340
|
var _GEMINI_BANNER_RE = /^\s*Gemini\s+CLI\s+v\d+/i;
|
|
5332
6341
|
var _GEMINI_TOKEN_METER_RE = /^\s*(?:Token\s+usage|Context|Tokens):\s+[\d,]+\s*\/\s*[\d,]+/i;
|
|
5333
6342
|
var _GEMINI_TOOL_SPINNER_RE = /^\s*[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✓✗►✦]\s+(?:Call(?:ing|ed)|Execut(?:ing|ed)|Running)\s+\S+/;
|
|
5334
|
-
var _GEMINI_FOOTER_RE = /^\s*(?:Type\s+\/help|Press\s+Ctrl|Use\s+Ctrl
|
|
6343
|
+
var _GEMINI_FOOTER_RE = /^\s*(?:Type\s+\/help|Press\s+Ctrl|Use\s+Ctrl)/i;
|
|
5335
6344
|
var _GEMINI_THINKING_RE = /^\s*(?:Thinking|Generating|Processing)\s*(?:\.{1,3}\s*)?$/i;
|
|
5336
6345
|
var _CLAUDE_CLI_MODEL_HDR_RE = /^\s*[◆◇►✦]\s+claude-/i;
|
|
5337
6346
|
var _CLAUDE_CLI_STATS_RE = /^\s*[↑↓⇑⇓]\s*\d[\d,]*(?:(?:\s*[↑↓⇑⇓]\s*|\s+)\d[\d,]*)?\s*tokens/i;
|
|
5338
6347
|
var _CLAUDE_CLI_CONTEXT_RE = /^\s*(?:Context(?:\s+window)?|Token\s+limit):\s+[\d,]+\s*\/\s*[\d,]+/i;
|
|
5339
|
-
var _CLAUDE_CLI_FOOTER_RE = /^\s*(?:Press\s+Ctrl|Enter\s+\/|Type\s+\/|Use\s+Ctrl
|
|
6348
|
+
var _CLAUDE_CLI_FOOTER_RE = /^\s*(?:Press\s+Ctrl|Enter\s+\/|Type\s+\/|Use\s+Ctrl)/i;
|
|
5340
6349
|
var _CLAUDE_CLI_SPINNER_RE = /^\s*[◎⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]\s+(?:Thinking|Generating|Processing|Running)\s*(?:\.{1,3}\s*)?$/;
|
|
5341
6350
|
var _CLAUDE_CLI_TOOL_LOG_RE = /^\s*(?:>\s+Using\s+tool:|✓\s+Tool\s+result:|◎\s+Tool:)/i;
|
|
5342
6351
|
var _CLAUDE_CLI_SKIP_SUBCMDS = /* @__PURE__ */ new Set(["install", "update", "doctor", "config", "login", "logout"]);
|
|
@@ -8315,7 +9324,8 @@ ${stderr.replace(/\s+$/, "")}` : stderr;
|
|
|
8315
9324
|
var awsFilter = new AwsFilter();
|
|
8316
9325
|
var _AWS_UPLOAD_RE = /^upload:\s+\S+\s+to\s+s3:\/\//i;
|
|
8317
9326
|
var _AWS_DOWNLOAD_RE = /^download:\s+s3:\/\//i;
|
|
8318
|
-
var
|
|
9327
|
+
var _AWS_S3_TRANSFER_FAILED_RE = /^(?:upload|download|copy|delete|move)\s+failed:/i;
|
|
9328
|
+
var _AWS_S3_PROGRESS_RE = /^(?:Completed\s+\d|\d+(?:\.\d+)?\s*(?:KiB|MiB|GiB|B)\/s|Calculating)/i;
|
|
8319
9329
|
var AWS_GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
8320
9330
|
"--profile",
|
|
8321
9331
|
"--region",
|
|
@@ -8337,7 +9347,8 @@ var AwsCliFilter = class extends ToolFilter {
|
|
|
8337
9347
|
_JSON_ARRAY_KEEP = 3;
|
|
8338
9348
|
compressBody(stdout, stderr, _exitCode, argv) {
|
|
8339
9349
|
const positionals = positionalArgs(argv.slice(1), AWS_GLOBAL_VALUE_FLAGS);
|
|
8340
|
-
const isS3Transfer = positionals.length >= 2 && positionals[0] === "s3" &&
|
|
9350
|
+
const isS3Transfer = positionals.length >= 2 && positionals[0] === "s3" && // `rm` belongs here for the failure path, not the volume one: `aws s3 rm --recursive` reports `delete failed:` per object, and routing it anywhere else meant those lines were never counted. Its `delete:` success lines are not folded into a count -- only `upload:`/`download:` are -- so adding it drops nothing that used to survive.
|
|
9351
|
+
(positionals[1] === "cp" || positionals[1] === "sync" || positionals[1] === "mv" || positionals[1] === "rm");
|
|
8341
9352
|
const isCfnEvents = positionals.length >= 2 && positionals[0] === "cloudformation" && positionals[1] === "describe-stack-events";
|
|
8342
9353
|
let text = stdout;
|
|
8343
9354
|
if (isS3Transfer) {
|
|
@@ -8369,6 +9380,7 @@ ${stderr.replace(/\s+$/, "")}` : stderr;
|
|
|
8369
9380
|
const kept = [];
|
|
8370
9381
|
let uploadCount = 0;
|
|
8371
9382
|
let downloadCount = 0;
|
|
9383
|
+
let failedCount = 0;
|
|
8372
9384
|
let progressDropped = 0;
|
|
8373
9385
|
for (const line of lines) {
|
|
8374
9386
|
if (_AWS_UPLOAD_RE.test(line)) {
|
|
@@ -8379,6 +9391,11 @@ ${stderr.replace(/\s+$/, "")}` : stderr;
|
|
|
8379
9391
|
downloadCount++;
|
|
8380
9392
|
continue;
|
|
8381
9393
|
}
|
|
9394
|
+
if (_AWS_S3_TRANSFER_FAILED_RE.test(line)) {
|
|
9395
|
+
failedCount++;
|
|
9396
|
+
kept.push(line);
|
|
9397
|
+
continue;
|
|
9398
|
+
}
|
|
8382
9399
|
if (_AWS_S3_PROGRESS_RE.test(line)) {
|
|
8383
9400
|
progressDropped++;
|
|
8384
9401
|
continue;
|
|
@@ -8388,6 +9405,7 @@ ${stderr.replace(/\s+$/, "")}` : stderr;
|
|
|
8388
9405
|
const notes = [];
|
|
8389
9406
|
maybeNote(notes, uploadCount, `uploaded ${uploadCount} file(s)`);
|
|
8390
9407
|
maybeNote(notes, downloadCount, `downloaded ${downloadCount} file(s)`);
|
|
9408
|
+
maybeNote(notes, failedCount, `${failedCount} transfer(s) failed`);
|
|
8391
9409
|
maybeNote(notes, progressDropped, `dropped ${progressDropped} progress line(s)`);
|
|
8392
9410
|
this.emitNotes(kept, notes);
|
|
8393
9411
|
return this.finalize(kept);
|
|
@@ -9488,8 +10506,9 @@ var RgFilter = class _RgFilter extends ToolFilter {
|
|
|
9488
10506
|
name = "rg";
|
|
9489
10507
|
binaries = /* @__PURE__ */ new Set(["rg", "grep"]);
|
|
9490
10508
|
static _SEP = "--";
|
|
9491
|
-
|
|
9492
|
-
static
|
|
10509
|
+
// The path prefix is optional because ripgrep only prints one when the search covers more than one file: `rg -n -C2 pat one.ts` emits `12-text` and `14:text`, not `one.ts-12-text` and `one.ts:14:text`. Requiring the prefix meant neither regex matched anything on a single-file search -- the ordinary shape of the command -- so no context line was ever suppressed there, and the only thing removed was the cosmetic `--` separator, under a note announcing a compression that had not happened.
|
|
10510
|
+
static _CTX_LINE_RE = /^(?:.+-)?\d+-/;
|
|
10511
|
+
static _MATCH_LINE_RE = /^(?:.+:)?\d+:/;
|
|
9493
10512
|
static _parseContextDepth(argv) {
|
|
9494
10513
|
let depth = 0;
|
|
9495
10514
|
const longFlags = /* @__PURE__ */ new Set(["--after-context", "--before-context", "--context"]);
|
|
@@ -9529,8 +10548,14 @@ var RgFilter = class _RgFilter extends ToolFilter {
|
|
|
9529
10548
|
// RgFilter only handles context-block output (-A/-B/-C/--context); a plain
|
|
9530
10549
|
// grep/rg with no context flags falls through to GrepFilter's per-file
|
|
9531
10550
|
// match-count summarizer, which produces dramatically smaller output.
|
|
10551
|
+
// Both line regexes hard-code ripgrep's default field separators (`:` after a match's line number, `-` after a context line's). `--field-match-separator=-` makes a real match read `12-text`, which is exactly the shape this filter drops, so a search that overrides either separator is released to the generic path rather than compressed against an assumption it broke.
|
|
10552
|
+
static _hasCustomFieldSeparator(argv) {
|
|
10553
|
+
const flags = ["--field-match-separator", "--field-context-separator"];
|
|
10554
|
+
return argv.some((a) => flags.some((f) => a === f || a.startsWith(f + "=")));
|
|
10555
|
+
}
|
|
9532
10556
|
matches(argv) {
|
|
9533
10557
|
if (!super.matches(argv)) return false;
|
|
10558
|
+
if (_RgFilter._hasCustomFieldSeparator(argv)) return false;
|
|
9534
10559
|
return _RgFilter._hasContextFlags(argv);
|
|
9535
10560
|
}
|
|
9536
10561
|
_compressGroups(groups) {
|
|
@@ -9563,7 +10588,8 @@ var RgFilter = class _RgFilter extends ToolFilter {
|
|
|
9563
10588
|
const kept = [];
|
|
9564
10589
|
let suppressed = 0;
|
|
9565
10590
|
for (const ln of lines) {
|
|
9566
|
-
if (ln === _RgFilter._SEP
|
|
10591
|
+
if (ln === _RgFilter._SEP) continue;
|
|
10592
|
+
if (_RgFilter._CTX_LINE_RE.test(ln) && !_RgFilter._MATCH_LINE_RE.test(ln)) {
|
|
9567
10593
|
suppressed++;
|
|
9568
10594
|
} else {
|
|
9569
10595
|
kept.push(ln);
|
|
@@ -13231,6 +14257,8 @@ var _DOCKER_OLD_STEP_ERROR_RE = /error|returned a non-zero code/i;
|
|
|
13231
14257
|
var DockerFilter = class extends ToolFilter {
|
|
13232
14258
|
name = "docker";
|
|
13233
14259
|
binaries = /* @__PURE__ */ new Set(["docker", "buildah", "podman", "nerdctl"]);
|
|
14260
|
+
// Every rule below is about image transfer and build noise -- layer digests, pull/push progress, cached step lines, step bodies -- so the filter is declared for exactly the subcommands that emit them, including buildah's `bud` spelling of build, `create` and `plugin install`/`plugin upgrade`, which pull layers and emit the same per-layer status lines as `pull`. The base matcher scans the first three positionals, so the management-command spellings (`docker image pull`, `docker container create`) are covered by the same entries. With no subcommand set it claimed every `docker …` invocation and removed a single blank line from the ones it has no rules for, which matters because dispatch stops at the first match: `docker logs` on a service repeating a heartbeat went 8702 bytes in, 8701 out, where the generic compressor it was displacing returns 6987. On output with nothing repeated (`docker images` here: 15912 bytes) neither saves anything, so the gain is confined to the repetitive case -- but a filter that claims a command it cannot compress blocks whatever could.
|
|
14261
|
+
subcommands = /* @__PURE__ */ new Set(["build", "bud", "buildx", "pull", "push", "run", "load", "create", "install", "upgrade"]);
|
|
13234
14262
|
// Docker writes progress/errors to stderr; only stdout carries build bodies. Merge with stderr first so errors appear before raw build output.
|
|
13235
14263
|
compress(stdout, stderr, _exitCode, _argv) {
|
|
13236
14264
|
const merged = this.combineOutput(stderr, stdout);
|
|
@@ -13457,6 +14485,7 @@ var _KEY_PREFIXES = [
|
|
|
13457
14485
|
"Namespace:",
|
|
13458
14486
|
"Status:",
|
|
13459
14487
|
"State:",
|
|
14488
|
+
"Last State:",
|
|
13460
14489
|
"Node:",
|
|
13461
14490
|
"IP:",
|
|
13462
14491
|
"PodIP:",
|
|
@@ -13464,6 +14493,7 @@ var _KEY_PREFIXES = [
|
|
|
13464
14493
|
"QoS Class:",
|
|
13465
14494
|
"Priority:",
|
|
13466
14495
|
"Image:",
|
|
14496
|
+
"Container ID:",
|
|
13467
14497
|
"Ready:",
|
|
13468
14498
|
"Restart Count:",
|
|
13469
14499
|
"Started:",
|
|
@@ -14401,12 +15431,18 @@ function _compressGitStatusVerbose(stdout, stderr, argv = null) {
|
|
|
14401
15431
|
const kept = [];
|
|
14402
15432
|
let section = null;
|
|
14403
15433
|
let counts = {};
|
|
15434
|
+
let fileLines = [];
|
|
14404
15435
|
function flush() {
|
|
14405
|
-
if (section !== null && section !== "unmerged" &&
|
|
14406
|
-
|
|
14407
|
-
|
|
15436
|
+
if (section !== null && section !== "unmerged" && fileLines.length) {
|
|
15437
|
+
if (fileLines.length > _DIFF_STAT_DIR_ROLLUP_THRESHOLD) {
|
|
15438
|
+
const parts = Object.entries(counts).map(([label, n]) => `${n} ${label}`);
|
|
15439
|
+
kept.push(" " + parts.join(", "));
|
|
15440
|
+
} else {
|
|
15441
|
+
kept.push(...fileLines);
|
|
15442
|
+
}
|
|
14408
15443
|
}
|
|
14409
15444
|
counts = {};
|
|
15445
|
+
fileLines = [];
|
|
14410
15446
|
}
|
|
14411
15447
|
for (const line of lines) {
|
|
14412
15448
|
const headerMatch = _GIT_STATUS_SECTION_RE.exec(line);
|
|
@@ -14423,6 +15459,7 @@ function _compressGitStatusVerbose(stdout, stderr, argv = null) {
|
|
|
14423
15459
|
} else {
|
|
14424
15460
|
const label = _gitStatusFileLabel(line, section);
|
|
14425
15461
|
counts[label] = (counts[label] ?? 0) + 1;
|
|
15462
|
+
fileLines.push(line);
|
|
14426
15463
|
}
|
|
14427
15464
|
continue;
|
|
14428
15465
|
}
|
|
@@ -17726,10 +18763,13 @@ function filterByName(name) {
|
|
|
17726
18763
|
init_define_import_meta_env();
|
|
17727
18764
|
|
|
17728
18765
|
export {
|
|
18766
|
+
pathEqClause,
|
|
18767
|
+
projectScopeClause,
|
|
17729
18768
|
getToolName,
|
|
17730
18769
|
getToolInput,
|
|
17731
18770
|
getFilePath,
|
|
17732
18771
|
getCwd,
|
|
18772
|
+
getTranscriptPath,
|
|
17733
18773
|
extractToolResponseField,
|
|
17734
18774
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
17735
18775
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
@@ -17793,6 +18833,38 @@ export {
|
|
|
17793
18833
|
capTokens,
|
|
17794
18834
|
shlexSplit,
|
|
17795
18835
|
clipLongMatchLine,
|
|
18836
|
+
isLockFile,
|
|
18837
|
+
isManifestFile,
|
|
18838
|
+
isInBuildDir,
|
|
18839
|
+
isGeneratedFile,
|
|
18840
|
+
isBuildCommand,
|
|
18841
|
+
isTestRunnerCommand,
|
|
18842
|
+
getMonitoringRecallHint,
|
|
18843
|
+
DEFAULT_QUERY_LIMIT,
|
|
18844
|
+
querySymbols,
|
|
18845
|
+
distinctSymbolKinds,
|
|
18846
|
+
countSymbols,
|
|
18847
|
+
queryRefs,
|
|
18848
|
+
countRefs,
|
|
18849
|
+
queryRefsByContext,
|
|
18850
|
+
queryRefCounts,
|
|
18851
|
+
getProjectFileEntries,
|
|
18852
|
+
getFileEntry,
|
|
18853
|
+
searchSymbolsFts,
|
|
18854
|
+
RECALL_DEFAULT_LIMIT,
|
|
18855
|
+
isRecallCacheType,
|
|
18856
|
+
indexRecallEntry,
|
|
18857
|
+
listRecentRecall,
|
|
18858
|
+
searchRecall,
|
|
18859
|
+
BASH_OUTPUT_SUBDIR,
|
|
18860
|
+
isScopedGitStatusOrDiffStatCommand,
|
|
18861
|
+
normalizeCommandForCacheKey,
|
|
18862
|
+
commandHash,
|
|
18863
|
+
isBashEntryStale,
|
|
18864
|
+
summarizeOutputDelta,
|
|
18865
|
+
storeBashOutputSync,
|
|
18866
|
+
storeBashOutput,
|
|
18867
|
+
getBashOutput,
|
|
17796
18868
|
anchoredMarkerPattern,
|
|
17797
18869
|
settingsPath,
|
|
17798
18870
|
installHooks,
|