From 4f4cd2e8aee00226451bc59834e00771c4e797a6 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 3 Jun 2026 18:23:23 -0400 Subject: [PATCH] docs: document cli shared helpers --- src/cli/dotenv.ts | 2 ++ src/cli/gateway-dispatch-dotenv.ts | 2 ++ src/cli/npm-resolution.ts | 7 +++++++ src/cli/parse-duration.ts | 3 +++ src/cli/progress.ts | 9 +++++++++ src/cli/root-option-scan.ts | 3 +++ src/cli/shared/parse-port.ts | 3 +++ 7 files changed, 29 insertions(+) diff --git a/src/cli/dotenv.ts b/src/cli/dotenv.ts index 0481c281971a..3e5c95620b11 100644 --- a/src/cli/dotenv.ts +++ b/src/cli/dotenv.ts @@ -1,7 +1,9 @@ +// CLI dotenv loader that preserves workspace overrides before global runtime fallbacks. import path from "node:path"; import { resolveStateDir } from "../config/paths.js"; import { loadGlobalRuntimeDotEnvFiles, loadWorkspaceDotEnvFile } from "../infra/dotenv.js"; +/** Load `.env` files for normal CLI commands without overriding existing process env. */ export function loadCliDotEnv(opts?: { quiet?: boolean }) { const quiet = opts?.quiet ?? true; const cwdEnvPath = path.join(process.cwd(), ".env"); diff --git a/src/cli/gateway-dispatch-dotenv.ts b/src/cli/gateway-dispatch-dotenv.ts index ef7174e0ef4e..4060f1eae890 100644 --- a/src/cli/gateway-dispatch-dotenv.ts +++ b/src/cli/gateway-dispatch-dotenv.ts @@ -1,8 +1,10 @@ +// Minimal dotenv loader for gateway-dispatched CLI commands. import fs from "node:fs"; import path from "node:path"; import { resolveStateDir } from "../config/paths.js"; import { loadGlobalRuntimeDotEnvFiles } from "../infra/dotenv-global.js"; +/** Load only the env files needed before dispatching a command through the gateway. */ export async function loadGatewayDispatchCliDotEnv(opts?: { quiet?: boolean }) { const quiet = opts?.quiet ?? true; const cwdEnvPath = path.join(process.cwd(), ".env"); diff --git a/src/cli/npm-resolution.ts b/src/cli/npm-resolution.ts index 7f549b66715e..c241facb0487 100644 --- a/src/cli/npm-resolution.ts +++ b/src/cli/npm-resolution.ts @@ -1,8 +1,10 @@ +// Helpers for recording npm plugin installs with optional exact-version pinning metadata. import { buildNpmResolutionFields, type NpmSpecResolution as NpmResolutionMetadata, } from "../infra/install-source-utils.js"; +/** Choose the install-record spec for an npm package, optionally pinning to the resolved version. */ export function resolvePinnedNpmSpec(params: { rawSpec: string; pin: boolean; @@ -24,6 +26,7 @@ export function resolvePinnedNpmSpec(params: { }; } +/** Convert npm resolver metadata into persisted install-record fields. */ export function mapNpmResolutionMetadata(resolution?: NpmResolutionMetadata): { resolvedName?: string; resolvedVersion?: string; @@ -35,6 +38,7 @@ export function mapNpmResolutionMetadata(resolution?: NpmResolutionMetadata): { return buildNpmResolutionFields(resolution); } +/** Build the npm section of a plugin install record. */ export function buildNpmInstallRecordFields(params: { spec: string; installPath: string; @@ -61,6 +65,7 @@ export function buildNpmInstallRecordFields(params: { }; } +/** Resolve and log npm pinning decisions before constructing the persisted install record. */ export function resolvePinnedNpmInstallRecord(params: { rawSpec: string; pin: boolean; @@ -84,6 +89,7 @@ export function resolvePinnedNpmInstallRecord(params: { }); } +/** CLI adapter for npm install-record pinning with styled warning output. */ export function resolvePinnedNpmInstallRecordForCli( rawSpec: string, pin: boolean, @@ -104,6 +110,7 @@ export function resolvePinnedNpmInstallRecordForCli( }); } +/** Emit any user-facing notice or warning from npm pin resolution. */ export function logPinnedNpmSpecMessages( pinInfo: { pinWarning?: string; pinNotice?: string }, log: (message: string) => void, diff --git a/src/cli/parse-duration.ts b/src/cli/parse-duration.ts index eb3c38aed5de..64342e083cdf 100644 --- a/src/cli/parse-duration.ts +++ b/src/cli/parse-duration.ts @@ -1,8 +1,10 @@ +// Duration parser shared by CLI flags, command directives, and config-backed timing values. import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; +/** Options for choosing the unit used by bare numeric duration values. */ export type DurationMsParseOptions = { defaultUnit?: "ms" | "s" | "m" | "h" | "d"; }; @@ -29,6 +31,7 @@ function roundSafeDurationMs(raw: string, value: number): number { return ms; } +/** Parse a non-negative duration into milliseconds, supporting single and composite units. */ export function parseDurationMs(raw: string, opts?: DurationMsParseOptions): number { const trimmed = normalizeLowercaseStringOrEmpty(normalizeOptionalString(raw) ?? ""); if (!trimmed) { diff --git a/src/cli/progress.ts b/src/cli/progress.ts index 56d2557b9f2b..274a0ba76b2d 100644 --- a/src/cli/progress.ts +++ b/src/cli/progress.ts @@ -1,3 +1,4 @@ +// Terminal progress reporter used by long-running CLI commands. import { spinner } from "@clack/prompts"; import { createOscProgressController, @@ -12,6 +13,7 @@ import { theme } from "../../packages/terminal-core/src/theme.js"; import { resolveTimerTimeoutMs } from "../shared/number-coercion.js"; const DEFAULT_DELAY_MS = 0; +// Only one active progress renderer may own the terminal line at a time. let activeProgress = 0; type ProgressOptions = { @@ -24,6 +26,7 @@ type ProgressOptions = { fallback?: "spinner" | "line" | "log" | "none"; }; +/** Minimal progress API exposed to CLI work callbacks. */ export type ProgressReporter = { setLabel: (label: string) => void; setPercent: (percent: number) => void; @@ -31,12 +34,14 @@ export type ProgressReporter = { done: () => void; }; +/** Completed/total progress update shape used by totals-based commands. */ export type ProgressTotalsUpdate = { completed: number; total: number; label?: string; }; +/** Decide whether the interactive spinner is safe for the current terminal state. */ export function shouldUseInteractiveProgressSpinner(params: { fallback?: ProgressOptions["fallback"]; streamIsTty?: boolean; @@ -53,6 +58,7 @@ const noopReporter: ProgressReporter = { done: () => {}, }; +/** Create a no-op, spinner, line, log, and OSC-capable progress reporter. */ export function createCliProgress(options: ProgressOptions): ProgressReporter { if (options.enabled === false) { return noopReporter; @@ -78,6 +84,7 @@ export function createCliProgress(options: ProgressOptions): ProgressReporter { }); const allowLine = isTty && options.fallback === "line"; if (isTty && stdinIsRaw && (options.fallback === undefined || options.fallback === "spinner")) { + // Raw stdin usually means an interactive prompt owns cursor movement. return noopReporter; } @@ -223,6 +230,7 @@ export function createCliProgress(options: ProgressOptions): ProgressReporter { return { setLabel, setPercent, tick, done }; } +/** Run async work with a progress reporter that is always stopped in finally. */ export async function withProgress( options: ProgressOptions, work: (progress: ProgressReporter) => Promise, @@ -235,6 +243,7 @@ export async function withProgress( } } +/** Run async work with a progress reporter plus a completed/total update adapter. */ export async function withProgressTotals( options: ProgressOptions, work: (update: (update: ProgressTotalsUpdate) => void, progress: ProgressReporter) => Promise, diff --git a/src/cli/root-option-scan.ts b/src/cli/root-option-scan.ts index 5a70e4f014e8..7171bbbd325c 100644 --- a/src/cli/root-option-scan.ts +++ b/src/cli/root-option-scan.ts @@ -1,3 +1,4 @@ +// Shared scanner for forwarding root CLI options while subcommands inspect their own args. import { FLAG_TERMINATOR } from "../infra/cli-root-options.js"; import { forwardConsumedCliRootOption } from "./root-option-forward.js"; @@ -8,6 +9,7 @@ type CliRootOptionVisitResult = | { kind: "handled"; consumedNext?: boolean } | { kind: "error"; error: string }; +/** Walk argv once, letting callers consume custom flags before forwarding root options. */ export function scanCliRootOptions( argv: string[], visit: (params: { @@ -29,6 +31,7 @@ export function scanCliRootOptions( continue; } if (arg === FLAG_TERMINATOR) { + // `--` ends root-option handling; everything after it belongs to the target command. out.push(arg, ...args.slice(i + 1)); break; } diff --git a/src/cli/shared/parse-port.ts b/src/cli/shared/parse-port.ts index 6d4482264487..ef4020eca112 100644 --- a/src/cli/shared/parse-port.ts +++ b/src/cli/shared/parse-port.ts @@ -1,7 +1,10 @@ +// CLI-facing TCP port parser wrapper. import { parseTcpPort } from "../../infra/tcp-port.js"; +/** Re-export the canonical TCP port parser and limit for CLI callers. */ export { MAX_TCP_PORT, parseTcpPort } from "../../infra/tcp-port.js"; +/** Parse a TCP port from unknown CLI/config input, returning null for invalid values. */ export function parsePort(raw: unknown): number | null { return parseTcpPort(raw); }