@specverse/engines 5.0.0 → 5.0.2
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.
- package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.d.ts +9 -7
- package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.d.ts.map +1 -1
- package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.js +27 -9
- package/dist/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.js.map +1 -1
- package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +14 -8
- package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +13 -7
- package/package.json +2 -2
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rule: lifecycle-state-visible-in-detail
|
|
3
3
|
*
|
|
4
|
-
* For every model with a lifecycle,
|
|
5
|
-
* the lifecycle
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* For every model with a lifecycle, after creating a fresh entity
|
|
5
|
+
* the UI should surface its current lifecycle state. v2 seeds an
|
|
6
|
+
* entity in the initial state via the same pattern as the
|
|
7
|
+
* state-sync rules (buildSeedData + createEntity) because an empty
|
|
8
|
+
* detail view has nothing to assert against — a fresh instance is
|
|
9
|
+
* the minimal setup that produces state-bearing UI.
|
|
8
10
|
*
|
|
9
11
|
* Lifecycle shape in the spec:
|
|
10
12
|
* lifecycles:
|
|
@@ -15,9 +17,9 @@
|
|
|
15
17
|
* different shape (e.g. an explicit `states: [...]`), the parser
|
|
16
18
|
* should normalize both into the same structure.
|
|
17
19
|
*
|
|
18
|
-
* One TestCase per (model, lifecycle) pair
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* One TestCase per (model, lifecycle) pair. Transitions between
|
|
21
|
+
* states are tested by evolve-reflects-in-list; this rule is the
|
|
22
|
+
* thin "initial state renders at all" counterpart.
|
|
21
23
|
*/
|
|
22
24
|
import type { UiContractRule } from '../test-case-types.js';
|
|
23
25
|
export declare const RULE_ID = "lifecycle-state-visible-in-detail";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-state-visible-in-detail.d.ts","sourceRoot":"","sources":["../../../../src/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"lifecycle-state-visible-in-detail.d.ts","sourceRoot":"","sources":["../../../../src/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAA4B,MAAM,uBAAuB,CAAC;AAGtF,eAAO,MAAM,OAAO,sCAAsC,CAAC;AAuB3D,eAAO,MAAM,6BAA6B,EAAE,cAoC3C,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rule: lifecycle-state-visible-in-detail
|
|
3
3
|
*
|
|
4
|
-
* For every model with a lifecycle,
|
|
5
|
-
* the lifecycle
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* For every model with a lifecycle, after creating a fresh entity
|
|
5
|
+
* the UI should surface its current lifecycle state. v2 seeds an
|
|
6
|
+
* entity in the initial state via the same pattern as the
|
|
7
|
+
* state-sync rules (buildSeedData + createEntity) because an empty
|
|
8
|
+
* detail view has nothing to assert against — a fresh instance is
|
|
9
|
+
* the minimal setup that produces state-bearing UI.
|
|
8
10
|
*
|
|
9
11
|
* Lifecycle shape in the spec:
|
|
10
12
|
* lifecycles:
|
|
@@ -15,10 +17,11 @@
|
|
|
15
17
|
* different shape (e.g. an explicit `states: [...]`), the parser
|
|
16
18
|
* should normalize both into the same structure.
|
|
17
19
|
*
|
|
18
|
-
* One TestCase per (model, lifecycle) pair
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* One TestCase per (model, lifecycle) pair. Transitions between
|
|
21
|
+
* states are tested by evolve-reflects-in-list; this rule is the
|
|
22
|
+
* thin "initial state renders at all" counterpart.
|
|
21
23
|
*/
|
|
24
|
+
import { pickDisplayAttribute, buildSeedData } from './_shared.js';
|
|
22
25
|
export const RULE_ID = 'lifecycle-state-visible-in-detail';
|
|
23
26
|
function extractInitialState(lifecycleDef) {
|
|
24
27
|
if (!lifecycleDef)
|
|
@@ -45,6 +48,15 @@ export const lifecycleStateVisibleInDetail = (spec) => {
|
|
|
45
48
|
const lifecycles = model.lifecycles;
|
|
46
49
|
if (!lifecycles)
|
|
47
50
|
continue;
|
|
51
|
+
// Need a way to seed an entity so there's something for the UI
|
|
52
|
+
// to render. Skip the test for models without a seedable shape.
|
|
53
|
+
const display = pickDisplayAttribute(model);
|
|
54
|
+
if (!display)
|
|
55
|
+
continue;
|
|
56
|
+
const marker = `ct-lcstate-${model.name}`;
|
|
57
|
+
const seedData = buildSeedData(model, marker);
|
|
58
|
+
if (!seedData)
|
|
59
|
+
continue;
|
|
48
60
|
for (const [lcName, lcDef] of Object.entries(lifecycles)) {
|
|
49
61
|
const initial = extractInitialState(lcDef);
|
|
50
62
|
if (!initial)
|
|
@@ -52,10 +64,16 @@ export const lifecycleStateVisibleInDetail = (spec) => {
|
|
|
52
64
|
cases.push({
|
|
53
65
|
ruleId: RULE_ID,
|
|
54
66
|
specElement: `${model.name}.${lcName}`,
|
|
55
|
-
name: `[${RULE_ID}] ${model.name}.${lcName} initial state '${initial}' visible`,
|
|
67
|
+
name: `[${RULE_ID}] ${model.name}.${lcName} initial state '${initial}' visible after create`,
|
|
56
68
|
steps: [
|
|
57
69
|
{ action: 'bootRuntime' },
|
|
58
|
-
{ action: '
|
|
70
|
+
{ action: 'navigateToModel', modelName: model.name },
|
|
71
|
+
{
|
|
72
|
+
action: 'createEntity',
|
|
73
|
+
modelName: model.name,
|
|
74
|
+
data: seedData,
|
|
75
|
+
uniqueField: display.name,
|
|
76
|
+
},
|
|
59
77
|
{ action: 'expectLifecycleState', modelName: model.name, stateName: initial },
|
|
60
78
|
],
|
|
61
79
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-state-visible-in-detail.js","sourceRoot":"","sources":["../../../../src/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"lifecycle-state-visible-in-detail.js","sourceRoot":"","sources":["../../../../src/inference/ui-contracts/rules/lifecycle-state-visible-in-detail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAE3D,SAAS,mBAAmB,CAAC,YAAiB;IAC5C,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/B,8CAA8C;IAC9C,IAAI,OAAO,YAAY,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IAED,kDAAkD;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI,CAAC;IACjE,CAAC;IAED,8CAA8C;IAC9C,IAAI,OAAO,YAAY,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC,OAAO,CAAC;IAE1E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,6BAA6B,GAAmB,CAAC,IAAoB,EAAc,EAAE;IAChG,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,KAAK,CAAC,UAA6C,CAAC;QACvE,IAAI,CAAC,UAAU;YAAE,SAAS;QAE1B,+DAA+D;QAC/D,gEAAgE;QAChE,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,MAAM,GAAG,cAAc,KAAK,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ;YAAE,SAAS;QAExB,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,KAAK,CAAC,IAAI,CAAC;gBACT,MAAM,EAAE,OAAO;gBACf,WAAW,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,EAAE;gBACtC,IAAI,EAAE,IAAI,OAAO,KAAK,KAAK,CAAC,IAAI,IAAI,MAAM,mBAAmB,OAAO,wBAAwB;gBAC5F,KAAK,EAAE;oBACL,EAAE,MAAM,EAAE,aAAa,EAAE;oBACzB,EAAE,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;oBACpD;wBACE,MAAM,EAAE,cAAc;wBACtB,SAAS,EAAE,KAAK,CAAC,IAAI;wBACrB,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,OAAO,CAAC,IAAI;qBAC1B;oBACD,EAAE,MAAM,EAAE,sBAAsB,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE;iBAC9E;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -142,7 +142,13 @@ function generateTsconfig() {
|
|
|
142
142
|
declaration: true,
|
|
143
143
|
outDir: "./dist",
|
|
144
144
|
rootDir: "./src",
|
|
145
|
-
resolveJsonModule: true
|
|
145
|
+
resolveJsonModule: true,
|
|
146
|
+
// Under moduleResolution: 'bundler' tsc's auto-inclusion of
|
|
147
|
+
// @types/* packages from node_modules/@types is environment-
|
|
148
|
+
// dependent — Node 20 on CI doesn't pick up @types/node while
|
|
149
|
+
// Node 24 locally does. Listing it explicitly forces consistent
|
|
150
|
+
// resolution everywhere.
|
|
151
|
+
types: ["node"]
|
|
146
152
|
},
|
|
147
153
|
include: ["src/**/*"],
|
|
148
154
|
exclude: ["node_modules", "dist"]
|
|
@@ -181,7 +187,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
181
187
|
})),
|
|
182
188
|
}));
|
|
183
189
|
|
|
184
|
-
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
190
|
+
server.setRequestHandler(CallToolRequestSchema, async (req: { params: { name: string; arguments?: Record<string, unknown> } }) => {
|
|
185
191
|
const { name, arguments: args } = req.params;
|
|
186
192
|
return callTool(name, args ?? {});
|
|
187
193
|
});
|
|
@@ -195,7 +201,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
|
195
201
|
})),
|
|
196
202
|
}));
|
|
197
203
|
|
|
198
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
|
|
204
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req: { params: { uri: string } }) => {
|
|
199
205
|
return readResource(req.params.uri);
|
|
200
206
|
});
|
|
201
207
|
|
|
@@ -250,14 +256,14 @@ export function runCli(
|
|
|
250
256
|
}
|
|
251
257
|
}
|
|
252
258
|
|
|
253
|
-
return new Promise(resolve => {
|
|
259
|
+
return new Promise<CliResult>(resolve => {
|
|
254
260
|
const child = spawn('specverse', argv, { cwd: cwd || process.cwd(), env: process.env });
|
|
255
261
|
let stdout = '';
|
|
256
262
|
let stderr = '';
|
|
257
|
-
child.stdout.on('data', d => { stdout += d.toString(); });
|
|
258
|
-
child.stderr.on('data', d => { stderr += d.toString(); });
|
|
259
|
-
child.on('close', code => resolve({ stdout, stderr, code }));
|
|
260
|
-
child.on('error', err => resolve({ stdout, stderr: stderr + '\\n' + err.message, code: -1 }));
|
|
263
|
+
child.stdout.on('data', (d: Buffer) => { stdout += d.toString(); });
|
|
264
|
+
child.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
|
265
|
+
child.on('close', (code: number | null) => resolve({ stdout, stderr, code }));
|
|
266
|
+
child.on('error', (err: Error) => resolve({ stdout, stderr: stderr + '\\n' + err.message, code: -1 }));
|
|
261
267
|
});
|
|
262
268
|
}
|
|
263
269
|
`;
|
|
@@ -208,6 +208,12 @@ function generateTsconfig(): string {
|
|
|
208
208
|
outDir: './dist',
|
|
209
209
|
rootDir: './src',
|
|
210
210
|
resolveJsonModule: true,
|
|
211
|
+
// Under moduleResolution: 'bundler' tsc's auto-inclusion of
|
|
212
|
+
// @types/* packages from node_modules/@types is environment-
|
|
213
|
+
// dependent — Node 20 on CI doesn't pick up @types/node while
|
|
214
|
+
// Node 24 locally does. Listing it explicitly forces consistent
|
|
215
|
+
// resolution everywhere.
|
|
216
|
+
types: ['node'],
|
|
211
217
|
},
|
|
212
218
|
include: ['src/**/*'],
|
|
213
219
|
exclude: ['node_modules', 'dist'],
|
|
@@ -247,7 +253,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
247
253
|
})),
|
|
248
254
|
}));
|
|
249
255
|
|
|
250
|
-
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
256
|
+
server.setRequestHandler(CallToolRequestSchema, async (req: { params: { name: string; arguments?: Record<string, unknown> } }) => {
|
|
251
257
|
const { name, arguments: args } = req.params;
|
|
252
258
|
return callTool(name, args ?? {});
|
|
253
259
|
});
|
|
@@ -261,7 +267,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
|
261
267
|
})),
|
|
262
268
|
}));
|
|
263
269
|
|
|
264
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
|
|
270
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req: { params: { uri: string } }) => {
|
|
265
271
|
return readResource(req.params.uri);
|
|
266
272
|
});
|
|
267
273
|
|
|
@@ -317,14 +323,14 @@ export function runCli(
|
|
|
317
323
|
}
|
|
318
324
|
}
|
|
319
325
|
|
|
320
|
-
return new Promise(resolve => {
|
|
326
|
+
return new Promise<CliResult>(resolve => {
|
|
321
327
|
const child = spawn('specverse', argv, { cwd: cwd || process.cwd(), env: process.env });
|
|
322
328
|
let stdout = '';
|
|
323
329
|
let stderr = '';
|
|
324
|
-
child.stdout.on('data', d => { stdout += d.toString(); });
|
|
325
|
-
child.stderr.on('data', d => { stderr += d.toString(); });
|
|
326
|
-
child.on('close', code => resolve({ stdout, stderr, code }));
|
|
327
|
-
child.on('error', err => resolve({ stdout, stderr: stderr + '\\n' + err.message, code: -1 }));
|
|
330
|
+
child.stdout.on('data', (d: Buffer) => { stdout += d.toString(); });
|
|
331
|
+
child.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
|
332
|
+
child.on('close', (code: number | null) => resolve({ stdout, stderr, code }));
|
|
333
|
+
child.on('error', (err: Error) => resolve({ stdout, stderr: stderr + '\\n' + err.message, code: -1 }));
|
|
328
334
|
});
|
|
329
335
|
}
|
|
330
336
|
`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specverse/engines",
|
|
3
|
-
"version": "5.0.
|
|
4
|
-
"description": "SpecVerse toolchain
|
|
3
|
+
"version": "5.0.2",
|
|
4
|
+
"description": "SpecVerse toolchain \u2014 parser, inference, realize, generators, AI, registry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|