openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
316 lines (315 loc) • 19.5 kB
JavaScript
import { t as formatDocsLink } from "./links-CsLBrRff.js";
import { r as theme } from "./theme-vjDs9tao.js";
import { n as defaultRuntime } from "./runtime-B4lgFmsS.js";
import { r as setVerbose } from "./global-state-BAD7XgmL.js";
import "./globals-GTrXU4s9.js";
import { n as runCommandWithRuntime } from "./cli-utils-Cuzzfy1Q.js";
import { t as formatHelpExamples } from "./help-format-CAcwboTs.js";
import { i as parseStrictPositiveIntOrUndefined, n as parsePositiveIntOrUndefined } from "./helpers-gBVG4H2O.js";
//#region src/cli/program/register.status-health-sessions.ts
function resolveVerbose(opts) {
return Boolean(opts.verbose || opts.debug);
}
function createModuleLoader(load) {
let promise;
return () => promise ??= load();
}
const loadCommitmentsCommands = createModuleLoader(() => import("./commitments-DNEFifHT.js"));
const loadTasksCommands = createModuleLoader(() => import("./tasks-C4tFyO1n.js"));
const loadFlowsCommands = createModuleLoader(() => import("./flows-CIS7ZV5-.js"));
function addSessionsListOptions(command) {
return command.option("--json", "Output as JSON", false).option("--verbose", "Verbose logging", false).option("--store <path>", "Path to session store (default: resolved from config)").option("--agent <id>", "Agent id to inspect (default: configured default agent)").option("--all-agents", "Aggregate sessions across all configured agents", false).option("--active <minutes>", "Only show sessions updated within the past N minutes").option("--limit <count>", "Max sessions to show (default: 100; use \"all\" for full output)");
}
function mergeSessionsListOptions(opts, parentOpts) {
return {
json: Boolean(opts.json || parentOpts?.json),
verbose: Boolean(opts.verbose || parentOpts?.verbose),
store: opts.store ?? parentOpts?.store,
agent: opts.agent ?? parentOpts?.agent,
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
active: opts.active ?? parentOpts?.active,
limit: opts.limit ?? parentOpts?.limit
};
}
async function runSessionsListCli(opts) {
setVerbose(Boolean(opts.verbose));
const { sessionsCommand } = await import("./sessions-DMIMtB8M.js");
await sessionsCommand({
json: Boolean(opts.json),
store: opts.store,
agent: opts.agent,
allAgents: Boolean(opts.allAgents),
active: opts.active,
limit: opts.limit
}, defaultRuntime);
}
function parseTimeoutMs(timeout) {
const parsed = parsePositiveIntOrUndefined(timeout);
if (timeout !== void 0 && parsed === void 0) {
defaultRuntime.error("--timeout must be a positive integer (milliseconds)");
defaultRuntime.exit(1);
return null;
}
return parsed;
}
function parseTasksAuditLimit(limit) {
const parsed = parseStrictPositiveIntOrUndefined(limit);
if (limit !== void 0 && parsed === void 0) {
defaultRuntime.error("--limit must be a positive integer, for example --limit 25.");
defaultRuntime.exit(1);
return null;
}
return parsed;
}
async function runWithVerboseAndTimeout(opts, action) {
const verbose = resolveVerbose(opts);
setVerbose(verbose);
const timeoutMs = parseTimeoutMs(opts.timeout);
if (timeoutMs === null) return;
await runCommandWithRuntime(defaultRuntime, async () => {
await action({
verbose,
timeoutMs
});
});
}
/** Register status/health plus persistent session/task inspection command groups. */
function registerStatusHealthSessionsCommands(program) {
program.command("status").description("Show channel health and recent session recipients").option("--json", "Output JSON instead of text", false).option("--all", "Full diagnosis (read-only, pasteable)", false).option("--usage", "Show model provider usage/quota snapshots", false).option("--deep", "Probe channels (WhatsApp Web + Telegram + Discord + Slack + Signal)", false).option("--timeout <ms>", "Probe timeout in milliseconds", "10000").option("--verbose", "Verbose logging", false).option("--debug", "Alias for --verbose", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
["openclaw status", "Show channel health + session summary."],
["openclaw status --all", "Full diagnosis (read-only)."],
["openclaw status --json", "Machine-readable output."],
["openclaw status --usage", "Show model provider usage/quota snapshots."],
["openclaw status --deep", "Run channel probes (WA + Telegram + Discord + Slack + Signal)."],
["openclaw status --deep --timeout 5000", "Tighten probe timeout."]
])}`).addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/status", "docs.openclaw.ai/cli/status")}\n`).action(async (opts) => {
await runWithVerboseAndTimeout(opts, async ({ verbose, timeoutMs }) => {
const { statusCommand } = await import("./status-BUsX5ajI.js");
await statusCommand({
json: Boolean(opts.json),
all: Boolean(opts.all),
deep: Boolean(opts.deep),
usage: Boolean(opts.usage),
timeoutMs,
verbose
}, defaultRuntime);
});
});
program.command("health").description("Fetch health from the running gateway").option("--json", "Output JSON instead of text", false).option("--timeout <ms>", "Connection timeout in milliseconds", "10000").option("--verbose", "Verbose logging", false).option("--debug", "Alias for --verbose", false).addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/health", "docs.openclaw.ai/cli/health")}\n`).action(async (opts) => {
await runWithVerboseAndTimeout(opts, async ({ verbose, timeoutMs }) => {
const { healthCommand } = await import("./health-B9v-C93Q.js");
await healthCommand({
json: Boolean(opts.json),
timeoutMs,
verbose
}, defaultRuntime);
});
});
const sessionsCmd = addSessionsListOptions(program.command("sessions").description("List stored conversation sessions")).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
["openclaw sessions", "List all sessions."],
["openclaw sessions --agent work", "List sessions for one agent."],
["openclaw sessions --all-agents", "Aggregate sessions across agents."],
["openclaw sessions --active 120", "Only last 2 hours."],
["openclaw sessions --limit 25", "Show the newest 25 sessions."],
["openclaw sessions --json", "Machine-readable output."],
["openclaw sessions --store ./tmp/sessions.json", "Use a specific session store."]
])}\n\n${theme.muted("Shows token usage per session when the agent reports it; set agents.defaults.contextTokens to cap the window and show %.")}`).addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sessions", "docs.openclaw.ai/cli/sessions")}\n`).action(async (opts) => {
await runSessionsListCli(opts);
});
sessionsCmd.enablePositionalOptions();
addSessionsListOptions(sessionsCmd.command("list").description("List stored conversation sessions")).action(async (opts, command) => {
const parentOpts = command.parent?.opts();
await runSessionsListCli(mergeSessionsListOptions(opts, parentOpts));
});
sessionsCmd.command("cleanup").description("Run session-store maintenance now").option("--store <path>", "Path to session store (default: resolved from config)").option("--agent <id>", "Agent id to maintain (default: configured default agent)").option("--all-agents", "Run maintenance across all configured agents", false).option("--dry-run", "Preview maintenance actions without writing", false).option("--enforce", "Apply maintenance even when configured mode is warn", false).option("--fix-missing", "Remove store entries whose transcript files are missing (bypasses age/count retention)", false).option("--fix-dm-scope", "Retire stale direct-DM session rows that no longer match session.dmScope=main", false).option("--active-key <key>", "Protect this session key from budget-eviction").option("--json", "Output JSON", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
["openclaw sessions cleanup --dry-run", "Preview stale/cap cleanup."],
["openclaw sessions cleanup --dry-run --fix-missing", "Also preview pruning entries with missing transcript files."],
["openclaw sessions cleanup --dry-run --fix-dm-scope", "Preview stale direct-DM rows after returning dmScope to main."],
["openclaw sessions cleanup --enforce", "Apply maintenance now."],
["openclaw sessions cleanup --agent work --dry-run", "Preview one agent store."],
["openclaw sessions cleanup --all-agents --dry-run", "Preview all agent stores."],
["openclaw sessions cleanup --enforce --store ./tmp/sessions.json", "Use a specific store."]
])}`).action(async (opts, command) => {
const parentOpts = command.parent?.opts();
await runCommandWithRuntime(defaultRuntime, async () => {
const { sessionsCleanupCommand } = await import("./sessions-cleanup-PuU5K9Jv.js");
await sessionsCleanupCommand({
store: opts.store ?? parentOpts?.store,
agent: opts.agent ?? parentOpts?.agent,
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
dryRun: Boolean(opts.dryRun),
enforce: Boolean(opts.enforce),
fixMissing: Boolean(opts.fixMissing),
fixDmScope: Boolean(opts.fixDmScope),
activeKey: opts.activeKey,
json: Boolean(opts.json || parentOpts?.json)
}, defaultRuntime);
});
});
sessionsCmd.command("tail").description("Tail human-readable session trajectory progress").option("--session-key <key>", "Session key to tail (default: active sessions or latest)").option("--tail <count>", "Number of existing trajectory events to show", "80").option("--follow", "Continue following for new trajectory events", false).option("--store <path>", "Path to session store (default: resolved from config)").option("--agent <id>", "Agent id to inspect (default: configured default agent)").option("--all-agents", "Aggregate sessions across all configured agents", false).action(async (opts, command) => {
const parentOpts = command.parent?.opts();
await runCommandWithRuntime(defaultRuntime, async () => {
const { sessionsTailCommand } = await import("./sessions-tail-AgPVoVrE.js");
await sessionsTailCommand({
sessionKey: opts.sessionKey,
store: opts.store ?? parentOpts?.store,
agent: opts.agent ?? parentOpts?.agent,
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
follow: Boolean(opts.follow),
tail: opts.tail
}, defaultRuntime);
});
});
sessionsCmd.command("export-trajectory").description("Export a redacted trajectory bundle for a stored session").option("--session-key <key>", "Session key to export").option("--output <path>", "Output directory name inside .openclaw/trajectory-exports").option("--workspace <path>", "Workspace root for the export (default: current directory)").option("--store <path>", "Path to session store (default: resolved from session key)").option("--agent <id>", "Agent id for resolving the default session store").option("--request-json-base64 <payload>", "Base64url-encoded export request").option("--json", "Output JSON", false).action(async (opts, command) => {
const parentOpts = command.parent?.opts();
await runCommandWithRuntime(defaultRuntime, async () => {
const { exportTrajectoryCommand } = await import("./export-trajectory-C5pdQrQf.js");
await exportTrajectoryCommand({
sessionKey: opts.sessionKey,
output: opts.output,
workspace: opts.workspace,
store: opts.store ?? parentOpts?.store,
agent: opts.agent ?? parentOpts?.agent,
requestJsonBase64: opts.requestJsonBase64,
json: Boolean(opts.json || parentOpts?.json)
}, defaultRuntime);
});
});
const commitmentsCmd = program.command("commitments").description("List and manage inferred follow-up commitments").option("--json", "Output JSON instead of text", false).option("--agent <id>", "Agent id to inspect").option("--status <status>", "Filter by status (pending, sent, dismissed, snoozed, expired)").option("--all", "Show all statuses", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
["openclaw commitments", "List pending inferred follow-ups."],
["openclaw commitments --all", "List all inferred follow-ups."],
["openclaw commitments --agent work", "List one agent's inferred follow-ups."],
["openclaw commitments dismiss cm_abc123", "Dismiss a follow-up."]
])}`).action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const { commitmentsListCommand } = await loadCommitmentsCommands();
await commitmentsListCommand({
json: Boolean(opts.json),
agent: opts.agent,
status: opts.status,
all: Boolean(opts.all)
}, defaultRuntime);
});
});
commitmentsCmd.enablePositionalOptions();
commitmentsCmd.command("list").description("List inferred follow-up commitments").option("--json", "Output JSON instead of text", false).option("--agent <id>", "Agent id to inspect").option("--status <status>", "Filter by status (pending, sent, dismissed, snoozed, expired)").option("--all", "Show all statuses", false).action(async (opts, command) => {
const parentOpts = command.parent?.opts();
await runCommandWithRuntime(defaultRuntime, async () => {
const { commitmentsListCommand } = await loadCommitmentsCommands();
await commitmentsListCommand({
json: Boolean(opts.json || parentOpts?.json),
agent: opts.agent ?? parentOpts?.agent,
status: opts.status ?? parentOpts?.status,
all: Boolean(opts.all || parentOpts?.all)
}, defaultRuntime);
});
});
commitmentsCmd.command("dismiss <ids...>").description("Dismiss inferred follow-up commitments").option("--json", "Output JSON instead of text", false).action(async (ids, opts, command) => {
const parentOpts = command.parent?.opts();
await runCommandWithRuntime(defaultRuntime, async () => {
const { commitmentsDismissCommand } = await loadCommitmentsCommands();
await commitmentsDismissCommand({
ids,
json: Boolean(opts.json || parentOpts?.json)
}, defaultRuntime);
});
});
const tasksCmd = program.command("tasks").description("Inspect durable background tasks and TaskFlow 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 () => {
const { tasksListCommand } = await loadTasksCommands();
await tasksListCommand({
json: Boolean(opts.json),
runtime: opts.runtime,
status: opts.status
}, 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();
await runCommandWithRuntime(defaultRuntime, async () => {
const { tasksListCommand } = await loadTasksCommands();
await tasksListCommand({
json: Boolean(opts.json || parentOpts?.json),
runtime: opts.runtime ?? parentOpts?.runtime,
status: opts.status ?? parentOpts?.status
}, defaultRuntime);
});
});
tasksCmd.command("audit").description("Show stale or broken background tasks and TaskFlows").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, restore_failed, stale_waiting, stale_blocked, cancel_stuck, missing_linked_tasks, blocked_task_missing)").option("--limit <n>", "Limit displayed findings").action(async (opts, command) => {
const parentOpts = command.parent?.opts();
const limit = parseTasksAuditLimit(opts.limit);
if (limit === null) return;
await runCommandWithRuntime(defaultRuntime, async () => {
const { tasksAuditCommand } = await loadTasksCommands();
await tasksAuditCommand({
json: Boolean(opts.json || parentOpts?.json),
severity: opts.severity,
code: opts.code,
limit
}, defaultRuntime);
});
});
tasksCmd.command("maintenance").description("Preview or apply tasks and TaskFlow 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();
await runCommandWithRuntime(defaultRuntime, async () => {
const { tasksMaintenanceCommand } = await loadTasksCommands();
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();
await runCommandWithRuntime(defaultRuntime, async () => {
const { tasksShowCommand } = await loadTasksCommands();
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 () => {
const { tasksNotifyCommand } = await loadTasksCommands();
await tasksNotifyCommand({
lookup,
notify
}, 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 () => {
const { tasksCancelCommand } = await loadTasksCommands();
await tasksCancelCommand({ lookup }, defaultRuntime);
});
});
const tasksFlowCmd = tasksCmd.command("flow").description("Inspect durable TaskFlow state under tasks");
tasksFlowCmd.command("list").description("List tracked TaskFlows").option("--json", "Output as JSON", false).option("--status <name>", "Filter by status (queued, running, waiting, blocked, succeeded, failed, cancelled, lost)").action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const { flowsListCommand } = await loadFlowsCommands();
await flowsListCommand({
json: Boolean(opts.json),
status: opts.status
}, defaultRuntime);
});
});
tasksFlowCmd.command("show").description("Show one TaskFlow by flow id or owner key").argument("<lookup>", "Flow id or owner key").option("--json", "Output as JSON", false).action(async (lookup, opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const { flowsShowCommand } = await loadFlowsCommands();
await flowsShowCommand({
lookup,
json: Boolean(opts.json)
}, defaultRuntime);
});
});
tasksFlowCmd.command("cancel").description("Cancel a running TaskFlow").argument("<lookup>", "Flow id or owner key").action(async (lookup) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const { flowsCancelCommand } = await loadFlowsCommands();
await flowsCancelCommand({ lookup }, defaultRuntime);
});
});
}
//#endregion
export { registerStatusHealthSessionsCommands };