diff --git a/package.json b/package.json index 8871b81..f02eee9 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ ], "scripts": { "build": "bunx tsc --build", + "build:bundles": "bash scripts/build-bundles.sh", "check": "bunx tsc --build && biome check .", "typecheck": "bunx tsc --build", "format": "biome format --write .", diff --git a/packages/workflow-cas/.gitignore b/packages/workflow-cas/.gitignore new file mode 100644 index 0000000..29649dd --- /dev/null +++ b/packages/workflow-cas/.gitignore @@ -0,0 +1 @@ +workflow-cas diff --git a/packages/workflow-execute/.gitignore b/packages/workflow-execute/.gitignore new file mode 100644 index 0000000..2cf78d8 --- /dev/null +++ b/packages/workflow-execute/.gitignore @@ -0,0 +1 @@ +workflow-execute diff --git a/packages/workflow-protocol/.gitignore b/packages/workflow-protocol/.gitignore new file mode 100644 index 0000000..b328d5b --- /dev/null +++ b/packages/workflow-protocol/.gitignore @@ -0,0 +1 @@ +workflow-protocol diff --git a/packages/workflow-register/.gitignore b/packages/workflow-register/.gitignore new file mode 100644 index 0000000..828d319 --- /dev/null +++ b/packages/workflow-register/.gitignore @@ -0,0 +1 @@ +workflow-register diff --git a/packages/workflow-register/src/bundle/ensure-uncaged-workflow-symlink.ts b/packages/workflow-register/src/bundle/ensure-uncaged-workflow-symlink.ts index cecc319..9aa4cc3 100644 --- a/packages/workflow-register/src/bundle/ensure-uncaged-workflow-symlink.ts +++ b/packages/workflow-register/src/bundle/ensure-uncaged-workflow-symlink.ts @@ -48,6 +48,9 @@ export async function ensureUncagedWorkflowSymlink(storageRoot: string): Promise { name: "workflow-runtime", dir: siblingPackageDir("workflow-runtime") }, { name: "workflow-cas", dir: siblingPackageDir("workflow-cas") }, { name: "workflow-protocol", dir: siblingPackageDir("workflow-protocol") }, + { name: "workflow-util", dir: siblingPackageDir("workflow-util") }, + { name: "workflow-execute", dir: siblingPackageDir("workflow-execute") }, + { name: "workflow-register", dir: siblingPackageDir("workflow-register") }, ]; for (const pkg of packages) { diff --git a/packages/workflow-runtime/.gitignore b/packages/workflow-runtime/.gitignore new file mode 100644 index 0000000..cf62672 --- /dev/null +++ b/packages/workflow-runtime/.gitignore @@ -0,0 +1 @@ +workflow-runtime diff --git a/packages/workflow-template-develop/bundle-entry.ts b/packages/workflow-template-develop/bundle-entry.ts index 78358c9..7ec826b 100644 --- a/packages/workflow-template-develop/bundle-entry.ts +++ b/packages/workflow-template-develop/bundle-entry.ts @@ -2,19 +2,17 @@ * develop bundle entry — 小橘 🍊 * * All roles use cursor-agent with workspace auto-extracted from context. + * + * ENV VARS: WORKFLOW_LLM_API_KEY (required), WORKFLOW_LLM_BASE_URL, + * WORKFLOW_LLM_MODEL, WORKFLOW_CURSOR_MODEL, WORKFLOW_CURSOR_TIMEOUT. + * Must be set before the first worker spawn — workers are persistent and + * do not pick up env changes after initial import. */ import { createCursorAgent } from "@uncaged/workflow-agent-cursor"; +import type { AgentContext, AgentFn, AgentFnResult } from "@uncaged/workflow-runtime"; import { createWorkflow } from "@uncaged/workflow-runtime"; import { buildDevelopDescriptor, developWorkflowDefinition } from "./src/index.js"; -function requireEnv(name: string): string { - const value = process.env[name]; - if (value === undefined || value === "") { - throw new Error(`missing required env var: ${name}`); - } - return value; -} - function optionalEnv(name: string): string | null { const value = process.env[name]; if (value === undefined || value === "") { @@ -23,23 +21,39 @@ function optionalEnv(name: string): string | null { return value; } -const llmProvider = { - baseUrl: - optionalEnv("WORKFLOW_LLM_BASE_URL") ?? "https://dashscope.aliyuncs.com/compatible-mode/v1", - apiKey: requireEnv("WORKFLOW_LLM_API_KEY"), - model: optionalEnv("WORKFLOW_LLM_MODEL") ?? "qwen-plus", -}; +function requireEnv(name: string): string { + const value = process.env[name]; + if (value === undefined || value === "") { + throw new Error(`missing required env var: ${name}`); + } + return value; +} -const agent = createCursorAgent({ - model: optionalEnv("WORKFLOW_CURSOR_MODEL"), - timeout: optionalEnv("WORKFLOW_CURSOR_TIMEOUT") - ? Number(optionalEnv("WORKFLOW_CURSOR_TIMEOUT")) - : 0, - workspace: null, - llmProvider, -}); +function createLazyAgent(): AgentFn { + let cached: AgentFn | null = null; + return (ctx: AgentContext): Promise => { + if (cached === null) { + const llmProvider = { + baseUrl: + optionalEnv("WORKFLOW_LLM_BASE_URL") ?? + "https://dashscope.aliyuncs.com/compatible-mode/v1", + apiKey: requireEnv("WORKFLOW_LLM_API_KEY"), + model: optionalEnv("WORKFLOW_LLM_MODEL") ?? "qwen-plus", + }; + cached = createCursorAgent({ + model: optionalEnv("WORKFLOW_CURSOR_MODEL"), + timeout: optionalEnv("WORKFLOW_CURSOR_TIMEOUT") + ? Number(optionalEnv("WORKFLOW_CURSOR_TIMEOUT")) + : 0, + workspace: null, + llmProvider, + }); + } + return cached(ctx); + }; +} -const wf = createWorkflow(developWorkflowDefinition, { agent, overrides: null }); +const wf = createWorkflow(developWorkflowDefinition, { agent: createLazyAgent(), overrides: null }); export const descriptor = buildDevelopDescriptor(); export const run = wf; diff --git a/packages/workflow-template-develop/package.json b/packages/workflow-template-develop/package.json index 3ab1f2f..7d2ad3e 100644 --- a/packages/workflow-template-develop/package.json +++ b/packages/workflow-template-develop/package.json @@ -12,6 +12,7 @@ "test": "bun test" }, "dependencies": { + "@uncaged/workflow-agent-cursor": "workspace:*", "@uncaged/workflow-register": "workspace:*", "@uncaged/workflow-runtime": "workspace:*", "zod": "^4.0.0" diff --git a/packages/workflow-template-solve-issue/bundle-entry.ts b/packages/workflow-template-solve-issue/bundle-entry.ts index 09b3dd9..12985a7 100644 --- a/packages/workflow-template-solve-issue/bundle-entry.ts +++ b/packages/workflow-template-solve-issue/bundle-entry.ts @@ -3,6 +3,10 @@ * * preparer + submitter → hermes agent * developer → workflow-as-agent (delegates to "develop" workflow) + * + * ENV VARS: WORKFLOW_HERMES_MODEL, WORKFLOW_HERMES_TIMEOUT. + * Must be set before the first worker spawn — workers are persistent and + * do not pick up env changes after initial import. */ import { createHermesAgent } from "@uncaged/workflow-agent-hermes"; import { workflowAsAgent } from "@uncaged/workflow-execute"; diff --git a/packages/workflow-template-solve-issue/package.json b/packages/workflow-template-solve-issue/package.json index 04a372c..44b1a00 100644 --- a/packages/workflow-template-solve-issue/package.json +++ b/packages/workflow-template-solve-issue/package.json @@ -12,13 +12,14 @@ "test": "bun test" }, "dependencies": { + "@uncaged/workflow-agent-hermes": "workspace:*", + "@uncaged/workflow-execute": "workspace:*", "@uncaged/workflow-register": "workspace:*", "@uncaged/workflow-runtime": "workspace:*", "zod": "^4.0.0" }, "devDependencies": { "@uncaged/workflow-cas": "workspace:*", - "@uncaged/workflow-execute": "workspace:*", "@uncaged/workflow-protocol": "workspace:*" } } diff --git a/packages/workflow-util/.gitignore b/packages/workflow-util/.gitignore new file mode 100644 index 0000000..581574d --- /dev/null +++ b/packages/workflow-util/.gitignore @@ -0,0 +1 @@ +workflow-util diff --git a/scripts/build-bundles.sh b/scripts/build-bundles.sh new file mode 100755 index 0000000..4e98d2d --- /dev/null +++ b/scripts/build-bundles.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Packages externalized from bundles — resolved at runtime via symlinks +# created by ensureUncagedWorkflowSymlink in workflow-register. +EXTERNAL=( + --external @uncaged/workflow-runtime + --external @uncaged/workflow-protocol + --external @uncaged/workflow-cas + --external @uncaged/workflow-util + --external @uncaged/workflow-execute + --external @uncaged/workflow-register +) + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$REPO_ROOT" + +mkdir -p dist + +echo "Building develop bundle..." +bun build packages/workflow-template-develop/bundle-entry.ts \ + --bundle --format esm --target bun \ + "${EXTERNAL[@]}" \ + --outfile dist/develop.esm.js + +echo "Building solve-issue bundle..." +bun build packages/workflow-template-solve-issue/bundle-entry.ts \ + --bundle --format esm --target bun \ + "${EXTERNAL[@]}" \ + --outfile dist/solve-issue.esm.js + +echo "Done. Bundles written to dist/" + +# Register bundles if --register flag is passed +if [[ "${1:-}" == "--register" ]]; then + STORAGE_ROOT="${UNCAGED_WORKFLOW_STORAGE_ROOT:-${WORKFLOW_STORAGE_ROOT:-$HOME/.uncaged/workflow}}" + echo "Registering bundles..." + for bundle in develop solve-issue; do + cp "dist/${bundle}.esm.js" "$STORAGE_ROOT/${bundle}.esm.js" + uncaged-workflow workflow add "$bundle" "$STORAGE_ROOT/${bundle}.esm.js" + done + echo "Bundles registered." +fi