agent-board-runner 0.1.10 → 0.1.11

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 (3) hide show
  1. package/dist/cli.js +41 -13
  2. package/dist/index.js +41 -13
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -881,7 +881,7 @@ async function getProject(supabase, projectId) {
881
881
  return data;
882
882
  }
883
883
  async function getProjectRepos(supabase, projectId) {
884
- const { data, error } = await supabase.from("project_repos").select("subpath, dev_command, column_actions").eq("project_id", projectId);
884
+ const { data, error } = await supabase.from("project_repos").select("id, subpath, dev_command, column_actions").eq("project_id", projectId);
885
885
  if (error) throw error;
886
886
  return data;
887
887
  }
@@ -2389,6 +2389,29 @@ async function ensureBranchWatchers(supabase, config) {
2389
2389
  import { exec } from "node:child_process";
2390
2390
  import { join as join11 } from "node:path";
2391
2391
  import { promisify as promisify4 } from "node:util";
2392
+
2393
+ // src/vaultSecrets.ts
2394
+ async function resolveProjectSecretsEnv(supabase, projectId, repoId) {
2395
+ try {
2396
+ const { data, error } = await supabase.rpc("resolve_project_secrets", { p_project_id: projectId, p_repo_id: repoId });
2397
+ if (error) throw error;
2398
+ const rows = data ?? [];
2399
+ const env = {};
2400
+ for (const row of rows) env[row.name] = row.value;
2401
+ if (rows.length > 0) {
2402
+ logger.runner.info(
2403
+ "VAULT",
2404
+ `Resolved ${rows.length} secret(s) for project ${projectId}${repoId ? ` (repo ${repoId})` : ""}: ${rows.map((r) => r.name).join(", ")}.`
2405
+ );
2406
+ }
2407
+ return env;
2408
+ } catch (err) {
2409
+ logger.runner.error("VAULT", `Failed to resolve secrets for project ${projectId}${repoId ? ` (repo ${repoId})` : ""}:`, err);
2410
+ return {};
2411
+ }
2412
+ }
2413
+
2414
+ // src/columnActions.ts
2392
2415
  var execAsync = promisify4(exec);
2393
2416
  var OUTPUT_TAIL_CHARS = 4e3;
2394
2417
  function tail(text) {
@@ -2397,15 +2420,15 @@ function tail(text) {
2397
2420
  function resolveTargets(project, children, repoRoot, column, timing) {
2398
2421
  if (children.length > 0) {
2399
2422
  return children.flatMap(
2400
- (child2) => (child2.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: child2.subpath, cwd: join11(repoRoot, child2.subpath), command: action.command }))
2423
+ (child2) => (child2.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: child2.subpath, cwd: join11(repoRoot, child2.subpath), command: action.command, repoId: child2.id }))
2401
2424
  );
2402
2425
  }
2403
- return (project.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: null, cwd: repoRoot, command: action.command }));
2426
+ return (project.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: null, cwd: repoRoot, command: action.command, repoId: null }));
2404
2427
  }
2405
2428
  var EXEC_OPTIONS = { maxBuffer: 10 * 1024 * 1024 };
2406
- async function runCommand(target) {
2429
+ async function runCommand(target, extraEnv) {
2407
2430
  try {
2408
- const { stdout, stderr } = await execAsync(target.command, { ...EXEC_OPTIONS, cwd: target.cwd });
2431
+ const { stdout, stderr } = await execAsync(target.command, { ...EXEC_OPTIONS, cwd: target.cwd, env: { ...process.env, ...extraEnv } });
2409
2432
  return { ok: true, output: tail(`${stdout}${stderr}`) };
2410
2433
  } catch (err) {
2411
2434
  const { stdout, stderr } = err;
@@ -2432,7 +2455,8 @@ async function handleColumnEntered(supabase, config, card) {
2432
2455
  );
2433
2456
  let failure = null;
2434
2457
  for (const target of targets) {
2435
- const result = await runCommand(target);
2458
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
2459
+ const result = await runCommand(target, secretsEnv);
2436
2460
  if (!result.ok) {
2437
2461
  failure = { label: target.label, output: result.output };
2438
2462
  break;
@@ -2462,10 +2486,11 @@ async function clearColumnActionStatus(supabase, card) {
2462
2486
  if (card.custom_action_status === null) return;
2463
2487
  await updateCard(supabase, card.id, { customActionStatus: null, customActionOutput: null });
2464
2488
  }
2465
- async function runAfterColumnActions(project, children, repoRoot, column) {
2489
+ async function runAfterColumnActions(supabase, project, children, repoRoot, column) {
2466
2490
  const targets = resolveTargets(project, children, repoRoot, column, "after");
2467
2491
  for (const target of targets) {
2468
- const result = await runCommand(target);
2492
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
2493
+ const result = await runCommand(target, secretsEnv);
2469
2494
  if (!result.ok) {
2470
2495
  return { ok: false, error: target.label ? `${target.label}: ${result.output}` : result.output };
2471
2496
  }
@@ -2643,7 +2668,7 @@ function killProcessTree(child2) {
2643
2668
  }
2644
2669
  }
2645
2670
  var previews = /* @__PURE__ */ new Map();
2646
- function ensurePreview(key, label, cwd, command2, cardId) {
2671
+ function ensurePreview(key, label, cwd, command2, cardId, extraEnv = {}) {
2647
2672
  const existing = previews.get(key);
2648
2673
  if (existing) {
2649
2674
  existing.cardIds.add(cardId);
@@ -2651,7 +2676,7 @@ function ensurePreview(key, label, cwd, command2, cardId) {
2651
2676
  }
2652
2677
  let child2;
2653
2678
  try {
2654
- child2 = spawn4(command2, { cwd, shell: true, windowsHide: true });
2679
+ child2 = spawn4(command2, { cwd, shell: true, windowsHide: true, env: { ...process.env, ...extraEnv } });
2655
2680
  } catch (err) {
2656
2681
  logger.runner.error("DEV_SERVER", `Failed to spawn "${command2}" in ${cwd}:`, err);
2657
2682
  return Promise.resolve(null);
@@ -3490,7 +3515,7 @@ async function runDeploy(supabase, config, project) {
3490
3515
  await clearProjectDeployRequest(supabase, project.id);
3491
3516
  return;
3492
3517
  }
3493
- const columnActionResult = await runAfterColumnActions(project, children, repoRoot, "deploy");
3518
+ const columnActionResult = await runAfterColumnActions(supabase, project, children, repoRoot, "deploy");
3494
3519
  if (!columnActionResult.ok) {
3495
3520
  logger.runner.error("DEPLOY", `Deploy column action failed for project ${project.id}: ${columnActionResult.error}`);
3496
3521
  await Promise.all(cards.map((card) => updateCard(supabase, card.id, { deployError: columnActionResult.error })));
@@ -3616,13 +3641,16 @@ async function handleCardEnteredRevisao(supabase, config, card) {
3616
3641
  const project = await getProject(supabase, card.project_id);
3617
3642
  const children = await getProjectRepos(supabase, project.id);
3618
3643
  const repoRoot = resolveRepoPath(config, project.repo_path);
3619
- const targets = children.length > 0 ? children.filter((child2) => child2.dev_command).map((child2) => ({ label: child2.subpath, cwd: join15(repoRoot, child2.subpath), command: child2.dev_command })) : project.dev_command ? [{ label: "", cwd: repoRoot, command: project.dev_command }] : [];
3644
+ const targets = children.length > 0 ? children.filter((child2) => child2.dev_command).map((child2) => ({ label: child2.subpath, cwd: join15(repoRoot, child2.subpath), command: child2.dev_command, repoId: child2.id })) : project.dev_command ? [{ label: "", cwd: repoRoot, command: project.dev_command, repoId: null }] : [];
3620
3645
  if (targets.length === 0) {
3621
3646
  logger.card.info(card.id, `No dev_command configured for project ${project.id}, skipping automatic preview.`);
3622
3647
  return;
3623
3648
  }
3624
3649
  const results = await Promise.all(
3625
- targets.map((target) => ensurePreview(`${project.id}:${target.label}`, target.label, target.cwd, target.command, card.id))
3650
+ targets.map(async (target) => {
3651
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
3652
+ return ensurePreview(`${project.id}:${target.label}`, target.label, target.cwd, target.command, card.id, secretsEnv);
3653
+ })
3626
3654
  );
3627
3655
  const previews2 = results.filter((result) => result !== null);
3628
3656
  if (previews2.length === 0) {
package/dist/index.js CHANGED
@@ -719,7 +719,7 @@ async function getProject(supabase, projectId) {
719
719
  return data;
720
720
  }
721
721
  async function getProjectRepos(supabase, projectId) {
722
- const { data, error } = await supabase.from("project_repos").select("subpath, dev_command, column_actions").eq("project_id", projectId);
722
+ const { data, error } = await supabase.from("project_repos").select("id, subpath, dev_command, column_actions").eq("project_id", projectId);
723
723
  if (error) throw error;
724
724
  return data;
725
725
  }
@@ -2328,6 +2328,29 @@ async function ensureBranchWatchers(supabase, config) {
2328
2328
  import { exec } from "node:child_process";
2329
2329
  import { join as join11 } from "node:path";
2330
2330
  import { promisify as promisify4 } from "node:util";
2331
+
2332
+ // src/vaultSecrets.ts
2333
+ async function resolveProjectSecretsEnv(supabase, projectId, repoId) {
2334
+ try {
2335
+ const { data, error } = await supabase.rpc("resolve_project_secrets", { p_project_id: projectId, p_repo_id: repoId });
2336
+ if (error) throw error;
2337
+ const rows = data ?? [];
2338
+ const env = {};
2339
+ for (const row of rows) env[row.name] = row.value;
2340
+ if (rows.length > 0) {
2341
+ logger.runner.info(
2342
+ "VAULT",
2343
+ `Resolved ${rows.length} secret(s) for project ${projectId}${repoId ? ` (repo ${repoId})` : ""}: ${rows.map((r) => r.name).join(", ")}.`
2344
+ );
2345
+ }
2346
+ return env;
2347
+ } catch (err) {
2348
+ logger.runner.error("VAULT", `Failed to resolve secrets for project ${projectId}${repoId ? ` (repo ${repoId})` : ""}:`, err);
2349
+ return {};
2350
+ }
2351
+ }
2352
+
2353
+ // src/columnActions.ts
2331
2354
  var execAsync = promisify4(exec);
2332
2355
  var OUTPUT_TAIL_CHARS = 4e3;
2333
2356
  function tail(text) {
@@ -2336,15 +2359,15 @@ function tail(text) {
2336
2359
  function resolveTargets(project, children, repoRoot, column, timing) {
2337
2360
  if (children.length > 0) {
2338
2361
  return children.flatMap(
2339
- (child2) => (child2.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: child2.subpath, cwd: join11(repoRoot, child2.subpath), command: action.command }))
2362
+ (child2) => (child2.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: child2.subpath, cwd: join11(repoRoot, child2.subpath), command: action.command, repoId: child2.id }))
2340
2363
  );
2341
2364
  }
2342
- return (project.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: null, cwd: repoRoot, command: action.command }));
2365
+ return (project.column_actions[column] ?? []).filter((action) => action.timing === timing).map((action) => ({ label: null, cwd: repoRoot, command: action.command, repoId: null }));
2343
2366
  }
2344
2367
  var EXEC_OPTIONS = { maxBuffer: 10 * 1024 * 1024 };
2345
- async function runCommand(target) {
2368
+ async function runCommand(target, extraEnv) {
2346
2369
  try {
2347
- const { stdout, stderr } = await execAsync(target.command, { ...EXEC_OPTIONS, cwd: target.cwd });
2370
+ const { stdout, stderr } = await execAsync(target.command, { ...EXEC_OPTIONS, cwd: target.cwd, env: { ...process.env, ...extraEnv } });
2348
2371
  return { ok: true, output: tail(`${stdout}${stderr}`) };
2349
2372
  } catch (err) {
2350
2373
  const { stdout, stderr } = err;
@@ -2371,7 +2394,8 @@ async function handleColumnEntered(supabase, config, card) {
2371
2394
  );
2372
2395
  let failure = null;
2373
2396
  for (const target of targets) {
2374
- const result = await runCommand(target);
2397
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
2398
+ const result = await runCommand(target, secretsEnv);
2375
2399
  if (!result.ok) {
2376
2400
  failure = { label: target.label, output: result.output };
2377
2401
  break;
@@ -2401,10 +2425,11 @@ async function clearColumnActionStatus(supabase, card) {
2401
2425
  if (card.custom_action_status === null) return;
2402
2426
  await updateCard(supabase, card.id, { customActionStatus: null, customActionOutput: null });
2403
2427
  }
2404
- async function runAfterColumnActions(project, children, repoRoot, column) {
2428
+ async function runAfterColumnActions(supabase, project, children, repoRoot, column) {
2405
2429
  const targets = resolveTargets(project, children, repoRoot, column, "after");
2406
2430
  for (const target of targets) {
2407
- const result = await runCommand(target);
2431
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
2432
+ const result = await runCommand(target, secretsEnv);
2408
2433
  if (!result.ok) {
2409
2434
  return { ok: false, error: target.label ? `${target.label}: ${result.output}` : result.output };
2410
2435
  }
@@ -2582,7 +2607,7 @@ function killProcessTree(child2) {
2582
2607
  }
2583
2608
  }
2584
2609
  var previews = /* @__PURE__ */ new Map();
2585
- function ensurePreview(key, label, cwd, command, cardId) {
2610
+ function ensurePreview(key, label, cwd, command, cardId, extraEnv = {}) {
2586
2611
  const existing = previews.get(key);
2587
2612
  if (existing) {
2588
2613
  existing.cardIds.add(cardId);
@@ -2590,7 +2615,7 @@ function ensurePreview(key, label, cwd, command, cardId) {
2590
2615
  }
2591
2616
  let child2;
2592
2617
  try {
2593
- child2 = spawn4(command, { cwd, shell: true, windowsHide: true });
2618
+ child2 = spawn4(command, { cwd, shell: true, windowsHide: true, env: { ...process.env, ...extraEnv } });
2594
2619
  } catch (err) {
2595
2620
  logger.runner.error("DEV_SERVER", `Failed to spawn "${command}" in ${cwd}:`, err);
2596
2621
  return Promise.resolve(null);
@@ -3429,7 +3454,7 @@ async function runDeploy(supabase, config, project) {
3429
3454
  await clearProjectDeployRequest(supabase, project.id);
3430
3455
  return;
3431
3456
  }
3432
- const columnActionResult = await runAfterColumnActions(project, children, repoRoot, "deploy");
3457
+ const columnActionResult = await runAfterColumnActions(supabase, project, children, repoRoot, "deploy");
3433
3458
  if (!columnActionResult.ok) {
3434
3459
  logger.runner.error("DEPLOY", `Deploy column action failed for project ${project.id}: ${columnActionResult.error}`);
3435
3460
  await Promise.all(cards.map((card) => updateCard(supabase, card.id, { deployError: columnActionResult.error })));
@@ -3555,13 +3580,16 @@ async function handleCardEnteredRevisao(supabase, config, card) {
3555
3580
  const project = await getProject(supabase, card.project_id);
3556
3581
  const children = await getProjectRepos(supabase, project.id);
3557
3582
  const repoRoot = resolveRepoPath(config, project.repo_path);
3558
- const targets = children.length > 0 ? children.filter((child2) => child2.dev_command).map((child2) => ({ label: child2.subpath, cwd: join15(repoRoot, child2.subpath), command: child2.dev_command })) : project.dev_command ? [{ label: "", cwd: repoRoot, command: project.dev_command }] : [];
3583
+ const targets = children.length > 0 ? children.filter((child2) => child2.dev_command).map((child2) => ({ label: child2.subpath, cwd: join15(repoRoot, child2.subpath), command: child2.dev_command, repoId: child2.id })) : project.dev_command ? [{ label: "", cwd: repoRoot, command: project.dev_command, repoId: null }] : [];
3559
3584
  if (targets.length === 0) {
3560
3585
  logger.card.info(card.id, `No dev_command configured for project ${project.id}, skipping automatic preview.`);
3561
3586
  return;
3562
3587
  }
3563
3588
  const results = await Promise.all(
3564
- targets.map((target) => ensurePreview(`${project.id}:${target.label}`, target.label, target.cwd, target.command, card.id))
3589
+ targets.map(async (target) => {
3590
+ const secretsEnv = await resolveProjectSecretsEnv(supabase, project.id, target.repoId);
3591
+ return ensurePreview(`${project.id}:${target.label}`, target.label, target.cwd, target.command, card.id, secretsEnv);
3592
+ })
3565
3593
  );
3566
3594
  const previews2 = results.filter((result) => result !== null);
3567
3595
  if (previews2.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-board-runner",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Local runner for Agent Board — signs in with your own Supabase account (no shared secrets) and drives Claude Code against repos under your local repos root.",
5
5
  "type": "module",
6
6
  "bin": {