@specverse/engines 4.3.4 → 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 (66) 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/scaffolding/templates/generic/package-json-generator.js +1 -1
  16. package/dist/libs/instance-factories/tools/README.md +1 -1
  17. package/dist/libs/instance-factories/tools/mcp.yaml +1 -1
  18. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +336 -116
  19. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +172 -8
  20. package/dist/libs/instance-factories/tools/vscode.yaml +1 -1
  21. package/libs/instance-factories/cli/templates/commander/command-generator.ts +27 -5
  22. package/libs/instance-factories/scaffolding/templates/generic/package-json-generator.ts +10 -6
  23. package/libs/instance-factories/tools/README.md +1 -1
  24. package/libs/instance-factories/tools/mcp.yaml +1 -1
  25. package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +386 -141
  26. package/libs/instance-factories/tools/templates/vscode/static/extension.ts +9 -2
  27. package/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.ts +246 -10
  28. package/libs/instance-factories/tools/vscode.yaml +1 -1
  29. package/package.json +5 -4
  30. package/libs/instance-factories/tools/templates/mcp/static/docs/DEPLOYMENT_GUIDE.md +0 -630
  31. package/libs/instance-factories/tools/templates/mcp/static/docs/HYBRID_RESOURCE_SYSTEM.md +0 -330
  32. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/EXTENSION_DEPLOYMENT.md +0 -552
  33. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/LOCAL_DEPLOYMENT.md +0 -164
  34. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/WEB_DEPLOYMENT.md +0 -247
  35. package/libs/instance-factories/tools/templates/mcp/static/package.json +0 -94
  36. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-enterprise.js +0 -284
  37. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-extension.js +0 -139
  38. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-local.js +0 -74
  39. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-web.js +0 -156
  40. package/libs/instance-factories/tools/templates/mcp/static/scripts/copy-canonical-files.js +0 -41
  41. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-deployments.js +0 -259
  42. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-resources.js +0 -231
  43. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-simple.js +0 -196
  44. package/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.ts +0 -293
  45. package/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.ts +0 -90
  46. package/libs/instance-factories/tools/templates/mcp/static/src/index.ts +0 -24
  47. package/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.ts +0 -15
  48. package/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.ts +0 -106
  49. package/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.ts +0 -75
  50. package/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.ts +0 -239
  51. package/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.ts +0 -1501
  52. package/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.ts +0 -211
  53. package/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.ts +0 -308
  54. package/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.ts +0 -210
  55. package/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.ts +0 -356
  56. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.ts +0 -522
  57. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.ts +0 -530
  58. package/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.ts +0 -594
  59. package/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.ts +0 -170
  60. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.init.test.ts +0 -544
  61. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.test.ts +0 -189
  62. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/ResourcesProviderService.test.ts +0 -89
  63. package/libs/instance-factories/tools/templates/mcp/static/src/types/index.ts +0 -110
  64. package/libs/instance-factories/tools/templates/mcp/static/tsconfig.json +0 -28
  65. package/libs/instance-factories/tools/templates/vscode/static/schemas/specverse-v3-schema.json +0 -4279
  66. /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
 
@@ -83,13 +83,17 @@ export default function generatePackageJson(context: TemplateContext): string {
83
83
  // this, tsx (backend) and vite (frontend) each pull a different
84
84
  // esbuild range, and npm's hoisting can land a JS host and native
85
85
  // binary from different patch versions in the same node_modules
86
- // tree — causing `Host 0.27.7 does not match binary 0.27.1` at
87
- // first `tsx watch`. Overriding forces one version down through
88
- // every transitive, including the platform-specific binary
89
- // (@esbuild/darwin-arm64 etc). Version tracks tsx's esbuild range
90
- // since tsx runs the backend dev loop where the error surfaces.
86
+ // tree — causing `Host X does not match binary Y` at first
87
+ // `tsx watch`.
88
+ //
89
+ // Version tracks VITE's range (^0.25), not tsx's (^0.27). Vite's
90
+ // build step has a known destructuring-transform regression on
91
+ // 0.27 that triggers "Transforming destructuring to the
92
+ // configured target environment is not supported yet" when it
93
+ // emits arrow-destructured useState pairs, even for targets that
94
+ // natively support destructuring. tsx is tolerant of 0.25.
91
95
  pkg.overrides = {
92
- 'esbuild': '0.27.7',
96
+ 'esbuild': '0.25.12',
93
97
  };
94
98
  } else {
95
99
  // Standalone mode - merge all scripts
@@ -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: