MCPcopy Create free account
hub / github.com/TestSprite/testsprite-cli / writeBundle

Function writeBundle

src/lib/bundle.ts:388–478  ·  view source on GitHub ↗
(
  ctx: CliFailureContext,
  options: WriteBundleOptions,
)

Source from the content-addressed store, hash-verified

386 * → 10 by default; the original ApiError is preserved when applicable).
387 */
388export async function writeBundle(
389 ctx: CliFailureContext,
390 options: WriteBundleOptions,
391): Promise<WriteBundleResult> {
392 const requestId = options.requestId ?? 'local';
393 assertContextIntegrity(ctx, requestId);
394
395 const filtered = options.failedOnly ? applyFailedOnly(ctx) : ctx;
396 // Re-check after filtering — in theory a buggy filter could leave a
397 // mismatched evidence list. Cheap defense-in-depth.
398 assertContextIntegrity(filtered, requestId);
399
400 const dir = resolveBundleDir(options.dir);
401 const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
402 const meta = buildMeta(filtered);
403 const codeExt = pickCodeExtension(filtered.code.language, filtered.code.framework);
404
405 await mkdir(dir, { recursive: true });
406 // Fresh `.tmp/` each run. A previous SIGKILL'd run can leave bytes
407 // behind; we don't want to mix them with the new fetch.
408 const tmpDir = await freshTmpDir(dir);
409 const stepsTmpDir = join(tmpDir, 'steps');
410 await mkdir(stepsTmpDir, { recursive: true });
411
412 const filesWritten: string[] = [];
413
414 try {
415 // result.json + failure.json + code.<ext> are local writes; no
416 // network, no streaming.
417 await writeFile(
418 join(tmpDir, 'result.json'),
419 JSON.stringify(filtered.result, null, 2) + '\n',
420 'utf8',
421 );
422 filesWritten.push('result.json');
423
424 await writeFile(
425 join(tmpDir, 'failure.json'),
426 JSON.stringify(filtered.failure, null, 2) + '\n',
427 'utf8',
428 );
429 filesWritten.push('failure.json');
430
431 const codeFile = `code.${codeExt}`;
432 if (isPresignedUrl(filtered.code.code)) {
433 // §6.3 alt: when the `code` field is a presigned URL (>= 100 KB
434 // bodies), stream the URL into the file rather than embedding
435 // the URL in code.<ext>. M2's backend hasn't shipped the
436 // >=100KB branch yet, but the contract supports it.
437 await streamUrlToFile(filtered.code.code, join(tmpDir, codeFile), fetchImpl);
438 } else {
439 await writeFile(join(tmpDir, codeFile), filtered.code.code, 'utf8');
440 }
441 filesWritten.push(codeFile);
442
443 // Optional video. Wire field is `result.videoUrl` (not in `failure`),
444 // and the CLI surfaces it as a top-level on-disk artifact for agent
445 // ergonomics — the agent doesn't have to know which sub-object held

Callers 2

runFailureGetFunction · 0.85
runArtifactGetFunction · 0.85

Calls 13

assertContextIntegrityFunction · 0.85
applyFailedOnlyFunction · 0.85
resolveBundleDirFunction · 0.85
buildMetaFunction · 0.85
pickCodeExtensionFunction · 0.85
isPresignedUrlFunction · 0.85
streamUrlToFileFunction · 0.85
writeStepArtifactsFunction · 0.85
commitBundleFunction · 0.85
writePartialMarkerFunction · 0.85
freshTmpDirFunction · 0.70
mkdirFunction · 0.50

Tested by

no test coverage detected