@actiondock/core 2.0.11 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -30
- package/dist/app/app.d.ts +73 -0
- package/dist/app/app.js +700 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/types.d.ts +283 -0
- package/dist/app/types.js +1 -0
- package/dist/catalog/action-index.d.ts +9 -0
- package/dist/catalog/action-index.js +93 -0
- package/dist/catalog/action-resolver.d.ts +20 -0
- package/dist/catalog/action-resolver.js +95 -0
- package/dist/catalog/index.d.ts +5 -0
- package/dist/catalog/index.js +5 -0
- package/dist/catalog/location-registry.d.ts +15 -0
- package/dist/catalog/location-registry.js +138 -0
- package/dist/catalog/package-catalog.d.ts +7 -0
- package/dist/catalog/package-catalog.js +76 -0
- package/dist/catalog/types.d.ts +68 -0
- package/dist/catalog/types.js +1 -0
- package/dist/doctor/doctor.d.ts +7 -0
- package/dist/doctor/doctor.js +613 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/types.d.ts +23 -0
- package/dist/doctor/types.js +1 -0
- package/dist/errors.d.ts +122 -0
- package/dist/errors.js +123 -0
- package/dist/execution/index.d.ts +2 -0
- package/dist/execution/index.js +2 -0
- package/dist/execution/service.d.ts +79 -0
- package/dist/execution/service.js +633 -0
- package/dist/execution/types.d.ts +131 -0
- package/dist/execution/types.js +1 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/export/index.js +1 -0
- package/dist/export/templates.d.ts +71 -0
- package/dist/export/templates.js +621 -0
- package/dist/filter/index.d.ts +1 -0
- package/dist/filter/index.js +1 -0
- package/dist/filter/intent.d.ts +33 -0
- package/dist/filter/intent.js +123 -0
- package/dist/host/host.d.ts +55 -0
- package/dist/host/host.js +740 -0
- package/dist/host/index.d.ts +2 -0
- package/dist/host/index.js +2 -0
- package/dist/host/types.d.ts +81 -0
- package/dist/host/types.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +20 -0
- package/dist/ipc/diagnostic.d.ts +65 -0
- package/dist/ipc/diagnostic.js +129 -0
- package/dist/ipc/host.d.ts +7 -0
- package/dist/ipc/host.js +93 -0
- package/dist/ipc/index.d.ts +4 -0
- package/dist/ipc/index.js +4 -0
- package/dist/ipc/target.d.ts +56 -0
- package/dist/ipc/target.js +297 -0
- package/dist/ipc/types.d.ts +42 -0
- package/dist/ipc/types.js +1 -0
- package/dist/platform/default.d.ts +32 -0
- package/dist/platform/default.js +40 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +3 -0
- package/dist/platform/node-fs.d.ts +37 -0
- package/dist/platform/node-fs.js +81 -0
- package/dist/platform/types.d.ts +104 -0
- package/dist/platform/types.js +1 -0
- package/dist/profile/client.d.ts +162 -0
- package/dist/profile/client.js +467 -0
- package/dist/profile/index.d.ts +3 -0
- package/dist/profile/index.js +3 -0
- package/dist/profile/manager.d.ts +47 -0
- package/dist/profile/manager.js +294 -0
- package/dist/profile/types.d.ts +61 -0
- package/dist/profile/types.js +1 -0
- package/dist/project/closure.d.ts +25 -0
- package/dist/project/closure.js +68 -0
- package/dist/project/digest.d.ts +29 -0
- package/dist/project/digest.js +324 -0
- package/dist/project/index.d.ts +10 -0
- package/dist/project/index.js +10 -0
- package/dist/project/init.d.ts +26 -0
- package/dist/project/init.js +175 -0
- package/dist/project/loader.d.ts +99 -0
- package/dist/project/loader.js +484 -0
- package/dist/project/lockfile.d.ts +55 -0
- package/dist/project/lockfile.js +175 -0
- package/dist/project/manifest.d.ts +22 -0
- package/dist/project/manifest.js +220 -0
- package/dist/project/resolver.d.ts +116 -0
- package/dist/project/resolver.js +376 -0
- package/dist/project/transactions.d.ts +103 -0
- package/dist/project/transactions.js +1203 -0
- package/dist/project/types-generator.d.ts +33 -0
- package/dist/project/types-generator.js +168 -0
- package/dist/project/types.d.ts +107 -0
- package/dist/project/types.js +1 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +5 -0
- package/dist/registry/lock.d.ts +27 -0
- package/dist/registry/lock.js +93 -0
- package/dist/registry/registry.d.ts +45 -0
- package/dist/registry/registry.js +611 -0
- package/dist/registry/resolve.d.ts +62 -0
- package/dist/registry/resolve.js +195 -0
- package/dist/registry/scan.d.ts +38 -0
- package/dist/registry/scan.js +135 -0
- package/dist/registry/types.d.ts +117 -0
- package/dist/registry/types.js +1 -0
- package/dist/runtime/action-collection.d.ts +27 -0
- package/dist/runtime/action-collection.js +57 -0
- package/dist/runtime/clock.d.ts +19 -0
- package/dist/runtime/clock.js +17 -0
- package/dist/runtime/context.d.ts +86 -0
- package/dist/runtime/context.js +242 -0
- package/dist/runtime/env.d.ts +56 -0
- package/dist/runtime/env.js +159 -0
- package/dist/runtime/events.d.ts +93 -0
- package/dist/runtime/events.js +604 -0
- package/dist/runtime/execution-manager.d.ts +48 -0
- package/dist/runtime/execution-manager.js +66 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/module-loader.d.ts +34 -0
- package/dist/runtime/module-loader.js +16 -0
- package/dist/runtime/process.d.ts +9 -0
- package/dist/runtime/process.js +146 -0
- package/dist/runtime/runner.d.ts +293 -0
- package/dist/runtime/runner.js +984 -0
- package/dist/runtime/standalone.d.ts +89 -0
- package/dist/runtime/standalone.js +536 -0
- package/dist/schema/validator.d.ts +28 -0
- package/dist/schema/validator.js +116 -0
- package/dist/server/body.d.ts +40 -0
- package/dist/server/body.js +93 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +5 -0
- package/dist/server/routes/actions.d.ts +5 -0
- package/dist/server/routes/actions.js +298 -0
- package/dist/server/routes/common.d.ts +47 -0
- package/dist/server/routes/common.js +104 -0
- package/dist/server/routes/config.d.ts +6 -0
- package/dist/server/routes/config.js +173 -0
- package/dist/server/routes/doctor.d.ts +5 -0
- package/dist/server/routes/doctor.js +63 -0
- package/dist/server/routes/health.d.ts +5 -0
- package/dist/server/routes/health.js +35 -0
- package/dist/server/routes/index.d.ts +9 -0
- package/dist/server/routes/index.js +9 -0
- package/dist/server/routes/info.d.ts +7 -0
- package/dist/server/routes/info.js +158 -0
- package/dist/server/routes/playbooks.d.ts +5 -0
- package/dist/server/routes/playbooks.js +134 -0
- package/dist/server/routes/runs.d.ts +5 -0
- package/dist/server/routes/runs.js +343 -0
- package/dist/server/routes/state.d.ts +6 -0
- package/dist/server/routes/state.js +169 -0
- package/dist/server/security.d.ts +44 -0
- package/dist/server/security.js +101 -0
- package/dist/server/server.d.ts +15 -0
- package/dist/server/server.js +355 -0
- package/dist/server/types.d.ts +78 -0
- package/dist/server/types.js +1 -0
- package/dist/storage/data-dir-lock.d.ts +119 -0
- package/dist/storage/data-dir-lock.js +1016 -0
- package/dist/storage/driver.d.ts +9 -0
- package/dist/storage/driver.js +59 -0
- package/dist/storage/index.d.ts +64 -0
- package/dist/storage/index.js +98 -0
- package/dist/storage/lazy.d.ts +8 -0
- package/dist/storage/lazy.js +44 -0
- package/dist/storage/mask.d.ts +26 -0
- package/dist/storage/mask.js +48 -0
- package/dist/storage/params.d.ts +13 -0
- package/dist/storage/params.js +32 -0
- package/dist/storage/sqlite.d.ts +79 -0
- package/dist/storage/sqlite.js +689 -0
- package/dist/storage/types.d.ts +172 -0
- package/dist/storage/types.js +14 -0
- package/dist/target/index.d.ts +4 -0
- package/dist/target/index.js +4 -0
- package/dist/target/local.d.ts +52 -0
- package/dist/target/local.js +343 -0
- package/dist/target/remote.d.ts +76 -0
- package/dist/target/remote.js +839 -0
- package/dist/target/target.d.ts +6 -0
- package/dist/target/target.js +35 -0
- package/dist/target/types.d.ts +246 -0
- package/dist/target/types.js +34 -0
- package/dist/utils/index.d.ts +49 -0
- package/dist/utils/index.js +180 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +4 -0
- package/package.json +13 -13
- package/src/build/index.ts +0 -1
- package/src/build/templates.ts +0 -59
- package/src/catalog/action-index.ts +0 -92
- package/src/catalog/action-resolver.ts +0 -120
- package/src/catalog/index.ts +0 -5
- package/src/catalog/location-registry.ts +0 -134
- package/src/catalog/package-catalog.ts +0 -87
- package/src/catalog/types.ts +0 -75
- package/src/doctor/doctor.ts +0 -419
- package/src/doctor/index.ts +0 -2
- package/src/doctor/types.ts +0 -25
- package/src/execution/index.ts +0 -2
- package/src/execution/service.ts +0 -322
- package/src/execution/types.ts +0 -73
- package/src/export/index.ts +0 -1
- package/src/export/templates.ts +0 -590
- package/src/filter/index.ts +0 -1
- package/src/filter/intent.ts +0 -154
- package/src/index.ts +0 -16
- package/src/profile/client.ts +0 -552
- package/src/profile/index.ts +0 -3
- package/src/profile/manager.ts +0 -341
- package/src/profile/types.ts +0 -71
- package/src/project/index.ts +0 -4
- package/src/project/init.ts +0 -242
- package/src/project/loader.ts +0 -479
- package/src/project/manifest.ts +0 -299
- package/src/project/types.ts +0 -141
- package/src/registry/index.ts +0 -2
- package/src/registry/registry.ts +0 -940
- package/src/registry/types.ts +0 -127
- package/src/runtime/clock.ts +0 -41
- package/src/runtime/context.ts +0 -259
- package/src/runtime/env.ts +0 -172
- package/src/runtime/events.ts +0 -142
- package/src/runtime/execution-manager.ts +0 -74
- package/src/runtime/index.ts +0 -10
- package/src/runtime/module-loader.ts +0 -67
- package/src/runtime/process.ts +0 -245
- package/src/runtime/runner.ts +0 -527
- package/src/runtime/standalone.ts +0 -429
- package/src/schema/validator.ts +0 -61
- package/src/server/body.ts +0 -112
- package/src/server/index.ts +0 -7
- package/src/server/routes/actions.ts +0 -262
- package/src/server/routes/common.ts +0 -126
- package/src/server/routes/config.ts +0 -147
- package/src/server/routes/doctor.ts +0 -29
- package/src/server/routes/health.ts +0 -40
- package/src/server/routes/index.ts +0 -9
- package/src/server/routes/info.ts +0 -221
- package/src/server/routes/playbooks.ts +0 -109
- package/src/server/routes/runs.ts +0 -301
- package/src/server/routes/state.ts +0 -133
- package/src/server/runtime-registry.ts +0 -115
- package/src/server/security.ts +0 -115
- package/src/server/server.ts +0 -251
- package/src/server/types.ts +0 -57
- package/src/storage/driver.ts +0 -126
- package/src/storage/index.ts +0 -81
- package/src/storage/mask.ts +0 -34
- package/src/storage/sqlite.ts +0 -714
- package/src/storage/types.ts +0 -139
- package/src/utils/index.ts +0 -62
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* 解析 JSON 文本并在检测到重复键时抛出错误。
|
|
4
|
+
* 遵循 RFC 8785 清单校验规范:解析阶段必须率先拦截并拒绝重复键。
|
|
5
|
+
*/
|
|
6
|
+
export function parseJsonWithoutDuplicates(jsonText) {
|
|
7
|
+
let pos = 0;
|
|
8
|
+
const len = jsonText.length;
|
|
9
|
+
function skipWhitespace() {
|
|
10
|
+
while (pos < len) {
|
|
11
|
+
const ch = jsonText.charCodeAt(pos);
|
|
12
|
+
if (ch === 0x20 || ch === 0x09 || ch === 0x0a || ch === 0x0d) {
|
|
13
|
+
pos++;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseString() {
|
|
21
|
+
if (jsonText[pos] !== '"') {
|
|
22
|
+
throw new SyntaxError(`Expected string at position ${pos}`);
|
|
23
|
+
}
|
|
24
|
+
const start = pos;
|
|
25
|
+
pos++; // 跳过开头的引号
|
|
26
|
+
let result = "";
|
|
27
|
+
while (pos < len) {
|
|
28
|
+
const ch = jsonText[pos];
|
|
29
|
+
if (ch === '"') {
|
|
30
|
+
pos++; // 跳过结束的引号
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
if (ch === "\\") {
|
|
34
|
+
pos++;
|
|
35
|
+
if (pos >= len) {
|
|
36
|
+
throw new SyntaxError(`Unterminated escape sequence in string at ${pos}`);
|
|
37
|
+
}
|
|
38
|
+
const esc = jsonText[pos];
|
|
39
|
+
if (esc === '"' || esc === "\\" || esc === "/") {
|
|
40
|
+
result += esc;
|
|
41
|
+
pos++;
|
|
42
|
+
}
|
|
43
|
+
else if (esc === "b") {
|
|
44
|
+
result += "\b";
|
|
45
|
+
pos++;
|
|
46
|
+
}
|
|
47
|
+
else if (esc === "f") {
|
|
48
|
+
result += "\f";
|
|
49
|
+
pos++;
|
|
50
|
+
}
|
|
51
|
+
else if (esc === "n") {
|
|
52
|
+
result += "\n";
|
|
53
|
+
pos++;
|
|
54
|
+
}
|
|
55
|
+
else if (esc === "r") {
|
|
56
|
+
result += "\r";
|
|
57
|
+
pos++;
|
|
58
|
+
}
|
|
59
|
+
else if (esc === "t") {
|
|
60
|
+
result += "\t";
|
|
61
|
+
pos++;
|
|
62
|
+
}
|
|
63
|
+
else if (esc === "u") {
|
|
64
|
+
pos++;
|
|
65
|
+
const hex = jsonText.slice(pos, pos + 4);
|
|
66
|
+
if (hex.length < 4 || !/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
67
|
+
throw new SyntaxError(`Invalid unicode escape sequence \\u${hex} at ${pos}`);
|
|
68
|
+
}
|
|
69
|
+
result += String.fromCharCode(parseInt(hex, 16));
|
|
70
|
+
pos += 4;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new SyntaxError(`Invalid escape character '\\${esc}' at ${pos}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
result += ch;
|
|
78
|
+
pos++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw new SyntaxError(`Unterminated string starting at ${start}`);
|
|
82
|
+
}
|
|
83
|
+
function parseNumber() {
|
|
84
|
+
const start = pos;
|
|
85
|
+
if (jsonText[pos] === "-") {
|
|
86
|
+
pos++;
|
|
87
|
+
}
|
|
88
|
+
if (pos >= len) {
|
|
89
|
+
throw new SyntaxError(`Expected digits at position ${pos}`);
|
|
90
|
+
}
|
|
91
|
+
if (jsonText[pos] === "0") {
|
|
92
|
+
pos++;
|
|
93
|
+
}
|
|
94
|
+
else if (jsonText[pos] >= "1" && jsonText[pos] <= "9") {
|
|
95
|
+
while (pos < len && jsonText[pos] >= "0" && jsonText[pos] <= "9") {
|
|
96
|
+
pos++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw new SyntaxError(`Invalid number at position ${pos}`);
|
|
101
|
+
}
|
|
102
|
+
if (pos < len && jsonText[pos] === ".") {
|
|
103
|
+
pos++;
|
|
104
|
+
if (pos >= len || jsonText[pos] < "0" || jsonText[pos] > "9") {
|
|
105
|
+
throw new SyntaxError(`Expected digit after decimal point at position ${pos}`);
|
|
106
|
+
}
|
|
107
|
+
while (pos < len && jsonText[pos] >= "0" && jsonText[pos] <= "9") {
|
|
108
|
+
pos++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (pos < len && (jsonText[pos] === "e" || jsonText[pos] === "E")) {
|
|
112
|
+
pos++;
|
|
113
|
+
if (pos < len && (jsonText[pos] === "+" || jsonText[pos] === "-")) {
|
|
114
|
+
pos++;
|
|
115
|
+
}
|
|
116
|
+
if (pos >= len || jsonText[pos] < "0" || jsonText[pos] > "9") {
|
|
117
|
+
throw new SyntaxError(`Expected digit after exponent at position ${pos}`);
|
|
118
|
+
}
|
|
119
|
+
while (pos < len && jsonText[pos] >= "0" && jsonText[pos] <= "9") {
|
|
120
|
+
pos++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const numStr = jsonText.slice(start, pos);
|
|
124
|
+
const num = Number(numStr);
|
|
125
|
+
if (!Number.isFinite(num)) {
|
|
126
|
+
throw new SyntaxError(`Number out of range: ${numStr}`);
|
|
127
|
+
}
|
|
128
|
+
return num;
|
|
129
|
+
}
|
|
130
|
+
function parseObject() {
|
|
131
|
+
const obj = {};
|
|
132
|
+
const keys = new Set();
|
|
133
|
+
pos++; // 跳过 '{'
|
|
134
|
+
skipWhitespace();
|
|
135
|
+
if (pos < len && jsonText[pos] === "}") {
|
|
136
|
+
pos++;
|
|
137
|
+
return obj;
|
|
138
|
+
}
|
|
139
|
+
while (pos < len) {
|
|
140
|
+
skipWhitespace();
|
|
141
|
+
if (jsonText[pos] !== '"') {
|
|
142
|
+
throw new SyntaxError(`Expected string key in object at position ${pos}`);
|
|
143
|
+
}
|
|
144
|
+
const key = parseString();
|
|
145
|
+
if (keys.has(key)) {
|
|
146
|
+
throw new Error(`Duplicate key '${key}' detected in JSON`);
|
|
147
|
+
}
|
|
148
|
+
keys.add(key);
|
|
149
|
+
skipWhitespace();
|
|
150
|
+
if (pos >= len || jsonText[pos] !== ":") {
|
|
151
|
+
throw new SyntaxError(`Expected ':' after key '${key}' at position ${pos}`);
|
|
152
|
+
}
|
|
153
|
+
pos++; // 跳过 ':'
|
|
154
|
+
skipWhitespace();
|
|
155
|
+
const val = parseValue();
|
|
156
|
+
obj[key] = val;
|
|
157
|
+
skipWhitespace();
|
|
158
|
+
if (pos >= len) {
|
|
159
|
+
throw new SyntaxError("Unexpected end of JSON in object");
|
|
160
|
+
}
|
|
161
|
+
if (jsonText[pos] === ",") {
|
|
162
|
+
pos++;
|
|
163
|
+
skipWhitespace();
|
|
164
|
+
}
|
|
165
|
+
else if (jsonText[pos] === "}") {
|
|
166
|
+
pos++;
|
|
167
|
+
return obj;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
throw new SyntaxError(`Expected ',' or '}' in object at position ${pos}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
throw new SyntaxError("Unterminated object in JSON");
|
|
174
|
+
}
|
|
175
|
+
function parseArray() {
|
|
176
|
+
const arr = [];
|
|
177
|
+
pos++; // 跳过 '['
|
|
178
|
+
skipWhitespace();
|
|
179
|
+
if (pos < len && jsonText[pos] === "]") {
|
|
180
|
+
pos++;
|
|
181
|
+
return arr;
|
|
182
|
+
}
|
|
183
|
+
while (pos < len) {
|
|
184
|
+
skipWhitespace();
|
|
185
|
+
const val = parseValue();
|
|
186
|
+
arr.push(val);
|
|
187
|
+
skipWhitespace();
|
|
188
|
+
if (pos >= len) {
|
|
189
|
+
throw new SyntaxError("Unexpected end of JSON in array");
|
|
190
|
+
}
|
|
191
|
+
if (jsonText[pos] === ",") {
|
|
192
|
+
pos++;
|
|
193
|
+
skipWhitespace();
|
|
194
|
+
}
|
|
195
|
+
else if (jsonText[pos] === "]") {
|
|
196
|
+
pos++;
|
|
197
|
+
return arr;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
throw new SyntaxError(`Expected ',' or ']' in array at position ${pos}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
throw new SyntaxError("Unterminated array in JSON");
|
|
204
|
+
}
|
|
205
|
+
function parseValue() {
|
|
206
|
+
skipWhitespace();
|
|
207
|
+
if (pos >= len) {
|
|
208
|
+
throw new SyntaxError("Unexpected end of JSON input");
|
|
209
|
+
}
|
|
210
|
+
const ch = jsonText[pos];
|
|
211
|
+
if (ch === "{")
|
|
212
|
+
return parseObject();
|
|
213
|
+
if (ch === "[")
|
|
214
|
+
return parseArray();
|
|
215
|
+
if (ch === '"')
|
|
216
|
+
return parseString();
|
|
217
|
+
if (ch === "-" || (ch >= "0" && ch <= "9"))
|
|
218
|
+
return parseNumber();
|
|
219
|
+
if (jsonText.startsWith("true", pos)) {
|
|
220
|
+
pos += 4;
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
if (jsonText.startsWith("false", pos)) {
|
|
224
|
+
pos += 5;
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
if (jsonText.startsWith("null", pos)) {
|
|
228
|
+
pos += 4;
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
throw new SyntaxError(`Unexpected token '${ch}' at position ${pos}`);
|
|
232
|
+
}
|
|
233
|
+
const result = parseValue();
|
|
234
|
+
skipWhitespace();
|
|
235
|
+
if (pos < len) {
|
|
236
|
+
throw new SyntaxError(`Unexpected trailing characters at position ${pos}`);
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 依据 RFC 8785 规范化 JSON 数据。
|
|
242
|
+
* 规则:
|
|
243
|
+
* - 对象属性依据 UTF-16 代码单元进行升序排序;
|
|
244
|
+
* - 符号与键值之间不包含多余空白字符;
|
|
245
|
+
* - 浮点数与整数遵循 ECMAScript 规范序列化(负零转为零,拒绝非有限数);
|
|
246
|
+
* - 字符串转义严格遵循标准规范;
|
|
247
|
+
* - 数组保持原有顺序且元素递归规范化。
|
|
248
|
+
*/
|
|
249
|
+
export function canonicalizeJson(value) {
|
|
250
|
+
if (value === null) {
|
|
251
|
+
return "null";
|
|
252
|
+
}
|
|
253
|
+
const type = typeof value;
|
|
254
|
+
if (type === "boolean") {
|
|
255
|
+
return value ? "true" : "false";
|
|
256
|
+
}
|
|
257
|
+
if (type === "number") {
|
|
258
|
+
if (!Number.isFinite(value)) {
|
|
259
|
+
throw new TypeError("RFC 8785 JSON 规范化拒绝非有限数值 (NaN 或 Infinity)");
|
|
260
|
+
}
|
|
261
|
+
if (Object.is(value, -0) || value === 0) {
|
|
262
|
+
return "0";
|
|
263
|
+
}
|
|
264
|
+
return JSON.stringify(value);
|
|
265
|
+
}
|
|
266
|
+
if (type === "string") {
|
|
267
|
+
return JSON.stringify(value);
|
|
268
|
+
}
|
|
269
|
+
if (Array.isArray(value)) {
|
|
270
|
+
const items = value.map((item) => {
|
|
271
|
+
if (item === undefined || typeof item === "function" || typeof item === "symbol") {
|
|
272
|
+
return "null";
|
|
273
|
+
}
|
|
274
|
+
return canonicalizeJson(item);
|
|
275
|
+
});
|
|
276
|
+
return `[${items.join(",")}]`;
|
|
277
|
+
}
|
|
278
|
+
if (type === "object") {
|
|
279
|
+
const obj = value;
|
|
280
|
+
const keys = Object.keys(obj).sort();
|
|
281
|
+
const entries = [];
|
|
282
|
+
for (const key of keys) {
|
|
283
|
+
const val = obj[key];
|
|
284
|
+
if (val === undefined || typeof val === "function" || typeof val === "symbol") {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
entries.push(`${JSON.stringify(key)}:${canonicalizeJson(val)}`);
|
|
288
|
+
}
|
|
289
|
+
return `{${entries.join(",")}}`;
|
|
290
|
+
}
|
|
291
|
+
return "null";
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 计算任意 JSON 结构或 JSON 字符串的 SHA-256 规范化摘要。
|
|
295
|
+
* 输出格式为 sha256-<hex>。
|
|
296
|
+
*/
|
|
297
|
+
export function computeDigest(value) {
|
|
298
|
+
let canonicalText;
|
|
299
|
+
if (typeof value === "string") {
|
|
300
|
+
const parsed = parseJsonWithoutDuplicates(value);
|
|
301
|
+
canonicalText = canonicalizeJson(parsed);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
canonicalText = canonicalizeJson(value);
|
|
305
|
+
}
|
|
306
|
+
const hash = createHash("sha256").update(canonicalText, "utf8").digest("hex");
|
|
307
|
+
return `sha256-${hash}`;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* 计算 Action 清单对象的唯一确定性 RFC 8785 摘要。
|
|
311
|
+
* 清单中的等价空格变化与字段顺序不会改变摘要结果。
|
|
312
|
+
*/
|
|
313
|
+
export function computeManifestDigest(manifest) {
|
|
314
|
+
return computeDigest(manifest);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* 校验给定清单的摘要是否与期望值一致。
|
|
318
|
+
*/
|
|
319
|
+
export function verifyManifestDigest(manifest, expectedDigest) {
|
|
320
|
+
if (!expectedDigest || typeof expectedDigest !== "string") {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
return computeManifestDigest(manifest) === expectedDigest;
|
|
324
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./closure.js";
|
|
2
|
+
export * from "./digest.js";
|
|
3
|
+
export * from "./init.js";
|
|
4
|
+
export * from "./loader.js";
|
|
5
|
+
export * from "./lockfile.js";
|
|
6
|
+
export * from "./manifest.js";
|
|
7
|
+
export * from "./resolver.js";
|
|
8
|
+
export { SNAPSHOT_TRACKED_FILES, type TransactionFileRecord, type TransactionMetadata, type ProjectTransaction, isPidAlive, isProjectLockHeld, acquireProjectLock, runFrozenInstall, hasPendingTransactions, beginTransaction, recoverPendingTransactions, } from "./transactions.js";
|
|
9
|
+
export * from "./types.js";
|
|
10
|
+
export * from "./types-generator.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./closure.js";
|
|
2
|
+
export * from "./digest.js";
|
|
3
|
+
export * from "./init.js";
|
|
4
|
+
export * from "./loader.js";
|
|
5
|
+
export * from "./lockfile.js";
|
|
6
|
+
export * from "./manifest.js";
|
|
7
|
+
export * from "./resolver.js";
|
|
8
|
+
export { SNAPSHOT_TRACKED_FILES, isPidAlive, isProjectLockHeld, acquireProjectLock, runFrozenInstall, hasPendingTransactions, beginTransaction, recoverPendingTransactions, } from "./transactions.js";
|
|
9
|
+
export * from "./types.js";
|
|
10
|
+
export * from "./types-generator.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目初始化脚手架选项。
|
|
3
|
+
*/
|
|
4
|
+
export interface InitOptions {
|
|
5
|
+
/** 自定义项目 ID(默认使用目录名) */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** 自定义项目展示名称(默认由目录名美化生成) */
|
|
8
|
+
name?: string;
|
|
9
|
+
/** 自定义项目描述 */
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 在目标目录初始化一个完整的 ActionDock 2.0 Action Package 脚手架。
|
|
14
|
+
* 生成内容包括:
|
|
15
|
+
* - actiondock.json(项目元数据、Action 与 Playbook 声明的单一事实源)
|
|
16
|
+
* - package.json(Node.js 标准脚本与依赖声明)
|
|
17
|
+
* - tsconfig.json(现代 NodeNext 模块规范)
|
|
18
|
+
* - .gitignore(排除持久化 db、node_modules、dist)
|
|
19
|
+
* - actions/greet.ts(标准示例 Action 执行 Handler,演示 config、state、log 使用)
|
|
20
|
+
* - playbooks/greet-user.md(纯 Markdown 标准 SOP Playbook 演示)
|
|
21
|
+
* - tests/greet.test.ts(基于 node:test 与 @actiondock/testing 的测试用例)
|
|
22
|
+
*
|
|
23
|
+
* @param targetDir 目标项目目录
|
|
24
|
+
* @param options 初始化选项
|
|
25
|
+
*/
|
|
26
|
+
export declare function initProject(targetDir: string, options?: InitOptions): void;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* 在目标目录初始化一个完整的 ActionDock 2.0 Action Package 脚手架。
|
|
5
|
+
* 生成内容包括:
|
|
6
|
+
* - actiondock.json(项目元数据、Action 与 Playbook 声明的单一事实源)
|
|
7
|
+
* - package.json(Node.js 标准脚本与依赖声明)
|
|
8
|
+
* - tsconfig.json(现代 NodeNext 模块规范)
|
|
9
|
+
* - .gitignore(排除持久化 db、node_modules、dist)
|
|
10
|
+
* - actions/greet.ts(标准示例 Action 执行 Handler,演示 config、state、log 使用)
|
|
11
|
+
* - playbooks/greet-user.md(纯 Markdown 标准 SOP Playbook 演示)
|
|
12
|
+
* - tests/greet.test.ts(基于 node:test 与 @actiondock/testing 的测试用例)
|
|
13
|
+
*
|
|
14
|
+
* @param targetDir 目标项目目录
|
|
15
|
+
* @param options 初始化选项
|
|
16
|
+
*/
|
|
17
|
+
export function initProject(targetDir, options = {}) {
|
|
18
|
+
const root = resolve(targetDir);
|
|
19
|
+
if (!existsSync(root)) {
|
|
20
|
+
mkdirSync(root, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
const dirName = basename(root);
|
|
23
|
+
const id = options.id || dirName;
|
|
24
|
+
const name = options.name || dirName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
25
|
+
const description = options.description || "ActionDock AI Agent Actions";
|
|
26
|
+
// 1. actiondock.json(单一事实源)
|
|
27
|
+
const actiondockJson = {
|
|
28
|
+
$schema: "https://actiondock.dev/schema/v2.json",
|
|
29
|
+
schemaVersion: 2,
|
|
30
|
+
id,
|
|
31
|
+
name,
|
|
32
|
+
version: "0.1.0",
|
|
33
|
+
description,
|
|
34
|
+
config: {
|
|
35
|
+
SAMPLE_GREETING: {
|
|
36
|
+
description: "Default greeting message",
|
|
37
|
+
default: "Hello",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
actions: {
|
|
41
|
+
"sample.greet": {
|
|
42
|
+
entry: "actions/greet.ts",
|
|
43
|
+
description: "Greeting action demonstrating basic input, config, and state usage",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
name: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "Name of the person to greet",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
required: ["name"],
|
|
53
|
+
},
|
|
54
|
+
outputSchema: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
message: { type: "string" },
|
|
58
|
+
timesGreeted: { type: "number" },
|
|
59
|
+
},
|
|
60
|
+
required: ["message", "timesGreeted"],
|
|
61
|
+
},
|
|
62
|
+
tags: ["sample"],
|
|
63
|
+
uses: [],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
playbooks: {
|
|
67
|
+
"greet-user": {
|
|
68
|
+
entry: "playbooks/greet-user.md",
|
|
69
|
+
description: "SOP for greeting a new user and verifying system health",
|
|
70
|
+
actions: ["sample.greet"],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
files: [],
|
|
74
|
+
};
|
|
75
|
+
writeFileSync(join(root, "actiondock.json"), JSON.stringify(actiondockJson, null, 2) + "\n");
|
|
76
|
+
// 2. package.json
|
|
77
|
+
const packageJson = {
|
|
78
|
+
name: id,
|
|
79
|
+
version: "0.1.0",
|
|
80
|
+
description,
|
|
81
|
+
type: "module",
|
|
82
|
+
scripts: {
|
|
83
|
+
test: "node --import tsx --test tests/*.test.ts",
|
|
84
|
+
},
|
|
85
|
+
engines: {
|
|
86
|
+
node: ">=24.12.0",
|
|
87
|
+
},
|
|
88
|
+
dependencies: {
|
|
89
|
+
"@actiondock/sdk": "^2.2.0",
|
|
90
|
+
},
|
|
91
|
+
devDependencies: {
|
|
92
|
+
"@actiondock/testing": "^2.2.0",
|
|
93
|
+
"@types/node": "^22.13.0",
|
|
94
|
+
"tsx": "^4.19.0",
|
|
95
|
+
"typescript": "^5.7.0",
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
writeFileSync(join(root, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
99
|
+
// 3. tsconfig.json
|
|
100
|
+
const tsconfigJson = {
|
|
101
|
+
compilerOptions: {
|
|
102
|
+
target: "ES2022",
|
|
103
|
+
module: "NodeNext",
|
|
104
|
+
moduleResolution: "NodeNext",
|
|
105
|
+
strict: true,
|
|
106
|
+
skipLibCheck: true,
|
|
107
|
+
types: ["node"],
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
writeFileSync(join(root, "tsconfig.json"), JSON.stringify(tsconfigJson, null, 2) + "\n");
|
|
111
|
+
// 4. .gitignore
|
|
112
|
+
const gitignore = `.actiondock/
|
|
113
|
+
node_modules/
|
|
114
|
+
dist/
|
|
115
|
+
build/
|
|
116
|
+
*.log
|
|
117
|
+
.env
|
|
118
|
+
`;
|
|
119
|
+
writeFileSync(join(root, ".gitignore"), gitignore);
|
|
120
|
+
// 5. actions/
|
|
121
|
+
const actionsDir = join(root, "actions");
|
|
122
|
+
mkdirSync(actionsDir, { recursive: true });
|
|
123
|
+
const sampleAction = `import { defineAction } from "@actiondock/sdk";
|
|
124
|
+
|
|
125
|
+
// 说明:若 Action 需导入包内其他源码目录(如 src/、lib/ 或辅助工具模块),
|
|
126
|
+
// 请务必在 actiondock.json 的 "files" 字段中声明对应目录以确保构建与导出完整。
|
|
127
|
+
export default defineAction(async (input: { name: string }, ctx) => {
|
|
128
|
+
const greeting = ctx.config.get("SAMPLE_GREETING", "Hello");
|
|
129
|
+
const count = ((await ctx.state.get<number>("greet_count")) || 0) + 1;
|
|
130
|
+
await ctx.state.set("greet_count", count);
|
|
131
|
+
|
|
132
|
+
ctx.log.info(\`Greeting \${input.name} (times greeted: \${count})\`);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
message: \`\${greeting}, \${input.name}!\`,
|
|
136
|
+
timesGreeted: count,
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
`;
|
|
140
|
+
writeFileSync(join(actionsDir, "greet.ts"), sampleAction);
|
|
141
|
+
// 6. playbooks/
|
|
142
|
+
const playbooksDir = join(root, "playbooks");
|
|
143
|
+
mkdirSync(playbooksDir, { recursive: true });
|
|
144
|
+
const samplePlaybook = `# Greeting SOP
|
|
145
|
+
|
|
146
|
+
- Call \`sample.greet\` with the user's name.
|
|
147
|
+
- Confirm the returned greeting message.
|
|
148
|
+
`;
|
|
149
|
+
writeFileSync(join(playbooksDir, "greet-user.md"), samplePlaybook);
|
|
150
|
+
// 7. tests/
|
|
151
|
+
const testsDir = join(root, "tests");
|
|
152
|
+
mkdirSync(testsDir, { recursive: true });
|
|
153
|
+
const sampleTest = `import { describe, it } from "node:test";
|
|
154
|
+
import assert from "node:assert/strict";
|
|
155
|
+
import { createTestRuntime } from "@actiondock/testing";
|
|
156
|
+
import greetAction from "../actions/greet.js";
|
|
157
|
+
|
|
158
|
+
describe("greet action", () => {
|
|
159
|
+
it("should greet user with greeting and increment count", async () => {
|
|
160
|
+
const runtime = createTestRuntime({
|
|
161
|
+
config: { SAMPLE_GREETING: "Hi" },
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const res1 = await runtime.run(greetAction, { name: "Alice" });
|
|
165
|
+
assert.equal(res1.message, "Hi, Alice!");
|
|
166
|
+
assert.equal(await runtime.state.get("greet_count"), 1);
|
|
167
|
+
|
|
168
|
+
const res2 = await runtime.run(greetAction, { name: "Bob" });
|
|
169
|
+
assert.equal(res2.message, "Hi, Bob!");
|
|
170
|
+
assert.equal(await runtime.state.get("greet_count"), 2);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
`;
|
|
174
|
+
writeFileSync(join(testsDir, "greet.test.ts"), sampleTest);
|
|
175
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ActionDefinition } from "@actiondock/sdk";
|
|
2
|
+
import { type ModuleLoader } from "../runtime/module-loader.js";
|
|
3
|
+
import type { ActionDockManifest, PlaybookDefinition, PlaybookManifestEntry, ProjectConfig } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
|
|
6
|
+
*
|
|
7
|
+
* @param cwd 起始搜索目录(默认为 process.cwd())
|
|
8
|
+
* @returns 项目根目录绝对路径,若未找到则返回 null
|
|
9
|
+
*/
|
|
10
|
+
export declare function findProjectRoot(cwd?: string): string | null;
|
|
11
|
+
/**
|
|
12
|
+
* 加载并校验指定目录下的 `actiondock.json` 配置文件。
|
|
13
|
+
*
|
|
14
|
+
* @param projectRoot 项目根目录绝对路径
|
|
15
|
+
* @returns 解析后的 ProjectConfig 对象
|
|
16
|
+
* @throws {Error} 若文件不存在或 JSON 格式错误、缺失必要字段
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadProjectConfig(projectRoot: string): ProjectConfig;
|
|
19
|
+
export declare const ALLOWED_INSTALLERS: Set<string>;
|
|
20
|
+
/**
|
|
21
|
+
* 探测宿主系统中可用的包管理工具。
|
|
22
|
+
* 优先级:
|
|
23
|
+
* - 环境变量 ACTIONDOCK_INSTALLER 显式指定(严格白名单校验:npm, bun);
|
|
24
|
+
* - 依据项目根目录下现存的锁文件进行精确匹配(bun.lock/bun.lockb -> bun, package-lock.json/npm-shrinkwrap.json -> npm);
|
|
25
|
+
* - 候选回退优先级探测(npm > bun)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function getInstallCommand(projectRoot?: string): string[];
|
|
28
|
+
/**
|
|
29
|
+
* 读取项目当前缓存的依赖指纹哈希。
|
|
30
|
+
*/
|
|
31
|
+
export declare function readStoredDependencyFingerprint(projectRoot: string): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* 将最新的依赖指纹哈希写入缓存文件。
|
|
34
|
+
*/
|
|
35
|
+
export declare function saveDependencyFingerprint(projectRoot: string, fingerprint: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* 计算项目依赖的指纹哈希(基于 package.json 依赖声明及可能存在的锁文件内容)。
|
|
38
|
+
*
|
|
39
|
+
* @param projectRoot 项目根目录
|
|
40
|
+
* @returns 64位十六进制哈希字符串,若 package.json 不存在或解析失败则返回 null
|
|
41
|
+
*/
|
|
42
|
+
export declare function computeDependencyFingerprint(projectRoot: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* 确保项目依赖(node_modules)已正确安装。
|
|
45
|
+
* 若尚未安装、依赖版本变更(指纹不匹配)或加载失败时,自动触发包管理器执行依赖安装。
|
|
46
|
+
*
|
|
47
|
+
* @param projectRoot 项目根目录
|
|
48
|
+
* @param force 是否强制重新安装
|
|
49
|
+
* @returns 是否成功执行了安装或更新
|
|
50
|
+
*/
|
|
51
|
+
export declare function ensureProjectDependencies(projectRoot: string, force?: boolean): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 发现并检索项目 actions 目录下的所有 Action 源码文件(.ts)。
|
|
54
|
+
*
|
|
55
|
+
* @param projectRoot 项目根目录
|
|
56
|
+
* @param actionsDir actions 子目录名称(默认 "actions")
|
|
57
|
+
*/
|
|
58
|
+
export declare function discoverActionFiles(projectRoot: string, actionsDir?: string): string[];
|
|
59
|
+
/**
|
|
60
|
+
* 动态导入并加载项目下的所有 Action 定义对象。
|
|
61
|
+
* 以 actiondock.json 为唯一事实源读取 Action 的元数据契约(id, description, inputSchema, outputSchema, tags, annotations, uses),
|
|
62
|
+
* 源码文件仅提供执行 Handler。
|
|
63
|
+
*
|
|
64
|
+
* @param projectRoot 项目根目录
|
|
65
|
+
* @param _actionsDir actions 子目录(向后兼容保留参数)
|
|
66
|
+
* @param options 模块加载器等选项
|
|
67
|
+
* @returns Map<ActionId, ActionDefinition> 映射
|
|
68
|
+
*/
|
|
69
|
+
export declare function loadActions(projectRoot: string, _actionsDir?: string, options?: {
|
|
70
|
+
autoInstall?: boolean;
|
|
71
|
+
loader?: ModuleLoader;
|
|
72
|
+
}): Promise<Map<string, ActionDefinition>>;
|
|
73
|
+
/**
|
|
74
|
+
* 发现项目 playbooks 目录下的所有 Playbook Markdown 文档(.md)。
|
|
75
|
+
*/
|
|
76
|
+
export declare function discoverPlaybookFiles(projectRoot: string, playbooksDir?: string): string[];
|
|
77
|
+
/**
|
|
78
|
+
* 解析单个 Playbook Markdown 文件的内容与元数据。
|
|
79
|
+
* Playbook 规程正文为纯 Markdown,其元数据(id, description, actions)直接由调用方传入(源自 actiondock.json)。
|
|
80
|
+
*
|
|
81
|
+
* @param content 文件 Markdown 文本内容
|
|
82
|
+
* @param filePath 物理文件路径
|
|
83
|
+
* @param metadata Playbook 清单元数据
|
|
84
|
+
* @returns PlaybookDefinition 对象
|
|
85
|
+
*/
|
|
86
|
+
export declare function parsePlaybookContent(content: string, filePath: string, metadata?: Partial<PlaybookManifestEntry> & {
|
|
87
|
+
id?: string;
|
|
88
|
+
name?: string;
|
|
89
|
+
}): PlaybookDefinition;
|
|
90
|
+
/**
|
|
91
|
+
* 加载项目声明的 Playbook SOP 规程文档。
|
|
92
|
+
* 以 actiondock.json 中的 playbooks 声明作为唯一事实源。
|
|
93
|
+
*
|
|
94
|
+
* @param projectRoot 项目根目录
|
|
95
|
+
* @param _playbooksDir playbooks 子目录(向后兼容保留参数)
|
|
96
|
+
* @param customManifest 可选的显式清单对象(若未提供则从磁盘加载)
|
|
97
|
+
* @returns Map<PlaybookId, PlaybookDefinition> 映射
|
|
98
|
+
*/
|
|
99
|
+
export declare function loadPlaybooks(projectRoot: string, _playbooksDir?: string, customManifest?: ActionDockManifest | null): Map<string, PlaybookDefinition>;
|