From 60acc1ed5d66235baa0e234e6cf278cba201bff0 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sun, 31 May 2026 16:47:36 -0400 Subject: [PATCH] refactor: share strip undefined helper --- packages/cli/src/agent-sandbox.ts | 6 +----- packages/cli/src/commands/recipe-run.ts | 6 +----- packages/cli/src/recipe-dry-run.ts | 6 +----- packages/cli/src/recipe-evidence.ts | 6 +----- packages/cli/src/runtime-command-wrappers.ts | 6 +----- packages/runtime-core/src/object-utils.ts | 4 ++++ packages/runtime-playground/src/artifacts.ts | 6 +----- 7 files changed, 10 insertions(+), 30 deletions(-) diff --git a/packages/cli/src/agent-sandbox.ts b/packages/cli/src/agent-sandbox.ts index e0e7fa6..ddec690 100644 --- a/packages/cli/src/agent-sandbox.ts +++ b/packages/cli/src/agent-sandbox.ts @@ -1,6 +1,6 @@ import { readFile } from "node:fs/promises" import { basename, resolve } from "node:path" -import { SANDBOX_DMC_PARENT_ONLY_ABILITIES, SANDBOX_DMC_SAFE_ABILITIES, SANDBOX_WORKSPACE_ROOT, type MountSpec, type RuntimePolicy, type SandboxWorkspaceContract, type SandboxWorkspaceMode, type WorkspaceRecipe } from "@chubes4/wp-codebox-core" +import { SANDBOX_DMC_PARENT_ONLY_ABILITIES, SANDBOX_DMC_SAFE_ABILITIES, SANDBOX_WORKSPACE_ROOT, stripUndefined, type MountSpec, type RuntimePolicy, type SandboxWorkspaceContract, type SandboxWorkspaceMode, type WorkspaceRecipe } from "@chubes4/wp-codebox-core" import { agentRuntimeProbeCode, agentSandboxRunCode, resolveSandboxTaskCode } from "./agent-code.js" import type { PreparedWorkspaceMount } from "./recipe-sources.js" import { defaultPolicy } from "./recipe-validation.js" @@ -452,7 +452,3 @@ function workspaceMountRef(target: string, mode: "readonly" | "readwrite", metad wpContentPath: typeof metadata.wpContentPath === "string" ? metadata.wpContentPath : undefined, }) } - -function stripUndefined>(value: T): T { - return Object.fromEntries(Object.entries(value).filter(([, entryValue]) => entryValue !== undefined)) as T -} diff --git a/packages/cli/src/commands/recipe-run.ts b/packages/cli/src/commands/recipe-run.ts index 824bf2c..68598e5 100644 --- a/packages/cli/src/commands/recipe-run.ts +++ b/packages/cli/src/commands/recipe-run.ts @@ -1,6 +1,6 @@ import { readFile } from "node:fs/promises" import { basename, dirname, resolve } from "node:path" -import { createRuntime, type ArtifactBundle, type ExecutionResult, type Runtime, type RuntimeInfo, type WorkspaceRecipe, type WorkspaceRecipePluginRuntimeHealthProbe, type WorkspaceRecipeSiteSeed } from "@chubes4/wp-codebox-core" +import { createRuntime, stripUndefined, type ArtifactBundle, type ExecutionResult, type Runtime, type RuntimeInfo, type WorkspaceRecipe, type WorkspaceRecipePluginRuntimeHealthProbe, type WorkspaceRecipeSiteSeed } from "@chubes4/wp-codebox-core" import { createPlaygroundRuntimeBackend } from "@chubes4/wp-codebox-playground" import { recipeExecutionSpec, sandboxWorkspaceContract } from "../agent-sandbox.js" import { captureStdout, printRecipeHumanOutput, printRecipeValidateHumanOutput, serializeError } from "../output.js" @@ -1293,7 +1293,3 @@ function matchesNumberSelector(record: Record, allowed: number[ const values = keys.map((key) => record[key]).filter((value): value is number => typeof value === "number") return values.some((value) => allowed.includes(value)) } - -function stripUndefined>(record: T): T { - return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T -} diff --git a/packages/cli/src/recipe-dry-run.ts b/packages/cli/src/recipe-dry-run.ts index 2367a17..5a9dcb4 100644 --- a/packages/cli/src/recipe-dry-run.ts +++ b/packages/cli/src/recipe-dry-run.ts @@ -1,6 +1,6 @@ import { readFile } from "node:fs/promises" import { basename, dirname, resolve } from "node:path" -import { SANDBOX_WORKSPACE_ROOT, validateRuntimePolicy, type MountSpec, type RuntimePolicy, type SandboxWorkspaceMode, type WorkspaceRecipe, type WorkspaceRecipePluginRuntime, type WorkspaceRecipePluginRuntimeHealthProbe, type WorkspaceRecipeSiteSeed, type WorkspaceRecipeWorkspace } from "@chubes4/wp-codebox-core" +import { SANDBOX_WORKSPACE_ROOT, stripUndefined, validateRuntimePolicy, type MountSpec, type RuntimePolicy, type SandboxWorkspaceMode, type WorkspaceRecipe, type WorkspaceRecipePluginRuntime, type WorkspaceRecipePluginRuntimeHealthProbe, type WorkspaceRecipeSiteSeed, type WorkspaceRecipeWorkspace } from "@chubes4/wp-codebox-core" import { serializeError } from "./output.js" import { activateExtraPluginsCode, defaultWorkspaceTarget, installMuPluginsCode, pluginTarget, recipeExtraPluginFile, recipeExtraPluginSlug, recipeExtraPlugins, recipeMountType, recipeSource, recipeSourceProvenance, resolveRecipeExtraPluginFile, stagedFileMountType, stagedFileProvenance, type RecipeSourceProvenance, type RecipeSourceType, type RecipeStagedFileProvenance } from "./recipe-sources.js" import { hasExplicitSiteSeedSelectors, parseWorkspaceRecipe, pluginRuntimeHealthProbeStep, recipePolicy, recipeWorkflowSteps, validateWorkspaceRecipe, type RecipeValidationIssue, type RecipeWorkflowPhase } from "./recipe-validation.js" @@ -514,7 +514,3 @@ export function siteSeedScopesAreBounded(siteSeed: WorkspaceRecipeSiteSeed): boo return Object.values(siteSeed.scopes).some((scope) => scope !== undefined && scope !== false) } - -function stripUndefined>(record: T): T { - return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T -} diff --git a/packages/cli/src/recipe-evidence.ts b/packages/cli/src/recipe-evidence.ts index f9a8d15..77f4c38 100644 --- a/packages/cli/src/recipe-evidence.ts +++ b/packages/cli/src/recipe-evidence.ts @@ -4,7 +4,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises" import { dirname, join, relative, resolve } from "node:path" import { fileURLToPath } from "node:url" import { promisify } from "node:util" -import { artifactFileDigest, artifactManifestFileWithSha256, checkWorkspacePolicy, isPlainObject as isRecord, refreshArtifactManifestFileSha256s, sha256StableJson, upsertArtifactManifestFiles, verifyArtifactBundle, type ArtifactBundle, type ArtifactBundleVerificationResult, type ArtifactManifest, type ArtifactManifestFile, type ExecutionResult, type Runtime, type RuntimeInfo, type RuntimePolicy, type WorkspacePolicyResult, type WorkspaceRecipe } from "@chubes4/wp-codebox-core" +import { artifactFileDigest, artifactManifestFileWithSha256, checkWorkspacePolicy, isPlainObject as isRecord, refreshArtifactManifestFileSha256s, sha256StableJson, stripUndefined, upsertArtifactManifestFiles, verifyArtifactBundle, type ArtifactBundle, type ArtifactBundleVerificationResult, type ArtifactManifest, type ArtifactManifestFile, type ExecutionResult, type Runtime, type RuntimeInfo, type RuntimePolicy, type WorkspacePolicyResult, type WorkspaceRecipe } from "@chubes4/wp-codebox-core" export interface RecipeArtifactEvidenceFile { path: string @@ -813,7 +813,3 @@ function markRecipeArtifactsFinalized(interruption: RecipeArtifactsFinalizationC ;(interruption.metadata as { artifactsFinalized: boolean }).artifactsFinalized = artifactsFinalized } - -function stripUndefined>(record: T): T { - return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T -} diff --git a/packages/cli/src/runtime-command-wrappers.ts b/packages/cli/src/runtime-command-wrappers.ts index 6c52e61..94bcc5d 100644 --- a/packages/cli/src/runtime-command-wrappers.ts +++ b/packages/cli/src/runtime-command-wrappers.ts @@ -1,4 +1,4 @@ -import { createRuntime, type ArtifactBundle, type ExecutionResult, type MountSpec, type Runtime, type RuntimeInfo, type RuntimePolicy } from "@chubes4/wp-codebox-core" +import { createRuntime, stripUndefined, type ArtifactBundle, type ExecutionResult, type MountSpec, type Runtime, type RuntimeInfo, type RuntimePolicy } from "@chubes4/wp-codebox-core" import { createPlaygroundRuntimeBackend } from "@chubes4/wp-codebox-playground" import { serializeError } from "./output.js" import { recipeMountType } from "./recipe-sources.js" @@ -362,7 +362,3 @@ export async function releaseRuntime(runtime: Runtime, previewHoldSeconds = 0, a await afterDestroy?.() } } - -function stripUndefined>(record: T): T { - return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T -} diff --git a/packages/runtime-core/src/object-utils.ts b/packages/runtime-core/src/object-utils.ts index 6d3e5e9..6255df7 100644 --- a/packages/runtime-core/src/object-utils.ts +++ b/packages/runtime-core/src/object-utils.ts @@ -23,6 +23,10 @@ export function sha256StableJson(value: unknown, trailingNewline = false): strin return createHash("sha256").update(`${stableJson(value)}${trailingNewline ? "\n" : ""}`).digest("hex") } +export function stripUndefined>(record: T): T { + return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T +} + export function stringList(value: unknown): string[] { if (!Array.isArray(value)) return [] diff --git a/packages/runtime-playground/src/artifacts.ts b/packages/runtime-playground/src/artifacts.ts index f67e104..e815a31 100644 --- a/packages/runtime-playground/src/artifacts.ts +++ b/packages/runtime-playground/src/artifacts.ts @@ -2,7 +2,7 @@ import { createHash } from "node:crypto" import { readdir, readFile } from "node:fs/promises" import { basename, join } from "node:path" import { normalizeBlueprint, preferredVersionsForEnvironment } from "./blueprint.js" -import { artifactFileDigest } from "@chubes4/wp-codebox-core" +import { artifactFileDigest, stripUndefined } from "@chubes4/wp-codebox-core" import type { ArtifactPreview, ArtifactProvenance, @@ -517,10 +517,6 @@ function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value) } -function stripUndefined>(record: T): T { - return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T -} - function fileDiff(path: string, before: string, after: string, isAdded: boolean, isDeleted: boolean): string { const beforeLines = splitLines(before) const afterLines = splitLines(after)