@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/bin/mcp.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,6 +17,20 @@ 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);
20
35
  var __export = (target, all) => {
21
36
  for (var name in all)
@@ -26,6 +41,7 @@ var __export = (target, all) => {
26
41
  set: (newValue) => all[name] = () => newValue
27
42
  });
28
43
  };
44
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
45
 
30
46
  // node_modules/ajv/dist/compile/codegen/code.js
31
47
  var require_code = __commonJS((exports) => {
@@ -6499,6 +6515,165 @@ var require_dist = __commonJS((exports, module) => {
6499
6515
  exports.default = formatsPlugin;
6500
6516
  });
6501
6517
 
6518
+ // src/lib/db.ts
6519
+ var exports_db = {};
6520
+ __export(exports_db, {
6521
+ getDbPath: () => getDbPath,
6522
+ getDb: () => getDb,
6523
+ closeDb: () => closeDb
6524
+ });
6525
+ import { Database } from "bun:sqlite";
6526
+ import { mkdirSync } from "fs";
6527
+ import { join, dirname } from "path";
6528
+ import { homedir } from "os";
6529
+ function getDbPath() {
6530
+ if (process.env.CONVERSATIONS_DB_PATH)
6531
+ return process.env.CONVERSATIONS_DB_PATH;
6532
+ return join(homedir(), ".conversations", "messages.db");
6533
+ }
6534
+ function getDb() {
6535
+ if (db)
6536
+ return db;
6537
+ const dbPath = getDbPath();
6538
+ mkdirSync(dirname(dbPath), { recursive: true });
6539
+ db = new Database(dbPath, { create: true });
6540
+ db.exec("PRAGMA journal_mode = WAL");
6541
+ db.exec("PRAGMA busy_timeout = 5000");
6542
+ db.exec(`
6543
+ CREATE TABLE IF NOT EXISTS messages (
6544
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
6545
+ session_id TEXT NOT NULL,
6546
+ from_agent TEXT NOT NULL,
6547
+ to_agent TEXT NOT NULL,
6548
+ space TEXT,
6549
+ content TEXT NOT NULL,
6550
+ priority TEXT NOT NULL DEFAULT 'normal',
6551
+ working_dir TEXT,
6552
+ repository TEXT,
6553
+ branch TEXT,
6554
+ metadata TEXT,
6555
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6556
+ read_at TEXT
6557
+ )
6558
+ `);
6559
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id)");
6560
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent)");
6561
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at)");
6562
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
6563
+ db.exec(`
6564
+ CREATE TABLE IF NOT EXISTS projects (
6565
+ id TEXT PRIMARY KEY,
6566
+ name TEXT NOT NULL UNIQUE,
6567
+ description TEXT,
6568
+ path TEXT,
6569
+ created_by TEXT NOT NULL,
6570
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6571
+ metadata TEXT,
6572
+ tags TEXT,
6573
+ status TEXT NOT NULL DEFAULT 'active',
6574
+ repository TEXT,
6575
+ settings TEXT
6576
+ )
6577
+ `);
6578
+ db.exec("CREATE INDEX IF NOT EXISTS idx_projects_name ON projects(name)");
6579
+ db.exec("CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status)");
6580
+ db.exec(`
6581
+ CREATE TABLE IF NOT EXISTS spaces (
6582
+ name TEXT PRIMARY KEY,
6583
+ description TEXT,
6584
+ parent_id TEXT REFERENCES spaces(name),
6585
+ project_id TEXT REFERENCES projects(id),
6586
+ created_by TEXT NOT NULL,
6587
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6588
+ archived_at TEXT
6589
+ )
6590
+ `);
6591
+ db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_parent ON spaces(parent_id)");
6592
+ db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_project ON spaces(project_id)");
6593
+ db.exec(`
6594
+ CREATE TABLE IF NOT EXISTS space_members (
6595
+ space TEXT NOT NULL REFERENCES spaces(name),
6596
+ agent TEXT NOT NULL,
6597
+ joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6598
+ PRIMARY KEY (space, agent)
6599
+ )
6600
+ `);
6601
+ db.exec(`
6602
+ CREATE TABLE IF NOT EXISTS agent_presence (
6603
+ agent TEXT PRIMARY KEY,
6604
+ status TEXT NOT NULL DEFAULT 'online',
6605
+ last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6606
+ metadata TEXT
6607
+ )
6608
+ `);
6609
+ const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
6610
+ const tableNames = existingTables.map((t) => t.name);
6611
+ if (tableNames.includes("channels") && tableNames.includes("spaces")) {
6612
+ const spaceCount = db.prepare("SELECT COUNT(*) as c FROM spaces").get().c;
6613
+ const channelCount = db.prepare("SELECT COUNT(*) as c FROM channels").get().c;
6614
+ if (channelCount > 0 && spaceCount === 0) {
6615
+ db.exec("BEGIN");
6616
+ try {
6617
+ db.exec(`
6618
+ INSERT OR IGNORE INTO spaces (name, description, created_by, created_at)
6619
+ SELECT name, description, created_by, created_at FROM channels
6620
+ `);
6621
+ if (tableNames.includes("channel_members")) {
6622
+ db.exec(`
6623
+ INSERT OR IGNORE INTO space_members (space, agent, joined_at)
6624
+ SELECT channel, agent, joined_at FROM channel_members
6625
+ `);
6626
+ }
6627
+ db.exec("COMMIT");
6628
+ } catch (e) {
6629
+ db.exec("ROLLBACK");
6630
+ throw e;
6631
+ }
6632
+ }
6633
+ db.exec("DROP TABLE IF EXISTS channel_members");
6634
+ db.exec("DROP TABLE IF EXISTS channels");
6635
+ }
6636
+ const msgCols = db.prepare("PRAGMA table_info(messages)").all();
6637
+ const colNames = msgCols.map((c) => c.name);
6638
+ if (colNames.includes("channel") && !colNames.includes("space")) {
6639
+ db.exec("ALTER TABLE messages ADD COLUMN space TEXT");
6640
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
6641
+ db.exec("UPDATE messages SET space = channel WHERE channel IS NOT NULL");
6642
+ db.exec(`
6643
+ UPDATE messages
6644
+ SET session_id = 'space:' || substr(session_id, 9)
6645
+ WHERE session_id LIKE 'channel:%'
6646
+ `);
6647
+ }
6648
+ const spaceCols = db.prepare("PRAGMA table_info(spaces)").all();
6649
+ const spaceColNames = spaceCols.map((c) => c.name);
6650
+ if (!spaceColNames.includes("archived_at")) {
6651
+ db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
6652
+ }
6653
+ const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
6654
+ const colNames2 = msgCols2.map((c) => c.name);
6655
+ if (!colNames2.includes("edited_at")) {
6656
+ db.exec("ALTER TABLE messages ADD COLUMN edited_at TEXT");
6657
+ }
6658
+ if (!colNames2.includes("pinned_at")) {
6659
+ db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
6660
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
6661
+ }
6662
+ if (!colNames2.includes("blocking")) {
6663
+ db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
6664
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
6665
+ }
6666
+ return db;
6667
+ }
6668
+ function closeDb() {
6669
+ if (db) {
6670
+ db.close();
6671
+ db = null;
6672
+ }
6673
+ }
6674
+ var db = null;
6675
+ var init_db = () => {};
6676
+
6502
6677
  // node_modules/zod/v3/helpers/util.js
6503
6678
  var util;
6504
6679
  (function(util2) {
@@ -28316,149 +28491,8 @@ class StdioServerTransport {
28316
28491
  }
28317
28492
  }
28318
28493
 
28319
- // src/lib/db.ts
28320
- import { Database } from "bun:sqlite";
28321
- import { mkdirSync } from "fs";
28322
- import { join, dirname } from "path";
28323
- import { homedir } from "os";
28324
- var db = null;
28325
- function getDbPath() {
28326
- if (process.env.CONVERSATIONS_DB_PATH)
28327
- return process.env.CONVERSATIONS_DB_PATH;
28328
- return join(homedir(), ".conversations", "messages.db");
28329
- }
28330
- function getDb() {
28331
- if (db)
28332
- return db;
28333
- const dbPath = getDbPath();
28334
- mkdirSync(dirname(dbPath), { recursive: true });
28335
- db = new Database(dbPath, { create: true });
28336
- db.exec("PRAGMA journal_mode = WAL");
28337
- db.exec("PRAGMA busy_timeout = 5000");
28338
- db.exec(`
28339
- CREATE TABLE IF NOT EXISTS messages (
28340
- id INTEGER PRIMARY KEY AUTOINCREMENT,
28341
- session_id TEXT NOT NULL,
28342
- from_agent TEXT NOT NULL,
28343
- to_agent TEXT NOT NULL,
28344
- space TEXT,
28345
- content TEXT NOT NULL,
28346
- priority TEXT NOT NULL DEFAULT 'normal',
28347
- working_dir TEXT,
28348
- repository TEXT,
28349
- branch TEXT,
28350
- metadata TEXT,
28351
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
28352
- read_at TEXT
28353
- )
28354
- `);
28355
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id)");
28356
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent)");
28357
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at)");
28358
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
28359
- db.exec(`
28360
- CREATE TABLE IF NOT EXISTS projects (
28361
- id TEXT PRIMARY KEY,
28362
- name TEXT NOT NULL UNIQUE,
28363
- description TEXT,
28364
- path TEXT,
28365
- created_by TEXT NOT NULL,
28366
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
28367
- metadata TEXT,
28368
- tags TEXT,
28369
- status TEXT NOT NULL DEFAULT 'active',
28370
- repository TEXT,
28371
- settings TEXT
28372
- )
28373
- `);
28374
- db.exec("CREATE INDEX IF NOT EXISTS idx_projects_name ON projects(name)");
28375
- db.exec("CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status)");
28376
- db.exec(`
28377
- CREATE TABLE IF NOT EXISTS spaces (
28378
- name TEXT PRIMARY KEY,
28379
- description TEXT,
28380
- parent_id TEXT REFERENCES spaces(name),
28381
- project_id TEXT REFERENCES projects(id),
28382
- created_by TEXT NOT NULL,
28383
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
28384
- archived_at TEXT
28385
- )
28386
- `);
28387
- db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_parent ON spaces(parent_id)");
28388
- db.exec("CREATE INDEX IF NOT EXISTS idx_spaces_project ON spaces(project_id)");
28389
- db.exec(`
28390
- CREATE TABLE IF NOT EXISTS space_members (
28391
- space TEXT NOT NULL REFERENCES spaces(name),
28392
- agent TEXT NOT NULL,
28393
- joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
28394
- PRIMARY KEY (space, agent)
28395
- )
28396
- `);
28397
- db.exec(`
28398
- CREATE TABLE IF NOT EXISTS agent_presence (
28399
- agent TEXT PRIMARY KEY,
28400
- status TEXT NOT NULL DEFAULT 'online',
28401
- last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
28402
- metadata TEXT
28403
- )
28404
- `);
28405
- const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
28406
- const tableNames = existingTables.map((t) => t.name);
28407
- if (tableNames.includes("channels") && tableNames.includes("spaces")) {
28408
- const spaceCount = db.prepare("SELECT COUNT(*) as c FROM spaces").get().c;
28409
- const channelCount = db.prepare("SELECT COUNT(*) as c FROM channels").get().c;
28410
- if (channelCount > 0 && spaceCount === 0) {
28411
- db.exec("BEGIN");
28412
- try {
28413
- db.exec(`
28414
- INSERT OR IGNORE INTO spaces (name, description, created_by, created_at)
28415
- SELECT name, description, created_by, created_at FROM channels
28416
- `);
28417
- if (tableNames.includes("channel_members")) {
28418
- db.exec(`
28419
- INSERT OR IGNORE INTO space_members (space, agent, joined_at)
28420
- SELECT channel, agent, joined_at FROM channel_members
28421
- `);
28422
- }
28423
- db.exec("COMMIT");
28424
- } catch (e) {
28425
- db.exec("ROLLBACK");
28426
- throw e;
28427
- }
28428
- }
28429
- db.exec("DROP TABLE IF EXISTS channel_members");
28430
- db.exec("DROP TABLE IF EXISTS channels");
28431
- }
28432
- const msgCols = db.prepare("PRAGMA table_info(messages)").all();
28433
- const colNames = msgCols.map((c) => c.name);
28434
- if (colNames.includes("channel") && !colNames.includes("space")) {
28435
- db.exec("ALTER TABLE messages ADD COLUMN space TEXT");
28436
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_space ON messages(space)");
28437
- db.exec("UPDATE messages SET space = channel WHERE channel IS NOT NULL");
28438
- db.exec(`
28439
- UPDATE messages
28440
- SET session_id = 'space:' || substr(session_id, 9)
28441
- WHERE session_id LIKE 'channel:%'
28442
- `);
28443
- }
28444
- const spaceCols = db.prepare("PRAGMA table_info(spaces)").all();
28445
- const spaceColNames = spaceCols.map((c) => c.name);
28446
- if (!spaceColNames.includes("archived_at")) {
28447
- db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
28448
- }
28449
- const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
28450
- const colNames2 = msgCols2.map((c) => c.name);
28451
- if (!colNames2.includes("edited_at")) {
28452
- db.exec("ALTER TABLE messages ADD COLUMN edited_at TEXT");
28453
- }
28454
- if (!colNames2.includes("pinned_at")) {
28455
- db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
28456
- db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
28457
- }
28458
- return db;
28459
- }
28460
-
28461
28494
  // src/lib/messages.ts
28495
+ init_db();
28462
28496
  import { randomUUID } from "crypto";
28463
28497
  function parseMessage(row) {
28464
28498
  let metadata = null;
@@ -28471,7 +28505,8 @@ function parseMessage(row) {
28471
28505
  }
28472
28506
  return {
28473
28507
  ...row,
28474
- metadata
28508
+ metadata,
28509
+ blocking: !!row.blocking
28475
28510
  };
28476
28511
  }
28477
28512
  function sendMessage(opts) {
@@ -28480,12 +28515,13 @@ function sendMessage(opts) {
28480
28515
  const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID().slice(0, 8)}`);
28481
28516
  const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
28482
28517
  const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
28518
+ const blocking = opts.blocking ? 1 : 0;
28483
28519
  const stmt = db2.prepare(`
28484
- INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata)
28485
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
28520
+ INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
28521
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
28486
28522
  RETURNING *
28487
28523
  `);
28488
- 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);
28524
+ 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);
28489
28525
  return parseMessage(row);
28490
28526
  }
28491
28527
  function readMessages(opts = {}) {
@@ -28642,6 +28678,19 @@ function getPinnedMessages(opts) {
28642
28678
  const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY pinned_at DESC, id DESC ${limit}`).all(...params);
28643
28679
  return rows.map(parseMessage);
28644
28680
  }
28681
+ function getUnreadBlockers(agent) {
28682
+ const db2 = getDb();
28683
+ const rows = db2.prepare(`
28684
+ SELECT * FROM messages
28685
+ WHERE blocking = 1 AND read_at IS NULL
28686
+ AND (
28687
+ to_agent = ?
28688
+ OR space IN (SELECT space FROM space_members WHERE agent = ?)
28689
+ )
28690
+ ORDER BY created_at ASC, id ASC
28691
+ `).all(agent, agent);
28692
+ return rows.map(parseMessage);
28693
+ }
28645
28694
  function searchMessages(opts) {
28646
28695
  const db2 = getDb();
28647
28696
  const conditions = ["content LIKE ?"];
@@ -28665,6 +28714,7 @@ function searchMessages(opts) {
28665
28714
  }
28666
28715
 
28667
28716
  // src/lib/sessions.ts
28717
+ init_db();
28668
28718
  function listSessions(agent) {
28669
28719
  const db2 = getDb();
28670
28720
  const agentFilter = agent ? "WHERE from_agent = ? OR to_agent = ?" : "";
@@ -28695,6 +28745,7 @@ function listSessions(agent) {
28695
28745
  }
28696
28746
 
28697
28747
  // src/lib/spaces.ts
28748
+ init_db();
28698
28749
  function getSpaceDepth(spaceName) {
28699
28750
  const db2 = getDb();
28700
28751
  let depth = 0;
@@ -28868,6 +28919,7 @@ function unarchiveSpace(name) {
28868
28919
  }
28869
28920
 
28870
28921
  // src/lib/projects.ts
28922
+ init_db();
28871
28923
  import { randomUUID as randomUUID2 } from "crypto";
28872
28924
  function parseProject(row) {
28873
28925
  let metadata = null;
@@ -29389,6 +29441,16 @@ var AGENT_NAMES = [
29389
29441
  // src/lib/identity.ts
29390
29442
  var AGENT_ID_FILE = join2(homedir2(), ".conversations", "agent-id");
29391
29443
  var cachedAutoName = null;
29444
+ function isNameTaken(name) {
29445
+ try {
29446
+ const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
29447
+ const db2 = getDb2();
29448
+ const row = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(name);
29449
+ return !!row;
29450
+ } catch {
29451
+ return false;
29452
+ }
29453
+ }
29392
29454
  function getAutoName() {
29393
29455
  if (cachedAutoName)
29394
29456
  return cachedAutoName;
@@ -29399,7 +29461,14 @@ function getAutoName() {
29399
29461
  return name2;
29400
29462
  }
29401
29463
  } catch {}
29402
- const name = AGENT_NAMES[Math.floor(Math.random() * AGENT_NAMES.length)];
29464
+ const shuffled = [...AGENT_NAMES].sort(() => Math.random() - 0.5);
29465
+ let name = shuffled[0];
29466
+ for (const candidate of shuffled) {
29467
+ if (!isNameTaken(candidate)) {
29468
+ name = candidate;
29469
+ break;
29470
+ }
29471
+ }
29403
29472
  cachedAutoName = name;
29404
29473
  try {
29405
29474
  mkdirSync2(dirname2(AGENT_ID_FILE), { recursive: true });
@@ -29419,6 +29488,7 @@ function resolveIdentity(explicit) {
29419
29488
  }
29420
29489
 
29421
29490
  // src/lib/presence.ts
29491
+ init_db();
29422
29492
  var ONLINE_THRESHOLD_SECONDS = 60;
29423
29493
  function parsePresence(row) {
29424
29494
  let metadata = null;
@@ -29465,15 +29535,32 @@ function listAgents(opts) {
29465
29535
  const rows = db2.prepare(query).all(...params);
29466
29536
  return rows.map(parsePresence);
29467
29537
  }
29538
+ function removePresence(agent) {
29539
+ const db2 = getDb();
29540
+ const result = db2.prepare("DELETE FROM agent_presence WHERE agent = ?").run(agent);
29541
+ return result.changes > 0;
29542
+ }
29543
+ function renameAgent(oldName, newName) {
29544
+ const db2 = getDb();
29545
+ const existing = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(oldName);
29546
+ if (!existing)
29547
+ return false;
29548
+ const conflict = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(newName);
29549
+ if (conflict)
29550
+ throw new Error(`Agent "${newName}" already exists`);
29551
+ db2.prepare("UPDATE agent_presence SET agent = ? WHERE agent = ?").run(newName, oldName);
29552
+ return true;
29553
+ }
29468
29554
  // package.json
29469
29555
  var package_default = {
29470
29556
  name: "@hasna/conversations",
29471
- version: "0.1.4",
29557
+ version: "0.1.6",
29472
29558
  description: "Real-time CLI messaging for AI agents",
29473
29559
  type: "module",
29474
29560
  bin: {
29475
29561
  conversations: "bin/index.js",
29476
- "conversations-mcp": "bin/mcp.js"
29562
+ "conversations-mcp": "bin/mcp.js",
29563
+ "conversations-hook": "bin/hook.js"
29477
29564
  },
29478
29565
  exports: {
29479
29566
  ".": {
@@ -29491,7 +29578,7 @@ var package_default = {
29491
29578
  main: "./dist/index.js",
29492
29579
  types: "./dist/index.d.ts",
29493
29580
  scripts: {
29494
- 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",
29581
+ 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",
29495
29582
  "build:dashboard": "cd dashboard && bun install && bun run build",
29496
29583
  test: "bun test",
29497
29584
  dev: "bun run ./src/cli/index.tsx",
@@ -29557,9 +29644,10 @@ server.registerTool("send_message", {
29557
29644
  working_dir: exports_external.string().optional().describe("Working directory context"),
29558
29645
  repository: exports_external.string().optional().describe("Repository context"),
29559
29646
  branch: exports_external.string().optional().describe("Branch context"),
29560
- metadata: exports_external.string().optional().describe("JSON metadata string")
29647
+ metadata: exports_external.string().optional().describe("JSON metadata string"),
29648
+ blocking: exports_external.boolean().optional().describe("Send as a blocking message. Recipients must acknowledge before continuing.")
29561
29649
  }
29562
- }, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata }) => {
29650
+ }, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata, blocking }) => {
29563
29651
  const from = resolveIdentity(fromParam);
29564
29652
  let parsedMetadata;
29565
29653
  if (metadata) {
@@ -29581,7 +29669,8 @@ server.registerTool("send_message", {
29581
29669
  working_dir,
29582
29670
  repository,
29583
29671
  branch,
29584
- metadata: parsedMetadata
29672
+ metadata: parsedMetadata,
29673
+ blocking
29585
29674
  });
29586
29675
  return {
29587
29676
  content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
@@ -29768,9 +29857,10 @@ server.registerTool("send_to_space", {
29768
29857
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
29769
29858
  space: exports_external.string().describe("Space name"),
29770
29859
  content: exports_external.string().describe("Message content"),
29771
- priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority")
29860
+ priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority"),
29861
+ blocking: exports_external.boolean().optional().describe("Send as a blocking message. All space members must acknowledge.")
29772
29862
  }
29773
- }, async ({ from: fromParam, space, content, priority }) => {
29863
+ }, async ({ from: fromParam, space, content, priority, blocking }) => {
29774
29864
  const from = resolveIdentity(fromParam);
29775
29865
  const sp = getSpace(space);
29776
29866
  if (!sp) {
@@ -29785,7 +29875,8 @@ server.registerTool("send_to_space", {
29785
29875
  content,
29786
29876
  space,
29787
29877
  session_id: `space:${space}`,
29788
- priority
29878
+ priority,
29879
+ blocking
29789
29880
  });
29790
29881
  return {
29791
29882
  content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
@@ -30224,6 +30315,74 @@ server.registerTool("list_agents", {
30224
30315
  content: [{ type: "text", text: JSON.stringify(agents, null, 2) }]
30225
30316
  };
30226
30317
  });
30318
+ server.registerTool("get_blockers", {
30319
+ title: "Get Blockers",
30320
+ description: "Check for unread blocking messages targeting you. Returns messages that must be acknowledged before continuing.",
30321
+ inputSchema: {
30322
+ from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var.")
30323
+ }
30324
+ }, async ({ from: fromParam }) => {
30325
+ const agent = resolveIdentity(fromParam);
30326
+ const blockers = getUnreadBlockers(agent);
30327
+ return {
30328
+ content: [{ type: "text", text: JSON.stringify(blockers, null, 2) }]
30329
+ };
30330
+ });
30331
+ server.registerTool("remove_agent", {
30332
+ title: "Remove Agent",
30333
+ description: "Remove an agent from the presence list. Only the agent itself should remove its own presence.",
30334
+ inputSchema: {
30335
+ from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
30336
+ agent: exports_external.string().optional().describe("Agent to remove (defaults to yourself)")
30337
+ }
30338
+ }, async ({ from: fromParam, agent: targetAgent }) => {
30339
+ const self = resolveIdentity(fromParam);
30340
+ const agent = targetAgent?.trim() || self;
30341
+ const removed = removePresence(agent);
30342
+ if (!removed) {
30343
+ return {
30344
+ content: [{ type: "text", text: `Agent "${agent}" not found` }],
30345
+ isError: true
30346
+ };
30347
+ }
30348
+ return {
30349
+ content: [{ type: "text", text: JSON.stringify({ agent, removed: true }, null, 2) }]
30350
+ };
30351
+ });
30352
+ server.registerTool("rename_agent", {
30353
+ title: "Rename Agent",
30354
+ description: "Rename an agent in the presence list. By default renames yourself.",
30355
+ inputSchema: {
30356
+ from: exports_external.string().optional().describe("Your current agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
30357
+ new_name: exports_external.string().describe("The new name for the agent")
30358
+ }
30359
+ }, async ({ from: fromParam, new_name }) => {
30360
+ const oldName = resolveIdentity(fromParam);
30361
+ const newName = new_name.trim();
30362
+ if (!newName) {
30363
+ return {
30364
+ content: [{ type: "text", text: "New name cannot be empty" }],
30365
+ isError: true
30366
+ };
30367
+ }
30368
+ try {
30369
+ const renamed = renameAgent(oldName, newName);
30370
+ if (!renamed) {
30371
+ return {
30372
+ content: [{ type: "text", text: `Agent "${oldName}" not found in presence list` }],
30373
+ isError: true
30374
+ };
30375
+ }
30376
+ return {
30377
+ content: [{ type: "text", text: JSON.stringify({ old_name: oldName, new_name: newName, renamed: true }, null, 2) }]
30378
+ };
30379
+ } catch (e) {
30380
+ return {
30381
+ content: [{ type: "text", text: e.message }],
30382
+ isError: true
30383
+ };
30384
+ }
30385
+ });
30227
30386
  async function startMcpServer() {
30228
30387
  const transport = new StdioServerTransport;
30229
30388
  await server.connect(transport);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
package/dist/index.d.ts CHANGED
@@ -9,12 +9,12 @@
9
9
  * Or use the interactive TUI:
10
10
  * conversations
11
11
  */
12
- export { sendMessage, readMessages, markRead, markSessionRead, markSpaceRead, markAllRead, getMessageById, searchMessages, exportMessages, deleteMessage, editMessage, pinMessage, unpinMessage, getPinnedMessages, } from "./lib/messages.js";
12
+ export { sendMessage, readMessages, markRead, markSessionRead, markSpaceRead, markAllRead, getMessageById, searchMessages, exportMessages, deleteMessage, editMessage, pinMessage, unpinMessage, getPinnedMessages, getUnreadBlockers, } from "./lib/messages.js";
13
13
  export { listSessions, getSession, } from "./lib/sessions.js";
14
14
  export { createSpace, updateSpace, archiveSpace, unarchiveSpace, listSpaces, getSpace, joinSpace, leaveSpace, getSpaceMembers, isSpaceMember, getSpaceDepth, } from "./lib/spaces.js";
15
15
  export { createProject, listProjects, getProject, getProjectByName, updateProject, deleteProject, } from "./lib/projects.js";
16
16
  export { getDb, getDbPath, closeDb, } from "./lib/db.js";
17
17
  export { startPolling, useSpaceMessages, } from "./lib/poll.js";
18
18
  export { resolveIdentity, requireIdentity, } from "./lib/identity.js";
19
- export { heartbeat, getPresence, listAgents, removePresence, } from "./lib/presence.js";
19
+ export { heartbeat, getPresence, listAgents, removePresence, renameAgent, } from "./lib/presence.js";
20
20
  export type { Message, Session, Space, SpaceInfo, SpaceMember, Project, ProjectInfo, Priority, SendMessageOptions, ReadMessagesOptions, SearchMessagesOptions, AgentPresence, } from "./types.js";