autosnippet 3.3.0 → 3.3.3

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 (245) hide show
  1. package/dashboard/dist/assets/icons-BJ2mUBi8.js +1 -0
  2. package/dashboard/dist/assets/index-B659K9t5.js +128 -0
  3. package/dashboard/dist/assets/index-NCm40PMD.css +1 -0
  4. package/dashboard/dist/index.html +3 -3
  5. package/dist/bin/cli.d.ts +1 -0
  6. package/dist/bin/cli.js +284 -142
  7. package/dist/lib/agent/context/ExplorationTracker.d.ts +2 -0
  8. package/dist/lib/agent/context/ExplorationTracker.js +21 -3
  9. package/dist/lib/agent/core/ToolExecutionPipeline.d.ts +3 -1
  10. package/dist/lib/agent/core/ToolExecutionPipeline.js +8 -1
  11. package/dist/lib/agent/forge/DynamicComposer.d.ts +58 -0
  12. package/dist/lib/agent/forge/DynamicComposer.js +99 -0
  13. package/dist/lib/agent/forge/SandboxRunner.d.ts +60 -0
  14. package/dist/lib/agent/forge/SandboxRunner.js +251 -0
  15. package/dist/lib/agent/forge/TemporaryToolRegistry.d.ts +76 -0
  16. package/dist/lib/agent/forge/TemporaryToolRegistry.js +154 -0
  17. package/dist/lib/agent/forge/ToolForge.d.ts +92 -0
  18. package/dist/lib/agent/forge/ToolForge.js +239 -0
  19. package/dist/lib/agent/forge/ToolRequirementAnalyzer.d.ts +44 -0
  20. package/dist/lib/agent/forge/ToolRequirementAnalyzer.js +119 -0
  21. package/dist/lib/agent/tools/ToolRegistry.d.ts +2 -0
  22. package/dist/lib/agent/tools/ToolRegistry.js +4 -0
  23. package/dist/lib/agent/tools/composite.js +0 -1
  24. package/dist/lib/agent/tools/index.d.ts +2 -50
  25. package/dist/lib/agent/tools/index.js +2 -3
  26. package/dist/lib/agent/tools/lifecycle.d.ts +1 -58
  27. package/dist/lib/agent/tools/lifecycle.js +2 -75
  28. package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
  29. package/dist/lib/cli/KnowledgeSyncService.js +33 -1
  30. package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
  31. package/dist/lib/cli/deploy/FileManifest.js +0 -11
  32. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +10 -0
  33. package/dist/lib/domain/knowledge/KnowledgeEntry.js +2 -0
  34. package/dist/lib/domain/knowledge/Lifecycle.d.ts +19 -2
  35. package/dist/lib/domain/knowledge/Lifecycle.js +32 -6
  36. package/dist/lib/domain/knowledge/UnifiedValidator.d.ts +1 -5
  37. package/dist/lib/domain/knowledge/UnifiedValidator.js +7 -44
  38. package/dist/lib/domain/knowledge/values/Stats.d.ts +29 -0
  39. package/dist/lib/domain/knowledge/values/Stats.js +41 -0
  40. package/dist/lib/external/mcp/McpServer.d.ts +19 -38
  41. package/dist/lib/external/mcp/McpServer.js +145 -117
  42. package/dist/lib/external/mcp/autoApproveInjector.js +0 -2
  43. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +26 -1
  44. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +41 -0
  45. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -0
  46. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +3 -0
  47. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +27 -0
  48. package/dist/lib/external/mcp/handlers/bootstrap/skills.js +1 -1
  49. package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -0
  50. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
  51. package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
  52. package/dist/lib/external/mcp/handlers/browse.js +2 -1
  53. package/dist/lib/external/mcp/handlers/consolidated.d.ts +117 -6
  54. package/dist/lib/external/mcp/handlers/consolidated.js +251 -71
  55. package/dist/lib/external/mcp/handlers/guard.d.ts +150 -0
  56. package/dist/lib/external/mcp/handlers/guard.js +239 -5
  57. package/dist/lib/external/mcp/handlers/knowledge.d.ts +0 -29
  58. package/dist/lib/external/mcp/handlers/knowledge.js +1 -76
  59. package/dist/lib/external/mcp/handlers/panorama.d.ts +36 -0
  60. package/dist/lib/external/mcp/handlers/panorama.js +156 -0
  61. package/dist/lib/external/mcp/handlers/system.d.ts +2 -54
  62. package/dist/lib/external/mcp/handlers/system.js +3 -113
  63. package/dist/lib/external/mcp/handlers/task.d.ts +13 -24
  64. package/dist/lib/external/mcp/handlers/task.js +218 -557
  65. package/dist/lib/external/mcp/handlers/types.d.ts +91 -8
  66. package/dist/lib/external/mcp/handlers/types.js +18 -1
  67. package/dist/lib/external/mcp/handlers/wiki-external.d.ts +18 -1
  68. package/dist/lib/external/mcp/handlers/wiki-external.js +16 -1
  69. package/dist/lib/external/mcp/tools.d.ts +18 -24
  70. package/dist/lib/external/mcp/tools.js +132 -159
  71. package/dist/lib/http/HttpServer.js +52 -0
  72. package/dist/lib/http/middleware/validate.js +7 -3
  73. package/dist/lib/http/routes/audit.d.ts +8 -0
  74. package/dist/lib/http/routes/audit.js +51 -0
  75. package/dist/lib/http/routes/guardReport.d.ts +10 -0
  76. package/dist/lib/http/routes/guardReport.js +143 -0
  77. package/dist/lib/http/routes/knowledge.js +32 -1
  78. package/dist/lib/http/routes/panorama.d.ts +11 -0
  79. package/dist/lib/http/routes/panorama.js +322 -0
  80. package/dist/lib/http/routes/signals.d.ts +10 -0
  81. package/dist/lib/http/routes/signals.js +104 -0
  82. package/dist/lib/http/routes/task.d.ts +2 -3
  83. package/dist/lib/http/routes/task.js +17 -347
  84. package/dist/lib/http/routes/violations.js +1 -1
  85. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +6 -1
  86. package/dist/lib/infrastructure/audit/AuditLogger.js +14 -1
  87. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +202 -504
  88. package/dist/lib/infrastructure/database/drizzle/schema.js +38 -69
  89. package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.d.ts +8 -0
  90. package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.js +43 -0
  91. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
  92. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
  93. package/dist/lib/infrastructure/logging/Logger.d.ts +2 -0
  94. package/dist/lib/infrastructure/logging/Logger.js +34 -7
  95. package/dist/lib/infrastructure/monitoring/ErrorTracker.js +3 -1
  96. package/dist/lib/infrastructure/monitoring/PerformanceMonitor.d.ts +2 -2
  97. package/dist/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -10
  98. package/dist/lib/infrastructure/notification/LarkNotifier.d.ts +24 -0
  99. package/dist/lib/infrastructure/notification/LarkNotifier.js +97 -0
  100. package/dist/lib/infrastructure/report/ReportStore.d.ts +45 -0
  101. package/dist/lib/infrastructure/report/ReportStore.js +133 -0
  102. package/dist/lib/infrastructure/signal/SignalAggregator.d.ts +18 -0
  103. package/dist/lib/infrastructure/signal/SignalAggregator.js +84 -0
  104. package/dist/lib/infrastructure/signal/SignalBridge.d.ts +13 -0
  105. package/dist/lib/infrastructure/signal/SignalBridge.js +20 -0
  106. package/dist/lib/infrastructure/signal/SignalBus.d.ts +63 -0
  107. package/dist/lib/infrastructure/signal/SignalBus.js +106 -0
  108. package/dist/lib/infrastructure/signal/SignalTraceWriter.d.ts +36 -0
  109. package/dist/lib/infrastructure/signal/SignalTraceWriter.js +130 -0
  110. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
  111. package/dist/lib/injection/ServiceContainer.js +8 -0
  112. package/dist/lib/injection/ServiceMap.d.ts +16 -10
  113. package/dist/lib/injection/modules/AgentModule.d.ts +1 -1
  114. package/dist/lib/injection/modules/AgentModule.js +7 -1
  115. package/dist/lib/injection/modules/AppModule.d.ts +1 -1
  116. package/dist/lib/injection/modules/AppModule.js +4 -13
  117. package/dist/lib/injection/modules/GuardModule.js +27 -2
  118. package/dist/lib/injection/modules/InfraModule.d.ts +0 -1
  119. package/dist/lib/injection/modules/InfraModule.js +9 -7
  120. package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
  121. package/dist/lib/injection/modules/KnowledgeModule.js +131 -0
  122. package/dist/lib/injection/modules/PanoramaModule.d.ts +18 -0
  123. package/dist/lib/injection/modules/PanoramaModule.js +76 -0
  124. package/dist/lib/injection/modules/SignalModule.d.ts +10 -0
  125. package/dist/lib/injection/modules/SignalModule.js +84 -0
  126. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +1 -0
  127. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +6 -0
  128. package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +3 -1
  129. package/dist/lib/service/bootstrap/BootstrapTaskManager.js +20 -1
  130. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
  131. package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
  132. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +4 -5
  133. package/dist/lib/service/delivery/CursorDeliveryPipeline.d.ts +3 -1
  134. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +13 -10
  135. package/dist/lib/service/delivery/RulesGenerator.js +3 -2
  136. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +114 -0
  137. package/dist/lib/service/evolution/ConsolidationAdvisor.js +542 -0
  138. package/dist/lib/service/evolution/ContradictionDetector.d.ts +54 -0
  139. package/dist/lib/service/evolution/ContradictionDetector.js +253 -0
  140. package/dist/lib/service/evolution/DecayDetector.d.ts +71 -0
  141. package/dist/lib/service/evolution/DecayDetector.js +244 -0
  142. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +38 -0
  143. package/dist/lib/service/evolution/EnhancementSuggester.js +220 -0
  144. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +82 -0
  145. package/dist/lib/service/evolution/KnowledgeMetabolism.js +167 -0
  146. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +53 -0
  147. package/dist/lib/service/evolution/RedundancyAnalyzer.js +210 -0
  148. package/dist/lib/service/evolution/StagingManager.d.ts +57 -0
  149. package/dist/lib/service/evolution/StagingManager.js +201 -0
  150. package/dist/lib/service/guard/ComplianceReporter.d.ts +42 -2
  151. package/dist/lib/service/guard/ComplianceReporter.js +43 -5
  152. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +54 -0
  153. package/dist/lib/service/guard/CoverageAnalyzer.js +149 -0
  154. package/dist/lib/service/guard/GuardCheckEngine.d.ts +42 -0
  155. package/dist/lib/service/guard/GuardCheckEngine.js +465 -14
  156. package/dist/lib/service/guard/GuardFeedbackLoop.d.ts +3 -0
  157. package/dist/lib/service/guard/GuardFeedbackLoop.js +9 -0
  158. package/dist/lib/service/guard/ReverseGuard.d.ts +73 -0
  159. package/dist/lib/service/guard/ReverseGuard.js +256 -0
  160. package/dist/lib/service/guard/RuleLearner.d.ts +12 -0
  161. package/dist/lib/service/guard/RuleLearner.js +38 -0
  162. package/dist/lib/service/guard/UncertaintyCollector.d.ts +83 -0
  163. package/dist/lib/service/guard/UncertaintyCollector.js +149 -0
  164. package/dist/lib/service/guard/ViolationsStore.d.ts +1 -0
  165. package/dist/lib/service/guard/ViolationsStore.js +33 -3
  166. package/dist/lib/service/knowledge/ConfidenceRouter.d.ts +13 -0
  167. package/dist/lib/service/knowledge/ConfidenceRouter.js +14 -0
  168. package/dist/lib/service/knowledge/KnowledgeService.js +22 -4
  169. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
  170. package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
  171. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +27 -0
  172. package/dist/lib/service/panorama/CouplingAnalyzer.js +192 -0
  173. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +28 -0
  174. package/dist/lib/service/panorama/DimensionAnalyzer.js +320 -0
  175. package/dist/lib/service/panorama/LayerInferrer.d.ts +19 -0
  176. package/dist/lib/service/panorama/LayerInferrer.js +182 -0
  177. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +24 -0
  178. package/dist/lib/service/panorama/ModuleDiscoverer.js +185 -0
  179. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +29 -0
  180. package/dist/lib/service/panorama/PanoramaAggregator.js +228 -0
  181. package/dist/lib/service/panorama/PanoramaScanner.d.ts +52 -0
  182. package/dist/lib/service/panorama/PanoramaScanner.js +188 -0
  183. package/dist/lib/service/panorama/PanoramaService.d.ts +125 -0
  184. package/dist/lib/service/panorama/PanoramaService.js +363 -0
  185. package/dist/lib/service/panorama/PanoramaTypes.d.ts +134 -0
  186. package/dist/lib/service/panorama/PanoramaTypes.js +6 -0
  187. package/dist/lib/service/panorama/RoleRefiner.d.ts +48 -0
  188. package/dist/lib/service/panorama/RoleRefiner.js +535 -0
  189. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  190. package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
  191. package/dist/lib/service/search/CoarseRanker.js +11 -10
  192. package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
  193. package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
  194. package/dist/lib/service/search/MultiSignalRanker.d.ts +3 -2
  195. package/dist/lib/service/search/MultiSignalRanker.js +17 -1
  196. package/dist/lib/service/search/SearchEngine.d.ts +9 -7
  197. package/dist/lib/service/search/SearchEngine.js +67 -10
  198. package/dist/lib/service/search/SearchTypes.d.ts +25 -3
  199. package/dist/lib/service/search/SearchTypes.js +6 -1
  200. package/dist/lib/service/signal/HitRecorder.d.ts +68 -0
  201. package/dist/lib/service/signal/HitRecorder.js +173 -0
  202. package/dist/lib/service/skills/SignalCollector.d.ts +3 -1
  203. package/dist/lib/service/skills/SignalCollector.js +31 -1
  204. package/dist/lib/service/task/IntentExtractor.d.ts +66 -0
  205. package/dist/lib/service/task/IntentExtractor.js +256 -0
  206. package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
  207. package/dist/lib/service/task/PrimeSearchPipeline.js +113 -0
  208. package/dist/lib/service/vector/VectorService.d.ts +3 -0
  209. package/dist/lib/service/vector/VectorService.js +38 -4
  210. package/dist/lib/shared/schemas/mcp-tools.d.ts +41 -96
  211. package/dist/lib/shared/schemas/mcp-tools.js +59 -119
  212. package/dist/scripts/analyze-signals.d.ts +20 -0
  213. package/dist/scripts/analyze-signals.js +155 -0
  214. package/dist/scripts/diagnose-mcp.js +1 -1
  215. package/package.json +1 -1
  216. package/skills/autosnippet-create/SKILL.md +98 -89
  217. package/skills/autosnippet-devdocs/SKILL.md +55 -57
  218. package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
  219. package/templates/cursor-hooks/hooks/session-start.sh +1 -1
  220. package/templates/guard-ci.yml +2 -2
  221. package/templates/instructions/agent-static.md +2 -1
  222. package/templates/instructions/conventions.md +5 -6
  223. package/templates/recipes-setup/README.md +1 -2
  224. package/templates/recipes-setup/_template.md +39 -39
  225. package/dashboard/dist/assets/icons-BofcEZ3f.js +0 -1
  226. package/dashboard/dist/assets/index-D0whuycy.css +0 -1
  227. package/dashboard/dist/assets/index-SiN1GChm.js +0 -128
  228. package/dist/lib/domain/task/Task.d.ts +0 -140
  229. package/dist/lib/domain/task/Task.js +0 -254
  230. package/dist/lib/domain/task/TaskDependency.d.ts +0 -23
  231. package/dist/lib/domain/task/TaskDependency.js +0 -34
  232. package/dist/lib/domain/task/TaskIdGenerator.d.ts +0 -40
  233. package/dist/lib/domain/task/TaskIdGenerator.js +0 -75
  234. package/dist/lib/domain/task/index.d.ts +0 -4
  235. package/dist/lib/domain/task/index.js +0 -4
  236. package/dist/lib/infrastructure/database/migrations/002_add_tasks.d.ts +0 -11
  237. package/dist/lib/infrastructure/database/migrations/002_add_tasks.js +0 -86
  238. package/dist/lib/repository/task/TaskRepository.impl.d.ts +0 -171
  239. package/dist/lib/repository/task/TaskRepository.impl.js +0 -347
  240. package/dist/lib/service/task/TaskGraphService.d.ts +0 -222
  241. package/dist/lib/service/task/TaskGraphService.js +0 -597
  242. package/dist/lib/service/task/TaskKnowledgeBridge.d.ts +0 -95
  243. package/dist/lib/service/task/TaskKnowledgeBridge.js +0 -298
  244. package/dist/lib/service/task/TaskReadyEngine.d.ts +0 -84
  245. package/dist/lib/service/task/TaskReadyEngine.js +0 -115
@@ -0,0 +1,99 @@
1
+ /**
2
+ * DynamicComposer — 运行时动态工具组合
3
+ *
4
+ * 将已有的原子工具按 sequential / parallel / conditional 策略组合成复合工具。
5
+ * 组合结果注册为临时工具(通过 TemporaryToolRegistry)。
6
+ *
7
+ * 与 PipelineStrategy 的区别:
8
+ * - PipelineStrategy 是 Agent 执行策略(Agent 层)
9
+ * - DynamicComposer 是工具组合(Tool 层),产出物是单个工具
10
+ */
11
+ import Logger from '#infra/logging/Logger.js';
12
+ /* ────────────────────── Class ────────────────────── */
13
+ export class DynamicComposer {
14
+ #registry;
15
+ #logger = Logger.getInstance();
16
+ constructor(registry) {
17
+ this.#registry = registry;
18
+ }
19
+ /**
20
+ * 验证组合 spec 的可行性(所有工具是否存在)
21
+ */
22
+ validate(spec) {
23
+ const missing = [];
24
+ for (const step of spec.steps) {
25
+ if (!this.#registry.has(step.tool)) {
26
+ missing.push(step.tool);
27
+ }
28
+ }
29
+ return { valid: missing.length === 0, missingTools: missing };
30
+ }
31
+ /**
32
+ * 构建组合工具
33
+ */
34
+ compose(spec) {
35
+ // 验证
36
+ const { valid, missingTools } = this.validate(spec);
37
+ if (!valid) {
38
+ return {
39
+ success: false,
40
+ error: `Missing tools: ${missingTools.join(', ')}`,
41
+ };
42
+ }
43
+ if (spec.steps.length === 0) {
44
+ return {
45
+ success: false,
46
+ error: 'Composition must have at least one step',
47
+ };
48
+ }
49
+ const registry = this.#registry;
50
+ const logger = this.#logger;
51
+ // 根据策略构建 handler
52
+ const handler = spec.mergeStrategy === 'parallel'
53
+ ? this.#buildParallelHandler(spec, registry, logger)
54
+ : this.#buildSequentialHandler(spec, registry, logger);
55
+ return { success: true, handler };
56
+ }
57
+ /* ── Internal ── */
58
+ #buildSequentialHandler(spec, registry, logger) {
59
+ return async (params, context) => {
60
+ let prevResult = params;
61
+ for (const step of spec.steps) {
62
+ const args = typeof step.args === 'function' ? step.args(prevResult) : { ...step.args, ...params };
63
+ logger.debug(`DynamicComposer [${spec.name}]: executing step "${step.tool}"`);
64
+ const result = await registry.execute(step.tool, args, context);
65
+ if (step.extractKey && typeof result === 'object' && result !== null) {
66
+ prevResult = result[step.extractKey];
67
+ }
68
+ else {
69
+ prevResult = result;
70
+ }
71
+ }
72
+ return prevResult;
73
+ };
74
+ }
75
+ #buildParallelHandler(spec, registry, logger) {
76
+ return async (params, context) => {
77
+ logger.debug(`DynamicComposer [${spec.name}]: executing ${spec.steps.length} steps in parallel`);
78
+ const promises = spec.steps.map(async (step) => {
79
+ const args = typeof step.args === 'function' ? step.args(params) : { ...step.args, ...params };
80
+ const result = await registry.execute(step.tool, args, context);
81
+ if (step.extractKey && typeof result === 'object' && result !== null) {
82
+ return { tool: step.tool, result: result[step.extractKey] };
83
+ }
84
+ return { tool: step.tool, result };
85
+ });
86
+ const results = await Promise.allSettled(promises);
87
+ const merged = {};
88
+ for (const r of results) {
89
+ if (r.status === 'fulfilled') {
90
+ merged[r.value.tool] = r.value.result;
91
+ }
92
+ else {
93
+ merged[`error_${Object.keys(merged).length}`] = r.reason?.message ?? 'Unknown error';
94
+ }
95
+ }
96
+ return merged;
97
+ };
98
+ }
99
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * SandboxRunner — 工具锻造沙箱验证
3
+ *
4
+ * 在受限环境中执行锻造的工具代码 + 测试用例,验证安全性和正确性。
5
+ * 使用 Node.js vm 模块提供隔离执行环境。
6
+ *
7
+ * 安全约束:
8
+ * - 5s 执行超时
9
+ * - 禁止 require/import (无文件系统 / 网络 / 子进程)
10
+ * - 内存限制 via vm 上下文隔离
11
+ * - 只暴露 console.log, JSON, Math, Date, Array, Object, String 等纯函数
12
+ */
13
+ export interface SandboxTestCase {
14
+ /** 测试描述 */
15
+ description: string;
16
+ /** 调用参数 */
17
+ input: Record<string, unknown>;
18
+ /** 预期输出(用 deepEqual 比较) */
19
+ expectedOutput: unknown;
20
+ }
21
+ export interface SandboxResult {
22
+ /** 是否全部通过 */
23
+ success: boolean;
24
+ /** 各测试用例结果 */
25
+ testResults: Array<{
26
+ description: string;
27
+ passed: boolean;
28
+ actualOutput?: unknown;
29
+ error?: string;
30
+ }>;
31
+ /** 总执行时间 (ms) */
32
+ executionTime: number;
33
+ /** 安全检查结果 */
34
+ safetyCheck: {
35
+ passed: boolean;
36
+ violations: string[];
37
+ };
38
+ }
39
+ export declare class SandboxRunner {
40
+ #private;
41
+ /**
42
+ * 对工具代码进行安全检查
43
+ */
44
+ checkSafety(code: string): {
45
+ passed: boolean;
46
+ violations: string[];
47
+ };
48
+ /**
49
+ * 在沙箱中执行工具代码 + 测试用例
50
+ *
51
+ * @param code 工具函数代码(应 export default 或赋给 __toolHandler__)
52
+ * @param testCases 测试用例
53
+ */
54
+ run(code: string, testCases: SandboxTestCase[]): SandboxResult;
55
+ /**
56
+ * 从验证通过的代码创建可调用 handler
57
+ * 返回的 handler 每次调用都在新沙箱中执行(隔离)
58
+ */
59
+ createHandler(code: string): (params: Record<string, unknown>, context: Record<string, unknown>) => Promise<unknown>;
60
+ }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * SandboxRunner — 工具锻造沙箱验证
3
+ *
4
+ * 在受限环境中执行锻造的工具代码 + 测试用例,验证安全性和正确性。
5
+ * 使用 Node.js vm 模块提供隔离执行环境。
6
+ *
7
+ * 安全约束:
8
+ * - 5s 执行超时
9
+ * - 禁止 require/import (无文件系统 / 网络 / 子进程)
10
+ * - 内存限制 via vm 上下文隔离
11
+ * - 只暴露 console.log, JSON, Math, Date, Array, Object, String 等纯函数
12
+ */
13
+ import { createContext, runInContext } from 'node:vm';
14
+ import Logger from '#infra/logging/Logger.js';
15
+ /* ────────────────────── Constants ────────────────────── */
16
+ const EXECUTION_TIMEOUT_MS = 5000;
17
+ /** 禁止使用的模式 */
18
+ const FORBIDDEN_PATTERNS = [
19
+ /\brequire\s*\(/,
20
+ /\bimport\s*\(/,
21
+ /\bprocess\b/,
22
+ /\b__dirname\b/,
23
+ /\b__filename\b/,
24
+ /\bglobal\b/,
25
+ /\bglobalThis\b/,
26
+ /\beval\s*\(/,
27
+ /\bFunction\s*\(/,
28
+ /\bfetch\s*\(/,
29
+ /\bXMLHttpRequest\b/,
30
+ /\bWebSocket\b/,
31
+ /\bchild_process\b/,
32
+ /\bfs\b\./,
33
+ /\bnet\b\./,
34
+ /\bhttp\b\./,
35
+ /\bhttps\b\./,
36
+ ];
37
+ /* ────────────────────── Class ────────────────────── */
38
+ export class SandboxRunner {
39
+ #logger = Logger.getInstance();
40
+ /**
41
+ * 对工具代码进行安全检查
42
+ */
43
+ checkSafety(code) {
44
+ const violations = [];
45
+ for (const pattern of FORBIDDEN_PATTERNS) {
46
+ if (pattern.test(code)) {
47
+ violations.push(`Forbidden pattern detected: ${pattern.source}`);
48
+ }
49
+ }
50
+ return { passed: violations.length === 0, violations };
51
+ }
52
+ /**
53
+ * 在沙箱中执行工具代码 + 测试用例
54
+ *
55
+ * @param code 工具函数代码(应 export default 或赋给 __toolHandler__)
56
+ * @param testCases 测试用例
57
+ */
58
+ run(code, testCases) {
59
+ const start = Date.now();
60
+ // 1. 安全检查
61
+ const safetyCheck = this.checkSafety(code);
62
+ if (!safetyCheck.passed) {
63
+ return {
64
+ success: false,
65
+ testResults: [],
66
+ executionTime: Date.now() - start,
67
+ safetyCheck,
68
+ };
69
+ }
70
+ // 2. 构建沙箱上下文 — 只暴露安全的全局对象
71
+ const logs = [];
72
+ const sandbox = createContext({
73
+ console: {
74
+ log: (...args) => logs.push(args.map(String).join(' ')),
75
+ warn: (...args) => logs.push(`[warn] ${args.map(String).join(' ')}`),
76
+ error: (...args) => logs.push(`[error] ${args.map(String).join(' ')}`),
77
+ },
78
+ JSON,
79
+ Math,
80
+ Date,
81
+ Array,
82
+ Object,
83
+ String,
84
+ Number,
85
+ Boolean,
86
+ RegExp,
87
+ Map,
88
+ Set,
89
+ Error,
90
+ TypeError,
91
+ RangeError,
92
+ parseInt,
93
+ parseFloat,
94
+ isNaN,
95
+ isFinite,
96
+ encodeURIComponent,
97
+ decodeURIComponent,
98
+ // 工具函数占位,由代码赋值
99
+ __toolHandler__: null,
100
+ });
101
+ // 3. 加载工具代码
102
+ try {
103
+ const wrappedCode = `${code}\n;(typeof toolHandler !== 'undefined') && (__toolHandler__ = toolHandler);`;
104
+ runInContext(wrappedCode, sandbox, {
105
+ timeout: EXECUTION_TIMEOUT_MS,
106
+ filename: 'forged-tool.js',
107
+ });
108
+ }
109
+ catch (err) {
110
+ return {
111
+ success: false,
112
+ testResults: [
113
+ {
114
+ description: 'Code loading',
115
+ passed: false,
116
+ error: `Failed to load tool code: ${err.message}`,
117
+ },
118
+ ],
119
+ executionTime: Date.now() - start,
120
+ safetyCheck,
121
+ };
122
+ }
123
+ const handler = sandbox.__toolHandler__;
124
+ if (typeof handler !== 'function') {
125
+ return {
126
+ success: false,
127
+ testResults: [
128
+ {
129
+ description: 'Handler check',
130
+ passed: false,
131
+ error: 'Tool code must define a `toolHandler` function',
132
+ },
133
+ ],
134
+ executionTime: Date.now() - start,
135
+ safetyCheck,
136
+ };
137
+ }
138
+ // 4. 执行测试用例
139
+ const testResults = [];
140
+ let allPassed = true;
141
+ for (const tc of testCases) {
142
+ try {
143
+ const testCode = `__toolHandler__(${JSON.stringify(tc.input)})`;
144
+ const actual = runInContext(testCode, sandbox, {
145
+ timeout: EXECUTION_TIMEOUT_MS,
146
+ filename: 'forged-tool-test.js',
147
+ });
148
+ const passed = SandboxRunner.#deepEqual(actual, tc.expectedOutput);
149
+ if (!passed) {
150
+ allPassed = false;
151
+ }
152
+ testResults.push({
153
+ description: tc.description,
154
+ passed,
155
+ actualOutput: actual,
156
+ error: passed
157
+ ? undefined
158
+ : `Expected ${JSON.stringify(tc.expectedOutput)}, got ${JSON.stringify(actual)}`,
159
+ });
160
+ }
161
+ catch (err) {
162
+ allPassed = false;
163
+ testResults.push({
164
+ description: tc.description,
165
+ passed: false,
166
+ error: err.message,
167
+ });
168
+ }
169
+ }
170
+ this.#logger.debug(`SandboxRunner: ${testResults.filter((t) => t.passed).length}/${testResults.length} tests passed`);
171
+ return {
172
+ success: allPassed,
173
+ testResults,
174
+ executionTime: Date.now() - start,
175
+ safetyCheck,
176
+ };
177
+ }
178
+ /**
179
+ * 从验证通过的代码创建可调用 handler
180
+ * 返回的 handler 每次调用都在新沙箱中执行(隔离)
181
+ */
182
+ createHandler(code) {
183
+ return async (params) => {
184
+ const sandbox = createContext({
185
+ console: { log: () => { }, warn: () => { }, error: () => { } },
186
+ JSON,
187
+ Math,
188
+ Date,
189
+ Array,
190
+ Object,
191
+ String,
192
+ Number,
193
+ Boolean,
194
+ RegExp,
195
+ Map,
196
+ Set,
197
+ Error,
198
+ TypeError,
199
+ RangeError,
200
+ parseInt,
201
+ parseFloat,
202
+ isNaN,
203
+ isFinite,
204
+ encodeURIComponent,
205
+ decodeURIComponent,
206
+ __toolHandler__: null,
207
+ });
208
+ const wrappedCode = `${code}\n;(typeof toolHandler !== 'undefined') && (__toolHandler__ = toolHandler);`;
209
+ runInContext(wrappedCode, sandbox, {
210
+ timeout: EXECUTION_TIMEOUT_MS,
211
+ filename: 'forged-tool.js',
212
+ });
213
+ const handler = sandbox.__toolHandler__;
214
+ if (typeof handler !== 'function') {
215
+ throw new Error('Forged tool code does not define a toolHandler function');
216
+ }
217
+ const execCode = `__toolHandler__(${JSON.stringify(params)})`;
218
+ const result = runInContext(execCode, sandbox, {
219
+ timeout: EXECUTION_TIMEOUT_MS,
220
+ filename: 'forged-tool-exec.js',
221
+ });
222
+ // 如果返回 Promise-like,需特殊处理(vm 里一般不会有真正的 Promise)
223
+ return result;
224
+ };
225
+ }
226
+ /** 简单深度比较 */
227
+ static #deepEqual(a, b) {
228
+ if (a === b) {
229
+ return true;
230
+ }
231
+ if (a === null || b === null || typeof a !== typeof b) {
232
+ return false;
233
+ }
234
+ if (typeof a !== 'object') {
235
+ return false;
236
+ }
237
+ const aObj = a;
238
+ const bObj = b;
239
+ const keysA = Object.keys(aObj);
240
+ const keysB = Object.keys(bObj);
241
+ if (keysA.length !== keysB.length) {
242
+ return false;
243
+ }
244
+ for (const key of keysA) {
245
+ if (!SandboxRunner.#deepEqual(aObj[key], bObj[key])) {
246
+ return false;
247
+ }
248
+ }
249
+ return true;
250
+ }
251
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * TemporaryToolRegistry — TTL 临时工具注册
3
+ *
4
+ * 在 ToolRegistry 之上增加 TTL 自动回收机制。
5
+ * 锻造的工具默认 30 分钟有效,到期自动从 ToolRegistry 中移除。
6
+ *
7
+ * 设计:
8
+ * - 装饰器模式,不修改 ToolRegistry 核心逻辑
9
+ * - 定期检查(60s 间隔)清理过期工具
10
+ * - 支持手动续期和提前回收
11
+ */
12
+ import type { SignalBus } from '#infra/signal/SignalBus.js';
13
+ interface ToolRegistryLike {
14
+ register(toolDef: {
15
+ name: string;
16
+ description: string;
17
+ parameters?: Record<string, unknown>;
18
+ handler: Function;
19
+ }): void;
20
+ unregister(name: string): boolean;
21
+ has(name: string): boolean;
22
+ }
23
+ export interface TemporaryTool {
24
+ name: string;
25
+ description: string;
26
+ parameters: Record<string, unknown>;
27
+ handler: (params: Record<string, unknown>, context: Record<string, unknown>) => Promise<unknown>;
28
+ /** 锻造模式 */
29
+ forgeMode: 'reuse' | 'compose' | 'generate';
30
+ /** 注册时间 (ms) */
31
+ registeredAt: number;
32
+ /** 过期时间 (ms),0 = never */
33
+ expiresAt: number;
34
+ }
35
+ export interface TemporaryToolInfo {
36
+ name: string;
37
+ forgeMode: string;
38
+ registeredAt: number;
39
+ expiresAt: number;
40
+ remainingMs: number;
41
+ }
42
+ export declare class TemporaryToolRegistry {
43
+ #private;
44
+ constructor(registry: ToolRegistryLike, options?: {
45
+ signalBus?: SignalBus;
46
+ });
47
+ /**
48
+ * 注册一个临时工具
49
+ */
50
+ registerTemporary(tool: Omit<TemporaryTool, 'registeredAt' | 'expiresAt'>, ttlMs?: number): void;
51
+ /**
52
+ * 手动回收临时工具
53
+ */
54
+ revoke(name: string): boolean;
55
+ /**
56
+ * 续期临时工具
57
+ */
58
+ renew(name: string, additionalMs?: number): boolean;
59
+ /**
60
+ * 清理过期工具
61
+ */
62
+ cleanup(): number;
63
+ /**
64
+ * 获取所有临时工具信息
65
+ */
66
+ list(): TemporaryToolInfo[];
67
+ /**
68
+ * 检查是否是临时工具
69
+ */
70
+ isTemporary(name: string): boolean;
71
+ /** 临时工具数量 */
72
+ get size(): number;
73
+ /** 停止定期清理(用于 shutdown) */
74
+ dispose(): void;
75
+ }
76
+ export {};
@@ -0,0 +1,154 @@
1
+ /**
2
+ * TemporaryToolRegistry — TTL 临时工具注册
3
+ *
4
+ * 在 ToolRegistry 之上增加 TTL 自动回收机制。
5
+ * 锻造的工具默认 30 分钟有效,到期自动从 ToolRegistry 中移除。
6
+ *
7
+ * 设计:
8
+ * - 装饰器模式,不修改 ToolRegistry 核心逻辑
9
+ * - 定期检查(60s 间隔)清理过期工具
10
+ * - 支持手动续期和提前回收
11
+ */
12
+ import Logger from '#infra/logging/Logger.js';
13
+ /* ────────────────────── Constants ────────────────────── */
14
+ const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
15
+ const CLEANUP_INTERVAL_MS = 60 * 1000; // 60 seconds
16
+ /* ────────────────────── Class ────────────────────── */
17
+ export class TemporaryToolRegistry {
18
+ #registry;
19
+ #tempTools = new Map();
20
+ #cleanupTimer = null;
21
+ #signalBus;
22
+ #logger = Logger.getInstance();
23
+ constructor(registry, options = {}) {
24
+ this.#registry = registry;
25
+ this.#signalBus = options.signalBus ?? null;
26
+ this.#startCleanup();
27
+ }
28
+ /**
29
+ * 注册一个临时工具
30
+ */
31
+ registerTemporary(tool, ttlMs = DEFAULT_TTL_MS) {
32
+ const now = Date.now();
33
+ const entry = {
34
+ ...tool,
35
+ registeredAt: now,
36
+ expiresAt: ttlMs > 0 ? now + ttlMs : 0,
37
+ };
38
+ // 如果已存在同名临时工具,先移除
39
+ if (this.#tempTools.has(tool.name)) {
40
+ this.revoke(tool.name);
41
+ }
42
+ // 注册到主 ToolRegistry
43
+ this.#registry.register({
44
+ name: tool.name,
45
+ description: `[Forged:${tool.forgeMode}] ${tool.description}`,
46
+ parameters: tool.parameters,
47
+ handler: tool.handler,
48
+ });
49
+ this.#tempTools.set(tool.name, entry);
50
+ if (this.#signalBus) {
51
+ this.#signalBus.send('forge', 'TemporaryToolRegistry', 1, {
52
+ target: tool.name,
53
+ metadata: { action: 'registered', forgeMode: tool.forgeMode, ttlMs },
54
+ });
55
+ }
56
+ this.#logger.debug(`TemporaryToolRegistry: registered "${tool.name}" (mode=${tool.forgeMode}, ttl=${ttlMs}ms)`);
57
+ }
58
+ /**
59
+ * 手动回收临时工具
60
+ */
61
+ revoke(name) {
62
+ const tool = this.#tempTools.get(name);
63
+ if (!tool) {
64
+ return false;
65
+ }
66
+ this.#registry.unregister(name);
67
+ this.#tempTools.delete(name);
68
+ if (this.#signalBus) {
69
+ this.#signalBus.send('forge', 'TemporaryToolRegistry', 0, {
70
+ target: name,
71
+ metadata: { action: 'revoked' },
72
+ });
73
+ }
74
+ this.#logger.debug(`TemporaryToolRegistry: revoked "${name}"`);
75
+ return true;
76
+ }
77
+ /**
78
+ * 续期临时工具
79
+ */
80
+ renew(name, additionalMs = DEFAULT_TTL_MS) {
81
+ const tool = this.#tempTools.get(name);
82
+ if (!tool) {
83
+ return false;
84
+ }
85
+ tool.expiresAt = Date.now() + additionalMs;
86
+ return true;
87
+ }
88
+ /**
89
+ * 清理过期工具
90
+ */
91
+ cleanup() {
92
+ const now = Date.now();
93
+ let cleaned = 0;
94
+ for (const [name, tool] of this.#tempTools) {
95
+ if (tool.expiresAt > 0 && tool.expiresAt <= now) {
96
+ this.#registry.unregister(name);
97
+ this.#tempTools.delete(name);
98
+ cleaned++;
99
+ this.#logger.debug(`TemporaryToolRegistry: expired "${name}"`);
100
+ }
101
+ }
102
+ return cleaned;
103
+ }
104
+ /**
105
+ * 获取所有临时工具信息
106
+ */
107
+ list() {
108
+ const now = Date.now();
109
+ const result = [];
110
+ for (const [name, tool] of this.#tempTools) {
111
+ result.push({
112
+ name,
113
+ forgeMode: tool.forgeMode,
114
+ registeredAt: tool.registeredAt,
115
+ expiresAt: tool.expiresAt,
116
+ remainingMs: tool.expiresAt > 0 ? Math.max(0, tool.expiresAt - now) : -1,
117
+ });
118
+ }
119
+ return result;
120
+ }
121
+ /**
122
+ * 检查是否是临时工具
123
+ */
124
+ isTemporary(name) {
125
+ return this.#tempTools.has(name);
126
+ }
127
+ /** 临时工具数量 */
128
+ get size() {
129
+ return this.#tempTools.size;
130
+ }
131
+ /** 停止定期清理(用于 shutdown) */
132
+ dispose() {
133
+ if (this.#cleanupTimer) {
134
+ clearInterval(this.#cleanupTimer);
135
+ this.#cleanupTimer = null;
136
+ }
137
+ // 回收所有临时工具
138
+ for (const name of [...this.#tempTools.keys()]) {
139
+ this.revoke(name);
140
+ }
141
+ }
142
+ /* ── Internal ── */
143
+ #startCleanup() {
144
+ this.#cleanupTimer = setInterval(() => {
145
+ this.cleanup();
146
+ }, CLEANUP_INTERVAL_MS);
147
+ // 允许 Node.js 进程在只剩此 timer 时退出
148
+ if (this.#cleanupTimer &&
149
+ typeof this.#cleanupTimer === 'object' &&
150
+ 'unref' in this.#cleanupTimer) {
151
+ this.#cleanupTimer.unref();
152
+ }
153
+ }
154
+ }