Add imperative feature bundles, intrinsic component sizing, and authoring timing logs

Generate state-backed atoms, interfaces, relationships and React/CSS packages
in a resumable command that prints the full source diff. Keep scaffold output
ordinary editable code. Shorten installed authoring guides while preserving
contracts and clarify historical design context.

Test generated bundles through immutable Nix verification and cover browser
isolation, nested sizing, interruption recovery, and command help.
This commit is contained in:
Timothy J. Aveni
2026-09-15 13:45:42 -07:00
parent 53708ac06f
commit a174faea5c
7 changed files with 100 additions and 14 deletions
+29 -1
View File
@@ -14,6 +14,8 @@ export type ScaffoldRecipe = {
template?: "typescript" | "typescript-react";
source: Source; directory?: string; name?: string; id?: string; revision?: string;
declaration?: string;
/** Initial authored files for a composed recipe; only used for a new package. */
initialFiles?: Record<string, string>;
tools?: {quixos: Source; protocol: Source; helpers: Source; sdk: Source};
nixifyPluginUrl?: string;
migration?: Omit<MigrationDeclaration, "implementation"> & {contracts: Record<string, unknown>};
@@ -69,7 +71,7 @@ export const scaffoldRecipe = async (root: string, command: "package" | "functio
if (react) {
create("src/component.tsx", `// Props are opaque at the platform boundary until capability generics exist.\nexport default function Component(_props: {camino: unknown; render: unknown; dispatch: (action: unknown) => void}) {\n return <section><h1>${name}</h1><p>Edit this component, then run qx-workspace check.</p></section>;\n}\n`);
create("src/impl/sourceGet.ts", `import componentSource from "../component.js?browser-source";\nimport type {Implementation} from "../gen/qx.js";\nexport const handler: Implementation["sourceGet"] = () => componentSource;\n`);
create("src/browser-assets.d.ts", `declare module "*?browser-source" { const source: string; export default source; }\n`);
create("src/browser-assets.d.ts", `declare module "*?browser-source" { const source: string; export default source; }\ndeclare module "*.css" {}\n`);
create("src/gen/web-studio-react-runtime.d.ts", reactPlatformTypes);
}
create(".gitignore", "node_modules/\ndist/\n.quixos/\nresult\n.yarn/install-state.gz\n");
@@ -161,5 +163,31 @@ export const scaffoldRecipe = async (root: string, command: "package" | "functio
create("src/migrate.ts", `import {serveMigration} from "@quixos/camino-package-runtime";\n` + migrations.map((entry, index) => `import {handler as impl${index}} from ${JSON.stringify(`./${entry.file.slice(4, -3)}.js`)};\n`).join("") + `await serveMigration({${migrations.map((entry, index) => `${JSON.stringify(entry.id)}: impl${index}`).join(", ")}});\n`);
}
generated("descriptor.quixos-package.txtpb", `# Generated by qx-scaffold-v1\npackage_id: ${JSON.stringify(packageModel.id)}\npackage_revision_id: ${JSON.stringify(packageModel.revision)}\nruntime_protocol_version: "quixos-capabilities-v1"\n` + packageModel.exports.map((entry) => `exports: { export_id: ${JSON.stringify(entry.id)} runtime_symbol: ${JSON.stringify(entry.name)} }\n`).join(""));
if (spec.initialFiles) {
if (command !== "package") throw new Error("initialFiles is only valid when creating a package");
const authored = spec.initialFiles["package.qx"];
if (authored !== undefined) {
const parsed = parseQx(authored);
const declaration = [...walkSyntax(parsed.root)].find(n => n.kind === "packageResourceDecl");
const literals = declaration?.children.filter(n => n.kind === "stringLiteral") ?? [];
const identifier = declaration?.children.find(n => n.kind === "identifier");
if (parsed.diagnostics.length || literals.length !== 2 || !identifier || authored.slice(identifier.start, identifier.end) !== spec.name ||
JSON.parse(authored.slice(literals[0].start, literals[0].end)) !== spec.id || JSON.parse(authored.slice(literals[1].start, literals[1].end)) !== spec.revision)
throw new Error("Initial package declaration must match the provisioned name, ID and revision");
}
for (const [file, content] of Object.entries(spec.initialFiles)) {
if (typeof content !== "string" || ["quixos.lock", "flake.nix", "quixos.toolchain.json", "quixos.check.json", "package.json"].includes(file)) throw new Error(`Not an initial authored file: ${file}`);
const existing = files.findIndex(entry => entry.file === prefix + file);
if (existing >= 0) files.splice(existing, 1);
create(file, content);
}
// A composed React recipe supplies its own modules and complete server.
if (reactRecipe(spec)) {
for (const file of ["src/component.tsx", "src/impl/sourceGet.ts", "descriptor.quixos-package.txtpb"])
if (!(file in spec.initialFiles)) {const index = files.findIndex(entry => entry.file === prefix + file); if (index >= 0) files.splice(index, 1);}
}
}
return {kind: "package", source: spec.source, resourceRoot: spec.directory, validation: "syntax", files};
};
const reactRecipe = (spec: ScaffoldRecipe) => spec.template === "typescript-react" && spec.initialFiles?.["package.qx"] && spec.initialFiles?.["src/server.ts"];