bitfab 0.61.1 → 0.61.3

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 (42) hide show
  1. package/dist/autoTrace.cjs.map +1 -1
  2. package/dist/autoTrace.d.cts +1 -0
  3. package/dist/autoTrace.d.ts +1 -0
  4. package/dist/autoTrace.js +1 -1
  5. package/dist/{chunk-HKUHPLAM.js → chunk-6IMUONDN.js} +47 -3
  6. package/dist/chunk-6IMUONDN.js.map +1 -0
  7. package/dist/{chunk-I5J2FDKH.js → chunk-HVEZHLVQ.js} +46 -3
  8. package/dist/chunk-HVEZHLVQ.js.map +1 -0
  9. package/dist/{chunk-VKGLQL7V.js → chunk-IZUZ5NBB.js} +473 -51
  10. package/dist/chunk-IZUZ5NBB.js.map +1 -0
  11. package/dist/{chunk-BMJNDIVA.js → chunk-K4XCWQBC.js} +1 -1
  12. package/dist/chunk-K4XCWQBC.js.map +1 -0
  13. package/dist/{chunk-ENHRFXCR.js → chunk-PAUXHTNF.js} +38 -7
  14. package/dist/chunk-PAUXHTNF.js.map +1 -0
  15. package/dist/{chunk-S4WE6U2Y.js → chunk-WOHIAKZF.js} +122 -52
  16. package/dist/chunk-WOHIAKZF.js.map +1 -0
  17. package/dist/{http-5DA23DKC.js → http-3IYU5Z54.js} +2 -2
  18. package/dist/{http-NY6M2AK3.js → http-BYICBOWP.js} +2 -2
  19. package/dist/index.cjs +563 -52
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +146 -3
  22. package/dist/index.d.ts +146 -3
  23. package/dist/index.js +4 -4
  24. package/dist/node.cjs +563 -52
  25. package/dist/node.cjs.map +1 -1
  26. package/dist/node.d.cts +1 -1
  27. package/dist/node.d.ts +1 -1
  28. package/dist/node.js +4 -4
  29. package/dist/{replay-KVENJRCX.js → replay-SXHX5BBU.js} +3 -3
  30. package/dist/replayCli.js +4 -3
  31. package/dist/replayCli.js.map +1 -1
  32. package/dist/seedCli.js +2 -2
  33. package/package.json +1 -1
  34. package/dist/chunk-BMJNDIVA.js.map +0 -1
  35. package/dist/chunk-ENHRFXCR.js.map +0 -1
  36. package/dist/chunk-HKUHPLAM.js.map +0 -1
  37. package/dist/chunk-I5J2FDKH.js.map +0 -1
  38. package/dist/chunk-S4WE6U2Y.js.map +0 -1
  39. package/dist/chunk-VKGLQL7V.js.map +0 -1
  40. /package/dist/{http-5DA23DKC.js.map → http-3IYU5Z54.js.map} +0 -0
  41. /package/dist/{http-NY6M2AK3.js.map → http-BYICBOWP.js.map} +0 -0
  42. /package/dist/{replay-KVENJRCX.js.map → replay-SXHX5BBU.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BitfabError
3
- } from "./chunk-I5J2FDKH.js";
3
+ } from "./chunk-HVEZHLVQ.js";
4
4
 
5
5
  // src/codeChange.ts
6
6
  var NUL = String.fromCharCode(0);
@@ -81,18 +81,39 @@ var VALUE_FLAGS = /* @__PURE__ */ new Set([
81
81
  "--grader-ids",
82
82
  "--mock",
83
83
  "--param",
84
- "--params"
84
+ "--params",
85
+ "--resume"
85
86
  ]);
86
87
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
87
88
  "--only-with-assertions",
88
89
  "--db-branch",
89
90
  "--no-db-branch",
90
91
  "--no-code-change",
91
- "--dry-run"
92
+ "--dry-run",
93
+ "--force"
92
94
  ]);
93
95
  var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
94
96
  var MAX_ATTEMPTS = 100;
95
97
  var MAX_PINNED_TRACE_IDS = 100;
98
+ var RESUME_CONFLICTING_FLAGS = [
99
+ ["traceIds", "--trace-ids"],
100
+ ["datasetIds", "--dataset-ids"],
101
+ ["limit", "--limit"],
102
+ ["attempts", "--attempts"],
103
+ ["graderIds", "--grader-ids"],
104
+ ["onlyWithAssertions", "--only-with-assertions"],
105
+ ["dryRun", "--dry-run"]
106
+ ];
107
+ var RESUME_CLEARED_OPTIONS = {
108
+ traceIds: void 0,
109
+ limit: void 0,
110
+ datasetId: void 0,
111
+ datasetIds: void 0,
112
+ attempts: void 0,
113
+ graderIds: void 0,
114
+ onlyWithAssertions: void 0,
115
+ dryRun: void 0
116
+ };
96
117
  function hasApprovedAssertion(assertions) {
97
118
  return assertions.some((assertion) => assertion.approvalState === "approved");
98
119
  }
@@ -156,6 +177,8 @@ Options:
156
177
  --mock none|all|marked
157
178
  --db-branch, --no-db-branch
158
179
  --dry-run (resolve inputs, run nothing)
180
+ --resume EXPERIMENT_ID (finish an experiment that stopped partway, running only the items it did not finish, with the traces, attempts, and graders it started with)
181
+ --force (with --resume, resume even when the experiment may still be running or the code changed since it started)
159
182
  --params PATH
160
183
  --param name=value (repeatable)
161
184
  -h, --help`;
@@ -236,7 +259,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
236
259
  sessionId: seedCase.sessionId
237
260
  })
238
261
  );
239
- const { flushTraces: flushTraces2 } = await import("./http-NY6M2AK3.js");
262
+ const { flushTraces: flushTraces2 } = await import("./http-BYICBOWP.js");
240
263
  await flushTraces2(3e4);
241
264
  return { pipeline, traceFunctionKey, traceIds };
242
265
  }
@@ -356,6 +379,9 @@ function parseReplayCliArgs(registry, argv) {
356
379
  case "--dry-run":
357
380
  parsed.dryRun = true;
358
381
  break;
382
+ case "--force":
383
+ parsed.force = true;
384
+ break;
359
385
  }
360
386
  continue;
361
387
  }
@@ -414,6 +440,22 @@ ${usage(registry)}`
414
440
  case "--param":
415
441
  parsed.params.push(raw);
416
442
  break;
443
+ case "--resume":
444
+ parsed.resume = raw;
445
+ break;
446
+ }
447
+ }
448
+ if (parsed.force === true && parsed.resume === void 0) {
449
+ throw new BitfabError("--force only applies with --resume <experimentId>.");
450
+ }
451
+ if (parsed.resume !== void 0) {
452
+ const conflicting = RESUME_CONFLICTING_FLAGS.filter(
453
+ ([key]) => parsed[key] !== void 0
454
+ ).map(([, flag]) => flag);
455
+ if (conflicting.length > 0) {
456
+ throw new BitfabError(
457
+ `--resume reuses the traces, attempts, and graders experiment ${parsed.resume} started with, so it cannot be combined with ${conflicting.join(", ")}.`
458
+ );
417
459
  }
418
460
  }
419
461
  if (parsed.traceIds !== void 0 && parsed.datasetIds !== void 0) {
@@ -525,7 +567,12 @@ function renderSummary(pipeline, result, stderr) {
525
567
  let matched = 0;
526
568
  let missed = 0;
527
569
  let errors = 0;
570
+ let carriedOver = 0;
528
571
  for (const item of result.items) {
572
+ if (item.carriedOver === true) {
573
+ carriedOver += 1;
574
+ continue;
575
+ }
529
576
  if (item.error !== null) {
530
577
  errors += 1;
531
578
  continue;
@@ -545,7 +592,10 @@ function renderSummary(pipeline, result, stderr) {
545
592
  }
546
593
  stderr("\n\u2500\u2500\u2500 Summary \u2500\u2500\u2500");
547
594
  stderr(` Pipeline: ${pipeline}`);
548
- stderr(` Replayed: ${result.items.length}`);
595
+ stderr(` Replayed: ${result.items.length - carriedOver}`);
596
+ if (carriedOver > 0) {
597
+ stderr(` Carried over from the earlier run: ${carriedOver}`);
598
+ }
549
599
  if (result.attempts > 1) {
550
600
  stderr(` Attempts: ${result.attempts}`);
551
601
  }
@@ -582,6 +632,9 @@ function safeJson(value) {
582
632
  return String(value);
583
633
  }
584
634
  }
635
+ function resumeCommand(registryPath, pipeline, experimentId) {
636
+ return `Resume with: bitfab-replay --registry ${registryPath ?? "<path>"} ${pipeline} --resume ${experimentId}`;
637
+ }
585
638
  function reportReplayError(error, stderr) {
586
639
  for (const item of error.items) {
587
640
  stderr(
@@ -589,7 +642,7 @@ function reportReplayError(error, stderr) {
589
642
  );
590
643
  }
591
644
  }
592
- async function runReplayCli(registry, argv = typeof process === "undefined" ? [] : process.argv.slice(2), io = {}) {
645
+ async function runReplayCli(registry, argv = typeof process === "undefined" ? [] : process.argv.slice(2), io = {}, registryPath) {
593
646
  const stdout = io.stdout ?? console.log;
594
647
  const stderr = io.stderr ?? console.error;
595
648
  const args = parseReplayCliArgs(registry, argv);
@@ -610,6 +663,7 @@ async function runReplayCli(registry, argv = typeof process === "undefined" ? []
610
663
  }
611
664
  const selectedDatasetIds = args.datasetIds ?? registrationDatasetIds;
612
665
  const codeChange = await loadCodeChange(args.codeChangePath, readFile);
666
+ let startedExperimentId;
613
667
  const options = {
614
668
  ...registrationOptions,
615
669
  ...args.name === void 0 ? {} : { name: args.name },
@@ -633,69 +687,85 @@ async function runReplayCli(registry, argv = typeof process === "undefined" ? []
633
687
  onItemStart: reportReplayProgress,
634
688
  onItemFinish: reportReplayProgress,
635
689
  onExperimentStart: ({ experimentId, experimentUrl }) => {
690
+ startedExperimentId = experimentId;
636
691
  stderr(`[replay] Experiment ${experimentId}: ${experimentUrl}`);
637
692
  }
638
693
  };
639
- if (args.traceIds !== void 0) {
640
- options.traceIds = args.traceIds;
641
- options.datasetIds = void 0;
642
- } else if (args.datasetIds !== void 0) {
643
- options.traceIds = void 0;
644
- }
645
- const bound = args.limit ?? registrationOptions.limit;
646
- options.limit = void 0;
647
- if (options.traceIds !== void 0) {
648
- if (bound !== void 0) {
649
- options.traceIds = await boundTraceIds(
650
- registration.client,
651
- options.traceIds,
652
- bound,
653
- options.onlyWithAssertions === true
654
- );
694
+ if (args.resume !== void 0) {
695
+ Object.assign(options, RESUME_CLEARED_OPTIONS, {
696
+ resume: args.resume,
697
+ ...args.force === true ? { force: true } : {}
698
+ });
699
+ stderr(
700
+ `[replay] Resuming experiment ${args.resume} of "${traceFunctionKey}"...`
701
+ );
702
+ } else {
703
+ if (args.traceIds !== void 0) {
704
+ options.traceIds = args.traceIds;
705
+ options.datasetIds = void 0;
706
+ } else if (args.datasetIds !== void 0) {
707
+ options.traceIds = void 0;
655
708
  }
656
- } else if (options.datasetIds !== void 0) {
657
- if (bound !== void 0) {
658
- const pinned = await pinnedDatasetMembers(
659
- registration.client,
660
- options.datasetIds,
661
- bound,
662
- options.onlyWithAssertions === true
663
- );
664
- if (pinned !== void 0) {
665
- options.traceIds = pinned;
709
+ const bound = args.limit ?? registrationOptions.limit;
710
+ options.limit = void 0;
711
+ if (options.traceIds !== void 0) {
712
+ if (bound !== void 0) {
713
+ options.traceIds = await boundTraceIds(
714
+ registration.client,
715
+ options.traceIds,
716
+ bound,
717
+ options.onlyWithAssertions === true
718
+ );
719
+ }
720
+ } else if (options.datasetIds !== void 0) {
721
+ if (bound !== void 0) {
722
+ const pinned = await pinnedDatasetMembers(
723
+ registration.client,
724
+ options.datasetIds,
725
+ bound,
726
+ options.onlyWithAssertions === true
727
+ );
728
+ if (pinned !== void 0) {
729
+ options.traceIds = pinned;
730
+ }
666
731
  }
732
+ } else {
733
+ options.limit = bound ?? 10;
667
734
  }
668
- } else {
669
- options.limit = bound ?? 10;
735
+ const attemptsSuffix = options.attempts !== void 0 && options.attempts > 1 ? ` (${options.attempts} attempts each)` : "";
736
+ stderr(
737
+ `[replay] ${args.dryRun === true ? "Resolving inputs for" : "Replaying"} ${describeSelection(options)} from "${traceFunctionKey}"${attemptsSuffix}...`
738
+ );
670
739
  }
671
- const attemptsSuffix = options.attempts !== void 0 && options.attempts > 1 ? ` (${options.attempts} attempts each)` : "";
672
- stderr(
673
- `[replay] ${args.dryRun === true ? "Resolving inputs for" : "Replaying"} ${describeSelection(options)} from "${traceFunctionKey}"${attemptsSuffix}...`
674
- );
740
+ let result;
675
741
  try {
676
- const result = await registration.client.replay(
742
+ result = await registration.client.replay(
677
743
  traceFunctionKey,
678
744
  registration.fn,
679
745
  options
680
746
  );
681
- if (args.dryRun === true) {
682
- renderDryRun(args.pipeline, result, stderr);
683
- } else {
684
- renderSummary(args.pipeline, result, stderr);
685
- }
686
- stdout(serializeReplayResult(result));
687
- if (result.items.length === 0) {
688
- throw new BitfabError(
689
- `No traces matched "${traceFunctionKey}", so nothing was replayed. Seed cases with --seed, or capture a trace first.`
690
- );
691
- }
692
- return result;
693
747
  } catch (error) {
694
748
  if (error instanceof ReplayError) {
695
749
  reportReplayError(error, stderr);
696
750
  }
751
+ const experimentId = error instanceof ReplayError ? error.experimentId : startedExperimentId;
752
+ if (experimentId !== void 0) {
753
+ stderr(resumeCommand(registryPath, args.pipeline, experimentId));
754
+ }
697
755
  throw error;
698
756
  }
757
+ if (args.dryRun === true) {
758
+ renderDryRun(args.pipeline, result, stderr);
759
+ } else {
760
+ renderSummary(args.pipeline, result, stderr);
761
+ }
762
+ stdout(serializeReplayResult(result));
763
+ if (result.items.length === 0) {
764
+ throw new BitfabError(
765
+ `No traces matched "${traceFunctionKey}", so nothing was replayed. Seed cases with --seed, or capture a trace first.`
766
+ );
767
+ }
768
+ return result;
699
769
  }
700
770
 
701
771
  // src/registryCommand.ts
@@ -790,4 +860,4 @@ export {
790
860
  runRegistryMain,
791
861
  runIfEntrypoint
792
862
  };
793
- //# sourceMappingURL=chunk-S4WE6U2Y.js.map
863
+ //# sourceMappingURL=chunk-WOHIAKZF.js.map