@yanglaofish/fishtools 0.3.0 → 0.4.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 (52) hide show
  1. package/README.md +2 -2
  2. package/manual/README.md +2 -2
  3. package/manual/docs/examples/script-plugin/LICENSE +21 -0
  4. package/manual/docs/examples/script-plugin/README.md +64 -0
  5. package/manual/docs/examples/script-plugin/index.js +39 -0
  6. package/manual/docs/examples/script-plugin/package.json +9 -0
  7. package/manual/docs/examples/script-plugin/scripts/benchmark.py +23 -0
  8. package/manual/docs/plugin-development.md +49 -8
  9. package/manual/docs/releases.md +11 -0
  10. package/manual/docs/roadmap.md +3 -1
  11. package/manual/docs/superpowers/plans/2026-10-12-plugin-developer-experience.md +50 -0
  12. package/manual/docs/superpowers/reviews/2026-10-12-plugin-release-review.md +20 -0
  13. package/manual/docs/superpowers/specs/2026-10-12-plugin-developer-experience.md +22 -0
  14. package/manual/docs/verification.md +17 -0
  15. package/manual/packages/core/src/application.js +45 -21
  16. package/manual/packages/core/src/host.js +20 -5
  17. package/node_modules/@mytools/core/bin/fst.js +27 -5
  18. package/node_modules/@mytools/core/package.json +2 -0
  19. package/node_modules/@mytools/core/src/application.js +45 -21
  20. package/node_modules/@mytools/core/src/contracts.js +26 -8
  21. package/node_modules/@mytools/core/src/environments.js +39 -1
  22. package/node_modules/@mytools/core/src/host.js +20 -5
  23. package/node_modules/@mytools/core/src/plugin-installations.js +84 -0
  24. package/node_modules/@mytools/core/src/plugin-tools.js +133 -0
  25. package/node_modules/@mytools/core/src/plugins.js +16 -6
  26. package/node_modules/@mytools/core/src/process.js +16 -7
  27. package/node_modules/@mytools/core/src/schema-path.js +31 -0
  28. package/node_modules/@mytools/core/src/validation.js +22 -9
  29. package/node_modules/@mytools/core/src/version.js +1 -1
  30. package/node_modules/@mytools/core/src/workflows.js +2 -15
  31. package/node_modules/@mytools/pack/dependencies.js +8 -1
  32. package/node_modules/@mytools/web/public/THIRD_PARTY_NOTICES.txt +1168 -1168
  33. package/node_modules/{tar → minipass-flush/node_modules/minipass}/node_modules/yallist/README.md +7 -8
  34. package/node_modules/minipass-flush/node_modules/minipass/node_modules/yallist/package.json +29 -0
  35. package/node_modules/yallist/README.md +8 -7
  36. package/node_modules/yallist/package.json +51 -12
  37. package/package.json +15 -15
  38. package/node_modules/tar/node_modules/yallist/package.json +0 -68
  39. /package/node_modules/{yallist → minipass-flush/node_modules/minipass/node_modules/yallist}/LICENSE +0 -0
  40. /package/node_modules/{yallist → minipass-flush/node_modules/minipass/node_modules/yallist}/iterator.js +0 -0
  41. /package/node_modules/{yallist → minipass-flush/node_modules/minipass/node_modules/yallist}/yallist.js +0 -0
  42. /package/node_modules/{tar/node_modules/yallist → yallist}/LICENSE.md +0 -0
  43. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/commonjs/index.d.ts +0 -0
  44. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/commonjs/index.d.ts.map +0 -0
  45. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/commonjs/index.js +0 -0
  46. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/commonjs/index.js.map +0 -0
  47. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/commonjs/package.json +0 -0
  48. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/esm/index.d.ts +0 -0
  49. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/esm/index.d.ts.map +0 -0
  50. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/esm/index.js +0 -0
  51. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/esm/index.js.map +0 -0
  52. /package/node_modules/{tar/node_modules/yallist → yallist}/dist/esm/package.json +0 -0
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  交互终端支持选择能力、配置参数和流程编排;官方 Web 插件默认提供,原子 CLI 子命令用于自动化。三种入口共用应用服务。YAML、依赖锁和版本解析由系统维护,不要求普通用户手写。
8
8
 
9
- 0.3.0 增加按对象组织的终端菜单、主面板执行摘要与插件用户输出、命令历史,并修复第三方插件进程调用和离线 Web 打包。此前 0.2.0 引入的条件控制、运行观察和离线开发手册仍可使用。发布与验证状态见 [版本记录](manual/docs/releases.md) 和 [验收记录](manual/docs/verification.md)。
9
+ 0.4.0 增加插件创建、离线校验、源码引用和安装批次回收,支持解释器候选、插件状态目录与输出编码,并改善 schema 诊断。输出不再按 schema 补默认值,插件须明确返回业务字段。此前版本的终端菜单、执行摘要、条件控制和离线开发手册继续可用。发布与验证状态见 [版本记录](manual/docs/releases.md) 和 [验收记录](manual/docs/verification.md)。
10
10
 
11
11
  插件接入层使用 JavaScript/TypeScript,通过通用进程接口调用 Python 脚本和系统命令。首款官方插件负责 Python/pip、NPU 与系统环境检查,使用与第三方插件相同的公开接口,按工作流依赖选入分发包。插件声明 Python 等环境使用宿主机还是自带资源;环境检查与业务兼容性由插件作者负责。包内始终携带编排器所需的 Node,完整便携包也携带 npm。
12
12
 
@@ -19,7 +19,7 @@ npm install -g @yanglaofish/fishtools
19
19
  fst
20
20
  ```
21
21
 
22
- 也可从 GitHub Release 下载 `.tgz` 后执行 `npm install -g ./yanglaofish-fishtools-0.3.0.tgz`。没有 Node/npm 的机器使用 Release 中的 Windows `.zip` 或 Linux `.tar.gz` 自包含包,解压后运行 `fst.cmd` 或 `./fst`。发布结果以 [GitHub Releases](https://github.com/yanglaofish/Fishtools/releases) 为准;当前仓库为私有,下载附件需要仓库访问权限。
22
+ 也可从 GitHub Release 下载 `.tgz` 后执行 `npm install -g ./yanglaofish-fishtools-0.4.0.tgz`。没有 Node/npm 的机器使用 Release 中的 Windows `.zip` 或 Linux `.tar.gz` 自包含包,解压后运行 `fst.cmd` 或 `./fst`。发布结果以 [GitHub Releases](https://github.com/yanglaofish/Fishtools/releases) 为准;当前仓库为私有,下载附件需要仓库访问权限。
23
23
 
24
24
  `fst` 在交互终端里启动终端工作台(TUI);`fst web` 启动 Web 并打印访问地址;`fst run hello` 直接执行工作流。首次使用在 `~/.fishtools` 创建工作区,也可通过 `FISHTOOLS_HOME` 指定。安装包已包含官方插件、页面和生产依赖,不需要源码仓库或前端构建。
25
25
 
package/manual/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  交互终端支持选择能力、配置参数和流程编排;官方 Web 插件默认提供,原子 CLI 子命令用于自动化。三种入口共用应用服务。YAML、依赖锁和版本解析由系统维护,不要求普通用户手写。
8
8
 
9
- 0.3.0 增加按对象组织的终端菜单、主面板执行摘要与插件用户输出、命令历史,并修复第三方插件进程调用和离线 Web 打包。此前 0.2.0 引入的条件控制、运行观察和离线开发手册仍可使用。发布与验证状态见 [版本记录](docs/releases.md) 和 [验收记录](docs/verification.md)。
9
+ 0.4.0 增加插件创建、离线校验、源码引用和安装批次回收,支持解释器候选、插件状态目录与输出编码,并改善 schema 诊断。输出不再按 schema 补默认值,插件须明确返回业务字段。此前版本的终端菜单、执行摘要、条件控制和离线开发手册继续可用。发布与验证状态见 [版本记录](docs/releases.md) 和 [验收记录](docs/verification.md)。
10
10
 
11
11
  插件接入层使用 JavaScript/TypeScript,通过通用进程接口调用 Python 脚本和系统命令。首款官方插件负责 Python/pip、NPU 与系统环境检查,使用与第三方插件相同的公开接口,按工作流依赖选入分发包。插件声明 Python 等环境使用宿主机还是自带资源;环境检查与业务兼容性由插件作者负责。包内始终携带编排器所需的 Node,完整便携包也携带 npm。
12
12
 
@@ -19,7 +19,7 @@ npm install -g @yanglaofish/fishtools
19
19
  fst
20
20
  ```
21
21
 
22
- 也可从 GitHub Release 下载 `.tgz` 后执行 `npm install -g ./yanglaofish-fishtools-0.3.0.tgz`。没有 Node/npm 的机器使用 Release 中的 Windows `.zip` 或 Linux `.tar.gz` 自包含包,解压后运行 `fst.cmd` 或 `./fst`。发布结果以 [GitHub Releases](https://github.com/yanglaofish/Fishtools/releases) 为准;当前仓库为私有,下载附件需要仓库访问权限。
22
+ 也可从 GitHub Release 下载 `.tgz` 后执行 `npm install -g ./yanglaofish-fishtools-0.4.0.tgz`。没有 Node/npm 的机器使用 Release 中的 Windows `.zip` 或 Linux `.tar.gz` 自包含包,解压后运行 `fst.cmd` 或 `./fst`。发布结果以 [GitHub Releases](https://github.com/yanglaofish/Fishtools/releases) 为准;当前仓库为私有,下载附件需要仓库访问权限。
23
23
 
24
24
  `fst` 在交互终端里启动终端工作台(TUI);`fst web` 启动 Web 并打印访问地址;`fst run hello` 直接执行工作流。首次使用在 `~/.fishtools` 创建工作区,也可通过 `FISHTOOLS_HOME` 指定。安装包已包含官方插件、页面和生产依赖,不需要源码仓库或前端构建。
25
25
 
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mytools contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # Python 脚本插件示例
2
+
3
+ 这是可独立安装的 ESM 插件包。npm 依赖为零,包内 Python 脚本只使用标准库。它演示嵌套输入、宿主解释器选择、脚本资源定位和业务条件分支;指标是确定性的教学计算,不是硬件性能基准。
4
+
5
+ ## 安装与运行
6
+
7
+ 先确认目标机器安装了 Python 3。插件声明 `host` 环境,按顺序查找 `python3`、`python`;不会下载 Python 或将解释器打入包。复制本目录到目标机器,在 Fishtools 项目中执行:
8
+
9
+ ```sh
10
+ fst plugin validate ./script-plugin
11
+ fst --project ./my-project plugin add ./script-plugin
12
+ ```
13
+
14
+ 创建输入文件 `benchmark.json`:
15
+
16
+ ```json
17
+ {"benchmark_config":{"samples":4,"threshold":7}}
18
+ ```
19
+
20
+ 将 `fishtools-python-benchmark-example:benchmark` 加入工作流,输入绑定 `benchmark_config`。如果 Python 不在 PATH 中,运行时会报告找不到 `python3`、`python`。在项目 `flow.project.json` 的 `environments` 中为该插件指定解释器绝对路径,例如:
21
+
22
+ ```json
23
+ {
24
+ "environments": {
25
+ "fishtools-python-benchmark-example": {
26
+ "python": {"source": "host", "executable": "C:/Python312/python.exe"}
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ 上面仅展示相关字段;编辑已有项目文件时保留原有 `plugins`、`config` 等字段。Linux/macOS 可将路径换成 `/usr/bin/python3` 等实际位置。显式路径不可用会报错,不回退到候选命令。解释器需要 Python 3;目标环境和脚本的兼容性由部署者验证。
33
+
34
+ ## 业务结果与分支
35
+
36
+ 脚本计算 `1²` 到 `samples²` 的平均值。`samples=4` 得到 `7.5`;`threshold=7` 返回 `ok:true`,`threshold=8` 返回 `ok:false`。两种结果都表示脚本正常完成,输出包含 `metrics.samples`、`metrics.average` 和 `reason`。动作提供 `conditions.passed`,可在工作流中选择通过和未通过分支:
37
+
38
+ ```yaml
39
+ schemaVersion: 1
40
+ id: python-benchmark-example
41
+ steps:
42
+ - id: measure
43
+ action: fishtools-python-benchmark-example:benchmark
44
+ with:
45
+ benchmark_config:
46
+ samples: 4
47
+ threshold: 8
48
+ - id: result
49
+ branch:
50
+ condition:
51
+ left: {$ref: steps.measure.output.ok}
52
+ op: eq
53
+ right: true
54
+ then:
55
+ - id: accepted
56
+ stop: {reason: 业务指标通过}
57
+ else:
58
+ - id: rejected
59
+ stop: {reason: 业务指标未通过}
60
+ ```
61
+
62
+ 将工作流保存为项目的 `workflows/python-benchmark-example.yaml` 后,可执行 `fst --project ./my-project workflow check python-benchmark-example` 和 `fst --project ./my-project run python-benchmark-example`。`ok:false` 应由业务分支处理;脚本非零退出或输出不是 JSON 才作为执行错误抛出。
63
+
64
+ 动作通过 `environments.python.executable` 取得最终解释器,通过 `resourceDir` 找包内 `scripts/benchmark.py`,再用上下文 `runProcess` 执行。宿主绑定的 `runProcess` 自动继承取消信号并将 stdout/stderr 写入运行日志。`package.json.files` 包含脚本,`npm pack` 生成的归档可独立安装。
@@ -0,0 +1,39 @@
1
+ import path from 'node:path';
2
+
3
+ // 直接导出插件定义,不依赖尚未独立发布的内部 SDK。
4
+ export default {
5
+ id:'fishtools-python-benchmark-example',version:'1.0.0',sdk:'^0.1.0',
6
+ title:'Python 脚本示例',description:'调用包内标准库脚本并区分业务未通过与执行失败。',
7
+ platforms:['win32','linux','darwin'],architectures:['x64','arm64'],
8
+ environments:{python:{source:'host',executable:['python3','python']}},
9
+ actions:{
10
+ benchmark:{
11
+ title:'计算样本指标',description:'用 Python 计算前 N 个正整数的平方均值,并与阈值比较。',
12
+ input:{type:'object',properties:{
13
+ benchmark_config:{type:'object',title:'计算配置',properties:{
14
+ samples:{type:'integer',minimum:1,maximum:100000,title:'样本数'},
15
+ threshold:{type:'number',minimum:0,title:'最低平方均值'},
16
+ },required:['samples','threshold'],additionalProperties:false},
17
+ },required:['benchmark_config'],additionalProperties:false},
18
+ output:{type:'object',properties:{
19
+ ok:{type:'boolean',title:'业务通过'},
20
+ metrics:{type:'object',properties:{
21
+ samples:{type:'integer'},average:{type:'number'},
22
+ },required:['samples','average'],additionalProperties:false},
23
+ reason:{type:'string',title:'判定原因'},
24
+ },required:['ok','metrics','reason'],additionalProperties:false},
25
+ conditions:{passed:{title:'业务通过',path:'ok',op:'eq',value:true}},
26
+ async run({benchmark_config},{environments,resourceDir,runProcess,signal}){
27
+ signal?.throwIfAborted();
28
+ const script=path.join(resourceDir,'scripts','benchmark.py');
29
+ // 宿主绑定的 runProcess 会自动继承当前调用的取消信号并记录输出。
30
+ const result=await runProcess(environments.python.executable,[script,JSON.stringify(benchmark_config)],{timeout:30000});
31
+ if(result.exitCode!==0)throw Object.assign(new Error(`Python 脚本执行失败(退出码 ${result.exitCode}):${result.stderr}`),{
32
+ code:'PYTHON_FAILED',details:{exitCode:result.exitCode,stderr:result.stderr},
33
+ });
34
+ try{return JSON.parse(result.stdout);}
35
+ catch(cause){throw Object.assign(new Error('Python 脚本返回无效 JSON',{cause}),{code:'PYTHON_OUTPUT_INVALID'});}
36
+ },
37
+ },
38
+ },
39
+ };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "fishtools-python-benchmark-example",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "index.js",
6
+ "files": ["index.js", "scripts", "README.md", "LICENSE"],
7
+ "license": "MIT",
8
+ "engines": {"node": ">=24.15.0"}
9
+ }
@@ -0,0 +1,23 @@
1
+ """用 Python 标准库计算确定性的示例指标。"""
2
+
3
+ import json
4
+ import sys
5
+
6
+
7
+ def main():
8
+ config = json.loads(sys.argv[1])
9
+ samples = config["samples"]
10
+ threshold = config["threshold"]
11
+ average = sum(value * value for value in range(1, samples + 1)) / samples
12
+ ok = average >= threshold
13
+ result = {
14
+ "ok": ok,
15
+ "metrics": {"samples": samples, "average": average},
16
+ "reason": "达到阈值" if ok else "平均值低于阈值",
17
+ }
18
+ # 默认 ASCII JSON 转义避免 Windows 控制台编码影响进程间协议。
19
+ print(json.dumps(result, ensure_ascii=True, separators=(",", ":")))
20
+
21
+
22
+ if __name__ == "__main__":
23
+ main()
@@ -4,6 +4,8 @@
4
4
 
5
5
  `print()` 用户输出接口、主面板默认折叠和 Ctrl+O 展开从 0.3.0 起纳入发行包;0.2.0 不包含这些能力。
6
6
 
7
+ 从 0.4.0 起包含下文的 `plugin create/validate/link/gc`、编码选项、插件状态目录和环境候选能力;0.3.0 不包含这些新增接口。源码试用时将 `fst` 替换为 `npm run fst --`。0.4.0 的输出校验停止补默认值,迁移说明见下文。发布结果见[版本记录](releases.md)。
8
+
7
9
  ## 从已安装的工具查阅规范
8
10
 
9
11
  完整 npm 与便携发行包随附离线资料,包含本文、控制流规范、服务示例和可安装的[零依赖动作插件](examples/action-plugin/README.md)。无需克隆源码仓库:
@@ -18,7 +20,7 @@ fst docs --export ./fishtools-manual
18
20
 
19
21
  `fst docs <主题>` 输出正文,`--path` 输出本地路径;`--export` 导出全部资料到新目录,已有目标会拒绝覆盖。资料按当前安装版本定位,不依赖当前工作目录,不启动插件或服务。TUI 中通过 `/docs` 选择主题,在内置阅读器查看。
20
22
 
21
- 导出目录保留相对链接,可离线浏览规范与示例。`plugins/`、`packages/`、`tests/` 中附带的源码仅供阅读,保留其 LICENSE;它们不是另一份可执行宿主或完整源码工作区。实际可安装示例位于 `docs/examples/action-plugin` 和 `examples/service-plugins`。内部 SDK 不承诺已作为独立公共 npm 包发布,首次开发可直接使用零依赖示例。
23
+ 导出目录保留相对链接,可离线浏览规范与示例。`plugins/`、`packages/`、`tests/` 中附带的源码仅供阅读,保留其 LICENSE;它们不是另一份可执行宿主或完整源码工作区。实际可安装示例位于 `docs/examples/action-plugin`、`docs/examples/script-plugin` 和 `examples/service-plugins`。内部 SDK 不承诺已作为独立公共 npm 包发布,首次开发可直接使用零依赖示例。
22
24
 
23
25
  ## 0.2.0:条件控制与运行观察
24
26
 
@@ -37,7 +39,7 @@ fst docs --export ./fishtools-manual
37
39
 
38
40
  | 约束 | 开发者要求 | 当前宿主检查 |
39
41
  | --- | --- | --- |
40
- | 标识与版本 | `id` 必须等于 npm 包名,`version` 必须等于包版本并使用 semver;升级时保持已有动作标识稳定 | 检查 ID 非空、重复;检查 SDK 和已声明插件依赖的版本兼容性;尚未自动比对包名/包版本 |
42
+ | 标识与版本 | `id` 必须等于 npm 包名,`version` 必须等于包版本并使用 semver;升级时保持已有动作标识稳定 | 宿主检查 ID 非空、重复和 SDK/依赖兼容性;`plugin validate` 比对包名/版本,开发引用也要求身份一致 |
41
43
  | 能力元数据 | 每个公开动作必须提供清楚的 `title`、`description`、`input`、`output`、`run` | 检查 `run` 是函数;编排前检查 input/output schema;标题和描述的质量由作者负责 |
42
44
  | 输入输出 | 显式提供有效的 JSON Schema,推荐对象形式声明类型、必填项、默认值和字段说明;无参数或无输出也要声明空对象 schema | 编排前校验 schema 声明,调用时用 Ajv 验证实际输入输出;返回值经过 JSON 序列化边界 |
43
45
  | 判定预设 | `conditions` 提供标题、相对输出路径、比较符和值;不提供可执行判定函数 | 加载时检查格式、比较符、危险路径及已声明的输出字段 |
@@ -53,6 +55,8 @@ JSON 序列化可能丢弃对象中的 `undefined`、函数或 Symbol,并将
53
55
 
54
56
  每份 schema 独立编译并缓存,`$id` 不会在不同插件或安装批次之间共享注册。插件升级可以保留相同 `$id` 并调整约束;定义内部的 `$ref` 正常解析,不支持隐式引用另一个插件曾注册的 schema。
55
57
 
58
+ 输入与配置校验继续应用 `default`;动作和交互命令的输出校验只验证实际返回值,不补默认值。旧插件若依靠输出 schema 自动生成 `ok` 等字段,必须在 `run` 返回值中明确赋值。诊断消息和 `details[].jsonPointer` 提供完整 JSON 指针(如 `/benchmark_config/model_name`),`schemaPath` 标明约束位置;`required` 放在顶层时只能报告顶层缺失,不会猜测作者原本想放在哪个子对象。
59
+
56
60
  无参数或无输出时,分别使用 `{type:'object', properties:{}, additionalProperties:false}`,动作返回 `{}`。JSON Schema 的布尔形式也受支持:`true` 接受任意值,`false` 拒绝所有值;为了生成字段表单与输出选择器,推荐明确声明对象和字段。缺省、`null`、数组、字符串和数值都不能代替 schema 声明。原有动作/子工作流的 `schemaVersion: 1` 格式保留;旧插件若要参与编排,需要补齐有效的 input/output 声明。正常返回且输出校验通过即执行成功,不要求返回额外的 `success:true`。
57
61
 
58
62
  ## 插件定义字段
@@ -125,10 +129,38 @@ fst plugin remove my-flow-plugin
125
129
 
126
130
  也支持 npm 包标识或本地 `.tgz`;Web“插件管理”提供相同入口。本地路径以服务器所在机器为准。
127
131
 
132
+ `plugin add <本地目录>` 是复制安装,源文件修改不会自动反映到已安装副本;重复 `add` 即可更新,无需先 `remove`。开发时使用下述引用模式。安装、移除、开发引用和 CLI 配置命令自动在管理模式下运行,不启动 runtime 服务;常驻 TUI/Web 保持维护模式保护。
133
+
128
134
  插件安装在 `.flow/installations/<随机安装批次ID>` 新目录,验证加载成功才切换状态,失败保留原配置。安装禁用 npm 生命周期脚本;TS 发布前编译,原生库及其目标平台资源由作者准备。核心不审核平台兼容性,也不自动重建原生库。工作流运行期间不能变更插件。
129
135
 
130
136
  业务 npm 库写入 `package.json.dependencies`,开发库写入 `devDependencies`。插件间依赖另外写在定义的 `dependencies: {'other-plugin': '^1.0.0'}`,用于宿主版本检查和打包闭包;被依赖插件也需安装并注册。
131
137
 
138
+ ### 创建、校验与开发引用
139
+
140
+ ```sh
141
+ fst plugin create my-plugin ./my-plugin
142
+ fst plugin validate ./my-plugin
143
+ fst plugin validate ./my-plugin --json
144
+ fst --project ./test-project plugin link ./my-plugin
145
+ ```
146
+
147
+ 脚手架生成 ESM 包、嵌套输入动作、业务判定、`node:test`、README 和 MIT LICENSE,不依赖内部 SDK,拒绝覆盖已有目录。按实际支持范围调整平台和架构声明。
148
+
149
+ `validate` 检查包身份、SDK 范围、schema、动作/命令、条件和环境等声明,不安装依赖、不执行动作或 `runtime.apply`。它会导入模块,因此模块顶层代码会执行,只校验可信插件。错误返回退出码 1;警告不改变成功退出码。未声明平台/架构、当前平台不匹配、同层未声明的 required 字段给出警告。JSON Schema 允许开放字段,因此 required 的位置提示不自动判定 schema 无效。校验无法代替硬件和业务环境测试。
150
+
151
+ `link` 将源码绝对路径保存到当前工作区,不复制源码,不安装源码目录的 npm 依赖;需要依赖时先在插件目录自行安装。源码修改后退出并重新启动 fst,TUI/Web 随新宿主读取修改;当前进程的模块缓存不会热更新。工作区迁移后需要重新 link。正常 `add` 同名包可替换开发引用,`remove` 解除引用,不删除源码。分发收集源码的发布文件和生产依赖快照,不把开发路径链接带给最终用户。
152
+
153
+ ### 安装批次清理与恢复
154
+
155
+ ```sh
156
+ fst plugin gc
157
+ fst plugin gc --apply
158
+ ```
159
+
160
+ 默认只预览。执行清理会重新核对状态,并在 `.flow/installation-backups/` 创建每个候选批次的 `.tgz` 备份后删除该批次。当前批次、上一批次及活动宿主的租约批次保留;未知目录和链接不清理。`.flow/plugins.previous.json` 保存上一次成功切换前的状态。备份也占用空间,应在确认不再需要恢复后自行删除。
161
+
162
+ 恢复时先退出该工作区所有 fst 进程,将对应备份解压回 `.flow/installations/`(归档自带批次子目录);需要退回上次插件列表时先另存当前 `plugins.json`,再用 `plugins.previous.json` 替换它。源码引用不包含源码副本,恢复前还需确保源码路径可访问。旧版 0.3.0 不登记租约,清理前必须退出旧版宿主。异常退出遗留 `.flow/plugin-mutation.lock` 时,确认没有活动修改进程再手工移除该空锁目录。
163
+
132
164
  ## 动作上下文
133
165
 
134
166
  服务插件的 `runtime` 初始化和生命周期见本文末尾;普通动作插件无需添加此字段。
@@ -140,6 +172,8 @@ fst plugin remove my-flow-plugin
140
172
  | `runId`、`stepId`、`callPath` | 运行和嵌套步骤定位 |
141
173
  | `outputDir` | 本次运行的可写结果目录 |
142
174
  | `resourceDir` | 插件包目录,用于定位脚本 |
175
+ | `projectDir` | 当前工作区根目录;可编辑便携包使用其包外工作区 |
176
+ | `stateDir` | 当前插件跨运行持久目录,与 outputDir 无关;只读项目或无应用的独立宿主为 undefined |
143
177
  | `getService(name)` | 获取本插件 runtime.inject/provides 声明的已就绪服务;未声明或不可用时抛错 |
144
178
  | `environments` | 按声明和来源选择解析的环境;包含解释器路径,随包环境另有资源根目录 |
145
179
  | `runProcess(file,args,options)` | 通用进程调用,自动关联当前日志与取消信号 |
@@ -148,6 +182,10 @@ fst plugin remove my-flow-plugin
148
182
 
149
183
  返回值必须可 JSON 序列化,输入输出经 Ajv 校验。插件在宿主进程中执行,属于可信代码;同步阻塞代码不能被取消信号抢占。
150
184
 
185
+ 可写应用在调用前创建 `.flow/plugin-state/<插件ID的SHA-256十六进制摘要>/`。固定长度目录避免 scoped 包名、Windows 大小写和长文件名问题;卸载不自动删除此目录,分发也不自动携带其中数据。插件自行处理原子写入、并发和数据版本。跨插件交换业务结果使用工作流输出或公开服务,不依赖其他插件的私有目录。只读精简包不创建持久状态,需要状态的插件应提示使用可编辑工作区。
186
+
187
+ `runProcess` 新增 `encoding`,默认 `utf8`,也可用 `utf16le`、`gbk` 等当前 Node TextDecoder 支持的编码;实时日志和返回文本采用同一编码,并正确处理跨块字符。示例:`runProcess('wsl',['-l','-v'],{encoding:'utf16le'})`,具体编码应以目标命令版本为准。Windows PowerShell 的编码和 CLIXML 是不同问题,宿主不自动猜编码或解析 CLIXML。输出上限仍按每个流的原始字节计量,默认 4 MiB;超限回收进程树并抛 `OUTPUT_LIMIT`,不返回伪装完整的截断结果。
188
+
151
189
  主面板默认展示步骤状态,Ctrl+O 展开或收起各步输入输出和技术日志。普通 `log` 与子进程 stdout/stderr 默认折叠;失败摘要始终直接显示。希望用户直接看到的进度或结果,显式使用 `await print('报告已保存', {file})`。`print` 沿用日志通道,以 `type: 'log', audience: 'user'` 持久化,工作流中自动带上步骤归属。动作和交互命令都支持,不应直接用 `console.log` 向 TUI 打印。
152
190
 
153
191
  若 Python 程序的部分输出需要直接展示,可使用 `runProcess(file, args, {onOutput: ({stream,message}) => stream === 'stdout' ? print(message) : undefined})`。回调按数据块触发;作者可先缓存成完整行再选择性 print。完整进程输出仍自动保存在诊断日志,print 的用户提示另外保留。写入 stderr 本身不等同执行失败,动作仍须按退出码决定抛错。
@@ -321,7 +359,7 @@ async function run({executable, text}, {resourceDir, runProcess, signal}) {
321
359
 
322
360
  ## 平台声明与责任边界
323
361
 
324
- 插件可声明 `platforms: ['win32', 'linux']` 和 `architectures: ['x64', 'arm64']`;未声明的旧插件继续可用。声明由作者负责,核心不据此拒绝加载、调用或导出;导出时显示声明不匹配的提示。核心检查接口、依赖收集与运行错误,不静态分析路径、系统 API,也不替开发者测试业务兼容性。
362
+ 插件可声明 `platforms: ['win32', 'linux']` 和 `architectures: ['x64', 'arm64']`;未声明的旧插件继续可用。声明由作者负责,核心不据此拒绝加载、调用或导出;CLI 启动、运行日志及导出计划都会提示对应的平台不匹配。核心检查接口、依赖收集与运行错误,不静态分析路径、系统 API,也不替开发者测试业务兼容性。
325
363
 
326
364
  ## 注册斜杠命令
327
365
 
@@ -359,7 +397,7 @@ environments: {
359
397
  python: {
360
398
  source: 'host',
361
399
  allowedSources: ['host', 'bundled'],
362
- executable: 'python3',
400
+ executable: ['python3', 'python'],
363
401
  version: '>=3.11',
364
402
  packages: { numpy: '2.x' },
365
403
  artifacts: {
@@ -377,12 +415,14 @@ environments: {
377
415
  ```
378
416
 
379
417
  - `host`:目标机器或容器内部提供;不携带 artifacts,也不自动检查/安装依赖。插件负责检查版本、库、设备和错误提示。
380
- - `bundled`:作者提供完整、可迁移的目标环境目录(包括所需库与许可证),工具按目标收集;目录和 executable 均为使用 `/` 分隔的相对路径。缺少所选资源、越界或目录循环时报打包错误。核心不自动下载 Python 或运行 pip。
418
+ - `bundled`:作者提供完整、可迁移的目标环境目录(包括所需库与许可证),工具按目标收集;目录和 executable 均为使用 `/` 分隔的相对路径。默认采用 bundled 时必须声明非空 `artifacts`;静态校验检查各目标项的字段和包内路径,但不要求包含开发机平台。实际导出缺少所选资源或遇到目录循环时仍会报错。核心不自动下载 Python 或运行 pip。
381
419
  - `tool`:首版只允许环境名 `node`,使用 Fishtools 自带的 Node。
382
420
  - `version`、`packages` 为作者元数据;宿主不将它们当作已验证的事实。`allowedSources` 决定导出时可以切换哪些来源,缺省只能使用 source。
383
421
 
384
422
  动作使用上下文 `environments.python.executable` 获得最终解释器路径,随包环境另有 `root`。继续通过 `runProcess(executable, args, {signal})` 调用。声明不会替换插件代码里自行写死的命令。
385
423
 
424
+ host 来源可声明有序候选数组,调用前按当前工作区和 PATH 选择第一个存在的程序,返回其绝对路径;不承诺该程序版本满足业务要求。单字符串声明继续透传。用户可在 `flow.project.json` 设置 `environments: {"插件ID": {"python": {"executable": "F:/miniconda/envs/example/python.exe"}}}`;显式覆盖只用于 host,找不到就报错,不回退到其他 Python。`source` 覆盖仍可单独使用。候选在目标机调用时解析,打包不会固化本机候选解析结果。
425
+
386
426
  完整插件的所有动作和命令随插件保留,所以其动作声明的环境均参与计划。不同动作的同名环境可以有不同资源,但导出时同一个插件/环境名的来源覆盖统一生效;允许来源取交集。相同资源路径只复制一次,不自动合并不同 Python 环境或推断版本兼容性。
387
427
 
388
428
  TUI `/pack` 选择来源并展示资源字节数;CLI 支持 `--plan` 和 `--environments 来源.json`:
@@ -405,7 +445,7 @@ TUI `/pack` 选择来源并展示资源字节数;CLI 支持 `--plan` 和 `--en
405
445
  6. **部署检查**:导出包含该动作的工作流,在包外目录运行;验证路径中有空格和中文、包目录只读且结果目录可写的情况。声明支持 Windows 和 Linux 时,应分别实测;依赖设备或驱动的能力注明所需环境和未验证项。
406
446
  7. **文档检查**:插件 README 写清支持平台、环境前提、配置示例、输入输出、错误行为、副作用、许可证与兼容范围。改变既有输入输出或行为时说明迁移方式并合理升级版本。
407
447
 
408
- 插件无需伪装成跨平台:仅适用 Linux 的 NPU 检查可以明确声明 Linux 前提,在其他平台给出可理解的错误。首版没有通用的 `platforms` 元数据执行门禁,不要添加一个未经宿主实现的字段后假定平台限制会自动生效。
448
+ 发布前先运行 `fst plugin validate <目录>`,再按平台声明逐项实际测试。仅适用 Linux 的 NPU 插件应明确声明 Linux;宿主对声明不匹配给出告警并记录到运行日志,继续允许执行。没有声明的旧插件继续兼容;不会根据描述中的 NPU、驱动等关键词猜测兼容性,也没有 `reject/allow/warn` 配置门禁。
409
449
 
410
450
  ## 参考实现与当前边界
411
451
 
@@ -414,8 +454,9 @@ TUI `/pack` 选择来源并展示资源字节数;CLI 支持 `--plan` 和 `--en
414
454
  - [SDK](../packages/sdk/index.js):`definePlugin`、`FlowError` 与 SDK 版本。
415
455
  - [宿主校验](../packages/core/src/host.js):加载、依赖、配置、动作输入输出和服务名检查。
416
456
  - [外部插件接入测试](../tests/application.test.js):仓库外插件安装、运行与移除。
457
+ - [完整 Python 脚本插件](examples/script-plugin/README.md):嵌套输入、解释器候选、业务不通过、异常和条件预设。
417
458
 
418
- 当前已有接入文档、可参考实现和运行时校验;尚未提供 `fst plugin create` 脚手架、`fst plugin lint` 命令、独立的完整插件定义 schema 或插件市场审核流程。SDK 也尚未独立发布到公共 npm;不要把仓库内部包名理解为已经可以在线安装。
459
+ 当前源码提供 `plugin create`、`plugin validate`、开发引用和批次回收;没有单独的 `plugin lint`、运行中热重载、插件市场审核流程。SDK 尚未独立发布到公共 npm;独立插件使用普通 ESM 默认导出即可。
419
460
 
420
461
  ## Cordis 共享服务与生命周期
421
462
 
@@ -457,7 +498,7 @@ Fishtools 等待 `ctx.on('dispose', async () => ...)` 的清理完成并报告
457
498
  ### 维护与 Web 资源
458
499
 
459
500
  - 有 runtime 插件时,安装、移除或修改插件配置会要求先进入维护模式,避免同时打开两套连接。
460
- - TUI `/plugins` 可进入维护模式并恢复服务;CLI 使用 `fst --maintenance plugin add ...`、`fst --maintenance configure ...`。维护模式不持久化,默认重启恢复服务。
501
+ - TUI `/plugins` 可进入维护模式并恢复服务;CLI 的 add/remove/link/configure 自动使用管理模式,也兼容显式 `--maintenance`。维护模式不持久化,默认重启恢复服务。
461
502
  - 维护模式停止 runtime 插件的动作和命令,普通插件仍可使用;声明校验仍执行,不能借维护模式加载无效插件定义。
462
503
  - 现有 `services.web` 仍为兼容的启动工厂;应用持有其返回的 close 句柄。`app.close()` 先关闭这些句柄,再关闭业务宿主,重复关闭安全。
463
504
  - 打包选择包含 Web 时,按 `services.web` 声明选取实际提供者,连同其传递插件依赖一起导出,不要求官方包名。完整便携包关闭 Web 选项时,仅省略非必需的 Web 提供者;工作流或其他插件确实依赖它时仍保留。
@@ -2,6 +2,17 @@
2
2
 
3
3
  产品名称 Fishtools,公共 npm 包名 `@yanglaofish/fishtools`,启动命令 `fst`。`0.x` 定位为早期可用版本。内部 `@mytools/*` 包随主包捆绑,不单独发布;内部插件 API 版本独立维护。
4
4
 
5
+ ## 0.4.0 第三方插件开发体验
6
+
7
+ - 增加 `fst plugin create/validate/link/gc`:生成零依赖插件、离线检查声明、引用开发源码、预览并备份清理旧安装批次。源码修改后需重启宿主。
8
+ - schema 路径校验统一支持带类型的动态字段;错误给出完整 JSON 指针和约束位置。动作及命令输出只验证,不再填充默认值;输入和配置保留默认值。
9
+ - `runProcess` 支持显式编码并统一实时日志与返回文本。`host` 环境支持有序解释器候选及显式路径覆盖;显式路径不存在时不回退。
10
+ - 插件获得按工作区及 ID 隔离的 `stateDir`,平台不匹配给告警;独立 CLI 管理命令自动使用维护模式。新增可安装的 Python 脚本插件和中文开发说明。
11
+
12
+ 升级时退出旧版宿主,再使用批次清理;旧版 0.3.0 不登记活动安装租约。若插件依赖输出 schema 的 `default`,请在动作返回值中明确填写对应字段。工作流格式和内部 SDK 版本不变;没有加入运行中热重载或平台强制拒绝策略。
13
+
14
+ 用户已于 2026-10-12 授权审查、验证后推送和发布;是否发布完成以本版本 GitHub Release 与验收记录为准。
15
+
5
16
  ## 0.3.0 终端交互与插件输出
6
17
 
7
18
  - 终端顶层按工作流、插件、工具和配置组织;命令历史保留未提交草稿,工作流编辑与执行互不覆盖。
@@ -1,9 +1,11 @@
1
1
  # Fishtools 路线图与当前状态
2
2
 
3
- 更新:2026-10-11,条件控制与运行观察阶段。本文是当前状态入口;早期设计和实施计划保留历史背景,发生冲突时以最新明确决策及验收记录为准。
3
+ 更新:2026-10-12,第三方插件开发体验阶段。本文是当前状态入口;早期设计和实施计划保留历史背景,发生冲突时以最新明确决策及验收记录为准。
4
4
 
5
5
  ## 当前所处阶段
6
6
 
7
+ 0.4.0 已纳入 GitHub #1/#2 的插件创建、校验、源码引用、批次回收、状态目录、环境候选及编码/契约修复,并进入发布验收。见[本轮规范](superpowers/specs/2026-10-12-plugin-developer-experience.md)、[实施计划](superpowers/plans/2026-10-12-plugin-developer-experience.md)与[验收记录](verification.md),发布结果以[版本记录](releases.md)为准。运行时热重载、长度条件、截断模式及平台拒绝策略留待后续。以下“本地试用”描述记录之前日志阶段的历史过程。
8
+
7
9
  当前增量:TUI 日志阅读与导航修复,处于**本地试用、待用户体验确认**阶段。首页 F4 进入统一运行记录,支持多个工作流的多次执行;不使用 `/resume`,避免与未来 LLM 会话恢复混淆。实时与历史使用同一阅读面板,默认简洁结果/错误,完整诊断按需查看。试用方式见 README,用户确认前不发布新版本。
8
10
 
9
11
  后续交互调整:`/workflows` 收纳新建、编辑、保存和可恢复删除;`/config` 配置工具,`/plugin` 管理插件及插件配置,插件名进入二级能力菜单。`/run` 补全工作流,执行过程留在主面板,多任务与配置操作共存;F4/日志页供详细回看。仍为本地试用,未发布。
@@ -0,0 +1,50 @@
1
+ # 第三方插件开发体验实施计划
2
+
3
+ > 执行方式:使用测试先行;独立模块按 superpowers:dispatching-parallel-agents 并行实施,宿主集成在当前会话完成。用户已经授权实施。
4
+
5
+ **目标:** 修复两个 issue 的明确缺陷,补齐第三方插件创建、校验、开发引用及宿主公共能力。
6
+
7
+ **架构:** schema 路径与校验共用一个契约层;开发工具复用加载契约且不启动服务;应用层管理插件批次与工作区状态。保持现有动作、工作流及 Cordis 生命周期结构。
8
+
9
+ **技术栈:** Node.js >=24.15.0、ESM、Ajv、Execa、Cordis、node:test。
10
+
11
+ **规范:** ../specs/2026-10-12-plugin-developer-experience.md
12
+
13
+ ## 全局约束与审查重点
14
+
15
+ 中文文档及注释。保持 utf8 默认、维护模式保护和输出上限;不实现运行时热重载、长度伪字段、输出截断及关键词平台推断。只在受控临时工作区测试数据操作。重点检查动态键嵌套类型、显式解释器不回退、Scoped npm ID 状态目录、失效源码链接、清理时恢复批次和多进程安全。
16
+
17
+ ## 任务 1:契约与诊断
18
+
19
+ 文件:validation.js、contracts.js、workflows.js、新 schema-path.js 及契约测试。
20
+ 接口:validate(schema,value,label,{useDefaults=true});共用 schema 路径解析。
21
+ - [x] 增加动态字段、非法嵌套、完整字段路径、输出不补默认值的失败测试。
22
+ - [x] 实现共用解析与校验策略,定向测试通过。
23
+
24
+ ## 任务 2:进程编码
25
+
26
+ 文件:process.js、tests/process.test.js。
27
+ 接口:runProcess(file,args,{encoding='utf8',...})。
28
+ - [x] 增加 UTF16LE 分块及编码一致性的失败测试。
29
+ - [x] 实现统一解码,验证取消/超时/字节限制回归。
30
+
31
+ ## 任务 3:插件工具
32
+
33
+ 文件:新 plugin-tools.js、fst.js、开发工具测试。
34
+ 接口:validatePluginDirectory(directory)、createPlugin(name,directory)。
35
+ - [x] 添加身份/schema/平台诊断、无 runtime 副作用和脚手架可安装的失败测试。
36
+ - [x] 实现 validate/create 与 CLI 输出及退出码,验证生成插件。
37
+
38
+ ## 任务 4:宿主和开发循环
39
+
40
+ 文件:plugins.js、application.js、host.js、environments.js、fst.js、pack 及测试。
41
+ - [x] 添加源码引用重启、状态隔离、候选解释器、CLI 管理模式和安全批次清理的失败测试。
42
+ - [x] 实现 link、受控清理预览/执行、CLI 管理模式、stateDir、平台告警与环境解析。
43
+ - [x] 验证依赖加载、失败状态保持和分发快照。
44
+
45
+ ## 任务 5:文档与整体验收
46
+
47
+ 文件:plugin-development.md、roadmap.md、verification.md、docs/examples 新真实脚本插件及离线文档收集。
48
+ - [x] 补齐公开契约、迁移说明、开发循环和脚本示例。
49
+ - [x] 完整 npm test、npm run build、npm run dist:npm,审阅所有差异。
50
+ - [x] 在功能分支提交并报告结果、后置能力与实际验证范围。
@@ -0,0 +1,20 @@
1
+ # 0.4.0 发布前双轴审查
2
+
3
+ 用户于 2026-10-12 要求使用 `code-review`,验证处理后推送并发包。固定基线为 `v0.3.0`(提交 `681ebd1`),被审查提交为 `addaece`,命令为 `git diff v0.3.0...addaece`。需求源是本轮插件开发体验规范、GitHub #1/#2 和用户附件;后续修复另做定向复核。
4
+
5
+ ## Standards
6
+
7
+ 没有发现明确的文档规范违反;中文说明、分支管理、安装状态备份和清理前备份均符合要求。未发现需要为本次发布安排重构的代码异味。
8
+
9
+ 发现 1 项 P2 正确性问题:Windows 的 `which` 对裸候选自动优先搜索宿主启动目录,可能误选同名解释器。已改为按工作区和 PATH 构造绝对路径后逐项查找;回归测试用子进程隔离启动目录与工作区,覆盖同名冲突、相对 PATH、显式路径及缺失不回退。新增两项测试先失败,修复后环境、宿主和进程定向 18/18 通过。
10
+
11
+ ## Spec
12
+
13
+ 发现 2 项 P2:
14
+
15
+ 1. 规范要求带类型的动态键,但 `type: ['object','null']` 的合法动态字段被路径解析器拒绝。现在只要联合类型允许 object,就继续按动态字段 schema 检查;纯标量及关闭对象中的未知字段仍拒绝。新增回归先失败,修复后覆盖 Ajv 输出、字段解析、条件预设和工作流绑定,相关 27/27 通过。
16
+ 2. Windows 解释器候选未按工作区查找,与开发手册冲突;与 Standards 轴同一问题,按上述修复和验证处理。
17
+
18
+ 其余采纳需求有实现,未发现额外范围扩张。热重载、长度伪字段、CLIXML 转换、自动猜编码、截断及强制平台门禁继续后置。
19
+
20
+ 汇总:Standards 1 项 P2,Spec 2 项 P2,其中 1 项重复,共 2 个独立问题,均已修复。发布仍需通过最终完整测试和既有双平台发布工作流。
@@ -0,0 +1,22 @@
1
+ # 第三方插件开发体验与宿主契约
2
+
3
+ 依据:GitHub #1、#2,用户提供的 fst-issue-draft.md,以及 2026-10-12 评审。用户已授权实施。
4
+
5
+ ## 本轮范围
6
+
7
+ - 统一工作流绑定和条件预设的 schema 路径解析,支持带类型的动态键,拒绝关闭对象的未知字段;长度计算留待后续。
8
+ - 输入/配置继续填默认值,动作/命令输出只验证。诊断提供完整 JSON 指针、缺失字段及 schema 位置。
9
+ - runProcess 的 encoding 同时作用于实时日志和返回文本,默认 utf8,支持 utf16le 与常用 Windows 编码;维持取消、字节上限、超时。自动猜编码、CLIXML 转换和截断模式不在本轮。
10
+ - plugin validate <dir> 提供人类可读和 JSON 报告、退出码,检查包身份、SDK、schema、动作、条件、环境与平台声明;不启动动作或 runtime。导入可信插件会执行模块顶层代码。
11
+ - plugin create <name> 生成可独立安装的 ESM 包、真实可运行的动作、测试、README、MIT LICENSE;平台声明明确,不依赖未公开的 SDK。
12
+ - plugin link <dir> 使用直接源码引用,重启宿主后加载修改,支持移除及分发时复制快照。运行中热重载后置。
13
+ - 独立 CLI 的 add/remove/link/configure 使用管理模式;保留常驻宿主维护模式保护,不增加 gate:false。
14
+ - 安装批次清理显式预览并保留恢复批次,不删除当前引用及不能确认安全的目录;备份插件状态文件,清理只针对本项目 installations 内目录。
15
+ - 动作和命令获得稳定的 projectDir、按插件隔离的 stateDir,状态随可写工作区,卸载不自动删除,不自动进入分发包。
16
+ - host 环境支持显式解释器覆盖和有序候选,显式路径失败不回退;tool/bundled 的语义保持。
17
+ - 平台/架构不匹配给明确告警,旧插件缺省保持兼容;不根据 NPU 等关键词推断平台。
18
+ - 增加 Python 脚本、嵌套输入、业务失败和条件预设的完整插件示例及离线文档。
19
+
20
+ ## 验收
21
+
22
+ 先复现缺陷再修复;定向测试覆盖错误路径、候选选择、UTF16 分块、动态键类型、无 runtime 副作用的校验、源码修改后重启、状态隔离、清理恢复保护。最后执行完整 npm test、build 与分发检查。未取得真实业务插件源码,不冒充已经完成其硬件验收。本轮完成源码演进,不自动发布新 npm 版本。
@@ -1,5 +1,22 @@
1
1
  # 首版验收记录
2
2
 
3
+ ## 0.4.0 发布前验证(2026-10-12)
4
+
5
+ - 用户授权使用 `code-review` 验证处理后推送和发包。以 `v0.3.0` 为固定基线并行审查 Standards / Spec;记录见[双轴审查](superpowers/reviews/2026-10-12-plugin-release-review.md)。两个独立 P2 均已先失败复现再修复:可空对象的动态字段解析,以及 Windows 候选解释器错误优先搜索宿主启动目录。
6
+ - `npm run dist:npm` 构建成功,版本和 CLI 同步为 0.4.0;归档含 276 个包。设置 `FISHTOOLS_TEST_NPM_ARCHIVE` 指向该归档后,完整 `npm test` **230/230 通过**,零失败、零跳过,159.3 秒,包括离线全局安装、脱离源码调用和再次导出。
7
+ - 输出默认值迁移、源码引用需重启、旧版宿主清理前退出等说明已更新。远端双平台、便携包、Docker 及 npm 发布结果待正式发布工作流完成后追加。
8
+
9
+ ## 2026-10-12 第三方插件开发体验(本地未发布)
10
+
11
+ - 分支 `codex/plugin-developer-experience`,基线 `681ebd1`。依据 GitHub #1、#2 及用户提供的 `fst-issue-draft.md`,实现插件创建、离线校验、源码引用、安装批次清理,并修复 schema 路径、输出默认值、编码与宿主环境契约。
12
+ - 开发循环测试实际执行 CLI 创建、校验、生成插件测试、独立安装及工作流调用;源码修改后新进程加载新代码,源码丢失仍可移除引用。打包复制开发插件快照,排除 `.flow` 私有状态,后续源码变化不影响快照。
13
+ - 清理测试覆盖预览不修改、当前/恢复/活动批次保留、目录链接拒绝,并实际解压清理备份确认文件可恢复。多进程配置更新测试确认不会用旧快照覆盖其他插件配置或日志设置。
14
+ - Python 示例使用真实 Python 解释器执行,另以可控子进程覆盖业务未通过、异常与取消协议;声明支持候选解释器和显式覆盖,显式路径不存在时不回退。
15
+ - 审查发现并修复随包环境缺失 `artifacts` 却通过静态校验的问题,新增失败复现后通过;合法的非当前平台资源仍可通过。合法长 npm ID 的状态目录也已补失败测试,改用固定长度哈希隔离。最终独立复核未发现剩余 P1/P2 阻断项。
16
+ - 修复后完整 `npm test` **227/227 通过**,零失败、零跳过,耗时 194.2 秒;包括 npm 离线全局安装、脱离源码运行并再次导出的集成验收。
17
+ - `npm run dist:npm` 成功,包含 Web 构建与许可收集;最终本地归档大小 9,493,874 字节、276 个包。核对新增开发工具模块、直接依赖及 Python 示例均已进入归档。版本号尚未调整,`dist/yanglaofish-fishtools-0.3.0.tgz` 仅供本次开发验收,不代表重新发布或替换公开 0.3.0。
18
+ - 本轮不包含真实 vLLM/昇腾 NPU 硬件验收,也没有运行中热重载、自动猜编码、CLIXML 转换、输出截断或平台拒绝门禁。新增能力尚未发布到 npm,当前公开 0.3.0 不包含这些接口。
19
+
3
20
  ## 0.3.0 发布前验证(2026-10-12)
4
21
 
5
22
  - 以 `v0.2.0` 为基线审查本轮代码和需求;修复离线手册缺失源码链接、并行取消测试时序、主面板密集日志重复全量快照与重绘,以及展开详情缺少完整错误链。