@lark-apaas/miaoda-cli 0.1.3 → 0.1.4-alpha.8b6506a

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 (109) hide show
  1. package/dist/api/app/api.js +3 -3
  2. package/dist/api/app/schemas.js +43 -43
  3. package/dist/api/db/api.js +398 -55
  4. package/dist/api/db/client.js +155 -28
  5. package/dist/api/db/index.js +12 -1
  6. package/dist/api/db/parsers.js +20 -20
  7. package/dist/api/db/sql-keywords.js +87 -87
  8. package/dist/api/deploy/api.js +5 -5
  9. package/dist/api/deploy/index.js +12 -1
  10. package/dist/api/deploy/modern-types.js +23 -0
  11. package/dist/api/deploy/modern.js +70 -0
  12. package/dist/api/deploy/plugin-instances-types.js +6 -0
  13. package/dist/api/deploy/plugin-instances.js +30 -0
  14. package/dist/api/deploy/schemas.js +32 -32
  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/observability/api.js +6 -6
  21. package/dist/api/observability/schemas.js +14 -14
  22. package/dist/api/plugin/api.js +31 -31
  23. package/dist/cli/commands/app/index.js +94 -13
  24. package/dist/cli/commands/db/index.js +602 -54
  25. package/dist/cli/commands/deploy/index.js +28 -28
  26. package/dist/cli/commands/deploy/modern.js +48 -0
  27. package/dist/cli/commands/file/index.js +85 -58
  28. package/dist/cli/commands/index.js +33 -5
  29. package/dist/cli/commands/observability/index.js +69 -69
  30. package/dist/cli/commands/plugin/index.js +27 -27
  31. package/dist/cli/commands/shared.js +10 -10
  32. package/dist/cli/commands/skills/index.js +63 -0
  33. package/dist/cli/handlers/app/index.js +6 -1
  34. package/dist/cli/handlers/app/init.js +84 -0
  35. package/dist/cli/handlers/app/update.js +2 -2
  36. package/dist/cli/handlers/db/_destructive.js +67 -0
  37. package/dist/cli/handlers/db/_env.js +26 -0
  38. package/dist/cli/handlers/db/_operator.js +35 -0
  39. package/dist/cli/handlers/db/audit.js +383 -0
  40. package/dist/cli/handlers/db/changelog.js +160 -0
  41. package/dist/cli/handlers/db/data.js +32 -31
  42. package/dist/cli/handlers/db/index.js +17 -1
  43. package/dist/cli/handlers/db/migration.js +234 -0
  44. package/dist/cli/handlers/db/quota.js +68 -0
  45. package/dist/cli/handlers/db/recovery.js +413 -0
  46. package/dist/cli/handlers/db/schema.js +33 -33
  47. package/dist/cli/handlers/db/sql.js +69 -69
  48. package/dist/cli/handlers/deploy/deploy.js +4 -4
  49. package/dist/cli/handlers/deploy/error-log.js +1 -1
  50. package/dist/cli/handlers/deploy/get.js +3 -3
  51. package/dist/cli/handlers/deploy/modern.js +32 -0
  52. package/dist/cli/handlers/deploy/polling.js +11 -11
  53. package/dist/cli/handlers/file/cp.js +30 -30
  54. package/dist/cli/handlers/file/index.js +3 -1
  55. package/dist/cli/handlers/file/ls.js +5 -5
  56. package/dist/cli/handlers/file/quota.js +66 -0
  57. package/dist/cli/handlers/file/rm.js +32 -30
  58. package/dist/cli/handlers/file/sign.js +3 -3
  59. package/dist/cli/handlers/file/stat.js +10 -9
  60. package/dist/cli/handlers/observability/analytics.js +47 -47
  61. package/dist/cli/handlers/observability/helpers.js +2 -2
  62. package/dist/cli/handlers/observability/log.js +9 -9
  63. package/dist/cli/handlers/observability/metric.js +26 -26
  64. package/dist/cli/handlers/observability/trace.js +5 -5
  65. package/dist/cli/handlers/plugin/plugin-local.js +53 -53
  66. package/dist/cli/handlers/plugin/plugin.js +15 -15
  67. package/dist/cli/handlers/skills/index.js +7 -0
  68. package/dist/cli/handlers/skills/status.js +31 -0
  69. package/dist/cli/handlers/skills/sync.js +38 -0
  70. package/dist/cli/help.js +16 -16
  71. package/dist/main.js +12 -12
  72. package/dist/services/app/init/index.js +12 -0
  73. package/dist/services/app/init/install.js +101 -0
  74. package/dist/services/app/init/template.js +85 -0
  75. package/dist/services/deploy/modern/atoms/build.js +54 -0
  76. package/dist/services/deploy/modern/atoms/context.js +30 -0
  77. package/dist/services/deploy/modern/atoms/index.js +17 -0
  78. package/dist/services/deploy/modern/atoms/local-release.js +27 -0
  79. package/dist/services/deploy/modern/atoms/pre-release.js +13 -0
  80. package/dist/services/deploy/modern/atoms/save-plugin-instances.js +72 -0
  81. package/dist/services/deploy/modern/atoms/upload.js +205 -0
  82. package/dist/services/deploy/modern/check.js +58 -0
  83. package/dist/services/deploy/modern/constants.js +13 -0
  84. package/dist/services/deploy/modern/index.js +16 -0
  85. package/dist/services/deploy/modern/pipelines/index.js +5 -0
  86. package/dist/services/deploy/modern/pipelines/local.js +75 -0
  87. package/dist/services/deploy/modern/protocol.js +43 -0
  88. package/dist/services/deploy/modern/run-types.js +4 -0
  89. package/dist/services/deploy/modern/run.js +13 -0
  90. package/dist/services/deploy/modern/template-key-map.js +29 -0
  91. package/dist/services/skills/index.js +5 -0
  92. package/dist/services/skills/status.js +37 -0
  93. package/dist/utils/args.js +1 -1
  94. package/dist/utils/coding-steering.js +84 -0
  95. package/dist/utils/colors.js +2 -2
  96. package/dist/utils/config.js +2 -2
  97. package/dist/utils/devops-error.js +9 -9
  98. package/dist/utils/error.js +2 -2
  99. package/dist/utils/git.js +4 -4
  100. package/dist/utils/http.js +28 -26
  101. package/dist/utils/index.js +3 -1
  102. package/dist/utils/npm-pack.js +55 -0
  103. package/dist/utils/output.js +67 -45
  104. package/dist/utils/poll.js +35 -0
  105. package/dist/utils/render.js +27 -27
  106. package/dist/utils/spark-meta.js +42 -0
  107. package/dist/utils/spinner.js +46 -0
  108. package/dist/utils/time.js +47 -42
  109. package/package.json +1 -1
@@ -28,7 +28,7 @@ const colors_1 = require("./colors");
28
28
  /** 将字节数格式化为人类可读(`24 KB` / `2.1 MB` / `1.5 GB`)。 */
29
29
  function formatSize(bytes) {
30
30
  if (!Number.isFinite(bytes) || bytes < 0)
31
- return "";
31
+ return '';
32
32
  if (bytes >= 1 << 30)
33
33
  return `${(bytes / (1 << 30)).toFixed(1)} GB`;
34
34
  if (bytes >= 1 << 20)
@@ -40,7 +40,7 @@ function formatSize(bytes) {
40
40
  /** 将 ISO 时间转为 TTY 下更友好的相对时间;non-TTY 保持 ISO 原值。 */
41
41
  function formatTime(iso, isTty) {
42
42
  if (!iso)
43
- return "";
43
+ return '';
44
44
  if (!isTty)
45
45
  return iso;
46
46
  const ts = Date.parse(iso);
@@ -65,8 +65,8 @@ function formatTime(iso, isTty) {
65
65
  // 超过 7 天,用 YYYY-MM-DD
66
66
  const date = new Date(ts);
67
67
  const y = String(date.getFullYear());
68
- const mo = String(date.getMonth() + 1).padStart(2, "0");
69
- const da = String(date.getDate()).padStart(2, "0");
68
+ const mo = String(date.getMonth() + 1).padStart(2, '0');
69
+ const da = String(date.getDate()).padStart(2, '0');
70
70
  return `${y}-${mo}-${da}`;
71
71
  }
72
72
  /**
@@ -103,7 +103,7 @@ function charWidth(cp) {
103
103
  }
104
104
  /** cell 可见字符宽度:剥离 ANSI 转义后按终端列宽逐字符累加(CJK 算 2 列)。 */
105
105
  function visibleWidth(s) {
106
- const stripped = s.replace(ANSI_SGR_RE, "");
106
+ const stripped = s.replace(ANSI_SGR_RE, '');
107
107
  let w = 0;
108
108
  for (const c of stripped) {
109
109
  w += charWidth(c.codePointAt(0) ?? 0);
@@ -112,7 +112,7 @@ function visibleWidth(s) {
112
112
  }
113
113
  function padVisibleEnd(s, targetWidth) {
114
114
  const w = visibleWidth(s);
115
- return w >= targetWidth ? s : s + " ".repeat(targetWidth - w);
115
+ return w >= targetWidth ? s : s + ' '.repeat(targetWidth - w);
116
116
  }
117
117
  /** 渲染 TTY 对齐表格(多行,列宽按最长内容;ANSI 转义不计入列宽)。
118
118
  * 表头按 spec 用 bold + cyan 染色;ANSI 序列由 visibleWidth 剥离不影响列宽。 */
@@ -120,7 +120,7 @@ function renderAlignedTable(headers, rows) {
120
120
  const colWidths = headers.map((h, i) => {
121
121
  let w = visibleWidth(h);
122
122
  for (const row of rows) {
123
- const cw = visibleWidth(row[i] || "");
123
+ const cw = visibleWidth(row[i] || '');
124
124
  if (cw > w)
125
125
  w = cw;
126
126
  }
@@ -129,34 +129,34 @@ function renderAlignedTable(headers, rows) {
129
129
  const lines = [];
130
130
  lines.push(headers
131
131
  .map((h, i) => colors_1.c.header(padVisibleEnd(h, colWidths[i])))
132
- .join(" ")
132
+ .join(' ')
133
133
  .trimEnd());
134
134
  for (const row of rows) {
135
135
  lines.push(row
136
- .map((cell, i) => padVisibleEnd(cell || "", colWidths[i]))
137
- .join(" ")
136
+ .map((cell, i) => padVisibleEnd(cell || '', colWidths[i]))
137
+ .join(' ')
138
138
  .trimEnd());
139
139
  }
140
- return lines.join("\n");
140
+ return lines.join('\n');
141
141
  }
142
142
  /** 渲染 non-TTY tab 分隔(字段原值,ISO 时间)。 */
143
143
  function renderTsv(headers, rows) {
144
144
  const lines = [];
145
- lines.push(headers.join("\t"));
145
+ lines.push(headers.join('\t'));
146
146
  for (const row of rows) {
147
- lines.push(row.join("\t"));
147
+ lines.push(row.join('\t'));
148
148
  }
149
- return lines.join("\n");
149
+ return lines.join('\n');
150
150
  }
151
151
  /** 渲染 key-value 多行(用于 stat 等单条详情)。key 右对齐 + bold cyan 染色。 */
152
152
  function renderKeyValue(pairs, isTty) {
153
153
  if (pairs.length === 0)
154
- return "";
154
+ return '';
155
155
  if (!isTty) {
156
- return pairs.map(([k, v]) => `${k}\t${v}`).join("\n");
156
+ return pairs.map(([k, v]) => `${k}\t${v}`).join('\n');
157
157
  }
158
158
  const keyWidth = Math.max(...pairs.map(([k]) => k.length));
159
- return pairs.map(([k, v]) => `${colors_1.c.header(k.padStart(keyWidth))}: ${v}`).join("\n");
159
+ return pairs.map(([k, v]) => `${colors_1.c.header(k.padStart(keyWidth))}: ${v}`).join('\n');
160
160
  }
161
161
  /** 通用 isTTY 判定(stdout 是否交互终端)。Node 运行时 isTTY 为 true 或 undefined;TS 类型上 tty.WriteStream 定义为固定 true,绕开做运行时判断。 */
162
162
  function isStdoutTty() {
@@ -170,15 +170,15 @@ function parseDuration(input) {
170
170
  throw new Error(`Invalid duration: ${input}`);
171
171
  }
172
172
  const n = Number(m[1]);
173
- const unit = m[2] || "s";
173
+ const unit = m[2] || 's';
174
174
  switch (unit) {
175
- case "s":
175
+ case 's':
176
176
  return n;
177
- case "m":
177
+ case 'm':
178
178
  return n * 60;
179
- case "h":
179
+ case 'h':
180
180
  return n * 3600;
181
- case "d":
181
+ case 'd':
182
182
  return n * 86400;
183
183
  default:
184
184
  return n;
@@ -191,15 +191,15 @@ function parseSize(input) {
191
191
  throw new Error(`Invalid size: ${input}`);
192
192
  }
193
193
  const n = Number(m[1]);
194
- const unit = (m[2] || "B").toUpperCase();
194
+ const unit = (m[2] || 'B').toUpperCase();
195
195
  switch (unit) {
196
- case "B":
196
+ case 'B':
197
197
  return Math.round(n);
198
- case "KB":
198
+ case 'KB':
199
199
  return Math.round(n * 1024);
200
- case "MB":
200
+ case 'MB':
201
201
  return Math.round(n * 1024 * 1024);
202
- case "GB":
202
+ case 'GB':
203
203
  return Math.round(n * 1024 * 1024 * 1024);
204
204
  default:
205
205
  return Math.round(n);
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readSparkMeta = readSparkMeta;
7
+ exports.writeSparkMeta = writeSparkMeta;
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const SPARK_DIR = '.spark';
11
+ const SPARK_META_FILE = 'meta.json';
12
+ function readSparkMeta(appDir) {
13
+ const metaPath = node_path_1.default.join(appDir, SPARK_DIR, SPARK_META_FILE);
14
+ if (!node_fs_1.default.existsSync(metaPath))
15
+ return {};
16
+ try {
17
+ return JSON.parse(node_fs_1.default.readFileSync(metaPath, 'utf-8'));
18
+ }
19
+ catch {
20
+ return {};
21
+ }
22
+ }
23
+ /**
24
+ * merge 写入:已有字段保留,undefined 不覆盖;不再维护时间戳。
25
+ */
26
+ function writeSparkMeta(appDir, meta) {
27
+ const sparkDir = node_path_1.default.join(appDir, SPARK_DIR);
28
+ node_fs_1.default.mkdirSync(sparkDir, { recursive: true });
29
+ const metaPath = node_path_1.default.join(sparkDir, SPARK_META_FILE);
30
+ let existing = {};
31
+ if (node_fs_1.default.existsSync(metaPath)) {
32
+ try {
33
+ existing = JSON.parse(node_fs_1.default.readFileSync(metaPath, 'utf-8'));
34
+ }
35
+ catch {
36
+ /* 读不出就当空 */
37
+ }
38
+ }
39
+ const defined = Object.fromEntries(Object.entries(meta).filter(([, v]) => v !== undefined));
40
+ const merged = { ...existing, ...defined };
41
+ node_fs_1.default.writeFileSync(metaPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
42
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startSpinner = startSpinner;
4
+ const config_1 = require("./config");
5
+ /**
6
+ * TTY 友好的 loading 指示器,写到 stderr 上避免污染 stdout(保证 --json 输出干净)。
7
+ *
8
+ * 设计:
9
+ * - 仅 stderr.isTTY 且非 --json 模式启用;其他情况静默(CI / 管道 / JSON 输出场景)
10
+ * - 80ms 一帧 braille 旋转字符 + 累计 elapsed 秒数
11
+ * - 返回 stop() 函数;调用方 finally 里调用,无论成功失败都清掉 spinner 行
12
+ *
13
+ * 用法:
14
+ * const stop = startSpinner('Applying migration to online');
15
+ * try { await someLongTask(); } finally { stop(); }
16
+ */
17
+ const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
18
+ const HIDE_CURSOR = '[?25l';
19
+ const SHOW_CURSOR = '[?25h';
20
+ const CLEAR_LINE = '\r';
21
+ function startSpinner(label) {
22
+ // 非 TTY / JSON 模式:静默 noop,避免污染管道与结构化输出
23
+ if (!process.stderr.isTTY || (0, config_1.getConfig)().json) {
24
+ return () => {
25
+ /* noop */
26
+ };
27
+ }
28
+ let frame = 0;
29
+ const start = Date.now();
30
+ process.stderr.write(HIDE_CURSOR);
31
+ const render = () => {
32
+ const elapsedSec = Math.round((Date.now() - start) / 1000);
33
+ process.stderr.write(`${CLEAR_LINE}${FRAMES[frame]} ${label}... ${String(elapsedSec)}s`);
34
+ frame = (frame + 1) % FRAMES.length;
35
+ };
36
+ render();
37
+ const timer = setInterval(render, 80);
38
+ let stopped = false;
39
+ return () => {
40
+ if (stopped)
41
+ return;
42
+ stopped = true;
43
+ clearInterval(timer);
44
+ process.stderr.write(`${CLEAR_LINE}${SHOW_CURSOR}`);
45
+ };
46
+ }
@@ -10,45 +10,48 @@ exports.parseToSec = parseToSec;
10
10
  exports.floorMsToBucket = floorMsToBucket;
11
11
  exports.ceilMsToBucket = ceilMsToBucket;
12
12
  const error_1 = require("./error");
13
- exports.TIMESTAMP_HELP = "支持格式:" +
14
- "相对时间 30m/1h/2d/1w;" +
15
- "日期 2026-04-01(本地时区当日 00:00:00);" +
16
- "本地日期+时间 2026-04-01T10:00:00(按本地时区,T 分隔);" +
17
- "带时区 ISO 2026-04-01T10:00:00Z(UTC)或 2026-04-01T10:00:00+08:00(指定偏移)。" +
18
- "禁止用空格分隔:'YYYY-MM-DD HH:mm:ss' 不带引号会被 shell 拆成两个参数。";
19
13
  /**
20
- * 解析时间字符串到毫秒时间戳;不匹配任一支持格式抛 ARGS_INVALID。
21
- *
22
- * 时区约定(重要):
23
- * - 不带显式时区的形式(YYYY-MM-DD、YYYY-MM-DDTHH:mm:ss)一律按
24
- * **本地时区**解释,与 pretty 输出(output.ts:renderDate 用 getFullYear 等本地方法)形成
25
- * 输入/输出闭环:用户复制输出文本作为 --since 不会差时区。
26
- * - 带显式时区(结尾 Z 或 ±HH:MM / ±HHMM)按显式时区解析,跨机器一致。
27
- * - 因此跨机器同步使用时建议带显式时区;同机器复制粘贴 pretty 输出更省事。
28
- *
29
- * 拒绝 Date.parse 松散接受的形式:YYYY/MM/DD、自然语言('April 1 2026')、单独年份等。
14
+ * 时间格式简短说明,对齐 Supabase / fly.io 等主流 CLI 的「简洁但严格」风格。
30
15
  *
16
+ * - 不接受 YYYY/MM/DD、'April 1 2026' 这类松散 / 区域性形式(Date.parse 会误吞)
17
+ * - 不接受空格分隔的 'YYYY-MM-DD HH:mm:ss':不带引号会被 shell 拆成两个参数,
18
+ * 宁可拒绝也不让用户踩「看起来传了 since 实际只传了一半」的坑
19
+ * - 不带显式时区的 (YYYY-MM-DD / YYYY-MM-DDTHH:mm:ss) 一律按**本地时区**解释,
20
+ * 跟 pretty 输出(renderDate 用 getFullYear 等本地方法)形成输入/输出闭环
21
+ * ——用户复制 pretty 输出的时间字符串当 --since 不会差时区
22
+ */
23
+ exports.TIMESTAMP_HELP = 'Accepted formats: ' +
24
+ 'relative (30s / 5m / 2h / 3d / 1w); ' +
25
+ 'date YYYY-MM-DD (local 00:00:00); ' +
26
+ 'local datetime YYYY-MM-DDTHH:mm:ss (local timezone, T-separated); ' +
27
+ 'ISO 8601 with timezone YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss+08:00.';
28
+ /**
29
+ * 解析时间字符串到毫秒时间戳;不匹配任一支持格式抛 ARGS_INVALID。
31
30
  * 失败抛 AppError("ARGS_INVALID", ...);CLI 层用 withHelp 自动转 exit 2 + help。
32
31
  */
33
32
  function parseTimeToMs(input, now = new Date()) {
34
- // 1. 相对时间:30m / 1h / 2d / 1w
35
- const relative = /^(\d+)([mhdw])$/.exec(input);
33
+ // 1. 相对时间:30s / 30m / 1h / 2d / 1w
34
+ const relative = /^(\d+)([smhdw])$/.exec(input);
36
35
  if (relative) {
37
36
  const n = Number(relative[1]);
37
+ if (n <= 0)
38
+ failInvalidTimestamp(input);
38
39
  const unit = relative[2];
39
- const factor = unit === "m"
40
- ? 60_000
41
- : unit === "h"
42
- ? 3_600_000
43
- : unit === "d"
44
- ? 86_400_000
45
- : /* w */ 604_800_000;
40
+ const factor = unit === 's'
41
+ ? 1_000
42
+ : unit === 'm'
43
+ ? 60_000
44
+ : unit === 'h'
45
+ ? 3_600_000
46
+ : unit === 'd'
47
+ ? 86_400_000
48
+ : /* w */ 604_800_000;
46
49
  return now.getTime() - n * factor;
47
50
  }
48
51
  // 2. 纯日期:YYYY-MM-DD → 本地当日 00:00:00
49
52
  const date = /^(\d{4})-(\d{2})-(\d{2})$/.exec(input);
50
53
  if (date) {
51
- return localDateMs(input, date[1], date[2], date[3], "00", "00", "00", "0");
54
+ return localDateMs(input, date[1], date[2], date[3], '00', '00', '00', '0');
52
55
  }
53
56
  // 3. 本地日期+时间:YYYY-MM-DDTHH:mm:ss[.SSS](不带时区,T 分隔)。
54
57
  // 不接受空格分隔——'YYYY-MM-DD HH:mm:ss' 不带引号会被 shell 拆成两个参数,
@@ -57,14 +60,14 @@ function parseTimeToMs(input, now = new Date()) {
57
60
  if (localDt) {
58
61
  // capture 7 是可选 .SSS 组,运行时可能 undefined;TS lib 的 RegExp match 索引
59
62
  // 类型把它标成 string,所以这里显式 cast 让 ?? 在 lint 视角下也"必要"。
60
- const msPart = localDt[7] ?? "0";
63
+ const msPart = localDt[7] ?? '0';
61
64
  return localDateMs(input, localDt[1], localDt[2], localDt[3], localDt[4], localDt[5], localDt[6], msPart);
62
65
  }
63
66
  // 4. 带显式时区的 ISO 8601:YYYY-MM-DDTHH:mm:ss[.SSS](Z|±HH:MM|±HHMM)
64
67
  const iso = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(Z|[+-](\d{2}):?(\d{2}))$/.exec(input);
65
68
  if (iso) {
66
69
  validateDateTimeParts(input, iso[1], iso[2], iso[3], iso[4], iso[5], iso[6]);
67
- if (iso[7] !== "Z")
70
+ if (iso[7] !== 'Z')
68
71
  validateOffset(input, iso[8], iso[9]);
69
72
  const ms = Date.parse(input);
70
73
  if (Number.isNaN(ms))
@@ -76,7 +79,7 @@ function parseTimeToMs(input, now = new Date()) {
76
79
  function localDateMs(input, y, mo, d, h, mi, s, msPart) {
77
80
  validateDateTimeParts(input, y, mo, d, h, mi, s);
78
81
  // 毫秒位补齐到 3 位再截断("5" → 500,"12" → 120,"123" → 123)
79
- const ms = Number(msPart.padEnd(3, "0").slice(0, 3));
82
+ const ms = Number(msPart.padEnd(3, '0').slice(0, 3));
80
83
  const date = new Date(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s), ms);
81
84
  if (date.getFullYear() !== Number(y) ||
82
85
  date.getMonth() !== Number(mo) - 1 ||
@@ -115,7 +118,9 @@ function validateOffset(input, h, mi) {
115
118
  failInvalidTimestamp(input);
116
119
  }
117
120
  function failInvalidTimestamp(input) {
118
- throw new error_1.AppError("ARGS_INVALID", `无法解析时间 '${input}'。${exports.TIMESTAMP_HELP}`);
121
+ throw new error_1.AppError('ARGS_INVALID', `Invalid timestamp '${input}'`, {
122
+ next_actions: [exports.TIMESTAMP_HELP],
123
+ });
119
124
  }
120
125
  /** 毫秒 → 纳秒(字符串,避免 JS Number 精度丢失) */
121
126
  function msToNs(ms) {
@@ -156,21 +161,21 @@ const MS_DAY = 86_400_000;
156
161
  /** 把 ms 向下对齐到桶起点(UTC)。未识别的 bucket 原样返回。 */
157
162
  function floorMsToBucket(ms, bucket) {
158
163
  switch (bucket) {
159
- case "1m":
164
+ case '1m':
160
165
  return Math.floor(ms / MS_MIN) * MS_MIN;
161
- case "1h":
166
+ case '1h':
162
167
  return Math.floor(ms / MS_HOUR) * MS_HOUR;
163
- case "1d":
164
- case "DAY": {
168
+ case '1d':
169
+ case 'DAY': {
165
170
  const d = new Date(ms);
166
171
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
167
172
  }
168
- case "WEEK": {
173
+ case 'WEEK': {
169
174
  const d = new Date(ms);
170
175
  const offsetDays = (d.getUTCDay() + 6) % 7; // 距上一个周一的天数
171
176
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - offsetDays);
172
177
  }
173
- case "MONTH": {
178
+ case 'MONTH': {
174
179
  const d = new Date(ms);
175
180
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
176
181
  }
@@ -184,16 +189,16 @@ function ceilMsToBucket(ms, bucket) {
184
189
  if (floor === ms)
185
190
  return ms;
186
191
  switch (bucket) {
187
- case "1m":
192
+ case '1m':
188
193
  return floor + MS_MIN;
189
- case "1h":
194
+ case '1h':
190
195
  return floor + MS_HOUR;
191
- case "1d":
192
- case "DAY":
196
+ case '1d':
197
+ case 'DAY':
193
198
  return floor + MS_DAY;
194
- case "WEEK":
199
+ case 'WEEK':
195
200
  return floor + 7 * MS_DAY;
196
- case "MONTH": {
201
+ case 'MONTH': {
197
202
  const d = new Date(floor);
198
203
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);
199
204
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.4-alpha.8b6506a",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {