@hasna/mementos 0.1.1 → 0.1.2

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/cli/index.js CHANGED
@@ -4,6 +4,7 @@ var __create = Object.create;
4
4
  var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
9
  var __toESM = (mod, isNodeMode, target) => {
9
10
  target = mod != null ? __create(__getProtoOf(mod)) : {};
@@ -16,7 +17,31 @@ var __toESM = (mod, isNodeMode, target) => {
16
17
  });
17
18
  return to;
18
19
  };
20
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
21
+ var __toCommonJS = (from) => {
22
+ var entry = __moduleCache.get(from), desc;
23
+ if (entry)
24
+ return entry;
25
+ entry = __defProp({}, "__esModule", { value: true });
26
+ if (from && typeof from === "object" || typeof from === "function")
27
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
28
+ get: () => from[key],
29
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
30
+ }));
31
+ __moduleCache.set(from, entry);
32
+ return entry;
33
+ };
19
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
35
+ var __export = (target, all) => {
36
+ for (var name in all)
37
+ __defProp(target, name, {
38
+ get: all[name],
39
+ enumerable: true,
40
+ configurable: true,
41
+ set: (newValue) => all[name] = () => newValue
42
+ });
43
+ };
44
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
20
45
  var __require = import.meta.require;
21
46
 
22
47
  // node_modules/commander/lib/error.js
@@ -2053,28 +2078,6 @@ var require_commander = __commonJS((exports) => {
2053
2078
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2054
2079
  });
2055
2080
 
2056
- // node_modules/commander/esm.mjs
2057
- var import__ = __toESM(require_commander(), 1);
2058
- var {
2059
- program,
2060
- createCommand,
2061
- createArgument,
2062
- createOption,
2063
- CommanderError,
2064
- InvalidArgumentError,
2065
- InvalidOptionArgumentError,
2066
- Command,
2067
- Argument,
2068
- Option,
2069
- Help
2070
- } = import__.default;
2071
-
2072
- // src/cli/index.tsx
2073
- import chalk from "chalk";
2074
- import { readFileSync as readFileSync2 } from "fs";
2075
- import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
2076
- import { fileURLToPath } from "url";
2077
-
2078
2081
  // src/db/database.ts
2079
2082
  import { Database } from "bun:sqlite";
2080
2083
  import { existsSync, mkdirSync } from "fs";
@@ -2132,8 +2135,59 @@ function ensureDir(filePath) {
2132
2135
  mkdirSync(dir, { recursive: true });
2133
2136
  }
2134
2137
  }
2135
- var MIGRATIONS = [
2136
- `
2138
+ function getDatabase(dbPath) {
2139
+ if (_db)
2140
+ return _db;
2141
+ const path = dbPath || getDbPath();
2142
+ ensureDir(path);
2143
+ _db = new Database(path, { create: true });
2144
+ _db.run("PRAGMA journal_mode = WAL");
2145
+ _db.run("PRAGMA busy_timeout = 5000");
2146
+ _db.run("PRAGMA foreign_keys = ON");
2147
+ runMigrations(_db);
2148
+ return _db;
2149
+ }
2150
+ function runMigrations(db) {
2151
+ try {
2152
+ const result = db.query("SELECT MAX(id) as max_id FROM _migrations").get();
2153
+ const currentLevel = result?.max_id ?? 0;
2154
+ for (let i = currentLevel;i < MIGRATIONS.length; i++) {
2155
+ try {
2156
+ db.exec(MIGRATIONS[i]);
2157
+ } catch {}
2158
+ }
2159
+ } catch {
2160
+ for (const migration of MIGRATIONS) {
2161
+ try {
2162
+ db.exec(migration);
2163
+ } catch {}
2164
+ }
2165
+ }
2166
+ }
2167
+ function now() {
2168
+ return new Date().toISOString();
2169
+ }
2170
+ function uuid() {
2171
+ return crypto.randomUUID();
2172
+ }
2173
+ function shortUuid() {
2174
+ return crypto.randomUUID().slice(0, 8);
2175
+ }
2176
+ function resolvePartialId(db, table, partialId) {
2177
+ if (partialId.length >= 36) {
2178
+ const row = db.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
2179
+ return row?.id ?? null;
2180
+ }
2181
+ const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ?`).all(`${partialId}%`);
2182
+ if (rows.length === 1) {
2183
+ return rows[0].id;
2184
+ }
2185
+ return null;
2186
+ }
2187
+ var MIGRATIONS, _db = null;
2188
+ var init_database = __esm(() => {
2189
+ MIGRATIONS = [
2190
+ `
2137
2191
  CREATE TABLE IF NOT EXISTS projects (
2138
2192
  id TEXT PRIMARY KEY,
2139
2193
  name TEXT NOT NULL,
@@ -2220,75 +2274,29 @@ var MIGRATIONS = [
2220
2274
 
2221
2275
  INSERT OR IGNORE INTO _migrations (id) VALUES (1);
2222
2276
  `
2223
- ];
2224
- var _db = null;
2225
- function getDatabase(dbPath) {
2226
- if (_db)
2227
- return _db;
2228
- const path = dbPath || getDbPath();
2229
- ensureDir(path);
2230
- _db = new Database(path, { create: true });
2231
- _db.run("PRAGMA journal_mode = WAL");
2232
- _db.run("PRAGMA busy_timeout = 5000");
2233
- _db.run("PRAGMA foreign_keys = ON");
2234
- runMigrations(_db);
2235
- return _db;
2236
- }
2237
- function runMigrations(db) {
2238
- try {
2239
- const result = db.query("SELECT MAX(id) as max_id FROM _migrations").get();
2240
- const currentLevel = result?.max_id ?? 0;
2241
- for (let i = currentLevel;i < MIGRATIONS.length; i++) {
2242
- try {
2243
- db.exec(MIGRATIONS[i]);
2244
- } catch {}
2245
- }
2246
- } catch {
2247
- for (const migration of MIGRATIONS) {
2248
- try {
2249
- db.exec(migration);
2250
- } catch {}
2251
- }
2252
- }
2253
- }
2254
- function now() {
2255
- return new Date().toISOString();
2256
- }
2257
- function uuid() {
2258
- return crypto.randomUUID();
2259
- }
2260
- function shortUuid() {
2261
- return crypto.randomUUID().slice(0, 8);
2262
- }
2263
- function resolvePartialId(db, table, partialId) {
2264
- if (partialId.length >= 36) {
2265
- const row = db.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
2266
- return row?.id ?? null;
2267
- }
2268
- const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ?`).all(`${partialId}%`);
2269
- if (rows.length === 1) {
2270
- return rows[0].id;
2271
- }
2272
- return null;
2273
- }
2277
+ ];
2278
+ });
2274
2279
 
2275
2280
  // src/types/index.ts
2276
- class MemoryNotFoundError extends Error {
2277
- constructor(id) {
2278
- super(`Memory not found: ${id}`);
2279
- this.name = "MemoryNotFoundError";
2280
- }
2281
- }
2282
- class VersionConflictError extends Error {
2283
- expected;
2284
- actual;
2285
- constructor(id, expected, actual) {
2286
- super(`Version conflict for memory ${id}: expected ${expected}, got ${actual}`);
2287
- this.name = "VersionConflictError";
2288
- this.expected = expected;
2289
- this.actual = actual;
2290
- }
2291
- }
2281
+ var MemoryNotFoundError, VersionConflictError;
2282
+ var init_types = __esm(() => {
2283
+ MemoryNotFoundError = class MemoryNotFoundError extends Error {
2284
+ constructor(id) {
2285
+ super(`Memory not found: ${id}`);
2286
+ this.name = "MemoryNotFoundError";
2287
+ }
2288
+ };
2289
+ VersionConflictError = class VersionConflictError extends Error {
2290
+ expected;
2291
+ actual;
2292
+ constructor(id, expected, actual) {
2293
+ super(`Version conflict for memory ${id}: expected ${expected}, got ${actual}`);
2294
+ this.name = "VersionConflictError";
2295
+ this.expected = expected;
2296
+ this.actual = actual;
2297
+ }
2298
+ };
2299
+ });
2292
2300
 
2293
2301
  // src/db/memories.ts
2294
2302
  function parseMemoryRow(row) {
@@ -2591,8 +2599,150 @@ function cleanExpiredMemories(db) {
2591
2599
  const result = d.run("DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < ?", [timestamp]);
2592
2600
  return result.changes;
2593
2601
  }
2602
+ var init_memories = __esm(() => {
2603
+ init_types();
2604
+ init_database();
2605
+ });
2606
+
2607
+ // src/lib/poll.ts
2608
+ var exports_poll = {};
2609
+ __export(exports_poll, {
2610
+ startPolling: () => startPolling
2611
+ });
2612
+ function startPolling(opts) {
2613
+ const interval = opts.interval_ms ?? 500;
2614
+ const db = opts.db ?? getDatabase();
2615
+ let stopped = false;
2616
+ let inFlight = false;
2617
+ let lastSeen = null;
2618
+ const seedLastSeen = () => {
2619
+ try {
2620
+ const latest = listMemories({
2621
+ scope: opts.scope,
2622
+ category: opts.category,
2623
+ agent_id: opts.agent_id,
2624
+ project_id: opts.project_id,
2625
+ limit: 1
2626
+ }, db);
2627
+ if (latest.length > 0 && latest[0]) {
2628
+ lastSeen = latest[0].updated_at;
2629
+ }
2630
+ } catch (err) {
2631
+ opts.on_error?.(err instanceof Error ? err : new Error(String(err)));
2632
+ }
2633
+ };
2634
+ const poll = () => {
2635
+ if (stopped || inFlight)
2636
+ return;
2637
+ inFlight = true;
2638
+ try {
2639
+ const conditions = ["status = 'active'"];
2640
+ const params = [];
2641
+ if (lastSeen) {
2642
+ conditions.push("(updated_at > ? OR created_at > ?)");
2643
+ params.push(lastSeen, lastSeen);
2644
+ }
2645
+ if (opts.scope) {
2646
+ conditions.push("scope = ?");
2647
+ params.push(opts.scope);
2648
+ }
2649
+ if (opts.category) {
2650
+ conditions.push("category = ?");
2651
+ params.push(opts.category);
2652
+ }
2653
+ if (opts.agent_id) {
2654
+ conditions.push("agent_id = ?");
2655
+ params.push(opts.agent_id);
2656
+ }
2657
+ if (opts.project_id) {
2658
+ conditions.push("project_id = ?");
2659
+ params.push(opts.project_id);
2660
+ }
2661
+ const sql = `SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY updated_at ASC`;
2662
+ const rows = db.query(sql).all(...params);
2663
+ if (rows.length > 0) {
2664
+ const memories = rows.map(parseMemoryRow3);
2665
+ const lastRow = memories[memories.length - 1];
2666
+ if (lastRow) {
2667
+ lastSeen = lastRow.updated_at;
2668
+ }
2669
+ try {
2670
+ opts.on_memories(memories);
2671
+ } catch (err) {
2672
+ opts.on_error?.(err instanceof Error ? err : new Error(String(err)));
2673
+ }
2674
+ }
2675
+ } catch (err) {
2676
+ opts.on_error?.(err instanceof Error ? err : new Error(String(err)));
2677
+ } finally {
2678
+ inFlight = false;
2679
+ }
2680
+ };
2681
+ seedLastSeen();
2682
+ const timer = setInterval(poll, interval);
2683
+ return {
2684
+ stop: () => {
2685
+ stopped = true;
2686
+ clearInterval(timer);
2687
+ }
2688
+ };
2689
+ }
2690
+ function parseMemoryRow3(row) {
2691
+ return {
2692
+ id: row["id"],
2693
+ key: row["key"],
2694
+ value: row["value"],
2695
+ category: row["category"],
2696
+ scope: row["scope"],
2697
+ summary: row["summary"] || null,
2698
+ tags: JSON.parse(row["tags"] || "[]"),
2699
+ importance: row["importance"],
2700
+ source: row["source"],
2701
+ status: row["status"],
2702
+ pinned: !!row["pinned"],
2703
+ agent_id: row["agent_id"] || null,
2704
+ project_id: row["project_id"] || null,
2705
+ session_id: row["session_id"] || null,
2706
+ metadata: JSON.parse(row["metadata"] || "{}"),
2707
+ access_count: row["access_count"],
2708
+ version: row["version"],
2709
+ expires_at: row["expires_at"] || null,
2710
+ created_at: row["created_at"],
2711
+ updated_at: row["updated_at"],
2712
+ accessed_at: row["accessed_at"] || null
2713
+ };
2714
+ }
2715
+ var init_poll = __esm(() => {
2716
+ init_memories();
2717
+ init_database();
2718
+ });
2719
+
2720
+ // node_modules/commander/esm.mjs
2721
+ var import__ = __toESM(require_commander(), 1);
2722
+ var {
2723
+ program,
2724
+ createCommand,
2725
+ createArgument,
2726
+ createOption,
2727
+ CommanderError,
2728
+ InvalidArgumentError,
2729
+ InvalidOptionArgumentError,
2730
+ Command,
2731
+ Argument,
2732
+ Option,
2733
+ Help
2734
+ } = import__.default;
2735
+
2736
+ // src/cli/index.tsx
2737
+ init_database();
2738
+ init_memories();
2739
+ import chalk from "chalk";
2740
+ import { readFileSync as readFileSync2 } from "fs";
2741
+ import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
2742
+ import { fileURLToPath } from "url";
2594
2743
 
2595
2744
  // src/db/agents.ts
2745
+ init_database();
2596
2746
  function parseAgentRow(row) {
2597
2747
  return {
2598
2748
  id: row["id"],
@@ -2650,8 +2800,34 @@ function listAgents(db) {
2650
2800
  const rows = d.query("SELECT * FROM agents ORDER BY last_seen_at DESC").all();
2651
2801
  return rows.map(parseAgentRow);
2652
2802
  }
2803
+ function updateAgent(id, updates, db) {
2804
+ const d = db || getDatabase();
2805
+ const agent = getAgent(id, d);
2806
+ if (!agent)
2807
+ return null;
2808
+ const timestamp = now();
2809
+ if (updates.name && updates.name !== agent.name) {
2810
+ const existing = d.query("SELECT id FROM agents WHERE name = ? AND id != ?").get(updates.name, agent.id);
2811
+ if (existing) {
2812
+ throw new Error(`Agent name already taken: ${updates.name}`);
2813
+ }
2814
+ d.run("UPDATE agents SET name = ? WHERE id = ?", [updates.name, agent.id]);
2815
+ }
2816
+ if (updates.description !== undefined) {
2817
+ d.run("UPDATE agents SET description = ? WHERE id = ?", [updates.description, agent.id]);
2818
+ }
2819
+ if (updates.role !== undefined) {
2820
+ d.run("UPDATE agents SET role = ? WHERE id = ?", [updates.role, agent.id]);
2821
+ }
2822
+ if (updates.metadata !== undefined) {
2823
+ d.run("UPDATE agents SET metadata = ? WHERE id = ?", [JSON.stringify(updates.metadata), agent.id]);
2824
+ }
2825
+ d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [timestamp, agent.id]);
2826
+ return getAgent(agent.id, d);
2827
+ }
2653
2828
 
2654
2829
  // src/db/projects.ts
2830
+ init_database();
2655
2831
  function parseProjectRow(row) {
2656
2832
  return {
2657
2833
  id: row["id"],
@@ -2696,6 +2872,7 @@ function listProjects(db) {
2696
2872
  }
2697
2873
 
2698
2874
  // src/lib/search.ts
2875
+ init_database();
2699
2876
  function parseMemoryRow2(row) {
2700
2877
  return {
2701
2878
  id: row["id"],
@@ -2929,6 +3106,8 @@ function loadConfig() {
2929
3106
  }
2930
3107
 
2931
3108
  // src/lib/retention.ts
3109
+ init_database();
3110
+ init_memories();
2932
3111
  function enforceQuotas(config, db) {
2933
3112
  const d = db || getDatabase();
2934
3113
  let totalEvicted = 0;
@@ -3440,6 +3619,47 @@ program2.command("agents").description("List all registered agents").action(() =
3440
3619
  handleError(e);
3441
3620
  }
3442
3621
  });
3622
+ program2.command("agent-update <id>").description("Update an agent's name, description, or role").option("--name <name>", "New agent name").option("-d, --description <text>", "New description").option("-r, --role <role>", "New role").action((id, opts) => {
3623
+ try {
3624
+ const globalOpts = program2.opts();
3625
+ const updates = {};
3626
+ if (opts.name !== undefined)
3627
+ updates.name = opts.name;
3628
+ if (opts.description !== undefined)
3629
+ updates.description = opts.description;
3630
+ if (opts.role !== undefined)
3631
+ updates.role = opts.role;
3632
+ if (Object.keys(updates).length === 0) {
3633
+ if (globalOpts.json) {
3634
+ outputJson({ error: "No updates provided. Use --name, --description, or --role." });
3635
+ } else {
3636
+ console.error(chalk.red("No updates provided. Use --name, --description, or --role."));
3637
+ }
3638
+ process.exit(1);
3639
+ }
3640
+ const agent = updateAgent(id, updates);
3641
+ if (!agent) {
3642
+ if (globalOpts.json) {
3643
+ outputJson({ error: `Agent not found: ${id}` });
3644
+ } else {
3645
+ console.error(chalk.red(`Agent not found: ${id}`));
3646
+ }
3647
+ process.exit(1);
3648
+ }
3649
+ if (globalOpts.json) {
3650
+ outputJson(agent);
3651
+ } else {
3652
+ console.log(chalk.green("Agent updated:"));
3653
+ console.log(` ${chalk.bold("ID:")} ${agent.id}`);
3654
+ console.log(` ${chalk.bold("Name:")} ${agent.name}`);
3655
+ console.log(` ${chalk.bold("Description:")} ${agent.description || "-"}`);
3656
+ console.log(` ${chalk.bold("Role:")} ${agent.role || "agent"}`);
3657
+ console.log(` ${chalk.bold("Last seen:")} ${agent.last_seen_at}`);
3658
+ }
3659
+ } catch (e) {
3660
+ handleError(e);
3661
+ }
3662
+ });
3443
3663
  program2.command("projects").description("Manage projects").option("--add", "Add a new project").option("--name <name>", "Project name").option("--path <path>", "Project path").option("--description <text>", "Project description").action((opts) => {
3444
3664
  try {
3445
3665
  const globalOpts = program2.opts();
@@ -3717,4 +3937,105 @@ args = []
3717
3937
  }
3718
3938
  }
3719
3939
  });
3940
+ program2.command("watch").description("Watch for new and changed memories in real-time").option("-s, --scope <scope>", "Scope filter: global, shared, private").option("-c, --category <cat>", "Category filter: preference, fact, knowledge, history").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--interval <ms>", "Poll interval in milliseconds", parseInt).action((opts) => {
3941
+ try {
3942
+ const globalOpts = program2.opts();
3943
+ const agentId = opts.agent || globalOpts.agent;
3944
+ const projectPath = opts.project || globalOpts.project;
3945
+ let projectId;
3946
+ if (projectPath) {
3947
+ const project = getProject(resolve3(projectPath));
3948
+ if (project)
3949
+ projectId = project.id;
3950
+ }
3951
+ const intervalMs = opts.interval || 500;
3952
+ console.log(chalk.bold.cyan("Watching memories...") + chalk.dim(" (Ctrl+C to stop)"));
3953
+ const filters = [];
3954
+ if (opts.scope)
3955
+ filters.push(`scope=${colorScope(opts.scope)}`);
3956
+ if (opts.category)
3957
+ filters.push(`category=${colorCategory(opts.category)}`);
3958
+ if (agentId)
3959
+ filters.push(`agent=${chalk.dim(agentId)}`);
3960
+ if (projectId)
3961
+ filters.push(`project=${chalk.dim(projectId)}`);
3962
+ if (filters.length > 0) {
3963
+ console.log(chalk.dim("Filters: ") + filters.join(chalk.dim(" | ")));
3964
+ }
3965
+ console.log(chalk.dim(`Poll interval: ${intervalMs}ms`));
3966
+ console.log();
3967
+ const filter = {
3968
+ scope: opts.scope,
3969
+ category: opts.category,
3970
+ agent_id: agentId,
3971
+ project_id: projectId,
3972
+ limit: 20
3973
+ };
3974
+ const recent = listMemories(filter);
3975
+ if (recent.length > 0) {
3976
+ console.log(chalk.bold.dim(`Recent (${recent.length}):`));
3977
+ for (const m of recent.reverse()) {
3978
+ console.log(formatWatchLine(m));
3979
+ }
3980
+ } else {
3981
+ console.log(chalk.dim("No recent memories."));
3982
+ }
3983
+ console.log(chalk.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Live \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3984
+ console.log();
3985
+ const { startPolling: startPolling2 } = (init_poll(), __toCommonJS(exports_poll));
3986
+ const handle = startPolling2({
3987
+ interval_ms: intervalMs,
3988
+ scope: opts.scope,
3989
+ category: opts.category,
3990
+ agent_id: agentId,
3991
+ project_id: projectId,
3992
+ on_memories: (memories) => {
3993
+ for (const m of memories) {
3994
+ console.log(formatWatchLine(m));
3995
+ sendNotification(m);
3996
+ }
3997
+ },
3998
+ on_error: (err) => {
3999
+ console.error(chalk.red(`Poll error: ${err.message}`));
4000
+ }
4001
+ });
4002
+ const cleanup = () => {
4003
+ handle.stop();
4004
+ console.log();
4005
+ console.log(chalk.dim("Stopped watching."));
4006
+ process.exit(0);
4007
+ };
4008
+ process.on("SIGINT", cleanup);
4009
+ process.on("SIGTERM", cleanup);
4010
+ } catch (e) {
4011
+ handleError(e);
4012
+ }
4013
+ });
4014
+ function formatWatchLine(m) {
4015
+ const scope = colorScope(m.scope);
4016
+ const cat = colorCategory(m.category);
4017
+ const imp = colorImportance(m.importance);
4018
+ const value = m.value.length > 100 ? m.value.slice(0, 100) + "..." : m.value;
4019
+ const main = ` [${scope}/${cat}] ${chalk.bold(m.key)} = ${value} ${chalk.dim(`(importance: ${imp})`)}`;
4020
+ const parts = [];
4021
+ if (m.tags.length > 0)
4022
+ parts.push(`Tags: ${m.tags.join(", ")}`);
4023
+ if (m.agent_id)
4024
+ parts.push(`Agent: ${m.agent_id}`);
4025
+ parts.push(`Updated: ${m.updated_at}`);
4026
+ const detail = chalk.dim(` ${parts.join(" | ")}`);
4027
+ return `${main}
4028
+ ${detail}`;
4029
+ }
4030
+ function sendNotification(m) {
4031
+ if (process.platform !== "darwin")
4032
+ return;
4033
+ try {
4034
+ const title = "Mementos";
4035
+ const msg = `[${m.scope}/${m.category}] ${m.key} = ${m.value.slice(0, 60)}`;
4036
+ const escaped = msg.replace(/"/g, "\\\"");
4037
+ const { execSync } = __require("child_process");
4038
+ execSync(`osascript -e 'display notification "${escaped}" with title "${title}"'`, { stdio: "ignore", timeout: 2000 });
4039
+ } catch {}
4040
+ }
3720
4041
  program2.parse(process.argv);
@@ -3,4 +3,10 @@ import type { Agent } from "../types/index.js";
3
3
  export declare function registerAgent(name: string, description?: string, role?: string, db?: Database): Agent;
4
4
  export declare function getAgent(idOrName: string, db?: Database): Agent | null;
5
5
  export declare function listAgents(db?: Database): Agent[];
6
+ export declare function updateAgent(id: string, updates: {
7
+ name?: string;
8
+ description?: string;
9
+ role?: string;
10
+ metadata?: Record<string, unknown>;
11
+ }, db?: Database): Agent | null;
6
12
  //# sourceMappingURL=agents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/db/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAe/C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,QAAQ,GACZ,KAAK,CAqCP;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,KAAK,GAAG,IAAI,CAsBd;AAED,wBAAgB,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,KAAK,EAAE,CAMjD"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/db/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAe/C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,QAAQ,GACZ,KAAK,CAqCP;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,KAAK,GAAG,IAAI,CAsBd;AAED,wBAAgB,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,KAAK,EAAE,CAMjD;AAED,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACnG,EAAE,CAAC,EAAE,QAAQ,GACZ,KAAK,GAAG,IAAI,CAkCd"}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export type { Memory, MemoryWithRelations, MemoryScope, MemoryCategory, MemorySo
2
2
  export { MemoryNotFoundError, DuplicateMemoryError, MemoryExpiredError, InvalidScopeError, VersionConflictError, } from "./types/index.js";
3
3
  export { getDatabase, closeDatabase, resetDatabase, getDbPath, resolvePartialId, now, uuid, shortUuid, } from "./db/database.js";
4
4
  export { createMemory, getMemory, getMemoryByKey, listMemories, updateMemory, deleteMemory, bulkDeleteMemories, touchMemory, cleanExpiredMemories, } from "./db/memories.js";
5
- export { registerAgent, getAgent, listAgents, } from "./db/agents.js";
5
+ export { registerAgent, getAgent, listAgents, updateAgent, } from "./db/agents.js";
6
6
  export { registerProject, getProject, listProjects, } from "./db/projects.js";
7
7
  export { searchMemories } from "./lib/search.js";
8
8
  export { loadConfig, DEFAULT_CONFIG } from "./lib/config.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,KAAK,EACL,OAAO,EACP,cAAc,EACd,aAAa,EACb,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,GAAG,EACH,IAAI,EACJ,SAAS,GACV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,YAAY,EACZ,SAAS,EACT,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,aAAa,EACb,QAAQ,EACR,UAAU,GACX,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,KAAK,EACL,OAAO,EACP,cAAc,EACd,aAAa,EACb,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,GAAG,EACH,IAAI,EACJ,SAAS,GACV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,YAAY,EACZ,SAAS,EACT,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,aAAa,EACb,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -602,6 +602,31 @@ function listAgents(db) {
602
602
  const rows = d.query("SELECT * FROM agents ORDER BY last_seen_at DESC").all();
603
603
  return rows.map(parseAgentRow);
604
604
  }
605
+ function updateAgent(id, updates, db) {
606
+ const d = db || getDatabase();
607
+ const agent = getAgent(id, d);
608
+ if (!agent)
609
+ return null;
610
+ const timestamp = now();
611
+ if (updates.name && updates.name !== agent.name) {
612
+ const existing = d.query("SELECT id FROM agents WHERE name = ? AND id != ?").get(updates.name, agent.id);
613
+ if (existing) {
614
+ throw new Error(`Agent name already taken: ${updates.name}`);
615
+ }
616
+ d.run("UPDATE agents SET name = ? WHERE id = ?", [updates.name, agent.id]);
617
+ }
618
+ if (updates.description !== undefined) {
619
+ d.run("UPDATE agents SET description = ? WHERE id = ?", [updates.description, agent.id]);
620
+ }
621
+ if (updates.role !== undefined) {
622
+ d.run("UPDATE agents SET role = ? WHERE id = ?", [updates.role, agent.id]);
623
+ }
624
+ if (updates.metadata !== undefined) {
625
+ d.run("UPDATE agents SET metadata = ? WHERE id = ?", [JSON.stringify(updates.metadata), agent.id]);
626
+ }
627
+ d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [timestamp, agent.id]);
628
+ return getAgent(agent.id, d);
629
+ }
605
630
  // src/db/projects.ts
606
631
  function parseProjectRow(row) {
607
632
  return {
@@ -1136,6 +1161,7 @@ var defaultSyncAgents = ["claude", "codex", "gemini"];
1136
1161
  export {
1137
1162
  uuid,
1138
1163
  updateMemory,
1164
+ updateAgent,
1139
1165
  touchMemory,
1140
1166
  syncMemories,
1141
1167
  shortUuid,
@@ -0,0 +1,17 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import type { Memory, MemoryScope, MemoryCategory } from "../types/index.js";
3
+ export interface PollOptions {
4
+ interval_ms?: number;
5
+ scope?: MemoryScope;
6
+ category?: MemoryCategory;
7
+ agent_id?: string;
8
+ project_id?: string;
9
+ on_memories: (memories: Memory[]) => void;
10
+ on_error?: (error: Error) => void;
11
+ db?: Database;
12
+ }
13
+ export interface PollHandle {
14
+ stop: () => void;
15
+ }
16
+ export declare function startPolling(opts: PollOptions): PollHandle;
17
+ //# sourceMappingURL=poll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../../src/lib/poll.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAQ7E,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CA0F1D"}
package/dist/mcp/index.js CHANGED
@@ -4577,6 +4577,31 @@ function listAgents(db) {
4577
4577
  const rows = d.query("SELECT * FROM agents ORDER BY last_seen_at DESC").all();
4578
4578
  return rows.map(parseAgentRow);
4579
4579
  }
4580
+ function updateAgent(id, updates, db) {
4581
+ const d = db || getDatabase();
4582
+ const agent = getAgent(id, d);
4583
+ if (!agent)
4584
+ return null;
4585
+ const timestamp = now();
4586
+ if (updates.name && updates.name !== agent.name) {
4587
+ const existing = d.query("SELECT id FROM agents WHERE name = ? AND id != ?").get(updates.name, agent.id);
4588
+ if (existing) {
4589
+ throw new Error(`Agent name already taken: ${updates.name}`);
4590
+ }
4591
+ d.run("UPDATE agents SET name = ? WHERE id = ?", [updates.name, agent.id]);
4592
+ }
4593
+ if (updates.description !== undefined) {
4594
+ d.run("UPDATE agents SET description = ? WHERE id = ?", [updates.description, agent.id]);
4595
+ }
4596
+ if (updates.role !== undefined) {
4597
+ d.run("UPDATE agents SET role = ? WHERE id = ?", [updates.role, agent.id]);
4598
+ }
4599
+ if (updates.metadata !== undefined) {
4600
+ d.run("UPDATE agents SET metadata = ? WHERE id = ?", [JSON.stringify(updates.metadata), agent.id]);
4601
+ }
4602
+ d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [timestamp, agent.id]);
4603
+ return getAgent(agent.id, d);
4604
+ }
4580
4605
 
4581
4606
  // src/db/projects.ts
4582
4607
  function parseProjectRow(row) {
@@ -5059,6 +5084,35 @@ Last seen: ${agent.last_seen_at}`
5059
5084
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
5060
5085
  }
5061
5086
  });
5087
+ server.tool("update_agent", "Update an agent's name, description, role, or metadata. Agents can update themselves.", {
5088
+ id: exports_external.string().describe("Agent ID or name"),
5089
+ name: exports_external.string().optional().describe("New agent name"),
5090
+ description: exports_external.string().optional().describe("New description"),
5091
+ role: exports_external.string().optional().describe("New role"),
5092
+ metadata: exports_external.record(exports_external.unknown()).optional().describe("Updated metadata")
5093
+ }, async (args) => {
5094
+ try {
5095
+ const { id, ...updates } = args;
5096
+ const agent = updateAgent(id, updates);
5097
+ if (!agent) {
5098
+ return { content: [{ type: "text", text: `Agent not found: ${id}` }] };
5099
+ }
5100
+ return {
5101
+ content: [{
5102
+ type: "text",
5103
+ text: `Agent updated:
5104
+ ID: ${agent.id}
5105
+ Name: ${agent.name}
5106
+ Description: ${agent.description || "-"}
5107
+ Role: ${agent.role || "agent"}
5108
+ Metadata: ${JSON.stringify(agent.metadata)}
5109
+ Last seen: ${agent.last_seen_at}`
5110
+ }]
5111
+ };
5112
+ } catch (e) {
5113
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
5114
+ }
5115
+ });
5062
5116
  server.tool("register_project", "Register a project for memory scoping", {
5063
5117
  name: exports_external.string().describe("Project name"),
5064
5118
  path: exports_external.string().describe("Absolute path to project"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",