@lokascript/framework 2.0.0 → 2.2.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 (138) hide show
  1. package/dist/aot/index.d.ts +1 -0
  2. package/dist/aot/index.d.ts.map +1 -1
  3. package/dist/aot/registry-bridge.d.ts +27 -0
  4. package/dist/aot/registry-bridge.d.ts.map +1 -0
  5. package/dist/api/create-dsl.d.ts.map +1 -1
  6. package/dist/api/dispatcher.d.ts +22 -0
  7. package/dist/api/dispatcher.d.ts.map +1 -1
  8. package/dist/api/domain-registry.d.ts +41 -0
  9. package/dist/api/domain-registry.d.ts.map +1 -1
  10. package/dist/api/index.js +1438 -21
  11. package/dist/api/index.js.map +1 -1
  12. package/dist/core/index.js +247 -10
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/core/pattern-matching/index.js +74 -10
  15. package/dist/core/pattern-matching/index.js.map +1 -1
  16. package/dist/core/pattern-matching/pattern-matcher.d.ts.map +1 -1
  17. package/dist/core/tokenization/index.js +133 -0
  18. package/dist/core/tokenization/index.js.map +1 -1
  19. package/dist/core/tokenization/morphology/base-normalizer.d.ts +94 -0
  20. package/dist/core/tokenization/morphology/base-normalizer.d.ts.map +1 -0
  21. package/dist/core/tokenization/morphology/index.d.ts +3 -1
  22. package/dist/core/tokenization/morphology/index.d.ts.map +1 -1
  23. package/dist/core/types.d.ts +81 -2
  24. package/dist/core/types.d.ts.map +1 -1
  25. package/dist/core/types.js +40 -0
  26. package/dist/core/types.js.map +1 -1
  27. package/dist/feedback/confidence-gate.d.ts +28 -0
  28. package/dist/feedback/confidence-gate.d.ts.map +1 -0
  29. package/dist/feedback/feedback-formatter.d.ts +21 -0
  30. package/dist/feedback/feedback-formatter.d.ts.map +1 -0
  31. package/dist/feedback/index.d.ts +11 -0
  32. package/dist/feedback/index.d.ts.map +1 -0
  33. package/dist/feedback/pattern-tracker.d.ts +47 -0
  34. package/dist/feedback/pattern-tracker.d.ts.map +1 -0
  35. package/dist/feedback/types.d.ts +113 -0
  36. package/dist/feedback/types.d.ts.map +1 -0
  37. package/dist/generation/index.js +2 -1
  38. package/dist/generation/index.js.map +1 -1
  39. package/dist/index.cjs +3264 -132
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.ts +8 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +3223 -132
  44. package/dist/index.js.map +1 -1
  45. package/dist/ir/explicit-parser.d.ts +86 -0
  46. package/dist/ir/explicit-parser.d.ts.map +1 -0
  47. package/dist/ir/explicit-renderer.d.ts +34 -0
  48. package/dist/ir/explicit-renderer.d.ts.map +1 -0
  49. package/dist/ir/from-interchange.d.ts +51 -0
  50. package/dist/ir/from-interchange.d.ts.map +1 -0
  51. package/dist/ir/index.d.ts +31 -0
  52. package/dist/ir/index.d.ts.map +1 -0
  53. package/dist/ir/index.js +1934 -0
  54. package/dist/ir/index.js.map +1 -0
  55. package/dist/ir/json-schema.d.ts +40 -0
  56. package/dist/ir/json-schema.d.ts.map +1 -0
  57. package/dist/ir/protocol-json.d.ts +73 -0
  58. package/dist/ir/protocol-json.d.ts.map +1 -0
  59. package/dist/ir/references.d.ts +19 -0
  60. package/dist/ir/references.d.ts.map +1 -0
  61. package/dist/ir/to-runtime-ast.d.ts +53 -0
  62. package/dist/ir/to-runtime-ast.d.ts.map +1 -0
  63. package/dist/ir/types.d.ts +151 -0
  64. package/dist/ir/types.d.ts.map +1 -0
  65. package/dist/parsing/index.js +74 -10
  66. package/dist/parsing/index.js.map +1 -1
  67. package/dist/prompts/index.d.ts +9 -0
  68. package/dist/prompts/index.d.ts.map +1 -0
  69. package/dist/prompts/prompt-generator.d.ts +49 -0
  70. package/dist/prompts/prompt-generator.d.ts.map +1 -0
  71. package/dist/prompts/types.d.ts +64 -0
  72. package/dist/prompts/types.d.ts.map +1 -0
  73. package/dist/schema/command-schema.d.ts +17 -0
  74. package/dist/schema/command-schema.d.ts.map +1 -1
  75. package/dist/schema/index.js.map +1 -1
  76. package/dist/testing/index.js +8673 -8260
  77. package/dist/testing/index.js.map +1 -1
  78. package/dist/training/index.d.ts +11 -0
  79. package/dist/training/index.d.ts.map +1 -0
  80. package/dist/training/jsonl-writer.d.ts +42 -0
  81. package/dist/training/jsonl-writer.d.ts.map +1 -0
  82. package/dist/training/schema-synthesizer.d.ts +20 -0
  83. package/dist/training/schema-synthesizer.d.ts.map +1 -0
  84. package/dist/training/types.d.ts +73 -0
  85. package/dist/training/types.d.ts.map +1 -0
  86. package/package.json +5 -1
  87. package/src/aot/index.ts +1 -0
  88. package/src/aot/registry-bridge.test.ts +104 -0
  89. package/src/aot/registry-bridge.ts +66 -0
  90. package/src/api/create-dsl.test.ts +306 -0
  91. package/src/api/create-dsl.ts +21 -0
  92. package/src/api/dispatcher.test.ts +66 -0
  93. package/src/api/dispatcher.ts +77 -9
  94. package/src/api/domain-registry.ts +120 -4
  95. package/src/core/pattern-matching/pattern-matcher.test.ts +131 -0
  96. package/src/core/pattern-matching/pattern-matcher.ts +102 -19
  97. package/src/core/tokenization/morphology/base-normalizer.ts +249 -0
  98. package/src/core/tokenization/morphology/index.ts +3 -1
  99. package/src/core/types.ts +147 -2
  100. package/src/feedback/confidence-gate.test.ts +111 -0
  101. package/src/feedback/confidence-gate.ts +70 -0
  102. package/src/feedback/feedback-formatter.test.ts +198 -0
  103. package/src/feedback/feedback-formatter.ts +298 -0
  104. package/src/feedback/index.ts +24 -0
  105. package/src/feedback/pattern-tracker.test.ts +198 -0
  106. package/src/feedback/pattern-tracker.ts +140 -0
  107. package/src/feedback/types.ts +149 -0
  108. package/src/generation/pattern-generator.ts +2 -2
  109. package/src/index.ts +29 -0
  110. package/src/integration/llm-lse-integration.test.ts +457 -0
  111. package/src/ir/conformance.test.ts +120 -0
  112. package/src/ir/explicit-parser.test.ts +612 -0
  113. package/src/ir/explicit-parser.ts +793 -0
  114. package/src/ir/explicit-renderer.test.ts +229 -0
  115. package/src/ir/explicit-renderer.ts +198 -0
  116. package/src/ir/from-interchange.test.ts +853 -0
  117. package/src/ir/from-interchange.ts +594 -0
  118. package/src/ir/index.ts +77 -0
  119. package/src/ir/json-schema.test.ts +281 -0
  120. package/src/ir/json-schema.ts +299 -0
  121. package/src/ir/protocol-json.test.ts +1187 -0
  122. package/src/ir/protocol-json.ts +751 -0
  123. package/src/ir/references.test.ts +38 -0
  124. package/src/ir/references.ts +33 -0
  125. package/src/ir/round-trip.test.ts +557 -0
  126. package/src/ir/to-runtime-ast.ts +203 -0
  127. package/src/ir/types.ts +191 -0
  128. package/src/prompts/index.ts +15 -0
  129. package/src/prompts/prompt-generator.test.ts +386 -0
  130. package/src/prompts/prompt-generator.ts +531 -0
  131. package/src/prompts/types.ts +89 -0
  132. package/src/schema/command-schema.ts +19 -0
  133. package/src/training/index.ts +13 -0
  134. package/src/training/jsonl-writer.test.ts +138 -0
  135. package/src/training/jsonl-writer.ts +67 -0
  136. package/src/training/schema-synthesizer.test.ts +250 -0
  137. package/src/training/schema-synthesizer.ts +306 -0
  138. package/src/training/types.ts +103 -0
package/dist/index.js CHANGED
@@ -14,6 +14,9 @@ function createPropertyPath(object, property) {
14
14
  function createExpression(raw) {
15
15
  return { type: "expression", raw };
16
16
  }
17
+ function createFlag(name, enabled = true) {
18
+ return { type: "flag", name, enabled };
19
+ }
17
20
  function createCommandNode(action, roles, metadata) {
18
21
  const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
19
22
  const node = {
@@ -65,6 +68,7 @@ function createCompoundNode(statements, chainType = "sequential", metadata) {
65
68
  return metadata ? { ...base, metadata } : base;
66
69
  }
67
70
  function extractValue(value) {
71
+ if (value.type === "flag") return value.name;
68
72
  if ("raw" in value && value.raw !== void 0) return String(value.raw);
69
73
  if ("value" in value && value.value !== void 0) return String(value.value);
70
74
  if (value.type === "property-path") return `${extractValue(value.object)}.${value.property}`;
@@ -91,6 +95,38 @@ function createLoopNode(action, roles, loopVariant, body, loopVariable, indexVar
91
95
  ...metadata && { metadata }
92
96
  };
93
97
  }
98
+ function createTryNode(body, catchBranch, finallyBranch, metadata) {
99
+ return {
100
+ kind: "command",
101
+ action: "try",
102
+ roles: /* @__PURE__ */ new Map(),
103
+ body,
104
+ ...catchBranch && catchBranch.length > 0 ? { catchBranch } : {},
105
+ ...finallyBranch && finallyBranch.length > 0 ? { finallyBranch } : {},
106
+ ...metadata ? { metadata } : {}
107
+ };
108
+ }
109
+ function createAsyncNode(variant, asyncBody, metadata) {
110
+ return {
111
+ kind: "command",
112
+ action: variant,
113
+ roles: /* @__PURE__ */ new Map(),
114
+ asyncVariant: variant,
115
+ asyncBody,
116
+ ...metadata ? { metadata } : {}
117
+ };
118
+ }
119
+ function createMatchNode(roles, arms, defaultArm, metadata) {
120
+ const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
121
+ return {
122
+ kind: "command",
123
+ action: "match",
124
+ roles: rolesMap,
125
+ arms,
126
+ ...defaultArm && defaultArm.length > 0 ? { defaultArm } : {},
127
+ ...metadata ? { metadata } : {}
128
+ };
129
+ }
94
130
 
95
131
  // src/core/logger.ts
96
132
  var DebugLogger = class {
@@ -346,7 +382,7 @@ var _PatternMatcher = class _PatternMatcher {
346
382
  * a token and the immediately following pattern token fails, the matcher
347
383
  * resets to before the optional role and retries the failed token.
348
384
  */
349
- matchTokenSequence(tokens, patternTokens, captured) {
385
+ matchTokenSequence(tokens, patternTokens, captured, parentStopMarkers) {
350
386
  const firstPatternToken = patternTokens[0];
351
387
  const patternExpectsConjunction = firstPatternToken?.type === "literal" && (firstPatternToken.value === "and" || firstPatternToken.value === "then" || firstPatternToken.alternatives?.includes("and") || firstPatternToken.alternatives?.includes("then"));
352
388
  if (this.currentProfile?.code === "ar" && !patternExpectsConjunction) {
@@ -370,6 +406,9 @@ var _PatternMatcher = class _PatternMatcher {
370
406
  );
371
407
  if (patternToken.type === "role" && patternToken.greedy) {
372
408
  const stopMarkers = this.collectStopMarkers(patternTokens, i + 1);
409
+ if (parentStopMarkers) {
410
+ for (const m of parentStopMarkers) stopMarkers.add(m);
411
+ }
373
412
  const values = [];
374
413
  while (!tokens.isAtEnd()) {
375
414
  const nextToken = tokens.peek();
@@ -389,8 +428,58 @@ var _PatternMatcher = class _PatternMatcher {
389
428
  return false;
390
429
  }
391
430
  }
431
+ if (patternToken.type === "group") {
432
+ const siblingStopMarkers = this.collectStopMarkers(patternTokens, i + 1);
433
+ if (parentStopMarkers) {
434
+ for (const m of parentStopMarkers) siblingStopMarkers.add(m);
435
+ }
436
+ const groupMatched = this.matchGroupToken(
437
+ tokens,
438
+ patternToken,
439
+ captured,
440
+ siblingStopMarkers
441
+ );
442
+ if (groupMatched) {
443
+ prevOptionalMark = null;
444
+ prevOptionalRole = null;
445
+ continue;
446
+ }
447
+ if (this.isOptional(patternToken)) {
448
+ continue;
449
+ }
450
+ return false;
451
+ }
392
452
  const isOptionalRole = patternToken.type === "role" && patternToken.optional === true;
393
453
  const markBefore = isOptionalRole ? tokens.mark() : null;
454
+ const isRoleToken = patternToken.type === "role";
455
+ if (isRoleToken && !isOptionalRole) {
456
+ const nextPT = i + 1 < patternTokens.length ? patternTokens[i + 1] : null;
457
+ if (nextPT?.type === "literal") {
458
+ const currentToken = tokens.peek();
459
+ if (currentToken && this.getMatchType(currentToken, nextPT.value) !== "none") {
460
+ this.logger.debug(
461
+ " >> MARKER-STEAL GUARD: current token matches next literal, skipping role"
462
+ );
463
+ this.logger.debug(" >> Token match FAILED");
464
+ if (this.isOptional(patternToken)) {
465
+ continue;
466
+ }
467
+ if (prevOptionalMark && prevOptionalRole) {
468
+ this.logger.debug(" >> BACKTRACKING: undoing optional role", prevOptionalRole);
469
+ tokens.reset(prevOptionalMark);
470
+ captured.delete(prevOptionalRole);
471
+ prevOptionalMark = null;
472
+ prevOptionalRole = null;
473
+ const retryMatched = this.matchPatternToken(tokens, patternToken, captured);
474
+ this.logger.debug(" >> Backtrack retry result:", retryMatched);
475
+ if (retryMatched) {
476
+ continue;
477
+ }
478
+ }
479
+ return false;
480
+ }
481
+ }
482
+ }
394
483
  const matched = this.matchPatternToken(tokens, patternToken, captured);
395
484
  this.logger.debug(" >> Match result:", matched);
396
485
  if (matched) {
@@ -511,7 +600,7 @@ var _PatternMatcher = class _PatternMatcher {
511
600
  const possessiveValue = this.tryMatchPossessiveExpression(tokens);
512
601
  if (possessiveValue) {
513
602
  if (patternToken.expectedTypes && patternToken.expectedTypes.length > 0) {
514
- if (!patternToken.expectedTypes.includes(possessiveValue.type) && !patternToken.expectedTypes.includes("expression")) {
603
+ if (!isTypeCompatible(possessiveValue.type, patternToken.expectedTypes)) {
515
604
  return patternToken.optional || false;
516
605
  }
517
606
  }
@@ -521,7 +610,7 @@ var _PatternMatcher = class _PatternMatcher {
521
610
  const methodCallValue = this.tryMatchMethodCallExpression(tokens);
522
611
  if (methodCallValue) {
523
612
  if (patternToken.expectedTypes && patternToken.expectedTypes.length > 0) {
524
- if (!patternToken.expectedTypes.includes(methodCallValue.type) && !patternToken.expectedTypes.includes("expression")) {
613
+ if (!isTypeCompatible(methodCallValue.type, patternToken.expectedTypes)) {
525
614
  return patternToken.optional || false;
526
615
  }
527
616
  }
@@ -541,7 +630,7 @@ var _PatternMatcher = class _PatternMatcher {
541
630
  const propertyAccessValue = this.tryMatchPropertyAccessExpression(tokens);
542
631
  if (propertyAccessValue) {
543
632
  if (patternToken.expectedTypes && patternToken.expectedTypes.length > 0) {
544
- if (!patternToken.expectedTypes.includes(propertyAccessValue.type) && !patternToken.expectedTypes.includes("expression")) {
633
+ if (!isTypeCompatible(propertyAccessValue.type, patternToken.expectedTypes)) {
545
634
  return patternToken.optional || false;
546
635
  }
547
636
  }
@@ -861,10 +950,15 @@ var _PatternMatcher = class _PatternMatcher {
861
950
  * (e.g., a value like 'hello') to sit between groups without blocking later
862
951
  * marker matches.
863
952
  */
864
- matchGroupToken(tokens, patternToken, captured) {
953
+ matchGroupToken(tokens, patternToken, captured, parentStopMarkers) {
865
954
  const mark = tokens.mark();
866
955
  const capturedBefore = new Set(captured.keys());
867
- const success = this.matchTokenSequence(tokens, patternToken.tokens, captured);
956
+ const success = this.matchTokenSequence(
957
+ tokens,
958
+ patternToken.tokens,
959
+ captured,
960
+ parentStopMarkers
961
+ );
868
962
  if (success) return true;
869
963
  tokens.reset(mark);
870
964
  for (const role of captured.keys()) {
@@ -886,7 +980,12 @@ var _PatternMatcher = class _PatternMatcher {
886
980
  "- skipping intervening tokens"
887
981
  );
888
982
  for (let s = 0; s < offset; s++) tokens.advance();
889
- const retrySuccess = this.matchTokenSequence(tokens, patternToken.tokens, captured);
983
+ const retrySuccess = this.matchTokenSequence(
984
+ tokens,
985
+ patternToken.tokens,
986
+ captured,
987
+ parentStopMarkers
988
+ );
890
989
  if (retrySuccess) return true;
891
990
  tokens.reset(mark);
892
991
  for (const role of captured.keys()) {
@@ -953,7 +1052,7 @@ var _PatternMatcher = class _PatternMatcher {
953
1052
  break;
954
1053
  }
955
1054
  }
956
- break;
1055
+ if (!pt.optional) break;
957
1056
  }
958
1057
  }
959
1058
  return markers;
@@ -963,8 +1062,9 @@ var _PatternMatcher = class _PatternMatcher {
963
1062
  */
964
1063
  isStopMarker(token, stopMarkers) {
965
1064
  if (stopMarkers.size === 0) return false;
966
- const value = (token.normalized || token.value).toLowerCase();
967
- return stopMarkers.has(value);
1065
+ if (stopMarkers.has(token.value.toLowerCase())) return true;
1066
+ if (token.normalized && stopMarkers.has(token.normalized.toLowerCase())) return true;
1067
+ return false;
968
1068
  }
969
1069
  /**
970
1070
  * Convert a language token to a semantic value.
@@ -1369,7 +1469,7 @@ function addRoleWithMarker(tokens, roleSpec, profile) {
1369
1469
  if (marker) {
1370
1470
  const markerInfo = profile.roleMarkers?.[roleSpec.role];
1371
1471
  const defaultPosition = profile.wordOrder === "SOV" ? "after" : "before";
1372
- const position = markerInfo?.position ?? defaultPosition;
1472
+ const position = roleSpec.markerPosition ?? markerInfo?.position ?? defaultPosition;
1373
1473
  if (isOptional) {
1374
1474
  if (position === "before") {
1375
1475
  tokens.push({
@@ -1909,153 +2009,2674 @@ function createTokenizerContext(tokenizer) {
1909
2009
  return ctx;
1910
2010
  }
1911
2011
 
1912
- // src/api/create-dsl.ts
1913
- var DSLRegistry = class {
1914
- constructor(config) {
1915
- this.patterns = /* @__PURE__ */ new Map();
1916
- this.tokenizers = /* @__PURE__ */ new Map();
1917
- this.schemas = config.schemas;
1918
- for (const lang of config.languages) {
1919
- this.registerLanguage(lang);
2012
+ // src/ir/references.ts
2013
+ var DEFAULT_REFERENCES = /* @__PURE__ */ new Set([
2014
+ "me",
2015
+ "you",
2016
+ "it",
2017
+ "result",
2018
+ "event",
2019
+ "target",
2020
+ "body"
2021
+ ]);
2022
+ function isValidReference2(value, referenceSet = DEFAULT_REFERENCES) {
2023
+ return referenceSet.has(value);
2024
+ }
2025
+
2026
+ // src/ir/explicit-parser.ts
2027
+ var STRUCTURAL_ROLES = /* @__PURE__ */ new Set([
2028
+ "body",
2029
+ "then",
2030
+ "else",
2031
+ "condition",
2032
+ "loop-body",
2033
+ "variable",
2034
+ "catch",
2035
+ // v1.2: try/catch/finally
2036
+ "finally"
2037
+ // v1.2: try/catch/finally
2038
+ ]);
2039
+ function isNestedCommand(value) {
2040
+ const inner = value.slice(1, -1);
2041
+ let depth = 0;
2042
+ for (const ch of inner) {
2043
+ if (ch === "[") depth++;
2044
+ else if (ch === "]") depth--;
2045
+ else if (depth === 0 && (ch === " " || ch === ":")) return true;
2046
+ }
2047
+ return false;
2048
+ }
2049
+ function parseExplicit(input, options = {}) {
2050
+ const trimmed = input.trim();
2051
+ const collect = options.collectDiagnostics === true;
2052
+ const diagnostics = [];
2053
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
2054
+ throw new Error("Explicit syntax must be wrapped in brackets: [command role:value ...]");
2055
+ }
2056
+ const content = trimmed.slice(1, -1).trim();
2057
+ if (!content) {
2058
+ throw new Error("Empty explicit statement");
2059
+ }
2060
+ const tokens = tokenizeExplicit(content);
2061
+ if (tokens.length === 0) {
2062
+ throw new Error("No command specified in explicit statement");
2063
+ }
2064
+ const command = tokens[0].toLowerCase();
2065
+ const roles = /* @__PURE__ */ new Map();
2066
+ const refSet = options.referenceSet ?? DEFAULT_REFERENCES;
2067
+ const schema = options.schemaLookup?.getSchema(command);
2068
+ const validRoleNames = schema ? new Set(schema.roles.map((r) => r.role)) : null;
2069
+ for (let i = 1; i < tokens.length; i++) {
2070
+ const token = tokens[i];
2071
+ if (token.startsWith("+") || token.startsWith("~")) {
2072
+ const enabled = token.startsWith("+");
2073
+ const flagName = token.slice(1);
2074
+ if (!flagName) {
2075
+ if (collect) {
2076
+ diagnostics.push({
2077
+ severity: "error",
2078
+ code: "EMPTY_FLAG",
2079
+ message: `Empty flag name: "${token}"`,
2080
+ source: "schema"
2081
+ });
2082
+ continue;
2083
+ }
2084
+ throw new Error(`Empty flag name: "${token}"`);
2085
+ }
2086
+ if (validRoleNames && !validRoleNames.has(flagName)) {
2087
+ const roleList = [...validRoleNames].join(", ");
2088
+ if (collect) {
2089
+ diagnostics.push({
2090
+ severity: "error",
2091
+ code: "UNKNOWN_FLAG",
2092
+ message: `Unknown flag "${flagName}" for command "${command}"`,
2093
+ source: "schema",
2094
+ suggestions: [...validRoleNames].map((r) => `+${r}`)
2095
+ });
2096
+ roles.set(flagName, createFlag(flagName, enabled));
2097
+ continue;
2098
+ }
2099
+ throw new Error(
2100
+ `Unknown flag "${flagName}" for command "${command}". Valid roles: ${roleList}`
2101
+ );
2102
+ }
2103
+ roles.set(flagName, createFlag(flagName, enabled));
2104
+ continue;
2105
+ }
2106
+ const colonIndex = token.indexOf(":");
2107
+ if (colonIndex === -1) {
2108
+ if (collect) {
2109
+ diagnostics.push({
2110
+ severity: "error",
2111
+ code: "INVALID_ROLE_FORMAT",
2112
+ message: `Invalid role format: "${token}". Expected role:value or +flag`,
2113
+ source: "schema"
2114
+ });
2115
+ continue;
2116
+ }
2117
+ throw new Error(`Invalid role format: "${token}". Expected role:value or +flag`);
2118
+ }
2119
+ const roleName = token.slice(0, colonIndex);
2120
+ if (validRoleNames && !STRUCTURAL_ROLES.has(roleName) && !validRoleNames.has(roleName)) {
2121
+ const roleList = [...validRoleNames].join(", ");
2122
+ if (collect) {
2123
+ diagnostics.push({
2124
+ severity: "error",
2125
+ code: "UNKNOWN_ROLE",
2126
+ message: `Unknown role "${roleName}" for command "${command}"`,
2127
+ source: "schema",
2128
+ suggestions: [...validRoleNames]
2129
+ });
2130
+ } else {
2131
+ throw new Error(
2132
+ `Unknown role "${roleName}" for command "${command}". Valid roles: ${roleList}`
2133
+ );
2134
+ }
2135
+ }
2136
+ const role = roleName;
2137
+ const valueStr = token.slice(colonIndex + 1);
2138
+ if (STRUCTURAL_ROLES.has(roleName) && valueStr.startsWith("[") && isNestedCommand(valueStr)) {
2139
+ const nestedEnd = findMatchingBracket(token, colonIndex + 1);
2140
+ const nestedSyntax = token.slice(colonIndex + 1, nestedEnd + 1);
2141
+ roles.set(role, { type: "expression", raw: nestedSyntax });
2142
+ continue;
2143
+ }
2144
+ const value = parseExplicitValue(valueStr, refSet);
2145
+ roles.set(role, value);
2146
+ }
2147
+ if (schema && command !== "on") {
2148
+ for (const roleSpec of schema.roles) {
2149
+ if (roleSpec.required && !roles.has(roleSpec.role) && !roleSpec.default) {
2150
+ if (collect) {
2151
+ diagnostics.push({
2152
+ severity: "error",
2153
+ code: "MISSING_REQUIRED_ROLE",
2154
+ message: `Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`,
2155
+ source: "schema"
2156
+ });
2157
+ } else {
2158
+ throw new Error(
2159
+ `Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`
2160
+ );
2161
+ }
2162
+ }
1920
2163
  }
1921
2164
  }
1922
- registerLanguage(lang) {
1923
- this.tokenizers.set(lang.code, lang.tokenizer);
1924
- const patterns = [];
1925
- for (const schema of this.schemas) {
1926
- const pattern = generatePattern(schema, lang.patternProfile);
1927
- patterns.push(pattern);
2165
+ const attachDiagnostics = (node) => {
2166
+ if (diagnostics.length === 0) return node;
2167
+ return { ...node, diagnostics };
2168
+ };
2169
+ switch (command) {
2170
+ case "on": {
2171
+ const eventValue = roles.get("event");
2172
+ if (!eventValue) {
2173
+ if (collect) {
2174
+ diagnostics.push({
2175
+ severity: "error",
2176
+ code: "MISSING_EVENT_ROLE",
2177
+ message: "Event handler requires event role: [on event:click ...]",
2178
+ source: "schema"
2179
+ });
2180
+ return attachDiagnostics(
2181
+ createEventHandlerNode("on", roles, [], {
2182
+ sourceLanguage: "explicit"
2183
+ })
2184
+ );
2185
+ }
2186
+ throw new Error("Event handler requires event role: [on event:click ...]");
2187
+ }
2188
+ const body = extractStructuralBody(roles, "body", options);
2189
+ roles.delete("body");
2190
+ return attachDiagnostics(
2191
+ createEventHandlerNode("on", roles, body, {
2192
+ sourceLanguage: "explicit"
2193
+ })
2194
+ );
1928
2195
  }
1929
- this.patterns.set(lang.code, patterns);
2196
+ case "if": {
2197
+ const thenBranch = extractStructuralBody(roles, "then", options);
2198
+ const elseBranch = extractStructuralBody(roles, "else", options);
2199
+ roles.delete("then");
2200
+ roles.delete("else");
2201
+ return attachDiagnostics(
2202
+ createConditionalNode(
2203
+ command,
2204
+ roles,
2205
+ thenBranch,
2206
+ elseBranch.length > 0 ? elseBranch : void 0,
2207
+ {
2208
+ sourceLanguage: "explicit"
2209
+ }
2210
+ )
2211
+ );
2212
+ }
2213
+ case "repeat": {
2214
+ const loopBody = extractStructuralBody(roles, "loop-body", options);
2215
+ const loopVariantValue = roles.get("loop-variant");
2216
+ const variableValue = roles.get("variable");
2217
+ const indexVariableValue = roles.get("index-variable");
2218
+ roles.delete("loop-body");
2219
+ roles.delete("loop-variant");
2220
+ roles.delete("variable");
2221
+ roles.delete("index-variable");
2222
+ let variant;
2223
+ if (loopVariantValue && loopVariantValue.type === "literal" && typeof loopVariantValue.value === "string") {
2224
+ variant = loopVariantValue.value;
2225
+ } else if (roles.has("quantity")) {
2226
+ variant = "times";
2227
+ } else if (roles.has("source")) {
2228
+ variant = "for";
2229
+ } else if (roles.has("condition")) {
2230
+ variant = "while";
2231
+ } else {
2232
+ variant = "forever";
2233
+ }
2234
+ const loopVariable = variableValue?.type === "literal" && typeof variableValue.value === "string" ? variableValue.value : variableValue?.type === "expression" ? variableValue.raw : void 0;
2235
+ const indexVariable = indexVariableValue?.type === "literal" && typeof indexVariableValue.value === "string" ? indexVariableValue.value : void 0;
2236
+ return attachDiagnostics(
2237
+ createLoopNode(command, roles, variant, loopBody, loopVariable, indexVariable, {
2238
+ sourceLanguage: "explicit"
2239
+ })
2240
+ );
2241
+ }
2242
+ default:
2243
+ return attachDiagnostics(
2244
+ createCommandNode(command, roles, {
2245
+ sourceLanguage: "explicit"
2246
+ })
2247
+ );
1930
2248
  }
1931
- getPatterns(language) {
1932
- return this.patterns.get(language) || [];
2249
+ }
2250
+ function isExplicitSyntax(input) {
2251
+ const trimmed = input.trim();
2252
+ return trimmed.startsWith("[") && trimmed.endsWith("]");
2253
+ }
2254
+ var CHAIN_KEYWORDS = /* @__PURE__ */ new Set(["then", "and", "async", "sequential"]);
2255
+ function splitCompoundSegments(input) {
2256
+ const segments = [];
2257
+ let chainType = null;
2258
+ let current = "";
2259
+ let bracketDepth = 0;
2260
+ let inString = false;
2261
+ let stringChar = "";
2262
+ for (let i = 0; i < input.length; i++) {
2263
+ const char = input[i];
2264
+ if (inString) {
2265
+ current += char;
2266
+ if (char === stringChar && input[i - 1] !== "\\") {
2267
+ inString = false;
2268
+ }
2269
+ continue;
2270
+ }
2271
+ if (char === '"' || char === "'") {
2272
+ inString = true;
2273
+ stringChar = char;
2274
+ current += char;
2275
+ continue;
2276
+ }
2277
+ if (char === "[") {
2278
+ bracketDepth++;
2279
+ current += char;
2280
+ continue;
2281
+ }
2282
+ if (char === "]") {
2283
+ bracketDepth--;
2284
+ current += char;
2285
+ if (bracketDepth === 0) {
2286
+ const rest = input.slice(i + 1);
2287
+ const pipeMatch = rest.match(/^\s*\|>\s*/);
2288
+ if (pipeMatch) {
2289
+ segments.push(current.trim());
2290
+ current = "";
2291
+ chainType ?? (chainType = "pipe");
2292
+ i += pipeMatch[0].length;
2293
+ continue;
2294
+ }
2295
+ const keywordMatch = rest.match(/^\s+(then|and|async|sequential)\s+/);
2296
+ if (keywordMatch && CHAIN_KEYWORDS.has(keywordMatch[1])) {
2297
+ segments.push(current.trim());
2298
+ current = "";
2299
+ chainType ?? (chainType = keywordMatch[1]);
2300
+ i += keywordMatch[0].length;
2301
+ continue;
2302
+ }
2303
+ }
2304
+ continue;
2305
+ }
2306
+ current += char;
1933
2307
  }
1934
- getTokenizer(language) {
1935
- return this.tokenizers.get(language);
2308
+ if (current.trim()) {
2309
+ segments.push(current.trim());
1936
2310
  }
1937
- getSupportedLanguages() {
1938
- return Array.from(this.patterns.keys());
2311
+ return { segments, chainType };
2312
+ }
2313
+ function parseCompound(input, options) {
2314
+ const trimmed = input.trim();
2315
+ const { annotations, remainder } = extractAnnotations(trimmed);
2316
+ const { segments, chainType } = splitCompoundSegments(remainder);
2317
+ let node;
2318
+ if (segments.length <= 1) {
2319
+ node = parseExplicit(segments[0] || remainder, options);
2320
+ } else {
2321
+ const statements = segments.map((seg) => parseExplicit(seg, options));
2322
+ node = createCompoundNode(statements, chainType ?? "sequential");
1939
2323
  }
1940
- };
1941
- var MultilingualDSLImpl = class {
1942
- constructor(config, registry, transformer) {
1943
- this.registry = registry;
1944
- this.matcher = new PatternMatcher();
1945
- this.transformer = transformer;
1946
- if (config.codeGenerator) {
1947
- this.codeGenerator = config.codeGenerator;
2324
+ if (annotations.length > 0) {
2325
+ return { ...node, annotations };
2326
+ }
2327
+ return node;
2328
+ }
2329
+ function extractAnnotations(input) {
2330
+ const annotations = [];
2331
+ let pos = 0;
2332
+ while (pos < input.length) {
2333
+ while (pos < input.length && (input[pos] === " " || input[pos] === " ")) {
2334
+ pos++;
1948
2335
  }
2336
+ if (pos >= input.length || input[pos] !== "@") {
2337
+ break;
2338
+ }
2339
+ pos++;
2340
+ const nameStart = pos;
2341
+ while (pos < input.length && /[A-Za-z0-9\-_]/.test(input[pos])) {
2342
+ pos++;
2343
+ }
2344
+ const name = input.slice(nameStart, pos);
2345
+ if (!name) break;
2346
+ let value;
2347
+ if (pos < input.length && input[pos] === "(") {
2348
+ pos++;
2349
+ const valueStart = pos;
2350
+ if (pos < input.length && (input[pos] === '"' || input[pos] === "'")) {
2351
+ const quote = input[pos];
2352
+ pos++;
2353
+ while (pos < input.length && input[pos] !== quote) {
2354
+ if (input[pos] === "\\") pos++;
2355
+ pos++;
2356
+ }
2357
+ pos++;
2358
+ value = input.slice(valueStart + 1, pos - 1);
2359
+ } else {
2360
+ while (pos < input.length && input[pos] !== ")") {
2361
+ pos++;
2362
+ }
2363
+ value = input.slice(valueStart, pos);
2364
+ }
2365
+ if (pos < input.length && input[pos] === ")") {
2366
+ pos++;
2367
+ }
2368
+ }
2369
+ annotations.push(value !== void 0 ? { name, value } : { name });
1949
2370
  }
1950
- parse(input, language) {
1951
- const result = this.parseWithConfidence(input, language);
1952
- return result.node;
2371
+ return { annotations, remainder: input.slice(pos).trim() };
2372
+ }
2373
+ var VERSION_HEADER_RE = /^#!lse\s+(\d+\.\d+(?:\.\d+)?)\s*$/;
2374
+ function parseDocument(input, options) {
2375
+ const lines = input.split("\n");
2376
+ let lseVersion = "1.0";
2377
+ const nodes = [];
2378
+ let startLine = 0;
2379
+ for (let i = 0; i < lines.length; i++) {
2380
+ const trimmed = lines[i].trim();
2381
+ if (!trimmed) continue;
2382
+ const versionMatch = trimmed.match(VERSION_HEADER_RE);
2383
+ if (versionMatch) {
2384
+ lseVersion = versionMatch[1];
2385
+ startLine = i + 1;
2386
+ }
2387
+ break;
2388
+ }
2389
+ for (let i = startLine; i < lines.length; i++) {
2390
+ const trimmed = lines[i].trim();
2391
+ if (!trimmed) continue;
2392
+ if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
2393
+ continue;
2394
+ }
2395
+ nodes.push(parseCompound(trimmed, options));
2396
+ }
2397
+ return { lseVersion, nodes };
2398
+ }
2399
+ function isCompoundSyntax(input) {
2400
+ const { segments } = splitCompoundSegments(input.trim());
2401
+ return segments.length > 1;
2402
+ }
2403
+ function isDocumentSyntax(input) {
2404
+ const trimmed = input.trim();
2405
+ if (trimmed.includes("\n")) return true;
2406
+ if (VERSION_HEADER_RE.test(trimmed)) return true;
2407
+ if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
2408
+ return true;
1953
2409
  }
1954
- parseWithConfidence(input, language) {
1955
- const tokenizer = this.registry.getTokenizer(language);
1956
- if (!tokenizer) {
1957
- throw new Error(`No tokenizer registered for language: ${language}`);
2410
+ return false;
2411
+ }
2412
+ function extractStructuralBody(roles, roleName, options) {
2413
+ const value = roles.get(roleName);
2414
+ if (!value) return [];
2415
+ if (value.type === "expression") {
2416
+ return [parseExplicit(value.raw, options)];
2417
+ }
2418
+ return [];
2419
+ }
2420
+ function inferSelectorKind(value) {
2421
+ if (!value) return void 0;
2422
+ if (value.startsWith("#")) return "id";
2423
+ if (value.startsWith(".")) return "class";
2424
+ if (value.startsWith("[")) return "attribute";
2425
+ if (value.startsWith("<") || value.startsWith("*")) return "element";
2426
+ if (/[>+~ ]/.test(value) && value.length > 1) return "complex";
2427
+ return void 0;
2428
+ }
2429
+ function tokenizeExplicit(content) {
2430
+ const tokens = [];
2431
+ let current = "";
2432
+ let inString = false;
2433
+ let stringChar = "";
2434
+ let bracketDepth = 0;
2435
+ for (let i = 0; i < content.length; i++) {
2436
+ const char = content[i];
2437
+ if (inString) {
2438
+ current += char;
2439
+ if (char === stringChar && content[i - 1] !== "\\") {
2440
+ inString = false;
2441
+ }
2442
+ continue;
2443
+ }
2444
+ if (char === '"' || char === "'") {
2445
+ inString = true;
2446
+ stringChar = char;
2447
+ current += char;
2448
+ continue;
2449
+ }
2450
+ if (char === "[") {
2451
+ bracketDepth++;
2452
+ current += char;
2453
+ continue;
2454
+ }
2455
+ if (char === "]") {
2456
+ bracketDepth--;
2457
+ current += char;
2458
+ continue;
2459
+ }
2460
+ if (char === " " && bracketDepth === 0) {
2461
+ if (current) {
2462
+ tokens.push(current);
2463
+ current = "";
2464
+ }
2465
+ continue;
1958
2466
  }
1959
- const tokens = tokenizer.tokenize(input);
1960
- const patterns = this.registry.getPatterns(language);
1961
- const profile = {
1962
- code: language
1963
- };
1964
- for (const pattern of patterns) {
1965
- const match = this.matcher.matchPattern(tokens, pattern, profile);
1966
- if (match) {
1967
- const node = {
1968
- kind: "command",
1969
- action: pattern.command,
1970
- roles: match.captured,
1971
- metadata: {
1972
- sourceLanguage: language,
1973
- sourceText: input,
1974
- patternId: pattern.id,
1975
- confidence: match.confidence
1976
- }
1977
- };
1978
- return { node, confidence: match.confidence };
2467
+ current += char;
2468
+ }
2469
+ if (current) {
2470
+ tokens.push(current);
2471
+ }
2472
+ return tokens;
2473
+ }
2474
+ function parseExplicitValue(valueStr, referenceSet) {
2475
+ if (valueStr.startsWith("#") || valueStr.startsWith(".") || valueStr.startsWith("[") || valueStr.startsWith("@") || valueStr.startsWith("*")) {
2476
+ return createSelector(valueStr, inferSelectorKind(valueStr));
2477
+ }
2478
+ if (valueStr.startsWith('"') || valueStr.startsWith("'")) {
2479
+ const inner = valueStr.slice(1, -1);
2480
+ return createLiteral(inner, "string");
2481
+ }
2482
+ if (valueStr === "true") return createLiteral(true, "boolean");
2483
+ if (valueStr === "false") return createLiteral(false, "boolean");
2484
+ const lowerRef = valueStr.toLowerCase();
2485
+ if (isValidReference2(lowerRef, referenceSet)) {
2486
+ return createReference(lowerRef);
2487
+ }
2488
+ const numMatch = valueStr.match(/^(-?\d+(?:\.\d+)?)(ms|s|m|h)?$/);
2489
+ if (numMatch) {
2490
+ const num = parseFloat(numMatch[1]);
2491
+ const suffix = numMatch[2];
2492
+ if (suffix) {
2493
+ return createLiteral(valueStr, "duration");
2494
+ }
2495
+ return createLiteral(num, "number");
2496
+ }
2497
+ return createLiteral(valueStr);
2498
+ }
2499
+ function findMatchingBracket(str, start) {
2500
+ let depth = 0;
2501
+ for (let i = start; i < str.length; i++) {
2502
+ if (str[i] === "[") depth++;
2503
+ else if (str[i] === "]") {
2504
+ depth--;
2505
+ if (depth === 0) return i;
2506
+ }
2507
+ }
2508
+ return str.length - 1;
2509
+ }
2510
+
2511
+ // src/ir/explicit-renderer.ts
2512
+ function renderExplicit(node) {
2513
+ let result;
2514
+ if (node.kind === "compound") {
2515
+ const compoundNode = node;
2516
+ const renderedStatements = compoundNode.statements.map((stmt) => renderExplicit(stmt));
2517
+ result = renderedStatements.join(` ${compoundNode.chainType} `);
2518
+ } else {
2519
+ result = renderBracketCommand(node);
2520
+ }
2521
+ if (node.annotations && node.annotations.length > 0) {
2522
+ const annParts = node.annotations.map(
2523
+ (ann) => ann.value !== void 0 ? `@${ann.name}(${ann.value})` : `@${ann.name}`
2524
+ );
2525
+ return annParts.join(" ") + " " + result;
2526
+ }
2527
+ return result;
2528
+ }
2529
+ function renderDocument(envelope) {
2530
+ const lines = [];
2531
+ if (envelope.lseVersion && envelope.lseVersion !== "1.0") {
2532
+ lines.push(`#!lse ${envelope.lseVersion}`);
2533
+ }
2534
+ for (const node of envelope.nodes) {
2535
+ lines.push(renderExplicit(node));
2536
+ }
2537
+ return lines.join("\n");
2538
+ }
2539
+ function renderBracketCommand(node) {
2540
+ const parts = [node.action];
2541
+ for (const [role, value] of node.roles) {
2542
+ if (value.type === "flag") {
2543
+ parts.push(value.enabled ? `+${value.name}` : `~${value.name}`);
2544
+ } else {
2545
+ parts.push(`${role}:${valueToString(value)}`);
2546
+ }
2547
+ }
2548
+ if (node.kind === "event-handler") {
2549
+ const eventNode = node;
2550
+ if (eventNode.body && eventNode.body.length > 0) {
2551
+ const bodyParts = eventNode.body.map((n) => renderExplicit(n));
2552
+ parts.push(`body:${bodyParts.join(" ")}`);
2553
+ }
2554
+ }
2555
+ if (node.kind === "conditional") {
2556
+ const condNode = node;
2557
+ if (condNode.thenBranch && condNode.thenBranch.length > 0) {
2558
+ const thenParts = condNode.thenBranch.map((n) => renderExplicit(n));
2559
+ parts.push(`then:${thenParts.join(" ")}`);
2560
+ }
2561
+ if (condNode.elseBranch && condNode.elseBranch.length > 0) {
2562
+ const elseParts = condNode.elseBranch.map((n) => renderExplicit(n));
2563
+ parts.push(`else:${elseParts.join(" ")}`);
2564
+ }
2565
+ }
2566
+ if (node.kind === "loop") {
2567
+ const loopNode = node;
2568
+ if (loopNode.loopVariant) {
2569
+ parts.push(`loop-variant:${loopNode.loopVariant}`);
2570
+ }
2571
+ if (loopNode.loopVariable) {
2572
+ parts.push(`variable:${loopNode.loopVariable}`);
2573
+ }
2574
+ if (loopNode.indexVariable) {
2575
+ parts.push(`index-variable:${loopNode.indexVariable}`);
2576
+ }
2577
+ if (loopNode.body && loopNode.body.length > 0) {
2578
+ const bodyParts = loopNode.body.map((n) => renderExplicit(n));
2579
+ parts.push(`loop-body:${bodyParts.join(" ")}`);
2580
+ }
2581
+ }
2582
+ if (node.kind === "command") {
2583
+ const cmd = node;
2584
+ if (cmd.body && cmd.body.length > 0) {
2585
+ const bodyParts = cmd.body.map((n) => renderExplicit(n));
2586
+ parts.push(`body:${bodyParts.join(" ")}`);
2587
+ }
2588
+ if (cmd.catchBranch && cmd.catchBranch.length > 0) {
2589
+ const catchParts = cmd.catchBranch.map((n) => renderExplicit(n));
2590
+ parts.push(`catch:${catchParts.join(" ")}`);
2591
+ }
2592
+ if (cmd.finallyBranch && cmd.finallyBranch.length > 0) {
2593
+ const finallyParts = cmd.finallyBranch.map((n) => renderExplicit(n));
2594
+ parts.push(`finally:${finallyParts.join(" ")}`);
2595
+ }
2596
+ if (cmd.asyncVariant) {
2597
+ parts.push(`async-variant:${cmd.asyncVariant}`);
2598
+ }
2599
+ if (cmd.asyncBody && cmd.asyncBody.length > 0) {
2600
+ const asyncParts = cmd.asyncBody.map((n) => renderExplicit(n));
2601
+ parts.push(`async-body:${asyncParts.join(" ")}`);
2602
+ }
2603
+ }
2604
+ return `[${parts.join(" ")}]`;
2605
+ }
2606
+ function valueToString(value) {
2607
+ switch (value.type) {
2608
+ case "literal":
2609
+ if (typeof value.value === "string") {
2610
+ if (value.dataType === "string" || /\s/.test(value.value)) {
2611
+ return `"${value.value}"`;
2612
+ }
2613
+ return value.value;
2614
+ }
2615
+ return String(value.value);
2616
+ case "selector":
2617
+ return value.value;
2618
+ case "reference":
2619
+ return value.value;
2620
+ case "property-path":
2621
+ return `${valueToString(value.object)}'s ${value.property}`;
2622
+ case "expression":
2623
+ return value.raw;
2624
+ case "flag":
2625
+ return value.name;
2626
+ }
2627
+ }
2628
+
2629
+ // src/ir/json-schema.ts
2630
+ var VALID_VALUE_TYPES = /* @__PURE__ */ new Set([
2631
+ "selector",
2632
+ "literal",
2633
+ "reference",
2634
+ "expression",
2635
+ "property-path",
2636
+ "flag"
2637
+ ]);
2638
+ function validateSemanticJSON(input) {
2639
+ const diagnostics = [];
2640
+ if (!input.action || typeof input.action !== "string") {
2641
+ diagnostics.push({
2642
+ severity: "error",
2643
+ code: "INVALID_ACTION",
2644
+ message: 'Field "action" is required and must be a string.',
2645
+ suggestion: 'Provide a command name like "toggle", "add", "set", etc.'
2646
+ });
2647
+ return diagnostics;
2648
+ }
2649
+ if (input.roles && typeof input.roles === "object") {
2650
+ for (const [role, value] of Object.entries(input.roles)) {
2651
+ if (!value || typeof value !== "object") {
2652
+ diagnostics.push({
2653
+ severity: "error",
2654
+ code: "INVALID_ROLE_VALUE",
2655
+ message: `Role "${role}" must be an object with "type" and "value" fields.`,
2656
+ suggestion: 'Use: { "type": "selector", "value": ".active" }'
2657
+ });
2658
+ continue;
2659
+ }
2660
+ const v = value;
2661
+ if (!VALID_VALUE_TYPES.has(v.type)) {
2662
+ diagnostics.push({
2663
+ severity: "error",
2664
+ code: "INVALID_VALUE_TYPE",
2665
+ message: `Role "${role}" has invalid type "${v.type}".`,
2666
+ suggestion: "Valid types: selector, literal, reference, expression, property-path."
2667
+ });
2668
+ }
2669
+ if (v.value === void 0 || v.value === null) {
2670
+ diagnostics.push({
2671
+ severity: "error",
2672
+ code: "MISSING_VALUE",
2673
+ message: `Role "${role}" is missing the "value" field.`
2674
+ });
1979
2675
  }
1980
2676
  }
1981
- throw new Error(`No pattern matched for input: ${input}`);
1982
2677
  }
1983
- validate(input, language) {
1984
- try {
1985
- const result = this.parseWithConfidence(input, language);
1986
- return {
1987
- valid: true,
1988
- node: result.node
1989
- };
1990
- } catch (error) {
1991
- return {
1992
- valid: false,
1993
- errors: [error instanceof Error ? error.message : String(error)]
1994
- };
2678
+ if (input.trigger) {
2679
+ if (!input.trigger.event || typeof input.trigger.event !== "string") {
2680
+ diagnostics.push({
2681
+ severity: "error",
2682
+ code: "INVALID_TRIGGER",
2683
+ message: 'Trigger "event" is required and must be a string.',
2684
+ suggestion: 'Use an event name like "click", "mouseover", "keydown".'
2685
+ });
1995
2686
  }
1996
2687
  }
1997
- translate(input, fromLanguage, toLanguage) {
1998
- return this.transformer.transform(input, fromLanguage, toLanguage);
2688
+ return diagnostics;
2689
+ }
2690
+ function jsonToSemanticNode(input) {
2691
+ const roles = /* @__PURE__ */ new Map();
2692
+ if (input.roles) {
2693
+ for (const [role, value] of Object.entries(input.roles)) {
2694
+ roles.set(role, convertJSONValue(value));
2695
+ }
2696
+ }
2697
+ if (input.trigger) {
2698
+ roles.set("event", createLiteral(input.trigger.event, "string"));
2699
+ const bodyRoles = new Map(roles);
2700
+ bodyRoles.delete("event");
2701
+ const bodyNode = createCommandNode(input.action, bodyRoles);
2702
+ return createEventHandlerNode(
2703
+ "on",
2704
+ roles,
2705
+ [bodyNode],
2706
+ { sourceLanguage: "json" },
2707
+ input.trigger.modifiers ?? {}
2708
+ );
1999
2709
  }
2000
- compile(input, language) {
2710
+ return createCommandNode(input.action, roles, {
2711
+ sourceLanguage: "json"
2712
+ });
2713
+ }
2714
+ function semanticNodeToJSON(node) {
2715
+ if (node.kind === "compound") {
2716
+ const compound = node;
2717
+ if (compound.statements.length > 0) {
2718
+ return semanticNodeToJSON(compound.statements[0]);
2719
+ }
2720
+ return { action: "compound", roles: {} };
2721
+ }
2722
+ if (node.kind === "event-handler") {
2723
+ const eventNode = node;
2724
+ const bodyAction = eventNode.body?.[0]?.action ?? node.action;
2725
+ const roles2 = {};
2726
+ if (eventNode.body?.[0]) {
2727
+ for (const [role, value] of eventNode.body[0].roles) {
2728
+ roles2[role] = semanticValueToJSON(value);
2729
+ }
2730
+ }
2731
+ const eventValue = node.roles.get("event");
2732
+ const eventName = eventValue ? "value" in eventValue ? String(eventValue.value) : "raw" in eventValue ? eventValue.raw : "unknown" : "unknown";
2733
+ const result = {
2734
+ action: bodyAction === "on" ? eventNode.body?.[0]?.action ?? "on" : bodyAction,
2735
+ roles: roles2,
2736
+ trigger: {
2737
+ event: eventName
2738
+ }
2739
+ };
2740
+ if (eventNode.eventModifiers && Object.keys(eventNode.eventModifiers).length > 0) {
2741
+ result.trigger.modifiers = eventNode.eventModifiers;
2742
+ }
2743
+ return result;
2744
+ }
2745
+ const roles = {};
2746
+ for (const [role, value] of node.roles) {
2747
+ roles[role] = semanticValueToJSON(value);
2748
+ }
2749
+ return { action: node.action, roles };
2750
+ }
2751
+ function convertJSONValue(value) {
2752
+ switch (value.type) {
2753
+ case "selector":
2754
+ return createSelector(String(value.value), detectSelectorKind(String(value.value)));
2755
+ case "literal":
2756
+ return createLiteral(
2757
+ value.value,
2758
+ typeof value.value === "number" ? "number" : typeof value.value === "boolean" ? "boolean" : "string"
2759
+ );
2760
+ case "reference":
2761
+ return createReference(String(value.value));
2762
+ case "expression":
2763
+ return createExpression(String(value.value));
2764
+ case "property-path":
2765
+ return createExpression(String(value.value));
2766
+ case "flag":
2767
+ return createFlag(String(value.value), true);
2768
+ default:
2769
+ return createLiteral(String(value.value), "string");
2770
+ }
2771
+ }
2772
+ function semanticValueToJSON(value) {
2773
+ switch (value.type) {
2774
+ case "selector":
2775
+ return { type: "selector", value: value.value };
2776
+ case "literal":
2777
+ return { type: "literal", value: value.value };
2778
+ case "reference":
2779
+ return { type: "reference", value: value.value };
2780
+ case "expression":
2781
+ return { type: "expression", value: value.raw };
2782
+ case "property-path":
2783
+ return {
2784
+ type: "property-path",
2785
+ value: `${semanticValueToJSON(value.object).value}.${value.property}`
2786
+ };
2787
+ case "flag":
2788
+ return { type: "flag", value: value.enabled };
2789
+ }
2790
+ }
2791
+ function detectSelectorKind(selector) {
2792
+ if (selector.startsWith("#")) return "id";
2793
+ if (selector.startsWith(".")) return "class";
2794
+ if (selector.startsWith("[")) return "attribute";
2795
+ return "complex";
2796
+ }
2797
+
2798
+ // src/ir/protocol-json.ts
2799
+ function toProtocolJSON(node) {
2800
+ const roles = rolesToProtocol(node.roles);
2801
+ let result;
2802
+ switch (node.kind) {
2803
+ case "command": {
2804
+ const cmd = node;
2805
+ result = { kind: "command", action: node.action, roles };
2806
+ if (cmd.body && cmd.body.length > 0) {
2807
+ result.body = cmd.body.map(toProtocolJSON);
2808
+ }
2809
+ if (cmd.catchBranch && cmd.catchBranch.length > 0) {
2810
+ result.catchBranch = cmd.catchBranch.map(toProtocolJSON);
2811
+ }
2812
+ if (cmd.finallyBranch && cmd.finallyBranch.length > 0) {
2813
+ result.finallyBranch = cmd.finallyBranch.map(toProtocolJSON);
2814
+ }
2815
+ if (cmd.asyncVariant) {
2816
+ result.asyncVariant = cmd.asyncVariant;
2817
+ }
2818
+ if (cmd.asyncBody && cmd.asyncBody.length > 0) {
2819
+ result.asyncBody = cmd.asyncBody.map(toProtocolJSON);
2820
+ }
2821
+ if (cmd.arms && cmd.arms.length > 0) {
2822
+ result.arms = cmd.arms.map((arm) => ({
2823
+ pattern: valueToProtocol(arm.pattern),
2824
+ body: arm.body.map(toProtocolJSON)
2825
+ }));
2826
+ }
2827
+ if (cmd.defaultArm && cmd.defaultArm.length > 0) {
2828
+ result.defaultArm = cmd.defaultArm.map(toProtocolJSON);
2829
+ }
2830
+ break;
2831
+ }
2832
+ case "event-handler": {
2833
+ const eh = node;
2834
+ result = {
2835
+ kind: "event-handler",
2836
+ action: node.action,
2837
+ roles,
2838
+ body: eh.body.map(toProtocolJSON)
2839
+ };
2840
+ break;
2841
+ }
2842
+ case "compound": {
2843
+ const c = node;
2844
+ result = {
2845
+ kind: "compound",
2846
+ action: "compound",
2847
+ statements: c.statements.map(toProtocolJSON),
2848
+ chainType: c.chainType
2849
+ };
2850
+ break;
2851
+ }
2852
+ case "conditional": {
2853
+ const cond = node;
2854
+ result = { kind: "command", action: node.action, roles };
2855
+ result.thenBranch = cond.thenBranch.map(toProtocolJSON);
2856
+ if (cond.elseBranch && cond.elseBranch.length > 0) {
2857
+ result.elseBranch = cond.elseBranch.map(toProtocolJSON);
2858
+ }
2859
+ break;
2860
+ }
2861
+ case "loop": {
2862
+ const loop = node;
2863
+ result = { kind: "command", action: node.action, roles };
2864
+ result.loopVariant = loop.loopVariant;
2865
+ result.loopBody = loop.body.map(toProtocolJSON);
2866
+ if (loop.loopVariable) result.loopVariable = loop.loopVariable;
2867
+ if (loop.indexVariable) result.indexVariable = loop.indexVariable;
2868
+ break;
2869
+ }
2870
+ }
2871
+ if (node.annotations && node.annotations.length > 0) {
2872
+ result.annotations = node.annotations.map(
2873
+ (a) => a.value !== void 0 ? { name: a.name, value: a.value } : { name: a.name }
2874
+ );
2875
+ }
2876
+ if (node.diagnostics && node.diagnostics.length > 0) {
2877
+ result.diagnostics = node.diagnostics.map((d) => {
2878
+ const json = {
2879
+ level: d.severity,
2880
+ message: d.message
2881
+ };
2882
+ if (d.code) json.code = d.code;
2883
+ if (d.source) json.source = d.source;
2884
+ if (d.suggestions && d.suggestions.length > 0) json.suggestions = [...d.suggestions];
2885
+ return json;
2886
+ });
2887
+ }
2888
+ return result;
2889
+ }
2890
+ function rolesToProtocol(roles) {
2891
+ const result = {};
2892
+ for (const [role, value] of roles) {
2893
+ result[role] = valueToProtocol(value);
2894
+ }
2895
+ return result;
2896
+ }
2897
+ function valueToProtocol(value) {
2898
+ switch (value.type) {
2899
+ case "selector": {
2900
+ const PROTOCOL_SELECTOR_KINDS = /* @__PURE__ */ new Set([
2901
+ "id",
2902
+ "class",
2903
+ "attribute",
2904
+ "element",
2905
+ "complex"
2906
+ ]);
2907
+ const sk = "selectorKind" in value ? value.selectorKind : void 0;
2908
+ const sv = { type: "selector", value: value.value };
2909
+ if (sk && PROTOCOL_SELECTOR_KINDS.has(sk)) {
2910
+ sv.selectorKind = sk;
2911
+ }
2912
+ return sv;
2913
+ }
2914
+ case "literal":
2915
+ return value.dataType ? { type: "literal", value: value.value, dataType: value.dataType } : { type: "literal", value: value.value };
2916
+ case "reference":
2917
+ return { type: "reference", value: value.value };
2918
+ case "expression":
2919
+ return { type: "expression", raw: value.raw };
2920
+ case "property-path":
2921
+ return { type: "expression", raw: extractValue(value) };
2922
+ case "flag":
2923
+ return { type: "flag", name: value.name, enabled: value.enabled };
2924
+ }
2925
+ }
2926
+ function fromProtocolJSON(json) {
2927
+ const roles = new Map(
2928
+ Object.entries(json.roles ?? {}).map(([role, val]) => [role, valueFromProtocol(val)])
2929
+ );
2930
+ const annotations = json.annotations?.map(
2931
+ (a) => a.value !== void 0 ? { name: a.name, value: a.value } : { name: a.name }
2932
+ );
2933
+ const diagnostics = json.diagnostics?.map((d) => ({
2934
+ severity: d.level,
2935
+ message: d.message,
2936
+ ...d.code ? { code: d.code } : {},
2937
+ ...d.source ? { source: d.source } : {},
2938
+ ...d.suggestions && d.suggestions.length > 0 ? { suggestions: d.suggestions } : {}
2939
+ }));
2940
+ if (json.trigger) {
2941
+ const eventName = json.trigger.event;
2942
+ roles.set("event", createLiteral(eventName, "string"));
2943
+ const bodyRoles = new Map(roles);
2944
+ bodyRoles.delete("event");
2945
+ const bodyNode = createCommandNode(json.action, bodyRoles);
2946
+ const node2 = createEventHandlerNode(
2947
+ "on",
2948
+ roles,
2949
+ [bodyNode],
2950
+ { sourceLanguage: "json" },
2951
+ json.trigger.modifiers ?? {}
2952
+ );
2953
+ return applyV12Metadata(node2, annotations, diagnostics);
2954
+ }
2955
+ const kind = json.kind ?? "command";
2956
+ if (kind === "event-handler") {
2957
+ const body = (json.body ?? []).map(fromProtocolJSON);
2958
+ const node2 = createEventHandlerNode(json.action, roles, body);
2959
+ return applyV12Metadata(node2, annotations, diagnostics);
2960
+ }
2961
+ if (kind === "compound") {
2962
+ const statements = (json.statements ?? []).map(fromProtocolJSON);
2963
+ const node2 = createCompoundNode(
2964
+ statements,
2965
+ json.chainType ?? "sequential"
2966
+ );
2967
+ return applyV12Metadata(node2, annotations, diagnostics);
2968
+ }
2969
+ if (json.thenBranch && json.thenBranch.length > 0) {
2970
+ const thenBranch = json.thenBranch.map(fromProtocolJSON);
2971
+ const elseBranch = json.elseBranch ? json.elseBranch.map(fromProtocolJSON) : void 0;
2972
+ const node2 = createConditionalNode(json.action, roles, thenBranch, elseBranch);
2973
+ return applyV12Metadata(node2, annotations, diagnostics);
2974
+ }
2975
+ if (json.loopVariant) {
2976
+ const loopBody = (json.loopBody ?? []).map(fromProtocolJSON);
2977
+ const node2 = createLoopNode(
2978
+ json.action,
2979
+ roles,
2980
+ json.loopVariant,
2981
+ loopBody,
2982
+ json.loopVariable,
2983
+ json.indexVariable
2984
+ );
2985
+ return applyV12Metadata(node2, annotations, diagnostics);
2986
+ }
2987
+ if (json.catchBranch || json.finallyBranch) {
2988
+ const body = (json.body ?? []).map(fromProtocolJSON);
2989
+ const catchBranch = json.catchBranch ? json.catchBranch.map(fromProtocolJSON) : void 0;
2990
+ const finallyBranch = json.finallyBranch ? json.finallyBranch.map(fromProtocolJSON) : void 0;
2991
+ const node2 = createTryNode(body, catchBranch, finallyBranch);
2992
+ return applyV12Metadata(node2, annotations, diagnostics);
2993
+ }
2994
+ if (json.asyncVariant) {
2995
+ const asyncBody = (json.asyncBody ?? []).map(fromProtocolJSON);
2996
+ const node2 = createAsyncNode(json.asyncVariant, asyncBody);
2997
+ return applyV12Metadata(node2, annotations, diagnostics);
2998
+ }
2999
+ if (json.arms && json.arms.length > 0) {
3000
+ const arms = json.arms.map((arm) => ({
3001
+ pattern: valueFromProtocol(arm.pattern),
3002
+ body: arm.body.map(fromProtocolJSON)
3003
+ }));
3004
+ const defaultArm = json.defaultArm ? json.defaultArm.map(fromProtocolJSON) : void 0;
3005
+ const node2 = createMatchNode(roles, arms, defaultArm);
3006
+ return applyV12Metadata(node2, annotations, diagnostics);
3007
+ }
3008
+ if (json.body && json.body.length > 0 && kind === "command") {
3009
+ const body = json.body.map(fromProtocolJSON);
3010
+ const node2 = createTryNode(body);
3011
+ return applyV12Metadata(node2, annotations, diagnostics);
3012
+ }
3013
+ const node = createCommandNode(json.action, roles);
3014
+ return applyV12Metadata(node, annotations, diagnostics);
3015
+ }
3016
+ function applyV12Metadata(node, annotations, diagnostics) {
3017
+ if ((!annotations || annotations.length === 0) && (!diagnostics || diagnostics.length === 0)) {
3018
+ return node;
3019
+ }
3020
+ return {
3021
+ ...node,
3022
+ ...annotations && annotations.length > 0 ? { annotations } : {},
3023
+ ...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
3024
+ };
3025
+ }
3026
+ function valueFromProtocol(value) {
3027
+ switch (value.type) {
3028
+ case "selector":
3029
+ return createSelector(String(value.value ?? ""), value.selectorKind);
3030
+ case "literal":
3031
+ return createLiteral(
3032
+ value.value !== void 0 ? value.value : "",
3033
+ value.dataType
3034
+ );
3035
+ case "reference":
3036
+ return createReference(String(value.value ?? ""));
3037
+ case "expression":
3038
+ return createExpression(value.raw ?? String(value.value ?? ""));
3039
+ case "flag":
3040
+ return createFlag(
3041
+ value.name ?? String(value.value ?? ""),
3042
+ value.enabled ?? (typeof value.value === "boolean" ? value.value : true)
3043
+ );
3044
+ case "property-path":
3045
+ return createExpression(String(value.value ?? value.raw ?? ""));
3046
+ }
3047
+ }
3048
+ function toEnvelopeJSON(envelope) {
3049
+ const result = {
3050
+ lseVersion: envelope.lseVersion,
3051
+ nodes: envelope.nodes.map(toProtocolJSON)
3052
+ };
3053
+ if (envelope.features && envelope.features.length > 0) {
3054
+ result.features = [...envelope.features];
3055
+ }
3056
+ return result;
3057
+ }
3058
+ function fromEnvelopeJSON(json) {
3059
+ return {
3060
+ lseVersion: json.lseVersion,
3061
+ ...json.features && json.features.length > 0 ? { features: json.features } : {},
3062
+ nodes: json.nodes.map(fromProtocolJSON)
3063
+ };
3064
+ }
3065
+ function isEnvelope(json) {
3066
+ return typeof json === "object" && json !== null && "lseVersion" in json && "nodes" in json && Array.isArray(json.nodes);
3067
+ }
3068
+ var VALID_KINDS = /* @__PURE__ */ new Set(["command", "event-handler", "compound"]);
3069
+ var VALID_VALUE_TYPES2 = /* @__PURE__ */ new Set([
3070
+ "selector",
3071
+ "literal",
3072
+ "reference",
3073
+ "expression",
3074
+ "property-path",
3075
+ "flag"
3076
+ ]);
3077
+ var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set(["then", "and", "async", "sequential", "pipe"]);
3078
+ var VALID_ASYNC_VARIANTS = /* @__PURE__ */ new Set(["all", "race"]);
3079
+ var VALID_DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set(["error", "warning", "info"]);
3080
+ function validateProtocolJSON(json) {
3081
+ const diagnostics = [];
3082
+ if (typeof json !== "object" || json === null) {
3083
+ return [{ severity: "error", code: "INVALID_ROOT", message: "Root must be a JSON object" }];
3084
+ }
3085
+ const node = json;
3086
+ const kind = "kind" in node ? String(node.kind) : "command";
3087
+ if ("kind" in node && !VALID_KINDS.has(kind)) {
3088
+ diagnostics.push({
3089
+ severity: "error",
3090
+ code: "INVALID_KIND",
3091
+ message: `Invalid kind "${node.kind}". Must be one of: command, event-handler, compound`
3092
+ });
3093
+ }
3094
+ if (!("action" in node)) {
3095
+ diagnostics.push({
3096
+ severity: "error",
3097
+ code: "MISSING_ACTION",
3098
+ message: "Missing required field: action"
3099
+ });
3100
+ } else if (typeof node.action !== "string" || node.action.length === 0) {
3101
+ diagnostics.push({
3102
+ severity: "error",
3103
+ code: "INVALID_ACTION",
3104
+ message: "action must be a non-empty string"
3105
+ });
3106
+ }
3107
+ if (!("roles" in node) && kind !== "compound") {
3108
+ diagnostics.push({
3109
+ severity: "error",
3110
+ code: "MISSING_ROLES",
3111
+ message: "Missing required field: roles"
3112
+ });
3113
+ } else if ("roles" in node && (typeof node.roles !== "object" || node.roles === null || Array.isArray(node.roles))) {
3114
+ diagnostics.push({
3115
+ severity: "error",
3116
+ code: "INVALID_ROLES",
3117
+ message: "roles must be a plain object"
3118
+ });
3119
+ } else if ("roles" in node && node.roles) {
3120
+ for (const [role, value] of Object.entries(node.roles)) {
3121
+ if (typeof value !== "object" || value === null) {
3122
+ diagnostics.push({
3123
+ severity: "error",
3124
+ code: "INVALID_ROLE_VALUE",
3125
+ message: `Role "${role}" value must be an object`
3126
+ });
3127
+ continue;
3128
+ }
3129
+ const v = value;
3130
+ if (!("type" in v) || !VALID_VALUE_TYPES2.has(String(v.type))) {
3131
+ diagnostics.push({
3132
+ severity: "error",
3133
+ code: "INVALID_VALUE_TYPE",
3134
+ message: `Role "${role}" has invalid type "${v.type}"`
3135
+ });
3136
+ }
3137
+ if (v.type === "flag") {
3138
+ const hasName = typeof v.name === "string";
3139
+ const hasEnabled = typeof v.enabled === "boolean";
3140
+ const hasValue = "value" in v;
3141
+ if (!hasName && !hasValue) {
3142
+ diagnostics.push({
3143
+ severity: "error",
3144
+ code: "MISSING_FLAG_NAME",
3145
+ message: `Flag role "${role}" missing required field: name (or value)`
3146
+ });
3147
+ }
3148
+ if (!hasEnabled && !hasValue) {
3149
+ diagnostics.push({
3150
+ severity: "error",
3151
+ code: "MISSING_FLAG_ENABLED",
3152
+ message: `Flag role "${role}" missing required field: enabled (or value)`
3153
+ });
3154
+ }
3155
+ }
3156
+ if (v.type === "expression" && typeof v.raw !== "string" && !("value" in v)) {
3157
+ diagnostics.push({
3158
+ severity: "error",
3159
+ code: "MISSING_EXPRESSION_RAW",
3160
+ message: `Expression role "${role}" missing required field: raw (or value)`
3161
+ });
3162
+ }
3163
+ }
3164
+ }
3165
+ if ("trigger" in node && node.trigger) {
3166
+ const trigger = node.trigger;
3167
+ if (typeof trigger !== "object" || trigger === null) {
3168
+ diagnostics.push({
3169
+ severity: "error",
3170
+ code: "INVALID_TRIGGER",
3171
+ message: "trigger must be an object"
3172
+ });
3173
+ } else if (!trigger.event || typeof trigger.event !== "string") {
3174
+ diagnostics.push({
3175
+ severity: "error",
3176
+ code: "INVALID_TRIGGER",
3177
+ message: "trigger.event is required and must be a non-empty string"
3178
+ });
3179
+ }
3180
+ }
3181
+ if (kind === "event-handler" && !("trigger" in node)) {
3182
+ if (!("body" in node) || !Array.isArray(node.body)) {
3183
+ diagnostics.push({
3184
+ severity: "error",
3185
+ code: "MISSING_BODY",
3186
+ message: "event-handler node requires a body array"
3187
+ });
3188
+ }
3189
+ }
3190
+ if (kind === "compound") {
3191
+ if (!("statements" in node) || !Array.isArray(node.statements)) {
3192
+ diagnostics.push({
3193
+ severity: "error",
3194
+ code: "MISSING_STATEMENTS",
3195
+ message: "compound node requires a statements array"
3196
+ });
3197
+ }
3198
+ if ("chainType" in node && !VALID_CHAIN_TYPES.has(String(node.chainType))) {
3199
+ diagnostics.push({
3200
+ severity: "error",
3201
+ code: "INVALID_CHAIN_TYPE",
3202
+ message: `Invalid chainType "${node.chainType}". Must be one of: then, and, async, sequential, pipe`
3203
+ });
3204
+ }
3205
+ }
3206
+ if ("diagnostics" in node) {
3207
+ if (!Array.isArray(node.diagnostics)) {
3208
+ diagnostics.push({
3209
+ severity: "error",
3210
+ code: "INVALID_DIAGNOSTICS",
3211
+ message: "diagnostics must be an array"
3212
+ });
3213
+ } else {
3214
+ for (let i = 0; i < node.diagnostics.length; i++) {
3215
+ const d = node.diagnostics[i];
3216
+ if (!d || typeof d !== "object") {
3217
+ diagnostics.push({
3218
+ severity: "error",
3219
+ code: "INVALID_DIAGNOSTIC_ENTRY",
3220
+ message: `diagnostics[${i}] must be an object`
3221
+ });
3222
+ continue;
3223
+ }
3224
+ if (!VALID_DIAGNOSTIC_LEVELS.has(String(d.level))) {
3225
+ diagnostics.push({
3226
+ severity: "error",
3227
+ code: "INVALID_DIAGNOSTIC_LEVEL",
3228
+ message: `diagnostics[${i}].level must be "error", "warning", or "info"`
3229
+ });
3230
+ }
3231
+ if (typeof d.message !== "string") {
3232
+ diagnostics.push({
3233
+ severity: "error",
3234
+ code: "MISSING_DIAGNOSTIC_MESSAGE",
3235
+ message: `diagnostics[${i}] missing required field: message`
3236
+ });
3237
+ }
3238
+ if ("code" in d && typeof d.code !== "string") {
3239
+ diagnostics.push({
3240
+ severity: "warning",
3241
+ code: "INVALID_DIAGNOSTIC_CODE",
3242
+ message: `diagnostics[${i}].code must be a string if present`
3243
+ });
3244
+ }
3245
+ }
3246
+ }
3247
+ }
3248
+ if ("annotations" in node) {
3249
+ if (!Array.isArray(node.annotations)) {
3250
+ diagnostics.push({
3251
+ severity: "error",
3252
+ code: "INVALID_ANNOTATIONS",
3253
+ message: "annotations must be an array"
3254
+ });
3255
+ } else {
3256
+ for (let i = 0; i < node.annotations.length; i++) {
3257
+ const a = node.annotations[i];
3258
+ if (!a || typeof a !== "object") {
3259
+ diagnostics.push({
3260
+ severity: "error",
3261
+ code: "INVALID_ANNOTATION_ENTRY",
3262
+ message: `annotations[${i}] must be an object`
3263
+ });
3264
+ continue;
3265
+ }
3266
+ if (typeof a.name !== "string" || a.name.length === 0) {
3267
+ diagnostics.push({
3268
+ severity: "error",
3269
+ code: "MISSING_ANNOTATION_NAME",
3270
+ message: `annotations[${i}] missing required field: name`
3271
+ });
3272
+ }
3273
+ }
3274
+ }
3275
+ }
3276
+ if ("asyncVariant" in node && !VALID_ASYNC_VARIANTS.has(String(node.asyncVariant))) {
3277
+ diagnostics.push({
3278
+ severity: "error",
3279
+ code: "INVALID_ASYNC_VARIANT",
3280
+ message: `Invalid asyncVariant "${node.asyncVariant}". Must be "all" or "race"`
3281
+ });
3282
+ }
3283
+ if ("arms" in node) {
3284
+ if (!Array.isArray(node.arms)) {
3285
+ diagnostics.push({
3286
+ severity: "error",
3287
+ code: "INVALID_ARMS",
3288
+ message: "arms must be an array"
3289
+ });
3290
+ } else {
3291
+ for (let i = 0; i < node.arms.length; i++) {
3292
+ const arm = node.arms[i];
3293
+ if (!arm || typeof arm !== "object") {
3294
+ diagnostics.push({
3295
+ severity: "error",
3296
+ code: "INVALID_ARM_ENTRY",
3297
+ message: `arms[${i}] must be an object`
3298
+ });
3299
+ continue;
3300
+ }
3301
+ if (!arm.pattern || typeof arm.pattern !== "object") {
3302
+ diagnostics.push({
3303
+ severity: "error",
3304
+ code: "MISSING_ARM_PATTERN",
3305
+ message: `arms[${i}] missing required field: pattern`
3306
+ });
3307
+ }
3308
+ if (!Array.isArray(arm.body)) {
3309
+ diagnostics.push({
3310
+ severity: "error",
3311
+ code: "MISSING_ARM_BODY",
3312
+ message: `arms[${i}] missing required field: body (array)`
3313
+ });
3314
+ }
3315
+ }
3316
+ }
3317
+ }
3318
+ return diagnostics;
3319
+ }
3320
+
3321
+ // src/ir/from-interchange.ts
3322
+ function fromInterchangeNode(node) {
3323
+ if (!node || typeof node !== "object") {
3324
+ return createCommandNode("unknown", {});
3325
+ }
3326
+ switch (node.type) {
3327
+ case "event":
3328
+ return convertEvent(node);
3329
+ case "command":
3330
+ return convertCommand(node);
3331
+ case "if":
3332
+ return convertIf(node);
3333
+ case "repeat":
3334
+ return convertRepeat(node);
3335
+ case "foreach":
3336
+ return convertForEach(node);
3337
+ case "while":
3338
+ return convertWhile(node);
3339
+ // Expression nodes — wrap as `get` command with patient role
3340
+ default:
3341
+ return createCommandNode("get", { patient: convertValue(node) });
3342
+ }
3343
+ }
3344
+ function convertEvent(node) {
3345
+ const event = String(node.event ?? "click");
3346
+ const bodyNodes = Array.isArray(node.body) ? node.body : [];
3347
+ const body = bodyNodes.map(fromInterchangeNode);
3348
+ const roles = {
3349
+ event: createLiteral(event)
3350
+ };
3351
+ if (node.target && typeof node.target === "object") {
3352
+ roles.source = convertValue(node.target);
3353
+ }
3354
+ const modifiers = node.modifiers;
3355
+ let eventModifiers;
3356
+ if (modifiers) {
3357
+ eventModifiers = bridgeEventModifiers(modifiers);
3358
+ if (modifiers.prevent) roles.prevent = createLiteral(true);
3359
+ if (modifiers.stop) roles.stop = createLiteral(true);
3360
+ if (modifiers.passive) roles.passive = createLiteral(true);
3361
+ if (modifiers.capture) roles.capture = createLiteral(true);
3362
+ }
3363
+ return createEventHandlerNode("on", roles, body, void 0, eventModifiers);
3364
+ }
3365
+ function convertCommand(node) {
3366
+ const name = String(node.name ?? "unknown");
3367
+ const args = Array.isArray(node.args) ? node.args : [];
3368
+ const target = node.target && typeof node.target === "object" ? node.target : void 0;
3369
+ const existingRoles = node.roles;
3370
+ const modifiers = node.modifiers;
3371
+ let roles;
3372
+ if (existingRoles && typeof existingRoles === "object" && Object.keys(existingRoles).length > 0) {
3373
+ roles = {};
3374
+ for (const [role, value] of Object.entries(existingRoles)) {
3375
+ if (value && typeof value === "object" && "type" in value) {
3376
+ roles[role] = convertValue(value);
3377
+ }
3378
+ }
3379
+ } else {
3380
+ roles = inferRoles(name, args, modifiers, target);
3381
+ }
3382
+ return createCommandNode(name, roles);
3383
+ }
3384
+ function convertIf(node) {
3385
+ const condition = node.condition && typeof node.condition === "object" ? convertValue(node.condition) : createExpression("true");
3386
+ const thenBody = Array.isArray(node.thenBranch) ? node.thenBranch : [];
3387
+ const thenBranch = thenBody.map(fromInterchangeNode);
3388
+ let elseBranch;
3389
+ const elseIfBranches = node.elseIfBranches;
3390
+ if (elseIfBranches && elseIfBranches.length > 0) {
3391
+ elseBranch = [chainElseIfs(elseIfBranches, node.elseBranch)];
3392
+ } else if (Array.isArray(node.elseBranch) && node.elseBranch.length > 0) {
3393
+ elseBranch = node.elseBranch.map(fromInterchangeNode);
3394
+ }
3395
+ const roles = { condition };
3396
+ return createConditionalNode("if", roles, thenBranch, elseBranch);
3397
+ }
3398
+ function chainElseIfs(branches, finalElse) {
3399
+ const [first, ...rest] = branches;
3400
+ const condition = convertValue(first.condition);
3401
+ const thenBranch = first.body.map(fromInterchangeNode);
3402
+ let elseBranch;
3403
+ if (rest.length > 0) {
3404
+ elseBranch = [chainElseIfs(rest, finalElse)];
3405
+ } else if (finalElse && finalElse.length > 0) {
3406
+ elseBranch = finalElse.map(fromInterchangeNode);
3407
+ }
3408
+ return createConditionalNode("if", { condition }, thenBranch, elseBranch);
3409
+ }
3410
+ function convertRepeat(node) {
3411
+ const bodyNodes = Array.isArray(node.body) ? node.body : [];
3412
+ const body = bodyNodes.map(fromInterchangeNode);
3413
+ const roles = {};
3414
+ let variant;
3415
+ if (node.count !== void 0 && node.count !== null) {
3416
+ variant = "times";
3417
+ if (typeof node.count === "number") {
3418
+ roles.quantity = createLiteral(node.count, "number");
3419
+ } else if (typeof node.count === "object") {
3420
+ roles.quantity = convertValue(node.count);
3421
+ }
3422
+ } else if (node.whileCondition && typeof node.whileCondition === "object") {
3423
+ variant = "while";
3424
+ roles.condition = convertValue(node.whileCondition);
3425
+ } else if (typeof node.untilEvent === "string") {
3426
+ variant = "until";
3427
+ roles.condition = createLiteral(node.untilEvent);
3428
+ } else {
3429
+ variant = "forever";
3430
+ }
3431
+ return createLoopNode("repeat", roles, variant, body);
3432
+ }
3433
+ function convertForEach(node) {
3434
+ const bodyNodes = Array.isArray(node.body) ? node.body : [];
3435
+ const body = bodyNodes.map(fromInterchangeNode);
3436
+ const roles = {};
3437
+ if (node.collection && typeof node.collection === "object") {
3438
+ roles.source = convertValue(node.collection);
3439
+ }
3440
+ const itemName = typeof node.itemName === "string" ? node.itemName : void 0;
3441
+ const indexName = typeof node.indexName === "string" ? node.indexName : void 0;
3442
+ return createLoopNode("repeat", roles, "for", body, itemName, indexName);
3443
+ }
3444
+ function convertWhile(node) {
3445
+ const bodyNodes = Array.isArray(node.body) ? node.body : [];
3446
+ const body = bodyNodes.map(fromInterchangeNode);
3447
+ const roles = {};
3448
+ if (node.condition && typeof node.condition === "object") {
3449
+ roles.condition = convertValue(node.condition);
3450
+ }
3451
+ return createLoopNode("repeat", roles, "while", body);
3452
+ }
3453
+ function convertValue(node) {
3454
+ switch (node.type) {
3455
+ case "literal":
3456
+ return convertLiteral(node);
3457
+ case "selector":
3458
+ return createSelector(String(node.value ?? ""), inferSelectorKind2(String(node.value ?? "")));
3459
+ case "identifier":
3460
+ return convertIdentifier(node);
3461
+ case "variable":
3462
+ return convertVariable(node);
3463
+ case "possessive":
3464
+ return createPropertyPath(
3465
+ node.object && typeof node.object === "object" ? convertValue(node.object) : createReference("me"),
3466
+ String(node.property ?? "")
3467
+ );
3468
+ // Complex expressions → collapse to raw string
3469
+ case "binary":
3470
+ case "unary":
3471
+ case "member":
3472
+ case "call":
3473
+ case "positional":
3474
+ return createExpression(renderExpr(node));
3475
+ default:
3476
+ if ("value" in node) return createLiteral(String(node.value ?? ""));
3477
+ return createExpression(renderExpr(node));
3478
+ }
3479
+ }
3480
+ function convertLiteral(node) {
3481
+ const value = node.value;
3482
+ if (value === null || value === void 0) return createLiteral("null");
3483
+ const dataType = typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : void 0;
3484
+ return createLiteral(value, dataType);
3485
+ }
3486
+ function convertIdentifier(node) {
3487
+ const value = String(node.value ?? "");
3488
+ if (DEFAULT_REFERENCES.has(value)) {
3489
+ return createReference(value);
3490
+ }
3491
+ return createLiteral(value);
3492
+ }
3493
+ function convertVariable(node) {
3494
+ const name = String(node.name ?? "");
3495
+ const scope = String(node.scope ?? "local");
3496
+ switch (scope) {
3497
+ case "element":
3498
+ return createExpression(`:${name}`);
3499
+ case "global":
3500
+ return createExpression(`$${name}`);
3501
+ default:
3502
+ return createExpression(name);
3503
+ }
3504
+ }
3505
+ function renderExpr(node) {
3506
+ if (!node || typeof node !== "object") return "";
3507
+ switch (node.type) {
3508
+ case "literal": {
3509
+ const v = node.value;
3510
+ if (v === null || v === void 0) return "null";
3511
+ if (typeof v === "string") return /\s/.test(v) ? `"${v}"` : v;
3512
+ return String(v);
3513
+ }
3514
+ case "identifier":
3515
+ return String(node.value ?? "");
3516
+ case "selector":
3517
+ return String(node.value ?? "");
3518
+ case "variable": {
3519
+ const name = String(node.name ?? "");
3520
+ const scope = String(node.scope ?? "local");
3521
+ if (scope === "element") return `:${name}`;
3522
+ if (scope === "global") return `$${name}`;
3523
+ return name;
3524
+ }
3525
+ case "binary": {
3526
+ const left = node.left && typeof node.left === "object" ? renderExpr(node.left) : "";
3527
+ const right = node.right && typeof node.right === "object" ? renderExpr(node.right) : "";
3528
+ return `${left} ${node.operator ?? ""} ${right}`;
3529
+ }
3530
+ case "unary": {
3531
+ const operand = node.operand && typeof node.operand === "object" ? renderExpr(node.operand) : "";
3532
+ return `${node.operator ?? ""} ${operand}`;
3533
+ }
3534
+ case "member": {
3535
+ const obj = node.object && typeof node.object === "object" ? renderExpr(node.object) : "";
3536
+ if (node.computed && node.property && typeof node.property === "object") {
3537
+ return `${obj}[${renderExpr(node.property)}]`;
3538
+ }
3539
+ const prop = typeof node.property === "string" ? node.property : node.property && typeof node.property === "object" ? renderExpr(node.property) : "";
3540
+ return `${obj}.${prop}`;
3541
+ }
3542
+ case "possessive": {
3543
+ const obj = node.object && typeof node.object === "object" ? renderExpr(node.object) : "";
3544
+ return `${obj}'s ${node.property ?? ""}`;
3545
+ }
3546
+ case "call": {
3547
+ const callee = node.callee && typeof node.callee === "object" ? renderExpr(node.callee) : "";
3548
+ const args = Array.isArray(node.args) ? node.args.map((a) => renderExpr(a)).join(", ") : "";
3549
+ return `${callee}(${args})`;
3550
+ }
3551
+ case "positional": {
3552
+ const target = node.target && typeof node.target === "object" ? renderExpr(node.target) : "";
3553
+ return target ? `${node.position ?? ""} ${target}` : String(node.position ?? "");
3554
+ }
3555
+ default:
3556
+ if ("value" in node) return String(node.value ?? "");
3557
+ return "";
3558
+ }
3559
+ }
3560
+ function inferRoles(name, args, modifiers, target) {
3561
+ const roles = {};
3562
+ switch (name) {
3563
+ case "set": {
3564
+ if (args[0]) roles.destination = convertValue(args[0]);
3565
+ const toVal = modifiers?.to;
3566
+ if (toVal && typeof toVal === "object" && "type" in toVal) {
3567
+ roles.patient = convertValue(toVal);
3568
+ } else if (args[1]) {
3569
+ roles.patient = convertValue(args[1]);
3570
+ }
3571
+ break;
3572
+ }
3573
+ case "put": {
3574
+ if (args[0]) roles.patient = convertValue(args[0]);
3575
+ if (modifiers) {
3576
+ for (const key of ["into", "before", "after"]) {
3577
+ const val = modifiers[key];
3578
+ if (val && typeof val === "object" && "type" in val) {
3579
+ roles.destination = convertValue(val);
3580
+ roles.method = createLiteral(key);
3581
+ break;
3582
+ }
3583
+ }
3584
+ }
3585
+ if (!roles.destination && target) {
3586
+ roles.destination = convertValue(target);
3587
+ }
3588
+ break;
3589
+ }
3590
+ case "increment":
3591
+ case "decrement": {
3592
+ if (args[0]) roles.destination = convertValue(args[0]);
3593
+ const byVal = modifiers?.by;
3594
+ if (byVal && typeof byVal === "object" && "type" in byVal) {
3595
+ roles.quantity = convertValue(byVal);
3596
+ } else if (args[1]) {
3597
+ roles.quantity = convertValue(args[1]);
3598
+ }
3599
+ break;
3600
+ }
3601
+ case "fetch": {
3602
+ if (args[0]) roles.source = convertValue(args[0]);
3603
+ const asVal = modifiers?.as;
3604
+ if (asVal && typeof asVal === "object" && "type" in asVal) {
3605
+ roles.responseType = convertValue(asVal);
3606
+ } else if (typeof asVal === "string") {
3607
+ roles.responseType = createLiteral(asVal);
3608
+ }
3609
+ break;
3610
+ }
3611
+ case "wait":
3612
+ case "settle": {
3613
+ if (args[0]) roles.duration = convertValue(args[0]);
3614
+ break;
3615
+ }
3616
+ case "toggle":
3617
+ case "add":
3618
+ case "show":
3619
+ case "hide": {
3620
+ if (args[0]) roles.patient = convertValue(args[0]);
3621
+ if (target) roles.destination = convertValue(target);
3622
+ break;
3623
+ }
3624
+ case "remove": {
3625
+ if (args[0]) roles.patient = convertValue(args[0]);
3626
+ if (target) roles.source = convertValue(target);
3627
+ break;
3628
+ }
3629
+ case "send":
3630
+ case "trigger": {
3631
+ if (args[0]) roles.patient = convertValue(args[0]);
3632
+ if (target) roles.destination = convertValue(target);
3633
+ break;
3634
+ }
3635
+ case "log": {
3636
+ if (args[0]) roles.patient = convertValue(args[0]);
3637
+ break;
3638
+ }
3639
+ default: {
3640
+ if (args[0]) roles.patient = convertValue(args[0]);
3641
+ if (target) roles.destination = convertValue(target);
3642
+ break;
3643
+ }
3644
+ }
3645
+ return roles;
3646
+ }
3647
+ function inferSelectorKind2(value) {
3648
+ if (!value) return void 0;
3649
+ if (value.startsWith("#")) return "id";
3650
+ if (value.startsWith(".")) return "class";
3651
+ if (value.startsWith("[")) return "attribute";
3652
+ if (value.startsWith("<") || value.startsWith("*")) return "element";
3653
+ if (/[>\+~ ]/.test(value) && value.length > 1) return "complex";
3654
+ return void 0;
3655
+ }
3656
+ function inferValueFromString(value) {
3657
+ if (DEFAULT_REFERENCES.has(value)) return createReference(value);
3658
+ const kind = inferSelectorKind2(value);
3659
+ if (kind) return createSelector(value, kind);
3660
+ return createLiteral(value);
3661
+ }
3662
+ function bridgeEventModifiers(mods) {
3663
+ const once = mods.once === true ? true : void 0;
3664
+ const debounce = typeof mods.debounce === "number" ? mods.debounce : void 0;
3665
+ const throttle = typeof mods.throttle === "number" ? mods.throttle : void 0;
3666
+ const from = typeof mods.from === "string" ? inferValueFromString(mods.from) : void 0;
3667
+ if (once === void 0 && debounce === void 0 && throttle === void 0 && from === void 0) {
3668
+ return void 0;
3669
+ }
3670
+ return {
3671
+ ...once !== void 0 ? { once } : {},
3672
+ ...debounce !== void 0 ? { debounce } : {},
3673
+ ...throttle !== void 0 ? { throttle } : {},
3674
+ ...from !== void 0 ? { from } : {}
3675
+ };
3676
+ }
3677
+
3678
+ // src/ir/to-runtime-ast.ts
3679
+ function semanticNodeToRuntimeAST(node) {
3680
+ switch (node.kind) {
3681
+ case "event-handler":
3682
+ return convertEventHandler(node);
3683
+ case "conditional":
3684
+ return convertConditional(node);
3685
+ case "loop":
3686
+ return convertLoop(node);
3687
+ case "compound": {
3688
+ const compound = node;
3689
+ const commands = (compound.statements ?? []).map(semanticNodeToRuntimeAST);
3690
+ return {
3691
+ type: "CommandSequence",
3692
+ commands
3693
+ };
3694
+ }
3695
+ case "command":
3696
+ default:
3697
+ return convertCommand2(node);
3698
+ }
3699
+ }
3700
+ function convertEventHandler(eh) {
3701
+ const eventValue = eh.roles.get("event");
3702
+ const eventName = eventValue && "value" in eventValue ? String(eventValue.value) : "click";
3703
+ const modifiers = {};
3704
+ if (eh.eventModifiers) {
3705
+ if (eh.eventModifiers.once) modifiers.once = true;
3706
+ if (eh.eventModifiers.debounce) modifiers.debounce = eh.eventModifiers.debounce;
3707
+ if (eh.eventModifiers.throttle) modifiers.throttle = eh.eventModifiers.throttle;
3708
+ if (eh.eventModifiers.queue) modifiers.queue = eh.eventModifiers.queue;
3709
+ }
3710
+ return {
3711
+ type: "event",
3712
+ event: eventName,
3713
+ modifiers,
3714
+ body: (eh.body ?? []).map(semanticNodeToRuntimeAST)
3715
+ };
3716
+ }
3717
+ function convertCommand2(node) {
3718
+ const roles = {};
3719
+ const args = [];
3720
+ for (const [roleName, value] of node.roles) {
3721
+ const astValue = semanticValueToAST(value);
3722
+ roles[roleName] = astValue;
3723
+ args.push(astValue);
3724
+ }
3725
+ return {
3726
+ type: "command",
3727
+ name: node.action,
3728
+ args,
3729
+ roles
3730
+ };
3731
+ }
3732
+ function convertConditional(node) {
3733
+ const conditionValue = node.roles.get("condition");
3734
+ return {
3735
+ type: "command",
3736
+ name: "if",
3737
+ args: conditionValue ? [semanticValueToAST(conditionValue)] : [],
3738
+ condition: conditionValue ? semanticValueToAST(conditionValue) : void 0,
3739
+ thenBranch: (node.thenBranch ?? []).map(semanticNodeToRuntimeAST),
3740
+ elseBranch: (node.elseBranch ?? []).map(semanticNodeToRuntimeAST)
3741
+ };
3742
+ }
3743
+ function convertLoop(node) {
3744
+ const countValue = node.roles.get("patient") || node.roles.get("count");
3745
+ return {
3746
+ type: "command",
3747
+ name: "repeat",
3748
+ args: countValue ? [semanticValueToAST(countValue)] : [],
3749
+ loopVariant: node.loopVariant ?? "forever",
3750
+ body: (node.body ?? []).map(semanticNodeToRuntimeAST),
3751
+ loopVariable: node.loopVariable,
3752
+ indexVariable: node.indexVariable
3753
+ };
3754
+ }
3755
+ function semanticValueToAST(value) {
3756
+ switch (value.type) {
3757
+ case "selector":
3758
+ return { type: "selector", value: value.value };
3759
+ case "reference":
3760
+ return { type: "identifier", value: value.value };
3761
+ case "literal": {
3762
+ const lit = value;
3763
+ if (lit.dataType === "duration") {
3764
+ const str = String(lit.value);
3765
+ const match = /^(\d+(?:\.\d+)?)(ms|s)$/.exec(str);
3766
+ if (match) {
3767
+ const ms = match[2] === "s" ? parseFloat(match[1]) * 1e3 : parseFloat(match[1]);
3768
+ return { type: "literal", value: ms };
3769
+ }
3770
+ }
3771
+ return { type: "literal", value: lit.value };
3772
+ }
3773
+ case "property-path": {
3774
+ const pp = value;
3775
+ const objectAST = semanticValueToAST(pp.object);
3776
+ return {
3777
+ type: "member",
3778
+ object: objectAST,
3779
+ property: pp.property
3780
+ };
3781
+ }
3782
+ case "expression": {
3783
+ const expr = value;
3784
+ return { type: "expression", value: expr.raw };
3785
+ }
3786
+ case "flag": {
3787
+ const flag = value;
3788
+ return { type: "literal", value: flag.enabled };
3789
+ }
3790
+ default:
3791
+ return { type: "literal", value: String(value.value ?? "") };
3792
+ }
3793
+ }
3794
+
3795
+ // src/api/create-dsl.ts
3796
+ var DSLRegistry = class {
3797
+ constructor(config) {
3798
+ this.patterns = /* @__PURE__ */ new Map();
3799
+ this.tokenizers = /* @__PURE__ */ new Map();
3800
+ this.schemas = config.schemas;
3801
+ for (const lang of config.languages) {
3802
+ this.registerLanguage(lang);
3803
+ }
3804
+ }
3805
+ registerLanguage(lang) {
3806
+ this.tokenizers.set(lang.code, lang.tokenizer);
3807
+ const patterns = [];
3808
+ for (const schema of this.schemas) {
3809
+ const pattern = generatePattern(schema, lang.patternProfile);
3810
+ patterns.push(pattern);
3811
+ }
3812
+ this.patterns.set(lang.code, patterns);
3813
+ }
3814
+ getPatterns(language) {
3815
+ return this.patterns.get(language) || [];
3816
+ }
3817
+ getTokenizer(language) {
3818
+ return this.tokenizers.get(language);
3819
+ }
3820
+ getSupportedLanguages() {
3821
+ return Array.from(this.patterns.keys());
3822
+ }
3823
+ };
3824
+ var MultilingualDSLImpl = class {
3825
+ constructor(config, registry, transformer) {
3826
+ this.registry = registry;
3827
+ this.matcher = new PatternMatcher();
3828
+ this.transformer = transformer;
3829
+ if (config.codeGenerator) {
3830
+ this.codeGenerator = config.codeGenerator;
3831
+ }
3832
+ const schemaMap = new Map(config.schemas.map((s) => [s.action, s]));
3833
+ this.schemaLookup = {
3834
+ getSchema: (action) => schemaMap.get(action)
3835
+ };
3836
+ }
3837
+ parse(input, language) {
3838
+ const result = this.parseWithConfidence(input, language);
3839
+ return result.node;
3840
+ }
3841
+ parseWithConfidence(input, language) {
3842
+ if (isExplicitSyntax(input)) {
3843
+ const node = parseExplicit(input, { schemaLookup: this.schemaLookup });
3844
+ if (!this.schemaLookup.getSchema(node.action)) {
3845
+ throw new Error(`No schema for action "${node.action}" in this DSL`);
3846
+ }
3847
+ return { node, confidence: 1 };
3848
+ }
3849
+ const tokenizer = this.registry.getTokenizer(language);
3850
+ if (!tokenizer) {
3851
+ throw new Error(`No tokenizer registered for language: ${language}`);
3852
+ }
3853
+ const tokens = tokenizer.tokenize(input);
3854
+ const patterns = this.registry.getPatterns(language);
3855
+ const profile = {
3856
+ code: language
3857
+ };
3858
+ for (const pattern of patterns) {
3859
+ const match = this.matcher.matchPattern(tokens, pattern, profile);
3860
+ if (match) {
3861
+ const node = {
3862
+ kind: "command",
3863
+ action: pattern.command,
3864
+ roles: match.captured,
3865
+ metadata: {
3866
+ sourceLanguage: language,
3867
+ sourceText: input,
3868
+ patternId: pattern.id,
3869
+ confidence: match.confidence
3870
+ }
3871
+ };
3872
+ return { node, confidence: match.confidence };
3873
+ }
3874
+ }
3875
+ throw new Error(`No pattern matched for input: ${input}`);
3876
+ }
3877
+ validate(input, language) {
3878
+ try {
3879
+ const result = this.parseWithConfidence(input, language);
3880
+ return {
3881
+ valid: true,
3882
+ node: result.node
3883
+ };
3884
+ } catch (error) {
3885
+ return {
3886
+ valid: false,
3887
+ errors: [error instanceof Error ? error.message : String(error)]
3888
+ };
3889
+ }
3890
+ }
3891
+ translate(input, fromLanguage, toLanguage) {
3892
+ if (isExplicitSyntax(input)) return input;
3893
+ return this.transformer.transform(input, fromLanguage, toLanguage);
3894
+ }
3895
+ compile(input, language) {
2001
3896
  if (!this.codeGenerator) {
2002
3897
  return {
2003
3898
  ok: false,
2004
3899
  errors: ["No code generator configured for this DSL"]
2005
3900
  };
2006
3901
  }
2007
- try {
2008
- const result = this.parseWithConfidence(input, language);
2009
- const code = this.codeGenerator.generate(result.node);
3902
+ try {
3903
+ const result = this.parseWithConfidence(input, language);
3904
+ const code = this.codeGenerator.generate(result.node);
3905
+ return {
3906
+ ok: true,
3907
+ code,
3908
+ node: result.node,
3909
+ metadata: {
3910
+ parser: "semantic",
3911
+ confidence: result.confidence
3912
+ }
3913
+ };
3914
+ } catch (error) {
3915
+ return {
3916
+ ok: false,
3917
+ errors: [error instanceof Error ? error.message : String(error)]
3918
+ };
3919
+ }
3920
+ }
3921
+ getSupportedLanguages() {
3922
+ return this.registry.getSupportedLanguages();
3923
+ }
3924
+ };
3925
+ function createDefaultDictionary(config) {
3926
+ const translations = {};
3927
+ for (const lang of config.languages) {
3928
+ const keywords = {};
3929
+ for (const [canonical, keywordDef] of Object.entries(lang.patternProfile.keywords)) {
3930
+ keywords[canonical] = keywordDef.primary;
3931
+ }
3932
+ translations[lang.code] = keywords;
3933
+ }
3934
+ return new InMemoryDictionary(translations);
3935
+ }
3936
+ function createDefaultProfileProvider(config) {
3937
+ const profiles = {};
3938
+ for (const lang of config.languages) {
3939
+ if (lang.grammarProfile) {
3940
+ profiles[lang.code] = lang.grammarProfile;
3941
+ }
3942
+ }
3943
+ return new InMemoryProfileProvider(profiles);
3944
+ }
3945
+ function createMultilingualDSL(config) {
3946
+ const dictionary = config.dictionary ?? createDefaultDictionary(config);
3947
+ const profileProvider = config.profileProvider ?? createDefaultProfileProvider(config);
3948
+ const transformer = new GrammarTransformer({
3949
+ dictionary,
3950
+ profileProvider
3951
+ });
3952
+ const registry = new DSLRegistry(config);
3953
+ return new MultilingualDSLImpl(config, registry, transformer);
3954
+ }
3955
+
3956
+ // src/prompts/prompt-generator.ts
3957
+ function generatePrompt(config) {
3958
+ const outputFormat = config.outputFormat ?? "both";
3959
+ const examplesPerCommand = config.examplesPerCommand ?? 2;
3960
+ const sections = [
3961
+ buildProtocolSection(),
3962
+ buildValueTypeSection(),
3963
+ buildCommandsSection(config.schemas, outputFormat, examplesPerCommand),
3964
+ buildOutputFormatSection(outputFormat),
3965
+ buildErrorRecoverySection()
3966
+ ];
3967
+ let finalSections = sections;
3968
+ if (config.maxTokens && config.maxTokens > 0) {
3969
+ finalSections = truncateToTokenBudget(sections, config.maxTokens);
3970
+ }
3971
+ const text = finalSections.map((s) => `## ${s.title}
3972
+
3973
+ ${s.content}`).join("\n\n---\n\n");
3974
+ const totalRoles = config.schemas.reduce((sum, s) => sum + s.roles.length, 0);
3975
+ const approximateTokens = estimateTokens(text);
3976
+ const metadata = {
3977
+ domain: config.domain,
3978
+ commandCount: config.schemas.length,
3979
+ roleCount: totalRoles,
3980
+ approximateTokens
3981
+ };
3982
+ return { text, sections: finalSections, metadata };
3983
+ }
3984
+ function generateExamples(schema, count = 2) {
3985
+ const combos = generateRoleCombinations(schema);
3986
+ const examples = [];
3987
+ for (let i = 0; i < Math.min(count, combos.length); i++) {
3988
+ const combo = combos[i];
3989
+ const roles = /* @__PURE__ */ new Map();
3990
+ for (const role of combo) {
3991
+ const sample = sampleValue(role);
3992
+ roles.set(role.role, sample);
3993
+ }
3994
+ const nodeRoles = /* @__PURE__ */ new Map();
3995
+ for (const [roleName, sample] of roles) {
3996
+ nodeRoles.set(roleName, toSemanticValue(sample));
3997
+ }
3998
+ const node = createCommandNode(schema.action, nodeRoles);
3999
+ const explicit = renderExplicit(node);
4000
+ const jsonRoles = {};
4001
+ for (const [roleName, sample] of roles) {
4002
+ jsonRoles[roleName] = sample;
4003
+ }
4004
+ const json = { action: schema.action, roles: jsonRoles };
4005
+ examples.push({ explicit, json });
4006
+ }
4007
+ return examples;
4008
+ }
4009
+ function generateProtocolReference() {
4010
+ const protocol = buildProtocolSection();
4011
+ const valueTypes = buildValueTypeSection();
4012
+ return `# LokaScript Explicit Syntax (LSE) Quick Reference
4013
+
4014
+ ${protocol.content}
4015
+
4016
+ ${valueTypes.content}`;
4017
+ }
4018
+ function buildProtocolSection() {
4019
+ const content = `LokaScript Explicit Syntax (LSE) is a bracket-based format for imperative commands.
4020
+
4021
+ ### Syntax
4022
+
4023
+ \`\`\`
4024
+ [command role1:value1 role2:value2 +flag1 ~flag2]
4025
+ \`\`\`
4026
+
4027
+ - **Command**: The first token inside brackets (lowercased)
4028
+ - **Role pair**: \`name:value\` \u2014 a named semantic role with a typed value (no space around colon)
4029
+ - **Enabled flag**: \`+name\` \u2014 boolean attribute present
4030
+ - **Disabled flag**: \`~name\` \u2014 boolean attribute negated
4031
+ - **Nested body**: \`body:[command ...]\` \u2014 a bracket command inside a role value
4032
+
4033
+ ### Rules
4034
+
4035
+ 1. Commands are always lowercased
4036
+ 2. Role names preserve their original case
4037
+ 3. No spaces around the colon in role:value pairs
4038
+ 4. Strings with spaces must be quoted: \`patient:"hello world"\`
4039
+ 5. Selectors start with \`#\`, \`.\`, \`[\`, \`@\`, or \`*\`
4040
+ 6. Output must be valid bracket syntax: \`[action role:value ...]\``;
4041
+ return {
4042
+ id: "protocol",
4043
+ title: "LSE Protocol",
4044
+ content,
4045
+ approximateTokens: estimateTokens(content)
4046
+ };
4047
+ }
4048
+ function buildValueTypeSection() {
4049
+ const content = `Values in LSE are classified by their syntactic form (first match wins):
4050
+
4051
+ | Type | Syntax | Example |
4052
+ |------|--------|---------|
4053
+ | Selector | Starts with \`#\` \`.\` \`[\` \`@\` \`*\` | \`#button\`, \`.active\`, \`[data-id]\` |
4054
+ | String | Quoted with \`"\` or \`'\` | \`"hello world"\`, \`'json'\` |
4055
+ | Boolean | Exact: \`true\` / \`false\` | \`visible:true\` |
4056
+ | Reference | Built-in name | \`me\`, \`you\`, \`it\`, \`result\`, \`event\`, \`target\`, \`body\` |
4057
+ | Duration | Number + suffix | \`500ms\`, \`2s\`, \`1m\`, \`1h\` |
4058
+ | Number | Digits with optional decimal | \`5\`, \`3.14\`, \`-1\` |
4059
+ | Plain | Fallback (any non-whitespace) | \`/api/users\`, \`json\`, \`production\` |
4060
+
4061
+ **Important**: Classification is by prefix, not by intent. \`#true\` is a selector (not boolean). \`event\` as a value is a reference (not plain text).`;
4062
+ return {
4063
+ id: "value-types",
4064
+ title: "Value Types",
4065
+ content,
4066
+ approximateTokens: estimateTokens(content)
4067
+ };
4068
+ }
4069
+ function buildCommandsSection(schemas, outputFormat, examplesPerCommand) {
4070
+ const parts = [];
4071
+ for (const schema of schemas) {
4072
+ parts.push(formatCommandDoc(schema, outputFormat, examplesPerCommand));
4073
+ }
4074
+ const content = parts.join("\n\n");
4075
+ return {
4076
+ id: "commands",
4077
+ title: "Available Commands",
4078
+ content,
4079
+ approximateTokens: estimateTokens(content)
4080
+ };
4081
+ }
4082
+ function buildOutputFormatSection(outputFormat) {
4083
+ let content;
4084
+ if (outputFormat === "explicit") {
4085
+ content = `Output valid LSE bracket syntax. Each command must be wrapped in brackets:
4086
+
4087
+ \`\`\`
4088
+ [command role:value ...]
4089
+ \`\`\`
4090
+
4091
+ Do NOT output JSON. Only use bracket syntax.`;
4092
+ } else if (outputFormat === "json") {
4093
+ content = `Output valid JSON in the LLM-simplified format:
4094
+
4095
+ \`\`\`json
4096
+ {
4097
+ "action": "command-name",
4098
+ "roles": {
4099
+ "roleName": { "type": "valueType", "value": "theValue" }
4100
+ }
4101
+ }
4102
+ \`\`\`
4103
+
4104
+ Valid value types: \`selector\`, \`literal\`, \`reference\`, \`expression\`.
4105
+ Do NOT output bracket syntax. Only use JSON.`;
4106
+ } else {
4107
+ content = `You may output EITHER format:
4108
+
4109
+ **Bracket syntax** (preferred for single commands):
4110
+ \`\`\`
4111
+ [command role:value ...]
4112
+ \`\`\`
4113
+
4114
+ **JSON format** (preferred when structured data is needed):
4115
+ \`\`\`json
4116
+ {
4117
+ "action": "command-name",
4118
+ "roles": {
4119
+ "roleName": { "type": "valueType", "value": "theValue" }
4120
+ }
4121
+ }
4122
+ \`\`\`
4123
+
4124
+ Both formats are equally valid. Use whichever is more natural for the context.`;
4125
+ }
4126
+ return {
4127
+ id: "output-format",
4128
+ title: "Output Format",
4129
+ content,
4130
+ approximateTokens: estimateTokens(content)
4131
+ };
4132
+ }
4133
+ function buildErrorRecoverySection() {
4134
+ const content = `If you're unsure about a command or role:
4135
+
4136
+ 1. **Unknown command**: Use the closest matching command from the Available Commands section. Do not invent commands.
4137
+ 2. **Unknown role**: Use only the roles listed for each command. Do not add roles not in the schema.
4138
+ 3. **Ambiguous value type**: When in doubt, use \`expression\` type (it's the most permissive).
4139
+ 4. **Missing required role**: Always include all required roles. Check the Required/Optional labels.
4140
+ 5. **Selector vs plain value**: If a value starts with \`#\`, \`.\`, \`[\`, \`@\`, or \`*\`, it's a selector. URLs like \`/api/data\` are plain values.
4141
+
4142
+ When generating LSE, prefer explicit role labeling over positional guessing. Every value should have a role name.`;
4143
+ return {
4144
+ id: "error-recovery",
4145
+ title: "Error Recovery",
4146
+ content,
4147
+ approximateTokens: estimateTokens(content)
4148
+ };
4149
+ }
4150
+ function formatCommandDoc(schema, outputFormat, examplesPerCommand) {
4151
+ const lines = [];
4152
+ lines.push(`### \`${schema.action}\` \u2014 ${schema.description}`);
4153
+ lines.push("");
4154
+ const required = schema.roles.filter((r) => r.required);
4155
+ const optional = schema.roles.filter((r) => !r.required);
4156
+ if (required.length > 0) {
4157
+ lines.push("**Required roles:**");
4158
+ for (const role of required) {
4159
+ lines.push(`- \`${role.role}\`: ${role.description} (type: ${formatExpectedTypes(role)})`);
4160
+ }
4161
+ }
4162
+ if (optional.length > 0) {
4163
+ lines.push("**Optional roles:**");
4164
+ for (const role of optional) {
4165
+ lines.push(`- \`${role.role}\`: ${role.description} (type: ${formatExpectedTypes(role)})`);
4166
+ }
4167
+ }
4168
+ const examples = generateExamples(schema, examplesPerCommand);
4169
+ if (examples.length > 0) {
4170
+ lines.push("");
4171
+ if (outputFormat === "explicit" || outputFormat === "both") {
4172
+ lines.push("**Bracket syntax:**");
4173
+ for (const ex of examples) {
4174
+ lines.push(`\`\`\`
4175
+ ${ex.explicit}
4176
+ \`\`\``);
4177
+ }
4178
+ }
4179
+ if (outputFormat === "json" || outputFormat === "both") {
4180
+ lines.push("**JSON format:**");
4181
+ for (const ex of examples) {
4182
+ lines.push(`\`\`\`json
4183
+ ${JSON.stringify(ex.json, null, 2)}
4184
+ \`\`\``);
4185
+ }
4186
+ }
4187
+ }
4188
+ return lines.join("\n");
4189
+ }
4190
+ function formatExpectedTypes(role) {
4191
+ return role.expectedTypes.join(" | ");
4192
+ }
4193
+ function generateRoleCombinations(schema) {
4194
+ const required = schema.roles.filter((r) => r.required);
4195
+ const optional = schema.roles.filter((r) => !r.required);
4196
+ const combos = [];
4197
+ if (required.length > 0) {
4198
+ combos.push(required);
4199
+ }
4200
+ for (const opt of optional) {
4201
+ combos.push([...required, opt]);
4202
+ }
4203
+ if (optional.length >= 2) {
4204
+ combos.push([...required, ...optional]);
4205
+ }
4206
+ if (combos.length === 0) {
4207
+ combos.push(schema.roles.slice());
4208
+ }
4209
+ return combos;
4210
+ }
4211
+ function sampleValue(role) {
4212
+ const primaryType = role.expectedTypes[0] || "expression";
4213
+ switch (primaryType) {
4214
+ case "selector":
4215
+ return sampleSelector(role.role);
4216
+ case "literal":
4217
+ return sampleLiteral(role.role);
4218
+ case "reference":
4219
+ return { type: "reference", value: "me" };
4220
+ case "expression":
4221
+ return sampleExpression(role.role);
4222
+ case "flag":
4223
+ return { type: "flag", value: true };
4224
+ default:
4225
+ return { type: "literal", value: "example" };
4226
+ }
4227
+ }
4228
+ function sampleSelector(roleName) {
4229
+ const selectors = {
4230
+ patient: ".active",
4231
+ destination: "#output",
4232
+ source: "#input",
4233
+ target: "#target"
4234
+ };
4235
+ return { type: "selector", value: selectors[roleName] || `#${roleName}` };
4236
+ }
4237
+ function sampleLiteral(roleName) {
4238
+ const literals = {
4239
+ duration: "30s",
4240
+ interval: "5s",
4241
+ delay: "500ms",
4242
+ timeout: "10s",
4243
+ quantity: 5,
4244
+ limit: 10,
4245
+ style: "json",
4246
+ manner: "rolling",
4247
+ format: "html"
4248
+ };
4249
+ return { type: "literal", value: literals[roleName] || roleName };
4250
+ }
4251
+ function sampleExpression(roleName) {
4252
+ const expressions = {
4253
+ source: "/api/data",
4254
+ destination: "#output",
4255
+ patient: ".active",
4256
+ instrument: "toUpperCase",
4257
+ condition: "age > 18",
4258
+ style: "json",
4259
+ duration: "5s",
4260
+ url: "/api/users"
4261
+ };
4262
+ return { type: "expression", value: expressions[roleName] || `/api/${roleName}` };
4263
+ }
4264
+ function toSemanticValue(sample) {
4265
+ switch (sample.type) {
4266
+ case "selector":
4267
+ return {
4268
+ type: "selector",
4269
+ value: String(sample.value),
4270
+ selectorKind: detectSelectorKind2(String(sample.value))
4271
+ };
4272
+ case "literal":
4273
+ return {
4274
+ type: "literal",
4275
+ value: sample.value,
4276
+ dataType: typeof sample.value === "number" ? "number" : typeof sample.value === "boolean" ? "boolean" : "string"
4277
+ };
4278
+ case "reference":
4279
+ return { type: "reference", value: String(sample.value) };
4280
+ case "expression":
4281
+ return { type: "expression", value: String(sample.value), raw: String(sample.value) };
4282
+ case "flag":
4283
+ return { type: "flag", value: sample.value };
4284
+ default:
4285
+ return { type: "literal", value: String(sample.value), dataType: "string" };
4286
+ }
4287
+ }
4288
+ function detectSelectorKind2(selector) {
4289
+ if (selector.startsWith("#")) return "id";
4290
+ if (selector.startsWith(".")) return "class";
4291
+ if (selector.startsWith("[")) return "attribute";
4292
+ return "complex";
4293
+ }
4294
+ function estimateTokens(text) {
4295
+ return Math.ceil(text.length / 4);
4296
+ }
4297
+ function truncateToTokenBudget(sections, maxTokens) {
4298
+ const result = [];
4299
+ let budget = maxTokens;
4300
+ for (const section of sections) {
4301
+ if (section.approximateTokens <= budget) {
4302
+ result.push(section);
4303
+ budget -= section.approximateTokens;
4304
+ } else {
4305
+ const charBudget = Math.max(budget * 4, 40);
4306
+ const truncatedContent = section.content.slice(0, charBudget) + "\n\n*(truncated)*";
4307
+ result.push({
4308
+ ...section,
4309
+ content: truncatedContent,
4310
+ approximateTokens: estimateTokens(truncatedContent)
4311
+ });
4312
+ break;
4313
+ }
4314
+ }
4315
+ return result;
4316
+ }
4317
+
4318
+ // src/training/schema-synthesizer.ts
4319
+ function synthesizeFromSchemas(schemas, config) {
4320
+ const maxPerCommand = config.maxPairsPerCommand ?? 5;
4321
+ const minQuality = config.minQuality ?? 0.5;
4322
+ const shuffleRoles = config.shuffleRoles ?? true;
4323
+ const languages = config.languages ?? ["en"];
4324
+ const pairs = [];
4325
+ let idCounter = 0;
4326
+ for (const schema of schemas) {
4327
+ const combos = generateRoleCombinations2(schema);
4328
+ for (const language of languages) {
4329
+ let commandPairCount = 0;
4330
+ for (const combo of combos) {
4331
+ if (commandPairCount >= maxPerCommand) break;
4332
+ const pair = buildTrainingPair(
4333
+ schema,
4334
+ combo,
4335
+ language,
4336
+ config.domain,
4337
+ `${config.domain}-synth-${idCounter++}`
4338
+ );
4339
+ if (pair.quality >= minQuality) {
4340
+ pairs.push(pair);
4341
+ commandPairCount++;
4342
+ }
4343
+ if (shuffleRoles && combo.length >= 2 && commandPairCount < maxPerCommand) {
4344
+ const shuffled = [...combo].reverse();
4345
+ const shuffledPair = buildTrainingPair(
4346
+ schema,
4347
+ shuffled,
4348
+ language,
4349
+ config.domain,
4350
+ `${config.domain}-synth-${idCounter++}`
4351
+ );
4352
+ if (shuffledPair.quality >= minQuality) {
4353
+ pairs.push(shuffledPair);
4354
+ commandPairCount++;
4355
+ }
4356
+ }
4357
+ }
4358
+ }
4359
+ }
4360
+ const metadata = {
4361
+ domain: config.domain,
4362
+ commandCount: schemas.length,
4363
+ pairCount: pairs.length,
4364
+ bySource: { synthetic: pairs.length },
4365
+ languages
4366
+ };
4367
+ return { pairs, metadata };
4368
+ }
4369
+ function generateRoleCombinations2(schema) {
4370
+ const required = schema.roles.filter((r) => r.required);
4371
+ const optional = schema.roles.filter((r) => !r.required);
4372
+ const combos = [];
4373
+ if (required.length > 0) {
4374
+ combos.push(required);
4375
+ }
4376
+ for (const opt of optional) {
4377
+ combos.push([...required, opt]);
4378
+ }
4379
+ if (optional.length >= 2) {
4380
+ combos.push([...required, ...optional]);
4381
+ }
4382
+ if (combos.length === 0) {
4383
+ combos.push(schema.roles.slice());
4384
+ }
4385
+ return combos;
4386
+ }
4387
+ function buildTrainingPair(schema, roles, language, domain, id) {
4388
+ const sampledRoles = /* @__PURE__ */ new Map();
4389
+ for (const role of roles) {
4390
+ sampledRoles.set(role.role, sampleValue2(role));
4391
+ }
4392
+ const nodeRoles = /* @__PURE__ */ new Map();
4393
+ for (const [name, sample] of sampledRoles) {
4394
+ nodeRoles.set(name, toSemanticValue2(sample));
4395
+ }
4396
+ const node = createCommandNode(schema.action, nodeRoles);
4397
+ const explicit = renderExplicit(node);
4398
+ const jsonRoles = {};
4399
+ for (const [name, sample] of sampledRoles) {
4400
+ jsonRoles[name] = sample;
4401
+ }
4402
+ const json = { action: schema.action, roles: jsonRoles };
4403
+ const natural = buildNaturalForm(schema, sampledRoles, language);
4404
+ const requiredCount = schema.roles.filter((r) => r.required).length;
4405
+ const filledRequired = roles.filter((r) => r.required).length;
4406
+ const quality = requiredCount > 0 ? filledRequired / requiredCount : 0.8;
4407
+ return {
4408
+ id,
4409
+ natural,
4410
+ language,
4411
+ explicit,
4412
+ json,
4413
+ domain,
4414
+ action: schema.action,
4415
+ source: "synthetic",
4416
+ quality
4417
+ };
4418
+ }
4419
+ function buildNaturalForm(schema, roles, language) {
4420
+ const parts = [schema.action];
4421
+ for (const roleSpec of schema.roles) {
4422
+ const sample = roles.get(roleSpec.role);
4423
+ if (!sample) continue;
4424
+ const marker = roleSpec.markerOverride?.[language];
4425
+ if (marker) {
4426
+ parts.push(marker);
4427
+ }
4428
+ parts.push(String(sample.value));
4429
+ }
4430
+ return parts.join(" ");
4431
+ }
4432
+ function sampleValue2(role) {
4433
+ const primaryType = role.expectedTypes[0] || "expression";
4434
+ switch (primaryType) {
4435
+ case "selector":
4436
+ return sampleSelector2(role.role);
4437
+ case "literal":
4438
+ return sampleLiteral2(role.role);
4439
+ case "reference":
4440
+ return { type: "reference", value: "me" };
4441
+ case "expression":
4442
+ return sampleExpression2(role.role);
4443
+ case "flag":
4444
+ return { type: "flag", value: true };
4445
+ default:
4446
+ return { type: "literal", value: "example" };
4447
+ }
4448
+ }
4449
+ function sampleSelector2(roleName) {
4450
+ const selectors = {
4451
+ patient: ".active",
4452
+ destination: "#output",
4453
+ source: "#input",
4454
+ target: "#target"
4455
+ };
4456
+ return { type: "selector", value: selectors[roleName] || `#${roleName}` };
4457
+ }
4458
+ function sampleLiteral2(roleName) {
4459
+ const literals = {
4460
+ duration: "30s",
4461
+ interval: "5s",
4462
+ delay: "500ms",
4463
+ timeout: "10s",
4464
+ quantity: 5,
4465
+ limit: 10,
4466
+ style: "json",
4467
+ manner: "rolling",
4468
+ format: "html"
4469
+ };
4470
+ return { type: "literal", value: literals[roleName] || roleName };
4471
+ }
4472
+ function sampleExpression2(roleName) {
4473
+ const expressions = {
4474
+ source: "/api/data",
4475
+ destination: "#output",
4476
+ patient: ".active",
4477
+ instrument: "toUpperCase",
4478
+ condition: "age > 18",
4479
+ style: "json",
4480
+ duration: "5s",
4481
+ url: "/api/users"
4482
+ };
4483
+ return { type: "expression", value: expressions[roleName] || `/api/${roleName}` };
4484
+ }
4485
+ function toSemanticValue2(sample) {
4486
+ switch (sample.type) {
4487
+ case "selector":
2010
4488
  return {
2011
- ok: true,
2012
- code,
2013
- node: result.node,
2014
- metadata: {
2015
- parser: "semantic",
2016
- confidence: result.confidence
2017
- }
4489
+ type: "selector",
4490
+ value: String(sample.value),
4491
+ selectorKind: detectSelectorKind3(String(sample.value))
2018
4492
  };
2019
- } catch (error) {
4493
+ case "literal":
2020
4494
  return {
2021
- ok: false,
2022
- errors: [error instanceof Error ? error.message : String(error)]
4495
+ type: "literal",
4496
+ value: sample.value,
4497
+ dataType: typeof sample.value === "number" ? "number" : typeof sample.value === "boolean" ? "boolean" : "string"
2023
4498
  };
4499
+ case "reference":
4500
+ return { type: "reference", value: String(sample.value) };
4501
+ case "expression":
4502
+ return { type: "expression", value: String(sample.value), raw: String(sample.value) };
4503
+ case "flag":
4504
+ return { type: "flag", value: sample.value };
4505
+ default:
4506
+ return { type: "literal", value: String(sample.value), dataType: "string" };
4507
+ }
4508
+ }
4509
+ function detectSelectorKind3(selector) {
4510
+ if (selector.startsWith("#")) return "id";
4511
+ if (selector.startsWith(".")) return "class";
4512
+ if (selector.startsWith("[")) return "attribute";
4513
+ return "complex";
4514
+ }
4515
+
4516
+ // src/feedback/feedback-formatter.ts
4517
+ function buildFeedback(input, inputFormat, diagnostics, schemaLookup, action) {
4518
+ const hasErrors = diagnostics.some((d) => d.severity === "error");
4519
+ const feedbackDiagnostics = diagnostics.map((d) => toFeedbackDiagnostic(d));
4520
+ const hints = generateHints(feedbackDiagnostics, schemaLookup, action);
4521
+ let schemaInfo;
4522
+ let correctedExample;
4523
+ if (action && schemaLookup) {
4524
+ const schema = schemaLookup.getSchema(action);
4525
+ if (schema) {
4526
+ schemaInfo = extractSchemaInfo(schema);
4527
+ if (hasErrors) {
4528
+ correctedExample = generateCorrectedExample(schema);
4529
+ }
2024
4530
  }
2025
4531
  }
2026
- getSupportedLanguages() {
2027
- return this.registry.getSupportedLanguages();
4532
+ return {
4533
+ accepted: !hasErrors,
4534
+ input: { format: inputFormat, text: input },
4535
+ diagnostics: feedbackDiagnostics,
4536
+ hints,
4537
+ ...schemaInfo && { schema: schemaInfo },
4538
+ ...correctedExample && { correctedExample }
4539
+ };
4540
+ }
4541
+ function toFeedbackDiagnostic(d) {
4542
+ const fixType = classifyFixType(d);
4543
+ return {
4544
+ severity: d.severity,
4545
+ code: d.code || "unknown",
4546
+ message: d.message,
4547
+ ...d.suggestions?.[0] && { suggestion: d.suggestions[0] },
4548
+ ...fixType && { fixType }
4549
+ };
4550
+ }
4551
+ function classifyFixType(d) {
4552
+ const code = (d.code || "").toLowerCase();
4553
+ const msg = d.message.toLowerCase();
4554
+ if (code.includes("missing-role") || code.includes("missing_role") || msg.includes("required role") || msg.includes("missing role")) {
4555
+ return "missing_role";
2028
4556
  }
2029
- };
2030
- function createDefaultDictionary(config) {
2031
- const translations = {};
2032
- for (const lang of config.languages) {
2033
- const keywords = {};
2034
- for (const [canonical, keywordDef] of Object.entries(lang.patternProfile.keywords)) {
2035
- keywords[canonical] = keywordDef.primary;
4557
+ if (code.includes("invalid-type") || code.includes("invalid_type") || code.includes("type-mismatch") || msg.includes("invalid type") || msg.includes("expected type")) {
4558
+ return "invalid_type";
4559
+ }
4560
+ if (code.includes("unknown-command") || code.includes("unknown_command") || msg.includes("unknown command") || msg.includes("not recognized") && msg.includes("command")) {
4561
+ return "unknown_command";
4562
+ }
4563
+ if (code.includes("unknown-role") || code.includes("unknown_role") || msg.includes("unknown role") || msg.includes("not recognized") && msg.includes("role")) {
4564
+ return "unknown_role";
4565
+ }
4566
+ if (code.includes("parse") || code.includes("syntax") || msg.includes("syntax error") || msg.includes("parse error") || msg.includes("unexpected")) {
4567
+ return "syntax_error";
4568
+ }
4569
+ return void 0;
4570
+ }
4571
+ function generateHints(diagnostics, schemaLookup, action) {
4572
+ const hints = [];
4573
+ const schema = action && schemaLookup ? schemaLookup.getSchema(action) : void 0;
4574
+ for (const d of diagnostics) {
4575
+ if (d.severity !== "error") continue;
4576
+ switch (d.fixType) {
4577
+ case "missing_role": {
4578
+ if (schema) {
4579
+ const required = schema.roles.filter((r) => r.required).map((r) => `'${r.role}' (${r.description}, type: ${r.expectedTypes.join("|")})`).join(", ");
4580
+ hints.push(`Required roles for '${action}': ${required}`);
4581
+ } else {
4582
+ hints.push("Check that all required roles are present.");
4583
+ }
4584
+ break;
4585
+ }
4586
+ case "unknown_command": {
4587
+ hints.push(
4588
+ `Command not recognized. Ensure you're using a valid command from the domain schema.`
4589
+ );
4590
+ break;
4591
+ }
4592
+ case "unknown_role": {
4593
+ if (schema) {
4594
+ const validRoles = schema.roles.map((r) => `'${r.role}'`).join(", ");
4595
+ hints.push(`Valid roles for '${action}': ${validRoles}`);
4596
+ } else {
4597
+ hints.push("Use only roles defined in the command schema.");
4598
+ }
4599
+ break;
4600
+ }
4601
+ case "invalid_type": {
4602
+ hints.push(
4603
+ "Check value types: selectors start with #.[@*, strings use quotes, numbers are plain digits."
4604
+ );
4605
+ break;
4606
+ }
4607
+ case "syntax_error": {
4608
+ hints.push("Ensure bracket syntax: [command role:value ...]. No spaces around the colon.");
4609
+ break;
4610
+ }
4611
+ default: {
4612
+ if (d.suggestion) {
4613
+ hints.push(d.suggestion);
4614
+ }
4615
+ }
2036
4616
  }
2037
- translations[lang.code] = keywords;
2038
4617
  }
2039
- return new InMemoryDictionary(translations);
4618
+ return [...new Set(hints)];
2040
4619
  }
2041
- function createDefaultProfileProvider(config) {
2042
- const profiles = {};
2043
- for (const lang of config.languages) {
2044
- if (lang.grammarProfile) {
2045
- profiles[lang.code] = lang.grammarProfile;
4620
+ function extractSchemaInfo(schema) {
4621
+ const requiredRoles = [];
4622
+ const optionalRoles = [];
4623
+ const roleDescriptions = {};
4624
+ for (const role of schema.roles) {
4625
+ if (role.required) {
4626
+ requiredRoles.push(role.role);
4627
+ } else {
4628
+ optionalRoles.push(role.role);
2046
4629
  }
4630
+ roleDescriptions[role.role] = role.description;
2047
4631
  }
2048
- return new InMemoryProfileProvider(profiles);
4632
+ return {
4633
+ action: schema.action,
4634
+ requiredRoles,
4635
+ optionalRoles,
4636
+ roleDescriptions
4637
+ };
2049
4638
  }
2050
- function createMultilingualDSL(config) {
2051
- const dictionary = config.dictionary ?? createDefaultDictionary(config);
2052
- const profileProvider = config.profileProvider ?? createDefaultProfileProvider(config);
2053
- const transformer = new GrammarTransformer({
2054
- dictionary,
2055
- profileProvider
2056
- });
2057
- const registry = new DSLRegistry(config);
2058
- return new MultilingualDSLImpl(config, registry, transformer);
4639
+ function generateCorrectedExample(schema) {
4640
+ const roles = /* @__PURE__ */ new Map();
4641
+ const jsonRoles = {};
4642
+ for (const role of schema.roles) {
4643
+ if (!role.required) continue;
4644
+ const sample = sampleDefaultValue(role.role, role.expectedTypes[0] || "expression");
4645
+ roles.set(role.role, toSemanticValue3(sample));
4646
+ jsonRoles[role.role] = sample;
4647
+ }
4648
+ const node = createCommandNode(schema.action, roles);
4649
+ const explicit = renderExplicit(node);
4650
+ const json = { action: schema.action, roles: jsonRoles };
4651
+ return { explicit, json };
4652
+ }
4653
+ function sampleDefaultValue(roleName, expectedType) {
4654
+ switch (expectedType) {
4655
+ case "selector":
4656
+ return { type: "selector", value: `#${roleName}` };
4657
+ case "expression":
4658
+ return { type: "expression", value: `<${roleName}-value>` };
4659
+ case "literal":
4660
+ return { type: "literal", value: `<${roleName}-value>` };
4661
+ case "reference":
4662
+ return { type: "reference", value: "me" };
4663
+ default:
4664
+ return { type: "expression", value: `<${roleName}-value>` };
4665
+ }
4666
+ }
4667
+ function toSemanticValue3(sample) {
4668
+ switch (sample.type) {
4669
+ case "selector":
4670
+ return { type: "selector", value: sample.value, selectorKind: "id" };
4671
+ case "expression":
4672
+ return { type: "expression", value: sample.value, raw: sample.value };
4673
+ case "literal":
4674
+ return { type: "literal", value: sample.value, dataType: "string" };
4675
+ case "reference":
4676
+ return { type: "reference", value: sample.value };
4677
+ default:
4678
+ return { type: "literal", value: sample.value, dataType: "string" };
4679
+ }
2059
4680
  }
2060
4681
 
2061
4682
  // src/api/domain-registry.ts
@@ -2075,6 +4696,17 @@ var DomainRegistry = class {
2075
4696
  }
2076
4697
  this.descriptors.set(descriptor.name, descriptor);
2077
4698
  }
4699
+ /**
4700
+ * Attach schemas to an already-registered domain.
4701
+ * Useful for lazy loading schemas after initial registration.
4702
+ */
4703
+ setSchemas(name, schemas) {
4704
+ const existing = this.descriptors.get(name);
4705
+ if (!existing) {
4706
+ throw new Error(`Domain not registered: ${name}`);
4707
+ }
4708
+ this.descriptors.set(name, { ...existing, schemas });
4709
+ }
2078
4710
  /**
2079
4711
  * Get all registered domain names.
2080
4712
  */
@@ -2144,6 +4776,71 @@ var DomainRegistry = class {
2144
4776
  return this.getDSL(descriptor);
2145
4777
  }
2146
4778
  // ---------------------------------------------------------------------------
4779
+ // LLM ↔ LSE Convenience Methods
4780
+ // ---------------------------------------------------------------------------
4781
+ /**
4782
+ * Generate an LLM system prompt for a domain from its schemas.
4783
+ * Returns null if the domain is not registered or has no schemas.
4784
+ */
4785
+ generatePrompt(domain, config) {
4786
+ const descriptor = this.descriptors.get(domain);
4787
+ if (!descriptor?.schemas || descriptor.schemas.length === 0) return null;
4788
+ return generatePrompt({
4789
+ domain,
4790
+ description: descriptor.description,
4791
+ schemas: descriptor.schemas,
4792
+ ...config
4793
+ });
4794
+ }
4795
+ /**
4796
+ * Synthesize training data for a domain from its schemas.
4797
+ * Returns null if the domain is not registered or has no schemas.
4798
+ */
4799
+ generateTrainingData(domain, config) {
4800
+ const descriptor = this.descriptors.get(domain);
4801
+ if (!descriptor?.schemas || descriptor.schemas.length === 0) return null;
4802
+ return synthesizeFromSchemas(descriptor.schemas, {
4803
+ domain,
4804
+ ...config
4805
+ });
4806
+ }
4807
+ /**
4808
+ * Build structured feedback for a failed LSE input in a domain.
4809
+ * Returns null if the domain is not registered or has no schemas.
4810
+ */
4811
+ buildFeedback(domain, input, inputFormat, diagnostics) {
4812
+ const descriptor = this.descriptors.get(domain);
4813
+ if (!descriptor?.schemas || descriptor.schemas.length === 0) return null;
4814
+ const schemaLookup = this.createSchemaLookup(descriptor.schemas);
4815
+ let action;
4816
+ try {
4817
+ if (inputFormat === "explicit") {
4818
+ const node = parseExplicit(input, { schemaLookup });
4819
+ action = node.action;
4820
+ }
4821
+ } catch {
4822
+ }
4823
+ return buildFeedback(input, inputFormat, diagnostics, schemaLookup, action);
4824
+ }
4825
+ /**
4826
+ * Get schemas for a domain (if available).
4827
+ */
4828
+ getSchemas(domain) {
4829
+ const descriptor = this.descriptors.get(domain);
4830
+ if (!descriptor?.schemas) return null;
4831
+ return descriptor.schemas;
4832
+ }
4833
+ /**
4834
+ * Create a SchemaLookup from a domain's schemas.
4835
+ */
4836
+ createSchemaLookup(schemas) {
4837
+ const map = /* @__PURE__ */ new Map();
4838
+ for (const s of schemas) {
4839
+ map.set(s.action, s);
4840
+ }
4841
+ return { getSchema: (action) => map.get(action) };
4842
+ }
4843
+ // ---------------------------------------------------------------------------
2147
4844
  // Private: DSL/renderer lifecycle
2148
4845
  // ---------------------------------------------------------------------------
2149
4846
  async getDSL(descriptor) {
@@ -2243,7 +4940,7 @@ function generateToolDefinitions(desc) {
2243
4940
  case "parse":
2244
4941
  tools.push({
2245
4942
  name: `parse_${desc.name}`,
2246
- description: `Parse a ${desc.description} input into a semantic representation. Supports: ${langList}.`,
4943
+ description: `Parse a ${desc.description} input into a semantic representation (action, roles, confidence). Supports: ${langList}.`,
2247
4944
  inputSchema: {
2248
4945
  type: "object",
2249
4946
  properties: {
@@ -2264,7 +4961,7 @@ function generateToolDefinitions(desc) {
2264
4961
  case "compile":
2265
4962
  tools.push({
2266
4963
  name: `compile_${desc.name}`,
2267
- description: `Compile a ${desc.description} input to target code. Supports: ${langList}.`,
4964
+ description: `Compile a ${desc.description} input to ${desc.outputDescription ?? "target code"}. Supports: ${langList}.`,
2268
4965
  inputSchema: {
2269
4966
  type: "object",
2270
4967
  properties: {
@@ -2285,7 +4982,7 @@ function generateToolDefinitions(desc) {
2285
4982
  case "validate":
2286
4983
  tools.push({
2287
4984
  name: `validate_${desc.name}`,
2288
- description: `Validate ${desc.description} syntax. Returns whether it parses successfully and any errors. Supports: ${langList}.`,
4985
+ description: `Check ${desc.description} syntax for errors. Returns {valid, errors[]}. Supports: ${langList}.`,
2289
4986
  inputSchema: {
2290
4987
  type: "object",
2291
4988
  properties: {
@@ -2306,7 +5003,7 @@ function generateToolDefinitions(desc) {
2306
5003
  case "translate":
2307
5004
  tools.push({
2308
5005
  name: `translate_${desc.name}`,
2309
- description: `Translate ${desc.description} input between natural languages. Parses in source language and renders in target language.`,
5006
+ description: `Translate ${desc.description} input between natural languages (requires 'from' and 'to' codes). Supports: ${langList}.`,
2310
5007
  inputSchema: {
2311
5008
  type: "object",
2312
5009
  properties: {
@@ -2372,9 +5069,9 @@ var CrossDomainDispatcher = class {
2372
5069
  if (domainNames.length === 0) return null;
2373
5070
  const candidates = [];
2374
5071
  for (const name of domainNames) {
2375
- const dsl = await this.registry.getDSLForDomain(name);
2376
- if (!dsl) continue;
2377
5072
  try {
5073
+ const dsl = await this.registry.getDSLForDomain(name);
5074
+ if (!dsl) continue;
2378
5075
  const { node, confidence } = dsl.parseWithConfidence(input, language);
2379
5076
  if (confidence >= this.minConfidence) {
2380
5077
  candidates.push({ domain: name, node, confidence, dsl });
@@ -2383,10 +5080,16 @@ var CrossDomainDispatcher = class {
2383
5080
  }
2384
5081
  }
2385
5082
  if (candidates.length === 0) return null;
2386
- candidates.sort((a, b) => {
2387
- if (b.confidence !== a.confidence) return b.confidence - a.confidence;
2388
- return this.getPriorityIndex(a.domain) - this.getPriorityIndex(b.domain);
2389
- });
5083
+ if (this.priority.length > 0) {
5084
+ candidates.sort((a, b) => {
5085
+ const pa = this.getPriorityIndex(a.domain);
5086
+ const pb = this.getPriorityIndex(b.domain);
5087
+ if (pa !== pb) return pa - pb;
5088
+ return b.confidence - a.confidence;
5089
+ });
5090
+ } else {
5091
+ candidates.sort((a, b) => b.confidence - a.confidence);
5092
+ }
2390
5093
  return candidates[0];
2391
5094
  }
2392
5095
  /**
@@ -2430,6 +5133,40 @@ var CrossDomainDispatcher = class {
2430
5133
  const result = detected.dsl.compile(input, language);
2431
5134
  return { ...result, domain: detected.domain };
2432
5135
  }
5136
+ /**
5137
+ * Compile multi-line input where each line may belong to a different domain.
5138
+ * Detects the domain for each line and compiles it, returning per-line results.
5139
+ * Empty lines and comment lines are skipped.
5140
+ */
5141
+ async compileComposite(input, language = "en") {
5142
+ const lines = input.split("\n");
5143
+ const statements = [];
5144
+ const errors = [];
5145
+ for (let i = 0; i < lines.length; i++) {
5146
+ const line = lines[i];
5147
+ if (isSkippableLine(line)) continue;
5148
+ const trimmed = line.trim();
5149
+ const detected = await this.detect(trimmed, language);
5150
+ if (detected) {
5151
+ const result = detected.dsl.compile(trimmed, language);
5152
+ statements.push({
5153
+ line: i + 1,
5154
+ input: trimmed,
5155
+ domain: detected.domain,
5156
+ ok: result.ok,
5157
+ code: result.code,
5158
+ errors: result.errors
5159
+ });
5160
+ } else {
5161
+ errors.push({
5162
+ line: i + 1,
5163
+ input: trimmed,
5164
+ message: "No domain matched this input"
5165
+ });
5166
+ }
5167
+ }
5168
+ return { statements, errors };
5169
+ }
2433
5170
  /**
2434
5171
  * Validate input against all domains, returning the best match.
2435
5172
  */
@@ -2711,6 +5448,30 @@ ${body}
2711
5448
  }
2712
5449
  };
2713
5450
 
5451
+ // src/aot/registry-bridge.ts
5452
+ async function registryToAOTBackends(registry) {
5453
+ const backends = [];
5454
+ for (const name of registry.getDomainNames()) {
5455
+ const descriptor = registry.getDescriptor(name);
5456
+ if (!descriptor?.scanConfig) continue;
5457
+ const dsl = await registry.getDSLForDomain(name);
5458
+ if (!dsl) continue;
5459
+ const scanConfig = {
5460
+ domain: name,
5461
+ attributes: [...descriptor.scanConfig.attributes],
5462
+ ...descriptor.scanConfig.scriptTypes ? { scriptTypes: [...descriptor.scanConfig.scriptTypes] } : {},
5463
+ defaultLanguage: descriptor.scanConfig.defaultLanguage ?? "en"
5464
+ };
5465
+ const codeGenerator = {
5466
+ generate(node) {
5467
+ return JSON.stringify({ action: node.action, roles: Object.fromEntries(node.roles) });
5468
+ }
5469
+ };
5470
+ backends.push({ domain: name, dsl, codeGenerator, scanConfig });
5471
+ }
5472
+ return backends;
5473
+ }
5474
+
2714
5475
  // src/schema/command-schema.ts
2715
5476
  function defineCommand(schema) {
2716
5477
  return {
@@ -4002,6 +6763,295 @@ function normalized(stem, confidence, metadata) {
4002
6763
  return { stem, confidence };
4003
6764
  }
4004
6765
 
6766
+ // src/core/tokenization/morphology/base-normalizer.ts
6767
+ var BaseMorphologicalNormalizer = class {
6768
+ constructor(config) {
6769
+ this.language = config.language;
6770
+ this.config = {
6771
+ minWordLength: 3,
6772
+ minStemLength: 2,
6773
+ ...config
6774
+ };
6775
+ }
6776
+ /**
6777
+ * Standard normalization pipeline. Override for custom behavior.
6778
+ */
6779
+ normalize(word) {
6780
+ const lower = word.toLowerCase();
6781
+ if (this.isAlreadyNormalized(lower)) {
6782
+ return noChange(word);
6783
+ }
6784
+ if (this.config.reflexiveSuffixes) {
6785
+ const reflexive = this.tryReflexiveNormalization(lower);
6786
+ if (reflexive) return reflexive;
6787
+ }
6788
+ if (this.config.endings) {
6789
+ const conjugation = this.tryConjugationEndings(lower);
6790
+ if (conjugation) return conjugation;
6791
+ }
6792
+ if (this.config.suffixRules) {
6793
+ const suffix = this.trySuffixRules(lower);
6794
+ if (suffix) return suffix;
6795
+ }
6796
+ if (this.config.prefixRules) {
6797
+ const prefix = this.tryPrefixRules(lower);
6798
+ if (prefix) return prefix;
6799
+ }
6800
+ return noChange(word);
6801
+ }
6802
+ /**
6803
+ * Check if word is already in dictionary form (e.g., ends in -ar/-er/-ir).
6804
+ * Override for language-specific checks.
6805
+ */
6806
+ isAlreadyNormalized(word) {
6807
+ if (this.config.infinitiveEndings) {
6808
+ return this.config.infinitiveEndings.some((e) => word.endsWith(e));
6809
+ }
6810
+ return false;
6811
+ }
6812
+ /**
6813
+ * Try to strip reflexive suffixes and normalize the remainder.
6814
+ * Common in Romance languages (Spanish, Portuguese, French).
6815
+ */
6816
+ tryReflexiveNormalization(word) {
6817
+ const suffixes = this.config.reflexiveSuffixes;
6818
+ if (!suffixes) return null;
6819
+ for (const suffix of suffixes) {
6820
+ if (!word.endsWith(suffix)) continue;
6821
+ const remainder = word.slice(0, -suffix.length);
6822
+ if (this.isAlreadyNormalized(remainder)) {
6823
+ return normalized(remainder, 0.88, {
6824
+ removedSuffixes: [suffix],
6825
+ conjugationType: "reflexive"
6826
+ });
6827
+ }
6828
+ const inner = this.tryConjugationEndings(remainder) || this.trySuffixRules(remainder);
6829
+ if (inner && inner.stem !== remainder) {
6830
+ return normalized(inner.stem, inner.confidence * 0.95, {
6831
+ removedSuffixes: [suffix, ...inner.metadata?.removedSuffixes || []],
6832
+ conjugationType: "reflexive"
6833
+ });
6834
+ }
6835
+ }
6836
+ return null;
6837
+ }
6838
+ /**
6839
+ * Try conjugation endings (verb class endings like -ar/-er/-ir patterns).
6840
+ * Endings must be pre-sorted longest-first.
6841
+ */
6842
+ tryConjugationEndings(word) {
6843
+ const endings = this.config.endings;
6844
+ if (!endings) return null;
6845
+ const minStem = this.config.minStemLength ?? 2;
6846
+ for (const rule of endings) {
6847
+ if (!word.endsWith(rule.ending)) continue;
6848
+ const stemBase = word.slice(0, -rule.ending.length);
6849
+ if (stemBase.length < minStem) continue;
6850
+ const infinitive = stemBase + rule.stem;
6851
+ return normalized(infinitive, rule.confidence, {
6852
+ removedSuffixes: [rule.ending],
6853
+ conjugationType: rule.type
6854
+ });
6855
+ }
6856
+ return null;
6857
+ }
6858
+ /**
6859
+ * Try SuffixRule-style normalization.
6860
+ * Rules must be pre-sorted longest-first.
6861
+ */
6862
+ trySuffixRules(word) {
6863
+ const rules = this.config.suffixRules;
6864
+ if (!rules) return null;
6865
+ const defaultMinStem = this.config.minStemLength ?? 2;
6866
+ for (const rule of rules) {
6867
+ if (!word.endsWith(rule.pattern)) continue;
6868
+ const stem = word.slice(0, -rule.pattern.length);
6869
+ const minStem = rule.minStemLength ?? defaultMinStem;
6870
+ if (stem.length < minStem) continue;
6871
+ const result = stem + (rule.replacement || "");
6872
+ return normalized(result, rule.confidence, {
6873
+ removedSuffixes: [rule.pattern],
6874
+ ...rule.conjugationType && { conjugationType: rule.conjugationType }
6875
+ });
6876
+ }
6877
+ return null;
6878
+ }
6879
+ /**
6880
+ * Try PrefixRule-style normalization.
6881
+ */
6882
+ tryPrefixRules(word) {
6883
+ const rules = this.config.prefixRules;
6884
+ if (!rules) return null;
6885
+ for (const rule of rules) {
6886
+ if (!word.startsWith(rule.pattern)) continue;
6887
+ const remainder = word.slice(rule.pattern.length);
6888
+ const minRemaining = rule.minRemaining ?? this.config.minStemLength ?? 2;
6889
+ if (remainder.length < minRemaining) continue;
6890
+ return normalized(remainder, 1 - rule.confidencePenalty, {
6891
+ removedPrefixes: [rule.pattern]
6892
+ });
6893
+ }
6894
+ return null;
6895
+ }
6896
+ };
6897
+
6898
+ // src/training/jsonl-writer.ts
6899
+ function toJSONL(pairs) {
6900
+ return pairs.map((pair) => JSON.stringify(toJSONLRow(pair))).join("\n");
6901
+ }
6902
+ function toJSONLRow(pair) {
6903
+ return {
6904
+ id: pair.id,
6905
+ prompt: pair.natural,
6906
+ completion: pair.explicit,
6907
+ metadata: {
6908
+ domain: pair.domain,
6909
+ action: pair.action,
6910
+ language: pair.language,
6911
+ source: pair.source,
6912
+ quality: pair.quality,
6913
+ ...pair.confidence !== void 0 && { confidence: pair.confidence }
6914
+ }
6915
+ };
6916
+ }
6917
+ function parseJSONL(text) {
6918
+ return text.split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
6919
+ }
6920
+
6921
+ // src/feedback/confidence-gate.ts
6922
+ function needsDisambiguation(confidence, low = 0.5, high = 0.7) {
6923
+ return confidence >= low && confidence < high;
6924
+ }
6925
+ function buildDisambiguation(input, candidates) {
6926
+ const sortedCandidates = [...candidates].sort((a, b) => b.confidence - a.confidence);
6927
+ const disambiguationCandidates = sortedCandidates.map((c, i) => ({
6928
+ action: c.action,
6929
+ confidence: c.confidence,
6930
+ explicit: renderExplicit(c.node),
6931
+ description: c.description || `${c.action} (option ${String.fromCharCode(97 + i)})`
6932
+ }));
6933
+ const optionLines = disambiguationCandidates.map(
6934
+ (c, i) => ` (${String.fromCharCode(97 + i)}) ${c.explicit} \u2014 ${c.description} (conf: ${c.confidence.toFixed(2)})`
6935
+ );
6936
+ const question = [
6937
+ `Your input parsed with confidence ${sortedCandidates[0]?.confidence.toFixed(2) ?? "?"}.`,
6938
+ ...optionLines,
6939
+ "Which did you mean?"
6940
+ ].join("\n");
6941
+ return {
6942
+ input,
6943
+ candidates: disambiguationCandidates,
6944
+ question
6945
+ };
6946
+ }
6947
+
6948
+ // src/feedback/pattern-tracker.ts
6949
+ var PatternTracker = class {
6950
+ constructor(maxEvents = 1e3) {
6951
+ this.events = [];
6952
+ this.maxEvents = maxEvents;
6953
+ }
6954
+ /**
6955
+ * Record a pattern event.
6956
+ */
6957
+ record(event) {
6958
+ this.events.push(event);
6959
+ if (this.events.length > this.maxEvents) {
6960
+ this.events = this.events.slice(this.events.length - this.maxEvents);
6961
+ }
6962
+ }
6963
+ /**
6964
+ * Get hit rate by command action.
6965
+ */
6966
+ getHitRateByCommand() {
6967
+ return this.computeHitRate((e) => e.action);
6968
+ }
6969
+ /**
6970
+ * Get hit rate by language.
6971
+ */
6972
+ getHitRateByLanguage() {
6973
+ return this.computeHitRate((e) => e.language);
6974
+ }
6975
+ /**
6976
+ * Get the most frequent failure diagnostic codes.
6977
+ */
6978
+ getTopFailures(limit = 10) {
6979
+ const codeMap = /* @__PURE__ */ new Map();
6980
+ for (const event of this.events) {
6981
+ if (event.outcome !== "rejected" || !event.diagnosticCodes) continue;
6982
+ for (const code of event.diagnosticCodes) {
6983
+ const entry = codeMap.get(code) || { count: 0, actions: /* @__PURE__ */ new Set() };
6984
+ entry.count++;
6985
+ entry.actions.add(event.action);
6986
+ codeMap.set(code, entry);
6987
+ }
6988
+ }
6989
+ return Array.from(codeMap.entries()).map(([code, { count, actions }]) => ({
6990
+ code,
6991
+ count,
6992
+ actions: Array.from(actions)
6993
+ })).sort((a, b) => b.count - a.count).slice(0, limit);
6994
+ }
6995
+ /**
6996
+ * Get a complete summary of tracking data.
6997
+ */
6998
+ getSummary() {
6999
+ const byOutcome = {};
7000
+ for (const event of this.events) {
7001
+ byOutcome[event.outcome] = (byOutcome[event.outcome] || 0) + 1;
7002
+ }
7003
+ return {
7004
+ totalEvents: this.events.length,
7005
+ byOutcome,
7006
+ byCommand: this.getHitRateByCommand(),
7007
+ byLanguage: this.getHitRateByLanguage(),
7008
+ topFailures: this.getTopFailures()
7009
+ };
7010
+ }
7011
+ /**
7012
+ * Export all events as JSONL.
7013
+ */
7014
+ exportJSONL() {
7015
+ return this.events.map((e) => JSON.stringify(e)).join("\n");
7016
+ }
7017
+ /**
7018
+ * Get the number of recorded events.
7019
+ */
7020
+ get size() {
7021
+ return this.events.length;
7022
+ }
7023
+ /**
7024
+ * Clear all events.
7025
+ */
7026
+ clear() {
7027
+ this.events = [];
7028
+ }
7029
+ // ---------------------------------------------------------------------------
7030
+ // Private
7031
+ // ---------------------------------------------------------------------------
7032
+ computeHitRate(keyFn) {
7033
+ const map = /* @__PURE__ */ new Map();
7034
+ for (const event of this.events) {
7035
+ const key = keyFn(event);
7036
+ const entry = map.get(key) || { attempts: 0, successes: 0 };
7037
+ entry.attempts++;
7038
+ if (event.outcome === "accepted") {
7039
+ entry.successes++;
7040
+ }
7041
+ map.set(key, entry);
7042
+ }
7043
+ const result = {};
7044
+ for (const [key, { attempts, successes }] of map) {
7045
+ result[key] = {
7046
+ attempts,
7047
+ successes,
7048
+ rate: attempts > 0 ? successes / attempts : 0
7049
+ };
7050
+ }
7051
+ return result;
7052
+ }
7053
+ };
7054
+
4005
7055
  // src/parsing/multi-statement.ts
4006
7056
  function createMultiStatementParser(dsl, config) {
4007
7057
  return new MultiStatementParserImpl(dsl, config);
@@ -4241,10 +7291,12 @@ function accumulateIndented(statements, config) {
4241
7291
  }
4242
7292
  export {
4243
7293
  AOTOrchestrator,
7294
+ BaseMorphologicalNormalizer,
4244
7295
  BaseTokenizer,
4245
7296
  CrossDomainDispatcher,
4246
7297
  DEFAULT_OPERATORS,
4247
7298
  DEFAULT_PUNCTUATION,
7299
+ DEFAULT_REFERENCES,
4248
7300
  DomainAwareScanner,
4249
7301
  DomainRegistry,
4250
7302
  GrammarTransformer,
@@ -4256,24 +7308,31 @@ export {
4256
7308
  NumberExtractor,
4257
7309
  OperatorExtractor,
4258
7310
  PatternMatcher,
7311
+ PatternTracker,
4259
7312
  PunctuationExtractor,
4260
7313
  StringLiteralExtractor,
4261
7314
  TokenStreamImpl,
4262
7315
  UnicodeIdentifierExtractor,
4263
7316
  WhitespaceExtractor,
4264
7317
  accumulateBlocks,
7318
+ buildDisambiguation,
7319
+ buildFeedback,
4265
7320
  buildPhrase,
4266
7321
  buildTablesFromProfiles,
4267
7322
  combineClassifiers,
7323
+ convertValue,
7324
+ createAsyncNode,
4268
7325
  createCommandNode,
4269
7326
  createCompoundNode,
4270
7327
  createConditionalNode,
4271
7328
  createDiagnosticCollector,
4272
7329
  createEventHandlerNode,
4273
7330
  createExpression,
7331
+ createFlag,
4274
7332
  createLatinCharClassifiers,
4275
7333
  createLiteral,
4276
7334
  createLoopNode,
7335
+ createMatchNode,
4277
7336
  createMultiStatementParser,
4278
7337
  createMultilingualDSL,
4279
7338
  createPosition,
@@ -4284,6 +7343,7 @@ export {
4284
7343
  createSimpleTokenizer,
4285
7344
  createToken,
4286
7345
  createTokenizerContext,
7346
+ createTryNode,
4287
7347
  createUnicodeRangeClassifier,
4288
7348
  defineCommand,
4289
7349
  defineRole,
@@ -4295,9 +7355,15 @@ export {
4295
7355
  extractUrl,
4296
7356
  extractValue,
4297
7357
  filterBySeverity,
7358
+ fromEnvelopeJSON,
4298
7359
  fromError,
7360
+ fromInterchangeNode,
7361
+ fromProtocolJSON,
7362
+ generateExamples,
4299
7363
  generatePattern,
4300
7364
  generatePatternVariants,
7365
+ generatePrompt,
7366
+ generateProtocolReference,
4301
7367
  getAllPossessiveKeywords,
4302
7368
  getDefaultExtractors,
4303
7369
  getPossessiveReference,
@@ -4308,8 +7374,12 @@ export {
4308
7374
  isCSSPropertyRef,
4309
7375
  isCSSSelector,
4310
7376
  isClassName,
7377
+ isCompoundSyntax,
4311
7378
  isContextAwareExtractor,
4312
7379
  isDigit,
7380
+ isDocumentSyntax,
7381
+ isEnvelope,
7382
+ isExplicitSyntax,
4313
7383
  isIdSelector,
4314
7384
  isNumericValue,
4315
7385
  isPossessiveKeyword,
@@ -4319,17 +7389,38 @@ export {
4319
7389
  isSelectorStart,
4320
7390
  isTypeCompatible,
4321
7391
  isUrlStart,
7392
+ isValidReference2 as isValidReference,
4322
7393
  isVariableRef,
4323
7394
  isWhitespace,
4324
7395
  joinTokens,
7396
+ jsonToSemanticNode,
4325
7397
  lookupKeyword,
4326
7398
  lookupMarker,
4327
7399
  matchBest,
4328
7400
  matchPattern,
7401
+ needsDisambiguation,
4329
7402
  noChange,
4330
7403
  normalized,
7404
+ parseCompound,
7405
+ parseDocument,
7406
+ parseExplicit,
7407
+ parseJSONL,
4331
7408
  patternMatcher,
7409
+ registryToAOTBackends,
7410
+ renderDocument,
7411
+ renderExplicit,
7412
+ renderExpr,
4332
7413
  reorderRoles,
7414
+ semanticNodeToJSON,
7415
+ semanticNodeToRuntimeAST,
7416
+ semanticValueToAST,
7417
+ synthesizeFromSchemas,
7418
+ toEnvelopeJSON,
7419
+ toJSONL,
7420
+ toJSONLRow,
7421
+ toProtocolJSON,
7422
+ validateProtocolJSON,
7423
+ validateSemanticJSON,
4333
7424
  validateValueType,
4334
7425
  withDefaultExtractors
4335
7426
  };