bitfab 0.52.4 → 0.52.5

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 (33) hide show
  1. package/README.md +2 -0
  2. package/dist/{chunk-IG3CPSRQ.js → chunk-3D7FNJ5R.js} +2 -2
  3. package/dist/{chunk-IG3CPSRQ.js.map → chunk-3D7FNJ5R.js.map} +1 -1
  4. package/dist/{chunk-HKTODDFP.js → chunk-3QXNM62Y.js} +3 -3
  5. package/dist/chunk-3QXNM62Y.js.map +1 -0
  6. package/dist/{chunk-U2D7ACC4.js → chunk-6DRFQJ75.js} +110 -13
  7. package/dist/chunk-6DRFQJ75.js.map +1 -0
  8. package/dist/{chunk-34B7PVAM.js → chunk-CAE7HE4C.js} +3 -2
  9. package/dist/{chunk-34B7PVAM.js.map → chunk-CAE7HE4C.js.map} +1 -1
  10. package/dist/{chunk-AUROMI67.js → chunk-EMRHO6YW.js} +241 -21
  11. package/dist/chunk-EMRHO6YW.js.map +1 -0
  12. package/dist/{http-RFNQ7LSU.js → http-Q6UEKZRF.js} +2 -2
  13. package/dist/{http-F3AXLOJT.js → http-UQT6QVBC.js} +2 -2
  14. package/dist/index.cjs +380 -57
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +10 -2
  17. package/dist/index.d.ts +10 -2
  18. package/dist/index.js +3 -3
  19. package/dist/node.cjs +380 -57
  20. package/dist/node.cjs.map +1 -1
  21. package/dist/node.d.cts +1 -1
  22. package/dist/node.d.ts +1 -1
  23. package/dist/node.js +3 -3
  24. package/dist/{replay-ZOTYMBMD.js → replay-UVSZFZW7.js} +3 -3
  25. package/dist/replayCli.js +2 -2
  26. package/dist/seedCli.js +2 -2
  27. package/package.json +1 -1
  28. package/dist/chunk-AUROMI67.js.map +0 -1
  29. package/dist/chunk-HKTODDFP.js.map +0 -1
  30. package/dist/chunk-U2D7ACC4.js.map +0 -1
  31. /package/dist/{http-F3AXLOJT.js.map → http-Q6UEKZRF.js.map} +0 -0
  32. /package/dist/{http-RFNQ7LSU.js.map → http-UQT6QVBC.js.map} +0 -0
  33. /package/dist/{replay-ZOTYMBMD.js.map → replay-UVSZFZW7.js.map} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  flushTraces,
7
7
  parseRetryAfterMs,
8
8
  serializePayloadBody
9
- } from "./chunk-34B7PVAM.js";
9
+ } from "./chunk-CAE7HE4C.js";
10
10
  import "./chunk-H6LZRFMN.js";
11
11
  export {
12
12
  BitfabError,
@@ -17,4 +17,4 @@ export {
17
17
  parseRetryAfterMs,
18
18
  serializePayloadBody
19
19
  };
20
- //# sourceMappingURL=http-RFNQ7LSU.js.map
20
+ //# sourceMappingURL=http-Q6UEKZRF.js.map
@@ -6,7 +6,7 @@ import {
6
6
  flushTraces,
7
7
  parseRetryAfterMs,
8
8
  serializePayloadBody
9
- } from "./chunk-IG3CPSRQ.js";
9
+ } from "./chunk-3D7FNJ5R.js";
10
10
  export {
11
11
  BitfabError,
12
12
  HttpClient,
@@ -16,4 +16,4 @@ export {
16
16
  parseRetryAfterMs,
17
17
  serializePayloadBody
18
18
  };
19
- //# sourceMappingURL=http-F3AXLOJT.js.map
19
+ //# sourceMappingURL=http-UQT6QVBC.js.map
package/dist/index.cjs CHANGED
@@ -51,7 +51,7 @@ var __version__, __packageName__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.52.4";
54
+ __version__ = "0.52.5";
55
55
  __packageName__ = "bitfab";
56
56
  }
57
57
  });
@@ -1130,7 +1130,7 @@ var init_otel = __esm({
1130
1130
  if (this.onDelivered === void 0) {
1131
1131
  return;
1132
1132
  }
1133
- const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
1133
+ const refs = spans.map((span) => span.ref).filter((ref2) => ref2 !== void 0);
1134
1134
  if (refs.length === 0) {
1135
1135
  return;
1136
1136
  }
@@ -1387,9 +1387,9 @@ function parseRetryAfterMs(header) {
1387
1387
  }
1388
1388
  return Math.max(0, at - Date.now());
1389
1389
  }
1390
- function carrierMeta(operation, payload, ref) {
1390
+ function carrierMeta(operation, payload, ref2) {
1391
1391
  return {
1392
- ref,
1392
+ ref: ref2,
1393
1393
  name: carrierName(operation, payload),
1394
1394
  startTime: payloadTimestamp(payload, "started_at"),
1395
1395
  endTime: payloadTimestamp(payload, "ended_at"),
@@ -1634,22 +1634,22 @@ var init_http = __esm({
1634
1634
  return reports;
1635
1635
  }
1636
1636
  /** Build a carrier's meta and record what it adds to its trace's expected set. */
1637
- recordedMeta(operation, payload, ref) {
1638
- this.recordSubmittedCarrier(ref);
1639
- return carrierMeta(operation, payload, ref);
1637
+ recordedMeta(operation, payload, ref2) {
1638
+ this.recordSubmittedCarrier(ref2);
1639
+ return carrierMeta(operation, payload, ref2);
1640
1640
  }
1641
- recordSubmittedCarrier(ref) {
1642
- if (ref === void 0) {
1641
+ recordSubmittedCarrier(ref2) {
1642
+ if (ref2 === void 0) {
1643
1643
  return;
1644
1644
  }
1645
- const delivery = this.traceDeliveries.get(ref.traceId);
1645
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1646
1646
  if (delivery === void 0) {
1647
1647
  return;
1648
1648
  }
1649
- if (ref.spanId === void 0) {
1649
+ if (ref2.spanId === void 0) {
1650
1650
  delivery.closed = true;
1651
1651
  } else {
1652
- delivery.submittedSpanIds.add(ref.spanId);
1652
+ delivery.submittedSpanIds.add(ref2.spanId);
1653
1653
  }
1654
1654
  }
1655
1655
  /**
@@ -1675,15 +1675,15 @@ var init_http = __esm({
1675
1675
  }
1676
1676
  }
1677
1677
  recordDeliveredCarriers(refs) {
1678
- for (const ref of refs) {
1679
- const delivery = this.traceDeliveries.get(ref.traceId);
1678
+ for (const ref2 of refs) {
1679
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1680
1680
  if (delivery === void 0) {
1681
1681
  continue;
1682
1682
  }
1683
- if (ref.spanId === void 0) {
1683
+ if (ref2.spanId === void 0) {
1684
1684
  delivery.closingAcked = true;
1685
1685
  } else {
1686
- delivery.ackedSpanIds.add(ref.spanId);
1686
+ delivery.ackedSpanIds.add(ref2.spanId);
1687
1687
  }
1688
1688
  }
1689
1689
  }
@@ -1713,9 +1713,9 @@ var init_http = __esm({
1713
1713
  */
1714
1714
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1715
1715
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1716
- const settled = await this.settleDeferredWork(timeoutMs);
1716
+ const settled2 = await this.settleDeferredWork(timeoutMs);
1717
1717
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1718
- return settled && flushed;
1718
+ return settled2 && flushed;
1719
1719
  }
1720
1720
  /**
1721
1721
  * Flush and permanently close this client's tracing transport. Idempotent:
@@ -1728,14 +1728,14 @@ var init_http = __esm({
1728
1728
  }
1729
1729
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1730
1730
  this.closing = (async () => {
1731
- const settled = await this.settleDeferredWork(
1731
+ const settled2 = await this.settleDeferredWork(
1732
1732
  Math.max(0, deadline - Date.now())
1733
1733
  );
1734
1734
  this.closed = true;
1735
1735
  const transport = this.traceTransport;
1736
1736
  this.traceTransport = void 0;
1737
1737
  const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
1738
- return settled && shutdownOk;
1738
+ return settled2 && shutdownOk;
1739
1739
  })();
1740
1740
  return this.closing;
1741
1741
  }
@@ -2346,6 +2346,112 @@ var init_randomUuid = __esm({
2346
2346
  }
2347
2347
  });
2348
2348
 
2349
+ // src/gitCommand.ts
2350
+ function isUnrefable(value) {
2351
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
2352
+ }
2353
+ function unrefStream(stream) {
2354
+ if (isUnrefable(stream)) {
2355
+ stream.unref();
2356
+ }
2357
+ }
2358
+ function terminate(child) {
2359
+ if (child.pid && process.platform !== "win32") {
2360
+ try {
2361
+ process.kill(-child.pid, "SIGTERM");
2362
+ return;
2363
+ } catch {
2364
+ child.kill("SIGTERM");
2365
+ return;
2366
+ }
2367
+ }
2368
+ child.kill("SIGTERM");
2369
+ }
2370
+ async function gitRunner(options) {
2371
+ let spawn;
2372
+ try {
2373
+ ;
2374
+ ({ spawn } = await import("child_process"));
2375
+ } catch {
2376
+ return null;
2377
+ }
2378
+ return (dir, args) => new Promise((resolve) => {
2379
+ let child;
2380
+ try {
2381
+ child = spawn("git", args, {
2382
+ cwd: dir,
2383
+ detached: process.platform !== "win32",
2384
+ stdio: ["ignore", "pipe", "pipe"]
2385
+ });
2386
+ } catch {
2387
+ resolve(null);
2388
+ return;
2389
+ }
2390
+ const chunks = [];
2391
+ let size = 0;
2392
+ let overflow = false;
2393
+ let exitCode = null;
2394
+ let done = false;
2395
+ const timers = [];
2396
+ const schedule = (callback, ms) => {
2397
+ const timer = setTimeout(callback, ms);
2398
+ if (!options.keepProcessAlive) {
2399
+ timer.unref();
2400
+ }
2401
+ timers.push(timer);
2402
+ };
2403
+ const finish = () => {
2404
+ if (done) {
2405
+ return;
2406
+ }
2407
+ done = true;
2408
+ for (const timer of timers) {
2409
+ clearTimeout(timer);
2410
+ }
2411
+ child.stdout?.destroy();
2412
+ child.stderr?.destroy();
2413
+ resolve(
2414
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
2415
+ );
2416
+ };
2417
+ child.stdout?.on("data", (chunk) => {
2418
+ size += chunk.length;
2419
+ if (size > options.maxBuffer) {
2420
+ overflow = true;
2421
+ terminate(child);
2422
+ return;
2423
+ }
2424
+ chunks.push(chunk);
2425
+ });
2426
+ child.stderr?.resume();
2427
+ child.on("error", () => {
2428
+ exitCode = null;
2429
+ finish();
2430
+ });
2431
+ child.on("exit", (code) => {
2432
+ exitCode = code;
2433
+ schedule(finish, EXIT_GRACE_MS);
2434
+ });
2435
+ child.on("close", (code) => {
2436
+ exitCode = code ?? exitCode;
2437
+ finish();
2438
+ });
2439
+ schedule(() => terminate(child), options.timeoutMs);
2440
+ if (!options.keepProcessAlive) {
2441
+ child.unref();
2442
+ unrefStream(child.stdout);
2443
+ unrefStream(child.stderr);
2444
+ }
2445
+ });
2446
+ }
2447
+ var EXIT_GRACE_MS;
2448
+ var init_gitCommand = __esm({
2449
+ "src/gitCommand.ts"() {
2450
+ "use strict";
2451
+ EXIT_GRACE_MS = 500;
2452
+ }
2453
+ });
2454
+
2349
2455
  // src/mockOverride.ts
2350
2456
  function resolveMockValue(value, ctx) {
2351
2457
  return typeof value === "function" ? value(ctx) : value;
@@ -2402,37 +2508,33 @@ async function readCodeChangeFile() {
2402
2508
  }
2403
2509
  }
2404
2510
  async function captureCodeChangeFromGit(cwd, label) {
2405
- let execFile;
2406
2511
  let readFile;
2407
2512
  try {
2408
2513
  ;
2409
- ({ execFile } = await import("child_process"));
2410
2514
  ({ readFile } = await import("fs/promises"));
2411
2515
  } catch {
2412
2516
  return null;
2413
2517
  }
2414
- const git = (dir, args) => new Promise((resolve) => {
2415
- execFile(
2416
- "git",
2417
- args,
2418
- // 30s timeout so a hung git (e.g. a network-touching ref op) can't
2419
- // block the whole replay indefinitely.
2420
- { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 3e4 },
2421
- (err, stdout) => resolve(err ? null : stdout)
2422
- );
2518
+ const git = await gitRunner({
2519
+ timeoutMs: 3e4,
2520
+ maxBuffer: 64 * 1024 * 1024,
2521
+ keepProcessAlive: true
2423
2522
  });
2523
+ if (!git) {
2524
+ return null;
2525
+ }
2424
2526
  try {
2425
2527
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
2426
2528
  if (!root) {
2427
2529
  return null;
2428
2530
  }
2429
- const resolved = await resolveBase(git, root);
2430
- if (!resolved) {
2531
+ const resolved2 = await resolveBase(git, root);
2532
+ if (!resolved2) {
2431
2533
  return null;
2432
2534
  }
2433
- const { base, fromTrunk } = resolved;
2434
- const blobBytes = async (ref, path) => {
2435
- const out = await git(root, ["cat-file", "-s", `${ref}:${path}`]);
2535
+ const { base, fromTrunk } = resolved2;
2536
+ const blobBytes = async (ref2, path) => {
2537
+ const out = await git(root, ["cat-file", "-s", `${ref2}:${path}`]);
2436
2538
  const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN;
2437
2539
  return Number.isFinite(n) ? n : 0;
2438
2540
  };
@@ -2524,8 +2626,8 @@ async function resolveBase(git, root) {
2524
2626
  }
2525
2627
  return await refExists(git, root, "HEAD") ? { base: "HEAD", fromTrunk: false } : null;
2526
2628
  }
2527
- async function refExists(git, root, ref) {
2528
- return await git(root, ["rev-parse", "--verify", `${ref}^{object}`]) !== null;
2629
+ async function refExists(git, root, ref2) {
2630
+ return await git(root, ["rev-parse", "--verify", `${ref2}^{object}`]) !== null;
2529
2631
  }
2530
2632
  async function readWorkingFile(readFile, root, path) {
2531
2633
  try {
@@ -2560,6 +2662,7 @@ var MAX_FILES, MAX_FILE_BYTES, MAX_TOTAL_BYTES, TRUNK_CANDIDATES, NUL;
2560
2662
  var init_codeChange = __esm({
2561
2663
  "src/codeChange.ts"() {
2562
2664
  "use strict";
2665
+ init_gitCommand();
2563
2666
  MAX_FILES = 60;
2564
2667
  MAX_FILE_BYTES = 5e5;
2565
2668
  MAX_TOTAL_BYTES = 2e6;
@@ -2764,9 +2867,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2764
2867
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2765
2868
  try {
2766
2869
  if (includeDbBranchLease && !lease && !leaseError) {
2767
- let resolved;
2870
+ let resolved2;
2768
2871
  try {
2769
- resolved = await httpClient.resolveDbBranchLease(
2872
+ resolved2 = await httpClient.resolveDbBranchLease(
2770
2873
  testRunId,
2771
2874
  originalTraceId,
2772
2875
  dbBranchSettings,
@@ -2780,10 +2883,10 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2780
2883
  cause
2781
2884
  );
2782
2885
  }
2783
- lease = resolved.lease ?? void 0;
2784
- leaseError = resolved.leaseError ?? void 0;
2785
- dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2786
- dbBranchTimings = resolved.timings ?? dbBranchTimings;
2886
+ lease = resolved2.lease ?? void 0;
2887
+ leaseError = resolved2.leaseError ?? void 0;
2888
+ dbSnapshotRef = resolved2.dbSnapshotRef ?? dbSnapshotRef;
2889
+ dbBranchTimings = resolved2.timings ?? dbBranchTimings;
2787
2890
  }
2788
2891
  if (leaseError) {
2789
2892
  throw new DbBranchReplayError(
@@ -4559,24 +4662,239 @@ function mixedTracingError(enteredApi, entered, enclosing, traceFunctionKey) {
4559
4662
  `opt-in and opt-out tracing can't be mixed in one call stack: ${enteredApi} (${entered})${subject} was entered inside a ${SURFACE_API[enclosing]} call (${enclosing}). ${MIXED_SURFACE_REMEDY[entered]}`
4560
4663
  );
4561
4664
  }
4562
- function assertSurfacesCompatible(requested, resolved, parentSurface, traceFunctionKey) {
4665
+ function assertSurfacesCompatible(requested, resolved2, parentSurface, traceFunctionKey) {
4563
4666
  if (requested === "inherit" || requested === "neutral") {
4564
4667
  return;
4565
4668
  }
4566
- if (resolved === void 0 || parentSurface === void 0) {
4669
+ if (resolved2 === void 0 || parentSurface === void 0) {
4567
4670
  return;
4568
4671
  }
4569
- if (parentSurface === resolved) {
4672
+ if (parentSurface === resolved2) {
4570
4673
  return;
4571
4674
  }
4572
4675
  throw mixedTracingError(
4573
- SURFACE_API[resolved],
4574
- resolved,
4676
+ SURFACE_API[resolved2],
4677
+ resolved2,
4575
4678
  parentSurface,
4576
4679
  traceFunctionKey
4577
4680
  );
4578
4681
  }
4579
4682
 
4683
+ // src/commitRef.ts
4684
+ init_gitCommand();
4685
+ init_readEnv();
4686
+ var EXPLICIT_SHA_ENV = "BITFAB_COMMIT_SHA";
4687
+ var DISABLE_ENV = "BITFAB_DISABLE_COMMIT_REF";
4688
+ var GIT_TIMEOUT_MS = 2e3;
4689
+ var GIT_MAX_BUFFER = 1024 * 1024;
4690
+ var VERCEL_PROVIDER_HOSTS = {
4691
+ github: "github.com",
4692
+ gitlab: "gitlab.com",
4693
+ bitbucket: "bitbucket.org"
4694
+ };
4695
+ function read(env, name) {
4696
+ if (name === null) {
4697
+ return null;
4698
+ }
4699
+ const value = env(name)?.trim();
4700
+ return value ? value : null;
4701
+ }
4702
+ function remoteFrom(...names) {
4703
+ return (env) => {
4704
+ const parts = names.map((name) => read(env, name));
4705
+ if (parts.some((part) => part === null)) {
4706
+ return null;
4707
+ }
4708
+ return normalizeRemote(parts.join("/"));
4709
+ };
4710
+ }
4711
+ function vercelRemote(env) {
4712
+ const provider = read(env, "VERCEL_GIT_PROVIDER")?.toLowerCase() ?? "";
4713
+ const host = VERCEL_PROVIDER_HOSTS[provider];
4714
+ const owner = read(env, "VERCEL_GIT_REPO_OWNER");
4715
+ const slug = read(env, "VERCEL_GIT_REPO_SLUG");
4716
+ if (!host || !owner || !slug) {
4717
+ return null;
4718
+ }
4719
+ return `${host}/${owner}/${slug}`;
4720
+ }
4721
+ function noRemote() {
4722
+ return null;
4723
+ }
4724
+ var PLATFORM_ENVS = [
4725
+ ["VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF", vercelRemote],
4726
+ [
4727
+ "GITHUB_SHA",
4728
+ "GITHUB_REF_NAME",
4729
+ remoteFrom("GITHUB_SERVER_URL", "GITHUB_REPOSITORY")
4730
+ ],
4731
+ ["RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH", noRemote],
4732
+ ["RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH", noRemote],
4733
+ ["SOURCE_VERSION", null, noRemote],
4734
+ ["CF_PAGES_COMMIT_SHA", "CF_PAGES_BRANCH", noRemote],
4735
+ ["CI_COMMIT_SHA", "CI_COMMIT_REF_NAME", remoteFrom("CI_REPOSITORY_URL")],
4736
+ [
4737
+ "BUILD_SOURCEVERSION",
4738
+ "BUILD_SOURCEBRANCHNAME",
4739
+ remoteFrom("BUILD_REPOSITORY_URI")
4740
+ ],
4741
+ ["CIRCLE_SHA1", "CIRCLE_BRANCH", remoteFrom("CIRCLE_REPOSITORY_URL")]
4742
+ ];
4743
+ var COMMIT_REF_ENV_NAMES = [
4744
+ EXPLICIT_SHA_ENV,
4745
+ DISABLE_ENV,
4746
+ ...PLATFORM_ENVS.flatMap(
4747
+ ([sha, branch]) => branch === null ? [sha] : [sha, branch]
4748
+ ),
4749
+ "GITHUB_SERVER_URL",
4750
+ "GITHUB_REPOSITORY",
4751
+ "CI_REPOSITORY_URL",
4752
+ "BUILD_REPOSITORY_URI",
4753
+ "CIRCLE_REPOSITORY_URL",
4754
+ "VERCEL_GIT_PROVIDER",
4755
+ "VERCEL_GIT_REPO_OWNER",
4756
+ "VERCEL_GIT_REPO_SLUG"
4757
+ ];
4758
+ function normalizeRemote(raw) {
4759
+ const value = raw?.trim();
4760
+ if (!value) {
4761
+ return null;
4762
+ }
4763
+ let host = "";
4764
+ let path = value;
4765
+ if (value.includes("://")) {
4766
+ try {
4767
+ const parsed = new URL(value);
4768
+ host = parsed.hostname;
4769
+ path = parsed.pathname;
4770
+ } catch {
4771
+ return null;
4772
+ }
4773
+ } else {
4774
+ const separator = value.indexOf(":");
4775
+ if (separator !== -1) {
4776
+ const head = value.slice(0, separator);
4777
+ host = head.slice(head.lastIndexOf("@") + 1);
4778
+ path = value.slice(separator + 1);
4779
+ }
4780
+ }
4781
+ path = path.replace(/^\/+|\/+$/g, "");
4782
+ if (path.endsWith(".git")) {
4783
+ path = path.slice(0, -".git".length).replace(/\/+$/, "");
4784
+ }
4785
+ if (!host) {
4786
+ return path || null;
4787
+ }
4788
+ return path ? `${host}/${path}` : host;
4789
+ }
4790
+ function resolveCommitRefFromEnv(env) {
4791
+ const explicit = read(env, EXPLICIT_SHA_ENV);
4792
+ const platform = PLATFORM_ENVS.find(([sha]) => read(env, sha) !== null);
4793
+ if (!platform) {
4794
+ if (explicit === null) {
4795
+ return null;
4796
+ }
4797
+ return {
4798
+ sha: explicit,
4799
+ branch: null,
4800
+ dirty: null,
4801
+ remote: null,
4802
+ rootSha: null
4803
+ };
4804
+ }
4805
+ const [shaEnv, branchEnv, readRemote] = platform;
4806
+ return {
4807
+ sha: explicit ?? read(env, shaEnv),
4808
+ branch: read(env, branchEnv),
4809
+ dirty: null,
4810
+ remote: readRemote(env),
4811
+ rootSha: null
4812
+ };
4813
+ }
4814
+ async function resolveCommitRefFromGit(cwd) {
4815
+ const git = await gitRunner({
4816
+ timeoutMs: GIT_TIMEOUT_MS,
4817
+ maxBuffer: GIT_MAX_BUFFER,
4818
+ keepProcessAlive: false
4819
+ });
4820
+ if (!git) {
4821
+ return null;
4822
+ }
4823
+ const run = async (args) => (await git(cwd, args))?.trim() ?? null;
4824
+ const sha = await run(["rev-parse", "HEAD"]);
4825
+ if (!sha) {
4826
+ return null;
4827
+ }
4828
+ const [branch, status, remote, roots] = await Promise.all([
4829
+ run(["symbolic-ref", "--short", "-q", "HEAD"]),
4830
+ run(["status", "--porcelain"]),
4831
+ run(["remote", "get-url", "origin"]),
4832
+ run(["rev-list", "--max-parents=0", "HEAD"])
4833
+ ]);
4834
+ return {
4835
+ sha,
4836
+ branch: branch || null,
4837
+ dirty: status === null ? null : status.length > 0,
4838
+ remote: normalizeRemote(remote),
4839
+ rootSha: roots ? roots.split(/\s+/).sort()[0] ?? null : null
4840
+ };
4841
+ }
4842
+ function commitRefWire(ref2) {
4843
+ return {
4844
+ sha: ref2.sha,
4845
+ branch: ref2.branch,
4846
+ dirty: ref2.dirty,
4847
+ remote: ref2.remote,
4848
+ root_sha: ref2.rootSha
4849
+ };
4850
+ }
4851
+ var resolved = false;
4852
+ var ref = null;
4853
+ var gitStarted = false;
4854
+ var settled = Promise.resolve();
4855
+ function startCommitRefResolution() {
4856
+ if (resolved || gitStarted) {
4857
+ return;
4858
+ }
4859
+ if (read(readEnv, DISABLE_ENV) !== null) {
4860
+ resolved = true;
4861
+ return;
4862
+ }
4863
+ const fromEnv = resolveCommitRefFromEnv(readEnv);
4864
+ if (fromEnv) {
4865
+ ref = fromEnv;
4866
+ resolved = true;
4867
+ return;
4868
+ }
4869
+ gitStarted = true;
4870
+ if (typeof process === "undefined") {
4871
+ resolved = true;
4872
+ return;
4873
+ }
4874
+ let cwd;
4875
+ try {
4876
+ cwd = process.cwd?.() ?? ".";
4877
+ } catch {
4878
+ resolved = true;
4879
+ return;
4880
+ }
4881
+ settled = resolveCommitRefFromGit(cwd).then(
4882
+ (fromGit) => {
4883
+ if (!resolved) {
4884
+ ref = fromGit;
4885
+ resolved = true;
4886
+ }
4887
+ },
4888
+ () => {
4889
+ resolved = true;
4890
+ }
4891
+ );
4892
+ }
4893
+ function currentCommitRef() {
4894
+ startCommitRefResolution();
4895
+ return ref;
4896
+ }
4897
+
4580
4898
  // src/client.ts
4581
4899
  init_constants();
4582
4900
 
@@ -5069,11 +5387,11 @@ var BitfabLangGraphCallbackHandler = class {
5069
5387
  this.invocations.set(invocation.rootRunId, invocation);
5070
5388
  }
5071
5389
  if (!willHide) {
5072
- let resolved = parentSpan;
5073
- while (resolved?.hidden === true) {
5074
- resolved = resolved.parentId ? this.runToSpan.get(resolved.parentId) : void 0;
5390
+ let resolved2 = parentSpan;
5391
+ while (resolved2?.hidden === true) {
5392
+ resolved2 = resolved2.parentId ? this.runToSpan.get(resolved2.parentId) : void 0;
5075
5393
  }
5076
- effectiveParentId = resolved ? resolved.spanId : invocation.activeContext?.spanId ?? null;
5394
+ effectiveParentId = resolved2 ? resolved2.spanId : invocation.activeContext?.spanId ?? null;
5077
5395
  } else {
5078
5396
  effectiveParentId = parentRunId ?? null;
5079
5397
  }
@@ -6573,6 +6891,7 @@ var Bitfab = class {
6573
6891
  validateDbSnapshotConfig(config.dbSnapshot);
6574
6892
  }
6575
6893
  this.dbSnapshot = config.dbSnapshot;
6894
+ startCommitRefResolution();
6576
6895
  this.httpClient = new HttpClient({
6577
6896
  apiKey: () => this.resolveApiKey(),
6578
6897
  serviceUrl: this.serviceUrl,
@@ -7666,15 +7985,15 @@ var Bitfab = class {
7666
7985
  );
7667
7986
  }
7668
7987
  return runWithSpanStack(newStack, async () => {
7669
- const resolved = await resolution;
7670
- if (resolved.matched) {
7988
+ const resolved2 = await resolution;
7989
+ if (resolved2.matched) {
7671
7990
  void sendSpan({
7672
- result: resolved.output,
7991
+ result: resolved2.output,
7673
7992
  mocked: true,
7674
7993
  mockTarget: "output",
7675
7994
  mockSource: "override"
7676
7995
  });
7677
- return resolved.output;
7996
+ return resolved2.output;
7678
7997
  }
7679
7998
  if (shouldMockWithBaseStrategy && !mockSpan) {
7680
7999
  throw new BitfabError(
@@ -7910,6 +8229,10 @@ var Bitfab = class {
7910
8229
  if (params.dbSnapshotRef) {
7911
8230
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7912
8231
  }
8232
+ const commitRef = currentCommitRef();
8233
+ if (commitRef) {
8234
+ rawTrace.commit_ref = commitRefWire(commitRef);
8235
+ }
7913
8236
  if (params.ingestionType) {
7914
8237
  rawTrace.ingestion_type = params.ingestionType;
7915
8238
  }