token-goat 2.6.33 → 2.6.35

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 (25) hide show
  1. package/README.md +4 -0
  2. package/SECURITY.md +11 -10
  3. package/dist/{token-goat-chunk-FN6WLFIX.mjs → token-goat-chunk-D5IZEGN2.mjs} +817 -53
  4. package/dist/{token-goat-hook-chunk-HXHFLKEL.mjs → token-goat-chunk-DQIT5JIF.mjs} +7 -2
  5. package/dist/{token-goat-chunk-72R7M5H7.mjs → token-goat-chunk-DRAIYVUI.mjs} +16 -14
  6. package/dist/{token-goat-chunk-RPOXYJWK.mjs → token-goat-chunk-HW4VUKJ5.mjs} +77 -26
  7. package/dist/{token-goat-chunk-TDYTBCT4.mjs → token-goat-chunk-I2KCEGIP.mjs} +704 -138
  8. package/dist/{token-goat-chunk-WFRR2DBG.mjs → token-goat-chunk-K7W3P2TJ.mjs} +583 -343
  9. package/dist/{token-goat-chunk-OHQ7RBLL.mjs → token-goat-chunk-SIHYQCTM.mjs} +2 -2
  10. package/dist/{token-goat-chunk-77CX3MCN.mjs → token-goat-chunk-UIZVX3HN.mjs} +2 -2
  11. package/dist/{token-goat-chunk-L6FVTDPD.mjs → token-goat-chunk-Y2NH6DGZ.mjs} +564 -31
  12. package/dist/{token-goat-chunk-HPWPUBAK.mjs → token-goat-chunk-YF67EWRH.mjs} +5 -5
  13. package/dist/{token-goat-hook-chunk-E6AIPKNF.mjs → token-goat-hook-chunk-2O7P4Z6Q.mjs} +579 -339
  14. package/dist/{token-goat-hook-chunk-WBBHV6TZ.mjs → token-goat-hook-chunk-3AAH72SO.mjs} +77 -26
  15. package/dist/{token-goat-hook-chunk-QD2DX2U7.mjs → token-goat-hook-chunk-4POU6OHK.mjs} +564 -31
  16. package/dist/{token-goat-hook-chunk-ZT47M3IA.mjs → token-goat-hook-chunk-CRBMPT74.mjs} +2 -2
  17. package/dist/{token-goat-hook-chunk-26DLRODR.mjs → token-goat-hook-chunk-D6UJEFHX.mjs} +2 -2
  18. package/dist/{token-goat-hook-chunk-XBOWDNJB.mjs → token-goat-hook-chunk-J4HKWUWZ.mjs} +5 -5
  19. package/dist/{token-goat-chunk-RQQ4SY2P.mjs → token-goat-hook-chunk-NIPXIAPA.mjs} +7 -2
  20. package/dist/{token-goat-hook-chunk-VDXQXYJK.mjs → token-goat-hook-chunk-NXVT4F3S.mjs} +817 -53
  21. package/dist/{token-goat-hook-chunk-EKGDLI4D.mjs → token-goat-hook-chunk-VU6VGZBM.mjs} +16 -14
  22. package/dist/{token-goat-hook-chunk-UWV4MTYI.mjs → token-goat-hook-chunk-XM4W3WCO.mjs} +704 -138
  23. package/dist/token-goat-hook.mjs +5 -5
  24. package/dist/token-goat.core.mjs +5 -5
  25. package/package.json +11 -10
@@ -76,13 +76,15 @@ import {
76
76
  runSymbol,
77
77
  runTestFor,
78
78
  runTypes,
79
+ runXmlOutline,
80
+ runXmlQuery,
79
81
  runYamlOutline,
80
82
  runYamlQuery,
81
83
  runZipList,
82
84
  runZipRead,
83
85
  symbolNamesInFile,
84
86
  upsertNote
85
- } from "./token-goat-hook-chunk-VDXQXYJK.mjs";
87
+ } from "./token-goat-hook-chunk-NXVT4F3S.mjs";
86
88
  import {
87
89
  BASH_OUTPUT_SUBDIR,
88
90
  GEMINI_TOOL_NAME_MAP,
@@ -103,7 +105,7 @@ import {
103
105
  readStdinJson,
104
106
  searchRecall,
105
107
  storeWebOutput
106
- } from "./token-goat-hook-chunk-ZT47M3IA.mjs";
108
+ } from "./token-goat-hook-chunk-CRBMPT74.mjs";
107
109
  import {
108
110
  AGENT_SALT_MARKER,
109
111
  CONTEXT_AUTOCOMPACT_TOKENS,
@@ -149,6 +151,7 @@ import {
149
151
  findLatestSessionId,
150
152
  findMemSuggestionCandidates,
151
153
  findMemoryMd,
154
+ findOrphanedChunkPaths,
152
155
  findStrayClaudeMdBlocks,
153
156
  findSystemTempFiles,
154
157
  formatAge,
@@ -170,6 +173,7 @@ import {
170
173
  incrementSkillHit,
171
174
  indexFileEmbeddings,
172
175
  indexFileSync,
176
+ indexedPathSpellingIsStale,
173
177
  installClaudeMd,
174
178
  installCodex,
175
179
  installCopilotCli,
@@ -207,6 +211,7 @@ import {
207
211
  pruneBlobs,
208
212
  pruneBlockedRoot,
209
213
  pruneDeletedFiles,
214
+ pruneOrphanedChunks,
210
215
  pruneSkillOutputs,
211
216
  pruneSystemTempFiles,
212
217
  querySheet,
@@ -238,7 +243,7 @@ import {
238
243
  vscodeDecoderConfigured,
239
244
  walkProject,
240
245
  writeCompact
241
- } from "./token-goat-hook-chunk-UWV4MTYI.mjs";
246
+ } from "./token-goat-hook-chunk-XM4W3WCO.mjs";
242
247
  import {
243
248
  C,
244
249
  CONFIG_KEY_ENV_OVERRIDES,
@@ -255,13 +260,17 @@ import {
255
260
  configPath,
256
261
  countNoun,
257
262
  dataDir,
263
+ decodeSource,
258
264
  defaultConfig,
259
265
  detectLanguage,
266
+ detectSourceEncoding,
267
+ encodeSource,
260
268
  ensureDirSync,
261
269
  ensureNewline,
262
270
  escapeRegExp,
263
271
  extractErrorMessage,
264
272
  fg,
273
+ fileIsAbsent,
265
274
  findProject,
266
275
  fingerprintContent,
267
276
  fingerprintFile,
@@ -313,7 +322,7 @@ import {
313
322
  withFileLock,
314
323
  withRetryOnLock,
315
324
  writeJsonSettings
316
- } from "./token-goat-hook-chunk-E6AIPKNF.mjs";
325
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
317
326
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
318
327
  import {
319
328
  __export
@@ -5460,7 +5469,7 @@ function purgeRoots() {
5460
5469
  function purgeDataDirectories() {
5461
5470
  const result = { removed: [], absent: [], failed: [] };
5462
5471
  for (const root of purgeRoots()) {
5463
- if (!fs10.existsSync(root)) {
5472
+ if (fileIsAbsent(root)) {
5464
5473
  result.absent.push(root);
5465
5474
  continue;
5466
5475
  }
@@ -6140,7 +6149,7 @@ async function runDoctorAndExit(opts) {
6140
6149
  }
6141
6150
 
6142
6151
  // src/webfetch.ts
6143
- import { existsSync as existsSync8, readdirSync as readdirSync5, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
6152
+ import { existsSync as existsSync7, readdirSync as readdirSync5, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
6144
6153
  import * as http from "http";
6145
6154
  import * as https from "https";
6146
6155
  import { isIPv4, isIPv6 } from "net";
@@ -6327,7 +6336,7 @@ function isPrivateIPv6(ip) {
6327
6336
  var STALE_DOWNLOAD_AGE_MS = 10 * 60 * 1e3;
6328
6337
  function cleanupStaleDownloads() {
6329
6338
  const cacheDir = webCacheDir();
6330
- if (!existsSync8(cacheDir)) return 0;
6339
+ if (!existsSync7(cacheDir)) return 0;
6331
6340
  let removed = 0;
6332
6341
  try {
6333
6342
  const files = readdirSync5(cacheDir);
@@ -8719,7 +8728,7 @@ function collectFiles(projectRoot, patterns, opts = {}) {
8719
8728
  }
8720
8729
  let content;
8721
8730
  try {
8722
- content = redactIfDotenv(p, fs13.readFileSync(fd, "utf8"));
8731
+ content = redactIfDotenv(p, decodeSource(fs13.readFileSync(fd)));
8723
8732
  } catch {
8724
8733
  result.skipped.push(`${rel} (unreadable)`);
8725
8734
  continue;
@@ -9526,7 +9535,7 @@ function isMarkerOccurrence(matched, hasColon) {
9526
9535
  function scanFileForTodos(filePath, kindSet) {
9527
9536
  let text;
9528
9537
  try {
9529
- text = fs16.readFileSync(filePath, "utf8");
9538
+ text = decodeSource(fs16.readFileSync(filePath));
9530
9539
  } catch {
9531
9540
  return [];
9532
9541
  }
@@ -11834,9 +11843,10 @@ function cmdProject(opts) {
11834
11843
  const removed = before.length - after.length;
11835
11844
  const stale = before.filter((r) => !after.includes(r));
11836
11845
  const staleTempFiles = findSystemTempFiles();
11846
+ const orphanChunkPaths = findOrphanedChunkPaths();
11837
11847
  if (opts.dryRun === true) {
11838
11848
  if (opts.json === true) {
11839
- emit(JSON.stringify({ dryRun: true, wouldPrune: removed, stale, wouldPruneTempFiles: staleTempFiles.length, staleTempFiles, blocked_roots: before }, null, 2));
11849
+ emit(JSON.stringify({ dryRun: true, wouldPrune: removed, stale, wouldPruneTempFiles: staleTempFiles.length, staleTempFiles, wouldPruneOrphanChunkFiles: orphanChunkPaths.length, orphanChunkPaths, blocked_roots: before }, null, 2));
11840
11850
  return;
11841
11851
  }
11842
11852
  if (removed === 0) {
@@ -11851,18 +11861,26 @@ function cmdProject(opts) {
11851
11861
  emit(`Would prune ${staleTempFiles.length} stale indexed temp-dir file(s):`);
11852
11862
  for (const p of staleTempFiles) emit(` ${p}`);
11853
11863
  }
11864
+ if (orphanChunkPaths.length === 0) {
11865
+ emit("Would prune 0 orphaned embedding chunk file(s). Nothing to do.");
11866
+ } else {
11867
+ emit(`Would prune orphaned embedding chunks for ${orphanChunkPaths.length} file(s):`);
11868
+ for (const p of orphanChunkPaths) emit(` ${p}`);
11869
+ }
11854
11870
  return;
11855
11871
  }
11856
11872
  cfg.worker.blocked_roots = after;
11857
11873
  saveConfigSafe(cfg);
11858
11874
  invalidateConfigCache();
11859
11875
  const prunedTempFiles = pruneSystemTempFiles();
11876
+ const prunedOrphanChunks = pruneOrphanedChunks();
11860
11877
  if (opts.json === true) {
11861
- emit(JSON.stringify({ pruned: removed, blocked_roots: after, prunedTempFiles: prunedTempFiles.length }, null, 2));
11878
+ emit(JSON.stringify({ pruned: removed, blocked_roots: after, prunedTempFiles: prunedTempFiles.length, prunedOrphanChunkFiles: prunedOrphanChunks.length }, null, 2));
11862
11879
  return;
11863
11880
  }
11864
11881
  emit(`Pruned ${removed} stale root(s). Remaining: ${after.length}`);
11865
11882
  emit(`Pruned ${prunedTempFiles.length} stale indexed temp-dir file(s).`);
11883
+ emit(`Pruned orphaned embedding chunks for ${prunedOrphanChunks.length} file(s).`);
11866
11884
  return;
11867
11885
  }
11868
11886
  emitErr2(`project: unknown action '${action}'. Use list, exclude, or prune.`);
@@ -13047,15 +13065,19 @@ function formatSpentCell(row) {
13047
13065
  if (row.bytesEmitted === null) return "n/a (legacy)";
13048
13066
  return row.legacyEmissions > 0 ? `${row.bytesEmitted} (${row.legacyEmissions} legacy)` : String(row.bytesEmitted);
13049
13067
  }
13068
+ function suppressedCell(row) {
13069
+ if (!row.suppressed) return "no";
13070
+ return row.suppressionPermanent ? "yes (permanent)" : "yes";
13071
+ }
13050
13072
  function printSummary(rows) {
13051
13073
  const w = (text) => {
13052
13074
  process.stdout.write(text);
13053
13075
  };
13054
- w(pad("category", 22) + pad("emitted", 9) + pad("acted-on", 10) + pad("efficacy", 10) + pad("suppressed", 12) + pad("manual+", 9) + pad("manual-", 9) + "spent\n");
13076
+ w(pad("category", 22) + pad("emitted", 9) + pad("acted-on", 10) + pad("efficacy", 10) + pad("suppressed", 17) + pad("manual+", 9) + pad("manual-", 9) + "spent\n");
13055
13077
  for (const row of rows) {
13056
13078
  const pct = row.efficacyPct === null ? "n/a" : `${row.efficacyPct}%`;
13057
13079
  w(
13058
- pad(row.category, 22) + pad(String(row.emitted), 9) + pad(String(row.actedOn), 10) + pad(pct, 10) + pad(row.suppressed ? "yes" : "no", 12) + pad(String(row.manualEffective), 9) + pad(String(row.manualIneffective), 9) + formatSpentCell(row) + "\n"
13080
+ pad(row.category, 22) + pad(String(row.emitted), 9) + pad(String(row.actedOn), 10) + pad(pct, 10) + pad(suppressedCell(row), 17) + pad(String(row.manualEffective), 9) + pad(String(row.manualIneffective), 9) + formatSpentCell(row) + "\n"
13059
13081
  );
13060
13082
  }
13061
13083
  }
@@ -13095,6 +13117,13 @@ function runHintStatsCommand(opts = {}) {
13095
13117
  process.stdout.write("No hint emissions recorded yet \u2014 the zeros below are absence of data, not measured ineffectiveness.\n");
13096
13118
  }
13097
13119
  printSummary(rows);
13120
+ const permanent = rows.filter((r) => r.suppressionPermanent);
13121
+ if (permanent.length > 0) {
13122
+ const names = permanent.map((r) => r.category).join(", ");
13123
+ process.stdout.write(`
13124
+ hints.backoff_thresholds is empty, so suppression here is permanent rather than a self-healing throttle: ${names} will not emit again on any occasion. Set backoff_thresholds to re-enable probe emissions, or run \`token-goat hint-stats --reset\` to clear the ledger.
13125
+ `);
13126
+ }
13098
13127
  printTotals(getHintStatsTotals());
13099
13128
  }
13100
13129
 
@@ -13334,7 +13363,8 @@ async function cmdIndex(pathArg, opts = {}) {
13334
13363
  const sha = fingerprintFile(key);
13335
13364
  if (sha === null && !fs26.existsSync(key)) continue;
13336
13365
  const entry = sha !== null ? getFileEntry(key, dbPath) : null;
13337
- const parseUnchanged = !force && sha !== null && entry?.sha === sha;
13366
+ const spellingStale = entry !== null && indexedPathSpellingIsStale(entry.filePath, key);
13367
+ const parseUnchanged = !force && !spellingStale && sha !== null && entry?.sha === sha;
13338
13368
  const embeddingsEnabled = loadConfig().indexing?.embeddings_enabled ?? true;
13339
13369
  const depsAvailable = embeddingsEnabled && embeddingsDepsAvailable(getDb(dbPath));
13340
13370
  const embedUnchanged = !force && parseUnchanged && sha !== null && isEmbedFresh(entry?.embedSha, sha, embeddingsEnabled, depsAvailable);
@@ -13417,7 +13447,7 @@ async function cmdMcpServe() {
13417
13447
  let StdioServerTransport;
13418
13448
  try {
13419
13449
  ;
13420
- ({ createMcpServer } = await import("./token-goat-hook-chunk-EKGDLI4D.mjs"));
13450
+ ({ createMcpServer } = await import("./token-goat-hook-chunk-VU6VGZBM.mjs"));
13421
13451
  ({ StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"));
13422
13452
  } catch (err2) {
13423
13453
  process.stderr.write(
@@ -13438,7 +13468,7 @@ async function cmdHook(event, opts) {
13438
13468
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
13439
13469
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
13440
13470
  }
13441
- const { relay } = await import("./token-goat-hook-chunk-XBOWDNJB.mjs");
13471
+ const { relay } = await import("./token-goat-hook-chunk-J4HKWUWZ.mjs");
13442
13472
  await relay(event);
13443
13473
  }
13444
13474
  async function cmdInstall(opts) {
@@ -13902,7 +13932,7 @@ function cmdBashOutput(id, opts) {
13902
13932
  if (st.isFIFO() || st.isSocket()) {
13903
13933
  throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
13904
13934
  }
13905
- content = redactIfDotenv(opts.file, fs26.readFileSync(opts.file, "utf-8"));
13935
+ content = redactIfDotenv(opts.file, decodeSource(fs26.readFileSync(opts.file)));
13906
13936
  } catch (e) {
13907
13937
  if (e instanceof CliError) throw e;
13908
13938
  throw new CliError(`cannot read file: ${opts.file}`);
@@ -14217,6 +14247,16 @@ function cmdYamlOutline(file, opts) {
14217
14247
  function cmdYamlQuery(file, yamlPath, opts) {
14218
14248
  process.exitCode = runYamlQuery({ file, path: yamlPath, ...opts });
14219
14249
  }
14250
+ function cmdXmlOutline(file, opts) {
14251
+ process.exitCode = runXmlOutline({
14252
+ file,
14253
+ ...opts.json === true ? { json: true } : {},
14254
+ ...opts.maxDepth !== void 0 ? { maxDepth: requireNonNegativeInt("--max-depth", opts.maxDepth) } : {}
14255
+ });
14256
+ }
14257
+ function cmdXmlQuery(file, xmlPath, opts) {
14258
+ process.exitCode = runXmlQuery({ file, path: xmlPath, ...opts });
14259
+ }
14220
14260
  function cmdOpenApiOutline(file, opts) {
14221
14261
  process.exitCode = runOpenApiOutline({ file, ...opts });
14222
14262
  }
@@ -14285,7 +14325,7 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
14285
14325
  }
14286
14326
  async function cmdCompress(opts) {
14287
14327
  try {
14288
- const bashRunner = await import("./token-goat-hook-chunk-26DLRODR.mjs");
14328
+ const bashRunner = await import("./token-goat-hook-chunk-D6UJEFHX.mjs");
14289
14329
  if (opts.compress === false) {
14290
14330
  process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
14291
14331
  return;
@@ -14311,7 +14351,7 @@ async function cmdSkillBody(name, opts) {
14311
14351
  if (filePath === null) {
14312
14352
  throw new CliError(`skill '${name}' not found`);
14313
14353
  }
14314
- const body = fs26.readFileSync(filePath, "utf-8");
14354
+ const body = decodeSource(fs26.readFileSync(filePath));
14315
14355
  if (opts.compact === true) {
14316
14356
  out(extractCompactFromMarker(body) ?? body);
14317
14357
  } else {
@@ -14328,7 +14368,7 @@ async function cmdSkillCompact(name, opts) {
14328
14368
  for (const skill of skills) {
14329
14369
  const filePath = await getSkillFilePath(skill.name);
14330
14370
  if (!filePath) continue;
14331
- const body2 = fs26.readFileSync(filePath, "utf-8");
14371
+ const body2 = decodeSource(fs26.readFileSync(filePath));
14332
14372
  const compact2 = extractCompactFromMarker(body2);
14333
14373
  if (compact2 === null) continue;
14334
14374
  const sourceSha2 = contentHash(body2);
@@ -14532,7 +14572,7 @@ async function cmdSkillSection(nameHeading, headingArg) {
14532
14572
  if (!filePath) {
14533
14573
  throw new CliError(`skill '${skillName}' not found`);
14534
14574
  }
14535
- const body = fs26.readFileSync(filePath, "utf-8");
14575
+ const body = decodeSource(fs26.readFileSync(filePath));
14536
14576
  const extracted = extractNamedSection(body, heading);
14537
14577
  if (!extracted) {
14538
14578
  process.exitCode = 1;
@@ -14963,7 +15003,13 @@ function writeReplacedBuffer(file, replacedBuf, preWriteStat) {
14963
15003
  const testDelayMs = Number(process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_MS"] ?? "");
14964
15004
  if (Number.isFinite(testDelayMs) && testDelayMs > 0) {
14965
15005
  process.stderr.write("TOKEN_GOAT_TEST_REPLACE_DELAY_READY\n");
14966
- sleepSync(testDelayMs);
15006
+ const until = process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_UNTIL"];
15007
+ const deadline = Date.now() + testDelayMs;
15008
+ if (until !== void 0 && until !== "") {
15009
+ while (Date.now() < deadline && !fs26.existsSync(until)) sleepSync(5);
15010
+ } else {
15011
+ sleepSync(testDelayMs);
15012
+ }
14967
15013
  }
14968
15014
  let preRenameStat;
14969
15015
  try {
@@ -15114,13 +15160,14 @@ function cmdInsertSection(file, opts) {
15114
15160
  else if (allHeadings.length > 0) messages.push(`Try: token-goat outline ${file}`);
15115
15161
  throw new CliError(messages.join("\n"));
15116
15162
  }
15117
- let rawText;
15163
+ let rawBytes;
15118
15164
  try {
15119
- rawText = fs26.readFileSync(file, "utf-8");
15165
+ rawBytes = fs26.readFileSync(file);
15120
15166
  } catch (e) {
15121
15167
  mapFsError(e, void 0, file);
15122
15168
  }
15123
- if (rawText.charCodeAt(0) === 65279) rawText = rawText.slice(1);
15169
+ const sourceEncoding = detectSourceEncoding(rawBytes);
15170
+ const rawText = decodeSource(rawBytes);
15124
15171
  const eol = detectDominantEol(Buffer.from(rawText, "utf8"));
15125
15172
  const lfLines = rawText.replace(/\r\n/g, "\n").split("\n");
15126
15173
  const insertAt = result.lineEnd;
@@ -15139,7 +15186,7 @@ function cmdInsertSection(file, opts) {
15139
15186
  }
15140
15187
  }
15141
15188
  try {
15142
- atomicWriteBuffer(file, Buffer.from(mergedText, "utf8"));
15189
+ atomicWriteBuffer(file, encodeSource(mergedText, sourceEncoding));
15143
15190
  } catch (e) {
15144
15191
  mapFsError(e, void 0, file);
15145
15192
  }
@@ -15810,6 +15857,10 @@ function buildProgram() {
15810
15857
  program2.command("yaml-query <file> <path>").description(
15811
15858
  "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]"
15812
15859
  ).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));
15860
+ 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));
15861
+ program2.command("xml-query <file> <path>").description(
15862
+ "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"
15863
+ ).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));
15813
15864
  program2.command("openapi-outline <file>").description("per-operation listing (method, path, operationId, summary, tags) of an OpenAPI 3.x / Swagger 2.0 spec (JSON or YAML) instead of a raw Read").option("--json", "emit the operation list as JSON instead of text").action(guard(cmdOpenApiOutline));
15814
15865
  program2.command("openapi-op <file> <operation>").description(
15815
15866
  'full detail (parameters, request body schema, response schemas, description) for exactly one OpenAPI operation instead of a raw Read\n\noperation may be an operationId (exact match) or a "METHOD path" spec, e.g. "GET /users/{id}"'