@lark-apaas/miaoda-cli 0.1.0-alpha.c11e8f1 → 0.1.0-alpha.ca2912e
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/api/db/client.js
CHANGED
|
@@ -19,7 +19,7 @@ function ensureInnerSuccess(body) {
|
|
|
19
19
|
const code = body.status_code ?? body.ErrorCode ?? "0";
|
|
20
20
|
if (code === "0" || code === "")
|
|
21
21
|
return;
|
|
22
|
-
const message = body.error_msg ?? body.ErrorMessage ?? `dataloom API error [${code}]
|
|
22
|
+
const message = stripPgPrefix(body.error_msg ?? body.ErrorMessage ?? `dataloom API error [${code}]`);
|
|
23
23
|
// k_dl_1300002 是 PG 执行透传错误;error_msg 里常带 SQLSTATE,优先按 SQLSTATE 映射
|
|
24
24
|
if (code === "k_dl_1300002") {
|
|
25
25
|
const sqlstate = extractSqlstate(message);
|
|
@@ -49,6 +49,14 @@ function ensureInnerSuccess(body) {
|
|
|
49
49
|
// 兜底:dataloom 未映射的 code 原样透传
|
|
50
50
|
throw new error_1.AppError(`DB_API_${code}`, message);
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* 剥掉 PG 透传错误的 "ERROR:" 前缀:CLI 输出本身就会前缀 "Error:",
|
|
54
|
+
* 不去掉就会变成 `Error: ERROR: relation ...` 双重前缀,PRD 不要这种冗余。
|
|
55
|
+
* 大小写敏感,只匹配 PG 标准格式。
|
|
56
|
+
*/
|
|
57
|
+
function stripPgPrefix(msg) {
|
|
58
|
+
return msg.replace(/^ERROR:\s*/, "");
|
|
59
|
+
}
|
|
52
60
|
/** 从 PG 执行错误消息里提取 "(SQLSTATE XXXXX)"。 */
|
|
53
61
|
function extractSqlstate(msg) {
|
|
54
62
|
const m = /SQLSTATE\s+([0-9A-Z]{5})/.exec(msg);
|
package/dist/api/db/parsers.js
CHANGED
|
@@ -27,7 +27,7 @@ function parseSqlResult(r) {
|
|
|
27
27
|
recordCount: r.recordCount ?? rows.length,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
if (r.sqlType === "INSERT" || r.sqlType === "UPDATE" || r.sqlType === "DELETE") {
|
|
30
|
+
if (r.sqlType === "INSERT" || r.sqlType === "UPDATE" || r.sqlType === "DELETE" || r.sqlType === "DML") {
|
|
31
31
|
const affected = r.affectedRows ?? extractRowCount(r.data);
|
|
32
32
|
return {
|
|
33
33
|
kind: "dml",
|
|
@@ -7,7 +7,9 @@ exports.withHelp = withHelp;
|
|
|
7
7
|
exports.failArgs = failArgs;
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const error_1 = require("../../utils/error");
|
|
10
|
-
/** --app-id option,需要应用上下文的命令自行 .addOption(appIdOption())
|
|
10
|
+
/** --app-id option,需要应用上下文的命令自行 .addOption(appIdOption())。
|
|
11
|
+
* Commander 的 .env() 只接受单个变量名,第二个兜底 `app_id` 在 resolveAppId 里手动检查。
|
|
12
|
+
*/
|
|
11
13
|
function appIdOption() {
|
|
12
14
|
return new commander_1.Option("--app-id <id>", "指定目标应用").env("MIAODA_APP_ID");
|
|
13
15
|
}
|
|
@@ -17,9 +19,12 @@ function appIdOption() {
|
|
|
17
19
|
function softRequiredOption(name, desc) {
|
|
18
20
|
return new commander_1.Option(name, desc);
|
|
19
21
|
}
|
|
20
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* 解析 appId,优先级:CLI flag > MIAODA_APP_ID > app_id > 抛错。
|
|
24
|
+
* app_id 是部分外部沙箱环境注入应用 ID 的别名,作为兜底兼容(小写下划线形态)。
|
|
25
|
+
*/
|
|
21
26
|
function resolveAppId(opts) {
|
|
22
|
-
const id = opts.appId ?? process.env.MIAODA_APP_ID;
|
|
27
|
+
const id = opts.appId ?? process.env.MIAODA_APP_ID ?? process.env.app_id;
|
|
23
28
|
if (!id) {
|
|
24
29
|
throw new error_1.AppError("APP_ID_MISSING", "未指定应用", {
|
|
25
30
|
next_actions: [
|
|
@@ -133,20 +133,22 @@ function toJson(parsed) {
|
|
|
133
133
|
return { data: parsed.rows };
|
|
134
134
|
}
|
|
135
135
|
if (parsed.kind === "dml") {
|
|
136
|
+
// PRD:DML 时 data = {command: "UPDATE", rows_affected: 3}
|
|
136
137
|
return {
|
|
137
138
|
data: {
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
command: parsed.sqlType,
|
|
140
|
+
rows_affected: parsed.affectedRows,
|
|
140
141
|
},
|
|
141
142
|
};
|
|
142
143
|
}
|
|
143
|
-
return { data: {
|
|
144
|
+
return { data: { command: "DDL" } };
|
|
144
145
|
}
|
|
145
146
|
function dmlVerb(type) {
|
|
146
147
|
switch (type) {
|
|
147
148
|
case "INSERT": return "inserted";
|
|
148
149
|
case "UPDATE": return "updated";
|
|
149
150
|
case "DELETE": return "deleted";
|
|
151
|
+
case "DML": return "affected"; // MERGE / 未识别子类的兜底
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
/** 从第一行收集列顺序;缺失列保留空白(兼容稀疏行)。 */
|
package/dist/utils/output.js
CHANGED
|
@@ -32,19 +32,19 @@ function emit(data) {
|
|
|
32
32
|
/**
|
|
33
33
|
* 输出错误(写入 stderr)
|
|
34
34
|
* - pretty 模式:Error: message\n hint: ...
|
|
35
|
-
* - json 模式:{
|
|
35
|
+
* - json 模式:PRD 约定 envelope 为 `{error: {code, message, hint?}}`
|
|
36
36
|
*/
|
|
37
37
|
function emitError(err) {
|
|
38
38
|
const info = toErrorInfo(err);
|
|
39
39
|
if (isJsonMode()) {
|
|
40
|
-
const
|
|
41
|
-
|
|
40
|
+
const errObj = {
|
|
41
|
+
code: info.code,
|
|
42
42
|
message: info.message,
|
|
43
43
|
};
|
|
44
44
|
if (info.next_actions && info.next_actions.length > 0) {
|
|
45
|
-
|
|
45
|
+
errObj.hint = info.next_actions.join(" ");
|
|
46
46
|
}
|
|
47
|
-
process.stderr.write(JSON.stringify(
|
|
47
|
+
process.stderr.write(JSON.stringify({ error: errObj }) + "\n");
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
50
|
process.stderr.write(`Error: ${info.message}\n`);
|
package/dist/utils/render.js
CHANGED
|
@@ -71,9 +71,39 @@ function formatTime(iso, isTty) {
|
|
|
71
71
|
* 算进列宽(比如 dim "NULL" 实际占 4 字符但 .length=11),导致表格对齐错位。
|
|
72
72
|
*/
|
|
73
73
|
const ANSI_SGR_RE = /\[[0-9;]*m/g;
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* 单字符的终端列宽:CJK 全角字符(汉字/假名/全角符号等)占 2 列,其它占 1 列。
|
|
76
|
+
* 对齐 Unicode East Asian Width 的 W/F 类,等价于 wcwidth 简化版。
|
|
77
|
+
* 不实现合字 / 零宽字符(ZWJ / 变体选择符)等极端情况,CLI 表格场景够用。
|
|
78
|
+
*/
|
|
79
|
+
function charWidth(cp) {
|
|
80
|
+
if ((cp >= 0x1100 && cp <= 0x115F) || // Hangul Jamo
|
|
81
|
+
cp === 0x2329 || cp === 0x232A ||
|
|
82
|
+
(cp >= 0x2E80 && cp <= 0x303E) || // CJK Radicals / Punctuation
|
|
83
|
+
(cp >= 0x3041 && cp <= 0x33FF) || // Hiragana / Katakana / CJK Symbols
|
|
84
|
+
(cp >= 0x3400 && cp <= 0x4DBF) || // CJK Ext A
|
|
85
|
+
(cp >= 0x4E00 && cp <= 0x9FFF) || // CJK Unified
|
|
86
|
+
(cp >= 0xA000 && cp <= 0xA4CF) || // Yi
|
|
87
|
+
(cp >= 0xAC00 && cp <= 0xD7A3) || // Hangul Syllables
|
|
88
|
+
(cp >= 0xF900 && cp <= 0xFAFF) || // CJK Compat Ideographs
|
|
89
|
+
(cp >= 0xFE30 && cp <= 0xFE4F) || // CJK Compat Forms
|
|
90
|
+
(cp >= 0xFF00 && cp <= 0xFF60) || // Fullwidth Forms
|
|
91
|
+
(cp >= 0xFFE0 && cp <= 0xFFE6) ||
|
|
92
|
+
(cp >= 0x20000 && cp <= 0x2FFFD) || // CJK Ext B-F
|
|
93
|
+
(cp >= 0x30000 && cp <= 0x3FFFD) // CJK Ext G-H
|
|
94
|
+
) {
|
|
95
|
+
return 2;
|
|
96
|
+
}
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
/** cell 可见字符宽度:剥离 ANSI 转义后按终端列宽逐字符累加(CJK 算 2 列)。 */
|
|
75
100
|
function visibleWidth(s) {
|
|
76
|
-
|
|
101
|
+
const stripped = s.replace(ANSI_SGR_RE, "");
|
|
102
|
+
let w = 0;
|
|
103
|
+
for (const c of stripped) {
|
|
104
|
+
w += charWidth(c.codePointAt(0) ?? 0);
|
|
105
|
+
}
|
|
106
|
+
return w;
|
|
77
107
|
}
|
|
78
108
|
function padVisibleEnd(s, targetWidth) {
|
|
79
109
|
const w = visibleWidth(s);
|