@actiondock/cli 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -32
- package/package.json +4 -3
- package/src/commands/action.ts +5 -5
- package/src/commands/config.ts +98 -12
- package/src/commands/doctor.ts +24 -6
- package/src/commands/index.ts +3 -3
- package/src/commands/info.ts +98 -119
- package/src/commands/link.ts +2 -2
- package/src/commands/playbook.ts +64 -3
- package/src/commands/profile.ts +7 -7
- package/src/commands/runs.ts +93 -3
- package/src/commands/serve.ts +33 -1
- package/src/commands/state.ts +125 -12
- package/dist/index.js +0 -44620
- /package/bin/{ac.js → ad.js} +0 -0
package/src/commands/info.ts
CHANGED
|
@@ -122,7 +122,7 @@ function printAggregatedPackages(
|
|
|
122
122
|
}
|
|
123
123
|
if (options?.showTip !== false) {
|
|
124
124
|
console.log(
|
|
125
|
-
"Tip: Run '
|
|
125
|
+
"Tip: Run 'ad info <package-id>' to view detailed package configuration and schema."
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
128
|
}
|
|
@@ -133,7 +133,7 @@ function printRegistryTree(status: ReturnType<typeof getRegistryStatus>): void {
|
|
|
133
133
|
|
|
134
134
|
if (!hasWorkspaces && !hasPackages) {
|
|
135
135
|
console.log("[INFO] No ActionDock packages or workspaces currently linked.");
|
|
136
|
-
console.log(" Run '
|
|
136
|
+
console.log(" Run 'ad link' inside an Action package or workspace to register it.");
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -165,7 +165,7 @@ function printRegistryTree(status: ReturnType<typeof getRegistryStatus>): void {
|
|
|
165
165
|
|
|
166
166
|
console.log(`\n[Summary] Total: ${status.totalPackagesCount} active package(s), ${status.workspaces.length} workspace(s)`);
|
|
167
167
|
if (status.staleCount > 0) {
|
|
168
|
-
console.log(`[WARN] ${status.staleCount} stale entry/entries detected. Run '
|
|
168
|
+
console.log(`[WARN] ${status.staleCount} stale entry/entries detected. Run 'ad unlink --prune' to clean up.`);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -191,16 +191,6 @@ export function registerInfoCommand(program: Command): void {
|
|
|
191
191
|
.option("--json", "Output information as JSON")
|
|
192
192
|
.action(async (patterns: string[] = [], options: any) => {
|
|
193
193
|
try {
|
|
194
|
-
if (options.tree) {
|
|
195
|
-
const status = getRegistryStatus();
|
|
196
|
-
if (options.json) {
|
|
197
|
-
console.log(JSON.stringify(status, null, 2));
|
|
198
|
-
} else {
|
|
199
|
-
printRegistryTree(status);
|
|
200
|
-
}
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
194
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
205
195
|
const shouldFallback = options.fallback !== false;
|
|
206
196
|
|
|
@@ -214,121 +204,110 @@ export function registerInfoCommand(program: Command): void {
|
|
|
214
204
|
if (target.type === "remote") {
|
|
215
205
|
const remoteInfo = await fetchRemoteInfo(
|
|
216
206
|
target.serverUrl!,
|
|
217
|
-
target.token
|
|
207
|
+
target.token,
|
|
208
|
+
{
|
|
209
|
+
intent: effectiveIntent,
|
|
210
|
+
package: options.package,
|
|
211
|
+
tree: Boolean(options.tree),
|
|
212
|
+
}
|
|
218
213
|
);
|
|
219
214
|
|
|
220
215
|
if (options.json) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
null,
|
|
243
|
-
2
|
|
244
|
-
)
|
|
245
|
-
);
|
|
246
|
-
} else {
|
|
247
|
-
console.log(JSON.stringify(remoteInfo, null, 2));
|
|
216
|
+
console.log(JSON.stringify(remoteInfo, null, 2));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
console.log(
|
|
221
|
+
`Remote ActionDock Server: ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""}\n`
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Remote Tree
|
|
225
|
+
if (remoteInfo.type === "tree" || (options.tree && remoteInfo.workspaces)) {
|
|
226
|
+
printRegistryTree(remoteInfo);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Remote Package Detail
|
|
231
|
+
if (remoteInfo.type === "package_detail" || (remoteInfo.id && !remoteInfo.packages)) {
|
|
232
|
+
console.log(`ActionDock Project: ${remoteInfo.name || remoteInfo.id} (${remoteInfo.id})`);
|
|
233
|
+
console.log(`Version: ${remoteInfo.version || "unknown"}`);
|
|
234
|
+
if (remoteInfo.description) console.log(`Description: ${remoteInfo.description}`);
|
|
235
|
+
if (remoteInfo.path || remoteInfo.projectRoot) {
|
|
236
|
+
console.log(`Root: ${remoteInfo.path || remoteInfo.projectRoot}`);
|
|
248
237
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
effectiveIntent,
|
|
258
|
-
[
|
|
259
|
-
(r: any) => r.id,
|
|
260
|
-
(r: any) => r.name,
|
|
261
|
-
(r: any) => r.description,
|
|
262
|
-
(r: any) => r.actions,
|
|
263
|
-
(r: any) => r.playbooks,
|
|
264
|
-
],
|
|
265
|
-
shouldFallback
|
|
266
|
-
);
|
|
267
|
-
if (match.matchedCount === 0 && !shouldFallback) {
|
|
268
|
-
console.error(
|
|
269
|
-
`Error: Remote project '${remoteInfo.id}' did not match intent '${effectiveIntent}'`
|
|
270
|
-
);
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
console.log(
|
|
275
|
-
`Project: ${remoteInfo.name || remoteInfo.id} (${remoteInfo.id})`
|
|
276
|
-
);
|
|
277
|
-
console.log(`Version: ${remoteInfo.version || "unknown"}`);
|
|
278
|
-
if (remoteInfo.description) {
|
|
279
|
-
console.log(`Description: ${remoteInfo.description}`);
|
|
280
|
-
}
|
|
281
|
-
if (Array.isArray(remoteInfo.actions)) {
|
|
282
|
-
console.log(`\nActions (${remoteInfo.actions.length}):`);
|
|
283
|
-
for (const actId of remoteInfo.actions) {
|
|
284
|
-
console.log(` - ${actId}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
if (Array.isArray(remoteInfo.playbooks)) {
|
|
288
|
-
console.log(`\nPlaybooks (${remoteInfo.playbooks.length}):`);
|
|
289
|
-
for (const pbId of remoteInfo.playbooks) {
|
|
290
|
-
console.log(` - ${pbId}`);
|
|
291
|
-
}
|
|
238
|
+
|
|
239
|
+
const actions = remoteInfo.actionsDetail || remoteInfo.actions || [];
|
|
240
|
+
console.log(`\nActions (${remoteInfo.actionsCount || actions.length}):`);
|
|
241
|
+
for (const act of actions) {
|
|
242
|
+
if (typeof act === "string") {
|
|
243
|
+
console.log(` - ${act}`);
|
|
244
|
+
} else {
|
|
245
|
+
console.log(` - ${(act.id || "").padEnd(28)} ${act.description || ""}`);
|
|
292
246
|
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
(p: any) => p.name,
|
|
303
|
-
(p: any) => p.description,
|
|
304
|
-
(p: any) => p.path,
|
|
305
|
-
(p: any) => p.actions,
|
|
306
|
-
(p: any) => p.playbooks,
|
|
307
|
-
],
|
|
308
|
-
shouldFallback
|
|
309
|
-
);
|
|
310
|
-
if (filterRes.matchedCount === 0 && !shouldFallback) {
|
|
311
|
-
console.error(
|
|
312
|
-
`Error: No remote packages matched intent '${effectiveIntent}'`
|
|
313
|
-
);
|
|
314
|
-
process.exit(1);
|
|
315
|
-
}
|
|
316
|
-
list = filterRes.items;
|
|
317
|
-
isFallback = filterRes.isFallback;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const playbooks = remoteInfo.playbooksDetail || remoteInfo.playbooks || [];
|
|
250
|
+
console.log(`\nPlaybooks (${remoteInfo.playbooksCount || playbooks.length}):`);
|
|
251
|
+
for (const pb of playbooks) {
|
|
252
|
+
if (typeof pb === "string") {
|
|
253
|
+
console.log(` - ${pb}`);
|
|
254
|
+
} else {
|
|
255
|
+
console.log(` - ${(pb.id || "").padEnd(28)} ${pb.description || ""}`);
|
|
318
256
|
}
|
|
319
|
-
|
|
320
|
-
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const declared = remoteInfo.configDeclared || {};
|
|
260
|
+
const declaredKeys = Object.keys(declared);
|
|
261
|
+
if (declaredKeys.length > 0) {
|
|
262
|
+
console.log(`\nDeclared Config Keys:`);
|
|
263
|
+
for (const k of declaredKeys) {
|
|
264
|
+
const item = declared[k];
|
|
265
|
+
const isSec = item?.secret ? " [secret]" : "";
|
|
266
|
+
const def =
|
|
267
|
+
item?.default !== undefined
|
|
268
|
+
? ` (default: ${JSON.stringify(item.default)})`
|
|
269
|
+
: "";
|
|
321
270
|
console.log(
|
|
322
|
-
|
|
271
|
+
` - ${k.padEnd(24)} ${item?.description || ""}${def}${isSec}`
|
|
323
272
|
);
|
|
324
273
|
}
|
|
325
|
-
console.log(`\nLinked Packages (${list.length}):`);
|
|
326
|
-
for (const pkg of list) {
|
|
327
|
-
console.log(` - ${pkg.id} (${pkg.path})`);
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
console.log(JSON.stringify(remoteInfo, null, 2));
|
|
331
274
|
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Remote Package List
|
|
279
|
+
const packages = remoteInfo.packages || remoteInfo.linkedPackages || [];
|
|
280
|
+
if (Array.isArray(packages)) {
|
|
281
|
+
console.log(`Remote ActionDock Packages (${packages.length}):\n`);
|
|
282
|
+
for (const p of packages) {
|
|
283
|
+
console.log(`* ${p.name || p.id} (${p.id}) v${p.version || "unknown"}`);
|
|
284
|
+
if (p.path) console.log(` Path: ${p.path}`);
|
|
285
|
+
if (p.description) console.log(` Desc: ${p.description}`);
|
|
286
|
+
const actNames = Array.isArray(p.actions)
|
|
287
|
+
? p.actions.map((a: any) => (typeof a === "string" ? a : a.id)).join(", ")
|
|
288
|
+
: "";
|
|
289
|
+
const pbNames = Array.isArray(p.playbooks)
|
|
290
|
+
? p.playbooks.map((pb: any) => (typeof pb === "string" ? pb : pb.id)).join(", ")
|
|
291
|
+
: "";
|
|
292
|
+
console.log(` Actions (${p.actionsCount || (p.actions ? p.actions.length : 0)}): ${actNames || "(none)"}`);
|
|
293
|
+
console.log(` Playbooks (${p.playbooksCount || (p.playbooks ? p.playbooks.length : 0)}): ${pbNames || "(none)"}`);
|
|
294
|
+
console.log("");
|
|
295
|
+
}
|
|
296
|
+
console.log("Tip: Run 'ad info <package-id> --server <url>' to view detailed package configuration and schema.");
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
console.log(JSON.stringify(remoteInfo, null, 2));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Local Tree
|
|
305
|
+
if (options.tree) {
|
|
306
|
+
const status = getRegistryStatus();
|
|
307
|
+
if (options.json) {
|
|
308
|
+
console.log(JSON.stringify(status, null, 2));
|
|
309
|
+
} else {
|
|
310
|
+
printRegistryTree(status);
|
|
332
311
|
}
|
|
333
312
|
return;
|
|
334
313
|
}
|
|
@@ -423,7 +402,7 @@ export function registerInfoCommand(program: Command): void {
|
|
|
423
402
|
"No ActionDock project in current directory, and no packages linked."
|
|
424
403
|
);
|
|
425
404
|
console.log(
|
|
426
|
-
"Run '
|
|
405
|
+
"Run 'ad link' inside an Action package to register it."
|
|
427
406
|
);
|
|
428
407
|
return;
|
|
429
408
|
}
|
package/src/commands/link.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
|
|
8
8
|
export function registerLinkCommands(program: Command): void {
|
|
9
|
-
//
|
|
9
|
+
// ad link [path]
|
|
10
10
|
program
|
|
11
11
|
.command("link [path]")
|
|
12
12
|
.option("-r, --recursive", "Recursively discover and link packages in subdirectories")
|
|
@@ -32,7 +32,7 @@ export function registerLinkCommands(program: Command): void {
|
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// ad unlink [id|path]
|
|
36
36
|
program
|
|
37
37
|
.command("unlink [identifier]")
|
|
38
38
|
.option("-p, --prune", "Automatically scan and prune any stale/missing paths from registry")
|
package/src/commands/playbook.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import {
|
|
4
|
+
fetchRemotePlaybooks,
|
|
5
|
+
fetchRemotePlaybookShow,
|
|
4
6
|
filterWithFallbackInfo,
|
|
5
7
|
findProjectRoot,
|
|
6
8
|
listLinkedPackages,
|
|
@@ -8,6 +10,7 @@ import {
|
|
|
8
10
|
loadPlaybooks,
|
|
9
11
|
loadProjectConfig,
|
|
10
12
|
resolvePlaybookProject,
|
|
13
|
+
resolveTarget,
|
|
11
14
|
} from "@actiondock/core";
|
|
12
15
|
import type { PlaybookDefinition } from "@actiondock/core";
|
|
13
16
|
import { Command } from "commander";
|
|
@@ -23,13 +26,45 @@ export function registerPlaybookCommands(program: Command): void {
|
|
|
23
26
|
.command("list [patterns...]")
|
|
24
27
|
.description("List playbooks in current project or linked packages")
|
|
25
28
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
29
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
30
|
+
.option("-p, --profile <name>", "Query against a specific profile")
|
|
31
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
32
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
26
33
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
27
34
|
.option("--json", "Output as JSON")
|
|
28
|
-
.action((patterns, options) => {
|
|
35
|
+
.action(async (patterns, options) => {
|
|
29
36
|
try {
|
|
30
37
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
31
38
|
const shouldFallback = options.fallback !== false;
|
|
32
39
|
|
|
40
|
+
const target = resolveTarget({
|
|
41
|
+
profile: options.profile,
|
|
42
|
+
server: options.server,
|
|
43
|
+
token: options.token,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (target.type === "remote") {
|
|
47
|
+
const remotePbs = await fetchRemotePlaybooks(target.serverUrl!, target.token, {
|
|
48
|
+
intent: effectiveIntent,
|
|
49
|
+
package: options.package,
|
|
50
|
+
});
|
|
51
|
+
if (options.json) {
|
|
52
|
+
console.log(JSON.stringify(remotePbs, null, 2));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log(
|
|
56
|
+
`Playbooks on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""}:\n`
|
|
57
|
+
);
|
|
58
|
+
if (remotePbs.length === 0) {
|
|
59
|
+
console.log(" (No playbooks found)");
|
|
60
|
+
} else {
|
|
61
|
+
for (const p of remotePbs) {
|
|
62
|
+
console.log(` ${p.id.padEnd(24)} ${p.description} (Package: ${p.packageId})`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
33
68
|
const root = findProjectRoot();
|
|
34
69
|
if (root) {
|
|
35
70
|
const config = loadProjectConfig(root);
|
|
@@ -65,7 +100,7 @@ export function registerPlaybookCommands(program: Command): void {
|
|
|
65
100
|
const linkedList = listLinkedPackages();
|
|
66
101
|
if (linkedList.length === 0) {
|
|
67
102
|
console.log("No ActionDock project in current directory, and no packages linked.");
|
|
68
|
-
console.log("Run '
|
|
103
|
+
console.log("Run 'ad link' inside an Action package to register it.");
|
|
69
104
|
return;
|
|
70
105
|
}
|
|
71
106
|
|
|
@@ -228,9 +263,35 @@ This playbook provides task execution guidance for AI Agents.
|
|
|
228
263
|
pbCmd
|
|
229
264
|
.command("show <id>")
|
|
230
265
|
.description("Show playbook content and metadata (from current project or linked packages)")
|
|
266
|
+
.option("-p, --profile <name>", "Query against a specific profile")
|
|
267
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
268
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
231
269
|
.option("--json", "Output as JSON")
|
|
232
|
-
.action((id, options) => {
|
|
270
|
+
.action(async (id, options) => {
|
|
233
271
|
try {
|
|
272
|
+
const target = resolveTarget({
|
|
273
|
+
profile: options.profile,
|
|
274
|
+
server: options.server,
|
|
275
|
+
token: options.token,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
if (target.type === "remote") {
|
|
279
|
+
const pb = await fetchRemotePlaybookShow(target.serverUrl!, id, target.token);
|
|
280
|
+
if (options.json) {
|
|
281
|
+
console.log(JSON.stringify(pb, null, 2));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
console.log(`Playbook: ${pb.id} (Package: ${pb.packageId})`);
|
|
285
|
+
if (pb.description) console.log(`Description: ${pb.description}`);
|
|
286
|
+
if (pb.actions && pb.actions.length > 0) {
|
|
287
|
+
console.log(`Actions: ${pb.actions.join(", ")}`);
|
|
288
|
+
}
|
|
289
|
+
if (pb.filePath) console.log(`File: ${pb.filePath}\n`);
|
|
290
|
+
console.log("--- Content ---");
|
|
291
|
+
console.log(pb.content);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
234
295
|
const resolved = resolvePlaybookProject(id);
|
|
235
296
|
const pb = resolved.playbook;
|
|
236
297
|
|
package/src/commands/profile.ts
CHANGED
|
@@ -20,7 +20,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
20
20
|
.command("profile")
|
|
21
21
|
.description("Manage multi-cloud and remote execution profiles");
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// ad profile list
|
|
24
24
|
profileCmd
|
|
25
25
|
.command("list [patterns...]")
|
|
26
26
|
.description("List all configured profiles")
|
|
@@ -86,7 +86,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
88
|
console.log(
|
|
89
|
-
"\nUse '
|
|
89
|
+
"\nUse 'ad profile use <name>' to switch or 'ad run <action> --profile <name>' to execute on a specific target."
|
|
90
90
|
);
|
|
91
91
|
}
|
|
92
92
|
} catch (err: any) {
|
|
@@ -95,7 +95,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
//
|
|
98
|
+
// ad profile add <name>
|
|
99
99
|
profileCmd
|
|
100
100
|
.command("add <name>")
|
|
101
101
|
.description("Add or update a remote execution profile")
|
|
@@ -123,7 +123,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
//
|
|
126
|
+
// ad profile use <name>
|
|
127
127
|
profileCmd
|
|
128
128
|
.command("use <name>")
|
|
129
129
|
.description("Switch active default profile")
|
|
@@ -137,7 +137,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
//
|
|
140
|
+
// ad profile show [name]
|
|
141
141
|
profileCmd
|
|
142
142
|
.command("show [name]")
|
|
143
143
|
.description("Display details of a profile (defaults to active profile)")
|
|
@@ -200,7 +200,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
200
200
|
}
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
-
//
|
|
203
|
+
// ad profile rm / remove <name>
|
|
204
204
|
profileCmd
|
|
205
205
|
.command("rm <name>")
|
|
206
206
|
.alias("remove")
|
|
@@ -223,7 +223,7 @@ export function registerProfileCommands(program: Command): void {
|
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
//
|
|
226
|
+
// ad profile test [name]
|
|
227
227
|
profileCmd
|
|
228
228
|
.command("test [name]")
|
|
229
229
|
.description("Test connection latency and health of a profile")
|
package/src/commands/runs.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import {
|
|
3
3
|
cancelRemoteRun,
|
|
4
|
+
clearRemoteRuns,
|
|
4
5
|
createStorage,
|
|
5
6
|
fetchRemoteRun,
|
|
7
|
+
fetchRemoteRuns,
|
|
6
8
|
filterWithFallbackInfo,
|
|
7
9
|
findProjectRoot,
|
|
8
10
|
listLinkedPackages,
|
|
@@ -49,14 +51,50 @@ export function registerRunsCommands(program: Command): void {
|
|
|
49
51
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
50
52
|
.option("-a, --action <actionId>", "Filter by action ID")
|
|
51
53
|
.option("-n, --limit <count>", "Maximum number of records to return", "20")
|
|
54
|
+
.option("-p, --profile <name>", "Query against a specific profile")
|
|
55
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
56
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
52
57
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
53
58
|
.option("--json", "Output as JSON")
|
|
54
|
-
.action((patterns, options) => {
|
|
59
|
+
.action(async (patterns, options) => {
|
|
55
60
|
try {
|
|
56
61
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
57
62
|
const shouldFallback = options.fallback !== false;
|
|
58
63
|
const limit = Number.parseInt(options.limit, 10) || 20;
|
|
59
64
|
|
|
65
|
+
const target = resolveTarget({
|
|
66
|
+
profile: options.profile,
|
|
67
|
+
server: options.server,
|
|
68
|
+
token: options.token,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (target.type === "remote") {
|
|
72
|
+
const res = await fetchRemoteRuns(target.serverUrl!, target.token, {
|
|
73
|
+
packageId: options.package,
|
|
74
|
+
actionId: options.action,
|
|
75
|
+
intent: effectiveIntent,
|
|
76
|
+
limit,
|
|
77
|
+
});
|
|
78
|
+
if (options.json) {
|
|
79
|
+
console.log(JSON.stringify(res.items, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log(
|
|
83
|
+
`Execution Runs on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""} (${res.items.length}):\n`
|
|
84
|
+
);
|
|
85
|
+
console.log(
|
|
86
|
+
` ${"RUN ID".padEnd(38)} ${"ACTION".padEnd(24)} ${"STATUS".padEnd(10)} ${"STARTED"}`
|
|
87
|
+
);
|
|
88
|
+
console.log(" " + "-".repeat(90));
|
|
89
|
+
for (const r of res.items) {
|
|
90
|
+
const time = (r.startedAt || "").replace("T", " ").slice(0, 19);
|
|
91
|
+
console.log(
|
|
92
|
+
` ${r.id.padEnd(38)} ${r.actionId.padEnd(24)} ${r.status.padEnd(10)} ${time}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
60
98
|
const targetRoot = options.package
|
|
61
99
|
? resolvePackageRoot(options.package)
|
|
62
100
|
: findProjectRoot();
|
|
@@ -107,7 +145,7 @@ export function registerRunsCommands(program: Command): void {
|
|
|
107
145
|
const linkedList = listLinkedPackages();
|
|
108
146
|
if (linkedList.length === 0) {
|
|
109
147
|
console.log("No ActionDock project in current directory, and no packages linked.");
|
|
110
|
-
console.log("Run '
|
|
148
|
+
console.log("Run 'ad link' inside an Action package to register it.");
|
|
111
149
|
return;
|
|
112
150
|
}
|
|
113
151
|
|
|
@@ -293,7 +331,7 @@ export function registerRunsCommands(program: Command): void {
|
|
|
293
331
|
|
|
294
332
|
if (target.type === "local") {
|
|
295
333
|
console.error(
|
|
296
|
-
"Error: '
|
|
334
|
+
"Error: 'ad runs cancel' is only supported for remote execution targets. Use --profile <name> or --server <url>."
|
|
297
335
|
);
|
|
298
336
|
process.exit(1);
|
|
299
337
|
}
|
|
@@ -315,5 +353,57 @@ export function registerRunsCommands(program: Command): void {
|
|
|
315
353
|
process.exit(1);
|
|
316
354
|
}
|
|
317
355
|
});
|
|
356
|
+
|
|
357
|
+
// runs clear
|
|
358
|
+
runsCmd
|
|
359
|
+
.command("clear")
|
|
360
|
+
.description("Clear execution run records (locally or on remote server)")
|
|
361
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
362
|
+
.option("-a, --action <actionId>", "Filter by action ID")
|
|
363
|
+
.option("-p, --profile <name>", "Target profile")
|
|
364
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
365
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
366
|
+
.option("--json", "Output as JSON")
|
|
367
|
+
.action(async (options) => {
|
|
368
|
+
try {
|
|
369
|
+
const target = resolveTarget({
|
|
370
|
+
profile: options.profile,
|
|
371
|
+
server: options.server,
|
|
372
|
+
token: options.token,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
if (target.type === "remote") {
|
|
376
|
+
const res = await clearRemoteRuns(target.serverUrl!, target.token, {
|
|
377
|
+
packageId: options.package,
|
|
378
|
+
actionId: options.action,
|
|
379
|
+
});
|
|
380
|
+
if (options.json) {
|
|
381
|
+
console.log(JSON.stringify(res, null, 2));
|
|
382
|
+
} else {
|
|
383
|
+
console.log(`Cleared ${res.clearedCount} execution run(s) on remote server.`);
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const targetRoot = options.package
|
|
389
|
+
? resolvePackageRoot(options.package)
|
|
390
|
+
: findProjectRoot();
|
|
391
|
+
|
|
392
|
+
if (targetRoot) {
|
|
393
|
+
const projConfig = loadProjectConfig(targetRoot);
|
|
394
|
+
const storage = createStorage(projConfig.id, { projectRoot: targetRoot });
|
|
395
|
+
const count = storage.clearRuns({ actionId: options.action });
|
|
396
|
+
storage.close();
|
|
397
|
+
if (options.json) {
|
|
398
|
+
console.log(JSON.stringify({ ok: true, clearedCount: count }, null, 2));
|
|
399
|
+
} else {
|
|
400
|
+
console.log(`Cleared ${count} execution run(s) in package '${projConfig.id}'.`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} catch (err: any) {
|
|
404
|
+
console.error(`Error: ${err.message}`);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
318
408
|
}
|
|
319
409
|
|
package/src/commands/serve.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { findProjectRoot, loadProjectConfig, startActionDockServer } from "@actiondock/core";
|
|
3
|
+
import { createActionDockMcpServer } from "@actiondock/mcp";
|
|
4
|
+
import { createMcpHandler } from "@modelcontextprotocol/server";
|
|
3
5
|
import { Command } from "commander";
|
|
4
6
|
import { parseByteSize } from "../utils/bytes";
|
|
5
7
|
|
|
@@ -19,6 +21,7 @@ export function registerServeCommand(program: Command): void {
|
|
|
19
21
|
)
|
|
20
22
|
.option("--max-body <size>", "Maximum allowed JSON request body size (e.g. 1mb, 500kb)", "1mb")
|
|
21
23
|
.option("--expose-debug-info", "Expose project root path in health and info responses")
|
|
24
|
+
.option("--no-mcp", "Disable unified MCP protocol endpoint at /mcp")
|
|
22
25
|
.option("-d, --dir <path>", "Project root directory (default: current working directory)")
|
|
23
26
|
.action(async (options) => {
|
|
24
27
|
const port = parseInt(options.port, 10) || 5177;
|
|
@@ -55,6 +58,30 @@ export function registerServeCommand(program: Command): void {
|
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
let mcpHandler: ((req: Request) => Promise<Response | null | undefined>) | undefined;
|
|
62
|
+
const enableMcp = options.mcp !== false;
|
|
63
|
+
if (enableMcp) {
|
|
64
|
+
try {
|
|
65
|
+
const handler = createMcpHandler(
|
|
66
|
+
() => {
|
|
67
|
+
return createActionDockMcpServer({
|
|
68
|
+
projectRoot: projectRoot || undefined,
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
onerror: (err) => {
|
|
73
|
+
process.stderr.write(`[MCP HTTP Error] ${err?.message || String(err)}\n`);
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
mcpHandler = async (req: Request) => {
|
|
78
|
+
return handler.fetch(req);
|
|
79
|
+
};
|
|
80
|
+
} catch {
|
|
81
|
+
// 忽略 MCP 初始化异常
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
58
85
|
try {
|
|
59
86
|
const server = startActionDockServer({
|
|
60
87
|
port,
|
|
@@ -64,6 +91,8 @@ export function registerServeCommand(program: Command): void {
|
|
|
64
91
|
corsOrigins,
|
|
65
92
|
maxBodyBytes,
|
|
66
93
|
exposeDebugInfo,
|
|
94
|
+
enableMcp,
|
|
95
|
+
mcpHandler,
|
|
67
96
|
projectRoot: projectRoot || undefined,
|
|
68
97
|
});
|
|
69
98
|
|
|
@@ -79,8 +108,11 @@ export function registerServeCommand(program: Command): void {
|
|
|
79
108
|
console.log(` * CORS Origins: ${corsOrigins ? corsOrigins.join(", ") : "Disabled (Default)"}`);
|
|
80
109
|
console.log(` * Max Body Size: ${options.maxBody || "1mb"}`);
|
|
81
110
|
console.log(` * Health Endpoint: http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${server.port}/api/v1/health`);
|
|
111
|
+
if (enableMcp) {
|
|
112
|
+
console.log(` * MCP Endpoint: http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${server.port}/mcp`);
|
|
113
|
+
}
|
|
82
114
|
console.log(`======================================================\n`);
|
|
83
|
-
console.log(`Server is ready to accept remote '
|
|
115
|
+
console.log(`Server is ready to accept remote 'ad run' requests.`);
|
|
84
116
|
console.log(`Press Ctrl+C to terminate.\n`);
|
|
85
117
|
|
|
86
118
|
// Keep process running
|