@lark-apaas/miaoda-cli 0.1.0-alpha.8825a76 → 0.1.0-alpha.bc5586f

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.
@@ -5,8 +5,6 @@ exports.getSchema = getSchema;
5
5
  exports.importData = importData;
6
6
  exports.exportData = exportData;
7
7
  const http_1 = require("../../utils/http");
8
- // TODO(REMOVE-BEFORE-RELEASE): debug-only HTTP trace(详见 _debug_trace.ts)
9
- const _debug_trace_1 = require("./_debug_trace");
10
8
  const error_1 = require("../../utils/error");
11
9
  const client_1 = require("./client");
12
10
  // CLI 不再为 dbBranch 设默认值:
@@ -26,9 +24,7 @@ async function execSql(opts) {
26
24
  const url = (0, client_1.buildInnerUrl)(opts.appId, "/db/sql", {
27
25
  dbBranch: opts.dbBranch,
28
26
  });
29
- (0, _debug_trace_1.traceRequest)("POST", url);
30
27
  const response = await client.post(url, { sql: opts.sql });
31
- (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
32
28
  if (!response.ok) {
33
29
  // 4xx / 5xx:尝试解析 body 取 status_code 映射业务错误
34
30
  let body = null;
@@ -61,9 +57,7 @@ async function getSchema(opts) {
61
57
  includeStats: opts.includeStats ? "true" : undefined,
62
58
  dbBranch: opts.dbBranch,
63
59
  });
64
- (0, _debug_trace_1.traceRequest)("GET", url);
65
60
  const response = await client.get(url);
66
- (0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
67
61
  if (!response.ok) {
68
62
  let body = null;
69
63
  try {
@@ -95,14 +89,12 @@ async function importData(opts) {
95
89
  });
96
90
  const contentType = opts.format === "csv" ? "text/csv" : "application/json";
97
91
  const ab = opts.body.buffer.slice(opts.body.byteOffset, opts.body.byteOffset + opts.body.byteLength);
98
- (0, _debug_trace_1.traceRequest)("POST", url);
99
92
  const response = await client.request({
100
93
  method: "POST",
101
94
  url,
102
95
  headers: { "Content-Type": contentType },
103
96
  body: ab,
104
97
  });
105
- (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
106
98
  if (!response.ok) {
107
99
  let body = null;
108
100
  try {
@@ -139,9 +131,7 @@ async function exportData(opts) {
139
131
  dbBranch: opts.dbBranch,
140
132
  });
141
133
  const reqBody = { limit: opts.limit ?? 5000 };
142
- (0, _debug_trace_1.traceRequest)("POST", url);
143
134
  const response = await client.post(url, reqBody);
144
- (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
145
135
  if (!response.ok) {
146
136
  // 错误路径:body 是 JSON envelope
147
137
  let body = null;
@@ -27,11 +27,10 @@ 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 === "DML") {
31
31
  const affected = r.affectedRows ?? extractRowCount(r.data);
32
32
  return {
33
33
  kind: "dml",
34
- sqlType: r.sqlType,
35
34
  affectedRows: affected,
36
35
  };
37
36
  }
@@ -8,8 +8,6 @@ exports.doPost = doPost;
8
8
  exports.doRequest = doRequest;
9
9
  const http_1 = require("../../utils/http");
10
10
  const error_1 = require("../../utils/error");
11
- // TODO(REMOVE-BEFORE-RELEASE): debug-only HTTP trace(详见 _debug_trace.ts)
12
- const _debug_trace_1 = require("./_debug_trace");
13
11
  const http_client_1 = require("@lark-apaas/http-client");
14
12
  /** 进程内 bucket 缓存:{appId: bucketId}。不跨进程。 */
15
13
  const bucketCache = new Map();
@@ -133,15 +131,10 @@ async function mapHttpError(err, opts) {
133
131
  */
134
132
  async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
135
133
  try {
136
- (0, _debug_trace_1.traceRequest)("GET", url);
137
134
  const response = await client.get(url);
138
- (0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
139
135
  return (await response.json());
140
136
  }
141
137
  catch (err) {
142
- if (err instanceof http_client_1.HttpError && err.response) {
143
- (0, _debug_trace_1.traceResponse)("GET", url, err.response.status, err.response.headers);
144
- }
145
138
  await mapHttpError(err, opts);
146
139
  throw err; // 不可达,mapHttpError 必定 throw
147
140
  }
@@ -149,15 +142,10 @@ async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
149
142
  /** 包一层 client.post + HttpError 统一映射。默认 admin innerapi,可显式切 runtime。 */
150
143
  async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()) {
151
144
  try {
152
- (0, _debug_trace_1.traceRequest)("POST", url);
153
145
  const response = await client.post(url, body);
154
- (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
155
146
  return (await response.json());
156
147
  }
157
148
  catch (err) {
158
- if (err instanceof http_client_1.HttpError && err.response) {
159
- (0, _debug_trace_1.traceResponse)("POST", url, err.response.status, err.response.headers);
160
- }
161
149
  await mapHttpError(err, opts);
162
150
  throw err;
163
151
  }
@@ -165,15 +153,10 @@ async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()
165
153
  /** 包一层 client.request + HttpError 统一映射(DELETE 带 body 的场景)。 */
166
154
  async function doRequest(cfg, opts = {}, client = (0, http_1.getHttpClient)()) {
167
155
  try {
168
- (0, _debug_trace_1.traceRequest)(cfg.method, cfg.url);
169
156
  const response = await client.request(cfg);
170
- (0, _debug_trace_1.traceResponse)(cfg.method, cfg.url, response.status, response.headers);
171
157
  return (await response.json());
172
158
  }
173
159
  catch (err) {
174
- if (err instanceof http_client_1.HttpError && err.response) {
175
- (0, _debug_trace_1.traceResponse)(cfg.method, cfg.url, err.response.status, err.response.headers);
176
- }
177
160
  await mapHttpError(err, opts);
178
161
  throw err;
179
162
  }
@@ -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
- /** 解析 appId,CLI flag > env > 抛错 */
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: [
@@ -80,7 +80,7 @@ async function handleDbSql(query, opts) {
80
80
  }
81
81
  // 其他场景:展示最后一条
82
82
  const last = results[results.length - 1];
83
- renderSingle(last);
83
+ renderSingle(last, sql);
84
84
  }
85
85
  /** 读取 stdin 并返回完整 SQL 文本(stdin 不是 TTY 即认为被 pipe)。 */
86
86
  async function readSql(inline) {
@@ -101,11 +101,11 @@ async function readSql(inline) {
101
101
  process.stdin.on("error", reject);
102
102
  });
103
103
  }
104
- function renderSingle(raw) {
104
+ function renderSingle(raw, originalSql) {
105
105
  const parsed = (0, index_1.parseSqlResult)(raw);
106
106
  const tty = (0, render_1.isStdoutTty)();
107
107
  if ((0, output_1.isJsonMode)()) {
108
- (0, output_1.emit)(toJson(parsed));
108
+ (0, output_1.emit)(toJson(parsed, originalSql));
109
109
  return;
110
110
  }
111
111
  if (parsed.kind === "select") {
@@ -119,7 +119,7 @@ function renderSingle(raw) {
119
119
  return;
120
120
  }
121
121
  if (parsed.kind === "dml") {
122
- const verb = dmlVerb(parsed.sqlType);
122
+ const verb = dmlVerb(originalSql);
123
123
  (0, output_1.emit)(tty
124
124
  ? `✓ ${String(parsed.affectedRows)} row${parsed.affectedRows === 1 ? "" : "s"} ${verb}`
125
125
  : `OK ${String(parsed.affectedRows)} rows ${verb}`);
@@ -128,26 +128,46 @@ function renderSingle(raw) {
128
128
  // DDL
129
129
  (0, output_1.emit)(tty ? "✓ DDL executed" : "OK DDL executed");
130
130
  }
131
- function toJson(parsed) {
131
+ function toJson(parsed, originalSql) {
132
132
  if (parsed.kind === "select") {
133
133
  return { data: parsed.rows };
134
134
  }
135
135
  if (parsed.kind === "dml") {
136
+ const op = dmlOp(originalSql);
136
137
  return {
137
138
  data: {
138
- sql_type: parsed.sqlType.toLowerCase(),
139
+ sql_type: op ?? "dml",
139
140
  affected_rows: parsed.affectedRows,
140
141
  },
141
142
  };
142
143
  }
143
144
  return { data: { sql_type: "ddl" } };
144
145
  }
145
- function dmlVerb(type) {
146
- switch (type) {
147
- case "INSERT": return "inserted";
148
- case "UPDATE": return "updated";
149
- case "DELETE": return "deleted";
150
- }
146
+ /**
147
+ * 从原始 SQL 推断 DML 动词。后端只回 "DML" 笼统类型,要给用户展示具体
148
+ * "inserted/updated/deleted" 必须 CLI 侧解析。多语句时取最后一条非空
149
+ * statement(与 PRD "只展示最后一条结果" 对齐)。
150
+ */
151
+ function dmlOp(originalSql) {
152
+ const stmts = originalSql.split(";").map((s) => s.trim()).filter((s) => s.length > 0);
153
+ const head = (stmts[stmts.length - 1] ?? "").toUpperCase();
154
+ if (head.startsWith("INSERT"))
155
+ return "insert";
156
+ if (head.startsWith("UPDATE"))
157
+ return "update";
158
+ if (head.startsWith("DELETE"))
159
+ return "delete";
160
+ return null;
161
+ }
162
+ function dmlVerb(originalSql) {
163
+ const op = dmlOp(originalSql);
164
+ if (op === "insert")
165
+ return "inserted";
166
+ if (op === "update")
167
+ return "updated";
168
+ if (op === "delete")
169
+ return "deleted";
170
+ return "affected";
151
171
  }
152
172
  /** 从第一行收集列顺序;缺失列保留空白(兼容稀疏行)。 */
153
173
  function collectColumns(rows) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.0-alpha.8825a76",
3
+ "version": "0.1.0-alpha.bc5586f",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.traceRequest = traceRequest;
4
- exports.traceResponse = traceResponse;
5
- /**
6
- * ⚠️ TODO(REMOVE-BEFORE-RELEASE): 调试用 HTTP trace。
7
- *
8
- * 仅在 `--verbose` 下把 db 域 admin-inner 请求的 URL 与后端 logid 打到 stderr,
9
- * 方便联调时把 logid 贴给后端查链路。正式版本前请整文件删除,并把
10
- * `src/api/db/{api,client}.ts` 里的 `traceRequest()` / `traceResponse()` 调用一并移除。
11
- */
12
- const logger_1 = require("../../utils/logger");
13
- /** 请求前打 method + 完整 URL(不含敏感 header)。 */
14
- function traceRequest(method, url) {
15
- (0, logger_1.debug)(`http → ${method} ${url}`);
16
- }
17
- /** 响应后打 status + x-tt-logid(后端追踪 ID)。 */
18
- function traceResponse(method, url, status, headers) {
19
- const logId = headers?.get("x-tt-logid") ?? headers?.get("X-Tt-Logid") ?? "(none)";
20
- (0, logger_1.debug)(`http ← ${method} ${url} status=${String(status)} x-tt-logid=${logId}`);
21
- }
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.traceRequest = traceRequest;
4
- exports.traceResponse = traceResponse;
5
- /**
6
- * ⚠️ TODO(REMOVE-BEFORE-RELEASE): 调试用 HTTP trace。
7
- *
8
- * 仅在 `--verbose` 下把 file 域请求的 URL 与后端 logid 打到 stderr,
9
- * 方便联调时把 logid 贴给后端查链路。正式版本前请整文件删除,并把
10
- * `src/api/file/client.ts` 里的 `traceRequest()` / `traceResponse()` 调用一并移除。
11
- */
12
- const logger_1 = require("../../utils/logger");
13
- /** 请求前打 method + 完整 URL(不含敏感 header)。 */
14
- function traceRequest(method, url) {
15
- (0, logger_1.debug)(`http → ${method} ${url}`);
16
- }
17
- /** 响应后打 status + x-tt-logid(后端追踪 ID)。 */
18
- function traceResponse(method, url, status, headers) {
19
- const logId = headers?.get("x-tt-logid") ?? headers?.get("X-Tt-Logid") ?? "(none)";
20
- (0, logger_1.debug)(`http ← ${method} ${url} status=${String(status)} x-tt-logid=${logId}`);
21
- }