@bitfab/sdk 0.68.11 → 0.70.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.
package/dist/replayCli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as runRegistryMain, c as runSeedCli, i as runIfEntrypoint, n as parseRegistryCommandArgs, o as checkReplayCliArgs, r as resolveRegistry, s as runReplayCli, t as importRegistry } from "./registryCommand-CWxt6kPp.js";
2
+ import { a as runRegistryMain, c as runSeedCli, i as runIfEntrypoint, n as parseRegistryCommandArgs, o as checkReplayCliArgs, r as resolveRegistry, s as runReplayCli, t as importRegistry } from "./registryCommand-jPTSRgL9.js";
3
3
  //#region src/cloudReplayCli.ts
4
4
  const CLOUD_REPLAY_HINT = "Add --cloud to run the same replay on GitHub Actions; bitfab-replay --cloud --help explains it.";
5
5
  function isCloudReplayCommand(argv) {
@@ -38,7 +38,7 @@ async function runCloudReplayCommand(argv, helper) {
38
38
  //#endregion
39
39
  //#region src/replayCli.ts
40
40
  const CHECK_ARGUMENTS_FLAG = "--check-arguments";
41
- const USAGE = `Usage: bitfab-replay --registry <path> <pipeline> [options]\n bitfab-replay --registry <path> <pipeline> --resume <experimentId>\n bitfab-replay --registry <path> <pipeline> --seed <cases.jsonl> [--run]\nRun bitfab-replay --registry <path> --help to list replay options.\n${CLOUD_REPLAY_HINT}`;
41
+ const USAGE = `Usage: bitfab-replay --registry <path> <pipeline> --code-change <type> [options]\n bitfab-replay --registry <path> <pipeline> --code-change <type> --resume <experimentId>\n bitfab-replay --registry <path> <pipeline> --seed <cases.jsonl> [--run]\nRun bitfab-replay --registry <path> --help to list replay options.\n${CLOUD_REPLAY_HINT}`;
42
42
  async function runReplayCommand(argv, io = {}, importer = importRegistry) {
43
43
  const { registryPath, commandArgs } = await parseRegistryCommandArgs(argv, USAGE);
44
44
  const registry = resolveRegistry(await importer(registryPath), registryPath);
@@ -1 +1 @@
1
- {"version":3,"file":"replayCli.js","names":[],"sources":["../src/cloudReplayCli.ts","../src/replayCli.ts"],"sourcesContent":["export const CLOUD_REPLAY_HINT =\n \"Add --cloud to run the same replay on GitHub Actions; bitfab-replay --cloud --help explains it.\"\n\nexport function isCloudReplayCommand(argv: readonly string[]): boolean {\n return argv.some((arg) => arg === \"--cloud\" || arg.startsWith(\"--cloud-\"))\n}\n\nexport async function runCloudReplayCommand(\n argv: readonly string[],\n helper?: string,\n): Promise<number> {\n const [{ spawn }, { fileURLToPath }] = await Promise.all([\n import(\"node:child_process\"),\n import(\"node:url\"),\n ])\n const script =\n helper ?? fileURLToPath(new URL(\"../cloudReplay.py\", import.meta.url))\n const replayCommand = [\n process.execPath,\n ...process.execArgv.filter((flag) => !/^--(inspect|debug)/.test(flag)),\n fileURLToPath(new URL(\"./replayCli.js\", import.meta.url)),\n ]\n const keepWaiting = () => {}\n process.on(\"SIGINT\", keepWaiting)\n try {\n return await new Promise<number>((resolve) => {\n const child = spawn(\"python3\", [script, ...argv], {\n stdio: \"inherit\",\n env: {\n ...process.env,\n BITFAB_REPLAY_COMMAND: JSON.stringify(replayCommand),\n BITFAB_SDK_LANGUAGE: \"typescript\",\n },\n })\n child.on(\"error\", () => {\n process.stderr.write(\n \"Cloud replay needs Python 3.10+ on PATH as python3\\n\",\n )\n resolve(1)\n })\n child.on(\"close\", (code, signal) =>\n resolve(code ?? (signal === \"SIGINT\" ? 130 : 1)),\n )\n })\n } finally {\n process.off(\"SIGINT\", keepWaiting)\n }\n}\n","#!/usr/bin/env node\n\nimport {\n CLOUD_REPLAY_HINT,\n isCloudReplayCommand,\n runCloudReplayCommand,\n} from \"./cloudReplayCli.js\"\nimport {\n importRegistry,\n parseRegistryCommandArgs,\n type RegistryImporter,\n resolveRegistry,\n runIfEntrypoint,\n runRegistryMain,\n} from \"./registryCommand.js\"\nimport type { ReplayResult } from \"./replay.js\"\nimport {\n checkReplayCliArgs,\n type ReplayCliIo,\n type ReseedRegistryResult,\n runReplayCli,\n runSeedCli,\n type SeedResult,\n} from \"./replayRegistry.js\"\n\nconst CHECK_ARGUMENTS_FLAG = \"--check-arguments\"\n\nconst USAGE = `Usage: bitfab-replay --registry <path> <pipeline> [options]\\n bitfab-replay --registry <path> <pipeline> --resume <experimentId>\\n bitfab-replay --registry <path> <pipeline> --seed <cases.jsonl> [--run]\\nRun bitfab-replay --registry <path> --help to list replay options.\\n${CLOUD_REPLAY_HINT}`\n\nexport async function runReplayCommand(\n argv: readonly string[],\n io: ReplayCliIo = {},\n importer: RegistryImporter = importRegistry,\n): Promise<ReplayResult<unknown> | SeedResult | ReseedRegistryResult | null> {\n const { registryPath, commandArgs } = await parseRegistryCommandArgs(\n argv,\n USAGE,\n )\n const registry = resolveRegistry(await importer(registryPath), registryPath)\n if (commandArgs.includes(\"--seed\")) {\n return runSeedCli(registry, commandArgs, io)\n }\n return runReplayCli(registry, commandArgs, io, registryPath)\n}\n\nexport async function runReplayMain(\n argv: readonly string[],\n io: ReplayCliIo = {},\n): Promise<number> {\n if (argv[0] === CHECK_ARGUMENTS_FLAG) {\n return runRegistryMain(async () => {\n const { commandArgs } = await parseRegistryCommandArgs(\n argv.slice(1),\n USAGE,\n )\n checkReplayCliArgs(commandArgs)\n }, io)\n }\n if (isCloudReplayCommand(argv)) {\n return runCloudReplayCommand(argv)\n }\n return runRegistryMain(() => runReplayCommand(argv, io), io)\n}\n\nrunIfEntrypoint(import.meta.url, () => runReplayMain(process.argv.slice(2)))\n"],"mappings":";;;AAAA,MAAa,oBACX;AAEF,SAAgB,qBAAqB,MAAkC;CACrE,OAAO,KAAK,MAAM,QAAQ,QAAQ,aAAa,IAAI,WAAW,UAAU,CAAC;AAC3E;AAEA,eAAsB,sBACpB,MACA,QACiB;CACjB,MAAM,CAAC,EAAE,SAAS,EAAE,mBAAmB,MAAM,QAAQ,IAAI,CACvD,OAAO,kBACP,OAAO,MACT,CAAC;CACD,MAAM,SACJ,UAAU,cAAc,IAAI,IAAI,qBAAqB,YAAY,GAAG,CAAC;CACvE,MAAM,gBAAgB;EACpB,QAAQ;EACR,GAAG,QAAQ,SAAS,QAAQ,SAAS,CAAC,qBAAqB,KAAK,IAAI,CAAC;EACrE,cAAc,IAAI,IAAI,kBAAkB,YAAY,GAAG,CAAC;CAC1D;CACA,MAAM,oBAAoB,CAAC;CAC3B,QAAQ,GAAG,UAAU,WAAW;CAChC,IAAI;EACF,OAAO,MAAM,IAAI,SAAiB,YAAY;GAC5C,MAAM,QAAQ,MAAM,WAAW,CAAC,QAAQ,GAAG,IAAI,GAAG;IAChD,OAAO;IACP,KAAK;KACH,GAAG,QAAQ;KACX,uBAAuB,KAAK,UAAU,aAAa;KACnD,qBAAqB;IACvB;GACF,CAAC;GACD,MAAM,GAAG,eAAe;IACtB,QAAQ,OAAO,MACb,sDACF;IACA,QAAQ,CAAC;GACX,CAAC;GACD,MAAM,GAAG,UAAU,MAAM,WACvB,QAAQ,SAAS,WAAW,WAAW,MAAM,EAAE,CACjD;EACF,CAAC;CACH,UAAU;EACR,QAAQ,IAAI,UAAU,WAAW;CACnC;AACF;;;ACtBA,MAAM,uBAAuB;AAE7B,MAAM,QAAQ,+RAA+R;AAE7S,eAAsB,iBACpB,MACA,KAAkB,CAAC,GACnB,WAA6B,gBAC8C;CAC3E,MAAM,EAAE,cAAc,gBAAgB,MAAM,yBAC1C,MACA,KACF;CACA,MAAM,WAAW,gBAAgB,MAAM,SAAS,YAAY,GAAG,YAAY;CAC3E,IAAI,YAAY,SAAS,QAAQ,GAC/B,OAAO,WAAW,UAAU,aAAa,EAAE;CAE7C,OAAO,aAAa,UAAU,aAAa,IAAI,YAAY;AAC7D;AAEA,eAAsB,cACpB,MACA,KAAkB,CAAC,GACF;CACjB,IAAI,KAAK,OAAO,sBACd,OAAO,gBAAgB,YAAY;EACjC,MAAM,EAAE,gBAAgB,MAAM,yBAC5B,KAAK,MAAM,CAAC,GACZ,KACF;EACA,mBAAmB,WAAW;CAChC,GAAG,EAAE;CAEP,IAAI,qBAAqB,IAAI,GAC3B,OAAO,sBAAsB,IAAI;CAEnC,OAAO,sBAAsB,iBAAiB,MAAM,EAAE,GAAG,EAAE;AAC7D;AAEA,gBAAgB,YAAY,WAAW,cAAc,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"replayCli.js","names":[],"sources":["../src/cloudReplayCli.ts","../src/replayCli.ts"],"sourcesContent":["export const CLOUD_REPLAY_HINT =\n \"Add --cloud to run the same replay on GitHub Actions; bitfab-replay --cloud --help explains it.\"\n\nexport function isCloudReplayCommand(argv: readonly string[]): boolean {\n return argv.some((arg) => arg === \"--cloud\" || arg.startsWith(\"--cloud-\"))\n}\n\nexport async function runCloudReplayCommand(\n argv: readonly string[],\n helper?: string,\n): Promise<number> {\n const [{ spawn }, { fileURLToPath }] = await Promise.all([\n import(\"node:child_process\"),\n import(\"node:url\"),\n ])\n const script =\n helper ?? fileURLToPath(new URL(\"../cloudReplay.py\", import.meta.url))\n const replayCommand = [\n process.execPath,\n ...process.execArgv.filter((flag) => !/^--(inspect|debug)/.test(flag)),\n fileURLToPath(new URL(\"./replayCli.js\", import.meta.url)),\n ]\n const keepWaiting = () => {}\n process.on(\"SIGINT\", keepWaiting)\n try {\n return await new Promise<number>((resolve) => {\n const child = spawn(\"python3\", [script, ...argv], {\n stdio: \"inherit\",\n env: {\n ...process.env,\n BITFAB_REPLAY_COMMAND: JSON.stringify(replayCommand),\n BITFAB_SDK_LANGUAGE: \"typescript\",\n },\n })\n child.on(\"error\", () => {\n process.stderr.write(\n \"Cloud replay needs Python 3.10+ on PATH as python3\\n\",\n )\n resolve(1)\n })\n child.on(\"close\", (code, signal) =>\n resolve(code ?? (signal === \"SIGINT\" ? 130 : 1)),\n )\n })\n } finally {\n process.off(\"SIGINT\", keepWaiting)\n }\n}\n","#!/usr/bin/env node\n\nimport {\n CLOUD_REPLAY_HINT,\n isCloudReplayCommand,\n runCloudReplayCommand,\n} from \"./cloudReplayCli.js\"\nimport {\n importRegistry,\n parseRegistryCommandArgs,\n type RegistryImporter,\n resolveRegistry,\n runIfEntrypoint,\n runRegistryMain,\n} from \"./registryCommand.js\"\nimport type { ReplayResult } from \"./replay.js\"\nimport {\n checkReplayCliArgs,\n type ReplayCliIo,\n type ReseedRegistryResult,\n runReplayCli,\n runSeedCli,\n type SeedResult,\n} from \"./replayRegistry.js\"\n\nconst CHECK_ARGUMENTS_FLAG = \"--check-arguments\"\n\nconst USAGE = `Usage: bitfab-replay --registry <path> <pipeline> --code-change <type> [options]\\n bitfab-replay --registry <path> <pipeline> --code-change <type> --resume <experimentId>\\n bitfab-replay --registry <path> <pipeline> --seed <cases.jsonl> [--run]\\nRun bitfab-replay --registry <path> --help to list replay options.\\n${CLOUD_REPLAY_HINT}`\n\nexport async function runReplayCommand(\n argv: readonly string[],\n io: ReplayCliIo = {},\n importer: RegistryImporter = importRegistry,\n): Promise<ReplayResult<unknown> | SeedResult | ReseedRegistryResult | null> {\n const { registryPath, commandArgs } = await parseRegistryCommandArgs(\n argv,\n USAGE,\n )\n const registry = resolveRegistry(await importer(registryPath), registryPath)\n if (commandArgs.includes(\"--seed\")) {\n return runSeedCli(registry, commandArgs, io)\n }\n return runReplayCli(registry, commandArgs, io, registryPath)\n}\n\nexport async function runReplayMain(\n argv: readonly string[],\n io: ReplayCliIo = {},\n): Promise<number> {\n if (argv[0] === CHECK_ARGUMENTS_FLAG) {\n return runRegistryMain(async () => {\n const { commandArgs } = await parseRegistryCommandArgs(\n argv.slice(1),\n USAGE,\n )\n checkReplayCliArgs(commandArgs)\n }, io)\n }\n if (isCloudReplayCommand(argv)) {\n return runCloudReplayCommand(argv)\n }\n return runRegistryMain(() => runReplayCommand(argv, io), io)\n}\n\nrunIfEntrypoint(import.meta.url, () => runReplayMain(process.argv.slice(2)))\n"],"mappings":";;;AAAA,MAAa,oBACX;AAEF,SAAgB,qBAAqB,MAAkC;CACrE,OAAO,KAAK,MAAM,QAAQ,QAAQ,aAAa,IAAI,WAAW,UAAU,CAAC;AAC3E;AAEA,eAAsB,sBACpB,MACA,QACiB;CACjB,MAAM,CAAC,EAAE,SAAS,EAAE,mBAAmB,MAAM,QAAQ,IAAI,CACvD,OAAO,kBACP,OAAO,MACT,CAAC;CACD,MAAM,SACJ,UAAU,cAAc,IAAI,IAAI,qBAAqB,YAAY,GAAG,CAAC;CACvE,MAAM,gBAAgB;EACpB,QAAQ;EACR,GAAG,QAAQ,SAAS,QAAQ,SAAS,CAAC,qBAAqB,KAAK,IAAI,CAAC;EACrE,cAAc,IAAI,IAAI,kBAAkB,YAAY,GAAG,CAAC;CAC1D;CACA,MAAM,oBAAoB,CAAC;CAC3B,QAAQ,GAAG,UAAU,WAAW;CAChC,IAAI;EACF,OAAO,MAAM,IAAI,SAAiB,YAAY;GAC5C,MAAM,QAAQ,MAAM,WAAW,CAAC,QAAQ,GAAG,IAAI,GAAG;IAChD,OAAO;IACP,KAAK;KACH,GAAG,QAAQ;KACX,uBAAuB,KAAK,UAAU,aAAa;KACnD,qBAAqB;IACvB;GACF,CAAC;GACD,MAAM,GAAG,eAAe;IACtB,QAAQ,OAAO,MACb,sDACF;IACA,QAAQ,CAAC;GACX,CAAC;GACD,MAAM,GAAG,UAAU,MAAM,WACvB,QAAQ,SAAS,WAAW,WAAW,MAAM,EAAE,CACjD;EACF,CAAC;CACH,UAAU;EACR,QAAQ,IAAI,UAAU,WAAW;CACnC;AACF;;;ACtBA,MAAM,uBAAuB;AAE7B,MAAM,QAAQ,yUAAyU;AAEvV,eAAsB,iBACpB,MACA,KAAkB,CAAC,GACnB,WAA6B,gBAC8C;CAC3E,MAAM,EAAE,cAAc,gBAAgB,MAAM,yBAC1C,MACA,KACF;CACA,MAAM,WAAW,gBAAgB,MAAM,SAAS,YAAY,GAAG,YAAY;CAC3E,IAAI,YAAY,SAAS,QAAQ,GAC/B,OAAO,WAAW,UAAU,aAAa,EAAE;CAE7C,OAAO,aAAa,UAAU,aAAa,IAAI,YAAY;AAC7D;AAEA,eAAsB,cACpB,MACA,KAAkB,CAAC,GACF;CACjB,IAAI,KAAK,OAAO,sBACd,OAAO,gBAAgB,YAAY;EACjC,MAAM,EAAE,gBAAgB,MAAM,yBAC5B,KAAK,MAAM,CAAC,GACZ,KACF;EACA,mBAAmB,WAAW;CAChC,GAAG,EAAE;CAEP,IAAI,qBAAqB,IAAI,GAC3B,OAAO,sBAAsB,IAAI;CAEnC,OAAO,sBAAsB,iBAAiB,MAAM,EAAE,GAAG,EAAE;AAC7D;AAEA,gBAAgB,YAAY,WAAW,cAAc,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC"}
package/dist/seedCli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as runRegistryMain, c as runSeedCli, i as runIfEntrypoint, n as parseRegistryCommandArgs, r as resolveRegistry, t as importRegistry } from "./registryCommand-CWxt6kPp.js";
2
+ import { a as runRegistryMain, c as runSeedCli, i as runIfEntrypoint, n as parseRegistryCommandArgs, r as resolveRegistry, t as importRegistry } from "./registryCommand-jPTSRgL9.js";
3
3
  //#region src/seedCli.ts
4
4
  const USAGE = "Usage: bitfab-seed --registry <path> <pipeline> --from-trace <id>[,<id>...]\n bitfab-seed --registry <path> <pipeline> --cases <cases.jsonl> [--run]\nRun bitfab-seed --registry <path> <pipeline> --help for details.";
5
5
  async function runSeedCommand(argv, io = {}, importer = importRegistry) {
@@ -1,5 +1,5 @@
1
1
  const require_bamlPeer = require("./bamlPeer-5Ohpq8q9.cjs");
2
- const require_http = require("./http-BN_Ry7Wf.cjs");
2
+ const require_http = require("./http-C6NC-zwf.cjs");
3
3
  const require_autoTrace = require("./autoTrace-DPWV1Xzr.cjs");
4
4
  const require_optionalPeer = require("./optionalPeer-CUH756lt.cjs");
5
5
  let superjson = require("superjson");
@@ -1234,6 +1234,9 @@ var ExperimentsClient = class {
1234
1234
  async getRollup(id) {
1235
1235
  return this.httpClient.get(`${EXPERIMENTS_PATH}/${encodeURIComponent(id)}/rollup`);
1236
1236
  }
1237
+ async getSummary(id) {
1238
+ return this.httpClient.get(`${EXPERIMENTS_PATH}/${encodeURIComponent(id)}/summary`);
1239
+ }
1237
1240
  async getRollupAll(ids) {
1238
1241
  if (ids.length === 0) return [];
1239
1242
  const query = new URLSearchParams({ experimentIds: ids.join(",") });
@@ -3003,17 +3006,57 @@ var BitfabPiIntegration = class {
3003
3006
  };
3004
3007
  //#endregion
3005
3008
  //#region src/codeChange.ts
3009
+ const CODE_CHANGE_TYPES = [
3010
+ "working-tree",
3011
+ "last-branch",
3012
+ "default-branch",
3013
+ "skip",
3014
+ "manual"
3015
+ ];
3016
+ const CODE_CHANGE_CHOICES = "\"working-tree\" (uncommitted changes vs HEAD), \"last-branch\" (the diff against the branch this one was cut from), \"default-branch\" (the diff against the default branch), \"skip\" (no code change), or \"manual\" (pass the files yourself)";
3017
+ function isCodeChangeType(value) {
3018
+ return CODE_CHANGE_TYPES.includes(value);
3019
+ }
3020
+ function validateCodeChange(request) {
3021
+ const { codeChange, codeChangeDescription, codeChangeFiles } = request;
3022
+ if (codeChange === void 0 || codeChange === null) throw new require_http.BitfabError(`replay needs a codeChange naming the code this run tests: ${CODE_CHANGE_CHOICES}.`);
3023
+ if (!isCodeChangeType(codeChange)) throw new require_http.BitfabError(`Unknown codeChange ${JSON.stringify(codeChange)}. Pass ${CODE_CHANGE_CHOICES}.`);
3024
+ const hasFiles = codeChangeFiles !== void 0 && codeChangeFiles !== null;
3025
+ if (codeChange === "manual" && !hasFiles) throw new require_http.BitfabError("codeChange \"manual\" needs codeChangeFiles: the path and before/after contents of each edited file.");
3026
+ if (codeChange !== "manual" && hasFiles) throw new require_http.BitfabError(`codeChangeFiles only applies with codeChange "manual" (got "${codeChange}").`);
3027
+ if (codeChange === "skip" && codeChangeDescription !== void 0 && codeChangeDescription !== null) throw new require_http.BitfabError("codeChange \"skip\" attaches no code change, so it cannot take a codeChangeDescription.");
3028
+ return codeChange;
3029
+ }
3030
+ async function resolveCodeChange(request, label) {
3031
+ const codeChange = validateCodeChange(request);
3032
+ const description = request.codeChangeDescription ?? void 0;
3033
+ if (codeChange === "skip") return {};
3034
+ if (codeChange === "manual") return {
3035
+ description,
3036
+ files: request.codeChangeFiles ?? []
3037
+ };
3038
+ const captured = await captureCodeChange(codeChange, label);
3039
+ if (captured?.files === void 0 || captured.files.length === 0) {
3040
+ try {
3041
+ console.warn(`Bitfab: codeChange "${codeChange}" found no changed files, so this replay has no code change attached.`);
3042
+ } catch {}
3043
+ return { description };
3044
+ }
3045
+ return {
3046
+ description: description ?? captured.description,
3047
+ files: captured.files
3048
+ };
3049
+ }
3006
3050
  const MAX_FILES = 60;
3007
3051
  const MAX_FILE_BYTES = 5e5;
3008
3052
  const MAX_TOTAL_BYTES = 2e6;
3009
3053
  const MAX_BRANCH_WALK = 1e3;
3010
3054
  const NUL = String.fromCharCode(0);
3011
- async function resolveAutoCodeChange(label) {
3055
+ async function captureCodeChange(type, label) {
3012
3056
  if (typeof process === "undefined") return null;
3013
- if (process.env?.BITFAB_DISABLE_CODE_CHANGE_CAPTURE) return null;
3014
3057
  const fromEnv = await readCodeChangeFile();
3015
3058
  if (fromEnv) return fromEnv;
3016
- return captureCodeChangeFromGit(process.cwd?.() ?? ".", label);
3059
+ return captureCodeChangeFromGit(process.cwd?.() ?? ".", type, label);
3017
3060
  }
3018
3061
  async function readCodeChangeFile() {
3019
3062
  const path = process.env?.BITFAB_CODE_CHANGE_PATH;
@@ -3032,7 +3075,7 @@ async function readCodeChangeFile() {
3032
3075
  return null;
3033
3076
  }
3034
3077
  }
3035
- async function captureCodeChangeFromGit(cwd, label) {
3078
+ async function captureCodeChangeFromGit(cwd, type, label) {
3036
3079
  let readFile;
3037
3080
  try {
3038
3081
  ({readFile} = await import("fs/promises"));
@@ -3048,16 +3091,9 @@ async function captureCodeChangeFromGit(cwd, label) {
3048
3091
  try {
3049
3092
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
3050
3093
  if (!root) return null;
3051
- let resolved = await resolveBase(git, root);
3094
+ const resolved = await resolveBase(git, root, type);
3052
3095
  if (!resolved) return null;
3053
- let entries = await listChanges(git, root, resolved.base);
3054
- if (entries.length === 0 && resolved.base === "HEAD") {
3055
- const branchPoint = await resolveBranchPoint(git, root);
3056
- if (branchPoint) {
3057
- resolved = branchPoint;
3058
- entries = await listChanges(git, root, branchPoint.base);
3059
- }
3060
- }
3096
+ const entries = await listChanges(git, root, resolved.base);
3061
3097
  if (entries.length === 0) return null;
3062
3098
  const { base, against } = resolved;
3063
3099
  const blobBytes = async (ref, path) => {
@@ -3236,23 +3272,22 @@ async function resolveBranchPoint(git, root) {
3236
3272
  against: `vs ${defaultBranch}`
3237
3273
  } : null;
3238
3274
  }
3239
- async function resolveBase(git, root) {
3240
- const forced = process.env?.BITFAB_CODE_CHANGE_BASE;
3241
- if (forced && await refExists(git, root, forced)) {
3242
- const base = (await git(root, [
3243
- "merge-base",
3244
- "HEAD",
3245
- forced
3246
- ]))?.trim() || (await git(root, [
3247
- "rev-parse",
3248
- "--verify",
3249
- forced
3250
- ]))?.trim() || null;
3251
- return base ? {
3252
- base,
3253
- against: `vs ${forced}`
3254
- } : null;
3255
- }
3275
+ async function resolveDefaultBranchPoint(git, root) {
3276
+ const defaultBranch = await resolveDefaultBranch(git, root);
3277
+ if (!defaultBranch) return null;
3278
+ const base = (await git(root, [
3279
+ "merge-base",
3280
+ "HEAD",
3281
+ defaultBranch
3282
+ ]))?.trim();
3283
+ return base ? {
3284
+ base,
3285
+ against: `vs ${defaultBranch}`
3286
+ } : null;
3287
+ }
3288
+ async function resolveBase(git, root, type) {
3289
+ if (type === "last-branch") return resolveBranchPoint(git, root);
3290
+ if (type === "default-branch") return resolveDefaultBranchPoint(git, root);
3256
3291
  return await refExists(git, root, "HEAD") ? {
3257
3292
  base: "HEAD",
3258
3293
  against: "uncommitted (vs HEAD)"
@@ -3774,6 +3809,7 @@ const REPLAY_OPTION_NAMES = [
3774
3809
  "notes",
3775
3810
  "metadata",
3776
3811
  "maxConcurrency",
3812
+ "codeChange",
3777
3813
  "codeChangeDescription",
3778
3814
  "codeChangeFiles",
3779
3815
  "mock",
@@ -4141,6 +4177,7 @@ function warnJudgeAssertionsDeprecated(write = console.warn) {
4141
4177
  require_autoTrace.writeOnce("judgeAssertions-deprecated", JUDGE_ASSERTIONS_DEPRECATION_WARNING, write);
4142
4178
  }
4143
4179
  async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, registeredOverrides = []) {
4180
+ validateCodeChange(options ?? {});
4144
4181
  if (options?.judgeAssertions !== void 0) warnJudgeAssertionsDeprecated();
4145
4182
  if (options?.resume !== void 0) validateResume(options.resume, options);
4146
4183
  else if (options?.force === true) throw new require_http.BitfabError("force only applies when resuming an experiment. Pass it together with resume.");
@@ -4161,15 +4198,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
4161
4198
  const maxConcurrency = options?.maxConcurrency ?? 10;
4162
4199
  if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1) throw new require_http.BitfabError(`maxConcurrency must be a positive integer (got ${maxConcurrency}).`);
4163
4200
  await require_http.replayContextReady;
4164
- let codeChangeDescription = options?.codeChangeDescription;
4165
- let codeChangeFiles = options?.codeChangeFiles;
4166
- if (codeChangeFiles === void 0) {
4167
- const captured = await resolveAutoCodeChange(options?.name);
4168
- if (captured) {
4169
- codeChangeFiles = captured.files;
4170
- if (codeChangeDescription === void 0) codeChangeDescription = captured.description;
4171
- }
4172
- }
4201
+ const { description: codeChangeDescription, files: codeChangeFiles } = await resolveCodeChange(options, options.name);
4173
4202
  const includeDbBranchLease = dbBranchEnabled(options?.dbBranch) && options?.dryRun !== true;
4174
4203
  let session;
4175
4204
  if (options?.resume === void 0) {
@@ -7009,7 +7038,7 @@ var Bitfab = class {
7009
7038
  await runWithSeedContext({ traceId }, async () => target(...args));
7010
7039
  } finally {
7011
7040
  try {
7012
- const { flushTraces } = await Promise.resolve().then(() => require("./http-BN_Ry7Wf.cjs")).then((n) => n.http_exports);
7041
+ const { flushTraces } = await Promise.resolve().then(() => require("./http-C6NC-zwf.cjs")).then((n) => n.http_exports);
7013
7042
  await flushTraces(3e4);
7014
7043
  } finally {
7015
7044
  unrecorded = activeTraceStates.delete(traceId);
@@ -7215,7 +7244,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
7215
7244
  metadata: seedCase.metadata,
7216
7245
  sessionId: seedCase.sessionId
7217
7246
  }));
7218
- const { flushTraces } = await Promise.resolve().then(() => require("./http-BN_Ry7Wf.cjs")).then((n) => n.http_exports);
7247
+ const { flushTraces } = await Promise.resolve().then(() => require("./http-C6NC-zwf.cjs")).then((n) => n.http_exports);
7219
7248
  await flushTraces(3e4);
7220
7249
  return {
7221
7250
  pipeline,
@@ -7465,4 +7494,4 @@ Object.defineProperty(exports, "serializeReplayResult", {
7465
7494
  }
7466
7495
  });
7467
7496
 
7468
- //# sourceMappingURL=src-G_mEK3GW.cjs.map
7497
+ //# sourceMappingURL=src-Cwzg-mER.cjs.map