@crewx/workflow 0.3.22-rc.3 → 0.3.22-rc.30

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/SKILL.md CHANGED
@@ -35,12 +35,20 @@ crewx workflow show standard-dev-core --mermaid
35
35
  # Validate all workflow files
36
36
  crewx workflow validate
37
37
 
38
- # Start a workflow execution
39
- crewx workflow run start standard-dev-core --set goal="implement feature X"
38
+ # Start a workflow execution and auto-run until completion/pause
39
+ crewx workflow run start standard-dev-core --set goal="implement feature X" --auto
40
+
41
+ # In the CrewX web chat, start a workflow as a signed ChatCard.
42
+ # Text after the workflow id becomes state.input.
43
+ /wf rc-publish prepare the next RC
44
+ /wf rc-publish --manual dry run only
40
45
 
41
46
  # Move to a node
42
47
  crewx workflow run node <exec-id> research
43
48
 
49
+ # Resume auto-run from the current node
50
+ crewx workflow run auto <exec-id>
51
+
44
52
  # Check execution state
45
53
  crewx workflow run state <exec-id>
46
54
  ```
@@ -78,10 +86,12 @@ crewx workflow validate workflows/standard-dev.yaml # Validate a specific file
78
86
  ### `workflow run start <id|file>`
79
87
 
80
88
  Creates a new execution instance. State is stored as a JSON file in `.crewx/workflow-runs/`.
89
+ Add `--auto` to immediately execute deterministic nodes and agent nodes until the run reaches `end`, `approval`, `parallel`, or a failure.
81
90
 
82
91
  ```bash
83
92
  crewx workflow run start standard-dev-core
84
93
  crewx workflow run start standard-dev-core --set goal="build auth module"
94
+ crewx workflow run start standard-dev-core --set goal="build auth module" --auto
85
95
  crewx workflow run start workflows/idea-validation.yaml
86
96
  ```
87
97
 
@@ -109,6 +119,36 @@ crewx workflow run node wfr_abc12345 research
109
119
  crewx workflow run node wfr_abc12345 end
110
120
  ```
111
121
 
122
+ ### `workflow run auto <exec-id>`
123
+
124
+ Auto-runs from the current node until the workflow reaches a natural pause or terminal state.
125
+
126
+ ```bash
127
+ crewx workflow run auto wfr_abc12345
128
+ crewx workflow run auto wfr_abc12345 --json
129
+ ```
130
+
131
+ Auto mode executes these node types directly:
132
+
133
+ | Node type | Auto behavior |
134
+ |-----------|---------------|
135
+ | `agent_task` | Invokes the configured agent via `crewx q/x`, stores output if `output` is set, then follows `next` |
136
+ | `skill_task` | Runs `crewx skill <skill> ...args`, stores output if `output` is set, then follows `next` |
137
+ | `shell_task` | Runs a gated argv command with `shell: false`, stores output if `output` is set, then follows `next` |
138
+ | `expression` | Evaluates safe state expressions and follows `next` |
139
+ | `branch` | Evaluates the branch condition and moves to the selected node |
140
+ | `join` | Checks predecessor completion and follows `next` |
141
+ | `end` | Marks the run as completed |
142
+
143
+ Auto mode pauses instead of crossing these boundaries:
144
+
145
+ | Node type | Why it pauses |
146
+ |-----------|---------------|
147
+ | `approval` | Requires an explicit human approve/reject decision |
148
+ | `parallel` | Branch scheduling/convergence must be handled separately |
149
+
150
+ `max_iterations` limits auto-run steps and prevents infinite loops.
151
+
112
152
  ### `workflow run reset <exec-id>`
113
153
 
114
154
  Restores execution state to `initial_state`.
@@ -181,6 +221,42 @@ analyze:
181
221
  next: calculate
182
222
  ```
183
223
 
224
+ #### agent_task — execution context & failure signaling
225
+
226
+ Every `agent_task` prompt is automatically prefixed with a `<crewx.workflow>` preamble
227
+ telling the agent it runs headless inside a workflow node (workflow ID, node ID, run ID),
228
+ that clarifying questions are impossible, and how to signal failure. Disable with
229
+ `CREWX_WORKFLOW_PREAMBLE=off`.
230
+
231
+ Two semantic-failure channels stop the run at the node (in addition to non-zero exit codes):
232
+
233
+ 1. **`workflow_signal` (agent-initiated)** — the agent outputs exactly one JSON object:
234
+
235
+ ```json
236
+ {"workflow_signal": "fail", "reason": "build is red — tsc reports 14 errors"}
237
+ ```
238
+
239
+ The engine detects it (pure JSON or embedded in prose), marks the node failed, and
240
+ records the reason in `run.error`. This is the agent's `exit 1`.
241
+
242
+ 2. **`fail_when` (node-declared)** — a safe expression evaluated against state *after*
243
+ the node's output is stored. Truthy → node fails, run halts. The judged output is
244
+ still preserved in state for inspection. No separate `check_*` branch node needed.
245
+
246
+ ```yaml
247
+ verify:
248
+ type: agent_task
249
+ agent: core_dev
250
+ output: verify_result
251
+ output_format: json
252
+ fail_when: 'state.verify_result.status !== "pass"'
253
+ next: smoke_test
254
+ ```
255
+
256
+ `fail_when` works on `agent_task`, `skill_task`, and `shell_task`. It uses the same
257
+ safe expression subset as `branch` conditions (`includes()`, `===`, `&&`, `Number()`...).
258
+ Use `branch` when failure should route somewhere; use `fail_when` when failure should stop the run.
259
+
184
260
  #### agent_task — JSON output mode
185
261
 
186
262
  When `output_format: json`, the engine requires the agent to return a single JSON object.
@@ -232,6 +308,81 @@ The schema is validated against JSON Schema 2020-12 (`@hyperjump/json-schema`).
232
308
 
233
309
  OpenAI Structured Outputs compatible — use `output_strict: true` to enforce the subset in the LLM prompt.
234
310
 
311
+ ### `skill_task` -- Run a CrewX skill
312
+
313
+ Runs a built-in or registered CrewX skill without asking an agent to do the mechanical work. Use this for deterministic steps such as document extraction, search, indexing, validation, or other skill-backed commands.
314
+
315
+ ```yaml
316
+ extract_attachments:
317
+ type: skill_task
318
+ skill: ocr-extractor
319
+ args: ["--input", "{{attachment_dir}}", "--json"]
320
+ output: extracted_text
321
+ output_format: json
322
+ output_retry: 2
323
+ timeout: 600
324
+ next: analyze
325
+ ```
326
+
327
+ | Field | Type | Required | Description |
328
+ |-------|------|----------|-------------|
329
+ | `skill` | string | **Yes** | Skill name. Must match `^[a-z0-9][a-z0-9-]*$`; path traversal and special characters are rejected. |
330
+ | `args` | string[] | No | CLI arguments appended after the skill name. Supports `{{state}}` template interpolation. |
331
+ | `cwd` | string | No | Working directory. Normalized and constrained under the project root. |
332
+ | `output` | string | No | State key to store stdout. |
333
+ | `output_format` | `'json'` | No | Parse stdout as JSON and validate with `output_schema` if provided. |
334
+ | `output_schema` | object | No | Standard JSON Schema 2020-12 for parsed output. |
335
+ | `output_retry` | integer | No | Retry attempts if JSON parse or schema validation fails. |
336
+
337
+ `skill_task` uses `CREWX_CLI` (default: `npx crewx`) and executes the equivalent of:
338
+
339
+ ```bash
340
+ crewx skill <skill> ...args
341
+ ```
342
+
343
+ ### `shell_task` -- Run a gated argv command
344
+
345
+ Runs a local command only when both safety gates are enabled:
346
+
347
+ 1. Environment opt-in: `CREWX_WORKFLOW_SHELL=1`
348
+ 2. Workflow opt-in: `metadata.shell_task_allowed: true`
349
+
350
+ ```yaml
351
+ workflows:
352
+ build-check:
353
+ metadata:
354
+ name: "Build check"
355
+ shell_task_allowed: true
356
+ nodes:
357
+ build:
358
+ type: shell_task
359
+ command: ["pnpm", "run", "build"]
360
+ cwd: "."
361
+ output: build_log
362
+ timeout: 600
363
+ next: end
364
+ end:
365
+ type: end
366
+ ```
367
+
368
+ | Field | Type | Required | Description |
369
+ |-------|------|----------|-------------|
370
+ | `command` | string[] | **Yes** | argv array. Plain string commands are rejected. `command[0]` is the program; remaining values are args. |
371
+ | `cwd` | string | No | Working directory. Normalized and constrained under the project root. |
372
+ | `env` | object | No | Explicit env pass-through. Dangerous keys such as `LD_PRELOAD` are rejected. |
373
+ | `output` | string | No | State key to store stdout. |
374
+ | `output_format` | `'json'` | No | Parse stdout as JSON and validate with `output_schema` if provided. |
375
+ | `output_schema` | object | No | Standard JSON Schema 2020-12 for parsed output. |
376
+ | `output_retry` | integer | No | Retry attempts if JSON parse or schema validation fails. |
377
+
378
+ Security rules:
379
+
380
+ - `shell_task.command` must be an argv array; it never runs through a shell.
381
+ - Shell interpreters such as `sh`, `bash`, `zsh`, `fish`, `cmd`, and `powershell` are blocked.
382
+ - Inline code flags such as `node -e`, `python -c`, and `ruby -e` are blocked.
383
+ - Parent environment is not inherited wholesale; only a minimal allowlist plus explicit safe `env` keys is passed.
384
+ - Commands run with timeout and process-group termination.
385
+
235
386
  ### `parallel` -- Fan-out to concurrent branches
236
387
 
237
388
  ```yaml
@@ -325,14 +476,15 @@ end:
325
476
  | `on_failure` | string | `fail_fast` \| `continue` \| `ignore` |
326
477
  | `on_error` | object | `{ handler?, fallback_node? }` |
327
478
  | `comment` | string | Human-readable annotation |
328
- | `output_format` | `'json'` | Enable JSON output mode (`agent_task` only) |
479
+ | `output` | string | State key to store stdout/result (`agent_task`, `skill_task`, `shell_task`) |
480
+ | `output_format` | `'json'` | Enable JSON output mode (`agent_task`, `skill_task`, `shell_task`) |
329
481
  | `output_schema` | object | Standard JSON Schema 2020-12 for output validation |
330
482
  | `output_strict` | boolean | Apply OpenAI Structured Outputs subset to LLM prompt (default: `false`) |
331
483
  | `output_retry` | integer | Retry count if JSON parse/validation fails (default: `1`) |
332
484
 
333
485
  ## Template Syntax
334
486
 
335
- Use `{{variable_name}}` in `input` fields to reference `state` values.
487
+ Use `{{variable_name}}` in fields such as `input`, `args`, `command`, `cwd`, and `env` values to reference `state` values.
336
488
 
337
489
  ```yaml
338
490
  state:
@@ -383,6 +535,9 @@ const exec: RunExecution = manager.start('workflows/dev.yaml', 'dev-core', { goa
383
535
  // Execute a node (triggers agent call for agent_task nodes)
384
536
  const updated: RunExecution = await manager.executeNode(exec.id, 'research');
385
537
 
538
+ // Auto-run until end, approval, parallel, or failure
539
+ const autoResult = await manager.runAuto(exec.id);
540
+
386
541
  // Move to node without executing
387
542
  const moved: RunExecution = manager.moveNode(exec.id, 'implement');
388
543
  ```
@@ -390,7 +545,16 @@ const moved: RunExecution = manager.moveNode(exec.id, 'implement');
390
545
  ### Key Types
391
546
 
392
547
  ```typescript
393
- type NodeType = 'agent_task' | 'parallel' | 'join' | 'branch' | 'approval' | 'expression' | 'end';
548
+ type NodeType =
549
+ | 'agent_task'
550
+ | 'skill_task'
551
+ | 'shell_task'
552
+ | 'parallel'
553
+ | 'join'
554
+ | 'branch'
555
+ | 'approval'
556
+ | 'expression'
557
+ | 'end';
394
558
 
395
559
  interface RunExecution {
396
560
  id: string; // 'wfr_{nanoid(8)}'
@@ -402,10 +566,82 @@ interface RunExecution {
402
566
  completed_nodes: string[];
403
567
  state: Record<string, unknown>;
404
568
  initial_state: Record<string, unknown>;
569
+ audit?: Array<{
570
+ node_id: string;
571
+ type: NodeType;
572
+ status: 'success' | 'failed' | 'timeout';
573
+ started_at: string;
574
+ finished_at: string;
575
+ duration_ms: number;
576
+ exit_code?: number | null;
577
+ trigger?: 'manual' | 'auto';
578
+ }>;
405
579
  status?: 'running' | 'completed' | 'failed';
406
580
  }
407
581
  ```
408
582
 
583
+ ## Web UI `/wf` ChatCard Integration
584
+
585
+ The CrewX web chat treats workflow runs as **conversation content**, not as a side panel. When a user sends a `/wf` command, the server creates a workflow run, stores the original user message in the thread transcript, and stores an assistant message containing a signed workflow ChatCard.
586
+
587
+ ### Syntax
588
+
589
+ ```text
590
+ /wf <workflow-id> [input...]
591
+ /wf <workflow-id> --manual [input...]
592
+ /wf <workflow-id> --auto [input...]
593
+ ```
594
+
595
+ Examples:
596
+
597
+ | Input | Run behavior |
598
+ |-------|--------------|
599
+ | `/wf rc-publish` | Starts `rc-publish` in auto mode |
600
+ | `/wf rc-publish 미리승인한다` | Starts `rc-publish` with `state.input = "미리승인한다"` |
601
+ | `/wf rc-publish --manual dry run` | Creates the run in manual mode with `state.input = "dry run"` |
602
+ | `/wf rc-publish --auto prepare RC notes` | Explicit auto mode; same as default |
603
+
604
+ `--manual` and `--auto` are parsed as options and are **not** included in `state.input`. All remaining text after the workflow id is copied to `state.input`.
605
+
606
+ ### `state.input`
607
+
608
+ `state.input` is the standard entry point for user instructions passed into a workflow run.
609
+
610
+ ```yaml
611
+ nodes:
612
+ - id: plan
613
+ type: agent_task
614
+ agent: "@core_dev"
615
+ prompt: |
616
+ User instruction:
617
+ {{input}}
618
+
619
+ Plan and execute the workflow step accordingly.
620
+ ```
621
+
622
+ Branches and templates may also read `state.input`:
623
+
624
+ ```yaml
625
+ condition: state.input.includes("dry run")
626
+ ```
627
+
628
+ Important security rule: `state.input` is **not authority**. It may influence prompts, branches, and templates, but it must never bypass an `approval` node. For example, `/wf rc-publish 미리승인한다` stores the text in `state.input`; it does not approve publishing. Approval still requires the signed ChatCard action button.
629
+
630
+ ### Stored ChatCard
631
+
632
+ The assistant message stores only a signed reference to the workflow run:
633
+
634
+ ```xml
635
+ <crewx_card type="workflow" version="1" run_id="wfr_xxx" workflow_id="rc-publish" mode="auto" proof="jwt..." />
636
+ ```
637
+
638
+ Rules:
639
+
640
+ - The `proof` is server-issued and expires after 7 days.
641
+ - Raw `<crewx_card>` text from users is rendered as plain text.
642
+ - Workflow actions such as resolve, auto resume, approve, reject, and cancel require a valid proof bound to the current workspace/thread/task.
643
+ - The mutable run state remains in `.crewx/workflow-runs/`; the ChatCard stores only a reference.
644
+
409
645
  ## Architecture
410
646
 
411
647
  ```
@@ -417,29 +653,37 @@ interface RunExecution {
417
653
  v
418
654
  workflows/*.yaml (source files)
419
655
 
420
- [CLI] crewx workflow run start/node/state
656
+ [CLI] crewx workflow run start/node/state/auto
421
657
  |
422
658
  v
423
659
  RunManager <-- execution state management
424
660
  |
425
661
  +---> .crewx/workflow-runs/wfr_*.json (state files)
426
- +---> crewx q/x (agent invocation for agent_task nodes)
662
+ +---> crewx q/x (agent_task)
663
+ +---> crewx skill <skill> (skill_task)
664
+ +---> argv command, shell:false (shell_task; gated)
427
665
 
428
666
  [Server] GET /api/v1/workflows[/:id]
667
+ POST /api/v1/workflows/:id/runs
668
+ GET/POST /api/v1/workflows/runs/:execId/*
429
669
  |
430
670
  v
431
- WorkflowService --> fs (YAML read) + WorkflowEngine.toMermaid()
671
+ WorkflowService --> fs (YAML read) + WorkflowEngine + RunManager
672
+ |
673
+ +---> Thread transcript card:
674
+ <crewx_card type="workflow" run_id="..." workflow_id="..." mode="auto" proof="jwt..." />
432
675
  ```
433
676
 
434
- > **Note:** The server only uses `WorkflowEngine.toMermaid()`. YAML listing/parsing is handled by the server's own `WorkflowService`. `RunManager` (execution state) is CLI-only.
677
+ > **Note:** The server uses `RunManager` for workflow runs and stores workflow UI references as ChatCard tags in thread messages. The mutable run status/state remains in `.crewx/workflow-runs/` and is fetched by `run_id`.
435
678
 
436
679
  ## Environment Variables
437
680
 
438
681
  | Variable | Description | Default |
439
682
  |----------|-------------|---------|
440
683
  | `CREWX_WORKSPACE` | Workspace directory (where `workflows/` lives) | `.` |
441
- | `CREWX_CLI` | CrewX CLI path (for agent execution in `run node`) | `npx crewx` |
442
- | `CREWX_WORKFLOW_TIMEOUT` | Node execution timeout (ms) | `1800000` (30 min) |
684
+ | `CREWX_CLI` | CrewX CLI path (for `agent_task` and `skill_task`) | `npx crewx` |
685
+ | `CREWX_WORKFLOW_TIMEOUT` | `agent_task` execution timeout (ms) | `1800000` (30 min) |
686
+ | `CREWX_WORKFLOW_SHELL` | First safety gate for `shell_task`; must be `1` | unset |
443
687
  | `CREWX_CONFIG` | Custom config file path | `crewx.yaml` |
444
688
 
445
689
  ## WARNING: Check Agent List Before Designing
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";AAgBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAgB,YAAY,EAAgB,MAAM,aAAa,CAAC;AA6F5F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;CACrC;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,EAAE,cAAc,EACtB,SAAS,CAAC,EAAE,cAAc,EAAE,GAC3B,gBAAgB,CAkDlB;AA6sBD,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAClC,MAAM,GAAG,IAAI,CAkBf;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,MAAM,EAAE,CAsB1E;AA4CD,wBAAsB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD9D"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";AAgBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAgB,YAAY,EAA+B,MAAM,aAAa,CAAC;AA6F3G,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;CACrC;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,EAAE,cAAc,EACtB,SAAS,CAAC,EAAE,cAAc,EAAE,GAC3B,gBAAgB,CAkDlB;AAmxBD,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAClC,MAAM,GAAG,IAAI,CAoBf;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,MAAM,EAAE,CAsB1E;AA4CD,wBAAsB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD9D"}
package/dist/cli.js CHANGED
@@ -63,7 +63,7 @@ async function loadTracer() {
63
63
  return null;
64
64
  }
65
65
  }
66
- const BOOLEAN_FLAGS = new Set(['help', 'json', 'mermaid', 'version', 'no-exec']);
66
+ const BOOLEAN_FLAGS = new Set(['help', 'json', 'mermaid', 'version', 'no-exec', 'auto']);
67
67
  function parseArgs(args) {
68
68
  const result = { positional: [], options: {} };
69
69
  for (let i = 0; i < args.length; i++) {
@@ -193,10 +193,11 @@ Commands:
193
193
  workflow list List all workflows
194
194
  workflow show <id|file> Show workflow detail
195
195
  workflow validate [id|file] Validate workflow YAML
196
- workflow run start <id|file> Create new execution
196
+ workflow run start <id|file> Create new execution (add --auto to run to completion)
197
197
  # Resolution: .yaml path → workflow ID → filename slug
198
198
  workflow run state <id> Get/set execution state
199
199
  workflow run node <id> <node> Execute node (auto-invoke agent)
200
+ workflow run auto <id> Auto-run from current node until end/pause
200
201
  workflow run reset <id> Reset execution
201
202
  workflow run list List all executions
202
203
  workflow usage Show detailed guide
@@ -298,8 +299,8 @@ function cmdList(engine, jsonMode) {
298
299
  const firstId = workflows[0]?.id;
299
300
  if (firstId) {
300
301
  console.log(`\n${'━'.repeat(43)}`);
301
- console.log(`🔍 워크플로 상세: npx workflow show ${firstId}`);
302
- console.log(`🔀 워크플로 실행: npx workflow run start <id> --set key="value"`);
302
+ console.log(`🔍 Workflow details: npx workflow show ${firstId}`);
303
+ console.log(`🔀 Run workflow: npx workflow run start <id> --set key="value"`);
303
304
  }
304
305
  const listCtx = {
305
306
  commandId: 'workflow.list',
@@ -564,8 +565,18 @@ async function cmdRun(rest, rawArgs, jsonMode, engine) {
564
565
  process.exit(1);
565
566
  }
566
567
  const sets = (0, run_manager_1.parseSetArgs)(rawArgs);
568
+ const auto = rawArgs.includes('--auto');
567
569
  try {
568
570
  const run = mgr.start(resolved.filePath, resolved.workflowId ?? positional[1], Object.keys(sets).length > 0 ? sets : undefined);
571
+ if (auto) {
572
+ if (!jsonMode) {
573
+ console.log(`✅ Created execution: ${run.id}`);
574
+ console.log(` Workflow: ${run.workflow_id} (${resolved.filePath})`);
575
+ }
576
+ const result = await mgr.runAuto(run.id);
577
+ reportAutoResult(result, jsonMode);
578
+ break;
579
+ }
569
580
  if (jsonMode) {
570
581
  console.log(JSON.stringify({ success: true, exec_id: run.id, run }, null, 2));
571
582
  }
@@ -828,8 +839,39 @@ async function cmdRun(rest, rawArgs, jsonMode, engine) {
828
839
  }
829
840
  break;
830
841
  }
842
+ case 'auto': {
843
+ const positional = runArgs.filter(a => !a.startsWith('--'));
844
+ const execId = positional[0];
845
+ if (!execId) {
846
+ const msg = 'Usage: workflow run auto <exec-id>';
847
+ if (jsonMode) {
848
+ console.log(JSON.stringify({ success: false, error: msg }));
849
+ }
850
+ else {
851
+ console.error(`❌ ${msg}`);
852
+ }
853
+ process.exit(1);
854
+ }
855
+ try {
856
+ const result = await mgr.runAuto(execId);
857
+ reportAutoResult(result, jsonMode);
858
+ if (result.outcome === 'failed')
859
+ process.exit(1);
860
+ }
861
+ catch (e) {
862
+ const msg = e.message;
863
+ if (jsonMode) {
864
+ console.log(JSON.stringify({ success: false, error: msg }));
865
+ }
866
+ else {
867
+ console.error(`❌ ${msg}`);
868
+ }
869
+ process.exit(1);
870
+ }
871
+ break;
872
+ }
831
873
  default: {
832
- const msg = `Unknown run subcommand: ${runSub || '(none)'}\nUsage: workflow run <start|state|node|reset|list> [args...]`;
874
+ const msg = `Unknown run subcommand: ${runSub || '(none)'}\nUsage: workflow run <start|state|node|auto|reset|list> [args...]`;
833
875
  if (jsonMode) {
834
876
  console.log(JSON.stringify({ success: false, error: msg }));
835
877
  }
@@ -840,12 +882,39 @@ async function cmdRun(rest, rawArgs, jsonMode, engine) {
840
882
  }
841
883
  }
842
884
  }
885
+ function reportAutoResult(result, jsonMode) {
886
+ const { run, outcome, reason, executed } = result;
887
+ const status = run.status ?? (outcome === 'paused' ? 'paused' : 'running');
888
+ if (jsonMode) {
889
+ console.log(JSON.stringify({
890
+ success: outcome !== 'failed',
891
+ exec_id: run.id,
892
+ status,
893
+ outcome,
894
+ current_node: run.current_node,
895
+ completed_nodes: run.completed_nodes,
896
+ executed,
897
+ ...(reason ? { reason } : {}),
898
+ }, null, 2));
899
+ return;
900
+ }
901
+ const icon = outcome === 'failed' ? '❌' : outcome === 'paused' ? '⏸️' : '✅';
902
+ console.log(`${icon} Auto run: ${run.id}`);
903
+ if (executed.length > 0) {
904
+ console.log(` Executed: ${executed.join(' → ')}`);
905
+ }
906
+ console.log(` Outcome: ${outcome}${reason ? ` (${reason})` : ''}`);
907
+ console.log(` Current: ${run.current_node || '(none)'}`);
908
+ console.log(` Status: ${status}`);
909
+ }
843
910
  function findNextNodeForCAL(currentNode, executedNodeId, nodes) {
844
911
  const executedNode = nodes[executedNodeId];
845
912
  if (!executedNode)
846
913
  return null;
847
914
  switch (executedNode.type) {
848
915
  case 'agent_task':
916
+ case 'skill_task':
917
+ case 'shell_task':
849
918
  case 'expression':
850
919
  return typeof executedNode.next === 'string' ? executedNode.next : null;
851
920
  case 'branch':