llm-usage-metrics 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +1319 -867
  3. package/package.json +17 -38
package/dist/index.js CHANGED
@@ -6,11 +6,46 @@ import { isMainThread, workerData } from "worker_threads";
6
6
  // src/config/runtime-overrides.ts
7
7
  import { availableParallelism } from "os";
8
8
 
9
- // src/persistence/event-store.ts
10
- import { createHash } from "crypto";
9
+ // src/persistence/event-store-administration.ts
11
10
  import { chmod, mkdir, open } from "fs/promises";
12
11
  import path2 from "path";
13
12
 
13
+ // src/utils/as-record.ts
14
+ function isRecord(value) {
15
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
16
+ }
17
+ function asRecord(value) {
18
+ if (!isRecord(value)) {
19
+ return void 0;
20
+ }
21
+ return value;
22
+ }
23
+
24
+ // src/cli/normalize-skipped-row-reasons.ts
25
+ function toPositiveInteger(value) {
26
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
27
+ return void 0;
28
+ }
29
+ return Math.trunc(value);
30
+ }
31
+ function normalizeSkippedRowReasons(value) {
32
+ if (!Array.isArray(value)) {
33
+ return [];
34
+ }
35
+ return value.flatMap((entry) => {
36
+ const record = asRecord(entry);
37
+ if (!record) {
38
+ return [];
39
+ }
40
+ const reason = typeof record.reason === "string" ? record.reason.trim() : "";
41
+ const count = toPositiveInteger(record.count);
42
+ if (!reason || count === void 0) {
43
+ return [];
44
+ }
45
+ return [{ reason, count }];
46
+ });
47
+ }
48
+
14
49
  // src/utils/compare-by-code-point.ts
15
50
  function compareByCodePoint(left5, right4) {
16
51
  if (left5 === right4) {
@@ -273,42 +308,6 @@ function isPriceableEvent(event) {
273
308
  return hasBillableTokenBuckets(event);
274
309
  }
275
310
 
276
- // src/utils/as-record.ts
277
- function isRecord(value) {
278
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
279
- }
280
- function asRecord(value) {
281
- if (!isRecord(value)) {
282
- return void 0;
283
- }
284
- return value;
285
- }
286
-
287
- // src/cli/normalize-skipped-row-reasons.ts
288
- function toPositiveInteger(value) {
289
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
290
- return void 0;
291
- }
292
- return Math.trunc(value);
293
- }
294
- function normalizeSkippedRowReasons(value) {
295
- if (!Array.isArray(value)) {
296
- return [];
297
- }
298
- return value.flatMap((entry) => {
299
- const record = asRecord(entry);
300
- if (!record) {
301
- return [];
302
- }
303
- const reason = typeof record.reason === "string" ? record.reason.trim() : "";
304
- const count = toPositiveInteger(record.count);
305
- if (!reason || count === void 0) {
306
- return [];
307
- }
308
- return [{ reason, count }];
309
- });
310
- }
311
-
312
311
  // src/sources/opencode/node-sqlite-loader.ts
313
312
  import { createRequire } from "module";
314
313
 
@@ -379,83 +378,14 @@ function getUserCacheRootDir(env = process.env, platform = process.platform, hom
379
378
  return path.join(homedir, ".cache");
380
379
  }
381
380
 
382
- // src/persistence/event-store.ts
383
- var EVENT_STORE_SCHEMA_VERSION = "3";
384
- var MIGRATION_BATCH_SIZE = 5e3;
385
- var EVENT_STORE_OPEN_TIMEOUT_MS = 2e3;
386
- var CONTROL_CHARACTERS_PATTERN2 = new RegExp(String.raw`[\u0000-\u001F\u007F-\u009F]`, "u");
387
- var NORMALIZED_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u;
388
- var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
389
- var FAST_PATH_REJECT = /* @__PURE__ */ Symbol("fast path reject");
390
- var loadEventStoreSqliteModule = () => loadNodeSqliteModule("Event store");
391
- var EventStoreSchemaVersionError = class extends Error {
392
- schemaVersion;
393
- constructor(schemaVersion) {
394
- const versionLabel = schemaVersion ? `v${schemaVersion}` : "an unknown schema version";
395
- super(
396
- `Event store uses ${versionLabel}, which is not supported by this version of llm-usage-metrics (supports v${EVENT_STORE_SCHEMA_VERSION}); leaving store untouched`
397
- );
398
- this.name = "EventStoreSchemaVersionError";
399
- this.schemaVersion = schemaVersion;
400
- }
401
- };
402
- function createSchemaSql() {
403
- return `
404
- CREATE TABLE IF NOT EXISTS meta (
405
- key TEXT PRIMARY KEY,
406
- value TEXT NOT NULL
407
- );
408
- CREATE TABLE IF NOT EXISTS files (
409
- source TEXT NOT NULL,
410
- file_path TEXT NOT NULL,
411
- fingerprint TEXT NOT NULL,
412
- skipped_rows INTEGER NOT NULL,
413
- skipped_row_reasons TEXT,
414
- ingested_at INTEGER NOT NULL,
415
- PRIMARY KEY (source, file_path)
416
- );
417
- CREATE TABLE IF NOT EXISTS events (
418
- id INTEGER PRIMARY KEY,
419
- source TEXT NOT NULL,
420
- file_path TEXT NOT NULL,
421
- event_index INTEGER NOT NULL,
422
- session_id TEXT NOT NULL,
423
- timestamp TEXT NOT NULL,
424
- model TEXT,
425
- provider TEXT,
426
- repo_root TEXT,
427
- input_tokens INTEGER NOT NULL,
428
- output_tokens INTEGER NOT NULL,
429
- reasoning_tokens INTEGER NOT NULL,
430
- cache_read_tokens INTEGER NOT NULL,
431
- cache_write_tokens INTEGER NOT NULL,
432
- total_tokens INTEGER NOT NULL,
433
- content_hash TEXT,
434
- cost_usd REAL,
435
- cost_mode TEXT NOT NULL
436
- );
437
- CREATE INDEX IF NOT EXISTS events_file ON events(source, file_path, event_index);
438
- CREATE INDEX IF NOT EXISTS events_content_hash ON events(content_hash);
439
- `;
440
- }
381
+ // src/persistence/event-store-codec.ts
382
+ import { createHash } from "crypto";
383
+
384
+ // src/persistence/event-store-database.ts
441
385
  function isEventStoreSqliteModule(value) {
442
386
  const moduleRecord = asRecord(value);
443
387
  return typeof moduleRecord?.DatabaseSync === "function";
444
388
  }
445
- function normalizeStoreSource(source) {
446
- const normalizedSource = normalizeSourceId(source)?.toLowerCase();
447
- if (!normalizedSource) {
448
- throw new Error("Event store source must be a non-empty string");
449
- }
450
- return normalizedSource;
451
- }
452
- function normalizeStoreFilePath(filePath) {
453
- const normalizedFilePath = filePath.trim();
454
- if (!normalizedFilePath) {
455
- throw new Error("Event store file path must be a non-empty string");
456
- }
457
- return normalizedFilePath;
458
- }
459
389
  function toNonNegativeInteger(value) {
460
390
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
461
391
  return void 0;
@@ -475,77 +405,22 @@ function toText(value) {
475
405
  const normalized = value.trim();
476
406
  return normalized || void 0;
477
407
  }
478
- function normalizeDependencyFingerprint(value) {
479
- const dependencyPath = toText(value.path);
480
- if (!dependencyPath) {
481
- return void 0;
482
- }
483
- if (!value.exists) {
484
- return {
485
- path: dependencyPath,
486
- exists: false
487
- };
488
- }
489
- const size = toNonNegativeInteger(value.size);
490
- const mtimeMs = toNonNegativeNumber(value.mtimeMs);
491
- if (size === void 0 || mtimeMs === void 0) {
492
- return void 0;
493
- }
494
- return {
495
- path: dependencyPath,
496
- exists: true,
497
- size,
498
- mtimeMs
499
- };
500
- }
501
- function compareDependencyFingerprint(left5, right4) {
502
- if (left5.path !== right4.path) {
503
- return compareByCodePoint(left5.path, right4.path);
504
- }
505
- if (left5.exists !== right4.exists) {
506
- return left5.exists ? 1 : -1;
507
- }
508
- if ((left5.size ?? -1) !== (right4.size ?? -1)) {
509
- return (left5.size ?? -1) - (right4.size ?? -1);
510
- }
511
- return (left5.mtimeMs ?? -1) - (right4.mtimeMs ?? -1);
512
- }
513
- function normalizeEventStoreFingerprint(fingerprint) {
514
- if (!Array.isArray(fingerprint.dependencies) || fingerprint.dependencies.length === 0) {
515
- return void 0;
516
- }
517
- const dependencies = [];
518
- for (const dependency of fingerprint.dependencies) {
519
- const normalizedDependency = normalizeDependencyFingerprint(dependency);
520
- if (!normalizedDependency) {
521
- return void 0;
522
- }
523
- dependencies.push(normalizedDependency);
524
- }
525
- dependencies.sort(compareDependencyFingerprint);
526
- return { dependencies };
527
- }
528
- function serializeEventStoreFingerprint(fingerprint) {
529
- const normalizedFingerprint = normalizeEventStoreFingerprint(fingerprint);
530
- if (!normalizedFingerprint) {
531
- throw new Error("Event store fingerprint must include valid dependency fingerprints");
532
- }
533
- return JSON.stringify(normalizedFingerprint);
534
- }
535
- function parseSkippedRowReasons(value) {
536
- if (typeof value !== "string") {
537
- return [];
538
- }
408
+ function runTransaction(database, task) {
409
+ database.exec("BEGIN IMMEDIATE");
539
410
  try {
540
- return normalizeSkippedRowReasons(JSON.parse(value));
541
- } catch {
542
- return [];
411
+ task();
412
+ database.exec("COMMIT");
413
+ } catch (error) {
414
+ database.exec("ROLLBACK");
415
+ throw error;
543
416
  }
544
417
  }
545
- function stringifySkippedRowReasons(skippedRowReasons) {
546
- const normalizedReasons = normalizeSkippedRowReasons(skippedRowReasons);
547
- return normalizedReasons.length > 0 ? JSON.stringify(normalizedReasons) : null;
548
- }
418
+
419
+ // src/persistence/event-store-codec.ts
420
+ var CONTROL_CHARACTERS_PATTERN2 = new RegExp(String.raw`[\u0000-\u001F\u007F-\u009F]`, "u");
421
+ var NORMALIZED_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u;
422
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
423
+ var FAST_PATH_REJECT = /* @__PURE__ */ Symbol("fast path reject");
549
424
  function normalizeStoredEvent(row) {
550
425
  return fastMaterializeStoredEvent(row) ?? slowNormalizeStoredEvent(row);
551
426
  }
@@ -577,23 +452,63 @@ function slowNormalizeStoredEvent(row) {
577
452
  }
578
453
  }
579
454
  function fastMaterializeStoredEvent(row) {
580
- const costMode = row.cost_mode === "explicit" || row.cost_mode === "estimated" ? row.cost_mode : void 0;
455
+ return materializeStoredEvent(
456
+ row.source,
457
+ row.session_id,
458
+ row.timestamp,
459
+ row.model,
460
+ row.provider,
461
+ row.repo_root,
462
+ row.input_tokens,
463
+ row.output_tokens,
464
+ row.reasoning_tokens,
465
+ row.cache_read_tokens,
466
+ row.cache_write_tokens,
467
+ row.total_tokens,
468
+ row.cost_usd,
469
+ row.cost_mode
470
+ );
471
+ }
472
+ function normalizeStoredEventTuple(row) {
473
+ const event = materializeStoredEvent(...row);
474
+ if (event) {
475
+ return event;
476
+ }
477
+ return slowNormalizeStoredEvent({
478
+ source: row[0],
479
+ session_id: row[1],
480
+ timestamp: row[2],
481
+ model: row[3],
482
+ provider: row[4],
483
+ repo_root: row[5],
484
+ input_tokens: row[6],
485
+ output_tokens: row[7],
486
+ reasoning_tokens: row[8],
487
+ cache_read_tokens: row[9],
488
+ cache_write_tokens: row[10],
489
+ total_tokens: row[11],
490
+ cost_usd: row[12],
491
+ cost_mode: row[13]
492
+ });
493
+ }
494
+ function materializeStoredEvent(sourceValue, sessionIdValue, timestampValue, modelValue, providerValue, repoRootValue, inputTokensValue, outputTokensValue, reasoningTokensValue, cacheReadTokensValue, cacheWriteTokensValue, totalTokensValue, costUsdValue, costModeValue) {
495
+ const costMode = costModeValue === "explicit" || costModeValue === "estimated" ? costModeValue : void 0;
581
496
  if (!costMode) {
582
497
  return void 0;
583
498
  }
584
- const source = toStoredRequiredText(row.source);
585
- const sessionId = toStoredRequiredText(row.session_id);
586
- const timestamp = toStoredTimestamp(row.timestamp);
587
- const repoRoot = toStoredOptionalText(row.repo_root);
588
- const provider = toStoredOptionalText(row.provider);
589
- const model = toStoredOptionalText(row.model);
590
- const inputTokens = toStoredNonNegativeInteger(row.input_tokens);
591
- const outputTokens = toStoredNonNegativeInteger(row.output_tokens);
592
- const reasoningTokens = toStoredNonNegativeInteger(row.reasoning_tokens);
593
- const cacheReadTokens = toStoredNonNegativeInteger(row.cache_read_tokens);
594
- const cacheWriteTokens = toStoredNonNegativeInteger(row.cache_write_tokens);
595
- const totalTokens = toStoredNonNegativeInteger(row.total_tokens);
596
- const costUsd = toStoredCostUsd(row.cost_usd, costMode);
499
+ const source = toStoredRequiredText(sourceValue);
500
+ const sessionId = toStoredRequiredText(sessionIdValue);
501
+ const timestamp = toStoredTimestamp(timestampValue);
502
+ const repoRoot = toStoredOptionalText(repoRootValue);
503
+ const provider = toStoredOptionalText(providerValue);
504
+ const model = toStoredOptionalText(modelValue);
505
+ const inputTokens = toStoredNonNegativeInteger(inputTokensValue);
506
+ const outputTokens = toStoredNonNegativeInteger(outputTokensValue);
507
+ const reasoningTokens = toStoredNonNegativeInteger(reasoningTokensValue);
508
+ const cacheReadTokens = toStoredNonNegativeInteger(cacheReadTokensValue);
509
+ const cacheWriteTokens = toStoredNonNegativeInteger(cacheWriteTokensValue);
510
+ const totalTokens = toStoredNonNegativeInteger(totalTokensValue);
511
+ const costUsd = toStoredCostUsd(costUsdValue, costMode);
597
512
  if (!source || !sessionId || !timestamp || repoRoot === FAST_PATH_REJECT || provider === FAST_PATH_REJECT || model === FAST_PATH_REJECT || inputTokens === void 0 || outputTokens === void 0 || reasoningTokens === void 0 || cacheReadTokens === void 0 || cacheWriteTokens === void 0 || totalTokens === void 0 || costUsd === FAST_PATH_REJECT) {
598
513
  return void 0;
599
514
  }
@@ -675,6 +590,79 @@ function toStoredCostUsd(value, costMode) {
675
590
  }
676
591
  return value;
677
592
  }
593
+ function computeEventContentHash(event) {
594
+ const fields = [
595
+ event.source.toLowerCase(),
596
+ event.sessionId,
597
+ event.timestamp,
598
+ event.model ?? "",
599
+ event.provider ?? "",
600
+ event.repoRoot ?? "",
601
+ event.inputTokens,
602
+ event.outputTokens,
603
+ event.reasoningTokens,
604
+ event.cacheReadTokens,
605
+ event.cacheWriteTokens,
606
+ event.totalTokens,
607
+ event.costMode,
608
+ event.costUsd ?? ""
609
+ ];
610
+ return createHash("sha256").update(fields.map(String).join("")).digest("hex").slice(0, 16);
611
+ }
612
+
613
+ // src/persistence/event-store-schema.ts
614
+ var EVENT_STORE_SCHEMA_VERSION = "3";
615
+ var MIGRATION_BATCH_SIZE = 5e3;
616
+ var EventStoreSchemaVersionError = class extends Error {
617
+ schemaVersion;
618
+ constructor(schemaVersion) {
619
+ const versionLabel = schemaVersion ? `v${schemaVersion}` : "an unknown schema version";
620
+ super(
621
+ `Event store uses ${versionLabel}, which is not supported by this version of llm-usage-metrics (supports v${EVENT_STORE_SCHEMA_VERSION}); leaving store untouched`
622
+ );
623
+ this.name = "EventStoreSchemaVersionError";
624
+ this.schemaVersion = schemaVersion;
625
+ }
626
+ };
627
+ function createSchemaSql() {
628
+ return `
629
+ CREATE TABLE IF NOT EXISTS meta (
630
+ key TEXT PRIMARY KEY,
631
+ value TEXT NOT NULL
632
+ );
633
+ CREATE TABLE IF NOT EXISTS files (
634
+ source TEXT NOT NULL,
635
+ file_path TEXT NOT NULL,
636
+ fingerprint TEXT NOT NULL,
637
+ skipped_rows INTEGER NOT NULL,
638
+ skipped_row_reasons TEXT,
639
+ ingested_at INTEGER NOT NULL,
640
+ PRIMARY KEY (source, file_path)
641
+ );
642
+ CREATE TABLE IF NOT EXISTS events (
643
+ id INTEGER PRIMARY KEY,
644
+ source TEXT NOT NULL,
645
+ file_path TEXT NOT NULL,
646
+ event_index INTEGER NOT NULL,
647
+ session_id TEXT NOT NULL,
648
+ timestamp TEXT NOT NULL,
649
+ model TEXT,
650
+ provider TEXT,
651
+ repo_root TEXT,
652
+ input_tokens INTEGER NOT NULL,
653
+ output_tokens INTEGER NOT NULL,
654
+ reasoning_tokens INTEGER NOT NULL,
655
+ cache_read_tokens INTEGER NOT NULL,
656
+ cache_write_tokens INTEGER NOT NULL,
657
+ total_tokens INTEGER NOT NULL,
658
+ content_hash TEXT,
659
+ cost_usd REAL,
660
+ cost_mode TEXT NOT NULL
661
+ );
662
+ CREATE INDEX IF NOT EXISTS events_file ON events(source, file_path, event_index);
663
+ CREATE INDEX IF NOT EXISTS events_content_hash ON events(content_hash);
664
+ `;
665
+ }
678
666
  function listUserTableNames(database) {
679
667
  return database.prepare(
680
668
  [
@@ -697,25 +685,6 @@ function createFreshSchema(database) {
697
685
  database.exec(createSchemaSql());
698
686
  database.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES ('schemaVersion', ?)").run(EVENT_STORE_SCHEMA_VERSION);
699
687
  }
700
- function computeEventContentHash(event) {
701
- const fields = [
702
- event.source.toLowerCase(),
703
- event.sessionId,
704
- event.timestamp,
705
- event.model ?? "",
706
- event.provider ?? "",
707
- event.repoRoot ?? "",
708
- event.inputTokens,
709
- event.outputTokens,
710
- event.reasoningTokens,
711
- event.cacheReadTokens,
712
- event.cacheWriteTokens,
713
- event.totalTokens,
714
- event.costMode,
715
- event.costUsd ?? ""
716
- ];
717
- return createHash("sha256").update(fields.map(String).join("")).digest("hex").slice(0, 16);
718
- }
719
688
  function migrateSchemaV1ToV2(database) {
720
689
  runTransaction(database, () => {
721
690
  if (readSchemaVersion(database) !== "1") {
@@ -809,29 +778,105 @@ function initializeSchema(database) {
809
778
  if (schemaVersion === EVENT_STORE_SCHEMA_VERSION) {
810
779
  return;
811
780
  }
812
- if (schemaVersion === "1") {
813
- migrateSchemaV1ToV2(database);
814
- migrateSchemaV2ToV3(database);
815
- return;
781
+ if (schemaVersion === "1") {
782
+ migrateSchemaV1ToV2(database);
783
+ migrateSchemaV2ToV3(database);
784
+ return;
785
+ }
786
+ if (schemaVersion === "2") {
787
+ migrateSchemaV2ToV3(database);
788
+ return;
789
+ }
790
+ throw new EventStoreSchemaVersionError(schemaVersion);
791
+ }
792
+
793
+ // src/persistence/event-store-administration.ts
794
+ var EVENT_STORE_OPEN_TIMEOUT_MS = 2e3;
795
+ var loadEventStoreSqliteModule = () => loadNodeSqliteModule("Event store");
796
+ function normalizeStoreSource(source) {
797
+ const normalizedSource = normalizeSourceId(source)?.toLowerCase();
798
+ if (!normalizedSource) {
799
+ throw new Error("Event store source must be a non-empty string");
800
+ }
801
+ return normalizedSource;
802
+ }
803
+ function normalizeStoreFilePath(filePath) {
804
+ const normalizedFilePath = filePath.trim();
805
+ if (!normalizedFilePath) {
806
+ throw new Error("Event store file path must be a non-empty string");
807
+ }
808
+ return normalizedFilePath;
809
+ }
810
+ function normalizeDependencyFingerprint(value) {
811
+ const dependencyPath = toText(value.path);
812
+ if (!dependencyPath) {
813
+ return void 0;
814
+ }
815
+ if (!value.exists) {
816
+ return {
817
+ path: dependencyPath,
818
+ exists: false
819
+ };
820
+ }
821
+ const size = toNonNegativeInteger(value.size);
822
+ const mtimeMs = toNonNegativeNumber(value.mtimeMs);
823
+ if (size === void 0 || mtimeMs === void 0) {
824
+ return void 0;
825
+ }
826
+ return {
827
+ path: dependencyPath,
828
+ exists: true,
829
+ size,
830
+ mtimeMs
831
+ };
832
+ }
833
+ function compareDependencyFingerprint(left5, right4) {
834
+ if (left5.path !== right4.path) {
835
+ return compareByCodePoint(left5.path, right4.path);
836
+ }
837
+ if (left5.exists !== right4.exists) {
838
+ return left5.exists ? 1 : -1;
839
+ }
840
+ if ((left5.size ?? -1) !== (right4.size ?? -1)) {
841
+ return (left5.size ?? -1) - (right4.size ?? -1);
842
+ }
843
+ return (left5.mtimeMs ?? -1) - (right4.mtimeMs ?? -1);
844
+ }
845
+ function normalizeEventStoreFingerprint(fingerprint) {
846
+ if (!Array.isArray(fingerprint.dependencies) || fingerprint.dependencies.length === 0) {
847
+ return void 0;
848
+ }
849
+ const dependencies = [];
850
+ for (const dependency of fingerprint.dependencies) {
851
+ const normalizedDependency = normalizeDependencyFingerprint(dependency);
852
+ if (!normalizedDependency) {
853
+ return void 0;
854
+ }
855
+ dependencies.push(normalizedDependency);
816
856
  }
817
- if (schemaVersion === "2") {
818
- migrateSchemaV2ToV3(database);
819
- return;
857
+ dependencies.sort(compareDependencyFingerprint);
858
+ return { dependencies };
859
+ }
860
+ function serializeEventStoreFingerprint(fingerprint) {
861
+ const normalizedFingerprint = normalizeEventStoreFingerprint(fingerprint);
862
+ if (!normalizedFingerprint) {
863
+ throw new Error("Event store fingerprint must include valid dependency fingerprints");
820
864
  }
821
- throw new EventStoreSchemaVersionError(schemaVersion);
865
+ return JSON.stringify(normalizedFingerprint);
822
866
  }
823
- function runTransaction(database, task) {
824
- database.exec("BEGIN IMMEDIATE");
867
+ function parseSkippedRowReasons(value) {
868
+ if (typeof value !== "string") {
869
+ return [];
870
+ }
825
871
  try {
826
- task();
827
- database.exec("COMMIT");
828
- } catch (error) {
829
- database.exec("ROLLBACK");
830
- throw error;
872
+ return normalizeSkippedRowReasons(JSON.parse(value));
873
+ } catch {
874
+ return [];
831
875
  }
832
876
  }
833
- function deleteFileEntry(store, source, filePath) {
834
- deleteStoredFiles(store, [{ source, filePath }]);
877
+ function stringifySkippedRowReasons(skippedRowReasons) {
878
+ const normalizedReasons = normalizeSkippedRowReasons(skippedRowReasons);
879
+ return normalizedReasons.length > 0 ? JSON.stringify(normalizedReasons) : null;
835
880
  }
836
881
  function getDefaultEventStorePath() {
837
882
  return path2.join(getUserCacheRootDir(), "llm-usage-metrics", "events.db");
@@ -933,6 +978,9 @@ async function readEventStoreStoredFiles(filePath = getDefaultEventStorePath(),
933
978
  database.close();
934
979
  }
935
980
  }
981
+ function deleteFileEntry(store, source, filePath) {
982
+ deleteStoredFiles(store, [{ source, filePath }]);
983
+ }
936
984
  function getFileEntry(store, source, filePath) {
937
985
  const normalizedSource = normalizeStoreSource(source);
938
986
  const normalizedFilePath = normalizeStoreFilePath(filePath);
@@ -960,16 +1008,21 @@ function getFileEntry(store, source, filePath) {
960
1008
  };
961
1009
  }
962
1010
  function selectFileEventRows(store, source, filePath) {
963
- const statement = store.statements.selectFileEvents ??= store.database.prepare(
964
- [
965
- "SELECT source, session_id, timestamp, model, provider, repo_root,",
966
- " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
967
- " cache_write_tokens, total_tokens, cost_usd, cost_mode",
968
- "FROM events",
969
- "WHERE source = ? AND file_path = ?",
970
- "ORDER BY event_index ASC"
971
- ].join("\n")
972
- );
1011
+ let statement = store.statements.selectFileEvents;
1012
+ if (!statement) {
1013
+ statement = store.database.prepare(
1014
+ [
1015
+ "SELECT source, session_id, timestamp, model, provider, repo_root,",
1016
+ " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1017
+ " cache_write_tokens, total_tokens, cost_usd, cost_mode",
1018
+ "FROM events",
1019
+ "WHERE source = ? AND file_path = ?",
1020
+ "ORDER BY event_index ASC"
1021
+ ].join("\n")
1022
+ );
1023
+ statement.setReturnArrays(true);
1024
+ store.statements.selectFileEvents = statement;
1025
+ }
973
1026
  return statement.all(source, filePath);
974
1027
  }
975
1028
  function readFileEvents(store, source, filePath) {
@@ -977,7 +1030,7 @@ function readFileEvents(store, source, filePath) {
977
1030
  const normalizedFilePath = normalizeStoreFilePath(filePath);
978
1031
  const events = [];
979
1032
  for (const row of selectFileEventRows(store, normalizedSource, normalizedFilePath)) {
980
- const event = normalizeStoredEvent(row);
1033
+ const event = normalizeStoredEventTuple(row);
981
1034
  if (!event) {
982
1035
  deleteFileEntry(store, normalizedSource, normalizedFilePath);
983
1036
  return void 0;
@@ -1214,105 +1267,13 @@ import { readFile as readFileFromFs } from "fs/promises";
1214
1267
  import os3 from "os";
1215
1268
  import path4 from "path";
1216
1269
 
1217
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/date.js
1218
- var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
1219
- var TomlDate = class _TomlDate extends Date {
1220
- #hasDate = false;
1221
- #hasTime = false;
1222
- #offset = null;
1223
- constructor(date) {
1224
- let hasDate = true;
1225
- let hasTime = true;
1226
- let offset = "Z";
1227
- if (typeof date === "string") {
1228
- let match = date.match(DATE_TIME_RE);
1229
- if (match) {
1230
- if (!match[1]) {
1231
- hasDate = false;
1232
- date = `0000-01-01T${date}`;
1233
- }
1234
- hasTime = !!match[2];
1235
- hasTime && date[10] === " " && (date = date.replace(" ", "T"));
1236
- if (match[2] && +match[2] > 23) {
1237
- date = "";
1238
- } else {
1239
- offset = match[3] || null;
1240
- date = date.toUpperCase();
1241
- if (!offset && hasTime)
1242
- date += "Z";
1243
- }
1244
- } else {
1245
- date = "";
1246
- }
1247
- }
1248
- super(date);
1249
- if (!isNaN(this.getTime())) {
1250
- this.#hasDate = hasDate;
1251
- this.#hasTime = hasTime;
1252
- this.#offset = offset;
1253
- }
1254
- }
1255
- isDateTime() {
1256
- return this.#hasDate && this.#hasTime;
1257
- }
1258
- isLocal() {
1259
- return !this.#hasDate || !this.#hasTime || !this.#offset;
1260
- }
1261
- isDate() {
1262
- return this.#hasDate && !this.#hasTime;
1263
- }
1264
- isTime() {
1265
- return this.#hasTime && !this.#hasDate;
1266
- }
1267
- isValid() {
1268
- return this.#hasDate || this.#hasTime;
1269
- }
1270
- toISOString() {
1271
- let iso = super.toISOString();
1272
- if (this.isDate())
1273
- return iso.slice(0, 10);
1274
- if (this.isTime())
1275
- return iso.slice(11, 23);
1276
- if (this.#offset === null)
1277
- return iso.slice(0, -1);
1278
- if (this.#offset === "Z")
1279
- return iso;
1280
- let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
1281
- offset = this.#offset[0] === "-" ? offset : -offset;
1282
- let offsetDate = new Date(this.getTime() - offset * 6e4);
1283
- return offsetDate.toISOString().slice(0, -1) + this.#offset;
1284
- }
1285
- static wrapAsOffsetDateTime(jsDate, offset = "Z") {
1286
- let date = new _TomlDate(jsDate);
1287
- date.#offset = offset;
1288
- return date;
1289
- }
1290
- static wrapAsLocalDateTime(jsDate) {
1291
- let date = new _TomlDate(jsDate);
1292
- date.#offset = null;
1293
- return date;
1294
- }
1295
- static wrapAsLocalDate(jsDate) {
1296
- let date = new _TomlDate(jsDate);
1297
- date.#hasTime = false;
1298
- date.#offset = null;
1299
- return date;
1300
- }
1301
- static wrapAsLocalTime(jsDate) {
1302
- let date = new _TomlDate(jsDate);
1303
- date.#hasDate = false;
1304
- date.#offset = null;
1305
- return date;
1306
- }
1307
- };
1308
-
1309
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/error.js
1270
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/error.js
1310
1271
  function getLineColFromPtr(string, ptr) {
1311
- let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
1272
+ let lines = string.slice(0, ptr).split(/\r?\n/);
1312
1273
  return [lines.length, lines.pop().length + 1];
1313
1274
  }
1314
1275
  function makeCodeBlock(string, line, column) {
1315
- let lines = string.split(/\r\n|\n|\r/g);
1276
+ let lines = string.split(/\r?\n/);
1316
1277
  let codeblock = "";
1317
1278
  let numberLen = (Math.log10(line + 1) | 0) + 1;
1318
1279
  for (let i = line - 1; i <= line + 1; i++) {
@@ -1330,7 +1291,7 @@ function makeCodeBlock(string, line, column) {
1330
1291
  }
1331
1292
  return codeblock;
1332
1293
  }
1333
- var TomlError = class extends Error {
1294
+ var TomlError = class _TomlError extends Error {
1334
1295
  line;
1335
1296
  column;
1336
1297
  codeblock;
@@ -1344,59 +1305,59 @@ ${codeblock}`, options);
1344
1305
  this.column = column;
1345
1306
  this.codeblock = codeblock;
1346
1307
  }
1308
+ /** @internal */
1309
+ static x(message, ctx, ptr) {
1310
+ throw new _TomlError(message, { toml: ctx.s, ptr: ptr ?? ctx.p });
1311
+ }
1347
1312
  };
1348
1313
 
1349
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/primitive.js
1350
- var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
1351
- var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
1352
- var LEADING_ZERO = /^[+-]?0[0-9_]/;
1353
- function parseString(str, ptr) {
1354
- let c = str[ptr++];
1314
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/primitive.js
1315
+ function parseString(ctx) {
1316
+ let startPtr = ctx.p;
1317
+ let c = ctx.s.charCodeAt(ctx.p++);
1355
1318
  let first = c;
1356
- let isLiteral = c === "'";
1357
- let isMultiline = c === str[ptr] && c === str[ptr + 1];
1319
+ let isLiteral = c === 39;
1320
+ let isMultiline = c === ctx.s.charCodeAt(ctx.p) && c === ctx.s.charCodeAt(ctx.p + 1);
1358
1321
  if (isMultiline) {
1359
- if (str[ptr += 2] === "\n")
1360
- ptr++;
1361
- else if (str[ptr] === "\r" && str[ptr + 1] === "\n")
1362
- ptr += 2;
1322
+ if ((c = ctx.s.charCodeAt(ctx.p += 2)) === 10)
1323
+ ctx.p++;
1324
+ else if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)
1325
+ ctx.p += 2;
1363
1326
  }
1364
1327
  let parsed = "";
1365
- let sliceStart = ptr;
1328
+ let sliceStart = ctx.p;
1366
1329
  let state = 0;
1367
- for (let i = ptr; i < str.length; i++) {
1368
- c = str[i];
1369
- if (isMultiline && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
1330
+ for (; ctx.p < ctx.s.length; ctx.p++) {
1331
+ c = ctx.s.charCodeAt(ctx.p);
1332
+ if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) {
1370
1333
  state = state && 3;
1371
- } else if (c < " " && c !== " " || c === "\x7F") {
1372
- throw new TomlError("control characters are not allowed in strings", {
1373
- toml: str,
1374
- ptr: i
1375
- });
1376
- } else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) {
1334
+ } else if (c < 32 && c !== 9 || c === 127) {
1335
+ TomlError.x("control characters are not allowed in strings", ctx);
1336
+ } else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
1377
1337
  if (isMultiline) {
1378
- if (str[i + 3] === first)
1379
- i++;
1380
- if (str[i + 3] === first)
1381
- i++;
1338
+ if (ctx.s.charCodeAt(ctx.p + 3) === first)
1339
+ ctx.p++;
1340
+ if (ctx.s.charCodeAt(ctx.p + 3) === first)
1341
+ ctx.p++;
1382
1342
  }
1383
- return [
1384
- // If we're in a newline escape still, then there's nothing to add.
1385
- // Also try to avoid concat if there's nothing to add to parsed, or nothing has been added to parsed.
1386
- state ? parsed : parsed + str.slice(sliceStart, i),
1387
- i + (isMultiline ? 3 : 1)
1388
- ];
1343
+ if (!state) {
1344
+ let s = ctx.s.slice(sliceStart, ctx.p);
1345
+ parsed = parsed ? parsed + s : s;
1346
+ }
1347
+ ctx.p += isMultiline ? 3 : 1;
1348
+ return parsed;
1389
1349
  } else if (!state) {
1390
- if (!isLiteral && c === "\\") {
1391
- parsed += str.slice(sliceStart, sliceStart = i);
1350
+ if (!isLiteral && c === 92) {
1351
+ parsed += ctx.s.slice(sliceStart, sliceStart = ctx.p);
1392
1352
  state = 1;
1393
1353
  }
1394
1354
  } else if (state === 1) {
1395
- if (c === "x" || c === "u" || c === "U") {
1355
+ if (c === 120 || c === 117 || c === 85) {
1356
+ let errPtr = ctx.p++ - 1;
1396
1357
  let value = 0;
1397
- let len = c === "x" ? 2 : c === "u" ? 4 : 8;
1398
- for (let j = 0; j < len; j++, i++) {
1399
- let hex = str.charCodeAt(i + 1);
1358
+ let len = c === 120 ? 2 : c === 117 ? 4 : 8;
1359
+ for (let j = 0; j < len; j++, ctx.p++) {
1360
+ let hex = ctx.s.charCodeAt(ctx.p);
1400
1361
  let digit = (
1401
1362
  /* 0-9 */
1402
1363
  hex >= 48 && hex <= 57 ? hex - 48 : (
@@ -1408,369 +1369,517 @@ function parseString(str, ptr) {
1408
1369
  )
1409
1370
  );
1410
1371
  if (digit < 0)
1411
- throw new TomlError("invalid non-hex character in unicode escape", { toml: str, ptr: i + 1 });
1372
+ TomlError.x("invalid non-hex character in unicode escape", ctx);
1412
1373
  value = value << 4 | digit;
1413
1374
  }
1414
1375
  if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
1415
- throw new TomlError("invalid unicode escape", { toml: str, ptr: i });
1376
+ TomlError.x("invalid unicode escape", ctx, errPtr);
1416
1377
  }
1417
1378
  parsed += String.fromCodePoint(value);
1418
- sliceStart = i + 1;
1379
+ sliceStart = ctx.p--;
1419
1380
  state = 0;
1420
- } else if (c === " " || c === " ") {
1381
+ } else if (isMultiline && (c === 32 || c === 9)) {
1421
1382
  state = 2;
1422
1383
  } else {
1423
- if (c === "b")
1384
+ if (c === 98)
1424
1385
  parsed += "\b";
1425
- else if (c === "t")
1386
+ else if (c === 116)
1426
1387
  parsed += " ";
1427
- else if (c === "n")
1388
+ else if (c === 110)
1428
1389
  parsed += "\n";
1429
- else if (c === "f")
1390
+ else if (c === 102)
1430
1391
  parsed += "\f";
1431
- else if (c === "r")
1392
+ else if (c === 114)
1432
1393
  parsed += "\r";
1433
- else if (c === "e")
1394
+ else if (c === 101)
1434
1395
  parsed += "\x1B";
1435
- else if (c === '"')
1396
+ else if (c === 34)
1436
1397
  parsed += '"';
1437
- else if (c === "\\")
1398
+ else if (c === 92)
1438
1399
  parsed += "\\";
1439
1400
  else
1440
- throw new TomlError("unrecognized escape sequence", { toml: str, ptr: i });
1441
- sliceStart = i + 1;
1401
+ TomlError.x("unrecognised escape sequence", ctx);
1402
+ sliceStart = ctx.p + 1;
1442
1403
  state = 0;
1443
1404
  }
1444
- } else if (c !== " " && c !== " ") {
1445
- if (state === 2) {
1446
- throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
1447
- toml: str,
1448
- ptr: sliceStart
1449
- });
1450
- }
1451
- state = !isLiteral && c === "\\" ? 1 : 0;
1452
- sliceStart = i;
1405
+ } else if (c !== 32 && c !== 9) {
1406
+ if (state === 2)
1407
+ TomlError.x("invalid escape: only line-ending whitespace may be escaped", ctx, sliceStart);
1408
+ state = !isLiteral && c === 92 ? 1 : 0;
1409
+ sliceStart = ctx.p;
1453
1410
  }
1454
1411
  }
1455
- throw new TomlError("unfinished string", { toml: str, ptr });
1412
+ TomlError.x("unfinished string", ctx, startPtr);
1456
1413
  }
1457
- function parseValue(value, toml, ptr, integersAsBigInt) {
1458
- if (value === "true")
1459
- return true;
1460
- if (value === "false")
1461
- return false;
1462
- if (value === "-inf")
1463
- return -Infinity;
1464
- if (value === "inf" || value === "+inf")
1465
- return Infinity;
1466
- if (value === "nan" || value === "+nan" || value === "-nan")
1467
- return NaN;
1468
- if (value === "-0")
1469
- return integersAsBigInt ? 0n : 0;
1470
- let isInt = INT_REGEX.test(value);
1471
- if (isInt || FLOAT_REGEX.test(value)) {
1472
- if (LEADING_ZERO.test(value)) {
1473
- throw new TomlError("leading zeroes are not allowed", {
1474
- toml,
1475
- ptr
1476
- });
1477
- }
1478
- value = value.replace(/_/g, "");
1479
- let numeric = +value;
1480
- if (isNaN(numeric)) {
1481
- throw new TomlError("invalid number", {
1482
- toml,
1483
- ptr
1484
- });
1485
- }
1486
- if (isInt) {
1487
- if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
1488
- throw new TomlError("integer value cannot be represented losslessly", {
1489
- toml,
1490
- ptr
1491
- });
1414
+
1415
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/date.js
1416
+ var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[Tt ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|z|[-+]\d{2}:\d{2})?$/i;
1417
+ var TomlDate = class _TomlDate extends Date {
1418
+ #hasDate = false;
1419
+ #hasTime = false;
1420
+ #offset = null;
1421
+ constructor(date, fasttype, unsafeDelim) {
1422
+ let hasDate = true;
1423
+ let hasTime = true;
1424
+ let offset = "Z";
1425
+ let c;
1426
+ if (typeof date === "string") {
1427
+ if (fasttype)
1428
+ prep: {
1429
+ if (fasttype < 3) {
1430
+ if (+date.slice(11, 13) > 23) {
1431
+ date = "";
1432
+ break prep;
1433
+ }
1434
+ if (fasttype === 2) {
1435
+ offset = null;
1436
+ date += "Z";
1437
+ } else if ((c = date.charCodeAt(date.length - 1)) !== 90 && c !== 122) {
1438
+ offset = date.slice(date.length - 6);
1439
+ }
1440
+ if (unsafeDelim)
1441
+ date = date.slice(0, 10) + "T" + date.slice(11);
1442
+ } else if (fasttype === 4) {
1443
+ date = +date.slice(0, 2) > 23 ? "" : `0000-01-01T${date}Z`;
1444
+ }
1445
+ hasDate = fasttype !== 4;
1446
+ hasTime = fasttype !== 3;
1447
+ }
1448
+ else {
1449
+ let match = date.match(DATE_TIME_RE);
1450
+ if (match) {
1451
+ if (!match[1]) {
1452
+ hasDate = false;
1453
+ date = `0000-01-01T${date}`;
1454
+ }
1455
+ hasTime = !!match[2];
1456
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
1457
+ if (match[2] && +match[2] > 23) {
1458
+ date = "";
1459
+ } else {
1460
+ offset = match[3] || null;
1461
+ if (!offset && hasTime)
1462
+ date += "Z";
1463
+ }
1464
+ } else {
1465
+ date = "";
1466
+ }
1492
1467
  }
1493
- if (isInt || integersAsBigInt === true)
1494
- numeric = BigInt(value);
1495
1468
  }
1496
- return numeric;
1469
+ super(date);
1470
+ if (!isNaN(this.getTime())) {
1471
+ this.#hasDate = hasDate;
1472
+ this.#hasTime = hasTime;
1473
+ this.#offset = offset;
1474
+ }
1497
1475
  }
1498
- const date = new TomlDate(value);
1499
- if (!date.isValid()) {
1500
- throw new TomlError("invalid value", {
1501
- toml,
1502
- ptr
1503
- });
1476
+ isDateTime() {
1477
+ return this.#hasDate && this.#hasTime;
1504
1478
  }
1505
- return date;
1506
- }
1479
+ isLocal() {
1480
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
1481
+ }
1482
+ isDate() {
1483
+ return this.#hasDate && !this.#hasTime;
1484
+ }
1485
+ isTime() {
1486
+ return this.#hasTime && !this.#hasDate;
1487
+ }
1488
+ isValid() {
1489
+ return this.#hasDate || this.#hasTime;
1490
+ }
1491
+ toISOString() {
1492
+ let iso = super.toISOString();
1493
+ if (this.isDate())
1494
+ return iso.slice(0, 10);
1495
+ if (this.isTime())
1496
+ return iso.slice(11, 23);
1497
+ if (this.#offset === null)
1498
+ return iso.slice(0, -1);
1499
+ if (this.#offset === "Z" || this.#offset === "z")
1500
+ return iso;
1501
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
1502
+ offset = this.#offset[0] === "-" ? offset : -offset;
1503
+ let offsetDate = new Date(this.getTime() - offset * 6e4);
1504
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
1505
+ }
1506
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
1507
+ let date = new _TomlDate(jsDate);
1508
+ date.#offset = offset;
1509
+ return date;
1510
+ }
1511
+ static wrapAsLocalDateTime(jsDate) {
1512
+ let date = new _TomlDate(jsDate);
1513
+ date.#offset = null;
1514
+ return date;
1515
+ }
1516
+ static wrapAsLocalDate(jsDate) {
1517
+ let date = new _TomlDate(jsDate);
1518
+ date.#hasTime = false;
1519
+ date.#offset = null;
1520
+ return date;
1521
+ }
1522
+ static wrapAsLocalTime(jsDate) {
1523
+ let date = new _TomlDate(jsDate);
1524
+ date.#hasDate = false;
1525
+ date.#offset = null;
1526
+ return date;
1527
+ }
1528
+ };
1507
1529
 
1508
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/util.js
1509
- function indexOfNewline(str, start = 0, end = str.length) {
1510
- let idx = str.indexOf("\n", start);
1511
- if (str[idx - 1] === "\r")
1512
- idx--;
1513
- return idx <= end ? idx : -1;
1514
- }
1515
- function skipComment(str, ptr) {
1516
- for (let i = ptr; i < str.length; i++) {
1517
- let c = str[i];
1518
- if (c === "\n")
1519
- return i;
1520
- if (c === "\r" && str[i + 1] === "\n")
1521
- return i + 1;
1522
- if (c < " " && c !== " " || c === "\x7F") {
1523
- throw new TomlError("control characters are not allowed in comments", {
1524
- toml: str,
1525
- ptr
1526
- });
1527
- }
1530
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/extract.js
1531
+ function isDigit(char, base = 10) {
1532
+ return base === 16 ? char > 47 && char < 58 || char > 64 && char < 71 || char > 96 && char < 103 : char > 47 && char < 48 + base;
1533
+ }
1534
+ function isEndOfValue(char, delim) {
1535
+ return char === 32 || char === 9 || char === 10 || char === 13 || // Structure end or next value delimiter
1536
+ delim && (char === delim || char === 44) || // Comment
1537
+ char === 35;
1538
+ }
1539
+ function extractValue(ctx, end) {
1540
+ let errPtr = ctx.p;
1541
+ let c = ctx.s.charCodeAt(ctx.p);
1542
+ if (c === 91 || c === 123) {
1543
+ ctx.d-- || TomlError.x("document contains excessively nested structures. aborting.", ctx);
1544
+ let value = c === 91 ? parseArray(ctx) : parseInlineTable(ctx);
1545
+ ctx.d++;
1546
+ return value;
1528
1547
  }
1529
- return str.length;
1530
- }
1531
- function skipVoid(str, ptr, banNewLines, banComments) {
1532
- let c;
1533
- while (1) {
1534
- while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
1535
- ptr++;
1536
- if (banComments || c !== "#")
1537
- break;
1538
- ptr = skipComment(str, ptr);
1548
+ if (c === 34 || c === 39) {
1549
+ return parseString(ctx);
1550
+ }
1551
+ if (c === 116) {
1552
+ if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101)
1553
+ TomlError.x("invalid value", ctx, errPtr);
1554
+ return ctx.p++, true;
1555
+ }
1556
+ if (c === 102) {
1557
+ if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 108 || ctx.s.charCodeAt(++ctx.p) !== 115 || ctx.s.charCodeAt(++ctx.p) !== 101)
1558
+ TomlError.x("invalid value", ctx, errPtr);
1559
+ return ctx.p++, false;
1539
1560
  }
1540
- return ptr;
1561
+ if (c === 43 || c === 45) {
1562
+ return parseNumber(ctx, ctx.p, ctx.s.charCodeAt(++ctx.p), 44 - c, end);
1563
+ }
1564
+ if (ctx.s.charCodeAt(ctx.p + 4) === 45 && ctx.s.charCodeAt(ctx.p + 7) === 45) {
1565
+ return parseDate(ctx, c, end);
1566
+ }
1567
+ if (ctx.s.charCodeAt(ctx.p + 2) === 58) {
1568
+ return parseTime(ctx, c, end);
1569
+ }
1570
+ return parseNumber(ctx, ctx.p, c, 0, end);
1541
1571
  }
1542
- function skipUntil(str, ptr, sep, end, banNewLines = false) {
1543
- if (!end) {
1544
- ptr = indexOfNewline(str, ptr);
1545
- return ptr < 0 ? str.length : ptr;
1572
+ function parseNumber(ctx, startPtr, startChr, sign, endChr) {
1573
+ let c = startChr;
1574
+ let state = 0;
1575
+ let hasUnderscores = false;
1576
+ if (c === 105) {
1577
+ if (ctx.s.charCodeAt(++ctx.p) !== 110 || ctx.s.charCodeAt(++ctx.p) !== 102)
1578
+ TomlError.x("invalid value", ctx, startPtr);
1579
+ return ctx.p++, (sign || 1) / 0;
1580
+ }
1581
+ if (c === 110) {
1582
+ if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 110)
1583
+ TomlError.x("invalid value", ctx, startPtr);
1584
+ return ctx.p++, NaN;
1585
+ }
1586
+ if (c === 48) {
1587
+ if (++ctx.p >= ctx.s.length || isEndOfValue(c = ctx.s.charCodeAt(ctx.p), endChr))
1588
+ return ctx.bi === true ? 0n : 0;
1589
+ if (!sign) {
1590
+ if (c === 120)
1591
+ return parseIntegerBaseN(ctx, startPtr, 16, endChr);
1592
+ else if (c === 98)
1593
+ return parseIntegerBaseN(ctx, startPtr, 2, endChr);
1594
+ else if (c === 111)
1595
+ return parseIntegerBaseN(ctx, startPtr, 8, endChr);
1596
+ }
1597
+ if (c === 46)
1598
+ state = 2;
1599
+ else if (c === 101 || c === 69)
1600
+ state = 4;
1601
+ else
1602
+ TomlError.x("illegal leading zero", ctx, startPtr);
1603
+ } else if (!isDigit(c))
1604
+ TomlError.x("invalid value", ctx, startPtr);
1605
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
1606
+ if (!state)
1607
+ state = 1;
1608
+ if (c === 95) {
1609
+ if (!(state & 1))
1610
+ TomlError.x("illegal underscore", ctx);
1611
+ state += 11;
1612
+ hasUnderscores = true;
1613
+ } else if (state === 1 && c === 46)
1614
+ state = 2;
1615
+ else if ((state === 1 || state === 3) && (c === 101 || c === 69))
1616
+ state = 4;
1617
+ else if (state === 4 && (c === 43 || c === 45)) {
1618
+ } else if (!isDigit(c))
1619
+ TomlError.x(`illegal character in numeric literal`, ctx);
1620
+ else if (state > 9)
1621
+ state -= 11;
1622
+ else if (!(state & 1))
1623
+ state++;
1624
+ }
1625
+ if (!state) {
1626
+ let val = (startChr - 48) * (sign || 1);
1627
+ return ctx.bi === true ? BigInt(val) : val;
1628
+ }
1629
+ if (!(state & 1))
1630
+ TomlError.x("unfinished numeric value", ctx, startPtr);
1631
+ let str = ctx.s.slice(startPtr, ctx.p);
1632
+ if (hasUnderscores)
1633
+ str = str.replaceAll("_", "");
1634
+ return state > 1 ? parseFloat(str) : parseInteger(ctx, str, 10, startPtr);
1635
+ }
1636
+ function parseIntegerBaseN(ctx, startPtr, base, endChr) {
1637
+ let c, underscore = 1;
1638
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
1639
+ if (c === 95) {
1640
+ if (underscore & 1)
1641
+ TomlError.x("illegal underscore", ctx);
1642
+ underscore = 3;
1643
+ } else if (!isDigit(c, base))
1644
+ TomlError.x(`illegal character in numeric literal`, ctx);
1645
+ else if (underscore & 1)
1646
+ underscore--;
1647
+ }
1648
+ if (underscore & 1)
1649
+ TomlError.x("unfinished numeric value", ctx);
1650
+ let str = ctx.s.slice(startPtr + 2, ctx.p);
1651
+ if (underscore)
1652
+ str = str.replaceAll("_", "");
1653
+ return parseInteger(ctx, str, base, startPtr);
1654
+ }
1655
+ function parseInteger(ctx, str, base, startPtr) {
1656
+ if (ctx.bi !== true)
1657
+ int: {
1658
+ let val = parseInt(str, base);
1659
+ if (!Number.isSafeInteger(val)) {
1660
+ if (ctx.bi)
1661
+ break int;
1662
+ TomlError.x("integer value cannot be represented losslessly", ctx, startPtr);
1663
+ }
1664
+ return val;
1665
+ }
1666
+ return base === 10 ? BigInt(str) : BigInt((base === 2 ? "0b" : base === 8 ? "0o" : "0x") + str);
1667
+ }
1668
+ function parseDate(ctx, c, endChr) {
1669
+ let startPtr = ctx.p++, unsafeSeparator;
1670
+ if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++))) {
1671
+ return parseNumber(ctx, ctx.p = startPtr, c, 0, endChr);
1672
+ }
1673
+ ctx.p += 5;
1674
+ if (!isDigit(ctx.s.charCodeAt(ctx.p++)))
1675
+ TomlError.x("invalid date-time: date part is malformed", ctx, startPtr);
1676
+ if (ctx.p >= ctx.s.length || ((c = ctx.s.charCodeAt(ctx.p)) !== 32 || (unsafeSeparator = true, !isDigit(ctx.s.charCodeAt(ctx.p + 1)))) && c !== 84 && c !== 116) {
1677
+ let t2 = ctx.s.slice(startPtr, ctx.p);
1678
+ return readDate(ctx, t2, 3, false, startPtr);
1679
+ }
1680
+ if (ctx.s.charCodeAt(ctx.p += 3) !== 58)
1681
+ TomlError.x("invalid date-time: time part is malformed", ctx, startPtr);
1682
+ if (ctx.s.charCodeAt(ctx.p += 3) === 58)
1683
+ ctx.p += 3;
1684
+ if (ctx.s.charCodeAt(ctx.p) === 46)
1685
+ while (isDigit(ctx.s.charCodeAt(++ctx.p)))
1686
+ ;
1687
+ if (c = ctx.s.charCodeAt(ctx.p)) {
1688
+ if (c === 90 || c === 122) {
1689
+ let t2 = ctx.s.slice(startPtr, ++ctx.p);
1690
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, "[+00:00]");
1691
+ }
1692
+ if (c === 43 || c === 45) {
1693
+ let t2 = ctx.s.slice(startPtr, ctx.p += 6);
1694
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, !ctx.ld && "[" + ctx.s.slice(ctx.p - 6, ctx.p) + "]");
1695
+ }
1696
+ }
1697
+ let t = ctx.s.slice(startPtr, ctx.p);
1698
+ return readDate(ctx, t, 2, unsafeSeparator, startPtr);
1699
+ }
1700
+ function parseTime(ctx, c, endChr) {
1701
+ let start = ctx.p;
1702
+ if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(++ctx.p))) {
1703
+ return parseNumber(ctx, --ctx.p, c, 0, endChr);
1704
+ }
1705
+ if (ctx.s.charCodeAt(ctx.p += 4) === 58)
1706
+ ctx.p += 3;
1707
+ if (ctx.s.charCodeAt(ctx.p) === 46)
1708
+ while (isDigit(ctx.s.charCodeAt(++ctx.p)))
1709
+ ;
1710
+ let t = ctx.s.slice(start, ctx.p);
1711
+ return readDate(ctx, t, 4, false, start);
1712
+ }
1713
+ function readDate(ctx, str, type, unsafeDelim, errPtr, temporalSuffix) {
1714
+ if (ctx.ld) {
1715
+ let date = new TomlDate(str, type, unsafeDelim);
1716
+ if (!date.isValid())
1717
+ TomlError.x("invalid date", ctx, errPtr);
1718
+ return date;
1546
1719
  }
1547
- for (let i = ptr; i < str.length; i++) {
1548
- let c = str[i];
1549
- if (c === "#") {
1550
- i = indexOfNewline(str, i);
1551
- } else if (c === sep) {
1552
- return i + 1;
1553
- } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
1554
- return i;
1720
+ try {
1721
+ if (temporalSuffix)
1722
+ str += temporalSuffix;
1723
+ switch (type) {
1724
+ case 1:
1725
+ return Temporal.ZonedDateTime.from(str);
1726
+ case 2:
1727
+ return Temporal.PlainDateTime.from(str);
1728
+ case 3:
1729
+ return Temporal.PlainDate.from(str);
1730
+ case 4:
1731
+ return Temporal.PlainTime.from(str);
1555
1732
  }
1733
+ } catch (e) {
1734
+ TomlError.x(e instanceof Error ? e.message : "" + e, ctx, errPtr);
1556
1735
  }
1557
- throw new TomlError("cannot find end of structure", {
1558
- toml: str,
1559
- ptr
1560
- });
1561
1736
  }
1562
1737
 
1563
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/extract.js
1564
- function sliceAndTrimEndOf(str, startPtr, endPtr) {
1565
- let value = str.slice(startPtr, endPtr);
1566
- let commentIdx = value.indexOf("#");
1567
- if (commentIdx > -1) {
1568
- skipComment(str, commentIdx);
1569
- value = value.slice(0, commentIdx);
1570
- }
1571
- return [value.trimEnd(), commentIdx];
1572
- }
1573
- function extractValue(str, ptr, end, depth, integersAsBigInt) {
1574
- if (depth === 0) {
1575
- throw new TomlError("document contains excessively nested structures. aborting.", {
1576
- toml: str,
1577
- ptr
1578
- });
1579
- }
1580
- let c = str[ptr];
1581
- if (c === "[" || c === "{") {
1582
- let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
1583
- if (end) {
1584
- endPtr2 = skipVoid(str, endPtr2);
1585
- if (str[endPtr2] === ",")
1586
- endPtr2++;
1587
- else if (str[endPtr2] !== end) {
1588
- throw new TomlError("expected comma or end of structure", {
1589
- toml: str,
1590
- ptr: endPtr2
1591
- });
1592
- }
1738
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/util.js
1739
+ function skipComment(ctx) {
1740
+ for (; ctx.p < ctx.s.length; ctx.p++) {
1741
+ let c = ctx.s.charCodeAt(ctx.p);
1742
+ if (c === 10)
1743
+ break;
1744
+ if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
1745
+ ctx.p++;
1746
+ break;
1593
1747
  }
1594
- return [value, endPtr2];
1595
- }
1596
- if (c === '"' || c === "'") {
1597
- let [parsed, endPtr2] = parseString(str, ptr);
1598
- if (end) {
1599
- endPtr2 = skipVoid(str, endPtr2);
1600
- if (str[endPtr2] && str[endPtr2] !== "," && str[endPtr2] !== end && str[endPtr2] !== "\n" && str[endPtr2] !== "\r") {
1601
- throw new TomlError("unexpected character encountered", {
1602
- toml: str,
1603
- ptr: endPtr2
1604
- });
1605
- }
1606
- if (str[endPtr2] === ",")
1607
- endPtr2++;
1748
+ if (c < 32 && c !== 9 || c === 127) {
1749
+ TomlError.x("control characters are not allowed in comments", ctx);
1608
1750
  }
1609
- return [parsed, endPtr2];
1610
- }
1611
- let endPtr = skipUntil(str, ptr, ",", end);
1612
- let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0));
1613
- if (!slice[0]) {
1614
- throw new TomlError("incomplete key-value declaration: no value specified", {
1615
- toml: str,
1616
- ptr
1617
- });
1618
1751
  }
1619
- if (end && slice[1] > -1) {
1620
- endPtr = skipVoid(str, ptr + slice[1]);
1621
- if (str[endPtr] === ",")
1622
- endPtr++;
1752
+ }
1753
+ function skipVoid(ctx, banNewLines, banComments) {
1754
+ let c;
1755
+ while (ctx.p < ctx.s.length) {
1756
+ while (ctx.p < ctx.s.length && ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)))
1757
+ ctx.p++;
1758
+ if (banComments || c !== 35)
1759
+ break;
1760
+ skipComment(ctx);
1623
1761
  }
1624
- return [
1625
- parseValue(slice[0], str, ptr, integersAsBigInt),
1626
- endPtr
1627
- ];
1628
1762
  }
1629
1763
 
1630
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/struct.js
1631
- var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
1632
- function parseKey(str, ptr, end = "=") {
1633
- let dot = ptr - 1;
1764
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/struct.js
1765
+ function parseKey(ctx, end = 61) {
1766
+ let startPtr;
1767
+ let state = 0;
1634
1768
  let parsed = [];
1635
- let endPtr = str.indexOf(end, ptr);
1636
- if (endPtr < 0) {
1637
- throw new TomlError("incomplete key-value: cannot find end of key", {
1638
- toml: str,
1639
- ptr
1640
- });
1641
- }
1769
+ let sliceStart;
1770
+ let c = ctx.s.charCodeAt(startPtr = ctx.p);
1642
1771
  do {
1643
- let c = str[ptr = ++dot];
1644
- if (c !== " " && c !== " ") {
1645
- if (c === '"' || c === "'") {
1646
- if (c === str[ptr + 1] && c === str[ptr + 2]) {
1647
- throw new TomlError("multiline strings are not allowed in keys", {
1648
- toml: str,
1649
- ptr
1650
- });
1651
- }
1652
- let [part, eos] = parseString(str, ptr);
1653
- dot = str.indexOf(".", eos);
1654
- let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
1655
- let newLine = indexOfNewline(strEnd);
1656
- if (newLine > -1) {
1657
- throw new TomlError("newlines are not allowed in keys", {
1658
- toml: str,
1659
- ptr: ptr + dot + newLine
1660
- });
1661
- }
1662
- if (strEnd.trimStart()) {
1663
- throw new TomlError("found extra tokens after the string part", {
1664
- toml: str,
1665
- ptr: eos
1666
- });
1667
- }
1668
- if (endPtr < eos) {
1669
- endPtr = str.indexOf(end, eos);
1670
- if (endPtr < 0) {
1671
- throw new TomlError("incomplete key-value: cannot find end of key", {
1672
- toml: str,
1673
- ptr
1674
- });
1675
- }
1676
- }
1677
- parsed.push(part);
1678
- } else {
1679
- dot = str.indexOf(".", ptr);
1680
- let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
1681
- if (!KEY_PART_RE.test(part)) {
1682
- throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
1683
- toml: str,
1684
- ptr
1685
- });
1686
- }
1687
- parsed.push(part.trimEnd());
1772
+ if (c === end) {
1773
+ if (!state)
1774
+ TomlError.x("unexpected end of key", ctx);
1775
+ if (state === 1)
1776
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
1777
+ return ctx.p++, parsed;
1778
+ } else if (c === 46) {
1779
+ if (!state)
1780
+ TomlError.x("illegal empty bare key", ctx);
1781
+ if (state === 1)
1782
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
1783
+ state = 0;
1784
+ } else if (!state && (c === 34 || c === 39)) {
1785
+ if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2))
1786
+ TomlError.x("illegal quoted key: multiline strings are not allowed", ctx);
1787
+ parsed.push(parseString(ctx));
1788
+ state = 2;
1789
+ ctx.p--;
1790
+ } else if (c === 32 || c === 9) {
1791
+ if (state === 1) {
1792
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
1793
+ state = 2;
1688
1794
  }
1795
+ } else if (state === 2 || c < 48 && c !== 45 || c > 57 && c < 65 || c > 90 && c < 97 && c !== 95 || c > 122) {
1796
+ TomlError.x("illegal character in key", ctx);
1797
+ } else if (!state) {
1798
+ state = 1;
1799
+ sliceStart = ctx.p;
1689
1800
  }
1690
- } while (dot + 1 && dot < endPtr);
1691
- return [parsed, skipVoid(str, endPtr + 1, true, true)];
1801
+ } while (c = ctx.s.charCodeAt(++ctx.p));
1802
+ TomlError.x("incomplete key-value: cannot find end of key", ctx, startPtr);
1692
1803
  }
1693
- function parseInlineTable(str, ptr, depth, integersAsBigInt) {
1694
- let res = {};
1804
+ function parseInlineTable(ctx) {
1805
+ let startPtr = ctx.p++;
1806
+ let res = /* @__PURE__ */ Object.create(null);
1695
1807
  let seen = /* @__PURE__ */ new Set();
1696
1808
  let c;
1697
- ptr++;
1698
- while ((c = str[ptr++]) !== "}" && c) {
1699
- if (c === ",") {
1700
- throw new TomlError("expected value, found comma", {
1701
- toml: str,
1702
- ptr: ptr - 1
1703
- });
1704
- } else if (c === "#")
1705
- ptr = skipComment(str, ptr);
1706
- else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
1707
- let k;
1708
- let t = res;
1709
- let hasOwn = false;
1710
- let [key, keyEndPtr] = parseKey(str, ptr - 1);
1711
- for (let i = 0; i < key.length; i++) {
1712
- if (i)
1713
- t = hasOwn ? t[k] : t[k] = {};
1714
- k = key[i];
1715
- if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
1716
- throw new TomlError("trying to redefine an already defined value", {
1717
- toml: str,
1718
- ptr
1719
- });
1720
- }
1721
- if (!hasOwn && k === "__proto__") {
1722
- Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
1723
- }
1809
+ while (ctx.p < ctx.s.length) {
1810
+ skipVoid(ctx);
1811
+ if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
1812
+ ctx.p++;
1813
+ return res;
1814
+ }
1815
+ let k;
1816
+ let t = res;
1817
+ let hasOwn = false;
1818
+ let errPtr = ctx.p;
1819
+ let key = parseKey(ctx);
1820
+ for (let i = 0; i < key.length; i++) {
1821
+ if (i)
1822
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
1823
+ k = key[i];
1824
+ if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
1825
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
1724
1826
  }
1725
- if (hasOwn) {
1726
- throw new TomlError("trying to redefine an already defined value", {
1727
- toml: str,
1728
- ptr
1729
- });
1827
+ let unsafe = k === "__proto__";
1828
+ if (ctx.uk && (unsafe || k === "constructor")) {
1829
+ t = ctx.uk !== 1 && TomlError.x("document contains an unsafe property", ctx, errPtr);
1830
+ break;
1831
+ }
1832
+ if (!hasOwn && unsafe) {
1833
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
1730
1834
  }
1731
- let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
1835
+ }
1836
+ if (hasOwn) {
1837
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
1838
+ }
1839
+ skipVoid(ctx, true, true);
1840
+ let value = extractValue(
1841
+ ctx,
1842
+ 125
1843
+ /* } */
1844
+ );
1845
+ if (t && typeof (t[k] = value) === "object")
1732
1846
  seen.add(value);
1733
- t[k] = value;
1734
- ptr = valueEndPtr;
1847
+ skipVoid(ctx);
1848
+ if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) {
1849
+ return res;
1735
1850
  }
1851
+ if (c !== 44)
1852
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
1736
1853
  }
1737
- if (!c) {
1738
- throw new TomlError("unfinished table encountered", {
1739
- toml: str,
1740
- ptr
1741
- });
1742
- }
1743
- return [res, ptr];
1854
+ TomlError.x("unfinished table", ctx, startPtr);
1744
1855
  }
1745
- function parseArray(str, ptr, depth, integersAsBigInt) {
1856
+ function parseArray(ctx) {
1857
+ let startPtr = ctx.p++;
1746
1858
  let res = [];
1747
1859
  let c;
1748
- ptr++;
1749
- while ((c = str[ptr++]) !== "]" && c) {
1750
- if (c === ",") {
1751
- throw new TomlError("expected value, found comma", {
1752
- toml: str,
1753
- ptr: ptr - 1
1754
- });
1755
- } else if (c === "#")
1756
- ptr = skipComment(str, ptr);
1757
- else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
1758
- let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
1759
- res.push(e[0]);
1760
- ptr = e[1];
1761
- }
1762
- }
1763
- if (!c) {
1764
- throw new TomlError("unfinished array encountered", {
1765
- toml: str,
1766
- ptr
1767
- });
1768
- }
1769
- return [res, ptr];
1860
+ while (ctx.p < ctx.s.length) {
1861
+ skipVoid(ctx);
1862
+ if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
1863
+ ctx.p++;
1864
+ return res;
1865
+ }
1866
+ res.push(extractValue(
1867
+ ctx,
1868
+ 93
1869
+ /* ] */
1870
+ ));
1871
+ skipVoid(ctx);
1872
+ if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) {
1873
+ return res;
1874
+ }
1875
+ if (c !== 44)
1876
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
1877
+ }
1878
+ TomlError.x("unfinished array", ctx, startPtr);
1770
1879
  }
1771
1880
 
1772
- // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/parse.js
1773
- function peekTable(key, table, meta, type) {
1881
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/parse.js
1882
+ function peekTable(ctx, key, table, meta, type) {
1774
1883
  let t = table;
1775
1884
  let m = meta;
1776
1885
  let k;
@@ -1778,7 +1887,7 @@ function peekTable(key, table, meta, type) {
1778
1887
  let state;
1779
1888
  for (let i = 0; i < key.length; i++) {
1780
1889
  if (i) {
1781
- t = hasOwn ? t[k] : t[k] = {};
1890
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
1782
1891
  m = (state = m[k]).c;
1783
1892
  if (type === 0 && (state.t === 1 || state.t === 2)) {
1784
1893
  return null;
@@ -1794,7 +1903,10 @@ function peekTable(key, table, meta, type) {
1794
1903
  return null;
1795
1904
  }
1796
1905
  if (!hasOwn) {
1797
- if (k === "__proto__") {
1906
+ let unsafe = k === "__proto__";
1907
+ if (ctx.uk && (unsafe || k === "constructor"))
1908
+ return false;
1909
+ if (unsafe) {
1798
1910
  Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
1799
1911
  Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
1800
1912
  }
@@ -1802,7 +1914,7 @@ function peekTable(key, table, meta, type) {
1802
1914
  t: i < key.length - 1 && type === 2 ? 3 : type,
1803
1915
  d: false,
1804
1916
  i: 0,
1805
- c: {}
1917
+ c: /* @__PURE__ */ Object.create(null)
1806
1918
  };
1807
1919
  }
1808
1920
  }
@@ -1815,85 +1927,103 @@ function peekTable(key, table, meta, type) {
1815
1927
  state.d = true;
1816
1928
  t[k] = [];
1817
1929
  }
1818
- t[k].push(t = {});
1819
- state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
1930
+ t[k].push(t = /* @__PURE__ */ Object.create(null));
1931
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: /* @__PURE__ */ Object.create(null) };
1820
1932
  }
1821
1933
  if (state.d) {
1822
1934
  return null;
1823
1935
  }
1824
1936
  state.d = true;
1825
1937
  if (type === 1) {
1826
- t = hasOwn ? t[k] : t[k] = {};
1938
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
1827
1939
  } else if (type === 0 && hasOwn) {
1828
1940
  return null;
1829
1941
  }
1830
1942
  return [k, t, state.c];
1831
1943
  }
1832
- function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
1833
- let res = {};
1834
- let meta = {};
1944
+ function validateTablePeek(ctx, peek, ptr) {
1945
+ if (peek === null || ctx.uk === 2)
1946
+ TomlError.x(peek === null ? "trying to redefine an already defined table or value" : "document contains an unsafe property", ctx, ptr);
1947
+ }
1948
+ function parse(toml, options = {}) {
1949
+ let ctx = {
1950
+ s: toml,
1951
+ p: 0,
1952
+ d: options.maxDepth ?? 1e3,
1953
+ bi: options.integersAsBigInt ?? false,
1954
+ ld: options.useLegacyDate ?? true,
1955
+ uk: options.unsafeKeyBehaviour === "throw" ? 2 : options.unsafeKeyBehaviour === "drop" ? 1 : 0
1956
+ };
1957
+ let res = /* @__PURE__ */ Object.create(null);
1958
+ let meta = /* @__PURE__ */ Object.create(null);
1959
+ let tmp;
1960
+ let skipping = false;
1835
1961
  let tbl = res;
1836
1962
  let m = meta;
1837
- for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
1838
- if (toml[ptr] === "[") {
1839
- let isTableArray = toml[++ptr] === "[";
1840
- let k = parseKey(toml, ptr += +isTableArray, "]");
1963
+ if (toml.charCodeAt(0) === 65279)
1964
+ ctx.p++;
1965
+ skipVoid(ctx);
1966
+ while (ctx.p < toml.length) {
1967
+ if (toml.charCodeAt(ctx.p) === 91) {
1968
+ let isTableArray = toml.charCodeAt(++ctx.p) === 91;
1969
+ tmp = ctx.p += +isTableArray;
1970
+ skipping = false;
1971
+ let k = parseKey(
1972
+ ctx,
1973
+ 93
1974
+ /* ] */
1975
+ );
1841
1976
  if (isTableArray) {
1842
- if (toml[k[1] - 1] !== "]") {
1843
- throw new TomlError("expected end of table declaration", {
1844
- toml,
1845
- ptr: k[1] - 1
1846
- });
1977
+ if (toml.charCodeAt(ctx.p) !== 93) {
1978
+ TomlError.x("expected end of table array declaration", ctx);
1847
1979
  }
1848
- k[1]++;
1980
+ ctx.p++;
1849
1981
  }
1850
1982
  let p = peekTable(
1851
- k[0],
1983
+ ctx,
1984
+ k,
1852
1985
  res,
1853
1986
  meta,
1854
1987
  isTableArray ? 2 : 1
1855
1988
  /* Type.EXPLICIT */
1856
1989
  );
1857
1990
  if (!p) {
1858
- throw new TomlError("trying to redefine an already defined table or value", {
1859
- toml,
1860
- ptr
1861
- });
1991
+ validateTablePeek(ctx, p, tmp);
1992
+ skipping = true;
1993
+ } else {
1994
+ m = p[2];
1995
+ tbl = p[1];
1862
1996
  }
1863
- m = p[2];
1864
- tbl = p[1];
1865
- ptr = k[1];
1866
1997
  } else {
1867
- let k = parseKey(toml, ptr);
1998
+ tmp = ctx.p;
1999
+ let k = parseKey(ctx);
1868
2000
  let p = peekTable(
1869
- k[0],
2001
+ ctx,
2002
+ k,
1870
2003
  tbl,
1871
2004
  m,
1872
2005
  0
1873
2006
  /* Type.DOTTED */
1874
2007
  );
1875
- if (!p) {
1876
- throw new TomlError("trying to redefine an already defined table or value", {
1877
- toml,
1878
- ptr
1879
- });
1880
- }
1881
- let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
1882
- p[1][p[0]] = v[0];
1883
- ptr = v[1];
1884
- }
1885
- ptr = skipVoid(toml, ptr, true);
1886
- if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
1887
- throw new TomlError("each key-value declaration must be followed by an end-of-line", {
1888
- toml,
1889
- ptr
1890
- });
2008
+ if (!p && !skipping)
2009
+ validateTablePeek(ctx, p, tmp);
2010
+ skipVoid(ctx, true, true);
2011
+ let v = extractValue(ctx, void 0);
2012
+ if (p && !skipping)
2013
+ p[1][p[0]] = v;
2014
+ }
2015
+ skipVoid(ctx, true);
2016
+ if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && (tmp !== 13 || toml.charCodeAt(ctx.p + 1) !== 10)) {
2017
+ TomlError.x("each key-value declaration must be followed by an end-of-line", ctx);
1891
2018
  }
1892
- ptr = skipVoid(toml, ptr);
2019
+ skipVoid(ctx);
1893
2020
  }
1894
2021
  return res;
1895
2022
  }
1896
2023
 
2024
+ // node_modules/.pnpm/smol-toml@1.9.0/node_modules/smol-toml/dist/stringify.js
2025
+ var HAS_WELLFORMED = !!"".isWellFormed;
2026
+
1897
2027
  // src/utils/config-root-dir.ts
1898
2028
  import os2 from "os";
1899
2029
  import path3 from "path";
@@ -1944,7 +2074,8 @@ var USER_CONFIG_SOURCE_DIR_KEYS = [
1944
2074
  "cline",
1945
2075
  "roocode",
1946
2076
  "kilocode",
1947
- "antigravity"
2077
+ "antigravity",
2078
+ "dsh"
1948
2079
  ];
1949
2080
  var knownTopLevelKeys = [
1950
2081
  "eventStore",
@@ -2003,10 +2134,10 @@ function hasConfigPathOverride(env) {
2003
2134
  function getLegacyJsonConfigPath(configPath) {
2004
2135
  return path4.join(path4.dirname(configPath), "config.json");
2005
2136
  }
2006
- async function throwIfLegacyJsonConfigExists(tomlPath, readFile8) {
2137
+ async function throwIfLegacyJsonConfigExists(tomlPath, readFile9) {
2007
2138
  const jsonPath = getLegacyJsonConfigPath(tomlPath);
2008
2139
  try {
2009
- await readFile8(jsonPath);
2140
+ await readFile9(jsonPath);
2010
2141
  } catch (error) {
2011
2142
  if (isMissingFileError(error)) {
2012
2143
  return;
@@ -2254,15 +2385,15 @@ function parseUserConfigRoot(filePath, content) {
2254
2385
  }
2255
2386
  return root;
2256
2387
  }
2257
- async function loadUserConfig(env = process.env, readFile8 = (filePath) => readFileFromFs(filePath, "utf8")) {
2388
+ async function loadUserConfig(env = process.env, readFile9 = (filePath) => readFileFromFs(filePath, "utf8")) {
2258
2389
  const configPath = resolveUserConfigPath(env);
2259
2390
  let content;
2260
2391
  try {
2261
- content = await readFile8(configPath);
2392
+ content = await readFile9(configPath);
2262
2393
  } catch (error) {
2263
2394
  if (isMissingFileError(error)) {
2264
2395
  if (!hasConfigPathOverride(env)) {
2265
- await throwIfLegacyJsonConfigExists(configPath, readFile8);
2396
+ await throwIfLegacyJsonConfigExists(configPath, readFile9);
2266
2397
  }
2267
2398
  return {
2268
2399
  config: {},
@@ -6781,16 +6912,310 @@ var DroidSourceAdapter = class {
6781
6912
  }
6782
6913
  };
6783
6914
 
6784
- // src/sources/gemini/gemini-source-adapter.ts
6785
- import { readdir as readdir2, readFile as readFile4 } from "fs/promises";
6915
+ // src/sources/dsh/dsh-source-adapter.ts
6916
+ import path17 from "path";
6917
+
6918
+ // src/sources/dsh/dsh-session-log-reader.ts
6919
+ import { readFile as readFile4 } from "fs/promises";
6920
+ import { Readable, Writable } from "stream";
6921
+ import { pipeline } from "stream/promises";
6922
+ import { createZstdDecompress } from "zlib";
6923
+ var DshSessionLogUnreadableError = class extends Error {
6924
+ constructor(message = "DSH session log could not be decompressed") {
6925
+ super(message);
6926
+ this.name = "DshSessionLogUnreadableError";
6927
+ }
6928
+ };
6929
+ var ZSTD_FRAME_MAGIC = Buffer.from([40, 181, 47, 253]);
6930
+ var UNDECODABLE_FRAME_REASON = "undecodable_jsonl_frame";
6931
+ function collectFrameSlices(compressed) {
6932
+ const frames = [];
6933
+ let damagedSlices = 0;
6934
+ let offset = 0;
6935
+ while (offset < compressed.length) {
6936
+ const nextOffset = compressed.indexOf(ZSTD_FRAME_MAGIC, offset + ZSTD_FRAME_MAGIC.length);
6937
+ const slice = nextOffset === -1 ? compressed.subarray(offset) : compressed.subarray(offset, nextOffset);
6938
+ if (slice.subarray(0, ZSTD_FRAME_MAGIC.length).equals(ZSTD_FRAME_MAGIC)) {
6939
+ frames.push(slice);
6940
+ } else {
6941
+ damagedSlices += 1;
6942
+ }
6943
+ if (nextOffset === -1) {
6944
+ break;
6945
+ }
6946
+ offset = nextOffset;
6947
+ }
6948
+ return { frames, damagedSlices };
6949
+ }
6950
+ async function decodeFrame(frameBytes) {
6951
+ const engine = createZstdDecompress();
6952
+ const chunks = [];
6953
+ await pipeline(
6954
+ Readable.from([frameBytes]),
6955
+ engine,
6956
+ new Writable({
6957
+ write(chunk, _encoding, callback) {
6958
+ chunks.push(chunk);
6959
+ callback();
6960
+ }
6961
+ })
6962
+ );
6963
+ const decoded = Buffer.concat(chunks);
6964
+ const frameConsumed = engine.bytesWritten === frameBytes.length;
6965
+ if (decoded.length === 0 || !frameConsumed) {
6966
+ throw new DshSessionLogUnreadableError("DSH session log frame is incomplete");
6967
+ }
6968
+ return decoded;
6969
+ }
6970
+ function splitJsonlLines(text) {
6971
+ const lines = [];
6972
+ for (const rawLine of text.split("\n")) {
6973
+ const line = rawLine.trim();
6974
+ if (line.length > 0) {
6975
+ lines.push(line);
6976
+ }
6977
+ }
6978
+ return lines;
6979
+ }
6980
+ async function readDshSessionLog(filePath) {
6981
+ const contents = await readFile4(filePath);
6982
+ if (!filePath.toLowerCase().endsWith(".zstd")) {
6983
+ return {
6984
+ lines: splitJsonlLines(contents.toString("utf8")),
6985
+ skippedRowReasons: []
6986
+ };
6987
+ }
6988
+ const lines = [];
6989
+ let decodedFrames = 0;
6990
+ const { frames, damagedSlices } = collectFrameSlices(contents);
6991
+ let undecodableFrames = damagedSlices;
6992
+ for (const frameBytes of frames) {
6993
+ try {
6994
+ const decoded = await decodeFrame(frameBytes);
6995
+ decodedFrames += 1;
6996
+ lines.push(...splitJsonlLines(decoded.toString("utf8")));
6997
+ } catch {
6998
+ undecodableFrames += 1;
6999
+ }
7000
+ }
7001
+ if (decodedFrames === 0) {
7002
+ throw new DshSessionLogUnreadableError();
7003
+ }
7004
+ return {
7005
+ lines,
7006
+ skippedRowReasons: undecodableFrames > 0 ? [{ reason: UNDECODABLE_FRAME_REASON, count: undecodableFrames }] : []
7007
+ };
7008
+ }
7009
+
7010
+ // src/sources/dsh/dsh-path-resolver.ts
6786
7011
  import os11 from "os";
6787
7012
  import path16 from "path";
6788
- var defaultGeminiDir = path16.join(os11.homedir(), ".gemini");
7013
+ function resolveDshHome(options) {
7014
+ const configuredHome = asTrimmedText(options.env.DSH_HOME);
7015
+ if (!configuredHome) {
7016
+ return path16.join(options.homeDir, ".dsh");
7017
+ }
7018
+ if (configuredHome === "~") {
7019
+ return options.homeDir;
7020
+ }
7021
+ if (configuredHome.startsWith("~/") || configuredHome.startsWith("~\\")) {
7022
+ return path16.join(options.homeDir, configuredHome.slice(2));
7023
+ }
7024
+ return configuredHome;
7025
+ }
7026
+ function getDefaultDshSessionsDir(options = {}) {
7027
+ const resolvedOptions = {
7028
+ env: options.env ?? process.env,
7029
+ homeDir: options.homeDir ?? os11.homedir()
7030
+ };
7031
+ return path16.join(resolveDshHome(resolvedOptions), "sessions");
7032
+ }
7033
+
7034
+ // src/sources/dsh/dsh-source-adapter.ts
7035
+ var DSH_SESSION_LOG_FILENAME_PATTERN = /^session(?:\.v[1-9][0-9]*)?\.jsonl(?:\.zstd)?$/u;
7036
+ var DSH_ASSISTANT_MESSAGE_LINE_PATTERN = /"type"\s*:\s*"assistant\/message"/u;
7037
+ var DSH_SESSION_LINE_PATTERN = /"type"\s*:\s*"session"/u;
7038
+ var DSH_TITLE_REQUEST_LINE_PATTERN = /"type"\s*:\s*"session\/title-llm-request"/u;
7039
+ function shouldParseDshJsonlLine(lineText) {
7040
+ return DSH_ASSISTANT_MESSAGE_LINE_PATTERN.test(lineText) || DSH_SESSION_LINE_PATTERN.test(lineText) || DSH_TITLE_REQUEST_LINE_PATTERN.test(lineText);
7041
+ }
7042
+ function isDshSessionLogFile(fileName) {
7043
+ return DSH_SESSION_LOG_FILENAME_PATTERN.test(fileName);
7044
+ }
7045
+ function getFallbackSessionId4(filePath) {
7046
+ const parentDirName = path17.basename(path17.dirname(filePath));
7047
+ if (parentDirName.startsWith("session-")) {
7048
+ return parentDirName;
7049
+ }
7050
+ return path17.basename(filePath).replace(/\.zstd$/u, "");
7051
+ }
7052
+ function resolveRoute(record) {
7053
+ const route = asRecord(record?.route) ?? record;
7054
+ return {
7055
+ provider: asTrimmedText(route?.provider),
7056
+ model: asTrimmedText(route?.model)
7057
+ };
7058
+ }
7059
+ function extractUsage2(usage) {
7060
+ const extracted = {
7061
+ inputTokens: toNumberLike(usage.inputTokens),
7062
+ outputTokens: toNumberLike(usage.outputTokens),
7063
+ reasoningTokens: toNumberLike(usage.reasoningTokens),
7064
+ cacheReadTokens: toNumberLike(usage.cacheReadTokens),
7065
+ cacheWriteTokens: toNumberLike(usage.cacheWriteTokens),
7066
+ totalTokens: toNumberLike(usage.totalTokens)
7067
+ };
7068
+ const usageCandidates = [
7069
+ extracted.inputTokens,
7070
+ extracted.outputTokens,
7071
+ extracted.reasoningTokens,
7072
+ extracted.cacheReadTokens,
7073
+ extracted.cacheWriteTokens,
7074
+ extracted.totalTokens
7075
+ ];
7076
+ return hasPositiveUsageOrCostSignal(usageCandidates, void 0) ? extracted : void 0;
7077
+ }
7078
+ function resolveTimestamp3(line) {
7079
+ const time = line.time;
7080
+ if (typeof time !== "number" || !Number.isFinite(time)) {
7081
+ return void 0;
7082
+ }
7083
+ const date = new Date(time);
7084
+ return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
7085
+ }
7086
+ var DshSourceAdapter = class {
7087
+ id = "dsh";
7088
+ rootDirs;
7089
+ requireDir;
7090
+ constructor(options = {}) {
7091
+ this.rootDirs = resolveRootDirs(
7092
+ options.dir,
7093
+ options.defaultRootDirs ?? [
7094
+ getDefaultDshSessionsDir({ env: options.env, homeDir: options.homeDir })
7095
+ ]
7096
+ );
7097
+ this.requireDir = options.requireDir ?? false;
7098
+ }
7099
+ async discoverFiles() {
7100
+ return discoverFilesAcrossRoots({
7101
+ rootDirs: this.rootDirs,
7102
+ requireDir: this.requireDir,
7103
+ directoryLabel: "DSH sessions directory",
7104
+ sortAcrossRoots: true,
7105
+ discoverInRoot: async (rootDir) => {
7106
+ const discovered = [
7107
+ ...await discoverFiles(rootDir, { extension: ".jsonl" }),
7108
+ ...await discoverFiles(rootDir, { extension: ".jsonl.zstd" })
7109
+ ];
7110
+ return discovered.filter((filePath) => isDshSessionLogFile(path17.basename(filePath)));
7111
+ }
7112
+ });
7113
+ }
7114
+ async parseFile(filePath) {
7115
+ const { events } = await this.parseFileWithDiagnostics(filePath);
7116
+ return events;
7117
+ }
7118
+ async parseFileWithDiagnostics(filePath) {
7119
+ const events = [];
7120
+ const skippedRowReasons = /* @__PURE__ */ new Map();
7121
+ const state = { sessionId: getFallbackSessionId4(filePath) };
7122
+ let skippedRows = 0;
7123
+ let log;
7124
+ try {
7125
+ log = await readDshSessionLog(filePath);
7126
+ } catch (error) {
7127
+ if (error instanceof DshSessionLogUnreadableError) {
7128
+ return toParseDiagnostics(events, 1, /* @__PURE__ */ new Map([["file_parse_failed", 1]]));
7129
+ }
7130
+ throw error;
7131
+ }
7132
+ for (const reasonStat of log.skippedRowReasons) {
7133
+ incrementSkippedReason(skippedRowReasons, reasonStat.reason);
7134
+ skippedRows += reasonStat.count;
7135
+ }
7136
+ for (const lineText of log.lines) {
7137
+ if (!shouldParseDshJsonlLine(lineText)) {
7138
+ continue;
7139
+ }
7140
+ let line;
7141
+ try {
7142
+ const parsedLine = asRecord(JSON.parse(lineText));
7143
+ if (!parsedLine) {
7144
+ continue;
7145
+ }
7146
+ line = parsedLine;
7147
+ } catch {
7148
+ skippedRows++;
7149
+ incrementSkippedReason(skippedRowReasons, "json_parse_error");
7150
+ continue;
7151
+ }
7152
+ if (line.type === "session") {
7153
+ state.sessionId = asTrimmedText(line.id) ?? state.sessionId;
7154
+ state.repoRoot = asTrimmedText(line.cwd) ?? state.repoRoot;
7155
+ continue;
7156
+ }
7157
+ if (line.type === "session/title-llm-request") {
7158
+ const route = resolveRoute(asRecord(line.data));
7159
+ state.provider = route.provider ?? state.provider;
7160
+ state.model = route.model ?? state.model;
7161
+ continue;
7162
+ }
7163
+ if (line.type !== "assistant/message") {
7164
+ continue;
7165
+ }
7166
+ const data = asRecord(line.data);
7167
+ const message = asRecord(data?.message);
7168
+ const usage = asRecord(data?.usage);
7169
+ if (!usage) {
7170
+ continue;
7171
+ }
7172
+ const extractedUsage = extractUsage2(usage);
7173
+ if (!extractedUsage) {
7174
+ skippedRows++;
7175
+ incrementSkippedReason(skippedRowReasons, "no_token_usage");
7176
+ continue;
7177
+ }
7178
+ const timestamp = resolveTimestamp3(line);
7179
+ if (!timestamp || !state.sessionId) {
7180
+ skippedRows++;
7181
+ incrementSkippedReason(skippedRowReasons, "invalid_timestamp");
7182
+ continue;
7183
+ }
7184
+ const source = asRecord(message?.source);
7185
+ const provider = asTrimmedText(source?.provider) ?? state.provider;
7186
+ const model = asTrimmedText(source?.model) ?? state.model;
7187
+ try {
7188
+ events.push(
7189
+ createUsageEvent({
7190
+ source: this.id,
7191
+ sessionId: state.sessionId,
7192
+ timestamp,
7193
+ repoRoot: state.repoRoot,
7194
+ provider,
7195
+ model,
7196
+ ...extractedUsage
7197
+ })
7198
+ );
7199
+ } catch {
7200
+ skippedRows++;
7201
+ incrementSkippedReason(skippedRowReasons, "event_creation_failed");
7202
+ continue;
7203
+ }
7204
+ }
7205
+ return toParseDiagnostics(events, skippedRows, skippedRowReasons);
7206
+ }
7207
+ };
7208
+
7209
+ // src/sources/gemini/gemini-source-adapter.ts
7210
+ import { readdir as readdir2, readFile as readFile5 } from "fs/promises";
7211
+ import os12 from "os";
7212
+ import path18 from "path";
7213
+ var defaultGeminiDir = path18.join(os12.homedir(), ".gemini");
6789
7214
  function resolveDefaultGeminiDir(env) {
6790
7215
  return asTrimmedText(env.GEMINI_CLI_HOME) ?? defaultGeminiDir;
6791
7216
  }
6792
7217
  function getProjectsJsonPath(geminiDir) {
6793
- return path16.join(geminiDir, "projects.json");
7218
+ return path18.join(geminiDir, "projects.json");
6794
7219
  }
6795
7220
  function parseProjectsJson(data) {
6796
7221
  const mapping = /* @__PURE__ */ new Map();
@@ -6814,7 +7239,7 @@ function parseProjectsJson(data) {
6814
7239
  async function loadProjectsJson(geminiDir) {
6815
7240
  const projectsPath = getProjectsJsonPath(geminiDir);
6816
7241
  try {
6817
- const content = await readFile4(projectsPath, "utf8");
7242
+ const content = await readFile5(projectsPath, "utf8");
6818
7243
  const parsed = JSON.parse(content);
6819
7244
  return parseProjectsJson(parsed);
6820
7245
  } catch (error) {
@@ -6825,7 +7250,7 @@ async function loadProjectsJson(geminiDir) {
6825
7250
  }
6826
7251
  }
6827
7252
  async function discoverSessionFiles(geminiDir) {
6828
- const tmpDir = path16.join(geminiDir, "tmp");
7253
+ const tmpDir = path18.join(geminiDir, "tmp");
6829
7254
  let projectEntries;
6830
7255
  try {
6831
7256
  projectEntries = await readdir2(tmpDir, { withFileTypes: true, encoding: "utf8" });
@@ -6842,7 +7267,7 @@ async function discoverSessionFiles(geminiDir) {
6842
7267
  if (!projectEntry.isDirectory() && !projectEntry.isSymbolicLink()) {
6843
7268
  continue;
6844
7269
  }
6845
- const chatsDir = path16.join(tmpDir, projectEntry.name, "chats");
7270
+ const chatsDir = path18.join(tmpDir, projectEntry.name, "chats");
6846
7271
  const discoveredChatFiles = await discoverFiles(chatsDir, { extension: ".json" });
6847
7272
  allSessionFiles.push(...discoveredChatFiles);
6848
7273
  }
@@ -6856,9 +7281,9 @@ function resolveRepoRoot(filePath, sessionData, projectMapping) {
6856
7281
  return mappedRoot;
6857
7282
  }
6858
7283
  }
6859
- const chatsDir = path16.dirname(filePath);
6860
- const projectDir = path16.dirname(chatsDir);
6861
- const projectIdentifier = path16.basename(projectDir);
7284
+ const chatsDir = path18.dirname(filePath);
7285
+ const projectDir = path18.dirname(chatsDir);
7286
+ const projectIdentifier = path18.basename(projectDir);
6862
7287
  return projectMapping.get(projectIdentifier);
6863
7288
  }
6864
7289
  function toFiniteNumber3(value) {
@@ -6967,7 +7392,7 @@ var GeminiSourceAdapter = class {
6967
7392
  incrementSkippedReason(skippedRowReasons, "invalid_session_data");
6968
7393
  return toParseDiagnostics(events, skippedRows, skippedRowReasons);
6969
7394
  }
6970
- const sessionId = asTrimmedText(sessionDataRecord.sessionId) ?? path16.basename(filePath, ".json");
7395
+ const sessionId = asTrimmedText(sessionDataRecord.sessionId) ?? path18.basename(filePath, ".json");
6971
7396
  const projectMapping = await this.getProjectMappingForParse();
6972
7397
  const repoRoot = resolveRepoRoot(filePath, sessionDataRecord, projectMapping);
6973
7398
  if (!Array.isArray(sessionDataRecord.messages)) {
@@ -7024,8 +7449,8 @@ var GeminiSourceAdapter = class {
7024
7449
  };
7025
7450
 
7026
7451
  // src/sources/goose/goose-db-path-resolver.ts
7027
- import os12 from "os";
7028
- import path17 from "path";
7452
+ import os13 from "os";
7453
+ import path19 from "path";
7029
7454
  function deduplicate(paths) {
7030
7455
  return [...new Set(paths)];
7031
7456
  }
@@ -7037,36 +7462,36 @@ function normalizeEnvPath3(value) {
7037
7462
  return normalized || void 0;
7038
7463
  }
7039
7464
  function getGooseDbPath(rootDir) {
7040
- return path17.join(rootDir, "goose", "sessions", "sessions.db");
7465
+ return path19.join(rootDir, "goose", "sessions", "sessions.db");
7041
7466
  }
7042
7467
  function getLinuxLikeCandidates(homeDir, env) {
7043
- const xdgDataHome = normalizeEnvPath3(env.XDG_DATA_HOME) ?? path17.join(homeDir, ".local", "share");
7468
+ const xdgDataHome = normalizeEnvPath3(env.XDG_DATA_HOME) ?? path19.join(homeDir, ".local", "share");
7044
7469
  return [
7045
7470
  getGooseDbPath(xdgDataHome),
7046
- path17.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7471
+ path19.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7047
7472
  ];
7048
7473
  }
7049
7474
  function getMacOsCandidates(homeDir) {
7050
7475
  return [
7051
- path17.join(homeDir, "Library", "Application Support", "goose", "sessions", "sessions.db"),
7052
- path17.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7476
+ path19.join(homeDir, "Library", "Application Support", "goose", "sessions", "sessions.db"),
7477
+ path19.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7053
7478
  ];
7054
7479
  }
7055
7480
  function getWindowsCandidates(homeDir, env) {
7056
7481
  const userProfile = normalizeEnvPath3(env.USERPROFILE);
7057
- const roamingBase = normalizeEnvPath3(env.APPDATA) ?? normalizeEnvPath3(env.LOCALAPPDATA) ?? (userProfile ? path17.join(userProfile, "AppData", "Roaming") : void 0);
7482
+ const roamingBase = normalizeEnvPath3(env.APPDATA) ?? normalizeEnvPath3(env.LOCALAPPDATA) ?? (userProfile ? path19.join(userProfile, "AppData", "Roaming") : void 0);
7058
7483
  const roamingCandidates = roamingBase ? [getGooseDbPath(roamingBase)] : [];
7059
7484
  return [
7060
7485
  ...roamingCandidates,
7061
- path17.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7486
+ path19.join(homeDir, ".local", "share", "Block", "goose", "sessions", "sessions.db")
7062
7487
  ];
7063
7488
  }
7064
7489
  function getDefaultGooseDbPathCandidates(options = {}) {
7065
7490
  const platform = options.platform ?? process.platform;
7066
- const homeDir = options.homeDir ?? os12.homedir();
7491
+ const homeDir = options.homeDir ?? os13.homedir();
7067
7492
  const env = options.env ?? process.env;
7068
7493
  const goosePathRoot = normalizeEnvPath3(env.GOOSE_PATH_ROOT);
7069
- const envCandidates = goosePathRoot ? [path17.join(goosePathRoot, "data", "sessions", "sessions.db")] : [];
7494
+ const envCandidates = goosePathRoot ? [path19.join(goosePathRoot, "data", "sessions", "sessions.db")] : [];
7070
7495
  switch (platform) {
7071
7496
  case "win32":
7072
7497
  return deduplicate([...envCandidates, ...getWindowsCandidates(homeDir, env)]);
@@ -7255,11 +7680,11 @@ var GooseSourceAdapter = class {
7255
7680
  };
7256
7681
 
7257
7682
  // src/sources/kimi/kimi-source-adapter.ts
7258
- import { readFile as readFile5 } from "fs/promises";
7259
- import os13 from "os";
7260
- import path18 from "path";
7261
- var defaultKimiCliSessionsDir = path18.join(os13.homedir(), ".kimi", "sessions");
7262
- var defaultKimiCodeSessionsDir = path18.join(os13.homedir(), ".kimi-code", "sessions");
7683
+ import { readFile as readFile6 } from "fs/promises";
7684
+ import os14 from "os";
7685
+ import path20 from "path";
7686
+ var defaultKimiCliSessionsDir = path20.join(os14.homedir(), ".kimi", "sessions");
7687
+ var defaultKimiCodeSessionsDir = path20.join(os14.homedir(), ".kimi-code", "sessions");
7263
7688
  var defaultRootDirs = [defaultKimiCliSessionsDir, defaultKimiCodeSessionsDir];
7264
7689
  var KIMI_STATUS_UPDATE_LINE_TEXT = '"StatusUpdate"';
7265
7690
  var KIMI_USAGE_RECORD_LINE_TEXT = '"usage.record"';
@@ -7306,18 +7731,18 @@ function incrementContextSkippedReason3(context, reason) {
7306
7731
  incrementSkippedReason(context.skippedRowReasons, reason);
7307
7732
  }
7308
7733
  function getCliSessionId(filePath) {
7309
- return path18.basename(path18.dirname(filePath));
7734
+ return path20.basename(path20.dirname(filePath));
7310
7735
  }
7311
7736
  function getCliConfigPath(filePath) {
7312
- const sessionsDir = path18.dirname(path18.dirname(path18.dirname(filePath)));
7313
- return path18.join(path18.dirname(sessionsDir), "config.json");
7737
+ const sessionsDir = path20.dirname(path20.dirname(path20.dirname(filePath)));
7738
+ return path20.join(path20.dirname(sessionsDir), "config.json");
7314
7739
  }
7315
7740
  function isCodeWireFile(filePath) {
7316
- return path18.basename(path18.dirname(path18.dirname(filePath))) === "agents";
7741
+ return path20.basename(path20.dirname(path20.dirname(filePath))) === "agents";
7317
7742
  }
7318
7743
  async function readCliConfigModel(filePath) {
7319
7744
  try {
7320
- const content = await readFile5(getCliConfigPath(filePath), "utf8");
7745
+ const content = await readFile6(getCliConfigPath(filePath), "utf8");
7321
7746
  return asTrimmedText(asRecord(JSON.parse(content))?.model);
7322
7747
  } catch {
7323
7748
  return void 0;
@@ -7327,10 +7752,10 @@ function getCliFallbackModel(timestamp) {
7327
7752
  return Date.parse(timestamp) < KIMI_K2_6_CUTOFF_MS ? KIMI_K2_5_MODEL : KIMI_K2_6_MODEL;
7328
7753
  }
7329
7754
  function getCodeSessionId(filePath) {
7330
- const agentDir = path18.dirname(filePath);
7331
- const agentsDir = path18.dirname(agentDir);
7332
- const sessionDir = path18.dirname(agentsDir);
7333
- return path18.basename(sessionDir);
7755
+ const agentDir = path20.dirname(filePath);
7756
+ const agentsDir = path20.dirname(agentDir);
7757
+ const sessionDir = path20.dirname(agentsDir);
7758
+ return path20.basename(sessionDir);
7334
7759
  }
7335
7760
  function normalizeKimiCodeModel(model) {
7336
7761
  const normalizedModel = asTrimmedText(model);
@@ -7431,7 +7856,7 @@ function parseUsageRecordLine(context, filePath, line) {
7431
7856
  }
7432
7857
  async function discoverWireFiles(rootDir) {
7433
7858
  const jsonlFiles = await discoverFiles(rootDir, { extension: ".jsonl" });
7434
- return jsonlFiles.filter((filePath) => path18.basename(filePath) === "wire.jsonl");
7859
+ return jsonlFiles.filter((filePath) => path20.basename(filePath) === "wire.jsonl");
7435
7860
  }
7436
7861
  var KimiSourceAdapter = class {
7437
7862
  id = "kimi";
@@ -7492,8 +7917,8 @@ var KimiSourceAdapter = class {
7492
7917
 
7493
7918
  // src/sources/opencode/opencode-db-path-resolver.ts
7494
7919
  import { readdirSync } from "fs";
7495
- import os14 from "os";
7496
- import path19 from "path";
7920
+ import os15 from "os";
7921
+ import path21 from "path";
7497
7922
  var CHANNEL_DB_FILE_PATTERN = /^opencode-.+\.db$/u;
7498
7923
  function deduplicate2(paths) {
7499
7924
  return [...new Set(paths)];
@@ -7516,34 +7941,34 @@ function listChannelDbFileNames(directory) {
7516
7941
  }
7517
7942
  function getDirectoryCandidates(directory) {
7518
7943
  return [
7519
- path19.join(directory, "opencode.db"),
7520
- ...listChannelDbFileNames(directory).map((fileName) => path19.join(directory, fileName)),
7521
- path19.join(directory, "db.sqlite")
7944
+ path21.join(directory, "opencode.db"),
7945
+ ...listChannelDbFileNames(directory).map((fileName) => path21.join(directory, fileName)),
7946
+ path21.join(directory, "db.sqlite")
7522
7947
  ];
7523
7948
  }
7524
7949
  function getLinuxLikeCandidates2(homeDir, env) {
7525
- const xdgDataHome = normalizeEnvPath4(env.XDG_DATA_HOME) ?? path19.join(homeDir, ".local", "share");
7950
+ const xdgDataHome = normalizeEnvPath4(env.XDG_DATA_HOME) ?? path21.join(homeDir, ".local", "share");
7526
7951
  return [
7527
- ...getDirectoryCandidates(path19.join(xdgDataHome, "opencode")),
7528
- ...getDirectoryCandidates(path19.join(homeDir, ".opencode"))
7952
+ ...getDirectoryCandidates(path21.join(xdgDataHome, "opencode")),
7953
+ ...getDirectoryCandidates(path21.join(homeDir, ".opencode"))
7529
7954
  ];
7530
7955
  }
7531
7956
  function getMacOsCandidates2(homeDir) {
7532
- const appSupportDir = path19.join(homeDir, "Library", "Application Support");
7957
+ const appSupportDir = path21.join(homeDir, "Library", "Application Support");
7533
7958
  return [
7534
- ...getDirectoryCandidates(path19.join(appSupportDir, "opencode")),
7535
- ...getDirectoryCandidates(path19.join(homeDir, ".opencode"))
7959
+ ...getDirectoryCandidates(path21.join(appSupportDir, "opencode")),
7960
+ ...getDirectoryCandidates(path21.join(homeDir, ".opencode"))
7536
7961
  ];
7537
7962
  }
7538
7963
  function getWindowsCandidates2(homeDir, env) {
7539
7964
  const userProfile = normalizeEnvPath4(env.USERPROFILE);
7540
- const roamingBase = normalizeEnvPath4(env.APPDATA) ?? normalizeEnvPath4(env.LOCALAPPDATA) ?? (userProfile ? path19.join(userProfile, "AppData", "Roaming") : void 0);
7541
- const roamingCandidates = roamingBase ? getDirectoryCandidates(path19.join(roamingBase, "opencode")) : [];
7542
- return [...roamingCandidates, ...getDirectoryCandidates(path19.join(homeDir, ".opencode"))];
7965
+ const roamingBase = normalizeEnvPath4(env.APPDATA) ?? normalizeEnvPath4(env.LOCALAPPDATA) ?? (userProfile ? path21.join(userProfile, "AppData", "Roaming") : void 0);
7966
+ const roamingCandidates = roamingBase ? getDirectoryCandidates(path21.join(roamingBase, "opencode")) : [];
7967
+ return [...roamingCandidates, ...getDirectoryCandidates(path21.join(homeDir, ".opencode"))];
7543
7968
  }
7544
7969
  function getDefaultOpenCodeDbPathCandidates(options = {}) {
7545
7970
  const platform = options.platform ?? process.platform;
7546
- const homeDir = options.homeDir ?? os14.homedir();
7971
+ const homeDir = options.homeDir ?? os15.homedir();
7547
7972
  const env = options.env ?? process.env;
7548
7973
  switch (platform) {
7549
7974
  case "win32":
@@ -7556,7 +7981,7 @@ function getDefaultOpenCodeDbPathCandidates(options = {}) {
7556
7981
  }
7557
7982
 
7558
7983
  // src/sources/opencode/opencode-row-parser.ts
7559
- function resolveTimestamp3(rowTimestamp, messagePayload) {
7984
+ function resolveTimestamp4(rowTimestamp, messagePayload) {
7560
7985
  const timestampCandidates = [
7561
7986
  rowTimestamp,
7562
7987
  messagePayload.timestamp,
@@ -7634,7 +8059,7 @@ function parseOpenCodeMessageRows(rows, sourceId) {
7634
8059
  if (role?.toLowerCase() !== "assistant") {
7635
8060
  continue;
7636
8061
  }
7637
- const timestamp = resolveTimestamp3(row.row_time, payload);
8062
+ const timestamp = resolveTimestamp4(row.row_time, payload);
7638
8063
  if (!timestamp) {
7639
8064
  recordSkippedRow("missing_timestamp");
7640
8065
  continue;
@@ -7979,11 +8404,11 @@ var OpenCodeSourceAdapter = class {
7979
8404
  };
7980
8405
 
7981
8406
  // src/sources/openclaw/openclaw-source-adapter.ts
7982
- import os15 from "os";
7983
- import path21 from "path";
8407
+ import os16 from "os";
8408
+ import path23 from "path";
7984
8409
 
7985
8410
  // src/sources/openclaw/openclaw-session-parser.ts
7986
- import path20 from "path";
8411
+ import path22 from "path";
7987
8412
  var SESSION_LINE_PATTERN = /"type"\s*:\s*"session"/u;
7988
8413
  var MESSAGE_LINE_PATTERN = /"type"\s*:\s*"message"/u;
7989
8414
  var MODEL_CHANGE_LINE_PATTERN = /"type"\s*:\s*"model_change"/u;
@@ -7993,8 +8418,8 @@ var PROVIDER_LINE_PATTERN = /"provider"\s*:/u;
7993
8418
  function shouldParseOpenClawJsonlLine(lineText) {
7994
8419
  return SESSION_LINE_PATTERN.test(lineText) || MESSAGE_LINE_PATTERN.test(lineText) || MODEL_CHANGE_LINE_PATTERN.test(lineText) || USAGE_LINE_PATTERN.test(lineText) || MODEL_LINE_PATTERN.test(lineText) || PROVIDER_LINE_PATTERN.test(lineText);
7995
8420
  }
7996
- function getFallbackSessionId4(filePath) {
7997
- return path20.basename(filePath, ".jsonl");
8421
+ function getFallbackSessionId5(filePath) {
8422
+ return path22.basename(filePath, ".jsonl");
7998
8423
  }
7999
8424
  function resolveRepoRootFromRecord(record) {
8000
8425
  if (!record) {
@@ -8060,14 +8485,14 @@ function mergeUsageExtracts(primary, fallback) {
8060
8485
  costUsd: primary.costUsd ?? fallback.costUsd
8061
8486
  };
8062
8487
  }
8063
- function extractUsage2(line, message) {
8488
+ function extractUsage3(line, message) {
8064
8489
  const lineUsage = asRecord(line.usage);
8065
8490
  const messageUsage = asRecord(message.usage);
8066
8491
  const extractedLineUsage = lineUsage ? extractUsageFromRecord(lineUsage) : void 0;
8067
8492
  const extractedMessageUsage = messageUsage ? extractUsageFromRecord(messageUsage) : void 0;
8068
8493
  return mergeUsageExtracts(extractedLineUsage, extractedMessageUsage);
8069
8494
  }
8070
- function resolveTimestamp4(line, message, state, fallbackTimestamp) {
8495
+ function resolveTimestamp5(line, message, state, fallbackTimestamp) {
8071
8496
  const candidates = [line.timestamp, message.timestamp, fallbackTimestamp, state.sessionTimestamp];
8072
8497
  for (const candidate of candidates) {
8073
8498
  const normalizedTimestamp = normalizeTimestampCandidate(candidate);
@@ -8103,7 +8528,7 @@ async function parseOpenClawSessionFile(sourceId, filePath) {
8103
8528
  const fileStats = await pathStat(filePath);
8104
8529
  const fallbackTimestamp = fileStats?.mtime.toISOString();
8105
8530
  const state = {
8106
- sessionId: getFallbackSessionId4(filePath)
8531
+ sessionId: getFallbackSessionId5(filePath)
8107
8532
  };
8108
8533
  for await (const line of readJsonlObjects(filePath, {
8109
8534
  shouldParseLine: shouldParseOpenClawJsonlLine,
@@ -8149,11 +8574,11 @@ async function parseOpenClawSessionFile(sourceId, filePath) {
8149
8574
  updateRuntimeStateFromRecord(state, line, message);
8150
8575
  const provider = rowProvider ?? state.provider;
8151
8576
  const model = rowModel ?? state.model;
8152
- const usage = extractUsage2(line, message);
8577
+ const usage = extractUsage3(line, message);
8153
8578
  if (!usage) {
8154
8579
  continue;
8155
8580
  }
8156
- const timestamp = resolveTimestamp4(line, message, state, fallbackTimestamp);
8581
+ const timestamp = resolveTimestamp5(line, message, state, fallbackTimestamp);
8157
8582
  if (!timestamp) {
8158
8583
  continue;
8159
8584
  }
@@ -8179,12 +8604,12 @@ async function parseOpenClawSessionFile(sourceId, filePath) {
8179
8604
  }
8180
8605
 
8181
8606
  // src/sources/openclaw/openclaw-source-adapter.ts
8182
- var defaultAgentsDir = path21.join(os15.homedir(), ".openclaw", "agents");
8607
+ var defaultAgentsDir = path23.join(os16.homedir(), ".openclaw", "agents");
8183
8608
  var defaultOpenClawRootDirs = [
8184
8609
  defaultAgentsDir,
8185
- path21.join(os15.homedir(), ".clawdbot", "agents"),
8186
- path21.join(os15.homedir(), ".moltbot", "agents"),
8187
- path21.join(os15.homedir(), ".moldbot", "agents")
8610
+ path23.join(os16.homedir(), ".clawdbot", "agents"),
8611
+ path23.join(os16.homedir(), ".moltbot", "agents"),
8612
+ path23.join(os16.homedir(), ".moldbot", "agents")
8188
8613
  ];
8189
8614
  var OpenClawSourceAdapter = class {
8190
8615
  id = "openclaw";
@@ -8214,12 +8639,12 @@ var OpenClawSourceAdapter = class {
8214
8639
  };
8215
8640
 
8216
8641
  // src/sources/pi/pi-source-adapter.ts
8217
- import os16 from "os";
8218
- import path22 from "path";
8219
- var defaultSessionsDir3 = path22.join(os16.homedir(), ".pi", "agent", "sessions");
8642
+ import os17 from "os";
8643
+ import path24 from "path";
8644
+ var defaultSessionsDir3 = path24.join(os17.homedir(), ".pi", "agent", "sessions");
8220
8645
  var defaultPiRootDirs = [
8221
8646
  defaultSessionsDir3,
8222
- path22.join(os16.homedir(), ".omp", "agent", "sessions")
8647
+ path24.join(os17.homedir(), ".omp", "agent", "sessions")
8223
8648
  ];
8224
8649
  var PI_MESSAGE_LINE_PATTERN = /"type"\s*:\s*"message"/u;
8225
8650
  var PI_SESSION_LINE_PATTERN = /"type"\s*:\s*"session"/u;
@@ -8227,7 +8652,7 @@ var PI_MODEL_CHANGE_LINE_PATTERN = /"type"\s*:\s*"model_change"/u;
8227
8652
  function shouldParsePiJsonlLine(lineText) {
8228
8653
  return PI_MESSAGE_LINE_PATTERN.test(lineText) || PI_SESSION_LINE_PATTERN.test(lineText) || PI_MODEL_CHANGE_LINE_PATTERN.test(lineText);
8229
8654
  }
8230
- function resolveTimestamp5(line, message, state) {
8655
+ function resolveTimestamp6(line, message, state) {
8231
8656
  const candidates = [line.timestamp, message?.timestamp, state.sessionTimestamp];
8232
8657
  for (const candidate of candidates) {
8233
8658
  const normalizedTimestamp = normalizeTimestampCandidate(candidate);
@@ -8260,7 +8685,7 @@ function extractUsageFromRecord2(usage) {
8260
8685
  ];
8261
8686
  return hasPositiveUsageOrCostSignal(usageCandidates, extracted.costUsd) ? extracted : void 0;
8262
8687
  }
8263
- function extractUsage3(line, message) {
8688
+ function extractUsage4(line, message) {
8264
8689
  const lineUsage = asRecord(line.usage);
8265
8690
  const messageUsage = asRecord(message?.usage);
8266
8691
  if (lineUsage) {
@@ -8274,8 +8699,8 @@ function extractUsage3(line, message) {
8274
8699
  }
8275
8700
  return extractUsageFromRecord2(messageUsage);
8276
8701
  }
8277
- function getFallbackSessionId5(filePath) {
8278
- return path22.basename(filePath, ".jsonl");
8702
+ function getFallbackSessionId6(filePath) {
8703
+ return path24.basename(filePath, ".jsonl");
8279
8704
  }
8280
8705
  function resolveRepoRootFromRecord2(record) {
8281
8706
  if (!record) {
@@ -8308,7 +8733,7 @@ var PiSourceAdapter = class {
8308
8733
  const events = [];
8309
8734
  let skippedRows = 0;
8310
8735
  const skippedRowReasons = /* @__PURE__ */ new Map();
8311
- const state = { sessionId: getFallbackSessionId5(filePath) };
8736
+ const state = { sessionId: getFallbackSessionId6(filePath) };
8312
8737
  for await (const line of readJsonlObjects(filePath, {
8313
8738
  shouldParseLine: shouldParsePiJsonlLine,
8314
8739
  onMalformedLine: () => {
@@ -8332,7 +8757,7 @@ var PiSourceAdapter = class {
8332
8757
  continue;
8333
8758
  }
8334
8759
  const message = asRecord(line.message);
8335
- const usage = extractUsage3(line, message);
8760
+ const usage = extractUsage4(line, message);
8336
8761
  if (!usage) {
8337
8762
  const hasUsageRecord = Boolean(asRecord(line.usage) ?? asRecord(message?.usage));
8338
8763
  if (hasUsageRecord) {
@@ -8342,7 +8767,7 @@ var PiSourceAdapter = class {
8342
8767
  continue;
8343
8768
  }
8344
8769
  const provider = asTrimmedText(line.provider) ?? asTrimmedText(message?.provider) ?? state.provider;
8345
- const timestamp = resolveTimestamp5(line, message, state);
8770
+ const timestamp = resolveTimestamp6(line, message, state);
8346
8771
  if (!timestamp || !state.sessionId) {
8347
8772
  skippedRows++;
8348
8773
  incrementSkippedReason(skippedRowReasons, "invalid_timestamp");
@@ -8373,9 +8798,9 @@ var PiSourceAdapter = class {
8373
8798
  };
8374
8799
 
8375
8800
  // src/sources/qwen/qwen-source-adapter.ts
8376
- import os17 from "os";
8377
- import path23 from "path";
8378
- var defaultProjectsDir = path23.join(os17.homedir(), ".qwen", "projects");
8801
+ import os18 from "os";
8802
+ import path25 from "path";
8803
+ var defaultProjectsDir = path25.join(os18.homedir(), ".qwen", "projects");
8379
8804
  var QWEN_USAGE_LINE_TEXT = '"usageMetadata"';
8380
8805
  function shouldParseQwenJsonlLine(lineText) {
8381
8806
  return lineText.includes(QWEN_USAGE_LINE_TEXT);
@@ -8409,11 +8834,11 @@ function extractTokenUsage2(usageMetadata) {
8409
8834
  }
8410
8835
  return extractedUsage;
8411
8836
  }
8412
- function getFallbackSessionId6(filePath) {
8413
- const chatsDir = path23.dirname(filePath);
8414
- const projectDir = path23.dirname(chatsDir);
8415
- const projectName = path23.basename(projectDir);
8416
- const fileStem = path23.basename(filePath, ".jsonl");
8837
+ function getFallbackSessionId7(filePath) {
8838
+ const chatsDir = path25.dirname(filePath);
8839
+ const projectDir = path25.dirname(chatsDir);
8840
+ const projectName = path25.basename(projectDir);
8841
+ const fileStem = path25.basename(filePath, ".jsonl");
8417
8842
  return `${projectName}-${fileStem}`;
8418
8843
  }
8419
8844
  var QwenSourceAdapter = class {
@@ -8448,7 +8873,7 @@ var QwenSourceAdapter = class {
8448
8873
  const events = [];
8449
8874
  let skippedRows = 0;
8450
8875
  const skippedRowReasons = /* @__PURE__ */ new Map();
8451
- const fallbackSessionId = getFallbackSessionId6(filePath);
8876
+ const fallbackSessionId = getFallbackSessionId7(filePath);
8452
8877
  for await (const line of readJsonlObjects(filePath, {
8453
8878
  shouldParseLine: shouldParseQwenJsonlLine,
8454
8879
  onMalformedLine: () => {
@@ -8517,8 +8942,8 @@ function parseSourceDirectoryOverrides(entries) {
8517
8942
  }
8518
8943
 
8519
8944
  // src/sources/create-default-adapters.ts
8520
- var dirOptions = ({ path: path30, requireExistingPath }) => ({
8521
- dir: path30,
8945
+ var dirOptions = ({ path: path32, requireExistingPath }) => ({
8946
+ dir: path32,
8522
8947
  requireDir: requireExistingPath
8523
8948
  });
8524
8949
  var sourceRegistrations = [
@@ -8567,7 +8992,7 @@ var sourceRegistrations = [
8567
8992
  flag: "--opencode-db <path>",
8568
8993
  help: "Path to OpenCode SQLite DB"
8569
8994
  },
8570
- create: ({ path: path30 }) => new OpenCodeSourceAdapter({ dbPath: path30 })
8995
+ create: ({ path: path32 }) => new OpenCodeSourceAdapter({ dbPath: path32 })
8571
8996
  },
8572
8997
  {
8573
8998
  id: "openclaw",
@@ -8607,7 +9032,7 @@ var sourceRegistrations = [
8607
9032
  format: "sqlite",
8608
9033
  supportsSourceDir: false,
8609
9034
  option: { key: "gooseDb", flag: "--goose-db <path>", help: "Path to Goose SQLite DB" },
8610
- create: ({ path: path30 }) => new GooseSourceAdapter({ dbPath: path30 })
9035
+ create: ({ path: path32 }) => new GooseSourceAdapter({ dbPath: path32 })
8611
9036
  },
8612
9037
  {
8613
9038
  id: "amp",
@@ -8681,6 +9106,17 @@ var sourceRegistrations = [
8681
9106
  help: "Path to Antigravity conversations directory"
8682
9107
  },
8683
9108
  create: (resolved) => new AntigravitySourceAdapter(dirOptions(resolved))
9109
+ },
9110
+ {
9111
+ id: "dsh",
9112
+ format: "jsonl",
9113
+ supportsSourceDir: true,
9114
+ option: {
9115
+ key: "dshDir",
9116
+ flag: "--dsh-dir <path>",
9117
+ help: "Path to DeepSeek Harness sessions directory"
9118
+ },
9119
+ create: (resolved) => new DshSourceAdapter(dirOptions(resolved))
8684
9120
  }
8685
9121
  ];
8686
9122
  var dedicatedOptionOrderIds = [
@@ -8699,7 +9135,8 @@ var dedicatedOptionOrderIds = [
8699
9135
  "cline",
8700
9136
  "roocode",
8701
9137
  "kilocode",
8702
- "antigravity"
9138
+ "antigravity",
9139
+ "dsh"
8703
9140
  ];
8704
9141
  function dedicatedFlagName(flag) {
8705
9142
  return flag.split(" ")[0];
@@ -9009,7 +9446,8 @@ var sourceDirOptionByConfigKey = {
9009
9446
  cline: "clineDir",
9010
9447
  roocode: "roocodeDir",
9011
9448
  kilocode: "kilocodeDir",
9012
- antigravity: "antigravityDir"
9449
+ antigravity: "antigravityDir",
9450
+ dsh: "dshDir"
9013
9451
  };
9014
9452
  var sourceDirConfigKeys = [
9015
9453
  "pi",
@@ -9027,7 +9465,8 @@ var sourceDirConfigKeys = [
9027
9465
  "cline",
9028
9466
  "roocode",
9029
9467
  "kilocode",
9030
- "antigravity"
9468
+ "antigravity",
9469
+ "dsh"
9031
9470
  ];
9032
9471
  function formatConfigValue(value) {
9033
9472
  if (Array.isArray(value)) {
@@ -9309,13 +9748,13 @@ function readLiveHashCounts(store) {
9309
9748
  const rows = store.database.prepare(
9310
9749
  [
9311
9750
  "SELECT events.content_hash AS content_hash, COUNT(*) AS count",
9312
- "FROM events",
9313
- "JOIN history_discovered_files AS discovered",
9314
- " ON events.source = discovered.source",
9315
- " AND events.file_path = discovered.file_path",
9751
+ "FROM history_discovered_files AS discovered",
9316
9752
  "JOIN history_selected_sources AS selected",
9317
- " ON events.source = selected.source",
9318
- "WHERE events.content_hash IS NOT NULL",
9753
+ " ON discovered.source = selected.source",
9754
+ "CROSS JOIN events",
9755
+ "WHERE events.source = discovered.source",
9756
+ " AND events.file_path = discovered.file_path",
9757
+ " AND events.content_hash IS NOT NULL",
9319
9758
  "GROUP BY events.content_hash"
9320
9759
  ].join("\n")
9321
9760
  ).all();
@@ -9391,9 +9830,9 @@ function readDepartedHashMultisets(store) {
9391
9830
  [
9392
9831
  "SELECT events.source AS source, events.file_path AS file_path,",
9393
9832
  " events.content_hash AS content_hash, COUNT(*) AS count",
9394
- "FROM events",
9395
- "JOIN history_departed_files AS departed",
9396
- " ON events.source = departed.source",
9833
+ "FROM history_departed_files AS departed",
9834
+ "CROSS JOIN events",
9835
+ "WHERE events.source = departed.source",
9397
9836
  " AND events.file_path = departed.file_path",
9398
9837
  "GROUP BY events.source, events.file_path, events.content_hash"
9399
9838
  ].join("\n")
@@ -9458,9 +9897,9 @@ function loadServedEvents(store, servedFiles) {
9458
9897
  " events.provider, events.repo_root, events.input_tokens, events.output_tokens,",
9459
9898
  " events.reasoning_tokens, events.cache_read_tokens, events.cache_write_tokens,",
9460
9899
  " events.total_tokens, events.cost_usd, events.cost_mode",
9461
- "FROM events",
9462
- "JOIN history_served_files AS served",
9463
- " ON events.source = served.source",
9900
+ "FROM history_served_files AS served",
9901
+ "CROSS JOIN events",
9902
+ "WHERE events.source = served.source",
9464
9903
  " AND events.file_path = served.file_path",
9465
9904
  "ORDER BY served.ordinal ASC, events.event_index ASC"
9466
9905
  ].join("\n")
@@ -10133,7 +10572,12 @@ async function parseAdapterEvents(adapter, maxParallelFileParsing, runWithParseB
10133
10572
  fileIndices2,
10134
10573
  (fileIndex) => resolveStoreHitOrWorkerMiss(fileIndex, missedFiles)
10135
10574
  );
10136
- missedFiles.sort((left5, right4) => left5.fileIndex - right4.fileIndex);
10575
+ missedFiles.sort((left5, right4) => {
10576
+ if (left5.byteSize !== right4.byteSize) {
10577
+ return right4.byteSize - left5.byteSize;
10578
+ }
10579
+ return left5.fileIndex - right4.fileIndex;
10580
+ });
10137
10581
  const missedBytes = missedFiles.reduce(
10138
10582
  (sum, missedFile) => sum + Math.max(0, missedFile.byteSize),
10139
10583
  0
@@ -10452,7 +10896,7 @@ function applyPricingToEvents(events, pricingSource) {
10452
10896
  }
10453
10897
 
10454
10898
  // src/pricing/pricing-override-source.ts
10455
- import { readFile as readFile6 } from "fs/promises";
10899
+ import { readFile as readFile7 } from "fs/promises";
10456
10900
  function toFiniteUsdRate(value) {
10457
10901
  if (value === null || value === void 0) {
10458
10902
  return void 0;
@@ -10508,7 +10952,7 @@ function normalizeOverrideFile(payload) {
10508
10952
  return overrides;
10509
10953
  }
10510
10954
  async function loadPricingOverrides(filePath) {
10511
- const fileContents = await readFile6(filePath, "utf8");
10955
+ const fileContents = await readFile7(filePath, "utf8");
10512
10956
  const parsed = JSON.parse(fileContents);
10513
10957
  return normalizeOverrideFile(parsed);
10514
10958
  }
@@ -10535,8 +10979,8 @@ var PricingOverrideSource = class {
10535
10979
  };
10536
10980
 
10537
10981
  // src/pricing/litellm-pricing-fetcher.ts
10538
- import { mkdir as mkdir3, readFile as readFile7, writeFile as writeFile2 } from "fs/promises";
10539
- import path24 from "path";
10982
+ import { mkdir as mkdir3, readFile as readFile8, writeFile as writeFile2 } from "fs/promises";
10983
+ import path26 from "path";
10540
10984
 
10541
10985
  // src/pricing/litellm-model-map.json
10542
10986
  var litellm_model_map_default = {
@@ -10571,10 +11015,11 @@ var litellm_model_map_default = {
10571
11015
  "anthropic/claude-sonnet-4.6": "claude-sonnet-4.6",
10572
11016
  "anthropic.claude-sonnet-4-6": "claude-sonnet-4.6"
10573
11017
  },
10574
- neverFuzzyMatch: ["kimi-for-coding"],
11018
+ neverFuzzyMatch: ["deepseek-flash", "deepseek-v4.1-flash", "kimi-for-coding"],
10575
11019
  notes: {
10576
11020
  "gpt-5.3-codex-spark": "Alias to gpt-5.3-codex because upstream publishes token pricing on the gpt-5.3-codex key",
10577
11021
  "gemini-3-flash-a": "Antigravity session data records gemini-3 models with an '-a' suffix (gemini-3-flash-a, gemini-3-pro-a); alias them to the canonical gemini-3 models",
11022
+ "deepseek-flash": "Deliberately NOT aliased: DeepSeek Harness reports its default route as deepseek-flash, which its catalog names DeepSeek-V41-Flash. LiteLLM publishes no v4.1 key (bundled snapshot or upstream main), and deepseek-v4-flash is the earlier V4 model at its own much lower rates, so any alias would silently bill V4.1 traffic at another model's prices. Fuzzy matching is blocked so the row stays visibly unpriced until a real key exists; the published V4.1 rate card is listed in site/src/content/docs/sources/dsh.mdx for use with --pricing-overrides",
10578
11023
  "kimi-for-coding": "Deliberately NOT aliased: the managed kimi-for-coding endpoint maps to kimi-k2.5 or kimi-k2.6 depending on the event timestamp. The kimi adapter resolves that fallback itself; a config-provided kimi-for-coding model stays unpriced rather than mispriced"
10579
11024
  },
10580
11025
  preferredPricingKeyByCanonicalModel: {
@@ -21817,7 +22262,7 @@ function formatBundledSnapshotWarning(fetchedAt) {
21817
22262
  return `Pricing: using the bundled LiteLLM snapshot from ${fetchedDate} (run online to refresh).`;
21818
22263
  }
21819
22264
  function getDefaultLiteLLMPricingCachePath() {
21820
- return path24.join(getUserCacheRootDir(), "llm-usage-metrics", "litellm-pricing-cache.json");
22265
+ return path26.join(getUserCacheRootDir(), "llm-usage-metrics", "litellm-pricing-cache.json");
21821
22266
  }
21822
22267
  var LiteLLMPricingFetcher = class {
21823
22268
  sourceUrl;
@@ -22027,7 +22472,7 @@ var LiteLLMPricingFetcher = class {
22027
22472
  async readCachePayload() {
22028
22473
  let content;
22029
22474
  try {
22030
- content = await readFile7(this.cacheFilePath, "utf8");
22475
+ content = await readFile8(this.cacheFilePath, "utf8");
22031
22476
  } catch {
22032
22477
  return void 0;
22033
22478
  }
@@ -22040,7 +22485,7 @@ var LiteLLMPricingFetcher = class {
22040
22485
  return normalizeLiteLLMCachePayload(parsedPayload);
22041
22486
  }
22042
22487
  async writeCache() {
22043
- const directoryPath = path24.dirname(this.cacheFilePath);
22488
+ const directoryPath = path26.dirname(this.cacheFilePath);
22044
22489
  await mkdir3(directoryPath, { recursive: true });
22045
22490
  const payload = {
22046
22491
  fetchedAt: this.now(),
@@ -23039,9 +23484,9 @@ function emitEnvVarOverrides(activeEnvOverrides, diagnosticsLogger) {
23039
23484
  import { spawn } from "child_process";
23040
23485
  import { constants as constants2 } from "fs";
23041
23486
  import { access as access2, writeFile as writeFile3 } from "fs/promises";
23042
- import path25 from "path";
23487
+ import path27 from "path";
23043
23488
  async function writeShareSvgFile(fileName, svgContent) {
23044
- const outputPath = path25.resolve(process.cwd(), fileName);
23489
+ const outputPath = path27.resolve(process.cwd(), fileName);
23045
23490
  await writeFile3(outputPath, svgContent, "utf8");
23046
23491
  return outputPath;
23047
23492
  }
@@ -23069,10 +23514,10 @@ async function resolveBinaryPath(primaryPath, fallbackNames) {
23069
23514
  if (await fileExists(primaryPath)) {
23070
23515
  return primaryPath;
23071
23516
  }
23072
- const pathDirs = (process.env.PATH ?? "").split(path25.delimiter).filter(Boolean);
23517
+ const pathDirs = (process.env.PATH ?? "").split(path27.delimiter).filter(Boolean);
23073
23518
  for (const fallbackName of fallbackNames) {
23074
23519
  for (const dir of pathDirs) {
23075
- const candidate = path25.join(dir, fallbackName);
23520
+ const candidate = path27.join(dir, fallbackName);
23076
23521
  if (await fileExists(candidate)) {
23077
23522
  return candidate;
23078
23523
  }
@@ -23943,7 +24388,7 @@ function aggregateEfficiency(options) {
23943
24388
  // src/efficiency/git-outcome-collector.ts
23944
24389
  import { spawn as spawn2 } from "child_process";
23945
24390
  import { createInterface } from "readline";
23946
- import path26 from "path";
24391
+ import path28 from "path";
23947
24392
  import { stat as stat5 } from "fs/promises";
23948
24393
  var GIT_COMMIT_MARKER = "";
23949
24394
  var SHORTSTAT_PATTERN = /(\d+)\s+files?\s+changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/u;
@@ -23963,13 +24408,13 @@ function resolveGitCommandFailureReason(result) {
23963
24408
  }
23964
24409
  function resolveRepoDir(repoDir) {
23965
24410
  if (repoDir === void 0) {
23966
- return path26.resolve(process.cwd());
24411
+ return path28.resolve(process.cwd());
23967
24412
  }
23968
24413
  const normalizedRepoDir = repoDir.trim();
23969
24414
  if (!normalizedRepoDir) {
23970
24415
  throw new Error("--repo-dir must be a non-empty path");
23971
24416
  }
23972
- return path26.resolve(normalizedRepoDir);
24417
+ return path28.resolve(normalizedRepoDir);
23973
24418
  }
23974
24419
  function getNodeErrorCode2(error) {
23975
24420
  if (typeof error !== "object" || error === null || !("code" in error)) {
@@ -24350,21 +24795,21 @@ async function collectGitOutcomes(options, deps = {}) {
24350
24795
 
24351
24796
  // src/efficiency/repo-attribution.ts
24352
24797
  import { access as access3, constants as constants3, realpath as realpath3 } from "fs/promises";
24353
- import path27 from "path";
24798
+ import path29 from "path";
24354
24799
  async function hasGitMarker(directoryPath) {
24355
24800
  try {
24356
- await access3(path27.join(directoryPath, ".git"), constants3.F_OK);
24801
+ await access3(path29.join(directoryPath, ".git"), constants3.F_OK);
24357
24802
  return true;
24358
24803
  } catch {
24359
24804
  return false;
24360
24805
  }
24361
24806
  }
24362
24807
  function normalizeComparablePath(value) {
24363
- const normalizedPath = path27.normalize(path27.resolve(value));
24808
+ const normalizedPath = path29.normalize(path29.resolve(value));
24364
24809
  return process.platform === "win32" ? normalizedPath.toLowerCase() : normalizedPath;
24365
24810
  }
24366
24811
  async function resolveComparablePath(value) {
24367
- const resolvedPath = path27.resolve(value);
24812
+ const resolvedPath = path29.resolve(value);
24368
24813
  try {
24369
24814
  return normalizeComparablePath(await realpath3(resolvedPath));
24370
24815
  } catch {
@@ -24376,12 +24821,12 @@ async function resolveRepoRootFromPathHint(pathHint) {
24376
24821
  if (!trimmedPath) {
24377
24822
  return void 0;
24378
24823
  }
24379
- let currentPath = path27.resolve(trimmedPath);
24824
+ let currentPath = path29.resolve(trimmedPath);
24380
24825
  for (; ; ) {
24381
24826
  if (await hasGitMarker(currentPath)) {
24382
24827
  return currentPath;
24383
24828
  }
24384
- const parentPath = path27.dirname(currentPath);
24829
+ const parentPath = path29.dirname(currentPath);
24385
24830
  if (parentPath === currentPath) {
24386
24831
  return void 0;
24387
24832
  }
@@ -24500,6 +24945,9 @@ function resolveScopeNote(options) {
24500
24945
  if (hasActiveTextOption(options.antigravityDir)) {
24501
24946
  activeFilters.push("--antigravity-dir");
24502
24947
  }
24948
+ if (hasActiveTextOption(options.dshDir)) {
24949
+ activeFilters.push("--dsh-dir");
24950
+ }
24503
24951
  if (hasActiveRepeatedFilter(options.sourceDir)) {
24504
24952
  activeFilters.push("--source-dir");
24505
24953
  }
@@ -25441,7 +25889,7 @@ async function runOptimizeReport(granularity, options) {
25441
25889
  }
25442
25890
 
25443
25891
  // src/render/render-session-report.ts
25444
- import path28 from "path";
25892
+ import path30 from "path";
25445
25893
  import { markdownTable as markdownTable4 } from "markdown-table";
25446
25894
 
25447
25895
  // src/render/format-duration.ts
@@ -25509,7 +25957,7 @@ function toSessionTableCells(row, options) {
25509
25957
  return [
25510
25958
  options.truncateSessionIds ? truncateSessionId(row.sessionId) : row.sessionId,
25511
25959
  row.source,
25512
- row.repoRoot ? path28.basename(row.repoRoot) : "-",
25960
+ row.repoRoot ? path30.basename(row.repoRoot) : "-",
25513
25961
  getPeriodKey(row.lastActivity, "daily", options.timezone),
25514
25962
  formatDuration(row.durationMs),
25515
25963
  formatInteger4(row.totalTokens),
@@ -25519,7 +25967,7 @@ function toSessionTableCells(row, options) {
25519
25967
  }
25520
25968
  function toRepoTableCells(row, timezone) {
25521
25969
  return [
25522
- row.repoRoot ? path28.basename(row.repoRoot) : "(no repo)",
25970
+ row.repoRoot ? path30.basename(row.repoRoot) : "(no repo)",
25523
25971
  formatInteger4(row.sessionCount),
25524
25972
  getPeriodKey(row.lastActivity, "daily", timezone),
25525
25973
  formatInteger4(row.totalTokens),
@@ -29144,7 +29592,7 @@ function createRootDescription() {
29144
29592
 
29145
29593
  // src/cli/create-config-command.ts
29146
29594
  import { access as access4, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
29147
- import path29 from "path";
29595
+ import path31 from "path";
29148
29596
  import { Command as Command2 } from "commander";
29149
29597
  var CONFIG_TEMPLATE_HEADER = `#:schema https://ayagmar.github.io/llm-usage-metrics/config-schema.json
29150
29598
  # llm-usage-metrics configuration. Uncomment a key to override its default.
@@ -29195,7 +29643,7 @@ function isExistingFileError(error) {
29195
29643
  return asRecord(error)?.code === "EEXIST";
29196
29644
  }
29197
29645
  async function writeConfigTemplate(configPath, options) {
29198
- await mkdir4(path29.dirname(configPath), { recursive: true });
29646
+ await mkdir4(path31.dirname(configPath), { recursive: true });
29199
29647
  try {
29200
29648
  await writeFile4(configPath, USER_CONFIG_TEMPLATE, {
29201
29649
  encoding: "utf8",
@@ -29347,6 +29795,10 @@ var config_schema_default = {
29347
29795
  antigravity: {
29348
29796
  description: "Default path for Antigravity conversations; maps to --antigravity-dir.",
29349
29797
  type: "string"
29798
+ },
29799
+ dsh: {
29800
+ description: "Default path for DeepSeek Harness sessions; maps to --dsh-dir.",
29801
+ type: "string"
29350
29802
  }
29351
29803
  }
29352
29804
  },
@@ -30827,11 +31279,11 @@ mainPromise.catch((error) => {
30827
31279
  });
30828
31280
  /*! Bundled license information:
30829
31281
 
30830
- smol-toml/dist/date.js:
30831
31282
  smol-toml/dist/error.js:
30832
31283
  smol-toml/dist/primitive.js:
30833
- smol-toml/dist/util.js:
31284
+ smol-toml/dist/date.js:
30834
31285
  smol-toml/dist/extract.js:
31286
+ smol-toml/dist/util.js:
30835
31287
  smol-toml/dist/struct.js:
30836
31288
  smol-toml/dist/parse.js:
30837
31289
  smol-toml/dist/stringify.js: