@bitfab/sdk 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-LQ32JQNZ.js → chunk-BEAGKWXY.js} +241 -21
  3. package/dist/chunk-BEAGKWXY.js.map +1 -0
  4. package/dist/{chunk-OF5GWNGU.js → chunk-IHAB7SPF.js} +3 -2
  5. package/dist/{chunk-OF5GWNGU.js.map → chunk-IHAB7SPF.js.map} +1 -1
  6. package/dist/{chunk-P2AZ7RUM.js → chunk-ITIMJ24H.js} +3 -3
  7. package/dist/chunk-ITIMJ24H.js.map +1 -0
  8. package/dist/{chunk-DP3QEGTV.js → chunk-THKLMOHS.js} +110 -13
  9. package/dist/chunk-THKLMOHS.js.map +1 -0
  10. package/dist/{chunk-MM4A6UWJ.js → chunk-VAIXHJ7O.js} +2 -2
  11. package/dist/{chunk-MM4A6UWJ.js.map → chunk-VAIXHJ7O.js.map} +1 -1
  12. package/dist/{http-UA54C2J2.js → http-6Y3IQQ2Z.js} +2 -2
  13. package/dist/{http-WBNDRQIV.js → http-KZU56HZA.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-RUONYMHD.js → replay-LZ7DIY5L.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-DP3QEGTV.js.map +0 -1
  29. package/dist/chunk-LQ32JQNZ.js.map +0 -1
  30. package/dist/chunk-P2AZ7RUM.js.map +0 -1
  31. /package/dist/{http-UA54C2J2.js.map → http-6Y3IQQ2Z.js.map} +0 -0
  32. /package/dist/{http-WBNDRQIV.js.map → http-KZU56HZA.js.map} +0 -0
  33. /package/dist/{replay-RUONYMHD.js.map → replay-LZ7DIY5L.js.map} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  flushTraces,
7
7
  parseRetryAfterMs,
8
8
  serializePayloadBody
9
- } from "./chunk-MM4A6UWJ.js";
9
+ } from "./chunk-VAIXHJ7O.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-UA54C2J2.js.map
19
+ //# sourceMappingURL=http-6Y3IQQ2Z.js.map
@@ -6,7 +6,7 @@ import {
6
6
  flushTraces,
7
7
  parseRetryAfterMs,
8
8
  serializePayloadBody
9
- } from "./chunk-OF5GWNGU.js";
9
+ } from "./chunk-IHAB7SPF.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-WBNDRQIV.js.map
20
+ //# sourceMappingURL=http-KZU56HZA.js.map
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.52.4";
45
+ __version__ = "0.52.5";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -1121,7 +1121,7 @@ var init_otel = __esm({
1121
1121
  if (this.onDelivered === void 0) {
1122
1122
  return;
1123
1123
  }
1124
- const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
1124
+ const refs = spans.map((span) => span.ref).filter((ref2) => ref2 !== void 0);
1125
1125
  if (refs.length === 0) {
1126
1126
  return;
1127
1127
  }
@@ -1378,9 +1378,9 @@ function parseRetryAfterMs(header) {
1378
1378
  }
1379
1379
  return Math.max(0, at - Date.now());
1380
1380
  }
1381
- function carrierMeta(operation, payload, ref) {
1381
+ function carrierMeta(operation, payload, ref2) {
1382
1382
  return {
1383
- ref,
1383
+ ref: ref2,
1384
1384
  name: carrierName(operation, payload),
1385
1385
  startTime: payloadTimestamp(payload, "started_at"),
1386
1386
  endTime: payloadTimestamp(payload, "ended_at"),
@@ -1625,22 +1625,22 @@ var init_http = __esm({
1625
1625
  return reports;
1626
1626
  }
1627
1627
  /** Build a carrier's meta and record what it adds to its trace's expected set. */
1628
- recordedMeta(operation, payload, ref) {
1629
- this.recordSubmittedCarrier(ref);
1630
- return carrierMeta(operation, payload, ref);
1628
+ recordedMeta(operation, payload, ref2) {
1629
+ this.recordSubmittedCarrier(ref2);
1630
+ return carrierMeta(operation, payload, ref2);
1631
1631
  }
1632
- recordSubmittedCarrier(ref) {
1633
- if (ref === void 0) {
1632
+ recordSubmittedCarrier(ref2) {
1633
+ if (ref2 === void 0) {
1634
1634
  return;
1635
1635
  }
1636
- const delivery = this.traceDeliveries.get(ref.traceId);
1636
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1637
1637
  if (delivery === void 0) {
1638
1638
  return;
1639
1639
  }
1640
- if (ref.spanId === void 0) {
1640
+ if (ref2.spanId === void 0) {
1641
1641
  delivery.closed = true;
1642
1642
  } else {
1643
- delivery.submittedSpanIds.add(ref.spanId);
1643
+ delivery.submittedSpanIds.add(ref2.spanId);
1644
1644
  }
1645
1645
  }
1646
1646
  /**
@@ -1666,15 +1666,15 @@ var init_http = __esm({
1666
1666
  }
1667
1667
  }
1668
1668
  recordDeliveredCarriers(refs) {
1669
- for (const ref of refs) {
1670
- const delivery = this.traceDeliveries.get(ref.traceId);
1669
+ for (const ref2 of refs) {
1670
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1671
1671
  if (delivery === void 0) {
1672
1672
  continue;
1673
1673
  }
1674
- if (ref.spanId === void 0) {
1674
+ if (ref2.spanId === void 0) {
1675
1675
  delivery.closingAcked = true;
1676
1676
  } else {
1677
- delivery.ackedSpanIds.add(ref.spanId);
1677
+ delivery.ackedSpanIds.add(ref2.spanId);
1678
1678
  }
1679
1679
  }
1680
1680
  }
@@ -1704,9 +1704,9 @@ var init_http = __esm({
1704
1704
  */
1705
1705
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1706
1706
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1707
- const settled = await this.settleDeferredWork(timeoutMs);
1707
+ const settled2 = await this.settleDeferredWork(timeoutMs);
1708
1708
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1709
- return settled && flushed;
1709
+ return settled2 && flushed;
1710
1710
  }
1711
1711
  /**
1712
1712
  * Flush and permanently close this client's tracing transport. Idempotent:
@@ -1719,14 +1719,14 @@ var init_http = __esm({
1719
1719
  }
1720
1720
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1721
1721
  this.closing = (async () => {
1722
- const settled = await this.settleDeferredWork(
1722
+ const settled2 = await this.settleDeferredWork(
1723
1723
  Math.max(0, deadline - Date.now())
1724
1724
  );
1725
1725
  this.closed = true;
1726
1726
  const transport = this.traceTransport;
1727
1727
  this.traceTransport = void 0;
1728
1728
  const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
1729
- return settled && shutdownOk;
1729
+ return settled2 && shutdownOk;
1730
1730
  })();
1731
1731
  return this.closing;
1732
1732
  }
@@ -2337,6 +2337,112 @@ var init_randomUuid = __esm({
2337
2337
  }
2338
2338
  });
2339
2339
 
2340
+ // src/gitCommand.ts
2341
+ function isUnrefable(value) {
2342
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
2343
+ }
2344
+ function unrefStream(stream) {
2345
+ if (isUnrefable(stream)) {
2346
+ stream.unref();
2347
+ }
2348
+ }
2349
+ function terminate(child) {
2350
+ if (child.pid && process.platform !== "win32") {
2351
+ try {
2352
+ process.kill(-child.pid, "SIGTERM");
2353
+ return;
2354
+ } catch {
2355
+ child.kill("SIGTERM");
2356
+ return;
2357
+ }
2358
+ }
2359
+ child.kill("SIGTERM");
2360
+ }
2361
+ async function gitRunner(options) {
2362
+ let spawn;
2363
+ try {
2364
+ ;
2365
+ ({ spawn } = await import("child_process"));
2366
+ } catch {
2367
+ return null;
2368
+ }
2369
+ return (dir, args) => new Promise((resolve) => {
2370
+ let child;
2371
+ try {
2372
+ child = spawn("git", args, {
2373
+ cwd: dir,
2374
+ detached: process.platform !== "win32",
2375
+ stdio: ["ignore", "pipe", "pipe"]
2376
+ });
2377
+ } catch {
2378
+ resolve(null);
2379
+ return;
2380
+ }
2381
+ const chunks = [];
2382
+ let size = 0;
2383
+ let overflow = false;
2384
+ let exitCode = null;
2385
+ let done = false;
2386
+ const timers = [];
2387
+ const schedule = (callback, ms) => {
2388
+ const timer = setTimeout(callback, ms);
2389
+ if (!options.keepProcessAlive) {
2390
+ timer.unref();
2391
+ }
2392
+ timers.push(timer);
2393
+ };
2394
+ const finish = () => {
2395
+ if (done) {
2396
+ return;
2397
+ }
2398
+ done = true;
2399
+ for (const timer of timers) {
2400
+ clearTimeout(timer);
2401
+ }
2402
+ child.stdout?.destroy();
2403
+ child.stderr?.destroy();
2404
+ resolve(
2405
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
2406
+ );
2407
+ };
2408
+ child.stdout?.on("data", (chunk) => {
2409
+ size += chunk.length;
2410
+ if (size > options.maxBuffer) {
2411
+ overflow = true;
2412
+ terminate(child);
2413
+ return;
2414
+ }
2415
+ chunks.push(chunk);
2416
+ });
2417
+ child.stderr?.resume();
2418
+ child.on("error", () => {
2419
+ exitCode = null;
2420
+ finish();
2421
+ });
2422
+ child.on("exit", (code) => {
2423
+ exitCode = code;
2424
+ schedule(finish, EXIT_GRACE_MS);
2425
+ });
2426
+ child.on("close", (code) => {
2427
+ exitCode = code ?? exitCode;
2428
+ finish();
2429
+ });
2430
+ schedule(() => terminate(child), options.timeoutMs);
2431
+ if (!options.keepProcessAlive) {
2432
+ child.unref();
2433
+ unrefStream(child.stdout);
2434
+ unrefStream(child.stderr);
2435
+ }
2436
+ });
2437
+ }
2438
+ var EXIT_GRACE_MS;
2439
+ var init_gitCommand = __esm({
2440
+ "src/gitCommand.ts"() {
2441
+ "use strict";
2442
+ EXIT_GRACE_MS = 500;
2443
+ }
2444
+ });
2445
+
2340
2446
  // src/mockOverride.ts
2341
2447
  function resolveMockValue(value, ctx) {
2342
2448
  return typeof value === "function" ? value(ctx) : value;
@@ -2393,37 +2499,33 @@ async function readCodeChangeFile() {
2393
2499
  }
2394
2500
  }
2395
2501
  async function captureCodeChangeFromGit(cwd, label) {
2396
- let execFile;
2397
2502
  let readFile;
2398
2503
  try {
2399
2504
  ;
2400
- ({ execFile } = await import("child_process"));
2401
2505
  ({ readFile } = await import("fs/promises"));
2402
2506
  } catch {
2403
2507
  return null;
2404
2508
  }
2405
- const git = (dir, args) => new Promise((resolve) => {
2406
- execFile(
2407
- "git",
2408
- args,
2409
- // 30s timeout so a hung git (e.g. a network-touching ref op) can't
2410
- // block the whole replay indefinitely.
2411
- { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 3e4 },
2412
- (err, stdout) => resolve(err ? null : stdout)
2413
- );
2509
+ const git = await gitRunner({
2510
+ timeoutMs: 3e4,
2511
+ maxBuffer: 64 * 1024 * 1024,
2512
+ keepProcessAlive: true
2414
2513
  });
2514
+ if (!git) {
2515
+ return null;
2516
+ }
2415
2517
  try {
2416
2518
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
2417
2519
  if (!root) {
2418
2520
  return null;
2419
2521
  }
2420
- const resolved = await resolveBase(git, root);
2421
- if (!resolved) {
2522
+ const resolved2 = await resolveBase(git, root);
2523
+ if (!resolved2) {
2422
2524
  return null;
2423
2525
  }
2424
- const { base, fromTrunk } = resolved;
2425
- const blobBytes = async (ref, path) => {
2426
- const out = await git(root, ["cat-file", "-s", `${ref}:${path}`]);
2526
+ const { base, fromTrunk } = resolved2;
2527
+ const blobBytes = async (ref2, path) => {
2528
+ const out = await git(root, ["cat-file", "-s", `${ref2}:${path}`]);
2427
2529
  const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN;
2428
2530
  return Number.isFinite(n) ? n : 0;
2429
2531
  };
@@ -2515,8 +2617,8 @@ async function resolveBase(git, root) {
2515
2617
  }
2516
2618
  return await refExists(git, root, "HEAD") ? { base: "HEAD", fromTrunk: false } : null;
2517
2619
  }
2518
- async function refExists(git, root, ref) {
2519
- return await git(root, ["rev-parse", "--verify", `${ref}^{object}`]) !== null;
2620
+ async function refExists(git, root, ref2) {
2621
+ return await git(root, ["rev-parse", "--verify", `${ref2}^{object}`]) !== null;
2520
2622
  }
2521
2623
  async function readWorkingFile(readFile, root, path) {
2522
2624
  try {
@@ -2551,6 +2653,7 @@ var MAX_FILES, MAX_FILE_BYTES, MAX_TOTAL_BYTES, TRUNK_CANDIDATES, NUL;
2551
2653
  var init_codeChange = __esm({
2552
2654
  "src/codeChange.ts"() {
2553
2655
  "use strict";
2656
+ init_gitCommand();
2554
2657
  MAX_FILES = 60;
2555
2658
  MAX_FILE_BYTES = 5e5;
2556
2659
  MAX_TOTAL_BYTES = 2e6;
@@ -2755,9 +2858,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2755
2858
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2756
2859
  try {
2757
2860
  if (includeDbBranchLease && !lease && !leaseError) {
2758
- let resolved;
2861
+ let resolved2;
2759
2862
  try {
2760
- resolved = await httpClient.resolveDbBranchLease(
2863
+ resolved2 = await httpClient.resolveDbBranchLease(
2761
2864
  testRunId,
2762
2865
  originalTraceId,
2763
2866
  dbBranchSettings,
@@ -2771,10 +2874,10 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2771
2874
  cause
2772
2875
  );
2773
2876
  }
2774
- lease = resolved.lease ?? void 0;
2775
- leaseError = resolved.leaseError ?? void 0;
2776
- dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2777
- dbBranchTimings = resolved.timings ?? dbBranchTimings;
2877
+ lease = resolved2.lease ?? void 0;
2878
+ leaseError = resolved2.leaseError ?? void 0;
2879
+ dbSnapshotRef = resolved2.dbSnapshotRef ?? dbSnapshotRef;
2880
+ dbBranchTimings = resolved2.timings ?? dbBranchTimings;
2778
2881
  }
2779
2882
  if (leaseError) {
2780
2883
  throw new DbBranchReplayError(
@@ -4550,24 +4653,239 @@ function mixedTracingError(enteredApi, entered, enclosing, traceFunctionKey) {
4550
4653
  `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]}`
4551
4654
  );
4552
4655
  }
4553
- function assertSurfacesCompatible(requested, resolved, parentSurface, traceFunctionKey) {
4656
+ function assertSurfacesCompatible(requested, resolved2, parentSurface, traceFunctionKey) {
4554
4657
  if (requested === "inherit" || requested === "neutral") {
4555
4658
  return;
4556
4659
  }
4557
- if (resolved === void 0 || parentSurface === void 0) {
4660
+ if (resolved2 === void 0 || parentSurface === void 0) {
4558
4661
  return;
4559
4662
  }
4560
- if (parentSurface === resolved) {
4663
+ if (parentSurface === resolved2) {
4561
4664
  return;
4562
4665
  }
4563
4666
  throw mixedTracingError(
4564
- SURFACE_API[resolved],
4565
- resolved,
4667
+ SURFACE_API[resolved2],
4668
+ resolved2,
4566
4669
  parentSurface,
4567
4670
  traceFunctionKey
4568
4671
  );
4569
4672
  }
4570
4673
 
4674
+ // src/commitRef.ts
4675
+ init_gitCommand();
4676
+ init_readEnv();
4677
+ var EXPLICIT_SHA_ENV = "BITFAB_COMMIT_SHA";
4678
+ var DISABLE_ENV = "BITFAB_DISABLE_COMMIT_REF";
4679
+ var GIT_TIMEOUT_MS = 2e3;
4680
+ var GIT_MAX_BUFFER = 1024 * 1024;
4681
+ var VERCEL_PROVIDER_HOSTS = {
4682
+ github: "github.com",
4683
+ gitlab: "gitlab.com",
4684
+ bitbucket: "bitbucket.org"
4685
+ };
4686
+ function read(env, name) {
4687
+ if (name === null) {
4688
+ return null;
4689
+ }
4690
+ const value = env(name)?.trim();
4691
+ return value ? value : null;
4692
+ }
4693
+ function remoteFrom(...names) {
4694
+ return (env) => {
4695
+ const parts = names.map((name) => read(env, name));
4696
+ if (parts.some((part) => part === null)) {
4697
+ return null;
4698
+ }
4699
+ return normalizeRemote(parts.join("/"));
4700
+ };
4701
+ }
4702
+ function vercelRemote(env) {
4703
+ const provider = read(env, "VERCEL_GIT_PROVIDER")?.toLowerCase() ?? "";
4704
+ const host = VERCEL_PROVIDER_HOSTS[provider];
4705
+ const owner = read(env, "VERCEL_GIT_REPO_OWNER");
4706
+ const slug = read(env, "VERCEL_GIT_REPO_SLUG");
4707
+ if (!host || !owner || !slug) {
4708
+ return null;
4709
+ }
4710
+ return `${host}/${owner}/${slug}`;
4711
+ }
4712
+ function noRemote() {
4713
+ return null;
4714
+ }
4715
+ var PLATFORM_ENVS = [
4716
+ ["VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF", vercelRemote],
4717
+ [
4718
+ "GITHUB_SHA",
4719
+ "GITHUB_REF_NAME",
4720
+ remoteFrom("GITHUB_SERVER_URL", "GITHUB_REPOSITORY")
4721
+ ],
4722
+ ["RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH", noRemote],
4723
+ ["RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH", noRemote],
4724
+ ["SOURCE_VERSION", null, noRemote],
4725
+ ["CF_PAGES_COMMIT_SHA", "CF_PAGES_BRANCH", noRemote],
4726
+ ["CI_COMMIT_SHA", "CI_COMMIT_REF_NAME", remoteFrom("CI_REPOSITORY_URL")],
4727
+ [
4728
+ "BUILD_SOURCEVERSION",
4729
+ "BUILD_SOURCEBRANCHNAME",
4730
+ remoteFrom("BUILD_REPOSITORY_URI")
4731
+ ],
4732
+ ["CIRCLE_SHA1", "CIRCLE_BRANCH", remoteFrom("CIRCLE_REPOSITORY_URL")]
4733
+ ];
4734
+ var COMMIT_REF_ENV_NAMES = [
4735
+ EXPLICIT_SHA_ENV,
4736
+ DISABLE_ENV,
4737
+ ...PLATFORM_ENVS.flatMap(
4738
+ ([sha, branch]) => branch === null ? [sha] : [sha, branch]
4739
+ ),
4740
+ "GITHUB_SERVER_URL",
4741
+ "GITHUB_REPOSITORY",
4742
+ "CI_REPOSITORY_URL",
4743
+ "BUILD_REPOSITORY_URI",
4744
+ "CIRCLE_REPOSITORY_URL",
4745
+ "VERCEL_GIT_PROVIDER",
4746
+ "VERCEL_GIT_REPO_OWNER",
4747
+ "VERCEL_GIT_REPO_SLUG"
4748
+ ];
4749
+ function normalizeRemote(raw) {
4750
+ const value = raw?.trim();
4751
+ if (!value) {
4752
+ return null;
4753
+ }
4754
+ let host = "";
4755
+ let path = value;
4756
+ if (value.includes("://")) {
4757
+ try {
4758
+ const parsed = new URL(value);
4759
+ host = parsed.hostname;
4760
+ path = parsed.pathname;
4761
+ } catch {
4762
+ return null;
4763
+ }
4764
+ } else {
4765
+ const separator = value.indexOf(":");
4766
+ if (separator !== -1) {
4767
+ const head = value.slice(0, separator);
4768
+ host = head.slice(head.lastIndexOf("@") + 1);
4769
+ path = value.slice(separator + 1);
4770
+ }
4771
+ }
4772
+ path = path.replace(/^\/+|\/+$/g, "");
4773
+ if (path.endsWith(".git")) {
4774
+ path = path.slice(0, -".git".length).replace(/\/+$/, "");
4775
+ }
4776
+ if (!host) {
4777
+ return path || null;
4778
+ }
4779
+ return path ? `${host}/${path}` : host;
4780
+ }
4781
+ function resolveCommitRefFromEnv(env) {
4782
+ const explicit = read(env, EXPLICIT_SHA_ENV);
4783
+ const platform = PLATFORM_ENVS.find(([sha]) => read(env, sha) !== null);
4784
+ if (!platform) {
4785
+ if (explicit === null) {
4786
+ return null;
4787
+ }
4788
+ return {
4789
+ sha: explicit,
4790
+ branch: null,
4791
+ dirty: null,
4792
+ remote: null,
4793
+ rootSha: null
4794
+ };
4795
+ }
4796
+ const [shaEnv, branchEnv, readRemote] = platform;
4797
+ return {
4798
+ sha: explicit ?? read(env, shaEnv),
4799
+ branch: read(env, branchEnv),
4800
+ dirty: null,
4801
+ remote: readRemote(env),
4802
+ rootSha: null
4803
+ };
4804
+ }
4805
+ async function resolveCommitRefFromGit(cwd) {
4806
+ const git = await gitRunner({
4807
+ timeoutMs: GIT_TIMEOUT_MS,
4808
+ maxBuffer: GIT_MAX_BUFFER,
4809
+ keepProcessAlive: false
4810
+ });
4811
+ if (!git) {
4812
+ return null;
4813
+ }
4814
+ const run = async (args) => (await git(cwd, args))?.trim() ?? null;
4815
+ const sha = await run(["rev-parse", "HEAD"]);
4816
+ if (!sha) {
4817
+ return null;
4818
+ }
4819
+ const [branch, status, remote, roots] = await Promise.all([
4820
+ run(["symbolic-ref", "--short", "-q", "HEAD"]),
4821
+ run(["status", "--porcelain"]),
4822
+ run(["remote", "get-url", "origin"]),
4823
+ run(["rev-list", "--max-parents=0", "HEAD"])
4824
+ ]);
4825
+ return {
4826
+ sha,
4827
+ branch: branch || null,
4828
+ dirty: status === null ? null : status.length > 0,
4829
+ remote: normalizeRemote(remote),
4830
+ rootSha: roots ? roots.split(/\s+/).sort()[0] ?? null : null
4831
+ };
4832
+ }
4833
+ function commitRefWire(ref2) {
4834
+ return {
4835
+ sha: ref2.sha,
4836
+ branch: ref2.branch,
4837
+ dirty: ref2.dirty,
4838
+ remote: ref2.remote,
4839
+ root_sha: ref2.rootSha
4840
+ };
4841
+ }
4842
+ var resolved = false;
4843
+ var ref = null;
4844
+ var gitStarted = false;
4845
+ var settled = Promise.resolve();
4846
+ function startCommitRefResolution() {
4847
+ if (resolved || gitStarted) {
4848
+ return;
4849
+ }
4850
+ if (read(readEnv, DISABLE_ENV) !== null) {
4851
+ resolved = true;
4852
+ return;
4853
+ }
4854
+ const fromEnv = resolveCommitRefFromEnv(readEnv);
4855
+ if (fromEnv) {
4856
+ ref = fromEnv;
4857
+ resolved = true;
4858
+ return;
4859
+ }
4860
+ gitStarted = true;
4861
+ if (typeof process === "undefined") {
4862
+ resolved = true;
4863
+ return;
4864
+ }
4865
+ let cwd;
4866
+ try {
4867
+ cwd = process.cwd?.() ?? ".";
4868
+ } catch {
4869
+ resolved = true;
4870
+ return;
4871
+ }
4872
+ settled = resolveCommitRefFromGit(cwd).then(
4873
+ (fromGit) => {
4874
+ if (!resolved) {
4875
+ ref = fromGit;
4876
+ resolved = true;
4877
+ }
4878
+ },
4879
+ () => {
4880
+ resolved = true;
4881
+ }
4882
+ );
4883
+ }
4884
+ function currentCommitRef() {
4885
+ startCommitRefResolution();
4886
+ return ref;
4887
+ }
4888
+
4571
4889
  // src/client.ts
4572
4890
  init_constants();
4573
4891
 
@@ -5060,11 +5378,11 @@ var BitfabLangGraphCallbackHandler = class {
5060
5378
  this.invocations.set(invocation.rootRunId, invocation);
5061
5379
  }
5062
5380
  if (!willHide) {
5063
- let resolved = parentSpan;
5064
- while (resolved?.hidden === true) {
5065
- resolved = resolved.parentId ? this.runToSpan.get(resolved.parentId) : void 0;
5381
+ let resolved2 = parentSpan;
5382
+ while (resolved2?.hidden === true) {
5383
+ resolved2 = resolved2.parentId ? this.runToSpan.get(resolved2.parentId) : void 0;
5066
5384
  }
5067
- effectiveParentId = resolved ? resolved.spanId : invocation.activeContext?.spanId ?? null;
5385
+ effectiveParentId = resolved2 ? resolved2.spanId : invocation.activeContext?.spanId ?? null;
5068
5386
  } else {
5069
5387
  effectiveParentId = parentRunId ?? null;
5070
5388
  }
@@ -6564,6 +6882,7 @@ var Bitfab = class {
6564
6882
  validateDbSnapshotConfig(config.dbSnapshot);
6565
6883
  }
6566
6884
  this.dbSnapshot = config.dbSnapshot;
6885
+ startCommitRefResolution();
6567
6886
  this.httpClient = new HttpClient({
6568
6887
  apiKey: () => this.resolveApiKey(),
6569
6888
  serviceUrl: this.serviceUrl,
@@ -7657,15 +7976,15 @@ var Bitfab = class {
7657
7976
  );
7658
7977
  }
7659
7978
  return runWithSpanStack(newStack, async () => {
7660
- const resolved = await resolution;
7661
- if (resolved.matched) {
7979
+ const resolved2 = await resolution;
7980
+ if (resolved2.matched) {
7662
7981
  void sendSpan({
7663
- result: resolved.output,
7982
+ result: resolved2.output,
7664
7983
  mocked: true,
7665
7984
  mockTarget: "output",
7666
7985
  mockSource: "override"
7667
7986
  });
7668
- return resolved.output;
7987
+ return resolved2.output;
7669
7988
  }
7670
7989
  if (shouldMockWithBaseStrategy && !mockSpan) {
7671
7990
  throw new BitfabError(
@@ -7901,6 +8220,10 @@ var Bitfab = class {
7901
8220
  if (params.dbSnapshotRef) {
7902
8221
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7903
8222
  }
8223
+ const commitRef = currentCommitRef();
8224
+ if (commitRef) {
8225
+ rawTrace.commit_ref = commitRefWire(commitRef);
8226
+ }
7904
8227
  if (params.ingestionType) {
7905
8228
  rawTrace.ingestion_type = params.ingestionType;
7906
8229
  }