@actiondock/sdk 2.0.2 → 2.0.3
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 +57 -71
- package/package.json +2 -2
- package/src/cli.ts +70 -21
- package/src/index.ts +11 -9
- package/src/test-runtime.ts +66 -0
- package/src/types.ts +215 -56
package/README.md
CHANGED
|
@@ -1,121 +1,107 @@
|
|
|
1
1
|
# @actiondock/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ActionDock 2.0 纯净核心开发者接口契约包。
|
|
4
4
|
|
|
5
|
-
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`@actiondock/sdk` 为开发者编写原子 Action 提供零外部依赖的纯净类型定义与核心契约。
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 安装方式
|
|
14
|
+
|
|
15
|
+
使用标准包管理器添加依赖:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
|
|
18
|
+
npm install @actiondock/sdk
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
---
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## 核心契约与函数
|
|
24
|
+
|
|
25
|
+
### defineAction 函数
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
用于声明并严格校验单个 Action 的静态属性与执行函数:
|
|
24
28
|
|
|
25
29
|
```ts
|
|
26
30
|
import { defineAction } from "@actiondock/sdk";
|
|
27
31
|
|
|
28
32
|
export default defineAction({
|
|
29
|
-
id: "
|
|
30
|
-
description: "
|
|
33
|
+
id: "calculator.add",
|
|
34
|
+
description: "计算两个数值之和",
|
|
31
35
|
|
|
32
36
|
inputSchema: {
|
|
33
37
|
type: "object",
|
|
34
38
|
properties: {
|
|
35
|
-
|
|
39
|
+
a: { type: "number", description: "第一个加数" },
|
|
40
|
+
b: { type: "number", description: "第二个加数" },
|
|
36
41
|
},
|
|
37
|
-
required: ["
|
|
42
|
+
required: ["a", "b"],
|
|
38
43
|
},
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
outputSchema: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {
|
|
48
|
+
result: { type: "number", description: "计算结果" },
|
|
49
|
+
},
|
|
50
|
+
required: ["result"],
|
|
51
|
+
},
|
|
45
52
|
|
|
53
|
+
async run(input, ctx) {
|
|
54
|
+
ctx.log.info(`计算加法: ${input.a} + ${input.b}`);
|
|
46
55
|
return {
|
|
47
|
-
|
|
48
|
-
count,
|
|
56
|
+
result: input.a + input.b,
|
|
49
57
|
};
|
|
50
58
|
},
|
|
51
59
|
});
|
|
52
60
|
```
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
`defineAction` 支持的完整契约字段:
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
config: { GREETING_PREFIX: "Welcome" },
|
|
65
|
-
state: { "greet:Alice": 2 },
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const result = await runtime.run(greetAction, { name: "Alice" });
|
|
69
|
-
expect(result.message).toBe("Welcome, Alice!");
|
|
70
|
-
expect(result.count).toBe(3);
|
|
71
|
-
expect(await runtime.state.get("greet:Alice")).toBe(3);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
```
|
|
64
|
+
- `id`:动作唯一标识符,格式通常为领域或命名空间前缀拼接名称。
|
|
65
|
+
- `description`:动作功能的人类可读说明。
|
|
66
|
+
- `inputSchema`:入参模式规范,采用标准 JSON Schema 格式。
|
|
67
|
+
- `outputSchema`:出参模式规范,采用标准 JSON Schema 格式。
|
|
68
|
+
- `uses`:静态声明当前 Action 所依赖的其他 Action 标识列表。
|
|
69
|
+
- `tags`:用于分类与检索的标签数组。
|
|
70
|
+
- `annotations`:面向协议适配器的扩展注解字典。
|
|
71
|
+
- `run`:业务执行入口函数,接收已通过校验的入参数据和运行时上下文对象。
|
|
75
72
|
|
|
76
73
|
---
|
|
77
74
|
|
|
78
|
-
##
|
|
75
|
+
## ActionContext 运行时上下文
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
- `ctx.config`: 5-tier configuration resolution (`override > sqlite > env > default > fallback`)
|
|
82
|
-
- `ctx.state`: Embedded SQLite state store with namespace and TTL support
|
|
83
|
-
- `ctx.actions`: Inter-action invocation with cycle detection
|
|
84
|
-
- `ctx.log`: Isolated logging directed to `stderr`
|
|
85
|
-
- `ctx.signal`: Cooperative cancellation via `AbortSignal`
|
|
86
|
-
- `execCli`: Deadlock-safe, cross-platform synchronous CLI executor with Windows `.cmd` resolution, stdin streaming, timeout, and signal support.
|
|
87
|
-
- `spawnDetached`: Safe asynchronous launcher for daemon-spawning CLI tools (e.g., `agent-browser open`), preventing pipe EOF hangs via fire-and-forget stdio decoupling and polling probe.
|
|
88
|
-
- `createTestRuntime`: Fast, zero-dependency in-memory test harness for unit tests.
|
|
89
|
-
|
|
90
|
-
---
|
|
77
|
+
在 Action 执行时,宿主环境注入标准化上下文对象 `ActionContext`,提供受控的系统交互能力:
|
|
91
78
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| `MemoryConfig` | Class | In-memory `Config` provider for unit tests |
|
|
101
|
-
| `MemoryStateStore` | Class | In-memory `StateStore` with TTL and namespace support |
|
|
102
|
-
| `MemoryLogger` | Class | In-memory `Logger` collecting log entries for test assertions |
|
|
103
|
-
| `ActionContext` | Interface | Runtime context provided to `action.run(input, ctx)` |
|
|
104
|
-
| `ActionDefinition` | Interface | Schema and execution contract for an Action |
|
|
105
|
-
| `ExecutionResult` | Type | Standard JSON envelope (`ok: true, data` or `ok: false, error`) |
|
|
79
|
+
- `ctx.process`:进程执行接口,提供 `exec` 与 `spawnDetached`,安全调用系统外部命令或启动后台守护进程,支持超时与输出截断保护。
|
|
80
|
+
- `ctx.log`:结构化日志输出接口,提供 `debug`、`info`、`warn`、`error` 级别日志。日志严格输出至标准错误流,彻底隔离标准输出流,杜绝污染协议报文。
|
|
81
|
+
- `ctx.progress`:进度报告器,支持在长时间运行的任务中通过 `report(current, total, message)` 上报当前阶段。
|
|
82
|
+
- `ctx.signal`:协作式取消信号,类型为标准 `AbortSignal`。当任务被外部客户端取消或超时时自动触发中止,业务逻辑需主动监听并响应。
|
|
83
|
+
- `ctx.run`:当前执行实例元数据,包含 `id`(本次运行标识)、`rootId`(根调用标识)和 `parentId`(父级调用标识),便于全链路追踪。
|
|
84
|
+
- `ctx.config`:分层配置读取接口,提供 `get` 与 `has` 方法,支持优先级回退与类型强转。
|
|
85
|
+
- `ctx.state`:持久化状态接口,提供基于当前 Package 命名空间隔离的键值存储与存活时间控制。
|
|
86
|
+
- `ctx.actions`:动作相互调用接口,支持调用包内其他 Action,并内置调用栈环路死锁检测。
|
|
106
87
|
|
|
107
88
|
---
|
|
108
89
|
|
|
109
|
-
##
|
|
90
|
+
## 快速单元测试
|
|
110
91
|
|
|
111
|
-
|
|
92
|
+
结合 `@actiondock/testing` 或 SDK 内置的测试辅助方法,可以在纯内存环境下毫秒级验证 Action:
|
|
112
93
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
94
|
+
```ts
|
|
95
|
+
import { createTestRuntime } from "@actiondock/sdk";
|
|
96
|
+
import addAction from "../actions/add";
|
|
97
|
+
|
|
98
|
+
const runtime = createTestRuntime();
|
|
99
|
+
const result = await runtime.run(addAction, { a: 10, b: 20 });
|
|
100
|
+
console.log(result.result); // 输出 30
|
|
101
|
+
```
|
|
116
102
|
|
|
117
103
|
---
|
|
118
104
|
|
|
119
|
-
##
|
|
105
|
+
## 开源协议
|
|
120
106
|
|
|
121
|
-
|
|
107
|
+
本项目采用 Apache-2.0 开源协议。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/sdk",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "ActionDock SDK for defining and testing standalone AI Agent Actions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"
|
|
20
|
+
"node": ">=22.12.0"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public",
|
package/src/cli.ts
CHANGED
|
@@ -77,6 +77,48 @@ export interface ExecCliResult {
|
|
|
77
77
|
* @param options 运行选项(工作目录、环境变量、取消信号、超时、stdin、字符编码、抛错开关)
|
|
78
78
|
* @returns ExecCliResult 执行结果结构体
|
|
79
79
|
*/
|
|
80
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
81
|
+
import { existsSync } from "node:fs";
|
|
82
|
+
import { delimiter, join } from "node:path";
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 跨运行时安全查找可执行文件绝对物理路径。
|
|
86
|
+
*/
|
|
87
|
+
function findExecutable(command: string): string | null {
|
|
88
|
+
if (typeof (globalThis as any).Bun !== "undefined" && typeof (globalThis as any).Bun.which === "function") {
|
|
89
|
+
try {
|
|
90
|
+
const bPath = (globalThis as any).Bun.which(command);
|
|
91
|
+
if (bPath) return bPath;
|
|
92
|
+
} catch {
|
|
93
|
+
// 忽略 Bun.which 异常,进入通用解析
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const hasPathSep = command.includes("/") || command.includes("\\");
|
|
98
|
+
if (hasPathSep) {
|
|
99
|
+
return existsSync(command) ? command : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const pathEnv = process.env.PATH || "";
|
|
103
|
+
const dirs = pathEnv.split(delimiter);
|
|
104
|
+
const isWindows = process.platform === "win32";
|
|
105
|
+
const pathext = isWindows
|
|
106
|
+
? (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";")
|
|
107
|
+
: [""];
|
|
108
|
+
|
|
109
|
+
for (const dir of dirs) {
|
|
110
|
+
if (!dir) continue;
|
|
111
|
+
for (const ext of pathext) {
|
|
112
|
+
const candidate = join(dir, isWindows && !command.includes(".") ? command + ext : command);
|
|
113
|
+
if (existsSync(candidate)) {
|
|
114
|
+
return candidate;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
80
122
|
export function execCli(
|
|
81
123
|
command: string,
|
|
82
124
|
args: string[] = [],
|
|
@@ -100,11 +142,11 @@ export function execCli(
|
|
|
100
142
|
return errRes;
|
|
101
143
|
}
|
|
102
144
|
|
|
103
|
-
// 2.
|
|
145
|
+
// 2. 跨平台绝对路径解析
|
|
104
146
|
const hasPathSep = command.includes("/") || command.includes("\\");
|
|
105
|
-
const binPath = hasPathSep ? command :
|
|
147
|
+
const binPath = hasPathSep ? (existsSync(command) ? command : null) : findExecutable(command);
|
|
106
148
|
|
|
107
|
-
if (!
|
|
149
|
+
if (!binPath) {
|
|
108
150
|
const errRes: ExecCliResult = {
|
|
109
151
|
ok: false,
|
|
110
152
|
exitCode: -1,
|
|
@@ -120,27 +162,26 @@ export function execCli(
|
|
|
120
162
|
}
|
|
121
163
|
|
|
122
164
|
// 3. 处理标准输入数据
|
|
123
|
-
let
|
|
165
|
+
let stdinInput: Buffer | undefined;
|
|
124
166
|
if (options.input !== undefined) {
|
|
125
167
|
if (typeof options.input === "string") {
|
|
126
|
-
|
|
168
|
+
stdinInput = Buffer.from(options.input);
|
|
127
169
|
} else if (options.input instanceof Uint8Array) {
|
|
128
|
-
|
|
170
|
+
stdinInput = Buffer.from(options.input);
|
|
129
171
|
}
|
|
130
172
|
}
|
|
131
173
|
|
|
132
174
|
try {
|
|
133
|
-
const proc =
|
|
175
|
+
const proc = spawnSync(binPath, args, {
|
|
134
176
|
cwd: options.cwd || process.cwd(),
|
|
135
177
|
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
stderr: "pipe",
|
|
178
|
+
input: stdinInput,
|
|
179
|
+
stdio: [stdinInput ? "pipe" : "ignore", "pipe", "pipe"],
|
|
139
180
|
timeout: options.timeout,
|
|
140
181
|
});
|
|
141
182
|
|
|
142
183
|
const durationMs = Math.round(performance.now() - startTime);
|
|
143
|
-
const timedOut = Boolean((proc as any).
|
|
184
|
+
const timedOut = Boolean(proc.error && (proc.error as any).code === "ETIMEDOUT");
|
|
144
185
|
|
|
145
186
|
// 4. 自定义字符集解码
|
|
146
187
|
const decoder = new TextDecoder(options.encoding || "utf-8");
|
|
@@ -154,7 +195,7 @@ export function execCli(
|
|
|
154
195
|
stderr = `Command '${command}' timed out after ${options.timeout}ms`;
|
|
155
196
|
}
|
|
156
197
|
|
|
157
|
-
const exitCode = timedOut ? -1 : (proc.
|
|
198
|
+
const exitCode = timedOut ? -1 : (proc.status ?? (proc.error ? -1 : 0));
|
|
158
199
|
const ok = !timedOut && exitCode === 0;
|
|
159
200
|
|
|
160
201
|
const result: ExecCliResult = {
|
|
@@ -255,28 +296,36 @@ export async function spawnDetached(options: SpawnDetachedOptions): Promise<bool
|
|
|
255
296
|
throw new Error("Command aborted before execution by signal");
|
|
256
297
|
}
|
|
257
298
|
|
|
258
|
-
// 2.
|
|
299
|
+
// 2. 跨平台绝对路径解析
|
|
259
300
|
const hasPathSep = command.includes("/") || command.includes("\\");
|
|
260
|
-
const binPath = hasPathSep ? command :
|
|
301
|
+
const binPath = hasPathSep ? (existsSync(command) ? command : null) : findExecutable(command);
|
|
261
302
|
|
|
262
|
-
if (!
|
|
303
|
+
if (!binPath) {
|
|
263
304
|
throw new Error(`Command '${command}' not found in PATH.`);
|
|
264
305
|
}
|
|
265
306
|
|
|
266
307
|
// 3. fire-and-forget:ignore 所有 stdio,unref 防止阻塞事件循环
|
|
267
|
-
const child =
|
|
308
|
+
const child = spawn(binPath, args, {
|
|
268
309
|
cwd: cwd || process.cwd(),
|
|
269
310
|
env: env ? { ...process.env, ...env } : process.env,
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
stderr: "ignore",
|
|
311
|
+
stdio: "ignore",
|
|
312
|
+
detached: true,
|
|
273
313
|
signal,
|
|
274
314
|
});
|
|
275
315
|
child.unref();
|
|
276
316
|
|
|
277
|
-
// 4. 等待 CLI
|
|
317
|
+
// 4. 等待 CLI 前端进程自身退出
|
|
278
318
|
try {
|
|
279
|
-
await
|
|
319
|
+
await new Promise<void>((resolveChild, rejectChild) => {
|
|
320
|
+
child.on("exit", () => resolveChild());
|
|
321
|
+
child.on("error", (err) => {
|
|
322
|
+
if (signal?.aborted) {
|
|
323
|
+
rejectChild(new Error("aborted"));
|
|
324
|
+
} else {
|
|
325
|
+
rejectChild(err);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
});
|
|
280
329
|
} catch (err) {
|
|
281
330
|
if (signal?.aborted) {
|
|
282
331
|
throw new Error("aborted");
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
export { defineAction } from "./action";
|
|
2
|
-
export {
|
|
3
|
-
execCli,
|
|
4
|
-
spawnDetached,
|
|
5
|
-
type ExecCliOptions,
|
|
6
|
-
type ExecCliResult,
|
|
7
|
-
type SpawnDetachedOptions,
|
|
8
|
-
} from "./cli";
|
|
9
2
|
export {
|
|
10
3
|
createTestRuntime,
|
|
11
4
|
MemoryConfig,
|
|
@@ -16,16 +9,25 @@ export {
|
|
|
16
9
|
} from "./test-runtime";
|
|
17
10
|
export type {
|
|
18
11
|
ActionContext,
|
|
12
|
+
ActionContract,
|
|
19
13
|
ActionDefinition,
|
|
20
14
|
ActionInvoker,
|
|
15
|
+
ActionRef,
|
|
21
16
|
Config,
|
|
17
|
+
DetachedProcessOptions,
|
|
18
|
+
DetachedProcessResult,
|
|
19
|
+
ExecutionEvent,
|
|
22
20
|
ExecutionResult,
|
|
23
21
|
JsonSchema,
|
|
22
|
+
JsonValue,
|
|
24
23
|
Logger,
|
|
24
|
+
ProcessAPI,
|
|
25
|
+
ProcessExecOptions,
|
|
26
|
+
ProcessResult,
|
|
27
|
+
ProgressReporter,
|
|
28
|
+
ResolvedActionRef,
|
|
25
29
|
RuntimeError,
|
|
26
30
|
RunRecord,
|
|
27
31
|
RunStatus,
|
|
28
32
|
StateStore,
|
|
29
33
|
} from "./types";
|
|
30
|
-
|
|
31
|
-
|
package/src/test-runtime.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { execCli, spawnDetached } from "./cli";
|
|
1
2
|
import type {
|
|
2
3
|
ActionContext,
|
|
3
4
|
ActionDefinition,
|
|
4
5
|
ActionInvoker,
|
|
5
6
|
Config,
|
|
6
7
|
Logger,
|
|
8
|
+
ProcessResult,
|
|
7
9
|
StateStore,
|
|
8
10
|
} from "./types";
|
|
9
11
|
|
|
@@ -248,12 +250,76 @@ export function createTestRuntime(options: TestRuntimeOptions = {}): TestRuntime
|
|
|
248
250
|
}
|
|
249
251
|
callStack.push(action.id);
|
|
250
252
|
try {
|
|
253
|
+
const runId = "test-" + Math.random().toString(36).slice(2, 10);
|
|
251
254
|
const ctx: ActionContext = {
|
|
252
255
|
config,
|
|
253
256
|
state,
|
|
254
257
|
actions: invoker,
|
|
258
|
+
process: {
|
|
259
|
+
async exec(command, args, options) {
|
|
260
|
+
const res = await execCli(command, args, {
|
|
261
|
+
cwd: options?.cwd,
|
|
262
|
+
env: options?.env,
|
|
263
|
+
input: options?.input,
|
|
264
|
+
timeout: options?.timeoutMs,
|
|
265
|
+
throwOnError: options?.throwOnError,
|
|
266
|
+
signal: options?.signal,
|
|
267
|
+
});
|
|
268
|
+
return {
|
|
269
|
+
ok: res.ok,
|
|
270
|
+
exitCode: res.exitCode,
|
|
271
|
+
stdout: res.stdout,
|
|
272
|
+
stderr: res.stderr,
|
|
273
|
+
raw: res.raw,
|
|
274
|
+
timedOut: res.timedOut ?? false,
|
|
275
|
+
cancelled: Boolean(options?.signal?.aborted),
|
|
276
|
+
durationMs: res.durationMs,
|
|
277
|
+
};
|
|
278
|
+
},
|
|
279
|
+
async spawnDetached(options) {
|
|
280
|
+
const probeFn = options.probe
|
|
281
|
+
? async () => {
|
|
282
|
+
const fakeRes: ProcessResult = {
|
|
283
|
+
ok: true,
|
|
284
|
+
exitCode: 0,
|
|
285
|
+
stdout: "",
|
|
286
|
+
stderr: "",
|
|
287
|
+
raw: new Uint8Array(),
|
|
288
|
+
timedOut: false,
|
|
289
|
+
cancelled: false,
|
|
290
|
+
durationMs: 0,
|
|
291
|
+
};
|
|
292
|
+
return options.probe!(fakeRes);
|
|
293
|
+
}
|
|
294
|
+
: () => true;
|
|
295
|
+
|
|
296
|
+
const ready = await spawnDetached({
|
|
297
|
+
command: options.command,
|
|
298
|
+
args: options.args,
|
|
299
|
+
cwd: options.cwd,
|
|
300
|
+
env: options.env,
|
|
301
|
+
timeoutMs: options.timeoutMs ?? options.probeTimeoutMs,
|
|
302
|
+
intervalMs: options.probeIntervalMs,
|
|
303
|
+
signal: options.signal,
|
|
304
|
+
probe: probeFn,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
ok: ready,
|
|
309
|
+
ready,
|
|
310
|
+
durationMs: 0,
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
},
|
|
255
314
|
log: logger,
|
|
315
|
+
progress: {
|
|
316
|
+
report() {},
|
|
317
|
+
},
|
|
256
318
|
signal,
|
|
319
|
+
run: {
|
|
320
|
+
id: runId,
|
|
321
|
+
rootId: runId,
|
|
322
|
+
},
|
|
257
323
|
};
|
|
258
324
|
return await action.run(input, ctx);
|
|
259
325
|
} finally {
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 标准 JSON 数据域。
|
|
3
|
+
*/
|
|
4
|
+
export type JsonValue =
|
|
5
|
+
| null
|
|
6
|
+
| boolean
|
|
7
|
+
| number
|
|
8
|
+
| string
|
|
9
|
+
| JsonValue[]
|
|
10
|
+
| { [key: string]: JsonValue };
|
|
11
|
+
|
|
1
12
|
/**
|
|
2
13
|
* 标准 JSON Schema 结构定义。
|
|
3
|
-
*
|
|
14
|
+
* 支持对象模式或布尔模式。
|
|
4
15
|
*/
|
|
5
16
|
export type JsonSchema = Record<string, unknown> | boolean;
|
|
6
17
|
|
|
@@ -8,25 +19,24 @@ export type JsonSchema = Record<string, unknown> | boolean;
|
|
|
8
19
|
* ActionDock 标准运行时错误对象。
|
|
9
20
|
*/
|
|
10
21
|
export interface RuntimeError {
|
|
11
|
-
/**
|
|
22
|
+
/** 机器可读的唯一错误码 */
|
|
12
23
|
code: string;
|
|
13
24
|
/** 人类可读的错误描述信息 */
|
|
14
25
|
message: string;
|
|
15
|
-
/**
|
|
26
|
+
/** 结构化的附加错误详情 */
|
|
16
27
|
details?: unknown;
|
|
17
28
|
/** 导致此错误的底层原始异常或原因 */
|
|
18
29
|
cause?: unknown;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
/**
|
|
22
|
-
*
|
|
23
|
-
* ActionDock 在 CLI、独立二进制、HTTP Runner 和 MCP 等所有场景中均输出该格式。
|
|
33
|
+
* 标准执行结果信封。
|
|
24
34
|
*/
|
|
25
|
-
export type ExecutionResult<T =
|
|
35
|
+
export type ExecutionResult<T = JsonValue> =
|
|
26
36
|
| {
|
|
27
37
|
/** 执行是否成功 */
|
|
28
38
|
ok: true;
|
|
29
|
-
/**
|
|
39
|
+
/** 本次执行的全局唯一运行标识 */
|
|
30
40
|
runId: string;
|
|
31
41
|
/** Action 执行返回的业务数据 */
|
|
32
42
|
data: T;
|
|
@@ -34,15 +44,58 @@ export type ExecutionResult<T = unknown> =
|
|
|
34
44
|
| {
|
|
35
45
|
/** 执行是否失败 */
|
|
36
46
|
ok: false;
|
|
37
|
-
/**
|
|
47
|
+
/** 本次执行的全局唯一运行标识 */
|
|
38
48
|
runId: string;
|
|
39
49
|
/** 运行时错误详情 */
|
|
40
50
|
error: RuntimeError;
|
|
41
51
|
};
|
|
42
52
|
|
|
43
53
|
/**
|
|
44
|
-
*
|
|
45
|
-
|
|
54
|
+
* Action 逻辑引用。
|
|
55
|
+
*/
|
|
56
|
+
export interface ActionRef {
|
|
57
|
+
/** 所属包标识 */
|
|
58
|
+
packageId?: string;
|
|
59
|
+
/** Action 动作标识 */
|
|
60
|
+
actionId: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 运行时完整解析后的 Action 引用。
|
|
65
|
+
*/
|
|
66
|
+
export interface ResolvedActionRef {
|
|
67
|
+
/** 包逻辑标识 */
|
|
68
|
+
packageId: string;
|
|
69
|
+
/** 包物理实例标识 */
|
|
70
|
+
packageInstanceId: string;
|
|
71
|
+
/** Action 动作标识 */
|
|
72
|
+
actionId: string;
|
|
73
|
+
/** 运行时代码快照代次标识 */
|
|
74
|
+
generationId: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Action 声明契约。
|
|
79
|
+
*/
|
|
80
|
+
export interface ActionContract {
|
|
81
|
+
/** Action 唯一标识 */
|
|
82
|
+
id: string;
|
|
83
|
+
/** Action 功能描述 */
|
|
84
|
+
description?: string;
|
|
85
|
+
/** 输入参数模式规范 */
|
|
86
|
+
inputSchema?: JsonSchema;
|
|
87
|
+
/** 输出结果模式规范 */
|
|
88
|
+
outputSchema?: JsonSchema;
|
|
89
|
+
/** 静态 Action 依赖列表 */
|
|
90
|
+
uses?: string[];
|
|
91
|
+
/** 检索与分类标签 */
|
|
92
|
+
tags?: string[];
|
|
93
|
+
/** 协议注解元数据 */
|
|
94
|
+
annotations?: Record<string, JsonValue>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 配置提供器接口。
|
|
46
99
|
*/
|
|
47
100
|
export interface Config {
|
|
48
101
|
/**
|
|
@@ -57,7 +110,7 @@ export interface Config {
|
|
|
57
110
|
*/
|
|
58
111
|
get<T = unknown>(key: string, defaultValue: T): T;
|
|
59
112
|
/**
|
|
60
|
-
*
|
|
113
|
+
* 检查指定键是否存在配置值
|
|
61
114
|
* @param key 配置键名
|
|
62
115
|
*/
|
|
63
116
|
has(key: string): boolean;
|
|
@@ -65,7 +118,6 @@ export interface Config {
|
|
|
65
118
|
|
|
66
119
|
/**
|
|
67
120
|
* 共享状态持久化存储接口。
|
|
68
|
-
* 提供跨 Action 调用的数据共享与持久化存储能力,支持命名空间与基于秒的 TTL 自动过期机制。
|
|
69
121
|
*/
|
|
70
122
|
export interface StateStore {
|
|
71
123
|
/**
|
|
@@ -74,31 +126,29 @@ export interface StateStore {
|
|
|
74
126
|
*/
|
|
75
127
|
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
76
128
|
/**
|
|
77
|
-
*
|
|
129
|
+
* 设置状态键值对,可选指定过期存活时间
|
|
78
130
|
* @param key 状态键名
|
|
79
|
-
* @param value
|
|
80
|
-
* @param ttl
|
|
131
|
+
* @param value 要存储的数据值
|
|
132
|
+
* @param ttl 存活时间(单位:秒)。不传或小于等于 0 表示永久有效
|
|
81
133
|
*/
|
|
82
134
|
set<T = unknown>(key: string, value: T, ttl?: number): Promise<void>;
|
|
83
135
|
/**
|
|
84
|
-
*
|
|
136
|
+
* 删除指定键的状态数据
|
|
85
137
|
* @param key 状态键名
|
|
86
|
-
* @returns 是否实际删除了数据(true: 存在并删除,false: 不存在)
|
|
87
138
|
*/
|
|
88
139
|
delete(key: string): Promise<boolean>;
|
|
89
140
|
/**
|
|
90
|
-
*
|
|
141
|
+
* 清空当前命名空间下的所有状态数据
|
|
91
142
|
* @param prefix 可选的键名前缀过滤条件
|
|
92
|
-
* @returns 实际清除的条目数量
|
|
93
143
|
*/
|
|
94
144
|
clear(prefix?: string): Promise<number>;
|
|
95
145
|
/**
|
|
96
|
-
*
|
|
146
|
+
* 列出当前命名空间下所有匹配前缀的状态键名
|
|
97
147
|
* @param prefix 键名前缀过滤条件
|
|
98
148
|
*/
|
|
99
149
|
keys(prefix?: string): Promise<string[]>;
|
|
100
150
|
/**
|
|
101
|
-
*
|
|
151
|
+
* 创建具有独立命名空间隔离的子 StateStore 实例
|
|
102
152
|
* @param namespace 命名空间标识
|
|
103
153
|
*/
|
|
104
154
|
scope(namespace: string): StateStore;
|
|
@@ -106,7 +156,6 @@ export interface StateStore {
|
|
|
106
156
|
|
|
107
157
|
/**
|
|
108
158
|
* 结构化日志记录器接口。
|
|
109
|
-
* 所有日志输出均定向到 stderr,确保不污染 stdout 中的 JSON 信封。
|
|
110
159
|
*/
|
|
111
160
|
export interface Logger {
|
|
112
161
|
/** 记录调试级别日志 */
|
|
@@ -119,86 +168,196 @@ export interface Logger {
|
|
|
119
168
|
error(message: string, data?: unknown): void;
|
|
120
169
|
}
|
|
121
170
|
|
|
171
|
+
/**
|
|
172
|
+
* 执行进度报告器接口。
|
|
173
|
+
*/
|
|
174
|
+
export interface ProgressReporter {
|
|
175
|
+
/**
|
|
176
|
+
* 报告当前任务执行进度
|
|
177
|
+
* @param current 当前完成量
|
|
178
|
+
* @param total 任务总量
|
|
179
|
+
* @param message 当前进度说明
|
|
180
|
+
*/
|
|
181
|
+
report(current: number, total?: number, message?: string): void;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 进程执行参数。
|
|
186
|
+
*/
|
|
187
|
+
export interface ProcessExecOptions {
|
|
188
|
+
cwd?: string;
|
|
189
|
+
env?: Record<string, string>;
|
|
190
|
+
input?: string | Uint8Array;
|
|
191
|
+
timeoutMs?: number;
|
|
192
|
+
signal?: AbortSignal;
|
|
193
|
+
encoding?: string;
|
|
194
|
+
throwOnError?: boolean;
|
|
195
|
+
maxOutputBytes?: number;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 进程执行结果。
|
|
200
|
+
*/
|
|
201
|
+
export interface ProcessResult {
|
|
202
|
+
ok: boolean;
|
|
203
|
+
exitCode: number | null;
|
|
204
|
+
signal?: string;
|
|
205
|
+
stdout: string;
|
|
206
|
+
stderr: string;
|
|
207
|
+
raw: Uint8Array;
|
|
208
|
+
timedOut: boolean;
|
|
209
|
+
cancelled: boolean;
|
|
210
|
+
durationMs: number;
|
|
211
|
+
error?: RuntimeError;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 后台守护进程启动选项。
|
|
216
|
+
*/
|
|
217
|
+
export interface DetachedProcessOptions {
|
|
218
|
+
command: string;
|
|
219
|
+
args?: string[];
|
|
220
|
+
cwd?: string;
|
|
221
|
+
env?: Record<string, string>;
|
|
222
|
+
timeoutMs?: number;
|
|
223
|
+
signal?: AbortSignal;
|
|
224
|
+
probeIntervalMs?: number;
|
|
225
|
+
probeTimeoutMs?: number;
|
|
226
|
+
probe?: (result: ProcessResult) => boolean | Promise<boolean>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 后台守护进程启动结果。
|
|
231
|
+
*/
|
|
232
|
+
export interface DetachedProcessResult {
|
|
233
|
+
ok: boolean;
|
|
234
|
+
pid?: number;
|
|
235
|
+
ready: boolean;
|
|
236
|
+
durationMs: number;
|
|
237
|
+
error?: RuntimeError;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 统一进程操作接口。
|
|
242
|
+
*/
|
|
243
|
+
export interface ProcessAPI {
|
|
244
|
+
/** 执行外部命令 */
|
|
245
|
+
exec(command: string, args?: string[], options?: ProcessExecOptions): Promise<ProcessResult>;
|
|
246
|
+
/** 启动脱离父进程的后台进程并探测就绪状态 */
|
|
247
|
+
spawnDetached(options: DetachedProcessOptions): Promise<DetachedProcessResult>;
|
|
248
|
+
}
|
|
249
|
+
|
|
122
250
|
/**
|
|
123
251
|
* Action 间相互调用的执行器接口。
|
|
124
|
-
* 支持在 Action 内部安全调用同 Package 或其他 Action,内置调用栈防死循环环路检测。
|
|
125
252
|
*/
|
|
126
253
|
export interface ActionInvoker {
|
|
127
254
|
/**
|
|
128
255
|
* 调用指定的 Action 并传入参数,返回其执行结果
|
|
129
|
-
* @param action 目标 Action
|
|
256
|
+
* @param action 目标 Action 定义对象、引用或标识符
|
|
130
257
|
* @param input 传递给目标 Action 的输入参数
|
|
131
258
|
*/
|
|
132
|
-
invoke<I, O>(
|
|
133
|
-
action: ActionDefinition<I, O
|
|
134
|
-
input
|
|
259
|
+
invoke<I = unknown, O = unknown>(
|
|
260
|
+
action: ActionDefinition<I, O> | ActionRef | string,
|
|
261
|
+
input?: I
|
|
135
262
|
): Promise<O>;
|
|
136
263
|
}
|
|
137
264
|
|
|
138
265
|
/**
|
|
139
|
-
* 传递给 Action
|
|
266
|
+
* 传递给 Action 业务函数的运行时上下文对象。
|
|
140
267
|
*/
|
|
141
268
|
export interface ActionContext {
|
|
142
|
-
/**
|
|
269
|
+
/** 配置读取接口 */
|
|
143
270
|
config: Config;
|
|
144
|
-
/**
|
|
271
|
+
/** 状态持久化存储接口 */
|
|
145
272
|
state: StateStore;
|
|
146
|
-
/** Action
|
|
273
|
+
/** Action 相互调用接口 */
|
|
147
274
|
actions: ActionInvoker;
|
|
148
|
-
/**
|
|
275
|
+
/** 进程执行接口 */
|
|
276
|
+
process: ProcessAPI;
|
|
277
|
+
/** 结构化日志接口 */
|
|
149
278
|
log: Logger;
|
|
150
|
-
/**
|
|
279
|
+
/** 进度报告接口 */
|
|
280
|
+
progress: ProgressReporter;
|
|
281
|
+
/** 取消信号 */
|
|
151
282
|
signal: AbortSignal;
|
|
283
|
+
/** 当前执行信息 */
|
|
284
|
+
run: {
|
|
285
|
+
id: string;
|
|
286
|
+
rootId: string;
|
|
287
|
+
parentId?: string;
|
|
288
|
+
};
|
|
152
289
|
}
|
|
153
290
|
|
|
154
291
|
/**
|
|
155
292
|
* Action 动作定义契约。
|
|
156
|
-
* 通过 `defineAction({...})` 声明。
|
|
157
293
|
*/
|
|
158
|
-
export interface ActionDefinition<I = unknown, O = unknown> {
|
|
159
|
-
/** Action 唯一标识符(例如: "github.get-pr" 或 "sample.greet") */
|
|
160
|
-
id: string;
|
|
161
|
-
/** Action 功能描述,用于 CLI 帮助文档、Agent 发现以及 MCP Tool 描述 */
|
|
162
|
-
description?: string;
|
|
163
|
-
/** 输入参数的 JSON Schema 校验规范 */
|
|
164
|
-
inputSchema?: JsonSchema;
|
|
165
|
-
/** 输出结果的 JSON Schema 校验规范 */
|
|
166
|
-
outputSchema?: JsonSchema;
|
|
294
|
+
export interface ActionDefinition<I = unknown, O = unknown> extends ActionContract {
|
|
167
295
|
/**
|
|
168
296
|
* Action 的核心业务执行函数
|
|
169
297
|
* @param input 符合 inputSchema 契约的输入数据
|
|
170
|
-
* @param ctx
|
|
298
|
+
* @param ctx 运行时上下文对象
|
|
171
299
|
*/
|
|
172
300
|
run(input: I, ctx: ActionContext): Promise<O> | O;
|
|
173
301
|
}
|
|
174
302
|
|
|
175
303
|
/**
|
|
176
|
-
*
|
|
304
|
+
* 运行记录状态。
|
|
177
305
|
*/
|
|
178
|
-
export type RunStatus =
|
|
306
|
+
export type RunStatus =
|
|
307
|
+
| "running"
|
|
308
|
+
| "success"
|
|
309
|
+
| "failed"
|
|
310
|
+
| "cancelled"
|
|
311
|
+
| "timed_out"
|
|
312
|
+
| "interrupted";
|
|
179
313
|
|
|
180
314
|
/**
|
|
181
315
|
* Action 执行运行历史记录。
|
|
182
316
|
*/
|
|
183
317
|
export interface RunRecord {
|
|
184
|
-
/**
|
|
318
|
+
/** 全局唯一运行标识 */
|
|
185
319
|
id: string;
|
|
186
|
-
/**
|
|
320
|
+
/** 根调用运行标识 */
|
|
321
|
+
rootRunId: string;
|
|
322
|
+
/** 父级调用的运行标识 */
|
|
323
|
+
parentRunId?: string;
|
|
324
|
+
/** 所属 Action Package 的逻辑标识 */
|
|
187
325
|
packageId: string;
|
|
188
|
-
/**
|
|
326
|
+
/** 包物理实例标识 */
|
|
327
|
+
packageInstanceId: string;
|
|
328
|
+
/** 所执行的 Action 标识 */
|
|
189
329
|
actionId: string;
|
|
190
|
-
/**
|
|
191
|
-
|
|
330
|
+
/** 运行时代码快照代次标识 */
|
|
331
|
+
generationId: string;
|
|
332
|
+
/** 执行宿主所有者标识 */
|
|
333
|
+
ownerId: string;
|
|
192
334
|
/** 运行生命周期状态 */
|
|
193
335
|
status: RunStatus;
|
|
194
336
|
/** 输入参数快照 */
|
|
195
|
-
input
|
|
196
|
-
/**
|
|
197
|
-
output?:
|
|
337
|
+
input?: JsonValue;
|
|
338
|
+
/** 执行成功时的输出结果快照 */
|
|
339
|
+
output?: JsonValue;
|
|
198
340
|
/** 执行失败时的错误信息 */
|
|
199
341
|
error?: RuntimeError;
|
|
200
|
-
/** 开始执行时间(ISO 8601 格式) */
|
|
342
|
+
/** 开始执行时间(UTC ISO 8601 格式) */
|
|
201
343
|
startedAt: string;
|
|
202
|
-
/** 结束执行时间(ISO 8601
|
|
344
|
+
/** 结束执行时间(UTC ISO 8601 格式) */
|
|
203
345
|
finishedAt?: string;
|
|
346
|
+
/** 运行耗时(单位:毫秒) */
|
|
347
|
+
durationMs?: number;
|
|
204
348
|
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* 执行生命周期事件。
|
|
352
|
+
*/
|
|
353
|
+
export type ExecutionEvent = {
|
|
354
|
+
runId: string;
|
|
355
|
+
rootRunId: string;
|
|
356
|
+
sequence: number;
|
|
357
|
+
timestamp: string;
|
|
358
|
+
} & (
|
|
359
|
+
| { type: "log"; level: "debug" | "info" | "warn" | "error"; message: string; data?: JsonValue }
|
|
360
|
+
| { type: "progress"; current?: number; total?: number; message?: string }
|
|
361
|
+
| { type: "status"; status: RunStatus }
|
|
362
|
+
| { type: "finish"; result: ExecutionResult }
|
|
363
|
+
);
|