@actiondock/core 2.0.0 → 2.0.2
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 +6 -6
- package/package.json +1 -1
- package/src/build/builder.ts +1 -1
- package/src/doctor/doctor.ts +13 -13
- package/src/export/templates.ts +59 -16
- package/src/profile/client.ts +252 -2
- package/src/profile/manager.ts +3 -3
- package/src/project/init.ts +2 -2
- package/src/registry/registry.ts +4 -4
- package/src/runtime/standalone.ts +2 -2
- package/src/server/runtime-registry.ts +36 -1
- package/src/server/server.ts +892 -66
- package/src/server/types.ts +4 -0
- package/src/storage/sqlite.ts +43 -16
- package/src/storage/types.ts +2 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ The core engine and domain kernel of ActionDock 2.0.
|
|
|
10
10
|
|
|
11
11
|
> **Role & Usage Context**:
|
|
12
12
|
> - **Authoring Actions**: Use [`@actiondock/sdk`](../sdk) for defining actions, testing with in-memory harness, and zero-dependency action packages.
|
|
13
|
-
> - **CLI Toolchain**: Use [`@actiondock/cli`](../cli) (`
|
|
13
|
+
> - **CLI Toolchain**: Use [`@actiondock/cli`](../cli) (`ad`) for command-line workflows.
|
|
14
14
|
> - **Engine & Embedding**: Use `@actiondock/core` when you need programmatic access to the ActionRunner engine, project loader, or custom server integrations.
|
|
15
15
|
>
|
|
16
16
|
> **Runtime requirement**: [Bun](https://bun.sh/) >= 1.2.0 is required (`@actiondock/core` leverages native `bun:sqlite` and Bun runtime APIs).
|
|
@@ -38,13 +38,13 @@ bun add @actiondock/core
|
|
|
38
38
|
|
|
39
39
|
## 📖 Documentation
|
|
40
40
|
|
|
41
|
-
- [Runtime Architecture](
|
|
42
|
-
- [Storage & Persistence Guide](
|
|
43
|
-
- [Standalone Binary Build](
|
|
44
|
-
- [HTTP Server & Remote Dispatch](
|
|
41
|
+
- [Runtime Architecture](../../docs/architecture/runtime.md)
|
|
42
|
+
- [Storage & Persistence Guide](../../docs/developer/storage.md)
|
|
43
|
+
- [Standalone Binary Build](../../docs/developer/build-and-export.md)
|
|
44
|
+
- [HTTP Server & Remote Dispatch](../../docs/consumer/http-service.md)
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
48
|
## License
|
|
49
49
|
|
|
50
|
-
[Apache-2.0](LICENSE) © team4u
|
|
50
|
+
[Apache-2.0](../../LICENSE) © team4u
|
package/package.json
CHANGED
package/src/build/builder.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface BuildOptions {
|
|
|
18
18
|
outfile?: string;
|
|
19
19
|
/** 是否开启代码压缩混淆(默认 true) */
|
|
20
20
|
minify?: boolean;
|
|
21
|
-
/** 是否编译为 V8/JavaScriptCore 字节码(默认
|
|
21
|
+
/** 是否编译为 V8/JavaScriptCore 字节码(默认 true) */
|
|
22
22
|
bytecode?: boolean;
|
|
23
23
|
/** 显式挑选打包的 Action ID 清单(用于按需子集打包) */
|
|
24
24
|
actions?: string[];
|
package/src/doctor/doctor.ts
CHANGED
|
@@ -55,25 +55,25 @@ export async function runDoctorChecks(options?: {
|
|
|
55
55
|
name: "Bun Runtime",
|
|
56
56
|
status: "error",
|
|
57
57
|
message: "Bun runtime not detected",
|
|
58
|
-
fix: "Install Bun via 'npm install
|
|
58
|
+
fix: "Install Bun via 'npm install -g bun'",
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// 2. Check CLI in PATH
|
|
63
|
-
let
|
|
63
|
+
let adPath: string | null = null;
|
|
64
64
|
try {
|
|
65
|
-
|
|
65
|
+
adPath = typeof Bun !== "undefined" && Bun.which ? Bun.which("ad") : null;
|
|
66
66
|
} catch {
|
|
67
67
|
// ignore
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
if (
|
|
70
|
+
if (adPath) {
|
|
71
71
|
checks.push({
|
|
72
72
|
id: "runtime.cli",
|
|
73
73
|
category: "runtime",
|
|
74
74
|
name: "CLI Executable",
|
|
75
75
|
status: "ok",
|
|
76
|
-
message: `Found '
|
|
76
|
+
message: `Found 'ad' in PATH at ${adPath}`,
|
|
77
77
|
});
|
|
78
78
|
} else {
|
|
79
79
|
checks.push({
|
|
@@ -81,8 +81,8 @@ export async function runDoctorChecks(options?: {
|
|
|
81
81
|
category: "runtime",
|
|
82
82
|
name: "CLI Executable",
|
|
83
83
|
status: "warn",
|
|
84
|
-
message: "'
|
|
85
|
-
fix: "Run '
|
|
84
|
+
message: "'ad' command not found in PATH",
|
|
85
|
+
fix: "Run 'npm install -g @actiondock/cli' or in SDK workspace run 'cd packages/cli && bun link'",
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -99,7 +99,7 @@ export async function runDoctorChecks(options?: {
|
|
|
99
99
|
category: "storage",
|
|
100
100
|
name: "Global Storage",
|
|
101
101
|
status: "ok",
|
|
102
|
-
message: `
|
|
102
|
+
message: `Global SQLite database verified at ${globalHome}`,
|
|
103
103
|
});
|
|
104
104
|
} catch (err: any) {
|
|
105
105
|
checks.push({
|
|
@@ -107,8 +107,8 @@ export async function runDoctorChecks(options?: {
|
|
|
107
107
|
category: "storage",
|
|
108
108
|
name: "Global Storage",
|
|
109
109
|
status: "error",
|
|
110
|
-
message: `Failed to
|
|
111
|
-
fix: `
|
|
110
|
+
message: `Failed to access global storage: ${err.message}`,
|
|
111
|
+
fix: `Ensure directory '${globalHome}' is writable`,
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -122,7 +122,7 @@ export async function runDoctorChecks(options?: {
|
|
|
122
122
|
name: "Global Registry",
|
|
123
123
|
status: "warn",
|
|
124
124
|
message: `${regStatus.totalPackagesCount} package(s), ${regStatus.workspaces.length} workspace(s), but ${regStatus.staleCount} stale path(s) detected`,
|
|
125
|
-
fix: "Run '
|
|
125
|
+
fix: "Run 'ad unlink --prune' to clean up stale entries from registry",
|
|
126
126
|
});
|
|
127
127
|
} else {
|
|
128
128
|
checks.push({
|
|
@@ -226,7 +226,7 @@ export async function runDoctorChecks(options?: {
|
|
|
226
226
|
name: "Actions",
|
|
227
227
|
status: "warn",
|
|
228
228
|
message: `No actions found in '${config.actionsDir || "actions"}'`,
|
|
229
|
-
fix: "Run '
|
|
229
|
+
fix: "Run 'ad action create <id>' to create your first action",
|
|
230
230
|
});
|
|
231
231
|
} else {
|
|
232
232
|
checks.push({
|
|
@@ -289,7 +289,7 @@ export async function runDoctorChecks(options?: {
|
|
|
289
289
|
name: "Config Readiness",
|
|
290
290
|
status: "warn",
|
|
291
291
|
message: `Required config item(s) missing: ${missingKeys.join(", ")}`,
|
|
292
|
-
fix: `Run '
|
|
292
|
+
fix: `Run 'ad config set <KEY> <VALUE>' to configure missing keys`,
|
|
293
293
|
});
|
|
294
294
|
} else {
|
|
295
295
|
checks.push({
|
package/src/export/templates.ts
CHANGED
|
@@ -30,7 +30,7 @@ function renderActionListMarkdown(
|
|
|
30
30
|
const idLabel = options.packageId
|
|
31
31
|
? `\`${options.packageId}/${a.id}\` (或 \`${a.id}\`)`
|
|
32
32
|
: `\`${a.id}\``;
|
|
33
|
-
return
|
|
33
|
+
return `- ${idLabel}${aDesc}${params}`;
|
|
34
34
|
})
|
|
35
35
|
.join("\n");
|
|
36
36
|
}
|
|
@@ -40,7 +40,7 @@ function renderPlaybookSectionMarkdown(playbooks: PlaybookDefinition[]): string
|
|
|
40
40
|
const list = playbooks
|
|
41
41
|
.map((p) => {
|
|
42
42
|
const rel = `./playbooks/${basename(p.filePath)}`;
|
|
43
|
-
return
|
|
43
|
+
return `- **${p.id}** (\`${rel}\`): ${p.description || "任务指南"}`;
|
|
44
44
|
})
|
|
45
45
|
.join("\n");
|
|
46
46
|
return `
|
|
@@ -73,34 +73,34 @@ description: ${desc}
|
|
|
73
73
|
|
|
74
74
|
${desc}
|
|
75
75
|
|
|
76
|
-
## ActionDock 运行时
|
|
76
|
+
## ActionDock 运行时
|
|
77
77
|
|
|
78
|
-
本技能为 **ActionDock
|
|
78
|
+
本技能为 **ActionDock 源码型技能包**。AI Agent 可直接通过已安装的 ActionDock 命令行工具 (\`ad\`) 执行其中的 Action。
|
|
79
79
|
|
|
80
|
-
### 注册与链接
|
|
80
|
+
### 注册与链接
|
|
81
81
|
|
|
82
82
|
在初次调用或初始化时,将包含本 \`SKILL.md\` 的目录解析为 \`<skill_root>\` 并完成注册:
|
|
83
83
|
|
|
84
84
|
\`\`\`bash
|
|
85
|
-
|
|
85
|
+
ad link "<skill_root>"
|
|
86
86
|
\`\`\`
|
|
87
87
|
|
|
88
|
-
> \`
|
|
88
|
+
> \`ad link\` 天然具备幂等性,同一 Package 多次执行会直接更新路径,可安全重复调用。
|
|
89
89
|
|
|
90
|
-
### 执行 Action
|
|
90
|
+
### 执行 Action
|
|
91
91
|
|
|
92
92
|
为避免多技能之间的 Action ID 命名冲突,建议统一使用带有 Package 前缀的完全限定 ID:
|
|
93
93
|
|
|
94
94
|
\`\`\`bash
|
|
95
|
-
# 格式:
|
|
96
|
-
|
|
95
|
+
# 格式:ad run <package-id>/<action-id> --input '<json>'
|
|
96
|
+
ad run ${pkgId}/${firstAction} --input '{"param": "value"}'
|
|
97
97
|
\`\`\`
|
|
98
98
|
|
|
99
|
-
>
|
|
99
|
+
> **免注册本地执行**:
|
|
100
100
|
> 若 Agent 工作目录已位于本 Skill 根目录,亦可直接免 link 执行:
|
|
101
101
|
> \`\`\`bash
|
|
102
102
|
> cd <skill_root>
|
|
103
|
-
>
|
|
103
|
+
> ad run <action-id> --input '<json>'
|
|
104
104
|
> \`\`\`
|
|
105
105
|
|
|
106
106
|
所有 Action 执行结果均在 \`stdout\` 输出标准格式的 JSON Envelope:
|
|
@@ -127,13 +127,56 @@ ${playbookSection}
|
|
|
127
127
|
|
|
128
128
|
\`\`\`bash
|
|
129
129
|
# 查看与设置配置项
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
ad config list --package ${pkgId}
|
|
131
|
+
ad config set KEY VALUE --package ${pkgId}
|
|
132
132
|
|
|
133
133
|
# 查看与检索状态数据
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
ad state list --package ${pkgId}
|
|
135
|
+
ad state get KEY --package ${pkgId}
|
|
136
136
|
\`\`\`
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 故障排查与环境安装指引(按需查阅)
|
|
141
|
+
|
|
142
|
+
> [!NOTE]
|
|
143
|
+
> **按需排查原则**:默认宿主环境中已预置 \`ad\` 命令行工具。正常执行流程直接调用上述 Action 即可,**严禁在任务启动前盲目进行前置环境检查或体检**;仅在终端明确报错提示命令不存在(如 \`ad: command not found\`)时,方可按本节指引安装初始化。
|
|
144
|
+
|
|
145
|
+
### 命令行工具未找到时的安装指引
|
|
146
|
+
|
|
147
|
+
若宿主环境未安装 \`ad\` 命令行工具,请依次按如下步骤完成安装:
|
|
148
|
+
|
|
149
|
+
- **安装 Bun 运行时**(若系统未安装):
|
|
150
|
+
\`\`\`bash
|
|
151
|
+
npm install -g bun
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
- **全局安装 ActionDock 命令行工具**:
|
|
155
|
+
\`\`\`bash
|
|
156
|
+
npm install -g @actiondock/cli
|
|
157
|
+
\`\`\`
|
|
158
|
+
|
|
159
|
+
- **验证工具就绪**:
|
|
160
|
+
\`\`\`bash
|
|
161
|
+
ad --version
|
|
162
|
+
\`\`\`
|
|
163
|
+
|
|
164
|
+
- **源码本地开发模式**(若在本地源码仓库中贡献或开发):
|
|
165
|
+
\`\`\`bash
|
|
166
|
+
cd packages/cli && bun link
|
|
167
|
+
cd ../sdk && bun link
|
|
168
|
+
\`\`\`
|
|
169
|
+
|
|
170
|
+
- **环境诊断与体检**:
|
|
171
|
+
安装完成后若仍遇到异常,执行体检命令排查:
|
|
172
|
+
\`\`\`bash
|
|
173
|
+
ad doctor
|
|
174
|
+
\`\`\`
|
|
175
|
+
|
|
176
|
+
- **完成安装后重新链接本技能**:
|
|
177
|
+
\`\`\`bash
|
|
178
|
+
ad link "<skill_root>"
|
|
179
|
+
\`\`\`
|
|
137
180
|
`;
|
|
138
181
|
}
|
|
139
182
|
|
package/src/profile/client.ts
CHANGED
|
@@ -291,12 +291,262 @@ export async function fetchRemoteActionShow(
|
|
|
291
291
|
|
|
292
292
|
export async function fetchRemoteInfo(
|
|
293
293
|
serverUrl: string,
|
|
294
|
-
token?: string
|
|
294
|
+
token?: string,
|
|
295
|
+
options?: { intent?: string; package?: string; tree?: boolean }
|
|
295
296
|
): Promise<any> {
|
|
297
|
+
const params = new URLSearchParams();
|
|
298
|
+
if (options?.intent) params.set("intent", options.intent);
|
|
299
|
+
if (options?.package) params.set("package", options.package);
|
|
300
|
+
if (options?.tree) params.set("tree", "true");
|
|
301
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
296
302
|
return fetchRemoteJson(
|
|
297
303
|
serverUrl,
|
|
298
|
-
|
|
304
|
+
`/api/v1/info${qs}`,
|
|
299
305
|
token,
|
|
300
306
|
{ errorPrefix: "Failed to fetch remote info" }
|
|
301
307
|
);
|
|
302
308
|
}
|
|
309
|
+
|
|
310
|
+
export async function fetchRemoteDoctor(
|
|
311
|
+
serverUrl: string,
|
|
312
|
+
token?: string,
|
|
313
|
+
targetPackage?: string
|
|
314
|
+
): Promise<any> {
|
|
315
|
+
const query = targetPackage ? `?package=${encodeURIComponent(targetPackage)}` : "";
|
|
316
|
+
return fetchRemoteJson(
|
|
317
|
+
serverUrl,
|
|
318
|
+
`/api/v1/doctor${query}`,
|
|
319
|
+
token,
|
|
320
|
+
{ errorPrefix: "Failed to fetch remote doctor report" }
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export async function fetchRemotePlaybooks(
|
|
325
|
+
serverUrl: string,
|
|
326
|
+
token?: string,
|
|
327
|
+
options?: { intent?: string; package?: string }
|
|
328
|
+
): Promise<Array<{ id: string; description: string; actions: string[]; packageId: string; filePath: string }>> {
|
|
329
|
+
const params = new URLSearchParams();
|
|
330
|
+
if (options?.intent) params.set("intent", options.intent);
|
|
331
|
+
if (options?.package) params.set("package", options.package);
|
|
332
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
333
|
+
return fetchRemoteJson(
|
|
334
|
+
serverUrl,
|
|
335
|
+
`/api/v1/playbooks${qs}`,
|
|
336
|
+
token,
|
|
337
|
+
{ errorPrefix: "Failed to fetch remote playbooks" }
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export async function fetchRemotePlaybookShow(
|
|
342
|
+
serverUrl: string,
|
|
343
|
+
playbookId: string,
|
|
344
|
+
token?: string
|
|
345
|
+
): Promise<any> {
|
|
346
|
+
return fetchRemoteJson(
|
|
347
|
+
serverUrl,
|
|
348
|
+
`/api/v1/playbooks/${encodeURIComponent(playbookId)}`,
|
|
349
|
+
token,
|
|
350
|
+
{ errorPrefix: `Failed to fetch remote playbook '${playbookId}'` }
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export async function fetchRemoteRuns(
|
|
355
|
+
serverUrl: string,
|
|
356
|
+
token?: string,
|
|
357
|
+
options?: { status?: string; actionId?: string; packageId?: string; intent?: string; limit?: number }
|
|
358
|
+
): Promise<{ ok: boolean; total: number; items: RunRecord[] }> {
|
|
359
|
+
const params = new URLSearchParams();
|
|
360
|
+
if (options?.status) params.set("status", options.status);
|
|
361
|
+
if (options?.actionId) params.set("actionId", options.actionId);
|
|
362
|
+
if (options?.packageId) params.set("packageId", options.packageId);
|
|
363
|
+
if (options?.intent) params.set("intent", options.intent);
|
|
364
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
365
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
366
|
+
return fetchRemoteJson(
|
|
367
|
+
serverUrl,
|
|
368
|
+
`/api/v1/runs${qs}`,
|
|
369
|
+
token,
|
|
370
|
+
{ errorPrefix: "Failed to fetch remote runs" }
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export async function clearRemoteRuns(
|
|
375
|
+
serverUrl: string,
|
|
376
|
+
token?: string,
|
|
377
|
+
options?: { packageId?: string; actionId?: string; status?: string }
|
|
378
|
+
): Promise<{ ok: boolean; clearedCount: number }> {
|
|
379
|
+
return fetchRemoteJson(
|
|
380
|
+
serverUrl,
|
|
381
|
+
"/api/v1/runs/clear",
|
|
382
|
+
token,
|
|
383
|
+
{
|
|
384
|
+
method: "POST",
|
|
385
|
+
body: options || {},
|
|
386
|
+
errorPrefix: "Failed to clear remote runs",
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export async function fetchRemoteStateList(
|
|
392
|
+
serverUrl: string,
|
|
393
|
+
token?: string,
|
|
394
|
+
options?: { package?: string; namespace?: string; prefix?: string }
|
|
395
|
+
): Promise<{ ok: boolean; packageId: string; keys: string[] }> {
|
|
396
|
+
const params = new URLSearchParams();
|
|
397
|
+
if (options?.package) params.set("package", options.package);
|
|
398
|
+
if (options?.namespace !== undefined) params.set("namespace", options.namespace);
|
|
399
|
+
if (options?.prefix) params.set("prefix", options.prefix);
|
|
400
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
401
|
+
return fetchRemoteJson(
|
|
402
|
+
serverUrl,
|
|
403
|
+
`/api/v1/state${qs}`,
|
|
404
|
+
token,
|
|
405
|
+
{ errorPrefix: "Failed to list remote state keys" }
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export async function getRemoteStateKey(
|
|
410
|
+
serverUrl: string,
|
|
411
|
+
key: string,
|
|
412
|
+
token?: string,
|
|
413
|
+
options?: { package?: string; namespace?: string }
|
|
414
|
+
): Promise<any> {
|
|
415
|
+
const params = new URLSearchParams();
|
|
416
|
+
if (options?.package) params.set("package", options.package);
|
|
417
|
+
if (options?.namespace !== undefined) params.set("namespace", options.namespace);
|
|
418
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
419
|
+
return fetchRemoteJson(
|
|
420
|
+
serverUrl,
|
|
421
|
+
`/api/v1/state/${encodeURIComponent(key)}${qs}`,
|
|
422
|
+
token,
|
|
423
|
+
{ errorPrefix: `Failed to fetch remote state key '${key}'` }
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export async function setRemoteStateKey(
|
|
428
|
+
serverUrl: string,
|
|
429
|
+
key: string,
|
|
430
|
+
value: unknown,
|
|
431
|
+
token?: string,
|
|
432
|
+
options?: { package?: string; namespace?: string; ttl?: number }
|
|
433
|
+
): Promise<any> {
|
|
434
|
+
return fetchRemoteJson(
|
|
435
|
+
serverUrl,
|
|
436
|
+
`/api/v1/state/${encodeURIComponent(key)}`,
|
|
437
|
+
token,
|
|
438
|
+
{
|
|
439
|
+
method: "PUT",
|
|
440
|
+
body: {
|
|
441
|
+
value,
|
|
442
|
+
package: options?.package,
|
|
443
|
+
namespace: options?.namespace,
|
|
444
|
+
ttl: options?.ttl,
|
|
445
|
+
},
|
|
446
|
+
errorPrefix: `Failed to set remote state key '${key}'`,
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export async function deleteRemoteStateKey(
|
|
452
|
+
serverUrl: string,
|
|
453
|
+
key: string,
|
|
454
|
+
token?: string,
|
|
455
|
+
options?: { package?: string; namespace?: string }
|
|
456
|
+
): Promise<any> {
|
|
457
|
+
const params = new URLSearchParams();
|
|
458
|
+
if (options?.package) params.set("package", options.package);
|
|
459
|
+
if (options?.namespace !== undefined) params.set("namespace", options.namespace);
|
|
460
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
461
|
+
return fetchRemoteJson(
|
|
462
|
+
serverUrl,
|
|
463
|
+
`/api/v1/state/${encodeURIComponent(key)}${qs}`,
|
|
464
|
+
token,
|
|
465
|
+
{
|
|
466
|
+
method: "DELETE",
|
|
467
|
+
errorPrefix: `Failed to delete remote state key '${key}'`,
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export async function clearRemoteState(
|
|
473
|
+
serverUrl: string,
|
|
474
|
+
token?: string,
|
|
475
|
+
options?: { package?: string; namespace?: string; prefix?: string; all?: boolean }
|
|
476
|
+
): Promise<{ ok: boolean; packageId: string; clearedCount: number }> {
|
|
477
|
+
return fetchRemoteJson(
|
|
478
|
+
serverUrl,
|
|
479
|
+
"/api/v1/state/clear",
|
|
480
|
+
token,
|
|
481
|
+
{
|
|
482
|
+
method: "POST",
|
|
483
|
+
body: options || {},
|
|
484
|
+
errorPrefix: "Failed to clear remote state",
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export async function fetchRemoteConfig(
|
|
490
|
+
serverUrl: string,
|
|
491
|
+
token?: string,
|
|
492
|
+
packageId?: string
|
|
493
|
+
): Promise<any> {
|
|
494
|
+
const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
|
|
495
|
+
return fetchRemoteJson(
|
|
496
|
+
serverUrl,
|
|
497
|
+
`/api/v1/config${query}`,
|
|
498
|
+
token,
|
|
499
|
+
{ errorPrefix: "Failed to fetch remote config" }
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export async function setRemoteConfig(
|
|
504
|
+
serverUrl: string,
|
|
505
|
+
key: string,
|
|
506
|
+
value: unknown,
|
|
507
|
+
token?: string,
|
|
508
|
+
packageId?: string
|
|
509
|
+
): Promise<any> {
|
|
510
|
+
return fetchRemoteJson(
|
|
511
|
+
serverUrl,
|
|
512
|
+
"/api/v1/config",
|
|
513
|
+
token,
|
|
514
|
+
{
|
|
515
|
+
method: "PUT",
|
|
516
|
+
body: { key, value, package: packageId },
|
|
517
|
+
errorPrefix: `Failed to set remote config '${key}'`,
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export async function deleteRemoteConfig(
|
|
523
|
+
serverUrl: string,
|
|
524
|
+
key: string,
|
|
525
|
+
token?: string,
|
|
526
|
+
packageId?: string
|
|
527
|
+
): Promise<any> {
|
|
528
|
+
const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
|
|
529
|
+
return fetchRemoteJson(
|
|
530
|
+
serverUrl,
|
|
531
|
+
`/api/v1/config/${encodeURIComponent(key)}${query}`,
|
|
532
|
+
token,
|
|
533
|
+
{
|
|
534
|
+
method: "DELETE",
|
|
535
|
+
errorPrefix: `Failed to delete remote config '${key}'`,
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export async function fetchRemoteConfigEnv(
|
|
541
|
+
serverUrl: string,
|
|
542
|
+
token?: string,
|
|
543
|
+
packageId?: string
|
|
544
|
+
): Promise<any> {
|
|
545
|
+
const query = packageId ? `?package=${encodeURIComponent(packageId)}` : "";
|
|
546
|
+
return fetchRemoteJson(
|
|
547
|
+
serverUrl,
|
|
548
|
+
`/api/v1/config/env${query}`,
|
|
549
|
+
token,
|
|
550
|
+
{ errorPrefix: "Failed to fetch remote config env checks" }
|
|
551
|
+
);
|
|
552
|
+
}
|
package/src/profile/manager.ts
CHANGED
|
@@ -144,7 +144,7 @@ export function useProfile(name: string, customHome?: string): void {
|
|
|
144
144
|
|
|
145
145
|
if (trimmedName !== "local" && !profilesConfig.profiles[trimmedName]) {
|
|
146
146
|
throw new Error(
|
|
147
|
-
`Profile '${trimmedName}' not found. Use '
|
|
147
|
+
`Profile '${trimmedName}' not found. Use 'ad profile list' to see available profiles or 'ad profile add' to register one.`
|
|
148
148
|
);
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -274,7 +274,7 @@ export function resolveTarget(
|
|
|
274
274
|
const found = profilesConfig.profiles[pName];
|
|
275
275
|
if (!found) {
|
|
276
276
|
throw new Error(
|
|
277
|
-
`Profile '${pName}' not found. Configure it with '
|
|
277
|
+
`Profile '${pName}' not found. Configure it with 'ad profile add ${pName} --server <url>'`
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
280
|
const resolvedToken = resolveProfileToken(pName, found, options.token);
|
|
@@ -307,7 +307,7 @@ export function resolveTarget(
|
|
|
307
307
|
const found = profilesConfig.profiles[pName];
|
|
308
308
|
if (!found) {
|
|
309
309
|
throw new Error(
|
|
310
|
-
`Profile '${pName}' (from ACTIONDOCK_PROFILE) not found. Configure it with '
|
|
310
|
+
`Profile '${pName}' (from ACTIONDOCK_PROFILE) not found. Configure it with 'ad profile add ${pName} --server <url>'`
|
|
311
311
|
);
|
|
312
312
|
}
|
|
313
313
|
const resolvedToken = resolveProfileToken(pName, found, options?.token);
|
package/src/project/init.ts
CHANGED
|
@@ -161,8 +161,8 @@ actions:
|
|
|
161
161
|
|
|
162
162
|
# Greeting SOP
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
- Call \`sample.greet\` with the user's name.
|
|
165
|
+
- Confirm the returned greeting message.
|
|
166
166
|
`;
|
|
167
167
|
writeFileSync(join(playbooksDir, "greet-user.md"), samplePlaybook);
|
|
168
168
|
|
package/src/registry/registry.ts
CHANGED
|
@@ -376,7 +376,7 @@ export async function resolveActionProject(
|
|
|
376
376
|
|
|
377
377
|
if (!pkg || !existsSync(pkg.path)) {
|
|
378
378
|
throw new Error(
|
|
379
|
-
`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run '
|
|
379
|
+
`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run 'ad link' in the package directory.`
|
|
380
380
|
);
|
|
381
381
|
}
|
|
382
382
|
|
|
@@ -428,7 +428,7 @@ export async function resolveActionProject(
|
|
|
428
428
|
throw new Error(`Action '${actionIdentifier}' not found in current project or any linked packages`);
|
|
429
429
|
} else {
|
|
430
430
|
throw new Error(
|
|
431
|
-
`Action '${actionIdentifier}' not found. You are not in an ActionDock project, and no linked package provides '${actionIdentifier}'. Use '
|
|
431
|
+
`Action '${actionIdentifier}' not found. You are not in an ActionDock project, and no linked package provides '${actionIdentifier}'. Use 'ad link' to register your package.`
|
|
432
432
|
);
|
|
433
433
|
}
|
|
434
434
|
}
|
|
@@ -505,7 +505,7 @@ export function resolvePlaybookProject(
|
|
|
505
505
|
|
|
506
506
|
if (!pkg || !existsSync(pkg.path)) {
|
|
507
507
|
throw new Error(
|
|
508
|
-
`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run '
|
|
508
|
+
`Linked package '${targetPackage}' not found or path no longer exists (${pkg?.path || "unregistered"}). Run 'ad link' in the package directory.`
|
|
509
509
|
);
|
|
510
510
|
}
|
|
511
511
|
|
|
@@ -564,7 +564,7 @@ export function resolvePlaybookProject(
|
|
|
564
564
|
throw new Error(`Playbook '${playbookIdentifier}' not found in current project or any linked packages`);
|
|
565
565
|
} else {
|
|
566
566
|
throw new Error(
|
|
567
|
-
`Playbook '${playbookIdentifier}' not found. You are not in an ActionDock project, and no linked package provides '${playbookIdentifier}'. Use '
|
|
567
|
+
`Playbook '${playbookIdentifier}' not found. You are not in an ActionDock project, and no linked package provides '${playbookIdentifier}'. Use 'ad link' to register your package.`
|
|
568
568
|
);
|
|
569
569
|
}
|
|
570
570
|
}
|
|
@@ -26,8 +26,8 @@ export interface StandaloneRuntimeOptions {
|
|
|
26
26
|
* 独立二进制可执行文件运行时(Standalone Runtime)。
|
|
27
27
|
*
|
|
28
28
|
* 职责:
|
|
29
|
-
* 1. 作为由 `
|
|
30
|
-
* 2. 保证与开发态(`
|
|
29
|
+
* 1. 作为由 `ad build` 编译生成的单文件独立可执行文件(Standalone Binary)的运行时入口。
|
|
30
|
+
* 2. 保证与开发态(`ad run` / `ad action`)在输出信封、配置优先级、状态存储等方面的 100% 行为一致性。
|
|
31
31
|
* 3. 自带轻量 CLI 分发器,支持 `list`, `describe`, `run`, `config`, `state`, `version`, `help` 子命令。
|
|
32
32
|
*/
|
|
33
33
|
export class StandaloneRuntime {
|
|
@@ -6,18 +6,53 @@ import type { RuntimeStorage } from "../storage/types";
|
|
|
6
6
|
* 服务端运行时注册表(ServerRuntimeRegistry)。
|
|
7
7
|
*
|
|
8
8
|
* 职责:
|
|
9
|
-
* 1. 在长期运行的 HTTP 服务端(`
|
|
9
|
+
* 1. 在长期运行的 HTTP 服务端(`ad serve` / `ad mcp serve`)中,跨请求缓存并池化管理 SQLite 数据库存储连接。
|
|
10
10
|
* 2. 集中维护活跃的在途任务执行句柄(ExecutionManager)。
|
|
11
11
|
* 3. 服务端停止或优雅关机(Graceful Shutdown)时,统一中断在途任务并安全关闭所有数据库连接。
|
|
12
12
|
*/
|
|
13
13
|
export class ServerRuntimeRegistry {
|
|
14
14
|
private storages = new Map<string, RuntimeStorage>();
|
|
15
|
+
private listeners = new Map<string, Set<(event: { type: string; data: any }) => void>>();
|
|
15
16
|
public executionManager: ExecutionManager;
|
|
16
17
|
|
|
17
18
|
constructor() {
|
|
18
19
|
this.executionManager = new ExecutionManager();
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* 订阅指定 runId 的事件(用于 SSE 流式推送)。
|
|
24
|
+
*/
|
|
25
|
+
public subscribe(runId: string, listener: (event: { type: string; data: any }) => void): () => void {
|
|
26
|
+
let set = this.listeners.get(runId);
|
|
27
|
+
if (!set) {
|
|
28
|
+
set = new Set();
|
|
29
|
+
this.listeners.set(runId, set);
|
|
30
|
+
}
|
|
31
|
+
set.add(listener);
|
|
32
|
+
return () => {
|
|
33
|
+
set?.delete(listener);
|
|
34
|
+
if (set && set.size === 0) {
|
|
35
|
+
this.listeners.delete(runId);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 向指定 runId 的订阅者广播事件。
|
|
42
|
+
*/
|
|
43
|
+
public emit(runId: string, event: { type: string; data: any }): void {
|
|
44
|
+
const set = this.listeners.get(runId);
|
|
45
|
+
if (set) {
|
|
46
|
+
for (const listener of set) {
|
|
47
|
+
try {
|
|
48
|
+
listener(event);
|
|
49
|
+
} catch {
|
|
50
|
+
// 忽略单个监听器错误
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
21
56
|
/**
|
|
22
57
|
* 获取或懒加载指定 Package 和 projectRoot 的缓存 RuntimeStorage 实例。
|
|
23
58
|
*
|