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