@membank/dashboard 0.5.4 → 0.6.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/dist/index.cjs CHANGED
@@ -45,46 +45,6 @@ const MIME = {
45
45
  ".png": "image/png",
46
46
  ".json": "application/json"
47
47
  };
48
- function parseReviewEvent(row) {
49
- return {
50
- id: row.id,
51
- memoryId: row.memory_id,
52
- conflictingMemoryId: row.conflicting_memory_id,
53
- similarity: row.similarity,
54
- conflictContentSnapshot: row.conflict_content_snapshot,
55
- reason: row.reason,
56
- createdAt: row.created_at,
57
- resolvedAt: row.resolved_at
58
- };
59
- }
60
- function getReviewEventsForMemories(db, ids) {
61
- if (ids.length === 0) return /* @__PURE__ */ new Map();
62
- const placeholders = ids.map(() => "?").join(", ");
63
- const rows = db.db.prepare(`SELECT * FROM memory_review_events WHERE memory_id IN (${placeholders}) AND resolved_at IS NULL ORDER BY created_at DESC`).all(...ids);
64
- const map = /* @__PURE__ */ new Map();
65
- for (const row of rows) {
66
- const event = parseReviewEvent(row);
67
- const existing = map.get(event.memoryId) ?? [];
68
- existing.push(event);
69
- map.set(event.memoryId, existing);
70
- }
71
- return map;
72
- }
73
- function parseRow(row, projects = [], reviewEvents = []) {
74
- return {
75
- id: row.id,
76
- content: row.content,
77
- type: row.type,
78
- tags: JSON.parse(row.tags),
79
- projects,
80
- sourceHarness: row.source,
81
- accessCount: row.access_count,
82
- pinned: row.pinned !== 0,
83
- reviewEvents,
84
- createdAt: row.created_at,
85
- updatedAt: row.updated_at
86
- };
87
- }
88
48
  function tryPort(port) {
89
49
  return new Promise((resolve, reject) => {
90
50
  const server = (0, node_net.createServer)();
@@ -108,29 +68,16 @@ async function findFreePort(preferred) {
108
68
  });
109
69
  }
110
70
  }
111
- function createApiApp(db, repo, projectRepo) {
71
+ function createApiApp(repo, projectRepo, embedder) {
112
72
  const app = new hono.Hono();
113
73
  app.get("/api/memories", (c) => {
114
74
  const { type, pinned, needsReview, search, projectId } = c.req.query();
115
- const conditions = [];
116
- const params = [];
117
- if (type) {
118
- conditions.push("m.type = ?");
119
- params.push(type);
120
- }
121
- if (pinned === "true") conditions.push("m.pinned = 1");
122
- if (needsReview === "true") conditions.push("EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)");
123
- if (projectId === "global") conditions.push("m.id NOT IN (SELECT memory_id FROM memory_projects)");
124
- else if (projectId) {
125
- conditions.push("m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)");
126
- params.push(projectId);
127
- }
128
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
129
- const rows = db.db.prepare(`SELECT m.* FROM memories m ${where} ORDER BY m.created_at DESC`).all(...params);
130
- const ids = rows.map((r) => r.id);
131
- const projectMap = projectRepo.getProjectsForMemories(ids);
132
- const eventMap = getReviewEventsForMemories(db, ids);
133
- let memories = rows.map((r) => parseRow(r, projectMap.get(r.id) ?? [], eventMap.get(r.id) ?? []));
75
+ let memories = repo.list({
76
+ type,
77
+ pinned: pinned === "true" ? true : void 0,
78
+ needsReview: needsReview === "true" ? true : void 0,
79
+ projectId
80
+ });
134
81
  if (search) {
135
82
  const q = search.toLowerCase();
136
83
  memories = memories.filter((m) => m.content.toLowerCase().includes(q));
@@ -138,50 +85,33 @@ function createApiApp(db, repo, projectRepo) {
138
85
  return c.json(memories);
139
86
  });
140
87
  app.get("/api/memories/:id", (c) => {
141
- const id = c.req.param("id");
142
- const row = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
143
- if (!row) return c.json({ error: "Not found" }, 404);
144
- const projectMap = projectRepo.getProjectsForMemories([id]);
145
- const eventMap = getReviewEventsForMemories(db, [id]);
146
- return c.json(parseRow(row, projectMap.get(id) ?? [], eventMap.get(id) ?? []));
88
+ const memory = repo.findById(c.req.param("id"));
89
+ if (!memory) return c.json({ error: "Not found" }, 404);
90
+ return c.json(memory);
147
91
  });
148
92
  app.patch("/api/memories/:id", async (c) => {
149
93
  const id = c.req.param("id");
150
- if (!db.db.prepare("SELECT id FROM memories WHERE id = ?").get(id)) return c.json({ error: "Not found" }, 404);
94
+ if (!repo.findById(id)) return c.json({ error: "Not found" }, 404);
151
95
  const body = await c.req.json();
152
- const sets = [];
153
- const sqlParams = [];
154
- if (body.pinned !== void 0) {
155
- sets.push("pinned = ?");
156
- sqlParams.push(body.pinned ? 1 : 0);
157
- }
158
- if (body.type !== void 0) {
159
- sets.push("type = ?");
160
- sqlParams.push(body.type);
161
- }
162
- if (sets.length > 0) {
163
- sets.push("updated_at = ?");
164
- sqlParams.push((/* @__PURE__ */ new Date()).toISOString(), id);
165
- db.db.prepare(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`).run(...sqlParams);
166
- }
96
+ if (body.pinned !== void 0) repo.setPin(id, body.pinned);
167
97
  if (body.needsReview === false) repo.resolveReviewEvents(id);
168
- if (body.content !== void 0 || body.tags !== void 0) await repo.update(id, {
98
+ if (body.content !== void 0 || body.tags !== void 0 || body.type !== void 0) await (0, _membank_core.updateMemory)(id, {
169
99
  content: body.content,
170
- tags: body.tags
100
+ tags: body.tags,
101
+ type: body.type
102
+ }, {
103
+ repo,
104
+ embedder
171
105
  });
172
- const updated = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
173
- const projectMap = projectRepo.getProjectsForMemories([id]);
174
- const eventMap = getReviewEventsForMemories(db, [id]);
175
- return c.json(parseRow(updated, projectMap.get(id) ?? [], eventMap.get(id) ?? []));
106
+ return c.json(repo.findById(id));
176
107
  });
177
- app.delete("/api/memories/:id", async (c) => {
178
- await repo.delete(c.req.param("id"));
108
+ app.delete("/api/memories/:id", (c) => {
109
+ repo.delete(c.req.param("id"));
179
110
  return c.json({ ok: true });
180
111
  });
181
112
  app.post("/api/memories/:id/projects", async (c) => {
182
- const memoryId = c.req.param("id");
183
113
  const body = await c.req.json();
184
- projectRepo.addAssociation(memoryId, body.projectId);
114
+ projectRepo.addAssociation(c.req.param("id"), body.projectId);
185
115
  return c.json({ ok: true });
186
116
  });
187
117
  app.delete("/api/memories/:id/projects/:projectId", (c) => {
@@ -192,30 +122,19 @@ function createApiApp(db, repo, projectRepo) {
192
122
  return c.json(projectRepo.list());
193
123
  });
194
124
  app.patch("/api/projects/:id", async (c) => {
195
- const id = c.req.param("id");
196
125
  const body = await c.req.json();
197
126
  try {
198
- return c.json(projectRepo.rename(id, body.name));
127
+ return c.json(projectRepo.rename(c.req.param("id"), body.name));
199
128
  } catch {
200
129
  return c.json({ error: "Not found" }, 404);
201
130
  }
202
131
  });
203
132
  app.get("/api/stats", (c) => {
204
- const byType = {
205
- correction: 0,
206
- preference: 0,
207
- decision: 0,
208
- learning: 0,
209
- fact: 0
210
- };
211
- const typeRows = db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
212
- for (const row of typeRows) if (row.type in byType) byType[row.type] = row.count;
213
- const totals = db.db.prepare("SELECT COUNT(*) as total FROM memories").get() ?? { total: 0 };
214
- const reviewRow = db.db.prepare("SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL").get() ?? { needsReview: 0 };
133
+ const { byType, total, needsReview } = repo.stats();
215
134
  return c.json({
216
135
  byType,
217
- total: totals.total,
218
- needsReview: reviewRow.needsReview
136
+ total,
137
+ needsReview
219
138
  });
220
139
  });
221
140
  return app;
@@ -224,8 +143,8 @@ async function startDashboard(opts) {
224
143
  const port = await findFreePort(opts?.port ?? PREFERRED_PORT);
225
144
  const db = _membank_core.DatabaseManager.open();
226
145
  const embedding = new _membank_core.EmbeddingService();
227
- const projects = new _membank_core.ProjectRepository(db);
228
- const app = createApiApp(db, new _membank_core.MemoryRepository(db, embedding, projects), projects);
146
+ const projects = (0, _membank_core.createProjectRepository)(db);
147
+ const app = createApiApp((0, _membank_core.createMemoryRepository)(db, projects), projects, embedding);
229
148
  const clientDir = (0, node_path.join)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), "client");
230
149
  app.get("*", (c) => {
231
150
  const filePath = (0, node_path.join)(clientDir, c.req.path === "/" ? "/index.html" : c.req.path);
@@ -241,13 +160,16 @@ async function startDashboard(opts) {
241
160
  db.close();
242
161
  process.exit(0);
243
162
  });
244
- (0, _hono_node_server.serve)({
245
- fetch: app.fetch,
246
- port
163
+ await new Promise((resolve) => {
164
+ (0, _hono_node_server.serve)({
165
+ fetch: app.fetch,
166
+ port
167
+ }, () => {
168
+ opts?.onReady?.(port);
169
+ resolve();
170
+ });
247
171
  });
248
- process.stdout.write(`\n Membank dashboard → http://localhost:${port}\n`);
249
- process.stdout.write(` Press Ctrl+C to stop\n\n`);
250
- await (0, open.default)(`http://localhost:${port}`);
172
+ if (opts?.open) await (0, open.default)(`http://localhost:${port}`);
251
173
  await new Promise(() => {});
252
174
  }
253
175
  //#endregion
package/dist/index.d.cts CHANGED
@@ -1,10 +1,12 @@
1
- import { DatabaseManager, MemoryRepository, ProjectRepository } from "@membank/core";
1
+ import { Embedder, MemoryRepository, ProjectRepository } from "@membank/core";
2
2
  import { Hono } from "hono";
3
3
 
4
4
  //#region src/server/index.d.ts
5
- declare function createApiApp(db: DatabaseManager, repo: MemoryRepository, projectRepo: ProjectRepository): Hono;
5
+ declare function createApiApp(repo: MemoryRepository, projectRepo: ProjectRepository, embedder: Embedder): Hono;
6
6
  declare function startDashboard(opts?: {
7
7
  port?: number;
8
+ open?: boolean;
9
+ onReady?: (port: number) => void;
8
10
  }): Promise<void>;
9
11
  //#endregion
10
12
  export { createApiApp, startDashboard };
package/dist/index.d.mts CHANGED
@@ -1,10 +1,12 @@
1
- import { DatabaseManager, MemoryRepository, ProjectRepository } from "@membank/core";
1
+ import { Embedder, MemoryRepository, ProjectRepository } from "@membank/core";
2
2
  import { Hono } from "hono";
3
3
 
4
4
  //#region src/server/index.d.ts
5
- declare function createApiApp(db: DatabaseManager, repo: MemoryRepository, projectRepo: ProjectRepository): Hono;
5
+ declare function createApiApp(repo: MemoryRepository, projectRepo: ProjectRepository, embedder: Embedder): Hono;
6
6
  declare function startDashboard(opts?: {
7
7
  port?: number;
8
+ open?: boolean;
9
+ onReady?: (port: number) => void;
8
10
  }): Promise<void>;
9
11
  //#endregion
10
12
  export { createApiApp, startDashboard };
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { createServer } from "node:net";
3
3
  import { dirname, extname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { serve } from "@hono/node-server";
6
- import { DatabaseManager, EmbeddingService, MemoryRepository, ProjectRepository } from "@membank/core";
6
+ import { DatabaseManager, EmbeddingService, createMemoryRepository, createProjectRepository, updateMemory } from "@membank/core";
7
7
  import { Hono } from "hono";
8
8
  import open from "open";
9
9
  //#region src/server/index.ts
@@ -21,46 +21,6 @@ const MIME = {
21
21
  ".png": "image/png",
22
22
  ".json": "application/json"
23
23
  };
24
- function parseReviewEvent(row) {
25
- return {
26
- id: row.id,
27
- memoryId: row.memory_id,
28
- conflictingMemoryId: row.conflicting_memory_id,
29
- similarity: row.similarity,
30
- conflictContentSnapshot: row.conflict_content_snapshot,
31
- reason: row.reason,
32
- createdAt: row.created_at,
33
- resolvedAt: row.resolved_at
34
- };
35
- }
36
- function getReviewEventsForMemories(db, ids) {
37
- if (ids.length === 0) return /* @__PURE__ */ new Map();
38
- const placeholders = ids.map(() => "?").join(", ");
39
- const rows = db.db.prepare(`SELECT * FROM memory_review_events WHERE memory_id IN (${placeholders}) AND resolved_at IS NULL ORDER BY created_at DESC`).all(...ids);
40
- const map = /* @__PURE__ */ new Map();
41
- for (const row of rows) {
42
- const event = parseReviewEvent(row);
43
- const existing = map.get(event.memoryId) ?? [];
44
- existing.push(event);
45
- map.set(event.memoryId, existing);
46
- }
47
- return map;
48
- }
49
- function parseRow(row, projects = [], reviewEvents = []) {
50
- return {
51
- id: row.id,
52
- content: row.content,
53
- type: row.type,
54
- tags: JSON.parse(row.tags),
55
- projects,
56
- sourceHarness: row.source,
57
- accessCount: row.access_count,
58
- pinned: row.pinned !== 0,
59
- reviewEvents,
60
- createdAt: row.created_at,
61
- updatedAt: row.updated_at
62
- };
63
- }
64
24
  function tryPort(port) {
65
25
  return new Promise((resolve, reject) => {
66
26
  const server = createServer();
@@ -84,29 +44,16 @@ async function findFreePort(preferred) {
84
44
  });
85
45
  }
86
46
  }
87
- function createApiApp(db, repo, projectRepo) {
47
+ function createApiApp(repo, projectRepo, embedder) {
88
48
  const app = new Hono();
89
49
  app.get("/api/memories", (c) => {
90
50
  const { type, pinned, needsReview, search, projectId } = c.req.query();
91
- const conditions = [];
92
- const params = [];
93
- if (type) {
94
- conditions.push("m.type = ?");
95
- params.push(type);
96
- }
97
- if (pinned === "true") conditions.push("m.pinned = 1");
98
- if (needsReview === "true") conditions.push("EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)");
99
- if (projectId === "global") conditions.push("m.id NOT IN (SELECT memory_id FROM memory_projects)");
100
- else if (projectId) {
101
- conditions.push("m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)");
102
- params.push(projectId);
103
- }
104
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
105
- const rows = db.db.prepare(`SELECT m.* FROM memories m ${where} ORDER BY m.created_at DESC`).all(...params);
106
- const ids = rows.map((r) => r.id);
107
- const projectMap = projectRepo.getProjectsForMemories(ids);
108
- const eventMap = getReviewEventsForMemories(db, ids);
109
- let memories = rows.map((r) => parseRow(r, projectMap.get(r.id) ?? [], eventMap.get(r.id) ?? []));
51
+ let memories = repo.list({
52
+ type,
53
+ pinned: pinned === "true" ? true : void 0,
54
+ needsReview: needsReview === "true" ? true : void 0,
55
+ projectId
56
+ });
110
57
  if (search) {
111
58
  const q = search.toLowerCase();
112
59
  memories = memories.filter((m) => m.content.toLowerCase().includes(q));
@@ -114,50 +61,33 @@ function createApiApp(db, repo, projectRepo) {
114
61
  return c.json(memories);
115
62
  });
116
63
  app.get("/api/memories/:id", (c) => {
117
- const id = c.req.param("id");
118
- const row = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
119
- if (!row) return c.json({ error: "Not found" }, 404);
120
- const projectMap = projectRepo.getProjectsForMemories([id]);
121
- const eventMap = getReviewEventsForMemories(db, [id]);
122
- return c.json(parseRow(row, projectMap.get(id) ?? [], eventMap.get(id) ?? []));
64
+ const memory = repo.findById(c.req.param("id"));
65
+ if (!memory) return c.json({ error: "Not found" }, 404);
66
+ return c.json(memory);
123
67
  });
124
68
  app.patch("/api/memories/:id", async (c) => {
125
69
  const id = c.req.param("id");
126
- if (!db.db.prepare("SELECT id FROM memories WHERE id = ?").get(id)) return c.json({ error: "Not found" }, 404);
70
+ if (!repo.findById(id)) return c.json({ error: "Not found" }, 404);
127
71
  const body = await c.req.json();
128
- const sets = [];
129
- const sqlParams = [];
130
- if (body.pinned !== void 0) {
131
- sets.push("pinned = ?");
132
- sqlParams.push(body.pinned ? 1 : 0);
133
- }
134
- if (body.type !== void 0) {
135
- sets.push("type = ?");
136
- sqlParams.push(body.type);
137
- }
138
- if (sets.length > 0) {
139
- sets.push("updated_at = ?");
140
- sqlParams.push((/* @__PURE__ */ new Date()).toISOString(), id);
141
- db.db.prepare(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`).run(...sqlParams);
142
- }
72
+ if (body.pinned !== void 0) repo.setPin(id, body.pinned);
143
73
  if (body.needsReview === false) repo.resolveReviewEvents(id);
144
- if (body.content !== void 0 || body.tags !== void 0) await repo.update(id, {
74
+ if (body.content !== void 0 || body.tags !== void 0 || body.type !== void 0) await updateMemory(id, {
145
75
  content: body.content,
146
- tags: body.tags
76
+ tags: body.tags,
77
+ type: body.type
78
+ }, {
79
+ repo,
80
+ embedder
147
81
  });
148
- const updated = db.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
149
- const projectMap = projectRepo.getProjectsForMemories([id]);
150
- const eventMap = getReviewEventsForMemories(db, [id]);
151
- return c.json(parseRow(updated, projectMap.get(id) ?? [], eventMap.get(id) ?? []));
82
+ return c.json(repo.findById(id));
152
83
  });
153
- app.delete("/api/memories/:id", async (c) => {
154
- await repo.delete(c.req.param("id"));
84
+ app.delete("/api/memories/:id", (c) => {
85
+ repo.delete(c.req.param("id"));
155
86
  return c.json({ ok: true });
156
87
  });
157
88
  app.post("/api/memories/:id/projects", async (c) => {
158
- const memoryId = c.req.param("id");
159
89
  const body = await c.req.json();
160
- projectRepo.addAssociation(memoryId, body.projectId);
90
+ projectRepo.addAssociation(c.req.param("id"), body.projectId);
161
91
  return c.json({ ok: true });
162
92
  });
163
93
  app.delete("/api/memories/:id/projects/:projectId", (c) => {
@@ -168,30 +98,19 @@ function createApiApp(db, repo, projectRepo) {
168
98
  return c.json(projectRepo.list());
169
99
  });
170
100
  app.patch("/api/projects/:id", async (c) => {
171
- const id = c.req.param("id");
172
101
  const body = await c.req.json();
173
102
  try {
174
- return c.json(projectRepo.rename(id, body.name));
103
+ return c.json(projectRepo.rename(c.req.param("id"), body.name));
175
104
  } catch {
176
105
  return c.json({ error: "Not found" }, 404);
177
106
  }
178
107
  });
179
108
  app.get("/api/stats", (c) => {
180
- const byType = {
181
- correction: 0,
182
- preference: 0,
183
- decision: 0,
184
- learning: 0,
185
- fact: 0
186
- };
187
- const typeRows = db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
188
- for (const row of typeRows) if (row.type in byType) byType[row.type] = row.count;
189
- const totals = db.db.prepare("SELECT COUNT(*) as total FROM memories").get() ?? { total: 0 };
190
- const reviewRow = db.db.prepare("SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL").get() ?? { needsReview: 0 };
109
+ const { byType, total, needsReview } = repo.stats();
191
110
  return c.json({
192
111
  byType,
193
- total: totals.total,
194
- needsReview: reviewRow.needsReview
112
+ total,
113
+ needsReview
195
114
  });
196
115
  });
197
116
  return app;
@@ -200,8 +119,8 @@ async function startDashboard(opts) {
200
119
  const port = await findFreePort(opts?.port ?? PREFERRED_PORT);
201
120
  const db = DatabaseManager.open();
202
121
  const embedding = new EmbeddingService();
203
- const projects = new ProjectRepository(db);
204
- const app = createApiApp(db, new MemoryRepository(db, embedding, projects), projects);
122
+ const projects = createProjectRepository(db);
123
+ const app = createApiApp(createMemoryRepository(db, projects), projects, embedding);
205
124
  const clientDir = join(dirname(fileURLToPath(import.meta.url)), "client");
206
125
  app.get("*", (c) => {
207
126
  const filePath = join(clientDir, c.req.path === "/" ? "/index.html" : c.req.path);
@@ -217,13 +136,16 @@ async function startDashboard(opts) {
217
136
  db.close();
218
137
  process.exit(0);
219
138
  });
220
- serve({
221
- fetch: app.fetch,
222
- port
139
+ await new Promise((resolve) => {
140
+ serve({
141
+ fetch: app.fetch,
142
+ port
143
+ }, () => {
144
+ opts?.onReady?.(port);
145
+ resolve();
146
+ });
223
147
  });
224
- process.stdout.write(`\n Membank dashboard → http://localhost:${port}\n`);
225
- process.stdout.write(` Press Ctrl+C to stop\n\n`);
226
- await open(`http://localhost:${port}`);
148
+ if (opts?.open) await open(`http://localhost:${port}`);
227
149
  await new Promise(() => {});
228
150
  }
229
151
  //#endregion
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@membank/dashboard",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/draekien-industries/membank.git",
8
8
  "directory": "packages/dashboard"
9
9
  },
10
+ "bin": {
11
+ "membank-dashboard": "./dist/bin.mjs"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "import": {
@@ -20,7 +23,8 @@
20
23
  }
21
24
  },
22
25
  "files": [
23
- "dist"
26
+ "dist",
27
+ "!dist/**/*.map"
24
28
  ],
25
29
  "dependencies": {
26
30
  "@base-ui/react": "^1.0.0",
@@ -35,12 +39,15 @@
35
39
  "@tanstack/react-hotkeys": "^0.10.0",
36
40
  "@tanstack/react-router": "^1.168.25",
37
41
  "@tanstack/router-plugin": "^1.167.28",
42
+ "chalk": "^5.6.2",
38
43
  "class-variance-authority": "^0.7.1",
39
44
  "clsx": "^2.1.1",
40
45
  "cmdk": "^1.1.1",
46
+ "commander": "^14.0.3",
41
47
  "hono": "^4.12.18",
42
48
  "next-themes": "^0.4.6",
43
49
  "open": "^10.1.0",
50
+ "ora": "^9.4.0",
44
51
  "react": "^19.0.0",
45
52
  "react-dom": "^19.0.0",
46
53
  "recharts": "3.8.0",
@@ -49,7 +56,7 @@
49
56
  "tailwind-merge": "^3.0.0",
50
57
  "tw-animate-css": "^1.0.0",
51
58
  "zod": "^4.3.6",
52
- "@membank/core": "0.9.3"
59
+ "@membank/core": "0.10.0"
53
60
  },
54
61
  "devDependencies": {
55
62
  "@tailwindcss/vite": "^4.0.0",