@actiondock/cli 2.0.12 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -34
- package/bin/ad.js +28 -41
- package/dist/commands/action/create.d.ts +9 -1
- package/dist/commands/action/create.js +120 -0
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.js +144 -0
- package/dist/commands/build.d.ts +2 -1
- package/dist/commands/build.js +83 -0
- package/dist/commands/config/delete.d.ts +9 -0
- package/dist/commands/config/delete.js +52 -0
- package/dist/commands/config/env.d.ts +9 -0
- package/dist/commands/config/env.js +85 -0
- package/dist/commands/config/get.d.ts +9 -0
- package/dist/commands/config/get.js +120 -0
- package/dist/commands/config/index.d.ts +9 -0
- package/dist/commands/config/index.js +23 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.js +137 -0
- package/dist/commands/config/schema.d.ts +9 -0
- package/dist/commands/config/schema.js +121 -0
- package/dist/commands/config/set.d.ts +9 -0
- package/dist/commands/config/set.js +85 -0
- package/dist/commands/describe.d.ts +9 -0
- package/dist/commands/describe.js +68 -0
- package/dist/commands/doctor.d.ts +2 -1
- package/dist/commands/doctor.js +82 -0
- package/dist/commands/export.d.ts +2 -1
- package/dist/commands/export.js +212 -0
- package/dist/commands/generate.d.ts +9 -0
- package/dist/commands/generate.js +44 -0
- package/dist/commands/index.d.ts +31 -1
- package/dist/commands/index.js +111 -0
- package/dist/commands/info.d.ts +9 -2
- package/dist/commands/info.js +210 -0
- package/dist/commands/init.js +24 -0
- package/dist/commands/link.js +71 -0
- package/dist/commands/list.d.ts +9 -0
- package/dist/commands/list.js +77 -0
- package/dist/commands/mcp.d.ts +9 -2
- package/dist/commands/mcp.js +172 -0
- package/dist/commands/new.d.ts +9 -0
- package/dist/commands/new.js +33 -0
- package/dist/commands/pack.d.ts +3 -0
- package/dist/commands/pack.js +63 -0
- package/dist/commands/playbook.d.ts +7 -3
- package/dist/commands/playbook.js +433 -0
- package/dist/commands/profile.js +253 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.js +118 -0
- package/dist/commands/run.d.ts +13 -0
- package/dist/commands/run.js +146 -0
- package/dist/commands/runs.d.ts +9 -2
- package/dist/commands/runs.js +245 -0
- package/dist/commands/serve.d.ts +9 -2
- package/dist/commands/serve.js +129 -0
- package/dist/commands/state-list.d.ts +24 -0
- package/dist/commands/state-list.js +82 -0
- package/dist/commands/state.d.ts +9 -2
- package/dist/commands/state.js +310 -0
- package/dist/commands/test.js +44 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.js +106 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.js +103 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +41 -1000
- package/dist/prompt.d.ts +53 -0
- package/dist/prompt.js +192 -0
- package/dist/renderer.d.ts +197 -0
- package/dist/renderer.js +502 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/inspect.d.ts +23 -0
- package/dist/services/inspect.js +96 -0
- package/dist/standalone/index.d.ts +16 -0
- package/dist/standalone/index.js +22 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.js +9 -0
- package/dist/utils/bytes.d.ts +1 -1
- package/dist/utils/bytes.js +1 -0
- package/dist/utils/duration.js +1 -0
- package/dist/utils/filter.d.ts +1 -1
- package/dist/utils/filter.js +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/spawn.d.ts +27 -0
- package/dist/utils/spawn.js +35 -0
- package/dist/utils/target.d.ts +45 -0
- package/dist/utils/target.js +78 -0
- package/dist/utils/utils.d.ts +38 -0
- package/dist/utils/utils.js +111 -0
- package/package.json +10 -12
- package/dist/commands/action/index.d.ts +0 -16
- package/dist/commands/action/list.d.ts +0 -5
- package/dist/commands/action/run.d.ts +0 -4
- package/dist/commands/action/show.d.ts +0 -5
- package/dist/commands/action/sync.d.ts +0 -2
- package/dist/commands/action/validate.d.ts +0 -5
- package/dist/commands/action.d.ts +0 -1
- package/dist/commands/config.d.ts +0 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { registerActionCommands } from "./action/create.js";
|
|
5
|
+
import { registerAddCommand } from "./add.js";
|
|
6
|
+
import { registerBuildCommand } from "./build.js";
|
|
7
|
+
import { registerConfigCommands } from "./config/index.js";
|
|
8
|
+
import { registerDescribeCommand } from "./describe.js";
|
|
9
|
+
import { registerDoctorCommand } from "./doctor.js";
|
|
10
|
+
import { registerExportCommand } from "./export.js";
|
|
11
|
+
import { registerGenerateCommands } from "./generate.js";
|
|
12
|
+
import { registerInfoCommand } from "./info.js";
|
|
13
|
+
import { registerInitCommand } from "./init.js";
|
|
14
|
+
import { registerLinkCommands } from "./link.js";
|
|
15
|
+
import { registerListCommand } from "./list.js";
|
|
16
|
+
import { registerMcpCommands } from "./mcp.js";
|
|
17
|
+
import { registerNewCommands } from "./new.js";
|
|
18
|
+
import { registerPackCommand } from "./pack.js";
|
|
19
|
+
import { registerPlaybookCommands } from "./playbook.js";
|
|
20
|
+
import { registerProfileCommands } from "./profile.js";
|
|
21
|
+
import { registerRemoveCommand } from "./remove.js";
|
|
22
|
+
import { registerRunCommand } from "./run.js";
|
|
23
|
+
import { registerRunsCommands } from "./runs.js";
|
|
24
|
+
import { registerServeCommand } from "./serve.js";
|
|
25
|
+
import { registerStateCommands } from "./state.js";
|
|
26
|
+
import { registerTestCommand } from "./test.js";
|
|
27
|
+
import { registerValidateCommand } from "./validate.js";
|
|
28
|
+
/**
|
|
29
|
+
* 读取 CLI 自身 package.json 的版本号(单一事实源)。
|
|
30
|
+
* 兼容源码运行(src/commands)与构建产物运行(dist/commands)两种目录层级。
|
|
31
|
+
*/
|
|
32
|
+
function readCliVersion() {
|
|
33
|
+
try {
|
|
34
|
+
const pkgJson = JSON.parse(readFileSync(join(import.meta.dirname, "../../package.json"), "utf-8"));
|
|
35
|
+
return (pkgJson && pkgJson.version) || "0.0.0";
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// package.json 缺失或损坏时回退占位版本,避免阻断启动
|
|
39
|
+
return "0.0.0";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* CLI 版本号(来自 package.json 单一事实源)。
|
|
44
|
+
*/
|
|
45
|
+
export const CLI_VERSION = readCliVersion();
|
|
46
|
+
/**
|
|
47
|
+
* 递归注入全局通用选项。
|
|
48
|
+
*
|
|
49
|
+
* 输出纪律契约:--json/--envelope 对所有命令统一注入;已实现 renderResult
|
|
50
|
+
* 数据输出的命令会消费它们,未实现机器输出的命令(init、link、test、new、
|
|
51
|
+
* serve、mcp 等)将其作为无操作标志忽略,不影响人类输出行为。
|
|
52
|
+
* 错误信封由顶层 main 的 renderError 统一兜底,与命令实现解耦。
|
|
53
|
+
*/
|
|
54
|
+
function applyCommonOptions(cmd) {
|
|
55
|
+
const hasOpt = (flagName) => cmd.options.some((o) => o.name() === flagName || o.long === `--${flagName}`);
|
|
56
|
+
if (!hasOpt("json")) {
|
|
57
|
+
cmd.option("--json", "Output as JSON");
|
|
58
|
+
}
|
|
59
|
+
if (!hasOpt("envelope")) {
|
|
60
|
+
cmd.option("--envelope", "Wrap JSON output in standard envelope");
|
|
61
|
+
}
|
|
62
|
+
if (!hasOpt("dataDir") && !hasOpt("data-dir")) {
|
|
63
|
+
cmd.option("--data-dir <path>", "Custom database storage directory");
|
|
64
|
+
}
|
|
65
|
+
for (const sub of cmd.commands) {
|
|
66
|
+
applyCommonOptions(sub);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function createCliProgram(context) {
|
|
70
|
+
const program = new Command();
|
|
71
|
+
program
|
|
72
|
+
.name("ad")
|
|
73
|
+
.description("ActionDock (ad) 2.0 - Toolchain for building and shipping standalone AI Agent Actions & Skills")
|
|
74
|
+
.version(CLI_VERSION, "-v, --version");
|
|
75
|
+
program.option("-V", "output the version number");
|
|
76
|
+
program.on("option:V", () => {
|
|
77
|
+
program._outputConfiguration.writeOut(`${program.version()}\n`);
|
|
78
|
+
program._exit(0, "commander.version", program.version());
|
|
79
|
+
});
|
|
80
|
+
// 禁用 Commander 内部直接 process.exit,统一由顶层调度器管控退出码
|
|
81
|
+
program.exitOverride((err) => {
|
|
82
|
+
throw err;
|
|
83
|
+
});
|
|
84
|
+
registerInitCommand(program);
|
|
85
|
+
registerAddCommand(program, context);
|
|
86
|
+
registerRemoveCommand(program, context);
|
|
87
|
+
registerNewCommands(program, context);
|
|
88
|
+
registerActionCommands(program, context);
|
|
89
|
+
registerInfoCommand(program, context);
|
|
90
|
+
registerDoctorCommand(program, context);
|
|
91
|
+
registerListCommand(program, context);
|
|
92
|
+
registerDescribeCommand(program, context);
|
|
93
|
+
registerRunCommand(program, context);
|
|
94
|
+
registerValidateCommand(program, context);
|
|
95
|
+
registerGenerateCommands(program, context);
|
|
96
|
+
registerPlaybookCommands(program, context);
|
|
97
|
+
registerConfigCommands(program, context);
|
|
98
|
+
registerStateCommands(program, context);
|
|
99
|
+
registerRunsCommands(program, context);
|
|
100
|
+
registerTestCommand(program);
|
|
101
|
+
registerBuildCommand(program, context);
|
|
102
|
+
registerPackCommand(program, context);
|
|
103
|
+
registerExportCommand(program, context);
|
|
104
|
+
registerLinkCommands(program);
|
|
105
|
+
registerProfileCommands(program);
|
|
106
|
+
registerServeCommand(program, context);
|
|
107
|
+
registerMcpCommands(program, context);
|
|
108
|
+
applyCommonOptions(program);
|
|
109
|
+
return program;
|
|
110
|
+
}
|
|
111
|
+
export { registerActionCommands, registerAddCommand, registerBuildCommand, registerConfigCommands, registerDescribeCommand, registerDoctorCommand, registerExportCommand, registerGenerateCommands, registerInfoCommand, registerInitCommand, registerLinkCommands, registerListCommand, registerMcpCommands, registerNewCommands, registerPackCommand, registerPlaybookCommands, registerProfileCommands, registerRemoveCommand, registerRunCommand, registerRunsCommands, registerServeCommand, registerStateCommands, registerTestCommand, registerValidateCommand, };
|
package/dist/commands/info.d.ts
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import type { CliContext } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 注册 info 命令。
|
|
5
|
+
*
|
|
6
|
+
* @param program Commander 实例
|
|
7
|
+
* @param context 命令行上下文
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerInfoCommand(program: Command, context?: CliContext): void;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { fetchRemoteInfo, filterWithFallbackInfo, getRegistryStatus, resolvePackageRoot, resolveTarget, } from "@actiondock/core";
|
|
2
|
+
import { ArgumentError, ExecutionError } from "../errors.js";
|
|
3
|
+
import { projectDetailToJson, renderAggregatedPackages, renderProjectDetail, renderRegistryTree, renderResult, } from "../renderer.js";
|
|
4
|
+
import { getProjectDetailInfo, scanLocalAggregatedPackages } from "../services/index.js";
|
|
5
|
+
import { getEffectiveOptions, resolveFallbackStrategy, resolveIntent } from "../utils/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* 将远端信息响应归一为本地工程详情视图。
|
|
8
|
+
*/
|
|
9
|
+
function remoteInfoToDetail(remoteInfo) {
|
|
10
|
+
return {
|
|
11
|
+
id: remoteInfo.id,
|
|
12
|
+
name: remoteInfo.name || remoteInfo.id,
|
|
13
|
+
version: remoteInfo.version || "unknown",
|
|
14
|
+
description: remoteInfo.description,
|
|
15
|
+
projectRoot: remoteInfo.path || remoteInfo.projectRoot || "",
|
|
16
|
+
actionsDir: "remote",
|
|
17
|
+
playbooksDir: "remote",
|
|
18
|
+
actionsCount: remoteInfo.actionsCount || (remoteInfo.actions ? remoteInfo.actions.length : 0),
|
|
19
|
+
playbooksCount: remoteInfo.playbooksCount || (remoteInfo.playbooks ? remoteInfo.playbooks.length : 0),
|
|
20
|
+
actions: (remoteInfo.actionsDetail || remoteInfo.actions || []).map((a) => typeof a === "string" ? a : a.id),
|
|
21
|
+
playbooks: (remoteInfo.playbooksDetail || remoteInfo.playbooks || []).map((pb) => typeof pb === "string" ? pb : pb.id),
|
|
22
|
+
configDeclared: Object.keys(remoteInfo.configDeclared || {}),
|
|
23
|
+
configDef: remoteInfo.configDeclared,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 渲染工程详情输出(机器模式输出视图转换结果,人类模式渲染详情)。
|
|
28
|
+
*/
|
|
29
|
+
function renderProjectDetailOutput(detail, options) {
|
|
30
|
+
renderResult(projectDetailToJson(detail), {
|
|
31
|
+
json: options.json,
|
|
32
|
+
envelope: options.envelope,
|
|
33
|
+
humanFormatter: () => renderProjectDetail(detail),
|
|
34
|
+
context: options.context,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 注册 info 命令。
|
|
39
|
+
*
|
|
40
|
+
* @param program Commander 实例
|
|
41
|
+
* @param context 命令行上下文
|
|
42
|
+
*/
|
|
43
|
+
export function registerInfoCommand(program, context) {
|
|
44
|
+
program
|
|
45
|
+
.command("info [patterns...]")
|
|
46
|
+
.description("Display information about current project, linked package, or remote target")
|
|
47
|
+
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
48
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
49
|
+
.option("--tree", "Display packages in hierarchical tree view grouped by workspace")
|
|
50
|
+
.option("-p, --profile <name>", "Query against a specific profile")
|
|
51
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
52
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
53
|
+
.option("--fallback", "Enable fallback to full list when no items match intent")
|
|
54
|
+
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
55
|
+
.option("--json", "Output information as JSON")
|
|
56
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
57
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
58
|
+
.action(async (patterns = [], rawOptions, cmd) => {
|
|
59
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
60
|
+
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
61
|
+
const { isMachine, shouldFallback } = resolveFallbackStrategy(options);
|
|
62
|
+
const outOpts = { json: options.json, envelope: options.envelope, context };
|
|
63
|
+
// 远端服务目标分支
|
|
64
|
+
const target = resolveTarget({
|
|
65
|
+
profile: options.profile,
|
|
66
|
+
server: options.server,
|
|
67
|
+
token: options.token,
|
|
68
|
+
}, context?.customHome);
|
|
69
|
+
if (target.type === "remote") {
|
|
70
|
+
const remoteInfo = await fetchRemoteInfo(target.serverUrl, target.token, {
|
|
71
|
+
intent: effectiveIntent,
|
|
72
|
+
package: options.package,
|
|
73
|
+
tree: Boolean(options.tree),
|
|
74
|
+
});
|
|
75
|
+
if (isMachine) {
|
|
76
|
+
renderResult(remoteInfo, outOpts);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (remoteInfo.type === "tree" || (options.tree && remoteInfo.workspaces)) {
|
|
80
|
+
renderResult(remoteInfo, {
|
|
81
|
+
humanFormatter: () => renderRegistryTree(remoteInfo),
|
|
82
|
+
context,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (remoteInfo.type === "package_detail" || (remoteInfo.id && !remoteInfo.packages)) {
|
|
87
|
+
const detail = remoteInfoToDetail(remoteInfo);
|
|
88
|
+
renderResult(detail, {
|
|
89
|
+
humanFormatter: () => renderProjectDetail(detail),
|
|
90
|
+
context,
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const packages = remoteInfo.packages || remoteInfo.linkedPackages || [];
|
|
95
|
+
renderResult(packages, {
|
|
96
|
+
humanFormatter: () => renderAggregatedPackages(packages),
|
|
97
|
+
context,
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// 本地注册表树状图分支
|
|
102
|
+
if (options.tree) {
|
|
103
|
+
const status = getRegistryStatus(context?.customHome);
|
|
104
|
+
renderResult(status, {
|
|
105
|
+
json: options.json,
|
|
106
|
+
envelope: options.envelope,
|
|
107
|
+
humanFormatter: () => renderRegistryTree(status),
|
|
108
|
+
context,
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// 显式指定 Package 参数分支
|
|
113
|
+
if (options.package) {
|
|
114
|
+
const directRoot = resolvePackageRoot(options.package);
|
|
115
|
+
if (directRoot) {
|
|
116
|
+
const detail = await getProjectDetailInfo(directRoot);
|
|
117
|
+
renderProjectDetailOutput(detail, outOpts);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
121
|
+
}
|
|
122
|
+
// 扫描本地候选包(当前工程根目录 + 全局已链接包)
|
|
123
|
+
const { currentRoot, aggregated } = scanLocalAggregatedPackages(context);
|
|
124
|
+
// 无关键字过滤场景
|
|
125
|
+
if (!effectiveIntent) {
|
|
126
|
+
if (currentRoot) {
|
|
127
|
+
const detail = await getProjectDetailInfo(currentRoot);
|
|
128
|
+
renderProjectDetailOutput(detail, outOpts);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (aggregated.length === 0) {
|
|
132
|
+
renderResult({ linkedPackages: [] }, {
|
|
133
|
+
...outOpts,
|
|
134
|
+
humanFormatter: () => "No ActionDock project in current directory, and no packages linked.\nRun 'ad link' inside an Action package to register it.",
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
renderResult({ linkedPackages: aggregated }, {
|
|
139
|
+
...outOpts,
|
|
140
|
+
humanFormatter: () => renderAggregatedPackages(aggregated),
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// 有关键字过滤场景:单一位置参数且非显式 --intent 时优先尝试包寻址
|
|
145
|
+
if (patterns.length === 1 && !options.intent) {
|
|
146
|
+
const directRoot = resolvePackageRoot(patterns[0]);
|
|
147
|
+
if (directRoot) {
|
|
148
|
+
const detail = await getProjectDetailInfo(directRoot);
|
|
149
|
+
renderProjectDetailOutput(detail, outOpts);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (aggregated.length === 0) {
|
|
154
|
+
if (isMachine) {
|
|
155
|
+
renderResult({ linkedPackages: [], matchedCount: 0, isFallback: false }, outOpts);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
throw new ExecutionError(`No ActionDock project or linked packages available to match '${effectiveIntent}'`);
|
|
159
|
+
}
|
|
160
|
+
const filterRes = filterWithFallbackInfo(aggregated, effectiveIntent, [
|
|
161
|
+
(p) => p.id,
|
|
162
|
+
(p) => p.name,
|
|
163
|
+
(p) => p.description,
|
|
164
|
+
(p) => p.path,
|
|
165
|
+
(p) => p.actions,
|
|
166
|
+
(p) => p.playbooks,
|
|
167
|
+
], shouldFallback);
|
|
168
|
+
// 无匹配项
|
|
169
|
+
if (filterRes.matchedCount === 0) {
|
|
170
|
+
if (!filterRes.isFallback) {
|
|
171
|
+
if (isMachine) {
|
|
172
|
+
renderResult({ linkedPackages: [], matchedCount: 0, isFallback: false }, outOpts);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
throw new ExecutionError(`No packages matched intent '${effectiveIntent}'`);
|
|
176
|
+
}
|
|
177
|
+
// 回退模式:展示全部包并附带提示
|
|
178
|
+
if (isMachine) {
|
|
179
|
+
renderResult({ linkedPackages: filterRes.items, isFallback: true, matchedCount: 0 }, outOpts);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
renderResult({ linkedPackages: filterRes.items, isFallback: true, matchedCount: 0 }, {
|
|
183
|
+
...outOpts,
|
|
184
|
+
humanFormatter: () => `(No linked packages matched intent '${effectiveIntent}', showing all packages)\n\n` +
|
|
185
|
+
renderAggregatedPackages(filterRes.items),
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// 机器模式下搜索:稳定返回列表结构,不因为 matchedCount === 1 突变为详情
|
|
190
|
+
if (isMachine) {
|
|
191
|
+
renderResult({ linkedPackages: filterRes.items, matchedCount: filterRes.matchedCount, isFallback: false }, outOpts);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// 人类终端交互:精确匹配单个包展开详情
|
|
195
|
+
if (filterRes.matchedCount === 1) {
|
|
196
|
+
const matchedPkg = filterRes.items[0];
|
|
197
|
+
const detail = await getProjectDetailInfo(matchedPkg.path);
|
|
198
|
+
renderProjectDetailOutput(detail, outOpts);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// 匹配多个包:输出摘要列表
|
|
202
|
+
renderResult({ linkedPackages: filterRes.items }, {
|
|
203
|
+
...outOpts,
|
|
204
|
+
humanFormatter: () => renderAggregatedPackages(filterRes.items, {
|
|
205
|
+
header: `ActionDock Linked Packages (${filterRes.matchedCount} matches for '${effectiveIntent}'):\n`,
|
|
206
|
+
showTip: true,
|
|
207
|
+
}),
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { initProject } from "@actiondock/core";
|
|
2
|
+
import { writeStdout } from "../renderer.js";
|
|
3
|
+
import { ExecutionError } from "../errors.js";
|
|
4
|
+
export function registerInitCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("init [directory]")
|
|
7
|
+
.description("Initialize a new ActionDock project")
|
|
8
|
+
.option("-i, --id <id>", "Project identifier")
|
|
9
|
+
.option("-n, --name <name>", "Project display name")
|
|
10
|
+
.option("-d, --desc <description>", "Project description")
|
|
11
|
+
.action((dir = ".", options) => {
|
|
12
|
+
try {
|
|
13
|
+
initProject(dir, {
|
|
14
|
+
id: options.id,
|
|
15
|
+
name: options.name,
|
|
16
|
+
description: options.desc,
|
|
17
|
+
});
|
|
18
|
+
writeStdout(`Successfully initialized ActionDock project in ${dir}`);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
throw new ExecutionError(err.message);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { linkPackage, pruneRegistry, unlinkPackage, } from "@actiondock/core";
|
|
2
|
+
import { ExecutionError } from "../errors.js";
|
|
3
|
+
import { writeStdout } from "../renderer.js";
|
|
4
|
+
export function registerLinkCommands(program) {
|
|
5
|
+
// ad link [path]
|
|
6
|
+
program
|
|
7
|
+
.command("link [path]")
|
|
8
|
+
.option("-r, --recursive", "Recursively discover and link packages in subdirectories")
|
|
9
|
+
.description("Link local Action package(s) or workspace directory into global registry for instant cross-directory execution")
|
|
10
|
+
.action(async (targetPath, options) => {
|
|
11
|
+
try {
|
|
12
|
+
const result = await linkPackage(targetPath || process.cwd(), undefined, {
|
|
13
|
+
recursive: options.recursive,
|
|
14
|
+
});
|
|
15
|
+
if (result.isWorkspace) {
|
|
16
|
+
writeStdout(`[OK] Linked workspace '${result.path}' (${result.entries.length} package${result.entries.length > 1 ? "s" : ""}):`);
|
|
17
|
+
for (const e of result.entries) {
|
|
18
|
+
writeStdout(` - ${e.id} (v${e.version}) -> ${e.path}`);
|
|
19
|
+
}
|
|
20
|
+
writeStdout("[INFO] Sub-packages added to this workspace will be automatically discovered.");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
writeStdout(`[OK] Linked package '${result.id}' (v${result.version}) from ${result.path}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw new ExecutionError(err.message);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
// ad unlink [id|path]
|
|
31
|
+
program
|
|
32
|
+
.command("unlink [identifier]")
|
|
33
|
+
.option("-p, --prune", "Automatically scan and prune any stale/missing paths from registry")
|
|
34
|
+
.description("Unlink a package, workspace, or prune stale entries from global developer registry")
|
|
35
|
+
.action(async (identifier, options) => {
|
|
36
|
+
try {
|
|
37
|
+
if (options.prune || identifier === "--prune") {
|
|
38
|
+
const result = await pruneRegistry();
|
|
39
|
+
const totalPruned = result.prunedPackages.length + result.prunedWorkspaces.length;
|
|
40
|
+
if (totalPruned === 0) {
|
|
41
|
+
writeStdout("[OK] No stale registry entries found.");
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
writeStdout(`[OK] Pruned ${result.prunedWorkspaces.length} workspace(s) and ${result.prunedPackages.length} package(s) from registry.`);
|
|
45
|
+
for (const ws of result.prunedWorkspaces) {
|
|
46
|
+
writeStdout(` - [workspace] ${ws.path}`);
|
|
47
|
+
}
|
|
48
|
+
for (const pkg of result.prunedPackages) {
|
|
49
|
+
writeStdout(` - [package] ${pkg.id} (${pkg.path})`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const removed = await unlinkPackage(identifier || process.cwd());
|
|
55
|
+
if (removed) {
|
|
56
|
+
if (removed.type === "workspace") {
|
|
57
|
+
writeStdout(`[OK] Unlinked workspace '${removed.path}' (${removed.packagesCount || 0} package${(removed.packagesCount || 0) > 1 ? "s" : ""} unlinked)`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
writeStdout(`[OK] Unlinked package '${removed.id}' (${removed.path})`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
writeStdout(`Package or workspace '${identifier || process.cwd()}' was not linked in registry`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
throw new ExecutionError(err.message);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import type { CliContext } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 注册顶层统一 list 命令:列出当前工程、已链接包或远端服务中的可用 Action。
|
|
5
|
+
*
|
|
6
|
+
* @param program Commander 根程序对象
|
|
7
|
+
* @param context 命令行上下文
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerListCommand(program: Command, context?: CliContext): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { filterWithFallbackInfo } from "@actiondock/core";
|
|
2
|
+
import { ArgumentError } from "../errors.js";
|
|
3
|
+
import { renderActionList, renderResult } from "../renderer.js";
|
|
4
|
+
import { getEffectiveOptions, resolveFallbackStrategy, resolveIntent, resolveLocalPackageRoot, withTarget } from "../utils/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* 注册顶层统一 list 命令:列出当前工程、已链接包或远端服务中的可用 Action。
|
|
7
|
+
*
|
|
8
|
+
* @param program Commander 根程序对象
|
|
9
|
+
* @param context 命令行上下文
|
|
10
|
+
*/
|
|
11
|
+
export function registerListCommand(program, context) {
|
|
12
|
+
program
|
|
13
|
+
.command("list [patterns...]")
|
|
14
|
+
.description("List actions in current project, linked packages, or remote profile")
|
|
15
|
+
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
16
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
17
|
+
.option("-p, --profile <name>", "Query against a specific execution profile")
|
|
18
|
+
.option("-s, --server <url>", "Remote server URL")
|
|
19
|
+
.option("-t, --token <token>", "Auth token for remote server")
|
|
20
|
+
.option("--fallback", "Enable fallback to full list when no items match intent")
|
|
21
|
+
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
22
|
+
.option("--json", "Output as JSON")
|
|
23
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
24
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
25
|
+
.action(async (patterns = [], rawOptions, cmd) => {
|
|
26
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
27
|
+
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
28
|
+
const { isMachine, shouldFallback } = resolveFallbackStrategy(options);
|
|
29
|
+
// 目标拓扑解析(仅 local 分支需要包寻址)
|
|
30
|
+
const targetPackageRoot = resolveLocalPackageRoot(options.package);
|
|
31
|
+
if (options.package && !targetPackageRoot) {
|
|
32
|
+
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
33
|
+
}
|
|
34
|
+
// 通过 Target 门面统一获取 Action 列表
|
|
35
|
+
await withTarget(options, context, async (target, resolved) => {
|
|
36
|
+
let rawSummaries = await target.listActions();
|
|
37
|
+
// 若指定了目标包但本地未过滤,则精确匹配包标识
|
|
38
|
+
if (options.package && !options.profile && !options.server) {
|
|
39
|
+
rawSummaries = rawSummaries.filter((s) => s.id.startsWith(`${options.package}/`) ||
|
|
40
|
+
s.packageId === options.package ||
|
|
41
|
+
!s.id.includes("/"));
|
|
42
|
+
}
|
|
43
|
+
const rawList = rawSummaries.map((s) => {
|
|
44
|
+
let id = s.id;
|
|
45
|
+
if (targetPackageRoot || options.package) {
|
|
46
|
+
const pkgId = s.packageId || options.package;
|
|
47
|
+
if (pkgId && id.startsWith(`${pkgId}/`)) {
|
|
48
|
+
id = id.slice(pkgId.length + 1);
|
|
49
|
+
}
|
|
50
|
+
else if (targetPackageRoot && id.includes("/")) {
|
|
51
|
+
id = id.slice(id.indexOf("/") + 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
id,
|
|
56
|
+
description: s.description || "",
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
const filterRes = filterWithFallbackInfo(rawList, effectiveIntent, [(a) => a.id, (a) => a.description], shouldFallback);
|
|
60
|
+
if (filterRes.isFallback && isMachine) {
|
|
61
|
+
renderResult({ items: filterRes.items, isFallback: true, matchedCount: 0 }, { json: options.json, envelope: options.envelope, context });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const title = resolved.type === "remote"
|
|
65
|
+
? `Actions on remote server ${resolved.serverUrl}${resolved.profileName ? ` (Profile: ${resolved.profileName})` : ""}`
|
|
66
|
+
: targetPackageRoot
|
|
67
|
+
? `Actions in ${options.package || "current project"}`
|
|
68
|
+
: "Available Actions";
|
|
69
|
+
renderResult(filterRes.items, {
|
|
70
|
+
json: options.json,
|
|
71
|
+
envelope: options.envelope,
|
|
72
|
+
humanFormatter: () => renderActionList(filterRes.items, title, filterRes.isFallback, effectiveIntent),
|
|
73
|
+
context,
|
|
74
|
+
});
|
|
75
|
+
}, { localRoot: targetPackageRoot || undefined, scanLinkedPackages: true });
|
|
76
|
+
});
|
|
77
|
+
}
|
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import type { CliContext } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 注册 mcp 命令(STDIO 与 HTTP 传输服务模式)。
|
|
5
|
+
*
|
|
6
|
+
* @param program Commander 实例
|
|
7
|
+
* @param context 命令行上下文
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerMcpCommands(program: Command, context?: CliContext): void;
|