@lark-apaas/miaoda-cli 0.1.3 → 0.1.4

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 (71) hide show
  1. package/dist/api/app/api.js +3 -3
  2. package/dist/api/app/schemas.js +43 -43
  3. package/dist/api/db/api.js +398 -55
  4. package/dist/api/db/client.js +155 -28
  5. package/dist/api/db/index.js +12 -1
  6. package/dist/api/db/parsers.js +20 -20
  7. package/dist/api/db/sql-keywords.js +87 -87
  8. package/dist/api/deploy/api.js +5 -5
  9. package/dist/api/deploy/schemas.js +32 -32
  10. package/dist/api/file/api.js +89 -87
  11. package/dist/api/file/client.js +62 -22
  12. package/dist/api/file/detect.js +3 -3
  13. package/dist/api/file/index.js +2 -1
  14. package/dist/api/file/parsers.js +18 -7
  15. package/dist/api/observability/api.js +6 -6
  16. package/dist/api/observability/schemas.js +14 -14
  17. package/dist/api/plugin/api.js +31 -31
  18. package/dist/cli/commands/app/index.js +12 -12
  19. package/dist/cli/commands/db/index.js +602 -54
  20. package/dist/cli/commands/deploy/index.js +28 -28
  21. package/dist/cli/commands/file/index.js +85 -58
  22. package/dist/cli/commands/observability/index.js +69 -69
  23. package/dist/cli/commands/plugin/index.js +27 -27
  24. package/dist/cli/commands/shared.js +10 -10
  25. package/dist/cli/handlers/app/update.js +2 -2
  26. package/dist/cli/handlers/db/_destructive.js +67 -0
  27. package/dist/cli/handlers/db/_env.js +26 -0
  28. package/dist/cli/handlers/db/_operator.js +35 -0
  29. package/dist/cli/handlers/db/audit.js +383 -0
  30. package/dist/cli/handlers/db/changelog.js +160 -0
  31. package/dist/cli/handlers/db/data.js +32 -31
  32. package/dist/cli/handlers/db/index.js +17 -1
  33. package/dist/cli/handlers/db/migration.js +234 -0
  34. package/dist/cli/handlers/db/quota.js +68 -0
  35. package/dist/cli/handlers/db/recovery.js +413 -0
  36. package/dist/cli/handlers/db/schema.js +33 -33
  37. package/dist/cli/handlers/db/sql.js +69 -69
  38. package/dist/cli/handlers/deploy/deploy.js +4 -4
  39. package/dist/cli/handlers/deploy/error-log.js +1 -1
  40. package/dist/cli/handlers/deploy/get.js +3 -3
  41. package/dist/cli/handlers/deploy/polling.js +11 -11
  42. package/dist/cli/handlers/file/cp.js +30 -30
  43. package/dist/cli/handlers/file/index.js +3 -1
  44. package/dist/cli/handlers/file/ls.js +5 -5
  45. package/dist/cli/handlers/file/quota.js +66 -0
  46. package/dist/cli/handlers/file/rm.js +32 -30
  47. package/dist/cli/handlers/file/sign.js +3 -3
  48. package/dist/cli/handlers/file/stat.js +10 -9
  49. package/dist/cli/handlers/observability/analytics.js +47 -47
  50. package/dist/cli/handlers/observability/helpers.js +2 -2
  51. package/dist/cli/handlers/observability/log.js +9 -9
  52. package/dist/cli/handlers/observability/metric.js +26 -26
  53. package/dist/cli/handlers/observability/trace.js +5 -5
  54. package/dist/cli/handlers/plugin/plugin-local.js +53 -53
  55. package/dist/cli/handlers/plugin/plugin.js +15 -15
  56. package/dist/cli/help.js +16 -16
  57. package/dist/main.js +12 -12
  58. package/dist/utils/args.js +1 -1
  59. package/dist/utils/colors.js +2 -2
  60. package/dist/utils/config.js +2 -2
  61. package/dist/utils/devops-error.js +9 -9
  62. package/dist/utils/error.js +2 -2
  63. package/dist/utils/git.js +4 -4
  64. package/dist/utils/http.js +19 -19
  65. package/dist/utils/index.js +3 -1
  66. package/dist/utils/output.js +67 -45
  67. package/dist/utils/poll.js +35 -0
  68. package/dist/utils/render.js +27 -27
  69. package/dist/utils/spinner.js +46 -0
  70. package/dist/utils/time.js +47 -42
  71. package/package.json +1 -1
@@ -47,37 +47,37 @@ const helpers_1 = require("./helpers");
47
47
  * 表头标签直接用 --series 名("total"/"error"/"p50"/"p99");单一指标则用 cliName。
48
48
  */
49
49
  const METRIC_LABELS = {
50
- cpu: { cpu_usage: "cpu" },
51
- memory: { mem_usage: "memory" },
50
+ cpu: { cpu_usage: 'cpu' },
51
+ memory: { mem_usage: 'memory' },
52
52
  requests: {
53
- client_api_request_count: "total",
54
- client_api_request_error_count: "error",
53
+ client_api_request_count: 'total',
54
+ client_api_request_error_count: 'error',
55
55
  },
56
56
  latency: {
57
- client_api_request_latency_p50: "p50",
58
- client_api_request_latency_p99: "p99",
57
+ client_api_request_latency_p50: 'p50',
58
+ client_api_request_latency_p99: 'p99',
59
59
  },
60
60
  };
61
61
  /** miaoda observability metric <metric-name> */
62
62
  async function handleObservabilityMetric(opts) {
63
63
  if (!opts.metricName)
64
- (0, args_1.failArgs)("<metric-name> 必填");
64
+ (0, args_1.failArgs)('<metric-name> 必填');
65
65
  const appID = opts.appId;
66
66
  const { metricNames, labelByMetric, extraFilters } = resolveMetricSelection(opts.metricName, opts.series);
67
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 },
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
70
  ...extraFilters,
71
71
  ]);
72
72
  // since/until 直接以秒透传到 BAM;当前未做桶对齐(如需开启把 until
73
73
  // 用 ceilMsToBucket(untilMs, downSample as GranularityBucket) 包一层即可)。
74
- const downSample = opts.downSample ?? "1m";
74
+ const downSample = opts.downSample ?? '1m';
75
75
  const nowMs = Date.now();
76
76
  const sinceMs = (0, helpers_1.parseToMs)(opts.since) ?? nowMs - 30 * 86_400_000;
77
77
  const untilMs = (0, helpers_1.parseToMs)(opts.until) ?? nowMs;
78
78
  const req = {
79
79
  appID,
80
- appEnv: "runtime",
80
+ appEnv: 'runtime',
81
81
  metricNames,
82
82
  startTimestamp: (0, helpers_1.msToSec)(sinceMs),
83
83
  endTimestamp: (0, helpers_1.msToSec)(untilMs),
@@ -91,7 +91,7 @@ async function handleObservabilityMetric(opts) {
91
91
  // - CLI 按"请求过的 metricNames"逐一兜底为 0,让"没有请求"和"没有数据"
92
92
  // 在表格 / JSON 里都显式呈现成 0,避免空格 / 缺字段被误解为缺失
93
93
  // latency / cpu / memory 不做这个兜底——p50 没数据 ≠ 延迟为 0。
94
- if (opts.metricName === "requests") {
94
+ if (opts.metricName === 'requests') {
95
95
  fillRequestedMetricsWithZero(resp, metricNames);
96
96
  }
97
97
  emitMetricsResponse(resp, labelByMetric);
@@ -126,7 +126,7 @@ function emitMetricsResponse(resp, labelByMetric) {
126
126
  (0, output_1.emit)({ data: [], next_cursor: null, has_more: false });
127
127
  return;
128
128
  }
129
- const hasLatency = Object.keys(labelByMetric).some((n) => n.includes("latency"));
129
+ const hasLatency = Object.keys(labelByMetric).some((n) => n.includes('latency'));
130
130
  (0, output_1.emit)({ data: rows, next_cursor: null, has_more: false }, buildPivotSchema(seriesLabels, hasLatency));
131
131
  }
132
132
  function renameAndSort(points, labelByMetric) {
@@ -149,7 +149,7 @@ function buildPivotSchema(seriesLabels, hasLatency) {
149
149
  const valueFormat = hasLatency ? output_1.fmt.durationMs() : undefined;
150
150
  return {
151
151
  columns: [
152
- { key: "timestamp", label: "time", format: output_1.fmt.sec() },
152
+ { key: 'timestamp', label: 'time', format: output_1.fmt.sec() },
153
153
  ...seriesLabels.map((label) => ({
154
154
  key: label,
155
155
  label,
@@ -166,28 +166,28 @@ function buildPivotSchema(seriesLabels, hasLatency) {
166
166
  */
167
167
  function resolveMetricSelection(cliName, series) {
168
168
  const extras = [];
169
- if (cliName === "latency") {
170
- if (series === "p99") {
171
- return single("client_api_request_latency_p99", "p99", extras);
169
+ if (cliName === 'latency') {
170
+ if (series === 'p99') {
171
+ return single('client_api_request_latency_p99', 'p99', extras);
172
172
  }
173
- if (series === "p50") {
174
- return single("client_api_request_latency_p50", "p50", extras);
173
+ if (series === 'p50') {
174
+ return single('client_api_request_latency_p50', 'p50', extras);
175
175
  }
176
176
  return all(METRIC_LABELS.latency, extras);
177
177
  }
178
- if (cliName === "requests") {
178
+ if (cliName === 'requests') {
179
179
  // v1.0.122 起 error 线由独立 metric 提供,不再走 is_error filter
180
- if (series === "total") {
181
- return single("client_api_request_count", "total", extras);
180
+ if (series === 'total') {
181
+ return single('client_api_request_count', 'total', extras);
182
182
  }
183
- if (series === "error") {
184
- return single("client_api_request_error_count", "error", extras);
183
+ if (series === 'error') {
184
+ return single('client_api_request_error_count', 'error', extras);
185
185
  }
186
186
  return all(METRIC_LABELS.requests, extras);
187
187
  }
188
- if (cliName === "cpu")
188
+ if (cliName === 'cpu')
189
189
  return all(METRIC_LABELS.cpu, extras);
190
- if (cliName === "memory")
190
+ if (cliName === 'memory')
191
191
  return all(METRIC_LABELS.memory, extras);
192
192
  // 兜底:CLI 名直接作为 metric name + label
193
193
  return single(cliName, cliName, extras);
@@ -43,7 +43,7 @@ const helpers_1 = require("./helpers");
43
43
  /** miaoda observability trace list */
44
44
  async function handleObservabilityTraceList(opts) {
45
45
  const appID = opts.appId;
46
- const appEnv = "runtime";
46
+ const appEnv = 'runtime';
47
47
  const limit = (0, helpers_1.validateLimit)(opts.limit ?? 50);
48
48
  // 过滤 key 对齐 BAM Span 字段名:
49
49
  // - 顶层字段:traceID(注意大小写)
@@ -51,8 +51,8 @@ async function handleObservabilityTraceList(opts) {
51
51
  // - 入口 span:BAM 没有 entrySpanName fieldFilter,统一走 fuzzyFilter(trace endpoint
52
52
  // 默认作用于 span name),所以 --root-span 不进 fieldFilters
53
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 },
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
56
  ]);
57
57
  const req = {
58
58
  appID,
@@ -77,9 +77,9 @@ function emitSearchTracesResponse(resp) {
77
77
  /** miaoda observability trace get <trace-id> */
78
78
  async function handleObservabilityTraceGet(opts) {
79
79
  if (!opts.traceId)
80
- (0, args_1.failArgs)("<trace-id> 必填");
80
+ (0, args_1.failArgs)('<trace-id> 必填');
81
81
  const appID = opts.appId;
82
- const appEnv = "runtime";
82
+ const appEnv = 'runtime';
83
83
  const resp = await api.observability.getTraces({
84
84
  appID,
85
85
  appEnv,
@@ -65,33 +65,33 @@ function getProjectRoot() {
65
65
  return process.cwd();
66
66
  }
67
67
  function getPackageJsonPath() {
68
- return node_path_1.default.join(getProjectRoot(), "package.json");
68
+ return node_path_1.default.join(getProjectRoot(), 'package.json');
69
69
  }
70
70
  function getPluginPath(pluginName) {
71
- return node_path_1.default.join(getProjectRoot(), "node_modules", pluginName);
71
+ return node_path_1.default.join(getProjectRoot(), 'node_modules', pluginName);
72
72
  }
73
73
  // ── Plugin name parsing ──
74
74
  function parsePluginName(input) {
75
75
  const match = /^(@[^/]+\/[^@]+)(?:@(.+))?$/.exec(input);
76
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"] });
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
78
  }
79
- return { name: match[1], version: match[2] ?? "latest" };
79
+ return { name: match[1], version: match[2] ?? 'latest' };
80
80
  }
81
81
  // ── package.json actionPlugins CRUD ──
82
82
  function readPackageJson() {
83
83
  const pkgPath = getPackageJsonPath();
84
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", {
86
- next_actions: ["在应用项目根目录运行"],
85
+ throw new error_1.AppError('PKG_JSON_NOT_FOUND', 'package.json not found in current directory', {
86
+ next_actions: ['在应用项目根目录运行'],
87
87
  });
88
88
  }
89
- const content = node_fs_1.default.readFileSync(pkgPath, "utf-8");
89
+ const content = node_fs_1.default.readFileSync(pkgPath, 'utf-8');
90
90
  return JSON.parse(content);
91
91
  }
92
92
  function writePackageJson(pkg) {
93
93
  const pkgPath = getPackageJsonPath();
94
- node_fs_1.default.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
94
+ node_fs_1.default.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
95
95
  }
96
96
  function readActionPlugins() {
97
97
  const pkg = readPackageJson();
@@ -112,11 +112,11 @@ function getInstalledPluginVersion(pluginName) {
112
112
  }
113
113
  // ── node_modules operations ──
114
114
  function getPackageVersion(pluginName) {
115
- const pkgJsonPath = node_path_1.default.join(getPluginPath(pluginName), "package.json");
115
+ const pkgJsonPath = node_path_1.default.join(getPluginPath(pluginName), 'package.json');
116
116
  if (!node_fs_1.default.existsSync(pkgJsonPath))
117
117
  return null;
118
118
  try {
119
- const content = node_fs_1.default.readFileSync(pkgJsonPath, "utf-8");
119
+ const content = node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8');
120
120
  const pkg = JSON.parse(content);
121
121
  return pkg.version ?? null;
122
122
  }
@@ -125,11 +125,11 @@ function getPackageVersion(pluginName) {
125
125
  }
126
126
  }
127
127
  function readPluginPackageJson(pluginPath) {
128
- const pkgJsonPath = node_path_1.default.join(pluginPath, "package.json");
128
+ const pkgJsonPath = node_path_1.default.join(pluginPath, 'package.json');
129
129
  if (!node_fs_1.default.existsSync(pkgJsonPath))
130
130
  return null;
131
131
  try {
132
- const content = node_fs_1.default.readFileSync(pkgJsonPath, "utf-8");
132
+ const content = node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8');
133
133
  return JSON.parse(content);
134
134
  }
135
135
  catch {
@@ -137,7 +137,7 @@ function readPluginPackageJson(pluginPath) {
137
137
  }
138
138
  }
139
139
  function extractTgzToNodeModules(tgzPath, pluginName) {
140
- const nodeModulesPath = node_path_1.default.join(getProjectRoot(), "node_modules");
140
+ const nodeModulesPath = node_path_1.default.join(getProjectRoot(), 'node_modules');
141
141
  const targetDir = node_path_1.default.join(nodeModulesPath, pluginName);
142
142
  const scopeDir = node_path_1.default.dirname(targetDir);
143
143
  if (!node_fs_1.default.existsSync(scopeDir)) {
@@ -146,14 +146,14 @@ function extractTgzToNodeModules(tgzPath, pluginName) {
146
146
  if (node_fs_1.default.existsSync(targetDir)) {
147
147
  node_fs_1.default.rmSync(targetDir, { recursive: true });
148
148
  }
149
- const tempDir = node_path_1.default.join(nodeModulesPath, ".cache", "miaoda-cli", "extract-temp");
149
+ const tempDir = node_path_1.default.join(nodeModulesPath, '.cache', 'miaoda-cli', 'extract-temp');
150
150
  if (node_fs_1.default.existsSync(tempDir)) {
151
151
  node_fs_1.default.rmSync(tempDir, { recursive: true });
152
152
  }
153
153
  node_fs_1.default.mkdirSync(tempDir, { recursive: true });
154
154
  try {
155
- (0, node_child_process_1.execSync)(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
156
- const extractedDir = node_path_1.default.join(tempDir, "package");
155
+ (0, node_child_process_1.execSync)(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: 'pipe' });
156
+ const extractedDir = node_path_1.default.join(tempDir, 'package');
157
157
  if (node_fs_1.default.existsSync(extractedDir)) {
158
158
  node_fs_1.default.renameSync(extractedDir, targetDir);
159
159
  }
@@ -163,7 +163,7 @@ function extractTgzToNodeModules(tgzPath, pluginName) {
163
163
  node_fs_1.default.renameSync(node_path_1.default.join(tempDir, files[0]), targetDir);
164
164
  }
165
165
  else {
166
- throw new error_1.AppError("INTERNAL_EXTRACT_FAILED", "Unexpected tgz structure");
166
+ throw new error_1.AppError('INTERNAL_EXTRACT_FAILED', 'Unexpected tgz structure');
167
167
  }
168
168
  }
169
169
  return targetDir;
@@ -178,7 +178,7 @@ function checkMissingPeerDeps(peerDeps) {
178
178
  if (!peerDeps || Object.keys(peerDeps).length === 0)
179
179
  return [];
180
180
  const missing = [];
181
- const nodeModulesPath = node_path_1.default.join(getProjectRoot(), "node_modules");
181
+ const nodeModulesPath = node_path_1.default.join(getProjectRoot(), 'node_modules');
182
182
  for (const depName of Object.keys(peerDeps)) {
183
183
  const depPath = node_path_1.default.join(nodeModulesPath, depName);
184
184
  if (!node_fs_1.default.existsSync(depPath)) {
@@ -190,29 +190,29 @@ function checkMissingPeerDeps(peerDeps) {
190
190
  function installMissingDeps(deps) {
191
191
  if (deps.length === 0)
192
192
  return;
193
- (0, logger_1.log)("plugin", `Installing missing dependencies: ${deps.join(", ")}`);
194
- const result = (0, node_child_process_1.spawnSync)("npm", ["install", ...deps, "--no-save", "--no-package-lock"], {
193
+ (0, logger_1.log)('plugin', `Installing missing dependencies: ${deps.join(', ')}`);
194
+ const result = (0, node_child_process_1.spawnSync)('npm', ['install', ...deps, '--no-save', '--no-package-lock'], {
195
195
  cwd: getProjectRoot(),
196
- stdio: "inherit",
196
+ stdio: 'inherit',
197
197
  });
198
198
  if (result.error) {
199
- throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed: ${result.error.message}`, {
200
- next_actions: ["确认本机已安装 npm,可 --verbose 查看执行详情"],
199
+ throw new error_1.AppError('INTERNAL_NPM_FAILED', `npm install failed: ${result.error.message}`, {
200
+ next_actions: ['确认本机已安装 npm,可 --verbose 查看执行详情'],
201
201
  });
202
202
  }
203
203
  if (result.status !== 0) {
204
- throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed with exit code ${String(result.status)}`, { next_actions: ["检查上方 npm 输出日志定位具体错误"] });
204
+ throw new error_1.AppError('INTERNAL_NPM_FAILED', `npm install failed with exit code ${String(result.status)}`, { next_actions: ['检查上方 npm 输出日志定位具体错误'] });
205
205
  }
206
206
  }
207
207
  function npmInstall(tgzPath) {
208
- const result = (0, node_child_process_1.spawnSync)("npm", ["install", tgzPath, "--no-save", "--no-package-lock", "--ignore-scripts"], { cwd: getProjectRoot(), stdio: "inherit" });
208
+ const result = (0, node_child_process_1.spawnSync)('npm', ['install', tgzPath, '--no-save', '--no-package-lock', '--ignore-scripts'], { cwd: getProjectRoot(), stdio: 'inherit' });
209
209
  if (result.error) {
210
- throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed: ${result.error.message}`, {
211
- next_actions: ["确认本机已安装 npm,可 --verbose 查看执行详情"],
210
+ throw new error_1.AppError('INTERNAL_NPM_FAILED', `npm install failed: ${result.error.message}`, {
211
+ next_actions: ['确认本机已安装 npm,可 --verbose 查看执行详情'],
212
212
  });
213
213
  }
214
214
  if (result.status !== 0) {
215
- throw new error_1.AppError("INTERNAL_NPM_FAILED", `npm install failed with exit code ${String(result.status)}`, { next_actions: ["检查上方 npm 输出日志定位具体错误"] });
215
+ throw new error_1.AppError('INTERNAL_NPM_FAILED', `npm install failed with exit code ${String(result.status)}`, { next_actions: ['检查上方 npm 输出日志定位具体错误'] });
216
216
  }
217
217
  }
218
218
  function removePluginDirectory(pluginName) {
@@ -222,7 +222,7 @@ function removePluginDirectory(pluginName) {
222
222
  }
223
223
  }
224
224
  // ── Capability FS ──
225
- const CAPABILITIES_DIR = "server/capabilities";
225
+ const CAPABILITIES_DIR = 'server/capabilities';
226
226
  function getCapabilitiesDir() {
227
227
  return node_path_1.default.join(getProjectRoot(), CAPABILITIES_DIR);
228
228
  }
@@ -235,23 +235,23 @@ function listCapabilityIds() {
235
235
  return [];
236
236
  const files = node_fs_1.default.readdirSync(dir);
237
237
  return files
238
- .filter((f) => f.endsWith(".json") && f !== "capabilities.json")
239
- .map((f) => f.replace(/\.json$/, ""));
238
+ .filter((f) => f.endsWith('.json') && f !== 'capabilities.json')
239
+ .map((f) => f.replace(/\.json$/, ''));
240
240
  }
241
241
  function readCapability(id) {
242
242
  const filePath = node_path_1.default.join(getCapabilitiesDir(), `${id}.json`);
243
243
  if (!node_fs_1.default.existsSync(filePath)) {
244
- throw new error_1.AppError("CAPABILITY_NOT_FOUND", `Capability not found: ${id}`, {
245
- next_actions: ["运行 miaoda plugin list 查看所有可用 capability id"],
244
+ throw new error_1.AppError('CAPABILITY_NOT_FOUND', `Capability not found: ${id}`, {
245
+ next_actions: ['运行 miaoda plugin list 查看所有可用 capability id'],
246
246
  });
247
247
  }
248
248
  try {
249
- const content = node_fs_1.default.readFileSync(filePath, "utf-8");
249
+ const content = node_fs_1.default.readFileSync(filePath, 'utf-8');
250
250
  return JSON.parse(content);
251
251
  }
252
252
  catch (error) {
253
253
  if (error instanceof SyntaxError) {
254
- throw new error_1.AppError("INVALID_JSON", `Invalid JSON in capability file: ${id}.json`, {
254
+ throw new error_1.AppError('INVALID_JSON', `Invalid JSON in capability file: ${id}.json`, {
255
255
  next_actions: [`检查 server/capabilities/${id}.json 的 JSON 语法`],
256
256
  });
257
257
  }
@@ -276,28 +276,28 @@ function readAllCapabilities() {
276
276
  }
277
277
  // ── Capability Hydration ──
278
278
  function getPluginManifestPath(pluginKey) {
279
- return node_path_1.default.join(getProjectRoot(), "node_modules", pluginKey, "manifest.json");
279
+ return node_path_1.default.join(getProjectRoot(), 'node_modules', pluginKey, 'manifest.json');
280
280
  }
281
281
  function readPluginManifest(pluginKey) {
282
282
  const manifestPath = getPluginManifestPath(pluginKey);
283
283
  if (!node_fs_1.default.existsSync(manifestPath)) {
284
- throw new error_1.AppError("MANIFEST_NOT_FOUND", `Plugin not installed: ${pluginKey} (manifest.json not found)`, { next_actions: [`运行 miaoda plugin install ${pluginKey}`] });
284
+ throw new error_1.AppError('MANIFEST_NOT_FOUND', `Plugin not installed: ${pluginKey} (manifest.json not found)`, { next_actions: [`运行 miaoda plugin install ${pluginKey}`] });
285
285
  }
286
286
  try {
287
- const content = node_fs_1.default.readFileSync(manifestPath, "utf-8");
287
+ const content = node_fs_1.default.readFileSync(manifestPath, 'utf-8');
288
288
  return JSON.parse(content);
289
289
  }
290
290
  catch (error) {
291
291
  if (error instanceof SyntaxError) {
292
- throw new error_1.AppError("INVALID_JSON", `Invalid JSON in plugin manifest: ${pluginKey}/manifest.json`, { next_actions: [`检查 node_modules/${pluginKey}/manifest.json 的 JSON 语法`] });
292
+ throw new error_1.AppError('INVALID_JSON', `Invalid JSON in plugin manifest: ${pluginKey}/manifest.json`, { next_actions: [`检查 node_modules/${pluginKey}/manifest.json 的 JSON 语法`] });
293
293
  }
294
294
  throw error;
295
295
  }
296
296
  }
297
297
  function isDynamicSchema(schema) {
298
298
  return (schema !== undefined &&
299
- typeof schema === "object" &&
300
- "dynamic" in schema &&
299
+ typeof schema === 'object' &&
300
+ 'dynamic' in schema &&
301
301
  schema.dynamic === true);
302
302
  }
303
303
  function hasValidParamsSchema(paramsSchema) {
@@ -305,29 +305,29 @@ function hasValidParamsSchema(paramsSchema) {
305
305
  }
306
306
  async function loadPlugin(pluginKey) {
307
307
  try {
308
- const userRequire = (0, node_module_1.createRequire)(node_path_1.default.join(getProjectRoot(), "package.json"));
308
+ const userRequire = (0, node_module_1.createRequire)(node_path_1.default.join(getProjectRoot(), 'package.json'));
309
309
  const resolvedPath = userRequire.resolve(pluginKey);
310
310
  const pluginModule = (await Promise.resolve(`${resolvedPath}`).then(s => __importStar(require(s))));
311
311
  const pluginPackage = (pluginModule.default ?? pluginModule);
312
- if (typeof pluginPackage.create !== "function") {
313
- throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Plugin ${pluginKey} does not export a valid create function`, { next_actions: [`该插件包版本可能过旧,尝试 miaoda plugin update ${pluginKey}`] });
312
+ if (typeof pluginPackage.create !== 'function') {
313
+ throw new error_1.AppError('INTERNAL_PLUGIN_LOAD_FAILED', `Plugin ${pluginKey} does not export a valid create function`, { next_actions: [`该插件包版本可能过旧,尝试 miaoda plugin update ${pluginKey}`] });
314
314
  }
315
315
  return pluginPackage;
316
316
  }
317
317
  catch (error) {
318
- if (error.code === "MODULE_NOT_FOUND") {
319
- throw new error_1.AppError("PLUGIN_NOT_FOUND", `Plugin not installed: ${pluginKey}`, {
318
+ if (error.code === 'MODULE_NOT_FOUND') {
319
+ throw new error_1.AppError('PLUGIN_NOT_FOUND', `Plugin not installed: ${pluginKey}`, {
320
320
  next_actions: [`运行 miaoda plugin install ${pluginKey}`],
321
321
  });
322
322
  }
323
- throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Failed to load plugin ${pluginKey}: ${error instanceof Error ? error.message : String(error)}`);
323
+ throw new error_1.AppError('INTERNAL_PLUGIN_LOAD_FAILED', `Failed to load plugin ${pluginKey}: ${error instanceof Error ? error.message : String(error)}`);
324
324
  }
325
325
  }
326
326
  async function hydrateCapability(capability) {
327
327
  try {
328
328
  const manifest = readPluginManifest(capability.pluginKey);
329
329
  if (manifest.actions.length === 0) {
330
- throw new error_1.AppError("INTERNAL_PLUGIN_LOAD_FAILED", `Plugin ${capability.pluginKey} has no actions defined`);
330
+ throw new error_1.AppError('INTERNAL_PLUGIN_LOAD_FAILED', `Plugin ${capability.pluginKey} has no actions defined`);
331
331
  }
332
332
  const hasDynamic = manifest.actions.some((action) => isDynamicSchema(action.inputSchema) || isDynamicSchema(action.outputSchema));
333
333
  let pluginInstance = null;
@@ -345,11 +345,11 @@ async function hydrateCapability(capability) {
345
345
  }
346
346
  else if (isDynamicSchema(manifestAction.inputSchema)) {
347
347
  if (!pluginInstance) {
348
- throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", "Plugin instance not available for dynamic schema");
348
+ throw new error_1.AppError('INTERNAL_SCHEMA_ERROR', 'Plugin instance not available for dynamic schema');
349
349
  }
350
350
  const jsonSchema = pluginInstance.getInputJsonSchema(manifestAction.key);
351
351
  if (!jsonSchema) {
352
- throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", `Failed to get input schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getInputJsonSchema 实现`] });
352
+ throw new error_1.AppError('INTERNAL_SCHEMA_ERROR', `Failed to get input schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getInputJsonSchema 实现`] });
353
353
  }
354
354
  inputSchema = jsonSchema;
355
355
  }
@@ -360,11 +360,11 @@ async function hydrateCapability(capability) {
360
360
  let outputSchema;
361
361
  if (isDynamicSchema(manifestAction.outputSchema)) {
362
362
  if (!pluginInstance) {
363
- throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", "Plugin instance not available for dynamic schema");
363
+ throw new error_1.AppError('INTERNAL_SCHEMA_ERROR', 'Plugin instance not available for dynamic schema');
364
364
  }
365
365
  const jsonSchema = pluginInstance.getOutputJsonSchema(manifestAction.key, capability.formValue);
366
366
  if (!jsonSchema) {
367
- throw new error_1.AppError("INTERNAL_SCHEMA_ERROR", `Failed to get output schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getOutputJsonSchema 实现`] });
367
+ throw new error_1.AppError('INTERNAL_SCHEMA_ERROR', `Failed to get output schema for action: ${manifestAction.key}`, { next_actions: [`检查插件 ${capability.pluginKey} 的 getOutputJsonSchema 实现`] });
368
368
  }
369
369
  outputSchema = jsonSchema;
370
370
  }
@@ -375,7 +375,7 @@ async function hydrateCapability(capability) {
375
375
  key: manifestAction.key,
376
376
  inputSchema,
377
377
  outputSchema,
378
- outputMode: manifestAction.outputMode || "",
378
+ outputMode: manifestAction.outputMode || '',
379
379
  });
380
380
  }
381
381
  return {
@@ -45,7 +45,7 @@ const error_1 = require("../../../utils/error");
45
45
  const logger_1 = require("../../../utils/logger");
46
46
  const plugin_local_1 = require("./plugin-local");
47
47
  const log = (msg) => {
48
- (0, logger_1.log)("plugin", msg);
48
+ (0, logger_1.log)('plugin', msg);
49
49
  };
50
50
  // ── Install ──
51
51
  function syncActionPluginsRecord(name, version) {
@@ -61,7 +61,7 @@ async function installOne(nameWithVersion) {
61
61
  try {
62
62
  log(`Installing ${name}@${requestedVersion}...`);
63
63
  const actualVersion = (0, plugin_local_1.getPackageVersion)(name);
64
- if (actualVersion && requestedVersion !== "latest") {
64
+ if (actualVersion && requestedVersion !== 'latest') {
65
65
  if (actualVersion === requestedVersion) {
66
66
  log(`${name}@${requestedVersion} already installed`);
67
67
  syncActionPluginsRecord(name, actualVersion);
@@ -72,8 +72,8 @@ async function installOne(nameWithVersion) {
72
72
  }
73
73
  }
74
74
  let targetVersion = requestedVersion;
75
- if (requestedVersion === "latest") {
76
- const latestInfo = await api.plugin.getPluginVersion(name, "latest");
75
+ if (requestedVersion === 'latest') {
76
+ const latestInfo = await api.plugin.getPluginVersion(name, 'latest');
77
77
  targetVersion = latestInfo.version;
78
78
  if (actualVersion === targetVersion) {
79
79
  log(`${name} already up to date (${actualVersion})`);
@@ -83,7 +83,7 @@ async function installOne(nameWithVersion) {
83
83
  });
84
84
  return { name, version: actualVersion, success: true, skipped: true };
85
85
  }
86
- log(`Found newer version: ${targetVersion} (installed: ${actualVersion ?? "none"})`);
86
+ log(`Found newer version: ${targetVersion} (installed: ${actualVersion ?? 'none'})`);
87
87
  }
88
88
  let tgzPath;
89
89
  let fromCache = false;
@@ -97,7 +97,7 @@ async function installOne(nameWithVersion) {
97
97
  const downloadResult = await api.plugin.downloadPlugin(name, requestedVersion);
98
98
  tgzPath = downloadResult.tgzPath;
99
99
  }
100
- log("Extracting to node_modules...");
100
+ log('Extracting to node_modules...');
101
101
  const pluginDir = (0, plugin_local_1.extractTgzToNodeModules)(tgzPath, name);
102
102
  const pluginPkg = (0, plugin_local_1.readPluginPackageJson)(pluginDir);
103
103
  if (pluginPkg?.peerDependencies) {
@@ -110,7 +110,7 @@ async function installOne(nameWithVersion) {
110
110
  const plugins = (0, plugin_local_1.readActionPlugins)();
111
111
  plugins[name] = installedVersion;
112
112
  (0, plugin_local_1.writeActionPlugins)(plugins);
113
- const source = fromCache ? "from cache" : "downloaded";
113
+ const source = fromCache ? 'from cache' : 'downloaded';
114
114
  log(`Installed ${name}@${installedVersion} (${source})`);
115
115
  api.plugin.reportInstallEvent(name, installedVersion).catch(() => {
116
116
  /* fire-and-forget */
@@ -151,9 +151,9 @@ async function updateOne(nameWithVersion) {
151
151
  log(`${name} is not installed`);
152
152
  return { name, success: false, notInstalled: true };
153
153
  }
154
- const oldVersion = (0, plugin_local_1.getInstalledPluginVersion)(name) ?? "unknown";
154
+ const oldVersion = (0, plugin_local_1.getInstalledPluginVersion)(name) ?? 'unknown';
155
155
  log(`Current version: ${oldVersion}`);
156
- const downloadResult = await api.plugin.downloadPlugin(name, "latest");
156
+ const downloadResult = await api.plugin.downloadPlugin(name, 'latest');
157
157
  if (oldVersion === downloadResult.version) {
158
158
  log(`${name} already up to date (${downloadResult.version})`);
159
159
  return {
@@ -203,8 +203,8 @@ async function handlePluginUpdate(opts) {
203
203
  function handlePluginRemove(opts) {
204
204
  const { name } = (0, plugin_local_1.parsePluginName)(opts.name);
205
205
  if (!(0, plugin_local_1.isPluginInstalled)(name)) {
206
- throw new error_1.AppError("PLUGIN_NOT_FOUND", `Plugin ${name} is not installed`, {
207
- next_actions: ["运行 miaoda plugin list-packages 查看已安装插件"],
206
+ throw new error_1.AppError('PLUGIN_NOT_FOUND', `Plugin ${name} is not installed`, {
207
+ next_actions: ['运行 miaoda plugin list-packages 查看已安装插件'],
208
208
  });
209
209
  }
210
210
  (0, plugin_local_1.removePluginDirectory)(name);
@@ -240,7 +240,7 @@ async function installOneForInit(name, version) {
240
240
  (0, plugin_local_1.installMissingDeps)(missingDeps);
241
241
  }
242
242
  }
243
- const source = fromCache ? "from cache" : "downloaded";
243
+ const source = fromCache ? 'from cache' : 'downloaded';
244
244
  log(`Installed ${name}@${version} (${source})`);
245
245
  return { name, version, success: true };
246
246
  }
@@ -254,7 +254,7 @@ async function handlePluginInit() {
254
254
  const plugins = (0, plugin_local_1.readActionPlugins)();
255
255
  const entries = Object.entries(plugins);
256
256
  if (entries.length === 0) {
257
- (0, output_1.emit)({ message: "No plugins found in package.json", installed: [], skipped: [] });
257
+ (0, output_1.emit)({ message: 'No plugins found in package.json', installed: [], skipped: [] });
258
258
  return;
259
259
  }
260
260
  log(`Found ${String(entries.length)} plugin(s) to install`);
@@ -275,8 +275,8 @@ async function handlePluginInit() {
275
275
  // ── List (capability configs) ──
276
276
  async function handlePluginList(opts) {
277
277
  if (!(0, plugin_local_1.capabilitiesDirExists)()) {
278
- throw new error_1.AppError("CAPABILITIES_DIR_NOT_FOUND", "server/capabilities directory not found", {
279
- next_actions: ["当前目录必须是含 server/capabilities/ 的应用项目"],
278
+ throw new error_1.AppError('CAPABILITIES_DIR_NOT_FOUND', 'server/capabilities directory not found', {
279
+ next_actions: ['当前目录必须是含 server/capabilities/ 的应用项目'],
280
280
  });
281
281
  }
282
282
  if (opts.id) {