token-goat 2.6.18 → 2.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/token-goat-hook.mjs +636 -89
- package/dist/token-goat.mjs +637 -89
- package/package.json +1 -1
package/dist/token-goat-hook.mjs
CHANGED
|
@@ -49,7 +49,7 @@ var init_define_import_meta_env = __esm({
|
|
|
49
49
|
import { createRequire } from "node:module";
|
|
50
50
|
function resolveVersion() {
|
|
51
51
|
if (true) {
|
|
52
|
-
return "2.6.
|
|
52
|
+
return "2.6.19";
|
|
53
53
|
}
|
|
54
54
|
const require2 = createRequire(import.meta.url);
|
|
55
55
|
const pkg = require2("../package.json");
|
|
@@ -3212,7 +3212,7 @@ function markerExists(current, marker) {
|
|
|
3212
3212
|
}
|
|
3213
3213
|
const resolved = fs7.realpathSync(markerPath);
|
|
3214
3214
|
const rel = path8.relative(path8.resolve(current), path8.resolve(resolved));
|
|
3215
|
-
return !rel.startsWith("..");
|
|
3215
|
+
return !rel.startsWith("..") && !path8.isAbsolute(rel);
|
|
3216
3216
|
} catch {
|
|
3217
3217
|
return false;
|
|
3218
3218
|
}
|
|
@@ -4561,6 +4561,33 @@ CREATE TABLE IF NOT EXISTS hint_suppression_probes (
|
|
|
4561
4561
|
PRIMARY KEY (category, harness)
|
|
4562
4562
|
);
|
|
4563
4563
|
|
|
4564
|
+
-- Free-text architecture/rationale notes (the "why" layer -- see notes.ts), attached either to
|
|
4565
|
+
-- a whole file (symbol = '') or to one specific indexed symbol within it (symbol = that
|
|
4566
|
+
-- symbol's name). '' rather than NULL for the whole-file case because SQLite's UNIQUE treats
|
|
4567
|
+
-- NULLs as pairwise-distinct (never conflicting with each other), which would let note-add
|
|
4568
|
+
-- accumulate unlimited duplicate whole-file notes for the same file instead of upserting one;
|
|
4569
|
+
-- '' is a real, comparable value so UNIQUE(file_path, symbol) enforces "at most one note per
|
|
4570
|
+
-- attachment point" for both cases identically. 'fingerprint' is a SHA-256 digest (see
|
|
4571
|
+
-- fingerprintContent in fingerprint.ts) captured at write time of exactly what the note
|
|
4572
|
+
-- describes -- the resolved symbol's current body text for a symbol-scoped note, or a stable
|
|
4573
|
+
-- digest of the file's current top-level symbol manifest (name:kind:line-range per symbol,
|
|
4574
|
+
-- sorted) for a file-scoped note -- so 'token-goat note-list --stale-only' can recompute the
|
|
4575
|
+
-- same fingerprint against the live index later and flag a mismatch (see notes.ts's
|
|
4576
|
+
-- isNoteStale). Staleness detection is purely advisory: nothing here ever auto-rewrites or
|
|
4577
|
+
-- deletes a note's content, only flags that the code it describes has moved since it was
|
|
4578
|
+
-- written -- a human/agent re-review decides what to do with a stale note.
|
|
4579
|
+
CREATE TABLE IF NOT EXISTS notes (
|
|
4580
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4581
|
+
file_path TEXT NOT NULL,
|
|
4582
|
+
symbol TEXT NOT NULL DEFAULT '',
|
|
4583
|
+
content TEXT NOT NULL,
|
|
4584
|
+
fingerprint TEXT NOT NULL,
|
|
4585
|
+
created_at REAL NOT NULL,
|
|
4586
|
+
updated_at REAL NOT NULL,
|
|
4587
|
+
UNIQUE(file_path, symbol)
|
|
4588
|
+
);
|
|
4589
|
+
CREATE INDEX IF NOT EXISTS idx_notes_file_folded ON notes(TG_LOWER(file_path));
|
|
4590
|
+
|
|
4564
4591
|
-- Baseline for skill_version_drift.ts's one-shot nudge: the token-goat CLI version (and its
|
|
4565
4592
|
-- flat command-name set, JSON-encoded) active the moment the token-goat skill's body was
|
|
4566
4593
|
-- last (re)loaded into this session -- see hooks_skill.ts's postSkillHandler. A session that
|
|
@@ -4626,7 +4653,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
4626
4653
|
VALUES (new.row_id, new.label, new.content);
|
|
4627
4654
|
END;
|
|
4628
4655
|
`;
|
|
4629
|
-
SCHEMA_VERSION =
|
|
4656
|
+
SCHEMA_VERSION = 8;
|
|
4630
4657
|
MIGRATIONS = {
|
|
4631
4658
|
// v1 -> v2: adds files.embed_sha, tracked separately from files.sha so embedding freshness can be gated independently of parse freshness (see makeIndexer in worker.ts). A pre-existing v1 database's `files` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, so a genuine ALTER TABLE failure is never silently lost.
|
|
4632
4659
|
1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
|
|
@@ -5108,7 +5135,7 @@ function _renderByDaySection(stats) {
|
|
|
5108
5135
|
function share(d) {
|
|
5109
5136
|
return _tokenOrByteShare(d.tokens, d.bytes, stats.totals.tokens, stats.totals.bytes);
|
|
5110
5137
|
}
|
|
5111
|
-
for (const d of [...stats.by_day].sort((a, b) => b.date.
|
|
5138
|
+
for (const d of [...stats.by_day].sort((a, b) => b.date < a.date ? -1 : b.date > a.date ? 1 : 0)) {
|
|
5112
5139
|
const s = share(d);
|
|
5113
5140
|
lines2.push(
|
|
5114
5141
|
_tableRow({
|
|
@@ -5718,6 +5745,7 @@ var init_stats = __esm({
|
|
|
5718
5745
|
docx_text: SOURCE_READ,
|
|
5719
5746
|
transcript_outline: SOURCE_READ,
|
|
5720
5747
|
transcript: SOURCE_READ,
|
|
5748
|
+
video_chapters: SOURCE_READ,
|
|
5721
5749
|
coverage_report_gaps: SOURCE_READ,
|
|
5722
5750
|
json_query: SOURCE_READ,
|
|
5723
5751
|
json_outline: SOURCE_READ,
|
|
@@ -5735,6 +5763,14 @@ var init_stats = __esm({
|
|
|
5735
5763
|
session_slice: SOURCE_READ,
|
|
5736
5764
|
gdrive_sections: SOURCE_READ,
|
|
5737
5765
|
pr_slice: SOURCE_READ,
|
|
5766
|
+
note_read: SOURCE_READ,
|
|
5767
|
+
note_list: SOURCE_READ,
|
|
5768
|
+
// note-add is a write (like insert-section/replace, which record no stat at all -- neither
|
|
5769
|
+
// has a "full source it replaces" savings concept). It still gets an event-only entry here
|
|
5770
|
+
// (no bytesSaved/tokensSaved argument, same as skill_load) purely so `token-goat note-add`
|
|
5771
|
+
// usage is visible in `token-goat stats --full` at all -- SOURCE_OTHER, not SOURCE_READ,
|
|
5772
|
+
// since it is not a token-savings substitute for a read.
|
|
5773
|
+
note_write: SOURCE_OTHER,
|
|
5738
5774
|
web_fetch: SOURCE_WEB,
|
|
5739
5775
|
injection_detected: SOURCE_WEB,
|
|
5740
5776
|
skill_load: SOURCE_SKILL,
|
|
@@ -5779,6 +5815,7 @@ var init_stats = __esm({
|
|
|
5779
5815
|
"docx-text": /* @__PURE__ */ new Set(["docx_text"]),
|
|
5780
5816
|
"transcript-outline": /* @__PURE__ */ new Set(["transcript_outline"]),
|
|
5781
5817
|
transcript: /* @__PURE__ */ new Set(["transcript"]),
|
|
5818
|
+
"video-chapters": /* @__PURE__ */ new Set(["video_chapters"]),
|
|
5782
5819
|
"coverage-report-gaps": /* @__PURE__ */ new Set(["coverage_report_gaps"]),
|
|
5783
5820
|
"json-query": /* @__PURE__ */ new Set(["json_query"]),
|
|
5784
5821
|
"json-outline": /* @__PURE__ */ new Set(["json_outline"]),
|
|
@@ -5796,6 +5833,9 @@ var init_stats = __esm({
|
|
|
5796
5833
|
"session-slice": /* @__PURE__ */ new Set(["session_slice"]),
|
|
5797
5834
|
"gdrive-sections": /* @__PURE__ */ new Set(["gdrive_sections"]),
|
|
5798
5835
|
"pr-slice": /* @__PURE__ */ new Set(["pr_slice"]),
|
|
5836
|
+
"note-add": /* @__PURE__ */ new Set(["note_write"]),
|
|
5837
|
+
"note-get": /* @__PURE__ */ new Set(["note_read"]),
|
|
5838
|
+
"note-list": /* @__PURE__ */ new Set(["note_list"]),
|
|
5799
5839
|
npm: /* @__PURE__ */ new Set([
|
|
5800
5840
|
"bash_compress:npm_install",
|
|
5801
5841
|
"bash_compress:npm_ci",
|
|
@@ -8237,6 +8277,7 @@ function formatHeadingTree(headings, filePath) {
|
|
|
8237
8277
|
const lines2 = [];
|
|
8238
8278
|
lines2.push(`Large markdown file (${headings.length} headings). Use token-goat section to read a specific section:`);
|
|
8239
8279
|
lines2.push(` token-goat section "${filePath}::Heading Name"`);
|
|
8280
|
+
lines2.push(` Tip: an unambiguous heading prefix also resolves (e.g. "Lesson 16" instead of the full heading text) \u2014 shorter to type and avoids shell-quoting issues with punctuation in long headings.`);
|
|
8240
8281
|
lines2.push(``);
|
|
8241
8282
|
lines2.push(`Sections:`);
|
|
8242
8283
|
let headingsAdded = 0;
|
|
@@ -11051,12 +11092,12 @@ function parseSectionOrdinal(heading) {
|
|
|
11051
11092
|
const match2 = heading.match(/^(.*?)(?:#(\d+))?$/);
|
|
11052
11093
|
if (!match2) return [heading, 1];
|
|
11053
11094
|
const baseHeading = match2[1] || heading;
|
|
11054
|
-
const
|
|
11055
|
-
return [baseHeading,
|
|
11095
|
+
const ordinal2 = match2[2] ? Math.max(1, parseInt(match2[2], 10)) : 1;
|
|
11096
|
+
return [baseHeading, ordinal2];
|
|
11056
11097
|
}
|
|
11057
11098
|
function extractNamedSection(body, heading) {
|
|
11058
11099
|
if (!body || !heading) return null;
|
|
11059
|
-
const [baseHeading,
|
|
11100
|
+
const [baseHeading, ordinal2] = parseSectionOrdinal(heading);
|
|
11060
11101
|
const headingLower = stripLower(baseHeading);
|
|
11061
11102
|
const lines2 = body.split("\n");
|
|
11062
11103
|
let matchCount = 0;
|
|
@@ -11066,7 +11107,7 @@ function extractNamedSection(body, heading) {
|
|
|
11066
11107
|
const headingText = stripLower(stripped.slice(3));
|
|
11067
11108
|
if (headingText === headingLower) {
|
|
11068
11109
|
matchCount++;
|
|
11069
|
-
if (matchCount ===
|
|
11110
|
+
if (matchCount === ordinal2) {
|
|
11070
11111
|
startIdx = i + 1;
|
|
11071
11112
|
break;
|
|
11072
11113
|
}
|
|
@@ -12326,6 +12367,11 @@ function isNodeModulesPath(p) {
|
|
|
12326
12367
|
const check2 = foldPath(p);
|
|
12327
12368
|
return check2.includes("/node_modules/") || check2.includes("\\node_modules\\");
|
|
12328
12369
|
}
|
|
12370
|
+
function relPathWithinRoot(root, target) {
|
|
12371
|
+
const rel = path20.relative(root, target).replace(/\\/g, "/");
|
|
12372
|
+
if (rel.startsWith("..") || path20.isAbsolute(rel)) return null;
|
|
12373
|
+
return rel;
|
|
12374
|
+
}
|
|
12329
12375
|
function _isDocFile(filePath) {
|
|
12330
12376
|
const lower = filePath.toLowerCase();
|
|
12331
12377
|
return lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".markdown") || lower.endsWith(".rst");
|
|
@@ -12490,7 +12536,8 @@ function loadSnapshotDiff(sessionId, normalized, basename19) {
|
|
|
12490
12536
|
}
|
|
12491
12537
|
function scanCrossSessionManifests(projectRoot, projectHash2, filePath, ttlSecs) {
|
|
12492
12538
|
try {
|
|
12493
|
-
const relPath =
|
|
12539
|
+
const relPath = relPathWithinRoot(projectRoot, filePath);
|
|
12540
|
+
if (relPath === null) return false;
|
|
12494
12541
|
const foldedRelPath = foldPath(relPath);
|
|
12495
12542
|
const manifests = readAllSessionManifests(projectHash2, ttlSecs);
|
|
12496
12543
|
for (const data of manifests) {
|
|
@@ -12534,7 +12581,7 @@ function isProtectedRecentRead(normalized, n) {
|
|
|
12534
12581
|
if (n <= 0) return false;
|
|
12535
12582
|
const ranked = Array.from(getSessionFiles().entries()).sort((a, b) => {
|
|
12536
12583
|
const byRecency = b[1].lastReadAt - a[1].lastReadAt;
|
|
12537
|
-
return byRecency !== 0 ? byRecency : a[0]
|
|
12584
|
+
return byRecency !== 0 ? byRecency : a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;
|
|
12538
12585
|
});
|
|
12539
12586
|
const rank = ranked.findIndex(([filePath]) => filePath === normalized);
|
|
12540
12587
|
return rank !== -1 && rank < n;
|
|
@@ -12778,8 +12825,7 @@ function preReadHandlerInner(event) {
|
|
|
12778
12825
|
if (!project) {
|
|
12779
12826
|
project = makeProjectAt(cwd);
|
|
12780
12827
|
}
|
|
12781
|
-
|
|
12782
|
-
if (!relPath.startsWith("..")) {
|
|
12828
|
+
if (relPathWithinRoot(project.root, normalized) !== null) {
|
|
12783
12829
|
const ttlSecs = config2.hints.cross_session_read_dedup_ttl_secs;
|
|
12784
12830
|
if (scanCrossSessionManifests(project.root, project.hash, normalized, ttlSecs)) {
|
|
12785
12831
|
recordActualRead(event, normalized);
|
|
@@ -12916,7 +12962,7 @@ function estimateTruncatedLineCount(normalized) {
|
|
|
12916
12962
|
return Infinity;
|
|
12917
12963
|
}
|
|
12918
12964
|
function editAnywayHint(normalized) {
|
|
12919
|
-
return 'To edit it anyway, use `token-goat replace "' + normalized + '" --old-from <oldfile> --new-from <newfile>` for a snippet edit, or `token-goat write-file "' + normalized + "\" --from <newfile>` to rewrite the whole file \u2014 Read/Edit's own precondition can't be satisfied after this deny.";
|
|
12965
|
+
return 'To edit it anyway, use `token-goat replace "' + normalized + '" --old-b64 <base64> --new-b64 <base64>` (preferred \u2014 no temp files needed) or `--old-from <oldfile> --new-from <newfile>` for a snippet edit, or `token-goat write-file "' + normalized + "\" --b64 <base64>` (or `--from <newfile>`) to rewrite the whole file \u2014 Read/Edit's own precondition can't be satisfied after this deny.";
|
|
12920
12966
|
}
|
|
12921
12967
|
function truncatedReadDenyMessage(normalized) {
|
|
12922
12968
|
return 'File was truncated on last read (>33K tokens). Use `token-goat skeleton "' + normalized + '"` for structure or `token-goat read "' + normalized + '::SymbolName"` for one function. ' + editAnywayHint(normalized);
|
|
@@ -12951,8 +12997,8 @@ function postReadHandlerInner(event) {
|
|
|
12951
12997
|
const sessionState = exportSessionState();
|
|
12952
12998
|
const mappedFiles = [];
|
|
12953
12999
|
for (const fileEntry of sessionState.files) {
|
|
12954
|
-
const relPath =
|
|
12955
|
-
if (
|
|
13000
|
+
const relPath = relPathWithinRoot(project.root, fileEntry.path);
|
|
13001
|
+
if (relPath !== null) {
|
|
12956
13002
|
mappedFiles.push({
|
|
12957
13003
|
rel_path: relPath,
|
|
12958
13004
|
hit_count: fileEntry.readCount
|
|
@@ -13895,6 +13941,17 @@ function slideShapes(parsedSlide) {
|
|
|
13895
13941
|
function shapeText(shape) {
|
|
13896
13942
|
return collectTextRuns(shape, "a:t").join(" ").trim();
|
|
13897
13943
|
}
|
|
13944
|
+
function tableRowBlocks(parsedSlide) {
|
|
13945
|
+
const blocks = [];
|
|
13946
|
+
for (const tbl of collectElements(parsedSlide, "a:tbl")) {
|
|
13947
|
+
for (const row of collectElements(tbl, "a:tr")) {
|
|
13948
|
+
const cellTexts = collectElements(row, "a:tc").map((cell) => collectTextRuns(cell, "a:t").join(" ").trim());
|
|
13949
|
+
const rowText = cellTexts.join(" | ").trim();
|
|
13950
|
+
if (rowText.length > 0) blocks.push(rowText);
|
|
13951
|
+
}
|
|
13952
|
+
}
|
|
13953
|
+
return blocks;
|
|
13954
|
+
}
|
|
13898
13955
|
async function slidePathsInPresentationOrder(entries) {
|
|
13899
13956
|
const presXml = decodeZipEntry(entries, "ppt/presentation.xml");
|
|
13900
13957
|
const relsXml = decodeZipEntry(entries, "ppt/_rels/presentation.xml.rels");
|
|
@@ -13994,7 +14051,7 @@ async function pptxSlideText(filePath, slideNumber, includeNotes) {
|
|
|
13994
14051
|
const path63 = slidePaths[slideNumber - 1];
|
|
13995
14052
|
const parsed = await parseSlide(entries, path63);
|
|
13996
14053
|
const shapes = slideShapes(parsed);
|
|
13997
|
-
const blocks = shapes.map(shapeText).filter((t) => t.length > 0);
|
|
14054
|
+
const blocks = [...shapes.map(shapeText).filter((t) => t.length > 0), ...tableRowBlocks(parsed)];
|
|
13998
14055
|
const lines2 = [`# Slide ${slideNumber}`, ...blocks];
|
|
13999
14056
|
if (includeNotes) {
|
|
14000
14057
|
const notes = await notesTextFor(entries, await notesPathFor(entries, path63));
|
|
@@ -14791,9 +14848,6 @@ function extractPhp(content, filePath) {
|
|
|
14791
14848
|
let braceDepth = 0;
|
|
14792
14849
|
let inComment = false;
|
|
14793
14850
|
let mlState = null;
|
|
14794
|
-
function currentClass() {
|
|
14795
|
-
return contextStack.length > 0 ? contextStack[contextStack.length - 1]?.[0] ?? null : null;
|
|
14796
|
-
}
|
|
14797
14851
|
for (let i = 0; i < lines2.length; i++) {
|
|
14798
14852
|
const rawLine = lines2[i] ?? "";
|
|
14799
14853
|
const lineNum = i + 1;
|
|
@@ -14857,7 +14911,9 @@ function extractPhp(content, filePath) {
|
|
|
14857
14911
|
if (clsM) {
|
|
14858
14912
|
const kind = clsM[1] ?? "class";
|
|
14859
14913
|
const name2 = clsM[2] ?? "";
|
|
14860
|
-
const
|
|
14914
|
+
const preLineDepth = braceDepth - openB + closeB;
|
|
14915
|
+
const topFrame2 = contextStack.length > 0 ? contextStack[contextStack.length - 1] : void 0;
|
|
14916
|
+
const parent = topFrame2 !== void 0 && preLineDepth === topFrame2[1] + 1 ? topFrame2[0] : null;
|
|
14861
14917
|
symbols.push(makeLineSymbol(filePath, name2, kind, lineNum, stripped.slice(0, 200), parent ?? void 0));
|
|
14862
14918
|
contextStack.push([name2, braceDepth - openB + closeB, false]);
|
|
14863
14919
|
if (openB > 0 && openB === closeB) {
|
|
@@ -15455,6 +15511,9 @@ function extractScala(content, filePath) {
|
|
|
15455
15511
|
const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
|
|
15456
15512
|
symbols.push(makeLineSymbol(filePath, cname, "class", lineNum, stripped.slice(0, 200), parent));
|
|
15457
15513
|
typeStack.push({ name: cname, startDepth: braceDepth, bodyEntered: false });
|
|
15514
|
+
if (/\bcase\s+class\b/.test(stripped) && !stripStringLiterals(line).includes("{")) {
|
|
15515
|
+
typeStack.pop();
|
|
15516
|
+
}
|
|
15458
15517
|
matched = true;
|
|
15459
15518
|
}
|
|
15460
15519
|
const om = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? OBJECT_RE.exec(stripped) : null;
|
|
@@ -15463,6 +15522,9 @@ function extractScala(content, filePath) {
|
|
|
15463
15522
|
const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
|
|
15464
15523
|
symbols.push(makeLineSymbol(filePath, oname, "object", lineNum, stripped.slice(0, 200), parent));
|
|
15465
15524
|
typeStack.push({ name: oname, startDepth: braceDepth, bodyEntered: false });
|
|
15525
|
+
if (/\bcase\s+object\b/.test(stripped) && !stripStringLiterals(line).includes("{")) {
|
|
15526
|
+
typeStack.pop();
|
|
15527
|
+
}
|
|
15466
15528
|
matched = true;
|
|
15467
15529
|
}
|
|
15468
15530
|
const tm = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? TRAIT_RE.exec(stripped) : null;
|
|
@@ -15550,13 +15612,13 @@ var init_scala = __esm({
|
|
|
15550
15612
|
init_common();
|
|
15551
15613
|
IMPORT_RE3 = /^import\s+([A-Za-z_][A-Za-z0-9_.]*(?:\._)?)/;
|
|
15552
15614
|
BRACE_IMPORT_RE = /^import\s+([A-Za-z_][A-Za-z0-9_.]*)\.\{([^}]*)\}/;
|
|
15553
|
-
CLASS_RE3 = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15554
|
-
OBJECT_RE = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15555
|
-
TRAIT_RE = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15615
|
+
CLASS_RE3 = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*class\s+([A-Za-z_][A-Za-z0-9_]*)(?:\s|\[|\(|:|$)/;
|
|
15616
|
+
OBJECT_RE = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*object\s+([A-Za-z_][A-Za-z0-9_]*)(?:\s|:|$)/;
|
|
15617
|
+
TRAIT_RE = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*trait\s+([A-Za-z_][A-Za-z0-9_]*)(?:\s|\[|:|$)/;
|
|
15556
15618
|
ENUM_RE = /^\s*(?:private|protected)?\s*enum\s+([A-Za-z_][A-Za-z0-9_]*)(?:\s|\[|\(|:|$)/;
|
|
15557
|
-
FUNC_RE2 = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15558
|
-
VAL_RE = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15559
|
-
VAR_RE = /^\s*(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)
|
|
15619
|
+
FUNC_RE2 = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*def\s+([A-Za-z_][A-Za-z0-9_]*|[+\-*/%=!<>&|^~]+)(?:\s*\[|\s*\(|\s*:)/;
|
|
15620
|
+
VAL_RE = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*val\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
15621
|
+
VAR_RE = /^\s*(?:(?:implicit|lazy|sealed|abstract|final|private|protected|override|covariant|contravariant|case)\s+)*var\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
15560
15622
|
}
|
|
15561
15623
|
});
|
|
15562
15624
|
|
|
@@ -15646,8 +15708,9 @@ function extractLua(content, filePath) {
|
|
|
15646
15708
|
funcStack.push({ name: "", endKeywordNeeded: true, isBlock: true });
|
|
15647
15709
|
continue;
|
|
15648
15710
|
}
|
|
15649
|
-
if (
|
|
15650
|
-
|
|
15711
|
+
if (/^(?:end(?:\s+|$))+$/.test(stripped)) {
|
|
15712
|
+
const popCount = (stripped.match(/\bend\b/g) ?? []).length;
|
|
15713
|
+
for (let k = 0; k < popCount && funcStack.length > 0; k++) {
|
|
15651
15714
|
funcStack.pop();
|
|
15652
15715
|
}
|
|
15653
15716
|
}
|
|
@@ -15690,6 +15753,7 @@ function extractElixir(content, filePath) {
|
|
|
15690
15753
|
continue;
|
|
15691
15754
|
}
|
|
15692
15755
|
const opensDoBlock = /\bdo\s*$/.test(stripped);
|
|
15756
|
+
const opensFnBlock = /\bfn\b/.test(stripped) && !/\bend\b/.test(stripped) && /(?:fn|->)\s*$/.test(stripped);
|
|
15693
15757
|
const modM = MODULE_RE.exec(stripped);
|
|
15694
15758
|
if (modM) {
|
|
15695
15759
|
const modName = modM[1] ?? "";
|
|
@@ -15739,7 +15803,7 @@ function extractElixir(content, filePath) {
|
|
|
15739
15803
|
}
|
|
15740
15804
|
continue;
|
|
15741
15805
|
}
|
|
15742
|
-
if (opensDoBlock) {
|
|
15806
|
+
if (opensDoBlock || opensFnBlock) {
|
|
15743
15807
|
moduleStack.push({ name: "", endKeywordNeeded: true, isBlock: true });
|
|
15744
15808
|
continue;
|
|
15745
15809
|
}
|
|
@@ -15815,6 +15879,14 @@ function extractDart(content, filePath) {
|
|
|
15815
15879
|
typeStack.push({ name: mname, startDepth: braceDepth, bodyEntered: false });
|
|
15816
15880
|
matched = true;
|
|
15817
15881
|
}
|
|
15882
|
+
const etm = !matched ? EXTENSION_TYPE_RE.exec(stripped) : null;
|
|
15883
|
+
if (etm) {
|
|
15884
|
+
const etname = etm[1] ?? "";
|
|
15885
|
+
const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
|
|
15886
|
+
symbols.push(makeLineSymbol(filePath, etname, "extension_type", lineNum, stripped.slice(0, 200), parent));
|
|
15887
|
+
typeStack.push({ name: etname, startDepth: braceDepth, bodyEntered: false });
|
|
15888
|
+
matched = true;
|
|
15889
|
+
}
|
|
15818
15890
|
const extm = !matched ? EXTENSION_RE.exec(stripped) : null;
|
|
15819
15891
|
if (extm) {
|
|
15820
15892
|
const extname14 = extm[1] ?? "extension";
|
|
@@ -15865,7 +15937,7 @@ function extractDart(content, filePath) {
|
|
|
15865
15937
|
}
|
|
15866
15938
|
return { symbols, imports };
|
|
15867
15939
|
}
|
|
15868
|
-
var CLASS_RE4, ENUM_RE2, MIXIN_RE, EXTENSION_RE, FUNC_RE5;
|
|
15940
|
+
var CLASS_RE4, ENUM_RE2, MIXIN_RE, EXTENSION_RE, EXTENSION_TYPE_RE, FUNC_RE5;
|
|
15869
15941
|
var init_dart = __esm({
|
|
15870
15942
|
"src/languages/dart.ts"() {
|
|
15871
15943
|
"use strict";
|
|
@@ -15875,6 +15947,7 @@ var init_dart = __esm({
|
|
|
15875
15947
|
ENUM_RE2 = /^enum\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
15876
15948
|
MIXIN_RE = /^(?:base\s+)?mixin\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
15877
15949
|
EXTENSION_RE = /^extension\s+(?:([A-Za-z_][A-Za-z0-9_]*)\s+)?on\s+/;
|
|
15950
|
+
EXTENSION_TYPE_RE = /^extension\s+type\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
15878
15951
|
FUNC_RE5 = /(?:^|\s)(?:static\s+)?(?:(?:void|Future|Stream|async|external)\s+|[A-Za-z_][A-Za-z0-9_<>]*(?:\s*\?)?\s+)([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/;
|
|
15879
15952
|
}
|
|
15880
15953
|
});
|
|
@@ -15901,33 +15974,39 @@ function extractZig(content, filePath) {
|
|
|
15901
15974
|
}
|
|
15902
15975
|
const isIndented = line[0] === " " || line[0] === " ";
|
|
15903
15976
|
let matched = false;
|
|
15904
|
-
|
|
15977
|
+
const outerFrame = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
15978
|
+
const outerDepthInType = outerFrame !== null ? braceDepth - outerFrame.startDepth : 0;
|
|
15979
|
+
const typeDetectionGateOk = scopeStack.length === 0 || outerDepthInType === 1;
|
|
15980
|
+
if (typeDetectionGateOk && (!isIndented || scopeStack.length > 0)) {
|
|
15905
15981
|
const sm = CONTAINER_RE.exec(stripped);
|
|
15906
15982
|
if (sm) {
|
|
15907
15983
|
const sname = sm[1] ?? "";
|
|
15908
15984
|
const skind = sm[2] ?? "struct";
|
|
15909
15985
|
if (sname) {
|
|
15910
|
-
const parent =
|
|
15986
|
+
const parent = outerFrame !== null ? outerFrame.name : void 0;
|
|
15911
15987
|
symbols.push(makeLineSymbol(filePath, sname, skind, lineNum, stripped.slice(0, 200), parent));
|
|
15912
15988
|
scopeStack.push({ name: sname, startDepth: braceDepth, bodyEntered: false });
|
|
15913
15989
|
matched = true;
|
|
15914
15990
|
}
|
|
15915
15991
|
}
|
|
15916
15992
|
}
|
|
15917
|
-
|
|
15993
|
+
const frame = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
15994
|
+
if (!matched && !isIndented && frame === null) {
|
|
15918
15995
|
const fm = FUNC_RE6.exec(stripped);
|
|
15919
15996
|
if (fm) {
|
|
15920
15997
|
const fname = fm[2] ?? "";
|
|
15921
15998
|
symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200)));
|
|
15922
15999
|
matched = true;
|
|
15923
16000
|
}
|
|
15924
|
-
} else if (!matched &&
|
|
15925
|
-
const
|
|
15926
|
-
if (
|
|
15927
|
-
const
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
16001
|
+
} else if (!matched && frame !== null) {
|
|
16002
|
+
const depthInType = braceDepth - frame.startDepth;
|
|
16003
|
+
if (depthInType === 1) {
|
|
16004
|
+
const fm = FUNC_RE6.exec(stripped);
|
|
16005
|
+
if (fm) {
|
|
16006
|
+
const fname = fm[2] ?? "";
|
|
16007
|
+
symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200), frame.name));
|
|
16008
|
+
matched = true;
|
|
16009
|
+
}
|
|
15931
16010
|
}
|
|
15932
16011
|
}
|
|
15933
16012
|
if (!matched && !isIndented) {
|
|
@@ -15948,9 +16027,9 @@ function extractZig(content, filePath) {
|
|
|
15948
16027
|
if (ch === "{") {
|
|
15949
16028
|
braceDepth++;
|
|
15950
16029
|
if (scopeStack.length > 0) {
|
|
15951
|
-
const
|
|
15952
|
-
if (braceDepth >
|
|
15953
|
-
|
|
16030
|
+
const frame2 = scopeStack[scopeStack.length - 1];
|
|
16031
|
+
if (braceDepth > frame2.startDepth) {
|
|
16032
|
+
frame2.bodyEntered = true;
|
|
15954
16033
|
}
|
|
15955
16034
|
}
|
|
15956
16035
|
} else if (ch === "}") {
|
|
@@ -19365,7 +19444,18 @@ var init_parser = __esm({
|
|
|
19365
19444
|
// `visit` already descends into `interface_body`/class bodies to find them.
|
|
19366
19445
|
["method_signature", "method"],
|
|
19367
19446
|
["property_signature", "var"],
|
|
19368
|
-
["abstract_method_signature", "method"]
|
|
19447
|
+
["abstract_method_signature", "method"],
|
|
19448
|
+
// `namespace Foo { ... }` (and the legacy `module Foo { ... }` synonym) parses as
|
|
19449
|
+
// `internal_module`; `declare module "some-string" { ... }` (an ambient module declaration,
|
|
19450
|
+
// common in .d.ts files) parses as `module` -- a distinct node type from either. Neither had a
|
|
19451
|
+
// kind-map entry, so the namespace/module declaration itself was silently invisible to
|
|
19452
|
+
// `symbol`/`outline`/`skeleton`/`read`, even though everything nested inside it still indexed
|
|
19453
|
+
// fine (the walk recurses into every node's children regardless of the parent's kind-map
|
|
19454
|
+
// membership) -- the same container-drop shape already fixed for C++ `namespace_definition`
|
|
19455
|
+
// and Rust `mod_item`. Both node types expose their name on the standard `name` field
|
|
19456
|
+
// (an identifier, nested_identifier, or string), so `nodeName` resolves it without special-casing.
|
|
19457
|
+
["internal_module", "namespace"],
|
|
19458
|
+
["module", "namespace"]
|
|
19369
19459
|
]);
|
|
19370
19460
|
TSJS_FN_SCOPE_TYPES = /* @__PURE__ */ new Set([
|
|
19371
19461
|
"function_declaration",
|
|
@@ -20031,6 +20121,7 @@ function workerHealthCheckMarkerPath(dir) {
|
|
|
20031
20121
|
return path28.join(dir, "worker-healthcheck.marker");
|
|
20032
20122
|
}
|
|
20033
20123
|
function ensureWorkerAlive(dir = dataDir()) {
|
|
20124
|
+
if (process.env["TOKEN_GOAT_NO_WORKER_SPAWN"] === "1") return;
|
|
20034
20125
|
const markerPath = workerHealthCheckMarkerPath(dir);
|
|
20035
20126
|
try {
|
|
20036
20127
|
const stat2 = fs24.statSync(markerPath);
|
|
@@ -24183,7 +24274,7 @@ function tableSectionEndIndex(headers, headerPos, totalLines) {
|
|
|
24183
24274
|
}
|
|
24184
24275
|
return totalLines;
|
|
24185
24276
|
}
|
|
24186
|
-
function resolveHeaderPos(headers, base,
|
|
24277
|
+
function resolveHeaderPos(headers, base, ordinal2) {
|
|
24187
24278
|
const target = base.toLowerCase();
|
|
24188
24279
|
const normalizedTarget = normalizeHeading(base).toLowerCase();
|
|
24189
24280
|
const strippedTarget = normalizeHeadingStrip(base).toLowerCase();
|
|
@@ -24204,12 +24295,12 @@ function resolveHeaderPos(headers, base, ordinal) {
|
|
|
24204
24295
|
}
|
|
24205
24296
|
const matches2 = exactMatches.length > 0 ? exactMatches : normalizedMatches.length > 0 ? normalizedMatches : strippedMatches;
|
|
24206
24297
|
if (matches2.length > 0) {
|
|
24207
|
-
const pick3 =
|
|
24298
|
+
const pick3 = ordinal2 === null ? 0 : ordinal2 - 1;
|
|
24208
24299
|
const headerPos = matches2[pick3];
|
|
24209
24300
|
if (headerPos === void 0) return null;
|
|
24210
24301
|
return { headerPos, redirectedFrom: null };
|
|
24211
24302
|
}
|
|
24212
|
-
if (
|
|
24303
|
+
if (ordinal2 !== null || normalizedTarget.length === 0) return null;
|
|
24213
24304
|
let prefixPos = -1;
|
|
24214
24305
|
const distinct = /* @__PURE__ */ new Set();
|
|
24215
24306
|
for (let i = 0; i < headers.length; i++) {
|
|
@@ -24245,10 +24336,10 @@ function buildSectionResult(headers, kind, lines2, headerPos, redirectedFrom) {
|
|
|
24245
24336
|
}
|
|
24246
24337
|
function resolveSectionFromText(text, headingSpec, language) {
|
|
24247
24338
|
const { headers, kind } = findHeaders(text, language);
|
|
24248
|
-
const { base, ordinal } = parseHeadingSpec(headingSpec, headers);
|
|
24339
|
+
const { base, ordinal: ordinal2 } = parseHeadingSpec(headingSpec, headers);
|
|
24249
24340
|
if (base.length === 0) return null;
|
|
24250
24341
|
const lines2 = text.split("\n");
|
|
24251
|
-
const resolved = resolveHeaderPos(headers, base,
|
|
24342
|
+
const resolved = resolveHeaderPos(headers, base, ordinal2);
|
|
24252
24343
|
if (resolved === null) return null;
|
|
24253
24344
|
return buildSectionResult(headers, kind, lines2, resolved.headerPos, resolved.redirectedFrom);
|
|
24254
24345
|
}
|
|
@@ -25195,6 +25286,11 @@ var init_graph_commands = __esm({
|
|
|
25195
25286
|
"opaque",
|
|
25196
25287
|
"mixin",
|
|
25197
25288
|
"extension",
|
|
25289
|
+
// 'extension_type' (Dart 3.3's zero-cost wrapper type, `extension type Meters(int value)`) is
|
|
25290
|
+
// a distinct declaration kind from a plain 'extension' -- languages/dart.ts's
|
|
25291
|
+
// EXTENSION_TYPE_RE emits it via the same makeLineSymbol code path as 'class'/'mixin'/
|
|
25292
|
+
// 'extension' above, so it needs the same TYPE_KINDS entry those already have.
|
|
25293
|
+
"extension_type",
|
|
25198
25294
|
"actor",
|
|
25199
25295
|
// Protocol Buffers (languages/proto_idx.ts's KIND_MAP) uses its own kind strings rather
|
|
25200
25296
|
// than the generic 'enum'/'interface' -- a proto message is a struct-shaped type, a proto
|
|
@@ -25236,7 +25332,26 @@ var init_graph_commands = __esm({
|
|
|
25236
25332
|
// excluded from `token-goat types` in its entirety, the same class of gap already fixed for
|
|
25237
25333
|
// Rust union, Swift protocol/actor, Zig opaque, Dart mixin/extension, proto message/enum/
|
|
25238
25334
|
// service, Apex class/interface/enum, and GraphQL type/interface/input/enum/union.
|
|
25239
|
-
"object"
|
|
25335
|
+
"object",
|
|
25336
|
+
// languages/sfc_idx.ts (Vue/Svelte/Astro single-file components) emits 'sfc_script_class' for
|
|
25337
|
+
// a top-level class declaration in the component's script block, a distinct kind string rather
|
|
25338
|
+
// than the generic 'class' -- so unlike a plain class it never reaches the looksLikeTypeClass
|
|
25339
|
+
// fallback below either, which only ever queries kind === 'class' literally. Every SFC
|
|
25340
|
+
// top-level class was indexed but silently excluded from `token-goat types` in its entirety,
|
|
25341
|
+
// the same class of gap already fixed for Rust union, Swift protocol/actor, Zig opaque, Dart
|
|
25342
|
+
// mixin/extension, proto message/enum/service, Apex class/interface/enum, GraphQL
|
|
25343
|
+
// type/interface/input/enum/union, and Kotlin/Scala object.
|
|
25344
|
+
"sfc_script_class",
|
|
25345
|
+
// languages/graphql_idx.ts's TYPE_RE handler maps EVERY `extend type|interface|input|enum|
|
|
25346
|
+
// union|scalar Foo { ... }` declaration to this one shared kind regardless of which keyword
|
|
25347
|
+
// follows `extend` -- GraphQL's mechanism for adding fields to a type from another file/module,
|
|
25348
|
+
// ubiquitous in federation and schema-stitching -- but unlike the six non-extend KIND_MAP
|
|
25349
|
+
// entries already listed above, this kind was never added here, so every `extend` declaration
|
|
25350
|
+
// was indexed but silently excluded from `token-goat types` in its entirety, the same class of
|
|
25351
|
+
// gap already fixed for the other six GraphQL kinds, Rust union, Swift protocol/actor, Zig
|
|
25352
|
+
// opaque, Dart mixin/extension, proto message/enum/service, Apex class/interface/enum, and
|
|
25353
|
+
// Kotlin/Scala object.
|
|
25354
|
+
"graphql_extend"
|
|
25240
25355
|
];
|
|
25241
25356
|
MAX_CYCLES = 200;
|
|
25242
25357
|
}
|
|
@@ -27679,7 +27794,8 @@ function extractOperations(spec) {
|
|
|
27679
27794
|
});
|
|
27680
27795
|
}
|
|
27681
27796
|
}
|
|
27682
|
-
|
|
27797
|
+
const ordinal2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
27798
|
+
operations.sort((a, b) => ordinal2(a.path, b.path) || ordinal2(a.method, b.method));
|
|
27683
27799
|
return operations;
|
|
27684
27800
|
}
|
|
27685
27801
|
function formatOpenApiOutline(operations) {
|
|
@@ -27767,7 +27883,7 @@ function listZipEntries(data) {
|
|
|
27767
27883
|
return false;
|
|
27768
27884
|
}
|
|
27769
27885
|
});
|
|
27770
|
-
entries.sort((a, b) => a.path.
|
|
27886
|
+
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
27771
27887
|
return entries;
|
|
27772
27888
|
}
|
|
27773
27889
|
function formatZipList(entries) {
|
|
@@ -28250,7 +28366,11 @@ function hasGap(f) {
|
|
|
28250
28366
|
}
|
|
28251
28367
|
function rankAndFilter(files) {
|
|
28252
28368
|
const withGaps = files.filter(hasGap);
|
|
28253
|
-
withGaps.sort((a, b) =>
|
|
28369
|
+
withGaps.sort((a, b) => {
|
|
28370
|
+
const byCount = b.uncoveredLineCount - a.uncoveredLineCount;
|
|
28371
|
+
if (byCount !== 0) return byCount;
|
|
28372
|
+
return a.filePath < b.filePath ? -1 : a.filePath > b.filePath ? 1 : 0;
|
|
28373
|
+
});
|
|
28254
28374
|
return withGaps;
|
|
28255
28375
|
}
|
|
28256
28376
|
function detectCoverageFormat(text) {
|
|
@@ -28798,6 +28918,83 @@ var init_screenshot = __esm({
|
|
|
28798
28918
|
}
|
|
28799
28919
|
});
|
|
28800
28920
|
|
|
28921
|
+
// src/notes.ts
|
|
28922
|
+
function toNoteRow(row) {
|
|
28923
|
+
return {
|
|
28924
|
+
id: row.id,
|
|
28925
|
+
filePath: row.file_path,
|
|
28926
|
+
symbol: row.symbol,
|
|
28927
|
+
content: row.content,
|
|
28928
|
+
fingerprint: row.fingerprint,
|
|
28929
|
+
createdAt: row.created_at,
|
|
28930
|
+
updatedAt: row.updated_at
|
|
28931
|
+
};
|
|
28932
|
+
}
|
|
28933
|
+
function pickEarliest(matches2) {
|
|
28934
|
+
return matches2.reduce((best, s) => s.lineStart < best.lineStart ? s : best);
|
|
28935
|
+
}
|
|
28936
|
+
function resolveSymbolMatch(filePath, symbolName, dbPath = globalDbPath()) {
|
|
28937
|
+
const matches2 = querySymbols({ filePath, name: symbolName }, dbPath);
|
|
28938
|
+
return matches2.length === 0 ? null : pickEarliest(matches2);
|
|
28939
|
+
}
|
|
28940
|
+
function symbolNamesInFile(filePath, dbPath = globalDbPath()) {
|
|
28941
|
+
const symbols = querySymbols({ filePath, limit: 1e5 }, dbPath);
|
|
28942
|
+
return [...new Set(symbols.map((s) => s.name))].sort();
|
|
28943
|
+
}
|
|
28944
|
+
function computeFileFingerprint(filePath, dbPath = globalDbPath()) {
|
|
28945
|
+
const symbols = querySymbols({ filePath, limit: 1e6 }, dbPath);
|
|
28946
|
+
const manifest = symbols.map((s) => `${s.name}:${s.kind}:${s.lineStart}-${s.lineEnd}`).sort().join("\n");
|
|
28947
|
+
return fingerprintContent(manifest);
|
|
28948
|
+
}
|
|
28949
|
+
function computeSymbolFingerprint(filePath, symbolName, dbPath = globalDbPath()) {
|
|
28950
|
+
const match2 = resolveSymbolMatch(filePath, symbolName, dbPath);
|
|
28951
|
+
return match2 === null ? null : fingerprintContent(match2.body);
|
|
28952
|
+
}
|
|
28953
|
+
function upsertNote(filePath, symbol3, content, fingerprint, dbPath = globalDbPath()) {
|
|
28954
|
+
const db = getDb(dbPath);
|
|
28955
|
+
const now = Date.now() / 1e3;
|
|
28956
|
+
db.prepare(
|
|
28957
|
+
`INSERT INTO notes (file_path, symbol, content, fingerprint, created_at, updated_at)
|
|
28958
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
28959
|
+
ON CONFLICT(file_path, symbol) DO UPDATE SET
|
|
28960
|
+
content = excluded.content,
|
|
28961
|
+
fingerprint = excluded.fingerprint,
|
|
28962
|
+
updated_at = excluded.updated_at`
|
|
28963
|
+
).run(filePath, symbol3, content, fingerprint, now, now);
|
|
28964
|
+
}
|
|
28965
|
+
function getNote(filePath, symbol3, dbPath = globalDbPath()) {
|
|
28966
|
+
const db = getDb(dbPath);
|
|
28967
|
+
const row = db.prepare(
|
|
28968
|
+
`SELECT id, file_path, symbol, content, fingerprint, created_at, updated_at FROM notes WHERE ${pathEqClause("file_path")} AND symbol = ?`
|
|
28969
|
+
).get(foldPath(filePath), symbol3);
|
|
28970
|
+
return row === void 0 ? null : toNoteRow(row);
|
|
28971
|
+
}
|
|
28972
|
+
function listNotes(dbPath = globalDbPath()) {
|
|
28973
|
+
const db = getDb(dbPath);
|
|
28974
|
+
const rows = db.prepare(
|
|
28975
|
+
"SELECT id, file_path, symbol, content, fingerprint, created_at, updated_at FROM notes ORDER BY file_path, symbol"
|
|
28976
|
+
).all();
|
|
28977
|
+
return rows.map(toNoteRow);
|
|
28978
|
+
}
|
|
28979
|
+
function isNoteStale(note, dbPath = globalDbPath()) {
|
|
28980
|
+
const current = note.symbol === WHOLE_FILE_NOTE_SYMBOL ? computeFileFingerprint(note.filePath, dbPath) : computeSymbolFingerprint(note.filePath, note.symbol, dbPath);
|
|
28981
|
+
return current === null || current !== note.fingerprint;
|
|
28982
|
+
}
|
|
28983
|
+
var WHOLE_FILE_NOTE_SYMBOL;
|
|
28984
|
+
var init_notes = __esm({
|
|
28985
|
+
"src/notes.ts"() {
|
|
28986
|
+
"use strict";
|
|
28987
|
+
init_define_import_meta_env();
|
|
28988
|
+
init_constants();
|
|
28989
|
+
init_db();
|
|
28990
|
+
init_fingerprint();
|
|
28991
|
+
init_index_reader();
|
|
28992
|
+
init_sql_path();
|
|
28993
|
+
init_util2();
|
|
28994
|
+
WHOLE_FILE_NOTE_SYMBOL = "";
|
|
28995
|
+
}
|
|
28996
|
+
});
|
|
28997
|
+
|
|
28801
28998
|
// src/ts_refs.ts
|
|
28802
28999
|
import { createRequire as createRequire6 } from "node:module";
|
|
28803
29000
|
import * as path45 from "node:path";
|
|
@@ -29350,6 +29547,9 @@ function runSection(opts) {
|
|
|
29350
29547
|
const heading = opts.spec.slice(colonIdx + 2);
|
|
29351
29548
|
const result = readSection(filePath, heading);
|
|
29352
29549
|
if (result === null) {
|
|
29550
|
+
if (!fs36.existsSync(filePath)) {
|
|
29551
|
+
return { text: `File not found: '${filePath}'`, code: 1 };
|
|
29552
|
+
}
|
|
29353
29553
|
const messages = [`Section '${heading}' not found in '${filePath}'`];
|
|
29354
29554
|
const available = listSections(filePath);
|
|
29355
29555
|
if (available.length > 0) messages.push(didYouMean(available));
|
|
@@ -29494,7 +29694,7 @@ function runRefsSingle(opts) {
|
|
|
29494
29694
|
function groupRefsByFile(refs) {
|
|
29495
29695
|
const byFile = /* @__PURE__ */ new Map();
|
|
29496
29696
|
for (const ref2 of refs) byFile.set(ref2.filePath, (byFile.get(ref2.filePath) ?? 0) + 1);
|
|
29497
|
-
return [...byFile.entries()].map(([file2, count]) => ({ file: file2, count })).sort((a, b) => b.count - a.count || a.file.
|
|
29697
|
+
return [...byFile.entries()].map(([file2, count]) => ({ file: file2, count })).sort((a, b) => b.count - a.count || (a.file < b.file ? -1 : a.file > b.file ? 1 : 0));
|
|
29498
29698
|
}
|
|
29499
29699
|
function renderTopFilesSummary(refs, topN) {
|
|
29500
29700
|
const grouped = groupRefsByFile(refs);
|
|
@@ -31004,6 +31204,11 @@ function extractImports(text, ext2) {
|
|
|
31004
31204
|
const m = /^\s*#\s*include\s+[<"]([^>"]+)[>"]/.exec(line);
|
|
31005
31205
|
if (m) push(m[1]);
|
|
31006
31206
|
}
|
|
31207
|
+
} else if ([".sh", ".bash"].includes(e)) {
|
|
31208
|
+
for (const line of lines2) {
|
|
31209
|
+
const m = /^\s*(?:source|\.)\s+['"]?([^\s'";]+)['"]?/.exec(line);
|
|
31210
|
+
if (m) push(m[1]);
|
|
31211
|
+
}
|
|
31007
31212
|
} else if ([".ps1", ".psm1"].includes(e)) {
|
|
31008
31213
|
for (const line of lines2) {
|
|
31009
31214
|
const importMod = /^\s*Import-Module\s+(?:-Name\s+)?['"]?([^\s'";]+)/i.exec(line);
|
|
@@ -31244,6 +31449,59 @@ ${previewLines(s.body, 3)}`);
|
|
|
31244
31449
|
recordReadStat("semantic_search", sumFileSizes(results.map((s) => s.filePath)), text, query);
|
|
31245
31450
|
return { text, code: 0 };
|
|
31246
31451
|
}
|
|
31452
|
+
function runNoteGet(opts) {
|
|
31453
|
+
const resolvedPath = resolveIndexPath(opts.file, opts.projectRoot ?? process.cwd());
|
|
31454
|
+
healStaleIndex(resolvedPath);
|
|
31455
|
+
const symbol3 = opts.symbol ?? WHOLE_FILE_NOTE_SYMBOL;
|
|
31456
|
+
const note = getNote(resolvedPath, symbol3);
|
|
31457
|
+
if (note === null) {
|
|
31458
|
+
const where = opts.symbol !== void 0 ? ` for symbol '${opts.symbol}'` : " (whole-file note)";
|
|
31459
|
+
return { text: `No note found for '${opts.file}'${where}`, code: 1 };
|
|
31460
|
+
}
|
|
31461
|
+
const stale = isNoteStale(note);
|
|
31462
|
+
if (opts.json === true) {
|
|
31463
|
+
const payload = {
|
|
31464
|
+
filePath: note.filePath,
|
|
31465
|
+
symbol: note.symbol === WHOLE_FILE_NOTE_SYMBOL ? null : note.symbol,
|
|
31466
|
+
content: note.content,
|
|
31467
|
+
stale,
|
|
31468
|
+
createdAt: note.createdAt,
|
|
31469
|
+
updatedAt: note.updatedAt
|
|
31470
|
+
};
|
|
31471
|
+
const text2 = JSON.stringify(payload, null, 2);
|
|
31472
|
+
recordStat("note_read");
|
|
31473
|
+
return { text: text2, code: 0 };
|
|
31474
|
+
}
|
|
31475
|
+
const target = note.symbol === WHOLE_FILE_NOTE_SYMBOL ? opts.file : `${opts.file}::${note.symbol}`;
|
|
31476
|
+
const staleTag = stale ? " [STALE \u2014 code changed since this note was written]" : "";
|
|
31477
|
+
const text = `# note \u2014 ${target}${staleTag}
|
|
31478
|
+
${note.content}`;
|
|
31479
|
+
recordStat("note_read");
|
|
31480
|
+
return { text, code: 0 };
|
|
31481
|
+
}
|
|
31482
|
+
function runNoteList(opts = {}) {
|
|
31483
|
+
const withStale = listNotes().map((note) => ({ note, stale: isNoteStale(note) }));
|
|
31484
|
+
const filtered = opts.staleOnly === true ? withStale.filter((n) => n.stale) : withStale;
|
|
31485
|
+
if (opts.json === true) {
|
|
31486
|
+
const items = filtered.map(({ note, stale }) => ({
|
|
31487
|
+
filePath: note.filePath,
|
|
31488
|
+
symbol: note.symbol === WHOLE_FILE_NOTE_SYMBOL ? null : note.symbol,
|
|
31489
|
+
stale,
|
|
31490
|
+
updatedAt: note.updatedAt
|
|
31491
|
+
}));
|
|
31492
|
+
recordStat("note_list");
|
|
31493
|
+
return { text: JSON.stringify(items, null, 2), code: 0 };
|
|
31494
|
+
}
|
|
31495
|
+
recordStat("note_list");
|
|
31496
|
+
if (filtered.length === 0) {
|
|
31497
|
+
return { text: opts.staleOnly === true ? "No stale notes." : "No notes recorded.", code: 0 };
|
|
31498
|
+
}
|
|
31499
|
+
const lines2 = filtered.map(({ note, stale }) => {
|
|
31500
|
+
const target = note.symbol === WHOLE_FILE_NOTE_SYMBOL ? note.filePath : `${note.filePath}::${note.symbol}`;
|
|
31501
|
+
return `${stale ? "[STALE] " : ""}${target}`;
|
|
31502
|
+
});
|
|
31503
|
+
return { text: lines2.join("\n"), code: 0 };
|
|
31504
|
+
}
|
|
31247
31505
|
var DIDYOUMEAN_LIMIT, GREP_MAX_LINES, FIND_SCAN_LIMIT, REFS_TOP_SCAN_LIMIT, STALE_WARNING, PARENT_IDENTIFIER_RE, SKELETON_SYMBOL_CAP, HUNK_HEADER_RE, DEFAULT_LOG_MAX_COUNT;
|
|
31248
31506
|
var init_read_commands = __esm({
|
|
31249
31507
|
"src/read_commands.ts"() {
|
|
@@ -31278,6 +31536,7 @@ var init_read_commands = __esm({
|
|
|
31278
31536
|
init_pdf_extract();
|
|
31279
31537
|
init_screenshot();
|
|
31280
31538
|
init_stats();
|
|
31539
|
+
init_notes();
|
|
31281
31540
|
init_ts_refs();
|
|
31282
31541
|
DIDYOUMEAN_LIMIT = 5;
|
|
31283
31542
|
GREP_MAX_LINES = 200;
|
|
@@ -47607,9 +47866,10 @@ async function storeBashOutput(command, output, exitCode, cwd = null) {
|
|
|
47607
47866
|
const id = await commandHash(command, cwd);
|
|
47608
47867
|
const fingerprints = computeBashFingerprints(command, cwd);
|
|
47609
47868
|
const redactedOutput = redactSecrets(output).text;
|
|
47869
|
+
const redactedCommand = redactSecrets(command).text;
|
|
47610
47870
|
const entry = {
|
|
47611
47871
|
id,
|
|
47612
|
-
command,
|
|
47872
|
+
command: redactedCommand,
|
|
47613
47873
|
output: redactedOutput,
|
|
47614
47874
|
exitCode,
|
|
47615
47875
|
storedAt: Date.now(),
|
|
@@ -47618,7 +47878,7 @@ async function storeBashOutput(command, output, exitCode, cwd = null) {
|
|
|
47618
47878
|
};
|
|
47619
47879
|
_byId.set(id, entry);
|
|
47620
47880
|
storeBlob(BASH_OUTPUT_SUBDIR, id, entry);
|
|
47621
|
-
indexRecallEntry("bash", id,
|
|
47881
|
+
indexRecallEntry("bash", id, redactedCommand, `${redactedCommand}
|
|
47622
47882
|
${redactedOutput}`, entry.storedAt);
|
|
47623
47883
|
return id;
|
|
47624
47884
|
}
|
|
@@ -49142,7 +49402,8 @@ function storeWebOutput(url2, content, dedupKey = url2) {
|
|
|
49142
49402
|
_byId2.set(cacheId, redactedContent);
|
|
49143
49403
|
_urlIndex.set(url2, cacheId);
|
|
49144
49404
|
storeBlob(WEB_OUTPUT_SUBDIR, cacheId, { url: url2, content: redactedContent });
|
|
49145
|
-
|
|
49405
|
+
const redactedUrl = redactSecrets(url2).text;
|
|
49406
|
+
indexRecallEntry("web", cacheId, redactedUrl, `${redactedUrl}
|
|
49146
49407
|
${redactedContent}`, Date.now());
|
|
49147
49408
|
return cacheId;
|
|
49148
49409
|
}
|
|
@@ -49590,8 +49851,17 @@ function pathStem(p) {
|
|
|
49590
49851
|
const dot = name2.lastIndexOf(".");
|
|
49591
49852
|
return dot > 0 ? name2.slice(0, dot) : name2;
|
|
49592
49853
|
}
|
|
49593
|
-
function positionalArgs(args) {
|
|
49594
|
-
|
|
49854
|
+
function positionalArgs(args, valueFlags) {
|
|
49855
|
+
const out2 = [];
|
|
49856
|
+
for (let i = 0; i < args.length; i++) {
|
|
49857
|
+
const a = args[i];
|
|
49858
|
+
if (a.startsWith("-")) {
|
|
49859
|
+
if (valueFlags?.has(a) === true && i + 1 < args.length) i++;
|
|
49860
|
+
continue;
|
|
49861
|
+
}
|
|
49862
|
+
out2.push(a);
|
|
49863
|
+
}
|
|
49864
|
+
return out2;
|
|
49595
49865
|
}
|
|
49596
49866
|
var SHORT_FLAGS_WITH_VALUE = /* @__PURE__ */ new Set(["-n", "-c", "-u", "-e"]);
|
|
49597
49867
|
function stripPrefixes(argv) {
|
|
@@ -49729,6 +49999,7 @@ function byteLength(s) {
|
|
|
49729
49999
|
|
|
49730
50000
|
// src/tool_filters/base.ts
|
|
49731
50001
|
init_define_import_meta_env();
|
|
50002
|
+
init_secret_redact();
|
|
49732
50003
|
var CompressedOutput = class {
|
|
49733
50004
|
constructor(text, originalBytes, compressedBytes, filterName, exitCode = 0, notes = []) {
|
|
49734
50005
|
this.text = text;
|
|
@@ -49898,6 +50169,9 @@ ${stderr.replace(/\s+$/, "")}`;
|
|
|
49898
50169
|
const lines2 = body.split("\n");
|
|
49899
50170
|
if (lines2.length > maxLines) body = truncateMiddleSmart(lines2, maxLines).join("\n");
|
|
49900
50171
|
body = capBytes(body, maxBytes);
|
|
50172
|
+
const redacted = redactSecrets(body);
|
|
50173
|
+
body = redacted.text;
|
|
50174
|
+
if (redacted.count > 0) notes.push(`redacted ${redacted.count} secret-shaped value(s)`);
|
|
49901
50175
|
if (notes.length) body = `[${notes.join("; ")}]
|
|
49902
50176
|
${body}`;
|
|
49903
50177
|
return new CompressedOutput(body, originalBytes, byteLength(body), this.name, exitCode, notes);
|
|
@@ -53148,7 +53422,9 @@ var _GIT_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
53148
53422
|
"-F",
|
|
53149
53423
|
"--file",
|
|
53150
53424
|
"--author",
|
|
53151
|
-
"--date"
|
|
53425
|
+
"--date",
|
|
53426
|
+
"--git-dir",
|
|
53427
|
+
"--work-tree"
|
|
53152
53428
|
]);
|
|
53153
53429
|
function gitPositionalArgs(args) {
|
|
53154
53430
|
const out2 = [];
|
|
@@ -55676,6 +55952,7 @@ var _DOCKER_OLD_SHA_RE = /^ *---> (?:sha256:)?[0-9a-f]{12,}\s*$/;
|
|
|
55676
55952
|
var _DOCKER_OLD_STEP_RE = /^Step \d+\/\d+ : /;
|
|
55677
55953
|
var _DOCKER_OLD_SUCCESS_RE = /^Successfully built [0-9a-f]+/;
|
|
55678
55954
|
var _DOCKER_OLD_INTERMEDIATE_RE = /^Removing intermediate container [0-9a-f]+/;
|
|
55955
|
+
var _DOCKER_OLD_STEP_ERROR_RE = /error|returned a non-zero code/i;
|
|
55679
55956
|
var DockerFilter = class extends ToolFilter {
|
|
55680
55957
|
name = "docker";
|
|
55681
55958
|
binaries = /* @__PURE__ */ new Set(["docker", "buildah", "podman", "nerdctl"]);
|
|
@@ -55756,7 +56033,7 @@ var DockerFilter = class extends ToolFilter {
|
|
|
55756
56033
|
oldStepErr = false;
|
|
55757
56034
|
continue;
|
|
55758
56035
|
}
|
|
55759
|
-
if (
|
|
56036
|
+
if (_DOCKER_OLD_STEP_ERROR_RE.test(ol)) oldStepErr = true;
|
|
55760
56037
|
oldNew.push(ol);
|
|
55761
56038
|
}
|
|
55762
56039
|
if (oldStepHdr !== null) {
|
|
@@ -55993,12 +56270,26 @@ function _compressKubectlDescribe(text) {
|
|
|
55993
56270
|
}
|
|
55994
56271
|
return kept.join("\n");
|
|
55995
56272
|
}
|
|
56273
|
+
var KUBECTL_GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
56274
|
+
"-n",
|
|
56275
|
+
"--namespace",
|
|
56276
|
+
"--context",
|
|
56277
|
+
"--kubeconfig",
|
|
56278
|
+
"--cluster",
|
|
56279
|
+
"--user",
|
|
56280
|
+
"-s",
|
|
56281
|
+
"--server",
|
|
56282
|
+
"--token",
|
|
56283
|
+
"--as",
|
|
56284
|
+
"--as-group",
|
|
56285
|
+
"--request-timeout"
|
|
56286
|
+
]);
|
|
55996
56287
|
var KubectlFilter = class extends ToolFilter {
|
|
55997
56288
|
name = "kubectl";
|
|
55998
56289
|
binaries = /* @__PURE__ */ new Set(["kubectl", "k", "k9s", "oc"]);
|
|
55999
56290
|
errorPassthrough = true;
|
|
56000
56291
|
compressBody(stdout, stderr, _exitCode, argv) {
|
|
56001
|
-
const pos = positionalArgs(argv.slice(1));
|
|
56292
|
+
const pos = positionalArgs(argv.slice(1), KUBECTL_GLOBAL_VALUE_FLAGS);
|
|
56002
56293
|
const subcommand = pos[0] ?? "";
|
|
56003
56294
|
let text = stdout;
|
|
56004
56295
|
if (subcommand === "get" || subcommand === "top") {
|
|
@@ -56180,7 +56471,7 @@ var KubectlLogsFilter = class extends ToolFilter {
|
|
|
56180
56471
|
const stem = pathStem(argv[0]).toLowerCase();
|
|
56181
56472
|
const name2 = pathName(argv[0]).toLowerCase();
|
|
56182
56473
|
if (!["kubectl", "k"].includes(stem) && !["kubectl", "k"].includes(name2)) return false;
|
|
56183
|
-
const pos = positionalArgs(argv.slice(1));
|
|
56474
|
+
const pos = positionalArgs(argv.slice(1), KUBECTL_GLOBAL_VALUE_FLAGS);
|
|
56184
56475
|
return pos.length > 0 && pos[0] === "logs";
|
|
56185
56476
|
}
|
|
56186
56477
|
compressBody(stdout, stderr, _exitCode, _argv) {
|
|
@@ -56626,6 +56917,19 @@ var awsFilter = new AwsFilter();
|
|
|
56626
56917
|
var _AWS_UPLOAD_RE = /^upload:\s+\S+\s+to\s+s3:\/\//i;
|
|
56627
56918
|
var _AWS_DOWNLOAD_RE = /^download:\s+s3:\/\//i;
|
|
56628
56919
|
var _AWS_S3_PROGRESS_RE = /^(?:Completed\s+\d|\d+(?:\.\d+)?\s*(?:KiB|MiB|GiB|B)\/s|Calculating|upload\s+failed:|download\s+failed:)/i;
|
|
56920
|
+
var AWS_GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
56921
|
+
"--profile",
|
|
56922
|
+
"--region",
|
|
56923
|
+
"--endpoint-url",
|
|
56924
|
+
"--output",
|
|
56925
|
+
"--query",
|
|
56926
|
+
"--color",
|
|
56927
|
+
"--ca-bundle",
|
|
56928
|
+
"--cli-read-timeout",
|
|
56929
|
+
"--cli-connect-timeout",
|
|
56930
|
+
"--cli-binary-format",
|
|
56931
|
+
"--cli-pager"
|
|
56932
|
+
]);
|
|
56629
56933
|
var AwsCliFilter = class extends ToolFilter {
|
|
56630
56934
|
name = "aws-cli";
|
|
56631
56935
|
binaries = /* @__PURE__ */ new Set(["aws", "aws2"]);
|
|
@@ -56633,7 +56937,7 @@ var AwsCliFilter = class extends ToolFilter {
|
|
|
56633
56937
|
_JSON_ARRAY_THRESHOLD = 10;
|
|
56634
56938
|
_JSON_ARRAY_KEEP = 3;
|
|
56635
56939
|
compressBody(stdout, stderr, _exitCode, argv) {
|
|
56636
|
-
const positionals = positionalArgs(argv.slice(1));
|
|
56940
|
+
const positionals = positionalArgs(argv.slice(1), AWS_GLOBAL_VALUE_FLAGS);
|
|
56637
56941
|
const isS3Transfer = positionals.length >= 2 && positionals[0] === "s3" && (positionals[1] === "cp" || positionals[1] === "sync" || positionals[1] === "mv");
|
|
56638
56942
|
const isCfnEvents = positionals.length >= 2 && positionals[0] === "cloudformation" && positionals[1] === "describe-stack-events";
|
|
56639
56943
|
let text = stdout;
|
|
@@ -58024,6 +58328,7 @@ var _GH_RUN_PASS_STEP_RE = /^\s*[✓√]\s/;
|
|
|
58024
58328
|
var _GH_RUN_FAIL_STEP_RE = /^\s*[X✗❌]\s|^\s*FAIL(:|ED|URE)\b|^\s*Error:\s/;
|
|
58025
58329
|
var _GH_API_URL_SUFFIX = "_url";
|
|
58026
58330
|
var _GH_API_URL_KEEP = /* @__PURE__ */ new Set(["html_url", "avatar_url", "clone_url", "ssh_url"]);
|
|
58331
|
+
var GH_GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["-R", "--repo", "--hostname"]);
|
|
58027
58332
|
var _GH_API_NOISE_KEYS = /* @__PURE__ */ new Set(["gravatar_id", "site_admin"]);
|
|
58028
58333
|
var _GH_CONTENT_B64_RE = /^[A-Za-z0-9+/=\n]+$/;
|
|
58029
58334
|
var _GH_BASE64_MIN_LEN = 200;
|
|
@@ -58308,7 +58613,7 @@ var GhFilter = class extends ToolFilter {
|
|
|
58308
58613
|
binaries = /* @__PURE__ */ new Set(["gh"]);
|
|
58309
58614
|
compress(stdout, stderr, _exitCode, argv) {
|
|
58310
58615
|
const redactedStdout = redactGhBase64Content(stdout);
|
|
58311
|
-
const positionals = positionalArgs(argv.slice(1));
|
|
58616
|
+
const positionals = positionalArgs(argv.slice(1), GH_GLOBAL_VALUE_FLAGS);
|
|
58312
58617
|
const subcommand = positionals[0] ?? "";
|
|
58313
58618
|
const action = positionals[1] ?? "";
|
|
58314
58619
|
const merged = this.combineOutput(redactedStdout, stderr);
|
|
@@ -59113,9 +59418,38 @@ var LsFilter = class _LsFilter extends ToolFilter {
|
|
|
59113
59418
|
var _EZA_PASSTHROUGH = 30;
|
|
59114
59419
|
var _HEADER_KEYWORDS = /* @__PURE__ */ new Set(["permission", "size", "date", "user", "name"]);
|
|
59115
59420
|
var _SUMMARY_KEYWORDS = ["director", "file", "total"];
|
|
59116
|
-
var EzaFilter = class extends ToolFilter {
|
|
59421
|
+
var EzaFilter = class _EzaFilter extends ToolFilter {
|
|
59117
59422
|
name = "eza";
|
|
59118
59423
|
binaries = /* @__PURE__ */ new Set(["eza", "exa", "ls"]);
|
|
59424
|
+
// Flags eza/exa support that plain GNU/BSD `ls` does not -- used to disambiguate the shared
|
|
59425
|
+
// 'ls' binary claim below (a common `alias ls=eza` setup means the literal command text is
|
|
59426
|
+
// "ls ...", but token-goat only ever sees that raw text, never the shell's alias resolution).
|
|
59427
|
+
static _EZA_ONLY_FLAGS = /* @__PURE__ */ new Set([
|
|
59428
|
+
"--tree",
|
|
59429
|
+
"-T",
|
|
59430
|
+
"--icons",
|
|
59431
|
+
"--no-icons",
|
|
59432
|
+
"--git",
|
|
59433
|
+
"--git-repos",
|
|
59434
|
+
"--git-repos-no-status",
|
|
59435
|
+
"--level"
|
|
59436
|
+
]);
|
|
59437
|
+
// LsFilter (registered before EzaFilter in SHELL_FILE_FILTERS) always wins a plain `ls`
|
|
59438
|
+
// invocation since binary-name matching alone can't tell a real GNU/BSD `ls` from an
|
|
59439
|
+
// `alias ls=eza` shell alias -- the literal command text is "ls ..." either way. Without this
|
|
59440
|
+
// gate, EzaFilter's own 'ls' binary claim was permanently unreachable dead code: LsFilter's
|
|
59441
|
+
// generic ls-format compressor (no awareness of eza's tree/column output) silently ran on
|
|
59442
|
+
// every aliased `ls --tree`/`ls --icons`/etc. invocation instead. Mirrors RgFilter's own
|
|
59443
|
+
// `_hasContextFlags` gate, which resolves the same kind of shared-binary ambiguity between
|
|
59444
|
+
// itself and GrepFilter.
|
|
59445
|
+
matches(argv) {
|
|
59446
|
+
if (!super.matches(argv)) return false;
|
|
59447
|
+
const first2 = argv[0];
|
|
59448
|
+
const stem = pathStem(first2).toLowerCase();
|
|
59449
|
+
const name2 = pathName(first2).toLowerCase();
|
|
59450
|
+
if (stem !== "ls" && name2 !== "ls") return true;
|
|
59451
|
+
return argv.slice(1).some((a) => _EzaFilter._EZA_ONLY_FLAGS.has(a));
|
|
59452
|
+
}
|
|
59119
59453
|
compressBody(stdout, stderr, _exitCode, argv) {
|
|
59120
59454
|
const merged = this.combineOutput(stdout, stderr);
|
|
59121
59455
|
const text = normalise(merged);
|
|
@@ -59873,9 +60207,11 @@ var SHELL_FILE_FILTERS = [
|
|
|
59873
60207
|
ffmpegFilter,
|
|
59874
60208
|
// Diff tool (plain POSIX diff; git diff is handled by GitFilter)
|
|
59875
60209
|
diffFilter,
|
|
59876
|
-
// Directory listings — LsFilter (
|
|
59877
|
-
|
|
60210
|
+
// Directory listings — EzaFilter before LsFilter: EzaFilter's matches() gate falls through to
|
|
60211
|
+
// LsFilter for a plain `ls` with no eza-only flag, but must run FIRST so it can actually claim
|
|
60212
|
+
// an aliased `ls --tree`/`ls --icons`/etc. invocation (see EzaFilter.matches doc comment).
|
|
59878
60213
|
ezaFilter,
|
|
60214
|
+
lsFilter,
|
|
59879
60215
|
fdFilter,
|
|
59880
60216
|
wcFilter,
|
|
59881
60217
|
treeFilter,
|
|
@@ -60385,7 +60721,7 @@ var flutterFilter = new FlutterFilter();
|
|
|
60385
60721
|
var DART_ANALYZING_RE = /^Analyzing\s/;
|
|
60386
60722
|
var DART_ANALYZE_RESULT_RE = /^(?:No issues found!|\d+ issue[s]? found\.|warning -|error -|info -|hint -)/;
|
|
60387
60723
|
var DART_TEST_PROGRESS_RE = /^\d{2}:\d{2}\s+[+\d]|^[.]+$/;
|
|
60388
|
-
var DART_COMPILE_DONE_RE = /^
|
|
60724
|
+
var DART_COMPILE_DONE_RE = /^Generated:\s/;
|
|
60389
60725
|
var DART_TEST_SUMMARY_RE = /(?:All tests passed\.?|\d+\s+test[s]?\s+(?:passed|failed))/;
|
|
60390
60726
|
var PUB_KEEP_RE2 = /^(?:Resolving dependencies|Changed \d+|No dependencies changed|Got dependencies|Downloading packages|Building package executable)/;
|
|
60391
60727
|
var PUB_PKG_LINE_RE2 = /^[+>!]\s+\S+\s+\S+/;
|
|
@@ -62727,6 +63063,7 @@ function recordSavings(result) {
|
|
|
62727
63063
|
|
|
62728
63064
|
// src/cli.ts
|
|
62729
63065
|
init_read_commands();
|
|
63066
|
+
init_notes();
|
|
62730
63067
|
|
|
62731
63068
|
// src/bridges_status.ts
|
|
62732
63069
|
init_define_import_meta_env();
|
|
@@ -63186,6 +63523,7 @@ function formatCues(cues) {
|
|
|
63186
63523
|
init_graph_commands();
|
|
63187
63524
|
init_skill_cache();
|
|
63188
63525
|
init_hooks_read();
|
|
63526
|
+
init_section_reader();
|
|
63189
63527
|
init_util2();
|
|
63190
63528
|
init_ansi();
|
|
63191
63529
|
init_config();
|
|
@@ -66533,6 +66871,9 @@ import * as fs43 from "node:fs";
|
|
|
66533
66871
|
import * as path53 from "node:path";
|
|
66534
66872
|
var MAX_ENTRIES = 30;
|
|
66535
66873
|
var KEY_RE2 = /^[A-Za-z0-9_-]{1,80}$/;
|
|
66874
|
+
function ordinal(a, b) {
|
|
66875
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
66876
|
+
}
|
|
66536
66877
|
function memoryPath(projectHash2) {
|
|
66537
66878
|
return path53.join(dataDir(), "projects", `${projectHash2}_memory.toml`);
|
|
66538
66879
|
}
|
|
@@ -66587,7 +66928,7 @@ function loadRaw(filePath) {
|
|
|
66587
66928
|
}
|
|
66588
66929
|
function save(filePath, entries) {
|
|
66589
66930
|
const lines2 = [];
|
|
66590
|
-
const sorted = Object.entries(entries).sort(([a], [b]) => a
|
|
66931
|
+
const sorted = Object.entries(entries).sort(([a], [b]) => ordinal(a, b));
|
|
66591
66932
|
for (const [k, v] of sorted) {
|
|
66592
66933
|
const escaped = v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
66593
66934
|
lines2.push(`${k} = "${escaped}"`);
|
|
@@ -66610,7 +66951,7 @@ function setEntry(projectHash2, key, value) {
|
|
|
66610
66951
|
const isNewKey = !(key in entries);
|
|
66611
66952
|
if (isNewKey && Object.keys(entries).length >= MAX_ENTRIES) {
|
|
66612
66953
|
const keysToKeep = MAX_ENTRIES - 1;
|
|
66613
|
-
const allKeys = Object.keys(entries).sort((a, b) => a
|
|
66954
|
+
const allKeys = Object.keys(entries).sort((a, b) => ordinal(a, b));
|
|
66614
66955
|
for (const k of allKeys.slice(keysToKeep)) {
|
|
66615
66956
|
delete entries[k];
|
|
66616
66957
|
}
|
|
@@ -67255,7 +67596,7 @@ function parseRequirementsTxt(content) {
|
|
|
67255
67596
|
const deps = [];
|
|
67256
67597
|
for (const raw of splitLines2(content)) {
|
|
67257
67598
|
if (/^\s*#/.test(raw)) continue;
|
|
67258
|
-
const eggMatch = /^\s*(?:git|hg|svn|bzr)\+.*#egg=([A-Za-z0-9_.-]+)/.exec(raw);
|
|
67599
|
+
const eggMatch = /^\s*(?:-e\s+|--editable[\s=]+)?(?:git|hg|svn|bzr)\+.*#egg=([A-Za-z0-9_.-]+)/.exec(raw);
|
|
67259
67600
|
if (eggMatch !== null) {
|
|
67260
67601
|
deps.push({ name: eggMatch[1] ?? "", version: "", kind: "unknown" });
|
|
67261
67602
|
continue;
|
|
@@ -67823,8 +68164,11 @@ function resolveTypesLocation(pkgDir, pkgJson, nodeModulesDir, pkgName) {
|
|
|
67823
68164
|
try {
|
|
67824
68165
|
const typesPkgJson = JSON.parse(typesPkgJsonRaw);
|
|
67825
68166
|
const entry = (typeof typesPkgJson["types"] === "string" ? typesPkgJson["types"] : void 0) ?? (typeof typesPkgJson["main"] === "string" ? typesPkgJson["main"] : void 0) ?? "index.d.ts";
|
|
67826
|
-
const
|
|
67827
|
-
|
|
68167
|
+
const entryCandidates = [entry, entry.endsWith(".d.ts") ? entry : `${entry}.d.ts`, entry.replace(/\.[cm]?[jt]s$/, ".d.ts")];
|
|
68168
|
+
for (const c of entryCandidates) {
|
|
68169
|
+
const entryPath = path55.join(typesPkgDir, c);
|
|
68170
|
+
if (fileExists2(entryPath)) return { path: entryPath, source: "@types" };
|
|
68171
|
+
}
|
|
67828
68172
|
} catch {
|
|
67829
68173
|
}
|
|
67830
68174
|
const fallback = path55.join(typesPkgDir, "index.d.ts");
|
|
@@ -69475,8 +69819,11 @@ var FILE_PATH_TOOLS = /* @__PURE__ */ new Set(["Read", "Edit", "Write", "Noteboo
|
|
|
69475
69819
|
function extractFilePath(name2, input) {
|
|
69476
69820
|
if (!FILE_PATH_TOOLS.has(name2)) return null;
|
|
69477
69821
|
if (input === null || typeof input !== "object") return null;
|
|
69478
|
-
const
|
|
69479
|
-
|
|
69822
|
+
const o = input;
|
|
69823
|
+
const fp = o["file_path"];
|
|
69824
|
+
if (typeof fp === "string") return fp;
|
|
69825
|
+
const notebookPath = o["notebook_path"];
|
|
69826
|
+
return typeof notebookPath === "string" ? notebookPath : null;
|
|
69480
69827
|
}
|
|
69481
69828
|
function extractCommand(name2, input) {
|
|
69482
69829
|
if (name2 !== "Bash") return null;
|
|
@@ -70769,7 +71116,11 @@ function cmdVideoChapters(file2) {
|
|
|
70769
71116
|
}
|
|
70770
71117
|
lines2.push("(extract a subtitle stream to .vtt/.srt with ffmpeg, then use transcript/transcript-outline on it)");
|
|
70771
71118
|
}
|
|
70772
|
-
|
|
71119
|
+
const text = lines2.join("\n");
|
|
71120
|
+
out(text);
|
|
71121
|
+
const fullSourceBytes = fileSizeOrZero(file2);
|
|
71122
|
+
const bytesSaved = Math.max(1, fullSourceBytes - Buffer.byteLength(text, "utf8"));
|
|
71123
|
+
recordStat("video_chapters", bytesSaved, Math.round(bytesSaved / 4));
|
|
70773
71124
|
}
|
|
70774
71125
|
function formatVideoTimestamp(totalSeconds) {
|
|
70775
71126
|
const hours = Math.floor(totalSeconds / 3600);
|
|
@@ -71406,6 +71757,50 @@ function decodeBase64Buffer(payload, label) {
|
|
|
71406
71757
|
}
|
|
71407
71758
|
return Buffer.from(normalized, "base64");
|
|
71408
71759
|
}
|
|
71760
|
+
function cmdNoteAdd(file2, opts) {
|
|
71761
|
+
if (!file2 || !file2.trim()) {
|
|
71762
|
+
throw new CliError("file path cannot be empty");
|
|
71763
|
+
}
|
|
71764
|
+
const usingFrom = opts.contentFrom !== void 0;
|
|
71765
|
+
const usingB64 = opts.contentB64 !== void 0;
|
|
71766
|
+
if (usingFrom && usingB64) {
|
|
71767
|
+
throw new CliError("cannot mix --content-from with --content-b64");
|
|
71768
|
+
}
|
|
71769
|
+
if (!usingFrom && !usingB64) {
|
|
71770
|
+
throw new CliError("must provide either --content-from or --content-b64");
|
|
71771
|
+
}
|
|
71772
|
+
const contentBytes = usingFrom ? readFileBoundedRaw(opts.contentFrom, "--content-from") : decodeBase64Buffer(opts.contentB64, "--content-b64");
|
|
71773
|
+
if (contentBytes.length === 0) {
|
|
71774
|
+
throw new CliError("note content cannot be empty");
|
|
71775
|
+
}
|
|
71776
|
+
if (Buffer.compare(Buffer.from(contentBytes.toString("utf8"), "utf8"), contentBytes) !== 0) {
|
|
71777
|
+
throw new CliError("note content must be valid UTF-8 text");
|
|
71778
|
+
}
|
|
71779
|
+
const resolvedPath = resolveIndexPath(file2);
|
|
71780
|
+
if (!fs52.existsSync(resolvedPath)) {
|
|
71781
|
+
throw new CliError(`File not found: '${resolvedPath}'`);
|
|
71782
|
+
}
|
|
71783
|
+
healStaleIndex(resolvedPath);
|
|
71784
|
+
let symbol3 = WHOLE_FILE_NOTE_SYMBOL;
|
|
71785
|
+
let fingerprint;
|
|
71786
|
+
if (opts.symbol !== void 0) {
|
|
71787
|
+
const match2 = resolveSymbolMatch(resolvedPath, opts.symbol);
|
|
71788
|
+
if (match2 === null) {
|
|
71789
|
+
const messages = [`No symbol named '${opts.symbol}' is indexed in '${file2}'`];
|
|
71790
|
+
const available = symbolNamesInFile(resolvedPath);
|
|
71791
|
+
if (available.length > 0) messages.push(didYouMean(available));
|
|
71792
|
+
throw new CliError(messages.join("\n"));
|
|
71793
|
+
}
|
|
71794
|
+
symbol3 = opts.symbol;
|
|
71795
|
+
fingerprint = fingerprintContent(match2.body);
|
|
71796
|
+
} else {
|
|
71797
|
+
fingerprint = computeFileFingerprint(resolvedPath);
|
|
71798
|
+
}
|
|
71799
|
+
upsertNote(resolvedPath, symbol3, contentBytes.toString("utf8"), fingerprint);
|
|
71800
|
+
const target = opts.symbol !== void 0 ? `${file2}::${opts.symbol}` : file2;
|
|
71801
|
+
out(`Note saved: ${target} (fingerprint ${fingerprint.slice(0, 12)})`);
|
|
71802
|
+
recordStat("note_write");
|
|
71803
|
+
}
|
|
71409
71804
|
function cmdWriteFile(dest, opts) {
|
|
71410
71805
|
validateWritablePath(dest, "destination");
|
|
71411
71806
|
if (opts.from !== void 0 && opts.b64 !== void 0) {
|
|
@@ -71511,6 +71906,56 @@ function diagnoseNearMiss(targetText, oldText) {
|
|
|
71511
71906
|
}
|
|
71512
71907
|
return void 0;
|
|
71513
71908
|
}
|
|
71909
|
+
function detectDominantEol(buf) {
|
|
71910
|
+
let crlf = 0;
|
|
71911
|
+
let lfOnly = 0;
|
|
71912
|
+
for (let i = 0; i < buf.length; i++) {
|
|
71913
|
+
if (buf[i] === 10) {
|
|
71914
|
+
if (i > 0 && buf[i - 1] === 13) crlf++;
|
|
71915
|
+
else lfOnly++;
|
|
71916
|
+
}
|
|
71917
|
+
}
|
|
71918
|
+
return crlf > lfOnly ? "\r\n" : "\n";
|
|
71919
|
+
}
|
|
71920
|
+
function normalizeEolToMatch(source, reference) {
|
|
71921
|
+
const eol = detectDominantEol(reference);
|
|
71922
|
+
const CR = 13;
|
|
71923
|
+
const LF = 10;
|
|
71924
|
+
const collapsed = [];
|
|
71925
|
+
for (let i = 0; i < source.length; i++) {
|
|
71926
|
+
if (source[i] === CR && source[i + 1] === LF) continue;
|
|
71927
|
+
collapsed.push(source[i]);
|
|
71928
|
+
}
|
|
71929
|
+
if (eol === "\n") return Buffer.from(collapsed);
|
|
71930
|
+
const expanded = [];
|
|
71931
|
+
for (const b of collapsed) {
|
|
71932
|
+
if (b === LF) expanded.push(CR, LF);
|
|
71933
|
+
else expanded.push(b);
|
|
71934
|
+
}
|
|
71935
|
+
return Buffer.from(expanded);
|
|
71936
|
+
}
|
|
71937
|
+
var MAX_CLOSEST_MATCH_COMPARISONS = 2e6;
|
|
71938
|
+
function findClosestLineWindow(targetText, oldText) {
|
|
71939
|
+
const targetLines = targetText.split("\n");
|
|
71940
|
+
const oldLines = oldText.split("\n");
|
|
71941
|
+
const windowSize = oldLines.length;
|
|
71942
|
+
if (windowSize === 0 || windowSize > targetLines.length) return void 0;
|
|
71943
|
+
if ((targetLines.length - windowSize + 1) * windowSize > MAX_CLOSEST_MATCH_COMPARISONS) return void 0;
|
|
71944
|
+
let bestIdx = -1;
|
|
71945
|
+
let bestScore = 0;
|
|
71946
|
+
for (let i = 0; i <= targetLines.length - windowSize; i++) {
|
|
71947
|
+
let score = 0;
|
|
71948
|
+
for (let j = 0; j < windowSize; j++) {
|
|
71949
|
+
if (targetLines[i + j] === oldLines[j]) score++;
|
|
71950
|
+
}
|
|
71951
|
+
if (score > bestScore) {
|
|
71952
|
+
bestScore = score;
|
|
71953
|
+
bestIdx = i;
|
|
71954
|
+
}
|
|
71955
|
+
}
|
|
71956
|
+
if (bestIdx === -1) return void 0;
|
|
71957
|
+
return { lineStart: bestIdx + 1, region: targetLines.slice(bestIdx, bestIdx + windowSize).join("\n") };
|
|
71958
|
+
}
|
|
71514
71959
|
function cmdReplace(file2, opts) {
|
|
71515
71960
|
validateWritablePath(file2, "target file");
|
|
71516
71961
|
const targetBuf = readFileBoundedRaw(file2, "target file", true);
|
|
@@ -71538,19 +71983,32 @@ function cmdReplace(file2, opts) {
|
|
|
71538
71983
|
}
|
|
71539
71984
|
const oldBytes = usingFrom ? readFileBoundedRaw(opts.oldFrom, "--old-from") : decodeBase64Buffer(opts.oldB64, "--old-b64");
|
|
71540
71985
|
const newBytes = usingFrom ? readFileBoundedRaw(opts.newFrom, "--new-from") : decodeBase64Buffer(opts.newB64, "--new-b64");
|
|
71541
|
-
|
|
71986
|
+
const normalizedOldBytes = opts.normalizeNewlines === true ? normalizeEolToMatch(oldBytes, targetBuf) : oldBytes;
|
|
71987
|
+
const normalizedNewBytes = opts.normalizeNewlines === true ? normalizeEolToMatch(newBytes, targetBuf) : newBytes;
|
|
71988
|
+
if (normalizedOldBytes.length === 0) {
|
|
71542
71989
|
throw new CliError("old string cannot be empty");
|
|
71543
71990
|
}
|
|
71544
71991
|
const matches2 = [];
|
|
71545
71992
|
let cursor = 0;
|
|
71546
|
-
while ((cursor = targetBuf.indexOf(
|
|
71993
|
+
while ((cursor = targetBuf.indexOf(normalizedOldBytes, cursor)) !== -1) {
|
|
71547
71994
|
matches2.push(cursor);
|
|
71548
|
-
cursor +=
|
|
71995
|
+
cursor += normalizedOldBytes.length;
|
|
71549
71996
|
}
|
|
71550
71997
|
const occurrences = matches2.length;
|
|
71551
71998
|
if (occurrences === 0) {
|
|
71552
|
-
const nearMiss = diagnoseNearMiss(targetBuf.toString("utf8"),
|
|
71553
|
-
|
|
71999
|
+
const nearMiss = diagnoseNearMiss(targetBuf.toString("utf8"), normalizedOldBytes.toString("utf8"));
|
|
72000
|
+
if (nearMiss !== void 0) {
|
|
72001
|
+
throw new CliError(`old string not found in ${file2} \u2014 ${nearMiss}`);
|
|
72002
|
+
}
|
|
72003
|
+
const closest = findClosestLineWindow(targetBuf.toString("utf8"), normalizedOldBytes.toString("utf8"));
|
|
72004
|
+
if (closest !== void 0) {
|
|
72005
|
+
const diff = buildLineDiff(closest.region, normalizedOldBytes.toString("utf8"), file2);
|
|
72006
|
+
throw new CliError(
|
|
72007
|
+
`old string not found in ${file2} \u2014 closest match at line ${closest.lineStart} (showing: what's actually there vs. what --old-from/--old-b64 searched for):
|
|
72008
|
+
${diff}`
|
|
72009
|
+
);
|
|
72010
|
+
}
|
|
72011
|
+
throw new CliError(`old string not found in ${file2}`);
|
|
71554
72012
|
}
|
|
71555
72013
|
if (occurrences > 1 && !opts.all) {
|
|
71556
72014
|
throw new CliError(`old string appears ${occurrences} times in ${file2} \u2014 pass --all to replace every occurrence, or provide a more specific match`);
|
|
@@ -71559,8 +72017,8 @@ function cmdReplace(file2, opts) {
|
|
|
71559
72017
|
let prevEnd = 0;
|
|
71560
72018
|
for (const pos of matches2) {
|
|
71561
72019
|
parts.push(targetBuf.subarray(prevEnd, pos));
|
|
71562
|
-
parts.push(
|
|
71563
|
-
prevEnd = pos +
|
|
72020
|
+
parts.push(normalizedNewBytes);
|
|
72021
|
+
prevEnd = pos + normalizedOldBytes.length;
|
|
71564
72022
|
}
|
|
71565
72023
|
parts.push(targetBuf.subarray(prevEnd));
|
|
71566
72024
|
const replacedBuf = Buffer.concat(parts);
|
|
@@ -71587,6 +72045,65 @@ function cmdReplace(file2, opts) {
|
|
|
71587
72045
|
enqueueDirtyPathSafe(file2);
|
|
71588
72046
|
out(`replaced ${occurrences} occurrence${occurrences === 1 ? "" : "s"} in ${file2}`);
|
|
71589
72047
|
}
|
|
72048
|
+
function cmdInsertSection(file2, opts) {
|
|
72049
|
+
validateWritablePath(file2, "target file");
|
|
72050
|
+
const usingFrom = opts.contentFrom !== void 0;
|
|
72051
|
+
const usingB64 = opts.contentB64 !== void 0;
|
|
72052
|
+
if (usingFrom && usingB64) {
|
|
72053
|
+
throw new CliError("cannot mix --content-from with --content-b64");
|
|
72054
|
+
}
|
|
72055
|
+
if (!usingFrom && !usingB64) {
|
|
72056
|
+
throw new CliError("must provide either --content-from or --content-b64");
|
|
72057
|
+
}
|
|
72058
|
+
const contentBytes = usingFrom ? readFileBoundedRaw(opts.contentFrom, "--content-from") : decodeBase64Buffer(opts.contentB64, "--content-b64");
|
|
72059
|
+
if (contentBytes.length === 0) {
|
|
72060
|
+
throw new CliError("content to insert cannot be empty");
|
|
72061
|
+
}
|
|
72062
|
+
let preWriteStat;
|
|
72063
|
+
try {
|
|
72064
|
+
preWriteStat = fs52.statSync(file2);
|
|
72065
|
+
} catch {
|
|
72066
|
+
}
|
|
72067
|
+
const result = readSection(file2, opts.after);
|
|
72068
|
+
if (result === null) {
|
|
72069
|
+
const available = listSections(file2);
|
|
72070
|
+
const messages = [`Section '${opts.after}' not found in '${file2}'`];
|
|
72071
|
+
if (available.length > 0) messages.push(didYouMean(available));
|
|
72072
|
+
throw new CliError(messages.join("\n"));
|
|
72073
|
+
}
|
|
72074
|
+
let rawText;
|
|
72075
|
+
try {
|
|
72076
|
+
rawText = fs52.readFileSync(file2, "utf-8");
|
|
72077
|
+
} catch (e) {
|
|
72078
|
+
mapFsError(e, void 0, file2);
|
|
72079
|
+
}
|
|
72080
|
+
if (rawText.charCodeAt(0) === 65279) rawText = rawText.slice(1);
|
|
72081
|
+
const eol = detectDominantEol(Buffer.from(rawText, "utf8"));
|
|
72082
|
+
const lfLines = rawText.replace(/\r\n/g, "\n").split("\n");
|
|
72083
|
+
const insertAt = result.lineEnd;
|
|
72084
|
+
const insertedLines = contentBytes.toString("utf8").replace(/\r\n/g, "\n").split("\n");
|
|
72085
|
+
if (insertedLines.length > 0 && insertedLines[insertedLines.length - 1] === "") insertedLines.pop();
|
|
72086
|
+
const mergedLfText = [...lfLines.slice(0, insertAt), ...insertedLines, ...lfLines.slice(insertAt)].join("\n");
|
|
72087
|
+
const mergedText = eol === "\n" ? mergedLfText : mergedLfText.replace(/\n/g, "\r\n");
|
|
72088
|
+
if (preWriteStat !== void 0) {
|
|
72089
|
+
let preRenameStat;
|
|
72090
|
+
try {
|
|
72091
|
+
preRenameStat = fs52.statSync(file2);
|
|
72092
|
+
} catch {
|
|
72093
|
+
}
|
|
72094
|
+
if (preRenameStat !== void 0 && (preRenameStat.mtimeMs !== preWriteStat.mtimeMs || preRenameStat.size !== preWriteStat.size)) {
|
|
72095
|
+
throw new CliError(`${file2} changed on disk while insert-section was running -- the file was modified concurrently, so the insert was NOT applied. Retry.`);
|
|
72096
|
+
}
|
|
72097
|
+
}
|
|
72098
|
+
try {
|
|
72099
|
+
atomicWriteBuffer(file2, Buffer.from(mergedText, "utf8"));
|
|
72100
|
+
} catch (e) {
|
|
72101
|
+
mapFsError(e, void 0, file2);
|
|
72102
|
+
}
|
|
72103
|
+
enqueueDirtyPathSafe(file2);
|
|
72104
|
+
const redirectNote = result.redirectedFrom !== void 0 ? ` (redirected from: '${result.redirectedFrom}')` : "";
|
|
72105
|
+
out(`inserted after '${result.heading}'${redirectNote} in ${file2}`);
|
|
72106
|
+
}
|
|
71590
72107
|
async function cmdGdriveSections(fileId, opts) {
|
|
71591
72108
|
const fetchOpts = { fresh: opts.fresh === true };
|
|
71592
72109
|
const text = await fetchDoc(fileId, fetchOpts);
|
|
@@ -71801,7 +72318,9 @@ function buildProgram() {
|
|
|
71801
72318
|
})
|
|
71802
72319
|
)
|
|
71803
72320
|
);
|
|
71804
|
-
program2.command("section <spec>").description(
|
|
72321
|
+
program2.command("section <spec>").description(
|
|
72322
|
+
'read one section from a file (spec: file::heading, or file::<unambiguous heading prefix> \u2014 e.g. "Lesson 16" resolves a longer unique heading), or list all sections with --list'
|
|
72323
|
+
).option("-j, --json", "output as JSON").option("--list", "list all section headings in the file instead of reading one").action(
|
|
71805
72324
|
(spec, opts) => opts.list === true ? runExit(() => runListSections({ file: spec, ...opts.json === true ? { json: true } : {} })) : runExitText(() => runSection({ spec, ...opts.json === true ? { json: true } : {} }))
|
|
71806
72325
|
);
|
|
71807
72326
|
program2.command("semantic <query>").description("semantic search (falls back to full-text search)").option("-l, --limit <n>", "max results").action(guard(cmdSemantic));
|
|
@@ -72162,7 +72681,33 @@ function buildProgram() {
|
|
|
72162
72681
|
).option("--summary", "line ranges and ours/base/theirs labels only, omitting the conflict content").option("--json", "emit the results as JSON instead of text").action(guard(cmdConflicts));
|
|
72163
72682
|
program2.command("screenshot <url> <destPath>").description("capture a local headless-browser screenshot, shrunk the same way local image reads are").option("--executable-path <path>", "Chrome/Chromium executable to launch (overrides config/auto-detect)").option("--width <n>", "viewport width in pixels (default: 1280)").option("--height <n>", "viewport height in pixels (default: 800)").option("--full-page", "capture the full scrollable page instead of just the viewport").action(guard(cmdScreenshot));
|
|
72164
72683
|
program2.command("write-file <dest>").description("write exact bytes to a file \u2014 handles backticks, quotes, $vars, CRLF without escaping\n\nModes: --b64 PAYLOAD (base64), --from SOURCE (copy file), or piped stdin").option("--from <source>", "copy bytes from this source file instead of stdin/base64").option("--b64 <payload>", "decode base64 payload and write to dest").action(guard(cmdWriteFile));
|
|
72165
|
-
program2.command("replace <file>").description("replace one string in a file; supply old/new text via --old-from/--new-from or --old-b64/--new-b64, and use --all to replace every occurrence").option("--old-from <source>", "read the old text from this source file").option("--new-from <source>", "read the new text from this source file").option("--old-b64 <payload>", "base64 payload for the old text").option("--new-b64 <payload>", "base64 payload for the new text").option("--all", "replace every occurrence instead of requiring a unique match").
|
|
72684
|
+
program2.command("replace <file>").description("replace one string in a file; supply old/new text via --old-from/--new-from or --old-b64/--new-b64, and use --all to replace every occurrence").option("--old-from <source>", "read the old text from this source file").option("--new-from <source>", "read the new text from this source file").option("--old-b64 <payload>", "base64 payload for the old text").option("--new-b64 <payload>", "base64 payload for the new text").option("--all", "replace every occurrence instead of requiring a unique match").option(
|
|
72685
|
+
"--normalize-newlines",
|
|
72686
|
+
"convert the old/new text's line endings (CRLF/LF) to match the target file's dominant line ending before matching, instead of requiring a byte-exact line-ending match"
|
|
72687
|
+
).action(guard(cmdReplace));
|
|
72688
|
+
program2.command("insert-section <file>").description(
|
|
72689
|
+
"insert content immediately after a matched section (spec resolved the same way as `section`: exact heading, or an unambiguous prefix), avoiding a stale byte-exact anchor for append-to-a-running-log edits"
|
|
72690
|
+
).requiredOption("--after <heading>", "heading text (or unambiguous prefix) to insert after").option("--content-from <source>", "read the content to insert from this source file").option("--content-b64 <payload>", "base64 payload for the content to insert").action(guard(cmdInsertSection));
|
|
72691
|
+
program2.command("note-add <file>").description(
|
|
72692
|
+
"attach a free-text architecture note to a file, or to one specific indexed symbol within it (--symbol NAME), fingerprinting what the note describes so `note-list --stale-only` can flag it once the code changes"
|
|
72693
|
+
).option("--symbol <name>", "attach the note to one indexed symbol in the file instead of the whole file").option("--content-from <source>", "read the note content (Markdown) from this source file").option("--content-b64 <payload>", "base64 payload for the note content").action(guard(cmdNoteAdd));
|
|
72694
|
+
program2.command("note-get <file>").description("read back the note attached to a file, or to one indexed symbol within it (--symbol NAME); flags whether it has gone stale since it was written").option("--symbol <name>", "read the note attached to this indexed symbol instead of the whole-file note").option("-j, --json", "output as JSON").action(
|
|
72695
|
+
(file2, opts) => runExitText(
|
|
72696
|
+
() => runNoteGet({
|
|
72697
|
+
file: file2,
|
|
72698
|
+
...opts.symbol !== void 0 ? { symbol: opts.symbol } : {},
|
|
72699
|
+
...opts.json === true ? { json: true } : {}
|
|
72700
|
+
})
|
|
72701
|
+
)
|
|
72702
|
+
);
|
|
72703
|
+
program2.command("note-list").description("list every recorded architecture note; --stale-only shows just the notes whose attached file/symbol changed since they were written").option("--stale-only", "only list notes whose fingerprint no longer matches the current index").option("-j, --json", "output as JSON").action(
|
|
72704
|
+
(opts) => runExitText(
|
|
72705
|
+
() => runNoteList({
|
|
72706
|
+
...opts.staleOnly === true ? { staleOnly: true } : {},
|
|
72707
|
+
...opts.json === true ? { json: true } : {}
|
|
72708
|
+
})
|
|
72709
|
+
)
|
|
72710
|
+
);
|
|
72166
72711
|
program2.command("gdrive-sections <file-id>").description("fetch and list sections from a public Google Doc").option("--heading <name>", "get content of one named section").option("--fresh", "skip the on-disk cache and force a live fetch").action(guard(cmdGdriveSections));
|
|
72167
72712
|
program2.command("compress").description("run a shell command and emit a compressed view of its output").requiredOption("-c, --cmd <command>", "the shell command to run, as one string").option("-f, --filter <name>", "filter name (auto-detected from the command when omitted)").option("--timeout <seconds>", "wall-clock timeout in seconds (0 = built-in default)").option("--no-compress", "stream output raw without compression (debug the wrapper)").option("--profile <name>", "compression profile: aggressive | balanced | minimal").option("--max-tokens <n>", "post-compress token cap (0 = no cap)").action(cmdCompress);
|
|
72168
72713
|
program2.command("version").description("print the token-goat version").action(
|
|
@@ -78322,7 +78867,7 @@ function preFetchHandler(event) {
|
|
|
78322
78867
|
if (cached2 !== null) {
|
|
78323
78868
|
const cachedBytes = Buffer.byteLength(cached2, "utf-8");
|
|
78324
78869
|
if (cachedBytes >= loadConfig().hints.web_dedup_min_bytes) {
|
|
78325
|
-
recordStat("webfetch:recall", cachedBytes, Math.round(
|
|
78870
|
+
recordStat("webfetch:recall", cachedBytes, Math.round(cachedBytes / 4));
|
|
78326
78871
|
return denyOutput(
|
|
78327
78872
|
"Already fetched this URL with this prompt; the response is cached. Use `token-goat web-output " + cacheId + "` to recall it (append `--grep PATTERN` to filter or `--section Heading` for a markdown section) instead of re-fetching."
|
|
78328
78873
|
);
|
|
@@ -79958,8 +80503,9 @@ function storeMcpOutput(sessionId, toolName, toolInput, resultText) {
|
|
|
79958
80503
|
const rawSizeBytes = Buffer.byteLength(resultText, "utf-8");
|
|
79959
80504
|
if (rawSizeBytes > MCP_MAX_CACHE_BYTES) return null;
|
|
79960
80505
|
const id = mcpOutputId(sessionId, mcpHash(toolName, toolInput));
|
|
79961
|
-
const
|
|
80506
|
+
const rawLabel = `mcp:${toolName} ${mcpInputPreview(toolInput)}`.trim();
|
|
79962
80507
|
const redactedOutput = redactSecrets(resultText).text;
|
|
80508
|
+
const label = redactSecrets(rawLabel).text;
|
|
79963
80509
|
const entry = {
|
|
79964
80510
|
id,
|
|
79965
80511
|
command: label,
|
|
@@ -80228,6 +80774,7 @@ function compressMcpResultWithPacks(toolName, resultText) {
|
|
|
80228
80774
|
}
|
|
80229
80775
|
|
|
80230
80776
|
// src/hooks_mcp.ts
|
|
80777
|
+
init_secret_redact();
|
|
80231
80778
|
function isMcpErrorResponse(raw) {
|
|
80232
80779
|
const tr = raw["tool_response"];
|
|
80233
80780
|
if (!tr || typeof tr !== "object") return false;
|
|
@@ -80267,7 +80814,7 @@ function postMcpHandler(event) {
|
|
|
80267
80814
|
return {
|
|
80268
80815
|
hookType: "rewriteOutput",
|
|
80269
80816
|
updatedOutput: `[token-goat: compressed, full via mcp-output ${id}]
|
|
80270
|
-
${compressed}`
|
|
80817
|
+
${redactSecrets(compressed).text}`
|
|
80271
80818
|
};
|
|
80272
80819
|
}
|
|
80273
80820
|
}
|