ahok-skill 1.3.1

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 (141) hide show
  1. package/.prettierrc +8 -0
  2. package/Dockerfile +59 -0
  3. package/RAW_SKILL.md +219 -0
  4. package/README.md +277 -0
  5. package/SKILL.md +58 -0
  6. package/bin/opm.js +268 -0
  7. package/data/openmemory.sqlite +0 -0
  8. package/data/openmemory.sqlite-shm +0 -0
  9. package/data/openmemory.sqlite-wal +0 -0
  10. package/dist/ai/graph.js +293 -0
  11. package/dist/ai/mcp.js +397 -0
  12. package/dist/cli.js +78 -0
  13. package/dist/core/cfg.js +87 -0
  14. package/dist/core/db.js +636 -0
  15. package/dist/core/memory.js +116 -0
  16. package/dist/core/migrate.js +227 -0
  17. package/dist/core/models.js +105 -0
  18. package/dist/core/telemetry.js +57 -0
  19. package/dist/core/types.js +2 -0
  20. package/dist/core/vector/postgres.js +52 -0
  21. package/dist/core/vector/valkey.js +246 -0
  22. package/dist/core/vector_store.js +2 -0
  23. package/dist/index.js +44 -0
  24. package/dist/memory/decay.js +301 -0
  25. package/dist/memory/embed.js +675 -0
  26. package/dist/memory/hsg.js +959 -0
  27. package/dist/memory/reflect.js +131 -0
  28. package/dist/memory/user_summary.js +99 -0
  29. package/dist/migrate.js +9 -0
  30. package/dist/ops/compress.js +255 -0
  31. package/dist/ops/dynamics.js +189 -0
  32. package/dist/ops/extract.js +333 -0
  33. package/dist/ops/ingest.js +214 -0
  34. package/dist/server/index.js +109 -0
  35. package/dist/server/middleware/auth.js +137 -0
  36. package/dist/server/routes/auth.js +186 -0
  37. package/dist/server/routes/compression.js +108 -0
  38. package/dist/server/routes/dashboard.js +399 -0
  39. package/dist/server/routes/docs.js +241 -0
  40. package/dist/server/routes/dynamics.js +312 -0
  41. package/dist/server/routes/ide.js +280 -0
  42. package/dist/server/routes/index.js +33 -0
  43. package/dist/server/routes/keys.js +132 -0
  44. package/dist/server/routes/langgraph.js +61 -0
  45. package/dist/server/routes/memory.js +213 -0
  46. package/dist/server/routes/sources.js +140 -0
  47. package/dist/server/routes/system.js +63 -0
  48. package/dist/server/routes/temporal.js +293 -0
  49. package/dist/server/routes/users.js +101 -0
  50. package/dist/server/routes/vercel.js +57 -0
  51. package/dist/server/server.js +211 -0
  52. package/dist/server.js +3 -0
  53. package/dist/sources/base.js +223 -0
  54. package/dist/sources/github.js +171 -0
  55. package/dist/sources/google_drive.js +166 -0
  56. package/dist/sources/google_sheets.js +112 -0
  57. package/dist/sources/google_slides.js +139 -0
  58. package/dist/sources/index.js +34 -0
  59. package/dist/sources/notion.js +165 -0
  60. package/dist/sources/onedrive.js +143 -0
  61. package/dist/sources/web_crawler.js +166 -0
  62. package/dist/temporal_graph/index.js +20 -0
  63. package/dist/temporal_graph/query.js +240 -0
  64. package/dist/temporal_graph/store.js +116 -0
  65. package/dist/temporal_graph/timeline.js +241 -0
  66. package/dist/temporal_graph/types.js +2 -0
  67. package/dist/utils/chunking.js +60 -0
  68. package/dist/utils/index.js +31 -0
  69. package/dist/utils/keyword.js +94 -0
  70. package/dist/utils/text.js +120 -0
  71. package/nodemon.json +7 -0
  72. package/package.json +50 -0
  73. package/references/api_reference.md +66 -0
  74. package/references/examples.md +45 -0
  75. package/src/ai/graph.ts +363 -0
  76. package/src/ai/mcp.ts +494 -0
  77. package/src/cli.ts +94 -0
  78. package/src/core/cfg.ts +110 -0
  79. package/src/core/db.ts +1052 -0
  80. package/src/core/memory.ts +99 -0
  81. package/src/core/migrate.ts +302 -0
  82. package/src/core/models.ts +107 -0
  83. package/src/core/telemetry.ts +47 -0
  84. package/src/core/types.ts +130 -0
  85. package/src/core/vector/postgres.ts +61 -0
  86. package/src/core/vector/valkey.ts +261 -0
  87. package/src/core/vector_store.ts +9 -0
  88. package/src/index.ts +5 -0
  89. package/src/memory/decay.ts +427 -0
  90. package/src/memory/embed.ts +707 -0
  91. package/src/memory/hsg.ts +1245 -0
  92. package/src/memory/reflect.ts +158 -0
  93. package/src/memory/user_summary.ts +110 -0
  94. package/src/migrate.ts +8 -0
  95. package/src/ops/compress.ts +296 -0
  96. package/src/ops/dynamics.ts +272 -0
  97. package/src/ops/extract.ts +360 -0
  98. package/src/ops/ingest.ts +286 -0
  99. package/src/server/index.ts +159 -0
  100. package/src/server/middleware/auth.ts +156 -0
  101. package/src/server/routes/auth.ts +223 -0
  102. package/src/server/routes/compression.ts +106 -0
  103. package/src/server/routes/dashboard.ts +420 -0
  104. package/src/server/routes/docs.ts +380 -0
  105. package/src/server/routes/dynamics.ts +516 -0
  106. package/src/server/routes/ide.ts +283 -0
  107. package/src/server/routes/index.ts +32 -0
  108. package/src/server/routes/keys.ts +131 -0
  109. package/src/server/routes/langgraph.ts +71 -0
  110. package/src/server/routes/memory.ts +440 -0
  111. package/src/server/routes/sources.ts +111 -0
  112. package/src/server/routes/system.ts +68 -0
  113. package/src/server/routes/temporal.ts +335 -0
  114. package/src/server/routes/users.ts +111 -0
  115. package/src/server/routes/vercel.ts +55 -0
  116. package/src/server/server.js +215 -0
  117. package/src/server.ts +1 -0
  118. package/src/sources/base.ts +257 -0
  119. package/src/sources/github.ts +156 -0
  120. package/src/sources/google_drive.ts +144 -0
  121. package/src/sources/google_sheets.ts +85 -0
  122. package/src/sources/google_slides.ts +115 -0
  123. package/src/sources/index.ts +19 -0
  124. package/src/sources/notion.ts +148 -0
  125. package/src/sources/onedrive.ts +131 -0
  126. package/src/sources/web_crawler.ts +161 -0
  127. package/src/temporal_graph/index.ts +4 -0
  128. package/src/temporal_graph/query.ts +299 -0
  129. package/src/temporal_graph/store.ts +156 -0
  130. package/src/temporal_graph/timeline.ts +319 -0
  131. package/src/temporal_graph/types.ts +41 -0
  132. package/src/utils/chunking.ts +66 -0
  133. package/src/utils/index.ts +25 -0
  134. package/src/utils/keyword.ts +137 -0
  135. package/src/utils/text.ts +115 -0
  136. package/tests/test_api_workspace_management.ts +413 -0
  137. package/tests/test_bulk_delete.ts +267 -0
  138. package/tests/test_omnibus.ts +166 -0
  139. package/tests/test_workspace_management.ts +278 -0
  140. package/tests/verify.ts +104 -0
  141. package/tsconfig.json +15 -0
@@ -0,0 +1,166 @@
1
+
2
+ import { Memory } from "../src/core/memory";
3
+ import { run_async, q } from "../src/core/db";
4
+
5
+ // Mock time for evolutionary stability
6
+ let mockTime: number | null = null;
7
+ const originalNow = Date.now;
8
+ Date.now = () => (mockTime !== null ? mockTime : originalNow());
9
+
10
+ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
11
+
12
+ async function cleanup(user_id: string) {
13
+ await run_async(`DELETE FROM memories`);
14
+ try { await run_async(`DELETE FROM vectors`); } catch { }
15
+ try { await run_async(`DELETE FROM openmemory_vectors`); } catch { }
16
+ try { await run_async(`DELETE FROM waypoints`); } catch { }
17
+ try { await run_async(`DELETE FROM users`); } catch { }
18
+ if (global.gc) global.gc();
19
+ }
20
+
21
+ // Force synthetic for reliability
22
+ process.env.OM_EMBEDDINGS = "synthetic";
23
+
24
+ async function check_vec(id: string) {
25
+ const row = await q.get_mem.get(id);
26
+ if (!row) console.error(`[DEBUG] Memory ${id} NOT FOUND in DB`);
27
+ else console.log(`[DEBUG] Memory ${id} vector length: ${row.mean_vec ? row.mean_vec.length : 'NULL'}`);
28
+ }
29
+
30
+ async function test_evolutionary_stability() {
31
+ console.log("\n[Phase 1] Evolutionary Stability (10 Generations)");
32
+ const mem = new Memory();
33
+ const uid = "u1";
34
+ await cleanup(uid);
35
+
36
+ // 1. Genesis
37
+ mockTime = originalNow();
38
+ const res_pop = await mem.add("I am the Popular Memory", { user_id: uid });
39
+ const res_unpop = await mem.add("I am the Unpopular Memory", { user_id: uid });
40
+ const pid = res_pop.id;
41
+ const uid_mem = res_unpop.id;
42
+
43
+ // 2. Evolution Loop
44
+ for (let gen = 0; gen < 10; gen++) {
45
+ // Advance 1 day per generation (86400000 ms)
46
+ mockTime += 86400 * 1000;
47
+
48
+ // Reinforce Popular every other generation
49
+ if (gen % 2 === 0) {
50
+ await mem.search("Popular", { user_id: uid, limit: 1 });
51
+ }
52
+ }
53
+
54
+ // 3. Final Judgment
55
+ mockTime += 86400 * 1000;
56
+
57
+ // Check Salience via DB directly to avoid search side-effects
58
+ const pop_final = await q.get_mem.get(pid);
59
+ const unpop_final = await q.get_mem.get(uid_mem);
60
+
61
+ if (!pop_final || !unpop_final) {
62
+ throw new Error("Memories lost in time!");
63
+ }
64
+
65
+ const s_pop = pop_final.salience;
66
+ const s_unpop = unpop_final.salience;
67
+
68
+ console.log(` -> Generation 10 Results:`);
69
+ console.log(` Popular Salience: ${s_pop.toFixed(4)}`);
70
+ console.log(` Unpopular Salience: ${s_unpop.toFixed(4)}`);
71
+
72
+ if (s_pop <= s_unpop) {
73
+ throw new Error(`FAIL: Popular memory (${s_pop}) should > Unpopular (${s_unpop})`);
74
+ }
75
+ console.log(" -> PASS: Survival of the fittest confirmed.");
76
+ mockTime = null; // Reset
77
+ }
78
+
79
+ async function test_boolean_metadata_logic() {
80
+ console.log("\n[Phase 2] Boolean Metadata Logic");
81
+ const mem = new Memory();
82
+ const uid = "filter_user_js";
83
+ await cleanup(uid);
84
+
85
+ // Wait 500ms for WAL safety buffer from previous test deletions if any
86
+ await sleep(500);
87
+
88
+ // 1. High Priority, Work context
89
+ await mem.add("Finish Report", { user_id: uid, tags: ["work", "urgent"], priority: 10 });
90
+ // 2. Low Priority, Work context
91
+ await mem.add("Clean Desk", { user_id: uid, tags: ["work"], priority: 2 });
92
+ // 3. High Prioriy, Home context
93
+ const res3 = await mem.add("Pay Bills", { user_id: uid, tags: ["home", "urgent"], priority: 10 });
94
+
95
+ // Ensure persistence
96
+ await sleep(1000);
97
+ await check_vec(res3.id);
98
+
99
+ console.log(" -> Filtering for 'work' AND 'urgent'...");
100
+ // Since search doesn't support complex filter syntax yet, we search semantic and verify post-hoc
101
+ const hits = await mem.search("Report", { user_id: uid, limit: 10 });
102
+
103
+ // Check logic
104
+ const found = hits.some((h: any) => {
105
+ const tags = typeof h.tags === 'string' ? JSON.parse(h.tags) : h.tags || [];
106
+ return tags.includes("urgent") && tags.includes("work");
107
+ });
108
+
109
+ if (!found) {
110
+ // console.error("DEBUG Hits:", JSON.stringify(hits, null, 2));
111
+ await require('fs/promises').writeFile('hits.json', JSON.stringify(hits, null, 2));
112
+ throw new Error("FAIL: Did not find item with both tags. Dumped hits to hits.json");
113
+ }
114
+ console.log(" -> PASS: Metadata attributes preserved and queryable.");
115
+ }
116
+
117
+ async function test_content_robustness() {
118
+ console.log("\n[Phase 3] Content Robustness");
119
+ const mem = new Memory();
120
+ const uid = "format_user_js";
121
+ await cleanup(uid);
122
+ await sleep(500);
123
+
124
+ const payloads = {
125
+ "HTML": "<div><h1>Title</h1><p>Body</p></div>",
126
+ "JSON": '{"key": "value", "list": [1, 2, 3]}',
127
+ "Markdown": "| Col1 | Col2 |\n|---|---|\n| Val1 | Val2 |"
128
+ };
129
+
130
+ for (const [fmt, content] of Object.entries(payloads)) {
131
+ await mem.add(content, { user_id: uid });
132
+ await sleep(200);
133
+
134
+ const hits = await mem.search(content.substring(0, 10), { user_id: uid, limit: 1 });
135
+ if (!hits || hits.length === 0) {
136
+ throw new Error(`FAIL: ${fmt} retrieval returned no results.`);
137
+ }
138
+
139
+ const retrieved = hits[0].content;
140
+
141
+ // Check containment
142
+ if (retrieved.includes("Title") || retrieved.includes("key") || retrieved.includes("Col1")) {
143
+ console.log(` -> ${fmt}: Verified (Key Match)`);
144
+ } else {
145
+ console.error(`original: ${content}`);
146
+ console.error(`retrieved: ${retrieved}`);
147
+ throw new Error(`FAIL: ${fmt} retrieval content mismatch.`);
148
+ }
149
+ }
150
+ console.log(" -> PASS: Complex formats handled.");
151
+ }
152
+
153
+ async function run_all() {
154
+ try {
155
+ await test_evolutionary_stability();
156
+ await test_boolean_metadata_logic();
157
+ await test_content_robustness();
158
+ console.log("\n[OMNIBUS] ALL TESTS PASSED");
159
+ process.exit(0);
160
+ } catch (e) {
161
+ console.error("\n[OMNIBUS] TEST FAILED:", e);
162
+ process.exit(1);
163
+ }
164
+ }
165
+
166
+ run_all();
@@ -0,0 +1,278 @@
1
+ /**
2
+ * End-to-end test for Memory Workspace Management
3
+ * Tests: workspace creation, renaming, statistics, bulk operations
4
+ *
5
+ * This test focuses on the database queries for workspace management
6
+ * without relying on the full memory creation pipeline.
7
+ */
8
+
9
+ import { q, run_async } from "../src/core/db";
10
+ import crypto from "crypto";
11
+
12
+ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
13
+
14
+ const TEST_USER_ID = `test_workspace_user_${Date.now()}`;
15
+
16
+ async function cleanup() {
17
+ console.log("\n[Cleanup] Removing test data...");
18
+ try {
19
+ await run_async(`DELETE FROM memories WHERE user_id = '${TEST_USER_ID}'`);
20
+ await run_async(`DELETE FROM api_keys WHERE user_id = '${TEST_USER_ID}'`);
21
+ } catch (e) {
22
+ console.log(" Cleanup warning:", e);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Test 1: Create multiple workspaces
28
+ */
29
+ async function test_create_workspaces(): Promise<string[]> {
30
+ console.log("\n[Test 1] Creating multiple workspaces...");
31
+
32
+ const workspaceIds: string[] = [];
33
+ const labels = ["Development", "Production", "Testing"];
34
+
35
+ for (const label of labels) {
36
+ const id = crypto.randomUUID();
37
+ const secret_key = `opm_sk_${crypto.randomBytes(24).toString("hex")}`;
38
+ const created_at = Date.now();
39
+
40
+ await q.ins_memory_key.run(id, TEST_USER_ID, label, secret_key, created_at);
41
+ workspaceIds.push(id);
42
+ console.log(` ✓ Created workspace: ${label} (${id})`);
43
+ }
44
+
45
+ // Verify workspaces were created
46
+ const workspaces = await q.get_memory_keys_by_user.all(TEST_USER_ID);
47
+ if (workspaces.length !== 3) {
48
+ throw new Error(`Expected 3 workspaces, got ${workspaces.length}`);
49
+ }
50
+
51
+ console.log(` ✓ Verified ${workspaces.length} workspaces exist`);
52
+ return workspaceIds;
53
+ }
54
+
55
+ /**
56
+ * Test 2: Rename a workspace
57
+ */
58
+ async function test_rename_workspace(workspaceId: string) {
59
+ console.log("\n[Test 2] Renaming workspace...");
60
+
61
+ const newLabel = "Development-Renamed";
62
+ const updated_at = Date.now();
63
+
64
+ await q.upd_memory_key_label.run(newLabel, updated_at, workspaceId, TEST_USER_ID);
65
+
66
+ // Verify rename
67
+ const workspaces = await q.get_memory_keys_by_user.all(TEST_USER_ID);
68
+ const renamed = workspaces.find(w => w.id === workspaceId);
69
+
70
+ if (!renamed || renamed.label !== newLabel) {
71
+ throw new Error(`Rename failed: expected "${newLabel}", got "${renamed?.label}"`);
72
+ }
73
+
74
+ console.log(` ✓ Workspace renamed to: ${newLabel}`);
75
+ }
76
+
77
+ /**
78
+ * Test 3: Create memories directly in database (bypassing embedding)
79
+ */
80
+ async function test_create_memories_in_workspaces(workspaceIds: string[]): Promise<string[]> {
81
+ console.log("\n[Test 3] Creating memories in different workspaces...");
82
+
83
+ const memoryIds: string[] = [];
84
+ const timestamp = Date.now();
85
+
86
+ // Create 2 memories in workspace 1
87
+ for (let i = 0; i < 2; i++) {
88
+ const id = crypto.randomUUID();
89
+ await run_async(
90
+ `INSERT INTO memories (id, user_id, content, primary_sector, created_at, memory_key_id)
91
+ VALUES ($1, $2, $3, $4, $5, $6)`,
92
+ [id, TEST_USER_ID, `Memory ${i + 1} in workspace 1 - ${timestamp}`, 'semantic', timestamp, workspaceIds[0]]
93
+ );
94
+ memoryIds.push(id);
95
+ console.log(` ✓ Created memory in workspace 1: ${id}`);
96
+ }
97
+
98
+ // Create 3 memories in workspace 2
99
+ for (let i = 0; i < 3; i++) {
100
+ const id = crypto.randomUUID();
101
+ await run_async(
102
+ `INSERT INTO memories (id, user_id, content, primary_sector, created_at, memory_key_id)
103
+ VALUES ($1, $2, $3, $4, $5, $6)`,
104
+ [id, TEST_USER_ID, `Memory ${i + 1} in workspace 2 - ${timestamp}`, 'semantic', timestamp, workspaceIds[1]]
105
+ );
106
+ memoryIds.push(id);
107
+ console.log(` ✓ Created memory in workspace 2: ${id}`);
108
+ }
109
+
110
+ // Create 1 memory in workspace 3
111
+ const id = crypto.randomUUID();
112
+ await run_async(
113
+ `INSERT INTO memories (id, user_id, content, primary_sector, created_at, memory_key_id)
114
+ VALUES ($1, $2, $3, $4, $5, $6)`,
115
+ [id, TEST_USER_ID, `Memory 1 in workspace 3 - ${timestamp}`, 'semantic', timestamp, workspaceIds[2]]
116
+ );
117
+ memoryIds.push(id);
118
+ console.log(` ✓ Created memory in workspace 3: ${id}`);
119
+
120
+ console.log(` ✓ Total memories created: ${memoryIds.length}`);
121
+ return memoryIds;
122
+ }
123
+
124
+ /**
125
+ * Test 4: Get workspace statistics (memory counts)
126
+ */
127
+ async function test_workspace_statistics(workspaceIds: string[]) {
128
+ console.log("\n[Test 4] Testing workspace statistics...");
129
+
130
+ const counts = await q.get_memory_counts_by_key.all(TEST_USER_ID);
131
+ console.log(" Memory counts by workspace:", counts);
132
+
133
+ // Create a map for easy lookup
134
+ const countMap = new Map<string, number>();
135
+ for (const item of counts) {
136
+ if (item.memory_key_id) {
137
+ countMap.set(item.memory_key_id, Number(item.count));
138
+ }
139
+ }
140
+
141
+ // Verify counts
142
+ const ws1Count = countMap.get(workspaceIds[0]) || 0;
143
+ const ws2Count = countMap.get(workspaceIds[1]) || 0;
144
+ const ws3Count = countMap.get(workspaceIds[2]) || 0;
145
+
146
+ console.log(` Workspace 1 count: ${ws1Count} (expected: 2)`);
147
+ console.log(` Workspace 2 count: ${ws2Count} (expected: 3)`);
148
+ console.log(` Workspace 3 count: ${ws3Count} (expected: 1)`);
149
+
150
+ if (ws1Count !== 2) throw new Error(`Workspace 1: expected 2, got ${ws1Count}`);
151
+ if (ws2Count !== 3) throw new Error(`Workspace 2: expected 3, got ${ws2Count}`);
152
+ if (ws3Count !== 1) throw new Error(`Workspace 3: expected 1, got ${ws3Count}`);
153
+
154
+ console.log(" ✓ All workspace statistics are correct");
155
+ }
156
+
157
+ /**
158
+ * Test 5: Bulk move memories between workspaces
159
+ */
160
+ async function test_bulk_move(memoryIds: string[], workspaceIds: string[]) {
161
+ console.log("\n[Test 5] Testing bulk move...");
162
+
163
+ // Move first 2 memories (from workspace 1) to workspace 3
164
+ const idsToMove = memoryIds.slice(0, 2);
165
+ const targetWorkspace = workspaceIds[2];
166
+ const updated_at = Date.now();
167
+
168
+ console.log(` Moving ${idsToMove.length} memories to workspace 3...`);
169
+ await q.bulk_upd_mem_key.run(targetWorkspace, updated_at, idsToMove, TEST_USER_ID);
170
+
171
+ // Verify the move by checking statistics
172
+ await sleep(200);
173
+ const counts = await q.get_memory_counts_by_key.all(TEST_USER_ID);
174
+
175
+ const countMap = new Map<string, number>();
176
+ for (const item of counts) {
177
+ if (item.memory_key_id) {
178
+ countMap.set(item.memory_key_id, Number(item.count));
179
+ }
180
+ }
181
+
182
+ const ws1Count = countMap.get(workspaceIds[0]) || 0;
183
+ const ws3Count = countMap.get(workspaceIds[2]) || 0;
184
+
185
+ console.log(` Workspace 1 count after move: ${ws1Count} (expected: 0)`);
186
+ console.log(` Workspace 3 count after move: ${ws3Count} (expected: 3)`);
187
+
188
+ if (ws1Count !== 0) throw new Error(`Workspace 1 after move: expected 0, got ${ws1Count}`);
189
+ if (ws3Count !== 3) throw new Error(`Workspace 3 after move: expected 3, got ${ws3Count}`);
190
+
191
+ console.log(" ✓ Bulk move successful");
192
+ }
193
+
194
+ /**
195
+ * Test 6: Bulk delete memories
196
+ */
197
+ async function test_bulk_delete(memoryIds: string[]) {
198
+ console.log("\n[Test 6] Testing bulk delete...");
199
+
200
+ // Delete the last 2 memories
201
+ const idsToDelete = memoryIds.slice(-2);
202
+
203
+ console.log(` Deleting ${idsToDelete.length} memories...`);
204
+ await q.bulk_del_mem.run(idsToDelete, TEST_USER_ID);
205
+
206
+ // Verify deletion
207
+ await sleep(200);
208
+ for (const id of idsToDelete) {
209
+ const mem = await q.get_mem.get(id);
210
+ if (mem) {
211
+ throw new Error(`Memory ${id} should have been deleted`);
212
+ }
213
+ }
214
+
215
+ console.log(" ✓ Bulk delete successful");
216
+ }
217
+
218
+ /**
219
+ * Test 7: Delete a workspace
220
+ */
221
+ async function test_delete_workspace(workspaceId: string) {
222
+ console.log("\n[Test 7] Testing workspace deletion...");
223
+
224
+ await q.del_memory_key.run(workspaceId, TEST_USER_ID);
225
+
226
+ // Verify deletion
227
+ const workspaces = await q.get_memory_keys_by_user.all(TEST_USER_ID);
228
+ const deleted = workspaces.find(w => w.id === workspaceId);
229
+
230
+ if (deleted) {
231
+ throw new Error(`Workspace ${workspaceId} should have been deleted`);
232
+ }
233
+
234
+ console.log(" ✓ Workspace deleted successfully");
235
+ }
236
+
237
+ async function run_all_tests() {
238
+ console.log("=".repeat(60));
239
+ console.log("Memory Workspace Management - End-to-End Tests");
240
+ console.log("=".repeat(60));
241
+
242
+ try {
243
+ // Initialize database by making a simple query
244
+ console.log("\n[Init] Initializing database...");
245
+ await sleep(1000); // Give time for db to initialize
246
+ console.log(" ✓ Database initialized");
247
+
248
+ // Cleanup any previous test data
249
+ await cleanup();
250
+
251
+ // Run tests
252
+ const workspaceIds = await test_create_workspaces();
253
+ await test_rename_workspace(workspaceIds[0]);
254
+ const memoryIds = await test_create_memories_in_workspaces(workspaceIds);
255
+ await test_workspace_statistics(workspaceIds);
256
+ await test_bulk_move(memoryIds, workspaceIds);
257
+ await test_bulk_delete(memoryIds);
258
+ await test_delete_workspace(workspaceIds[0]);
259
+
260
+ // Final cleanup
261
+ await cleanup();
262
+
263
+ console.log("\n" + "=".repeat(60));
264
+ console.log("✅ ALL TESTS PASSED");
265
+ console.log("=".repeat(60));
266
+ process.exit(0);
267
+ } catch (error) {
268
+ console.error("\n" + "=".repeat(60));
269
+ console.error("❌ TEST FAILED:", error);
270
+ console.error("=".repeat(60));
271
+
272
+ // Cleanup on failure
273
+ await cleanup();
274
+ process.exit(1);
275
+ }
276
+ }
277
+
278
+ run_all_tests();
@@ -0,0 +1,104 @@
1
+
2
+ import { Memory } from "../src/core/memory";
3
+ import { env } from "../src/core/cfg";
4
+ import { q } from "../src/core/db";
5
+
6
+ async function runTest() {
7
+ console.log("\\n[TEST] 🧪 Starting JS Deep Sector & Vector Verification...");
8
+ console.log(`[TEST] Target Vector Dim: ${env.vec_dim}`);
9
+
10
+ const uid = "js_sector_tester_v1";
11
+ // We need to implement delete_all in JS if not present?
12
+ // JS `Memory` class likely has it? Checked API parity.
13
+ // If not, we can use `q` directly.
14
+ try {
15
+ await q.conn.run("DELETE FROM memories WHERE user_id = ?", [uid]);
16
+ } catch (e) {
17
+ console.log("Cleanup warning:", e);
18
+ }
19
+
20
+ const mem = new Memory(uid);
21
+ console.log(`[TEST] Cleared memory for user: ${uid}`);
22
+
23
+ const testCases = [
24
+ {
25
+ type: "episodic",
26
+ text: "Yesterday I went to the park at 4:00 PM and saw a dog.",
27
+ expected: "episodic"
28
+ },
29
+ {
30
+ type: "emotional",
31
+ text: "I feel absolutely amazing and excited about this new project! Wow!",
32
+ expected: "emotional"
33
+ },
34
+ {
35
+ type: "procedural",
36
+ text: "To install the package, first run npm install, then configure the settings.",
37
+ expected: "procedural"
38
+ },
39
+ {
40
+ type: "reflective",
41
+ text: "I realized that the pattern of failure was due to my own lack of patience.",
42
+ expected: "reflective"
43
+ },
44
+ {
45
+ type: "semantic",
46
+ text: "Python is a high-level programming language known for its readability.",
47
+ expected: "semantic"
48
+ }
49
+ ];
50
+
51
+ console.log("\\n[TEST] Ingesting Samples...");
52
+ let passed = true;
53
+
54
+ for (const c of testCases) {
55
+ console.log(` > Ingesting (${c.type}): "${c.text.substring(0, 40)}..."`);
56
+ const res = await mem.add(c.text);
57
+ const mid = res.id;
58
+
59
+ // Wait for WAL
60
+ await new Promise(r => setTimeout(r, 500));
61
+
62
+ // Get from DB
63
+ const row = await q.get_mem.get(mid);
64
+ if (!row) {
65
+ console.log(" FAIL: Memory not found in DB");
66
+ passed = false;
67
+ continue;
68
+ }
69
+
70
+ const actual = row.primary_sector;
71
+ const status = actual === c.expected ? "PASS" : `FAIL (Got: ${actual})`;
72
+ console.log(` - ID: ${mid}`);
73
+ console.log(` - Assigned Sector: ${actual.toUpperCase()} ${status}`);
74
+
75
+ if (actual !== c.expected) passed = false;
76
+
77
+ console.log(` - Checking Vector Dimensions...`);
78
+ const vecBuf = row.mean_vec;
79
+ if (!vecBuf) {
80
+ console.log(" FAIL: No vector generated!");
81
+ passed = false;
82
+ } else {
83
+ // Buffer in Node/Bun.
84
+ const vecLen = vecBuf.length; // bytes
85
+ const dim = vecLen / 4;
86
+ if (dim === 1536) {
87
+ console.log(` PASS: Vector Dim ${dim} (Size: ${vecLen} bytes)`);
88
+ } else {
89
+ console.log(` FAIL: Vector Dim ${dim} (Expected 1536)`);
90
+ passed = false;
91
+ }
92
+ }
93
+ }
94
+
95
+ console.log("\\n[TEST] Summary:");
96
+ if (passed) {
97
+ console.log("ALL JS SECTOR & VECTOR TESTS PASSED.");
98
+ } else {
99
+ console.log("SOME TESTS FAILED.");
100
+ process.exit(1);
101
+ }
102
+ }
103
+
104
+ runTest().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "node",
6
+ "outDir": "dist",
7
+ "allowJs": true,
8
+ "checkJs": false,
9
+ "esModuleInterop": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "strict": true,
12
+ "skipLibCheck": true
13
+ },
14
+ "include": ["src"]
15
+ }