@hegemonart/get-design-done 1.52.0 → 1.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,133 @@
1
+ // scripts/lib/mappers/incremental-discover.d.cts — types for incremental-discover.cjs (Phase 53 DISC-01).
2
+ //
3
+ // Mirrors the .d.cts sidecar convention used by concurrency-tuner.cjs so the
4
+ // .ts explore-parallel-runner can import planIncremental without a TS7016
5
+ // implicit-any. The runtime module is dep-free CJS (it dynamic-import()s the
6
+ // .mjs batchers + the .ts fingerprint engine internally).
7
+
8
+ /** A community batch (the A-subsystem `computeBatches` shape). */
9
+ export interface Batch {
10
+ id: string;
11
+ members: string[];
12
+ mergeable: boolean;
13
+ kind: 'code' | 'token' | 'motion' | 'a11y' | 'misc';
14
+ source: 'louvain' | 'fallback' | 'subsplit' | 'merge';
15
+ }
16
+
17
+ /** A single per-node fingerprint-compare entry fed to the classifier. */
18
+ export interface CompareResult {
19
+ id: string;
20
+ type?: string;
21
+ change: 'NONE' | 'COSMETIC' | 'STRUCTURAL';
22
+ }
23
+
24
+ /** The change-classifier result (sdk/fingerprint/classify.cjs). */
25
+ export interface Classification {
26
+ action: 'SKIP' | 'PARTIAL_UPDATE' | 'ARCHITECTURE_UPDATE' | 'FULL_UPDATE';
27
+ structuralCount: number;
28
+ pct: number;
29
+ dirChanged: boolean;
30
+ majorRestructure: boolean;
31
+ affectedBatchHints: string[];
32
+ reason: string;
33
+ thresholds: { fullFileCount: number; fullPct: number; archPctMax: number };
34
+ }
35
+
36
+ /** A per-node fingerprint pair plus its node type, as persisted to the store. */
37
+ export interface StoredFingerprint {
38
+ full: string;
39
+ structural: string;
40
+ type?: string;
41
+ }
42
+
43
+ /** The neighborMap sidecar for one batch (neighbor-map.mjs shape). */
44
+ export interface NeighborMap {
45
+ batchId: string | null;
46
+ neighbors: Record<string, unknown[]>;
47
+ truncated: Record<string, { omitted: number }>;
48
+ }
49
+
50
+ /** Options bag for planIncremental. */
51
+ export interface PlanIncrementalOptions {
52
+ /** The `--full` opt-out: force a FULL re-map regardless of the classifier. */
53
+ forceFull?: boolean;
54
+ /** Forwarded to computeBatches (resolution, maxCommunitySize, configCwd, …). */
55
+ computeBatchesOpts?: unknown;
56
+ /** buildNeighborMap cap (default 50). */
57
+ neighborCap?: number;
58
+ /** Forwarded into classify's projectStats.thresholds. */
59
+ thresholds?: unknown;
60
+ /** Force the bootstrap signal off when the store had a snapshot but it was empty. */
61
+ hadPriorBaseline?: boolean;
62
+ }
63
+
64
+ /** The incremental plan returned by planIncremental. */
65
+ export interface IncrementalPlan {
66
+ action: 'SKIP' | 'PARTIAL_UPDATE' | 'ARCHITECTURE_UPDATE' | 'FULL_UPDATE';
67
+ batches: Batch[];
68
+ batchesToMap: Batch[];
69
+ neighborMaps: Record<string, NeighborMap>;
70
+ fingerprints: Record<string, StoredFingerprint>;
71
+ compareResults: CompareResult[];
72
+ classification: Classification;
73
+ method: 'louvain' | 'count-fallback';
74
+ modularity: number | null;
75
+ }
76
+
77
+ /** A DirShape derived from node-id provenance. */
78
+ export interface DirShape {
79
+ dirs: string[];
80
+ counts: Record<string, number>;
81
+ layerHist: Record<string, number>;
82
+ }
83
+
84
+ /**
85
+ * Plan an incremental discover/explore cycle: compute community batches, run the
86
+ * change classifier against the prior fingerprint snapshot, and elect which
87
+ * batches to re-map (SKIP=[], PARTIAL=affected, FULL=all). Async (it
88
+ * dynamic-import()s the .mjs batchers + the .ts fingerprint engine).
89
+ */
90
+ export function planIncremental(args: {
91
+ graph: unknown;
92
+ prevFingerprints?: unknown;
93
+ opts?: PlanIncrementalOptions;
94
+ }): Promise<IncrementalPlan>;
95
+
96
+ /** Pure batch-selection matrix: SKIP→[], FULL→all, PARTIAL/ARCH→hint intersection. */
97
+ export function selectBatches(
98
+ batches: Batch[],
99
+ action: string,
100
+ affectedBatchHints: string[],
101
+ ): Batch[];
102
+
103
+ /** Derive the current DirShape (+ totalFiles) from a graph's file-nodes. */
104
+ export function deriveDirShape(
105
+ graph: unknown,
106
+ ): DirShape & { totalFiles: number };
107
+
108
+ /** Reconstruct the prior DirShape from a prevFingerprints map (null when empty). */
109
+ export function derivePrevDirShape(
110
+ prevFingerprints: unknown,
111
+ ): DirShape | null;
112
+
113
+ /** Build current fingerprints + the compareResults change set for a graph. */
114
+ export function buildCompareResults(
115
+ graph: unknown,
116
+ prevFingerprints: unknown,
117
+ fingerprint: (input: unknown, type: string) => { full: string; structural: string },
118
+ compareFingerprints: (
119
+ a: { full: string; structural: string } | null,
120
+ b: { full: string; structural: string } | null,
121
+ ) => string,
122
+ ): { fingerprints: Record<string, StoredFingerprint>; compareResults: CompareResult[] };
123
+
124
+ /** Project one fingerprintable node into its per-type fingerprint input. */
125
+ export function projectNode(node: unknown, fpType: string, idx: unknown): unknown;
126
+
127
+ /** Build the once-per-graph relationship index used by projectNode. */
128
+ export function indexForProjection(
129
+ graph: unknown,
130
+ ): { byId: Map<string, unknown>; tokensOf: Map<string, Set<string>>; variantsOf: Map<string, Set<string>> };
131
+
132
+ /** The graph node `type` values that are independently fingerprinted. */
133
+ export const FINGERPRINTABLE: Map<string, string>;
package/sdk/cli/index.js CHANGED
@@ -527,6 +527,329 @@ var require_concurrency_tuner = __commonJS({
527
527
  }
528
528
  });
529
529
 
530
+ // scripts/lib/mappers/incremental-discover.cjs
531
+ var require_incremental_discover = __commonJS({
532
+ "scripts/lib/mappers/incremental-discover.cjs"(exports2, module2) {
533
+ "use strict";
534
+ var path = require("node:path");
535
+ var fs = require("node:fs");
536
+ var { pathToFileURL } = require("node:url");
537
+ function pkgRoot() {
538
+ let dir = __dirname;
539
+ for (let i = 0; i < 10; i += 1) {
540
+ if (fs.existsSync(path.join(dir, "package.json"))) return dir;
541
+ const parent = path.dirname(dir);
542
+ if (parent === dir) break;
543
+ dir = parent;
544
+ }
545
+ return process.cwd();
546
+ }
547
+ var ROOT = pkgRoot();
548
+ var MAPPERS_DIR = path.join(ROOT, "scripts", "lib", "mappers");
549
+ var SDK_FP_DIR = path.join(ROOT, "sdk", "fingerprint");
550
+ var _classify = null;
551
+ function classify(...args) {
552
+ if (!_classify) _classify = require(path.join(SDK_FP_DIR, "classify.cjs")).classify;
553
+ return _classify(...args);
554
+ }
555
+ var _batchMod = null;
556
+ var _neighborMod = null;
557
+ var _fpMod = null;
558
+ async function loadBatchMod() {
559
+ if (!_batchMod) {
560
+ _batchMod = await import(pathToFileURL(path.join(MAPPERS_DIR, "compute-batches.mjs")).href);
561
+ }
562
+ return _batchMod;
563
+ }
564
+ async function loadNeighborMod() {
565
+ if (!_neighborMod) {
566
+ _neighborMod = await import(pathToFileURL(path.join(MAPPERS_DIR, "neighbor-map.mjs")).href);
567
+ }
568
+ return _neighborMod;
569
+ }
570
+ async function loadFingerprintMod() {
571
+ if (!_fpMod) {
572
+ _fpMod = await import(pathToFileURL(path.join(SDK_FP_DIR, "index.ts")).href);
573
+ }
574
+ return _fpMod;
575
+ }
576
+ function nodeList(graph) {
577
+ return Array.isArray(graph && graph.nodes) ? graph.nodes : [];
578
+ }
579
+ function edgeList(graph) {
580
+ return Array.isArray(graph && graph.edges) ? graph.edges : [];
581
+ }
582
+ var STRUCTURAL_EDGE_TYPES = /* @__PURE__ */ new Set([
583
+ "composes",
584
+ "extends",
585
+ "depends-on",
586
+ "consumes-context",
587
+ "provides-context"
588
+ ]);
589
+ var FINGERPRINTABLE = /* @__PURE__ */ new Map([
590
+ ["component", "component"],
591
+ ["token", "token"],
592
+ ["motion-fragment", "motion"]
593
+ ]);
594
+ function indexForProjection(graph) {
595
+ const byId = /* @__PURE__ */ new Map();
596
+ for (const n of nodeList(graph)) {
597
+ if (n && typeof n.id === "string") byId.set(n.id, n);
598
+ }
599
+ const tokensOf = /* @__PURE__ */ new Map();
600
+ const variantsOf = /* @__PURE__ */ new Map();
601
+ const ensure = (map, id) => {
602
+ let s = map.get(id);
603
+ if (!s) {
604
+ s = /* @__PURE__ */ new Set();
605
+ map.set(id, s);
606
+ }
607
+ return s;
608
+ };
609
+ const typeOf = (id) => byId.get(id) && byId.get(id).type;
610
+ const nameOf = (id) => {
611
+ const node = byId.get(id);
612
+ return node && typeof node.name === "string" ? node.name : id;
613
+ };
614
+ for (const e of edgeList(graph)) {
615
+ if (!e || typeof e.source !== "string" || typeof e.target !== "string") continue;
616
+ const sType = typeOf(e.source);
617
+ const tType = typeOf(e.target);
618
+ if (e.type === "uses-token") {
619
+ if (sType === "component" && tType === "token") ensure(tokensOf, e.source).add(e.target);
620
+ else if (tType === "component" && sType === "token") ensure(tokensOf, e.target).add(e.source);
621
+ } else if (e.type === "extends") {
622
+ if (tType === "component" && (sType === "variant" || sType === "state")) {
623
+ ensure(variantsOf, e.target).add(nameOf(e.source));
624
+ } else if (sType === "component" && (tType === "variant" || tType === "state")) {
625
+ ensure(variantsOf, e.source).add(nameOf(e.target));
626
+ }
627
+ } else if (STRUCTURAL_EDGE_TYPES.has(e.type)) {
628
+ if (sType === "component" && tType === "state") ensure(variantsOf, e.source).add(nameOf(e.target));
629
+ else if (tType === "component" && sType === "state") ensure(variantsOf, e.target).add(nameOf(e.source));
630
+ }
631
+ }
632
+ return { byId, tokensOf, variantsOf };
633
+ }
634
+ function strArray(v) {
635
+ if (!Array.isArray(v)) return [];
636
+ const out = [];
637
+ const seen = /* @__PURE__ */ new Set();
638
+ for (const x of v) {
639
+ const s = typeof x === "string" ? x : x && typeof x.name === "string" ? x.name : null;
640
+ if (s != null && !seen.has(s)) {
641
+ seen.add(s);
642
+ out.push(s);
643
+ }
644
+ }
645
+ out.sort();
646
+ return out;
647
+ }
648
+ function propShape(props) {
649
+ if (!Array.isArray(props)) return [];
650
+ const out = [];
651
+ for (const p of props) {
652
+ if (typeof p === "string") {
653
+ out.push({ name: p, type: "" });
654
+ } else if (p && typeof p === "object" && typeof p.name === "string") {
655
+ out.push({
656
+ name: p.name,
657
+ type: typeof p.type === "string" ? p.type : "",
658
+ ...typeof p.optional === "boolean" ? { optional: p.optional } : {}
659
+ });
660
+ }
661
+ }
662
+ return out;
663
+ }
664
+ function projectNode(node, fpType, idx) {
665
+ if (fpType === "component") {
666
+ const usedTokens = idx.tokensOf.has(node.id) ? [...idx.tokensOf.get(node.id)].sort() : [];
667
+ const variantsFromGraph = idx.variantsOf.has(node.id) ? [...idx.variantsOf.get(node.id)] : [];
668
+ const variantsFromNode = strArray(node.exported_variants || node.variants);
669
+ const exportedVariants = [.../* @__PURE__ */ new Set([...variantsFromGraph, ...variantsFromNode])].sort();
670
+ return {
671
+ component_signature: {
672
+ name: typeof node.name === "string" ? node.name : node.id,
673
+ members: strArray(node.members)
674
+ },
675
+ props_shape: propShape(node.props),
676
+ used_tokens: usedTokens,
677
+ exported_variants: exportedVariants
678
+ };
679
+ }
680
+ if (fpType === "token") {
681
+ return {
682
+ token_name: typeof node.name === "string" ? node.name : node.id,
683
+ token_value: node.value === void 0 ? null : typeof node.value === "object" ? JSON.stringify(node.value) : node.value,
684
+ token_type: typeof node.subtype === "string" ? node.subtype : typeof node.token_type === "string" ? node.token_type : "",
685
+ ...typeof node.subtype === "string" ? { subtype: node.subtype } : {},
686
+ ...typeof node.theme_scope === "string" ? { theme_scope: node.theme_scope } : {}
687
+ };
688
+ }
689
+ return {
690
+ animation_target: typeof node.name === "string" ? node.name : node.id,
691
+ ...Number.isFinite(node.duration_ms) ? { duration_ms: node.duration_ms } : {},
692
+ ...typeof node.easing === "string" ? { easing: node.easing } : {}
693
+ };
694
+ }
695
+ function idNamespace(id) {
696
+ if (typeof id !== "string") return "unknown";
697
+ const i = id.indexOf(":");
698
+ return i > 0 ? id.slice(0, i) : id;
699
+ }
700
+ function isFileNode(node) {
701
+ return !!node && FINGERPRINTABLE.has(node.type);
702
+ }
703
+ function deriveDirShape(graph) {
704
+ const counts = {};
705
+ const layerHist = {};
706
+ let totalFiles = 0;
707
+ for (const n of nodeList(graph)) {
708
+ if (!isFileNode(n)) continue;
709
+ totalFiles += 1;
710
+ const ns = idNamespace(n.id);
711
+ let dir = ns;
712
+ if (n.type === "token" && typeof n.subtype === "string" && n.subtype.length) {
713
+ dir = `token:${n.subtype}`;
714
+ }
715
+ counts[dir] = (counts[dir] || 0) + 1;
716
+ layerHist[ns] = (layerHist[ns] || 0) + 1;
717
+ }
718
+ const dirs = Object.keys(counts).sort();
719
+ return { dirs, counts, layerHist, totalFiles };
720
+ }
721
+ function derivePrevDirShape(prevFingerprints) {
722
+ const fps = prevFingerprints && typeof prevFingerprints === "object" ? prevFingerprints : {};
723
+ const ids = Object.keys(fps);
724
+ if (ids.length === 0) return null;
725
+ const counts = {};
726
+ const layerHist = {};
727
+ for (const id of ids) {
728
+ const ns = idNamespace(id);
729
+ let dir = ns;
730
+ if (ns === "token") {
731
+ const parts = id.split(":");
732
+ if (parts.length >= 3 && parts[1]) dir = `token:${parts[1]}`;
733
+ }
734
+ counts[dir] = (counts[dir] || 0) + 1;
735
+ layerHist[ns] = (layerHist[ns] || 0) + 1;
736
+ }
737
+ return { dirs: Object.keys(counts).sort(), counts, layerHist };
738
+ }
739
+ function asFingerprint(v) {
740
+ if (v == null) return null;
741
+ if (typeof v === "string") return { full: v, structural: v };
742
+ if (typeof v === "object" && typeof v.full === "string") {
743
+ return { full: v.full, structural: typeof v.structural === "string" ? v.structural : v.full };
744
+ }
745
+ return null;
746
+ }
747
+ function buildCompareResults(graph, prevFingerprints, fingerprint, compareFingerprints) {
748
+ const idx = indexForProjection(graph);
749
+ const prev = prevFingerprints && typeof prevFingerprints === "object" ? prevFingerprints : {};
750
+ const fingerprints = {};
751
+ const compareResults = [];
752
+ const currentIds = /* @__PURE__ */ new Set();
753
+ for (const node of nodeList(graph)) {
754
+ if (!node || typeof node.id !== "string") continue;
755
+ const fpType = FINGERPRINTABLE.get(node.type);
756
+ if (!fpType) continue;
757
+ currentIds.add(node.id);
758
+ let fp;
759
+ try {
760
+ fp = fingerprint(projectNode(node, fpType, idx), fpType);
761
+ } catch {
762
+ compareResults.push({ id: node.id, type: node.type, change: "STRUCTURAL" });
763
+ continue;
764
+ }
765
+ fingerprints[node.id] = { full: fp.full, structural: fp.structural, type: node.type };
766
+ const before = asFingerprint(prev[node.id]);
767
+ const change = compareFingerprints(before, { full: fp.full, structural: fp.structural });
768
+ compareResults.push({ id: node.id, type: node.type, change });
769
+ }
770
+ for (const id of Object.keys(prev)) {
771
+ if (currentIds.has(id)) continue;
772
+ const before = asFingerprint(prev[id]);
773
+ const change = compareFingerprints(before, null);
774
+ const t = prev[id] && typeof prev[id] === "object" && typeof prev[id].type === "string" ? prev[id].type : idNamespace(id);
775
+ compareResults.push({ id, type: t, change });
776
+ }
777
+ return { fingerprints, compareResults };
778
+ }
779
+ function selectBatches(batches, action, affectedBatchHints) {
780
+ const all = Array.isArray(batches) ? batches : [];
781
+ if (action === "SKIP") return [];
782
+ if (action === "FULL_UPDATE") return all.slice();
783
+ const hints = new Set(Array.isArray(affectedBatchHints) ? affectedBatchHints : []);
784
+ if (hints.size === 0) return [];
785
+ const out = [];
786
+ for (const b of all) {
787
+ const members = Array.isArray(b && b.members) ? b.members : [];
788
+ if (members.some((m) => hints.has(m))) out.push(b);
789
+ }
790
+ return out;
791
+ }
792
+ async function planIncremental2(args) {
793
+ const { graph, prevFingerprints, opts } = args && typeof args === "object" ? args : {};
794
+ const o = opts && typeof opts === "object" ? opts : {};
795
+ const prev = prevFingerprints && typeof prevFingerprints === "object" ? prevFingerprints : {};
796
+ const { computeBatches } = await loadBatchMod();
797
+ const { batches, modularity, method } = computeBatches(graph, o.computeBatchesOpts);
798
+ const { fingerprint, compareFingerprints } = await loadFingerprintMod();
799
+ const { fingerprints, compareResults } = buildCompareResults(
800
+ graph,
801
+ prev,
802
+ fingerprint,
803
+ compareFingerprints
804
+ );
805
+ const currDirShape = deriveDirShape(graph);
806
+ let prevDirShape = derivePrevDirShape(prev);
807
+ if (o.hadPriorBaseline === false) prevDirShape = null;
808
+ const projectStats = {
809
+ totalFiles: currDirShape.totalFiles,
810
+ prevDirShape,
811
+ currDirShape: { dirs: currDirShape.dirs, counts: currDirShape.counts, layerHist: currDirShape.layerHist },
812
+ ...o.thresholds && typeof o.thresholds === "object" ? { thresholds: o.thresholds } : {}
813
+ };
814
+ const classification = classify(compareResults, projectStats);
815
+ const effectiveAction = o.forceFull ? "FULL_UPDATE" : classification.action;
816
+ const batchesToMap = selectBatches(batches, effectiveAction, classification.affectedBatchHints);
817
+ const neighborMaps = {};
818
+ if (batchesToMap.length > 0) {
819
+ const { buildNeighborMap } = await loadNeighborMod();
820
+ const cap = Number.isInteger(o.neighborCap) && o.neighborCap >= 0 ? o.neighborCap : 50;
821
+ for (const b of batchesToMap) {
822
+ if (b && typeof b.id === "string") {
823
+ neighborMaps[b.id] = buildNeighborMap(b, graph, { cap });
824
+ }
825
+ }
826
+ }
827
+ return {
828
+ action: effectiveAction,
829
+ batches,
830
+ batchesToMap,
831
+ neighborMaps,
832
+ fingerprints,
833
+ compareResults,
834
+ classification,
835
+ method,
836
+ modularity
837
+ };
838
+ }
839
+ module2.exports = {
840
+ planIncremental: planIncremental2,
841
+ // exported for the wiring layer + tests (pure helpers, no side effects).
842
+ selectBatches,
843
+ deriveDirShape,
844
+ derivePrevDirShape,
845
+ buildCompareResults,
846
+ projectNode,
847
+ indexForProjection,
848
+ FINGERPRINTABLE
849
+ };
850
+ }
851
+ });
852
+
530
853
  // sdk/cli/index.ts
531
854
  var index_exports = {};
532
855
  __export(index_exports, {
@@ -5560,6 +5883,7 @@ var import_node_path14 = require("node:path");
5560
5883
  // scripts/lib/explore-parallel-runner/index.ts
5561
5884
  var import_node_path12 = require("node:path");
5562
5885
  var import_concurrency_tuner = __toESM(require_concurrency_tuner());
5886
+ var import_incremental_discover = __toESM(require_incremental_discover());
5563
5887
 
5564
5888
  // scripts/lib/explore-parallel-runner/mappers.ts
5565
5889
  var import_node_fs12 = require("node:fs");
@@ -5903,6 +6227,47 @@ async function run3(opts) {
5903
6227
  const concurrency = opts.concurrency ?? (0, import_concurrency_tuner.resolveConcurrency)();
5904
6228
  const logger = getLogger().child("explore.runner");
5905
6229
  const outputPath = (0, import_node_path12.resolve)(cwd, ".design/DESIGN-PATTERNS.md");
6230
+ let batching = void 0;
6231
+ if (opts.incremental && opts.incremental.graph !== void 0 && opts.incremental.graph !== null) {
6232
+ try {
6233
+ const plan = await (0, import_incremental_discover.planIncremental)({
6234
+ graph: opts.incremental.graph,
6235
+ prevFingerprints: opts.incremental.prevFingerprints,
6236
+ opts: {
6237
+ ...opts.incremental.forceFull !== void 0 ? { forceFull: opts.incremental.forceFull } : {},
6238
+ ...opts.incremental.computeBatchesOpts !== void 0 ? { computeBatchesOpts: opts.incremental.computeBatchesOpts } : {},
6239
+ ...opts.incremental.neighborCap !== void 0 ? { neighborCap: opts.incremental.neighborCap } : {},
6240
+ ...opts.incremental.thresholds !== void 0 ? { thresholds: opts.incremental.thresholds } : {}
6241
+ }
6242
+ });
6243
+ batching = Object.freeze({
6244
+ action: plan.action,
6245
+ method: plan.method,
6246
+ modularity: plan.modularity,
6247
+ batches: Object.freeze(plan.batches.map((b) => Object.freeze({
6248
+ id: b.id,
6249
+ members: Object.freeze([...b.members]),
6250
+ mergeable: b.mergeable,
6251
+ kind: b.kind,
6252
+ source: b.source
6253
+ }))),
6254
+ batchesToMap: Object.freeze(plan.batchesToMap.map((b) => b.id)),
6255
+ neighborMaps: Object.freeze({ ...plan.neighborMaps }),
6256
+ classification: Object.freeze({ ...plan.classification })
6257
+ });
6258
+ logger.info("explore.runner.batching", {
6259
+ action: plan.action,
6260
+ method: plan.method,
6261
+ batch_count: plan.batches.length,
6262
+ batches_to_map: plan.batchesToMap.length,
6263
+ structural_count: plan.classification.structuralCount
6264
+ });
6265
+ } catch (err) {
6266
+ const message = err instanceof Error ? err.message : String(err);
6267
+ logger.warn("explore.runner.batching_failed", { message });
6268
+ batching = void 0;
6269
+ }
6270
+ }
5906
6271
  logger.info("explore.runner.started", {
5907
6272
  mapper_count: specs.length,
5908
6273
  concurrency
@@ -5924,7 +6289,8 @@ async function run3(opts) {
5924
6289
  }),
5925
6290
  parallel_count: 0,
5926
6291
  serial_count: 0,
5927
- total_usage: { input_tokens: 0, output_tokens: 0, usd_cost: 0 }
6292
+ total_usage: { input_tokens: 0, output_tokens: 0, usd_cost: 0 },
6293
+ ...batching !== void 0 ? { batching } : {}
5928
6294
  });
5929
6295
  }
5930
6296
  const safeSpecs = [];
@@ -6040,7 +6406,8 @@ async function run3(opts) {
6040
6406
  input_tokens: totalInput,
6041
6407
  output_tokens: totalOutput,
6042
6408
  usd_cost: totalCost
6043
- }
6409
+ },
6410
+ ...batching !== void 0 ? { batching } : {}
6044
6411
  });
6045
6412
  }
6046
6413