@specverse/engines 4.3.5 → 5.0.1

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 (68) 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/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.d.ts +9 -7
  15. package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.d.ts.map +1 -1
  16. package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.js +27 -9
  17. package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.js.map +1 -1
  18. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +27 -5
  19. package/dist/libs/instance-factories/tools/README.md +1 -1
  20. package/dist/libs/instance-factories/tools/mcp.yaml +1 -1
  21. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +342 -116
  22. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +172 -8
  23. package/dist/libs/instance-factories/tools/vscode.yaml +1 -1
  24. package/libs/instance-factories/cli/templates/commander/command-generator.ts +27 -5
  25. package/libs/instance-factories/tools/README.md +1 -1
  26. package/libs/instance-factories/tools/mcp.yaml +1 -1
  27. package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +392 -141
  28. package/libs/instance-factories/tools/templates/vscode/static/extension.ts +9 -2
  29. package/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.ts +246 -10
  30. package/libs/instance-factories/tools/vscode.yaml +1 -1
  31. package/package.json +5 -4
  32. package/libs/instance-factories/tools/templates/mcp/static/docs/DEPLOYMENT_GUIDE.md +0 -630
  33. package/libs/instance-factories/tools/templates/mcp/static/docs/HYBRID_RESOURCE_SYSTEM.md +0 -330
  34. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/EXTENSION_DEPLOYMENT.md +0 -552
  35. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/LOCAL_DEPLOYMENT.md +0 -164
  36. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/WEB_DEPLOYMENT.md +0 -247
  37. package/libs/instance-factories/tools/templates/mcp/static/package.json +0 -94
  38. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-enterprise.js +0 -284
  39. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-extension.js +0 -139
  40. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-local.js +0 -74
  41. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-web.js +0 -156
  42. package/libs/instance-factories/tools/templates/mcp/static/scripts/copy-canonical-files.js +0 -41
  43. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-deployments.js +0 -259
  44. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-resources.js +0 -231
  45. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-simple.js +0 -196
  46. package/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.ts +0 -293
  47. package/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.ts +0 -90
  48. package/libs/instance-factories/tools/templates/mcp/static/src/index.ts +0 -24
  49. package/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.ts +0 -15
  50. package/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.ts +0 -106
  51. package/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.ts +0 -75
  52. package/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.ts +0 -239
  53. package/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.ts +0 -1501
  54. package/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.ts +0 -211
  55. package/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.ts +0 -308
  56. package/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.ts +0 -210
  57. package/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.ts +0 -356
  58. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.ts +0 -522
  59. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.ts +0 -530
  60. package/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.ts +0 -594
  61. package/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.ts +0 -170
  62. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.init.test.ts +0 -544
  63. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.test.ts +0 -189
  64. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/ResourcesProviderService.test.ts +0 -89
  65. package/libs/instance-factories/tools/templates/mcp/static/src/types/index.ts +0 -110
  66. package/libs/instance-factories/tools/templates/mcp/static/tsconfig.json +0 -28
  67. package/libs/instance-factories/tools/templates/vscode/static/schemas/specverse-v3-schema.json +0 -4279
  68. /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: