/* RFC-0356 §7: sternsystem.extract — extract an apps// site into a Sternsystem git repo. Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file. RFC-0356: initial sternsystem.extract command handler. RFC-0381: schema-compliant pin generation using shared pin-helpers; case-insensitive RFC regex; resolve ecosystem metadata. RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt */ import path from "node:path"; import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { systemPinSchema, type SystemPin } from "@warpgogol/werkstatt-engine/schemas"; import { readSystemConfig, writeSystemConfig, resolveCacheClonePath, resolveMirrors, } from "../sternsystem/registry-io.ts"; import { acquireLock, releaseLock, generateOperationId } from "../werkstatt/index.ts"; import { atomicWriteFile } from "../werkstatt/atomic.ts"; import { appendAndCommitBordbuch } from "../bordbuch/bordbuch-commit-helper.ts"; import { resolveCurrentEcosystem, resolvePlatformSemanticHash } from "../handoff/bundle-io.ts"; import { allMigratorIds } from "../migrators/registry.ts"; import { highestRfcId, snapshotCapabilities } from "./pin-helpers.ts"; import { createDefaultIO, type WorkspaceIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io"; export interface SternsystemExtractData { appId: string; systemId: string; mirrors: Array<{ path: string; storageType: string }>; extractedAt: string; pinVersion: string; } function flagString(input: KernelCommandInput, key: string): string | undefined { const v = input.flags[key]; return typeof v === "string" ? v : undefined; } const EXTRACTION_DATA_PATHS = ["src/content", "public", "provenance"]; async function copyDir( src: string, dest: string, io: WorkspaceIO = createDefaultIO().io, ): Promise { if (!(await io.exists(src))) return; await io.mkdir(dest); const entries = await io.readdir(src); for (const entry of entries) { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name); if (entry.isDirectory) { await copyDir(srcPath, destPath); } else { await io.copyFile(srcPath, destPath); } } } export async function runSternsystemExtract( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot, logger } = context; const siteId = flagString(input, "site"); const mirrorsFlag = flagString(input, "mirrors"); if (!siteId) throw new Error("[sternsystem.extract] --site is required"); const appDir = path.join(workspaceRoot, "apps", siteId); if (!(await context.io.exists(appDir))) { throw new Error(`[sternsystem.extract] apps/${siteId}/ does not exist`); } const mirrors = mirrorsFlag ? mirrorsFlag.split(",").map((entry) => { const [pathPart, typePart] = entry.split(":"); return { path: pathPart, storageType: typePart || "non-bare" }; }) : [ { path: `../systems-cache/${siteId}`, storageType: "non-bare" }, { path: `../systems-git/${siteId}`, storageType: "bare" }, ]; const operationId = generateOperationId(); await acquireLock(workspaceRoot, `system:${siteId}`, operationId, "sternsystem.extract", "agent"); try { let config: Awaited> | null = null; try { config = await readSystemConfig(workspaceRoot, siteId); } catch { config = null; } const systemDir = config ? resolveMirrors(workspaceRoot, config).cachePath : resolveCacheClonePath(workspaceRoot, siteId); await context.io.mkdir(systemDir); // Copy data paths for (const dataPath of EXTRACTION_DATA_PATHS) { const src = path.join(appDir, dataPath); const dest = path.join(systemDir, dataPath); if (await context.io.exists(src)) { await copyDir(src, dest); logger.info(` Copied ${dataPath}`); } } // Write pin file (schema-compliant per systemPinSchema) const { version: pinVersion, commit } = await resolveCurrentEcosystem(workspaceRoot); const rfcHead = await highestRfcId(workspaceRoot); const platformSemanticHash = await resolvePlatformSemanticHash(workspaceRoot); const capabilities = await snapshotCapabilities(workspaceRoot); const pin: SystemPin = { schemaVersion: "1.0.0", systemId: siteId, cosmicStar: config?.cosmicStar ?? "Vega", pinnedAt: new Date().toISOString(), platform: { version: pinVersion, commit: commit === "unknown" ? "0000000" : commit, rfcHead, platformSemanticHash, }, migratorCursor: allMigratorIds(), capabilities, }; systemPinSchema.parse(pin); await atomicWriteFile( path.join(systemDir, "system.pin.json"), JSON.stringify(pin, null, 2) + "\n", ); // Write initial Bordbuch (RFC-0750: commit atomically) await appendAndCommitBordbuch( workspaceRoot, siteId, "pin-update", `Initial pin at ${pinVersion}`, "agent", { writerRole: "sternsystem", metadata: { oldVersion: null, newVersion: pinVersion }, }, `Bordbuch: pin-update ${siteId}`, ); // Update config if (config) { config.status = "active"; config.pinnedPlatform = pinVersion; config.mirrors = mirrors as Array<{ path: string; storageType: "non-bare" | "bare" | "bundle"; }>; await writeSystemConfig(workspaceRoot, siteId, config); } const now = new Date().toISOString(); logger.success(`[sternsystem.extract] extracted ${siteId} to ${mirrors[0].path}`); return { data: { appId: siteId, systemId: siteId, mirrors, extractedAt: now, pinVersion }, exitCode: 0, summary: `[sternsystem.extract] extracted ${siteId} to ${mirrors[0].path}`, }; } finally { await releaseLock(workspaceRoot, `system:${siteId}`); } }