mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 21:31:26 +00:00
refactor: move tasks into bundled plugin
This commit is contained in:
@@ -10,12 +10,6 @@ const mocks = vi.hoisted(() => ({
|
||||
flowsCancelCommand: vi.fn(),
|
||||
sessionsCommand: vi.fn(),
|
||||
sessionsCleanupCommand: vi.fn(),
|
||||
tasksListCommand: vi.fn(),
|
||||
tasksAuditCommand: vi.fn(),
|
||||
tasksMaintenanceCommand: vi.fn(),
|
||||
tasksShowCommand: vi.fn(),
|
||||
tasksNotifyCommand: vi.fn(),
|
||||
tasksCancelCommand: vi.fn(),
|
||||
setVerbose: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
@@ -31,12 +25,6 @@ const flowsShowCommand = mocks.flowsShowCommand;
|
||||
const flowsCancelCommand = mocks.flowsCancelCommand;
|
||||
const sessionsCommand = mocks.sessionsCommand;
|
||||
const sessionsCleanupCommand = mocks.sessionsCleanupCommand;
|
||||
const tasksListCommand = mocks.tasksListCommand;
|
||||
const tasksAuditCommand = mocks.tasksAuditCommand;
|
||||
const tasksMaintenanceCommand = mocks.tasksMaintenanceCommand;
|
||||
const tasksShowCommand = mocks.tasksShowCommand;
|
||||
const tasksNotifyCommand = mocks.tasksNotifyCommand;
|
||||
const tasksCancelCommand = mocks.tasksCancelCommand;
|
||||
const setVerbose = mocks.setVerbose;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
@@ -62,15 +50,6 @@ vi.mock("../../commands/sessions-cleanup.js", () => ({
|
||||
sessionsCleanupCommand: mocks.sessionsCleanupCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/tasks.js", () => ({
|
||||
tasksListCommand: mocks.tasksListCommand,
|
||||
tasksAuditCommand: mocks.tasksAuditCommand,
|
||||
tasksMaintenanceCommand: mocks.tasksMaintenanceCommand,
|
||||
tasksShowCommand: mocks.tasksShowCommand,
|
||||
tasksNotifyCommand: mocks.tasksNotifyCommand,
|
||||
tasksCancelCommand: mocks.tasksCancelCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../globals.js", () => ({
|
||||
setVerbose: mocks.setVerbose,
|
||||
}));
|
||||
@@ -96,12 +75,6 @@ describe("registerStatusHealthSessionsCommands", () => {
|
||||
flowsCancelCommand.mockResolvedValue(undefined);
|
||||
sessionsCommand.mockResolvedValue(undefined);
|
||||
sessionsCleanupCommand.mockResolvedValue(undefined);
|
||||
tasksListCommand.mockResolvedValue(undefined);
|
||||
tasksAuditCommand.mockResolvedValue(undefined);
|
||||
tasksMaintenanceCommand.mockResolvedValue(undefined);
|
||||
tasksShowCommand.mockResolvedValue(undefined);
|
||||
tasksNotifyCommand.mockResolvedValue(undefined);
|
||||
tasksCancelCommand.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
it("runs status command with timeout and debug-derived verbose", async () => {
|
||||
@@ -249,90 +222,6 @@ describe("registerStatusHealthSessionsCommands", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks list from the parent command", async () => {
|
||||
await runCli(["tasks", "--json", "--runtime", "acp", "--status", "running"]);
|
||||
|
||||
expect(tasksListCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
json: true,
|
||||
runtime: "acp",
|
||||
status: "running",
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks show subcommand with lookup forwarding", async () => {
|
||||
await runCli(["tasks", "show", "run-123", "--json"]);
|
||||
|
||||
expect(tasksShowCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
lookup: "run-123",
|
||||
json: true,
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks maintenance subcommand with apply forwarding", async () => {
|
||||
await runCli(["tasks", "--json", "maintenance", "--apply"]);
|
||||
|
||||
expect(tasksMaintenanceCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
json: true,
|
||||
apply: true,
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks audit subcommand with filters", async () => {
|
||||
await runCli([
|
||||
"tasks",
|
||||
"--json",
|
||||
"audit",
|
||||
"--severity",
|
||||
"error",
|
||||
"--code",
|
||||
"stale_running",
|
||||
"--limit",
|
||||
"5",
|
||||
]);
|
||||
|
||||
expect(tasksAuditCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
json: true,
|
||||
severity: "error",
|
||||
code: "stale_running",
|
||||
limit: 5,
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks notify subcommand with lookup and policy forwarding", async () => {
|
||||
await runCli(["tasks", "notify", "run-123", "state_changes"]);
|
||||
|
||||
expect(tasksNotifyCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
lookup: "run-123",
|
||||
notify: "state_changes",
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs tasks cancel subcommand with lookup forwarding", async () => {
|
||||
await runCli(["tasks", "cancel", "run-123"]);
|
||||
|
||||
expect(tasksCancelCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
lookup: "run-123",
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
});
|
||||
|
||||
it("runs flows list from the parent command", async () => {
|
||||
await runCli(["flows", "--json", "--status", "blocked"]);
|
||||
|
||||
|
||||
@@ -4,28 +4,24 @@ import { healthCommand } from "../../commands/health.js";
|
||||
import { sessionsCleanupCommand } from "../../commands/sessions-cleanup.js";
|
||||
import { sessionsCommand } from "../../commands/sessions.js";
|
||||
import { statusCommand } from "../../commands/status.js";
|
||||
import {
|
||||
tasksAuditCommand,
|
||||
tasksCancelCommand,
|
||||
tasksListCommand,
|
||||
tasksMaintenanceCommand,
|
||||
tasksNotifyCommand,
|
||||
tasksShowCommand,
|
||||
} from "../../commands/tasks.js";
|
||||
import { setVerbose } from "../../globals.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { formatDocsLink } from "../../terminal/links.js";
|
||||
import { theme } from "../../terminal/theme.js";
|
||||
import { runCommandWithRuntime } from "../cli-utils.js";
|
||||
import { formatHelpExamples } from "../help-format.js";
|
||||
import { parsePositiveIntOrUndefined } from "./helpers.js";
|
||||
|
||||
function resolveVerbose(opts: { verbose?: boolean; debug?: boolean }): boolean {
|
||||
return Boolean(opts.verbose || opts.debug);
|
||||
}
|
||||
|
||||
function parseTimeoutMs(timeout: unknown): number | null | undefined {
|
||||
const parsed = parsePositiveIntOrUndefined(timeout);
|
||||
const parsedRaw =
|
||||
typeof timeout === "string" && timeout.trim() ? Number.parseInt(timeout, 10) : undefined;
|
||||
const parsed =
|
||||
typeof parsedRaw === "number" && Number.isFinite(parsedRaw) && parsedRaw > 0
|
||||
? parsedRaw
|
||||
: undefined;
|
||||
if (timeout !== undefined && parsed === undefined) {
|
||||
defaultRuntime.error("--timeout must be a positive integer (milliseconds)");
|
||||
defaultRuntime.exit(1);
|
||||
@@ -222,159 +218,6 @@ export function registerStatusHealthSessionsCommands(program: Command) {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const tasksCmd = program
|
||||
.command("tasks")
|
||||
.description("Inspect durable background task state")
|
||||
.option("--json", "Output as JSON", false)
|
||||
.option("--runtime <name>", "Filter by kind (subagent, acp, cron, cli)")
|
||||
.option(
|
||||
"--status <name>",
|
||||
"Filter by status (queued, running, succeeded, failed, timed_out, cancelled, lost)",
|
||||
)
|
||||
.action(async (opts) => {
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksListCommand(
|
||||
{
|
||||
json: Boolean(opts.json),
|
||||
runtime: opts.runtime as string | undefined,
|
||||
status: opts.status as string | undefined,
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
tasksCmd.enablePositionalOptions();
|
||||
|
||||
tasksCmd
|
||||
.command("list")
|
||||
.description("List tracked background tasks")
|
||||
.option("--json", "Output as JSON", false)
|
||||
.option("--runtime <name>", "Filter by kind (subagent, acp, cron, cli)")
|
||||
.option(
|
||||
"--status <name>",
|
||||
"Filter by status (queued, running, succeeded, failed, timed_out, cancelled, lost)",
|
||||
)
|
||||
.action(async (opts, command) => {
|
||||
const parentOpts = command.parent?.opts() as
|
||||
| {
|
||||
json?: boolean;
|
||||
runtime?: string;
|
||||
status?: string;
|
||||
}
|
||||
| undefined;
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksListCommand(
|
||||
{
|
||||
json: Boolean(opts.json || parentOpts?.json),
|
||||
runtime: (opts.runtime as string | undefined) ?? parentOpts?.runtime,
|
||||
status: (opts.status as string | undefined) ?? parentOpts?.status,
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
tasksCmd
|
||||
.command("audit")
|
||||
.description("Show stale or broken background task runs")
|
||||
.option("--json", "Output as JSON", false)
|
||||
.option("--severity <level>", "Filter by severity (warn, error)")
|
||||
.option(
|
||||
"--code <name>",
|
||||
"Filter by finding code (stale_queued, stale_running, lost, delivery_failed, missing_cleanup, inconsistent_timestamps)",
|
||||
)
|
||||
.option("--limit <n>", "Limit displayed findings")
|
||||
.action(async (opts, command) => {
|
||||
const parentOpts = command.parent?.opts() as { json?: boolean } | undefined;
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksAuditCommand(
|
||||
{
|
||||
json: Boolean(opts.json || parentOpts?.json),
|
||||
severity: opts.severity as "warn" | "error" | undefined,
|
||||
code: opts.code as
|
||||
| "stale_queued"
|
||||
| "stale_running"
|
||||
| "lost"
|
||||
| "delivery_failed"
|
||||
| "missing_cleanup"
|
||||
| "inconsistent_timestamps"
|
||||
| undefined,
|
||||
limit: parsePositiveIntOrUndefined(opts.limit),
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
tasksCmd
|
||||
.command("maintenance")
|
||||
.description("Preview or apply task ledger maintenance")
|
||||
.option("--json", "Output as JSON", false)
|
||||
.option("--apply", "Apply reconciliation, cleanup stamping, and pruning", false)
|
||||
.action(async (opts, command) => {
|
||||
const parentOpts = command.parent?.opts() as { json?: boolean } | undefined;
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksMaintenanceCommand(
|
||||
{
|
||||
json: Boolean(opts.json || parentOpts?.json),
|
||||
apply: Boolean(opts.apply),
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
tasksCmd
|
||||
.command("show")
|
||||
.description("Show one background task by task id, run id, or session key")
|
||||
.argument("<lookup>", "Task id, run id, or session key")
|
||||
.option("--json", "Output as JSON", false)
|
||||
.action(async (lookup, opts, command) => {
|
||||
const parentOpts = command.parent?.opts() as { json?: boolean } | undefined;
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksShowCommand(
|
||||
{
|
||||
lookup,
|
||||
json: Boolean(opts.json || parentOpts?.json),
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
tasksCmd
|
||||
.command("notify")
|
||||
.description("Set task notify policy")
|
||||
.argument("<lookup>", "Task id, run id, or session key")
|
||||
.argument("<notify>", "Notify policy (done_only, state_changes, silent)")
|
||||
.action(async (lookup, notify) => {
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksNotifyCommand(
|
||||
{
|
||||
lookup,
|
||||
notify: notify as "done_only" | "state_changes" | "silent",
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
tasksCmd
|
||||
.command("cancel")
|
||||
.description("Cancel a running background task")
|
||||
.argument("<lookup>", "Task id, run id, or session key")
|
||||
.action(async (lookup) => {
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await tasksCancelCommand(
|
||||
{
|
||||
lookup,
|
||||
},
|
||||
defaultRuntime,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const flowsCmd = program
|
||||
.command("flows")
|
||||
.description("Inspect ClawFlow state")
|
||||
|
||||
Reference in New Issue
Block a user