@lark-apaas/miaoda-cli 0.1.0-alpha.08508f4

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 (47) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +66 -0
  3. package/bin/miaoda.js +2 -0
  4. package/dist/api/db/api.js +200 -0
  5. package/dist/api/db/client.js +166 -0
  6. package/dist/api/db/index.js +16 -0
  7. package/dist/api/db/parsers.js +161 -0
  8. package/dist/api/db/types.js +10 -0
  9. package/dist/api/file/api.js +425 -0
  10. package/dist/api/file/client.js +199 -0
  11. package/dist/api/file/detect.js +56 -0
  12. package/dist/api/file/index.js +17 -0
  13. package/dist/api/file/parsers.js +72 -0
  14. package/dist/api/file/types.js +3 -0
  15. package/dist/api/index.js +42 -0
  16. package/dist/api/plugin/api.js +243 -0
  17. package/dist/api/plugin/index.js +12 -0
  18. package/dist/api/plugin/types.js +3 -0
  19. package/dist/cli/commands/db/index.js +69 -0
  20. package/dist/cli/commands/file/index.js +75 -0
  21. package/dist/cli/commands/index.js +11 -0
  22. package/dist/cli/commands/plugin/index.js +204 -0
  23. package/dist/cli/commands/shared.js +52 -0
  24. package/dist/cli/handlers/db/data.js +168 -0
  25. package/dist/cli/handlers/db/index.js +11 -0
  26. package/dist/cli/handlers/db/schema.js +163 -0
  27. package/dist/cli/handlers/db/sql.js +252 -0
  28. package/dist/cli/handlers/file/cp.js +220 -0
  29. package/dist/cli/handlers/file/index.js +13 -0
  30. package/dist/cli/handlers/file/ls.js +110 -0
  31. package/dist/cli/handlers/file/rm.js +263 -0
  32. package/dist/cli/handlers/file/sign.js +96 -0
  33. package/dist/cli/handlers/file/stat.js +97 -0
  34. package/dist/cli/handlers/index.js +19 -0
  35. package/dist/cli/handlers/plugin/index.js +10 -0
  36. package/dist/cli/handlers/plugin/plugin-local.js +382 -0
  37. package/dist/cli/handlers/plugin/plugin.js +308 -0
  38. package/dist/main.js +31 -0
  39. package/dist/utils/config.js +31 -0
  40. package/dist/utils/error.js +38 -0
  41. package/dist/utils/http.js +67 -0
  42. package/dist/utils/index.js +27 -0
  43. package/dist/utils/log_id.js +13 -0
  44. package/dist/utils/logger.js +15 -0
  45. package/dist/utils/output.js +72 -0
  46. package/dist/utils/render.js +187 -0
  47. package/package.json +53 -0
@@ -0,0 +1,382 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getProjectRoot = getProjectRoot;
40
+ exports.getPluginPath = getPluginPath;
41
+ exports.parsePluginName = parsePluginName;
42
+ exports.readActionPlugins = readActionPlugins;
43
+ exports.writeActionPlugins = writeActionPlugins;
44
+ exports.isPluginInstalled = isPluginInstalled;
45
+ exports.getInstalledPluginVersion = getInstalledPluginVersion;
46
+ exports.getPackageVersion = getPackageVersion;
47
+ exports.readPluginPackageJson = readPluginPackageJson;
48
+ exports.extractTgzToNodeModules = extractTgzToNodeModules;
49
+ exports.checkMissingPeerDeps = checkMissingPeerDeps;
50
+ exports.installMissingDeps = installMissingDeps;
51
+ exports.npmInstall = npmInstall;
52
+ exports.removePluginDirectory = removePluginDirectory;
53
+ exports.capabilitiesDirExists = capabilitiesDirExists;
54
+ exports.readCapability = readCapability;
55
+ exports.readAllCapabilities = readAllCapabilities;
56
+ exports.hydrateCapability = hydrateCapability;
57
+ const node_fs_1 = __importDefault(require("node:fs"));
58
+ const node_path_1 = __importDefault(require("node:path"));
59
+ const node_child_process_1 = require("node:child_process");
60
+ const node_module_1 = require("node:module");
61
+ const error_1 = require("../../../utils/error");
62
+ const logger_1 = require("../../../utils/logger");
63
+ // ── Project paths ──
64
+ function getProjectRoot() {
65
+ return process.cwd();
66
+ }
67
+ function getPackageJsonPath() {
68
+ return node_path_1.default.join(getProjectRoot(), "package.json");
69
+ }
70
+ function getPluginPath(pluginName) {
71
+ return node_path_1.default.join(getProjectRoot(), "node_modules", pluginName);
72
+ }
73
+ // ── Plugin name parsing ──
74
+ function parsePluginName(input) {
75
+ const match = /^(@[^/]+\/[^@]+)(?:@(.+))?$/.exec(input);
76
+ if (!match) {
77
+ throw new error_1.AppError("INVALID_PLUGIN_NAME", `Invalid plugin name format: ${input}. Expected: @scope/name or @scope/name@version`, { next_actions: ["示例:@demo/example-plugin 或 @demo/example-plugin@1.2.3"] });
78
+ }
79
+ return { name: match[1], version: match[2] ?? "latest" };
80
+ }
81
+ // ── package.json actionPlugins CRUD ──
82
+ function readPackageJson() {
83
+ const pkgPath = getPackageJsonPath();
84
+ if (!node_fs_1.default.existsSync(pkgPath)) {
85
+ throw new error_1.AppError("PKG_JSON_NOT_FOUND", "package.json not found in current directory", { next_actions: ["在应用项目根目录运行"] });
86
+ }
87
+ const content = node_fs_1.default.readFileSync(pkgPath, "utf-8");
88
+ return JSON.parse(content);
89
+ }
90
+ function writePackageJson(pkg) {
91
+ const pkgPath = getPackageJsonPath();
92
+ node_fs_1.default.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
93
+ }
94
+ function readActionPlugins() {
95
+ const pkg = readPackageJson();
96
+ return pkg.actionPlugins ?? {};
97
+ }
98
+ function writeActionPlugins(plugins) {
99
+ const pkg = readPackageJson();
100
+ pkg.actionPlugins = plugins;
101
+ writePackageJson(pkg);
102
+ }
103
+ function isPluginInstalled(pluginName) {
104
+ const plugins = readActionPlugins();
105
+ return pluginName in plugins;
106
+ }
107
+ function getInstalledPluginVersion(pluginName) {
108
+ const plugins = readActionPlugins();
109
+ return plugins[pluginName] ?? null;
110
+ }
111
+ // ── node_modules operations ──
112
+ function getPackageVersion(pluginName) {
113
+ const pkgJsonPath = node_path_1.default.join(getPluginPath(pluginName), "package.json");
114
+ if (!node_fs_1.default.existsSync(pkgJsonPath))
115
+ return null;
116
+ try {
117
+ const content = node_fs_1.default.readFileSync(pkgJsonPath, "utf-8");
118
+ const pkg = JSON.parse(content);
119
+ return pkg.version ?? null;
120
+ }
121
+ catch {
122
+ return null;
123
+ }
124
+ }
125
+ function readPluginPackageJson(pluginPath) {
126
+ const pkgJsonPath = node_path_1.default.join(pluginPath, "package.json");
127
+ if (!node_fs_1.default.existsSync(pkgJsonPath))
128
+ return null;
129
+ try {
130
+ const content = node_fs_1.default.readFileSync(pkgJsonPath, "utf-8");
131
+ return JSON.parse(content);
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
137
+ function extractTgzToNodeModules(tgzPath, pluginName) {
138
+ const nodeModulesPath = node_path_1.default.join(getProjectRoot(), "node_modules");
139
+ const targetDir = node_path_1.default.join(nodeModulesPath, pluginName);
140
+ const scopeDir = node_path_1.default.dirname(targetDir);
141
+ if (!node_fs_1.default.existsSync(scopeDir)) {
142
+ node_fs_1.default.mkdirSync(scopeDir, { recursive: true });
143
+ }
144
+ if (node_fs_1.default.existsSync(targetDir)) {
145
+ node_fs_1.default.rmSync(targetDir, { recursive: true });
146
+ }
147
+ const tempDir = node_path_1.default.join(nodeModulesPath, ".cache", "miaoda-cli", "extract-temp");
148
+ if (node_fs_1.default.existsSync(tempDir)) {
149
+ node_fs_1.default.rmSync(tempDir, { recursive: true });
150
+ }
151
+ node_fs_1.default.mkdirSync(tempDir, { recursive: true });
152
+ try {
153
+ (0, node_child_process_1.execSync)(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
154
+ const extractedDir = node_path_1.default.join(tempDir, "package");
155
+ if (node_fs_1.default.existsSync(extractedDir)) {
156
+ node_fs_1.default.renameSync(extractedDir, targetDir);
157
+ }
158
+ else {
159
+ const files = node_fs_1.default.readdirSync(tempDir);
160
+ if (files.length === 1) {
161
+ node_fs_1.default.renameSync(node_path_1.default.join(tempDir, files[0]), targetDir);
162
+ }
163
+ else {
164
+ throw new error_1.AppError("INTERNAL_EXTRACT_FAILED", "Unexpected tgz structure");
165
+ }
166
+ }
167
+ return targetDir;
168
+ }
169
+ finally {
170
+ if (node_fs_1.default.existsSync(tempDir)) {
171
+ node_fs_1.default.rmSync(tempDir, { recursive: true });
172
+ }
173
+ }
174
+ }
175
+ function checkMissingPeerDeps(peerDeps) {
176
+ if (!peerDeps || Object.keys(peerDeps).length === 0)
177
+ return [];
178
+ const missing = [];
179
+ const nodeModulesPath = node_path_1.default.join(getProjectRoot(), "node_modules");
180
+ for (const depName of Object.keys(peerDeps)) {
181
+ const depPath = node_path_1.default.join(nodeModulesPath, depName);
182
+ if (!node_fs_1.default.existsSync(depPath)) {
183
+ missing.push(depName);
184
+ }
185
+ }
186
+ return missing;
187
+ }
188
+ function installMissingDeps(deps) {
189
+ if (deps.length === 0)
190
+ return;
191
+ (0, logger_1.log)("plugin", `Installing missing dependencies: ${deps.join(", ")}`);
192
+ const result = (0, node_child_process_1.spawnSync)("npm", ["install", ...deps, "--no-save", "--no-package-lock"], { cwd: getProjectRoot(), stdio: "inherit" });
193
+ if (result.error) {
194
+ throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed: ${result.error.message}`, { next_actions: ["确认本机已安装 npm,可 --verbose 查看执行详情"] });
195
+ }
196
+ if (result.status !== 0) {
197
+ throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed with exit code ${String(result.status)}`, { next_actions: ["检查上方 npm 输出日志定位具体错误"] });
198
+ }
199
+ }
200
+ function npmInstall(tgzPath) {
201
+ const result = (0, node_child_process_1.spawnSync)("npm", ["install", tgzPath, "--no-save", "--no-package-lock", "--ignore-scripts"], { cwd: getProjectRoot(), stdio: "inherit" });
202
+ if (result.error) {
203
+ throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed: ${result.error.message}`, { next_actions: ["确认本机已安装 npm,可 --verbose 查看执行详情"] });
204
+ }
205
+ if (result.status !== 0) {
206
+ throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed with exit code ${String(result.status)}`, { next_actions: ["检查上方 npm 输出日志定位具体错误"] });
207
+ }
208
+ }
209
+ function removePluginDirectory(pluginName) {
210
+ const pluginPath = getPluginPath(pluginName);
211
+ if (node_fs_1.default.existsSync(pluginPath)) {
212
+ node_fs_1.default.rmSync(pluginPath, { recursive: true });
213
+ }
214
+ }
215
+ // ── Capability FS ──
216
+ const CAPABILITIES_DIR = "server/capabilities";
217
+ function getCapabilitiesDir() {
218
+ return node_path_1.default.join(getProjectRoot(), CAPABILITIES_DIR);
219
+ }
220
+ function capabilitiesDirExists() {
221
+ return node_fs_1.default.existsSync(getCapabilitiesDir());
222
+ }
223
+ function listCapabilityIds() {
224
+ const dir = getCapabilitiesDir();
225
+ if (!node_fs_1.default.existsSync(dir))
226
+ return [];
227
+ const files = node_fs_1.default.readdirSync(dir);
228
+ return files
229
+ .filter((f) => f.endsWith(".json") && f !== "capabilities.json")
230
+ .map((f) => f.replace(/\.json$/, ""));
231
+ }
232
+ function readCapability(id) {
233
+ const filePath = node_path_1.default.join(getCapabilitiesDir(), `${id}.json`);
234
+ if (!node_fs_1.default.existsSync(filePath)) {
235
+ throw new error_1.AppError("CAPABILITY_NOT_FOUND", `Capability not found: ${id}`, { next_actions: ["运行 miaoda plugin list 查看所有可用 capability id"] });
236
+ }
237
+ try {
238
+ const content = node_fs_1.default.readFileSync(filePath, "utf-8");
239
+ return JSON.parse(content);
240
+ }
241
+ catch (error) {
242
+ if (error instanceof SyntaxError) {
243
+ throw new error_1.AppError("INVALID_JSON", `Invalid JSON in capability file: ${id}.json`, { next_actions: [`检查 server/capabilities/${id}.json 的 JSON 语法`] });
244
+ }
245
+ throw error;
246
+ }
247
+ }
248
+ function readAllCapabilities() {
249
+ const ids = listCapabilityIds();
250
+ const capabilities = [];
251
+ for (const id of ids) {
252
+ try {
253
+ const cap = readCapability(id);
254
+ if (!cap.pluginKey)
255
+ continue;
256
+ capabilities.push(cap);
257
+ }
258
+ catch {
259
+ continue;
260
+ }
261
+ }
262
+ return capabilities;
263
+ }
264
+ // ── Capability Hydration ──
265
+ function getPluginManifestPath(pluginKey) {
266
+ return node_path_1.default.join(getProjectRoot(), "node_modules", pluginKey, "manifest.json");
267
+ }
268
+ function readPluginManifest(pluginKey) {
269
+ const manifestPath = getPluginManifestPath(pluginKey);
270
+ if (!node_fs_1.default.existsSync(manifestPath)) {
271
+ throw new error_1.AppError("MANIFEST_NOT_FOUND", `Plugin not installed: ${pluginKey} (manifest.json not found)`, { next_actions: [`运行 miaoda plugin install ${pluginKey}`] });
272
+ }
273
+ try {
274
+ const content = node_fs_1.default.readFileSync(manifestPath, "utf-8");
275
+ return JSON.parse(content);
276
+ }
277
+ catch (error) {
278
+ if (error instanceof SyntaxError) {
279
+ throw new error_1.AppError("INVALID_JSON", `Invalid JSON in plugin manifest: ${pluginKey}/manifest.json`, { next_actions: [`检查 node_modules/${pluginKey}/manifest.json 的 JSON 语法`] });
280
+ }
281
+ throw error;
282
+ }
283
+ }
284
+ function isDynamicSchema(schema) {
285
+ return (schema !== undefined &&
286
+ typeof schema === "object" &&
287
+ "dynamic" in schema &&
288
+ schema.dynamic === true);
289
+ }
290
+ function hasValidParamsSchema(paramsSchema) {
291
+ return paramsSchema !== undefined && Object.keys(paramsSchema).length > 0;
292
+ }
293
+ async function loadPlugin(pluginKey) {
294
+ try {
295
+ const userRequire = (0, node_module_1.createRequire)(node_path_1.default.join(getProjectRoot(), "package.json"));
296
+ const resolvedPath = userRequire.resolve(pluginKey);
297
+ const pluginModule = (await Promise.resolve(`${resolvedPath}`).then(s => __importStar(require(s))));
298
+ const pluginPackage = (pluginModule.default ?? pluginModule);
299
+ if (typeof pluginPackage.create !== "function") {
300
+ throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Plugin ${pluginKey} does not export a valid create function`, { next_actions: [`该插件包版本可能过旧,尝试 miaoda plugin update ${pluginKey}`] });
301
+ }
302
+ return pluginPackage;
303
+ }
304
+ catch (error) {
305
+ if (error.code === "MODULE_NOT_FOUND") {
306
+ throw new error_1.AppError("PLUGIN_NOT_FOUND", `Plugin not installed: ${pluginKey}`, { next_actions: [`运行 miaoda plugin install ${pluginKey}`] });
307
+ }
308
+ throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Failed to load plugin ${pluginKey}: ${error instanceof Error ? error.message : String(error)}`);
309
+ }
310
+ }
311
+ async function hydrateCapability(capability) {
312
+ try {
313
+ const manifest = readPluginManifest(capability.pluginKey);
314
+ if (manifest.actions.length === 0) {
315
+ throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Plugin ${capability.pluginKey} has no actions defined`);
316
+ }
317
+ const hasDynamic = manifest.actions.some((action) => isDynamicSchema(action.inputSchema) ||
318
+ isDynamicSchema(action.outputSchema));
319
+ let pluginInstance = null;
320
+ if (hasDynamic) {
321
+ const plugin = await loadPlugin(capability.pluginKey);
322
+ pluginInstance = plugin.create(capability.formValue);
323
+ }
324
+ const actions = [];
325
+ for (let index = 0; index < manifest.actions.length; index++) {
326
+ const manifestAction = manifest.actions[index];
327
+ // inputSchema
328
+ let inputSchema;
329
+ if (index === 0 && hasValidParamsSchema(capability.paramsSchema)) {
330
+ inputSchema = capability.paramsSchema;
331
+ }
332
+ else if (isDynamicSchema(manifestAction.inputSchema)) {
333
+ if (!pluginInstance) {
334
+ throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", "Plugin instance not available for dynamic schema");
335
+ }
336
+ const jsonSchema = pluginInstance.getInputJsonSchema(manifestAction.key);
337
+ if (!jsonSchema) {
338
+ throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", `Failed to get input schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getInputJsonSchema 实现`] });
339
+ }
340
+ inputSchema = jsonSchema;
341
+ }
342
+ else {
343
+ inputSchema = manifestAction.inputSchema;
344
+ }
345
+ // outputSchema
346
+ let outputSchema;
347
+ if (isDynamicSchema(manifestAction.outputSchema)) {
348
+ if (!pluginInstance) {
349
+ throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", "Plugin instance not available for dynamic schema");
350
+ }
351
+ const jsonSchema = pluginInstance.getOutputJsonSchema(manifestAction.key, capability.formValue);
352
+ if (!jsonSchema) {
353
+ throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", `Failed to get output schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getOutputJsonSchema 实现`] });
354
+ }
355
+ outputSchema = jsonSchema;
356
+ }
357
+ else {
358
+ outputSchema = manifestAction.outputSchema;
359
+ }
360
+ actions.push({
361
+ key: manifestAction.key,
362
+ inputSchema,
363
+ outputSchema,
364
+ outputMode: manifestAction.outputMode || "",
365
+ });
366
+ }
367
+ return {
368
+ id: capability.id,
369
+ pluginKey: capability.pluginKey,
370
+ pluginVersion: capability.pluginVersion,
371
+ name: capability.name,
372
+ description: capability.description,
373
+ actions,
374
+ createdAt: capability.createdAt,
375
+ updatedAt: capability.updatedAt,
376
+ };
377
+ }
378
+ catch (error) {
379
+ const message = error instanceof Error ? error.message : String(error);
380
+ return { ...capability, _hydrateError: message };
381
+ }
382
+ }
@@ -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
+ }