token-goat 2.6.16 → 2.6.17
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 +24 -4
- package/dist/token-goat-hook.mjs +824 -328
- package/dist/token-goat.mjs +9762 -7995
- package/package.json +1 -1
package/dist/token-goat-hook.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import * as path from "node:path";
|
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
function resolveVersion() {
|
|
11
11
|
if (true) {
|
|
12
|
-
return "2.6.
|
|
12
|
+
return "2.6.17";
|
|
13
13
|
}
|
|
14
14
|
const require2 = createRequire(import.meta.url);
|
|
15
15
|
const pkg = require2("../package.json");
|
|
@@ -126,6 +126,7 @@ var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
|
|
|
126
126
|
"pi",
|
|
127
127
|
"copilot_cli",
|
|
128
128
|
"grok",
|
|
129
|
+
"qwen",
|
|
129
130
|
"generic"
|
|
130
131
|
]);
|
|
131
132
|
function detectHarness() {
|
|
@@ -1728,10 +1729,8 @@ var CONFIG_DEFAULTS = {
|
|
|
1728
1729
|
record_zero_savings: false
|
|
1729
1730
|
},
|
|
1730
1731
|
hints: {
|
|
1731
|
-
suppress_after_ignored: 5,
|
|
1732
1732
|
quiet_hours: "",
|
|
1733
1733
|
json_sidecar: false,
|
|
1734
|
-
verbose_until_seen_count: 2,
|
|
1735
1734
|
min_file_lines_for_hint: 0,
|
|
1736
1735
|
bash_dedup_min_bytes: 200,
|
|
1737
1736
|
web_dedup_min_bytes: 200,
|
|
@@ -1874,8 +1873,6 @@ var NUMERIC_FIELD_BOUNDS = {
|
|
|
1874
1873
|
"image_shrink.ocr_min_confidence": { min: 0, max: 100 },
|
|
1875
1874
|
"repomap.compact_file_threshold": { min: 0, max: 1e5 },
|
|
1876
1875
|
"overflow_guard.max_tokens": { min: 1e3, max: 1e6 },
|
|
1877
|
-
"hints.suppress_after_ignored": { min: 0, max: 1e3 },
|
|
1878
|
-
"hints.verbose_until_seen_count": { min: 0, max: 1e4 },
|
|
1879
1876
|
"hints.min_file_lines_for_hint": { min: 0, max: 1e6 },
|
|
1880
1877
|
"hints.bash_dedup_min_bytes": { min: 0, max: 1e5 },
|
|
1881
1878
|
"hints.web_dedup_min_bytes": { min: 0, max: 1e5 },
|
|
@@ -1957,9 +1954,12 @@ var ENV_KEYS2 = [
|
|
|
1957
1954
|
"TOKEN_GOAT_WRITE_REWRITE_MIN_LINES",
|
|
1958
1955
|
"TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"
|
|
1959
1956
|
];
|
|
1957
|
+
function allEnvKeys() {
|
|
1958
|
+
return [.../* @__PURE__ */ new Set([...ENV_KEYS2, ...Object.values(CONFIG_KEY_ENV_OVERRIDES).flat()])];
|
|
1959
|
+
}
|
|
1960
1960
|
function configEnvFingerprint() {
|
|
1961
1961
|
const snap = {};
|
|
1962
|
-
for (const k of
|
|
1962
|
+
for (const k of allEnvKeys()) {
|
|
1963
1963
|
snap[k] = process.env[k];
|
|
1964
1964
|
}
|
|
1965
1965
|
return JSON.stringify(snap);
|
|
@@ -2007,6 +2007,25 @@ function resolveConfigProjectRoot() {
|
|
|
2007
2007
|
_projectRootCache = { cwd, root };
|
|
2008
2008
|
return root;
|
|
2009
2009
|
}
|
|
2010
|
+
function isAutoTriggerMultiplierExplicit() {
|
|
2011
|
+
const setsMultiplier = (text) => {
|
|
2012
|
+
const raw = parse(text);
|
|
2013
|
+
const ca_raw = raw["compact_assist"];
|
|
2014
|
+
if (ca_raw === null || typeof ca_raw !== "object" || Array.isArray(ca_raw)) {
|
|
2015
|
+
return false;
|
|
2016
|
+
}
|
|
2017
|
+
return ca_raw["auto_trigger_multiplier"] !== void 0;
|
|
2018
|
+
};
|
|
2019
|
+
try {
|
|
2020
|
+
if (setsMultiplier(fs3.readFileSync(configPath(), "utf8"))) return true;
|
|
2021
|
+
} catch {
|
|
2022
|
+
}
|
|
2023
|
+
try {
|
|
2024
|
+
return setsMultiplier(fs3.readFileSync(projectConfigPath(resolveConfigProjectRoot()), "utf8"));
|
|
2025
|
+
} catch {
|
|
2026
|
+
return false;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2010
2029
|
function loadConfig(projectRoot) {
|
|
2011
2030
|
const p = configPath();
|
|
2012
2031
|
const root = projectRoot ?? resolveConfigProjectRoot();
|
|
@@ -2143,10 +2162,8 @@ function _buildConfig(raw, projectRaw = {}) {
|
|
|
2143
2162
|
st.record_zero_savings = validatedBool(st_raw["record_zero_savings"], st.record_zero_savings);
|
|
2144
2163
|
const hi_raw = section(raw, "hints");
|
|
2145
2164
|
const hi = getDefaultConfig("hints");
|
|
2146
|
-
hi.suppress_after_ignored = validatedInt(hi_raw["suppress_after_ignored"], hi.suppress_after_ignored, ...boundsOf("hints.suppress_after_ignored"));
|
|
2147
2165
|
hi.quiet_hours = validatedStr(hi_raw["quiet_hours"], hi.quiet_hours);
|
|
2148
2166
|
hi.json_sidecar = validatedBool(hi_raw["json_sidecar"], hi.json_sidecar);
|
|
2149
|
-
hi.verbose_until_seen_count = validatedInt(hi_raw["verbose_until_seen_count"], hi.verbose_until_seen_count, ...boundsOf("hints.verbose_until_seen_count"));
|
|
2150
2167
|
hi.min_file_lines_for_hint = validatedInt(hi_raw["min_file_lines_for_hint"], hi.min_file_lines_for_hint, ...boundsOf("hints.min_file_lines_for_hint"));
|
|
2151
2168
|
hi.bash_dedup_min_bytes = validatedInt(hi_raw["bash_dedup_min_bytes"], hi.bash_dedup_min_bytes, ...boundsOf("hints.bash_dedup_min_bytes"));
|
|
2152
2169
|
hi.bash_dedup_min_bytes = envInt("TOKEN_GOAT_BASH_DEDUP_MIN_BYTES", hi.bash_dedup_min_bytes, ...boundsOf("hints.bash_dedup_min_bytes"));
|
|
@@ -2262,6 +2279,49 @@ function _buildConfig(raw, projectRaw = {}) {
|
|
|
2262
2279
|
hint_stats: hs
|
|
2263
2280
|
};
|
|
2264
2281
|
}
|
|
2282
|
+
var CONFIG_KEY_ENV_OVERRIDES = {
|
|
2283
|
+
"compact_assist.enabled": ["TOKEN_GOAT_COMPACT_ASSIST", "TOKENWISE_COMPACT_ASSIST"],
|
|
2284
|
+
"bash_compress.enabled": ["TOKEN_GOAT_BASH_COMPRESS"],
|
|
2285
|
+
"bash_compress.cache_min_bytes": ["TOKEN_GOAT_BASH_CACHE_MIN_BYTES"],
|
|
2286
|
+
"bash_compress.cache_max_file_count": ["TOKEN_GOAT_BASH_CACHE_MAX_FILES"],
|
|
2287
|
+
"bash_compress.cache_max_bytes": ["TOKEN_GOAT_BASH_CACHE_MAX_BYTES"],
|
|
2288
|
+
"bash_compress.cache_max_bytes_per_output": ["TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT"],
|
|
2289
|
+
"session_brief.enabled": ["TOKEN_GOAT_SESSION_BRIEF"],
|
|
2290
|
+
"skill_preservation.enabled": ["TOKEN_GOAT_SKILL_PRESERVATION"],
|
|
2291
|
+
"skill_preservation.compress_bodies": ["TOKEN_GOAT_SKILL_COMPRESS"],
|
|
2292
|
+
"skill_preservation.pre_skill_enabled": ["TOKEN_GOAT_PRE_SKILL"],
|
|
2293
|
+
"skill_preservation.orphan_sweep_enabled": ["TOKEN_GOAT_ORPHAN_SWEEP"],
|
|
2294
|
+
"image_shrink.max_image_pixels": ["TOKEN_GOAT_MAX_IMAGE_PIXELS"],
|
|
2295
|
+
"image_shrink.ocr_enabled": ["TOKEN_GOAT_OCR_ENABLED"],
|
|
2296
|
+
"repomap.compact_file_threshold": ["TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD"],
|
|
2297
|
+
"repomap.exclude_tests": ["TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS"],
|
|
2298
|
+
"overflow_guard.enabled": ["TOKEN_GOAT_OVERFLOW_GUARD"],
|
|
2299
|
+
"overflow_guard.max_tokens": ["TOKEN_GOAT_OVERFLOW_MAX_TOKENS"],
|
|
2300
|
+
"hints.json_sidecar": ["TOKEN_GOAT_HINT_JSON_SIDECAR"],
|
|
2301
|
+
"hints.bash_dedup_min_bytes": ["TOKEN_GOAT_BASH_DEDUP_MIN_BYTES"],
|
|
2302
|
+
"hints.web_dedup_min_bytes": ["TOKEN_GOAT_WEB_DEDUP_MIN_BYTES"],
|
|
2303
|
+
"hints.grep_dedup_min_matches": ["TOKEN_GOAT_GREP_DEDUP_MIN_MATCHES"],
|
|
2304
|
+
"hints.glob_dedup_min_matches": ["TOKEN_GOAT_GLOB_DEDUP_MIN_MATCHES"],
|
|
2305
|
+
"hints.write_rewrite_min_lines": ["TOKEN_GOAT_WRITE_REWRITE_MIN_LINES"],
|
|
2306
|
+
"hints.write_rewrite_unchanged_pct": ["TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"],
|
|
2307
|
+
"hints.large_read_redirect_bytes": ["TOKEN_GOAT_LARGE_READ_BYTES"],
|
|
2308
|
+
"hints.warn_unbalanced_shell_quoting": ["TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING"],
|
|
2309
|
+
"hints.serve_diff_on_reread": ["TOKEN_GOAT_SERVE_DIFF_ON_REREAD"],
|
|
2310
|
+
"hints.log_large_file_hint_outcomes": ["TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES"],
|
|
2311
|
+
"hints.cross_session_read_dedup": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP"],
|
|
2312
|
+
"hints.cross_session_read_dedup_ttl_secs": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS"],
|
|
2313
|
+
"hints.mcp_dedup_ttl_secs": ["TOKEN_GOAT_MCP_DEDUP_TTL_SECS"],
|
|
2314
|
+
"hints.min_session_hint_savings_bytes": ["TOKEN_GOAT_SESSION_HINT_MIN_BYTES"],
|
|
2315
|
+
"hooks.watchdog_ms": ["TOKEN_GOAT_HOOK_WATCHDOG_MS"],
|
|
2316
|
+
"webfetch.max_file_count": ["TOKEN_GOAT_WEB_CACHE_MAX_FILES"],
|
|
2317
|
+
"webfetch.max_bytes": ["TOKEN_GOAT_WEB_CACHE_MAX_BYTES"],
|
|
2318
|
+
"webfetch.compress_bodies": ["TOKEN_GOAT_WEB_COMPRESS"],
|
|
2319
|
+
"worker.max_pool_workers": ["TOKEN_GOAT_WORKER_MAX_POOL"],
|
|
2320
|
+
"compression.profile": ["TOKEN_GOAT_COMPRESS_PROFILE"],
|
|
2321
|
+
"context.model_window_tokens": ["TOKEN_GOAT_MODEL_WINDOW_TOKENS"],
|
|
2322
|
+
"injection.enabled": ["TOKEN_GOAT_INJECTION_ENABLED"],
|
|
2323
|
+
"indexing.embeddings_enabled": ["TOKEN_GOAT_EMBEDDINGS_ENABLED"]
|
|
2324
|
+
};
|
|
2265
2325
|
|
|
2266
2326
|
// src/secret_redact.ts
|
|
2267
2327
|
var SECRET_PATTERNS = [
|
|
@@ -2269,8 +2329,17 @@ var SECRET_PATTERNS = [
|
|
|
2269
2329
|
// ("sk-ant-"), so they're matched first — the generic OpenAI pattern's
|
|
2270
2330
|
// negative lookahead below is defense in depth, not the sole guard.
|
|
2271
2331
|
["anthropic_api_key", /sk-ant-[A-Za-z0-9_-]{20,}/g],
|
|
2272
|
-
|
|
2332
|
+
// Modern (post-2024, now the default) OpenAI project keys: "sk-proj-" followed by a long
|
|
2333
|
+
// base64url-ish body that legitimately contains '-' and '_' -- the generic pattern below
|
|
2334
|
+
// deliberately excludes those characters (hyphenated prose would false-fire), so this needs
|
|
2335
|
+
// its own entry with the more specific prefix matched first, like sk-ant- above.
|
|
2336
|
+
["openai_project_key", /sk-proj-[A-Za-z0-9_-]{20,}/g],
|
|
2337
|
+
["openai_api_key", /sk-(?!ant-|proj-)[A-Za-z0-9]{20,}/g],
|
|
2273
2338
|
["aws_access_key", /AKIA[0-9A-Z]{16}/g],
|
|
2339
|
+
// Fine-grained PATs ("github_pat_...") are matched before the classic gh[oprsu]_ pattern so
|
|
2340
|
+
// the full token is always consumed as one match -- a fine-grained token's own body can
|
|
2341
|
+
// contain '_' and could otherwise partially match the classic pattern.
|
|
2342
|
+
["github_token", /github_pat_[A-Za-z0-9_]{22,}/g],
|
|
2274
2343
|
["github_token", /gh[oprsu]_[A-Za-z0-9]{36,}/g],
|
|
2275
2344
|
["slack_token", /xox[baprs]-[A-Za-z0-9-]+/g],
|
|
2276
2345
|
// Matches the full block (BEGIN marker through its matching END marker), not just the
|
|
@@ -2425,6 +2494,23 @@ CREATE TABLE IF NOT EXISTS hint_manual_marks (
|
|
|
2425
2494
|
effective_count INTEGER NOT NULL DEFAULT 0,
|
|
2426
2495
|
ineffective_count INTEGER NOT NULL DEFAULT 0
|
|
2427
2496
|
);
|
|
2497
|
+
|
|
2498
|
+
-- Durable counter backing hint_stats.ts's backoff-threshold probe-recovery schedule: how many
|
|
2499
|
+
-- CONSECUTIVE suppressed occasions have elapsed for (category, harness) since a hint in this
|
|
2500
|
+
-- category was last actually shown (either organically, because shouldSuppress no longer holds,
|
|
2501
|
+
-- or via a prior probe). shouldSuppress itself stays a pure function of hint_emissions -- this
|
|
2502
|
+
-- table exists only because a suppressed occasion is deliberately never written to
|
|
2503
|
+
-- hint_emissions (see that table's own comment), so without a separate durable counter here
|
|
2504
|
+
-- there would be no way to know "how many suppressed occasions have we seen" across the
|
|
2505
|
+
-- short-lived hook CLI processes that call applyHintTracking. Keyed by (category, harness), not
|
|
2506
|
+
-- category alone, to match shouldSuppress/categoryStats' own per-harness scoping -- unlike
|
|
2507
|
+
-- hint_manual_marks (a human-entered vote, deliberately not harness-split).
|
|
2508
|
+
CREATE TABLE IF NOT EXISTS hint_suppression_probes (
|
|
2509
|
+
category TEXT NOT NULL,
|
|
2510
|
+
harness TEXT NOT NULL,
|
|
2511
|
+
streak INTEGER NOT NULL DEFAULT 0,
|
|
2512
|
+
PRIMARY KEY (category, harness)
|
|
2513
|
+
);
|
|
2428
2514
|
`;
|
|
2429
2515
|
var FTS_SQL = `
|
|
2430
2516
|
CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(
|
|
@@ -2475,7 +2561,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
2475
2561
|
VALUES (new.row_id, new.label, new.content);
|
|
2476
2562
|
END;
|
|
2477
2563
|
`;
|
|
2478
|
-
var SCHEMA_VERSION =
|
|
2564
|
+
var SCHEMA_VERSION = 6;
|
|
2479
2565
|
function alterTableIdempotent(conn, sql) {
|
|
2480
2566
|
try {
|
|
2481
2567
|
conn.exec(sql);
|
|
@@ -3521,6 +3607,42 @@ function denyOutput(message) {
|
|
|
3521
3607
|
function contextOutput(context) {
|
|
3522
3608
|
return { hookType: "context", context };
|
|
3523
3609
|
}
|
|
3610
|
+
function countNonEmptyLines(text) {
|
|
3611
|
+
return text.split(/\r\n|\r|\n/).filter((line) => line.length > 0).length;
|
|
3612
|
+
}
|
|
3613
|
+
function makeDedupHintHandlers(opts) {
|
|
3614
|
+
const post = (event) => {
|
|
3615
|
+
try {
|
|
3616
|
+
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
3617
|
+
const signature = opts.buildSignature(getToolInput(event));
|
|
3618
|
+
if (signature === null) return passOutput();
|
|
3619
|
+
const text = extractToolResponseField(event.raw, OUTPUT_FIRST_TOOL_RESPONSE_KEYS);
|
|
3620
|
+
opts.recordQuery(signature, countNonEmptyLines(text));
|
|
3621
|
+
return passOutput();
|
|
3622
|
+
} catch {
|
|
3623
|
+
return passOutput();
|
|
3624
|
+
}
|
|
3625
|
+
};
|
|
3626
|
+
const pre = (event) => {
|
|
3627
|
+
try {
|
|
3628
|
+
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
3629
|
+
const toolInput = getToolInput(event);
|
|
3630
|
+
const signature = opts.buildSignature(toolInput);
|
|
3631
|
+
if (signature === null) return passOutput();
|
|
3632
|
+
const priorCount = opts.getMatchCount(signature);
|
|
3633
|
+
if (priorCount === null) return passOutput();
|
|
3634
|
+
if (priorCount < loadConfig().hints[opts.minMatchesConfigKey]) return passOutput();
|
|
3635
|
+
recordStat(opts.statName, 0, 0);
|
|
3636
|
+
const pattern = typeof toolInput["pattern"] === "string" ? toolInput["pattern"] : "";
|
|
3637
|
+
return contextOutput(
|
|
3638
|
+
"Note: an identical " + opts.toolName + ' for "' + pattern + '" already ran this session and returned ' + priorCount + (priorCount === 1 ? " match" : " matches") + ". If that result already answers this, you can skip re-running it."
|
|
3639
|
+
);
|
|
3640
|
+
} catch {
|
|
3641
|
+
return passOutput();
|
|
3642
|
+
}
|
|
3643
|
+
};
|
|
3644
|
+
return { post, pre };
|
|
3645
|
+
}
|
|
3524
3646
|
|
|
3525
3647
|
// src/hint_stats.ts
|
|
3526
3648
|
var HINT_CATEGORIES = [
|
|
@@ -3555,6 +3677,10 @@ function extractPathCorrelator(text) {
|
|
|
3555
3677
|
return cleaned;
|
|
3556
3678
|
}
|
|
3557
3679
|
function classifyBashHint(text) {
|
|
3680
|
+
const fileMatch = /token-goat bash-output --file "([^"]+)"/.exec(text);
|
|
3681
|
+
if (fileMatch?.[1] !== void 0) {
|
|
3682
|
+
return { category: "bash_recall", correlator: fileMatch[1] };
|
|
3683
|
+
}
|
|
3558
3684
|
const idMatch = /token-goat bash-output ([A-Za-z0-9_.-]+)/.exec(text);
|
|
3559
3685
|
if (idMatch?.[1] !== void 0) {
|
|
3560
3686
|
return { category: "bash_recall", correlator: idMatch[1] };
|
|
@@ -3568,13 +3694,49 @@ function classifyReadHint(text) {
|
|
|
3568
3694
|
function classifyEditHint(text) {
|
|
3569
3695
|
return { category: "edit_reread_suggest", correlator: extractPathCorrelator(text) };
|
|
3570
3696
|
}
|
|
3697
|
+
function isProbeOccasion(occasion, thresholds) {
|
|
3698
|
+
const sorted = [...new Set(thresholds.filter((t) => t > 0))].sort((a, b) => a - b);
|
|
3699
|
+
if (sorted.length === 0) return false;
|
|
3700
|
+
if (sorted.includes(occasion)) return true;
|
|
3701
|
+
const last = sorted[sorted.length - 1];
|
|
3702
|
+
return occasion > last && occasion % last === 0;
|
|
3703
|
+
}
|
|
3704
|
+
function bumpSuppressionStreak(category) {
|
|
3705
|
+
try {
|
|
3706
|
+
const db = getDb(globalDbPath());
|
|
3707
|
+
const harness = getHarnessName();
|
|
3708
|
+
db.prepare(
|
|
3709
|
+
`INSERT INTO hint_suppression_probes (category, harness, streak) VALUES (@category, @harness, 1)
|
|
3710
|
+
ON CONFLICT(category, harness) DO UPDATE SET streak = streak + 1`
|
|
3711
|
+
).run({ category, harness });
|
|
3712
|
+
const row = db.prepare(`SELECT streak FROM hint_suppression_probes WHERE category = ? AND harness = ?`).get(category, harness);
|
|
3713
|
+
return row?.streak ?? 0;
|
|
3714
|
+
} catch {
|
|
3715
|
+
return 0;
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
function resetSuppressionStreak(category) {
|
|
3719
|
+
try {
|
|
3720
|
+
const db = getDb(globalDbPath());
|
|
3721
|
+
db.prepare(`UPDATE hint_suppression_probes SET streak = 0 WHERE category = ? AND harness = ?`).run(category, getHarnessName());
|
|
3722
|
+
} catch {
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3571
3725
|
function applyHintTracking(event, output, classify) {
|
|
3572
3726
|
if (output.hookType !== "context") return output;
|
|
3573
3727
|
const { category, correlator } = classify(output.context);
|
|
3728
|
+
const compensateSelfResolve = event.eventName === "pre_tool_use";
|
|
3574
3729
|
if (shouldSuppress(category, event.sessionId)) {
|
|
3575
|
-
|
|
3730
|
+
const occasion = bumpSuppressionStreak(category);
|
|
3731
|
+
const thresholds = loadConfig().hints.backoff_thresholds;
|
|
3732
|
+
if (!isProbeOccasion(occasion, thresholds)) {
|
|
3733
|
+
return passOutput();
|
|
3734
|
+
}
|
|
3735
|
+
logHintEmission(category, event.sessionId, correlator, compensateSelfResolve);
|
|
3736
|
+
return output;
|
|
3576
3737
|
}
|
|
3577
|
-
|
|
3738
|
+
resetSuppressionStreak(category);
|
|
3739
|
+
logHintEmission(category, event.sessionId, correlator, compensateSelfResolve);
|
|
3578
3740
|
return output;
|
|
3579
3741
|
}
|
|
3580
3742
|
function logHintEmission(category, sessionId, correlator, compensateSelfResolve = false) {
|
|
@@ -3598,12 +3760,21 @@ function logHintEmission(category, sessionId, correlator, compensateSelfResolve
|
|
|
3598
3760
|
}
|
|
3599
3761
|
}
|
|
3600
3762
|
var TOKEN_GOAT_INVOCATION_RE = /(?:^|[\s;&|])token-goat(?=[\s]|$)/;
|
|
3763
|
+
function commandMentionsCorrelator(command, correlator) {
|
|
3764
|
+
let idx = command.indexOf(correlator);
|
|
3765
|
+
while (idx !== -1) {
|
|
3766
|
+
const after = command[idx + correlator.length];
|
|
3767
|
+
if (after === void 0 || !/[A-Za-z0-9_.-]/.test(after)) return true;
|
|
3768
|
+
idx = command.indexOf(correlator, idx + 1);
|
|
3769
|
+
}
|
|
3770
|
+
return false;
|
|
3771
|
+
}
|
|
3601
3772
|
function isActedOn(category, correlator, command) {
|
|
3602
3773
|
if (!TOKEN_GOAT_INVOCATION_RE.test(command)) return false;
|
|
3603
3774
|
if (category === "bash_recall") {
|
|
3604
|
-
return command.includes("bash-output") && command
|
|
3775
|
+
return command.includes("bash-output") && commandMentionsCorrelator(command, correlator);
|
|
3605
3776
|
}
|
|
3606
|
-
return command
|
|
3777
|
+
return commandMentionsCorrelator(command, correlator);
|
|
3607
3778
|
}
|
|
3608
3779
|
function resolvePendingHintsForEvent(event) {
|
|
3609
3780
|
try {
|
|
@@ -3660,6 +3831,18 @@ function meetsSavingsFloor(bytesSaved) {
|
|
|
3660
3831
|
// src/compact.ts
|
|
3661
3832
|
import * as fs8 from "node:fs";
|
|
3662
3833
|
import * as path9 from "node:path";
|
|
3834
|
+
|
|
3835
|
+
// src/bash_compress.ts
|
|
3836
|
+
var ANSI_ESCAPE_RE = (
|
|
3837
|
+
// eslint-disable-next-line no-control-regex -- intentionally matches ESC (\x1B) and BEL (\x07) control bytes
|
|
3838
|
+
/\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\|$)|\x1B[PX^_].*?\x1B\\|\x1B[@-_]/gs
|
|
3839
|
+
);
|
|
3840
|
+
function stripAnsiCodes(text) {
|
|
3841
|
+
if (!text.includes("\x1B")) return text;
|
|
3842
|
+
return text.replace(ANSI_ESCAPE_RE, "");
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
// src/compact.ts
|
|
3663
3846
|
var CONTEXT_AUTOCOMPACT_TOKENS = 66e4;
|
|
3664
3847
|
var CATALOG_TOKENS = 10800;
|
|
3665
3848
|
var CONTEXT_TIER_WARM = 0.5;
|
|
@@ -3676,7 +3859,8 @@ var HARNESS_MULTIPLIER_DEFAULTS = {
|
|
|
3676
3859
|
generic: 1
|
|
3677
3860
|
};
|
|
3678
3861
|
function estimateTokens(text) {
|
|
3679
|
-
|
|
3862
|
+
const stripped = stripAnsiCodes(text);
|
|
3863
|
+
return Math.max(1, Math.floor(stripped.length / 3) + 1);
|
|
3680
3864
|
}
|
|
3681
3865
|
function tierForFraction(fill) {
|
|
3682
3866
|
if (fill >= CONTEXT_TIER_CRITICAL) return "critical";
|
|
@@ -3704,19 +3888,6 @@ function getEffectiveAutoTriggerWindow() {
|
|
|
3704
3888
|
);
|
|
3705
3889
|
return CONTEXT_AUTOCOMPACT_TOKENS * multiplier;
|
|
3706
3890
|
}
|
|
3707
|
-
function isAutoTriggerMultiplierExplicit() {
|
|
3708
|
-
try {
|
|
3709
|
-
const text = fs8.readFileSync(configPath(), "utf8");
|
|
3710
|
-
const raw = parse(text);
|
|
3711
|
-
const ca_raw = raw["compact_assist"];
|
|
3712
|
-
if (ca_raw === null || typeof ca_raw !== "object" || Array.isArray(ca_raw)) {
|
|
3713
|
-
return false;
|
|
3714
|
-
}
|
|
3715
|
-
return ca_raw["auto_trigger_multiplier"] !== void 0;
|
|
3716
|
-
} catch {
|
|
3717
|
-
return false;
|
|
3718
|
-
}
|
|
3719
|
-
}
|
|
3720
3891
|
function getContextPressure(cache) {
|
|
3721
3892
|
try {
|
|
3722
3893
|
if (!cache) {
|
|
@@ -3984,11 +4155,11 @@ function buildPackageManifestHint(options) {
|
|
|
3984
4155
|
return null;
|
|
3985
4156
|
}
|
|
3986
4157
|
}
|
|
3987
|
-
function _sanitizeHintPath(
|
|
3988
|
-
if (typeof
|
|
4158
|
+
function _sanitizeHintPath(path24) {
|
|
4159
|
+
if (typeof path24 !== "string") {
|
|
3989
4160
|
return "???";
|
|
3990
4161
|
}
|
|
3991
|
-
return
|
|
4162
|
+
return path24.replace(/[\x00]/g, "").slice(0, 200);
|
|
3992
4163
|
}
|
|
3993
4164
|
|
|
3994
4165
|
// src/hints/lang_patterns.ts
|
|
@@ -6435,11 +6606,9 @@ async function findCrossSessionEntry(skillName, contentSha) {
|
|
|
6435
6606
|
}
|
|
6436
6607
|
const dir = skillOutputsDir();
|
|
6437
6608
|
const bodyPath = resolve5(dir, `${meta.outputId}.txt`);
|
|
6438
|
-
const gzPath = resolve5(dir, `${meta.outputId}.gz`);
|
|
6439
6609
|
try {
|
|
6440
6610
|
const bodyExists = await fs10.access(bodyPath).then(() => true).catch(() => false);
|
|
6441
|
-
|
|
6442
|
-
if (bodyExists || gzExists) {
|
|
6611
|
+
if (bodyExists) {
|
|
6443
6612
|
return meta;
|
|
6444
6613
|
}
|
|
6445
6614
|
} catch {
|
|
@@ -6684,7 +6853,7 @@ function pruneSkillOutputs(maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_
|
|
|
6684
6853
|
entries.push({ outputId, ts });
|
|
6685
6854
|
}
|
|
6686
6855
|
const removeEntry = (outputId) => {
|
|
6687
|
-
for (const ext of [".meta", ".txt"
|
|
6856
|
+
for (const ext of [".meta", ".txt"]) {
|
|
6688
6857
|
try {
|
|
6689
6858
|
unlinkSync5(resolve5(dir, `${outputId}${ext}`));
|
|
6690
6859
|
} catch {
|
|
@@ -6716,6 +6885,22 @@ function pruneSkillOutputs(maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_
|
|
|
6716
6885
|
import * as fs11 from "node:fs";
|
|
6717
6886
|
import * as path12 from "node:path";
|
|
6718
6887
|
|
|
6888
|
+
// src/lazy_module.ts
|
|
6889
|
+
function createLazyModuleLoader(load2, errorLabel) {
|
|
6890
|
+
let cache;
|
|
6891
|
+
return async () => {
|
|
6892
|
+
if (cache !== void 0) return cache;
|
|
6893
|
+
try {
|
|
6894
|
+
cache = await load2();
|
|
6895
|
+
} catch (err) {
|
|
6896
|
+
process.stderr.write(`token-goat: ${errorLabel}: ${String(err)}
|
|
6897
|
+
`);
|
|
6898
|
+
cache = null;
|
|
6899
|
+
}
|
|
6900
|
+
return cache;
|
|
6901
|
+
};
|
|
6902
|
+
}
|
|
6903
|
+
|
|
6719
6904
|
// src/image_ocr.ts
|
|
6720
6905
|
import { spawn as spawn2 } from "node:child_process";
|
|
6721
6906
|
import { createRequire as createRequire3 } from "node:module";
|
|
@@ -6838,19 +7023,10 @@ function formatShrinkSummary(result, subject) {
|
|
|
6838
7023
|
const dataUrl = `data:image/${result.format};base64,${result.data.toString("base64")}`;
|
|
6839
7024
|
return { summary, dataUrl };
|
|
6840
7025
|
}
|
|
6841
|
-
var
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
const mod = await import("sharp");
|
|
6846
|
-
_sharpCache = mod.default;
|
|
6847
|
-
} catch (err) {
|
|
6848
|
-
process.stderr.write(`token-goat: image shrink disabled (sharp unavailable): ${String(err)}
|
|
6849
|
-
`);
|
|
6850
|
-
_sharpCache = null;
|
|
6851
|
-
}
|
|
6852
|
-
return _sharpCache;
|
|
6853
|
-
}
|
|
7026
|
+
var loadSharp = createLazyModuleLoader(async () => {
|
|
7027
|
+
const mod = await import("sharp");
|
|
7028
|
+
return mod.default;
|
|
7029
|
+
}, "image shrink disabled (sharp unavailable)");
|
|
6854
7030
|
function isImagePath(p) {
|
|
6855
7031
|
return IMAGE_EXTENSIONS.has(path12.extname(p).toLowerCase());
|
|
6856
7032
|
}
|
|
@@ -6897,14 +7073,36 @@ async function preReadImageHandler(event) {
|
|
|
6897
7073
|
if (filePath === void 0) return passOutput();
|
|
6898
7074
|
if (!isImagePath(filePath)) return passOutput();
|
|
6899
7075
|
const size = statSize(filePath);
|
|
6900
|
-
if (size === null
|
|
6901
|
-
let input;
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
7076
|
+
if (size === null) return passOutput();
|
|
7077
|
+
let input = null;
|
|
7078
|
+
let qualifies = size >= DEFAULT_SIZE_THRESHOLD_BYTES;
|
|
7079
|
+
if (!qualifies) {
|
|
7080
|
+
try {
|
|
7081
|
+
input = fs11.readFileSync(filePath);
|
|
7082
|
+
} catch {
|
|
7083
|
+
return passOutput();
|
|
7084
|
+
}
|
|
7085
|
+
const sharp = await loadSharp();
|
|
7086
|
+
if (sharp === null) return passOutput();
|
|
7087
|
+
try {
|
|
7088
|
+
const cfg = loadConfig().image_shrink;
|
|
7089
|
+
const limitInputPixels = cfg.max_image_pixels > 0 ? cfg.max_image_pixels : false;
|
|
7090
|
+
const meta = await sharp(input, { limitInputPixels }).metadata();
|
|
7091
|
+
const longestEdge = Math.max(meta.width ?? 0, meta.height ?? 0);
|
|
7092
|
+
qualifies = longestEdge > DEFAULT_MAX_DIMENSION;
|
|
7093
|
+
} catch {
|
|
7094
|
+
return passOutput();
|
|
7095
|
+
}
|
|
6906
7096
|
}
|
|
6907
|
-
|
|
7097
|
+
if (!qualifies) return passOutput();
|
|
7098
|
+
if (input === null) {
|
|
7099
|
+
try {
|
|
7100
|
+
input = fs11.readFileSync(filePath);
|
|
7101
|
+
} catch {
|
|
7102
|
+
return passOutput();
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
const result = await shrinkImage(input, { sizeThresholdBytes: 0 });
|
|
6908
7106
|
if (result === null) return passOutput();
|
|
6909
7107
|
const basename9 = path12.basename(filePath);
|
|
6910
7108
|
if (loadConfig().image_shrink.ocr_enabled) {
|
|
@@ -7160,7 +7358,11 @@ var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
|
|
|
7160
7358
|
[".tokens", "salesforce_markup"],
|
|
7161
7359
|
[".page", "salesforce_markup"],
|
|
7162
7360
|
[".component", "salesforce_markup"],
|
|
7163
|
-
[".email", "salesforce_markup"]
|
|
7361
|
+
[".email", "salesforce_markup"],
|
|
7362
|
+
[".vue", "vue"],
|
|
7363
|
+
[".svelte", "svelte"],
|
|
7364
|
+
[".astro", "astro"],
|
|
7365
|
+
[".ipynb", "ipynb"]
|
|
7164
7366
|
]);
|
|
7165
7367
|
var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
|
|
7166
7368
|
["dockerfile", "dockerfile"],
|
|
@@ -7878,12 +8080,6 @@ function postReadHandler(event) {
|
|
|
7878
8080
|
registerHook("post_tool_use", postReadHandler, { toolName: "Read" });
|
|
7879
8081
|
|
|
7880
8082
|
// src/hooks_grep.ts
|
|
7881
|
-
function extractToolResponse(raw) {
|
|
7882
|
-
return extractToolResponseField(raw, OUTPUT_FIRST_TOOL_RESPONSE_KEYS);
|
|
7883
|
-
}
|
|
7884
|
-
function countNonEmptyLines(text) {
|
|
7885
|
-
return text.split(/\r\n|\r|\n/).filter((line) => line.length > 0).length;
|
|
7886
|
-
}
|
|
7887
8083
|
function grepIntInput(toolInput, key) {
|
|
7888
8084
|
const value = toolInput[key];
|
|
7889
8085
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -7896,7 +8092,7 @@ function grepIntInput(toolInput, key) {
|
|
|
7896
8092
|
function grepSignature(toolInput) {
|
|
7897
8093
|
const pattern = toolInput["pattern"];
|
|
7898
8094
|
if (typeof pattern !== "string" || pattern === "") return null;
|
|
7899
|
-
const
|
|
8095
|
+
const path24 = typeof toolInput["path"] === "string" ? toolInput["path"] : "";
|
|
7900
8096
|
const outputMode = typeof toolInput["output_mode"] === "string" ? toolInput["output_mode"] : "files_with_matches";
|
|
7901
8097
|
const glob = typeof toolInput["glob"] === "string" ? toolInput["glob"] : "";
|
|
7902
8098
|
const type = typeof toolInput["type"] === "string" ? toolInput["type"] : "";
|
|
@@ -7911,7 +8107,7 @@ function grepSignature(toolInput) {
|
|
|
7911
8107
|
const offset = grepIntInput(toolInput, "offset");
|
|
7912
8108
|
return JSON.stringify([
|
|
7913
8109
|
pattern,
|
|
7914
|
-
|
|
8110
|
+
path24,
|
|
7915
8111
|
outputMode,
|
|
7916
8112
|
glob,
|
|
7917
8113
|
type,
|
|
@@ -7926,95 +8122,47 @@ function grepSignature(toolInput) {
|
|
|
7926
8122
|
offset
|
|
7927
8123
|
]);
|
|
7928
8124
|
}
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
return passOutput();
|
|
7938
|
-
}
|
|
7939
|
-
}
|
|
7940
|
-
function preGrepDedupHandler(event) {
|
|
7941
|
-
try {
|
|
7942
|
-
if (getToolName(event) !== "Grep") return passOutput();
|
|
7943
|
-
const toolInput = getToolInput(event);
|
|
7944
|
-
const signature = grepSignature(toolInput);
|
|
7945
|
-
if (signature === null) return passOutput();
|
|
7946
|
-
const priorCount = getGrepMatchCount(signature);
|
|
7947
|
-
if (priorCount === null) return passOutput();
|
|
7948
|
-
if (priorCount < loadConfig().hints.grep_dedup_min_matches) return passOutput();
|
|
7949
|
-
recordStat("grep_dedup_hint", 0, 0);
|
|
7950
|
-
const pattern = typeof toolInput["pattern"] === "string" ? toolInput["pattern"] : "";
|
|
7951
|
-
return contextOutput(
|
|
7952
|
-
'Note: an identical Grep for "' + pattern + '" already ran this session and returned ' + priorCount + (priorCount === 1 ? " match" : " matches") + ". If that result already answers this, you can skip re-running it."
|
|
7953
|
-
);
|
|
7954
|
-
} catch {
|
|
7955
|
-
return passOutput();
|
|
7956
|
-
}
|
|
7957
|
-
}
|
|
8125
|
+
var { post: postGrepHandler, pre: preGrepDedupHandler } = makeDedupHintHandlers({
|
|
8126
|
+
toolName: "Grep",
|
|
8127
|
+
buildSignature: grepSignature,
|
|
8128
|
+
recordQuery: recordGrepQuery,
|
|
8129
|
+
getMatchCount: getGrepMatchCount,
|
|
8130
|
+
minMatchesConfigKey: "grep_dedup_min_matches",
|
|
8131
|
+
statName: "grep_dedup_hint"
|
|
8132
|
+
});
|
|
7958
8133
|
registerHook("pre_tool_use", preGrepDedupHandler, { toolName: "Grep" });
|
|
7959
8134
|
registerHook("post_tool_use", postGrepHandler, { toolName: "Grep" });
|
|
7960
8135
|
|
|
7961
8136
|
// src/hooks_glob.ts
|
|
7962
|
-
function extractToolResponse2(raw) {
|
|
7963
|
-
return extractToolResponseField(raw, OUTPUT_FIRST_TOOL_RESPONSE_KEYS);
|
|
7964
|
-
}
|
|
7965
|
-
function countNonEmptyLines2(text) {
|
|
7966
|
-
return text.split(/\r\n|\r|\n/).filter((line) => line.length > 0).length;
|
|
7967
|
-
}
|
|
7968
8137
|
function globSignature(toolInput) {
|
|
7969
8138
|
const pattern = toolInput["pattern"];
|
|
7970
8139
|
if (typeof pattern !== "string" || pattern === "") return null;
|
|
7971
|
-
const
|
|
7972
|
-
return JSON.stringify([pattern,
|
|
7973
|
-
}
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
return passOutput();
|
|
7983
|
-
}
|
|
7984
|
-
}
|
|
7985
|
-
function preGlobDedupHandler(event) {
|
|
7986
|
-
try {
|
|
7987
|
-
if (getToolName(event) !== "Glob") return passOutput();
|
|
7988
|
-
const toolInput = getToolInput(event);
|
|
7989
|
-
const signature = globSignature(toolInput);
|
|
7990
|
-
if (signature === null) return passOutput();
|
|
7991
|
-
const priorCount = getGlobMatchCount(signature);
|
|
7992
|
-
if (priorCount === null) return passOutput();
|
|
7993
|
-
if (priorCount < loadConfig().hints.glob_dedup_min_matches) return passOutput();
|
|
7994
|
-
recordStat("glob_dedup_hint", 0, 0);
|
|
7995
|
-
const pattern = typeof toolInput["pattern"] === "string" ? toolInput["pattern"] : "";
|
|
7996
|
-
return contextOutput(
|
|
7997
|
-
'Note: an identical Glob for "' + pattern + '" already ran this session and returned ' + priorCount + (priorCount === 1 ? " match" : " matches") + ". If that result already answers this, you can skip re-running it."
|
|
7998
|
-
);
|
|
7999
|
-
} catch {
|
|
8000
|
-
return passOutput();
|
|
8001
|
-
}
|
|
8002
|
-
}
|
|
8140
|
+
const path24 = typeof toolInput["path"] === "string" ? toolInput["path"] : "";
|
|
8141
|
+
return JSON.stringify([pattern, path24]);
|
|
8142
|
+
}
|
|
8143
|
+
var { post: postGlobHandler, pre: preGlobDedupHandler } = makeDedupHintHandlers({
|
|
8144
|
+
toolName: "Glob",
|
|
8145
|
+
buildSignature: globSignature,
|
|
8146
|
+
recordQuery: recordGlobQuery,
|
|
8147
|
+
getMatchCount: getGlobMatchCount,
|
|
8148
|
+
minMatchesConfigKey: "glob_dedup_min_matches",
|
|
8149
|
+
statName: "glob_dedup_hint"
|
|
8150
|
+
});
|
|
8003
8151
|
registerHook("pre_tool_use", preGlobDedupHandler, { toolName: "Glob" });
|
|
8004
8152
|
registerHook("post_tool_use", postGlobHandler, { toolName: "Glob" });
|
|
8005
8153
|
|
|
8006
8154
|
// src/hooks_edit.ts
|
|
8007
|
-
import * as
|
|
8155
|
+
import * as path21 from "node:path";
|
|
8008
8156
|
import { statSync as statSync11 } from "node:fs";
|
|
8009
8157
|
|
|
8010
8158
|
// src/hooks_index.ts
|
|
8011
8159
|
import * as fs17 from "node:fs";
|
|
8012
|
-
import * as
|
|
8160
|
+
import * as path20 from "node:path";
|
|
8013
8161
|
|
|
8014
8162
|
// src/worker.ts
|
|
8015
8163
|
import { spawn as spawn3 } from "node:child_process";
|
|
8016
8164
|
import * as fs16 from "node:fs";
|
|
8017
|
-
import * as
|
|
8165
|
+
import * as path19 from "node:path";
|
|
8018
8166
|
import { fileURLToPath } from "node:url";
|
|
8019
8167
|
|
|
8020
8168
|
// src/parser.ts
|
|
@@ -8052,6 +8200,44 @@ registerReset(() => {
|
|
|
8052
8200
|
PIPELINE_RETRY_DELAY_MS = DEFAULT_PIPELINE_RETRY_DELAY_MS;
|
|
8053
8201
|
});
|
|
8054
8202
|
|
|
8203
|
+
// src/doc_embed_extract.ts
|
|
8204
|
+
import * as path17 from "node:path";
|
|
8205
|
+
|
|
8206
|
+
// src/pdf_extract.ts
|
|
8207
|
+
var loadPdfjs = createLazyModuleLoader(async () => {
|
|
8208
|
+
const mod = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
8209
|
+
if (typeof import.meta.resolve === "function") {
|
|
8210
|
+
try {
|
|
8211
|
+
mod.GlobalWorkerOptions.workerSrc = await import.meta.resolve("pdfjs-dist/legacy/build/pdf.worker.mjs");
|
|
8212
|
+
} catch {
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8215
|
+
return mod;
|
|
8216
|
+
}, "pdf-extract disabled (pdfjs-dist unavailable)");
|
|
8217
|
+
|
|
8218
|
+
// src/ooxml_extract.ts
|
|
8219
|
+
var loadFflate = createLazyModuleLoader(
|
|
8220
|
+
async () => await import("fflate"),
|
|
8221
|
+
"office-file reading disabled (fflate unavailable)"
|
|
8222
|
+
);
|
|
8223
|
+
var loadXmlParser = createLazyModuleLoader(
|
|
8224
|
+
async () => await import("fast-xml-parser"),
|
|
8225
|
+
"office-file reading disabled (fast-xml-parser unavailable)"
|
|
8226
|
+
);
|
|
8227
|
+
var MAX_OOXML_INPUT_BYTES = 50 * 1024 * 1024;
|
|
8228
|
+
|
|
8229
|
+
// src/xlsx_extract.ts
|
|
8230
|
+
var loadExcelJs = createLazyModuleLoader(async () => {
|
|
8231
|
+
const mod = await import("exceljs");
|
|
8232
|
+
return mod.default ?? mod;
|
|
8233
|
+
}, "xlsx reading disabled (exceljs package unavailable)");
|
|
8234
|
+
|
|
8235
|
+
// src/doc_embed_extract.ts
|
|
8236
|
+
var EMBEDDABLE_DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([".pdf", ".docx", ".pptx", ".xlsx"]);
|
|
8237
|
+
function isEmbeddableDocument(filePath) {
|
|
8238
|
+
return EMBEDDABLE_DOCUMENT_EXTENSIONS.has(path17.extname(filePath).toLowerCase());
|
|
8239
|
+
}
|
|
8240
|
+
|
|
8055
8241
|
// src/languages/csharp.ts
|
|
8056
8242
|
var DELEGATE_RE = new RegExp(
|
|
8057
8243
|
"^\\s*(?:public|protected|private|internal)?\\s*delegate\\s+(?:[A-Za-z_][A-Za-z0-9_<>?,\\[\\]\\s]*?)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*[<(]"
|
|
@@ -8084,20 +8270,21 @@ var PROP_RE = new RegExp(
|
|
|
8084
8270
|
);
|
|
8085
8271
|
|
|
8086
8272
|
// src/languages/kotlin.ts
|
|
8273
|
+
var RECEIVER_RE = "(?:[A-Za-z_][A-Za-z0-9_<>?.,\\s]*\\.)?";
|
|
8087
8274
|
var FUN_RE = new RegExp(
|
|
8088
|
-
"^\\s*(?:(?:public|internal|protected|private|open|override|abstract|suspend|inline|infix|operator|external|actual|expect|final|sealed|tailrec)\\s+)*fun\\s+(?:<[^>]*>\\s*)?([A-Za-z_][A-Za-z0-9_]*)\\s*[(<]"
|
|
8275
|
+
"^\\s*(?:(?:public|internal|protected|private|open|override|abstract|suspend|inline|infix|operator|external|actual|expect|final|sealed|tailrec)\\s+)*fun\\s+(?:<[^>]*>\\s*)?" + RECEIVER_RE + "([A-Za-z_][A-Za-z0-9_]*)\\s*[(<]"
|
|
8089
8276
|
);
|
|
8090
8277
|
var CONST_RE = new RegExp(
|
|
8091
8278
|
"^\\s*(?:(?:public|internal|protected|private|open|override|abstract|final|actual|expect|const|lateinit|companion)\\s+)*(?:const\\s+)?val\\s+([A-Z_][A-Z0-9_]*)\\s*(?::|=)"
|
|
8092
8279
|
);
|
|
8093
8280
|
var CLASS_HEADER_RE2 = new RegExp(
|
|
8094
|
-
"^(?:(?:public|internal|protected|private|open|abstract|sealed|data|inner|expect|actual|value|annotation|fun)\\s+)*(
|
|
8281
|
+
"^(?:(?:public|internal|protected|private|open|abstract|sealed|data|inner|expect|actual|value|annotation|fun)\\s+)*(class|interface|object|enum\\s+class)\\s+([A-Za-z_][A-Za-z0-9_]*)"
|
|
8095
8282
|
);
|
|
8096
8283
|
var COMPANION_RE = new RegExp(
|
|
8097
8284
|
"^(?:(?:public|internal|protected|private)\\s+)*companion\\s+object(?:\\s+([A-Za-z_][A-Za-z0-9_]*))?\\b"
|
|
8098
8285
|
);
|
|
8099
8286
|
var TOP_FUN_RE = new RegExp(
|
|
8100
|
-
"^(?:(?:public|internal|private|suspend|inline|infix|operator|external|actual|expect|tailrec)\\s+)*fun\\s+(?:<[^>]*>\\s*)?([A-Za-z_][A-Za-z0-9_]*)\\s*[(<]"
|
|
8287
|
+
"^(?:(?:public|internal|private|suspend|inline|infix|operator|external|actual|expect|tailrec)\\s+)*fun\\s+(?:<[^>]*>\\s*)?" + RECEIVER_RE + "([A-Za-z_][A-Za-z0-9_]*)\\s*[(<]"
|
|
8101
8288
|
);
|
|
8102
8289
|
|
|
8103
8290
|
// src/languages/sql_idx.ts
|
|
@@ -8141,6 +8328,7 @@ var METHOD_RE3 = new RegExp(
|
|
|
8141
8328
|
"gm"
|
|
8142
8329
|
);
|
|
8143
8330
|
var PURE_ANNOTATION_LINE_RE = new RegExp(`^(?:@${IDENT}(?:\\([^)]*\\))?[ \\t]*)+$`);
|
|
8331
|
+
var ANNOTATION_OPENER_RE = new RegExp(`^@${IDENT}\\(`);
|
|
8144
8332
|
|
|
8145
8333
|
// src/parser.ts
|
|
8146
8334
|
var _require4 = createRequire5(import.meta.url);
|
|
@@ -8305,14 +8493,14 @@ var JS_NOISE = REF_NOISE_BY_LANG.get("typescript") ?? /* @__PURE__ */ new Set();
|
|
|
8305
8493
|
|
|
8306
8494
|
// src/index_prune.ts
|
|
8307
8495
|
import * as fs15 from "node:fs";
|
|
8308
|
-
import * as
|
|
8496
|
+
import * as path18 from "node:path";
|
|
8309
8497
|
function isTooShallowToPrune(rootPrefix) {
|
|
8310
8498
|
const segments = rootPrefix.split("/").filter((s) => s.length > 0 && !/^[a-z]:$/i.test(s));
|
|
8311
8499
|
if (segments.length === 2 && segments[0]?.toLowerCase() === "mnt" && /^[a-z]$/i.test(segments[1] ?? "")) return true;
|
|
8312
8500
|
return segments.length === 0;
|
|
8313
8501
|
}
|
|
8314
8502
|
function recordKnownRoot(filePath, dbPath = globalDbPath()) {
|
|
8315
|
-
const project = findProject(
|
|
8503
|
+
const project = findProject(path18.dirname(filePath));
|
|
8316
8504
|
if (project === null || isTooShallowToPrune(project.root)) return;
|
|
8317
8505
|
const db = getDb(dbPath);
|
|
8318
8506
|
db.prepare(
|
|
@@ -8323,7 +8511,7 @@ function recordKnownRoot(filePath, dbPath = globalDbPath()) {
|
|
|
8323
8511
|
var KNOWN_ROOT_MISSING_GRACE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
8324
8512
|
var KNOWN_ROOT_RECORD_MIN_INTERVAL_MS = 60 * 60 * 1e3;
|
|
8325
8513
|
function knownRootRecordMarkerPath(dir) {
|
|
8326
|
-
return
|
|
8514
|
+
return path18.join(dir, "known-root-record.marker");
|
|
8327
8515
|
}
|
|
8328
8516
|
function recordKnownRootThrottled(filePath, dir = dataDir(), dbPath = globalDbPath()) {
|
|
8329
8517
|
const markerPath = knownRootRecordMarkerPath(dir);
|
|
@@ -8358,10 +8546,10 @@ function parseDirtyQueueLines(raw) {
|
|
|
8358
8546
|
return out;
|
|
8359
8547
|
}
|
|
8360
8548
|
function workerPidPath(dir = dataDir()) {
|
|
8361
|
-
return
|
|
8549
|
+
return path19.join(dir, "worker.pid");
|
|
8362
8550
|
}
|
|
8363
8551
|
function workerErrorLogPath(dir) {
|
|
8364
|
-
return
|
|
8552
|
+
return path19.join(dir, "worker-errors.log");
|
|
8365
8553
|
}
|
|
8366
8554
|
var WORKER_ERROR_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
8367
8555
|
var CORRUPT_QUARANTINE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -8401,7 +8589,7 @@ function isWorkerRunning(dir = dataDir()) {
|
|
|
8401
8589
|
return pidAlive(pid);
|
|
8402
8590
|
}
|
|
8403
8591
|
function workerHealthCheckMarkerPath(dir) {
|
|
8404
|
-
return
|
|
8592
|
+
return path19.join(dir, "worker-healthcheck.marker");
|
|
8405
8593
|
}
|
|
8406
8594
|
var WORKER_HEALTHCHECK_MIN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
8407
8595
|
function ensureWorkerAlive(dir = dataDir()) {
|
|
@@ -8504,11 +8692,11 @@ var KNOWN_ROOTS_SWEEP_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
|
8504
8692
|
|
|
8505
8693
|
// src/hooks_index.ts
|
|
8506
8694
|
function dirtyQueuePath() {
|
|
8507
|
-
return
|
|
8695
|
+
return path20.join(dataDir(), "queue", "dirty.txt");
|
|
8508
8696
|
}
|
|
8509
8697
|
function appendDirtyPath(normalizedPath) {
|
|
8510
8698
|
const queuePath = dirtyQueuePath();
|
|
8511
|
-
const dir =
|
|
8699
|
+
const dir = path20.dirname(queuePath);
|
|
8512
8700
|
try {
|
|
8513
8701
|
fs17.mkdirSync(dir, { recursive: true });
|
|
8514
8702
|
} catch (e) {
|
|
@@ -8523,6 +8711,12 @@ function appendDirtyPath(normalizedPath) {
|
|
|
8523
8711
|
fs17.appendFileSync(queuePath, `${leadingNewline}${normalizedPath}
|
|
8524
8712
|
`);
|
|
8525
8713
|
}
|
|
8714
|
+
function enqueueDirtyPathSafe(filePath, opts) {
|
|
8715
|
+
try {
|
|
8716
|
+
appendDirtyPath(opts?.alreadyResolved === true ? filePath : resolveIndexPath(filePath));
|
|
8717
|
+
} catch {
|
|
8718
|
+
}
|
|
8719
|
+
}
|
|
8526
8720
|
function getDirtyPaths() {
|
|
8527
8721
|
const queuePath = dirtyQueuePath();
|
|
8528
8722
|
let raw;
|
|
@@ -8536,9 +8730,9 @@ function getDirtyPaths() {
|
|
|
8536
8730
|
function preCompactIndexHandler(_event) {
|
|
8537
8731
|
const paths = getDirtyPaths();
|
|
8538
8732
|
if (paths.length > 0) {
|
|
8539
|
-
const sidecar =
|
|
8733
|
+
const sidecar = path20.join(dataDir(), "queue", "pending.txt");
|
|
8540
8734
|
try {
|
|
8541
|
-
fs17.mkdirSync(
|
|
8735
|
+
fs17.mkdirSync(path20.dirname(sidecar), { recursive: true });
|
|
8542
8736
|
atomicWriteBytes(sidecar, Buffer.from(`${paths.join("\n")}
|
|
8543
8737
|
`, "utf8"));
|
|
8544
8738
|
} catch {
|
|
@@ -8575,7 +8769,7 @@ function postEditHandlerInner(event) {
|
|
|
8575
8769
|
if (loadConfig().hints.stable_doc_compacts) {
|
|
8576
8770
|
markCompactStale(compactPathFor(normalized));
|
|
8577
8771
|
}
|
|
8578
|
-
const editedBasename =
|
|
8772
|
+
const editedBasename = path21.basename(normalized);
|
|
8579
8773
|
if (/\.(md|mdx|markdown|rst)$/i.test(editedBasename)) {
|
|
8580
8774
|
let editedSize = Infinity;
|
|
8581
8775
|
try {
|
|
@@ -8602,6 +8796,7 @@ registerHook("post_tool_use", postEditHandler, { toolName: "NotebookEdit" });
|
|
|
8602
8796
|
// src/hooks_write.ts
|
|
8603
8797
|
import { readFileSync as readFileSync13, statSync as statSync12 } from "node:fs";
|
|
8604
8798
|
var MAX_LINES_FOR_DIFF = 4e3;
|
|
8799
|
+
var MAX_OLD_FILE_BYTES_FOR_DIFF = 4 * 1024 * 1024;
|
|
8605
8800
|
function splitLines(text) {
|
|
8606
8801
|
return text.split(/\r\n|\r|\n/);
|
|
8607
8802
|
}
|
|
@@ -8634,6 +8829,7 @@ function preWriteRewriteHandler(event) {
|
|
|
8634
8829
|
return passOutput();
|
|
8635
8830
|
}
|
|
8636
8831
|
if (!stat2.isFile()) return passOutput();
|
|
8832
|
+
if (stat2.size > MAX_OLD_FILE_BYTES_FOR_DIFF) return passOutput();
|
|
8637
8833
|
let oldContent;
|
|
8638
8834
|
try {
|
|
8639
8835
|
oldContent = readFileSync13(filePath, "utf-8");
|
|
@@ -8751,11 +8947,11 @@ function gitStateFingerprintSync(cwd) {
|
|
|
8751
8947
|
}
|
|
8752
8948
|
}
|
|
8753
8949
|
var DIR_FINGERPRINT_LISTING_CAP_ENTRIES = 1e4;
|
|
8754
|
-
function dirStateFingerprintSync(
|
|
8950
|
+
function dirStateFingerprintSync(path24) {
|
|
8755
8951
|
try {
|
|
8756
|
-
const stat2 = statSync13(
|
|
8952
|
+
const stat2 = statSync13(path24);
|
|
8757
8953
|
if (!stat2.isDirectory()) return null;
|
|
8758
|
-
const entries = readdirSync10(
|
|
8954
|
+
const entries = readdirSync10(path24);
|
|
8759
8955
|
if (entries.length <= DIR_FINGERPRINT_LISTING_CAP_ENTRIES) {
|
|
8760
8956
|
return shortFingerprint(entries.slice().sort().join("\0"));
|
|
8761
8957
|
}
|
|
@@ -8765,12 +8961,12 @@ function dirStateFingerprintSync(path23) {
|
|
|
8765
8961
|
}
|
|
8766
8962
|
}
|
|
8767
8963
|
var FILE_FINGERPRINT_CONTENT_CAP_BYTES = 2 * 1024 * 1024;
|
|
8768
|
-
function fileStateFingerprintSync(
|
|
8964
|
+
function fileStateFingerprintSync(path24) {
|
|
8769
8965
|
try {
|
|
8770
|
-
const stat2 = statSync13(
|
|
8966
|
+
const stat2 = statSync13(path24);
|
|
8771
8967
|
if (!stat2.isFile()) return null;
|
|
8772
8968
|
if (stat2.size <= FILE_FINGERPRINT_CONTENT_CAP_BYTES) {
|
|
8773
|
-
return shortFingerprint(readFileSync14(
|
|
8969
|
+
return shortFingerprint(readFileSync14(path24));
|
|
8774
8970
|
}
|
|
8775
8971
|
return shortFingerprint(`${stat2.mtimeMs}\0${stat2.size}`);
|
|
8776
8972
|
} catch {
|
|
@@ -8964,19 +9160,20 @@ function summarizeOutputDelta(oldOutput, newOutput) {
|
|
|
8964
9160
|
async function storeBashOutput(command, output, exitCode, cwd = null) {
|
|
8965
9161
|
const id = await commandHash(command, cwd);
|
|
8966
9162
|
const fingerprints = computeBashFingerprints(command, cwd);
|
|
9163
|
+
const redactedOutput = redactSecrets(output).text;
|
|
8967
9164
|
const entry = {
|
|
8968
9165
|
id,
|
|
8969
9166
|
command,
|
|
8970
|
-
output,
|
|
9167
|
+
output: redactedOutput,
|
|
8971
9168
|
exitCode,
|
|
8972
9169
|
storedAt: Date.now(),
|
|
8973
|
-
sizeBytes: Buffer.byteLength(
|
|
9170
|
+
sizeBytes: Buffer.byteLength(redactedOutput, "utf-8"),
|
|
8974
9171
|
...fingerprints ? { fingerprints } : {}
|
|
8975
9172
|
};
|
|
8976
9173
|
_byId.set(id, entry);
|
|
8977
9174
|
storeBlob(BASH_OUTPUT_SUBDIR, id, entry);
|
|
8978
9175
|
indexRecallEntry("bash", id, command, `${command}
|
|
8979
|
-
${
|
|
9176
|
+
${redactedOutput}`, entry.storedAt);
|
|
8980
9177
|
return id;
|
|
8981
9178
|
}
|
|
8982
9179
|
function coerceBashEntry(raw) {
|
|
@@ -9087,7 +9284,14 @@ function buildManifest(sessionId) {
|
|
|
9087
9284
|
);
|
|
9088
9285
|
lines.push(...buildSafeToDiscardSection(files));
|
|
9089
9286
|
lines.push(...buildMemEpochSection());
|
|
9090
|
-
return lines.join("\n");
|
|
9287
|
+
return capManifestChars(lines.join("\n"));
|
|
9288
|
+
}
|
|
9289
|
+
function capManifestChars(manifest) {
|
|
9290
|
+
const cap = loadConfig().compact_assist.max_manifest_chars;
|
|
9291
|
+
if (cap <= 0 || manifest.length <= cap) return manifest;
|
|
9292
|
+
const omitted = manifest.length - cap;
|
|
9293
|
+
return manifest.slice(0, cap) + `
|
|
9294
|
+
...(manifest truncated at ${cap} chars; ${omitted} chars omitted)`;
|
|
9091
9295
|
}
|
|
9092
9296
|
function buildSafeToDiscardSection(files) {
|
|
9093
9297
|
const rerunHashes = getSessionBashReruns();
|
|
@@ -9148,6 +9352,7 @@ function buildMemEpochSection() {
|
|
|
9148
9352
|
];
|
|
9149
9353
|
}
|
|
9150
9354
|
function preCompactHandler(event) {
|
|
9355
|
+
if (!loadConfig().compact_assist.enabled) return passOutput();
|
|
9151
9356
|
return contextOutput(buildManifest(event.sessionId));
|
|
9152
9357
|
}
|
|
9153
9358
|
registerHook("pre_compact", preCompactHandler);
|
|
@@ -9231,11 +9436,12 @@ function cacheIdForUrl(url) {
|
|
|
9231
9436
|
}
|
|
9232
9437
|
function storeWebOutput(url, content, dedupKey = url) {
|
|
9233
9438
|
const cacheId = cacheIdForUrl(dedupKey);
|
|
9234
|
-
|
|
9439
|
+
const redactedContent = redactSecrets(content).text;
|
|
9440
|
+
_byId2.set(cacheId, redactedContent);
|
|
9235
9441
|
_urlIndex.set(url, cacheId);
|
|
9236
|
-
storeBlob(WEB_OUTPUT_SUBDIR, cacheId, { url, content });
|
|
9442
|
+
storeBlob(WEB_OUTPUT_SUBDIR, cacheId, { url, content: redactedContent });
|
|
9237
9443
|
indexRecallEntry("web", cacheId, url, `${url}
|
|
9238
|
-
${
|
|
9444
|
+
${redactedContent}`, Date.now());
|
|
9239
9445
|
return cacheId;
|
|
9240
9446
|
}
|
|
9241
9447
|
function coerceWebBlob(raw) {
|
|
@@ -13546,8 +13752,8 @@ function trimCharacterEnd(str, char) {
|
|
|
13546
13752
|
function unicodeEscape(str) {
|
|
13547
13753
|
return str.replace(/[\s\S]/g, (c) => "\\u" + c.charCodeAt().toString(16).padStart(4, "0"));
|
|
13548
13754
|
}
|
|
13549
|
-
function get(obj,
|
|
13550
|
-
for (const key of
|
|
13755
|
+
function get(obj, path24) {
|
|
13756
|
+
for (const key of path24) {
|
|
13551
13757
|
if (!obj) {
|
|
13552
13758
|
return void 0;
|
|
13553
13759
|
}
|
|
@@ -14748,8 +14954,8 @@ function withBrackets(str, brackets) {
|
|
|
14748
14954
|
const rbr = typeof brackets[1] === "string" ? brackets[1] : "]";
|
|
14749
14955
|
return lbr + str + rbr;
|
|
14750
14956
|
}
|
|
14751
|
-
function pathRewrite(
|
|
14752
|
-
const modifiedPath = typeof rewriter === "function" ? rewriter(
|
|
14957
|
+
function pathRewrite(path24, rewriter, baseUrl, metadata, elem) {
|
|
14958
|
+
const modifiedPath = typeof rewriter === "function" ? rewriter(path24, metadata, elem) : path24;
|
|
14753
14959
|
return modifiedPath[0] === "/" && baseUrl ? trimCharacterEnd(baseUrl, "/") + modifiedPath : modifiedPath;
|
|
14754
14960
|
}
|
|
14755
14961
|
function formatImage(elem, walk, builder, formatOptions) {
|
|
@@ -15073,9 +15279,9 @@ function handleDeprecatedOptions(options) {
|
|
|
15073
15279
|
options.selectors.push(...tagDefinitions);
|
|
15074
15280
|
options.selectors = mergeDuplicatesPreferLast(options.selectors, (s) => s.selector);
|
|
15075
15281
|
}
|
|
15076
|
-
function set(obj,
|
|
15077
|
-
const valueKey =
|
|
15078
|
-
for (const key of
|
|
15282
|
+
function set(obj, path24, value) {
|
|
15283
|
+
const valueKey = path24.pop();
|
|
15284
|
+
for (const key of path24) {
|
|
15079
15285
|
let nested = obj[key];
|
|
15080
15286
|
if (!nested) {
|
|
15081
15287
|
nested = {};
|
|
@@ -15151,7 +15357,7 @@ ${safeText}
|
|
|
15151
15357
|
}
|
|
15152
15358
|
|
|
15153
15359
|
// src/hooks_fetch.ts
|
|
15154
|
-
function
|
|
15360
|
+
function extractToolResponse(raw) {
|
|
15155
15361
|
return extractToolResponseField(raw, BODY_FIRST_TOOL_RESPONSE_KEYS);
|
|
15156
15362
|
}
|
|
15157
15363
|
function resolveWebFetchContext(event) {
|
|
@@ -15201,7 +15407,7 @@ function postFetchHandler(event) {
|
|
|
15201
15407
|
}
|
|
15202
15408
|
const { toolInput, url } = ctx;
|
|
15203
15409
|
recordStat("web_fetch");
|
|
15204
|
-
const body =
|
|
15410
|
+
const body = extractToolResponse(event.raw);
|
|
15205
15411
|
const injCfg = loadConfig().injection;
|
|
15206
15412
|
const injectionMatches = injCfg.enabled && body ? scanForInjectionPatterns(body) : [];
|
|
15207
15413
|
if (injectionMatches.length > 0) {
|
|
@@ -15326,16 +15532,6 @@ async function postSkillHandler(event) {
|
|
|
15326
15532
|
registerHook("pre_tool_use", preSkillHandler, { toolName: "Skill" });
|
|
15327
15533
|
registerHook("post_tool_use", postSkillHandler, { toolName: "Skill" });
|
|
15328
15534
|
|
|
15329
|
-
// src/bash_compress.ts
|
|
15330
|
-
var ANSI_ESCAPE_RE = (
|
|
15331
|
-
// eslint-disable-next-line no-control-regex -- intentionally matches ESC (\x1B) and BEL (\x07) control bytes
|
|
15332
|
-
/\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\)|\x1B[PX^_].*?\x1B\\|\x1B[@-Z\\-_]/gs
|
|
15333
|
-
);
|
|
15334
|
-
function stripAnsiCodes(text) {
|
|
15335
|
-
if (!text.includes("\x1B")) return text;
|
|
15336
|
-
return text.replace(ANSI_ESCAPE_RE, "");
|
|
15337
|
-
}
|
|
15338
|
-
|
|
15339
15535
|
// src/tool_filters/helpers.ts
|
|
15340
15536
|
var DEFAULT_MAX_LINES = 1e3;
|
|
15341
15537
|
var DEFAULT_MAX_BYTES = 64 * 1024;
|
|
@@ -15407,7 +15603,10 @@ function sanitizeControlChars(text) {
|
|
|
15407
15603
|
}
|
|
15408
15604
|
function stripProgress(text) {
|
|
15409
15605
|
if (!text.includes("\r")) return text;
|
|
15410
|
-
return text.split("\n").map((line) =>
|
|
15606
|
+
return text.split("\n").map((line) => {
|
|
15607
|
+
const trimmed = line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
15608
|
+
return trimmed.includes("\r") ? trimmed.slice(trimmed.lastIndexOf("\r") + 1) : trimmed;
|
|
15609
|
+
}).join("\n");
|
|
15411
15610
|
}
|
|
15412
15611
|
function normalise(text, opts = {}) {
|
|
15413
15612
|
if (!text) return "";
|
|
@@ -16317,7 +16516,7 @@ function makeLanguageFilter(cfg) {
|
|
|
16317
16516
|
let deduped = false;
|
|
16318
16517
|
for (let i = 0; i < dRules.length; i++) {
|
|
16319
16518
|
if (dRules[i].re.test(line)) {
|
|
16320
|
-
const key = line.slice(0, dRules[i].keyLen
|
|
16519
|
+
const key = dRules[i].keyLen !== void 0 ? line.slice(0, dRules[i].keyLen) : line;
|
|
16321
16520
|
const ds = dState[i];
|
|
16322
16521
|
const seen = (ds.seen.get(key) ?? 0) + 1;
|
|
16323
16522
|
ds.seen.set(key, seen);
|
|
@@ -17742,61 +17941,42 @@ function compressNpmAuditJson(text) {
|
|
|
17742
17941
|
const result = { ...data, vulnerabilities: keep };
|
|
17743
17942
|
return JSON.stringify(result, null, 2);
|
|
17744
17943
|
}
|
|
17944
|
+
var _NPM_AUDIT_SEVERITY_LINE_RE = /^Severity:\s*(critical|high|moderate|low)/i;
|
|
17945
|
+
var _NPM_AUDIT_LEGACY_HDR_RE = /^(critical|high|moderate|low)\s+\S/i;
|
|
17745
17946
|
function compressNpmAuditHuman(text) {
|
|
17746
|
-
const
|
|
17947
|
+
const paragraphs = [[]];
|
|
17948
|
+
for (const line of text.split("\n")) {
|
|
17949
|
+
if (line.trim() === "") paragraphs.push([]);
|
|
17950
|
+
else paragraphs[paragraphs.length - 1].push(line);
|
|
17951
|
+
}
|
|
17952
|
+
const blockSeverity = (para) => {
|
|
17953
|
+
for (const l of para) {
|
|
17954
|
+
const modern = _NPM_AUDIT_SEVERITY_LINE_RE.exec(l);
|
|
17955
|
+
if (modern) return modern[1].toLowerCase();
|
|
17956
|
+
if (_NPM_AUDIT_LEGACY_HDR_RE.test(l)) return l.trim().split(/\s+/)[0].toLowerCase();
|
|
17957
|
+
}
|
|
17958
|
+
return null;
|
|
17959
|
+
};
|
|
17747
17960
|
const kept = [];
|
|
17748
17961
|
const severityCounts = {};
|
|
17749
17962
|
let blockCount = 0;
|
|
17750
|
-
|
|
17751
|
-
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
|
|
17757
|
-
continue;
|
|
17758
|
-
}
|
|
17759
|
-
if (SEVERITY_HDR_RE.test(line)) {
|
|
17760
|
-
if (inBlock && blockLines.length) {
|
|
17761
|
-
if (blockCount < 10) kept.push(...blockLines);
|
|
17762
|
-
else {
|
|
17763
|
-
const sev = (blockLines[0] ?? "").split(/\s+/)[0].toLowerCase();
|
|
17764
|
-
severityCounts[sev] = (severityCounts[sev] ?? 0) + 1;
|
|
17765
|
-
}
|
|
17766
|
-
blockCount += 1;
|
|
17767
|
-
}
|
|
17768
|
-
inBlock = true;
|
|
17769
|
-
blockLines = [line];
|
|
17770
|
-
continue;
|
|
17771
|
-
}
|
|
17772
|
-
if (inBlock) {
|
|
17773
|
-
if (line.trim() === "") {
|
|
17774
|
-
blockLines.push(line);
|
|
17775
|
-
if (blockCount < 10) kept.push(...blockLines);
|
|
17776
|
-
else {
|
|
17777
|
-
const sev = (blockLines[0] ?? "").split(/\s+/)[0].toLowerCase();
|
|
17778
|
-
severityCounts[sev] = (severityCounts[sev] ?? 0) + 1;
|
|
17779
|
-
}
|
|
17780
|
-
blockLines = [];
|
|
17781
|
-
blockCount += 1;
|
|
17782
|
-
inBlock = false;
|
|
17783
|
-
} else {
|
|
17784
|
-
blockLines.push(line);
|
|
17785
|
-
}
|
|
17963
|
+
for (const para of paragraphs) {
|
|
17964
|
+
if (!para.length) continue;
|
|
17965
|
+
const severity = blockSeverity(para);
|
|
17966
|
+
if (severity === null || blockCount < 10) {
|
|
17967
|
+
if (kept.length) kept.push("");
|
|
17968
|
+
kept.push(...para);
|
|
17969
|
+
if (severity !== null) blockCount += 1;
|
|
17786
17970
|
} else {
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
}
|
|
17790
|
-
if (inBlock && blockLines.length) {
|
|
17791
|
-
if (blockCount < 10) kept.push(...blockLines);
|
|
17792
|
-
else {
|
|
17793
|
-
const sev = (blockLines[0] ?? "").split(/\s+/)[0].toLowerCase();
|
|
17794
|
-
severityCounts[sev] = (severityCounts[sev] ?? 0) + 1;
|
|
17971
|
+
severityCounts[severity] = (severityCounts[severity] ?? 0) + 1;
|
|
17972
|
+
blockCount += 1;
|
|
17795
17973
|
}
|
|
17796
17974
|
}
|
|
17797
17975
|
if (Object.keys(severityCounts).length) {
|
|
17798
|
-
|
|
17799
|
-
|
|
17976
|
+
kept.push(
|
|
17977
|
+
"",
|
|
17978
|
+
`[token-goat: collapsed ${Object.values(severityCounts).reduce((a, b) => a + b, 0)} additional advisory blocks (${Object.entries(severityCounts).map(([s, n]) => `${n} ${s}`).join(", ")})]`
|
|
17979
|
+
);
|
|
17800
17980
|
}
|
|
17801
17981
|
return squeezeBlankLines(kept.join("\n"));
|
|
17802
17982
|
}
|
|
@@ -17872,6 +18052,7 @@ function _compressEslintStanza(text) {
|
|
|
17872
18052
|
if (!currentFile.length) return;
|
|
17873
18053
|
const header = currentFile[0];
|
|
17874
18054
|
const body = currentFile.slice(1);
|
|
18055
|
+
out.push(header);
|
|
17875
18056
|
let perRule = /* @__PURE__ */ new Map();
|
|
17876
18057
|
for (const line of body) {
|
|
17877
18058
|
if (!_ESLINT_LOC_RE.test(line)) {
|
|
@@ -17887,7 +18068,6 @@ function _compressEslintStanza(text) {
|
|
|
17887
18068
|
bucket.push(line);
|
|
17888
18069
|
perRule.set(rule, bucket);
|
|
17889
18070
|
}
|
|
17890
|
-
out.push(header);
|
|
17891
18071
|
out.push(..._emitEslintRules(perRule));
|
|
17892
18072
|
currentFile = [];
|
|
17893
18073
|
}
|
|
@@ -19554,7 +19734,28 @@ function _hunkWhitespaceEolOnlyPairCount(hunkLines) {
|
|
|
19554
19734
|
}
|
|
19555
19735
|
return removed.length;
|
|
19556
19736
|
}
|
|
19557
|
-
function
|
|
19737
|
+
function _hunkDensity(hunkText) {
|
|
19738
|
+
const content = hunkText.split("\n").slice(1);
|
|
19739
|
+
if (content.length === 0) return 0;
|
|
19740
|
+
const changed = content.filter((l) => l.startsWith("+") || l.startsWith("-")).length;
|
|
19741
|
+
return changed / content.length;
|
|
19742
|
+
}
|
|
19743
|
+
function _capHunksByDensity(hunks, maxHunksPerFile) {
|
|
19744
|
+
const real = hunks.slice(1);
|
|
19745
|
+
if (maxHunksPerFile <= 0 || real.length <= maxHunksPerFile) return { hunks, note: null };
|
|
19746
|
+
const scored = real.map((h, i) => ({ i, h, d: _hunkDensity(h) }));
|
|
19747
|
+
const keepSet = new Set(
|
|
19748
|
+
scored.slice().sort((a, b) => b.d - a.d).slice(0, maxHunksPerFile).map((x) => x.i)
|
|
19749
|
+
);
|
|
19750
|
+
const dropped = scored.filter((x) => !keepSet.has(x.i));
|
|
19751
|
+
const avg = dropped.length ? dropped.reduce((a, x) => a + x.d, 0) / dropped.length : 0;
|
|
19752
|
+
const kept = scored.filter((x) => keepSet.has(x.i)).map((x) => x.h);
|
|
19753
|
+
return {
|
|
19754
|
+
hunks: [hunks[0] ?? "", ...kept],
|
|
19755
|
+
note: `[token-goat: ${dropped.length} more hunks, avg density ${avg.toFixed(2)} \u2014 likely whitespace/formatting]`
|
|
19756
|
+
};
|
|
19757
|
+
}
|
|
19758
|
+
function _compressGitDiffBody(stdout, stderr, maxHunksPerFile = 10) {
|
|
19558
19759
|
const MAX_HUNK_CHANGED = 50;
|
|
19559
19760
|
const HUNK_HEAD_KEEP = 20;
|
|
19560
19761
|
const HUNK_TAIL_KEEP = 5;
|
|
@@ -19572,11 +19773,13 @@ function _compressGitDiffBody(stdout, stderr) {
|
|
|
19572
19773
|
outBlocks.push((blockLines[0] ?? "") + "\n" + binaryLine);
|
|
19573
19774
|
continue;
|
|
19574
19775
|
}
|
|
19575
|
-
|
|
19776
|
+
let hunks = splitBlocks(block, _GIT_DIFF_HUNK_RE);
|
|
19576
19777
|
if (hunks.length <= 1) {
|
|
19577
19778
|
outBlocks.push(block);
|
|
19578
19779
|
continue;
|
|
19579
19780
|
}
|
|
19781
|
+
const { hunks: cappedHunks, note: hunkCapNote } = _capHunksByDensity(hunks, maxHunksPerFile);
|
|
19782
|
+
hunks = cappedHunks;
|
|
19580
19783
|
const compressedHunks = [];
|
|
19581
19784
|
for (const hunk of hunks) {
|
|
19582
19785
|
const hunkLines = hunk.split("\n");
|
|
@@ -19623,6 +19826,7 @@ function _compressGitDiffBody(stdout, stderr) {
|
|
|
19623
19826
|
}
|
|
19624
19827
|
}
|
|
19625
19828
|
}
|
|
19829
|
+
if (hunkCapNote) compressedHunks.push(hunkCapNote);
|
|
19626
19830
|
outBlocks.push(compressedHunks.join("\n"));
|
|
19627
19831
|
}
|
|
19628
19832
|
let text = outBlocks.join("\n");
|
|
@@ -19670,7 +19874,13 @@ function _compressGitDiffEnhanced(stdout, stderr, argv) {
|
|
|
19670
19874
|
const flags = new Set(argv);
|
|
19671
19875
|
const isStat = flags.has("--stat") || flags.has("--shortstat") || flags.has("--name-only");
|
|
19672
19876
|
if (isStat) return _compressGitDiffStat(stdout, stderr, argv);
|
|
19673
|
-
|
|
19877
|
+
let maxHunksPerFile;
|
|
19878
|
+
try {
|
|
19879
|
+
maxHunksPerFile = loadConfig().bash_diff.max_hunks_per_file;
|
|
19880
|
+
} catch {
|
|
19881
|
+
maxHunksPerFile = void 0;
|
|
19882
|
+
}
|
|
19883
|
+
return maxHunksPerFile === void 0 ? _compressGitDiffBody(stdout, stderr) : _compressGitDiffBody(stdout, stderr, maxHunksPerFile);
|
|
19674
19884
|
}
|
|
19675
19885
|
var GitDiffFilter = class extends GitBaseFilter {
|
|
19676
19886
|
name = "git-diff";
|
|
@@ -20820,7 +21030,7 @@ var MesonFilter = class extends ToolFilter {
|
|
|
20820
21030
|
}
|
|
20821
21031
|
};
|
|
20822
21032
|
var MSBUILD_ERROR_RE = /.*\(\d+(?:,\d+)?\)\s*:\s*error\s+/;
|
|
20823
|
-
var MSBUILD_WARNING_RE = /(.*?)\((\d+)(
|
|
21033
|
+
var MSBUILD_WARNING_RE = /(.*?)\((\d+)(?:,(\d+))?\)\s*:\s*warning\s+(\w+)/;
|
|
20824
21034
|
var MSBUILD_BUILD_STARTED_RE = /^Build started/;
|
|
20825
21035
|
var MSBUILD_PROJECT_BUILDING_RE = /^------ Build started: Project:/;
|
|
20826
21036
|
var MSBUILD_COPY_RE = /^\s+(?:Copy|CopyFilesToOutputDirectory|CopyToOutputDirectory)\b/;
|
|
@@ -20857,8 +21067,9 @@ var MSBuildFilter = class extends ToolFilter {
|
|
|
20857
21067
|
if (warnMatch) {
|
|
20858
21068
|
const filePath = (warnMatch[1] ?? "").trim();
|
|
20859
21069
|
const lineNum = warnMatch[2] ?? "";
|
|
20860
|
-
const
|
|
20861
|
-
const
|
|
21070
|
+
const colNum = warnMatch[3] ?? "";
|
|
21071
|
+
const code = warnMatch[4] ?? "";
|
|
21072
|
+
const dedupKey = `${filePath}|${lineNum}|${colNum}|${code}`;
|
|
20862
21073
|
if (!seenWarningCodes.has(dedupKey)) {
|
|
20863
21074
|
seenWarningCodes.add(dedupKey);
|
|
20864
21075
|
kept.push(line);
|
|
@@ -21316,7 +21527,7 @@ ${stdout.replace(/\s+$/, "")}` : stderr : stdout;
|
|
|
21316
21527
|
for (const line of benchLines) {
|
|
21317
21528
|
if (CARGO_TEST_RUNNING_RE.test(line)) {
|
|
21318
21529
|
runnerHeaderCount++;
|
|
21319
|
-
if (runnerHeaderCount
|
|
21530
|
+
if (runnerHeaderCount === 1) kept.push(line);
|
|
21320
21531
|
continue;
|
|
21321
21532
|
}
|
|
21322
21533
|
kept.push(line);
|
|
@@ -22519,7 +22730,8 @@ ${stderr.replace(/\s+$/, "")}` : stderr;
|
|
|
22519
22730
|
maybeNote(notes, providerCollapsed, `collapsed ${providerCollapsed} provider install/find lines`);
|
|
22520
22731
|
if (nonEmpty.length > 12) {
|
|
22521
22732
|
let compressed = headTailCompress(nonEmpty, 5, 5, "lines");
|
|
22522
|
-
if (notes.length) compressed = compressed.replace(/\s+$/, "")
|
|
22733
|
+
if (notes.length) compressed = `${compressed.replace(/\s+$/, "")}
|
|
22734
|
+
[token-goat: ${notes.join("; ")}]`;
|
|
22523
22735
|
return compressed;
|
|
22524
22736
|
}
|
|
22525
22737
|
this.emitNotes(kept, notes);
|
|
@@ -22660,7 +22872,11 @@ var AwsCliFilter = class extends ToolFilter {
|
|
|
22660
22872
|
this._JSON_ARRAY_THRESHOLD,
|
|
22661
22873
|
this._JSON_ARRAY_KEEP
|
|
22662
22874
|
);
|
|
22663
|
-
if (compressed !== null)
|
|
22875
|
+
if (compressed !== null) {
|
|
22876
|
+
text = compressed;
|
|
22877
|
+
} else if (text.includes("\n") && text.includes("|")) {
|
|
22878
|
+
text = _compressTable(text, 25);
|
|
22879
|
+
}
|
|
22664
22880
|
}
|
|
22665
22881
|
if (stderr.trim()) {
|
|
22666
22882
|
text = text.trim() ? `${text.replace(/\s+$/, "")}
|
|
@@ -24157,14 +24373,13 @@ function compressGhRunView(text) {
|
|
|
24157
24373
|
}
|
|
24158
24374
|
function compressGhList(text, subcommand) {
|
|
24159
24375
|
const lines = text.split("\n");
|
|
24160
|
-
let
|
|
24376
|
+
let dataStart = 0;
|
|
24161
24377
|
for (let i = 0; i < lines.length; i++) {
|
|
24162
24378
|
if (lines[i].trim()) {
|
|
24163
|
-
|
|
24379
|
+
dataStart = i;
|
|
24164
24380
|
break;
|
|
24165
24381
|
}
|
|
24166
24382
|
}
|
|
24167
|
-
const dataStart = headerIdx + 1;
|
|
24168
24383
|
let dataEnd = lines.length;
|
|
24169
24384
|
for (let i = dataStart; i < lines.length; i++) {
|
|
24170
24385
|
if (!lines[i].trim()) {
|
|
@@ -24519,7 +24734,6 @@ var BanditFilter = class extends ToolFilter {
|
|
|
24519
24734
|
inIssue = false;
|
|
24520
24735
|
issueBuf = [];
|
|
24521
24736
|
currentSeverity = "";
|
|
24522
|
-
if (line.trim()) kept.push(line);
|
|
24523
24737
|
} else {
|
|
24524
24738
|
const sevM = /Severity:\s*(\w+)/i.exec(line);
|
|
24525
24739
|
if (sevM) currentSeverity = sevM[1] ?? "";
|
|
@@ -25049,7 +25263,7 @@ var LsFilter = class _LsFilter extends ToolFilter {
|
|
|
25049
25263
|
const entrySet = new Set(entryIdx);
|
|
25050
25264
|
const keptEntryIdx = new Set(entryIdx.slice(0, _LS_MAX_ENTRIES));
|
|
25051
25265
|
const hiddenCount = entryIdx.length - keptEntryIdx.size;
|
|
25052
|
-
const fileEntries = entryIdx.map((i) => lines[i]).filter((l) => !_DIR_EXE_DIR_ENTRY_RE.test(l));
|
|
25266
|
+
const fileEntries = entryIdx.slice(_LS_MAX_ENTRIES).map((i) => lines[i]).filter((l) => !_DIR_EXE_DIR_ENTRY_RE.test(l));
|
|
25053
25267
|
const extPart = _lsExtSummary(fileEntries);
|
|
25054
25268
|
const hiddenMarker = extPart ? _LS_HIDDEN_MARKER_EXT.replace("{n}", String(hiddenCount)).replace("{ext_summary}", () => extPart) : _LS_HIDDEN_MARKER.replace("{n}", String(hiddenCount));
|
|
25055
25269
|
const out = [];
|
|
@@ -25088,7 +25302,7 @@ var LsFilter = class _LsFilter extends ToolFilter {
|
|
|
25088
25302
|
}
|
|
25089
25303
|
out.push(...entries.slice(0, _LS_MAX_ENTRIES));
|
|
25090
25304
|
const hidden = entries.length - _LS_MAX_ENTRIES;
|
|
25091
|
-
const extPart = _lsExtSummary(entries);
|
|
25305
|
+
const extPart = _lsExtSummary(entries.slice(_LS_MAX_ENTRIES));
|
|
25092
25306
|
if (extPart) {
|
|
25093
25307
|
out.push(_LS_HIDDEN_MARKER_EXT.replace("{n}", String(hidden)).replace("{ext_summary}", () => extPart));
|
|
25094
25308
|
} else {
|
|
@@ -26970,7 +27184,6 @@ var haskellFilter = makeLanguageFilter({
|
|
|
26970
27184
|
{
|
|
26971
27185
|
re: HASKELL_WARNING_RE,
|
|
26972
27186
|
maxPerKey: 3,
|
|
26973
|
-
keyLen: 40,
|
|
26974
27187
|
note: (n) => `deduplicated ${n} repeated warning(s)`
|
|
26975
27188
|
}
|
|
26976
27189
|
]
|
|
@@ -27572,13 +27785,20 @@ var Sqlite3Filter = class _Sqlite3Filter extends ToolFilter {
|
|
|
27572
27785
|
if (nonEmpty.length && schemaLines.length / nonEmpty.length >= 0.5) return merged;
|
|
27573
27786
|
const errors = lines.filter((ln) => SQLITE3_ERROR_RE.test(ln));
|
|
27574
27787
|
const dataLines = lines.filter((ln) => !SQLITE3_ERROR_RE.test(ln));
|
|
27575
|
-
const nonEmptyData = dataLines.filter((ln) => ln.trim());
|
|
27576
27788
|
const kept = [...errors];
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27789
|
+
let headerRows = [];
|
|
27790
|
+
let bodyLines = dataLines;
|
|
27791
|
+
if (dataLines.length >= 2 && dataLines[0].trim() && /^[\s\-+]+$/.test(dataLines[1]) && dataLines[1].trim()) {
|
|
27792
|
+
headerRows = dataLines.slice(0, 2);
|
|
27793
|
+
bodyLines = dataLines.slice(2);
|
|
27794
|
+
}
|
|
27795
|
+
kept.push(...headerRows);
|
|
27796
|
+
const nonEmptyBody = bodyLines.filter((ln) => ln.trim());
|
|
27797
|
+
if (nonEmptyBody.length > _Sqlite3Filter.ROW_THRESHOLD) {
|
|
27798
|
+
kept.push(...nonEmptyBody.slice(0, _Sqlite3Filter.KEEP_ROWS));
|
|
27799
|
+
kept.push(`[token-goat: ${nonEmptyBody.length} rows (showing first ${_Sqlite3Filter.KEEP_ROWS})]`);
|
|
27580
27800
|
} else {
|
|
27581
|
-
kept.push(...
|
|
27801
|
+
kept.push(...bodyLines);
|
|
27582
27802
|
}
|
|
27583
27803
|
return this.finalize(kept);
|
|
27584
27804
|
}
|
|
@@ -27786,6 +28006,26 @@ var SysPackageFilter = class extends ToolFilter {
|
|
|
27786
28006
|
}
|
|
27787
28007
|
};
|
|
27788
28008
|
var sysPackageFilter = new SysPackageFilter();
|
|
28009
|
+
var WmicFilter = class extends ToolFilter {
|
|
28010
|
+
name = "wmic";
|
|
28011
|
+
binaries = /* @__PURE__ */ new Set(["wmic"]);
|
|
28012
|
+
compressBody(stdout, stderr, _exitCode, _argv) {
|
|
28013
|
+
const merged = this.combineOutput(stdout, stderr);
|
|
28014
|
+
const lines = merged.split("\n");
|
|
28015
|
+
let padCount = 0;
|
|
28016
|
+
const kept = lines.map(
|
|
28017
|
+
(line) => line.replace(/[ \t]{2,}/g, () => {
|
|
28018
|
+
padCount++;
|
|
28019
|
+
return " ";
|
|
28020
|
+
}).replace(/[ \t]+$/, "")
|
|
28021
|
+
);
|
|
28022
|
+
const notes = [];
|
|
28023
|
+
maybeNote(notes, padCount, `collapsed ${padCount} runs of fixed-width column padding`);
|
|
28024
|
+
this.emitNotes(kept, notes);
|
|
28025
|
+
return this.finalize(kept);
|
|
28026
|
+
}
|
|
28027
|
+
};
|
|
28028
|
+
var wmicFilter = new WmicFilter();
|
|
27789
28029
|
var PROTOC_INFO_RE = /^\[libprotobuf INFO /;
|
|
27790
28030
|
var PROTOC_LIB_WARN_RE = /^\[libprotobuf (?:WARNING|ERROR) /;
|
|
27791
28031
|
var PROTOC_DIAG_RE = /^[^\s:][^:]*\.proto:\d+:\d+: (?:warning|error):/i;
|
|
@@ -28482,6 +28722,7 @@ var MISC_FILTERS = [
|
|
|
28482
28722
|
sqlite3Filter,
|
|
28483
28723
|
redisCLIFilter,
|
|
28484
28724
|
sysPackageFilter,
|
|
28725
|
+
wmicFilter,
|
|
28485
28726
|
protocFilter,
|
|
28486
28727
|
sassFilter,
|
|
28487
28728
|
toxFilter,
|
|
@@ -28566,7 +28807,7 @@ function detectFromCommand(command) {
|
|
|
28566
28807
|
|
|
28567
28808
|
// src/shell.ts
|
|
28568
28809
|
import * as fs18 from "node:fs";
|
|
28569
|
-
import * as
|
|
28810
|
+
import * as path22 from "node:path";
|
|
28570
28811
|
var WSL_LAUNCHER_SEGMENTS = /* @__PURE__ */ new Set(["system32", "syswow64", "windowsapps"]);
|
|
28571
28812
|
function isExecutable(p) {
|
|
28572
28813
|
try {
|
|
@@ -28579,15 +28820,15 @@ function isWslLauncherDir(dir) {
|
|
|
28579
28820
|
return dir.toLowerCase().split(/[\\/]+/).some((seg) => WSL_LAUNCHER_SEGMENTS.has(seg));
|
|
28580
28821
|
}
|
|
28581
28822
|
function locateBashOnPath(pathValue, isExe = isExecutable) {
|
|
28582
|
-
for (const dir of (pathValue ?? "").split(
|
|
28823
|
+
for (const dir of (pathValue ?? "").split(path22.delimiter)) {
|
|
28583
28824
|
if (!dir || isWslLauncherDir(dir)) continue;
|
|
28584
|
-
const cand =
|
|
28825
|
+
const cand = path22.join(dir, "bash.exe");
|
|
28585
28826
|
if (isExe(cand)) return cand;
|
|
28586
28827
|
}
|
|
28587
28828
|
return null;
|
|
28588
28829
|
}
|
|
28589
28830
|
function knownGitBashPaths() {
|
|
28590
|
-
const localPrograms = process.env["LOCALAPPDATA"] ?
|
|
28831
|
+
const localPrograms = process.env["LOCALAPPDATA"] ? path22.join(process.env["LOCALAPPDATA"], "Programs") : void 0;
|
|
28591
28832
|
const bases = [
|
|
28592
28833
|
process.env["ProgramFiles"],
|
|
28593
28834
|
process.env["ProgramFiles(x86)"],
|
|
@@ -28597,8 +28838,8 @@ function knownGitBashPaths() {
|
|
|
28597
28838
|
const out = [];
|
|
28598
28839
|
for (const base of bases) {
|
|
28599
28840
|
if (!base) continue;
|
|
28600
|
-
out.push(
|
|
28601
|
-
out.push(
|
|
28841
|
+
out.push(path22.join(base, "Git", "bin", "bash.exe"));
|
|
28842
|
+
out.push(path22.join(base, "Git", "usr", "bin", "bash.exe"));
|
|
28602
28843
|
}
|
|
28603
28844
|
return out;
|
|
28604
28845
|
}
|
|
@@ -28647,8 +28888,8 @@ function resolveCdHintPath(rawCmd, filePath, cwd) {
|
|
|
28647
28888
|
function surgicalHintFor(hintPath, isEnv, isConfig, isDoc) {
|
|
28648
28889
|
return isEnv ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to read one function or class.';
|
|
28649
28890
|
}
|
|
28650
|
-
function surgicalHintForConfigDoc(filePath, isConfig, isDoc) {
|
|
28651
|
-
return isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
28891
|
+
function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql) {
|
|
28892
|
+
return isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isSql ? 'Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
28652
28893
|
}
|
|
28653
28894
|
function stripOutputPipeline(cmd) {
|
|
28654
28895
|
let inSingle = false;
|
|
@@ -28697,6 +28938,15 @@ function extractCommand(event) {
|
|
|
28697
28938
|
const cmd = event.toolInput["command"];
|
|
28698
28939
|
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
28699
28940
|
}
|
|
28941
|
+
var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick)\b/i;
|
|
28942
|
+
var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:.*\s)?--(?:\s|$)/i;
|
|
28943
|
+
function isHeadMovingGitCommand(cmd) {
|
|
28944
|
+
if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
|
|
28945
|
+
if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
|
|
28946
|
+
return true;
|
|
28947
|
+
}
|
|
28948
|
+
var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
|
|
28949
|
+
var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
|
|
28700
28950
|
function isTempPath(fp) {
|
|
28701
28951
|
const norm = fp.replace(/\\/g, "/");
|
|
28702
28952
|
return /^\/tmp\//i.test(norm) || /\/var\/folders\//i.test(norm) || /AppData\/Local\/Temp\//i.test(norm) || norm.startsWith("/c/Users/") && norm.includes("/AppData/Local/Temp/");
|
|
@@ -28720,6 +28970,12 @@ function classifyFileExtensions(filePath) {
|
|
|
28720
28970
|
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
28721
28971
|
return { isDoc, isEnv, isConfig, isSql };
|
|
28722
28972
|
}
|
|
28973
|
+
function classifyDocConfig(filePath) {
|
|
28974
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
28975
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
28976
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
28977
|
+
return { isDoc, isConfig, isSql };
|
|
28978
|
+
}
|
|
28723
28979
|
function classifyCatPath(filePath, cmd0) {
|
|
28724
28980
|
if (isTempPath(filePath)) return null;
|
|
28725
28981
|
const flags = classifyFileExtensions(filePath);
|
|
@@ -28871,9 +29127,8 @@ function extractHeadFile(cmd) {
|
|
|
28871
29127
|
if (filePath === void 0) return null;
|
|
28872
29128
|
if (isTempPath(filePath)) return null;
|
|
28873
29129
|
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
28874
|
-
const isDoc =
|
|
28875
|
-
|
|
28876
|
-
return { filePath, isDoc, isConfig };
|
|
29130
|
+
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
29131
|
+
return { filePath, isDoc, isConfig, isSql };
|
|
28877
29132
|
}
|
|
28878
29133
|
function extractSedRange(cmd) {
|
|
28879
29134
|
const m = /^sed\s+-n\s+['"](?:\d+,\d+p)(?:;\d+,\d+p)*['"]\s+(?:"([^"]+)"|'([^']+)'|(\S+))(?:\s+2>\/dev\/null)?\s*$/.exec(cmd);
|
|
@@ -28964,9 +29219,8 @@ function extractNodeFileRead(cmd) {
|
|
|
28964
29219
|
const filePath = readSync2[1];
|
|
28965
29220
|
if (isOrchestratorStateFile(filePath)) return null;
|
|
28966
29221
|
if (isTempPath(filePath)) return null;
|
|
28967
|
-
const isDoc =
|
|
28968
|
-
|
|
28969
|
-
return { filePath, isDoc, isConfig };
|
|
29222
|
+
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
29223
|
+
return { filePath, isDoc, isConfig, isSql };
|
|
28970
29224
|
}
|
|
28971
29225
|
const requireM = /require\(['"]([^'"]+\.json)['"]\)/i.exec(cmd);
|
|
28972
29226
|
if (requireM?.[1]) {
|
|
@@ -28974,7 +29228,7 @@ function extractNodeFileRead(cmd) {
|
|
|
28974
29228
|
if (filePath.includes("node_modules")) return null;
|
|
28975
29229
|
if (isOrchestratorStateFile(filePath)) return null;
|
|
28976
29230
|
if (isTempPath(filePath)) return null;
|
|
28977
|
-
return { filePath, isDoc: false, isConfig: true };
|
|
29231
|
+
return { filePath, isDoc: false, isConfig: true, isSql: false };
|
|
28978
29232
|
}
|
|
28979
29233
|
return null;
|
|
28980
29234
|
}
|
|
@@ -28990,9 +29244,8 @@ function extractTailFile(cmd) {
|
|
|
28990
29244
|
if (!filePath) return null;
|
|
28991
29245
|
if (isTempPath(filePath)) return null;
|
|
28992
29246
|
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
28993
|
-
const isDoc =
|
|
28994
|
-
|
|
28995
|
-
return { filePath, isDoc, isConfig };
|
|
29247
|
+
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
29248
|
+
return { filePath, isDoc, isConfig, isSql };
|
|
28996
29249
|
}
|
|
28997
29250
|
function extractGetContentTail(cmd) {
|
|
28998
29251
|
const tailMatch = /-Tail\s+(\d+)/i.exec(cmd);
|
|
@@ -29004,26 +29257,24 @@ function extractGetContentTail(cmd) {
|
|
|
29004
29257
|
const afterCmd = cmd.slice(getnMatch[0].length);
|
|
29005
29258
|
const beforeTail = afterCmd.split(/-Tail/i)[0]?.trim() ?? "";
|
|
29006
29259
|
const afterTail = afterCmd.split(/-Tail\s+\d+/i)[1]?.trim() ?? "";
|
|
29007
|
-
const filePath = beforeTail || afterTail;
|
|
29260
|
+
const filePath = (beforeTail || afterTail).replace(/^["']|["']$/g, "");
|
|
29008
29261
|
if (!filePath) return null;
|
|
29009
29262
|
if (isTempPath(filePath)) return null;
|
|
29010
29263
|
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
|
|
29011
|
-
const isDoc =
|
|
29012
|
-
|
|
29013
|
-
return { filePath, isDoc, isConfig };
|
|
29264
|
+
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
29265
|
+
return { filePath, isDoc, isConfig, isSql };
|
|
29014
29266
|
}
|
|
29015
29267
|
function extractGetContentSelectFirst(cmd) {
|
|
29016
29268
|
const m = /^(Get-Content|gc)\s+([^|]+)\s*\|\s*(Select-Object|select)\s+(-First\s+(\d+))/i.exec(cmd);
|
|
29017
29269
|
if (!m) return null;
|
|
29018
|
-
const filePath = m[2]?.trim() ?? "";
|
|
29270
|
+
const filePath = (m[2]?.trim() ?? "").replace(/^["']|["']$/g, "");
|
|
29019
29271
|
const n = parseInt(m[5] ?? "0", 10);
|
|
29020
29272
|
if (n <= 10) return null;
|
|
29021
29273
|
if (!filePath) return null;
|
|
29022
29274
|
if (isTempPath(filePath)) return null;
|
|
29023
29275
|
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
|
|
29024
|
-
const isDoc =
|
|
29025
|
-
|
|
29026
|
-
return { filePath, isDoc, isConfig };
|
|
29276
|
+
const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
|
|
29277
|
+
return { filePath, isDoc, isConfig, isSql };
|
|
29027
29278
|
}
|
|
29028
29279
|
function extractTasksOutput(cmd) {
|
|
29029
29280
|
const taskOutputRe = /[/\\]tasks[/\\]([a-z0-9]+)\.output$/;
|
|
@@ -29137,10 +29388,10 @@ function extractTgSurgicalRead(cmd, cwd) {
|
|
|
29137
29388
|
}
|
|
29138
29389
|
function curlHasUnsafeFlags(cmd) {
|
|
29139
29390
|
if (/-X\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return true;
|
|
29140
|
-
if (/--request
|
|
29391
|
+
if (/--request(?:\s+|=)(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return true;
|
|
29141
29392
|
if (/(?:^|\s)(?:-d|--data(?:-raw|-binary|-urlencode)?|-F|--form)\b/.test(cmd)) return true;
|
|
29142
29393
|
if (/(?:^|\s)(?:-u|--user)\b/.test(cmd)) return true;
|
|
29143
|
-
if (
|
|
29394
|
+
if (/(?:-H|--header)(?:\s+|=)['"]?Authorization/i.test(cmd)) return true;
|
|
29144
29395
|
return false;
|
|
29145
29396
|
}
|
|
29146
29397
|
function isCurlGetCommand(cmd) {
|
|
@@ -29150,9 +29401,9 @@ function isCurlGetCommand(cmd) {
|
|
|
29150
29401
|
function isReadOnlyGhApi(cmd) {
|
|
29151
29402
|
if (!/^gh\s+api\b/.test(cmd)) return false;
|
|
29152
29403
|
if (/\bgraphql\b/.test(cmd)) return false;
|
|
29153
|
-
if (
|
|
29154
|
-
if (/(?:-X|--method)
|
|
29155
|
-
if (/(?:-X|--method)
|
|
29404
|
+
if (/(?:-H|--header)(?:\s+|=)['"]?Authorization/i.test(cmd)) return false;
|
|
29405
|
+
if (/(?:-X|--method)(?:\s+|=)GET\b/i.test(cmd)) return true;
|
|
29406
|
+
if (/(?:-X|--method)(?:\s+|=)(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/i.test(cmd)) return false;
|
|
29156
29407
|
if (/\s(?:-f|-F|--field|--raw-field|--input)\b/.test(cmd)) return false;
|
|
29157
29408
|
return true;
|
|
29158
29409
|
}
|
|
@@ -29430,29 +29681,31 @@ function preBashHandlerInner(event) {
|
|
|
29430
29681
|
const sedRange = extractSedRange(cmd);
|
|
29431
29682
|
if (sedRange !== null) {
|
|
29432
29683
|
const { filePath, ranges } = sedRange;
|
|
29684
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29433
29685
|
recordStat("session_hint", 0, 0);
|
|
29434
|
-
const sedDedupKey = resolveIndexPath(
|
|
29686
|
+
const sedDedupKey = resolveIndexPath(hintPath, preHookCwd ?? process.cwd());
|
|
29435
29687
|
const overlapHints = [];
|
|
29436
29688
|
const freshRanges = [];
|
|
29437
29689
|
for (const [start, end] of ranges) {
|
|
29438
29690
|
const priorOverlap = findRangeOverlap(getFileLineRanges(sedDedupKey), start, end);
|
|
29439
29691
|
recordFileLineRange(sedDedupKey, start, end);
|
|
29440
29692
|
if (priorOverlap !== null) {
|
|
29441
|
-
overlapHints.push(sedOverlapHint(
|
|
29693
|
+
overlapHints.push(sedOverlapHint(hintPath, priorOverlap, start, end));
|
|
29442
29694
|
} else {
|
|
29443
29695
|
freshRanges.push([start, end]);
|
|
29444
29696
|
}
|
|
29445
29697
|
}
|
|
29446
29698
|
const hints = [...overlapHints];
|
|
29447
|
-
if (freshRanges.length > 0) hints.push(sedRangeHint(
|
|
29699
|
+
if (freshRanges.length > 0) hints.push(sedRangeHint(hintPath, freshRanges));
|
|
29448
29700
|
return contextOutput(hints.join(" "));
|
|
29449
29701
|
}
|
|
29450
29702
|
const catJsonPipe = extractCatJsonPipe(cmd);
|
|
29451
29703
|
if (catJsonPipe !== null) {
|
|
29452
29704
|
const { filePath } = catJsonPipe;
|
|
29705
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29453
29706
|
recordStat("session_hint", 0, 0);
|
|
29454
29707
|
return contextOutput(
|
|
29455
|
-
'`cat | jq` loads the whole file. Use `token-goat config-get "' +
|
|
29708
|
+
'`cat | jq` loads the whole file. Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to slice one value.'
|
|
29456
29709
|
);
|
|
29457
29710
|
}
|
|
29458
29711
|
const catResult = extractCatFile(cmd);
|
|
@@ -29487,7 +29740,7 @@ function preBashHandlerInner(event) {
|
|
|
29487
29740
|
recordStat("session_hint", 0, 0);
|
|
29488
29741
|
const lead = "`Get-Content` via a `powershell -Command` wrapper bypasses read hooks and loads the entire file into context. ";
|
|
29489
29742
|
if (isSql) {
|
|
29490
|
-
return
|
|
29743
|
+
return contextOutput(lead + 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.');
|
|
29491
29744
|
}
|
|
29492
29745
|
const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
|
|
29493
29746
|
return cdStripped ? contextOutput(lead + hint) : denyOutput(lead + hint);
|
|
@@ -29519,33 +29772,37 @@ function preBashHandlerInner(event) {
|
|
|
29519
29772
|
}
|
|
29520
29773
|
const tailResult = extractTailFile(cmd);
|
|
29521
29774
|
if (tailResult !== null) {
|
|
29522
|
-
const { filePath, isDoc, isConfig } = tailResult;
|
|
29775
|
+
const { filePath, isDoc, isConfig, isSql } = tailResult;
|
|
29776
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29523
29777
|
recordStat("session_hint", 0, 0);
|
|
29524
|
-
return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(
|
|
29778
|
+
return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
29525
29779
|
}
|
|
29526
29780
|
const headResult = extractHeadFile(cmd);
|
|
29527
29781
|
if (headResult !== null) {
|
|
29528
|
-
const { filePath, isDoc, isConfig } = headResult;
|
|
29782
|
+
const { filePath, isDoc, isConfig, isSql } = headResult;
|
|
29783
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29529
29784
|
recordStat("session_hint", 0, 0);
|
|
29530
|
-
return contextOutput("`head` bypasses read hooks. " + surgicalHintForConfigDoc(
|
|
29785
|
+
return contextOutput("`head` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
29531
29786
|
}
|
|
29532
29787
|
const gcTailResult = extractGetContentTail(cmd);
|
|
29533
29788
|
if (gcTailResult !== null) {
|
|
29534
|
-
const { filePath, isDoc, isConfig } = gcTailResult;
|
|
29789
|
+
const { filePath, isDoc, isConfig, isSql } = gcTailResult;
|
|
29790
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29535
29791
|
recordStat("session_hint", 0, 0);
|
|
29536
|
-
return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(
|
|
29792
|
+
return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
29537
29793
|
}
|
|
29538
29794
|
const gcSelectResult = extractGetContentSelectFirst(cmd);
|
|
29539
29795
|
if (gcSelectResult !== null) {
|
|
29540
|
-
const { filePath, isDoc, isConfig } = gcSelectResult;
|
|
29796
|
+
const { filePath, isDoc, isConfig, isSql } = gcSelectResult;
|
|
29797
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29541
29798
|
recordStat("session_hint", 0, 0);
|
|
29542
|
-
return contextOutput("`Select-Object -First` bypasses read hooks. " + surgicalHintForConfigDoc(
|
|
29799
|
+
return contextOutput("`Select-Object -First` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
|
|
29543
29800
|
}
|
|
29544
29801
|
const nodeRead = extractNodeFileRead(cmd);
|
|
29545
29802
|
if (nodeRead !== null) {
|
|
29546
|
-
const { filePath, isDoc, isConfig } = nodeRead;
|
|
29803
|
+
const { filePath, isDoc, isConfig, isSql } = nodeRead;
|
|
29547
29804
|
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29548
|
-
const hint = isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to extract a specific symbol.';
|
|
29805
|
+
const hint = isSql ? 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to extract a specific symbol.';
|
|
29549
29806
|
recordStat("session_hint", 0, 0);
|
|
29550
29807
|
return cdStripped ? contextOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint) : denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
|
|
29551
29808
|
}
|
|
@@ -29558,9 +29815,10 @@ function preBashHandlerInner(event) {
|
|
|
29558
29815
|
const mdHeadingGrep = extractMarkdownHeadingGrep(cmd);
|
|
29559
29816
|
if (mdHeadingGrep !== null) {
|
|
29560
29817
|
const { filePath } = mdHeadingGrep;
|
|
29818
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29561
29819
|
recordStat("session_hint", 0, 0);
|
|
29562
29820
|
return contextOutput(
|
|
29563
|
-
'Use `token-goat outline "' +
|
|
29821
|
+
'Use `token-goat outline "' + hintPath + '"` to get all headings with line ranges \u2014 then `token-goat section "' + hintPath + '::Heading"` to read one section.'
|
|
29564
29822
|
);
|
|
29565
29823
|
}
|
|
29566
29824
|
const rgSymbol = extractRgSymbolSearch(cmd);
|
|
@@ -29574,9 +29832,10 @@ function preBashHandlerInner(event) {
|
|
|
29574
29832
|
const rgStructural = extractRgStructuralSearch(cmd);
|
|
29575
29833
|
if (rgStructural !== null) {
|
|
29576
29834
|
const { filePath } = rgStructural;
|
|
29835
|
+
const hintPath = cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath;
|
|
29577
29836
|
recordStat("session_hint", 0, 0);
|
|
29578
29837
|
return contextOutput(
|
|
29579
|
-
'Searching for code definitions with `rg`/`grep` is slower than surgical reads. Use `token-goat skeleton "' +
|
|
29838
|
+
'Searching for code definitions with `rg`/`grep` is slower than surgical reads. Use `token-goat skeleton "' + hintPath + '"` to see all symbols with line numbers, or `token-goat outline "' + hintPath + '"` for symbols with docstrings and line ranges.'
|
|
29580
29839
|
);
|
|
29581
29840
|
}
|
|
29582
29841
|
const monitoringHint = getMonitoringRecallHint(cmd);
|
|
@@ -29738,6 +29997,27 @@ async function postBashHandler(event) {
|
|
|
29738
29997
|
const exitCode = extractExitCode(event.raw);
|
|
29739
29998
|
const cwd = getCwd(event) ?? null;
|
|
29740
29999
|
const cacheMinBytes = loadConfig().bash_compress.cache_min_bytes;
|
|
30000
|
+
if (isHeadMovingGitCommand(cmd) && (exitCode === null || exitCode === 0)) {
|
|
30001
|
+
const gitDir = cwd ?? process.cwd();
|
|
30002
|
+
let diffBase = "HEAD@{1}";
|
|
30003
|
+
if (ORIG_HEAD_ELIGIBLE_GIT_RE.test(cmd)) {
|
|
30004
|
+
const reflogTop = runGit(["reflog", "-1", "--format=%gs", "HEAD"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
30005
|
+
if (reflogTop.exitCode === 0 && ORIG_HEAD_REFLOG_MSG_RE.test(reflogTop.stdout.trim())) {
|
|
30006
|
+
const origHead = runGit(["rev-parse", "--verify", "-q", "ORIG_HEAD"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
30007
|
+
if (origHead.exitCode === 0 && origHead.stdout.trim() !== "") diffBase = "ORIG_HEAD";
|
|
30008
|
+
}
|
|
30009
|
+
}
|
|
30010
|
+
const mutationDiff = runGit(["diff", "--name-only", diffBase, "HEAD"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
30011
|
+
if (mutationDiff.exitCode === 0) {
|
|
30012
|
+
const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
|
|
30013
|
+
const repoRoot = toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : gitDir;
|
|
30014
|
+
for (const rel of mutationDiff.stdout.split("\n")) {
|
|
30015
|
+
const trimmed = rel.trim();
|
|
30016
|
+
if (trimmed.length === 0) continue;
|
|
30017
|
+
enqueueDirtyPathSafe(resolveIndexPath(trimmed, repoRoot), { alreadyResolved: true });
|
|
30018
|
+
}
|
|
30019
|
+
}
|
|
30020
|
+
}
|
|
29741
30021
|
const curlDl = extractCurlDownload(cmd);
|
|
29742
30022
|
if (curlDl !== null && (exitCode === null || exitCode === 0)) {
|
|
29743
30023
|
const resolvedOutputPath = resolveIndexPath(curlDl.outputPath, cwd ?? process.cwd());
|
|
@@ -29832,7 +30112,9 @@ function postBashOutputHandler(event) {
|
|
|
29832
30112
|
if (getToolName(event) !== "BashOutput" || !event.sessionId) return passOutput();
|
|
29833
30113
|
const bashId = getBashId(getToolInput(event));
|
|
29834
30114
|
if (bashId === void 0) return passOutput();
|
|
29835
|
-
const
|
|
30115
|
+
const rawOutput = extractToolResultText(event.raw);
|
|
30116
|
+
if (!rawOutput) return passOutput();
|
|
30117
|
+
const output = redactSecrets(rawOutput).text;
|
|
29836
30118
|
if (!output) return passOutput();
|
|
29837
30119
|
const prior = getBashOutput(pollCacheId(event.sessionId, bashId));
|
|
29838
30120
|
const minBytes = loadConfig().bash_compress.cache_min_bytes;
|
|
@@ -29866,10 +30148,109 @@ ${delta}`
|
|
|
29866
30148
|
}
|
|
29867
30149
|
registerHook("post_tool_use", postBashOutputHandler, { toolName: "BashOutput" });
|
|
29868
30150
|
|
|
30151
|
+
// src/hooks_taskoutput.ts
|
|
30152
|
+
function pollCacheId2(sessionId, taskId) {
|
|
30153
|
+
return `taskpoll_${shortFingerprint(`${sessionId}\0taskoutput\0${taskId}`)}`;
|
|
30154
|
+
}
|
|
30155
|
+
function storePollSnapshot2(sessionId, taskId, output) {
|
|
30156
|
+
const id = pollCacheId2(sessionId, taskId);
|
|
30157
|
+
const entry = {
|
|
30158
|
+
id,
|
|
30159
|
+
command: `taskoutput:${taskId}`,
|
|
30160
|
+
output,
|
|
30161
|
+
exitCode: 0,
|
|
30162
|
+
storedAt: Date.now(),
|
|
30163
|
+
sizeBytes: Buffer.byteLength(output, "utf-8")
|
|
30164
|
+
};
|
|
30165
|
+
storeBlob(BASH_OUTPUT_SUBDIR, id, entry);
|
|
30166
|
+
}
|
|
30167
|
+
function collapseRepeatedLines(text) {
|
|
30168
|
+
return dedupeConsecutive(text.split("\n")).join("\n");
|
|
30169
|
+
}
|
|
30170
|
+
function getTaskId(toolInput) {
|
|
30171
|
+
const value = toolInput["task_id"];
|
|
30172
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
30173
|
+
}
|
|
30174
|
+
function postTaskOutputHandler(event) {
|
|
30175
|
+
try {
|
|
30176
|
+
if (getToolName(event) !== "TaskOutput" || !event.sessionId) return passOutput();
|
|
30177
|
+
const taskId = getTaskId(getToolInput(event));
|
|
30178
|
+
if (taskId === void 0) return passOutput();
|
|
30179
|
+
const rawOutput = extractToolResultText(event.raw);
|
|
30180
|
+
if (!rawOutput) return passOutput();
|
|
30181
|
+
const output = redactSecrets(rawOutput).text;
|
|
30182
|
+
if (!output) return passOutput();
|
|
30183
|
+
const prior = getBashOutput(pollCacheId2(event.sessionId, taskId));
|
|
30184
|
+
const minBytes = loadConfig().bash_compress.cache_min_bytes;
|
|
30185
|
+
if (prior === null) {
|
|
30186
|
+
storePollSnapshot2(event.sessionId, taskId, output);
|
|
30187
|
+
const collapsed = collapseRepeatedLines(output);
|
|
30188
|
+
if (collapsed === output) return passOutput();
|
|
30189
|
+
const savings = Buffer.byteLength(output, "utf-8") - Buffer.byteLength(collapsed, "utf-8");
|
|
30190
|
+
if (savings < minBytes) return passOutput();
|
|
30191
|
+
return {
|
|
30192
|
+
hookType: "rewriteOutput",
|
|
30193
|
+
updatedOutput: collapsed
|
|
30194
|
+
};
|
|
30195
|
+
}
|
|
30196
|
+
if (output === prior.output) {
|
|
30197
|
+
storePollSnapshot2(event.sessionId, taskId, output);
|
|
30198
|
+
if (Buffer.byteLength(output, "utf-8") < minBytes) return passOutput();
|
|
30199
|
+
return {
|
|
30200
|
+
hookType: "rewriteOutput",
|
|
30201
|
+
updatedOutput: `[token-goat: task_id ${taskId} unchanged since last poll -- no new output]`
|
|
30202
|
+
};
|
|
30203
|
+
}
|
|
30204
|
+
if (!output.startsWith(prior.output)) {
|
|
30205
|
+
storePollSnapshot2(event.sessionId, taskId, output);
|
|
30206
|
+
return passOutput();
|
|
30207
|
+
}
|
|
30208
|
+
const delta = output.slice(prior.output.length);
|
|
30209
|
+
storePollSnapshot2(event.sessionId, taskId, output);
|
|
30210
|
+
if (Buffer.byteLength(delta, "utf-8") < minBytes) return passOutput();
|
|
30211
|
+
return {
|
|
30212
|
+
hookType: "rewriteOutput",
|
|
30213
|
+
updatedOutput: `[token-goat: task_id ${taskId} delta since last poll]
|
|
30214
|
+
${collapseRepeatedLines(delta)}`
|
|
30215
|
+
};
|
|
30216
|
+
} catch {
|
|
30217
|
+
return passOutput();
|
|
30218
|
+
}
|
|
30219
|
+
}
|
|
30220
|
+
registerHook("post_tool_use", postTaskOutputHandler, { toolName: "TaskOutput" });
|
|
30221
|
+
|
|
30222
|
+
// src/hooks_exitplanmode.ts
|
|
30223
|
+
var PLAN_OMIT_POINTER = "[token-goat: plan body omitted -- identical to this call's own tool_input, already saved to the plans file]";
|
|
30224
|
+
var APPROVED_PLAN_MARKER = "## Approved Plan:";
|
|
30225
|
+
function postExitPlanModeHandler(event) {
|
|
30226
|
+
try {
|
|
30227
|
+
if (getToolName(event) !== "ExitPlanMode") return passOutput();
|
|
30228
|
+
const output = extractToolResultText(event.raw);
|
|
30229
|
+
if (!output) return passOutput();
|
|
30230
|
+
const markerIndex = output.indexOf(APPROVED_PLAN_MARKER);
|
|
30231
|
+
if (markerIndex === -1) return passOutput();
|
|
30232
|
+
const planValue = getToolInput(event)["plan"];
|
|
30233
|
+
if (typeof planValue !== "string" || planValue.trim() === "") return passOutput();
|
|
30234
|
+
const plan = planValue.trim();
|
|
30235
|
+
const suffix = output.slice(markerIndex + APPROVED_PLAN_MARKER.length).trim();
|
|
30236
|
+
if (suffix !== plan && !suffix.includes(plan) && !plan.includes(suffix)) return passOutput();
|
|
30237
|
+
const prefix = output.slice(0, markerIndex + APPROVED_PLAN_MARKER.length);
|
|
30238
|
+
const rewritten = `${prefix}
|
|
30239
|
+
${PLAN_OMIT_POINTER}`;
|
|
30240
|
+
return {
|
|
30241
|
+
hookType: "rewriteOutput",
|
|
30242
|
+
updatedOutput: rewritten
|
|
30243
|
+
};
|
|
30244
|
+
} catch {
|
|
30245
|
+
return passOutput();
|
|
30246
|
+
}
|
|
30247
|
+
}
|
|
30248
|
+
registerHook("post_tool_use", postExitPlanModeHandler, { toolName: "ExitPlanMode" });
|
|
30249
|
+
|
|
29869
30250
|
// src/mcp_cache.ts
|
|
29870
30251
|
var MCP_MAX_CACHE_BYTES = 2 * 1024 * 1024;
|
|
29871
30252
|
var READ_VERBS_RE = /(?:^|_)(?:get|list|search|read|view|fetch|describe|export|download|find|show|query|resolve|context)(?=_|$)/i;
|
|
29872
|
-
var MUTATING_VERBS_RE = /^request(?=_|$)|(?:^|_)(?:create|update|delete|send|write|push|post|remove|label|unlabel|merge|modify|draft|fork|reply|move|rename|set|add|
|
|
30253
|
+
var MUTATING_VERBS_RE = /^(?:request|run)(?=_|$)|(?:^|_)(?:create|update|delete|send|write|push|post|remove|label|unlabel|merge|modify|draft|fork|reply|move|rename|set|add|execute|close|copy|upload|insert|revoke|reset|archive|restore|annotate|register|unregister|star|unstar|like|unlike|vote|block|unblock|invite|kick|ban|click|fill|press|type|navigate|evaluate|drag|hover|handle|snapshot|wait|emulate|new|select|resize|audit|apply|commit|grant|deploy|toggle|pin|trigger|finalize|approve|cancel|sync)(?=_|$)/i;
|
|
29873
30254
|
var STATE_CHANGING_INPUT_KEYS = ["createIfEmpty", "clear", "save_to_disk"];
|
|
29874
30255
|
function isMcpReadOnly(toolName, toolInput) {
|
|
29875
30256
|
if (!toolName.startsWith("mcp__")) {
|
|
@@ -29902,21 +30283,28 @@ function mcpInputPreview(toolInput) {
|
|
|
29902
30283
|
}
|
|
29903
30284
|
function storeMcpOutput(sessionId, toolName, toolInput, resultText) {
|
|
29904
30285
|
if (!sessionId || !resultText) return null;
|
|
29905
|
-
const
|
|
29906
|
-
if (
|
|
30286
|
+
const rawSizeBytes = Buffer.byteLength(resultText, "utf-8");
|
|
30287
|
+
if (rawSizeBytes > MCP_MAX_CACHE_BYTES) return null;
|
|
29907
30288
|
const id = mcpOutputId(sessionId, mcpHash(toolName, toolInput));
|
|
29908
30289
|
const label = `mcp:${toolName} ${mcpInputPreview(toolInput)}`.trim();
|
|
30290
|
+
const redactedOutput = redactSecrets(resultText).text;
|
|
29909
30291
|
const entry = {
|
|
29910
30292
|
id,
|
|
29911
30293
|
command: label,
|
|
29912
|
-
output:
|
|
30294
|
+
output: redactedOutput,
|
|
29913
30295
|
exitCode: 0,
|
|
29914
30296
|
storedAt: Date.now(),
|
|
29915
|
-
|
|
30297
|
+
// Sized off the redacted output, not the raw pre-redaction resultText (rawSizeBytes is only
|
|
30298
|
+
// the cache-eligibility gate above) -- mirrors bash_output_cache.ts's storeBashOutput, whose
|
|
30299
|
+
// sizeBytes is likewise computed from redactedOutput. Sizing off the raw text here left
|
|
30300
|
+
// mcp-audit's per-call token estimate and `mcp-history`'s byte column reporting a stale byte
|
|
30301
|
+
// count for any entry a secret was actually stripped from, out of sync with the stored/served
|
|
30302
|
+
// (redacted, shorter) output.
|
|
30303
|
+
sizeBytes: Buffer.byteLength(redactedOutput, "utf-8")
|
|
29916
30304
|
};
|
|
29917
30305
|
if (!storeBlob(BASH_OUTPUT_SUBDIR, id, entry)) return null;
|
|
29918
30306
|
indexRecallEntry("mcp", id, label, `${label}
|
|
29919
|
-
${
|
|
30307
|
+
${redactedOutput}`, entry.storedAt);
|
|
29920
30308
|
return id;
|
|
29921
30309
|
}
|
|
29922
30310
|
function getMcpOutput(sessionId, toolName, toolInput, ttlMs = Number.POSITIVE_INFINITY) {
|
|
@@ -30041,9 +30429,34 @@ var BROWSER_NETWORK_STRIP_KEYS = /* @__PURE__ */ new Set([
|
|
|
30041
30429
|
"responseCookies",
|
|
30042
30430
|
"cookies"
|
|
30043
30431
|
]);
|
|
30432
|
+
var BROWSER_SNAPSHOT_METHOD_RE = /(?:^|_)(?:take_snapshot|read_page|page_snapshot|snapshot)$/i;
|
|
30433
|
+
var SNAPSHOT_NAME_MAX_CHARS = 200;
|
|
30434
|
+
var SNAPSHOT_NODE_LINE_RE = /^( *)(uid=\S+) (\S+) "((?:[^"\\]|\\.)*)"(.*)$/;
|
|
30435
|
+
function truncateSnapshotLine(line) {
|
|
30436
|
+
const m = SNAPSHOT_NODE_LINE_RE.exec(line);
|
|
30437
|
+
if (!m) return line;
|
|
30438
|
+
const [, indent, uid, role, name2, rest] = m;
|
|
30439
|
+
if (name2 === void 0) return line;
|
|
30440
|
+
if (name2.length <= SNAPSHOT_NAME_MAX_CHARS) return line;
|
|
30441
|
+
const elided = name2.length - SNAPSHOT_NAME_MAX_CHARS;
|
|
30442
|
+
return `${indent}${uid} ${role} "${name2.slice(0, SNAPSHOT_NAME_MAX_CHARS)} \u2026 [${elided} chars elided]"${rest}`;
|
|
30443
|
+
}
|
|
30444
|
+
function compressSnapshotText(resultText) {
|
|
30445
|
+
const compressed = resultText.split("\n").map(truncateSnapshotLine).join("\n");
|
|
30446
|
+
if (compressed.length >= resultText.length) return null;
|
|
30447
|
+
if (compressed.length > resultText.length * (1 - PACK_MIN_SAVINGS_RATIO)) return null;
|
|
30448
|
+
return compressed;
|
|
30449
|
+
}
|
|
30044
30450
|
function compressBrowserMcpResult(toolName, resultText) {
|
|
30045
30451
|
if (!BROWSER_TOOL_RE.test(toolName)) return null;
|
|
30046
30452
|
const method = toolName.split("__").pop() || "";
|
|
30453
|
+
if (BROWSER_SNAPSHOT_METHOD_RE.test(method)) {
|
|
30454
|
+
try {
|
|
30455
|
+
return compressSnapshotText(resultText);
|
|
30456
|
+
} catch {
|
|
30457
|
+
return null;
|
|
30458
|
+
}
|
|
30459
|
+
}
|
|
30047
30460
|
let shouldStrip = null;
|
|
30048
30461
|
if (BROWSER_CONSOLE_METHOD_RE.test(method)) shouldStrip = (key) => BROWSER_CONSOLE_STRIP_KEYS.has(key);
|
|
30049
30462
|
else if (BROWSER_NETWORK_METHOD_RE.test(method)) shouldStrip = (key) => BROWSER_NETWORK_STRIP_KEYS.has(key);
|
|
@@ -30057,8 +30470,81 @@ function compressBrowserMcpResult(toolName, resultText) {
|
|
|
30057
30470
|
const stripped = deepStrip(parsed, shouldStrip);
|
|
30058
30471
|
return finishWithGenericPass(resultText, stripped);
|
|
30059
30472
|
}
|
|
30473
|
+
var GWORKSPACE_TOOL_RE = /^mcp__.*(?:gmail|drive).*__/i;
|
|
30474
|
+
var GWORKSPACE_STRIP_EXACT_KEYS = /* @__PURE__ */ new Set(["htmlBody", "html_body", "raw", "payload"]);
|
|
30475
|
+
var GWORKSPACE_BODY_KEYS = /* @__PURE__ */ new Set(["plaintextBody", "plaintext_body", "body"]);
|
|
30476
|
+
var GWORKSPACE_ATTACHMENT_KEEP_KEYS = /* @__PURE__ */ new Set(["id", "filename", "name", "mimeType", "mime_type", "size", "inline"]);
|
|
30477
|
+
var QUOTED_REPLY_LINE_RE = /^(?:>|On .{0,120} wrote:$|-{2,}\s*Original Message\s*-{2,}$)/i;
|
|
30478
|
+
var FORWARD_HEADER_FROM_RE = /^From:\s/i;
|
|
30479
|
+
var FORWARD_HEADER_CLUSTER_RE = /^(?:Sent|Date|To|Subject):\s/i;
|
|
30480
|
+
var FORWARD_HEADER_CLUSTER_LOOKAHEAD = 3;
|
|
30481
|
+
var FORWARD_HEADER_CLUSTER_MIN_MATCHES = 2;
|
|
30482
|
+
function findQuotedReplyOffset(text) {
|
|
30483
|
+
const lines = text.split("\n");
|
|
30484
|
+
let offset = 0;
|
|
30485
|
+
for (let i = 0; i < lines.length; i++) {
|
|
30486
|
+
const line = lines[i] ?? "";
|
|
30487
|
+
if (QUOTED_REPLY_LINE_RE.test(line)) return offset;
|
|
30488
|
+
if (FORWARD_HEADER_FROM_RE.test(line)) {
|
|
30489
|
+
let siblingMatches = 0;
|
|
30490
|
+
for (let j = i + 1; j < lines.length && j <= i + FORWARD_HEADER_CLUSTER_LOOKAHEAD; j++) {
|
|
30491
|
+
if (FORWARD_HEADER_CLUSTER_RE.test(lines[j] ?? "")) siblingMatches++;
|
|
30492
|
+
}
|
|
30493
|
+
if (siblingMatches >= FORWARD_HEADER_CLUSTER_MIN_MATCHES) return offset;
|
|
30494
|
+
}
|
|
30495
|
+
offset += line.length + 1;
|
|
30496
|
+
}
|
|
30497
|
+
return -1;
|
|
30498
|
+
}
|
|
30499
|
+
function trimQuotedReply(text) {
|
|
30500
|
+
const offset = findQuotedReplyOffset(text);
|
|
30501
|
+
if (offset < 0) return text;
|
|
30502
|
+
return text.slice(0, offset).trimEnd();
|
|
30503
|
+
}
|
|
30504
|
+
function trimGmailBodies(value) {
|
|
30505
|
+
if (Array.isArray(value)) return value.map(trimGmailBodies);
|
|
30506
|
+
if (value === null || typeof value !== "object") return value;
|
|
30507
|
+
const out = {};
|
|
30508
|
+
for (const [key, val] of Object.entries(value)) {
|
|
30509
|
+
out[key] = GWORKSPACE_BODY_KEYS.has(key) && typeof val === "string" ? trimQuotedReply(val) : trimGmailBodies(val);
|
|
30510
|
+
}
|
|
30511
|
+
return out;
|
|
30512
|
+
}
|
|
30513
|
+
function summarizeAttachments(value) {
|
|
30514
|
+
if (Array.isArray(value)) return value.map(summarizeAttachments);
|
|
30515
|
+
if (value === null || typeof value !== "object") return value;
|
|
30516
|
+
const out = {};
|
|
30517
|
+
for (const [key, val] of Object.entries(value)) {
|
|
30518
|
+
if (key === "attachments" && Array.isArray(val)) {
|
|
30519
|
+
out[key] = val.map((att) => {
|
|
30520
|
+
if (att === null || typeof att !== "object") return att;
|
|
30521
|
+
const kept = {};
|
|
30522
|
+
for (const [k, v] of Object.entries(att)) {
|
|
30523
|
+
if (GWORKSPACE_ATTACHMENT_KEEP_KEYS.has(k)) kept[k] = v;
|
|
30524
|
+
}
|
|
30525
|
+
return kept;
|
|
30526
|
+
});
|
|
30527
|
+
} else {
|
|
30528
|
+
out[key] = summarizeAttachments(val);
|
|
30529
|
+
}
|
|
30530
|
+
}
|
|
30531
|
+
return out;
|
|
30532
|
+
}
|
|
30533
|
+
function compressGWorkspaceMcpResult(toolName, resultText) {
|
|
30534
|
+
if (!GWORKSPACE_TOOL_RE.test(toolName)) return null;
|
|
30535
|
+
let parsed;
|
|
30536
|
+
try {
|
|
30537
|
+
parsed = JSON.parse(resultText);
|
|
30538
|
+
} catch {
|
|
30539
|
+
return null;
|
|
30540
|
+
}
|
|
30541
|
+
const stripped = deepStrip(parsed, (key) => GWORKSPACE_STRIP_EXACT_KEYS.has(key));
|
|
30542
|
+
const trimmed = trimGmailBodies(stripped);
|
|
30543
|
+
const summarized = summarizeAttachments(trimmed);
|
|
30544
|
+
return finishWithGenericPass(resultText, summarized);
|
|
30545
|
+
}
|
|
30060
30546
|
function compressMcpResultWithPacks(toolName, resultText) {
|
|
30061
|
-
return compressGithubMcpResult(toolName, resultText) ?? compressBrowserMcpResult(toolName, resultText);
|
|
30547
|
+
return compressGithubMcpResult(toolName, resultText) ?? compressBrowserMcpResult(toolName, resultText) ?? compressGWorkspaceMcpResult(toolName, resultText);
|
|
30062
30548
|
}
|
|
30063
30549
|
|
|
30064
30550
|
// src/hooks_mcp.ts
|
|
@@ -30081,23 +30567,29 @@ function preMcpHandler(event) {
|
|
|
30081
30567
|
}
|
|
30082
30568
|
function postMcpHandler(event) {
|
|
30083
30569
|
const toolName = getToolName(event);
|
|
30084
|
-
if (!toolName || !event.sessionId) return passOutput();
|
|
30570
|
+
if (!toolName || !event.sessionId || !toolName.startsWith("mcp__")) return passOutput();
|
|
30085
30571
|
const toolInput = getToolInput(event);
|
|
30086
|
-
if (!isMcpReadOnly(toolName, toolInput)) return passOutput();
|
|
30087
30572
|
if (isMcpErrorResponse(event.raw)) return passOutput();
|
|
30088
|
-
const
|
|
30089
|
-
if (getMcpOutput(event.sessionId, toolName, toolInput, ttlMs)) return passOutput();
|
|
30573
|
+
const readOnly = isMcpReadOnly(toolName, toolInput);
|
|
30090
30574
|
const resultText = extractToolResultText(event.raw);
|
|
30091
30575
|
if (!resultText) return passOutput();
|
|
30092
|
-
|
|
30093
|
-
if (
|
|
30576
|
+
let id = null;
|
|
30577
|
+
if (readOnly) {
|
|
30578
|
+
const ttlMs = loadConfig().hints.mcp_dedup_ttl_secs * 1e3;
|
|
30579
|
+
if (getMcpOutput(event.sessionId, toolName, toolInput, ttlMs)) return passOutput();
|
|
30580
|
+
id = storeMcpOutput(event.sessionId, toolName, toolInput, resultText);
|
|
30581
|
+
}
|
|
30582
|
+
if (resultText.length >= MCP_COMPRESS_MIN_BYTES && process.env["TOKEN_GOAT_MCP_COMPRESS"] !== "0") {
|
|
30094
30583
|
const compressed = compressMcpResultWithPacks(toolName, resultText) ?? compressMcpResult(resultText);
|
|
30095
30584
|
if (compressed !== null) {
|
|
30096
|
-
|
|
30097
|
-
|
|
30098
|
-
|
|
30585
|
+
if (id === null) id = storeMcpOutput(event.sessionId, toolName, toolInput, resultText);
|
|
30586
|
+
if (id !== null) {
|
|
30587
|
+
return {
|
|
30588
|
+
hookType: "rewriteOutput",
|
|
30589
|
+
updatedOutput: `[token-goat: compressed, full via mcp-output ${id}]
|
|
30099
30590
|
${compressed}`
|
|
30100
|
-
|
|
30591
|
+
};
|
|
30592
|
+
}
|
|
30101
30593
|
}
|
|
30102
30594
|
}
|
|
30103
30595
|
return passOutput();
|
|
@@ -30252,7 +30744,7 @@ registerHook("post_tool_use", postBrowserImageHandler);
|
|
|
30252
30744
|
|
|
30253
30745
|
// src/baseline.ts
|
|
30254
30746
|
import * as fs19 from "node:fs";
|
|
30255
|
-
import * as
|
|
30747
|
+
import * as path23 from "node:path";
|
|
30256
30748
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
30257
30749
|
"node_modules",
|
|
30258
30750
|
".git",
|
|
@@ -30282,6 +30774,7 @@ function walkProject(rootDir, opts = {}) {
|
|
|
30282
30774
|
const languages = {};
|
|
30283
30775
|
const stack = [rootDir];
|
|
30284
30776
|
const excludeTests = opts.excludeTests === true;
|
|
30777
|
+
const includeEmbeddableDocuments = opts.includeEmbeddableDocuments === true;
|
|
30285
30778
|
const extraSkipDirs = loadConfig().indexing.skip_dirs;
|
|
30286
30779
|
while (stack.length > 0 && files.length < MAX_FILES_SCANNED) {
|
|
30287
30780
|
const dir = stack.pop();
|
|
@@ -30293,7 +30786,7 @@ function walkProject(rootDir, opts = {}) {
|
|
|
30293
30786
|
continue;
|
|
30294
30787
|
}
|
|
30295
30788
|
for (const entry of entries) {
|
|
30296
|
-
const full =
|
|
30789
|
+
const full = path23.join(dir, entry.name);
|
|
30297
30790
|
if (entry.isDirectory()) {
|
|
30298
30791
|
if (SKIP_DIRS.has(entry.name) || extraSkipDirs.includes(entry.name)) continue;
|
|
30299
30792
|
if (entry.name.startsWith(".") && entry.name !== ".") {
|
|
@@ -30302,7 +30795,7 @@ function walkProject(rootDir, opts = {}) {
|
|
|
30302
30795
|
stack.push(full);
|
|
30303
30796
|
} else if (entry.isFile()) {
|
|
30304
30797
|
const lang = detectLanguage(full);
|
|
30305
|
-
if (lang === "unknown") continue;
|
|
30798
|
+
if (lang === "unknown" && !(includeEmbeddableDocuments && isEmbeddableDocument(full))) continue;
|
|
30306
30799
|
if (excludeTests && isTestFile(full)) continue;
|
|
30307
30800
|
files.push(full);
|
|
30308
30801
|
languages[lang] = (languages[lang] ?? 0) + 1;
|
|
@@ -30338,9 +30831,11 @@ function fetchTopSymbols(limit, dbPath, rootDir) {
|
|
|
30338
30831
|
}
|
|
30339
30832
|
}
|
|
30340
30833
|
function buildProjectMap(rootDir = process.cwd(), opts = {}) {
|
|
30341
|
-
const root =
|
|
30342
|
-
const
|
|
30343
|
-
const
|
|
30834
|
+
const root = path23.resolve(rootDir);
|
|
30835
|
+
const config = loadConfig();
|
|
30836
|
+
const { files, languages } = walkProject(root, { excludeTests: config.repomap.exclude_tests });
|
|
30837
|
+
const compact = opts.compact === true || files.length > config.repomap.compact_file_threshold;
|
|
30838
|
+
const symbolLimit = compact ? 10 : 30;
|
|
30344
30839
|
const topSymbols = fetchTopSymbols(symbolLimit, globalDbPath(), root);
|
|
30345
30840
|
const recentFiles = files.map((f) => {
|
|
30346
30841
|
let mtime;
|
|
@@ -30350,18 +30845,19 @@ function buildProjectMap(rootDir = process.cwd(), opts = {}) {
|
|
|
30350
30845
|
mtime = 0;
|
|
30351
30846
|
}
|
|
30352
30847
|
return { f, mtime };
|
|
30353
|
-
}).sort((a, b) => b.mtime - a.mtime).slice(0,
|
|
30848
|
+
}).sort((a, b) => b.mtime - a.mtime).slice(0, compact ? 5 : 15).map((x) => path23.relative(root, x.f));
|
|
30354
30849
|
return {
|
|
30355
30850
|
rootDir: root,
|
|
30356
30851
|
fileCount: files.length,
|
|
30357
30852
|
languages,
|
|
30358
30853
|
topSymbols,
|
|
30359
|
-
recentFiles
|
|
30854
|
+
recentFiles,
|
|
30855
|
+
compact
|
|
30360
30856
|
};
|
|
30361
30857
|
}
|
|
30362
30858
|
function formatProjectMap(map2, compact = false) {
|
|
30363
30859
|
const lines = [];
|
|
30364
|
-
const rel =
|
|
30860
|
+
const rel = path23.basename(map2.rootDir);
|
|
30365
30861
|
lines.push(`# Project map: ${rel}`);
|
|
30366
30862
|
lines.push(`Files: ${map2.fileCount}`);
|
|
30367
30863
|
const langPairs = Object.entries(map2.languages).sort((a, b) => b[1] - a[1]);
|
|
@@ -30374,7 +30870,7 @@ function formatProjectMap(map2, compact = false) {
|
|
|
30374
30870
|
if (compact) {
|
|
30375
30871
|
lines.push(`- ${s.name} (${s.kind})`);
|
|
30376
30872
|
} else {
|
|
30377
|
-
const loc = `${
|
|
30873
|
+
const loc = `${path23.basename(s.filePath)}:${s.lineStart}-${s.lineEnd}`;
|
|
30378
30874
|
lines.push(`- ${s.name} (${s.kind}) \u2014 ${loc}`);
|
|
30379
30875
|
}
|
|
30380
30876
|
}
|
|
@@ -30398,7 +30894,7 @@ function buildSubagentBriefing() {
|
|
|
30398
30894
|
lines.push("## Session briefing (for context)");
|
|
30399
30895
|
try {
|
|
30400
30896
|
const map2 = buildProjectMap(process.cwd(), { compact: true });
|
|
30401
|
-
const mapText = formatProjectMap(map2,
|
|
30897
|
+
const mapText = formatProjectMap(map2, map2.compact);
|
|
30402
30898
|
lines.push(mapText);
|
|
30403
30899
|
} catch {
|
|
30404
30900
|
}
|