docs: document cli config and cron helpers

This commit is contained in:
Peter Steinberger
2026-06-04 10:51:58 -04:00
parent 5522268b24
commit 09cee22249
10 changed files with 19 additions and 0 deletions
+2
View File
@@ -1,3 +1,4 @@
// Shell completion runtime: cache paths, profile installation, and shell detection.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -132,6 +133,7 @@ function updateCompletionProfile(
cachePath: string | null,
sourceLine: string,
): { next: string; changed: boolean; hadExisting: boolean } {
// Remove both cached and old dynamic blocks so installs converge to one fast source line.
const lines = content.split("\n");
const filtered: string[] = [];
let hadExisting = false;
+2
View File
@@ -1,3 +1,4 @@
// Config CLI command implementation for get/set/unset/patch/validate and secret refs.
import fs from "node:fs";
import { isRecord as isPlainRecord } from "@openclaw/normalization-core/record-coerce";
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
@@ -143,6 +144,7 @@ function normalizeAgentDefaultModelValueForConfigMutation(value: unknown): unkno
}
function normalizeAgentListModelRefsForConfigMutation(value: unknown): unknown {
// Config mutation normalizes model refs at write time so later readers see canonical ids.
if (!Array.isArray(value)) {
return value;
}
+2
View File
@@ -1,3 +1,4 @@
// Input-mode parsing helpers for `openclaw config set` values, refs, providers, and batches.
import fs from "node:fs";
import {
normalizeOptionalString,
@@ -117,6 +118,7 @@ function parseBatchEntries(raw: string, sourceLabel: string): ConfigSetBatchEntr
}
export function parseBatchSource(opts: ConfigSetOptions): ConfigSetBatchEntry[] | null {
// Batch mode is exclusive because each entry carries its own value/ref/provider mode.
const batchJson = normalizeOptionalString(opts.batchJson);
const batchFile = normalizeOptionalString(opts.batchFile);
const hasInline = Boolean(batchJson);
+2
View File
@@ -1,3 +1,4 @@
// CLI container targeting: parse --container and re-exec the command inside Docker/Podman.
import { spawnSync } from "node:child_process";
import { isIP } from "node:net";
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
@@ -134,6 +135,7 @@ function buildContainerExecArgs(params: {
stdinIsTTY: boolean;
stdoutIsTTY: boolean;
}): string[] {
// Preserve proxy env only after loopback validation; localhost would point inside the container.
const envFlag = params.exec.runtime === "docker" ? "-e" : "--env";
const proxyUrl = normalizeOptionalString(params.env.OPENCLAW_PROXY_URL);
if (proxyUrl) {
+2
View File
@@ -1,3 +1,4 @@
// Cron status/list/add command registration and create-payload normalization.
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
@@ -173,6 +174,7 @@ export function registerCronAddCommand(cron: Command) {
}
const payload = (() => {
// Main-session jobs use system events; isolated/current/session jobs use messages.
const systemEvent = normalizeOptionalString(opts.systemEvent) ?? "";
const optionMessage = normalizeOptionalString(opts.message);
const positionalMessage = normalizeOptionalString(messageArg);
+2
View File
@@ -1,3 +1,4 @@
// Cron edit command registration and patch construction for existing jobs.
import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
@@ -39,6 +40,7 @@ async function loadCronJobForEditSchedulePatch(
opts: Record<string, unknown>,
id: string,
): Promise<CronJob | undefined> {
// Schedule patches need the existing job; page defensively because gateway stores can be large.
let offset = 0;
for (let page = 0; page < CRON_EDIT_LOOKUP_MAX_PAGES; page += 1) {
const listed = (await callGatewayFromCli("cron.list", opts, {
+2
View File
@@ -1,3 +1,4 @@
// Cron simple command registration: remove, toggle, show, runs, and run-now.
import {
resolvePositiveTimerTimeoutMs,
resolveTimerTimeoutMs,
@@ -68,6 +69,7 @@ async function waitForCronRunCompletion(params: {
timeoutMs: number;
pollIntervalMs: number;
}): Promise<CronRunLogEntryResult> {
// Poll the run log rather than cron.run because completion state is written asynchronously.
const startedAt = Date.now();
for (;;) {
const page = (await callGatewayFromCli("cron.runs", params.opts, {
+1
View File
@@ -1,3 +1,4 @@
// Top-level cron CLI registration and subcommand wiring.
import type { Command } from "commander";
import { formatDocsLink } from "../../../packages/terminal-core/src/links.js";
import { theme } from "../../../packages/terminal-core/src/theme.js";
+2
View File
@@ -1,3 +1,4 @@
// Shared cron CLI formatting, parsing, delivery preview, and warning helpers.
import {
resolveExpiresAtMsFromDurationMs,
timestampMsToIsoString,
@@ -101,6 +102,7 @@ export function handleCronCliError(err: unknown) {
}
export async function warnIfCronSchedulerDisabled(opts: GatewayRpcOpts) {
// Old/offline gateways should not make successful cron mutations fail after the fact.
try {
const res = (await callGatewayFromCli("cron.status", opts, {})) as {
enabled?: boolean;
+2
View File
@@ -1,3 +1,4 @@
// Cron CLI parsing helpers for Telegram topic thread ids and session targets.
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
@@ -19,6 +20,7 @@ export function parseCronThreadIdOption(value: unknown): number | undefined {
}
export function normalizeCronSessionTargetOption(value: unknown): string | undefined {
// Preserve explicit session ids after `session:` while normalizing the mode prefix.
const raw = normalizeOptionalString(value);
if (!raw) {
return undefined;