@hasna/conversations 0.1.4 → 0.1.6

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.js CHANGED
@@ -3,6 +3,7 @@ var __create = Object.create;
3
3
  var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
8
  var __toESM = (mod, isNodeMode, target) => {
8
9
  target = mod != null ? __create(__getProtoOf(mod)) : {};
@@ -15,7 +16,190 @@ var __toESM = (mod, isNodeMode, target) => {
15
16
  });
16
17
  return to;
17
18
  };
19
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
20
+ var __toCommonJS = (from) => {
21
+ var entry = __moduleCache.get(from), desc;
22
+ if (entry)
23
+ return entry;
24
+ entry = __defProp({}, "__esModule", { value: true });
25
+ if (from && typeof from === "object" || typeof from === "function")
26
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
27
+ get: () => from[key],
28
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
29
+ }));
30
+ __moduleCache.set(from, entry);
31
+ return entry;
32
+ };
18
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __export = (target, all) => {
35
+ for (var name in all)
36
+ __defProp(target, name, {
37
+ get: all[name],
38
+ enumerable: true,
39
+ configurable: true,
40
+ set: (newValue) => all[name] = () => newValue
41
+ });
42
+ };
43
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
44
+
45
+ // src/lib/db.ts
46
+ var exports_db = {};
47
+ __export(exports_db, {
48
+ getDbPath: () => getDbPath,
49
+ getDb: () => getDb,
50
+ closeDb: () => closeDb
51
+ });
52
+ import { Database } from "bun:sqlite";
53
+ import { mkdirSync } from "fs";
54
+ import { join, dirname } from "path";
55
+ import { homedir } from "os";
56
+ function getDbPath() {
57
+ if (process.env.CONVERSATIONS_DB_PATH)
58
+ return process.env.CONVERSATIONS_DB_PATH;
59
+ return join(homedir(), ".conversations", "messages.db");
60
+ }
61
+ function getDb() {
62
+ if (db)
63
+ return db;
64
+ const dbPath = getDbPath();
65
+ mkdirSync(dirname(dbPath), { recursive: true });
66
+ db = new Database(dbPath, { create: true });
67
+ db.exec("PRAGMA journal_mode = WAL");
68
+ db.exec("PRAGMA busy_timeout = 5000");
69
+ db.exec(`
70
+ CREATE TABLE IF NOT EXISTS messages (
71
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
72
+ session_id TEXT NOT NULL,
73
+ from_agent TEXT NOT NULL,
74
+ to_agent TEXT NOT NULL,
75
+ space TEXT,
76
+ content TEXT NOT NULL,
77
+ priority TEXT NOT NULL DEFAULT 'normal',
78
+ working_dir TEXT,
79
+ repository TEXT,
80
+ branch TEXT,
81
+ metadata TEXT,
82
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
83
+ read_at TEXT
84
+ )
85
+ `);
86
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id)");
87
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent)");
88
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at)");
89
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
90
+ db.exec(`
91
+ CREATE TABLE IF NOT EXISTS projects (
92
+ id TEXT PRIMARY KEY,
93
+ name TEXT NOT NULL UNIQUE,
94
+ description TEXT,
95
+ path TEXT,
96
+ created_by TEXT NOT NULL,
97
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
98
+ metadata TEXT,
99
+ tags TEXT,
100
+ status TEXT NOT NULL DEFAULT 'active',
101
+ repository TEXT,
102
+ settings TEXT
103
+ )
104
+ `);
105
+ db.exec("CREATE INDEX IF NOT EXISTS idx_projects_name ON projects(name)");
106
+ db.exec("CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status)");
107
+ db.exec(`
108
+ CREATE TABLE IF NOT EXISTS spaces (
109
+ name TEXT PRIMARY KEY,
110
+ description TEXT,
111
+ parent_id TEXT REFERENCES spaces(name),
112
+ project_id TEXT REFERENCES projects(id),
113
+ created_by TEXT NOT NULL,
114
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
115
+ archived_at TEXT
116
+ )
117
+ `);
118
+ db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_parent ON spaces(parent_id)");
119
+ db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_project ON spaces(project_id)");
120
+ db.exec(`
121
+ CREATE TABLE IF NOT EXISTS space_members (
122
+ space TEXT NOT NULL REFERENCES spaces(name),
123
+ agent TEXT NOT NULL,
124
+ joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
125
+ PRIMARY KEY (space, agent)
126
+ )
127
+ `);
128
+ db.exec(`
129
+ CREATE TABLE IF NOT EXISTS agent_presence (
130
+ agent TEXT PRIMARY KEY,
131
+ status TEXT NOT NULL DEFAULT 'online',
132
+ last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
133
+ metadata TEXT
134
+ )
135
+ `);
136
+ const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
137
+ const tableNames = existingTables.map((t) => t.name);
138
+ if (tableNames.includes("channels") && tableNames.includes("spaces")) {
139
+ const spaceCount = db.prepare("SELECT COUNT(*) as c FROM spaces").get().c;
140
+ const channelCount = db.prepare("SELECT COUNT(*) as c FROM channels").get().c;
141
+ if (channelCount > 0 && spaceCount === 0) {
142
+ db.exec("BEGIN");
143
+ try {
144
+ db.exec(`
145
+ INSERT OR IGNORE INTO spaces (name, description, created_by, created_at)
146
+ SELECT name, description, created_by, created_at FROM channels
147
+ `);
148
+ if (tableNames.includes("channel_members")) {
149
+ db.exec(`
150
+ INSERT OR IGNORE INTO space_members (space, agent, joined_at)
151
+ SELECT channel, agent, joined_at FROM channel_members
152
+ `);
153
+ }
154
+ db.exec("COMMIT");
155
+ } catch (e) {
156
+ db.exec("ROLLBACK");
157
+ throw e;
158
+ }
159
+ }
160
+ db.exec("DROP TABLE IF EXISTS channel_members");
161
+ db.exec("DROP TABLE IF EXISTS channels");
162
+ }
163
+ const msgCols = db.prepare("PRAGMA table_info(messages)").all();
164
+ const colNames = msgCols.map((c) => c.name);
165
+ if (colNames.includes("channel") && !colNames.includes("space")) {
166
+ db.exec("ALTER TABLE messages ADD COLUMN space TEXT");
167
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
168
+ db.exec("UPDATE messages SET space = channel WHERE channel IS NOT NULL");
169
+ db.exec(`
170
+ UPDATE messages
171
+ SET session_id = 'space:' || substr(session_id, 9)
172
+ WHERE session_id LIKE 'channel:%'
173
+ `);
174
+ }
175
+ const spaceCols = db.prepare("PRAGMA table_info(spaces)").all();
176
+ const spaceColNames = spaceCols.map((c) => c.name);
177
+ if (!spaceColNames.includes("archived_at")) {
178
+ db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
179
+ }
180
+ const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
181
+ const colNames2 = msgCols2.map((c) => c.name);
182
+ if (!colNames2.includes("edited_at")) {
183
+ db.exec("ALTER TABLE messages ADD COLUMN edited_at TEXT");
184
+ }
185
+ if (!colNames2.includes("pinned_at")) {
186
+ db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
187
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
188
+ }
189
+ if (!colNames2.includes("blocking")) {
190
+ db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
191
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
192
+ }
193
+ return db;
194
+ }
195
+ function closeDb() {
196
+ if (db) {
197
+ db.close();
198
+ db = null;
199
+ }
200
+ }
201
+ var db = null;
202
+ var init_db = () => {};
19
203
 
20
204
  // node_modules/react/cjs/react.development.js
21
205
  var require_react_development = __commonJS((exports, module) => {
@@ -1828,155 +2012,8 @@ var require_react = __commonJS((exports, module) => {
1828
2012
  }
1829
2013
  });
1830
2014
 
1831
- // src/lib/db.ts
1832
- import { Database } from "bun:sqlite";
1833
- import { mkdirSync } from "fs";
1834
- import { join, dirname } from "path";
1835
- import { homedir } from "os";
1836
- var db = null;
1837
- function getDbPath() {
1838
- if (process.env.CONVERSATIONS_DB_PATH)
1839
- return process.env.CONVERSATIONS_DB_PATH;
1840
- return join(homedir(), ".conversations", "messages.db");
1841
- }
1842
- function getDb() {
1843
- if (db)
1844
- return db;
1845
- const dbPath = getDbPath();
1846
- mkdirSync(dirname(dbPath), { recursive: true });
1847
- db = new Database(dbPath, { create: true });
1848
- db.exec("PRAGMA journal_mode = WAL");
1849
- db.exec("PRAGMA busy_timeout = 5000");
1850
- db.exec(`
1851
- CREATE TABLE IF NOT EXISTS messages (
1852
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1853
- session_id TEXT NOT NULL,
1854
- from_agent TEXT NOT NULL,
1855
- to_agent TEXT NOT NULL,
1856
- space TEXT,
1857
- content TEXT NOT NULL,
1858
- priority TEXT NOT NULL DEFAULT 'normal',
1859
- working_dir TEXT,
1860
- repository TEXT,
1861
- branch TEXT,
1862
- metadata TEXT,
1863
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1864
- read_at TEXT
1865
- )
1866
- `);
1867
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id)");
1868
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent)");
1869
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at)");
1870
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
1871
- db.exec(`
1872
- CREATE TABLE IF NOT EXISTS projects (
1873
- id TEXT PRIMARY KEY,
1874
- name TEXT NOT NULL UNIQUE,
1875
- description TEXT,
1876
- path TEXT,
1877
- created_by TEXT NOT NULL,
1878
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1879
- metadata TEXT,
1880
- tags TEXT,
1881
- status TEXT NOT NULL DEFAULT 'active',
1882
- repository TEXT,
1883
- settings TEXT
1884
- )
1885
- `);
1886
- db.exec("CREATE INDEX IF NOT EXISTS idx_projects_name ON projects(name)");
1887
- db.exec("CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status)");
1888
- db.exec(`
1889
- CREATE TABLE IF NOT EXISTS spaces (
1890
- name TEXT PRIMARY KEY,
1891
- description TEXT,
1892
- parent_id TEXT REFERENCES spaces(name),
1893
- project_id TEXT REFERENCES projects(id),
1894
- created_by TEXT NOT NULL,
1895
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1896
- archived_at TEXT
1897
- )
1898
- `);
1899
- db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_parent ON spaces(parent_id)");
1900
- db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_project ON spaces(project_id)");
1901
- db.exec(`
1902
- CREATE TABLE IF NOT EXISTS space_members (
1903
- space TEXT NOT NULL REFERENCES spaces(name),
1904
- agent TEXT NOT NULL,
1905
- joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1906
- PRIMARY KEY (space, agent)
1907
- )
1908
- `);
1909
- db.exec(`
1910
- CREATE TABLE IF NOT EXISTS agent_presence (
1911
- agent TEXT PRIMARY KEY,
1912
- status TEXT NOT NULL DEFAULT 'online',
1913
- last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1914
- metadata TEXT
1915
- )
1916
- `);
1917
- const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
1918
- const tableNames = existingTables.map((t) => t.name);
1919
- if (tableNames.includes("channels") && tableNames.includes("spaces")) {
1920
- const spaceCount = db.prepare("SELECT COUNT(*) as c FROM spaces").get().c;
1921
- const channelCount = db.prepare("SELECT COUNT(*) as c FROM channels").get().c;
1922
- if (channelCount > 0 && spaceCount === 0) {
1923
- db.exec("BEGIN");
1924
- try {
1925
- db.exec(`
1926
- INSERT OR IGNORE INTO spaces (name, description, created_by, created_at)
1927
- SELECT name, description, created_by, created_at FROM channels
1928
- `);
1929
- if (tableNames.includes("channel_members")) {
1930
- db.exec(`
1931
- INSERT OR IGNORE INTO space_members (space, agent, joined_at)
1932
- SELECT channel, agent, joined_at FROM channel_members
1933
- `);
1934
- }
1935
- db.exec("COMMIT");
1936
- } catch (e) {
1937
- db.exec("ROLLBACK");
1938
- throw e;
1939
- }
1940
- }
1941
- db.exec("DROP TABLE IF EXISTS channel_members");
1942
- db.exec("DROP TABLE IF EXISTS channels");
1943
- }
1944
- const msgCols = db.prepare("PRAGMA table_info(messages)").all();
1945
- const colNames = msgCols.map((c) => c.name);
1946
- if (colNames.includes("channel") && !colNames.includes("space")) {
1947
- db.exec("ALTER TABLE messages ADD COLUMN space TEXT");
1948
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
1949
- db.exec("UPDATE messages SET space = channel WHERE channel IS NOT NULL");
1950
- db.exec(`
1951
- UPDATE messages
1952
- SET session_id = 'space:' || substr(session_id, 9)
1953
- WHERE session_id LIKE 'channel:%'
1954
- `);
1955
- }
1956
- const spaceCols = db.prepare("PRAGMA table_info(spaces)").all();
1957
- const spaceColNames = spaceCols.map((c) => c.name);
1958
- if (!spaceColNames.includes("archived_at")) {
1959
- db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
1960
- }
1961
- const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
1962
- const colNames2 = msgCols2.map((c) => c.name);
1963
- if (!colNames2.includes("edited_at")) {
1964
- db.exec("ALTER TABLE messages ADD COLUMN edited_at TEXT");
1965
- }
1966
- if (!colNames2.includes("pinned_at")) {
1967
- db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
1968
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
1969
- }
1970
- return db;
1971
- }
1972
- function closeDb() {
1973
- if (db) {
1974
- db.close();
1975
- db = null;
1976
- }
1977
- }
1978
-
1979
2015
  // src/lib/messages.ts
2016
+ init_db();
1980
2017
  import { randomUUID } from "crypto";
1981
2018
  function parseMessage(row) {
1982
2019
  let metadata = null;
@@ -1989,7 +2026,8 @@ function parseMessage(row) {
1989
2026
  }
1990
2027
  return {
1991
2028
  ...row,
1992
- metadata
2029
+ metadata,
2030
+ blocking: !!row.blocking
1993
2031
  };
1994
2032
  }
1995
2033
  function sendMessage(opts) {
@@ -1998,12 +2036,13 @@ function sendMessage(opts) {
1998
2036
  const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID().slice(0, 8)}`);
1999
2037
  const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
2000
2038
  const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
2039
+ const blocking = opts.blocking ? 1 : 0;
2001
2040
  const stmt = db2.prepare(`
2002
- INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata)
2003
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2041
+ INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
2042
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2004
2043
  RETURNING *
2005
2044
  `);
2006
- const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata);
2045
+ const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking);
2007
2046
  return parseMessage(row);
2008
2047
  }
2009
2048
  function readMessages(opts = {}) {
@@ -2172,6 +2211,19 @@ function getPinnedMessages(opts) {
2172
2211
  const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY pinned_at DESC, id DESC ${limit}`).all(...params);
2173
2212
  return rows.map(parseMessage);
2174
2213
  }
2214
+ function getUnreadBlockers(agent) {
2215
+ const db2 = getDb();
2216
+ const rows = db2.prepare(`
2217
+ SELECT * FROM messages
2218
+ WHERE blocking = 1 AND read_at IS NULL
2219
+ AND (
2220
+ to_agent = ?
2221
+ OR space IN (SELECT space FROM space_members WHERE agent = ?)
2222
+ )
2223
+ ORDER BY created_at ASC, id ASC
2224
+ `).all(agent, agent);
2225
+ return rows.map(parseMessage);
2226
+ }
2175
2227
  function searchMessages(opts) {
2176
2228
  const db2 = getDb();
2177
2229
  const conditions = ["content LIKE ?"];
@@ -2194,6 +2246,7 @@ function searchMessages(opts) {
2194
2246
  return rows.map(parseMessage);
2195
2247
  }
2196
2248
  // src/lib/sessions.ts
2249
+ init_db();
2197
2250
  function listSessions(agent) {
2198
2251
  const db2 = getDb();
2199
2252
  const agentFilter = agent ? "WHERE from_agent = ? OR to_agent = ?" : "";
@@ -2248,6 +2301,7 @@ function getSession(sessionId) {
2248
2301
  };
2249
2302
  }
2250
2303
  // src/lib/spaces.ts
2304
+ init_db();
2251
2305
  function getSpaceDepth(spaceName) {
2252
2306
  const db2 = getDb();
2253
2307
  let depth = 0;
@@ -2429,6 +2483,7 @@ function isSpaceMember(spaceName, agent) {
2429
2483
  return !!row;
2430
2484
  }
2431
2485
  // src/lib/projects.ts
2486
+ init_db();
2432
2487
  import { randomUUID as randomUUID2 } from "crypto";
2433
2488
  function parseProject(row) {
2434
2489
  let metadata = null;
@@ -2592,6 +2647,10 @@ function deleteProject(id) {
2592
2647
  const result = db2.prepare("DELETE FROM projects WHERE id = ?").run(id);
2593
2648
  return result.changes > 0;
2594
2649
  }
2650
+
2651
+ // src/index.ts
2652
+ init_db();
2653
+
2595
2654
  // src/lib/poll.ts
2596
2655
  var import_react = __toESM(require_react(), 1);
2597
2656
  function startPolling(opts) {
@@ -3017,6 +3076,16 @@ var AGENT_NAMES = [
3017
3076
  // src/lib/identity.ts
3018
3077
  var AGENT_ID_FILE = join2(homedir2(), ".conversations", "agent-id");
3019
3078
  var cachedAutoName = null;
3079
+ function isNameTaken(name) {
3080
+ try {
3081
+ const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
3082
+ const db2 = getDb2();
3083
+ const row = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(name);
3084
+ return !!row;
3085
+ } catch {
3086
+ return false;
3087
+ }
3088
+ }
3020
3089
  function getAutoName() {
3021
3090
  if (cachedAutoName)
3022
3091
  return cachedAutoName;
@@ -3027,7 +3096,14 @@ function getAutoName() {
3027
3096
  return name2;
3028
3097
  }
3029
3098
  } catch {}
3030
- const name = AGENT_NAMES[Math.floor(Math.random() * AGENT_NAMES.length)];
3099
+ const shuffled = [...AGENT_NAMES].sort(() => Math.random() - 0.5);
3100
+ let name = shuffled[0];
3101
+ for (const candidate of shuffled) {
3102
+ if (!isNameTaken(candidate)) {
3103
+ name = candidate;
3104
+ break;
3105
+ }
3106
+ }
3031
3107
  cachedAutoName = name;
3032
3108
  try {
3033
3109
  mkdirSync2(dirname2(AGENT_ID_FILE), { recursive: true });
@@ -3055,6 +3131,7 @@ function requireIdentity(explicit) {
3055
3131
  throw new Error("Agent identity required. Set CONVERSATIONS_AGENT_ID env var or pass --from flag.");
3056
3132
  }
3057
3133
  // src/lib/presence.ts
3134
+ init_db();
3058
3135
  var ONLINE_THRESHOLD_SECONDS = 60;
3059
3136
  function parsePresence(row) {
3060
3137
  let metadata = null;
@@ -3111,6 +3188,17 @@ function removePresence(agent) {
3111
3188
  const result = db2.prepare("DELETE FROM agent_presence WHERE agent = ?").run(agent);
3112
3189
  return result.changes > 0;
3113
3190
  }
3191
+ function renameAgent(oldName, newName) {
3192
+ const db2 = getDb();
3193
+ const existing = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(oldName);
3194
+ if (!existing)
3195
+ return false;
3196
+ const conflict = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(newName);
3197
+ if (conflict)
3198
+ throw new Error(`Agent "${newName}" already exists`);
3199
+ db2.prepare("UPDATE agent_presence SET agent = ? WHERE agent = ?").run(newName, oldName);
3200
+ return true;
3201
+ }
3114
3202
  export {
3115
3203
  useSpaceMessages,
3116
3204
  updateSpace,
@@ -3122,6 +3210,7 @@ export {
3122
3210
  searchMessages,
3123
3211
  resolveIdentity,
3124
3212
  requireIdentity,
3213
+ renameAgent,
3125
3214
  removePresence,
3126
3215
  readMessages,
3127
3216
  pinMessage,
@@ -3137,6 +3226,7 @@ export {
3137
3226
  joinSpace,
3138
3227
  isSpaceMember,
3139
3228
  heartbeat,
3229
+ getUnreadBlockers,
3140
3230
  getSpaceMembers,
3141
3231
  getSpaceDepth,
3142
3232
  getSpace,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Get or create a persistent auto-generated agent name.
3
3
  * Stored in ~/.conversations/agent-id so the same installation
4
- * always gets the same name.
4
+ * always gets the same name. Checks the DB to avoid duplicates.
5
5
  */
6
6
  export declare function getAutoName(): string;
7
7
  /**
@@ -24,4 +24,5 @@ export declare function getPinnedMessages(opts?: {
24
24
  session_id?: string;
25
25
  limit?: number;
26
26
  }): Message[];
27
+ export declare function getUnreadBlockers(agent: string): Message[];
27
28
  export declare function searchMessages(opts: SearchMessagesOptions): Message[];
@@ -5,3 +5,4 @@ export declare function listAgents(opts?: {
5
5
  online_only?: boolean;
6
6
  }): AgentPresence[];
7
7
  export declare function removePresence(agent: string): boolean;
8
+ export declare function renameAgent(oldName: string, newName: string): boolean;
package/dist/types.d.ts CHANGED
@@ -15,6 +15,7 @@ export interface Message {
15
15
  read_at: string | null;
16
16
  edited_at: string | null;
17
17
  pinned_at: string | null;
18
+ blocking: boolean;
18
19
  }
19
20
  export interface Session {
20
21
  session_id: string;
@@ -69,6 +70,7 @@ export interface SendMessageOptions {
69
70
  repository?: string;
70
71
  branch?: string;
71
72
  metadata?: Record<string, unknown>;
73
+ blocking?: boolean;
72
74
  }
73
75
  export interface ReadMessagesOptions {
74
76
  session_id?: string;
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@hasna/conversations",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Real-time CLI messaging for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "conversations": "bin/index.js",
8
- "conversations-mcp": "bin/mcp.js"
8
+ "conversations-mcp": "bin/mcp.js",
9
+ "conversations-hook": "bin/hook.js"
9
10
  },
10
11
  "exports": {
11
12
  ".": {
@@ -23,7 +24,7 @@
23
24
  "main": "./dist/index.js",
24
25
  "types": "./dist/index.d.ts",
25
26
  "scripts": {
26
- "build": "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
27
+ "build": "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/hooks/blocker-hook.ts --outfile ./bin/hook.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
27
28
  "build:dashboard": "cd dashboard && bun install && bun run build",
28
29
  "test": "bun test",
29
30
  "dev": "bun run ./src/cli/index.tsx",