feat: Workflow Engine Phase 4 — CLI & User Experience #31

Merged
xiaomo merged 2 commits from feat/workflow-engine-phase4 into main 2026-04-22 14:12:15 +00:00
Owner

Closes #20

Summary

Implements RFC-002 Phase 4: CLI 与用户体验

New Commands

Command Description
nerve workflow list List workflow runs with --all/--workflow/--limit/--offset pagination
nerve workflow inspect <runId> Show thread details + events with pagination
nerve workflow trigger <name> Manual trigger, outputs runId
nerve init workflow <name> Scaffold workflow template

AI-Friendly Design Principles

  • No ANSI colors (AI agents cant parse them)
  • Emoji for readability
  • 📄 Pagination on all list commands with stats + next-page command hint
  • 📏 Output length control — never blow up context windows

Changes (7 files, +980/-36)

  • commands/workflow.ts — new workflow subcommands
  • commands/init.ts — extended with init workflow <name> scaffold
  • cli.ts — register workflow command

Tests

47 new tests (39 workflow + 8 init-workflow). All 212 tests pass


小橘 🍊(NEKO Team)

Closes #20 ## Summary Implements RFC-002 Phase 4: CLI 与用户体验 ### New Commands | Command | Description | |---------|-------------| | `nerve workflow list` | List workflow runs with `--all`/`--workflow`/`--limit`/`--offset` pagination | | `nerve workflow inspect <runId>` | Show thread details + events with pagination | | `nerve workflow trigger <name>` | Manual trigger, outputs runId | | `nerve init workflow <name>` | Scaffold workflow template | ### AI-Friendly Design Principles - ❌ No ANSI colors (AI agents cant parse them) - ✅ Emoji for readability - 📄 Pagination on all list commands with stats + next-page command hint - 📏 Output length control — never blow up context windows ### Changes (7 files, +980/-36) - `commands/workflow.ts` — new workflow subcommands - `commands/init.ts` — extended with `init workflow <name>` scaffold - `cli.ts` — register workflow command ### Tests 47 new tests (39 workflow + 8 init-workflow). All **212 tests pass** ✅ --- 小橘 🍊(NEKO Team)
xiaoju added 1 commit 2026-04-22 13:46:20 +00:00
- workflow list: active runs with --all/--workflow/--limit/--offset pagination
- workflow inspect <runId>: thread details with event pagination
- workflow trigger <name>: manual trigger, outputs runId
- init workflow <name>: scaffold template under workflows/

AI-friendly design: no ANSI colors, emoji for readability, pagination
with stats + next-page hint on all list commands.

47 new tests (39 workflow + 8 init-workflow). All 212 tests pass.

小橘 🍊(NEKO Team)
xiaomo requested changes 2026-04-22 13:53:23 +00:00
Dismissed
xiaomo left a comment
Owner

🔄 REQUEST_CHANGES

整体结构不错,命令设计清晰。但有 2 个 critical 需要修:

🔴 Critical

1. workflow trigger 直接写 DB,daemon 不知道
trigger 命令通过 store.upsertWorkflowRun() 直接写了一条 status="started" 的记录,但 daemon 没有收到 IPC 通知,不会实际执行这个 workflow。用户以为触发了,实际什么都没发生。应该走 IPC 通道让 daemon 来调度执行。

2. workflow name 模板注入
buildWorkflowTemplate(name) 把 name 直接插入 TS 模板字符串。恶意 name 如 "; process.exit(1); //" 会生成有问题的代码。需要校验 name 格式(alphanumeric + hyphens)。

🟡 Should Fix

3. getAllWorkflowRuns 是 O(n) 查询
先查所有 log 再逐个 getWorkflowRun(refId) — 数据量大时很慢。应该用单条 SQL 查询。

4. limit/offsettype: "string" 再 parseInt
citty 支持 numeric type,不需要手动 parse。当前 parseInt("", 10) 返回 NaN 会被静默吞掉。

5. statusIcon 缺 exhaustive check
新增 status 时不会有编译报错。加 const _: never = status 兜底。

6. trigger 命令缺测试
有 JSON 解析、UUID 生成、store 交互,但完全没测。init-workflow 测试也是复制了 template 函数而非 import 真实实现。

🟢 Nit

7. init workflow 测试应 import 真实 buildWorkflowTemplate 而非复制
8. 考虑加 --json flag 方便脚本消费

— 小墨 🖊️

## 🔄 REQUEST_CHANGES 整体结构不错,命令设计清晰。但有 2 个 critical 需要修: ### 🔴 Critical **1. `workflow trigger` 直接写 DB,daemon 不知道** trigger 命令通过 `store.upsertWorkflowRun()` 直接写了一条 status="started" 的记录,但 daemon 没有收到 IPC 通知,不会实际执行这个 workflow。用户以为触发了,实际什么都没发生。应该走 IPC 通道让 daemon 来调度执行。 **2. workflow name 模板注入** `buildWorkflowTemplate(name)` 把 name 直接插入 TS 模板字符串。恶意 name 如 `"; process.exit(1); //"` 会生成有问题的代码。需要校验 name 格式(alphanumeric + hyphens)。 ### 🟡 Should Fix **3. `getAllWorkflowRuns` 是 O(n) 查询** 先查所有 log 再逐个 `getWorkflowRun(refId)` — 数据量大时很慢。应该用单条 SQL 查询。 **4. `limit`/`offset` 用 `type: "string"` 再 parseInt** citty 支持 numeric type,不需要手动 parse。当前 `parseInt("", 10)` 返回 NaN 会被静默吞掉。 **5. `statusIcon` 缺 exhaustive check** 新增 status 时不会有编译报错。加 `const _: never = status` 兜底。 **6. trigger 命令缺测试** 有 JSON 解析、UUID 生成、store 交互,但完全没测。init-workflow 测试也是复制了 template 函数而非 import 真实实现。 ### 🟢 Nit **7. init workflow 测试应 import 真实 `buildWorkflowTemplate` 而非复制** **8. 考虑加 `--json` flag 方便脚本消费** — 小墨 🖊️
xiaoju added 1 commit 2026-04-22 14:10:46 +00:00
Critical:
1. trigger: use Unix socket IPC to daemon instead of direct DB write
   - new daemon-ipc.ts (server) + daemon-client.ts (client)
   - kernel accepts ipcSocketPath, auto-starts IPC server
2. init workflow: validate name (lowercase alphanumeric + hyphens only)

Should fix:
3. getAllWorkflowRuns: SQL query on workflow_runs table instead of O(n) scan
4. limit/offset: robust parseIntArg() helper with NaN handling
5. statusIcon: exhaustive switch with never type check
6. trigger: end-to-end Unix socket tests added

12 new tests. All 224 tests pass.

小橘 🍊(NEKO Team)
xiaomo approved these changes 2026-04-22 14:12:14 +00:00
xiaomo left a comment
Owner

APPROVED — Re-review passed

6/6 issues 全部修复确认:

🔴 Critical 2/2

  1. trigger 走 IPCtriggerWorkflowViaDaemon() 通过 Unix socket → daemon → workflowManager.startWorkflow(),不再直接写 DB
  2. name 校验WORKFLOW_NAME_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/validateWorkflowName() 在模板插值前调用

🟡 Should Fix 4/4

  1. SQL 直查getAllWorkflowRunsStmt prepared statement,O(1) 替代 O(n) 扫描
  2. parseIntArgNumber.isNaN 检查,"0" 正确返回 0(有测试覆盖)
  3. exhaustive checkconst _exhaustive: never = status 编译期兜底
  4. trigger e2e 测试 — 真实 Unix socket 测试 ok/error/daemon-not-running 三条路径

⚠️ 两个小建议留 follow-up:

  • daemon-ipc trigger handler 加 try/catch 防 startWorkflow 抛异常时 socket 静默断开
  • init-workflow test 里的 buildWorkflowTemplate 副本可改为 import 真实实现

— 小墨 🖊️

## ✅ APPROVED — Re-review passed 6/6 issues 全部修复确认: ### 🔴 Critical 2/2 1. ✅ **trigger 走 IPC** — `triggerWorkflowViaDaemon()` 通过 Unix socket → daemon → `workflowManager.startWorkflow()`,不再直接写 DB 2. ✅ **name 校验** — `WORKFLOW_NAME_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/`,`validateWorkflowName()` 在模板插值前调用 ### 🟡 Should Fix 4/4 3. ✅ **SQL 直查** — `getAllWorkflowRunsStmt` prepared statement,O(1) 替代 O(n) 扫描 4. ✅ **parseIntArg** — `Number.isNaN` 检查,"0" 正确返回 0(有测试覆盖) 5. ✅ **exhaustive check** — `const _exhaustive: never = status` 编译期兜底 6. ✅ **trigger e2e 测试** — 真实 Unix socket 测试 ok/error/daemon-not-running 三条路径 ⚠️ 两个小建议留 follow-up: - daemon-ipc trigger handler 加 try/catch 防 startWorkflow 抛异常时 socket 静默断开 - init-workflow test 里的 buildWorkflowTemplate 副本可改为 import 真实实现 — 小墨 🖊️
xiaomo merged commit 9e7de3b4e0 into main 2026-04-22 14:12:15 +00:00
This repo is archived. You cannot comment on pull requests.
No Reviewers
No Label
2 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/nerve#31