From de34dfdbe8c4e7ec52553887654ce550ca1faad7 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Thu, 2 Jul 2026 22:12:53 -0700 Subject: [PATCH] refactor(plugins): consolidate record guards (#99361) --- extensions/codex-supervisor/src/config.ts | 5 +---- extensions/codex-supervisor/src/json-rpc-client.ts | 5 +---- extensions/codex-supervisor/src/supervisor.ts | 5 +---- extensions/codex/src/app-server/protocol-validators.ts | 5 +---- extensions/copilot/index.ts | 5 +---- extensions/diagnostics-otel/src/service.ts | 5 +---- extensions/feishu/src/doctor.ts | 5 +---- extensions/google/cli-backend-auth.runtime.ts | 5 +---- extensions/imessage/doctor-contract-api.ts | 5 +---- extensions/memory-wiki/doctor-contract-api.ts | 5 +---- extensions/msteams/doctor-contract-api.ts | 5 +---- extensions/nvidia/provider-catalog.ts | 5 +---- extensions/openrouter/oauth.ts | 5 +---- extensions/parallel/src/parallel-mcp-search.runtime.ts | 5 +---- extensions/policy/src/policy-conformance.ts | 5 +---- extensions/qa-lab/src/confidence-report.ts | 8 ++------ extensions/qa-lab/src/jsonl-replay.ts | 5 +---- extensions/qa-lab/src/providers/shared/auth-store.ts | 5 +---- extensions/qa-lab/src/suite-runtime-agent-process.ts | 5 +---- extensions/telegram/src/bot/body-helpers.ts | 5 +---- extensions/tokenjuice/tool-result-middleware.ts | 5 +---- extensions/workboard/src/cli.ts | 5 +---- 22 files changed, 23 insertions(+), 90 deletions(-) diff --git a/extensions/codex-supervisor/src/config.ts b/extensions/codex-supervisor/src/config.ts index 06fc0ec1317..db13e2ac649 100644 --- a/extensions/codex-supervisor/src/config.ts +++ b/extensions/codex-supervisor/src/config.ts @@ -1,3 +1,4 @@ +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; /** * Config parsing for Codex Supervisor endpoints and safety gates. */ @@ -61,10 +62,6 @@ function normalizeEndpointId(value: string, index: number): string { return `endpoint-${index + 1}`; } -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function parseEndpointRecord(value: unknown, index: number): CodexSupervisorEndpoint | undefined { if (!isRecord(value)) { return undefined; diff --git a/extensions/codex-supervisor/src/json-rpc-client.ts b/extensions/codex-supervisor/src/json-rpc-client.ts index 1b3ef284a0c..1eda2263e3a 100644 --- a/extensions/codex-supervisor/src/json-rpc-client.ts +++ b/extensions/codex-supervisor/src/json-rpc-client.ts @@ -7,6 +7,7 @@ import { randomUUID } from "node:crypto"; import * as net from "node:net"; import * as os from "node:os"; import * as path from "node:path"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import WebSocket from "ws"; import type { CodexJsonRpcConnection, CodexSupervisorEndpoint } from "./types.js"; @@ -16,10 +17,6 @@ type PendingRequest = { timeout: NodeJS.Timeout; }; -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function formatJsonRpcError(message: Record): Error { const error = isRecord(message.error) ? message.error : {}; const detail = diff --git a/extensions/codex-supervisor/src/supervisor.ts b/extensions/codex-supervisor/src/supervisor.ts index 8b26bbc1d56..0f29612f17f 100644 --- a/extensions/codex-supervisor/src/supervisor.ts +++ b/extensions/codex-supervisor/src/supervisor.ts @@ -2,6 +2,7 @@ * Codex app-server supervisor that lists sessions, reads transcripts, and * starts/steers/interrupts turns across configured endpoints. */ +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { connectCodexAppServerEndpoint } from "./json-rpc-client.js"; import type { CodexJsonRpcConnection, @@ -19,10 +20,6 @@ type EndpointConnector = (endpoint: CodexSupervisorEndpoint) => Promise { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function asRecordArray(value: unknown): Record[] { if (!Array.isArray(value)) { return []; diff --git a/extensions/codex/src/app-server/protocol-validators.ts b/extensions/codex/src/app-server/protocol-validators.ts index 109e528aff9..0f4ce819a4e 100644 --- a/extensions/codex/src/app-server/protocol-validators.ts +++ b/extensions/codex/src/app-server/protocol-validators.ts @@ -2,6 +2,7 @@ * Runtime validators for Codex app-server protocol payloads, including schema * normalization for generated JSON Schema before TypeBox compilation. */ +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { Compile, type Validator as TypeBoxValidator } from "typebox/compile"; import dynamicToolCallParamsSchema from "./protocol-generated/json/DynamicToolCallParams.json" with { type: "json" }; import errorNotificationSchema from "./protocol-generated/json/v2/ErrorNotification.json" with { type: "json" }; @@ -40,10 +41,6 @@ function compileCodexSchema(schema: unknown): CodexValidator { }; } -function isRecord(value: unknown): value is Record { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} - const schemaMapKeywords = new Set([ "$defs", "definitions", diff --git a/extensions/copilot/index.ts b/extensions/copilot/index.ts index cba6c43c0a2..b99947aad1d 100644 --- a/extensions/copilot/index.ts +++ b/extensions/copilot/index.ts @@ -1,11 +1,8 @@ // Copilot plugin entrypoint registers its OpenClaw integration. import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { createCopilotAgentHarness, type CopilotSessionBinding } from "./harness.js"; -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function readPoolOptions(pluginConfig: unknown): { idleTtlMs: number } | undefined { if (!isRecord(pluginConfig)) { return undefined; diff --git a/extensions/diagnostics-otel/src/service.ts b/extensions/diagnostics-otel/src/service.ts index df6063e98e2..3cd8f0f504e 100644 --- a/extensions/diagnostics-otel/src/service.ts +++ b/extensions/diagnostics-otel/src/service.ts @@ -30,6 +30,7 @@ import { } from "@opentelemetry/semantic-conventions/incubating"; import { waitForDiagnosticEventsDrained } from "openclaw/plugin-sdk/diagnostic-runtime"; import { registerUnhandledRejectionHandler } from "openclaw/plugin-sdk/runtime-env"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import type { DiagnosticEventMetadata, DiagnosticEventPayload, @@ -807,10 +808,6 @@ function describeJsonValue(value: unknown): string { return typeof value; } -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function textPart(content: string): Record { return { type: "text", content }; } diff --git a/extensions/feishu/src/doctor.ts b/extensions/feishu/src/doctor.ts index 48c7880713c..fad47d522d0 100644 --- a/extensions/feishu/src/doctor.ts +++ b/extensions/feishu/src/doctor.ts @@ -15,6 +15,7 @@ import { updateSessionStore, } from "openclaw/plugin-sdk/session-store-runtime"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; const FEISHU_STATE_DIR = "feishu"; const BACKUP_PREFIX = "feishu-state-repair"; @@ -84,10 +85,6 @@ function timestampForPath(now = new Date()): string { return now.toISOString().replaceAll(":", "-"); } -function isRecord(value: unknown): value is Record { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} - function toFeishuSessionEntry(value: unknown): FeishuSessionEntry { if (!isRecord(value)) { return {}; diff --git a/extensions/google/cli-backend-auth.runtime.ts b/extensions/google/cli-backend-auth.runtime.ts index c17d9afbec7..e3a9b6ec771 100644 --- a/extensions/google/cli-backend-auth.runtime.ts +++ b/extensions/google/cli-backend-auth.runtime.ts @@ -2,6 +2,7 @@ import crypto from "node:crypto"; import fs from "node:fs/promises"; import path from "node:path"; import type { CliBackendPreparedExecution } from "openclaw/plugin-sdk/cli-backend"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path"; import { GOOGLE_GEMINI_CLI_PROVIDER_ID, @@ -187,10 +188,6 @@ function resolveGeminiCliProfileHome(ctx: GeminiCliAuthHomeContext): { return { home, geminiDir: path.join(home, ".gemini") }; } -function isRecord(value: unknown): value is Record { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - function readGeminiAuthProfileCredential( credential: unknown, ): GeminiAuthProfileCredential | undefined { diff --git a/extensions/imessage/doctor-contract-api.ts b/extensions/imessage/doctor-contract-api.ts index d01fc209876..542c4696895 100644 --- a/extensions/imessage/doctor-contract-api.ts +++ b/extensions/imessage/doctor-contract-api.ts @@ -4,15 +4,12 @@ import type { ChannelDoctorLegacyConfigRule, } from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; // Disabled `channels.imessage.catchup` blocks are retired. Enabled blocks stay // as a compatibility contract: older configs that opted into replay still get // downtime recovery, while new/default installs use the always-on recovery // cursor plus stale-backlog fence. -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function isEnabledCatchup(value: unknown): boolean { return isRecord(value) && value.enabled === true; } diff --git a/extensions/memory-wiki/doctor-contract-api.ts b/extensions/memory-wiki/doctor-contract-api.ts index efa4d2adae3..adc4731cf4b 100644 --- a/extensions/memory-wiki/doctor-contract-api.ts +++ b/extensions/memory-wiki/doctor-contract-api.ts @@ -5,6 +5,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry"; import type { PluginDoctorStateMigration } from "openclaw/plugin-sdk/runtime-doctor"; import { resolveMemoryWikiConfig, type MemoryWikiPluginConfig } from "./src/config.js"; export { legacyConfigRules, normalizeCompatibilityConfig } from "./src/config-compat.js"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { countMemoryWikiImportRunStateRows, createMemoryWikiImportRunStateStore, @@ -24,10 +25,6 @@ import { writeMemoryWikiSourceSyncState, } from "./src/source-sync-state.js"; -function isRecord(value: unknown): value is Record { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} - function resolveHomeDir(env: NodeJS.ProcessEnv): string | undefined { return env.HOME?.trim() || env.USERPROFILE?.trim() || undefined; } diff --git a/extensions/msteams/doctor-contract-api.ts b/extensions/msteams/doctor-contract-api.ts index 944ddb861f0..165d3fe064d 100644 --- a/extensions/msteams/doctor-contract-api.ts +++ b/extensions/msteams/doctor-contract-api.ts @@ -5,6 +5,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import type { PluginDoctorStateMigration } from "openclaw/plugin-sdk/runtime-doctor"; import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { normalizeStoredConversationId } from "./src/conversation-store-helpers.js"; import { buildMSTeamsConversationStateKey, @@ -156,10 +157,6 @@ async function readLegacyJsonFile( } } -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function isStringArray(value: unknown): value is string[] { return Array.isArray(value) && value.every((entry) => typeof entry === "string"); } diff --git a/extensions/nvidia/provider-catalog.ts b/extensions/nvidia/provider-catalog.ts index 3fbdc2dfe08..163e4cec35d 100644 --- a/extensions/nvidia/provider-catalog.ts +++ b/extensions/nvidia/provider-catalog.ts @@ -13,6 +13,7 @@ import { type LookupFn, ssrfPolicyFromHttpBaseUrlAllowedHostname, } from "openclaw/plugin-sdk/ssrf-runtime"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import manifest from "./openclaw.plugin.json" with { type: "json" }; export const NVIDIA_DEFAULT_MODEL_ID = "nvidia/nemotron-3-ultra-550b-a55b"; @@ -165,10 +166,6 @@ function applyNvidiaModelDefaults(models: ModelDefinitionConfig[]): ModelDefinit ); } -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function parseNvidiaFeaturedModel(row: unknown): ModelDefinitionConfig | null { if (!row || typeof row !== "object") { return null; diff --git a/extensions/openrouter/oauth.ts b/extensions/openrouter/oauth.ts index 62b2843f7ba..83fb70b8857 100644 --- a/extensions/openrouter/oauth.ts +++ b/extensions/openrouter/oauth.ts @@ -9,6 +9,7 @@ import { } from "openclaw/plugin-sdk/provider-auth"; import { generateOAuthState } from "openclaw/plugin-sdk/provider-auth-runtime"; import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { applyOpenrouterConfig, OPENROUTER_DEFAULT_MODEL_REF } from "./onboard.js"; const PROVIDER_ID = "openrouter"; @@ -44,10 +45,6 @@ type OpenRouterOAuthLoginOptions = { waitForCallback?: typeof waitForOpenRouterOAuthCallback; }; -function isRecord(value: unknown): value is Record { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - function readString(value: unknown): string | undefined { return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined; } diff --git a/extensions/parallel/src/parallel-mcp-search.runtime.ts b/extensions/parallel/src/parallel-mcp-search.runtime.ts index 91153dd074a..9bf441e56e7 100644 --- a/extensions/parallel/src/parallel-mcp-search.runtime.ts +++ b/extensions/parallel/src/parallel-mcp-search.runtime.ts @@ -6,6 +6,7 @@ import { readResponseTextLimited, } from "openclaw/plugin-sdk/provider-http"; import { withTrustedWebSearchEndpoint } from "openclaw/plugin-sdk/provider-web-search"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; // Free hosted Search MCP. This keyless transport is used only after the user // explicitly selects the `parallel-free` web_search provider. Docs: @@ -37,10 +38,6 @@ export type ParallelMcpSearchResponse = { usage?: unknown; }; -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function mcpHeaders(params: { sessionId?: string; protocolVersion?: string; diff --git a/extensions/policy/src/policy-conformance.ts b/extensions/policy/src/policy-conformance.ts index 8e4d996c81f..e85b154aa72 100644 --- a/extensions/policy/src/policy-conformance.ts +++ b/extensions/policy/src/policy-conformance.ts @@ -4,6 +4,7 @@ import { basename, isAbsolute, resolve } from "node:path"; import JSON5 from "json5"; import type { HealthFinding } from "openclaw/plugin-sdk/health"; import { normalizeAgentId } from "openclaw/plugin-sdk/routing"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { isPolicyValueAtLeastAsStrict, policyContainerShapeFindings, @@ -624,7 +625,3 @@ function ocPathSegment(value: string): string { } return JSON.stringify(value); } - -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} diff --git a/extensions/qa-lab/src/confidence-report.ts b/extensions/qa-lab/src/confidence-report.ts index 6c4fa2bb3a3..9f009a1a45e 100644 --- a/extensions/qa-lab/src/confidence-report.ts +++ b/extensions/qa-lab/src/confidence-report.ts @@ -2,6 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { formatGatewayLogSentinelSummary, type GatewayLogSentinelFinding, @@ -140,10 +141,6 @@ const QA_CONFIDENCE_SELF_TEST_CANARY_IDS = [ "jsonl-replay-ordering-drift", ] as const; -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function readString(value: unknown): string | undefined { return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined; } @@ -389,8 +386,7 @@ function evaluateQaSuiteSummary(payload: unknown): QaConfidenceLaneEvaluation { const failedCount = readCount(counts?.failed); const explicitSkippedCount = readCount(counts?.skipped); if (totalCount !== undefined) { - const providedCountSum = - (passedCount ?? 0) + (failedCount ?? 0) + (explicitSkippedCount ?? 0); + const providedCountSum = (passedCount ?? 0) + (failedCount ?? 0) + (explicitSkippedCount ?? 0); if (totalCount < providedCountSum) { return { passed: false, diff --git a/extensions/qa-lab/src/jsonl-replay.ts b/extensions/qa-lab/src/jsonl-replay.ts index ed41f7de8da..ae51de5eee3 100644 --- a/extensions/qa-lab/src/jsonl-replay.ts +++ b/extensions/qa-lab/src/jsonl-replay.ts @@ -1,6 +1,7 @@ // Qa Lab plugin module implements jsonl replay behavior. import fs from "node:fs/promises"; import path from "node:path"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { runRuntimeParityScenario, type RuntimeId, @@ -51,10 +52,6 @@ export type JsonlReplayMarkdownReport = { transcripts: JsonlReplayResult["transcripts"]; }; -function isRecord(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); -} - function readString(value: unknown): string | undefined { return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined; } diff --git a/extensions/qa-lab/src/providers/shared/auth-store.ts b/extensions/qa-lab/src/providers/shared/auth-store.ts index 230c5e7a9f4..0e7fdac6999 100644 --- a/extensions/qa-lab/src/providers/shared/auth-store.ts +++ b/extensions/qa-lab/src/providers/shared/auth-store.ts @@ -1,6 +1,7 @@ // Qa Lab plugin module implements auth store behavior. import fs from "node:fs/promises"; import path from "node:path"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; type QaAuthProfileCredential = | { @@ -172,7 +173,3 @@ function isQaLegacyOAuthRef(value: unknown): value is QaLegacyOAuthRef { /^[a-f0-9]{32}$/.test(value.id) ); } - -function isRecord(value: unknown): value is Record { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} diff --git a/extensions/qa-lab/src/suite-runtime-agent-process.ts b/extensions/qa-lab/src/suite-runtime-agent-process.ts index 4d73edc4da2..c747e728032 100644 --- a/extensions/qa-lab/src/suite-runtime-agent-process.ts +++ b/extensions/qa-lab/src/suite-runtime-agent-process.ts @@ -5,6 +5,7 @@ import path from "node:path"; import { setTimeout as sleep } from "node:timers/promises"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { appendQaChildOutput, appendQaChildOutputTail, @@ -51,10 +52,6 @@ const MANAGED_DREAMING_CRON_MARKER = "[managed-by=memory-core.short-term-promoti const MANAGED_DREAMING_CRON_NAME = "Memory Dreaming Promotion"; const MANAGED_DREAMING_PROMPT = "__openclaw_memory_core_short_term_promotion_dream__"; -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function stripAnsiCodes(text: string) { return text.replace(ANSI_ESCAPE_PATTERN, ""); } diff --git a/extensions/telegram/src/bot/body-helpers.ts b/extensions/telegram/src/bot/body-helpers.ts index 6f0f6df7861..da97938f519 100644 --- a/extensions/telegram/src/bot/body-helpers.ts +++ b/extensions/telegram/src/bot/body-helpers.ts @@ -2,6 +2,7 @@ import type { Chat, Message, MessageOrigin, User } from "grammy/types"; import type { NormalizedLocation } from "openclaw/plugin-sdk/channel-inbound"; import { + isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "openclaw/plugin-sdk/string-coerce-runtime"; @@ -104,10 +105,6 @@ function hasTelegramRichMessage(value: unknown): boolean { return typeof value === "object" && value !== null && !Array.isArray(value); } -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function compactRichText(value: string): string { return value .split("\n") diff --git a/extensions/tokenjuice/tool-result-middleware.ts b/extensions/tokenjuice/tool-result-middleware.ts index fda39b2e9e7..25881533bb5 100644 --- a/extensions/tokenjuice/tool-result-middleware.ts +++ b/extensions/tokenjuice/tool-result-middleware.ts @@ -5,6 +5,7 @@ import type { AgentToolResultMiddlewareEvent, OpenClawAgentToolResult, } from "openclaw/plugin-sdk/agent-harness"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { createTokenjuiceOpenClawEmbeddedExtension } from "./runtime-api.js"; type TokenjuiceToolResultHandler = ( @@ -18,10 +19,6 @@ type TokenjuiceToolResultHandler = ( ctx: { cwd: string }, ) => Promise | void> | Partial | void; -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - function readCwd(event: AgentToolResultMiddlewareEvent): string { if (event.cwd?.trim()) { return event.cwd; diff --git a/extensions/workboard/src/cli.ts b/extensions/workboard/src/cli.ts index 26b25cad142..16e3f52e67d 100644 --- a/extensions/workboard/src/cli.ts +++ b/extensions/workboard/src/cli.ts @@ -3,6 +3,7 @@ import type { Command } from "commander"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; import { addGatewayClientOptions, callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime"; import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot"; +import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolveWorkboardCardByIdOrPrefix } from "./card-lookup.js"; import type { WorkboardDispatchResult, WorkboardStore } from "./store.js"; import type { WorkboardCard } from "./types.js"; @@ -27,10 +28,6 @@ function writeLine(value: string): void { process.stdout.write(`${value}\n`); } -function isRecord(value: unknown): value is Record { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} - function splitLabels(value: string | undefined): string[] | undefined { return value ?.split(",")