@hyperfixi/patterns-reference 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.
@@ -0,0 +1,731 @@
1
+ import Database from 'better-sqlite3';
2
+ import { fileURLToPath } from 'url';
3
+ import { dirname, join } from 'path';
4
+
5
+ // src/database/connection.ts
6
+ var __filename$1 = fileURLToPath(import.meta.url);
7
+ var __dirname$1 = dirname(__filename$1);
8
+ var DEFAULT_DB_PATH = process.env.LSP_DB_PATH || process.env.HYPERSCRIPT_LSP_DB || join(__dirname$1, "../data/patterns.db");
9
+ var dbInstance = null;
10
+ var currentDbPath = null;
11
+ function getDatabase(options = {}) {
12
+ const dbPath = options.dbPath ?? DEFAULT_DB_PATH;
13
+ if (dbInstance !== null && currentDbPath === dbPath) {
14
+ return dbInstance;
15
+ }
16
+ if (dbInstance !== null) {
17
+ dbInstance.close();
18
+ }
19
+ dbInstance = new Database(dbPath, {
20
+ readonly: options.readonly ?? false
21
+ });
22
+ dbInstance.pragma("foreign_keys = ON");
23
+ currentDbPath = dbPath;
24
+ return dbInstance;
25
+ }
26
+
27
+ // src/api/patterns.ts
28
+ async function getPatternById(id, options) {
29
+ const db = getDatabase({ ...options, readonly: true });
30
+ const row = db.prepare(
31
+ `
32
+ SELECT id, title, raw_code, description, feature, engine, created_at
33
+ FROM code_examples
34
+ WHERE id = ?
35
+ `
36
+ ).get(id);
37
+ return row ? mapRowToPattern(row) : null;
38
+ }
39
+ async function getPatternsByCategory(category, options) {
40
+ const db = getDatabase({ ...options, readonly: true });
41
+ const rows = db.prepare(
42
+ `
43
+ SELECT id, title, raw_code, description, feature, engine, created_at
44
+ FROM code_examples
45
+ WHERE feature = ?
46
+ ORDER BY title
47
+ `
48
+ ).all(category);
49
+ return rows.map(mapRowToPattern);
50
+ }
51
+ async function getPatternsByCommand(command, options) {
52
+ const db = getDatabase({ ...options, readonly: true });
53
+ const rows = db.prepare(
54
+ `
55
+ SELECT id, title, raw_code, description, feature, engine, created_at
56
+ FROM code_examples
57
+ WHERE raw_code LIKE ?
58
+ ORDER BY title
59
+ `
60
+ ).all(`%${command}%`);
61
+ return rows.filter((row) => new RegExp(`\\b${command}\\b`, "i").test(row.raw_code)).map(mapRowToPattern);
62
+ }
63
+ async function searchPatterns(query, searchOptions = {}, connOptions) {
64
+ const db = getDatabase({ ...connOptions, readonly: true });
65
+ const { limit = 50, offset = 0 } = searchOptions;
66
+ const rows = db.prepare(
67
+ `
68
+ SELECT id, title, raw_code, description, feature, engine, created_at
69
+ FROM code_examples
70
+ WHERE title LIKE ? OR raw_code LIKE ? OR description LIKE ?
71
+ ORDER BY title
72
+ LIMIT ? OFFSET ?
73
+ `
74
+ ).all(`%${query}%`, `%${query}%`, `%${query}%`, limit, offset);
75
+ return rows.map(mapRowToPattern);
76
+ }
77
+ async function getAllPatterns(searchOptions = {}, connOptions) {
78
+ const db = getDatabase({ ...connOptions, readonly: true });
79
+ const { limit = 1e3, offset = 0 } = searchOptions;
80
+ const rows = db.prepare(
81
+ `
82
+ SELECT id, title, raw_code, description, feature, engine, created_at
83
+ FROM code_examples
84
+ ORDER BY title
85
+ LIMIT ? OFFSET ?
86
+ `
87
+ ).all(limit, offset);
88
+ return rows.map(mapRowToPattern);
89
+ }
90
+ async function getPatternStats(connOptions) {
91
+ const db = getDatabase({ ...connOptions, readonly: true });
92
+ const patternCount = db.prepare("SELECT COUNT(*) as count FROM code_examples").get();
93
+ const translationCount = db.prepare("SELECT COUNT(*) as count FROM pattern_translations").get();
94
+ const byLangRows = db.prepare(
95
+ `
96
+ SELECT
97
+ language,
98
+ COUNT(*) as count,
99
+ SUM(verified_parses) as verified_count
100
+ FROM pattern_translations
101
+ GROUP BY language
102
+ `
103
+ ).all();
104
+ const byLanguage = {};
105
+ for (const row of byLangRows) {
106
+ byLanguage[row.language] = {
107
+ count: row.count,
108
+ verifiedCount: row.verified_count
109
+ };
110
+ }
111
+ const byCatRows = db.prepare(
112
+ `
113
+ SELECT feature, COUNT(*) as count
114
+ FROM code_examples
115
+ WHERE feature IS NOT NULL
116
+ GROUP BY feature
117
+ `
118
+ ).all();
119
+ const byCategory = {};
120
+ for (const row of byCatRows) {
121
+ byCategory[row.feature] = row.count;
122
+ }
123
+ const avgConfResult = db.prepare("SELECT AVG(confidence) as avg FROM pattern_translations WHERE confidence > 0").get();
124
+ return {
125
+ totalPatterns: patternCount.count,
126
+ totalTranslations: translationCount.count,
127
+ byLanguage,
128
+ byCategory,
129
+ avgConfidence: avgConfResult.avg || 0
130
+ };
131
+ }
132
+ function mapRowToPattern(row) {
133
+ return {
134
+ id: row.id,
135
+ title: row.title,
136
+ description: row.description,
137
+ rawCode: row.raw_code,
138
+ category: row.feature,
139
+ primaryCommand: extractPrimaryCommand(row.raw_code),
140
+ tags: extractTags(row.raw_code),
141
+ difficulty: inferDifficulty(row.raw_code),
142
+ engine: row.engine || null,
143
+ createdAt: new Date(row.created_at)
144
+ };
145
+ }
146
+ function extractPrimaryCommand(code) {
147
+ const match = code.match(/^(on|toggle|put|set|add|remove|show|hide|wait|log|send|fetch|call)\b/i);
148
+ return match ? match[1].toLowerCase() : null;
149
+ }
150
+ function extractTags(code) {
151
+ const tags = [];
152
+ if (code.includes(".")) tags.push("class");
153
+ if (code.includes("#")) tags.push("id");
154
+ if (code.includes("on ")) tags.push("event");
155
+ if (code.includes("fetch")) tags.push("async");
156
+ if (code.includes("wait")) tags.push("timing");
157
+ return tags;
158
+ }
159
+ function inferDifficulty(code) {
160
+ const lines = code.split("\n").filter((l) => l.trim()).length;
161
+ if (lines === 1 && !code.includes("then")) return "beginner";
162
+ if (lines <= 3) return "intermediate";
163
+ return "advanced";
164
+ }
165
+
166
+ // src/api/translations.ts
167
+ async function getTranslation(patternId, language, options) {
168
+ const db = getDatabase({ ...options, readonly: true });
169
+ const row = db.prepare(
170
+ `
171
+ SELECT * FROM pattern_translations
172
+ WHERE code_example_id = ? AND language = ?
173
+ `
174
+ ).get(patternId, language);
175
+ return row ? mapRowToTranslation(row) : null;
176
+ }
177
+ async function getAllTranslations(patternId, options) {
178
+ const db = getDatabase({ ...options, readonly: true });
179
+ const rows = db.prepare(
180
+ `
181
+ SELECT * FROM pattern_translations
182
+ WHERE code_example_id = ?
183
+ ORDER BY language
184
+ `
185
+ ).all(patternId);
186
+ return rows.map(mapRowToTranslation);
187
+ }
188
+ async function getTranslationsByLanguage(language, limit = 100, options) {
189
+ const db = getDatabase({ ...options, readonly: true });
190
+ const rows = db.prepare(
191
+ `
192
+ SELECT * FROM pattern_translations
193
+ WHERE language = ?
194
+ ORDER BY confidence DESC
195
+ LIMIT ?
196
+ `
197
+ ).all(language, limit);
198
+ return rows.map(mapRowToTranslation);
199
+ }
200
+ async function getVerifiedTranslations(language, limit = 100, options) {
201
+ const db = getDatabase({ ...options, readonly: true });
202
+ const rows = db.prepare(
203
+ `
204
+ SELECT * FROM pattern_translations
205
+ WHERE language = ? AND verified_parses = 1
206
+ ORDER BY confidence DESC
207
+ LIMIT ?
208
+ `
209
+ ).all(language, limit);
210
+ return rows.map(mapRowToTranslation);
211
+ }
212
+ async function getHighConfidenceTranslations(minConfidence = 0.8, limit = 100, options) {
213
+ const db = getDatabase({ ...options, readonly: true });
214
+ const rows = db.prepare(
215
+ `
216
+ SELECT * FROM pattern_translations
217
+ WHERE confidence >= ? AND verified_parses = 1
218
+ ORDER BY confidence DESC
219
+ LIMIT ?
220
+ `
221
+ ).all(minConfidence, limit);
222
+ return rows.map(mapRowToTranslation);
223
+ }
224
+ async function verifyTranslation(translation, options) {
225
+ let parseSuccess = false;
226
+ let errorMessage = null;
227
+ let confidence = translation.confidence;
228
+ try {
229
+ const { canParse, parse } = await import('@lokascript/semantic');
230
+ if (canParse(translation.hyperscript, translation.language)) {
231
+ parse(translation.hyperscript, translation.language);
232
+ parseSuccess = true;
233
+ } else {
234
+ errorMessage = "canParse returned false";
235
+ }
236
+ } catch (e) {
237
+ errorMessage = e.message;
238
+ }
239
+ const db = getDatabase(options);
240
+ db.prepare(
241
+ `
242
+ UPDATE pattern_translations
243
+ SET verified_parses = ?, updated_at = datetime('now')
244
+ WHERE id = ?
245
+ `
246
+ ).run(parseSuccess ? 1 : 0, translation.id);
247
+ db.prepare(
248
+ `
249
+ INSERT INTO pattern_tests
250
+ (code_example_id, language, test_date, parse_success, error_message)
251
+ VALUES (?, ?, datetime('now'), ?, ?)
252
+ `
253
+ ).run(translation.codeExampleId, translation.language, parseSuccess ? 1 : 0, errorMessage);
254
+ return {
255
+ translation,
256
+ parseSuccess,
257
+ executeSuccess: false,
258
+ // Not implemented yet
259
+ errorMessage,
260
+ confidence,
261
+ testedAt: /* @__PURE__ */ new Date()
262
+ };
263
+ }
264
+ async function getTranslationStats(options) {
265
+ const db = getDatabase({ ...options, readonly: true });
266
+ const rows = db.prepare(
267
+ `
268
+ SELECT
269
+ language,
270
+ COUNT(*) as total,
271
+ SUM(verified_parses) as verified,
272
+ AVG(confidence) as avg_confidence
273
+ FROM pattern_translations
274
+ GROUP BY language
275
+ `
276
+ ).all();
277
+ const stats = {};
278
+ for (const row of rows) {
279
+ stats[row.language] = {
280
+ total: row.total,
281
+ verified: row.verified,
282
+ avgConfidence: row.avg_confidence || 0
283
+ };
284
+ }
285
+ return stats;
286
+ }
287
+ function mapRowToTranslation(row) {
288
+ return {
289
+ id: row.id,
290
+ codeExampleId: row.code_example_id,
291
+ language: row.language,
292
+ hyperscript: row.hyperscript,
293
+ wordOrder: row.word_order,
294
+ translationMethod: row.translation_method,
295
+ confidence: row.confidence,
296
+ verifiedParses: row.verified_parses === 1,
297
+ verifiedExecutes: row.verified_executes === 1,
298
+ roleAlignmentScore: row.role_alignment_score ?? null,
299
+ createdAt: new Date(row.created_at),
300
+ updatedAt: new Date(row.updated_at)
301
+ };
302
+ }
303
+ function getWordOrder(language) {
304
+ const wordOrders = {
305
+ en: "SVO",
306
+ es: "SVO",
307
+ fr: "SVO",
308
+ pt: "SVO",
309
+ id: "SVO",
310
+ sw: "SVO",
311
+ zh: "SVO",
312
+ ja: "SOV",
313
+ ko: "SOV",
314
+ tr: "SOV",
315
+ qu: "SOV",
316
+ ar: "VSO",
317
+ de: "V2"
318
+ };
319
+ return wordOrders[language] || "SVO";
320
+ }
321
+
322
+ // src/api/llm.ts
323
+ async function getLLMExamples(prompt, language = "en", limit = 5, options) {
324
+ const db = getDatabase({ ...options, readonly: true });
325
+ const keywords = extractKeywords(prompt);
326
+ if (keywords.length === 0) {
327
+ const rows2 = db.prepare(
328
+ `
329
+ SELECT * FROM llm_examples
330
+ WHERE language = ?
331
+ ORDER BY quality_score DESC, usage_count DESC
332
+ LIMIT ?
333
+ `
334
+ ).all(language, limit);
335
+ trackUsage(
336
+ db,
337
+ rows2.map((r) => r.id)
338
+ );
339
+ return rows2.map(mapRowToLLMExample);
340
+ }
341
+ const likeClauses = keywords.map(() => "(prompt LIKE ? OR completion LIKE ?)").join(" OR ");
342
+ const params = keywords.flatMap((k) => [`%${k}%`, `%${k}%`]);
343
+ const rows = db.prepare(
344
+ `
345
+ SELECT * FROM llm_examples
346
+ WHERE language = ? AND (${likeClauses})
347
+ ORDER BY quality_score DESC
348
+ LIMIT ?
349
+ `
350
+ ).all(language, ...params, limit);
351
+ trackUsage(
352
+ db,
353
+ rows.map((r) => r.id)
354
+ );
355
+ return rows.map(mapRowToLLMExample);
356
+ }
357
+ async function getExamplesByCommand(command, language = "en", limit = 5, options) {
358
+ const db = getDatabase({ ...options, readonly: true });
359
+ const rows = db.prepare(
360
+ `
361
+ SELECT * FROM llm_examples
362
+ WHERE language = ? AND completion LIKE ?
363
+ ORDER BY quality_score DESC
364
+ LIMIT ?
365
+ `
366
+ ).all(language, `%${command}%`, limit);
367
+ return rows.map(mapRowToLLMExample);
368
+ }
369
+ async function getHighQualityExamples(language = "en", minQuality = 0.8, limit = 10, options) {
370
+ const db = getDatabase({ ...options, readonly: true });
371
+ const rows = db.prepare(
372
+ `
373
+ SELECT * FROM llm_examples
374
+ WHERE language = ? AND quality_score >= ?
375
+ ORDER BY quality_score DESC, usage_count DESC
376
+ LIMIT ?
377
+ `
378
+ ).all(language, minQuality, limit);
379
+ return rows.map(mapRowToLLMExample);
380
+ }
381
+ async function getMostUsedExamples(language = "en", limit = 10, options) {
382
+ const db = getDatabase({ ...options, readonly: true });
383
+ const rows = db.prepare(
384
+ `
385
+ SELECT * FROM llm_examples
386
+ WHERE language = ?
387
+ ORDER BY usage_count DESC, quality_score DESC
388
+ LIMIT ?
389
+ `
390
+ ).all(language, limit);
391
+ return rows.map(mapRowToLLMExample);
392
+ }
393
+ async function buildFewShotContext(prompt, language = "en", numExamples = 3, options) {
394
+ const examples = await getLLMExamples(prompt, language, numExamples, options);
395
+ if (examples.length === 0) {
396
+ return "";
397
+ }
398
+ let context = "Here are some example hyperscript patterns:\n\n";
399
+ for (const ex of examples) {
400
+ context += `Task: ${ex.prompt}
401
+ `;
402
+ context += `Code: ${ex.completion}
403
+
404
+ `;
405
+ }
406
+ context += `Now generate hyperscript for: ${prompt}
407
+ `;
408
+ return context;
409
+ }
410
+ async function addLLMExample(example, options) {
411
+ const db = getDatabase(options);
412
+ const result = db.prepare(
413
+ `
414
+ INSERT INTO llm_examples
415
+ (code_example_id, language, prompt, completion, quality_score, usage_count, created_at)
416
+ VALUES (?, ?, ?, ?, ?, 0, datetime('now'))
417
+ `
418
+ ).run(
419
+ example.patternId,
420
+ example.language,
421
+ example.prompt,
422
+ example.completion,
423
+ example.qualityScore
424
+ );
425
+ return result.lastInsertRowid;
426
+ }
427
+ async function updateQualityScore(id, qualityScore, options) {
428
+ const db = getDatabase(options);
429
+ db.prepare(
430
+ `
431
+ UPDATE llm_examples SET quality_score = ? WHERE id = ?
432
+ `
433
+ ).run(qualityScore, id);
434
+ }
435
+ async function getLLMStats(options) {
436
+ const db = getDatabase({ ...options, readonly: true });
437
+ const totalResult = db.prepare("SELECT COUNT(*) as count FROM llm_examples").get();
438
+ const byLangResult = db.prepare(
439
+ `
440
+ SELECT language, COUNT(*) as count
441
+ FROM llm_examples
442
+ GROUP BY language
443
+ `
444
+ ).all();
445
+ const avgResult = db.prepare("SELECT AVG(quality_score) as avg FROM llm_examples").get();
446
+ const usageResult = db.prepare("SELECT SUM(usage_count) as total FROM llm_examples").get();
447
+ const byLanguage = {};
448
+ for (const { language, count } of byLangResult) {
449
+ byLanguage[language] = count;
450
+ }
451
+ return {
452
+ total: totalResult.count,
453
+ byLanguage,
454
+ avgQuality: avgResult.avg || 0,
455
+ totalUsage: usageResult.total || 0
456
+ };
457
+ }
458
+ function extractKeywords(prompt) {
459
+ const stopWords = /* @__PURE__ */ new Set([
460
+ "a",
461
+ "an",
462
+ "the",
463
+ "to",
464
+ "on",
465
+ "in",
466
+ "for",
467
+ "is",
468
+ "it",
469
+ "when",
470
+ "i",
471
+ "want",
472
+ "need",
473
+ "create",
474
+ "make",
475
+ "please",
476
+ "can",
477
+ "you",
478
+ "would",
479
+ "should",
480
+ "like",
481
+ "that",
482
+ "this",
483
+ "with",
484
+ "from"
485
+ ]);
486
+ return prompt.toLowerCase().split(/\W+/).filter((word) => word.length > 2 && !stopWords.has(word));
487
+ }
488
+ function trackUsage(db, ids) {
489
+ if (ids.length === 0) return;
490
+ try {
491
+ const stmt = db.prepare(`
492
+ UPDATE llm_examples SET usage_count = usage_count + 1 WHERE id = ?
493
+ `);
494
+ for (const id of ids) {
495
+ stmt.run(id);
496
+ }
497
+ } catch {
498
+ }
499
+ }
500
+ function mapRowToLLMExample(row) {
501
+ return {
502
+ id: row.id,
503
+ patternId: row.code_example_id,
504
+ language: row.language,
505
+ prompt: row.prompt,
506
+ completion: row.completion,
507
+ qualityScore: row.quality_score,
508
+ usageCount: row.usage_count,
509
+ createdAt: new Date(row.created_at)
510
+ };
511
+ }
512
+
513
+ // src/api/roles.ts
514
+ async function getPatternRoles(patternId, options) {
515
+ const db = getDatabase({ ...options, readonly: true });
516
+ const rows = db.prepare(
517
+ `
518
+ SELECT id, code_example_id, command_index, role, role_value, role_type, required
519
+ FROM pattern_roles
520
+ WHERE code_example_id = ?
521
+ ORDER BY command_index, role
522
+ `
523
+ ).all(patternId);
524
+ return rows.map(mapRowToPatternRole);
525
+ }
526
+ async function getPatternsByRole(role, options) {
527
+ const db = getDatabase({ ...options, readonly: true });
528
+ const rows = db.prepare(
529
+ `
530
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
531
+ FROM code_examples ce
532
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
533
+ WHERE pr.role = ?
534
+ ORDER BY ce.title
535
+ `
536
+ ).all(role);
537
+ return rows.map(mapRowToPattern2);
538
+ }
539
+ async function getPatternsByRoles(roles, matchMode = "any", options) {
540
+ if (roles.length === 0) return [];
541
+ const db = getDatabase({ ...options, readonly: true });
542
+ if (matchMode === "any") {
543
+ const placeholders = roles.map(() => "?").join(", ");
544
+ const rows = db.prepare(
545
+ `
546
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
547
+ FROM code_examples ce
548
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
549
+ WHERE pr.role IN (${placeholders})
550
+ ORDER BY ce.title
551
+ `
552
+ ).all(...roles);
553
+ return rows.map(mapRowToPattern2);
554
+ } else {
555
+ const placeholders = roles.map(() => "?").join(", ");
556
+ const rows = db.prepare(
557
+ `
558
+ SELECT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
559
+ FROM code_examples ce
560
+ WHERE (
561
+ SELECT COUNT(DISTINCT pr.role)
562
+ FROM pattern_roles pr
563
+ WHERE pr.code_example_id = ce.id AND pr.role IN (${placeholders})
564
+ ) = ?
565
+ ORDER BY ce.title
566
+ `
567
+ ).all(...roles, roles.length);
568
+ return rows.map(mapRowToPattern2);
569
+ }
570
+ }
571
+ async function getPatternsByRoleValue(role, value, options) {
572
+ const db = getDatabase({ ...options, readonly: true });
573
+ const rows = db.prepare(
574
+ `
575
+ SELECT DISTINCT ce.id, ce.title, ce.raw_code, ce.description, ce.feature, ce.engine, ce.created_at
576
+ FROM code_examples ce
577
+ INNER JOIN pattern_roles pr ON ce.id = pr.code_example_id
578
+ WHERE pr.role = ? AND pr.role_value LIKE ?
579
+ ORDER BY ce.title
580
+ `
581
+ ).all(role, `%${value}%`);
582
+ return rows.map(mapRowToPattern2);
583
+ }
584
+ async function getRoleStats(options) {
585
+ const db = getDatabase({ ...options, readonly: true });
586
+ const totalRow = db.prepare("SELECT COUNT(*) as count FROM pattern_roles").get();
587
+ const roleRows = db.prepare(
588
+ `
589
+ SELECT role, COUNT(*) as count
590
+ FROM pattern_roles
591
+ GROUP BY role
592
+ ORDER BY count DESC
593
+ `
594
+ ).all();
595
+ const byRole = {};
596
+ for (const row of roleRows) {
597
+ byRole[row.role] = row.count;
598
+ }
599
+ const typeRows = db.prepare(
600
+ `
601
+ SELECT role_type, COUNT(*) as count
602
+ FROM pattern_roles
603
+ WHERE role_type IS NOT NULL
604
+ GROUP BY role_type
605
+ `
606
+ ).all();
607
+ const byRoleType = {};
608
+ for (const row of typeRows) {
609
+ byRoleType[row.role_type] = row.count;
610
+ }
611
+ const valueRows = db.prepare(
612
+ `
613
+ SELECT role, role_value, COUNT(*) as count
614
+ FROM pattern_roles
615
+ WHERE role_value IS NOT NULL
616
+ GROUP BY role, role_value
617
+ ORDER BY count DESC
618
+ LIMIT 20
619
+ `
620
+ ).all();
621
+ const topRoleValues = valueRows.map((row) => ({
622
+ role: row.role,
623
+ value: row.role_value,
624
+ count: row.count
625
+ }));
626
+ const withRolesRow = db.prepare(
627
+ `
628
+ SELECT COUNT(DISTINCT code_example_id) as count
629
+ FROM pattern_roles
630
+ `
631
+ ).get();
632
+ const totalPatternsRow = db.prepare("SELECT COUNT(*) as count FROM code_examples").get();
633
+ return {
634
+ totalRoles: totalRow.count,
635
+ byRole,
636
+ byRoleType,
637
+ topRoleValues,
638
+ patternsWithRoles: withRolesRow.count,
639
+ patternsWithoutRoles: totalPatternsRow.count - withRolesRow.count
640
+ };
641
+ }
642
+ async function getRolesByCommand(command, options) {
643
+ const db = getDatabase({ ...options, readonly: true });
644
+ const rows = db.prepare(
645
+ `
646
+ SELECT pr.role, COUNT(*) as count
647
+ FROM pattern_roles pr
648
+ INNER JOIN code_examples ce ON pr.code_example_id = ce.id
649
+ WHERE ce.raw_code LIKE ?
650
+ GROUP BY pr.role
651
+ `
652
+ ).all(`%${command}%`);
653
+ const result = {};
654
+ for (const row of rows) {
655
+ result[row.role] = row.count;
656
+ }
657
+ return result;
658
+ }
659
+ async function insertPatternRole(role, options) {
660
+ const db = getDatabase(options);
661
+ const result = db.prepare(
662
+ `
663
+ INSERT INTO pattern_roles (code_example_id, command_index, role, role_value, role_type, required)
664
+ VALUES (?, ?, ?, ?, ?, ?)
665
+ `
666
+ ).run(
667
+ role.codeExampleId,
668
+ role.commandIndex,
669
+ role.role,
670
+ role.roleValue,
671
+ role.roleType,
672
+ role.required ? 1 : 0
673
+ );
674
+ return result.lastInsertRowid;
675
+ }
676
+ async function deletePatternRoles(patternId, options) {
677
+ const db = getDatabase(options);
678
+ const result = db.prepare("DELETE FROM pattern_roles WHERE code_example_id = ?").run(patternId);
679
+ return result.changes;
680
+ }
681
+ async function clearAllRoles(options) {
682
+ const db = getDatabase(options);
683
+ const result = db.prepare("DELETE FROM pattern_roles").run();
684
+ return result.changes;
685
+ }
686
+ function mapRowToPatternRole(row) {
687
+ return {
688
+ id: row.id,
689
+ codeExampleId: row.code_example_id,
690
+ commandIndex: row.command_index,
691
+ role: row.role,
692
+ roleValue: row.role_value,
693
+ roleType: row.role_type,
694
+ required: Boolean(row.required)
695
+ };
696
+ }
697
+ function mapRowToPattern2(row) {
698
+ return {
699
+ id: row.id,
700
+ title: row.title,
701
+ description: row.description,
702
+ rawCode: row.raw_code,
703
+ category: row.feature,
704
+ primaryCommand: extractPrimaryCommand2(row.raw_code),
705
+ tags: extractTags2(row.raw_code),
706
+ difficulty: inferDifficulty2(row.raw_code),
707
+ engine: row.engine || null,
708
+ createdAt: new Date(row.created_at)
709
+ };
710
+ }
711
+ function extractPrimaryCommand2(code) {
712
+ const match = code.match(/^(on|toggle|put|set|add|remove|show|hide|wait|log|send|fetch|call)\b/i);
713
+ return match ? match[1].toLowerCase() : null;
714
+ }
715
+ function extractTags2(code) {
716
+ const tags = [];
717
+ if (code.includes(".")) tags.push("class");
718
+ if (code.includes("#")) tags.push("id");
719
+ if (code.includes("on ")) tags.push("event");
720
+ if (code.includes("fetch")) tags.push("async");
721
+ if (code.includes("wait")) tags.push("timing");
722
+ return tags;
723
+ }
724
+ function inferDifficulty2(code) {
725
+ const lines = code.split("\n").filter((l) => l.trim()).length;
726
+ if (lines === 1 && !code.includes("then")) return "beginner";
727
+ if (lines <= 3) return "intermediate";
728
+ return "advanced";
729
+ }
730
+
731
+ export { addLLMExample, buildFewShotContext, clearAllRoles, deletePatternRoles, getAllPatterns, getAllTranslations, getExamplesByCommand, getHighConfidenceTranslations, getHighQualityExamples, getLLMExamples, getLLMStats, getMostUsedExamples, getPatternById, getPatternRoles, getPatternStats, getPatternsByCategory, getPatternsByCommand, getPatternsByRole, getPatternsByRoleValue, getPatternsByRoles, getRoleStats, getRolesByCommand, getTranslation, getTranslationStats, getTranslationsByLanguage, getVerifiedTranslations, getWordOrder, insertPatternRole, searchPatterns, updateQualityScore, verifyTranslation };