@actiondock/cli 2.0.11 → 2.0.12
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 +15 -2
- package/bin/ad.js +13 -2
- package/dist/commands/action/create.d.ts +2 -0
- package/dist/commands/action/index.d.ts +16 -0
- package/dist/commands/action/list.d.ts +5 -0
- package/dist/commands/action/run.d.ts +4 -0
- package/dist/commands/action/show.d.ts +5 -0
- package/dist/commands/action/sync.d.ts +2 -0
- package/dist/commands/action/validate.d.ts +5 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/link.d.ts +2 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/playbook.d.ts +6 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/runs.d.ts +2 -0
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/state.d.ts +2 -0
- package/dist/commands/test.d.ts +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +745 -65708
- package/{src/utils/bytes.ts → dist/utils/bytes.d.ts} +0 -1
- package/{src/utils/filter.ts → dist/utils/filter.d.ts} +0 -1
- package/package.json +20 -15
- package/src/commands/action/create.ts +0 -129
- package/src/commands/action/index.ts +0 -27
- package/src/commands/action/list.ts +0 -247
- package/src/commands/action/run.ts +0 -197
- package/src/commands/action/show.ts +0 -128
- package/src/commands/action/sync.ts +0 -76
- package/src/commands/action/validate.ts +0 -102
- package/src/commands/build.ts +0 -56
- package/src/commands/config.ts +0 -583
- package/src/commands/doctor.ts +0 -84
- package/src/commands/export.ts +0 -196
- package/src/commands/index.ts +0 -75
- package/src/commands/info.ts +0 -537
- package/src/commands/init.ts +0 -24
- package/src/commands/link.ts +0 -73
- package/src/commands/mcp.ts +0 -195
- package/src/commands/playbook.ts +0 -566
- package/src/commands/profile.ts +0 -296
- package/src/commands/runs.ts +0 -452
- package/src/commands/serve.ts +0 -132
- package/src/commands/state.ts +0 -590
- package/src/commands/test.ts +0 -48
- package/src/index.ts +0 -58
- /package/{src/commands/action.ts → dist/commands/action.d.ts} +0 -0
- /package/{src/utils/duration.ts → dist/utils/duration.d.ts} +0 -0
package/src/commands/runs.ts
DELETED
|
@@ -1,452 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
cancelRemoteRun,
|
|
4
|
-
clearRemoteRuns,
|
|
5
|
-
createStorage,
|
|
6
|
-
fetchRemoteRun,
|
|
7
|
-
fetchRemoteRuns,
|
|
8
|
-
filterWithFallbackInfo,
|
|
9
|
-
findProjectRoot,
|
|
10
|
-
listLinkedPackages,
|
|
11
|
-
loadProjectConfig,
|
|
12
|
-
resolvePackageRoot,
|
|
13
|
-
resolveTarget,
|
|
14
|
-
} from "@actiondock/core";
|
|
15
|
-
import { Command } from "commander";
|
|
16
|
-
import { ArgumentError, CliError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
17
|
-
import { resolveIntent } from "../utils/filter";
|
|
18
|
-
|
|
19
|
-
function printRunRecord(run: any): void {
|
|
20
|
-
console.log(`Run: ${run.id}`);
|
|
21
|
-
console.log(`Action: ${run.actionId}`);
|
|
22
|
-
if (run.packageId) console.log(`Package: ${run.packageId}`);
|
|
23
|
-
console.log(`Status: ${run.status}`);
|
|
24
|
-
if (run.parentRunId) console.log(`Parent Run: ${run.parentRunId}`);
|
|
25
|
-
console.log(`Started: ${run.startedAt}`);
|
|
26
|
-
if (run.finishedAt) console.log(`Finished: ${run.finishedAt}`);
|
|
27
|
-
|
|
28
|
-
console.log("\nInput:");
|
|
29
|
-
console.log(JSON.stringify(run.input, null, 2));
|
|
30
|
-
|
|
31
|
-
if (run.output !== undefined) {
|
|
32
|
-
console.log("\nOutput:");
|
|
33
|
-
console.log(JSON.stringify(run.output, null, 2));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (run.error) {
|
|
37
|
-
console.log("\nError:");
|
|
38
|
-
console.log(JSON.stringify(run.error, null, 2));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function registerRunsCommands(program: Command): void {
|
|
43
|
-
const runsCmd = program
|
|
44
|
-
.command("runs")
|
|
45
|
-
.description("Inspect action execution history");
|
|
46
|
-
|
|
47
|
-
// runs list
|
|
48
|
-
runsCmd
|
|
49
|
-
.command("list [patterns...]")
|
|
50
|
-
.description("List recent execution records (in current project or linked packages)")
|
|
51
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
52
|
-
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
53
|
-
.option("-a, --action <actionId>", "Filter by action ID")
|
|
54
|
-
.option("-n, --limit <count>", "Maximum number of records to return", "20")
|
|
55
|
-
.option("-p, --profile <name>", "Query against a specific profile")
|
|
56
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
57
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
58
|
-
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
59
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
60
|
-
.option("--json", "Output as JSON")
|
|
61
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
62
|
-
.action(async (patterns, rawOptions, cmd) => {
|
|
63
|
-
try {
|
|
64
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
65
|
-
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
66
|
-
const shouldFallback = options.fallback !== false;
|
|
67
|
-
const limit = Number.parseInt(options.limit, 10) || 20;
|
|
68
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
69
|
-
|
|
70
|
-
const target = resolveTarget({
|
|
71
|
-
profile: options.profile,
|
|
72
|
-
server: options.server,
|
|
73
|
-
token: options.token,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (target.type === "remote") {
|
|
77
|
-
const res = await fetchRemoteRuns(target.serverUrl!, target.token, {
|
|
78
|
-
packageId: options.package,
|
|
79
|
-
actionId: options.action,
|
|
80
|
-
intent: effectiveIntent,
|
|
81
|
-
limit,
|
|
82
|
-
});
|
|
83
|
-
if (isMachine) {
|
|
84
|
-
renderResult(res.items, { json: options.json, envelope: options.envelope });
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
console.log(
|
|
88
|
-
`Execution Runs on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""} (${res.items.length}):\n`
|
|
89
|
-
);
|
|
90
|
-
console.log(
|
|
91
|
-
` ${"RUN ID".padEnd(38)} ${"ACTION".padEnd(24)} ${"STATUS".padEnd(10)} ${"STARTED"}`
|
|
92
|
-
);
|
|
93
|
-
console.log(" " + "-".repeat(90));
|
|
94
|
-
for (const r of res.items) {
|
|
95
|
-
const time = (r.startedAt || "").replace("T", " ").slice(0, 19);
|
|
96
|
-
console.log(
|
|
97
|
-
` ${r.id.padEnd(38)} ${r.actionId.padEnd(24)} ${r.status.padEnd(10)} ${time}`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const targetRoot = options.package
|
|
104
|
-
? resolvePackageRoot(options.package)
|
|
105
|
-
: findProjectRoot();
|
|
106
|
-
|
|
107
|
-
if (options.package && !targetRoot) {
|
|
108
|
-
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (targetRoot) {
|
|
112
|
-
const projConfig = loadProjectConfig(targetRoot);
|
|
113
|
-
const storage = createStorage(projConfig.id, {
|
|
114
|
-
projectRoot: targetRoot,
|
|
115
|
-
dataDir: options.dataDir,
|
|
116
|
-
});
|
|
117
|
-
const records = storage.listRuns({
|
|
118
|
-
actionId: options.action,
|
|
119
|
-
limit,
|
|
120
|
-
});
|
|
121
|
-
storage.close();
|
|
122
|
-
|
|
123
|
-
const filterRes = filterWithFallbackInfo(
|
|
124
|
-
records,
|
|
125
|
-
effectiveIntent,
|
|
126
|
-
[(r) => r.id, (r) => r.actionId, (r) => r.status, (r) => r.error?.message],
|
|
127
|
-
shouldFallback
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (isMachine) {
|
|
131
|
-
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
132
|
-
} else {
|
|
133
|
-
console.log(`Execution Runs in ${projConfig.id} (${filterRes.items.length}):\n`);
|
|
134
|
-
if (filterRes.isFallback && effectiveIntent) {
|
|
135
|
-
console.log(`(No runs matched intent '${effectiveIntent}', showing all runs)\n`);
|
|
136
|
-
}
|
|
137
|
-
console.log(
|
|
138
|
-
` ${"RUN ID".padEnd(38)} ${"ACTION".padEnd(24)} ${"STATUS".padEnd(10)} ${"STARTED"}`
|
|
139
|
-
);
|
|
140
|
-
console.log(" " + "-".repeat(90));
|
|
141
|
-
for (const r of filterRes.items) {
|
|
142
|
-
const time = r.startedAt.replace("T", " ").slice(0, 19);
|
|
143
|
-
console.log(
|
|
144
|
-
` ${r.id.padEnd(38)} ${r.actionId.padEnd(24)} ${r.status.padEnd(10)} ${time}`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Outside project: List recent runs across all linked packages
|
|
152
|
-
const linkedList = listLinkedPackages();
|
|
153
|
-
if (linkedList.length === 0) {
|
|
154
|
-
if (isMachine) {
|
|
155
|
-
renderResult([], { json: options.json, envelope: options.envelope });
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
console.log("No ActionDock project in current directory, and no packages linked.");
|
|
159
|
-
console.log("Run 'ad link' inside an Action package to register it.");
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
let allRecords: any[] = [];
|
|
164
|
-
for (const pkg of linkedList) {
|
|
165
|
-
if (!existsSync(pkg.path)) continue;
|
|
166
|
-
try {
|
|
167
|
-
const projConfig = loadProjectConfig(pkg.path);
|
|
168
|
-
const storage = createStorage(projConfig.id, {
|
|
169
|
-
projectRoot: pkg.path,
|
|
170
|
-
dataDir: options.dataDir,
|
|
171
|
-
});
|
|
172
|
-
const records = storage.listRuns({
|
|
173
|
-
actionId: options.action,
|
|
174
|
-
limit,
|
|
175
|
-
});
|
|
176
|
-
storage.close();
|
|
177
|
-
for (const r of records) {
|
|
178
|
-
allRecords.push({ ...r, packageId: projConfig.id });
|
|
179
|
-
}
|
|
180
|
-
} catch {
|
|
181
|
-
// Ignore broken linked package
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Sort by startedAt desc
|
|
186
|
-
allRecords.sort((a, b) => (b.startedAt > a.startedAt ? 1 : b.startedAt < a.startedAt ? -1 : 0));
|
|
187
|
-
allRecords = allRecords.slice(0, limit);
|
|
188
|
-
|
|
189
|
-
const filterRes = filterWithFallbackInfo(
|
|
190
|
-
allRecords,
|
|
191
|
-
effectiveIntent,
|
|
192
|
-
[(r) => r.id, (r) => r.actionId, (r) => r.packageId, (r) => r.status, (r) => r.error?.message],
|
|
193
|
-
shouldFallback
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
if (isMachine) {
|
|
197
|
-
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
198
|
-
} else {
|
|
199
|
-
console.log(`Execution Runs across Linked Packages (${filterRes.items.length}):\n`);
|
|
200
|
-
if (filterRes.isFallback && effectiveIntent) {
|
|
201
|
-
console.log(`(No runs matched intent '${effectiveIntent}', showing all runs)\n`);
|
|
202
|
-
}
|
|
203
|
-
console.log(
|
|
204
|
-
` ${"RUN ID".padEnd(38)} ${"PACKAGE".padEnd(20)} ${"ACTION".padEnd(22)} ${"STATUS".padEnd(10)} ${"STARTED"}`
|
|
205
|
-
);
|
|
206
|
-
console.log(" " + "-".repeat(110));
|
|
207
|
-
for (const r of filterRes.items) {
|
|
208
|
-
const time = r.startedAt.replace("T", " ").slice(0, 19);
|
|
209
|
-
console.log(
|
|
210
|
-
` ${r.id.padEnd(38)} ${(r.packageId || "").padEnd(20)} ${r.actionId.padEnd(22)} ${r.status.padEnd(10)} ${time}`
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
} catch (err: any) {
|
|
215
|
-
if (err instanceof CliError) {
|
|
216
|
-
throw err;
|
|
217
|
-
}
|
|
218
|
-
throw new ExecutionError(err.message);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// runs show
|
|
223
|
-
runsCmd
|
|
224
|
-
.command("show <id>")
|
|
225
|
-
.description("Show details of a specific execution run (searches current project or linked packages)")
|
|
226
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
227
|
-
.option("-p, --profile <name>", "Query run against a specific profile")
|
|
228
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
229
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
230
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
231
|
-
.option("--json", "Output as JSON")
|
|
232
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
233
|
-
.action(async (id, rawOptions, cmd) => {
|
|
234
|
-
let target;
|
|
235
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
236
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
237
|
-
try {
|
|
238
|
-
target = resolveTarget({
|
|
239
|
-
profile: options.profile,
|
|
240
|
-
server: options.server,
|
|
241
|
-
token: options.token,
|
|
242
|
-
});
|
|
243
|
-
} catch (err: any) {
|
|
244
|
-
throw new ExecutionError(err.message);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (target.type === "remote") {
|
|
248
|
-
try {
|
|
249
|
-
const run = await fetchRemoteRun(target.serverUrl!, id, target.token);
|
|
250
|
-
if (isMachine) {
|
|
251
|
-
renderResult(run, { json: options.json, envelope: options.envelope });
|
|
252
|
-
} else {
|
|
253
|
-
printRunRecord(run);
|
|
254
|
-
}
|
|
255
|
-
return;
|
|
256
|
-
} catch (err: any) {
|
|
257
|
-
throw new ExecutionError(err.message);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Local show
|
|
262
|
-
try {
|
|
263
|
-
let foundRun: any = null;
|
|
264
|
-
|
|
265
|
-
if (options.package) {
|
|
266
|
-
const targetRoot = resolvePackageRoot(options.package);
|
|
267
|
-
if (!targetRoot) {
|
|
268
|
-
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
269
|
-
}
|
|
270
|
-
const projConfig = loadProjectConfig(targetRoot);
|
|
271
|
-
const storage = createStorage(projConfig.id, {
|
|
272
|
-
projectRoot: targetRoot,
|
|
273
|
-
dataDir: options.dataDir,
|
|
274
|
-
});
|
|
275
|
-
foundRun = storage.getRun(id);
|
|
276
|
-
storage.close();
|
|
277
|
-
if (foundRun && !foundRun.packageId) {
|
|
278
|
-
foundRun.packageId = projConfig.id;
|
|
279
|
-
}
|
|
280
|
-
} else {
|
|
281
|
-
// 1. Try current project root if exists
|
|
282
|
-
const currentRoot = findProjectRoot();
|
|
283
|
-
if (currentRoot) {
|
|
284
|
-
try {
|
|
285
|
-
const projConfig = loadProjectConfig(currentRoot);
|
|
286
|
-
const storage = createStorage(projConfig.id, {
|
|
287
|
-
projectRoot: currentRoot,
|
|
288
|
-
dataDir: options.dataDir,
|
|
289
|
-
});
|
|
290
|
-
foundRun = storage.getRun(id);
|
|
291
|
-
storage.close();
|
|
292
|
-
if (foundRun && !foundRun.packageId) {
|
|
293
|
-
foundRun.packageId = projConfig.id;
|
|
294
|
-
}
|
|
295
|
-
} catch {}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// 2. If not found in current project, search across all linked packages
|
|
299
|
-
if (!foundRun) {
|
|
300
|
-
const linkedList = listLinkedPackages();
|
|
301
|
-
for (const pkg of linkedList) {
|
|
302
|
-
if (!existsSync(pkg.path)) continue;
|
|
303
|
-
try {
|
|
304
|
-
const projConfig = loadProjectConfig(pkg.path);
|
|
305
|
-
const storage = createStorage(projConfig.id, {
|
|
306
|
-
projectRoot: pkg.path,
|
|
307
|
-
dataDir: options.dataDir,
|
|
308
|
-
});
|
|
309
|
-
const r = storage.getRun(id);
|
|
310
|
-
storage.close();
|
|
311
|
-
if (r) {
|
|
312
|
-
foundRun = { ...r, packageId: projConfig.id };
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
} catch {}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (!foundRun) {
|
|
321
|
-
throw new ExecutionError(`Run record '${id}' not found in current project or any linked packages`);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (isMachine) {
|
|
325
|
-
renderResult(foundRun, { json: options.json, envelope: options.envelope });
|
|
326
|
-
} else {
|
|
327
|
-
printRunRecord(foundRun);
|
|
328
|
-
}
|
|
329
|
-
} catch (err: any) {
|
|
330
|
-
if (err instanceof CliError) {
|
|
331
|
-
throw err;
|
|
332
|
-
}
|
|
333
|
-
throw new ExecutionError(err.message);
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// runs cancel
|
|
338
|
-
runsCmd
|
|
339
|
-
.command("cancel <id>")
|
|
340
|
-
.description("Cancel a running action execution on a remote server")
|
|
341
|
-
.option("-p, --profile <name>", "Execute cancel against a specific profile")
|
|
342
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
343
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
344
|
-
.option("-r, --reason <reason>", "Reason for cancellation")
|
|
345
|
-
.option("--json", "Output as JSON")
|
|
346
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
347
|
-
.action(async (id, rawOptions, cmd) => {
|
|
348
|
-
let target;
|
|
349
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
350
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
351
|
-
try {
|
|
352
|
-
target = resolveTarget({
|
|
353
|
-
profile: options.profile,
|
|
354
|
-
server: options.server,
|
|
355
|
-
token: options.token,
|
|
356
|
-
});
|
|
357
|
-
} catch (err: any) {
|
|
358
|
-
throw new ExecutionError(err.message);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (target.type === "local") {
|
|
362
|
-
throw new ArgumentError(
|
|
363
|
-
"'ad runs cancel' is only supported for remote execution targets. Use --profile <name> or --server <url>."
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
try {
|
|
368
|
-
const result = await cancelRemoteRun(
|
|
369
|
-
target.serverUrl!,
|
|
370
|
-
id,
|
|
371
|
-
target.token,
|
|
372
|
-
options.reason
|
|
373
|
-
);
|
|
374
|
-
if (isMachine) {
|
|
375
|
-
renderResult(result, { json: options.json, envelope: options.envelope });
|
|
376
|
-
} else {
|
|
377
|
-
console.log(`Run '${id}' cancellation requested (Status: ${result.status}).`);
|
|
378
|
-
}
|
|
379
|
-
} catch (err: any) {
|
|
380
|
-
throw new ExecutionError(err.message);
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// runs clear
|
|
385
|
-
runsCmd
|
|
386
|
-
.command("clear")
|
|
387
|
-
.description("Clear execution run records (locally or on remote server)")
|
|
388
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
389
|
-
.option("-a, --action <actionId>", "Filter by action ID")
|
|
390
|
-
.option("-p, --profile <name>", "Target profile")
|
|
391
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
392
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
393
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
394
|
-
.option("--json", "Output as JSON")
|
|
395
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
396
|
-
.action(async (rawOptions, cmd) => {
|
|
397
|
-
try {
|
|
398
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
399
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
400
|
-
const target = resolveTarget({
|
|
401
|
-
profile: options.profile,
|
|
402
|
-
server: options.server,
|
|
403
|
-
token: options.token,
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
if (target.type === "remote") {
|
|
407
|
-
const res = await clearRemoteRuns(target.serverUrl!, target.token, {
|
|
408
|
-
packageId: options.package,
|
|
409
|
-
actionId: options.action,
|
|
410
|
-
});
|
|
411
|
-
if (isMachine) {
|
|
412
|
-
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
413
|
-
} else {
|
|
414
|
-
console.log(`Cleared ${res.clearedCount} execution run(s) on remote server.`);
|
|
415
|
-
}
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const targetRoot = options.package
|
|
420
|
-
? resolvePackageRoot(options.package)
|
|
421
|
-
: findProjectRoot();
|
|
422
|
-
|
|
423
|
-
if (options.package && !targetRoot) {
|
|
424
|
-
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (targetRoot) {
|
|
428
|
-
const projConfig = loadProjectConfig(targetRoot);
|
|
429
|
-
const storage = createStorage(projConfig.id, {
|
|
430
|
-
projectRoot: targetRoot,
|
|
431
|
-
dataDir: options.dataDir,
|
|
432
|
-
});
|
|
433
|
-
const count = storage.clearRuns({ actionId: options.action });
|
|
434
|
-
storage.close();
|
|
435
|
-
if (isMachine) {
|
|
436
|
-
renderResult({ ok: true, clearedCount: count, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
437
|
-
} else {
|
|
438
|
-
console.log(`Cleared ${count} execution run(s) in package '${projConfig.id}'.`);
|
|
439
|
-
}
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
throw new ArgumentError(
|
|
444
|
-
"Not in an ActionDock project. Please specify -P, --package <id> or cd into a project directory."
|
|
445
|
-
);
|
|
446
|
-
} catch (err: any) {
|
|
447
|
-
if (err instanceof CliError) throw err;
|
|
448
|
-
throw new ExecutionError(err.message);
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
|
package/src/commands/serve.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
|
-
import { findProjectRoot, loadProjectConfig, startActionDockServer } from "@actiondock/core";
|
|
3
|
-
import { createActionDockMcpServer } from "@actiondock/mcp";
|
|
4
|
-
import { createMcpHandler } from "@modelcontextprotocol/server";
|
|
5
|
-
import { Command } from "commander";
|
|
6
|
-
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
7
|
-
import { parseByteSize } from "../utils/bytes";
|
|
8
|
-
|
|
9
|
-
export function registerServeCommand(program: Command): void {
|
|
10
|
-
program
|
|
11
|
-
.command("serve")
|
|
12
|
-
.description("Start the ActionDock lightweight HTTP Runner server for remote execution")
|
|
13
|
-
.option("-p, --port <port>", "Port to listen on (default: 5177)", "5177")
|
|
14
|
-
.option("-H, --host <host>", "Host address to bind to (default: 127.0.0.1)", "127.0.0.1")
|
|
15
|
-
.option("-t, --token <token>", "Authentication token for securing the endpoint (or set ACTIONDOCK_TOKEN)")
|
|
16
|
-
.option("--allow-insecure-no-auth", "Allow non-loopback host binding without authentication token (INSECURE)")
|
|
17
|
-
.option(
|
|
18
|
-
"--cors-origin <origin>",
|
|
19
|
-
"Allowed CORS origin (can be specified multiple times)",
|
|
20
|
-
(val: string, prev: string[] = []) => [...prev, val],
|
|
21
|
-
[]
|
|
22
|
-
)
|
|
23
|
-
.option("--max-body <size>", "Maximum allowed JSON request body size (e.g. 1mb, 500kb)", "1mb")
|
|
24
|
-
.option("--expose-debug-info", "Expose project root path in health and info responses")
|
|
25
|
-
.option("--no-mcp", "Disable unified MCP protocol endpoint at /mcp")
|
|
26
|
-
.option("-d, --dir <path>", "Project root directory (default: current working directory)")
|
|
27
|
-
.action(async (options) => {
|
|
28
|
-
const port = parseInt(options.port, 10) || 5177;
|
|
29
|
-
const host = options.host || "127.0.0.1";
|
|
30
|
-
const token = options.token || process.env.ACTIONDOCK_TOKEN;
|
|
31
|
-
const allowInsecureNoAuth = Boolean(options.allowInsecureNoAuth);
|
|
32
|
-
const corsOrigins = options.corsOrigin && options.corsOrigin.length > 0 ? options.corsOrigin : undefined;
|
|
33
|
-
const exposeDebugInfo = Boolean(options.exposeDebugInfo);
|
|
34
|
-
|
|
35
|
-
let maxBodyBytes: number | undefined;
|
|
36
|
-
if (options.maxBody) {
|
|
37
|
-
try {
|
|
38
|
-
maxBodyBytes = parseByteSize(options.maxBody);
|
|
39
|
-
} catch (err: any) {
|
|
40
|
-
throw new ExecutionError(err.message);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const projectRoot = options.dir
|
|
45
|
-
? resolve(options.dir)
|
|
46
|
-
: findProjectRoot(process.cwd());
|
|
47
|
-
|
|
48
|
-
let projectName = "Global Registry Mode";
|
|
49
|
-
let packageId = "none";
|
|
50
|
-
|
|
51
|
-
if (projectRoot) {
|
|
52
|
-
try {
|
|
53
|
-
const config = loadProjectConfig(projectRoot);
|
|
54
|
-
projectName = `${config.name} (${config.id})`;
|
|
55
|
-
packageId = config.id;
|
|
56
|
-
} catch {
|
|
57
|
-
// fallback
|
|
58
|
-
}
|
|
59
|
-
}
|
|
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
|
-
|
|
85
|
-
try {
|
|
86
|
-
const server = startActionDockServer({
|
|
87
|
-
port,
|
|
88
|
-
host,
|
|
89
|
-
token,
|
|
90
|
-
allowInsecureNoAuth,
|
|
91
|
-
corsOrigins,
|
|
92
|
-
maxBodyBytes,
|
|
93
|
-
exposeDebugInfo,
|
|
94
|
-
enableMcp,
|
|
95
|
-
mcpHandler,
|
|
96
|
-
projectRoot: projectRoot || undefined,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
console.log(`\n======================================================`);
|
|
100
|
-
console.log(` ActionDock 2.0 HTTP Runner Server`);
|
|
101
|
-
console.log(`======================================================`);
|
|
102
|
-
console.log(` * Listening on: http://${host}:${server.port}`);
|
|
103
|
-
console.log(` * Project: ${projectName}`);
|
|
104
|
-
if (projectRoot && exposeDebugInfo) {
|
|
105
|
-
console.log(` * Root Path: ${projectRoot}`);
|
|
106
|
-
}
|
|
107
|
-
console.log(` * Authentication: ${token ? "Bearer Token / Query Token Enabled" : "Disabled (Public/Local)"}`);
|
|
108
|
-
console.log(` * CORS Origins: ${corsOrigins ? corsOrigins.join(", ") : "Disabled (Default)"}`);
|
|
109
|
-
console.log(` * Max Body Size: ${options.maxBody || "1mb"}`);
|
|
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
|
-
}
|
|
114
|
-
console.log(`======================================================\n`);
|
|
115
|
-
console.log(`Server is ready to accept remote 'ad run' requests.`);
|
|
116
|
-
console.log(`Press Ctrl+C to terminate.\n`);
|
|
117
|
-
|
|
118
|
-
// Keep process running
|
|
119
|
-
process.on("SIGINT", () => {
|
|
120
|
-
console.log("\nStopping ActionDock server...");
|
|
121
|
-
server.stop();
|
|
122
|
-
process.exit(0);
|
|
123
|
-
});
|
|
124
|
-
process.on("SIGTERM", () => {
|
|
125
|
-
server.stop();
|
|
126
|
-
process.exit(0);
|
|
127
|
-
});
|
|
128
|
-
} catch (err: any) {
|
|
129
|
-
throw new ExecutionError(`Failed to start ActionDock server: ${err.message}`);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
}
|