@hasna/testers 0.0.45 → 0.0.46

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/index.js CHANGED
@@ -59,6 +59,12 @@ function workflowExecutionFromValue(value) {
59
59
  const sandboxSyncStrategy = syncStrategyValue(input["sandboxSyncStrategy"]);
60
60
  const setupCommand = stringValue(input["setupCommand"]);
61
61
  const packageSpec = stringValue(input["packageSpec"]);
62
+ const appSourceDir = stringValue(input["appSourceDir"]);
63
+ const appRemoteDir = stringValue(input["appRemoteDir"]);
64
+ const appStartCommand = stringValue(input["appStartCommand"]);
65
+ const appUrl = stringValue(input["appUrl"]);
66
+ const appWaitUrl = stringValue(input["appWaitUrl"]);
67
+ const appWaitTimeoutMs = numberValue(input["appWaitTimeoutMs"]);
62
68
  const timeoutMs = numberValue(input["timeoutMs"]);
63
69
  const env = stringMap(input["env"]);
64
70
  return {
@@ -70,6 +76,12 @@ function workflowExecutionFromValue(value) {
70
76
  ...sandboxSyncStrategy ? { sandboxSyncStrategy } : {},
71
77
  ...setupCommand ? { setupCommand } : {},
72
78
  ...packageSpec ? { packageSpec } : {},
79
+ ...appSourceDir ? { appSourceDir } : {},
80
+ ...appRemoteDir ? { appRemoteDir } : {},
81
+ ...appStartCommand ? { appStartCommand } : {},
82
+ ...appUrl ? { appUrl } : {},
83
+ ...appWaitUrl ? { appWaitUrl } : {},
84
+ ...appWaitTimeoutMs !== undefined ? { appWaitTimeoutMs } : {},
73
85
  ...timeoutMs !== undefined ? { timeoutMs } : {},
74
86
  ...env ? { env } : {}
75
87
  };
@@ -17200,9 +17212,20 @@ function estimateCost(model, tokens) {
17200
17212
  }
17201
17213
  // src/lib/workflow-runner.ts
17202
17214
  init_database();
17203
- import { mkdtempSync, rmSync, writeFileSync as writeFileSync3 } from "fs";
17215
+ import { spawnSync } from "child_process";
17216
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, mkdtempSync, rmSync, statSync } from "fs";
17204
17217
  import { tmpdir } from "os";
17205
- import { join as join14 } from "path";
17218
+ import { join as join14, posix as pathPosix } from "path";
17219
+ var APP_SOURCE_EXCLUDES = [
17220
+ "node_modules",
17221
+ ".git",
17222
+ "dist",
17223
+ ".next",
17224
+ ".turbo",
17225
+ ".cache",
17226
+ ".venv",
17227
+ "__pycache__"
17228
+ ];
17206
17229
  function buildWorkflowRunPlan(workflow, options) {
17207
17230
  const runOptions = {
17208
17231
  url: options.url,
@@ -17244,10 +17267,16 @@ function createWorkflowDatabaseBundle(workflow, plan) {
17244
17267
  if (!plan.sandbox)
17245
17268
  throw new Error(`Workflow is not configured for sandbox execution: ${workflow.name}`);
17246
17269
  const localDir = mkdtempSync(join14(tmpdir(), `testers-workflow-${workflow.id.slice(0, 8)}-`));
17247
- writeFileSync3(join14(localDir, "testers.db"), getDatabase().serialize());
17270
+ const stateDir = join14(localDir, ".testers-state");
17271
+ mkdirSync9(stateDir, { recursive: true });
17272
+ writeDatabaseSnapshot(join14(stateDir, "testers.db"));
17273
+ if (plan.sandbox.appSourceDir && plan.sandbox.appRemoteDir) {
17274
+ const relativeAppDir = relativeRemotePath(plan.sandbox.remoteDir, plan.sandbox.appRemoteDir);
17275
+ copyAppSource(plan.sandbox.appSourceDir, join14(localDir, relativeAppDir));
17276
+ }
17248
17277
  return {
17249
17278
  localDir,
17250
- remoteDir: plan.sandbox.stateRemoteDir,
17279
+ remoteDir: plan.sandbox.remoteDir,
17251
17280
  cleanup: () => rmSync(localDir, { recursive: true, force: true })
17252
17281
  };
17253
17282
  }
@@ -17258,15 +17287,63 @@ function validatePersonaIds(workflow) {
17258
17287
  }
17259
17288
  }
17260
17289
  }
17290
+ function relativeRemotePath(remoteDir, remoteChildDir) {
17291
+ if (!remoteChildDir.startsWith("/")) {
17292
+ const relative3 = remoteChildDir.replace(/^\/+/, "").replace(/\/+$/, "");
17293
+ if (!relative3 || relative3 === ".") {
17294
+ throw new Error("Sandbox app remote directory must be a child directory, not the workflow root");
17295
+ }
17296
+ return relative3;
17297
+ }
17298
+ const base = remoteDir.replace(/\/+$/, "") || "/";
17299
+ const child = remoteChildDir.replace(/\/+$/, "") || "/";
17300
+ const relative2 = pathPosix.relative(base, child);
17301
+ if (!relative2 || relative2 === "." || relative2.startsWith("..") || pathPosix.isAbsolute(relative2)) {
17302
+ throw new Error(`Sandbox app remote directory must be inside the workflow remote directory (${remoteDir}): ${remoteChildDir}`);
17303
+ }
17304
+ return relative2;
17305
+ }
17306
+ function copyAppSource(sourceDir, targetDir) {
17307
+ if (!existsSync11(sourceDir) || !statSync(sourceDir).isDirectory()) {
17308
+ throw new Error(`Sandbox app source directory does not exist or is not a directory: ${sourceDir}`);
17309
+ }
17310
+ mkdirSync9(targetDir, { recursive: true });
17311
+ const result = spawnSync("rsync", [
17312
+ "-a",
17313
+ "--delete",
17314
+ ...APP_SOURCE_EXCLUDES.flatMap((item) => ["--exclude", item]),
17315
+ `${sourceDir.replace(/\/+$/, "")}/`,
17316
+ `${targetDir.replace(/\/+$/, "")}/`
17317
+ ], { encoding: "utf8" });
17318
+ if (result.error) {
17319
+ throw new Error(`Failed to rsync sandbox app source: ${result.error.message}`);
17320
+ }
17321
+ if (result.status !== 0) {
17322
+ throw new Error(`Failed to rsync sandbox app source (${result.status}): ${result.stderr.trim()}`);
17323
+ }
17324
+ }
17325
+ function writeDatabaseSnapshot(targetPath) {
17326
+ getDatabase().exec(`VACUUM INTO ${sqlString(targetPath)}`);
17327
+ }
17328
+ function sqlString(value) {
17329
+ return `'${value.replaceAll("'", "''")}'`;
17330
+ }
17261
17331
  function buildSandboxPlan(workflow, execution, runOptions) {
17262
17332
  const remoteDir = execution.sandboxRemoteDir ?? `/tmp/testers-workflow-${workflow.id.slice(0, 8)}`;
17263
17333
  const stateRemoteDir = `${remoteDir.replace(/\/+$/, "")}/.testers-state`;
17334
+ const appRemoteDir = execution.appSourceDir ? execution.appRemoteDir ?? `${remoteDir.replace(/\/+$/, "")}/app` : execution.appRemoteDir;
17264
17335
  return {
17265
17336
  provider: execution.provider,
17266
17337
  image: execution.sandboxImage,
17267
17338
  name: `testers-${workflow.id.slice(0, 8)}`,
17268
17339
  remoteDir,
17269
17340
  stateRemoteDir,
17341
+ ...execution.appSourceDir ? { appSourceDir: execution.appSourceDir } : {},
17342
+ ...appRemoteDir ? { appRemoteDir } : {},
17343
+ ...execution.appStartCommand ? { appStartCommand: execution.appStartCommand } : {},
17344
+ ...execution.appUrl ? { appUrl: execution.appUrl } : {},
17345
+ ...execution.appWaitUrl ? { appWaitUrl: execution.appWaitUrl } : {},
17346
+ ...execution.appWaitTimeoutMs !== undefined ? { appWaitTimeoutMs: execution.appWaitTimeoutMs } : {},
17270
17347
  cleanup: execution.sandboxCleanup ?? "delete",
17271
17348
  syncStrategy: execution.sandboxSyncStrategy ?? "rsync",
17272
17349
  timeoutMs: execution.timeoutMs,
@@ -17274,6 +17351,12 @@ function buildSandboxPlan(workflow, execution, runOptions) {
17274
17351
  command: buildSandboxCommand({
17275
17352
  runOptions,
17276
17353
  remoteDir,
17354
+ stateRemoteDir,
17355
+ appRemoteDir,
17356
+ appStartCommand: execution.appStartCommand,
17357
+ appUrl: execution.appUrl,
17358
+ appWaitUrl: execution.appWaitUrl,
17359
+ appWaitTimeoutMs: execution.appWaitTimeoutMs,
17277
17360
  dbPath: `${stateRemoteDir}/testers.db`,
17278
17361
  setupCommand: execution.setupCommand,
17279
17362
  packageSpec: execution.packageSpec ?? "@hasna/testers"
@@ -17281,11 +17364,12 @@ function buildSandboxPlan(workflow, execution, runOptions) {
17281
17364
  };
17282
17365
  }
17283
17366
  function buildSandboxCommand(input) {
17367
+ const targetUrl = input.appUrl ?? input.runOptions.url;
17284
17368
  const args = [
17285
17369
  "bunx",
17286
17370
  input.packageSpec,
17287
17371
  "run",
17288
- input.runOptions.url,
17372
+ targetUrl,
17289
17373
  ...input.runOptions.scenarioIds?.length ? ["--scenario", input.runOptions.scenarioIds.join(",")] : [],
17290
17374
  ...input.runOptions.tags?.length ? input.runOptions.tags.flatMap((tag) => ["--tag", tag]) : [],
17291
17375
  ...input.runOptions.priority ? ["--priority", input.runOptions.priority] : [],
@@ -17301,12 +17385,46 @@ function buildSandboxCommand(input) {
17301
17385
  return [
17302
17386
  "set -euo pipefail",
17303
17387
  `mkdir -p ${shellQuote(input.remoteDir)}`,
17304
- `cd ${shellQuote(input.remoteDir)}`,
17388
+ `mkdir -p ${shellQuote(input.stateRemoteDir)}`,
17389
+ input.appRemoteDir ? `mkdir -p ${shellQuote(input.appRemoteDir)}` : undefined,
17390
+ `cd ${shellQuote(input.appRemoteDir ?? input.remoteDir)}`,
17305
17391
  input.setupCommand,
17392
+ buildAppStartCommand(input),
17306
17393
  `HASNA_TESTERS_DB_PATH=${shellQuote(input.dbPath)} ${args.map(shellQuote).join(" ")}`
17307
17394
  ].filter(Boolean).join(`
17308
17395
  `);
17309
17396
  }
17397
+ function buildAppStartCommand(input) {
17398
+ if (!input.appStartCommand)
17399
+ return;
17400
+ const waitUrl = input.appWaitUrl ?? input.appUrl ?? input.runOptions.url;
17401
+ const waitTimeoutMs = input.appWaitTimeoutMs ?? 120000;
17402
+ return [
17403
+ `( ${input.appStartCommand} ) > ${shellQuote(`${input.stateRemoteDir}/app.log`)} 2>&1 &`,
17404
+ "APP_PID=$!",
17405
+ `echo "$APP_PID" > ${shellQuote(`${input.stateRemoteDir}/app.pid`)}`,
17406
+ `trap 'kill "$APP_PID" 2>/dev/null || true' EXIT`,
17407
+ waitUrl ? buildWaitForUrlCommand(waitUrl, waitTimeoutMs) : undefined
17408
+ ].filter(Boolean).join(`
17409
+ `);
17410
+ }
17411
+ function buildWaitForUrlCommand(url, timeoutMs) {
17412
+ const script = `
17413
+ const url = ${JSON.stringify(url)};
17414
+ const timeoutMs = ${JSON.stringify(timeoutMs)};
17415
+ const deadline = Date.now() + timeoutMs;
17416
+ while (Date.now() <= deadline) {
17417
+ try {
17418
+ const response = await fetch(url);
17419
+ if (response.status >= 200 && response.status < 500) process.exit(0);
17420
+ } catch {}
17421
+ await new Promise((resolve) => setTimeout(resolve, 1000));
17422
+ }
17423
+ console.error(\`Timed out waiting for \${url} after \${timeoutMs}ms\`);
17424
+ process.exit(1);
17425
+ `.trim();
17426
+ return `bun -e ${shellQuote(script)}`;
17427
+ }
17310
17428
  async function runViaSandbox(plan, dependencies) {
17311
17429
  if (!plan.sandbox)
17312
17430
  throw new Error("Workflow does not have a sandbox plan");
@@ -17829,11 +17947,11 @@ class Scheduler {
17829
17947
  }
17830
17948
  // src/lib/init.ts
17831
17949
  init_paths();
17832
- import { existsSync as existsSync11, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync9 } from "fs";
17950
+ import { existsSync as existsSync12, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync10 } from "fs";
17833
17951
  import { join as join15, basename } from "path";
17834
17952
  function detectFramework(dir) {
17835
17953
  const pkgPath = join15(dir, "package.json");
17836
- if (!existsSync11(pkgPath))
17954
+ if (!existsSync12(pkgPath))
17837
17955
  return null;
17838
17956
  let pkg;
17839
17957
  try {
@@ -18061,17 +18179,17 @@ function initProject(options) {
18061
18179
  }).filter((s) => s !== null);
18062
18180
  const configDir = getTestersDir();
18063
18181
  const configPath = join15(configDir, "config.json");
18064
- if (!existsSync11(configDir)) {
18065
- mkdirSync9(configDir, { recursive: true });
18182
+ if (!existsSync12(configDir)) {
18183
+ mkdirSync10(configDir, { recursive: true });
18066
18184
  }
18067
18185
  let config = {};
18068
- if (existsSync11(configPath)) {
18186
+ if (existsSync12(configPath)) {
18069
18187
  try {
18070
18188
  config = JSON.parse(readFileSync3(configPath, "utf-8"));
18071
18189
  } catch {}
18072
18190
  }
18073
18191
  config.activeProject = project.id;
18074
- writeFileSync4(configPath, JSON.stringify(config, null, 2), "utf-8");
18192
+ writeFileSync3(configPath, JSON.stringify(config, null, 2), "utf-8");
18075
18193
  return { project, scenarios, framework, url };
18076
18194
  }
18077
18195
  // src/lib/smoke.ts
@@ -19701,9 +19819,9 @@ function deleteAuthPreset(name) {
19701
19819
  }
19702
19820
  // src/lib/report.ts
19703
19821
  init_runs();
19704
- import { readFileSync as readFileSync4, existsSync as existsSync12 } from "fs";
19822
+ import { readFileSync as readFileSync4, existsSync as existsSync13 } from "fs";
19705
19823
  function imageToBase64(filePath) {
19706
- if (!filePath || !existsSync12(filePath))
19824
+ if (!filePath || !existsSync13(filePath))
19707
19825
  return "";
19708
19826
  try {
19709
19827
  const buffer = readFileSync4(filePath);
@@ -19992,14 +20110,14 @@ async function startWatcher(options) {
19992
20110
  }
19993
20111
  // src/lib/repo-discovery.ts
19994
20112
  init_paths();
19995
- import { existsSync as existsSync13, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync5, mkdirSync as mkdirSync10, unlinkSync } from "fs";
20113
+ import { existsSync as existsSync14, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync2, writeFileSync as writeFileSync4, mkdirSync as mkdirSync11, unlinkSync } from "fs";
19996
20114
  import { createHash } from "crypto";
19997
20115
  import { join as join16, resolve as resolve2, relative as relative2 } from "path";
19998
20116
  function getCacheDir() {
19999
20117
  const testersDir = getTestersDir();
20000
20118
  const cacheDir = join16(testersDir, "repo-index");
20001
- if (!existsSync13(cacheDir)) {
20002
- mkdirSync10(cacheDir, { recursive: true });
20119
+ if (!existsSync14(cacheDir)) {
20120
+ mkdirSync11(cacheDir, { recursive: true });
20003
20121
  }
20004
20122
  return cacheDir;
20005
20123
  }
@@ -20012,10 +20130,10 @@ function getCachePath(repoPath) {
20012
20130
  function isCacheStale(cached, repoPath) {
20013
20131
  for (const spec of cached.specs) {
20014
20132
  const fullPath = join16(repoPath, spec.file);
20015
- if (!existsSync13(fullPath))
20133
+ if (!existsSync14(fullPath))
20016
20134
  return true;
20017
20135
  try {
20018
- const stat = statSync(fullPath);
20136
+ const stat = statSync2(fullPath);
20019
20137
  if (stat.mtimeMs !== spec.mtimeMs)
20020
20138
  return true;
20021
20139
  } catch {
@@ -20024,10 +20142,10 @@ function isCacheStale(cached, repoPath) {
20024
20142
  }
20025
20143
  if (cached.configPath) {
20026
20144
  const configFullPath = join16(repoPath, cached.configPath);
20027
- if (!existsSync13(configFullPath))
20145
+ if (!existsSync14(configFullPath))
20028
20146
  return true;
20029
20147
  try {
20030
- statSync(configFullPath);
20148
+ statSync2(configFullPath);
20031
20149
  const age = Date.now() - new Date(cached.snapshotAt).getTime();
20032
20150
  if (age > 3600000)
20033
20151
  return true;
@@ -20039,7 +20157,7 @@ function isCacheStale(cached, repoPath) {
20039
20157
  }
20040
20158
  function loadCache(repoPath) {
20041
20159
  const cachePath = getCachePath(repoPath);
20042
- if (!existsSync13(cachePath))
20160
+ if (!existsSync14(cachePath))
20043
20161
  return null;
20044
20162
  try {
20045
20163
  const raw = JSON.parse(readFileSync5(cachePath, "utf-8"));
@@ -20050,14 +20168,14 @@ function loadCache(repoPath) {
20050
20168
  }
20051
20169
  function saveCache(snapshot) {
20052
20170
  const cachePath = getCachePath(snapshot.repoPath);
20053
- writeFileSync5(cachePath, JSON.stringify(snapshot, null, 2), "utf-8");
20171
+ writeFileSync4(cachePath, JSON.stringify(snapshot, null, 2), "utf-8");
20054
20172
  }
20055
20173
  function detectPackageManager(repoPath) {
20056
20174
  const result = {
20057
- npm: existsSync13(join16(repoPath, "package-lock.json")),
20058
- yarn: existsSync13(join16(repoPath, "yarn.lock")),
20059
- pnpm: existsSync13(join16(repoPath, "pnpm-lock.yaml")),
20060
- bun: existsSync13(join16(repoPath, "bun.lockb")) || existsSync13(join16(repoPath, "bun.lock")),
20175
+ npm: existsSync14(join16(repoPath, "package-lock.json")),
20176
+ yarn: existsSync14(join16(repoPath, "yarn.lock")),
20177
+ pnpm: existsSync14(join16(repoPath, "pnpm-lock.yaml")),
20178
+ bun: existsSync14(join16(repoPath, "bun.lockb")) || existsSync14(join16(repoPath, "bun.lock")),
20061
20179
  preferred: "npm"
20062
20180
  };
20063
20181
  if (result.bun)
@@ -20072,7 +20190,7 @@ function detectPackageManager(repoPath) {
20072
20190
  }
20073
20191
  function detectDevScripts(repoPath) {
20074
20192
  const pkgPath = join16(repoPath, "package.json");
20075
- if (!existsSync13(pkgPath)) {
20193
+ if (!existsSync14(pkgPath)) {
20076
20194
  return { dev: null, test: null, seed: null, build: null };
20077
20195
  }
20078
20196
  let scripts;
@@ -20098,7 +20216,7 @@ function findPlaywrightConfig(repoPath) {
20098
20216
  "playwright-ct.config.js"
20099
20217
  ];
20100
20218
  for (const name of candidates) {
20101
- if (existsSync13(join16(repoPath, name)))
20219
+ if (existsSync14(join16(repoPath, name)))
20102
20220
  return name;
20103
20221
  }
20104
20222
  return null;
@@ -20157,7 +20275,7 @@ function findSpecFiles(repoPath, globPatterns) {
20157
20275
  const dirsToSearch = ["", ".", "tests", "e2e", "test", "__tests__", "specs", "src"];
20158
20276
  for (const dir of dirsToSearch) {
20159
20277
  const searchDir = dir ? join16(repoPath, dir) : repoPath;
20160
- if (!existsSync13(searchDir))
20278
+ if (!existsSync14(searchDir))
20161
20279
  continue;
20162
20280
  try {
20163
20281
  const files = walkDir(searchDir);
@@ -20169,7 +20287,7 @@ function findSpecFiles(repoPath, globPatterns) {
20169
20287
  seen.add(relativePath);
20170
20288
  const content = readFileSync5(file, "utf-8");
20171
20289
  const contentHash = createHash("sha256").update(content).digest("hex").slice(0, 16);
20172
- const stat = statSync(file);
20290
+ const stat = statSync2(file);
20173
20291
  specs.push({
20174
20292
  file: relativePath,
20175
20293
  fromGlob: pattern,
@@ -20209,7 +20327,7 @@ function matchesGlob(filePath, pattern) {
20209
20327
  }
20210
20328
  function detectSuggestedUrl(repoPath) {
20211
20329
  const pkgPath = join16(repoPath, "package.json");
20212
- if (!existsSync13(pkgPath))
20330
+ if (!existsSync14(pkgPath))
20213
20331
  return null;
20214
20332
  try {
20215
20333
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
@@ -20229,10 +20347,10 @@ function detectSuggestedUrl(repoPath) {
20229
20347
  }
20230
20348
  function checkPlaywrightBrowserInstalled(repoPath) {
20231
20349
  const cacheDir = join16(repoPath, "node_modules", ".cache", "ms-playwright");
20232
- if (existsSync13(cacheDir))
20350
+ if (existsSync14(cacheDir))
20233
20351
  return true;
20234
20352
  const globalCache = join16(repoPath, ".cache", "ms-playwright");
20235
- if (existsSync13(globalCache))
20353
+ if (existsSync14(globalCache))
20236
20354
  return true;
20237
20355
  return false;
20238
20356
  }
@@ -20272,7 +20390,7 @@ function discoverRepo(opts) {
20272
20390
  const specs = findSpecFiles(repoPath, globPatterns);
20273
20391
  const packageManager = detectPackageManager(repoPath);
20274
20392
  const devScripts = detectDevScripts(repoPath);
20275
- const playwrightInstalled = existsSync13(join16(repoPath, "node_modules", "playwright")) || existsSync13(join16(repoPath, "node_modules", "@playwright", "test"));
20393
+ const playwrightInstalled = existsSync14(join16(repoPath, "node_modules", "playwright")) || existsSync14(join16(repoPath, "node_modules", "@playwright", "test"));
20276
20394
  const browsersInstalled = checkPlaywrightBrowserInstalled(repoPath);
20277
20395
  const configExists = configPath !== null;
20278
20396
  const specsFound = specs.length > 0;
@@ -20331,11 +20449,11 @@ function discoverRepo(opts) {
20331
20449
  }
20332
20450
  function clearDiscoveryCache(repoPath) {
20333
20451
  const cacheDir = getCacheDir();
20334
- if (!existsSync13(cacheDir))
20452
+ if (!existsSync14(cacheDir))
20335
20453
  return;
20336
20454
  if (repoPath) {
20337
20455
  const cachePath = getCachePath(repoPath);
20338
- if (existsSync13(cachePath)) {
20456
+ if (existsSync14(cachePath)) {
20339
20457
  unlinkSync(cachePath);
20340
20458
  }
20341
20459
  } else {
@@ -20348,7 +20466,7 @@ function clearDiscoveryCache(repoPath) {
20348
20466
  }
20349
20467
  function getDiscoveryCacheInfo(repoPath) {
20350
20468
  const cachePath = getCachePath(repoPath);
20351
- if (!existsSync13(cachePath))
20469
+ if (!existsSync14(cachePath))
20352
20470
  return null;
20353
20471
  const cached = loadCache(repoPath);
20354
20472
  if (!cached)
@@ -20364,11 +20482,11 @@ init_runs();
20364
20482
  init_database();
20365
20483
  init_paths();
20366
20484
  import { execSync as execSync2 } from "child_process";
20367
- import { existsSync as existsSync14, mkdirSync as mkdirSync11, writeFileSync as writeFileSync6 } from "fs";
20485
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync5 } from "fs";
20368
20486
  import { join as join17 } from "path";
20369
20487
  function resolvePlaywrightCmd(repoPath) {
20370
20488
  const localPw = join17(repoPath, "node_modules", ".bin", "playwright");
20371
- if (existsSync14(localPw)) {
20489
+ if (existsSync15(localPw)) {
20372
20490
  return [localPw, "test"];
20373
20491
  }
20374
20492
  return ["npx", "playwright", "test"];
@@ -20564,9 +20682,9 @@ async function runRepoTests(opts) {
20564
20682
  const resultRecord = { id: resultId };
20565
20683
  if (result.stdout || result.stderr) {
20566
20684
  const reportersDir = join17(getTestersDir(), "repo-run-output");
20567
- mkdirSync11(reportersDir, { recursive: true });
20685
+ mkdirSync12(reportersDir, { recursive: true });
20568
20686
  const outputFile = join17(reportersDir, `${resultRecord.id}.log`);
20569
- writeFileSync6(outputFile, `=== stdout ===
20687
+ writeFileSync5(outputFile, `=== stdout ===
20570
20688
  ${result.stdout}
20571
20689
 
20572
20690
  === stderr ===
@@ -14,6 +14,12 @@ export interface WorkflowSandboxPlan {
14
14
  name: string;
15
15
  remoteDir: string;
16
16
  stateRemoteDir: string;
17
+ appSourceDir?: string;
18
+ appRemoteDir?: string;
19
+ appStartCommand?: string;
20
+ appUrl?: string;
21
+ appWaitUrl?: string;
22
+ appWaitTimeoutMs?: number;
17
23
  command: string;
18
24
  cleanup: WorkflowSandboxCleanup;
19
25
  syncStrategy: WorkflowSandboxSyncStrategy;
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-runner.d.ts","sourceRoot":"","sources":["../../src/lib/workflow-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-runner.d.ts","sourceRoot":"","sources":["../../src/lib/workflow-runner.ts"],"names":[],"mappings":"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"}