@specverse/engines 6.3.0 → 6.3.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.
@@ -32,7 +32,7 @@ export type EventPayloads = Record<string, any>;
32
32
  const interfaces = [];
33
33
  const payloadMapEntries = [];
34
34
  for (const [eventName, eventDef] of events) {
35
- const def = eventDef;
35
+ const def = eventDef || {};
36
36
  const attrs = def.attributes || def.payload || {};
37
37
  const attrEntries = Array.isArray(attrs) ? attrs.map((a) => [a.name, a]) : Object.entries(attrs);
38
38
  const fields = attrEntries.map(([name, attrDef]) => {
@@ -48,6 +48,7 @@ async function generateAiBehaviors(context) {
48
48
  if (!controller?.actions) return "";
49
49
  const modelName = model?.name || controller.model || "Model";
50
50
  const modelVar = modelName.charAt(0).toLowerCase() + modelName.slice(1);
51
+ const availableModels = (context.models || []).map((m) => m?.name).filter(Boolean);
51
52
  const unmatchedFunctions = [];
52
53
  for (const [actionName, action] of Object.entries(controller.actions)) {
53
54
  const steps = action.steps || [];
@@ -105,7 +106,7 @@ async function generateAiBehaviors(context) {
105
106
  });
106
107
  }
107
108
  async function generateAiBehaviorsFile(opts) {
108
- const { ownerName, unmatchedFunctions, availableModels: availableModels2, spec } = opts;
109
+ const { ownerName, unmatchedFunctions, availableModels, spec } = opts;
109
110
  if (unmatchedFunctions.length === 0) return "";
110
111
  let aiService = null;
111
112
  try {
@@ -158,7 +159,7 @@ ${body}
158
159
  functionName,
159
160
  parameterNames: inputs,
160
161
  // the actual inputs to the pure function
161
- availableModels: availableModels2,
162
+ availableModels,
162
163
  spec,
163
164
  returnType
164
165
  // Pass declared return type to Claude
@@ -2,7 +2,10 @@ function toVar(name) {
2
2
  return name.charAt(0).toLowerCase() + name.slice(1);
3
3
  }
4
4
  function toMethod(words) {
5
- return words.trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toLowerCase());
5
+ const cleaned = words.trim().replace(/[^A-Za-z0-9\s]+/g, " ");
6
+ const camel = cleaned.replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toLowerCase());
7
+ const safe = camel.replace(/[^A-Za-z0-9_$]/g, "");
8
+ return safe || "unnamedStep";
6
9
  }
7
10
  function resolveValue(rawValue, ctx) {
8
11
  const value = rawValue.trim().replace(/^['"]|['"]$/g, "");
@@ -37,7 +37,10 @@ export type EventPayloads = Record<string, any>;
37
37
  const payloadMapEntries: string[] = [];
38
38
 
39
39
  for (const [eventName, eventDef] of events) {
40
- const def = eventDef as any;
40
+ const def = (eventDef as any) || {};
41
+ // Multi-component fan-out can produce events with no attributes/payload
42
+ // block (e.g. reference-only events in PubsubDomain). Default to empty
43
+ // map so downstream rendering still emits a valid `{}` payload type.
41
44
  const attrs = def.attributes || def.payload || {};
42
45
 
43
46
  // Handle both array and object attribute formats
@@ -100,6 +100,12 @@ export default async function generateAiBehaviors(context: TemplateContext): Pro
100
100
 
101
101
  const modelName = model?.name || controller.model || 'Model';
102
102
  const modelVar = modelName.charAt(0).toLowerCase() + modelName.slice(1);
103
+ // List of all entity-model names available in the realized output. Forwarded
104
+ // to the AI prompt so generated function bodies can reference them by type.
105
+ // Previously left undefined here; only the service-level path declared it,
106
+ // which surfaced as `availableModels is not defined` in the realize warning
107
+ // tail when the controller-level path emitted an *.ai.ts file.
108
+ const availableModels: string[] = ((context as any).models || []).map((m: any) => m?.name).filter(Boolean);
103
109
 
104
110
  // Find unmatched steps across all actions.
105
111
  // We simulate step execution through matchStep() so declaredVars accumulates
@@ -31,7 +31,17 @@ function toVar(name: string): string {
31
31
  }
32
32
 
33
33
  function toMethod(words: string): string {
34
- return words.trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/^\w/, c => c.toLowerCase());
34
+ // Split on whitespace AND non-identifier chars (hyphens, commas, equals,
35
+ // parens, etc.) so step text like "Compile via expr-eval Parser" yields
36
+ // "compileViaExprEvalParser", not "compileViaExpr-evalParser" (which is
37
+ // not a valid TypeScript identifier and breaks esbuild downstream).
38
+ const cleaned = words.trim().replace(/[^A-Za-z0-9\s]+/g, ' ');
39
+ const camel = cleaned.replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/^\w/, c => c.toLowerCase());
40
+ // Strip any remaining non-identifier chars (digits at start, etc.) and
41
+ // ensure the result is a valid TS identifier. If the input collapses to
42
+ // the empty string, fall back to a generic name.
43
+ const safe = camel.replace(/[^A-Za-z0-9_$]/g, '');
44
+ return safe || 'unnamedStep';
35
45
  }
36
46
 
37
47
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "6.3.0",
3
+ "version": "6.3.1",
4
4
  "description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry, bundles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",