@actiondock/cli 2.0.1 → 2.0.3
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 +67 -41
- package/bin/ad.js +27 -2
- package/package.json +8 -5
- package/src/commands/action.ts +32 -1
- package/src/commands/config.ts +96 -10
- package/src/commands/doctor.ts +24 -6
- package/src/commands/index.ts +1 -1
- package/src/commands/info.ts +94 -115
- package/src/commands/playbook.ts +84 -5
- package/src/commands/profile.ts +1 -1
- package/src/commands/runs.ts +91 -1
- package/src/commands/serve.ts +32 -0
- package/src/commands/state.ts +124 -11
- package/src/commands/test.ts +29 -7
- package/src/index.ts +5 -3
package/README.md
CHANGED
|
@@ -1,84 +1,110 @@
|
|
|
1
1
|
# @actiondock/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ActionDock 2.0 官方命令行门面工具链。
|
|
4
4
|
|
|
5
|
-
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`@actiondock/cli` 提供 `ad` 命令行接口,用于开发、测试、构建、分发和运行 AI 智能体工具与技能。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 运行环境
|
|
14
|
+
|
|
15
|
+
- 原生基于 Node.js 22.12.0 或更高版本运行。
|
|
16
|
+
- 支持 npm、pnpm 与 yarn 进行全局安装或项目级管理。
|
|
17
|
+
- 日常开发、调试、测试、MCP 服务启动与 HTTP 部署完全基于 Node.js,无需安装 Bun。
|
|
18
|
+
- 仅在使用 `ad build` 编译单文件独立二进制产物时,需要系统安装外部 Bun 编译器。
|
|
12
19
|
|
|
13
20
|
---
|
|
14
21
|
|
|
15
|
-
##
|
|
22
|
+
## 安装方式
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
# 1. Install Bun runtime (if not already installed)
|
|
19
|
-
npm install -g bun
|
|
24
|
+
使用标准包管理器全局安装:
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
```bash
|
|
22
27
|
npm install -g @actiondock/cli
|
|
23
28
|
```
|
|
24
29
|
|
|
30
|
+
也可以在项目中通过 npx 临时调用:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx ad --help
|
|
34
|
+
```
|
|
35
|
+
|
|
25
36
|
---
|
|
26
37
|
|
|
27
|
-
##
|
|
38
|
+
## 快速上手流程
|
|
28
39
|
|
|
40
|
+
- 初始化项目脚手架:
|
|
29
41
|
```bash
|
|
30
|
-
# 1. Initialize a new Action package scaffold
|
|
31
42
|
ad init my-tools
|
|
32
43
|
cd my-tools
|
|
44
|
+
npm install
|
|
45
|
+
```
|
|
33
46
|
|
|
34
|
-
|
|
47
|
+
- 本地执行 Action:
|
|
48
|
+
```bash
|
|
35
49
|
ad run sample.greet --input '{"name": "Alice"}'
|
|
50
|
+
```
|
|
36
51
|
|
|
37
|
-
|
|
52
|
+
- 运行单元测试:
|
|
53
|
+
```bash
|
|
38
54
|
ad test
|
|
55
|
+
```
|
|
39
56
|
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
- 启动为 MCP 协议服务:
|
|
58
|
+
```bash
|
|
59
|
+
ad mcp
|
|
60
|
+
```
|
|
42
61
|
|
|
43
|
-
|
|
62
|
+
- 导出为便携式 Agent Skill 技能包:
|
|
63
|
+
```bash
|
|
44
64
|
ad export skill
|
|
45
65
|
```
|
|
46
66
|
|
|
67
|
+
- 编译为零依赖单文件独立二进制产物(需外部安装 Bun):
|
|
68
|
+
```bash
|
|
69
|
+
ad build
|
|
70
|
+
```
|
|
71
|
+
|
|
47
72
|
---
|
|
48
73
|
|
|
49
|
-
##
|
|
74
|
+
## 常用命令速查
|
|
50
75
|
|
|
51
|
-
|
|
|
76
|
+
| 命令 | 说明 |
|
|
52
77
|
|---|---|
|
|
53
|
-
| `ad init [dir]` |
|
|
54
|
-
| `ad info [patterns...]` |
|
|
55
|
-
| `ad doctor` |
|
|
56
|
-
| `ad
|
|
57
|
-
| `ad
|
|
58
|
-
| `ad
|
|
59
|
-
| `ad
|
|
60
|
-
| `ad
|
|
61
|
-
| `ad
|
|
62
|
-
| `ad
|
|
63
|
-
| `ad
|
|
64
|
-
| `ad
|
|
65
|
-
| `ad
|
|
66
|
-
| `ad
|
|
78
|
+
| `ad init [dir]` | 初始化 Action Package 项目脚手架 |
|
|
79
|
+
| `ad info [patterns...]` | 检索包元数据与能力清单,支持模式匹配与树形展示 |
|
|
80
|
+
| `ad doctor` | 执行运行环境与项目结构健康诊断 |
|
|
81
|
+
| `ad run <id>` | 本地执行指定 Action 并输出标准信封结果 |
|
|
82
|
+
| `ad action list` | 列出包内所有已注册的 Action |
|
|
83
|
+
| `ad playbook list` / `show` | 查看智能体操作规程 Playbook |
|
|
84
|
+
| `ad config list` / `get` / `set` | 管理包运行时配置与环境变量绑定 |
|
|
85
|
+
| `ad state list` / `get` / `set` / `delete` / `clear` | 查看与维护 SQLite 持久化状态 |
|
|
86
|
+
| `ad runs list` / `show` | 查询任务执行历史与追踪记录 |
|
|
87
|
+
| `ad test` | 执行快速单元测试 |
|
|
88
|
+
| `ad build` | 调度外部 Bun 编译器打包单文件独立二进制产物 |
|
|
89
|
+
| `ad export skill` | 导出包含操作规程的 Agent Skill 技能包 |
|
|
90
|
+
| `ad link` / `unlink` | 注册或注销工作区全局路由与符号链接 |
|
|
91
|
+
| `ad profile` | 管理远程执行节点凭证与环境配置 |
|
|
92
|
+
| `ad serve` | 启动远程 HTTP 执行调度微服务 |
|
|
93
|
+
| `ad mcp` | 以 STDIO 或 HTTP 协议启动 MCP 服务 |
|
|
67
94
|
|
|
68
95
|
---
|
|
69
96
|
|
|
70
|
-
##
|
|
97
|
+
## 架构集成
|
|
71
98
|
|
|
72
|
-
|
|
99
|
+
作为顶层门面,`@actiondock/cli` 串联以下子包:
|
|
73
100
|
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
- [Agent Skill Usage Guide](../../docs/consumer/use-as-skill.md)
|
|
101
|
+
- 运行时适配:依赖 `@actiondock/runtime-node`,在启动时自动注入基于 Node.js 原生能力的驱动实现。
|
|
102
|
+
- 共享命令集:复用 `@actiondock/runtime-cli` 的命令处理器与标准信封输出渲染器。
|
|
103
|
+
- 构建与打包:调用 `@actiondock/builder` 完成依赖闭包分析与产物装配。
|
|
104
|
+
- 协议服务:通过 `@actiondock/mcp` 与 `@actiondock/core` 启动协议监听。
|
|
79
105
|
|
|
80
106
|
---
|
|
81
107
|
|
|
82
|
-
##
|
|
108
|
+
## 开源协议
|
|
83
109
|
|
|
84
|
-
|
|
110
|
+
本项目采用 Apache-2.0 开源协议。
|
package/bin/ad.js
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
import {
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
|
|
5
|
+
const isBun = typeof process.versions.bun !== "undefined";
|
|
6
|
+
|
|
7
|
+
if (!isBun && !process.env.ACTIONDOCK_TSX_BOOTSTRAPPED) {
|
|
8
|
+
const hasTsx =
|
|
9
|
+
process.execArgv.some((arg, i) => arg === "--import" && process.execArgv[i + 1] === "tsx") ||
|
|
10
|
+
process.execArgv.some((arg) => arg.includes("tsx"));
|
|
11
|
+
if (!hasTsx) {
|
|
12
|
+
const res = spawnSync(
|
|
13
|
+
process.execPath,
|
|
14
|
+
["--import", "tsx", fileURLToPath(import.meta.url), ...process.argv.slice(2)],
|
|
15
|
+
{
|
|
16
|
+
stdio: "inherit",
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
ACTIONDOCK_TSX_BOOTSTRAPPED: "1",
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
process.exit(res.status ?? (res.signal ? 1 : 0));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { main } = await import("../src/index.ts");
|
|
4
28
|
await main(process.argv);
|
|
29
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "ActionDock CLI facade for developing, testing, building, and exporting standalone Agent Actions and Skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"
|
|
20
|
+
"node": ">=22.12.0"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public",
|
|
@@ -28,9 +28,12 @@
|
|
|
28
28
|
"build": "bun build ./src/index.ts --outdir ./dist --target bun"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@actiondock/
|
|
32
|
-
"@actiondock/
|
|
33
|
-
"@actiondock/
|
|
31
|
+
"@actiondock/builder": "workspace:*",
|
|
32
|
+
"@actiondock/core": "workspace:*",
|
|
33
|
+
"@actiondock/mcp": "workspace:*",
|
|
34
|
+
"@actiondock/runtime-cli": "workspace:*",
|
|
35
|
+
"@actiondock/runtime-node": "workspace:*",
|
|
36
|
+
"@actiondock/sdk": "workspace:*",
|
|
34
37
|
"commander": "^13.1.0"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
package/src/commands/action.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import {
|
|
4
4
|
ActionRunner,
|
|
5
5
|
createStorage,
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
11
11
|
getPackageSlug,
|
|
12
12
|
listLinkedPackages,
|
|
13
13
|
loadActions,
|
|
14
|
+
loadManifest,
|
|
14
15
|
loadProjectConfig,
|
|
15
16
|
resolveActionProject,
|
|
16
17
|
resolveTarget,
|
|
18
|
+
saveManifest,
|
|
17
19
|
validateSchema,
|
|
18
20
|
} from "@actiondock/core";
|
|
19
21
|
import { Command } from "commander";
|
|
@@ -281,6 +283,35 @@ export default defineAction<Input, Output>({
|
|
|
281
283
|
`;
|
|
282
284
|
|
|
283
285
|
writeFileSync(targetFullFile, template, "utf-8");
|
|
286
|
+
|
|
287
|
+
const manifest = loadManifest(root) || { schemaVersion: 1, actions: {}, assets: [] };
|
|
288
|
+
manifest.actions = manifest.actions || {};
|
|
289
|
+
manifest.actions[id] = {
|
|
290
|
+
entry: join(config.actionsDir || "actions", targetRelFile),
|
|
291
|
+
description: desc,
|
|
292
|
+
inputSchema: {
|
|
293
|
+
type: "object",
|
|
294
|
+
properties: {
|
|
295
|
+
exampleParam: {
|
|
296
|
+
type: "string",
|
|
297
|
+
description: "Example parameter description",
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
required: [],
|
|
301
|
+
},
|
|
302
|
+
outputSchema: {
|
|
303
|
+
type: "object",
|
|
304
|
+
properties: {
|
|
305
|
+
success: { type: "boolean" },
|
|
306
|
+
result: {},
|
|
307
|
+
},
|
|
308
|
+
required: ["success"],
|
|
309
|
+
},
|
|
310
|
+
uses: [],
|
|
311
|
+
tags: [],
|
|
312
|
+
};
|
|
313
|
+
saveManifest(root, manifest);
|
|
314
|
+
|
|
284
315
|
console.log(`[OK] Created Action '${id}' at ${targetFullFile}`);
|
|
285
316
|
console.log(`\nTo run this action:`);
|
|
286
317
|
console.log(` ad action run ${id} --input '{"exampleParam": "hello"}'`);
|
package/src/commands/config.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createGlobalStorage,
|
|
3
3
|
createStorage,
|
|
4
|
+
deleteRemoteConfig,
|
|
5
|
+
fetchRemoteConfig,
|
|
4
6
|
filterWithFallbackInfo,
|
|
5
7
|
isSecretConfigKey,
|
|
6
8
|
loadProjectConfig,
|
|
7
9
|
maskSecretValue,
|
|
8
10
|
resolvePackageRoot,
|
|
11
|
+
resolveTarget,
|
|
12
|
+
setRemoteConfig,
|
|
9
13
|
type ConfigItemDefinition,
|
|
10
14
|
} from "@actiondock/core";
|
|
11
15
|
import { Command } from "commander";
|
|
@@ -69,18 +73,17 @@ export function registerConfigCommands(program: Command): void {
|
|
|
69
73
|
resolvedValue = itemDef.default;
|
|
70
74
|
source = "default";
|
|
71
75
|
status = "DEFAULT";
|
|
72
|
-
} else {
|
|
73
|
-
status = "MISSING";
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
const displayValue = isSecret && resolvedValue !== undefined ? maskSecretValue(resolvedValue) : resolvedValue;
|
|
79
|
+
|
|
76
80
|
return {
|
|
77
81
|
key,
|
|
78
|
-
|
|
79
|
-
secret: isSecret,
|
|
80
|
-
default: itemDef.default,
|
|
82
|
+
value: displayValue,
|
|
81
83
|
status,
|
|
82
84
|
source,
|
|
83
|
-
|
|
85
|
+
secret: isSecret,
|
|
86
|
+
description: itemDef.description || "",
|
|
84
87
|
required: itemDef.default === undefined,
|
|
85
88
|
};
|
|
86
89
|
});
|
|
@@ -141,16 +144,45 @@ export function registerConfigCommands(program: Command): void {
|
|
|
141
144
|
.description("List configuration entries (Global & Project)")
|
|
142
145
|
.option("-P, --package <id>", "Target package ID or path")
|
|
143
146
|
.option("-g, --global", "Show only global configurations")
|
|
147
|
+
.option("-p, --profile <name>", "Query config on a remote target")
|
|
148
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
149
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
144
150
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
145
151
|
.option("--reveal, --show-secrets", "Reveal plain text values for secrets")
|
|
146
152
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
147
153
|
.option("--json", "Output as JSON")
|
|
148
|
-
.action((patterns, options) => {
|
|
154
|
+
.action(async (patterns, options) => {
|
|
149
155
|
try {
|
|
150
156
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
151
157
|
const shouldFallback = options.fallback !== false;
|
|
152
158
|
const reveal = options.reveal || options.showSecrets;
|
|
153
159
|
|
|
160
|
+
const target = resolveTarget({
|
|
161
|
+
profile: options.profile,
|
|
162
|
+
server: options.server,
|
|
163
|
+
token: options.token,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (target.type === "remote") {
|
|
167
|
+
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
168
|
+
if (options.json) {
|
|
169
|
+
console.log(JSON.stringify(res, null, 2));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.log(
|
|
173
|
+
`Config on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""}:\n`
|
|
174
|
+
);
|
|
175
|
+
const entries = Object.entries(res.values || {});
|
|
176
|
+
if (entries.length === 0) {
|
|
177
|
+
console.log(" (No config entries stored)");
|
|
178
|
+
} else {
|
|
179
|
+
for (const [k, v] of entries) {
|
|
180
|
+
console.log(` ${k.padEnd(24)} = ${JSON.stringify(v)}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
154
186
|
const globalStorage = createGlobalStorage();
|
|
155
187
|
const globalConfig = globalStorage.listConfig();
|
|
156
188
|
|
|
@@ -246,10 +278,30 @@ export function registerConfigCommands(program: Command): void {
|
|
|
246
278
|
.description("Get a configuration value")
|
|
247
279
|
.option("-P, --package <id>", "Target package ID or path")
|
|
248
280
|
.option("-g, --global", "Get from global configuration only")
|
|
281
|
+
.option("-p, --profile <name>", "Query config on a remote target")
|
|
282
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
283
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
249
284
|
.option("--reveal, --show-secrets", "Reveal plain text value for secret")
|
|
250
285
|
.option("--json", "Output as JSON")
|
|
251
|
-
.action((key, options) => {
|
|
286
|
+
.action(async (key, options) => {
|
|
252
287
|
try {
|
|
288
|
+
const target = resolveTarget({
|
|
289
|
+
profile: options.profile,
|
|
290
|
+
server: options.server,
|
|
291
|
+
token: options.token,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (target.type === "remote") {
|
|
295
|
+
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
296
|
+
const val = res.values?.[key];
|
|
297
|
+
if (options.json) {
|
|
298
|
+
console.log(JSON.stringify({ key, value: val }, null, 2));
|
|
299
|
+
} else {
|
|
300
|
+
console.log(val !== undefined ? JSON.stringify(val) : "undefined");
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
253
305
|
const reveal = options.reveal || options.showSecrets;
|
|
254
306
|
const globalStorage = createGlobalStorage();
|
|
255
307
|
const globalVal = globalStorage.getConfig(key);
|
|
@@ -326,7 +378,10 @@ export function registerConfigCommands(program: Command): void {
|
|
|
326
378
|
.description("Set a configuration value (Global by default outside project, or use -g for global)")
|
|
327
379
|
.option("-P, --package <id>", "Target package ID or path")
|
|
328
380
|
.option("-g, --global", "Set globally across all packages")
|
|
329
|
-
.
|
|
381
|
+
.option("-p, --profile <name>", "Set config on a remote target")
|
|
382
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
383
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
384
|
+
.action(async (key, rawValue, options) => {
|
|
330
385
|
try {
|
|
331
386
|
let parsed: unknown = rawValue;
|
|
332
387
|
try {
|
|
@@ -335,6 +390,18 @@ export function registerConfigCommands(program: Command): void {
|
|
|
335
390
|
parsed = rawValue;
|
|
336
391
|
}
|
|
337
392
|
|
|
393
|
+
const target = resolveTarget({
|
|
394
|
+
profile: options.profile,
|
|
395
|
+
server: options.server,
|
|
396
|
+
token: options.token,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
if (target.type === "remote") {
|
|
400
|
+
await setRemoteConfig(target.serverUrl!, key, parsed, target.token, options.package);
|
|
401
|
+
console.log(`[OK] Remote config '${key}' updated on ${target.serverUrl}`);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
338
405
|
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
339
406
|
const isSecret = isSecretConfigKey(key);
|
|
340
407
|
const displayVal = isSecret ? maskSecretValue(parsed) : JSON.stringify(parsed);
|
|
@@ -366,8 +433,27 @@ export function registerConfigCommands(program: Command): void {
|
|
|
366
433
|
.description("Delete a configuration value")
|
|
367
434
|
.option("-P, --package <id>", "Target package ID or path")
|
|
368
435
|
.option("-g, --global", "Delete from global configuration")
|
|
369
|
-
.
|
|
436
|
+
.option("-p, --profile <name>", "Delete config on a remote target")
|
|
437
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
438
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
439
|
+
.action(async (key, options) => {
|
|
370
440
|
try {
|
|
441
|
+
const target = resolveTarget({
|
|
442
|
+
profile: options.profile,
|
|
443
|
+
server: options.server,
|
|
444
|
+
token: options.token,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
if (target.type === "remote") {
|
|
448
|
+
const res = await deleteRemoteConfig(target.serverUrl!, key, target.token, options.package);
|
|
449
|
+
if (res.deleted) {
|
|
450
|
+
console.log(`[OK] Remote config '${key}' deleted from ${target.serverUrl}`);
|
|
451
|
+
} else {
|
|
452
|
+
console.log(`Remote config '${key}' not found on ${target.serverUrl}`);
|
|
453
|
+
}
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
371
457
|
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
372
458
|
|
|
373
459
|
if (options.global || !projectRoot) {
|
package/src/commands/doctor.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runDoctorChecks } from "@actiondock/core";
|
|
1
|
+
import { fetchRemoteDoctor, resolveTarget, runDoctorChecks } from "@actiondock/core";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
|
|
4
4
|
export function registerDoctorCommand(program: Command): void {
|
|
@@ -6,13 +6,28 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
6
6
|
.command("doctor")
|
|
7
7
|
.description("Check ActionDock environment, registry health, and project diagnostics")
|
|
8
8
|
.option("-P, --package <id|path>", "Target package ID or directory path for project diagnostics")
|
|
9
|
+
.option("-p, --profile <name>", "Query doctor diagnostics on a remote target")
|
|
10
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
11
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
9
12
|
.option("--json", "Output diagnostics report in JSON format")
|
|
10
13
|
.action(async (options) => {
|
|
11
14
|
try {
|
|
12
|
-
const
|
|
13
|
-
|
|
15
|
+
const target = resolveTarget({
|
|
16
|
+
profile: options.profile,
|
|
17
|
+
server: options.server,
|
|
18
|
+
token: options.token,
|
|
14
19
|
});
|
|
15
20
|
|
|
21
|
+
let report;
|
|
22
|
+
if (target.type === "remote") {
|
|
23
|
+
const remoteRes = await fetchRemoteDoctor(target.serverUrl!, target.token, options.package);
|
|
24
|
+
report = remoteRes.report || remoteRes;
|
|
25
|
+
} else {
|
|
26
|
+
report = await runDoctorChecks({
|
|
27
|
+
packageIdOrPath: options.package,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
if (options.json) {
|
|
17
32
|
console.log(JSON.stringify(report, null, 2));
|
|
18
33
|
if (!report.ok) {
|
|
@@ -21,11 +36,14 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
21
36
|
return;
|
|
22
37
|
}
|
|
23
38
|
|
|
24
|
-
|
|
39
|
+
const title = target.type === "remote"
|
|
40
|
+
? `[DOCTOR] Remote ActionDock Server Diagnostics (${target.serverUrl}${target.profileName ? ` - Profile: ${target.profileName}` : ""})\n`
|
|
41
|
+
: "[DOCTOR] ActionDock System & Project Diagnostics\n";
|
|
42
|
+
console.log(title);
|
|
25
43
|
|
|
26
44
|
// 1. Runtime & Environment Group
|
|
27
45
|
console.log("[Runtime & Environment]");
|
|
28
|
-
const envChecks = report.checks.filter((c) => c.category === "runtime" || c.category === "storage" || c.category === "registry");
|
|
46
|
+
const envChecks = (report.checks || []).filter((c: any) => c.category === "runtime" || c.category === "storage" || c.category === "registry");
|
|
29
47
|
for (const c of envChecks) {
|
|
30
48
|
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
31
49
|
console.log(` ${tag} ${c.name}: ${c.message}`);
|
|
@@ -37,7 +55,7 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
37
55
|
// 2. Project Group
|
|
38
56
|
if (report.hasProject) {
|
|
39
57
|
console.log(`\n[Project: ${report.packageId || "unknown"}] (${report.projectRoot})`);
|
|
40
|
-
const projChecks = report.checks.filter((c) => c.category === "project");
|
|
58
|
+
const projChecks = (report.checks || []).filter((c: any) => c.category === "project");
|
|
41
59
|
for (const c of projChecks) {
|
|
42
60
|
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
43
61
|
console.log(` ${tag} ${c.name}: ${c.message}`);
|
package/src/commands/index.ts
CHANGED
|
@@ -21,7 +21,7 @@ export function createCliProgram(): Command {
|
|
|
21
21
|
program
|
|
22
22
|
.name("ad")
|
|
23
23
|
.description("ActionDock (ad) 2.0 - Toolchain for building and shipping standalone AI Agent Actions & Skills")
|
|
24
|
-
.version("2.0.
|
|
24
|
+
.version("2.0.3");
|
|
25
25
|
|
|
26
26
|
registerInitCommand(program);
|
|
27
27
|
registerInfoCommand(program);
|