@cccarv82/freya 2.14.1 → 2.16.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/cli/web-ui.css +457 -3
- package/cli/web-ui.js +494 -229
- package/cli/web.js +460 -52
- package/package.json +2 -2
- package/scripts/lib/DataLayer.js +10 -1
- package/scripts/lib/DataManager.js +1 -0
- package/scripts/lib/Embedder.js +5 -1
- package/templates/base/scripts/lib/DataLayer.js +11 -2
- package/templates/base/scripts/lib/DataManager.js +15 -14
- package/templates/base/scripts/lib/Embedder.js +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cccarv82/freya",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.0",
|
|
4
4
|
"description": "Personal AI Assistant with local-first persistence",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"health": "node scripts/validate-data.js && node scripts/validate-structure.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
],
|
|
32
32
|
"preferGlobal": true,
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@
|
|
34
|
+
"@huggingface/transformers": "^3.8.1",
|
|
35
35
|
"pdf-lib": "^1.17.1",
|
|
36
36
|
"sql.js": "^1.12.0"
|
|
37
37
|
}
|
package/scripts/lib/DataLayer.js
CHANGED
|
@@ -319,13 +319,22 @@ class DataLayer {
|
|
|
319
319
|
CREATE TABLE IF NOT EXISTS document_embeddings (
|
|
320
320
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
321
321
|
reference_type TEXT NOT NULL, /* 'daily_log', 'task', 'blocker' */
|
|
322
|
-
reference_id TEXT NOT NULL,
|
|
322
|
+
reference_id TEXT NOT NULL,
|
|
323
323
|
chunk_index INTEGER DEFAULT 0,
|
|
324
324
|
text_chunk TEXT NOT NULL,
|
|
325
325
|
embedding BLOB NOT NULL, /* Stored as Buffer of Float32Array */
|
|
326
326
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
327
327
|
);
|
|
328
328
|
`);
|
|
329
|
+
|
|
330
|
+
// --- Migrations for existing databases ---
|
|
331
|
+
// Add due_date column to tasks (safe to run multiple times)
|
|
332
|
+
try {
|
|
333
|
+
const cols = this.db.prepare("PRAGMA table_info(tasks)").all();
|
|
334
|
+
if (!cols.some(c => c.name === 'due_date')) {
|
|
335
|
+
this.db.exec("ALTER TABLE tasks ADD COLUMN due_date TEXT");
|
|
336
|
+
}
|
|
337
|
+
} catch { /* ignore if PRAGMA not supported */ }
|
|
329
338
|
}
|
|
330
339
|
|
|
331
340
|
// Helper close method
|
package/scripts/lib/Embedder.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
class Embedder {
|
|
2
2
|
constructor() {
|
|
3
|
+
// V3: use the official HuggingFace model name (same weights, new namespace)
|
|
3
4
|
this.modelName = 'Xenova/all-MiniLM-L6-v2';
|
|
4
5
|
this.extractorInfo = null;
|
|
5
6
|
this.initPromise = null;
|
|
@@ -9,7 +10,9 @@ class Embedder {
|
|
|
9
10
|
if (this.extractorInfo) return;
|
|
10
11
|
if (!this.initPromise) {
|
|
11
12
|
this.initPromise = (async () => {
|
|
12
|
-
|
|
13
|
+
// V3: @huggingface/transformers replaces @xenova/transformers
|
|
14
|
+
// sharp 0.34+ uses prebuilt platform binaries (no node-gyp needed)
|
|
15
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
13
16
|
this.extractorInfo = await pipeline('feature-extraction', this.modelName, { quantized: true });
|
|
14
17
|
})().catch((err) => {
|
|
15
18
|
this.initPromise = null;
|
|
@@ -25,6 +28,7 @@ class Embedder {
|
|
|
25
28
|
if (!cleanText) return new Float32Array(384); // Empty zero vector for model
|
|
26
29
|
|
|
27
30
|
const output = await this.extractorInfo(cleanText, { pooling: 'mean', normalize: true });
|
|
31
|
+
// V3: output.data may be a typed array or need .tolist()
|
|
28
32
|
return new Float32Array(output.data);
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DataLayer.js (V2.1 - sql.js powered, no native compilation needed)
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Drop-in replacement for better-sqlite3 using sql.js (WebAssembly SQLite).
|
|
5
5
|
* Exposes the same API surface: .prepare().all(), .prepare().get(), .prepare().run(),
|
|
6
6
|
* .exec(), .pragma(), .transaction(), .close()
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* Auto-persists to disk after every write operation.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -326,6 +326,15 @@ class DataLayer {
|
|
|
326
326
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
327
327
|
);
|
|
328
328
|
`);
|
|
329
|
+
|
|
330
|
+
// --- Migrations for existing databases ---
|
|
331
|
+
// Add due_date column to tasks (safe to run multiple times)
|
|
332
|
+
try {
|
|
333
|
+
const cols = this.db.prepare("PRAGMA table_info(tasks)").all();
|
|
334
|
+
if (!cols.some(c => c.name === 'due_date')) {
|
|
335
|
+
this.db.exec("ALTER TABLE tasks ADD COLUMN due_date TEXT");
|
|
336
|
+
}
|
|
337
|
+
} catch { /* ignore if PRAGMA not supported */ }
|
|
329
338
|
}
|
|
330
339
|
|
|
331
340
|
// Helper close method
|
|
@@ -40,6 +40,7 @@ class DataManager {
|
|
|
40
40
|
status: t.status,
|
|
41
41
|
createdAt: t.created_at,
|
|
42
42
|
completedAt: t.completed_at,
|
|
43
|
+
dueDate: t.due_date || null,
|
|
43
44
|
priority: meta.priority,
|
|
44
45
|
streamSlug: meta.streamSlug
|
|
45
46
|
};
|
|
@@ -54,13 +55,13 @@ class DataManager {
|
|
|
54
55
|
|
|
55
56
|
const tasks = this.getTasksRaw();
|
|
56
57
|
const completed = dl.db.prepare(`
|
|
57
|
-
SELECT * FROM tasks
|
|
58
|
-
WHERE status = 'COMPLETED'
|
|
58
|
+
SELECT * FROM tasks
|
|
59
|
+
WHERE status = 'COMPLETED'
|
|
59
60
|
AND completed_at >= ? AND completed_at <= ?
|
|
60
61
|
`).all(startIso, endIso).map(t => ({ ...t, completedAt: t.completed_at, createdAt: t.created_at }));
|
|
61
62
|
|
|
62
63
|
const pending = dl.db.prepare(`
|
|
63
|
-
SELECT * FROM tasks
|
|
64
|
+
SELECT * FROM tasks
|
|
64
65
|
WHERE status = 'PENDING' AND category = 'DO_NOW'
|
|
65
66
|
`).all().map(t => ({ ...t, createdAt: t.created_at }));
|
|
66
67
|
|
|
@@ -100,27 +101,27 @@ class DataManager {
|
|
|
100
101
|
const blockers = this.getBlockersRaw();
|
|
101
102
|
|
|
102
103
|
const open = dl.db.prepare(`
|
|
103
|
-
SELECT * FROM blockers
|
|
104
|
+
SELECT * FROM blockers
|
|
104
105
|
WHERE status NOT IN ('RESOLVED', 'CLOSED', 'DONE', 'FIXED')
|
|
105
106
|
AND resolved_at IS NULL
|
|
106
|
-
ORDER BY
|
|
107
|
-
CASE severity
|
|
108
|
-
WHEN 'CRITICAL' THEN 0
|
|
109
|
-
WHEN 'HIGH' THEN 1
|
|
110
|
-
WHEN 'MEDIUM' THEN 2
|
|
111
|
-
WHEN 'LOW' THEN 3
|
|
112
|
-
ELSE 99
|
|
107
|
+
ORDER BY
|
|
108
|
+
CASE severity
|
|
109
|
+
WHEN 'CRITICAL' THEN 0
|
|
110
|
+
WHEN 'HIGH' THEN 1
|
|
111
|
+
WHEN 'MEDIUM' THEN 2
|
|
112
|
+
WHEN 'LOW' THEN 3
|
|
113
|
+
ELSE 99
|
|
113
114
|
END ASC,
|
|
114
115
|
created_at ASC
|
|
115
116
|
`).all().map(b => ({ ...b, projectSlug: b.project_slug, createdAt: b.created_at }));
|
|
116
117
|
|
|
117
118
|
const openedRecent = dl.db.prepare(`
|
|
118
|
-
SELECT * FROM blockers
|
|
119
|
+
SELECT * FROM blockers
|
|
119
120
|
WHERE created_at >= ? AND created_at <= ?
|
|
120
121
|
`).all(startIso, endIso).map(b => ({ ...b, projectSlug: b.project_slug, createdAt: b.created_at }));
|
|
121
122
|
|
|
122
123
|
const resolvedRecent = dl.db.prepare(`
|
|
123
|
-
SELECT * FROM blockers
|
|
124
|
+
SELECT * FROM blockers
|
|
124
125
|
WHERE resolved_at >= ? AND resolved_at <= ?
|
|
125
126
|
`).all(startIso, endIso).map(b => ({ ...b, projectSlug: b.project_slug, resolvedAt: b.resolved_at }));
|
|
126
127
|
|
|
@@ -234,7 +235,7 @@ class DataManager {
|
|
|
234
235
|
|
|
235
236
|
// Fetch all stored embeddings. For a local personal tool with < 100k chunks, in-memory cosine sim is perfectly fast.
|
|
236
237
|
const rows = dl.db.prepare(`
|
|
237
|
-
SELECT reference_type, reference_id, chunk_index, text_chunk, embedding
|
|
238
|
+
SELECT reference_type, reference_id, chunk_index, text_chunk, embedding
|
|
238
239
|
FROM document_embeddings
|
|
239
240
|
`).all();
|
|
240
241
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
class Embedder {
|
|
2
2
|
constructor() {
|
|
3
|
+
// V3: use the official HuggingFace model name (same weights, new namespace)
|
|
3
4
|
this.modelName = 'Xenova/all-MiniLM-L6-v2';
|
|
4
5
|
this.extractorInfo = null;
|
|
5
6
|
this.initPromise = null;
|
|
@@ -9,7 +10,9 @@ class Embedder {
|
|
|
9
10
|
if (this.extractorInfo) return;
|
|
10
11
|
if (!this.initPromise) {
|
|
11
12
|
this.initPromise = (async () => {
|
|
12
|
-
|
|
13
|
+
// V3: @huggingface/transformers replaces @xenova/transformers
|
|
14
|
+
// sharp 0.34+ uses prebuilt platform binaries (no node-gyp needed)
|
|
15
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
13
16
|
this.extractorInfo = await pipeline('feature-extraction', this.modelName, { quantized: true });
|
|
14
17
|
})().catch((err) => {
|
|
15
18
|
this.initPromise = null;
|
|
@@ -25,6 +28,7 @@ class Embedder {
|
|
|
25
28
|
if (!cleanText) return new Float32Array(384); // Empty zero vector for model
|
|
26
29
|
|
|
27
30
|
const output = await this.extractorInfo(cleanText, { pooling: 'mean', normalize: true });
|
|
31
|
+
// V3: output.data may be a typed array or need .tolist()
|
|
28
32
|
return new Float32Array(output.data);
|
|
29
33
|
}
|
|
30
34
|
|