token-goat 2.9.11 → 2.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/{token-goat-chunk-FDURVZQD.mjs → token-goat-chunk-2WC4ZUXN.mjs} +1 -1
- package/dist/{token-goat-chunk-MRZ555B3.mjs → token-goat-chunk-3ESRORNM.mjs} +188 -97
- package/dist/token-goat-chunk-4NXUKV7D.mjs +56 -0
- package/dist/{token-goat-chunk-Y5VKNLVD.mjs → token-goat-chunk-6B44WLIF.mjs} +5 -5
- package/dist/{token-goat-chunk-2ZUPQYLO.mjs → token-goat-chunk-B3CTCQTH.mjs} +1 -1
- package/dist/{token-goat-chunk-V53Z47ZH.mjs → token-goat-chunk-FQCNJV4V.mjs} +20 -6
- package/dist/{token-goat-chunk-3ZALKJ23.mjs → token-goat-chunk-FZU7GMUS.mjs} +49 -24
- package/dist/{token-goat-chunk-AAEYU2U2.mjs → token-goat-chunk-JOXLE672.mjs} +344 -5699
- package/dist/{token-goat-chunk-HDL77BN3.mjs → token-goat-chunk-JVNPCQB7.mjs} +10 -7
- package/dist/{token-goat-chunk-LHLQFGWQ.mjs → token-goat-chunk-OMNQUUIT.mjs} +9 -27
- package/dist/{token-goat-chunk-PJPFOOGM.mjs → token-goat-chunk-P2PU4CR5.mjs} +8 -6
- package/dist/{token-goat-chunk-YCKCFYTM.mjs → token-goat-chunk-QKXBGBQR.mjs} +110 -21
- package/dist/{token-goat-chunk-MKITQ5RY.mjs → token-goat-chunk-QWSUZWFP.mjs} +44 -33
- package/dist/{token-goat-chunk-4NZUXC4F.mjs → token-goat-chunk-RDITECDL.mjs} +7 -5
- package/dist/{token-goat-chunk-LKOYKSID.mjs → token-goat-chunk-U7X6LQD2.mjs} +271 -69
- package/dist/token-goat-chunk-UM47DRD3.mjs +242 -0
- package/dist/token-goat-chunk-UMXJN7DI.mjs +5521 -0
- package/dist/token-goat-chunk-YOA4N6WA.mjs +308 -0
- package/dist/{token-goat-chunk-SY7WTZMW.mjs → token-goat-chunk-ZZI3IDQZ.mjs} +1016 -995
- package/dist/token-goat-hook.mjs +8 -6
- package/dist/token-goat.core.mjs +10 -7
- package/docs/cli.md +11 -8
- package/docs/security.md +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
stripMultilineStringSpan,
|
|
10
10
|
stripNestedBlockCommentSpan,
|
|
11
11
|
stripStringLiterals
|
|
12
|
-
} from "./token-goat-chunk-
|
|
12
|
+
} from "./token-goat-chunk-QKXBGBQR.mjs";
|
|
13
13
|
import {
|
|
14
14
|
init_define_import_meta_env
|
|
15
15
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -5,19 +5,23 @@ import {
|
|
|
5
5
|
enqueueDirtyPathSafe,
|
|
6
6
|
getProjectFileEntries,
|
|
7
7
|
getTrackedFiles,
|
|
8
|
-
indexRecallEntry
|
|
8
|
+
indexRecallEntry
|
|
9
|
+
} from "./token-goat-chunk-ZZI3IDQZ.mjs";
|
|
10
|
+
import {
|
|
11
|
+
estimateTokensFromLength
|
|
12
|
+
} from "./token-goat-chunk-JOXLE672.mjs";
|
|
13
|
+
import {
|
|
9
14
|
isBlobStale,
|
|
10
15
|
loadBlob,
|
|
11
16
|
storeBlob
|
|
12
|
-
} from "./token-goat-chunk-
|
|
17
|
+
} from "./token-goat-chunk-UM47DRD3.mjs";
|
|
13
18
|
import {
|
|
14
|
-
estimateTokensFromLength,
|
|
15
19
|
fingerprintFile,
|
|
16
20
|
getDb,
|
|
17
21
|
getDisplayRoot,
|
|
18
22
|
redactSecrets,
|
|
19
23
|
shortFingerprint
|
|
20
|
-
} from "./token-goat-chunk-
|
|
24
|
+
} from "./token-goat-chunk-UMXJN7DI.mjs";
|
|
21
25
|
import {
|
|
22
26
|
registerReset
|
|
23
27
|
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
@@ -33,7 +37,7 @@ import {
|
|
|
33
37
|
normalizePath,
|
|
34
38
|
resolveIndexPath,
|
|
35
39
|
toDisplayPath
|
|
36
|
-
} from "./token-goat-chunk-
|
|
40
|
+
} from "./token-goat-chunk-QKXBGBQR.mjs";
|
|
37
41
|
import {
|
|
38
42
|
init_define_import_meta_env
|
|
39
43
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -319,7 +323,17 @@ function reconcileProject(opts = {}) {
|
|
|
319
323
|
const removed = [];
|
|
320
324
|
if (!budgetExhausted && !trackedUnavailable) {
|
|
321
325
|
for (const [folded, entry] of indexed) {
|
|
322
|
-
if (
|
|
326
|
+
if (seenOnDisk.has(folded)) continue;
|
|
327
|
+
if (Date.now() - startedAt > budgetMs) {
|
|
328
|
+
budgetExhausted = true;
|
|
329
|
+
removed.length = 0;
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
fs.statSync(entry.filePath);
|
|
334
|
+
} catch {
|
|
335
|
+
removed.push(entry.filePath);
|
|
336
|
+
}
|
|
323
337
|
}
|
|
324
338
|
}
|
|
325
339
|
let enqueued = 0;
|
|
@@ -25,8 +25,7 @@ import {
|
|
|
25
25
|
runSkeleton,
|
|
26
26
|
runSymbol,
|
|
27
27
|
withPinnedReads
|
|
28
|
-
} from "./token-goat-chunk-
|
|
29
|
-
import "./token-goat-chunk-2ZUPQYLO.mjs";
|
|
28
|
+
} from "./token-goat-chunk-U7X6LQD2.mjs";
|
|
30
29
|
import {
|
|
31
30
|
buildProjectMap,
|
|
32
31
|
embeddingsDepsAvailable,
|
|
@@ -35,7 +34,10 @@ import {
|
|
|
35
34
|
getProjectIndexCounts,
|
|
36
35
|
isWorkerRunning,
|
|
37
36
|
mapLookupBytesSaved
|
|
38
|
-
} from "./token-goat-chunk-
|
|
37
|
+
} from "./token-goat-chunk-ZZI3IDQZ.mjs";
|
|
38
|
+
import "./token-goat-chunk-JOXLE672.mjs";
|
|
39
|
+
import "./token-goat-chunk-YOA4N6WA.mjs";
|
|
40
|
+
import "./token-goat-chunk-UM47DRD3.mjs";
|
|
39
41
|
import {
|
|
40
42
|
envStrList,
|
|
41
43
|
getDb,
|
|
@@ -43,8 +45,9 @@ import {
|
|
|
43
45
|
recordStat,
|
|
44
46
|
resolveProjectRoot,
|
|
45
47
|
savedTokensFromBytes
|
|
46
|
-
} from "./token-goat-chunk-
|
|
48
|
+
} from "./token-goat-chunk-UMXJN7DI.mjs";
|
|
47
49
|
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
50
|
+
import "./token-goat-chunk-B3CTCQTH.mjs";
|
|
48
51
|
import {
|
|
49
52
|
ENV_KEYS,
|
|
50
53
|
VERSION,
|
|
@@ -54,7 +57,7 @@ import {
|
|
|
54
57
|
foldCaseForContainment,
|
|
55
58
|
globalDbPath,
|
|
56
59
|
normalizePath
|
|
57
|
-
} from "./token-goat-chunk-
|
|
60
|
+
} from "./token-goat-chunk-QKXBGBQR.mjs";
|
|
58
61
|
import {
|
|
59
62
|
init_define_import_meta_env
|
|
60
63
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -242,7 +245,7 @@ function mcpToolAllowlist() {
|
|
|
242
245
|
return names.length === 0 ? null : new Set(names);
|
|
243
246
|
}
|
|
244
247
|
async function createMcpServer() {
|
|
245
|
-
const [{ McpServer }, { z }] = await Promise.all([import("./token-goat-chunk-
|
|
248
|
+
const [{ McpServer }, { z }] = await Promise.all([import("./token-goat-chunk-OMNQUUIT.mjs"), import("./token-goat-chunk-T6M7DAW3.mjs")]);
|
|
246
249
|
const server = new McpServer({ name: "token-goat", version: VERSION });
|
|
247
250
|
const allowlist = mcpToolAllowlist();
|
|
248
251
|
if (allowlist !== null) {
|
|
@@ -276,7 +279,8 @@ async function createMcpServer() {
|
|
|
276
279
|
kind: z.string().optional().describe("restrict to one kind (function, class, ...)"),
|
|
277
280
|
json: z.boolean().optional().describe("output as JSON"),
|
|
278
281
|
projectRoot: projectRootField
|
|
279
|
-
}
|
|
282
|
+
},
|
|
283
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
280
284
|
},
|
|
281
285
|
(args) => {
|
|
282
286
|
const { name, limit, file, kind, json, projectRoot } = args;
|
|
@@ -314,7 +318,9 @@ async function createMcpServer() {
|
|
|
314
318
|
forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
|
|
315
319
|
stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
|
|
316
320
|
projectRoot: projectRootField
|
|
317
|
-
}
|
|
321
|
+
},
|
|
322
|
+
// What readOnlyHint claims here, once, for all fifteen tools that carry it: the caller's own environment is untouched -- the project's files, and anything the caller would notice missing. Three things these tools do are deliberately outside that. They append a row to token-goat's `stats` table. They may reparse a file whose index entry is stale, and enqueue it for the background indexer. Opening a database for the first time creates its schema. All three are token-goat's own derived state, rebuilt from the project on demand and worth nothing if deleted; calling a symbol lookup a writing tool on their account would cost the caller a confirmation prompt for every read while protecting nothing. A tool that touches anything the caller owns says so instead, and the guard beside this file measures which tools those are rather than trusting the claim.
|
|
323
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
318
324
|
},
|
|
319
325
|
(args) => {
|
|
320
326
|
const { spec, json, forceRefresh, stats, projectRoot } = args;
|
|
@@ -343,7 +349,8 @@ async function createMcpServer() {
|
|
|
343
349
|
spec: z.string().describe("file::Heading"),
|
|
344
350
|
json: z.boolean().optional().describe("output as JSON"),
|
|
345
351
|
projectRoot: projectRootField
|
|
346
|
-
}
|
|
352
|
+
},
|
|
353
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
347
354
|
},
|
|
348
355
|
(args) => {
|
|
349
356
|
const { spec, json, projectRoot } = args;
|
|
@@ -373,7 +380,8 @@ async function createMcpServer() {
|
|
|
373
380
|
forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
|
|
374
381
|
stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
|
|
375
382
|
projectRoot: projectRootField
|
|
376
|
-
}
|
|
383
|
+
},
|
|
384
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
377
385
|
},
|
|
378
386
|
(args) => {
|
|
379
387
|
const { file, json, minLines, forceRefresh, stats, projectRoot } = args;
|
|
@@ -406,7 +414,8 @@ async function createMcpServer() {
|
|
|
406
414
|
forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
|
|
407
415
|
stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
|
|
408
416
|
projectRoot: projectRootField
|
|
409
|
-
}
|
|
417
|
+
},
|
|
418
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
410
419
|
},
|
|
411
420
|
(args) => {
|
|
412
421
|
const { file, json, minLines, forceRefresh, stats, projectRoot } = args;
|
|
@@ -439,7 +448,9 @@ async function createMcpServer() {
|
|
|
439
448
|
excludeTests: z.boolean().optional().describe("hide hits whose file is a test file (opt-in; default output is unchanged)"),
|
|
440
449
|
json: z.boolean().optional().describe("output as JSON"),
|
|
441
450
|
projectRoot: makeProjectRootField("search")
|
|
442
|
-
}
|
|
451
|
+
},
|
|
452
|
+
// openWorldHint stays false although a first call on a machine with no cached model downloads one over the network: what this tool interacts with is the local index, and the download provisions the tool rather than being the tool reaching out. A client reading `true` here would take it as "this searches the internet", which is the wrong warning.
|
|
453
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
443
454
|
},
|
|
444
455
|
async (args) => {
|
|
445
456
|
const { query, limit, grep, excludeTests, json, projectRoot } = args;
|
|
@@ -461,7 +472,8 @@ async function createMcpServer() {
|
|
|
461
472
|
description: 'Report whether the index for a project can be trusted right now: whether it has ever been indexed at all, current file/symbol counts, dirty-reindex-queue depth, whether the background worker is alive, and whether embeddings are available (semantic silently degrades to full-text search without them). Call this after an unexpectedly empty result from another token-goat tool (symbol/read/semantic/refs/brief/...) to tell apart "no match" from "the index is not ready yet" -- an MCP-only client has no hook layer to warn about this on its own, so an empty tool result and a stale/unindexed project look identical without this check.',
|
|
462
473
|
inputSchema: {
|
|
463
474
|
projectRoot: makeProjectRootField("check")
|
|
464
|
-
}
|
|
475
|
+
},
|
|
476
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
465
477
|
},
|
|
466
478
|
(args) => {
|
|
467
479
|
const { projectRoot } = args;
|
|
@@ -520,7 +532,8 @@ async function createMcpServer() {
|
|
|
520
532
|
),
|
|
521
533
|
json: z.boolean().optional().describe("output as JSON"),
|
|
522
534
|
projectRoot: projectRootField
|
|
523
|
-
}
|
|
535
|
+
},
|
|
536
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
524
537
|
},
|
|
525
538
|
(args) => {
|
|
526
539
|
const { spec, callers, limit, top, json, projectRoot } = args;
|
|
@@ -554,7 +567,8 @@ async function createMcpServer() {
|
|
|
554
567
|
excludeTests: z.boolean().optional().describe("hide callers whose call site lives in a test file (opt-in; default output is unchanged)"),
|
|
555
568
|
grep: z.string().optional().describe("only show callers whose enclosing symbol name matches this regex (literal substring if it is not valid regex)"),
|
|
556
569
|
projectRoot: makeProjectRootField("orient")
|
|
557
|
-
}
|
|
570
|
+
},
|
|
571
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
558
572
|
},
|
|
559
573
|
(args) => {
|
|
560
574
|
const { spec, limit, json, context, excludeTests, grep, projectRoot } = args;
|
|
@@ -584,7 +598,8 @@ async function createMcpServer() {
|
|
|
584
598
|
inputSchema: {
|
|
585
599
|
compact: z.boolean().optional().describe("compact, low-token summary"),
|
|
586
600
|
projectRoot: makeProjectRootField("overview")
|
|
587
|
-
}
|
|
601
|
+
},
|
|
602
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
588
603
|
},
|
|
589
604
|
(args) => {
|
|
590
605
|
const { compact, projectRoot } = args;
|
|
@@ -604,7 +619,8 @@ async function createMcpServer() {
|
|
|
604
619
|
symbolMode: z.boolean().optional().describe("list symbols instead of files"),
|
|
605
620
|
json: z.boolean().optional().describe("output as JSON"),
|
|
606
621
|
projectRoot: projectRootField
|
|
607
|
-
}
|
|
622
|
+
},
|
|
623
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
608
624
|
},
|
|
609
625
|
(args) => {
|
|
610
626
|
const { ref, symbolMode, json, projectRoot } = args;
|
|
@@ -631,7 +647,8 @@ async function createMcpServer() {
|
|
|
631
647
|
context: z.number().int().nonnegative().max(MCP_MAX_CONTEXT_LINES).optional().describe("lines of context to show before and after each match"),
|
|
632
648
|
// runGrep takes no projectRoot of its own (its `path` array is its scope), so this field only names the root the confinement check is made against -- without it, a search rooted anywhere but the server process's cwd is refused.
|
|
633
649
|
projectRoot: makeProjectRootField("search")
|
|
634
|
-
}
|
|
650
|
+
},
|
|
651
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
635
652
|
},
|
|
636
653
|
(args) => {
|
|
637
654
|
const { pattern, path: searchPath, maxLines, json, recursive, context, projectRoot } = args;
|
|
@@ -663,7 +680,8 @@ async function createMcpServer() {
|
|
|
663
680
|
file: z.string().describe("file path"),
|
|
664
681
|
json: z.boolean().optional().describe("output as JSON"),
|
|
665
682
|
projectRoot: projectRootField
|
|
666
|
-
}
|
|
683
|
+
},
|
|
684
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
667
685
|
},
|
|
668
686
|
(args) => {
|
|
669
687
|
const { file, json, projectRoot } = args;
|
|
@@ -686,7 +704,8 @@ async function createMcpServer() {
|
|
|
686
704
|
file: z.string().describe("file path"),
|
|
687
705
|
json: z.boolean().optional().describe("output as JSON"),
|
|
688
706
|
projectRoot: projectRootField
|
|
689
|
-
}
|
|
707
|
+
},
|
|
708
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
690
709
|
},
|
|
691
710
|
(args) => {
|
|
692
711
|
const { file, json, projectRoot } = args;
|
|
@@ -707,7 +726,9 @@ async function createMcpServer() {
|
|
|
707
726
|
description: "Compress arbitrary local text, persist it in the bounded local cache, and return an opaque recovery ID plus metadata.",
|
|
708
727
|
inputSchema: {
|
|
709
728
|
text: z.string().max(CONTENT_MAX_INPUT_CHARS).describe("text to compress")
|
|
710
|
-
}
|
|
729
|
+
},
|
|
730
|
+
// destructiveHint is true for every tool that writes here, including the ones that only ever add: the store is bounded by item count and by total bytes, so a write can evict an earlier entry and leave a recovery id the caller is holding unredeemable. idempotentHint survives a repeat writing a fresh timestamp and another stats row, on the same reading of "its environment" set out on the read tool above.
|
|
731
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
|
|
711
732
|
},
|
|
712
733
|
(args) => toCallToolResult({ text: displaySafeJson(compressionPayload(compressText(args.text))), code: 0 })
|
|
713
734
|
);
|
|
@@ -717,7 +738,8 @@ async function createMcpServer() {
|
|
|
717
738
|
description: "Retrieve original text from a token-goat compression ID.",
|
|
718
739
|
inputSchema: {
|
|
719
740
|
id: z.string().regex(/^tg_[0-9a-f]{16}$/).describe("opaque token-goat content ID")
|
|
720
|
-
}
|
|
741
|
+
},
|
|
742
|
+
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
721
743
|
},
|
|
722
744
|
(args) => {
|
|
723
745
|
const text = retrieveText(args.id);
|
|
@@ -732,7 +754,8 @@ async function createMcpServer() {
|
|
|
732
754
|
name: z.string().regex(/^[A-Za-z0-9._-]{1,128}$/).describe("handoff name"),
|
|
733
755
|
text: z.string().max(CONTENT_MAX_INPUT_CHARS).describe("handoff text"),
|
|
734
756
|
projectRoot: makeProjectRootField("scope")
|
|
735
|
-
}
|
|
757
|
+
},
|
|
758
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
|
|
736
759
|
},
|
|
737
760
|
(args) => toCallToolResult({
|
|
738
761
|
text: displaySafeJson(createHandoff(args.name, args.text, resolveToolRoot(args.projectRoot))),
|
|
@@ -747,7 +770,9 @@ async function createMcpServer() {
|
|
|
747
770
|
name: z.string().regex(/^[A-Za-z0-9._-]{1,128}$/).describe("handoff name"),
|
|
748
771
|
full: z.boolean().optional().describe("return full text instead of a compact payload"),
|
|
749
772
|
projectRoot: makeProjectRootField("scope")
|
|
750
|
-
}
|
|
773
|
+
},
|
|
774
|
+
// Reads like a read, and is not one: resolving compactly runs the handoff text back through compressText, which stores the compact payload so the recovery id it hands back can be redeemed. A measurement, not a reading of this code -- the guard hashes the store's bytes around every tool call, and this is the tool it caught.
|
|
775
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
|
|
751
776
|
},
|
|
752
777
|
(args) => {
|
|
753
778
|
const result = resolveHandoff(args.name, {
|