@actiondock/cli 2.15.0 → 2.16.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/dist/commands/config/delete.js +19 -8
- package/dist/commands/config/env.js +2 -3
- package/dist/commands/config/get.js +17 -10
- package/dist/commands/config/list.js +16 -10
- package/dist/commands/config/schema.js +6 -7
- package/dist/commands/config/set.js +34 -12
- package/dist/commands/describe.js +9 -6
- package/dist/commands/info.js +18 -97
- package/dist/commands/list.js +16 -16
- package/dist/commands/playbook.js +105 -148
- package/dist/commands/run.js +20 -7
- package/dist/commands/state.js +2 -19
- package/dist/renderers/project.d.ts +0 -4
- package/dist/renderers/project.js +0 -16
- package/dist/services/inspect.d.ts +1 -14
- package/dist/services/inspect.js +12 -54
- package/dist/utils/target.d.ts +4 -94
- package/dist/utils/target.js +26 -304
- package/package.json +5 -5
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
|
-
import { assertPathWithinRoot, loadManifest, loadPlaybooks, saveManifest, filterWithFallbackInfo, } from "@actiondock/core/project";
|
|
4
|
-
import { DefaultActionCatalog, resolveAction, resolvePlaybook, } from "@actiondock/core/graph";
|
|
3
|
+
import { assertPathWithinRoot, loadActions, loadManifest, loadPlaybooks, saveManifest, filterWithFallbackInfo, } from "@actiondock/core/project";
|
|
4
|
+
import { DefaultActionCatalog, PackageGraphBuilder, resolveAction, resolvePlaybook, } from "@actiondock/core/graph";
|
|
5
5
|
import { fetchRemotePlaybooks, fetchRemotePlaybookShow, } from "@actiondock/core/profile";
|
|
6
6
|
import { loadProjectConfig, } from "@actiondock/core";
|
|
7
7
|
import { listLinkedPackages, } from "@actiondock/core/registry";
|
|
8
8
|
import { ArgumentError, CliError, ExecutionError, NO_PROJECT_NO_LINKED_MESSAGE, wrapAsExecutionError, } from "../errors.js";
|
|
9
|
-
import { renderPlaybookDetail, renderPlaybookList, renderResult,
|
|
10
|
-
import { applyTargetOptions,
|
|
9
|
+
import { renderPlaybookDetail, renderPlaybookList, renderResult, writeStdout, } from "../renderer.js";
|
|
10
|
+
import { applyTargetOptions, getEffectiveOptions, remoteTargetSuffix, requirePackageRoot, resolveFallbackStrategy, resolveIntent, resolveLocalPackageRoot, resolveTargetFromOptions, } from "../utils/index.js";
|
|
11
11
|
/**
|
|
12
12
|
* 注册 Playbook 命令集合(list, show, validate, create)。
|
|
13
13
|
*
|
|
@@ -34,15 +34,14 @@ export function registerPlaybookCommands(program, context) {
|
|
|
34
34
|
const hints = [
|
|
35
35
|
"Tip: Run 'ad playbook show <id>' to inspect procedure steps before execution.",
|
|
36
36
|
];
|
|
37
|
-
// 1.
|
|
38
|
-
const target =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const remotePbs = await fetchRemotePlaybooks(target.resolved.serverUrl, target.resolved.token, {
|
|
37
|
+
// 1. 远端服务分支
|
|
38
|
+
const target = resolveTargetFromOptions(options, context);
|
|
39
|
+
if (target.type === "remote") {
|
|
40
|
+
const remotePbs = await fetchRemotePlaybooks(target.serverUrl, target.token, {
|
|
42
41
|
intent: effectiveIntent,
|
|
43
42
|
package: options.package,
|
|
44
43
|
allowInsecureHttp: Boolean(options.allowInsecureHttp),
|
|
45
|
-
insecure: target.
|
|
44
|
+
insecure: target.insecure,
|
|
46
45
|
});
|
|
47
46
|
if (isMachine) {
|
|
48
47
|
renderResult({ items: remotePbs, hints }, { json: options.json, context });
|
|
@@ -50,44 +49,24 @@ export function registerPlaybookCommands(program, context) {
|
|
|
50
49
|
}
|
|
51
50
|
renderResult(remotePbs, {
|
|
52
51
|
json: options.json,
|
|
53
|
-
humanFormatter: () => renderPlaybookList(remotePbs, `Playbooks ${remoteTargetSuffix(target
|
|
52
|
+
humanFormatter: () => renderPlaybookList(remotePbs, `Playbooks ${remoteTargetSuffix(target)}`, false, effectiveIntent),
|
|
54
53
|
context,
|
|
55
54
|
});
|
|
56
55
|
return;
|
|
57
56
|
}
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
title = isComposite
|
|
75
|
-
? `Playbooks in ${options.package || target.localSkill.root}`
|
|
76
|
-
: `Playbooks in ${target.localSkill.packages[0].packageId} (${target.localSkill.packages[0].packageRoot})`;
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
const config = loadProjectConfig(target.targetPackageRoot);
|
|
80
|
-
const playbooks = loadPlaybooks(target.targetPackageRoot, config.playbooksDir, config);
|
|
81
|
-
for (const pb of playbooks.values()) {
|
|
82
|
-
rawList.push({
|
|
83
|
-
id: pb.id,
|
|
84
|
-
description: pb.description,
|
|
85
|
-
packageId: config.id,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
title = `Playbooks in ${config.id} (${target.targetPackageRoot})`;
|
|
89
|
-
}
|
|
90
|
-
const filterRes = filterWithFallbackInfo(rawList, effectiveIntent, [(p) => p.id, (p) => p.description || ""], shouldFallback);
|
|
57
|
+
// 2. 本地工程模式
|
|
58
|
+
const targetRoot = options.package
|
|
59
|
+
? requirePackageRoot(options.package).root
|
|
60
|
+
: resolveLocalPackageRoot();
|
|
61
|
+
if (targetRoot) {
|
|
62
|
+
const config = loadProjectConfig(targetRoot);
|
|
63
|
+
const playbooks = loadPlaybooks(targetRoot, config.playbooksDir);
|
|
64
|
+
const rawList = Array.from(playbooks.values()).map((pb) => ({
|
|
65
|
+
id: pb.id,
|
|
66
|
+
description: pb.description,
|
|
67
|
+
packageId: config.id,
|
|
68
|
+
}));
|
|
69
|
+
const filterRes = filterWithFallbackInfo(rawList, effectiveIntent, [(p) => p.id, (p) => p.description], shouldFallback);
|
|
91
70
|
if (isMachine) {
|
|
92
71
|
if (filterRes.isFallback) {
|
|
93
72
|
renderResult({ items: filterRes.items, isFallback: true, matchedCount: 0, hints }, { json: options.json, context });
|
|
@@ -102,7 +81,7 @@ export function registerPlaybookCommands(program, context) {
|
|
|
102
81
|
}
|
|
103
82
|
renderResult(filterRes.items, {
|
|
104
83
|
json: options.json,
|
|
105
|
-
humanFormatter: () => renderPlaybookList(filterRes.items,
|
|
84
|
+
humanFormatter: () => renderPlaybookList(filterRes.items, `Playbooks in ${config.id} (${targetRoot})`, filterRes.isFallback, effectiveIntent),
|
|
106
85
|
context,
|
|
107
86
|
});
|
|
108
87
|
return;
|
|
@@ -123,22 +102,25 @@ export function registerPlaybookCommands(program, context) {
|
|
|
123
102
|
}
|
|
124
103
|
const aggregated = [];
|
|
125
104
|
for (const pkg of linkedList) {
|
|
126
|
-
if (!existsSync(pkg.path))
|
|
127
|
-
writeStderr(`Skipping inaccessible linked package '${pkg.id}' at '${pkg.path}'`, context);
|
|
105
|
+
if (!existsSync(pkg.path))
|
|
128
106
|
continue;
|
|
107
|
+
try {
|
|
108
|
+
const config = loadProjectConfig(pkg.path);
|
|
109
|
+
const pbs = loadPlaybooks(pkg.path, config.playbooksDir);
|
|
110
|
+
const list = Array.from(pbs.values()).map((p) => ({
|
|
111
|
+
id: p.id,
|
|
112
|
+
description: p.description,
|
|
113
|
+
}));
|
|
114
|
+
aggregated.push({
|
|
115
|
+
packageId: pkg.id,
|
|
116
|
+
packageName: pkg.name,
|
|
117
|
+
path: pkg.path,
|
|
118
|
+
playbooks: list,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// 单个链接包清单损坏或 Playbook 加载失败时跳过,继续聚合其余包
|
|
129
123
|
}
|
|
130
|
-
const config = loadProjectConfig(pkg.path);
|
|
131
|
-
const pbs = loadPlaybooks(pkg.path, config.playbooksDir, config);
|
|
132
|
-
const list = Array.from(pbs.values()).map((p) => ({
|
|
133
|
-
id: p.id,
|
|
134
|
-
description: p.description,
|
|
135
|
-
}));
|
|
136
|
-
aggregated.push({
|
|
137
|
-
packageId: pkg.id,
|
|
138
|
-
packageName: pkg.name,
|
|
139
|
-
path: pkg.path,
|
|
140
|
-
playbooks: list,
|
|
141
|
-
});
|
|
142
124
|
}
|
|
143
125
|
let filteredPackages = [];
|
|
144
126
|
let isFallback = false;
|
|
@@ -201,14 +183,13 @@ export function registerPlaybookCommands(program, context) {
|
|
|
201
183
|
if (!id) {
|
|
202
184
|
throw new ArgumentError("Playbook ID is required for show");
|
|
203
185
|
}
|
|
204
|
-
// 1.
|
|
205
|
-
const target =
|
|
206
|
-
|
|
207
|
-
if (target.isRemote) {
|
|
186
|
+
// 1. 远端服务分支
|
|
187
|
+
const target = resolveTargetFromOptions(options, context);
|
|
188
|
+
if (target.type === "remote") {
|
|
208
189
|
try {
|
|
209
|
-
const detail = await fetchRemotePlaybookShow(target.
|
|
190
|
+
const detail = await fetchRemotePlaybookShow(target.serverUrl, id, target.token, {
|
|
210
191
|
allowInsecureHttp: Boolean(options.allowInsecureHttp),
|
|
211
|
-
insecure: target.
|
|
192
|
+
insecure: target.insecure,
|
|
212
193
|
});
|
|
213
194
|
renderResult(detail, {
|
|
214
195
|
json: options.json,
|
|
@@ -222,15 +203,20 @@ export function registerPlaybookCommands(program, context) {
|
|
|
222
203
|
throw new ArgumentError(`${err.message}\n${hint}`, err?.details, err?.code, hint);
|
|
223
204
|
}
|
|
224
205
|
}
|
|
225
|
-
//
|
|
226
|
-
|
|
206
|
+
// 2. 本地项目模式
|
|
207
|
+
let showTarget = id;
|
|
208
|
+
if (options.package && !id.includes("/")) {
|
|
209
|
+
requirePackageRoot(options.package);
|
|
210
|
+
showTarget = `${options.package}/${id}`;
|
|
211
|
+
}
|
|
227
212
|
let resolved;
|
|
228
213
|
try {
|
|
229
|
-
const graph =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
:
|
|
233
|
-
|
|
214
|
+
const graph = new PackageGraphBuilder({
|
|
215
|
+
root: resolveLocalPackageRoot() || undefined,
|
|
216
|
+
customHome: context?.customHome,
|
|
217
|
+
allowDevLinks: true,
|
|
218
|
+
}).buildSync();
|
|
219
|
+
resolved = resolvePlaybook(showTarget, { graph });
|
|
234
220
|
}
|
|
235
221
|
catch (err) {
|
|
236
222
|
const hint = "Tip: Run 'ad playbook list' to discover available playbooks.";
|
|
@@ -263,73 +249,36 @@ export function registerPlaybookCommands(program, context) {
|
|
|
263
249
|
.option("--json", "Output as JSON")
|
|
264
250
|
.action(async (id, rawOptions, cmd) => {
|
|
265
251
|
const options = getEffectiveOptions(rawOptions, cmd);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const catalog = new DefaultActionCatalog(graph);
|
|
252
|
+
const root = options.package
|
|
253
|
+
? requirePackageRoot(options.package).root
|
|
254
|
+
: resolveLocalPackageRoot();
|
|
270
255
|
const targets = [];
|
|
271
|
-
if (
|
|
272
|
-
if (id) {
|
|
273
|
-
const showTarget = target.resolvePlaybookRef(id);
|
|
274
|
-
const caller = target.localSkill.type === "single" ? target.localSkill.packages[0].packageId : undefined;
|
|
275
|
-
let resolved;
|
|
276
|
-
try {
|
|
277
|
-
resolved = resolvePlaybook(showTarget, { graph, caller });
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
throw new ArgumentError(err.message, err?.details, err?.code);
|
|
281
|
-
}
|
|
282
|
-
targets.push({
|
|
283
|
-
root: resolved.projectRoot,
|
|
284
|
-
packageId: resolved.packageId,
|
|
285
|
-
playbooks: [resolved.playbook],
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
for (const pkg of target.localSkill.packages) {
|
|
290
|
-
const playbooks = loadPlaybooks(pkg.packageRoot, pkg.projectConfig.playbooksDir);
|
|
291
|
-
targets.push({
|
|
292
|
-
root: pkg.packageRoot,
|
|
293
|
-
packageId: pkg.packageId,
|
|
294
|
-
playbooks: Array.from(playbooks.values()),
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
else if (target.targetPackageRoot) {
|
|
300
|
-
const root = target.targetPackageRoot;
|
|
256
|
+
if (root) {
|
|
301
257
|
const config = loadProjectConfig(root);
|
|
258
|
+
const playbooks = loadPlaybooks(root, config.playbooksDir);
|
|
302
259
|
if (id) {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
resolved = resolvePlaybook(showTarget, { graph, caller: config.id });
|
|
260
|
+
const pb = playbooks.get(id);
|
|
261
|
+
if (!pb) {
|
|
262
|
+
throw new ArgumentError(`Playbook '${id}' not found in package '${config.id}'`);
|
|
307
263
|
}
|
|
308
|
-
|
|
309
|
-
throw new ArgumentError(err.message, err?.details, err?.code);
|
|
310
|
-
}
|
|
311
|
-
targets.push({
|
|
312
|
-
root: resolved.projectRoot,
|
|
313
|
-
packageId: resolved.packageId,
|
|
314
|
-
playbooks: [resolved.playbook],
|
|
315
|
-
});
|
|
264
|
+
targets.push({ root, packageId: config.id, playbooks: [pb] });
|
|
316
265
|
}
|
|
317
266
|
else {
|
|
318
|
-
|
|
319
|
-
targets.push({
|
|
320
|
-
root,
|
|
321
|
-
packageId: config.id,
|
|
322
|
-
playbooks: Array.from(playbooks.values()),
|
|
323
|
-
});
|
|
267
|
+
targets.push({ root, packageId: config.id, playbooks: Array.from(playbooks.values()) });
|
|
324
268
|
}
|
|
325
269
|
}
|
|
326
270
|
else if (id) {
|
|
327
271
|
let resolved;
|
|
328
272
|
try {
|
|
273
|
+
const graph = new PackageGraphBuilder({
|
|
274
|
+
root: resolveLocalPackageRoot() || undefined,
|
|
275
|
+
customHome: context?.customHome,
|
|
276
|
+
allowDevLinks: true,
|
|
277
|
+
}).buildSync();
|
|
329
278
|
resolved = resolvePlaybook(id, { graph });
|
|
330
279
|
}
|
|
331
280
|
catch (err) {
|
|
332
|
-
throw new ArgumentError(err.message
|
|
281
|
+
throw new ArgumentError(err.message);
|
|
333
282
|
}
|
|
334
283
|
targets.push({
|
|
335
284
|
root: resolved.projectRoot,
|
|
@@ -343,22 +292,34 @@ export function registerPlaybookCommands(program, context) {
|
|
|
343
292
|
throw new ArgumentError(`${NO_PROJECT_NO_LINKED_MESSAGE} Please run 'ad link' inside a package first.`);
|
|
344
293
|
}
|
|
345
294
|
for (const pkg of linkedList) {
|
|
346
|
-
if (!existsSync(pkg.path))
|
|
347
|
-
writeStderr(`Skipping inaccessible linked package '${pkg.id}' at '${pkg.path}'`, context);
|
|
295
|
+
if (!existsSync(pkg.path))
|
|
348
296
|
continue;
|
|
297
|
+
try {
|
|
298
|
+
const config = loadProjectConfig(pkg.path);
|
|
299
|
+
const playbooks = loadPlaybooks(pkg.path, config.playbooksDir);
|
|
300
|
+
targets.push({
|
|
301
|
+
root: pkg.path,
|
|
302
|
+
packageId: pkg.id,
|
|
303
|
+
playbooks: Array.from(playbooks.values()),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// 单个链接包清单损坏或 Playbook 加载失败时跳过,不阻断整体校验
|
|
349
308
|
}
|
|
350
|
-
const config = loadProjectConfig(pkg.path);
|
|
351
|
-
const playbooks = loadPlaybooks(pkg.path, config.playbooksDir, config);
|
|
352
|
-
targets.push({
|
|
353
|
-
root: pkg.path,
|
|
354
|
-
packageId: pkg.id,
|
|
355
|
-
playbooks: Array.from(playbooks.values()),
|
|
356
|
-
});
|
|
357
309
|
}
|
|
358
310
|
}
|
|
359
311
|
const results = [];
|
|
360
|
-
|
|
361
|
-
|
|
312
|
+
const graph = new PackageGraphBuilder({
|
|
313
|
+
root: resolveLocalPackageRoot() || undefined,
|
|
314
|
+
customHome: context?.customHome,
|
|
315
|
+
allowDevLinks: true,
|
|
316
|
+
}).buildSync();
|
|
317
|
+
const catalog = new DefaultActionCatalog(graph);
|
|
318
|
+
for (const target of targets) {
|
|
319
|
+
const config = loadProjectConfig(target.root);
|
|
320
|
+
const manifest = loadManifest(target.root);
|
|
321
|
+
const actions = await loadActions(target.root, config.actionsDir);
|
|
322
|
+
for (const pb of target.playbooks) {
|
|
362
323
|
const warnings = [];
|
|
363
324
|
const errors = [];
|
|
364
325
|
if (!pb.id) {
|
|
@@ -369,30 +330,26 @@ export function registerPlaybookCommands(program, context) {
|
|
|
369
330
|
}
|
|
370
331
|
if (pb.actions && Array.isArray(pb.actions)) {
|
|
371
332
|
for (const actRef of pb.actions) {
|
|
372
|
-
if (
|
|
373
|
-
errors.push(`Referenced action must be a non-empty string, received ${JSON.stringify(actRef)}`);
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
const trimmed = actRef.trim();
|
|
377
|
-
if (trimmed.includes("/")) {
|
|
333
|
+
if (actRef.includes("/")) {
|
|
378
334
|
try {
|
|
379
|
-
resolveAction(
|
|
335
|
+
resolveAction(actRef, { graph, catalog, caller: target.packageId });
|
|
380
336
|
}
|
|
381
337
|
catch (e) {
|
|
382
|
-
errors.push(`Referenced cross-package action '${
|
|
338
|
+
errors.push(`Referenced cross-package action '${actRef}' not resolvable: ${e.message}. Hint: Action '${actRef}' not found. Run 'ad action create ${actRef}' to create local action, or 'ad add <pkg>' to install external dependency.`);
|
|
383
339
|
}
|
|
384
340
|
}
|
|
385
341
|
else {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
342
|
+
const foundInActions = actions.has(actRef);
|
|
343
|
+
const foundInManifest = Boolean(manifest?.actions?.[actRef]);
|
|
344
|
+
if (!foundInActions && !foundInManifest) {
|
|
345
|
+
errors.push(`Referenced action '${actRef}' not found in project actions. Hint: Action '${actRef}' not found. Run 'ad action create ${actRef}' to create local action, or 'ad add <pkg>' to install external dependency.`);
|
|
389
346
|
}
|
|
390
347
|
}
|
|
391
348
|
}
|
|
392
349
|
}
|
|
393
350
|
results.push({
|
|
394
351
|
id: pb.id,
|
|
395
|
-
packageId:
|
|
352
|
+
packageId: target.packageId,
|
|
396
353
|
valid: errors.length === 0,
|
|
397
354
|
warnings,
|
|
398
355
|
errors,
|
package/dist/commands/run.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { validateActionInputValue, mapInputValidationFailure, } from "@actiondock/core/project";
|
|
2
|
+
import { resolveTarget, } from "@actiondock/core/profile";
|
|
2
3
|
import { ACTION_NOT_FOUND, NOT_FOUND, resolveExecutionHint, } from "@actiondock/core";
|
|
3
|
-
import { ArgumentError, ExecutionError, SigintError } from "../errors.js";
|
|
4
|
+
import { ArgumentError, ExecutionError, SigintError, packageNotFoundError } from "../errors.js";
|
|
4
5
|
import { extractTextFieldPayload, resolveActionDefaultTextField, writeStderr, writeStdout, } from "../renderer.js";
|
|
5
|
-
import { applyTargetOptions, getEffectiveOptions, resolveActionInput,
|
|
6
|
+
import { applyTargetOptions, getEffectiveOptions, resolveActionInput, resolveLocalPackageRoot, resolveTimeoutMs, withService, } from "../utils/index.js";
|
|
6
7
|
/**
|
|
7
8
|
* 以原始纯文本形式渲染 Action 执行终态结果(默认纯文本模式)。
|
|
8
9
|
*
|
|
@@ -110,13 +111,25 @@ export async function executeAction(id, options, context, flatArgs, control) {
|
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
try {
|
|
113
|
-
// 目标拓扑与动作引用解析(远端目标完全隔离本地文件系统)
|
|
114
|
-
const target = resolveCommandTarget(options, context);
|
|
115
114
|
// 异步执行仅支持远端目标,本地模式直接拒绝
|
|
116
|
-
|
|
115
|
+
const resolvedTopology = resolveTarget({
|
|
116
|
+
profile: options.profile,
|
|
117
|
+
server: options.server,
|
|
118
|
+
token: options.token,
|
|
119
|
+
insecure: options.insecure,
|
|
120
|
+
}, context?.customHome);
|
|
121
|
+
if (resolvedTopology.type === "local" && options.async) {
|
|
117
122
|
throw new ExecutionError("Async execution requires a long-running ActionDock server.\nUse --profile, --server, or start 'ad serve'.");
|
|
118
123
|
}
|
|
119
|
-
|
|
124
|
+
// 目标拓扑解析(仅 local 分支需要包寻址)
|
|
125
|
+
const targetPackageRoot = resolveLocalPackageRoot(options.package);
|
|
126
|
+
if (options.package && !targetPackageRoot) {
|
|
127
|
+
throw packageNotFoundError(options.package);
|
|
128
|
+
}
|
|
129
|
+
let targetRef = id;
|
|
130
|
+
if (options.package && !id.includes("/")) {
|
|
131
|
+
targetRef = `${options.package}/${id}`;
|
|
132
|
+
}
|
|
120
133
|
// 通过 Service 统一执行
|
|
121
134
|
await withService(options, context, async (service) => {
|
|
122
135
|
const isMachine = Boolean(options.json);
|
|
@@ -192,7 +205,7 @@ export async function executeAction(id, options, context, flatArgs, control) {
|
|
|
192
205
|
return;
|
|
193
206
|
}
|
|
194
207
|
}
|
|
195
|
-
}, { localRoot:
|
|
208
|
+
}, { localRoot: targetPackageRoot || undefined, scanLinkedPackages: true, ownDataDir: true });
|
|
196
209
|
}
|
|
197
210
|
catch (err) {
|
|
198
211
|
// sigint 取消源、中断链路特征错误码或 SigintError 本身,均统一归并为 SigintError
|
package/dist/commands/state.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { decodeStateKey, } from "@actiondock/sdk";
|
|
2
|
-
import { loadProjectConfig,
|
|
2
|
+
import { loadProjectConfig, } from "@actiondock/core";
|
|
3
3
|
import { filterWithFallbackInfo, } from "@actiondock/core/project";
|
|
4
4
|
import { listLinkedPackages, } from "@actiondock/core/registry";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import { ArgumentError, ExecutionError, NO_PROJECT_NO_LINKED_MESSAGE } from "../errors.js";
|
|
7
7
|
import { renderResult, renderStateList, writeStderr, writeStdout } from "../renderer.js";
|
|
8
|
-
import { applyTargetOptions,
|
|
8
|
+
import { applyTargetOptions, getEffectiveOptions, getTargetRoot, remoteTargetLabel, requirePackageRoot, resolveFallbackStrategy, resolveIntent, resolveLocalPackageRoot, resolveTargetFromOptions, withService, } from "../utils/index.js";
|
|
9
9
|
/**
|
|
10
10
|
* 统一预解码状态键寻址(get、set、delete 共享的单一事实源)。
|
|
11
11
|
*
|
|
@@ -57,22 +57,6 @@ function resolveStateScope(resolved, options, rawKey) {
|
|
|
57
57
|
localRoot: undefined,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
assertNotCompositeSkill(options.package);
|
|
61
|
-
// 本地单包技能目录优先处理
|
|
62
|
-
if (options.package) {
|
|
63
|
-
const localSkill = inspectLocalPackageDirectory(options.package);
|
|
64
|
-
if (localSkill?.type === "single") {
|
|
65
|
-
const pkg = localSkill.packages[0];
|
|
66
|
-
return {
|
|
67
|
-
packageId: pkg.packageId,
|
|
68
|
-
scopeSuffix: `in package '${pkg.packageId}'`,
|
|
69
|
-
deleteSuffix: `from package '${pkg.packageId}'`,
|
|
70
|
-
effectiveKey: rawKey || "",
|
|
71
|
-
projConfig: pkg.projectConfig,
|
|
72
|
-
localRoot: pkg.packageRoot,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
60
|
// 本地项目模式:getTargetRoot 会从键中剥离 pkg/ 前缀,寻址基于解耦后的裸键
|
|
77
61
|
const { root, key: effectiveKey } = getTargetRoot(options.package, rawKey);
|
|
78
62
|
const projConfig = loadProjectConfig(root);
|
|
@@ -191,7 +175,6 @@ export function registerStateCommands(program, context) {
|
|
|
191
175
|
return;
|
|
192
176
|
}
|
|
193
177
|
// 本地工程与链接包模式:按目标根目录决策输出范围
|
|
194
|
-
assertNotCompositeSkill(options.package);
|
|
195
178
|
const targetRoot = options.package
|
|
196
179
|
? requirePackageRoot(options.package).root
|
|
197
180
|
: resolveLocalPackageRoot();
|
|
@@ -43,7 +43,3 @@ export type RegistryTreeView = RegistryStatusReport | (Record<string, unknown> &
|
|
|
43
43
|
* 格式化渲染注册表层级树结构。
|
|
44
44
|
*/
|
|
45
45
|
export declare function renderRegistryTree(status: RegistryTreeView): string;
|
|
46
|
-
/**
|
|
47
|
-
* 格式化渲染复合技能各子包的自省卡片列表。
|
|
48
|
-
*/
|
|
49
|
-
export declare function renderCompositeSkillDetail(root: string, filteredDetails: ProjectDetailInfo[], isFallback?: boolean, effectiveIntent?: string): string;
|
|
@@ -194,19 +194,3 @@ export function renderRegistryTree(status) {
|
|
|
194
194
|
}
|
|
195
195
|
return lines.join("\n");
|
|
196
196
|
}
|
|
197
|
-
/**
|
|
198
|
-
* 格式化渲染复合技能各子包的自省卡片列表。
|
|
199
|
-
*/
|
|
200
|
-
export function renderCompositeSkillDetail(root, filteredDetails, isFallback, effectiveIntent) {
|
|
201
|
-
const lines = [];
|
|
202
|
-
if (isFallback) {
|
|
203
|
-
lines.push(`(No packages in skill matched intent '${effectiveIntent}', showing all packages)\n`);
|
|
204
|
-
}
|
|
205
|
-
lines.push(`ActionDock Composite Skill: ${root}`);
|
|
206
|
-
lines.push(`Packages (${filteredDetails.length}):\n`);
|
|
207
|
-
for (const d of filteredDetails) {
|
|
208
|
-
lines.push(renderProjectDetail(d));
|
|
209
|
-
lines.push("");
|
|
210
|
-
}
|
|
211
|
-
return lines.join("\n").trimEnd();
|
|
212
|
-
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type LocalSkillDirectory } from "@actiondock/core/project";
|
|
2
1
|
import type { AggregatedPackage, CliContext, ProjectDetailInfo } from "../types.js";
|
|
3
2
|
/**
|
|
4
3
|
* 装配单个工程的详情自省信息(清单、动作映射与 Playbook 映射)。
|
|
@@ -6,18 +5,6 @@ import type { AggregatedPackage, CliContext, ProjectDetailInfo } from "../types.
|
|
|
6
5
|
* @param root 工程根目录
|
|
7
6
|
*/
|
|
8
7
|
export declare function getProjectDetailInfo(root: string): Promise<ProjectDetailInfo>;
|
|
9
|
-
/**
|
|
10
|
-
* 装配复合技能各子包的自省详情,将 Action 与 Playbook 的调用索引提升为完全限定 ID。
|
|
11
|
-
*/
|
|
12
|
-
export declare function buildCompositeDetails(localSkill: LocalSkillDirectory): Promise<ProjectDetailInfo[]>;
|
|
13
|
-
/**
|
|
14
|
-
* 单包与复合技能共享相同的详情过滤规则(单一事实源)。
|
|
15
|
-
*/
|
|
16
|
-
export declare function filterProjectDetails(details: ProjectDetailInfo[], effectiveIntent?: string, shouldFallback?: boolean): {
|
|
17
|
-
items: ProjectDetailInfo[];
|
|
18
|
-
matchedCount: number;
|
|
19
|
-
isFallback: boolean;
|
|
20
|
-
};
|
|
21
8
|
/**
|
|
22
9
|
* 装配单个包的摘要聚合信息(不含动作与 Playbook 明细映射)。
|
|
23
10
|
*
|
|
@@ -26,7 +13,7 @@ export declare function filterProjectDetails(details: ProjectDetailInfo[], effec
|
|
|
26
13
|
export declare function getPackageSummary(root: string): AggregatedPackage;
|
|
27
14
|
/**
|
|
28
15
|
* 扫描本地候选包集合(当前工程根目录优先,叠加全局已链接包,按物理路径去重)。
|
|
29
|
-
*
|
|
16
|
+
* 清单损坏或磁盘失效的候选项跳过,不影响其余条目聚合。
|
|
30
17
|
*
|
|
31
18
|
* @param context CLI 上下文(提供 customHome 定位全局注册表)
|
|
32
19
|
*/
|
package/dist/services/inspect.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
|
|
3
3
|
import { listLinkedPackages, } from "@actiondock/core/registry";
|
|
4
|
-
import {
|
|
4
|
+
import { loadManifest, loadPlaybooks, } from "@actiondock/core/project";
|
|
5
5
|
/**
|
|
6
6
|
* 装配单个工程的详情自省信息(清单、动作映射与 Playbook 映射)。
|
|
7
7
|
*
|
|
@@ -38,51 +38,6 @@ export async function getProjectDetailInfo(root) {
|
|
|
38
38
|
playbooksMap: playbooks,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
/**
|
|
42
|
-
* 装配复合技能各子包的自省详情,将 Action 与 Playbook 的调用索引提升为完全限定 ID。
|
|
43
|
-
*/
|
|
44
|
-
export async function buildCompositeDetails(localSkill) {
|
|
45
|
-
const details = [];
|
|
46
|
-
for (const pkg of localSkill.packages) {
|
|
47
|
-
const detail = await getProjectDetailInfo(pkg.packageRoot);
|
|
48
|
-
const qualifiedActionsMap = new Map();
|
|
49
|
-
if (detail.actionsMap) {
|
|
50
|
-
for (const [actId, act] of detail.actionsMap.entries()) {
|
|
51
|
-
const fullId = `${pkg.packageId}/${actId}`;
|
|
52
|
-
qualifiedActionsMap.set(fullId, { id: fullId, description: act.description });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const qualifiedPlaybooksMap = new Map();
|
|
56
|
-
if (detail.playbooksMap) {
|
|
57
|
-
for (const [pbId, pb] of detail.playbooksMap.entries()) {
|
|
58
|
-
const fullId = `${pkg.packageId}/${pbId}`;
|
|
59
|
-
qualifiedPlaybooksMap.set(fullId, { ...pb, id: fullId });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
detail.actionsMap = qualifiedActionsMap;
|
|
63
|
-
detail.actions = Array.from(qualifiedActionsMap.keys());
|
|
64
|
-
detail.playbooksMap = qualifiedPlaybooksMap;
|
|
65
|
-
detail.playbooks = Array.from(qualifiedPlaybooksMap.keys());
|
|
66
|
-
details.push(detail);
|
|
67
|
-
}
|
|
68
|
-
return details;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 单包与复合技能共享相同的详情过滤规则(单一事实源)。
|
|
72
|
-
*/
|
|
73
|
-
export function filterProjectDetails(details, effectiveIntent, shouldFallback = false) {
|
|
74
|
-
if (!effectiveIntent) {
|
|
75
|
-
return { items: details, matchedCount: details.length, isFallback: false };
|
|
76
|
-
}
|
|
77
|
-
return filterWithFallbackInfo(details, effectiveIntent, [
|
|
78
|
-
(d) => d.id,
|
|
79
|
-
(d) => d.name,
|
|
80
|
-
(d) => d.description || "",
|
|
81
|
-
(d) => d.projectRoot,
|
|
82
|
-
(d) => d.actions.join(" "),
|
|
83
|
-
(d) => d.playbooks.join(" "),
|
|
84
|
-
], Boolean(shouldFallback));
|
|
85
|
-
}
|
|
86
41
|
/**
|
|
87
42
|
* 装配单个包的摘要聚合信息(不含动作与 Playbook 明细映射)。
|
|
88
43
|
*
|
|
@@ -108,7 +63,7 @@ export function getPackageSummary(root) {
|
|
|
108
63
|
}
|
|
109
64
|
/**
|
|
110
65
|
* 扫描本地候选包集合(当前工程根目录优先,叠加全局已链接包,按物理路径去重)。
|
|
111
|
-
*
|
|
66
|
+
* 清单损坏或磁盘失效的候选项跳过,不影响其余条目聚合。
|
|
112
67
|
*
|
|
113
68
|
* @param context CLI 上下文(提供 customHome 定位全局注册表)
|
|
114
69
|
*/
|
|
@@ -118,22 +73,25 @@ export function scanLocalAggregatedPackages(context) {
|
|
|
118
73
|
const aggregated = [];
|
|
119
74
|
const seenPaths = new Set();
|
|
120
75
|
if (currentRoot) {
|
|
121
|
-
|
|
122
|
-
|
|
76
|
+
try {
|
|
77
|
+
aggregated.push(getPackageSummary(currentRoot));
|
|
78
|
+
seenPaths.add(currentRoot);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// 忽略异常工程根目录(清单损坏)
|
|
82
|
+
}
|
|
123
83
|
}
|
|
124
84
|
for (const pkg of linkedList) {
|
|
125
|
-
if (!existsSync(pkg.path))
|
|
126
|
-
process.stderr.write(`[actiondock] Diagnostic: Skipping inaccessible linked package '${pkg.id}' at '${pkg.path}'\n`);
|
|
85
|
+
if (!existsSync(pkg.path))
|
|
127
86
|
continue;
|
|
128
|
-
}
|
|
129
87
|
if (seenPaths.has(pkg.path))
|
|
130
88
|
continue;
|
|
131
89
|
try {
|
|
132
90
|
aggregated.push(getPackageSummary(pkg.path));
|
|
133
91
|
seenPaths.add(pkg.path);
|
|
134
92
|
}
|
|
135
|
-
catch
|
|
136
|
-
|
|
93
|
+
catch {
|
|
94
|
+
// 忽略失效链接(清单损坏或磁盘异常)
|
|
137
95
|
}
|
|
138
96
|
}
|
|
139
97
|
return { currentRoot, aggregated };
|