@actiondock/cli 2.7.0 → 2.8.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 +4 -6
- package/dist/commands/action/create.js +4 -5
- package/dist/commands/add.js +9 -17
- package/dist/commands/build.js +3 -18
- package/dist/commands/config/delete.js +8 -7
- package/dist/commands/config/env.js +7 -11
- package/dist/commands/config/get.js +8 -5
- package/dist/commands/config/list.js +16 -22
- package/dist/commands/config/schema.d.ts +7 -1
- package/dist/commands/config/schema.js +44 -67
- package/dist/commands/config/set.js +9 -7
- package/dist/commands/describe.js +10 -9
- package/dist/commands/doctor.js +4 -3
- package/dist/commands/export.js +5 -13
- package/dist/commands/generate.js +4 -3
- package/dist/commands/info.js +3 -1
- package/dist/commands/init.js +3 -3
- package/dist/commands/link.js +4 -4
- package/dist/commands/list.js +19 -10
- package/dist/commands/mcp.js +27 -66
- package/dist/commands/pack.js +3 -12
- package/dist/commands/playbook.js +30 -10
- package/dist/commands/profile.js +10 -19
- package/dist/commands/remove.js +5 -14
- package/dist/commands/run.d.ts +5 -2
- package/dist/commands/run.js +19 -20
- package/dist/commands/runs.js +26 -35
- package/dist/commands/serve.js +66 -44
- package/dist/commands/state-list.d.ts +2 -2
- package/dist/commands/state-list.js +10 -8
- package/dist/commands/state.d.ts +2 -2
- package/dist/commands/state.js +110 -103
- package/dist/commands/test.js +1 -1
- package/dist/commands/validate.js +4 -17
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +46 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/renderer.d.ts +1 -1
- package/dist/renderer.js +1 -1
- package/dist/services/config-merge.d.ts +6 -5
- package/dist/services/config-merge.js +10 -8
- package/dist/services/inspect.js +3 -1
- package/dist/standalone/index.d.ts +4 -14
- package/dist/standalone/index.js +5 -44
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utils/cert.js +1 -1
- package/dist/utils/duration.d.ts +1 -1
- package/dist/utils/duration.js +1 -1
- package/dist/utils/index.d.ts +1 -2
- package/dist/utils/index.js +1 -2
- package/dist/utils/input.d.ts +9 -1
- package/dist/utils/input.js +12 -1
- package/dist/utils/server-launch.d.ts +61 -0
- package/dist/utils/server-launch.js +114 -0
- package/dist/utils/target.d.ts +14 -13
- package/dist/utils/target.js +20 -39
- package/dist/utils/utils.d.ts +101 -1
- package/dist/utils/utils.js +97 -7
- package/package.json +5 -6
- package/dist/utils/bytes.d.ts +0 -1
- package/dist/utils/bytes.js +0 -1
- package/dist/utils/filter.d.ts +0 -1
- package/dist/utils/filter.js +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @actiondock/cli
|
|
2
2
|
|
|
3
|
-
ActionDock 2.
|
|
3
|
+
ActionDock 2.x 官方命令行门面工具链。
|
|
4
4
|
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
@@ -15,7 +15,6 @@ ActionDock 2.0 官方命令行门面工具链。
|
|
|
15
15
|
- 原生基于 Node.js >=24.12.0 运行,充分依托原生类型擦除、内置 SQLite 与原生 HTTP 特性。
|
|
16
16
|
- 支持 npm、pnpm 与 yarn 标准包管理器进行全局安装与项目级管理。
|
|
17
17
|
- 日常开发、调试、测试、构建、打包、MCP 服务启动与 HTTP 部署完全基于 Node.js 与 npm 标准工作流,无需安装外部编译器。
|
|
18
|
-
- 单文件独立二进制构建(`--target`、`--bytecode`、`--standalone`)与 `actiondock.manifest.json` 已在 2.0 中彻底移除,由标准的 Node.js 目录交付产物与 npm 打包取代。
|
|
19
18
|
|
|
20
19
|
---
|
|
21
20
|
|
|
@@ -190,10 +189,9 @@ $data | ConvertTo-Json -Depth 100 | ad run complex-action --input-file -
|
|
|
190
189
|
|
|
191
190
|
作为顶层门面与独立运行分发器,`@actiondock/cli` 串联以下子包:
|
|
192
191
|
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
- 协议服务:通过 [@actiondock/mcp](../mcp/README.md) 启动协议监听。
|
|
192
|
+
- 领域内核与运行时:依赖 [@actiondock/core](../core/README.md),统一对接标准服务端口体系(`DiscoveryPort`、`ExecutionPort`、`RunsPort`、`ConfigPort`、`StatePort`)与统一服务门面(`createActionDock`、`connectActionDock`),承载原生运行时、存储驱动与受管进程治理。
|
|
193
|
+
- 构建与打包:依赖 [@actiondock/builder](../builder/README.md),完成依赖闭包规划、Node 目录交付产物构建、npm 打包与 Agent Skill 资产导出。
|
|
194
|
+
- 协议服务:通过 [@actiondock/mcp](../mcp/README.md) 启动 Model Context Protocol 协议监听与适配。
|
|
197
195
|
|
|
198
196
|
---
|
|
199
197
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
-
import { assertPathWithinRoot,
|
|
4
|
-
import {
|
|
3
|
+
import { assertPathWithinRoot, getPackageSlug, loadManifest, saveManifest, writeActionTypes, } from "@actiondock/core/project";
|
|
4
|
+
import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
|
|
5
|
+
import { ExecutionError, notInProjectError, wrapAsExecutionError } from "../../errors.js";
|
|
5
6
|
import { writeStdout } from "../../renderer.js";
|
|
6
7
|
import { attachDescribeCommand } from "../describe.js";
|
|
7
8
|
import { attachListCommand } from "../list.js";
|
|
@@ -210,8 +211,6 @@ ${returnBody}
|
|
|
210
211
|
writeStdout(` 复杂输入或大段文本:ad run ${id} --json --input-file input.json`, context);
|
|
211
212
|
}
|
|
212
213
|
catch (err) {
|
|
213
|
-
|
|
214
|
-
throw err;
|
|
215
|
-
throw new ExecutionError(err.message);
|
|
214
|
+
throw wrapAsExecutionError(err);
|
|
216
215
|
}
|
|
217
216
|
}
|
package/dist/commands/add.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { PackageGraphBuilder, } from "@actiondock/core/graph";
|
|
4
|
+
import { beginTransaction, computeManifestDigest, getInstallCommand, loadLockfile, MANIFEST_FILE_NAME, parseJsonWithoutDuplicates, saveLockfile, saveManifest, } from "@actiondock/core/project";
|
|
5
5
|
import { renderResult } from "../renderer.js";
|
|
6
|
-
import { assertSafePackageSpec, getEffectiveOptions, spawnAsync } from "../utils/index.js";
|
|
6
|
+
import { assertSafePackageSpec, getEffectiveOptions, requireProjectManifestRoot, rollbackAndRethrow, spawnAsync, } from "../utils/index.js";
|
|
7
7
|
/**
|
|
8
8
|
* 从安装说明符中提取基础 npm 包名(去除版本号及前缀范围)。
|
|
9
9
|
*/
|
|
@@ -36,14 +36,7 @@ export function registerAddCommand(program, context) {
|
|
|
36
36
|
.option("--json", "Output as JSON")
|
|
37
37
|
.action(async (packageSpec, rawOptions, cmd) => {
|
|
38
38
|
const options = getEffectiveOptions(rawOptions, cmd);
|
|
39
|
-
const root
|
|
40
|
-
if (!root) {
|
|
41
|
-
throw notInProjectError("Please specify -P, --package <path> or cd into a project directory.");
|
|
42
|
-
}
|
|
43
|
-
const manifest = loadManifest(root);
|
|
44
|
-
if (!manifest) {
|
|
45
|
-
throw new ArgumentError(`actiondock.json not found in ${root}`);
|
|
46
|
-
}
|
|
39
|
+
const { root, manifest } = requireProjectManifestRoot(options.package);
|
|
47
40
|
// 包说明符白名单前置校验:拒绝 shell 元字符,消除 win32 shell 拼接注入面
|
|
48
41
|
assertSafePackageSpec(packageSpec);
|
|
49
42
|
const npmPackageName = extractNpmPackageName(packageSpec);
|
|
@@ -97,9 +90,9 @@ export function registerAddCommand(program, context) {
|
|
|
97
90
|
manifest.dependencies = manifest.dependencies || {};
|
|
98
91
|
manifest.dependencies[targetPackageId] =
|
|
99
92
|
targetPackageId === npmPackageName ? `^${targetVersion}` : npmPackageName;
|
|
100
|
-
//
|
|
101
|
-
const
|
|
102
|
-
const graph =
|
|
93
|
+
// 触发依赖图构建及版本冲突检测
|
|
94
|
+
const builder = new PackageGraphBuilder({ projectRoot: root, manifest });
|
|
95
|
+
const graph = builder.buildSync();
|
|
103
96
|
// 更新 actiondock.lock.json
|
|
104
97
|
const lockfile = loadLockfile(root) || {
|
|
105
98
|
lockfileVersion: 1,
|
|
@@ -137,8 +130,7 @@ export function registerAddCommand(program, context) {
|
|
|
137
130
|
});
|
|
138
131
|
}
|
|
139
132
|
catch (err) {
|
|
140
|
-
await tx
|
|
141
|
-
throw new ExecutionError(err.message, err, err.code || "ADD_DEPENDENCY_FAILED");
|
|
133
|
+
await rollbackAndRethrow(tx, err, "ADD_DEPENDENCY_FAILED");
|
|
142
134
|
}
|
|
143
135
|
});
|
|
144
136
|
}
|
package/dist/commands/build.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ExecutionError, notInProjectError, packageNotFoundError } from "../errors.js";
|
|
1
|
+
import { ExecutionError } from "../errors.js";
|
|
3
2
|
import { renderResult, writeStdout } from "../renderer.js";
|
|
4
|
-
import { getEffectiveOptions, parseListOption } from "../utils/index.js";
|
|
3
|
+
import { getEffectiveOptions, parseListOption, requirePackageRoot } from "../utils/index.js";
|
|
5
4
|
export function registerBuildCommand(program, context) {
|
|
6
5
|
program
|
|
7
6
|
.command("build")
|
|
@@ -14,23 +13,9 @@ export function registerBuildCommand(program, context) {
|
|
|
14
13
|
.option("--vendor-deps", "Materialize locked production dependencies into the output")
|
|
15
14
|
.option("--allow-install-scripts", "Allow lifecycle install scripts to run during vendor-deps")
|
|
16
15
|
.option("--require-reproducible", "Require reproducible build and fail if install scripts must run")
|
|
17
|
-
.option("-t, --target <target>", "Target compilation platform (removed)")
|
|
18
|
-
.option("--bytecode", "Bytecode compilation (removed)")
|
|
19
16
|
.action(async (rawOptions, cmd) => {
|
|
20
17
|
const options = getEffectiveOptions(rawOptions, cmd);
|
|
21
|
-
|
|
22
|
-
if (options.target !== undefined || options.bytecode !== undefined) {
|
|
23
|
-
throw new ExecutionError("Unsupported build mode: '--target' and '--bytecode' standalone single-file binary compilation have been removed in ActionDock 2.0. Directory-based Node.js builds are now the standard distribution format.", undefined, "UNSUPPORTED_BUILD_MODE");
|
|
24
|
-
}
|
|
25
|
-
const root = options.package
|
|
26
|
-
? resolvePackageRoot(options.package)
|
|
27
|
-
: findProjectRoot();
|
|
28
|
-
if (!root) {
|
|
29
|
-
if (options.package) {
|
|
30
|
-
throw packageNotFoundError(options.package);
|
|
31
|
-
}
|
|
32
|
-
throw notInProjectError("Please specify -P, --package <id> or cd into a project directory.");
|
|
33
|
-
}
|
|
18
|
+
const { root } = requirePackageRoot(options.package);
|
|
34
19
|
const isMachine = Boolean(options.json);
|
|
35
20
|
if (!isMachine) {
|
|
36
21
|
writeStdout("Building Node.js delivery artifact...");
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { loadProjectConfig,
|
|
1
|
+
import { loadProjectConfig, } from "@actiondock/core";
|
|
2
|
+
import { resolvePackageRoot, } from "@actiondock/core/registry";
|
|
2
3
|
import { ArgumentError, packageNotFoundError } from "../../errors.js";
|
|
3
4
|
import { writeStdout } from "../../renderer.js";
|
|
4
|
-
import { applyTargetOptions, getEffectiveOptions,
|
|
5
|
+
import { applyTargetOptions, getEffectiveOptions, withService } from "../../utils/index.js";
|
|
5
6
|
/**
|
|
6
7
|
* 注册 config delete 子命令:删除配置项。
|
|
7
8
|
*
|
|
@@ -22,14 +23,14 @@ export function registerConfigDeleteCommand(configCmd, context) {
|
|
|
22
23
|
throw new ArgumentError("Configuration key is required");
|
|
23
24
|
}
|
|
24
25
|
const root = resolvePackageRoot(options.package);
|
|
25
|
-
await
|
|
26
|
+
await withService(options, context, async (service, resolved) => {
|
|
26
27
|
if (resolved.type === "remote") {
|
|
27
|
-
await
|
|
28
|
+
await service.management?.config.delete(options.package || "", key);
|
|
28
29
|
writeStdout(`[OK] Configuration '${key}' deleted from remote server`, context);
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
if (options.global) {
|
|
32
|
-
await
|
|
33
|
+
await service.management?.config.delete("global", key);
|
|
33
34
|
writeStdout(`[OK] Global configuration '${key}' deleted`, context);
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
@@ -37,12 +38,12 @@ export function registerConfigDeleteCommand(configCmd, context) {
|
|
|
37
38
|
if (options.package) {
|
|
38
39
|
throw packageNotFoundError(options.package);
|
|
39
40
|
}
|
|
40
|
-
await
|
|
41
|
+
await service.management?.config.delete("global", key);
|
|
41
42
|
writeStdout(`[OK] Global configuration '${key}' deleted`, context);
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
const projConfig = loadProjectConfig(root);
|
|
45
|
-
await
|
|
46
|
+
await service.management?.config.delete(projConfig.id, key);
|
|
46
47
|
writeStdout(`[OK] Configuration '${key}' deleted for package '${projConfig.id}'`, context);
|
|
47
48
|
});
|
|
48
49
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { fetchRemoteConfigEnv,
|
|
2
|
-
import {
|
|
1
|
+
import { fetchRemoteConfigEnv, resolveEnvValue, } from "@actiondock/core/profile";
|
|
2
|
+
import { isSecretConfigKey, } from "@actiondock/core/project";
|
|
3
3
|
import { renderConfigEnv, renderResult } from "../../renderer.js";
|
|
4
|
-
import { applyTargetOptions, getEffectiveOptions, resolveTargetFromOptions } from "../../utils/index.js";
|
|
4
|
+
import { applyTargetOptions, getEffectiveOptions, requirePackageRoot, resolveTargetFromOptions } from "../../utils/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* 注册 config env 子命令:诊断环境变量对声明配置的满足率。
|
|
7
7
|
*
|
|
@@ -36,14 +36,10 @@ export function registerConfigEnvCommand(configCmd, context) {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
// 本地项目分支
|
|
39
|
-
const root =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
throw notInProjectError("Usage: ad config env [package-id] or cd into a project directory.");
|
|
45
|
-
}
|
|
46
|
-
const projConfig = loadProjectConfig(root);
|
|
39
|
+
const { root, projConfig } = requirePackageRoot(targetPkg, {
|
|
40
|
+
loadConfig: true,
|
|
41
|
+
hint: "Usage: ad config env [package-id] or cd into a project directory.",
|
|
42
|
+
});
|
|
47
43
|
const declared = projConfig.config || {};
|
|
48
44
|
const envChecks = [];
|
|
49
45
|
for (const [key, itemDef] of Object.entries(declared)) {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { fetchRemoteConfig,
|
|
1
|
+
import { fetchRemoteConfig, } from "@actiondock/core/profile";
|
|
2
|
+
import { isSecretConfigKey, maskSecretValue, } from "@actiondock/core/project";
|
|
3
|
+
import { loadProjectConfig, } from "@actiondock/core";
|
|
4
|
+
import { resolvePackageRoot, } from "@actiondock/core/registry";
|
|
2
5
|
import { ArgumentError, packageNotFoundError } from "../../errors.js";
|
|
3
6
|
import { renderResult } from "../../renderer.js";
|
|
4
7
|
import { resolveMergedConfigEntry } from "../../services/config-merge.js";
|
|
5
|
-
import { applyTargetOptions, getEffectiveOptions, resolveTargetFromOptions,
|
|
8
|
+
import { applyTargetOptions, getEffectiveOptions, resolveTargetFromOptions, withService, } from "../../utils/index.js";
|
|
6
9
|
/**
|
|
7
10
|
* 注册 config get 子命令:查询指定配置键的生效值。
|
|
8
11
|
*
|
|
@@ -49,12 +52,12 @@ export function registerConfigGetCommand(configCmd, context) {
|
|
|
49
52
|
}
|
|
50
53
|
// 本地分支
|
|
51
54
|
const root = resolvePackageRoot(options.package);
|
|
52
|
-
await
|
|
55
|
+
await withService(options, context, async (service) => {
|
|
53
56
|
if (options.global || !root) {
|
|
54
57
|
if (!options.global && options.package && !root) {
|
|
55
58
|
throw packageNotFoundError(options.package);
|
|
56
59
|
}
|
|
57
|
-
const confView = await
|
|
60
|
+
const confView = await service.management?.config.get("global", key);
|
|
58
61
|
const val = confView?.value;
|
|
59
62
|
const isSecret = confView?.secret ?? isSecretConfigKey(key);
|
|
60
63
|
const displayValue = !reveal && isSecret && val !== undefined ? maskSecretValue(val) : val;
|
|
@@ -74,7 +77,7 @@ export function registerConfigGetCommand(configCmd, context) {
|
|
|
74
77
|
const projConfig = loadProjectConfig(root);
|
|
75
78
|
const declaredItem = projConfig.config?.[key];
|
|
76
79
|
// 合并优先级链单一事实源:项目包级 > 全局持久化 > 环境变量 > 声明默认值
|
|
77
|
-
const { value: displayValue, source, secret: isSecret } = await resolveMergedConfigEntry(key, projConfig.id, declaredItem,
|
|
80
|
+
const { value: displayValue, source, secret: isSecret } = await resolveMergedConfigEntry(key, projConfig.id, declaredItem, service, reveal);
|
|
78
81
|
const payload = {
|
|
79
82
|
key,
|
|
80
83
|
value: displayValue,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { fetchRemoteConfig,
|
|
1
|
+
import { fetchRemoteConfig, } from "@actiondock/core/profile";
|
|
2
|
+
import { findProjectRoot, loadProjectConfig, } from "@actiondock/core";
|
|
3
|
+
import { filterWithFallbackInfo, isSecretConfigKey, maskSecretValue, } from "@actiondock/core/project";
|
|
4
|
+
import { resolvePackageRoot, } from "@actiondock/core/registry";
|
|
2
5
|
import { packageNotFoundError } from "../../errors.js";
|
|
3
6
|
import { renderConfigList, renderResult } from "../../renderer.js";
|
|
4
7
|
import { buildMergedConfigEntries } from "../../services/config-merge.js";
|
|
5
|
-
import { applyTargetOptions, getEffectiveOptions, resolveIntent, resolveTargetFromOptions,
|
|
8
|
+
import { applyTargetOptions, getEffectiveOptions, remoteTargetLabel, resolveFallbackStrategy, resolveIntent, resolveTargetFromOptions, withService, } from "../../utils/index.js";
|
|
6
9
|
/**
|
|
7
10
|
* 构造单条配置项的展示视图(含掩码决策,reveal 为假且为敏感键时打码)。
|
|
8
11
|
* 掩码决策收敛于命令层,renderer 仅负责值的字符串格式化。
|
|
@@ -31,13 +34,14 @@ export function registerConfigListCommand(configCmd, context) {
|
|
|
31
34
|
.option("-g, --global", "Show only global configurations"))
|
|
32
35
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
33
36
|
.option("--reveal, --show-secrets", "Reveal plain text values for secrets")
|
|
37
|
+
.option("--fallback", "Enable fallback to full list when no items match intent")
|
|
34
38
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
35
39
|
.option("--data-dir <path>", "Custom database storage directory")
|
|
36
40
|
.option("--json", "Output as JSON")
|
|
37
41
|
.action(async (patterns = [], rawOptions, cmd) => {
|
|
38
42
|
const options = getEffectiveOptions(rawOptions, cmd);
|
|
39
43
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
40
|
-
const shouldFallback = options
|
|
44
|
+
const { shouldFallback } = resolveFallbackStrategy(options);
|
|
41
45
|
const reveal = Boolean(options.reveal || options.showSecrets);
|
|
42
46
|
// 远端服务分支不经过 Target 门面,直接查询远端配置接口
|
|
43
47
|
const remoteTargetInfo = resolveTargetFromOptions(options, context);
|
|
@@ -49,42 +53,32 @@ export function registerConfigListCommand(configCmd, context) {
|
|
|
49
53
|
const entries = Object.entries(res.values || {}).map(([k, v]) => toDisplayEntry(k, v, "remote", isSecretConfigKey(k, res.declared?.[k]), reveal, res.declared?.[k]?.description || ""));
|
|
50
54
|
renderResult(entries, {
|
|
51
55
|
json: options.json,
|
|
52
|
-
humanFormatter: () => renderConfigList(entries,
|
|
56
|
+
humanFormatter: () => renderConfigList(entries, remoteTargetLabel(remoteTargetInfo), false, effectiveIntent),
|
|
53
57
|
context,
|
|
54
58
|
});
|
|
55
59
|
return;
|
|
56
60
|
}
|
|
57
|
-
// 本地分支(通过
|
|
58
|
-
await
|
|
61
|
+
// 本地分支(通过 Service 门面统一访问)
|
|
62
|
+
await withService(options, context, async (service) => {
|
|
59
63
|
const root = options.package ? resolvePackageRoot(options.package) : findProjectRoot();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const filterRes = filterWithFallbackInfo(entries, effectiveIntent, [(c) => c.key, (c) => c.value], shouldFallback);
|
|
64
|
-
renderResult(filterRes.items, {
|
|
65
|
-
json: options.json,
|
|
66
|
-
humanFormatter: () => renderConfigList(filterRes.items, "Global Scope", filterRes.isFallback, effectiveIntent),
|
|
67
|
-
context,
|
|
68
|
-
});
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (!root) {
|
|
72
|
-
if (options.package) {
|
|
64
|
+
// 全局作用域分支:显式 --global 或无工程回退时仅列举全局配置
|
|
65
|
+
if (options.global || !root) {
|
|
66
|
+
if (!options.global && options.package) {
|
|
73
67
|
throw packageNotFoundError(options.package);
|
|
74
68
|
}
|
|
75
|
-
const all = await
|
|
69
|
+
const all = (await service.management?.config.list("global")) ?? [];
|
|
76
70
|
const entries = all.map((item) => toDisplayEntry(item.key, item.value, "global", item.secret || isSecretConfigKey(item.key), reveal));
|
|
77
71
|
const filterRes = filterWithFallbackInfo(entries, effectiveIntent, [(c) => c.key, (c) => c.value], shouldFallback);
|
|
78
72
|
renderResult(filterRes.items, {
|
|
79
73
|
json: options.json,
|
|
80
|
-
humanFormatter: () => renderConfigList(filterRes.items, "Global Scope (No project found)", filterRes.isFallback, effectiveIntent),
|
|
74
|
+
humanFormatter: () => renderConfigList(filterRes.items, options.global ? "Global Scope" : "Global Scope (No project found)", filterRes.isFallback, effectiveIntent),
|
|
81
75
|
context,
|
|
82
76
|
});
|
|
83
77
|
return;
|
|
84
78
|
}
|
|
85
79
|
const projConfig = loadProjectConfig(root);
|
|
86
80
|
// 跨作用域合并视图单一事实源:项目包级 > 全局持久化 > 环境变量 > 声明默认值
|
|
87
|
-
const merged = await buildMergedConfigEntries(root,
|
|
81
|
+
const merged = await buildMergedConfigEntries(root, service, reveal);
|
|
88
82
|
const filterRes = filterWithFallbackInfo(merged, effectiveIntent, [(c) => c.key, (c) => c.value, (c) => c.description, (c) => c.source], shouldFallback);
|
|
89
83
|
renderResult(filterRes.items, {
|
|
90
84
|
json: options.json,
|
|
@@ -3,7 +3,13 @@ import type { CliContext } from "../../types.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* 注册 config schema 子命令:检查声明配置的解析状态。
|
|
5
5
|
*
|
|
6
|
+
* 状态推导复用 config-merge 的跨作用域合并视图单一事实源
|
|
7
|
+
* (项目包级 > 全局持久化 > 环境变量 > 声明默认值):
|
|
8
|
+
* - source 命中 project、global 或 env 时状态为 SET;
|
|
9
|
+
* - source 为 default(仅声明默认值兜底)时状态为 DEFAULT;
|
|
10
|
+
* - 键无任何来源(不在合并视图中,即未声明默认值也未持久化)时状态为 MISSING。
|
|
11
|
+
*
|
|
6
12
|
* @param configCmd config 命令实例
|
|
7
|
-
* @param context
|
|
13
|
+
* @param context CLI 上下文
|
|
8
14
|
*/
|
|
9
15
|
export declare function registerConfigSchemaCommand(configCmd: Command, context?: CliContext): void;
|
|
@@ -1,80 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isSecretConfigKey, } from "@actiondock/core/project";
|
|
2
|
+
import { notInProjectError } from "../../errors.js";
|
|
3
3
|
import { renderConfigSchema, renderResult, writeStdout } from "../../renderer.js";
|
|
4
|
-
import {
|
|
4
|
+
import { buildMergedConfigEntries } from "../../services/config-merge.js";
|
|
5
|
+
import { applyTargetOptions, getEffectiveOptions, requirePackageRoot, withService } from "../../utils/index.js";
|
|
5
6
|
/**
|
|
6
7
|
* 注册 config schema 子命令:检查声明配置的解析状态。
|
|
7
8
|
*
|
|
9
|
+
* 状态推导复用 config-merge 的跨作用域合并视图单一事实源
|
|
10
|
+
* (项目包级 > 全局持久化 > 环境变量 > 声明默认值):
|
|
11
|
+
* - source 命中 project、global 或 env 时状态为 SET;
|
|
12
|
+
* - source 为 default(仅声明默认值兜底)时状态为 DEFAULT;
|
|
13
|
+
* - 键无任何来源(不在合并视图中,即未声明默认值也未持久化)时状态为 MISSING。
|
|
14
|
+
*
|
|
8
15
|
* @param configCmd config 命令实例
|
|
9
|
-
* @param context
|
|
16
|
+
* @param context CLI 上下文
|
|
10
17
|
*/
|
|
11
18
|
export function registerConfigSchemaCommand(configCmd, context) {
|
|
12
|
-
configCmd
|
|
19
|
+
applyTargetOptions(configCmd
|
|
13
20
|
.command("schema [identifier]")
|
|
14
21
|
.alias("check")
|
|
15
22
|
.description("Inspect declared configuration requirements and check resolution status")
|
|
16
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
23
|
+
.option("-P, --package <id>", "Target package ID or path"))
|
|
17
24
|
.option("--data-dir <path>", "Custom database storage directory")
|
|
18
25
|
.option("--json", "Output as JSON")
|
|
19
26
|
.action(async (identifier, rawOptions, cmd) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
dataDir: options.dataDir || context?.dataDir,
|
|
38
|
-
});
|
|
39
|
-
let globalConfig = [];
|
|
40
|
-
let projectConfig = [];
|
|
41
|
-
try {
|
|
42
|
-
globalConfig = await target.listConfig("global");
|
|
43
|
-
projectConfig = await target.listConfig(projConfig.id);
|
|
44
|
-
}
|
|
45
|
-
finally {
|
|
46
|
-
await target.close();
|
|
47
|
-
}
|
|
48
|
-
const projectConfigMap = new Map(projectConfig.map((c) => [c.key, c]));
|
|
49
|
-
const globalConfigMap = new Map(globalConfig.map((c) => [c.key, c]));
|
|
50
|
-
const items = declaredKeys.map((key) => {
|
|
27
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
28
|
+
const targetPkg = identifier || options.package;
|
|
29
|
+
const { root, projConfig } = requirePackageRoot(targetPkg, {
|
|
30
|
+
loadConfig: true,
|
|
31
|
+
hint: "Usage: ad config schema [package-id] or cd into a project directory.",
|
|
32
|
+
});
|
|
33
|
+
const declared = projConfig.config || {};
|
|
34
|
+
// 远端目标显式拒绝:schema 状态推导依赖本地工程声明与环境变量解析,
|
|
35
|
+
// 远端作用域无法获得等价视图,静默落到本地会误导调用方
|
|
36
|
+
if (options.profile || options.server) {
|
|
37
|
+
throw notInProjectError("'ad config schema' only supports local projects. Remote targets are not supported for schema inspection.");
|
|
38
|
+
}
|
|
39
|
+
// 跨作用域合并视图单一事实源:与 config list 共享同一条优先级链
|
|
40
|
+
await withService(options, context, async (service) => {
|
|
41
|
+
const merged = await buildMergedConfigEntries(root, service, true);
|
|
42
|
+
const mergedByKey = new Map(merged.map((entry) => [entry.key, entry]));
|
|
43
|
+
const items = Object.keys(declared).map((key) => {
|
|
51
44
|
const itemDef = declared[key];
|
|
52
45
|
const isSecret = isSecretConfigKey(key, itemDef);
|
|
53
|
-
|
|
46
|
+
const mergedEntry = mergedByKey.get(key);
|
|
54
47
|
let source = "missing";
|
|
55
48
|
let status = "MISSING";
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
else if (envResolved !== undefined) {
|
|
70
|
-
resolvedValue = envResolved.value;
|
|
71
|
-
source = "env";
|
|
72
|
-
status = "SET";
|
|
73
|
-
}
|
|
74
|
-
else if (itemDef.default !== undefined) {
|
|
75
|
-
resolvedValue = itemDef.default;
|
|
76
|
-
source = "default";
|
|
77
|
-
status = "DEFAULT";
|
|
49
|
+
let resolvedValue;
|
|
50
|
+
if (mergedEntry) {
|
|
51
|
+
source = mergedEntry.source;
|
|
52
|
+
resolvedValue = mergedEntry.value;
|
|
53
|
+
// 合并视图的 default 来源仅是链尾兑底标签:
|
|
54
|
+
// 真正的 DEFAULT 状态要求声明确实携带默认值,否则视为 MISSING
|
|
55
|
+
if (mergedEntry.source !== "default") {
|
|
56
|
+
status = "SET";
|
|
57
|
+
}
|
|
58
|
+
else if (itemDef.default !== undefined) {
|
|
59
|
+
status = "DEFAULT";
|
|
60
|
+
}
|
|
78
61
|
}
|
|
79
62
|
return {
|
|
80
63
|
key,
|
|
@@ -108,12 +91,6 @@ export function registerConfigSchemaCommand(configCmd, context) {
|
|
|
108
91
|
if (!ok) {
|
|
109
92
|
process.exitCode = 1;
|
|
110
93
|
}
|
|
111
|
-
}
|
|
112
|
-
catch (err) {
|
|
113
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
114
|
-
throw err;
|
|
115
|
-
}
|
|
116
|
-
throw new ExecutionError(err.message);
|
|
117
|
-
}
|
|
94
|
+
}, { localRoot: root });
|
|
118
95
|
});
|
|
119
96
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { isSecretConfigKey,
|
|
1
|
+
import { isSecretConfigKey, } from "@actiondock/core/project";
|
|
2
|
+
import { loadProjectConfig, } from "@actiondock/core";
|
|
3
|
+
import { resolvePackageRoot, } from "@actiondock/core/registry";
|
|
2
4
|
import { ArgumentError, packageNotFoundError } from "../../errors.js";
|
|
3
5
|
import { writeStdout } from "../../renderer.js";
|
|
4
|
-
import { applyTargetOptions, getEffectiveOptions,
|
|
6
|
+
import { applyTargetOptions, getEffectiveOptions, withService } from "../../utils/index.js";
|
|
5
7
|
import { resolveConfigValueInput } from "../../prompt.js";
|
|
6
8
|
/**
|
|
7
9
|
* 注册 config set 子命令:写入配置值(支持标准输入与安全提示)。
|
|
@@ -56,14 +58,14 @@ export function registerConfigSetCommand(configCmd, context) {
|
|
|
56
58
|
parsedVal = effectiveValueStr;
|
|
57
59
|
}
|
|
58
60
|
// 目标解析与写入(远端分支直接写远端作用域,本地分支按全局/项目作用域写入)
|
|
59
|
-
await
|
|
61
|
+
await withService(options, context, async (service, resolved) => {
|
|
60
62
|
if (resolved.type === "remote") {
|
|
61
|
-
await
|
|
63
|
+
await service.management?.config.set(options.package || "", key, parsedVal);
|
|
62
64
|
writeStdout(`[OK] Configuration '${key}' updated on remote server`, context);
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
if (options.global) {
|
|
66
|
-
await
|
|
68
|
+
await service.management?.config.set("global", key, parsedVal);
|
|
67
69
|
writeStdout(`[OK] Global configuration '${key}' updated`, context);
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
@@ -71,11 +73,11 @@ export function registerConfigSetCommand(configCmd, context) {
|
|
|
71
73
|
if (options.package) {
|
|
72
74
|
throw packageNotFoundError(options.package);
|
|
73
75
|
}
|
|
74
|
-
await
|
|
76
|
+
await service.management?.config.set("global", key, parsedVal);
|
|
75
77
|
writeStdout(`[OK] Global configuration '${key}' updated (no project in current directory)`, context);
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
|
-
await
|
|
80
|
+
await service.management?.config.set(projConfig.id, key, parsedVal);
|
|
79
81
|
writeStdout(`[OK] Configuration '${key}' updated for package '${projConfig.id}'`, context);
|
|
80
82
|
});
|
|
81
83
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ACTION_NOT_FOUND, PACKAGE_NOT_FOUND, NOT_FOUND, } from "@actiondock/core";
|
|
2
|
+
import { buildActionDescribePayload, formatActionDetail, } from "@actiondock/core/project";
|
|
2
3
|
import { ArgumentError, ExecutionError, packageNotFoundError } from "../errors.js";
|
|
3
4
|
import { renderResult } from "../renderer.js";
|
|
4
|
-
import { applyTargetOptions, getEffectiveOptions, resolveLocalPackageRoot,
|
|
5
|
+
import { applyTargetOptions, getEffectiveOptions, resolveLocalPackageRoot, withService, } from "../utils/index.js";
|
|
5
6
|
/**
|
|
6
7
|
* 挂载 describe 子命令至指定 Commander 节点。
|
|
7
8
|
*
|
|
@@ -28,18 +29,18 @@ export function attachDescribeCommand(parent, context) {
|
|
|
28
29
|
throw packageNotFoundError(options.package);
|
|
29
30
|
}
|
|
30
31
|
const targetRef = id;
|
|
31
|
-
// 通过
|
|
32
|
-
await
|
|
32
|
+
// 通过 Service 门面统一查询 Action 规范
|
|
33
|
+
await withService(options, context, async (service) => {
|
|
33
34
|
let spec;
|
|
34
35
|
try {
|
|
35
|
-
spec = await
|
|
36
|
+
spec = await service.discovery.describeAction(targetRef);
|
|
36
37
|
}
|
|
37
38
|
catch (err) {
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
throw new ArgumentError(
|
|
39
|
+
const code = err?.code;
|
|
40
|
+
if (code === ACTION_NOT_FOUND || code === NOT_FOUND || code === PACKAGE_NOT_FOUND) {
|
|
41
|
+
throw new ArgumentError(err?.message || String(err), err?.details, code);
|
|
41
42
|
}
|
|
42
|
-
throw new ExecutionError(
|
|
43
|
+
throw new ExecutionError(err?.message || String(err), err?.details, code);
|
|
43
44
|
}
|
|
44
45
|
const payload = buildActionDescribePayload(spec);
|
|
45
46
|
renderResult(payload, {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { fetchRemoteDoctor,
|
|
2
|
-
import {
|
|
1
|
+
import { fetchRemoteDoctor, } from "@actiondock/core/profile";
|
|
2
|
+
import { runDoctorChecks, } from "@actiondock/core/project";
|
|
3
|
+
import { wrapAsExecutionError } from "../errors.js";
|
|
3
4
|
import { renderResult } from "../renderer.js";
|
|
4
5
|
import { applyTargetOptions, getEffectiveOptions, resolveTargetFromOptions } from "../utils/index.js";
|
|
5
6
|
export function registerDoctorCommand(program, context) {
|
|
@@ -71,7 +72,7 @@ export function registerDoctorCommand(program, context) {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
catch (err) {
|
|
74
|
-
throw
|
|
75
|
+
throw wrapAsExecutionError(err, "Doctor failed to run diagnostics: ");
|
|
75
76
|
}
|
|
76
77
|
});
|
|
77
78
|
}
|