@ait-co/console-cli 0.1.8 → 0.1.10

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/dist/cli.mjs CHANGED
@@ -204,6 +204,24 @@ async function fetchReviewStatus(workspaceId, cookies, opts = {}) {
204
204
  })
205
205
  };
206
206
  }
207
+ async function fetchMiniAppWithDraft(workspaceId, miniAppId, cookies, opts = {}) {
208
+ const raw = await requestConsoleApi({
209
+ url: `${BASE$2}/workspaces/${workspaceId}/mini-app/${miniAppId}/with-draft`,
210
+ cookies,
211
+ ...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
212
+ });
213
+ if (raw === null || typeof raw !== "object") throw new Error(`Unexpected with-draft shape for mini-app=${miniAppId}`);
214
+ const rec = raw;
215
+ return {
216
+ current: isRecordOrNull(rec.current) ? rec.current : null,
217
+ draft: isRecordOrNull(rec.draft) ? rec.draft : null,
218
+ approvalType: typeof rec.approvalType === "string" ? rec.approvalType : null,
219
+ rejectedMessage: typeof rec.rejectedMessage === "string" ? rec.rejectedMessage : null
220
+ };
221
+ }
222
+ function isRecordOrNull(v) {
223
+ return v === null || typeof v === "object" && !Array.isArray(v);
224
+ }
207
225
  async function createMiniApp(workspaceId, payload, cookies, opts = {}) {
208
226
  return normalizeCreateResult(await requestConsoleApi({
209
227
  url: `${BASE$2}/workspaces/${workspaceId}/mini-app/review`,
@@ -1028,64 +1046,312 @@ function reviewStateFor(entry) {
1028
1046
  const raw = entry.reviewState ?? entry.status;
1029
1047
  return typeof raw === "string" ? raw : void 0;
1030
1048
  }
1049
+ const lsCommand$3 = defineCommand({
1050
+ meta: {
1051
+ name: "ls",
1052
+ description: "List mini-apps in the selected workspace."
1053
+ },
1054
+ args: {
1055
+ workspace: {
1056
+ type: "string",
1057
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
1058
+ },
1059
+ json: {
1060
+ type: "boolean",
1061
+ description: "Emit machine-readable JSON to stdout.",
1062
+ default: false
1063
+ }
1064
+ },
1065
+ async run({ args }) {
1066
+ const ctx = await resolveWorkspaceContext(args);
1067
+ if (!ctx) return;
1068
+ const { session, workspaceId } = ctx;
1069
+ try {
1070
+ const [apps, review] = await Promise.all([fetchMiniApps(workspaceId, session.cookies), fetchReviewStatus(workspaceId, session.cookies)]);
1071
+ if (args.json) {
1072
+ const joined = apps.map((app) => {
1073
+ const reviewState = reviewStateFor(findReviewEntry(review.miniApps, app.id));
1074
+ return {
1075
+ id: app.id,
1076
+ name: app.name ?? null,
1077
+ ...reviewState !== void 0 ? { reviewState } : {},
1078
+ extra: app.extra
1079
+ };
1080
+ });
1081
+ emitJson({
1082
+ ok: true,
1083
+ workspaceId,
1084
+ hasPolicyViolation: review.hasPolicyViolation,
1085
+ apps: joined
1086
+ });
1087
+ return exitAfterFlush(ExitCode.Ok);
1088
+ }
1089
+ if (apps.length === 0) {
1090
+ process.stdout.write(`No apps in workspace ${workspaceId}.\n`);
1091
+ if (review.hasPolicyViolation) process.stderr.write("Note: workspace-wide policy violation flag is set.\n");
1092
+ return exitAfterFlush(ExitCode.Ok);
1093
+ }
1094
+ for (const app of apps) {
1095
+ const reviewState = reviewStateFor(findReviewEntry(review.miniApps, app.id)) ?? "-";
1096
+ const name = app.name ?? "(unnamed)";
1097
+ process.stdout.write(`${app.id}\t${name}\t${reviewState}\n`);
1098
+ }
1099
+ if (review.hasPolicyViolation) process.stderr.write("Note: workspace-wide policy violation flag is set.\n");
1100
+ return exitAfterFlush(ExitCode.Ok);
1101
+ } catch (err) {
1102
+ return emitFailureFromError(args.json, err);
1103
+ }
1104
+ }
1105
+ });
1106
+ function pickMiniAppView(envelope, view) {
1107
+ const extract = (side) => {
1108
+ if (side === null) return null;
1109
+ const ma = side.miniApp;
1110
+ if (ma !== null && typeof ma === "object" && !Array.isArray(ma)) return ma;
1111
+ return null;
1112
+ };
1113
+ const draft = extract(envelope.draft);
1114
+ const current = extract(envelope.current);
1115
+ if (view === "draft") return draft;
1116
+ if (view === "current") return current;
1117
+ if (current !== null && draft !== null) return {
1118
+ ...current,
1119
+ ...draft
1120
+ };
1121
+ return draft ?? current;
1122
+ }
1123
+ function parseAppId(raw) {
1124
+ if (raw === void 0 || raw === "") return null;
1125
+ const n = Number(raw);
1126
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) return null;
1127
+ return n;
1128
+ }
1129
+ const showCommand$1 = defineCommand({
1130
+ meta: {
1131
+ name: "show",
1132
+ description: "Show full details of a mini-app, including fields only visible in the draft view."
1133
+ },
1134
+ args: {
1135
+ id: {
1136
+ type: "positional",
1137
+ description: "Mini-app ID (the numeric `appId` from `app ls` or `app register`).",
1138
+ required: true
1139
+ },
1140
+ workspace: {
1141
+ type: "string",
1142
+ description: "Workspace ID. Defaults to the selected workspace."
1143
+ },
1144
+ view: {
1145
+ type: "string",
1146
+ description: "Which view to render: `draft` (default), `current`, or `merged`.",
1147
+ default: "draft"
1148
+ },
1149
+ json: {
1150
+ type: "boolean",
1151
+ description: "Emit machine-readable JSON to stdout.",
1152
+ default: false
1153
+ }
1154
+ },
1155
+ async run({ args }) {
1156
+ const appId = parseAppId(args.id);
1157
+ if (appId === null) {
1158
+ if (args.json) emitJson({
1159
+ ok: false,
1160
+ reason: "invalid-id",
1161
+ message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
1162
+ });
1163
+ else process.stderr.write(`app show: invalid id ${JSON.stringify(args.id)}\n`);
1164
+ return exitAfterFlush(ExitCode.Usage);
1165
+ }
1166
+ const view = args.view;
1167
+ if (view !== "draft" && view !== "current" && view !== "merged") {
1168
+ if (args.json) emitJson({
1169
+ ok: false,
1170
+ reason: "invalid-config",
1171
+ field: "view",
1172
+ message: `--view must be one of draft|current|merged (got ${JSON.stringify(view)})`
1173
+ });
1174
+ else process.stderr.write(`app show: invalid --view ${JSON.stringify(view)}\n`);
1175
+ return exitAfterFlush(ExitCode.Usage);
1176
+ }
1177
+ const ctx = await resolveWorkspaceContext(args);
1178
+ if (!ctx) return;
1179
+ const { session, workspaceId } = ctx;
1180
+ try {
1181
+ const envelope = await fetchMiniAppWithDraft(workspaceId, appId, session.cookies);
1182
+ const miniApp = pickMiniAppView(envelope, view);
1183
+ if (args.json) {
1184
+ emitJson({
1185
+ ok: true,
1186
+ workspaceId,
1187
+ appId,
1188
+ view,
1189
+ miniApp
1190
+ });
1191
+ return exitAfterFlush(ExitCode.Ok);
1192
+ }
1193
+ if (miniApp === null) {
1194
+ if (view === "current" && envelope.draft !== null) process.stdout.write(`App ${appId} has no \`current\` view yet (not reviewed). Try --view draft.\n`);
1195
+ else process.stdout.write(`App ${appId} has no data for view=${view}.\n`);
1196
+ return exitAfterFlush(ExitCode.Ok);
1197
+ }
1198
+ const pick = (k) => {
1199
+ const v = miniApp[k];
1200
+ return v === null || v === void 0 ? "-" : String(v);
1201
+ };
1202
+ const images = Array.isArray(miniApp.images) ? miniApp.images : [];
1203
+ const impression = miniApp.impression !== null && typeof miniApp.impression === "object" ? miniApp.impression : {};
1204
+ const keywords = Array.isArray(impression.keywordList) ? impression.keywordList : [];
1205
+ const categoryPaths = Array.isArray(impression.categoryPaths) ? impression.categoryPaths : [];
1206
+ process.stdout.write(`# App ${appId} (view=${view})\n\n`);
1207
+ process.stdout.write(`Name (ko) ${pick("title")}\n`);
1208
+ process.stdout.write(`Name (en) ${pick("titleEn")}\n`);
1209
+ process.stdout.write(`App slug ${pick("appName")}\n`);
1210
+ process.stdout.write(`Status ${pick("status")}\n`);
1211
+ process.stdout.write(`Home page ${pick("homePageUri")}\n`);
1212
+ process.stdout.write(`CS email ${pick("csEmail")}\n`);
1213
+ process.stdout.write(`Logo ${pick("iconUri")}\n`);
1214
+ process.stdout.write(`Subtitle ${pick("description")}\n`);
1215
+ const detail = typeof miniApp.detailDescription === "string" ? `${[...miniApp.detailDescription].length} chars` : "-";
1216
+ process.stdout.write(`Detail desc ${detail}\n`);
1217
+ process.stdout.write(`Images ${images.length}\n`);
1218
+ process.stdout.write(`Keywords ${keywords.length} (${keywords.join(", ")})\n`);
1219
+ const firstPath = categoryPaths[0];
1220
+ if (firstPath && typeof firstPath === "object") {
1221
+ const fp = firstPath;
1222
+ const parts = [];
1223
+ for (const key of [
1224
+ "group",
1225
+ "category",
1226
+ "subCategory"
1227
+ ]) {
1228
+ const node = fp[key];
1229
+ if (node !== null && typeof node === "object") {
1230
+ const nm = node.name;
1231
+ if (typeof nm === "string") parts.push(nm);
1232
+ }
1233
+ }
1234
+ process.stdout.write(`Category ${parts.join(" > ") || "-"}\n`);
1235
+ } else process.stdout.write(`Category -\n`);
1236
+ return exitAfterFlush(ExitCode.Ok);
1237
+ } catch (err) {
1238
+ return emitFailureFromError(args.json, err);
1239
+ }
1240
+ }
1241
+ });
1242
+ function deriveReviewState(env) {
1243
+ const hasCurrent = env.current !== null;
1244
+ const hasDraft = env.draft !== null;
1245
+ const approvalType = env.approvalType;
1246
+ const rejectedMessage = env.rejectedMessage;
1247
+ let state;
1248
+ if (approvalType === null) state = "not-submitted";
1249
+ else if (rejectedMessage !== null) state = "rejected";
1250
+ else if (!hasCurrent) state = "under-review";
1251
+ else if (hasDraft) state = "approved-with-edits";
1252
+ else state = "approved";
1253
+ if (approvalType !== null && approvalType !== "REVIEW" && state === "under-review") state = "unknown";
1254
+ return {
1255
+ state,
1256
+ approvalType,
1257
+ rejectedMessage,
1258
+ hasCurrent,
1259
+ hasDraft
1260
+ };
1261
+ }
1262
+ const POLL_MIN_INTERVAL_SEC = 30;
1263
+ const POLL_MAX_INTERVAL_SEC = 3600;
1031
1264
  const appCommand = defineCommand({
1032
1265
  meta: {
1033
1266
  name: "app",
1034
1267
  description: "Inspect mini-apps in a workspace."
1035
1268
  },
1036
1269
  subCommands: {
1037
- ls: defineCommand({
1270
+ ls: lsCommand$3,
1271
+ show: showCommand$1,
1272
+ status: defineCommand({
1038
1273
  meta: {
1039
- name: "ls",
1040
- description: "List mini-apps in the selected workspace."
1274
+ name: "status",
1275
+ description: "Show the derived review state of a mini-app (under-review / rejected / approved)."
1041
1276
  },
1042
1277
  args: {
1278
+ id: {
1279
+ type: "positional",
1280
+ description: "Mini-app ID.",
1281
+ required: true
1282
+ },
1043
1283
  workspace: {
1044
1284
  type: "string",
1045
- description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
1285
+ description: "Workspace ID. Defaults to the selected workspace."
1286
+ },
1287
+ watch: {
1288
+ type: "boolean",
1289
+ description: "Poll until the review state flips off `under-review` (rejected or approved). Combine with `--interval <seconds>`.",
1290
+ default: false
1291
+ },
1292
+ interval: {
1293
+ type: "string",
1294
+ description: "Polling interval in seconds when --watch is set. Clamped to [30, 3600].",
1295
+ default: "60"
1046
1296
  },
1047
1297
  json: {
1048
1298
  type: "boolean",
1049
- description: "Emit machine-readable JSON to stdout.",
1299
+ description: "Emit machine-readable JSON.",
1050
1300
  default: false
1051
1301
  }
1052
1302
  },
1053
1303
  async run({ args }) {
1304
+ const appId = parseAppId(args.id);
1305
+ if (appId === null) {
1306
+ if (args.json) emitJson({
1307
+ ok: false,
1308
+ reason: "invalid-id",
1309
+ message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
1310
+ });
1311
+ else process.stderr.write(`app status: invalid id ${JSON.stringify(args.id)}\n`);
1312
+ return exitAfterFlush(ExitCode.Usage);
1313
+ }
1314
+ const intervalRaw = Number(args.interval);
1315
+ if (!Number.isFinite(intervalRaw) || intervalRaw <= 0) {
1316
+ if (args.json) emitJson({
1317
+ ok: false,
1318
+ reason: "invalid-config",
1319
+ field: "interval",
1320
+ message: `--interval must be a positive number (got ${JSON.stringify(args.interval)})`
1321
+ });
1322
+ else process.stderr.write(`app status: invalid --interval ${JSON.stringify(args.interval)}\n`);
1323
+ return exitAfterFlush(ExitCode.Usage);
1324
+ }
1325
+ const intervalSec = Math.max(POLL_MIN_INTERVAL_SEC, Math.min(POLL_MAX_INTERVAL_SEC, Math.floor(intervalRaw)));
1054
1326
  const ctx = await resolveWorkspaceContext(args);
1055
1327
  if (!ctx) return;
1056
1328
  const { session, workspaceId } = ctx;
1329
+ const emit = (status) => {
1330
+ if (args.json) emitJson({
1331
+ ok: true,
1332
+ workspaceId,
1333
+ appId,
1334
+ ...status
1335
+ });
1336
+ else process.stdout.write(`App ${appId} (ws ${workspaceId}): ${status.state}` + (status.rejectedMessage ? `\n reason: ${status.rejectedMessage}` : "") + "\n");
1337
+ };
1057
1338
  try {
1058
- const [apps, review] = await Promise.all([fetchMiniApps(workspaceId, session.cookies), fetchReviewStatus(workspaceId, session.cookies)]);
1059
- if (args.json) {
1060
- const joined = apps.map((app) => {
1061
- const reviewState = reviewStateFor(findReviewEntry(review.miniApps, app.id));
1062
- return {
1063
- id: app.id,
1064
- name: app.name ?? null,
1065
- ...reviewState !== void 0 ? { reviewState } : {},
1066
- extra: app.extra
1067
- };
1068
- });
1069
- emitJson({
1070
- ok: true,
1071
- workspaceId,
1072
- hasPolicyViolation: review.hasPolicyViolation,
1073
- apps: joined
1074
- });
1339
+ const once = async () => {
1340
+ return deriveReviewState(await fetchMiniAppWithDraft(workspaceId, appId, session.cookies));
1341
+ };
1342
+ if (!args.watch) {
1343
+ emit(await once());
1075
1344
  return exitAfterFlush(ExitCode.Ok);
1076
1345
  }
1077
- if (apps.length === 0) {
1078
- process.stdout.write(`No apps in workspace ${workspaceId}.\n`);
1079
- if (review.hasPolicyViolation) process.stderr.write("Note: workspace-wide policy violation flag is set.\n");
1080
- return exitAfterFlush(ExitCode.Ok);
1081
- }
1082
- for (const app of apps) {
1083
- const reviewState = reviewStateFor(findReviewEntry(review.miniApps, app.id)) ?? "-";
1084
- const name = app.name ?? "(unnamed)";
1085
- process.stdout.write(`${app.id}\t${name}\t${reviewState}\n`);
1346
+ let lastState = null;
1347
+ while (true) {
1348
+ const status = await once();
1349
+ if (args.json) emit(status);
1350
+ else if (status.state !== lastState) emit(status);
1351
+ lastState = status.state;
1352
+ if (status.state !== "under-review") return exitAfterFlush(ExitCode.Ok);
1353
+ await new Promise((resolve) => setTimeout(resolve, intervalSec * 1e3));
1086
1354
  }
1087
- if (review.hasPolicyViolation) process.stderr.write("Note: workspace-wide policy violation flag is set.\n");
1088
- return exitAfterFlush(ExitCode.Ok);
1089
1355
  } catch (err) {
1090
1356
  return emitFailureFromError(args.json, err);
1091
1357
  }
@@ -2082,7 +2348,7 @@ function resolveVersion() {
2082
2348
  if (typeof injected === "string" && injected.length > 0) return injected;
2083
2349
  } catch {}
2084
2350
  try {
2085
- return "0.1.8";
2351
+ return "0.1.10";
2086
2352
  } catch {}
2087
2353
  return "0.0.0-dev";
2088
2354
  }