token-goat 2.9.26 → 2.9.29

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.
Files changed (78) hide show
  1. package/README.md +30 -88
  2. package/SECURITY.md +14 -0
  3. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-2AWQ2R5X.mjs} +2 -2
  4. package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-2NNUA2LR.mjs} +4 -4
  5. package/dist/token-goat-chunk-2WOUYWLM.mjs +955 -0
  6. package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-435UQTKD.mjs} +5 -3
  7. package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-44BM7DDQ.mjs} +5 -3
  8. package/dist/token-goat-chunk-52NSDWYY.mjs +96 -0
  9. package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-67BNIKKO.mjs} +32 -18
  10. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-6AK46ZT7.mjs} +2 -3
  11. package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-7CPMDFGB.mjs} +166 -40
  12. package/dist/token-goat-chunk-ASLWOQ3I.mjs +14 -0
  13. package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-BGYOZ6DO.mjs} +6 -4
  14. package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-C5YPNZKQ.mjs} +22 -8
  15. package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-CIQ2FTY3.mjs} +23 -242
  16. package/dist/token-goat-chunk-D4ETHJD6.mjs +246 -0
  17. package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-DNRPXHYH.mjs} +25 -17
  18. package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-DNSPXQXQ.mjs} +2 -2
  19. package/dist/token-goat-chunk-DPNLUJWB.mjs +220 -0
  20. package/dist/token-goat-chunk-E4ZOJIZK.mjs +1382 -0
  21. package/dist/token-goat-chunk-E5TK5DNO.mjs +718 -0
  22. package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-EUSDXRXU.mjs} +62 -12
  23. package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-FTP4U4QA.mjs} +12 -8
  24. package/dist/token-goat-chunk-G23DWHV4.mjs +142 -0
  25. package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-G7IWXCFF.mjs} +223 -15
  26. package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-GLXRTTLE.mjs} +7 -5
  27. package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-H5J3C56Q.mjs} +95 -573
  28. package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-HNFZZHFW.mjs} +2 -2
  29. package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-HUYUHODZ.mjs} +1036 -759
  30. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  31. package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-IVWI2OCK.mjs} +72 -45
  32. package/dist/{token-goat-chunk-GMOUBOX4.mjs → token-goat-chunk-JTKCQMQA.mjs} +37 -5
  33. package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-KOPIR3KZ.mjs} +46 -23
  34. package/dist/token-goat-chunk-L7H3U27L.mjs +35 -0
  35. package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-LZNBQTDK.mjs} +6 -4
  36. package/dist/token-goat-chunk-MELOKFDJ.mjs +199 -0
  37. package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-NMBWLRHW.mjs} +164 -50
  38. package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-O6I2XU4P.mjs} +27 -967
  39. package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-ONXH6NZ5.mjs} +2 -87
  40. package/dist/token-goat-chunk-ORNFMIER.mjs +295 -0
  41. package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-PGTH2U4C.mjs} +1 -1
  42. package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-PKRWMHVP.mjs} +76 -59
  43. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-PQ53BSCF.mjs} +1 -1
  44. package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-PYSUADX4.mjs} +2 -2
  45. package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-QO3LXVVR.mjs} +4247 -5005
  46. package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-RLP6J7WR.mjs} +6 -6
  47. package/dist/token-goat-chunk-RQGGMPCR.mjs +205 -0
  48. package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-RTMVLHWX.mjs} +3708 -4003
  49. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-S4VSXURL.mjs} +8 -6
  50. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-SE6E4BKJ.mjs} +1 -1
  51. package/dist/token-goat-chunk-TCQANXYC.mjs +351 -0
  52. package/dist/token-goat-chunk-TDUT2CL6.mjs +564 -0
  53. package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-TGOXNAHW.mjs} +54 -111
  54. package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-UA5BKWWQ.mjs} +1 -1
  55. package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UXSXQQIY.mjs} +1 -1
  56. package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-VMFWNHGR.mjs} +84 -73
  57. package/dist/token-goat-chunk-VQ6F6T7X.mjs +36 -0
  58. package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-VZQEWRVH.mjs} +6 -4
  59. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  60. package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-XYWPOSCN.mjs} +57 -615
  61. package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-YAGLESS3.mjs} +8 -5
  62. package/dist/token-goat-chunk-YKSRAWUU.mjs +33 -0
  63. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-YOOVFPTP.mjs} +2 -2
  64. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  65. package/dist/token-goat-chunk-Z6KBMOBI.mjs +53 -0
  66. package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-ZER6EAXZ.mjs} +81 -70
  67. package/dist/token-goat-hook-client.cjs +475 -0
  68. package/dist/token-goat-hook-client.mjs +26 -0
  69. package/dist/token-goat-hook.mjs +31 -21
  70. package/dist/token-goat.core.mjs +9 -39
  71. package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
  72. package/docs/cli.md +35 -23
  73. package/docs/install.md +18 -14
  74. package/package.json +1 -1
  75. package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
  76. package/dist/token-goat-chunk-E6B2UFDF.mjs +0 -30
  77. package/dist/token-goat-chunk-GKZ2US5B.mjs +0 -187
  78. package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
@@ -25,10 +25,11 @@ import {
25
25
  runSemantic,
26
26
  runSkeleton,
27
27
  runSymbol,
28
+ statThroughHandle,
28
29
  withPinnedReads
29
- } from "./token-goat-chunk-RH27ZSPF.mjs";
30
- import "./token-goat-chunk-5M3NRJD2.mjs";
31
- import "./token-goat-chunk-DA43OE7L.mjs";
30
+ } from "./token-goat-chunk-NMBWLRHW.mjs";
31
+ import "./token-goat-chunk-VZQEWRVH.mjs";
32
+ import "./token-goat-chunk-PQ53BSCF.mjs";
32
33
  import {
33
34
  buildProjectMap,
34
35
  formatProjectMap,
@@ -37,54 +38,66 @@ import {
37
38
  getProjectIndexCounts,
38
39
  isWorkerRunning,
39
40
  mapLookupBytesSaved
40
- } from "./token-goat-chunk-MBDJR6HU.mjs";
41
- import "./token-goat-chunk-4GEDH2WU.mjs";
42
- import "./token-goat-chunk-VVROQBQJ.mjs";
43
- import "./token-goat-chunk-M6CVNHTW.mjs";
41
+ } from "./token-goat-chunk-RTMVLHWX.mjs";
42
+ import "./token-goat-chunk-L7H3U27L.mjs";
43
+ import "./token-goat-chunk-RRNZMM3A.mjs";
44
+ import "./token-goat-chunk-E5TK5DNO.mjs";
45
+ import "./token-goat-chunk-ZER6EAXZ.mjs";
46
+ import "./token-goat-chunk-EUSDXRXU.mjs";
47
+ import "./token-goat-chunk-H5J3C56Q.mjs";
48
+ import "./token-goat-chunk-TDUT2CL6.mjs";
44
49
  import {
45
50
  claudeConfigDir
46
- } from "./token-goat-chunk-G6EYO5CD.mjs";
47
- import "./token-goat-chunk-43JFN26X.mjs";
51
+ } from "./token-goat-chunk-ONXH6NZ5.mjs";
52
+ import "./token-goat-chunk-O6I2XU4P.mjs";
53
+ import "./token-goat-chunk-D4ETHJD6.mjs";
54
+ import "./token-goat-chunk-52NSDWYY.mjs";
55
+ import "./token-goat-chunk-2WOUYWLM.mjs";
48
56
  import {
49
57
  recordStat,
50
58
  savedTokensFromBytes
51
- } from "./token-goat-chunk-D2X7XN5M.mjs";
52
- import "./token-goat-chunk-LKSXAMJB.mjs";
53
- import "./token-goat-chunk-L43RKNHA.mjs";
59
+ } from "./token-goat-chunk-CIQ2FTY3.mjs";
60
+ import "./token-goat-chunk-SE6E4BKJ.mjs";
61
+ import "./token-goat-chunk-DNSPXQXQ.mjs";
54
62
  import "./token-goat-chunk-3BTK54F3.mjs";
55
63
  import "./token-goat-chunk-XTQAOTSO.mjs";
56
64
  import "./token-goat-chunk-AH6QILZM.mjs";
57
- import "./token-goat-chunk-LHUP4DXZ.mjs";
65
+ import "./token-goat-chunk-PGTH2U4C.mjs";
58
66
  import {
59
67
  checkEmbeddingPreflight,
60
68
  embeddingsDepsAvailable
61
- } from "./token-goat-chunk-7EPYB34H.mjs";
62
- import "./token-goat-chunk-IKZLSRII.mjs";
69
+ } from "./token-goat-chunk-VMFWNHGR.mjs";
70
+ import "./token-goat-chunk-435UQTKD.mjs";
63
71
  import {
64
72
  getDb
65
- } from "./token-goat-chunk-7SXPJOSZ.mjs";
73
+ } from "./token-goat-chunk-7CPMDFGB.mjs";
66
74
  import {
67
- envStrList,
68
75
  loadConfig,
69
76
  resolveProjectRoot
70
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
71
- import "./token-goat-chunk-EEIDFMEM.mjs";
72
- import "./token-goat-chunk-OSUFN2FV.mjs";
77
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
78
+ import "./token-goat-chunk-XB5KKOCG.mjs";
79
+ import "./token-goat-chunk-YZAAZU2S.mjs";
73
80
  import {
74
- ENV_KEYS,
75
- VERSION,
76
- dataDir,
77
- extractErrorMessage,
78
- foldCaseForContainment,
79
- globalDbPath
80
- } from "./token-goat-chunk-6E2IDLHF.mjs";
81
+ envStrList
82
+ } from "./token-goat-chunk-IVE6U7KV.mjs";
83
+ import {
84
+ extractErrorMessage
85
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
86
+ import {
87
+ foldCaseForContainment
88
+ } from "./token-goat-chunk-TCQANXYC.mjs";
81
89
  import {
82
90
  displaySafeJson,
83
91
  normalizePath
84
92
  } from "./token-goat-chunk-NMTKNYGF.mjs";
93
+ import {
94
+ ENV_KEYS,
95
+ VERSION,
96
+ dataDir,
97
+ globalDbPath
98
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
85
99
  import "./token-goat-chunk-Y4AFKTHK.mjs";
86
- import "./token-goat-chunk-GMOUBOX4.mjs";
87
- import "./token-goat-chunk-RRNZMM3A.mjs";
100
+ import "./token-goat-chunk-JTKCQMQA.mjs";
88
101
  import {
89
102
  init_define_import_meta_env
90
103
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -98,6 +111,7 @@ var TOKEN_GOAT_RETRY_RE = /token-goat (\w[\w-]*) "([^"]+)"/g;
98
111
  var MCP_MAX_LIMIT = 1e3;
99
112
  var MCP_MAX_CONTEXT_LINES = 50;
100
113
  var MCP_MAX_OUTPUT_LINES = 1e4;
114
+ var MCP_MAX_MIN_LINES = 1e5;
101
115
  var RETRY_PARAM_BY_COMMAND = {
102
116
  read: "spec",
103
117
  section: "spec",
@@ -216,6 +230,12 @@ function assertRootAllowed(resolvedRoot) {
216
230
  }
217
231
  var NO_CHECK_PINS = [];
218
232
  function identityOf(p) {
233
+ try {
234
+ return fileIdentity(statThroughHandle(p));
235
+ } catch (err) {
236
+ const code = err.code;
237
+ if (code === "ENOENT" || code === "ENOTDIR") return null;
238
+ }
219
239
  try {
220
240
  return fileIdentity(fs.statSync(p, { bigint: true }));
221
241
  } catch {
@@ -325,7 +345,7 @@ function mcpToolAllowlist() {
325
345
  return names.length === 0 ? null : new Set(names);
326
346
  }
327
347
  async function createMcpServer() {
328
- const [{ McpServer }, { z }] = await Promise.all([import("./token-goat-chunk-XBESNWEX.mjs"), import("./token-goat-chunk-CHLHM42P.mjs")]);
348
+ const [{ McpServer }, { z }] = await Promise.all([import("./token-goat-chunk-6AK46ZT7.mjs"), import("./token-goat-chunk-CHLHM42P.mjs")]);
329
349
  const server = new McpServer({ name: "token-goat", version: VERSION });
330
350
  const allowlist = mcpToolAllowlist();
331
351
  if (allowlist !== null) {
@@ -344,10 +364,7 @@ async function createMcpServer() {
344
364
  }
345
365
  }, 0).unref();
346
366
  }
347
- const makeProjectRootField = (verb) => z.string().optional().describe(
348
- `absolute path to the workspace root to scope this ${verb} to; defaults to the MCP server process's cwd, which is not always the actual workspace root for MCP clients -- pass this explicitly when it might differ`
349
- );
350
- const projectRootField = makeProjectRootField("lookup");
367
+ const projectRootField = z.string().optional().describe("absolute workspace root; defaults to the server's cwd, which may not be the workspace, so pass it when unsure");
351
368
  server.registerTool(
352
369
  "symbol",
353
370
  {
@@ -391,9 +408,9 @@ async function createMcpServer() {
391
408
  server.registerTool(
392
409
  "read",
393
410
  {
394
- description: "Read one symbol's full body, given a spec of the form file::symbol, or a line range file@N-M / file@N, or a bare file path. Pass a comma-separated spec (file::a,b) to fetch several symbols' bodies from one file in a single call.",
411
+ description: "Read a symbol's full body (file::symbol), several from one file (file::a,b), a line range (file@N-M, file@N), or a file.",
395
412
  inputSchema: {
396
- spec: z.string().describe("file::symbol, file@N-M, file@N, a bare file path, or comma-separated file::a,b for a merged multi-symbol view"),
413
+ spec: z.string().describe("file::symbol, file::a,b, file@N-M, file@N, or a file path"),
397
414
  json: z.boolean().optional().describe("output as JSON"),
398
415
  forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
399
416
  stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
@@ -456,7 +473,7 @@ async function createMcpServer() {
456
473
  inputSchema: {
457
474
  file: z.string().describe("file path"),
458
475
  json: z.boolean().optional().describe("output as JSON"),
459
- minLines: z.number().int().optional().describe("only show symbols at least N lines long"),
476
+ minLines: z.number().int().nonnegative().max(MCP_MAX_MIN_LINES).optional().describe("only show symbols at least N lines long"),
460
477
  forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
461
478
  stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
462
479
  projectRoot: projectRootField
@@ -490,7 +507,7 @@ async function createMcpServer() {
490
507
  inputSchema: {
491
508
  file: z.string().describe("file path"),
492
509
  json: z.boolean().optional().describe("output as JSON"),
493
- minLines: z.number().int().optional().describe("only show symbols at least N lines long"),
510
+ minLines: z.number().int().nonnegative().max(MCP_MAX_MIN_LINES).optional().describe("only show symbols at least N lines long"),
494
511
  forceRefresh: z.boolean().optional().describe("reparse file from disk before querying (ignore stale index)"),
495
512
  stats: z.boolean().optional().describe("add per-symbol reference count and doc-coverage flag"),
496
513
  projectRoot: projectRootField
@@ -520,16 +537,16 @@ async function createMcpServer() {
520
537
  server.registerTool(
521
538
  "semantic",
522
539
  {
523
- description: "Semantic search over the indexed project (falls back to full-text search when no embedding index is available). Scoped to projectRoot if given, else the MCP server process's own cwd -- which may not be the actual workspace root for a client that launched the server from elsewhere, so pass projectRoot explicitly when in doubt.",
540
+ description: "Semantic search over the indexed project; falls back to full-text search without an embedding index.",
524
541
  inputSchema: {
525
542
  query: z.string().describe("natural-language search query"),
526
543
  limit: z.number().int().positive().max(MCP_MAX_LIMIT).optional().describe("max results (default: 20)"),
527
- grep: z.string().optional().describe("filter to hits whose file path matches this regex (literal substring if it does not compile as regex); matched against the path as rendered, same convention as refs --grep"),
528
- excludeTests: z.boolean().optional().describe("hide hits whose file is a test file (opt-in; default output is unchanged)"),
529
- preflight: z.boolean().optional().describe("run semantic embedding preflight check and return status"),
530
- warm: z.boolean().optional().describe("warm up the embedding model session in memory before query execution"),
544
+ grep: z.string().optional().describe("only hits whose file path matches this regex (a literal substring if it is not valid regex)"),
545
+ excludeTests: z.boolean().optional().describe("hide hits in test files"),
546
+ preflight: z.boolean().optional().describe("report whether embeddings are ready, instead of searching"),
547
+ warm: z.boolean().optional().describe("load the embedding model before the query"),
531
548
  json: z.boolean().optional().describe("output as JSON"),
532
- projectRoot: makeProjectRootField("search")
549
+ projectRoot: projectRootField
533
550
  },
534
551
  // 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.
535
552
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -553,9 +570,9 @@ async function createMcpServer() {
553
570
  server.registerTool(
554
571
  "index_status",
555
572
  {
556
- 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.',
573
+ description: 'Whether the project index can be trusted now: indexed at all, file and symbol counts, reindex queue depth, worker alive, and embeddings available (without them semantic falls back to full-text search). Call it when another token-goat tool returns nothing, to tell "no match" from "index not ready".',
557
574
  inputSchema: {
558
- projectRoot: makeProjectRootField("check")
575
+ projectRoot: projectRootField
559
576
  },
560
577
  annotations: { readOnlyHint: true, openWorldHint: false }
561
578
  },
@@ -615,13 +632,13 @@ async function createMcpServer() {
615
632
  server.registerTool(
616
633
  "refs",
617
634
  {
618
- description: "Find references to one or more symbols (spec: file::symbol, symbol, or comma-separated a,b,c / file::a,b for a merged multi-symbol view). For an unambiguous TypeScript symbol, automatically type-resolves candidates via the TypeScript compiler API to drop same-named-different-symbol false positives; falls back to name-based matching when that is not possible.",
635
+ description: "Find references to symbols. An unambiguous TypeScript symbol is type-resolved, dropping same-named symbols; anything else matches by name.",
619
636
  inputSchema: {
620
- spec: z.string().describe("file::symbol, symbol, or comma-separated a,b,c / file::a,b for a merged multi-symbol view"),
637
+ spec: z.string().describe("file::symbol, symbol, a,b,c, or file::a,b"),
621
638
  callers: z.boolean().optional().describe("group references by their enclosing caller symbol"),
622
639
  limit: z.number().int().positive().max(MCP_MAX_LIMIT).optional().describe("max results"),
623
640
  top: z.number().int().positive().max(MCP_MAX_LIMIT).optional().describe(
624
- "for a high-fanout symbol, group references by file (count only) and show only the top N files by reference count instead of a per-line dump"
641
+ "list only the top N files by reference count, instead of every reference"
625
642
  ),
626
643
  json: z.boolean().optional().describe("output as JSON"),
627
644
  projectRoot: projectRootField
@@ -651,15 +668,15 @@ async function createMcpServer() {
651
668
  server.registerTool(
652
669
  "brief",
653
670
  {
654
- description: "One-shot symbol orientation: signature, location, token count, body, callers, and containing doc section, in a single call (spec: file::symbol; comma-separated file::a,b for a merged multi-symbol view; cross-file a.ts::x,b.ts::y is also supported -- unlike refs, a bare symbol name with no file is not accepted). Prefer this over separate read + refs calls when the goal is to understand a symbol, not just fetch its source: it folds the work of read (body) and refs --callers (call sites) into one result, at a fraction of the combined round-trip cost.",
671
+ description: "Understand a symbol in one call: signature, location, token count, body, callers and containing doc section. Prefer it to read plus refs. Spec file::symbol, file::a,b or a.ts::x,b.ts::y; a bare name without a file is not accepted.",
655
672
  inputSchema: {
656
- spec: z.string().describe("file::symbol; comma-separated file::a,b for a merged multi-symbol view; cross-file a.ts::x,b.ts::y is also supported"),
673
+ spec: z.string().describe("file::symbol, file::a,b, or a.ts::x,b.ts::y"),
657
674
  limit: z.number().int().positive().max(MCP_MAX_LIMIT).optional().describe("max callers to show (default: 20)"),
658
675
  json: z.boolean().optional().describe("output as JSON"),
659
- context: z.number().int().nonnegative().max(MCP_MAX_CONTEXT_LINES).optional().describe("lines of call-site source to show before and after each caller (default 0)"),
660
- excludeTests: z.boolean().optional().describe("hide callers whose call site lives in a test file (opt-in; default output is unchanged)"),
661
- grep: z.string().optional().describe("only show callers whose enclosing symbol name matches this regex (literal substring if it is not valid regex)"),
662
- projectRoot: makeProjectRootField("orient")
676
+ context: z.number().int().nonnegative().max(MCP_MAX_CONTEXT_LINES).optional().describe("call-site lines to show around each caller (default 0)"),
677
+ excludeTests: z.boolean().optional().describe("hide callers in test files"),
678
+ grep: z.string().optional().describe("only callers whose enclosing symbol matches this regex (a literal substring if it is not valid regex)"),
679
+ projectRoot: projectRootField
663
680
  },
664
681
  annotations: { readOnlyHint: true, openWorldHint: false }
665
682
  },
@@ -690,7 +707,7 @@ async function createMcpServer() {
690
707
  description: "Project overview: file count, languages, headline symbols, and recently modified files.",
691
708
  inputSchema: {
692
709
  compact: z.boolean().optional().describe("compact, low-token summary"),
693
- projectRoot: makeProjectRootField("overview")
710
+ projectRoot: projectRootField
694
711
  },
695
712
  annotations: { readOnlyHint: true, openWorldHint: false }
696
713
  },
@@ -739,7 +756,7 @@ async function createMcpServer() {
739
756
  recursive: z.boolean().optional().describe("descend into subdirectories (default: true)"),
740
757
  context: z.number().int().nonnegative().max(MCP_MAX_CONTEXT_LINES).optional().describe("lines of context to show before and after each match"),
741
758
  // 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.
742
- projectRoot: makeProjectRootField("search")
759
+ projectRoot: projectRootField
743
760
  },
744
761
  annotations: { readOnlyHint: true, openWorldHint: false }
745
762
  },
@@ -846,7 +863,7 @@ async function createMcpServer() {
846
863
  inputSchema: {
847
864
  name: z.string().regex(/^[A-Za-z0-9._-]{1,128}$/).describe("handoff name"),
848
865
  text: z.string().max(CONTENT_MAX_INPUT_CHARS).describe("handoff text"),
849
- projectRoot: makeProjectRootField("scope")
866
+ projectRoot: projectRootField
850
867
  },
851
868
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
852
869
  },
@@ -862,7 +879,7 @@ async function createMcpServer() {
862
879
  inputSchema: {
863
880
  name: z.string().regex(/^[A-Za-z0-9._-]{1,128}$/).describe("handoff name"),
864
881
  full: z.boolean().optional().describe("return full text instead of a compact payload"),
865
- projectRoot: makeProjectRootField("scope")
882
+ projectRoot: projectRootField
866
883
  },
867
884
  // 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.
868
885
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
@@ -2,7 +2,7 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  Database
5
- } from "./token-goat-chunk-OSUFN2FV.mjs";
5
+ } from "./token-goat-chunk-XB5KKOCG.mjs";
6
6
  import {
7
7
  displaySafeText
8
8
  } from "./token-goat-chunk-NMTKNYGF.mjs";
@@ -3,7 +3,7 @@ const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  queryCsv,
5
5
  quoteCsvCell
6
- } from "./token-goat-chunk-L43RKNHA.mjs";
6
+ } from "./token-goat-chunk-DNSPXQXQ.mjs";
7
7
  import {
8
8
  NotAnOfficeDocumentError,
9
9
  assertOoxmlWithinDeadline,
@@ -12,7 +12,7 @@ import {
12
12
  ooxmlWorkDeadline,
13
13
  parseOoxmlPart,
14
14
  readOoxmlZip
15
- } from "./token-goat-chunk-RIB6XY2V.mjs";
15
+ } from "./token-goat-chunk-UXSXQQIY.mjs";
16
16
  import {
17
17
  displaySafeText
18
18
  } from "./token-goat-chunk-NMTKNYGF.mjs";