oh-my-workflow 0.1.0 → 0.2.1

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/README.md CHANGED
@@ -94,6 +94,23 @@ and fix your script. stdout is one result JSON; the `--pretty` tree and a
94
94
  (fan-out / verify-vote / pipeline / loop-until-dry), the debug loop, and the
95
95
  conventions. That skill is the primary product; this README is the human intro.
96
96
 
97
+ ## Install the skill (the primary product)
98
+
99
+ omw's primary product is an **agent-authoring skill** (`skill/SKILL.md`) — it
100
+ teaches a coding agent to write, run, and repair omw workflows. After the package
101
+ is installed, wire the skill into your agent in one step:
102
+
103
+ ```sh
104
+ omw skill install # → ~/.claude/skills/oh-my-workflow (Claude Code auto-discovers it)
105
+ omw skill install --project # → ./.claude/skills/oh-my-workflow (this repo only)
106
+ omw skill path # print the bundled SKILL.md path (cat / pipe / point an agent at it)
107
+ ```
108
+
109
+ Then ask your coding agent: *"use oh-my-workflow to <task>"* — it authors a
110
+ `workflow.ts` and runs it with `omw run`. (The skill is Claude-Code-flavored;
111
+ for other hosts use `omw skill path` and feed the file in however that host loads
112
+ context.)
113
+
97
114
  ## Adapters
98
115
 
99
116
  A node is a coding agent driven through its headless prompt→result CLI.
@@ -101,8 +118,8 @@ A node is a coding agent driven through its headless prompt→result CLI.
101
118
  | adapter | status | notes |
102
119
  |---|---|---|
103
120
  | **fake** | built-in, free, deterministic | the no-key demo engine and test double |
104
- | **claude** | **full** (live-verified, 2.1.177) | `claude -p --output-format json`; `--resume` powers in-session schema self-repair |
105
- | **codex** | **experimental** (live-verified, 0.137.0) | `codex exec --json`; **no cost field**; tolerates malformed JSONL ([openai/codex#15451](https://github.com/openai/codex/issues/15451)) and fails *actionably* |
121
+ | **claude** | **full** (live-verified, 2.1.x) | `claude -p --output-format json`; `--resume` powers in-session schema self-repair |
122
+ | **codex** | **experimental** (live-verified, 0.137.x) | `codex exec --json`; **no cost field**; tolerates malformed JSONL ([openai/codex#15451](https://github.com/openai/codex/issues/15451)) and fails *actionably* |
106
123
  | **pi** | planned | not wired yet (`--agent pi` → exit 3 + install hint) |
107
124
  | **kiro** | not a fit | its CLI is an IDE launcher (open files/diffs), no headless prompt→result interface |
108
125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-workflow",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Run coding-agent CLIs (claude -p / codex exec) as nodes in a plain-JS workflow. The thin deterministic glue.",
5
5
  "type": "module",
6
6
  "author": "Dongwook Kim (https://github.com/domuk-k)",
package/skill/SKILL.md CHANGED
@@ -34,22 +34,35 @@ bad node never crashes the run.
34
34
  single raw LLM API call (that's LangGraph/Mastra territory; an omw node is a
35
35
  *whole coding agent*).
36
36
 
37
- ## The 30-second free demo (no API key)
37
+ ## The 30-second free demo (no API key, nothing to clone)
38
+
39
+ omw is on npm, so you can run the whole thing in one line — no install step, no
40
+ key, no cost:
41
+
42
+ ```sh
43
+ bunx oh-my-workflow@latest run examples/deep-research --agent fake
44
+ # → {"confirmed":[…],"summary":{…}} exit 0 · no key · no cost · deterministic
45
+ ```
46
+
47
+ > Tip: use `@latest`. A bare `bunx oh-my-workflow` can serve a stale cached copy.
48
+
49
+ That single command runs the **whole spine** for you — a fan-out search, a
50
+ pipeline, a scripted schema-fail→self-repair, and a scripted timeout→drop — and
51
+ prints one result JSON. Want to watch it happen? Add `--pretty` for the
52
+ phase/fan-out tree on stderr:
38
53
 
39
54
  ```sh
40
- git clone <repo-url> && cd oh-my-workflow # repo not yet public; fill in the URL
41
- bun install
42
- bun src/cli/omw.ts run examples/deep-research --agent fake
43
- # → {"confirmed":[…],"summary":{…}} exit 0 · no key · no cost · `--agent fake` is deterministic
55
+ bunx oh-my-workflow@latest run examples/deep-research --agent fake --pretty
44
56
  ```
45
57
 
46
- `--agent fake` is a built-in deterministic adapter: it runs the full spine
47
- (fan-out + pipeline + a scripted schema-fail→self-repair + a scripted
48
- timeout→drop) and prints one result JSON. Add `--pretty` to see the phase/fan-out
49
- tree on stderr. Swap `--agent claude` once you've run `claude login`.
58
+ `--agent fake` is a built-in, deterministic adapter it's the no-key demo engine
59
+ and the test double. When you're ready for real work, run `claude login` once and
60
+ swap `--agent fake` `--agent claude`. Same script, real nodes.
50
61
 
51
- > Once published this is `bunx oh-my-workflow run …`; today run the bin directly
52
- > from a clone as shown above.
62
+ > **Reading this as a skill?** You already have it. To install/update it for a
63
+ > coding agent: `bunx oh-my-workflow@latest skill install` (→ `~/.claude/skills/`,
64
+ > or `--project` for one repo); `omw skill path` prints the bundled copy for other
65
+ > hosts. Re-run `skill install` anytime to refresh.
53
66
 
54
67
  ---
55
68
 
@@ -389,8 +402,8 @@ agents that expose such a CLI can be nodes.
389
402
  | adapter | status | invoke | structured out | in-session follow-up |
390
403
  |---|---|---|---|---|
391
404
  | **fake** | built-in, free, deterministic | in-process fixtures | as scripted | yes (fixture) |
392
- | **claude** | **full** (live-verified, claude 2.1.177) | `claude -p <p> --output-format json` | parse `.result` | `--resume` |
393
- | **codex** | **experimental** (live-verified, codex 0.137.0) | `codex exec --json -s workspace-write` | last `agent_message` from JSONL | `exec resume` |
405
+ | **claude** | **full** (live-verified, claude 2.1.x) | `claude -p <p> --output-format json` | parse `.result` | `--resume` |
406
+ | **codex** | **experimental** (live-verified, codex 0.137.x) | `codex exec --json -s workspace-write` | last `agent_message` from JSONL | `exec resume` |
394
407
  | **pi** | planned | `pi --print` | stdout | — |
395
408
  | **kiro** | **not a fit** | — | — | — |
396
409
 
package/src/cli/omw.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  import { runCommand } from "./run";
7
7
  import { replayCommand } from "./replay";
8
8
  import { validateCommand } from "./validate";
9
+ import { skillCommand } from "./skill";
9
10
 
10
11
  const io = {
11
12
  stdout: (s: string) => process.stdout.write(s),
@@ -21,13 +22,16 @@ async function main(argv: string[]): Promise<number> {
21
22
  return replayCommand(rest, io);
22
23
  case "validate":
23
24
  return validateCommand(rest, io);
25
+ case "skill":
26
+ return skillCommand(rest, io);
24
27
  default:
25
28
  io.stderr(
26
29
  "usage: omw <command>\n\n" +
27
30
  "commands:\n" +
28
31
  " run <workflow> --agent <fake|claude|codex|pi> [--args JSON] [--concurrency N] [--resume <journal.jsonl>] [--pretty]\n" +
29
32
  " replay <journal.jsonl> [--json]\n" +
30
- " validate <workflow> [--json]\n\n" +
33
+ " validate <workflow> [--json]\n" +
34
+ " skill install [--project] install the omw authoring skill for your coding agent\n\n" +
31
35
  "free demo (no API key): omw run examples/deep-research --agent fake\n",
32
36
  );
33
37
  return cmd === undefined ? 2 : 2;
@@ -0,0 +1,104 @@
1
+ // `omw skill <install|path>` — make "installed npm package" → "active authoring
2
+ // skill" one ergonomic step. The bundled skill/SKILL.md is the primary product:
3
+ // it teaches a coding agent to author, run, and repair omw workflows. `install`
4
+ // copies it into a coding agent's skills dir (auto-discovered by Claude Code);
5
+ // `path` prints the bundled copy's location for piping / pointing an agent at it.
6
+ //
7
+ // fs is reachable directly (this is the IO wiring command, like run.ts); the arg
8
+ // parse is a pure function so the contract is testable without touching disk.
9
+
10
+ import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { dirname, join, resolve } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ /** Package root, so the bundled skill resolves whether omw runs from a clone or
16
+ * an npm install invoked from any cwd. (Same technique as run.ts's PKG_ROOT.) */
17
+ const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
18
+ const SKILL_NAME = "oh-my-workflow";
19
+
20
+ export type SkillIo = {
21
+ stdout: (s: string) => void;
22
+ stderr: (s: string) => void;
23
+ /** Overridable for tests; default to the real environment. */
24
+ homeDir?: string;
25
+ cwd?: string;
26
+ /** Directory holding the bundled SKILL.md; defaults to <pkg>/skill. */
27
+ skillDir?: string;
28
+ };
29
+
30
+ export type SkillParse =
31
+ | { ok: true; sub: "install"; project: boolean }
32
+ | { ok: true; sub: "path" }
33
+ | { ok: true; sub: "help" }
34
+ | { ok: false; error: string };
35
+
36
+ const USAGE =
37
+ "usage: omw skill <command>\n\n" +
38
+ "commands:\n" +
39
+ " install [--project] copy the skill into a skills dir so a coding agent picks it up\n" +
40
+ " (default: ~/.claude/skills/oh-my-workflow; --project: ./.claude/skills/…)\n" +
41
+ " path print the bundled SKILL.md path (for cat / piping / pointing an agent at it)\n";
42
+
43
+ export function parseSkillArgs(argv: string[]): SkillParse {
44
+ const [sub, ...rest] = argv;
45
+ if (sub === undefined || sub === "help" || sub === "--help" || sub === "-h") {
46
+ return { ok: true, sub: "help" };
47
+ }
48
+ if (sub === "path") {
49
+ if (rest.length > 0) return { ok: false, error: `unexpected argument: ${rest[0]}` };
50
+ return { ok: true, sub: "path" };
51
+ }
52
+ if (sub === "install") {
53
+ let project = false;
54
+ for (const tok of rest) {
55
+ if (tok === "--project") project = true;
56
+ else return { ok: false, error: `unexpected argument: ${tok}` };
57
+ }
58
+ return { ok: true, sub: "install", project };
59
+ }
60
+ return { ok: false, error: `unknown skill subcommand: ${sub}` };
61
+ }
62
+
63
+ export async function skillCommand(argv: string[], io: SkillIo): Promise<number> {
64
+ const parsed = parseSkillArgs(argv);
65
+ if (!parsed.ok) {
66
+ io.stderr(`${parsed.error}\n\n${USAGE}`);
67
+ return 2;
68
+ }
69
+ if (parsed.sub === "help") {
70
+ io.stdout(USAGE);
71
+ return 0;
72
+ }
73
+
74
+ const srcDir = io.skillDir ?? join(PKG_ROOT, "skill");
75
+ const srcFile = join(srcDir, "SKILL.md");
76
+ if (!existsSync(srcFile)) {
77
+ io.stderr(`bundled skill not found at ${srcFile} — reinstall oh-my-workflow?\n`);
78
+ return 1;
79
+ }
80
+
81
+ if (parsed.sub === "path") {
82
+ io.stdout(`${srcFile}\n`);
83
+ return 0;
84
+ }
85
+
86
+ // install — idempotent: copy the whole skill dir (SKILL.md + any bundled
87
+ // resources) in place, and report installed vs updated.
88
+ const base = parsed.project ? join(io.cwd ?? process.cwd(), ".claude") : join(io.homeDir ?? homedir(), ".claude");
89
+ const destDir = join(base, "skills", SKILL_NAME);
90
+ const dest = join(destDir, "SKILL.md");
91
+ const updating = existsSync(dest);
92
+ // Clean replace, not an additive copy: drop a prior install first so a file
93
+ // that was removed from the bundle doesn't linger as stale content.
94
+ rmSync(destDir, { recursive: true, force: true });
95
+ mkdirSync(destDir, { recursive: true });
96
+ cpSync(srcDir, destDir, { recursive: true });
97
+
98
+ io.stdout(
99
+ `${updating ? "updated" : "installed"} ${SKILL_NAME} skill → ${dest}\n` +
100
+ `${parsed.project ? "This project's" : "Claude Code"} agent auto-discovers skills here.\n` +
101
+ `Next: ask your coding agent to "use oh-my-workflow to <your task>".\n`,
102
+ );
103
+ return 0;
104
+ }