@actiondock/core 2.0.11 → 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 +61 -30
- package/dist/app/app.d.ts +73 -0
- package/dist/app/app.js +700 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/types.d.ts +283 -0
- package/dist/app/types.js +1 -0
- package/dist/catalog/action-index.d.ts +9 -0
- package/dist/catalog/action-index.js +93 -0
- package/dist/catalog/action-resolver.d.ts +20 -0
- package/dist/catalog/action-resolver.js +95 -0
- package/dist/catalog/index.d.ts +5 -0
- package/dist/catalog/index.js +5 -0
- package/dist/catalog/location-registry.d.ts +15 -0
- package/dist/catalog/location-registry.js +138 -0
- package/dist/catalog/package-catalog.d.ts +7 -0
- package/dist/catalog/package-catalog.js +76 -0
- package/dist/catalog/types.d.ts +68 -0
- package/dist/catalog/types.js +1 -0
- package/dist/doctor/doctor.d.ts +7 -0
- package/dist/doctor/doctor.js +613 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/types.d.ts +23 -0
- package/dist/doctor/types.js +1 -0
- package/dist/errors.d.ts +122 -0
- package/dist/errors.js +123 -0
- package/dist/execution/index.d.ts +2 -0
- package/dist/execution/index.js +2 -0
- package/dist/execution/service.d.ts +79 -0
- package/dist/execution/service.js +633 -0
- package/dist/execution/types.d.ts +131 -0
- package/dist/execution/types.js +1 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/export/index.js +1 -0
- package/dist/export/templates.d.ts +71 -0
- package/dist/export/templates.js +621 -0
- package/dist/filter/index.d.ts +1 -0
- package/dist/filter/index.js +1 -0
- package/dist/filter/intent.d.ts +33 -0
- package/dist/filter/intent.js +123 -0
- package/dist/host/host.d.ts +55 -0
- package/dist/host/host.js +740 -0
- package/dist/host/index.d.ts +2 -0
- package/dist/host/index.js +2 -0
- package/dist/host/types.d.ts +81 -0
- package/dist/host/types.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +20 -0
- package/dist/ipc/diagnostic.d.ts +65 -0
- package/dist/ipc/diagnostic.js +129 -0
- package/dist/ipc/host.d.ts +7 -0
- package/dist/ipc/host.js +93 -0
- package/dist/ipc/index.d.ts +4 -0
- package/dist/ipc/index.js +4 -0
- package/dist/ipc/target.d.ts +56 -0
- package/dist/ipc/target.js +297 -0
- package/dist/ipc/types.d.ts +42 -0
- package/dist/ipc/types.js +1 -0
- package/dist/platform/default.d.ts +32 -0
- package/dist/platform/default.js +40 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +3 -0
- package/dist/platform/node-fs.d.ts +37 -0
- package/dist/platform/node-fs.js +81 -0
- package/dist/platform/types.d.ts +104 -0
- package/dist/platform/types.js +1 -0
- package/dist/profile/client.d.ts +162 -0
- package/dist/profile/client.js +467 -0
- package/dist/profile/index.d.ts +3 -0
- package/dist/profile/index.js +3 -0
- package/dist/profile/manager.d.ts +47 -0
- package/dist/profile/manager.js +294 -0
- package/dist/profile/types.d.ts +61 -0
- package/dist/profile/types.js +1 -0
- package/dist/project/closure.d.ts +25 -0
- package/dist/project/closure.js +68 -0
- package/dist/project/digest.d.ts +29 -0
- package/dist/project/digest.js +324 -0
- package/dist/project/index.d.ts +10 -0
- package/dist/project/index.js +10 -0
- package/dist/project/init.d.ts +26 -0
- package/dist/project/init.js +175 -0
- package/dist/project/loader.d.ts +99 -0
- package/dist/project/loader.js +484 -0
- package/dist/project/lockfile.d.ts +55 -0
- package/dist/project/lockfile.js +175 -0
- package/dist/project/manifest.d.ts +22 -0
- package/dist/project/manifest.js +220 -0
- package/dist/project/resolver.d.ts +116 -0
- package/dist/project/resolver.js +376 -0
- package/dist/project/transactions.d.ts +103 -0
- package/dist/project/transactions.js +1203 -0
- package/dist/project/types-generator.d.ts +33 -0
- package/dist/project/types-generator.js +168 -0
- package/dist/project/types.d.ts +107 -0
- package/dist/project/types.js +1 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +5 -0
- package/dist/registry/lock.d.ts +27 -0
- package/dist/registry/lock.js +93 -0
- package/dist/registry/registry.d.ts +45 -0
- package/dist/registry/registry.js +611 -0
- package/dist/registry/resolve.d.ts +62 -0
- package/dist/registry/resolve.js +195 -0
- package/dist/registry/scan.d.ts +38 -0
- package/dist/registry/scan.js +135 -0
- package/dist/registry/types.d.ts +117 -0
- package/dist/registry/types.js +1 -0
- package/dist/runtime/action-collection.d.ts +27 -0
- package/dist/runtime/action-collection.js +57 -0
- package/dist/runtime/clock.d.ts +19 -0
- package/dist/runtime/clock.js +17 -0
- package/dist/runtime/context.d.ts +86 -0
- package/dist/runtime/context.js +242 -0
- package/dist/runtime/env.d.ts +56 -0
- package/dist/runtime/env.js +159 -0
- package/dist/runtime/events.d.ts +93 -0
- package/dist/runtime/events.js +604 -0
- package/dist/runtime/execution-manager.d.ts +48 -0
- package/dist/runtime/execution-manager.js +66 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/module-loader.d.ts +34 -0
- package/dist/runtime/module-loader.js +16 -0
- package/dist/runtime/process.d.ts +9 -0
- package/dist/runtime/process.js +146 -0
- package/dist/runtime/runner.d.ts +293 -0
- package/dist/runtime/runner.js +984 -0
- package/dist/runtime/standalone.d.ts +89 -0
- package/dist/runtime/standalone.js +536 -0
- package/dist/schema/validator.d.ts +28 -0
- package/dist/schema/validator.js +116 -0
- package/dist/server/body.d.ts +40 -0
- package/dist/server/body.js +93 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +5 -0
- package/dist/server/routes/actions.d.ts +5 -0
- package/dist/server/routes/actions.js +298 -0
- package/dist/server/routes/common.d.ts +47 -0
- package/dist/server/routes/common.js +104 -0
- package/dist/server/routes/config.d.ts +6 -0
- package/dist/server/routes/config.js +173 -0
- package/dist/server/routes/doctor.d.ts +5 -0
- package/dist/server/routes/doctor.js +63 -0
- package/dist/server/routes/health.d.ts +5 -0
- package/dist/server/routes/health.js +35 -0
- package/dist/server/routes/index.d.ts +9 -0
- package/dist/server/routes/index.js +9 -0
- package/dist/server/routes/info.d.ts +7 -0
- package/dist/server/routes/info.js +158 -0
- package/dist/server/routes/playbooks.d.ts +5 -0
- package/dist/server/routes/playbooks.js +134 -0
- package/dist/server/routes/runs.d.ts +5 -0
- package/dist/server/routes/runs.js +343 -0
- package/dist/server/routes/state.d.ts +6 -0
- package/dist/server/routes/state.js +169 -0
- package/dist/server/security.d.ts +44 -0
- package/dist/server/security.js +101 -0
- package/dist/server/server.d.ts +15 -0
- package/dist/server/server.js +355 -0
- package/dist/server/types.d.ts +78 -0
- package/dist/server/types.js +1 -0
- package/dist/storage/data-dir-lock.d.ts +119 -0
- package/dist/storage/data-dir-lock.js +1016 -0
- package/dist/storage/driver.d.ts +9 -0
- package/dist/storage/driver.js +59 -0
- package/dist/storage/index.d.ts +64 -0
- package/dist/storage/index.js +98 -0
- package/dist/storage/lazy.d.ts +8 -0
- package/dist/storage/lazy.js +44 -0
- package/dist/storage/mask.d.ts +26 -0
- package/dist/storage/mask.js +48 -0
- package/dist/storage/params.d.ts +13 -0
- package/dist/storage/params.js +32 -0
- package/dist/storage/sqlite.d.ts +79 -0
- package/dist/storage/sqlite.js +689 -0
- package/dist/storage/types.d.ts +172 -0
- package/dist/storage/types.js +14 -0
- package/dist/target/index.d.ts +4 -0
- package/dist/target/index.js +4 -0
- package/dist/target/local.d.ts +52 -0
- package/dist/target/local.js +343 -0
- package/dist/target/remote.d.ts +76 -0
- package/dist/target/remote.js +839 -0
- package/dist/target/target.d.ts +6 -0
- package/dist/target/target.js +35 -0
- package/dist/target/types.d.ts +246 -0
- package/dist/target/types.js +34 -0
- package/dist/utils/index.d.ts +49 -0
- package/dist/utils/index.js +180 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +4 -0
- package/package.json +13 -13
- package/src/build/index.ts +0 -1
- package/src/build/templates.ts +0 -59
- package/src/catalog/action-index.ts +0 -92
- package/src/catalog/action-resolver.ts +0 -120
- package/src/catalog/index.ts +0 -5
- package/src/catalog/location-registry.ts +0 -134
- package/src/catalog/package-catalog.ts +0 -87
- package/src/catalog/types.ts +0 -75
- package/src/doctor/doctor.ts +0 -419
- package/src/doctor/index.ts +0 -2
- package/src/doctor/types.ts +0 -25
- package/src/execution/index.ts +0 -2
- package/src/execution/service.ts +0 -322
- package/src/execution/types.ts +0 -73
- package/src/export/index.ts +0 -1
- package/src/export/templates.ts +0 -590
- package/src/filter/index.ts +0 -1
- package/src/filter/intent.ts +0 -154
- package/src/index.ts +0 -16
- package/src/profile/client.ts +0 -552
- package/src/profile/index.ts +0 -3
- package/src/profile/manager.ts +0 -341
- package/src/profile/types.ts +0 -71
- package/src/project/index.ts +0 -4
- package/src/project/init.ts +0 -242
- package/src/project/loader.ts +0 -479
- package/src/project/manifest.ts +0 -299
- package/src/project/types.ts +0 -141
- package/src/registry/index.ts +0 -2
- package/src/registry/registry.ts +0 -940
- package/src/registry/types.ts +0 -127
- package/src/runtime/clock.ts +0 -41
- package/src/runtime/context.ts +0 -259
- package/src/runtime/env.ts +0 -172
- package/src/runtime/events.ts +0 -142
- package/src/runtime/execution-manager.ts +0 -74
- package/src/runtime/index.ts +0 -10
- package/src/runtime/module-loader.ts +0 -67
- package/src/runtime/process.ts +0 -245
- package/src/runtime/runner.ts +0 -527
- package/src/runtime/standalone.ts +0 -429
- package/src/schema/validator.ts +0 -61
- package/src/server/body.ts +0 -112
- package/src/server/index.ts +0 -7
- package/src/server/routes/actions.ts +0 -262
- package/src/server/routes/common.ts +0 -126
- package/src/server/routes/config.ts +0 -147
- package/src/server/routes/doctor.ts +0 -29
- package/src/server/routes/health.ts +0 -40
- package/src/server/routes/index.ts +0 -9
- package/src/server/routes/info.ts +0 -221
- package/src/server/routes/playbooks.ts +0 -109
- package/src/server/routes/runs.ts +0 -301
- package/src/server/routes/state.ts +0 -133
- package/src/server/runtime-registry.ts +0 -115
- package/src/server/security.ts +0 -115
- package/src/server/server.ts +0 -251
- package/src/server/types.ts +0 -57
- package/src/storage/driver.ts +0 -126
- package/src/storage/index.ts +0 -81
- package/src/storage/mask.ts +0 -34
- package/src/storage/sqlite.ts +0 -714
- package/src/storage/types.ts +0 -139
- package/src/utils/index.ts +0 -62
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { toSnakeUpperCase } from "../runtime/env.js";
|
|
4
|
+
import { isLoopbackHost } from "../server/security.js";
|
|
5
|
+
import { getActionDockHome } from "../utils/index.js";
|
|
6
|
+
const PROFILE_NAME_REGEX = /^[a-zA-Z0-9_\-\.]+$/;
|
|
7
|
+
/**
|
|
8
|
+
* 默认初始 Profiles 配置(预设 local 本地环境)。
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_PROFILES_CONFIG = {
|
|
11
|
+
currentProfile: "local",
|
|
12
|
+
profiles: {
|
|
13
|
+
local: {
|
|
14
|
+
serverUrl: "local",
|
|
15
|
+
description: "Local execution environment",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* 格式化并规范化 Server URL 地址(若未指定协议,本地回环地址默认使用 http://,非本地回环地址默认使用 https://,并移除末尾斜杠)。
|
|
21
|
+
*/
|
|
22
|
+
export function normalizeServerUrl(url) {
|
|
23
|
+
let cleaned = url.trim().replace(/\/+$/, "");
|
|
24
|
+
if (!cleaned || cleaned === "local") {
|
|
25
|
+
return cleaned;
|
|
26
|
+
}
|
|
27
|
+
if (!/^https?:\/\//i.test(cleaned)) {
|
|
28
|
+
let hostname = cleaned;
|
|
29
|
+
const slashIdx = hostname.indexOf("/");
|
|
30
|
+
if (slashIdx !== -1) {
|
|
31
|
+
hostname = hostname.slice(0, slashIdx);
|
|
32
|
+
}
|
|
33
|
+
if (hostname.startsWith("[")) {
|
|
34
|
+
const endBracket = hostname.indexOf("]");
|
|
35
|
+
if (endBracket !== -1) {
|
|
36
|
+
hostname = hostname.slice(1, endBracket);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const colonIdx = hostname.indexOf(":");
|
|
41
|
+
if (colonIdx !== -1) {
|
|
42
|
+
hostname = hostname.slice(0, colonIdx);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const isLoopback = isLoopbackHost(hostname);
|
|
46
|
+
cleaned = `${isLoopback ? "http" : "https"}://${cleaned}`;
|
|
47
|
+
}
|
|
48
|
+
return cleaned;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 获取 profiles.json 配置文件的物理绝对路径(~/.actiondock/profiles.json)。
|
|
52
|
+
*/
|
|
53
|
+
export function getProfilesFilePath(customHome) {
|
|
54
|
+
const baseDir = getActionDockHome(customHome);
|
|
55
|
+
return join(baseDir, ".actiondock", "profiles.json");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 加载并读取 profiles.json 配置文件。
|
|
59
|
+
*/
|
|
60
|
+
export function loadProfiles(customHome) {
|
|
61
|
+
const filePath = getProfilesFilePath(customHome);
|
|
62
|
+
if (!existsSync(filePath)) {
|
|
63
|
+
return structuredClone(DEFAULT_PROFILES_CONFIG);
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
67
|
+
const parsed = JSON.parse(raw);
|
|
68
|
+
if (!parsed || typeof parsed !== "object" || !parsed.profiles) {
|
|
69
|
+
return structuredClone(DEFAULT_PROFILES_CONFIG);
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return structuredClone(DEFAULT_PROFILES_CONFIG);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 保存并写入 profiles.json 配置文件,并严格限制文件权限为 0600。
|
|
79
|
+
*/
|
|
80
|
+
export function saveProfiles(data, customHome) {
|
|
81
|
+
const filePath = getProfilesFilePath(customHome);
|
|
82
|
+
const dir = dirname(filePath);
|
|
83
|
+
try {
|
|
84
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
85
|
+
try {
|
|
86
|
+
chmodSync(dir, 0o700);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Ignore on systems where chmod is not supported
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore
|
|
94
|
+
}
|
|
95
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", {
|
|
96
|
+
encoding: "utf-8",
|
|
97
|
+
mode: 0o600,
|
|
98
|
+
});
|
|
99
|
+
try {
|
|
100
|
+
chmodSync(filePath, 0o600);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Ignore on systems where chmod is not supported
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function addProfile(name, entry, customHome) {
|
|
107
|
+
const trimmedName = name.trim();
|
|
108
|
+
if (!trimmedName) {
|
|
109
|
+
throw new Error("Profile name cannot be empty");
|
|
110
|
+
}
|
|
111
|
+
if (!PROFILE_NAME_REGEX.test(trimmedName)) {
|
|
112
|
+
throw new Error(`Invalid profile name '${trimmedName}'. Profile names may only contain letters, numbers, hyphens, underscores, and dots.`);
|
|
113
|
+
}
|
|
114
|
+
const profilesConfig = loadProfiles(customHome);
|
|
115
|
+
const normalizedServer = normalizeServerUrl(entry.serverUrl);
|
|
116
|
+
profilesConfig.profiles[trimmedName] = {
|
|
117
|
+
serverUrl: normalizedServer,
|
|
118
|
+
token: entry.token?.trim() || undefined,
|
|
119
|
+
tokenEnv: entry.tokenEnv?.trim() || undefined,
|
|
120
|
+
description: entry.description?.trim() || undefined,
|
|
121
|
+
};
|
|
122
|
+
saveProfiles(profilesConfig, customHome);
|
|
123
|
+
}
|
|
124
|
+
export function removeProfile(name, customHome) {
|
|
125
|
+
const trimmedName = name.trim();
|
|
126
|
+
const profilesConfig = loadProfiles(customHome);
|
|
127
|
+
if (!profilesConfig.profiles[trimmedName]) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
delete profilesConfig.profiles[trimmedName];
|
|
131
|
+
if (profilesConfig.currentProfile === trimmedName) {
|
|
132
|
+
profilesConfig.currentProfile = "local";
|
|
133
|
+
}
|
|
134
|
+
saveProfiles(profilesConfig, customHome);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
export function useProfile(name, customHome) {
|
|
138
|
+
const trimmedName = name.trim();
|
|
139
|
+
const profilesConfig = loadProfiles(customHome);
|
|
140
|
+
if (trimmedName !== "local" && !profilesConfig.profiles[trimmedName]) {
|
|
141
|
+
throw new Error(`Profile '${trimmedName}' not found. Use 'ad profile list' to see available profiles or 'ad profile add' to register one.`);
|
|
142
|
+
}
|
|
143
|
+
profilesConfig.currentProfile = trimmedName;
|
|
144
|
+
saveProfiles(profilesConfig, customHome);
|
|
145
|
+
}
|
|
146
|
+
export function getProfile(name, customHome) {
|
|
147
|
+
const profilesConfig = loadProfiles(customHome);
|
|
148
|
+
return profilesConfig.profiles[name.trim()];
|
|
149
|
+
}
|
|
150
|
+
export function listProfiles(customHome) {
|
|
151
|
+
const profilesConfig = loadProfiles(customHome);
|
|
152
|
+
const current = profilesConfig.currentProfile || "local";
|
|
153
|
+
const entries = [];
|
|
154
|
+
// Ensure 'local' is listed
|
|
155
|
+
if (!profilesConfig.profiles["local"]) {
|
|
156
|
+
entries.push({
|
|
157
|
+
name: "local",
|
|
158
|
+
isCurrent: current === "local",
|
|
159
|
+
entry: {
|
|
160
|
+
serverUrl: "local",
|
|
161
|
+
description: "Local execution environment",
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
for (const [name, entry] of Object.entries(profilesConfig.profiles)) {
|
|
166
|
+
entries.push({
|
|
167
|
+
name,
|
|
168
|
+
isCurrent: name === current,
|
|
169
|
+
entry,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return entries;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolves token following multi-tier precedence:
|
|
176
|
+
* 1. CLI explicit --token
|
|
177
|
+
* 2. profile.tokenEnv specified environment variable
|
|
178
|
+
* 3. Derived profile environment variable: ACTIONDOCK_<PROFILE>_TOKEN or <PROFILE>_TOKEN
|
|
179
|
+
* 4. Stored token in profiles.json (deprecated)
|
|
180
|
+
* 5. Global ACTIONDOCK_TOKEN
|
|
181
|
+
*/
|
|
182
|
+
export function resolveProfileToken(profileName, entry, explicitToken) {
|
|
183
|
+
// 1. Explicit CLI --token
|
|
184
|
+
if (explicitToken && explicitToken.trim()) {
|
|
185
|
+
return { token: explicitToken.trim(), source: "cli" };
|
|
186
|
+
}
|
|
187
|
+
// 2. Explicit tokenEnv in profile
|
|
188
|
+
if (entry?.tokenEnv && entry.tokenEnv.trim()) {
|
|
189
|
+
const envKey = entry.tokenEnv.trim();
|
|
190
|
+
const envVal = process.env[envKey];
|
|
191
|
+
if (envVal !== undefined && envVal.trim()) {
|
|
192
|
+
return { token: envVal.trim(), source: "tokenEnv" };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// 3. Derived profile environment variable: ACTIONDOCK_<PROFILE>_TOKEN / <PROFILE>_TOKEN
|
|
196
|
+
if (profileName && profileName !== "local") {
|
|
197
|
+
const snakeName = toSnakeUpperCase(profileName);
|
|
198
|
+
const candidate1 = `ACTIONDOCK_${snakeName}_TOKEN`;
|
|
199
|
+
const candidate2 = `${snakeName}_TOKEN`;
|
|
200
|
+
if (process.env[candidate1] && process.env[candidate1].trim()) {
|
|
201
|
+
return { token: process.env[candidate1].trim(), source: "profileEnv" };
|
|
202
|
+
}
|
|
203
|
+
if (process.env[candidate2] && process.env[candidate2].trim()) {
|
|
204
|
+
return { token: process.env[candidate2].trim(), source: "profileEnv" };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// 4. Stored token in profiles.json (deprecated fallback)
|
|
208
|
+
if (entry?.token && entry.token.trim()) {
|
|
209
|
+
return { token: entry.token.trim(), source: "profile" };
|
|
210
|
+
}
|
|
211
|
+
// 5. Global ACTIONDOCK_TOKEN
|
|
212
|
+
if (process.env.ACTIONDOCK_TOKEN && process.env.ACTIONDOCK_TOKEN.trim()) {
|
|
213
|
+
return { token: process.env.ACTIONDOCK_TOKEN.trim(), source: "globalEnv" };
|
|
214
|
+
}
|
|
215
|
+
return { token: undefined, source: "none" };
|
|
216
|
+
}
|
|
217
|
+
export function resolveTarget(options, customHome) {
|
|
218
|
+
// 1. Explicit CLI --server flag
|
|
219
|
+
if (options?.server && options.server.trim()) {
|
|
220
|
+
const resolvedToken = resolveProfileToken(undefined, undefined, options.token);
|
|
221
|
+
return {
|
|
222
|
+
type: "remote",
|
|
223
|
+
serverUrl: normalizeServerUrl(options.server),
|
|
224
|
+
token: resolvedToken.token,
|
|
225
|
+
tokenSource: resolvedToken.source,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const profilesConfig = loadProfiles(customHome);
|
|
229
|
+
// 2. Explicit CLI --profile flag
|
|
230
|
+
if (options?.profile && options.profile.trim()) {
|
|
231
|
+
const pName = options.profile.trim();
|
|
232
|
+
if (pName === "local") {
|
|
233
|
+
return { type: "local", profileName: "local" };
|
|
234
|
+
}
|
|
235
|
+
const found = profilesConfig.profiles[pName];
|
|
236
|
+
if (!found) {
|
|
237
|
+
throw new Error(`Profile '${pName}' not found. Configure it with 'ad profile add ${pName} --server <url>'`);
|
|
238
|
+
}
|
|
239
|
+
const resolvedToken = resolveProfileToken(pName, found, options.token);
|
|
240
|
+
return {
|
|
241
|
+
type: "remote",
|
|
242
|
+
profileName: pName,
|
|
243
|
+
serverUrl: found.serverUrl,
|
|
244
|
+
token: resolvedToken.token,
|
|
245
|
+
tokenSource: resolvedToken.source,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
// 3. Environment variable ACTIONDOCK_SERVER_URL
|
|
249
|
+
if (process.env.ACTIONDOCK_SERVER_URL && process.env.ACTIONDOCK_SERVER_URL.trim()) {
|
|
250
|
+
const resolvedToken = resolveProfileToken(undefined, undefined, options?.token);
|
|
251
|
+
return {
|
|
252
|
+
type: "remote",
|
|
253
|
+
serverUrl: normalizeServerUrl(process.env.ACTIONDOCK_SERVER_URL),
|
|
254
|
+
token: resolvedToken.token,
|
|
255
|
+
tokenSource: resolvedToken.source,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// 4. Environment variable ACTIONDOCK_PROFILE
|
|
259
|
+
if (process.env.ACTIONDOCK_PROFILE && process.env.ACTIONDOCK_PROFILE.trim()) {
|
|
260
|
+
const pName = process.env.ACTIONDOCK_PROFILE.trim();
|
|
261
|
+
if (pName === "local") {
|
|
262
|
+
return { type: "local", profileName: "local" };
|
|
263
|
+
}
|
|
264
|
+
const found = profilesConfig.profiles[pName];
|
|
265
|
+
if (!found) {
|
|
266
|
+
throw new Error(`Profile '${pName}' (from ACTIONDOCK_PROFILE) not found. Configure it with 'ad profile add ${pName} --server <url>'`);
|
|
267
|
+
}
|
|
268
|
+
const resolvedToken = resolveProfileToken(pName, found, options?.token);
|
|
269
|
+
return {
|
|
270
|
+
type: "remote",
|
|
271
|
+
profileName: pName,
|
|
272
|
+
serverUrl: found.serverUrl,
|
|
273
|
+
token: resolvedToken.token,
|
|
274
|
+
tokenSource: resolvedToken.source,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// 5. Current Profile in config
|
|
278
|
+
const current = profilesConfig.currentProfile;
|
|
279
|
+
if (current && current !== "local") {
|
|
280
|
+
const found = profilesConfig.profiles[current];
|
|
281
|
+
if (found && found.serverUrl && found.serverUrl !== "local") {
|
|
282
|
+
const resolvedToken = resolveProfileToken(current, found, options?.token);
|
|
283
|
+
return {
|
|
284
|
+
type: "remote",
|
|
285
|
+
profileName: current,
|
|
286
|
+
serverUrl: found.serverUrl,
|
|
287
|
+
token: resolvedToken.token,
|
|
288
|
+
tokenSource: resolvedToken.source,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// 6. Default to local
|
|
293
|
+
return { type: "local", profileName: "local" };
|
|
294
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 单个远端配置环境(Profile)实体定义。
|
|
3
|
+
*/
|
|
4
|
+
export interface ProfileEntry {
|
|
5
|
+
/** 远端 ActionDock 服务端地址(如 "http://192.168.1.100:5177" 或 "local") */
|
|
6
|
+
serverUrl: string;
|
|
7
|
+
/**
|
|
8
|
+
* 存储在配置文件中的明文鉴权 Token。
|
|
9
|
+
* @deprecated 强烈建议使用 tokenEnv 或标准环境变量(如 ACTIONDOCK_<PROFILE>_TOKEN),避免明文持久化
|
|
10
|
+
*/
|
|
11
|
+
token?: string;
|
|
12
|
+
/** 指定从哪一个操作系统环境变量名动态读取 Token */
|
|
13
|
+
tokenEnv?: string;
|
|
14
|
+
/** 该机器/环境的描述信息 */
|
|
15
|
+
description?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 全局 profiles.json 配置文件结构契约。
|
|
19
|
+
*/
|
|
20
|
+
export interface ProfilesConfig {
|
|
21
|
+
/** 当前激活的默认 Profile 名称(默认为 "local") */
|
|
22
|
+
currentProfile?: string;
|
|
23
|
+
/** 已配置的 Profile 字典映射表 */
|
|
24
|
+
profiles: Record<string, ProfileEntry>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Token 解析命中来源枚举。
|
|
28
|
+
*/
|
|
29
|
+
export type TokenResolutionSource = "cli" | "tokenEnv" | "profileEnv" | "profile" | "globalEnv" | "none";
|
|
30
|
+
/**
|
|
31
|
+
* 经过解析后确定的最终执行目标环境。
|
|
32
|
+
*/
|
|
33
|
+
export interface ResolvedTarget {
|
|
34
|
+
/** 执行环境类型:local (本地 Node.js 进程) 或 remote (远端 HTTP Server) */
|
|
35
|
+
type: "local" | "remote";
|
|
36
|
+
/** 命中的 Profile 名称 */
|
|
37
|
+
profileName?: string;
|
|
38
|
+
/** 远端 Server URL */
|
|
39
|
+
serverUrl?: string;
|
|
40
|
+
/** 解析出的有效鉴权 Token */
|
|
41
|
+
token?: string;
|
|
42
|
+
/** Token 数据来源 */
|
|
43
|
+
tokenSource?: TokenResolutionSource;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 远端服务器健康探测与时延检测结果。
|
|
47
|
+
*/
|
|
48
|
+
export interface RemoteHealthResult {
|
|
49
|
+
/** 服务端是否连通且鉴权成功 */
|
|
50
|
+
ok: boolean;
|
|
51
|
+
/** 服务端状态标识(如 "ok") */
|
|
52
|
+
status?: string;
|
|
53
|
+
/** 远端 ActionDock 版本号 */
|
|
54
|
+
version?: string;
|
|
55
|
+
/** 远端服务运行时间(秒) */
|
|
56
|
+
uptime?: number;
|
|
57
|
+
/** 网络往返延迟(毫秒) */
|
|
58
|
+
latencyMs: number;
|
|
59
|
+
/** 探测失败时的错误信息 */
|
|
60
|
+
error?: string;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface EnsureDependencyClosureOptions {
|
|
2
|
+
/**
|
|
3
|
+
* 自定义依赖安装回调函数(便于单测 Mock 与自定义扩展)
|
|
4
|
+
*/
|
|
5
|
+
ensure?: (root: string) => boolean | Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* 自定义 ActionDock 家目录
|
|
8
|
+
*/
|
|
9
|
+
customHome?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DependencyClosureResult {
|
|
12
|
+
/** 成功执行依赖安装或更新的项目根路径列表 */
|
|
13
|
+
installed: string[];
|
|
14
|
+
/** 无法在注册表中解析包引用的警告列表 */
|
|
15
|
+
warnings: string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一执行依赖预装(ensureProjectDependencies)。
|
|
19
|
+
* 内部已尊重 ACTIONDOCK_AUTO_INSTALL=false 环境变量。
|
|
20
|
+
*
|
|
21
|
+
* @param roots 根项目目录列表
|
|
22
|
+
* @param opts 选项参数
|
|
23
|
+
* @returns 安装成功的路径列表及警告信息
|
|
24
|
+
*/
|
|
25
|
+
export declare function ensureDependencyClosure(roots: string[], opts?: EnsureDependencyClosureOptions): Promise<DependencyClosureResult>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { ActionResolver } from "../catalog/action-resolver.js";
|
|
3
|
+
import { resolvePackageRoot } from "../registry/registry.js";
|
|
4
|
+
import { ensureProjectDependencies } from "./loader.js";
|
|
5
|
+
import { loadManifest } from "./manifest.js";
|
|
6
|
+
/**
|
|
7
|
+
* 广度优先遍历 (BFS) uses 声明的跨包依赖闭包,对涉及的每个项目包逐一执行依赖预装(ensureProjectDependencies)。
|
|
8
|
+
* 内部已尊重 ACTIONDOCK_AUTO_INSTALL=false 环境变量。
|
|
9
|
+
*
|
|
10
|
+
* @param roots 根项目目录列表
|
|
11
|
+
* @param opts 选项参数
|
|
12
|
+
* @returns 安装成功的路径列表及警告信息
|
|
13
|
+
*/
|
|
14
|
+
export async function ensureDependencyClosure(roots, opts = {}) {
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const queue = [...roots];
|
|
17
|
+
const installed = [];
|
|
18
|
+
const warnings = [];
|
|
19
|
+
while (queue.length > 0) {
|
|
20
|
+
const rawRoot = queue.shift();
|
|
21
|
+
if (!rawRoot)
|
|
22
|
+
continue;
|
|
23
|
+
const root = resolve(rawRoot);
|
|
24
|
+
if (seen.has(root))
|
|
25
|
+
continue;
|
|
26
|
+
seen.add(root);
|
|
27
|
+
const ensureFn = opts.ensure ?? ensureProjectDependencies;
|
|
28
|
+
const wasInstalled = await ensureFn(root);
|
|
29
|
+
if (wasInstalled) {
|
|
30
|
+
installed.push(root);
|
|
31
|
+
}
|
|
32
|
+
let manifest;
|
|
33
|
+
try {
|
|
34
|
+
manifest = loadManifest(root);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!manifest || !manifest.actions)
|
|
40
|
+
continue;
|
|
41
|
+
for (const actionEntry of Object.values(manifest.actions)) {
|
|
42
|
+
if (!Array.isArray(actionEntry.uses))
|
|
43
|
+
continue;
|
|
44
|
+
for (const rawRef of actionEntry.uses) {
|
|
45
|
+
if (typeof rawRef !== "string" || !rawRef.trim())
|
|
46
|
+
continue;
|
|
47
|
+
let parsed;
|
|
48
|
+
try {
|
|
49
|
+
parsed = ActionResolver.parseRef(rawRef);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
warnings.push(`uses 声明 '${rawRef}' 未在注册表中解析到包`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (parsed.packageId) {
|
|
56
|
+
const depRoot = resolvePackageRoot(parsed.packageId, root, opts.customHome);
|
|
57
|
+
if (depRoot) {
|
|
58
|
+
queue.push(resolve(depRoot));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
warnings.push(`uses 声明 '${rawRef}' 未在注册表中解析到包`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { installed, warnings };
|
|
68
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析 JSON 文本并在检测到重复键时抛出错误。
|
|
3
|
+
* 遵循 RFC 8785 清单校验规范:解析阶段必须率先拦截并拒绝重复键。
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseJsonWithoutDuplicates<T = unknown>(jsonText: string): T;
|
|
6
|
+
/**
|
|
7
|
+
* 依据 RFC 8785 规范化 JSON 数据。
|
|
8
|
+
* 规则:
|
|
9
|
+
* - 对象属性依据 UTF-16 代码单元进行升序排序;
|
|
10
|
+
* - 符号与键值之间不包含多余空白字符;
|
|
11
|
+
* - 浮点数与整数遵循 ECMAScript 规范序列化(负零转为零,拒绝非有限数);
|
|
12
|
+
* - 字符串转义严格遵循标准规范;
|
|
13
|
+
* - 数组保持原有顺序且元素递归规范化。
|
|
14
|
+
*/
|
|
15
|
+
export declare function canonicalizeJson(value: unknown): string;
|
|
16
|
+
/**
|
|
17
|
+
* 计算任意 JSON 结构或 JSON 字符串的 SHA-256 规范化摘要。
|
|
18
|
+
* 输出格式为 sha256-<hex>。
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeDigest(value: unknown): string;
|
|
21
|
+
/**
|
|
22
|
+
* 计算 Action 清单对象的唯一确定性 RFC 8785 摘要。
|
|
23
|
+
* 清单中的等价空格变化与字段顺序不会改变摘要结果。
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeManifestDigest(manifest: unknown): string;
|
|
26
|
+
/**
|
|
27
|
+
* 校验给定清单的摘要是否与期望值一致。
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyManifestDigest(manifest: unknown, expectedDigest: string): boolean;
|