@actiondock/cli 2.0.11 → 2.0.12
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 +15 -2
- package/bin/ad.js +13 -2
- package/dist/commands/action/create.d.ts +2 -0
- package/dist/commands/action/index.d.ts +16 -0
- package/dist/commands/action/list.d.ts +5 -0
- package/dist/commands/action/run.d.ts +4 -0
- package/dist/commands/action/show.d.ts +5 -0
- package/dist/commands/action/sync.d.ts +2 -0
- package/dist/commands/action/validate.d.ts +5 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/link.d.ts +2 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/playbook.d.ts +6 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/runs.d.ts +2 -0
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/state.d.ts +2 -0
- package/dist/commands/test.d.ts +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +745 -65708
- package/{src/utils/bytes.ts → dist/utils/bytes.d.ts} +0 -1
- package/{src/utils/filter.ts → dist/utils/filter.d.ts} +0 -1
- package/package.json +20 -15
- package/src/commands/action/create.ts +0 -129
- package/src/commands/action/index.ts +0 -27
- package/src/commands/action/list.ts +0 -247
- package/src/commands/action/run.ts +0 -197
- package/src/commands/action/show.ts +0 -128
- package/src/commands/action/sync.ts +0 -76
- package/src/commands/action/validate.ts +0 -102
- package/src/commands/build.ts +0 -56
- package/src/commands/config.ts +0 -583
- package/src/commands/doctor.ts +0 -84
- package/src/commands/export.ts +0 -196
- package/src/commands/index.ts +0 -75
- package/src/commands/info.ts +0 -537
- package/src/commands/init.ts +0 -24
- package/src/commands/link.ts +0 -73
- package/src/commands/mcp.ts +0 -195
- package/src/commands/playbook.ts +0 -566
- package/src/commands/profile.ts +0 -296
- package/src/commands/runs.ts +0 -452
- package/src/commands/serve.ts +0 -132
- package/src/commands/state.ts +0 -590
- package/src/commands/test.ts +0 -48
- package/src/index.ts +0 -58
- /package/{src/commands/action.ts → dist/commands/action.d.ts} +0 -0
- /package/{src/utils/duration.ts → dist/utils/duration.d.ts} +0 -0
package/src/commands/config.ts
DELETED
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createGlobalStorage,
|
|
3
|
-
createStorage,
|
|
4
|
-
deleteRemoteConfig,
|
|
5
|
-
fetchRemoteConfig,
|
|
6
|
-
filterWithFallbackInfo,
|
|
7
|
-
isSecretConfigKey,
|
|
8
|
-
loadProjectConfig,
|
|
9
|
-
maskSecretValue,
|
|
10
|
-
resolvePackageRoot,
|
|
11
|
-
resolveTarget,
|
|
12
|
-
setRemoteConfig,
|
|
13
|
-
type ConfigItemDefinition,
|
|
14
|
-
} from "@actiondock/core";
|
|
15
|
-
import { Command } from "commander";
|
|
16
|
-
import { ArgumentError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
17
|
-
import { resolveIntent } from "../utils/filter";
|
|
18
|
-
|
|
19
|
-
export function registerConfigCommands(program: Command): void {
|
|
20
|
-
const configCmd = program
|
|
21
|
-
.command("config")
|
|
22
|
-
.description("Manage runtime configuration store (Global & Project-level)");
|
|
23
|
-
|
|
24
|
-
// config schema / check
|
|
25
|
-
configCmd
|
|
26
|
-
.command("schema [identifier]")
|
|
27
|
-
.alias("check")
|
|
28
|
-
.description("Inspect declared configuration requirements and check resolution status")
|
|
29
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
30
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
31
|
-
.option("--json", "Output as JSON")
|
|
32
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
33
|
-
.action((identifier, rawOptions, cmd) => {
|
|
34
|
-
try {
|
|
35
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
36
|
-
const targetPkg = identifier || options.package;
|
|
37
|
-
const root = resolvePackageRoot(targetPkg);
|
|
38
|
-
if (!root) {
|
|
39
|
-
if (targetPkg) {
|
|
40
|
-
throw new ArgumentError(
|
|
41
|
-
`Package '${targetPkg}' not found in linked packages or path`
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
throw new ArgumentError(
|
|
45
|
-
"Not in an ActionDock project.\nUsage: ad config schema [package-id] or cd into a project directory."
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const projConfig = loadProjectConfig(root);
|
|
50
|
-
const declared = projConfig.config || {};
|
|
51
|
-
const declaredKeys = Object.keys(declared);
|
|
52
|
-
|
|
53
|
-
const globalStorage = createGlobalStorage(options.dataDir);
|
|
54
|
-
const globalConfig = globalStorage.listConfig();
|
|
55
|
-
globalStorage.close();
|
|
56
|
-
|
|
57
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
58
|
-
projectRoot: root,
|
|
59
|
-
dataDir: options.dataDir,
|
|
60
|
-
});
|
|
61
|
-
const projectConfig = projectStorage.listConfig();
|
|
62
|
-
projectStorage.close();
|
|
63
|
-
|
|
64
|
-
const items = declaredKeys.map((key) => {
|
|
65
|
-
const itemDef = declared[key];
|
|
66
|
-
const isSecret = isSecretConfigKey(key, itemDef);
|
|
67
|
-
|
|
68
|
-
let resolvedValue: unknown;
|
|
69
|
-
let source: "project" | "global" | "env" | "default" | "missing" = "missing";
|
|
70
|
-
let status: "SET" | "DEFAULT" | "MISSING" = "MISSING";
|
|
71
|
-
|
|
72
|
-
if (projectConfig[key] !== undefined) {
|
|
73
|
-
resolvedValue = projectConfig[key];
|
|
74
|
-
source = "project";
|
|
75
|
-
status = "SET";
|
|
76
|
-
} else if (globalConfig[key] !== undefined) {
|
|
77
|
-
resolvedValue = globalConfig[key];
|
|
78
|
-
source = "global";
|
|
79
|
-
status = "SET";
|
|
80
|
-
} else if (typeof process !== "undefined" && process.env && process.env[key] !== undefined) {
|
|
81
|
-
resolvedValue = process.env[key];
|
|
82
|
-
source = "env";
|
|
83
|
-
status = "SET";
|
|
84
|
-
} else if (itemDef.default !== undefined) {
|
|
85
|
-
resolvedValue = itemDef.default;
|
|
86
|
-
source = "default";
|
|
87
|
-
status = "DEFAULT";
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const displayValue = isSecret && resolvedValue !== undefined ? maskSecretValue(resolvedValue) : resolvedValue;
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
key,
|
|
94
|
-
value: displayValue,
|
|
95
|
-
status,
|
|
96
|
-
source,
|
|
97
|
-
secret: isSecret,
|
|
98
|
-
description: itemDef.description || "",
|
|
99
|
-
required: itemDef.default === undefined,
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const missingRequired = items.filter((i) => i.status === "MISSING");
|
|
104
|
-
const payload = {
|
|
105
|
-
packageId: projConfig.id,
|
|
106
|
-
projectRoot: root,
|
|
107
|
-
allReady: missingRequired.length === 0,
|
|
108
|
-
configs: items,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
if (options.json || options.envelope) {
|
|
112
|
-
renderResult(payload, { json: options.json, envelope: options.envelope });
|
|
113
|
-
} else {
|
|
114
|
-
console.log(`Configuration Requirements for ${projConfig.id} (${root}):\n`);
|
|
115
|
-
if (items.length === 0) {
|
|
116
|
-
console.log(" (No configuration dependencies declared for this package)");
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.log(
|
|
121
|
-
` ${"KEY".padEnd(24)} ${"STATUS".padEnd(12)} ${"SOURCE".padEnd(10)} ${"SECRET".padEnd(8)} DESCRIPTION`
|
|
122
|
-
);
|
|
123
|
-
console.log(" " + "-".repeat(85));
|
|
124
|
-
|
|
125
|
-
for (const item of items) {
|
|
126
|
-
const statusLabel = item.status === "SET" ? "[SET]" : item.status === "DEFAULT" ? "[DEFAULT]" : "[MISSING]";
|
|
127
|
-
const secretLabel = item.secret ? "yes" : "no";
|
|
128
|
-
console.log(
|
|
129
|
-
` ${item.key.padEnd(24)} ${statusLabel.padEnd(12)} ${item.source.padEnd(10)} ${secretLabel.padEnd(8)} ${item.description}`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (missingRequired.length > 0) {
|
|
134
|
-
console.log(`\n[WARNING] ${missingRequired.length} required config(s) not set:`);
|
|
135
|
-
for (const m of missingRequired) {
|
|
136
|
-
console.log(` - ${m.key}: Run 'ad config set ${m.key} <value>' to configure.`);
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
console.log("\n[OK] All configuration dependencies are satisfied.");
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
} catch (err: any) {
|
|
143
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
144
|
-
throw err;
|
|
145
|
-
}
|
|
146
|
-
throw new ExecutionError(err.message);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// config list
|
|
151
|
-
configCmd
|
|
152
|
-
.command("list [patterns...]")
|
|
153
|
-
.description("List configuration entries (Global & Project)")
|
|
154
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
155
|
-
.option("-g, --global", "Show only global configurations")
|
|
156
|
-
.option("-p, --profile <name>", "Query config on a remote target")
|
|
157
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
158
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
159
|
-
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
160
|
-
.option("--reveal, --show-secrets", "Reveal plain text values for secrets")
|
|
161
|
-
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
162
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
163
|
-
.option("--json", "Output as JSON")
|
|
164
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
165
|
-
.action(async (patterns, rawOptions, cmd) => {
|
|
166
|
-
try {
|
|
167
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
168
|
-
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
169
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
170
|
-
const fallbackExplicit = options.fallback === true || (Array.isArray(process.argv) && process.argv.includes("--fallback"));
|
|
171
|
-
const shouldFallback = isMachine ? fallbackExplicit : options.fallback !== false;
|
|
172
|
-
const reveal = options.reveal || options.showSecrets;
|
|
173
|
-
|
|
174
|
-
const target = resolveTarget({
|
|
175
|
-
profile: options.profile,
|
|
176
|
-
server: options.server,
|
|
177
|
-
token: options.token,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
if (target.type === "remote") {
|
|
181
|
-
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
182
|
-
if (isMachine) {
|
|
183
|
-
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
console.log(
|
|
187
|
-
`Config on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""}:\n`
|
|
188
|
-
);
|
|
189
|
-
const entries = Object.entries(res.values || {});
|
|
190
|
-
if (entries.length === 0) {
|
|
191
|
-
console.log(" (No config entries stored)");
|
|
192
|
-
} else {
|
|
193
|
-
for (const [k, v] of entries) {
|
|
194
|
-
console.log(` ${k.padEnd(24)} = ${JSON.stringify(v)}`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (options.package && !options.global) {
|
|
201
|
-
const directRoot = resolvePackageRoot(options.package);
|
|
202
|
-
if (!directRoot) {
|
|
203
|
-
throw new ArgumentError(
|
|
204
|
-
`Package '${options.package}' not found in linked packages or path`
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const globalStorage = createGlobalStorage(options.dataDir);
|
|
210
|
-
const globalConfig = globalStorage.listConfig();
|
|
211
|
-
|
|
212
|
-
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
213
|
-
let projectStored: Record<string, unknown> = {};
|
|
214
|
-
let declaredDefaults: Record<string, ConfigItemDefinition> = {};
|
|
215
|
-
let packageId = "global";
|
|
216
|
-
|
|
217
|
-
if (projectRoot) {
|
|
218
|
-
try {
|
|
219
|
-
const projConfig = loadProjectConfig(projectRoot);
|
|
220
|
-
packageId = projConfig.id;
|
|
221
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
222
|
-
projectRoot,
|
|
223
|
-
dataDir: options.dataDir,
|
|
224
|
-
});
|
|
225
|
-
projectStored = projectStorage.listConfig();
|
|
226
|
-
declaredDefaults = projConfig.config || {};
|
|
227
|
-
projectStorage.close();
|
|
228
|
-
} catch {
|
|
229
|
-
// Ignore project load error
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
globalStorage.close();
|
|
234
|
-
|
|
235
|
-
const allKeys = new Set([
|
|
236
|
-
...Object.keys(declaredDefaults),
|
|
237
|
-
...Object.keys(globalConfig),
|
|
238
|
-
...Object.keys(projectStored),
|
|
239
|
-
]);
|
|
240
|
-
|
|
241
|
-
const rawList = Array.from(allKeys).map((k) => {
|
|
242
|
-
let rawValue: unknown;
|
|
243
|
-
let source: "project" | "global" | "env" | "default" = "default";
|
|
244
|
-
|
|
245
|
-
if (projectStored[k] !== undefined) {
|
|
246
|
-
rawValue = projectStored[k];
|
|
247
|
-
source = "project";
|
|
248
|
-
} else if (globalConfig[k] !== undefined) {
|
|
249
|
-
rawValue = globalConfig[k];
|
|
250
|
-
source = "global";
|
|
251
|
-
} else if (typeof process !== "undefined" && process.env && process.env[k] !== undefined) {
|
|
252
|
-
rawValue = process.env[k];
|
|
253
|
-
source = "env";
|
|
254
|
-
} else {
|
|
255
|
-
rawValue = declaredDefaults[k]?.default;
|
|
256
|
-
source = "default";
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const isSecret = isSecretConfigKey(k, declaredDefaults[k]);
|
|
260
|
-
const displayValue = !reveal && isSecret && rawValue !== undefined ? maskSecretValue(rawValue) : rawValue;
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
key: k,
|
|
264
|
-
value: displayValue,
|
|
265
|
-
source,
|
|
266
|
-
secret: isSecret,
|
|
267
|
-
description: declaredDefaults[k]?.description || "",
|
|
268
|
-
};
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
const filterRes = filterWithFallbackInfo(
|
|
272
|
-
rawList,
|
|
273
|
-
effectiveIntent,
|
|
274
|
-
[(c) => c.key, (c) => c.value, (c) => c.description, (c) => c.source],
|
|
275
|
-
shouldFallback
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
if (isMachine) {
|
|
279
|
-
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
280
|
-
} else {
|
|
281
|
-
const scopeLabel = projectRoot ? `${packageId} (${projectRoot})` : "Global Scope";
|
|
282
|
-
console.log(`Configurations [${scopeLabel}]:\n`);
|
|
283
|
-
if (filterRes.isFallback && effectiveIntent) {
|
|
284
|
-
console.log(`(No config entries matched intent '${effectiveIntent}', showing all entries)\n`);
|
|
285
|
-
}
|
|
286
|
-
if (filterRes.items.length === 0) {
|
|
287
|
-
console.log(" (No configuration entries found)");
|
|
288
|
-
}
|
|
289
|
-
for (const item of filterRes.items) {
|
|
290
|
-
const valStr = typeof item.value === "string" && item.secret && !reveal ? item.value : JSON.stringify(item.value);
|
|
291
|
-
const secretBadge = item.secret ? ", secret" : "";
|
|
292
|
-
console.log(` ${item.key.padEnd(24)} = ${valStr} (${item.source}${secretBadge})`);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
} catch (err: any) {
|
|
296
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
297
|
-
throw err;
|
|
298
|
-
}
|
|
299
|
-
throw new ExecutionError(err.message);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
// config get
|
|
304
|
-
configCmd
|
|
305
|
-
.command("get <key>")
|
|
306
|
-
.description("Get a configuration value")
|
|
307
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
308
|
-
.option("-g, --global", "Get from global configuration only")
|
|
309
|
-
.option("-p, --profile <name>", "Query config on a remote target")
|
|
310
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
311
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
312
|
-
.option("--reveal, --show-secrets", "Reveal plain text value for secret")
|
|
313
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
314
|
-
.option("--json", "Output as JSON")
|
|
315
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
316
|
-
.action(async (key, rawOptions, cmd) => {
|
|
317
|
-
try {
|
|
318
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
319
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
320
|
-
const target = resolveTarget({
|
|
321
|
-
profile: options.profile,
|
|
322
|
-
server: options.server,
|
|
323
|
-
token: options.token,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
if (target.type === "remote") {
|
|
327
|
-
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
328
|
-
const val = res.values?.[key];
|
|
329
|
-
if (isMachine) {
|
|
330
|
-
renderResult({ key, value: val }, { json: options.json, envelope: options.envelope });
|
|
331
|
-
} else {
|
|
332
|
-
console.log(val !== undefined ? JSON.stringify(val) : "undefined");
|
|
333
|
-
}
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (options.package && !options.global) {
|
|
338
|
-
const directRoot = resolvePackageRoot(options.package);
|
|
339
|
-
if (!directRoot) {
|
|
340
|
-
throw new ArgumentError(
|
|
341
|
-
`Package '${options.package}' not found in linked packages or path`
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const reveal = options.reveal || options.showSecrets;
|
|
347
|
-
const globalStorage = createGlobalStorage(options.dataDir);
|
|
348
|
-
const globalVal = globalStorage.getConfig(key);
|
|
349
|
-
globalStorage.close();
|
|
350
|
-
|
|
351
|
-
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
352
|
-
let projVal: unknown = undefined;
|
|
353
|
-
let fallbackVal: unknown = undefined;
|
|
354
|
-
let declaredItem: ConfigItemDefinition | undefined;
|
|
355
|
-
|
|
356
|
-
if (projectRoot) {
|
|
357
|
-
try {
|
|
358
|
-
const projConfig = loadProjectConfig(projectRoot);
|
|
359
|
-
declaredItem = projConfig.config?.[key];
|
|
360
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
361
|
-
projectRoot,
|
|
362
|
-
dataDir: options.dataDir,
|
|
363
|
-
});
|
|
364
|
-
projVal = projectStorage.getConfig(key);
|
|
365
|
-
fallbackVal = projConfig.config?.[key]?.default;
|
|
366
|
-
projectStorage.close();
|
|
367
|
-
} catch {
|
|
368
|
-
// Ignore
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const envVal = typeof process !== "undefined" && process.env ? process.env[key] : undefined;
|
|
373
|
-
|
|
374
|
-
const rawEffective =
|
|
375
|
-
projVal !== undefined
|
|
376
|
-
? projVal
|
|
377
|
-
: globalVal !== undefined
|
|
378
|
-
? globalVal
|
|
379
|
-
: envVal !== undefined
|
|
380
|
-
? envVal
|
|
381
|
-
: fallbackVal;
|
|
382
|
-
|
|
383
|
-
const source: string =
|
|
384
|
-
projVal !== undefined
|
|
385
|
-
? "project"
|
|
386
|
-
: globalVal !== undefined
|
|
387
|
-
? "global"
|
|
388
|
-
: envVal !== undefined
|
|
389
|
-
? "env"
|
|
390
|
-
: fallbackVal !== undefined
|
|
391
|
-
? "default"
|
|
392
|
-
: "undefined";
|
|
393
|
-
|
|
394
|
-
const isSecret = isSecretConfigKey(key, declaredItem);
|
|
395
|
-
const effective = !reveal && isSecret && rawEffective !== undefined ? maskSecretValue(rawEffective) : rawEffective;
|
|
396
|
-
|
|
397
|
-
if (isMachine) {
|
|
398
|
-
renderResult(
|
|
399
|
-
{
|
|
400
|
-
key,
|
|
401
|
-
value: effective,
|
|
402
|
-
source,
|
|
403
|
-
secret: isSecret,
|
|
404
|
-
},
|
|
405
|
-
{ json: options.json, envelope: options.envelope }
|
|
406
|
-
);
|
|
407
|
-
} else {
|
|
408
|
-
console.log(effective !== undefined ? (typeof effective === "string" && isSecret && !reveal ? effective : JSON.stringify(effective)) : "undefined");
|
|
409
|
-
}
|
|
410
|
-
} catch (err: any) {
|
|
411
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
412
|
-
throw err;
|
|
413
|
-
}
|
|
414
|
-
throw new ExecutionError(err.message);
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// config set
|
|
419
|
-
configCmd
|
|
420
|
-
.command("set <key> <value>")
|
|
421
|
-
.description("Set a configuration value (Global by default outside project, or use -g for global)")
|
|
422
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
423
|
-
.option("-g, --global", "Set globally across all packages")
|
|
424
|
-
.option("-p, --profile <name>", "Set config on a remote target")
|
|
425
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
426
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
427
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
428
|
-
.option("--json", "Output as JSON")
|
|
429
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
430
|
-
.action(async (key, rawValue, rawOptions, cmd) => {
|
|
431
|
-
try {
|
|
432
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
433
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
434
|
-
let parsed: unknown = rawValue;
|
|
435
|
-
try {
|
|
436
|
-
parsed = JSON.parse(rawValue);
|
|
437
|
-
} catch {
|
|
438
|
-
parsed = rawValue;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const target = resolveTarget({
|
|
442
|
-
profile: options.profile,
|
|
443
|
-
server: options.server,
|
|
444
|
-
token: options.token,
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
if (target.type === "remote") {
|
|
448
|
-
await setRemoteConfig(target.serverUrl!, key, parsed, target.token, options.package);
|
|
449
|
-
if (isMachine) {
|
|
450
|
-
renderResult({ ok: true, key, value: parsed }, { json: options.json, envelope: options.envelope });
|
|
451
|
-
} else {
|
|
452
|
-
console.log(`[OK] Remote config '${key}' updated on ${target.serverUrl}`);
|
|
453
|
-
}
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (options.package && !options.global) {
|
|
458
|
-
const directRoot = resolvePackageRoot(options.package);
|
|
459
|
-
if (!directRoot) {
|
|
460
|
-
throw new ArgumentError(
|
|
461
|
-
`Package '${options.package}' not found in linked packages or path`
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
467
|
-
const isSecret = isSecretConfigKey(key);
|
|
468
|
-
const displayVal = isSecret ? maskSecretValue(parsed) : JSON.stringify(parsed);
|
|
469
|
-
|
|
470
|
-
if (options.global || !projectRoot) {
|
|
471
|
-
// Set in Global storage
|
|
472
|
-
const globalStorage = createGlobalStorage(options.dataDir);
|
|
473
|
-
globalStorage.setConfig(key, parsed);
|
|
474
|
-
globalStorage.close();
|
|
475
|
-
if (isMachine) {
|
|
476
|
-
renderResult({ ok: true, key, value: parsed, scope: "global" }, { json: options.json, envelope: options.envelope });
|
|
477
|
-
} else {
|
|
478
|
-
console.log(`[OK] Global config '${key}' set to ${displayVal}`);
|
|
479
|
-
}
|
|
480
|
-
} else {
|
|
481
|
-
// Set in Project storage
|
|
482
|
-
const projConfig = loadProjectConfig(projectRoot);
|
|
483
|
-
const storage = createStorage(projConfig.id, {
|
|
484
|
-
projectRoot,
|
|
485
|
-
dataDir: options.dataDir,
|
|
486
|
-
});
|
|
487
|
-
storage.setConfig(key, parsed);
|
|
488
|
-
storage.close();
|
|
489
|
-
if (isMachine) {
|
|
490
|
-
renderResult({ ok: true, key, value: parsed, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
491
|
-
} else {
|
|
492
|
-
console.log(`[OK] Config '${key}' set to ${displayVal} in ${projConfig.id}`);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
} catch (err: any) {
|
|
496
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
497
|
-
throw err;
|
|
498
|
-
}
|
|
499
|
-
throw new ExecutionError(err.message);
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// config delete
|
|
504
|
-
configCmd
|
|
505
|
-
.command("delete <key>")
|
|
506
|
-
.alias("rm")
|
|
507
|
-
.description("Delete a configuration value")
|
|
508
|
-
.option("-P, --package <id>", "Target package ID or path")
|
|
509
|
-
.option("-g, --global", "Delete from global configuration")
|
|
510
|
-
.option("-p, --profile <name>", "Delete config on a remote target")
|
|
511
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
512
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
513
|
-
.option("--data-dir <path>", "Custom database storage directory")
|
|
514
|
-
.option("--json", "Output as JSON")
|
|
515
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
516
|
-
.action(async (key, rawOptions, cmd) => {
|
|
517
|
-
try {
|
|
518
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
519
|
-
const isMachine = Boolean(options.json || options.envelope);
|
|
520
|
-
const target = resolveTarget({
|
|
521
|
-
profile: options.profile,
|
|
522
|
-
server: options.server,
|
|
523
|
-
token: options.token,
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
if (target.type === "remote") {
|
|
527
|
-
const res = await deleteRemoteConfig(target.serverUrl!, key, target.token, options.package);
|
|
528
|
-
if (isMachine) {
|
|
529
|
-
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
530
|
-
} else if (res.deleted) {
|
|
531
|
-
console.log(`[OK] Remote config '${key}' deleted from ${target.serverUrl}`);
|
|
532
|
-
} else {
|
|
533
|
-
console.log(`Remote config '${key}' not found on ${target.serverUrl}`);
|
|
534
|
-
}
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (options.package && !options.global) {
|
|
539
|
-
const directRoot = resolvePackageRoot(options.package);
|
|
540
|
-
if (!directRoot) {
|
|
541
|
-
throw new ArgumentError(
|
|
542
|
-
`Package '${options.package}' not found in linked packages or path`
|
|
543
|
-
);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
548
|
-
|
|
549
|
-
if (options.global || !projectRoot) {
|
|
550
|
-
const globalStorage = createGlobalStorage(options.dataDir);
|
|
551
|
-
const deleted = globalStorage.deleteConfig(key);
|
|
552
|
-
globalStorage.close();
|
|
553
|
-
if (isMachine) {
|
|
554
|
-
renderResult({ ok: true, key, deleted, scope: "global" }, { json: options.json, envelope: options.envelope });
|
|
555
|
-
} else if (deleted) {
|
|
556
|
-
console.log(`[OK] Global config '${key}' deleted`);
|
|
557
|
-
} else {
|
|
558
|
-
console.log(`Global config '${key}' was not found`);
|
|
559
|
-
}
|
|
560
|
-
} else {
|
|
561
|
-
const projConfig = loadProjectConfig(projectRoot);
|
|
562
|
-
const storage = createStorage(projConfig.id, {
|
|
563
|
-
projectRoot,
|
|
564
|
-
dataDir: options.dataDir,
|
|
565
|
-
});
|
|
566
|
-
const deleted = storage.deleteConfig(key);
|
|
567
|
-
storage.close();
|
|
568
|
-
if (isMachine) {
|
|
569
|
-
renderResult({ ok: true, key, deleted, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
570
|
-
} else if (deleted) {
|
|
571
|
-
console.log(`[OK] Config '${key}' deleted from ${projConfig.id}`);
|
|
572
|
-
} else {
|
|
573
|
-
console.log(`Config '${key}' was not set in database for ${projConfig.id}`);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
} catch (err: any) {
|
|
577
|
-
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
578
|
-
throw err;
|
|
579
|
-
}
|
|
580
|
-
throw new ExecutionError(err.message);
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
}
|
package/src/commands/doctor.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { fetchRemoteDoctor, resolveTarget, runDoctorChecks } from "@actiondock/core";
|
|
2
|
-
import { ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
3
|
-
import { Command } from "commander";
|
|
4
|
-
|
|
5
|
-
export function registerDoctorCommand(program: Command): void {
|
|
6
|
-
program
|
|
7
|
-
.command("doctor")
|
|
8
|
-
.description("Check ActionDock environment, registry health, and project diagnostics")
|
|
9
|
-
.option("-P, --package <id|path>", "Target package ID or directory path for project diagnostics")
|
|
10
|
-
.option("-p, --profile <name>", "Query doctor diagnostics on a remote target")
|
|
11
|
-
.option("-s, --server <url>", "Remote server URL")
|
|
12
|
-
.option("-t, --token <token>", "Auth token for remote server")
|
|
13
|
-
.option("--json", "Output diagnostics report in JSON format")
|
|
14
|
-
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
15
|
-
.action(async (rawOptions, cmd) => {
|
|
16
|
-
try {
|
|
17
|
-
const options = getEffectiveOptions(rawOptions, cmd);
|
|
18
|
-
const target = resolveTarget({
|
|
19
|
-
profile: options.profile,
|
|
20
|
-
server: options.server,
|
|
21
|
-
token: options.token,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
let report;
|
|
25
|
-
if (target.type === "remote") {
|
|
26
|
-
const remoteRes = await fetchRemoteDoctor(target.serverUrl!, target.token, options.package);
|
|
27
|
-
report = remoteRes.report || remoteRes;
|
|
28
|
-
} else {
|
|
29
|
-
report = await runDoctorChecks({
|
|
30
|
-
packageIdOrPath: options.package,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
renderResult(report, {
|
|
35
|
-
json: options.json,
|
|
36
|
-
envelope: options.envelope,
|
|
37
|
-
humanFormatter: () => {
|
|
38
|
-
const lines: string[] = [];
|
|
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
|
-
lines.push(title);
|
|
43
|
-
|
|
44
|
-
// 1. Runtime & Environment Group
|
|
45
|
-
lines.push("[Runtime & Environment]");
|
|
46
|
-
const envChecks = (report.checks || []).filter((c: any) => c.category === "runtime" || c.category === "storage" || c.category === "registry");
|
|
47
|
-
for (const c of envChecks) {
|
|
48
|
-
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
49
|
-
lines.push(` ${tag} ${c.name}: ${c.message}`);
|
|
50
|
-
if (c.fix) {
|
|
51
|
-
lines.push(` Fix: ${c.fix}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. Project Group
|
|
56
|
-
if (report.hasProject) {
|
|
57
|
-
lines.push(`\n[Project: ${report.packageId || "unknown"}] (${report.projectRoot})`);
|
|
58
|
-
const projChecks = (report.checks || []).filter((c: any) => c.category === "project");
|
|
59
|
-
for (const c of projChecks) {
|
|
60
|
-
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
61
|
-
lines.push(` ${tag} ${c.name}: ${c.message}`);
|
|
62
|
-
if (c.fix) {
|
|
63
|
-
lines.push(` Fix: ${c.fix}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
lines.push("\n[Project Context]");
|
|
68
|
-
lines.push(" [INFO] Not inside an ActionDock project directory (skipped project checks)");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 3. Summary
|
|
72
|
-
lines.push(`\n[Summary] ${report.summary.ok} passed, ${report.summary.warn} warning(s), ${report.summary.error} error(s)`);
|
|
73
|
-
return lines.join("\n");
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (!report.ok) {
|
|
78
|
-
process.exitCode = 1;
|
|
79
|
-
}
|
|
80
|
-
} catch (err: any) {
|
|
81
|
-
throw new ExecutionError(`Doctor failed to run diagnostics: ${err.message}`);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|