@getverbal/cli 0.3.0 → 0.4.0

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 (2) hide show
  1. package/dist/cli.js +2076 -683
  2. package/package.json +4 -2
package/dist/cli.js CHANGED
@@ -29,7 +29,7 @@ var __export = (target, all) => {
29
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
30
30
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
31
31
 
32
- // node_modules/picocolors/picocolors.js
32
+ // node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
33
33
  var require_picocolors = __commonJS((exports, module) => {
34
34
  var p = process || {};
35
35
  var argv = p.argv || [];
@@ -180,19 +180,282 @@ async function clearCredentials() {
180
180
  var APP_DIR = "getverbal", CREDENTIALS_FILE = "credentials.json";
181
181
  var init_credentials = () => {};
182
182
 
183
+ // src/mcp/preflight-state.ts
184
+ var exports_preflight_state = {};
185
+ __export(exports_preflight_state, {
186
+ updatePreflightStats: () => updatePreflightStats,
187
+ savePreflightState: () => savePreflightState,
188
+ loadPreflightState: () => loadPreflightState,
189
+ isCooldownActive: () => isCooldownActive,
190
+ getDefaultStateDir: () => getDefaultStateDir,
191
+ drainPendingFeedback: () => drainPendingFeedback,
192
+ addPendingFeedback: () => addPendingFeedback,
193
+ activateCooldown: () => activateCooldown,
194
+ DEFAULT_PREFLIGHT_CONFIG: () => DEFAULT_PREFLIGHT_CONFIG
195
+ });
196
+ import fs from "node:fs";
197
+ import path from "node:path";
198
+ import os from "node:os";
199
+ function defaultState() {
200
+ return {
201
+ config: { ...DEFAULT_PREFLIGHT_CONFIG },
202
+ stats: { total_shown: 0, total_accepted: 0, total_dismissed: 0, total_skipped: 0, avg_score_when_shown: 0 },
203
+ cooldown: { active_until: null },
204
+ pending_feedback: []
205
+ };
206
+ }
207
+ function loadPreflightState(stateDir) {
208
+ const statePath = path.join(stateDir, STATE_FILENAME);
209
+ try {
210
+ if (!fs.existsSync(statePath))
211
+ return defaultState();
212
+ const raw = JSON.parse(fs.readFileSync(statePath, "utf8"));
213
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
214
+ const obj = raw;
215
+ return {
216
+ config: { ...DEFAULT_PREFLIGHT_CONFIG, ...obj.config },
217
+ stats: { ...defaultState().stats, ...obj.stats },
218
+ cooldown: obj.cooldown ?? { active_until: null },
219
+ pending_feedback: Array.isArray(obj.pending_feedback) ? obj.pending_feedback : []
220
+ };
221
+ }
222
+ } catch {}
223
+ return defaultState();
224
+ }
225
+ function savePreflightState(stateDir, state) {
226
+ fs.mkdirSync(stateDir, { recursive: true });
227
+ fs.writeFileSync(path.join(stateDir, STATE_FILENAME), JSON.stringify(state, null, 2));
228
+ }
229
+ function getDefaultStateDir() {
230
+ return path.join(os.homedir(), ".verbal");
231
+ }
232
+ function updatePreflightStats(state, action, score) {
233
+ const stats = { ...state.stats };
234
+ if (action === "shown") {
235
+ const prevTotal = stats.total_shown;
236
+ stats.total_shown += 1;
237
+ stats.avg_score_when_shown = Math.round((stats.avg_score_when_shown * prevTotal + score) / stats.total_shown);
238
+ } else if (action === "accepted") {
239
+ stats.total_accepted += 1;
240
+ } else if (action === "dismissed") {
241
+ stats.total_dismissed += 1;
242
+ } else if (action === "skipped") {
243
+ stats.total_skipped += 1;
244
+ }
245
+ return { ...state, stats };
246
+ }
247
+ function isCooldownActive(state) {
248
+ if (!state.cooldown.active_until)
249
+ return false;
250
+ return new Date(state.cooldown.active_until) > new Date;
251
+ }
252
+ function activateCooldown(state, minutes) {
253
+ const until = new Date(Date.now() + minutes * 60 * 1000).toISOString();
254
+ return { ...state, cooldown: { active_until: until } };
255
+ }
256
+ function addPendingFeedback(state, entry) {
257
+ return { ...state, pending_feedback: [...state.pending_feedback, entry] };
258
+ }
259
+ function drainPendingFeedback(state) {
260
+ return {
261
+ feedback: [...state.pending_feedback],
262
+ updatedState: { ...state, pending_feedback: [] }
263
+ };
264
+ }
265
+ var DEFAULT_PREFLIGHT_CONFIG, STATE_FILENAME = "preflight-state.json";
266
+ var init_preflight_state = __esm(() => {
267
+ DEFAULT_PREFLIGHT_CONFIG = {
268
+ threshold: 60,
269
+ cooldown_minutes: 15,
270
+ mode: "notify",
271
+ enable_llm_rewrite: false
272
+ };
273
+ });
274
+
275
+ // src/agent-hooks/launchagent.ts
276
+ function escapeXml(str) {
277
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
278
+ }
279
+ function buildUnifiedWatcherPlist(options) {
280
+ const { nodePath, cliPath, configPath } = options;
281
+ return `<?xml version="1.0" encoding="UTF-8"?>
282
+ ` + `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
283
+ ` + `<plist version="1.0">
284
+ ` + `<dict>
285
+ ` + ` <key>Label</key>
286
+ ` + ` <string>ai.verbal.watcher</string>
287
+ ` + ` <key>ProgramArguments</key>
288
+ ` + ` <array>
289
+ ` + ` <string>${escapeXml(nodePath)}</string>
290
+ ` + ` <string>${escapeXml(cliPath)}</string>
291
+ ` + ` <string>watch</string>
292
+ ` + ` </array>
293
+ ` + ` <key>RunAtLoad</key>
294
+ ` + ` <true/>
295
+ ` + ` <key>KeepAlive</key>
296
+ ` + ` <true/>
297
+ ` + ` <key>EnvironmentVariables</key>
298
+ ` + ` <dict>
299
+ ` + (configPath ? ` <key>VERBAL_CONFIG_PATH</key>
300
+ <string>${escapeXml(configPath)}</string>
301
+ ` : "") + ` </dict>
302
+ ` + `</dict>
303
+ ` + `</plist>
304
+ `;
305
+ }
306
+ function buildCodexLaunchAgentPlist(options) {
307
+ const { nodePath, cliPath, configPath } = options;
308
+ return `<?xml version="1.0" encoding="UTF-8"?>
309
+ ` + `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
310
+ ` + `<plist version="1.0">
311
+ ` + `<dict>
312
+ ` + ` <key>Label</key>
313
+ ` + ` <string>ai.verbal.codex-hooks</string>
314
+ ` + ` <key>ProgramArguments</key>
315
+ ` + ` <array>
316
+ ` + ` <string>${escapeXml(nodePath)}</string>
317
+ ` + ` <string>${escapeXml(cliPath)}</string>
318
+ ` + ` <string>watch</string>
319
+ ` + ` <string>--codex</string>
320
+ ` + ` </array>
321
+ ` + ` <key>RunAtLoad</key>
322
+ ` + ` <true/>
323
+ ` + ` <key>KeepAlive</key>
324
+ ` + ` <true/>
325
+ ` + ` <key>EnvironmentVariables</key>
326
+ ` + ` <dict>
327
+ ` + (configPath ? ` <key>VERBAL_CONFIG_PATH</key>
328
+ <string>${escapeXml(configPath)}</string>
329
+ ` : "") + ` </dict>
330
+ ` + `</dict>
331
+ ` + `</plist>
332
+ `;
333
+ }
334
+
335
+ // src/agent-hooks/hooks-installer.ts
336
+ var exports_hooks_installer = {};
337
+ __export(exports_hooks_installer, {
338
+ installUnifiedWatcher: () => installUnifiedWatcher,
339
+ installClaudeHooks: () => installClaudeHooks
340
+ });
341
+ import fs2 from "node:fs";
342
+ import os2 from "node:os";
343
+ import path2 from "node:path";
344
+ import { fileURLToPath } from "node:url";
345
+ import { execSync as execSync5 } from "node:child_process";
346
+ function installClaudeHooks(useGlobal = false) {
347
+ const settingsPath = path2.join(os2.homedir(), ".claude", "settings.json");
348
+ const hooksRoot = path2.resolve(__dirname2, "..", "..", "hooks");
349
+ const stopHook = path2.join(hooksRoot, "ingest-stop-hook.sh");
350
+ const endHook = path2.join(hooksRoot, "ingest-session-end-hook.sh");
351
+ const configPath = findMcpConfigPath();
352
+ const settings = readJson(settingsPath) ?? {};
353
+ settings.hooks = settings.hooks ?? {};
354
+ upsertHook(settings, "Stop", stopHook, {
355
+ timeout: 30,
356
+ statusMessage: "Tracking usage in Verbal",
357
+ async: true,
358
+ env: configPath ? { VERBAL_CONFIG_PATH: configPath } : undefined
359
+ });
360
+ upsertHook(settings, "SessionEnd", endHook, {
361
+ timeout: 30,
362
+ statusMessage: "Finalizing usage data",
363
+ env: configPath ? { VERBAL_CONFIG_PATH: configPath } : undefined
364
+ });
365
+ const reviewPromptHook = path2.join(hooksRoot, "session-review-prompt.js");
366
+ upsertHook(settings, "Stop", `node ${reviewPromptHook}`, {
367
+ timeout: 5,
368
+ statusMessage: "Checking session review timer"
369
+ });
370
+ const preflightHook = path2.join(hooksRoot, "preflight-hook.sh");
371
+ if (fs2.existsSync(preflightHook)) {
372
+ upsertHook(settings, "UserPromptSubmit", preflightHook, {
373
+ timeout: 10,
374
+ statusMessage: "Coaching prompt",
375
+ env: configPath ? { VERBAL_CONFIG_PATH: configPath } : undefined
376
+ });
377
+ }
378
+ fs2.mkdirSync(path2.dirname(settingsPath), { recursive: true });
379
+ fs2.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
380
+ }
381
+ function installUnifiedWatcher(useGlobal = false) {
382
+ const plistPath = path2.join(os2.homedir(), "Library", "LaunchAgents", "ai.verbal.watcher.plist");
383
+ const cliPath = useGlobal ? "getverbal" : path2.resolve(__dirname2, "cli.js");
384
+ const nodePath = process.execPath;
385
+ const configPath = findMcpConfigPath() ?? undefined;
386
+ const plist = buildUnifiedWatcherPlist({ nodePath, cliPath, configPath });
387
+ fs2.mkdirSync(path2.dirname(plistPath), { recursive: true });
388
+ const oldPlistPath = path2.join(os2.homedir(), "Library", "LaunchAgents", "ai.verbal.codex-hooks.plist");
389
+ tryUnloadPlist(oldPlistPath);
390
+ tryUnloadPlist(plistPath);
391
+ fs2.writeFileSync(plistPath, plist);
392
+ try {
393
+ execSync5(`launchctl load "${plistPath}"`, { stdio: "pipe" });
394
+ } catch {
395
+ console.error(`Note: Run 'launchctl load "${plistPath}"' to start the background watcher.`);
396
+ }
397
+ }
398
+ function tryUnloadPlist(plistPath) {
399
+ if (!fs2.existsSync(plistPath))
400
+ return;
401
+ try {
402
+ execSync5(`launchctl unload "${plistPath}"`, { stdio: "pipe" });
403
+ } catch {}
404
+ }
405
+ function upsertHook(settings, hookName, command, options) {
406
+ const hookEntry = {
407
+ matcher: "",
408
+ hooks: [{ type: "command", command, ...options }]
409
+ };
410
+ settings.hooks = settings.hooks ?? {};
411
+ settings.hooks[hookName] = settings.hooks[hookName] ?? [];
412
+ const existingIndex = settings.hooks[hookName].findIndex((entry) => entry.hooks?.some((hook) => hook.command.includes(path2.basename(command))));
413
+ if (existingIndex >= 0) {
414
+ settings.hooks[hookName][existingIndex] = hookEntry;
415
+ } else {
416
+ settings.hooks[hookName].push(hookEntry);
417
+ }
418
+ }
419
+ function readJson(filePath) {
420
+ try {
421
+ if (!fs2.existsSync(filePath))
422
+ return null;
423
+ return JSON.parse(fs2.readFileSync(filePath, "utf8"));
424
+ } catch {
425
+ return null;
426
+ }
427
+ }
428
+ function findMcpConfigPath() {
429
+ let current = process.cwd();
430
+ for (;; ) {
431
+ const candidate = path2.join(current, ".mcp.json");
432
+ if (fs2.existsSync(candidate))
433
+ return candidate;
434
+ const parent = path2.dirname(current);
435
+ if (parent === current)
436
+ return null;
437
+ current = parent;
438
+ }
439
+ }
440
+ var __filename2, __dirname2;
441
+ var init_hooks_installer = __esm(() => {
442
+ __filename2 = fileURLToPath(import.meta.url);
443
+ __dirname2 = path2.dirname(__filename2);
444
+ });
445
+
183
446
  // src/import/index.ts
184
447
  var exports_import = {};
185
448
  __export(exports_import, {
186
449
  detectImportSources: () => detectImportSources
187
450
  });
188
- import { existsSync as existsSync6, readdirSync } from "node:fs";
189
- import { join as join10 } from "node:path";
190
- import { homedir as homedir9 } from "node:os";
451
+ import { existsSync as existsSync7, readdirSync } from "node:fs";
452
+ import { join as join11 } from "node:path";
453
+ import { homedir as homedir10 } from "node:os";
191
454
  function detectImportSources() {
192
455
  const sources = [];
193
- const home = homedir9();
194
- const claudeDir = join10(home, ".claude");
195
- if (existsSync6(claudeDir)) {
456
+ const home = homedir10();
457
+ const claudeDir = join11(home, ".claude");
458
+ if (existsSync7(claudeDir)) {
196
459
  const sessions = countSessions(claudeDir, "projects");
197
460
  if (sessions > 0) {
198
461
  sources.push({
@@ -203,8 +466,8 @@ function detectImportSources() {
203
466
  });
204
467
  }
205
468
  }
206
- const codexDir = join10(home, ".codex");
207
- if (existsSync6(codexDir)) {
469
+ const codexDir = join11(home, ".codex");
470
+ if (existsSync7(codexDir)) {
208
471
  const sessions = countSessions(codexDir, "sessions");
209
472
  if (sessions > 0) {
210
473
  sources.push({
@@ -219,8 +482,8 @@ function detectImportSources() {
219
482
  }
220
483
  function countSessions(dir, subdir) {
221
484
  try {
222
- const target = join10(dir, subdir);
223
- if (!existsSync6(target))
485
+ const target = join11(dir, subdir);
486
+ if (!existsSync7(target))
224
487
  return 0;
225
488
  return readdirSync(target, { recursive: true }).filter((f) => String(f).endsWith(".jsonl") || String(f).endsWith(".json")).length;
226
489
  } catch {
@@ -344,10 +607,10 @@ var init_pricing = __esm(() => {
344
607
  });
345
608
 
346
609
  // src/mcp/git-context.ts
347
- import { execSync as execSync5 } from "child_process";
610
+ import { execSync as execSync6 } from "child_process";
348
611
  function gitCommand(cmd, cwd) {
349
612
  try {
350
- return execSync5(cmd, {
613
+ return execSync6(cmd, {
351
614
  cwd,
352
615
  encoding: "utf8",
353
616
  stdio: ["pipe", "pipe", "ignore"]
@@ -401,9 +664,9 @@ function getGitContext(cwd) {
401
664
  var init_git_context = () => {};
402
665
 
403
666
  // src/agent-hooks/runtime-context.ts
404
- import fs from "node:fs";
405
- import os from "node:os";
406
- import path from "node:path";
667
+ import fs3 from "node:fs";
668
+ import os3 from "node:os";
669
+ import path3 from "node:path";
407
670
  import crypto from "node:crypto";
408
671
  function collectRuntimeContext(cwd = process.cwd()) {
409
672
  return {
@@ -419,7 +682,7 @@ function readMcpServers(cwd) {
419
682
  if (!configPath)
420
683
  return [];
421
684
  try {
422
- const raw = fs.readFileSync(configPath, "utf8");
685
+ const raw = fs3.readFileSync(configPath, "utf8");
423
686
  const parsed = JSON.parse(raw);
424
687
  const servers = parsed.mcpServers ?? {};
425
688
  return Object.entries(servers).map(([name, conf]) => {
@@ -443,22 +706,22 @@ function readMcpServers(cwd) {
443
706
  }
444
707
  function readInstalledSkills() {
445
708
  const roots = [
446
- process.env.CODEX_HOME ? path.join(process.env.CODEX_HOME, "skills") : "",
447
- path.join(os.homedir(), ".codex", "skills"),
709
+ process.env.CODEX_HOME ? path3.join(process.env.CODEX_HOME, "skills") : "",
710
+ path3.join(os3.homedir(), ".codex", "skills"),
448
711
  "/opt/codex/skills"
449
712
  ].filter(Boolean);
450
713
  const seen = new Set;
451
714
  const skills = [];
452
715
  for (const root of roots) {
453
- if (!fs.existsSync(root))
716
+ if (!fs3.existsSync(root))
454
717
  continue;
455
- const entries = fs.readdirSync(root, { withFileTypes: true });
718
+ const entries = fs3.readdirSync(root, { withFileTypes: true });
456
719
  for (const entry of entries) {
457
720
  if (!entry.isDirectory())
458
721
  continue;
459
- const skillDir = path.join(root, entry.name);
460
- const skillDoc = path.join(skillDir, "SKILL.md");
461
- if (!fs.existsSync(skillDoc))
722
+ const skillDir = path3.join(root, entry.name);
723
+ const skillDoc = path3.join(skillDir, "SKILL.md");
724
+ if (!fs3.existsSync(skillDoc))
462
725
  continue;
463
726
  const key = `${entry.name}:${skillDir}`;
464
727
  if (seen.has(key))
@@ -476,10 +739,10 @@ function readActiveSkills() {
476
739
  function findMcpConfig(startDir) {
477
740
  let current = startDir;
478
741
  for (;; ) {
479
- const candidate = path.join(current, ".mcp.json");
480
- if (fs.existsSync(candidate))
742
+ const candidate = path3.join(current, ".mcp.json");
743
+ if (fs3.existsSync(candidate))
481
744
  return candidate;
482
- const parent = path.dirname(current);
745
+ const parent = path3.dirname(current);
483
746
  if (parent === current)
484
747
  return null;
485
748
  current = parent;
@@ -638,9 +901,9 @@ var init_session_tracker = __esm(() => {
638
901
 
639
902
  // src/mcp/ingestor.ts
640
903
  import crypto2 from "node:crypto";
641
- import fs2 from "node:fs";
642
- import os2 from "node:os";
643
- import path2 from "node:path";
904
+ import fs4 from "node:fs";
905
+ import os4 from "node:os";
906
+ import path4 from "node:path";
644
907
 
645
908
  class VerbalIngestor {
646
909
  config;
@@ -666,7 +929,7 @@ class VerbalIngestor {
666
929
  billingType: config.billingType ?? "api",
667
930
  maxRetries: config.maxRetries ?? 3,
668
931
  retryBaseDelayMs: config.retryBaseDelayMs ?? 200,
669
- deadLetterPath: config.deadLetterPath ?? path2.join(os2.homedir(), ".verbal", "dead-letter.jsonl")
932
+ deadLetterPath: config.deadLetterPath ?? path4.join(os4.homedir(), ".verbal", "dead-letter.jsonl")
670
933
  };
671
934
  this.runtimeContext = collectRuntimeContext();
672
935
  this.gitContext = this.config.gitContextEnabled ? getGitContext(process.cwd()) : null;
@@ -811,135 +1074,998 @@ class VerbalIngestor {
811
1074
  isUuid(value) {
812
1075
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
813
1076
  }
814
- async postToIngest(body) {
815
- const payload = JSON.stringify(body);
816
- const headers = {
817
- "Content-Type": "application/json",
818
- Authorization: `Bearer ${this.config.apiKey}`
819
- };
820
- if (this.config.hmacSecret) {
821
- const signature = crypto2.createHmac("sha256", this.config.hmacSecret).update(payload).digest("hex");
822
- headers["x-verbal-signature"] = signature;
1077
+ async postToIngest(body) {
1078
+ const payload = JSON.stringify(body);
1079
+ const headers = {
1080
+ "Content-Type": "application/json",
1081
+ Authorization: `Bearer ${this.config.apiKey}`
1082
+ };
1083
+ if (this.config.hmacSecret) {
1084
+ const signature = crypto2.createHmac("sha256", this.config.hmacSecret).update(payload).digest("hex");
1085
+ headers["x-verbal-signature"] = signature;
1086
+ }
1087
+ const eventCount = "events" in body ? body.events.length : 1;
1088
+ for (let attempt = 0;attempt <= this.config.maxRetries; attempt++) {
1089
+ const controller = new AbortController;
1090
+ const timeout = setTimeout(() => controller.abort(), this.config.httpTimeoutMs);
1091
+ try {
1092
+ const response = await fetch(this.config.endpoint, {
1093
+ method: "POST",
1094
+ headers,
1095
+ body: payload,
1096
+ signal: controller.signal
1097
+ });
1098
+ if (response.ok) {
1099
+ return {
1100
+ ok: true,
1101
+ status: response.status,
1102
+ statusText: response.statusText,
1103
+ sent: eventCount,
1104
+ failed: 0
1105
+ };
1106
+ }
1107
+ if (attempt < this.config.maxRetries && response.status >= 500) {
1108
+ await this.sleepWithJitter(attempt);
1109
+ continue;
1110
+ }
1111
+ await this.writeDeadLetter(body, `HTTP ${response.status} ${response.statusText}`);
1112
+ return {
1113
+ ok: false,
1114
+ status: response.status,
1115
+ statusText: response.statusText,
1116
+ sent: 0,
1117
+ failed: eventCount
1118
+ };
1119
+ } catch (error) {
1120
+ if (attempt < this.config.maxRetries) {
1121
+ await this.sleepWithJitter(attempt);
1122
+ continue;
1123
+ }
1124
+ const statusText = error instanceof Error ? error.message : "Unknown error";
1125
+ await this.writeDeadLetter(body, statusText);
1126
+ return {
1127
+ ok: false,
1128
+ statusText,
1129
+ sent: 0,
1130
+ failed: eventCount
1131
+ };
1132
+ } finally {
1133
+ clearTimeout(timeout);
1134
+ }
1135
+ }
1136
+ await this.writeDeadLetter(body, "Retry budget exhausted");
1137
+ return {
1138
+ ok: false,
1139
+ statusText: "Retry budget exhausted",
1140
+ sent: 0,
1141
+ failed: eventCount
1142
+ };
1143
+ }
1144
+ async sleepWithJitter(attempt) {
1145
+ const base = this.config.retryBaseDelayMs * Math.pow(2, attempt);
1146
+ const jitter = Math.floor(Math.random() * this.config.retryBaseDelayMs);
1147
+ const delay = base + jitter;
1148
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
1149
+ }
1150
+ async writeDeadLetter(body, reason) {
1151
+ try {
1152
+ const dir = path4.dirname(this.config.deadLetterPath);
1153
+ fs4.mkdirSync(dir, { recursive: true });
1154
+ const record = {
1155
+ timestamp: new Date().toISOString(),
1156
+ reason,
1157
+ body
1158
+ };
1159
+ fs4.appendFileSync(this.config.deadLetterPath, `${JSON.stringify(record)}
1160
+ `, "utf8");
1161
+ } catch (error) {
1162
+ console.error("[VerbalIngestor] Failed to write dead-letter record", error);
1163
+ }
1164
+ }
1165
+ destroy() {
1166
+ if (this.flushTimer) {
1167
+ clearInterval(this.flushTimer);
1168
+ this.flushTimer = undefined;
1169
+ }
1170
+ }
1171
+ }
1172
+ function attachExitHooks(ingestor) {
1173
+ const cleanup = () => {
1174
+ ingestor.flush().catch((err) => {
1175
+ console.error("[VerbalIngestor] Exit flush error:", err);
1176
+ });
1177
+ ingestor.destroy();
1178
+ sessionTracker.destroy();
1179
+ };
1180
+ process.on("beforeExit", cleanup);
1181
+ process.on("SIGINT", () => {
1182
+ cleanup();
1183
+ process.exit(0);
1184
+ });
1185
+ process.on("SIGTERM", () => {
1186
+ cleanup();
1187
+ process.exit(0);
1188
+ });
1189
+ }
1190
+ var init_ingestor = __esm(() => {
1191
+ init_pricing();
1192
+ init_git_context();
1193
+ init_runtime_context();
1194
+ init_session_tracker();
1195
+ });
1196
+
1197
+ // src/platforms/state.ts
1198
+ import fs5 from "node:fs";
1199
+ import path5 from "node:path";
1200
+ function loadPlatformState(stateDir, platformId) {
1201
+ const statePath = path5.join(stateDir, `platform-${platformId}-state.json`);
1202
+ try {
1203
+ if (!fs5.existsSync(statePath))
1204
+ return null;
1205
+ return JSON.parse(fs5.readFileSync(statePath, "utf8"));
1206
+ } catch {
1207
+ return null;
1208
+ }
1209
+ }
1210
+ function savePlatformState(stateDir, platformId, state) {
1211
+ const statePath = path5.join(stateDir, `platform-${platformId}-state.json`);
1212
+ fs5.mkdirSync(stateDir, { recursive: true });
1213
+ fs5.writeFileSync(statePath, JSON.stringify(state, null, 2));
1214
+ }
1215
+ var init_state = () => {};
1216
+
1217
+ // src/shared/parsing-utils.ts
1218
+ import fs6 from "node:fs";
1219
+ function readJsonLines(filePath) {
1220
+ const content = fs6.readFileSync(filePath, "utf8");
1221
+ const lines = content.split(`
1222
+ `).filter((line) => line.trim().length > 0);
1223
+ const results = [];
1224
+ for (const line of lines) {
1225
+ try {
1226
+ results.push(JSON.parse(line));
1227
+ } catch {
1228
+ continue;
1229
+ }
1230
+ }
1231
+ return results;
1232
+ }
1233
+ function flattenContent(content) {
1234
+ if (!content)
1235
+ return;
1236
+ if (typeof content === "string")
1237
+ return content;
1238
+ if (Array.isArray(content)) {
1239
+ const parts = content.map((item) => {
1240
+ if (!item || typeof item !== "object")
1241
+ return "";
1242
+ const typed = item;
1243
+ if (typed.type === "thinking" || typed.type === "tool_use" || typed.type === "reasoning")
1244
+ return "";
1245
+ return typed.text ?? typed.input_text ?? typed.output_text ?? "";
1246
+ }).filter(Boolean);
1247
+ return parts.length ? parts.join(`
1248
+ `) : undefined;
1249
+ }
1250
+ return;
1251
+ }
1252
+ function estimateTokens(prompt, response) {
1253
+ const tokensIn = prompt ? Math.ceil(prompt.length / 4) : 0;
1254
+ const tokensOut = response ? Math.ceil(response.length / 4) : 0;
1255
+ return { tokensIn, tokensOut };
1256
+ }
1257
+ var init_parsing_utils = () => {};
1258
+
1259
+ // src/platforms/parsers/claude-code.ts
1260
+ import fs7 from "node:fs";
1261
+ import path6 from "node:path";
1262
+ import os5 from "node:os";
1263
+ function getEntryId(entry) {
1264
+ return entry.uuid ?? entry.message?.id ?? entry.id ?? entry.messageId;
1265
+ }
1266
+ function findEntryIndex(entries, id) {
1267
+ return entries.findIndex((entry) => getEntryId(entry) === id);
1268
+ }
1269
+ function extractMessage(entry) {
1270
+ const message = entry.message;
1271
+ const role = message?.role ?? entry.type;
1272
+ const content = flattenContent(message?.content ?? entry.content);
1273
+ return { role, content };
1274
+ }
1275
+ function findConversationFiles(baseDir) {
1276
+ if (!fs7.existsSync(baseDir))
1277
+ return [];
1278
+ const results = [];
1279
+ const walk = (dir) => {
1280
+ let entries;
1281
+ try {
1282
+ entries = fs7.readdirSync(dir, { withFileTypes: true });
1283
+ } catch {
1284
+ return;
1285
+ }
1286
+ for (const entry of entries) {
1287
+ const full = path6.join(dir, entry.name);
1288
+ if (entry.isDirectory()) {
1289
+ walk(full);
1290
+ } else if (entry.isFile() && full.endsWith(".jsonl")) {
1291
+ results.push(full);
1292
+ }
1293
+ }
1294
+ };
1295
+ walk(baseDir);
1296
+ return results;
1297
+ }
1298
+
1299
+ class ClaudeCodeParser {
1300
+ info = {
1301
+ id: "claude-code",
1302
+ name: "Claude Code",
1303
+ provider: "anthropic",
1304
+ billing_type: "subscription"
1305
+ };
1306
+ baseDir;
1307
+ constructor(baseDir) {
1308
+ this.baseDir = baseDir ?? path6.join(os5.homedir(), ".claude", "projects");
1309
+ }
1310
+ discover() {
1311
+ return findConversationFiles(this.baseDir);
1312
+ }
1313
+ async parse(state, opts) {
1314
+ const claudeState = state;
1315
+ const sessions = claudeState?.sessions ?? {};
1316
+ const warnings = [];
1317
+ const events = [];
1318
+ const files = this.discover();
1319
+ for (const filePath of files) {
1320
+ const relative = path6.relative(this.baseDir, filePath);
1321
+ const sessionId = relative.replace(/\.jsonl$/, "").replace(/[\\/]/g, ":");
1322
+ let entries;
1323
+ try {
1324
+ entries = readJsonLines(filePath);
1325
+ } catch (err) {
1326
+ warnings.push(`Failed to read ${filePath}: ${String(err)}`);
1327
+ continue;
1328
+ }
1329
+ if (entries.length === 0)
1330
+ continue;
1331
+ const lastId = sessions[sessionId];
1332
+ const startIndex = lastId ? findEntryIndex(entries, lastId) + 1 : 0;
1333
+ const newEntries = entries.slice(Math.max(startIndex, 0));
1334
+ if (newEntries.length === 0)
1335
+ continue;
1336
+ let lastUserContent;
1337
+ for (const entry of newEntries) {
1338
+ const { role, content } = extractMessage(entry);
1339
+ if (role === "user" || role === "human") {
1340
+ lastUserContent = content;
1341
+ continue;
1342
+ }
1343
+ if (role === "assistant") {
1344
+ const usage = entry.message?.usage ?? entry.usage;
1345
+ if (!usage)
1346
+ continue;
1347
+ const tokensIn = usage.input_tokens ?? 0;
1348
+ const tokensOut = usage.output_tokens ?? 0;
1349
+ if (!tokensIn && !tokensOut)
1350
+ continue;
1351
+ const entryTimestamp = entry.timestamp ?? new Date().toISOString();
1352
+ if (opts.since && entryTimestamp < opts.since)
1353
+ continue;
1354
+ if (opts.until && entryTimestamp > opts.until)
1355
+ continue;
1356
+ const entryId = getEntryId(entry) ?? `${sessionId}:${events.length}`;
1357
+ const dedupKey = `claude-code:${sessionId}:${entryId}`;
1358
+ const event = {
1359
+ event_id: entryId,
1360
+ request_id: dedupKey,
1361
+ session_id: sessionId,
1362
+ provider: "anthropic",
1363
+ model: entry.message?.model ?? entry.model ?? "claude",
1364
+ tokens_in: tokensIn,
1365
+ tokens_out: tokensOut,
1366
+ cache_read_tokens: usage.cache_read_input_tokens ?? 0,
1367
+ cache_write_tokens: usage.cache_creation_input_tokens ?? 0,
1368
+ timestamp: entryTimestamp,
1369
+ billing_type: "subscription",
1370
+ tags: ["claude-code"],
1371
+ metadata: {
1372
+ stop_reason: entry.message?.stop_reason ?? entry.stop_reason,
1373
+ source_file: filePath
1374
+ }
1375
+ };
1376
+ if (opts.captureMode === "full") {
1377
+ event.prompt = lastUserContent;
1378
+ event.response = content;
1379
+ }
1380
+ events.push(event);
1381
+ }
1382
+ }
1383
+ const lastEntry = newEntries[newEntries.length - 1];
1384
+ const lastEntryId = getEntryId(lastEntry);
1385
+ if (lastEntryId) {
1386
+ sessions[sessionId] = lastEntryId;
1387
+ }
1388
+ }
1389
+ const newState = {
1390
+ ...claudeState,
1391
+ sessions,
1392
+ lastSyncTimestamp: new Date().toISOString()
1393
+ };
1394
+ return { events, newState, warnings };
1395
+ }
1396
+ }
1397
+ var init_claude_code = __esm(() => {
1398
+ init_parsing_utils();
1399
+ });
1400
+
1401
+ // src/platforms/parsers/codex.ts
1402
+ import fs8 from "node:fs";
1403
+ import path7 from "node:path";
1404
+ import os6 from "node:os";
1405
+ function readCodexFile(filePath) {
1406
+ const content = fs8.readFileSync(filePath, "utf8").trim();
1407
+ if (!content)
1408
+ return { entries: [], sessionId: path7.basename(filePath) };
1409
+ const isJsonl = filePath.endsWith(".jsonl");
1410
+ if (!isJsonl && content.startsWith("{")) {
1411
+ try {
1412
+ const parsed = JSON.parse(content);
1413
+ return {
1414
+ entries: parsed.items ?? [],
1415
+ sessionId: parsed.session?.id ?? path7.basename(filePath)
1416
+ };
1417
+ } catch {}
1418
+ }
1419
+ const lines = content.split(`
1420
+ `).filter(Boolean);
1421
+ const entries = lines.map((line) => JSON.parse(line));
1422
+ const sessionMeta = entries.find((entry) => entry.type === "session_meta");
1423
+ const sessionId = sessionMeta?.payload?.id ?? path7.basename(filePath);
1424
+ return { entries, sessionId };
1425
+ }
1426
+ function extractMessage2(entry) {
1427
+ if (entry.type === "response_item" && entry.payload && typeof entry.payload === "object") {
1428
+ const payload = entry.payload;
1429
+ if (payload.type === "message") {
1430
+ const role = payload.role;
1431
+ const content = flattenContent(payload.content);
1432
+ if (role)
1433
+ return { role, content };
1434
+ }
1435
+ }
1436
+ if (entry.type === "message" && entry.role) {
1437
+ return { role: entry.role, content: flattenContent(entry.content) };
1438
+ }
1439
+ if (entry.type === "user" || entry.type === "assistant") {
1440
+ const role = entry.type;
1441
+ const content = flattenContent(entry.content ?? entry.message);
1442
+ return { role, content };
1443
+ }
1444
+ return null;
1445
+ }
1446
+ function findSessionFiles(baseDir) {
1447
+ if (!fs8.existsSync(baseDir))
1448
+ return [];
1449
+ const results = [];
1450
+ const walk = (dir) => {
1451
+ let entries;
1452
+ try {
1453
+ entries = fs8.readdirSync(dir, { withFileTypes: true });
1454
+ } catch {
1455
+ return;
1456
+ }
1457
+ for (const entry of entries) {
1458
+ const full = path7.join(dir, entry.name);
1459
+ if (entry.isDirectory()) {
1460
+ walk(full);
1461
+ } else if (entry.isFile() && (full.endsWith(".json") || full.endsWith(".jsonl"))) {
1462
+ results.push(full);
1463
+ }
1464
+ }
1465
+ };
1466
+ walk(baseDir);
1467
+ return results;
1468
+ }
1469
+
1470
+ class CodexParser {
1471
+ info = {
1472
+ id: "codex",
1473
+ name: "OpenAI Codex",
1474
+ provider: "openai",
1475
+ billing_type: "api"
1476
+ };
1477
+ baseDir;
1478
+ constructor(baseDir) {
1479
+ this.baseDir = baseDir ?? path7.join(os6.homedir(), ".codex", "sessions");
1480
+ }
1481
+ discover() {
1482
+ return findSessionFiles(this.baseDir);
1483
+ }
1484
+ async parse(state, opts) {
1485
+ const codexState = state;
1486
+ const fileStates = codexState?.files ?? {};
1487
+ const warnings = [];
1488
+ const events = [];
1489
+ const files = this.discover();
1490
+ for (const filePath of files) {
1491
+ let fileEntries;
1492
+ let sessionId;
1493
+ try {
1494
+ const result = readCodexFile(filePath);
1495
+ fileEntries = result.entries;
1496
+ sessionId = result.sessionId;
1497
+ } catch (err) {
1498
+ warnings.push(`Failed to read ${filePath}: ${String(err)}`);
1499
+ continue;
1500
+ }
1501
+ if (fileEntries.length === 0)
1502
+ continue;
1503
+ const fileState = fileStates[filePath] ?? { lastIndex: -1 };
1504
+ const startIndex = Math.max(fileState.lastIndex + 1, 0);
1505
+ const newEntries = fileEntries.slice(startIndex);
1506
+ if (newEntries.length === 0) {
1507
+ fileStates[filePath] = fileState;
1508
+ continue;
1509
+ }
1510
+ let lastUserContent;
1511
+ let currentModel;
1512
+ let currentProvider;
1513
+ let lastTokenUsage;
1514
+ let pendingEvent;
1515
+ let pendingPrompt;
1516
+ let pendingResponse;
1517
+ let eventIndex = 0;
1518
+ for (const entry of newEntries) {
1519
+ if (entry.type === "session_meta" && entry.payload && typeof entry.payload === "object") {
1520
+ const payload = entry.payload;
1521
+ currentProvider = payload.model_provider ?? currentProvider;
1522
+ currentModel = payload.model ?? currentModel;
1523
+ continue;
1524
+ }
1525
+ if (entry.type === "turn_context" && entry.payload && typeof entry.payload === "object") {
1526
+ const payload = entry.payload;
1527
+ currentModel = payload.model ?? currentModel;
1528
+ continue;
1529
+ }
1530
+ if (entry.type === "event_msg" && entry.payload) {
1531
+ const payload = entry.payload;
1532
+ if (payload.type === "token_count" && payload.info?.last_token_usage) {
1533
+ lastTokenUsage = payload.info.last_token_usage;
1534
+ if (pendingEvent) {
1535
+ const usage = lastTokenUsage;
1536
+ pendingEvent.tokens_in = usage.input_tokens ?? 0;
1537
+ pendingEvent.tokens_out = usage.output_tokens ?? 0;
1538
+ const entryTs = pendingEvent.timestamp;
1539
+ if (!opts.since || entryTs >= opts.since) {
1540
+ if (!opts.until || entryTs <= opts.until) {
1541
+ events.push(pendingEvent);
1542
+ }
1543
+ }
1544
+ pendingEvent = undefined;
1545
+ pendingPrompt = undefined;
1546
+ pendingResponse = undefined;
1547
+ lastTokenUsage = undefined;
1548
+ }
1549
+ }
1550
+ continue;
1551
+ }
1552
+ const message = extractMessage2(entry);
1553
+ if (message) {
1554
+ if (message.role === "user") {
1555
+ lastUserContent = message.content;
1556
+ continue;
1557
+ }
1558
+ if (message.role === "assistant") {
1559
+ if (pendingEvent) {
1560
+ const { tokensIn, tokensOut } = estimateTokens(pendingPrompt, pendingResponse);
1561
+ pendingEvent.tokens_in = tokensIn;
1562
+ pendingEvent.tokens_out = tokensOut;
1563
+ pendingEvent.metadata = {
1564
+ ...pendingEvent.metadata,
1565
+ token_estimate_method: "chars/4"
1566
+ };
1567
+ const entryTs = pendingEvent.timestamp;
1568
+ if (!opts.since || entryTs >= opts.since) {
1569
+ if (!opts.until || entryTs <= opts.until) {
1570
+ events.push(pendingEvent);
1571
+ }
1572
+ }
1573
+ pendingEvent = undefined;
1574
+ pendingPrompt = undefined;
1575
+ pendingResponse = undefined;
1576
+ }
1577
+ const entryTimestamp = entry.timestamp ?? new Date().toISOString();
1578
+ const entryId = entry.id ?? `${sessionId}:${startIndex + eventIndex}`;
1579
+ const dedupKey = `codex:${sessionId}:${startIndex + eventIndex}`;
1580
+ eventIndex++;
1581
+ const event = {
1582
+ event_id: entryId,
1583
+ request_id: dedupKey,
1584
+ session_id: sessionId,
1585
+ provider: currentProvider ?? "openai",
1586
+ model: currentModel ?? "codex",
1587
+ tokens_in: 0,
1588
+ tokens_out: 0,
1589
+ timestamp: entryTimestamp,
1590
+ billing_type: "api",
1591
+ tags: ["codex"],
1592
+ metadata: {
1593
+ source_file: filePath,
1594
+ source: "codex"
1595
+ }
1596
+ };
1597
+ if (opts.captureMode === "full") {
1598
+ event.prompt = lastUserContent;
1599
+ event.response = message.content;
1600
+ }
1601
+ if (lastTokenUsage) {
1602
+ event.tokens_in = lastTokenUsage.input_tokens ?? 0;
1603
+ event.tokens_out = lastTokenUsage.output_tokens ?? 0;
1604
+ lastTokenUsage = undefined;
1605
+ const entryTs = event.timestamp;
1606
+ if (!opts.since || entryTs >= opts.since) {
1607
+ if (!opts.until || entryTs <= opts.until) {
1608
+ events.push(event);
1609
+ }
1610
+ }
1611
+ } else {
1612
+ pendingEvent = event;
1613
+ pendingPrompt = lastUserContent;
1614
+ pendingResponse = message.content;
1615
+ }
1616
+ }
1617
+ continue;
1618
+ }
1619
+ }
1620
+ if (pendingEvent) {
1621
+ const { tokensIn, tokensOut } = estimateTokens(pendingPrompt, pendingResponse);
1622
+ pendingEvent.tokens_in = tokensIn;
1623
+ pendingEvent.tokens_out = tokensOut;
1624
+ pendingEvent.metadata = {
1625
+ ...pendingEvent.metadata,
1626
+ token_estimate_method: "chars/4"
1627
+ };
1628
+ const entryTs = pendingEvent.timestamp;
1629
+ if (!opts.since || entryTs >= opts.since) {
1630
+ if (!opts.until || entryTs <= opts.until) {
1631
+ events.push(pendingEvent);
1632
+ }
1633
+ }
1634
+ }
1635
+ fileStates[filePath] = { lastIndex: fileEntries.length - 1 };
1636
+ }
1637
+ const newState = {
1638
+ ...codexState,
1639
+ files: fileStates,
1640
+ lastSyncTimestamp: new Date().toISOString()
1641
+ };
1642
+ return { events, newState, warnings };
1643
+ }
1644
+ }
1645
+ var init_codex = __esm(() => {
1646
+ init_parsing_utils();
1647
+ });
1648
+
1649
+ // src/platforms/parsers/cursor.ts
1650
+ import fs9 from "node:fs";
1651
+ import path8 from "node:path";
1652
+ import os7 from "node:os";
1653
+ function globVscdbFiles(baseDir) {
1654
+ if (!fs9.existsSync(baseDir))
1655
+ return [];
1656
+ const results = [];
1657
+ let workspaceDirs;
1658
+ try {
1659
+ workspaceDirs = fs9.readdirSync(baseDir, { withFileTypes: true });
1660
+ } catch {
1661
+ return [];
1662
+ }
1663
+ for (const entry of workspaceDirs) {
1664
+ if (!entry.isDirectory())
1665
+ continue;
1666
+ const candidate = path8.join(baseDir, entry.name, "state.vscdb");
1667
+ if (fs9.existsSync(candidate)) {
1668
+ results.push(candidate);
1669
+ }
1670
+ }
1671
+ return results;
1672
+ }
1673
+ function extractBubbleId(bubble) {
1674
+ return bubble.bubbleId ?? bubble.id;
1675
+ }
1676
+ function extractBubbleText(bubble) {
1677
+ if (typeof bubble.text === "string" && bubble.text.length > 0)
1678
+ return bubble.text;
1679
+ return;
1680
+ }
1681
+ function isAssistantBubble(bubble) {
1682
+ const type = (bubble.type ?? "").toLowerCase();
1683
+ const role = (bubble.role ?? "").toLowerCase();
1684
+ return type === "ai" || type === "assistant" || role === "assistant";
1685
+ }
1686
+ function isUserBubble(bubble) {
1687
+ const type = (bubble.type ?? "").toLowerCase();
1688
+ const role = (bubble.role ?? "").toLowerCase();
1689
+ return type === "user" || role === "user" || type === "human";
1690
+ }
1691
+ function bubbleTimestamp(bubble) {
1692
+ const ms = bubble.serverTimestamp ?? bubble.timestamp;
1693
+ if (ms)
1694
+ return new Date(ms).toISOString();
1695
+ return new Date().toISOString();
1696
+ }
1697
+
1698
+ class CursorParser {
1699
+ info = {
1700
+ id: "cursor",
1701
+ name: "Cursor",
1702
+ provider: "anthropic",
1703
+ billing_type: "subscription"
1704
+ };
1705
+ baseDir;
1706
+ constructor(baseDir) {
1707
+ if (baseDir) {
1708
+ this.baseDir = baseDir;
1709
+ } else if (process.platform === "win32") {
1710
+ this.baseDir = path8.join(process.env.APPDATA || path8.join(os7.homedir(), "AppData", "Roaming"), "Cursor", "User", "workspaceStorage");
1711
+ } else if (process.platform === "linux") {
1712
+ this.baseDir = path8.join(os7.homedir(), ".config", "Cursor", "User", "workspaceStorage");
1713
+ } else {
1714
+ this.baseDir = path8.join(os7.homedir(), "Library", "Application Support", "Cursor", "User", "workspaceStorage");
1715
+ }
1716
+ }
1717
+ discover() {
1718
+ return globVscdbFiles(this.baseDir);
1719
+ }
1720
+ async parse(state, opts) {
1721
+ const cursorState = state;
1722
+ const workspaces = { ...cursorState?.workspaces ?? {} };
1723
+ const warnings = [];
1724
+ const events = [];
1725
+ let Database;
1726
+ try {
1727
+ const mod = await import("bun:sqlite");
1728
+ Database = mod.Database;
1729
+ } catch {
1730
+ warnings.push("Cursor parser requires Bun runtime for SQLite access. Run via `bun run` or `bunx getverbal sync`.");
1731
+ return {
1732
+ events: [],
1733
+ newState: { ...cursorState ?? {}, workspaces, lastSyncTimestamp: new Date().toISOString() },
1734
+ warnings
1735
+ };
823
1736
  }
824
- const eventCount = "events" in body ? body.events.length : 1;
825
- for (let attempt = 0;attempt <= this.config.maxRetries; attempt++) {
826
- const controller = new AbortController;
827
- const timeout = setTimeout(() => controller.abort(), this.config.httpTimeoutMs);
1737
+ const dbFiles = this.discover();
1738
+ for (const dbPath of dbFiles) {
1739
+ const workspaceHash = path8.basename(path8.dirname(dbPath));
1740
+ let mtime;
828
1741
  try {
829
- const response = await fetch(this.config.endpoint, {
830
- method: "POST",
831
- headers,
832
- body: payload,
833
- signal: controller.signal
834
- });
835
- if (response.ok) {
836
- return {
837
- ok: true,
838
- status: response.status,
839
- statusText: response.statusText,
840
- sent: eventCount,
841
- failed: 0
842
- };
843
- }
844
- if (attempt < this.config.maxRetries && response.status >= 500) {
845
- await this.sleepWithJitter(attempt);
846
- continue;
1742
+ mtime = fs9.statSync(dbPath).mtime.toISOString();
1743
+ } catch (err) {
1744
+ warnings.push(`Cannot stat ${dbPath}: ${String(err)}`);
1745
+ continue;
1746
+ }
1747
+ const prevWorkspaceState = workspaces[workspaceHash];
1748
+ if (prevWorkspaceState?.fullyProcessed && prevWorkspaceState.lastMtime === mtime) {
1749
+ continue;
1750
+ }
1751
+ let db;
1752
+ try {
1753
+ db = new Database(dbPath, { readonly: true });
1754
+ db.exec("PRAGMA journal_mode=WAL");
1755
+ const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'").all();
1756
+ let lastComposerId = prevWorkspaceState?.lastComposerId ?? "";
1757
+ for (const row of rows) {
1758
+ let composerData;
1759
+ try {
1760
+ composerData = JSON.parse(row.value);
1761
+ } catch {
1762
+ warnings.push(`Failed to parse composer JSON for key ${row.key} in ${dbPath}`);
1763
+ continue;
1764
+ }
1765
+ const composerId = composerData.composerId ?? composerData.id ?? row.key;
1766
+ const bubbles = composerData.allBubbles ?? composerData.bubbles ?? composerData.conversation ?? [];
1767
+ if (bubbles.length === 0)
1768
+ continue;
1769
+ let lastUserText;
1770
+ for (let i = 0;i < bubbles.length; i++) {
1771
+ const bubble = bubbles[i];
1772
+ if (isUserBubble(bubble)) {
1773
+ lastUserText = extractBubbleText(bubble);
1774
+ continue;
1775
+ }
1776
+ if (!isAssistantBubble(bubble))
1777
+ continue;
1778
+ const bubbleId = extractBubbleId(bubble) ?? `${composerId}:${i}`;
1779
+ const dedupKey = `cursor:${workspaceHash}:${composerId}:${bubbleId}`;
1780
+ const timestamp = bubbleTimestamp(bubble);
1781
+ if (opts.since && timestamp < opts.since)
1782
+ continue;
1783
+ if (opts.until && timestamp > opts.until)
1784
+ continue;
1785
+ const responseText = extractBubbleText(bubble);
1786
+ const model = bubble.modelType ?? bubble.model ?? composerData.model ?? "claude";
1787
+ let tokensIn = bubble.inputTokenCount ?? 0;
1788
+ let tokensOut = bubble.outputTokenCount ?? bubble.numTokens ?? 0;
1789
+ let tokenEstimateMethod;
1790
+ if (!tokensIn && !tokensOut) {
1791
+ const est = estimateTokens(lastUserText, responseText);
1792
+ tokensIn = est.tokensIn;
1793
+ tokensOut = est.tokensOut;
1794
+ tokenEstimateMethod = "chars/4";
1795
+ }
1796
+ const event = {
1797
+ event_id: bubbleId,
1798
+ request_id: dedupKey,
1799
+ session_id: `cursor:${workspaceHash}:${composerId}`,
1800
+ provider: "anthropic",
1801
+ model,
1802
+ tokens_in: tokensIn,
1803
+ tokens_out: tokensOut,
1804
+ timestamp,
1805
+ billing_type: "subscription",
1806
+ tags: ["cursor"],
1807
+ metadata: {
1808
+ source_file: dbPath,
1809
+ workspace_hash: workspaceHash,
1810
+ composer_id: composerId,
1811
+ bubble_id: bubbleId,
1812
+ ...tokenEstimateMethod ? { token_estimate_method: tokenEstimateMethod } : {}
1813
+ }
1814
+ };
1815
+ if (opts.captureMode === "full") {
1816
+ event.prompt = lastUserText;
1817
+ event.response = responseText;
1818
+ }
1819
+ events.push(event);
1820
+ }
1821
+ lastComposerId = composerId;
847
1822
  }
848
- await this.writeDeadLetter(body, `HTTP ${response.status} ${response.statusText}`);
849
- return {
850
- ok: false,
851
- status: response.status,
852
- statusText: response.statusText,
853
- sent: 0,
854
- failed: eventCount
1823
+ workspaces[workspaceHash] = {
1824
+ lastMtime: mtime,
1825
+ lastComposerId,
1826
+ fullyProcessed: true
855
1827
  };
856
- } catch (error) {
857
- if (attempt < this.config.maxRetries) {
858
- await this.sleepWithJitter(attempt);
859
- continue;
1828
+ } catch (err) {
1829
+ const msg = String(err);
1830
+ if (msg.includes("SQLITE_BUSY") || msg.includes("SQLITE_LOCKED")) {
1831
+ warnings.push(`Database locked, skipping ${dbPath}: ${msg}`);
1832
+ } else {
1833
+ warnings.push(`Error reading ${dbPath}: ${msg}`);
860
1834
  }
861
- const statusText = error instanceof Error ? error.message : "Unknown error";
862
- await this.writeDeadLetter(body, statusText);
863
- return {
864
- ok: false,
865
- statusText,
866
- sent: 0,
867
- failed: eventCount
868
- };
869
1835
  } finally {
870
- clearTimeout(timeout);
1836
+ try {
1837
+ db?.close();
1838
+ } catch {}
871
1839
  }
872
1840
  }
873
- await this.writeDeadLetter(body, "Retry budget exhausted");
874
- return {
875
- ok: false,
876
- statusText: "Retry budget exhausted",
877
- sent: 0,
878
- failed: eventCount
1841
+ const newState = {
1842
+ ...cursorState ?? {},
1843
+ workspaces,
1844
+ lastSyncTimestamp: new Date().toISOString()
879
1845
  };
1846
+ return { events, newState, warnings };
880
1847
  }
881
- async sleepWithJitter(attempt) {
882
- const base = this.config.retryBaseDelayMs * Math.pow(2, attempt);
883
- const jitter = Math.floor(Math.random() * this.config.retryBaseDelayMs);
884
- const delay = base + jitter;
885
- await new Promise((resolve2) => setTimeout(resolve2, delay));
886
- }
887
- async writeDeadLetter(body, reason) {
1848
+ }
1849
+ var init_cursor = __esm(() => {
1850
+ init_parsing_utils();
1851
+ });
1852
+
1853
+ // src/platforms/parsers/gemini.ts
1854
+ import fs10 from "node:fs";
1855
+ import path9 from "node:path";
1856
+ import os8 from "node:os";
1857
+ function flattenParts(parts) {
1858
+ if (!parts || parts.length === 0)
1859
+ return;
1860
+ const texts = parts.map((p) => p.text ?? "").filter(Boolean);
1861
+ return texts.length ? texts.join(`
1862
+ `) : undefined;
1863
+ }
1864
+ function chatDirs(home) {
1865
+ return [
1866
+ path9.join(home, ".gemini", "tmp"),
1867
+ path9.join(home, ".gemini", "chats"),
1868
+ path9.join(home, ".config", "gemini", "chats")
1869
+ ];
1870
+ }
1871
+ function findJsonFiles(baseDir) {
1872
+ if (!fs10.existsSync(baseDir))
1873
+ return [];
1874
+ const results = [];
1875
+ const walk = (dir) => {
1876
+ let entries;
888
1877
  try {
889
- const dir = path2.dirname(this.config.deadLetterPath);
890
- fs2.mkdirSync(dir, { recursive: true });
891
- const record = {
892
- timestamp: new Date().toISOString(),
893
- reason,
894
- body
895
- };
896
- fs2.appendFileSync(this.config.deadLetterPath, `${JSON.stringify(record)}
897
- `, "utf8");
898
- } catch (error) {
899
- console.error("[VerbalIngestor] Failed to write dead-letter record", error);
1878
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
1879
+ } catch {
1880
+ return;
900
1881
  }
901
- }
902
- destroy() {
903
- if (this.flushTimer) {
904
- clearInterval(this.flushTimer);
905
- this.flushTimer = undefined;
1882
+ for (const entry of entries) {
1883
+ const full = path9.join(dir, entry.name);
1884
+ if (entry.isDirectory()) {
1885
+ walk(full);
1886
+ } else if (entry.isFile() && full.endsWith(".json")) {
1887
+ results.push(full);
1888
+ }
906
1889
  }
1890
+ };
1891
+ walk(baseDir);
1892
+ return results;
1893
+ }
1894
+ function extractMessages(session) {
1895
+ return session.messages ?? session.contents ?? session.history ?? [];
1896
+ }
1897
+ function deriveSessionId(filePath, home) {
1898
+ const rel = path9.relative(home, filePath).replace(/\.json$/, "").replace(/[\\/]/g, ":");
1899
+ return rel || path9.basename(filePath, ".json");
1900
+ }
1901
+ function deriveProjectHash(filePath) {
1902
+ const parts = filePath.split(path9.sep);
1903
+ const tmpIdx = parts.lastIndexOf("tmp");
1904
+ if (tmpIdx !== -1 && parts.length > tmpIdx + 1) {
1905
+ return parts[tmpIdx + 1];
907
1906
  }
1907
+ return "default";
908
1908
  }
909
- function attachExitHooks(ingestor) {
910
- const cleanup = () => {
911
- ingestor.flush().catch((err) => {
912
- console.error("[VerbalIngestor] Exit flush error:", err);
913
- });
914
- ingestor.destroy();
915
- sessionTracker.destroy();
1909
+
1910
+ class GeminiParser {
1911
+ info = {
1912
+ id: "gemini",
1913
+ name: "Gemini CLI",
1914
+ provider: "google",
1915
+ billing_type: "api"
916
1916
  };
917
- process.on("beforeExit", cleanup);
918
- process.on("SIGINT", () => {
919
- cleanup();
920
- process.exit(0);
921
- });
922
- process.on("SIGTERM", () => {
923
- cleanup();
924
- process.exit(0);
925
- });
1917
+ home;
1918
+ constructor(home) {
1919
+ this.home = home ?? os8.homedir();
1920
+ }
1921
+ discover() {
1922
+ const results = [];
1923
+ for (const dir of chatDirs(this.home)) {
1924
+ results.push(...findJsonFiles(dir));
1925
+ }
1926
+ return [...new Set(results)];
1927
+ }
1928
+ async parse(state, opts) {
1929
+ const geminiState = state;
1930
+ const fileStates = { ...geminiState?.files ?? {} };
1931
+ const warnings = [];
1932
+ const events = [];
1933
+ const files = this.discover();
1934
+ for (const filePath of files) {
1935
+ let mtime;
1936
+ try {
1937
+ mtime = fs10.statSync(filePath).mtime.toISOString();
1938
+ } catch (err) {
1939
+ warnings.push(`Cannot stat ${filePath}: ${String(err)}`);
1940
+ continue;
1941
+ }
1942
+ const prevFileState = fileStates[filePath];
1943
+ if (prevFileState && prevFileState.lastMtime === mtime) {
1944
+ continue;
1945
+ }
1946
+ let session;
1947
+ try {
1948
+ const raw = fs10.readFileSync(filePath, "utf8");
1949
+ session = JSON.parse(raw);
1950
+ } catch (err) {
1951
+ warnings.push(`Failed to read/parse ${filePath}: ${String(err)}`);
1952
+ continue;
1953
+ }
1954
+ const messages = extractMessages(session);
1955
+ if (messages.length === 0) {
1956
+ fileStates[filePath] = { lastMtime: mtime, lastMessageIndex: -1 };
1957
+ continue;
1958
+ }
1959
+ const startIndex = (prevFileState?.lastMessageIndex ?? -1) + 1;
1960
+ const newMessages = messages.slice(startIndex);
1961
+ if (newMessages.length === 0) {
1962
+ fileStates[filePath] = { lastMtime: mtime, lastMessageIndex: messages.length - 1 };
1963
+ continue;
1964
+ }
1965
+ const sessionId = deriveSessionId(filePath, this.home);
1966
+ const projectHash = deriveProjectHash(filePath);
1967
+ const modelFromMeta = session.metadata?.model ?? session.model ?? "gemini";
1968
+ let lastUserText;
1969
+ for (let i = 0;i < newMessages.length; i++) {
1970
+ const msg = newMessages[i];
1971
+ const role = (msg.role ?? "").toLowerCase();
1972
+ const absoluteIndex = startIndex + i;
1973
+ const text = flattenParts(msg.parts);
1974
+ if (role === "user") {
1975
+ lastUserText = text;
1976
+ continue;
1977
+ }
1978
+ if (role !== "model" && role !== "assistant")
1979
+ continue;
1980
+ const usage = msg.usageMetadata ?? msg.metadata?.usageMetadata;
1981
+ const timestamp = mtime;
1982
+ if (opts.since && timestamp < opts.since)
1983
+ continue;
1984
+ if (opts.until && timestamp > opts.until)
1985
+ continue;
1986
+ let tokensIn = usage?.promptTokenCount ?? 0;
1987
+ let tokensOut = usage?.candidatesTokenCount ?? 0;
1988
+ let tokenEstimateMethod;
1989
+ if (!tokensIn && !tokensOut) {
1990
+ const est = estimateTokens(lastUserText, text);
1991
+ tokensIn = est.tokensIn;
1992
+ tokensOut = est.tokensOut;
1993
+ tokenEstimateMethod = "chars/4";
1994
+ }
1995
+ const dedupKey = `gemini:${projectHash}:${sessionId}:${absoluteIndex}`;
1996
+ const event = {
1997
+ event_id: `${sessionId}:${absoluteIndex}`,
1998
+ request_id: dedupKey,
1999
+ session_id: sessionId,
2000
+ provider: "google",
2001
+ model: modelFromMeta,
2002
+ tokens_in: tokensIn,
2003
+ tokens_out: tokensOut,
2004
+ timestamp,
2005
+ billing_type: "api",
2006
+ tags: ["gemini"],
2007
+ metadata: {
2008
+ source_file: filePath,
2009
+ project_hash: projectHash,
2010
+ message_index: absoluteIndex,
2011
+ ...tokenEstimateMethod ? { token_estimate_method: tokenEstimateMethod } : {}
2012
+ }
2013
+ };
2014
+ if (opts.captureMode === "full") {
2015
+ event.prompt = lastUserText;
2016
+ event.response = text;
2017
+ }
2018
+ events.push(event);
2019
+ }
2020
+ fileStates[filePath] = { lastMtime: mtime, lastMessageIndex: messages.length - 1 };
2021
+ }
2022
+ const newState = {
2023
+ ...geminiState ?? {},
2024
+ files: fileStates,
2025
+ lastSyncTimestamp: new Date().toISOString()
2026
+ };
2027
+ return { events, newState, warnings };
2028
+ }
926
2029
  }
927
- var init_ingestor = __esm(() => {
928
- init_pricing();
929
- init_git_context();
930
- init_runtime_context();
931
- init_session_tracker();
2030
+ var init_gemini = __esm(() => {
2031
+ init_parsing_utils();
2032
+ });
2033
+
2034
+ // src/platforms/parsers/index.ts
2035
+ var init_parsers = __esm(() => {
2036
+ init_claude_code();
2037
+ init_codex();
2038
+ init_cursor();
2039
+ init_gemini();
2040
+ });
2041
+
2042
+ // src/platforms/registry.ts
2043
+ function getAllParsers() {
2044
+ return PARSERS;
2045
+ }
2046
+ function getParser(platformId) {
2047
+ return PARSERS.find((p) => p.info.id === platformId);
2048
+ }
2049
+ var PARSERS;
2050
+ var init_registry = __esm(() => {
2051
+ init_parsers();
2052
+ PARSERS = [
2053
+ new ClaudeCodeParser,
2054
+ new CodexParser,
2055
+ new CursorParser,
2056
+ new GeminiParser
2057
+ ];
932
2058
  });
933
2059
 
934
2060
  // src/agent-hooks/state.ts
935
- import fs3 from "node:fs";
936
- import path3 from "node:path";
2061
+ import fs11 from "node:fs";
2062
+ import path10 from "node:path";
937
2063
  function loadClaudeState(stateDir) {
938
- const statePath = path3.join(stateDir, "last-ingested.json");
2064
+ const statePath = path10.join(stateDir, "last-ingested.json");
939
2065
  try {
940
- if (!fs3.existsSync(statePath))
2066
+ if (!fs11.existsSync(statePath))
941
2067
  return {};
942
- const raw = JSON.parse(fs3.readFileSync(statePath, "utf8"));
2068
+ const raw = JSON.parse(fs11.readFileSync(statePath, "utf8"));
943
2069
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
944
2070
  if ("sessions" in raw) {
945
2071
  const sessions = raw.sessions;
@@ -953,16 +2079,16 @@ function loadClaudeState(stateDir) {
953
2079
  return {};
954
2080
  }
955
2081
  function saveClaudeState(stateDir, state) {
956
- const statePath = path3.join(stateDir, "last-ingested.json");
957
- fs3.mkdirSync(stateDir, { recursive: true });
958
- fs3.writeFileSync(statePath, JSON.stringify(state, null, 2));
2082
+ const statePath = path10.join(stateDir, "last-ingested.json");
2083
+ fs11.mkdirSync(stateDir, { recursive: true });
2084
+ fs11.writeFileSync(statePath, JSON.stringify(state, null, 2));
959
2085
  }
960
2086
  function loadCodexState(stateDir) {
961
- const statePath = path3.join(stateDir, "codex-last-ingested.json");
2087
+ const statePath = path10.join(stateDir, "codex-last-ingested.json");
962
2088
  try {
963
- if (!fs3.existsSync(statePath))
2089
+ if (!fs11.existsSync(statePath))
964
2090
  return { files: {} };
965
- const raw = JSON.parse(fs3.readFileSync(statePath, "utf8"));
2091
+ const raw = JSON.parse(fs11.readFileSync(statePath, "utf8"));
966
2092
  if (raw && typeof raw === "object" && raw.files && typeof raw.files === "object") {
967
2093
  return raw;
968
2094
  }
@@ -972,16 +2098,16 @@ function loadCodexState(stateDir) {
972
2098
  return { files: {} };
973
2099
  }
974
2100
  function saveCodexState(stateDir, state) {
975
- const statePath = path3.join(stateDir, "codex-last-ingested.json");
976
- fs3.mkdirSync(stateDir, { recursive: true });
977
- fs3.writeFileSync(statePath, JSON.stringify(state, null, 2));
2101
+ const statePath = path10.join(stateDir, "codex-last-ingested.json");
2102
+ fs11.mkdirSync(stateDir, { recursive: true });
2103
+ fs11.writeFileSync(statePath, JSON.stringify(state, null, 2));
978
2104
  }
979
2105
  function loadTokscaleState(stateDir) {
980
- const statePath = path3.join(stateDir, "tokscale-state.json");
2106
+ const statePath = path10.join(stateDir, "tokscale-state.json");
981
2107
  try {
982
- if (!fs3.existsSync(statePath))
2108
+ if (!fs11.existsSync(statePath))
983
2109
  return {};
984
- const raw = JSON.parse(fs3.readFileSync(statePath, "utf8"));
2110
+ const raw = JSON.parse(fs11.readFileSync(statePath, "utf8"));
985
2111
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
986
2112
  return raw;
987
2113
  }
@@ -990,156 +2116,100 @@ function loadTokscaleState(stateDir) {
990
2116
  }
991
2117
  return {};
992
2118
  }
993
- function saveTokscaleState(stateDir, state) {
994
- const statePath = path3.join(stateDir, "tokscale-state.json");
995
- fs3.mkdirSync(stateDir, { recursive: true });
996
- fs3.writeFileSync(statePath, JSON.stringify(state, null, 2));
997
- }
998
- var init_state = () => {};
2119
+ var init_state2 = () => {};
999
2120
 
1000
- // src/agent-hooks/tokscale.ts
1001
- var exports_tokscale = {};
1002
- __export(exports_tokscale, {
1003
- syncFromTokscale: () => syncFromTokscale,
1004
- runTokscale: () => runTokscale,
1005
- mapTokscaleToEvents: () => mapTokscaleToEvents
2121
+ // src/platforms/orchestrator.ts
2122
+ var exports_orchestrator = {};
2123
+ __export(exports_orchestrator, {
2124
+ syncPlatforms: () => syncPlatforms
1006
2125
  });
1007
- import { spawn } from "node:child_process";
1008
- function inferBillingType(source) {
1009
- if (!source)
1010
- return "api";
1011
- const lower = source.toLowerCase();
1012
- if (lower.includes("desktop") || lower === "cursor")
1013
- return "subscription";
1014
- return "api";
1015
- }
1016
- function normalizeProvider(providerId) {
1017
- const lower = providerId.toLowerCase();
1018
- if (lower.includes("anthropic") || lower.includes("claude"))
1019
- return "anthropic";
1020
- if (lower.includes("openai") || lower.includes("gpt"))
1021
- return "openai";
1022
- if (lower.includes("google") || lower.includes("gemini"))
1023
- return "google";
1024
- return providerId;
1025
- }
1026
- async function runTokscale(options) {
1027
- const args = ["tokscale@latest", "--json"];
1028
- if (options.since) {
1029
- args.push("--since", options.since);
1030
- }
1031
- if (options.until) {
1032
- args.push("--until", options.until);
1033
- }
1034
- if (options.platforms && options.platforms.length > 0) {
1035
- args.push("--platforms", options.platforms.join(","));
1036
- }
1037
- try {
1038
- return await spawnTokscale("bunx", args);
1039
- } catch (err) {
1040
- const nodeErr = err;
1041
- if (nodeErr.code === "ENOENT") {
1042
- return await spawnTokscale("npx", args);
1043
- }
1044
- throw err;
1045
- }
1046
- }
1047
- function spawnTokscale(runner, args) {
1048
- return new Promise((resolve2, reject) => {
1049
- const chunks = [];
1050
- const errChunks = [];
1051
- const child = spawn(runner, args, { stdio: ["ignore", "pipe", "pipe"] });
1052
- child.stdout.on("data", (chunk) => chunks.push(chunk));
1053
- child.stderr.on("data", (chunk) => errChunks.push(chunk));
1054
- child.on("error", (err) => reject(err));
1055
- child.on("close", (code) => {
1056
- if (code !== 0) {
1057
- const stderr = Buffer.concat(errChunks).toString("utf8");
1058
- reject(new Error(`tokscale exited with code ${code}: ${stderr}`));
1059
- return;
1060
- }
1061
- const stdout = Buffer.concat(chunks).toString("utf8");
1062
- try {
1063
- resolve2(JSON.parse(stdout));
1064
- } catch (parseErr) {
1065
- reject(new Error(`Failed to parse tokscale JSON output: ${parseErr.message}`));
1066
- }
1067
- });
1068
- });
1069
- }
1070
- function mapTokscaleToEvents(output, project) {
1071
- const events = [];
1072
- for (const daily of output.daily) {
1073
- for (const source of daily.sources) {
1074
- const event = {
1075
- event_type: "usage",
1076
- provider: normalizeProvider(source.providerId),
1077
- model: source.modelId,
1078
- tokens_in: source.tokens.input,
1079
- tokens_out: source.tokens.output,
1080
- cache_read_tokens: source.tokens.cacheRead,
1081
- cache_write_tokens: source.tokens.cacheWrite,
1082
- cost: source.cost,
1083
- currency: "USD",
1084
- billing_type: inferBillingType(source.source),
1085
- timestamp: `${daily.utcDate}T12:00:00Z`,
1086
- session_id: `tokscale-${daily.utcDate}`,
1087
- request_id: `tokscale:${daily.utcDate}:${source.source}:${source.modelId}`,
1088
- tags: ["tokscale", source.source],
1089
- ...project ? { project } : {},
1090
- metadata: {
1091
- import_source: "tokscale",
1092
- tokscale_intensity: daily.intensity,
1093
- tokscale_message_count: source.messageCount,
1094
- reasoning_tokens: source.tokens.reasoning,
1095
- day_total_cost: daily.totalCost,
1096
- day_total_tokens: daily.totalTokens
1097
- }
1098
- };
1099
- events.push(event);
2126
+ async function syncPlatforms(config, options = {}) {
2127
+ const targets = options.platforms ? options.platforms.map((id) => getParser(id)).filter((p) => p !== undefined) : getAllParsers();
2128
+ const tokscaleState = loadTokscaleState(config.stateDir);
2129
+ const since = options.since ?? tokscaleState.lastSyncDate;
2130
+ const platformResults = [];
2131
+ let totalEvents = 0;
2132
+ let totalCost = 0;
2133
+ const ingestor = new VerbalIngestor({
2134
+ apiKey: config.apiKey,
2135
+ endpoint: config.ingestUrl,
2136
+ hmacSecret: config.hmacSecret,
2137
+ orgId: config.orgId,
2138
+ batchSize: config.batchSize,
2139
+ flushIntervalMs: config.flushIntervalMs,
2140
+ httpTimeoutMs: config.httpTimeoutMs
2141
+ });
2142
+ for (const parser of targets) {
2143
+ try {
2144
+ const state = loadPlatformState(config.stateDir, parser.info.id);
2145
+ const result = await parser.parse(state, {
2146
+ since,
2147
+ until: options.until,
2148
+ captureMode: options.captureMode
2149
+ });
2150
+ const usageEvents = result.events.map((ev) => mapParsedEventToUsageEvent(ev, options.project));
2151
+ let platformCost = 0;
2152
+ for (const event of usageEvents) {
2153
+ platformCost += event.cost ?? 0;
2154
+ await ingestor.track(event);
2155
+ }
2156
+ savePlatformState(config.stateDir, parser.info.id, result.newState);
2157
+ platformResults.push({
2158
+ id: parser.info.id,
2159
+ events: result.events.length,
2160
+ totalCost: platformCost,
2161
+ warnings: result.warnings
2162
+ });
2163
+ totalEvents += result.events.length;
2164
+ totalCost += platformCost;
2165
+ } catch (err) {
2166
+ platformResults.push({
2167
+ id: parser.info.id,
2168
+ events: 0,
2169
+ totalCost: 0,
2170
+ warnings: [],
2171
+ error: `Parser failed: ${err.message}`
2172
+ });
2173
+ continue;
1100
2174
  }
1101
2175
  }
1102
- return events;
2176
+ await ingestor.flush();
2177
+ ingestor.destroy();
2178
+ return { platforms: platformResults, totalEvents, totalCost };
1103
2179
  }
1104
- async function syncFromTokscale(config, options) {
1105
- const state = loadTokscaleState(config.stateDir);
1106
- const since = options.since ?? state.lastSyncDate;
1107
- const until = options.until;
1108
- const platforms = options.platforms;
1109
- const output = await runTokscale({ since, until, platforms });
1110
- const events = mapTokscaleToEvents(output, options.project);
1111
- if (events.length > 0) {
1112
- const ingestor = new VerbalIngestor({
1113
- apiKey: config.apiKey,
1114
- endpoint: config.ingestUrl,
1115
- hmacSecret: config.hmacSecret,
1116
- orgId: config.orgId,
1117
- batchSize: config.batchSize,
1118
- flushIntervalMs: config.flushIntervalMs,
1119
- httpTimeoutMs: config.httpTimeoutMs
1120
- });
1121
- for (const event of events) {
1122
- await ingestor.track(event);
1123
- }
1124
- await ingestor.flush();
1125
- }
1126
- const today = new Date().toISOString().slice(0, 10);
1127
- const newState = {
1128
- lastSyncDate: output.metadata.endDate ?? today,
1129
- lastSyncTimestamp: new Date().toISOString(),
1130
- platformsSynced: platforms
1131
- };
1132
- saveTokscaleState(config.stateDir, newState);
1133
- const totalCost = events.reduce((sum, e) => sum + (e.cost ?? 0), 0);
2180
+ function mapParsedEventToUsageEvent(event, project) {
2181
+ const cost = event.billing_type === "subscription" ? 0 : calculateCost(event.model, event.tokens_in, event.tokens_out, event.cache_read_tokens, event.cache_write_tokens);
1134
2182
  return {
1135
- days: output.daily.length,
1136
- events: events.length,
1137
- totalCost
2183
+ event_id: event.event_id,
2184
+ event_type: "usage",
2185
+ provider: event.provider,
2186
+ model: event.model,
2187
+ tokens_in: event.tokens_in,
2188
+ tokens_out: event.tokens_out,
2189
+ total_tokens: event.tokens_in + event.tokens_out,
2190
+ cache_read_tokens: event.cache_read_tokens,
2191
+ cache_write_tokens: event.cache_write_tokens,
2192
+ cost,
2193
+ billing_type: event.billing_type,
2194
+ timestamp: event.timestamp,
2195
+ session_id: event.session_id,
2196
+ request_id: event.request_id,
2197
+ tags: event.tags,
2198
+ ...project ? { project } : {},
2199
+ prompt: event.prompt,
2200
+ response: event.response,
2201
+ metadata: {
2202
+ ...event.metadata,
2203
+ import_source: "native-parser"
2204
+ }
1138
2205
  };
1139
2206
  }
1140
- var init_tokscale = __esm(() => {
2207
+ var init_orchestrator = __esm(() => {
1141
2208
  init_ingestor();
2209
+ init_pricing();
1142
2210
  init_state();
2211
+ init_registry();
2212
+ init_state2();
1143
2213
  });
1144
2214
 
1145
2215
  // src/update-check/check.ts
@@ -1148,9 +2218,9 @@ __export(exports_check, {
1148
2218
  checkForUpdate: () => checkForUpdate
1149
2219
  });
1150
2220
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
1151
- import { join as join12 } from "node:path";
2221
+ import { join as join13 } from "node:path";
1152
2222
  function getCachePath() {
1153
- return join12(getCredentialsDir(), CACHE_FILE);
2223
+ return join13(getCredentialsDir(), CACHE_FILE);
1154
2224
  }
1155
2225
  function readCache() {
1156
2226
  try {
@@ -1240,9 +2310,9 @@ var exports_import2 = {};
1240
2310
  __export(exports_import2, {
1241
2311
  runImport: () => runImport
1242
2312
  });
1243
- import { existsSync as existsSync8 } from "node:fs";
1244
- import { join as join13 } from "node:path";
1245
- import { homedir as homedir11 } from "node:os";
2313
+ import { existsSync as existsSync9 } from "node:fs";
2314
+ import { join as join14 } from "node:path";
2315
+ import { homedir as homedir12 } from "node:os";
1246
2316
  import { createInterface as createInterface3 } from "node:readline";
1247
2317
  async function runImport() {
1248
2318
  console.log(`
@@ -1310,10 +2380,9 @@ async function runImport() {
1310
2380
  async function handleLocalImport(source, creds) {
1311
2381
  console.log(`
1312
2382
  Importing ${source.id}...`);
1313
- const { syncFromTokscale: syncFromTokscale2 } = await Promise.resolve().then(() => (init_tokscale(), exports_tokscale));
1314
- const stateDir = join13(homedir11(), ".config", "getverbal");
1315
- const platform = source.id === "claude-code" ? "claude" : "codex";
1316
- const result = await syncFromTokscale2({
2383
+ const { syncPlatforms: syncPlatforms2 } = await Promise.resolve().then(() => (init_orchestrator(), exports_orchestrator));
2384
+ const stateDir = join14(homedir12(), ".config", "getverbal");
2385
+ const result = await syncPlatforms2({
1317
2386
  apiKey: creds.api_key,
1318
2387
  ingestUrl: creds.ingest_url,
1319
2388
  batchSize: 100,
@@ -1321,12 +2390,12 @@ async function handleLocalImport(source, creds) {
1321
2390
  httpTimeoutMs: 30000,
1322
2391
  stateDir
1323
2392
  }, {
1324
- platforms: [platform]
2393
+ platforms: [source.id]
1325
2394
  });
1326
- console.log(import_picocolors6.default.green(` ✓ ${result.events} events imported from ${source.id}`));
2395
+ console.log(import_picocolors6.default.green(` ✓ ${result.totalEvents} events imported from ${source.id}`));
1327
2396
  }
1328
2397
  async function handleFileImport(filePath, source, creds) {
1329
- if (!existsSync8(filePath)) {
2398
+ if (!existsSync9(filePath)) {
1330
2399
  console.error(import_picocolors6.default.red(` File not found: ${filePath}`));
1331
2400
  process.exitCode = 1;
1332
2401
  return;
@@ -1371,7 +2440,7 @@ var exports_update = {};
1371
2440
  __export(exports_update, {
1372
2441
  runUpdate: () => runUpdate
1373
2442
  });
1374
- import { execSync as execSync7 } from "node:child_process";
2443
+ import { execSync as execSync8 } from "node:child_process";
1375
2444
  async function runUpdate(currentVersion) {
1376
2445
  console.log(`
1377
2446
  ${import_picocolors7.default.bold("Verbal")} — Update
@@ -1405,7 +2474,7 @@ async function runUpdate(currentVersion) {
1405
2474
  const installCmd = pm === "bun" ? `bun install -g @getverbal/cli@${latest}` : `npm install -g @getverbal/cli@${latest}`;
1406
2475
  console.log(` Running: ${import_picocolors7.default.dim(installCmd)}`);
1407
2476
  try {
1408
- execSync7(installCmd, { stdio: "inherit" });
2477
+ execSync8(installCmd, { stdio: "inherit" });
1409
2478
  console.log(import_picocolors7.default.green(`
1410
2479
  Updated getverbal ${currentVersion} → ${latest}`));
1411
2480
  } catch {
@@ -1417,7 +2486,7 @@ async function runUpdate(currentVersion) {
1417
2486
  }
1418
2487
  function detectPackageManager() {
1419
2488
  try {
1420
- const which = execSync7("which getverbal", { encoding: "utf-8" }).trim();
2489
+ const which = execSync8("which getverbal", { encoding: "utf-8" }).trim();
1421
2490
  if (which.includes(".bun/"))
1422
2491
  return "bun";
1423
2492
  } catch {}
@@ -1429,7 +2498,7 @@ var init_update = __esm(() => {
1429
2498
  import_picocolors7 = __toESM(require_picocolors(), 1);
1430
2499
  });
1431
2500
 
1432
- // node_modules/zod/v4/core/core.js
2501
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/core.js
1433
2502
  function $constructor(name, initializer, params) {
1434
2503
  function init(inst, def) {
1435
2504
  var _a;
@@ -1492,7 +2561,7 @@ var init_core = __esm(() => {
1492
2561
  globalConfig = {};
1493
2562
  });
1494
2563
 
1495
- // node_modules/zod/v4/core/util.js
2564
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/util.js
1496
2565
  var exports_util = {};
1497
2566
  __export(exports_util, {
1498
2567
  unwrapMessage: () => unwrapMessage,
@@ -1625,10 +2694,10 @@ function assignProp(target, prop, value) {
1625
2694
  configurable: true
1626
2695
  });
1627
2696
  }
1628
- function getElementAtPath(obj, path4) {
1629
- if (!path4)
2697
+ function getElementAtPath(obj, path11) {
2698
+ if (!path11)
1630
2699
  return obj;
1631
- return path4.reduce((acc, key) => acc?.[key], obj);
2700
+ return path11.reduce((acc, key) => acc?.[key], obj);
1632
2701
  }
1633
2702
  function promiseAllObject(promisesObj) {
1634
2703
  const keys = Object.keys(promisesObj);
@@ -1874,11 +2943,11 @@ function aborted(x, startIndex = 0) {
1874
2943
  }
1875
2944
  return false;
1876
2945
  }
1877
- function prefixIssues(path4, issues) {
2946
+ function prefixIssues(path11, issues) {
1878
2947
  return issues.map((iss) => {
1879
2948
  var _a;
1880
2949
  (_a = iss).path ?? (_a.path = []);
1881
- iss.path.unshift(path4);
2950
+ iss.path.unshift(path11);
1882
2951
  return iss;
1883
2952
  });
1884
2953
  }
@@ -2008,7 +3077,7 @@ var init_util = __esm(() => {
2008
3077
  };
2009
3078
  });
2010
3079
 
2011
- // node_modules/zod/v4/core/errors.js
3080
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/errors.js
2012
3081
  function flattenError(error, mapper = (issue2) => issue2.message) {
2013
3082
  const fieldErrors = {};
2014
3083
  const formErrors = [];
@@ -2086,7 +3155,7 @@ var init_errors = __esm(() => {
2086
3155
  $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error });
2087
3156
  });
2088
3157
 
2089
- // node_modules/zod/v4/core/parse.js
3158
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/parse.js
2090
3159
  var _parse = (_Err) => (schema, value, _ctx, _params) => {
2091
3160
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
2092
3161
  const result = schema._zod.run({ value, issues: [] }, ctx);
@@ -2138,7 +3207,7 @@ var init_parse = __esm(() => {
2138
3207
  safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
2139
3208
  });
2140
3209
 
2141
- // node_modules/zod/v4/core/regexes.js
3210
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/regexes.js
2142
3211
  function emoji() {
2143
3212
  return new RegExp(_emoji, "u");
2144
3213
  }
@@ -2195,7 +3264,7 @@ var init_regexes = __esm(() => {
2195
3264
  uppercase = /^[^a-z]*$/;
2196
3265
  });
2197
3266
 
2198
- // node_modules/zod/v4/core/checks.js
3267
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/checks.js
2199
3268
  var $ZodCheck, numericOriginMap, $ZodCheckLessThan, $ZodCheckGreaterThan, $ZodCheckMultipleOf, $ZodCheckNumberFormat, $ZodCheckMaxLength, $ZodCheckMinLength, $ZodCheckLengthEquals, $ZodCheckStringFormat, $ZodCheckRegex, $ZodCheckLowerCase, $ZodCheckUpperCase, $ZodCheckIncludes, $ZodCheckStartsWith, $ZodCheckEndsWith, $ZodCheckOverwrite;
2200
3269
  var init_checks = __esm(() => {
2201
3270
  init_core();
@@ -2585,7 +3654,7 @@ var init_checks = __esm(() => {
2585
3654
  });
2586
3655
  });
2587
3656
 
2588
- // node_modules/zod/v4/core/doc.js
3657
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/doc.js
2589
3658
  class Doc {
2590
3659
  constructor(args = []) {
2591
3660
  this.content = [];
@@ -2623,7 +3692,7 @@ class Doc {
2623
3692
  }
2624
3693
  }
2625
3694
 
2626
- // node_modules/zod/v4/core/versions.js
3695
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/versions.js
2627
3696
  var version;
2628
3697
  var init_versions = __esm(() => {
2629
3698
  version = {
@@ -2633,7 +3702,7 @@ var init_versions = __esm(() => {
2633
3702
  };
2634
3703
  });
2635
3704
 
2636
- // node_modules/zod/v4/core/schemas.js
3705
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/schemas.js
2637
3706
  function isValidBase64(data) {
2638
3707
  if (data === "")
2639
3708
  return true;
@@ -3875,7 +4944,7 @@ var init_schemas = __esm(() => {
3875
4944
  });
3876
4945
  });
3877
4946
 
3878
- // node_modules/zod/v4/locales/en.js
4947
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/en.js
3879
4948
  function en_default() {
3880
4949
  return {
3881
4950
  localeError: error()
@@ -3995,10 +5064,10 @@ var init_en = __esm(() => {
3995
5064
  init_util();
3996
5065
  });
3997
5066
 
3998
- // node_modules/zod/v4/locales/index.js
5067
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/index.js
3999
5068
  var init_locales = () => {};
4000
5069
 
4001
- // node_modules/zod/v4/core/registries.js
5070
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/registries.js
4002
5071
  class $ZodRegistry {
4003
5072
  constructor() {
4004
5073
  this._map = new Map;
@@ -4051,7 +5120,7 @@ var init_registries = __esm(() => {
4051
5120
  globalRegistry = /* @__PURE__ */ registry();
4052
5121
  });
4053
5122
 
4054
- // node_modules/zod/v4/core/api.js
5123
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/api.js
4055
5124
  function _string(Class2, params) {
4056
5125
  return new Class2({
4057
5126
  type: "string",
@@ -4491,16 +5560,16 @@ var init_api = __esm(() => {
4491
5560
  init_util();
4492
5561
  });
4493
5562
 
4494
- // node_modules/zod/v4/core/function.js
5563
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/function.js
4495
5564
  var init_function = () => {};
4496
5565
 
4497
- // node_modules/zod/v4/core/to-json-schema.js
5566
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/to-json-schema.js
4498
5567
  var init_to_json_schema = () => {};
4499
5568
 
4500
- // node_modules/zod/v4/core/json-schema.js
5569
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/json-schema.js
4501
5570
  var init_json_schema = () => {};
4502
5571
 
4503
- // node_modules/zod/v4/core/index.js
5572
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/index.js
4504
5573
  var init_core2 = __esm(() => {
4505
5574
  init_util();
4506
5575
  init_regexes();
@@ -4518,24 +5587,24 @@ var init_core2 = __esm(() => {
4518
5587
  init_to_json_schema();
4519
5588
  });
4520
5589
 
4521
- // node_modules/zod/v4/mini/parse.js
5590
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/parse.js
4522
5591
  var init_parse2 = __esm(() => {
4523
5592
  init_core2();
4524
5593
  });
4525
5594
 
4526
- // node_modules/zod/v4/mini/schemas.js
5595
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/schemas.js
4527
5596
  var init_schemas2 = () => {};
4528
5597
 
4529
- // node_modules/zod/v4/mini/checks.js
5598
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/checks.js
4530
5599
  var init_checks2 = () => {};
4531
5600
 
4532
- // node_modules/zod/v4/mini/iso.js
5601
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/iso.js
4533
5602
  var init_iso = () => {};
4534
5603
 
4535
- // node_modules/zod/v4/mini/coerce.js
5604
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/coerce.js
4536
5605
  var init_coerce = () => {};
4537
5606
 
4538
- // node_modules/zod/v4/mini/external.js
5607
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/external.js
4539
5608
  var init_external = __esm(() => {
4540
5609
  init_core2();
4541
5610
  init_locales();
@@ -4546,17 +5615,17 @@ var init_external = __esm(() => {
4546
5615
  init_checks2();
4547
5616
  });
4548
5617
 
4549
- // node_modules/zod/v4/mini/index.js
5618
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/mini/index.js
4550
5619
  var init_mini = __esm(() => {
4551
5620
  init_external();
4552
5621
  });
4553
5622
 
4554
- // node_modules/zod/v4-mini/index.js
5623
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4-mini/index.js
4555
5624
  var init_v4_mini = __esm(() => {
4556
5625
  init_mini();
4557
5626
  });
4558
5627
 
4559
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
5628
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
4560
5629
  function isZ4Schema(s) {
4561
5630
  const schema = s;
4562
5631
  return !!schema._zod;
@@ -4622,12 +5691,12 @@ var init_zod_compat = __esm(() => {
4622
5691
  init_v4_mini();
4623
5692
  });
4624
5693
 
4625
- // node_modules/zod/v4/classic/checks.js
5694
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/checks.js
4626
5695
  var init_checks3 = __esm(() => {
4627
5696
  init_core2();
4628
5697
  });
4629
5698
 
4630
- // node_modules/zod/v4/classic/iso.js
5699
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/iso.js
4631
5700
  var exports_iso2 = {};
4632
5701
  __export(exports_iso2, {
4633
5702
  time: () => time2,
@@ -4673,7 +5742,7 @@ var init_iso2 = __esm(() => {
4673
5742
  });
4674
5743
  });
4675
5744
 
4676
- // node_modules/zod/v4/classic/errors.js
5745
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/errors.js
4677
5746
  var initializer2 = (inst, issues) => {
4678
5747
  $ZodError.init(inst, issues);
4679
5748
  inst.name = "ZodError";
@@ -4706,7 +5775,7 @@ var init_errors2 = __esm(() => {
4706
5775
  });
4707
5776
  });
4708
5777
 
4709
- // node_modules/zod/v4/classic/parse.js
5778
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/parse.js
4710
5779
  var parse4, parseAsync2, safeParse3, safeParseAsync2;
4711
5780
  var init_parse3 = __esm(() => {
4712
5781
  init_core2();
@@ -4717,7 +5786,7 @@ var init_parse3 = __esm(() => {
4717
5786
  safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
4718
5787
  });
4719
5788
 
4720
- // node_modules/zod/v4/classic/schemas.js
5789
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/schemas.js
4721
5790
  function string2(params) {
4722
5791
  return _string(ZodString, params);
4723
5792
  }
@@ -5331,13 +6400,13 @@ var init_schemas3 = __esm(() => {
5331
6400
  });
5332
6401
  });
5333
6402
 
5334
- // node_modules/zod/v4/classic/compat.js
6403
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/compat.js
5335
6404
  var init_compat = () => {};
5336
6405
 
5337
- // node_modules/zod/v4/classic/coerce.js
6406
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/coerce.js
5338
6407
  var init_coerce2 = () => {};
5339
6408
 
5340
- // node_modules/zod/v4/classic/external.js
6409
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/external.js
5341
6410
  var init_external2 = __esm(() => {
5342
6411
  init_core2();
5343
6412
  init_core2();
@@ -5353,17 +6422,17 @@ var init_external2 = __esm(() => {
5353
6422
  config(en_default());
5354
6423
  });
5355
6424
 
5356
- // node_modules/zod/v4/classic/index.js
6425
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/index.js
5357
6426
  var init_classic = __esm(() => {
5358
6427
  init_external2();
5359
6428
  });
5360
6429
 
5361
- // node_modules/zod/v4/index.js
6430
+ // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/index.js
5362
6431
  var init_v4 = __esm(() => {
5363
6432
  init_classic();
5364
6433
  });
5365
6434
 
5366
- // node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
6435
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
5367
6436
  var LATEST_PROTOCOL_VERSION = "2025-11-25", SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task", JSONRPC_VERSION = "2.0", AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams = (value) => TaskAugmentedRequestParamsSchema.safeParse(value).success, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success, JSONRPCNotificationSchema, isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success, JSONRPCResultResponseSchema, isJSONRPCResultResponse = (value) => JSONRPCResultResponseSchema.safeParse(value).success, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse = (value) => JSONRPCErrorResponseSchema.safeParse(value).success, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
5368
6437
  var init_types = __esm(() => {
5369
6438
  init_v4();
@@ -6188,65 +7257,65 @@ var init_types = __esm(() => {
6188
7257
  };
6189
7258
  });
6190
7259
 
6191
- // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
7260
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
6192
7261
  function isTerminal(status) {
6193
7262
  return status === "completed" || status === "failed" || status === "cancelled";
6194
7263
  }
6195
7264
 
6196
- // node_modules/zod-to-json-schema/dist/esm/Options.js
7265
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Options.js
6197
7266
  var ignoreOverride;
6198
7267
  var init_Options = __esm(() => {
6199
7268
  ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
6200
7269
  });
6201
7270
 
6202
- // node_modules/zod-to-json-schema/dist/esm/Refs.js
7271
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Refs.js
6203
7272
  var init_Refs = __esm(() => {
6204
7273
  init_Options();
6205
7274
  });
6206
- // node_modules/zod-to-json-schema/dist/esm/parsers/any.js
7275
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/any.js
6207
7276
  var init_any = () => {};
6208
7277
 
6209
- // node_modules/zod-to-json-schema/dist/esm/parsers/array.js
7278
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/array.js
6210
7279
  var init_array = __esm(() => {
6211
7280
  init_parseDef();
6212
7281
  });
6213
7282
 
6214
- // node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js
7283
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js
6215
7284
  var init_bigint = () => {};
6216
- // node_modules/zod-to-json-schema/dist/esm/parsers/branded.js
7285
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js
6217
7286
  var init_branded = __esm(() => {
6218
7287
  init_parseDef();
6219
7288
  });
6220
7289
 
6221
- // node_modules/zod-to-json-schema/dist/esm/parsers/catch.js
7290
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js
6222
7291
  var init_catch = __esm(() => {
6223
7292
  init_parseDef();
6224
7293
  });
6225
7294
 
6226
- // node_modules/zod-to-json-schema/dist/esm/parsers/date.js
7295
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/date.js
6227
7296
  var init_date = () => {};
6228
7297
 
6229
- // node_modules/zod-to-json-schema/dist/esm/parsers/default.js
7298
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/default.js
6230
7299
  var init_default = __esm(() => {
6231
7300
  init_parseDef();
6232
7301
  });
6233
7302
 
6234
- // node_modules/zod-to-json-schema/dist/esm/parsers/effects.js
7303
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js
6235
7304
  var init_effects = __esm(() => {
6236
7305
  init_parseDef();
6237
7306
  init_any();
6238
7307
  });
6239
- // node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js
7308
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js
6240
7309
  var init_intersection = __esm(() => {
6241
7310
  init_parseDef();
6242
7311
  });
6243
- // node_modules/zod-to-json-schema/dist/esm/parsers/string.js
7312
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/string.js
6244
7313
  var ALPHA_NUMERIC;
6245
7314
  var init_string = __esm(() => {
6246
7315
  ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
6247
7316
  });
6248
7317
 
6249
- // node_modules/zod-to-json-schema/dist/esm/parsers/record.js
7318
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/record.js
6250
7319
  var init_record = __esm(() => {
6251
7320
  init_parseDef();
6252
7321
  init_string();
@@ -6254,77 +7323,77 @@ var init_record = __esm(() => {
6254
7323
  init_any();
6255
7324
  });
6256
7325
 
6257
- // node_modules/zod-to-json-schema/dist/esm/parsers/map.js
7326
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/map.js
6258
7327
  var init_map = __esm(() => {
6259
7328
  init_parseDef();
6260
7329
  init_record();
6261
7330
  init_any();
6262
7331
  });
6263
- // node_modules/zod-to-json-schema/dist/esm/parsers/never.js
7332
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/never.js
6264
7333
  var init_never = __esm(() => {
6265
7334
  init_any();
6266
7335
  });
6267
- // node_modules/zod-to-json-schema/dist/esm/parsers/union.js
7336
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/union.js
6268
7337
  var init_union = __esm(() => {
6269
7338
  init_parseDef();
6270
7339
  });
6271
7340
 
6272
- // node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js
7341
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js
6273
7342
  var init_nullable = __esm(() => {
6274
7343
  init_parseDef();
6275
7344
  init_union();
6276
7345
  });
6277
7346
 
6278
- // node_modules/zod-to-json-schema/dist/esm/parsers/number.js
7347
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/number.js
6279
7348
  var init_number = () => {};
6280
7349
 
6281
- // node_modules/zod-to-json-schema/dist/esm/parsers/object.js
7350
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/object.js
6282
7351
  var init_object = __esm(() => {
6283
7352
  init_parseDef();
6284
7353
  });
6285
7354
 
6286
- // node_modules/zod-to-json-schema/dist/esm/parsers/optional.js
7355
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js
6287
7356
  var init_optional = __esm(() => {
6288
7357
  init_parseDef();
6289
7358
  init_any();
6290
7359
  });
6291
7360
 
6292
- // node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js
7361
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js
6293
7362
  var init_pipeline = __esm(() => {
6294
7363
  init_parseDef();
6295
7364
  });
6296
7365
 
6297
- // node_modules/zod-to-json-schema/dist/esm/parsers/promise.js
7366
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js
6298
7367
  var init_promise = __esm(() => {
6299
7368
  init_parseDef();
6300
7369
  });
6301
7370
 
6302
- // node_modules/zod-to-json-schema/dist/esm/parsers/set.js
7371
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/set.js
6303
7372
  var init_set = __esm(() => {
6304
7373
  init_parseDef();
6305
7374
  });
6306
7375
 
6307
- // node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js
7376
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js
6308
7377
  var init_tuple = __esm(() => {
6309
7378
  init_parseDef();
6310
7379
  });
6311
7380
 
6312
- // node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js
7381
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js
6313
7382
  var init_undefined = __esm(() => {
6314
7383
  init_any();
6315
7384
  });
6316
7385
 
6317
- // node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js
7386
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js
6318
7387
  var init_unknown = __esm(() => {
6319
7388
  init_any();
6320
7389
  });
6321
7390
 
6322
- // node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js
7391
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js
6323
7392
  var init_readonly = __esm(() => {
6324
7393
  init_parseDef();
6325
7394
  });
6326
7395
 
6327
- // node_modules/zod-to-json-schema/dist/esm/selectParser.js
7396
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/selectParser.js
6328
7397
  var init_selectParser = __esm(() => {
6329
7398
  init_any();
6330
7399
  init_array();
@@ -6353,24 +7422,24 @@ var init_selectParser = __esm(() => {
6353
7422
  init_readonly();
6354
7423
  });
6355
7424
 
6356
- // node_modules/zod-to-json-schema/dist/esm/parseDef.js
7425
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parseDef.js
6357
7426
  var init_parseDef = __esm(() => {
6358
7427
  init_Options();
6359
7428
  init_selectParser();
6360
7429
  init_any();
6361
7430
  });
6362
7431
 
6363
- // node_modules/zod-to-json-schema/dist/esm/parseTypes.js
7432
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parseTypes.js
6364
7433
  var init_parseTypes = () => {};
6365
7434
 
6366
- // node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js
7435
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js
6367
7436
  var init_zodToJsonSchema = __esm(() => {
6368
7437
  init_parseDef();
6369
7438
  init_Refs();
6370
7439
  init_any();
6371
7440
  });
6372
7441
 
6373
- // node_modules/zod-to-json-schema/dist/esm/index.js
7442
+ // node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/index.js
6374
7443
  var init_esm = __esm(() => {
6375
7444
  init_zodToJsonSchema();
6376
7445
  init_Options();
@@ -6406,7 +7475,7 @@ var init_esm = __esm(() => {
6406
7475
  init_zodToJsonSchema();
6407
7476
  });
6408
7477
 
6409
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
7478
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
6410
7479
  function getMethodLiteral(schema) {
6411
7480
  const shape = getObjectShape(schema);
6412
7481
  const methodSchema = shape?.method;
@@ -6431,7 +7500,7 @@ var init_zod_json_schema_compat = __esm(() => {
6431
7500
  init_esm();
6432
7501
  });
6433
7502
 
6434
- // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
7503
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
6435
7504
  class Protocol {
6436
7505
  constructor(_options) {
6437
7506
  this._options = _options;
@@ -7270,7 +8339,7 @@ var init_protocol = __esm(() => {
7270
8339
  init_zod_json_schema_compat();
7271
8340
  });
7272
8341
 
7273
- // node_modules/ajv/dist/compile/codegen/code.js
8342
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
7274
8343
  var require_code = __commonJS((exports) => {
7275
8344
  Object.defineProperty(exports, "__esModule", { value: true });
7276
8345
  exports.regexpCode = exports.getEsmExportName = exports.getProperty = exports.safeStringify = exports.stringify = exports.strConcat = exports.addCodeArg = exports.str = exports._ = exports.nil = exports._Code = exports.Name = exports.IDENTIFIER = exports._CodeOrName = undefined;
@@ -7424,7 +8493,7 @@ var require_code = __commonJS((exports) => {
7424
8493
  exports.regexpCode = regexpCode;
7425
8494
  });
7426
8495
 
7427
- // node_modules/ajv/dist/compile/codegen/scope.js
8496
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/scope.js
7428
8497
  var require_scope = __commonJS((exports) => {
7429
8498
  Object.defineProperty(exports, "__esModule", { value: true });
7430
8499
  exports.ValueScope = exports.ValueScopeName = exports.Scope = exports.varKinds = exports.UsedValueState = undefined;
@@ -7570,7 +8639,7 @@ var require_scope = __commonJS((exports) => {
7570
8639
  exports.ValueScope = ValueScope;
7571
8640
  });
7572
8641
 
7573
- // node_modules/ajv/dist/compile/codegen/index.js
8642
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/index.js
7574
8643
  var require_codegen = __commonJS((exports) => {
7575
8644
  Object.defineProperty(exports, "__esModule", { value: true });
7576
8645
  exports.or = exports.and = exports.not = exports.CodeGen = exports.operators = exports.varKinds = exports.ValueScopeName = exports.ValueScope = exports.Scope = exports.Name = exports.regexpCode = exports.stringify = exports.getProperty = exports.nil = exports.strConcat = exports.str = exports._ = undefined;
@@ -8280,7 +9349,7 @@ var require_codegen = __commonJS((exports) => {
8280
9349
  }
8281
9350
  });
8282
9351
 
8283
- // node_modules/ajv/dist/compile/util.js
9352
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/util.js
8284
9353
  var require_util = __commonJS((exports) => {
8285
9354
  Object.defineProperty(exports, "__esModule", { value: true });
8286
9355
  exports.checkStrictMode = exports.getErrorPath = exports.Type = exports.useFunc = exports.setEvaluated = exports.evaluatedPropsToName = exports.mergeEvaluated = exports.eachItem = exports.unescapeJsonPointer = exports.escapeJsonPointer = exports.escapeFragment = exports.unescapeFragment = exports.schemaRefOrVal = exports.schemaHasRulesButRef = exports.schemaHasRules = exports.checkUnknownRules = exports.alwaysValidSchema = exports.toHash = undefined;
@@ -8444,7 +9513,7 @@ var require_util = __commonJS((exports) => {
8444
9513
  exports.checkStrictMode = checkStrictMode;
8445
9514
  });
8446
9515
 
8447
- // node_modules/ajv/dist/compile/names.js
9516
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/names.js
8448
9517
  var require_names = __commonJS((exports) => {
8449
9518
  Object.defineProperty(exports, "__esModule", { value: true });
8450
9519
  var codegen_1 = require_codegen();
@@ -8469,7 +9538,7 @@ var require_names = __commonJS((exports) => {
8469
9538
  exports.default = names;
8470
9539
  });
8471
9540
 
8472
- // node_modules/ajv/dist/compile/errors.js
9541
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/errors.js
8473
9542
  var require_errors = __commonJS((exports) => {
8474
9543
  Object.defineProperty(exports, "__esModule", { value: true });
8475
9544
  exports.extendErrors = exports.resetErrorsCount = exports.reportExtraError = exports.reportError = exports.keyword$DataError = exports.keywordError = undefined;
@@ -8587,7 +9656,7 @@ var require_errors = __commonJS((exports) => {
8587
9656
  }
8588
9657
  });
8589
9658
 
8590
- // node_modules/ajv/dist/compile/validate/boolSchema.js
9659
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/boolSchema.js
8591
9660
  var require_boolSchema = __commonJS((exports) => {
8592
9661
  Object.defineProperty(exports, "__esModule", { value: true });
8593
9662
  exports.boolOrEmptySchema = exports.topBoolOrEmptySchema = undefined;
@@ -8635,7 +9704,7 @@ var require_boolSchema = __commonJS((exports) => {
8635
9704
  }
8636
9705
  });
8637
9706
 
8638
- // node_modules/ajv/dist/compile/rules.js
9707
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/rules.js
8639
9708
  var require_rules = __commonJS((exports) => {
8640
9709
  Object.defineProperty(exports, "__esModule", { value: true });
8641
9710
  exports.getRules = exports.isJSONType = undefined;
@@ -8663,7 +9732,7 @@ var require_rules = __commonJS((exports) => {
8663
9732
  exports.getRules = getRules;
8664
9733
  });
8665
9734
 
8666
- // node_modules/ajv/dist/compile/validate/applicability.js
9735
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/applicability.js
8667
9736
  var require_applicability = __commonJS((exports) => {
8668
9737
  Object.defineProperty(exports, "__esModule", { value: true });
8669
9738
  exports.shouldUseRule = exports.shouldUseGroup = exports.schemaHasRulesForType = undefined;
@@ -8683,7 +9752,7 @@ var require_applicability = __commonJS((exports) => {
8683
9752
  exports.shouldUseRule = shouldUseRule;
8684
9753
  });
8685
9754
 
8686
- // node_modules/ajv/dist/compile/validate/dataType.js
9755
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/dataType.js
8687
9756
  var require_dataType = __commonJS((exports) => {
8688
9757
  Object.defineProperty(exports, "__esModule", { value: true });
8689
9758
  exports.reportTypeError = exports.checkDataTypes = exports.checkDataType = exports.coerceAndCheckDataType = exports.getJSONTypes = exports.getSchemaTypes = exports.DataType = undefined;
@@ -8864,7 +9933,7 @@ var require_dataType = __commonJS((exports) => {
8864
9933
  }
8865
9934
  });
8866
9935
 
8867
- // node_modules/ajv/dist/compile/validate/defaults.js
9936
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/defaults.js
8868
9937
  var require_defaults = __commonJS((exports) => {
8869
9938
  Object.defineProperty(exports, "__esModule", { value: true });
8870
9939
  exports.assignDefaults = undefined;
@@ -8898,7 +9967,7 @@ var require_defaults = __commonJS((exports) => {
8898
9967
  }
8899
9968
  });
8900
9969
 
8901
- // node_modules/ajv/dist/vocabularies/code.js
9970
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/code.js
8902
9971
  var require_code2 = __commonJS((exports) => {
8903
9972
  Object.defineProperty(exports, "__esModule", { value: true });
8904
9973
  exports.validateUnion = exports.validateArray = exports.usePattern = exports.callValidateCode = exports.schemaProperties = exports.allSchemaProperties = exports.noPropertyInData = exports.propertyInData = exports.isOwnProperty = exports.hasPropFunc = exports.reportMissingProp = exports.checkMissingProp = exports.checkReportMissingProp = undefined;
@@ -9027,7 +10096,7 @@ var require_code2 = __commonJS((exports) => {
9027
10096
  exports.validateUnion = validateUnion;
9028
10097
  });
9029
10098
 
9030
- // node_modules/ajv/dist/compile/validate/keyword.js
10099
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/keyword.js
9031
10100
  var require_keyword = __commonJS((exports) => {
9032
10101
  Object.defineProperty(exports, "__esModule", { value: true });
9033
10102
  exports.validateKeywordUsage = exports.validSchemaType = exports.funcKeywordCode = exports.macroKeywordCode = undefined;
@@ -9142,7 +10211,7 @@ var require_keyword = __commonJS((exports) => {
9142
10211
  exports.validateKeywordUsage = validateKeywordUsage;
9143
10212
  });
9144
10213
 
9145
- // node_modules/ajv/dist/compile/validate/subschema.js
10214
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/subschema.js
9146
10215
  var require_subschema = __commonJS((exports) => {
9147
10216
  Object.defineProperty(exports, "__esModule", { value: true });
9148
10217
  exports.extendSubschemaMode = exports.extendSubschemaData = exports.getSubschema = undefined;
@@ -9222,7 +10291,7 @@ var require_subschema = __commonJS((exports) => {
9222
10291
  exports.extendSubschemaMode = extendSubschemaMode;
9223
10292
  });
9224
10293
 
9225
- // node_modules/fast-deep-equal/index.js
10294
+ // node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js
9226
10295
  var require_fast_deep_equal = __commonJS((exports, module) => {
9227
10296
  module.exports = function equal(a, b) {
9228
10297
  if (a === b)
@@ -9264,7 +10333,7 @@ var require_fast_deep_equal = __commonJS((exports, module) => {
9264
10333
  };
9265
10334
  });
9266
10335
 
9267
- // node_modules/json-schema-traverse/index.js
10336
+ // node_modules/.pnpm/json-schema-traverse@1.0.0/node_modules/json-schema-traverse/index.js
9268
10337
  var require_json_schema_traverse = __commonJS((exports, module) => {
9269
10338
  var traverse = module.exports = function(schema, opts, cb) {
9270
10339
  if (typeof opts == "function") {
@@ -9347,7 +10416,7 @@ var require_json_schema_traverse = __commonJS((exports, module) => {
9347
10416
  }
9348
10417
  });
9349
10418
 
9350
- // node_modules/ajv/dist/compile/resolve.js
10419
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/resolve.js
9351
10420
  var require_resolve = __commonJS((exports) => {
9352
10421
  Object.defineProperty(exports, "__esModule", { value: true });
9353
10422
  exports.getSchemaRefs = exports.resolveUrl = exports.normalizeId = exports._getFullPath = exports.getFullPath = exports.inlineRef = undefined;
@@ -9500,7 +10569,7 @@ var require_resolve = __commonJS((exports) => {
9500
10569
  exports.getSchemaRefs = getSchemaRefs;
9501
10570
  });
9502
10571
 
9503
- // node_modules/ajv/dist/compile/validate/index.js
10572
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/validate/index.js
9504
10573
  var require_validate = __commonJS((exports) => {
9505
10574
  Object.defineProperty(exports, "__esModule", { value: true });
9506
10575
  exports.getData = exports.KeywordCxt = exports.validateFunctionCode = undefined;
@@ -10005,7 +11074,7 @@ var require_validate = __commonJS((exports) => {
10005
11074
  exports.getData = getData;
10006
11075
  });
10007
11076
 
10008
- // node_modules/ajv/dist/runtime/validation_error.js
11077
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/runtime/validation_error.js
10009
11078
  var require_validation_error = __commonJS((exports) => {
10010
11079
  Object.defineProperty(exports, "__esModule", { value: true });
10011
11080
 
@@ -10019,7 +11088,7 @@ var require_validation_error = __commonJS((exports) => {
10019
11088
  exports.default = ValidationError;
10020
11089
  });
10021
11090
 
10022
- // node_modules/ajv/dist/compile/ref_error.js
11091
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/ref_error.js
10023
11092
  var require_ref_error = __commonJS((exports) => {
10024
11093
  Object.defineProperty(exports, "__esModule", { value: true });
10025
11094
  var resolve_1 = require_resolve();
@@ -10034,7 +11103,7 @@ var require_ref_error = __commonJS((exports) => {
10034
11103
  exports.default = MissingRefError;
10035
11104
  });
10036
11105
 
10037
- // node_modules/ajv/dist/compile/index.js
11106
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/index.js
10038
11107
  var require_compile = __commonJS((exports) => {
10039
11108
  Object.defineProperty(exports, "__esModule", { value: true });
10040
11109
  exports.resolveSchema = exports.getCompilingSchema = exports.resolveRef = exports.compileSchema = exports.SchemaEnv = undefined;
@@ -10255,7 +11324,7 @@ var require_compile = __commonJS((exports) => {
10255
11324
  }
10256
11325
  });
10257
11326
 
10258
- // node_modules/ajv/dist/refs/data.json
11327
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/refs/data.json
10259
11328
  var require_data = __commonJS((exports, module) => {
10260
11329
  module.exports = {
10261
11330
  $id: "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#",
@@ -10272,7 +11341,7 @@ var require_data = __commonJS((exports, module) => {
10272
11341
  };
10273
11342
  });
10274
11343
 
10275
- // node_modules/fast-uri/lib/utils.js
11344
+ // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/utils.js
10276
11345
  var require_utils = __commonJS((exports, module) => {
10277
11346
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
10278
11347
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
@@ -10394,8 +11463,8 @@ var require_utils = __commonJS((exports, module) => {
10394
11463
  }
10395
11464
  return ind;
10396
11465
  }
10397
- function removeDotSegments(path4) {
10398
- let input = path4;
11466
+ function removeDotSegments(path11) {
11467
+ let input = path11;
10399
11468
  const output = [];
10400
11469
  let nextSlash = -1;
10401
11470
  let len = 0;
@@ -10527,7 +11596,7 @@ var require_utils = __commonJS((exports, module) => {
10527
11596
  };
10528
11597
  });
10529
11598
 
10530
- // node_modules/fast-uri/lib/schemes.js
11599
+ // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/schemes.js
10531
11600
  var require_schemes = __commonJS((exports, module) => {
10532
11601
  var { isUUID } = require_utils();
10533
11602
  var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
@@ -10585,8 +11654,8 @@ var require_schemes = __commonJS((exports, module) => {
10585
11654
  wsComponent.secure = undefined;
10586
11655
  }
10587
11656
  if (wsComponent.resourceName) {
10588
- const [path4, query] = wsComponent.resourceName.split("?");
10589
- wsComponent.path = path4 && path4 !== "/" ? path4 : undefined;
11657
+ const [path11, query] = wsComponent.resourceName.split("?");
11658
+ wsComponent.path = path11 && path11 !== "/" ? path11 : undefined;
10590
11659
  wsComponent.query = query;
10591
11660
  wsComponent.resourceName = undefined;
10592
11661
  }
@@ -10701,7 +11770,7 @@ var require_schemes = __commonJS((exports, module) => {
10701
11770
  };
10702
11771
  });
10703
11772
 
10704
- // node_modules/fast-uri/index.js
11773
+ // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/index.js
10705
11774
  var require_fast_uri = __commonJS((exports, module) => {
10706
11775
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
10707
11776
  var { SCHEMES, getSchemeHandler } = require_schemes();
@@ -10952,7 +12021,7 @@ var require_fast_uri = __commonJS((exports, module) => {
10952
12021
  module.exports.fastUri = fastUri;
10953
12022
  });
10954
12023
 
10955
- // node_modules/ajv/dist/runtime/uri.js
12024
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/runtime/uri.js
10956
12025
  var require_uri = __commonJS((exports) => {
10957
12026
  Object.defineProperty(exports, "__esModule", { value: true });
10958
12027
  var uri = require_fast_uri();
@@ -10960,7 +12029,7 @@ var require_uri = __commonJS((exports) => {
10960
12029
  exports.default = uri;
10961
12030
  });
10962
12031
 
10963
- // node_modules/ajv/dist/core.js
12032
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/core.js
10964
12033
  var require_core = __commonJS((exports) => {
10965
12034
  Object.defineProperty(exports, "__esModule", { value: true });
10966
12035
  exports.CodeGen = exports.Name = exports.nil = exports.stringify = exports.str = exports._ = exports.KeywordCxt = undefined;
@@ -11553,7 +12622,7 @@ var require_core = __commonJS((exports) => {
11553
12622
  }
11554
12623
  });
11555
12624
 
11556
- // node_modules/ajv/dist/vocabularies/core/id.js
12625
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/core/id.js
11557
12626
  var require_id = __commonJS((exports) => {
11558
12627
  Object.defineProperty(exports, "__esModule", { value: true });
11559
12628
  var def = {
@@ -11565,7 +12634,7 @@ var require_id = __commonJS((exports) => {
11565
12634
  exports.default = def;
11566
12635
  });
11567
12636
 
11568
- // node_modules/ajv/dist/vocabularies/core/ref.js
12637
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/core/ref.js
11569
12638
  var require_ref = __commonJS((exports) => {
11570
12639
  Object.defineProperty(exports, "__esModule", { value: true });
11571
12640
  exports.callRef = exports.getValidate = undefined;
@@ -11684,7 +12753,7 @@ var require_ref = __commonJS((exports) => {
11684
12753
  exports.default = def;
11685
12754
  });
11686
12755
 
11687
- // node_modules/ajv/dist/vocabularies/core/index.js
12756
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/core/index.js
11688
12757
  var require_core2 = __commonJS((exports) => {
11689
12758
  Object.defineProperty(exports, "__esModule", { value: true });
11690
12759
  var id_1 = require_id();
@@ -11702,7 +12771,7 @@ var require_core2 = __commonJS((exports) => {
11702
12771
  exports.default = core2;
11703
12772
  });
11704
12773
 
11705
- // node_modules/ajv/dist/vocabularies/validation/limitNumber.js
12774
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/limitNumber.js
11706
12775
  var require_limitNumber = __commonJS((exports) => {
11707
12776
  Object.defineProperty(exports, "__esModule", { value: true });
11708
12777
  var codegen_1 = require_codegen();
@@ -11731,7 +12800,7 @@ var require_limitNumber = __commonJS((exports) => {
11731
12800
  exports.default = def;
11732
12801
  });
11733
12802
 
11734
- // node_modules/ajv/dist/vocabularies/validation/multipleOf.js
12803
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/multipleOf.js
11735
12804
  var require_multipleOf = __commonJS((exports) => {
11736
12805
  Object.defineProperty(exports, "__esModule", { value: true });
11737
12806
  var codegen_1 = require_codegen();
@@ -11756,7 +12825,7 @@ var require_multipleOf = __commonJS((exports) => {
11756
12825
  exports.default = def;
11757
12826
  });
11758
12827
 
11759
- // node_modules/ajv/dist/runtime/ucs2length.js
12828
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/runtime/ucs2length.js
11760
12829
  var require_ucs2length = __commonJS((exports) => {
11761
12830
  Object.defineProperty(exports, "__esModule", { value: true });
11762
12831
  function ucs2length(str) {
@@ -11779,7 +12848,7 @@ var require_ucs2length = __commonJS((exports) => {
11779
12848
  ucs2length.code = 'require("ajv/dist/runtime/ucs2length").default';
11780
12849
  });
11781
12850
 
11782
- // node_modules/ajv/dist/vocabularies/validation/limitLength.js
12851
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/limitLength.js
11783
12852
  var require_limitLength = __commonJS((exports) => {
11784
12853
  Object.defineProperty(exports, "__esModule", { value: true });
11785
12854
  var codegen_1 = require_codegen();
@@ -11808,7 +12877,7 @@ var require_limitLength = __commonJS((exports) => {
11808
12877
  exports.default = def;
11809
12878
  });
11810
12879
 
11811
- // node_modules/ajv/dist/vocabularies/validation/pattern.js
12880
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/pattern.js
11812
12881
  var require_pattern = __commonJS((exports) => {
11813
12882
  Object.defineProperty(exports, "__esModule", { value: true });
11814
12883
  var code_1 = require_code2();
@@ -11842,7 +12911,7 @@ var require_pattern = __commonJS((exports) => {
11842
12911
  exports.default = def;
11843
12912
  });
11844
12913
 
11845
- // node_modules/ajv/dist/vocabularies/validation/limitProperties.js
12914
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/limitProperties.js
11846
12915
  var require_limitProperties = __commonJS((exports) => {
11847
12916
  Object.defineProperty(exports, "__esModule", { value: true });
11848
12917
  var codegen_1 = require_codegen();
@@ -11868,7 +12937,7 @@ var require_limitProperties = __commonJS((exports) => {
11868
12937
  exports.default = def;
11869
12938
  });
11870
12939
 
11871
- // node_modules/ajv/dist/vocabularies/validation/required.js
12940
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/required.js
11872
12941
  var require_required = __commonJS((exports) => {
11873
12942
  Object.defineProperty(exports, "__esModule", { value: true });
11874
12943
  var code_1 = require_code2();
@@ -11947,7 +13016,7 @@ var require_required = __commonJS((exports) => {
11947
13016
  exports.default = def;
11948
13017
  });
11949
13018
 
11950
- // node_modules/ajv/dist/vocabularies/validation/limitItems.js
13019
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/limitItems.js
11951
13020
  var require_limitItems = __commonJS((exports) => {
11952
13021
  Object.defineProperty(exports, "__esModule", { value: true });
11953
13022
  var codegen_1 = require_codegen();
@@ -11973,7 +13042,7 @@ var require_limitItems = __commonJS((exports) => {
11973
13042
  exports.default = def;
11974
13043
  });
11975
13044
 
11976
- // node_modules/ajv/dist/runtime/equal.js
13045
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/runtime/equal.js
11977
13046
  var require_equal = __commonJS((exports) => {
11978
13047
  Object.defineProperty(exports, "__esModule", { value: true });
11979
13048
  var equal = require_fast_deep_equal();
@@ -11981,7 +13050,7 @@ var require_equal = __commonJS((exports) => {
11981
13050
  exports.default = equal;
11982
13051
  });
11983
13052
 
11984
- // node_modules/ajv/dist/vocabularies/validation/uniqueItems.js
13053
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/uniqueItems.js
11985
13054
  var require_uniqueItems = __commonJS((exports) => {
11986
13055
  Object.defineProperty(exports, "__esModule", { value: true });
11987
13056
  var dataType_1 = require_dataType();
@@ -12045,7 +13114,7 @@ var require_uniqueItems = __commonJS((exports) => {
12045
13114
  exports.default = def;
12046
13115
  });
12047
13116
 
12048
- // node_modules/ajv/dist/vocabularies/validation/const.js
13117
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/const.js
12049
13118
  var require_const = __commonJS((exports) => {
12050
13119
  Object.defineProperty(exports, "__esModule", { value: true });
12051
13120
  var codegen_1 = require_codegen();
@@ -12071,7 +13140,7 @@ var require_const = __commonJS((exports) => {
12071
13140
  exports.default = def;
12072
13141
  });
12073
13142
 
12074
- // node_modules/ajv/dist/vocabularies/validation/enum.js
13143
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/enum.js
12075
13144
  var require_enum = __commonJS((exports) => {
12076
13145
  Object.defineProperty(exports, "__esModule", { value: true });
12077
13146
  var codegen_1 = require_codegen();
@@ -12117,7 +13186,7 @@ var require_enum = __commonJS((exports) => {
12117
13186
  exports.default = def;
12118
13187
  });
12119
13188
 
12120
- // node_modules/ajv/dist/vocabularies/validation/index.js
13189
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/validation/index.js
12121
13190
  var require_validation = __commonJS((exports) => {
12122
13191
  Object.defineProperty(exports, "__esModule", { value: true });
12123
13192
  var limitNumber_1 = require_limitNumber();
@@ -12147,7 +13216,7 @@ var require_validation = __commonJS((exports) => {
12147
13216
  exports.default = validation;
12148
13217
  });
12149
13218
 
12150
- // node_modules/ajv/dist/vocabularies/applicator/additionalItems.js
13219
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/additionalItems.js
12151
13220
  var require_additionalItems = __commonJS((exports) => {
12152
13221
  Object.defineProperty(exports, "__esModule", { value: true });
12153
13222
  exports.validateAdditionalItems = undefined;
@@ -12197,7 +13266,7 @@ var require_additionalItems = __commonJS((exports) => {
12197
13266
  exports.default = def;
12198
13267
  });
12199
13268
 
12200
- // node_modules/ajv/dist/vocabularies/applicator/items.js
13269
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/items.js
12201
13270
  var require_items = __commonJS((exports) => {
12202
13271
  Object.defineProperty(exports, "__esModule", { value: true });
12203
13272
  exports.validateTuple = undefined;
@@ -12251,7 +13320,7 @@ var require_items = __commonJS((exports) => {
12251
13320
  exports.default = def;
12252
13321
  });
12253
13322
 
12254
- // node_modules/ajv/dist/vocabularies/applicator/prefixItems.js
13323
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/prefixItems.js
12255
13324
  var require_prefixItems = __commonJS((exports) => {
12256
13325
  Object.defineProperty(exports, "__esModule", { value: true });
12257
13326
  var items_1 = require_items();
@@ -12265,7 +13334,7 @@ var require_prefixItems = __commonJS((exports) => {
12265
13334
  exports.default = def;
12266
13335
  });
12267
13336
 
12268
- // node_modules/ajv/dist/vocabularies/applicator/items2020.js
13337
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/items2020.js
12269
13338
  var require_items2020 = __commonJS((exports) => {
12270
13339
  Object.defineProperty(exports, "__esModule", { value: true });
12271
13340
  var codegen_1 = require_codegen();
@@ -12297,7 +13366,7 @@ var require_items2020 = __commonJS((exports) => {
12297
13366
  exports.default = def;
12298
13367
  });
12299
13368
 
12300
- // node_modules/ajv/dist/vocabularies/applicator/contains.js
13369
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/contains.js
12301
13370
  var require_contains = __commonJS((exports) => {
12302
13371
  Object.defineProperty(exports, "__esModule", { value: true });
12303
13372
  var codegen_1 = require_codegen();
@@ -12388,7 +13457,7 @@ var require_contains = __commonJS((exports) => {
12388
13457
  exports.default = def;
12389
13458
  });
12390
13459
 
12391
- // node_modules/ajv/dist/vocabularies/applicator/dependencies.js
13460
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/dependencies.js
12392
13461
  var require_dependencies = __commonJS((exports) => {
12393
13462
  Object.defineProperty(exports, "__esModule", { value: true });
12394
13463
  exports.validateSchemaDeps = exports.validatePropertyDeps = exports.error = undefined;
@@ -12473,7 +13542,7 @@ var require_dependencies = __commonJS((exports) => {
12473
13542
  exports.default = def;
12474
13543
  });
12475
13544
 
12476
- // node_modules/ajv/dist/vocabularies/applicator/propertyNames.js
13545
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/propertyNames.js
12477
13546
  var require_propertyNames = __commonJS((exports) => {
12478
13547
  Object.defineProperty(exports, "__esModule", { value: true });
12479
13548
  var codegen_1 = require_codegen();
@@ -12513,7 +13582,7 @@ var require_propertyNames = __commonJS((exports) => {
12513
13582
  exports.default = def;
12514
13583
  });
12515
13584
 
12516
- // node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js
13585
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js
12517
13586
  var require_additionalProperties = __commonJS((exports) => {
12518
13587
  Object.defineProperty(exports, "__esModule", { value: true });
12519
13588
  var code_1 = require_code2();
@@ -12616,7 +13685,7 @@ var require_additionalProperties = __commonJS((exports) => {
12616
13685
  exports.default = def;
12617
13686
  });
12618
13687
 
12619
- // node_modules/ajv/dist/vocabularies/applicator/properties.js
13688
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/properties.js
12620
13689
  var require_properties = __commonJS((exports) => {
12621
13690
  Object.defineProperty(exports, "__esModule", { value: true });
12622
13691
  var validate_1 = require_validate();
@@ -12671,7 +13740,7 @@ var require_properties = __commonJS((exports) => {
12671
13740
  exports.default = def;
12672
13741
  });
12673
13742
 
12674
- // node_modules/ajv/dist/vocabularies/applicator/patternProperties.js
13743
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/patternProperties.js
12675
13744
  var require_patternProperties = __commonJS((exports) => {
12676
13745
  Object.defineProperty(exports, "__esModule", { value: true });
12677
13746
  var code_1 = require_code2();
@@ -12742,7 +13811,7 @@ var require_patternProperties = __commonJS((exports) => {
12742
13811
  exports.default = def;
12743
13812
  });
12744
13813
 
12745
- // node_modules/ajv/dist/vocabularies/applicator/not.js
13814
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/not.js
12746
13815
  var require_not = __commonJS((exports) => {
12747
13816
  Object.defineProperty(exports, "__esModule", { value: true });
12748
13817
  var util_1 = require_util();
@@ -12770,7 +13839,7 @@ var require_not = __commonJS((exports) => {
12770
13839
  exports.default = def;
12771
13840
  });
12772
13841
 
12773
- // node_modules/ajv/dist/vocabularies/applicator/anyOf.js
13842
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/anyOf.js
12774
13843
  var require_anyOf = __commonJS((exports) => {
12775
13844
  Object.defineProperty(exports, "__esModule", { value: true });
12776
13845
  var code_1 = require_code2();
@@ -12784,7 +13853,7 @@ var require_anyOf = __commonJS((exports) => {
12784
13853
  exports.default = def;
12785
13854
  });
12786
13855
 
12787
- // node_modules/ajv/dist/vocabularies/applicator/oneOf.js
13856
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/oneOf.js
12788
13857
  var require_oneOf = __commonJS((exports) => {
12789
13858
  Object.defineProperty(exports, "__esModule", { value: true });
12790
13859
  var codegen_1 = require_codegen();
@@ -12839,7 +13908,7 @@ var require_oneOf = __commonJS((exports) => {
12839
13908
  exports.default = def;
12840
13909
  });
12841
13910
 
12842
- // node_modules/ajv/dist/vocabularies/applicator/allOf.js
13911
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/allOf.js
12843
13912
  var require_allOf = __commonJS((exports) => {
12844
13913
  Object.defineProperty(exports, "__esModule", { value: true });
12845
13914
  var util_1 = require_util();
@@ -12863,7 +13932,7 @@ var require_allOf = __commonJS((exports) => {
12863
13932
  exports.default = def;
12864
13933
  });
12865
13934
 
12866
- // node_modules/ajv/dist/vocabularies/applicator/if.js
13935
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/if.js
12867
13936
  var require_if = __commonJS((exports) => {
12868
13937
  Object.defineProperty(exports, "__esModule", { value: true });
12869
13938
  var codegen_1 = require_codegen();
@@ -12929,7 +13998,7 @@ var require_if = __commonJS((exports) => {
12929
13998
  exports.default = def;
12930
13999
  });
12931
14000
 
12932
- // node_modules/ajv/dist/vocabularies/applicator/thenElse.js
14001
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/thenElse.js
12933
14002
  var require_thenElse = __commonJS((exports) => {
12934
14003
  Object.defineProperty(exports, "__esModule", { value: true });
12935
14004
  var util_1 = require_util();
@@ -12944,7 +14013,7 @@ var require_thenElse = __commonJS((exports) => {
12944
14013
  exports.default = def;
12945
14014
  });
12946
14015
 
12947
- // node_modules/ajv/dist/vocabularies/applicator/index.js
14016
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/applicator/index.js
12948
14017
  var require_applicator = __commonJS((exports) => {
12949
14018
  Object.defineProperty(exports, "__esModule", { value: true });
12950
14019
  var additionalItems_1 = require_additionalItems();
@@ -12987,7 +14056,7 @@ var require_applicator = __commonJS((exports) => {
12987
14056
  exports.default = getApplicator;
12988
14057
  });
12989
14058
 
12990
- // node_modules/ajv/dist/vocabularies/format/format.js
14059
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/format/format.js
12991
14060
  var require_format = __commonJS((exports) => {
12992
14061
  Object.defineProperty(exports, "__esModule", { value: true });
12993
14062
  var codegen_1 = require_codegen();
@@ -13074,7 +14143,7 @@ var require_format = __commonJS((exports) => {
13074
14143
  exports.default = def;
13075
14144
  });
13076
14145
 
13077
- // node_modules/ajv/dist/vocabularies/format/index.js
14146
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/format/index.js
13078
14147
  var require_format2 = __commonJS((exports) => {
13079
14148
  Object.defineProperty(exports, "__esModule", { value: true });
13080
14149
  var format_1 = require_format();
@@ -13082,7 +14151,7 @@ var require_format2 = __commonJS((exports) => {
13082
14151
  exports.default = format;
13083
14152
  });
13084
14153
 
13085
- // node_modules/ajv/dist/vocabularies/metadata.js
14154
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/metadata.js
13086
14155
  var require_metadata = __commonJS((exports) => {
13087
14156
  Object.defineProperty(exports, "__esModule", { value: true });
13088
14157
  exports.contentVocabulary = exports.metadataVocabulary = undefined;
@@ -13102,7 +14171,7 @@ var require_metadata = __commonJS((exports) => {
13102
14171
  ];
13103
14172
  });
13104
14173
 
13105
- // node_modules/ajv/dist/vocabularies/draft7.js
14174
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/draft7.js
13106
14175
  var require_draft7 = __commonJS((exports) => {
13107
14176
  Object.defineProperty(exports, "__esModule", { value: true });
13108
14177
  var core_1 = require_core2();
@@ -13121,7 +14190,7 @@ var require_draft7 = __commonJS((exports) => {
13121
14190
  exports.default = draft7Vocabularies;
13122
14191
  });
13123
14192
 
13124
- // node_modules/ajv/dist/vocabularies/discriminator/types.js
14193
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/discriminator/types.js
13125
14194
  var require_types = __commonJS((exports) => {
13126
14195
  Object.defineProperty(exports, "__esModule", { value: true });
13127
14196
  exports.DiscrError = undefined;
@@ -13132,7 +14201,7 @@ var require_types = __commonJS((exports) => {
13132
14201
  })(DiscrError || (exports.DiscrError = DiscrError = {}));
13133
14202
  });
13134
14203
 
13135
- // node_modules/ajv/dist/vocabularies/discriminator/index.js
14204
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/vocabularies/discriminator/index.js
13136
14205
  var require_discriminator = __commonJS((exports) => {
13137
14206
  Object.defineProperty(exports, "__esModule", { value: true });
13138
14207
  var codegen_1 = require_codegen();
@@ -13234,7 +14303,7 @@ var require_discriminator = __commonJS((exports) => {
13234
14303
  exports.default = def;
13235
14304
  });
13236
14305
 
13237
- // node_modules/ajv/dist/refs/json-schema-draft-07.json
14306
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/refs/json-schema-draft-07.json
13238
14307
  var require_json_schema_draft_07 = __commonJS((exports, module) => {
13239
14308
  module.exports = {
13240
14309
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -13389,7 +14458,7 @@ var require_json_schema_draft_07 = __commonJS((exports, module) => {
13389
14458
  };
13390
14459
  });
13391
14460
 
13392
- // node_modules/ajv/dist/ajv.js
14461
+ // node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/ajv.js
13393
14462
  var require_ajv = __commonJS((exports, module) => {
13394
14463
  Object.defineProperty(exports, "__esModule", { value: true });
13395
14464
  exports.MissingRefError = exports.ValidationError = exports.CodeGen = exports.Name = exports.nil = exports.stringify = exports.str = exports._ = exports.KeywordCxt = exports.Ajv = undefined;
@@ -13457,7 +14526,7 @@ var require_ajv = __commonJS((exports, module) => {
13457
14526
  } });
13458
14527
  });
13459
14528
 
13460
- // node_modules/ajv-formats/dist/formats.js
14529
+ // node_modules/.pnpm/ajv-formats@3.0.1_ajv@8.18.0/node_modules/ajv-formats/dist/formats.js
13461
14530
  var require_formats = __commonJS((exports) => {
13462
14531
  Object.defineProperty(exports, "__esModule", { value: true });
13463
14532
  exports.formatNames = exports.fastFormats = exports.fullFormats = undefined;
@@ -13634,7 +14703,7 @@ var require_formats = __commonJS((exports) => {
13634
14703
  }
13635
14704
  });
13636
14705
 
13637
- // node_modules/ajv-formats/dist/limit.js
14706
+ // node_modules/.pnpm/ajv-formats@3.0.1_ajv@8.18.0/node_modules/ajv-formats/dist/limit.js
13638
14707
  var require_limit = __commonJS((exports) => {
13639
14708
  Object.defineProperty(exports, "__esModule", { value: true });
13640
14709
  exports.formatLimitDefinition = undefined;
@@ -13703,7 +14772,7 @@ var require_limit = __commonJS((exports) => {
13703
14772
  exports.default = formatLimitPlugin;
13704
14773
  });
13705
14774
 
13706
- // node_modules/ajv-formats/dist/index.js
14775
+ // node_modules/.pnpm/ajv-formats@3.0.1_ajv@8.18.0/node_modules/ajv-formats/dist/index.js
13707
14776
  var require_dist = __commonJS((exports, module) => {
13708
14777
  Object.defineProperty(exports, "__esModule", { value: true });
13709
14778
  var formats_1 = require_formats();
@@ -13730,19 +14799,19 @@ var require_dist = __commonJS((exports, module) => {
13730
14799
  throw new Error(`Unknown format "${name}"`);
13731
14800
  return f;
13732
14801
  };
13733
- function addFormats(ajv, list, fs4, exportName) {
14802
+ function addFormats(ajv, list, fs12, exportName) {
13734
14803
  var _a;
13735
14804
  var _b;
13736
14805
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
13737
14806
  for (const f of list)
13738
- ajv.addFormat(f, fs4[f]);
14807
+ ajv.addFormat(f, fs12[f]);
13739
14808
  }
13740
14809
  module.exports = exports = formatsPlugin;
13741
14810
  Object.defineProperty(exports, "__esModule", { value: true });
13742
14811
  exports.default = formatsPlugin;
13743
14812
  });
13744
14813
 
13745
- // node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
14814
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
13746
14815
  function createDefaultAjvInstance() {
13747
14816
  const ajv = new import_ajv.default({
13748
14817
  strict: false,
@@ -13785,7 +14854,7 @@ var init_ajv_provider = __esm(() => {
13785
14854
  import_ajv_formats = __toESM(require_dist(), 1);
13786
14855
  });
13787
14856
 
13788
- // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
14857
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
13789
14858
  class ExperimentalServerTasks {
13790
14859
  constructor(_server) {
13791
14860
  this._server = _server;
@@ -13866,7 +14935,7 @@ var init_server = __esm(() => {
13866
14935
  init_types();
13867
14936
  });
13868
14937
 
13869
- // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
14938
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
13870
14939
  function assertToolsCallTaskCapability(requests, method, entityName) {
13871
14940
  if (!requests) {
13872
14941
  throw new Error(`${entityName} does not support task creation (required for ${method})`);
@@ -13901,7 +14970,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
13901
14970
  }
13902
14971
  }
13903
14972
 
13904
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
14973
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
13905
14974
  var Server;
13906
14975
  var init_server2 = __esm(() => {
13907
14976
  init_protocol();
@@ -14242,7 +15311,7 @@ var init_server2 = __esm(() => {
14242
15311
  };
14243
15312
  });
14244
15313
 
14245
- // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
15314
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
14246
15315
  class ReadBuffer {
14247
15316
  append(chunk) {
14248
15317
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
@@ -14275,7 +15344,7 @@ var init_stdio = __esm(() => {
14275
15344
  init_types();
14276
15345
  });
14277
15346
 
14278
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
15347
+ // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
14279
15348
  import process2 from "node:process";
14280
15349
 
14281
15350
  class StdioServerTransport {
@@ -14866,8 +15935,8 @@ var exports_server = {};
14866
15935
  __export(exports_server, {
14867
15936
  startMcpServer: () => startMcpServer
14868
15937
  });
14869
- import os3 from "node:os";
14870
- import path4 from "node:path";
15938
+ import os9 from "node:os";
15939
+ import path11 from "node:path";
14871
15940
  function ensureString(value) {
14872
15941
  if (typeof value === "string" && value.trim().length > 0)
14873
15942
  return value;
@@ -14902,7 +15971,7 @@ var init_server3 = __esm(() => {
14902
15971
  init_types();
14903
15972
  init_ingestor();
14904
15973
  init_tools();
14905
- init_tokscale();
15974
+ init_orchestrator();
14906
15975
  init_session_tracker();
14907
15976
  config2 = {
14908
15977
  apiKey: process.env.VERBAL_API_KEY ?? "",
@@ -15128,9 +16197,35 @@ var init_server3 = __esm(() => {
15128
16197
  }
15129
16198
  }
15130
16199
  },
16200
+ {
16201
+ name: "sync_platforms",
16202
+ description: "Sync usage data from local AI tool sessions using native parsers. Scans Claude Code, Codex, Cursor, Gemini, and other supported platforms directly without requiring external tools.",
16203
+ inputSchema: {
16204
+ type: "object",
16205
+ properties: {
16206
+ since: {
16207
+ type: "string",
16208
+ description: "Start date (YYYY-MM-DD). Defaults to last sync date."
16209
+ },
16210
+ until: {
16211
+ type: "string",
16212
+ description: "End date (YYYY-MM-DD). Defaults to today."
16213
+ },
16214
+ platforms: {
16215
+ type: "array",
16216
+ items: { type: "string" },
16217
+ description: "Platforms to sync (e.g. claude-code, codex, cursor, gemini). Defaults to all."
16218
+ },
16219
+ project: {
16220
+ type: "string",
16221
+ description: "Project identifier to tag events with."
16222
+ }
16223
+ }
16224
+ }
16225
+ },
15131
16226
  {
15132
16227
  name: "sync_tokscale",
15133
- description: "Sync usage data from local AI tool sessions via tokscale. Scans Claude Code, Codex, Cursor, Gemini, and other supported platforms.",
16228
+ description: "[Deprecated: use sync_platforms] Sync usage data from local AI tool sessions. Alias for sync_platforms.",
15134
16229
  inputSchema: {
15135
16230
  type: "object",
15136
16231
  properties: {
@@ -15145,7 +16240,7 @@ var init_server3 = __esm(() => {
15145
16240
  platforms: {
15146
16241
  type: "array",
15147
16242
  items: { type: "string" },
15148
- description: "Platforms to sync (e.g. claude, codex, cursor). Defaults to all."
16243
+ description: "Platforms to sync (e.g. claude-code, codex, cursor, gemini). Defaults to all."
15149
16244
  },
15150
16245
  project: {
15151
16246
  type: "string",
@@ -15400,7 +16495,7 @@ var init_server3 = __esm(() => {
15400
16495
  ]
15401
16496
  };
15402
16497
  }
15403
- if (name === "sync_tokscale") {
16498
+ if (name === "sync_platforms" || name === "sync_tokscale") {
15404
16499
  const syncConfig = {
15405
16500
  apiKey: config2.apiKey,
15406
16501
  ingestUrl: config2.endpoint,
@@ -15409,7 +16504,7 @@ var init_server3 = __esm(() => {
15409
16504
  batchSize: config2.batchSize,
15410
16505
  flushIntervalMs: 0,
15411
16506
  httpTimeoutMs: config2.httpTimeoutMs,
15412
- stateDir: path4.join(os3.homedir(), ".claude", "verbal-logs")
16507
+ stateDir: path11.join(os9.homedir(), ".claude", "verbal-logs")
15413
16508
  };
15414
16509
  const syncOptions = {
15415
16510
  since: typeof args.since === "string" ? args.since : undefined,
@@ -15417,12 +16512,15 @@ var init_server3 = __esm(() => {
15417
16512
  platforms: Array.isArray(args.platforms) ? args.platforms.filter((p) => typeof p === "string") : undefined,
15418
16513
  project: typeof args.project === "string" ? args.project : config2.defaultProject
15419
16514
  };
15420
- const result = await syncFromTokscale(syncConfig, syncOptions);
16515
+ const result = await syncPlatforms(syncConfig, syncOptions);
16516
+ const lines = result.platforms.map((p) => p.error ? ` ${p.id}: ERROR — ${p.error}` : ` ${p.id}: ${p.events} events, $${p.totalCost.toFixed(2)}`);
15421
16517
  return {
15422
16518
  content: [
15423
16519
  {
15424
16520
  type: "text",
15425
- text: `Tokscale sync complete: ${result.events} events, ${result.days} days, $${result.totalCost.toFixed(2)} total cost`
16521
+ text: `Platform sync complete: ${result.totalEvents} events, $${result.totalCost.toFixed(2)}
16522
+ ${lines.join(`
16523
+ `)}`
15426
16524
  }
15427
16525
  ]
15428
16526
  };
@@ -15544,9 +16642,9 @@ async function runMcpServe() {
15544
16642
  }
15545
16643
 
15546
16644
  // src/agent-hooks/config.ts
15547
- import fs4 from "node:fs";
15548
- import os4 from "node:os";
15549
- import path5 from "node:path";
16645
+ import fs12 from "node:fs";
16646
+ import os10 from "node:os";
16647
+ import path12 from "node:path";
15550
16648
  function loadHookConfig(options = {}) {
15551
16649
  const env = options.env ?? process.env;
15552
16650
  const cwd = options.cwd ?? process.cwd();
@@ -15562,6 +16660,7 @@ function loadHookConfig(options = {}) {
15562
16660
  apiKey,
15563
16661
  ingestUrl,
15564
16662
  traceUrl,
16663
+ apiUrl: env.VERBAL_API_URL ?? mcpEnv.VERBAL_API_URL ?? deriveApiUrl(ingestUrl),
15565
16664
  hmacSecret: env.VERBAL_HMAC_SECRET ?? mcpEnv.VERBAL_HMAC_SECRET,
15566
16665
  orgId: env.VERBAL_ORG_ID ?? mcpEnv.VERBAL_ORG_ID,
15567
16666
  defaultProject: env.VERBAL_DEFAULT_PROJECT ?? mcpEnv.VERBAL_DEFAULT_PROJECT,
@@ -15578,8 +16677,8 @@ function loadHookConfig(options = {}) {
15578
16677
  gitContextEnabled: parseBoolean(env.VERBAL_GIT_CONTEXT_ENABLED ?? mcpEnv.VERBAL_GIT_CONTEXT_ENABLED, DEFAULTS.gitContextEnabled),
15579
16678
  costCalcEnabled: parseBoolean(env.VERBAL_COST_CALC_ENABLED ?? mcpEnv.VERBAL_COST_CALC_ENABLED, DEFAULTS.costCalcEnabled),
15580
16679
  billingType: parseBillingType(env.VERBAL_BILLING_TYPE ?? mcpEnv.VERBAL_BILLING_TYPE),
15581
- claudeStateDir: env.VERBAL_CLAUDE_STATE_DIR ?? path5.join(os4.homedir(), ".claude", "verbal-logs"),
15582
- codexStateDir: env.VERBAL_CODEX_STATE_DIR ?? path5.join(os4.homedir(), ".codex", "verbal-logs")
16680
+ claudeStateDir: env.VERBAL_CLAUDE_STATE_DIR ?? path12.join(os10.homedir(), ".claude", "verbal-logs"),
16681
+ codexStateDir: env.VERBAL_CODEX_STATE_DIR ?? path12.join(os10.homedir(), ".codex", "verbal-logs")
15583
16682
  };
15584
16683
  }
15585
16684
  function redactText(value, patterns) {
@@ -15637,7 +16736,7 @@ function buildRedactionPatterns(value, disableDefault) {
15637
16736
  }
15638
16737
  function loadMcpEnv(configPath) {
15639
16738
  try {
15640
- const raw = fs4.readFileSync(configPath, "utf8");
16739
+ const raw = fs12.readFileSync(configPath, "utf8");
15641
16740
  const parsed = JSON.parse(raw);
15642
16741
  return parsed.mcpServers?.verbal?.env ?? {};
15643
16742
  } catch {
@@ -15647,15 +16746,26 @@ function loadMcpEnv(configPath) {
15647
16746
  function findMcpConfig2(startDir) {
15648
16747
  let current = startDir;
15649
16748
  for (;; ) {
15650
- const candidate = path5.join(current, ".mcp.json");
15651
- if (fs4.existsSync(candidate))
16749
+ const candidate = path12.join(current, ".mcp.json");
16750
+ if (fs12.existsSync(candidate))
15652
16751
  return candidate;
15653
- const parent = path5.dirname(current);
16752
+ const parent = path12.dirname(current);
15654
16753
  if (parent === current)
15655
16754
  return null;
15656
16755
  current = parent;
15657
16756
  }
15658
16757
  }
16758
+ function deriveApiUrl(ingestUrl) {
16759
+ if (!ingestUrl)
16760
+ return "";
16761
+ try {
16762
+ const url = new URL(ingestUrl);
16763
+ url.pathname = "";
16764
+ return url.origin;
16765
+ } catch {
16766
+ return ingestUrl.replace(/\/api\/v1\/ingest\/?$/, "").replace(/\/+$/, "");
16767
+ }
16768
+ }
15659
16769
  function deriveTraceUrl(ingestUrl) {
15660
16770
  if (!ingestUrl)
15661
16771
  return "";
@@ -15859,27 +16969,27 @@ var init_tool_extraction = __esm(() => {
15859
16969
  });
15860
16970
 
15861
16971
  // src/agent-hooks/claude.ts
15862
- import fs5 from "node:fs";
16972
+ import fs13 from "node:fs";
15863
16973
  async function ingestClaudeHookInput(input, config3) {
15864
16974
  if (input.stop_hook_active)
15865
16975
  return;
15866
16976
  if (!input.session_id || !input.transcript_path) {
15867
16977
  throw new Error("Claude hook input missing session_id or transcript_path");
15868
16978
  }
15869
- if (!fs5.existsSync(input.transcript_path)) {
16979
+ if (!fs13.existsSync(input.transcript_path)) {
15870
16980
  throw new Error(`Transcript file not found: ${input.transcript_path}`);
15871
16981
  }
15872
- const entries = readJsonLines(input.transcript_path);
16982
+ const entries = readJsonLines2(input.transcript_path);
15873
16983
  const state = loadClaudeState(config3.claudeStateDir);
15874
16984
  const lastId = state[input.session_id];
15875
- const startIndex = lastId ? findEntryIndex(entries, lastId) + 1 : 0;
16985
+ const startIndex = lastId ? findEntryIndex2(entries, lastId) + 1 : 0;
15876
16986
  const newEntries = entries.slice(Math.max(startIndex, 0));
15877
16987
  if (newEntries.length === 0)
15878
16988
  return;
15879
16989
  let lastUserContent;
15880
16990
  const ingestor2 = createIngestor(config3);
15881
16991
  for (const entry of newEntries) {
15882
- const { role, content } = extractMessage(entry);
16992
+ const { role, content } = extractMessage3(entry);
15883
16993
  if (role === "user" || role === "human") {
15884
16994
  lastUserContent = content;
15885
16995
  continue;
@@ -15892,7 +17002,7 @@ async function ingestClaudeHookInput(input, config3) {
15892
17002
  const tokensOut = usage.output_tokens ?? 0;
15893
17003
  if (!tokensIn && !tokensOut)
15894
17004
  continue;
15895
- const eventId = getEntryId(entry);
17005
+ const eventId = getEntryId2(entry);
15896
17006
  const event = {
15897
17007
  event_id: eventId,
15898
17008
  event_type: "usage",
@@ -16019,24 +17129,24 @@ async function ingestClaudeHookInput(input, config3) {
16019
17129
  await sendTrace(config3, input.session_id, "claude-tool-calls", toolTraceEvents);
16020
17130
  }
16021
17131
  const lastEntry = newEntries[newEntries.length - 1];
16022
- const lastEntryId = getEntryId(lastEntry);
17132
+ const lastEntryId = getEntryId2(lastEntry);
16023
17133
  if (lastEntryId) {
16024
17134
  state[input.session_id] = lastEntryId;
16025
17135
  saveClaudeState(config3.claudeStateDir, state);
16026
17136
  }
16027
17137
  }
16028
- function readJsonLines(filePath) {
16029
- const content = fs5.readFileSync(filePath, "utf8");
17138
+ function readJsonLines2(filePath) {
17139
+ const content = fs13.readFileSync(filePath, "utf8");
16030
17140
  return content.split(`
16031
17141
  `).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
16032
17142
  }
16033
- function extractMessage(entry) {
17143
+ function extractMessage3(entry) {
16034
17144
  const message = entry.message;
16035
17145
  const role = message?.role ?? entry.type;
16036
- const content = flattenContent(message?.content ?? entry.content);
17146
+ const content = flattenContent2(message?.content ?? entry.content);
16037
17147
  return { role, content };
16038
17148
  }
16039
- function flattenContent(content) {
17149
+ function flattenContent2(content) {
16040
17150
  if (!content)
16041
17151
  return;
16042
17152
  if (typeof content === "string")
@@ -16055,26 +17165,26 @@ function flattenContent(content) {
16055
17165
  }
16056
17166
  return;
16057
17167
  }
16058
- function getEntryId(entry) {
17168
+ function getEntryId2(entry) {
16059
17169
  return entry.uuid ?? entry.message?.id ?? entry.id ?? entry.messageId;
16060
17170
  }
16061
- function findEntryIndex(entries, id) {
16062
- return entries.findIndex((entry) => getEntryId(entry) === id);
17171
+ function findEntryIndex2(entries, id) {
17172
+ return entries.findIndex((entry) => getEntryId2(entry) === id);
16063
17173
  }
16064
17174
  var init_claude = __esm(() => {
16065
17175
  init_config();
16066
17176
  init_ingest();
16067
- init_state();
17177
+ init_state2();
16068
17178
  init_tool_extraction();
16069
17179
  });
16070
17180
 
16071
17181
  // src/agent-hooks/codex.ts
16072
- import fs6 from "node:fs";
16073
- import path6 from "node:path";
16074
- import os5 from "node:os";
17182
+ import fs14 from "node:fs";
17183
+ import path13 from "node:path";
17184
+ import os11 from "node:os";
16075
17185
  async function ingestCodexSessions(config3, options = {}) {
16076
- const baseDir = options.path ?? path6.join(os5.homedir(), ".codex", "sessions");
16077
- const files = findSessionFiles(baseDir);
17186
+ const baseDir = options.path ?? path13.join(os11.homedir(), ".codex", "sessions");
17187
+ const files = findSessionFiles2(baseDir);
16078
17188
  if (files.length === 0)
16079
17189
  return;
16080
17190
  const state = loadCodexState(config3.codexStateDir);
@@ -16086,11 +17196,11 @@ async function ingestCodexSessions(config3, options = {}) {
16086
17196
  saveCodexState(config3.codexStateDir, state);
16087
17197
  }
16088
17198
  async function watchCodexSessions(config3, options = {}) {
16089
- const baseDir = options.path ?? path6.join(os5.homedir(), ".codex", "sessions");
17199
+ const baseDir = options.path ?? path13.join(os11.homedir(), ".codex", "sessions");
16090
17200
  const intervalMs = options.intervalMs ?? 3000;
16091
17201
  const state = loadCodexState(config3.codexStateDir);
16092
17202
  setInterval(async () => {
16093
- const files = findSessionFiles(baseDir);
17203
+ const files = findSessionFiles2(baseDir);
16094
17204
  for (const filePath of files) {
16095
17205
  const updated = await ingestCodexFile(filePath, config3, state.files[filePath]);
16096
17206
  if (updated)
@@ -16100,7 +17210,7 @@ async function watchCodexSessions(config3, options = {}) {
16100
17210
  }, intervalMs);
16101
17211
  }
16102
17212
  async function ingestCodexFile(filePath, config3, fileState) {
16103
- const { entries, sessionId } = readCodexFile(filePath);
17213
+ const { entries, sessionId } = readCodexFile2(filePath);
16104
17214
  if (entries.length === 0)
16105
17215
  return null;
16106
17216
  const state = fileState ?? { lastIndex: -1 };
@@ -16156,7 +17266,7 @@ async function ingestCodexFile(filePath, config3, fileState) {
16156
17266
  }
16157
17267
  continue;
16158
17268
  }
16159
- const message = extractMessage2(entry);
17269
+ const message = extractMessage4(entry);
16160
17270
  if (message) {
16161
17271
  if (message.role === "user") {
16162
17272
  lastUserContent = message.content;
@@ -16175,7 +17285,7 @@ async function ingestCodexFile(filePath, config3, fileState) {
16175
17285
  if (pending && !lastTokenUsage) {
16176
17286
  if (config3.allowTokenEstimates) {
16177
17287
  const pendingEvent = pending.event;
16178
- const { tokensIn, tokensOut } = estimateTokens(pending.prompt, pending.response);
17288
+ const { tokensIn, tokensOut } = estimateTokens2(pending.prompt, pending.response);
16179
17289
  pendingEvent.tokens_in = tokensIn;
16180
17290
  pendingEvent.tokens_out = tokensOut;
16181
17291
  pendingEvent.total_tokens = tokensIn + tokensOut;
@@ -16216,7 +17326,7 @@ async function ingestCodexFile(filePath, config3, fileState) {
16216
17326
  lastTokenUsage = undefined;
16217
17327
  events.push(event);
16218
17328
  } else if (config3.allowTokenEstimates) {
16219
- const { tokensIn, tokensOut } = estimateTokens(lastUserContent, message.content);
17329
+ const { tokensIn, tokensOut } = estimateTokens2(lastUserContent, message.content);
16220
17330
  event.tokens_in = tokensIn;
16221
17331
  event.tokens_out = tokensOut;
16222
17332
  event.total_tokens = tokensIn + tokensOut;
@@ -16319,17 +17429,17 @@ async function ingestCodexFile(filePath, config3, fileState) {
16319
17429
  state.pending = pending;
16320
17430
  return state;
16321
17431
  }
16322
- function readCodexFile(filePath) {
16323
- const content = fs6.readFileSync(filePath, "utf8").trim();
17432
+ function readCodexFile2(filePath) {
17433
+ const content = fs14.readFileSync(filePath, "utf8").trim();
16324
17434
  if (!content)
16325
- return { entries: [], sessionId: path6.basename(filePath) };
17435
+ return { entries: [], sessionId: path13.basename(filePath) };
16326
17436
  const isJsonl = filePath.endsWith(".jsonl");
16327
17437
  if (!isJsonl && content.startsWith("{")) {
16328
17438
  try {
16329
17439
  const parsed = JSON.parse(content);
16330
17440
  return {
16331
17441
  entries: parsed.items ?? [],
16332
- sessionId: parsed.session?.id ?? path6.basename(filePath)
17442
+ sessionId: parsed.session?.id ?? path13.basename(filePath)
16333
17443
  };
16334
17444
  } catch {}
16335
17445
  }
@@ -16337,30 +17447,30 @@ function readCodexFile(filePath) {
16337
17447
  `).filter(Boolean);
16338
17448
  const entries = lines.map((line) => JSON.parse(line));
16339
17449
  const sessionMeta = entries.find((entry) => entry.type === "session_meta");
16340
- const sessionId = sessionMeta?.payload?.id ?? path6.basename(filePath);
17450
+ const sessionId = sessionMeta?.payload?.id ?? path13.basename(filePath);
16341
17451
  return { entries, sessionId };
16342
17452
  }
16343
- function extractMessage2(entry) {
17453
+ function extractMessage4(entry) {
16344
17454
  if (entry.type === "response_item" && entry.payload && typeof entry.payload === "object") {
16345
17455
  const payload = entry.payload;
16346
17456
  if (payload.type === "message") {
16347
17457
  const role = payload.role;
16348
- const content = flattenContent2(payload.content);
17458
+ const content = flattenContent3(payload.content);
16349
17459
  if (role)
16350
17460
  return { role, content };
16351
17461
  }
16352
17462
  }
16353
17463
  if (entry.type === "message" && entry.role) {
16354
- return { role: entry.role, content: flattenContent2(entry.content) };
17464
+ return { role: entry.role, content: flattenContent3(entry.content) };
16355
17465
  }
16356
17466
  if (entry.type === "user" || entry.type === "assistant") {
16357
17467
  const role = entry.type;
16358
- const content = flattenContent2(entry.content ?? entry.message);
17468
+ const content = flattenContent3(entry.content ?? entry.message);
16359
17469
  return { role, content };
16360
17470
  }
16361
17471
  return null;
16362
17472
  }
16363
- function flattenContent2(content) {
17473
+ function flattenContent3(content) {
16364
17474
  if (!content)
16365
17475
  return;
16366
17476
  if (typeof content === "string")
@@ -16379,19 +17489,19 @@ function flattenContent2(content) {
16379
17489
  }
16380
17490
  return;
16381
17491
  }
16382
- function estimateTokens(prompt2, response) {
17492
+ function estimateTokens2(prompt2, response) {
16383
17493
  const tokensIn = prompt2 ? Math.ceil(prompt2.length / 4) : 0;
16384
17494
  const tokensOut = response ? Math.ceil(response.length / 4) : 0;
16385
17495
  return { tokensIn, tokensOut };
16386
17496
  }
16387
- function findSessionFiles(baseDir) {
16388
- if (!fs6.existsSync(baseDir))
17497
+ function findSessionFiles2(baseDir) {
17498
+ if (!fs14.existsSync(baseDir))
16389
17499
  return [];
16390
17500
  const results = [];
16391
17501
  const walk = (dir) => {
16392
- const entries = fs6.readdirSync(dir, { withFileTypes: true });
17502
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
16393
17503
  for (const entry of entries) {
16394
- const full = path6.join(dir, entry.name);
17504
+ const full = path13.join(dir, entry.name);
16395
17505
  if (entry.isDirectory()) {
16396
17506
  walk(full);
16397
17507
  } else if (entry.isFile() && (full.endsWith(".json") || full.endsWith(".jsonl"))) {
@@ -16402,52 +17512,191 @@ function findSessionFiles(baseDir) {
16402
17512
  walk(baseDir);
16403
17513
  return results;
16404
17514
  }
16405
- var init_codex = __esm(() => {
17515
+ var init_codex2 = __esm(() => {
16406
17516
  init_config();
16407
17517
  init_ingest();
16408
- init_state();
17518
+ init_state2();
16409
17519
  init_tool_extraction();
16410
17520
  });
16411
17521
 
16412
- // src/agent-hooks/launchagent.ts
16413
- function buildCodexLaunchAgentPlist(options) {
16414
- const { nodePath, cliPath, configPath } = options;
16415
- return `<?xml version="1.0" encoding="UTF-8"?>
16416
- ` + `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
16417
- ` + `<plist version="1.0">
16418
- ` + `<dict>
16419
- ` + ` <key>Label</key>
16420
- ` + ` <string>ai.verbal.codex-hooks</string>
16421
- ` + ` <key>ProgramArguments</key>
16422
- ` + ` <array>
16423
- ` + ` <string>${nodePath}</string>
16424
- ` + ` <string>${cliPath}</string>
16425
- ` + ` <string>watch</string>
16426
- ` + ` <string>--codex</string>
16427
- ` + ` </array>
16428
- ` + ` <key>RunAtLoad</key>
16429
- ` + ` <true/>
16430
- ` + ` <key>KeepAlive</key>
16431
- ` + ` <true/>
16432
- ` + ` <key>EnvironmentVariables</key>
16433
- ` + ` <dict>
16434
- ` + (configPath ? ` <key>VERBAL_CONFIG_PATH</key>
16435
- <string>${configPath}</string>
16436
- ` : "") + ` </dict>
16437
- ` + `</dict>
16438
- ` + `</plist>
16439
- `;
17522
+ // src/mcp/preflight.ts
17523
+ var exports_preflight = {};
17524
+ __export(exports_preflight, {
17525
+ runPreflight: () => runPreflight,
17526
+ formatPreflightForTerminal: () => formatPreflightForTerminal,
17527
+ buildSuggestion: () => buildSuggestion,
17528
+ ISSUE_SUGGESTIONS: () => ISSUE_SUGGESTIONS
17529
+ });
17530
+ function buildSuggestion(issues) {
17531
+ const top = issues.slice(0, 2);
17532
+ if (top.length === 0)
17533
+ return "";
17534
+ const tips = top.map((key) => ISSUE_SUGGESTIONS[key]).filter((tip) => Boolean(tip));
17535
+ if (tips.length === 0)
17536
+ return "";
17537
+ if (tips.length === 1)
17538
+ return tips[0];
17539
+ return `${tips[0]} Also: ${tips[1]}`;
17540
+ }
17541
+ async function runPreflight(prompt2, options) {
17542
+ const { config: config3, apiKey, apiUrl, cooldownActive } = options;
17543
+ if (prompt2.trim().length < 20) {
17544
+ return { skipped: true, skip_reason: "short_prompt" };
17545
+ }
17546
+ if (cooldownActive) {
17547
+ return { skipped: true, skip_reason: "cooldown" };
17548
+ }
17549
+ const requestThreshold = config3.enable_llm_rewrite ? config3.threshold : 101;
17550
+ let response;
17551
+ try {
17552
+ response = await fetch(`${apiUrl}/api/v1/optimize`, {
17553
+ method: "POST",
17554
+ headers: {
17555
+ Authorization: `Bearer ${apiKey}`,
17556
+ "Content-Type": "application/json"
17557
+ },
17558
+ body: JSON.stringify({
17559
+ prompt: prompt2,
17560
+ threshold: requestThreshold
17561
+ })
17562
+ });
17563
+ } catch {
17564
+ return { skipped: true, skip_reason: "error" };
17565
+ }
17566
+ if (response.status === 402) {
17567
+ return { skipped: true, skip_reason: "tier_gate" };
17568
+ }
17569
+ if (!response.ok) {
17570
+ return { skipped: true, skip_reason: "error" };
17571
+ }
17572
+ let data;
17573
+ try {
17574
+ data = await response.json();
17575
+ } catch {
17576
+ return { skipped: true, skip_reason: "error" };
17577
+ }
17578
+ const score = data.original_score;
17579
+ const issues = Array.isArray(data.issues) ? data.issues : [];
17580
+ if (score >= config3.threshold) {
17581
+ return {
17582
+ skipped: true,
17583
+ skip_reason: "above_threshold",
17584
+ score,
17585
+ issues
17586
+ };
17587
+ }
17588
+ const suggestion = buildSuggestion(issues);
17589
+ return {
17590
+ skipped: false,
17591
+ score,
17592
+ issues,
17593
+ suggestion,
17594
+ optimized_prompt: config3.enable_llm_rewrite ? data.optimized_prompt : null,
17595
+ improvement_delta: config3.enable_llm_rewrite ? data.improvement_delta : null
17596
+ };
17597
+ }
17598
+ function formatPreflightForTerminal(result) {
17599
+ if (result.skipped)
17600
+ return "";
17601
+ const lines = [];
17602
+ lines.push(`⚡ Prompt score: ${result.score ?? "?"}/100`);
17603
+ if (result.suggestion) {
17604
+ lines.push(`\uD83D\uDCA1 ${result.suggestion}`);
17605
+ }
17606
+ if (result.optimized_prompt) {
17607
+ const delta = result.improvement_delta != null ? ` (+${result.improvement_delta} pts)` : "";
17608
+ lines.push(`✨ Optimized prompt${delta}:`);
17609
+ lines.push("");
17610
+ lines.push(result.optimized_prompt);
17611
+ }
17612
+ return lines.join(`
17613
+ `);
17614
+ }
17615
+ var ISSUE_SUGGESTIONS;
17616
+ var init_preflight = __esm(() => {
17617
+ ISSUE_SUGGESTIONS = {
17618
+ vague_instruction: "Be more specific — describe the exact outcome you want, not just the task category.",
17619
+ no_output_format: 'Specify the output format (e.g. "return a JSON object", "write a numbered list", "respond in markdown").',
17620
+ missing_constraints: "Add constraints (e.g. word count, language, framework version) to narrow the solution space.",
17621
+ no_context: "Include relevant context (e.g. language, tech stack, existing code) so the model has what it needs.",
17622
+ ambiguous_subject: "Clarify the subject — what exactly should be modified, created, or explained?",
17623
+ missing_examples: "Provide an example input/output pair to show the pattern you expect.",
17624
+ overly_broad: "Break this into smaller, focused requests rather than asking for everything at once.",
17625
+ passive_voice: 'Use active, imperative phrasing (e.g. "Generate X" instead of "X should be generated").',
17626
+ no_success_criteria: 'State what "done" looks like so the model can self-verify its response.',
17627
+ redundant_preamble: 'Start with the request — cut the "I want you to act as" or similar preambles.'
17628
+ };
17629
+ });
17630
+
17631
+ // src/agent-hooks/cursor-watcher.ts
17632
+ var exports_cursor_watcher = {};
17633
+ __export(exports_cursor_watcher, {
17634
+ watchCursorWorkspaces: () => watchCursorWorkspaces
17635
+ });
17636
+ async function watchCursorWorkspaces(config3, options = {}) {
17637
+ const intervalMs = options.intervalMs ?? 5000;
17638
+ const parser = new CursorParser;
17639
+ const stateDir = config3.claudeStateDir;
17640
+ const sync = async () => {
17641
+ try {
17642
+ const state = loadPlatformState(stateDir, "cursor");
17643
+ const result = await parser.parse(state, {});
17644
+ if (result.events.length > 0) {
17645
+ const ingestor2 = createIngestor(config3);
17646
+ for (const event of result.events) {
17647
+ const cost = event.billing_type === "subscription" ? 0 : calculateCost(event.model, event.tokens_in, event.tokens_out, event.cache_read_tokens, event.cache_write_tokens);
17648
+ const usageEvent = {
17649
+ event_id: event.event_id,
17650
+ event_type: "usage",
17651
+ provider: event.provider,
17652
+ model: event.model,
17653
+ tokens_in: event.tokens_in,
17654
+ tokens_out: event.tokens_out,
17655
+ total_tokens: event.tokens_in + event.tokens_out,
17656
+ cache_read_tokens: event.cache_read_tokens,
17657
+ cache_write_tokens: event.cache_write_tokens,
17658
+ cost,
17659
+ billing_type: event.billing_type,
17660
+ timestamp: event.timestamp,
17661
+ session_id: event.session_id,
17662
+ request_id: event.request_id,
17663
+ tags: event.tags,
17664
+ metadata: { ...event.metadata, import_source: "cursor-watcher" }
17665
+ };
17666
+ await ingestor2.track(usageEvent);
17667
+ }
17668
+ await ingestor2.flush();
17669
+ ingestor2.destroy();
17670
+ }
17671
+ savePlatformState(stateDir, "cursor", result.newState);
17672
+ if (result.warnings.length > 0) {
17673
+ for (const warning of result.warnings) {
17674
+ console.error(`[Cursor watcher] ${warning}`);
17675
+ }
17676
+ }
17677
+ } catch (err) {
17678
+ console.error("[Cursor watcher] Error:", err instanceof Error ? err.message : err);
17679
+ }
17680
+ };
17681
+ await sync();
17682
+ setInterval(sync, intervalMs);
16440
17683
  }
17684
+ var init_cursor_watcher = __esm(() => {
17685
+ init_cursor();
17686
+ init_state();
17687
+ init_ingest();
17688
+ init_pricing();
17689
+ });
16441
17690
 
16442
17691
  // src/agent-hooks/cli.ts
16443
17692
  var exports_cli = {};
16444
17693
  __export(exports_cli, {
16445
17694
  main: () => main
16446
17695
  });
16447
- import fs7 from "node:fs";
16448
- import os6 from "node:os";
16449
- import path7 from "node:path";
16450
- import { fileURLToPath } from "node:url";
17696
+ import fs15 from "node:fs";
17697
+ import os12 from "node:os";
17698
+ import path14 from "node:path";
17699
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
16451
17700
  async function main(args = process.argv) {
16452
17701
  const command = args[2];
16453
17702
  switch (command) {
@@ -16457,6 +17706,53 @@ async function main(args = process.argv) {
16457
17706
  await ingestClaudeHookInput(input, config3);
16458
17707
  return;
16459
17708
  }
17709
+ case "preflight": {
17710
+ const config3 = loadHookConfig();
17711
+ const flags = parseFlags(args.slice(3));
17712
+ const prompt2 = await readStdinText();
17713
+ if (!prompt2 || prompt2.trim().length === 0) {
17714
+ return;
17715
+ }
17716
+ const { runPreflight: runPreflight2, formatPreflightForTerminal: formatPreflightForTerminal2 } = await Promise.resolve().then(() => (init_preflight(), exports_preflight));
17717
+ const {
17718
+ loadPreflightState: loadPreflightState2,
17719
+ savePreflightState: savePreflightState2,
17720
+ getDefaultStateDir: getDefaultStateDir2,
17721
+ isCooldownActive: isCooldownActive2,
17722
+ updatePreflightStats: updatePreflightStats2,
17723
+ addPendingFeedback: addPendingFeedback2
17724
+ } = await Promise.resolve().then(() => (init_preflight_state(), exports_preflight_state));
17725
+ const stateDir = getDefaultStateDir2();
17726
+ const state = loadPreflightState2(stateDir);
17727
+ const mode = flags.mode ?? state.config.mode;
17728
+ const threshold = flags.threshold ?? state.config.threshold;
17729
+ const result = await runPreflight2(prompt2.trim(), {
17730
+ config: { threshold, mode, enable_llm_rewrite: state.config.enable_llm_rewrite, cooldown_minutes: state.config.cooldown_minutes },
17731
+ apiKey: config3.apiKey,
17732
+ apiUrl: config3.apiUrl,
17733
+ cooldownActive: isCooldownActive2(state)
17734
+ });
17735
+ let updatedState = result.skipped ? updatePreflightStats2(state, "skipped", result.score ?? 0) : updatePreflightStats2(state, "shown", result.score ?? 0);
17736
+ if (!result.skipped && mode !== "silent") {
17737
+ const formatted = formatPreflightForTerminal2(result);
17738
+ if (formatted) {
17739
+ process.stderr.write(formatted + `
17740
+ `);
17741
+ }
17742
+ }
17743
+ if (!result.skipped) {
17744
+ updatedState = addPendingFeedback2(updatedState, {
17745
+ timestamp: new Date().toISOString(),
17746
+ score: result.score ?? 0,
17747
+ action: "dismissed",
17748
+ issues: result.issues ?? []
17749
+ });
17750
+ }
17751
+ savePreflightState2(stateDir, updatedState);
17752
+ process.stdout.write(JSON.stringify(result) + `
17753
+ `);
17754
+ return;
17755
+ }
16460
17756
  case "ingest-now": {
16461
17757
  const config3 = loadHookConfig();
16462
17758
  const flags = parseFlags(args.slice(3));
@@ -16467,9 +17763,9 @@ async function main(args = process.argv) {
16467
17763
  const input = { session_id: `manual-${Date.now()}`, transcript_path: flags.path };
16468
17764
  await ingestClaudeHookInput(input, config3);
16469
17765
  }
16470
- if (flags.tokscale) {
16471
- const { syncFromTokscale: syncFromTokscale2 } = await Promise.resolve().then(() => (init_tokscale(), exports_tokscale));
16472
- const result = await syncFromTokscale2({
17766
+ if (flags.sync || flags.tokscale) {
17767
+ const { syncPlatforms: syncPlatforms2 } = await Promise.resolve().then(() => (init_orchestrator(), exports_orchestrator));
17768
+ const result = await syncPlatforms2({
16473
17769
  apiKey: config3.apiKey,
16474
17770
  ingestUrl: config3.ingestUrl,
16475
17771
  hmacSecret: config3.hmacSecret,
@@ -16484,29 +17780,55 @@ async function main(args = process.argv) {
16484
17780
  platforms: flags.platforms,
16485
17781
  project: config3.defaultProject
16486
17782
  });
16487
- console.log(`Tokscale sync: ${result.events} events, ${result.days} days, $${result.totalCost.toFixed(2)} total`);
17783
+ console.log(`Platform sync: ${result.totalEvents} events, $${result.totalCost.toFixed(2)} total`);
17784
+ for (const p of result.platforms) {
17785
+ if (p.error)
17786
+ console.log(` ${p.id}: ERROR — ${p.error}`);
17787
+ else
17788
+ console.log(` ${p.id}: ${p.events} events, $${p.totalCost.toFixed(2)}`);
17789
+ }
16488
17790
  }
16489
17791
  return;
16490
17792
  }
16491
17793
  case "watch": {
16492
17794
  const config3 = loadHookConfig();
16493
17795
  const flags = parseFlags(args.slice(3));
16494
- if (flags.codex) {
16495
- await watchCodexSessions(config3, { path: flags.path });
16496
- await new Promise(() => {
16497
- return;
16498
- });
17796
+ const watchCodex = flags.codex || !flags.codex && !flags.cursor;
17797
+ const watchCursor = flags.cursor || !flags.codex && !flags.cursor;
17798
+ const promises = [];
17799
+ if (watchCodex) {
17800
+ promises.push(watchCodexSessions(config3, { path: flags.path }));
17801
+ }
17802
+ if (watchCursor) {
17803
+ const { watchCursorWorkspaces: watchCursorWorkspaces2 } = await Promise.resolve().then(() => (init_cursor_watcher(), exports_cursor_watcher));
17804
+ promises.push(watchCursorWorkspaces2(config3));
17805
+ }
17806
+ if (promises.length === 0) {
17807
+ console.log("Nothing to watch. Use --codex or --cursor.");
17808
+ return;
16499
17809
  }
16500
- console.log("Nothing to watch. Use --codex.");
17810
+ await Promise.race(promises);
17811
+ await new Promise(() => {
17812
+ return;
17813
+ });
16501
17814
  return;
16502
17815
  }
16503
17816
  case "install": {
16504
17817
  const flags = parseFlags(args.slice(3));
16505
17818
  if (flags.claude) {
16506
- installClaudeHooks();
17819
+ const { installClaudeHooks: installClaude } = await Promise.resolve().then(() => (init_hooks_installer(), exports_hooks_installer));
17820
+ installClaude();
17821
+ console.log(`Installed Claude hooks in ${path14.join(os12.homedir(), ".claude", "settings.json")}`);
16507
17822
  }
16508
17823
  if (flags.codex) {
16509
- installCodexLaunchAgent();
17824
+ if (process.platform === "darwin") {
17825
+ const { installUnifiedWatcher: installUnifiedWatcher2 } = await Promise.resolve().then(() => (init_hooks_installer(), exports_hooks_installer));
17826
+ installUnifiedWatcher2();
17827
+ const plistPath = path14.join(os12.homedir(), "Library", "LaunchAgents", "ai.verbal.watcher.plist");
17828
+ console.log(`Wrote LaunchAgent to ${plistPath}`);
17829
+ } else {
17830
+ installCodexLaunchAgent();
17831
+ }
16510
17832
  }
16511
17833
  return;
16512
17834
  }
@@ -16541,7 +17863,9 @@ function parseFlags(args) {
16541
17863
  const flags = {
16542
17864
  codex: false,
16543
17865
  claude: false,
17866
+ cursor: false,
16544
17867
  tokscale: false,
17868
+ sync: false,
16545
17869
  path: undefined,
16546
17870
  since: undefined,
16547
17871
  until: undefined,
@@ -16553,8 +17877,12 @@ function parseFlags(args) {
16553
17877
  flags.codex = true;
16554
17878
  if (arg === "--claude")
16555
17879
  flags.claude = true;
17880
+ if (arg === "--cursor")
17881
+ flags.cursor = true;
16556
17882
  if (arg === "--tokscale")
16557
17883
  flags.tokscale = true;
17884
+ if (arg === "--sync")
17885
+ flags.sync = true;
16558
17886
  if (arg === "--path") {
16559
17887
  flags.path = args[i + 1];
16560
17888
  i++;
@@ -16572,86 +17900,46 @@ function parseFlags(args) {
16572
17900
  flags.platforms = raw ? raw.split(",").map((p) => p.trim()).filter(Boolean) : [];
16573
17901
  i++;
16574
17902
  }
17903
+ if (arg === "--mode") {
17904
+ flags.mode = args[i + 1];
17905
+ i++;
17906
+ }
17907
+ if (arg === "--threshold") {
17908
+ flags.threshold = parseInt(args[i + 1], 10);
17909
+ i++;
17910
+ }
16575
17911
  }
16576
17912
  return flags;
16577
17913
  }
16578
- function installClaudeHooks() {
16579
- const settingsPath = path7.join(os6.homedir(), ".claude", "settings.json");
16580
- const hooksRoot = path7.resolve(__dirname2, "..", "..", "hooks");
16581
- const stopHook = path7.join(hooksRoot, "ingest-stop-hook.sh");
16582
- const endHook = path7.join(hooksRoot, "ingest-session-end-hook.sh");
16583
- const configPath = findMcpConfigPath();
16584
- const settings = readJson(settingsPath) ?? {};
16585
- settings.hooks = settings.hooks ?? {};
16586
- upsertHook(settings, "Stop", stopHook, {
16587
- timeout: 30,
16588
- statusMessage: "Tracking usage in Verbal",
16589
- async: true,
16590
- env: configPath ? { VERBAL_CONFIG_PATH: configPath } : undefined
16591
- });
16592
- upsertHook(settings, "SessionEnd", endHook, {
16593
- timeout: 30,
16594
- statusMessage: "Finalizing usage data",
16595
- env: configPath ? { VERBAL_CONFIG_PATH: configPath } : undefined
16596
- });
16597
- const reviewPromptHook = path7.join(hooksRoot, "session-review-prompt.js");
16598
- upsertHook(settings, "Stop", `node ${reviewPromptHook}`, {
16599
- timeout: 5,
16600
- statusMessage: "Checking session review timer"
16601
- });
16602
- fs7.mkdirSync(path7.dirname(settingsPath), { recursive: true });
16603
- fs7.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
16604
- console.log(`Installed Claude hooks in ${settingsPath}`);
16605
- }
16606
17914
  function uninstallClaudeHooks() {
16607
- const settingsPath = path7.join(os6.homedir(), ".claude", "settings.json");
16608
- const settings = readJson(settingsPath);
17915
+ const settingsPath = path14.join(os12.homedir(), ".claude", "settings.json");
17916
+ const settings = readJson2(settingsPath);
16609
17917
  if (!settings?.hooks)
16610
17918
  return;
16611
17919
  removeHook(settings, "Stop", "ingest-stop-hook.sh");
16612
17920
  removeHook(settings, "Stop", "session-review-prompt.js");
16613
17921
  removeHook(settings, "SessionEnd", "ingest-session-end-hook.sh");
16614
- fs7.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
17922
+ fs15.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
16615
17923
  console.log(`Removed Verbal Claude hooks from ${settingsPath}`);
16616
17924
  }
16617
17925
  function installCodexLaunchAgent() {
16618
- const plistPath = path7.join(os6.homedir(), "Library", "LaunchAgents", "ai.verbal.codex-hooks.plist");
16619
- const cliPath = path7.resolve(__dirname2, "cli.js");
17926
+ const plistPath = path14.join(os12.homedir(), "Library", "LaunchAgents", "ai.verbal.codex-hooks.plist");
17927
+ const cliPath = path14.resolve(__dirname3, "cli.js");
16620
17928
  const nodePath = process.execPath;
16621
- const configPath = findMcpConfigPath() ?? undefined;
17929
+ const configPath = findMcpConfigPath2() ?? undefined;
16622
17930
  const plist = buildCodexLaunchAgentPlist({ nodePath, cliPath, configPath });
16623
- fs7.mkdirSync(path7.dirname(plistPath), { recursive: true });
16624
- fs7.writeFileSync(plistPath, plist);
17931
+ fs15.mkdirSync(path14.dirname(plistPath), { recursive: true });
17932
+ fs15.writeFileSync(plistPath, plist);
16625
17933
  console.log(`Wrote LaunchAgent to ${plistPath}`);
16626
17934
  console.log("Load with: launchctl load ~/Library/LaunchAgents/ai.verbal.codex-hooks.plist");
16627
17935
  }
16628
17936
  function uninstallCodexLaunchAgent() {
16629
- const plistPath = path7.join(os6.homedir(), "Library", "LaunchAgents", "ai.verbal.codex-hooks.plist");
16630
- if (fs7.existsSync(plistPath)) {
16631
- fs7.unlinkSync(plistPath);
17937
+ const plistPath = path14.join(os12.homedir(), "Library", "LaunchAgents", "ai.verbal.codex-hooks.plist");
17938
+ if (fs15.existsSync(plistPath)) {
17939
+ fs15.unlinkSync(plistPath);
16632
17940
  console.log(`Removed ${plistPath}`);
16633
17941
  }
16634
17942
  }
16635
- function upsertHook(settings, hookName, command, options) {
16636
- const hookEntry = {
16637
- matcher: "",
16638
- hooks: [
16639
- {
16640
- type: "command",
16641
- command,
16642
- ...options
16643
- }
16644
- ]
16645
- };
16646
- settings.hooks = settings.hooks ?? {};
16647
- settings.hooks[hookName] = settings.hooks[hookName] ?? [];
16648
- const existingIndex = settings.hooks[hookName].findIndex((entry) => entry.hooks?.some((hook) => hook.command.includes(path7.basename(command))));
16649
- if (existingIndex >= 0) {
16650
- settings.hooks[hookName][existingIndex] = hookEntry;
16651
- } else {
16652
- settings.hooks[hookName].push(hookEntry);
16653
- }
16654
- }
16655
17943
  function removeHook(settings, hookName, commandFragment) {
16656
17944
  if (!settings.hooks?.[hookName])
16657
17945
  return;
@@ -16660,22 +17948,22 @@ function removeHook(settings, hookName, commandFragment) {
16660
17948
  return !hooks.some((hook) => hook.command.includes(commandFragment));
16661
17949
  });
16662
17950
  }
16663
- function readJson(filePath) {
17951
+ function readJson2(filePath) {
16664
17952
  try {
16665
- if (!fs7.existsSync(filePath))
17953
+ if (!fs15.existsSync(filePath))
16666
17954
  return null;
16667
- return JSON.parse(fs7.readFileSync(filePath, "utf8"));
17955
+ return JSON.parse(fs15.readFileSync(filePath, "utf8"));
16668
17956
  } catch {
16669
17957
  return null;
16670
17958
  }
16671
17959
  }
16672
- function findMcpConfigPath() {
17960
+ function findMcpConfigPath2() {
16673
17961
  let current = process.cwd();
16674
17962
  for (;; ) {
16675
- const candidate = path7.join(current, ".mcp.json");
16676
- if (fs7.existsSync(candidate))
17963
+ const candidate = path14.join(current, ".mcp.json");
17964
+ if (fs15.existsSync(candidate))
16677
17965
  return candidate;
16678
- const parent = path7.dirname(current);
17966
+ const parent = path14.dirname(current);
16679
17967
  if (parent === current)
16680
17968
  return null;
16681
17969
  current = parent;
@@ -16691,24 +17979,35 @@ async function readStdinJson() {
16691
17979
  const content = Buffer.concat(chunks).toString("utf8");
16692
17980
  return JSON.parse(content);
16693
17981
  }
17982
+ async function readStdinText() {
17983
+ const chunks = [];
17984
+ for await (const chunk of process.stdin) {
17985
+ chunks.push(Buffer.from(chunk));
17986
+ }
17987
+ return Buffer.concat(chunks).toString("utf8");
17988
+ }
16694
17989
  function printHelp() {
16695
17990
  console.log(`verbal-hooks usage:
16696
17991
  verbal-hooks install --claude --codex
16697
17992
  verbal-hooks ingest-now --codex [--path <dir>]
16698
17993
  verbal-hooks ingest-now --claude --path <transcript.jsonl>
16699
- verbal-hooks ingest-now --tokscale [--since YYYY-MM-DD] [--until YYYY-MM-DD] [--platforms claude,codex,...]
16700
- verbal-hooks watch --codex [--path <dir>]
17994
+ verbal-hooks ingest-now --sync [--since YYYY-MM-DD] [--until YYYY-MM-DD] [--platforms claude-code,codex,...]
17995
+ verbal-hooks ingest-now --tokscale [--since YYYY-MM-DD] [--until YYYY-MM-DD] [--platforms claude-code,codex,...]
17996
+ verbal-hooks watch [--codex [--path <dir>]] [--cursor]
17997
+ (no flags = auto-detect, watches all available sources)
17998
+ verbal-hooks preflight [--mode silent|notify|blocking] [--threshold 60]
17999
+ (reads prompt from stdin, prints coaching to stderr)
16701
18000
  verbal-hooks status
16702
18001
  verbal-hooks uninstall --claude --codex
16703
18002
  `);
16704
18003
  }
16705
- var __filename2, __dirname2;
18004
+ var __filename3, __dirname3;
16706
18005
  var init_cli = __esm(() => {
16707
18006
  init_config();
16708
18007
  init_claude();
16709
- init_codex();
16710
- __filename2 = fileURLToPath(import.meta.url);
16711
- __dirname2 = path7.dirname(__filename2);
18008
+ init_codex2();
18009
+ __filename3 = fileURLToPath2(import.meta.url);
18010
+ __dirname3 = path14.dirname(__filename3);
16712
18011
  if (import.meta.url === `file://${process.argv[1]}`) {
16713
18012
  main(process.argv).catch((error2) => {
16714
18013
  console.error(error2 instanceof Error ? error2.message : error2);
@@ -16733,10 +18032,10 @@ __export(exports_notify, {
16733
18032
  printUpdateNotice: () => printUpdateNotice
16734
18033
  });
16735
18034
  import { readFileSync as readFileSync10 } from "node:fs";
16736
- import { join as join14 } from "node:path";
18035
+ import { join as join15 } from "node:path";
16737
18036
  function printUpdateNotice(currentVersion) {
16738
18037
  try {
16739
- const cachePath = join14(getCredentialsDir(), "update-check.json");
18038
+ const cachePath = join15(getCredentialsDir(), "update-check.json");
16740
18039
  const raw = readFileSync10(cachePath, "utf-8");
16741
18040
  const cache = JSON.parse(raw);
16742
18041
  if (compareSemver(currentVersion, cache.latest) >= 0)
@@ -16773,10 +18072,10 @@ var import_picocolors9 = __toESM(require_picocolors(), 1);
16773
18072
  // src/commands/init.ts
16774
18073
  var import_picocolors = __toESM(require_picocolors(), 1);
16775
18074
  import { createInterface } from "node:readline/promises";
16776
- import { execSync as execSync6 } from "node:child_process";
16777
- import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
16778
- import { join as join11 } from "node:path";
16779
- import { homedir as homedir10 } from "node:os";
18075
+ import { execSync as execSync7 } from "node:child_process";
18076
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
18077
+ import { join as join12 } from "node:path";
18078
+ import { homedir as homedir11 } from "node:os";
16780
18079
 
16781
18080
  // src/auth/browser-auth.ts
16782
18081
  import { createServer } from "node:http";
@@ -17237,19 +18536,49 @@ async function detectCodex() {
17237
18536
  }
17238
18537
  }
17239
18538
 
18539
+ // src/detect/gemini.ts
18540
+ import { existsSync as existsSync5 } from "node:fs";
18541
+ import { homedir as homedir6 } from "node:os";
18542
+ import { join as join6 } from "node:path";
18543
+ async function detectGemini() {
18544
+ const home = homedir6();
18545
+ const paths = [
18546
+ join6(home, ".gemini"),
18547
+ join6(home, ".config", "gemini")
18548
+ ];
18549
+ const found = paths.find((p) => existsSync5(p));
18550
+ if (!found) {
18551
+ return {
18552
+ tool: "gemini",
18553
+ detected: false,
18554
+ configPath: "",
18555
+ existingConfig: false,
18556
+ details: "Gemini CLI data not found"
18557
+ };
18558
+ }
18559
+ return {
18560
+ tool: "gemini",
18561
+ detected: true,
18562
+ configPath: "",
18563
+ existingConfig: false,
18564
+ details: `Gemini CLI data at ${found}`
18565
+ };
18566
+ }
18567
+
17240
18568
  // src/detect/index.ts
17241
18569
  async function detectAll() {
17242
18570
  const results = await Promise.allSettled([
17243
18571
  detectClaudeCode(),
17244
18572
  detectClaudeDesktop(),
17245
18573
  detectCursor(),
17246
- detectCodex()
18574
+ detectCodex(),
18575
+ detectGemini()
17247
18576
  ]);
17248
18577
  return results.map((result, index) => {
17249
18578
  if (result.status === "fulfilled") {
17250
18579
  return result.value;
17251
18580
  }
17252
- const tools = ["claude-code", "claude-desktop", "cursor", "codex"];
18581
+ const tools = ["claude-code", "claude-desktop", "cursor", "codex", "gemini"];
17253
18582
  const tool = tools[index];
17254
18583
  return {
17255
18584
  tool,
@@ -17262,28 +18591,28 @@ async function detectAll() {
17262
18591
  }
17263
18592
 
17264
18593
  // src/configure/index.ts
17265
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "node:fs";
18594
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync2, existsSync as existsSync6 } from "node:fs";
17266
18595
  import { dirname, resolve } from "node:path";
17267
18596
 
17268
18597
  // src/configure/claude-code.ts
17269
- import { join as join6 } from "node:path";
18598
+ import { join as join7 } from "node:path";
17270
18599
  async function configureClaudeCode(_detection, credentials, billingType, useGlobal = false) {
17271
- const configPath = join6(process.cwd(), ".mcp.json");
18600
+ const configPath = join7(process.cwd(), ".mcp.json");
17272
18601
  mergeConfig(configPath, credentials, billingType, useGlobal);
17273
18602
  }
17274
18603
 
17275
18604
  // src/configure/claude-desktop.ts
17276
- import { homedir as homedir6 } from "node:os";
17277
- import { join as join7 } from "node:path";
18605
+ import { homedir as homedir7 } from "node:os";
18606
+ import { join as join8 } from "node:path";
17278
18607
  function getConfigPath2() {
17279
18608
  const platform = process.platform;
17280
18609
  if (platform === "darwin") {
17281
- return join7(homedir6(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
18610
+ return join8(homedir7(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
17282
18611
  }
17283
18612
  if (platform === "win32") {
17284
- return join7(process.env["APPDATA"] ?? homedir6(), "Claude", "claude_desktop_config.json");
18613
+ return join8(process.env["APPDATA"] ?? homedir7(), "Claude", "claude_desktop_config.json");
17285
18614
  }
17286
- return join7(homedir6(), ".config", "claude", "claude_desktop_config.json");
18615
+ return join8(homedir7(), ".config", "claude", "claude_desktop_config.json");
17287
18616
  }
17288
18617
  async function configureClaudeDesktop(_detection, credentials, billingType, useGlobal = false) {
17289
18618
  const configPath = getConfigPath2();
@@ -17291,27 +18620,31 @@ async function configureClaudeDesktop(_detection, credentials, billingType, useG
17291
18620
  }
17292
18621
 
17293
18622
  // src/configure/cursor.ts
17294
- import { homedir as homedir7 } from "node:os";
17295
- import { join as join8 } from "node:path";
18623
+ import { homedir as homedir8 } from "node:os";
18624
+ import { join as join9 } from "node:path";
17296
18625
  async function configureCursor(_detection, credentials, billingType, useGlobal = false) {
17297
- const configPath = join8(homedir7(), ".cursor", "mcp.json");
18626
+ const configPath = join9(homedir8(), ".cursor", "mcp.json");
17298
18627
  mergeConfig(configPath, credentials, billingType, useGlobal);
17299
18628
  }
17300
18629
 
17301
18630
  // src/configure/codex.ts
17302
- import { homedir as homedir8 } from "node:os";
17303
- import { join as join9 } from "node:path";
18631
+ import { homedir as homedir9 } from "node:os";
18632
+ import { join as join10 } from "node:path";
17304
18633
  async function configureCodex(_detection, credentials, billingType, useGlobal = false) {
17305
- const configPath = join9(homedir8(), ".codex", "config.json");
18634
+ const configPath = join10(homedir9(), ".codex", "config.json");
17306
18635
  mergeConfig(configPath, credentials, billingType, useGlobal);
17307
18636
  }
17308
18637
 
18638
+ // src/configure/gemini.ts
18639
+ async function configureGemini(_detection, _credentials, _billingType, _useGlobal) {}
18640
+
17309
18641
  // src/configure/index.ts
17310
18642
  var TOOL_DEFAULT_BILLING_TYPE = {
17311
18643
  "claude-code": "api",
17312
18644
  "claude-desktop": "subscription",
17313
18645
  cursor: "subscription",
17314
- codex: "api"
18646
+ codex: "api",
18647
+ gemini: "api"
17315
18648
  };
17316
18649
  function buildVerbalMcpEntry(credentials, billingType = "api", useGlobal = false) {
17317
18650
  return {
@@ -17333,7 +18666,7 @@ function buildVerbalMcpEntry(credentials, billingType = "api", useGlobal = false
17333
18666
  function mergeConfig(configPath, credentials, billingType, useGlobal = false) {
17334
18667
  mkdirSync2(dirname(configPath), { recursive: true });
17335
18668
  let config = {};
17336
- if (existsSync5(configPath)) {
18669
+ if (existsSync6(configPath)) {
17337
18670
  try {
17338
18671
  config = JSON.parse(readFileSync6(configPath, "utf-8"));
17339
18672
  } catch {
@@ -17350,7 +18683,7 @@ function mergeConfig(configPath, credentials, billingType, useGlobal = false) {
17350
18683
  }
17351
18684
  function removeVerbalConfig(configPath) {
17352
18685
  const resolvedPath = resolve(configPath);
17353
- if (!existsSync5(resolvedPath)) {
18686
+ if (!existsSync6(resolvedPath)) {
17354
18687
  return;
17355
18688
  }
17356
18689
  let config;
@@ -17398,10 +18731,9 @@ async function configureAll(detections, credentials, useGlobal = false) {
17398
18731
  case "codex":
17399
18732
  await configureCodex(detection, credentials, billingType, useGlobal);
17400
18733
  break;
17401
- default: {
17402
- const _exhaustive = detection.tool;
17403
- throw new Error(`Unknown tool: ${String(_exhaustive)}`);
17404
- }
18734
+ case "gemini":
18735
+ await configureGemini(detection, credentials, billingType, useGlobal);
18736
+ break;
17405
18737
  }
17406
18738
  success = true;
17407
18739
  } catch (err) {
@@ -17449,6 +18781,7 @@ async function verifyConnection(credentials) {
17449
18781
  }
17450
18782
 
17451
18783
  // src/commands/init.ts
18784
+ init_preflight_state();
17452
18785
  async function confirm(rl, message, defaultYes) {
17453
18786
  const hint = defaultYes ? "(Y/n)" : "(y/N)";
17454
18787
  const answer = await rl.question(`${message} ${hint} `);
@@ -17458,8 +18791,8 @@ async function confirm(rl, message, defaultYes) {
17458
18791
  return trimmed === "y" || trimmed === "yes";
17459
18792
  }
17460
18793
  function isInGitignore(filename) {
17461
- const gitignorePath = join11(process.cwd(), ".gitignore");
17462
- if (!existsSync7(gitignorePath))
18794
+ const gitignorePath = join12(process.cwd(), ".gitignore");
18795
+ if (!existsSync8(gitignorePath))
17463
18796
  return false;
17464
18797
  try {
17465
18798
  const content = readFileSync7(gitignorePath, "utf-8");
@@ -17479,6 +18812,8 @@ function toolDisplayName(tool) {
17479
18812
  return "Cursor";
17480
18813
  case "codex":
17481
18814
  return "Codex";
18815
+ case "gemini":
18816
+ return "Gemini CLI";
17482
18817
  default: {
17483
18818
  const _exhaustive = tool;
17484
18819
  return String(_exhaustive);
@@ -17487,7 +18822,7 @@ function toolDisplayName(tool) {
17487
18822
  }
17488
18823
  function isGloballyInstalled() {
17489
18824
  try {
17490
- const which = execSync6("which getverbal", { encoding: "utf-8" }).trim();
18825
+ const which = execSync7("which getverbal", { encoding: "utf-8" }).trim();
17491
18826
  return !which.includes("npx") && !which.includes(".npm/_npx");
17492
18827
  } catch {
17493
18828
  return false;
@@ -17504,7 +18839,7 @@ async function promoteToGlobal(rl) {
17504
18839
  console.log(`
17505
18840
  ${import_picocolors.default.dim("ℹ")} Installing globally...`);
17506
18841
  try {
17507
- execSync6(`npm install -g @getverbal/cli@${VERSION}`, { stdio: "inherit" });
18842
+ execSync7(`npm install -g @getverbal/cli@${VERSION}`, { stdio: "inherit" });
17508
18843
  console.log(import_picocolors.default.green(` ✓ Installed getverbal v${VERSION} globally`));
17509
18844
  return true;
17510
18845
  } catch {
@@ -17544,6 +18879,32 @@ async function runInit() {
17544
18879
  process.exit(1);
17545
18880
  }
17546
18881
  }
18882
+ {
18883
+ const stateDir = getDefaultStateDir();
18884
+ const preflightState = loadPreflightState(stateDir);
18885
+ let enableLlmRewrite = false;
18886
+ try {
18887
+ const probeRes = await fetch(`${credentials.api_url}/api/v1/optimize`, {
18888
+ method: "POST",
18889
+ headers: {
18890
+ "Content-Type": "application/json",
18891
+ Authorization: `Bearer ${credentials.api_key}`
18892
+ },
18893
+ body: JSON.stringify({ prompt: ".", threshold: 101 })
18894
+ });
18895
+ if (probeRes.status === 200) {
18896
+ enableLlmRewrite = true;
18897
+ }
18898
+ } catch {}
18899
+ preflightState.config.enable_llm_rewrite = enableLlmRewrite;
18900
+ savePreflightState(stateDir, preflightState);
18901
+ if (enableLlmRewrite) {
18902
+ console.log(import_picocolors.default.green(" ✓ Preflight LLM rewrite enabled (Pro/Team)"));
18903
+ } else {
18904
+ console.log(import_picocolors.default.dim(" ✗ Preflight LLM rewrite disabled (Free tier)"));
18905
+ }
18906
+ console.log();
18907
+ }
17547
18908
  console.log(import_picocolors.default.bold("Detecting AI tools..."));
17548
18909
  const detections = await detectAll();
17549
18910
  for (const d of detections) {
@@ -17598,6 +18959,39 @@ async function runInit() {
17598
18959
  }
17599
18960
  console.log();
17600
18961
  }
18962
+ const confirmedTools = confirmed.map((d) => d.tool);
18963
+ if (confirmedTools.includes("claude-code")) {
18964
+ try {
18965
+ const { installClaudeHooks: installClaudeHooks2 } = await Promise.resolve().then(() => (init_hooks_installer(), exports_hooks_installer));
18966
+ installClaudeHooks2(useGlobal);
18967
+ console.log(import_picocolors.default.green(" ✓ Claude Code real-time hooks installed"));
18968
+ } catch (err) {
18969
+ const msg = err instanceof Error ? err.message : String(err);
18970
+ console.log(import_picocolors.default.yellow(` ⚠ Claude Code hooks: ${msg}`));
18971
+ }
18972
+ }
18973
+ const needsWatcher = confirmedTools.includes("codex") || confirmedTools.includes("cursor");
18974
+ if (needsWatcher && process.platform === "darwin") {
18975
+ try {
18976
+ const { installUnifiedWatcher: installUnifiedWatcher2 } = await Promise.resolve().then(() => (init_hooks_installer(), exports_hooks_installer));
18977
+ installUnifiedWatcher2(useGlobal);
18978
+ console.log(import_picocolors.default.green(" ✓ Background watcher installed (Codex + Cursor)"));
18979
+ } catch (err) {
18980
+ const msg = err instanceof Error ? err.message : String(err);
18981
+ console.log(import_picocolors.default.yellow(` ⚠ Background watcher: ${msg}`));
18982
+ }
18983
+ }
18984
+ if (confirmedTools.includes("gemini")) {
18985
+ console.log(import_picocolors.default.dim(" ℹ Gemini: batch sync only (run `getverbal import --sync --platforms gemini`)"));
18986
+ }
18987
+ if (confirmedTools.includes("cursor")) {
18988
+ try {
18989
+ await import("bun:sqlite");
18990
+ } catch {
18991
+ console.log(import_picocolors.default.yellow(" ⚠ Cursor detected but bun:sqlite not available."));
18992
+ console.log(import_picocolors.default.yellow(" Cursor sync requires Bun runtime. Run via: bunx getverbal sync"));
18993
+ }
18994
+ }
17601
18995
  process.stdout.write(import_picocolors.default.dim("Verifying connection..."));
17602
18996
  try {
17603
18997
  await verifyConnection(credentials);
@@ -17608,8 +19002,8 @@ async function runInit() {
17608
19002
  console.log(import_picocolors.default.yellow(`⚠ Verification warning: ${message}`));
17609
19003
  }
17610
19004
  console.log();
17611
- const mcpJsonPath = join11(process.cwd(), ".mcp.json");
17612
- if (existsSync7(mcpJsonPath) && !isInGitignore(".mcp.json")) {
19005
+ const mcpJsonPath = join12(process.cwd(), ".mcp.json");
19006
+ if (existsSync8(mcpJsonPath) && !isInGitignore(".mcp.json")) {
17613
19007
  console.log(import_picocolors.default.yellow("⚠ .mcp.json contains your API key. Add it to .gitignore to avoid leaking credentials:"));
17614
19008
  console.log(import_picocolors.default.dim(' echo ".mcp.json" >> .gitignore'));
17615
19009
  console.log();
@@ -17635,10 +19029,9 @@ async function runInit() {
17635
19029
  console.log(`
17636
19030
  Importing ${source.id}...`);
17637
19031
  try {
17638
- const { syncFromTokscale: syncFromTokscale2 } = await Promise.resolve().then(() => (init_tokscale(), exports_tokscale));
17639
- const stateDir = join11(homedir10(), ".config", "getverbal");
17640
- const platform = source.id === "claude-code" ? "claude" : "codex";
17641
- const result = await syncFromTokscale2({
19032
+ const { syncPlatforms: syncPlatforms2 } = await Promise.resolve().then(() => (init_orchestrator(), exports_orchestrator));
19033
+ const stateDir = join12(homedir11(), ".config", "getverbal");
19034
+ const result = await syncPlatforms2({
17642
19035
  apiKey: credentials.api_key,
17643
19036
  ingestUrl: credentials.ingest_url,
17644
19037
  batchSize: 100,
@@ -17646,9 +19039,9 @@ async function runInit() {
17646
19039
  httpTimeoutMs: 30000,
17647
19040
  stateDir
17648
19041
  }, {
17649
- platforms: [platform]
19042
+ platforms: [source.id]
17650
19043
  });
17651
- console.log(import_picocolors.default.green(` ✓ ${result.events} sessions imported`));
19044
+ console.log(import_picocolors.default.green(` ✓ ${result.totalEvents} sessions imported`));
17652
19045
  } catch (importErr) {
17653
19046
  const message = importErr instanceof Error ? importErr.message : String(importErr);
17654
19047
  console.log(import_picocolors.default.yellow(` ⚠ Import skipped: ${message}`));