@yanglaofish/fishtools 0.4.0 → 0.5.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.
- package/README.md +33 -5
- package/bin/fst.js +1 -1
- package/manual/README.md +33 -5
- package/manual/docs/deployment.md +3 -3
- package/manual/docs/kernel-generation.md +97 -0
- package/manual/docs/modules.md +57 -0
- package/manual/docs/plugin-development.md +120 -10
- package/manual/docs/releases.md +12 -0
- package/manual/docs/research/2026-10-11-plugin-kernel-capabilities.md +6 -6
- package/manual/docs/roadmap.md +14 -3
- package/manual/docs/superpowers/plans/2026-10-09-workflow-mvp.md +5 -5
- package/manual/docs/superpowers/plans/2026-10-11-public-plugin-fixes.md +2 -2
- package/manual/docs/superpowers/plans/2026-10-12-kernel-generation.md +22 -0
- package/manual/docs/superpowers/plans/2026-10-12-modular-kernel.md +40 -0
- package/manual/docs/superpowers/reviews/2026-10-12-kernel-generation-review.md +27 -0
- package/manual/docs/superpowers/reviews/2026-10-12-modular-kernel-review.md +32 -0
- package/manual/docs/superpowers/reviews/2026-10-13-kernel-runtime-release-review.md +19 -0
- package/manual/docs/superpowers/specs/2026-10-12-action-network-policy-design.md +52 -0
- package/manual/docs/superpowers/specs/2026-10-12-kernel-generation-design.md +38 -0
- package/manual/docs/superpowers/specs/2026-10-12-modular-kernel-design.md +70 -0
- package/manual/docs/superpowers/specs/2026-10-12-plugin-readiness-design.md +21 -0
- package/manual/docs/superpowers/specs/2026-10-12-runtime-maintenance-granularity-design.md +35 -0
- package/manual/docs/superpowers/specs/2026-10-12-workflow-variation-design.md +19 -0
- package/manual/docs/verification.md +42 -2
- package/manual/packages/core/README.md +44 -0
- package/manual/packages/core/package.json +38 -0
- package/manual/packages/core/src/application.js +242 -85
- package/manual/packages/core/src/bundle.js +2 -0
- package/manual/packages/core/src/development-watch-worker.js +69 -0
- package/manual/packages/core/src/development.js +146 -0
- package/manual/packages/core/src/environments.js +2 -0
- package/manual/packages/core/src/export-snapshot.js +42 -0
- package/manual/packages/core/src/plugin-update.js +108 -0
- package/manual/packages/core/src/process.js +2 -0
- package/manual/packages/core/src/resources.js +31 -0
- package/manual/packages/core/src/version.js +2 -0
- package/manual/packages/fst-cli/LICENSE +21 -0
- package/manual/packages/fst-cli/README.md +54 -0
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/bin/fst.js +55 -23
- package/manual/packages/fst-cli/package.json +49 -0
- package/manual/packages/fst-cli/src/development.js +53 -0
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/model.js +1 -1
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/navigation.js +1 -1
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/presentation.js +9 -1
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/run-feed.js +31 -5
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/run-viewer.js +9 -7
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/schema.js +1 -1
- package/manual/packages/{core → fst-cli}/src/terminal/session.js +137 -9
- package/manual/packages/{core → fst-cli}/src/terminal/view.js +20 -3
- package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/workflow-menu.js +17 -2
- package/manual/packages/fst-devtools/LICENSE +21 -0
- package/manual/packages/fst-devtools/README.md +28 -0
- package/manual/packages/fst-devtools/package.json +29 -0
- package/{node_modules/@mytools/core → manual/packages/fst-devtools}/src/documentation.js +3 -1
- package/manual/packages/fst-devtools/src/plugin-quality.js +136 -0
- package/{node_modules/@mytools/core → manual/packages/fst-devtools}/src/plugin-tools.js +24 -5
- package/manual/packages/fst-logs/LICENSE +21 -0
- package/manual/packages/fst-logs/README.md +56 -0
- package/manual/packages/fst-logs/package.json +24 -0
- package/manual/packages/fst-logs/src/log-bounds.js +91 -0
- package/manual/packages/fst-logs/src/run-logs.js +239 -0
- package/manual/packages/fst-platform/LICENSE +21 -0
- package/manual/packages/fst-platform/README.md +67 -0
- package/manual/packages/fst-platform/package.json +33 -0
- package/manual/packages/fst-platform/src/bundle.js +17 -0
- package/manual/packages/fst-platform/src/environments.js +67 -0
- package/manual/packages/fst-platform/src/file-probe-engine.js +183 -0
- package/manual/packages/fst-platform/src/file-probe-worker.js +43 -0
- package/manual/packages/fst-platform/src/file-probe.js +6 -0
- package/manual/packages/fst-platform/src/json.js +5 -0
- package/manual/packages/fst-platform/src/network.js +199 -0
- package/manual/packages/fst-platform/src/npm.js +11 -0
- package/manual/packages/fst-platform/src/process.js +110 -0
- package/manual/packages/fst-plugin/LICENSE +21 -0
- package/manual/packages/fst-plugin/README.md +29 -0
- package/manual/packages/fst-plugin/package.json +29 -0
- package/{node_modules/@mytools/core → manual/packages/fst-plugin}/src/contracts.js +30 -3
- package/manual/packages/fst-plugin/src/host.js +232 -0
- package/manual/packages/fst-plugin/src/loader.js +21 -0
- package/manual/packages/fst-plugin/src/privileges.js +91 -0
- package/{node_modules/@mytools/core → manual/packages/fst-plugin}/src/runtime.js +20 -4
- package/manual/packages/fst-workflow/LICENSE +21 -0
- package/manual/packages/fst-workflow/README.md +28 -0
- package/manual/packages/fst-workflow/package.json +24 -0
- package/{node_modules/@mytools/core → manual/packages/fst-workflow}/src/control.js +3 -2
- package/manual/packages/{core → fst-workflow}/src/engine.js +2 -2
- package/manual/packages/fst-workspace/LICENSE +21 -0
- package/manual/packages/fst-workspace/README.md +32 -0
- package/manual/packages/fst-workspace/package.json +34 -0
- package/{node_modules/@mytools/core → manual/packages/fst-workspace}/src/bundle-workspace.js +1 -1
- package/manual/packages/fst-workspace/src/index.js +3 -0
- package/{node_modules/@mytools/core → manual/packages/fst-workspace}/src/plugins.js +6 -36
- package/{node_modules/@mytools/core → manual/packages/fst-workspace}/src/workflows.js +40 -7
- package/manual/packages/pack/LICENSE +21 -0
- package/manual/packages/pack/README.md +31 -0
- package/manual/packages/pack/archive.js +15 -0
- package/manual/packages/pack/dependencies.js +105 -0
- package/manual/packages/pack/environments.js +50 -0
- package/manual/packages/pack/index.js +103 -0
- package/manual/packages/pack/package.json +29 -0
- package/manual/packages/pack/runtime.js +61 -0
- package/manual/packages/sdk/README.md +31 -0
- package/manual/packages/sdk/conditions.js +1 -0
- package/manual/packages/sdk/package.json +23 -1
- package/manual/plugins/web/README.md +29 -0
- package/manual/tests/application.test.js +6 -4
- package/node_modules/@mytools/core/README.md +44 -0
- package/node_modules/@mytools/core/package.json +17 -17
- package/node_modules/@mytools/core/src/application.js +242 -85
- package/node_modules/@mytools/core/src/bundle.js +2 -17
- package/node_modules/@mytools/core/src/development-watch-worker.js +69 -0
- package/node_modules/@mytools/core/src/development.js +146 -0
- package/node_modules/@mytools/core/src/environments.js +2 -67
- package/node_modules/@mytools/core/src/export-snapshot.js +42 -0
- package/node_modules/@mytools/core/src/plugin-update.js +108 -0
- package/node_modules/@mytools/core/src/process.js +2 -80
- package/node_modules/@mytools/core/src/version.js +1 -1
- package/node_modules/@mytools/fst-cli/LICENSE +21 -0
- package/node_modules/@mytools/fst-cli/README.md +54 -0
- package/node_modules/@mytools/fst-cli/bin/fst.js +124 -0
- package/node_modules/@mytools/fst-cli/package.json +49 -0
- package/node_modules/@mytools/fst-cli/src/cli-run.js +12 -0
- package/node_modules/@mytools/fst-cli/src/development.js +53 -0
- package/node_modules/@mytools/fst-cli/src/terminal/conditions.js +32 -0
- package/node_modules/@mytools/fst-cli/src/terminal/log-viewer.js +45 -0
- package/node_modules/@mytools/fst-cli/src/terminal/model.js +104 -0
- package/node_modules/@mytools/fst-cli/src/terminal/navigation.js +17 -0
- package/node_modules/@mytools/fst-cli/src/terminal/presentation.js +50 -0
- package/{manual/packages/core → node_modules/@mytools/fst-cli}/src/terminal/run-feed.js +31 -5
- package/node_modules/@mytools/fst-cli/src/terminal/run-presentation.js +60 -0
- package/node_modules/@mytools/fst-cli/src/terminal/run-viewer.js +106 -0
- package/node_modules/@mytools/fst-cli/src/terminal/schema.js +52 -0
- package/node_modules/@mytools/{core → fst-cli}/src/terminal/session.js +137 -9
- package/node_modules/@mytools/fst-cli/src/terminal/theme.js +29 -0
- package/node_modules/@mytools/{core → fst-cli}/src/terminal/view.js +20 -3
- package/node_modules/@mytools/fst-cli/src/terminal/workflow-menu.js +65 -0
- package/node_modules/@mytools/fst-devtools/LICENSE +21 -0
- package/node_modules/@mytools/fst-devtools/README.md +28 -0
- package/node_modules/@mytools/fst-devtools/package.json +29 -0
- package/node_modules/@mytools/fst-devtools/src/documentation.js +67 -0
- package/node_modules/@mytools/fst-devtools/src/plugin-quality.js +136 -0
- package/node_modules/@mytools/fst-devtools/src/plugin-tools.js +152 -0
- package/node_modules/@mytools/fst-logs/LICENSE +21 -0
- package/node_modules/@mytools/fst-logs/README.md +56 -0
- package/node_modules/@mytools/fst-logs/package.json +24 -0
- package/node_modules/@mytools/fst-logs/src/log-bounds.js +91 -0
- package/node_modules/@mytools/fst-logs/src/markdown-log.js +55 -0
- package/node_modules/@mytools/fst-logs/src/run-logs.js +239 -0
- package/node_modules/@mytools/fst-platform/LICENSE +21 -0
- package/node_modules/@mytools/fst-platform/README.md +67 -0
- package/node_modules/@mytools/fst-platform/package.json +33 -0
- package/node_modules/@mytools/fst-platform/src/bundle.js +17 -0
- package/node_modules/@mytools/fst-platform/src/environments.js +67 -0
- package/node_modules/@mytools/fst-platform/src/file-probe-engine.js +183 -0
- package/node_modules/@mytools/fst-platform/src/file-probe-worker.js +43 -0
- package/node_modules/@mytools/fst-platform/src/file-probe.js +6 -0
- package/node_modules/@mytools/fst-platform/src/json.js +5 -0
- package/node_modules/@mytools/fst-platform/src/network.js +199 -0
- package/node_modules/@mytools/fst-platform/src/npm.js +11 -0
- package/node_modules/@mytools/fst-platform/src/process.js +110 -0
- package/node_modules/@mytools/fst-plugin/LICENSE +21 -0
- package/node_modules/@mytools/fst-plugin/README.md +29 -0
- package/node_modules/@mytools/fst-plugin/package.json +29 -0
- package/node_modules/@mytools/fst-plugin/src/contracts.js +86 -0
- package/node_modules/@mytools/fst-plugin/src/host.js +232 -0
- package/node_modules/@mytools/fst-plugin/src/loader.js +21 -0
- package/node_modules/@mytools/fst-plugin/src/privileges.js +91 -0
- package/{manual/packages/core → node_modules/@mytools/fst-plugin}/src/runtime.js +20 -4
- package/node_modules/@mytools/fst-workflow/LICENSE +21 -0
- package/node_modules/@mytools/fst-workflow/README.md +28 -0
- package/node_modules/@mytools/fst-workflow/package.json +24 -0
- package/node_modules/@mytools/fst-workflow/src/control.js +64 -0
- package/node_modules/@mytools/{core → fst-workflow}/src/engine.js +2 -2
- package/node_modules/@mytools/fst-workspace/LICENSE +21 -0
- package/node_modules/@mytools/fst-workspace/README.md +32 -0
- package/node_modules/@mytools/fst-workspace/package.json +34 -0
- package/node_modules/@mytools/fst-workspace/src/bundle-workspace.js +39 -0
- package/node_modules/@mytools/fst-workspace/src/index.js +3 -0
- package/node_modules/@mytools/fst-workspace/src/plugin-installations.js +84 -0
- package/node_modules/@mytools/fst-workspace/src/plugins.js +35 -0
- package/node_modules/@mytools/fst-workspace/src/project.js +29 -0
- package/node_modules/@mytools/fst-workspace/src/workflows.js +150 -0
- package/node_modules/@mytools/fst-workspace/templates/control-demo.yaml +47 -0
- package/node_modules/@mytools/fst-workspace/templates/hello.yaml +35 -0
- package/node_modules/@mytools/fst-workspace/templates/python-check.yaml +26 -0
- package/node_modules/@mytools/fst-workspace/templates/system-check.yaml +11 -0
- package/node_modules/@mytools/pack/README.md +31 -0
- package/node_modules/@mytools/pack/dependencies.js +7 -2
- package/node_modules/@mytools/pack/environments.js +1 -1
- package/node_modules/@mytools/pack/index.js +33 -25
- package/node_modules/@mytools/pack/package.json +29 -1
- package/node_modules/@mytools/sdk/README.md +31 -0
- package/node_modules/@mytools/sdk/conditions.js +1 -0
- package/node_modules/@mytools/sdk/diagnostics.js +27 -0
- package/node_modules/@mytools/sdk/package.json +23 -1
- package/node_modules/@mytools/sdk/schema-path.js +31 -0
- package/node_modules/@mytools/sdk/validation.js +78 -0
- package/node_modules/@mytools/web/README.md +29 -0
- package/node_modules/@mytools/web/package.json +7 -0
- package/node_modules/@mytools/web/public/THIRD_PARTY_NOTICES.txt +1398 -1199
- package/node_modules/@mytools/web/public/assets/index-BaVzHycP.js +70 -0
- package/node_modules/@mytools/web/public/assets/index-DA8Ae92t.css +1 -0
- package/node_modules/@mytools/web/public/index.html +2 -2
- package/node_modules/@mytools/web/server.js +24 -17
- package/node_modules/@mytools/web/src/model.js +84 -0
- package/node_modules/acorn/CHANGELOG.md +1012 -0
- package/node_modules/acorn/LICENSE +21 -0
- package/node_modules/acorn/README.md +309 -0
- package/node_modules/acorn/bin/acorn +4 -0
- package/node_modules/acorn/dist/acorn.d.mts +897 -0
- package/node_modules/acorn/dist/acorn.d.ts +897 -0
- package/node_modules/acorn/dist/acorn.js +6370 -0
- package/node_modules/acorn/dist/acorn.mjs +6341 -0
- package/node_modules/acorn/dist/bin.js +90 -0
- package/node_modules/acorn/package.json +50 -0
- package/node_modules/{minipass-flush/node_modules/minipass → tar}/node_modules/yallist/README.md +8 -7
- package/node_modules/tar/node_modules/yallist/package.json +68 -0
- package/node_modules/yallist/README.md +7 -8
- package/node_modules/yallist/package.json +12 -51
- package/package.json +131 -115
- package/manual/packages/core/src/host.js +0 -139
- package/node_modules/@mytools/core/src/host.js +0 -139
- package/node_modules/@mytools/core/src/run-logs.js +0 -63
- package/node_modules/@mytools/web/public/assets/index-DT2B4tMV.js +0 -70
- package/node_modules/@mytools/web/public/assets/index-vuZvrUTT.css +0 -1
- package/node_modules/minipass-flush/node_modules/minipass/node_modules/yallist/package.json +0 -29
- /package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/cli-run.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/conditions.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/log-viewer.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/run-presentation.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-cli}/src/terminal/theme.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-logs}/src/markdown-log.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/src/plugin-installations.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/src/project.js +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/templates/control-demo.yaml +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/templates/hello.yaml +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/templates/python-check.yaml +0 -0
- /package/{node_modules/@mytools/core → manual/packages/fst-workspace}/templates/system-check.yaml +0 -0
- /package/{node_modules/@mytools/core/src → manual/packages/sdk}/diagnostics.js +0 -0
- /package/{node_modules/@mytools/core/src → manual/packages/sdk}/schema-path.js +0 -0
- /package/{node_modules/@mytools/core/src → manual/packages/sdk}/validation.js +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/LICENSE.md +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/commonjs/index.js +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/commonjs/index.js.map +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/commonjs/package.json +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/esm/index.d.ts +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/esm/index.js +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/esm/index.js.map +0 -0
- /package/node_modules/{yallist → tar/node_modules/yallist}/dist/esm/package.json +0 -0
- /package/node_modules/{minipass-flush/node_modules/minipass/node_modules/yallist → yallist}/LICENSE +0 -0
- /package/node_modules/{minipass-flush/node_modules/minipass/node_modules/yallist → yallist}/iterator.js +0 -0
- /package/node_modules/{minipass-flush/node_modules/minipass/node_modules/yallist → yallist}/yallist.js +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { mkdir, writeFile, readFile, readdir, chmod,cp } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
3
|
import { randomUUID } from 'node:crypto';
|
|
5
4
|
import { collectPackages, copyPackages } from './dependencies.js';
|
|
6
5
|
import { copyRuntime, digest } from './runtime.js';
|
|
7
6
|
import { FlowError } from '@mytools/sdk';
|
|
8
7
|
import YAML from 'yaml';
|
|
9
|
-
import { verifyBundle } from '@mytools/
|
|
8
|
+
import { verifyBundle } from '@mytools/fst-platform/bundle';
|
|
10
9
|
import {planEnvironments} from './environments.js';
|
|
11
10
|
import {archiveDirectory} from './archive.js';
|
|
12
|
-
import {copyDocumentation} from '
|
|
11
|
+
import {copyDocumentation} from '@mytools/fst-devtools/documentation';
|
|
13
12
|
export {verifyBundle};
|
|
14
13
|
|
|
15
14
|
async function hashes(root,dir=root,result={}){
|
|
@@ -21,40 +20,49 @@ async function hashes(root,dir=root,result={}){
|
|
|
21
20
|
}
|
|
22
21
|
return result;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
function declaredPrivileges(closure,plugins){
|
|
24
|
+
const used=new Set();
|
|
25
|
+
const scan=steps=>{for(const step of steps??[]){
|
|
26
|
+
if(step.action)used.add(step.action);
|
|
27
|
+
if(step.branch){scan(step.branch.then);scan(step.branch.else);}
|
|
28
|
+
if(step.parallel)scan(step.parallel.steps);
|
|
29
|
+
}};
|
|
30
|
+
for(const workflow of closure.workflows)scan(workflow.steps);
|
|
31
|
+
const report=[];
|
|
32
|
+
for(const plugin of plugins){
|
|
33
|
+
if(plugin.requirements?.privilege)report.push({plugin:plugin.id,scope:'plugin',privilege:plugin.requirements.privilege});
|
|
34
|
+
for(const [name,action] of Object.entries(plugin.actions??{}))if(used.has(`${plugin.id}:${name}`)&&action.requirements?.privilege)report.push({plugin:plugin.id,action:name,scope:'action',privilege:action.requirements.privilege});
|
|
35
|
+
}
|
|
36
|
+
return report;
|
|
37
|
+
}
|
|
38
|
+
async function prepare(source,{entries,target,includeWeb=false,portable=false,environments={}}){
|
|
39
|
+
// 兼容既有 packApplication(app) 调用,但只使用明确的快照 Interface。
|
|
40
|
+
const snapshot=typeof source.exportSnapshot==='function'?await source.exportSnapshot({entries,includeWeb,portable}):source;
|
|
41
|
+
const {closure,plugins}=snapshot;entries=snapshot.entries;
|
|
26
42
|
if(!portable&&!entries?.length)throw new FlowError('请至少选择一个工作流');
|
|
27
43
|
if(!['win32-x64','linux-x64-glibc'].includes(target))throw new FlowError('请选择支持的目标平台');
|
|
28
|
-
const
|
|
29
|
-
const webProvider=[...app.host.definitions.values()].find(plugin=>typeof plugin.services?.web==='function');
|
|
30
|
-
const ids=new Set(portable?[...app.host.definitions.keys()].filter(id=>id!==webProvider?.id||includeWeb):closure.plugins);
|
|
31
|
-
for(const id of closure.plugins)ids.add(id);
|
|
32
|
-
if(includeWeb){if(!webProvider)throw new FlowError('未安装提供 Web 服务的插件');ids.add(webProvider.id);}
|
|
33
|
-
// Web 与其他入口使用相同的依赖闭包,包含提供者自身的传递依赖。
|
|
34
|
-
for(const id of ids)for(const dependency of Object.keys(app.host.definitions.get(id)?.dependencies??{}))ids.add(dependency);
|
|
35
|
-
const plugins=[...ids].map(id=>app.host.definitions.get(id));
|
|
44
|
+
const ids=new Set(plugins.map(p=>p.id));
|
|
36
45
|
if(plugins.some(p=>!p.root))throw new FlowError('内存中临时定义的插件不能打包,请先安装为标准包');
|
|
37
|
-
const overrides=structuredClone(
|
|
46
|
+
const overrides=structuredClone(snapshot.project.environments??{});
|
|
38
47
|
for(const [id,value] of Object.entries(environments))overrides[id]={...overrides[id],...value};
|
|
39
48
|
// 未选中的插件配置不进入导出,但显式拼错的覆盖项应报错。
|
|
40
49
|
for(const id of Object.keys(overrides))if(!ids.has(id)&&!Object.hasOwn(environments,id))delete overrides[id];
|
|
41
50
|
const environmentPlan=await planEnvironments(plugins,target,overrides);
|
|
42
|
-
return {closure,plugins,environmentPlan,overrides,entries};
|
|
51
|
+
return {closure,plugins,environmentPlan,overrides,entries,snapshot};
|
|
43
52
|
}
|
|
44
53
|
export async function planApplication(app,options={}){
|
|
45
|
-
const {plugins,environmentPlan,entries}=await prepare(app,options);
|
|
46
|
-
return {target:options.target,entries,plugins:plugins.map(p=>({id:p.id,platforms:p.platforms,architectures:p.architectures})),environments:environmentPlan.entries,environmentBytes:environmentPlan.bytes,warnings:environmentPlan.warnings};
|
|
54
|
+
const {plugins,closure,environmentPlan,entries,snapshot}=await prepare(app,options);
|
|
55
|
+
return {target:options.target,entries,plugins:plugins.map(p=>({id:p.id,platforms:p.platforms,architectures:p.architectures})),network:snapshot.project.network,privileges:declaredPrivileges(closure,plugins),environments:environmentPlan.entries,environmentBytes:environmentPlan.bytes,warnings:environmentPlan.warnings};
|
|
47
56
|
}
|
|
48
57
|
export async function packApplication(app,{entries,target,outDir='dist',includeWeb=false,runtimePath,cacheDir=path.resolve('.cache','runtimes'),readOnly=false,portable=false,environments={}}={}){
|
|
49
58
|
const prepared=await prepare(app,{entries,target,includeWeb,portable,environments});
|
|
50
|
-
const {closure,plugins,environmentPlan,overrides}=prepared;entries=prepared.entries;
|
|
51
|
-
const
|
|
52
|
-
const nodes=await collectPackages([readOnly?coreRoot:packRoot,...plugins.map(p=>p.root)]);
|
|
59
|
+
const {closure,plugins,environmentPlan,overrides,snapshot}=prepared;entries=prepared.entries;
|
|
60
|
+
const nodes=await collectPackages([snapshot.toolRoot,...plugins.map(p=>p.root)],{omitOptionalPeers:readOnly?['@mytools/pack']:[]});
|
|
53
61
|
const name=`fishtools-${target}-${Date.now()}-${randomUUID().slice(0,6)}`;
|
|
54
62
|
const directory=path.resolve(outDir,name);await mkdir(directory,{recursive:true});
|
|
55
63
|
const packages=await copyPackages(nodes,path.join(directory,'app'),target,{filters:environmentPlan.filters});
|
|
56
64
|
let runtime;
|
|
57
|
-
const base=
|
|
65
|
+
const base=snapshot.project.baseBundle?.root;
|
|
58
66
|
if(base){
|
|
59
67
|
const previous=JSON.parse(await readFile(path.join(base,'manifest.json'),'utf8'));
|
|
60
68
|
if(previous.target===target&&(readOnly||previous.runtime.npm)){
|
|
@@ -70,13 +78,13 @@ export async function packApplication(app,{entries,target,outDir='dist',includeW
|
|
|
70
78
|
for(const w of closure.workflows)await writeFile(path.join(workflowDir,`${w.id}.yaml`),YAML.stringify(w));
|
|
71
79
|
const config={};
|
|
72
80
|
for(const p of plugins)if(p.defaultConfig)config[p.id]=p.defaultConfig;
|
|
73
|
-
await writeFile(path.join(directory,'flow.project.json'),JSON.stringify({readOnly,plugins:plugins.map(p=>`./app/node_modules/${p.id}`),config,entries,environments:overrides,logs:
|
|
81
|
+
await writeFile(path.join(directory,'flow.project.json'),JSON.stringify({readOnly,plugins:plugins.map(p=>`./app/node_modules/${p.id}`),config,entries,environments:overrides,network:snapshot.project.network,logs:snapshot.project.logs},null,2));
|
|
74
82
|
const bundleId=randomUUID();
|
|
75
83
|
await writeFile(path.join(directory,'bundle.json'),JSON.stringify({format:2,id:bundleId,editable:!readOnly}));
|
|
76
84
|
await writeFile(path.join(directory,'package.json'),JSON.stringify({private:true,type:'module'},null,2));
|
|
77
85
|
const launch=target==='win32-x64'
|
|
78
|
-
? '@echo off\r\n"%~dp0runtime\\node.exe" "%~dp0app\\node_modules\\@mytools\\
|
|
79
|
-
: '#!/bin/sh\nROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)\nexec "$ROOT/runtime/node" "$ROOT/app/node_modules/@mytools/
|
|
86
|
+
? '@echo off\r\n"%~dp0runtime\\node.exe" "%~dp0app\\node_modules\\@mytools\\fst-cli\\bin\\fst.js" --project "%~dp0." %*\r\n'
|
|
87
|
+
: '#!/bin/sh\nROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)\nexec "$ROOT/runtime/node" "$ROOT/app/node_modules/@mytools/fst-cli/bin/fst.js" --project "$ROOT" "$@"\n';
|
|
80
88
|
const launcher=path.join(directory,target==='win32-x64'?'run.cmd':'run.sh');await writeFile(launcher,launch);await chmod(launcher,0o755);
|
|
81
89
|
const fst=path.join(directory,target==='win32-x64'?'fst.cmd':'fst');await writeFile(fst,launch);await chmod(fst,0o755);
|
|
82
90
|
await mkdir(path.join(directory,'bin'),{recursive:true});
|
|
@@ -88,7 +96,7 @@ export async function packApplication(app,{entries,target,outDir='dist',includeW
|
|
|
88
96
|
const file=['app',p.path,e.executable].join('/');executablePaths.add(file);await chmod(path.join(directory,file),0o755);
|
|
89
97
|
}
|
|
90
98
|
await copyDocumentation(path.join(directory,'manual'));
|
|
91
|
-
const manifest={format:2,bundleId,editable:!readOnly,createdAt:new Date().toISOString(),target,runtime,entries,workflows:closure.workflows.map(w=>w.id),plugins:plugins.map(p=>({id:p.id,version:p.version,platforms:p.platforms,architectures:p.architectures})),environments:environmentPlan.entries,warnings:environmentPlan.warnings,packages,files:await hashes(directory)};
|
|
99
|
+
const manifest={format:2,bundleId,editable:!readOnly,createdAt:new Date().toISOString(),target,runtime,entries,workflows:closure.workflows.map(w=>w.id),plugins:plugins.map(p=>({id:p.id,version:p.version,platforms:p.platforms,architectures:p.architectures})),network:snapshot.project.network,privileges:declaredPrivileges(closure,plugins),environments:environmentPlan.entries,warnings:environmentPlan.warnings,packages,files:await hashes(directory)};
|
|
92
100
|
await writeFile(path.join(directory,'manifest.json'),JSON.stringify(manifest,null,2));
|
|
93
101
|
const archive=await archiveDirectory(directory,target,executablePaths);
|
|
94
102
|
return {directory,archive,manifest};
|
|
@@ -1 +1,29 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@mytools/pack",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"*.js"
|
|
8
|
+
],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@mytools/sdk": "0.1.0",
|
|
12
|
+
"@npmcli/arborist": "10.0.3",
|
|
13
|
+
"archiver": "8.0.0",
|
|
14
|
+
"make-fetch-happen": "16.0.1",
|
|
15
|
+
"npm-packlist": "11.3.0",
|
|
16
|
+
"tar": "7.5.22",
|
|
17
|
+
"yaml": "2.9.1",
|
|
18
|
+
"@mytools/fst-platform": "0.1.0",
|
|
19
|
+
"@mytools/fst-devtools": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./index.js",
|
|
23
|
+
"./dependencies": "./dependencies.js",
|
|
24
|
+
"./runtime": "./runtime.js",
|
|
25
|
+
"./environments": "./environments.js",
|
|
26
|
+
"./archive": "./archive.js",
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# SDK模块
|
|
2
|
+
|
|
3
|
+
包名:`@mytools/sdk`。内部 workspace 包,随 `@yanglaofish/fishtools` 统一交付。
|
|
4
|
+
|
|
5
|
+
## 职责与边界
|
|
6
|
+
|
|
7
|
+
插件定义、错误和共享 schema/条件契约。不承接宿主生命周期、磁盘持久化或界面行为。
|
|
8
|
+
|
|
9
|
+
内部依赖:无。
|
|
10
|
+
## 公开入口
|
|
11
|
+
|
|
12
|
+
| 导入路径 | 实现位置 |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `@mytools/sdk` | `./index.js` |
|
|
15
|
+
| `@mytools/sdk/schema` | `./validation.js` |
|
|
16
|
+
| `@mytools/sdk/schema-path` | `./schema-path.js` |
|
|
17
|
+
| `@mytools/sdk/diagnostics` | `./diagnostics.js` |
|
|
18
|
+
| `@mytools/sdk/conditions` | `./conditions.js` |
|
|
19
|
+
| `@mytools/sdk/package.json` | `./package.json` |
|
|
20
|
+
|
|
21
|
+
仅依赖 exports 声明的入口,禁止消费者跨包读取 src/bin 私有文件。入口路径由本模块维护,修改协议时同步消费方回归。
|
|
22
|
+
|
|
23
|
+
## 维护与验证
|
|
24
|
+
|
|
25
|
+
本模块负责上述职责的实现、文档与回归;跨模块接口调整需要同时检查生产者与消费者。具体维护人员尚未指定。
|
|
26
|
+
|
|
27
|
+
在仓库根目录执行:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
node --test tests/modules.test.js tests/plugin-contract.test.js tests/schema-diagnostics.test.js
|
|
31
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const conditionOperators=['eq','ne','gt','gte','lt','lte','contains','exists'];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {FlowError} from '@mytools/sdk';
|
|
2
|
+
|
|
3
|
+
export function pluginError(cause,identity){
|
|
4
|
+
const error=new FlowError(`插件 ${identity.plugin}(${identity.action??identity.command})执行失败:${cause?.message??String(cause)}`,{code:cause?.code??'EXECUTION_FAILED',details:cause?.details,cause});
|
|
5
|
+
return Object.assign(error,identity);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Error 的 message/stack/cause 默认不可枚举,必须显式转换才会进入 JSON 日志。
|
|
9
|
+
export function errorRecord(error,seen=new Set()){
|
|
10
|
+
if(error==null||typeof error!=='object')return {message:String(error)};
|
|
11
|
+
if(seen.has(error)||seen.size>=8)return {message:'错误链已截断'};
|
|
12
|
+
seen.add(error);
|
|
13
|
+
const record={name:error.name??'Error',message:error.message??String(error)};
|
|
14
|
+
for(const key of ['code','plugin','action','command','stack'])if(typeof error[key]==='string')record[key]=error[key];
|
|
15
|
+
if(error.details!==undefined){
|
|
16
|
+
try{
|
|
17
|
+
const objects=new WeakSet();
|
|
18
|
+
record.details=JSON.parse(JSON.stringify({value:error.details},(_key,value)=>{
|
|
19
|
+
if(typeof value==='bigint')return String(value);
|
|
20
|
+
if(value&&typeof value==='object'){if(objects.has(value))return '[循环引用]';objects.add(value);}
|
|
21
|
+
return value;
|
|
22
|
+
})).value;
|
|
23
|
+
}catch(cause){record.details={serializationError:cause?.message??String(cause)};}
|
|
24
|
+
}
|
|
25
|
+
if(error.cause!==undefined)record.cause=errorRecord(error.cause,seen);
|
|
26
|
+
return record;
|
|
27
|
+
}
|
|
@@ -1 +1,23 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@mytools/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.js",
|
|
8
|
+
"./schema": "./validation.js",
|
|
9
|
+
"./schema-path": "./schema-path.js",
|
|
10
|
+
"./diagnostics": "./diagnostics.js",
|
|
11
|
+
"./conditions": "./conditions.js",
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"*.js",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"ajv": "8.20.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {FlowError} from '@mytools/sdk';
|
|
2
|
+
|
|
3
|
+
const forbidden=new Set(['__proto__','constructor','prototype']);
|
|
4
|
+
const missing=ref=>{throw new FlowError(`引用字段不存在:${ref}`,{code:'VALIDATION'});};
|
|
5
|
+
|
|
6
|
+
// 路径只用于已声明的字段;开放对象可继续引用,带类型的动态键则继续逐层检查。
|
|
7
|
+
export function resolveSchemaPath(schema,fields,ref=Array.isArray(fields)?fields.join('.'):fields){
|
|
8
|
+
const parts=Array.isArray(fields)?fields:typeof fields==='string'?fields.split('.'):[];
|
|
9
|
+
if(!parts.length)return schema;
|
|
10
|
+
if(parts.some(part=>typeof part!=='string'||!part||forbidden.has(part)))missing(ref);
|
|
11
|
+
let current=schema;
|
|
12
|
+
for(const field of parts){
|
|
13
|
+
if(current===true){continue;}
|
|
14
|
+
if(current===false||!current||typeof current!=='object'||Array.isArray(current))missing(ref);
|
|
15
|
+
const types=Array.isArray(current.type)?current.type:[current.type];
|
|
16
|
+
const isArray=types.includes('array')||current.items!==undefined;
|
|
17
|
+
if(isArray){
|
|
18
|
+
if(!/^(0|[1-9]\d*)$/.test(field))missing(ref);
|
|
19
|
+
if(Array.isArray(current.items))current=current.items[Number(field)]??current.additionalItems??true;
|
|
20
|
+
else current=current.items??true;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if(current.properties&&Object.hasOwn(current.properties,field)){
|
|
24
|
+
current=current.properties[field];continue;
|
|
25
|
+
}
|
|
26
|
+
if(!types.includes('object')&&types.some(type=>type!==undefined))missing(ref);
|
|
27
|
+
current=current.additionalProperties??true;
|
|
28
|
+
}
|
|
29
|
+
if(current===false)missing(ref);
|
|
30
|
+
return current;
|
|
31
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import { FlowError } from '@mytools/sdk';
|
|
3
|
+
|
|
4
|
+
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
5
|
+
const validators = {true:new WeakMap(),false:new WeakMap()};
|
|
6
|
+
const booleanValidators = {true:new Map(),false:new Map()};
|
|
7
|
+
export const emptyObject = { type: 'object', properties: {}, additionalProperties: false };
|
|
8
|
+
|
|
9
|
+
export function assertSchema(schema,label,{useDefaults=true}={}) {
|
|
10
|
+
if (!(typeof schema==='boolean'||schema&&typeof schema==='object'&&!Array.isArray(schema))) throw new FlowError(`${label} 必须声明有效的 JSON Schema`,{code:'VALIDATION'});
|
|
11
|
+
const cache=(typeof schema==='boolean'?booleanValidators:validators)[Boolean(useDefaults)];
|
|
12
|
+
let check=cache.get(schema);
|
|
13
|
+
if(!check){
|
|
14
|
+
// 每份定义独立解析 $id/$ref,避免插件重载或不同插件共用 ID 时串用约束。
|
|
15
|
+
// 编译结果仍按对象缓存;注册表随校验器释放,不污染后续安装批次。
|
|
16
|
+
try{check=new Ajv({allErrors:true,strict:false,useDefaults:Boolean(useDefaults)}).compile(schema);cache.set(schema,check);}
|
|
17
|
+
catch(cause){throw new FlowError(`${label} JSON Schema 无效:${cause.message}`,{code:'VALIDATION',cause});}
|
|
18
|
+
}
|
|
19
|
+
return check;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const pointerToken=value=>String(value).replaceAll('~','~0').replaceAll('/','~1');
|
|
23
|
+
function diagnostic(error){
|
|
24
|
+
let instancePath=error.instancePath;
|
|
25
|
+
if(error.keyword==='required')instancePath+=`/${pointerToken(error.params.missingProperty)}`;
|
|
26
|
+
if(error.keyword==='additionalProperties')instancePath+=`/${pointerToken(error.params.additionalProperty)}`;
|
|
27
|
+
// 保留 Ajv 原有 instancePath 语义,新字段提供指向缺失/额外属性的完整位置。
|
|
28
|
+
return {...error,jsonPointer:instancePath};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function validate(schema, value, label,{useDefaults=true}={}) {
|
|
32
|
+
if (schema==null) return structuredClone(value);
|
|
33
|
+
const check = assertSchema(schema,label,{useDefaults});
|
|
34
|
+
const copy = structuredClone(value);
|
|
35
|
+
if (!check(copy)) {
|
|
36
|
+
const details=check.errors.map(diagnostic);
|
|
37
|
+
const locations=details.map(error=>`${error.jsonPointer||'/'} (${error.schemaPath})`).join(';');
|
|
38
|
+
throw new FlowError(`${label}: ${ajv.errorsText(check.errors, { separator: ';' })};位置 ${locations}`, { code: 'VALIDATION', details });
|
|
39
|
+
}
|
|
40
|
+
return copy;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function assertId(id) {
|
|
44
|
+
if (typeof id !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,79}$/.test(id)) {
|
|
45
|
+
throw new FlowError('标识 ID 只能使用字母、数字、下划线和短横线,最多 80 字符', { code: 'VALIDATION' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function referenceParts(ref) {
|
|
50
|
+
if (typeof ref !== 'string') throw new FlowError('引用必须为字符串', {code:'VALIDATION'});
|
|
51
|
+
const parts = ref.split('.');
|
|
52
|
+
if (parts.some(p => !p || ['__proto__', 'constructor', 'prototype'].includes(p))) throw new FlowError(`非法引用字段:${ref}`, {code:'VALIDATION'});
|
|
53
|
+
if (parts[0] !== 'inputs' && !(parts[0] === 'steps' && parts[2] === 'output')) throw new FlowError(`非法引用:${ref}`, {code:'VALIDATION'});
|
|
54
|
+
return parts;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function references(value, visit) {
|
|
58
|
+
if (!value || typeof value !== 'object') return;
|
|
59
|
+
if (Object.hasOwn(value, '$ref')) {
|
|
60
|
+
if (Object.keys(value).length !== 1) throw new FlowError('引用对象不能同时包含其他字段', {code:'VALIDATION'});
|
|
61
|
+
visit(value.$ref); return;
|
|
62
|
+
}
|
|
63
|
+
Object.values(value).forEach(v => references(v, visit));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function bind(value, context) {
|
|
67
|
+
if (!value || typeof value !== 'object') return value;
|
|
68
|
+
if (Object.hasOwn(value, '$ref')) {
|
|
69
|
+
let current = context;
|
|
70
|
+
for (const field of referenceParts(value.$ref)) {
|
|
71
|
+
if (current == null || !Object.hasOwn(current, field)) throw new FlowError(`引用的值不存在:${value.$ref}`,{code:'MISSING_REFERENCE'});
|
|
72
|
+
current = current[field];
|
|
73
|
+
}
|
|
74
|
+
return structuredClone(current);
|
|
75
|
+
}
|
|
76
|
+
if (Array.isArray(value)) return value.map(v => bind(v, context));
|
|
77
|
+
return Object.fromEntries(Object.entries(value).map(([key, v]) => [key, bind(v, context)]));
|
|
78
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Web模块
|
|
2
|
+
|
|
3
|
+
包名:`@mytools/web`。内部 workspace 包,随 `@yanglaofish/fishtools` 统一交付。
|
|
4
|
+
|
|
5
|
+
## 职责与边界
|
|
6
|
+
|
|
7
|
+
官方 Web 插件、HTTP 服务、前端交互及模型投影。通过服务工厂参数获得应用接口,前端构建产物仍在本包 public 中。
|
|
8
|
+
|
|
9
|
+
内部依赖:`@mytools/sdk`。
|
|
10
|
+
## 公开入口
|
|
11
|
+
|
|
12
|
+
| 导入路径 | 实现位置 |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `@mytools/web` | `./index.js` |
|
|
15
|
+
| `@mytools/web/server` | `./server.js` |
|
|
16
|
+
| `@mytools/web/model` | `./src/model.js` |
|
|
17
|
+
| `@mytools/web/package.json` | `./package.json` |
|
|
18
|
+
|
|
19
|
+
仅依赖 exports 声明的入口,禁止消费者跨包读取 src/bin 私有文件。入口路径由本模块维护,修改协议时同步消费方回归。
|
|
20
|
+
|
|
21
|
+
## 维护与验证
|
|
22
|
+
|
|
23
|
+
本模块负责上述职责的实现、文档与回归;跨模块接口调整需要同时检查生产者与消费者。具体维护人员尚未指定。
|
|
24
|
+
|
|
25
|
+
在仓库根目录执行:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
node --test tests/modules.test.js tests/web.test.js tests/web-control.test.js
|
|
29
|
+
```
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
8
8
|
"server.js",
|
|
9
|
+
"src/model.js",
|
|
9
10
|
"public"
|
|
10
11
|
],
|
|
11
12
|
"license": "MIT",
|
|
@@ -28,5 +29,11 @@
|
|
|
28
29
|
"react": "19.3.0",
|
|
29
30
|
"react-dom": "19.3.0",
|
|
30
31
|
"vite": "8.3.4"
|
|
32
|
+
},
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./index.js",
|
|
35
|
+
"./server": "./server.js",
|
|
36
|
+
"./model": "./src/model.js",
|
|
37
|
+
"./package.json": "./package.json"
|
|
31
38
|
}
|
|
32
39
|
}
|