token-goat 2.9.13 → 2.9.14

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 (44) hide show
  1. package/README.md +13 -0
  2. package/dist/token-goat-chunk-2ESBO4IN.mjs +209 -0
  3. package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
  4. package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-3XQPEJMV.mjs} +1 -1
  5. package/dist/token-goat-chunk-4SDX3QP3.mjs +122 -0
  6. package/dist/token-goat-chunk-7OGKZ7AP.mjs +142 -0
  7. package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
  8. package/dist/token-goat-chunk-AMYCQJX4.mjs +1548 -0
  9. package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-ASVVF4JV.mjs} +10 -7
  10. package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-DAMXYVIW.mjs} +12026 -11796
  11. package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-DBNY4RLN.mjs} +2 -2
  12. package/dist/token-goat-chunk-EG3663UT.mjs +226 -0
  13. package/dist/token-goat-chunk-EZNVAIR3.mjs +21 -0
  14. package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
  15. package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-HF6H7RNK.mjs} +1 -1
  16. package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-IT6O3PNN.mjs} +2874 -7088
  17. package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
  18. package/dist/token-goat-chunk-O5WAMISC.mjs +167 -0
  19. package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-PGGDW7DZ.mjs} +28 -13
  20. package/dist/token-goat-chunk-POBYR64E.mjs +1632 -0
  21. package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-PRJVGIC5.mjs} +6 -4
  22. package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-RUDOKYPJ.mjs} +10160 -10053
  23. package/dist/token-goat-chunk-SAQ5PG4L.mjs +2634 -0
  24. package/dist/{token-goat-chunk-UMXJN7DI.mjs → token-goat-chunk-T2IWWTHB.mjs} +288 -2654
  25. package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-VZYD4OZB.mjs} +1164 -92
  26. package/dist/token-goat-chunk-XEH6KBWW.mjs +23 -0
  27. package/dist/token-goat-chunk-XQF5J25J.mjs +33 -0
  28. package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
  29. package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-XVZ4MNQC.mjs} +587 -587
  30. package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
  31. package/dist/token-goat-chunk-YHGTGG6K.mjs +396 -0
  32. package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-YTQHZJXW.mjs} +20 -11
  33. package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
  34. package/dist/token-goat-chunk-ZD4EM4LR.mjs +30 -0
  35. package/dist/token-goat-chunk-ZFM4PWXL.mjs +585 -0
  36. package/dist/{token-goat-chunk-FQCNJV4V.mjs → token-goat-chunk-ZYNNQ36L.mjs} +116 -330
  37. package/dist/token-goat-hook.mjs +12 -8
  38. package/dist/token-goat.core.mjs +22 -10
  39. package/docs/cli.md +1 -0
  40. package/package.json +4 -2
  41. package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
  42. package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
  43. package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
  44. package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
@@ -3,41 +3,41 @@ const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  PARSER_FINGERPRINT,
5
5
  enqueueDirtyPathSafe,
6
+ getTrackedFiles
7
+ } from "./token-goat-chunk-IT6O3PNN.mjs";
8
+ import {
6
9
  getProjectFileEntries,
7
- getTrackedFiles,
8
10
  indexRecallEntry
9
- } from "./token-goat-chunk-ZZI3IDQZ.mjs";
10
- import {
11
- estimateTokensFromLength
12
- } from "./token-goat-chunk-JOXLE672.mjs";
11
+ } from "./token-goat-chunk-VZYD4OZB.mjs";
13
12
  import {
13
+ getDb,
14
14
  isBlobStale,
15
15
  loadBlob,
16
+ redactSecrets,
16
17
  storeBlob
17
- } from "./token-goat-chunk-UM47DRD3.mjs";
18
+ } from "./token-goat-chunk-T2IWWTHB.mjs";
18
19
  import {
19
20
  fingerprintFile,
20
- getDb,
21
21
  getDisplayRoot,
22
- redactSecrets,
23
22
  shortFingerprint
24
- } from "./token-goat-chunk-UMXJN7DI.mjs";
23
+ } from "./token-goat-chunk-SAQ5PG4L.mjs";
25
24
  import {
26
25
  registerReset
27
26
  } from "./token-goat-chunk-EEIDFMEM.mjs";
28
27
  import {
29
28
  SYMBOL_BODY_CHAR_CAP,
30
- compileGuardedRegex,
31
29
  countNoun,
32
30
  displaySafeJson,
33
- displaySafeText,
34
31
  extractErrorMessage,
35
32
  foldPath,
36
33
  globalDbPath,
37
34
  normalizePath,
38
35
  resolveIndexPath,
39
36
  toDisplayPath
40
- } from "./token-goat-chunk-QKXBGBQR.mjs";
37
+ } from "./token-goat-chunk-AMYCQJX4.mjs";
38
+ import {
39
+ compileGuardedRegex
40
+ } from "./token-goat-chunk-GMOUBOX4.mjs";
41
41
  import {
42
42
  init_define_import_meta_env
43
43
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -99,6 +99,73 @@ registerReset(() => {
99
99
  _urlIndex = /* @__PURE__ */ new Map();
100
100
  });
101
101
 
102
+ // src/stdin_json.ts
103
+ init_define_import_meta_env();
104
+ var DEFAULT_STDIN_TIMEOUT_MS = 5e3;
105
+ var MAX_STDIN_WALL_MS = 6e4;
106
+ var MAX_STDIN_BYTES = 64 * 1024 * 1024;
107
+ function readStdinJson(timeoutMs = DEFAULT_STDIN_TIMEOUT_MS, maxBytes = MAX_STDIN_BYTES) {
108
+ return new Promise((resolve, reject) => {
109
+ const chunks = [];
110
+ let totalBytes = 0;
111
+ let settled = false;
112
+ const finish = (fn) => {
113
+ if (settled) return;
114
+ settled = true;
115
+ clearTimeout(idleTimer);
116
+ clearTimeout(wallTimer);
117
+ process.stdin.removeListener("data", onData);
118
+ process.stdin.removeListener("end", onEnd);
119
+ process.stdin.removeListener("error", onError);
120
+ fn();
121
+ };
122
+ let idleTimer = setTimeout(() => {
123
+ finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
124
+ }, timeoutMs);
125
+ const wallTimer = setTimeout(() => {
126
+ finish(() => {
127
+ process.stdin.destroy();
128
+ reject(new Error(`readStdinJson: stdin took longer than ${MAX_STDIN_WALL_MS} ms`));
129
+ });
130
+ }, MAX_STDIN_WALL_MS);
131
+ const onData = (chunk) => {
132
+ clearTimeout(idleTimer);
133
+ idleTimer = setTimeout(() => {
134
+ finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
135
+ }, timeoutMs);
136
+ totalBytes += chunk.length;
137
+ if (totalBytes > maxBytes) {
138
+ finish(() => {
139
+ process.stdin.destroy();
140
+ reject(new Error(`readStdinJson: stdin exceeded ${maxBytes} bytes`));
141
+ });
142
+ return;
143
+ }
144
+ chunks.push(chunk);
145
+ };
146
+ const onEnd = () => {
147
+ finish(() => {
148
+ const text = Buffer.concat(chunks).toString("utf8").trim();
149
+ if (text === "") {
150
+ reject(new Error("readStdinJson: empty stdin"));
151
+ return;
152
+ }
153
+ try {
154
+ resolve(JSON.parse(text));
155
+ } catch (err) {
156
+ reject(err instanceof Error ? err : new Error(String(err)));
157
+ }
158
+ });
159
+ };
160
+ const onError = (err) => {
161
+ finish(() => reject(err instanceof Error ? err : new Error(String(err))));
162
+ };
163
+ process.stdin.on("data", onData);
164
+ process.stdin.on("end", onEnd);
165
+ process.stdin.on("error", onError);
166
+ });
167
+ }
168
+
102
169
  // src/types.ts
103
170
  init_define_import_meta_env();
104
171
  var HOOK_EVENTS = [
@@ -179,9 +246,37 @@ function formatCommandManifest(manifest) {
179
246
  return lines.join("\n").trimEnd();
180
247
  }
181
248
 
249
+ // src/symbol_body_probe.ts
250
+ init_define_import_meta_env();
251
+ import * as fs from "fs";
252
+ var OVERSIZED_BODY_PROBE_SQL = `SELECT 1 FROM symbols WHERE LENGTH(body) > ${SYMBOL_BODY_CHAR_CAP} LIMIT 1`;
253
+ function checkSymbolBodySize(dbPath) {
254
+ if (!fs.existsSync(dbPath)) {
255
+ return { name: "Symbol body size", status: "ok", message: "no database yet" };
256
+ }
257
+ try {
258
+ const db = getDb(dbPath);
259
+ const row = db.prepare(OVERSIZED_BODY_PROBE_SQL).get();
260
+ if (row !== void 0) {
261
+ return {
262
+ name: "Symbol body size",
263
+ status: "warn",
264
+ message: `one or more stored symbol bodies exceed the ${SYMBOL_BODY_CHAR_CAP}-char cap enforced by boundSymbolBody -- likely a pre-fix leftover from a minified/generated file. A plain 'token-goat reclaim-index' (VACUUM only) CANNOT remove these rows -- it only reclaims freed pages, it never deletes row content. Only 'token-goat reclaim-index --rebuild' drops and re-derives them under the cap (stop the worker first with 'token-goat worker stop', since reclaim-index refuses to run while it's live); --rebuild reparses and re-embeds every indexed file across every project and can take a long time on a large multi-project index`
265
+ };
266
+ }
267
+ return { name: "Symbol body size", status: "ok", message: "no stored symbol body exceeds the cap" };
268
+ } catch (err) {
269
+ return {
270
+ name: "Symbol body size",
271
+ status: "warn",
272
+ message: `could not query symbol body size: ${extractErrorMessage(err)}`
273
+ };
274
+ }
275
+ }
276
+
182
277
  // src/reconcile.ts
183
278
  init_define_import_meta_env();
184
- import * as fs from "node:fs";
279
+ import * as fs2 from "node:fs";
185
280
  var DEFAULT_RECONCILE_BUDGET_MS = 1500;
186
281
  function readReconcileCursor(dbPath, root) {
187
282
  try {
@@ -302,7 +397,7 @@ function reconcileProject(opts = {}) {
302
397
  }
303
398
  let mtimeMs;
304
399
  try {
305
- mtimeMs = fs.statSync(file).mtimeMs;
400
+ mtimeMs = fs2.statSync(file).mtimeMs;
306
401
  } catch {
307
402
  changed.push(file);
308
403
  continue;
@@ -330,7 +425,7 @@ function reconcileProject(opts = {}) {
330
425
  break;
331
426
  }
332
427
  try {
333
- fs.statSync(entry.filePath);
428
+ fs2.statSync(entry.filePath);
334
429
  } catch {
335
430
  removed.push(entry.filePath);
336
431
  }
@@ -363,305 +458,6 @@ function reconcileProject(opts = {}) {
363
458
  };
364
459
  }
365
460
 
366
- // src/stdin_json.ts
367
- init_define_import_meta_env();
368
- var DEFAULT_STDIN_TIMEOUT_MS = 5e3;
369
- var MAX_STDIN_WALL_MS = 6e4;
370
- var MAX_STDIN_BYTES = 64 * 1024 * 1024;
371
- function readStdinJson(timeoutMs = DEFAULT_STDIN_TIMEOUT_MS, maxBytes = MAX_STDIN_BYTES) {
372
- return new Promise((resolve, reject) => {
373
- const chunks = [];
374
- let totalBytes = 0;
375
- let settled = false;
376
- const finish = (fn) => {
377
- if (settled) return;
378
- settled = true;
379
- clearTimeout(idleTimer);
380
- clearTimeout(wallTimer);
381
- process.stdin.removeListener("data", onData);
382
- process.stdin.removeListener("end", onEnd);
383
- process.stdin.removeListener("error", onError);
384
- fn();
385
- };
386
- let idleTimer = setTimeout(() => {
387
- finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
388
- }, timeoutMs);
389
- const wallTimer = setTimeout(() => {
390
- finish(() => {
391
- process.stdin.destroy();
392
- reject(new Error(`readStdinJson: stdin took longer than ${MAX_STDIN_WALL_MS} ms`));
393
- });
394
- }, MAX_STDIN_WALL_MS);
395
- const onData = (chunk) => {
396
- clearTimeout(idleTimer);
397
- idleTimer = setTimeout(() => {
398
- finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
399
- }, timeoutMs);
400
- totalBytes += chunk.length;
401
- if (totalBytes > maxBytes) {
402
- finish(() => {
403
- process.stdin.destroy();
404
- reject(new Error(`readStdinJson: stdin exceeded ${maxBytes} bytes`));
405
- });
406
- return;
407
- }
408
- chunks.push(chunk);
409
- };
410
- const onEnd = () => {
411
- finish(() => {
412
- const text = Buffer.concat(chunks).toString("utf8").trim();
413
- if (text === "") {
414
- reject(new Error("readStdinJson: empty stdin"));
415
- return;
416
- }
417
- try {
418
- resolve(JSON.parse(text));
419
- } catch (err) {
420
- reject(err instanceof Error ? err : new Error(String(err)));
421
- }
422
- });
423
- };
424
- const onError = (err) => {
425
- finish(() => reject(err instanceof Error ? err : new Error(String(err))));
426
- };
427
- process.stdin.on("data", onData);
428
- process.stdin.on("end", onEnd);
429
- process.stdin.on("error", onError);
430
- });
431
- }
432
-
433
- // src/symbol_body_probe.ts
434
- init_define_import_meta_env();
435
- import * as fs2 from "fs";
436
- var OVERSIZED_BODY_PROBE_SQL = `SELECT 1 FROM symbols WHERE LENGTH(body) > ${SYMBOL_BODY_CHAR_CAP} LIMIT 1`;
437
- function checkSymbolBodySize(dbPath) {
438
- if (!fs2.existsSync(dbPath)) {
439
- return { name: "Symbol body size", status: "ok", message: "no database yet" };
440
- }
441
- try {
442
- const db = getDb(dbPath);
443
- const row = db.prepare(OVERSIZED_BODY_PROBE_SQL).get();
444
- if (row !== void 0) {
445
- return {
446
- name: "Symbol body size",
447
- status: "warn",
448
- message: `one or more stored symbol bodies exceed the ${SYMBOL_BODY_CHAR_CAP}-char cap enforced by boundSymbolBody -- likely a pre-fix leftover from a minified/generated file. A plain 'token-goat reclaim-index' (VACUUM only) CANNOT remove these rows -- it only reclaims freed pages, it never deletes row content. Only 'token-goat reclaim-index --rebuild' drops and re-derives them under the cap (stop the worker first with 'token-goat worker stop', since reclaim-index refuses to run while it's live); --rebuild reparses and re-embeds every indexed file across every project and can take a long time on a large multi-project index`
449
- };
450
- }
451
- return { name: "Symbol body size", status: "ok", message: "no stored symbol body exceeds the cap" };
452
- } catch (err) {
453
- return {
454
- name: "Symbol body size",
455
- status: "warn",
456
- message: `could not query symbol body size: ${extractErrorMessage(err)}`
457
- };
458
- }
459
- }
460
-
461
- // src/resident_context.ts
462
- init_define_import_meta_env();
463
- import * as fs3 from "node:fs";
464
- var LARGE_TASK_LIST_BYTES = 2e4;
465
- var LARGE_SKILL_BODY_BYTES = 2e4;
466
- var SKILL_BODY_REPEAT_THRESHOLD = 2;
467
- var RESIDENT_TAIL_MAX_BYTES = 1048576;
468
- function createResidentContextStats() {
469
- return {
470
- attachmentsByType: /* @__PURE__ */ new Map(),
471
- latestTaskList: null,
472
- taskReminderCount: 0,
473
- taskReminderBytes: 0,
474
- skillBodies: /* @__PURE__ */ new Map(),
475
- compactionCount: 0
476
- };
477
- }
478
- function bump(map, key, bytes) {
479
- const entry = map.get(key);
480
- if (entry === void 0) map.set(key, { count: 1, bytes });
481
- else {
482
- entry.count += 1;
483
- entry.bytes += bytes;
484
- }
485
- }
486
- function messageText(message) {
487
- if (message === null || typeof message !== "object") return "";
488
- const content = message["content"];
489
- if (typeof content === "string") return content;
490
- if (!Array.isArray(content)) return "";
491
- let out = "";
492
- for (const block of content) {
493
- if (block === null || typeof block !== "object") continue;
494
- const text = block["text"];
495
- if (typeof text === "string") out += text;
496
- }
497
- return out;
498
- }
499
- function skillNameFromBody(text) {
500
- const dir = /^Base directory for this skill:\s*(.+?)\s*$/m.exec(text);
501
- if (dir?.[1] !== void 0) {
502
- const segments = dir[1].split(/[\\/]/).filter((s) => s.length > 0);
503
- const last = segments[segments.length - 1];
504
- if (last !== void 0 && last.length > 0) return last;
505
- }
506
- const heading = /^#\s+(.+?)\s*$/m.exec(text);
507
- if (heading?.[1] !== void 0 && heading[1].length > 0) return heading[1];
508
- return null;
509
- }
510
- function readTaskList(attachment, bytes) {
511
- const snapshot = {
512
- bytes,
513
- itemCount: typeof attachment["itemCount"] === "number" ? attachment["itemCount"] : 0,
514
- completed: 0,
515
- inProgress: 0,
516
- pending: 0,
517
- descriptionBytes: 0,
518
- completedDescriptionBytes: 0
519
- };
520
- const content = attachment["content"];
521
- if (!Array.isArray(content)) return snapshot;
522
- if (content.length > snapshot.itemCount) snapshot.itemCount = content.length;
523
- for (const item of content) {
524
- if (item === null || typeof item !== "object") continue;
525
- const record = item;
526
- const status = typeof record["status"] === "string" ? record["status"] : "";
527
- const description = typeof record["description"] === "string" ? record["description"] : "";
528
- snapshot.descriptionBytes += description.length;
529
- if (status === "completed") {
530
- snapshot.completed += 1;
531
- snapshot.completedDescriptionBytes += description.length;
532
- } else if (status === "in_progress") snapshot.inProgress += 1;
533
- else if (status === "pending") snapshot.pending += 1;
534
- }
535
- return snapshot;
536
- }
537
- function collectInvokedSkills(acc, record) {
538
- const skills = record["skills"];
539
- if (!Array.isArray(skills)) return;
540
- for (const entry of skills) {
541
- if (entry === null || typeof entry !== "object") continue;
542
- const skill = entry;
543
- const content = skill["content"];
544
- if (typeof content !== "string" || content.length < LARGE_SKILL_BODY_BYTES) continue;
545
- const name = skillName(skill);
546
- if (name !== null) bump(acc.skillBodies, name, content.length);
547
- }
548
- }
549
- function skillName(skill) {
550
- const name = skill["name"];
551
- if (typeof name === "string" && name.trim() !== "") return name.trim();
552
- const path = skill["path"];
553
- if (typeof path !== "string") return null;
554
- const segments = path.split(/[\\/]/).filter((part) => part !== "");
555
- const last = segments[segments.length - 1];
556
- return last === void 0 || last === "" ? null : last;
557
- }
558
- function accumulateResidentLine(acc, parsed, bytes) {
559
- try {
560
- if (parsed === null || typeof parsed !== "object") return;
561
- const line = parsed;
562
- if (line["type"] === "system" && line["subtype"] === "compact_boundary") acc.compactionCount += 1;
563
- const attachment = line["attachment"];
564
- if (attachment !== null && typeof attachment === "object") {
565
- const record = attachment;
566
- const type = typeof record["type"] === "string" ? record["type"] : "unknown";
567
- bump(acc.attachmentsByType, type, bytes);
568
- if (type === "task_reminder") {
569
- acc.taskReminderCount += 1;
570
- acc.taskReminderBytes += bytes;
571
- acc.latestTaskList = readTaskList(record, bytes);
572
- }
573
- if (type === "invoked_skills") collectInvokedSkills(acc, record);
574
- }
575
- if (line["isMeta"] === true && line["type"] === "user") {
576
- const text = messageText(line["message"]);
577
- if (text.length >= LARGE_SKILL_BODY_BYTES) {
578
- const skill = skillNameFromBody(text);
579
- if (skill !== null) bump(acc.skillBodies, skill, text.length);
580
- }
581
- }
582
- } catch {
583
- }
584
- }
585
- function summarizeResidentContext(acc) {
586
- const attachmentClasses = [...acc.attachmentsByType.entries()].map(([type, v]) => ({ type, count: v.count, bytes: v.bytes })).sort((a, b) => b.bytes - a.bytes || a.type.localeCompare(b.type));
587
- const repeatedSkillBodies = [...acc.skillBodies.entries()].filter(([, v]) => v.count >= SKILL_BODY_REPEAT_THRESHOLD).map(([skill, v]) => ({ skill, count: v.count, bytes: v.bytes })).sort((a, b) => b.bytes - a.bytes || a.skill.localeCompare(b.skill));
588
- return {
589
- attachmentClasses,
590
- totalAttachmentBytes: attachmentClasses.reduce((n, c) => n + c.bytes, 0),
591
- latestTaskList: acc.latestTaskList,
592
- taskReminderCount: acc.taskReminderCount,
593
- taskReminderBytes: acc.taskReminderBytes,
594
- repeatedSkillBodies,
595
- compactionCount: acc.compactionCount
596
- };
597
- }
598
- function formatBytes(bytes) {
599
- if (bytes >= 1e6) return `${(bytes / 1048576).toFixed(1)} MB`;
600
- if (bytes >= 1e3) return `${Math.round(bytes / 1024)} KB`;
601
- return `${bytes} B`;
602
- }
603
- function formatTokenEstimate(tokens) {
604
- return tokens >= 1e3 ? `${Math.round(tokens / 1e3)}K` : String(tokens);
605
- }
606
- function taskListPruneHint(snapshot) {
607
- if (snapshot === null) return null;
608
- if (snapshot.bytes < LARGE_TASK_LIST_BYTES) return null;
609
- if (snapshot.completed === 0) return null;
610
- const tokens = formatTokenEstimate(estimateTokensFromLength(snapshot.bytes));
611
- const prunable = formatBytes(snapshot.completedDescriptionBytes);
612
- return `Your task list is ${formatBytes(snapshot.bytes)} (~${tokens} tok est) and is re-injected in full whenever it changes; ${snapshot.completed} of ${snapshot.itemCount} items are already completed and their descriptions alone are ${prunable}. Prune completed items or shorten their descriptions with TaskUpdate. Check ownership first if other agents share this list.`;
613
- }
614
- function repeatedSkillBodyHint(injections) {
615
- const worst = injections[0];
616
- if (worst === void 0) return null;
617
- if (worst.count < SKILL_BODY_REPEAT_THRESHOLD || worst.bytes < LARGE_SKILL_BODY_BYTES) return null;
618
- const skill = displaySafeText(worst.skill);
619
- const tokens = formatTokenEstimate(estimateTokensFromLength(worst.bytes));
620
- return `The \`${skill}\` skill body has been injected ${worst.count} times this session (${formatBytes(worst.bytes)} total, ~${tokens} tok est). Slash expansion and the Skill tool both send the whole body every time, and no hook can intercept either. If it is already loaded, work from it instead of re-invoking; to reread one part, use \`token-goat skill-section ${skill} '<heading>'\`.`;
621
- }
622
- function readTranscriptTail(transcriptPath, maxBytes = RESIDENT_TAIL_MAX_BYTES) {
623
- let fd = null;
624
- try {
625
- const stat = fs3.statSync(transcriptPath);
626
- if (!stat.isFile() || stat.size === 0) return [];
627
- const start = Math.max(0, stat.size - maxBytes);
628
- const length = stat.size - start;
629
- fd = fs3.openSync(transcriptPath, "r");
630
- const buf = Buffer.allocUnsafe(length);
631
- const read = fs3.readSync(fd, buf, 0, length, start);
632
- const lines = buf.subarray(0, read).toString("utf8").split("\n");
633
- if (start > 0) lines.shift();
634
- return lines;
635
- } catch {
636
- return [];
637
- } finally {
638
- if (fd !== null) {
639
- try {
640
- fs3.closeSync(fd);
641
- } catch {
642
- }
643
- }
644
- }
645
- }
646
- function lineMayCarryResidentSignal(line) {
647
- return line.includes('"task_reminder"') || line.includes('"compact_boundary"') || line.includes('"invoked_skills"') || line.includes('"isMeta"');
648
- }
649
- function accumulateResidentLines(lines) {
650
- const acc = createResidentContextStats();
651
- for (const line of lines) {
652
- const trimmed = line.trim();
653
- if (trimmed === "") continue;
654
- let parsed;
655
- try {
656
- parsed = JSON.parse(trimmed);
657
- } catch {
658
- continue;
659
- }
660
- accumulateResidentLine(acc, parsed, trimmed.length);
661
- }
662
- return acc;
663
- }
664
-
665
461
  export {
666
462
  checkSymbolBodySize,
667
463
  WEB_OUTPUT_SUBDIR,
@@ -669,25 +465,15 @@ export {
669
465
  getWebOutput,
670
466
  getWebOutputRaw,
671
467
  getWebOutputByUrlFromDisk,
672
- HOOK_EVENTS,
673
- buildCommandManifest,
674
- flattenCommandNames,
675
- filterCommandManifest,
676
- formatCommandManifest,
677
468
  DEFAULT_RECONCILE_BUDGET_MS,
678
469
  runReconcile,
679
470
  isReconcileClean,
680
471
  reconcileProject,
681
- createResidentContextStats,
682
- accumulateResidentLine,
683
- summarizeResidentContext,
684
- formatBytes,
685
- formatTokenEstimate,
686
- taskListPruneHint,
687
- repeatedSkillBodyHint,
688
- readTranscriptTail,
689
- lineMayCarryResidentSignal,
690
- accumulateResidentLines,
691
472
  MAX_STDIN_BYTES,
692
- readStdinJson
473
+ readStdinJson,
474
+ HOOK_EVENTS,
475
+ buildCommandManifest,
476
+ flattenCommandNames,
477
+ filterCommandManifest,
478
+ formatCommandManifest
693
479
  };
@@ -2,15 +2,19 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  relayInProcess
5
- } from "./token-goat-chunk-QWSUZWFP.mjs";
6
- import "./token-goat-chunk-2WC4ZUXN.mjs";
7
- import "./token-goat-chunk-FQCNJV4V.mjs";
8
- import "./token-goat-chunk-ZZI3IDQZ.mjs";
9
- import "./token-goat-chunk-JOXLE672.mjs";
10
- import "./token-goat-chunk-UM47DRD3.mjs";
11
- import "./token-goat-chunk-UMXJN7DI.mjs";
5
+ } from "./token-goat-chunk-XVZ4MNQC.mjs";
6
+ import "./token-goat-chunk-3XQPEJMV.mjs";
7
+ import "./token-goat-chunk-ZYNNQ36L.mjs";
8
+ import "./token-goat-chunk-IT6O3PNN.mjs";
9
+ import "./token-goat-chunk-VZYD4OZB.mjs";
10
+ import "./token-goat-chunk-3BTK54F3.mjs";
11
+ import "./token-goat-chunk-Y4AFKTHK.mjs";
12
+ import "./token-goat-chunk-T2IWWTHB.mjs";
13
+ import "./token-goat-chunk-SAQ5PG4L.mjs";
12
14
  import "./token-goat-chunk-EEIDFMEM.mjs";
13
- import "./token-goat-chunk-QKXBGBQR.mjs";
15
+ import "./token-goat-chunk-POBYR64E.mjs";
16
+ import "./token-goat-chunk-AMYCQJX4.mjs";
17
+ import "./token-goat-chunk-GMOUBOX4.mjs";
14
18
  import {
15
19
  init_define_import_meta_env
16
20
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -2,19 +2,31 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./token-goat-chunk-3ESRORNM.mjs";
6
- import "./token-goat-chunk-FQCNJV4V.mjs";
7
- import "./token-goat-chunk-U7X6LQD2.mjs";
8
- import "./token-goat-chunk-ZZI3IDQZ.mjs";
9
- import "./token-goat-chunk-JOXLE672.mjs";
10
- import "./token-goat-chunk-YOA4N6WA.mjs";
11
- import "./token-goat-chunk-UM47DRD3.mjs";
12
- import "./token-goat-chunk-UMXJN7DI.mjs";
5
+ } from "./token-goat-chunk-DAMXYVIW.mjs";
6
+ import "./token-goat-chunk-RUDOKYPJ.mjs";
7
+ import "./token-goat-chunk-ZYNNQ36L.mjs";
8
+ import "./token-goat-chunk-IT6O3PNN.mjs";
9
+ import "./token-goat-chunk-VZYD4OZB.mjs";
10
+ import "./token-goat-chunk-NEI4NC54.mjs";
11
+ import "./token-goat-chunk-4SDX3QP3.mjs";
12
+ import "./token-goat-chunk-2ESBO4IN.mjs";
13
+ import "./token-goat-chunk-ZFM4PWXL.mjs";
14
+ import "./token-goat-chunk-EG3663UT.mjs";
15
+ import "./token-goat-chunk-3BTK54F3.mjs";
16
+ import "./token-goat-chunk-YHGTGG6K.mjs";
17
+ import "./token-goat-chunk-XTQAOTSO.mjs";
18
+ import "./token-goat-chunk-AH6QILZM.mjs";
19
+ import "./token-goat-chunk-Y4AFKTHK.mjs";
20
+ import "./token-goat-chunk-DBNY4RLN.mjs";
21
+ import "./token-goat-chunk-T2IWWTHB.mjs";
22
+ import "./token-goat-chunk-SAQ5PG4L.mjs";
13
23
  import "./token-goat-chunk-EEIDFMEM.mjs";
14
- import "./token-goat-chunk-B3CTCQTH.mjs";
24
+ import "./token-goat-chunk-HF6H7RNK.mjs";
25
+ import "./token-goat-chunk-POBYR64E.mjs";
15
26
  import {
16
27
  installEpipeGuard
17
- } from "./token-goat-chunk-QKXBGBQR.mjs";
28
+ } from "./token-goat-chunk-AMYCQJX4.mjs";
29
+ import "./token-goat-chunk-GMOUBOX4.mjs";
18
30
  import {
19
31
  init_define_import_meta_env
20
32
  } from "./token-goat-chunk-A37V4PBF.mjs";
package/docs/cli.md CHANGED
@@ -173,6 +173,7 @@ token-goat pdf-extract manual.pdf --pages 12-15 --layout --head 120
173
173
  | `token-goat project exclude <path>` | Add a project root to the blocklist so the worker never indexes it. Writes the resolved absolute path to `[worker] blocked_roots` in `config.toml`; idempotent. It also removes anything already indexed under that path and says how many files went, so excluding a directory means its contents stop being readable through `symbol` rather than merely stopping future indexing. Remove the entry from the config to re-enable indexing, then run `token-goat index` to bring the contents back. |
174
174
  | `token-goat project prune [--dry-run]` | Remove blocked/excluded roots that no longer exist on disk. `--dry-run` previews removals without touching the config file. Useful after deleting or moving projects. |
175
175
  | `token-goat install` | Wire up hooks (and, with the harness flags below, other AI tool integrations). No `--dry-run` or `--verify` flag — run `token-goat doctor` after install to audit the result. |
176
+ | `token-goat upgrade` | Check for updates or upgrade token-goat to the latest version via npm. Pass `--check` to report status without installing. `--json` emits machine-readable version status. |
176
177
  | `token-goat doctor` | Confirm everything is wired correctly. Surfaces install state, cold-import timing, cache hit rates, compaction-budget telemetry, opt-in flag status, and canonical-root sanity. A **Parser freshness** check reports how much of the index for this project was written by a different build of the extractor. The stamp only refreshes when something touches a file, so after an upgrade a project goes on answering `symbol`, `read`, `outline` and `skeleton` from the previous extractor with nothing saying so. It warns past a quarter and names the fix: a plain `token-goat index` in that project, which is enough on its own, since a parser mismatch reparses without `--force`. A **Tool names** check reports any tool name a harness sent that reached no handler wanting it, and calls out the ones that differ from a handled name only by capitalisation or punctuation — the signature of a bridge that forgot to rename something, which is otherwise invisible. A **Security** section reports the posture in one place: whether offline mode is on, whether injection scanning is on, whether the Google Drive integration is enabled, whether fetching runs against an allow list or a deny list, whether MCP reads are confined to the project root, and whether the data directory is readable by other local users. It only warns when a protection that ships on has been switched off, so a default install stays quiet. It read-only audits `~/.copilot/mcp-config.json` for globally configured Chrome DevTools or Playwright `npx` launchers, recommending project scope or removal when inactive; it never prints server configuration or secrets. On Windows, it also reports duplicate Chrome DevTools/Playwright MCP launchers and orphaned Node processes without terminating anything. Pass `--context` to show the **Context footprint** section: a fill bar with severity (ok / warn / high / URGENT), per-component breakdown (skills catalog, loaded skill bodies, CLAUDE.md+MEMORY.md, conversation estimate), session-to-session growth trend with sessions-to-URGENT projection, and tiered compaction recommendations (Tier 0–4) naming the exact commands to run. Auto-shown when fill > 40 % or any loaded skill > 2 K tokens lacks a compact. `--json` emits the check results (one entry per check, with `ok`/`warn`/`fail` status) as JSON instead of text. |
177
178
  | `token-goat capabilities` | List every capability that can send data off this machine or leave data on it, with whether it is currently on, the config key that decides that, and the exact `file::symbol` where the decision is made — so a reviewer can open the code rather than take the list's word for it. `--json` emits the same thing for a pipeline to assert on, which is the point: the answer comes from the binary installed on your machine, not from documentation that may describe a different build. A test in the suite fails the build when a module that can open a network connection is missing from this list, and equally when the list names one that no longer connects anywhere. |
178
179
  | `token-goat baseline` | Emit a project map: file count, per-language file counts, the top indexed symbols (by name/kind/location), and the most recently modified files. `--subagent` emits a terser variant (fewer symbols, fewer recent files) for context handed to a freshly spawned subagent; `--json` for the machine-readable form. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-goat",
3
- "version": "2.9.13",
3
+ "version": "2.9.14",
4
4
  "description": "Surgical token-reduction companion for Claude Code and other AI coding agents",
5
5
  "type": "module",
6
6
  "main": "./dist/token-goat.mjs",
@@ -38,7 +38,9 @@
38
38
  "parser:fingerprint": "node scripts/parser-fingerprint.mjs",
39
39
  "parser:fingerprint:check": "node scripts/parser-fingerprint.mjs --check",
40
40
  "schema:copilot": "node scripts/extract_harness_schema.mjs auto --harness copilot_cli --out schemas/copilot_cli.hooks.json",
41
- "schema:copilot:check": "node scripts/extract_harness_schema.mjs auto --harness copilot_cli --out schemas/copilot_cli.hooks.json --check"
41
+ "schema:copilot:check": "node scripts/extract_harness_schema.mjs auto --harness copilot_cli --out schemas/copilot_cli.hooks.json --check",
42
+ "docs:arch": "node scripts/sync-arch-docs.mjs",
43
+ "docs:arch:check": "node scripts/sync-arch-docs.mjs --check"
42
44
  },
43
45
  "contributors": [
44
46
  {
@@ -1,31 +0,0 @@
1
- import { createRequire as __cjsRequire } from 'node:module';
2
- const require = __cjsRequire(import.meta.url);
3
- import {
4
- applyExitOverride,
5
- buildProgram,
6
- cmdIndex,
7
- expandGlobs,
8
- leftoverIntegrations,
9
- run,
10
- visualStudioManualSteps
11
- } from "./token-goat-chunk-3ESRORNM.mjs";
12
- import "./token-goat-chunk-FQCNJV4V.mjs";
13
- import "./token-goat-chunk-U7X6LQD2.mjs";
14
- import "./token-goat-chunk-ZZI3IDQZ.mjs";
15
- import "./token-goat-chunk-JOXLE672.mjs";
16
- import "./token-goat-chunk-YOA4N6WA.mjs";
17
- import "./token-goat-chunk-UM47DRD3.mjs";
18
- import "./token-goat-chunk-UMXJN7DI.mjs";
19
- import "./token-goat-chunk-EEIDFMEM.mjs";
20
- import "./token-goat-chunk-B3CTCQTH.mjs";
21
- import "./token-goat-chunk-QKXBGBQR.mjs";
22
- import "./token-goat-chunk-A37V4PBF.mjs";
23
- export {
24
- applyExitOverride,
25
- buildProgram,
26
- cmdIndex,
27
- expandGlobs,
28
- leftoverIntegrations,
29
- run,
30
- visualStudioManualSteps
31
- };
@@ -1,26 +0,0 @@
1
- import { createRequire as __cjsRequire } from 'node:module';
2
- const require = __cjsRequire(import.meta.url);
3
- import {
4
- buildEvent,
5
- relay,
6
- relayInProcess
7
- } from "./token-goat-chunk-QWSUZWFP.mjs";
8
- import "./token-goat-chunk-2WC4ZUXN.mjs";
9
- import {
10
- MAX_STDIN_BYTES,
11
- readStdinJson
12
- } from "./token-goat-chunk-FQCNJV4V.mjs";
13
- import "./token-goat-chunk-ZZI3IDQZ.mjs";
14
- import "./token-goat-chunk-JOXLE672.mjs";
15
- import "./token-goat-chunk-UM47DRD3.mjs";
16
- import "./token-goat-chunk-UMXJN7DI.mjs";
17
- import "./token-goat-chunk-EEIDFMEM.mjs";
18
- import "./token-goat-chunk-QKXBGBQR.mjs";
19
- import "./token-goat-chunk-A37V4PBF.mjs";
20
- export {
21
- MAX_STDIN_BYTES,
22
- buildEvent,
23
- readStdinJson,
24
- relay,
25
- relayInProcess
26
- };