@openworkflow/cli 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +0 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -4
- package/dist/templates.d.ts +1 -1
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +5 -1
- package/package.json +6 -5
- package/dist/skills.d.ts +0 -61
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -286
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,aAAa,CAAC;AAiC3E,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAoBnC;AAED;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoItE;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDxE;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,cAAc,CAAC;AAE/D;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAuEf;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2D3E;AAwOD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,GAC5B,MAAM,EAAE,CA4CV;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,aAAa,CAAC;AAiC3E,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAoBnC;AAED;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoItE;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDxE;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,cAAc,CAAC;AAE/D;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAuEf;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2D3E;AAwOD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,GAC5B,MAAM,EAAE,CA4CV;AAiWD,UAAU,oBAAoB;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAsBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAMR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAKR;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAKR;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAKR"}
|
package/dist/commands.js
CHANGED
|
@@ -686,10 +686,10 @@ function updateGitignoreForSqlite() {
|
|
|
686
686
|
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
687
687
|
const spinner = p.spinner();
|
|
688
688
|
spinner.start("Updating .gitignore...");
|
|
689
|
-
const result = ensureGitignoreEntry(gitignorePath, "openworkflow/backend.db");
|
|
689
|
+
const result = ensureGitignoreEntry(gitignorePath, "openworkflow/backend.db*");
|
|
690
690
|
spinner.stop(result.added
|
|
691
|
-
? "Added openworkflow/backend.db to .gitignore"
|
|
692
|
-
: "openworkflow/backend.db already in .gitignore");
|
|
691
|
+
? "Added openworkflow/backend.db* to .gitignore"
|
|
692
|
+
: "openworkflow/backend.db* already in .gitignore");
|
|
693
693
|
}
|
|
694
694
|
/**
|
|
695
695
|
* Add worker script to package.json.
|
|
@@ -717,7 +717,7 @@ function addWorkerScriptToPackageJson() {
|
|
|
717
717
|
* Ensure a specific entry exists in a .gitignore file. Creates the file if it
|
|
718
718
|
* doesn't exist, appends the entry if not present.
|
|
719
719
|
* @param gitignorePath - Path to the .gitignore file
|
|
720
|
-
* @param entry - The entry to add (e.g. "openworkflow/backend.db")
|
|
720
|
+
* @param entry - The entry to add (e.g. "openworkflow/backend.db*")
|
|
721
721
|
* @returns Object indicating whether the entry was added or already existed
|
|
722
722
|
*/
|
|
723
723
|
function ensureGitignoreEntry(gitignorePath, entry) {
|
package/dist/templates.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export declare const POSTGRES_CLIENT = "import { BackendPostgres } from \"openwo
|
|
|
3
3
|
export declare const POSTGRES_PROD_SQLITE_DEV_CLIENT = "import { BackendPostgres } from \"openworkflow/postgres\";\nimport { BackendSqlite } from \"openworkflow/sqlite\";\nimport { OpenWorkflow } from \"openworkflow\";\n\nexport const backend =\n process.env[\"NODE_ENV\"] === \"production\"\n ? await BackendPostgres.connect(process.env[\"OPENWORKFLOW_POSTGRES_URL\"])\n : BackendSqlite.connect(\"openworkflow/backend.db\");\nexport const ow = new OpenWorkflow({ backend });\n";
|
|
4
4
|
export declare const CONFIG = "import { backend } from \"./openworkflow/client.js\";\nimport { defineConfig } from \"@openworkflow/cli\";\n\nexport default defineConfig({\n backend,\n dirs: \"./openworkflow\",\n ignorePatterns: [\"**/*.run.*\"],\n});\n";
|
|
5
5
|
export declare const HELLO_WORLD_WORKFLOW = "import { defineWorkflow } from \"openworkflow\";\n\n/**\n * Example workflow that greets the world.\n *\n * This workflow is auto-discovered by the CLI worker.\n * To trigger it, use ow.runWorkflow() from your app:\n * ```ts\n * import { ow } from \"./openworkflow/client.js\";\n * import { helloWorld } from \"./openworkflow/hello-world.js\";\n * const handle = await ow.runWorkflow(helloWorld.spec, {});\n * const result = await handle.result();\n * ```\n */\nexport const helloWorld = defineWorkflow(\n { name: \"hello-world\" },\n async ({ step }) => {\n const greeting = await step.run({ name: \"greet\" }, () => {\n return \"Hello, World!\";\n });\n\n await step.sleep(\"wait-a-bit\", \"1s\");\n\n return { greeting };\n },\n);\n";
|
|
6
|
-
export declare const HELLO_WORLD_RUNNER = "import { ow } from \"./client.js\";\nimport { helloWorld } from \"./hello-world.js\";\n\n// Run this file:\n// JS: `node openworkflow/hello-world.run.js`\n// TS: `npx tsx openworkflow/hello-world.run.ts`\n//\n// This file is a temporary dev helper generated by\n// `npx @openworkflow/cli init` so you can quickly run the example workflow.\n//\n// Copy the code anywhere in your app (e.g., an API route or a script) and\n// modify it to run your workflows.\n//\n// You can delete this file once you're done with it.\n\nconsole.log(\"Running hello-world workflow...\");\nconst handle = await ow.runWorkflow(helloWorld.spec, {});\n\nconsole.log(\"Waiting for result...\");\nconst result = await handle.result(); // for very short workflows only\n\nconsole.log(`Workflow result: ${JSON.stringify(result, null, 2)}`);\n";
|
|
6
|
+
export declare const HELLO_WORLD_RUNNER = "import { backend, ow } from \"./client.js\";\nimport { helloWorld } from \"./hello-world.js\";\n\n// Run this file:\n// JS: `node openworkflow/hello-world.run.js`\n// TS: `npx tsx openworkflow/hello-world.run.ts`\n//\n// This file is a temporary dev helper generated by\n// `npx @openworkflow/cli init` so you can quickly run the example workflow.\n//\n// Copy the code anywhere in your app (e.g., an API route or a script) and\n// modify it to run your workflows.\n//\n// You can delete this file once you're done with it.\n\nconsole.log(\"Running hello-world workflow...\");\nconst handle = await ow.runWorkflow(helloWorld.spec, {});\n\nconsole.log(\"Waiting for result...\");\nconst result = await handle.result(); // for very short workflows only\n\nconsole.log(`Workflow result: ${JSON.stringify(result, null, 2)}`);\n\n// Stop backend. Only needed if this is a standalone script that you want to\n// exit after running the workflow.\nawait backend.stop();\n";
|
|
7
7
|
//# sourceMappingURL=templates.d.ts.map
|
package/dist/templates.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../templates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,6OAKzB,CAAC;AAEF,eAAO,MAAM,eAAe,+QAO3B,CAAC;AAEF,eAAO,MAAM,+BAA+B,ibAS3C,CAAC;AAEF,eAAO,MAAM,MAAM,qOAQlB,CAAC;AAEF,eAAO,MAAM,oBAAoB,wvBA0BhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../templates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,6OAKzB,CAAC;AAEF,eAAO,MAAM,eAAe,+QAO3B,CAAC;AAEF,eAAO,MAAM,+BAA+B,ibAS3C,CAAC;AAEF,eAAO,MAAM,MAAM,qOAQlB,CAAC;AAEF,eAAO,MAAM,oBAAoB,wvBA0BhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,w8BA0B9B,CAAC"}
|
package/dist/templates.js
CHANGED
|
@@ -58,7 +58,7 @@ export const helloWorld = defineWorkflow(
|
|
|
58
58
|
},
|
|
59
59
|
);
|
|
60
60
|
`;
|
|
61
|
-
export const HELLO_WORLD_RUNNER = `import { ow } from "./client.js";
|
|
61
|
+
export const HELLO_WORLD_RUNNER = `import { backend, ow } from "./client.js";
|
|
62
62
|
import { helloWorld } from "./hello-world.js";
|
|
63
63
|
|
|
64
64
|
// Run this file:
|
|
@@ -80,4 +80,8 @@ console.log("Waiting for result...");
|
|
|
80
80
|
const result = await handle.result(); // for very short workflows only
|
|
81
81
|
|
|
82
82
|
console.log(\`Workflow result: \${JSON.stringify(result, null, 2)}\`);
|
|
83
|
+
|
|
84
|
+
// Stop backend. Only needed if this is a standalone script that you want to
|
|
85
|
+
// exit after running the workflow.
|
|
86
|
+
await backend.stop();
|
|
83
87
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openworkflow/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -22,14 +22,15 @@
|
|
|
22
22
|
"!*.tsbuildinfo"
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build": "tsc",
|
|
25
|
+
"build": "npm run clean && tsc",
|
|
26
|
+
"clean": "rm -rf dist",
|
|
26
27
|
"prepublishOnly": "npm run build"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@clack/prompts": "^1.0.
|
|
30
|
+
"@clack/prompts": "^1.0.1",
|
|
30
31
|
"commander": "^14.0.3",
|
|
31
32
|
"consola": "^3.4.2",
|
|
32
|
-
"dotenv": "^17.
|
|
33
|
+
"dotenv": "^17.3.1",
|
|
33
34
|
"jiti": "^2.6.1",
|
|
34
35
|
"nypm": "^0.6.5"
|
|
35
36
|
},
|
|
@@ -38,6 +39,6 @@
|
|
|
38
39
|
"vitest": "^4.0.18"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
|
-
"openworkflow": "^0.6.0 || ^0.7.0"
|
|
42
|
+
"openworkflow": "^0.6.0 || ^0.7.0 || ^0.8.0"
|
|
42
43
|
}
|
|
43
44
|
}
|
package/dist/skills.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
declare const SUPPORTED_SKILL_AGENTS: readonly ["codex", "claude"];
|
|
2
|
-
export type SkillAgent = (typeof SUPPORTED_SKILL_AGENTS)[number];
|
|
3
|
-
export interface SkillCatalogEntry {
|
|
4
|
-
name: string;
|
|
5
|
-
description: string;
|
|
6
|
-
}
|
|
7
|
-
export interface InstallOpenWorkflowSkillsOptions {
|
|
8
|
-
agent: SkillAgent;
|
|
9
|
-
force: boolean;
|
|
10
|
-
requestedSkillNames?: string[];
|
|
11
|
-
targetDirectory?: string;
|
|
12
|
-
workspaceDirectory: string;
|
|
13
|
-
}
|
|
14
|
-
export interface InstalledSkill {
|
|
15
|
-
name: string;
|
|
16
|
-
overwritten: boolean;
|
|
17
|
-
path: string;
|
|
18
|
-
}
|
|
19
|
-
export interface InstallOpenWorkflowSkillsResult {
|
|
20
|
-
installedSkills: InstalledSkill[];
|
|
21
|
-
targetDirectory: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* True when the provided value is a supported skill agent.
|
|
25
|
-
* @param value - Agent value from CLI options
|
|
26
|
-
* @returns Whether the value is supported
|
|
27
|
-
*/
|
|
28
|
-
export declare function isSkillAgent(value: string): value is SkillAgent;
|
|
29
|
-
/**
|
|
30
|
-
* Returns the default skill directory for an agent.
|
|
31
|
-
* @param agent - Skill agent
|
|
32
|
-
* @returns Relative target directory
|
|
33
|
-
*/
|
|
34
|
-
export declare function getDefaultSkillDirectory(agent: SkillAgent): string;
|
|
35
|
-
/**
|
|
36
|
-
* List available OpenWorkflow skills.
|
|
37
|
-
* @returns Skill catalog entries
|
|
38
|
-
*/
|
|
39
|
-
export declare function listOpenWorkflowSkills(): SkillCatalogEntry[];
|
|
40
|
-
/**
|
|
41
|
-
* Resolve requested skill names, defaulting to all.
|
|
42
|
-
* @param requestedSkillNames - Skill names from CLI options
|
|
43
|
-
* @returns Unique, validated skill names
|
|
44
|
-
* @throws {Error} When one or more skill names are unknown
|
|
45
|
-
*/
|
|
46
|
-
export declare function resolveSkillNames(requestedSkillNames?: string[]): string[];
|
|
47
|
-
/**
|
|
48
|
-
* Install OpenWorkflow skills to an agent skill directory.
|
|
49
|
-
* @param options - Install options
|
|
50
|
-
* @returns Install result metadata
|
|
51
|
-
* @throws {Error} When skill names are invalid or files already exist without force
|
|
52
|
-
*/
|
|
53
|
-
export declare function installOpenWorkflowSkills(options: InstallOpenWorkflowSkillsOptions): InstallOpenWorkflowSkillsResult;
|
|
54
|
-
/**
|
|
55
|
-
* Read a skill file from disk. Used by tests.
|
|
56
|
-
* @param skillPath - Path to the skill file
|
|
57
|
-
* @returns File content
|
|
58
|
-
*/
|
|
59
|
-
export declare function readSkillFile(skillPath: string): string;
|
|
60
|
-
export {};
|
|
61
|
-
//# sourceMappingURL=skills.d.ts.map
|
package/dist/skills.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../skills.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,sBAAsB,8BAA+B,CAAC;AAE5D,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,+BAA+B;IAC9C,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB;AAyMD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,UAAU,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CAK5D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAiB1E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,+BAA+B,CA2CjC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
package/dist/skills.js
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
const SUPPORTED_SKILL_AGENTS = ["codex", "claude"];
|
|
4
|
-
const DEFAULT_SKILL_DIRECTORIES = {
|
|
5
|
-
codex: path.join(".agents", "skills"),
|
|
6
|
-
claude: path.join(".claude", "skills"),
|
|
7
|
-
};
|
|
8
|
-
const OPENWORKFLOW_SKILLS = [
|
|
9
|
-
{
|
|
10
|
-
name: "openworkflow-quickstart",
|
|
11
|
-
description: "Scaffold, implement, and run durable workflows with the OpenWorkflow CLI.",
|
|
12
|
-
files: {
|
|
13
|
-
"SKILL.md": `---
|
|
14
|
-
name: openworkflow-quickstart
|
|
15
|
-
description: Use when a user asks to create, run, or update OpenWorkflow workflows in an app codebase.
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
# OpenWorkflow Quickstart
|
|
19
|
-
|
|
20
|
-
Use this skill when the user wants to build or update a workflow quickly.
|
|
21
|
-
|
|
22
|
-
## Standard flow
|
|
23
|
-
|
|
24
|
-
1. Confirm the project has OpenWorkflow set up. If not, run \`npx @openworkflow/cli init\`.
|
|
25
|
-
2. Create or update workflow code in \`openworkflow/\` with \`defineWorkflow\`.
|
|
26
|
-
3. Keep side effects inside \`step.run(...)\` calls, and keep step names stable.
|
|
27
|
-
4. Start a worker with \`npx @openworkflow/cli worker start\`.
|
|
28
|
-
5. Trigger the workflow with \`ow.runWorkflow(workflow.spec, input)\`.
|
|
29
|
-
6. Validate setup with \`npx @openworkflow/cli doctor\`.
|
|
30
|
-
|
|
31
|
-
## Guardrails
|
|
32
|
-
|
|
33
|
-
- Keep workflow replay deterministic outside of \`step.run\`.
|
|
34
|
-
- Use explicit, descriptive, stable step names.
|
|
35
|
-
- Use \`step.sleep\` for durable waits instead of process timers.
|
|
36
|
-
- Return JSON-serializable values from steps and workflow output.
|
|
37
|
-
|
|
38
|
-
## Useful commands
|
|
39
|
-
|
|
40
|
-
\`\`\`bash
|
|
41
|
-
npx @openworkflow/cli init
|
|
42
|
-
npx @openworkflow/cli worker start
|
|
43
|
-
npx @openworkflow/cli doctor
|
|
44
|
-
npx @openworkflow/cli dashboard
|
|
45
|
-
\`\`\`
|
|
46
|
-
`,
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: "openworkflow-patterns",
|
|
51
|
-
description: "Apply durable workflow patterns for retries, idempotency, and versioning.",
|
|
52
|
-
files: {
|
|
53
|
-
"SKILL.md": `---
|
|
54
|
-
name: openworkflow-patterns
|
|
55
|
-
description: Use when a user asks for production workflow design patterns in OpenWorkflow.
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
# OpenWorkflow Patterns
|
|
59
|
-
|
|
60
|
-
Use this skill for architecture and implementation guidance on durable workflows.
|
|
61
|
-
|
|
62
|
-
## Patterns to apply
|
|
63
|
-
|
|
64
|
-
1. Prefer many small \`step.run\` calls over one large step.
|
|
65
|
-
2. Keep external side effects in steps with stable names to preserve memoization.
|
|
66
|
-
3. Use idempotency keys for enqueue endpoints that may be retried.
|
|
67
|
-
4. Use workflow versioning when behavior changes in non-backward-compatible ways.
|
|
68
|
-
5. Use \`step.sleep\` for delays and backoff scheduling.
|
|
69
|
-
|
|
70
|
-
## Failure handling
|
|
71
|
-
|
|
72
|
-
- Let transient failures throw from step functions so retries can reschedule runs.
|
|
73
|
-
- Use explicit deadlines for workflows that should fail fast.
|
|
74
|
-
- Add compensation steps for side effects that need rollback behavior.
|
|
75
|
-
|
|
76
|
-
## Review checklist
|
|
77
|
-
|
|
78
|
-
- Is workflow code deterministic between checkpoints?
|
|
79
|
-
- Are step names stable across deployments?
|
|
80
|
-
- Are retry expectations documented for each external dependency?
|
|
81
|
-
- Are deadline and workflow cancel paths tested?
|
|
82
|
-
`,
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: "openworkflow-sql-inspector",
|
|
87
|
-
description: "Inspect workflow and step state directly in SQLite or PostgreSQL with read-only SQL.",
|
|
88
|
-
files: {
|
|
89
|
-
"SKILL.md": `---
|
|
90
|
-
name: openworkflow-sql-inspector
|
|
91
|
-
description: Use when a user asks why workflows are stuck, slow, failed, or repeatedly retried.
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
# OpenWorkflow SQL Inspector
|
|
95
|
-
|
|
96
|
-
Use this skill to answer workflow runtime questions from database state.
|
|
97
|
-
|
|
98
|
-
## Safety rules
|
|
99
|
-
|
|
100
|
-
1. Use read-only SQL only.
|
|
101
|
-
2. Do not run INSERT, UPDATE, DELETE, ALTER, DROP, TRUNCATE, or CREATE.
|
|
102
|
-
3. Always add \`LIMIT\` to exploratory queries (default 100).
|
|
103
|
-
4. Redact sensitive values before sharing query output.
|
|
104
|
-
|
|
105
|
-
## Database notes
|
|
106
|
-
|
|
107
|
-
- SQLite default path from CLI init: \`openworkflow/backend.db\`.
|
|
108
|
-
- PostgreSQL default schema: \`openworkflow\`.
|
|
109
|
-
- Core tables: \`workflow_runs\`, \`step_attempts\`.
|
|
110
|
-
|
|
111
|
-
Read [references/sql-queries.md](references/sql-queries.md) for practical query templates.
|
|
112
|
-
`,
|
|
113
|
-
"references/sql-queries.md": `# SQL Query Templates
|
|
114
|
-
|
|
115
|
-
## PostgreSQL
|
|
116
|
-
|
|
117
|
-
Use a read-only transaction for ad hoc inspection:
|
|
118
|
-
|
|
119
|
-
\`\`\`sql
|
|
120
|
-
BEGIN READ ONLY;
|
|
121
|
-
SELECT
|
|
122
|
-
namespace_id,
|
|
123
|
-
id,
|
|
124
|
-
workflow_name,
|
|
125
|
-
status,
|
|
126
|
-
attempts,
|
|
127
|
-
available_at,
|
|
128
|
-
deadline_at,
|
|
129
|
-
created_at,
|
|
130
|
-
updated_at
|
|
131
|
-
FROM openworkflow.workflow_runs
|
|
132
|
-
ORDER BY created_at DESC
|
|
133
|
-
LIMIT 100;
|
|
134
|
-
COMMIT;
|
|
135
|
-
\`\`\`
|
|
136
|
-
|
|
137
|
-
Recent step attempts for a workflow run:
|
|
138
|
-
|
|
139
|
-
\`\`\`sql
|
|
140
|
-
SELECT
|
|
141
|
-
namespace_id,
|
|
142
|
-
id,
|
|
143
|
-
workflow_run_id,
|
|
144
|
-
step_name,
|
|
145
|
-
kind,
|
|
146
|
-
status,
|
|
147
|
-
started_at,
|
|
148
|
-
finished_at,
|
|
149
|
-
created_at
|
|
150
|
-
FROM openworkflow.step_attempts
|
|
151
|
-
WHERE workflow_run_id = $1
|
|
152
|
-
ORDER BY created_at DESC
|
|
153
|
-
LIMIT 200;
|
|
154
|
-
\`\`\`
|
|
155
|
-
|
|
156
|
-
## SQLite
|
|
157
|
-
|
|
158
|
-
List recent workflow runs:
|
|
159
|
-
|
|
160
|
-
\`\`\`sql
|
|
161
|
-
SELECT
|
|
162
|
-
namespace_id,
|
|
163
|
-
id,
|
|
164
|
-
workflow_name,
|
|
165
|
-
status,
|
|
166
|
-
attempts,
|
|
167
|
-
available_at,
|
|
168
|
-
deadline_at,
|
|
169
|
-
created_at,
|
|
170
|
-
updated_at
|
|
171
|
-
FROM workflow_runs
|
|
172
|
-
ORDER BY created_at DESC
|
|
173
|
-
LIMIT 100;
|
|
174
|
-
\`\`\`
|
|
175
|
-
|
|
176
|
-
List step attempts for one run:
|
|
177
|
-
|
|
178
|
-
\`\`\`sql
|
|
179
|
-
SELECT
|
|
180
|
-
namespace_id,
|
|
181
|
-
id,
|
|
182
|
-
workflow_run_id,
|
|
183
|
-
step_name,
|
|
184
|
-
kind,
|
|
185
|
-
status,
|
|
186
|
-
started_at,
|
|
187
|
-
finished_at,
|
|
188
|
-
created_at
|
|
189
|
-
FROM step_attempts
|
|
190
|
-
WHERE workflow_run_id = ?
|
|
191
|
-
ORDER BY created_at DESC
|
|
192
|
-
LIMIT 200;
|
|
193
|
-
\`\`\`
|
|
194
|
-
`,
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
];
|
|
198
|
-
/**
|
|
199
|
-
* True when the provided value is a supported skill agent.
|
|
200
|
-
* @param value - Agent value from CLI options
|
|
201
|
-
* @returns Whether the value is supported
|
|
202
|
-
*/
|
|
203
|
-
export function isSkillAgent(value) {
|
|
204
|
-
return SUPPORTED_SKILL_AGENTS.includes(value);
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Returns the default skill directory for an agent.
|
|
208
|
-
* @param agent - Skill agent
|
|
209
|
-
* @returns Relative target directory
|
|
210
|
-
*/
|
|
211
|
-
export function getDefaultSkillDirectory(agent) {
|
|
212
|
-
return DEFAULT_SKILL_DIRECTORIES[agent];
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* List available OpenWorkflow skills.
|
|
216
|
-
* @returns Skill catalog entries
|
|
217
|
-
*/
|
|
218
|
-
export function listOpenWorkflowSkills() {
|
|
219
|
-
return OPENWORKFLOW_SKILLS.map((skill) => ({
|
|
220
|
-
name: skill.name,
|
|
221
|
-
description: skill.description,
|
|
222
|
-
}));
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Resolve requested skill names, defaulting to all.
|
|
226
|
-
* @param requestedSkillNames - Skill names from CLI options
|
|
227
|
-
* @returns Unique, validated skill names
|
|
228
|
-
* @throws {Error} When one or more skill names are unknown
|
|
229
|
-
*/
|
|
230
|
-
export function resolveSkillNames(requestedSkillNames) {
|
|
231
|
-
const requested = requestedSkillNames && requestedSkillNames.length > 0
|
|
232
|
-
? requestedSkillNames
|
|
233
|
-
: OPENWORKFLOW_SKILLS.map((skill) => skill.name);
|
|
234
|
-
const deduped = [...new Set(requested)];
|
|
235
|
-
const unknownSkills = deduped.filter((name) => OPENWORKFLOW_SKILLS.every((skill) => skill.name !== name));
|
|
236
|
-
if (unknownSkills.length > 0) {
|
|
237
|
-
throw new Error(`Unknown skill name${unknownSkills.length === 1 ? "" : "s"}: ${unknownSkills.join(", ")}`);
|
|
238
|
-
}
|
|
239
|
-
return deduped;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Install OpenWorkflow skills to an agent skill directory.
|
|
243
|
-
* @param options - Install options
|
|
244
|
-
* @returns Install result metadata
|
|
245
|
-
* @throws {Error} When skill names are invalid or files already exist without force
|
|
246
|
-
*/
|
|
247
|
-
export function installOpenWorkflowSkills(options) {
|
|
248
|
-
const requestedSkillNames = resolveSkillNames(options.requestedSkillNames);
|
|
249
|
-
const defaultDirectory = getDefaultSkillDirectory(options.agent);
|
|
250
|
-
const targetDirectory = path.resolve(options.workspaceDirectory, options.targetDirectory ?? defaultDirectory);
|
|
251
|
-
mkdirSync(targetDirectory, { recursive: true });
|
|
252
|
-
const installedSkills = [];
|
|
253
|
-
for (const skillName of requestedSkillNames) {
|
|
254
|
-
const skill = OPENWORKFLOW_SKILLS.find((item) => item.name === skillName);
|
|
255
|
-
if (!skill) {
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
const skillDirectory = path.join(targetDirectory, skill.name);
|
|
259
|
-
const hadExistingDirectory = existsSync(skillDirectory);
|
|
260
|
-
if (hadExistingDirectory && !options.force) {
|
|
261
|
-
throw new Error(`Skill "${skill.name}" already exists at ${skillDirectory}. Use --force to overwrite.`);
|
|
262
|
-
}
|
|
263
|
-
if (hadExistingDirectory) {
|
|
264
|
-
rmSync(skillDirectory, { force: true, recursive: true });
|
|
265
|
-
}
|
|
266
|
-
for (const [relativePath, content] of Object.entries(skill.files)) {
|
|
267
|
-
const destinationPath = path.join(skillDirectory, relativePath);
|
|
268
|
-
mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
269
|
-
writeFileSync(destinationPath, content, "utf8");
|
|
270
|
-
}
|
|
271
|
-
installedSkills.push({
|
|
272
|
-
name: skill.name,
|
|
273
|
-
overwritten: hadExistingDirectory,
|
|
274
|
-
path: skillDirectory,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
return { installedSkills, targetDirectory };
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Read a skill file from disk. Used by tests.
|
|
281
|
-
* @param skillPath - Path to the skill file
|
|
282
|
-
* @returns File content
|
|
283
|
-
*/
|
|
284
|
-
export function readSkillFile(skillPath) {
|
|
285
|
-
return readFileSync(skillPath, "utf8");
|
|
286
|
-
}
|