token-goat 2.9.12 → 2.9.13

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 +7 -1
  2. package/dist/{token-goat-chunk-6NIGPPN6.mjs → token-goat-chunk-2WC4ZUXN.mjs} +1 -1
  3. package/dist/{token-goat-chunk-GCXX67HM.mjs → token-goat-chunk-3ESRORNM.mjs} +188 -97
  4. package/dist/token-goat-chunk-4NXUKV7D.mjs +56 -0
  5. package/dist/{token-goat-chunk-OTW7LC4Y.mjs → token-goat-chunk-6B44WLIF.mjs} +5 -5
  6. package/dist/{token-goat-chunk-6F5TLJC7.mjs → token-goat-chunk-B3CTCQTH.mjs} +1 -1
  7. package/dist/{token-goat-chunk-A6QTLAWO.mjs → token-goat-chunk-FQCNJV4V.mjs} +20 -6
  8. package/dist/{token-goat-chunk-SBYRP3X4.mjs → token-goat-chunk-FZU7GMUS.mjs} +49 -24
  9. package/dist/{token-goat-chunk-TOGYS5A7.mjs → token-goat-chunk-JOXLE672.mjs} +344 -5699
  10. package/dist/{token-goat-chunk-HKFOH6JH.mjs → token-goat-chunk-JVNPCQB7.mjs} +10 -7
  11. package/dist/{token-goat-chunk-LHLQFGWQ.mjs → token-goat-chunk-OMNQUUIT.mjs} +9 -27
  12. package/dist/{token-goat-chunk-VRWX6QYW.mjs → token-goat-chunk-P2PU4CR5.mjs} +8 -6
  13. package/dist/{token-goat-chunk-LOCOX2ML.mjs → token-goat-chunk-QKXBGBQR.mjs} +110 -21
  14. package/dist/{token-goat-chunk-THLHC6QJ.mjs → token-goat-chunk-QWSUZWFP.mjs} +44 -33
  15. package/dist/{token-goat-chunk-SF2CKCFQ.mjs → token-goat-chunk-RDITECDL.mjs} +7 -5
  16. package/dist/{token-goat-chunk-4CK445AW.mjs → token-goat-chunk-U7X6LQD2.mjs} +271 -69
  17. package/dist/token-goat-chunk-UM47DRD3.mjs +242 -0
  18. package/dist/token-goat-chunk-UMXJN7DI.mjs +5521 -0
  19. package/dist/token-goat-chunk-YOA4N6WA.mjs +308 -0
  20. package/dist/{token-goat-chunk-GM6QZWCF.mjs → token-goat-chunk-ZZI3IDQZ.mjs} +963 -966
  21. package/dist/token-goat-hook.mjs +8 -6
  22. package/dist/token-goat.core.mjs +10 -7
  23. package/docs/cli.md +11 -8
  24. package/docs/security.md +1 -1
  25. package/package.json +1 -1
package/README.md CHANGED
@@ -117,7 +117,11 @@ The fastest way to reduce AI token costs is fixing these five, not writing short
117
117
  | Subagent reads a ≥30 KB markdown file whole, on its first look at it | Off by default. Set `subagent_markdown_first_read_deny = true` under `[hints]` to block that read and answer with the heading tree instead. Only fires in a subagent, only on a first, un-ranged read of a `.md`/`.mdx`/`.markdown` file with at least three headings; a read that already asks for a line range, and every main-session read, pass through untouched |
118
118
  | A source file is read whole for the first time, with no earlier copy to compare it against | Keeps each function's declaration and its first eight lines, replacing the rest with one line naming the symbol, the exact range removed, and the command that returns it. Set `fold_code_bodies = false` under `[hints]` to turn it off. Comment blocks of twelve lines or more fold to their first two on the same terms. Imports, signatures, type declarations, classes and interfaces are never folded, and a file whose index no longer matches what is on disk keeps its bodies. Measured on this repository's own source: 229 of 256 files fold, and 43% of what a read of them delivers is removed. A read that already names an offset or a limit, and any file holding something that looks like a secret, pass through untouched |
119
119
  | PDF opened via Read | Full read denied; PDF shows page count and outline (`token-goat pdf-extract` pulls the actual text, optionally paged/sliced, when the outline isn't enough) |
120
- | Excel/PowerPoint/Word file (.xlsx/.pptx/.docx) opened via Read | Full read denied; redirects to the matching narrow-slice command family (`xlsx-sheets`/`xlsx-head`/`xlsx-range`/`xlsx-query`, `pptx-outline`/`pptx-slide`/`pptx-notes`/`pptx-text`, `docx-outline`/`docx-text`) instead of extracting the whole document as text |
120
+ | Excel/PowerPoint/Word file (.xlsx/.pptx/.docx) opened via Read | Full read denied; redirects to the matching narrow-slice command family (`xlsx-sheets`/`xlsx-columns`/`xlsx-head`/`xlsx-range`/`xlsx-query`, `pptx-outline`/`pptx-slide`/`pptx-notes`/`pptx-text`, `docx-outline`/`docx-tables`/`docx-text`) instead of extracting the whole document as text |
121
+ | SQLite database (.db, .sqlite, .sqlite3, .db3) opened via Read | Full read denied; redirects to the SQLite narrow-slice family (`sqlite-tables`/`sqlite-schema`/`sqlite-query`) instead of reading binary bytes into context |
122
+ | Parquet file (.parquet) opened via Read | Full read denied; redirects to DuckDB for SQL querying instead of reading binary columnar data |
123
+ | Large JSON or YAML file (≥20 KB) read in full | Top-level keys or array summary previewed; redirects to `json-outline`/`json-query` or `yaml-outline`/`yaml-query` instead of blowing context on multi-megabyte payloads |
124
+ | Large JSON Lines file (.jsonl ≥20 KB) read in full | Record count and first-record schema shown; suggests slicing records with offset/limit instead of loading millions of tokens |
121
125
  | Other Office binary (.odt, .ods, .ott, .odp) opened via Read | Full read denied; redirects to `pandoc` for text extraction (no dedicated reader for these formats yet) |
122
126
  | Large CSV or TSV file (≥10 KB) read in full | Column headers, row count, and 3 sample rows shown; `token-goat csv-query` projects columns and/or filters rows instead of a full read; `duckdb` query suggestion for very large tabular data |
123
127
  | WebFetch returns a page's full raw HTML | HTML-to-text extraction strips markup/scripts/styles before the model ever sees it — readable prose instead of a wall of tags |
@@ -519,6 +523,8 @@ The pipeline is written in TypeScript and decodes PNG, JPEG, GIF, and BMP itself
519
523
 
520
524
  The one thing the decoders will do is decline. A file whose header asks for more than 256 MB of pixel buffer, or that is in a variant token-goat cannot read exactly, is refused rather than guessed at, and the untouched original goes to the model. An untouched original is the right picture, so the only cost of a refusal is that the read is not shrunk.
521
525
 
526
+ When `tesseract.js` is installed, text-heavy images can also have their text extracted via OCR (`token-goat image-text <file>`) to replace raw pixel data with plain text. English (`eng`) is always enabled by default, and users can combine one or more additional languages (`token-goat image-text <file> --lang "fra,spa"`). Language preferences persist across version updates when saved globally (`token-goat config set image_shrink.ocr_lang "fra,spa"`), per-project in `.token-goat.toml` (`[image_shrink] ocr_lang = "fra+spa"`), or via `TOKEN_GOAT_OCR_LANG`. 16 languages are supported (`eng`, `fra`, `spa`, `deu`, `ita`, `por`, `nld`, `pol`, `rus`, `tur`, `swe`, `ara`, `chi_sim`, `chi_tra`, `jpn`, `kor`), each cryptographically verified against pinned package checksums to protect against supply-chain tampering.
527
+
522
528
  ## Stats display
523
529
 
524
530
  `token-goat stats` uses 24-bit ANSI color and Unicode block characters for gradient bars, sparklines, and the activity heatmap. In the right terminal it renders sharply. In the wrong one you get broken characters, flat gray blocks, or a "rich is not installed" error.
@@ -2,7 +2,7 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  detectHarness
5
- } from "./token-goat-chunk-TOGYS5A7.mjs";
5
+ } from "./token-goat-chunk-UMXJN7DI.mjs";
6
6
  import {
7
7
  init_define_import_meta_env
8
8
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -1,5 +1,25 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ DEFAULT_RECONCILE_BUDGET_MS,
5
+ HOOK_EVENTS,
6
+ WEB_OUTPUT_SUBDIR,
7
+ accumulateResidentLine,
8
+ buildCommandManifest,
9
+ checkSymbolBodySize,
10
+ createResidentContextStats,
11
+ filterCommandManifest,
12
+ formatBytes,
13
+ formatCommandManifest,
14
+ formatTokenEstimate,
15
+ getWebOutput,
16
+ getWebOutputByUrlFromDisk,
17
+ getWebOutputRaw,
18
+ readStdinJson,
19
+ runReconcile,
20
+ storeWebOutput,
21
+ summarizeResidentContext
22
+ } from "./token-goat-chunk-FQCNJV4V.mjs";
3
23
  import {
4
24
  ALL_SYMBOLS_IN_FILE_LIMIT,
5
25
  AMBIGUOUS_HEADING_LIMIT,
@@ -15,6 +35,7 @@ import {
15
35
  extractTranscriptText,
16
36
  filterSimilarHeadings,
17
37
  findSpecSeparator,
38
+ guardJsonRows,
18
39
  healStaleIndex,
19
40
  isAvailable as isAvailable2,
20
41
  load,
@@ -75,6 +96,7 @@ import {
75
96
  runSkeleton,
76
97
  runSqliteQuery,
77
98
  runSqliteSchema,
99
+ runSqliteTables,
78
100
  runSymbol,
79
101
  runTestFor,
80
102
  runTypes,
@@ -87,33 +109,11 @@ import {
87
109
  symbolNamesInFile,
88
110
  upsertNote,
89
111
  warnIfFilesStale
90
- } from "./token-goat-chunk-4CK445AW.mjs";
91
- import {
92
- DEFAULT_RECONCILE_BUDGET_MS,
93
- HOOK_EVENTS,
94
- WEB_OUTPUT_SUBDIR,
95
- accumulateResidentLine,
96
- buildCommandManifest,
97
- checkSymbolBodySize,
98
- createResidentContextStats,
99
- filterCommandManifest,
100
- formatBytes,
101
- formatCommandManifest,
102
- formatTokenEstimate,
103
- getWebOutput,
104
- getWebOutputByUrlFromDisk,
105
- getWebOutputRaw,
106
- readStdinJson,
107
- runReconcile,
108
- storeWebOutput,
109
- summarizeResidentContext
110
- } from "./token-goat-chunk-A6QTLAWO.mjs";
112
+ } from "./token-goat-chunk-U7X6LQD2.mjs";
111
113
  import {
112
114
  AGENT_SALT_MARKER,
113
115
  BASH_OUTPUT_SUBDIR,
114
116
  CONTEXT_AUTOCOMPACT_TOKENS,
115
- DEFAULT_MAX_AGE_MS,
116
- DEFAULT_MAX_COUNT,
117
117
  MAX_FILES_SCANNED,
118
118
  PARSER_FINGERPRINT,
119
119
  RECALL_DEFAULT_LIMIT,
@@ -137,6 +137,7 @@ import {
137
137
  detectWalkMode,
138
138
  dirtyQueuePathFor,
139
139
  docxOutline,
140
+ docxTables,
140
141
  docxText,
141
142
  drainHeartbeatPathFor,
142
143
  embeddingBackendLoadError,
@@ -158,8 +159,10 @@ import {
158
159
  findSystemTempFiles,
159
160
  formatAge,
160
161
  formatCsvTable,
162
+ formatDocxTables,
161
163
  formatMemSuggestions,
162
164
  formatProjectMap,
165
+ formatXlsxColumns,
163
166
  formatXlsxRange,
164
167
  getBashOutput,
165
168
  getContextPressure,
@@ -192,13 +195,11 @@ import {
192
195
  isSuppressionCategory,
193
196
  isTreeSitterAvailable,
194
197
  isWorkerRunning,
195
- listBlobs,
196
198
  listOutputs,
197
199
  listRecentRecall,
198
200
  listSections,
199
201
  listSheets,
200
202
  listSkills,
201
- loadBlob,
202
203
  loadRegexExtractors,
203
204
  loadSessionCache,
204
205
  mapLookupBytesSaved,
@@ -211,7 +212,6 @@ import {
211
212
  pptxOutline,
212
213
  pptxSlideText,
213
214
  pptxTextGrep,
214
- pruneBlobs,
215
215
  pruneBlockedRoot,
216
216
  pruneDeletedFiles,
217
217
  pruneOrphanedChunks,
@@ -239,56 +239,32 @@ import {
239
239
  urlPolicyDenialReason,
240
240
  visionTokensSavedByText,
241
241
  walkProject,
242
- writeCompact
243
- } from "./token-goat-chunk-GM6QZWCF.mjs";
242
+ writeCompact,
243
+ xlsxColumns
244
+ } from "./token-goat-chunk-ZZI3IDQZ.mjs";
244
245
  import {
245
- C,
246
- CONFIG_KEY_ENV_OVERRIDES,
247
246
  CompressedOutput,
248
247
  FILTERS,
249
248
  GEMINI_TOOL_NAME_MAP,
250
249
  HOOKS_SCRIPT_FILE,
251
250
  MATERIALIZE_SHRUNK_IMAGE_JS,
252
- PROJECT_LOCKED_KEYS,
253
- PROJECT_LOCKED_SECTIONS,
254
- RESET,
255
251
  TOOL_FILTERS,
256
- TREE_SITTER_LANGUAGES,
257
252
  ToolFilter,
258
- _useRichStats,
259
253
  anchoredMarkerPattern,
260
254
  bundledCliPath,
261
255
  capJsonRows,
262
256
  clipLongMatchLine,
263
- colorStdout,
264
257
  combineStreams,
265
- compileCustomPatterns,
266
258
  copilotCliConfigPath,
267
259
  copilotCliMcpToolsDir,
268
260
  copilotCliScriptPath,
269
261
  copilotCliUserRoot,
270
- defaultConfig,
271
262
  deliverCompressed,
272
263
  detectFromCommand,
273
- detectLanguage,
274
- detectLanguageOfFile,
275
264
  dropEmptyServers,
276
- envBool,
277
265
  estimateTokens,
278
266
  estimateTokensFromLength,
279
- fenceFor,
280
- fg,
281
- fileIsAbsent,
282
- findProject,
283
267
  findStrayClaudeMdBlocks,
284
- fingerprintContent,
285
- fingerprintFile,
286
- formatLocalTimestamp,
287
- getDb,
288
- getDisplayRoot,
289
- getLastConfigParseError,
290
- getLastProjectConfigParseError,
291
- getProjectConfigInfo,
292
268
  groupHasTokenGoat,
293
269
  hasManagedServer,
294
270
  installClaudeMd,
@@ -300,38 +276,18 @@ import {
300
276
  installSkill,
301
277
  installVisualStudio,
302
278
  installVscode,
303
- invalidateConfigCache,
304
279
  isCodexInstalled,
305
280
  isCopilotCliInstalled,
306
- isDotenvPath,
307
281
  isGrokInstalled,
308
282
  isInstalled,
309
283
  isKimiInstalled,
310
284
  isVisualStudioInstalled,
311
- lastProjectConfigLockedKeys,
312
- loadConfig,
313
- loadPersistedConfig,
314
- nonTreeSitterLanguageCount,
315
285
  otherScopeHasManagedServer,
316
- parse,
317
- readConfigSource,
318
286
  readCopilotMcpTools,
319
287
  readServersJson,
320
- readUnmappedTools,
321
- recordStat,
322
- redactIfDotenv,
323
- redactSecrets,
324
- renderShortStats,
325
- renderStats,
326
- resolveConfigKeyLayer,
327
- resolveProjectRoot,
328
- saveConfig,
329
- savedTokensFromBytes,
330
288
  serversOf,
331
289
  setTokenGoatServer,
332
290
  settingsPath,
333
- stripAnsi,
334
- summarize,
335
291
  toolMatcherFor,
336
292
  trimToBudget,
337
293
  uninstallClaudeMd,
@@ -343,8 +299,6 @@ import {
343
299
  uninstallSkill,
344
300
  uninstallVisualStudio,
345
301
  uninstallVscode,
346
- validateEnumField,
347
- validateNumericField,
348
302
  visualStudioDuplicateNote,
349
303
  visualStudioManagedEntry,
350
304
  visualStudioMcpStatus,
@@ -356,7 +310,65 @@ import {
356
310
  vscodeHooksInstalled,
357
311
  vscodeScopeFromFlags,
358
312
  vscodeUsesClaudeHooks
359
- } from "./token-goat-chunk-TOGYS5A7.mjs";
313
+ } from "./token-goat-chunk-JOXLE672.mjs";
314
+ import {
315
+ DEFAULT_MAX_AGE_MS,
316
+ DEFAULT_MAX_COUNT,
317
+ listBlobs,
318
+ loadBlob,
319
+ pruneBlobs
320
+ } from "./token-goat-chunk-UM47DRD3.mjs";
321
+ import {
322
+ C,
323
+ CONFIG_KEY_ENV_OVERRIDES,
324
+ PROJECT_LOCKED_KEYS,
325
+ PROJECT_LOCKED_SECTIONS,
326
+ RESET,
327
+ SUPPORTED_OCR_LANG_CODES,
328
+ TREE_SITTER_LANGUAGES,
329
+ _useRichStats,
330
+ colorStdout,
331
+ compileCustomPatterns,
332
+ defaultConfig,
333
+ detectLanguage,
334
+ detectLanguageOfFile,
335
+ envBool,
336
+ fenceFor,
337
+ fg,
338
+ fileIsAbsent,
339
+ findProject,
340
+ fingerprintContent,
341
+ fingerprintFile,
342
+ formatLocalTimestamp,
343
+ getDb,
344
+ getDisplayRoot,
345
+ getLastConfigParseError,
346
+ getLastProjectConfigParseError,
347
+ getProjectConfigInfo,
348
+ invalidateConfigCache,
349
+ isDotenvPath,
350
+ isSupportedOcrLang,
351
+ lastProjectConfigLockedKeys,
352
+ loadConfig,
353
+ loadPersistedConfig,
354
+ nonTreeSitterLanguageCount,
355
+ parse,
356
+ readConfigSource,
357
+ readUnmappedTools,
358
+ recordStat,
359
+ redactIfDotenv,
360
+ redactSecrets,
361
+ renderShortStats,
362
+ renderStats,
363
+ resolveConfigKeyLayer,
364
+ resolveProjectRoot,
365
+ saveConfig,
366
+ savedTokensFromBytes,
367
+ stripAnsi,
368
+ summarize,
369
+ validateEnumField,
370
+ validateNumericField
371
+ } from "./token-goat-chunk-UMXJN7DI.mjs";
360
372
  import {
361
373
  ENV_KEYS,
362
374
  LOCK_WAIT_MS_HARDENED,
@@ -387,6 +399,7 @@ import {
387
399
  fenceUntrustedContent,
388
400
  fenceUntrustedOcrText,
389
401
  foldPath,
402
+ formatSymbolLocation,
390
403
  globalDbPath,
391
404
  installSingleFilePlugin,
392
405
  isTestFile,
@@ -425,7 +438,7 @@ import {
425
438
  withRetryOnLock,
426
439
  writeIfDifferent,
427
440
  writeJsonSettings
428
- } from "./token-goat-chunk-LOCOX2ML.mjs";
441
+ } from "./token-goat-chunk-QKXBGBQR.mjs";
429
442
  import {
430
443
  __export,
431
444
  init_define_import_meta_env
@@ -11051,7 +11064,7 @@ function formatFrameBody(frame, projectRoot, seen) {
11051
11064
  if (resolved === null) {
11052
11065
  return [` # body: No symbols enclosing line ${frame.lineNo} in '${frame.file}'`];
11053
11066
  }
11054
- const header = ` # body: ${resolved.name} ${resolved.kind} ${resolved.filePath}:${resolved.lineStart}-${resolved.lineEnd}`;
11067
+ const header = ` # body: ${resolved.name} ${resolved.kind} ${formatSymbolLocation(resolved.filePath, resolved.lineStart, resolved.lineEnd)}`;
11055
11068
  if (seen.has(resolved.key)) {
11056
11069
  return [`${header} (same as above)`];
11057
11070
  }
@@ -16171,7 +16184,7 @@ async function cmdMcpServe() {
16171
16184
  let StdioServerTransport;
16172
16185
  try {
16173
16186
  ;
16174
- ({ createMcpServer } = await import("./token-goat-chunk-SBYRP3X4.mjs"));
16187
+ ({ createMcpServer } = await import("./token-goat-chunk-FZU7GMUS.mjs"));
16175
16188
  ({ StdioServerTransport } = await import("./token-goat-chunk-EVC4TOLE.mjs"));
16176
16189
  } catch (err2) {
16177
16190
  process.stderr.write(
@@ -16196,7 +16209,7 @@ async function cmdHook(event, opts) {
16196
16209
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
16197
16210
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
16198
16211
  }
16199
- const { relay } = await import("./token-goat-chunk-VRWX6QYW.mjs");
16212
+ const { relay } = await import("./token-goat-chunk-P2PU4CR5.mjs");
16200
16213
  await relay(event);
16201
16214
  }
16202
16215
  function projectHooksCommitNote(pathFiles, hooksConfigPath) {
@@ -16233,7 +16246,7 @@ async function cmdInstall(opts) {
16233
16246
  if (opts.project === true && opts.user === true) {
16234
16247
  throw new Error("install takes either -p/--project or --user, not both.");
16235
16248
  }
16236
- await import("./token-goat-chunk-VRWX6QYW.mjs");
16249
+ await import("./token-goat-chunk-P2PU4CR5.mjs");
16237
16250
  const scope = opts.project === true ? "project" : "user";
16238
16251
  if (wantsClaudeCodeBase(opts)) {
16239
16252
  const result = installHooks(scope);
@@ -16917,7 +16930,14 @@ function fenceOcrText(text) {
16917
16930
  return fenceUntrustedOcrText(text);
16918
16931
  }
16919
16932
  async function cmdImageText(file, opts = {}) {
16920
- const result = await runImageText(file);
16933
+ if (opts.lang) {
16934
+ const tokens = opts.lang.split(/[+,;\s]+/).map((s) => s.trim().toLowerCase()).filter(Boolean);
16935
+ const invalid = tokens.filter((t) => !isSupportedOcrLang(t));
16936
+ if (invalid.length > 0) {
16937
+ throw new CliError(`unsupported OCR language(s) '${invalid.join(", ")}'; must be from: ${SUPPORTED_OCR_LANG_CODES.join(", ")}`);
16938
+ }
16939
+ }
16940
+ const result = await runImageText(file, opts.lang);
16921
16941
  if (!result.ocrAvailable) {
16922
16942
  const msg = "image-text unavailable (install tesseract.js to use this feature)";
16923
16943
  const text2 = opts.json === true ? displaySafeJson({ ocrAvailable: false, error: msg }) : msg;
@@ -17003,10 +17023,28 @@ async function cmdXlsxSheets(file, opts = {}) {
17003
17023
  }
17004
17024
  async function cmdXlsxHead(file, opts) {
17005
17025
  const rows = opts.rows !== void 0 ? requireNonNegativeInt("--rows", opts.rows) : 20;
17006
- const text = fenceFileText(await headSheet(file, opts.sheet, rows));
17026
+ const columns = opts.columns ? opts.columns.split(",").map((c) => c.trim()).filter(Boolean) : void 0;
17027
+ const text = fenceFileText(await headSheet(file, opts.sheet, rows, columns));
17007
17028
  out(text);
17008
17029
  recordXlsxStat("xlsx_head", file, text);
17009
17030
  }
17031
+ async function cmdXlsxColumns(file, opts = {}) {
17032
+ const maxRows = opts.head !== void 0 ? requireNonNegativeInt("--head", opts.head) : 100;
17033
+ const result = await xlsxColumns(file, opts.sheet, maxRows);
17034
+ if (opts.json === true) {
17035
+ const text = displaySafeJson({
17036
+ ...result,
17037
+ sheetName: fenceFileFieldIfMatched(result.sheetName),
17038
+ columns: result.columns.map((c) => ({ ...c, name: fenceFileFieldIfMatched(c.name), sampleValues: c.sampleValues.map(fenceFileFieldIfMatched) }))
17039
+ });
17040
+ out(text);
17041
+ recordXlsxStat("xlsx_columns", file, text);
17042
+ } else {
17043
+ const text = fenceFileText(formatXlsxColumns(result));
17044
+ out(text);
17045
+ recordXlsxStat("xlsx_columns", file, text);
17046
+ }
17047
+ }
17010
17048
  async function cmdXlsxRange(file, opts) {
17011
17049
  const result = await rangeSheet(file, opts.sheet, opts.range, opts.formulas === true);
17012
17050
  const text = fenceFileText(formatXlsxRange(result));
@@ -17021,9 +17059,26 @@ async function cmdXlsxQuery(file, opts) {
17021
17059
  ...wheres !== void 0 ? { wheres } : {},
17022
17060
  ...opts.head !== void 0 ? { head: requireNonNegativeInt("--head", opts.head) } : {}
17023
17061
  });
17024
- const text = fenceFileText(formatCsvTable(result, (opts.where ?? []).map((w) => `--where ${w}`)));
17025
- out(text);
17026
- recordXlsxStat("xlsx_query", file, text);
17062
+ if (opts.json === true) {
17063
+ const rowsJson = result.rows.map((r) => Object.fromEntries(result.header.map((h, i) => [h, fenceFileFieldIfMatched(r[i] ?? "")])));
17064
+ const headTruncated = result.rows.length < result.totalRows;
17065
+ const capped = guardJsonRows(rowsJson);
17066
+ const text = displaySafeJson(
17067
+ {
17068
+ items: capped.items,
17069
+ truncated: capped.truncated || headTruncated,
17070
+ totalCount: result.totalRows,
17071
+ ...result.totalRows === 0 && result.preFilterRows > 0 ? { filteredFromRows: result.preFilterRows } : {}
17072
+ },
17073
+ 0
17074
+ );
17075
+ out(text);
17076
+ recordXlsxStat("xlsx_query", file, text);
17077
+ } else {
17078
+ const text = fenceFileText(formatCsvTable(result, (opts.where ?? []).map((w) => `--where ${w}`)));
17079
+ out(text);
17080
+ recordXlsxStat("xlsx_query", file, text);
17081
+ }
17027
17082
  }
17028
17083
  function recordDocStat(kind, file, emitted) {
17029
17084
  const fullSourceBytes = fileSizeOrZero(file);
@@ -17075,6 +17130,35 @@ async function cmdDocxOutline(file, opts) {
17075
17130
  out(text);
17076
17131
  recordDocStat("docx_outline", file, text);
17077
17132
  }
17133
+ async function cmdDocxTables(file, opts) {
17134
+ const tableIdx = opts.table !== void 0 ? parseInt(opts.table, 10) : void 0;
17135
+ if (tableIdx !== void 0 && (Number.isNaN(tableIdx) || tableIdx < 1)) {
17136
+ throw new CliError(`--table must be a positive integer, got: ${opts.table}`);
17137
+ }
17138
+ const tables = await docxTables(file);
17139
+ if (tables.length === 0) {
17140
+ if (opts.json === true) {
17141
+ out(displaySafeJson([]));
17142
+ } else {
17143
+ out("no tables found in document");
17144
+ }
17145
+ return;
17146
+ }
17147
+ const selected = tableIdx !== void 0 ? tables.filter((t) => t.tableIndex === tableIdx) : tables;
17148
+ if (selected.length === 0) {
17149
+ throw new CliError(`table ${tableIdx} not found (document has ${tables.length} table${tables.length === 1 ? "" : "s"})`);
17150
+ }
17151
+ if (opts.json === true) {
17152
+ const fenced = selected.map((t) => ({ ...t, rows: t.rows.map((r) => r.map(fenceFileFieldIfMatched)) }));
17153
+ const text2 = displaySafeJson(tableIdx !== void 0 ? fenced[0] : fenced);
17154
+ out(text2);
17155
+ recordDocStat("docx_tables", file, text2);
17156
+ return;
17157
+ }
17158
+ const text = fenceFileText(formatDocxTables(tables, tableIdx !== void 0 ? { tableIndex: tableIdx } : void 0));
17159
+ out(text);
17160
+ recordDocStat("docx_tables", file, text);
17161
+ }
17078
17162
  async function cmdDocxText(file, opts) {
17079
17163
  const text = await docxText(file);
17080
17164
  const printed = _applyFiltersAndPrint(text, opts, true, UNTRUSTED_FILE_TAG);
@@ -17171,6 +17255,9 @@ async function cmdZipRead(file, entry, opts) {
17171
17255
  function cmdPrSlice(pr, slice, opts) {
17172
17256
  process.exitCode = runPrSlice({ pr, slice, ...opts });
17173
17257
  }
17258
+ function cmdSqliteTables(file, opts) {
17259
+ process.exitCode = runSqliteTables({ file, ...opts });
17260
+ }
17174
17261
  function cmdSqliteSchema(file, opts) {
17175
17262
  process.exitCode = runSqliteSchema({ file, ...opts });
17176
17263
  }
@@ -17236,7 +17323,7 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
17236
17323
  }
17237
17324
  async function cmdCompress(opts) {
17238
17325
  try {
17239
- const bashRunner = await import("./token-goat-chunk-SF2CKCFQ.mjs");
17326
+ const bashRunner = await import("./token-goat-chunk-RDITECDL.mjs");
17240
17327
  if (opts.compress === false) {
17241
17328
  process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
17242
17329
  return;
@@ -18341,9 +18428,10 @@ function generateCompactHelp() {
18341
18428
  " exports, imports, find, grep",
18342
18429
  "",
18343
18430
  "File Formats: pdf-meta, pdf-outline, pdf-extract, pdf-locate, xlsx-sheets,",
18344
- " xlsx-head, xlsx-query, xlsx-range, yaml-outline, yaml-query, json-outline,",
18345
- " json-query, xml-outline, xml-query, html-outline, html-query, html-lint,",
18346
- " docx-outline, docx-text, pptx-outline, pptx-slide, pptx-text, pptx-notes",
18431
+ " xlsx-head, xlsx-columns, xlsx-query, xlsx-range, yaml-outline, yaml-query,",
18432
+ " json-outline, json-query, xml-outline, xml-query, html-outline, html-query,",
18433
+ " html-lint, docx-outline, docx-tables, docx-text, pptx-outline, pptx-slide, pptx-text,",
18434
+ " pptx-notes",
18347
18435
  "",
18348
18436
  "Index & Search: index, map, reconcile, doctor, commands, ask, pack, tokens,",
18349
18437
  " budget, failures, todo, trace, logfold, lockdeps, dep-docs, recent, hot,",
@@ -18365,8 +18453,8 @@ function generateCompactHelp() {
18365
18453
  " bridges-status, worker, statusline, version, config, config-get,",
18366
18454
  " capabilities, help",
18367
18455
  "",
18368
- "Data: note, note-add, note-get, note-list, sqlite-query, sqlite-schema,",
18369
- " csv-profile, csv-query",
18456
+ "Data: note, note-add, note-get, note-list, sqlite-query, sqlite-tables,",
18457
+ " sqlite-schema, csv-profile, csv-query",
18370
18458
  "",
18371
18459
  "Utils: ignores, bash-history, web-history, openapi-op, openapi-outline,",
18372
18460
  " gdrive-sections, screenshot, opencode-*, fetch-image, image-meta,",
@@ -18877,23 +18965,25 @@ function buildProgram() {
18877
18965
  program2.command("pdf-outline <file>").description("list a PDF's bookmark/outline tree with page numbers instead of a raw Read").option("-j, --json", "output as JSON").action(guard(cmdPdfOutline));
18878
18966
  program2.command("pdf-meta <file>").description("page count, title/author, and whether a PDF has an extractable text layer").option("-j, --json", "output as JSON").action(guard(cmdPdfMeta));
18879
18967
  program2.command("image-meta <file>").description("dimensions, byte size, format, and what a shrink would cost -- image metadata only, never runs OCR").option("-j, --json", "output as JSON").action(guard(cmdImageMeta));
18880
- program2.command("image-text <file>").description("OCR text for an image instead of a raw Read, honest about low-confidence results").option("-j, --json", "output as JSON").action(guard(cmdImageText));
18968
+ program2.command("image-text <file>").description("OCR text for an image instead of a raw Read, honest about low-confidence results").option("--lang <lang>", "OCR language code (e.g. eng, fra, spa)").option("-j, --json", "output as JSON").action(guard(cmdImageText));
18881
18969
  program2.command("sharepoint-resolve <shareUrl>").description("best-effort resolve a SharePoint/OneDrive sharing URL to a local synced file path (no network call)").action(guard(cmdSharepointResolve));
18882
18970
  program2.command("video-chapters <file>").description("list a video's embedded chapter markers and subtitle streams via ffprobe, instead of downloading/transcoding it").action(guard(cmdVideoChapters));
18883
18971
  program2.command("xlsx-sheets <file>").description("list sheet names + used range/dimensions in an Excel workbook instead of a raw Read").option("-j, --json", "output as JSON").action(guard(cmdXlsxSheets));
18884
- program2.command("xlsx-head <file>").description("preview the header + first N rows of one sheet instead of a raw Read").requiredOption("--sheet <name>", "sheet name (see xlsx-sheets)").option("--rows <n>", "number of data rows to show (default 20)").action(guard(cmdXlsxHead));
18885
- program2.command("xlsx-range <file>").description("extract one cell range (e.g. A1:D50) from a sheet instead of a raw Read").requiredOption("--sheet <name>", "sheet name (see xlsx-sheets)").requiredOption("--range <a1-notation>", "cell range, e.g. A1:D50").option("--formulas", "show formulas instead of computed values where present").action(guard(cmdXlsxRange));
18886
- program2.command("xlsx-query <file>").description("project columns / filter rows from one sheet instead of a raw Read").requiredOption("--sheet <name>", "sheet name (see xlsx-sheets)").option("--columns <a,b,c>", "comma-separated columns to project (default: all)").option(
18972
+ program2.command("xlsx-head <file>").description("preview the header + first N rows of one sheet instead of a raw Read").option("--sheet <name>", "sheet name (default: first sheet, see xlsx-sheets)").option("--rows <n>", "number of data rows to show (default 20)").option("--columns <a,b,c>", "comma-separated column names or letters to project (default: all)").action(guard(cmdXlsxHead));
18973
+ program2.command("xlsx-columns <file>").description("column names, letters, fill rates, and sample values instead of a raw Read").option("--sheet <name>", "sheet name (default: first sheet, see xlsx-sheets)").option("--head <n>", "max rows to sample for fill rates and distinct values (default: 100)").option("--json", "emit column summaries as JSON").action(guard(cmdXlsxColumns));
18974
+ program2.command("xlsx-range <file>").description("extract one cell range (e.g. A1:D50) from a sheet instead of a raw Read").option("--sheet <name>", "sheet name (default: first sheet, see xlsx-sheets)").requiredOption("--range <a1-notation>", "cell range, e.g. A1:D50").option("--formulas", "show formulas instead of computed values where present").action(guard(cmdXlsxRange));
18975
+ program2.command("xlsx-query <file>").description("project columns / filter rows from one sheet instead of a raw Read").option("--sheet <name>", "sheet name (default: first sheet, see xlsx-sheets)").option("--columns <a,b,c>", "comma-separated columns to project (default: all)").option(
18887
18976
  "--where <spec>",
18888
18977
  "filter, repeatable (ANDed): col=value, col!=value, col>value, col<value, col~=regex",
18889
18978
  (v, prev) => [...prev, v],
18890
18979
  []
18891
- ).option("--head <n>", "max rows to show").action(guard(cmdXlsxQuery));
18980
+ ).option("--head <n>", "max rows to show").option("--json", "emit rows as a JSON array of objects instead of a table").action(guard(cmdXlsxQuery));
18892
18981
  program2.command("pptx-outline <file>").description("per-slide title + body size + notes flag instead of a raw Read").option("-j, --json", "output as JSON").action(guard(cmdPptxOutline));
18893
18982
  program2.command("pptx-slide <file>").description("full text of one slide instead of a raw Read").requiredOption("--slide <n>", "slide number (see pptx-outline)").option("--notes", "include this slide's speaker notes").action(guard(cmdPptxSlide));
18894
18983
  program2.command("pptx-notes <file>").description("speaker notes for one slide, or all slides, instead of a raw Read").option("--slide <n>", "slide number (default: all slides)").action(guard(cmdPptxNotes));
18895
18984
  program2.command("pptx-text <file>").description("find slides whose text matches a pattern instead of a raw Read").requiredOption("--grep <pattern>", "regex to search slide text for").action(guard(cmdPptxText));
18896
18985
  program2.command("docx-outline <file>").description("heading tree of a Word document instead of a raw Read").option("-j, --json", "output as JSON").action(guard(cmdDocxOutline));
18986
+ program2.command("docx-tables <file>").description("extract tables from a Word document instead of a raw Read").option("--table <n>", "show only the Nth table (1-based index)").option("-j, --json", "output as JSON").action(guard(cmdDocxTables));
18897
18987
  program2.command("docx-text <file>").description("full body text of a Word document instead of a raw Read").option("--head <n>", "show only the first N lines").option("--tail <n>", "show only the last N lines").option("--grep <pattern>", "filter to lines matching this regex").option("--section <heading>", "extract one markdown section by heading").option("--max-matches <n>", "cap the number of --grep matches shown").action(guard(cmdDocxText));
18898
18988
  program2.command("transcript-outline <file>").description("speaker list, duration, and time-bucketed markers for a WebVTT/SRT transcript instead of a raw Read").option("-j, --json", "output as JSON").action(guard(cmdTranscriptOutline));
18899
18989
  program2.command("transcript <file>").description("slice a WebVTT/SRT transcript by speaker/time range/pattern instead of a raw Read").option("--speaker <name>", "only cues from this speaker").option("--from <hh:mm:ss>", "only cues starting at or after this time").option("--to <hh:mm:ss>", "only cues starting at or before this time").option("--grep <pattern>", "only cues whose text matches this regex").action(guard(cmdTranscript));
@@ -18934,6 +19024,7 @@ function buildProgram() {
18934
19024
  program2.command("pr-slice <pr> <slice>").description(
18935
19025
  "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)"
18936
19026
  ).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));
19027
+ program2.command("sqlite-tables <file>").description("compact inventory of tables and views with row counts and column counts instead of a raw Read").option("--json", "emit the table inventory as JSON instead of text").action(guard(cmdSqliteTables));
18937
19028
  program2.command("sqlite-schema <file>").description("tables/views, columns, indexes, foreign keys, and row counts of a SQLite database instead of a raw Read").option("--json", "emit the schema as JSON instead of text").action(guard(cmdSqliteSchema));
18938
19029
  program2.command("sqlite-query <file> <sql>").description("run a read-only SELECT against a SQLite database instead of a raw Read or shelling out to sqlite3 -- rejects any non-SELECT statement").option("--head <n>", "limit to the first N returned rows").option("--json", "emit rows as a JSON array of objects instead of a table").action(guard(cmdSqliteQuery));
18939
19030
  program2.command("coverage-report-gaps <file>").description(
@@ -0,0 +1,56 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ OCR_LANG_FILE,
5
+ OCR_LANG_PATH,
6
+ OCR_LANG_SHA256,
7
+ SUPPORTED_OCR_LANGS,
8
+ buildChildScript,
9
+ formatOcrSummary,
10
+ getActiveOcrLangs,
11
+ getOcrLangSpec,
12
+ isOcrEngineAvailable,
13
+ isTextHeavy,
14
+ ocrBlockedOffline,
15
+ ocrImage,
16
+ ocrIntegrityFailed,
17
+ quarantineOcrLangCache,
18
+ resetOcrStateForTesting,
19
+ resolveOcrLang,
20
+ setOcrTimeoutForTesting,
21
+ setTesseractEntryForTesting,
22
+ verifyOcrLangCache
23
+ } from "./token-goat-chunk-YOA4N6WA.mjs";
24
+ import "./token-goat-chunk-UM47DRD3.mjs";
25
+ import {
26
+ DEFAULT_OCR_LANG,
27
+ isSupportedOcrLang,
28
+ resolveOcrLangs
29
+ } from "./token-goat-chunk-UMXJN7DI.mjs";
30
+ import "./token-goat-chunk-EEIDFMEM.mjs";
31
+ import "./token-goat-chunk-QKXBGBQR.mjs";
32
+ import "./token-goat-chunk-A37V4PBF.mjs";
33
+ export {
34
+ DEFAULT_OCR_LANG,
35
+ OCR_LANG_FILE,
36
+ OCR_LANG_PATH,
37
+ OCR_LANG_SHA256,
38
+ SUPPORTED_OCR_LANGS,
39
+ buildChildScript,
40
+ formatOcrSummary,
41
+ getActiveOcrLangs,
42
+ getOcrLangSpec,
43
+ isOcrEngineAvailable,
44
+ isSupportedOcrLang,
45
+ isTextHeavy,
46
+ ocrBlockedOffline,
47
+ ocrImage,
48
+ ocrIntegrityFailed,
49
+ quarantineOcrLangCache,
50
+ resetOcrStateForTesting,
51
+ resolveOcrLang,
52
+ resolveOcrLangs,
53
+ setOcrTimeoutForTesting,
54
+ setTesseractEntryForTesting,
55
+ verifyOcrLangCache
56
+ };
@@ -25,7 +25,7 @@ import {
25
25
  extractSwift,
26
26
  extractThrift,
27
27
  extractWgsl
28
- } from "./token-goat-chunk-6F5TLJC7.mjs";
28
+ } from "./token-goat-chunk-B3CTCQTH.mjs";
29
29
  import {
30
30
  assignBraceBlockSpans,
31
31
  assignFlatEndLines,
@@ -56,7 +56,7 @@ import {
56
56
  stripMultilineStringSpan,
57
57
  stripStringLiterals,
58
58
  stripXmlComments
59
- } from "./token-goat-chunk-LOCOX2ML.mjs";
59
+ } from "./token-goat-chunk-QKXBGBQR.mjs";
60
60
  import {
61
61
  init_define_import_meta_env
62
62
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -2225,13 +2225,13 @@ function stripGraphqlDescriptions(text) {
2225
2225
  const tripleOpenerPos = line.indexOf('"""');
2226
2226
  if (hashPos !== -1 && (tripleOpenerPos === -1 || hashPos < tripleOpenerPos)) {
2227
2227
  const head = line.slice(0, hashPos);
2228
- const { code: code2, state: nextState2 } = stripMultilineStringSpan(head, null, "kotlin");
2228
+ const { code: code2, state: nextState2 } = stripMultilineStringSpan(head, null, "graphql");
2229
2229
  state = nextState2;
2230
2230
  outLines.push(stripStringLiterals(code2) + line.slice(hashPos));
2231
2231
  continue;
2232
2232
  }
2233
2233
  }
2234
- const { code, state: nextState } = stripMultilineStringSpan(line, state, "kotlin");
2234
+ const { code, state: nextState } = stripMultilineStringSpan(line, state, "graphql");
2235
2235
  state = nextState;
2236
2236
  outLines.push(stripStringLiterals(code));
2237
2237
  }
@@ -3761,7 +3761,7 @@ function metadataName(filePath, content, suffix) {
3761
3761
  function addFlowElements(symbols, seen, content, filePath, flowName) {
3762
3762
  const lineIndex = buildLineIndex(content);
3763
3763
  const tagAlternation = Object.keys(FLOW_TAG_KIND).join("|");
3764
- const re = new RegExp(`<(${tagAlternation})>\\s*([\\s\\S]*?)\\s*</\\1\\s*>`, "g");
3764
+ const re = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?(${tagAlternation})(?:\\s[^>]*)?>\\s*([\\s\\S]*?)\\s*</(?:[A-Za-z_][\\w.-]*:)?\\1\\s*>`, "g");
3765
3765
  for (const match of content.matchAll(re)) {
3766
3766
  if (symbols.length >= MAX_SYMBOLS11) return;
3767
3767
  const tag = match[1] ?? "";