@ait-co/console-cli 0.1.9 → 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
@@ -214,7 +214,9 @@ async function fetchMiniAppWithDraft(workspaceId, miniAppId, cookies, opts = {})
214
214
  const rec = raw;
215
215
  return {
216
216
  current: isRecordOrNull(rec.current) ? rec.current : null,
217
- draft: isRecordOrNull(rec.draft) ? rec.draft : 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
218
220
  };
219
221
  }
220
222
  function isRecordOrNull(v) {
@@ -1124,6 +1126,141 @@ function parseAppId(raw) {
1124
1126
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) return null;
1125
1127
  return n;
1126
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;
1127
1264
  const appCommand = defineCommand({
1128
1265
  meta: {
1129
1266
  name: "app",
@@ -1131,29 +1268,35 @@ const appCommand = defineCommand({
1131
1268
  },
1132
1269
  subCommands: {
1133
1270
  ls: lsCommand$3,
1134
- show: defineCommand({
1271
+ show: showCommand$1,
1272
+ status: defineCommand({
1135
1273
  meta: {
1136
- name: "show",
1137
- description: "Show full details of a mini-app, including fields only visible in the draft view."
1274
+ name: "status",
1275
+ description: "Show the derived review state of a mini-app (under-review / rejected / approved)."
1138
1276
  },
1139
1277
  args: {
1140
1278
  id: {
1141
1279
  type: "positional",
1142
- description: "Mini-app ID (the numeric `appId` from `app ls` or `app register`).",
1280
+ description: "Mini-app ID.",
1143
1281
  required: true
1144
1282
  },
1145
1283
  workspace: {
1146
1284
  type: "string",
1147
1285
  description: "Workspace ID. Defaults to the selected workspace."
1148
1286
  },
1149
- view: {
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: {
1150
1293
  type: "string",
1151
- description: "Which view to render: `draft` (default), `current`, or `merged`.",
1152
- default: "draft"
1294
+ description: "Polling interval in seconds when --watch is set. Clamped to [30, 3600].",
1295
+ default: "60"
1153
1296
  },
1154
1297
  json: {
1155
1298
  type: "boolean",
1156
- description: "Emit machine-readable JSON to stdout.",
1299
+ description: "Emit machine-readable JSON.",
1157
1300
  default: false
1158
1301
  }
1159
1302
  },
@@ -1165,80 +1308,50 @@ const appCommand = defineCommand({
1165
1308
  reason: "invalid-id",
1166
1309
  message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
1167
1310
  });
1168
- else process.stderr.write(`app show: invalid id ${JSON.stringify(args.id)}\n`);
1311
+ else process.stderr.write(`app status: invalid id ${JSON.stringify(args.id)}\n`);
1169
1312
  return exitAfterFlush(ExitCode.Usage);
1170
1313
  }
1171
- const view = args.view;
1172
- if (view !== "draft" && view !== "current" && view !== "merged") {
1314
+ const intervalRaw = Number(args.interval);
1315
+ if (!Number.isFinite(intervalRaw) || intervalRaw <= 0) {
1173
1316
  if (args.json) emitJson({
1174
1317
  ok: false,
1175
1318
  reason: "invalid-config",
1176
- field: "view",
1177
- message: `--view must be one of draft|current|merged (got ${JSON.stringify(view)})`
1319
+ field: "interval",
1320
+ message: `--interval must be a positive number (got ${JSON.stringify(args.interval)})`
1178
1321
  });
1179
- else process.stderr.write(`app show: invalid --view ${JSON.stringify(view)}\n`);
1322
+ else process.stderr.write(`app status: invalid --interval ${JSON.stringify(args.interval)}\n`);
1180
1323
  return exitAfterFlush(ExitCode.Usage);
1181
1324
  }
1325
+ const intervalSec = Math.max(POLL_MIN_INTERVAL_SEC, Math.min(POLL_MAX_INTERVAL_SEC, Math.floor(intervalRaw)));
1182
1326
  const ctx = await resolveWorkspaceContext(args);
1183
1327
  if (!ctx) return;
1184
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
+ };
1185
1338
  try {
1186
- const envelope = await fetchMiniAppWithDraft(workspaceId, appId, session.cookies);
1187
- const miniApp = pickMiniAppView(envelope, view);
1188
- if (args.json) {
1189
- emitJson({
1190
- ok: true,
1191
- workspaceId,
1192
- appId,
1193
- view,
1194
- miniApp
1195
- });
1339
+ const once = async () => {
1340
+ return deriveReviewState(await fetchMiniAppWithDraft(workspaceId, appId, session.cookies));
1341
+ };
1342
+ if (!args.watch) {
1343
+ emit(await once());
1196
1344
  return exitAfterFlush(ExitCode.Ok);
1197
1345
  }
1198
- if (miniApp === null) {
1199
- if (view === "current" && envelope.draft !== null) process.stdout.write(`App ${appId} has no \`current\` view yet (not reviewed). Try --view draft.\n`);
1200
- else process.stdout.write(`App ${appId} has no data for view=${view}.\n`);
1201
- return exitAfterFlush(ExitCode.Ok);
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));
1202
1354
  }
1203
- const pick = (k) => {
1204
- const v = miniApp[k];
1205
- return v === null || v === void 0 ? "-" : String(v);
1206
- };
1207
- const images = Array.isArray(miniApp.images) ? miniApp.images : [];
1208
- const impression = miniApp.impression !== null && typeof miniApp.impression === "object" ? miniApp.impression : {};
1209
- const keywords = Array.isArray(impression.keywordList) ? impression.keywordList : [];
1210
- const categoryPaths = Array.isArray(impression.categoryPaths) ? impression.categoryPaths : [];
1211
- process.stdout.write(`# App ${appId} (view=${view})\n\n`);
1212
- process.stdout.write(`Name (ko) ${pick("title")}\n`);
1213
- process.stdout.write(`Name (en) ${pick("titleEn")}\n`);
1214
- process.stdout.write(`App slug ${pick("appName")}\n`);
1215
- process.stdout.write(`Status ${pick("status")}\n`);
1216
- process.stdout.write(`Home page ${pick("homePageUri")}\n`);
1217
- process.stdout.write(`CS email ${pick("csEmail")}\n`);
1218
- process.stdout.write(`Logo ${pick("iconUri")}\n`);
1219
- process.stdout.write(`Subtitle ${pick("description")}\n`);
1220
- const detail = typeof miniApp.detailDescription === "string" ? `${[...miniApp.detailDescription].length} chars` : "-";
1221
- process.stdout.write(`Detail desc ${detail}\n`);
1222
- process.stdout.write(`Images ${images.length}\n`);
1223
- process.stdout.write(`Keywords ${keywords.length} (${keywords.join(", ")})\n`);
1224
- const firstPath = categoryPaths[0];
1225
- if (firstPath && typeof firstPath === "object") {
1226
- const fp = firstPath;
1227
- const parts = [];
1228
- for (const key of [
1229
- "group",
1230
- "category",
1231
- "subCategory"
1232
- ]) {
1233
- const node = fp[key];
1234
- if (node !== null && typeof node === "object") {
1235
- const nm = node.name;
1236
- if (typeof nm === "string") parts.push(nm);
1237
- }
1238
- }
1239
- process.stdout.write(`Category ${parts.join(" > ") || "-"}\n`);
1240
- } else process.stdout.write(`Category -\n`);
1241
- return exitAfterFlush(ExitCode.Ok);
1242
1355
  } catch (err) {
1243
1356
  return emitFailureFromError(args.json, err);
1244
1357
  }
@@ -2235,7 +2348,7 @@ function resolveVersion() {
2235
2348
  if (typeof injected === "string" && injected.length > 0) return injected;
2236
2349
  } catch {}
2237
2350
  try {
2238
- return "0.1.9";
2351
+ return "0.1.10";
2239
2352
  } catch {}
2240
2353
  return "0.0.0-dev";
2241
2354
  }