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
@@ -2,15 +2,17 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  getDb
5
- } from "./token-goat-chunk-7SXPJOSZ.mjs";
5
+ } from "./token-goat-chunk-7CPMDFGB.mjs";
6
6
  import {
7
7
  foldPath,
8
- globalDbPath,
9
8
  isCaseInsensitiveFs
10
- } from "./token-goat-chunk-6E2IDLHF.mjs";
9
+ } from "./token-goat-chunk-TCQANXYC.mjs";
11
10
  import {
12
11
  normalizePath
13
12
  } from "./token-goat-chunk-NMTKNYGF.mjs";
13
+ import {
14
+ globalDbPath
15
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
14
16
  import {
15
17
  init_define_import_meta_env
16
18
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -4,14 +4,16 @@ import {
4
4
  accumulateResidentLine,
5
5
  claudeConfigDir,
6
6
  createResidentContextStats,
7
- estimateTokens,
8
7
  summarizeResidentContext
9
- } from "./token-goat-chunk-G6EYO5CD.mjs";
8
+ } from "./token-goat-chunk-ONXH6NZ5.mjs";
10
9
  import {
11
10
  commandHash,
12
11
  getBashOutput,
13
12
  normalizeCommandForCacheKey
14
- } from "./token-goat-chunk-43JFN26X.mjs";
13
+ } from "./token-goat-chunk-O6I2XU4P.mjs";
14
+ import {
15
+ estimateTokens
16
+ } from "./token-goat-chunk-52NSDWYY.mjs";
15
17
  import {
16
18
  init_define_import_meta_env
17
19
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -0,0 +1,96 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ classifyContent,
5
+ guardDivisor,
6
+ stripAnsiEscapes
7
+ } from "./token-goat-chunk-CIQ2FTY3.mjs";
8
+ import {
9
+ safeSlice
10
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
11
+ import {
12
+ init_define_import_meta_env
13
+ } from "./token-goat-chunk-A37V4PBF.mjs";
14
+
15
+ // src/overflow_guard.ts
16
+ init_define_import_meta_env();
17
+ function estimateTokensFromLength(length, cls = "text") {
18
+ return Math.max(1, Math.floor(Math.max(0, length) / guardDivisor(cls)) + 1);
19
+ }
20
+ function estimateTokens(text) {
21
+ const stripped = stripAnsiEscapes(text);
22
+ return estimateTokensFromLength(stripped.length, classifyContent(stripped));
23
+ }
24
+ function trimToBudget(text, budgetTokens, command) {
25
+ const markerMarginTokens = 64;
26
+ const strippedAll = stripAnsiEscapes(text);
27
+ const contentClass = classifyContent(strippedAll);
28
+ const totalTokens = estimateTokensFromLength(strippedAll.length, contentClass);
29
+ if (totalTokens <= budgetTokens) {
30
+ return text;
31
+ }
32
+ const lines = text.split("\n");
33
+ if (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
34
+ const totalLines = lines.length;
35
+ const bodyBudget = Math.max(1, budgetTokens - markerMarginTokens);
36
+ const charBudget = bodyBudget * guardDivisor(contentClass);
37
+ const kept = [];
38
+ let used = 0;
39
+ for (const ln of lines) {
40
+ const stripped = stripAnsiEscapes(ln);
41
+ const cost = ln.length + 1;
42
+ if (kept.length === 0 && cost > charBudget) {
43
+ const truncated = safeSlice(stripped, charBudget);
44
+ kept.push(truncated);
45
+ break;
46
+ }
47
+ if (kept.length > 0 && used + cost > charBudget) {
48
+ break;
49
+ }
50
+ kept.push(ln);
51
+ used += cost;
52
+ }
53
+ const shown = kept.length;
54
+ const hint = getHintFor(command);
55
+ const marker = `[token-goat: output capped at ~${budgetTokens} tokens to protect context \u2014 showing ${shown} of ${totalLines} lines. ${hint}]`;
56
+ return kept.join("\n") + "\n" + marker;
57
+ }
58
+ function capJsonRows(items, budgetTokens) {
59
+ const totalCount = items.length;
60
+ const charBudget = Math.max(1, budgetTokens * guardDivisor());
61
+ const kept = [];
62
+ let used = 0;
63
+ for (const item of items) {
64
+ const cost = JSON.stringify(item).length + 2;
65
+ if (kept.length > 0 && used + cost > charBudget) break;
66
+ kept.push(item);
67
+ used += cost;
68
+ }
69
+ return { items: kept, truncated: kept.length < totalCount, totalCount };
70
+ }
71
+ function getHintFor(command) {
72
+ const cmd = (command || "").toLowerCase().trim();
73
+ if (cmd === "symbol") {
74
+ return "Request a specific method (file.py::Class.method) or use --json for structured access.";
75
+ }
76
+ if (cmd === "heading" || cmd === "section") {
77
+ return "Request a narrower sub-heading, e.g. 'doc.md::Section#2'.";
78
+ }
79
+ if (cmd === "lines") {
80
+ return "Request a smaller line range, e.g. 'file.py@100-150'.";
81
+ }
82
+ if (cmd === "bash-output" || cmd === "web-output") {
83
+ return "Use --grep PATTERN, --section HEADING, or --tail N to narrow the cached output.";
84
+ }
85
+ if (cmd === "semantic") {
86
+ return "Narrow your query text or pass --limit to reduce the number of matches returned.";
87
+ }
88
+ return "Narrow your query or raise overflow_guard max_tokens in config.";
89
+ }
90
+
91
+ export {
92
+ estimateTokensFromLength,
93
+ estimateTokens,
94
+ trimToBudget,
95
+ capJsonRows
96
+ };
@@ -1,29 +1,37 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
+ MCP_DISABLE_NOTE,
4
5
  buildCopilotWasteReport,
5
6
  findProjectSession,
6
- isCopilotTranscript
7
- } from "./token-goat-chunk-PAV6NNY7.mjs";
7
+ isCopilotTranscript,
8
+ unusedMcpServers
9
+ } from "./token-goat-chunk-C5YPNZKQ.mjs";
8
10
  import {
9
11
  buildWasteReport
10
- } from "./token-goat-chunk-62IHOU6L.mjs";
11
- import "./token-goat-chunk-VVROQBQJ.mjs";
12
- import "./token-goat-chunk-G6EYO5CD.mjs";
13
- import "./token-goat-chunk-43JFN26X.mjs";
14
- import "./token-goat-chunk-D2X7XN5M.mjs";
15
- import "./token-goat-chunk-IKZLSRII.mjs";
16
- import "./token-goat-chunk-7SXPJOSZ.mjs";
12
+ } from "./token-goat-chunk-44BM7DDQ.mjs";
13
+ import "./token-goat-chunk-EUSDXRXU.mjs";
14
+ import "./token-goat-chunk-ONXH6NZ5.mjs";
15
+ import "./token-goat-chunk-O6I2XU4P.mjs";
16
+ import "./token-goat-chunk-D4ETHJD6.mjs";
17
+ import "./token-goat-chunk-52NSDWYY.mjs";
18
+ import "./token-goat-chunk-2WOUYWLM.mjs";
19
+ import "./token-goat-chunk-CIQ2FTY3.mjs";
20
+ import "./token-goat-chunk-435UQTKD.mjs";
21
+ import "./token-goat-chunk-7CPMDFGB.mjs";
17
22
  import {
18
23
  resolveProjectRoot
19
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
20
- import "./token-goat-chunk-EEIDFMEM.mjs";
21
- import "./token-goat-chunk-OSUFN2FV.mjs";
22
- import "./token-goat-chunk-6E2IDLHF.mjs";
24
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
25
+ import "./token-goat-chunk-XB5KKOCG.mjs";
26
+ import "./token-goat-chunk-YZAAZU2S.mjs";
27
+ import "./token-goat-chunk-IVE6U7KV.mjs";
28
+ import "./token-goat-chunk-XYWPOSCN.mjs";
29
+ import "./token-goat-chunk-TCQANXYC.mjs";
23
30
  import {
24
31
  displaySafeJson
25
32
  } from "./token-goat-chunk-NMTKNYGF.mjs";
26
- import "./token-goat-chunk-GMOUBOX4.mjs";
33
+ import "./token-goat-chunk-MELOKFDJ.mjs";
34
+ import "./token-goat-chunk-JTKCQMQA.mjs";
27
35
  import {
28
36
  init_define_import_meta_env
29
37
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -77,10 +85,16 @@ function buildFeedbackCardFromCopilot(report) {
77
85
  preAudit.push(
78
86
  `High fixed MCP tool definition overhead: ${details}; total ~${totalMcpTokens.toLocaleString()} tok/turn re-sent across ${turns} turn(s) (~${cumulative.toLocaleString()} cumulative tokens).`
79
87
  );
80
- const heavyNames = (heavy.length > 0 ? heavy : report.mcpTools.servers).map((s) => s.serverName).join(", ");
81
- fixes.push(
82
- `Disable unused MCP server(s) (${heavyNames}) via 'copilot mcp disable <name>' or exclude individual tools with '--excluded-tools'.`
83
- );
88
+ const unused = unusedMcpServers(report);
89
+ if (unused === null) {
90
+ const heavyNames = (heavy.length > 0 ? heavy : report.mcpTools.servers).map((s) => s.serverName).join(", ");
91
+ fixes.push(
92
+ `Disable the MCP server(s) you do not use among ${heavyNames} with 'copilot mcp disable <name>', or exclude individual tools with '--excluded-tools'. This session's log records no tool calls, so it cannot say which went unused.`
93
+ );
94
+ } else if (unused.length > 0) {
95
+ const commands = unused.map((s) => `'copilot mcp disable ${s.serverName}' (~${s.estimatedTokens.toLocaleString()} tok/turn)`).join(", ");
96
+ fixes.push(`Disable the MCP server(s) this session never called: ${commands}. ${MCP_DISABLE_NOTE}`);
97
+ }
84
98
  }
85
99
  }
86
100
  if (preAudit.length === 0) {
@@ -20,13 +20,12 @@ var SUPPORTED_PROTOCOL_VERSIONS = [
20
20
  var JSONRPC_INVALID_REQUEST = -32600;
21
21
  var JSONRPC_METHOD_NOT_FOUND = -32601;
22
22
  var JSONRPC_INVALID_PARAMS = -32602;
23
- var DRAFT_07_SCHEMA_ID = "http://json-schema.org/draft-07/schema#";
24
23
  var MCP_INVALID_PARAMS_PREFIX = `MCP error ${JSONRPC_INVALID_PARAMS}: `;
25
24
  var EMPTY_OBJECT_JSON_SCHEMA = { type: "object", properties: {} };
26
25
  function buildJsonSchema(shape) {
27
26
  if (shape === void 0 || Object.keys(shape).length === 0) return { ...EMPTY_OBJECT_JSON_SCHEMA };
28
- const schema = external_exports.toJSONSchema(external_exports.object(shape), { io: "input" });
29
- return { ...schema, $schema: DRAFT_07_SCHEMA_ID };
27
+ const { $schema: _dialect, ...schema } = external_exports.toJSONSchema(external_exports.object(shape), { io: "input" });
28
+ return schema;
30
29
  }
31
30
  function describeParseError(error) {
32
31
  return error.issues.map((issue) => {
@@ -1,24 +1,28 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
- import {
4
- registerReset
5
- } from "./token-goat-chunk-EEIDFMEM.mjs";
6
3
  import {
7
4
  Database
8
- } from "./token-goat-chunk-OSUFN2FV.mjs";
5
+ } from "./token-goat-chunk-XB5KKOCG.mjs";
6
+ import {
7
+ registerReset
8
+ } from "./token-goat-chunk-YZAAZU2S.mjs";
9
9
  import {
10
- SYMBOL_BODY_CHAR_CAP,
11
10
  countContentLines,
12
- dataDir,
13
11
  ensureDirSync,
14
- escapeRegExp,
12
+ escapeRegExp
13
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
14
+ import {
15
15
  foldCase,
16
16
  foldPath,
17
17
  sleepSync
18
- } from "./token-goat-chunk-6E2IDLHF.mjs";
18
+ } from "./token-goat-chunk-TCQANXYC.mjs";
19
19
  import {
20
20
  safeJoin
21
21
  } from "./token-goat-chunk-NMTKNYGF.mjs";
22
+ import {
23
+ SYMBOL_BODY_CHAR_CAP,
24
+ dataDir
25
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
22
26
  import {
23
27
  init_define_import_meta_env
24
28
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -2313,7 +2317,7 @@ function runMigrations(conn, fromVersion, toVersion) {
2313
2317
  }
2314
2318
  }
2315
2319
  var WAL_SWITCH_DEADLINE_MS = 15e3;
2316
- function enableWalWithRetry(conn, budgetMs = WAL_SWITCH_DEADLINE_MS) {
2320
+ function enableWalWithRetry(conn, budgetMs = WAL_SWITCH_DEADLINE_MS, stopOn) {
2317
2321
  const deadline = Date.now() + budgetMs;
2318
2322
  let lastError;
2319
2323
  for (; ; ) {
@@ -2323,55 +2327,147 @@ function enableWalWithRetry(conn, budgetMs = WAL_SWITCH_DEADLINE_MS) {
2323
2327
  lastError = new Error(`got: ${String(mode)}`);
2324
2328
  } catch (e) {
2325
2329
  lastError = e;
2330
+ if (isDamagedDatabaseError(e) || stopOn?.(e) === true) throw walSwitchError(e);
2326
2331
  }
2327
2332
  try {
2328
2333
  if (String(conn.pragma("journal_mode", { simple: true })).toLowerCase() === "wal") return;
2329
2334
  } catch {
2330
2335
  }
2331
- if (Date.now() >= deadline) {
2332
- throw new Error(`db: failed to enable WAL mode (${lastError instanceof Error ? lastError.message : String(lastError)})`);
2333
- }
2336
+ if (Date.now() >= deadline) throw walSwitchError(lastError);
2334
2337
  sleepSync(25);
2335
2338
  }
2336
2339
  }
2337
- function initConnection(conn) {
2340
+ function isDamagedDatabaseError(e) {
2341
+ const code = e?.code;
2342
+ return typeof code === "string" && /^SQLITE_(?:NOTADB|CORRUPT)/.test(code);
2343
+ }
2344
+ function walSwitchError(lastError) {
2345
+ return new Error(`db: failed to enable WAL mode (${lastError instanceof Error ? lastError.message : String(lastError)})`, { cause: lastError });
2346
+ }
2347
+ function initConnection(conn, walStopOn) {
2338
2348
  conn.pragma("busy_timeout = 15000");
2339
- enableWalWithRetry(conn);
2349
+ enableWalWithRetry(conn, WAL_SWITCH_DEADLINE_MS, walStopOn);
2340
2350
  conn.pragma("synchronous = NORMAL");
2341
2351
  conn.pragma("cache_size = -32000");
2342
2352
  conn.pragma("temp_store = MEMORY");
2343
2353
  conn.pragma("mmap_size = 134217728");
2344
- conn.function(
2345
- "TG_LOWER",
2346
- { deterministic: true },
2347
- (value) => value === null ? null : foldCase(String(value))
2348
- );
2354
+ registerTgLower(conn);
2349
2355
  const storedVersion = Number(conn.pragma("user_version", { simple: true }));
2350
- if (storedVersion > SCHEMA_VERSION) {
2351
- throw new Error(
2352
- `db: index schema version ${storedVersion} is newer than this token-goat build supports (expected ${SCHEMA_VERSION}). Update token-goat, or delete the stale index database and let it rebuild.`
2353
- );
2354
- }
2356
+ if (storedVersion > SCHEMA_VERSION) throw newerSchemaError(storedVersion);
2355
2357
  conn.exec(SCHEMA_SQL);
2356
2358
  try {
2357
2359
  conn.exec(FTS_SQL);
2358
2360
  } catch {
2359
2361
  }
2360
- try {
2361
- const sqliteVec = _require("sqlite-vec");
2362
- sqliteVec.load(conn);
2363
- conn.exec(
2364
- `CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vectors USING vec0(
2362
+ if (loadSqliteVec(conn)) {
2363
+ try {
2364
+ conn.exec(
2365
+ `CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vectors USING vec0(
2365
2366
  embedding float[384]
2366
2367
  );`
2367
- );
2368
- } catch {
2368
+ );
2369
+ } catch {
2370
+ }
2369
2371
  }
2370
2372
  if (storedVersion < SCHEMA_VERSION) {
2371
2373
  runMigrations(conn, storedVersion, SCHEMA_VERSION);
2372
2374
  conn.pragma(`user_version = ${SCHEMA_VERSION}`);
2373
2375
  }
2374
2376
  }
2377
+ function newerSchemaError(storedVersion) {
2378
+ return new Error(
2379
+ `db: index schema version ${storedVersion} is newer than this token-goat build supports (expected ${SCHEMA_VERSION}). Update token-goat, or delete the stale index database and let it rebuild.`
2380
+ );
2381
+ }
2382
+ function registerTgLower(conn) {
2383
+ conn.function(
2384
+ "TG_LOWER",
2385
+ { deterministic: true },
2386
+ (value) => value === null ? null : foldCase(String(value))
2387
+ );
2388
+ }
2389
+ function loadSqliteVec(conn) {
2390
+ try {
2391
+ const sqliteVec = _require("sqlite-vec");
2392
+ sqliteVec.load(conn);
2393
+ return true;
2394
+ } catch {
2395
+ return false;
2396
+ }
2397
+ }
2398
+ var _readOnlyFallback;
2399
+ var _readOnlyConnections = /* @__PURE__ */ new Map();
2400
+ function allowReadOnlyIndex(onFirstUse) {
2401
+ _readOnlyFallback = { onFirstUse, used: false };
2402
+ }
2403
+ function isReadOnlyDb(dbPath) {
2404
+ if (_readOnlyFallback === void 0) return false;
2405
+ try {
2406
+ getDb(dbPath);
2407
+ } catch {
2408
+ return false;
2409
+ }
2410
+ return _readOnlyConnections.has(connectionKey(dbPath).key);
2411
+ }
2412
+ var WRITE_ACCESS_SQLITE_CODE_RE = /^SQLITE_(?:CANTOPEN|READONLY|PERM|IOERR_ACCESS|IOERR_SHMOPEN)/;
2413
+ var WRITE_ACCESS_FS_CODES = /* @__PURE__ */ new Set(["EACCES", "EPERM", "EROFS"]);
2414
+ function isWriteAccessError(e) {
2415
+ for (let cur = e, depth = 0; cur instanceof Error && depth < 4; cur = cur.cause, depth++) {
2416
+ const code = cur.code;
2417
+ if (typeof code === "string" && (WRITE_ACCESS_SQLITE_CODE_RE.test(code) || WRITE_ACCESS_FS_CODES.has(code))) return true;
2418
+ }
2419
+ return false;
2420
+ }
2421
+ function writeRefusal(resolved) {
2422
+ let fd;
2423
+ try {
2424
+ fd = fs2.openSync(resolved, "r+");
2425
+ } catch (e) {
2426
+ return isWriteAccessError(e) ? e : void 0;
2427
+ }
2428
+ fs2.closeSync(fd);
2429
+ return void 0;
2430
+ }
2431
+ function openReadOnlyAt(resolved, immutable) {
2432
+ const conn = new Database(resolved, { readonly: true, fileMustExist: true, immutable });
2433
+ try {
2434
+ conn.pragma("busy_timeout = 15000");
2435
+ return { conn, storedVersion: Number(conn.pragma("user_version", { simple: true })) };
2436
+ } catch (e) {
2437
+ try {
2438
+ conn.close();
2439
+ } catch {
2440
+ }
2441
+ throw e;
2442
+ }
2443
+ }
2444
+ function openIndexReadOnly(resolved) {
2445
+ let opened;
2446
+ try {
2447
+ opened = openReadOnlyAt(resolved, false);
2448
+ } catch (e) {
2449
+ if (!isWriteAccessError(e)) throw e;
2450
+ opened = openReadOnlyAt(resolved, true);
2451
+ }
2452
+ const { conn, storedVersion } = opened;
2453
+ try {
2454
+ if (storedVersion > SCHEMA_VERSION) throw newerSchemaError(storedVersion);
2455
+ if (storedVersion < SCHEMA_VERSION) {
2456
+ throw new Error(
2457
+ `db: index schema version ${storedVersion} predates this token-goat build (expected ${SCHEMA_VERSION}) and cannot be upgraded without write access. Run token-goat once where its data directory is writable.`
2458
+ );
2459
+ }
2460
+ registerTgLower(conn);
2461
+ loadSqliteVec(conn);
2462
+ } catch (e) {
2463
+ try {
2464
+ conn.close();
2465
+ } catch {
2466
+ }
2467
+ throw e;
2468
+ }
2469
+ return conn;
2470
+ }
2375
2471
  function resolveDbPath(dbPath) {
2376
2472
  if (path2.isAbsolute(dbPath)) return dbPath;
2377
2473
  if (dbPath.includes("/") || dbPath.includes("\\")) return path2.resolve(dbPath);
@@ -2385,35 +2481,63 @@ function getDb(dbPath) {
2385
2481
  const { resolved, key } = connectionKey(dbPath);
2386
2482
  const existing = _connections.get(key);
2387
2483
  if (existing !== void 0) return existing;
2484
+ const fallback = _readOnlyFallback;
2485
+ if (fallback !== void 0) {
2486
+ const readOnly = _readOnlyConnections.get(key);
2487
+ if (readOnly !== void 0) return readOnly;
2488
+ const refused = writeRefusal(resolved);
2489
+ if (refused !== void 0) return openReadOnlyFallback(resolved, key, fallback, refused);
2490
+ }
2388
2491
  const dir = path2.dirname(resolved);
2389
2492
  try {
2390
2493
  ensureDirSync(dir);
2391
2494
  } catch (e) {
2392
2495
  if (e.code !== "EEXIST" || !fs2.existsSync(dir)) throw e;
2393
2496
  }
2394
- const conn = new Database(resolved);
2497
+ let conn;
2395
2498
  try {
2396
- initConnection(conn);
2499
+ conn = new Database(resolved);
2500
+ initConnection(conn, fallback !== void 0 ? isWriteAccessError : void 0);
2397
2501
  } catch (e) {
2398
2502
  try {
2399
- conn.close();
2503
+ conn?.close();
2400
2504
  } catch {
2401
2505
  }
2506
+ if (fallback !== void 0 && isWriteAccessError(e)) return openReadOnlyFallback(resolved, key, fallback, e);
2402
2507
  throw e;
2403
2508
  }
2404
2509
  _connections.set(key, conn);
2405
2510
  return conn;
2406
2511
  }
2512
+ function openReadOnlyFallback(resolved, key, fallback, writeError) {
2513
+ let conn;
2514
+ try {
2515
+ conn = openIndexReadOnly(resolved);
2516
+ } catch (e) {
2517
+ throw isWriteAccessError(e) || !fs2.existsSync(resolved) ? writeError : e;
2518
+ }
2519
+ _readOnlyConnections.set(key, conn);
2520
+ if (!fallback.used) {
2521
+ fallback.used = true;
2522
+ fallback.onFirstUse();
2523
+ }
2524
+ return conn;
2525
+ }
2407
2526
  function closeAllDbs() {
2408
- for (const conn of _connections.values()) {
2409
- try {
2410
- conn.close();
2411
- } catch {
2527
+ for (const cache of [_connections, _readOnlyConnections]) {
2528
+ for (const conn of cache.values()) {
2529
+ try {
2530
+ conn.close();
2531
+ } catch {
2532
+ }
2412
2533
  }
2534
+ cache.clear();
2413
2535
  }
2414
- _connections.clear();
2415
2536
  }
2416
- registerReset(closeAllDbs);
2537
+ registerReset(closeAllDbs, { perRequest: true });
2538
+ registerReset(() => {
2539
+ _readOnlyFallback = void 0;
2540
+ }, { perRequest: true });
2417
2541
 
2418
2542
  export {
2419
2543
  precedingDocComment,
@@ -2470,5 +2594,7 @@ export {
2470
2594
  unsupportedLanguageName,
2471
2595
  isDotenvPath,
2472
2596
  redactIfDotenv,
2597
+ allowReadOnlyIndex,
2598
+ isReadOnlyDb,
2473
2599
  getDb
2474
2600
  };
@@ -0,0 +1,14 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ serveBatch,
5
+ serveOne,
6
+ swapEnv
7
+ } from "./token-goat-chunk-S4VSXURL.mjs";
8
+ import "./token-goat-chunk-YZAAZU2S.mjs";
9
+ import "./token-goat-chunk-A37V4PBF.mjs";
10
+ export {
11
+ serveBatch,
12
+ serveOne,
13
+ swapEnv
14
+ };
@@ -5,14 +5,16 @@ import {
5
5
  docxTables,
6
6
  docxText,
7
7
  formatDocxTables
8
- } from "./token-goat-chunk-WNBSCSAI.mjs";
9
- import "./token-goat-chunk-RIB6XY2V.mjs";
8
+ } from "./token-goat-chunk-UA5BKWWQ.mjs";
9
+ import "./token-goat-chunk-UXSXQQIY.mjs";
10
10
  import "./token-goat-chunk-XTQAOTSO.mjs";
11
11
  import "./token-goat-chunk-AH6QILZM.mjs";
12
- import "./token-goat-chunk-6E2IDLHF.mjs";
12
+ import "./token-goat-chunk-XYWPOSCN.mjs";
13
+ import "./token-goat-chunk-TCQANXYC.mjs";
13
14
  import "./token-goat-chunk-NMTKNYGF.mjs";
15
+ import "./token-goat-chunk-MELOKFDJ.mjs";
14
16
  import "./token-goat-chunk-Y4AFKTHK.mjs";
15
- import "./token-goat-chunk-GMOUBOX4.mjs";
17
+ import "./token-goat-chunk-JTKCQMQA.mjs";
16
18
  import "./token-goat-chunk-A37V4PBF.mjs";
17
19
  export {
18
20
  docxOutline,
@@ -3,14 +3,14 @@ const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  findLatestTranscript,
5
5
  readFileLines
6
- } from "./token-goat-chunk-62IHOU6L.mjs";
6
+ } from "./token-goat-chunk-44BM7DDQ.mjs";
7
7
  import {
8
8
  copilotCliUserRoot,
9
9
  readCopilotMcpTools
10
- } from "./token-goat-chunk-VVROQBQJ.mjs";
10
+ } from "./token-goat-chunk-EUSDXRXU.mjs";
11
11
  import {
12
12
  canonicalize
13
- } from "./token-goat-chunk-6E2IDLHF.mjs";
13
+ } from "./token-goat-chunk-TCQANXYC.mjs";
14
14
  import {
15
15
  init_define_import_meta_env
16
16
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -213,6 +213,11 @@ function readNumber(source, key) {
213
213
  const value = source[key];
214
214
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
215
215
  }
216
+ function unusedMcpServers(report) {
217
+ const calls = report.mcpCalls;
218
+ return calls === null ? null : report.mcpTools.servers.filter((server) => (calls[server.serverName] ?? 0) === 0);
219
+ }
220
+ var MCP_DISABLE_NOTE = "'copilot mcp enable <name>' restores one, and '--disable-mcp-server <name>' drops one for a single run instead.";
216
221
  function buildCopilotWasteReport(eventsPath) {
217
222
  const report = {
218
223
  sessionPath: eventsPath,
@@ -224,14 +229,14 @@ function buildCopilotWasteReport(eventsPath) {
224
229
  hookRecordBytes: 0,
225
230
  // Measured off the file rather than off a string of its contents: an event log large enough for this number to matter is exactly the one readFileSync cannot return, since V8 caps a string at about 512 MB.
226
231
  totalEventBytes: fs.statSync(eventsPath).size,
227
- // Read through the real resolution chain rather than passed in. Copilot's
228
- // own COPILOT_CACHE_HOME override is what tests point at a fixture, so the
229
- // shipping path is the tested path and there is no seam here that only a
230
- // test ever supplies.
231
- mcpTools: readCopilotMcpTools()
232
+ // Read through the real resolution chain rather than passed in. Copilot's own COPILOT_CACHE_HOME override is what tests point at a fixture, so the shipping path is the tested path and there is no seam here that only a test ever supplies.
233
+ mcpTools: readCopilotMcpTools(),
234
+ mcpCalls: null
232
235
  };
233
236
  const classes = /* @__PURE__ */ new Map();
234
237
  const seen = /* @__PURE__ */ new Map();
238
+ const mcpCalls = /* @__PURE__ */ new Map();
239
+ let toolExecutions = 0;
235
240
  for (const line of readFileLines(eventsPath)) {
236
241
  const trimmed = line.trim();
237
242
  if (trimmed === "") continue;
@@ -266,6 +271,12 @@ function buildCopilotWasteReport(eventsPath) {
266
271
  });
267
272
  continue;
268
273
  }
274
+ if (type === "tool.execution_start") {
275
+ toolExecutions += 1;
276
+ const server = data["mcpServerName"];
277
+ if (typeof server === "string") mcpCalls.set(server, (mcpCalls.get(server) ?? 0) + 1);
278
+ continue;
279
+ }
269
280
  if (type !== "user.message") continue;
270
281
  const transformed = typeof data["transformedContent"] === "string" ? data["transformedContent"] : "";
271
282
  if (transformed === "") continue;
@@ -293,6 +304,7 @@ function buildCopilotWasteReport(eventsPath) {
293
304
  }
294
305
  }
295
306
  report.blocks = [...classes.values()].sort((a, b) => b.bytes - a.bytes);
307
+ report.mcpCalls = toolExecutions === 0 ? null : Object.fromEntries(mcpCalls);
296
308
  return report;
297
309
  }
298
310
 
@@ -300,5 +312,7 @@ export {
300
312
  isCopilotTranscript,
301
313
  findLatestCopilotSession,
302
314
  findProjectSession,
315
+ unusedMcpServers,
316
+ MCP_DISABLE_NOTE,
303
317
  buildCopilotWasteReport
304
318
  };