@specverse/engines 4.3.5 → 5.0.0

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 (64) hide show
  1. package/assets/examples/10-api/README.md +3 -3
  2. package/assets/prompts/core/README.md +1 -1
  3. package/dist/inference/core/rule-engine.d.ts +0 -12
  4. package/dist/inference/core/rule-engine.d.ts.map +1 -1
  5. package/dist/inference/core/rule-engine.js +99 -968
  6. package/dist/inference/core/rule-engine.js.map +1 -1
  7. package/dist/inference/core/template-helpers.d.ts +56 -0
  8. package/dist/inference/core/template-helpers.d.ts.map +1 -0
  9. package/dist/inference/core/template-helpers.js +87 -0
  10. package/dist/inference/core/template-helpers.js.map +1 -0
  11. package/dist/inference/logical/generators/service-generator.d.ts.map +1 -1
  12. package/dist/inference/logical/generators/service-generator.js +0 -4
  13. package/dist/inference/logical/generators/service-generator.js.map +1 -1
  14. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +27 -5
  15. package/dist/libs/instance-factories/tools/README.md +1 -1
  16. package/dist/libs/instance-factories/tools/mcp.yaml +1 -1
  17. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +336 -116
  18. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +172 -8
  19. package/dist/libs/instance-factories/tools/vscode.yaml +1 -1
  20. package/libs/instance-factories/cli/templates/commander/command-generator.ts +27 -5
  21. package/libs/instance-factories/tools/README.md +1 -1
  22. package/libs/instance-factories/tools/mcp.yaml +1 -1
  23. package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +386 -141
  24. package/libs/instance-factories/tools/templates/vscode/static/extension.ts +9 -2
  25. package/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.ts +246 -10
  26. package/libs/instance-factories/tools/vscode.yaml +1 -1
  27. package/package.json +5 -4
  28. package/libs/instance-factories/tools/templates/mcp/static/docs/DEPLOYMENT_GUIDE.md +0 -630
  29. package/libs/instance-factories/tools/templates/mcp/static/docs/HYBRID_RESOURCE_SYSTEM.md +0 -330
  30. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/EXTENSION_DEPLOYMENT.md +0 -552
  31. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/LOCAL_DEPLOYMENT.md +0 -164
  32. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/WEB_DEPLOYMENT.md +0 -247
  33. package/libs/instance-factories/tools/templates/mcp/static/package.json +0 -94
  34. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-enterprise.js +0 -284
  35. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-extension.js +0 -139
  36. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-local.js +0 -74
  37. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-web.js +0 -156
  38. package/libs/instance-factories/tools/templates/mcp/static/scripts/copy-canonical-files.js +0 -41
  39. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-deployments.js +0 -259
  40. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-resources.js +0 -231
  41. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-simple.js +0 -196
  42. package/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.ts +0 -293
  43. package/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.ts +0 -90
  44. package/libs/instance-factories/tools/templates/mcp/static/src/index.ts +0 -24
  45. package/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.ts +0 -15
  46. package/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.ts +0 -106
  47. package/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.ts +0 -75
  48. package/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.ts +0 -239
  49. package/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.ts +0 -1501
  50. package/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.ts +0 -211
  51. package/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.ts +0 -308
  52. package/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.ts +0 -210
  53. package/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.ts +0 -356
  54. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.ts +0 -522
  55. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.ts +0 -530
  56. package/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.ts +0 -594
  57. package/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.ts +0 -170
  58. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.init.test.ts +0 -544
  59. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.test.ts +0 -189
  60. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/ResourcesProviderService.test.ts +0 -89
  61. package/libs/instance-factories/tools/templates/mcp/static/src/types/index.ts +0 -110
  62. package/libs/instance-factories/tools/templates/mcp/static/tsconfig.json +0 -28
  63. package/libs/instance-factories/tools/templates/vscode/static/schemas/specverse-v3-schema.json +0 -4279
  64. /package/libs/instance-factories/tools/templates/vscode/static/themes/{specverse-complete-theme.json → specverse-dark-theme.json} +0 -0
@@ -1,22 +1,63 @@
1
- import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync, copyFileSync } from "fs";
1
+ import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync, copyFileSync, unlinkSync } from "fs";
2
2
  import { join, dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
+ import { createRequire } from "module";
4
5
  const __generatorDir = dirname(fileURLToPath(import.meta.url));
6
+ const __require = createRequire(import.meta.url);
7
+ function resolveComposedSchemaPath() {
8
+ try {
9
+ const entitiesPkg = __require.resolve("@specverse/entities/package.json");
10
+ const schemaPath = join(dirname(entitiesPkg), "schema", "SPECVERSE-SCHEMA.json");
11
+ if (existsSync(schemaPath)) return schemaPath;
12
+ } catch {
13
+ }
14
+ return null;
15
+ }
5
16
  function generateVSCodeExtension(context) {
6
17
  const { spec, outputDir } = context;
7
18
  const extensionDir = join(outputDir || ".", "tools", "vscode-extension");
8
19
  if (!existsSync(extensionDir)) mkdirSync(extensionDir, { recursive: true });
9
20
  const distribution = extractDistribution(spec);
10
21
  let cliCommands = [];
22
+ const submenuDefs = [];
11
23
  if (distribution?.commands) {
12
- cliCommands = distribution.commands.map((cmd) => {
24
+ const specCommandsByName = buildCLICommandMap(spec);
25
+ const standardByName = new Map(
26
+ getStandardCommands().map((c) => [c.command, c])
27
+ );
28
+ cliCommands = distribution.commands.flatMap((cmd) => {
13
29
  const parts = (cmd.from || cmd.command || "").split(".");
14
30
  const name = parts[parts.length - 1] || "unknown";
15
- return {
16
- command: `specverse.${name}`,
17
- title: cmd.title || `${capitalize(name)}: ${cmd.description || ""}`,
31
+ const specNode = findSpecCommand(spec, cmd.from || name);
32
+ const subs = specNode?.subcommands;
33
+ if (subs && Object.keys(subs).length > 0) {
34
+ const submenuId = `specverse.${name}`;
35
+ const submenuLabel = cmd.title || specNode?.description || capitalize(name);
36
+ submenuDefs.push({ id: submenuId, label: capitalize(name) });
37
+ return Object.entries(subs).map(([childName, childDef]) => ({
38
+ command: `specverse.${name}.${childName}`,
39
+ title: `${capitalize(name)} ${capitalize(childName)}`,
40
+ category: "SpecVerse",
41
+ submenu: submenuId,
42
+ submenuLabel
43
+ }));
44
+ }
45
+ const commandId = `specverse.${name}`;
46
+ let title = cmd.title;
47
+ if (!title && cmd.from) {
48
+ const specCmd = specCommandsByName.get(cmd.from);
49
+ if (specCmd?.description) title = specCmd.description;
50
+ }
51
+ if (!title) {
52
+ const std = standardByName.get(commandId);
53
+ if (std) title = std.title;
54
+ }
55
+ if (!title) title = capitalize(name);
56
+ return [{
57
+ command: commandId,
58
+ title,
18
59
  category: "SpecVerse"
19
- };
60
+ }];
20
61
  });
21
62
  }
22
63
  if (cliCommands.length === 0) {
@@ -44,6 +85,56 @@ function generateVSCodeExtension(context) {
44
85
  scopeName: lang.grammar,
45
86
  path: `./syntaxes/${lang.id}.tmLanguage.json`
46
87
  }));
88
+ packageJson.activationEvents = [];
89
+ const fileMatch = distribution.languages.flatMap((lang) => (lang.extensions || []).map((ext) => `*${ext}`));
90
+ if (fileMatch.length > 0) {
91
+ packageJson.contributes.jsonValidation = [{
92
+ fileMatch,
93
+ url: "./schemas/specverse-schema.json"
94
+ }];
95
+ }
96
+ const extnames = distribution.languages.flatMap((lang) => lang.extensions || []);
97
+ const langIds = distribution.languages.map((lang) => lang.id);
98
+ const explorerWhen = extnames.map((e) => `resourceExtname == ${e}`).join(" || ");
99
+ const editorWhen = langIds.map((id) => `editorLangId == ${id}`).join(" || ");
100
+ const seenSubmenus = /* @__PURE__ */ new Set();
101
+ const topEntries = [];
102
+ for (const c of cliCommands) {
103
+ if (c.submenu) {
104
+ if (!seenSubmenus.has(c.submenu)) {
105
+ seenSubmenus.add(c.submenu);
106
+ topEntries.push({ submenu: c.submenu });
107
+ }
108
+ } else {
109
+ topEntries.push({ command: c.command });
110
+ }
111
+ }
112
+ if (topEntries.length > 0 && (explorerWhen || editorWhen)) {
113
+ const explorerMenu = topEntries.map((e, i) => ({
114
+ ...e.submenu ? { submenu: e.submenu } : { command: e.command },
115
+ when: explorerWhen,
116
+ group: `specverse@${i + 1}`
117
+ }));
118
+ const editorMenu = topEntries.map((e, i) => ({
119
+ ...e.submenu ? { submenu: e.submenu } : { command: e.command },
120
+ when: editorWhen,
121
+ group: `specverse@${i + 1}`
122
+ }));
123
+ const menus = {
124
+ "explorer/context": explorerMenu,
125
+ "editor/context": editorMenu
126
+ };
127
+ for (const sub of submenuDefs) {
128
+ menus[sub.id] = cliCommands.filter((c) => c.submenu === sub.id).map((c) => ({ command: c.command }));
129
+ }
130
+ packageJson.contributes.menus = menus;
131
+ if (submenuDefs.length > 0) {
132
+ packageJson.contributes.submenus = submenuDefs.map((s) => ({
133
+ id: s.id,
134
+ label: s.label
135
+ }));
136
+ }
137
+ }
47
138
  }
48
139
  if (distribution.themes && distribution.themes.length > 0) {
49
140
  packageJson.contributes.themes = distribution.themes.map((theme) => ({
@@ -61,6 +152,29 @@ function generateVSCodeExtension(context) {
61
152
  if (existsSync(staticDir)) {
62
153
  copyRecursive(staticDir, extensionDir);
63
154
  }
155
+ const schemaSrc = resolveComposedSchemaPath();
156
+ if (schemaSrc) {
157
+ const schemasDir = join(extensionDir, "schemas");
158
+ if (!existsSync(schemasDir)) mkdirSync(schemasDir, { recursive: true });
159
+ copyFileSync(schemaSrc, join(schemasDir, "specverse-schema.json"));
160
+ }
161
+ if (distribution?.languages && distribution.languages.length > 0) {
162
+ const syntaxesDir = join(extensionDir, "syntaxes");
163
+ if (existsSync(syntaxesDir)) {
164
+ const langId = distribution.languages[0].id;
165
+ const targetName = `${langId}.tmLanguage.json`;
166
+ const targetPath = join(syntaxesDir, targetName);
167
+ if (!existsSync(targetPath)) {
168
+ const existing = readdirSync(syntaxesDir).find(
169
+ (f) => f.endsWith(".tmLanguage.json") && f !== targetName
170
+ );
171
+ if (existing) {
172
+ copyFileSync(join(syntaxesDir, existing), targetPath);
173
+ unlinkSync(join(syntaxesDir, existing));
174
+ }
175
+ }
176
+ }
177
+ }
64
178
  const srcDir = join(extensionDir, "src");
65
179
  if (!existsSync(srcDir)) mkdirSync(srcDir, { recursive: true });
66
180
  const extTs = join(staticDir, "extension.ts");
@@ -102,6 +216,56 @@ function extractDistribution(spec) {
102
216
  }
103
217
  return allDistributions.length > 0 ? allDistributions[0] : null;
104
218
  }
219
+ function findSpecCommand(spec, ref) {
220
+ if (!ref) return null;
221
+ const parts = ref.split(".");
222
+ const target = parts[parts.length - 1];
223
+ const components = spec?.components || {};
224
+ const componentList = Array.isArray(components) ? components : Object.entries(components).map(([name, data]) => ({ name, ...data }));
225
+ for (const comp of componentList) {
226
+ const cliCommands = comp?.commands;
227
+ if (!cliCommands) continue;
228
+ for (const [, rootDef] of Object.entries(cliCommands)) {
229
+ const subcommands = rootDef?.subcommands || {};
230
+ if (subcommands[target]) return subcommands[target];
231
+ }
232
+ }
233
+ return null;
234
+ }
235
+ function buildCLICommandMap(spec) {
236
+ const map = /* @__PURE__ */ new Map();
237
+ const components = spec?.components || {};
238
+ const componentList = Array.isArray(components) ? components : Object.entries(components).map(([name, data]) => ({ name, ...data }));
239
+ for (const comp of componentList) {
240
+ const compName = comp.name || "";
241
+ const cliCommands = comp?.commands;
242
+ if (!cliCommands) continue;
243
+ for (const [rootName, rootDef] of Object.entries(cliCommands)) {
244
+ const subcommands = rootDef?.subcommands || {};
245
+ for (const [subName, subDef] of Object.entries(subcommands)) {
246
+ const sub = subDef;
247
+ const entry = { description: sub.description, title: sub.title };
248
+ if (compName) map.set(`${compName}.${subName}`, entry);
249
+ map.set(`${rootName}.${subName}`, entry);
250
+ if (!map.has(subName)) map.set(subName, entry);
251
+ const nestedSubs = sub?.subcommands;
252
+ if (nestedSubs) {
253
+ for (const [nestedName, nestedDef] of Object.entries(nestedSubs)) {
254
+ const nestedEntry = {
255
+ description: nestedDef.description,
256
+ title: nestedDef.title
257
+ };
258
+ const qualified = `${subName}.${nestedName}`;
259
+ if (compName) map.set(`${compName}.${qualified}`, nestedEntry);
260
+ map.set(`${rootName}.${qualified}`, nestedEntry);
261
+ if (!map.has(qualified)) map.set(qualified, nestedEntry);
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ return map;
268
+ }
105
269
  function extractCLICommands(spec) {
106
270
  const commands = [];
107
271
  const components = spec?.components || {};
@@ -159,7 +323,7 @@ function generatePackageJson(commands, _entityTypes, specVersion = "1.0.0") {
159
323
  publisher: "specverse",
160
324
  engines: { vscode: "^1.80.0" },
161
325
  categories: ["Programming Languages", "Linters", "Snippets"],
162
- activationEvents: ["onLanguage:specverse"],
326
+ activationEvents: [],
163
327
  main: "./dist/extension.js",
164
328
  contributes: {
165
329
  languages: [{
@@ -175,7 +339,7 @@ function generatePackageJson(commands, _entityTypes, specVersion = "1.0.0") {
175
339
  }],
176
340
  jsonValidation: [{
177
341
  fileMatch: ["*.specly", "*.specverse"],
178
- url: "./schemas/specverse-v3-schema.json"
342
+ url: "./schemas/specverse-schema.json"
179
343
  }],
180
344
  themes: [
181
345
  { label: "SpecVerse Dark", uiTheme: "vs-dark", path: "./themes/specverse-complete-theme.json" },
@@ -9,7 +9,7 @@ metadata:
9
9
  tags: [vscode, ide, extension, language-support]
10
10
 
11
11
  compatibility:
12
- specverse: "^4.0.0"
12
+ specverse: ">=4.0.0"
13
13
  node: ">=18.0.0"
14
14
 
15
15
  capabilities:
@@ -249,7 +249,7 @@ import type { ParserEngine, InferenceEngine } from '@specverse/types';`,
249
249
  },
250
250
  realize: {
251
251
  imports: `import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
252
- import { resolve, join } from 'path';
252
+ import { resolve, join, dirname } from 'path';
253
253
  import { EngineRegistry } from '@specverse/entities';
254
254
  import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/types';`,
255
255
  handler: `if (!existsSync(file)) {
@@ -386,10 +386,32 @@ import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/ty
386
386
  }
387
387
  const inferredSpec = { ...componentData, componentName, components: inferredYaml?.components || {} };
388
388
 
389
- // Realize — let the realize engine handle its own library
390
- const manifestPath = options.manifest || resolve((process.env.SPECVERSE_USER_CWD || process.cwd()), 'manifests/implementation.yaml');
391
- if (!existsSync(manifestPath)) {
392
- console.error('Manifest not found:', manifestPath);
389
+ // Realize — let the realize engine handle its own library.
390
+ // Locate the nearest implementation manifest by walking up from the
391
+ // spec file, then falling back to the user's cwd. This lets the same
392
+ // invocation work from any subdirectory (CLI, VSCode right-click, CI).
393
+ const cwd = process.env.SPECVERSE_USER_CWD || process.cwd();
394
+ let manifestPath: string | null = null;
395
+ if (options.manifest) {
396
+ manifestPath = resolve(cwd, options.manifest);
397
+ } else {
398
+ let searchDir = dirname(resolve(file));
399
+ while (true) {
400
+ const inManifests = join(searchDir, 'manifests', 'implementation.yaml');
401
+ if (existsSync(inManifests)) { manifestPath = inManifests; break; }
402
+ const flat = join(searchDir, 'implementation.yaml');
403
+ if (existsSync(flat)) { manifestPath = flat; break; }
404
+ const parent = dirname(searchDir);
405
+ if (parent === searchDir) break;
406
+ searchDir = parent;
407
+ }
408
+ if (!manifestPath) {
409
+ const cwdBased = resolve(cwd, 'manifests/implementation.yaml');
410
+ if (existsSync(cwdBased)) manifestPath = cwdBased;
411
+ }
412
+ }
413
+ if (!manifestPath || !existsSync(manifestPath)) {
414
+ console.error('Manifest not found. Looked for manifests/implementation.yaml walking up from the spec file, then in ' + cwd);
393
415
  process.exit(1);
394
416
  }
395
417
 
@@ -24,7 +24,7 @@ The static framework includes:
24
24
 
25
25
  The generated MCP server exposes tools like `specverse-create`, `specverse-analyse`, `specverse-validate`, `specverse-realize`, and `specverse-suggest`, plus resources for schema, conventions, library catalog, and prompt templates.
26
26
 
27
- **Package**: `@specverse/mcp` v3.5.2, depends on `@modelcontextprotocol/sdk` and `@specverse/lang`.
27
+ **Package**: `@specverse/mcp` v3.5.2, depends on `@modelcontextprotocol/sdk` and `@specverse/engines`.
28
28
 
29
29
  ### VSCode Extension (`templates/vscode/`)
30
30
 
@@ -9,7 +9,7 @@ metadata:
9
9
  tags: [mcp, ai, tools, claude, llm]
10
10
 
11
11
  compatibility:
12
- specverse: "^4.0.0"
12
+ specverse: ">=4.0.0"
13
13
  node: ">=18.0.0"
14
14
 
15
15
  capabilities: