@actiondock/core 2.0.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 (43) hide show
  1. package/README.md +50 -0
  2. package/package.json +51 -0
  3. package/src/build/builder.ts +205 -0
  4. package/src/build/index.ts +2 -0
  5. package/src/build/templates.ts +59 -0
  6. package/src/doctor/doctor.ts +332 -0
  7. package/src/doctor/index.ts +2 -0
  8. package/src/doctor/types.ts +25 -0
  9. package/src/export/index.ts +2 -0
  10. package/src/export/skill.ts +349 -0
  11. package/src/export/templates.ts +258 -0
  12. package/src/filter/index.ts +1 -0
  13. package/src/filter/intent.ts +154 -0
  14. package/src/index.ts +13 -0
  15. package/src/profile/client.ts +302 -0
  16. package/src/profile/index.ts +3 -0
  17. package/src/profile/manager.ts +341 -0
  18. package/src/profile/types.ts +71 -0
  19. package/src/project/index.ts +3 -0
  20. package/src/project/init.ts +194 -0
  21. package/src/project/loader.ts +382 -0
  22. package/src/project/types.ts +62 -0
  23. package/src/registry/index.ts +2 -0
  24. package/src/registry/registry.ts +703 -0
  25. package/src/registry/types.ts +127 -0
  26. package/src/runtime/context.ts +232 -0
  27. package/src/runtime/env.ts +172 -0
  28. package/src/runtime/execution-manager.ts +74 -0
  29. package/src/runtime/index.ts +5 -0
  30. package/src/runtime/runner.ts +368 -0
  31. package/src/runtime/standalone.ts +429 -0
  32. package/src/schema/validator.ts +61 -0
  33. package/src/server/body.ts +112 -0
  34. package/src/server/index.ts +6 -0
  35. package/src/server/runtime-registry.ts +80 -0
  36. package/src/server/security.ts +115 -0
  37. package/src/server/server.ts +572 -0
  38. package/src/server/types.ts +42 -0
  39. package/src/storage/index.ts +64 -0
  40. package/src/storage/mask.ts +34 -0
  41. package/src/storage/sqlite.ts +578 -0
  42. package/src/storage/types.ts +111 -0
  43. package/src/utils/index.ts +60 -0
@@ -0,0 +1,2 @@
1
+ export * from "./doctor";
2
+ export * from "./types";
@@ -0,0 +1,25 @@
1
+ export type CheckStatus = "ok" | "warn" | "error";
2
+
3
+ export interface DoctorCheckItem {
4
+ id: string;
5
+ category: "runtime" | "storage" | "registry" | "project";
6
+ name: string;
7
+ status: CheckStatus;
8
+ message: string;
9
+ detail?: string;
10
+ fix?: string;
11
+ }
12
+
13
+ export interface DoctorReport {
14
+ ok: boolean;
15
+ hasProject: boolean;
16
+ projectRoot?: string;
17
+ packageId?: string;
18
+ summary: {
19
+ total: number;
20
+ ok: number;
21
+ warn: number;
22
+ error: number;
23
+ };
24
+ checks: DoctorCheckItem[];
25
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./skill";
2
+ export * from "./templates";
@@ -0,0 +1,349 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname, join, resolve } from "node:path";
3
+ import { buildProject } from "../build/builder";
4
+ import {
5
+ discoverPlaybookFiles,
6
+ loadActionFileMap,
7
+ loadActions,
8
+ loadPlaybooks,
9
+ loadProjectConfig,
10
+ } from "../project/loader";
11
+ import type { ProjectConfig } from "../project/types";
12
+ import { getPackageSlug } from "../utils";
13
+ import { generateSkillJson, generateSkillMd, generateSourceSkillMd, generateStandaloneSkillMd } from "./templates";
14
+
15
+ /**
16
+ * 导出 Agent Skill 产物时的配置选项。
17
+ */
18
+ export interface ExportSkillOptions {
19
+ /** 源码项目根目录 */
20
+ projectRoot: string;
21
+ /** 导出模式:source (源码模式) 或 standalone (独立二进制模式) */
22
+ mode?: "source" | "standalone";
23
+ /** 是否强制独立二进制模式 */
24
+ standalone?: boolean;
25
+ /** 二进制编译目标架构(默认 host) */
26
+ target?: string;
27
+ /** 导出目录路径(默认 dist/skills/) */
28
+ outDir?: string;
29
+ /** 是否自动压缩打包为 .skill.tar.gz 归档包 */
30
+ archive?: boolean;
31
+ /** 按需挑选的 Playbook 列表(触发 Playbook-driven 最小化依赖 Tree-shaking 导出) */
32
+ playbooks?: string[];
33
+ /** 显式挑选导出的 Action ID 清单 */
34
+ actions?: string[];
35
+ /** 独立模式下是否开启代码混淆压缩 */
36
+ minify?: boolean;
37
+ /** 独立模式下是否编译为字节码 */
38
+ bytecode?: boolean;
39
+ }
40
+
41
+ /**
42
+ * Skill 导出完成后的产物描述结果。
43
+ */
44
+ export interface ExportSkillResult {
45
+ /** 所属 Package ID */
46
+ packageId: string;
47
+ /** 版本号 */
48
+ version: string;
49
+ /** 导出模式 */
50
+ mode: "source" | "standalone";
51
+ /** 目标架构 */
52
+ target: string;
53
+ /** 生成的 Skill 目录绝对路径 */
54
+ skillDir: string;
55
+ /** 若开启了 archive,生成的 tar.gz 归档文件绝对路径 */
56
+ archivePath?: string;
57
+ /** 导出的 Action 数量 */
58
+ actionsCount: number;
59
+ /** 导出的 Playbook 数量 */
60
+ playbooksCount: number;
61
+ }
62
+
63
+ /**
64
+ * 将 ActionDock 项目导出为兼容各大 AI Agent 平台(如 Claude Desktop / Antigravity / Open-Interpreter 等)的通用 Agent Skill 规范包。
65
+ *
66
+ * 支持两种模式:
67
+ * 1. source 源码模式:导出 SKILL.md + actiondock.json + 源码文件,配合 CLI 直接执行。
68
+ * 2. standalone 独立模式:导出 SKILL.md + 单文件独立二进制可执行文件,目标环境零依赖即跑。
69
+ *
70
+ * 支持 Playbook 驱动的最小化 Tree-shaking 依赖裁剪。
71
+ *
72
+ * @param options 导出配置选项
73
+ * @returns 导出产物详细结果
74
+ */
75
+ export async function exportSkill(
76
+ options: ExportSkillOptions
77
+ ): Promise<ExportSkillResult> {
78
+ const root = resolve(options.projectRoot);
79
+ const config = loadProjectConfig(root);
80
+ const mode: "source" | "standalone" =
81
+ options.standalone || options.mode === "standalone" ? "standalone" : "source";
82
+ const target = options.target || "host";
83
+
84
+ const actionsMap = await loadActions(root, config.actionsDir);
85
+ const playbooksMap = loadPlaybooks(root, config.playbooksDir);
86
+
87
+ // Map each action ID to its corresponding source file path
88
+ const actionFileMap = await loadActionFileMap(root, config.actionsDir);
89
+
90
+ let selectedPlaybooks = Array.from(playbooksMap.values());
91
+ let selectedActions = Array.from(actionsMap.values());
92
+
93
+ // 1. If playbooks are explicitly specified (Playbook-driven minimal export)
94
+ if (options.playbooks && options.playbooks.length > 0) {
95
+ const specifiedPlaybookIds = new Set(options.playbooks);
96
+ const pbList = [];
97
+ for (const id of specifiedPlaybookIds) {
98
+ const pb = playbooksMap.get(id);
99
+ if (!pb) {
100
+ throw new Error(
101
+ `Playbook '${id}' specified in export options not found in project`
102
+ );
103
+ }
104
+ pbList.push(pb);
105
+ }
106
+ selectedPlaybooks = pbList;
107
+
108
+ // If actions were not explicitly specified, derive required actions from selected playbooks
109
+ if (!options.actions || options.actions.length === 0) {
110
+ const requiredActions = new Set<string>();
111
+ for (const pb of selectedPlaybooks) {
112
+ if (pb.actions) {
113
+ for (const act of pb.actions) {
114
+ requiredActions.add(act);
115
+ }
116
+ }
117
+ }
118
+ if (requiredActions.size > 0) {
119
+ for (const actId of requiredActions) {
120
+ if (!actionsMap.has(actId)) {
121
+ console.warn(
122
+ `[WARN] Action '${actId}' referenced in playbook is not found in project`
123
+ );
124
+ }
125
+ }
126
+ selectedActions = Array.from(actionsMap.values()).filter((a) =>
127
+ requiredActions.has(a.id)
128
+ );
129
+ }
130
+ }
131
+ }
132
+
133
+ // 2. If actions are explicitly specified (Action-driven export)
134
+ if (options.actions && options.actions.length > 0) {
135
+ const specifiedActionIds = new Set(options.actions);
136
+ for (const actId of specifiedActionIds) {
137
+ if (!actionsMap.has(actId)) {
138
+ throw new Error(
139
+ `Action '${actId}' specified in export options not found in project`
140
+ );
141
+ }
142
+ }
143
+ selectedActions = Array.from(actionsMap.values()).filter((a) =>
144
+ specifiedActionIds.has(a.id)
145
+ );
146
+
147
+ // If playbooks were not explicitly specified, tree-shake playbooks whose required actions are not included
148
+ if (!options.playbooks || options.playbooks.length === 0) {
149
+ selectedPlaybooks = selectedPlaybooks.filter((pb) => {
150
+ if (!pb.actions || pb.actions.length === 0) return true;
151
+ return pb.actions.every((a) => specifiedActionIds.has(a));
152
+ });
153
+ }
154
+ }
155
+
156
+ const pkgSlug = getPackageSlug(config.id);
157
+
158
+ const targetSuffix = mode === "standalone" && target !== "host" ? `-${target}` : "";
159
+ const skillFolderName = `${pkgSlug}-skill${targetSuffix}`;
160
+ const defaultSkillDir = join(root, "dist", skillFolderName);
161
+ const skillDir = resolve(options.outDir || defaultSkillDir);
162
+
163
+ const playbooksDestDir = join(skillDir, "playbooks");
164
+
165
+ if (mode === "source") {
166
+ // ----------------------------------------------------
167
+ // SOURCE SKILL EXPORT (Default)
168
+ // Structure: SKILL.md + actiondock.json + package.json + actions/* + playbooks/*
169
+ // ----------------------------------------------------
170
+ const actionsDestDir = join(skillDir, "actions");
171
+ mkdirSync(actionsDestDir, { recursive: true });
172
+ if (selectedPlaybooks.length > 0) {
173
+ mkdirSync(playbooksDestDir, { recursive: true });
174
+ }
175
+
176
+ // 1. Generate SKILL.md for Source Package
177
+ const skillMd = generateSourceSkillMd(
178
+ config,
179
+ selectedActions,
180
+ selectedPlaybooks
181
+ );
182
+ writeFileSync(join(skillDir, "SKILL.md"), skillMd, "utf-8");
183
+
184
+ // 2. Export tailored actiondock.json
185
+ const exportedConfig: Partial<ProjectConfig> = {
186
+ id: config.id,
187
+ name: config.name,
188
+ version: config.version,
189
+ description: config.description,
190
+ actionsDir: "actions",
191
+ playbooksDir: "playbooks",
192
+ };
193
+ if (config.config) {
194
+ exportedConfig.config = config.config;
195
+ }
196
+ writeFileSync(
197
+ join(skillDir, "actiondock.json"),
198
+ JSON.stringify(exportedConfig, null, 2) + "\n",
199
+ "utf-8"
200
+ );
201
+
202
+ // 3. Export package.json
203
+ const projectPkgJsonPath = join(root, "package.json");
204
+ if (existsSync(projectPkgJsonPath)) {
205
+ try {
206
+ const rawPkg = readFileSync(projectPkgJsonPath, "utf-8");
207
+ const parsedPkg = JSON.parse(rawPkg);
208
+ const exportedPkg = {
209
+ name: parsedPkg.name || pkgSlug,
210
+ version: config.version || parsedPkg.version || "0.1.0",
211
+ description: config.description || parsedPkg.description,
212
+ type: "module",
213
+ dependencies: parsedPkg.dependencies || {
214
+ "@actiondock/sdk": "^2.0.0",
215
+ },
216
+ devDependencies: parsedPkg.devDependencies,
217
+ };
218
+ writeFileSync(
219
+ join(skillDir, "package.json"),
220
+ JSON.stringify(exportedPkg, null, 2) + "\n",
221
+ "utf-8"
222
+ );
223
+ } catch {
224
+ copyFileSync(projectPkgJsonPath, join(skillDir, "package.json"));
225
+ }
226
+ } else {
227
+ const minimalPkg = {
228
+ name: pkgSlug,
229
+ version: config.version,
230
+ description: config.description,
231
+ type: "module",
232
+ dependencies: {
233
+ "@actiondock/sdk": "^2.0.0",
234
+ },
235
+ };
236
+ writeFileSync(
237
+ join(skillDir, "package.json"),
238
+ JSON.stringify(minimalPkg, null, 2) + "\n",
239
+ "utf-8"
240
+ );
241
+ }
242
+
243
+ // 4. Copy tsconfig.json if available
244
+ const tsconfigPath = join(root, "tsconfig.json");
245
+ if (existsSync(tsconfigPath)) {
246
+ copyFileSync(tsconfigPath, join(skillDir, "tsconfig.json"));
247
+ }
248
+
249
+ // 5. Copy selected action source files
250
+ for (const act of selectedActions) {
251
+ const entry = actionFileMap.get(act.id);
252
+ const srcPath = entry?.filePath;
253
+ if (srcPath && existsSync(srcPath)) {
254
+ copyFileSync(srcPath, join(actionsDestDir, basename(srcPath)));
255
+ }
256
+ }
257
+
258
+ // 6. Copy selected playbooks
259
+ for (const pb of selectedPlaybooks) {
260
+ if (pb.filePath && existsSync(pb.filePath)) {
261
+ const filename = basename(pb.filePath);
262
+ copyFileSync(pb.filePath, join(playbooksDestDir, filename));
263
+ }
264
+ }
265
+ } else {
266
+ // ----------------------------------------------------
267
+ // STANDALONE SKILL EXPORT (--standalone)
268
+ // Structure: SKILL.md + actiondock.skill.json + bin/<binary> + playbooks/*
269
+ // ----------------------------------------------------
270
+ const binDir = join(skillDir, "bin");
271
+ mkdirSync(binDir, { recursive: true });
272
+ if (selectedPlaybooks.length > 0) {
273
+ mkdirSync(playbooksDestDir, { recursive: true });
274
+ }
275
+
276
+ const binaryName = pkgSlug;
277
+ const binaryPath = join(binDir, binaryName);
278
+
279
+ // Build standalone binary with selected actions
280
+ const buildRes = await buildProject({
281
+ projectRoot: root,
282
+ target: options.target,
283
+ outfile: binaryPath,
284
+ actions: selectedActions.map((a) => a.id),
285
+ minify: options.minify,
286
+ bytecode: options.bytecode,
287
+ });
288
+
289
+ const actualBinaryName = basename(buildRes.executablePath);
290
+
291
+ // Generate SKILL.md for Standalone Binary
292
+ const skillMd = generateStandaloneSkillMd(
293
+ config,
294
+ selectedActions,
295
+ selectedPlaybooks,
296
+ `./bin/${actualBinaryName}`
297
+ );
298
+ writeFileSync(join(skillDir, "SKILL.md"), skillMd, "utf-8");
299
+
300
+ // Generate actiondock.skill.json
301
+ const skillJson = generateSkillJson(
302
+ config,
303
+ selectedActions,
304
+ actualBinaryName,
305
+ target
306
+ );
307
+ writeFileSync(join(skillDir, "actiondock.skill.json"), skillJson, "utf-8");
308
+
309
+ // Copy selected playbooks
310
+ for (const pb of selectedPlaybooks) {
311
+ if (pb.filePath && existsSync(pb.filePath)) {
312
+ const filename = basename(pb.filePath);
313
+ copyFileSync(pb.filePath, join(playbooksDestDir, filename));
314
+ }
315
+ }
316
+ }
317
+
318
+ let archivePath: string | undefined;
319
+ if (options.archive) {
320
+ const zipName = `${skillFolderName}.zip`;
321
+ archivePath = join(dirname(skillDir), zipName);
322
+ const zipProc = Bun.spawnSync(
323
+ ["zip", "-r", archivePath, basename(skillDir)],
324
+ {
325
+ cwd: dirname(skillDir),
326
+ stdout: "pipe",
327
+ stderr: "pipe",
328
+ }
329
+ );
330
+ if (zipProc.exitCode !== 0) {
331
+ console.warn(
332
+ `[WARN] Failed to create zip archive: ${zipProc.stderr.toString()}`
333
+ );
334
+ archivePath = undefined;
335
+ }
336
+ }
337
+
338
+ return {
339
+ packageId: config.id,
340
+ version: config.version,
341
+ mode,
342
+ target,
343
+ skillDir,
344
+ archivePath,
345
+ actionsCount: selectedActions.length,
346
+ playbooksCount: selectedPlaybooks.length,
347
+ };
348
+ }
349
+
@@ -0,0 +1,258 @@
1
+ import { basename } from "node:path";
2
+ import type { ActionDefinition } from "@actiondock/sdk";
3
+ import type { PlaybookDefinition, ProjectConfig } from "../project/types";
4
+
5
+ function getCleanSkillMetadata(config: ProjectConfig) {
6
+ const cleanName = config.id.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
7
+ const desc = config.description || `AI Agent skill for ${config.name} (${config.id})`;
8
+ return { cleanName, desc };
9
+ }
10
+
11
+ function renderActionListMarkdown(
12
+ actions: ActionDefinition[],
13
+ options: { packageId?: string } = {}
14
+ ): string {
15
+ return actions
16
+ .map((a) => {
17
+ const aDesc = a.description ? ` - ${a.description}` : "";
18
+ let params = "";
19
+ if (
20
+ a.inputSchema &&
21
+ typeof a.inputSchema === "object" &&
22
+ (a.inputSchema as any).properties
23
+ ) {
24
+ const props = Object.keys((a.inputSchema as any).properties);
25
+ const req = (a.inputSchema as any).required || [];
26
+ params = `\n - 参数列表: ${props
27
+ .map((p) => (req.includes(p) ? `\`${p}\` (必填)` : `\`${p}\``))
28
+ .join(", ")}`;
29
+ }
30
+ const idLabel = options.packageId
31
+ ? `\`${options.packageId}/${a.id}\` (或 \`${a.id}\`)`
32
+ : `\`${a.id}\``;
33
+ return `* ${idLabel}${aDesc}${params}`;
34
+ })
35
+ .join("\n");
36
+ }
37
+
38
+ function renderPlaybookSectionMarkdown(playbooks: PlaybookDefinition[]): string {
39
+ if (playbooks.length === 0) return "";
40
+ const list = playbooks
41
+ .map((p) => {
42
+ const rel = `./playbooks/${basename(p.filePath)}`;
43
+ return `* **${p.id}** (\`${rel}\`): ${p.description || "任务指南"}`;
44
+ })
45
+ .join("\n");
46
+ return `
47
+ ## 任务指南 (Playbook SOPs)
48
+
49
+ Playbook 为复杂任务提供逐步操作规程。详细 SOP 请阅读对应 Markdown 文档:
50
+
51
+ ${list}
52
+ `;
53
+ }
54
+
55
+ export function generateSourceSkillMd(
56
+ config: ProjectConfig,
57
+ actions: ActionDefinition[],
58
+ playbooks: PlaybookDefinition[]
59
+ ): string {
60
+ const { cleanName, desc } = getCleanSkillMetadata(config);
61
+ const pkgId = config.id;
62
+ const firstAction = actions[0]?.id || "sample.greet";
63
+
64
+ const actionListMd = renderActionListMarkdown(actions, { packageId: pkgId });
65
+ const playbookSection = renderPlaybookSectionMarkdown(playbooks);
66
+
67
+ return `---
68
+ name: ${cleanName}
69
+ description: ${desc}
70
+ ---
71
+
72
+ # ${config.name} (${config.id})
73
+
74
+ ${desc}
75
+
76
+ ## ActionDock 运行时 (ActionDock Runtime)
77
+
78
+ 本技能为 **ActionDock 源码型 Package (Source Skill)**。AI Agent 可直接通过已安装的 ActionDock 命令行工具 (\`ac\`) 执行其中的 Action。
79
+
80
+ ### 注册与链接 (Idempotent Setup)
81
+
82
+ 在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\` 并完成注册:
83
+
84
+ \`\`\`bash
85
+ ac link "<skill_root>"
86
+ \`\`\`
87
+
88
+ > \`ac link\` 天然具备幂等性,同一 Package 多次执行会直接更新路径,可安全重复调用。
89
+
90
+ ### 执行 Action (统一推荐 Package-Qualified ID)
91
+
92
+ 为避免多技能之间的 Action ID 命名冲突,建议统一使用带有 Package 前缀的完全限定 ID:
93
+
94
+ \`\`\`bash
95
+ # 格式:ac run <package-id>/<action-id> --input '<json>'
96
+ ac run ${pkgId}/${firstAction} --input '{"param": "value"}'
97
+ \`\`\`
98
+
99
+ > **免注册本地执行 (Direct Execution Alternative)**:
100
+ > 若 Agent 工作目录已位于本 Skill 根目录,亦可直接免 link 执行:
101
+ > \`\`\`bash
102
+ > cd <skill_root>
103
+ > ac run <action-id> --input '<json>'
104
+ > \`\`\`
105
+
106
+ 所有 Action 执行结果均在 \`stdout\` 输出标准格式的 JSON Envelope:
107
+ \`\`\`json
108
+ {
109
+ "ok": true,
110
+ "runId": "01J...",
111
+ "data": { ... }
112
+ }
113
+ \`\`\`
114
+ 日志与诊断信息输出至 \`stderr\`。
115
+
116
+ ---
117
+
118
+ ## Action 目录
119
+
120
+ ${actionListMd}
121
+ ${playbookSection}
122
+ ---
123
+
124
+ ## 运行时配置与持久化状态
125
+
126
+ 如需检查或配置该 Package 的运行时参数与持久化数据:
127
+
128
+ \`\`\`bash
129
+ # 查看与设置配置项
130
+ ac config list --package ${pkgId}
131
+ ac config set KEY VALUE --package ${pkgId}
132
+
133
+ # 查看与检索状态数据
134
+ ac state list --package ${pkgId}
135
+ ac state get KEY --package ${pkgId}
136
+ \`\`\`
137
+ `;
138
+ }
139
+
140
+ export function generateStandaloneSkillMd(
141
+ config: ProjectConfig,
142
+ actions: ActionDefinition[],
143
+ playbooks: PlaybookDefinition[],
144
+ binaryRelPath = "./bin/action-bin"
145
+ ): string {
146
+ const { cleanName, desc } = getCleanSkillMetadata(config);
147
+ const firstAction = actions[0]?.id || "sample.greet";
148
+
149
+ const actionListMd = renderActionListMarkdown(actions);
150
+ const playbookSection = renderPlaybookSectionMarkdown(playbooks);
151
+
152
+ return `---
153
+ name: ${cleanName}
154
+ description: ${desc}
155
+ ---
156
+
157
+ # ${config.name} (${config.id})
158
+
159
+ ${desc}
160
+
161
+ ## 如何调用 Action
162
+
163
+ 使用 Skill 目录中自带的独立可执行文件 \`${binaryRelPath}\` 即可完成工具发现与调用。
164
+ **该工具无需在系统预先安装任何依赖**(无需安装 Node.js、Bun、Python 或 Java)。
165
+
166
+ ### 发现可用 Action 清单
167
+ \`\`\`bash
168
+ ${binaryRelPath} list --json
169
+ \`\`\`
170
+
171
+ ### 查看 Action 结构与入参 Schema
172
+ \`\`\`bash
173
+ ${binaryRelPath} describe <action-id> --json
174
+ \`\`\`
175
+
176
+ ### 执行 Action
177
+ \`\`\`bash
178
+ ${binaryRelPath} run <action-id> --input '{"param": "value"}'
179
+
180
+ # 示例:
181
+ ${binaryRelPath} run ${firstAction} --input '{"param": "value"}'
182
+ \`\`\`
183
+
184
+ 所有 Action 执行结果均在 \`stdout\` 输出标准格式的 JSON 结果:
185
+ \`\`\`json
186
+ {
187
+ "ok": true,
188
+ "runId": "01J...",
189
+ "data": { ... }
190
+ }
191
+ \`\`\`
192
+ 日志与诊断信息输出至 \`stderr\`。
193
+
194
+ ---
195
+
196
+ ## Action 目录
197
+
198
+ ${actionListMd}
199
+ ${playbookSection}
200
+ ---
201
+
202
+ ## 运行时配置与持久化状态
203
+
204
+ 独立二进制会自动管理其本地 SQLite 数据库。如需检查或配置:
205
+
206
+ \`\`\`bash
207
+ # 查看与设置配置项
208
+ ${binaryRelPath} config list
209
+ ${binaryRelPath} config set KEY VALUE
210
+
211
+ # 查看与检索状态数据
212
+ ${binaryRelPath} state list
213
+ ${binaryRelPath} state get KEY
214
+ \`\`\`
215
+ `;
216
+ }
217
+
218
+ export function generateSkillMd(
219
+ config: ProjectConfig,
220
+ actions: ActionDefinition[],
221
+ playbooks: PlaybookDefinition[],
222
+ optionsOrBinaryPath: string | { mode?: "source" | "standalone"; binaryRelPath?: string } = "./bin/action-bin"
223
+ ): string {
224
+ if (typeof optionsOrBinaryPath === "string") {
225
+ return generateStandaloneSkillMd(config, actions, playbooks, optionsOrBinaryPath);
226
+ }
227
+ if (optionsOrBinaryPath.mode === "source") {
228
+ return generateSourceSkillMd(config, actions, playbooks);
229
+ }
230
+ return generateStandaloneSkillMd(config, actions, playbooks, optionsOrBinaryPath.binaryRelPath || "./bin/action-bin");
231
+ }
232
+
233
+ export function generateSkillJson(
234
+ config: ProjectConfig,
235
+ actions: ActionDefinition[],
236
+ binaryName: string,
237
+ target: string
238
+ ): string {
239
+ const manifest = {
240
+ schemaVersion: "2.0.0",
241
+ packageId: config.id,
242
+ name: config.name,
243
+ version: config.version,
244
+ description: config.description,
245
+ target,
246
+ executable: `./bin/${binaryName}`,
247
+ actions: actions.map((a) => ({
248
+ id: a.id,
249
+ description: a.description,
250
+ inputSchema: a.inputSchema,
251
+ outputSchema: a.outputSchema,
252
+ })),
253
+ exportedAt: new Date().toISOString(),
254
+ };
255
+
256
+ return JSON.stringify(manifest, null, 2) + "\n";
257
+ }
258
+
@@ -0,0 +1 @@
1
+ export * from "./intent";