@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 CHANGED
@@ -1,84 +1,110 @@
1
1
  # @actiondock/cli
2
2
 
3
- The official Command Line Interface (CLI) toolchain for ActionDock 2.0.
3
+ ActionDock 2.0 官方命令行门面工具链。
4
4
 
5
- [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.2-black?logo=bun)](https://bun.sh/)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.12.0-green?logo=node.js)](https://nodejs.org/)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue?logo=typescript)](https://www.typescriptlang.org/)
7
7
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
8
 
9
- > **Runtime requirement**: [Bun](https://bun.sh/) >= 1.2.0.
9
+ `@actiondock/cli` 提供 `ad` 命令行接口,用于开发、测试、构建、分发和运行 AI 智能体工具与技能。
10
10
 
11
- `@actiondock/cli` provides the `ad` command to develop, test, build, deploy, and export AI Agent Actions and Skills across MCP, HTTP, CLI, and standalone executables.
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
- ## Installation
22
+ ## 安装方式
16
23
 
17
- ```bash
18
- # 1. Install Bun runtime (if not already installed)
19
- npm install -g bun
24
+ 使用标准包管理器全局安装:
20
25
 
21
- # 2. Install ActionDock CLI
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
- ## Quick Start in 5 Steps
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
- # 2. Run an Action locally (outputs standard JSON envelope)
47
+ - 本地执行 Action:
48
+ ```bash
35
49
  ad run sample.greet --input '{"name": "Alice"}'
50
+ ```
36
51
 
37
- # 3. Run in-memory unit tests
52
+ - 运行单元测试:
53
+ ```bash
38
54
  ad test
55
+ ```
39
56
 
40
- # 4. Compile into a single standalone binary
41
- ad build
57
+ - 启动为 MCP 协议服务:
58
+ ```bash
59
+ ad mcp
60
+ ```
42
61
 
43
- # 5. Export as a portable Agent Skill (with SOPs)
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
- ## Command Cheat Sheet
74
+ ## 常用命令速查
50
75
 
51
- | Command | Purpose |
76
+ | 命令 | 说明 |
52
77
  |---|---|
53
- | `ad init [dir]` | Initialize an Action package scaffold |
54
- | `ad info [patterns...]` | Explore capabilities and display metadata (supports fuzzy matching and `--tree`) |
55
- | `ad doctor` | Run environment, global registry health, and project diagnostics |
56
- | `ad action list` / `ad run <id>` | List and execute Actions |
57
- | `ad playbook list` / `show` | Inspect agent task SOP Playbooks |
58
- | `ad config list` / `get` / `set` | Manage runtime configurations |
59
- | `ad state list` / `get` / `set` / `delete` / `clear` | Inspect and manage persistent state (with namespaces, TTL, and clear) |
60
- | `ad runs list` / `show` | Inspect execution history and traces |
61
- | `ad test` | Run fast unit tests |
62
- | `ad build` | Compile into a zero-dependency standalone binary |
63
- | `ad export skill` | Export Skill bundle for AI Agent platforms |
64
- | `ad link` / `unlink` | Manage global router (with live subproject auto-discovery and prune) |
65
- | `ad profile` / `ad serve` | Manage remote node profiles and start HTTP Runner |
66
- | `ad mcp` | Start ActionDock as STDIO or HTTP MCP server |
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
- ## 📖 Complete Documentation
97
+ ## 架构集成
71
98
 
72
- For the full list of flags, options, remote profiles, and advanced usage, refer to the [ActionDock Documentation Center](../../docs/README.md):
99
+ 作为顶层门面,`@actiondock/cli` 串联以下子包:
73
100
 
74
- - [CLI Reference Manual](../../docs/reference/cli.md)
75
- - [Quick Start Guide](../../docs/developer/quick-start.md)
76
- - [MCP Integration Guide](../../docs/consumer/use-as-mcp.md)
77
- - [Standalone Binary Build Guide](../../docs/developer/build-and-export.md)
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
- ## License
108
+ ## 开源协议
83
109
 
84
- [Apache-2.0](../../LICENSE) © team4u
110
+ 本项目采用 Apache-2.0 开源协议。
package/bin/ad.js CHANGED
@@ -1,4 +1,29 @@
1
- #!/usr/bin/env bun
2
- import { main } from "../src/index.js";
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.1",
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
- "bun": ">=1.2.0"
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/core": "^2.0.0",
32
- "@actiondock/mcp": "^2.0.0",
33
- "@actiondock/sdk": "^2.0.0",
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": {
@@ -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"}'`);
@@ -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
- description: itemDef.description || "",
79
- secret: isSecret,
80
- default: itemDef.default,
82
+ value: displayValue,
81
83
  status,
82
84
  source,
83
- value: isSecret && resolvedValue !== undefined ? maskSecretValue(resolvedValue) : resolvedValue,
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
- .action((key, rawValue, options) => {
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
- .action((key, options) => {
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) {
@@ -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 report = await runDoctorChecks({
13
- packageIdOrPath: options.package,
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
- console.log("[DOCTOR] ActionDock System & Project Diagnostics\n");
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}`);
@@ -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.1");
24
+ .version("2.0.3");
25
25
 
26
26
  registerInitCommand(program);
27
27
  registerInfoCommand(program);