#!/usr/bin/env node import { writeFile } from "node:fs/promises"; import process from "node:process"; import { compileWorkspaceRepository } from "./assembly.js"; import { createGitCapabilityResolver } from "./git-resolver.js"; const usage = `usage: quixos-workspace-compile --root DIRECTORY --checkout-root DIRECTORY [--snapshot-map PATH] [--graph-out PATH] [--workspace-id ID] [--workspace-revision-id ID] [--source-root-commit GIT_REV] Resolves a workspace's recursive resource-lock graph, clones every exact resource revision, validates standalone interface/package manifests, and emits the checked workspace plan as JSON.`; const parseArgs = (args: string[]) => { const values = new Map(); for (let index = 0; index < args.length; index += 2) { const key = args[index]; const value = args[index + 1]; if (!key?.startsWith("--") || !value) throw new Error(usage); values.set(key, value); } const rootDirectory = values.get("--root"); const checkoutRoot = values.get("--checkout-root"); if (!rootDirectory || !checkoutRoot) throw new Error(usage); return { rootDirectory, checkoutRoot, graphOut: values.get("--graph-out"), snapshotMap: values.get("--snapshot-map"), workspaceId: values.get("--workspace-id"), workspaceRevisionId: values.get("--workspace-revision-id"), sourceRootCommit: values.get("--source-root-commit"), }; }; const main = async () => { if (process.argv.includes("--help") || process.argv.includes("-h")) { process.stdout.write(`${usage}\n`); return; } const options = parseArgs(process.argv.slice(2)); const resolveResource = await createGitCapabilityResolver({ checkoutRoot: options.checkoutRoot, snapshotMap: options.snapshotMap, }); const assembled = await compileWorkspaceRepository({ rootDirectory: options.rootDirectory, workspaceId: options.workspaceId, workspaceRevisionId: options.workspaceRevisionId, sourceRootCommit: options.sourceRootCommit, resolveResource, }); if (options.graphOut) { await writeFile(options.graphOut, `${JSON.stringify({ formatVersion: 1, quixos: assembled.lock.quixos, directResources: [...assembled.directResources.entries()].map(([bindingKey, node]) => { const [kind, binding] = bindingKey.split("\0"); return { kind, binding, resourceKey: node.key, directory: node.directory }; }), resources: assembled.resources.map((node) => ({ key: node.key, kind: node.kind, source: node.source, directory: node.directory, resourceId: node.resource.kind === "interface" ? node.resource.revision.interfaceId : node.resource.revision.packageId, revisionId: node.resource.revision.revisionId, dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({ binding, resourceKey: dependency.key, })), })), }, null, 2)}\n`); } process.stdout.write(`${JSON.stringify(assembled.workspace, null, 2)}\n`); }; main().catch((error: unknown) => { process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`); process.exitCode = 1; });