@yanglaofish/fishtools 0.1.4 → 0.2.0

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.
Files changed (77) hide show
  1. package/README.md +46 -18
  2. package/manual/LICENSE +21 -0
  3. package/manual/README.md +173 -0
  4. package/manual/THIRD_PARTY_NOTICES.md +32 -0
  5. package/manual/docs/examples/action-plugin/LICENSE +21 -0
  6. package/manual/docs/examples/action-plugin/README.md +38 -0
  7. package/manual/docs/examples/action-plugin/index.js +18 -0
  8. package/manual/docs/examples/action-plugin/input.json +1 -0
  9. package/manual/docs/examples/action-plugin/package.json +9 -0
  10. package/manual/docs/plans/2026-10-10-workbench-ui.md +27 -0
  11. package/{docs → manual/docs}/plugin-development.md +151 -19
  12. package/{docs → manual/docs}/releases.md +13 -1
  13. package/manual/docs/roadmap.md +85 -0
  14. package/manual/docs/superpowers/plans/2026-10-09-workflow-mvp.md +115 -0
  15. package/manual/docs/superpowers/plans/2026-10-10-cordis-services.md +34 -0
  16. package/manual/docs/superpowers/plans/2026-10-10-fst-terminal.md +33 -0
  17. package/manual/docs/superpowers/plans/2026-10-10-portable-plugin-contract.md +35 -0
  18. package/manual/docs/superpowers/plans/2026-10-11-control-observation.md +77 -0
  19. package/manual/docs/superpowers/specs/2026-10-09-workflow-cli-design.md +377 -0
  20. package/manual/docs/superpowers/specs/2026-10-10-cordis-services-design.md +88 -0
  21. package/manual/docs/superpowers/specs/2026-10-10-portable-plugin-contract.md +31 -0
  22. package/manual/docs/superpowers/specs/2026-10-10-run-logs.md +28 -0
  23. package/manual/docs/superpowers/specs/2026-10-11-control-observation.md +37 -0
  24. package/{docs → manual/docs}/verification.md +14 -1
  25. package/manual/examples/service-plugins/README.md +20 -0
  26. package/manual/examples/service-plugins/consumer/LICENSE +21 -0
  27. package/manual/examples/service-plugins/consumer/index.js +14 -0
  28. package/manual/examples/service-plugins/consumer/package.json +1 -0
  29. package/manual/examples/service-plugins/provider/LICENSE +21 -0
  30. package/manual/examples/service-plugins/provider/index.js +19 -0
  31. package/manual/examples/service-plugins/provider/package.json +1 -0
  32. package/manual/packages/core/LICENSE +21 -0
  33. package/manual/packages/core/src/host.js +122 -0
  34. package/manual/packages/sdk/LICENSE +21 -0
  35. package/manual/packages/sdk/index.js +14 -0
  36. package/manual/packages/sdk/package.json +1 -0
  37. package/manual/plugins/environment/LICENSE +21 -0
  38. package/manual/plugins/environment/index.js +92 -0
  39. package/manual/plugins/environment/package.json +1 -0
  40. package/manual/plugins/examples/LICENSE +21 -0
  41. package/manual/plugins/examples/index.js +23 -0
  42. package/manual/plugins/examples/package.json +1 -0
  43. package/manual/plugins/examples/scripts/echo.py +5 -0
  44. package/manual/tests/application.test.js +45 -0
  45. package/node_modules/@mytools/core/bin/fst.js +12 -4
  46. package/node_modules/@mytools/core/src/application.js +9 -4
  47. package/node_modules/@mytools/core/src/cli-run.js +6 -0
  48. package/node_modules/@mytools/core/src/contracts.js +15 -2
  49. package/node_modules/@mytools/core/src/control.js +63 -0
  50. package/node_modules/@mytools/core/src/documentation.js +65 -0
  51. package/node_modules/@mytools/core/src/engine.js +80 -26
  52. package/node_modules/@mytools/core/src/host.js +13 -2
  53. package/node_modules/@mytools/core/src/markdown-log.js +8 -5
  54. package/node_modules/@mytools/core/src/process.js +35 -14
  55. package/node_modules/@mytools/core/src/project.js +1 -1
  56. package/node_modules/@mytools/core/src/run-logs.js +1 -1
  57. package/node_modules/@mytools/core/src/terminal/conditions.js +32 -0
  58. package/node_modules/@mytools/core/src/terminal/log-viewer.js +7 -8
  59. package/node_modules/@mytools/core/src/terminal/model.js +32 -3
  60. package/node_modules/@mytools/core/src/terminal/presentation.js +7 -9
  61. package/node_modules/@mytools/core/src/terminal/run-viewer.js +86 -0
  62. package/node_modules/@mytools/core/src/terminal/session.js +109 -22
  63. package/node_modules/@mytools/core/src/terminal/theme.js +28 -0
  64. package/node_modules/@mytools/core/src/terminal/view.js +74 -19
  65. package/node_modules/@mytools/core/src/validation.js +15 -4
  66. package/node_modules/@mytools/core/src/version.js +1 -1
  67. package/node_modules/@mytools/core/src/workflows.js +30 -19
  68. package/node_modules/@mytools/core/templates/control-demo.yaml +47 -0
  69. package/node_modules/@mytools/environment/index.js +14 -2
  70. package/node_modules/@mytools/pack/index.js +2 -0
  71. package/node_modules/@mytools/web/public/THIRD_PARTY_NOTICES.txt +215 -216
  72. package/node_modules/@mytools/web/public/assets/index-DT2B4tMV.js +70 -0
  73. package/node_modules/@mytools/web/public/assets/{index-BeV6IqTW.css → index-vuZvrUTT.css} +1 -1
  74. package/node_modules/@mytools/web/public/index.html +2 -2
  75. package/package.json +2 -2
  76. package/node_modules/@mytools/web/public/assets/index-TgsBnZgG.js +0 -70
  77. /package/{docs → manual/docs}/deployment.md +0 -0
@@ -1,6 +1,33 @@
1
1
  # 插件开发
2
2
 
3
- 本文是 Fishtools 首版的公共插件接入规范,面向第三方开发者。普通动作插件与官方环境检查插件使用同一套契约;不要求依赖 Web 前端,也不要求开发者直接操作 Cordis。
3
+ 本文是 Fishtools 的公共插件接入规范,面向第三方开发者。普通动作插件与官方环境检查插件使用同一套契约;不要求依赖 Web 前端,也不要求开发者直接操作 Cordis。
4
+
5
+ ## 从已安装的工具查阅规范
6
+
7
+ 完整 npm 与便携发行包随附离线资料,包含本文、控制流规范、服务示例和可安装的[零依赖动作插件](examples/action-plugin/README.md)。无需克隆源码仓库:
8
+
9
+ ```sh
10
+ fst docs
11
+ fst docs plugins
12
+ fst docs control
13
+ fst docs plugins --path
14
+ fst docs --export ./fishtools-manual
15
+ ```
16
+
17
+ `fst docs <主题>` 输出正文,`--path` 输出本地路径;`--export` 导出全部资料到新目录,已有目标会拒绝覆盖。资料按当前安装版本定位,不依赖当前工作目录,不启动插件或服务。TUI 中通过 `/docs` 选择主题,在内置阅读器查看。
18
+
19
+ 导出目录保留相对链接,可离线浏览规范与示例。`plugins/`、`packages/`、`tests/` 中附带的源码仅供阅读,保留其 LICENSE;它们不是另一份可执行宿主或完整源码工作区。实际可安装示例位于 `docs/examples/action-plugin` 和 `examples/service-plugins`。内部 SDK 不承诺已作为独立公共 npm 包发布,首次开发可直接使用零依赖示例。
20
+
21
+ ## 0.2.0:条件控制与运行观察
22
+
23
+ 本版本包含条件分支、并行组、提前结束和运行观察接口。以下说明对应 0.2.0 源码实现;执行模型见 [控制流规范](superpowers/specs/2026-10-11-control-observation.md),发布与验证范围以 [版本记录](releases.md) 和 [验收记录](verification.md) 为准。
24
+
25
+ - 可编排动作必须声明输入与输出 schema。正常返回且输出校验通过即“执行成功”,不强制作者再写成功判定。
26
+ - 检测完成与检测通过分开:检查类能力返回 `ok/passed/count/exists` 等结构化业务字段;异常代表执行失败。工作流决定结果不符合要求时分支、跳过还是提前结束。
27
+ - 动作可以提供 `conditions` 判定预设,例如 `conditions: {passed: {title:'检查通过', path:'ok', op:'eq', value:true}}`,`path` 相对于输出;无需提供可执行判定函数。
28
+ - 工作流使用条件分支、并行组、提前结束节点;插件不自行操作编排器的流程指针。并行调用必须正确响应 `signal`,共享文件/连接的并发安全由插件实现负责。
29
+ - `runProcess` 提供实时 stdout/stderr,使用 `await log(message,data)` 记录业务日志。运行面板按步骤调用路径区分输出,用户可切换总览/详情/日志;退出观察页面不等于取消任务。
30
+ - 保持旧环境 `check` 动作的失败语义,新增报告动作供条件编排使用,避免升级后旧流程意外继续运行。
4
31
 
5
32
  ## 开发约束与实际校验
6
33
 
@@ -9,18 +36,21 @@
9
36
  | 约束 | 开发者要求 | 当前宿主检查 |
10
37
  | --- | --- | --- |
11
38
  | 标识与版本 | `id` 必须等于 npm 包名,`version` 必须等于包版本并使用 semver;升级时保持已有动作标识稳定 | 检查 ID 非空、重复;检查 SDK 和已声明插件依赖的版本兼容性;尚未自动比对包名/包版本 |
12
- | 能力元数据 | 每个公开动作必须提供清楚的 `title`、`description`、`input`、`output`、`run` | 检查 `run` 是函数;标题、描述和 schema 是否完整仍由作者负责 |
13
- | 输入输出 | 使用 JSON Schema 声明类型、必填项、默认值和字段说明;输出必须是明确的 JSON 数据 | 已声明的 schema 经 Ajv 验证;返回值经过 JSON 序列化边界 |
39
+ | 能力元数据 | 每个公开动作必须提供清楚的 `title`、`description`、`input`、`output`、`run` | 检查 `run` 是函数;编排前检查 input/output schema;标题和描述的质量由作者负责 |
40
+ | 输入输出 | 显式提供有效的 JSON Schema,推荐对象形式声明类型、必填项、默认值和字段说明;无参数或无输出也要声明空对象 schema | 编排前校验 schema 声明,调用时用 Ajv 验证实际输入输出;返回值经过 JSON 序列化边界 |
41
+ | 判定预设 | `conditions` 提供标题、相对输出路径、比较符和值;不提供可执行判定函数 | 加载时检查格式、比较符、危险路径及已声明的输出字段 |
14
42
  | 配置 | 将机器地址、解释器位置等放入配置或动作参数;`defaultConfig` 只包含可公开默认值 | 加载时验证已声明的配置 schema;不自动识别敏感配置 |
15
43
  | 依赖 | npm 库写入包的 `dependencies`,插件依赖写入插件定义的 `dependencies`;不得依赖开发机偶然安装的库 | 加载时检查插件依赖;打包收集生产 npm 依赖与工作流依赖闭包 |
16
44
  | 子进程 | 必须使用上下文 `runProcess`,参数逐项传入数组,传递 `signal`;非零退出必须按业务处理 | 使用该接口时提供超时、取消、输出上限和进程树回收;无法约束插件绕过接口直接启动的进程 |
17
45
  | 脚本与文件 | 自带资源必须位于包内并进入发布文件;用 `resourceDir` 找资源、`outputDir` 写结果,不能写死开发机路径 | 打包按 npm 发布文件规则收集资源;不会静态检查所有路径或保证脚本在目标机可运行 |
18
- | 环境前提 | 必需 Python、pip 包、驱动或设备缺失时明确失败;环境检查插件不自动安装或修复 | 官方环境检查动作实现检查失败;第三方业务插件需声明自己的环境要求 |
46
+ | 环境前提 | 业务动作无法执行时应抛错;报告动作可以返回未通过的结构化结果,由工作流决定后续处理 | 官方 `check` 未通过会抛错,`report` 返回 `ok:false`;均不自动安装或修复 |
19
47
  | 可取消与副作用 | 响应 `signal`;重复执行、覆盖文件、网络请求等副作用应在说明中写清 | 调用前后检查取消信号;同步阻塞代码无法被抢占,不提供自动回滚 |
20
48
  | 日志与许可 | 使用 `log`,不得记录密码/令牌;保留所有适用的 LICENSE/NOTICE | 记录结构化日志、保留发布文件中的许可证;不自动脱敏或审计第三方许可证 |
21
49
 
22
50
  JSON 序列化可能丢弃对象中的 `undefined`、函数或 Symbol,并将非有限数字转为 `null`;不能把“能够序列化”当作完整的类型保证。请给输出写明确的 schema,不返回循环引用、BigInt、函数或依赖隐式转换的对象。
23
51
 
52
+ 无参数或无输出时,分别使用 `{type:'object', properties:{}, additionalProperties:false}`,动作返回 `{}`。JSON Schema 的布尔形式也受支持:`true` 接受任意值,`false` 拒绝所有值;为了生成字段表单与输出选择器,推荐明确声明对象和字段。缺省、`null`、数组、字符串和数值都不能代替 schema 声明。原有动作/子工作流的 `schemaVersion: 1` 格式保留;旧插件若要参与编排,需要补齐有效的 input/output 声明。正常返回且输出校验通过即执行成功,不要求返回额外的 `success:true`。
53
+
24
54
  ## 插件定义字段
25
55
 
26
56
  | 字段 | 发布要求与语义 |
@@ -79,14 +109,14 @@ export default {
79
109
  };
80
110
  ```
81
111
 
82
- 包名/版本应与 `id`/`version` 一致。能力标识为 `my-flow-plugin:greet`,用户看到中文标题、描述、表单和输出字段。仓库内可使用 `@mytools/sdk` 的 `definePlugin()` 和 `FlowError`。
112
+ 包名/版本应与 `id`/`version` 一致。能力标识为 `my-flow-plugin:greet`,用户看到中文标题、描述、表单和输出字段。仓库内部可使用 `@mytools/sdk` 的 `definePlugin()` 和 `FlowError`;独立插件不能假设全局 Fishtools 安装会使这个内部包自动可解析。首次开发优先复制[零依赖完整示例](examples/action-plugin/README.md)。
83
113
 
84
114
  ## 安装与依赖
85
115
 
86
116
  ```sh
87
- npm run fst -- --project examples plugin add /absolute/path/to/my-flow-plugin
88
- npm run fst -- --project examples plugin list
89
- npm run fst -- --project examples plugin remove my-flow-plugin
117
+ fst plugin add /absolute/path/to/my-flow-plugin
118
+ fst plugin list
119
+ fst plugin remove my-flow-plugin
90
120
  ```
91
121
 
92
122
  也支持 npm 包标识或本地 `.tgz`;Web“插件管理”提供相同入口。本地路径以服务器所在机器为准。
@@ -108,25 +138,32 @@ npm run fst -- --project examples plugin remove my-flow-plugin
108
138
  | `resourceDir` | 插件包目录,用于定位脚本 |
109
139
  | `getService(name)` | 获取本插件 runtime.inject/provides 声明的已就绪服务;未声明或不可用时抛错 |
110
140
  | `environments` | 按声明和来源选择解析的环境;包含解释器路径,随包环境另有资源根目录 |
111
- | `runProcess(file,args,options)` | 通用进程调用 |
112
- | `log(message,data)` | 写结构化日志,返回 Promise |
141
+ | `runProcess(file,args,options)` | 通用进程调用,自动关联当前日志与取消信号 |
142
+ | `log(message,data,meta?)` | 写结构化日志并返回落盘 Promise;常规调用保持 `log(message,data)` |
113
143
 
114
144
  返回值必须可 JSON 序列化,输入输出经 Ajv 校验。插件在宿主进程中执行,属于可信代码;同步阻塞代码不能被取消信号抢占。
115
145
 
116
- `runProcess` 默认无 Shell,参数用数组。支持 `cwd`、`env`、`signal`、`timeout`(30 秒)、`maxBuffer`(4 MiB)。普通非零退出返回 `{exitCode,stdout,stderr}`,动作应自行抛出业务错误;缺失程序、超时、取消、输出超限抛错。不要把密码或令牌写入日志。
146
+ `runProcess` 默认无 Shell,参数用数组。支持 `cwd`、`env`、`signal`、`timeout`(默认 30 秒)、`maxBuffer`(stdout/stderr 各默认 4 MiB)和可选的 `onOutput({stream,message})`。普通非零退出返回 `{exitCode,stdout,stderr}`,动作应自行决定是否抛出业务错误;缺失程序、超时、取消、输出超限抛错,并等待进程树回收。不要把密码或令牌写入日志。
147
+
148
+ 通过动作上下文调用时,stdout/stderr 在子进程执行期间自动产生 `type:'log'` 事件,`stream` 为 `stdout` 或 `stderr`,工作流事件保留 `stepId` 和 `callPath`。例如同一动作分别位于 `main/group/left`、`main/group/right`,日志按各自调用归属显示。写入 stderr 本身不会把运行改成失败。
149
+
150
+ 输出按 UTF-8 解码,跨数据块的中文和 emoji 不会被拆坏;回调消息是流数据块,不保证一条消息就是一整行。可选 `onOutput` 在自动日志落盘后执行,不需要再手动 `log` 同一份输出。回调可以返回 Promise,`runProcess` 会等待;回调抛错或拒绝会终止受管进程并向调用方报告错误。完整 stdout/stderr 返回缓冲仍受输出上限约束。不要启动未等待的回调后台任务。
151
+
152
+ 宿主使用 `log(message, undefined, {stream})` 写入进程事件。插件的业务日志继续使用 `await log('检查完成', {count:3})`;调用路径由执行器固定,不能用元数据覆盖步骤归属。宿主同时绑定当前运行的取消信号,显式传入额外 `signal` 时任一信号取消都会终止进程。
117
153
 
118
154
  ### 用日志定位插件错误
119
155
 
120
156
  每次通过应用运行工作流或插件命令,都在 `.flow/runs/<runId>/` 写入 `run.md`、`events.jsonl` 与 `result.json`(指定 `--output` 时使用该目录;便携版写入可写工作区)。
121
157
 
122
- - **优先打开 `run.md` 阅读**:按时间顺序展示步骤、作者日志、执行结果、失败原因、错误详情和调用栈,结束后附最终状态。它在执行过程中逐条追加,尚未结束也能用 Markdown 阅读器或普通文本编辑器打开;TUI 运行结束显示此文件路径。调用栈使用原始换行,不需要读 JSON 转义。
123
- - **TUI 直接阅读**:输入 `/logs`,选择历史运行后在终端内查看 Markdown,方向键滚动、PageUp/PageDown 翻页、Home/End 跳转,Esc 返回。重启后读取磁盘历史;旧版本只有 result.json 时从事件快照生成阅读内容。
158
+ - **运行中直接观察**:TUI 运行工作流后打开观察面板,或通过 `/runs` 选择当前会话的运行;Web 使用“查看运行”。两者提供步骤总览、输入输出和实时日志,按调用路径查看同一动作的不同调用。
159
+ - **历史日志直接阅读**:TUI `/logs` 选择记录后在终端内阅读 Markdown;方向键或鼠标滚轮滚动,PageUp/PageDown 翻页,Home/End 跳转,Esc、Enter 或 q 返回。重启后读取磁盘历史;旧版本只有 result.json 时从事件快照生成内容。
160
+ - **导出阅读内容**:`run.md` 按时间顺序展示步骤、作者日志、stdout/stderr、执行结果、失败原因、错误详情和调用栈,结束后附最终状态。它在执行过程中逐条追加,也可使用外部 Markdown 阅读器查看。调用栈保留原始换行。
124
161
 
125
- - `events.jsonl` 按顺序记录启动、步骤成功/失败、作者的 `log` 和运行结束。失败事件包含插件 ID、动作或命令、错误码、message,以及 `error` 中的 stack 和 cause 链。工作流还有 stepId、callPath、耗时。
126
- - `result.json` 保存最终状态、输出、错误和完整事件快照。单步输出可在 `events` 的 `step.succeeded.output` 中查看,即使后续步骤失败也保留;命令成功结果在顶层 output。逐行事件文件不重复保存业务输出。
162
+ - `events.jsonl` 按顺序记录启动、步骤成功/失败/跳过/停止、作者日志、进程流输出和运行结束。`step.started` 含解析后的 input;失败事件包含插件 ID、动作或命令、错误码、message,以及 `error` 中的 stack 和 cause 链。工作流还有 stepId、callPath、耗时。
163
+ - `result.json` 保存最终状态、输出、错误和完整事件快照。正常提前结束为 `status:'stopped'`,保存字符串 reason,不生成 error。单步输出可在 `events` 的 `step.succeeded.output` 查看,即使后续失败或停止也保留;逐行事件文件不重复保存业务输出。
127
164
  - 例如调用不存在的 Python 时,运行失败,message 含具体插件及“未找到程序”,错误链包含 `ENOENT` 和 `details.executable`。无需先运行环境检查插件才能捕获此错误。
128
- - Python 脚本异常或依赖缺失通常通过非零退出码及 stderr 报告。作者必须检查返回值并抛错,例如 `throw new FlowError('Python 脚本失败', {code:'PYTHON_FAILED', details:{exitCode:r.exitCode, stderr:r.stderr}})`;不要捕获后返回成功。
129
- - 插件可 `await log('正在检查 Python', {phase:'python-check'})` 补充业务阶段。`console.log`、自行启动的子进程和未 await 的后台任务不会自动进入这套日志;受管进程的 stdout/stderr 也不会自动全量写入。
165
+ - Python 脚本异常或依赖缺失通常通过非零退出码及 stderr 报告。作者必须检查返回值并抛错,例如 `throw Object.assign(new Error('Python 脚本失败'), {code:'PYTHON_FAILED', details:{exitCode:r.exitCode, stderr:r.stderr}})`;不要捕获后返回成功。此写法无需内部 SDK。
166
+ - 插件可 `await log('正在检查 Python', {phase:'python-check'})` 补充业务阶段。插件自身的 `console.log`、自行启动的子进程和未 await 的后台任务不会自动进入这套日志;动作上下文 `runProcess` 的 stdout/stderr 会实时写入。
130
167
  - 核心不自动记录命令参数、环境变量和插件配置。错误消息、stderr、调用栈、作者 log 和返回结果仍可能包含敏感内容;作者应在返回或抛错前按业务脱敏。
131
168
 
132
169
  定位顺序:按 runId 打开 run.md → 查看失败插件及步骤 → 查看原始错误码与调用栈 → 结合之前的日志和成功步骤输出复现。JSON 文件是给程序查询与界面使用的结构化记录,不要求用户通过 JSON 阅读日志。此处是运行诊断;插件加载/初始化失败发生在运行创建之前,目前由启动错误报告,不会凭空产生工作流运行目录。
@@ -139,12 +176,105 @@ TUI `/logs` → “设置日志保留次数”可指定整个项目合计保留
139
176
  {"logs":{"keepRuns":10}}
140
177
  ```
141
178
 
142
- 未配置或设为 null 时不自动清理,0 和负数无效。保存保留策略时立即清理,之后每次运行结束自动执行,按结束时间从新到旧保留。正在执行或尚未写完日志的运行受到保护。
179
+ 未配置或设为 null 时不自动清理,0 和负数无效。保存保留策略时立即清理,之后每次运行结束自动执行,按结束时间从新到旧保留。成功、失败、取消及正常停止都计入已结束运行;正在执行或尚未写完日志的运行受到保护。
143
180
 
144
181
  只移除过期运行的 run.md、events.jsonl 和 result.json;不递归删除运行目录,不删除插件生成的业务文件,不跟随日志目录或文件的符号链接。没有其他文件的空目录可移除。被清理的日志不再进入历史列表;业务文件仍可在原输出目录找到。自动清理失败会写入本次运行日志,不把业务成功改成失败。
145
182
 
146
183
  记录按项目目录标识归属,共用 `--output` 时互不清理。无归属字段的旧记录仅在本项目默认 `.flow/runs` 内兼容读取和清理,共享输出目录中的旧记录不会自动认领。应用 API 的 `await run.done` 返回完成结果快照;并发任务的调用方应使用该快照,避免依赖可能已按保留策略移除的历史记录。
147
184
 
185
+ ## 工作流条件与控制节点
186
+
187
+ `schemaVersion: 1` 保留顺序列表:同一层从上到下执行,每个步骤必须恰有一个执行目标。TUI 和 Web 都通过表单生成这些结构,不要求用户手写 YAML。
188
+
189
+ | 目标 | 结构与行为 |
190
+ | --- | --- |
191
+ | 动作 | `{action:'插件ID:动作', with:{...}}`,调用插件并校验输入输出 |
192
+ | 子工作流 | `{workflow:'./child.yaml', with:{...}}`,调用工作流目录中的子流程 |
193
+ | 条件分支 | `{branch:{condition, then:[步骤], else:[步骤]}}`,只执行命中的一侧;else 可省略 |
194
+ | 并行组 | `{parallel:{steps:[步骤], concurrency:2}}`,并发执行独立子步骤;并发数为 1–32 的整数,默认 4 |
195
+ | 提前结束 | `{stop:{reason:'环境不满足'}}`,正常结束整个顶层运行;原因必须为非空字符串 |
196
+
197
+ 任一步骤可以增加 `when`。条件不成立时记 `step.skipped`,不调用插件,也不生成该步骤输出。未选择的分支同样标记跳过。节点可以嵌套,同一工作流内的步骤 ID 必须唯一,不能在不同分支重复使用。
198
+
199
+ ### 条件与判定预设
200
+
201
+ 比较条件例如 `{left:{$ref:'steps.check.output.ok'}, op:'eq', right:true}`。支持 `eq/ne`(严格类型的相等/不等)、`gt/gte/lt/lte`(数值比较)、`contains`(字符串包含或数组包含同类型值)、`exists`(字段存在,不需要 right)。组合条件使用 `{all:[条件]}`、`{any:[条件]}`、`{not:条件}`,不执行 JavaScript 表达式。
202
+
203
+ 已声明字段在本次运行中缺失时,`exists` 为 false,其他比较也为 false。前向引用、并行兄弟引用、危险字段和静态可知不存在的字段会在执行前拒绝;不能用 `exists` 绕过非法引用。
204
+
205
+ 插件可以给动作添加可选预设:
206
+
207
+ ```js
208
+ conditions: {
209
+ passed: {title:'检查通过', path:'ok', op:'eq', value:true},
210
+ }
211
+ ```
212
+
213
+ `path` 是相对本动作输出的字段路径,必须能够从 output schema 找到。界面选择前序动作的预设后,将其展开为普通条件,例如 `steps.check.output.ok`。预设不改变动作是否执行成功,也不取代实际输出 schema 校验;普通文本转换动作无需额外声明“执行成功”预设。
214
+
215
+ ### 引用范围、并行失败与停止
216
+
217
+ 嵌套序列可以读取外层已完成步骤和本层前序步骤;并行兄弟不能互相读取结果。分支和并行组只将实际完成的直接子步骤汇总为 `子步骤 ID → 输出`,组外通过 `steps.group.output.child.field` 读取。嵌套组可以继续沿该结构读取;不能从外层直接引用组内子步骤的裸 ID。
218
+
219
+ 跳过或未选中的步骤没有输出。普通参数绑定读到缺失输出会明确失败,应先用条件判断、分支或提前结束避免无效读取。打包依赖闭包包含所有分支和并行组中引用的插件及子工作流,不只包含本次命中的路径。
220
+
221
+ 并行组出现首个失败或提前结束时,停止调度未开始的步骤、向已启动兄弟发出取消信号,并等待它们清理结束。插件应响应 `signal`;共享文件或连接的并发安全由插件负责。已经发生的业务副作用不会自动回滚。
222
+
223
+ `stop` 从嵌套分支、并行组或子工作流传播到整个运行,保留已完成步骤的事件和输出,记录 `step.stopped`、`workflow.stopped`、`run.stopped`。最终为 `stopped`,有 reason、无 error;不生成正常完成时的汇总输出。用户主动取消为 `cancelled`,执行异常为 `failed`。CLI 的 `run` 和 `command` 遇到正常停止返回退出码 0,并打印 `{status:'stopped', reason:'...'}`。
224
+
225
+ ### 环境 report 与 check
226
+
227
+ `@mytools/environment:check` 保持原语义:缺少要求的解释器、包或设备时抛出 `ENVIRONMENT_FAILED`,旧流程因此停止执行。`@mytools/environment:report` 使用同样的检查,但未通过时正常返回包含 `ok:false`、system、checks 的报告;它提供 passed 预设,由工作流选择处理方式。两者都不会安装依赖或修复环境,也都会传播取消。
228
+
229
+ 例如先报告,再在环境不满足时正常结束:
230
+
231
+ ```yaml
232
+ schemaVersion: 1
233
+ id: guarded-check
234
+ inputs:
235
+ type: object
236
+ required: [executable]
237
+ properties:
238
+ executable: {type: string, title: Python 解释器路径}
239
+ steps:
240
+ - id: inspect
241
+ action: '@mytools/environment:report'
242
+ with:
243
+ python:
244
+ executable: {$ref: inputs.executable}
245
+ - id: finish-if-unavailable
246
+ when:
247
+ left: {$ref: steps.inspect.output.ok}
248
+ op: eq
249
+ right: false
250
+ stop:
251
+ reason: 环境未满足要求,请查看检查明细
252
+ outputs:
253
+ report: {$ref: steps.inspect.output}
254
+ ```
255
+
256
+ 报告通过时,stop 节点跳过并返回汇总报告;不通过时,最终状态为 stopped,可从 inspect 的步骤输出阅读检查明细。TUI 命令 `/env.check`、`/env.report` 分别对应这两个动作。
257
+
258
+ ## TUI 与 Web 运行观察
259
+
260
+ TUI `/add` 选择动作、子工作流、条件分支、并行组或提前结束;`/steps` 可进入分支/并行组编辑内部步骤,设置执行条件、并发数和结束原因。条件表单支持选择字段或预设,也支持且、或、取反。`/save` 保存后,Web 可继续编辑同一份工作流。
261
+
262
+ TUI `/run` 启动工作流后打开观察面板,`/runs` 可重新选择当前会话的运行(包括已完成运行)。跨重启历史通过 `/logs` 阅读。
263
+
264
+ | 面板键位 | 行为 |
265
+ | --- | --- |
266
+ | `1` / `2` / `3` | 步骤总览 / 输入输出 / 实时日志 |
267
+ | `[` / `]` | 选择上一个 / 下一个步骤调用 |
268
+ | `a` | 切换本步骤日志与全部日志 |
269
+ | ↑↓、鼠标滚轮、PageUp/PageDown、Home | 滚动或跳到开头;手动滚动暂停日志跟随 |
270
+ | End / `f` | End 跳至尾部并恢复跟随;f 切换跟随状态 |
271
+ | Esc、q、Enter、Ctrl+C | 关闭观察面板,任务继续运行 |
272
+ | `x`,再按 `y` | 确认取消整个运行;确认提示中其他键返回 |
273
+
274
+ 关闭观察面板不等于退出应用。主提示符 `/exit` 或 Ctrl+C 遇到后台运行时,会提示退出将取消这些任务,默认不退出。普通参数输入和插件命令忙碌页仍使用原有 Ctrl+C 取消行为。鼠标模式只在阅读面板中启用,关闭后恢复。
275
+
276
+ Web 通过“添加步骤 → 流程控制”添加分支、并行组或提前结束,点击节点填写条件、并发数、原因及内部步骤;普通步骤也可设置执行条件。保存后点击“运行工作流”,运行面板提供“步骤总览 / 输入输出 / 实时日志”和调用路径筛选。向上滚动日志会暂停跟随,可以点击“恢复自动跟随”继续查看尾部。关闭观察窗口后任务继续,顶部“查看运行”可重新打开;“停止运行”发送取消请求。只读运行包允许运行和观察,不允许修改流程。
277
+
148
278
  ## Python 脚本
149
279
 
150
280
  JS 负责元数据和参数适配,业务可用 Python:
@@ -154,12 +284,14 @@ import path from 'node:path';
154
284
 
155
285
  async function run({executable, text}, {resourceDir, runProcess, signal}) {
156
286
  const result = await runProcess(executable,
157
- [path.join(resourceDir, 'scripts', 'task.py'), text], {signal});
287
+ ['-u', path.join(resourceDir, 'scripts', 'task.py'), text], {signal});
158
288
  if (result.exitCode !== 0) throw new Error(result.stderr);
159
289
  return JSON.parse(result.stdout);
160
290
  }
161
291
  ```
162
292
 
293
+ 需要实时进度时,使用 Python 的 `-u` 或 `print(..., flush=True)`,避免子进程自身的输出缓冲延迟消息。若 stdout 用于返回 JSON,把进度写到 stderr,避免进度文本混入最终 JSON。
294
+
163
295
  将脚本纳入包 `files`。解释器和业务库使用目标机器环境,推荐先加入官方“检查目标环境”,把输出 `python.executable` 绑定到后续动作。支持 Python 版本、pip、distribution 包名及可选导入模块;版本范围用 semver(如 `>=3.9 <4`),不支持完整 PEP 440 预发行版本语义。
164
296
 
165
297
  ## 配置与许可
@@ -1,6 +1,18 @@
1
1
  # 版本发布
2
2
 
3
- 产品名称 Fishtools,公共 npm 包名 `@yanglaofish/fishtools`,启动命令 `fst`。`0.1.x` 定位为早期可用版本。内部 `@mytools/*` 包随主包捆绑,不单独发布;内部插件 API 版本独立维护。
3
+ 产品名称 Fishtools,公共 npm 包名 `@yanglaofish/fishtools`,启动命令 `fst`。`0.x` 定位为早期可用版本。内部 `@mytools/*` 包随主包捆绑,不单独发布;内部插件 API 版本独立维护。
4
+
5
+ ## 0.2.0 控制流与运行观察
6
+
7
+ - 增加执行条件、条件分支、并行组、提前结束;TUI/Web 均可通过表单编辑嵌套步骤与参数引用。
8
+ - 正常返回且输出通过 schema 校验即动作成功;环境 `report` 返回业务结果供工作流判断,原 `check` 保留失败即抛错的行为。
9
+ - `/runs` 提供步骤总览、输入输出和实时日志;支持键盘、鼠标滚轮、暂停与恢复跟随。关闭观察面板后任务继续,取消需明确操作。
10
+ - `runProcess` 自动将 stdout/stderr 实时记录到当前步骤,Markdown 日志与结构化记录保留停止原因及错误来源。
11
+ - 新工作区带有 `control-demo` 示例;导出继续收集所有分支、并行子节点与子工作流的插件依赖。
12
+ - TUI 首页改为青绿色紧凑块字标识,统一菜单与日志配色,支持窄屏与 `NO_COLOR`;`/docs` 可直接阅读离线开发资料。
13
+ - npm 和便携包随附自包含开发手册、接口规范、参考源码、许可证与零依赖示例插件;`fst docs --export <新目录>` 导出整套资料,不需要访问源码仓库。
14
+
15
+ 升级说明:参与工作流编排的旧插件需要补齐有效的 `input` 与 `output` JSON Schema;无参数/无输出可使用空对象 schema 并返回 `{}`。不需要额外编写“成功判定”函数。原有顺序工作流仍使用 `schemaVersion: 1`。发布是否完成以本版本的 GitHub Release 和下方验收记录为准。
4
16
 
5
17
  ## 发布入口
6
18
 
@@ -0,0 +1,85 @@
1
+ # Fishtools 路线图与当前状态
2
+
3
+ 更新:2026-10-11,条件控制与运行观察阶段。本文是当前状态入口;早期设计和实施计划保留历史背景,发生冲突时以最新明确决策及验收记录为准。
4
+
5
+ ## 当前所处阶段
6
+
7
+ 既有版本已交付顺序编排、第三方插件安装、CLI/TUI/Web、日志和选定工作流自包含导出,随后加入完整便携工具、独立可写工作区、插件斜杠命令、环境声明、共享服务生命周期,以及 Markdown 诊断日志和按项目保留数量。各历史版本的测试和 CI 结果见验收记录。
8
+
9
+ 0.2.0 源码已实现条件分支、步骤执行条件、受限并发、正常提前结束、stdout/stderr 实时日志,以及 TUI/Web 的控制节点编辑和运行观察。本地 Windows 全量 143 项测试、Windows 便携包、WSL 真实 TUI、浏览器及断网 Docker 验收已通过。远端 CI 与 npm/Release 状态见验收记录。
10
+
11
+ “首版功能闭环完成”不表示插件生态基础设施、所有目标系统和硬件验证均已完成。Cordis 承担服务依赖激活,适配层负责受管异步初始化与清理;第三方开发工具化仍是后续方向。
12
+
13
+ ## 原始实施计划:六项任务
14
+
15
+ 编号对应 `superpowers/plans/2026-10-09-workflow-mvp.md` 的 Task 1—6;原始设计第 10 节另有六步验证顺序,不是额外的六个版本里程碑。
16
+
17
+ | 原始任务 | 当前状态 | 证据与剩余范围 |
18
+ | --- | --- | --- |
19
+ | 1. SDK、Host、工作流模型与执行 | 首版完成,已扩展服务管理 | `packages/sdk`、`core/src/host.js`、`runtime.js`、`engine.js`、`workflows.js`;动作/子流程、引用校验、失败停止、共享服务与受管清理 |
20
+ | 2. 应用服务、CLI、外部插件 | 首版完成 | `application.js`、`plugins.js`、`process.js`;安装、配置、日志、取消及仓库外插件接入 |
21
+ | 3. 官方环境检查和示例 | 首版完成,硬件验证有缺口 | `plugins/environment`、`plugins/examples`;真实 NPU 验证未完成 |
22
+ | 4. 自包含分发 | 首版完成,已扩展 | `packages/pack`;按工作流依赖收集、Windows/Linux 包、Docker 挂载;现默认完整可编辑工具 |
23
+ | 5. 官方离线 Web 工作台 | 首版完成,已优化易用性 | `plugins/web`;能力目录、顺序列表、表单、保存运行与导出;没有独立的完整历史检索界面 |
24
+ | 6. 文档、跨平台验证与交付 | 按版本持续验收 | `verification.md`;历史本地、WSL、断网 Docker 与 CI 按对应提交记录,本轮控制流增量另行验收 |
25
+
26
+ ## 后续已完成的增量
27
+
28
+ | 增量 | 状态 | 记录 |
29
+ | --- | --- | --- |
30
+ | 首次使用体验与窄屏 Web | 已交付 | `plans/2026-10-10-workbench-ui.md`、验收记录 |
31
+ | `fst` TUI,斜杠、方向键、文件补全 | 已交付 | `superpowers/plans/2026-10-10-fst-terminal.md`;提交 bdd9cdf 的双平台 CI 成功 |
32
+ | 分层便携工具、可编辑导出、内部 npm | 已交付 | `superpowers/specs/2026-10-10-portable-plugin-contract.md` |
33
+ | 插件命令、平台声明、环境来源与资源选择 | 已交付 | 同上,`plugin-development.md` |
34
+ | Markdown 诊断日志、TUI 历史阅读、按项目保留 N 次 | 已交付,77 项测试及双平台 CI 通过 | `superpowers/specs/2026-10-10-run-logs.md`,CI 见验收记录 |
35
+
36
+ 日志阶段的代码/测试提交:`e55075e`,[Windows 与 Ubuntu CI](https://github.com/yanglaofish/Fishtools/actions/runs/38053011826) 均成功。服务阶段的测试与对应 CI 单独记录在 `verification.md`。
37
+
38
+ ## 0.2.0 增量:本地验收通过
39
+
40
+ 依据 [控制流与运行观察规范](superpowers/specs/2026-10-11-control-observation.md),当前实现包括:
41
+
42
+ | 范围 | 当前源码行为 | 本轮状态 |
43
+ | --- | --- | --- |
44
+ | 控制流 | 保留 schemaVersion 1;增加 when、branch、parallel、stop,递归校验作用域和依赖闭包 | 本地验收通过 |
45
+ | 插件契约 | 编排动作显式声明有效 input/output schema;可选 conditions 预设引用已声明输出字段 | 输入输出契约与旧顺序流程验证通过 |
46
+ | 环境检查 | 原 check 未通过仍抛错;新增 report 返回 ok:false,由工作流决定后续处理 | 已实现,真实 NPU 验证仍未完成 |
47
+ | 运行记录 | stdout/stderr 按 UTF-8 流式记录并归属到 callPath;stopped 保存原因且无 error,CLI 正常退出 | 本地验收通过 |
48
+ | TUI | 表单编辑控制节点;/runs 切换总览、输入输出、实时日志,键盘/滚轮浏览,关闭面板后继续运行 | Windows / WSL 交互验收通过 |
49
+ | Web | 控制节点与执行条件表单;按调用路径观察结果和日志、暂停/恢复跟随、显式取消 | 1440 / 390 宽度真实浏览器验收通过 |
50
+
51
+ 观察与取消的边界已明确:TUI 面板内 Esc/q/Enter/Ctrl+C 只关闭,x 后按 y 确认取消;Web 关闭观察窗口不停止任务,“停止运行”发送取消。退出整个 TUI 应用时若仍有任务,需要确认取消后退出。已完成记录继续通过 /logs 与运行日志文件阅读。
52
+
53
+ 尚未承诺暂停/恢复、持久化断点、多机执行或自动回滚。并行任务需要响应取消信号,插件仍对自身业务副作用与资源并发安全负责。
54
+
55
+ ## 当前有效决策
56
+
57
+ - 名称 Fishtools,命令 `fst`;交互终端无参数启动 TUI,`fst web` 启动官方 Web。
58
+ - 保留 Cordis。Fishtools 保留工作流、元数据、输入输出契约和打包职责,逐步把共享服务依赖与受管资源生命周期落实到 Cordis。
59
+ - 插件的平台与架构由作者声明,核心不据此禁止加载、调用或跨目标打包,也不审核业务逻辑的平台正确性。
60
+ - Node 始终自包含;完整便携工具含内部 npm。Python 等按声明使用宿主或作者准备的随包资源;核心不自动探测、下载或构建 Python。
61
+ - 默认导出支持编辑与安装插件,数据放独立工作区;`--read-only` 选择精简执行包。
62
+ - 每一层步骤按列表顺序执行;需要独立并发时显式添加并行组,条件分支和提前结束由工作流决定。TUI/Web 使用表单维护同一协议及引用。
63
+ - 正常返回并通过输出校验即动作执行成功;业务检查字段与可选判定预设交由工作流使用。正常提前结束为 stopped,用户取消为 cancelled,异常为 failed。
64
+
65
+ ## 演进阶段:按依赖顺序推进
66
+
67
+ 以下是本次整理的新阶段编号,不能当作原始计划中已经承诺完成的功能。
68
+
69
+ | 阶段 | 目标 | 当前成熟度 | 完成条件 |
70
+ | --- | --- | --- | --- |
71
+ | N1. Cordis 服务与生命周期 | 插件之间共享能力、依赖就绪、关闭清理与失败定位 | 已实现,本地与便携包验收通过 | 提供者/消费者示例、61 项测试、维护模式、Web 资源归属;远端 CI 见验收记录 |
72
+ | 控制流与运行观察增量 | 条件、并行、提前结束、实时子进程日志和双界面观察 | 当前源码本地验收通过,未声明发布 | 控制协议、取消首因、递归依赖、真实界面操作及 Windows/Linux 验收与发布记录 |
73
+ | N2. 第三方开发体验 | 可独立使用的模板、类型提示、示例和接入契约测试 | 离线手册随包、/docs 阅读与导出、零依赖示例已完成;脚手架与 lint 未完成 | 仓库外作者仅按文档完成动作插件、服务插件与打包;契约检查不承担业务平台认证 |
74
+ | N3. 真实业务插件验证 | 用实际业务检验服务契约,例如 SSH 连接与远程检查共享 | 候选方向,具体插件待实际需求确定 | 两个独立插件复用同一服务,包含取消、错误、关闭与离线分发测试 |
75
+ | N4. 按需求扩展 | LLM/外部 Agent、Kubernetes、多机能力等 | 方向记录,未作实施承诺 | 每个扩展单独明确场景、接口和验收,不进入核心的默认依赖 |
76
+
77
+ N1 的历史验收对应提交 `061f0e4`,[Windows / Ubuntu CI](https://github.com/yanglaofish/Fishtools/actions/runs/38055698922) 均成功,不能替代当前控制流增量的验收。细化见 [Cordis 服务与生命周期设计](superpowers/specs/2026-10-10-cordis-services-design.md)。源码监听热更新、运行中无缝升级、插件市场、Alpine/ARM 不在本轮控制流增量范围内。
78
+
79
+ ## 文档导航
80
+
81
+ - 使用与安装:`../README.md`
82
+ - 插件当前可用接口:`plugin-development.md`
83
+ - 分发和工作区:`deployment.md`
84
+ - 实测范围与缺口:`verification.md`
85
+ - 历史初始设计:`superpowers/specs/2026-10-09-workflow-cli-design.md`
@@ -0,0 +1,115 @@
1
+ # 插件式工作流首版实施计划
2
+
3
+ > 已交付的历史实施计划。当前 CLI 名称、环境来源和分发行为以 [路线图](../../roadmap.md) 及其链接的最新设计为准;下面保留当时的实施约束。
4
+
5
+ > **For agentic workers:** REQUIRED SUB-SKILL: 使用 superpowers:executing-plans 在本会话逐项执行。用户已明确“没别的疑问就进入开发”,因此直接落盘并执行,不新增审批回合。
6
+
7
+ **Goal:** 交付可运行的插件式工作流工具,包含离线 Web 列表编排、CLI、官方环境检查插件和按选定工作流打包。
8
+
9
+ **Architecture:** Cordis Host 加载标准 JS 插件;核心公开能力目录、工作流保存/执行、日志、插件管理与打包服务。Web 和环境检查作为独立官方插件,CLI 与 Web 复用应用服务。Python 使用目标环境。
10
+
11
+ **Tech Stack:** Node.js 24.15.0、JavaScript ESM、Cordis 3.18.1、Ajv、YAML、Node 内建测试;npm workspaces + lockfile。按用户复用开源要求,前端采用 React、RJSF、dnd-kit、Lucide、Vite,构建为本地静态资源,无 CDN。进程用 Execa;打包复用 Arborist、npm-packlist、Archiver。
12
+
13
+ **Spec:** `docs/superpowers/specs/2026-10-09-workflow-cli-design.md`
14
+
15
+ **实施状态(2026-10-10):** 六项开发任务已完成,独立审查的重要问题已修复。实际测试、体积和平台缺口见 `docs/verification.md`;勾选开发任务不表示设计中的所有干净系统与硬件场景均已实测。Python/pip 解释器绑定采用真实环境手工验证;Docker Debian 12、Ubuntu 24.04 和 Python 3.12 容器已补测通过,真实 NPU 硬件待后续验证。
16
+
17
+ ## Global Constraints
18
+
19
+ - 中文界面、说明和注释;Windows x64 与 Linux x64 glibc 分别出包。
20
+ - 工作流是有序步骤列表,支持插件动作及子工作流;用户不手写 YAML 或依赖锁。
21
+ - 必需环境检查失败终止后续步骤;Python 环境不随包安装或替换。
22
+ - 包内携带 Node.js、所选工作流依赖闭包、脚本和资源;Linux 包可挂载进容器。
23
+ - 官方 Web 插件标准发行默认提供,纯 CLI 运行包可不包含它。
24
+ - 网页资源离线可用,支持堡垒机端口转发;不在本轮发布 npm 或推送远端。
25
+
26
+ ## Review Focus
27
+
28
+ - 重排或删除前序步骤后引用失效:校验阻止运行并指明字段(任务 1、5)。
29
+ - 中文/空格路径、不同工作目录和包外符号链接:启动定位及打包独立性(任务 2、4)。
30
+ - 缺少 Python、pip、NPU 工具不能误判成功,检查与执行不能切换解释器(任务 3)。
31
+ - 子流程失败、取消和大输出不能留下假成功或未关闭的受管进程(任务 1、2)。
32
+ - Web 令牌、路径越界、离线资源和端口转发不得破坏执行边界(任务 5)。
33
+
34
+ ## 文件结构
35
+
36
+ - `packages/sdk/`:插件定义与公共协议。
37
+ - `packages/core/src/host.js`:Cordis 生命周期、插件动作目录。
38
+ - `packages/core/src/workflows.js`:存取、静态校验、引用与闭包。
39
+ - `packages/core/src/engine.js`:执行快照、顺序调用、日志和取消。
40
+ - `packages/core/src/process.js`:无 Shell 的程序调用及回收。
41
+ - `packages/core/src/application.js`:共用应用服务。
42
+ - `packages/core/src/plugins.js`:安装、移除与锁定外部插件。
43
+ - `packages/pack/`:生产依赖收集、运行时和归档,独立于执行包。
44
+ - `packages/core/bin/flow.js`:CLI。
45
+ - `plugins/environment/`:目标环境检查。
46
+ - `plugins/examples/`:可组合的本地示例与 Python 调用。
47
+ - `plugins/web/`:HTTP 适配和静态界面。
48
+ - `examples/`:可直接运行的工作流。
49
+ - `tests/`:真实文件、进程和 HTTP 边界测试。
50
+
51
+ ### Task 1: 插件目录与顺序工作流
52
+
53
+ **Files:** SDK、`host.js`、`workflows.js`、`engine.js`、`tests/workflows.test.js`。
54
+
55
+ **Interfaces:** `createHost({plugins,config})` 返回动作目录与 `invoke(id,input,context)`;`WorkflowStore(root)` 提供 `list/get/save/resolve`;`runWorkflow({store,host,id,input,signal,onEvent})` 返回输出。
56
+
57
+ - [x] 写失败测试:真实测试插件两个动作串联得到 `{text:'HELLO'}`;子流程传参;失败后动作未执行;循环/前向引用/越界路径被拒绝。
58
+ - [x] `node --test tests/workflows.test.js`:先因待实现模块失败。
59
+ - [x] 实现 SDK、Cordis Host、静态模型与执行;输入输出使用 Ajv 校验,拒绝危险字段路径。
60
+ - [x] 同一命令全部通过,再运行 `npm test`;提交任务代码。
61
+
62
+ ### Task 2: 共用应用服务、CLI 和外部插件
63
+
64
+ **Files:** `process.js`、`plugins.js`、`application.js`、CLI、`tests/application.test.js`、`tests/process.test.js`。
65
+
66
+ **Interfaces:** `createApplication({projectDir,outputDir})` 提供 `catalog/listWorkflows/saveWorkflow/startRun/getRun/cancelRun/installPlugin/removePlugin/pack/close`;`runProcess(file,args,options)` 返回退出信息。
67
+
68
+ - [x] 写失败测试:带空格/中文参数真实传递;非零退出、输出上限、取消;JSONL 日志持久化;在仓库外安装本地插件并运行动作。
69
+ - [x] 执行新增测试,确认缺失行为导致失败。
70
+ - [x] 实现项目配置、准确插件位置、npm 安装适配与可读 CLI;安装失败不覆盖原项目状态。
71
+ - [x] 执行 `npm test`,验证外部插件闭环,提交。
72
+
73
+ ### Task 3: 官方环境检查与示例
74
+
75
+ **Files:** `plugins/environment/`、`plugins/examples/`、`examples/`、`tests/environment.test.js`。
76
+
77
+ **Interfaces:** 环境插件公开 `check` 动作,输入为所需环境与解释器,输出为检查报告及解析后的解释器;示例插件提供文本动作和目标 Python 脚本调用。
78
+
79
+ - [x] 写失败测试:不存在的解释器令检查失败且带报告;系统信息可读;pip 与指定解释器绑定;检查输出用于后续动作。
80
+ - [x] 执行新增测试观察失败。
81
+ - [x] 实现 Node 系统探测、目标 Python/pip 查询、NPU 命令适配及结构化报告;不安装环境。
82
+ - [x] `npm test` 全绿;运行纯 JS 示例与可用目标 Python 示例,提交。
83
+
84
+ ### Task 4: 自包含分发
85
+
86
+ **Files:** 打包模块、运行时下载与清单、`tests/pack.test.js`。
87
+
88
+ **Interfaces:** `packApplication(app,{entries,target,outDir,includeWeb,runtimePath})` 返回目录、归档与 manifest;`verifyBundle(root)` 验证清单。
89
+
90
+ - [x] 写失败测试:A 引用 B,C 不入包;重复依赖去重;可选 Web;篡改文件校验失败。
91
+ - [x] 执行新增测试观察失败。
92
+ - [x] 基于实际安装树按解析结果复制生产依赖,保留多版本嵌套关系且消除外部链接;锁定准确版本与哈希。
93
+ - [x] 按平台收集经过官方校验值验证的 Node.js 与许可,生成相对路径启动器、ZIP/tar.gz;原生依赖跨目标拒绝不可靠复制。
94
+ - [x] 脱离源码的 Windows 包实际运行;可用 Linux/容器执行验证;`npm test` 通过,记录未具备环境的验证缺口并提交。
95
+
96
+ ### Task 5: 官方离线 Web 工作台
97
+
98
+ **Files:** `plugins/web/`、`tests/web.test.js`,必要的浏览器验证记录。
99
+
100
+ **Interfaces:** Web 插件通过公开应用服务提供目录、工作流、运行、日志、插件管理与导出 API;浏览器只调用同源相对 URL。
101
+
102
+ - [x] 写失败测试:真实 HTTP 下未授权请求被拒绝、工作流保存后能运行、越界静态路径被拒绝、全部静态资源本地可用。
103
+ - [x] 执行新增测试观察失败。
104
+ - [x] 实现令牌、请求来源检查、绑定地址与静态资源;界面包含能力/流程列表、有序步骤、参数来源选择、结果日志、插件安装与导出。
105
+ - [x] `npm test`;浏览器实际添加、排序、引用输出、保存、运行和观察失败,修正发现的问题。
106
+ - [x] 保存界面与 CLI 一致性验证证据,提交。
107
+
108
+ ### Task 6: 交付验证与文档
109
+
110
+ **Files:** README、插件开发说明、部署说明、跨平台 CI 和验收记录。
111
+
112
+ - [x] 运行全套测试与本机包冒烟;检查打包不携带开发工具链和外部绝对链接。
113
+ - [x] 编写启动、插件开发、目标 Python 配置、离线部署、堡垒机端口转发和分发包使用说明。
114
+ - [x] 全分支独立审查;对重要问题以失败测试复现后修复,再跑全套。
115
+ - [x] 记录平台实测范围、硬件缺口、产物大小和运行方式;提交并交付可打开的 Web 界面。
@@ -0,0 +1,34 @@
1
+ # Cordis 服务与生命周期实施计划
2
+
3
+ > 使用 superpowers:executing-plans 在当前会话实施。用户已审阅设计并要求继续开发;保留当前本地分支工作方式,不重复请求授权。结束时做一次独立审查。
4
+
5
+ **目标:** 保持旧插件兼容,落实应用级资源归属和 Cordis 服务插件。
6
+ **设计:** `../specs/2026-10-10-cordis-services-design.md`。
7
+ **技术:** 锁定 Cordis 3.18.1、Node 24、现有 node:test。
8
+
9
+ ## 全局约束与审查重点
10
+
11
+ - 不实现第二套动态服务激活机制;静态声明与打包契约由 Fishtools 校验。
12
+ - 插件平台仅声明,不审核业务正确性;旧 actions/commands/services 协议兼容。
13
+ - Web 开启时宿主切换不能中断控制入口;阻止活动 Web 提供者替换和移除。
14
+ - 异步清理要等待、错误要传播;初始化失败释放已获取资源。
15
+ - 安装/配置/关闭竞争、失效服务调用、缺失或循环声明、服务提供者打包闭包均需测试。
16
+
17
+ ## 任务与测试
18
+
19
+ 1. [x] 应用资源:新增 `core/src/resources.js`,提供 `own(factory)`、`close()`、`active`;修改 application.startWeb/close,生命周期开始关闭后拒绝新增任务。`tests/lifecycle.test.js` 验证真实端口释放、幂等关闭、异步启动与关闭竞争、失败清理。
20
+ 2. [x] 服务宿主:新增 `runtime.js` 校验 runtime.provides/inject/apply、提供者所属 dependencies 及循环;Cordis 管理注入激活。host 暴露 `runtimeStatus()`、`hasRuntime`,动作和命令上下文提供 `getService(name)`;绑定注册清理,等待异步 dispose,并传播启动/停止错误。`tests/runtime.test.js` 覆盖乱序加载、共享实例、就绪、失败/缺失/重复/循环、取消与作用域撤销。
21
+ 3. [x] 应用整合:有 runtime 插件时拒绝在线重建宿主;活动 Web 不能移除或替换。状态进入 listPlugins/TUI/CLI/Web API;pack 依赖闭包保留服务提供者。lifecycle/Web/pack 测试覆盖更新保护及导出后加载。
22
+ 4. [x] 公开示例与文档:提供可独立安装的 provider/consumer 示例,写出服务就绪后发布、getService 与 async dispose 用法;更新路线图和开发规范。
23
+ 5. [x] 验收:定向测试、构建和全套测试;一次独立审查并修复重要问题;便携包跨平台服务调用;提交推送并核对对应 CI。
24
+
25
+ ## 执行记录
26
+
27
+ - 基线 e8672ef;分支 feat/cordis-services。本轮沿用已授权的当前工作区和连续实施。
28
+ - 版本核查:Cordis 的 start 等待 ready 任务,但 stop/reset 不等待异步 disposer。采用受管 dispose 监听器的 Promise 收集,保持 Cordis 负责触发和撤销;不假设 stop 已释放全部资源。
29
+ - 任务 1—3:资源关闭、服务声明/注入、失败清理、失效调用、Web 更新保护均经历失败测试后实现并通过。额外红绿测试修复关闭顺序,先释放 Web 再关闭其依赖宿主。
30
+ - 裁定:增加进程级维护模式及 TUI 切换;只说“停止后再修改”会使下次 CLI 启动又加载服务,导致用户无从维护。维护模式关闭 runtime 激活,保留契约校验和普通插件;不写入项目配置。
31
+ - 任务 4:提供两个可独立安装的 MIT 服务插件。service-pack 集成测试验证安装、调用、导出提供者闭包及独立启动;TUI 维护切换测试通过。
32
+ - 独立审查一次,发现初始化撤销后的资源泄漏、旧调用穿透激活代次两项 Important;先补三项失败测试,再按每次激活跟踪初始化/清理及绑定 getService 令牌。最终本地 61/61 通过(150.5 秒)。
33
+ - Windows 与 WSL 便携包实际调用共享服务成功;WSL 真实 TUI 进入维护、显示停止、恢复服务成功;断网只读 Debian 容器服务调用与完整性校验通过。
34
+ - 代码提交 `061f0e4` 已推送至 main,Windows / Ubuntu CI 均通过:https://github.com/yanglaofish/Fishtools/actions/runs/38055698922 。本地保留 feat/cordis-services 分支;Windows、Linux 完整便携包位于 dist/cordis,npm 安装包位于 dist/fishtools-0.1.0.tgz。
@@ -0,0 +1,33 @@
1
+ # fst 交互终端实施计划
2
+
3
+ **目标:** 将启动命令改为 `fst`,无 Web 时也能通过斜杠命令、文件补全和方向键完成编排及运行。
4
+
5
+ **用户意图:** 终端需要像 Claude 一样可以发现命令和选择项目,而不是要求记住全部命令行参数。产品仍叫 Fishtools,保留批处理子命令;交互终端不引入 LLM。
6
+
7
+ **架构:** 使用 Pi 的 `@mariozechner/pi-tui`(MIT)提供 Editor、命令/文件补全、SelectList 和终端渲染。终端适配层调用现有 application、schema 校验和工作流格式,不绑定 Web 插件,不重复实现执行器。无参数且非 TTY 时打印帮助,不启动后台服务或挂起。
8
+
9
+ ## 交互设计
10
+
11
+ - `fst` 默认启动终端工作台;`fst web` 显式启动 Web。
12
+ - `/help`、`/workflows`、`/new`、`/add`、`/steps`、`/outputs`、`/save`、`/run`、`/plugins`、`/pack`、`/web`、`/exit`。
13
+ - 所有选择列表支持上下箭头、Enter,Escape 返回。编辑和切换时保留未保存提醒;Ctrl+C 取消当前选择或运行,空闲时退出并确认未保存修改。
14
+ - 参数由 schema 引导填写,支持固定值、前序输出、运行时填写。对象逐字段处理、数组按项编辑,复杂联合 schema 可用 JSON 输入并校验。
15
+ - `@` 与 Tab 补全目标机器本地路径;参数中的 `@路径` 转为绝对路径,`@@` 表示字面量 @。只在 `/run [工作流ID] @文件.json` 的明确位置读取 JSON;文件内容不被隐式当成命令执行。
16
+ - `/steps` 可改参数、上下移动、删除步骤;`/outputs` 选择最终输出;新建不要求手写 YAML。
17
+ - 只读运行包支持浏览、参数填写与运行,禁用编排、安装和重新打包。
18
+ - `fst run` 等原子命令继续用于自动化。npm 只注册 `fst`,不占用 Fish Shell 的 `fish`;包启动器同步改名,保留 `run`/`web` 兼容脚本。
19
+
20
+ ## 实施任务
21
+
22
+ 1. [x] 重命名 CLI、npm bin、自包含启动器和测试;增加默认非 TTY 行为测试。
23
+ 2. [x] 增加终端视图适配、schema 编辑与流程控制;测试路径解析、参数绑定、编排保存、取消和只读模式。
24
+ 3. [x] 用真实 PTY 验证 `/`、方向键、`@`、完整编排运行;跑全套测试,更新文档和许可证,生成 npm 包。
25
+ 4. [x] 独立审查后推送,等待对应提交的 Windows 与 Ubuntu CI 都完成;失败继续修复。提交 `bdd9cdf` 的 [双平台 CI](https://github.com/yanglaofish/Fishtools/actions/runs/38049659095) 已成功,本项补记已核对的状态。
26
+
27
+ ## 验收重点
28
+
29
+ - 中文和带空格的文件路径、Windows 反斜杠、取消中途编辑不污染已保存工作流。
30
+ - 运行时参数和前序输出引用不会被固定值表单覆盖,切换输入来源不会留下不再使用的运行必填项。
31
+ - 无 Web 插件时能启动终端;缺少 Web 时 `/web` 明确报错并返回主提示符。
32
+ - npm 安装端和自包含运行包都使用 `fst`,原子命令输出仍可机器读取。
33
+ - 以远端 CI 的最终状态作为交付门槛,不能用推送成功替代检查通过。
@@ -0,0 +1,35 @@
1
+ # 分层分发与插件契约实施计划
2
+
3
+ > 使用 superpowers:executing-plans 在当前会话按任务执行;用户已明确授权演进设计并继续编码。
4
+
5
+ **目标:** 同一 fst 工具支持便携开发、可编辑流程导出、插件命令和声明式环境资源。
6
+ **架构:** 复用 Node/npm/Cordis,独立插件契约、环境计划、工作区初始化与归档模块;不创建包管理器或业务兼容性检查器。
7
+ **技术栈:** Node 24.15.0、JavaScript、Cordis、Pi TUI、npm、node-tar、Archiver。
8
+ **设计:** ../specs/2026-10-10-portable-plugin-contract.md
9
+
10
+ ## 全局约束
11
+
12
+ - 中文说明与注释;Windows x64 / Linux x64 glibc;相同 TUI。
13
+ - 平台声明不阻止加载/调用;业务环境检查交给插件。
14
+ - 包含 npm 的完整分发能安装本地插件并再次导出;不发布公共 npm。
15
+
16
+ ## 审查重点
17
+
18
+ 命令与核心入口冲突、取消交互后运行收尾、环境资源越界、工作区重复初始化与移动、隔离 PATH 后内部 npm 调用。
19
+
20
+ ## 任务
21
+
22
+ 1. [x] 契约与命令:新增 core/src/contracts.js、environments.js;扩展 host/application/terminal;测试平台声明仅提示、非法契约、命令调用与冲突、取消。先运行新增失败测试,再实现并执行相关测试。
23
+ 2. [x] 环境打包计划:新增 pack/environments.js;扩展 copyPackages 资源筛选并移除业务平台门禁;测试 host 不入包、目标 artifacts、越界、源切换。API planApplication(app,options) 返回清单与 bytes。
24
+ 3. [x] 完整运行环境与可编辑导出:扩展 runtime/index/project/CLI,新增工作区模块与共用归档;新增 portable 命令、--read-only、--workspace、--environments。测试改参持久化、只读兼容、完整性与内部 npm。
25
+ 4. [x] 统一 TUI:动态插件斜杠命令、/config、/pack 计划与来源选择;官方示例展示契约;更新接入指南及部署文档。
26
+ 5. [x] 验收交付:运行全套测试与构建、Windows/Linux/Docker 产物测试、独立审查、必要修复、推送并等待 Windows/Ubuntu CI。
27
+
28
+ ## 执行记录
29
+
30
+ - 开始:基线 bdd9cdf,分支 feat/portable-plugin-contract。用户授权本轮直接开发,采用会话内实施和一次最终独立审查。
31
+
32
+ - 本地验收:构建成功、47/47 测试通过;Windows 与 WSL 真实 TUI、Linux 归档解压、断网无 Node/npm 容器安装及再次打包通过。
33
+ - 独立审查:2 项 Important 均修复并补回归。另修复归档执行权限和应用层依赖清单,等待远端双平台 CI。
34
+
35
+ - 最终 CI:e55075e 的 Windows 与 Ubuntu 均通过,https://github.com/yanglaofish/Fishtools/actions/runs/38053011826 。后续仅归档验收文档。