@membank/cli 0.6.0 → 0.7.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 (2) hide show
  1. package/dist/index.mjs +69 -27
  2. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { cancel, confirm, intro, isCancel, multiselect, note, outro } from "@clack/prompts";
3
- import { DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MemoryRepository, ProjectRepository, QueryEngine, SessionContextBuilder, resolveProject } from "@membank/core";
3
+ import { DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MemoryRepository, ProjectRepository, QueryEngine, SessionContextBuilder, resolveProject, runScopeToProjectsMigration } from "@membank/core";
4
4
  import { startServer } from "@membank/mcp";
5
5
  import chalk from "chalk";
6
6
  import { Command } from "commander";
@@ -22,12 +22,13 @@ async function addCommand(content, options, formatter, db, embeddingService) {
22
22
  try {
23
23
  const repo = new MemoryRepository(resolvedDb, embeddingService ?? new EmbeddingService(), new ProjectRepository(resolvedDb));
24
24
  const tags = options.tags !== void 0 ? options.tags.split(",").map((t) => t.trim()) : [];
25
+ const projectScope = options.global ? void 0 : await resolveProject();
25
26
  const spinner = formatter.isJson ? null : ora("Saving memory…").start();
26
27
  const memory = await repo.save({
27
28
  content,
28
29
  type: options.type,
29
30
  tags,
30
- projectHash: options.scope
31
+ projectScope
31
32
  });
32
33
  spinner?.succeed("Memory saved");
33
34
  formatter.outputMemory(memory);
@@ -165,10 +166,7 @@ function outputAdditionalContext(text, harness, eventName) {
165
166
  process.stdout.write(`${text}\n`);
166
167
  }
167
168
  async function handleSessionStart(opts) {
168
- const projectScope = (opts.scope !== void 0 ? {
169
- hash: opts.scope,
170
- name: opts.scope
171
- } : await resolveProject()).hash;
169
+ const projectScope = (await resolveProject()).hash;
172
170
  const db = DatabaseManager.open();
173
171
  let text;
174
172
  try {
@@ -199,18 +197,53 @@ async function listCommand(options, formatter) {
199
197
  }
200
198
  }
201
199
  //#endregion
200
+ //#region src/commands/migrate.ts
201
+ async function migrateCommand(mode, name, formatter) {
202
+ if (mode === "list") {
203
+ if (formatter.isJson) process.stdout.write(`${JSON.stringify(MIGRATIONS.map((m) => ({
204
+ name: m.name,
205
+ description: m.description
206
+ })))}\n`);
207
+ else for (const m of MIGRATIONS) process.stdout.write(`${m.name}\n ${m.description}\n`);
208
+ return;
209
+ }
210
+ if (name === void 0) {
211
+ formatter.error("Migration name is required for run mode.");
212
+ process.exit(1);
213
+ }
214
+ if (!MIGRATIONS.some((m) => m.name === name)) {
215
+ formatter.error(`Unknown migration: "${name}". Available: ${MIGRATIONS.map((m) => m.name).join(", ")}`);
216
+ process.exit(1);
217
+ }
218
+ const db = DatabaseManager.open();
219
+ try {
220
+ if (name === "scope-to-projects") {
221
+ const result = await runScopeToProjectsMigration(new ProjectRepository(db));
222
+ if (result === null) {
223
+ formatter.error("No project found for current directory.");
224
+ return;
225
+ }
226
+ if (formatter.isJson) process.stdout.write(`${JSON.stringify(result)}\n`);
227
+ else {
228
+ const { oldName, newName, memoryCount } = result;
229
+ process.stdout.write(`Found project: ${oldName} (${memoryCount} ${memoryCount === 1 ? "memory" : "memories"})\n`);
230
+ process.stdout.write(`Resolved name: ${newName}\n`);
231
+ process.stdout.write(`Renamed → ${newName}\n`);
232
+ process.stdout.write("Done.\n");
233
+ }
234
+ }
235
+ } finally {
236
+ db.close();
237
+ }
238
+ }
239
+ //#endregion
202
240
  //#region src/commands/pin.ts
203
- function pinCommand(id, formatter, db) {
241
+ function pinCommand(id, db) {
204
242
  const ownDb = db === void 0;
205
243
  const resolvedDb = db ?? DatabaseManager.open();
206
244
  try {
207
- if (resolvedDb.db.prepare("SELECT id FROM memories WHERE id = ?").get(id) === void 0) {
208
- formatter.error(`Memory not found: ${id}`);
209
- process.exit(2);
210
- } else {
211
- resolvedDb.db.prepare("UPDATE memories SET pinned = 1 WHERE id = ?").run(id);
212
- process.stdout.write(`${chalk.green("✓")} Pinned: ${chalk.dim(id)}\n`);
213
- }
245
+ new MemoryRepository(resolvedDb, new EmbeddingService(), new ProjectRepository(resolvedDb)).setPin(id, true);
246
+ process.stdout.write(`${chalk.green("✓")} Pinned: ${chalk.dim(id)}\n`);
214
247
  } finally {
215
248
  if (ownDb) resolvedDb.close();
216
249
  }
@@ -248,17 +281,12 @@ async function statsCommand(formatter) {
248
281
  }
249
282
  //#endregion
250
283
  //#region src/commands/unpin.ts
251
- function unpinCommand(id, formatter, db) {
284
+ function unpinCommand(id, db) {
252
285
  const ownDb = db === void 0;
253
286
  const resolvedDb = db ?? DatabaseManager.open();
254
287
  try {
255
- if (resolvedDb.db.prepare("SELECT id FROM memories WHERE id = ?").get(id) === void 0) {
256
- formatter.error(`Memory not found: ${id}`);
257
- process.exit(2);
258
- } else {
259
- resolvedDb.db.prepare("UPDATE memories SET pinned = 0 WHERE id = ?").run(id);
260
- process.stdout.write(`${chalk.green("✓")} Unpinned: ${chalk.dim(id)}\n`);
261
- }
288
+ new MemoryRepository(resolvedDb, new EmbeddingService(), new ProjectRepository(resolvedDb)).setPin(id, false);
289
+ process.stdout.write(`${chalk.green("✓")} Unpinned: ${chalk.dim(id)}\n`);
262
290
  } finally {
263
291
  if (ownDb) resolvedDb.close();
264
292
  }
@@ -299,7 +327,7 @@ var Formatter = class Formatter {
299
327
  process.stdout.write(` ${colorType(memory.type)} ${chalk.dim(memory.id)}\n`);
300
328
  process.stdout.write(` ${memory.content}\n`);
301
329
  const scope = memory.projects.length > 0 ? memory.projects.map((p) => p.name).join(", ") : "global";
302
- process.stdout.write(` ${chalk.dim("Tags:")} ${tags} ${chalk.dim("Scope:")} ${scope}\n`);
330
+ process.stdout.write(` ${chalk.dim("Tags:")} ${tags} ${chalk.dim("Project:")} ${scope}\n`);
303
331
  process.stdout.write(`\n ${chalk.dim(`Hint: pin with membank pin ${memory.id}`)}\n\n`);
304
332
  }
305
333
  outputMemories(memories) {
@@ -1257,7 +1285,7 @@ program.command("delete <id>").description("delete a memory by ID").action(async
1257
1285
  db.close();
1258
1286
  }
1259
1287
  });
1260
- program.command("add <content>").description("save a new memory").requiredOption("--type <type>", "memory type (correction|preference|decision|learning|fact)").option("--tags <tags>", "comma-separated tags").option("--scope <scope>", "scope (global or project identifier)").action(async (content, cmdOptions) => {
1288
+ program.command("add <content>").description("save a new memory").requiredOption("--type <type>", "memory type (correction|preference|decision|learning|fact)").option("--tags <tags>", "comma-separated tags").option("--global", "save as a global memory, not tied to any project").action(async (content, cmdOptions) => {
1261
1289
  const globalOpts = program.opts();
1262
1290
  const formatter = Formatter.create(globalOpts.json === true);
1263
1291
  try {
@@ -1271,7 +1299,7 @@ program.command("pin <id>").description("pin a memory by ID").action((id) => {
1271
1299
  const globalOpts = program.opts();
1272
1300
  const formatter = Formatter.create(globalOpts.json === true);
1273
1301
  try {
1274
- pinCommand(id, formatter);
1302
+ pinCommand(id);
1275
1303
  } catch (err) {
1276
1304
  formatter.error(err instanceof Error ? err.message : String(err));
1277
1305
  process.exit(2);
@@ -1281,7 +1309,7 @@ program.command("unpin <id>").description("unpin a memory by ID").action((id) =>
1281
1309
  const globalOpts = program.opts();
1282
1310
  const formatter = Formatter.create(globalOpts.json === true);
1283
1311
  try {
1284
- unpinCommand(id, formatter);
1312
+ unpinCommand(id);
1285
1313
  } catch (err) {
1286
1314
  formatter.error(err instanceof Error ? err.message : String(err));
1287
1315
  process.exit(2);
@@ -1314,7 +1342,7 @@ program.command("import <file>").description("import memories from a JSON export
1314
1342
  db.close();
1315
1343
  }
1316
1344
  });
1317
- program.command("inject").description("output session context for harness injection (used by setup hooks)").option("--harness <name>", "format output for a specific harness (claude-code|copilot-cli|codex|opencode)").option("--scope <scope>", "project scope override (default: auto-detect from git remote)").option("--event <event>", "hook event type (only session-start is supported; other values no-op for legacy hook compatibility)", "session-start").action(async (cmdOptions) => {
1345
+ program.command("inject").description("output session context for harness injection (used by setup hooks)").option("--harness <name>", "format output for a specific harness (claude-code|copilot-cli|codex|opencode)").option("--event <event>", "hook event type (only session-start is supported; other values no-op for legacy hook compatibility)", "session-start").action(async (cmdOptions) => {
1318
1346
  try {
1319
1347
  await injectCommand(cmdOptions);
1320
1348
  } catch (err) {
@@ -1390,6 +1418,20 @@ program.command("setup").description("detect installed harnesses and write MCP c
1390
1418
  process.exit(2);
1391
1419
  }
1392
1420
  });
1421
+ program.command("migrate <mode> [name]").description("list or run a named data migration (modes: list, run)").action(async (mode, name) => {
1422
+ if (mode !== "list" && mode !== "run") {
1423
+ process.stderr.write(`Error: mode must be "list" or "run"\n`);
1424
+ process.exit(1);
1425
+ }
1426
+ const globalOpts = program.opts();
1427
+ const formatter = Formatter.create(globalOpts.json === true);
1428
+ try {
1429
+ await migrateCommand(mode, name, formatter);
1430
+ } catch (err) {
1431
+ formatter.error(err instanceof Error ? err.message : String(err));
1432
+ process.exit(2);
1433
+ }
1434
+ });
1393
1435
  program.command("dashboard").description("open the memory management dashboard in the browser").option("--port <port>", "port to listen on (default: 3847, fallback to random)").action(async (cmdOptions) => {
1394
1436
  try {
1395
1437
  await dashboardCommand(cmdOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@membank/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,9 +20,9 @@
20
20
  "cli-table3": "^0.6.5",
21
21
  "commander": "^14.0.3",
22
22
  "ora": "^9.4.0",
23
- "@membank/core": "0.6.0",
24
- "@membank/dashboard": "0.3.0",
25
- "@membank/mcp": "0.7.0"
23
+ "@membank/core": "0.6.1",
24
+ "@membank/mcp": "0.8.0",
25
+ "@membank/dashboard": "0.4.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^25.6.0",