@lark-apaas/miaoda-cli 0.1.2 → 0.1.3-alpha.09899c4

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 (85) hide show
  1. package/README.md +8 -7
  2. package/dist/api/app/api.js +25 -0
  3. package/dist/api/app/index.js +15 -0
  4. package/dist/api/app/schemas.js +79 -0
  5. package/dist/api/app/types.js +58 -0
  6. package/dist/api/db/api.js +390 -55
  7. package/dist/api/db/client.js +65 -25
  8. package/dist/api/db/index.js +12 -1
  9. package/dist/api/db/parsers.js +20 -20
  10. package/dist/api/db/sql-keywords.js +87 -87
  11. package/dist/api/deploy/api.js +60 -0
  12. package/dist/api/deploy/index.js +16 -0
  13. package/dist/api/deploy/schemas.js +105 -0
  14. package/dist/api/deploy/types.js +22 -0
  15. package/dist/api/file/api.js +89 -87
  16. package/dist/api/file/client.js +62 -22
  17. package/dist/api/file/detect.js +3 -3
  18. package/dist/api/file/index.js +2 -1
  19. package/dist/api/file/parsers.js +18 -7
  20. package/dist/api/index.js +7 -1
  21. package/dist/api/observability/api.js +52 -0
  22. package/dist/api/observability/index.js +16 -0
  23. package/dist/api/observability/schemas.js +60 -0
  24. package/dist/api/observability/types.js +27 -0
  25. package/dist/api/plugin/api.js +31 -31
  26. package/dist/cli/commands/app/index.js +62 -0
  27. package/dist/cli/commands/db/index.js +600 -59
  28. package/dist/cli/commands/deploy/index.js +155 -0
  29. package/dist/cli/commands/file/index.js +91 -63
  30. package/dist/cli/commands/index.js +10 -6
  31. package/dist/cli/commands/observability/index.js +240 -0
  32. package/dist/cli/commands/plugin/index.js +27 -27
  33. package/dist/cli/commands/shared.js +86 -10
  34. package/dist/cli/handlers/app/get.js +47 -0
  35. package/dist/cli/handlers/app/index.js +7 -0
  36. package/dist/cli/handlers/app/update.js +59 -0
  37. package/dist/cli/handlers/db/_operator.js +35 -0
  38. package/dist/cli/handlers/db/audit.js +383 -0
  39. package/dist/cli/handlers/db/changelog.js +160 -0
  40. package/dist/cli/handlers/db/data.js +34 -34
  41. package/dist/cli/handlers/db/index.js +17 -1
  42. package/dist/cli/handlers/db/migration.js +245 -0
  43. package/dist/cli/handlers/db/quota.js +68 -0
  44. package/dist/cli/handlers/db/recovery.js +387 -0
  45. package/dist/cli/handlers/db/schema.js +35 -36
  46. package/dist/cli/handlers/db/sql.js +70 -71
  47. package/dist/cli/handlers/deploy/deploy.js +84 -0
  48. package/dist/cli/handlers/deploy/error-log.js +60 -0
  49. package/dist/cli/handlers/deploy/format.js +39 -0
  50. package/dist/cli/handlers/deploy/get.js +71 -0
  51. package/dist/cli/handlers/deploy/helpers.js +41 -0
  52. package/dist/cli/handlers/deploy/history.js +70 -0
  53. package/dist/cli/handlers/deploy/index.js +14 -0
  54. package/dist/cli/handlers/deploy/polling.js +162 -0
  55. package/dist/cli/handlers/file/cp.js +31 -32
  56. package/dist/cli/handlers/file/index.js +3 -1
  57. package/dist/cli/handlers/file/ls.js +6 -7
  58. package/dist/cli/handlers/file/quota.js +66 -0
  59. package/dist/cli/handlers/file/rm.js +33 -32
  60. package/dist/cli/handlers/file/sign.js +4 -5
  61. package/dist/cli/handlers/file/stat.js +11 -11
  62. package/dist/cli/handlers/observability/analytics.js +212 -0
  63. package/dist/cli/handlers/observability/helpers.js +66 -0
  64. package/dist/cli/handlers/observability/index.js +12 -0
  65. package/dist/cli/handlers/observability/log.js +94 -0
  66. package/dist/cli/handlers/observability/metric.js +208 -0
  67. package/dist/cli/handlers/observability/trace.js +102 -0
  68. package/dist/cli/handlers/plugin/plugin-local.js +53 -53
  69. package/dist/cli/handlers/plugin/plugin.js +15 -15
  70. package/dist/cli/help.js +16 -16
  71. package/dist/main.js +13 -9
  72. package/dist/utils/args.js +8 -0
  73. package/dist/utils/colors.js +2 -2
  74. package/dist/utils/config.js +2 -2
  75. package/dist/utils/devops-error.js +28 -0
  76. package/dist/utils/error.js +2 -2
  77. package/dist/utils/git.js +29 -0
  78. package/dist/utils/http.js +119 -1
  79. package/dist/utils/index.js +15 -1
  80. package/dist/utils/output.js +373 -20
  81. package/dist/utils/poll.js +35 -0
  82. package/dist/utils/render.js +27 -27
  83. package/dist/utils/spinner.js +46 -0
  84. package/dist/utils/time.js +208 -0
  85. package/package.json +7 -5
@@ -42,7 +42,6 @@ const error_1 = require("../../../utils/error");
42
42
  const output_1 = require("../../../utils/output");
43
43
  const config_1 = require("../../../utils/config");
44
44
  const logger_1 = require("../../../utils/logger");
45
- const shared_1 = require("../../../cli/commands/shared");
46
45
  const render_1 = require("../../../utils/render");
47
46
  const colors_1 = require("../../../utils/colors");
48
47
  const fuzzy_match_1 = require("../../../utils/fuzzy-match");
@@ -62,10 +61,10 @@ const node_path_1 = __importDefault(require("node:path"));
62
61
  * 末尾汇总,--json 输出 data 数组。
63
62
  */
64
63
  async function handleDbSql(query, opts) {
65
- const appId = (0, shared_1.resolveAppId)(opts);
64
+ const appId = opts.appId;
66
65
  const sql = await readSql(query);
67
66
  if (!sql.trim()) {
68
- throw new error_1.AppError("ARGS_INVALID", "Empty SQL (no inline query and stdin is empty)");
67
+ throw new error_1.AppError('ARGS_INVALID', 'Empty SQL (no inline query and stdin is empty)');
69
68
  }
70
69
  let results;
71
70
  try {
@@ -87,7 +86,7 @@ async function handleDbSql(query, opts) {
87
86
  (0, output_1.emit)({ data: [] });
88
87
  return;
89
88
  }
90
- (0, output_1.emit)("✓ No results");
89
+ (0, output_1.emit)((0, render_1.isStdoutTty)() ? colors_1.c.success('✓ No results') : 'OK No results');
91
90
  return;
92
91
  }
93
92
  if (results.length === 1) {
@@ -122,7 +121,7 @@ async function handleDbSql(query, opts) {
122
121
  * statement 都执行成功,无需再校验逐条状态。
123
122
  */
124
123
  /** agent runtime 中固定的项目根目录;放在此处便于以后调整。 */
125
- const AGENT_PROJECT_ROOT = "/home/gem/workspace/code";
124
+ const AGENT_PROJECT_ROOT = '/home/gem/workspace/code';
126
125
  /** drain 子进程 pipe stream:默认静默模式下消费 chunk 防止缓冲区反压。 */
127
126
  function drainChunk(_chunk) {
128
127
  // 显式接 chunk 参数让 ESLint 不再当成 empty function;不做任何处理
@@ -132,7 +131,7 @@ async function maybeSyncAgentSchema(results) {
132
131
  return;
133
132
  const projectRoot = await resolveAgentProjectRoot();
134
133
  if (!projectRoot) {
135
- (0, logger_1.debug)("[db sql] agent project root not found or missing gen:db-schema script, skip schema sync");
134
+ (0, logger_1.debug)('[db sql] agent project root not found or missing gen:db-schema script, skip schema sync');
136
135
  return;
137
136
  }
138
137
  const verbose = (0, config_1.getConfig)().verbose;
@@ -141,8 +140,8 @@ async function maybeSyncAgentSchema(results) {
141
140
  (0, logger_1.debug)(`[db sql] DDL detected, running \`npm run gen:db-schema\` in ${projectRoot}`);
142
141
  try {
143
142
  await new Promise((resolve) => {
144
- const proc = (0, node_child_process_1.spawn)("npm", ["run", "gen:db-schema"], {
145
- stdio: ["ignore", "pipe", "pipe"],
143
+ const proc = (0, node_child_process_1.spawn)('npm', ['run', 'gen:db-schema'], {
144
+ stdio: ['ignore', 'pipe', 'pipe'],
146
145
  cwd: projectRoot,
147
146
  });
148
147
  // --verbose:实时透传到 stderr 看进度;默认完全静默丢弃。
@@ -153,15 +152,15 @@ async function maybeSyncAgentSchema(results) {
153
152
  proc.stderr.pipe(process.stderr);
154
153
  }
155
154
  else {
156
- proc.stdout.on("data", drainChunk);
157
- proc.stderr.on("data", drainChunk);
155
+ proc.stdout.on('data', drainChunk);
156
+ proc.stderr.on('data', drainChunk);
158
157
  }
159
158
  let timedOut = false;
160
159
  const timer = setTimeout(() => {
161
160
  timedOut = true;
162
- proc.kill("SIGKILL");
161
+ proc.kill('SIGKILL');
163
162
  }, TIMEOUT_MS);
164
- proc.on("close", (code) => {
163
+ proc.on('close', (code) => {
165
164
  clearTimeout(timer);
166
165
  if (timedOut) {
167
166
  (0, logger_1.debug)(`[db sql] gen:db-schema timed out after ${String(TIMEOUT_MS / 1000)}s, killed`);
@@ -170,11 +169,11 @@ async function maybeSyncAgentSchema(results) {
170
169
  (0, logger_1.debug)(`[db sql] gen:db-schema exited with code ${String(code)}`);
171
170
  }
172
171
  else {
173
- (0, logger_1.debug)("[db sql] gen:db-schema completed");
172
+ (0, logger_1.debug)('[db sql] gen:db-schema completed');
174
173
  }
175
174
  resolve();
176
175
  });
177
- proc.on("error", (err) => {
176
+ proc.on('error', (err) => {
178
177
  clearTimeout(timer);
179
178
  (0, logger_1.debug)(`[db sql] gen:db-schema spawn error: ${err.message}`);
180
179
  resolve();
@@ -194,10 +193,10 @@ async function maybeSyncAgentSchema(results) {
194
193
  */
195
194
  async function resolveAgentProjectRoot() {
196
195
  try {
197
- const pkgPath = node_path_1.default.join(AGENT_PROJECT_ROOT, "package.json");
198
- const raw = await node_fs_1.promises.readFile(pkgPath, "utf8");
196
+ const pkgPath = node_path_1.default.join(AGENT_PROJECT_ROOT, 'package.json');
197
+ const raw = await node_fs_1.promises.readFile(pkgPath, 'utf8');
199
198
  const pkg = JSON.parse(raw);
200
- if (pkg.scripts?.["gen:db-schema"])
199
+ if (pkg.scripts?.['gen:db-schema'])
201
200
  return AGENT_PROJECT_ROOT;
202
201
  }
203
202
  catch {
@@ -207,7 +206,7 @@ async function resolveAgentProjectRoot() {
207
206
  }
208
207
  /** 是否有任意一条 statement 是 DDL(CREATE / ALTER / DROP / GRANT / TRUNCATE / COMMENT 等)。 */
209
208
  function hasDdl(results) {
210
- return results.some((r) => (0, index_1.parseSqlResult)(r).kind === "ddl");
209
+ return results.some((r) => (0, index_1.parseSqlResult)(r).kind === 'ddl');
211
210
  }
212
211
  /** 读取 stdin 并返回完整 SQL 文本(stdin 不是 TTY 即认为被 pipe)。 */
213
212
  async function readSql(inline) {
@@ -215,17 +214,17 @@ async function readSql(inline) {
215
214
  return inline;
216
215
  const stdin = process.stdin;
217
216
  if (stdin.isTTY)
218
- return "";
217
+ return '';
219
218
  return new Promise((resolve, reject) => {
220
- let data = "";
221
- process.stdin.setEncoding("utf8");
222
- process.stdin.on("data", (chunk) => {
219
+ let data = '';
220
+ process.stdin.setEncoding('utf8');
221
+ process.stdin.on('data', (chunk) => {
223
222
  data += chunk;
224
223
  });
225
- process.stdin.on("end", () => {
224
+ process.stdin.on('end', () => {
226
225
  resolve(data);
227
226
  });
228
- process.stdin.on("error", reject);
227
+ process.stdin.on('error', reject);
229
228
  });
230
229
  }
231
230
  function renderSingle(raw) {
@@ -235,9 +234,9 @@ function renderSingle(raw) {
235
234
  (0, output_1.emit)(toJson(parsed));
236
235
  return;
237
236
  }
238
- if (parsed.kind === "select") {
237
+ if (parsed.kind === 'select') {
239
238
  if (parsed.rows.length === 0) {
240
- (0, output_1.emit)("(0 rows)");
239
+ (0, output_1.emit)('(0 rows)');
241
240
  return;
242
241
  }
243
242
  const cols = collectColumns(parsed.rows);
@@ -245,22 +244,22 @@ function renderSingle(raw) {
245
244
  (0, output_1.emit)(tty ? (0, render_1.renderAlignedTable)(cols, rows) : (0, render_1.renderTsv)(cols, rows));
246
245
  return;
247
246
  }
248
- if (parsed.kind === "dml") {
247
+ if (parsed.kind === 'dml') {
249
248
  const verb = dmlVerb(parsed.sqlType);
250
249
  (0, output_1.emit)(tty
251
- ? colors_1.c.success(`✓ ${String(parsed.affectedRows)} row${parsed.affectedRows === 1 ? "" : "s"} ${verb}`)
250
+ ? colors_1.c.success(`✓ ${String(parsed.affectedRows)} row${parsed.affectedRows === 1 ? '' : 's'} ${verb}`)
252
251
  : `OK ${String(parsed.affectedRows)} rows ${verb}`);
253
252
  return;
254
253
  }
255
254
  // DDL
256
- (0, output_1.emit)(tty ? colors_1.c.success("✓ DDL executed") : "OK DDL executed");
255
+ (0, output_1.emit)(tty ? colors_1.c.success('✓ DDL executed') : 'OK DDL executed');
257
256
  }
258
257
  function toJson(parsed) {
259
- if (parsed.kind === "select") {
258
+ if (parsed.kind === 'select') {
260
259
  // PRD 单 SELECT:data 直接是行数组(按 --json 字段投影裁剪)
261
260
  return { data: projectRows(parsed.rows) };
262
261
  }
263
- if (parsed.kind === "dml") {
262
+ if (parsed.kind === 'dml') {
264
263
  // PRD 单 DML:data = {command, rows_affected}
265
264
  return {
266
265
  data: {
@@ -278,10 +277,10 @@ function toJson(parsed) {
278
277
  * {command:"SELECT", rows:[...]}(PRD 约定,避免数组里嵌套数组造成歧义)。
279
278
  */
280
279
  function toMultiElement(parsed) {
281
- if (parsed.kind === "select") {
282
- return { command: "SELECT", rows: projectRows(parsed.rows) };
280
+ if (parsed.kind === 'select') {
281
+ return { command: 'SELECT', rows: projectRows(parsed.rows) };
283
282
  }
284
- if (parsed.kind === "dml") {
283
+ if (parsed.kind === 'dml') {
285
284
  return { command: parsed.sqlType, rows_affected: parsed.affectedRows };
286
285
  }
287
286
  // DDL:用后端给的细粒度 command
@@ -307,10 +306,10 @@ function projectRows(rows) {
307
306
  /** 读取 --json [fields]:返回字段列表;boolean true 或 undefined 返回 null(不裁剪)。 */
308
307
  function parseJsonFields() {
309
308
  const v = (0, config_1.getConfig)().json;
310
- if (typeof v !== "string" || v === "")
309
+ if (typeof v !== 'string' || v === '')
311
310
  return null;
312
311
  return v
313
- .split(",")
312
+ .split(',')
314
313
  .map((s) => s.trim())
315
314
  .filter((s) => s.length > 0);
316
315
  }
@@ -321,9 +320,9 @@ function renderMultiPretty(results) {
321
320
  for (let i = 0; i < results.length; i++) {
322
321
  const parsed = (0, index_1.parseSqlResult)(results[i]);
323
322
  const idx = i + 1;
324
- if (parsed.kind === "select") {
323
+ if (parsed.kind === 'select') {
325
324
  const n = parsed.rows.length;
326
- lines.push(`Statement ${String(idx)}: SELECT (${String(n)} row${n === 1 ? "" : "s"})`);
325
+ lines.push(`Statement ${String(idx)}: SELECT (${String(n)} row${n === 1 ? '' : 's'})`);
327
326
  if (n > 0) {
328
327
  const cols = collectColumns(parsed.rows);
329
328
  const tbl = parsed.rows.map((r) => cols.map((col) => formatCell(r[col], tty)));
@@ -331,37 +330,37 @@ function renderMultiPretty(results) {
331
330
  }
332
331
  // 块间空行(最后一条不留)
333
332
  if (i < results.length - 1)
334
- lines.push("");
333
+ lines.push('');
335
334
  continue;
336
335
  }
337
- if (parsed.kind === "dml") {
336
+ if (parsed.kind === 'dml') {
338
337
  const verb = dmlVerb(parsed.sqlType);
339
338
  const n = parsed.affectedRows;
340
- const body = `${String(n)} row${n === 1 ? "" : "s"} ${verb}`;
341
- lines.push(`Statement ${String(idx)}: ${tty ? colors_1.c.success("" + body) : body}`);
339
+ const body = `${String(n)} row${n === 1 ? '' : 's'} ${verb}`;
340
+ lines.push(`Statement ${String(idx)}: ${tty ? colors_1.c.success('' + body) : body}`);
342
341
  continue;
343
342
  }
344
343
  // DDL
345
- lines.push(`Statement ${String(idx)}: ${tty ? colors_1.c.success("✓ DDL executed") : "DDL executed"}`);
344
+ lines.push(`Statement ${String(idx)}: ${tty ? colors_1.c.success('✓ DDL executed') : 'DDL executed'}`);
346
345
  }
347
346
  // 汇总行:所有 statement 都跑完了
348
347
  lines.push(tty
349
348
  ? colors_1.c.success(`✓ ${String(results.length)} statements executed`)
350
349
  : `OK ${String(results.length)} statements executed`);
351
- (0, output_1.emit)(lines.join("\n"));
350
+ (0, output_1.emit)(lines.join('\n'));
352
351
  }
353
352
  function dmlVerb(type) {
354
353
  switch (type) {
355
- case "INSERT":
356
- return "inserted";
357
- case "UPDATE":
358
- return "updated";
359
- case "DELETE":
360
- return "deleted";
361
- case "MERGE":
362
- return "merged";
363
- case "DML":
364
- return "affected"; // 未识别子类的兜底
354
+ case 'INSERT':
355
+ return 'inserted';
356
+ case 'UPDATE':
357
+ return 'updated';
358
+ case 'DELETE':
359
+ return 'deleted';
360
+ case 'MERGE':
361
+ return 'merged';
362
+ case 'DML':
363
+ return 'affected'; // 未识别子类的兜底
365
364
  }
366
365
  }
367
366
  /** 从第一行收集列顺序;缺失列保留空白(兼容稀疏行)。 */
@@ -381,9 +380,9 @@ function collectColumns(rows) {
381
380
  */
382
381
  function formatCell(v, tty) {
383
382
  if (v === null || v === undefined) {
384
- return tty ? colors_1.c.muted("NULL") : "NULL";
383
+ return tty ? colors_1.c.muted('NULL') : 'NULL';
385
384
  }
386
- if (typeof v === "string") {
385
+ if (typeof v === 'string') {
387
386
  // TTY 下检测到 ISO 8601 时间字符串 → 转成相对时间("3h ago" / "2d ago" /
388
387
  // "2026-03-15"),方便 _created_at / _updated_at 等列直观可读
389
388
  if (tty && ISO_TIMESTAMP_RE.test(v) && !Number.isNaN(Date.parse(v))) {
@@ -391,7 +390,7 @@ function formatCell(v, tty) {
391
390
  }
392
391
  return v;
393
392
  }
394
- if (typeof v === "number" || typeof v === "boolean")
393
+ if (typeof v === 'number' || typeof v === 'boolean')
395
394
  return String(v);
396
395
  // object / array → JSON
397
396
  return JSON.stringify(v);
@@ -488,7 +487,7 @@ async function loadTableMap(ctx) {
488
487
  try {
489
488
  const resp = await api.db.getSchema({
490
489
  appId: ctx.appId,
491
- format: "schema",
490
+ format: 'schema',
492
491
  dbBranch: ctx.env,
493
492
  });
494
493
  return extractTableFieldMap(resp.schema);
@@ -501,7 +500,7 @@ function enrichRelationNotExist(err, relation, tableMap) {
501
500
  const guess = (0, fuzzy_match_1.suggest)(relation, Object.keys(tableMap));
502
501
  err.next_actions.push(guess
503
502
  ? `Did you mean '${guess}'? Run \`miaoda db schema list\` to see all tables.`
504
- : "Run `miaoda db schema list` to see all tables.");
503
+ : 'Run `miaoda db schema list` to see all tables.');
505
504
  }
506
505
  function enrichColumnNotExist(err, colMatch, tableMap) {
507
506
  const colName = colMatch[1];
@@ -523,7 +522,7 @@ function enrichColumnNotExist(err, colMatch, tableMap) {
523
522
  const guess = (0, fuzzy_match_1.suggest)(colName, allCols);
524
523
  err.next_actions.push(guess
525
524
  ? `Did you mean '${guess}'? Run \`miaoda db schema get <table>\` to see columns.`
526
- : "Run `miaoda db schema get <table>` to see all columns.");
525
+ : 'Run `miaoda db schema get <table>` to see all columns.');
527
526
  }
528
527
  /**
529
528
  * 扫整段 SQL 找一个看似"拼错的关键字"token:纯字母 + 长度 ≥ 3 + 不是已知 keyword
@@ -594,7 +593,7 @@ function enrichMultiStatementError(err, sql) {
594
593
  }
595
594
  // rolled_back=true 时追加 spec hint:"Transaction rolled back; no changes persisted."
596
595
  if (err.rolled_back) {
597
- err.next_actions.push("Transaction rolled back; no changes persisted.");
596
+ err.next_actions.push('Transaction rolled back; no changes persisted.');
598
597
  }
599
598
  }
600
599
  /**
@@ -606,9 +605,9 @@ function enrichMultiStatementError(err, sql) {
606
605
  function inferRolledBack(completed) {
607
606
  let depth = 0;
608
607
  for (const e of completed) {
609
- if (e.command === "BEGIN")
608
+ if (e.command === 'BEGIN')
610
609
  depth++;
611
- else if (e.command === "COMMIT" || e.command === "ROLLBACK")
610
+ else if (e.command === 'COMMIT' || e.command === 'ROLLBACK')
612
611
  depth--;
613
612
  }
614
613
  return depth > 0;
@@ -631,25 +630,25 @@ function writeMultiStatementBreakdown(err, completed) {
631
630
  const lines = [];
632
631
  for (let i = 0; i < completed.length; i++) {
633
632
  const e = completed[i];
634
- const verb = e.command === "BEGIN" || e.command === "COMMIT" || e.command === "ROLLBACK"
633
+ const verb = e.command === 'BEGIN' || e.command === 'COMMIT' || e.command === 'ROLLBACK'
635
634
  ? e.command
636
635
  : describeCompleted(e);
637
- lines.push(`Statement ${String(i + 1)}: ${tty ? colors_1.c.success("") : ""}${verb}`);
636
+ lines.push(`Statement ${String(i + 1)}: ${tty ? colors_1.c.success('') : ''}${verb}`);
638
637
  }
639
638
  // 失败那条
640
639
  const failedIdx = err.statement_index ?? completed.length;
641
- lines.push(`Statement ${String(failedIdx + 1)}: ${tty ? colors_1.c.fail("") : ""}${err.message}`);
642
- process.stderr.write(lines.join("\n") + "\n\n");
640
+ lines.push(`Statement ${String(failedIdx + 1)}: ${tty ? colors_1.c.fail('') : ''}${err.message}`);
641
+ process.stderr.write(lines.join('\n') + '\n\n');
643
642
  }
644
643
  /** completed 单条结果的人类可读描述(用于 stderr breakdown 行尾)。 */
645
644
  function describeCompleted(e) {
646
645
  const r = e;
647
- if (r.command === "SELECT" && Array.isArray(r.rows)) {
648
- return `SELECT (${String(r.rows.length)} row${r.rows.length === 1 ? "" : "s"})`;
646
+ if (r.command === 'SELECT' && Array.isArray(r.rows)) {
647
+ return `SELECT (${String(r.rows.length)} row${r.rows.length === 1 ? '' : 's'})`;
649
648
  }
650
- if (typeof r.rows_affected === "number") {
649
+ if (typeof r.rows_affected === 'number') {
651
650
  const verb = dmlVerb(r.command);
652
- return `${String(r.rows_affected)} row${r.rows_affected === 1 ? "" : "s"} ${verb}`;
651
+ return `${String(r.rows_affected)} row${r.rows_affected === 1 ? '' : 's'} ${verb}`;
653
652
  }
654
653
  return `${r.command} executed`;
655
654
  }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.handleDeploy = handleDeploy;
37
+ const api = __importStar(require("../../../api/index"));
38
+ const output_1 = require("../../../utils/output");
39
+ const index_1 = require("../../../api/deploy/index");
40
+ const polling_1 = require("./polling");
41
+ const format_1 = require("./format");
42
+ /** miaoda deploy [--branch ...] [--wait] [--timeout 300] */
43
+ async function handleDeploy(opts) {
44
+ const appID = opts.appId;
45
+ const resp = await api.deploy.createRelease({ appID, branch: opts.branch });
46
+ const pipelineTaskID = resp.pipelineTaskID ?? '';
47
+ if (!opts.wait) {
48
+ if (!(0, output_1.isJsonMode)()) {
49
+ process.stdout.write(`✓ Deployment triggered. (deploy-id: ${pipelineTaskID})\n`);
50
+ process.stdout.write(` hint: No terminal status yet. Poll every 2s with \`miaoda deploy get ${pipelineTaskID} --json\`; if no deploy-id is visible, first get it from \`miaoda deploy history --limit 1 --json\`.\n`);
51
+ }
52
+ (0, output_1.emit)({
53
+ data: { pipelineTaskID },
54
+ next_cursor: null,
55
+ has_more: false,
56
+ });
57
+ return;
58
+ }
59
+ if (!(0, output_1.isJsonMode)()) {
60
+ process.stdout.write(`Waiting for deployment to complete... (deploy-id: ${pipelineTaskID})\n`);
61
+ }
62
+ const detail = await (0, polling_1.waitForPipeline)({
63
+ appID,
64
+ pipelineTaskID,
65
+ timeoutSec: opts.timeout ?? 300,
66
+ });
67
+ if (!(0, output_1.isJsonMode)()) {
68
+ if (detail.status === index_1.NodeStatus.SUCCESS) {
69
+ process.stdout.write('✓ 发布成功\n');
70
+ }
71
+ else if (detail.status === index_1.NodeStatus.FAILED) {
72
+ process.stdout.write('✗ 发布失败\n');
73
+ process.stdout.write(` hint: Run \`miaoda deploy error-log ${pipelineTaskID}\` to view error logs\n`);
74
+ }
75
+ else {
76
+ process.stdout.write('• 发布已取消\n');
77
+ }
78
+ }
79
+ (0, output_1.emit)({
80
+ data: { pipelineTaskID, detail: (0, format_1.formatPipelineInstance)(detail) },
81
+ next_cursor: null,
82
+ has_more: false,
83
+ });
84
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.handleDeployErrorLog = handleDeployErrorLog;
37
+ const api = __importStar(require("../../../api/index"));
38
+ const output_1 = require("../../../utils/output");
39
+ const args_1 = require("../../../utils/args");
40
+ const index_1 = require("../../../api/deploy/index");
41
+ const helpers_1 = require("./helpers");
42
+ /** miaoda deploy error-log <deploy-id> */
43
+ async function handleDeployErrorLog(opts) {
44
+ if (!opts.deployId)
45
+ (0, args_1.failArgs)('<deploy-id> 必填');
46
+ const appID = opts.appId;
47
+ (0, helpers_1.parseDeployId)(opts.deployId); // 仅校验数字形式;URL 直接用原字符串
48
+ const instanceID = opts.deployId;
49
+ const resp = await api.deploy.getErrorLog({ appID, instanceID });
50
+ (0, output_1.emit)({
51
+ data: resp.errorJobs,
52
+ next_cursor: null,
53
+ has_more: false,
54
+ }, index_1.errorJobSchema);
55
+ // pretty 模式额外打一行整体状态。
56
+ if (!process.stdout.isTTY)
57
+ return;
58
+ const statusText = (0, index_1.nodeStatusText)(resp.status) ?? String(resp.status);
59
+ process.stdout.write(`\n— pipeline status: ${statusText}\n`);
60
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatStatusMetadata = formatStatusMetadata;
4
+ exports.formatSimpleInstance = formatSimpleInstance;
5
+ exports.formatPipelineInstance = formatPipelineInstance;
6
+ const index_1 = require("../../../api/deploy/index");
7
+ function formatStatusMetadata(statusCode) {
8
+ return {
9
+ status: (0, index_1.nodeStatusText)(statusCode) ?? `unknown(${String(statusCode)})`,
10
+ status_code: statusCode,
11
+ };
12
+ }
13
+ function formatSimpleInstance(instance) {
14
+ if (instance.status === undefined)
15
+ return { ...instance };
16
+ return {
17
+ ...instance,
18
+ ...formatStatusMetadata(instance.status),
19
+ };
20
+ }
21
+ function formatPipelineInstance(detail) {
22
+ const stages = Array.isArray(detail.stages) ? detail.stages : [];
23
+ return {
24
+ ...detail,
25
+ ...formatStatusMetadata(detail.status),
26
+ stages: stages.map((stage) => ({
27
+ ...stage,
28
+ ...formatStatusMetadata(stage.status),
29
+ jobs: stage.jobs.map((group) => group.map((job) => ({
30
+ ...job,
31
+ ...formatStatusMetadata(job.status),
32
+ steps: job.steps?.map((step) => ({
33
+ ...step,
34
+ ...formatStatusMetadata(step.status),
35
+ })),
36
+ }))),
37
+ })),
38
+ };
39
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.handleDeployGet = handleDeployGet;
37
+ const api = __importStar(require("../../../api/index"));
38
+ const output_1 = require("../../../utils/output");
39
+ const args_1 = require("../../../utils/args");
40
+ const error_1 = require("../../../utils/error");
41
+ const index_1 = require("../../../api/deploy/index");
42
+ const helpers_1 = require("./helpers");
43
+ const format_1 = require("./format");
44
+ /**
45
+ * 单页拉取上限:BAM listPipelineInstances 限制 1~500,取 500 让 deploy get
46
+ * 在最近 500 条记录里按 ID 命中。
47
+ */
48
+ const DEPLOY_GET_LOOKUP_LIMIT = 500;
49
+ /**
50
+ * miaoda deploy get <deploy-id>
51
+ *
52
+ * BAM 没有 by-ID 的查询接口,复用 listPipelineInstances 在最近窗口里按 ID 筛一条。
53
+ * 命中失败时抛 DEPLOY_NOT_FOUND,提示用户用 history 查窗口。
54
+ */
55
+ async function handleDeployGet(opts) {
56
+ if (!opts.deployId)
57
+ (0, args_1.failArgs)('<deploy-id> 必填');
58
+ const appID = opts.appId;
59
+ const deployId = (0, helpers_1.parseDeployId)(opts.deployId);
60
+ const resp = await api.deploy.listPipelineInstances({
61
+ appID,
62
+ limit: DEPLOY_GET_LOOKUP_LIMIT,
63
+ });
64
+ const instance = resp.instances?.find((it) => Number(it.ID) === deployId);
65
+ if (!instance) {
66
+ throw new error_1.AppError('DEPLOY_NOT_FOUND', `未在最近 ${String(DEPLOY_GET_LOOKUP_LIMIT)} 条记录中找到 deploy-id=${opts.deployId}`, {
67
+ next_actions: ['运行 `miaoda deploy history` 确认 deploy-id 是否在最近窗口内'],
68
+ });
69
+ }
70
+ (0, output_1.emit)({ data: (0, format_1.formatSimpleInstance)(instance), next_cursor: null, has_more: false }, index_1.deployGetSchema);
71
+ }