- run a singleton Codex App Server adapter in each dev workspace - gate Web Studio with a reloadable fragment-token to HttpOnly-session exchange - add ChatGPT device login and streamed chat to Web Studio - isolate authoring access in a declarative NixOS service account - split Web Studio canvas, object, panel, and model concerns - check generated Quixos protocol clients for drift - resolve same-repository quixos.lock fragments deterministically - preserve the collaborative canvas gesture fixes
87 lines
3.0 KiB
TypeScript
87 lines
3.0 KiB
TypeScript
import childProcess from "node:child_process";
|
|
import crypto from "node:crypto";
|
|
import { mkdir, readFile, realpath } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { promisify } from "node:util";
|
|
import type { CapabilityRepositoryResolver } from "./assembly.js";
|
|
|
|
const execFile = promisify(childProcess.execFile);
|
|
|
|
const sourceKey = (kind: string, repository: string, commit: string) =>
|
|
`${kind}\0${repository}\0${commit.toLowerCase()}`;
|
|
|
|
const checkoutName = (kind: string, repository: string, commit: string) => {
|
|
const digest = crypto
|
|
.createHash("sha256")
|
|
.update(sourceKey(kind, repository, commit))
|
|
.digest("hex")
|
|
.slice(0, 24);
|
|
return `${kind}-${digest}`;
|
|
};
|
|
|
|
export const createGitCapabilityResolver = async (options: {
|
|
checkoutRoot: string;
|
|
snapshotMap?: string;
|
|
}): Promise<CapabilityRepositoryResolver> => {
|
|
await mkdir(options.checkoutRoot, { recursive: true });
|
|
const checkoutRoot = await realpath(options.checkoutRoot);
|
|
const snapshots = new Map<string, string>();
|
|
if (options.snapshotMap) {
|
|
const snapshotMapPath = await realpath(options.snapshotMap);
|
|
const document = JSON.parse(await readFile(snapshotMapPath, "utf8")) as {
|
|
resources?: Array<{
|
|
kind: string;
|
|
repository: string;
|
|
commit: string;
|
|
directory: string;
|
|
}>;
|
|
};
|
|
for (const entry of document.resources ?? []) {
|
|
if (entry.kind !== "interface" && entry.kind !== "package") {
|
|
throw new Error(`Snapshot map has unsupported resource kind ${entry.kind}`);
|
|
}
|
|
const key = sourceKey(entry.kind, entry.repository, entry.commit);
|
|
if (snapshots.has(key)) throw new Error(`Snapshot map repeats ${key}`);
|
|
const directory = path.resolve(path.dirname(snapshotMapPath), entry.directory);
|
|
snapshots.set(key, await realpath(directory));
|
|
}
|
|
}
|
|
|
|
const checkouts = new Map<string, Promise<{ directory: string }>>();
|
|
return async (source, kind) => {
|
|
const key = sourceKey(kind, source.repository, source.commit);
|
|
const snapshot = snapshots.get(key);
|
|
if (snapshot) return { directory: snapshot };
|
|
const existing = checkouts.get(key);
|
|
if (existing) return await existing;
|
|
const pending = (async () => {
|
|
const directory = path.join(
|
|
checkoutRoot,
|
|
checkoutName(kind, source.repository, source.commit),
|
|
);
|
|
await execFile("git", [
|
|
"-c",
|
|
"advice.detachedHead=false",
|
|
"clone",
|
|
"--depth",
|
|
"1",
|
|
"--single-branch",
|
|
"--branch",
|
|
`quixos-reachability/${source.commit.toLowerCase()}`,
|
|
source.repository,
|
|
directory,
|
|
]);
|
|
const { stdout } = await execFile("git", ["-C", directory, "rev-parse", "HEAD"]);
|
|
if (stdout.trim().toLowerCase() !== source.commit.toLowerCase()) {
|
|
throw new Error(
|
|
`Locked commit mismatch for ${source.repository}: ` +
|
|
`wanted ${source.commit}, fetched ${stdout.trim()}`,
|
|
);
|
|
}
|
|
return { directory };
|
|
})();
|
|
checkouts.set(key, pending);
|
|
return await pending;
|
|
};
|
|
};
|