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,399 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.track_req = track_req;
37
+ exports.req_tracker_mw = req_tracker_mw;
38
+ exports.dash = dash;
39
+ const db_1 = require("../../core/db");
40
+ const cfg_1 = require("../../core/cfg");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const is_pg = cfg_1.env.metadata_backend === "postgres";
44
+ const get_mem_table = () => {
45
+ if (is_pg) {
46
+ const sc = process.env.OM_PG_SCHEMA || "public";
47
+ const tbl = process.env.OM_PG_TABLE || "openmemory_memories";
48
+ return `"${sc}"."${tbl}"`;
49
+ }
50
+ return "memories";
51
+ };
52
+ let reqz = {
53
+ win_start: Date.now(),
54
+ win_cnt: 0,
55
+ qps_hist: [],
56
+ };
57
+ const log_metric = async (type, value) => {
58
+ try {
59
+ const sc = process.env.OM_PG_SCHEMA || "public";
60
+ const sql = is_pg
61
+ ? `insert into "${sc}"."stats"(type,count,ts) values($1,$2,$3)`
62
+ : "insert into stats(type,count,ts) values(?,?,?)";
63
+ await (0, db_1.run_async)(sql, [type, value, Date.now()]);
64
+ }
65
+ catch (e) {
66
+ console.error("[metrics] log err:", e);
67
+ }
68
+ };
69
+ function track_req(success) {
70
+ const now = Date.now();
71
+ if (now - reqz.win_start >= 1000) {
72
+ const qps = reqz.win_cnt;
73
+ reqz.qps_hist.push(qps);
74
+ if (reqz.qps_hist.length > 5)
75
+ reqz.qps_hist.shift();
76
+ // Log metrics to database every second
77
+ log_metric("qps", qps).catch(console.error);
78
+ if (!success)
79
+ log_metric("error", 1).catch(console.error);
80
+ reqz.win_start = now;
81
+ reqz.win_cnt = 1;
82
+ }
83
+ else {
84
+ reqz.win_cnt++;
85
+ }
86
+ }
87
+ function req_tracker_mw() {
88
+ return (req, res, next) => {
89
+ if (req.url.startsWith("/dashboard") || req.url.startsWith("/health")) {
90
+ return next();
91
+ }
92
+ const orig = res.json.bind(res);
93
+ res.json = (data) => {
94
+ track_req(res.statusCode < 400);
95
+ return orig(data);
96
+ };
97
+ next();
98
+ };
99
+ }
100
+ const get_db_sz = async () => {
101
+ try {
102
+ if (is_pg) {
103
+ const db_name = process.env.OM_PG_DB || "openmemory";
104
+ const result = await (0, db_1.all_async)(`SELECT pg_database_size('${db_name}') as size`);
105
+ return result[0]?.size
106
+ ? Math.round(result[0].size / 1024 / 1024)
107
+ : 0;
108
+ }
109
+ else {
110
+ const dbp = path.resolve(process.cwd(), "./backend", cfg_1.env.db_path);
111
+ if (fs.existsSync(dbp)) {
112
+ const st = fs.statSync(dbp);
113
+ return Math.round(st.size / 1024 / 1024);
114
+ }
115
+ return 0;
116
+ }
117
+ }
118
+ catch (e) {
119
+ console.error("[db_sz] err:", e);
120
+ return 0;
121
+ }
122
+ };
123
+ function dash(app) {
124
+ app.get("/dashboard/stats", async (_req, res) => {
125
+ try {
126
+ const mem_table = get_mem_table();
127
+ const totmem = await (0, db_1.all_async)(`SELECT COUNT(*) as count FROM ${mem_table}`);
128
+ const sectcnt = await (0, db_1.all_async)(`
129
+ SELECT primary_sector, COUNT(*) as count
130
+ FROM ${mem_table}
131
+ GROUP BY primary_sector
132
+ `);
133
+ const dayago = Date.now() - 24 * 60 * 60 * 1000;
134
+ const recmem = await (0, db_1.all_async)(is_pg
135
+ ? `SELECT COUNT(*) as count FROM ${mem_table} WHERE created_at > $1`
136
+ : `SELECT COUNT(*) as count FROM ${mem_table} WHERE created_at > ?`, [dayago]);
137
+ const avgsal = await (0, db_1.all_async)(`SELECT AVG(salience) as avg FROM ${mem_table}`);
138
+ const decst = await (0, db_1.all_async)(`
139
+ SELECT
140
+ COUNT(*) as total,
141
+ AVG(decay_lambda) as avg_lambda,
142
+ MIN(salience) as min_salience,
143
+ MAX(salience) as max_salience
144
+ FROM ${mem_table}
145
+ `);
146
+ const upt = process.uptime();
147
+ // Calculate QPS stats from database (last hour)
148
+ const hour_ago = Date.now() - 60 * 60 * 1000;
149
+ const sc = process.env.OM_PG_SCHEMA || "public";
150
+ const qps_data = await (0, db_1.all_async)(is_pg
151
+ ? `SELECT count, ts FROM "${sc}"."stats" WHERE type=$1 AND ts > $2 ORDER BY ts DESC`
152
+ : "SELECT count, ts FROM stats WHERE type=? AND ts > ? ORDER BY ts DESC", ["qps", hour_ago]);
153
+ const err_data = await (0, db_1.all_async)(is_pg
154
+ ? `SELECT COUNT(*) as total FROM "${sc}"."stats" WHERE type=$1 AND ts > $2`
155
+ : "SELECT COUNT(*) as total FROM stats WHERE type=? AND ts > ?", ["error", hour_ago]);
156
+ const peak_qps = qps_data.length > 0
157
+ ? Math.max(...qps_data.map((d) => d.count))
158
+ : 0;
159
+ const avg_qps = reqz.qps_hist.length > 0
160
+ ? Math.round((reqz.qps_hist.reduce((a, b) => a + b, 0) /
161
+ reqz.qps_hist.length) *
162
+ 100) / 100
163
+ : 0;
164
+ const total_reqs = qps_data.reduce((sum, d) => sum + d.count, 0);
165
+ const total_errs = err_data[0]?.total || 0;
166
+ const err_rate = total_reqs > 0
167
+ ? ((total_errs / total_reqs) * 100).toFixed(1)
168
+ : "0.0";
169
+ const dbsz = await get_db_sz();
170
+ const dbpct = dbsz > 0 ? Math.min(100, Math.round((dbsz / 1024) * 100)) : 0;
171
+ const cachit = totmem[0]?.count > 0
172
+ ? Math.round((totmem[0].count /
173
+ (totmem[0].count + total_errs * 2)) *
174
+ 100)
175
+ : 0;
176
+ res.json({
177
+ totalMemories: totmem[0]?.count || 0,
178
+ recentMemories: recmem[0]?.count || 0,
179
+ sectorCounts: sectcnt.reduce((acc, row) => {
180
+ acc[row.primary_sector] = row.count;
181
+ return acc;
182
+ }, {}),
183
+ avgSalience: Number(avgsal[0]?.avg || 0).toFixed(3),
184
+ decayStats: {
185
+ total: decst[0]?.total || 0,
186
+ avgLambda: Number(decst[0]?.avg_lambda || 0).toFixed(3),
187
+ minSalience: Number(decst[0]?.min_salience || 0).toFixed(3),
188
+ maxSalience: Number(decst[0]?.max_salience || 0).toFixed(3),
189
+ },
190
+ requests: {
191
+ total: total_reqs,
192
+ errors: total_errs,
193
+ errorRate: err_rate,
194
+ lastHour: qps_data.length,
195
+ },
196
+ qps: { peak: peak_qps, average: avg_qps, cacheHitRate: cachit },
197
+ system: {
198
+ memoryUsage: dbpct,
199
+ heapUsed: dbsz,
200
+ heapTotal: 1024,
201
+ uptime: {
202
+ seconds: Math.floor(upt),
203
+ days: Math.floor(upt / 86400),
204
+ hours: Math.floor((upt % 86400) / 3600),
205
+ },
206
+ },
207
+ config: {
208
+ port: cfg_1.env.port,
209
+ vecDim: cfg_1.env.vec_dim,
210
+ cacheSegments: cfg_1.env.cache_segments,
211
+ maxActive: cfg_1.env.max_active,
212
+ decayInterval: cfg_1.env.decay_interval_minutes,
213
+ embedProvider: cfg_1.env.emb_kind,
214
+ },
215
+ });
216
+ }
217
+ catch (e) {
218
+ console.error("[dash] stats err:", e);
219
+ res.status(500).json({ err: "internal", message: e.message });
220
+ }
221
+ });
222
+ app.get("/dashboard/health", async (_req, res) => {
223
+ try {
224
+ const memusg = process.memoryUsage();
225
+ const upt = process.uptime();
226
+ res.json({
227
+ memory: {
228
+ heapUsed: Math.round(memusg.heapUsed / 1024 / 1024),
229
+ heapTotal: Math.round(memusg.heapTotal / 1024 / 1024),
230
+ rss: Math.round(memusg.rss / 1024 / 1024),
231
+ external: Math.round(memusg.external / 1024 / 1024),
232
+ },
233
+ uptime: {
234
+ seconds: Math.floor(upt),
235
+ days: Math.floor(upt / 86400),
236
+ hours: Math.floor((upt % 86400) / 3600),
237
+ },
238
+ process: {
239
+ pid: process.pid,
240
+ version: process.version,
241
+ platform: process.platform,
242
+ },
243
+ });
244
+ }
245
+ catch (e) {
246
+ res.status(500).json({ err: "internal", message: e.message });
247
+ }
248
+ });
249
+ app.get("/dashboard/activity", async (req, res) => {
250
+ try {
251
+ const mem_table = get_mem_table();
252
+ const lim = parseInt(req.query.limit || "50");
253
+ const recmem = await (0, db_1.all_async)(is_pg
254
+ ? `SELECT id, content, primary_sector, salience, created_at, updated_at, last_seen_at
255
+ FROM ${mem_table} ORDER BY updated_at DESC LIMIT $1`
256
+ : `SELECT id, content, primary_sector, salience, created_at, updated_at, last_seen_at
257
+ FROM ${mem_table} ORDER BY updated_at DESC LIMIT ?`, [lim]);
258
+ res.json({
259
+ activities: recmem.map((m) => ({
260
+ id: m.id,
261
+ type: "memory_updated",
262
+ sector: m.primary_sector,
263
+ content: m.content.substring(0, 100) + "...",
264
+ salience: m.salience,
265
+ timestamp: m.updated_at || m.created_at,
266
+ })),
267
+ });
268
+ }
269
+ catch (e) {
270
+ res.status(500).json({ err: "internal", message: e.message });
271
+ }
272
+ });
273
+ app.get("/dashboard/sectors/timeline", async (req, res) => {
274
+ try {
275
+ const mem_table = get_mem_table();
276
+ const hrs = parseInt(req.query.hours || "24");
277
+ const strt = Date.now() - hrs * 60 * 60 * 1000;
278
+ // Use different grouping based on time range
279
+ let displayFormat;
280
+ let sortFormat;
281
+ let timeKey;
282
+ if (hrs <= 24) {
283
+ // For 24 hours or less, group by date+hour for sorting, display only hour
284
+ displayFormat = is_pg
285
+ ? "to_char(to_timestamp(created_at/1000), 'HH24:00')"
286
+ : "strftime('%H:00', datetime(created_at/1000, 'unixepoch', 'localtime'))";
287
+ sortFormat = is_pg
288
+ ? "to_char(to_timestamp(created_at/1000), 'YYYY-MM-DD HH24:00')"
289
+ : "strftime('%Y-%m-%d %H:00', datetime(created_at/1000, 'unixepoch', 'localtime'))";
290
+ timeKey = "hour";
291
+ }
292
+ else if (hrs <= 168) {
293
+ // For up to 7 days, group by day
294
+ displayFormat = is_pg
295
+ ? "to_char(to_timestamp(created_at/1000), 'MM-DD')"
296
+ : "strftime('%m-%d', datetime(created_at/1000, 'unixepoch', 'localtime'))";
297
+ sortFormat = is_pg
298
+ ? "to_char(to_timestamp(created_at/1000), 'YYYY-MM-DD')"
299
+ : "strftime('%Y-%m-%d', datetime(created_at/1000, 'unixepoch', 'localtime'))";
300
+ timeKey = "day";
301
+ }
302
+ else {
303
+ // For longer periods (30 days), group by day showing month-day
304
+ displayFormat = is_pg
305
+ ? "to_char(to_timestamp(created_at/1000), 'MM-DD')"
306
+ : "strftime('%m-%d', datetime(created_at/1000, 'unixepoch', 'localtime'))";
307
+ sortFormat = is_pg
308
+ ? "to_char(to_timestamp(created_at/1000), 'YYYY-MM-DD')"
309
+ : "strftime('%Y-%m-%d', datetime(created_at/1000, 'unixepoch', 'localtime'))";
310
+ timeKey = "day";
311
+ }
312
+ const tl = await (0, db_1.all_async)(is_pg
313
+ ? `SELECT primary_sector, ${displayFormat} as label, ${sortFormat} as sort_key, COUNT(*) as count
314
+ FROM ${mem_table} WHERE created_at > $1 GROUP BY primary_sector, ${sortFormat} ORDER BY sort_key`
315
+ : `SELECT primary_sector, ${displayFormat} as label, ${sortFormat} as sort_key, COUNT(*) as count
316
+ FROM ${mem_table} WHERE created_at > ? GROUP BY primary_sector, ${sortFormat} ORDER BY sort_key`, [strt]);
317
+ res.json({
318
+ timeline: tl.map((row) => ({ ...row, hour: row.label })),
319
+ grouping: timeKey,
320
+ });
321
+ }
322
+ catch (e) {
323
+ res.status(500).json({ err: "internal", message: e.message });
324
+ }
325
+ });
326
+ app.get("/dashboard/top-memories", async (req, res) => {
327
+ try {
328
+ const mem_table = get_mem_table();
329
+ const lim = parseInt(req.query.limit || "10");
330
+ const topm = await (0, db_1.all_async)(is_pg
331
+ ? `SELECT id, content, primary_sector, salience, last_seen_at
332
+ FROM ${mem_table} ORDER BY salience DESC LIMIT $1`
333
+ : `SELECT id, content, primary_sector, salience, last_seen_at
334
+ FROM ${mem_table} ORDER BY salience DESC LIMIT ?`, [lim]);
335
+ res.json({
336
+ memories: topm.map((m) => ({
337
+ id: m.id,
338
+ content: m.content,
339
+ sector: m.primary_sector,
340
+ salience: m.salience,
341
+ lastSeen: m.last_seen_at,
342
+ })),
343
+ });
344
+ }
345
+ catch (e) {
346
+ res.status(500).json({ err: "internal", message: e.message });
347
+ }
348
+ });
349
+ app.get("/dashboard/maintenance", async (req, res) => {
350
+ try {
351
+ const hrs = parseInt(req.query.hours || "24");
352
+ const strt = Date.now() - hrs * 60 * 60 * 1000;
353
+ const sc = process.env.OM_PG_SCHEMA || "public";
354
+ const ops = await (0, db_1.all_async)(is_pg
355
+ ? `SELECT type, to_char(to_timestamp(ts/1000), 'HH24:00') as hour, SUM(count) as cnt
356
+ FROM "${sc}"."stats" WHERE ts > $1 GROUP BY type, hour ORDER BY hour`
357
+ : `SELECT type, strftime('%H:00', datetime(ts/1000, 'unixepoch', 'localtime')) as hour, SUM(count) as cnt
358
+ FROM stats WHERE ts > ? GROUP BY type, hour ORDER BY hour`, [strt]);
359
+ const totals = await (0, db_1.all_async)(is_pg
360
+ ? `SELECT type, SUM(count) as total FROM "${sc}"."stats" WHERE ts > $1 GROUP BY type`
361
+ : `SELECT type, SUM(count) as total FROM stats WHERE ts > ? GROUP BY type`, [strt]);
362
+ const by_hr = {};
363
+ for (const op of ops) {
364
+ if (!by_hr[op.hour])
365
+ by_hr[op.hour] = {
366
+ hour: op.hour,
367
+ decay: 0,
368
+ reflection: 0,
369
+ consolidation: 0,
370
+ };
371
+ if (op.type === "decay")
372
+ by_hr[op.hour].decay = op.cnt;
373
+ else if (op.type === "reflect")
374
+ by_hr[op.hour].reflection = op.cnt;
375
+ else if (op.type === "consolidate")
376
+ by_hr[op.hour].consolidation = op.cnt;
377
+ }
378
+ const tot_decay = totals.find((t) => t.type === "decay")?.total || 0;
379
+ const tot_reflect = totals.find((t) => t.type === "reflect")?.total || 0;
380
+ const tot_consol = totals.find((t) => t.type === "consolidate")?.total || 0;
381
+ const tot_ops = tot_decay + tot_reflect + tot_consol;
382
+ const efficiency = tot_ops > 0
383
+ ? Math.round(((tot_reflect + tot_consol) / tot_ops) * 100)
384
+ : 0;
385
+ res.json({
386
+ operations: Object.values(by_hr),
387
+ totals: {
388
+ cycles: tot_decay,
389
+ reflections: tot_reflect,
390
+ consolidations: tot_consol,
391
+ efficiency,
392
+ },
393
+ });
394
+ }
395
+ catch (e) {
396
+ res.status(500).json({ err: "internal", message: e.message });
397
+ }
398
+ });
399
+ }
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.docs_route = docs_route;
4
+ const OPENAPI_SPEC = {
5
+ openapi: "3.1.0",
6
+ info: {
7
+ title: "Ahok Memory Cloud API",
8
+ description: "Universal Long-Term Memory for AI Agents and Applications. High-performance, multi-sector vector memory based on Hierarchical Segmented Graphs (HSG).",
9
+ version: "2.0.0",
10
+ },
11
+ servers: [
12
+ {
13
+ url: "https://zqmt62peqz.us-east-1.awsapprunner.com",
14
+ description: "Production Environment",
15
+ },
16
+ ],
17
+ components: {
18
+ securitySchemes: {
19
+ ApiKeyAuth: {
20
+ type: "apiKey",
21
+ in: "header",
22
+ name: "x-api-key",
23
+ },
24
+ },
25
+ schemas: {
26
+ Memory: {
27
+ type: "object",
28
+ properties: {
29
+ id: { type: "string", format: "uuid" },
30
+ content: { type: "string" },
31
+ primary_sector: { type: "string" },
32
+ sectors: { type: "array", items: { type: "string" } },
33
+ tags: { type: "array", items: { type: "string" } },
34
+ metadata: { type: "object" },
35
+ created_at: { type: "number" },
36
+ updated_at: { type: "number" },
37
+ salience: { type: "number" },
38
+ },
39
+ },
40
+ },
41
+ },
42
+ security: [{ ApiKeyAuth: [] }],
43
+ paths: {
44
+ "/memory/add": {
45
+ post: {
46
+ summary: "Add a new memory",
47
+ description: "Stores a piece of information in the long-term memory. It will be automatically classified and indexed across relevant sectors.",
48
+ requestBody: {
49
+ required: true,
50
+ content: {
51
+ "application/json": {
52
+ schema: {
53
+ type: "object",
54
+ required: ["content"],
55
+ properties: {
56
+ content: { type: "string", description: "The text content to remember." },
57
+ tags: { type: "array", items: { type: "string" }, description: "Optional tags for categorization." },
58
+ metadata: { type: "object", description: "Optional arbitrary metadata." },
59
+ user_id: { type: "string", description: "Optional user identifier for multi-tenant isolation." },
60
+ },
61
+ },
62
+ },
63
+ },
64
+ },
65
+ responses: {
66
+ 200: {
67
+ description: "Memory successfully added",
68
+ content: {
69
+ "application/json": {
70
+ schema: { $ref: "#/components/schemas/Memory" },
71
+ },
72
+ },
73
+ },
74
+ },
75
+ },
76
+ },
77
+ "/memory/query": {
78
+ post: {
79
+ summary: "Query contextual memory",
80
+ description: "Performs a semantic and contextual search across memories. Returns the most relevant matches based on similarity, salience, and temporal factors.",
81
+ requestBody: {
82
+ required: true,
83
+ content: {
84
+ "application/json": {
85
+ schema: {
86
+ type: "object",
87
+ required: ["query"],
88
+ properties: {
89
+ query: { type: "string", description: "The search query (natural language)." },
90
+ k: { type: "integer", default: 8, description: "Number of results to return." },
91
+ user_id: { type: "string", description: "Filter by user identifier." },
92
+ filters: {
93
+ type: "object",
94
+ properties: {
95
+ sector: { type: "string", description: "Filter by a specific memory sector." },
96
+ min_score: { type: "number", description: "Minimum relevance score (0-1)." },
97
+ },
98
+ },
99
+ },
100
+ },
101
+ },
102
+ },
103
+ },
104
+ responses: {
105
+ 200: {
106
+ description: "Matching memories found",
107
+ content: {
108
+ "application/json": {
109
+ schema: {
110
+ type: "object",
111
+ properties: {
112
+ query: { type: "string" },
113
+ matches: {
114
+ type: "array",
115
+ items: {
116
+ type: "object",
117
+ properties: {
118
+ id: { type: "string" },
119
+ content: { type: "string" },
120
+ score: { type: "number" },
121
+ sectors: { type: "array", items: { type: "string" } },
122
+ salience: { type: "number" },
123
+ },
124
+ },
125
+ },
126
+ },
127
+ },
128
+ },
129
+ },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ "/memory/all": {
135
+ get: {
136
+ summary: "List all memories",
137
+ description: "Retrieves a paginated list of all stored memories.",
138
+ parameters: [
139
+ { name: "user_id", in: "query", schema: { type: "string" } },
140
+ { name: "l", in: "query", schema: { type: "integer", default: 50 }, description: "Limit" },
141
+ { name: "u", in: "query", schema: { type: "integer", default: 0 }, description: "Offset" },
142
+ ],
143
+ responses: {
144
+ 200: {
145
+ description: "List of memories",
146
+ content: {
147
+ "application/json": {
148
+ schema: {
149
+ type: "object",
150
+ properties: {
151
+ items: { type: "array", items: { $ref: "#/components/schemas/Memory" } },
152
+ },
153
+ },
154
+ },
155
+ },
156
+ },
157
+ },
158
+ },
159
+ },
160
+ "/memory/{id}": {
161
+ delete: {
162
+ summary: "Delete a memory",
163
+ parameters: [
164
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
165
+ { name: "user_id", in: "query", schema: { type: "string" } },
166
+ ],
167
+ responses: {
168
+ 200: {
169
+ description: "Memory deleted",
170
+ content: { "application/json": { schema: { type: "object", properties: { ok: { type: "boolean" } } } } },
171
+ },
172
+ },
173
+ },
174
+ },
175
+ "/health": {
176
+ get: {
177
+ summary: "System health check",
178
+ security: [],
179
+ responses: {
180
+ 200: {
181
+ description: "System is healthy",
182
+ content: { "application/json": { schema: { type: "object", properties: { ok: { type: "boolean" } } } } },
183
+ },
184
+ },
185
+ },
186
+ },
187
+ },
188
+ };
189
+ function docs_route(app) {
190
+ app.get("/openapi.json", (req, res) => {
191
+ res.json(OPENAPI_SPEC);
192
+ });
193
+ app.get("/docs", (req, res) => {
194
+ const html = `<!DOCTYPE html>
195
+ <html lang="en">
196
+ <head>
197
+ <meta charset="UTF-8">
198
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
199
+ <title>Ahok Memory Cloud API Docs</title>
200
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
201
+ <style>
202
+ body { margin: 0; background: #020617; }
203
+ .swagger-ui .topbar { display: none; }
204
+ .swagger-ui .info .title { color: #f8fafc; }
205
+ .swagger-ui .scheme-container { background: #0f172a; box-shadow: none; border-bottom: 1px solid #1e293b; }
206
+ .swagger-ui select, .swagger-ui input { background: #1e293b; color: #f8fafc; border: 1px solid #334155; }
207
+ .swagger-ui .opblock { border-radius: 12px; background: #0f172a; border: 1px solid #1e293b; }
208
+ .swagger-ui .opblock-tag { color: #f8fafc; border-bottom: 1px solid #1e293b; }
209
+ .swagger-ui .opblock .opblock-summary-description { color: #94a3b8; }
210
+ .swagger-ui section.models { border: 1px solid #1e293b; background: #0f172a; border-radius: 12px; }
211
+ .swagger-ui section.models h4 { color: #f8fafc; }
212
+ .swagger-ui .model-box { background: #020617; border: 1px solid #1e293b; }
213
+ .swagger-ui .btn.authorize { color: #10b981; border-color: #10b981; }
214
+ .swagger-ui .btn.authorize svg { fill: #10b981; }
215
+ .swagger-ui .opblock.opblock-post { border-color: #0ea5e9; }
216
+ .swagger-ui .opblock.opblock-post .opblock-summary { border-color: #0ea5e9; }
217
+ .swagger-ui .opblock.opblock-post .opblock-summary-method { background: #0ea5e9; }
218
+ </style>
219
+ </head>
220
+ <body>
221
+ <div id="swagger-ui"></div>
222
+ <script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js"></script>
223
+ <script>
224
+ window.onload = () => {
225
+ window.ui = SwaggerUIBundle({
226
+ url: '/openapi.json',
227
+ dom_id: '#swagger-ui',
228
+ deepLinking: true,
229
+ presets: [
230
+ SwaggerUIBundle.presets.apis,
231
+ ],
232
+ layout: "BaseLayout"
233
+ });
234
+ };
235
+ </script>
236
+ </body>
237
+ </html>`;
238
+ res.setHeader("Content-Type", "text/html");
239
+ res.send(html);
240
+ });
241
+ }