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,61 @@
1
+ import { VectorStore } from "../vector_store";
2
+ import { cosineSimilarity, bufferToVector, vectorToBuffer } from "../../memory/embed";
3
+
4
+ export interface DbOps {
5
+ run_async: (sql: string, params?: any[]) => Promise<void>;
6
+ get_async: (sql: string, params?: any[]) => Promise<any>;
7
+ all_async: (sql: string, params?: any[]) => Promise<any[]>;
8
+ }
9
+
10
+ export class PostgresVectorStore implements VectorStore {
11
+ private table: string;
12
+
13
+ constructor(private db: DbOps, tableName: string = "vectors") {
14
+ this.table = tableName;
15
+ }
16
+
17
+ async storeVector(id: string, sector: string, vector: number[], dim: number, user_id?: string): Promise<void> {
18
+ console.error(`[Vector] Storing ID: ${id}, Sector: ${sector}, Dim: ${dim}`);
19
+ const v = vectorToBuffer(vector);
20
+ const sql = `insert into ${this.table}(id,sector,user_id,v,dim) values($1,$2,$3,$4,$5) on conflict(id,sector) do update set user_id=excluded.user_id,v=excluded.v,dim=excluded.dim`;
21
+ await this.db.run_async(sql, [id, sector, user_id || "anonymous", v, dim]);
22
+ }
23
+
24
+ async deleteVector(id: string, sector: string): Promise<void> {
25
+ await this.db.run_async(`delete from ${this.table} where id=$1 and sector=$2`, [id, sector]);
26
+ }
27
+
28
+ async deleteVectors(id: string): Promise<void> {
29
+ await this.db.run_async(`delete from ${this.table} where id=$1`, [id]);
30
+ }
31
+
32
+ async searchSimilar(sector: string, queryVec: number[], topK: number): Promise<Array<{ id: string; score: number }>> {
33
+ // Postgres implementation (in-memory cosine sim for now, as per original)
34
+ const rows = await this.db.all_async(`select id,v,dim from ${this.table} where sector=$1`, [sector]);
35
+ console.error(`[Vector] Search Sector: ${sector}, Found ${rows.length} rows.`);
36
+ const sims: Array<{ id: string; score: number }> = [];
37
+ for (const row of rows) {
38
+ const vec = bufferToVector(row.v);
39
+ const sim = cosineSimilarity(queryVec, vec);
40
+ sims.push({ id: row.id, score: sim });
41
+ }
42
+ sims.sort((a, b) => b.score - a.score);
43
+ return sims.slice(0, topK);
44
+ }
45
+
46
+ async getVector(id: string, sector: string): Promise<{ vector: number[]; dim: number } | null> {
47
+ const row = await this.db.get_async(`select v,dim from ${this.table} where id=$1 and sector=$2`, [id, sector]);
48
+ if (!row) return null;
49
+ return { vector: bufferToVector(row.v), dim: row.dim };
50
+ }
51
+
52
+ async getVectorsById(id: string): Promise<Array<{ sector: string; vector: number[]; dim: number }>> {
53
+ const rows = await this.db.all_async(`select sector,v,dim from ${this.table} where id=$1`, [id]);
54
+ return rows.map(row => ({ sector: row.sector, vector: bufferToVector(row.v), dim: row.dim }));
55
+ }
56
+
57
+ async getVectorsBySector(sector: string): Promise<Array<{ id: string; vector: number[]; dim: number }>> {
58
+ const rows = await this.db.all_async(`select id,v,dim from ${this.table} where sector=$1`, [sector]);
59
+ return rows.map(row => ({ id: row.id, vector: bufferToVector(row.v), dim: row.dim }));
60
+ }
61
+ }
@@ -0,0 +1,261 @@
1
+ import { VectorStore } from "../vector_store";
2
+ import Redis from "ioredis";
3
+ import { env } from "../cfg";
4
+ import { vectorToBuffer, bufferToVector } from "../../memory/embed";
5
+
6
+ export class ValkeyVectorStore implements VectorStore {
7
+ private client: Redis;
8
+
9
+ constructor() {
10
+ this.client = new Redis({
11
+ host: env.valkey_host || "localhost",
12
+ port: env.valkey_port || 6379,
13
+ password: env.valkey_password,
14
+ });
15
+ }
16
+
17
+ private getKey(id: string, sector: string): string {
18
+ return `vec:${sector}:${id}`;
19
+ }
20
+
21
+ async storeVector(id: string, sector: string, vector: number[], dim: number, user_id?: string): Promise<void> {
22
+ const key = this.getKey(id, sector);
23
+ const buf = vectorToBuffer(vector);
24
+ // Store as Hash: v (blob), dim (int), user_id (string)
25
+ await this.client.hset(key, {
26
+ v: buf,
27
+ dim: dim,
28
+ user_id: user_id || "anonymous",
29
+ id: id,
30
+ sector: sector
31
+ });
32
+ }
33
+
34
+ async deleteVector(id: string, sector: string): Promise<void> {
35
+ const key = this.getKey(id, sector);
36
+ await this.client.del(key);
37
+ }
38
+
39
+ async deleteVectors(id: string): Promise<void> {
40
+ // This is inefficient in Redis without an index on ID across sectors.
41
+ // We might need to track which sectors an ID has.
42
+ // For now, we can scan or just assume we know the sectors?
43
+ // The interface implies we delete ALL vectors for this ID.
44
+ // In Postgres we did `delete from vectors where id=$1`.
45
+ // In Redis, we might need to know the sectors.
46
+ // Or we can use `keys vec:*:${id}` which is slow.
47
+ // Better approach: maintain a set of sectors for each ID?
48
+ // Or just iterate over known sectors (from hsg.ts sectors list).
49
+ // I'll import `sectors` from `../../memory/hsg`? No, circular dependency risk.
50
+ // I'll use a scan for now as it's safer, or just accept it might be slow.
51
+ // Actually, `keys` is blocking. `scan` is better.
52
+ // But `id` is at the end of the key `vec:{sector}:{id}`.
53
+ // Pattern: `vec:*:${id}`.
54
+
55
+ let cursor = "0";
56
+ do {
57
+ const res = await this.client.scan(cursor, "MATCH", `vec:*:${id}`, "COUNT", 100);
58
+ cursor = res[0];
59
+ const keys = res[1];
60
+ if (keys.length) await this.client.del(...keys);
61
+ } while (cursor !== "0");
62
+ }
63
+
64
+ async searchSimilar(sector: string, queryVec: number[], topK: number): Promise<Array<{ id: string; score: number }>> {
65
+ // Try to use FT.SEARCH if index exists.
66
+ // Index name assumption: `idx:{sector}`
67
+ // Query: `*=>[KNN {k} @v $blob AS score]`
68
+ const indexName = `idx:${sector}`;
69
+ const blob = vectorToBuffer(queryVec);
70
+
71
+ try {
72
+ // Check if index exists (optional, or just try search)
73
+ // We'll try the search.
74
+ // FT.SEARCH idx:sector "*=>[KNN 10 @v $blob AS score]" PARAMS 2 blob "\x..." DIALECT 2
75
+ const res = await this.client.call(
76
+ "FT.SEARCH",
77
+ indexName,
78
+ `*=>[KNN ${topK} @v $blob AS score]`,
79
+ "PARAMS",
80
+ "2",
81
+ "blob",
82
+ blob,
83
+ "DIALECT",
84
+ "2"
85
+ ) as any[];
86
+
87
+ // Parse result
88
+ // [total_results, key1, [field1, val1, ...], key2, ...]
89
+ // We need to parse the array.
90
+ const count = res[0];
91
+ const results: Array<{ id: string; score: number }> = [];
92
+ for (let i = 1; i < res.length; i += 2) {
93
+ const key = res[i] as string; // e.g. vec:semantic:123
94
+ const fields = res[i + 1] as any[];
95
+ let id = "";
96
+ let score = 0;
97
+ // fields is array [k, v, k, v...]
98
+ for (let j = 0; j < fields.length; j += 2) {
99
+ const f = fields[j];
100
+ const v = fields[j + 1];
101
+ if (f === "id") id = v;
102
+ if (f === "score") score = 1 - (parseFloat(v) / 2); // Cosine distance to similarity?
103
+ // Valkey HNSW usually returns distance.
104
+ // If metric is COSINE, distance is 1 - cosine_sim.
105
+ // So sim = 1 - dist.
106
+ // Wait, standard RediSearch KNN distance depends on metric.
107
+ // Assuming COSINE metric.
108
+ }
109
+ // If id not in fields, extract from key
110
+ if (!id) {
111
+ const parts = key.split(":");
112
+ id = parts[parts.length - 1];
113
+ }
114
+ // If score not found (should be there as 'score'), default 0
115
+ // Actually, 'score' is the alias we gave.
116
+ // Wait, in FT.SEARCH response, the score is returned if we ask for it?
117
+ // Yes, "AS score" puts it in the fields.
118
+
119
+ // Correction: RediSearch returns distance by default for KNN?
120
+ // Yes, but we aliased it "AS score".
121
+ // So it should be in the fields as "score".
122
+
123
+ // Distance conversion:
124
+ // If distance is d, and we want cosine similarity.
125
+ // Cosine distance = 1 - cosine similarity.
126
+ // So similarity = 1 - distance.
127
+ results.push({ id, score: 1 - parseFloat(fields.find((f: any, idx: number) => f === "score" && idx % 2 === 0 ? false : fields[idx - 1] === "score") || "0") });
128
+ // The find logic above is tricky.
129
+ // Let's just loop.
130
+ }
131
+
132
+ // Fix score parsing loop
133
+ results.length = 0; // clear
134
+ for (let i = 1; i < res.length; i += 2) {
135
+ const key = res[i] as string;
136
+ const fields = res[i + 1] as any[];
137
+ let id = "";
138
+ let dist = 0;
139
+ for (let j = 0; j < fields.length; j += 2) {
140
+ if (fields[j] === "id") id = fields[j + 1];
141
+ if (fields[j] === "score") dist = parseFloat(fields[j + 1]);
142
+ }
143
+ if (!id) id = key.split(":").pop()!;
144
+ results.push({ id, score: 1 - dist });
145
+ }
146
+
147
+ return results;
148
+
149
+ } catch (e) {
150
+ console.warn(`[Valkey] FT.SEARCH failed for ${sector}, falling back to scan (slow):`, e);
151
+ // Fallback: Scan all vectors in sector and compute cosine sim
152
+ // This is very slow but ensures correctness if index is missing.
153
+ let cursor = "0";
154
+ const allVecs: Array<{ id: string; vector: number[] }> = [];
155
+ do {
156
+ const res = await this.client.scan(cursor, "MATCH", `vec:${sector}:*`, "COUNT", 100);
157
+ cursor = res[0];
158
+ const keys = res[1];
159
+ if (keys.length) {
160
+ // Pipeline get all
161
+ const pipe = this.client.pipeline();
162
+ keys.forEach(k => pipe.hget(k, "v"));
163
+ const buffers = await pipe.exec();
164
+ buffers?.forEach((b, idx) => {
165
+ if (b && b[1]) {
166
+ const buf = b[1] as Buffer;
167
+ const id = keys[idx].split(":").pop()!;
168
+ allVecs.push({ id, vector: bufferToVector(buf) });
169
+ }
170
+ });
171
+ }
172
+ } while (cursor !== "0");
173
+
174
+ const sims = allVecs.map(v => ({
175
+ id: v.id,
176
+ score: this.cosineSimilarity(queryVec, v.vector)
177
+ }));
178
+ sims.sort((a, b) => b.score - a.score);
179
+ return sims.slice(0, topK);
180
+ }
181
+ }
182
+
183
+ private cosineSimilarity(a: number[], b: number[]) {
184
+ if (a.length !== b.length) return 0;
185
+ let dot = 0, na = 0, nb = 0;
186
+ for (let i = 0; i < a.length; i++) {
187
+ dot += a[i] * b[i];
188
+ na += a[i] * a[i];
189
+ nb += b[i] * b[i];
190
+ }
191
+ return na && nb ? dot / (Math.sqrt(na) * Math.sqrt(nb)) : 0;
192
+ }
193
+
194
+ async getVector(id: string, sector: string): Promise<{ vector: number[]; dim: number } | null> {
195
+ const key = this.getKey(id, sector);
196
+ const res = await this.client.hmget(key, "v", "dim");
197
+ if (!res[0]) return null;
198
+ return {
199
+ vector: bufferToVector(res[0] as unknown as Buffer),
200
+ dim: parseInt(res[1] as string)
201
+ };
202
+ }
203
+
204
+ async getVectorsById(id: string): Promise<Array<{ sector: string; vector: number[]; dim: number }>> {
205
+ // Scan for vec:*:{id}
206
+ const results: Array<{ sector: string; vector: number[]; dim: number }> = [];
207
+ let cursor = "0";
208
+ do {
209
+ const res = await this.client.scan(cursor, "MATCH", `vec:*:${id}`, "COUNT", 100);
210
+ cursor = res[0];
211
+ const keys = res[1];
212
+ if (keys.length) {
213
+ const pipe = this.client.pipeline();
214
+ keys.forEach(k => pipe.hmget(k, "v", "dim"));
215
+ const res = await pipe.exec();
216
+ res?.forEach((r, idx) => {
217
+ if (r && r[1]) {
218
+ const [v, dim] = r[1] as [Buffer, string];
219
+ const key = keys[idx];
220
+ const parts = key.split(":");
221
+ const sector = parts[1];
222
+ results.push({
223
+ sector,
224
+ vector: bufferToVector(v),
225
+ dim: parseInt(dim)
226
+ });
227
+ }
228
+ });
229
+ }
230
+ } while (cursor !== "0");
231
+ return results;
232
+ }
233
+
234
+ async getVectorsBySector(sector: string): Promise<Array<{ id: string; vector: number[]; dim: number }>> {
235
+ const results: Array<{ id: string; vector: number[]; dim: number }> = [];
236
+ let cursor = "0";
237
+ do {
238
+ const res = await this.client.scan(cursor, "MATCH", `vec:${sector}:*`, "COUNT", 100);
239
+ cursor = res[0];
240
+ const keys = res[1];
241
+ if (keys.length) {
242
+ const pipe = this.client.pipeline();
243
+ keys.forEach(k => pipe.hmget(k, "v", "dim"));
244
+ const res = await pipe.exec();
245
+ res?.forEach((r, idx) => {
246
+ if (r && r[1]) {
247
+ const [v, dim] = r[1] as [Buffer, string];
248
+ const key = keys[idx];
249
+ const id = key.split(":").pop()!;
250
+ results.push({
251
+ id,
252
+ vector: bufferToVector(v),
253
+ dim: parseInt(dim)
254
+ });
255
+ }
256
+ });
257
+ }
258
+ } while (cursor !== "0");
259
+ return results;
260
+ }
261
+ }
@@ -0,0 +1,9 @@
1
+ export interface VectorStore {
2
+ storeVector(id: string, sector: string, vector: number[], dim: number, user_id?: string): Promise<void>;
3
+ deleteVector(id: string, sector: string): Promise<void>;
4
+ deleteVectors(id: string): Promise<void>;
5
+ searchSimilar(sector: string, queryVec: number[], topK: number): Promise<Array<{ id: string; score: number }>>;
6
+ getVector(id: string, sector: string): Promise<{ vector: number[]; dim: number } | null>;
7
+ getVectorsById(id: string): Promise<Array<{ sector: string; vector: number[]; dim: number }>>;
8
+ getVectorsBySector(sector: string): Promise<Array<{ id: string; vector: number[]; dim: number }>>;
9
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ // Export core functionality for use as a package
2
+ export * from "./core/memory";
3
+ export * from "./server/index";
4
+ export * from "./ops/ingest";
5
+ export * as sources from "./sources";