mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-18 20:24:47 +00:00
refactor: dedupe command config lowercase helpers
This commit is contained in:
@@ -12,6 +12,7 @@ import { logConfigUpdated } from "../config/logging.js";
|
||||
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../routing/session-key.js";
|
||||
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { resolveUserPath, shortenHomePath } from "../utils.js";
|
||||
import { createClackPrompter } from "../wizard/clack-prompter.js";
|
||||
import { WizardCancelledError } from "../wizard/prompts.js";
|
||||
@@ -241,7 +242,8 @@ export async function agentsAddCommand(
|
||||
const sourceAuthPath = resolveAuthStorePath(resolveAgentDir(cfg, defaultAgentId));
|
||||
const destAuthPath = resolveAuthStorePath(agentDir);
|
||||
const sameAuthPath =
|
||||
path.resolve(sourceAuthPath).toLowerCase() === path.resolve(destAuthPath).toLowerCase();
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(sourceAuthPath)) ===
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(destAuthPath));
|
||||
if (
|
||||
!sameAuthPath &&
|
||||
(await fileExists(sourceAuthPath)) &&
|
||||
|
||||
@@ -108,7 +108,7 @@ export async function channelsLogsCommand(
|
||||
}
|
||||
for (const line of lines) {
|
||||
const ts = line.time ? `${line.time} ` : "";
|
||||
const level = line.level ? `${line.level.toLowerCase()} ` : "";
|
||||
const level = line.level ? `${normalizeLowercaseStringOrEmpty(line.level)} ` : "";
|
||||
runtime.log(`${ts}${level}${line.message}`.trim());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ import {
|
||||
import { resolveGatewayService } from "../daemon/service.js";
|
||||
import { uninstallLegacySystemdUnits } from "../daemon/systemd.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { note } from "../terminal/note.js";
|
||||
import { buildGatewayInstallPlan } from "./daemon-install-helpers.js";
|
||||
import { DEFAULT_GATEWAY_DAEMON_RUNTIME, type GatewayDaemonRuntime } from "./daemon-runtime.js";
|
||||
@@ -34,7 +37,7 @@ const execFileAsync = promisify(execFile);
|
||||
function detectGatewayRuntime(programArguments: string[] | undefined): GatewayDaemonRuntime {
|
||||
const first = programArguments?.[0];
|
||||
if (first) {
|
||||
const base = path.basename(first).toLowerCase();
|
||||
const base = normalizeLowercaseStringOrEmpty(path.basename(first));
|
||||
if (base === "bun" || base === "bun.exe") {
|
||||
return "bun";
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { isTruthyEnvValue } from "../infra/env.js";
|
||||
import { runGatewayUpdate } from "../infra/update-runner.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { note } from "../terminal/note.js";
|
||||
import type { DoctorOptions } from "./doctor-prompter.js";
|
||||
|
||||
@@ -16,7 +17,7 @@ async function detectOpenClawGitCheckout(root: string): Promise<"git" | "not-git
|
||||
if (res.code !== 0) {
|
||||
// Avoid noisy "Update via package manager" notes when git is missing/broken,
|
||||
// but do show it when this is clearly not a git checkout.
|
||||
if (res.stderr.toLowerCase().includes("not a git repository")) {
|
||||
if (normalizeLowercaseStringOrEmpty(res.stderr).includes("not a git repository")) {
|
||||
return "not-git";
|
||||
}
|
||||
return "unknown";
|
||||
|
||||
@@ -12,6 +12,7 @@ import { loadConfig } from "../config/config.js";
|
||||
import type { OutboundSendDeps } from "../infra/outbound/deliver.js";
|
||||
import { runMessageAction } from "../infra/outbound/message-action-runner.js";
|
||||
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
||||
import { buildMessageCliJson, formatMessageCliText } from "./message-format.js";
|
||||
|
||||
@@ -42,8 +43,9 @@ export async function messageCommand(
|
||||
});
|
||||
const rawAction = typeof opts.action === "string" ? opts.action.trim() : "";
|
||||
const actionInput = rawAction || "send";
|
||||
const normalizedActionInput = normalizeLowercaseStringOrEmpty(actionInput);
|
||||
const actionMatch = (CHANNEL_MESSAGE_ACTION_NAMES as readonly string[]).find(
|
||||
(name) => name.toLowerCase() === actionInput.toLowerCase(),
|
||||
(name) => normalizeLowercaseStringOrEmpty(name) === normalizedActionInput,
|
||||
);
|
||||
if (!actionMatch) {
|
||||
throw new Error(`Unknown message action: ${actionInput}`);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
resolveUsableCustomProviderApiKey,
|
||||
} from "../../agents/model-auth.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { shortenHomePath } from "../../utils.js";
|
||||
import { maskApiKey } from "./list.format.js";
|
||||
import type { ProviderAuthOverview } from "./list.types.js";
|
||||
@@ -113,8 +114,9 @@ export function resolveProviderAuthOverview(params: {
|
||||
};
|
||||
}
|
||||
if (envKey) {
|
||||
const normalizedSource = normalizeLowercaseStringOrEmpty(envKey.source);
|
||||
const isOAuthEnv =
|
||||
envKey.source.includes("OAUTH_TOKEN") || envKey.source.toLowerCase().includes("oauth");
|
||||
envKey.source.includes("OAUTH_TOKEN") || normalizedSource.includes("oauth");
|
||||
return {
|
||||
kind: "env",
|
||||
detail: isOAuthEnv ? "OAuth (env)" : maskApiKey(envKey.apiKey),
|
||||
@@ -139,10 +141,12 @@ export function resolveProviderAuthOverview(params: {
|
||||
...(envKey
|
||||
? {
|
||||
env: {
|
||||
value:
|
||||
envKey.source.includes("OAUTH_TOKEN") || envKey.source.toLowerCase().includes("oauth")
|
||||
value: (() => {
|
||||
const normalizedSource = normalizeLowercaseStringOrEmpty(envKey.source);
|
||||
return envKey.source.includes("OAUTH_TOKEN") || normalizedSource.includes("oauth")
|
||||
? "OAuth (env)"
|
||||
: maskApiKey(envKey.apiKey),
|
||||
: maskApiKey(envKey.apiKey);
|
||||
})(),
|
||||
source: envKey.source,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { toAgentModelListLike } from "../../config/model-input.js";
|
||||
import type { AgentModelEntryConfig } from "../../config/types.agent-defaults.js";
|
||||
import type { AgentModelConfig } from "../../config/types.agents-shared.js";
|
||||
import { normalizeAgentId } from "../../routing/session-key.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
|
||||
export const ensureFlagCompatibility = (opts: { json?: boolean; plain?: boolean }) => {
|
||||
if (opts.json && opts.plain) {
|
||||
@@ -51,7 +52,7 @@ export const formatMs = (value?: number | null) => {
|
||||
export const isLocalBaseUrl = (baseUrl: string) => {
|
||||
try {
|
||||
const url = new URL(baseUrl);
|
||||
const host = url.hostname.toLowerCase();
|
||||
const host = normalizeLowercaseStringOrEmpty(url.hostname);
|
||||
return (
|
||||
host === "localhost" ||
|
||||
host === "127.0.0.1" ||
|
||||
|
||||
@@ -109,13 +109,18 @@ function resolveActiveChannel(params: {
|
||||
entry?.lastProvider ??
|
||||
entry?.provider ??
|
||||
""
|
||||
)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (candidate === INTERNAL_MESSAGE_CHANNEL) {
|
||||
).trim();
|
||||
const normalizedCandidate = normalizeOptionalLowercaseString(candidate);
|
||||
if (!normalizedCandidate) {
|
||||
return inferProviderFromSessionKey({
|
||||
cfg: params.cfg,
|
||||
sessionKey: params.sessionKey,
|
||||
});
|
||||
}
|
||||
if (normalizedCandidate === INTERNAL_MESSAGE_CHANNEL) {
|
||||
return INTERNAL_MESSAGE_CHANNEL;
|
||||
}
|
||||
const normalized = normalizeAnyChannelId(candidate);
|
||||
const normalized = normalizeAnyChannelId(normalizedCandidate);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import fs from "node:fs/promises";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
|
||||
export async function readFileTailLines(filePath: string, maxLines: number): Promise<string[]> {
|
||||
const raw = await fs.readFile(filePath, "utf8").catch(() => "");
|
||||
@@ -117,7 +118,7 @@ export function summarizeLogTail(rawLines: string[], opts?: { maxLines?: number
|
||||
const code = parsed?.error?.code?.trim() || null;
|
||||
const msg = parsed?.error?.message?.trim() || null;
|
||||
const msgShort = msg
|
||||
? msg.toLowerCase().includes("signing in again")
|
||||
? normalizeLowercaseStringOrEmpty(msg).includes("signing in again")
|
||||
? "re-auth required"
|
||||
: shorten(msg, 52)
|
||||
: null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js";
|
||||
import type { Tone } from "../memory-host-sdk/status.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import type { TableColumn } from "../terminal/table.js";
|
||||
import type { HealthSummary } from "./health.js";
|
||||
import type { AgentLocalStatus } from "./status.agent-local.js";
|
||||
@@ -253,7 +254,7 @@ export function buildStatusHealthRows(params: {
|
||||
}
|
||||
const item = line.slice(0, colon).trim();
|
||||
const detail = line.slice(colon + 1).trim();
|
||||
const normalized = detail.toLowerCase();
|
||||
const normalized = normalizeLowercaseStringOrEmpty(detail);
|
||||
const status = normalized.startsWith("ok")
|
||||
? params.ok("OK")
|
||||
: normalized.startsWith("failed")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { formatDurationPrecise } from "../infra/format-time/format-duration.ts";
|
||||
import { formatRuntimeStatusWithDetails } from "../infra/runtime-status.ts";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import type { SessionStatus } from "./status.types.js";
|
||||
export { shortenText } from "./text-format.js";
|
||||
|
||||
@@ -109,7 +110,8 @@ export const formatDaemonRuntimeShort = (runtime?: {
|
||||
const details: string[] = [];
|
||||
const detail = runtime.detail?.replace(/\s+/g, " ").trim() || "";
|
||||
const noisyLaunchctlDetail =
|
||||
runtime.missingUnit === true && detail.toLowerCase().includes("could not find service");
|
||||
runtime.missingUnit === true &&
|
||||
normalizeLowercaseStringOrEmpty(detail).includes("could not find service");
|
||||
if (detail && !noisyLaunchctlDetail) {
|
||||
details.push(detail);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../routing/session-key.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { resolveStateDir } from "./paths.js";
|
||||
import type { OpenClawConfig } from "./types.js";
|
||||
@@ -24,7 +25,7 @@ export class DuplicateAgentDirError extends Error {
|
||||
function canonicalizeAgentDir(agentDir: string): string {
|
||||
const resolved = path.resolve(agentDir);
|
||||
if (process.platform === "darwin" || process.platform === "win32") {
|
||||
return resolved.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(resolved);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
const MAX_ALLOWED_VALUES_HINT = 12;
|
||||
const MAX_ALLOWED_VALUE_CHARS = 160;
|
||||
|
||||
@@ -86,7 +88,7 @@ export function summarizeAllowedValues(
|
||||
}
|
||||
|
||||
function messageAlreadyIncludesAllowedValues(message: string): boolean {
|
||||
const lower = message.toLowerCase();
|
||||
const lower = normalizeLowercaseStringOrEmpty(message);
|
||||
return lower.includes("(allowed:") || lower.includes("expected one of");
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function normalizeSenderKey(
|
||||
return "";
|
||||
}
|
||||
const withoutAt = options.stripLeadingAt && trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
||||
return withoutAt.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(withoutAt);
|
||||
}
|
||||
|
||||
function normalizeTypedSenderKey(value: string, type: SenderKeyType): string {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
isSensitiveUrlConfigPath,
|
||||
redactSensitiveUrlLikeString,
|
||||
} from "../shared/net/redact-sensitive-url.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import {
|
||||
replaceSensitiveValuesInRaw,
|
||||
shouldFallbackToStructuredRawRedaction,
|
||||
@@ -28,7 +29,7 @@ function isEnvVarPlaceholder(value: string): boolean {
|
||||
}
|
||||
|
||||
function isWholeObjectSensitivePath(path: string): boolean {
|
||||
const lowered = path.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(path);
|
||||
return lowered.endsWith("serviceaccount") || lowered.endsWith("serviceaccountref");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
isSensitiveUrlConfigPath,
|
||||
SENSITIVE_URL_HINT_TAG,
|
||||
} from "../shared/net/redact-sensitive-url.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { FIELD_HELP } from "./schema.help.js";
|
||||
import { FIELD_LABELS } from "./schema.labels.js";
|
||||
import { applyDerivedTags } from "./schema.tags.js";
|
||||
@@ -128,7 +129,7 @@ const SENSITIVE_KEY_WHITELIST_SUFFIXES = [
|
||||
"passwordFile",
|
||||
] as const;
|
||||
const NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES = SENSITIVE_KEY_WHITELIST_SUFFIXES.map((suffix) =>
|
||||
suffix.toLowerCase(),
|
||||
normalizeLowercaseStringOrEmpty(suffix),
|
||||
);
|
||||
|
||||
const SENSITIVE_PATTERNS = [
|
||||
@@ -142,7 +143,7 @@ const SENSITIVE_PATTERNS = [
|
||||
];
|
||||
|
||||
function isWhitelistedSensitivePath(path: string): boolean {
|
||||
const lowerPath = path.toLowerCase();
|
||||
const lowerPath = normalizeLowercaseStringOrEmpty(path);
|
||||
return NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES.some((suffix) => lowerPath.endsWith(suffix));
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ function addTags(set: Set<ConfigTag>, tags: ReadonlyArray<ConfigTag>): void {
|
||||
}
|
||||
|
||||
export function deriveTagsForPath(path: string, hint?: ConfigUiHint): ConfigTag[] {
|
||||
const lowerPath = path.toLowerCase();
|
||||
const lowerPath = normalizeLowercaseStringOrEmpty(path);
|
||||
const override = resolveOverride(path);
|
||||
if (override) {
|
||||
return normalizeTags(override);
|
||||
|
||||
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { expandHomePrefix, resolveRequiredHomeDir } from "../../infra/home-dir.js";
|
||||
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../../routing/session-key.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { resolveStateDir } from "../paths.js";
|
||||
|
||||
function resolveAgentSessionsDir(
|
||||
@@ -142,7 +143,7 @@ function resolveStructuralSessionFallbackPath(
|
||||
return undefined;
|
||||
}
|
||||
const normalizedAgentId = normalizeAgentId(agentIdPart);
|
||||
if (normalizedAgentId !== agentIdPart.toLowerCase()) {
|
||||
if (normalizedAgentId !== normalizeLowercaseStringOrEmpty(agentIdPart)) {
|
||||
return undefined;
|
||||
}
|
||||
if (normalizedAgentId !== normalizeAgentId(expectedAgentId)) {
|
||||
|
||||
@@ -133,7 +133,7 @@ export function resolveChannelResetConfig(params: {
|
||||
if (!key) {
|
||||
return undefined;
|
||||
}
|
||||
return resetByChannel[key] ?? resetByChannel[key.toLowerCase()];
|
||||
return resetByChannel[key];
|
||||
}
|
||||
|
||||
export function evaluateSessionFreshness(params: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ChatType } from "../channels/chat-type.js";
|
||||
import type { SafeBinProfileFixture } from "../infra/exec-safe-bin-policy.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import type { AgentElevatedAllowFromConfig, SessionSendPolicyAction } from "./types.base.js";
|
||||
import type { MemoryQmdIndexPath } from "./types.memory.js";
|
||||
import type { ConfiguredProviderRequest } from "./types.provider-request.js";
|
||||
@@ -208,7 +209,7 @@ export function parseToolsBySenderTypedKey(
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
const lowered = trimmed.toLowerCase();
|
||||
const lowered = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
for (const type of TOOLS_BY_SENDER_KEY_TYPES) {
|
||||
const prefix = `${type}:`;
|
||||
if (!lowered.startsWith(prefix)) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
isWindowsAbsolutePath,
|
||||
} from "../shared/avatar-policy.js";
|
||||
import { isCanonicalDottedDecimalIPv4, isLoopbackIpAddress } from "../shared/net/ip.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
import { findDuplicateAgentDirs, formatDuplicateAgentDirError } from "./agent-dirs.js";
|
||||
import { appendAllowedValuesHint, summarizeAllowedValues } from "./allowed-values.js";
|
||||
@@ -830,7 +831,7 @@ function validateConfigObjectWithPluginsBase(
|
||||
|
||||
const heartbeatChannelIds = new Set<string>();
|
||||
for (const channelId of CHANNEL_IDS) {
|
||||
heartbeatChannelIds.add(channelId.toLowerCase());
|
||||
heartbeatChannelIds.add(normalizeLowercaseStringOrEmpty(channelId));
|
||||
}
|
||||
|
||||
const validateHeartbeatTarget = (target: string | undefined, path: string) => {
|
||||
@@ -842,7 +843,7 @@ function validateConfigObjectWithPluginsBase(
|
||||
issues.push({ path, message: "heartbeat target must not be empty" });
|
||||
return;
|
||||
}
|
||||
const normalized = trimmed.toLowerCase();
|
||||
const normalized = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
if (normalized === "last" || normalized === "none") {
|
||||
return;
|
||||
}
|
||||
@@ -855,7 +856,7 @@ function validateConfigObjectWithPluginsBase(
|
||||
for (const channelId of record.channels) {
|
||||
const pluginChannel = channelId.trim();
|
||||
if (pluginChannel) {
|
||||
heartbeatChannelIds.add(pluginChannel.toLowerCase());
|
||||
heartbeatChannelIds.add(normalizeLowercaseStringOrEmpty(pluginChannel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import path from "node:path";
|
||||
import { normalizeLowercaseStringOrEmpty } from "./string-coerce.js";
|
||||
|
||||
export const AVATAR_MAX_BYTES = 2 * 1024 * 1024;
|
||||
|
||||
@@ -25,7 +26,7 @@ export const WINDOWS_ABS_RE = /^[a-zA-Z]:[\\/]/;
|
||||
const AVATAR_PATH_EXT_RE = /\.(png|jpe?g|gif|webp|svg|ico)$/i;
|
||||
|
||||
export function resolveAvatarMime(filePath: string): string {
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const ext = normalizeLowercaseStringOrEmpty(path.extname(filePath));
|
||||
return AVATAR_MIME_BY_EXT[ext] ?? "application/octet-stream";
|
||||
}
|
||||
|
||||
@@ -78,6 +79,6 @@ export function looksLikeAvatarPath(value: string): boolean {
|
||||
}
|
||||
|
||||
export function isSupportedLocalAvatarExtension(filePath: string): boolean {
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const ext = normalizeLowercaseStringOrEmpty(path.extname(filePath));
|
||||
return LOCAL_AVATAR_EXTENSIONS.has(ext);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "./string-coerce.js";
|
||||
|
||||
export function inferParamBFromIdOrName(text: string): number | null {
|
||||
const raw = text.toLowerCase();
|
||||
const raw = normalizeLowercaseStringOrEmpty(text);
|
||||
const matches = raw.matchAll(/(?:^|[^a-z0-9])[a-z]?(\d+(?:\.\d+)?)b(?:[^a-z0-9]|$)/g);
|
||||
let best: number | null = null;
|
||||
for (const match of matches) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import ipaddr from "ipaddr.js";
|
||||
import { normalizeOptionalString } from "../string-coerce.js";
|
||||
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../string-coerce.js";
|
||||
|
||||
export type ParsedIpAddress = ipaddr.IPv4 | ipaddr.IPv6;
|
||||
type Ipv4Range = ReturnType<ipaddr.IPv4["range"]>;
|
||||
@@ -176,7 +176,7 @@ export function normalizeIpAddress(raw: string | undefined): string | undefined
|
||||
return undefined;
|
||||
}
|
||||
const normalized = normalizeIpv4MappedAddress(parsed);
|
||||
return normalized.toString().toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(normalized.toString());
|
||||
}
|
||||
|
||||
export function isCanonicalDottedDecimalIPv4(raw: string | undefined): boolean {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ConfigUiHint } from "../config-ui-hints-types.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../string-coerce.js";
|
||||
|
||||
export const SENSITIVE_URL_HINT_TAG = "url-secret";
|
||||
|
||||
@@ -17,7 +18,7 @@ const SENSITIVE_URL_QUERY_PARAM_NAMES = new Set([
|
||||
]);
|
||||
|
||||
export function isSensitiveUrlQueryParamName(name: string): boolean {
|
||||
return SENSITIVE_URL_QUERY_PARAM_NAMES.has(name.toLowerCase());
|
||||
return SENSITIVE_URL_QUERY_PARAM_NAMES.has(normalizeLowercaseStringOrEmpty(name));
|
||||
}
|
||||
|
||||
export function isSensitiveUrlConfigPath(path: string): boolean {
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { normalizeOptionalLowercaseString, normalizeOptionalString } from "./string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "./string-coerce.js";
|
||||
|
||||
export type NodeMatchCandidate = {
|
||||
nodeId: string;
|
||||
@@ -15,8 +19,7 @@ type ScoredNodeMatch = {
|
||||
};
|
||||
|
||||
export function normalizeNodeKey(value: string) {
|
||||
return value
|
||||
.toLowerCase()
|
||||
return normalizeLowercaseStringOrEmpty(value)
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+/, "")
|
||||
.replace(/-+$/, "");
|
||||
|
||||
@@ -5,7 +5,7 @@ export function normalizeStringEntries(list?: ReadonlyArray<unknown>) {
|
||||
}
|
||||
|
||||
export function normalizeStringEntriesLower(list?: ReadonlyArray<unknown>) {
|
||||
return normalizeStringEntries(list).map((entry) => entry.toLowerCase());
|
||||
return normalizeStringEntries(list).map((entry) => normalizeOptionalLowercaseString(entry) ?? "");
|
||||
}
|
||||
|
||||
export function normalizeTrimmedStringList(value: unknown): string[] {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../string-coerce.js";
|
||||
import { findCodeRegions, isInsideCode } from "./code-regions.js";
|
||||
import { stripModelSpecialTokens } from "./model-special-tokens.js";
|
||||
import {
|
||||
@@ -133,7 +134,7 @@ function parseToolCallTagAt(text: string, start: number): ParsedToolCallTag | nu
|
||||
cursor += 1;
|
||||
}
|
||||
|
||||
const tagName = text.slice(nameStart, cursor).toLowerCase();
|
||||
const tagName = normalizeLowercaseStringOrEmpty(text.slice(nameStart, cursor));
|
||||
if (!TOOL_CALL_TAG_NAMES.has(tagName) || !isToolCallBoundary(text[cursor])) {
|
||||
return null;
|
||||
}
|
||||
@@ -391,7 +392,7 @@ export function stripDowngradedToolCallText(text: string): string {
|
||||
while (index < input.length && (input[index] === " " || input[index] === "\t")) {
|
||||
index += 1;
|
||||
}
|
||||
if (input.slice(index, index + 9).toLowerCase() === "arguments") {
|
||||
if (normalizeLowercaseStringOrEmpty(input.slice(index, index + 9)) === "arguments") {
|
||||
index += 9;
|
||||
if (input[index] === ":") {
|
||||
index += 1;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../string-coerce.js";
|
||||
|
||||
const FILE_REF_EXTENSIONS = ["md", "go", "py", "pl", "sh", "am", "at", "be", "cc"] as const;
|
||||
|
||||
export const FILE_REF_EXTENSIONS_WITH_TLD = new Set<string>(FILE_REF_EXTENSIONS);
|
||||
@@ -11,7 +13,7 @@ export function isAutoLinkedFileRef(href: string, label: string): boolean {
|
||||
if (dotIndex < 1) {
|
||||
return false;
|
||||
}
|
||||
const ext = label.slice(dotIndex + 1).toLowerCase();
|
||||
const ext = normalizeLowercaseStringOrEmpty(label.slice(dotIndex + 1));
|
||||
if (!FILE_REF_EXTENSIONS_WITH_TLD.has(ext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user