Add exact recursive source checkout, independent Git/jj developer workbenches and source-only backup/recovery commands, with Workspace instance binding outside source. Qualify two empty Reader Graphs, packaged source commands, Agent VM compilation, exact Gitea read grants and reconciled Reader settings/annotation stability. Publish checked Reader Package/root revisions to canonical review branches and retention tags, retain all 57 repositories independently in private versioned storage, verify downloaded-backup recovery and advance the example pin. Add bounded Central pin acquisition and selection-specific read-only identities, qualified against all 57 canonical repositories without write authority. Replace regex fork dependency discovery with compiler-parsed lock imports and rewrite proposals; preserve source identities and unrelated files, passing instance binding through packed and ordinary host checks. Hosted run-pin versus authoring preparation and maintained duplicate removal remain pending. Live source selections, Template defaults and default source branches are unchanged.
168 lines
7.0 KiB
JavaScript
168 lines
7.0 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { readFile, writeFile } from "node:fs/promises";
|
|
import process from "node:process";
|
|
import { compileWorkspaceRepository } from "./assembly.js";
|
|
import { createGitCapabilityResolver } from "./git-resolver.js";
|
|
import { loadQueryGenerator } from "./query-generator.js";
|
|
import { loadCheckedResources } from "./checked-resources.js";
|
|
import { profile } from "./profile.js";
|
|
import { compileExecutionPlan, packageBuildContexts } from "../execution-world/index.js";
|
|
import { bindingSchema, specializeBindingSchema } from "../bindings/index.js";
|
|
import {
|
|
planEvolution,
|
|
runtimeContracts,
|
|
type EvolutionReview,
|
|
type WorkspaceRevision,
|
|
} from "../capability-model/index.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] [--baseline PLAN_JSON] [--evolution-out PATH]
|
|
[--reviews REVIEW_JSON] [--schemas-out PATH] [--execution-plan-out PATH] [--build-contexts-out PATH]
|
|
[--query-generator BUILD_MODULE_PATH] [--checked-resources NIX_MAP]
|
|
|
|
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<string, string>();
|
|
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"),
|
|
schemasOut: values.get("--schemas-out"),
|
|
executionPlanOut: values.get("--execution-plan-out"),
|
|
buildContextsOut: values.get("--build-contexts-out"),
|
|
snapshotMap: values.get("--snapshot-map"),
|
|
workspaceId: values.get("--workspace-id"),
|
|
workspaceRevisionId: values.get("--workspace-revision-id"),
|
|
sourceRootCommit: values.get("--source-root-commit"),
|
|
baseline: values.get("--baseline"),
|
|
evolutionOut: values.get("--evolution-out"),
|
|
reviews: values.get("--reviews"),
|
|
queryGenerator: values.get("--query-generator"),
|
|
checkedResources: values.get("--checked-resources"),
|
|
};
|
|
};
|
|
|
|
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 assemblyStarted = performance.now();
|
|
const assembled = await compileWorkspaceRepository({
|
|
rootDirectory: options.rootDirectory,
|
|
workspaceId: options.workspaceId,
|
|
workspaceRevisionId: options.workspaceRevisionId,
|
|
sourceRootCommit: options.sourceRootCommit,
|
|
resolveResource,
|
|
generateQueries: await loadQueryGenerator(options.queryGenerator),
|
|
checkedResource: await loadCheckedResources(options.checkedResources),
|
|
});
|
|
profile("workspace-assembly", assemblyStarted, { resources: assembled.resources.length });
|
|
|
|
if (options.graphOut) {
|
|
await writeFile(
|
|
options.graphOut,
|
|
`${JSON.stringify(
|
|
{
|
|
formatVersion: 1,
|
|
workspaceId: assembled.workspace.workspaceId,
|
|
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,
|
|
...(node.resource.kind === "build"
|
|
? {}
|
|
: {
|
|
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`,
|
|
);
|
|
}
|
|
const candidate = { ...assembled.workspace, executionContracts: runtimeContracts(assembled.workspace) };
|
|
if (options.executionPlanOut || options.buildContextsOut) {
|
|
const executionStarted = performance.now();
|
|
const plan = compileExecutionPlan(assembled.workspace);
|
|
// Machine-consumed immutable metadata should not spend its bounded input
|
|
// reservation on indentation. Its parsed allocation is charged separately.
|
|
if (options.executionPlanOut) await writeFile(options.executionPlanOut, `${JSON.stringify(plan)}\n`);
|
|
if (options.buildContextsOut)
|
|
await writeFile(options.buildContextsOut, JSON.stringify(packageBuildContexts(plan.definition.bindingSchema)));
|
|
profile("execution-plan-and-contexts", executionStarted);
|
|
}
|
|
if (options.schemasOut) {
|
|
const schemasStarted = performance.now();
|
|
const schemas: Record<string, unknown> = {};
|
|
for (const node of assembled.capabilityResources.filter((entry) => entry.kind === "package")) {
|
|
const closure = new Map<string, typeof node>();
|
|
const visit = (entry: typeof node) => {
|
|
if (closure.has(entry.key) || entry.kind === "build") return;
|
|
closure.set(entry.key, entry);
|
|
entry.dependencies.forEach(visit);
|
|
};
|
|
visit(node);
|
|
if (node.resource.kind !== "package") continue;
|
|
schemas[node.resource.revision.revisionId] = specializeBindingSchema(
|
|
bindingSchema({ resources: [...closure.values()] }),
|
|
candidate,
|
|
node.resource.revision.revisionId,
|
|
);
|
|
}
|
|
await writeFile(options.schemasOut, JSON.stringify(schemas));
|
|
profile("package-schemas", schemasStarted);
|
|
}
|
|
if (options.evolutionOut) {
|
|
const baseline = options.baseline
|
|
? (JSON.parse(await readFile(options.baseline, "utf8")) as WorkspaceRevision)
|
|
: null;
|
|
const reviews = options.reviews ? (JSON.parse(await readFile(options.reviews, "utf8")) as EvolutionReview[]) : [];
|
|
if (!Array.isArray(reviews)) throw new Error("Review file must contain an array");
|
|
await writeFile(
|
|
options.evolutionOut,
|
|
`${JSON.stringify(planEvolution(baseline, candidate, { reviews }), null, 2)}\n`,
|
|
);
|
|
}
|
|
process.stdout.write(`${JSON.stringify(candidate, null, 2)}\n`);
|
|
};
|
|
|
|
main().catch((error: unknown) => {
|
|
process.stderr.write(`${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`);
|
|
process.exitCode = 1;
|
|
});
|