@amaster.ai/runtime-cli 1.1.7 → 1.1.9
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 +337 -126
- package/dist/cli.cjs +959 -255
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +961 -257
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +959 -255
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +961 -257
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2,20 +2,14 @@
|
|
|
2
2
|
import { existsSync, rmSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { join, resolve } from 'path';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
|
-
import { Command } from 'commander';
|
|
5
|
+
import { Command, Option } from 'commander';
|
|
6
6
|
import chalk7 from 'chalk';
|
|
7
7
|
import { createClient } from '@amaster.ai/client';
|
|
8
|
-
import
|
|
8
|
+
import ora from 'ora';
|
|
9
9
|
import yaml from 'yaml';
|
|
10
10
|
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
12
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
14
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
15
|
-
}) : x)(function(x) {
|
|
16
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
|
-
});
|
|
19
13
|
var __esm = (fn, res) => function __init() {
|
|
20
14
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
21
15
|
};
|
|
@@ -55,8 +49,7 @@ function getConfig() {
|
|
|
55
49
|
}
|
|
56
50
|
function saveConfig(config) {
|
|
57
51
|
if (!existsSync(AMASTER_CONFIG_DIR)) {
|
|
58
|
-
|
|
59
|
-
fs.mkdirSync(AMASTER_CONFIG_DIR, { recursive: true });
|
|
52
|
+
mkdirSync(AMASTER_CONFIG_DIR, { recursive: true });
|
|
60
53
|
}
|
|
61
54
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
62
55
|
}
|
|
@@ -124,8 +117,7 @@ function getAuthSession(appCode) {
|
|
|
124
117
|
}
|
|
125
118
|
function saveAuthSession(appCode, session) {
|
|
126
119
|
if (!existsSync(AMASTER_CONFIG_DIR)) {
|
|
127
|
-
|
|
128
|
-
fs.mkdirSync(AMASTER_CONFIG_DIR, { recursive: true });
|
|
120
|
+
mkdirSync(AMASTER_CONFIG_DIR, { recursive: true });
|
|
129
121
|
}
|
|
130
122
|
const authFile = join(AMASTER_CONFIG_DIR, `auth-${appCode}.json`);
|
|
131
123
|
writeFileSync(authFile, JSON.stringify(session, null, 2), { mode: 384 });
|
|
@@ -172,8 +164,163 @@ init_config();
|
|
|
172
164
|
|
|
173
165
|
// src/commands/auth.ts
|
|
174
166
|
init_config();
|
|
167
|
+
var OUTPUT_FORMATS = ["json", "pretty", "table", "ndjson", "csv"];
|
|
168
|
+
function createFormatOption(description = "Output format") {
|
|
169
|
+
return new Option(
|
|
170
|
+
"--format <format>",
|
|
171
|
+
`${description}: ${OUTPUT_FORMATS.join(", ")}`
|
|
172
|
+
).choices([...OUTPUT_FORMATS]).default("json");
|
|
173
|
+
}
|
|
174
|
+
function resolveOutputFormat(format) {
|
|
175
|
+
if (!format) {
|
|
176
|
+
return "json";
|
|
177
|
+
}
|
|
178
|
+
if (OUTPUT_FORMATS.includes(format)) {
|
|
179
|
+
return format;
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Unsupported output format: ${format}`);
|
|
182
|
+
}
|
|
183
|
+
function isPrettyOutput(format) {
|
|
184
|
+
return resolveOutputFormat(format) === "pretty";
|
|
185
|
+
}
|
|
186
|
+
function createSpinner(text, format) {
|
|
187
|
+
return ora({
|
|
188
|
+
text,
|
|
189
|
+
isSilent: !isPrettyOutput(format)
|
|
190
|
+
}).start();
|
|
191
|
+
}
|
|
192
|
+
function renderOutput(data, options = {}) {
|
|
193
|
+
const format = resolveOutputFormat(options.format);
|
|
194
|
+
switch (format) {
|
|
195
|
+
case "pretty":
|
|
196
|
+
if (options.pretty) {
|
|
197
|
+
options.pretty();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
renderPrettyFallback(data);
|
|
201
|
+
return;
|
|
202
|
+
case "json":
|
|
203
|
+
console.log(JSON.stringify(data ?? null, null, 2));
|
|
204
|
+
return;
|
|
205
|
+
case "ndjson":
|
|
206
|
+
renderNdjson(options.ndjsonItems ?? data);
|
|
207
|
+
return;
|
|
208
|
+
case "table":
|
|
209
|
+
renderTable(options.tableRows ?? inferRows(data));
|
|
210
|
+
return;
|
|
211
|
+
case "csv":
|
|
212
|
+
renderCsv(options.csvRows ?? inferRows(data));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function renderPrettyFallback(data) {
|
|
217
|
+
const rows = inferRows(data);
|
|
218
|
+
if (rows.length === 0) {
|
|
219
|
+
console.log(JSON.stringify(data ?? null, null, 2));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
renderTable(rows);
|
|
223
|
+
}
|
|
224
|
+
function renderNdjson(data) {
|
|
225
|
+
const items = inferNdjsonItems(data);
|
|
226
|
+
for (const item of items) {
|
|
227
|
+
console.log(JSON.stringify(item ?? null));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function renderTable(rows) {
|
|
231
|
+
console.table(rows);
|
|
232
|
+
}
|
|
233
|
+
function renderCsv(rows) {
|
|
234
|
+
if (rows.length === 0) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const headers = [];
|
|
238
|
+
for (const row of rows) {
|
|
239
|
+
for (const key of Object.keys(row)) {
|
|
240
|
+
if (!headers.includes(key)) {
|
|
241
|
+
headers.push(key);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (headers.length === 0) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
console.log(headers.join(","));
|
|
249
|
+
for (const row of rows) {
|
|
250
|
+
console.log(headers.map((header) => escapeCsv(row[header])).join(","));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function inferNdjsonItems(data) {
|
|
254
|
+
const collection = extractCollection(data);
|
|
255
|
+
if (collection) {
|
|
256
|
+
return collection;
|
|
257
|
+
}
|
|
258
|
+
if (Array.isArray(data)) {
|
|
259
|
+
return data;
|
|
260
|
+
}
|
|
261
|
+
return [data ?? null];
|
|
262
|
+
}
|
|
263
|
+
function inferRows(data) {
|
|
264
|
+
const collection = extractCollection(data);
|
|
265
|
+
if (collection) {
|
|
266
|
+
return normalizeRows(collection);
|
|
267
|
+
}
|
|
268
|
+
if (Array.isArray(data)) {
|
|
269
|
+
return normalizeRows(data);
|
|
270
|
+
}
|
|
271
|
+
if (isPlainObject(data)) {
|
|
272
|
+
return [normalizeRow(data)];
|
|
273
|
+
}
|
|
274
|
+
return [{ value: normalizeCell(data) }];
|
|
275
|
+
}
|
|
276
|
+
function extractCollection(data) {
|
|
277
|
+
if (!isPlainObject(data)) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(data.items)) {
|
|
281
|
+
return data.items;
|
|
282
|
+
}
|
|
283
|
+
if (Array.isArray(data.list)) {
|
|
284
|
+
return data.list;
|
|
285
|
+
}
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
function normalizeRows(items) {
|
|
289
|
+
return items.map((item) => {
|
|
290
|
+
if (isPlainObject(item)) {
|
|
291
|
+
return normalizeRow(item);
|
|
292
|
+
}
|
|
293
|
+
return { value: normalizeCell(item) };
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function normalizeRow(row) {
|
|
297
|
+
return Object.fromEntries(
|
|
298
|
+
Object.entries(row).map(([key, value]) => [key, normalizeCell(value)])
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function normalizeCell(value) {
|
|
302
|
+
if (value === null || value === void 0) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
return JSON.stringify(value);
|
|
309
|
+
}
|
|
310
|
+
function escapeCsv(value) {
|
|
311
|
+
const cell = value === null || value === void 0 ? "" : typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
|
|
312
|
+
if (/[",\n]/.test(cell)) {
|
|
313
|
+
return `"${cell.replace(/"/g, '""')}"`;
|
|
314
|
+
}
|
|
315
|
+
return cell;
|
|
316
|
+
}
|
|
317
|
+
function isPlainObject(value) {
|
|
318
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/commands/auth.ts
|
|
175
322
|
async function login(appCode, options) {
|
|
176
|
-
const spinner =
|
|
323
|
+
const spinner = createSpinner(`Logging in to ${appCode}...`, options.format);
|
|
177
324
|
try {
|
|
178
325
|
const appConfig = getAppConfig(appCode);
|
|
179
326
|
if (!appConfig) {
|
|
@@ -183,16 +330,16 @@ async function login(appCode, options) {
|
|
|
183
330
|
console.log(chalk7.yellow(`Initialize it first: amaster init --app-code ${appCode} --url <url>`));
|
|
184
331
|
process.exit(1);
|
|
185
332
|
}
|
|
333
|
+
let username = options.username;
|
|
186
334
|
let email = options.email;
|
|
187
335
|
let password = options.password;
|
|
188
|
-
if (!
|
|
336
|
+
if (!username && !email) {
|
|
189
337
|
const { default: inquirer } = await import('inquirer');
|
|
190
338
|
const answers = await inquirer.prompt([
|
|
191
339
|
{
|
|
192
340
|
type: "input",
|
|
193
|
-
name: "
|
|
194
|
-
message: "Email:"
|
|
195
|
-
when: !email
|
|
341
|
+
name: "login",
|
|
342
|
+
message: "Username or Email:"
|
|
196
343
|
},
|
|
197
344
|
{
|
|
198
345
|
type: "password",
|
|
@@ -201,11 +348,32 @@ async function login(appCode, options) {
|
|
|
201
348
|
when: !password
|
|
202
349
|
}
|
|
203
350
|
]);
|
|
204
|
-
|
|
351
|
+
const login2 = answers.login;
|
|
352
|
+
if (login2.includes("@")) {
|
|
353
|
+
email = login2;
|
|
354
|
+
} else {
|
|
355
|
+
username = login2;
|
|
356
|
+
}
|
|
205
357
|
password = password || answers.password;
|
|
358
|
+
} else if (!password) {
|
|
359
|
+
const { default: inquirer } = await import('inquirer');
|
|
360
|
+
const answers = await inquirer.prompt([
|
|
361
|
+
{
|
|
362
|
+
type: "password",
|
|
363
|
+
name: "password",
|
|
364
|
+
message: "Password:"
|
|
365
|
+
}
|
|
366
|
+
]);
|
|
367
|
+
password = answers.password;
|
|
206
368
|
}
|
|
207
369
|
const client = createClient({ baseURL: appConfig.baseURL });
|
|
208
|
-
const
|
|
370
|
+
const loginParams = { password };
|
|
371
|
+
if (email) {
|
|
372
|
+
loginParams.email = email;
|
|
373
|
+
} else if (username) {
|
|
374
|
+
loginParams.username = username;
|
|
375
|
+
}
|
|
376
|
+
const result = await client.auth.login(loginParams);
|
|
209
377
|
if (result.error) {
|
|
210
378
|
spinner.fail("Login failed");
|
|
211
379
|
console.error(chalk7.red(result.error.message));
|
|
@@ -216,29 +384,53 @@ async function login(appCode, options) {
|
|
|
216
384
|
spinner.fail("Login failed: No access token received");
|
|
217
385
|
process.exit(1);
|
|
218
386
|
}
|
|
387
|
+
const loggedInAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
388
|
+
const expiresAt = loginData.expiresIn ? new Date(Date.now() + loginData.expiresIn * 1e3).toISOString() : void 0;
|
|
389
|
+
const sessionUser = loginData.user ? {
|
|
390
|
+
uid: loginData.user.uid,
|
|
391
|
+
email: loginData.user.email || "",
|
|
392
|
+
name: loginData.user.displayName || loginData.user.username || void 0
|
|
393
|
+
} : void 0;
|
|
219
394
|
saveAuthSession(appCode, {
|
|
220
395
|
accessToken: loginData.accessToken,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
loggedInAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
396
|
+
expiresAt,
|
|
397
|
+
user: sessionUser,
|
|
398
|
+
loggedInAt
|
|
225
399
|
});
|
|
226
400
|
spinner.succeed(`Login successful: ${appCode}`);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
401
|
+
renderOutput(
|
|
402
|
+
{
|
|
403
|
+
appCode,
|
|
404
|
+
baseURL: appConfig.baseURL,
|
|
405
|
+
user: loginData.user ?? null,
|
|
406
|
+
expiresAt: expiresAt ?? null,
|
|
407
|
+
loggedInAt
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
format: options.format,
|
|
411
|
+
pretty: () => {
|
|
412
|
+
console.log(
|
|
413
|
+
chalk7.green(
|
|
414
|
+
`
|
|
415
|
+
Welcome, ${loginData.user?.displayName || loginData.user?.email || loginData.user?.username || email}!`
|
|
416
|
+
)
|
|
417
|
+
);
|
|
418
|
+
console.log(chalk7.gray(`App: ${appCode}`));
|
|
419
|
+
console.log(chalk7.gray(`URL: ${appConfig.baseURL}`));
|
|
420
|
+
if (expiresAt) {
|
|
421
|
+
const expires = new Date(expiresAt);
|
|
422
|
+
console.log(chalk7.gray(`Session expires: ${expires.toLocaleString()}`));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
);
|
|
235
427
|
} catch (error) {
|
|
236
428
|
spinner.fail("Login failed");
|
|
237
429
|
throw error;
|
|
238
430
|
}
|
|
239
431
|
}
|
|
240
|
-
async function logout(appCode) {
|
|
241
|
-
const spinner =
|
|
432
|
+
async function logout(appCode, options = {}) {
|
|
433
|
+
const spinner = createSpinner(`Logging out from ${appCode}...`, options.format);
|
|
242
434
|
try {
|
|
243
435
|
const appConfig = getAppConfig(appCode);
|
|
244
436
|
if (appConfig) {
|
|
@@ -255,13 +447,25 @@ async function logout(appCode) {
|
|
|
255
447
|
}
|
|
256
448
|
clearAuthSession(appCode);
|
|
257
449
|
spinner.succeed(`Logout successful: ${appCode}`);
|
|
450
|
+
renderOutput(
|
|
451
|
+
{
|
|
452
|
+
appCode,
|
|
453
|
+
loggedOut: true
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
format: options.format,
|
|
457
|
+
pretty: () => {
|
|
458
|
+
console.log(chalk7.green(`Logged out from ${appCode}`));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
);
|
|
258
462
|
} catch (error) {
|
|
259
463
|
spinner.fail("Logout failed");
|
|
260
464
|
throw error;
|
|
261
465
|
}
|
|
262
466
|
}
|
|
263
|
-
async function getMe(getClient) {
|
|
264
|
-
const spinner =
|
|
467
|
+
async function getMe(getClient, options = {}) {
|
|
468
|
+
const spinner = createSpinner("Fetching user info...", options.format);
|
|
265
469
|
try {
|
|
266
470
|
const client = getClient();
|
|
267
471
|
const result = await client.auth.getMe();
|
|
@@ -272,160 +476,462 @@ async function getMe(getClient) {
|
|
|
272
476
|
}
|
|
273
477
|
spinner.succeed("User info retrieved");
|
|
274
478
|
const user = result.data;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
479
|
+
renderOutput(user, {
|
|
480
|
+
format: options.format,
|
|
481
|
+
pretty: () => {
|
|
482
|
+
console.log(chalk7.blue("\n\u{1F464} User Profile\n"));
|
|
483
|
+
console.log(` ${chalk7.bold("UID:")} ${user?.uid}`);
|
|
484
|
+
console.log(` ${chalk7.bold("Email:")} ${user?.email}`);
|
|
485
|
+
console.log(` ${chalk7.bold("Name:")} ${user?.displayName || user?.username || "N/A"}`);
|
|
486
|
+
console.log(` ${chalk7.bold("Status:")} ${user?.isActive ? "Active" : "Inactive"}`);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
280
489
|
} catch (error) {
|
|
281
490
|
spinner.fail("Failed to fetch user info");
|
|
282
491
|
throw error;
|
|
283
492
|
}
|
|
284
493
|
}
|
|
494
|
+
function isPlainObject2(value) {
|
|
495
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
496
|
+
}
|
|
497
|
+
function resolveInputSource(input) {
|
|
498
|
+
if (!input.startsWith("@")) {
|
|
499
|
+
return input;
|
|
500
|
+
}
|
|
501
|
+
const filePath = input.slice(1);
|
|
502
|
+
if (!filePath) {
|
|
503
|
+
throw new Error("File path is required after '@'.");
|
|
504
|
+
}
|
|
505
|
+
return readFileSync(filePath, "utf8");
|
|
506
|
+
}
|
|
507
|
+
function parseJsonInput(input, label) {
|
|
508
|
+
const source = resolveInputSource(input).trim();
|
|
509
|
+
if (!source) {
|
|
510
|
+
throw new Error(`${label} is required.`);
|
|
511
|
+
}
|
|
512
|
+
try {
|
|
513
|
+
return JSON.parse(source);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
516
|
+
throw new Error(`Invalid ${label}: ${reason}`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
async function promptForJson(message, defaultValue) {
|
|
520
|
+
const { default: inquirer } = await import('inquirer');
|
|
521
|
+
const { jsonData } = await inquirer.prompt([
|
|
522
|
+
{
|
|
523
|
+
type: "editor",
|
|
524
|
+
name: "jsonData",
|
|
525
|
+
message,
|
|
526
|
+
default: defaultValue
|
|
527
|
+
}
|
|
528
|
+
]);
|
|
529
|
+
return jsonData;
|
|
530
|
+
}
|
|
531
|
+
async function loadJsonObjectInput(input, label, promptMessage) {
|
|
532
|
+
const source = input ?? await promptForJson(promptMessage, "{}");
|
|
533
|
+
const value = parseJsonInput(source, label);
|
|
534
|
+
if (!isPlainObject2(value)) {
|
|
535
|
+
throw new Error(`${label} must be a JSON object.`);
|
|
536
|
+
}
|
|
537
|
+
return value;
|
|
538
|
+
}
|
|
539
|
+
async function loadJsonArrayInput(input, label, promptMessage) {
|
|
540
|
+
const source = input ?? await promptForJson(promptMessage, "[]");
|
|
541
|
+
const value = parseJsonInput(source, label);
|
|
542
|
+
if (!Array.isArray(value)) {
|
|
543
|
+
throw new Error(`${label} must be a JSON array.`);
|
|
544
|
+
}
|
|
545
|
+
return value;
|
|
546
|
+
}
|
|
547
|
+
function loadOptionalJsonObjectInput(input, label) {
|
|
548
|
+
if (!input) {
|
|
549
|
+
return {};
|
|
550
|
+
}
|
|
551
|
+
const value = parseJsonInput(input, label);
|
|
552
|
+
if (!isPlainObject2(value)) {
|
|
553
|
+
throw new Error(`${label} must be a JSON object.`);
|
|
554
|
+
}
|
|
555
|
+
return value;
|
|
556
|
+
}
|
|
557
|
+
function parseCommaSeparatedValues(value) {
|
|
558
|
+
if (!value) {
|
|
559
|
+
return void 0;
|
|
560
|
+
}
|
|
561
|
+
const values = value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
562
|
+
return values.length > 0 ? values : void 0;
|
|
563
|
+
}
|
|
564
|
+
function validateBulkUpdateItems(items) {
|
|
565
|
+
return items.map((item, index) => {
|
|
566
|
+
if (!isPlainObject2(item)) {
|
|
567
|
+
throw new Error(`Bulk update item at index ${index} must be a JSON object.`);
|
|
568
|
+
}
|
|
569
|
+
if (typeof item.id !== "string" && typeof item.id !== "number") {
|
|
570
|
+
throw new Error(`Bulk update item at index ${index} must include an 'id'.`);
|
|
571
|
+
}
|
|
572
|
+
return item;
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
function parseIdsInput(input) {
|
|
576
|
+
const source = resolveInputSource(input).trim();
|
|
577
|
+
if (!source) {
|
|
578
|
+
throw new Error("IDs are required.");
|
|
579
|
+
}
|
|
580
|
+
if (source.startsWith("[")) {
|
|
581
|
+
const value = parseJsonInput(input, "IDs");
|
|
582
|
+
if (!Array.isArray(value)) {
|
|
583
|
+
throw new Error("IDs must be a JSON array.");
|
|
584
|
+
}
|
|
585
|
+
return value.map((id, index) => {
|
|
586
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
587
|
+
throw new Error(`ID at index ${index} must be a string or number.`);
|
|
588
|
+
}
|
|
589
|
+
return id;
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
const ids = source.split(/[,\n]/).map((id) => id.trim()).filter(Boolean);
|
|
593
|
+
if (ids.length === 0) {
|
|
594
|
+
throw new Error("IDs are required.");
|
|
595
|
+
}
|
|
596
|
+
return ids;
|
|
597
|
+
}
|
|
598
|
+
async function loadIdsInput(input) {
|
|
599
|
+
if (input) {
|
|
600
|
+
return parseIdsInput(input);
|
|
601
|
+
}
|
|
602
|
+
const { default: inquirer } = await import('inquirer');
|
|
603
|
+
const { ids } = await inquirer.prompt([
|
|
604
|
+
{
|
|
605
|
+
type: "input",
|
|
606
|
+
name: "ids",
|
|
607
|
+
message: "Enter IDs (comma-separated or JSON array):"
|
|
608
|
+
}
|
|
609
|
+
]);
|
|
610
|
+
return parseIdsInput(ids);
|
|
611
|
+
}
|
|
612
|
+
function exitWithCommandError(spinner, failureMessage, error) {
|
|
613
|
+
spinner.fail(failureMessage);
|
|
614
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
615
|
+
if (details) {
|
|
616
|
+
console.error(chalk7.red(details));
|
|
617
|
+
}
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
function buildListQueryParams(options) {
|
|
621
|
+
const params = loadOptionalJsonObjectInput(options.query, "query params");
|
|
622
|
+
const fields = parseCommaSeparatedValues(options.fields);
|
|
623
|
+
const relations = parseCommaSeparatedValues(options.relations);
|
|
624
|
+
const keywordFields = parseCommaSeparatedValues(options.keywordFields);
|
|
625
|
+
if (keywordFields && !options.keyword) {
|
|
626
|
+
throw new Error("--keyword-fields requires --keyword.");
|
|
627
|
+
}
|
|
628
|
+
if (options.orderDir && !options.orderBy) {
|
|
629
|
+
throw new Error("--order-dir requires --order-by.");
|
|
630
|
+
}
|
|
631
|
+
if (options.orders && (options.orderBy || options.orderDir)) {
|
|
632
|
+
throw new Error("--orders cannot be used together with --order-by or --order-dir.");
|
|
633
|
+
}
|
|
634
|
+
if (fields) {
|
|
635
|
+
params.__fields = fields;
|
|
636
|
+
}
|
|
637
|
+
if (relations) {
|
|
638
|
+
params.__relations = relations;
|
|
639
|
+
}
|
|
640
|
+
if (options.keyword) {
|
|
641
|
+
params.__keywords = keywordFields ? { fields: keywordFields, value: options.keyword } : options.keyword;
|
|
642
|
+
}
|
|
643
|
+
if (options.orderBy) {
|
|
644
|
+
params.orderBy = options.orderBy;
|
|
645
|
+
}
|
|
646
|
+
if (options.orderDir) {
|
|
647
|
+
params.orderDir = options.orderDir;
|
|
648
|
+
}
|
|
649
|
+
if (options.orders) {
|
|
650
|
+
params.__orders = options.orders;
|
|
651
|
+
}
|
|
652
|
+
if (options.filter) {
|
|
653
|
+
params.__filter = loadOptionalJsonObjectInput(options.filter, "filter");
|
|
654
|
+
}
|
|
655
|
+
if (options.limit !== void 0) {
|
|
656
|
+
params.limit = options.limit;
|
|
657
|
+
}
|
|
658
|
+
if (options.offset !== void 0) {
|
|
659
|
+
params.offset = options.offset;
|
|
660
|
+
}
|
|
661
|
+
return params;
|
|
662
|
+
}
|
|
285
663
|
async function listEntities(client, options) {
|
|
286
|
-
const spinner =
|
|
664
|
+
const spinner = createSpinner(`Fetching ${options.entity}...`, options.format);
|
|
287
665
|
try {
|
|
288
|
-
const
|
|
666
|
+
const entityClient = client.entity;
|
|
667
|
+
const query = buildListQueryParams(options);
|
|
668
|
+
const result = await entityClient.list(options.namespace, options.entity, {
|
|
669
|
+
...query,
|
|
289
670
|
page: options.page || 1,
|
|
290
|
-
|
|
671
|
+
perPage: options.pageSize || 10
|
|
291
672
|
});
|
|
292
673
|
if (result.error) {
|
|
293
674
|
spinner.fail("Failed to fetch entities");
|
|
294
675
|
console.error(chalk7.red(result.error.message));
|
|
295
676
|
process.exit(1);
|
|
296
677
|
}
|
|
297
|
-
spinner.
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
678
|
+
spinner.stop();
|
|
679
|
+
const listData = result.data;
|
|
680
|
+
let items = [];
|
|
681
|
+
let total = 0;
|
|
682
|
+
if (Array.isArray(listData)) {
|
|
683
|
+
items = listData;
|
|
684
|
+
total = items.length;
|
|
685
|
+
} else if (listData?.items) {
|
|
686
|
+
items = listData.items;
|
|
687
|
+
total = listData.total || items.length;
|
|
688
|
+
} else if (listData?.list) {
|
|
689
|
+
items = listData.list;
|
|
690
|
+
total = listData.total || items.length;
|
|
691
|
+
}
|
|
692
|
+
renderOutput(result.data, {
|
|
693
|
+
format: options.format,
|
|
694
|
+
pretty: () => {
|
|
695
|
+
console.log(chalk7.blue(`
|
|
696
|
+
\u{1F4E6} ${options.entity} in ${options.namespace}`));
|
|
697
|
+
console.log(chalk7.gray(`\u5171 ${total} \u6761\u8BB0\u5F55:
|
|
301
698
|
`));
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
699
|
+
if (items.length === 0) {
|
|
700
|
+
console.log(chalk7.gray(" \u6682\u65E0\u6570\u636E"));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const firstItem = items[0];
|
|
704
|
+
const keys = Object.keys(firstItem).slice(0, 8);
|
|
705
|
+
const widths = {};
|
|
706
|
+
keys.forEach((key) => {
|
|
707
|
+
const maxValueWidth = Math.max(
|
|
708
|
+
key.length,
|
|
709
|
+
...items.map((item) => {
|
|
710
|
+
const val = item[key];
|
|
711
|
+
if (val === null || val === void 0) return 4;
|
|
712
|
+
const str = typeof val === "object" ? JSON.stringify(val) : String(val);
|
|
713
|
+
return str.length;
|
|
714
|
+
})
|
|
715
|
+
);
|
|
716
|
+
widths[key] = Math.min(maxValueWidth + 2, 30);
|
|
717
|
+
});
|
|
718
|
+
const headerLine = keys.map((key) => {
|
|
719
|
+
const width = widths[key] ?? 0;
|
|
720
|
+
return chalk7.bold(key.slice(0, width).padEnd(width));
|
|
721
|
+
}).join("\u2502");
|
|
722
|
+
console.log(" " + headerLine);
|
|
723
|
+
console.log(" " + keys.map((key) => "\u2500".repeat(widths[key] ?? 0)).join("\u253C"));
|
|
724
|
+
for (const item of items) {
|
|
725
|
+
const rowLine = keys.map((key) => {
|
|
726
|
+
const width = widths[key] ?? 0;
|
|
727
|
+
let val = item[key];
|
|
728
|
+
if (val === null || val === void 0) val = "null";
|
|
729
|
+
const str = typeof val === "object" ? JSON.stringify(val).slice(0, width - 2) : String(val).slice(0, width - 2);
|
|
730
|
+
return str.padEnd(width);
|
|
731
|
+
}).join("\u2502");
|
|
732
|
+
console.log(" " + rowLine);
|
|
733
|
+
}
|
|
734
|
+
console.log();
|
|
735
|
+
if (items.length < total) {
|
|
736
|
+
console.log(chalk7.gray(` ... \u8FD8\u6709 ${total - items.length} \u6761\u8BB0\u5F55`));
|
|
310
737
|
}
|
|
311
738
|
}
|
|
312
|
-
|
|
313
|
-
console.log(` ${chalk7.gray("...")}`);
|
|
314
|
-
}
|
|
315
|
-
console.log();
|
|
316
|
-
}
|
|
317
|
-
if (items.length > 10) {
|
|
318
|
-
console.log(chalk7.gray(` ... and ${items.length - 10} more`));
|
|
319
|
-
}
|
|
739
|
+
});
|
|
320
740
|
} catch (error) {
|
|
321
|
-
spinner
|
|
322
|
-
throw error;
|
|
741
|
+
exitWithCommandError(spinner, "Failed to fetch entities", error);
|
|
323
742
|
}
|
|
324
743
|
}
|
|
325
744
|
async function getEntity(client, options) {
|
|
326
|
-
const spinner =
|
|
745
|
+
const spinner = createSpinner(`Fetching ${options.entity}...`, options.format);
|
|
327
746
|
try {
|
|
328
|
-
const
|
|
747
|
+
const entityClient = client.entity;
|
|
748
|
+
const result = await entityClient.get(options.namespace, options.entity, options.id);
|
|
329
749
|
if (result.error) {
|
|
330
750
|
spinner.fail("Failed to fetch entity");
|
|
331
751
|
console.error(chalk7.red(result.error.message));
|
|
332
752
|
process.exit(1);
|
|
333
753
|
}
|
|
334
754
|
spinner.succeed("Entity retrieved");
|
|
335
|
-
|
|
755
|
+
renderOutput(result.data, {
|
|
756
|
+
format: options.format,
|
|
757
|
+
pretty: () => {
|
|
758
|
+
console.log(chalk7.blue(`
|
|
336
759
|
\u{1F4C4} ${options.entity}
|
|
337
760
|
`));
|
|
338
|
-
|
|
761
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
762
|
+
}
|
|
763
|
+
});
|
|
339
764
|
} catch (error) {
|
|
340
|
-
spinner
|
|
341
|
-
throw error;
|
|
765
|
+
exitWithCommandError(spinner, "Failed to fetch entity", error);
|
|
342
766
|
}
|
|
343
767
|
}
|
|
344
768
|
async function createEntity(client, options) {
|
|
345
|
-
const spinner =
|
|
769
|
+
const spinner = createSpinner(`Creating ${options.entity}...`, options.format);
|
|
346
770
|
try {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
} else {
|
|
351
|
-
const { default: inquirer } = await import('inquirer');
|
|
352
|
-
const { jsonData } = await inquirer.prompt([
|
|
353
|
-
{
|
|
354
|
-
type: "editor",
|
|
355
|
-
name: "jsonData",
|
|
356
|
-
message: "Enter JSON data:",
|
|
357
|
-
default: "{}"
|
|
358
|
-
}
|
|
359
|
-
]);
|
|
360
|
-
data = JSON.parse(jsonData);
|
|
361
|
-
}
|
|
362
|
-
const result = await client.entity.create(options.namespace, options.entity, data);
|
|
771
|
+
const entityClient = client.entity;
|
|
772
|
+
const data = await loadJsonObjectInput(options.data, "entity data", "Enter JSON data:");
|
|
773
|
+
const result = await entityClient.create(options.namespace, options.entity, data);
|
|
363
774
|
if (result.error) {
|
|
364
775
|
spinner.fail("Failed to create entity");
|
|
365
776
|
console.error(chalk7.red(result.error.message));
|
|
366
777
|
process.exit(1);
|
|
367
778
|
}
|
|
368
779
|
spinner.succeed("Entity created");
|
|
369
|
-
|
|
370
|
-
|
|
780
|
+
renderOutput(result.data, {
|
|
781
|
+
format: options.format,
|
|
782
|
+
pretty: () => {
|
|
783
|
+
console.log(chalk7.green("\nCreated entity:"));
|
|
784
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
785
|
+
}
|
|
786
|
+
});
|
|
371
787
|
} catch (error) {
|
|
372
|
-
spinner
|
|
373
|
-
throw error;
|
|
788
|
+
exitWithCommandError(spinner, "Failed to create entity", error);
|
|
374
789
|
}
|
|
375
790
|
}
|
|
376
791
|
async function updateEntity(client, options) {
|
|
377
|
-
const spinner =
|
|
792
|
+
const spinner = createSpinner(`Updating ${options.entity}...`, options.format);
|
|
378
793
|
try {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
} else {
|
|
383
|
-
const { default: inquirer } = await import('inquirer');
|
|
384
|
-
const { jsonData } = await inquirer.prompt([
|
|
385
|
-
{
|
|
386
|
-
type: "editor",
|
|
387
|
-
name: "jsonData",
|
|
388
|
-
message: "Enter JSON data:",
|
|
389
|
-
default: "{}"
|
|
390
|
-
}
|
|
391
|
-
]);
|
|
392
|
-
data = JSON.parse(jsonData);
|
|
393
|
-
}
|
|
394
|
-
const result = await client.entity.update(options.namespace, options.entity, options.id, data);
|
|
794
|
+
const entityClient = client.entity;
|
|
795
|
+
const data = await loadJsonObjectInput(options.data, "entity data", "Enter JSON data:");
|
|
796
|
+
const result = await entityClient.update(options.namespace, options.entity, options.id, data);
|
|
395
797
|
if (result.error) {
|
|
396
798
|
spinner.fail("Failed to update entity");
|
|
397
799
|
console.error(chalk7.red(result.error.message));
|
|
398
800
|
process.exit(1);
|
|
399
801
|
}
|
|
400
802
|
spinner.succeed("Entity updated");
|
|
401
|
-
|
|
402
|
-
|
|
803
|
+
renderOutput(result.data, {
|
|
804
|
+
format: options.format,
|
|
805
|
+
pretty: () => {
|
|
806
|
+
console.log(chalk7.green("\nUpdated entity:"));
|
|
807
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
808
|
+
}
|
|
809
|
+
});
|
|
403
810
|
} catch (error) {
|
|
404
|
-
spinner
|
|
405
|
-
throw error;
|
|
811
|
+
exitWithCommandError(spinner, "Failed to update entity", error);
|
|
406
812
|
}
|
|
407
813
|
}
|
|
408
814
|
async function deleteEntity(client, options) {
|
|
409
|
-
const spinner =
|
|
815
|
+
const spinner = createSpinner(`Deleting ${options.entity}...`, options.format);
|
|
410
816
|
try {
|
|
411
|
-
const
|
|
817
|
+
const entityClient = client.entity;
|
|
818
|
+
const result = await entityClient.delete(options.namespace, options.entity, options.id);
|
|
412
819
|
if (result.error) {
|
|
413
820
|
spinner.fail("Failed to delete entity");
|
|
414
821
|
console.error(chalk7.red(result.error.message));
|
|
415
822
|
process.exit(1);
|
|
416
823
|
}
|
|
417
824
|
spinner.succeed("Entity deleted");
|
|
418
|
-
|
|
825
|
+
renderOutput(
|
|
826
|
+
{
|
|
827
|
+
namespace: options.namespace,
|
|
828
|
+
entity: options.entity,
|
|
829
|
+
id: options.id,
|
|
830
|
+
deleted: true
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
format: options.format,
|
|
834
|
+
pretty: () => {
|
|
835
|
+
console.log(chalk7.green(`
|
|
419
836
|
Deleted ${options.entity} with ID: ${options.id}`));
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
);
|
|
420
840
|
} catch (error) {
|
|
421
|
-
spinner
|
|
422
|
-
|
|
841
|
+
exitWithCommandError(spinner, "Failed to delete entity", error);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
async function listEntityOptions(client, options) {
|
|
845
|
+
const spinner = createSpinner(`Fetching ${options.entity} options...`, options.format);
|
|
846
|
+
try {
|
|
847
|
+
const entityClient = client.entity;
|
|
848
|
+
const fields = parseCommaSeparatedValues(options.fields);
|
|
849
|
+
const result = await entityClient.options(options.namespace, options.entity, fields);
|
|
850
|
+
if (result.error) {
|
|
851
|
+
spinner.fail("Failed to fetch entity options");
|
|
852
|
+
console.error(chalk7.red(result.error.message));
|
|
853
|
+
process.exit(1);
|
|
854
|
+
}
|
|
855
|
+
spinner.succeed(`Found ${result.data?.length || 0} options`);
|
|
856
|
+
renderOutput(result.data || [], {
|
|
857
|
+
format: options.format,
|
|
858
|
+
pretty: () => {
|
|
859
|
+
console.log(chalk7.blue(`
|
|
860
|
+
\u{1F9FE} ${options.entity} options
|
|
861
|
+
`));
|
|
862
|
+
console.log(JSON.stringify(result.data || [], null, 2));
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
} catch (error) {
|
|
866
|
+
exitWithCommandError(spinner, "Failed to fetch entity options", error);
|
|
423
867
|
}
|
|
424
868
|
}
|
|
425
|
-
async function
|
|
426
|
-
const spinner =
|
|
869
|
+
async function bulkUpdateEntities(client, options) {
|
|
870
|
+
const spinner = createSpinner(`Bulk updating ${options.entity}...`, options.format);
|
|
427
871
|
try {
|
|
428
|
-
const
|
|
872
|
+
const entityClient = client.entity;
|
|
873
|
+
const rawItems = await loadJsonArrayInput(
|
|
874
|
+
options.items,
|
|
875
|
+
"bulk update items",
|
|
876
|
+
"Enter JSON array of items:"
|
|
877
|
+
);
|
|
878
|
+
const items = validateBulkUpdateItems(rawItems);
|
|
879
|
+
const result = await entityClient.bulkUpdate(options.namespace, options.entity, items);
|
|
880
|
+
if (result.error) {
|
|
881
|
+
spinner.fail("Failed to bulk update entities");
|
|
882
|
+
console.error(chalk7.red(result.error.message));
|
|
883
|
+
process.exit(1);
|
|
884
|
+
}
|
|
885
|
+
spinner.succeed(`Updated ${items.length} entities`);
|
|
886
|
+
renderOutput(result.data, {
|
|
887
|
+
format: options.format,
|
|
888
|
+
pretty: () => {
|
|
889
|
+
console.log(chalk7.green(`
|
|
890
|
+
Bulk updated ${items.length} ${options.entity} records:`));
|
|
891
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
} catch (error) {
|
|
895
|
+
exitWithCommandError(spinner, "Failed to bulk update entities", error);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
async function bulkDeleteEntities(client, options) {
|
|
899
|
+
const spinner = createSpinner(`Bulk deleting ${options.entity}...`, options.format);
|
|
900
|
+
try {
|
|
901
|
+
const entityClient = client.entity;
|
|
902
|
+
const ids = await loadIdsInput(options.ids);
|
|
903
|
+
const result = await entityClient.bulkDelete(options.namespace, options.entity, ids);
|
|
904
|
+
if (result.error) {
|
|
905
|
+
spinner.fail("Failed to bulk delete entities");
|
|
906
|
+
console.error(chalk7.red(result.error.message));
|
|
907
|
+
process.exit(1);
|
|
908
|
+
}
|
|
909
|
+
spinner.succeed(`Deleted ${ids.length} entities`);
|
|
910
|
+
renderOutput(
|
|
911
|
+
{
|
|
912
|
+
namespace: options.namespace,
|
|
913
|
+
entity: options.entity,
|
|
914
|
+
ids,
|
|
915
|
+
deleted: true,
|
|
916
|
+
count: ids.length
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
format: options.format,
|
|
920
|
+
pretty: () => {
|
|
921
|
+
console.log(chalk7.green(`
|
|
922
|
+
Deleted ${ids.length} ${options.entity} records.`));
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
);
|
|
926
|
+
} catch (error) {
|
|
927
|
+
exitWithCommandError(spinner, "Failed to bulk delete entities", error);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
async function listProcesses(client, options = {}) {
|
|
931
|
+
const spinner = createSpinner("Fetching process definitions...", options.format);
|
|
932
|
+
try {
|
|
933
|
+
const bpmClient = client.bpm;
|
|
934
|
+
const result = await bpmClient.getProcessDefinitions();
|
|
429
935
|
if (result.error) {
|
|
430
936
|
spinner.fail("Failed to fetch processes");
|
|
431
937
|
console.error(chalk7.red(result.error.message));
|
|
@@ -433,23 +939,29 @@ async function listProcesses(client) {
|
|
|
433
939
|
}
|
|
434
940
|
spinner.succeed(`Found ${result.data?.length || 0} process definitions`);
|
|
435
941
|
const processes = result.data || [];
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
942
|
+
renderOutput(processes, {
|
|
943
|
+
format: options.format,
|
|
944
|
+
pretty: () => {
|
|
945
|
+
console.log(chalk7.blue("\n\u{1F4CA} Process Definitions\n"));
|
|
946
|
+
for (const proc of processes) {
|
|
947
|
+
console.log(` ${chalk7.green("\u2022")} ${chalk7.bold(proc.key)}`);
|
|
948
|
+
console.log(` ${chalk7.gray("Name:")} ${proc.name || "N/A"}`);
|
|
949
|
+
console.log(` ${chalk7.gray("Version:")} ${proc.version || "N/A"}`);
|
|
950
|
+
console.log();
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
});
|
|
443
954
|
} catch (error) {
|
|
444
955
|
spinner.fail("Failed to fetch processes");
|
|
445
956
|
throw error;
|
|
446
957
|
}
|
|
447
958
|
}
|
|
448
959
|
async function startProcess(client, options) {
|
|
449
|
-
const spinner =
|
|
960
|
+
const spinner = createSpinner(`Starting process: ${options.key}...`, options.format);
|
|
450
961
|
try {
|
|
962
|
+
const bpmClient = client.bpm;
|
|
451
963
|
const variables = options.variables ? JSON.parse(options.variables) : {};
|
|
452
|
-
const result = await
|
|
964
|
+
const result = await bpmClient.startProcess({
|
|
453
965
|
processKey: options.key,
|
|
454
966
|
variables
|
|
455
967
|
});
|
|
@@ -459,24 +971,30 @@ async function startProcess(client, options) {
|
|
|
459
971
|
process.exit(1);
|
|
460
972
|
}
|
|
461
973
|
spinner.succeed("Process started");
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
974
|
+
renderOutput(result.data, {
|
|
975
|
+
format: options.format,
|
|
976
|
+
pretty: () => {
|
|
977
|
+
console.log(chalk7.green("\nProcess Instance:"));
|
|
978
|
+
console.log(` ${chalk7.bold("ID:")} ${result.data?.id}`);
|
|
979
|
+
console.log(` ${chalk7.bold("Definition ID:")} ${result.data?.definitionId}`);
|
|
980
|
+
console.log(` ${chalk7.bold("Business Key:")} ${result.data?.businessKey || "N/A"}`);
|
|
981
|
+
console.log(` ${chalk7.bold("Status:")} ${result.data?.suspended ? "Suspended" : "Active"}`);
|
|
982
|
+
}
|
|
983
|
+
});
|
|
467
984
|
} catch (error) {
|
|
468
985
|
spinner.fail("Failed to start process");
|
|
469
986
|
throw error;
|
|
470
987
|
}
|
|
471
988
|
}
|
|
472
989
|
async function listTasks(client, options) {
|
|
473
|
-
const spinner =
|
|
990
|
+
const spinner = createSpinner("Fetching tasks...", options.format);
|
|
474
991
|
try {
|
|
992
|
+
const bpmClient = client.bpm;
|
|
475
993
|
const params = {};
|
|
476
994
|
if (options.assignee) {
|
|
477
995
|
params.assignee = options.assignee;
|
|
478
996
|
}
|
|
479
|
-
const result = await
|
|
997
|
+
const result = await bpmClient.getMyTasks(params);
|
|
480
998
|
if (result.error) {
|
|
481
999
|
spinner.fail("Failed to fetch tasks");
|
|
482
1000
|
console.error(chalk7.red(result.error.message));
|
|
@@ -484,39 +1002,58 @@ async function listTasks(client, options) {
|
|
|
484
1002
|
}
|
|
485
1003
|
spinner.succeed(`Found ${result.data?.length || 0} tasks`);
|
|
486
1004
|
const tasks = result.data || [];
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
1005
|
+
renderOutput(tasks, {
|
|
1006
|
+
format: options.format,
|
|
1007
|
+
pretty: () => {
|
|
1008
|
+
console.log(chalk7.blue("\n\u{1F4DD} Tasks\n"));
|
|
1009
|
+
for (const task of tasks) {
|
|
1010
|
+
console.log(` ${chalk7.green("\u2022")} ${chalk7.bold(task.name || task.id)}`);
|
|
1011
|
+
console.log(` ${chalk7.gray("ID:")} ${task.id}`);
|
|
1012
|
+
console.log(` ${chalk7.gray("Assignee:")} ${task.assignee || "Unassigned"}`);
|
|
1013
|
+
console.log(` ${chalk7.gray("Created:")} ${task.created || "N/A"}`);
|
|
1014
|
+
console.log();
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
495
1018
|
} catch (error) {
|
|
496
1019
|
spinner.fail("Failed to fetch tasks");
|
|
497
1020
|
throw error;
|
|
498
1021
|
}
|
|
499
1022
|
}
|
|
500
1023
|
async function completeTask(client, options) {
|
|
501
|
-
const spinner =
|
|
1024
|
+
const spinner = createSpinner(`Completing task: ${options.id}...`, options.format);
|
|
502
1025
|
try {
|
|
1026
|
+
const bpmClient = client.bpm;
|
|
503
1027
|
const variables = options.variables ? JSON.parse(options.variables) : {};
|
|
504
|
-
const result = await
|
|
1028
|
+
const result = await bpmClient.completeTask(options.id, { variables });
|
|
505
1029
|
if (result.error) {
|
|
506
1030
|
spinner.fail("Failed to complete task");
|
|
507
1031
|
console.error(chalk7.red(result.error.message));
|
|
508
1032
|
process.exit(1);
|
|
509
1033
|
}
|
|
510
1034
|
spinner.succeed("Task completed");
|
|
1035
|
+
renderOutput(
|
|
1036
|
+
{
|
|
1037
|
+
id: options.id,
|
|
1038
|
+
completed: true
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
format: options.format,
|
|
1042
|
+
pretty: () => {
|
|
1043
|
+
console.log(chalk7.green(`Completed task: ${options.id}`));
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
);
|
|
511
1047
|
} catch (error) {
|
|
512
1048
|
spinner.fail("Failed to complete task");
|
|
513
1049
|
throw error;
|
|
514
1050
|
}
|
|
515
1051
|
}
|
|
516
|
-
async function listWorkflows(client) {
|
|
517
|
-
const spinner =
|
|
1052
|
+
async function listWorkflows(client, options = {}) {
|
|
1053
|
+
const spinner = createSpinner("Fetching workflows...", options.format);
|
|
518
1054
|
try {
|
|
519
|
-
const
|
|
1055
|
+
const workflowClient = client.workflow;
|
|
1056
|
+
const result = await workflowClient.listWorkflows();
|
|
520
1057
|
if (result.error) {
|
|
521
1058
|
spinner.fail("Failed to fetch workflows");
|
|
522
1059
|
console.error(chalk7.red(result.error.message));
|
|
@@ -524,24 +1061,30 @@ async function listWorkflows(client) {
|
|
|
524
1061
|
}
|
|
525
1062
|
spinner.succeed(`Found ${result.data?.length || 0} workflows`);
|
|
526
1063
|
const workflows = result.data || [];
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
1064
|
+
renderOutput(workflows, {
|
|
1065
|
+
format: options.format,
|
|
1066
|
+
pretty: () => {
|
|
1067
|
+
console.log(chalk7.blue("\n\u26A1 Workflows\n"));
|
|
1068
|
+
for (const workflow of workflows) {
|
|
1069
|
+
console.log(` ${chalk7.green("\u2022")} ${chalk7.bold(workflow.code || workflow.id)}`);
|
|
1070
|
+
console.log(` ${chalk7.gray("Name:")} ${workflow.name || "N/A"}`);
|
|
1071
|
+
console.log(` ${chalk7.gray("Description:")} ${workflow.description || "N/A"}`);
|
|
1072
|
+
console.log(` ${chalk7.gray("Status:")} ${workflow.status || "N/A"}`);
|
|
1073
|
+
console.log();
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
535
1077
|
} catch (error) {
|
|
536
1078
|
spinner.fail("Failed to fetch workflows");
|
|
537
1079
|
throw error;
|
|
538
1080
|
}
|
|
539
1081
|
}
|
|
540
1082
|
async function executeWorkflow(client, options) {
|
|
541
|
-
const spinner =
|
|
1083
|
+
const spinner = createSpinner(`Executing workflow: ${options.id}...`, options.format);
|
|
542
1084
|
try {
|
|
1085
|
+
const workflowClient = client.workflow;
|
|
543
1086
|
const input = options.input ? JSON.parse(options.input) : {};
|
|
544
|
-
const result = await
|
|
1087
|
+
const result = await workflowClient.execute(options.id, {
|
|
545
1088
|
input,
|
|
546
1089
|
version: options.version
|
|
547
1090
|
});
|
|
@@ -551,22 +1094,28 @@ async function executeWorkflow(client, options) {
|
|
|
551
1094
|
process.exit(1);
|
|
552
1095
|
}
|
|
553
1096
|
spinner.succeed("Workflow executed");
|
|
554
|
-
|
|
555
|
-
|
|
1097
|
+
renderOutput(result.data, {
|
|
1098
|
+
format: options.format,
|
|
1099
|
+
pretty: () => {
|
|
1100
|
+
console.log(chalk7.green("\nExecution Result:"));
|
|
1101
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
556
1104
|
} catch (error) {
|
|
557
1105
|
spinner.fail("Failed to execute workflow");
|
|
558
1106
|
throw error;
|
|
559
1107
|
}
|
|
560
1108
|
}
|
|
561
1109
|
async function uploadFile(client, options) {
|
|
562
|
-
const spinner =
|
|
1110
|
+
const spinner = createSpinner("Uploading file...", options.format);
|
|
563
1111
|
try {
|
|
1112
|
+
const s3Client = client.s3;
|
|
564
1113
|
const filePath = resolve(options.file);
|
|
565
1114
|
if (!existsSync(filePath)) {
|
|
566
1115
|
spinner.fail(`File not found: ${options.file}`);
|
|
567
1116
|
process.exit(1);
|
|
568
1117
|
}
|
|
569
|
-
const result = await
|
|
1118
|
+
const result = await s3Client.uploadFile(filePath, {
|
|
570
1119
|
key: options.key,
|
|
571
1120
|
bucket: options.bucket,
|
|
572
1121
|
isPublic: options.public
|
|
@@ -577,19 +1126,25 @@ async function uploadFile(client, options) {
|
|
|
577
1126
|
process.exit(1);
|
|
578
1127
|
}
|
|
579
1128
|
spinner.succeed("Upload complete");
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
1129
|
+
renderOutput(result.data, {
|
|
1130
|
+
format: options.format,
|
|
1131
|
+
pretty: () => {
|
|
1132
|
+
console.log(chalk7.green("\nFile uploaded:"));
|
|
1133
|
+
console.log(` ${chalk7.bold("Key:")} ${result.data?.key}`);
|
|
1134
|
+
console.log(` ${chalk7.bold("URL:")} ${result.data?.url || "N/A"}`);
|
|
1135
|
+
console.log(` ${chalk7.bold("Bucket:")} ${result.data?.bucket || options.bucket || "default"}`);
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
584
1138
|
} catch (error) {
|
|
585
1139
|
spinner.fail("Upload failed");
|
|
586
1140
|
throw error;
|
|
587
1141
|
}
|
|
588
1142
|
}
|
|
589
1143
|
async function listFiles(client, options) {
|
|
590
|
-
const spinner =
|
|
1144
|
+
const spinner = createSpinner("Fetching files...", options.format);
|
|
591
1145
|
try {
|
|
592
|
-
const
|
|
1146
|
+
const s3Client = client.s3;
|
|
1147
|
+
const result = await s3Client.listFiles({
|
|
593
1148
|
bucket: options.bucket,
|
|
594
1149
|
prefix: options.prefix,
|
|
595
1150
|
page: options.page || 1,
|
|
@@ -602,15 +1157,20 @@ async function listFiles(client, options) {
|
|
|
602
1157
|
}
|
|
603
1158
|
spinner.succeed(`Found ${result.data?.total || 0} files`);
|
|
604
1159
|
const files = result.data?.list || [];
|
|
605
|
-
|
|
1160
|
+
renderOutput(result.data, {
|
|
1161
|
+
format: options.format,
|
|
1162
|
+
pretty: () => {
|
|
1163
|
+
console.log(chalk7.blue(`
|
|
606
1164
|
\u{1F4C1} Files${options.bucket ? ` in ${options.bucket}` : ""}
|
|
607
1165
|
`));
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
1166
|
+
for (const file of files) {
|
|
1167
|
+
console.log(` ${chalk7.green("\u2022")} ${chalk7.bold(file.key)}`);
|
|
1168
|
+
console.log(` ${chalk7.gray("Size:")} ${formatBytes(file.size || 0)}`);
|
|
1169
|
+
console.log(` ${chalk7.gray("Modified:")} ${file.lastModified || "N/A"}`);
|
|
1170
|
+
console.log();
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
614
1174
|
} catch (error) {
|
|
615
1175
|
spinner.fail("Failed to fetch files");
|
|
616
1176
|
throw error;
|
|
@@ -649,7 +1209,14 @@ function getAppMcpConfigPath(appCode) {
|
|
|
649
1209
|
return `/openclaw/apps/${appCode}/mcp-config.yaml`;
|
|
650
1210
|
}
|
|
651
1211
|
async function initOpenClaw(options) {
|
|
652
|
-
const spinner =
|
|
1212
|
+
const spinner = createSpinner(`Initializing app: ${options.appCode}...`, options.format);
|
|
1213
|
+
const pretty = isPrettyOutput(options.format);
|
|
1214
|
+
const ossEndpoint = options.ossEndpoint || DEFAULT_OSS_ENDPOINT;
|
|
1215
|
+
let installedSkills = 0;
|
|
1216
|
+
let configuredMcpServers = 0;
|
|
1217
|
+
let skillsError = null;
|
|
1218
|
+
let mcpError = null;
|
|
1219
|
+
const openClawDetected = existsSync(OPENCLAW_CONFIG_DIR);
|
|
653
1220
|
try {
|
|
654
1221
|
const existingConfig = getAppConfig(options.appCode);
|
|
655
1222
|
if (existingConfig && !options.force) {
|
|
@@ -658,29 +1225,45 @@ async function initOpenClaw(options) {
|
|
|
658
1225
|
console.log(chalk7.gray(`Current URL: ${existingConfig.baseURL}`));
|
|
659
1226
|
process.exit(1);
|
|
660
1227
|
}
|
|
661
|
-
if (!existsSync(OPENCLAW_CONFIG_DIR)) {
|
|
662
|
-
spinner.fail("OpenClaw not detected");
|
|
663
|
-
console.log(chalk7.yellow("\n\u26A0\uFE0F Please install OpenClaw first:"));
|
|
664
|
-
console.log(chalk7.gray(" npm install -g openclaw"));
|
|
665
|
-
process.exit(1);
|
|
666
|
-
}
|
|
667
1228
|
addApp(options.appCode, {
|
|
668
1229
|
baseURL: options.baseURL,
|
|
669
|
-
ossEndpoint
|
|
1230
|
+
ossEndpoint,
|
|
670
1231
|
initializedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
671
1232
|
});
|
|
1233
|
+
if (!openClawDetected) {
|
|
1234
|
+
spinner.succeed(`App initialized: ${options.appCode}`);
|
|
1235
|
+
if (pretty) {
|
|
1236
|
+
console.log(chalk7.yellow("\n\u26A0\uFE0F OpenClaw not detected, skipping skill download"));
|
|
1237
|
+
console.log(chalk7.gray(" Install OpenClaw: npm install -g openclaw"));
|
|
1238
|
+
} else {
|
|
1239
|
+
renderOutput(
|
|
1240
|
+
{
|
|
1241
|
+
appCode: options.appCode,
|
|
1242
|
+
baseURL: options.baseURL,
|
|
1243
|
+
ossEndpoint,
|
|
1244
|
+
openClawDetected: false,
|
|
1245
|
+
installedSkills: 0,
|
|
1246
|
+
configuredMcpServers: 0
|
|
1247
|
+
},
|
|
1248
|
+
{ format: options.format }
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
672
1253
|
spinner.succeed(`App initialized: ${options.appCode}`);
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
1254
|
+
if (pretty) {
|
|
1255
|
+
console.log(chalk7.blue("\n\u{1F4CB} Configuration:\n"));
|
|
1256
|
+
console.log(` App Code: ${chalk7.green(options.appCode)}`);
|
|
1257
|
+
console.log(` Base URL: ${chalk7.gray(options.baseURL)}`);
|
|
1258
|
+
console.log();
|
|
1259
|
+
}
|
|
678
1260
|
spinner.start("Downloading skills...");
|
|
679
1261
|
try {
|
|
680
1262
|
const skills = await downloadSkillManifest(ossEndpoint, options.appCode);
|
|
681
1263
|
if (skills.length === 0) {
|
|
682
1264
|
spinner.warn("No skills found");
|
|
683
1265
|
} else {
|
|
1266
|
+
installedSkills = skills.length;
|
|
684
1267
|
spinner.text = `Installing ${skills.length} skills...`;
|
|
685
1268
|
const appSkillsDir = join(OPENCLAW_SKILLS_DIR, options.appCode);
|
|
686
1269
|
if (options.force && existsSync(appSkillsDir)) {
|
|
@@ -696,12 +1279,14 @@ async function initOpenClaw(options) {
|
|
|
696
1279
|
spinner.succeed(`Installed ${skills.length} skills`);
|
|
697
1280
|
}
|
|
698
1281
|
} catch (error) {
|
|
1282
|
+
skillsError = error instanceof Error ? error.message : String(error);
|
|
699
1283
|
spinner.warn("Skills download failed (optional)");
|
|
700
1284
|
}
|
|
701
1285
|
spinner.start("Configuring MCP servers...");
|
|
702
1286
|
try {
|
|
703
1287
|
const mcpServers = await downloadMcpConfig(ossEndpoint, options.appCode);
|
|
704
1288
|
if (Object.keys(mcpServers).length > 0) {
|
|
1289
|
+
configuredMcpServers = Object.keys(mcpServers).length;
|
|
705
1290
|
const openClawConfig = getOpenClawConfig();
|
|
706
1291
|
if (!openClawConfig.mcpServers) {
|
|
707
1292
|
openClawConfig.mcpServers = {};
|
|
@@ -715,23 +1300,48 @@ async function initOpenClaw(options) {
|
|
|
715
1300
|
spinner.succeed("No MCP servers to configure");
|
|
716
1301
|
}
|
|
717
1302
|
} catch (error) {
|
|
1303
|
+
mcpError = error instanceof Error ? error.message : String(error);
|
|
718
1304
|
spinner.warn("MCP configuration failed (optional)");
|
|
719
1305
|
}
|
|
720
|
-
console.log();
|
|
721
|
-
console.log(chalk7.green("\u2705 Initialization complete!"));
|
|
722
|
-
console.log();
|
|
723
|
-
console.log(`Next step: Login to your app`);
|
|
724
|
-
console.log(chalk7.gray(` amaster login --app ${options.appCode}`));
|
|
725
|
-
console.log();
|
|
726
1306
|
const apps = listApps();
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1307
|
+
const configuredApps = apps.map((app) => {
|
|
1308
|
+
const config = getAppConfig(app);
|
|
1309
|
+
return {
|
|
1310
|
+
appCode: app,
|
|
1311
|
+
baseURL: config?.baseURL || null
|
|
1312
|
+
};
|
|
1313
|
+
});
|
|
1314
|
+
const summary = {
|
|
1315
|
+
appCode: options.appCode,
|
|
1316
|
+
baseURL: options.baseURL,
|
|
1317
|
+
ossEndpoint,
|
|
1318
|
+
openClawDetected: true,
|
|
1319
|
+
installedSkills,
|
|
1320
|
+
configuredMcpServers,
|
|
1321
|
+
configuredApps,
|
|
1322
|
+
warnings: {
|
|
1323
|
+
skills: skillsError,
|
|
1324
|
+
mcpServers: mcpError
|
|
732
1325
|
}
|
|
1326
|
+
};
|
|
1327
|
+
if (pretty) {
|
|
1328
|
+
console.log();
|
|
1329
|
+
console.log(chalk7.green("\u2705 Initialization complete!"));
|
|
733
1330
|
console.log();
|
|
1331
|
+
console.log(`Next step: Login to your app`);
|
|
1332
|
+
console.log(chalk7.gray(` amaster login --app ${options.appCode}`));
|
|
1333
|
+
console.log();
|
|
1334
|
+
if (apps.length > 1) {
|
|
1335
|
+
console.log(chalk7.blue("Configured apps:"));
|
|
1336
|
+
for (const app of apps) {
|
|
1337
|
+
const config = getAppConfig(app);
|
|
1338
|
+
console.log(` ${chalk7.gray("\u2022")} ${app} - ${config?.baseURL}`);
|
|
1339
|
+
}
|
|
1340
|
+
console.log();
|
|
1341
|
+
}
|
|
1342
|
+
return;
|
|
734
1343
|
}
|
|
1344
|
+
renderOutput(summary, { format: options.format });
|
|
735
1345
|
} catch (error) {
|
|
736
1346
|
spinner.fail("Initialization failed");
|
|
737
1347
|
throw error;
|
|
@@ -854,163 +1464,257 @@ function createAmasterClient(appCode) {
|
|
|
854
1464
|
process.exit(1);
|
|
855
1465
|
}
|
|
856
1466
|
if (shouldRefreshToken(appCode)) {
|
|
857
|
-
console.
|
|
1467
|
+
console.error(chalk7.yellow("\u26A0\uFE0F Session expiring soon. Please login again."));
|
|
858
1468
|
}
|
|
859
|
-
|
|
1469
|
+
const client = createClient({
|
|
860
1470
|
baseURL: appConfig.baseURL,
|
|
861
1471
|
headers: {
|
|
862
1472
|
Authorization: `Bearer ${token}`
|
|
863
1473
|
},
|
|
864
1474
|
onUnauthorized: () => {
|
|
865
1475
|
console.error(chalk7.red("\n\u274C Session expired. Please login again."));
|
|
866
|
-
console.
|
|
1476
|
+
console.error(chalk7.yellow(`Run: amaster login --app ${appCode}`));
|
|
867
1477
|
process.exit(1);
|
|
868
1478
|
}
|
|
869
1479
|
});
|
|
1480
|
+
client.setAccessToken(token);
|
|
1481
|
+
return client;
|
|
870
1482
|
}
|
|
871
1483
|
var program = new Command();
|
|
872
1484
|
program.name("amaster").description("CLI for Amaster SDK - Multi-app support for OpenClaw").version("1.0.0");
|
|
873
|
-
program.command("apps").description("List all configured apps").action(() => {
|
|
1485
|
+
program.command("apps").description("List all configured apps").addOption(createFormatOption()).action((options) => {
|
|
874
1486
|
const apps = listApps();
|
|
875
1487
|
const current = getCurrentApp();
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
console.log(
|
|
1488
|
+
const appSummaries = apps.map((appCode) => {
|
|
1489
|
+
const config = getAppConfig(appCode);
|
|
1490
|
+
return {
|
|
1491
|
+
appCode,
|
|
1492
|
+
baseURL: config?.baseURL || null,
|
|
1493
|
+
authenticated: isAuthenticated(appCode),
|
|
1494
|
+
current: appCode === current
|
|
1495
|
+
};
|
|
1496
|
+
});
|
|
1497
|
+
renderOutput(appSummaries, {
|
|
1498
|
+
format: options.format,
|
|
1499
|
+
pretty: () => {
|
|
1500
|
+
console.log(chalk7.blue("\n\u{1F4F1} Configured Apps\n"));
|
|
1501
|
+
if (appSummaries.length === 0) {
|
|
1502
|
+
console.log(chalk7.gray(" No apps configured"));
|
|
1503
|
+
console.log(chalk7.gray(" Run: amaster init --app-code <code> --url <url>"));
|
|
1504
|
+
} else {
|
|
1505
|
+
for (const app of appSummaries) {
|
|
1506
|
+
const prefix = app.current ? chalk7.green("\u2192 ") : " ";
|
|
1507
|
+
console.log(`${prefix}${chalk7.bold(app.appCode)}${app.current ? chalk7.green(" (current)") : ""}`);
|
|
1508
|
+
console.log(` ${chalk7.gray(app.baseURL || "No URL")}`);
|
|
1509
|
+
console.log(
|
|
1510
|
+
` ${app.authenticated ? chalk7.green("\u25CF Authenticated") : chalk7.yellow("\u25CB Not authenticated")}`
|
|
1511
|
+
);
|
|
1512
|
+
console.log();
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
889
1515
|
console.log();
|
|
890
1516
|
}
|
|
891
|
-
}
|
|
892
|
-
console.log();
|
|
1517
|
+
});
|
|
893
1518
|
});
|
|
894
|
-
program.command("use <app-code>").description("Set the default app for subsequent commands").action((appCode) => {
|
|
1519
|
+
program.command("use <app-code>").description("Set the default app for subsequent commands").addOption(createFormatOption()).action((appCode, options) => {
|
|
895
1520
|
if (setCurrentApp(appCode)) {
|
|
896
|
-
|
|
1521
|
+
renderOutput(
|
|
1522
|
+
{
|
|
1523
|
+
appCode,
|
|
1524
|
+
current: true
|
|
1525
|
+
},
|
|
1526
|
+
{
|
|
1527
|
+
format: options.format,
|
|
1528
|
+
pretty: () => {
|
|
1529
|
+
console.log(chalk7.green(`\u2705 Now using app: ${appCode}`));
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
);
|
|
897
1533
|
} else {
|
|
898
1534
|
console.error(chalk7.red(`\u274C App not found: ${appCode}`));
|
|
899
1535
|
process.exit(1);
|
|
900
1536
|
}
|
|
901
1537
|
});
|
|
902
|
-
program.command("init").description("Initialize an app for OpenClaw integration").requiredOption("--app-code <code>", "Application code (e.g., fhv94bto1)").requiredOption("--url <url>", "Base URL (e.g., https://fhv94bto1.helige.cn)").option("--api-key <key>", "API Key for OSS access").option("--oss-endpoint <endpoint>", "OSS endpoint").action(async (options) => {
|
|
1538
|
+
program.command("init").description("Initialize an app for OpenClaw integration").requiredOption("--app-code <code>", "Application code (e.g., fhv94bto1)").requiredOption("--url <url>", "Base URL (e.g., https://fhv94bto1.helige.cn)").option("--api-key <key>", "API Key for OSS access").option("--oss-endpoint <endpoint>", "OSS endpoint").option("--force", "Reinitialize an existing app").addOption(createFormatOption()).action(async (options) => {
|
|
903
1539
|
await initOpenClaw({
|
|
904
1540
|
appCode: options.appCode,
|
|
905
1541
|
baseURL: options.url,
|
|
906
1542
|
apiKey: options.apiKey,
|
|
907
|
-
ossEndpoint: options.ossEndpoint
|
|
1543
|
+
ossEndpoint: options.ossEndpoint,
|
|
1544
|
+
force: options.force,
|
|
1545
|
+
format: options.format
|
|
908
1546
|
});
|
|
909
1547
|
});
|
|
910
|
-
program.command("login").description("Authenticate with an app").option("--app <app-code>", "App code (uses default if not specified)").option("-e, --email <email>", "Email address").option("-p, --password <password>", "Password").action(async (options) => {
|
|
1548
|
+
program.command("login").description("Authenticate with an app").option("--app <app-code>", "App code (uses default if not specified)").option("-u, --username <username>", "Username").option("-e, --email <email>", "Email address").option("-p, --password <password>", "Password").addOption(createFormatOption()).action(async (options) => {
|
|
911
1549
|
const appCode = resolveAppCode(options.app);
|
|
912
|
-
await login(appCode, {
|
|
1550
|
+
await login(appCode, {
|
|
1551
|
+
username: options.username,
|
|
1552
|
+
email: options.email,
|
|
1553
|
+
password: options.password,
|
|
1554
|
+
format: options.format
|
|
1555
|
+
});
|
|
913
1556
|
});
|
|
914
|
-
program.command("logout").description("Logout from an app").option("--app <app-code>", "App code (uses default if not specified)").action(async (options) => {
|
|
1557
|
+
program.command("logout").description("Logout from an app").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (options) => {
|
|
915
1558
|
const appCode = resolveAppCode(options.app);
|
|
916
|
-
await logout(appCode);
|
|
1559
|
+
await logout(appCode, { format: options.format });
|
|
917
1560
|
});
|
|
918
|
-
program.command("whoami").description("Show current user information").option("--app <app-code>", "App code (uses default if not specified)").action(async (options) => {
|
|
1561
|
+
program.command("whoami").description("Show current user information").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (options) => {
|
|
919
1562
|
const appCode = resolveAppCode(options.app);
|
|
920
|
-
await getMe(() => createAmasterClient(appCode));
|
|
1563
|
+
await getMe(() => createAmasterClient(appCode), { format: options.format });
|
|
921
1564
|
});
|
|
922
1565
|
var entityCmd = program.command("entity").description("Manage entities");
|
|
923
|
-
entityCmd.command("list <namespace> <entity>").description("List entities").option("--app <app-code>", "App code (uses default if not specified)").option("--page <page>", "Page number", "1").option("--page-size <size>", "Page size", "10").action(async (namespace, entityName, options) => {
|
|
1566
|
+
entityCmd.command("list <namespace> <entity>").description("List entities").option("--app <app-code>", "App code (uses default if not specified)").option("--page <page>", "Page number", "1").option("--page-size <size>", "Page size", "10").option("-f, --fields <fields>", "Comma-separated fields to return").option("-r, --relations <relations>", "Comma-separated relations to load").option("-k, --keyword <keyword>", "Keyword to search").option("--keyword-fields <fields>", "Comma-separated fields for keyword search").option("--order-by <field>", "Field to sort by").addOption(new Option("--order-dir <dir>", "Sort direction").choices(["asc", "desc"])).option("--orders <orders>", "Multi-order expression, e.g. created_at:desc,name:asc").option("--filter <json>", "Advanced __filter JSON or @file").option("--limit <limit>", "Limit number of records").option("--offset <offset>", "Offset number of records").option("-q, --query <json>", "Additional EntityQueryParams as JSON or @file").addOption(createFormatOption()).action(async (namespace, entityName, options) => {
|
|
924
1567
|
const appCode = resolveAppCode(options.app);
|
|
925
1568
|
await listEntities(createAmasterClient(appCode), {
|
|
926
1569
|
namespace,
|
|
927
1570
|
entity: entityName,
|
|
928
1571
|
page: parseInt(options.page),
|
|
929
|
-
pageSize: parseInt(options.pageSize)
|
|
1572
|
+
pageSize: parseInt(options.pageSize),
|
|
1573
|
+
fields: options.fields,
|
|
1574
|
+
relations: options.relations,
|
|
1575
|
+
keyword: options.keyword,
|
|
1576
|
+
keywordFields: options.keywordFields,
|
|
1577
|
+
orderBy: options.orderBy,
|
|
1578
|
+
orderDir: options.orderDir,
|
|
1579
|
+
orders: options.orders,
|
|
1580
|
+
filter: options.filter,
|
|
1581
|
+
limit: options.limit ? parseInt(options.limit) : void 0,
|
|
1582
|
+
offset: options.offset ? parseInt(options.offset) : void 0,
|
|
1583
|
+
query: options.query,
|
|
1584
|
+
format: options.format
|
|
930
1585
|
});
|
|
931
1586
|
});
|
|
932
|
-
entityCmd.command("get <namespace> <entity> <id>").description("Get entity by ID").option("--app <app-code>", "App code (uses default if not specified)").action(async (namespace, entityName, id, options) => {
|
|
1587
|
+
entityCmd.command("get <namespace> <entity> <id>").description("Get entity by ID").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (namespace, entityName, id, options) => {
|
|
933
1588
|
const appCode = resolveAppCode(options.app);
|
|
934
|
-
await getEntity(createAmasterClient(appCode), {
|
|
1589
|
+
await getEntity(createAmasterClient(appCode), {
|
|
1590
|
+
namespace,
|
|
1591
|
+
entity: entityName,
|
|
1592
|
+
id,
|
|
1593
|
+
format: options.format
|
|
1594
|
+
});
|
|
935
1595
|
});
|
|
936
|
-
entityCmd.command("create <namespace> <entity>").description("Create new entity").option("--app <app-code>", "App code (uses default if not specified)").option("-d, --data <json>", "Entity data as JSON").action(async (namespace, entityName, options) => {
|
|
1596
|
+
entityCmd.command("create <namespace> <entity>").description("Create new entity").option("--app <app-code>", "App code (uses default if not specified)").option("-d, --data <json>", "Entity data as JSON or @file").addOption(createFormatOption()).action(async (namespace, entityName, options) => {
|
|
937
1597
|
const appCode = resolveAppCode(options.app);
|
|
938
1598
|
await createEntity(createAmasterClient(appCode), {
|
|
939
1599
|
namespace,
|
|
940
1600
|
entity: entityName,
|
|
941
|
-
data: options.data
|
|
1601
|
+
data: options.data,
|
|
1602
|
+
format: options.format
|
|
942
1603
|
});
|
|
943
1604
|
});
|
|
944
|
-
entityCmd.command("update <namespace> <entity> <id>").description("Update entity").option("--app <app-code>", "App code (uses default if not specified)").option("-d, --data <json>", "Entity data as JSON").action(async (namespace, entityName, id, options) => {
|
|
1605
|
+
entityCmd.command("update <namespace> <entity> <id>").description("Update entity").option("--app <app-code>", "App code (uses default if not specified)").option("-d, --data <json>", "Entity data as JSON or @file").addOption(createFormatOption()).action(async (namespace, entityName, id, options) => {
|
|
945
1606
|
const appCode = resolveAppCode(options.app);
|
|
946
1607
|
await updateEntity(createAmasterClient(appCode), {
|
|
947
1608
|
namespace,
|
|
948
1609
|
entity: entityName,
|
|
949
1610
|
id,
|
|
950
|
-
data: options.data
|
|
1611
|
+
data: options.data,
|
|
1612
|
+
format: options.format
|
|
951
1613
|
});
|
|
952
1614
|
});
|
|
953
|
-
entityCmd.command("delete <namespace> <entity> <id>").description("Delete entity").option("--app <app-code>", "App code (uses default if not specified)").action(async (namespace, entityName, id, options) => {
|
|
1615
|
+
entityCmd.command("delete <namespace> <entity> <id>").description("Delete entity").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (namespace, entityName, id, options) => {
|
|
954
1616
|
const appCode = resolveAppCode(options.app);
|
|
955
1617
|
await deleteEntity(createAmasterClient(appCode), {
|
|
956
1618
|
namespace,
|
|
957
1619
|
entity: entityName,
|
|
958
|
-
id
|
|
1620
|
+
id,
|
|
1621
|
+
format: options.format
|
|
1622
|
+
});
|
|
1623
|
+
});
|
|
1624
|
+
entityCmd.command("options <namespace> <entity>").description("List entity options").option("--app <app-code>", "App code (uses default if not specified)").option("-f, --fields <fields>", "Comma-separated fields to return").addOption(createFormatOption()).action(async (namespace, entityName, options) => {
|
|
1625
|
+
const appCode = resolveAppCode(options.app);
|
|
1626
|
+
await listEntityOptions(createAmasterClient(appCode), {
|
|
1627
|
+
namespace,
|
|
1628
|
+
entity: entityName,
|
|
1629
|
+
fields: options.fields,
|
|
1630
|
+
format: options.format
|
|
1631
|
+
});
|
|
1632
|
+
});
|
|
1633
|
+
entityCmd.command("bulk-update <namespace> <entity>").description("Bulk update entities").option("--app <app-code>", "App code (uses default if not specified)").option("-i, --items <json>", "Items array as JSON or @file").addOption(createFormatOption()).action(async (namespace, entityName, options) => {
|
|
1634
|
+
const appCode = resolveAppCode(options.app);
|
|
1635
|
+
await bulkUpdateEntities(createAmasterClient(appCode), {
|
|
1636
|
+
namespace,
|
|
1637
|
+
entity: entityName,
|
|
1638
|
+
items: options.items,
|
|
1639
|
+
format: options.format
|
|
1640
|
+
});
|
|
1641
|
+
});
|
|
1642
|
+
entityCmd.command("bulk-delete <namespace> <entity>").description("Bulk delete entities").option("--app <app-code>", "App code (uses default if not specified)").option("--ids <ids>", "Comma-separated IDs, JSON array, or @file").addOption(createFormatOption()).action(async (namespace, entityName, options) => {
|
|
1643
|
+
const appCode = resolveAppCode(options.app);
|
|
1644
|
+
await bulkDeleteEntities(createAmasterClient(appCode), {
|
|
1645
|
+
namespace,
|
|
1646
|
+
entity: entityName,
|
|
1647
|
+
ids: options.ids,
|
|
1648
|
+
format: options.format
|
|
959
1649
|
});
|
|
960
1650
|
});
|
|
961
1651
|
var bpmCmd = program.command("bpm").description("Manage BPM processes and tasks");
|
|
962
|
-
bpmCmd.command("processes").description("List process definitions").option("--app <app-code>", "App code (uses default if not specified)").action(async (options) => {
|
|
1652
|
+
bpmCmd.command("processes").description("List process definitions").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (options) => {
|
|
963
1653
|
const appCode = resolveAppCode(options.app);
|
|
964
|
-
await listProcesses(createAmasterClient(appCode));
|
|
1654
|
+
await listProcesses(createAmasterClient(appCode), { format: options.format });
|
|
965
1655
|
});
|
|
966
|
-
bpmCmd.command("start <key>").description("Start a process instance").option("--app <app-code>", "App code (uses default if not specified)").option("-v, --variables <json>", "Process variables as JSON").action(async (key, options) => {
|
|
1656
|
+
bpmCmd.command("start <key>").description("Start a process instance").option("--app <app-code>", "App code (uses default if not specified)").option("-v, --variables <json>", "Process variables as JSON").addOption(createFormatOption()).action(async (key, options) => {
|
|
967
1657
|
const appCode = resolveAppCode(options.app);
|
|
968
1658
|
await startProcess(createAmasterClient(appCode), {
|
|
969
1659
|
key,
|
|
970
|
-
variables: options.variables
|
|
1660
|
+
variables: options.variables,
|
|
1661
|
+
format: options.format
|
|
971
1662
|
});
|
|
972
1663
|
});
|
|
973
|
-
bpmCmd.command("tasks").description("List tasks").option("--app <app-code>", "App code (uses default if not specified)").option("-a, --assignee <assignee>", "Filter by assignee").action(async (options) => {
|
|
1664
|
+
bpmCmd.command("tasks").description("List tasks").option("--app <app-code>", "App code (uses default if not specified)").option("-a, --assignee <assignee>", "Filter by assignee").addOption(createFormatOption()).action(async (options) => {
|
|
974
1665
|
const appCode = resolveAppCode(options.app);
|
|
975
|
-
await listTasks(createAmasterClient(appCode), {
|
|
1666
|
+
await listTasks(createAmasterClient(appCode), {
|
|
1667
|
+
assignee: options.assignee,
|
|
1668
|
+
format: options.format
|
|
1669
|
+
});
|
|
976
1670
|
});
|
|
977
|
-
bpmCmd.command("complete <id>").description("Complete a task").option("--app <app-code>", "App code (uses default if not specified)").option("-v, --variables <json>", "Task variables as JSON").action(async (id, options) => {
|
|
1671
|
+
bpmCmd.command("complete <id>").description("Complete a task").option("--app <app-code>", "App code (uses default if not specified)").option("-v, --variables <json>", "Task variables as JSON").addOption(createFormatOption()).action(async (id, options) => {
|
|
978
1672
|
const appCode = resolveAppCode(options.app);
|
|
979
1673
|
await completeTask(createAmasterClient(appCode), {
|
|
980
1674
|
id,
|
|
981
|
-
variables: options.variables
|
|
1675
|
+
variables: options.variables,
|
|
1676
|
+
format: options.format
|
|
982
1677
|
});
|
|
983
1678
|
});
|
|
984
1679
|
var workflowCmd = program.command("workflow").description("Manage workflows");
|
|
985
|
-
workflowCmd.command("list").description("List workflows").option("--app <app-code>", "App code (uses default if not specified)").action(async (options) => {
|
|
1680
|
+
workflowCmd.command("list").description("List workflows").option("--app <app-code>", "App code (uses default if not specified)").addOption(createFormatOption()).action(async (options) => {
|
|
986
1681
|
const appCode = resolveAppCode(options.app);
|
|
987
|
-
await listWorkflows(createAmasterClient(appCode));
|
|
1682
|
+
await listWorkflows(createAmasterClient(appCode), { format: options.format });
|
|
988
1683
|
});
|
|
989
|
-
workflowCmd.command("execute <id>").description("Execute a workflow").option("--app <app-code>", "App code (uses default if not specified)").option("-i, --input <json>", "Workflow input as JSON").action(async (id, options) => {
|
|
1684
|
+
workflowCmd.command("execute <id>").description("Execute a workflow").option("--app <app-code>", "App code (uses default if not specified)").option("-i, --input <json>", "Workflow input as JSON").addOption(createFormatOption()).action(async (id, options) => {
|
|
990
1685
|
const appCode = resolveAppCode(options.app);
|
|
991
1686
|
await executeWorkflow(createAmasterClient(appCode), {
|
|
992
1687
|
id,
|
|
993
|
-
input: options.input
|
|
1688
|
+
input: options.input,
|
|
1689
|
+
format: options.format
|
|
994
1690
|
});
|
|
995
1691
|
});
|
|
996
1692
|
var s3Cmd = program.command("s3").description("Manage S3 files");
|
|
997
|
-
s3Cmd.command("list").description("List files").option("--app <app-code>", "App code (uses default if not specified)").option("-b, --bucket <bucket>", "Bucket name").action(async (options) => {
|
|
1693
|
+
s3Cmd.command("list").description("List files").option("--app <app-code>", "App code (uses default if not specified)").option("-b, --bucket <bucket>", "Bucket name").addOption(createFormatOption()).action(async (options) => {
|
|
998
1694
|
const appCode = resolveAppCode(options.app);
|
|
999
1695
|
await listFiles(createAmasterClient(appCode), {
|
|
1000
|
-
bucket: options.bucket
|
|
1696
|
+
bucket: options.bucket,
|
|
1697
|
+
format: options.format
|
|
1001
1698
|
});
|
|
1002
1699
|
});
|
|
1003
|
-
s3Cmd.command("upload <file>").description("Upload a file").option("--app <app-code>", "App code (uses default if not specified)").option("-b, --bucket <bucket>", "Bucket name").option("-k, --key <key>", "Object key").action(async (file, options) => {
|
|
1700
|
+
s3Cmd.command("upload <file>").description("Upload a file").option("--app <app-code>", "App code (uses default if not specified)").option("-b, --bucket <bucket>", "Bucket name").option("-k, --key <key>", "Object key").addOption(createFormatOption()).action(async (file, options) => {
|
|
1004
1701
|
const appCode = resolveAppCode(options.app);
|
|
1005
1702
|
await uploadFile(createAmasterClient(appCode), {
|
|
1006
1703
|
file,
|
|
1007
1704
|
bucket: options.bucket,
|
|
1008
|
-
key: options.key
|
|
1705
|
+
key: options.key,
|
|
1706
|
+
format: options.format
|
|
1009
1707
|
});
|
|
1010
1708
|
});
|
|
1011
1709
|
var isMainModule = import.meta.url === new URL(process.argv[1] || "", import.meta.url).href || import.meta.url.endsWith(process.argv[1] || "") || process.argv[1]?.includes("cli.js") || false;
|
|
1012
1710
|
if (isMainModule) {
|
|
1013
|
-
program.
|
|
1711
|
+
program.parseAsync(process.argv).then(
|
|
1712
|
+
() => process.exit(0),
|
|
1713
|
+
(err) => {
|
|
1714
|
+
console.error(err);
|
|
1715
|
+
process.exit(1);
|
|
1716
|
+
}
|
|
1717
|
+
);
|
|
1014
1718
|
}
|
|
1015
1719
|
|
|
1016
1720
|
export { createAmasterClient, resolveAppCode };
|