feat: implement runCommand wrapper and refactor command executions across modules
This commit is contained in:
@@ -1,13 +1,10 @@
|
||||
/**
|
||||
* setup/agent.ts — Agent creation and workspace resolution.
|
||||
*/
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
import { runCommand } from "../run-command.js";
|
||||
|
||||
/**
|
||||
* Create a new agent via `openclaw agents add`.
|
||||
@@ -27,7 +24,7 @@ export async function createAgent(
|
||||
if (channelBinding) args.push("--bind", channelBinding);
|
||||
|
||||
try {
|
||||
await execFileAsync("openclaw", args, { timeout: 30_000 });
|
||||
await runCommand(["openclaw", ...args], { timeoutMs: 30_000 });
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to create agent "${name}": ${(err as Error).message}`);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
*
|
||||
* Uses an LLM to understand model capabilities and assign optimal models to DevClaw roles.
|
||||
*/
|
||||
import { execSync } from "node:child_process";
|
||||
import { writeFileSync, unlinkSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { runCommand } from "../run-command.js";
|
||||
|
||||
export type ModelAssignment = {
|
||||
dev: {
|
||||
@@ -76,27 +73,18 @@ Return ONLY a JSON object in this exact format (no markdown, no explanation):
|
||||
}
|
||||
}`;
|
||||
|
||||
// Write prompt to temp file for safe passing to shell
|
||||
const tmpFile = join(tmpdir(), `devclaw-model-select-${Date.now()}.txt`);
|
||||
writeFileSync(tmpFile, prompt, "utf-8");
|
||||
|
||||
try {
|
||||
// Call openclaw agent using current session context if available
|
||||
const sessionFlag = sessionKey
|
||||
? `--session-id "${sessionKey}"`
|
||||
: `--session-id devclaw-model-selection`;
|
||||
const sessionId = sessionKey ?? "devclaw-model-selection";
|
||||
|
||||
const result = execSync(
|
||||
`openclaw agent --local ${sessionFlag} --message "$(cat ${tmpFile})" --json`,
|
||||
{
|
||||
encoding: "utf-8",
|
||||
timeout: 30000,
|
||||
stdio: ["pipe", "pipe", "ignore"],
|
||||
},
|
||||
).trim();
|
||||
const result = await runCommand(
|
||||
["openclaw", "agent", "--local", "--session-id", sessionId, "--message", prompt, "--json"],
|
||||
{ timeoutMs: 30_000 },
|
||||
);
|
||||
|
||||
const output = result.stdout.trim();
|
||||
|
||||
// Parse the response from openclaw agent --json
|
||||
const lines = result.split("\n");
|
||||
const lines = output.split("\n");
|
||||
const jsonStartIndex = lines.findIndex((line) => line.trim().startsWith("{"));
|
||||
|
||||
if (jsonStartIndex === -1) {
|
||||
@@ -146,12 +134,5 @@ Return ONLY a JSON object in this exact format (no markdown, no explanation):
|
||||
} catch (err) {
|
||||
console.error("LLM model selection failed:", (err as Error).message);
|
||||
return null;
|
||||
} finally {
|
||||
// Clean up temp file
|
||||
try {
|
||||
unlinkSync(tmpFile);
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* model-fetcher.ts — Shared helper for fetching OpenClaw models without logging.
|
||||
* model-fetcher.ts — Shared helper for fetching OpenClaw models.
|
||||
*
|
||||
* Uses execSync to bypass OpenClaw's command logging infrastructure.
|
||||
* Uses the plugin SDK's runCommand to run openclaw CLI commands.
|
||||
*/
|
||||
import { execSync } from "node:child_process";
|
||||
import { runCommand } from "../run-command.js";
|
||||
|
||||
export type OpenClawModelRow = {
|
||||
key: string;
|
||||
@@ -17,25 +17,19 @@ export type OpenClawModelRow = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch all models from OpenClaw without logging.
|
||||
* Fetch all models from OpenClaw.
|
||||
*
|
||||
* @param allModels - If true, fetches all models (--all flag). If false, only authenticated models.
|
||||
* @returns Array of model objects from OpenClaw's model registry
|
||||
*/
|
||||
export function fetchModels(allModels = true): OpenClawModelRow[] {
|
||||
export async function fetchModels(allModels = true): Promise<OpenClawModelRow[]> {
|
||||
try {
|
||||
const command = allModels
|
||||
? "openclaw models list --all --json"
|
||||
: "openclaw models list --json";
|
||||
const args = allModels
|
||||
? ["openclaw", "models", "list", "--all", "--json"]
|
||||
: ["openclaw", "models", "list", "--json"];
|
||||
|
||||
// Use execSync directly to bypass OpenClaw's command logging
|
||||
const output = execSync(command, {
|
||||
encoding: "utf-8",
|
||||
timeout: 10000,
|
||||
cwd: process.cwd(),
|
||||
// Suppress stderr to avoid any error messages
|
||||
stdio: ["pipe", "pipe", "ignore"],
|
||||
}).trim();
|
||||
const result = await runCommand(args, { timeoutMs: 10_000 });
|
||||
const output = result.stdout.trim();
|
||||
|
||||
if (!output) {
|
||||
throw new Error("Empty output from openclaw models list");
|
||||
@@ -75,7 +69,6 @@ export function fetchModels(allModels = true): OpenClawModelRow[] {
|
||||
/**
|
||||
* Fetch only authenticated models (available: true).
|
||||
*/
|
||||
export function fetchAuthenticatedModels(): OpenClawModelRow[] {
|
||||
// Use --all flag but suppress logging via stdio in fetchModels()
|
||||
return fetchModels(true).filter((m) => m.available === true);
|
||||
export async function fetchAuthenticatedModels(): Promise<OpenClawModelRow[]> {
|
||||
return (await fetchModels(true)).filter((m) => m.available === true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user