@lark-apaas/miaoda-cli 0.1.0-alpha.c783fb5

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.
@@ -0,0 +1,308 @@
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.handlePluginInstall = handlePluginInstall;
37
+ exports.handlePluginUpdate = handlePluginUpdate;
38
+ exports.handlePluginRemove = handlePluginRemove;
39
+ exports.handlePluginInit = handlePluginInit;
40
+ exports.handlePluginList = handlePluginList;
41
+ exports.handlePluginListPlugins = handlePluginListPlugins;
42
+ const api = __importStar(require("../../../api/index"));
43
+ const output_1 = require("../../../utils/output");
44
+ const error_1 = require("../../../utils/error");
45
+ const logger_1 = require("../../../utils/logger");
46
+ const plugin_local_1 = require("./plugin-local");
47
+ const log = (msg) => { (0, logger_1.log)("plugin", msg); };
48
+ // ── Install ──
49
+ function syncActionPluginsRecord(name, version) {
50
+ const plugins = (0, plugin_local_1.readActionPlugins)();
51
+ if (plugins[name] !== version) {
52
+ plugins[name] = version;
53
+ (0, plugin_local_1.writeActionPlugins)(plugins);
54
+ log(`Synced record: ${name}@${version}`);
55
+ }
56
+ }
57
+ async function installOne(nameWithVersion) {
58
+ const { name, version: requestedVersion } = (0, plugin_local_1.parsePluginName)(nameWithVersion);
59
+ try {
60
+ log(`Installing ${name}@${requestedVersion}...`);
61
+ const actualVersion = (0, plugin_local_1.getPackageVersion)(name);
62
+ if (actualVersion && requestedVersion !== "latest") {
63
+ if (actualVersion === requestedVersion) {
64
+ log(`${name}@${requestedVersion} already installed`);
65
+ syncActionPluginsRecord(name, actualVersion);
66
+ api.plugin.reportCreateInstanceEvent(name, actualVersion).catch(() => { });
67
+ return { name, version: actualVersion, success: true, skipped: true };
68
+ }
69
+ }
70
+ let targetVersion = requestedVersion;
71
+ if (requestedVersion === "latest") {
72
+ const latestInfo = await api.plugin.getPluginVersion(name, "latest");
73
+ targetVersion = latestInfo.version;
74
+ if (actualVersion === targetVersion) {
75
+ log(`${name} already up to date (${actualVersion})`);
76
+ syncActionPluginsRecord(name, actualVersion);
77
+ api.plugin.reportCreateInstanceEvent(name, actualVersion).catch(() => { });
78
+ return { name, version: actualVersion, success: true, skipped: true };
79
+ }
80
+ log(`Found newer version: ${targetVersion} (installed: ${actualVersion ?? "none"})`);
81
+ }
82
+ let tgzPath;
83
+ let fromCache = false;
84
+ if (api.plugin.hasCachedPlugin(name, targetVersion)) {
85
+ log(`Using cached ${name}@${targetVersion}`);
86
+ tgzPath = api.plugin.getCachePath(name, targetVersion);
87
+ fromCache = true;
88
+ }
89
+ else {
90
+ log(`Downloading ${name}@${targetVersion}...`);
91
+ const downloadResult = await api.plugin.downloadPlugin(name, requestedVersion);
92
+ tgzPath = downloadResult.tgzPath;
93
+ }
94
+ log("Extracting to node_modules...");
95
+ const pluginDir = (0, plugin_local_1.extractTgzToNodeModules)(tgzPath, name);
96
+ const pluginPkg = (0, plugin_local_1.readPluginPackageJson)(pluginDir);
97
+ if (pluginPkg?.peerDependencies) {
98
+ const missingDeps = (0, plugin_local_1.checkMissingPeerDeps)(pluginPkg.peerDependencies);
99
+ if (missingDeps.length > 0) {
100
+ (0, plugin_local_1.installMissingDeps)(missingDeps);
101
+ }
102
+ }
103
+ const installedVersion = (0, plugin_local_1.getPackageVersion)(name) ?? targetVersion;
104
+ const plugins = (0, plugin_local_1.readActionPlugins)();
105
+ plugins[name] = installedVersion;
106
+ (0, plugin_local_1.writeActionPlugins)(plugins);
107
+ const source = fromCache ? "from cache" : "downloaded";
108
+ log(`Installed ${name}@${installedVersion} (${source})`);
109
+ api.plugin.reportInstallEvent(name, installedVersion).catch(() => { });
110
+ api.plugin.reportCreateInstanceEvent(name, installedVersion).catch(() => { });
111
+ return { name, version: installedVersion, success: true };
112
+ }
113
+ catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ log(`Failed to install ${name}: ${message}`);
116
+ return { name, version: requestedVersion, success: false, error: message };
117
+ }
118
+ }
119
+ async function handlePluginInstall(opts) {
120
+ const { names } = opts;
121
+ const results = [];
122
+ for (const n of names) {
123
+ const result = await installOne(n);
124
+ results.push(result);
125
+ }
126
+ (0, output_1.emit)({
127
+ installed: results.filter((r) => r.success && !r.skipped).map((r) => `${r.name}@${r.version}`),
128
+ skipped: results.filter((r) => r.skipped).map((r) => r.name),
129
+ failed: results.filter((r) => !r.success).map((r) => ({ name: r.name, error: r.error })),
130
+ });
131
+ if (results.some((r) => !r.success)) {
132
+ process.exitCode = 1;
133
+ }
134
+ }
135
+ // ── Update ──
136
+ async function updateOne(nameWithVersion) {
137
+ const { name } = (0, plugin_local_1.parsePluginName)(nameWithVersion);
138
+ try {
139
+ log(`Updating ${name}...`);
140
+ if (!(0, plugin_local_1.isPluginInstalled)(name)) {
141
+ log(`${name} is not installed`);
142
+ return { name, success: false, notInstalled: true };
143
+ }
144
+ const oldVersion = (0, plugin_local_1.getInstalledPluginVersion)(name) ?? "unknown";
145
+ log(`Current version: ${oldVersion}`);
146
+ const downloadResult = await api.plugin.downloadPlugin(name, "latest");
147
+ if (oldVersion === downloadResult.version) {
148
+ log(`${name} already up to date (${downloadResult.version})`);
149
+ return {
150
+ name,
151
+ oldVersion,
152
+ newVersion: downloadResult.version,
153
+ success: true,
154
+ skipped: true,
155
+ };
156
+ }
157
+ (0, plugin_local_1.npmInstall)(downloadResult.tgzPath);
158
+ const installedVersion = (0, plugin_local_1.getPackageVersion)(name) ?? downloadResult.version;
159
+ const plugins = (0, plugin_local_1.readActionPlugins)();
160
+ plugins[name] = installedVersion;
161
+ (0, plugin_local_1.writeActionPlugins)(plugins);
162
+ log(`Updated ${name}: ${oldVersion} → ${installedVersion}`);
163
+ return { name, oldVersion, newVersion: installedVersion, success: true };
164
+ }
165
+ catch (error) {
166
+ const message = error instanceof Error ? error.message : String(error);
167
+ log(`Failed to update ${name}: ${message}`);
168
+ return { name, success: false, error: message };
169
+ }
170
+ }
171
+ async function handlePluginUpdate(opts) {
172
+ const { names } = opts;
173
+ const results = [];
174
+ for (const n of names) {
175
+ const result = await updateOne(n);
176
+ results.push(result);
177
+ }
178
+ (0, output_1.emit)({
179
+ updated: results
180
+ .filter((r) => r.success && !r.skipped)
181
+ .map((r) => ({ name: r.name, from: r.oldVersion, to: r.newVersion })),
182
+ skipped: results.filter((r) => r.skipped).map((r) => r.name),
183
+ notInstalled: results.filter((r) => r.notInstalled).map((r) => r.name),
184
+ failed: results
185
+ .filter((r) => !r.success && !r.notInstalled)
186
+ .map((r) => ({ name: r.name, error: r.error })),
187
+ });
188
+ if (results.some((r) => !r.success && !r.notInstalled)) {
189
+ process.exitCode = 1;
190
+ }
191
+ }
192
+ // ── Remove ──
193
+ function handlePluginRemove(opts) {
194
+ const { name } = (0, plugin_local_1.parsePluginName)(opts.name);
195
+ if (!(0, plugin_local_1.isPluginInstalled)(name)) {
196
+ throw new error_1.AppError("PLUGIN_NOT_FOUND", `Plugin ${name} is not installed`, { next_actions: ["运行 miaoda plugin list-packages 查看已安装插件"] });
197
+ }
198
+ (0, plugin_local_1.removePluginDirectory)(name);
199
+ const plugins = (0, plugin_local_1.readActionPlugins)();
200
+ const { [name]: _, ...remaining } = plugins;
201
+ (0, plugin_local_1.writeActionPlugins)(remaining);
202
+ (0, output_1.emit)({ removed: name });
203
+ }
204
+ // ── Init ──
205
+ async function installOneForInit(name, version) {
206
+ try {
207
+ const installedVersion = (0, plugin_local_1.getPackageVersion)(name);
208
+ if (installedVersion === version) {
209
+ return { name, version, success: true, skipped: true };
210
+ }
211
+ let tgzPath;
212
+ let fromCache = false;
213
+ if (api.plugin.hasCachedPlugin(name, version)) {
214
+ log(`Restoring ${name}@${version} from cache...`);
215
+ tgzPath = api.plugin.getCachePath(name, version);
216
+ fromCache = true;
217
+ }
218
+ else {
219
+ log(`Downloading ${name}@${version}...`);
220
+ const downloadResult = await api.plugin.downloadPlugin(name, version);
221
+ tgzPath = downloadResult.tgzPath;
222
+ }
223
+ const pluginDir = (0, plugin_local_1.extractTgzToNodeModules)(tgzPath, name);
224
+ const pluginPkg = (0, plugin_local_1.readPluginPackageJson)(pluginDir);
225
+ if (pluginPkg?.peerDependencies) {
226
+ const missingDeps = (0, plugin_local_1.checkMissingPeerDeps)(pluginPkg.peerDependencies);
227
+ if (missingDeps.length > 0) {
228
+ (0, plugin_local_1.installMissingDeps)(missingDeps);
229
+ }
230
+ }
231
+ const source = fromCache ? "from cache" : "downloaded";
232
+ log(`Installed ${name}@${version} (${source})`);
233
+ return { name, version, success: true };
234
+ }
235
+ catch (error) {
236
+ const message = error instanceof Error ? error.message : String(error);
237
+ log(`Failed to install ${name}: ${message}`);
238
+ return { name, version, success: false, error: message };
239
+ }
240
+ }
241
+ async function handlePluginInit() {
242
+ const plugins = (0, plugin_local_1.readActionPlugins)();
243
+ const entries = Object.entries(plugins);
244
+ if (entries.length === 0) {
245
+ (0, output_1.emit)({ message: "No plugins found in package.json", installed: [], skipped: [] });
246
+ return;
247
+ }
248
+ log(`Found ${String(entries.length)} plugin(s) to install`);
249
+ const results = [];
250
+ for (const [name, version] of entries) {
251
+ const result = await installOneForInit(name, version);
252
+ results.push(result);
253
+ }
254
+ (0, output_1.emit)({
255
+ installed: results.filter((r) => r.success && !r.skipped).map((r) => `${r.name}@${r.version}`),
256
+ skipped: results.filter((r) => r.skipped).map((r) => r.name),
257
+ failed: results.filter((r) => !r.success).map((r) => ({ name: r.name, error: r.error })),
258
+ });
259
+ if (results.some((r) => !r.success)) {
260
+ process.exitCode = 1;
261
+ }
262
+ }
263
+ // ── List (capability configs) ──
264
+ async function handlePluginList(opts) {
265
+ if (!(0, plugin_local_1.capabilitiesDirExists)()) {
266
+ throw new error_1.AppError("CAPABILITIES_DIR_NOT_FOUND", "server/capabilities directory not found", { next_actions: ["当前目录必须是含 server/capabilities/ 的应用项目"] });
267
+ }
268
+ if (opts.id) {
269
+ const capability = (0, plugin_local_1.readCapability)(opts.id);
270
+ if (opts.summary) {
271
+ (0, output_1.emit)(capability);
272
+ }
273
+ else {
274
+ const hydrated = await (0, plugin_local_1.hydrateCapability)(capability);
275
+ (0, output_1.emit)(hydrated);
276
+ }
277
+ }
278
+ else {
279
+ const capabilities = (0, plugin_local_1.readAllCapabilities)();
280
+ if (capabilities.length === 0) {
281
+ (0, output_1.emit)([]);
282
+ return;
283
+ }
284
+ if (opts.summary) {
285
+ (0, output_1.emit)(capabilities);
286
+ }
287
+ else {
288
+ const hydrated = [];
289
+ for (const cap of capabilities) {
290
+ const result = await (0, plugin_local_1.hydrateCapability)(cap);
291
+ hydrated.push(result);
292
+ }
293
+ (0, output_1.emit)(hydrated);
294
+ }
295
+ }
296
+ }
297
+ // ── List plugins (installed) ──
298
+ function handlePluginListPlugins() {
299
+ const plugins = Object.entries((0, plugin_local_1.readActionPlugins)());
300
+ if (plugins.length === 0) {
301
+ (0, output_1.emit)({ plugins: [], total: 0 });
302
+ return;
303
+ }
304
+ (0, output_1.emit)({
305
+ plugins: plugins.map(([name, version]) => ({ name, version })),
306
+ total: plugins.length,
307
+ });
308
+ }
package/dist/main.js ADDED
@@ -0,0 +1,31 @@
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
+ const commander_1 = require("commander");
7
+ const index_1 = require("./cli/commands/index");
8
+ const config_1 = require("./utils/config");
9
+ const log_id_1 = require("./utils/log_id");
10
+ const output_1 = require("./utils/output");
11
+ const package_json_1 = __importDefault(require("../package.json"));
12
+ const program = new commander_1.Command();
13
+ const { version } = package_json_1.default;
14
+ program
15
+ .name("miaoda")
16
+ .description("妙搭平台命令行工具")
17
+ .version(version, "-v, --version", "显示版本号")
18
+ .option("--json [fields]", "JSON 输出,可选字段级选择")
19
+ .option("--output <format>", "输出格式(pretty|json)", "pretty")
20
+ .option("--verbose", "debug 日志到 stderr")
21
+ .helpOption("-h, --help", "显示帮助信息")
22
+ .hook("preAction", (_thisCmd, actionCmd) => {
23
+ (0, log_id_1.generateLogId)();
24
+ const opts = actionCmd.optsWithGlobals();
25
+ (0, config_1.initConfigFromOpts)(opts);
26
+ });
27
+ (0, index_1.registerCommands)(program);
28
+ program.parseAsync(process.argv).catch((err) => {
29
+ (0, output_1.emitError)(err);
30
+ process.exitCode = 1;
31
+ });
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConfig = getConfig;
4
+ exports.setConfig = setConfig;
5
+ exports.resetConfig = resetConfig;
6
+ exports.initConfigFromOpts = initConfigFromOpts;
7
+ const defaults = {
8
+ json: false,
9
+ output: "pretty",
10
+ verbose: false,
11
+ };
12
+ let config = { ...defaults };
13
+ function getConfig() {
14
+ return config;
15
+ }
16
+ function setConfig(partial) {
17
+ config = { ...config, ...partial };
18
+ }
19
+ function resetConfig() {
20
+ config = { ...defaults };
21
+ }
22
+ /** 从 CLI 全局 option 初始化 config */
23
+ function initConfigFromOpts(opts) {
24
+ const json = opts.json;
25
+ const output = opts.output;
26
+ setConfig({
27
+ json: json ?? defaults.json,
28
+ output: output === "json" || json ? "json" : defaults.output,
29
+ verbose: opts.verbose ?? defaults.verbose,
30
+ });
31
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpError = exports.AppError = void 0;
4
+ class AppError extends Error {
5
+ code;
6
+ retryable;
7
+ next_actions;
8
+ constructor(code, message, opts) {
9
+ super(message);
10
+ this.name = "AppError";
11
+ this.code = code;
12
+ this.retryable = opts?.retryable ?? false;
13
+ this.next_actions = opts?.next_actions ?? [];
14
+ }
15
+ toJSON() {
16
+ return {
17
+ code: this.code,
18
+ message: this.message,
19
+ retryable: this.retryable,
20
+ next_actions: this.next_actions,
21
+ };
22
+ }
23
+ }
24
+ exports.AppError = AppError;
25
+ class HttpError extends AppError {
26
+ status;
27
+ url;
28
+ constructor(status, url, message, opts) {
29
+ super(`HTTP_${String(status)}`, message, opts ?? { retryable: status >= 500 || status === 429 });
30
+ this.name = "HttpError";
31
+ this.status = status;
32
+ this.url = url;
33
+ }
34
+ }
35
+ exports.HttpError = HttpError;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getHttpClient = getHttpClient;
4
+ exports.resetHttpClient = resetHttpClient;
5
+ exports.setHttpClient = setHttpClient;
6
+ exports.applyCanaryHeader = applyCanaryHeader;
7
+ const http_client_1 = require("@lark-apaas/http-client");
8
+ let client;
9
+ /** 获取单例 HttpClient,首次调用时初始化 */
10
+ function getHttpClient() {
11
+ client ??= createClient();
12
+ return client;
13
+ }
14
+ /** 重建客户端 */
15
+ function resetHttpClient() {
16
+ client = undefined;
17
+ }
18
+ /** 替换为自定义 HttpClient 实例(用于测试 mock) */
19
+ function setHttpClient(custom) {
20
+ client = custom;
21
+ }
22
+ function createClient() {
23
+ const config = {
24
+ timeout: 30_000,
25
+ platform: {
26
+ enabled: true,
27
+ tokenProvider: { type: "file" },
28
+ },
29
+ security: {
30
+ strictMode: true,
31
+ },
32
+ };
33
+ const instance = new http_client_1.HttpClient(config);
34
+ instance.interceptors.request.use(applyCanaryHeader);
35
+ return instance;
36
+ }
37
+ /** 若 MIAODA_CANARY_HEADER 已设置,注入 x-tt-env 小流量头 */
38
+ function applyCanaryHeader(reqConfig) {
39
+ const canary = process.env.MIAODA_CANARY_HEADER;
40
+ if (!canary)
41
+ return reqConfig;
42
+ const headers = new Headers(reqConfig.headers);
43
+ headers.set("x-tt-env", canary);
44
+ reqConfig.headers = headers;
45
+ return reqConfig;
46
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setHttpClient = exports.resetHttpClient = exports.getHttpClient = exports.log = exports.debug = exports.isJsonMode = exports.emitError = exports.emit = exports.getLogId = exports.generateLogId = exports.initConfigFromOpts = exports.resetConfig = exports.setConfig = exports.getConfig = exports.HttpError = exports.AppError = void 0;
4
+ var error_1 = require("./error");
5
+ Object.defineProperty(exports, "AppError", { enumerable: true, get: function () { return error_1.AppError; } });
6
+ Object.defineProperty(exports, "HttpError", { enumerable: true, get: function () { return error_1.HttpError; } });
7
+ var config_1 = require("./config");
8
+ Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return config_1.getConfig; } });
9
+ Object.defineProperty(exports, "setConfig", { enumerable: true, get: function () { return config_1.setConfig; } });
10
+ Object.defineProperty(exports, "resetConfig", { enumerable: true, get: function () { return config_1.resetConfig; } });
11
+ Object.defineProperty(exports, "initConfigFromOpts", { enumerable: true, get: function () { return config_1.initConfigFromOpts; } });
12
+ var log_id_1 = require("./log_id");
13
+ Object.defineProperty(exports, "generateLogId", { enumerable: true, get: function () { return log_id_1.generateLogId; } });
14
+ Object.defineProperty(exports, "getLogId", { enumerable: true, get: function () { return log_id_1.getLogId; } });
15
+ var output_1 = require("./output");
16
+ Object.defineProperty(exports, "emit", { enumerable: true, get: function () { return output_1.emit; } });
17
+ Object.defineProperty(exports, "emitError", { enumerable: true, get: function () { return output_1.emitError; } });
18
+ Object.defineProperty(exports, "isJsonMode", { enumerable: true, get: function () { return output_1.isJsonMode; } });
19
+ var logger_1 = require("./logger");
20
+ Object.defineProperty(exports, "debug", { enumerable: true, get: function () { return logger_1.debug; } });
21
+ Object.defineProperty(exports, "log", { enumerable: true, get: function () { return logger_1.log; } });
22
+ var http_1 = require("./http");
23
+ Object.defineProperty(exports, "getHttpClient", { enumerable: true, get: function () { return http_1.getHttpClient; } });
24
+ Object.defineProperty(exports, "resetHttpClient", { enumerable: true, get: function () { return http_1.resetHttpClient; } });
25
+ Object.defineProperty(exports, "setHttpClient", { enumerable: true, get: function () { return http_1.setHttpClient; } });
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateLogId = generateLogId;
4
+ exports.getLogId = getLogId;
5
+ const node_crypto_1 = require("node:crypto");
6
+ let current;
7
+ function generateLogId() {
8
+ current = (0, node_crypto_1.randomUUID)();
9
+ return current;
10
+ }
11
+ function getLogId() {
12
+ return current ?? generateLogId();
13
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.debug = debug;
4
+ exports.log = log;
5
+ const config_1 = require("./config");
6
+ /** verbose 模式下输出 debug 日志到 stderr */
7
+ function debug(msg) {
8
+ if ((0, config_1.getConfig)().verbose) {
9
+ process.stderr.write(`[debug] ${msg}\n`);
10
+ }
11
+ }
12
+ /** 始终输出到 stderr 的进度日志 */
13
+ function log(prefix, msg) {
14
+ process.stderr.write(`[${prefix}] ${msg}\n`);
15
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isJsonMode = isJsonMode;
4
+ exports.emit = emit;
5
+ exports.emitError = emitError;
6
+ const config_1 = require("./config");
7
+ const error_1 = require("./error");
8
+ function isJsonMode() {
9
+ const cfg = (0, config_1.getConfig)();
10
+ return cfg.output === "json" || Boolean(cfg.json);
11
+ }
12
+ /**
13
+ * 输出数据
14
+ * - pretty 模式:格式化文本到 stdout
15
+ * - json 模式:裸 JSON 到 stdout
16
+ */
17
+ function emit(data) {
18
+ if (isJsonMode()) {
19
+ process.stdout.write(JSON.stringify(data) + "\n");
20
+ }
21
+ else {
22
+ if (typeof data === "string") {
23
+ process.stdout.write(data + "\n");
24
+ }
25
+ else {
26
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
27
+ }
28
+ }
29
+ }
30
+ /**
31
+ * 输出错误(写入 stderr)
32
+ * - pretty 模式:Error: message\n hint: ...
33
+ * - json 模式:{"error_code": "...", "message": "...", "hint": "..."}
34
+ */
35
+ function emitError(err) {
36
+ const info = toErrorInfo(err);
37
+ if (isJsonMode()) {
38
+ const jsonErr = {
39
+ error_code: info.code,
40
+ message: info.message,
41
+ };
42
+ if (info.next_actions && info.next_actions.length > 0) {
43
+ jsonErr.hint = info.next_actions.join(" ");
44
+ }
45
+ process.stderr.write(JSON.stringify(jsonErr) + "\n");
46
+ }
47
+ else {
48
+ process.stderr.write(`Error: ${info.message}\n`);
49
+ if (info.next_actions && info.next_actions.length > 0) {
50
+ process.stderr.write(` hint: ${info.next_actions.join(" ")}\n`);
51
+ }
52
+ }
53
+ }
54
+ function toErrorInfo(err) {
55
+ if (err instanceof error_1.AppError)
56
+ return err.toJSON();
57
+ const message = err instanceof Error ? err.message : String(err);
58
+ return { code: "UNKNOWN", message, retryable: false, next_actions: [] };
59
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@lark-apaas/miaoda-cli",
3
+ "version": "0.1.0-alpha.c783fb5",
4
+ "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
+ "type": "commonjs",
6
+ "bin": {
7
+ "miaoda": "bin/miaoda.js"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "keywords": [
19
+ "miaoda",
20
+ "cli",
21
+ "agent"
22
+ ],
23
+ "license": "MIT",
24
+ "engines": {
25
+ "node": ">=20"
26
+ },
27
+ "dependencies": {
28
+ "@lark-apaas/http-client": "^0.1.3",
29
+ "commander": "^13.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.15.3",
33
+ "@typescript-eslint/eslint-plugin": "^8.58.2",
34
+ "@typescript-eslint/parser": "^8.58.2",
35
+ "@vitest/coverage-v8": "^4.1.4",
36
+ "eslint": "^9.25.1",
37
+ "husky": "^9.1.7",
38
+ "tsc-alias": "^1.8.11",
39
+ "tsx": "^4.19.4",
40
+ "typescript": "^5.8.3",
41
+ "vitest": "^4.1.4",
42
+ "xml2js": "^0.6.2"
43
+ },
44
+ "scripts": {
45
+ "build": "bash scripts/build.sh",
46
+ "typecheck": "tsc --noEmit -p tsconfig.json",
47
+ "lint": "eslint src/ --max-warnings 0",
48
+ "test": "vitest run",
49
+ "test:watch": "vitest",
50
+ "test:integration": "vitest run --config vitest.integration.config.ts",
51
+ "dev": "node --import tsx src/main.ts"
52
+ }
53
+ }