feat: implement runCommand wrapper and refactor command executions across modules
This commit is contained in:
@@ -84,7 +84,7 @@ export function registerHeartbeatService(api: OpenClawPluginApi) {
|
||||
return;
|
||||
}
|
||||
|
||||
const agents = discoverAgents(ctx.config);
|
||||
const agents = discoverAgents(api.config);
|
||||
if (agents.length === 0) {
|
||||
ctx.logger.warn("work_heartbeat service: no DevClaw agents registered");
|
||||
return;
|
||||
@@ -117,20 +117,39 @@ export function registerHeartbeatService(api: OpenClawPluginApi) {
|
||||
/**
|
||||
* Discover DevClaw agents by scanning which agent workspaces have projects.
|
||||
* Self-discovering: any agent whose workspace contains projects/projects.json is processed.
|
||||
* Also checks the default workspace (agents.defaults.workspace) for projects.
|
||||
*/
|
||||
function discoverAgents(config: ServiceContext["config"]): Agent[] {
|
||||
const agentsList = config.agents?.list || [];
|
||||
function discoverAgents(config: {
|
||||
agents?: {
|
||||
list?: Array<{ id: string; workspace?: string }>;
|
||||
defaults?: { workspace?: string };
|
||||
};
|
||||
}): Agent[] {
|
||||
const seen = new Set<string>();
|
||||
const agents: Agent[] = [];
|
||||
|
||||
return agentsList
|
||||
.filter((a): a is { id: string; workspace: string } => {
|
||||
if (!a.workspace) return false;
|
||||
try {
|
||||
return fs.existsSync(path.join(a.workspace, "projects", "projects.json"));
|
||||
} catch {
|
||||
return false;
|
||||
// Check explicit agent list
|
||||
for (const a of config.agents?.list || []) {
|
||||
if (!a.workspace) continue;
|
||||
try {
|
||||
if (fs.existsSync(path.join(a.workspace, "projects", "projects.json"))) {
|
||||
agents.push({ agentId: a.id, workspace: a.workspace });
|
||||
seen.add(a.workspace);
|
||||
}
|
||||
})
|
||||
.map((a) => ({ agentId: a.id, workspace: a.workspace }));
|
||||
} catch { /* skip */ }
|
||||
}
|
||||
|
||||
// Check default workspace (used when no explicit agents are registered)
|
||||
const defaultWorkspace = config.agents?.defaults?.workspace;
|
||||
if (defaultWorkspace && !seen.has(defaultWorkspace)) {
|
||||
try {
|
||||
if (fs.existsSync(path.join(defaultWorkspace, "projects", "projects.json"))) {
|
||||
agents.push({ agentId: "main", workspace: defaultWorkspace });
|
||||
}
|
||||
} catch { /* skip */ }
|
||||
}
|
||||
|
||||
return agents;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +305,7 @@ async function performHealthPass(
|
||||
groupId: string,
|
||||
project: any,
|
||||
): Promise<number> {
|
||||
const { provider } = createProvider({ repo: project.repo });
|
||||
const { provider } = await createProvider({ repo: project.repo });
|
||||
let fixedCount = 0;
|
||||
|
||||
for (const role of ["dev", "qa"] as const) {
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
*
|
||||
* Replaces 7 if-blocks with a data-driven lookup table.
|
||||
*/
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import type { StateLabel, IssueProvider } from "../providers/provider.js";
|
||||
import { deactivateWorker } from "../projects.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
import { runCommand } from "../run-command.js";
|
||||
|
||||
export type CompletionRule = {
|
||||
from: StateLabel;
|
||||
@@ -84,7 +81,7 @@ export async function executeCompletion(opts: {
|
||||
// Git pull (dev:done)
|
||||
if (rule.gitPull) {
|
||||
try {
|
||||
await execFileAsync("git", ["pull"], { cwd: repoPath, timeout: 30_000 });
|
||||
await runCommand(["git", "pull"], { timeoutMs: 30_000, cwd: repoPath });
|
||||
} catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export function getRoleForLabel(label: QueueLabel): "dev" | "qa" {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function fetchProjectQueues(project: Project): Promise<Record<QueueLabel, Issue[]>> {
|
||||
const { provider } = createProvider({ repo: project.repo });
|
||||
const { provider } = await createProvider({ repo: project.repo });
|
||||
const labels: QueueLabel[] = ["To Improve", "To Test", "To Do"];
|
||||
const queues: Record<QueueLabel, Issue[]> = { "To Improve": [], "To Test": [], "To Do": [] };
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ export async function projectTick(opts: {
|
||||
const project = (await readProjects(workspaceDir)).projects[groupId];
|
||||
if (!project) return { pickups: [], skipped: [{ reason: `Project not found: ${groupId}` }] };
|
||||
|
||||
const provider = opts.provider ?? createProvider({ repo: project.repo }).provider;
|
||||
const provider = opts.provider ?? (await createProvider({ repo: project.repo })).provider;
|
||||
const roleExecution = project.roleExecution ?? "parallel";
|
||||
const roles: Array<"dev" | "qa"> = targetRole ? [targetRole] : ["dev", "qa"];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user