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