agent-board-runner 0.1.10 → 0.1.12
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/cli.js +41 -13
- package/dist/index.js +41 -13
- 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
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
|
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) =>
|
|
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.
|
|
3
|
+
"version": "0.1.12",
|
|
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": {
|