Files
united-workforce/packages/cli-workflow/src/bundle-store.ts
T
xingyue 9bbdfc41bd feat(execute): create @uncaged/workflow-execute + CLI migration
Phase 7: Engine + extract + workflow-as-agent merged into execute package.
All CLI imports migrated from @uncaged/workflow to specific packages.
105 CLI tests pass, 0 failures.

Changes:
- New @uncaged/workflow-execute package (engine/, extract/, workflow-as-agent)
- CLI src/ and __tests__/ rewritten to import from split packages
- bundle-validator updated to allow @uncaged/workflow-cas imports
- ensure-uncaged-workflow-symlink creates symlinks for all new packages

Ref: #143, closes #150
2026-05-09 11:35:03 +08:00

112 lines
3.0 KiB
TypeScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { err, ok, type Result } from "@uncaged/workflow-protocol";
import { pathExists } from "./fs-utils.js";
export type BundleFileSource = { kind: "text"; text: string } | { kind: "path"; path: string };
export type WorkflowBundleStoreInput = {
esmJs: BundleFileSource;
yaml: BundleFileSource;
dts: BundleFileSource | null;
};
async function resolveSourceText(src: BundleFileSource): Promise<Result<string, string>> {
if (src.kind === "text") {
return ok(src.text);
}
try {
return ok(await readFile(src.path, "utf8"));
} catch (e) {
const message = e instanceof Error ? e.message : String(e);
return err(`failed to read bundle artifact: ${message}`);
}
}
async function ensureMatchingOrWrite(
destPath: string,
text: string,
label: string,
): Promise<Result<void, string>> {
if (!(await pathExists(destPath))) {
try {
await writeFile(destPath, text, "utf8");
} catch (e) {
const message = e instanceof Error ? e.message : String(e);
return err(`failed to write ${label}: ${message}`);
}
return ok(undefined);
}
let existing: string;
try {
existing = await readFile(destPath, "utf8");
} catch (e) {
const message = e instanceof Error ? e.message : String(e);
return err(`failed to read existing ${label}: ${message}`);
}
if (existing !== text) {
return err(
`${label} for this hash already exists with different contents; refusing to overwrite`,
);
}
return ok(undefined);
}
/** Store `.esm.js`, `.yaml`, and optional `.d.ts` under `bundles/` keyed by hash. */
export async function storeWorkflowBundleArtifacts(
storageRoot: string,
hash: string,
input: WorkflowBundleStoreInput,
): Promise<Result<void, string>> {
const bundlesDir = join(storageRoot, "bundles");
try {
await mkdir(bundlesDir, { recursive: true });
} catch (e) {
const message = e instanceof Error ? e.message : String(e);
return err(`failed to store bundle: ${message}`);
}
const esmText = await resolveSourceText(input.esmJs);
if (!esmText.ok) {
return esmText;
}
const yamlText = await resolveSourceText(input.yaml);
if (!yamlText.ok) {
return yamlText;
}
let dtsText: string | null = null;
if (input.dts !== null) {
const dtsResolved = await resolveSourceText(input.dts);
if (!dtsResolved.ok) {
return dtsResolved;
}
dtsText = dtsResolved.value;
}
const destEsm = join(bundlesDir, `${hash}.esm.js`);
const destYaml = join(bundlesDir, `${hash}.yaml`);
const destDts = join(bundlesDir, `${hash}.d.ts`);
const w1 = await ensureMatchingOrWrite(destEsm, esmText.value, "bundle");
if (!w1.ok) {
return w1;
}
const w2 = await ensureMatchingOrWrite(destYaml, yamlText.value, "descriptor");
if (!w2.ok) {
return w2;
}
if (dtsText !== null) {
const w3 = await ensureMatchingOrWrite(destDts, dtsText, "types");
if (!w3.ok) {
return w3;
}
}
return ok(undefined);
}