@membank/dashboard 0.2.1 → 0.2.3
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/dist/index.cjs +201 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.mts +10 -0
- package/package.json +10 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let node_fs = require("node:fs");
|
|
25
|
+
let node_net = require("node:net");
|
|
26
|
+
let node_path = require("node:path");
|
|
27
|
+
let node_url = require("node:url");
|
|
28
|
+
let _hono_node_server = require("@hono/node-server");
|
|
29
|
+
let _membank_core = require("@membank/core");
|
|
30
|
+
let hono = require("hono");
|
|
31
|
+
let open = require("open");
|
|
32
|
+
open = __toESM(open, 1);
|
|
33
|
+
//#region src/server/index.ts
|
|
34
|
+
const PREFERRED_PORT = 3847;
|
|
35
|
+
const MIME = {
|
|
36
|
+
".js": "application/javascript",
|
|
37
|
+
".mjs": "application/javascript",
|
|
38
|
+
".css": "text/css",
|
|
39
|
+
".html": "text/html",
|
|
40
|
+
".svg": "image/svg+xml",
|
|
41
|
+
".ico": "image/x-icon",
|
|
42
|
+
".woff2": "font/woff2",
|
|
43
|
+
".woff": "font/woff",
|
|
44
|
+
".ttf": "font/ttf",
|
|
45
|
+
".png": "image/png",
|
|
46
|
+
".json": "application/json"
|
|
47
|
+
};
|
|
48
|
+
function parseRow(row) {
|
|
49
|
+
return {
|
|
50
|
+
id: row.id,
|
|
51
|
+
content: row.content,
|
|
52
|
+
type: row.type,
|
|
53
|
+
tags: JSON.parse(row.tags),
|
|
54
|
+
scope: row.scope,
|
|
55
|
+
sourceHarness: row.source,
|
|
56
|
+
accessCount: row.access_count,
|
|
57
|
+
pinned: row.pinned !== 0,
|
|
58
|
+
needsReview: row.needs_review !== 0,
|
|
59
|
+
createdAt: row.created_at,
|
|
60
|
+
updatedAt: row.updated_at
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function tryPort(port) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const server = (0, node_net.createServer)();
|
|
66
|
+
server.listen(port, () => {
|
|
67
|
+
server.close(() => resolve(port));
|
|
68
|
+
});
|
|
69
|
+
server.on("error", reject);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function findFreePort(preferred) {
|
|
73
|
+
try {
|
|
74
|
+
return await tryPort(preferred);
|
|
75
|
+
} catch {
|
|
76
|
+
return await new Promise((resolve) => {
|
|
77
|
+
const server = (0, node_net.createServer)();
|
|
78
|
+
server.listen(0, () => {
|
|
79
|
+
const addr = server.address();
|
|
80
|
+
const port = addr !== null && typeof addr === "object" ? addr.port : 0;
|
|
81
|
+
server.close(() => resolve(port));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function createApiApp(db, repo) {
|
|
87
|
+
const app = new hono.Hono();
|
|
88
|
+
app.get("/api/memories", (c) => {
|
|
89
|
+
const { type, pinned, needsReview, search, scope } = c.req.query();
|
|
90
|
+
const conditions = [];
|
|
91
|
+
const params = [];
|
|
92
|
+
if (type) {
|
|
93
|
+
conditions.push("type = ?");
|
|
94
|
+
params.push(type);
|
|
95
|
+
}
|
|
96
|
+
if (pinned === "true") conditions.push("pinned = 1");
|
|
97
|
+
if (needsReview === "true") conditions.push("needs_review = 1");
|
|
98
|
+
if (scope) {
|
|
99
|
+
conditions.push("scope = ?");
|
|
100
|
+
params.push(scope);
|
|
101
|
+
}
|
|
102
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
103
|
+
let memories = db.db.prepare(`SELECT * FROM memories ${where} ORDER BY created_at DESC`).all(...params).map(parseRow);
|
|
104
|
+
if (search) {
|
|
105
|
+
const q = search.toLowerCase();
|
|
106
|
+
memories = memories.filter((m) => m.content.toLowerCase().includes(q));
|
|
107
|
+
}
|
|
108
|
+
return c.json(memories);
|
|
109
|
+
});
|
|
110
|
+
app.get("/api/memories/:id", (c) => {
|
|
111
|
+
const row = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(c.req.param("id"));
|
|
112
|
+
if (!row) return c.json({ error: "Not found" }, 404);
|
|
113
|
+
return c.json(parseRow(row));
|
|
114
|
+
});
|
|
115
|
+
app.patch("/api/memories/:id", async (c) => {
|
|
116
|
+
const id = c.req.param("id");
|
|
117
|
+
if (!db.db.prepare("SELECT id FROM memories WHERE id = ?").get(id)) return c.json({ error: "Not found" }, 404);
|
|
118
|
+
const body = await c.req.json();
|
|
119
|
+
const sets = [];
|
|
120
|
+
const sqlParams = [];
|
|
121
|
+
if (body.pinned !== void 0) {
|
|
122
|
+
sets.push("pinned = ?");
|
|
123
|
+
sqlParams.push(body.pinned ? 1 : 0);
|
|
124
|
+
}
|
|
125
|
+
if (body.needsReview !== void 0) {
|
|
126
|
+
sets.push("needs_review = ?");
|
|
127
|
+
sqlParams.push(body.needsReview ? 1 : 0);
|
|
128
|
+
}
|
|
129
|
+
if (body.type !== void 0) {
|
|
130
|
+
sets.push("type = ?");
|
|
131
|
+
sqlParams.push(body.type);
|
|
132
|
+
}
|
|
133
|
+
if (sets.length > 0) {
|
|
134
|
+
sets.push("updated_at = ?");
|
|
135
|
+
sqlParams.push((/* @__PURE__ */ new Date()).toISOString(), id);
|
|
136
|
+
db.db.prepare(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`).run(...sqlParams);
|
|
137
|
+
}
|
|
138
|
+
if (body.content !== void 0 || body.tags !== void 0) await repo.update(id, {
|
|
139
|
+
content: body.content,
|
|
140
|
+
tags: body.tags
|
|
141
|
+
});
|
|
142
|
+
const updated = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
|
|
143
|
+
return c.json(parseRow(updated));
|
|
144
|
+
});
|
|
145
|
+
app.delete("/api/memories/:id", async (c) => {
|
|
146
|
+
await repo.delete(c.req.param("id"));
|
|
147
|
+
return c.json({ ok: true });
|
|
148
|
+
});
|
|
149
|
+
app.get("/api/stats", (c) => {
|
|
150
|
+
const byType = {
|
|
151
|
+
correction: 0,
|
|
152
|
+
preference: 0,
|
|
153
|
+
decision: 0,
|
|
154
|
+
learning: 0,
|
|
155
|
+
fact: 0
|
|
156
|
+
};
|
|
157
|
+
const typeRows = db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
|
|
158
|
+
for (const row of typeRows) if (row.type in byType) byType[row.type] = row.count;
|
|
159
|
+
const totals = db.db.prepare("SELECT COUNT(*) as total, SUM(needs_review) as needsReview FROM memories").get() ?? {
|
|
160
|
+
total: 0,
|
|
161
|
+
needsReview: 0
|
|
162
|
+
};
|
|
163
|
+
return c.json({
|
|
164
|
+
byType,
|
|
165
|
+
total: totals.total,
|
|
166
|
+
needsReview: totals.needsReview ?? 0
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
return app;
|
|
170
|
+
}
|
|
171
|
+
async function startDashboard(opts) {
|
|
172
|
+
const port = await findFreePort(opts?.port ?? PREFERRED_PORT);
|
|
173
|
+
const db = _membank_core.DatabaseManager.open();
|
|
174
|
+
const app = createApiApp(db, new _membank_core.MemoryRepository(db, new _membank_core.EmbeddingService()));
|
|
175
|
+
const clientDir = (0, node_path.join)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), "client");
|
|
176
|
+
app.get("*", (c) => {
|
|
177
|
+
const filePath = (0, node_path.join)(clientDir, c.req.path === "/" ? "/index.html" : c.req.path);
|
|
178
|
+
if ((0, node_fs.existsSync)(filePath)) {
|
|
179
|
+
const content = (0, node_fs.readFileSync)(filePath);
|
|
180
|
+
const mime = MIME[(0, node_path.extname)(filePath)] ?? "application/octet-stream";
|
|
181
|
+
return new Response(content, { headers: { "content-type": mime } });
|
|
182
|
+
}
|
|
183
|
+
const html = (0, node_fs.readFileSync)((0, node_path.join)(clientDir, "index.html"));
|
|
184
|
+
return new Response(html, { headers: { "content-type": "text/html" } });
|
|
185
|
+
});
|
|
186
|
+
process.on("SIGINT", () => {
|
|
187
|
+
db.close();
|
|
188
|
+
process.exit(0);
|
|
189
|
+
});
|
|
190
|
+
(0, _hono_node_server.serve)({
|
|
191
|
+
fetch: app.fetch,
|
|
192
|
+
port
|
|
193
|
+
});
|
|
194
|
+
process.stdout.write(`\n Membank dashboard → http://localhost:${port}\n`);
|
|
195
|
+
process.stdout.write(` Press Ctrl+C to stop\n\n`);
|
|
196
|
+
await (0, open.default)(`http://localhost:${port}`);
|
|
197
|
+
await new Promise(() => {});
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
exports.createApiApp = createApiApp;
|
|
201
|
+
exports.startDashboard = startDashboard;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DatabaseManager, MemoryRepository } from "@membank/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
|
|
4
|
+
//#region src/server/index.d.ts
|
|
5
|
+
declare function createApiApp(db: DatabaseManager, repo: MemoryRepository): Hono;
|
|
6
|
+
declare function startDashboard(opts?: {
|
|
7
|
+
port?: number;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { createApiApp, startDashboard };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DatabaseManager, MemoryRepository } from "@membank/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
|
|
4
|
+
//#region src/server/index.d.ts
|
|
5
|
+
declare function createApiApp(db: DatabaseManager, repo: MemoryRepository): Hono;
|
|
6
|
+
declare function startDashboard(opts?: {
|
|
7
|
+
port?: number;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { createApiApp, startDashboard };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@membank/dashboard",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"import":
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"default": "./dist/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
13
20
|
}
|
|
14
21
|
},
|
|
15
22
|
"files": [
|
|
@@ -36,7 +43,7 @@
|
|
|
36
43
|
"tailwind-merge": "^3.0.0",
|
|
37
44
|
"tw-animate-css": "^1.0.0",
|
|
38
45
|
"zod": "^4.3.6",
|
|
39
|
-
"@membank/core": "0.
|
|
46
|
+
"@membank/core": "0.5.1"
|
|
40
47
|
},
|
|
41
48
|
"devDependencies": {
|
|
42
49
|
"@tailwindcss/vite": "^4.0.0",
|