@lokascript/framework 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +142 -0
  3. package/dist/aot/aot-orchestrator.d.ts +75 -0
  4. package/dist/aot/aot-orchestrator.d.ts.map +1 -0
  5. package/dist/aot/domain-scanner.d.ts +27 -0
  6. package/dist/aot/domain-scanner.d.ts.map +1 -0
  7. package/dist/aot/index.d.ts +8 -0
  8. package/dist/aot/index.d.ts.map +1 -0
  9. package/dist/aot/types.d.ts +103 -0
  10. package/dist/aot/types.d.ts.map +1 -0
  11. package/dist/api/create-dsl.d.ts +91 -0
  12. package/dist/api/create-dsl.d.ts.map +1 -0
  13. package/dist/api/dispatcher.d.ts +108 -0
  14. package/dist/api/dispatcher.d.ts.map +1 -0
  15. package/dist/api/domain-registry.d.ts +152 -0
  16. package/dist/api/domain-registry.d.ts.map +1 -0
  17. package/dist/api/index.d.ts +7 -0
  18. package/dist/api/index.d.ts.map +1 -0
  19. package/dist/api/index.js +2082 -0
  20. package/dist/api/index.js.map +1 -0
  21. package/dist/core/index.d.ts +7 -0
  22. package/dist/core/index.d.ts.map +1 -0
  23. package/dist/core/index.js +2674 -0
  24. package/dist/core/index.js.map +1 -0
  25. package/dist/core/logger.d.ts +32 -0
  26. package/dist/core/logger.d.ts.map +1 -0
  27. package/dist/core/pattern-matching/index.d.ts +6 -0
  28. package/dist/core/pattern-matching/index.d.ts.map +1 -0
  29. package/dist/core/pattern-matching/index.js +1239 -0
  30. package/dist/core/pattern-matching/index.js.map +1 -0
  31. package/dist/core/pattern-matching/pattern-matcher.d.ts +239 -0
  32. package/dist/core/pattern-matching/pattern-matcher.d.ts.map +1 -0
  33. package/dist/core/pattern-matching/utils/index.d.ts +6 -0
  34. package/dist/core/pattern-matching/utils/index.d.ts.map +1 -0
  35. package/dist/core/pattern-matching/utils/possessive-keywords.d.ts +38 -0
  36. package/dist/core/pattern-matching/utils/possessive-keywords.d.ts.map +1 -0
  37. package/dist/core/pattern-matching/utils/type-validation.d.ts +63 -0
  38. package/dist/core/pattern-matching/utils/type-validation.d.ts.map +1 -0
  39. package/dist/core/tokenization/base-tokenizer.d.ts +344 -0
  40. package/dist/core/tokenization/base-tokenizer.d.ts.map +1 -0
  41. package/dist/core/tokenization/char-classifiers.d.ts +56 -0
  42. package/dist/core/tokenization/char-classifiers.d.ts.map +1 -0
  43. package/dist/core/tokenization/default-extractors.d.ts +48 -0
  44. package/dist/core/tokenization/default-extractors.d.ts.map +1 -0
  45. package/dist/core/tokenization/extractors/index.d.ts +9 -0
  46. package/dist/core/tokenization/extractors/index.d.ts.map +1 -0
  47. package/dist/core/tokenization/extractors/operator.d.ts +23 -0
  48. package/dist/core/tokenization/extractors/operator.d.ts.map +1 -0
  49. package/dist/core/tokenization/extractors/punctuation.d.ts +22 -0
  50. package/dist/core/tokenization/extractors/punctuation.d.ts.map +1 -0
  51. package/dist/core/tokenization/extractors.d.ts +61 -0
  52. package/dist/core/tokenization/extractors.d.ts.map +1 -0
  53. package/dist/core/tokenization/index.d.ts +11 -0
  54. package/dist/core/tokenization/index.d.ts.map +1 -0
  55. package/dist/core/tokenization/index.js +1345 -0
  56. package/dist/core/tokenization/index.js.map +1 -0
  57. package/dist/core/tokenization/morphology/index.d.ts +5 -0
  58. package/dist/core/tokenization/morphology/index.d.ts.map +1 -0
  59. package/dist/core/tokenization/morphology/types.d.ts +110 -0
  60. package/dist/core/tokenization/morphology/types.d.ts.map +1 -0
  61. package/dist/core/tokenization/token-utils.d.ts +111 -0
  62. package/dist/core/tokenization/token-utils.d.ts.map +1 -0
  63. package/dist/core/types.d.ts +382 -0
  64. package/dist/core/types.d.ts.map +1 -0
  65. package/dist/core/types.js +108 -0
  66. package/dist/core/types.js.map +1 -0
  67. package/dist/generation/diagnostics.d.ts +120 -0
  68. package/dist/generation/diagnostics.d.ts.map +1 -0
  69. package/dist/generation/index.d.ts +7 -0
  70. package/dist/generation/index.d.ts.map +1 -0
  71. package/dist/generation/index.js +339 -0
  72. package/dist/generation/index.js.map +1 -0
  73. package/dist/generation/pattern-generator.d.ts +48 -0
  74. package/dist/generation/pattern-generator.d.ts.map +1 -0
  75. package/dist/generation/renderer.d.ts +115 -0
  76. package/dist/generation/renderer.d.ts.map +1 -0
  77. package/dist/grammar/index.d.ts +10 -0
  78. package/dist/grammar/index.d.ts.map +1 -0
  79. package/dist/grammar/index.js +391 -0
  80. package/dist/grammar/index.js.map +1 -0
  81. package/dist/grammar/transformer.d.ts +56 -0
  82. package/dist/grammar/transformer.d.ts.map +1 -0
  83. package/dist/grammar/types.d.ts +236 -0
  84. package/dist/grammar/types.d.ts.map +1 -0
  85. package/dist/index.cjs +4454 -0
  86. package/dist/index.cjs.map +1 -0
  87. package/dist/index.d.ts +46 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +4336 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/interfaces/dictionary.d.ts +82 -0
  92. package/dist/interfaces/dictionary.d.ts.map +1 -0
  93. package/dist/interfaces/index.d.ts +10 -0
  94. package/dist/interfaces/index.d.ts.map +1 -0
  95. package/dist/interfaces/profile-provider.d.ts +67 -0
  96. package/dist/interfaces/profile-provider.d.ts.map +1 -0
  97. package/dist/interfaces/value-extractor.d.ts +168 -0
  98. package/dist/interfaces/value-extractor.d.ts.map +1 -0
  99. package/dist/multilingual/index.d.ts +8 -0
  100. package/dist/multilingual/index.d.ts.map +1 -0
  101. package/dist/multilingual/index.js +1 -0
  102. package/dist/multilingual/index.js.map +1 -0
  103. package/dist/parsing/index.d.ts +8 -0
  104. package/dist/parsing/index.d.ts.map +1 -0
  105. package/dist/parsing/index.js +1415 -0
  106. package/dist/parsing/index.js.map +1 -0
  107. package/dist/parsing/multi-statement.d.ts +265 -0
  108. package/dist/parsing/multi-statement.d.ts.map +1 -0
  109. package/dist/schema/command-schema.d.ts +78 -0
  110. package/dist/schema/command-schema.d.ts.map +1 -0
  111. package/dist/schema/index.d.ts +5 -0
  112. package/dist/schema/index.d.ts.map +1 -0
  113. package/dist/schema/index.js +25 -0
  114. package/dist/schema/index.js.map +1 -0
  115. package/dist/test-setup.d.ts +9 -0
  116. package/dist/test-setup.d.ts.map +1 -0
  117. package/dist/testing/index.d.ts +50 -0
  118. package/dist/testing/index.d.ts.map +1 -0
  119. package/dist/testing/index.js +16969 -0
  120. package/dist/testing/index.js.map +1 -0
  121. package/package.json +122 -0
  122. package/src/__test__/fixtures/sql-dsl.ts +232 -0
  123. package/src/__test__/sql-integration.test.ts +189 -0
  124. package/src/__test__/test-utils.ts +260 -0
  125. package/src/aot/aot-orchestrator.test.ts +413 -0
  126. package/src/aot/aot-orchestrator.ts +238 -0
  127. package/src/aot/domain-scanner.ts +178 -0
  128. package/src/aot/index.ts +8 -0
  129. package/src/aot/types.ts +124 -0
  130. package/src/api/create-dsl.ts +367 -0
  131. package/src/api/dispatcher.test.ts +336 -0
  132. package/src/api/dispatcher.ts +222 -0
  133. package/src/api/domain-registry.test.ts +336 -0
  134. package/src/api/domain-registry.ts +500 -0
  135. package/src/api/index.ts +7 -0
  136. package/src/core/index.ts +7 -0
  137. package/src/core/logger.ts +130 -0
  138. package/src/core/pattern-matching/index.ts +6 -0
  139. package/src/core/pattern-matching/pattern-matcher.test.ts +900 -0
  140. package/src/core/pattern-matching/pattern-matcher.ts +1548 -0
  141. package/src/core/pattern-matching/pattern-matcher.ts.backup +1267 -0
  142. package/src/core/pattern-matching/utils/index.ts +6 -0
  143. package/src/core/pattern-matching/utils/possessive-keywords.ts +55 -0
  144. package/src/core/pattern-matching/utils/type-validation.test.ts +316 -0
  145. package/src/core/pattern-matching/utils/type-validation.ts +134 -0
  146. package/src/core/tokenization/base-tokenizer.ts +916 -0
  147. package/src/core/tokenization/char-classifiers.ts +79 -0
  148. package/src/core/tokenization/create-simple-tokenizer.test.ts +260 -0
  149. package/src/core/tokenization/default-extractors.ts +69 -0
  150. package/src/core/tokenization/extractors/index.ts +9 -0
  151. package/src/core/tokenization/extractors/operator.ts +75 -0
  152. package/src/core/tokenization/extractors/punctuation.ts +39 -0
  153. package/src/core/tokenization/extractors.ts +452 -0
  154. package/src/core/tokenization/index.ts +11 -0
  155. package/src/core/tokenization/morphology/index.ts +5 -0
  156. package/src/core/tokenization/morphology/types.ts +211 -0
  157. package/src/core/tokenization/token-utils.ts +252 -0
  158. package/src/core/types.ts +589 -0
  159. package/src/generation/diagnostics.test.ts +171 -0
  160. package/src/generation/diagnostics.ts +239 -0
  161. package/src/generation/index.ts +7 -0
  162. package/src/generation/pattern-generator.test.ts +430 -0
  163. package/src/generation/pattern-generator.ts +315 -0
  164. package/src/generation/renderer.test.ts +266 -0
  165. package/src/generation/renderer.ts +244 -0
  166. package/src/grammar/index.ts +12 -0
  167. package/src/grammar/transformer.ts +159 -0
  168. package/src/grammar/types.ts +630 -0
  169. package/src/index.ts +157 -0
  170. package/src/interfaces/dictionary.ts +123 -0
  171. package/src/interfaces/index.ts +10 -0
  172. package/src/interfaces/profile-provider.ts +88 -0
  173. package/src/interfaces/value-extractor.ts +435 -0
  174. package/src/multilingual/index.ts +9 -0
  175. package/src/parsing/index.ts +27 -0
  176. package/src/parsing/multi-statement.test.ts +480 -0
  177. package/src/parsing/multi-statement.ts +648 -0
  178. package/src/schema/command-schema.ts +118 -0
  179. package/src/schema/index.ts +5 -0
  180. package/src/test-setup.ts +45 -0
  181. package/src/testing/index.ts +137 -0
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Domain Registry
3
+ *
4
+ * Provides auto-discovery and registration of framework domains for MCP servers.
5
+ * Instead of hardcoding tool definitions and dispatch logic per domain, domains
6
+ * export a `DomainDescriptor` and the registry generates everything automatically.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { DomainRegistry } from '@lokascript/framework';
11
+ *
12
+ * const registry = new DomainRegistry();
13
+ *
14
+ * // Register domains (each provides a descriptor)
15
+ * registry.register({
16
+ * name: 'sql',
17
+ * description: 'Natural language SQL',
18
+ * languages: ['en', 'es', 'ja', 'ar'],
19
+ * inputLabel: 'query',
20
+ * inputDescription: 'SQL query in natural language',
21
+ * getDSL: () => import('@lokascript/domain-sql').then(m => m.createSQLDSL()),
22
+ * getRenderer: () => import('@lokascript/domain-sql').then(m => m.renderSQL),
23
+ * });
24
+ *
25
+ * // Auto-generate MCP tool definitions
26
+ * const tools = registry.getToolDefinitions();
27
+ *
28
+ * // Dispatch a tool call
29
+ * const result = await registry.handleToolCall('parse_sql', { query: 'select name from users' });
30
+ * ```
31
+ */
32
+
33
+ import type { SemanticNode } from '../core/types';
34
+ import type { MultilingualDSL, CompileResult, ValidationResult } from './create-dsl';
35
+ import type { NaturalLanguageRenderer } from '../generation/renderer';
36
+
37
+ // =============================================================================
38
+ // Descriptor Interface
39
+ // =============================================================================
40
+
41
+ /**
42
+ * Describes a domain for auto-registration in MCP servers.
43
+ *
44
+ * Domains provide this descriptor to the registry, which generates
45
+ * tool definitions and handles dispatch automatically.
46
+ */
47
+ export interface DomainDescriptor {
48
+ /** Short identifier (used in tool names: parse_{name}, compile_{name}, etc.) */
49
+ readonly name: string;
50
+
51
+ /** Human-readable description */
52
+ readonly description: string;
53
+
54
+ /** Supported language codes */
55
+ readonly languages: readonly string[];
56
+
57
+ /** Label for the primary input parameter (e.g., 'query', 'scenario', 'code') */
58
+ readonly inputLabel: string;
59
+
60
+ /** Description of the primary input parameter */
61
+ readonly inputDescription: string;
62
+
63
+ /**
64
+ * Factory to lazily create the DSL instance.
65
+ * Called once on first tool use. The result is cached.
66
+ */
67
+ readonly getDSL: () => MultilingualDSL | Promise<MultilingualDSL>;
68
+
69
+ /**
70
+ * Factory to lazily create the renderer.
71
+ * Required for translate_{name} tool. Called once on first use.
72
+ */
73
+ readonly getRenderer?: () =>
74
+ | NaturalLanguageRenderer
75
+ | ((node: SemanticNode, language: string) => string)
76
+ | Promise<NaturalLanguageRenderer | ((node: SemanticNode, language: string) => string)>;
77
+
78
+ /**
79
+ * Which standard tools to generate. Default: all four.
80
+ */
81
+ readonly tools?: readonly ('parse' | 'compile' | 'validate' | 'translate')[];
82
+
83
+ /**
84
+ * Optional scan configuration for AOT compilation and Vite plugin.
85
+ * Declares which HTML attributes/script types this domain uses.
86
+ */
87
+ readonly scanConfig?: {
88
+ /** Attribute names to scan for (e.g., ['data-sql', '_sql']) */
89
+ readonly attributes: readonly string[];
90
+ /** Script tag types to scan for (e.g., ['text/sql-dsl']) */
91
+ readonly scriptTypes?: readonly string[];
92
+ /** Default language when not specified on element */
93
+ readonly defaultLanguage?: string;
94
+ /** Keywords for detection, keyed by language code */
95
+ readonly keywords?: Readonly<Record<string, readonly string[]>>;
96
+ };
97
+ }
98
+
99
+ // =============================================================================
100
+ // MCP Tool Types (minimal — compatible with @modelcontextprotocol/sdk)
101
+ // =============================================================================
102
+
103
+ /**
104
+ * MCP tool definition. Compatible with the MCP SDK's tool schema.
105
+ */
106
+ export interface MCPToolDefinition {
107
+ readonly name: string;
108
+ readonly description: string;
109
+ readonly inputSchema: {
110
+ readonly type: 'object';
111
+ readonly properties: Record<string, unknown>;
112
+ readonly required: readonly string[];
113
+ };
114
+ }
115
+
116
+ /**
117
+ * MCP tool response. Compatible with the MCP SDK's response format.
118
+ */
119
+ export interface MCPToolResponse {
120
+ readonly content: ReadonlyArray<{ readonly type: string; readonly text: string }>;
121
+ readonly isError?: boolean;
122
+ }
123
+
124
+ // =============================================================================
125
+ // Domain Registry
126
+ // =============================================================================
127
+
128
+ /**
129
+ * Registry for framework domains.
130
+ *
131
+ * Manages domain descriptors, generates MCP tool definitions,
132
+ * and dispatches tool calls to the appropriate domain.
133
+ */
134
+ export class DomainRegistry {
135
+ private descriptors = new Map<string, DomainDescriptor>();
136
+ private dslCache = new Map<string, MultilingualDSL>();
137
+ private rendererCache = new Map<
138
+ string,
139
+ NaturalLanguageRenderer | ((node: SemanticNode, language: string) => string)
140
+ >();
141
+
142
+ /**
143
+ * Register a domain.
144
+ * @throws if a domain with the same name is already registered
145
+ */
146
+ register(descriptor: DomainDescriptor): void {
147
+ if (this.descriptors.has(descriptor.name)) {
148
+ throw new Error(`Domain already registered: ${descriptor.name}`);
149
+ }
150
+ this.descriptors.set(descriptor.name, descriptor);
151
+ }
152
+
153
+ /**
154
+ * Get all registered domain names.
155
+ */
156
+ getDomainNames(): string[] {
157
+ return Array.from(this.descriptors.keys());
158
+ }
159
+
160
+ /**
161
+ * Get a specific domain descriptor.
162
+ */
163
+ getDescriptor(name: string): DomainDescriptor | undefined {
164
+ return this.descriptors.get(name);
165
+ }
166
+
167
+ /**
168
+ * Generate MCP tool definitions for all registered domains.
169
+ */
170
+ getToolDefinitions(): MCPToolDefinition[] {
171
+ const tools: MCPToolDefinition[] = [];
172
+ for (const desc of this.descriptors.values()) {
173
+ tools.push(...generateToolDefinitions(desc));
174
+ }
175
+ return tools;
176
+ }
177
+
178
+ /**
179
+ * Check if a tool name belongs to a registered domain.
180
+ */
181
+ canHandle(toolName: string): boolean {
182
+ const parsed = parseToolName(toolName);
183
+ if (!parsed) return false;
184
+ return this.descriptors.has(parsed.domain);
185
+ }
186
+
187
+ /**
188
+ * Handle a tool call by dispatching to the appropriate domain.
189
+ * Returns null if the tool name doesn't match any registered domain.
190
+ */
191
+ async handleToolCall(
192
+ toolName: string,
193
+ args: Record<string, unknown>
194
+ ): Promise<MCPToolResponse | null> {
195
+ const parsed = parseToolName(toolName);
196
+ if (!parsed) return null;
197
+
198
+ const descriptor = this.descriptors.get(parsed.domain);
199
+ if (!descriptor) return null;
200
+
201
+ try {
202
+ const dsl = await this.getDSL(descriptor);
203
+
204
+ switch (parsed.operation) {
205
+ case 'parse':
206
+ return await this.handleParse(descriptor, dsl, args);
207
+ case 'compile':
208
+ return await this.handleCompile(descriptor, dsl, args);
209
+ case 'validate':
210
+ return await this.handleValidate(descriptor, dsl, args);
211
+ case 'translate':
212
+ return await this.handleTranslate(descriptor, dsl, args);
213
+ default:
214
+ return jsonResponse({ error: `Unknown operation: ${parsed.operation}` }, true);
215
+ }
216
+ } catch (error) {
217
+ const message = error instanceof Error ? error.message : String(error);
218
+ return jsonResponse({ error: `${descriptor.name} tool error: ${message}` }, true);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Get the DSL instance for a named domain.
224
+ * Returns null if the domain is not registered.
225
+ * The DSL is lazily created and cached.
226
+ */
227
+ async getDSLForDomain(name: string): Promise<MultilingualDSL | null> {
228
+ const descriptor = this.descriptors.get(name);
229
+ if (!descriptor) return null;
230
+ return this.getDSL(descriptor);
231
+ }
232
+
233
+ // ---------------------------------------------------------------------------
234
+ // Private: DSL/renderer lifecycle
235
+ // ---------------------------------------------------------------------------
236
+
237
+ private async getDSL(descriptor: DomainDescriptor): Promise<MultilingualDSL> {
238
+ const cached = this.dslCache.get(descriptor.name);
239
+ if (cached) return cached;
240
+
241
+ const dsl = await descriptor.getDSL();
242
+ this.dslCache.set(descriptor.name, dsl);
243
+ return dsl;
244
+ }
245
+
246
+ private async getRenderer(
247
+ descriptor: DomainDescriptor
248
+ ): Promise<NaturalLanguageRenderer | ((node: SemanticNode, language: string) => string) | null> {
249
+ if (!descriptor.getRenderer) return null;
250
+
251
+ const cached = this.rendererCache.get(descriptor.name);
252
+ if (cached) return cached;
253
+
254
+ const renderer = await descriptor.getRenderer();
255
+ this.rendererCache.set(descriptor.name, renderer);
256
+ return renderer;
257
+ }
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // Private: Tool handlers
261
+ // ---------------------------------------------------------------------------
262
+
263
+ private async handleParse(
264
+ descriptor: DomainDescriptor,
265
+ dsl: MultilingualDSL,
266
+ args: Record<string, unknown>
267
+ ): Promise<MCPToolResponse> {
268
+ const input = getString(args, descriptor.inputLabel);
269
+ if (!input) return missingParam(descriptor.inputLabel);
270
+ const language = getString(args, 'language', 'en');
271
+
272
+ const node = dsl.parse(input, language);
273
+
274
+ const roles: Record<string, unknown> = {};
275
+ for (const [key, value] of node.roles) {
276
+ roles[key] = value;
277
+ }
278
+
279
+ return jsonResponse({
280
+ action: node.action,
281
+ roles,
282
+ language,
283
+ [descriptor.inputLabel]: input,
284
+ });
285
+ }
286
+
287
+ private async handleCompile(
288
+ descriptor: DomainDescriptor,
289
+ dsl: MultilingualDSL,
290
+ args: Record<string, unknown>
291
+ ): Promise<MCPToolResponse> {
292
+ const input = getString(args, descriptor.inputLabel);
293
+ if (!input) return missingParam(descriptor.inputLabel);
294
+ const language = getString(args, 'language', 'en');
295
+
296
+ const result: CompileResult = dsl.compile(input, language);
297
+
298
+ return jsonResponse({
299
+ ok: result.ok,
300
+ code: result.code,
301
+ errors: result.errors,
302
+ language,
303
+ input,
304
+ });
305
+ }
306
+
307
+ private async handleValidate(
308
+ descriptor: DomainDescriptor,
309
+ dsl: MultilingualDSL,
310
+ args: Record<string, unknown>
311
+ ): Promise<MCPToolResponse> {
312
+ const input = getString(args, descriptor.inputLabel);
313
+ if (!input) return missingParam(descriptor.inputLabel);
314
+ const language = getString(args, 'language', 'en');
315
+
316
+ const result: ValidationResult = dsl.validate(input, language);
317
+
318
+ return jsonResponse({
319
+ valid: result.valid,
320
+ errors: result.errors,
321
+ language,
322
+ [descriptor.inputLabel]: input,
323
+ });
324
+ }
325
+
326
+ private async handleTranslate(
327
+ descriptor: DomainDescriptor,
328
+ dsl: MultilingualDSL,
329
+ args: Record<string, unknown>
330
+ ): Promise<MCPToolResponse> {
331
+ const input = getString(args, descriptor.inputLabel);
332
+ if (!input) return missingParam(descriptor.inputLabel);
333
+ const from = getString(args, 'from');
334
+ if (!from) return missingParam('from');
335
+ const to = getString(args, 'to');
336
+ if (!to) return missingParam('to');
337
+
338
+ // Parse in source language
339
+ const node = dsl.parse(input, from);
340
+
341
+ // Compile (language-neutral output)
342
+ const compiled = dsl.compile(input, from);
343
+
344
+ // Render to target language
345
+ let rendered: string | null = null;
346
+ const renderer = await this.getRenderer(descriptor);
347
+ if (renderer) {
348
+ try {
349
+ rendered = typeof renderer === 'function' ? renderer(node, to) : renderer.render(node, to);
350
+ } catch {
351
+ // Fall through with rendered = null
352
+ }
353
+ }
354
+
355
+ const roles: Record<string, unknown> = {};
356
+ for (const [key, value] of node.roles) {
357
+ roles[key] = value;
358
+ }
359
+
360
+ return jsonResponse({
361
+ input: { [descriptor.inputLabel]: input, language: from },
362
+ ...(rendered != null && { rendered: { text: rendered, language: to } }),
363
+ semantic: { action: node.action, roles },
364
+ ...(compiled.ok && compiled.code != null && { compiled: compiled.code }),
365
+ });
366
+ }
367
+ }
368
+
369
+ // =============================================================================
370
+ // Tool Definition Generator
371
+ // =============================================================================
372
+
373
+ function generateToolDefinitions(desc: DomainDescriptor): MCPToolDefinition[] {
374
+ const tools: MCPToolDefinition[] = [];
375
+ const ops = desc.tools ?? (['parse', 'compile', 'validate', 'translate'] as const);
376
+ const langList = desc.languages.join(', ');
377
+
378
+ for (const op of ops) {
379
+ switch (op) {
380
+ case 'parse':
381
+ tools.push({
382
+ name: `parse_${desc.name}`,
383
+ description: `Parse a ${desc.description} input into a semantic representation. Supports: ${langList}.`,
384
+ inputSchema: {
385
+ type: 'object',
386
+ properties: {
387
+ [desc.inputLabel]: {
388
+ type: 'string',
389
+ description: desc.inputDescription,
390
+ },
391
+ language: {
392
+ type: 'string',
393
+ description: `Language code: ${langList}`,
394
+ default: 'en',
395
+ },
396
+ },
397
+ required: [desc.inputLabel],
398
+ },
399
+ });
400
+ break;
401
+
402
+ case 'compile':
403
+ tools.push({
404
+ name: `compile_${desc.name}`,
405
+ description: `Compile a ${desc.description} input to target code. Supports: ${langList}.`,
406
+ inputSchema: {
407
+ type: 'object',
408
+ properties: {
409
+ [desc.inputLabel]: {
410
+ type: 'string',
411
+ description: desc.inputDescription,
412
+ },
413
+ language: {
414
+ type: 'string',
415
+ description: `Language code: ${langList}`,
416
+ default: 'en',
417
+ },
418
+ },
419
+ required: [desc.inputLabel],
420
+ },
421
+ });
422
+ break;
423
+
424
+ case 'validate':
425
+ tools.push({
426
+ name: `validate_${desc.name}`,
427
+ description: `Validate ${desc.description} syntax. Returns whether it parses successfully and any errors. Supports: ${langList}.`,
428
+ inputSchema: {
429
+ type: 'object',
430
+ properties: {
431
+ [desc.inputLabel]: {
432
+ type: 'string',
433
+ description: `${desc.inputDescription} to validate`,
434
+ },
435
+ language: {
436
+ type: 'string',
437
+ description: `Language code: ${langList}`,
438
+ default: 'en',
439
+ },
440
+ },
441
+ required: [desc.inputLabel],
442
+ },
443
+ });
444
+ break;
445
+
446
+ case 'translate':
447
+ tools.push({
448
+ name: `translate_${desc.name}`,
449
+ description: `Translate ${desc.description} input between natural languages. Parses in source language and renders in target language.`,
450
+ inputSchema: {
451
+ type: 'object',
452
+ properties: {
453
+ [desc.inputLabel]: {
454
+ type: 'string',
455
+ description: `${desc.inputDescription} to translate`,
456
+ },
457
+ from: {
458
+ type: 'string',
459
+ description: `Source language code: ${langList}`,
460
+ },
461
+ to: {
462
+ type: 'string',
463
+ description: `Target language code: ${langList}`,
464
+ },
465
+ },
466
+ required: [desc.inputLabel, 'from', 'to'],
467
+ },
468
+ });
469
+ break;
470
+ }
471
+ }
472
+
473
+ return tools;
474
+ }
475
+
476
+ // =============================================================================
477
+ // Helpers
478
+ // =============================================================================
479
+
480
+ function parseToolName(name: string): { operation: string; domain: string } | null {
481
+ const match = name.match(/^(parse|compile|validate|translate)_(.+)$/);
482
+ if (!match) return null;
483
+ return { operation: match[1], domain: match[2] };
484
+ }
485
+
486
+ function getString(args: Record<string, unknown>, name: string, defaultValue = ''): string {
487
+ const value = args[name];
488
+ return typeof value === 'string' ? value : defaultValue;
489
+ }
490
+
491
+ function jsonResponse(data: unknown, isError?: boolean): MCPToolResponse {
492
+ return {
493
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
494
+ ...(isError && { isError: true }),
495
+ };
496
+ }
497
+
498
+ function missingParam(param: string): MCPToolResponse {
499
+ return jsonResponse({ error: `Missing required parameter: ${param}` }, true);
500
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Main API exports for @lokascript/framework
3
+ */
4
+
5
+ export * from './create-dsl';
6
+ export * from './domain-registry';
7
+ export * from './dispatcher';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Core types and utilities for the multilingual DSL framework
3
+ */
4
+
5
+ export * from './types';
6
+ export * from './tokenization';
7
+ export * from './pattern-matching';
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Debug Logging System
3
+ *
4
+ * Provides environment-aware debug logging for the framework.
5
+ * Enable via DEBUG environment variable or programmatically.
6
+ */
7
+
8
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
9
+
10
+ interface Logger {
11
+ debug(message: string, ...args: any[]): void;
12
+ info(message: string, ...args: any[]): void;
13
+ warn(message: string, ...args: any[]): void;
14
+ error(message: string, ...args: any[]): void;
15
+ isEnabled(): boolean;
16
+ }
17
+
18
+ class DebugLogger {
19
+ private enabled: boolean;
20
+ private namespace: string;
21
+
22
+ constructor(namespace: string) {
23
+ this.namespace = namespace;
24
+ this.enabled = this.checkEnabled();
25
+ }
26
+
27
+ private checkEnabled(): boolean {
28
+ // Check if running in Node.js
29
+ if (typeof process !== 'undefined' && process.env) {
30
+ const DEBUG = process.env.DEBUG || '';
31
+ // Enable if DEBUG=* or DEBUG=framework:* or DEBUG=framework:namespace
32
+ return (
33
+ DEBUG === '*' ||
34
+ DEBUG.includes('framework:*') ||
35
+ DEBUG.includes(`framework:${this.namespace}`)
36
+ );
37
+ }
38
+ return false;
39
+ }
40
+
41
+ private log(level: LogLevel, message: string, ...args: any[]): void {
42
+ if (!this.enabled) return;
43
+
44
+ const prefix = `[framework:${this.namespace}]`;
45
+ const timestamp = new Date().toISOString();
46
+
47
+ switch (level) {
48
+ case 'debug':
49
+ // eslint-disable-next-line no-console
50
+ console.debug(`${timestamp} ${prefix} DEBUG:`, message, ...args);
51
+ break;
52
+ case 'info':
53
+ // eslint-disable-next-line no-console
54
+ console.info(`${timestamp} ${prefix} INFO:`, message, ...args);
55
+ break;
56
+ case 'warn':
57
+ // eslint-disable-next-line no-console
58
+ console.warn(`${timestamp} ${prefix} WARN:`, message, ...args);
59
+ break;
60
+ case 'error':
61
+ // eslint-disable-next-line no-console
62
+ console.error(`${timestamp} ${prefix} ERROR:`, message, ...args);
63
+ break;
64
+ }
65
+ }
66
+
67
+ debug(message: string, ...args: any[]): void {
68
+ this.log('debug', message, ...args);
69
+ }
70
+
71
+ info(message: string, ...args: any[]): void {
72
+ this.log('info', message, ...args);
73
+ }
74
+
75
+ warn(message: string, ...args: any[]): void {
76
+ this.log('warn', message, ...args);
77
+ }
78
+
79
+ error(message: string, ...args: any[]): void {
80
+ this.log('error', message, ...args);
81
+ }
82
+
83
+ /**
84
+ * Check if logging is enabled for this namespace.
85
+ */
86
+ isEnabled(): boolean {
87
+ return this.enabled;
88
+ }
89
+
90
+ /**
91
+ * Programmatically enable logging for this namespace.
92
+ */
93
+ enable(): void {
94
+ this.enabled = true;
95
+ }
96
+
97
+ /**
98
+ * Programmatically disable logging for this namespace.
99
+ */
100
+ disable(): void {
101
+ this.enabled = false;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Create a logger for a specific namespace.
107
+ *
108
+ * @param namespace - Logger namespace (e.g., 'pattern-matcher', 'tokenizer')
109
+ * @returns Logger instance
110
+ *
111
+ * @example
112
+ * const logger = createLogger('pattern-matcher');
113
+ * logger.debug('Matching pattern:', pattern.id);
114
+ * logger.warn('Low confidence match:', confidence);
115
+ */
116
+ export function createLogger(namespace: string): Logger {
117
+ return new DebugLogger(namespace);
118
+ }
119
+
120
+ /**
121
+ * No-op logger that does nothing.
122
+ * Useful for disabling logging in production builds.
123
+ */
124
+ export const noopLogger: Logger = {
125
+ debug: () => {},
126
+ info: () => {},
127
+ warn: () => {},
128
+ error: () => {},
129
+ isEnabled: () => false,
130
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Pattern matching infrastructure for semantic parsing
3
+ */
4
+
5
+ export * from './pattern-matcher';
6
+ export * from './utils';