@specverse/engines 4.1.14 → 4.1.15

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 (57) hide show
  1. package/assets/prompts/core/standard/v9/behavior.prompt.yaml +7 -1
  2. package/dist/ai/behavior-ai-service.d.ts +2 -0
  3. package/dist/ai/behavior-ai-service.d.ts.map +1 -1
  4. package/dist/ai/behavior-ai-service.js +2 -0
  5. package/dist/ai/behavior-ai-service.js.map +1 -1
  6. package/dist/ai/prompt-loader.js +2 -2
  7. package/dist/inference/quint-transpiler.d.ts.map +1 -1
  8. package/dist/inference/quint-transpiler.js +204 -4
  9. package/dist/inference/quint-transpiler.js.map +1 -1
  10. package/dist/libs/instance-factories/applications/templates/generic/backend-package-json-generator.js +4 -1
  11. package/dist/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.js +2 -2
  12. package/dist/libs/instance-factories/applications/templates/react/runtime-package-json-generator.js +1 -0
  13. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +81 -22
  14. package/dist/libs/instance-factories/communication/templates/eventemitter/bus-generator.js +2 -3
  15. package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +21 -1
  16. package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.js +10 -2
  17. package/dist/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.js +130 -22
  18. package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +14 -7
  19. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +29 -54
  20. package/dist/libs/instance-factories/services/templates/prisma/service-generator.js +31 -10
  21. package/dist/libs/instance-factories/services/templates/prisma/step-conventions.js +1 -1
  22. package/dist/libs/instance-factories/views/templates/react/components-generator.js +40 -10
  23. package/dist/realize/index.d.ts.map +1 -1
  24. package/dist/realize/index.js +138 -23
  25. package/dist/realize/index.js.map +1 -1
  26. package/libs/instance-factories/applications/templates/generic/backend-package-json-generator.ts +4 -1
  27. package/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.ts +2 -2
  28. package/libs/instance-factories/applications/templates/react/runtime-package-json-generator.ts +6 -1
  29. package/libs/instance-factories/cli/templates/commander/command-generator.ts +99 -22
  30. package/libs/instance-factories/communication/templates/eventemitter/bus-generator.ts +2 -3
  31. package/libs/instance-factories/controllers/templates/fastify/routes-generator.ts +27 -2
  32. package/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.ts +23 -2
  33. package/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.ts +185 -20
  34. package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +34 -9
  35. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +37 -59
  36. package/libs/instance-factories/services/templates/prisma/service-generator.ts +40 -10
  37. package/libs/instance-factories/services/templates/prisma/step-conventions.ts +4 -1
  38. package/libs/instance-factories/views/templates/react/components-generator.ts +50 -10
  39. package/package.json +1 -1
  40. package/dist/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.js +0 -232
  41. package/dist/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.js +0 -49
  42. package/dist/libs/instance-factories/tools/templates/mcp/static/src/index.js +0 -18
  43. package/dist/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.js +0 -0
  44. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.js +0 -97
  45. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.js +0 -64
  46. package/dist/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.js +0 -182
  47. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.js +0 -1210
  48. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.js +0 -172
  49. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.js +0 -240
  50. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.js +0 -147
  51. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.js +0 -281
  52. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.js +0 -409
  53. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.js +0 -414
  54. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.js +0 -467
  55. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.js +0 -135
  56. package/dist/libs/instance-factories/tools/templates/mcp/static/src/types/index.js +0 -0
  57. package/dist/libs/instance-factories/tools/templates/vscode/static/extension.js +0 -965
@@ -22,23 +22,29 @@ export default function generatePrismaService(context: TemplateContext): string
22
22
  const hasEvents = (service.publishes && service.publishes.length > 0) ||
23
23
  (service.subscribes && service.subscribes.length > 0);
24
24
 
25
+ // Generate operations first so we can detect what symbols they use in the output
26
+ const operationsCode = generateOperationsWithHelpers(service);
27
+ // If the generated code contains `aiBehaviors.`, we need to import the AI file
28
+ const hasAiBehaviors = /\baiBehaviors\./.test(operationsCode);
29
+ // Only emit the prisma client binding + import if the operations actually use it
30
+ const usesPrisma = /\bprisma\b/.test(operationsCode);
31
+
25
32
  return `/**
26
33
  * ${serviceName}
27
34
  * Abstract business logic service
28
35
  * ${service.description || ''}
29
36
  */
30
-
31
- import { PrismaClient } from '@prisma/client';
32
- ${hasEvents ? `import { eventBus, EventName } from '../events/eventBus.js';` : ''}
33
-
34
- const prisma = new PrismaClient();
37
+ ${usesPrisma ? `\nimport { PrismaClient } from '@prisma/client';` : ''}
38
+ ${hasEvents ? `import { eventBus } from '../events/eventBus.js';` : ''}
39
+ ${hasAiBehaviors ? `import * as aiBehaviors from '../behaviors/${serviceName}.ai.js';` : ''}
40
+ ${usesPrisma ? `\nconst prisma = new PrismaClient();` : ''}
35
41
 
36
42
  /**
37
43
  * ${serviceName} class
38
44
  */
39
45
  export class ${serviceName} {
40
46
  ${generateConstructor(service)}
41
- ${generateOperationsWithHelpers(service)}
47
+ ${operationsCode}
42
48
  ${generateEventSubscriptions(service)}
43
49
  }
44
50
 
@@ -143,8 +149,12 @@ function generateOperations(service: any): string {
143
149
  * Generate individual operation
144
150
  */
145
151
  function generateOperation(operationName: string, operation: any, service: any): string {
146
- const params = generateOperationParams(operation);
152
+ const rawParams = generateOperationParams(operation);
147
153
  const hasPublish = service.publishes && service.publishes.length > 0;
154
+ const body = generateOperationLogic(operation, service);
155
+ // Rename any operation parameter that the body doesn't reference so tsc's
156
+ // noUnusedParameters doesn't trip on placeholder service stubs.
157
+ const params = renameUnusedParams(rawParams, body);
148
158
 
149
159
  return `
150
160
  /**
@@ -153,7 +163,7 @@ function generateOperation(operationName: string, operation: any, service: any):
153
163
  */
154
164
  public async ${operationName}(${params}): Promise<any> {
155
165
  try {
156
- ${generateOperationLogic(operation, service)}
166
+ ${body}
157
167
 
158
168
  ${hasPublish ? `
159
169
  // Publish event (example)
@@ -173,6 +183,24 @@ function generateOperation(operationName: string, operation: any, service: any):
173
183
  `;
174
184
  }
175
185
 
186
+ /**
187
+ * Rename each parameter with a leading underscore if its name isn't referenced
188
+ * in the operation body (suppresses TS6133 on placeholder stubs).
189
+ */
190
+ function renameUnusedParams(paramsString: string, body: string): string {
191
+ if (!paramsString.trim()) return paramsString;
192
+ return paramsString.split(',').map(segment => {
193
+ const trimmed = segment.trim();
194
+ const nameMatch = trimmed.match(/^(\w+)/);
195
+ if (!nameMatch) return segment;
196
+ const name = nameMatch[1];
197
+ if (name.startsWith('_')) return segment;
198
+ const re = new RegExp(`\\b${name}\\b`);
199
+ if (re.test(body)) return segment;
200
+ return segment.replace(new RegExp(`\\b${name}\\b`), `_${name}`);
201
+ }).join(', ');
202
+ }
203
+
176
204
  /**
177
205
  * Generate operation parameters
178
206
  */
@@ -214,18 +242,20 @@ function generateOperationLogic(operation: any, service: any): string {
214
242
  if (impl.preconditions?.length || impl.postconditions?.length || impl.steps?.length || impl.transactional) {
215
243
  // L3: Generate from behavioral specification
216
244
  const modelName = inferModelFromServiceName(service.name);
245
+ const parameterNames = Object.keys(operation.parameters || {});
217
246
  const context: BehaviorContext = {
218
247
  modelName,
219
248
  serviceName: service.name,
220
249
  operationName: operation.name || 'execute',
221
- prismaModel: modelName
250
+ prismaModel: modelName,
251
+ parameterNames,
222
252
  };
223
253
 
224
254
  const behavior: BehaviorMetadata = {
225
255
  preconditions: impl.preconditions || [],
226
256
  postconditions: impl.postconditions || [],
227
257
  sideEffects: impl.sideEffects || [],
228
- steps: impl.steps || [],
258
+ steps: impl.steps || operation.steps || [],
229
259
  transactional: impl.transactional || false
230
260
  };
231
261
 
@@ -22,6 +22,8 @@ export interface StepContext {
22
22
  parameterNames?: string[];
23
23
  /** Variables already declared (to avoid redeclaration) */
24
24
  declaredVars?: Set<string>;
25
+ /** Named result variable (from spec's `as:` clause) */
26
+ resultName?: string;
25
27
  }
26
28
 
27
29
  function toVar(name: string): string {
@@ -373,7 +375,8 @@ export function matchStep(
373
375
  const paramNames = ctx.parameterNames || [];
374
376
  const inputs = [...paramNames, ...declared];
375
377
 
376
- const resultVar = `step${ctx.stepNum}Result`;
378
+ // Use named result from spec (`as:`) or default to stepNResult
379
+ const resultVar = ctx.resultName || `step${ctx.stepNum}Result`;
377
380
  const inputObj = inputs.length > 0 ? `{ ${inputs.join(', ')} }` : '{}';
378
381
 
379
382
  // Register the result variable so subsequent steps can reference it
@@ -37,27 +37,67 @@ export default function generateReactComponent(context: TemplateContext): string
37
37
  const lifecycle = getLifecycle(model);
38
38
  const classified = classifyAttrs(attrs, lifecycle);
39
39
 
40
+ let body: string;
40
41
  switch (viewType) {
41
42
  case 'list':
42
- return generateListView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
43
+ body = generateListView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
44
+ break;
43
45
  case 'detail':
44
- return generateDetailView(componentName, modelName, lower, plural, api, classified, belongsTo, hasMany, lifecycle, view);
46
+ body = generateDetailView(componentName, modelName, lower, plural, api, classified, belongsTo, hasMany, lifecycle, view);
47
+ break;
45
48
  case 'form':
46
- return generateFormView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
49
+ body = generateFormView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
50
+ break;
47
51
  case 'dashboard':
48
- return generateDashboardView(componentName, modelName, lower, plural, api, classified, view, model);
52
+ body = generateDashboardView(componentName, modelName, lower, plural, api, classified, view, model);
53
+ break;
49
54
  case 'board':
50
55
  case 'workflow':
51
- return generateBoardView(componentName, modelName, lower, plural, api, lifecycle, view);
56
+ body = generateBoardView(componentName, modelName, lower, plural, api, lifecycle, view);
57
+ break;
52
58
  case 'timeline':
53
- return generateTimelineView(componentName, modelName, lower, plural, api, view);
59
+ body = generateTimelineView(componentName, modelName, lower, plural, api, view);
60
+ break;
54
61
  case 'calendar':
55
- return generateCalendarView(componentName, modelName, lower, plural, api, view, model);
62
+ body = generateCalendarView(componentName, modelName, lower, plural, api, view, model);
63
+ break;
56
64
  case 'analytics':
57
- return generateAnalyticsView(componentName, modelName, lower, plural, api, classified, lifecycle, view, model);
65
+ body = generateAnalyticsView(componentName, modelName, lower, plural, api, classified, lifecycle, view, model);
66
+ break;
58
67
  default:
59
- return generateListView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
68
+ body = generateListView(componentName, modelName, lower, plural, api, classified, belongsTo, lifecycle, view);
60
69
  }
70
+ return stripUnusedImports(body);
71
+ }
72
+
73
+ /**
74
+ * Rewrite the top-of-file named imports to drop symbols the body doesn't
75
+ * reference. The view generators import every helper unconditionally; this
76
+ * pass keeps them clean under tsc's `noUnusedLocals`.
77
+ */
78
+ function stripUnusedImports(source: string): string {
79
+ // Process only the leading contiguous run of named imports.
80
+ const lines = source.split('\n');
81
+ const out: string[] = [];
82
+ let i = 0;
83
+ // Find the end of the import block.
84
+ while (i < lines.length) {
85
+ const line = lines[i];
86
+ const match = line.match(/^import\s+\{\s*([^}]+?)\s*\}\s+from\s+(['"][^'"]+['"]);?\s*$/);
87
+ if (!match) break;
88
+ const names = match[1].split(',').map(s => s.trim()).filter(Boolean);
89
+ const from = match[2];
90
+ // Join all following lines as the usage body so we can scan for references.
91
+ const rest = lines.slice(i + 1).join('\n');
92
+ const used = names.filter(n => new RegExp(`\\b${n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(rest));
93
+ if (used.length === 0) {
94
+ // drop the import entirely
95
+ } else {
96
+ out.push(`import { ${used.join(', ')} } from ${from};`);
97
+ }
98
+ i++;
99
+ }
100
+ return [...out, ...lines.slice(i)].join('\n');
61
101
  }
62
102
 
63
103
  // ============================================================================
@@ -427,7 +467,7 @@ ${lifecycle.states.map(s => ` <option value="${s}">${s.replace(/[_-]/g,
427
467
  }
428
468
 
429
469
  const t = type.toLowerCase();
430
- if (t === 'boolean') return ` <input type="checkbox" name="${n}" checked={!!form.${n}} onChange={e => setForm(f => ({...f, ${n}: e.target.checked}))} className="h-4 w-4 text-blue-600 rounded" />`;
470
+ if (t === 'boolean') return ` <input type="checkbox" name="${n}" checked={!!form.${n}} onChange={e => setForm((f: any) => ({...f, ${n}: e.target.checked}))} className="h-4 w-4 text-blue-600 rounded" />`;
431
471
  if (t.includes('date') || t.includes('timestamp')) return ` <input type="datetime-local" name="${n}" value={form.${n} || ''} onChange={handleChange} className="w-full px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"${req} />`;
432
472
  if (t === 'integer' || t === 'number' || t === 'money' || t === 'decimal' || t === 'float') return ` <input type="number" name="${n}" value={form.${n} || ''} onChange={handleChange} className="w-full px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"${req} />`;
433
473
  if (n.toLowerCase().includes('description') || n.toLowerCase().includes('content') || n.toLowerCase().includes('body')) return ` <textarea name="${n}" value={form.${n} || ''} onChange={handleChange} rows={4} className="w-full px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"${req} />`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "4.1.14",
3
+ "version": "4.1.15",
4
4
  "description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,232 +0,0 @@
1
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import {
3
- ListResourcesRequestSchema,
4
- ReadResourceRequestSchema,
5
- ListToolsRequestSchema,
6
- CallToolRequestSchema
7
- } from "@modelcontextprotocol/sdk/types.js";
8
- import { HybridResourcesProvider } from "../services/HybridResourcesProvider.js";
9
- import { CLIProxyService } from "../services/CLIProxyService.js";
10
- import { EntityModuleService } from "../services/EntityModuleService.js";
11
- import { EventEmitter } from "../events/EventEmitter.js";
12
- class MCPServerController {
13
- server;
14
- config;
15
- resourcesProvider;
16
- cliProxy;
17
- entityModuleService;
18
- eventEmitter;
19
- constructor(config) {
20
- this.config = config;
21
- this.eventEmitter = new EventEmitter();
22
- this.server = new Server({
23
- name: "specverse-dynamic-cli",
24
- version: "1.0.0"
25
- }, {
26
- capabilities: {
27
- resources: {},
28
- tools: {}
29
- }
30
- });
31
- this.resourcesProvider = new HybridResourcesProvider({
32
- mode: "auto",
33
- resourcesPath: config.resources_path
34
- });
35
- this.cliProxy = new CLIProxyService();
36
- this.entityModuleService = new EntityModuleService();
37
- this.setupHandlers();
38
- }
39
- async listResources() {
40
- try {
41
- const startTime = Date.now();
42
- const resources = await this.resourcesProvider.listResources();
43
- if (this.entityModuleService.isAvailable()) {
44
- resources.push(...this.entityModuleService.generateResources());
45
- }
46
- this.eventEmitter.emit("resource-requested", {
47
- uri: "LIST_ALL",
48
- requestTime: /* @__PURE__ */ new Date()
49
- });
50
- if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
51
- console.error(`Listed ${resources.length} resources in ${Date.now() - startTime}ms`);
52
- }
53
- return resources;
54
- } catch (error) {
55
- this.eventEmitter.emit("error-occurred", {
56
- operation: "listResources",
57
- error: error instanceof Error ? error.message : String(error)
58
- });
59
- throw error;
60
- }
61
- }
62
- async readResource(uri) {
63
- try {
64
- const startTime = Date.now();
65
- if (uri.startsWith("specverse://entities/") && this.entityModuleService.isAvailable()) {
66
- const entityResources = this.entityModuleService.generateResources();
67
- const resource2 = entityResources.find((r) => r.uri === uri);
68
- if (resource2) {
69
- this.eventEmitter.emit("resource-requested", { uri, requestTime: /* @__PURE__ */ new Date() });
70
- return resource2;
71
- }
72
- }
73
- const content = await this.resourcesProvider.getResourceContent(uri);
74
- const resources = await this.resourcesProvider.listResources();
75
- const resource = resources.find((r) => r.uri === uri);
76
- if (!resource) {
77
- throw new Error(`Resource not found: ${uri}`);
78
- }
79
- this.eventEmitter.emit("resource-requested", {
80
- uri,
81
- requestTime: /* @__PURE__ */ new Date()
82
- });
83
- if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
84
- console.error(`Read resource ${uri} in ${Date.now() - startTime}ms`);
85
- }
86
- return {
87
- ...resource,
88
- content
89
- };
90
- } catch (error) {
91
- this.eventEmitter.emit("error-occurred", {
92
- operation: "readResource",
93
- error: error instanceof Error ? error.message : String(error),
94
- context: { uri }
95
- });
96
- throw error;
97
- }
98
- }
99
- setupHandlers() {
100
- this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
101
- const resources = await this.listResources();
102
- return { resources };
103
- });
104
- this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
105
- const resource = await this.readResource(request.params.uri);
106
- return {
107
- contents: [{
108
- uri: resource.uri,
109
- mimeType: resource.mimeType,
110
- text: resource.content
111
- }]
112
- };
113
- });
114
- this.server.setRequestHandler(ListToolsRequestSchema, async () => {
115
- let dynamicCliTools = [];
116
- try {
117
- dynamicCliTools = await this.cliProxy.generateMCPTools();
118
- if (this.config.logging && this.config.mode !== "local" && process.env.MCP_DEBUG) {
119
- console.error(`\u{1F527} Generated ${dynamicCliTools.length} dynamic CLI tools`);
120
- }
121
- } catch (error) {
122
- if (this.config.logging && process.env.MCP_DEBUG) {
123
- console.error("\u26A0\uFE0F Failed to generate dynamic CLI tools:", error);
124
- }
125
- }
126
- if (this.entityModuleService.isAvailable()) {
127
- dynamicCliTools.push(...this.entityModuleService.generateTools());
128
- }
129
- return { tools: dynamicCliTools };
130
- });
131
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
132
- try {
133
- const { name, arguments: args } = request.params;
134
- const entityToolNames = ["specverse_expand_constraint", "specverse_list_conventions", "specverse_entity_info"];
135
- if (entityToolNames.includes(name) && this.entityModuleService.isAvailable()) {
136
- return await this.entityModuleService.executeTool(name, args || {});
137
- }
138
- if (name.startsWith("specverse_")) {
139
- const result = await this.cliProxy.executeCommand(name, args || {});
140
- return { content: result.content };
141
- } else {
142
- return {
143
- content: [{
144
- type: "text",
145
- text: `Error: Unknown tool '${name}'. Only dynamic CLI tools (prefixed with 'specverse_') are supported.`
146
- }]
147
- };
148
- }
149
- } catch (error) {
150
- return {
151
- content: [{
152
- type: "text",
153
- text: `Error in tool handler: ${error instanceof Error ? error.message : String(error)}`
154
- }]
155
- };
156
- }
157
- });
158
- }
159
- /**
160
- * Start the MCP server
161
- */
162
- async start() {
163
- try {
164
- await this.resourcesProvider.initializeResources();
165
- const entityAvailable = await this.entityModuleService.initialize();
166
- if (this.config.logging && process.env.MCP_DEBUG) {
167
- if (entityAvailable) {
168
- const modules = this.entityModuleService.getEntityModules();
169
- console.error(`\u{1F9E9} Entity modules loaded: ${modules.length} modules, ${modules.reduce((s, m) => s + m.inferenceRuleCount, 0)} rules`);
170
- } else {
171
- console.error("\u26A0\uFE0F Entity modules not available in this deployment");
172
- }
173
- }
174
- this.eventEmitter.emit("server-started", {
175
- serverName: "SpecVerse Dynamic CLI",
176
- mode: this.config.mode,
177
- timestamp: /* @__PURE__ */ new Date(),
178
- featuresEnabled: this.config.features,
179
- pid: process.pid
180
- });
181
- if (this.config.logging && process.env.MCP_DEBUG) {
182
- const mode = this.config.mode || "local";
183
- const resourceCount = this.resourcesProvider.getCachedResourceCount();
184
- console.error(`\u{1F680} SpecVerse MCP Server started in ${mode} mode`);
185
- console.error(`\u{1F4DA} Loaded ${resourceCount} resources`);
186
- console.error(`\u{1F527} Dynamic CLI integration enabled - all tools from CLI`);
187
- }
188
- } catch (error) {
189
- this.eventEmitter.emit("error-occurred", {
190
- operation: "start",
191
- error: error instanceof Error ? error.message : String(error)
192
- });
193
- throw error;
194
- }
195
- }
196
- /**
197
- * Stop the MCP server
198
- */
199
- async stop() {
200
- try {
201
- await this.server.close();
202
- if (this.config.logging && process.env.MCP_DEBUG) {
203
- console.error("\u{1F6D1} SpecVerse MCP Server stopped");
204
- }
205
- } catch (error) {
206
- this.eventEmitter.emit("error-occurred", {
207
- operation: "stop",
208
- error: error instanceof Error ? error.message : String(error)
209
- });
210
- throw error;
211
- }
212
- }
213
- // Methods expected by the main server
214
- getEventEmitter() {
215
- return this.eventEmitter;
216
- }
217
- async initialize() {
218
- await this.start();
219
- }
220
- getServer() {
221
- return this.server;
222
- }
223
- getMetrics() {
224
- return {
225
- resourceCount: this.resourcesProvider.getCachedResourceCount(),
226
- cliIntegration: true
227
- };
228
- }
229
- }
230
- export {
231
- MCPServerController
232
- };
@@ -1,49 +0,0 @@
1
- class EventEmitter {
2
- listeners = /* @__PURE__ */ new Map();
3
- on(eventType, handler) {
4
- if (!this.listeners.has(eventType)) {
5
- this.listeners.set(eventType, []);
6
- }
7
- this.listeners.get(eventType).push(handler);
8
- }
9
- off(eventType, handler) {
10
- const handlers = this.listeners.get(eventType);
11
- if (handlers) {
12
- const index = handlers.indexOf(handler);
13
- if (index !== -1) {
14
- handlers.splice(index, 1);
15
- }
16
- }
17
- }
18
- async emit(eventType, data) {
19
- const handlers = this.listeners.get(eventType);
20
- if (handlers) {
21
- const promises = handlers.map((handler) => {
22
- try {
23
- const result = handler(data);
24
- return Promise.resolve(result);
25
- } catch (error) {
26
- console.error(`Error in event handler for ${eventType}:`, error);
27
- return Promise.resolve();
28
- }
29
- });
30
- await Promise.allSettled(promises);
31
- }
32
- }
33
- removeAllListeners(eventType) {
34
- if (eventType) {
35
- this.listeners.delete(eventType);
36
- } else {
37
- this.listeners.clear();
38
- }
39
- }
40
- listenerCount(eventType) {
41
- return this.listeners.get(eventType)?.length || 0;
42
- }
43
- eventNames() {
44
- return Array.from(this.listeners.keys());
45
- }
46
- }
47
- export {
48
- EventEmitter
49
- };
@@ -1,18 +0,0 @@
1
- import { SpecVerseCleanMCPServer } from "./server/mcp-server.js";
2
- import { MCPServerController } from "./controllers/MCPServerController.js";
3
- import { ResourcesProviderService } from "./services/ResourcesProviderService.js";
4
- import { LibraryToolsService } from "./services/LibraryToolsService.js";
5
- import { PromptToolsService } from "./services/PromptToolsService.js";
6
- import { SpecVerseResourceModel } from "./models/SpecVerseResource.js";
7
- import { LibrarySuggestionModel } from "./models/LibrarySuggestion.js";
8
- import { EventEmitter } from "./events/EventEmitter.js";
9
- export {
10
- EventEmitter,
11
- LibrarySuggestionModel,
12
- LibraryToolsService,
13
- MCPServerController,
14
- PromptToolsService,
15
- ResourcesProviderService,
16
- SpecVerseCleanMCPServer,
17
- SpecVerseResourceModel
18
- };
@@ -1,97 +0,0 @@
1
- import { z } from "zod";
2
- const LibrarySuggestionSchema = z.object({
3
- name: z.string().min(1, "Name is required"),
4
- path: z.string().min(1, "Path is required"),
5
- type: z.enum(["deployment", "domain", "manifest", "type", "standard"]),
6
- description: z.string().min(1, "Description is required"),
7
- ai_description: z.string().min(1, "AI description is required"),
8
- expansion_factor: z.number().min(1, "Expansion factor must be >= 1"),
9
- complexity_level: z.enum(["low", "medium", "high"]),
10
- best_for: z.array(z.string()).min(1, "Must specify at least one use case")
11
- });
12
- class LibrarySuggestionModel {
13
- constructor(name, path, type, description, ai_description, expansion_factor, complexity_level, best_for) {
14
- this.name = name;
15
- this.path = path;
16
- this.type = type;
17
- this.description = description;
18
- this.ai_description = ai_description;
19
- this.expansion_factor = expansion_factor;
20
- this.complexity_level = complexity_level;
21
- this.best_for = best_for;
22
- }
23
- static create(data) {
24
- const validated = LibrarySuggestionSchema.parse(data);
25
- return new LibrarySuggestionModel(
26
- validated.name,
27
- validated.path,
28
- validated.type,
29
- validated.description,
30
- validated.ai_description,
31
- validated.expansion_factor,
32
- validated.complexity_level,
33
- validated.best_for
34
- );
35
- }
36
- static fromJson(json) {
37
- const data = JSON.parse(json);
38
- return this.create(data);
39
- }
40
- toJson() {
41
- return JSON.stringify({
42
- name: this.name,
43
- path: this.path,
44
- type: this.type,
45
- description: this.description,
46
- ai_description: this.ai_description,
47
- expansion_factor: this.expansion_factor,
48
- complexity_level: this.complexity_level,
49
- best_for: this.best_for
50
- });
51
- }
52
- matchesContext(context, scale) {
53
- let score = 0;
54
- const contextLower = context.toLowerCase();
55
- for (const useCase of this.best_for) {
56
- if (contextLower.includes(useCase.toLowerCase())) {
57
- score += 2;
58
- }
59
- }
60
- const scaleComplexity = this.getScaleComplexity(scale);
61
- const complexityScore = this.getComplexityScore();
62
- const complexityMatch = Math.abs(complexityScore - scaleComplexity);
63
- score += Math.max(0, 3 - complexityMatch);
64
- return score;
65
- }
66
- getScaleComplexity(scale) {
67
- switch (scale) {
68
- case "personal":
69
- return 1;
70
- case "business":
71
- return 2;
72
- case "enterprise":
73
- return 3;
74
- default:
75
- return 2;
76
- }
77
- }
78
- getComplexityScore() {
79
- switch (this.complexity_level) {
80
- case "low":
81
- return 1;
82
- case "medium":
83
- return 2;
84
- case "high":
85
- return 3;
86
- default:
87
- return 2;
88
- }
89
- }
90
- getRelevanceScore() {
91
- return this.expansion_factor * this.getComplexityScore();
92
- }
93
- }
94
- export {
95
- LibrarySuggestionModel,
96
- LibrarySuggestionSchema
97
- };
@@ -1,64 +0,0 @@
1
- import { z } from "zod";
2
- const SpecVerseResourceSchema = z.object({
3
- uri: z.string().min(1, "URI is required").regex(/^specverse:\/\//, "URI must start with specverse://"),
4
- name: z.string().min(1, "Name is required"),
5
- description: z.string().min(1, "Description is required"),
6
- mimeType: z.string().min(1, "MIME type is required"),
7
- content: z.string().optional(),
8
- metadata: z.record(z.any()).optional()
9
- });
10
- class SpecVerseResourceModel {
11
- constructor(uri, name, description, mimeType, content, metadata) {
12
- this.uri = uri;
13
- this.name = name;
14
- this.description = description;
15
- this.mimeType = mimeType;
16
- this.content = content;
17
- this.metadata = metadata;
18
- }
19
- static create(data) {
20
- const validated = SpecVerseResourceSchema.parse(data);
21
- return new SpecVerseResourceModel(
22
- validated.uri,
23
- validated.name,
24
- validated.description,
25
- validated.mimeType,
26
- validated.content,
27
- validated.metadata
28
- );
29
- }
30
- static fromJson(json) {
31
- const data = JSON.parse(json);
32
- return this.create(data);
33
- }
34
- toJson() {
35
- return JSON.stringify({
36
- uri: this.uri,
37
- name: this.name,
38
- description: this.description,
39
- mimeType: this.mimeType,
40
- content: this.content,
41
- metadata: this.metadata
42
- });
43
- }
44
- withContent(content) {
45
- return new SpecVerseResourceModel(
46
- this.uri,
47
- this.name,
48
- this.description,
49
- this.mimeType,
50
- content,
51
- this.metadata
52
- );
53
- }
54
- matches(uri) {
55
- return this.uri === uri;
56
- }
57
- isLoaded() {
58
- return this.content !== void 0;
59
- }
60
- }
61
- export {
62
- SpecVerseResourceModel,
63
- SpecVerseResourceSchema
64
- };