token-goat 2.6.34 → 2.6.36
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 +4 -2
- package/SECURITY.md +14 -11
- package/dist/{token-goat-chunk-L7QLEVO7.mjs → token-goat-chunk-65BKISIS.mjs} +16 -14
- package/dist/{token-goat-chunk-I6EQH27G.mjs → token-goat-chunk-CNDOJ3ZP.mjs} +2 -2
- package/dist/{token-goat-chunk-FRMEOIRU.mjs → token-goat-chunk-FRTBMRP7.mjs} +208 -13
- package/dist/{token-goat-chunk-IYYQOPY4.mjs → token-goat-chunk-IYTVE6KN.mjs} +29 -10
- package/dist/{token-goat-chunk-GXBPEQR2.mjs → token-goat-chunk-KYFJC37X.mjs} +21 -14
- package/dist/{token-goat-chunk-CKRATWCJ.mjs → token-goat-chunk-LN6OUHTV.mjs} +5 -5
- package/dist/{token-goat-chunk-WA2ER6TZ.mjs → token-goat-chunk-MGOUYAA2.mjs} +1 -1
- package/dist/{token-goat-chunk-CN7GUPX6.mjs → token-goat-chunk-UFOVM7ZN.mjs} +461 -97
- package/dist/{token-goat-chunk-7FWBSPCT.mjs → token-goat-chunk-V465YKOR.mjs} +198 -21
- package/dist/{token-goat-chunk-OA3GFKP2.mjs → token-goat-chunk-VYMGEVZS.mjs} +16 -4
- package/dist/{token-goat-hook-chunk-2ISZ4AZR.mjs → token-goat-hook-chunk-3ZDBWJDF.mjs} +1 -1
- package/dist/{token-goat-hook-chunk-6C5RN3CM.mjs → token-goat-hook-chunk-5UH54CW6.mjs} +16 -4
- package/dist/{token-goat-hook-chunk-OQML5EMA.mjs → token-goat-hook-chunk-6ODM3MP7.mjs} +16 -14
- package/dist/{token-goat-hook-chunk-6QTWMSRO.mjs → token-goat-hook-chunk-A77A26A7.mjs} +461 -97
- package/dist/{token-goat-hook-chunk-BU5OFDGQ.mjs → token-goat-hook-chunk-BDR6C6IE.mjs} +208 -13
- package/dist/{token-goat-hook-chunk-I5VM5PO5.mjs → token-goat-hook-chunk-C6GIABOX.mjs} +21 -14
- package/dist/{token-goat-hook-chunk-QTZ6YUMQ.mjs → token-goat-hook-chunk-E257IGSN.mjs} +2 -2
- package/dist/{token-goat-hook-chunk-KGLMNOGD.mjs → token-goat-hook-chunk-MW5HPEGD.mjs} +29 -10
- package/dist/{token-goat-hook-chunk-ATEGFQAU.mjs → token-goat-hook-chunk-QSCYNJ2B.mjs} +5 -5
- package/dist/{token-goat-hook-chunk-CNLMPHXT.mjs → token-goat-hook-chunk-Y2WHX2P3.mjs} +198 -21
- package/dist/token-goat-hook.mjs +5 -5
- package/dist/token-goat.core.mjs +5 -5
- package/package.json +13 -11
- package/scripts/install-git-hooks.mjs +55 -0
package/README.md
CHANGED
|
@@ -349,8 +349,10 @@ For archive/document work specifically, token-goat's bounded SQLite, XLSX, and P
|
|
|
349
349
|
brew install ast-grep uv ruff ripgrep fd bat eza git-delta jq yq sd miller sqlite gh hyperfine fzf lazygit
|
|
350
350
|
|
|
351
351
|
# Debian / Ubuntu — note the binary renames: rg=ripgrep, fd=fdfind, bat=batcat
|
|
352
|
-
sudo apt install -y ripgrep fd-find bat jq sqlite3 fzf
|
|
353
|
-
|
|
352
|
+
sudo apt install -y ripgrep fd-find bat jq sqlite3 fzf pipx
|
|
353
|
+
pipx install uv && pipx ensurepath # pipx puts uv in ~/.local/bin
|
|
354
|
+
export PATH="$HOME/.local/bin:$PATH" # this shell; ensurepath covers later ones
|
|
355
|
+
uv tool install ruff
|
|
354
356
|
npm install -g @ast-grep/cli
|
|
355
357
|
```
|
|
356
358
|
|
package/SECURITY.md
CHANGED
|
@@ -46,7 +46,7 @@ The following are not treated as security issues unless paired with a working pr
|
|
|
46
46
|
| What you scan | Command | Result |
|
|
47
47
|
| --- | --- | --- |
|
|
48
48
|
| this repository | `npm audit` | clean, development dependencies included |
|
|
49
|
-
| an install without optional packages | `npm install --omit=optional token-goat` then `npm audit --omit=dev --omit=optional` | clean,
|
|
49
|
+
| an install without optional packages | `npm install --omit=optional token-goat` then `npm audit --omit=dev --omit=optional` | clean, 40 packages |
|
|
50
50
|
| a default install | `npm install token-goat` then `npm audit --omit=dev` | the optional packages in the table below |
|
|
51
51
|
|
|
52
52
|
The repository is clean because [`package.json`](package.json) carries an `overrides` block that pins five transitive packages to patched versions. **npm applies `overrides` only in the root project**, so those pins do not travel to anyone who installs Token-Goat as a dependency. We are saying so plainly rather than letting a clean repository scan stand in for a clean install: if your scanner reads this repository or its lockfile it will report nothing, and that is not the whole picture.
|
|
@@ -56,12 +56,15 @@ Without the overrides a consumer resolves `protobufjs` at 6.x, which carries mor
|
|
|
56
56
|
| Package | Advisories it carries | Where it loads | Why the advisory does not reach you through Token-Goat |
|
|
57
57
|
| --- | --- | --- | --- |
|
|
58
58
|
| `@xenova/transformers` | [`protobufjs`](https://github.com/advisories/GHSA-xq3m-2v4x-88gg) (critical), `onnx-proto`, `onnxruntime-web`, and its own pinned `sharp` | optional; loaded only when semantic search builds or queries embeddings | not mitigated, so it is the one to weigh. Skip it with `npm install --omit=optional`, or leave `indexing.embeddings_enabled` off, and the code never loads |
|
|
59
|
-
| `exceljs` | [`uuid`](https://github.com/advisories/GHSA-w5hq-g745-h8pq) | optional; loaded only when an `xlsx-*` command opens a workbook | the advisory is a missing bounds check on a caller-supplied `buf` argument; ExcelJS never passes one |
|
|
60
59
|
|
|
61
|
-
`npm install --omit=optional` gives you an install without
|
|
60
|
+
`npm install --omit=optional` gives you an install without it, and `npm audit` reports it clean. Every command still starts; the ones that need a package you skipped say so. The `xlsx-*`, `docx-*` and `pptx-*` commands report that fflate is not installed rather than failing oddly, `zip-list`/`zip-read` do the same, and `semantic` keeps working on keyword search alone: it is the embedding half that goes away, not the command.
|
|
61
|
+
|
|
62
|
+
`exceljs` used to appear in that table, carrying [`uuid`](https://github.com/advisories/GHSA-w5hq-g745-h8pq). It is now a development dependency instead. The `xlsx-*` commands read the workbook container directly with `fflate` and `fast-xml-parser`, the same two packages the `.docx` and `.pptx` readers already used, so `exceljs` is only a test fixture writer now. That removes 55 packages from a default install, including every deprecated one in the tree.
|
|
62
63
|
|
|
63
64
|
`html-to-text` used to appear in that table, carrying [`deepmerge-ts`](https://github.com/advisories/GHSA-ggr8-5vv4-36mx). It is now a development dependency instead. esbuild inlines it into `dist/token-goat.mjs` at build time and nothing in the published bundle imports it, so it was a runtime dependency in name only: moving it removes `html-to-text`, `deepmerge-ts`, `htmlparser2`, `selderee`, and `dom-serializer` from an installed copy while the HTML-to-text output stays byte-for-byte identical. That is what takes the no-optional install to zero, and it is better than the alternative we had considered, rolling `html-to-text` back to 9.x: that version pins `htmlparser2` two majors lower, and `htmlparser2` is what parses fetched pages, so it would have traded an advisory in an options merger for an older parser on the one path that handles untrusted input.
|
|
64
65
|
|
|
66
|
+
Five more packages were in `dependencies` for the same reason and have moved the same way: `commander`, `csv-parse`, `js-yaml`, `smol-toml` and `zod`. esbuild inlines each one into the bundle, and the published bundle resolves none of them, so a consumer was downloading code the artifact already carried. Moving them takes an install without optional packages from 46 packages to 40. `better-sqlite3` and `jsonc-parser` stay, because the bundle really does load them at run time: the first is a native addon, and the second is reached through `createRequire` rather than an import esbuild can inline. `zod` is the largest of the five on disk and the one that saves least in practice, because `@modelcontextprotocol/sdk` and `puppeteer-core` both depend on it and a default install still gets it from them.
|
|
67
|
+
|
|
65
68
|
Direct dependencies with a forward patch are kept current rather than pinned: `sharp` and `puppeteer-core` were both moved across a major version to clear their advisories.
|
|
66
69
|
|
|
67
70
|
For a scanner that ingests a bill of materials rather than a lockfile, `npm run sbom` writes CycloneDX 1.5 to stdout.
|
|
@@ -89,8 +92,8 @@ Token-Goat is source-available under the PolyForm Noncommercial License 1.0.0. S
|
|
|
89
92
|
|
|
90
93
|
Every production dependency is permissively licensed, but a scan does not read it that way on its
|
|
91
94
|
own. Counted from `package-lock.json`, which lists the packages for every platform rather than only
|
|
92
|
-
the ones this machine installed,
|
|
93
|
-
cannot resolve, and
|
|
95
|
+
the ones this machine installed, 21 entries need a human answer: 7 declare a license a scanner
|
|
96
|
+
cannot resolve, and 14 carry a copyleft term. All 21 arrive through optional dependencies. Install
|
|
94
97
|
with `npm install --omit=optional token-goat` and not one of them is present.
|
|
95
98
|
|
|
96
99
|
**Declarations a scanner cannot resolve.** Both are upstream mistakes, and both are the same
|
|
@@ -110,19 +113,19 @@ an unresolvable one.
|
|
|
110
113
|
| --- | --- | --- |
|
|
111
114
|
| `@img/sharp-libvips-<platform>` (10 packages) | `LGPL-3.0-or-later` | libvips, shipped as a prebuilt shared library and used unmodified. LGPL asks that the library stay replaceable, and it is: it is a separate package that `sharp` loads at runtime. |
|
|
112
115
|
| `@img/sharp-<platform>` (4 packages) | `Apache-2.0 AND LGPL-3.0-or-later` | the Apache half is `sharp` itself, the LGPL half is the same libvips |
|
|
113
|
-
| `jszip` | `(MIT OR GPL-3.0-or-later)` | a choice between the two, and the MIT half is taken |
|
|
114
116
|
|
|
115
|
-
`sharp`
|
|
116
|
-
`exceljs
|
|
117
|
+
`sharp` is optional: it powers image shrinking. `jszip` used to be listed here too; it arrived
|
|
118
|
+
through `exceljs`, which is no longer a dependency a consumer installs.
|
|
117
119
|
|
|
118
120
|
**Three packages with no license at all used to be here.** `buffers@0.1.1` and `chainsaw@0.1.0`
|
|
119
121
|
shipped with neither a `license` field nor a license file, and `traverse@0.3.9` had the file but
|
|
120
122
|
not the field. No grant at all is worse for a review than a copyleft grant, because there is
|
|
121
123
|
nothing to apply policy to. They arrived through `exceljs`, which depends on `unzipper`, which
|
|
122
124
|
depended on `binary`, which depended on all three. `unzipper` dropped `binary` in 0.11, so an
|
|
123
|
-
override to `^0.12.5` removes the sub-chain, and the deprecated `fstream` with it.
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
override to `^0.12.5` removes the sub-chain, and the deprecated `fstream` with it. `exceljs` is now
|
|
126
|
+
a development dependency, so none of that chain reaches an installed copy either way; the override
|
|
127
|
+
stays because it is what keeps this repository's own `npm audit`, which includes development
|
|
128
|
+
dependencies, clean.
|
|
126
129
|
|
|
127
130
|
Reproduce the whole picture:
|
|
128
131
|
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
runSkeleton,
|
|
26
26
|
runSymbol,
|
|
27
27
|
withPinnedReads
|
|
28
|
-
} from "./token-goat-chunk-
|
|
28
|
+
} from "./token-goat-chunk-IYTVE6KN.mjs";
|
|
29
29
|
import {
|
|
30
30
|
buildProjectMap,
|
|
31
31
|
embeddingsDepsAvailable,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
getProjectIndexCounts,
|
|
35
35
|
isWorkerRunning,
|
|
36
36
|
mapLookupBytesSaved
|
|
37
|
-
} from "./token-goat-chunk-
|
|
37
|
+
} from "./token-goat-chunk-UFOVM7ZN.mjs";
|
|
38
38
|
import {
|
|
39
39
|
VERSION,
|
|
40
40
|
dataDir,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
normalizePath,
|
|
46
46
|
recordStat,
|
|
47
47
|
resolveProjectRoot
|
|
48
|
-
} from "./token-goat-chunk-
|
|
48
|
+
} from "./token-goat-chunk-V465YKOR.mjs";
|
|
49
49
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
50
50
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
51
51
|
|
|
@@ -126,7 +126,19 @@ function forCompare(p) {
|
|
|
126
126
|
return process.platform === "win32" ? p.toLowerCase() : p;
|
|
127
127
|
}
|
|
128
128
|
function resolveToolRoot(projectRoot) {
|
|
129
|
-
|
|
129
|
+
const resolved = resolveProjectRoot(projectRoot !== void 0 ? { project: projectRoot } : {});
|
|
130
|
+
assertRootAllowed(resolved);
|
|
131
|
+
return resolved;
|
|
132
|
+
}
|
|
133
|
+
var RootNotAllowedError = class extends Error {
|
|
134
|
+
};
|
|
135
|
+
function assertRootAllowed(resolvedRoot) {
|
|
136
|
+
const allowedRoots = loadConfig().mcp.allowed_roots;
|
|
137
|
+
if (allowedRoots.length === 0) return;
|
|
138
|
+
if (allowedRoots.some((allowed) => checkWithinProjectRoot(resolvedRoot, allowed).inside)) return;
|
|
139
|
+
throw new RootNotAllowedError(
|
|
140
|
+
`refused: "${resolvedRoot}" is not inside any root listed in mcp.allowed_roots. A caller-supplied projectRoot is untrusted input, so this deployment pins which roots may be named; add the root to mcp.allowed_roots (or TOKEN_GOAT_MCP_ALLOWED_ROOTS) to permit it.`
|
|
141
|
+
);
|
|
130
142
|
}
|
|
131
143
|
function checkWithinProjectRoot(target, resolvedRoot) {
|
|
132
144
|
const root = forCompare(normalizePath(realPathOrSelf(resolvedRoot)));
|
|
@@ -150,16 +162,6 @@ function specFilePart(spec) {
|
|
|
150
162
|
var NO_PINS = /* @__PURE__ */ new Map();
|
|
151
163
|
function confineTargets(targets, resolvedRoot, splitCommas = true) {
|
|
152
164
|
if (!loadConfig(resolvedRoot).mcp.confine_reads_to_project_root) return { ok: true, targets, pins: NO_PINS };
|
|
153
|
-
const allowedRoots = loadConfig().mcp.allowed_roots;
|
|
154
|
-
if (allowedRoots.length > 0 && !allowedRoots.some((allowed) => checkWithinProjectRoot(resolvedRoot, allowed).inside)) {
|
|
155
|
-
return {
|
|
156
|
-
ok: false,
|
|
157
|
-
refusal: toCallToolResult({
|
|
158
|
-
text: `refused: "${resolvedRoot}" is not inside any root listed in mcp.allowed_roots. A caller-supplied projectRoot is untrusted input, so this deployment pins which roots may be named; add the root to mcp.allowed_roots (or TOKEN_GOAT_MCP_ALLOWED_ROOTS) to permit it.`,
|
|
159
|
-
code: 1
|
|
160
|
-
})
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
165
|
const checked = [];
|
|
164
166
|
const pins = /* @__PURE__ */ new Map();
|
|
165
167
|
for (const raw of targets) {
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
selectFilter,
|
|
11
11
|
shlexSplit,
|
|
12
12
|
wrappedShell
|
|
13
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-MGOUYAA2.mjs";
|
|
14
14
|
import {
|
|
15
15
|
loadConfig,
|
|
16
16
|
recordStat
|
|
17
|
-
} from "./token-goat-chunk-
|
|
17
|
+
} from "./token-goat-chunk-V465YKOR.mjs";
|
|
18
18
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
19
19
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
20
20
|
|
|
@@ -2,13 +2,15 @@ import { createRequire as __cjsRequire } from 'node:module';
|
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
canRunWrappedShell,
|
|
5
|
+
compressOutput,
|
|
5
6
|
dedupeConsecutive,
|
|
6
7
|
detectFromCommand,
|
|
8
|
+
filterByName,
|
|
7
9
|
hasBareBackgroundOrNewline,
|
|
8
10
|
isRewriteWorthwhile,
|
|
9
11
|
resolveMinNetSavingsBytes,
|
|
10
12
|
shlexSplit
|
|
11
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-MGOUYAA2.mjs";
|
|
12
14
|
import {
|
|
13
15
|
BASH_OUTPUT_SUBDIR,
|
|
14
16
|
HOOK_EVENTS,
|
|
@@ -27,7 +29,7 @@ import {
|
|
|
27
29
|
storeBashOutput,
|
|
28
30
|
storeWebOutput,
|
|
29
31
|
summarizeOutputDelta
|
|
30
|
-
} from "./token-goat-chunk-
|
|
32
|
+
} from "./token-goat-chunk-VYMGEVZS.mjs";
|
|
31
33
|
import {
|
|
32
34
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
33
35
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
@@ -117,7 +119,7 @@ import {
|
|
|
117
119
|
wasCliReadThisSession,
|
|
118
120
|
wasFileReadThisSession,
|
|
119
121
|
wasHintShown
|
|
120
|
-
} from "./token-goat-chunk-
|
|
122
|
+
} from "./token-goat-chunk-UFOVM7ZN.mjs";
|
|
121
123
|
import {
|
|
122
124
|
VERSION,
|
|
123
125
|
detectHarness,
|
|
@@ -136,7 +138,7 @@ import {
|
|
|
136
138
|
runGit,
|
|
137
139
|
shortFingerprint,
|
|
138
140
|
toKB
|
|
139
|
-
} from "./token-goat-chunk-
|
|
141
|
+
} from "./token-goat-chunk-V465YKOR.mjs";
|
|
140
142
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
141
143
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
142
144
|
|
|
@@ -576,7 +578,7 @@ import crypto from "node:crypto";
|
|
|
576
578
|
var TRACKED_SKILL = "token-goat";
|
|
577
579
|
var MAX_COMMANDS_SHOWN = 8;
|
|
578
580
|
async function currentCommandNames() {
|
|
579
|
-
const { buildProgram } = await import("./token-goat-chunk-
|
|
581
|
+
const { buildProgram } = await import("./token-goat-chunk-LN6OUHTV.mjs");
|
|
580
582
|
return flattenCommandNames(buildCommandManifest(buildProgram()));
|
|
581
583
|
}
|
|
582
584
|
async function recordSkillVersionSnapshot(sessionId, skillName) {
|
|
@@ -7905,12 +7907,151 @@ function extractRgStructuralSearch(cmd) {
|
|
|
7905
7907
|
function extractGrepPipeChain(cmd) {
|
|
7906
7908
|
return /^(?:rg|grep)\b.*\|\s*(?:rg|grep)\b/.test(cmd);
|
|
7907
7909
|
}
|
|
7910
|
+
function splitCommandWords(cmd) {
|
|
7911
|
+
const words = [];
|
|
7912
|
+
let cur = "";
|
|
7913
|
+
let quote = null;
|
|
7914
|
+
let started = false;
|
|
7915
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
7916
|
+
const ch = cmd[i];
|
|
7917
|
+
if (quote !== null) {
|
|
7918
|
+
if (ch === "\\" && quote === '"' && i + 1 < cmd.length) {
|
|
7919
|
+
cur += cmd[i + 1];
|
|
7920
|
+
i++;
|
|
7921
|
+
continue;
|
|
7922
|
+
}
|
|
7923
|
+
if (ch === quote) quote = null;
|
|
7924
|
+
else cur += ch;
|
|
7925
|
+
continue;
|
|
7926
|
+
}
|
|
7927
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
7928
|
+
cur += cmd[i + 1];
|
|
7929
|
+
i++;
|
|
7930
|
+
started = true;
|
|
7931
|
+
continue;
|
|
7932
|
+
}
|
|
7933
|
+
if (ch === '"' || ch === "'") {
|
|
7934
|
+
quote = ch;
|
|
7935
|
+
started = true;
|
|
7936
|
+
continue;
|
|
7937
|
+
}
|
|
7938
|
+
if (/\s/.test(ch)) {
|
|
7939
|
+
if (started) words.push(cur);
|
|
7940
|
+
cur = "";
|
|
7941
|
+
started = false;
|
|
7942
|
+
continue;
|
|
7943
|
+
}
|
|
7944
|
+
cur += ch;
|
|
7945
|
+
started = true;
|
|
7946
|
+
}
|
|
7947
|
+
if (started) words.push(cur);
|
|
7948
|
+
return words;
|
|
7949
|
+
}
|
|
7950
|
+
var CURL_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
7951
|
+
"-H",
|
|
7952
|
+
"--header",
|
|
7953
|
+
"-A",
|
|
7954
|
+
"--user-agent",
|
|
7955
|
+
"-e",
|
|
7956
|
+
"--referer",
|
|
7957
|
+
"-b",
|
|
7958
|
+
"--cookie",
|
|
7959
|
+
"-c",
|
|
7960
|
+
"--cookie-jar",
|
|
7961
|
+
"-o",
|
|
7962
|
+
"--output",
|
|
7963
|
+
"--output-dir",
|
|
7964
|
+
"-u",
|
|
7965
|
+
"--user",
|
|
7966
|
+
"-U",
|
|
7967
|
+
"--proxy-user",
|
|
7968
|
+
"-x",
|
|
7969
|
+
"--proxy",
|
|
7970
|
+
"-X",
|
|
7971
|
+
"--request",
|
|
7972
|
+
"-d",
|
|
7973
|
+
"--data",
|
|
7974
|
+
"--data-raw",
|
|
7975
|
+
"--data-binary",
|
|
7976
|
+
"--data-urlencode",
|
|
7977
|
+
"-F",
|
|
7978
|
+
"--form",
|
|
7979
|
+
"-T",
|
|
7980
|
+
"--upload-file",
|
|
7981
|
+
"-K",
|
|
7982
|
+
"--config",
|
|
7983
|
+
"-w",
|
|
7984
|
+
"--write-out",
|
|
7985
|
+
"-m",
|
|
7986
|
+
"--max-time",
|
|
7987
|
+
"--connect-to",
|
|
7988
|
+
"--resolve",
|
|
7989
|
+
"--retry",
|
|
7990
|
+
"--cacert",
|
|
7991
|
+
"-E",
|
|
7992
|
+
"--cert",
|
|
7993
|
+
"--key",
|
|
7994
|
+
"--range",
|
|
7995
|
+
"-r",
|
|
7996
|
+
"--interface",
|
|
7997
|
+
// Options whose own value is a URL or a host. Leaving these out was the same defect as reading
|
|
7998
|
+
// the first URL in the string: `curl --doh-url https://doh/ -o f https://target` answered with
|
|
7999
|
+
// the DoH resolver rather than the file being fetched. `--url-query` belongs here too -- it
|
|
8000
|
+
// appends query data to the request, it does not name the request target.
|
|
8001
|
+
"--url-query",
|
|
8002
|
+
"--doh-url",
|
|
8003
|
+
"--preproxy",
|
|
8004
|
+
"--proxy1.0",
|
|
8005
|
+
"--socks4",
|
|
8006
|
+
"--socks4a",
|
|
8007
|
+
"--socks5",
|
|
8008
|
+
"--socks5-hostname",
|
|
8009
|
+
"--proxy-header",
|
|
8010
|
+
"--noproxy",
|
|
8011
|
+
"--dns-servers",
|
|
8012
|
+
"--aws-sigv4",
|
|
8013
|
+
"--proxy-cacert",
|
|
8014
|
+
"--proxy-cert",
|
|
8015
|
+
"--proxy-key",
|
|
8016
|
+
"--oauth2-bearer",
|
|
8017
|
+
"--hsts",
|
|
8018
|
+
"--alt-svc",
|
|
8019
|
+
"--etag-save",
|
|
8020
|
+
"--etag-compare",
|
|
8021
|
+
"--trace",
|
|
8022
|
+
"--trace-ascii",
|
|
8023
|
+
"--dump-header",
|
|
8024
|
+
"-D"
|
|
8025
|
+
]);
|
|
7908
8026
|
function extractCurlUrl(cmd) {
|
|
7909
|
-
const
|
|
7910
|
-
|
|
8027
|
+
const words = splitCommandWords(cmd);
|
|
8028
|
+
let positional = null;
|
|
8029
|
+
for (let i = 0; i < words.length; i++) {
|
|
8030
|
+
const w = words[i];
|
|
8031
|
+
if (w === "--url") {
|
|
8032
|
+
const next = words[i + 1];
|
|
8033
|
+
if (next !== void 0 && /^https?:\/\//.test(next)) return next;
|
|
8034
|
+
i++;
|
|
8035
|
+
continue;
|
|
8036
|
+
}
|
|
8037
|
+
const eq = w.indexOf("=");
|
|
8038
|
+
if (w.startsWith("--") && eq > 0) {
|
|
8039
|
+
if (w.slice(0, eq) === "--url" && /^https?:\/\//.test(w.slice(eq + 1))) return w.slice(eq + 1);
|
|
8040
|
+
continue;
|
|
8041
|
+
}
|
|
8042
|
+
if (CURL_VALUE_FLAGS.has(w)) {
|
|
8043
|
+
i++;
|
|
8044
|
+
continue;
|
|
8045
|
+
}
|
|
8046
|
+
if (w.startsWith("-") && w !== "-") continue;
|
|
8047
|
+
if (/^https?:\/\//.test(w)) return w;
|
|
8048
|
+
positional ??= /https?:\/\/[^\s'")}`]+/.exec(w)?.[0] ?? null;
|
|
8049
|
+
}
|
|
8050
|
+
if (positional !== null) return positional;
|
|
8051
|
+
return null;
|
|
7911
8052
|
}
|
|
7912
8053
|
function extractTgSurgicalRead(cmd, cwd) {
|
|
7913
|
-
const m = /^token-goat\s+(symbol|read|section|skill-body|skill-compact|map)(?:\s+(.*))?$/.exec(cmd);
|
|
8054
|
+
const m = /^(?:token-goat|tg)\s+(symbol|read|section|skill-body|skill-compact|map)(?:\s+(.*))?$/.exec(cmd);
|
|
7914
8055
|
if (!m) return null;
|
|
7915
8056
|
const sub = m[1];
|
|
7916
8057
|
const rest = (m[2] ?? "").trim();
|
|
@@ -7989,9 +8130,9 @@ function extractCurlDownload(cmd) {
|
|
|
7989
8130
|
const outputPath = outputMatch[1] ?? outputMatch[2] ?? outputMatch[3];
|
|
7990
8131
|
if (!outputPath) return null;
|
|
7991
8132
|
if (curlHasUnsafeFlags(cmd)) return null;
|
|
7992
|
-
const
|
|
7993
|
-
if (
|
|
7994
|
-
return { url
|
|
8133
|
+
const url = extractCurlUrl(cmd);
|
|
8134
|
+
if (url === null) return null;
|
|
8135
|
+
return { url, outputPath };
|
|
7995
8136
|
}
|
|
7996
8137
|
function isTscCommand(cmd) {
|
|
7997
8138
|
return /^\s*tsc(\s|$)/i.test(cmd);
|
|
@@ -8044,9 +8185,34 @@ function maybeCompressRewrite(event, rawCmd, cmd) {
|
|
|
8044
8185
|
const wrapped = `token-goat compress -f ${filterName} --timeout ${cfg.timeout_seconds} -c ${shellQuoteSingle(rawCmd)}`;
|
|
8045
8186
|
return { hookType: "rewriteInput", updatedInput: { ...event.toolInput, command: wrapped } };
|
|
8046
8187
|
}
|
|
8188
|
+
async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes) {
|
|
8189
|
+
if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
|
|
8190
|
+
if (isCompressibleSingleCommand(cmd)) return null;
|
|
8191
|
+
if (exitCode !== null && exitCode !== 0) return null;
|
|
8192
|
+
let cfg;
|
|
8193
|
+
try {
|
|
8194
|
+
cfg = loadConfig().bash_compress;
|
|
8195
|
+
} catch {
|
|
8196
|
+
return null;
|
|
8197
|
+
}
|
|
8198
|
+
if (!cfg.enabled || cfg.disabled_filters.includes("generic")) return null;
|
|
8199
|
+
if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return null;
|
|
8200
|
+
const filter3 = filterByName("generic");
|
|
8201
|
+
if (filter3 === null) return null;
|
|
8202
|
+
const compressed = compressOutput(filter3, output, "", exitCode ?? 0, [], {
|
|
8203
|
+
maxLines: cfg.max_lines,
|
|
8204
|
+
maxBytes: cfg.max_bytes
|
|
8205
|
+
});
|
|
8206
|
+
const minNet = resolveMinNetSavingsBytes();
|
|
8207
|
+
if (!compressed.worthApplying(minNet)) return null;
|
|
8208
|
+
const id = await storeBashOutput(cmd, output, exitCode ?? 0, cwd);
|
|
8209
|
+
recordStat("bash_compress:generic", compressed.bytesSaved, compressed.tokensSaved);
|
|
8210
|
+
const body = compressed.withMarker(minNet) + "\n[token-goat] full output: bash-output " + id + " --full";
|
|
8211
|
+
return { hookType: "rewriteOutput", updatedOutput: body };
|
|
8212
|
+
}
|
|
8047
8213
|
function unwrapCompressCommand(executed) {
|
|
8048
8214
|
const t = executed.trim();
|
|
8049
|
-
if (!/^token-goat\s+compress\b/.test(t)) return null;
|
|
8215
|
+
if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
|
|
8050
8216
|
let argv;
|
|
8051
8217
|
try {
|
|
8052
8218
|
argv = shlexSplit(t);
|
|
@@ -8098,6 +8264,28 @@ function detectUnbalancedShellSyntax(cmd) {
|
|
|
8098
8264
|
i = j;
|
|
8099
8265
|
continue;
|
|
8100
8266
|
}
|
|
8267
|
+
if (ch === "$" && cmd[i + 1] === "'") {
|
|
8268
|
+
let j = i + 2;
|
|
8269
|
+
let closed = false;
|
|
8270
|
+
while (j < cmd.length) {
|
|
8271
|
+
if (cmd[j] === "\\") {
|
|
8272
|
+
j += 2;
|
|
8273
|
+
continue;
|
|
8274
|
+
}
|
|
8275
|
+
if (cmd[j] === "'") {
|
|
8276
|
+
j++;
|
|
8277
|
+
closed = true;
|
|
8278
|
+
break;
|
|
8279
|
+
}
|
|
8280
|
+
j++;
|
|
8281
|
+
}
|
|
8282
|
+
if (!closed) {
|
|
8283
|
+
inSingle = true;
|
|
8284
|
+
break;
|
|
8285
|
+
}
|
|
8286
|
+
i = j;
|
|
8287
|
+
continue;
|
|
8288
|
+
}
|
|
8101
8289
|
if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
|
|
8102
8290
|
const nl2 = cmd.indexOf("\n", i);
|
|
8103
8291
|
i = nl2 === -1 ? cmd.length : nl2 + 1;
|
|
@@ -8704,7 +8892,11 @@ async function postBashHandler(event) {
|
|
|
8704
8892
|
recordBashOutput(gitScopedCacheHash, gitScopedCacheId, Buffer.byteLength(output, "utf-8"));
|
|
8705
8893
|
}
|
|
8706
8894
|
const isMonitoring = getMonitoringRecallHint(cmd) !== null;
|
|
8707
|
-
if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd))
|
|
8895
|
+
if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) {
|
|
8896
|
+
const compound = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes);
|
|
8897
|
+
if (compound !== null) return compound;
|
|
8898
|
+
return passOutput();
|
|
8899
|
+
}
|
|
8708
8900
|
if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return passOutput();
|
|
8709
8901
|
const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : stripOutputPipeline(cmd);
|
|
8710
8902
|
const simpleHash = shortFingerprint(cacheKey);
|
|
@@ -9830,6 +10022,9 @@ async function relayInProcess(eventName, rawPayload) {
|
|
|
9830
10022
|
async function relay(eventName) {
|
|
9831
10023
|
try {
|
|
9832
10024
|
if (!isHookEventName(eventName)) {
|
|
10025
|
+
console.error(
|
|
10026
|
+
`[relay] unknown hook event '${eventName}'; nothing ran. Valid events: ${HOOK_EVENTS.join(", ")}`
|
|
10027
|
+
);
|
|
9833
10028
|
process.stdout.write("{}");
|
|
9834
10029
|
return;
|
|
9835
10030
|
}
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
walkProject,
|
|
51
51
|
yamlLineClosesQuote,
|
|
52
52
|
yamlOpenQuoteAfter
|
|
53
|
-
} from "./token-goat-chunk-
|
|
53
|
+
} from "./token-goat-chunk-UFOVM7ZN.mjs";
|
|
54
54
|
import {
|
|
55
55
|
PER_FILE_COUNTERFACTUAL_CEILING,
|
|
56
56
|
_detectOpenQuote,
|
|
@@ -83,6 +83,7 @@ import {
|
|
|
83
83
|
loadConfig,
|
|
84
84
|
normalizePath,
|
|
85
85
|
offsetToLine,
|
|
86
|
+
pushAll,
|
|
86
87
|
recordStat,
|
|
87
88
|
redactIfDotenv,
|
|
88
89
|
redactSecrets,
|
|
@@ -100,7 +101,7 @@ import {
|
|
|
100
101
|
unsupportedLanguageName,
|
|
101
102
|
windowsCmdQuoteArg,
|
|
102
103
|
withExtension
|
|
103
|
-
} from "./token-goat-chunk-
|
|
104
|
+
} from "./token-goat-chunk-V465YKOR.mjs";
|
|
104
105
|
import {
|
|
105
106
|
registerReset
|
|
106
107
|
} from "./token-goat-chunk-AO2QD2AG.mjs";
|
|
@@ -563,9 +564,9 @@ function evalJsonPath(data, ops) {
|
|
|
563
564
|
} else if (op.kind === "wildcard") {
|
|
564
565
|
fanned = true;
|
|
565
566
|
if (Array.isArray(item)) {
|
|
566
|
-
next
|
|
567
|
+
pushAll(next, item);
|
|
567
568
|
} else if (typeof item === "object" && item !== null) {
|
|
568
|
-
next
|
|
569
|
+
pushAll(next, Object.values(item));
|
|
569
570
|
}
|
|
570
571
|
} else {
|
|
571
572
|
fanned = true;
|
|
@@ -997,7 +998,7 @@ function queryXml(xmlText, pathStr) {
|
|
|
997
998
|
const attrName = step.attributeSelect;
|
|
998
999
|
for (const cand of currentCandidates) {
|
|
999
1000
|
if (attrName === "*") {
|
|
1000
|
-
attrVals
|
|
1001
|
+
pushAll(attrVals, Object.values(cand.attributes));
|
|
1001
1002
|
} else if (cand.attributes[attrName] !== void 0) {
|
|
1002
1003
|
attrVals.push(cand.attributes[attrName]);
|
|
1003
1004
|
}
|
|
@@ -1046,7 +1047,7 @@ function queryXml(xmlText, pathStr) {
|
|
|
1046
1047
|
if (step.allIndices || matching.length > 1 || step.attributeFilter !== void 0) {
|
|
1047
1048
|
hasFanned = true;
|
|
1048
1049
|
}
|
|
1049
|
-
nextCandidates
|
|
1050
|
+
pushAll(nextCandidates, matching);
|
|
1050
1051
|
}
|
|
1051
1052
|
}
|
|
1052
1053
|
currentCandidates = nextCandidates;
|
|
@@ -6552,6 +6553,10 @@ function mergeListingJson(files, blocks, anyOk) {
|
|
|
6552
6553
|
const payload = { items, truncated, totalCount, ...errors.length > 0 ? { errors } : {} };
|
|
6553
6554
|
return { text: JSON.stringify(payload, null, 2), code: anyOk ? 0 : 1 };
|
|
6554
6555
|
}
|
|
6556
|
+
function symbolCountLabel(shown, truncated, trueCount) {
|
|
6557
|
+
if (!truncated || trueCount === void 0 || trueCount <= shown) return countNoun(shown, "symbol");
|
|
6558
|
+
return `${shown} of ${countNoun(trueCount, "symbol")}`;
|
|
6559
|
+
}
|
|
6555
6560
|
function runSkeleton(opts) {
|
|
6556
6561
|
const multiFiles = parseMultiFileSpec(opts.file);
|
|
6557
6562
|
if (multiFiles !== null) return runPerFileListing(multiFiles, (file) => runSkeleton({ ...opts, file, includeFilePath: true }), opts.json === true);
|
|
@@ -6584,7 +6589,7 @@ function runSkeleton(opts) {
|
|
|
6584
6589
|
return { text: text2, code: 0 };
|
|
6585
6590
|
}
|
|
6586
6591
|
const totalLines = filtered.length > 0 ? Math.max(...filtered.map((s) => s.lineEnd)) : 0;
|
|
6587
|
-
const lines = [`# Skeleton: ${opts.file} (${
|
|
6592
|
+
const lines = [`# Skeleton: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)}, ${countNoun(totalLines, "line")})`];
|
|
6588
6593
|
if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
|
|
6589
6594
|
for (const sym of filtered) {
|
|
6590
6595
|
const lineStr = sym.lineStart.toString().padStart(6);
|
|
@@ -6626,7 +6631,7 @@ function runOutline(opts) {
|
|
|
6626
6631
|
recordReadStat("outline", fullSourceBytes, text2, opts.file);
|
|
6627
6632
|
return { text: text2, code: 0 };
|
|
6628
6633
|
}
|
|
6629
|
-
const lines = [`# Outline: ${opts.file} (${
|
|
6634
|
+
const lines = [`# Outline: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)})`];
|
|
6630
6635
|
if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
|
|
6631
6636
|
for (const sym of filtered) {
|
|
6632
6637
|
const rangeStr = `${sym.lineStart.toString().padStart(4)}-${sym.lineEnd.toString().padEnd(6)}`;
|
|
@@ -7644,10 +7649,16 @@ function buildChangedRefHint(cwd, ref) {
|
|
|
7644
7649
|
const commitWord = commitCount === 1 ? "1 commit" : `${commitCount} commits`;
|
|
7645
7650
|
return `Hint: this repo has only ${commitWord}; '${ref}' does not exist. Try: token-goat changed --since ${suggestedRef}`;
|
|
7646
7651
|
}
|
|
7652
|
+
function refIsSafe(ref) {
|
|
7653
|
+
return !ref.startsWith("-");
|
|
7654
|
+
}
|
|
7655
|
+
function emitUnsafeRef(ref) {
|
|
7656
|
+
emitErr(`Refusing a git ref that starts with '-': ${ref}`);
|
|
7657
|
+
}
|
|
7647
7658
|
function runChanged(opts = {}) {
|
|
7648
7659
|
const ref = opts.ref ?? "HEAD~5";
|
|
7649
|
-
if (ref
|
|
7650
|
-
|
|
7660
|
+
if (!refIsSafe(ref)) {
|
|
7661
|
+
emitUnsafeRef(ref);
|
|
7651
7662
|
return 1;
|
|
7652
7663
|
}
|
|
7653
7664
|
const cwd = opts.projectRoot ?? process.cwd();
|
|
@@ -7824,6 +7835,10 @@ function resolveSymbolSpecOrEmitError(commandName, spec, projectRoot) {
|
|
|
7824
7835
|
return resolution.entry;
|
|
7825
7836
|
}
|
|
7826
7837
|
function runDiff(opts) {
|
|
7838
|
+
if (opts.ref !== void 0 && !refIsSafe(opts.ref)) {
|
|
7839
|
+
emitUnsafeRef(opts.ref);
|
|
7840
|
+
return 1;
|
|
7841
|
+
}
|
|
7827
7842
|
const match = resolveSymbolSpecOrEmitError("diff", opts.spec, opts.projectRoot);
|
|
7828
7843
|
if (match === null) return 1;
|
|
7829
7844
|
const cwd = opts.projectRoot ?? process.cwd();
|
|
@@ -7911,6 +7926,10 @@ function parseLogDashLOutput(stdout) {
|
|
|
7911
7926
|
return entries;
|
|
7912
7927
|
}
|
|
7913
7928
|
function runLog(opts) {
|
|
7929
|
+
if (opts.ref !== void 0 && !refIsSafe(opts.ref)) {
|
|
7930
|
+
emitUnsafeRef(opts.ref);
|
|
7931
|
+
return 1;
|
|
7932
|
+
}
|
|
7914
7933
|
const match = resolveSymbolSpecOrEmitError("log", opts.spec, opts.projectRoot);
|
|
7915
7934
|
if (match === null) return 1;
|
|
7916
7935
|
const cwd = opts.projectRoot ?? process.cwd();
|