feat: expose unified product server from bun os CLI

This commit is contained in:
aphrody-dev committed 2026-10-13 22:49:11 +02:00
1 parent ca4b5549fc
commit 020ecaea9e
3 files changed
+97 -73

No files matched your search

+17 -2
View File
@@ -4,6 +4,7 @@
flowchart TD
UI[Aphrody shell] --> SDK[Bun Tauri v3 / CEF]
UI --> Backend[Bun backend]
Product[Standalone product API] --> Workspace
Backend --> Workspace[Native library orchestration]
Workspace --> Sources[Pinned library submodules]
Backend --> Video[Typed video adapter]
@@ -18,11 +19,17 @@ flowchart TD
Infra[Aphrody Infra] --> Apps
Infra --> Control[Rust deployment controller]
Forge[Git forge and runner] --> Factory
Infra --> Forge
Forge --> Portal[source.aphrody.app]
Sources --> Crates[Flat pinned crates / root Cargo workspace]
```
- `apps/desktop`: Aphrody shell, built and served by Bun.
- `packages/workspace`: app identity, config, provenance, source coverage,
native execution, asset manifests and the app transport.
- `packages/bun-workspace`: app identity, config, provenance, source coverage,
native execution, asset manifests and shared process ownership.
- `packages/workspace`: OS CLI and adapters consuming that shared owner.
- `packages/bun-app-host`: product server, common authenticated API transport,
standalone compilation and executable qualification.
- `packages/bun-video-project`: exact JSON, bounded native operations and runtime availability.
- `packages/bun-artifacts`: target manifests, standalone compilation and verified
native payload extraction.
@@ -51,4 +58,12 @@ Provider credentials, sessions, datasets and model weights remain isolated.
Aphrody Infra owns host, service, route and activation policy. Komodo actuates
deployment; Gitea and its runner host Git and execute the same Bun factory.
The root `bun-os` CLI routes `server` commands to the same app-host CLI owner.
Just coordinates setup, shared quality, Cargo, apps, product server and vendor
without implementing another build pipeline. The root owns `node_modules`,
`target`, `build` and `install`.
Source, artifact, CI and public service qualification are recorded separately.
The complete 239-repository Labs inventory and resumable mirror admission live
in Aphrody Infra. The embedded product catalog is a pinned distribution
snapshot, not a claim that every mirror or native application is qualified.
+4 -2
View File
@@ -6,8 +6,8 @@ import { productCatalog } from "./build.ts";
import { startProduct } from "./product.ts";
import { verifyProduct } from "./verify.ts";
if (import.meta.main) {
const [action = "help", root = repositoryRoot, receipt] = Bun.argv.slice(2);
export async function runProductCLI(args: readonly string[]): Promise<void> {
const [action = "help", root = repositoryRoot, receipt] = args;
if (action === "help" || action === "--help")
console.log("Aphrody / Bun server: cli.ts serve [ROOT] | verify [BINARY] [RECEIPT] | --version");
else if (action === "--version") console.log("Aphrody / Bun server 1.4.4");
@@ -26,3 +26,5 @@ if (import.meta.main) {
console.log(JSON.stringify(await verifyProduct(binary, receipt ? resolve(receipt) : binary + ".json")));
} else throw new Error("Use serve, verify or --version.");
}
if (import.meta.main) await runProductCLI(Bun.argv.slice(2));
+76 -69
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bun
import { resolve } from "node:path";
import { parseArgs } from "node:util";
import { runProductCLI } from "../packages/bun-app-host/src/cli.ts";
import {
assembleSources,
buildImage,
@@ -14,6 +15,7 @@ import {
} from "./distribution.ts";
const usage = `Bun OS factory
server serve [ROOT] | verify [BINARY] [RECEIPT] | --version
plan [--profile full|perf] [--target linux-x64|linux-arm64|windows-x64|macos-arm64|wasm]
sources --out DIR [--config FILE]
stage --out DIR --runtime FILE --receipt FILE --profile full|perf --target TARGET
@@ -26,77 +28,82 @@ Sources contain committed, pinned files and every locked submodule; protected st
WASM builds libm3's portable API. Native Bun/JSC and the Linux compositor require their native targets.`;
try {
const { positionals, values } = parseArgs({
args: Bun.argv.slice(2),
allowPositionals: true,
options: {
help: { type: "boolean", short: "h" },
profile: { type: "string", default: "perf" },
target: { type: "string", default: "linux-x64" },
out: { type: "string" },
config: { type: "string" },
runtime: { type: "string" },
receipt: { type: "string" },
material: { type: "string" },
tag: { type: "string" },
},
});
if (values.help || !positionals.length) {
console.log(usage);
process.exit(0);
}
if (positionals.length !== 1) throw new Error("Expected one factory command");
if (values.profile !== "full" && values.profile !== "perf") throw new Error("Unknown distribution profile");
const profile: Profile = values.profile;
if (!["linux-x64", "linux-arm64", "windows-x64", "macos-arm64", "wasm"].includes(values.target!))
throw new Error("Unknown target");
const target = values.target as Target;
const required = (name: "out" | "runtime" | "receipt" | "material" | "tag") => {
const value = values[name];
if (!value) throw new Error(`Missing --${name}`);
return value;
};
let config: Config = {};
if (values.config) {
const file = resolve(values.config);
config = await Bun.file(file).json();
for (const [id, path] of Object.entries(config.checkouts ?? {})) config.checkouts![id] = resolve(file, "..", path);
if (config.sourceExport) {
if (config.sourceExport.cache) config.sourceExport.cache = resolve(file, "..", config.sourceExport.cache);
for (const [id, path] of Object.entries(config.sourceExport.repositories ?? {}))
config.sourceExport.repositories![id] = resolve(file, "..", path);
config.sourceExport.protectedRoots = config.sourceExport.protectedRoots?.map(path => resolve(file, "..", path));
if (Bun.argv[2] === "server") {
await runProductCLI(Bun.argv.slice(3));
} else {
const { positionals, values } = parseArgs({
args: Bun.argv.slice(2),
allowPositionals: true,
options: {
help: { type: "boolean", short: "h" },
profile: { type: "string", default: "perf" },
target: { type: "string", default: "linux-x64" },
out: { type: "string" },
config: { type: "string" },
runtime: { type: "string" },
receipt: { type: "string" },
material: { type: "string" },
tag: { type: "string" },
},
});
if (values.help || !positionals.length) {
console.log(usage);
process.exit(0);
}
if (positionals.length !== 1) throw new Error("Expected one factory command");
if (values.profile !== "full" && values.profile !== "perf") throw new Error("Unknown distribution profile");
const profile: Profile = values.profile;
if (!["linux-x64", "linux-arm64", "windows-x64", "macos-arm64", "wasm"].includes(values.target!))
throw new Error("Unknown target");
const target = values.target as Target;
const required = (name: "out" | "runtime" | "receipt" | "material" | "tag") => {
const value = values[name];
if (!value) throw new Error(`Missing --${name}`);
return value;
};
let config: Config = {};
if (values.config) {
const file = resolve(values.config);
config = await Bun.file(file).json();
for (const [id, path] of Object.entries(config.checkouts ?? {}))
config.checkouts![id] = resolve(file, "..", path);
if (config.sourceExport) {
if (config.sourceExport.cache) config.sourceExport.cache = resolve(file, "..", config.sourceExport.cache);
for (const [id, path] of Object.entries(config.sourceExport.repositories ?? {}))
config.sourceExport.repositories![id] = resolve(file, "..", path);
config.sourceExport.protectedRoots = config.sourceExport.protectedRoots?.map(path => resolve(file, "..", path));
}
}
let result: unknown;
switch (positionals[0]) {
case "plan":
result = await plan(profile, target, config);
break;
case "sources":
result = await assembleSources(resolve(required("out")), config);
break;
case "stage":
if (target === "wasm") throw new Error("Use the wasm command for the portable library target");
await stageRuntime(
resolve(required("out")),
resolve(required("runtime")),
resolve(required("receipt")),
profile,
target,
);
result = { staged: true, profile, target };
break;
case "wasm":
result = await buildWasm(resolve(required("out")), config);
break;
case "image":
result = await buildImage(resolve(required("out")), profile, target, required("tag"));
break;
default:
throw new Error(`Unknown command ${positionals[0]}; run ${packageRoot}/src/cli.ts --help`);
}
console.log(JSON.stringify(result, null, 2));
}
let result: unknown;
switch (positionals[0]) {
case "plan":
result = await plan(profile, target, config);
break;
case "sources":
result = await assembleSources(resolve(required("out")), config);
break;
case "stage":
if (target === "wasm") throw new Error("Use the wasm command for the portable library target");
await stageRuntime(
resolve(required("out")),
resolve(required("runtime")),
resolve(required("receipt")),
profile,
target,
);
result = { staged: true, profile, target };
break;
case "wasm":
result = await buildWasm(resolve(required("out")), config);
break;
case "image":
result = await buildImage(resolve(required("out")), profile, target, required("tag"));
break;
default:
throw new Error(`Unknown command ${positionals[0]}; run ${packageRoot}/src/cli.ts --help`);
}
console.log(JSON.stringify(result, null, 2));
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;