@lingjingai/lj-awb-cli-pre 0.3.15

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.
Files changed (49) hide show
  1. package/README.md +335 -0
  2. package/build/_shared.mjs +130 -0
  3. package/build/build.mjs +50 -0
  4. package/build/pre-publish.mjs +57 -0
  5. package/build/pre.mjs +42 -0
  6. package/build/prod.mjs +52 -0
  7. package/install.mjs +53 -0
  8. package/package.json +44 -0
  9. package/packages/awb-cli/README.md +19 -0
  10. package/packages/awb-cli/bin/lj-awb +19 -0
  11. package/packages/awb-cli/bin/lj-awb.js +11 -0
  12. package/packages/awb-cli/package.json +18 -0
  13. package/packages/awb-core/README.md +12 -0
  14. package/packages/awb-core/package.json +21 -0
  15. package/packages/awb-core/src/api.js +349 -0
  16. package/packages/awb-core/src/artifact.js +936 -0
  17. package/packages/awb-core/src/auth.js +80 -0
  18. package/packages/awb-core/src/commands.js +1321 -0
  19. package/packages/awb-core/src/common.js +508 -0
  20. package/packages/awb-core/src/output.js +1189 -0
  21. package/packages/awb-core/src/services.js +3811 -0
  22. package/packages/awb-core/src/standalone.js +1213 -0
  23. package/skills/lj-awb/SKILL.md +160 -0
  24. package/skills/lj-awb/VERSION +1 -0
  25. package/skills/lj-awb/compat.json +6 -0
  26. package/skills/lj-awb/modules/account.md +30 -0
  27. package/skills/lj-awb/modules/artifact/asset.md +64 -0
  28. package/skills/lj-awb/modules/artifact/clip.md +65 -0
  29. package/skills/lj-awb/modules/artifact/script.md +37 -0
  30. package/skills/lj-awb/modules/artifact/video.md +65 -0
  31. package/skills/lj-awb/modules/artifact.md +65 -0
  32. package/skills/lj-awb/modules/asset.md +53 -0
  33. package/skills/lj-awb/modules/auth.md +30 -0
  34. package/skills/lj-awb/modules/create-contract.md +118 -0
  35. package/skills/lj-awb/modules/credits.md +28 -0
  36. package/skills/lj-awb/modules/evals.md +186 -0
  37. package/skills/lj-awb/modules/image.md +75 -0
  38. package/skills/lj-awb/modules/model.md +110 -0
  39. package/skills/lj-awb/modules/project.md +30 -0
  40. package/skills/lj-awb/modules/subject.md +32 -0
  41. package/skills/lj-awb/modules/task-manual.md +185 -0
  42. package/skills/lj-awb/modules/task.md +62 -0
  43. package/skills/lj-awb/modules/upload.md +33 -0
  44. package/skills/lj-awb/modules/video.md +102 -0
  45. package/skills/lj-awb/modules/workflows.md +482 -0
  46. package/skills/lj-awb/references/error-codes.md +102 -0
  47. package/skills/lj-awb/references/model-options-read.md +49 -0
  48. package/skills/lj-awb/references/output-fields.md +113 -0
  49. package/skills/lj-awb/scripts/resolve-lj-awb-cmd.sh +10 -0
@@ -0,0 +1,1189 @@
1
+ function isPlainObject(value) {
2
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
3
+ }
4
+
5
+ function compactRecord(record) {
6
+ const result = {};
7
+ for (const [key, value] of Object.entries(record || {})) {
8
+ if (value === undefined || value === null || value === '') continue;
9
+ result[key] = value;
10
+ }
11
+ return result;
12
+ }
13
+
14
+ function commandPrefix() {
15
+ return process.env.LINGJING_AWB_COMMAND_PREFIX || 'lj-awb';
16
+ }
17
+
18
+ function rewriteCommandPrefix(value) {
19
+ if (typeof value !== 'string') return value;
20
+ return value.replace(/\blj-awb\b/g, commandPrefix());
21
+ }
22
+
23
+ function cleanNested(value) {
24
+ if (Array.isArray(value)) return value.map((item) => cleanNested(item));
25
+ if (!isPlainObject(value)) return rewriteCommandPrefix(value);
26
+ const result = {};
27
+ for (const [key, item] of Object.entries(value)) {
28
+ if (['updatedAt', 'updatedAtText'].includes(key)) continue;
29
+ if (item === undefined) continue;
30
+ result[key] = cleanNested(item);
31
+ }
32
+ return result;
33
+ }
34
+
35
+ function rewriteNested(value) {
36
+ if (Array.isArray(value)) return value.map((item) => rewriteNested(item));
37
+ if (!isPlainObject(value)) return rewriteCommandPrefix(value);
38
+ const result = {};
39
+ for (const [key, item] of Object.entries(value)) {
40
+ if (item === undefined) continue;
41
+ result[key] = rewriteNested(item);
42
+ }
43
+ return result;
44
+ }
45
+
46
+ function requestSummary(request = {}) {
47
+ const promptParams = request.promptParams || {};
48
+ return compactRecord({
49
+ requestSource: request.requestSource,
50
+ modelGroupCode: request.modelGroupCode,
51
+ projectGroupNo: request.projectGroupNo,
52
+ customBizId: request.customBizId,
53
+ prompt: promptParams.prompt,
54
+ ratio: promptParams.ratio,
55
+ quality: promptParams.quality,
56
+ duration: promptParams.duration,
57
+ needAudio: promptParams.need_audio,
58
+ generateNum: promptParams.generate_num,
59
+ resourceCount: Array.isArray(promptParams.resources) ? promptParams.resources.length : undefined,
60
+ });
61
+ }
62
+
63
+ function scalarRequestSummary(request = {}) {
64
+ if (!isPlainObject(request)) return {};
65
+ const result = {};
66
+ for (const [key, value] of Object.entries(request)) {
67
+ if (value === undefined || value === null || value === '') continue;
68
+ if (Array.isArray(value) || isPlainObject(value)) continue;
69
+ result[key] = value;
70
+ }
71
+ return result;
72
+ }
73
+
74
+ function scalarDataSummary(data = {}) {
75
+ if (!isPlainObject(data)) return {};
76
+ const excluded = new Set([
77
+ 'request',
78
+ 'files',
79
+ 'assets',
80
+ 'localFile',
81
+ 'localFiles',
82
+ 'results',
83
+ 'raw',
84
+ 'subject',
85
+ 'upload',
86
+ 'uploads',
87
+ 'waited',
88
+ 'data',
89
+ ]);
90
+ const result = {};
91
+ for (const [key, value] of Object.entries(data)) {
92
+ if (excluded.has(key)) continue;
93
+ if (value === undefined || value === null || value === '') continue;
94
+ if (Array.isArray(value) || isPlainObject(value)) continue;
95
+ result[key] = value;
96
+ }
97
+ return result;
98
+ }
99
+
100
+ function normalizeAuthStatus(data = {}) {
101
+ return compactRecord({
102
+ configured: data.loginState === '已配置',
103
+ authType: data.authType,
104
+ accessKey: data.accessKey,
105
+ source: [data.accessKeySource, data.accessKeySourceName].filter(Boolean).join('/'),
106
+ verified: data.verified,
107
+ verification: data.verification,
108
+ verifyCommand: data.verifyCommand,
109
+ userId: data.user?.userId,
110
+ userName: data.user?.userName,
111
+ groupId: data.user?.groupId,
112
+ groupName: data.user?.groupName,
113
+ user: data.user,
114
+ });
115
+ }
116
+
117
+ function normalizeAuthLogin(data = {}) {
118
+ return compactRecord({
119
+ saved: data.saved ?? Boolean(data.auth || data.accessKey),
120
+ verified: data.verified,
121
+ accessKey: data.accessKey || data.auth?.accessKey,
122
+ source: data.auth ? [data.auth.accessKeySource, data.auth.accessKeySourceName].filter(Boolean).join('/') : undefined,
123
+ user: data.user,
124
+ dryRun: data.dryRun,
125
+ });
126
+ }
127
+
128
+ function normalizeDryRunResult(row = {}) {
129
+ if (!isPlainObject(row) || !row.dryRun) return cleanNested(row);
130
+ const localFiles = Array.isArray(row.localFiles) ? row.localFiles : (row.localFile ? [row.localFile] : []);
131
+ return compactRecord({
132
+ ...scalarDataSummary(row),
133
+ ...scalarRequestSummary(row.request),
134
+ ...requestSummary(row.request),
135
+ localFileCount: localFiles.length || undefined,
136
+ fileCount: Array.isArray(row.files) ? row.files.length : undefined,
137
+ assetCount: Array.isArray(row.assets) ? row.assets.length : undefined,
138
+ });
139
+ }
140
+
141
+ function normalizeDryRun(data = {}) {
142
+ const localFiles = Array.isArray(data.localFiles) ? data.localFiles : (data.localFile ? [data.localFile] : undefined);
143
+ const resourceConversions = Array.isArray(data.resourceConversions) ? data.resourceConversions : undefined;
144
+ return compactRecord({
145
+ dryRun: true,
146
+ action: data.action,
147
+ ...scalarDataSummary(data),
148
+ ...scalarRequestSummary(data.request),
149
+ ...requestSummary(data.request),
150
+ localFileCount: Array.isArray(localFiles) ? localFiles.length : undefined,
151
+ resourceConversionCount: Array.isArray(resourceConversions) ? resourceConversions.length : undefined,
152
+ resourceConversion: Array.isArray(resourceConversions) && resourceConversions.length === 1
153
+ ? `${resourceConversions[0].resource || 'resource'} ${resourceConversions[0].fromFormat}->${resourceConversions[0].toFormat}`
154
+ : undefined,
155
+ fileCount: Array.isArray(data.files) ? data.files.length : undefined,
156
+ assetCount: Array.isArray(data.assets) ? data.assets.length : undefined,
157
+ files: data.files,
158
+ assets: data.assets,
159
+ localFiles,
160
+ results: Array.isArray(data.results) ? data.results.map((row) => normalizeDryRunResult(row)) : data.results,
161
+ nextRefSubject: data.nextRefSubject,
162
+ });
163
+ }
164
+
165
+ function normalizeTaskSubmission(data = {}) {
166
+ return compactRecord({
167
+ taskId: data.taskId,
168
+ taskType: data.taskType,
169
+ modelGroupCode: data.modelGroupCode,
170
+ projectGroupNo: data.projectGroupNo,
171
+ pointNo: data.pointNo,
172
+ points: data.points ?? data.point ?? data.costPoint ?? data.estimatePoint,
173
+ pointCost: data.pointCost,
174
+ billingPointBalance: data.billingPointBalance ?? data.teamPointBalance,
175
+ billingPointRemainingAfter: data.billingPointRemainingAfter ?? data.teamPointRemainingAfter,
176
+ projectBudgetBalance: data.projectBudgetBalance ?? data.projectPointBalance,
177
+ projectBudgetMax: data.projectBudgetMax ?? data.projectPointMax,
178
+ projectBudgetRemainingAfter: data.projectBudgetRemainingAfter ?? data.projectPointRemainingAfter,
179
+ uploadCount: Array.isArray(data.uploads) ? data.uploads.length : undefined,
180
+ nextCommand: rewriteCommandPrefix(data.nextCommand),
181
+ waited: data.waited ? normalizeTaskStatus(data.waited) : undefined,
182
+ });
183
+ }
184
+
185
+ function normalizeSubtitleSubmission(data = {}) {
186
+ return compactRecord({
187
+ submitted: data.submitted,
188
+ remoteTaskId: data.remoteTaskId,
189
+ publicId: data.publicId,
190
+ });
191
+ }
192
+
193
+ function normalizeFee(data = {}) {
194
+ return compactRecord({
195
+ modelGroupCode: data.modelGroupCode,
196
+ projectGroupNo: data.projectGroupNo,
197
+ pointCost: data.pointCost,
198
+ billingPointBalance: data.billingPointBalance ?? data.teamPointBalance,
199
+ billingPointRemainingAfter: data.billingPointRemainingAfter ?? data.teamPointRemainingAfter,
200
+ projectBudgetBalance: data.projectBudgetBalance ?? data.projectPointBalance,
201
+ projectBudgetMax: data.projectBudgetMax ?? data.projectPointMax,
202
+ projectBudgetRemainingAfter: data.projectBudgetRemainingAfter ?? data.projectPointRemainingAfter,
203
+ });
204
+ }
205
+
206
+ function normalizeAccountInfo(data = {}) {
207
+ return compactRecord({
208
+ userId: data.userId,
209
+ userName: data.userName,
210
+ groupId: data.groupId,
211
+ groupName: data.groupName,
212
+ currentProjectGroupNo: data.currentProjectGroupNo,
213
+ currentProjectGroupName: data.currentProjectGroupName,
214
+ billingPointBalance: data.billingPointBalance ?? data.teamPointBalance,
215
+ projectBudgetBalance: data.projectBudgetBalance ?? data.projectPointBalance,
216
+ projectBudgetMax: data.projectBudgetMax ?? data.projectPointMax,
217
+ });
218
+ }
219
+
220
+ function normalizeCredits(data = {}) {
221
+ return compactRecord({
222
+ billingPointBalance: data.billingPointBalance ?? data.teamPointBalance,
223
+ currentProjectGroupNo: data.currentProjectGroupNo,
224
+ currentProjectGroupName: data.currentProjectGroupName,
225
+ projectBudgetBalance: data.projectBudgetBalance ?? data.projectPointBalance,
226
+ projectBudgetMax: data.projectBudgetMax ?? data.projectPointMax,
227
+ });
228
+ }
229
+
230
+ function normalizeProjectSummary(data = {}) {
231
+ return compactRecord({
232
+ selected: data.selected,
233
+ created: data.created,
234
+ updated: data.updated,
235
+ reused: data.reused,
236
+ projectGroupNo: data.projectGroupNo,
237
+ projectGroupName: data.projectGroupName,
238
+ isSelected: data.isSelected,
239
+ projectBudgetBalance: data.projectBudgetBalance ?? data.projectPointBalance,
240
+ projectBudgetMax: data.projectBudgetMax ?? data.projectPointMax,
241
+ memberCount: data.memberCount,
242
+ });
243
+ }
244
+
245
+ function normalizeCreditsUsage(data = {}) {
246
+ const buckets = isPlainObject(data.buckets)
247
+ ? Object.entries(data.buckets).map(([taskType, bucket]) => compactRecord({
248
+ taskType,
249
+ taskCount: bucket?.taskCount,
250
+ successTaskCount: bucket?.successTaskCount,
251
+ resultCount: bucket?.resultCount,
252
+ pointTotal: bucket?.pointTotal,
253
+ }))
254
+ : undefined;
255
+ return compactRecord({
256
+ projectGroupNo: data.projectGroupNo,
257
+ sinceMs: data.sinceMs,
258
+ sinceText: data.sinceText,
259
+ untilMs: data.untilMs,
260
+ untilText: data.untilText,
261
+ scannedTaskCount: data.scannedTaskCount,
262
+ pointTotal: data.pointTotal,
263
+ buckets,
264
+ tasks: data.tasks,
265
+ });
266
+ }
267
+
268
+ function normalizeTaskStatus(data = {}) {
269
+ return compactRecord({
270
+ taskId: data.taskId,
271
+ publicId: data.publicId,
272
+ remoteTaskId: data.remoteTaskId,
273
+ taskType: data.taskType,
274
+ taskStatus: data.taskStatus,
275
+ isTerminal: data.isTerminal,
276
+ modelGroupCode: data.modelGroupCode,
277
+ projectGroupNo: data.projectGroupNo,
278
+ pointNo: data.pointNo,
279
+ gmtCreate: data.gmtCreate,
280
+ resultCount: data.resultCount,
281
+ resultUrls: data.resultUrls,
282
+ originUrls: data.originUrls,
283
+ errorMessage: data.errorMessage,
284
+ timedOut: data.timedOut,
285
+ waitedMs: data.waitedMs,
286
+ });
287
+ }
288
+
289
+ function normalizeSubject(data = {}) {
290
+ return compactRecord({
291
+ created: data.created,
292
+ name: data.name,
293
+ elementId: data.elementId,
294
+ subjectId: data.subjectId,
295
+ externalId: data.externalId,
296
+ status: data.status,
297
+ nextRefSubject: data.nextRefSubject,
298
+ });
299
+ }
300
+
301
+ function normalizeAsset(data = {}) {
302
+ return compactRecord({
303
+ created: data.created,
304
+ updated: data.updated,
305
+ registered: data.registered,
306
+ groupId: data.groupId,
307
+ assetId: data.assetId,
308
+ name: data.name,
309
+ projectName: data.projectName,
310
+ assetPath: data.assetPath,
311
+ uploadBackendPath: data.upload?.backendPath,
312
+ uploadUrl: data.upload?.url,
313
+ });
314
+ }
315
+
316
+ function normalizeList(data = {}, keys) {
317
+ const key = keys.find((item) => Array.isArray(data[item]));
318
+ if (!key) return cleanNested(data);
319
+ return compactRecord({
320
+ count: data.count ?? data[key].length,
321
+ [key]: data[key],
322
+ ...Object.fromEntries(Object.entries(data).filter(([item]) => ![key, 'raw'].includes(item))),
323
+ });
324
+ }
325
+
326
+ function normalizeArtifactList(commandName, data) {
327
+ if (Array.isArray(data)) {
328
+ return compactRecord({ count: data.length, items: cleanNested(data) });
329
+ }
330
+ if (!isPlainObject(data)) return cleanNested(data);
331
+ const arrayKey = Object.keys(data).find((key) => Array.isArray(data[key]));
332
+ if (arrayKey) {
333
+ return compactRecord({
334
+ count: data.count ?? data[arrayKey].length,
335
+ [arrayKey]: cleanNested(data[arrayKey]),
336
+ ...Object.fromEntries(
337
+ Object.entries(data)
338
+ .filter(([key]) => key !== arrayKey && key !== 'raw')
339
+ .map(([key, value]) => [key, cleanNested(value)]),
340
+ ),
341
+ });
342
+ }
343
+ return cleanNested(data);
344
+ }
345
+
346
+ function normalizeArtifactRecord(data) {
347
+ if (!isPlainObject(data)) return cleanNested(data);
348
+ const out = compactRecord({
349
+ id: data.id,
350
+ projectId: data.projectId,
351
+ rowKind: data.rowKind,
352
+ entityKey: data.entityKey,
353
+ parentKey: data.parentKey,
354
+ sortOrder: data.sortOrder,
355
+ actorKey: data.actorKey,
356
+ propKey: data.propKey,
357
+ locationKey: data.locationKey,
358
+ stateKey: data.stateKey,
359
+ episodeId: data.episodeId,
360
+ sceneId: data.sceneId,
361
+ clipId: data.clipId,
362
+ videoEpisodeId: data.videoEpisodeId,
363
+ status: data.status,
364
+ title: data.title,
365
+ name: data.name,
366
+ displayName: data.displayName,
367
+ description: data.description,
368
+ });
369
+ for (const [key, value] of Object.entries(data)) {
370
+ if (key in out) continue;
371
+ if (Array.isArray(value)) out[`${key}Count`] = value.length;
372
+ else if (!isPlainObject(value)) out[key] = value;
373
+ }
374
+ return cleanNested(out);
375
+ }
376
+
377
+ function normalizeArtifactFull(data) {
378
+ if (!isPlainObject(data)) return cleanNested(data);
379
+ const out = compactRecord({
380
+ projectId: data.projectId,
381
+ id: data.id,
382
+ title: data.title,
383
+ status: data.status,
384
+ });
385
+ for (const [key, value] of Object.entries(data)) {
386
+ if (Array.isArray(value)) out[`${key}Count`] = value.length;
387
+ else if (isPlainObject(value)) {
388
+ const innerKey = Object.keys(value).find((k) => Array.isArray(value[k]));
389
+ if (innerKey) out[`${key}.${innerKey}Count`] = value[innerKey].length;
390
+ } else if (!(key in out)) out[key] = value;
391
+ }
392
+ return out;
393
+ }
394
+
395
+ function normalizeArtifactImport(data = {}) {
396
+ if (!isPlainObject(data)) return cleanNested(data);
397
+ return compactRecord({
398
+ imported: data.imported,
399
+ dryRun: data.dryRun,
400
+ action: data.action,
401
+ projectId: data.projectId,
402
+ sourceFile: data.sourceFile,
403
+ inputDir: data.inputDir,
404
+ inputFile: data.inputFile,
405
+ rowCount: data.rowCount,
406
+ actorCount: data.actorCount,
407
+ propCount: data.propCount,
408
+ locationCount: data.locationCount,
409
+ episodeCount: data.episodeCount,
410
+ sceneCount: data.sceneCount,
411
+ clipCount: data.clipCount,
412
+ batchCount: Array.isArray(data.batch) ? data.batch.length : undefined,
413
+ rowsByKind: data.rowsByKind,
414
+ files: isPlainObject(data.files)
415
+ ? compactRecord({
416
+ actors: data.files.actorsFile,
417
+ props: data.files.propsFile,
418
+ locations: data.files.locationsFile,
419
+ })
420
+ : undefined,
421
+ });
422
+ }
423
+
424
+ function normalizeArtifactWrite(data) {
425
+ if (!isPlainObject(data)) return cleanNested(data);
426
+ return normalizeArtifactRecord(data);
427
+ }
428
+
429
+ function normalizeArtifactDelete(data) {
430
+ if (!isPlainObject(data)) return cleanNested(data);
431
+ return compactRecord({
432
+ deleted: data.deleted ?? true,
433
+ action: data.action,
434
+ projectId: data.projectId,
435
+ key: data.key,
436
+ stateKey: data.stateKey,
437
+ episodeId: data.episodeId,
438
+ sceneId: data.sceneId,
439
+ clipId: data.clipId,
440
+ videoEpisodeId: data.videoEpisodeId,
441
+ rowKind: data.rowKind,
442
+ entityKey: data.entityKey,
443
+ });
444
+ }
445
+
446
+ function normalizeArtifactStatus(data) {
447
+ if (!isPlainObject(data)) return cleanNested(data);
448
+ return compactRecord({
449
+ updated: data.updated ?? true,
450
+ videoEpisodeId: data.videoEpisodeId ?? data.id,
451
+ status: data.status,
452
+ messageCount: Array.isArray(data.messages) ? data.messages.length : undefined,
453
+ });
454
+ }
455
+
456
+ export function normalizeOutputData(commandName, data) {
457
+ if (!isPlainObject(data)) return cleanNested(data);
458
+ switch (commandName) {
459
+ case 'auth status':
460
+ case 'auth verify':
461
+ return normalizeAuthStatus(data);
462
+ case 'auth login':
463
+ return normalizeAuthLogin(data);
464
+ default:
465
+ break;
466
+ }
467
+ if (data.dryRun) return normalizeDryRun(data);
468
+ switch (commandName) {
469
+ case 'image create':
470
+ case 'video create':
471
+ return normalizeTaskSubmission(data);
472
+ case 'video subtitle-remove':
473
+ return normalizeSubtitleSubmission(data);
474
+ case 'image fee':
475
+ case 'video fee':
476
+ return normalizeFee(data);
477
+ case 'account info':
478
+ return normalizeAccountInfo(data);
479
+ case 'credits balance':
480
+ return normalizeCredits(data);
481
+ case 'project current':
482
+ case 'project use':
483
+ case 'project create':
484
+ case 'project update':
485
+ case 'project ensure':
486
+ return normalizeProjectSummary(data);
487
+ case 'credits usage':
488
+ return normalizeCreditsUsage(data);
489
+ case 'image status':
490
+ case 'video status':
491
+ case 'task wait':
492
+ case 'video subtitle-status':
493
+ return normalizeTaskStatus(data);
494
+ case 'subject publish':
495
+ case 'subject wait':
496
+ return normalizeSubject(data);
497
+ case 'asset group-create':
498
+ case 'asset group-update':
499
+ case 'asset register':
500
+ return normalizeAsset(data);
501
+ case 'model image-models':
502
+ case 'model video-models':
503
+ return normalizeList(data, ['models', 'items', 'rows']);
504
+ case 'account teams':
505
+ return normalizeList(data, ['teams']);
506
+ case 'project list':
507
+ return normalizeList(data, ['projectGroups']);
508
+ case 'project users':
509
+ return normalizeList(data, ['users']);
510
+ case 'task list':
511
+ return normalizeList(data, ['tasks']);
512
+ case 'task records':
513
+ return normalizeList(data, ['records']);
514
+ case 'asset groups':
515
+ return normalizeList(data, ['groups']);
516
+ case 'asset match-actor':
517
+ return normalizeList(data, ['matches']);
518
+ case 'subject list':
519
+ return normalizeList(data, ['subjects']);
520
+ default:
521
+ break;
522
+ }
523
+ if (commandName?.startsWith('artifact ')) {
524
+ return normalizeArtifactByCommand(commandName, data);
525
+ }
526
+ return cleanNested(data);
527
+ }
528
+
529
+ const ARTIFACT_LIST_COMMANDS = new Set([
530
+ 'artifact script rows',
531
+ 'artifact script children',
532
+ 'artifact asset actors',
533
+ 'artifact asset props',
534
+ 'artifact asset locations',
535
+ 'artifact video episodes',
536
+ 'artifact video scenes',
537
+ 'artifact video clips',
538
+ 'artifact clip episodes',
539
+ ]);
540
+
541
+ const ARTIFACT_RECORD_COMMANDS = new Set([
542
+ 'artifact script document',
543
+ 'artifact script row',
544
+ 'artifact asset actor',
545
+ 'artifact asset prop',
546
+ 'artifact asset location',
547
+ 'artifact video episode',
548
+ 'artifact video scene',
549
+ 'artifact video clip',
550
+ 'artifact clip episode',
551
+ 'artifact clip episode-by-id',
552
+ ]);
553
+
554
+ const ARTIFACT_FULL_COMMANDS = new Set([
555
+ 'artifact script get',
556
+ 'artifact asset get',
557
+ 'artifact video get',
558
+ 'artifact clip get',
559
+ ]);
560
+
561
+ const ARTIFACT_IMPORT_COMMANDS = new Set([
562
+ 'artifact script import',
563
+ 'artifact asset import',
564
+ 'artifact video import-storyboard',
565
+ 'artifact clip upsert-batch',
566
+ ]);
567
+
568
+ const ARTIFACT_WRITE_COMMANDS = new Set([
569
+ 'artifact script upsert-row',
570
+ 'artifact asset upsert-actor',
571
+ 'artifact asset upsert-prop',
572
+ 'artifact asset upsert-location',
573
+ 'artifact asset upsert-actor-state',
574
+ 'artifact asset upsert-prop-state',
575
+ 'artifact asset upsert-location-state',
576
+ 'artifact video upsert-episode',
577
+ 'artifact video upsert-scene',
578
+ 'artifact video upsert-clip',
579
+ 'artifact video update-clip-urls',
580
+ 'artifact clip upsert-episode',
581
+ ]);
582
+
583
+ const ARTIFACT_DELETE_COMMANDS = new Set([
584
+ 'artifact script delete-row',
585
+ 'artifact asset delete-actor',
586
+ 'artifact asset delete-prop',
587
+ 'artifact asset delete-location',
588
+ 'artifact asset delete-actor-state',
589
+ 'artifact asset delete-prop-state',
590
+ 'artifact asset delete-location-state',
591
+ 'artifact video delete-episode',
592
+ 'artifact video delete-scene',
593
+ 'artifact video delete-clip',
594
+ 'artifact clip delete-episode',
595
+ ]);
596
+
597
+ function normalizeArtifactByCommand(commandName, data) {
598
+ if (ARTIFACT_LIST_COMMANDS.has(commandName)) return normalizeArtifactList(commandName, data);
599
+ if (ARTIFACT_RECORD_COMMANDS.has(commandName)) return normalizeArtifactRecord(data);
600
+ if (ARTIFACT_FULL_COMMANDS.has(commandName)) return normalizeArtifactFull(data);
601
+ if (ARTIFACT_IMPORT_COMMANDS.has(commandName)) return normalizeArtifactImport(data);
602
+ if (ARTIFACT_WRITE_COMMANDS.has(commandName)) return normalizeArtifactWrite(data);
603
+ if (ARTIFACT_DELETE_COMMANDS.has(commandName)) return normalizeArtifactDelete(data);
604
+ if (commandName === 'artifact clip update-status') return normalizeArtifactStatus(data);
605
+ return cleanNested(data);
606
+ }
607
+
608
+ export function normalizeJsonData(commandName, data) {
609
+ if (!isPlainObject(data)) return rewriteNested(data);
610
+ if (data.dryRun) return rewriteNested(data);
611
+ return normalizeOutputData(commandName, data);
612
+ }
613
+
614
+ function shortValue(value) {
615
+ if (Array.isArray(value)) {
616
+ if (value.every((item) => !isPlainObject(item) && !Array.isArray(item))) return valueList(value, 8) || '[]';
617
+ return `[${value.length}]`;
618
+ }
619
+ if (isPlainObject(value)) return '{...}';
620
+ const text = String(value);
621
+ if (/\s/.test(text)) return JSON.stringify(text.length > 96 ? `${text.slice(0, 93)}...` : text);
622
+ return text.length > 120 ? `${text.slice(0, 117)}...` : text;
623
+ }
624
+
625
+ function valueList(values, limit = 12) {
626
+ if (!Array.isArray(values) || !values.length) return undefined;
627
+ const items = values
628
+ .map((item) => {
629
+ if (!isPlainObject(item)) return item;
630
+ return item.enumValue ?? item.value ?? item.label ?? item.enumName ?? item.name;
631
+ })
632
+ .filter((item) => item !== undefined && item !== null && item !== '');
633
+ if (!items.length) return undefined;
634
+ const visible = items.slice(0, limit).join('|');
635
+ return items.length > limit ? `${visible}|...(+${items.length - limit})` : visible;
636
+ }
637
+
638
+ function renderRecord(record, preferredKeys = [], excludedKeys = []) {
639
+ const excluded = new Set(excludedKeys);
640
+ const keys = [
641
+ ...preferredKeys.filter((key) => !excluded.has(key) && record[key] !== undefined),
642
+ ...Object.keys(record).filter((key) => !excluded.has(key) && !preferredKeys.includes(key) && !Array.isArray(record[key]) && !isPlainObject(record[key])),
643
+ ];
644
+ return keys.map((key) => `${key}=${shortValue(record[key])}`).join(' ');
645
+ }
646
+
647
+ function firstList(data) {
648
+ for (const [key, value] of Object.entries(data || {})) {
649
+ if (['resultUrls', 'originUrls'].includes(key)) continue;
650
+ if (Array.isArray(value)) return { key, rows: value };
651
+ }
652
+ return null;
653
+ }
654
+
655
+ function rowSummary(row) {
656
+ if (!isPlainObject(row)) return shortValue(row);
657
+ const keys = [
658
+ 'id',
659
+ 'taskId',
660
+ 'publicId',
661
+ 'remoteTaskId',
662
+ 'taskType',
663
+ 'modelGroupCode',
664
+ 'provider',
665
+ 'displayName',
666
+ 'modelStatus',
667
+ 'taskQueueNum',
668
+ 'feeCalcType',
669
+ 'inputModes',
670
+ 'params',
671
+ 'name',
672
+ 'status',
673
+ 'message',
674
+ 'title',
675
+ 'description',
676
+ 'groupId',
677
+ 'groupName',
678
+ 'projectGroupNo',
679
+ 'projectGroupName',
680
+ 'projectId',
681
+ 'isSelected',
682
+ 'userId',
683
+ 'userName',
684
+ 'role',
685
+ 'isCheck',
686
+ 'currentGroup',
687
+ 'dryRun',
688
+ 'action',
689
+ 'created',
690
+ 'updated',
691
+ 'registered',
692
+ 'imported',
693
+ 'submitted',
694
+ 'selected',
695
+ 'reused',
696
+ 'cleared',
697
+ 'memberCount',
698
+ 'taskStatus',
699
+ 'taskCount',
700
+ 'successTaskCount',
701
+ 'pointTotal',
702
+ 'billingPointBalance',
703
+ 'billingPointRemainingAfter',
704
+ 'projectBudgetBalance',
705
+ 'projectBudgetMax',
706
+ 'projectBudgetRemainingAfter',
707
+ 'projectPointBalance',
708
+ 'projectPointMax',
709
+ 'teamPointBalance',
710
+ 'assetId',
711
+ 'assetKind',
712
+ 'assetKey',
713
+ 'assetName',
714
+ 'actorKey',
715
+ 'propKey',
716
+ 'locationKey',
717
+ 'stateKey',
718
+ 'stateName',
719
+ 'partType',
720
+ 'score',
721
+ 'imageUrl',
722
+ 'subjectId',
723
+ 'elementId',
724
+ 'externalId',
725
+ 'label',
726
+ 'assetPath',
727
+ 'isPrimary',
728
+ 'referenceType',
729
+ 'resultCount',
730
+ 'promptSummary',
731
+ 'recordedAt',
732
+ 'gmtCreate',
733
+ 'gmtModified',
734
+ 'createdAt',
735
+ 'filePath',
736
+ 'fileName',
737
+ 'exists',
738
+ 'size',
739
+ 'mime',
740
+ 'mimeType',
741
+ 'width',
742
+ 'height',
743
+ 'format',
744
+ 'backendPath',
745
+ 'url',
746
+ 'sceneType',
747
+ 'projectName',
748
+ 'inputIndex',
749
+ 'rowKind',
750
+ 'entityKey',
751
+ 'parentKey',
752
+ 'revisionNo',
753
+ 'sortOrder',
754
+ 'schemaVersion',
755
+ 'speakerKey',
756
+ 'episodeKey',
757
+ 'episodeId',
758
+ 'episodeNo',
759
+ 'episodeTitle',
760
+ 'sceneKey',
761
+ 'sceneId',
762
+ 'sceneNo',
763
+ 'clipId',
764
+ 'expectedDuration',
765
+ 'completePrompt',
766
+ 'key',
767
+ 'sourceFile',
768
+ 'inputDir',
769
+ 'rowCount',
770
+ 'actorCount',
771
+ 'propCount',
772
+ 'locationCount',
773
+ 'sceneCount',
774
+ 'clipCount',
775
+ 'requestSource',
776
+ 'prompt',
777
+ 'ratio',
778
+ 'quality',
779
+ 'duration',
780
+ 'needAudio',
781
+ 'generateNum',
782
+ 'resourceCount',
783
+ 'paramKey',
784
+ 'cliArg',
785
+ 'paramName',
786
+ 'paramType',
787
+ 'meaning',
788
+ ];
789
+ return keys
790
+ .filter((key) => {
791
+ const value = row[key];
792
+ if (value === undefined || value === null || value === '') return false;
793
+ if (Array.isArray(value) && value.length === 0) return false;
794
+ return true;
795
+ })
796
+ .map((key) => `${key}=${shortValue(row[key])}`)
797
+ .join(' ');
798
+ }
799
+
800
+ function textSources(values = []) {
801
+ const names = {
802
+ local_file: 'file',
803
+ http_url: 'url',
804
+ backendPath: 'platformPath',
805
+ asset_id: 'asset',
806
+ };
807
+ return valueList((Array.isArray(values) ? values : []).map((item) => names[item] || item));
808
+ }
809
+
810
+ function textFileCount(item = {}) {
811
+ if (item.minFiles != null && item.maxFiles != null && item.minFiles === item.maxFiles) return String(item.maxFiles);
812
+ if (item.minFiles != null && item.maxFiles != null) return `${item.minFiles}..${item.maxFiles}`;
813
+ if (item.maxFiles != null) return `<=${item.maxFiles}`;
814
+ if (item.minFiles != null) return `>=${item.minFiles}`;
815
+ return undefined;
816
+ }
817
+
818
+ function textDurationRange(item = {}) {
819
+ if (item.minDurationMs != null && item.maxDurationMs != null) return `${item.minDurationMs}..${item.maxDurationMs}`;
820
+ if (item.maxDurationMs != null) return `<=${item.maxDurationMs}`;
821
+ if (item.minDurationMs != null) return `>=${item.minDurationMs}`;
822
+ return undefined;
823
+ }
824
+
825
+ function textItemCount(item = {}) {
826
+ if (item.minItems != null && item.maxItems != null && item.minItems === item.maxItems) return String(item.maxItems);
827
+ if (item.minItems != null && item.maxItems != null) return `${item.minItems}..${item.maxItems}`;
828
+ if (item.maxItems != null) return `<=${item.maxItems}`;
829
+ if (item.minItems != null) return `>=${item.minItems}`;
830
+ return undefined;
831
+ }
832
+
833
+ function textAllowValues(values = []) {
834
+ return Array.isArray(values) && values.length ? valueList(values) : '<none>';
835
+ }
836
+
837
+ function textConditionValue(value) {
838
+ if (value === '__NOT_EMPTY__') return 'present';
839
+ if (value === '__EMPTY__') return 'empty';
840
+ return value;
841
+ }
842
+
843
+ function textConstraintConditions(conditions = []) {
844
+ if (!Array.isArray(conditions) || !conditions.length) return undefined;
845
+ return conditions
846
+ .map((item) => {
847
+ const key = item.key || item.configCode;
848
+ return key ? `${key}=${textConditionValue(item.value)}` : null;
849
+ })
850
+ .filter(Boolean)
851
+ .join('&');
852
+ }
853
+
854
+ const NORMAL_IMAGE_FORMATS = ['jpg', 'jpeg', 'png', 'jfif'];
855
+
856
+ function textImageFormats(item = {}) {
857
+ const policy = String(item.formatPolicy || '');
858
+ if (policy === 'normal_plus_webp') return valueList([...NORMAL_IMAGE_FORMATS, 'webp']);
859
+ if (policy === 'normal_without_webp') return valueList(NORMAL_IMAGE_FORMATS);
860
+ return valueList(item.fileTypes);
861
+ }
862
+
863
+ function textResourceFormats(item = {}) {
864
+ if (item.mediaType === 'IMAGE') return textImageFormats(item);
865
+ return valueList(item.fileTypes);
866
+ }
867
+
868
+ function textWebpInput(item = {}) {
869
+ if (item.mediaType !== 'IMAGE') return undefined;
870
+ const policy = String(item.formatPolicy || '');
871
+ if (policy === 'normal_plus_webp') return 'accepted';
872
+ if (policy === 'normal_without_webp') return item.autoConvertTo ? `autoConvertTo${String(item.autoConvertTo).toUpperCase()}` : 'unsupported';
873
+ return undefined;
874
+ }
875
+
876
+ function textResourceAutoConvert(item = {}) {
877
+ if (item.mediaType === 'IMAGE' && ['normal_plus_webp', 'normal_without_webp'].includes(String(item.formatPolicy || ''))) return undefined;
878
+ return item.autoConvertTo;
879
+ }
880
+
881
+ function formatModelOptionsOutput(data = {}) {
882
+ const params = Array.isArray(data.params) ? data.params : [];
883
+ const resources = Array.isArray(data.resources) ? data.resources : [];
884
+ const constraints = Array.isArray(data.constraints) ? data.constraints : [];
885
+ const lines = ['ok model options'];
886
+ lines.push(renderRecord(compactRecord({
887
+ modelGroupCode: data.modelGroupCode,
888
+ taskKind: data.taskKind,
889
+ }), ['modelGroupCode', 'taskKind']));
890
+ lines.push(`params.count=${params.length}`);
891
+ for (const [index, param] of params.entries()) {
892
+ lines.push(`param[${index}]: ${renderRecord(compactRecord({
893
+ key: param.key,
894
+ type: param.valueType,
895
+ values: valueList(param.values),
896
+ default: param.defaultValue,
897
+ maxLength: param.maxLength,
898
+ required: param.required,
899
+ }), ['key', 'type', 'values', 'default', 'maxLength', 'required'])}`);
900
+ }
901
+ if (resources.length) {
902
+ lines.push(`resources.count=${resources.length}`);
903
+ for (const [index, item] of resources.entries()) {
904
+ lines.push(`resource[${index}]: ${renderRecord(compactRecord({
905
+ mode: item.mode,
906
+ media: item.mediaType,
907
+ usage: item.usage,
908
+ sources: textSources(item.sources),
909
+ formats: textResourceFormats(item),
910
+ webpInput: textWebpInput(item),
911
+ autoConvert: textResourceAutoConvert(item),
912
+ files: textFileCount(item),
913
+ maxSizeKB: item.maxSizeKB,
914
+ durationMs: textDurationRange(item),
915
+ totalDurationMs: item.maxTotalDurationMs != null ? `<=${item.maxTotalDurationMs}` : undefined,
916
+ items: textItemCount(item),
917
+ maxPromptLength: item.maxPromptLength,
918
+ lastFrameOnly: item.supportLastFrameOnly,
919
+ }), [
920
+ 'mode',
921
+ 'media',
922
+ 'usage',
923
+ 'sources',
924
+ 'formats',
925
+ 'webpInput',
926
+ 'autoConvert',
927
+ 'files',
928
+ 'maxSizeKB',
929
+ 'durationMs',
930
+ 'totalDurationMs',
931
+ 'items',
932
+ 'maxPromptLength',
933
+ 'lastFrameOnly',
934
+ ])}`);
935
+ }
936
+ }
937
+ if (constraints.length) {
938
+ lines.push(`constraints.count=${constraints.length}`);
939
+ for (const [index, item] of constraints.entries()) {
940
+ lines.push(`constraint[${index}]: ${renderRecord(compactRecord({
941
+ target: item.target,
942
+ targetConfig: item.targetConfigCode && item.targetConfigCode !== item.target ? item.targetConfigCode : undefined,
943
+ allowedValues: textAllowValues(item.allowValues),
944
+ when: textConstraintConditions(item.conditions),
945
+ effect: item.effect,
946
+ priority: item.priority,
947
+ name: item.name,
948
+ }), ['target', 'targetConfig', 'allowedValues', 'when', 'effect', 'priority', 'name'])}`);
949
+ }
950
+ }
951
+ return `${lines.join('\n')}\n`;
952
+ }
953
+
954
+ function textKeyBinding(value) {
955
+ if (value === 'key_required') return 'required';
956
+ if (value === 'optional_key') return 'optional';
957
+ if (value === 'none') return 'none';
958
+ return value;
959
+ }
960
+
961
+ function formatModelCreateSpecOutput(data = {}) {
962
+ const intents = Array.isArray(data.supportedIntents) ? data.supportedIntents : [];
963
+ const examples = Array.isArray(data.examples) ? data.examples : [];
964
+ const lines = ['ok model create-spec'];
965
+ lines.push(renderRecord(compactRecord({
966
+ modelGroupCode: data.modelGroupCode,
967
+ taskKind: data.taskKind,
968
+ create: data.createCommand,
969
+ fee: data.feeCommand,
970
+ statusTaskType: data.statusCommandTaskType,
971
+ }), ['modelGroupCode', 'taskKind', 'create', 'fee', 'statusTaskType']));
972
+ lines.push(renderRecord(compactRecord({
973
+ input: data.inputRequirement?.summary,
974
+ acceptedModes: valueList(data.inputRequirement?.acceptedModes),
975
+ }), ['input', 'acceptedModes']));
976
+ lines.push(`intents.count=${intents.length}`);
977
+ for (const [index, intent] of intents.entries()) {
978
+ lines.push(`intent[${index}]: ${renderRecord(compactRecord({
979
+ mode: intent.mode,
980
+ intent: intent.intent,
981
+ args: valueList(intent.requiredArgs),
982
+ usage: valueList(intent.resourceUsages),
983
+ resources: valueList(intent.resourceSyntax),
984
+ key: textKeyBinding(intent.promptBinding),
985
+ }), ['mode', 'intent', 'args', 'usage', 'resources', 'key'])}`);
986
+ }
987
+ if (examples.length) {
988
+ lines.push(`examples.count=${examples.length}`);
989
+ for (const [index, example] of examples.entries()) lines.push(`example[${index}]=${example}`);
990
+ }
991
+ if (data.optionsCommand) lines.push(`options=${commandPrefix()} ${data.optionsCommand}`);
992
+ return `${lines.join('\n')}\n`;
993
+ }
994
+
995
+ function formatGuideTableRows(rows = []) {
996
+ return (Array.isArray(rows) ? rows : []).map((item, index) => {
997
+ const values = valueList(item.values);
998
+ return `field[${index}]: ${renderRecord(compactRecord({
999
+ name: item.field,
1000
+ values,
1001
+ desc: item.description,
1002
+ }), ['name', 'values', 'desc'])}`;
1003
+ });
1004
+ }
1005
+
1006
+ function formatModelInputGuideOutput(data = {}) {
1007
+ const lines = ['ok model input-guide'];
1008
+ lines.push('commonFields.count=' + (Array.isArray(data.commonFields) ? data.commonFields.length : 0));
1009
+ lines.push(...formatGuideTableRows(data.commonFields));
1010
+ lines.push('resourceFields.count=' + (Array.isArray(data.resourceFields) ? data.resourceFields.length : 0));
1011
+ lines.push(...formatGuideTableRows(data.resourceFields));
1012
+ const rules = Array.isArray(data.resourceRules) ? data.resourceRules : [];
1013
+ if (rules.length) {
1014
+ lines.push(`resourceRules.count=${rules.length}`);
1015
+ for (const [index, rule] of rules.entries()) lines.push(`rule[${index}]=${rule}`);
1016
+ }
1017
+ const referenceKeyGuide = Array.isArray(data.referenceKeyGuide) ? data.referenceKeyGuide : [];
1018
+ if (referenceKeyGuide.length) {
1019
+ lines.push(`referenceKey.count=${referenceKeyGuide.length}`);
1020
+ for (const [index, item] of referenceKeyGuide.entries()) lines.push(`referenceKey[${index}]=${item}`);
1021
+ }
1022
+ return `${lines.join('\n')}\n`;
1023
+ }
1024
+
1025
+ function defaultJsonCommand(commandName) {
1026
+ return `${commandPrefix()} ${commandName} -f json`;
1027
+ }
1028
+
1029
+ function modelListNextCommand(commandName) {
1030
+ if (commandName === 'model image-models' || commandName === 'model video-models') {
1031
+ return `${commandPrefix()} model options --model-group-code <modelGroupCode>`;
1032
+ }
1033
+ return null;
1034
+ }
1035
+
1036
+ function statusNextCommand(commandName, normalized) {
1037
+ if (!isPlainObject(normalized) || normalized.isTerminal !== false || !normalized.taskId) return null;
1038
+ const taskType = normalized.taskType || (commandName === 'video status' ? 'VIDEO_GROUP' : 'IMAGE_CREATE');
1039
+ return `${commandPrefix()} task wait --task-id ${normalized.taskId} --task-type ${taskType} --wait-seconds 180`;
1040
+ }
1041
+
1042
+ function subtitleRemoveNextCommand(commandName, normalized) {
1043
+ if (commandName !== 'video status' && commandName !== 'task wait') return null;
1044
+ if (!Array.isArray(normalized.originUrls) || !normalized.originUrls.length) return null;
1045
+ return `${commandPrefix()} video subtitle-remove --video-url <originUrl[0]> --dry-run`;
1046
+ }
1047
+
1048
+ export function formatTextOutput(commandName, data, context = {}) {
1049
+ if (commandName === 'model options') return formatModelOptionsOutput(data);
1050
+ if (commandName === 'model create-spec') return formatModelCreateSpecOutput(data);
1051
+ if (commandName === 'model input-guide') return formatModelInputGuideOutput(data);
1052
+ const normalized = normalizeOutputData(commandName, data);
1053
+ if (!isPlainObject(normalized)) return `ok ${commandName}\nvalue=${shortValue(normalized)}\n`;
1054
+ const lines = [`ok ${commandName}`];
1055
+ const list = firstList(normalized);
1056
+ const isModelList = commandName === 'model image-models' || commandName === 'model video-models';
1057
+ const scalarLine = renderRecord(
1058
+ normalized,
1059
+ [
1060
+ 'configured',
1061
+ 'accessKey',
1062
+ 'verified',
1063
+ 'verification',
1064
+ 'verifyCommand',
1065
+ 'userId',
1066
+ 'userName',
1067
+ 'doctorStatus',
1068
+ 'taskId',
1069
+ 'publicId',
1070
+ 'remoteTaskId',
1071
+ 'pointNo',
1072
+ 'taskType',
1073
+ 'taskStatus',
1074
+ 'modelGroupCode',
1075
+ 'projectGroupNo',
1076
+ 'projectId',
1077
+ 'groupId',
1078
+ 'groupName',
1079
+ 'assetId',
1080
+ 'elementId',
1081
+ 'externalId',
1082
+ 'status',
1083
+ 'imported',
1084
+ 'updated',
1085
+ 'deleted',
1086
+ 'sourceFile',
1087
+ 'inputDir',
1088
+ 'inputFile',
1089
+ 'count',
1090
+ 'rowCount',
1091
+ 'actorCount',
1092
+ 'propCount',
1093
+ 'locationCount',
1094
+ 'episodeCount',
1095
+ 'sceneCount',
1096
+ 'clipCount',
1097
+ 'batchCount',
1098
+ 'id',
1099
+ 'videoEpisodeId',
1100
+ 'episodeId',
1101
+ 'rowKind',
1102
+ 'entityKey',
1103
+ 'parentKey',
1104
+ 'assetKind',
1105
+ 'assetKey',
1106
+ 'actorKey',
1107
+ 'propKey',
1108
+ 'locationKey',
1109
+ 'stateKey',
1110
+ 'sceneId',
1111
+ 'clipId',
1112
+ 'name',
1113
+ 'displayName',
1114
+ 'title',
1115
+ 'resultCount',
1116
+ 'resourceConversionCount',
1117
+ 'resourceConversion',
1118
+ 'pointCost',
1119
+ 'billingPointBalance',
1120
+ 'billingPointRemainingAfter',
1121
+ 'projectBudgetBalance',
1122
+ 'projectBudgetMax',
1123
+ 'projectBudgetRemainingAfter',
1124
+ 'pointTotal',
1125
+ 'dryRun',
1126
+ 'action',
1127
+ ],
1128
+ ['nextCommand', 'nextRefSubject', ...(list ? ['count'] : []), ...(isModelList ? ['usage'] : [])],
1129
+ );
1130
+ if (scalarLine) lines.push(scalarLine);
1131
+ if (list) {
1132
+ const total = list.rows.length;
1133
+ lines.push(`${list.key}.count=${total}`);
1134
+ const configuredLimit = context.listLimit === Number.POSITIVE_INFINITY
1135
+ ? list.rows.length
1136
+ : (Number.isFinite(context.listLimit) ? context.listLimit : 8);
1137
+ const visibleLimit = Math.max(0, configuredLimit);
1138
+ const visibleRows = list.rows.slice(0, visibleLimit);
1139
+ for (const [index, row] of visibleRows.entries()) {
1140
+ const summary = rowSummary(row);
1141
+ if (summary) lines.push(`${list.key}[${index}]: ${summary}`);
1142
+ if (isPlainObject(row) && Array.isArray(row.resultUrls)) {
1143
+ for (const [urlIndex, url] of row.resultUrls.slice(0, 2).entries()) lines.push(`${list.key}[${index}].resultUrl[${urlIndex}]=${url}`);
1144
+ }
1145
+ if (isPlainObject(row) && Array.isArray(row.originUrls)) {
1146
+ for (const [urlIndex, url] of row.originUrls.slice(0, 2).entries()) lines.push(`${list.key}[${index}].originUrl[${urlIndex}]=${url}`);
1147
+ }
1148
+ }
1149
+ if (total > visibleRows.length) {
1150
+ lines.push(`${list.key}.more=${total - visibleRows.length}`);
1151
+ lines.push(`moreCommand=${context.moreCommand || context.jsonCommand || defaultJsonCommand(commandName)}`);
1152
+ }
1153
+ }
1154
+ if (normalized.nextCommand) lines.push(`next=${normalized.nextCommand}`);
1155
+ if (normalized.nextRefSubject) lines.push(`nextRefSubject=${normalized.nextRefSubject}`);
1156
+ if (normalized.dryRun && context.confirmCommand) lines.push(`nextAfterConfirm=${context.confirmCommand}`);
1157
+ if (normalized.dryRun && !context.confirmCommand && context.executeCommand) lines.push(`next=${context.executeCommand}`);
1158
+ const modelNext = modelListNextCommand(commandName);
1159
+ if (modelNext) lines.push(`next=${modelNext}`);
1160
+ const waitNext = statusNextCommand(commandName, normalized);
1161
+ if (waitNext) lines.push(`next=${waitNext}`);
1162
+ const subtitleNext = subtitleRemoveNextCommand(commandName, normalized);
1163
+ if (subtitleNext) lines.push(`nextSubtitleRemove=${subtitleNext}`);
1164
+ if (Array.isArray(normalized.resultUrls)) {
1165
+ for (const [index, url] of normalized.resultUrls.slice(0, 3).entries()) lines.push(`resultUrl[${index}]=${url}`);
1166
+ }
1167
+ if (Array.isArray(normalized.originUrls)) {
1168
+ for (const [index, url] of normalized.originUrls.slice(0, 3).entries()) lines.push(`originUrl[${index}]=${url}`);
1169
+ }
1170
+ return `${lines.join('\n')}\n`;
1171
+ }
1172
+
1173
+ export function formatTextError(error) {
1174
+ const lines = [`error type=${error.type || 'error'}`, `message=${JSON.stringify(error.message || String(error))}`];
1175
+ if (error.hint) lines.push(`hint=${JSON.stringify(rewriteCommandPrefix(error.hint))}`);
1176
+ if (isPlainObject(error.details)) {
1177
+ const payload = isPlainObject(error.details.payload) ? error.details.payload : {};
1178
+ const detailLine = renderRecord(compactRecord({
1179
+ status: error.details.status ?? payload.status,
1180
+ code: error.details.code ?? payload.code,
1181
+ msg: error.details.msg ?? payload.msg ?? payload.message,
1182
+ traceId: error.details.traceId ?? payload.traceId,
1183
+ causeCode: error.details.causeCode,
1184
+ unknownOptions: Array.isArray(error.details.unknownOptions) ? error.details.unknownOptions.join(',') : undefined,
1185
+ }), ['status', 'code', 'msg', 'traceId', 'causeCode', 'unknownOptions']);
1186
+ if (detailLine) lines.push(`details ${detailLine}`);
1187
+ }
1188
+ return `${lines.join('\n')}\n`;
1189
+ }