@actiondock/cli 2.0.12 → 2.2.1
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 +41 -34
- package/bin/ad.js +28 -41
- package/dist/commands/action/create.d.ts +9 -1
- package/dist/commands/action/create.js +120 -0
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.js +144 -0
- package/dist/commands/build.d.ts +2 -1
- package/dist/commands/build.js +83 -0
- package/dist/commands/config/delete.d.ts +9 -0
- package/dist/commands/config/delete.js +52 -0
- package/dist/commands/config/env.d.ts +9 -0
- package/dist/commands/config/env.js +85 -0
- package/dist/commands/config/get.d.ts +9 -0
- package/dist/commands/config/get.js +120 -0
- package/dist/commands/config/index.d.ts +9 -0
- package/dist/commands/config/index.js +23 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.js +137 -0
- package/dist/commands/config/schema.d.ts +9 -0
- package/dist/commands/config/schema.js +121 -0
- package/dist/commands/config/set.d.ts +9 -0
- package/dist/commands/config/set.js +85 -0
- package/dist/commands/describe.d.ts +9 -0
- package/dist/commands/describe.js +68 -0
- package/dist/commands/doctor.d.ts +2 -1
- package/dist/commands/doctor.js +82 -0
- package/dist/commands/export.d.ts +2 -1
- package/dist/commands/export.js +212 -0
- package/dist/commands/generate.d.ts +9 -0
- package/dist/commands/generate.js +44 -0
- package/dist/commands/index.d.ts +31 -1
- package/dist/commands/index.js +111 -0
- package/dist/commands/info.d.ts +9 -2
- package/dist/commands/info.js +210 -0
- package/dist/commands/init.js +24 -0
- package/dist/commands/link.js +71 -0
- package/dist/commands/list.d.ts +9 -0
- package/dist/commands/list.js +77 -0
- package/dist/commands/mcp.d.ts +9 -2
- package/dist/commands/mcp.js +173 -0
- package/dist/commands/new.d.ts +9 -0
- package/dist/commands/new.js +33 -0
- package/dist/commands/pack.d.ts +3 -0
- package/dist/commands/pack.js +63 -0
- package/dist/commands/playbook.d.ts +7 -3
- package/dist/commands/playbook.js +433 -0
- package/dist/commands/profile.js +253 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.js +118 -0
- package/dist/commands/run.d.ts +13 -0
- package/dist/commands/run.js +146 -0
- package/dist/commands/runs.d.ts +9 -2
- package/dist/commands/runs.js +245 -0
- package/dist/commands/serve.d.ts +9 -2
- package/dist/commands/serve.js +135 -0
- package/dist/commands/state-list.d.ts +24 -0
- package/dist/commands/state-list.js +82 -0
- package/dist/commands/state.d.ts +9 -2
- package/dist/commands/state.js +310 -0
- package/dist/commands/test.js +44 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.js +106 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.js +103 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +41 -1000
- package/dist/prompt.d.ts +53 -0
- package/dist/prompt.js +192 -0
- package/dist/renderer.d.ts +197 -0
- package/dist/renderer.js +502 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/inspect.d.ts +23 -0
- package/dist/services/inspect.js +96 -0
- package/dist/standalone/index.d.ts +16 -0
- package/dist/standalone/index.js +22 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.js +9 -0
- package/dist/utils/bytes.d.ts +1 -1
- package/dist/utils/bytes.js +1 -0
- package/dist/utils/duration.js +1 -0
- package/dist/utils/filter.d.ts +1 -1
- package/dist/utils/filter.js +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/spawn.d.ts +27 -0
- package/dist/utils/spawn.js +35 -0
- package/dist/utils/target.d.ts +45 -0
- package/dist/utils/target.js +78 -0
- package/dist/utils/utils.d.ts +38 -0
- package/dist/utils/utils.js +111 -0
- package/package.json +10 -12
- package/dist/commands/action/index.d.ts +0 -16
- package/dist/commands/action/list.d.ts +0 -5
- package/dist/commands/action/run.d.ts +0 -4
- package/dist/commands/action/show.d.ts +0 -5
- package/dist/commands/action/sync.d.ts +0 -2
- package/dist/commands/action/validate.d.ts +0 -5
- package/dist/commands/action.d.ts +0 -1
- package/dist/commands/config.d.ts +0 -2
package/dist/renderer.js
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import { formatError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* 构造标准成功结果信封。
|
|
4
|
+
*
|
|
5
|
+
* @param data 业务数据载荷
|
|
6
|
+
* @param meta 附加元数据
|
|
7
|
+
*/
|
|
8
|
+
export function createSuccessEnvelope(data, meta) {
|
|
9
|
+
const result = {
|
|
10
|
+
ok: true,
|
|
11
|
+
data,
|
|
12
|
+
};
|
|
13
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
14
|
+
result.meta = meta;
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 构造标准失败结果信封。
|
|
20
|
+
*
|
|
21
|
+
* @param code 错误码
|
|
22
|
+
* @param message 错误描述信息
|
|
23
|
+
* @param details 附加错误细节
|
|
24
|
+
* @param meta 附加元数据
|
|
25
|
+
*/
|
|
26
|
+
export function createErrorEnvelope(code, message, details, meta) {
|
|
27
|
+
const result = {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: {
|
|
30
|
+
code,
|
|
31
|
+
message,
|
|
32
|
+
...(details !== undefined ? { details } : {}),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
36
|
+
result.meta = meta;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 序列化数据为格式化 JSON 字符串。
|
|
42
|
+
*
|
|
43
|
+
* @param data 待序列化数据
|
|
44
|
+
* @param pretty 是否美化格式
|
|
45
|
+
*/
|
|
46
|
+
export function formatJson(data, pretty = true) {
|
|
47
|
+
return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 标准输出写入辅助方法。
|
|
51
|
+
*/
|
|
52
|
+
export function writeStdout(message, context) {
|
|
53
|
+
if (context?.stdout) {
|
|
54
|
+
context.stdout(message);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 标准错误写入辅助方法。
|
|
62
|
+
*/
|
|
63
|
+
export function writeStderr(message, context) {
|
|
64
|
+
if (context?.stderr) {
|
|
65
|
+
context.stderr(message);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.error(message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 统一根据输出模式进行渲染输出。
|
|
73
|
+
*/
|
|
74
|
+
export function renderResult(data, options) {
|
|
75
|
+
const isJson = Boolean(options.json || options.envelope);
|
|
76
|
+
const useEnvelope = Boolean(options.envelope || (isJson && options.context?.defaultEnvelope));
|
|
77
|
+
if (isJson) {
|
|
78
|
+
if (useEnvelope) {
|
|
79
|
+
// 避免重复包装已有信封
|
|
80
|
+
if (typeof data === "object" && data !== null && "ok" in data) {
|
|
81
|
+
writeStdout(formatJson(data), options.context);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
writeStdout(formatJson(createSuccessEnvelope(data)), options.context);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
writeStdout(formatJson(data), options.context);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if (options.humanFormatter) {
|
|
93
|
+
writeStdout(options.humanFormatter(), options.context);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
writeStdout(typeof data === "string" ? data : formatJson(data), options.context);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 统一渲染异常输出。
|
|
102
|
+
*/
|
|
103
|
+
export function renderError(err, options) {
|
|
104
|
+
const formatted = formatError(err);
|
|
105
|
+
const isMachine = Boolean(options.json || options.envelope || options.context?.defaultEnvelope);
|
|
106
|
+
if (isMachine) {
|
|
107
|
+
const errorEnv = createErrorEnvelope(formatted.code, formatted.message, formatted.details);
|
|
108
|
+
writeStdout(formatJson(errorEnv), options.context);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
writeStderr(`Error: ${formatted.message}`, options.context);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 将工程详情信息转换为机器输出视图(剔除 Map 明细与定义字典)。
|
|
116
|
+
*/
|
|
117
|
+
export function projectDetailToJson(info) {
|
|
118
|
+
return {
|
|
119
|
+
id: info.id,
|
|
120
|
+
name: info.name || info.id,
|
|
121
|
+
version: info.version || "0.0.0",
|
|
122
|
+
description: info.description,
|
|
123
|
+
projectRoot: info.projectRoot,
|
|
124
|
+
actionsDir: info.actionsDir,
|
|
125
|
+
playbooksDir: info.playbooksDir,
|
|
126
|
+
actionsCount: info.actionsCount,
|
|
127
|
+
playbooksCount: info.playbooksCount,
|
|
128
|
+
actions: info.actions,
|
|
129
|
+
playbooks: info.playbooks,
|
|
130
|
+
configDeclared: info.configDeclared,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 格式化渲染单个项目的元数据与详情信息。
|
|
135
|
+
*/
|
|
136
|
+
export function renderProjectDetail(info) {
|
|
137
|
+
const lines = [];
|
|
138
|
+
lines.push(`ActionDock Project: ${info.name} (${info.id})`);
|
|
139
|
+
lines.push(`Version: ${info.version}`);
|
|
140
|
+
if (info.description) {
|
|
141
|
+
lines.push(`Description: ${info.description}`);
|
|
142
|
+
}
|
|
143
|
+
lines.push(`Root: ${info.projectRoot}`);
|
|
144
|
+
lines.push(`\nActions (${info.actionsCount}):`);
|
|
145
|
+
if (info.actionsMap) {
|
|
146
|
+
for (const [id, act] of info.actionsMap.entries()) {
|
|
147
|
+
lines.push(` - ${id.padEnd(28)} ${act.description || ""}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
for (const actId of info.actions) {
|
|
152
|
+
lines.push(` - ${actId}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
lines.push(`\nPlaybooks (${info.playbooksCount}):`);
|
|
156
|
+
if (info.playbooksMap) {
|
|
157
|
+
for (const [id, pb] of info.playbooksMap.entries()) {
|
|
158
|
+
lines.push(` - ${id.padEnd(28)} ${pb.description || ""}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
for (const pbId of info.playbooks) {
|
|
163
|
+
lines.push(` - ${pbId}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (info.configDeclared.length > 0) {
|
|
167
|
+
lines.push(`\nDeclared Config Keys:`);
|
|
168
|
+
for (const k of info.configDeclared) {
|
|
169
|
+
const item = info.configDef?.[k];
|
|
170
|
+
const isSec = item?.secret ? " [secret]" : "";
|
|
171
|
+
const def = item?.default !== undefined ? ` (default: ${JSON.stringify(item.default)})` : "";
|
|
172
|
+
lines.push(` - ${k.padEnd(24)} ${item?.description || ""}${def}${isSec}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 格式化渲染已链接的多个 Package 摘要信息。
|
|
179
|
+
*/
|
|
180
|
+
export function renderAggregatedPackages(packages, options) {
|
|
181
|
+
const lines = [];
|
|
182
|
+
if (options?.header) {
|
|
183
|
+
lines.push(options.header);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
lines.push(`ActionDock Linked Packages (${packages.length}):\n`);
|
|
187
|
+
}
|
|
188
|
+
for (const p of packages) {
|
|
189
|
+
lines.push(`- ${p.name} (${p.id}) v${p.version}`);
|
|
190
|
+
lines.push(` Path: ${p.path}`);
|
|
191
|
+
if (p.description) {
|
|
192
|
+
lines.push(` Desc: ${p.description}`);
|
|
193
|
+
}
|
|
194
|
+
lines.push(` Actions (${p.actionsCount}): ${p.actions.join(", ") || "(none)"}`);
|
|
195
|
+
lines.push(` Playbooks (${p.playbooksCount}): ${p.playbooks.join(", ") || "(none)"}`);
|
|
196
|
+
lines.push("");
|
|
197
|
+
}
|
|
198
|
+
if (options?.showTip !== false) {
|
|
199
|
+
lines.push("Tip: Run 'ad info <package-id>' to view detailed package configuration and schema.");
|
|
200
|
+
}
|
|
201
|
+
return lines.join("\n");
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 格式化渲染注册表层级树结构。
|
|
205
|
+
*/
|
|
206
|
+
export function renderRegistryTree(status) {
|
|
207
|
+
const lines = [];
|
|
208
|
+
const workspaces = status.workspaces || [];
|
|
209
|
+
const packages = status.packages || [];
|
|
210
|
+
const hasWorkspaces = workspaces.length > 0;
|
|
211
|
+
const hasPackages = packages.length > 0;
|
|
212
|
+
if (!hasWorkspaces && !hasPackages) {
|
|
213
|
+
lines.push("[INFO] No ActionDock packages or workspaces currently linked.");
|
|
214
|
+
lines.push(" Run 'ad link' inside an Action package or workspace to register it.");
|
|
215
|
+
return lines.join("\n");
|
|
216
|
+
}
|
|
217
|
+
lines.push("[ActionDock Workspace & Package Tree]\n");
|
|
218
|
+
if (hasWorkspaces) {
|
|
219
|
+
lines.push("Workspaces:");
|
|
220
|
+
for (const ws of workspaces) {
|
|
221
|
+
const tag = ws.status === "active" ? "[OK]" : "[STALE]";
|
|
222
|
+
lines.push(` ${tag} ${ws.path} (${ws.packagesCount} package${ws.packagesCount === 1 ? "" : "s"})`);
|
|
223
|
+
if (ws.children && ws.children.length > 0) {
|
|
224
|
+
const children = ws.children;
|
|
225
|
+
children.forEach((child, idx) => {
|
|
226
|
+
const isLast = idx === children.length - 1;
|
|
227
|
+
const prefix = isLast ? " +-- " : " |-- ";
|
|
228
|
+
lines.push(`${prefix}${child.id} (v${child.version}) -> ${child.path}`);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (hasPackages) {
|
|
234
|
+
if (hasWorkspaces)
|
|
235
|
+
lines.push("");
|
|
236
|
+
lines.push("Standalone Packages:");
|
|
237
|
+
for (const pkg of packages) {
|
|
238
|
+
const tag = pkg.status === "active" ? "[OK]" : "[STALE]";
|
|
239
|
+
lines.push(` ${tag} ${pkg.id} (v${pkg.version || "unknown"}) -> ${pkg.path}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const totalActive = status.totalPackagesCount ?? packages.length;
|
|
243
|
+
lines.push(`\n[Summary] Total: ${totalActive} active package(s), ${workspaces.length} workspace(s)`);
|
|
244
|
+
if (status.staleCount && status.staleCount > 0) {
|
|
245
|
+
lines.push(`[WARN] ${status.staleCount} stale entry/entries detected. Run 'ad unlink --prune' to clean up.`);
|
|
246
|
+
}
|
|
247
|
+
return lines.join("\n");
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 格式化渲染 Action 列表。
|
|
251
|
+
*/
|
|
252
|
+
export function renderActionList(items, title = "Actions", isFallback = false, intent) {
|
|
253
|
+
const lines = [];
|
|
254
|
+
lines.push(`${title}:\n`);
|
|
255
|
+
if (isFallback && intent) {
|
|
256
|
+
lines.push(`(No actions matched intent '${intent}', showing all actions)\n`);
|
|
257
|
+
}
|
|
258
|
+
if (items.length === 0) {
|
|
259
|
+
lines.push(" (no actions found)");
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
for (const a of items) {
|
|
263
|
+
lines.push(` - ${a.id.padEnd(28)} ${a.description}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return lines.join("\n");
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 格式化渲染 Action 详情。
|
|
270
|
+
*/
|
|
271
|
+
export function renderActionDetail(action) {
|
|
272
|
+
const lines = [];
|
|
273
|
+
lines.push(`Action: ${action.id}`);
|
|
274
|
+
if (action.packageId) {
|
|
275
|
+
const rootDesc = action.projectRoot ? ` (${action.projectRoot})` : "";
|
|
276
|
+
lines.push(`Package: ${action.packageId}${rootDesc}`);
|
|
277
|
+
}
|
|
278
|
+
if (action.description) {
|
|
279
|
+
lines.push(`Description: ${action.description}`);
|
|
280
|
+
}
|
|
281
|
+
if (action.inputSchema) {
|
|
282
|
+
lines.push("\nInput Schema:");
|
|
283
|
+
lines.push(JSON.stringify(action.inputSchema, null, 2));
|
|
284
|
+
}
|
|
285
|
+
if (action.outputSchema) {
|
|
286
|
+
lines.push("\nOutput Schema:");
|
|
287
|
+
lines.push(JSON.stringify(action.outputSchema, null, 2));
|
|
288
|
+
}
|
|
289
|
+
return lines.join("\n");
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* 格式化渲染 Action 校验结果。
|
|
293
|
+
*/
|
|
294
|
+
export function renderActionValidation(results) {
|
|
295
|
+
const lines = [];
|
|
296
|
+
for (const r of results) {
|
|
297
|
+
if (r.valid) {
|
|
298
|
+
lines.push(`[OK] ${r.id}: Valid`);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
lines.push(`[FAIL] ${r.id}: ${r.errors.join(", ")}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* 格式化渲染 Playbook 列表。
|
|
308
|
+
*/
|
|
309
|
+
export function renderPlaybookList(items, title = "Playbooks", isFallback = false, intent) {
|
|
310
|
+
const lines = [];
|
|
311
|
+
lines.push(`${title}:\n`);
|
|
312
|
+
if (isFallback && intent) {
|
|
313
|
+
lines.push(`(No playbooks matched intent '${intent}', showing all playbooks)\n`);
|
|
314
|
+
}
|
|
315
|
+
if (items.length === 0) {
|
|
316
|
+
lines.push(" (no playbooks found)");
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
for (const p of items) {
|
|
320
|
+
const pkgDesc = p.packageId ? ` (Package: ${p.packageId})` : "";
|
|
321
|
+
lines.push(` - ${p.id.padEnd(26)} ${p.description}${pkgDesc}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return lines.join("\n");
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* 格式化渲染 Playbook 详情。
|
|
328
|
+
*/
|
|
329
|
+
export function renderPlaybookDetail(pb) {
|
|
330
|
+
const lines = [];
|
|
331
|
+
const pkgDesc = pb.packageId ? ` (Package: ${pb.packageId})` : "";
|
|
332
|
+
lines.push(`Playbook: ${pb.id}${pkgDesc}`);
|
|
333
|
+
if (pb.description)
|
|
334
|
+
lines.push(`Description: ${pb.description}`);
|
|
335
|
+
if (pb.actions && pb.actions.length > 0) {
|
|
336
|
+
lines.push(`Actions: ${pb.actions.join(", ")}`);
|
|
337
|
+
}
|
|
338
|
+
if (pb.filePath)
|
|
339
|
+
lines.push(`File: ${pb.filePath}\n`);
|
|
340
|
+
if (pb.content) {
|
|
341
|
+
lines.push("--- Content ---");
|
|
342
|
+
lines.push(pb.content);
|
|
343
|
+
}
|
|
344
|
+
return lines.join("\n");
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 格式化渲染配置项列表。
|
|
348
|
+
* 掩码决策收敛在命令层(传入的 value 已完成是否打码处理),
|
|
349
|
+
* 此处仅负责值的字符串格式化:字符串原样输出,其余类型 JSON 序列化。
|
|
350
|
+
*/
|
|
351
|
+
export function renderConfigList(items, scopeLabel = "Global Scope", isFallback = false, intent) {
|
|
352
|
+
const lines = [];
|
|
353
|
+
lines.push(`Configurations [${scopeLabel}]:\n`);
|
|
354
|
+
if (isFallback && intent) {
|
|
355
|
+
lines.push(`(No config entries matched intent '${intent}', showing all entries)\n`);
|
|
356
|
+
}
|
|
357
|
+
if (items.length === 0) {
|
|
358
|
+
lines.push(" (No configuration entries found)");
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
for (const item of items) {
|
|
362
|
+
const valStr = formatConfigValue(item.value);
|
|
363
|
+
const secretBadge = item.secret ? ", secret" : "";
|
|
364
|
+
lines.push(` - ${item.key.padEnd(24)} = ${valStr} (${item.source}${secretBadge})`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return lines.join("\n");
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 格式化配置值:字符串原样输出,其余类型 JSON 序列化。
|
|
371
|
+
*/
|
|
372
|
+
function formatConfigValue(value) {
|
|
373
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* 格式化渲染配置依赖规范检查。
|
|
377
|
+
*/
|
|
378
|
+
export function renderConfigSchema(items, packageId, root) {
|
|
379
|
+
const lines = [];
|
|
380
|
+
lines.push(`Configuration Requirements for ${packageId} (${root}):\n`);
|
|
381
|
+
if (items.length === 0) {
|
|
382
|
+
lines.push(" (No configuration dependencies declared for this package)");
|
|
383
|
+
return lines.join("\n");
|
|
384
|
+
}
|
|
385
|
+
lines.push(` ${"KEY".padEnd(24)} ${"STATUS".padEnd(12)} ${"SOURCE".padEnd(10)} ${"SECRET".padEnd(8)} DESCRIPTION`);
|
|
386
|
+
lines.push(" " + "-".repeat(85));
|
|
387
|
+
const missing = [];
|
|
388
|
+
for (const item of items) {
|
|
389
|
+
const statusLabel = item.status === "SET" ? "[SET]" : item.status === "DEFAULT" ? "[DEFAULT]" : "[MISSING]";
|
|
390
|
+
const secretLabel = item.secret ? "yes" : "no";
|
|
391
|
+
lines.push(` ${item.key.padEnd(24)} ${statusLabel.padEnd(12)} ${item.source.padEnd(10)} ${secretLabel.padEnd(8)} ${item.description}`);
|
|
392
|
+
if (item.status === "MISSING") {
|
|
393
|
+
missing.push(item.key);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (missing.length > 0) {
|
|
397
|
+
lines.push(`\n[WARNING] ${missing.length} required config(s) not set:`);
|
|
398
|
+
for (const m of missing) {
|
|
399
|
+
lines.push(` - ${m}: Run 'ad config set ${m} <value>' to configure.`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
lines.push("\n[OK] All configuration dependencies are satisfied.");
|
|
404
|
+
}
|
|
405
|
+
return lines.join("\n");
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* 格式化渲染环境变量满足率诊断。
|
|
409
|
+
*/
|
|
410
|
+
export function renderConfigEnv(checks, packageId) {
|
|
411
|
+
const lines = [];
|
|
412
|
+
const targetDesc = packageId ? `for Package '${packageId}'` : "Global";
|
|
413
|
+
lines.push(`Environment Variable Satisfaction Diagnostics ${targetDesc}:\n`);
|
|
414
|
+
if (checks.length === 0) {
|
|
415
|
+
lines.push(" (No configuration dependencies declared)");
|
|
416
|
+
return lines.join("\n");
|
|
417
|
+
}
|
|
418
|
+
lines.push(` ${"KEY".padEnd(24)} ${"SATISFIED".padEnd(12)} ${"REQUIRED".padEnd(10)} ${"MATCHED ENV".padEnd(28)} SECRET`);
|
|
419
|
+
lines.push(" " + "-".repeat(85));
|
|
420
|
+
for (const c of checks) {
|
|
421
|
+
const satLabel = c.satisfied ? "[OK]" : "[MISSING]";
|
|
422
|
+
const reqLabel = c.required ? "yes" : "no";
|
|
423
|
+
const matched = c.matchedEnv || (c.hasDefault ? "(using default)" : "-");
|
|
424
|
+
const secLabel = c.secret ? "yes" : "no";
|
|
425
|
+
lines.push(` ${c.key.padEnd(24)} ${satLabel.padEnd(12)} ${reqLabel.padEnd(10)} ${matched.padEnd(28)} ${secLabel}`);
|
|
426
|
+
}
|
|
427
|
+
const missingRequired = checks.filter((c) => c.required && !c.satisfied);
|
|
428
|
+
if (missingRequired.length > 0) {
|
|
429
|
+
lines.push(`\n[WARNING] ${missingRequired.length} required environment variable(s) not satisfied:`);
|
|
430
|
+
for (const m of missingRequired) {
|
|
431
|
+
lines.push(` - ${m.key}: Please export ${m.key}=... in your environment.`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
lines.push("\n[OK] All declared configuration dependencies are satisfied by environment or defaults.");
|
|
436
|
+
}
|
|
437
|
+
return lines.join("\n");
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* 格式化渲染状态键列表。
|
|
441
|
+
*/
|
|
442
|
+
export function renderStateList(keys, scopeLabel = "Current State", isFallback = false, intent) {
|
|
443
|
+
const lines = [];
|
|
444
|
+
lines.push(`State keys for ${scopeLabel} (${keys.length}):\n`);
|
|
445
|
+
if (isFallback && intent) {
|
|
446
|
+
lines.push(`(No state keys matched intent '${intent}', showing all keys)\n`);
|
|
447
|
+
}
|
|
448
|
+
if (keys.length === 0) {
|
|
449
|
+
lines.push(" (no state keys found)");
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
for (const k of keys) {
|
|
453
|
+
lines.push(` - ${k}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return lines.join("\n");
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* 格式化渲染执行记录列表。
|
|
460
|
+
*/
|
|
461
|
+
export function renderRunsList(items, scopeLabel = "Execution Runs", isFallback = false, intent) {
|
|
462
|
+
const lines = [];
|
|
463
|
+
lines.push(`${scopeLabel} (${items.length}):\n`);
|
|
464
|
+
if (isFallback && intent) {
|
|
465
|
+
lines.push(`(No runs matched intent '${intent}', showing all runs)\n`);
|
|
466
|
+
}
|
|
467
|
+
lines.push(` ${"RUN ID".padEnd(38)} ${"PACKAGE".padEnd(18)} ${"ACTION".padEnd(22)} ${"STATUS".padEnd(10)} STARTED`);
|
|
468
|
+
lines.push(" " + "-".repeat(105));
|
|
469
|
+
for (const r of items) {
|
|
470
|
+
const time = (r.startedAt || "").replace("T", " ").slice(0, 19);
|
|
471
|
+
const pkg = (r.packageId || "").padEnd(18);
|
|
472
|
+
lines.push(` ${r.id.padEnd(38)} ${pkg} ${r.actionId.padEnd(22)} ${r.status.padEnd(10)} ${time}`);
|
|
473
|
+
}
|
|
474
|
+
return lines.join("\n");
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* 格式化渲染单次执行记录详情。
|
|
478
|
+
*/
|
|
479
|
+
export function renderRunDetail(run) {
|
|
480
|
+
const lines = [];
|
|
481
|
+
lines.push(`Run: ${run.id}`);
|
|
482
|
+
lines.push(`Action: ${run.actionId}`);
|
|
483
|
+
if (run.packageId)
|
|
484
|
+
lines.push(`Package: ${run.packageId}`);
|
|
485
|
+
lines.push(`Status: ${run.status}`);
|
|
486
|
+
if (run.parentRunId)
|
|
487
|
+
lines.push(`Parent Run: ${run.parentRunId}`);
|
|
488
|
+
lines.push(`Started: ${run.startedAt}`);
|
|
489
|
+
if (run.finishedAt)
|
|
490
|
+
lines.push(`Finished: ${run.finishedAt}`);
|
|
491
|
+
lines.push("\nInput:");
|
|
492
|
+
lines.push(JSON.stringify(run.input, null, 2));
|
|
493
|
+
if (run.output !== undefined) {
|
|
494
|
+
lines.push("\nOutput:");
|
|
495
|
+
lines.push(JSON.stringify(run.output, null, 2));
|
|
496
|
+
}
|
|
497
|
+
if (run.error) {
|
|
498
|
+
lines.push("\nError:");
|
|
499
|
+
lines.push(JSON.stringify(run.error, null, 2));
|
|
500
|
+
}
|
|
501
|
+
return lines.join("\n");
|
|
502
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./inspect.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./inspect.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AggregatedPackage, CliContext, ProjectDetailInfo } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 装配单个工程的详情自省信息(清单、动作映射与 Playbook 映射)。
|
|
4
|
+
*
|
|
5
|
+
* @param root 工程根目录
|
|
6
|
+
*/
|
|
7
|
+
export declare function getProjectDetailInfo(root: string): Promise<ProjectDetailInfo>;
|
|
8
|
+
/**
|
|
9
|
+
* 装配单个包的摘要聚合信息(不含动作与 Playbook 明细映射)。
|
|
10
|
+
*
|
|
11
|
+
* @param root 包根目录
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPackageSummary(root: string): AggregatedPackage;
|
|
14
|
+
/**
|
|
15
|
+
* 扫描本地候选包集合(当前工程根目录优先,叠加全局已链接包,按物理路径去重)。
|
|
16
|
+
* 清单损坏或磁盘失效的候选项跳过,不影响其余条目聚合。
|
|
17
|
+
*
|
|
18
|
+
* @param context CLI 上下文(提供 customHome 定位全局注册表)
|
|
19
|
+
*/
|
|
20
|
+
export declare function scanLocalAggregatedPackages(context?: CliContext): {
|
|
21
|
+
currentRoot: string | null;
|
|
22
|
+
aggregated: AggregatedPackage[];
|
|
23
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { findProjectRoot, listLinkedPackages, loadManifest, loadPlaybooks, loadProjectConfig, } from "@actiondock/core";
|
|
3
|
+
/**
|
|
4
|
+
* 装配单个工程的详情自省信息(清单、动作映射与 Playbook 映射)。
|
|
5
|
+
*
|
|
6
|
+
* @param root 工程根目录
|
|
7
|
+
*/
|
|
8
|
+
export async function getProjectDetailInfo(root) {
|
|
9
|
+
const config = loadProjectConfig(root);
|
|
10
|
+
const manifest = loadManifest(root);
|
|
11
|
+
const actionsMap = new Map();
|
|
12
|
+
if (manifest?.actions) {
|
|
13
|
+
for (const [id, item] of Object.entries(manifest.actions)) {
|
|
14
|
+
actionsMap.set(id, {
|
|
15
|
+
id,
|
|
16
|
+
description: item.description,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const playbooks = loadPlaybooks(root, config.playbooksDir);
|
|
21
|
+
return {
|
|
22
|
+
id: config.id,
|
|
23
|
+
name: config.name || config.id,
|
|
24
|
+
version: config.version || "0.0.0",
|
|
25
|
+
description: config.description,
|
|
26
|
+
projectRoot: root,
|
|
27
|
+
actionsDir: config.actionsDir || "actions",
|
|
28
|
+
playbooksDir: config.playbooksDir || "playbooks",
|
|
29
|
+
actionsCount: actionsMap.size,
|
|
30
|
+
playbooksCount: playbooks.size,
|
|
31
|
+
actions: Array.from(actionsMap.keys()),
|
|
32
|
+
playbooks: Array.from(playbooks.keys()),
|
|
33
|
+
configDeclared: config.config ? Object.keys(config.config) : [],
|
|
34
|
+
configDef: config.config,
|
|
35
|
+
actionsMap,
|
|
36
|
+
playbooksMap: playbooks,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 装配单个包的摘要聚合信息(不含动作与 Playbook 明细映射)。
|
|
41
|
+
*
|
|
42
|
+
* @param root 包根目录
|
|
43
|
+
*/
|
|
44
|
+
export function getPackageSummary(root) {
|
|
45
|
+
const config = loadProjectConfig(root);
|
|
46
|
+
const manifest = loadManifest(root);
|
|
47
|
+
const manifestActionIds = manifest?.actions ? Object.keys(manifest.actions) : [];
|
|
48
|
+
const playbooks = loadPlaybooks(root, config.playbooksDir);
|
|
49
|
+
return {
|
|
50
|
+
id: config.id,
|
|
51
|
+
name: config.name || config.id,
|
|
52
|
+
version: config.version || "0.0.0",
|
|
53
|
+
description: config.description,
|
|
54
|
+
path: root,
|
|
55
|
+
actionsCount: manifestActionIds.length,
|
|
56
|
+
playbooksCount: playbooks.size,
|
|
57
|
+
actions: manifestActionIds,
|
|
58
|
+
playbooks: Array.from(playbooks.keys()),
|
|
59
|
+
configDeclared: config.config ? Object.keys(config.config) : [],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 扫描本地候选包集合(当前工程根目录优先,叠加全局已链接包,按物理路径去重)。
|
|
64
|
+
* 清单损坏或磁盘失效的候选项跳过,不影响其余条目聚合。
|
|
65
|
+
*
|
|
66
|
+
* @param context CLI 上下文(提供 customHome 定位全局注册表)
|
|
67
|
+
*/
|
|
68
|
+
export function scanLocalAggregatedPackages(context) {
|
|
69
|
+
const currentRoot = findProjectRoot();
|
|
70
|
+
const linkedList = listLinkedPackages(context?.customHome);
|
|
71
|
+
const aggregated = [];
|
|
72
|
+
const seenPaths = new Set();
|
|
73
|
+
if (currentRoot) {
|
|
74
|
+
try {
|
|
75
|
+
aggregated.push(getPackageSummary(currentRoot));
|
|
76
|
+
seenPaths.add(currentRoot);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// 忽略异常工程根目录(清单损坏)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const pkg of linkedList) {
|
|
83
|
+
if (!existsSync(pkg.path))
|
|
84
|
+
continue;
|
|
85
|
+
if (seenPaths.has(pkg.path))
|
|
86
|
+
continue;
|
|
87
|
+
try {
|
|
88
|
+
aggregated.push(getPackageSummary(pkg.path));
|
|
89
|
+
seenPaths.add(pkg.path);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// 忽略失效链接(清单损坏或磁盘异常)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { currentRoot, aggregated };
|
|
96
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StandaloneDispatcher as CoreStandaloneDispatcher } from "@actiondock/core";
|
|
2
|
+
import type { StandaloneOptions } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 独立二进制轻量参数解析分发器(委托 Core 统一实现,消除重复逻辑)。
|
|
5
|
+
*/
|
|
6
|
+
export declare class StandaloneDispatcher extends CoreStandaloneDispatcher {
|
|
7
|
+
constructor(options: StandaloneOptions);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 运行独立二进制参数解析分发器并返回退出状态码。
|
|
11
|
+
*/
|
|
12
|
+
export declare function runStandaloneCli(argv: string[] | undefined, options: StandaloneOptions): Promise<number>;
|
|
13
|
+
/**
|
|
14
|
+
* 创建独立二进制运行时分发器实例。
|
|
15
|
+
*/
|
|
16
|
+
export declare function createStandaloneDispatcher(options: StandaloneOptions): StandaloneDispatcher;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { StandaloneDispatcher as CoreStandaloneDispatcher, } from "@actiondock/core";
|
|
2
|
+
/**
|
|
3
|
+
* 独立二进制轻量参数解析分发器(委托 Core 统一实现,消除重复逻辑)。
|
|
4
|
+
*/
|
|
5
|
+
export class StandaloneDispatcher extends CoreStandaloneDispatcher {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 运行独立二进制参数解析分发器并返回退出状态码。
|
|
12
|
+
*/
|
|
13
|
+
export async function runStandaloneCli(argv = process.argv.slice(2), options) {
|
|
14
|
+
const dispatcher = new StandaloneDispatcher(options);
|
|
15
|
+
return dispatcher.dispatch(argv);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 创建独立二进制运行时分发器实例。
|
|
19
|
+
*/
|
|
20
|
+
export function createStandaloneDispatcher(options) {
|
|
21
|
+
return new StandaloneDispatcher(options);
|
|
22
|
+
}
|