@coralai/sps-cli 0.66.8 → 0.67.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/CHANGELOG.md +35 -0
- package/assembly/art.yml +6 -0
- package/assembly/base.yml +72 -0
- package/assembly/cli.yml +4 -0
- package/assembly/console.yml +4 -0
- package/assembly/daemon.yml +4 -0
- package/dist/commands/agentCommand.d.ts +22 -1
- package/dist/commands/agentCommand.d.ts.map +1 -1
- package/dist/commands/agentCommand.js +14 -15
- package/dist/commands/agentCommand.js.map +1 -1
- package/dist/commands/cardAdd.d.ts +14 -1
- package/dist/commands/cardAdd.d.ts.map +1 -1
- package/dist/commands/cardAdd.js +5 -13
- package/dist/commands/cardAdd.js.map +1 -1
- package/dist/commands/cardInsert.d.ts +19 -1
- package/dist/commands/cardInsert.d.ts.map +1 -1
- package/dist/commands/cardInsert.js +5 -18
- package/dist/commands/cardInsert.js.map +1 -1
- package/dist/commands/consoleCommand.d.ts +20 -1
- package/dist/commands/consoleCommand.d.ts.map +1 -1
- package/dist/commands/consoleCommand.js +5 -2
- package/dist/commands/consoleCommand.js.map +1 -1
- package/dist/commands/imCommand.d.ts +9 -1
- package/dist/commands/imCommand.d.ts.map +1 -1
- package/dist/commands/imCommand.js +2 -9
- package/dist/commands/imCommand.js.map +1 -1
- package/dist/commands/memoryCommand.d.ts +11 -1
- package/dist/commands/memoryCommand.d.ts.map +1 -1
- package/dist/commands/memoryCommand.js +12 -18
- package/dist/commands/memoryCommand.js.map +1 -1
- package/dist/commands/monitorTick.d.ts +24 -1
- package/dist/commands/monitorTick.d.ts.map +1 -1
- package/dist/commands/monitorTick.js +8 -4
- package/dist/commands/monitorTick.js.map +1 -1
- package/dist/commands/openaiAgent.d.ts +2 -1
- package/dist/commands/openaiAgent.d.ts.map +1 -1
- package/dist/commands/openaiAgent.js +7 -3
- package/dist/commands/openaiAgent.js.map +1 -1
- package/dist/commands/pipelineTick.d.ts +4 -1
- package/dist/commands/pipelineTick.d.ts.map +1 -1
- package/dist/commands/pipelineTick.js +11 -7
- package/dist/commands/pipelineTick.js.map +1 -1
- package/dist/commands/pluginCommand.d.ts +2 -0
- package/dist/commands/pluginCommand.d.ts.map +1 -0
- package/dist/commands/pluginCommand.js +160 -0
- package/dist/commands/pluginCommand.js.map +1 -0
- package/dist/commands/qaTick.d.ts +4 -1
- package/dist/commands/qaTick.d.ts.map +1 -1
- package/dist/commands/qaTick.js +11 -7
- package/dist/commands/qaTick.js.map +1 -1
- package/dist/commands/schedulerTick.d.ts +24 -1
- package/dist/commands/schedulerTick.d.ts.map +1 -1
- package/dist/commands/schedulerTick.js +5 -23
- package/dist/commands/schedulerTick.js.map +1 -1
- package/dist/commands/tick.d.ts +25 -2
- package/dist/commands/tick.d.ts.map +1 -1
- package/dist/commands/tick.js +39 -16
- package/dist/commands/tick.js.map +1 -1
- package/dist/commands/workerLaunch.d.ts +4 -1
- package/dist/commands/workerLaunch.d.ts.map +1 -1
- package/dist/commands/workerLaunch.js +11 -7
- package/dist/commands/workerLaunch.js.map +1 -1
- package/dist/console/index.d.ts +21 -0
- package/dist/console/index.d.ts.map +1 -1
- package/dist/console/index.js +8 -4
- package/dist/console/index.js.map +1 -1
- package/dist/console/routes/capabilities.d.ts +3 -0
- package/dist/console/routes/capabilities.d.ts.map +1 -1
- package/dist/console/routes/capabilities.js +2 -21
- package/dist/console/routes/capabilities.js.map +1 -1
- package/dist/console/routes/cards.d.ts +19 -0
- package/dist/console/routes/cards.d.ts.map +1 -1
- package/dist/console/routes/cards.js +1 -1
- package/dist/console/routes/cards.js.map +1 -1
- package/dist/console/routes/mcpTools.d.ts +2 -1
- package/dist/console/routes/mcpTools.d.ts.map +1 -1
- package/dist/console/routes/mcpTools.js +3 -8
- package/dist/console/routes/mcpTools.js.map +1 -1
- package/dist/console/routes/plugins.d.ts +20 -0
- package/dist/console/routes/plugins.d.ts.map +1 -0
- package/dist/console/routes/plugins.js +185 -0
- package/dist/console/routes/plugins.js.map +1 -0
- package/dist/console/routes/tts.d.ts +2 -1
- package/dist/console/routes/tts.d.ts.map +1 -1
- package/dist/console/routes/tts.js +2 -3
- package/dist/console/routes/tts.js.map +1 -1
- package/dist/console-assets/assets/{ShowcasePage-C8tqVK7m.js → ShowcasePage-3ekOTV_g.js} +1 -1
- package/dist/console-assets/assets/{index-DCKXZKta.css → index-Dd7MTFgX.css} +1 -1
- package/dist/console-assets/assets/{index-DAvJ1-Qg.js → index-o3svZ9mC.js} +223 -213
- package/dist/console-assets/index.html +2 -2
- package/dist/core/agents/resolveBackend.d.ts +0 -5
- package/dist/core/agents/resolveBackend.d.ts.map +1 -1
- package/dist/core/agents/resolveBackend.js +6 -52
- package/dist/core/agents/resolveBackend.js.map +1 -1
- package/dist/core/art/artRunService.d.ts +13 -1
- package/dist/core/art/artRunService.d.ts.map +1 -1
- package/dist/core/art/artRunService.js +1 -0
- package/dist/core/art/artRunService.js.map +1 -1
- package/dist/core/mcpToolCatalog.d.ts +14 -1
- package/dist/core/mcpToolCatalog.d.ts.map +1 -1
- package/dist/core/mcpToolCatalog.js +7 -11
- package/dist/core/mcpToolCatalog.js.map +1 -1
- package/dist/core/tools/ToolCardExecutor.d.ts +12 -2
- package/dist/core/tools/ToolCardExecutor.d.ts.map +1 -1
- package/dist/core/tools/ToolCardExecutor.js.map +1 -1
- package/dist/daemon/daemonClient.d.ts +8 -2
- package/dist/daemon/daemonClient.d.ts.map +1 -1
- package/dist/daemon/daemonClient.js +9 -0
- package/dist/daemon/daemonClient.js.map +1 -1
- package/dist/daemon/sessionDaemon.d.ts +7 -2
- package/dist/daemon/sessionDaemon.d.ts.map +1 -1
- package/dist/daemon/sessionDaemon.js +49 -10
- package/dist/daemon/sessionDaemon.js.map +1 -1
- package/dist/engines/StageEngine.d.ts +6 -1
- package/dist/engines/StageEngine.d.ts.map +1 -1
- package/dist/engines/StageEngine.js +10 -7
- package/dist/engines/StageEngine.js.map +1 -1
- package/dist/im/IMGatewayManager.d.ts +12 -0
- package/dist/im/IMGatewayManager.d.ts.map +1 -1
- package/dist/im/IMGatewayManager.js +10 -18
- package/dist/im/IMGatewayManager.js.map +1 -1
- package/dist/main.js +67 -21
- package/dist/main.js.map +1 -1
- package/dist/manager/makeBackendFactory.d.ts +12 -0
- package/dist/manager/makeBackendFactory.d.ts.map +1 -1
- package/dist/manager/makeBackendFactory.js +3 -2
- package/dist/manager/makeBackendFactory.js.map +1 -1
- package/dist/manager/worker-manager-impl.d.ts +19 -0
- package/dist/manager/worker-manager-impl.d.ts.map +1 -1
- package/dist/manager/worker-manager-impl.js +15 -15
- package/dist/manager/worker-manager-impl.js.map +1 -1
- package/dist/openai-agent/memory/v2Bridge.d.ts +28 -2
- package/dist/openai-agent/memory/v2Bridge.d.ts.map +1 -1
- package/dist/openai-agent/memory/v2Bridge.js +4 -20
- package/dist/openai-agent/memory/v2Bridge.js.map +1 -1
- package/dist/openai-agent/runWorker.d.ts +8 -6
- package/dist/openai-agent/runWorker.d.ts.map +1 -1
- package/dist/openai-agent/runWorker.js +5 -4
- package/dist/openai-agent/runWorker.js.map +1 -1
- package/dist/openai-agent/sandbox/execution.d.ts +10 -2
- package/dist/openai-agent/sandbox/execution.d.ts.map +1 -1
- package/dist/openai-agent/sandbox/execution.js +9 -6
- package/dist/openai-agent/sandbox/execution.js.map +1 -1
- package/dist/plugin/assembly.d.ts +37 -0
- package/dist/plugin/assembly.d.ts.map +1 -0
- package/dist/plugin/assembly.js +95 -0
- package/dist/plugin/assembly.js.map +1 -0
- package/dist/plugin/context.d.ts +101 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +187 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/hot.d.ts +34 -0
- package/dist/plugin/hot.d.ts.map +1 -0
- package/dist/plugin/hot.js +62 -0
- package/dist/plugin/hot.js.map +1 -0
- package/dist/plugin/layers.d.ts +40 -0
- package/dist/plugin/layers.d.ts.map +1 -0
- package/dist/plugin/layers.js +101 -0
- package/dist/plugin/layers.js.map +1 -0
- package/dist/plugin/manager.d.ts +80 -0
- package/dist/plugin/manager.d.ts.map +1 -0
- package/dist/plugin/manager.js +202 -0
- package/dist/plugin/manager.js.map +1 -0
- package/dist/plugin/run.d.ts +53 -0
- package/dist/plugin/run.d.ts.map +1 -0
- package/dist/plugin/run.js +72 -0
- package/dist/plugin/run.js.map +1 -0
- package/dist/providers/art/artGen.d.ts +18 -3
- package/dist/providers/art/artGen.d.ts.map +1 -1
- package/dist/providers/art/artGen.js +15 -15
- package/dist/providers/art/artGen.js.map +1 -1
- package/dist/providers/art/artRunChild.d.ts +2 -1
- package/dist/providers/art/artRunChild.d.ts.map +1 -1
- package/dist/providers/art/artRunChild.js +15 -8
- package/dist/providers/art/artRunChild.js.map +1 -1
- package/dist/providers/llm/chatTools.d.ts +10 -1
- package/dist/providers/llm/chatTools.d.ts.map +1 -1
- package/dist/providers/llm/chatTools.js +4 -4
- package/dist/providers/llm/chatTools.js.map +1 -1
- package/dist/providers/mcp/spsMcpServer.d.ts +3 -0
- package/dist/providers/mcp/spsMcpServer.d.ts.map +1 -1
- package/dist/providers/mcp/spsMcpServer.js +25 -31
- package/dist/providers/mcp/spsMcpServer.js.map +1 -1
- package/dist/providers/mcp/spsMcpStdio.js +12 -1
- package/dist/providers/mcp/spsMcpStdio.js.map +1 -1
- package/dist/providers/media/generateAsset.d.ts +11 -0
- package/dist/providers/media/generateAsset.d.ts.map +1 -1
- package/dist/providers/media/generateAsset.js +2 -3
- package/dist/providers/media/generateAsset.js.map +1 -1
- package/dist/providers/registry.d.ts +0 -4
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +1 -14
- package/dist/providers/registry.js.map +1 -1
- package/dist/seams/agents/index.d.ts +49 -0
- package/dist/seams/agents/index.d.ts.map +1 -0
- package/dist/seams/agents/index.js +54 -0
- package/dist/seams/agents/index.js.map +1 -0
- package/dist/seams/agents-builtin/index.d.ts +19 -0
- package/dist/seams/agents-builtin/index.d.ts.map +1 -0
- package/dist/seams/agents-builtin/index.js +69 -0
- package/dist/seams/agents-builtin/index.js.map +1 -0
- package/dist/seams/capabilities/index.d.ts +39 -0
- package/dist/seams/capabilities/index.d.ts.map +1 -0
- package/dist/seams/capabilities/index.js +47 -0
- package/dist/seams/capabilities/index.js.map +1 -0
- package/dist/seams/capabilities-art/index.d.ts +14 -0
- package/dist/seams/capabilities-art/index.d.ts.map +1 -0
- package/dist/seams/capabilities-art/index.js +9 -0
- package/dist/seams/capabilities-art/index.js.map +1 -0
- package/dist/seams/im/index.d.ts +28 -0
- package/dist/seams/im/index.d.ts.map +1 -0
- package/dist/seams/im/index.js +36 -0
- package/dist/seams/im/index.js.map +1 -0
- package/dist/seams/im-builtin/index.d.ts +13 -0
- package/dist/seams/im-builtin/index.d.ts.map +1 -0
- package/dist/seams/im-builtin/index.js +25 -0
- package/dist/seams/im-builtin/index.js.map +1 -0
- package/dist/seams/media/index.d.ts +30 -0
- package/dist/seams/media/index.d.ts.map +1 -0
- package/dist/seams/media/index.js +38 -0
- package/dist/seams/media/index.js.map +1 -0
- package/dist/seams/media-builtin/index.d.ts +13 -0
- package/dist/seams/media-builtin/index.d.ts.map +1 -0
- package/dist/seams/media-builtin/index.js +10 -0
- package/dist/seams/media-builtin/index.js.map +1 -0
- package/dist/seams/memory/index.d.ts +58 -0
- package/dist/seams/memory/index.d.ts.map +1 -0
- package/dist/seams/memory/index.js +28 -0
- package/dist/seams/memory/index.js.map +1 -0
- package/dist/seams/memory-local/index.d.ts +31 -0
- package/dist/seams/memory-local/index.d.ts.map +1 -0
- package/dist/seams/memory-local/index.js +55 -0
- package/dist/seams/memory-local/index.js.map +1 -0
- package/dist/seams/notifier/index.d.ts +37 -0
- package/dist/seams/notifier/index.d.ts.map +1 -0
- package/dist/seams/notifier/index.js +30 -0
- package/dist/seams/notifier/index.js.map +1 -0
- package/dist/seams/notifier-matrix/index.d.ts +17 -0
- package/dist/seams/notifier-matrix/index.d.ts.map +1 -0
- package/dist/seams/notifier-matrix/index.js +8 -0
- package/dist/seams/notifier-matrix/index.js.map +1 -0
- package/dist/seams/notifier-none/index.d.ts +18 -0
- package/dist/seams/notifier-none/index.d.ts.map +1 -0
- package/dist/seams/notifier-none/index.js +14 -0
- package/dist/seams/notifier-none/index.js.map +1 -0
- package/dist/seams/repo/index.d.ts +38 -0
- package/dist/seams/repo/index.d.ts.map +1 -0
- package/dist/seams/repo/index.js +43 -0
- package/dist/seams/repo/index.js.map +1 -0
- package/dist/seams/repo-builtin/index.d.ts +14 -0
- package/dist/seams/repo-builtin/index.d.ts.map +1 -0
- package/dist/seams/repo-builtin/index.js +14 -0
- package/dist/seams/repo-builtin/index.js.map +1 -0
- package/dist/seams/tools/index.d.ts +83 -0
- package/dist/seams/tools/index.d.ts.map +1 -0
- package/dist/seams/tools/index.js +67 -0
- package/dist/seams/tools/index.js.map +1 -0
- package/dist/services/MemoryService.d.ts +12 -0
- package/dist/services/MemoryService.d.ts.map +1 -1
- package/dist/services/MemoryService.js +14 -18
- package/dist/services/MemoryService.js.map +1 -1
- package/dist/services/container.d.ts +20 -1
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +10 -3
- package/dist/services/container.js.map +1 -1
- package/dist/services/executors.d.ts +4 -0
- package/dist/services/executors.d.ts.map +1 -1
- package/dist/services/executors.js +27 -5
- package/dist/services/executors.js.map +1 -1
- package/dist/services/promptPreview.d.ts +14 -1
- package/dist/services/promptPreview.d.ts.map +1 -1
- package/dist/services/promptPreview.js +4 -3
- package/dist/services/promptPreview.js.map +1 -1
- package/package.json +16 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** 装配档里的一行。`name` 之外的字段原样透传给 loader。 */
|
|
2
|
+
export interface AssemblyRow {
|
|
3
|
+
/** 覆盖用的稳定标识。省略时用 `name` 当 id —— 出厂档每行都写了 id。 */
|
|
4
|
+
id?: string;
|
|
5
|
+
/** 插件模块:包名(从 loader 所在位置解析)或 `file://` 绝对入口。 */
|
|
6
|
+
name: string;
|
|
7
|
+
/** 传给插件 `apply(ctx, config)` 的配置;schemastery 会补默认值。 */
|
|
8
|
+
config?: unknown;
|
|
9
|
+
/** true = 装了但不启用(保留配置)。 */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
[k: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 用户层目录。默认 `~/.coral/assembly`,`SPS_ASSEMBLY_USER_DIR` 可覆盖。
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ 环境变量**只为测试隔离**存在 —— 没有它,任何一条测试都会去读写真实
|
|
17
|
+
* 的 `~/.coral`,而那是本机在用的配置。
|
|
18
|
+
*/
|
|
19
|
+
export declare function userAssemblyDir(): string;
|
|
20
|
+
export declare function userAssemblyPath(name: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* 读一份装配档。
|
|
23
|
+
*
|
|
24
|
+
* @param required 出厂档为 true(缺失 = 包不完整,立刻抛);用户层为 false
|
|
25
|
+
* (缺失是**常态** —— 没装过任何插件的机器上就是没有)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function readAssemblyFile(path: string, required: boolean): AssemblyRow[];
|
|
28
|
+
/** 一行的覆盖键。 */
|
|
29
|
+
export declare function rowKey(row: AssemblyRow): string;
|
|
30
|
+
/**
|
|
31
|
+
* 按 id 合并多层,**后面的整行替换前面的**。
|
|
32
|
+
*
|
|
33
|
+
* 🔴 **整行替换,不深合并 config**:深合并会让"这个值最终是什么"要读 N 层
|
|
34
|
+
* 才算得出来。同一条规矩出厂档里已经写着,这里是它第一次真的被执行。
|
|
35
|
+
*
|
|
36
|
+
* 顺序保持"首次出现的位置" —— 上层改了某行,它不会跳到列表末尾。
|
|
37
|
+
* (行序对激活没有语义,但对**人读**有:改一行不该让整份档看起来面目全非。)
|
|
38
|
+
*/
|
|
39
|
+
export declare function mergeAssembly(...layers: AssemblyRow[][]): AssemblyRow[];
|
|
40
|
+
//# sourceMappingURL=layers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/plugin/layers.ts"],"names":[],"mappings":"AAuBA,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,EAAE,CAW/E;AAkBD,cAAc;AACd,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAE/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,WAAW,EAAE,CAWvE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin/layers
|
|
3
|
+
* @description **装配档的两层**:包内出厂档(只读)+ 用户层(`~/.coral/assembly`)。
|
|
4
|
+
*
|
|
5
|
+
* @layer plugin
|
|
6
|
+
*
|
|
7
|
+
* 🔴 **为什么要有用户层**:出厂档在**包目录内部**。
|
|
8
|
+
* `npm i -g @coralai/sps-cli@latest` 会整个替换包目录 ——
|
|
9
|
+
* 装过的插件全丢,而且是静默的(升级完一切正常,只是插件不见了)。
|
|
10
|
+
* 用户装的东西必须落在包外面。
|
|
11
|
+
*
|
|
12
|
+
* 🔴 **覆盖必须在进程内先合并,不能指望 loader**。
|
|
13
|
+
* 文档一度写着「上层装配档按 id 覆盖」——**实测是假的**:
|
|
14
|
+
* loader 的每个被包含文件是独立子树,id 各算各的,
|
|
15
|
+
* 两档同 id 的结果是**并存**(两个插件都跑起来),不是覆盖。
|
|
16
|
+
* 这条从没被走过(四份进程档一直是空的),所以一直没暴露。
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
19
|
+
import { homedir } from 'node:os';
|
|
20
|
+
import { dirname, resolve } from 'node:path';
|
|
21
|
+
import { pathToFileURL } from 'node:url';
|
|
22
|
+
import { parse as parseYaml } from 'yaml';
|
|
23
|
+
/**
|
|
24
|
+
* 用户层目录。默认 `~/.coral/assembly`,`SPS_ASSEMBLY_USER_DIR` 可覆盖。
|
|
25
|
+
*
|
|
26
|
+
* ⚠️ 环境变量**只为测试隔离**存在 —— 没有它,任何一条测试都会去读写真实
|
|
27
|
+
* 的 `~/.coral`,而那是本机在用的配置。
|
|
28
|
+
*/
|
|
29
|
+
export function userAssemblyDir() {
|
|
30
|
+
const override = process.env.SPS_ASSEMBLY_USER_DIR;
|
|
31
|
+
if (override)
|
|
32
|
+
return resolve(override);
|
|
33
|
+
return resolve(homedir(), '.coral', 'assembly');
|
|
34
|
+
}
|
|
35
|
+
export function userAssemblyPath(name) {
|
|
36
|
+
return resolve(userAssemblyDir(), `${name}.yml`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 读一份装配档。
|
|
40
|
+
*
|
|
41
|
+
* @param required 出厂档为 true(缺失 = 包不完整,立刻抛);用户层为 false
|
|
42
|
+
* (缺失是**常态** —— 没装过任何插件的机器上就是没有)。
|
|
43
|
+
*/
|
|
44
|
+
export function readAssemblyFile(path, required) {
|
|
45
|
+
if (!existsSync(path)) {
|
|
46
|
+
if (required) {
|
|
47
|
+
throw new Error(`装配档缺失:${path}(包不完整?检查 package.json 的 files)`);
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const parsed = parseYaml(readFileSync(path, 'utf8'));
|
|
52
|
+
if (parsed === null || parsed === undefined)
|
|
53
|
+
return [];
|
|
54
|
+
if (!Array.isArray(parsed))
|
|
55
|
+
throw new Error(`装配档不是数组:${path}`);
|
|
56
|
+
return parsed.map((row) => resolveRowName(row, path));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 相对名(`./x.mjs`)按**该装配档自己的位置**解析成 `file://` 绝对入口。
|
|
60
|
+
*
|
|
61
|
+
* 🔴 这一步以前是 loader 的 include 插件做的(它会把 baseUrl 换成被包含文件的目录)。
|
|
62
|
+
* 合并改成在进程内做之后,include 不再参与 ⇒ 相对名会按**出厂档目录**解析,
|
|
63
|
+
* 也就是解析到别的地方去。差点静默带走仓内夹具那条用例。
|
|
64
|
+
*
|
|
65
|
+
* 包名(`@scope/pkg`、`pkg/sub`)原样不动 —— 它们由 loader 从自己所在位置解析。
|
|
66
|
+
*/
|
|
67
|
+
function resolveRowName(row, sourcePath) {
|
|
68
|
+
if (typeof row.name !== 'string')
|
|
69
|
+
return row;
|
|
70
|
+
if (!row.name.startsWith('./') && !row.name.startsWith('../'))
|
|
71
|
+
return row;
|
|
72
|
+
const abs = resolve(dirname(sourcePath), row.name);
|
|
73
|
+
return { ...row, name: pathToFileURL(abs).href };
|
|
74
|
+
}
|
|
75
|
+
/** 一行的覆盖键。 */
|
|
76
|
+
export function rowKey(row) {
|
|
77
|
+
return row.id ?? row.name;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 按 id 合并多层,**后面的整行替换前面的**。
|
|
81
|
+
*
|
|
82
|
+
* 🔴 **整行替换,不深合并 config**:深合并会让"这个值最终是什么"要读 N 层
|
|
83
|
+
* 才算得出来。同一条规矩出厂档里已经写着,这里是它第一次真的被执行。
|
|
84
|
+
*
|
|
85
|
+
* 顺序保持"首次出现的位置" —— 上层改了某行,它不会跳到列表末尾。
|
|
86
|
+
* (行序对激活没有语义,但对**人读**有:改一行不该让整份档看起来面目全非。)
|
|
87
|
+
*/
|
|
88
|
+
export function mergeAssembly(...layers) {
|
|
89
|
+
const order = [];
|
|
90
|
+
const byKey = new Map();
|
|
91
|
+
for (const layer of layers) {
|
|
92
|
+
for (const row of layer) {
|
|
93
|
+
const key = rowKey(row);
|
|
94
|
+
if (!byKey.has(key))
|
|
95
|
+
order.push(key);
|
|
96
|
+
byKey.set(key, row);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return order.map((k) => byKey.get(k));
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=layers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/plugin/layers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin/manager
|
|
3
|
+
* @description **插件管理**:装 / 卸 / 启 / 停,以及"现在到底跑着什么"。
|
|
4
|
+
*
|
|
5
|
+
* @layer plugin
|
|
6
|
+
*
|
|
7
|
+
* 两件事必须**同一次操作里都做**:
|
|
8
|
+
* ```
|
|
9
|
+
* 写用户层装配档 → 持久:一次性 CLI 进程、下次启动都带上
|
|
10
|
+
* 动 loader → 当场:这个长活进程立刻生效,不用重启
|
|
11
|
+
* ```
|
|
12
|
+
* 只写文件 = 页面上点了没反应;只动 loader = 重启后白装(loader 基类的
|
|
13
|
+
* `write()` 是空实现,运行时 create 的东西**不会**被写回装配档,已实测)。
|
|
14
|
+
*
|
|
15
|
+
* 🔴 **失败必须带原因。** 网络 / registry 401 / 版本不存在 / 装上了但不是
|
|
16
|
+
* Cordis 插件 / apply 抛了 —— 处置完全不同,合成一句"安装失败"等于没说。
|
|
17
|
+
*/
|
|
18
|
+
import { type AssemblyName } from './assembly.js';
|
|
19
|
+
import { type AssemblyRow } from './layers.js';
|
|
20
|
+
/** 插件装在哪。**不是** sps-cli 自己的 node_modules —— 不碰包目录。 */
|
|
21
|
+
export declare function pluginsDir(): string;
|
|
22
|
+
/**
|
|
23
|
+
* 失败原因分类。**每一类的处置不同**,所以不合并:
|
|
24
|
+
* - `network` 重试 / 换 registry
|
|
25
|
+
* - `auth` 配凭据
|
|
26
|
+
* - `not-found` 名字或版本写错
|
|
27
|
+
* - `not-plugin` 装上了,但它不是 Cordis 插件 —— 别写进装配档
|
|
28
|
+
* - `apply` 插件自己的代码抛了 —— 找作者
|
|
29
|
+
* - `conflict` id 重复 / 服务重名
|
|
30
|
+
*/
|
|
31
|
+
export type PluginErrorKind = 'network' | 'auth' | 'not-found' | 'not-plugin' | 'apply' | 'conflict' | 'unknown';
|
|
32
|
+
export declare class PluginError extends Error {
|
|
33
|
+
readonly kind: PluginErrorKind;
|
|
34
|
+
/** 底层工具的原文(npm 的 stderr 等)。**不截断**:截断的报错等于没有报错。 */
|
|
35
|
+
readonly detail?: string | undefined;
|
|
36
|
+
constructor(kind: PluginErrorKind, message: string,
|
|
37
|
+
/** 底层工具的原文(npm 的 stderr 等)。**不截断**:截断的报错等于没有报错。 */
|
|
38
|
+
detail?: string | undefined);
|
|
39
|
+
}
|
|
40
|
+
/** 从 npm 的 stderr 认出到底哪儿错了。 */
|
|
41
|
+
export declare function classifyNpmError(stderr: string): PluginErrorKind;
|
|
42
|
+
export interface InstallResult {
|
|
43
|
+
pkg: string;
|
|
44
|
+
version: string;
|
|
45
|
+
/** 解析出来的入口,写进装配档的就是它的 file:// 形式。 */
|
|
46
|
+
entry: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 把包装到 `~/.coral/plugins`,并解析出入口。
|
|
50
|
+
*
|
|
51
|
+
* 🔴 **写 `file://` 入口而不是裸包名**:实测裸包名是从 **loader 自己所在的包**
|
|
52
|
+
* 解析的(`loader.internal` 没设),跟 baseUrl 无关 ⇒ 装在用户目录的包
|
|
53
|
+
* 永远找不到。要支持裸包名得自己实现一个 ModuleLoader,没必要。
|
|
54
|
+
*/
|
|
55
|
+
export declare function installPackage(spec: string): Promise<InstallResult>;
|
|
56
|
+
/** `foo@1.2.3` / `@scope/foo@1.2.3` → 包名。**只对 registry spec 成立。** */
|
|
57
|
+
export declare function packageNameOf(spec: string): string;
|
|
58
|
+
export declare function uninstallPackage(name: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* 它能不能**当插件用**。
|
|
61
|
+
*
|
|
62
|
+
* 🔴 只验"能不能解析"是不够的:一个能解析但不是 Cordis 插件的包写进装配档,
|
|
63
|
+
* 下次启动整个进程起不来。已实测 `plugin add yaml` 之后连 `plugin remove`
|
|
64
|
+
* 自己都起不来(它当时也要先挂装配档)。
|
|
65
|
+
*
|
|
66
|
+
* ⚠️ 验的方式是**真的 import 它**(会执行模块顶层代码)。这是有意的:
|
|
67
|
+
* 我们下一秒本来就要挂它,提前一秒执行不增加风险,却能把失败挪到人还在看着的时候。
|
|
68
|
+
*/
|
|
69
|
+
export declare function assertIsPlugin(entry: string): Promise<void>;
|
|
70
|
+
export declare function readUserRows(target: AssemblyName | 'base'): AssemblyRow[];
|
|
71
|
+
export declare function writeUserRows(target: AssemblyName | 'base', rows: AssemblyRow[]): void;
|
|
72
|
+
/** 生效清单里每一行,外加它来自哪一层。console 插件页直接摆这个。 */
|
|
73
|
+
export interface PluginView extends AssemblyRow {
|
|
74
|
+
key: string;
|
|
75
|
+
layer: 'factory' | 'user';
|
|
76
|
+
}
|
|
77
|
+
export declare function listPlugins(target: AssemblyName): PluginView[];
|
|
78
|
+
/** 出厂档里有没有这一行 —— 有的话用户层只能**盖**,不能删。 */
|
|
79
|
+
export declare function isFactoryRow(target: AssemblyName, key: string): boolean;
|
|
80
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/plugin/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,OAAO,EAAE,KAAK,YAAY,EAAmC,MAAM,eAAe,CAAC;AACnF,OAAO,EACL,KAAK,WAAW,EAMjB,MAAM,aAAa,CAAC;AAIrB,sDAAsD;AACtD,wBAAgB,UAAU,IAAI,MAAM,CAInC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,MAAM,GACN,WAAW,GACX,YAAY,GACZ,OAAO,GACP,UAAU,GACV,SAAS,CAAC;AAEd,qBAAa,WAAY,SAAQ,KAAK;IAElC,QAAQ,CAAC,IAAI,EAAE,eAAe;IAE9B,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;gBAHf,IAAI,EAAE,eAAe,EAC9B,OAAO,EAAE,MAAM;IACf,mDAAmD;IAC1C,MAAM,CAAC,EAAE,MAAM,YAAA;CAK3B;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAehE;AAiBD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAkCzE;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAoBD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlE;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBjE;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,WAAW,EAAE,CAEzE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAMtF;AAED,0CAA0C;AAC1C,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;CAC3B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,EAAE,CAS9D;AAED,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAMvE"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin/manager
|
|
3
|
+
* @description **插件管理**:装 / 卸 / 启 / 停,以及"现在到底跑着什么"。
|
|
4
|
+
*
|
|
5
|
+
* @layer plugin
|
|
6
|
+
*
|
|
7
|
+
* 两件事必须**同一次操作里都做**:
|
|
8
|
+
* ```
|
|
9
|
+
* 写用户层装配档 → 持久:一次性 CLI 进程、下次启动都带上
|
|
10
|
+
* 动 loader → 当场:这个长活进程立刻生效,不用重启
|
|
11
|
+
* ```
|
|
12
|
+
* 只写文件 = 页面上点了没反应;只动 loader = 重启后白装(loader 基类的
|
|
13
|
+
* `write()` 是空实现,运行时 create 的东西**不会**被写回装配档,已实测)。
|
|
14
|
+
*
|
|
15
|
+
* 🔴 **失败必须带原因。** 网络 / registry 401 / 版本不存在 / 装上了但不是
|
|
16
|
+
* Cordis 插件 / apply 抛了 —— 处置完全不同,合成一句"安装失败"等于没说。
|
|
17
|
+
*/
|
|
18
|
+
import { execFile } from 'node:child_process';
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
20
|
+
import { createRequire } from 'node:module';
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
import { resolve } from 'node:path';
|
|
23
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
24
|
+
import { promisify } from 'node:util';
|
|
25
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
26
|
+
import { writeSecretFile } from '../infra/secretFile.js';
|
|
27
|
+
import { assemblyPath, effectiveAssembly } from './assembly.js';
|
|
28
|
+
import { mergeAssembly, readAssemblyFile, rowKey, userAssemblyDir, userAssemblyPath, } from './layers.js';
|
|
29
|
+
const exec = promisify(execFile);
|
|
30
|
+
/** 插件装在哪。**不是** sps-cli 自己的 node_modules —— 不碰包目录。 */
|
|
31
|
+
export function pluginsDir() {
|
|
32
|
+
return process.env.SPS_PLUGINS_DIR
|
|
33
|
+
? resolve(process.env.SPS_PLUGINS_DIR)
|
|
34
|
+
: resolve(homedir(), '.coral', 'plugins');
|
|
35
|
+
}
|
|
36
|
+
export class PluginError extends Error {
|
|
37
|
+
kind;
|
|
38
|
+
detail;
|
|
39
|
+
constructor(kind, message,
|
|
40
|
+
/** 底层工具的原文(npm 的 stderr 等)。**不截断**:截断的报错等于没有报错。 */
|
|
41
|
+
detail) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.kind = kind;
|
|
44
|
+
this.detail = detail;
|
|
45
|
+
this.name = 'PluginError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** 从 npm 的 stderr 认出到底哪儿错了。 */
|
|
49
|
+
export function classifyNpmError(stderr) {
|
|
50
|
+
const s = stderr.toLowerCase();
|
|
51
|
+
if (s.includes('e404') || s.includes('notarget') || s.includes('no matching version')) {
|
|
52
|
+
return 'not-found';
|
|
53
|
+
}
|
|
54
|
+
if (s.includes('e401') || s.includes('e403') || s.includes('need auth'))
|
|
55
|
+
return 'auth';
|
|
56
|
+
if (s.includes('enotfound') ||
|
|
57
|
+
s.includes('etimedout') ||
|
|
58
|
+
s.includes('econnrefused') ||
|
|
59
|
+
s.includes('network')) {
|
|
60
|
+
return 'network';
|
|
61
|
+
}
|
|
62
|
+
return 'unknown';
|
|
63
|
+
}
|
|
64
|
+
/** `~/.coral/plugins` 得是个有 package.json 的目录,否则 npm 会往上找。 */
|
|
65
|
+
function ensurePluginsDir() {
|
|
66
|
+
const dir = pluginsDir();
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
68
|
+
const pkg = resolve(dir, 'package.json');
|
|
69
|
+
if (!existsSync(pkg)) {
|
|
70
|
+
// 🔴 `private: true` —— 防止手滑把它发出去;也让 npm 不去猜 name/version。
|
|
71
|
+
writeSecretFile(pkg, `${JSON.stringify({ name: 'coral-plugins', private: true, version: '0.0.0' }, null, 2)}\n`);
|
|
72
|
+
}
|
|
73
|
+
return dir;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 把包装到 `~/.coral/plugins`,并解析出入口。
|
|
77
|
+
*
|
|
78
|
+
* 🔴 **写 `file://` 入口而不是裸包名**:实测裸包名是从 **loader 自己所在的包**
|
|
79
|
+
* 解析的(`loader.internal` 没设),跟 baseUrl 无关 ⇒ 装在用户目录的包
|
|
80
|
+
* 永远找不到。要支持裸包名得自己实现一个 ModuleLoader,没必要。
|
|
81
|
+
*/
|
|
82
|
+
export async function installPackage(spec) {
|
|
83
|
+
const dir = ensurePluginsDir();
|
|
84
|
+
try {
|
|
85
|
+
await exec('npm', ['install', '--no-audit', '--no-fund', '--save-exact', spec], {
|
|
86
|
+
cwd: dir,
|
|
87
|
+
timeout: 180_000,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
const stderr = e.stderr ?? String(e);
|
|
92
|
+
throw new PluginError(classifyNpmError(stderr), `安装 ${spec} 失败`, stderr);
|
|
93
|
+
}
|
|
94
|
+
// 🔴 包名要取**装好之后它自己声明的**,不能从 spec 推。
|
|
95
|
+
// spec 可以是本地路径(`/tmp/x/realplug`)、tarball、git URL ——
|
|
96
|
+
// 那时 `packageNameOf(spec)` 返回的是整条路径,后面所有按 key 的操作全部对不上。
|
|
97
|
+
// 实测:装成功了,但 list/停用/卸载 一律 404。
|
|
98
|
+
const name = installedNameOf(spec);
|
|
99
|
+
const req = createRequire(`${dir}/`);
|
|
100
|
+
let entry;
|
|
101
|
+
try {
|
|
102
|
+
entry = req.resolve(name);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
throw new PluginError('not-found', `${name} 装上了,但解析不到入口(它的 package.json 可能没有 main/exports)`, e instanceof Error ? e.message : String(e));
|
|
106
|
+
}
|
|
107
|
+
let version = '';
|
|
108
|
+
try {
|
|
109
|
+
version = req(`${name}/package.json`).version ?? '';
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// 有些包不导出 package.json(exports 收紧)。版本只用于展示,拿不到不算失败。
|
|
113
|
+
}
|
|
114
|
+
return { pkg: name, version, entry };
|
|
115
|
+
}
|
|
116
|
+
/** `foo@1.2.3` / `@scope/foo@1.2.3` → 包名。**只对 registry spec 成立。** */
|
|
117
|
+
export function packageNameOf(spec) {
|
|
118
|
+
const at = spec.lastIndexOf('@');
|
|
119
|
+
if (at <= 0)
|
|
120
|
+
return spec;
|
|
121
|
+
return spec.slice(0, at);
|
|
122
|
+
}
|
|
123
|
+
/** spec 是不是一个本地路径(而不是 registry 上的包名)。 */
|
|
124
|
+
function isPathSpec(spec) {
|
|
125
|
+
return spec.startsWith('.') || spec.startsWith('/') || spec.startsWith('file:');
|
|
126
|
+
}
|
|
127
|
+
/** 装完之后它到底叫什么。路径 spec 读它自己的 package.json;registry spec 才能从名字推。 */
|
|
128
|
+
function installedNameOf(spec) {
|
|
129
|
+
if (!isPathSpec(spec))
|
|
130
|
+
return packageNameOf(spec);
|
|
131
|
+
const dir = spec.startsWith('file:') ? fileURLToPath(spec) : resolve(spec);
|
|
132
|
+
const pkgPath = resolve(dir, 'package.json');
|
|
133
|
+
if (!existsSync(pkgPath)) {
|
|
134
|
+
throw new PluginError('not-found', `${spec} 里没有 package.json`);
|
|
135
|
+
}
|
|
136
|
+
const name = JSON.parse(readFileSync(pkgPath, 'utf8')).name;
|
|
137
|
+
if (!name)
|
|
138
|
+
throw new PluginError('not-found', `${spec} 的 package.json 没有 name`);
|
|
139
|
+
return name;
|
|
140
|
+
}
|
|
141
|
+
export async function uninstallPackage(name) {
|
|
142
|
+
const dir = ensurePluginsDir();
|
|
143
|
+
try {
|
|
144
|
+
await exec('npm', ['uninstall', '--no-audit', '--no-fund', name], {
|
|
145
|
+
cwd: dir,
|
|
146
|
+
timeout: 120_000,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
const stderr = e.stderr ?? String(e);
|
|
151
|
+
throw new PluginError(classifyNpmError(stderr), `卸载 ${name} 失败`, stderr);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 它能不能**当插件用**。
|
|
156
|
+
*
|
|
157
|
+
* 🔴 只验"能不能解析"是不够的:一个能解析但不是 Cordis 插件的包写进装配档,
|
|
158
|
+
* 下次启动整个进程起不来。已实测 `plugin add yaml` 之后连 `plugin remove`
|
|
159
|
+
* 自己都起不来(它当时也要先挂装配档)。
|
|
160
|
+
*
|
|
161
|
+
* ⚠️ 验的方式是**真的 import 它**(会执行模块顶层代码)。这是有意的:
|
|
162
|
+
* 我们下一秒本来就要挂它,提前一秒执行不增加风险,却能把失败挪到人还在看着的时候。
|
|
163
|
+
*/
|
|
164
|
+
export async function assertIsPlugin(entry) {
|
|
165
|
+
let mod;
|
|
166
|
+
try {
|
|
167
|
+
mod = await import(entry.startsWith('file://') ? entry : pathToFileURL(entry).href);
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
throw new PluginError('apply', `导入失败(模块顶层就抛了)`, e instanceof Error ? (e.stack ?? e.message) : String(e));
|
|
171
|
+
}
|
|
172
|
+
const m = mod.default ?? mod;
|
|
173
|
+
const ok = typeof m === 'function' ||
|
|
174
|
+
(typeof m === 'object' && m !== null && typeof m.apply === 'function');
|
|
175
|
+
if (!ok) {
|
|
176
|
+
throw new PluginError('not-plugin', '它不是 Cordis 插件(既不是函数,也没有 apply 导出)', `导出的键:${typeof m === 'object' && m ? Object.keys(m).join(', ') || '(无)' : typeof m}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ── 用户层装配档的读写 ────────────────────────────────────────────────
|
|
180
|
+
export function readUserRows(target) {
|
|
181
|
+
return readAssemblyFile(userAssemblyPath(target), false);
|
|
182
|
+
}
|
|
183
|
+
export function writeUserRows(target, rows) {
|
|
184
|
+
mkdirSync(userAssemblyDir(), { recursive: true });
|
|
185
|
+
const header = `# sps 装配档 · ${target}(用户层,叠在包内出厂档之上)\n` +
|
|
186
|
+
`# ⚠️ 本文件由 \`sps plugin\` 与 console 插件页改写,注释不会保留。\n\n`;
|
|
187
|
+
writeSecretFile(userAssemblyPath(target), header + stringifyYaml(rows));
|
|
188
|
+
}
|
|
189
|
+
export function listPlugins(target) {
|
|
190
|
+
const userKeys = new Set(mergeAssembly(readUserRows('base'), readUserRows(target)).map(rowKey));
|
|
191
|
+
return effectiveAssembly(target).map((row) => ({
|
|
192
|
+
...row,
|
|
193
|
+
key: rowKey(row),
|
|
194
|
+
layer: userKeys.has(rowKey(row)) ? 'user' : 'factory',
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
/** 出厂档里有没有这一行 —— 有的话用户层只能**盖**,不能删。 */
|
|
198
|
+
export function isFactoryRow(target, key) {
|
|
199
|
+
const factory = mergeAssembly(readAssemblyFile(assemblyPath('base'), true), readAssemblyFile(assemblyPath(target), true));
|
|
200
|
+
return factory.some((r) => rowKey(r) === key);
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/plugin/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin/run
|
|
3
|
+
* @description 插件应用的**生命周期包装**:挂载 → 等就绪 → 干活 → 收拾。
|
|
4
|
+
*
|
|
5
|
+
* @layer plugin
|
|
6
|
+
*
|
|
7
|
+
* sps 有两种进程形态,这里各给一个入口:
|
|
8
|
+
* ```
|
|
9
|
+
* withContext() 一次性命令:跑完就收拾,收拾完才返回
|
|
10
|
+
* startContext() 长驻进程(console / daemon):返回 stop(),由调用方挂到 SIGINT/SIGTERM
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* 🔴 **disposer 不许承担持久化职责。** 落盘要在**业务点**做(如 `captureFlush` ——
|
|
14
|
+
* 它是同步的、在卡片完成时调,不在退出时调);disposer 只做资源释放
|
|
15
|
+
* (关连接 · 清定时器 · 注销 watcher)。
|
|
16
|
+
* 理由:靠"每处记得 await dispose"就不是护栏;而只要没人把落盘写进 disposer,
|
|
17
|
+
* 就**没有可丢的东西**。这条把风险从流程移到设计。
|
|
18
|
+
*
|
|
19
|
+
* 🔴 **收拾必须有界。** 一个挂住的 disposer 会让**命令永远不退出** ——
|
|
20
|
+
* 那比丢一次缓冲严重得多(用户看到的是 CLI 卡死)。
|
|
21
|
+
* ⇒ 超时后**报出来并继续退出**,不静默、也不无限等。
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ 全部插件挂在**同一个根 fiber** 下,于是"收拾"只需要 dispose 这一个句柄。
|
|
24
|
+
* (实测:根 fiber dispose 后,子服务真的从 ctx 上消失。)
|
|
25
|
+
*/
|
|
26
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
27
|
+
import { type SettleOptions } from './context.js';
|
|
28
|
+
export interface RunOptions extends SettleOptions {
|
|
29
|
+
/** 收拾的上限,默认 5000ms。超时不抛,只上报并继续。 */
|
|
30
|
+
disposeTimeoutMs?: number;
|
|
31
|
+
/** 收拾超时时的回调。缺省行为:往 stderr 写一行 —— **不能静默**。 */
|
|
32
|
+
onDisposeTimeout?: (ms: number) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 一次性命令:挂载 → 等就绪 → 跑 body → **收拾完才返回**。
|
|
36
|
+
*
|
|
37
|
+
* 🔴 body 抛错时**照样收拾**(finally),否则一次失败的命令会留下没关的资源。
|
|
38
|
+
* 🔴 就绪失败时**不跑 body** —— 缺提供方是配置错误,不是降级运行。
|
|
39
|
+
*/
|
|
40
|
+
export declare function withContext<T>(mount: (ctx: Context) => void | Promise<void>, body: (ctx: Context) => Promise<T>, opts?: RunOptions): Promise<T>;
|
|
41
|
+
export interface RunningContext {
|
|
42
|
+
ctx: Context;
|
|
43
|
+
/** 收拾;有界。挂到 SIGINT/SIGTERM 上。重复调用是安全的。 */
|
|
44
|
+
stop: () => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 长驻进程:挂载 → 等就绪 → 交回 ctx 与 stop()。
|
|
48
|
+
*
|
|
49
|
+
* ⚠️ 调用方负责把 `stop` 挂到信号上 —— console / im / logs / dashboard / agent
|
|
50
|
+
* **本来就各自有 SIGINT/SIGTERM 处理**,接上去即可,不新增机制。
|
|
51
|
+
*/
|
|
52
|
+
export declare function startContext(mount: (ctx: Context) => void | Promise<void>, opts?: RunOptions): Promise<RunningContext>;
|
|
53
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/plugin/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,mCAAmC;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AA2BD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EAClC,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,CAAC,CAAC,CAWZ;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAC7C,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,cAAc,CAAC,CAoBzB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createSpsContext } from './context.js';
|
|
2
|
+
const DEFAULT_DISPOSE_TIMEOUT_MS = 5000;
|
|
3
|
+
function warnTimeout(ms) {
|
|
4
|
+
process.stderr.write(`⚠️ 插件收拾超过 ${ms}ms 仍未完成,继续退出。` +
|
|
5
|
+
`多半是某个 disposer 在做 I/O —— disposer 只该释放资源,不该落盘。\n`);
|
|
6
|
+
}
|
|
7
|
+
/** 收拾,但有界:超时就放手,并把这件事说出来。 */
|
|
8
|
+
async function disposeBounded(dispose, opts) {
|
|
9
|
+
const ms = opts.disposeTimeoutMs ?? DEFAULT_DISPOSE_TIMEOUT_MS;
|
|
10
|
+
let timer;
|
|
11
|
+
const timeout = new Promise((resolve) => {
|
|
12
|
+
timer = setTimeout(() => resolve('timeout'), ms);
|
|
13
|
+
timer.unref?.(); // 别让这个计时器自己把进程吊住
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const r = await Promise.race([dispose().then(() => 'done'), timeout]);
|
|
17
|
+
if (r === 'timeout')
|
|
18
|
+
(opts.onDisposeTimeout ?? warnTimeout)(ms);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
if (timer)
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 一次性命令:挂载 → 等就绪 → 跑 body → **收拾完才返回**。
|
|
27
|
+
*
|
|
28
|
+
* 🔴 body 抛错时**照样收拾**(finally),否则一次失败的命令会留下没关的资源。
|
|
29
|
+
* 🔴 就绪失败时**不跑 body** —— 缺提供方是配置错误,不是降级运行。
|
|
30
|
+
*/
|
|
31
|
+
export async function withContext(mount, body, opts = {}) {
|
|
32
|
+
const { ctx, requireReady } = createSpsContext();
|
|
33
|
+
const root = ctx.plugin(async (child) => {
|
|
34
|
+
await mount(child);
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
await requireReady(opts);
|
|
38
|
+
return await body(ctx);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await disposeBounded(() => root.dispose(), opts);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 长驻进程:挂载 → 等就绪 → 交回 ctx 与 stop()。
|
|
46
|
+
*
|
|
47
|
+
* ⚠️ 调用方负责把 `stop` 挂到信号上 —— console / im / logs / dashboard / agent
|
|
48
|
+
* **本来就各自有 SIGINT/SIGTERM 处理**,接上去即可,不新增机制。
|
|
49
|
+
*/
|
|
50
|
+
export async function startContext(mount, opts = {}) {
|
|
51
|
+
const { ctx, requireReady } = createSpsContext();
|
|
52
|
+
const root = ctx.plugin(async (child) => {
|
|
53
|
+
await mount(child);
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
await requireReady(opts);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
// 就绪失败也要收拾:否则一个起不来的进程会留下已挂载的那部分插件。
|
|
60
|
+
await disposeBounded(() => root.dispose(), opts);
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
let stopped;
|
|
64
|
+
return {
|
|
65
|
+
ctx,
|
|
66
|
+
stop: () => {
|
|
67
|
+
stopped ??= disposeBounded(() => root.dispose(), opts);
|
|
68
|
+
return stopped;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/plugin/run.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,gBAAgB,EAAsB,MAAM,cAAc,CAAC;AASpE,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAExC,SAAS,WAAW,CAAC,EAAU;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,cAAc,EAAE,eAAe;QAC7B,kDAAkD,CACrD,CAAC;AACJ,CAAC;AAED,6BAA6B;AAC7B,KAAK,UAAU,cAAc,CAAC,OAA4B,EAAE,IAAgB;IAC1E,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;IAC/D,IAAI,KAAiC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,EAAE;QACjD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;QACjD,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,iBAAiB;IACpC,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAe,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,KAAK,SAAS;YAAE,CAAC,IAAI,CAAC,gBAAgB,IAAI,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAA6C,EAC7C,IAAkC,EAClC,OAAmB,EAAE;IAErB,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAAC;IACjD,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QAC/C,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC,CAAgD,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;YAAS,CAAC;QACT,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAQD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAA6C,EAC7C,OAAmB,EAAE;IAErB,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAAC;IACjD,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QAC/C,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC,CAAgD,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,mCAAmC;QACnC,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;QACjD,MAAM,CAAC,CAAC;IACV,CAAC;IACD,IAAI,OAAkC,CAAC;IACvC,OAAO;QACL,GAAG;QACH,IAAI,EAAE,GAAG,EAAE;YACT,OAAO,KAAK,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;YACvD,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 美术资源生成 Job(阶段 1:串行生成)。
|
|
3
|
+
* 读 docs/art-manifest.json → 对每个 asset 调图像管线生成(prompt = desc + 全局 style)→
|
|
4
|
+
* 存 repo/assets/<id>.png + assets/asset-status.json(done/failed)。
|
|
5
|
+
* 失败不阻塞其它(代码侧回退矢量)。匹配复用/并发提速留阶段 3。
|
|
6
|
+
*/
|
|
7
|
+
import { type ProjectLocator } from '../../core/art/assetLocator.js';
|
|
8
|
+
import { type MediaAdapterLookup } from '../media/generateAsset.js';
|
|
9
|
+
import { type UsableMediaProvider } from '../media/mediaProviders.js';
|
|
2
10
|
import { type ArtPrompts } from './artPrompt.js';
|
|
3
11
|
import { type PixelOps } from './composeAsset.js';
|
|
4
|
-
import { type
|
|
5
|
-
import { type ProjectLocator } from '../../core/art/assetLocator.js';
|
|
12
|
+
import { type PackedSheet } from './sheet.js';
|
|
6
13
|
export interface ArtAsset {
|
|
7
14
|
id: string;
|
|
8
15
|
usage?: string;
|
|
@@ -179,6 +186,8 @@ interface GenCtx {
|
|
|
179
186
|
assetsDir: string;
|
|
180
187
|
artPrompts: ArtPrompts;
|
|
181
188
|
ops: PixelOps;
|
|
189
|
+
/** 媒体适配器注册表 —— 一路透传到 `generateAsset`。 */
|
|
190
|
+
adapters: MediaAdapterLookup;
|
|
182
191
|
}
|
|
183
192
|
/** 生成单张资源(含尺寸+抠图)→ 存盘。**429/限流/5xx/超时 自动指数退避重试**(适配 API QPS 限制)。
|
|
184
193
|
*
|
|
@@ -249,6 +258,12 @@ export interface ArtGenTask {
|
|
|
249
258
|
jobId: string;
|
|
250
259
|
manifestFile: string;
|
|
251
260
|
artPrompts: ArtPrompts;
|
|
261
|
+
/**
|
|
262
|
+
* 媒体适配器注册表。
|
|
263
|
+
* 🔴 美术真跑在**子进程**(`artRunChild`)里 —— 进程边界上传不了函数,
|
|
264
|
+
* 所以那边是自己挂一次装配档拿到 `sps.media`,不是从父进程序列化过来的。
|
|
265
|
+
*/
|
|
266
|
+
adapters: MediaAdapterLookup;
|
|
252
267
|
}
|
|
253
268
|
export declare function generateGameArt(task: ArtGenTask, onProgress?: (done: number, total: number) => void, opts?: {
|
|
254
269
|
rawOnly?: boolean;
|