@lark-apaas/nestjs-capability 0.0.1-alpha.0 → 0.0.1-alpha.10

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.
package/dist/index.cjs CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  CapabilityNotFoundError: () => CapabilityNotFoundError,
37
37
  CapabilityService: () => CapabilityService,
38
38
  DebugController: () => DebugController,
39
+ ErrorCodes: () => ErrorCodes,
39
40
  PluginLoadError: () => PluginLoadError,
40
41
  PluginLoaderService: () => PluginLoaderService,
41
42
  PluginNotFoundError: () => PluginNotFoundError,
@@ -44,6 +45,26 @@ __export(index_exports, {
44
45
  });
45
46
  module.exports = __toCommonJS(index_exports);
46
47
 
48
+ // ../../../node_modules/tsup/assets/cjs_shims.js
49
+ var getImportMetaUrl = /* @__PURE__ */ __name(() => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href, "getImportMetaUrl");
50
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
51
+
52
+ // src/interfaces/error-codes.ts
53
+ var ErrorCodes = {
54
+ /** 成功 */
55
+ SUCCESS: "0",
56
+ /** 能力不存在 */
57
+ CAPABILITY_NOT_FOUND: "k_ec_cap_001",
58
+ /** 插件不存在 */
59
+ PLUGIN_NOT_FOUND: "k_ec_cap_002",
60
+ /** Action 不存在 */
61
+ ACTION_NOT_FOUND: "k_ec_cap_003",
62
+ /** 参数验证失败 */
63
+ PARAMS_VALIDATION_ERROR: "k_ec_cap_004",
64
+ /** 执行失败 */
65
+ EXECUTION_ERROR: "k_ec_cap_005"
66
+ };
67
+
47
68
  // src/services/template-engine.service.ts
48
69
  var import_common = require("@nestjs/common");
49
70
  function _ts_decorate(decorators, target, key, desc) {
@@ -57,7 +78,10 @@ var TemplateEngineService = class {
57
78
  static {
58
79
  __name(this, "TemplateEngineService");
59
80
  }
60
- TEMPLATE_REGEX = /^\{\{input\.(.+)\}\}$/;
81
+ // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
82
+ EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
83
+ // 匹配整串单个表达式
84
+ WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
61
85
  resolve(template, input) {
62
86
  if (typeof template === "string") {
63
87
  return this.resolveString(template, input);
@@ -71,12 +95,25 @@ var TemplateEngineService = class {
71
95
  return template;
72
96
  }
73
97
  resolveString(template, input) {
74
- const match = template.match(this.TEMPLATE_REGEX);
75
- if (!match) {
98
+ const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);
99
+ if (wholeMatch) {
100
+ const path2 = wholeMatch[1];
101
+ const value = this.getValueByPath(input, path2);
102
+ return value !== void 0 ? value : template;
103
+ }
104
+ this.EXPR_REGEX.lastIndex = 0;
105
+ if (!this.EXPR_REGEX.test(template)) {
76
106
  return template;
77
107
  }
78
- const path2 = match[1];
79
- return this.getValueByPath(input, path2);
108
+ this.EXPR_REGEX.lastIndex = 0;
109
+ const result = template.replace(this.EXPR_REGEX, (match, path2) => {
110
+ const value = this.getValueByPath(input, path2);
111
+ if (value === void 0) {
112
+ return match;
113
+ }
114
+ return String(value);
115
+ });
116
+ return result;
80
117
  }
81
118
  resolveObject(template, input) {
82
119
  const result = {};
@@ -103,6 +140,7 @@ TemplateEngineService = _ts_decorate([
103
140
 
104
141
  // src/services/plugin-loader.service.ts
105
142
  var import_common2 = require("@nestjs/common");
143
+ var import_node_module = require("module");
106
144
  function _ts_decorate2(decorators, target, key, desc) {
107
145
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
108
146
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -110,12 +148,13 @@ function _ts_decorate2(decorators, target, key, desc) {
110
148
  return c > 3 && r && Object.defineProperty(target, key, r), r;
111
149
  }
112
150
  __name(_ts_decorate2, "_ts_decorate");
151
+ var require2 = (0, import_node_module.createRequire)(importMetaUrl);
113
152
  var PluginNotFoundError = class extends Error {
114
153
  static {
115
154
  __name(this, "PluginNotFoundError");
116
155
  }
117
- constructor(pluginID) {
118
- super(`Plugin not found: ${pluginID}`);
156
+ constructor(pluginKey) {
157
+ super(`Plugin not found: ${pluginKey}`);
119
158
  this.name = "PluginNotFoundError";
120
159
  }
121
160
  };
@@ -123,8 +162,8 @@ var PluginLoadError = class extends Error {
123
162
  static {
124
163
  __name(this, "PluginLoadError");
125
164
  }
126
- constructor(pluginID, reason) {
127
- super(`Failed to load plugin ${pluginID}: ${reason}`);
165
+ constructor(pluginKey, reason) {
166
+ super(`Failed to load plugin ${pluginKey}: ${reason}`);
128
167
  this.name = "PluginLoadError";
129
168
  }
130
169
  };
@@ -134,46 +173,94 @@ var PluginLoaderService = class _PluginLoaderService {
134
173
  }
135
174
  logger = new import_common2.Logger(_PluginLoaderService.name);
136
175
  pluginInstances = /* @__PURE__ */ new Map();
137
- loadPlugin(pluginID) {
138
- const cached = this.pluginInstances.get(pluginID);
176
+ /** 记录每个插件的加载版本(时间戳),用于 ESM 缓存绕过 */
177
+ pluginVersions = /* @__PURE__ */ new Map();
178
+ async loadPlugin(pluginKey) {
179
+ const cached = this.pluginInstances.get(pluginKey);
139
180
  if (cached) {
140
- this.logger.debug(`Using cached plugin instance: ${pluginID}`);
181
+ this.logger.debug(`Using cached plugin instance: ${pluginKey}`);
141
182
  return cached;
142
183
  }
143
- this.logger.log(`Loading plugin: ${pluginID}`);
184
+ this.logger.log(`Loading plugin: ${pluginKey}`);
144
185
  try {
145
- const pluginPackage = require(pluginID);
186
+ const version = this.pluginVersions.get(pluginKey) ?? 0;
187
+ const importPath = version > 0 ? `${pluginKey}?v=${version}` : pluginKey;
188
+ const pluginPackage = (await import(importPath)).default;
146
189
  if (typeof pluginPackage.create !== "function") {
147
- throw new PluginLoadError(pluginID, "Plugin does not export create() function");
190
+ throw new PluginLoadError(pluginKey, "Plugin does not export create() function");
148
191
  }
149
192
  const instance = pluginPackage.create();
150
- this.pluginInstances.set(pluginID, instance);
151
- this.logger.log(`Plugin loaded successfully: ${pluginID}`);
193
+ this.pluginInstances.set(pluginKey, instance);
194
+ this.logger.log(`Plugin loaded successfully: ${pluginKey}`);
152
195
  return instance;
153
196
  } catch (error) {
154
197
  if (error.code === "MODULE_NOT_FOUND") {
155
- throw new PluginNotFoundError(pluginID);
198
+ throw new PluginNotFoundError(pluginKey);
156
199
  }
157
- throw new PluginLoadError(pluginID, error instanceof Error ? error.message : String(error));
200
+ throw new PluginLoadError(pluginKey, error instanceof Error ? error.message : String(error));
158
201
  }
159
202
  }
160
- isPluginInstalled(pluginID) {
203
+ isPluginInstalled(pluginKey) {
161
204
  try {
162
- require.resolve(pluginID);
205
+ require2.resolve(pluginKey);
163
206
  return true;
164
207
  } catch {
165
208
  return false;
166
209
  }
167
210
  }
168
- clearCache(pluginID) {
169
- if (pluginID) {
170
- this.pluginInstances.delete(pluginID);
171
- this.logger.log(`Cleared cache for plugin: ${pluginID}`);
211
+ /**
212
+ * 清除插件缓存(包括 Node.js 模块缓存)
213
+ * @param pluginKey - 插件标识,不传则清除所有
214
+ */
215
+ clearCache(pluginKey) {
216
+ if (pluginKey) {
217
+ this.pluginInstances.delete(pluginKey);
218
+ this.clearNodeModuleCache(pluginKey);
219
+ this.pluginVersions.set(pluginKey, Date.now());
220
+ this.logger.log(`Cleared cache for plugin: ${pluginKey}`);
172
221
  } else {
222
+ for (const key of this.pluginInstances.keys()) {
223
+ this.clearNodeModuleCache(key);
224
+ this.pluginVersions.set(key, Date.now());
225
+ }
173
226
  this.pluginInstances.clear();
174
227
  this.logger.log("Cleared all plugin caches");
175
228
  }
176
229
  }
230
+ /**
231
+ * 清除 CJS 模块缓存
232
+ */
233
+ clearNodeModuleCache(pluginKey) {
234
+ try {
235
+ const resolvedPath = require2.resolve(pluginKey);
236
+ const mod = require2.cache[resolvedPath];
237
+ if (mod) {
238
+ this.clearModuleAndChildren(mod, pluginKey);
239
+ }
240
+ delete require2.cache[resolvedPath];
241
+ } catch {
242
+ }
243
+ }
244
+ /**
245
+ * 递归清除子模块缓存
246
+ */
247
+ clearModuleAndChildren(mod, pluginKey) {
248
+ const pluginScope = pluginKey.startsWith("@") ? pluginKey.split("/").slice(0, 2).join("/") : pluginKey;
249
+ mod.children.forEach((child) => {
250
+ if (child.filename.includes(`node_modules/${pluginScope}`)) {
251
+ this.clearModuleAndChildren(child, pluginKey);
252
+ delete require2.cache[child.filename];
253
+ }
254
+ });
255
+ }
256
+ /**
257
+ * 强制重新加载插件
258
+ * @param pluginKey - 插件标识
259
+ */
260
+ async reloadPlugin(pluginKey) {
261
+ this.clearCache(pluginKey);
262
+ return this.loadPlugin(pluginKey);
263
+ }
177
264
  };
178
265
  PluginLoaderService = _ts_decorate2([
179
266
  (0, import_common2.Injectable)()
@@ -184,6 +271,29 @@ var import_common3 = require("@nestjs/common");
184
271
  var import_nestjs_common = require("@lark-apaas/nestjs-common");
185
272
  var fs = __toESM(require("fs"), 1);
186
273
  var path = __toESM(require("path"), 1);
274
+ var chokidar = __toESM(require("chokidar"), 1);
275
+
276
+ // src/utils/log-utils.ts
277
+ var DEFAULT_MAX_LENGTH = 1e3;
278
+ function truncateString(str, maxLength) {
279
+ if (str.length <= maxLength) {
280
+ return str;
281
+ }
282
+ return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;
283
+ }
284
+ __name(truncateString, "truncateString");
285
+ function stringifyForLog(value, maxLength = DEFAULT_MAX_LENGTH) {
286
+ try {
287
+ const str = JSON.stringify(value, null, 2);
288
+ return truncateString(str, maxLength);
289
+ } catch {
290
+ const str = String(value);
291
+ return truncateString(str, maxLength);
292
+ }
293
+ }
294
+ __name(stringifyForLog, "stringifyForLog");
295
+
296
+ // src/services/capability.service.ts
187
297
  function _ts_decorate3(decorators, target, key, desc) {
188
298
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
189
299
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -214,8 +324,8 @@ var ActionNotFoundError = class extends Error {
214
324
  static {
215
325
  __name(this, "ActionNotFoundError");
216
326
  }
217
- constructor(pluginID, actionName) {
218
- super(`Action '${actionName}' not found in plugin ${pluginID}`);
327
+ constructor(pluginKey, actionName) {
328
+ super(`Action '${actionName}' not found in plugin ${pluginKey}`);
219
329
  this.name = "ActionNotFoundError";
220
330
  }
221
331
  };
@@ -224,25 +334,150 @@ var CapabilityService = class _CapabilityService {
224
334
  __name(this, "CapabilityService");
225
335
  }
226
336
  requestContextService;
227
- httpClient;
337
+ platformHttpClient;
228
338
  pluginLoaderService;
229
339
  templateEngineService;
230
340
  logger = new import_common3.Logger(_CapabilityService.name);
231
341
  capabilities = /* @__PURE__ */ new Map();
342
+ /** 文件路径到 capability id 的映射,用于文件删除时查找 */
343
+ filePathToId = /* @__PURE__ */ new Map();
232
344
  capabilitiesDir;
233
- constructor(requestContextService, httpClient, pluginLoaderService, templateEngineService) {
345
+ fileWatcher = null;
346
+ options = {};
347
+ constructor(requestContextService, platformHttpClient, pluginLoaderService, templateEngineService) {
234
348
  this.requestContextService = requestContextService;
235
- this.httpClient = httpClient;
349
+ this.platformHttpClient = platformHttpClient;
236
350
  this.pluginLoaderService = pluginLoaderService;
237
351
  this.templateEngineService = templateEngineService;
238
- this.capabilitiesDir = path.join(process.cwd(), "server/capabilities");
352
+ const isDev = process.env.NODE_ENV === "development";
353
+ this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
354
+ }
355
+ /**
356
+ * 设置模块配置
357
+ */
358
+ setOptions(options) {
359
+ this.options = options;
360
+ if (options.capabilitiesDir) {
361
+ this.capabilitiesDir = options.capabilitiesDir;
362
+ }
239
363
  }
240
364
  setCapabilitiesDir(dir) {
241
365
  this.capabilitiesDir = dir;
242
366
  }
243
367
  async onModuleInit() {
244
368
  await this.loadCapabilities();
369
+ if (this.options.enableWatching) {
370
+ this.startWatching();
371
+ }
372
+ }
373
+ async onModuleDestroy() {
374
+ this.stopWatching();
375
+ }
376
+ // ==================== 文件监听相关方法 ====================
377
+ /**
378
+ * 启动文件监听(沙箱环境自动调用)
379
+ */
380
+ startWatching() {
381
+ if (this.fileWatcher) {
382
+ return;
383
+ }
384
+ if (!fs.existsSync(this.capabilitiesDir)) {
385
+ this.logger.warn(`Cannot start watching: directory not found: ${this.capabilitiesDir}`);
386
+ return;
387
+ }
388
+ const pattern = path.join(this.capabilitiesDir, "*.json");
389
+ const debounce = this.options.watchDebounce ?? 300;
390
+ this.logger.log(`Starting file watcher: ${pattern}`);
391
+ this.fileWatcher = chokidar.watch(pattern, {
392
+ persistent: true,
393
+ ignoreInitial: true,
394
+ awaitWriteFinish: {
395
+ // 等待写入完成
396
+ stabilityThreshold: debounce,
397
+ pollInterval: 100
398
+ }
399
+ });
400
+ this.fileWatcher.on("add", (filePath) => this.handleFileAdd(filePath)).on("change", (filePath) => this.handleFileChange(filePath)).on("unlink", (filePath) => this.handleFileUnlink(filePath)).on("error", (error) => this.logger.error("File watcher error:", error));
401
+ this.logger.log("File watcher started");
402
+ }
403
+ /**
404
+ * 停止文件监听
405
+ */
406
+ stopWatching() {
407
+ if (this.fileWatcher) {
408
+ this.fileWatcher.close();
409
+ this.fileWatcher = null;
410
+ this.logger.log("File watcher stopped");
411
+ }
412
+ }
413
+ /**
414
+ * 重新加载所有能力配置
415
+ */
416
+ async reloadAllCapabilities() {
417
+ this.capabilities.clear();
418
+ this.filePathToId.clear();
419
+ await this.loadCapabilities();
420
+ }
421
+ handleFileAdd(filePath) {
422
+ this.logger.log(`Capability file added: ${filePath}`);
423
+ try {
424
+ this.loadCapabilityFromFile(filePath);
425
+ } catch (error) {
426
+ this.logger.error(`Failed to load new capability: ${filePath}`, error);
427
+ }
428
+ }
429
+ handleFileChange(filePath) {
430
+ this.logger.log(`Capability file changed: ${filePath}`);
431
+ try {
432
+ this.reloadCapabilityFromFile(filePath);
433
+ } catch (error) {
434
+ this.logger.error(`Failed to reload capability: ${filePath}`, error);
435
+ }
436
+ }
437
+ handleFileUnlink(filePath) {
438
+ this.logger.log(`Capability file removed: ${filePath}`);
439
+ this.removeCapabilityByFile(filePath);
440
+ }
441
+ /**
442
+ * 从文件加载单个能力配置
443
+ */
444
+ loadCapabilityFromFile(filePath) {
445
+ const content = fs.readFileSync(filePath, "utf-8");
446
+ const config = JSON.parse(content);
447
+ if (!config.id) {
448
+ this.logger.warn(`Skipping capability without id: ${filePath}`);
449
+ return;
450
+ }
451
+ this.capabilities.set(config.id, config);
452
+ this.filePathToId.set(filePath, config.id);
453
+ this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
454
+ }
455
+ /**
456
+ * 重新加载单个能力配置
457
+ */
458
+ reloadCapabilityFromFile(filePath) {
459
+ const oldId = this.filePathToId.get(filePath);
460
+ if (oldId) {
461
+ const oldConfig = this.capabilities.get(oldId);
462
+ if (oldConfig) {
463
+ this.pluginLoaderService.clearCache(oldConfig.pluginKey);
464
+ }
465
+ this.capabilities.delete(oldId);
466
+ }
467
+ this.loadCapabilityFromFile(filePath);
468
+ }
469
+ /**
470
+ * 根据文件路径移除能力配置
471
+ */
472
+ removeCapabilityByFile(filePath) {
473
+ const capabilityId = this.filePathToId.get(filePath);
474
+ if (capabilityId) {
475
+ this.capabilities.delete(capabilityId);
476
+ this.filePathToId.delete(filePath);
477
+ this.logger.log(`Removed capability: ${capabilityId}`);
478
+ }
245
479
  }
480
+ // ==================== 原有方法 ====================
246
481
  async loadCapabilities() {
247
482
  this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);
248
483
  if (!fs.existsSync(this.capabilitiesDir)) {
@@ -253,14 +488,7 @@ var CapabilityService = class _CapabilityService {
253
488
  for (const file of files) {
254
489
  try {
255
490
  const filePath = path.join(this.capabilitiesDir, file);
256
- const content = fs.readFileSync(filePath, "utf-8");
257
- const config = JSON.parse(content);
258
- if (!config.id) {
259
- this.logger.warn(`Skipping capability without id: ${file}`);
260
- continue;
261
- }
262
- this.capabilities.set(config.id, config);
263
- this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
491
+ this.loadCapabilityFromFile(filePath);
264
492
  } catch (error) {
265
493
  this.logger.error(`Failed to load capability from ${file}:`, error);
266
494
  }
@@ -278,56 +506,246 @@ var CapabilityService = class _CapabilityService {
278
506
  if (!config) {
279
507
  throw new CapabilityNotFoundError(capabilityId);
280
508
  }
509
+ return this.createExecutor(config);
510
+ }
511
+ /**
512
+ * 使用传入的配置加载能力执行器
513
+ * 用于 debug 场景,支持用户传入自定义配置
514
+ */
515
+ loadWithConfig(config) {
516
+ return this.createExecutor(config);
517
+ }
518
+ createExecutor(config) {
281
519
  return {
282
520
  call: /* @__PURE__ */ __name(async (actionName, input, contextOverride) => {
283
- return this.execute(config, actionName, input, contextOverride);
284
- }, "call")
521
+ return this.executeCall(config, actionName, input, contextOverride);
522
+ }, "call"),
523
+ callStream: /* @__PURE__ */ __name((actionName, input, contextOverride) => {
524
+ return this.executeCallStream(config, actionName, input, contextOverride);
525
+ }, "callStream"),
526
+ callStreamWithEvents: /* @__PURE__ */ __name((actionName, input, contextOverride) => {
527
+ return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);
528
+ }, "callStreamWithEvents"),
529
+ isStream: /* @__PURE__ */ __name(async (actionName) => {
530
+ return this.checkIsStream(config, actionName);
531
+ }, "isStream")
285
532
  };
286
533
  }
287
- async execute(config, actionName, input, contextOverride) {
534
+ /**
535
+ * 检查 action 是否为流式
536
+ */
537
+ async checkIsStream(config, actionName) {
538
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
539
+ if (!pluginInstance.hasAction(actionName)) {
540
+ throw new ActionNotFoundError(config.pluginKey, actionName);
541
+ }
542
+ return pluginInstance.isStreamAction?.(actionName) ?? false;
543
+ }
544
+ /**
545
+ * 执行 capability(始终返回 Promise)
546
+ * - unary action: 直接返回结果
547
+ * - stream action: 内部聚合所有 chunk 后返回
548
+ */
549
+ async executeCall(config, actionName, input, contextOverride) {
288
550
  const startTime = Date.now();
551
+ const loggerContext = {
552
+ capability_id: config.id,
553
+ plugin_key: config.pluginKey,
554
+ action: actionName
555
+ };
289
556
  try {
290
- const pluginInstance = this.pluginLoaderService.loadPlugin(config.pluginID);
557
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
291
558
  if (!pluginInstance.hasAction(actionName)) {
292
- throw new ActionNotFoundError(config.pluginID, actionName);
559
+ throw new ActionNotFoundError(config.pluginKey, actionName);
293
560
  }
294
- const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
561
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
295
562
  const context = this.buildActionContext(contextOverride);
296
- this.logger.log({
297
- message: "Executing capability",
298
- capabilityId: config.id,
299
- action: actionName,
300
- pluginID: config.pluginID
563
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
564
+ this.logger.log("Executing capability (call)", {
565
+ ...loggerContext,
566
+ is_stream: isStream,
567
+ input: stringifyForLog(input)
301
568
  });
302
- const result = await pluginInstance.run(actionName, context, resolvedParams);
303
- this.logger.log({
304
- message: "Capability executed successfully",
305
- capabilityId: config.id,
306
- action: actionName,
307
- duration: Date.now() - startTime
569
+ let result;
570
+ if (isStream && pluginInstance.runStream) {
571
+ const chunks = [];
572
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
573
+ chunks.push(chunk);
574
+ }
575
+ result = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
576
+ } else {
577
+ result = await pluginInstance.run(actionName, context, resolvedParams);
578
+ }
579
+ this.logger.log("Capability (call) executed successfully", {
580
+ ...loggerContext,
581
+ duration_ms: Date.now() - startTime,
582
+ output: stringifyForLog(result)
308
583
  });
309
584
  return result;
310
585
  } catch (error) {
311
- this.logger.error({
312
- message: "Capability execution failed",
313
- capabilityId: config.id,
314
- action: actionName,
315
- error: error instanceof Error ? error.message : String(error),
316
- duration: Date.now() - startTime
586
+ this.logger.error("Capability (call) execution failed", {
587
+ ...loggerContext,
588
+ duration_ms: Date.now() - startTime,
589
+ error: error instanceof Error ? error.message : String(error)
590
+ });
591
+ throw error;
592
+ }
593
+ }
594
+ /**
595
+ * 流式执行 capability
596
+ * - stream action: 返回原始 AsyncIterable
597
+ * - unary action: 包装为单次 yield
598
+ */
599
+ async *executeCallStream(config, actionName, input, contextOverride) {
600
+ const startTime = Date.now();
601
+ const loggerContext = {
602
+ capability_id: config.id,
603
+ plugin_key: config.pluginKey,
604
+ action: actionName
605
+ };
606
+ const chunks = [];
607
+ try {
608
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
609
+ if (!pluginInstance.hasAction(actionName)) {
610
+ throw new ActionNotFoundError(config.pluginKey, actionName);
611
+ }
612
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
613
+ const context = this.buildActionContext(contextOverride);
614
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
615
+ this.logger.log("Executing capability (stream)", {
616
+ ...loggerContext,
617
+ is_stream: isStream,
618
+ input: stringifyForLog(input)
619
+ });
620
+ if (isStream && pluginInstance.runStream) {
621
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
622
+ chunks.push(chunk);
623
+ yield chunk;
624
+ }
625
+ } else {
626
+ const result = await pluginInstance.run(actionName, context, resolvedParams);
627
+ chunks.push(result);
628
+ yield result;
629
+ }
630
+ const aggregatedResult = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
631
+ this.logger.log("Capability (stream) executed successfully", {
632
+ ...loggerContext,
633
+ duration_ms: Date.now() - startTime,
634
+ output: stringifyForLog(aggregatedResult)
635
+ });
636
+ } catch (error) {
637
+ this.logger.error("Capability (stream) execution failed", {
638
+ ...loggerContext,
639
+ duration_ms: Date.now() - startTime,
640
+ error: error instanceof Error ? error.message : String(error)
317
641
  });
318
642
  throw error;
319
643
  }
320
644
  }
645
+ /**
646
+ * 流式执行 capability,返回带事件协议的流
647
+ * - 优先使用 pluginInstance.runStreamWithEvents
648
+ * - 如果插件不支持,则包装 runStream/run 为 StreamEvent
649
+ */
650
+ async *executeCallStreamWithEvents(config, actionName, input, contextOverride) {
651
+ const startTime = Date.now();
652
+ const loggerContext = {
653
+ capability_id: config.id,
654
+ plugin_key: config.pluginKey,
655
+ action: actionName
656
+ };
657
+ const chunks = [];
658
+ try {
659
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
660
+ if (!pluginInstance.hasAction(actionName)) {
661
+ throw new ActionNotFoundError(config.pluginKey, actionName);
662
+ }
663
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
664
+ const context = this.buildActionContext(contextOverride);
665
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
666
+ this.logger.log("Executing capability (streamWithEvents)", {
667
+ ...loggerContext,
668
+ is_stream: isStream,
669
+ input: stringifyForLog(input)
670
+ });
671
+ if (pluginInstance.runStreamWithEvents) {
672
+ for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {
673
+ if (event.type === "data") {
674
+ chunks.push(event.data);
675
+ yield event;
676
+ } else if (event.type === "done") {
677
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
678
+ yield {
679
+ type: "done",
680
+ metadata: {
681
+ ...event.metadata,
682
+ aggregated: aggregatedResult2
683
+ }
684
+ };
685
+ } else {
686
+ yield event;
687
+ }
688
+ }
689
+ } else {
690
+ if (isStream && pluginInstance.runStream) {
691
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
692
+ chunks.push(chunk);
693
+ yield {
694
+ type: "data",
695
+ data: chunk
696
+ };
697
+ }
698
+ } else {
699
+ const result = await pluginInstance.run(actionName, context, resolvedParams);
700
+ chunks.push(result);
701
+ yield {
702
+ type: "data",
703
+ data: result
704
+ };
705
+ }
706
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
707
+ yield {
708
+ type: "done",
709
+ metadata: {
710
+ chunks: chunks.length,
711
+ duration: Date.now() - startTime,
712
+ aggregated: aggregatedResult2
713
+ }
714
+ };
715
+ }
716
+ const aggregatedResult = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
717
+ this.logger.log("Capability (streamWithEvents) executed successfully", {
718
+ ...loggerContext,
719
+ duration_ms: Date.now() - startTime,
720
+ output: stringifyForLog(aggregatedResult)
721
+ });
722
+ } catch (error) {
723
+ this.logger.error("Capability (streamWithEvents) execution failed", {
724
+ ...loggerContext,
725
+ duration_ms: Date.now() - startTime,
726
+ error: error instanceof Error ? error.message : String(error)
727
+ });
728
+ yield {
729
+ type: "error",
730
+ error: {
731
+ code: "EXECUTION_ERROR",
732
+ message: error instanceof Error ? error.message : String(error)
733
+ }
734
+ };
735
+ }
736
+ }
321
737
  buildActionContext(override) {
322
738
  return {
323
739
  logger: this.logger,
324
- httpClient: this.httpClient,
325
- userContext: override?.userContext ?? this.getUserContext()
740
+ platformHttpClient: this.platformHttpClient,
741
+ userContext: override?.userContext ?? this.getUserContext(),
742
+ isDebug: override?.isDebug ?? false
326
743
  };
327
744
  }
328
745
  getUserContext() {
329
746
  const ctx = this.requestContextService.getContext();
330
747
  return {
748
+ appId: ctx?.appId ?? "",
331
749
  userId: ctx?.userId ?? "",
332
750
  tenantId: ctx?.tenantId ?? ""
333
751
  };
@@ -364,31 +782,41 @@ function _ts_param2(paramIndex, decorator) {
364
782
  };
365
783
  }
366
784
  __name(_ts_param2, "_ts_param");
367
- var DebugController = class {
785
+ var DebugController = class _DebugController {
368
786
  static {
369
787
  __name(this, "DebugController");
370
788
  }
371
789
  capabilityService;
790
+ pluginLoaderService;
372
791
  templateEngineService;
373
- constructor(capabilityService, templateEngineService) {
792
+ logger = new import_common4.Logger(_DebugController.name);
793
+ constructor(capabilityService, pluginLoaderService, templateEngineService) {
374
794
  this.capabilityService = capabilityService;
795
+ this.pluginLoaderService = pluginLoaderService;
375
796
  this.templateEngineService = templateEngineService;
376
797
  }
377
798
  list() {
378
799
  const capabilities = this.capabilityService.listCapabilities();
379
800
  return {
380
- code: 0,
381
- message: "success",
382
- data: capabilities.map((c) => ({
383
- id: c.id,
384
- name: c.name,
385
- pluginID: c.pluginID,
386
- pluginVersion: c.pluginVersion
387
- }))
801
+ status_code: ErrorCodes.SUCCESS,
802
+ data: {
803
+ capabilities: capabilities.map((c) => ({
804
+ id: c.id,
805
+ name: c.name,
806
+ pluginID: c.pluginKey,
807
+ pluginVersion: c.pluginVersion
808
+ }))
809
+ }
388
810
  };
389
811
  }
390
- async debug(capabilityId, body) {
391
- const startTime = Date.now();
812
+ /**
813
+ * 获取 capability 配置
814
+ * 优先使用 body.capability,否则从服务获取
815
+ */
816
+ getCapabilityConfig(capabilityId, bodyCapability) {
817
+ if (bodyCapability) {
818
+ return bodyCapability;
819
+ }
392
820
  const config = this.capabilityService.getCapability(capabilityId);
393
821
  if (!config) {
394
822
  throw new import_common4.HttpException({
@@ -397,72 +825,194 @@ var DebugController = class {
397
825
  error: "CAPABILITY_NOT_FOUND"
398
826
  }, import_common4.HttpStatus.NOT_FOUND);
399
827
  }
400
- const resolvedParams = this.templateEngineService.resolve(config.formValue, body.params);
828
+ return config;
829
+ }
830
+ /**
831
+ * 获取 action 名称
832
+ * 优先使用传入的 action,否则使用插件第一个 action
833
+ */
834
+ async getActionName(pluginKey, bodyAction) {
835
+ if (bodyAction) {
836
+ return bodyAction;
837
+ }
838
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
839
+ const actions = pluginInstance.listActions();
840
+ if (actions.length === 0) {
841
+ throw new import_common4.HttpException({
842
+ code: 1,
843
+ message: `Plugin ${pluginKey} has no actions`,
844
+ error: "NO_ACTIONS"
845
+ }, import_common4.HttpStatus.BAD_REQUEST);
846
+ }
847
+ return actions[0];
848
+ }
849
+ async debug(capabilityId, body) {
850
+ const startTime = Date.now();
851
+ const params = body.params ?? {};
852
+ const config = this.getCapabilityConfig(capabilityId, body.capability);
853
+ const action = await this.getActionName(config.pluginKey, body.action);
854
+ const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
401
855
  try {
402
- const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
856
+ const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
857
+ isDebug: true
858
+ });
403
859
  return {
404
- code: 0,
405
- message: "success",
406
- data: result,
407
- debug: {
408
- capabilityConfig: config,
409
- resolvedParams,
410
- duration: Date.now() - startTime,
411
- pluginID: config.pluginID
860
+ status_code: ErrorCodes.SUCCESS,
861
+ data: {
862
+ output: result,
863
+ debug: {
864
+ capabilityConfig: config,
865
+ resolvedParams,
866
+ duration: Date.now() - startTime,
867
+ pluginID: config.pluginKey,
868
+ action
869
+ }
412
870
  }
413
871
  };
414
872
  } catch (error) {
415
- const duration = Date.now() - startTime;
416
873
  if (error instanceof CapabilityNotFoundError) {
417
874
  throw new import_common4.HttpException({
418
- code: 1,
419
- message: error.message,
420
- error: "CAPABILITY_NOT_FOUND",
421
- debug: {
422
- duration
423
- }
875
+ status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
876
+ error_msg: `Capability not found: ${capabilityId}`
424
877
  }, import_common4.HttpStatus.NOT_FOUND);
425
878
  }
426
879
  if (error instanceof PluginNotFoundError) {
427
880
  throw new import_common4.HttpException({
428
- code: 1,
429
- message: error.message,
430
- error: "PLUGIN_NOT_FOUND",
431
- debug: {
432
- duration,
433
- pluginID: config.pluginID
434
- }
881
+ status_code: ErrorCodes.PLUGIN_NOT_FOUND,
882
+ error_msg: `Plugin not found: ${config.pluginKey}`
435
883
  }, import_common4.HttpStatus.INTERNAL_SERVER_ERROR);
436
884
  }
437
885
  if (error instanceof ActionNotFoundError) {
438
886
  throw new import_common4.HttpException({
439
- code: 1,
440
- message: error.message,
441
- error: "ACTION_NOT_FOUND",
442
- debug: {
443
- duration,
444
- pluginID: config.pluginID
445
- }
887
+ status_code: ErrorCodes.ACTION_NOT_FOUND,
888
+ error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`
446
889
  }, import_common4.HttpStatus.BAD_REQUEST);
447
890
  }
448
891
  throw new import_common4.HttpException({
449
- code: 1,
450
- message: error instanceof Error ? error.message : String(error),
451
- error: "EXECUTION_ERROR",
452
- debug: {
453
- duration,
454
- pluginID: config.pluginID,
455
- resolvedParams
456
- }
892
+ status_code: ErrorCodes.EXECUTION_ERROR,
893
+ error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
457
894
  }, import_common4.HttpStatus.INTERNAL_SERVER_ERROR);
458
895
  }
459
896
  }
897
+ async debugStream(capabilityId, body, res) {
898
+ const params = body.params ?? {};
899
+ res.setHeader("Content-Type", "text/event-stream");
900
+ res.setHeader("Cache-Control", "no-cache");
901
+ res.setHeader("Connection", "keep-alive");
902
+ try {
903
+ const config = this.getCapabilityConfig(capabilityId, body.capability);
904
+ const action = await this.getActionName(config.pluginKey, body.action);
905
+ const loggerContext = {
906
+ capability_id: config.id,
907
+ plugin_key: config.pluginKey,
908
+ action
909
+ };
910
+ this.logger.log(`Executing capability (stream)`, {
911
+ ...loggerContext,
912
+ input: stringifyForLog(params)
913
+ });
914
+ const capability = this.capabilityService.loadWithConfig(config);
915
+ const eventStream = capability.callStreamWithEvents(action, params, {
916
+ isDebug: true
917
+ });
918
+ let pendingChunk = null;
919
+ for await (const event of eventStream) {
920
+ switch (event.type) {
921
+ case "data": {
922
+ if (pendingChunk !== null) {
923
+ const response = {
924
+ status_code: ErrorCodes.SUCCESS,
925
+ data: {
926
+ type: "content",
927
+ delta: pendingChunk
928
+ }
929
+ };
930
+ res.write(`data: ${JSON.stringify(response)}
931
+
932
+ `);
933
+ }
934
+ pendingChunk = event.data;
935
+ break;
936
+ }
937
+ case "done": {
938
+ if (pendingChunk !== null) {
939
+ const response = {
940
+ status_code: ErrorCodes.SUCCESS,
941
+ data: {
942
+ type: "content",
943
+ delta: pendingChunk,
944
+ finished: true
945
+ }
946
+ };
947
+ res.write(`data: ${JSON.stringify(response)}
948
+
949
+ `);
950
+ }
951
+ this.logger.log(`Capability (stream) executed successfully`, {
952
+ ...loggerContext,
953
+ duration_ms: event.metadata.duration,
954
+ output: stringifyForLog(event.metadata.aggregated)
955
+ });
956
+ res.end();
957
+ return;
958
+ }
959
+ case "error": {
960
+ const response = {
961
+ status_code: ErrorCodes.SUCCESS,
962
+ data: {
963
+ type: "error",
964
+ error: {
965
+ code: 0,
966
+ message: event.error.message
967
+ }
968
+ }
969
+ };
970
+ res.write(`data: ${JSON.stringify(response)}
971
+
972
+ `);
973
+ res.end();
974
+ return;
975
+ }
976
+ }
977
+ }
978
+ if (pendingChunk !== null) {
979
+ const response = {
980
+ status_code: ErrorCodes.SUCCESS,
981
+ data: {
982
+ type: "content",
983
+ delta: pendingChunk,
984
+ finished: true
985
+ }
986
+ };
987
+ res.write(`data: ${JSON.stringify(response)}
988
+
989
+ `);
990
+ }
991
+ res.end();
992
+ } catch (error) {
993
+ const errorMsg = error instanceof Error ? error.message : String(error);
994
+ const response = {
995
+ status_code: ErrorCodes.SUCCESS,
996
+ data: {
997
+ type: "error",
998
+ error: {
999
+ code: 0,
1000
+ message: errorMsg
1001
+ }
1002
+ }
1003
+ };
1004
+ res.write(`data: ${JSON.stringify(response)}
1005
+
1006
+ `);
1007
+ res.end();
1008
+ }
1009
+ }
460
1010
  };
461
1011
  _ts_decorate4([
462
1012
  (0, import_common4.Get)("list"),
463
1013
  _ts_metadata2("design:type", Function),
464
1014
  _ts_metadata2("design:paramtypes", []),
465
- _ts_metadata2("design:returntype", typeof ListResponse === "undefined" ? Object : ListResponse)
1015
+ _ts_metadata2("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
466
1016
  ], DebugController.prototype, "list", null);
467
1017
  _ts_decorate4([
468
1018
  (0, import_common4.Post)("debug/:capability_id"),
@@ -471,15 +1021,29 @@ _ts_decorate4([
471
1021
  _ts_metadata2("design:type", Function),
472
1022
  _ts_metadata2("design:paramtypes", [
473
1023
  String,
474
- typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody
1024
+ typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody
475
1025
  ]),
476
1026
  _ts_metadata2("design:returntype", Promise)
477
1027
  ], DebugController.prototype, "debug", null);
1028
+ _ts_decorate4([
1029
+ (0, import_common4.Post)("debug/:capability_id/stream"),
1030
+ _ts_param2(0, (0, import_common4.Param)("capability_id")),
1031
+ _ts_param2(1, (0, import_common4.Body)()),
1032
+ _ts_param2(2, (0, import_common4.Res)()),
1033
+ _ts_metadata2("design:type", Function),
1034
+ _ts_metadata2("design:paramtypes", [
1035
+ String,
1036
+ typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody,
1037
+ typeof Response === "undefined" ? Object : Response
1038
+ ]),
1039
+ _ts_metadata2("design:returntype", Promise)
1040
+ ], DebugController.prototype, "debugStream", null);
478
1041
  DebugController = _ts_decorate4([
479
1042
  (0, import_common4.Controller)("__innerapi__/capability"),
480
1043
  _ts_metadata2("design:type", Function),
481
1044
  _ts_metadata2("design:paramtypes", [
482
1045
  typeof CapabilityService === "undefined" ? Object : CapabilityService,
1046
+ typeof PluginLoaderService === "undefined" ? Object : PluginLoaderService,
483
1047
  typeof TemplateEngineService === "undefined" ? Object : TemplateEngineService
484
1048
  ])
485
1049
  ], DebugController);
@@ -503,52 +1067,177 @@ function _ts_param3(paramIndex, decorator) {
503
1067
  };
504
1068
  }
505
1069
  __name(_ts_param3, "_ts_param");
506
- var WebhookController = class {
1070
+ var WebhookController = class _WebhookController {
507
1071
  static {
508
1072
  __name(this, "WebhookController");
509
1073
  }
510
1074
  capabilityService;
1075
+ logger = new import_common5.Logger(_WebhookController.name);
511
1076
  constructor(capabilityService) {
512
1077
  this.capabilityService = capabilityService;
513
1078
  }
1079
+ list() {
1080
+ const capabilities = this.capabilityService.listCapabilities();
1081
+ return {
1082
+ status_code: ErrorCodes.SUCCESS,
1083
+ data: {
1084
+ capabilities: capabilities.map((c) => ({
1085
+ id: c.id,
1086
+ name: c.name,
1087
+ pluginID: c.pluginKey,
1088
+ pluginVersion: c.pluginVersion
1089
+ }))
1090
+ }
1091
+ };
1092
+ }
514
1093
  async execute(capabilityId, body) {
515
1094
  try {
516
1095
  const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
517
1096
  return {
518
- code: 0,
519
- message: "success",
520
- data: result
1097
+ status_code: ErrorCodes.SUCCESS,
1098
+ data: {
1099
+ output: result
1100
+ }
521
1101
  };
522
1102
  } catch (error) {
523
1103
  if (error instanceof CapabilityNotFoundError) {
524
1104
  throw new import_common5.HttpException({
525
- code: 1,
526
- message: error.message,
527
- error: "CAPABILITY_NOT_FOUND"
1105
+ status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
1106
+ error_msg: `Capability not found: ${capabilityId}`
528
1107
  }, import_common5.HttpStatus.NOT_FOUND);
529
1108
  }
530
1109
  if (error instanceof PluginNotFoundError) {
531
1110
  throw new import_common5.HttpException({
532
- code: 1,
533
- message: error.message,
534
- error: "PLUGIN_NOT_FOUND"
1111
+ status_code: ErrorCodes.PLUGIN_NOT_FOUND,
1112
+ error_msg: `Plugin not found`
535
1113
  }, import_common5.HttpStatus.INTERNAL_SERVER_ERROR);
536
1114
  }
537
1115
  if (error instanceof ActionNotFoundError) {
538
1116
  throw new import_common5.HttpException({
539
- code: 1,
540
- message: error.message,
541
- error: "ACTION_NOT_FOUND"
1117
+ status_code: ErrorCodes.ACTION_NOT_FOUND,
1118
+ error_msg: `Action '${body.action}' not found`
542
1119
  }, import_common5.HttpStatus.BAD_REQUEST);
543
1120
  }
544
1121
  throw new import_common5.HttpException({
545
- code: 1,
546
- message: error instanceof Error ? error.message : String(error),
547
- error: "EXECUTION_ERROR"
1122
+ status_code: ErrorCodes.EXECUTION_ERROR,
1123
+ error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
548
1124
  }, import_common5.HttpStatus.INTERNAL_SERVER_ERROR);
549
1125
  }
550
1126
  }
1127
+ async executeStream(capabilityId, body, res) {
1128
+ const loggerContext = {
1129
+ capability_id: capabilityId,
1130
+ action: body.action
1131
+ };
1132
+ res.setHeader("Content-Type", "text/event-stream");
1133
+ res.setHeader("Cache-Control", "no-cache");
1134
+ res.setHeader("Connection", "keep-alive");
1135
+ try {
1136
+ this.logger.log(`Executing capability (stream)`, {
1137
+ ...loggerContext,
1138
+ input: stringifyForLog(body.params)
1139
+ });
1140
+ const capability = this.capabilityService.load(capabilityId);
1141
+ const eventStream = capability.callStreamWithEvents(body.action, body.params);
1142
+ let pendingChunk = null;
1143
+ for await (const event of eventStream) {
1144
+ switch (event.type) {
1145
+ case "data": {
1146
+ if (pendingChunk !== null) {
1147
+ const response = {
1148
+ status_code: ErrorCodes.SUCCESS,
1149
+ data: {
1150
+ type: "content",
1151
+ delta: pendingChunk
1152
+ }
1153
+ };
1154
+ res.write(`data: ${JSON.stringify(response)}
1155
+
1156
+ `);
1157
+ }
1158
+ pendingChunk = event.data;
1159
+ break;
1160
+ }
1161
+ case "done": {
1162
+ if (pendingChunk !== null) {
1163
+ const response = {
1164
+ status_code: ErrorCodes.SUCCESS,
1165
+ data: {
1166
+ type: "content",
1167
+ delta: pendingChunk,
1168
+ finished: true
1169
+ }
1170
+ };
1171
+ res.write(`data: ${JSON.stringify(response)}
1172
+
1173
+ `);
1174
+ }
1175
+ this.logger.log(`Capability (stream) executed successfully`, {
1176
+ ...loggerContext,
1177
+ duration_ms: event.metadata.duration,
1178
+ output: stringifyForLog(event.metadata.aggregated)
1179
+ });
1180
+ res.end();
1181
+ return;
1182
+ }
1183
+ case "error": {
1184
+ const response = {
1185
+ status_code: ErrorCodes.SUCCESS,
1186
+ data: {
1187
+ type: "error",
1188
+ error: {
1189
+ code: 0,
1190
+ message: event.error.message
1191
+ }
1192
+ }
1193
+ };
1194
+ res.write(`data: ${JSON.stringify(response)}
1195
+
1196
+ `);
1197
+ res.end();
1198
+ return;
1199
+ }
1200
+ }
1201
+ }
1202
+ if (pendingChunk !== null) {
1203
+ const response = {
1204
+ status_code: ErrorCodes.SUCCESS,
1205
+ data: {
1206
+ type: "content",
1207
+ delta: pendingChunk,
1208
+ finished: true
1209
+ }
1210
+ };
1211
+ res.write(`data: ${JSON.stringify(response)}
1212
+
1213
+ `);
1214
+ }
1215
+ res.end();
1216
+ } catch (error) {
1217
+ const errorMsg = error instanceof Error ? error.message : String(error);
1218
+ const response = {
1219
+ status_code: ErrorCodes.SUCCESS,
1220
+ data: {
1221
+ type: "error",
1222
+ error: {
1223
+ code: 0,
1224
+ message: errorMsg
1225
+ }
1226
+ }
1227
+ };
1228
+ res.write(`data: ${JSON.stringify(response)}
1229
+
1230
+ `);
1231
+ res.end();
1232
+ }
1233
+ }
551
1234
  };
1235
+ _ts_decorate5([
1236
+ (0, import_common5.Get)("list"),
1237
+ _ts_metadata3("design:type", Function),
1238
+ _ts_metadata3("design:paramtypes", []),
1239
+ _ts_metadata3("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
1240
+ ], WebhookController.prototype, "list", null);
552
1241
  _ts_decorate5([
553
1242
  (0, import_common5.Post)(":capability_id"),
554
1243
  _ts_param3(0, (0, import_common5.Param)("capability_id")),
@@ -560,6 +1249,19 @@ _ts_decorate5([
560
1249
  ]),
561
1250
  _ts_metadata3("design:returntype", Promise)
562
1251
  ], WebhookController.prototype, "execute", null);
1252
+ _ts_decorate5([
1253
+ (0, import_common5.Post)(":capability_id/stream"),
1254
+ _ts_param3(0, (0, import_common5.Param)("capability_id")),
1255
+ _ts_param3(1, (0, import_common5.Body)()),
1256
+ _ts_param3(2, (0, import_common5.Res)()),
1257
+ _ts_metadata3("design:type", Function),
1258
+ _ts_metadata3("design:paramtypes", [
1259
+ String,
1260
+ typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody,
1261
+ typeof Response === "undefined" ? Object : Response
1262
+ ]),
1263
+ _ts_metadata3("design:returntype", Promise)
1264
+ ], WebhookController.prototype, "executeStream", null);
563
1265
  WebhookController = _ts_decorate5([
564
1266
  (0, import_common5.Controller)("api/capability"),
565
1267
  _ts_metadata3("design:type", Function),
@@ -597,6 +1299,9 @@ var CapabilityModule = class _CapabilityModule {
597
1299
  static forRoot(options) {
598
1300
  return {
599
1301
  module: _CapabilityModule,
1302
+ imports: [
1303
+ import_nestjs_common2.CommonModule
1304
+ ],
600
1305
  controllers: getControllers(),
601
1306
  providers: [
602
1307
  {
@@ -607,8 +1312,8 @@ var CapabilityModule = class _CapabilityModule {
607
1312
  provide: CapabilityService,
608
1313
  useFactory: /* @__PURE__ */ __name((requestContextService, httpClient, pluginLoader, templateEngine, moduleOptions) => {
609
1314
  const service = new CapabilityService(requestContextService, httpClient, pluginLoader, templateEngine);
610
- if (moduleOptions?.capabilitiesDir) {
611
- service.setCapabilitiesDir(moduleOptions.capabilitiesDir);
1315
+ if (moduleOptions) {
1316
+ service.setOptions(moduleOptions);
612
1317
  }
613
1318
  return service;
614
1319
  }, "useFactory"),
@@ -631,6 +1336,9 @@ var CapabilityModule = class _CapabilityModule {
631
1336
  };
632
1337
  CapabilityModule = _ts_decorate6([
633
1338
  (0, import_common6.Module)({
1339
+ imports: [
1340
+ import_nestjs_common2.CommonModule
1341
+ ],
634
1342
  controllers: getControllers(),
635
1343
  providers: [
636
1344
  CapabilityService,
@@ -649,6 +1357,7 @@ CapabilityModule = _ts_decorate6([
649
1357
  CapabilityNotFoundError,
650
1358
  CapabilityService,
651
1359
  DebugController,
1360
+ ErrorCodes,
652
1361
  PluginLoadError,
653
1362
  PluginLoaderService,
654
1363
  PluginNotFoundError,