@membank/cli 0.13.1 → 0.14.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.
package/README.md CHANGED
@@ -157,14 +157,30 @@ membank config show
157
157
 
158
158
  ### `membank synthesize`
159
159
 
160
- View memory synthesis state.
160
+ View and manage memory synthesis.
161
161
 
162
162
  ```bash
163
+ membank synthesize run # trigger a synthesis run for a scope
163
164
  membank synthesize show # current synthesis for global scope
164
165
  membank synthesize show --scope <s> # synthesis for a specific project scope
165
166
  membank synthesize status # all scopes and their synthesis state
166
167
  ```
167
168
 
169
+ Options for `run` and `show`: `--scope <scope>`
170
+
171
+ ### `membank activity`
172
+
173
+ List activity events for the current project.
174
+
175
+ ```bash
176
+ membank activity
177
+ membank activity --type memory.created
178
+ membank activity --since 2025-01-01
179
+ membank activity --global
180
+ ```
181
+
182
+ Options: `--type <event_type>` (memory.created|updated|deleted|flagged|queried), `--since <date>`, `--memory-id <id>`, `--limit <n>` (default 50), `--global`, `--scope <hash>`
183
+
168
184
  ### `membank inject`
169
185
 
170
186
  Output session context formatted for a harness. Called automatically by session hooks — you don't normally run this directly.
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, MIGRATIONS, MODEL_NAME, MemoryTypeSchema, MemoryTypeSchema as MemoryTypeSchema$1, ModelDownloader, PIN_BUDGET_THRESHOLD, QueryEngine, SessionContextBuilder, createMemoryRepository, createProjectRepository, createSynthesisRepository, resolveProject, runScopeToProjectsMigration, saveMemory } from "@membank/core";
3
+ import { ACTIVITY_EVENT_TYPE_VALUES, ActivityEventTypeSchema, DatabaseManager, EmbeddingService, GLOBAL_SCOPE_HASH, MIGRATIONS, MODEL_NAME, MemoryTypeSchema, MemoryTypeSchema as MemoryTypeSchema$1, ModelDownloader, PIN_BUDGET_THRESHOLD, QueryEngine, SessionContextBuilder, createActivityLogger, createActivityRepository, createMemoryRepository, createProjectRepository, createSynthesisRepository, deleteMemory, listEvents, resolveProject, runScopeToProjectsMigration, saveMemory } from "@membank/core";
4
4
  import { runExtraction, runSynthesis, startServer } from "@membank/mcp";
5
5
  import chalk from "chalk";
6
6
  import { Command } from "commander";
@@ -13,6 +13,63 @@ import Table from "cli-table3";
13
13
  import { execFile } from "node:child_process";
14
14
  import { promisify } from "node:util";
15
15
  import { createInterface } from "node:readline";
16
+ //#region src/commands/activity.ts
17
+ const EVENT_COLORS = {
18
+ "memory.created": chalk.green,
19
+ "memory.updated": chalk.cyan,
20
+ "memory.deleted": chalk.red,
21
+ "memory.flagged": chalk.yellow,
22
+ "memory.queried": chalk.dim
23
+ };
24
+ function formatEvent(event) {
25
+ return ` ${(EVENT_COLORS[event.eventType] ?? chalk.white)(event.eventType.padEnd(16))} ${new Date(event.createdAt).toLocaleTimeString()}${event.memoryId !== null ? chalk.dim(` [${event.memoryId.slice(0, 8)}]`) : ""}`;
26
+ }
27
+ async function activityCommand(options, formatter) {
28
+ const db = DatabaseManager.open();
29
+ try {
30
+ const activityRepo = createActivityRepository(db);
31
+ let scope;
32
+ if (options.scope !== void 0) scope = options.scope;
33
+ else if (options.global === true) scope = GLOBAL_SCOPE_HASH;
34
+ else scope = (await resolveProject()).hash;
35
+ let validatedType;
36
+ if (options.type !== void 0) {
37
+ const parsed = ActivityEventTypeSchema.safeParse(options.type);
38
+ if (!parsed.success) {
39
+ formatter.error(`Invalid event type: "${options.type}". Valid values: ${ACTIVITY_EVENT_TYPE_VALUES.join(", ")}`);
40
+ process.exit(1);
41
+ }
42
+ validatedType = parsed.data;
43
+ }
44
+ const events = listEvents({
45
+ scope,
46
+ type: validatedType,
47
+ since: options.since,
48
+ limit: options.limit !== void 0 ? parseInt(options.limit, 10) : 50
49
+ }, activityRepo);
50
+ if (formatter.isJson) {
51
+ process.stdout.write(`${JSON.stringify(events)}\n`);
52
+ return;
53
+ }
54
+ if (events.length === 0) {
55
+ process.stdout.write(chalk.dim(" No activity found.\n"));
56
+ return;
57
+ }
58
+ let lastDay = "";
59
+ for (const event of events) {
60
+ const day = event.createdAt.slice(0, 10);
61
+ if (day !== lastDay) {
62
+ lastDay = day;
63
+ process.stdout.write(`\n${chalk.bold(day)}\n`);
64
+ }
65
+ process.stdout.write(`${formatEvent(event)}\n`);
66
+ }
67
+ process.stdout.write("\n");
68
+ } finally {
69
+ db.close();
70
+ }
71
+ }
72
+ //#endregion
16
73
  //#region src/schemas.ts
17
74
  const SETUP_HARNESS_VALUES = [
18
75
  "claude-code",
@@ -59,6 +116,7 @@ async function addCommand(content, options, formatter, db, embeddingService) {
59
116
  try {
60
117
  const embedder = embeddingService ?? new EmbeddingService();
61
118
  const repo = createMemoryRepository(resolvedDb, createProjectRepository(resolvedDb));
119
+ const activityLogger = createActivityLogger(resolvedDb);
62
120
  const tags = options.tags !== void 0 ? options.tags.split(",").map((t) => t.trim()) : [];
63
121
  const projectScope = options.global ? void 0 : await resolveProject();
64
122
  const spinner = formatter.isJson ? null : ora("Saving memory…").start();
@@ -69,7 +127,8 @@ async function addCommand(content, options, formatter, db, embeddingService) {
69
127
  projectScope
70
128
  }, {
71
129
  repo,
72
- embedder
130
+ embedder,
131
+ activityLogger
73
132
  });
74
133
  spinner?.succeed("Memory saved");
75
134
  formatter.outputMemory(memory);
@@ -160,7 +219,7 @@ async function deleteCommand(id, db, formatter, prompt) {
160
219
  process.exit(1);
161
220
  }
162
221
  if (!await prompt.confirm(`Delete memory ${id}?`)) return;
163
- repo.delete(id);
222
+ await deleteMemory(id, repo, createActivityLogger(db));
164
223
  process.stdout.write(`${chalk.green("✓")} Deleted memory: ${chalk.dim(id)}\n`);
165
224
  }
166
225
  //#endregion
@@ -370,7 +429,7 @@ async function buildText() {
370
429
  try {
371
430
  const builder = new SessionContextBuilder(createMemoryRepository(db, createProjectRepository(db)));
372
431
  const synthRepo = createSynthesisRepository(db);
373
- const globalRow = synthRepo.getSynthesis("global");
432
+ const globalRow = synthRepo.getSynthesis(GLOBAL_SCOPE_HASH);
374
433
  const projectRow = synthRepo.getSynthesis(resolved.hash);
375
434
  const synthesis = pickBestSynthesis(globalRow?.inFlightSince === null ? globalRow.content : void 0, projectRow?.inFlightSince === null ? projectRow.content : void 0);
376
435
  return formatContext(builder.getSessionContext(resolved.hash, synthesis));
@@ -532,7 +591,8 @@ function synthesizeShowCommand(opts, formatter) {
532
591
  try {
533
592
  const scope = opts.scope ?? "global";
534
593
  let resolvedScope = scope;
535
- if (scope !== "global" && !/^[0-9a-f]{16}$/.test(scope)) {
594
+ if (scope === "global") resolvedScope = GLOBAL_SCOPE_HASH;
595
+ else if (!/^[0-9a-f]{16}$/.test(scope)) {
536
596
  const project = createProjectRepository(db).getByName(scope);
537
597
  if (project !== void 0) resolvedScope = project.scopeHash;
538
598
  }
@@ -569,7 +629,7 @@ function synthesizeStatusCommand(formatter) {
569
629
  }
570
630
  process.stdout.write("\n");
571
631
  for (const s of syntheses) {
572
- const displayScope = (s.scope !== "global" ? projectRepo.getByHash(s.scope) : void 0)?.name ?? s.scope;
632
+ const displayScope = (s.scope !== GLOBAL_SCOPE_HASH ? projectRepo.getByHash(s.scope) : void 0)?.name ?? (s.scope === GLOBAL_SCOPE_HASH ? "global" : s.scope);
573
633
  const inFlight = s.inFlightSince !== null ? " [in-flight]" : "";
574
634
  const synthesized = new Date(s.synthesizedAt).toLocaleString();
575
635
  const expires = new Date(s.expiresAt).toLocaleString();
@@ -1876,6 +1936,19 @@ synthesizeCmd.command("status").description("show all scopes with synthesis stat
1876
1936
  process.exit(2);
1877
1937
  }
1878
1938
  });
1939
+ program.command("activity").description("list activity events for the current project (or --global for global memories)").option("--type <event_type>", "filter by event type (memory.created|updated|deleted|flagged|queried)").option("--since <date>", "return events after this ISO date/time").option("--memory-id <id>", "filter by memory id").option("--limit <n>", "maximum number of results (default 50)").option("--global", "show activity for global (sentinel) project").option("--scope <hash>", "show activity for a specific scope hash (advanced)").action(async (cmdOptions) => {
1940
+ const globalOpts = program.opts();
1941
+ const formatter = Formatter.create(globalOpts.json === true);
1942
+ try {
1943
+ await activityCommand({
1944
+ ...cmdOptions,
1945
+ json: globalOpts.json
1946
+ }, formatter);
1947
+ } catch (err) {
1948
+ formatter.error(err instanceof Error ? err.message : String(err));
1949
+ process.exit(2);
1950
+ }
1951
+ });
1879
1952
  program.on("command:*", () => {
1880
1953
  program.outputHelp();
1881
1954
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@membank/cli",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,8 +21,8 @@
21
21
  "commander": "^14.0.3",
22
22
  "ora": "^9.4.0",
23
23
  "zod": "^4.4.3",
24
- "@membank/mcp": "0.14.1",
25
- "@membank/core": "0.11.1"
24
+ "@membank/core": "0.12.1",
25
+ "@membank/mcp": "0.14.3"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^25.6.0",