token-goat 2.9.18 → 2.9.19
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 +2 -0
- package/dist/{token-goat-chunk-V3ZWBEHM.mjs → token-goat-chunk-2GTB5RBZ.mjs} +365 -26
- package/dist/{token-goat-chunk-ARNRFR6M.mjs → token-goat-chunk-3W5P673V.mjs} +1 -1
- package/dist/{token-goat-chunk-YQZE5NS6.mjs → token-goat-chunk-62VJ47WN.mjs} +6 -6
- package/dist/{token-goat-chunk-CTOYJ232.mjs → token-goat-chunk-7DGTVBWP.mjs} +45 -8
- package/dist/{token-goat-chunk-5MMJAJF3.mjs → token-goat-chunk-AVRD7SBO.mjs} +60 -8
- package/dist/{token-goat-chunk-7VLWNQDQ.mjs → token-goat-chunk-BTKDZW7F.mjs} +1 -1
- package/dist/{token-goat-chunk-LMFO66YD.mjs → token-goat-chunk-DA43OE7L.mjs} +1 -1
- package/dist/{token-goat-chunk-6LGVCCMY.mjs → token-goat-chunk-DA6TIDLI.mjs} +21 -16
- package/dist/{token-goat-chunk-UENEL6KX.mjs → token-goat-chunk-DHIXE6GV.mjs} +2 -2
- package/dist/{token-goat-chunk-W3E65QOW.mjs → token-goat-chunk-EP7TCWHM.mjs} +304 -46
- package/dist/{token-goat-chunk-HIZXQVNU.mjs → token-goat-chunk-EXLLLIC3.mjs} +4 -4
- package/dist/{token-goat-chunk-H3FONFBO.mjs → token-goat-chunk-F24NE3FO.mjs} +3 -3
- package/dist/{token-goat-chunk-LA3O4JGD.mjs → token-goat-chunk-FJZ5MZK7.mjs} +3 -3
- package/dist/{token-goat-chunk-BFEWOMA3.mjs → token-goat-chunk-FQYMZASI.mjs} +632 -352
- package/dist/{token-goat-chunk-OWSJJY5R.mjs → token-goat-chunk-FX5DHKGF.mjs} +5 -5
- package/dist/{token-goat-chunk-K4DG6EEF.mjs → token-goat-chunk-GYC34EGE.mjs} +7 -8
- package/dist/{token-goat-chunk-WFX2V3OF.mjs → token-goat-chunk-HPMMLV37.mjs} +358 -116
- package/dist/{token-goat-chunk-I67CPTDD.mjs → token-goat-chunk-IBTFGZBX.mjs} +19 -14
- package/dist/{token-goat-chunk-L7VCX33I.mjs → token-goat-chunk-JNIFSVWM.mjs} +36 -10
- package/dist/{token-goat-chunk-EPXNOKIV.mjs → token-goat-chunk-KWM6KBPA.mjs} +2 -2
- package/dist/{token-goat-chunk-BWCRC23L.mjs → token-goat-chunk-L2UOJBV4.mjs} +21 -20
- package/dist/{token-goat-chunk-52IMXJ2L.mjs → token-goat-chunk-LACH3WKS.mjs} +4 -4
- package/dist/token-goat-chunk-MU6I4IDI.mjs +337 -0
- package/dist/{token-goat-chunk-GRI6HWX3.mjs → token-goat-chunk-NJKNAC37.mjs} +1 -1
- package/dist/{token-goat-chunk-ERTXEKB6.mjs → token-goat-chunk-NMTKNYGF.mjs} +2 -0
- package/dist/{token-goat-chunk-34OUJ2IE.mjs → token-goat-chunk-NYFYIRG3.mjs} +12 -12
- package/dist/{token-goat-chunk-4EXFN2AW.mjs → token-goat-chunk-OZRSREKR.mjs} +2 -2
- package/dist/token-goat-chunk-P46RTOAQ.mjs +27 -0
- package/dist/{token-goat-chunk-QML7ITHJ.mjs → token-goat-chunk-PIAESKVU.mjs} +139 -23
- package/dist/{token-goat-chunk-HPOFR6QX.mjs → token-goat-chunk-S7RFIX4Y.mjs} +180 -50
- package/dist/{token-goat-chunk-CA6V36KW.mjs → token-goat-chunk-SOKAPOOC.mjs} +23 -4
- package/dist/token-goat-chunk-VJQBYSXG.mjs +20 -0
- package/dist/{token-goat-chunk-LTYWLKAG.mjs → token-goat-chunk-WKO5TVNA.mjs} +922 -611
- package/dist/{token-goat-chunk-QIDLJGXZ.mjs → token-goat-chunk-ZGQXRYKE.mjs} +29 -5
- package/dist/token-goat-hook.mjs +12 -12
- package/dist/token-goat.core.mjs +21 -20
- package/docs/cli.md +2 -1
- package/docs/security.md +1 -1
- package/package.json +1 -1
- package/dist/token-goat-chunk-2KTZ6J7T.mjs +0 -173
- package/dist/token-goat-chunk-RHHFEXKF.mjs +0 -93
|
@@ -2,15 +2,15 @@ import { createRequire as __cjsRequire } from 'node:module';
|
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
getDb
|
|
5
|
-
} from "./token-goat-chunk-
|
|
5
|
+
} from "./token-goat-chunk-JNIFSVWM.mjs";
|
|
6
6
|
import {
|
|
7
7
|
foldPath,
|
|
8
8
|
globalDbPath,
|
|
9
9
|
isCaseInsensitiveFs
|
|
10
|
-
} from "./token-goat-chunk-
|
|
10
|
+
} from "./token-goat-chunk-ZGQXRYKE.mjs";
|
|
11
11
|
import {
|
|
12
12
|
normalizePath
|
|
13
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
14
14
|
import {
|
|
15
15
|
init_define_import_meta_env
|
|
16
16
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -50,6 +50,9 @@ function projectScopeClause(column) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// src/index_reader.ts
|
|
53
|
+
function indexKey(p) {
|
|
54
|
+
return normalizePath(p);
|
|
55
|
+
}
|
|
53
56
|
function toSymbolEntry(row) {
|
|
54
57
|
return {
|
|
55
58
|
filePath: row.file_path,
|
|
@@ -75,7 +78,7 @@ function applyRootDirScope(rootDir, column, where, params) {
|
|
|
75
78
|
if (rootDir === void 0) return;
|
|
76
79
|
const { clause, params: bounds } = projectScopeClause(column);
|
|
77
80
|
where.push(clause);
|
|
78
|
-
params.push(...bounds(rootDir));
|
|
81
|
+
params.push(...bounds(indexKey(rootDir)));
|
|
79
82
|
}
|
|
80
83
|
function buildSymbolWhere(opts) {
|
|
81
84
|
const where = [];
|
|
@@ -85,13 +88,14 @@ function buildSymbolWhere(opts) {
|
|
|
85
88
|
params.push(opts.name);
|
|
86
89
|
}
|
|
87
90
|
if (opts.filePath !== void 0) {
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
const key = indexKey(opts.filePath);
|
|
92
|
+
if (key.includes("/") || key.includes("\\")) {
|
|
93
|
+
const alt = key.includes("/") ? key.replace(/\//g, "\\") : key.replace(/\\/g, "/");
|
|
90
94
|
where.push(`(${pathEqClause("file_path")} OR ${pathEqClause("file_path")})`);
|
|
91
|
-
params.push(foldPath(
|
|
95
|
+
params.push(foldPath(key), foldPath(alt));
|
|
92
96
|
} else {
|
|
93
97
|
where.push(pathEqClause("file_path"));
|
|
94
|
-
params.push(foldPath(
|
|
98
|
+
params.push(foldPath(key));
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
if (opts.kind !== void 0) {
|
|
@@ -141,7 +145,7 @@ function buildRefsWhere(opts) {
|
|
|
141
145
|
const params = [opts.name];
|
|
142
146
|
if (opts.filePath !== void 0) {
|
|
143
147
|
where.push(pathEqClause("file_path"));
|
|
144
|
-
params.push(foldPath(opts.filePath));
|
|
148
|
+
params.push(foldPath(indexKey(opts.filePath)));
|
|
145
149
|
}
|
|
146
150
|
applyRootDirScope(opts.rootDir, "file_path", where, params);
|
|
147
151
|
return { clause: `WHERE ${where.join(" AND ")}`, params };
|
|
@@ -164,7 +168,7 @@ function countRefs(opts, dbPath = globalDbPath()) {
|
|
|
164
168
|
function queryRefsByContext(context, filePath, dbPath = globalDbPath()) {
|
|
165
169
|
const sql = `SELECT file_path, name, line, col, context FROM refs WHERE context = ? AND ${pathEqClause("file_path")} ORDER BY line LIMIT 20`;
|
|
166
170
|
const db = getDb(dbPath);
|
|
167
|
-
const rows = db.prepare(sql).all(context, foldPath(filePath));
|
|
171
|
+
const rows = db.prepare(sql).all(context, foldPath(indexKey(filePath)));
|
|
168
172
|
return rows.map(toRefEntry);
|
|
169
173
|
}
|
|
170
174
|
var REF_COUNT_BATCH = 900;
|
|
@@ -192,7 +196,7 @@ function queryRefCounts(names, dbPath = globalDbPath(), rootDir) {
|
|
|
192
196
|
function getProjectFileEntries(rootDir, dbPath = globalDbPath()) {
|
|
193
197
|
const db = getDb(dbPath);
|
|
194
198
|
const { clause, params } = projectScopeClause("path");
|
|
195
|
-
const rows = db.prepare(`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${clause}`).all(...params(rootDir));
|
|
199
|
+
const rows = db.prepare(`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${clause}`).all(...params(indexKey(rootDir)));
|
|
196
200
|
const out = /* @__PURE__ */ new Map();
|
|
197
201
|
for (const row of rows) {
|
|
198
202
|
out.set(foldPath(row.path), {
|
|
@@ -209,11 +213,12 @@ function getProjectFileEntries(rootDir, dbPath = globalDbPath()) {
|
|
|
209
213
|
}
|
|
210
214
|
function getFileEntry(filePath, dbPath = globalDbPath()) {
|
|
211
215
|
const db = getDb(dbPath);
|
|
216
|
+
const key = indexKey(filePath);
|
|
212
217
|
let row = db.prepare(
|
|
213
218
|
`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${pathEqClause("path")}`
|
|
214
|
-
).get(foldPath(
|
|
215
|
-
if (row === void 0 && (
|
|
216
|
-
const altPath =
|
|
219
|
+
).get(foldPath(key));
|
|
220
|
+
if (row === void 0 && (key.includes("/") || key.includes("\\"))) {
|
|
221
|
+
const altPath = key.includes("/") ? key.replace(/\//g, "\\") : key.replace(/\\/g, "/");
|
|
217
222
|
row = db.prepare(
|
|
218
223
|
`SELECT path, sha, mtime, language, indexed_at, embed_sha, parser_sha FROM files WHERE ${pathEqClause("path")}`
|
|
219
224
|
).get(foldPath(altPath));
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
foldCase,
|
|
16
16
|
foldPath,
|
|
17
17
|
sleepSync
|
|
18
|
-
} from "./token-goat-chunk-
|
|
18
|
+
} from "./token-goat-chunk-ZGQXRYKE.mjs";
|
|
19
19
|
import {
|
|
20
20
|
safeJoin
|
|
21
|
-
} from "./token-goat-chunk-
|
|
21
|
+
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
22
22
|
import {
|
|
23
23
|
init_define_import_meta_env
|
|
24
24
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -2044,12 +2044,29 @@ CREATE INDEX IF NOT EXISTS idx_cache_recall_type ON cache_recall(cache_type);
|
|
|
2044
2044
|
-- emission event (a hook returning a 'context' HookOutput classified as a discretionary
|
|
2045
2045
|
-- efficiency nudge, as opposed to a mandatory informational injection -- see hint_stats.ts's
|
|
2046
2046
|
-- doc comment for the exact category list and what is deliberately excluded). correlator is a
|
|
2047
|
-
--
|
|
2047
|
+
-- file-path/output-id pointer the hint carries, used to check
|
|
2048
2048
|
-- whether a later Bash tool call in the same session actually followed the hint's specific
|
|
2049
|
-
-- pointer (see resolvePendingHintsForEvent)
|
|
2050
|
-
--
|
|
2051
|
-
--
|
|
2052
|
-
--
|
|
2049
|
+
-- pointer (see resolvePendingHintsForEvent). Supplied by the hint builder itself via
|
|
2050
|
+
-- HookOutput's correlators field wherever one exists, and only fallen back to a regex scrape
|
|
2051
|
+
-- of the rendered hint text (hint_stats.ts's extractPathCorrelator, whose doc comment records
|
|
2052
|
+
-- what that scrape actually measured) where it does not. A row can name SEVERAL files -- the
|
|
2053
|
+
-- sed/awk line-range hint joins one per file into one emission -- stored newline-separated and
|
|
2054
|
+
-- matched on any member; see joinCorrelators. NULL when no pointer could be supplied or extracted,
|
|
2055
|
+
-- in which case the row is inserted already resolved and observable=0: there is nothing a later
|
|
2056
|
+
-- command could do that this row would recognize, so no verdict about it was ever observed.
|
|
2057
|
+
-- observable=1 is the normal case. Efficacy counts only observable rows, numerator and denominator
|
|
2058
|
+
-- both, because an unobservable row's acted_on is a fabrication in whichever direction the code
|
|
2059
|
+
-- picked and averaging fabrications into a measured rate is how 174 of bash_redirect's 698 rows
|
|
2060
|
+
-- came to hold its efficacy down to 0.86% when the observed figure was 1.15%. calls_remaining is
|
|
2061
|
+
-- the countdown of subsequent tool-use events still eligible to resolve this row before it is
|
|
2062
|
+
-- considered timed out. displayed=0 marks a detection that never reached the agent -- auto-
|
|
2063
|
+
-- suppressed, or declined by a hint's own net-benefit gate -- recorded so the ledger can answer
|
|
2064
|
+
-- how often a hint fired at all, which it previously could not: a suppressed detection left no
|
|
2065
|
+
-- trace, so a fully-muted category was indistinguishable from one that had stopped triggering.
|
|
2066
|
+
-- Such a row is always observable=0 and bytes_emitted=0: nothing was shown, so nothing was spent
|
|
2067
|
+
-- and no verdict was available. It shares hint_emissions' 180-day retention (pruneHintEmissions
|
|
2068
|
+
-- in stats.ts deletes on emitted_at alone), deliberately unlike hint_suppression_probes, which is
|
|
2069
|
+
-- one upserted row per key rather than a growing log and is therefore never pruned.
|
|
2053
2070
|
CREATE TABLE IF NOT EXISTS hint_emissions (
|
|
2054
2071
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
2055
2072
|
category TEXT NOT NULL,
|
|
@@ -2060,7 +2077,9 @@ CREATE TABLE IF NOT EXISTS hint_emissions (
|
|
|
2060
2077
|
resolved INTEGER NOT NULL DEFAULT 0,
|
|
2061
2078
|
acted_on INTEGER NOT NULL DEFAULT 0,
|
|
2062
2079
|
calls_remaining INTEGER NOT NULL DEFAULT 0,
|
|
2063
|
-
bytes_emitted INTEGER
|
|
2080
|
+
bytes_emitted INTEGER,
|
|
2081
|
+
observable INTEGER NOT NULL DEFAULT 1,
|
|
2082
|
+
displayed INTEGER NOT NULL DEFAULT 1
|
|
2064
2083
|
);
|
|
2065
2084
|
CREATE INDEX IF NOT EXISTS idx_hint_emissions_category ON hint_emissions(category);
|
|
2066
2085
|
CREATE INDEX IF NOT EXISTS idx_hint_emissions_session_pending ON hint_emissions(session_id, resolved);
|
|
@@ -2206,7 +2225,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
2206
2225
|
VALUES (new.row_id, new.label, new.content);
|
|
2207
2226
|
END;
|
|
2208
2227
|
`;
|
|
2209
|
-
var SCHEMA_VERSION =
|
|
2228
|
+
var SCHEMA_VERSION = 16;
|
|
2210
2229
|
function alterTableIdempotent(conn, sql) {
|
|
2211
2230
|
try {
|
|
2212
2231
|
conn.exec(sql);
|
|
@@ -2262,7 +2281,14 @@ var MIGRATIONS = {
|
|
|
2262
2281
|
// v12 -> v13: adds files.parser_sha, the digest of the extraction logic that produced this file's rows, tracked separately from files.sha for the same reason embed_sha is -- content freshness and parse freshness are different questions, and the content sha alone could only ever answer the first. A pre-existing v12 database's `files` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has it from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v1 -> v2 / v2 -> v3 / v8 -> v9 / v9 -> v10 above. Deliberately left NULL for every existing row rather than backfilled with the current fingerprint: NULL is the truthful answer (nobody recorded which parser wrote those rows), and it is also the answer that makes the freshness gates reparse them once, which is exactly what a database indexed by an older parser needs. v13 -> v14: changes both FTS5 tables' tokenizer to `unicode61 remove_diacritics 2`, so a search for `Noi` or `Viet` finds `Hà Nội` and `Việt Nam` -- combining marks that `remove_diacritics 1`, FTS5's default, leaves in place. This is the first schema change that `CREATE VIRTUAL TABLE IF NOT EXISTS` cannot express at all rather than merely cannot express on a populated table: against an existing virtual table that statement is a silent no-op, so without MIGRATIONS[13] the new tokenizer would reach only databases created after this release. The step drops both tables, re-runs FTS_SQL to re-create them at the current declaration, and rebuilds each from its content table.
|
|
2263
2282
|
12: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN parser_sha TEXT"),
|
|
2264
2283
|
// v13 -> v14: re-creates both FTS5 tables at the tokenizer FTS_SQL currently declares (see the SCHEMA_VERSION comment above for why no `IF NOT EXISTS` form can do this).
|
|
2265
|
-
13: rebuildFtsAtCurrentTokenizer
|
|
2284
|
+
13: rebuildFtsAtCurrentTokenizer,
|
|
2285
|
+
// v14 -> v15: adds hint_emissions.observable and backfills it from the column that always implied it. A pre-existing v14 database's `hint_emissions` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has it from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v8 -> v9 / v9 -> v10 / v12 -> v13 above. The backfill is exact rather than a guess: until this version a NULL correlator was the only way a row could be born with nothing to wait for, so `correlator IS NULL` identifies precisely the population the new column names. It runs unconditionally after the ALTER because alterTableIdempotent swallows the duplicate-column case, and re-running the UPDATE on an already-migrated database sets the same rows to the same values.
|
|
2286
|
+
14: (conn) => {
|
|
2287
|
+
alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN observable INTEGER NOT NULL DEFAULT 1");
|
|
2288
|
+
conn.prepare("UPDATE hint_emissions SET observable = 0 WHERE correlator IS NULL").run();
|
|
2289
|
+
},
|
|
2290
|
+
// v15 -> v16: adds hint_emissions.displayed (see the SCHEMA_VERSION comment above for why). A pre-existing v15 database's `hint_emissions` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has it from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v8 -> v9 / v9 -> v10 / v12 -> v13 / v14 -> v15 above. No backfill, unlike v14 -> v15: until this version a row was only ever written when a hint was actually shown, so the column's own DEFAULT 1 is already the truth for every existing row, and an UPDATE would be a no-op dressed up as a migration step.
|
|
2291
|
+
15: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN displayed INTEGER NOT NULL DEFAULT 1")
|
|
2266
2292
|
};
|
|
2267
2293
|
function runMigrations(conn, fromVersion, toVersion) {
|
|
2268
2294
|
for (let v = fromVersion; v < toVersion; v++) {
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./token-goat-chunk-3BTK54F3.mjs";
|
|
6
6
|
import {
|
|
7
7
|
filtersFilteredToEmptyNotice
|
|
8
|
-
} from "./token-goat-chunk-
|
|
8
|
+
} from "./token-goat-chunk-ZGQXRYKE.mjs";
|
|
9
9
|
import {
|
|
10
10
|
displaySafeText
|
|
11
|
-
} from "./token-goat-chunk-
|
|
11
|
+
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
12
12
|
import {
|
|
13
13
|
compileGuardedRegexCached
|
|
14
14
|
} from "./token-goat-chunk-GMOUBOX4.mjs";
|
|
@@ -70,35 +70,36 @@ import {
|
|
|
70
70
|
requirePositiveInt,
|
|
71
71
|
run,
|
|
72
72
|
visualStudioManualSteps
|
|
73
|
-
} from "./token-goat-chunk-
|
|
74
|
-
import "./token-goat-chunk-
|
|
75
|
-
import "./token-goat-chunk-
|
|
76
|
-
import "./token-goat-chunk-
|
|
73
|
+
} from "./token-goat-chunk-WKO5TVNA.mjs";
|
|
74
|
+
import "./token-goat-chunk-GYC34EGE.mjs";
|
|
75
|
+
import "./token-goat-chunk-PIAESKVU.mjs";
|
|
76
|
+
import "./token-goat-chunk-F24NE3FO.mjs";
|
|
77
|
+
import "./token-goat-chunk-DA43OE7L.mjs";
|
|
77
78
|
import {
|
|
78
79
|
cmdDescribe,
|
|
79
80
|
cmdSessionSchema
|
|
80
|
-
} from "./token-goat-chunk-
|
|
81
|
-
import "./token-goat-chunk-
|
|
82
|
-
import "./token-goat-chunk-
|
|
83
|
-
import "./token-goat-chunk-
|
|
81
|
+
} from "./token-goat-chunk-2GTB5RBZ.mjs";
|
|
82
|
+
import "./token-goat-chunk-FQYMZASI.mjs";
|
|
83
|
+
import "./token-goat-chunk-7DGTVBWP.mjs";
|
|
84
|
+
import "./token-goat-chunk-S7RFIX4Y.mjs";
|
|
84
85
|
import "./token-goat-chunk-LKSXAMJB.mjs";
|
|
85
|
-
import "./token-goat-chunk-
|
|
86
|
-
import "./token-goat-chunk-
|
|
87
|
-
import "./token-goat-chunk-
|
|
88
|
-
import "./token-goat-chunk-
|
|
86
|
+
import "./token-goat-chunk-DHIXE6GV.mjs";
|
|
87
|
+
import "./token-goat-chunk-3W5P673V.mjs";
|
|
88
|
+
import "./token-goat-chunk-FJZ5MZK7.mjs";
|
|
89
|
+
import "./token-goat-chunk-KWM6KBPA.mjs";
|
|
89
90
|
import "./token-goat-chunk-3BTK54F3.mjs";
|
|
90
|
-
import "./token-goat-chunk-
|
|
91
|
+
import "./token-goat-chunk-BTKDZW7F.mjs";
|
|
91
92
|
import "./token-goat-chunk-XTQAOTSO.mjs";
|
|
92
93
|
import "./token-goat-chunk-AH6QILZM.mjs";
|
|
93
|
-
import "./token-goat-chunk-
|
|
94
|
-
import "./token-goat-chunk-
|
|
95
|
-
import "./token-goat-chunk-
|
|
96
|
-
import "./token-goat-chunk-
|
|
97
|
-
import "./token-goat-chunk-
|
|
94
|
+
import "./token-goat-chunk-NJKNAC37.mjs";
|
|
95
|
+
import "./token-goat-chunk-EP7TCWHM.mjs";
|
|
96
|
+
import "./token-goat-chunk-IBTFGZBX.mjs";
|
|
97
|
+
import "./token-goat-chunk-JNIFSVWM.mjs";
|
|
98
|
+
import "./token-goat-chunk-SOKAPOOC.mjs";
|
|
98
99
|
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
99
100
|
import "./token-goat-chunk-OSUFN2FV.mjs";
|
|
100
|
-
import "./token-goat-chunk-
|
|
101
|
-
import "./token-goat-chunk-
|
|
101
|
+
import "./token-goat-chunk-ZGQXRYKE.mjs";
|
|
102
|
+
import "./token-goat-chunk-NMTKNYGF.mjs";
|
|
102
103
|
import "./token-goat-chunk-Y4AFKTHK.mjs";
|
|
103
104
|
import "./token-goat-chunk-GMOUBOX4.mjs";
|
|
104
105
|
import "./token-goat-chunk-RRNZMM3A.mjs";
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
pptxOutline,
|
|
7
7
|
pptxSlideText,
|
|
8
8
|
pptxTextGrep
|
|
9
|
-
} from "./token-goat-chunk-
|
|
10
|
-
import "./token-goat-chunk-
|
|
9
|
+
} from "./token-goat-chunk-3W5P673V.mjs";
|
|
10
|
+
import "./token-goat-chunk-BTKDZW7F.mjs";
|
|
11
11
|
import "./token-goat-chunk-XTQAOTSO.mjs";
|
|
12
12
|
import "./token-goat-chunk-AH6QILZM.mjs";
|
|
13
|
-
import "./token-goat-chunk-
|
|
14
|
-
import "./token-goat-chunk-
|
|
13
|
+
import "./token-goat-chunk-ZGQXRYKE.mjs";
|
|
14
|
+
import "./token-goat-chunk-NMTKNYGF.mjs";
|
|
15
15
|
import "./token-goat-chunk-Y4AFKTHK.mjs";
|
|
16
16
|
import "./token-goat-chunk-GMOUBOX4.mjs";
|
|
17
17
|
import "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
ToolFilter,
|
|
5
|
+
capTokens,
|
|
6
|
+
compressedTokensSaved,
|
|
7
|
+
deliverCompressed,
|
|
8
|
+
dispatchArgv,
|
|
9
|
+
filterByName,
|
|
10
|
+
selectFilter,
|
|
11
|
+
shlexSplit,
|
|
12
|
+
storeBashOutputSync
|
|
13
|
+
} from "./token-goat-chunk-7DGTVBWP.mjs";
|
|
14
|
+
import {
|
|
15
|
+
recordStat
|
|
16
|
+
} from "./token-goat-chunk-S7RFIX4Y.mjs";
|
|
17
|
+
import {
|
|
18
|
+
detectHarness,
|
|
19
|
+
loadConfig
|
|
20
|
+
} from "./token-goat-chunk-SOKAPOOC.mjs";
|
|
21
|
+
import {
|
|
22
|
+
init_define_import_meta_env
|
|
23
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
24
|
+
|
|
25
|
+
// src/bash_runner.ts
|
|
26
|
+
init_define_import_meta_env();
|
|
27
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
28
|
+
import * as os from "node:os";
|
|
29
|
+
|
|
30
|
+
// src/delivery_cap.ts
|
|
31
|
+
init_define_import_meta_env();
|
|
32
|
+
var CLAUDE_CODE_BASH_OUTPUT_CAP_BYTES = 2e4;
|
|
33
|
+
var CLAUDE_CODE_PERSISTED_PREVIEW_BYTES = 2048;
|
|
34
|
+
function bashOutputCapBytes(harness = detectHarness()) {
|
|
35
|
+
return harness === "claudecode" ? CLAUDE_CODE_BASH_OUTPUT_CAP_BYTES : null;
|
|
36
|
+
}
|
|
37
|
+
function clipToDeliveryCap(text, reserveBytes) {
|
|
38
|
+
const cap = bashOutputCapBytes();
|
|
39
|
+
const room = cap === null ? null : cap - reserveBytes;
|
|
40
|
+
if (room === null || room <= 0 || Buffer.byteLength(text, "utf-8") <= room) return { text, clipped: false };
|
|
41
|
+
const sliced = Buffer.from(text, "utf-8").subarray(0, room).toString("utf-8");
|
|
42
|
+
const lastNewline = sliced.lastIndexOf("\n");
|
|
43
|
+
return { text: lastNewline > 0 ? sliced.slice(0, lastNewline) : sliced, clipped: true };
|
|
44
|
+
}
|
|
45
|
+
function deliveredOutputBytes(originalBytes, harness) {
|
|
46
|
+
const cap = bashOutputCapBytes(harness);
|
|
47
|
+
if (cap === null) return Math.max(0, originalBytes);
|
|
48
|
+
if (originalBytes <= cap) return Math.max(0, originalBytes);
|
|
49
|
+
return CLAUDE_CODE_PERSISTED_PREVIEW_BYTES;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/shell.ts
|
|
53
|
+
init_define_import_meta_env();
|
|
54
|
+
import * as fs from "node:fs";
|
|
55
|
+
import * as path from "node:path";
|
|
56
|
+
var WSL_LAUNCHER_SEGMENTS = /* @__PURE__ */ new Set(["system32", "syswow64", "windowsapps"]);
|
|
57
|
+
function isExecutable(p) {
|
|
58
|
+
try {
|
|
59
|
+
return fs.statSync(p).isFile();
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function isWslLauncherDir(dir) {
|
|
65
|
+
return dir.toLowerCase().split(/[\\/]+/).some((seg) => WSL_LAUNCHER_SEGMENTS.has(seg));
|
|
66
|
+
}
|
|
67
|
+
function locateBashOnPath(pathValue, isExe = isExecutable) {
|
|
68
|
+
for (const dir of (pathValue ?? "").split(path.delimiter)) {
|
|
69
|
+
if (!dir || isWslLauncherDir(dir)) continue;
|
|
70
|
+
const cand = path.join(dir, "bash.exe");
|
|
71
|
+
if (isExe(cand)) return cand;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function knownGitBashPaths() {
|
|
76
|
+
const localPrograms = process.env["LOCALAPPDATA"] ? path.join(process.env["LOCALAPPDATA"], "Programs") : void 0;
|
|
77
|
+
const bases = [
|
|
78
|
+
process.env["ProgramFiles"],
|
|
79
|
+
process.env["ProgramFiles(x86)"],
|
|
80
|
+
process.env["ProgramW6432"],
|
|
81
|
+
localPrograms
|
|
82
|
+
];
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const base of bases) {
|
|
85
|
+
if (!base) continue;
|
|
86
|
+
out.push(path.join(base, "Git", "bin", "bash.exe"));
|
|
87
|
+
out.push(path.join(base, "Git", "usr", "bin", "bash.exe"));
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
function resolveWindowsBash() {
|
|
92
|
+
if (process.platform !== "win32") return null;
|
|
93
|
+
const override = process.env["TOKEN_GOAT_BASH"];
|
|
94
|
+
if (override && isExecutable(override)) return override;
|
|
95
|
+
const onPath = locateBashOnPath(process.env["PATH"]);
|
|
96
|
+
if (onPath) return onPath;
|
|
97
|
+
for (const cand of knownGitBashPaths()) {
|
|
98
|
+
if (isExecutable(cand)) return cand;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
function wrappedShell() {
|
|
103
|
+
if (process.platform !== "win32") return true;
|
|
104
|
+
return resolveWindowsBash() ?? true;
|
|
105
|
+
}
|
|
106
|
+
function canRunWrappedShell() {
|
|
107
|
+
return process.platform !== "win32" || resolveWindowsBash() !== null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/bash_runner.ts
|
|
111
|
+
var IdentityFilter = class extends ToolFilter {
|
|
112
|
+
name = "passthrough";
|
|
113
|
+
};
|
|
114
|
+
var DEFAULT_TIMEOUT_SECONDS = 600;
|
|
115
|
+
var MAX_CAPTURE_BYTES = 32 * 1024 * 1024;
|
|
116
|
+
var MIN_RECORD_STAT_BYTES = 32;
|
|
117
|
+
var DEFAULT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
118
|
+
var CaptureSink = class {
|
|
119
|
+
constructor(cap) {
|
|
120
|
+
this.cap = cap;
|
|
121
|
+
}
|
|
122
|
+
cap;
|
|
123
|
+
chunks = [];
|
|
124
|
+
bytes = 0;
|
|
125
|
+
overflowed = false;
|
|
126
|
+
push(chunk) {
|
|
127
|
+
if (this.overflowed) return;
|
|
128
|
+
this.bytes += chunk.length;
|
|
129
|
+
if (this.bytes > this.cap) {
|
|
130
|
+
this.overflowed = true;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this.chunks.push(chunk);
|
|
134
|
+
}
|
|
135
|
+
text() {
|
|
136
|
+
return decode(Buffer.concat(this.chunks));
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
function scheduleHeartbeat(startTime, intervalMs, write) {
|
|
140
|
+
let interval = intervalMs;
|
|
141
|
+
let timer;
|
|
142
|
+
const arm = () => {
|
|
143
|
+
timer = setTimeout(() => {
|
|
144
|
+
write(Math.round((Date.now() - startTime) / 1e3));
|
|
145
|
+
interval *= 2;
|
|
146
|
+
arm();
|
|
147
|
+
}, interval);
|
|
148
|
+
timer.unref();
|
|
149
|
+
};
|
|
150
|
+
arm();
|
|
151
|
+
return {
|
|
152
|
+
onOutput: () => {
|
|
153
|
+
interval = intervalMs;
|
|
154
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
155
|
+
arm();
|
|
156
|
+
},
|
|
157
|
+
stop: () => {
|
|
158
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function resolveFilter(command, filterName, cwd) {
|
|
163
|
+
let split;
|
|
164
|
+
try {
|
|
165
|
+
split = shlexSplit(command);
|
|
166
|
+
} catch {
|
|
167
|
+
split = null;
|
|
168
|
+
}
|
|
169
|
+
const argv = split === null ? [command] : dispatchArgv(split, cwd).argv;
|
|
170
|
+
if (filterName) {
|
|
171
|
+
const named = filterByName(filterName);
|
|
172
|
+
if (named !== null) return { filter: named, argv };
|
|
173
|
+
}
|
|
174
|
+
if (split === null) return { filter: null, argv };
|
|
175
|
+
return { filter: selectFilter(split, cwd), argv };
|
|
176
|
+
}
|
|
177
|
+
function baseSpawnOptions(timeout, cwd) {
|
|
178
|
+
return { timeout: timeout * 1e3, cwd };
|
|
179
|
+
}
|
|
180
|
+
function spawnTarget(command, nativeShell) {
|
|
181
|
+
const shell = nativeShell ? true : wrappedShell();
|
|
182
|
+
if (typeof shell === "string") return { file: shell, args: ["-c", 'eval "$TG_CMD"'], shell: false, cmdEnv: { TG_CMD: command } };
|
|
183
|
+
return { file: command, args: [], shell };
|
|
184
|
+
}
|
|
185
|
+
function mergeSpawnEnv(env, cmdEnv) {
|
|
186
|
+
return cmdEnv ? { ...env ?? process.env, ...cmdEnv } : env;
|
|
187
|
+
}
|
|
188
|
+
function signalExitCode(signal) {
|
|
189
|
+
const num = os.constants.signals[signal];
|
|
190
|
+
return 128 + (num ?? 0);
|
|
191
|
+
}
|
|
192
|
+
function resolveProfile(explicit) {
|
|
193
|
+
if (explicit) return explicit;
|
|
194
|
+
try {
|
|
195
|
+
const p = loadConfig().compression.profile;
|
|
196
|
+
return p && p !== "auto" ? p : "balanced";
|
|
197
|
+
} catch {
|
|
198
|
+
return "balanced";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function resolveCompressLimits() {
|
|
202
|
+
try {
|
|
203
|
+
const bc = loadConfig().bash_compress;
|
|
204
|
+
return { maxLines: bc.max_lines, maxBytes: bc.max_bytes };
|
|
205
|
+
} catch {
|
|
206
|
+
return { maxLines: 1e3, maxBytes: 64 * 1024 };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function run(command, opts = {}) {
|
|
210
|
+
const timeout = opts.timeout ?? DEFAULT_TIMEOUT_SECONDS;
|
|
211
|
+
const { filter, argv } = resolveFilter(command, opts.filterName, opts.cwd);
|
|
212
|
+
if (filter === null) {
|
|
213
|
+
if ((opts.maxTokens ?? 0) > 0 || opts.quietSuccess) {
|
|
214
|
+
return wrapAndCompress(command, argv, new IdentityFilter(), timeout, resolveProfile(opts.compressionProfile), opts);
|
|
215
|
+
}
|
|
216
|
+
return passthrough(command, timeout, opts.cwd, opts.env, opts.nativeShell);
|
|
217
|
+
}
|
|
218
|
+
return wrapAndCompress(command, argv, filter, timeout, resolveProfile(opts.compressionProfile), opts);
|
|
219
|
+
}
|
|
220
|
+
function runRaw(command, timeout = DEFAULT_TIMEOUT_SECONDS) {
|
|
221
|
+
return passthrough(command, timeout, void 0, void 0);
|
|
222
|
+
}
|
|
223
|
+
function passthrough(command, timeout, cwd, env, nativeShell) {
|
|
224
|
+
const { file, args, shell, cmdEnv } = spawnTarget(command, nativeShell);
|
|
225
|
+
const result = spawnSync(file, args, {
|
|
226
|
+
...baseSpawnOptions(timeout, cwd),
|
|
227
|
+
shell,
|
|
228
|
+
env: mergeSpawnEnv(env, cmdEnv),
|
|
229
|
+
stdio: "inherit"
|
|
230
|
+
});
|
|
231
|
+
if (isTimeout(result.error)) return 124;
|
|
232
|
+
if (result.status !== null) return result.status;
|
|
233
|
+
if (result.signal) return signalExitCode(result.signal);
|
|
234
|
+
return 0;
|
|
235
|
+
}
|
|
236
|
+
function isTimeout(error) {
|
|
237
|
+
return !!error && error.code === "ETIMEDOUT";
|
|
238
|
+
}
|
|
239
|
+
function decode(buf) {
|
|
240
|
+
if (buf == null) return "";
|
|
241
|
+
return typeof buf === "string" ? buf : buf.toString("utf8");
|
|
242
|
+
}
|
|
243
|
+
async function wrapAndCompress(command, argv, filter, timeout, profile, opts) {
|
|
244
|
+
const writeStdout = opts.writeStdout ?? ((s) => process.stdout.write(s));
|
|
245
|
+
const writeStderr = opts.writeStderr ?? ((s) => process.stderr.write(s));
|
|
246
|
+
const startTime = Date.now();
|
|
247
|
+
const { file, args, shell, cmdEnv } = spawnTarget(command, opts.nativeShell);
|
|
248
|
+
const stdoutSink = new CaptureSink(MAX_CAPTURE_BYTES);
|
|
249
|
+
const stderrSink = new CaptureSink(MAX_CAPTURE_BYTES);
|
|
250
|
+
let timedOut = false;
|
|
251
|
+
let overflowed = false;
|
|
252
|
+
const child = spawn(file, args, { cwd: opts.cwd, shell, env: mergeSpawnEnv(opts.env, cmdEnv), stdio: ["ignore", "pipe", "pipe"] });
|
|
253
|
+
const heartbeat = scheduleHeartbeat(startTime, opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS, (elapsed) => {
|
|
254
|
+
writeStderr(`[token-goat compress] still running, ${elapsed}s elapsed
|
|
255
|
+
`);
|
|
256
|
+
});
|
|
257
|
+
const timeoutHandle = setTimeout(() => {
|
|
258
|
+
timedOut = true;
|
|
259
|
+
child.kill();
|
|
260
|
+
}, timeout * 1e3);
|
|
261
|
+
const onData = (sink) => (chunk) => {
|
|
262
|
+
heartbeat.onOutput();
|
|
263
|
+
sink.push(chunk);
|
|
264
|
+
if (sink.overflowed) {
|
|
265
|
+
overflowed = true;
|
|
266
|
+
child.kill();
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
child.stdout?.on("data", onData(stdoutSink));
|
|
270
|
+
child.stderr?.on("data", onData(stderrSink));
|
|
271
|
+
const { code, signal } = await new Promise((resolve) => {
|
|
272
|
+
child.on("close", (code2, signal2) => resolve({ code: code2, signal: signal2 }));
|
|
273
|
+
});
|
|
274
|
+
heartbeat.stop();
|
|
275
|
+
clearTimeout(timeoutHandle);
|
|
276
|
+
let stdoutText = stdoutSink.text();
|
|
277
|
+
let stderrText = stderrSink.text();
|
|
278
|
+
if (overflowed) {
|
|
279
|
+
stdoutText += `
|
|
280
|
+
[token-goat: capture capped at ${MAX_CAPTURE_BYTES / (1024 * 1024)} MiB]`;
|
|
281
|
+
}
|
|
282
|
+
let exitCode;
|
|
283
|
+
if (timedOut) {
|
|
284
|
+
exitCode = 124;
|
|
285
|
+
stderrText = (stderrText ? stderrText + "\n" : "") + `[token-goat: command exceeded ${timeout}s timeout and was killed]`;
|
|
286
|
+
} else if (code !== null) {
|
|
287
|
+
exitCode = code;
|
|
288
|
+
} else if (signal) {
|
|
289
|
+
exitCode = signalExitCode(signal);
|
|
290
|
+
} else {
|
|
291
|
+
exitCode = 0;
|
|
292
|
+
}
|
|
293
|
+
if (opts.quietSuccess && exitCode === 0) {
|
|
294
|
+
const duration = ((Date.now() - startTime) / 1e3).toFixed(1) + "s";
|
|
295
|
+
const fullRaw = (stdoutText + (stderrText ? "\n" + stderrText : "")).trim();
|
|
296
|
+
const id = storeBashOutputSync(command, fullRaw, 0, opts.cwd ?? null);
|
|
297
|
+
const summary = `[tg: ok] ${command} (${duration}, recall: token-goat bash-output ${id})
|
|
298
|
+
`;
|
|
299
|
+
writeStdout(summary);
|
|
300
|
+
return 0;
|
|
301
|
+
}
|
|
302
|
+
const limits = resolveCompressLimits();
|
|
303
|
+
const { applied, marker, compressed, text: delivered } = deliverCompressed(filter, stdoutText, stderrText, exitCode, argv, {
|
|
304
|
+
compressionProfile: profile,
|
|
305
|
+
maxLines: limits.maxLines,
|
|
306
|
+
maxBytes: limits.maxBytes
|
|
307
|
+
});
|
|
308
|
+
let text = delivered;
|
|
309
|
+
const maxTokens = opts.maxTokens ?? 0;
|
|
310
|
+
if (maxTokens > 0) text = capTokens(text, maxTokens);
|
|
311
|
+
let body = text + marker;
|
|
312
|
+
if (applied) {
|
|
313
|
+
const fullRaw = (stdoutText + (stderrText ? "\n" + stderrText : "")).trim();
|
|
314
|
+
const recallId = storeBashOutputSync(command, fullRaw, exitCode, opts.cwd ?? null);
|
|
315
|
+
body += "\n[token-goat] full output: bash-output " + recallId + " --full";
|
|
316
|
+
}
|
|
317
|
+
writeStdout(body.endsWith("\n") ? body : body + "\n");
|
|
318
|
+
if (applied) recordSavings(compressed);
|
|
319
|
+
return exitCode;
|
|
320
|
+
}
|
|
321
|
+
function recordSavings(result) {
|
|
322
|
+
const delivered = deliveredOutputBytes(result.originalBytes);
|
|
323
|
+
const bytesSaved = Math.max(0, delivered - result.compressedBytes);
|
|
324
|
+
if (bytesSaved < MIN_RECORD_STAT_BYTES) return;
|
|
325
|
+
recordStat(`bash_compress:${result.filterName}`, bytesSaved, compressedTokensSaved(bytesSaved));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export {
|
|
329
|
+
clipToDeliveryCap,
|
|
330
|
+
deliveredOutputBytes,
|
|
331
|
+
canRunWrappedShell,
|
|
332
|
+
DEFAULT_TIMEOUT_SECONDS,
|
|
333
|
+
MAX_CAPTURE_BYTES,
|
|
334
|
+
DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
335
|
+
run,
|
|
336
|
+
runRaw
|
|
337
|
+
};
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
stripMultilineStringSpan,
|
|
11
11
|
stripNestedBlockCommentSpan,
|
|
12
12
|
stripStringLiterals
|
|
13
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-JNIFSVWM.mjs";
|
|
14
14
|
import {
|
|
15
15
|
init_define_import_meta_env
|
|
16
16
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -133,6 +133,7 @@ function shellMountToWindowsPath(p) {
|
|
|
133
133
|
}
|
|
134
134
|
return s;
|
|
135
135
|
}
|
|
136
|
+
var TOOL_RESULTS_ID_CHARS = "[a-z0-9_-]+";
|
|
136
137
|
function normalizePath(p) {
|
|
137
138
|
let s = p;
|
|
138
139
|
if (EXTENDED_UNC_PREFIX_RE.test(s)) {
|
|
@@ -217,6 +218,7 @@ export {
|
|
|
217
218
|
MSYS_PATH_RE,
|
|
218
219
|
expandShortPath,
|
|
219
220
|
lowercaseDriveLetter,
|
|
221
|
+
TOOL_RESULTS_ID_CHARS,
|
|
220
222
|
normalizePath,
|
|
221
223
|
normalizeDarwinSystemAlias,
|
|
222
224
|
resolveIndexPath,
|