openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
137 lines (136 loc) • 6.98 kB
JavaScript
import { w as parseStrictPositiveInteger } from "./number-coercion-CuVhdCBs.mjs";
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { t as formatErrorMessage } from "./errors-O33D01XW.mjs";
import { r as getRuntimeConfig } from "./io.runtime-BsUXSsD4.mjs";
import { n as callGatewayFromCli, t as addGatewayClientOptions } from "./gateway-rpc-0aouJxQt.mjs";
import "./error-runtime-BmospGvZ.mjs";
import "./string-coerce-runtime-50qKeWeL.mjs";
import "./number-runtime-CgyXj1A5.mjs";
import "./runtime-config-snapshot-A-BTduWa.mjs";
import "./gateway-runtime-CAr3K4tf.mjs";
import { d as WORKBOARD_STATUSES, h as redactDispatchResult, m as redactClaimToken } from "./src-C_j7E0TD.mjs";
import { t as resolveWorkboardCardByIdOrPrefix } from "./card-lookup-BoXKYGHH.mjs";
//#region extensions/workboard/src/cli.ts
function parseMaxStarts(value) {
const parsed = parseStrictPositiveInteger(value);
if (parsed === void 0) throw Object.assign(/* @__PURE__ */ new Error("--max-starts must be a positive integer."), {
name: "InvalidArgumentError",
code: "commander.invalidArgument",
exitCode: 1
});
return parsed;
}
function writeJson(value) {
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
}
function writeLine(value) {
process.stdout.write(`${value}\n`);
}
function formatCardLine(card) {
const boardId = card.metadata?.automation?.boardId ?? "default";
const agent = card.agentId ? ` ${card.agentId}` : "";
const archived = card.metadata?.archivedAt ? " (archived)" : "";
return `${card.id.slice(0, 8)} ${card.status.padEnd(8)} ${card.priority.padEnd(6)} ${boardId}${agent} ${card.title}${archived}`;
}
function writeCards(cards, options) {
if (options.json) {
writeJson({ cards: cards.map(redactClaimToken) });
return;
}
for (const card of cards) writeLine(formatCardLine(card));
}
function writeCard(card, options) {
if (options.json) writeJson({ card: redactClaimToken(card) });
else writeLine(formatCardLine(card));
}
async function callWorkboardGateway(method, options, params) {
return await callGatewayFromCli(method, options, params, {
mode: "cli",
scopes: options.admin ? [
"operator.admin",
"operator.write",
"operator.read"
] : ["operator.write", "operator.read"]
});
}
function isGatewayUnavailableError(error) {
const message = formatErrorMessage(error).toLowerCase();
if ([
"econnrefused",
"econnreset",
"ehostunreach",
"enotfound",
"gateway not connected",
"gateway unavailable"
].some((marker) => message.includes(marker))) return true;
return message.match(/unknown method:\s*([a-z0-9._-]+)/)?.[1] === "workboard.cards.dispatch";
}
function hasExplicitGatewayTarget(options) {
return Boolean(options.url?.trim() || options.token?.trim());
}
function hasConfiguredRemoteGatewayTarget() {
if (process.env.OPENCLAW_GATEWAY_URL?.trim()) return true;
try {
return getRuntimeConfig().gateway?.mode === "remote";
} catch {
return false;
}
}
function registerWorkboardCli(params) {
const workboard = params.program.command("workboard").description("Manage Workboard cards and worker dispatch");
workboard.command("list").description("List Workboard cards").option("--board <id>", "Board id").option("--status <status>", "Filter by status").option("--include-archived", "Include archived cards (default false)").option("--json", "Print JSON", false).action(async (options) => {
let cards = await params.store.list({ boardId: options.board });
if (!options.json && options.includeArchived !== true) cards = cards.filter((card) => !card.metadata?.archivedAt);
if (options.status) cards = cards.filter((card) => card.status === options.status);
writeCards(cards, options);
});
workboard.command("create").argument("<title...>", "Card title").description("Create a Workboard card").option("--notes <text>", "Card notes").option("--status <status>", "Initial status", "todo").option("--priority <priority>", "Priority", "normal").option("--agent <id>", "Assigned agent id").option("--board <id>", "Board id").option("--labels <items>", "Comma-separated labels").option("--json", "Print JSON", false).action(async (title, options) => {
writeCard(await params.store.create({
title: title.join(" "),
notes: options.notes,
status: options.status,
priority: options.priority,
agentId: options.agent,
boardId: options.board,
labels: options.labels,
workspaceAccess: { unrestricted: true }
}), options);
});
workboard.command("show").argument("<id>", "Card id or prefix").description("Show one Workboard card").option("--json", "Print JSON", false).action(async (id, options) => {
const cards = await params.store.list();
const { card, error } = resolveWorkboardCardByIdOrPrefix(cards, id);
if (!card) throw new Error(error);
writeCard(card, options);
if (!options.json && card.notes) writeLine(card.notes);
});
workboard.command("move").argument("<id>", "Card id or prefix").description("Move a Workboard card to another status").requiredOption("--status <status>", "Target status").option("--json", "Print JSON", false).action(async (id, options) => {
if (!WORKBOARD_STATUSES.includes(options.status)) throw new Error(`--status must be one of: ${WORKBOARD_STATUSES.join(", ")}.`);
const cards = await params.store.list();
const { card, error } = resolveWorkboardCardByIdOrPrefix(cards, id);
if (!card) throw new Error(error);
writeCard(await params.store.move(card.id, options.status, void 0), options);
});
addGatewayClientOptions(workboard.command("dispatch").description("Promote ready cards and start worker runs through the Gateway").option("--board <id>", "Dispatch a single board").option("--max-starts <count>", "Maximum new worker runs to start in this pass (default 3)", parseMaxStarts).option("--admin", "Request full-host workspace access", false).option("--json", "Print JSON", false)).action(async (options) => {
try {
const result = await callWorkboardGateway(options.maxStarts === void 0 ? "workboard.cards.dispatch" : "workboard.cards.dispatchWithOptions", options, {
boardId: options.board,
...options.maxStarts !== void 0 ? { maxStarts: options.maxStarts } : {}
});
if (options.json) writeJson(result);
else {
const record = isRecord(result) ? result : {};
writeLine(`dispatch complete: started=${Array.isArray(record.started) ? record.started.length : 0} failures=${Array.isArray(record.startFailures) ? record.startFailures.length : 0}`);
}
} catch (error) {
if (!isGatewayUnavailableError(error) || hasExplicitGatewayTarget(options) || hasConfiguredRemoteGatewayTarget()) throw error;
const result = redactDispatchResult(await params.store.dispatch({ boardId: options.board }));
if (options.json) writeJson({
...result,
gatewayUnavailable: true
});
else writeLine(`gateway unavailable; data dispatch only: promoted=${result.promoted.length} blocked=${result.blocked.length}`);
}
});
}
//#endregion
export { registerWorkboardCli };