@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
@@ -0,0 +1,94 @@
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.handleObservabilityLog = handleObservabilityLog;
37
+ const api = __importStar(require("../../../api/index"));
38
+ const output_1 = require("../../../utils/output");
39
+ const index_1 = require("../../../api/observability/index");
40
+ const helpers_1 = require("./helpers");
41
+ /** miaoda observability log */
42
+ async function handleObservabilityLog(opts) {
43
+ const appID = opts.appId;
44
+ const appEnv = 'runtime';
45
+ const limit = (0, helpers_1.validateLimit)(opts.limit ?? 50);
46
+ // 过滤 key 对齐 BAM 查询字段名:
47
+ // - 顶层字段:severity_text / trace_id(输出仍映射成 severityText / traceID)
48
+ // - attributes 里的业务字段:module / user_id / page / api / ob_data_id(snake_case,
49
+ // 依据 BAM IDL 的 LogItem.attributes 描述:"包括 tenant_id, module, user_id, page, api 等")
50
+ // - duration_ms 暂未在 BAM 描述里明确列出,留 TODO 等 e2e 验证
51
+ const fieldFilters = (0, helpers_1.buildFieldFilters)([
52
+ { key: 'severity_text', value: opts.level ? (0, helpers_1.eqFilter)(opts.level) : undefined },
53
+ { key: 'attributes.ob_data_id', value: opts.logId ? (0, helpers_1.eqFilter)(opts.logId) : undefined },
54
+ { key: 'trace_id', value: opts.traceId ? (0, helpers_1.eqFilter)(opts.traceId) : undefined },
55
+ { key: 'module', value: opts.module ? (0, helpers_1.eqFilter)(opts.module) : undefined },
56
+ { key: 'user_id', value: opts.userId ? (0, helpers_1.eqFilter)(opts.userId, 'i64') : undefined },
57
+ { key: 'page', value: opts.page ? (0, helpers_1.eqFilter)(opts.page) : undefined },
58
+ { key: 'api', value: opts.api ? (0, helpers_1.eqFilter)(opts.api) : undefined },
59
+ {
60
+ // TODO: 确认 BAM 是否真用 duration_ms 作为 attribute key
61
+ key: 'duration_ms',
62
+ value: opts.minDuration !== undefined || opts.maxDuration !== undefined
63
+ ? (0, helpers_1.rangeFilter)({ gte: opts.minDuration, lte: opts.maxDuration })
64
+ : undefined,
65
+ },
66
+ ]);
67
+ const fuzzyFilter = opts.grep
68
+ ? {
69
+ include: {
70
+ words: [opts.grep],
71
+ operator: 1, // AND
72
+ },
73
+ }
74
+ : undefined;
75
+ const req = {
76
+ appID,
77
+ appEnv,
78
+ startTimestampNs: (0, helpers_1.parseToNs)(opts.since),
79
+ endTimestampNs: (0, helpers_1.parseToNs)(opts.until),
80
+ limit,
81
+ pageToken: opts.cursor,
82
+ fieldFilters,
83
+ fuzzyFilter,
84
+ };
85
+ const resp = await api.observability.searchLogs(req);
86
+ emitSearchLogsResponse(resp);
87
+ }
88
+ function emitSearchLogsResponse(resp) {
89
+ (0, output_1.emit)({
90
+ data: resp.logItems ?? [],
91
+ next_cursor: resp.hasMore ? resp.nextPageToken : null,
92
+ has_more: resp.hasMore,
93
+ }, index_1.logItemSchema);
94
+ }
@@ -0,0 +1,208 @@
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.handleObservabilityMetric = handleObservabilityMetric;
37
+ const api = __importStar(require("../../../api/index"));
38
+ const output_1 = require("../../../utils/output");
39
+ const args_1 = require("../../../utils/args");
40
+ const helpers_1 = require("./helpers");
41
+ /**
42
+ * PRD <metric-name> + --series → 服务端 metric name → 表头列名(=对应 --series 取值)。
43
+ *
44
+ * - 缺省 --series 时返回该 cliName 下所有相关线。
45
+ * - latency / requests 的 error 线 v1.0.122 起由独立 metric 提供(不再 is_error filter)。
46
+ *
47
+ * 表头标签直接用 --series 名("total"/"error"/"p50"/"p99");单一指标则用 cliName。
48
+ */
49
+ const METRIC_LABELS = {
50
+ cpu: { cpu_usage: 'cpu' },
51
+ memory: { mem_usage: 'memory' },
52
+ requests: {
53
+ client_api_request_count: 'total',
54
+ client_api_request_error_count: 'error',
55
+ },
56
+ latency: {
57
+ client_api_request_latency_p50: 'p50',
58
+ client_api_request_latency_p99: 'p99',
59
+ },
60
+ };
61
+ /** miaoda observability metric <metric-name> */
62
+ async function handleObservabilityMetric(opts) {
63
+ if (!opts.metricName)
64
+ (0, args_1.failArgs)('<metric-name> 必填');
65
+ const appID = opts.appId;
66
+ const { metricNames, labelByMetric, extraFilters } = resolveMetricSelection(opts.metricName, opts.series);
67
+ const filters = (0, helpers_1.buildFieldFilters)([
68
+ { key: 'referer_path', value: opts.page ? (0, helpers_1.eqFilter)(opts.page) : undefined },
69
+ { key: 'api', value: opts.api ? (0, helpers_1.eqFilter)(opts.api) : undefined },
70
+ ...extraFilters,
71
+ ]);
72
+ // since/until 直接以秒透传到 BAM;当前未做桶对齐(如需开启把 until
73
+ // 用 ceilMsToBucket(untilMs, downSample as GranularityBucket) 包一层即可)。
74
+ const downSample = opts.downSample ?? '1m';
75
+ const nowMs = Date.now();
76
+ const sinceMs = (0, helpers_1.parseToMs)(opts.since) ?? nowMs - 30 * 86_400_000;
77
+ const untilMs = (0, helpers_1.parseToMs)(opts.until) ?? nowMs;
78
+ const req = {
79
+ appID,
80
+ appEnv: 'runtime',
81
+ metricNames,
82
+ startTimestamp: (0, helpers_1.msToSec)(sinceMs),
83
+ endTimestamp: (0, helpers_1.msToSec)(untilMs),
84
+ filters,
85
+ downSample,
86
+ needPackLackPoint: false,
87
+ };
88
+ const resp = await api.observability.queryMetricsData(req);
89
+ // requests 的 count / error_count:
90
+ // - BAM 在该时间点无数据时会传 null,或者 values 里干脆缺 key
91
+ // - CLI 按"请求过的 metricNames"逐一兜底为 0,让"没有请求"和"没有数据"
92
+ // 在表格 / JSON 里都显式呈现成 0,避免空格 / 缺字段被误解为缺失
93
+ // latency / cpu / memory 不做这个兜底——p50 没数据 ≠ 延迟为 0。
94
+ if (opts.metricName === 'requests') {
95
+ fillRequestedMetricsWithZero(resp, metricNames);
96
+ }
97
+ emitMetricsResponse(resp, labelByMetric);
98
+ }
99
+ /**
100
+ * 按"客户端请求过的 metricNames"兜底缺失/为 null 的值为 0;不去动 BAM 多返回的
101
+ * 其他字段(防御性,避免误改不属于本次查询的数据)。
102
+ */
103
+ function fillRequestedMetricsWithZero(resp, requestedMetricNames) {
104
+ for (const point of resp.points ?? []) {
105
+ for (const name of requestedMetricNames) {
106
+ point.values[name] ??= 0;
107
+ }
108
+ }
109
+ }
110
+ // ── 渲染 ─────────
111
+ //
112
+ // BAM v1.0.123 起返回 points: [{timestamp, dimensions, values: {metricName: v}}]——
113
+ // 服务端已把多 metric 合并到同 timestamp 的 row,下游直接平铺即可。
114
+ // JSON 模式:原样透传 points(保留 BAM 原 metricName 作为 values 的 key)。
115
+ // Pretty 模式:把 values 里的 metricName 重命名成 CLI label(p50/p99/total 等),
116
+ // 再走 buildPivotSchema 渲染。
117
+ function emitMetricsResponse(resp, labelByMetric) {
118
+ const points = resp.points ?? [];
119
+ // metric 不分页,但仍补齐 has_more / next_cursor 以对齐 log/trace 的信封形状
120
+ if ((0, output_1.isJsonMode)()) {
121
+ (0, output_1.emit)({ data: points, next_cursor: null, has_more: false });
122
+ return;
123
+ }
124
+ const { rows, seriesLabels } = renameAndSort(points, labelByMetric);
125
+ if (rows.length === 0) {
126
+ (0, output_1.emit)({ data: [], next_cursor: null, has_more: false });
127
+ return;
128
+ }
129
+ const hasLatency = Object.keys(labelByMetric).some((n) => n.includes('latency'));
130
+ (0, output_1.emit)({ data: rows, next_cursor: null, has_more: false }, buildPivotSchema(seriesLabels, hasLatency));
131
+ }
132
+ function renameAndSort(points, labelByMetric) {
133
+ // 列顺序按 labelByMetric 声明顺序,避免 BAM 返回顺序波动影响表头
134
+ const seriesLabels = Object.values(labelByMetric);
135
+ // TODO: 当 dimensions 非空(groupBy 多 series)时,把 dimensions 也并入 row
136
+ const rows = points.map((point) => {
137
+ const row = { timestamp: point.timestamp };
138
+ for (const [metricName, value] of Object.entries(point.values)) {
139
+ const label = labelByMetric[metricName] ?? metricName;
140
+ row[label] = value;
141
+ }
142
+ return row;
143
+ });
144
+ // 按时间倒序,与 log/trace 的"最新在前"风格一致
145
+ rows.sort((a, b) => b.timestamp - a.timestamp);
146
+ return { rows, seriesLabels };
147
+ }
148
+ function buildPivotSchema(seriesLabels, hasLatency) {
149
+ const valueFormat = hasLatency ? output_1.fmt.durationMs() : undefined;
150
+ return {
151
+ columns: [
152
+ { key: 'timestamp', label: 'time', format: output_1.fmt.sec() },
153
+ ...seriesLabels.map((label) => ({
154
+ key: label,
155
+ label,
156
+ ...(valueFormat ? { format: valueFormat } : {}),
157
+ })),
158
+ ],
159
+ strict: true,
160
+ };
161
+ }
162
+ /**
163
+ * 解析 <metric-name> + --series 的组合:决定最终 metricNames、表头 label 映射、附加过滤。
164
+ *
165
+ * label 直接用 --series 取值("total"/"error"/"p50"/"p99");单一指标 cliName 也作为 label。
166
+ */
167
+ function resolveMetricSelection(cliName, series) {
168
+ const extras = [];
169
+ if (cliName === 'latency') {
170
+ if (series === 'p99') {
171
+ return single('client_api_request_latency_p99', 'p99', extras);
172
+ }
173
+ if (series === 'p50') {
174
+ return single('client_api_request_latency_p50', 'p50', extras);
175
+ }
176
+ return all(METRIC_LABELS.latency, extras);
177
+ }
178
+ if (cliName === 'requests') {
179
+ // v1.0.122 起 error 线由独立 metric 提供,不再走 is_error filter
180
+ if (series === 'total') {
181
+ return single('client_api_request_count', 'total', extras);
182
+ }
183
+ if (series === 'error') {
184
+ return single('client_api_request_error_count', 'error', extras);
185
+ }
186
+ return all(METRIC_LABELS.requests, extras);
187
+ }
188
+ if (cliName === 'cpu')
189
+ return all(METRIC_LABELS.cpu, extras);
190
+ if (cliName === 'memory')
191
+ return all(METRIC_LABELS.memory, extras);
192
+ // 兜底:CLI 名直接作为 metric name + label
193
+ return single(cliName, cliName, extras);
194
+ }
195
+ function single(metricName, label, extras) {
196
+ return {
197
+ metricNames: [metricName],
198
+ labelByMetric: { [metricName]: label },
199
+ extraFilters: extras,
200
+ };
201
+ }
202
+ function all(labelByMetric, extras) {
203
+ return {
204
+ metricNames: Object.keys(labelByMetric),
205
+ labelByMetric,
206
+ extraFilters: extras,
207
+ };
208
+ }
@@ -0,0 +1,102 @@
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.handleObservabilityTraceList = handleObservabilityTraceList;
37
+ exports.handleObservabilityTraceGet = handleObservabilityTraceGet;
38
+ const api = __importStar(require("../../../api/index"));
39
+ const output_1 = require("../../../utils/output");
40
+ const args_1 = require("../../../utils/args");
41
+ const index_1 = require("../../../api/observability/index");
42
+ const helpers_1 = require("./helpers");
43
+ /** miaoda observability trace list */
44
+ async function handleObservabilityTraceList(opts) {
45
+ const appID = opts.appId;
46
+ const appEnv = 'runtime';
47
+ const limit = (0, helpers_1.validateLimit)(opts.limit ?? 50);
48
+ // 过滤 key 对齐 BAM Span 字段名:
49
+ // - 顶层字段:traceID(注意大小写)
50
+ // - attributes 业务字段:user_id(snake_case)
51
+ // - 入口 span:BAM 没有 entrySpanName fieldFilter,统一走 fuzzyFilter(trace endpoint
52
+ // 默认作用于 span name),所以 --root-span 不进 fieldFilters
53
+ const fieldFilters = (0, helpers_1.buildFieldFilters)([
54
+ { key: 'trace_id', value: opts.traceId ? (0, helpers_1.eqFilter)(opts.traceId) : undefined },
55
+ { key: 'user_id', value: opts.userId ? (0, helpers_1.eqFilter)(opts.userId, 'i64') : undefined },
56
+ ]);
57
+ const req = {
58
+ appID,
59
+ appEnv,
60
+ startTimestampNs: (0, helpers_1.parseToNs)(opts.since),
61
+ endTimestampNs: (0, helpers_1.parseToNs)(opts.until),
62
+ limit,
63
+ pageToken: opts.cursor,
64
+ fieldFilters,
65
+ fuzzyFilter: opts.rootSpan ? (0, helpers_1.fuzzyFilter)(opts.rootSpan) : undefined,
66
+ };
67
+ const resp = await api.observability.searchTraces(req);
68
+ emitSearchTracesResponse(resp);
69
+ }
70
+ function emitSearchTracesResponse(resp) {
71
+ (0, output_1.emit)({
72
+ data: resp.spans ?? [],
73
+ next_cursor: resp.hasMore ? resp.nextPageToken : null,
74
+ has_more: resp.hasMore,
75
+ }, index_1.spanSchema);
76
+ }
77
+ /** miaoda observability trace get <trace-id> */
78
+ async function handleObservabilityTraceGet(opts) {
79
+ if (!opts.traceId)
80
+ (0, args_1.failArgs)('<trace-id> 必填');
81
+ const appID = opts.appId;
82
+ const appEnv = 'runtime';
83
+ const resp = await api.observability.getTraces({
84
+ appID,
85
+ appEnv,
86
+ traceID: opts.traceId,
87
+ withLogSeverityCount: opts.withLogSeverityCount,
88
+ });
89
+ emitGetTraceResponse(resp);
90
+ }
91
+ function emitGetTraceResponse(resp) {
92
+ // JSON 模式:保持单条信封语义,便于下游一次解析
93
+ if ((0, output_1.isJsonMode)()) {
94
+ (0, output_1.emit)({
95
+ data: { spans: resp.spans ?? [], isBreak: resp.isBreak },
96
+ });
97
+ return;
98
+ }
99
+ // Pretty 模式:先打头部 key-value(断链状态等元信息),再按 spanSchema 渲染主表
100
+ (0, output_1.emit)({ data: { isBreak: resp.isBreak } });
101
+ (0, output_1.emit)({ data: resp.spans ?? [] }, index_1.spanSchema);
102
+ }