mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 08:02:13 +00:00
* refactor: share talk event metric extraction * refactor: reuse shared coercion helpers * refactor: reuse shared primitive guards * refactor: reuse shared record guard * refactor: reuse shared primitive helpers * refactor: reuse shared string guards * refactor: reuse shared non-empty string guard * refactor: share plugin primitive coercion helpers * refactor: reuse plugin coercion helpers * refactor: reuse plugin coercion helpers in more plugins * refactor: reuse channel coercion helpers * refactor: reuse monitor coercion helpers * refactor: reuse provider coercion helpers * refactor: reuse core coercion helpers * refactor: reuse runtime coercion helpers * refactor: reuse helper coercion in codex paths * refactor: reuse helper coercion in runtime paths * refactor: reuse codex app-server coercion helpers * refactor: reuse codex record helpers * refactor: reuse migration and qa record helpers * refactor: reuse feishu and core helper guards * refactor: reuse browser and policy coercion helpers * refactor: reuse memory wiki record helper * refactor: share boolean coercion helpers * refactor: reuse finite number coercion * refactor: reuse trimmed string list helpers * refactor: reuse string list normalization * refactor: reuse remaining string list helpers * refactor: reuse string entry normalizer * refactor: share sorted string helpers * refactor: share string list normalization * test: preserve command registry browser imports * refactor: reuse trimmed list helpers * refactor: reuse string dedupe helpers * refactor: reuse local dedupe helpers * refactor: reuse more string dedupe helpers * refactor: reuse command string dedupe helpers * refactor: dedupe memory path lists with helper * refactor: expose string dedupe helpers to plugins * refactor: reuse core string dedupe helpers * refactor: reuse shared unique value helpers * refactor: reuse unique helpers in agent utilities * refactor: reuse unique helpers in config plumbing * refactor: reuse unique helpers in extensions * refactor: reuse unique helpers in core utilities * refactor: reuse unique helpers in qa plugins * refactor: reuse unique helpers in memory plugins * refactor: reuse unique helpers in channel plugins * refactor: reuse unique helpers in core tails * refactor: reuse unique helper in comfy workflow * refactor: reuse unique helpers in test utilities * refactor: expose unique value helper to plugins * refactor: reuse unique helpers for numeric lists * refactor: replace index dedupe filters * refactor: reuse string entry normalization * refactor: reuse string normalization in plugin helpers * refactor: reuse string normalization in extension helpers * refactor: reuse string normalization in channel parsers * refactor: reuse string normalization in memory search * refactor: reuse string normalization in provider parsers * refactor: reuse string normalization in qa helpers * refactor: reuse string normalization in infra parsers * refactor: reuse string normalization in messaging parsers * refactor: reuse string normalization in core parsers * refactor: reuse string normalization in extension parsers * refactor: reuse string normalization in remaining parsers * refactor: reuse string normalization in final parser spots * refactor: reuse string normalization in qa media helpers * refactor: reuse normalization in provider and media lists * refactor: reuse normalization for remaining set filters * refactor: reuse normalization in policy allowlists * refactor: reuse normalization in session and owner lists * refactor: centralize primitive string lists * refactor: reuse lowercase entry helpers * refactor: reuse sorted string helpers * refactor: reuse unique trimmed helpers * refactor: reuse string normalization helpers * refactor: reuse catalog string helpers * refactor: reuse remaining string helpers * refactor: simplify remaining list normalization * refactor: reuse codex auth order normalization * chore: refresh plugin sdk api baseline * fix: make shared string sorting deterministic * chore: refresh plugin sdk api baseline * fix: align host env security ordering
162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import { formatCliCommand } from "../cli/command-format.js";
|
|
import {
|
|
listCommitments,
|
|
markCommitmentsStatus,
|
|
resolveCommitmentStorePath,
|
|
} from "../commitments/store.js";
|
|
import type { CommitmentRecord, CommitmentStatus } from "../commitments/types.js";
|
|
import { getRuntimeConfig } from "../config/config.js";
|
|
import { info } from "../globals.js";
|
|
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
|
|
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
|
import { normalizeStringEntries } from "../shared/string-normalization.js";
|
|
import { sanitizeTerminalText } from "../terminal/safe-text.js";
|
|
import { isRich, theme } from "../terminal/theme.js";
|
|
|
|
const STATUS_VALUES = new Set<CommitmentStatus>([
|
|
"pending",
|
|
"sent",
|
|
"dismissed",
|
|
"snoozed",
|
|
"expired",
|
|
]);
|
|
|
|
function truncate(value: string, maxChars: number): string {
|
|
return value.length <= maxChars ? value : `${value.slice(0, maxChars - 1)}...`;
|
|
}
|
|
|
|
function safe(value: string): string {
|
|
return sanitizeTerminalText(value);
|
|
}
|
|
|
|
function parseStatus(raw: string | undefined, runtime: RuntimeEnv): CommitmentStatus | undefined {
|
|
const status = normalizeOptionalString(raw);
|
|
if (!status) {
|
|
return undefined;
|
|
}
|
|
if (STATUS_VALUES.has(status as CommitmentStatus)) {
|
|
return status as CommitmentStatus;
|
|
}
|
|
runtime.error(
|
|
`Unknown commitment status: ${status}. Use one of: ${Array.from(STATUS_VALUES).join(", ")}.`,
|
|
);
|
|
runtime.exit(1);
|
|
return undefined;
|
|
}
|
|
|
|
function isActiveCommitment(commitment: CommitmentRecord): boolean {
|
|
return commitment.status === "pending" || commitment.status === "snoozed";
|
|
}
|
|
|
|
function formatDue(ms: number): string {
|
|
return new Date(ms).toISOString();
|
|
}
|
|
|
|
function formatRows(commitments: CommitmentRecord[], rich: boolean): string[] {
|
|
const header = [
|
|
"ID".padEnd(16),
|
|
"Status".padEnd(10),
|
|
"Kind".padEnd(16),
|
|
"Due".padEnd(24),
|
|
"Scope".padEnd(28),
|
|
"Suggested text",
|
|
].join(" ");
|
|
const lines = [rich ? theme.heading(header) : header];
|
|
for (const commitment of commitments) {
|
|
const scope = truncate(
|
|
[
|
|
safe(commitment.agentId),
|
|
safe(commitment.channel),
|
|
safe(commitment.to ?? commitment.sessionKey),
|
|
]
|
|
.filter(Boolean)
|
|
.join("/"),
|
|
28,
|
|
);
|
|
lines.push(
|
|
[
|
|
truncate(safe(commitment.id), 16).padEnd(16),
|
|
safe(commitment.status).padEnd(10),
|
|
safe(commitment.kind).padEnd(16),
|
|
formatDue(commitment.dueWindow.earliestMs).padEnd(24),
|
|
scope.padEnd(28),
|
|
truncate(safe(commitment.suggestedText), 90),
|
|
].join(" "),
|
|
);
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
export async function commitmentsListCommand(
|
|
opts: { json?: boolean; status?: string; all?: boolean; agent?: string },
|
|
runtime: RuntimeEnv,
|
|
): Promise<void> {
|
|
const cfg = getRuntimeConfig();
|
|
const status = opts.all ? undefined : parseStatus(opts.status ?? "pending", runtime);
|
|
if (!opts.all && opts.status && !status) {
|
|
return;
|
|
}
|
|
const commitments = (
|
|
await listCommitments({
|
|
cfg,
|
|
status,
|
|
agentId: normalizeOptionalString(opts.agent),
|
|
})
|
|
).filter((commitment) => opts.all || status || isActiveCommitment(commitment));
|
|
|
|
if (opts.json) {
|
|
writeRuntimeJson(runtime, {
|
|
count: commitments.length,
|
|
status: status ?? (opts.all ? null : "pending"),
|
|
agentId: normalizeOptionalString(opts.agent) ?? null,
|
|
store: resolveCommitmentStorePath(),
|
|
commitments,
|
|
});
|
|
return;
|
|
}
|
|
|
|
runtime.log(info(`Commitments: ${commitments.length}`));
|
|
runtime.log(info(`Store: ${resolveCommitmentStorePath()}`));
|
|
if (status) {
|
|
runtime.log(info(`Status filter: ${status}`));
|
|
}
|
|
if (opts.agent) {
|
|
runtime.log(info(`Agent filter: ${opts.agent}`));
|
|
}
|
|
if (commitments.length === 0) {
|
|
runtime.log(
|
|
`No commitments found. Run ${formatCliCommand("openclaw commitments --all")} to include dismissed and expired commitments.`,
|
|
);
|
|
return;
|
|
}
|
|
for (const line of formatRows(commitments, isRich())) {
|
|
runtime.log(line);
|
|
}
|
|
}
|
|
|
|
export async function commitmentsDismissCommand(
|
|
opts: { ids: string[]; json?: boolean },
|
|
runtime: RuntimeEnv,
|
|
): Promise<void> {
|
|
const ids = normalizeStringEntries(opts.ids);
|
|
if (ids.length === 0) {
|
|
runtime.error(
|
|
`At least one commitment id is required. Run ${formatCliCommand("openclaw commitments list")} to choose one.`,
|
|
);
|
|
runtime.exit(1);
|
|
return;
|
|
}
|
|
const cfg = getRuntimeConfig();
|
|
await markCommitmentsStatus({
|
|
cfg,
|
|
ids,
|
|
status: "dismissed",
|
|
nowMs: Date.now(),
|
|
});
|
|
if (opts.json) {
|
|
writeRuntimeJson(runtime, { dismissed: ids });
|
|
return;
|
|
}
|
|
runtime.log(info(`Dismissed commitments: ${ids.join(", ")}`));
|
|
}
|