token-goat 2.9.14 → 2.9.15

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 (41) hide show
  1. package/README.md +15 -1
  2. package/dist/token-goat-chunk-2X2EBBC6.mjs +277 -0
  3. package/dist/{token-goat-chunk-XQF5J25J.mjs → token-goat-chunk-3NSDDTGL.mjs} +5 -4
  4. package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
  5. package/dist/{token-goat-chunk-4SDX3QP3.mjs → token-goat-chunk-5V7DAC7V.mjs} +5 -4
  6. package/dist/token-goat-chunk-6DLVZDB6.mjs +34 -0
  7. package/dist/{token-goat-chunk-XEH6KBWW.mjs → token-goat-chunk-7ZYK25AO.mjs} +4 -3
  8. package/dist/{token-goat-chunk-7OGKZ7AP.mjs → token-goat-chunk-A4JYKD5H.mjs} +5 -3
  9. package/dist/{token-goat-chunk-2ESBO4IN.mjs → token-goat-chunk-ASYEPR3S.mjs} +10 -7
  10. package/dist/{token-goat-chunk-PGGDW7DZ.mjs → token-goat-chunk-ATIFTMRC.mjs} +9 -6
  11. package/dist/{token-goat-chunk-IT6O3PNN.mjs → token-goat-chunk-BL5LNGBG.mjs} +813 -4613
  12. package/dist/{token-goat-chunk-PRJVGIC5.mjs → token-goat-chunk-C5JIO6HK.mjs} +7 -5
  13. package/dist/{token-goat-chunk-YTQHZJXW.mjs → token-goat-chunk-DQ4J5AFF.mjs} +40 -17
  14. package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
  15. package/dist/{token-goat-chunk-ASVVF4JV.mjs → token-goat-chunk-GIIHUSZX.mjs} +137 -19
  16. package/dist/{token-goat-chunk-DAMXYVIW.mjs → token-goat-chunk-GMQQA7E4.mjs} +296 -276
  17. package/dist/{token-goat-chunk-T2IWWTHB.mjs → token-goat-chunk-IVUQLQWN.mjs} +33 -1142
  18. package/dist/{token-goat-chunk-POBYR64E.mjs → token-goat-chunk-K7F2BFIK.mjs} +801 -3
  19. package/dist/{token-goat-chunk-RUDOKYPJ.mjs → token-goat-chunk-LCZBPOIN.mjs} +1733 -1360
  20. package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
  21. package/dist/{token-goat-chunk-EZNVAIR3.mjs → token-goat-chunk-LT7JRU6K.mjs} +4 -3
  22. package/dist/{token-goat-chunk-YHGTGG6K.mjs → token-goat-chunk-MZDIJJ3R.mjs} +29 -5
  23. package/dist/{token-goat-chunk-O5WAMISC.mjs → token-goat-chunk-NDPO7GAH.mjs} +26 -16
  24. package/dist/token-goat-chunk-NDRP4KJQ.mjs +4371 -0
  25. package/dist/{token-goat-chunk-ZFM4PWXL.mjs → token-goat-chunk-NU7TLMQK.mjs} +3 -3
  26. package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
  27. package/dist/token-goat-chunk-OUGNPMDA.mjs +959 -0
  28. package/dist/{token-goat-chunk-AMYCQJX4.mjs → token-goat-chunk-PM76YS22.mjs} +49 -256
  29. package/dist/{token-goat-chunk-SAQ5PG4L.mjs → token-goat-chunk-S4XRY446.mjs} +5 -2
  30. package/dist/{token-goat-chunk-DBNY4RLN.mjs → token-goat-chunk-SFAS46RE.mjs} +5 -3
  31. package/dist/{token-goat-chunk-XVZ4MNQC.mjs → token-goat-chunk-SZWYESBS.mjs} +221 -78
  32. package/dist/{token-goat-chunk-HF6H7RNK.mjs → token-goat-chunk-XEPXYDPI.mjs} +3 -2
  33. package/dist/{token-goat-chunk-EG3663UT.mjs → token-goat-chunk-YKG35VHC.mjs} +4 -2
  34. package/dist/{token-goat-chunk-VZYD4OZB.mjs → token-goat-chunk-YQ7WI2CO.mjs} +78 -266
  35. package/dist/{token-goat-chunk-3XQPEJMV.mjs → token-goat-chunk-YZX7EFG4.mjs} +1 -1
  36. package/dist/token-goat-hook.mjs +13 -9
  37. package/dist/token-goat.core.mjs +21 -16
  38. package/docs/cli.md +8 -6
  39. package/package.json +1 -1
  40. package/dist/token-goat-chunk-ZD4EM4LR.mjs +0 -30
  41. package/dist/token-goat-chunk-ZYNNQ36L.mjs +0 -479
@@ -20,6 +20,7 @@ import {
20
20
  isAvailable as isAvailable2,
21
21
  load,
22
22
  loadError,
23
+ queryJson,
23
24
  rankSimilarNames,
24
25
  resolveBody,
25
26
  resolveHandoff,
@@ -89,13 +90,15 @@ import {
89
90
  symbolNamesInFile,
90
91
  upsertNote,
91
92
  warnIfFilesStale
92
- } from "./token-goat-chunk-RUDOKYPJ.mjs";
93
+ } from "./token-goat-chunk-LCZBPOIN.mjs";
93
94
  import {
94
95
  DEFAULT_RECONCILE_BUDGET_MS,
95
96
  HOOK_EVENTS,
96
97
  WEB_OUTPUT_SUBDIR,
97
98
  buildCommandManifest,
98
99
  checkSymbolBodySize,
100
+ cmdDescribe,
101
+ cmdSessionSchema,
99
102
  filterCommandManifest,
100
103
  formatCommandManifest,
101
104
  getWebOutput,
@@ -104,12 +107,11 @@ import {
104
107
  readStdinJson,
105
108
  runReconcile,
106
109
  storeWebOutput
107
- } from "./token-goat-chunk-ZYNNQ36L.mjs";
110
+ } from "./token-goat-chunk-OUGNPMDA.mjs";
108
111
  import {
109
112
  AGENT_SALT_MARKER,
110
113
  CONTEXT_AUTOCOMPACT_TOKENS,
111
114
  MAX_FILES_SCANNED,
112
- PARSER_FINGERPRINT,
113
115
  SESSIONS_SUBDIR,
114
116
  SKILLS_OUTPUT_SUBDIR,
115
117
  SKIP_DIRS,
@@ -123,6 +125,7 @@ import {
123
125
  buildManifestWithCount,
124
126
  buildProjectMap,
125
127
  buildStats,
128
+ cmdReclaimIndex,
126
129
  compactDoc,
127
130
  compactPathFor,
128
131
  confirmAndApply,
@@ -131,15 +134,11 @@ import {
131
134
  detectWalkMode,
132
135
  dirtyQueuePathFor,
133
136
  drainHeartbeatPathFor,
134
- embeddingBackendLoadError,
135
- embeddingsDepsAvailable,
136
137
  emptyIndexMessage,
137
138
  enqueueDirtyPathSafe,
138
- ensureEmbeddingProvenance,
139
139
  extractChecklistSection,
140
140
  extractCompactFromMarker,
141
141
  extractNamedSection,
142
- extractSection,
143
142
  fenceUntrusted,
144
143
  findClaudeMdFiles,
145
144
  findContentDuplicates,
@@ -166,37 +165,25 @@ import {
166
165
  getSkillFilePath,
167
166
  getTrackedFiles,
168
167
  incrementSkillHit,
169
- indexFileEmbeddings,
170
- indexFileSync,
171
- indexedPathSpellingIsStale,
172
168
  injectionFencingEnabled,
173
- isAvailable,
174
169
  isCompactFresh,
175
- isEmbedFresh,
176
- isEmbeddableDocument,
177
170
  isHintCategory,
178
- isParseSkipEligible,
179
171
  isPrivateIpv4Octets,
180
172
  isPrivateIpv6Groups,
181
173
  isSuppressionCategory,
182
- isTreeSitterAvailable,
183
174
  isWorkerRunning,
184
175
  listOutputs,
185
- listSections,
186
176
  listSkills,
187
- loadRegexExtractors,
188
177
  loadSessionCache,
189
178
  mapLookupBytesSaved,
190
179
  markCategoryEffective,
191
180
  markCategoryIneffective,
192
- missingTreeSitterGrammarPackages,
193
181
  pruneBlockedRoot,
194
182
  pruneDeletedFiles,
195
183
  pruneOrphanedChunks,
196
184
  pruneSkillOutputs,
197
185
  pruneSystemTempFiles,
198
186
  readCompactBody,
199
- readSection,
200
187
  removeFileFromIndex,
201
188
  resetHintStats,
202
189
  runContextStats,
@@ -209,13 +196,11 @@ import {
209
196
  storeCompact,
210
197
  storeOutput,
211
198
  summarizeResidentContext,
212
- treeSitterCoreAvailable,
213
- treeSitterCoreLoadError,
214
199
  urlPolicyDenialReason,
215
200
  visionTokensSavedByText,
216
201
  walkProject,
217
202
  writeCompact
218
- } from "./token-goat-chunk-IT6O3PNN.mjs";
203
+ } from "./token-goat-chunk-BL5LNGBG.mjs";
219
204
  import {
220
205
  BASH_OUTPUT_SUBDIR,
221
206
  CompressedOutput,
@@ -243,7 +228,6 @@ import {
243
228
  estimateTokensFromLength,
244
229
  findStrayClaudeMdBlocks,
245
230
  getBashOutput,
246
- getFileEntry,
247
231
  groupHasTokenGoat,
248
232
  hasManagedServer,
249
233
  installClaudeMd,
@@ -265,7 +249,6 @@ import {
265
249
  listRecentRecall,
266
250
  normalizeCommandForCacheKey,
267
251
  otherScopeHasManagedServer,
268
- querySymbols,
269
252
  readCopilotMcpTools,
270
253
  readServersJson,
271
254
  searchRecall,
@@ -294,19 +277,19 @@ import {
294
277
  vscodeHooksInstalled,
295
278
  vscodeScopeFromFlags,
296
279
  vscodeUsesClaudeHooks
297
- } from "./token-goat-chunk-VZYD4OZB.mjs";
280
+ } from "./token-goat-chunk-YQ7WI2CO.mjs";
298
281
  import {
299
282
  docxOutline,
300
283
  docxTables,
301
284
  docxText,
302
285
  formatDocxTables
303
- } from "./token-goat-chunk-4SDX3QP3.mjs";
286
+ } from "./token-goat-chunk-5V7DAC7V.mjs";
304
287
  import {
305
288
  pptxNotesText,
306
289
  pptxOutline,
307
290
  pptxSlideText,
308
291
  pptxTextGrep
309
- } from "./token-goat-chunk-2ESBO4IN.mjs";
292
+ } from "./token-goat-chunk-ASYEPR3S.mjs";
310
293
  import {
311
294
  formatXlsxColumns,
312
295
  formatXlsxRange,
@@ -315,41 +298,69 @@ import {
315
298
  querySheet,
316
299
  rangeSheet,
317
300
  xlsxColumns
318
- } from "./token-goat-chunk-ZFM4PWXL.mjs";
301
+ } from "./token-goat-chunk-NU7TLMQK.mjs";
319
302
  import {
320
303
  formatCsvTable,
321
304
  parseWhereSpecs
322
- } from "./token-goat-chunk-EG3663UT.mjs";
305
+ } from "./token-goat-chunk-YKG35VHC.mjs";
306
+ import {
307
+ PARSER_FINGERPRINT,
308
+ embeddingBackendLoadError,
309
+ embeddingsDepsAvailable,
310
+ ensureEmbeddingProvenance,
311
+ extractSection,
312
+ indexFileEmbeddings,
313
+ indexFileSync,
314
+ indexedPathSpellingIsStale,
315
+ isAvailable,
316
+ isEmbedFresh,
317
+ isEmbeddableDocument,
318
+ isParseSkipEligible,
319
+ isTreeSitterAvailable,
320
+ listSections,
321
+ loadRegexExtractors,
322
+ missingTreeSitterGrammarPackages,
323
+ readSection,
324
+ treeSitterCoreAvailable,
325
+ treeSitterCoreLoadError
326
+ } from "./token-goat-chunk-NDRP4KJQ.mjs";
327
+ import {
328
+ getFileEntry,
329
+ querySymbols
330
+ } from "./token-goat-chunk-2X2EBBC6.mjs";
323
331
  import {
324
332
  C,
325
333
  DEFAULT_MAX_AGE_MS,
326
334
  DEFAULT_MAX_COUNT,
327
335
  RESET,
328
- TREE_SITTER_LANGUAGES,
329
336
  _useRichStats,
330
337
  colorStdout,
331
338
  compileCustomPatterns,
332
- detectLanguage,
333
- detectLanguageOfFile,
334
- fenceFor,
335
339
  fg,
336
340
  formatLocalTimestamp,
337
- getDb,
338
- isDotenvPath,
339
341
  listBlobs,
340
342
  loadBlob,
341
- nonTreeSitterLanguageCount,
342
343
  pruneBlobs,
343
344
  readUnmappedTools,
344
345
  recordStat,
345
- redactIfDotenv,
346
346
  redactSecrets,
347
347
  renderShortStats,
348
348
  renderStats,
349
349
  savedTokensFromBytes,
350
350
  stripAnsi,
351
351
  summarize
352
- } from "./token-goat-chunk-T2IWWTHB.mjs";
352
+ } from "./token-goat-chunk-IVUQLQWN.mjs";
353
+ import {
354
+ TREE_SITTER_LANGUAGES,
355
+ detectLanguage,
356
+ detectLanguageOfFile,
357
+ fenceFor,
358
+ getDb,
359
+ isDotenvPath,
360
+ matchGroovySlashy,
361
+ nonTreeSitterLanguageCount,
362
+ redactIfDotenv
363
+ } from "./token-goat-chunk-K7F2BFIK.mjs";
353
364
  import {
354
365
  CONFIG_KEY_ENV_OVERRIDES,
355
366
  PROJECT_LOCKED_KEYS,
@@ -377,17 +388,11 @@ import {
377
388
  saveConfig,
378
389
  validateEnumField,
379
390
  validateNumericField
380
- } from "./token-goat-chunk-SAQ5PG4L.mjs";
381
- import {
382
- matchGroovySlashy
383
- } from "./token-goat-chunk-POBYR64E.mjs";
391
+ } from "./token-goat-chunk-S4XRY446.mjs";
384
392
  import {
385
393
  ENV_KEYS,
386
394
  LOCK_WAIT_MS_HARDENED,
387
395
  PACKAGE_NAME,
388
- UNTRUSTED_FILE_TAG,
389
- UNTRUSTED_TOOL_TAG,
390
- UNTRUSTED_WEB_TAG,
391
396
  VERSION,
392
397
  atomicWriteBytes,
393
398
  atomicWriteText,
@@ -399,24 +404,17 @@ import {
399
404
  dataDir,
400
405
  decodeSource,
401
406
  detectSourceEncoding,
402
- displaySafeJson,
403
- displaySafePath,
404
- displaySafeText,
405
407
  encodeSource,
406
408
  ensureDirSync,
407
409
  ensureNewline,
408
410
  escapeRegExp,
409
411
  extractErrorMessage,
410
- fenceUntrustedContent,
411
- fenceUntrustedOcrText,
412
412
  foldPath,
413
413
  globalDbPath,
414
414
  installSingleFilePlugin,
415
415
  isTestFile,
416
416
  isUnderBlockedRoot,
417
417
  isWindows,
418
- normalizeDarwinSystemAlias,
419
- normalizePath,
420
418
  pad,
421
419
  projectScopeRoot,
422
420
  pushAll,
@@ -427,7 +425,6 @@ import {
427
425
  removeFileInScope,
428
426
  requireNonNegativeStrictInt,
429
427
  requirePositiveStrictInt,
430
- resolveIndexPath,
431
428
  resolveOnPath,
432
429
  runGit,
433
430
  safeSlice,
@@ -436,7 +433,6 @@ import {
436
433
  stripOwnHooksFromMap,
437
434
  stripStaleGroupHooks,
438
435
  takeCreatedConfig,
439
- toDisplayPath,
440
436
  toKB,
441
437
  tokenGoatHome,
442
438
  uninstallSingleFilePlugin,
@@ -446,7 +442,21 @@ import {
446
442
  withRetryOnLock,
447
443
  writeIfDifferent,
448
444
  writeJsonSettings
449
- } from "./token-goat-chunk-AMYCQJX4.mjs";
445
+ } from "./token-goat-chunk-PM76YS22.mjs";
446
+ import {
447
+ UNTRUSTED_FILE_TAG,
448
+ UNTRUSTED_TOOL_TAG,
449
+ UNTRUSTED_WEB_TAG,
450
+ displaySafeJson,
451
+ displaySafePath,
452
+ displaySafeText,
453
+ fenceUntrustedContent,
454
+ fenceUntrustedOcrText,
455
+ normalizeDarwinSystemAlias,
456
+ normalizePath,
457
+ resolveIndexPath,
458
+ toDisplayPath
459
+ } from "./token-goat-chunk-ERTXEKB6.mjs";
450
460
  import {
451
461
  compileGuardedRegex
452
462
  } from "./token-goat-chunk-GMOUBOX4.mjs";
@@ -3580,9 +3590,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3580
3590
  * @param {string} [path]
3581
3591
  * @return {(string|null|Command)}
3582
3592
  */
3583
- executableDir(path40) {
3584
- if (path40 === void 0) return this._executableDir;
3585
- this._executableDir = path40;
3593
+ executableDir(path39) {
3594
+ if (path39 === void 0) return this._executableDir;
3595
+ this._executableDir = path39;
3586
3596
  return this;
3587
3597
  }
3588
3598
  /**
@@ -3882,8 +3892,8 @@ function attemptedCommandName(argv) {
3882
3892
  }
3883
3893
 
3884
3894
  // src/cli.ts
3885
- import * as fs43 from "fs";
3886
- import * as path39 from "path";
3895
+ import * as fs42 from "fs";
3896
+ import * as path38 from "path";
3887
3897
  import { homedir as homedir15 } from "os";
3888
3898
 
3889
3899
  // src/walk_index.ts
@@ -5432,13 +5442,16 @@ function checkMcpProcessHealth(processes) {
5432
5442
  const launchers = chromeLaunchers.length + playwrightLaunchers.length;
5433
5443
  if (launchers > 2 || orphanedNodeProcesses.length > 0) {
5434
5444
  const details = [];
5435
- if (chromeLaunchers.length > 1) details.push(`${chromeLaunchers.length} Chrome DevTools MCP launchers`);
5436
- if (playwrightLaunchers.length > 1) details.push(`${playwrightLaunchers.length} Playwright MCP launchers`);
5437
- if (orphanedNodeProcesses.length > 0) details.push(`${orphanedNodeProcesses.length} orphaned Node process${orphanedNodeProcesses.length === 1 ? "" : "es"}`);
5445
+ if (chromeLaunchers.length > 1) details.push(`${chromeLaunchers.length} Chrome DevTools MCP launchers (PIDs: ${chromeLaunchers.map((p) => p.processId).join(", ")})`);
5446
+ if (playwrightLaunchers.length > 1) details.push(`${playwrightLaunchers.length} Playwright MCP launchers (PIDs: ${playwrightLaunchers.map((p) => p.processId).join(", ")})`);
5447
+ if (orphanedNodeProcesses.length > 0) {
5448
+ const pids = orphanedNodeProcesses.map((p) => p.processId).join(", ");
5449
+ details.push(`${orphanedNodeProcesses.length} orphaned Node process${orphanedNodeProcesses.length === 1 ? "" : "es"} (PIDs: ${pids})`);
5450
+ }
5438
5451
  return {
5439
5452
  name: "MCP process health",
5440
5453
  status: "warn",
5441
- message: `${details.join("; ")} detected. These are host-managed processes; close stale Copilot sessions before terminating a specific confirmed orphan.`
5454
+ message: `${details.join("; ")} detected. These are host-managed processes left by closed terminal/CLI sessions; close stale sessions or terminate specific confirmed orphan PIDs with Stop-Process -Id <PID>.`
5442
5455
  };
5443
5456
  }
5444
5457
  return { name: "MCP process health", status: "ok", message: "no duplicate MCP launchers or orphaned Node processes detected" };
@@ -6356,7 +6369,7 @@ async function runDoctorAndExit(opts) {
6356
6369
  }
6357
6370
  }
6358
6371
  try {
6359
- const { checkUpdateStatus } = await import("./token-goat-chunk-7OGKZ7AP.mjs");
6372
+ const { checkUpdateStatus } = await import("./token-goat-chunk-A4JYKD5H.mjs");
6360
6373
  const update = await checkUpdateStatus(1500);
6361
6374
  if (update.updateAvailable && update.latest) {
6362
6375
  console.log(`
@@ -6469,7 +6482,7 @@ function generateCompactHelp() {
6469
6482
  "",
6470
6483
  "Session: stats, waste, session-outline, session-audit, session-slice,",
6471
6484
  " session-summary, context-stats, bootstrap-audit, memory, hint-stats,",
6472
- " mcp-audit",
6485
+ " session-schema, mcp-audit",
6473
6486
  "",
6474
6487
  "Skills: skill-body, skill-compact, skill-list, skill-size, skill-history,",
6475
6488
  " skill-diff, skill-section",
@@ -6482,8 +6495,8 @@ function generateCompactHelp() {
6482
6495
  " bridges-status, worker, statusline, version, config, config-get,",
6483
6496
  " capabilities, help",
6484
6497
  "",
6485
- "Data: note, note-add, note-get, note-list, sqlite-query, sqlite-tables,",
6486
- " sqlite-schema, csv-profile, csv-query",
6498
+ "Data: note, note-add, note-get, note-list, describe, sqlite-query,",
6499
+ " sqlite-tables, sqlite-schema, csv-profile, csv-query",
6487
6500
  "",
6488
6501
  "Utils: ignores, bash-history, web-history, openapi-op, openapi-outline,",
6489
6502
  " gdrive-sections, screenshot, opencode-*, fetch-image, image-meta,",
@@ -7490,14 +7503,14 @@ init_define_import_meta_env();
7490
7503
  init_define_import_meta_env();
7491
7504
  var balanced = (a, b, str) => {
7492
7505
  const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
7493
- const mb2 = b instanceof RegExp ? maybeMatch(b, str) : b;
7494
- const r = ma !== null && mb2 != null && range(ma, mb2, str);
7506
+ const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
7507
+ const r = ma !== null && mb != null && range(ma, mb, str);
7495
7508
  return r && {
7496
7509
  start: r[0],
7497
7510
  end: r[1],
7498
7511
  pre: str.slice(0, r[0]),
7499
7512
  body: str.slice(r[0] + ma.length, r[1]),
7500
- post: str.slice(r[1] + mb2.length)
7513
+ post: str.slice(r[1] + mb.length)
7501
7514
  };
7502
7515
  };
7503
7516
  var maybeMatch = (reg, str) => {
@@ -11107,14 +11120,33 @@ function cmdYamlQuery(file, yamlPath, opts) {
11107
11120
  process.exitCode = runYamlQuery({ file, path: yamlPath, ...opts });
11108
11121
  }
11109
11122
  function cmdXmlOutline(file, opts) {
11123
+ const depthStr = opts.depth ?? opts.maxDepth;
11110
11124
  process.exitCode = runXmlOutline({
11111
11125
  file,
11112
11126
  ...opts.json === true ? { json: true } : {},
11113
- ...opts.maxDepth !== void 0 ? { maxDepth: requireNonNegativeInt2("--max-depth", opts.maxDepth) } : {}
11127
+ ...depthStr !== void 0 ? { maxDepth: requireNonNegativeInt2("--max-depth", depthStr) } : {}
11114
11128
  });
11115
11129
  }
11116
- function cmdXmlQuery(file, xmlPath, opts) {
11117
- process.exitCode = runXmlQuery({ file, path: xmlPath, ...opts });
11130
+ function cmdXmlQuery(file, pathOrOpts, optsMaybe) {
11131
+ let xmlPath;
11132
+ let opts = {};
11133
+ if (typeof pathOrOpts === "string") {
11134
+ xmlPath = pathOrOpts;
11135
+ opts = optsMaybe ?? {};
11136
+ } else if (typeof pathOrOpts === "object" && pathOrOpts !== null) {
11137
+ opts = pathOrOpts;
11138
+ } else if (typeof optsMaybe === "object" && optsMaybe !== null) {
11139
+ opts = optsMaybe;
11140
+ }
11141
+ process.exitCode = runXmlQuery({
11142
+ file,
11143
+ ...xmlPath !== void 0 ? { path: xmlPath } : {},
11144
+ ...opts.xpath !== void 0 ? { xpath: opts.xpath } : {},
11145
+ ...opts.head !== void 0 ? { head: opts.head } : {},
11146
+ ...opts.json === true ? { json: true } : {},
11147
+ ...opts.withLines === true ? { withLines: true } : {},
11148
+ ...opts.decodeEmbeddedXml === true ? { decodeEmbeddedXml: true } : {}
11149
+ });
11118
11150
  }
11119
11151
  function cmdHtmlOutline(file, opts) {
11120
11152
  process.exitCode = runHtmlOutline({ file, ...opts });
@@ -11764,7 +11796,7 @@ ${msg}`;
11764
11796
  out(text2);
11765
11797
  return;
11766
11798
  }
11767
- const shrinkLine = meta.wouldShrink && meta.shrunkBytes !== null ? `Shrink: would save ${meta.bytes - meta.shrunkBytes} bytes (${meta.bytes} -> ${meta.shrunkBytes})` : "Shrink: no benefit (already small/optimal)";
11799
+ const shrinkLine = meta.wouldShrink && meta.shrunkBytes !== null ? `Shrink: would save ${meta.bytes - meta.shrunkBytes} bytes (${meta.bytes} -> ${meta.shrunkBytes})` : !meta.shrinkable ? `Shrink: not attempted (token-goat re-encodes png, jpeg, bmp and gif; this is ${meta.format ?? "an unknown format"})` : "Shrink: no benefit (already small/optimal)";
11768
11800
  const lines = [
11769
11801
  `Dimensions: ${meta.width}x${meta.height}`,
11770
11802
  `Format: ${meta.format ?? "(unknown)"}`,
@@ -11865,10 +11897,10 @@ function registerFormatCommands(program2, guard) {
11865
11897
  program2.command("yaml-query <file> <path>").description(
11866
11898
  "extract one value or a projected/filtered subset from a YAML document by dot-path instead of a raw Read (same grammar as json-query)\n\npath grammar: dot-separated keys with optional bracket segments -- [n] index, [*] wildcard (projects every element/value), [field=value] filter (keeps array elements whose field stringifies to value). Examples: spec.containers[0].image, items[*].name, items[kind=Service]"
11867
11899
  ).option("--head <n>", "limit a projected/filtered result to the first N items").option("--json", "emit the result as JSON instead of text").action(guard(cmdYamlQuery));
11868
- program2.command("xml-outline <file>").description("structural summary of an XML document (element hierarchy / attribute names / child counts) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").option("--max-depth <n>", "max depth of element hierarchy to show").action(guard(cmdXmlOutline));
11869
- program2.command("xml-query <file> <path>").description(
11870
- "extract elements or attributes from an XML document by tag path instead of a raw Read\n\npath grammar: slash- or dot-separated tag names with optional bracket segments and attribute selectors -- [n] index, [*] wildcard, [@attr] or [@attr=value] filter, and trailing @attr to extract attribute value. Examples: root.child, catalog/book[@id=101]/title, /feed/entry[*]/@href"
11871
- ).option("--head <n>", "limit a matching result list to the first N items").option("--json", "emit the result as JSON instead of text").action(guard(cmdXmlQuery));
11900
+ program2.command("xml-outline <file>").description("structural summary of an XML document (element hierarchy / attribute names / child counts) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").option("--max-depth <n>", "max depth of element hierarchy to show").option("--depth <n>", "alias for --max-depth").action(guard(cmdXmlOutline));
11901
+ program2.command("xml-query <file> [path]").description(
11902
+ "extract elements or attributes from an XML document by tag path or XPath expression instead of a raw Read\n\npath grammar: slash- or dot-separated tag names with optional bracket segments and attribute selectors -- [n] index, [*] wildcard, [@attr] or [@attr=value] filter, and trailing @attr to extract attribute value. Bracket clauses stack and apply left to right, so an index after a filter counts within the filtered set. A clause may also be a comparison, contains() or starts-with() on an attribute or text(), joined with and/or; a clause outside that set, such as not(), matches nothing rather than being ignored, so you get an empty result instead of the unfiltered list. Examples: root.child, catalog/book[@id=101]/title, catalog/book[@genre=Fantasy][0], /feed/entry[*]/@href, //DTS:Executable[@DTS:ExecutableType='...']"
11903
+ ).option("--head <n>", "limit a matching result list to the first N items").option("--xpath <expression>", "query using an XPath expression").option("--with-lines", "show exact source line numbers for matched nodes").option("--decode-embedded-xml", "decode and format embedded entity-encoded XML/AML in text and attributes").option("--json", "emit the result as JSON instead of text").action(guard(cmdXmlQuery));
11872
11904
  program2.command("html-outline <file>").description("structural summary of an HTML document (title, doctype, landmarks, headings, tables, forms, scripts, styles) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").action(guard(cmdHtmlOutline));
11873
11905
  program2.command("html-query <file> <selector>").description(
11874
11906
  'extract elements, text, or attributes from an HTML document by CSS selector instead of a raw Read\n\nselector grammar: tags, #id, .class, [attr=val], child (>), descendant (space), comma-separated union, or trailing @attr. Examples: #main, .inquiry-row, table > tbody > tr, a[href^="https"], div@id'
@@ -14011,10 +14043,10 @@ var SHELL_READER_TOKEN_RE = /\b(?:sed|grep|cat|head|tail|awk|rg|less|nl|python3?
14011
14043
  function escapeRegExp2(s) {
14012
14044
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14013
14045
  }
14014
- function shellReadMatch(command, basename11) {
14015
- if (basename11 === "" || !SHELL_READER_TOKEN_RE.test(command)) return "none";
14016
- if (!command.includes(basename11)) return "none";
14017
- const escaped = escapeRegExp2(basename11);
14046
+ function shellReadMatch(command, basename10) {
14047
+ if (basename10 === "" || !SHELL_READER_TOKEN_RE.test(command)) return "none";
14048
+ if (!command.includes(basename10)) return "none";
14049
+ const escaped = escapeRegExp2(basename10);
14018
14050
  const strict = new RegExp(`(?:^|["'\`/\\\\\\s])${escaped}(?:$|["'\`/\\\\\\s,;:)])`);
14019
14051
  return strict.test(command) ? "match" : "ambiguous";
14020
14052
  }
@@ -14267,13 +14299,13 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
14267
14299
  if (name === "Read" || name === "Skill") {
14268
14300
  const denyTemplate = DENY_TEMPLATES.find((t) => t.tool === name && t.re.test(text));
14269
14301
  if (denyTemplate !== void 0) {
14270
- const path40 = readPathById.get(id) ?? "";
14271
- const lastSlash = path40.lastIndexOf("/");
14302
+ const path39 = readPathById.get(id) ?? "";
14303
+ const lastSlash = path39.lastIndexOf("/");
14272
14304
  openDenies.push({
14273
14305
  kind: denyTemplate.kind,
14274
14306
  withheldBytes: parseWithheldBytes(denyTemplate.kind, text),
14275
- path: path40,
14276
- basename: lastSlash === -1 ? path40 : path40.slice(lastSlash + 1),
14307
+ path: path39,
14308
+ basename: lastSlash === -1 ? path39 : path39.slice(lastSlash + 1),
14277
14309
  callIndexAtDeny: perCall.length,
14278
14310
  compactEpochAtOpen: compactEpoch,
14279
14311
  compactEpochAtWindow: null,
@@ -16654,133 +16686,6 @@ async function cmdSkillSection(nameHeading, headingArg) {
16654
16686
  out(extracted);
16655
16687
  }
16656
16688
 
16657
- // src/index_reclaim.ts
16658
- init_define_import_meta_env();
16659
- import * as fs39 from "node:fs";
16660
- import * as path35 from "node:path";
16661
- var DERIVED_TABLES = ["chunk_vectors", "chunks", "refs", "symbols", "files"];
16662
- function indexSizeBytes(dbPath) {
16663
- let total = 0;
16664
- for (const p of [dbPath, `${dbPath}-wal`]) {
16665
- try {
16666
- total += fs39.statSync(p).size;
16667
- } catch {
16668
- }
16669
- }
16670
- return total;
16671
- }
16672
- function comparableSizes(result) {
16673
- const walInFlight = result.checkpointBusy && result.afterBytes > result.beforeBytes;
16674
- const before = walInFlight ? result.beforeDbBytes : result.beforeBytes;
16675
- const after = walInFlight ? result.afterDbBytes : result.afterBytes;
16676
- return { before, after, freed: before - after };
16677
- }
16678
- function dbFileBytes(dbPath) {
16679
- try {
16680
- return fs39.statSync(dbPath).size;
16681
- } catch {
16682
- return 0;
16683
- }
16684
- }
16685
- function tableExists(db, table) {
16686
- const row = db.prepare(`SELECT 1 AS present FROM sqlite_master WHERE type IN ('table','view') AND name = ?`).get(table);
16687
- return row?.present === 1;
16688
- }
16689
- function reclaimIndex(dbPath, opts = {}) {
16690
- const rebuild = opts.rebuild === true;
16691
- const beforeBytes = indexSizeBytes(dbPath);
16692
- const beforeDbBytes = dbFileBytes(dbPath);
16693
- const db = getDb(dbPath);
16694
- const dropped = {};
16695
- if (rebuild) {
16696
- db.transaction(() => {
16697
- for (const table of DERIVED_TABLES) {
16698
- if (!tableExists(db, table)) continue;
16699
- const before = db.prepare(`SELECT count(*) AS c FROM "${table}"`).get().c;
16700
- db.prepare(`DELETE FROM "${table}"`).run();
16701
- dropped[table] = before;
16702
- }
16703
- }).immediate();
16704
- if (tableExists(db, "symbols_fts")) {
16705
- try {
16706
- db.prepare(`INSERT INTO symbols_fts(symbols_fts) VALUES('rebuild')`).run();
16707
- } catch {
16708
- }
16709
- }
16710
- }
16711
- const checkpointBusy = walCheckpointBusy(db);
16712
- const vacuumDeferred = !vacuumOrDefer(db);
16713
- const finalCheckpointBusy = walCheckpointBusy(db);
16714
- return {
16715
- beforeBytes,
16716
- afterBytes: indexSizeBytes(dbPath),
16717
- beforeDbBytes,
16718
- afterDbBytes: dbFileBytes(dbPath),
16719
- dropped,
16720
- rebuilt: rebuild,
16721
- checkpointBusy: checkpointBusy || finalCheckpointBusy,
16722
- vacuumDeferred
16723
- };
16724
- }
16725
- function vacuumOrDefer(db) {
16726
- try {
16727
- db.exec("VACUUM");
16728
- return true;
16729
- } catch (err2) {
16730
- const code = err2.code ?? "";
16731
- if (!code.startsWith("SQLITE_BUSY") && !code.startsWith("SQLITE_LOCKED")) throw err2;
16732
- return false;
16733
- }
16734
- }
16735
- function walCheckpointBusy(db) {
16736
- const rows = db.pragma("wal_checkpoint(TRUNCATE)");
16737
- return rows[0]?.busy === 1;
16738
- }
16739
- function mb(bytes) {
16740
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
16741
- }
16742
- function cmdReclaimIndex(opts) {
16743
- const dbPath = opts.dbPath ?? globalDbPath();
16744
- if (opts.force !== true && isWorkerRunning(path35.dirname(dbPath))) {
16745
- throw new Error(
16746
- "reclaim-index: the worker daemon is running and writing to this index. Stop it first with 'token-goat worker stop', then re-run. Pass --force to proceed anyway (results may be inaccurate if the worker is really live)."
16747
- );
16748
- }
16749
- const result = reclaimIndex(dbPath, { rebuild: opts.rebuild === true });
16750
- if (opts.json === true) {
16751
- process.stdout.write(displaySafeJson({ dbPath, ...result }) + "\n");
16752
- return;
16753
- }
16754
- const { before, after, freed } = comparableSizes(result);
16755
- const delta = freed >= 0 ? `freed ${mb(freed)}` : `grew ${mb(-freed)}`;
16756
- process.stdout.write(`reclaim-index: ${displaySafeText(dbPath)}
16757
- `);
16758
- process.stdout.write(` ${mb(before)} -> ${mb(after)} (${delta})
16759
- `);
16760
- if (result.rebuilt) {
16761
- for (const [table, n] of Object.entries(result.dropped)) {
16762
- process.stdout.write(` dropped ${n} row(s) from ${displaySafeText(table)}
16763
- `);
16764
- }
16765
- process.stdout.write(
16766
- ` derived rows dropped -- run 'token-goat index' in each project to rebuild them
16767
- `
16768
- );
16769
- }
16770
- if (result.vacuumDeferred) {
16771
- process.stdout.write(
16772
- ` note: VACUUM could not get an exclusive lock and was skipped, so on-disk size may be unchanged. The index itself was reclaimed; re-run 'token-goat reclaim-index' once nothing else is using the database to release the freed pages
16773
- `
16774
- );
16775
- }
16776
- if (result.checkpointBusy) {
16777
- process.stdout.write(
16778
- ` note: a concurrent reader blocked WAL truncation, so some space is still held in ${path35.basename(dbPath)}-wal and the figures above count the main file only. The next checkpoint releases it
16779
- `
16780
- );
16781
- }
16782
- }
16783
-
16784
16689
  // src/cache_session_commands.ts
16785
16690
  init_define_import_meta_env();
16786
16691
 
@@ -16868,8 +16773,8 @@ async function buildResumePacket(sessionId) {
16868
16773
 
16869
16774
  // src/cli_stats.ts
16870
16775
  init_define_import_meta_env();
16871
- import * as fs40 from "node:fs";
16872
- import * as path36 from "node:path";
16776
+ import * as fs39 from "node:fs";
16777
+ import * as path35 from "node:path";
16873
16778
  function writeRaw(text) {
16874
16779
  const payload = colorStdout() ? text : stripAnsi(text);
16875
16780
  process.stdout.write(ensureNewline(payload));
@@ -16881,8 +16786,8 @@ function formatTopFiles(ranked) {
16881
16786
  if (ranked.length === 0) return "";
16882
16787
  const lines = ["Top files this session:"];
16883
16788
  for (const { path: filePath, count } of ranked) {
16884
- const basename11 = path36.basename(filePath);
16885
- lines.push(` ${count.toString().padStart(3)}x ${basename11} (${filePath})`);
16789
+ const basename10 = path35.basename(filePath);
16790
+ lines.push(` ${count.toString().padStart(3)}x ${basename10} (${filePath})`);
16886
16791
  }
16887
16792
  return lines.join("\n");
16888
16793
  }
@@ -16898,12 +16803,12 @@ function renderTopSessionFiles(topN = 5) {
16898
16803
  }
16899
16804
  function renderTopSessionFilesFromDisk(topN = 5, overrideSessionsDir) {
16900
16805
  try {
16901
- const sessionsDir = overrideSessionsDir ?? path36.join(dataDir(), "sessions");
16902
- if (!fs40.existsSync(sessionsDir)) return "";
16903
- const files = fs40.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, mtime: fs40.statSync(path36.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).slice(0, 3);
16806
+ const sessionsDir = overrideSessionsDir ?? path35.join(dataDir(), "sessions");
16807
+ if (!fs39.existsSync(sessionsDir)) return "";
16808
+ const files = fs39.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, mtime: fs39.statSync(path35.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).slice(0, 3);
16904
16809
  for (const { name } of files) {
16905
16810
  try {
16906
- const raw = fs40.readFileSync(path36.join(sessionsDir, name), "utf-8");
16811
+ const raw = fs39.readFileSync(path35.join(sessionsDir, name), "utf-8");
16907
16812
  const data = JSON.parse(raw);
16908
16813
  const filesList = data["files"];
16909
16814
  if (!Array.isArray(filesList)) continue;
@@ -17442,6 +17347,8 @@ function registerSessionCommands(program2, guard) {
17442
17347
  ...opts.sentences !== void 0 ? { sentences: opts.sentences } : {},
17443
17348
  ...opts.show === true ? { show: true } : {}
17444
17349
  }))());
17350
+ program2.command("session-schema [table]").description("authoritative schema discovery for Copilot session_store_sql (DuckDB/SQLite) and session SQLite tables instead of trial-and-error SELECT *").option("-j, --json", "output as JSON").action(guard(cmdSessionSchema));
17351
+ program2.command("describe [target] [table]").description("describe columns and structure of a session store table or SQLite database file instead of querying SELECT *").option("-j, --json", "output as JSON").action(guard(cmdDescribe));
17445
17352
  }
17446
17353
 
17447
17354
  // src/bridges_status.ts
@@ -17780,25 +17687,25 @@ function installVerificationNotice(harness) {
17780
17687
 
17781
17688
  // src/purge.ts
17782
17689
  init_define_import_meta_env();
17783
- import * as fs41 from "node:fs";
17784
- import * as path37 from "node:path";
17690
+ import * as fs40 from "node:fs";
17691
+ import * as path36 from "node:path";
17785
17692
  function directorySize(root) {
17786
17693
  let total = 0;
17787
17694
  let entries;
17788
17695
  try {
17789
- entries = fs41.readdirSync(root, { withFileTypes: true });
17696
+ entries = fs40.readdirSync(root, { withFileTypes: true });
17790
17697
  } catch {
17791
17698
  return 0;
17792
17699
  }
17793
17700
  for (const entry of entries) {
17794
- const full = path37.join(root, entry.name);
17701
+ const full = path36.join(root, entry.name);
17795
17702
  if (entry.isDirectory()) {
17796
17703
  total += directorySize(full);
17797
17704
  continue;
17798
17705
  }
17799
17706
  if (!entry.isFile()) continue;
17800
17707
  try {
17801
- total += fs41.statSync(full).size;
17708
+ total += fs40.statSync(full).size;
17802
17709
  } catch {
17803
17710
  }
17804
17711
  }
@@ -17817,7 +17724,7 @@ function purgeDataDirectories() {
17817
17724
  }
17818
17725
  const bytes = directorySize(root);
17819
17726
  try {
17820
- fs41.rmSync(root, { recursive: true, force: true });
17727
+ fs40.rmSync(root, { recursive: true, force: true });
17821
17728
  result.removed.push({ path: root, bytes });
17822
17729
  } catch (e) {
17823
17730
  result.failed.push({ path: root, reason: e instanceof Error ? e.message : String(e) });
@@ -17964,8 +17871,8 @@ async function getSectionContent(fileId, heading, opts = {}) {
17964
17871
 
17965
17872
  // src/cli_bench.ts
17966
17873
  init_define_import_meta_env();
17967
- import * as fs42 from "node:fs";
17968
- import * as path38 from "node:path";
17874
+ import * as fs41 from "node:fs";
17875
+ import * as path37 from "node:path";
17969
17876
  var ControlFilter = class extends ToolFilter {
17970
17877
  constructor(name, transform) {
17971
17878
  super();
@@ -17986,13 +17893,13 @@ var CONTROL_FILTERS = {
17986
17893
  };
17987
17894
  var MAX_BENCH_FILE_BYTES = 5 * 1024 * 1024;
17988
17895
  function readCaseFile(id, filePath, what) {
17989
- const bytes = fs42.statSync(filePath).size;
17896
+ const bytes = fs41.statSync(filePath).size;
17990
17897
  if (bytes > MAX_BENCH_FILE_BYTES) {
17991
17898
  throw new Error(
17992
17899
  `bench case ${id}: ${what} is ${bytes} bytes, over the ${MAX_BENCH_FILE_BYTES}-byte limit for a corpus file (${filePath})`
17993
17900
  );
17994
17901
  }
17995
- return fs42.readFileSync(filePath, "utf8");
17902
+ return fs41.readFileSync(filePath, "utf8");
17996
17903
  }
17997
17904
  function parseCase(id, metaPath, outputPath) {
17998
17905
  const metaText = readCaseFile(id, metaPath, "metadata");
@@ -18027,7 +17934,7 @@ function parseCase(id, metaPath, outputPath) {
18027
17934
  function loadCorpus(dir) {
18028
17935
  let entries;
18029
17936
  try {
18030
- entries = fs42.readdirSync(dir);
17937
+ entries = fs41.readdirSync(dir);
18031
17938
  } catch {
18032
17939
  throw new Error(`bench corpus not found: ${dir}`);
18033
17940
  }
@@ -18035,9 +17942,9 @@ function loadCorpus(dir) {
18035
17942
  for (const entry of entries.sort()) {
18036
17943
  if (!entry.endsWith(".json")) continue;
18037
17944
  const id = entry.slice(0, -".json".length);
18038
- const outputPath = path38.join(dir, `${id}.txt`);
18039
- if (!fs42.existsSync(outputPath)) throw new Error(`bench case ${id}: missing output file ${outputPath}`);
18040
- cases.push(parseCase(id, path38.join(dir, entry), outputPath));
17945
+ const outputPath = path37.join(dir, `${id}.txt`);
17946
+ if (!fs41.existsSync(outputPath)) throw new Error(`bench case ${id}: missing output file ${outputPath}`);
17947
+ cases.push(parseCase(id, path37.join(dir, entry), outputPath));
18041
17948
  }
18042
17949
  if (cases.length === 0) throw new Error(`bench corpus is empty: ${dir}`);
18043
17950
  return cases;
@@ -18157,10 +18064,10 @@ function appendTsv(file, report, commit) {
18157
18064
  report.mustKeepTotal,
18158
18065
  report.coveredFilters
18159
18066
  ].join(" ");
18160
- const dir = path38.dirname(path38.resolve(file));
18161
- fs42.mkdirSync(dir, { recursive: true });
18162
- const header = fs42.existsSync(file) ? "" : TSV_HEADER;
18163
- fs42.appendFileSync(file, header + row + "\n", "utf8");
18067
+ const dir = path37.dirname(path37.resolve(file));
18068
+ fs41.mkdirSync(dir, { recursive: true });
18069
+ const header = fs41.existsSync(file) ? "" : TSV_HEADER;
18070
+ fs41.appendFileSync(file, header + row + "\n", "utf8");
18164
18071
  }
18165
18072
  function currentCommit(cwd) {
18166
18073
  const opts = cwd === void 0 ? {} : { cwd };
@@ -18200,10 +18107,10 @@ function readBoundedText(text, file) {
18200
18107
  if (text === void 0 && file === void 0) throw new CliError("provide text or --file");
18201
18108
  let value;
18202
18109
  if (file !== void 0) {
18203
- if (fs43.statSync(file).size > CONTENT_MAX_INPUT_CHARS) {
18110
+ if (fs42.statSync(file).size > CONTENT_MAX_INPUT_CHARS) {
18204
18111
  throw new CliError(`file exceeds the ${CONTENT_MAX_INPUT_CHARS}-byte safety limit`);
18205
18112
  }
18206
- value = fs43.readFileSync(file, "utf8");
18113
+ value = fs42.readFileSync(file, "utf8");
18207
18114
  } else {
18208
18115
  if (text === void 0) throw new CliError("provide text or --file");
18209
18116
  value = text;
@@ -18273,12 +18180,17 @@ function requirePositiveInt2(flag, raw) {
18273
18180
  return n;
18274
18181
  }
18275
18182
  async function cmdSemantic(query, opts) {
18183
+ if (!query && !opts.preflight && !opts.warm) {
18184
+ throw new CliError("missing required argument: query");
18185
+ }
18276
18186
  const limit = opts.limit !== void 0 ? requireNonNegativeInt2("--limit", opts.limit) : 20;
18277
- const { text, code } = await runSemantic(query, {
18187
+ const { text, code } = await runSemantic(query ?? "", {
18278
18188
  limit,
18279
18189
  ...opts.json === true ? { json: true } : {},
18280
18190
  ...opts.grep !== void 0 ? { grep: opts.grep } : {},
18281
- ...opts.excludeTests === true ? { excludeTests: true } : {}
18191
+ ...opts.excludeTests === true ? { excludeTests: true } : {},
18192
+ ...opts.preflight === true ? { preflight: true } : {},
18193
+ ...opts.warm === true ? { warm: true } : {}
18282
18194
  });
18283
18195
  (opts.json === true || code === 0 ? out : err)(text);
18284
18196
  process.exitCode = code;
@@ -18344,7 +18256,7 @@ async function cmdIndex(pathArg, opts = {}) {
18344
18256
  continue;
18345
18257
  }
18346
18258
  const sha = fingerprintFile(key);
18347
- if (sha === null && !fs43.existsSync(key)) continue;
18259
+ if (sha === null && !fs42.existsSync(key)) continue;
18348
18260
  const entry = sha !== null ? getFileEntry(key, dbPath) : null;
18349
18261
  const spellingStale = entry !== null && indexedPathSpellingIsStale(entry.filePath, key);
18350
18262
  const parseUnchanged = !force && !spellingStale && sha !== null && entry?.sha === sha && entry.parserSha === PARSER_FINGERPRINT;
@@ -18377,7 +18289,7 @@ async function cmdIndex(pathArg, opts = {}) {
18377
18289
  }
18378
18290
  continue;
18379
18291
  }
18380
- if (!fs43.existsSync(key)) continue;
18292
+ if (!fs42.existsSync(key)) continue;
18381
18293
  }
18382
18294
  if (!embedUnchanged) {
18383
18295
  paintProgress("embedding");
@@ -18437,7 +18349,7 @@ async function cmdMcpServe() {
18437
18349
  let StdioServerTransport;
18438
18350
  try {
18439
18351
  ;
18440
- ({ createMcpServer } = await import("./token-goat-chunk-YTQHZJXW.mjs"));
18352
+ ({ createMcpServer } = await import("./token-goat-chunk-DQ4J5AFF.mjs"));
18441
18353
  ({ StdioServerTransport } = await import("./token-goat-chunk-EVC4TOLE.mjs"));
18442
18354
  } catch (err2) {
18443
18355
  process.stderr.write(
@@ -18462,11 +18374,11 @@ async function cmdHook(event, opts) {
18462
18374
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
18463
18375
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
18464
18376
  }
18465
- const { relay } = await import("./token-goat-chunk-ZD4EM4LR.mjs");
18377
+ const { relay } = await import("./token-goat-chunk-6DLVZDB6.mjs");
18466
18378
  await relay(event);
18467
18379
  }
18468
18380
  function projectHooksCommitNote(pathFiles, hooksConfigPath) {
18469
- const shim = hooksConfigPath === void 0 ? "" : ` (${displaySafePath(path39.join(path39.dirname(hooksConfigPath), HOOKS_SCRIPT_FILE))} is generated with them)`;
18381
+ const shim = hooksConfigPath === void 0 ? "" : ` (${displaySafePath(path38.join(path38.dirname(hooksConfigPath), HOOKS_SCRIPT_FILE))} is generated with them)`;
18470
18382
  return `Note: ${pathFiles.map((p) => displaySafePath(p)).join(", ")} ${pathFiles.length === 1 ? "holds" : "hold"} absolute paths to node and token-goat on this machine${shim}, so do not commit them: list them in .git/info/exclude or .gitignore.`;
18471
18383
  }
18472
18384
  function visualStudioManualSteps(scope) {
@@ -18499,7 +18411,7 @@ async function cmdInstall(opts) {
18499
18411
  if (opts.project === true && opts.user === true) {
18500
18412
  throw new Error("install takes either -p/--project or --user, not both.");
18501
18413
  }
18502
- await import("./token-goat-chunk-ZD4EM4LR.mjs");
18414
+ await import("./token-goat-chunk-6DLVZDB6.mjs");
18503
18415
  const scope = opts.project === true ? "project" : "user";
18504
18416
  if (wantsClaudeCodeBase(opts)) {
18505
18417
  const result = installHooks(scope);
@@ -18645,16 +18557,16 @@ async function cmdInstall(opts) {
18645
18557
  );
18646
18558
  }
18647
18559
  try {
18648
- const skillDir = path39.join(homedir15(), ".claude", "skills");
18649
- if (fs43.existsSync(skillDir)) {
18650
- const entries = fs43.readdirSync(skillDir, { withFileTypes: true });
18560
+ const skillDir = path38.join(homedir15(), ".claude", "skills");
18561
+ if (fs42.existsSync(skillDir)) {
18562
+ const entries = fs42.readdirSync(skillDir, { withFileTypes: true });
18651
18563
  const skillNames = [];
18652
18564
  const sessionId = getSessionId();
18653
18565
  for (const entry of entries) {
18654
18566
  if (!entry.isDirectory()) continue;
18655
- const skillFile = path39.join(skillDir, entry.name, "SKILL.md");
18656
- if (fs43.existsSync(skillFile)) {
18657
- const body = fs43.readFileSync(skillFile, "utf-8");
18567
+ const skillFile = path38.join(skillDir, entry.name, "SKILL.md");
18568
+ if (fs42.existsSync(skillFile)) {
18569
+ const body = fs42.readFileSync(skillFile, "utf-8");
18658
18570
  const compact = extractCompactFromMarker(body);
18659
18571
  if (compact === null) continue;
18660
18572
  const sourceSha = contentHash(body);
@@ -18665,9 +18577,9 @@ async function cmdInstall(opts) {
18665
18577
  if (skillNames.length > 0) {
18666
18578
  const dir = skillOutputsDir();
18667
18579
  ensureDirSync(dir);
18668
- const pregenPath = path39.join(dir, "pregen.json");
18580
+ const pregenPath = path38.join(dir, "pregen.json");
18669
18581
  const pregenData = { ts: Date.now(), names: skillNames };
18670
- await fs43.promises.writeFile(pregenPath, JSON.stringify(pregenData, null, 2));
18582
+ await fs42.promises.writeFile(pregenPath, JSON.stringify(pregenData, null, 2));
18671
18583
  out(`Pre-generated ${skillNames.length} skill compacts.`);
18672
18584
  }
18673
18585
  }
@@ -18908,6 +18820,15 @@ function _applyFiltersAndPrint(content, opts, fenceByProvenance = false, fenceTa
18908
18820
  return emit3(result.join("\n"));
18909
18821
  }
18910
18822
  function cmdBashOutput(id, opts) {
18823
+ const parseVerifyThreshold = (optVal) => {
18824
+ if (optVal === void 0 || optVal === false) return void 0;
18825
+ if (typeof optVal === "string" && optVal.trim() !== "" && !isNaN(Number(optVal))) {
18826
+ const parsed = Number(optVal);
18827
+ return parsed >= 0 ? parsed : 60;
18828
+ }
18829
+ return 60;
18830
+ };
18831
+ const verifyThresholdSec = parseVerifyThreshold(opts.verifyLastWrite);
18911
18832
  if (opts.file !== void 0) {
18912
18833
  if (opts.file.includes("\0")) {
18913
18834
  throw new CliError("--file path contains a null byte");
@@ -18917,11 +18838,22 @@ function cmdBashOutput(id, opts) {
18917
18838
  }
18918
18839
  let content;
18919
18840
  try {
18920
- const st = fs43.statSync(opts.file);
18841
+ const st = fs42.statSync(opts.file);
18921
18842
  if (st.isFIFO() || st.isSocket()) {
18922
18843
  throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
18923
18844
  }
18924
- content = redactIfDotenv(opts.file, decodeSource(fs43.readFileSync(opts.file)));
18845
+ if (verifyThresholdSec !== void 0) {
18846
+ const ageSec = Math.round((Date.now() - st.mtimeMs) / 1e3);
18847
+ if (ageSec > verifyThresholdSec) {
18848
+ const msg = `stale write: '${opts.file}' was modified ${ageSec}s ago (threshold: ${verifyThresholdSec}s). Terminal command may have silently failed or no-op'd.`;
18849
+ if (opts.strict === true) {
18850
+ throw new CliError(msg);
18851
+ }
18852
+ process.stderr.write(`[tg: stale-write] ${msg}
18853
+ `);
18854
+ }
18855
+ }
18856
+ content = redactIfDotenv(opts.file, decodeSource(fs42.readFileSync(opts.file)));
18925
18857
  } catch (e) {
18926
18858
  if (e instanceof CliError) throw e;
18927
18859
  throw new CliError(`cannot read file: ${opts.file}`);
@@ -18936,6 +18868,17 @@ function cmdBashOutput(id, opts) {
18936
18868
  if (entry === null) {
18937
18869
  throw new CliError(`no cached bash output for id: ${id}. If this id is from a background task, recall its output file directly with: token-goat bash-output --file <path-to-output-file>`);
18938
18870
  }
18871
+ if (verifyThresholdSec !== void 0) {
18872
+ const ageSec = Math.round((Date.now() - entry.storedAt) / 1e3);
18873
+ if (ageSec > verifyThresholdSec) {
18874
+ const msg = `stale write: cached output '${id}' was recorded ${ageSec}s ago (threshold: ${verifyThresholdSec}s). Terminal command may have silently failed or not re-run.`;
18875
+ if (opts.strict === true) {
18876
+ throw new CliError(msg);
18877
+ }
18878
+ process.stderr.write(`[tg: stale-write] ${msg}
18879
+ `);
18880
+ }
18881
+ }
18939
18882
  _applyFiltersAndPrint(entry.output, opts, true, UNTRUSTED_TOOL_TAG);
18940
18883
  }
18941
18884
  function cmdWebOutput(id, opts) {
@@ -18948,18 +18891,95 @@ function cmdWebOutput(id, opts) {
18948
18891
  }
18949
18892
  _applyFiltersAndPrint(content, opts, true);
18950
18893
  }
18951
- function cmdMcpOutput(id, opts) {
18952
- if (id === void 0) {
18953
- throw new CliError("provide an mcp-output <id>");
18954
- }
18955
- if (!id.startsWith("mcp_")) {
18956
- throw new CliError(`not an mcp-output id: ${id} (expected an id starting with 'mcp_')`);
18894
+ function extractJsonFromMcpOutput(text) {
18895
+ const trimmed = text.trim();
18896
+ try {
18897
+ return JSON.parse(trimmed);
18898
+ } catch {
18899
+ const cleaned = trimmed.replace(/^\[token-goat:[^\]]+\]\r?\n?/i, "").replace(/^<untrusted-tool-output[^>]*>\r?\n?/i, "").replace(/\r?\n?<\/untrusted-tool-output>$/i, "").trim();
18900
+ try {
18901
+ return JSON.parse(cleaned);
18902
+ } catch {
18903
+ const blockMatch = /```(?:json)?\r?\n([\s\S]*?)```/.exec(trimmed);
18904
+ if (blockMatch && blockMatch[1]) {
18905
+ try {
18906
+ return JSON.parse(blockMatch[1].trim());
18907
+ } catch {
18908
+ }
18909
+ }
18910
+ throw new CliError("content is not valid JSON for --json-query");
18911
+ }
18957
18912
  }
18958
- const entry = getBashOutput(id);
18959
- if (entry === null) {
18960
- throw new CliError(`no cached mcp output for id: ${id}. The cache may have expired; re-run the MCP tool call to repopulate it.`);
18913
+ }
18914
+ function cmdMcpOutput(id, opts) {
18915
+ let content;
18916
+ if (opts.file !== void 0) {
18917
+ if (opts.file.includes("\0")) {
18918
+ throw new CliError("--file path contains a null byte");
18919
+ }
18920
+ if (!fs42.existsSync(opts.file)) {
18921
+ throw new CliError(`file not found: ${opts.file}`);
18922
+ }
18923
+ try {
18924
+ const st = fs42.statSync(opts.file);
18925
+ if (st.isFIFO() || st.isSocket()) {
18926
+ throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
18927
+ }
18928
+ content = decodeSource(fs42.readFileSync(opts.file));
18929
+ } catch (e) {
18930
+ if (e instanceof CliError) throw e;
18931
+ throw new CliError(`cannot read file: ${opts.file}`);
18932
+ }
18933
+ } else if (id !== void 0) {
18934
+ if (!id.startsWith("mcp_")) {
18935
+ throw new CliError(`not an mcp-output id: ${id} (expected an id starting with 'mcp_')`);
18936
+ }
18937
+ const entry = getBashOutput(id);
18938
+ if (entry === null) {
18939
+ throw new CliError(`no cached mcp output for id: ${id}. The cache may have expired; re-run the MCP tool call to repopulate it.`);
18940
+ }
18941
+ content = entry.output;
18942
+ } else {
18943
+ throw new CliError("provide an mcp-output <id> or --file <path>");
18944
+ }
18945
+ if (opts.jsonQuery !== void 0) {
18946
+ const data = extractJsonFromMcpOutput(content);
18947
+ let head;
18948
+ if (opts.head !== void 0) {
18949
+ head = requireNonNegativeInt2("--head", opts.head);
18950
+ }
18951
+ const queryResult = queryJson(data, opts.jsonQuery);
18952
+ const { head: _omittedHead, ...restOpts } = opts;
18953
+ const printOpts = { ...restOpts, full: true };
18954
+ if (!queryResult.fanned) {
18955
+ const val = queryResult.items[0];
18956
+ const formatted = opts.json === true ? displaySafeJson(val, 0) : displaySafeJson(val);
18957
+ _applyFiltersAndPrint(formatted, printOpts, true, UNTRUSTED_TOOL_TAG);
18958
+ return;
18959
+ }
18960
+ const totalCount = queryResult.items.length;
18961
+ const limited = head !== void 0 ? queryResult.items.slice(0, head) : queryResult.items;
18962
+ const headTruncated = limited.length < totalCount;
18963
+ if (opts.json === true) {
18964
+ const capped = guardJsonRows(limited);
18965
+ const jsonText = displaySafeJson(
18966
+ { items: capped.items, truncated: capped.truncated || headTruncated || queryResult.truncated, totalCount },
18967
+ 0
18968
+ );
18969
+ _applyFiltersAndPrint(jsonText, printOpts, true, UNTRUSTED_TOOL_TAG);
18970
+ } else {
18971
+ const lines = limited.map((item) => displaySafeJson(item, 0));
18972
+ if (headTruncated) {
18973
+ lines.push(`...(${totalCount - limited.length} more items elided; use --head to see more)`);
18974
+ }
18975
+ if (queryResult.truncated) {
18976
+ lines.push(`...(the search stopped early at this tool's traversal limit; these are not necessarily all the matches. Narrow the path to search less of the document.)`);
18977
+ }
18978
+ _applyFiltersAndPrint(lines.join("\n"), printOpts, true, UNTRUSTED_TOOL_TAG);
18979
+ }
18980
+ return;
18961
18981
  }
18962
- _applyFiltersAndPrint(entry.output, opts, true, UNTRUSTED_TOOL_TAG);
18982
+ _applyFiltersAndPrint(content, opts, true, UNTRUSTED_TOOL_TAG);
18963
18983
  }
18964
18984
  function cmdPrSlice(pr, slice, opts) {
18965
18985
  process.exitCode = runPrSlice({ pr, slice, ...opts });
@@ -18978,7 +18998,7 @@ async function cmdCompress(commandArgs, opts = {}) {
18978
18998
  process.exitCode = 1;
18979
18999
  return;
18980
19000
  }
18981
- const bashRunner = await import("./token-goat-chunk-PGGDW7DZ.mjs");
19001
+ const bashRunner = await import("./token-goat-chunk-ATIFTMRC.mjs");
18982
19002
  if (opts.compress === false) {
18983
19003
  process.exitCode = bashRunner.runRaw(command, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
18984
19004
  return;
@@ -19138,7 +19158,7 @@ function buildProgram() {
19138
19158
  () => noteExtraFileArgs("section", spec, more, () => runSection({ spec, ...opts.json === true ? { json: true } : {} }), { noun: "spec" })
19139
19159
  )
19140
19160
  );
19141
- program2.command("semantic <query>").description("semantic search (falls back to full-text search)").option("-l, --limit <n>", "max results").option("-j, --json", "output as JSON").option("--grep <pattern>", "filter to hits whose file path matches this regex (literal substring if it is not valid regex); matched against the path as rendered").option("--exclude-tests", "hide hits whose file is a test file (opt-in; default output is unchanged)").action(guard(cmdSemantic));
19161
+ program2.command("semantic [query]").description("semantic search (falls back to full-text search)").option("-l, --limit <n>", "max results").option("-j, --json", "output as JSON").option("--grep <pattern>", "filter to hits whose file path matches this regex (literal substring if it is not valid regex); matched against the path as rendered").option("--exclude-tests", "hide hits whose file is a test file (opt-in; default output is unchanged)").option("--preflight", "run semantic embedding preflight check and exit").option("--warm", "warm up the embedding model session in memory").action(guard(cmdSemantic));
19142
19162
  const registerSymbolListing = (name, description, run2) => {
19143
19163
  program2.command(`${name} <file> [more...]`).description(description).option("-j, --json", "output as JSON").option("--min-lines <n>", "only show symbols at least N lines long").option("--grep <pattern>", "only show symbols whose name matches this regex (literal substring if it is not valid regex)").option("--force-refresh", "reparse file from disk before querying (ignore stale index)").option("--stats", "add per-symbol reference count and doc-coverage flag").action(
19144
19164
  (file, more, opts) => runExitText(
@@ -19194,7 +19214,7 @@ function buildProgram() {
19194
19214
  program2.command("bench").description("replay a corpus of captured command output through the compressors; prints the byte savings ratio and a fidelity check, and exits 1 when a must-keep line was dropped").option("--corpus <dir>", "corpus directory (default: tests/fixtures/bench, relative to the working directory)").option("--tsv <path>", "append one result row, keyed by the current commit, creating the file and its header if absent").option("--validate", "score the corpus with control filters instead: proves the ratio has a floor and the fidelity guard can actually fail").option("-j, --json", "output as JSON").action(
19195
19215
  (opts) => runExitText(
19196
19216
  () => runBenchCommand({
19197
- corpus: opts.corpus ?? path39.join("tests", "fixtures", "bench"),
19217
+ corpus: opts.corpus ?? path38.join("tests", "fixtures", "bench"),
19198
19218
  ...opts.tsv !== void 0 ? { tsv: opts.tsv } : {},
19199
19219
  ...opts.validate === true ? { validate: true } : {},
19200
19220
  ...opts.json === true ? { json: true } : {}
@@ -19215,9 +19235,9 @@ function buildProgram() {
19215
19235
  worker.command("status").description("check if the indexer is running").action(guard(cmdWorkerStatus));
19216
19236
  program2.command("stats").description("show session statistics (bare = totals only; --full for the breakdown)").option("-j, --json", "output as JSON").option("--full", "show the full breakdown (by source, by command, by day)").option("--short", "force the rich short KPI view even when stdout is not a TTY (e.g. piped)").option("--methodology", "explain local savings estimates and their billing limits").option("--window-days <days>", "days to include (0 = all time)", "30").option("--home-dir <path>", "home directory (for testing)").action(guard(cmdStats));
19217
19237
  program2.command("doctor").description("diagnose token-goat health").option("--context", "include context footprint analysis").option("--json", "emit check results as JSON instead of text").action(guard(cmdDoctor));
19218
- program2.command("bash-output [id]").description("retrieve cached bash output by ID or file").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the output").option("--full", "print the entire cached entry with no head/tail elision").option("--file <path>", "read from raw output file instead of cache").option("--transcript", "parse the --file as a JSONL agent transcript: keep assistant text blocks in order before filtering").action(guard(cmdBashOutput));
19238
+ program2.command("bash-output [id]").description("retrieve cached bash output by ID or file").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the output").option("--full", "print the entire cached entry with no head/tail elision").option("--file <path>", "read from raw output file instead of cache").option("--transcript", "parse the --file as a JSONL agent transcript: keep assistant text blocks in order before filtering").option("--verify-last-write [seconds]", "verify the file or cache entry was written within [seconds] (default: 60s) to catch stale/no-op terminal output").option("--strict", "exit non-zero when --verify-last-write detects stale output").action(guard(cmdBashOutput));
19219
19239
  program2.command("web-output [id]").description("retrieve a cached WebFetch response body by ID").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the response").option("--full", "print the entire cached entry with no head/tail elision").option("--raw", "return the body as actually fetched, before extractCleanText cleaning, instead of the default cleaned text").action(guard(cmdWebOutput));
19220
- program2.command("mcp-output [id]").description("retrieve a cached MCP tool result by ID (the id an MCP post_tool_use hook cached, or a `[token-goat: compressed, full via mcp-output <id>]` label points here)").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the result").option("--full", "print the entire cached entry with no head/tail elision").action(guard(cmdMcpOutput));
19240
+ program2.command("mcp-output [id]").description("retrieve a cached MCP tool result by ID (the id an MCP post_tool_use hook cached, or a `[token-goat: compressed, full via mcp-output <id>]` label points here)").option("--head <n>", "show first N lines (or first N items with --json-query)").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the result").option("--full", "print the entire cached entry with no head/tail elision").option("--json-query <path>", 'query JSON content using a dot/bracket path expression (e.g. "issues[*].key")').option("--file <path>", "read and query an on-disk tool spill file (e.g. content.json) instead of cache").option("--json", "emit query results as structured JSON envelope").action(guard(cmdMcpOutput));
19221
19241
  program2.command("pr-slice <pr> <slice>").description(
19222
19242
  "one slice of a GitHub PR (files / one file's diff / review comments / description) via `gh` instead of a full `gh pr view`/`gh pr diff` dump\n\npr is a PR number or URL. slice is one of: files (changed files with +/- counts), diff:<path> (one file's diff hunk), comments (review comments), description (title/body/metadata)"
19223
19243
  ).option("--repo <owner/repo>", "target repo (default: resolved from the current directory's git remote 'origin')").option("--json", "emit the slice as JSON instead of text").action(guard(cmdPrSlice));
@@ -19228,7 +19248,7 @@ function buildProgram() {
19228
19248
  program2.command("compress [command...]").alias("bash").alias("run").description("run a shell command (under a POSIX shell / bash) and emit a compressed view of its output").allowUnknownOption(true).option("-c, --cmd <command>", "the shell command to run, as one string (use / for paths across platforms)").option("--cmd-b64 <payload>", "the shell command as a base64-encoded string (preserves quotes, backslashes, and symbols across platforms)").option("-f, --filter <name>", "filter name (auto-detected from the command when omitted)").option("--timeout <seconds>", "wall-clock timeout in seconds (0 = built-in default)").option("--no-compress", "stream output raw without compression (debug the wrapper)").option("--profile <name>", "compression profile: aggressive | balanced | minimal").option("--max-tokens <n>", "post-compress token cap (0 = no cap)").option("-q, --quiet-success", "on exit code 0, emit only [tg: ok] summary and store full output for recall via bash-output").option("--native", "use native platform shell (e.g. cmd.exe on Windows) instead of bash, preserving Windows path backslashes").action(cmdCompress);
19229
19249
  program2.command("upgrade").alias("update").description("check for updates and upgrade token-goat to the latest version").option("--check", "check whether an update is available without installing").option("-j, --json", "emit version check status as JSON").action(
19230
19250
  (opts) => guard(async () => {
19231
- const { cmdUpgrade } = await import("./token-goat-chunk-7OGKZ7AP.mjs");
19251
+ const { cmdUpgrade } = await import("./token-goat-chunk-A4JYKD5H.mjs");
19232
19252
  await cmdUpgrade(opts, () => cmdInstall({}));
19233
19253
  })()
19234
19254
  );