token-goat 2.9.6 → 2.9.9
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 +7 -4
- package/SECURITY.md +1 -1
- package/dist/{token-goat-chunk-3HJQR4OO.mjs → token-goat-chunk-BYDDWQ2T.mjs} +200 -32
- package/dist/{token-goat-chunk-3ZAMYHQG.mjs → token-goat-chunk-DRH4CVGF.mjs} +5 -5
- package/dist/{token-goat-chunk-TX64YIIV.mjs → token-goat-chunk-K5GKX6ND.mjs} +5 -5
- package/dist/{token-goat-chunk-T2OE7MYM.mjs → token-goat-chunk-KIEOFWLL.mjs} +2794 -2760
- package/dist/{token-goat-chunk-46VKOCUH.mjs → token-goat-chunk-L6Q2XM5X.mjs} +2 -2
- package/dist/{token-goat-chunk-C7LLUVUT.mjs → token-goat-chunk-LQ3SGWIW.mjs} +3 -3
- package/dist/{token-goat-chunk-LXIC7MTW.mjs → token-goat-chunk-OBDTBOQA.mjs} +1 -1
- package/dist/{token-goat-chunk-EIZYCVBM.mjs → token-goat-chunk-P5SQX2VK.mjs} +408 -84
- package/dist/{token-goat-chunk-J7LGMKF3.mjs → token-goat-chunk-PNMGVJ4C.mjs} +44 -9
- package/dist/{token-goat-chunk-7GJBID7S.mjs → token-goat-chunk-QCHD2ENV.mjs} +5 -3
- package/dist/{token-goat-chunk-UJORWTI4.mjs → token-goat-chunk-WBPVYAEO.mjs} +2 -2
- package/dist/token-goat-hook.mjs +5 -5
- package/dist/token-goat.core.mjs +5 -5
- package/docs/install.md +62 -0
- package/docs/security.md +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Restart your AI sessions. Run `token-goat stats` a couple of minutes after your
|
|
|
37
37
|
|
|
38
38
|
> **Built and continually improved, free, by one person. If it saves you tokens, drop a ⭐️ at the top of this page. One click. Makes my day. Also, if you'd like anything added, [drop me a line](mailto:token-goat@dfkhelper.com).**
|
|
39
39
|
|
|
40
|
-
[Install](docs/install.md) · [CLI](docs/cli.md) · [What gets installed?](docs/install.md#what-gets-installed) · [Stats](#stats-display) · [Security & uninstall](docs/security.md)
|
|
40
|
+
[Install](docs/install.md) · [CLI](docs/cli.md) · [Architecture Q&A](docs/architecture-qa.html) · [What gets installed?](docs/install.md#what-gets-installed) · [Stats](#stats-display) · [Security & uninstall](docs/security.md)
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
@@ -129,7 +129,7 @@ The fastest way to reduce AI token costs is fixing these five, not writing short
|
|
|
129
129
|
| `claude-in-chrome`'s `computer`/`browser_batch` return a raw, full-resolution base64 screenshot in-band, with no destination-file option to redirect through image-shrink | Inline screenshot blocks are shrunk via the same image-shrink pipeline in place, and a repeated `Tab Context:` listing (appended to nearly every call, often unchanged) collapses to a placeholder once seen unchanged this session |
|
|
130
130
|
| Agent tool spawns a subagent with no orientation and no reuse hints | A `PreToolUse` handler appends a compact briefing pack to the prompt: a one-line project-map summary, 2-3 recent cached-output IDs, and a surgical-read reminder (~300 tokens) |
|
|
131
131
|
| Subagent's own final report runs long and gets discarded once the parent moves on | Agent tool results ≥8000 characters get a recall pointer appended (`token-goat recall`); the original report always reaches the parent untouched |
|
|
132
|
-
| Agent tool spawns with no `subagent_type` (or an explicit `general-purpose`), so the lane starts by paying for every tool and MCP schema on the machine | Once per session, a `PostToolUse` advisory names up to three `tools:`-restricted agent definitions found in `~/.claude/agents` and suggests passing one as `subagent_type` on a future spawn that fits. It fires only when at least one restricted definition exists, states outright that the observed spawn already ran and nothing was saved, and records a zero-credit stat |
|
|
132
|
+
| Agent tool spawns with no `subagent_type` (or an explicit `general-purpose`), so the lane starts by paying for every tool and MCP schema on the machine | Once per session, a `PostToolUse` advisory names up to three `tools:`-restricted agent definitions found in `~/.claude/agents` or the current project's `.claude/agents` and suggests passing one as `subagent_type` on a future spawn that fits. It fires only when at least one restricted definition exists, states outright that the observed spawn already ran and nothing was saved, and records a zero-credit stat |
|
|
133
133
|
| Large MCP tool result (≥2 KB) is a homogeneous array of objects, e.g. a list/search result | Deterministic structural compression: table-ified into one header row + tab-delimited rows, with columns constant across every row hoisted into a single `constant:` line instead of repeated per row; only applied when it saves ≥15%. Full original always recoverable via `token-goat bash-output <id>` (labeled `[token-goat: compressed, full via mcp-output <id>]`). Disable with `TOKEN_GOAT_MCP_COMPRESS=0` |
|
|
134
134
|
| Large MCP tool result (≥2 KB) doesn't table-ify (an object-rooted config dump, a single-resource response, a nested settings tree) but most of its bytes are `null`/`""`/`[]`/`{}` | Deterministic empty-value pruning: recursively drops those four empty shapes to a fixed point (a container left empty by its own dropped children is dropped too) and renders the remainder as compact JSON with a trailing `dropped N empty value(s) (null, "", [], {})` summary line; `0` and `false` are never dropped; only applied when it saves ≥15%. Same full-recovery-by-id guarantee and `TOKEN_GOAT_MCP_COMPRESS=0` opt-out as the table pass |
|
|
135
135
|
| GitHub MCP tool result (`list_pull_requests`, `list_issues`, `search_code`, `get_file_contents`, `pull_request_read`, …) carries dozens of boilerplate fields per object | GitHub compression pack strips `_links`, `node_id`, `gravatar_id`, `site_admin`, and every `*_url` field (`avatar_url`, `html_url`, `events_url`, `gists_url`, `followers_url`, …) except `download_url`/`git_url`/`clone_url`/`ssh_url`, before handing the shrunk JSON to the same table-ifying pass — same `TOKEN_GOAT_MCP_COMPRESS=0` opt-out and full-recovery-by-id guarantee |
|
|
@@ -169,6 +169,9 @@ The fastest way to reduce AI token costs is fixing these five, not writing short
|
|
|
169
169
|
| Fetched web content lands raw in model context | Always wrapped in an untrusted-content fence; scanned for attack patterns, and a matched pattern name is written to the log and into the fence's notice |
|
|
170
170
|
| Chatty log repeats the same error or event thousands of times | `token-goat logfold` collapses consecutive duplicates to `[Nx]` counts; same event logged with different timestamps or request IDs folds correctly — ~90–95% smaller on repetitive logs |
|
|
171
171
|
| Reading poetry.lock or package-lock.json to find a pinned version | `token-goat lockdeps` returns a name/version table of direct dependencies; optional packages and transitive entries excluded |
|
|
172
|
+
| Large SVG / diagram file (≥8 KB) read in full | Coordinate path flooding blocked; extracted layer/group IDs and title shown; redirects to `token-goat xml-outline` and `xml-query` |
|
|
173
|
+
| Broad recursive Glob sweep (`*`, `**/*`) on root directory | Pre-Glob hook warns against tree-dumping and points at `token-goat map --compact` for fast, lightweight structure inspection |
|
|
174
|
+
| Compound test/build pipeline (`npm run build && npm run typecheck && npm test`) | Post-Bash hook routes chained build/test/lint commands to `generic-ci` compression, dropping verbose passing steps and compiler noise |
|
|
172
175
|
|
|
173
176
|
On a per-token API plan, 100K wasted tokens per session runs about $0.30. Five sessions a week is ~$450/year. AI coding cost reduction at that scale comes from fixing the waste, not from using the product less. Token-goat is free. And on subscription plans, it can result in limits feeling 10x higher.
|
|
174
177
|
|
|
@@ -320,7 +323,7 @@ corpus of captured shell output through the real compression path and reports ho
|
|
|
320
323
|
result got, alongside a count of the lines each case is not allowed to lose. Deleting output makes
|
|
321
324
|
the first number look better, so the second one is what keeps the first honest.
|
|
322
325
|
|
|
323
|
-
Every command, with its flags, its output, and the comparison workflows that chain them: **[CLI reference](docs/cli.md)**.
|
|
326
|
+
Every command, with its flags, its output, and the comparison workflows that chain them: **[CLI reference](docs/cli.md)**. For architectural analysis, empirical evaluations, and technical answers to common engineering questions: **[Architecture & Technical Q&A](docs/architecture-qa.html)**.
|
|
324
327
|
|
|
325
328
|
## MCP server
|
|
326
329
|
|
|
@@ -422,7 +425,7 @@ never drift on where `mcp.json` lives or what key name it looks for.
|
|
|
422
425
|
|
|
423
426
|
**What the index actually holds, in plain terms.** The point of a surgical read is returning a function body without the file around it, which means the database stores those bodies. `symbols.body` holds the source text of every indexed symbol, `symbols.docstring` its doc comment, `refs.context` the line around each reference, and `chunks.text` the passages that semantic search embeds. There is also a full-text index over the bodies and docstrings. So the database is not a list of names and line numbers: it is a substantial copy of your source, sitting in a plain unencrypted SQLite file outside the repository.
|
|
424
427
|
|
|
425
|
-
The file-by-file table for each harness, and the path that file sits at: **[What gets installed](docs/install.md#what-gets-installed)
|
|
428
|
+
The file-by-file table for each harness, and the path that file sits at: **[What gets installed](docs/install.md#what-gets-installed)** (see also **[Permissions & auto-approval](docs/install.md#command-auto-approval-and-permissions)**).
|
|
426
429
|
|
|
427
430
|
## Zero maintenance
|
|
428
431
|
|
package/SECURITY.md
CHANGED
|
@@ -101,7 +101,7 @@ For a scanner that ingests a bill of materials rather than a lockfile, `npm run
|
|
|
101
101
|
|
|
102
102
|
## Verifying what you installed
|
|
103
103
|
|
|
104
|
-
Every published version is built and pushed by one workflow, [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which runs only when a GitHub release is published (or manually, and then only from `main`). It publishes with npm provenance, so npm holds a signed attestation tying the tarball to the commit and workflow run that produced it. Nothing is ever published from a
|
|
104
|
+
Every published version is built and pushed by one workflow, [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which runs only when a GitHub release is published (or manually, and then only from `main`). It publishes with npm provenance, so npm holds a signed attestation tying the tarball to the commit and workflow run that produced it. Nothing is ever published from a developer workstation.
|
|
105
105
|
|
|
106
106
|
To check a copy you already have:
|
|
107
107
|
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
getFilePath,
|
|
48
48
|
getHarnessName,
|
|
49
49
|
globalDbPath,
|
|
50
|
+
hasUnquotedOperator,
|
|
50
51
|
isAutoTriggerMultiplierExplicit,
|
|
51
52
|
isCaseInsensitiveFs,
|
|
52
53
|
isCodeFenceDelimiter,
|
|
@@ -100,7 +101,7 @@ import {
|
|
|
100
101
|
toDisplayPath,
|
|
101
102
|
toKB,
|
|
102
103
|
withFileLock
|
|
103
|
-
} from "./token-goat-chunk-
|
|
104
|
+
} from "./token-goat-chunk-KIEOFWLL.mjs";
|
|
104
105
|
import {
|
|
105
106
|
registerReset
|
|
106
107
|
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
@@ -6688,11 +6689,15 @@ function getFileLineRanges(filePath) {
|
|
|
6688
6689
|
return _fileLineRanges.get(foldPath(normalizePath(filePath))) ?? [];
|
|
6689
6690
|
}
|
|
6690
6691
|
var MAX_SERVED_OUTPUTS_PER_FILE = 8;
|
|
6692
|
+
var GENERIC_SERVED_OUTPUT_KEY = "\0<bash-generic-served>";
|
|
6693
|
+
var GENERIC_SERVED_OUTPUT_FOLDED_KEY = foldPath(normalizePath(GENERIC_SERVED_OUTPUT_KEY));
|
|
6694
|
+
var MAX_GENERIC_SERVED_OUTPUTS = 32;
|
|
6691
6695
|
function recordFileServedOutput(filePath, outputId) {
|
|
6692
6696
|
const key = foldPath(normalizePath(filePath));
|
|
6697
|
+
const cap = key === GENERIC_SERVED_OUTPUT_FOLDED_KEY ? MAX_GENERIC_SERVED_OUTPUTS : MAX_SERVED_OUTPUTS_PER_FILE;
|
|
6693
6698
|
const ids = (_fileServedOutputs.get(key) ?? []).filter((id) => id !== outputId);
|
|
6694
6699
|
ids.push(outputId);
|
|
6695
|
-
if (ids.length >
|
|
6700
|
+
if (ids.length > cap) ids.splice(0, ids.length - cap);
|
|
6696
6701
|
_fileServedOutputs.set(key, ids);
|
|
6697
6702
|
}
|
|
6698
6703
|
function getFileServedOutputs(filePath) {
|
|
@@ -7624,6 +7629,7 @@ function isPsMultilineSystemQuery(cmd) {
|
|
|
7624
7629
|
}
|
|
7625
7630
|
function getMonitoringRecallHint(cmd) {
|
|
7626
7631
|
const trimmed = cmd.trim();
|
|
7632
|
+
if (hasUnquotedOperator(trimmed, ["&&", "||", ";"])) return null;
|
|
7627
7633
|
for (const { pattern, recallHint } of MONITORING_COMMAND_PATTERNS) {
|
|
7628
7634
|
if (pattern.test(trimmed)) return recallHint;
|
|
7629
7635
|
}
|
|
@@ -8191,13 +8197,15 @@ function mergeLineRanges(disk, mem) {
|
|
|
8191
8197
|
}
|
|
8192
8198
|
return Array.from(byPath.entries());
|
|
8193
8199
|
}
|
|
8200
|
+
var GENERIC_SERVED_OUTPUT_FOLDED_KEY2 = foldPath(normalizePath(GENERIC_SERVED_OUTPUT_KEY));
|
|
8194
8201
|
function mergeServedOutputs(disk, mem) {
|
|
8195
8202
|
const byPath = /* @__PURE__ */ new Map();
|
|
8196
8203
|
for (const [filePath, ids] of disk) byPath.set(filePath, [...ids]);
|
|
8197
8204
|
for (const [filePath, ids] of mem) {
|
|
8198
8205
|
const prev = byPath.get(filePath) ?? [];
|
|
8199
8206
|
const merged = [...prev.filter((id) => !ids.includes(id)), ...ids];
|
|
8200
|
-
|
|
8207
|
+
const cap = filePath === GENERIC_SERVED_OUTPUT_FOLDED_KEY2 ? MAX_GENERIC_SERVED_OUTPUTS : MAX_SERVED_OUTPUTS_PER_FILE;
|
|
8208
|
+
if (merged.length > cap) merged.splice(0, merged.length - cap);
|
|
8201
8209
|
byPath.set(filePath, merged);
|
|
8202
8210
|
}
|
|
8203
8211
|
return Array.from(byPath.entries());
|
|
@@ -9939,7 +9947,7 @@ function pruneShrinkCache() {
|
|
|
9939
9947
|
}
|
|
9940
9948
|
}
|
|
9941
9949
|
async function finalizeShrinkResult(result, filePath) {
|
|
9942
|
-
const basename12 = path6.basename(filePath);
|
|
9950
|
+
const basename12 = displaySafePath(path6.basename(filePath));
|
|
9943
9951
|
const shrinkSaved = result.originalBytes - result.shrunkBytes;
|
|
9944
9952
|
const tier = loadConfig().image_shrink.vision_tier;
|
|
9945
9953
|
recordStat("image_shrink", shrinkSaved, visionTokensSaved(result.originalWidth, result.originalHeight, result.width, result.height, tier), void 0, basename12);
|
|
@@ -10260,6 +10268,47 @@ function modelDir() {
|
|
|
10260
10268
|
function downloadUrl(file) {
|
|
10261
10269
|
return `https://huggingface.co/${DEFAULT_MODEL}/resolve/${PINNED_MODEL_REVISION}/${file.name}`;
|
|
10262
10270
|
}
|
|
10271
|
+
function sharedModelCacheDir() {
|
|
10272
|
+
const raw = process.env["TOKEN_GOAT_MODEL_CACHE_DIR"]?.trim();
|
|
10273
|
+
if (!raw) return null;
|
|
10274
|
+
return path7.join(raw, ...DEFAULT_MODEL.split("/"), PINNED_MODEL_REVISION);
|
|
10275
|
+
}
|
|
10276
|
+
async function copyFromSharedCache(shared, file, target) {
|
|
10277
|
+
const source = path7.join(shared, file.name);
|
|
10278
|
+
const temp = `${target}.${process.pid}.shared`;
|
|
10279
|
+
try {
|
|
10280
|
+
if (!fs11.existsSync(source)) return false;
|
|
10281
|
+
fs11.copyFileSync(source, temp);
|
|
10282
|
+
if (await sha256Of(temp) !== file.sha256) {
|
|
10283
|
+
fs11.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
|
|
10284
|
+
fs11.rmSync(source, { force: true, maxRetries: 20, retryDelay: 25 });
|
|
10285
|
+
return false;
|
|
10286
|
+
}
|
|
10287
|
+
fs11.renameSync(temp, target);
|
|
10288
|
+
return true;
|
|
10289
|
+
} catch {
|
|
10290
|
+
try {
|
|
10291
|
+
fs11.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
|
|
10292
|
+
} catch {
|
|
10293
|
+
}
|
|
10294
|
+
return false;
|
|
10295
|
+
}
|
|
10296
|
+
}
|
|
10297
|
+
function publishToSharedCache(shared, file, target) {
|
|
10298
|
+
const destination = path7.join(shared, file.name);
|
|
10299
|
+
const temp = `${destination}.${process.pid}.partial`;
|
|
10300
|
+
try {
|
|
10301
|
+
if (fs11.existsSync(destination)) return;
|
|
10302
|
+
fs11.mkdirSync(path7.dirname(destination), { recursive: true });
|
|
10303
|
+
fs11.copyFileSync(target, temp);
|
|
10304
|
+
fs11.renameSync(temp, destination);
|
|
10305
|
+
} catch {
|
|
10306
|
+
try {
|
|
10307
|
+
fs11.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
|
|
10308
|
+
} catch {
|
|
10309
|
+
}
|
|
10310
|
+
}
|
|
10311
|
+
}
|
|
10263
10312
|
var _ort = null;
|
|
10264
10313
|
var _ortError = null;
|
|
10265
10314
|
var _ortLoadAttempted = false;
|
|
@@ -10355,6 +10404,7 @@ async function ensureModelFiles(modelName = DEFAULT_MODEL) {
|
|
|
10355
10404
|
ensureDataDirPrivate();
|
|
10356
10405
|
const dir = modelDir();
|
|
10357
10406
|
const offline = loadConfig().network.offline;
|
|
10407
|
+
const shared = sharedModelCacheDir();
|
|
10358
10408
|
for (const file of MODEL_FILES) {
|
|
10359
10409
|
const target = path7.join(dir, file.name);
|
|
10360
10410
|
if (fs11.existsSync(target)) {
|
|
@@ -10362,6 +10412,10 @@ async function ensureModelFiles(modelName = DEFAULT_MODEL) {
|
|
|
10362
10412
|
if (digest === file.sha256) continue;
|
|
10363
10413
|
fs11.rmSync(target, { force: true });
|
|
10364
10414
|
}
|
|
10415
|
+
if (shared) {
|
|
10416
|
+
fs11.mkdirSync(path7.dirname(target), { recursive: true });
|
|
10417
|
+
if (await copyFromSharedCache(shared, file, target)) continue;
|
|
10418
|
+
}
|
|
10365
10419
|
if (offline) {
|
|
10366
10420
|
throw new Error(
|
|
10367
10421
|
`Offline mode is on (network.offline): refusing to download ${file.name} for the embedding model. Copy the pinned files into ${dir} on a connected machine to use semantic search here.`
|
|
@@ -10372,6 +10426,7 @@ async function ensureModelFiles(modelName = DEFAULT_MODEL) {
|
|
|
10372
10426
|
`Downloading the embedding model, once (${file.name}, ${Math.round(file.bytes / 1024 / 1024)} MB) into ${dir}`
|
|
10373
10427
|
);
|
|
10374
10428
|
await download(file, target);
|
|
10429
|
+
if (shared) publishToSharedCache(shared, file, target);
|
|
10375
10430
|
}
|
|
10376
10431
|
return dir;
|
|
10377
10432
|
}
|
|
@@ -11061,7 +11116,7 @@ function _pathPriorityPenalty(filePath) {
|
|
|
11061
11116
|
|
|
11062
11117
|
// src/parser_fingerprint.ts
|
|
11063
11118
|
init_define_import_meta_env();
|
|
11064
|
-
var PARSER_FINGERPRINT = "
|
|
11119
|
+
var PARSER_FINGERPRINT = "d96c01d5957651c0";
|
|
11065
11120
|
|
|
11066
11121
|
// src/parser.ts
|
|
11067
11122
|
init_define_import_meta_env();
|
|
@@ -14798,16 +14853,26 @@ ${commented}`);
|
|
|
14798
14853
|
// src/parser.ts
|
|
14799
14854
|
var _require3 = createRequire3(import.meta.url);
|
|
14800
14855
|
var _parserCtor;
|
|
14856
|
+
var _parserCtorError = null;
|
|
14857
|
+
var _parserCtorOverride = void 0;
|
|
14801
14858
|
var _grammarCache = /* @__PURE__ */ new Map();
|
|
14802
14859
|
function loadParserCtor() {
|
|
14860
|
+
if (_parserCtorOverride !== void 0) return _parserCtorOverride;
|
|
14803
14861
|
if (_parserCtor !== void 0) return _parserCtor;
|
|
14804
14862
|
try {
|
|
14805
14863
|
_parserCtor = _require3("tree-sitter");
|
|
14806
|
-
} catch {
|
|
14864
|
+
} catch (e) {
|
|
14807
14865
|
_parserCtor = null;
|
|
14866
|
+
_parserCtorError = e instanceof Error ? e : new Error(String(e));
|
|
14808
14867
|
}
|
|
14809
14868
|
return _parserCtor;
|
|
14810
14869
|
}
|
|
14870
|
+
function treeSitterCoreAvailable() {
|
|
14871
|
+
return loadParserCtor() !== null;
|
|
14872
|
+
}
|
|
14873
|
+
function treeSitterCoreLoadError() {
|
|
14874
|
+
return _parserCtorError;
|
|
14875
|
+
}
|
|
14811
14876
|
var CPP_HEADER_SNIFF_RE = /\bclass\s+\w|\bnamespace\s+\w|\btemplate\s*<|::\s*\w|\b(?:public|private|protected)\s*:/;
|
|
14812
14877
|
var MAX_SYMBOL_BODY_CHARS = SYMBOL_BODY_CHAR_CAP;
|
|
14813
14878
|
function boundSymbolBody(body) {
|
|
@@ -18768,6 +18833,9 @@ var FILE_TYPE_THRESHOLDS = {
|
|
|
18768
18833
|
// always intercept (any size)
|
|
18769
18834
|
html: 5e4,
|
|
18770
18835
|
txt: 2e4,
|
|
18836
|
+
log: 1e4,
|
|
18837
|
+
svg: 8e3,
|
|
18838
|
+
xml: 2e4,
|
|
18771
18839
|
csv: 1e4,
|
|
18772
18840
|
tsv: 1e4,
|
|
18773
18841
|
transcript: 1e4,
|
|
@@ -18835,8 +18903,9 @@ ${headings.join("\n")}` : ""].filter(Boolean).join("\n")
|
|
|
18835
18903
|
}
|
|
18836
18904
|
function handleTxt(filePath, content, contentLengthHint) {
|
|
18837
18905
|
const length = contentLengthHint ?? content.length;
|
|
18838
|
-
if (length < FILE_TYPE_THRESHOLDS.txt) return { shouldBlock: false, message: "" };
|
|
18839
18906
|
const isLog = /\.(log|out|err|trace)$/i.test(filePath) || /[\\/]logs[\\/]/.test(filePath);
|
|
18907
|
+
const threshold = isLog ? FILE_TYPE_THRESHOLDS.log : FILE_TYPE_THRESHOLDS.txt;
|
|
18908
|
+
if (length < threshold) return { shouldBlock: false, message: "" };
|
|
18840
18909
|
const recall = isLog ? `Log file \u2014 use Read with offset/limit params, or: token-goat bash-output --file "${filePath}" --tail 100 --grep "error|ERROR"` : "Use Read with offset and limit params to sample specific line ranges.";
|
|
18841
18910
|
if (previewUnavailable(content, length)) {
|
|
18842
18911
|
return {
|
|
@@ -18868,6 +18937,64 @@ ${fenceUntrustedFileContent(preview)}
|
|
|
18868
18937
|
${recall}`
|
|
18869
18938
|
};
|
|
18870
18939
|
}
|
|
18940
|
+
function handleSvg(filePath, content, contentLengthHint) {
|
|
18941
|
+
const length = contentLengthHint ?? content.length;
|
|
18942
|
+
if (length < FILE_TYPE_THRESHOLDS.svg) return { shouldBlock: false, message: "" };
|
|
18943
|
+
if (previewUnavailable(content, length)) {
|
|
18944
|
+
return {
|
|
18945
|
+
shouldBlock: true,
|
|
18946
|
+
message: [
|
|
18947
|
+
`Large SVG file (${formatBytes(length)}) \u2014 too large to preview (exceeds the in-hook scan cap).`,
|
|
18948
|
+
`Inspect structure: token-goat xml-outline "${filePath}"`,
|
|
18949
|
+
`Query layers/elements: token-goat xml-query "${filePath}" "//g[@id]"`
|
|
18950
|
+
].join("\n")
|
|
18951
|
+
};
|
|
18952
|
+
}
|
|
18953
|
+
const titleMatch = content.match(/<title[^>]*>([^<]*)<\/title>/i);
|
|
18954
|
+
const title = titleMatch ? titleMatch[1]?.trim() : "";
|
|
18955
|
+
const groupIds = [];
|
|
18956
|
+
const idRegex = /<g[^>]*\bid=["']([^"']+)["']/gi;
|
|
18957
|
+
let match;
|
|
18958
|
+
while ((match = idRegex.exec(content)) !== null && groupIds.length < 10) {
|
|
18959
|
+
if (match[1]) groupIds.push(match[1]);
|
|
18960
|
+
}
|
|
18961
|
+
const preview = [
|
|
18962
|
+
title ? `Title: ${title}` : "",
|
|
18963
|
+
groupIds.length > 0 ? `Layer/Group IDs: ${groupIds.join(", ")}` : ""
|
|
18964
|
+
].filter(Boolean).join("\n");
|
|
18965
|
+
return {
|
|
18966
|
+
shouldBlock: true,
|
|
18967
|
+
message: [
|
|
18968
|
+
`Large SVG/diagram file (${formatBytes(length)}) \u2014 raw coordinate paths flood context.`,
|
|
18969
|
+
preview ? fenceUntrustedFileContent(preview) : "",
|
|
18970
|
+
`Inspect structure: token-goat xml-outline "${filePath}"`,
|
|
18971
|
+
`Query elements: token-goat xml-query "${filePath}" "//g[@id]"`,
|
|
18972
|
+
`Search text labels: token-goat grep "<text>" --glob "${filePath}"`
|
|
18973
|
+
].filter(Boolean).join("\n")
|
|
18974
|
+
};
|
|
18975
|
+
}
|
|
18976
|
+
function handleXml(filePath, content, contentLengthHint) {
|
|
18977
|
+
const length = contentLengthHint ?? content.length;
|
|
18978
|
+
if (length < FILE_TYPE_THRESHOLDS.xml) return { shouldBlock: false, message: "" };
|
|
18979
|
+
if (previewUnavailable(content, length)) {
|
|
18980
|
+
return {
|
|
18981
|
+
shouldBlock: true,
|
|
18982
|
+
message: [
|
|
18983
|
+
`Large XML file (${formatBytes(length)}) \u2014 too large to preview (exceeds the in-hook scan cap).`,
|
|
18984
|
+
`Inspect structure: token-goat xml-outline "${filePath}"`,
|
|
18985
|
+
`Query nodes: token-goat xml-query "${filePath}" "<selector>"`
|
|
18986
|
+
].join("\n")
|
|
18987
|
+
};
|
|
18988
|
+
}
|
|
18989
|
+
return {
|
|
18990
|
+
shouldBlock: true,
|
|
18991
|
+
message: [
|
|
18992
|
+
`Large XML file (${formatBytes(length)}).`,
|
|
18993
|
+
`Inspect hierarchy: token-goat xml-outline "${filePath}"`,
|
|
18994
|
+
`Query specific elements: token-goat xml-query "${filePath}" "<selector>"`
|
|
18995
|
+
].join("\n")
|
|
18996
|
+
};
|
|
18997
|
+
}
|
|
18871
18998
|
function handleOfficeBinary(filePath) {
|
|
18872
18999
|
const filename = filePath.split(/[\\/]/).pop() || "";
|
|
18873
19000
|
const parts = filename.split(".");
|
|
@@ -18986,6 +19113,8 @@ function dispatchFileTypeHandler(filePath, content, contentLengthHint) {
|
|
|
18986
19113
|
if (["md", "mdx", "markdown", "rst"].includes(ext)) return null;
|
|
18987
19114
|
const effectiveLength = contentLengthHint ?? content.length;
|
|
18988
19115
|
if (ext === "pdf") return handlePdf(filePath, effectiveLength);
|
|
19116
|
+
if (ext === "svg") return handleSvg(filePath, content, effectiveLength);
|
|
19117
|
+
if (ext === "xml") return handleXml(filePath, content, effectiveLength);
|
|
18989
19118
|
if (["html", "htm", "xhtml"].includes(ext)) return handleHtml(filePath, content, effectiveLength);
|
|
18990
19119
|
if (["txt", "log", "out", "err", "trace"].includes(ext)) return handleTxt(filePath, content, effectiveLength);
|
|
18991
19120
|
if (ext === "xlsx") return handleXlsx(filePath);
|
|
@@ -19335,7 +19464,7 @@ function buildDeltaCapsule(projectRoot, limit = 8) {
|
|
|
19335
19464
|
}).slice(0, limit);
|
|
19336
19465
|
if (changed.length === 0) return null;
|
|
19337
19466
|
return `Cross-session evidence changed since it was cached:
|
|
19338
|
-
${changed.map((entry) => `- ${entry.source} (use a fresh surgical read)`).join("\n")}`;
|
|
19467
|
+
${changed.map((entry) => `- ${displaySafePath(entry.source)} (use a fresh surgical read)`).join("\n")}`;
|
|
19339
19468
|
}
|
|
19340
19469
|
|
|
19341
19470
|
// src/notebook_compact.ts
|
|
@@ -19941,6 +20070,41 @@ function readIntToolInput(event, key) {
|
|
|
19941
20070
|
}
|
|
19942
20071
|
return void 0;
|
|
19943
20072
|
}
|
|
20073
|
+
function readRequestedSliceWindow(event) {
|
|
20074
|
+
const rawOffset = readIntToolInput(event, "offset");
|
|
20075
|
+
const rawLimit = readIntToolInput(event, "limit");
|
|
20076
|
+
if (rawOffset !== void 0 || rawLimit !== void 0) {
|
|
20077
|
+
return {
|
|
20078
|
+
offset: rawOffset !== void 0 && rawOffset >= 1 ? Math.floor(rawOffset) : 1,
|
|
20079
|
+
limit: rawLimit !== void 0 && rawLimit > 0 ? Math.floor(rawLimit) : void 0,
|
|
20080
|
+
isExplicitSlice: true
|
|
20081
|
+
};
|
|
20082
|
+
}
|
|
20083
|
+
const rawRange = event.toolInput["view_range"] ?? event.toolInput["lines"] ?? event.toolInput["range"];
|
|
20084
|
+
if (Array.isArray(rawRange) && rawRange.length >= 1) {
|
|
20085
|
+
const rawStart = Number(rawRange[0]);
|
|
20086
|
+
const startVal = Number.isFinite(rawStart) && rawStart >= 1 ? Math.floor(rawStart) : 1;
|
|
20087
|
+
if (rawRange.length >= 2) {
|
|
20088
|
+
const rawEnd = Number(rawRange[1]);
|
|
20089
|
+
if (rawEnd === -1) {
|
|
20090
|
+
return { offset: startVal, isExplicitSlice: true };
|
|
20091
|
+
}
|
|
20092
|
+
if (Number.isFinite(rawEnd) && rawEnd >= startVal) {
|
|
20093
|
+
const lineCount = Math.floor(rawEnd - startVal + 1);
|
|
20094
|
+
return { offset: startVal, limit: lineCount, isExplicitSlice: true };
|
|
20095
|
+
}
|
|
20096
|
+
}
|
|
20097
|
+
return { offset: startVal, isExplicitSlice: true };
|
|
20098
|
+
}
|
|
20099
|
+
const startLine = readIntToolInput(event, "start_line") ?? readIntToolInput(event, "startLine") ?? readIntToolInput(event, "start");
|
|
20100
|
+
const endLine = readIntToolInput(event, "end_line") ?? readIntToolInput(event, "endLine") ?? readIntToolInput(event, "end");
|
|
20101
|
+
if (startLine !== void 0 || endLine !== void 0) {
|
|
20102
|
+
const effectiveStart = startLine !== void 0 && startLine >= 1 ? Math.floor(startLine) : 1;
|
|
20103
|
+
const effectiveLimit = endLine !== void 0 && endLine >= effectiveStart ? Math.floor(endLine - effectiveStart + 1) : void 0;
|
|
20104
|
+
return { offset: effectiveStart, limit: effectiveLimit, isExplicitSlice: true };
|
|
20105
|
+
}
|
|
20106
|
+
return { isExplicitSlice: false };
|
|
20107
|
+
}
|
|
19944
20108
|
function readStartLine(event) {
|
|
19945
20109
|
const resp = event.raw["tool_response"];
|
|
19946
20110
|
if (resp === null || typeof resp !== "object") return 1;
|
|
@@ -20004,11 +20168,10 @@ function scanRequestedSlice(absPath, offset, limit) {
|
|
|
20004
20168
|
}
|
|
20005
20169
|
}
|
|
20006
20170
|
function estimateRequestedSlice(event, absPath) {
|
|
20007
|
-
const
|
|
20008
|
-
|
|
20009
|
-
|
|
20010
|
-
const
|
|
20011
|
-
const scan = scanRequestedSlice(absPath, effectiveOffset, limit);
|
|
20171
|
+
const window2 = readRequestedSliceWindow(event);
|
|
20172
|
+
if (window2.limit === void 0 || window2.limit <= 0) return { kind: "unbounded" };
|
|
20173
|
+
const effectiveOffset = window2.offset !== void 0 && window2.offset >= 1 ? window2.offset : 1;
|
|
20174
|
+
const scan = scanRequestedSlice(absPath, effectiveOffset, window2.limit);
|
|
20012
20175
|
if (scan === null) return { kind: "unbounded" };
|
|
20013
20176
|
if (scan.nearSingleLine) return { kind: "nearSingleLine" };
|
|
20014
20177
|
if (scan.trustworthy) return { kind: "bytes", bytes: scan.bytes };
|
|
@@ -20032,7 +20195,7 @@ function isSourceExtension(basename12) {
|
|
|
20032
20195
|
return language === "apex" || language === "salesforce_metadata" || language === "salesforce_markup";
|
|
20033
20196
|
}
|
|
20034
20197
|
var BINARY_FILE_TYPE_EXTS = /* @__PURE__ */ new Set(["pdf", "docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"]);
|
|
20035
|
-
var TEXT_FILE_TYPE_EXTS = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv", "vtt", "srt"]);
|
|
20198
|
+
var TEXT_FILE_TYPE_EXTS = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv", "vtt", "srt", "svg", "xml"]);
|
|
20036
20199
|
var DISPATCHED_FILE_TYPE_EXTS = /* @__PURE__ */ new Set([...BINARY_FILE_TYPE_EXTS, ...TEXT_FILE_TYPE_EXTS]);
|
|
20037
20200
|
function isDispatchedFileType(basename12) {
|
|
20038
20201
|
return DISPATCHED_FILE_TYPE_EXTS.has(path21.extname(basename12).slice(1).toLowerCase());
|
|
@@ -20051,7 +20214,7 @@ function surgicalHint(filePath, basename12, lineCount) {
|
|
|
20051
20214
|
}
|
|
20052
20215
|
function detectSkillFile(filePath) {
|
|
20053
20216
|
const match = filePath.match(/\.claude[\\/]skills[\\/]([^\\/]+)[\\/]SKILL\.md$/i);
|
|
20054
|
-
return match ? match[1] : null;
|
|
20217
|
+
return match ? displaySafePath(match[1]) : null;
|
|
20055
20218
|
}
|
|
20056
20219
|
function buildLineDiffDetailed(oldContent, newContent, label) {
|
|
20057
20220
|
const oldLines = oldContent.split("\n");
|
|
@@ -20196,7 +20359,7 @@ function preReadHandlerInner(event) {
|
|
|
20196
20359
|
} catch {
|
|
20197
20360
|
}
|
|
20198
20361
|
}
|
|
20199
|
-
const basename12 = path21.basename(normalized);
|
|
20362
|
+
const basename12 = displaySafePath(path21.basename(normalized));
|
|
20200
20363
|
if (isLockFile(basename12)) {
|
|
20201
20364
|
return denyOutput(
|
|
20202
20365
|
'Lock files are rarely useful to read in full. Use `token-goat section "' + shown + '::<section>"` to extract a specific dependency, or read the relevant manifest instead.'
|
|
@@ -20248,7 +20411,7 @@ function preReadHandlerInner(event) {
|
|
|
20248
20411
|
} catch {
|
|
20249
20412
|
}
|
|
20250
20413
|
}
|
|
20251
|
-
const compactUnrangedRead =
|
|
20414
|
+
const compactUnrangedRead = !readRequestedSliceWindow(event).isExplicitSlice;
|
|
20252
20415
|
if (event.toolName !== "Grep" && compactUnrangedRead && loadConfig().hints.stable_doc_compacts && _isDocFile(normalized)) {
|
|
20253
20416
|
const compactPath = compactPathFor(normalized);
|
|
20254
20417
|
if (isCompactFresh(compactPath, normalized)) {
|
|
@@ -20257,7 +20420,7 @@ function preReadHandlerInner(event) {
|
|
|
20257
20420
|
recordActualRead(event, normalized);
|
|
20258
20421
|
const fullSize = statSize(normalized) ?? 0;
|
|
20259
20422
|
const savedBytes = counterfactualCredit(fullSize, compactBody.length);
|
|
20260
|
-
recordStat("session_hint", savedBytes, savedTokensFromBytes(savedBytes));
|
|
20423
|
+
recordStat("session_hint", savedBytes, savedTokensFromBytes(savedBytes), void 0, "stable-doc-compact");
|
|
20261
20424
|
return denyOutput(
|
|
20262
20425
|
"Serving the extractive compact sidecar in place of the full file (source unchanged since the last `compact-doc` build):\n\n" + fenceUntrustedFileContent(compactBody) + '\n\nThis is a lossy extract, not the whole file: front matter and any prose before the first heading are dropped entirely, each section is cut to its opening sentences, and long code fences are truncated. If you need content it left out, re-read with offset/limit for a line window, or `token-goat section "' + shown + '::Heading"` for one section in full. Use `token-goat compact-doc "' + shown + '" --force` to rebuild it, or `token-goat compact-doc "' + shown + '" --show` to view it directly. ' + editAnywayHint(normalized)
|
|
20263
20426
|
);
|
|
@@ -20274,7 +20437,7 @@ function preReadHandlerInner(event) {
|
|
|
20274
20437
|
if (savedBytes >= NB_STRIP_MIN_SAVINGS) {
|
|
20275
20438
|
recordActualRead(event, normalized);
|
|
20276
20439
|
const nbCredit = counterfactualCredit(rawBytes.length, sidecarContent.length);
|
|
20277
|
-
recordStat("session_hint", nbCredit, savedTokensFromBytes(nbCredit));
|
|
20440
|
+
recordStat("session_hint", nbCredit, savedTokensFromBytes(nbCredit), void 0, "notebook-strip");
|
|
20278
20441
|
return denyOutput(
|
|
20279
20442
|
"Serving the output-stripped notebook in place of the full file (code-cell outputs and execution counts removed; source and metadata preserved):\n\n" + fenceUntrustedFileContent(sidecarContent) + "\n\n" + editAnywayHint(normalized)
|
|
20280
20443
|
);
|
|
@@ -20331,7 +20494,7 @@ function preReadHandlerInner(event) {
|
|
|
20331
20494
|
}
|
|
20332
20495
|
return denyOutput(message);
|
|
20333
20496
|
}
|
|
20334
|
-
const unrangedRead =
|
|
20497
|
+
const unrangedRead = !readRequestedSliceWindow(event).isExplicitSlice;
|
|
20335
20498
|
if (loadConfig().hints.subagent_markdown_first_read_deny && event.agentId !== void 0 && unrangedRead && SUBAGENT_MD_FIRST_READ_DENY_EXT_RE.test(basename12) && markdownSize !== null && markdownSize >= SUBAGENT_MD_FIRST_READ_DENY_BYTES) {
|
|
20336
20499
|
recordStat("subagent_markdown_first_read_deny", 0, 0);
|
|
20337
20500
|
return denyOutput(
|
|
@@ -20402,7 +20565,7 @@ function preReadHandlerInner(event) {
|
|
|
20402
20565
|
if (snapDiff.kind === "diff") {
|
|
20403
20566
|
recordActualRead(event, normalized);
|
|
20404
20567
|
const artifactDiffCredit = counterfactualCredit(snapDiff.currentContent.length, snapDiff.diff.length);
|
|
20405
|
-
recordStat("session_hint", artifactDiffCredit, savedTokensFromBytes(artifactDiffCredit));
|
|
20568
|
+
recordStat("session_hint", artifactDiffCredit, savedTokensFromBytes(artifactDiffCredit), void 0, "artifact-snapshot-diff");
|
|
20406
20569
|
return denyOutput(
|
|
20407
20570
|
"Content changed since last read of " + basename12 + ". Here is what changed:\n\n" + fenceUntrustedFileContent("```diff\n" + snapDiff.diff + "\n```") + "\n\n" + sessionArtifactRecall(normalized)
|
|
20408
20571
|
);
|
|
@@ -20420,7 +20583,7 @@ function preReadHandlerInner(event) {
|
|
|
20420
20583
|
recordActualRead(event, normalized);
|
|
20421
20584
|
if (outputSize !== null && outputSize >= TASK_OUTPUT_DENY_BYTES) {
|
|
20422
20585
|
const artifactDenyCredit = counterfactualCredit(outputSize);
|
|
20423
|
-
recordStat("session_hint", artifactDenyCredit, savedTokensFromBytes(artifactDenyCredit));
|
|
20586
|
+
recordStat("session_hint", artifactDenyCredit, savedTokensFromBytes(artifactDenyCredit), void 0, "artifact-large-deny");
|
|
20424
20587
|
return denyOutput(
|
|
20425
20588
|
label + " is large (" + toKB(outputSize) + "KB). " + sessionArtifactRecall(normalized)
|
|
20426
20589
|
);
|
|
@@ -20509,12 +20672,12 @@ function preReadHandlerInner(event) {
|
|
|
20509
20672
|
if (config2.hints.reread_deny && !protectedRead) {
|
|
20510
20673
|
if (wasFileTruncatedThisSession(normalized)) {
|
|
20511
20674
|
if (estimateTruncatedLineCount(normalized) >= config2.hints.truncated_read_min_lines) {
|
|
20512
|
-
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit));
|
|
20675
|
+
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit), void 0, "reread-truncated-deny");
|
|
20513
20676
|
return denyOutput(truncatedReadDenyMessage(normalized));
|
|
20514
20677
|
}
|
|
20515
20678
|
}
|
|
20516
20679
|
if (/\.(md|mdx|markdown|rst)$/i.test(basename12)) {
|
|
20517
|
-
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit));
|
|
20680
|
+
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit), void 0, "reread-doc-deny");
|
|
20518
20681
|
return denyOutput(
|
|
20519
20682
|
'Markdown file already read this session. Use `token-goat section "' + shown + '::HeadingName"` to read one section.'
|
|
20520
20683
|
);
|
|
@@ -20530,7 +20693,7 @@ function preReadHandlerInner(event) {
|
|
|
20530
20693
|
}
|
|
20531
20694
|
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + shown + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
20532
20695
|
if (config2.hints.reread_deny && !protectedRead && (rereadBytes >= config2.hints.reread_deny_min_bytes || reads >= 2)) {
|
|
20533
|
-
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit));
|
|
20696
|
+
recordStat("session_hint", rereadCredit, savedTokensFromBytes(rereadCredit), void 0, "reread-count-deny");
|
|
20534
20697
|
return denyOutput(
|
|
20535
20698
|
shown + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
20536
20699
|
);
|
|
@@ -20555,7 +20718,7 @@ function preReadHandlerInner(event) {
|
|
|
20555
20718
|
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + shown + '::SectionName"` to read one section.' : "Consider token-goat skeleton or token-goat section.";
|
|
20556
20719
|
if (gateSize >= largeFileDenyBytes()) {
|
|
20557
20720
|
const denyCredit = counterfactualCredit(size);
|
|
20558
|
-
recordStat("session_hint", denyCredit, savedTokensFromBytes(denyCredit));
|
|
20721
|
+
recordStat("session_hint", denyCredit, savedTokensFromBytes(denyCredit), void 0, "large-file-deny");
|
|
20559
20722
|
return denyOutput(
|
|
20560
20723
|
shown + " is very large (" + kb + "KB). " + hint + " " + describeSliceAdvice(slice, normalized) + " " + editAnywayHint(normalized)
|
|
20561
20724
|
);
|
|
@@ -20701,9 +20864,9 @@ function readWindowFromDisk(event, normalized) {
|
|
|
20701
20864
|
const size = statSize(normalized);
|
|
20702
20865
|
if (size === null || size > SLICE_ESTIMATE_SCAN_CAP_BYTES) return null;
|
|
20703
20866
|
const text = decodeSource(fs21.readFileSync(normalized));
|
|
20704
|
-
const
|
|
20705
|
-
const
|
|
20706
|
-
const
|
|
20867
|
+
const window2 = readRequestedSliceWindow(event);
|
|
20868
|
+
const start = window2.offset !== void 0 && window2.offset >= 1 ? window2.offset : 1;
|
|
20869
|
+
const limit = window2.limit;
|
|
20707
20870
|
if (start === 1 && (limit === void 0 || limit <= 0)) return text;
|
|
20708
20871
|
const lines2 = text.split("\n");
|
|
20709
20872
|
const from = start - 1;
|
|
@@ -20826,7 +20989,7 @@ function elideAlreadyServedLines(event, respText) {
|
|
|
20826
20989
|
function structuralFoldInputs(event, respText) {
|
|
20827
20990
|
const filePath = getFilePath(event);
|
|
20828
20991
|
if (filePath === void 0) return null;
|
|
20829
|
-
if (
|
|
20992
|
+
if (readRequestedSliceWindow(event).isExplicitSlice) return null;
|
|
20830
20993
|
if (isTruncatedReadDelivery(event, respText)) return null;
|
|
20831
20994
|
if (redactSecrets(respText).count > 0) return null;
|
|
20832
20995
|
const parsed = parseNumberedReadResult(respText, readStartLine(event));
|
|
@@ -20861,14 +21024,15 @@ function foldCodeBodies(event, respText) {
|
|
|
20861
21024
|
if (filePath === void 0) return null;
|
|
20862
21025
|
const normalized = normalizePath(filePath);
|
|
20863
21026
|
if (isImagePath(normalized)) return null;
|
|
20864
|
-
const
|
|
21027
|
+
const sliceWin = readRequestedSliceWindow(event);
|
|
21028
|
+
const requestedOffset = sliceWin.offset;
|
|
20865
21029
|
if (requestedOffset !== void 0 && readStartLine(event) !== requestedOffset) return null;
|
|
20866
21030
|
if (isTruncatedReadDelivery(event, respText)) return null;
|
|
20867
21031
|
if (redactSecrets(respText).count > 0) return null;
|
|
20868
21032
|
const parsed = parseNumberedReadResult(respText, readStartLine(event));
|
|
20869
21033
|
if (parsed === null) return null;
|
|
20870
21034
|
const shown = displaySafePath(toDisplayPath(findProject(getCwd(event) ?? process.cwd())?.root, normalized));
|
|
20871
|
-
const folded = foldDelivery(parsed.rows, normalized, shown,
|
|
21035
|
+
const folded = foldDelivery(parsed.rows, normalized, shown, sliceWin.isExplicitSlice);
|
|
20872
21036
|
if (folded === null) return null;
|
|
20873
21037
|
const rewritten = [...parsed.header, fenceUntrustedFileContent(folded.numbered.join("\n")), ...parsed.trailer].join("\n");
|
|
20874
21038
|
const originalBytes = Buffer.byteLength(respText, "utf-8");
|
|
@@ -21991,6 +22155,7 @@ export {
|
|
|
21991
22155
|
clearCurlDownload,
|
|
21992
22156
|
recordFileLineRange,
|
|
21993
22157
|
getFileLineRanges,
|
|
22158
|
+
GENERIC_SERVED_OUTPUT_KEY,
|
|
21994
22159
|
recordFileServedOutput,
|
|
21995
22160
|
getFileServedOutputs,
|
|
21996
22161
|
markFileTruncated,
|
|
@@ -22099,6 +22264,9 @@ export {
|
|
|
22099
22264
|
PARSER_FINGERPRINT,
|
|
22100
22265
|
stripLeadingAttributes2 as stripLeadingAttributes,
|
|
22101
22266
|
IMPORT_RE2 as IMPORT_RE,
|
|
22267
|
+
treeSitterCoreAvailable,
|
|
22268
|
+
treeSitterCoreLoadError,
|
|
22269
|
+
isTreeSitterAvailable,
|
|
22102
22270
|
yamlOpenQuoteAfter,
|
|
22103
22271
|
yamlLineClosesQuote,
|
|
22104
22272
|
lineOpenDelimiterAfter,
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
expandGlobs,
|
|
8
8
|
leftoverIntegrations,
|
|
9
9
|
run
|
|
10
|
-
} from "./token-goat-chunk-
|
|
11
|
-
import "./token-goat-chunk-
|
|
12
|
-
import "./token-goat-chunk-
|
|
13
|
-
import "./token-goat-chunk-
|
|
14
|
-
import "./token-goat-chunk-
|
|
10
|
+
} from "./token-goat-chunk-PNMGVJ4C.mjs";
|
|
11
|
+
import "./token-goat-chunk-L6Q2XM5X.mjs";
|
|
12
|
+
import "./token-goat-chunk-QCHD2ENV.mjs";
|
|
13
|
+
import "./token-goat-chunk-BYDDWQ2T.mjs";
|
|
14
|
+
import "./token-goat-chunk-KIEOFWLL.mjs";
|
|
15
15
|
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
16
16
|
import "./token-goat-chunk-A37V4PBF.mjs";
|
|
17
17
|
export {
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
buildEvent,
|
|
5
5
|
relay,
|
|
6
6
|
relayInProcess
|
|
7
|
-
} from "./token-goat-chunk-
|
|
7
|
+
} from "./token-goat-chunk-P5SQX2VK.mjs";
|
|
8
8
|
import {
|
|
9
9
|
MAX_STDIN_BYTES,
|
|
10
10
|
readStdinJson
|
|
11
|
-
} from "./token-goat-chunk-
|
|
12
|
-
import "./token-goat-chunk-
|
|
13
|
-
import "./token-goat-chunk-
|
|
14
|
-
import "./token-goat-chunk-
|
|
11
|
+
} from "./token-goat-chunk-QCHD2ENV.mjs";
|
|
12
|
+
import "./token-goat-chunk-BYDDWQ2T.mjs";
|
|
13
|
+
import "./token-goat-chunk-OBDTBOQA.mjs";
|
|
14
|
+
import "./token-goat-chunk-KIEOFWLL.mjs";
|
|
15
15
|
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
16
16
|
import "./token-goat-chunk-A37V4PBF.mjs";
|
|
17
17
|
export {
|