token-goat 2.8.0 → 2.8.1

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.
@@ -2,6 +2,7 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  ALL_SYMBOLS_IN_FILE_LIMIT,
5
+ AMBIGUOUS_HEADING_LIMIT,
5
6
  CONTENT_MAX_INPUT_CHARS,
6
7
  WHOLE_FILE_NOTE_SYMBOL,
7
8
  compressText,
@@ -60,6 +61,7 @@ import {
60
61
  runOpenApiOutline,
61
62
  runOutline,
62
63
  runPdfExtractText,
64
+ runPdfLocate,
63
65
  runPdfMeta,
64
66
  runPdfOutline,
65
67
  runPrSlice,
@@ -84,7 +86,7 @@ import {
84
86
  runZipRead,
85
87
  symbolNamesInFile,
86
88
  upsertNote
87
- } from "./token-goat-chunk-SRAR6DOK.mjs";
89
+ } from "./token-goat-chunk-RMDQFTQD.mjs";
88
90
  import {
89
91
  BASH_OUTPUT_SUBDIR,
90
92
  GEMINI_TOOL_NAME_MAP,
@@ -111,7 +113,7 @@ import {
111
113
  searchRecall,
112
114
  storeWebOutput,
113
115
  summarizeResidentContext
114
- } from "./token-goat-chunk-AO6MFFTW.mjs";
116
+ } from "./token-goat-chunk-XEDQH5DA.mjs";
115
117
  import {
116
118
  AGENT_SALT_MARKER,
117
119
  CONTEXT_AUTOCOMPACT_TOKENS,
@@ -254,7 +256,7 @@ import {
254
256
  vscodeDecoderConfigured,
255
257
  walkProject,
256
258
  writeCompact
257
- } from "./token-goat-chunk-2F6TFBZE.mjs";
259
+ } from "./token-goat-chunk-2G6RAB4G.mjs";
258
260
  import {
259
261
  C,
260
262
  CONFIG_KEY_ENV_OVERRIDES,
@@ -307,6 +309,7 @@ import {
307
309
  parse,
308
310
  pushAll,
309
311
  readConfigSource,
312
+ readUnmappedTools,
310
313
  recordStat,
311
314
  redactIfDotenv,
312
315
  redactUrlQuery,
@@ -335,7 +338,7 @@ import {
335
338
  withFileLock,
336
339
  withRetryOnLock,
337
340
  writeJsonSettings
338
- } from "./token-goat-chunk-44Y77VHR.mjs";
341
+ } from "./token-goat-chunk-ELDJRLHZ.mjs";
339
342
  import {
340
343
  __export
341
344
  } from "./token-goat-chunk-AEX54RUZ.mjs";
@@ -5012,11 +5015,23 @@ var NO_SERVER_HANDLER_REASON = "token-goat has no registered server-side handler
5012
5015
  var NO_POST_COMPACT_EVENT_REASON = "post_compact is a Claude Code event (hook_event_name PostCompact, carrying compact_summary); no equivalent has been confirmed for this harness, so it is left unwired rather than guessed at";
5013
5016
  var NO_SEPARATE_FAILURE_EVENT_REASON = "post_tool_use_failure exists because Copilot CLI routes a failed tool result to a separate postToolUseFailure event instead of postToolUse. No separate failure event is wired for this harness, so a failed tool call either arrives on post_tool_use like any other result or is not seen; which of the two has not been checked here";
5014
5017
  var COPILOT_NO_POST_COMPACT_REASON = "Copilot CLI has no post-compaction hook: its HookType enum (schemas/api.schema.json, 1.0.79 and 1.0.80) declares preCompact and no postCompact, and both preCompact call sites in app.js await the hook and never assign its result. Whether the summary is reachable another way is open. app.js does emit session.compaction_complete carrying summaryContent, and the session event writer subscribes to '*' -- but emit() vs emitEphemeral() does NOT gate that writer: dispatchEventHandlers runs outside the ephemeral branch in emitInternal, on('*') early-returns past every filter, and the writer's callback applies no filter of its own before handing the JSON to native recordEventJson. The durable-vs-ephemeral decision is in Rust (api_session_event_writer.rs) and was not readable. Nor is the event uniformly summary-bearing: two of the four emit sites are the branches taken when no summary exists, summaryContent is optional in the schema, and the relay session class emits the same event via emitEphemeral. No compaction has ever been observed on the machines checked, so nothing empirical anchors any of it. Context can be written back on the next turn through userPromptSubmitted additionalContext";
5018
+ var VERIFICATION_RANK = {
5019
+ dogfooded: 0,
5020
+ sourced: 1,
5021
+ documented: 2
5022
+ };
5023
+ var VERIFICATION_BLURB = {
5024
+ dogfooded: "driven against the real harness binary",
5025
+ sourced: "wire format read from the harness's own source or declarations, never driven against it",
5026
+ documented: "wired from the harness's documentation only, never driven against it"
5027
+ };
5015
5028
  var BRIDGE_CAPABILITY_MATRIX = [
5016
5029
  {
5017
5030
  harness: "claudecode",
5018
5031
  label: "Claude Code",
5019
5032
  sourceFile: "src/install.ts (HOOK_EVENT_MAP)",
5033
+ verification: "dogfooded",
5034
+ verificationNote: "The harness this repo is developed and released under; CLAUDE.md requires every CLI/hook change be run against the built binary here before it ships.",
5020
5035
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "post_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
5021
5036
  reasons: [
5022
5037
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5027,6 +5042,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5027
5042
  harness: "codex",
5028
5043
  label: "Codex CLI",
5029
5044
  sourceFile: "src/bridges/codex_install.ts (CODEX_HOOK_EVENTS, CODEX_GLOBAL_HOOK_EVENTS)",
5045
+ verification: "sourced",
5046
+ verificationNote: "Wire format pinned to Codex 0.137.0+'s declared hookSpecificOutput schema (src/bridges/codex.ts); no run against a Codex binary is recorded here.",
5030
5047
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
5031
5048
  reasons: [
5032
5049
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5042,6 +5059,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5042
5059
  harness: "grok",
5043
5060
  label: "Grok CLI",
5044
5061
  sourceFile: "src/bridges/grok_install.ts (GROK_HOOK_EVENTS)",
5062
+ verification: "dogfooded",
5063
+ verificationNote: "grok 0.2.93, 2026-07-09: observed executing the global settings.json hooks config unmodified and setting GROK_SESSION_ID on every hook subprocess (src/bridges/registry.ts, src/hooks_cli.ts).",
5045
5064
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
5046
5065
  reasons: [
5047
5066
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5106,6 +5125,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5106
5125
  harness: "copilot_cli",
5107
5126
  label: "Copilot CLI",
5108
5127
  sourceFile: "src/bridges/copilot_cli_install.ts (COPILOT_CLI_HOOK_EVENTS), src/bridges/copilot_cli.ts (COPILOT_TO_TG_EVENT)",
5128
+ verification: "dogfooded",
5129
+ verificationNote: "doctor's checkCopilotCli drives the installed shim end to end, and every hook payload field is cross-checked against Copilot's own declarations pinned at 1.0.80 (schemas/copilot_cli.hooks.json).",
5109
5130
  implemented: /* @__PURE__ */ new Set([
5110
5131
  "session_start",
5111
5132
  "pre_tool_use",
@@ -5128,6 +5149,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5128
5149
  harness: "gemini",
5129
5150
  label: "Gemini CLI",
5130
5151
  sourceFile: "src/bridges/gemini_install.ts (GEMINI_HOOK_EVENTS)",
5152
+ verification: "sourced",
5153
+ verificationNote: "Verified against Gemini CLI's published hooks reference (src/bridges/gemini_install.ts); no run against a Gemini binary is recorded here.",
5131
5154
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
5132
5155
  reasons: [
5133
5156
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5142,6 +5165,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5142
5165
  harness: "qwen",
5143
5166
  label: "Qwen Code",
5144
5167
  sourceFile: "src/bridges/qwen_install.ts (QWEN_HOOK_EVENTS)",
5168
+ verification: "documented",
5169
+ verificationNote: "Wired from QwenLM/qwen-code's hooks.md, which src/bridges/qwen_install.ts states was not live-tested against a running install.",
5145
5170
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop"]),
5146
5171
  reasons: [
5147
5172
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5161,6 +5186,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5161
5186
  harness: "kimi",
5162
5187
  label: "Kimi Code CLI",
5163
5188
  sourceFile: "src/bridges/kimi_install.ts (KIMI_EVENT_ARG), src/bridges/kimi.ts (KIMI_HOOK_SCRIPT)",
5189
+ verification: "sourced",
5190
+ verificationNote: "Payload keys and response contract read from MoonshotAI/kimi-code's own source (externalHooksRunner/runner.ts, externalHooksService.ts); no run against a Kimi binary is recorded here.",
5164
5191
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
5165
5192
  reasons: [
5166
5193
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5172,6 +5199,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5172
5199
  harness: "opencode",
5173
5200
  label: "opencode",
5174
5201
  sourceFile: "src/bridges/opencode.ts",
5202
+ verification: "sourced",
5203
+ verificationNote: "Tool ids, parameter keys and handler behavior read directly from opencode's own source (src/bridges/opencode.ts); no run against a running gateway is recorded here.",
5175
5204
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
5176
5205
  reasons: [
5177
5206
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5186,6 +5215,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5186
5215
  harness: "openclaw",
5187
5216
  label: "OpenClaw",
5188
5217
  sourceFile: "src/bridges/openclaw.ts",
5218
+ verification: "sourced",
5219
+ verificationNote: "Verified against the live plugin docs and OpenClaw's aristotle-agent/types.ts; the bridge's own note lists what stays unverified without a live instance (built-in tool names, session id).",
5189
5220
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
5190
5221
  reasons: [
5191
5222
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5200,6 +5231,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
5200
5231
  harness: "pi",
5201
5232
  label: "pi (pi-coding-agent)",
5202
5233
  sourceFile: "src/bridges/pi.ts",
5234
+ verification: "sourced",
5235
+ verificationNote: "Response shape verified against pi's own TextContent/ImageContent types (src/bridges/pi.ts); no run against a pi binary is recorded here.",
5203
5236
  implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact"]),
5204
5237
  reasons: [
5205
5238
  { events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
@@ -5223,7 +5256,15 @@ function bridgesStatusToJson(matrix = BRIDGE_CAPABILITY_MATRIX) {
5223
5256
  reasons[event] = reason;
5224
5257
  }
5225
5258
  }
5226
- return { harness: row.harness, label: row.label, sourceFile: row.sourceFile, events, reasons };
5259
+ return {
5260
+ harness: row.harness,
5261
+ label: row.label,
5262
+ sourceFile: row.sourceFile,
5263
+ verification: row.verification,
5264
+ verificationNote: row.verificationNote,
5265
+ events,
5266
+ reasons
5267
+ };
5227
5268
  });
5228
5269
  }
5229
5270
  function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
@@ -5234,7 +5275,8 @@ function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
5234
5275
  lines.push("Read-only static analysis of src/bridges/*_install.ts and *.ts -- never invokes a real harness binary.");
5235
5276
  lines.push("");
5236
5277
  const harnessWidth = Math.max(...matrix.map((r) => r.harness.length), "harness".length);
5237
- const header = ["harness".padEnd(harnessWidth), ...HOOK_EVENTS.map((e) => e), "score"].join(" ");
5278
+ const verifyWidth = Math.max(...matrix.map((r) => r.verification.length), "verified".length);
5279
+ const header = ["harness".padEnd(harnessWidth), ...HOOK_EVENTS.map((e) => e), "score", "verified".padEnd(verifyWidth)].join(" ");
5238
5280
  lines.push(header);
5239
5281
  for (const row of matrix) {
5240
5282
  const cells = HOOK_EVENTS.map((event) => {
@@ -5242,7 +5284,16 @@ function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
5242
5284
  return cell.padEnd(event.length);
5243
5285
  });
5244
5286
  const score = `${row.implemented.size}/${HOOK_EVENTS.length}`;
5245
- lines.push([row.harness.padEnd(harnessWidth), ...cells, score].join(" "));
5287
+ lines.push([row.harness.padEnd(harnessWidth), ...cells, score, row.verification.padEnd(verifyWidth)].join(" "));
5288
+ }
5289
+ lines.push("");
5290
+ lines.push("## How each row was established");
5291
+ for (const level of Object.keys(VERIFICATION_RANK)) {
5292
+ lines.push(`- ${level}: ${VERIFICATION_BLURB[level]}`);
5293
+ }
5294
+ lines.push("");
5295
+ for (const row of [...matrix].sort((a, b) => VERIFICATION_RANK[a.verification] - VERIFICATION_RANK[b.verification])) {
5296
+ lines.push(`- ${row.harness} (${row.verification}): ${row.verificationNote}`);
5246
5297
  }
5247
5298
  const gapRows = matrix.filter((r) => r.reasons.length > 0);
5248
5299
  if (gapRows.length > 0) {
@@ -5256,6 +5307,11 @@ function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
5256
5307
  }
5257
5308
  return lines.join("\n");
5258
5309
  }
5310
+ function installVerificationNotice(harness) {
5311
+ const row = BRIDGE_CAPABILITY_MATRIX.find((r) => r.harness === harness);
5312
+ if (row === void 0 || row.verification === "dogfooded") return null;
5313
+ return `NOTE: the ${row.label} bridge is ${row.verification} -- ${VERIFICATION_BLURB[row.verification]}. If a token-goat feature seems to do nothing here, run \`token-goat doctor\` (its "Tool names" check reports what ${row.label} actually sent) and please open an issue. Details: token-goat bridges-status.`;
5314
+ }
5259
5315
 
5260
5316
  // src/sharepoint_resolve.ts
5261
5317
  import * as fs8 from "node:fs";
@@ -5673,6 +5729,7 @@ function runStats(opts = {}) {
5673
5729
  by_project: summary.by_project,
5674
5730
  by_command: summary.by_command,
5675
5731
  by_source: summary.by_source,
5732
+ by_harness: summary.by_harness,
5676
5733
  window_days: summary.window_days
5677
5734
  };
5678
5735
  process.stdout.write(JSON.stringify(out2) + "\n");
@@ -5767,7 +5824,9 @@ function checkMcpProcessHealth(processes) {
5767
5824
  const nodeProcesses = processes.filter((process3) => process3.name.toLowerCase() === "node.exe");
5768
5825
  const chromeLaunchers = nodeProcesses.filter((process3) => /npx-cli\.js.*chrome-devtools-mcp/i.test(process3.commandLine));
5769
5826
  const playwrightLaunchers = nodeProcesses.filter((process3) => /npx-cli\.js.*@playwright[\\/]mcp/i.test(process3.commandLine));
5770
- const orphanedNodeProcesses = nodeProcesses.filter((process3) => !byPid.has(process3.parentProcessId));
5827
+ const orphanedNodeProcesses = nodeProcesses.filter(
5828
+ (process3) => !byPid.has(process3.parentProcessId) && !/--worker-daemon\b/.test(process3.commandLine)
5829
+ );
5771
5830
  const launchers = chromeLaunchers.length + playwrightLaunchers.length;
5772
5831
  if (launchers > 2 || orphanedNodeProcesses.length > 0) {
5773
5832
  const details = [];
@@ -6211,6 +6270,38 @@ function checkCompactionChannel(dbPath) {
6211
6270
  return { name, status: "warn", message: `could not read compaction stats: ${extractErrorMessage(e)}` };
6212
6271
  }
6213
6272
  }
6273
+ var UNMAPPED_TOOL_SAMPLE = 5;
6274
+ function checkUnmappedTools(dbPath) {
6275
+ const name = "Tool names";
6276
+ if (!fs12.existsSync(dbPath)) {
6277
+ return { name, status: "ok", message: "no database yet" };
6278
+ }
6279
+ try {
6280
+ const rows = readUnmappedTools(dbPath);
6281
+ if (rows.length === 0) {
6282
+ return { name, status: "ok", message: "every tool name seen so far reached a handler that wanted it" };
6283
+ }
6284
+ const nearMisses = rows.filter((r) => r.near_miss !== null && r.near_miss !== void 0);
6285
+ if (nearMisses.length > 0) {
6286
+ const shown2 = nearMisses.slice(0, UNMAPPED_TOOL_SAMPLE).map((r) => `${r.harness} sent "${r.tool_name}" where "${r.near_miss}" is handled (${r.event_name}, ${r.hits}x)`);
6287
+ const more2 = nearMisses.length > UNMAPPED_TOOL_SAMPLE ? ` (+${nearMisses.length - UNMAPPED_TOOL_SAMPLE} more)` : "";
6288
+ return {
6289
+ name,
6290
+ status: "warn",
6291
+ message: `${shown2.join("; ")}${more2} -- these differ only by case or separators, so that bridge's tool-rename step is very likely not being applied and every handler behind those names is inert`
6292
+ };
6293
+ }
6294
+ const shown = rows.slice(0, UNMAPPED_TOOL_SAMPLE).map((r) => `${r.tool_name} (${r.hits}x)`);
6295
+ const more = rows.length > UNMAPPED_TOOL_SAMPLE ? `, +${rows.length - UNMAPPED_TOOL_SAMPLE} more` : "";
6296
+ return {
6297
+ name,
6298
+ status: "ok",
6299
+ message: `${rows.length} tool name(s) seen with no handler, none resembling one token-goat handles: ${shown.join(", ")}${more}`
6300
+ };
6301
+ } catch (e) {
6302
+ return { name, status: "warn", message: `could not read the tool-name histogram: ${extractErrorMessage(e)}` };
6303
+ }
6304
+ }
6214
6305
  function runDoctor(dataDir2, configPath2, rootDir, processes) {
6215
6306
  const results = [];
6216
6307
  const actualDataDir = dataDir2 || dataDir();
@@ -6223,6 +6314,7 @@ function runDoctor(dataDir2, configPath2, rootDir, processes) {
6223
6314
  results.push(checkSymbolCount(path11.join(actualDataDir, "global.db"), rootDir));
6224
6315
  results.push(checkDirtyQueueHealth(actualDataDir));
6225
6316
  results.push(checkCompactionChannel(path11.join(actualDataDir, "global.db")));
6317
+ results.push(checkUnmappedTools(path11.join(actualDataDir, "global.db")));
6226
6318
  const actualConfigPath = configPath2 || configPath();
6227
6319
  results.push(checkConfigValid(actualConfigPath));
6228
6320
  results.push(checkEmbeddings(loadConfig(rootDir)));
@@ -9118,6 +9210,10 @@ var GO_FAIL = /^--- FAIL:\s+(\S+)/;
9118
9210
  var CARGO_FAIL = /^test (\S+) \.\.\. FAILED/;
9119
9211
  var CARGO_SECTION = /^---- (\S+) (?:stdout|stderr) ----$/;
9120
9212
  var CARGO_RESULT = /^test result:/;
9213
+ var VITEST_FAIL_HEADER = /^\s+FAIL\s+(.+?)\s*$/;
9214
+ var VITEST_BANNER = /⎯+\s*Failed Tests\s+\d+\s*⎯+/;
9215
+ var VITEST_SEPARATOR = /^⎯+.*⎯+$/;
9216
+ var VITEST_SUMMARY = /^\s*(Test Files|Tests|Start at|Duration)\s/;
9121
9217
  function detectRunner(text) {
9122
9218
  if (text.includes("=== FAILURES ===") || text.includes("=== ERRORS ===")) {
9123
9219
  return "pytest";
@@ -9125,6 +9221,9 @@ function detectRunner(text) {
9125
9221
  if (/\bFAILED\b.+::test_/.test(text) || /short test summary/i.test(text)) {
9126
9222
  return "pytest";
9127
9223
  }
9224
+ if (VITEST_BANNER.test(text) || /^\s*Test Files\s+/m.test(text) && /^\s*Tests\s+\d+\s+(failed|passed)/m.test(text)) {
9225
+ return "vitest";
9226
+ }
9128
9227
  if (/^\s+●\s/m.test(text) || /^FAIL\s+\S+\.test\b/m.test(text)) {
9129
9228
  return "jest";
9130
9229
  }
@@ -9249,6 +9348,44 @@ function extractJest(lines) {
9249
9348
  }
9250
9349
  return result;
9251
9350
  }
9351
+ function extractVitest(lines) {
9352
+ const result = { runner: "vitest", blocks: [], summaryLines: [], statsLine: "" };
9353
+ let inBlock = false;
9354
+ let currentName = "";
9355
+ let currentBody = [];
9356
+ const flush = () => {
9357
+ if (inBlock && currentName) result.blocks.push({ name: currentName, body: currentBody.join("\n").trimEnd() });
9358
+ inBlock = false;
9359
+ currentName = "";
9360
+ currentBody = [];
9361
+ };
9362
+ for (const line of lines) {
9363
+ const s = line.trimEnd();
9364
+ const header = VITEST_FAIL_HEADER.exec(s);
9365
+ if (header) {
9366
+ flush();
9367
+ currentName = header[1] ?? "";
9368
+ currentBody = [];
9369
+ inBlock = true;
9370
+ result.summaryLines.push(currentName);
9371
+ continue;
9372
+ }
9373
+ if (VITEST_SUMMARY.test(s)) {
9374
+ if (/^\s*Tests\s/.test(s)) result.statsLine = s.trim();
9375
+ flush();
9376
+ continue;
9377
+ }
9378
+ if (inBlock) {
9379
+ if (VITEST_SEPARATOR.test(s)) {
9380
+ flush();
9381
+ continue;
9382
+ }
9383
+ currentBody.push(s);
9384
+ }
9385
+ }
9386
+ flush();
9387
+ return result;
9388
+ }
9252
9389
  function extractGo(lines) {
9253
9390
  const result = {
9254
9391
  runner: "go",
@@ -9371,6 +9508,9 @@ function extractFailures(text, options) {
9371
9508
  if (detected === "pytest") {
9372
9509
  return extractPytest(lines);
9373
9510
  }
9511
+ if (detected === "vitest") {
9512
+ return extractVitest(lines);
9513
+ }
9374
9514
  if (detected === "jest") {
9375
9515
  return extractJest(lines);
9376
9516
  }
@@ -13898,7 +14038,7 @@ async function cmdMcpServe() {
13898
14038
  let StdioServerTransport;
13899
14039
  try {
13900
14040
  ;
13901
- ({ createMcpServer } = await import("./token-goat-chunk-FBGBTICM.mjs"));
14041
+ ({ createMcpServer } = await import("./token-goat-chunk-73MF6YWW.mjs"));
13902
14042
  ({ StdioServerTransport } = await import("./token-goat-chunk-324QOJYZ.mjs"));
13903
14043
  } catch (err2) {
13904
14044
  process.stderr.write(
@@ -13915,11 +14055,15 @@ async function cmdMcpServe() {
13915
14055
  server.onclose = resolve12;
13916
14056
  });
13917
14057
  }
14058
+ function printBridgeVerificationNotice(harness) {
14059
+ const notice = installVerificationNotice(harness);
14060
+ if (notice !== null) out(notice);
14061
+ }
13918
14062
  async function cmdHook(event, opts) {
13919
14063
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
13920
14064
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
13921
14065
  }
13922
- const { relay } = await import("./token-goat-chunk-A62K4XW2.mjs");
14066
+ const { relay } = await import("./token-goat-chunk-YUGNM3KL.mjs");
13923
14067
  await relay(event);
13924
14068
  }
13925
14069
  async function cmdInstall(opts) {
@@ -13946,6 +14090,7 @@ async function cmdInstall(opts) {
13946
14090
  } else {
13947
14091
  out(`Installed token-goat Codex CLI integration \u2192 ${codexResult.configPath}, ${codexResult.agentsPath}`);
13948
14092
  }
14093
+ printBridgeVerificationNotice("codex");
13949
14094
  }
13950
14095
  if (opts.gemini === true) {
13951
14096
  const geminiResult = installGemini();
@@ -13954,6 +14099,7 @@ async function cmdInstall(opts) {
13954
14099
  } else {
13955
14100
  out(`Installed token-goat Gemini CLI integration \u2192 ${geminiResult.settingsPath}`);
13956
14101
  }
14102
+ printBridgeVerificationNotice("gemini");
13957
14103
  }
13958
14104
  if (opts.qwen === true) {
13959
14105
  const qwenResult = installQwen();
@@ -13962,6 +14108,7 @@ async function cmdInstall(opts) {
13962
14108
  } else {
13963
14109
  out(`Installed token-goat Qwen Code integration \u2192 ${qwenResult.settingsPath}`);
13964
14110
  }
14111
+ printBridgeVerificationNotice("qwen");
13965
14112
  }
13966
14113
  if (opts.kimi === true) {
13967
14114
  const kimiResult = installKimi();
@@ -13970,6 +14117,7 @@ async function cmdInstall(opts) {
13970
14117
  } else {
13971
14118
  out(`Installed token-goat Kimi Code integration \u2192 ${kimiResult.configPath}, ${kimiResult.hookScriptPath}, ${kimiResult.agentsPath}, ${kimiResult.skillPath}`);
13972
14119
  }
14120
+ printBridgeVerificationNotice("kimi");
13973
14121
  }
13974
14122
  if (opts.pi === true) {
13975
14123
  const piResult = installPi({ local: opts.local === true });
@@ -13978,6 +14126,7 @@ async function cmdInstall(opts) {
13978
14126
  } else {
13979
14127
  out(`Installed token-goat pi extension \u2192 ${piResult.extensionPath}`);
13980
14128
  }
14129
+ printBridgeVerificationNotice("pi");
13981
14130
  }
13982
14131
  if (opts.openclaw === true) {
13983
14132
  const openclawResult = installOpenclaw();
@@ -13986,6 +14135,7 @@ async function cmdInstall(opts) {
13986
14135
  } else {
13987
14136
  out(`Installed token-goat OpenClaw integration \u2192 ${openclawResult.configPath}, ${openclawResult.pluginPath}`);
13988
14137
  }
14138
+ printBridgeVerificationNotice("openclaw");
13989
14139
  }
13990
14140
  if (opts.copilot === true) {
13991
14141
  const copilotResult = installCopilotCli({ local: opts.local === true });
@@ -13994,6 +14144,7 @@ async function cmdInstall(opts) {
13994
14144
  } else {
13995
14145
  out(`Installed token-goat Copilot CLI integration \u2192 ${copilotResult.configPath}, ${copilotResult.scriptPath}, ${copilotResult.instructionsPath}`);
13996
14146
  }
14147
+ printBridgeVerificationNotice("copilot_cli");
13997
14148
  }
13998
14149
  if (opts.opencode === true) {
13999
14150
  const opencodeResult = installOpencode();
@@ -14002,6 +14153,7 @@ async function cmdInstall(opts) {
14002
14153
  } else {
14003
14154
  out(`Installed token-goat opencode plugin \u2192 ${opencodeResult.pluginPath}`);
14004
14155
  }
14156
+ printBridgeVerificationNotice("opencode");
14005
14157
  }
14006
14158
  if (opts.grok === true) {
14007
14159
  const grokResult = installGrok();
@@ -14010,6 +14162,7 @@ async function cmdInstall(opts) {
14010
14162
  } else {
14011
14163
  out(`Installed token-goat Grok CLI integration \u2192 ${grokResult.configPath}, ${grokResult.hookScriptPath}`);
14012
14164
  }
14165
+ printBridgeVerificationNotice("grok");
14013
14166
  }
14014
14167
  if (opts.vscode === true) {
14015
14168
  const vscodeResult = installVscode({ project: opts.project === true });
@@ -14344,10 +14497,11 @@ function _applyFiltersAndPrint(content, opts, fenceUntrusted = false, fenceTag =
14344
14497
  content = [...matched.slice(0, cap), "[token-goat: showing first " + cap + " of " + matched.length + " matching lines; raise --max-matches for more]"].join("\n");
14345
14498
  }
14346
14499
  }
14347
- const lines = content.split(/\r?\n/);
14500
+ const rawLines = content.split(/\r?\n/);
14348
14501
  if (opts.full === true) {
14349
- return emit2(lines.join("\n"));
14502
+ return emit2(rawLines.join("\n"));
14350
14503
  }
14504
+ const lines = rawLines.length > 1 && rawLines[rawLines.length - 1] === "" ? rawLines.slice(0, -1) : rawLines;
14351
14505
  const headN = opts.head !== void 0 ? requireNonNegativeInt("--head", opts.head) : 30;
14352
14506
  const tailN = opts.tail !== void 0 ? requireNonNegativeInt("--tail", opts.tail) : 80;
14353
14507
  const applyElision = (lines2, headN2, tailN2) => lines2.length > headN2 + tailN2 + 1 ? [...lines2.slice(0, headN2), "...(elided)...", ...lines2.slice(lines2.length - tailN2)] : lines2;
@@ -14431,6 +14585,33 @@ async function cmdPdfExtract(file, opts) {
14431
14585
  const bytesSaved = Math.max(1, fullSourceBytes - Buffer.byteLength(printed, "utf8"));
14432
14586
  recordStat("pdf_extract", bytesSaved, Math.round(bytesSaved / 4));
14433
14587
  }
14588
+ async function cmdPdfLocate(file, pattern, opts) {
14589
+ const locateOpts = {
14590
+ ignoreCase: opts.ignoreCase === true
14591
+ };
14592
+ if (opts.maxMatches !== void 0) locateOpts.maxMatches = requirePositiveInt("--max-matches", opts.maxMatches);
14593
+ if (opts.context !== void 0) locateOpts.context = requirePositiveInt("--context", opts.context);
14594
+ if (opts.pages !== void 0) locateOpts.pages = opts.pages;
14595
+ const matches2 = await runPdfLocate(file, pattern, locateOpts);
14596
+ const pages = matches2.map((m) => m.page);
14597
+ let printed;
14598
+ if (opts.json === true) {
14599
+ printed = JSON.stringify({ file, pattern, matchCount: matches2.length, pages, matches: matches2 }, null, 2);
14600
+ out(printed);
14601
+ } else if (matches2.length === 0) {
14602
+ printed = "(no matches)";
14603
+ out(printed);
14604
+ } else {
14605
+ const lines = matches2.map((m) => `p${m.page}: ${m.snippet}`);
14606
+ printed = `${lines.join("\n")}
14607
+
14608
+ ${countNoun(matches2.length, "match", "matches")} across ${countNoun(pages.length, "page")}`;
14609
+ out(printed);
14610
+ }
14611
+ const fullSourceBytes = fileSizeOrZero(file);
14612
+ const bytesSaved = Math.max(1, fullSourceBytes - Buffer.byteLength(printed, "utf8"));
14613
+ recordStat("pdf_locate", bytesSaved, Math.round(bytesSaved / 4));
14614
+ }
14434
14615
  async function cmdPdfOutline(file, opts) {
14435
14616
  const entries = await runPdfOutline(file);
14436
14617
  if (entries.length === 0) {
@@ -14777,7 +14958,7 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
14777
14958
  }
14778
14959
  async function cmdCompress(opts) {
14779
14960
  try {
14780
- const bashRunner = await import("./token-goat-chunk-4KZILRZN.mjs");
14961
+ const bashRunner = await import("./token-goat-chunk-I6TOUPLP.mjs");
14781
14962
  if (opts.compress === false) {
14782
14963
  process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
14783
14964
  return;
@@ -15027,8 +15208,13 @@ async function cmdSkillSection(nameHeading, headingArg) {
15027
15208
  const body = decodeSource(fs27.readFileSync(filePath));
15028
15209
  const extracted = extractNamedSection(body, heading);
15029
15210
  if (!extracted) {
15030
- process.exitCode = 1;
15031
- return;
15211
+ const messages = [`Section '${heading}' not found in skill '${skillName}'`];
15212
+ const allHeadings = listSections(filePath);
15213
+ const available = filterSimilarHeadings(allHeadings, heading);
15214
+ if (available.length > 0) messages.push(didYouMean(available));
15215
+ else if (allHeadings.length === 0) messages.push(`skill '${skillName}' has no headings`);
15216
+ else messages.push(`Try: token-goat outline ${filePath}`);
15217
+ throw new CliError(messages.join("\n"));
15032
15218
  }
15033
15219
  out(extracted);
15034
15220
  }
@@ -15081,7 +15267,7 @@ function mapFsError(e, src, dest, srcLabel = "source") {
15081
15267
  if (fe.code === "ENOENT") {
15082
15268
  const errPath = fe.path ?? "";
15083
15269
  const isSource = src !== void 0 && path27.resolve(errPath) === path27.resolve(src);
15084
- if (isSource) throw new CliError(`${srcLabel} file not found: ${src}`);
15270
+ if (isSource) throw new CliError(`${/\bfile$/i.test(srcLabel) ? srcLabel : `${srcLabel} file`} not found: ${src}`);
15085
15271
  const destDir = dest ? path27.dirname(path27.resolve(dest)) : path27.dirname(path27.resolve(errPath || "."));
15086
15272
  throw new CliError(`destination directory does not exist: ${destDir}`);
15087
15273
  }
@@ -15612,6 +15798,18 @@ function cmdInsertSection(file, opts) {
15612
15798
  else if (allHeadings.length > 0) messages.push(`Try: token-goat outline ${file}`);
15613
15799
  throw new CliError(messages.join("\n"));
15614
15800
  }
15801
+ if (result.occurrences !== void 0) {
15802
+ const lines = [
15803
+ `Ambiguous heading '${opts.after}' in '${file}': ${countNoun(result.occurrences.length, "heading")} match. Retry with one of the qualified forms below to pick one:`
15804
+ ];
15805
+ for (const [i, line] of result.occurrences.slice(0, AMBIGUOUS_HEADING_LIMIT).entries()) {
15806
+ lines.push(` - line ${line} -> --after "${opts.after}#${i + 1}"`);
15807
+ }
15808
+ if (result.occurrences.length > AMBIGUOUS_HEADING_LIMIT) {
15809
+ lines.push(` (${result.occurrences.length - AMBIGUOUS_HEADING_LIMIT} more not shown)`);
15810
+ }
15811
+ throw new CliError(lines.join("\n"));
15812
+ }
15615
15813
  let rawBytes;
15616
15814
  try {
15617
15815
  rawBytes = fs27.readFileSync(file);
@@ -16266,6 +16464,9 @@ function buildProgram() {
16266
16464
  );
16267
16465
  program2.command("config-get <file> <key>").description("read one value from a config file (TOML/JSON/YAML/INI)").action((file, key) => runExit(() => runConfigGet({ file, key })));
16268
16466
  program2.command("pdf-extract <file>").description("extract plain text from a PDF (optionally --pages N or N-M) instead of a raw Read").option("--pages <spec>", "page range to extract, e.g. 1-5 or 3 (default: all pages)").option("--layout", "heuristic column-aware reading-order reconstruction from text-item coordinates (imperfect on rotated/overlapping text)").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(cmdPdfExtract));
16467
+ program2.command("pdf-locate <file> <pattern>").description(
16468
+ "find which pages of a PDF match a regex, with a snippet per match, so you can pdf-extract only those pages instead of the whole document"
16469
+ ).option("-i, --ignore-case", "case-insensitive matching").option("--max-matches <n>", "stop after this many page matches (default: 50)").option("--context <n>", "snippet length in characters around each match (default: 80)").option("--pages <spec>", "page range to scan, e.g. 1-5 or 3 (default: all pages)").option("-j, --json", "output as JSON").action(guard(cmdPdfLocate));
16269
16470
  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));
16270
16471
  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));
16271
16472
  program2.command("image-meta <file>").description("dimensions, byte size, format, and what a shrink would cost -- sharp metadata only, never runs OCR").option("-j, --json", "output as JSON").action(guard(cmdImageMeta));
@@ -8,7 +8,7 @@ import {
8
8
  loadBlob,
9
9
  sanitizeFtsQuery,
10
10
  storeBlob
11
- } from "./token-goat-chunk-2F6TFBZE.mjs";
11
+ } from "./token-goat-chunk-2G6RAB4G.mjs";
12
12
  import {
13
13
  SYMBOL_BODY_CHAR_CAP,
14
14
  extractErrorMessage,
@@ -18,7 +18,7 @@ import {
18
18
  redactSecrets,
19
19
  runGit,
20
20
  shortFingerprint
21
- } from "./token-goat-chunk-44Y77VHR.mjs";
21
+ } from "./token-goat-chunk-ELDJRLHZ.mjs";
22
22
  import {
23
23
  registerReset
24
24
  } from "./token-goat-chunk-AO2QD2AG.mjs";
@@ -7,11 +7,11 @@ import {
7
7
  expandGlobs,
8
8
  leftoverIntegrations,
9
9
  run
10
- } from "./token-goat-chunk-VXSYZGBA.mjs";
11
- import "./token-goat-chunk-SRAR6DOK.mjs";
12
- import "./token-goat-chunk-AO6MFFTW.mjs";
13
- import "./token-goat-chunk-2F6TFBZE.mjs";
14
- import "./token-goat-chunk-44Y77VHR.mjs";
10
+ } from "./token-goat-chunk-VBXBLGTO.mjs";
11
+ import "./token-goat-chunk-RMDQFTQD.mjs";
12
+ import "./token-goat-chunk-XEDQH5DA.mjs";
13
+ import "./token-goat-chunk-2G6RAB4G.mjs";
14
+ import "./token-goat-chunk-ELDJRLHZ.mjs";
15
15
  import "./token-goat-chunk-AO2QD2AG.mjs";
16
16
  import "./token-goat-chunk-AEX54RUZ.mjs";
17
17
  export {
@@ -4,14 +4,14 @@ import {
4
4
  buildEvent,
5
5
  relay,
6
6
  relayInProcess
7
- } from "./token-goat-chunk-LVCBDJVE.mjs";
7
+ } from "./token-goat-chunk-AOBZUFNJ.mjs";
8
8
  import {
9
9
  MAX_STDIN_BYTES,
10
10
  readStdinJson
11
- } from "./token-goat-chunk-AO6MFFTW.mjs";
12
- import "./token-goat-chunk-2F6TFBZE.mjs";
13
- import "./token-goat-chunk-TUPJRK7R.mjs";
14
- import "./token-goat-chunk-44Y77VHR.mjs";
11
+ } from "./token-goat-chunk-XEDQH5DA.mjs";
12
+ import "./token-goat-chunk-2G6RAB4G.mjs";
13
+ import "./token-goat-chunk-7JDXDERZ.mjs";
14
+ import "./token-goat-chunk-ELDJRLHZ.mjs";
15
15
  import "./token-goat-chunk-AO2QD2AG.mjs";
16
16
  import "./token-goat-chunk-AEX54RUZ.mjs";
17
17
  export {
@@ -2,11 +2,11 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  relayInProcess
5
- } from "./token-goat-chunk-LVCBDJVE.mjs";
6
- import "./token-goat-chunk-AO6MFFTW.mjs";
7
- import "./token-goat-chunk-2F6TFBZE.mjs";
8
- import "./token-goat-chunk-TUPJRK7R.mjs";
9
- import "./token-goat-chunk-44Y77VHR.mjs";
5
+ } from "./token-goat-chunk-AOBZUFNJ.mjs";
6
+ import "./token-goat-chunk-XEDQH5DA.mjs";
7
+ import "./token-goat-chunk-2G6RAB4G.mjs";
8
+ import "./token-goat-chunk-7JDXDERZ.mjs";
9
+ import "./token-goat-chunk-ELDJRLHZ.mjs";
10
10
  import "./token-goat-chunk-AO2QD2AG.mjs";
11
11
  import "./token-goat-chunk-AEX54RUZ.mjs";
12
12
  export {
@@ -2,13 +2,13 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./token-goat-chunk-VXSYZGBA.mjs";
6
- import "./token-goat-chunk-SRAR6DOK.mjs";
7
- import "./token-goat-chunk-AO6MFFTW.mjs";
8
- import "./token-goat-chunk-2F6TFBZE.mjs";
5
+ } from "./token-goat-chunk-VBXBLGTO.mjs";
6
+ import "./token-goat-chunk-RMDQFTQD.mjs";
7
+ import "./token-goat-chunk-XEDQH5DA.mjs";
8
+ import "./token-goat-chunk-2G6RAB4G.mjs";
9
9
  import {
10
10
  installEpipeGuard
11
- } from "./token-goat-chunk-44Y77VHR.mjs";
11
+ } from "./token-goat-chunk-ELDJRLHZ.mjs";
12
12
  import "./token-goat-chunk-AO2QD2AG.mjs";
13
13
  import "./token-goat-chunk-AEX54RUZ.mjs";
14
14