Files
united-workforce/packages/workflow-dashboard/server/workflow.ts
T
xingyue e067a2f25a
CI / check (pull_request) Failing after 9m51s
refactor: rebrand npm packages @uncaged/* → @united-workforce/*
Package mapping:
- @uncaged/cli-workflow → @united-workforce/cli
- @uncaged/workflow-protocol → @united-workforce/protocol
- @uncaged/workflow-util → @united-workforce/util
- @uncaged/workflow-util-agent → @united-workforce/util-agent
- @uncaged/workflow-agent-hermes → @united-workforce/agent-hermes
- @uncaged/workflow-agent-claude-code → @united-workforce/agent-claude-code
- @uncaged/workflow-agent-builtin → @united-workforce/agent-builtin
- @uncaged/workflow-dashboard → @united-workforce/dashboard

Changes:
- 8 package.json name + dependency refs
- 82 files: import statements updated
- .changeset/config.json updated
- CLAUDE.md updated
- bunfig.toml restored for preload

CLI command (uwf) and directory names unchanged.

Closes shazhou/united-workforce#8
2026-06-02 20:56:06 +08:00

126 lines
3.9 KiB
TypeScript

import { mkdir, readdir, readFile, unlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import type { RoleDefinition, Target, WorkflowPayload } from "@united-workforce/protocol";
import YAML from "yaml";
import type { WorkFlowSteps, WorkFlowTransition, WorkflowSummary } from "../shared/types.ts";
const WORKFLOW_DIR = join(import.meta.dirname, "..", "tmp", "workflow");
async function ensureDir() {
await mkdir(WORKFLOW_DIR, { recursive: true });
}
function payloadToSteps(payload: WorkflowPayload): WorkFlowSteps {
const steps: WorkFlowSteps = [];
for (const [roleName, roleDef] of Object.entries(payload.roles)) {
const statusMap = payload.graph[roleName] ?? {};
const transitions: WorkFlowTransition[] = Object.entries(statusMap).map(([status, target]) => ({
target: target.role === "$END" ? "END" : target.role,
status,
}));
steps.push({
role: {
name: roleName,
description: roleDef.description,
identity: roleDef.goal,
prepare: roleDef.capabilities.join("\n"),
execute: roleDef.procedure,
report: roleDef.output,
},
transitions,
});
}
return steps;
}
function stepsToPayload(name: string, description: string, steps: WorkFlowSteps): WorkflowPayload {
const roles: Record<string, RoleDefinition> = {};
const graph: Record<string, Record<string, Target>> = {};
for (const step of steps) {
const r = step.role;
roles[r.name] = {
description: r.description,
goal: r.identity,
capabilities: r.prepare ? r.prepare.split("\n").filter(Boolean) : [],
procedure: r.execute,
output: r.report,
frontmatter: "",
};
const statusMap: Record<string, Target> = {};
for (const t of step.transitions) {
const targetRole = t.target === "END" ? "$END" : t.target;
statusMap[t.status] = {
role: targetRole,
prompt: `Transition to ${targetRole}.`,
};
}
graph[r.name] = statusMap;
}
if (steps.length > 0) {
const firstRole = steps[0].role.name;
graph.$START = {
_: {
role: firstRole,
prompt: `Begin workflow at role ${firstRole}.`,
},
};
}
return { name, description, roles, graph };
}
export async function listWorkflows(): Promise<WorkflowSummary[]> {
await ensureDir();
const files = await readdir(WORKFLOW_DIR);
const results: WorkflowSummary[] = [];
for (const file of files) {
if (!file.endsWith(".yaml")) continue;
const content = await readFile(join(WORKFLOW_DIR, file), "utf-8");
const payload = YAML.parse(content) as WorkflowPayload;
results.push({ name: payload.name, description: payload.description });
}
return results;
}
export async function getWorkflow(name: string): Promise<WorkFlowSteps> {
const content = await readFile(join(WORKFLOW_DIR, `${name}.yaml`), "utf-8");
const payload = YAML.parse(content) as WorkflowPayload;
return payloadToSteps(payload);
}
export async function createWorkflow(name: string, description: string): Promise<void> {
await ensureDir();
const payload: WorkflowPayload = {
name,
description,
roles: {},
graph: {},
};
await writeFile(join(WORKFLOW_DIR, `${name}.yaml`), YAML.stringify(payload), "utf-8");
}
export async function saveWorkflow(name: string, steps: WorkFlowSteps): Promise<void> {
const filePath = join(WORKFLOW_DIR, `${name}.yaml`);
let description = "";
try {
const existing = await readFile(filePath, "utf-8");
const existingPayload = YAML.parse(existing) as WorkflowPayload;
description = existingPayload.description;
} catch {
// file doesn't exist, use empty description
}
const payload = stepsToPayload(name, description, steps);
await writeFile(filePath, YAML.stringify(payload), "utf-8");
}
export async function deleteWorkflow(name: string): Promise<void> {
await unlink(join(WORKFLOW_DIR, `${name}.yaml`));
}