mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor: dedupe infra trimmed readers
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { ChannelApprovalNativeTarget } from "../channels/plugins/types.adapters.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export function buildChannelApprovalNativeTargetKey(target: ChannelApprovalNativeTarget): string {
|
||||
return `${target.to.trim()}\u0000${
|
||||
target.threadId == null ? "" : String(target.threadId).trim()
|
||||
return `${normalizeOptionalString(target.to) ?? ""}\u0000${
|
||||
target.threadId == null ? "" : (normalizeOptionalString(String(target.threadId)) ?? "")
|
||||
}`;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export function formatBonjourError(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
const trimmedMessage = err.message.trim();
|
||||
const msg = trimmedMessage || err.name || String(err).trim();
|
||||
const msg = trimmedMessage || err.name || (normalizeOptionalString(String(err)) ?? "");
|
||||
if (err.name && err.name !== "Error") {
|
||||
return msg === err.name ? err.name : `${err.name}: ${msg}`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
resolveGatewayDiscoveryEndpoint,
|
||||
type GatewayBonjourBeacon,
|
||||
@@ -25,13 +26,14 @@ export function buildGatewayDiscoveryTarget(
|
||||
): GatewayDiscoveryTarget {
|
||||
const endpoint = resolveGatewayDiscoveryEndpoint(beacon);
|
||||
const sshPort = pickSshPort(beacon);
|
||||
const sshUser = opts?.sshUser?.trim() ?? "";
|
||||
const sshUser = normalizeOptionalString(opts?.sshUser) ?? "";
|
||||
const baseSshTarget = endpoint ? (sshUser ? `${sshUser}@${endpoint.host}` : endpoint.host) : null;
|
||||
const sshTarget =
|
||||
baseSshTarget && sshPort && sshPort !== 22 ? `${baseSshTarget}:${sshPort}` : baseSshTarget;
|
||||
return {
|
||||
title: (beacon.displayName || beacon.instanceName || "Gateway").trim(),
|
||||
domain: (beacon.domain || "local.").trim(),
|
||||
title:
|
||||
normalizeOptionalString(beacon.displayName || beacon.instanceName || "Gateway") ?? "Gateway",
|
||||
domain: normalizeOptionalString(beacon.domain || "local.") ?? "local.",
|
||||
endpoint,
|
||||
wsUrl: endpoint?.wsUrl ?? null,
|
||||
sshPort,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type HeartbeatReasonKind =
|
||||
| "retry"
|
||||
| "interval"
|
||||
@@ -9,7 +11,7 @@ export type HeartbeatReasonKind =
|
||||
| "other";
|
||||
|
||||
function trimReason(reason?: string): string {
|
||||
return typeof reason === "string" ? reason.trim() : "";
|
||||
return normalizeOptionalString(reason) ?? "";
|
||||
}
|
||||
|
||||
export function normalizeHeartbeatWakeReason(reason?: string): string {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { parseDurationMs } from "../cli/parse-duration.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { AgentDefaultsConfig } from "../config/types.agent-defaults.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
type HeartbeatConfig = AgentDefaultsConfig["heartbeat"];
|
||||
|
||||
@@ -53,7 +54,7 @@ export function resolveHeartbeatIntervalMs(
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
const trimmed = String(raw).trim();
|
||||
const trimmed = normalizeOptionalString(String(raw)) ?? "";
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
isHeartbeatActionWakeReason,
|
||||
normalizeHeartbeatWakeReason,
|
||||
@@ -71,7 +72,7 @@ function normalizeWakeReason(reason?: string): string {
|
||||
}
|
||||
|
||||
function normalizeWakeTarget(value?: string): string | undefined {
|
||||
const trimmed = typeof value === "string" ? value.trim() : "";
|
||||
const trimmed = normalizeOptionalString(value) ?? "";
|
||||
return trimmed || undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import os from "node:os";
|
||||
import { promisify } from "node:util";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
@@ -12,7 +13,7 @@ async function tryScutil(key: "ComputerName" | "LocalHostName") {
|
||||
timeout: 1000,
|
||||
windowsHide: true,
|
||||
});
|
||||
const value = String(stdout ?? "").trim();
|
||||
const value = normalizeOptionalString(String(stdout ?? "")) ?? "";
|
||||
return value.length > 0 ? value : null;
|
||||
} catch {
|
||||
return null;
|
||||
@@ -20,7 +21,7 @@ async function tryScutil(key: "ComputerName" | "LocalHostName") {
|
||||
}
|
||||
|
||||
function fallbackHostName() {
|
||||
const trimmed = os.hostname().trim();
|
||||
const trimmed = normalizeOptionalString(os.hostname()) ?? "";
|
||||
return trimmed.replace(/\.local$/i, "") || "openclaw";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ChannelOutboundTargetMode } from "../../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { normalizeAccountId } from "../../utils/account-id.js";
|
||||
import {
|
||||
INTERNAL_MESSAGE_CHANNEL,
|
||||
@@ -47,15 +48,11 @@ export function resolveAgentDeliveryPlan(params: {
|
||||
/** Turn-source `threadId` — paired with `turnSourceChannel`. */
|
||||
turnSourceThreadId?: string | number;
|
||||
}): AgentDeliveryPlan {
|
||||
const requestedRaw =
|
||||
typeof params.requestedChannel === "string" ? params.requestedChannel.trim() : "";
|
||||
const requestedRaw = normalizeOptionalString(params.requestedChannel) ?? "";
|
||||
const normalizedRequested = requestedRaw ? normalizeMessageChannel(requestedRaw) : undefined;
|
||||
const requestedChannel = normalizedRequested || "last";
|
||||
|
||||
const explicitTo =
|
||||
typeof params.explicitTo === "string" && params.explicitTo.trim()
|
||||
? params.explicitTo.trim()
|
||||
: undefined;
|
||||
const explicitTo = normalizeOptionalString(params.explicitTo) ?? undefined;
|
||||
|
||||
// Resolve turn-source channel for cross-channel safety.
|
||||
const normalizedTurnSource = params.turnSourceChannel
|
||||
@@ -65,10 +62,7 @@ export function resolveAgentDeliveryPlan(params: {
|
||||
normalizedTurnSource && isDeliverableMessageChannel(normalizedTurnSource)
|
||||
? normalizedTurnSource
|
||||
: undefined;
|
||||
const turnSourceTo =
|
||||
typeof params.turnSourceTo === "string" && params.turnSourceTo.trim()
|
||||
? params.turnSourceTo.trim()
|
||||
: undefined;
|
||||
const turnSourceTo = normalizeOptionalString(params.turnSourceTo) ?? undefined;
|
||||
const turnSourceAccountId = normalizeAccountId(params.turnSourceAccountId);
|
||||
const turnSourceThreadId =
|
||||
params.turnSourceThreadId != null && params.turnSourceThreadId !== ""
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { hasNonEmptyString as sharedHasNonEmptyString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
hasNonEmptyString as sharedHasNonEmptyString,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { MESSAGE_ACTION_TARGET_MODE } from "./message-action-spec.js";
|
||||
|
||||
export const hasNonEmptyString = sharedHasNonEmptyString;
|
||||
@@ -13,7 +16,7 @@ export function applyTargetToParams(params: {
|
||||
action: string;
|
||||
args: Record<string, unknown>;
|
||||
}): void {
|
||||
const target = typeof params.args.target === "string" ? params.args.target.trim() : "";
|
||||
const target = normalizeOptionalString(params.args.target) ?? "";
|
||||
const hasLegacyTo = hasNonEmptyString(params.args.to);
|
||||
const hasLegacyChannelId = hasNonEmptyString(params.args.channelId);
|
||||
const mode =
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {
|
||||
ChannelMessageActionName,
|
||||
ChannelThreadingToolContext,
|
||||
} from "../../channels/plugins/types.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
isDeliverableMessageChannel,
|
||||
normalizeMessageChannel,
|
||||
@@ -16,18 +17,16 @@ export function normalizeMessageActionInput(params: {
|
||||
}): Record<string, unknown> {
|
||||
const normalizedArgs = { ...params.args };
|
||||
const { action, toolContext } = params;
|
||||
const explicitChannel =
|
||||
typeof normalizedArgs.channel === "string" ? normalizedArgs.channel.trim() : "";
|
||||
const explicitChannel = normalizeOptionalString(normalizedArgs.channel) ?? "";
|
||||
const inferredChannel =
|
||||
explicitChannel || normalizeMessageChannel(toolContext?.currentChannelProvider) || "";
|
||||
|
||||
const explicitTarget =
|
||||
typeof normalizedArgs.target === "string" ? normalizedArgs.target.trim() : "";
|
||||
const explicitTarget = normalizeOptionalString(normalizedArgs.target) ?? "";
|
||||
const hasLegacyTargetFields =
|
||||
typeof normalizedArgs.to === "string" || typeof normalizedArgs.channelId === "string";
|
||||
const hasLegacyTarget =
|
||||
(typeof normalizedArgs.to === "string" && normalizedArgs.to.trim().length > 0) ||
|
||||
(typeof normalizedArgs.channelId === "string" && normalizedArgs.channelId.trim().length > 0);
|
||||
(normalizeOptionalString(normalizedArgs.to) ?? "").length > 0 ||
|
||||
(normalizeOptionalString(normalizedArgs.channelId) ?? "").length > 0;
|
||||
|
||||
if (explicitTarget && hasLegacyTargetFields) {
|
||||
delete normalizedArgs.to;
|
||||
@@ -40,16 +39,15 @@ export function normalizeMessageActionInput(params: {
|
||||
actionRequiresTarget(action) &&
|
||||
!actionHasTarget(action, normalizedArgs, { channel: inferredChannel })
|
||||
) {
|
||||
const inferredTarget = toolContext?.currentChannelId?.trim();
|
||||
const inferredTarget = normalizeOptionalString(toolContext?.currentChannelId);
|
||||
if (inferredTarget) {
|
||||
normalizedArgs.target = inferredTarget;
|
||||
}
|
||||
}
|
||||
|
||||
if (!explicitTarget && actionRequiresTarget(action) && hasLegacyTarget) {
|
||||
const legacyTo = typeof normalizedArgs.to === "string" ? normalizedArgs.to.trim() : "";
|
||||
const legacyChannelId =
|
||||
typeof normalizedArgs.channelId === "string" ? normalizedArgs.channelId.trim() : "";
|
||||
const legacyTo = normalizeOptionalString(normalizedArgs.to) ?? "";
|
||||
const legacyChannelId = normalizeOptionalString(normalizedArgs.channelId) ?? "";
|
||||
const legacyTarget = legacyTo || legacyChannelId;
|
||||
if (legacyTarget) {
|
||||
normalizedArgs.target = legacyTarget;
|
||||
|
||||
@@ -236,7 +236,7 @@ async function resolveActionTarget(params: {
|
||||
accountId?: string | null;
|
||||
}): Promise<ResolvedMessagingTarget | undefined> {
|
||||
let resolvedTarget: ResolvedMessagingTarget | undefined;
|
||||
const toRaw = typeof params.args.to === "string" ? params.args.to.trim() : "";
|
||||
const toRaw = normalizeOptionalString(params.args.to) ?? "";
|
||||
if (toRaw) {
|
||||
const resolved = await resolveResolvedTargetOrThrow({
|
||||
cfg: params.cfg,
|
||||
@@ -247,8 +247,7 @@ async function resolveActionTarget(params: {
|
||||
params.args.to = resolved.to;
|
||||
resolvedTarget = resolved;
|
||||
}
|
||||
const channelIdRaw =
|
||||
typeof params.args.channelId === "string" ? params.args.channelId.trim() : "";
|
||||
const channelIdRaw = normalizeOptionalString(params.args.channelId) ?? "";
|
||||
if (channelIdRaw) {
|
||||
const resolved = await resolveResolvedTargetOrThrow({
|
||||
cfg: params.cfg,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { getBootstrapChannelPlugin } from "../../channels/plugins/bootstrap-registry.js";
|
||||
import type { ChannelMessageActionName } from "../../channels/plugins/types.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
|
||||
export type MessageActionTargetMode = "to" | "channelId" | "none";
|
||||
|
||||
@@ -109,11 +112,11 @@ export function actionHasTarget(
|
||||
params: Record<string, unknown>,
|
||||
options?: { channel?: string },
|
||||
): boolean {
|
||||
const to = typeof params.to === "string" ? params.to.trim() : "";
|
||||
const to = normalizeOptionalString(params.to) ?? "";
|
||||
if (to) {
|
||||
return true;
|
||||
}
|
||||
const channelId = typeof params.channelId === "string" ? params.channelId.trim() : "";
|
||||
const channelId = normalizeOptionalString(params.channelId) ?? "";
|
||||
if (channelId) {
|
||||
return true;
|
||||
}
|
||||
@@ -125,7 +128,7 @@ export function actionHasTarget(
|
||||
spec.aliases.some((alias) => {
|
||||
const value = params[alias];
|
||||
if (typeof value === "string") {
|
||||
return value.trim().length > 0;
|
||||
return Boolean(normalizeOptionalString(value));
|
||||
}
|
||||
if (typeof value === "number") {
|
||||
return Number.isFinite(value);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { PluginInstallRecord } from "../config/types.plugins.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type PluginInstallPathIssue = {
|
||||
kind: "custom-path" | "missing-path";
|
||||
@@ -16,7 +17,7 @@ function resolvePluginInstallCandidatePaths(
|
||||
}
|
||||
|
||||
return [install.sourcePath, install.installPath]
|
||||
.map((value) => (typeof value === "string" ? value.trim() : ""))
|
||||
.map((value) => normalizeOptionalString(value) ?? "")
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ import { listAgentWorkspaceDirs } from "../agents/workspace-dirs.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { NodeRegistry } from "../gateway/node-registry.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { listNodePairing, updatePairedNodeMetadata } from "./node-pairing.js";
|
||||
|
||||
type RemoteNodeRecord = {
|
||||
@@ -214,12 +217,12 @@ function parseBinProbePayload(payloadJSON: string | null | undefined, payload?:
|
||||
? (JSON.parse(payloadJSON) as { stdout?: unknown; bins?: unknown })
|
||||
: (payload as { stdout?: unknown; bins?: unknown });
|
||||
if (Array.isArray(parsed.bins)) {
|
||||
return parsed.bins.map((bin) => String(bin).trim()).filter(Boolean);
|
||||
return parsed.bins.map((bin) => normalizeOptionalString(String(bin)) ?? "").filter(Boolean);
|
||||
}
|
||||
if (typeof parsed.stdout === "string") {
|
||||
return parsed.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.map((line) => normalizeOptionalString(line) ?? "")
|
||||
.filter(Boolean);
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
// events ephemeral. Events are session-scoped and require an explicit key.
|
||||
|
||||
import { resolveGlobalMap } from "../shared/global-singleton.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import {
|
||||
mergeDeliveryContext,
|
||||
normalizeDeliveryContext,
|
||||
@@ -38,7 +41,7 @@ type SystemEventOptions = {
|
||||
};
|
||||
|
||||
function requireSessionKey(key?: string | null): string {
|
||||
const trimmed = typeof key === "string" ? key.trim() : "";
|
||||
const trimmed = normalizeOptionalString(key) ?? "";
|
||||
if (!trimmed) {
|
||||
throw new Error("system events require a sessionKey");
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { resolveRuntimeServiceVersion } from "../version.js";
|
||||
import { pickBestEffortPrimaryLanIPv4 } from "./network-discovery-display.js";
|
||||
@@ -55,7 +56,7 @@ function initSelfPresence() {
|
||||
const res = spawnSync("sysctl", ["-n", "hw.model"], {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
const out = typeof res.stdout === "string" ? res.stdout.trim() : "";
|
||||
const out = normalizeOptionalString(res.stdout) ?? "";
|
||||
return out.length > 0 ? out : undefined;
|
||||
}
|
||||
return os.arch();
|
||||
@@ -64,7 +65,7 @@ function initSelfPresence() {
|
||||
const res = spawnSync("sw_vers", ["-productVersion"], {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
const out = typeof res.stdout === "string" ? res.stdout.trim() : "";
|
||||
const out = normalizeOptionalString(res.stdout) ?? "";
|
||||
return out.length > 0 ? out : os.release();
|
||||
};
|
||||
const platform = (() => {
|
||||
@@ -178,7 +179,7 @@ function mergeStringList(...values: Array<string[] | undefined>): string[] | und
|
||||
continue;
|
||||
}
|
||||
for (const item of list) {
|
||||
const trimmed = String(item).trim();
|
||||
const trimmed = normalizeOptionalString(String(item)) ?? "";
|
||||
if (trimmed) {
|
||||
out.add(trimmed);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { createAsyncLock, readJsonFile, writeJsonAtomic } from "./json-files.js";
|
||||
|
||||
export type VoiceWakeConfig = {
|
||||
@@ -16,7 +17,7 @@ function resolvePath(baseDir?: string) {
|
||||
|
||||
function sanitizeTriggers(triggers: string[] | undefined | null): string[] {
|
||||
const cleaned = (triggers ?? [])
|
||||
.map((w) => (typeof w === "string" ? w.trim() : ""))
|
||||
.map((w) => normalizeOptionalString(w) ?? "")
|
||||
.filter((w) => w.length > 0);
|
||||
return cleaned.length > 0 ? cleaned : DEFAULT_TRIGGERS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user