@hasna/conversations 0.1.18 → 0.1.20

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/index.js CHANGED
@@ -2045,6 +2045,43 @@ function getDb() {
2045
2045
  if (!colNames2.includes("attachments")) {
2046
2046
  db.exec("ALTER TABLE messages ADD COLUMN attachments TEXT");
2047
2047
  }
2048
+ if (!colNames2.includes("reply_to")) {
2049
+ db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
2050
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
2051
+ }
2052
+ const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
2053
+ if (!ftsExists) {
2054
+ db.exec(`
2055
+ CREATE VIRTUAL TABLE messages_fts USING fts5(
2056
+ content, from_agent, to_agent, space,
2057
+ content_rowid='id', content='messages'
2058
+ )
2059
+ `);
2060
+ db.exec(`
2061
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
2062
+ SELECT id, content, from_agent, to_agent, space FROM messages
2063
+ `);
2064
+ db.exec(`
2065
+ CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON messages BEGIN
2066
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
2067
+ VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
2068
+ END
2069
+ `);
2070
+ db.exec(`
2071
+ CREATE TRIGGER IF NOT EXISTS messages_fts_delete AFTER DELETE ON messages BEGIN
2072
+ INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
2073
+ VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
2074
+ END
2075
+ `);
2076
+ db.exec(`
2077
+ CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE OF content ON messages BEGIN
2078
+ INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
2079
+ VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
2080
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
2081
+ VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
2082
+ END
2083
+ `);
2084
+ }
2048
2085
  return db;
2049
2086
  }
2050
2087
  function closeDb() {
@@ -2056,11 +2093,84 @@ function closeDb() {
2056
2093
  var db = null;
2057
2094
  var init_db = () => {};
2058
2095
 
2096
+ // src/lib/webhooks.ts
2097
+ import { readFileSync } from "fs";
2098
+ import { join as join2 } from "path";
2099
+ import { homedir as homedir2 } from "os";
2100
+ function getConfigPath() {
2101
+ return process.env.CONVERSATIONS_CONFIG_PATH || join2(homedir2(), ".conversations", "config.json");
2102
+ }
2103
+ function loadConfig() {
2104
+ const now = Date.now();
2105
+ if (cachedConfig && now - configLoadedAt < CONFIG_CACHE_MS)
2106
+ return cachedConfig;
2107
+ try {
2108
+ const raw = readFileSync(getConfigPath(), "utf-8");
2109
+ cachedConfig = JSON.parse(raw);
2110
+ configLoadedAt = now;
2111
+ return cachedConfig;
2112
+ } catch {
2113
+ cachedConfig = {};
2114
+ configLoadedAt = now;
2115
+ return cachedConfig;
2116
+ }
2117
+ }
2118
+ function matchesEvent(webhook, msg) {
2119
+ for (const event of webhook.events) {
2120
+ if (event === "dm" && !msg.space)
2121
+ return true;
2122
+ if (event === "blocker" && msg.blocking)
2123
+ return true;
2124
+ if (event === "space" && msg.space)
2125
+ return true;
2126
+ if (event === "mention" && webhook.agent && msg.content.includes(`@${webhook.agent}`))
2127
+ return true;
2128
+ }
2129
+ return false;
2130
+ }
2131
+ function fireWebhooks(msg) {
2132
+ const config = loadConfig();
2133
+ if (!config.webhooks || config.webhooks.length === 0)
2134
+ return;
2135
+ for (const webhook of config.webhooks) {
2136
+ if (webhook.agent && msg.to_agent !== webhook.agent && !msg.space)
2137
+ continue;
2138
+ if (!matchesEvent(webhook, msg))
2139
+ continue;
2140
+ fetch(webhook.url, {
2141
+ method: "POST",
2142
+ headers: { "Content-Type": "application/json" },
2143
+ body: JSON.stringify({
2144
+ id: msg.id,
2145
+ from: msg.from_agent,
2146
+ to: msg.to_agent,
2147
+ space: msg.space,
2148
+ content: msg.content,
2149
+ priority: msg.priority,
2150
+ blocking: msg.blocking,
2151
+ created_at: msg.created_at
2152
+ })
2153
+ }).catch(() => {});
2154
+ }
2155
+ }
2156
+ var cachedConfig = null, configLoadedAt = 0, CONFIG_CACHE_MS = 1e4;
2157
+ var init_webhooks = () => {};
2158
+
2059
2159
  // src/lib/messages.ts
2060
2160
  import { randomUUID } from "crypto";
2061
2161
  import { mkdirSync as mkdirSync2, copyFileSync, statSync } from "fs";
2062
- import { join as join2 } from "path";
2063
- import { homedir as homedir2 } from "os";
2162
+ import { join as join3 } from "path";
2163
+ import { homedir as homedir3 } from "os";
2164
+ function compactMessage(msg) {
2165
+ const result = {};
2166
+ for (const key of Object.keys(msg)) {
2167
+ const val = msg[key];
2168
+ if (val !== null && val !== undefined) {
2169
+ result[key] = val;
2170
+ }
2171
+ }
2172
+ return result;
2173
+ }
2064
2174
  function parseMessage(row) {
2065
2175
  let metadata = null;
2066
2176
  if (row.metadata) {
@@ -2082,13 +2192,14 @@ function parseMessage(row) {
2082
2192
  ...row,
2083
2193
  metadata,
2084
2194
  attachments,
2085
- blocking: !!row.blocking
2195
+ blocking: !!row.blocking,
2196
+ reply_to: row.reply_to || null
2086
2197
  };
2087
2198
  }
2088
2199
  function getAttachmentsDir() {
2089
2200
  if (process.env.CONVERSATIONS_ATTACHMENTS_DIR)
2090
2201
  return process.env.CONVERSATIONS_ATTACHMENTS_DIR;
2091
- return join2(homedir2(), ".conversations", "attachments");
2202
+ return join3(homedir3(), ".conversations", "attachments");
2092
2203
  }
2093
2204
  function guessMimeType(name) {
2094
2205
  const ext = name.split(".").pop()?.toLowerCase();
@@ -2124,19 +2235,20 @@ function sendMessage(opts) {
2124
2235
  const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
2125
2236
  const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
2126
2237
  const blocking = opts.blocking ? 1 : 0;
2238
+ const replyTo = opts.reply_to || null;
2127
2239
  const stmt = db2.prepare(`
2128
- INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
2129
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2240
+ INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
2241
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2130
2242
  RETURNING *
2131
2243
  `);
2132
- 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);
2244
+ 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, replyTo);
2133
2245
  const message = parseMessage(row);
2134
2246
  if (opts.attachments && opts.attachments.length > 0) {
2135
- const attachmentsDir = join2(getAttachmentsDir(), String(message.id));
2247
+ const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
2136
2248
  mkdirSync2(attachmentsDir, { recursive: true });
2137
2249
  const attachmentInfos = [];
2138
2250
  for (const att of opts.attachments) {
2139
- const destPath = join2(attachmentsDir, att.name);
2251
+ const destPath = join3(attachmentsDir, att.name);
2140
2252
  copyFileSync(att.source_path, destPath);
2141
2253
  const stat = statSync(destPath);
2142
2254
  attachmentInfos.push({
@@ -2150,6 +2262,7 @@ function sendMessage(opts) {
2150
2262
  db2.prepare("UPDATE messages SET attachments = ? WHERE id = ?").run(attachmentsJson, message.id);
2151
2263
  message.attachments = attachmentInfos;
2152
2264
  }
2265
+ fireWebhooks(message);
2153
2266
  return message;
2154
2267
  }
2155
2268
  function readMessages(opts = {}) {
@@ -2184,10 +2297,13 @@ function readMessages(opts = {}) {
2184
2297
  conditions.push("read_at IS NULL");
2185
2298
  }
2186
2299
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2187
- const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? `LIMIT ${Math.floor(opts.limit)}` : "";
2300
+ const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
2188
2301
  const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
2189
- const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} ${limit}`).all(...params);
2190
- return rows.map(parseMessage);
2302
+ const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
2303
+ const messages = rows.map(parseMessage);
2304
+ if (opts.compact)
2305
+ return messages.map(compactMessage);
2306
+ return messages;
2191
2307
  }
2192
2308
  function markRead(ids, reader) {
2193
2309
  const db2 = getDb();
@@ -2333,6 +2449,33 @@ function getUnreadBlockers(agent) {
2333
2449
  }
2334
2450
  function searchMessages(opts) {
2335
2451
  const db2 = getDb();
2452
+ const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
2453
+ try {
2454
+ const ftsConditions = [];
2455
+ const ftsParams = [];
2456
+ const words = opts.query.trim().split(/\s+/).filter(Boolean);
2457
+ const ftsQuery = words.map((w) => `"${w.replace(/"/g, '""')}"`).join(" ");
2458
+ ftsConditions.push("messages_fts MATCH ?");
2459
+ ftsParams.push(ftsQuery);
2460
+ let extraWhere = "";
2461
+ if (opts.space) {
2462
+ extraWhere += " AND m.space = ?";
2463
+ ftsParams.push(opts.space);
2464
+ }
2465
+ if (opts.from) {
2466
+ extraWhere += " AND m.from_agent = ?";
2467
+ ftsParams.push(opts.from);
2468
+ }
2469
+ if (opts.to) {
2470
+ extraWhere += " AND m.to_agent = ?";
2471
+ ftsParams.push(opts.to);
2472
+ }
2473
+ const rows2 = db2.prepare(`SELECT m.* FROM messages m
2474
+ JOIN messages_fts ON messages_fts.rowid = m.id
2475
+ WHERE ${ftsConditions.join(" AND ")}${extraWhere}
2476
+ ORDER BY m.created_at DESC, m.id DESC LIMIT ${limit}`).all(...ftsParams);
2477
+ return rows2.map(parseMessage);
2478
+ } catch {}
2336
2479
  const conditions = ["content LIKE ?"];
2337
2480
  const params = [`%${opts.query}%`];
2338
2481
  if (opts.space) {
@@ -2347,13 +2490,13 @@ function searchMessages(opts) {
2347
2490
  conditions.push("to_agent = ?");
2348
2491
  params.push(opts.to);
2349
2492
  }
2350
- const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 50;
2351
2493
  const where = `WHERE ${conditions.join(" AND ")}`;
2352
2494
  const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
2353
2495
  return rows.map(parseMessage);
2354
2496
  }
2355
2497
  var init_messages = __esm(() => {
2356
2498
  init_db();
2499
+ init_webhooks();
2357
2500
  });
2358
2501
 
2359
2502
  // src/lib/sessions.ts
@@ -3090,9 +3233,9 @@ var init_names = __esm(() => {
3090
3233
  });
3091
3234
 
3092
3235
  // src/lib/identity.ts
3093
- import { readFileSync, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
3094
- import { join as join3, dirname as dirname2 } from "path";
3095
- import { homedir as homedir3 } from "os";
3236
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
3237
+ import { join as join4, dirname as dirname2 } from "path";
3238
+ import { homedir as homedir4 } from "os";
3096
3239
  function isNameTaken(name) {
3097
3240
  try {
3098
3241
  const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
@@ -3107,7 +3250,7 @@ function getAutoName() {
3107
3250
  if (cachedAutoName)
3108
3251
  return cachedAutoName;
3109
3252
  try {
3110
- const name2 = readFileSync(AGENT_ID_FILE, "utf-8").trim();
3253
+ const name2 = readFileSync2(AGENT_ID_FILE, "utf-8").trim();
3111
3254
  if (name2) {
3112
3255
  cachedAutoName = name2;
3113
3256
  return name2;
@@ -3141,7 +3284,7 @@ function resolveIdentity(explicit) {
3141
3284
  var AGENT_ID_FILE, cachedAutoName = null;
3142
3285
  var init_identity = __esm(() => {
3143
3286
  init_names();
3144
- AGENT_ID_FILE = join3(homedir3(), ".conversations", "agent-id");
3287
+ AGENT_ID_FILE = join4(homedir4(), ".conversations", "agent-id");
3145
3288
  });
3146
3289
 
3147
3290
  // src/lib/presence.ts
@@ -3216,6 +3359,52 @@ var init_presence = __esm(() => {
3216
3359
  init_db();
3217
3360
  });
3218
3361
 
3362
+ // src/lib/terminal-markdown.ts
3363
+ var exports_terminal_markdown = {};
3364
+ __export(exports_terminal_markdown, {
3365
+ renderInline: () => renderInline,
3366
+ renderContent: () => renderContent
3367
+ });
3368
+ import chalk from "chalk";
3369
+ var renderInline = (text) => {
3370
+ return text.replace(/`([^`]+)`/g, (_, code) => chalk.bgGray.white(` ${code} `)).replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => chalk.bold.italic(t)).replace(/\*\*(.+?)\*\*/g, (_, t) => chalk.bold(t)).replace(/\*(.+?)\*/g, (_, t) => chalk.italic(t)).replace(/~~(.+?)~~/g, (_, t) => chalk.strikethrough(t));
3371
+ }, renderContent = (content) => {
3372
+ const lines = content.split(`
3373
+ `);
3374
+ const rendered = [];
3375
+ for (const line of lines) {
3376
+ let l = line;
3377
+ const h = l.match(/^(#{1,3})\s+(.+)/);
3378
+ if (h) {
3379
+ rendered.push(chalk.bold(h[2]));
3380
+ continue;
3381
+ }
3382
+ if (/^\s*[-*+]\s/.test(l)) {
3383
+ rendered.push(" " + chalk.dim("\u2022") + " " + renderInline(l.replace(/^\s*[-*+]\s/, "")));
3384
+ continue;
3385
+ }
3386
+ const ol = l.match(/^\s*(\d+)[.)]\s(.*)/);
3387
+ if (ol) {
3388
+ rendered.push(" " + chalk.dim(ol[1] + ".") + " " + renderInline(ol[2]));
3389
+ continue;
3390
+ }
3391
+ if (l.startsWith(">")) {
3392
+ rendered.push(chalk.dim(" \u2502 ") + chalk.italic(renderInline(l.replace(/^>\s?/, ""))));
3393
+ continue;
3394
+ }
3395
+ if (l.trimStart().startsWith("```"))
3396
+ continue;
3397
+ if (l.trim() === "") {
3398
+ rendered.push("");
3399
+ continue;
3400
+ }
3401
+ rendered.push(renderInline(l));
3402
+ }
3403
+ return rendered.join(`
3404
+ `);
3405
+ };
3406
+ var init_terminal_markdown = () => {};
3407
+
3219
3408
  // src/lib/poll.ts
3220
3409
  var exports_poll = {};
3221
3410
  __export(exports_poll, {
@@ -3314,7 +3503,7 @@ var init_poll = __esm(() => {
3314
3503
  var require_package = __commonJS((exports, module) => {
3315
3504
  module.exports = {
3316
3505
  name: "@hasna/conversations",
3317
- version: "0.1.18",
3506
+ version: "0.1.20",
3318
3507
  description: "Real-time CLI messaging for AI agents",
3319
3508
  type: "module",
3320
3509
  bin: {
@@ -32286,9 +32475,9 @@ var init_mcp2 = __esm(() => {
32286
32475
  });
32287
32476
  server.registerTool("send_message", {
32288
32477
  title: "Send Message",
32289
- description: "Send a direct message to another agent. Pass 'from' to identify yourself, or it falls back to CONVERSATIONS_AGENT_ID env var.",
32478
+ description: "Send a direct message to another agent.",
32290
32479
  inputSchema: {
32291
- from: exports_external.string().optional().describe("Your agent ID (e.g. 'claude-1', 'assistant'). Falls back to CONVERSATIONS_AGENT_ID env var."),
32480
+ from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32292
32481
  to: exports_external.string().describe("Recipient agent ID"),
32293
32482
  content: exports_external.string().describe("Message content"),
32294
32483
  session_id: exports_external.string().optional().describe("Session ID (auto-generated if omitted)"),
@@ -32297,7 +32486,7 @@ var init_mcp2 = __esm(() => {
32297
32486
  repository: exports_external.string().optional().describe("Repository context"),
32298
32487
  branch: exports_external.string().optional().describe("Branch context"),
32299
32488
  metadata: exports_external.string().optional().describe("JSON metadata string"),
32300
- blocking: exports_external.boolean().optional().describe("Send as a blocking message. Recipients must acknowledge before continuing.")
32489
+ blocking: exports_external.boolean().optional().describe("Blocking message \u2014 recipients must acknowledge before continuing")
32301
32490
  }
32302
32491
  }, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata, blocking }) => {
32303
32492
  const from = resolveIdentity(fromParam);
@@ -32307,7 +32496,7 @@ var init_mcp2 = __esm(() => {
32307
32496
  parsedMetadata = JSON.parse(metadata);
32308
32497
  } catch {
32309
32498
  return {
32310
- content: [{ type: "text", text: "Invalid metadata JSON." }],
32499
+ content: [{ type: "text", text: "invalid JSON" }],
32311
32500
  isError: true
32312
32501
  };
32313
32502
  }
@@ -32330,15 +32519,15 @@ var init_mcp2 = __esm(() => {
32330
32519
  });
32331
32520
  server.registerTool("read_messages", {
32332
32521
  title: "Read Messages",
32333
- description: "Read messages with optional filters. Returns messages sorted by time.",
32522
+ description: "Read messages with filters, newest first.",
32334
32523
  inputSchema: {
32335
32524
  session_id: exports_external.string().optional().describe("Filter by session ID"),
32336
- from: exports_external.string().optional().describe("Filter by sender agent ID"),
32337
- to: exports_external.string().optional().describe("Filter by recipient agent ID"),
32525
+ from: exports_external.string().optional().describe("Filter by sender"),
32526
+ to: exports_external.string().optional().describe("Filter by recipient"),
32338
32527
  space: exports_external.string().optional().describe("Filter by space name"),
32339
- since: exports_external.string().optional().describe("Messages after this ISO timestamp"),
32340
- limit: exports_external.number().optional().describe("Max messages to return"),
32341
- unread_only: exports_external.boolean().optional().describe("Only return unread messages")
32528
+ since: exports_external.string().optional().describe("ISO timestamp lower bound"),
32529
+ limit: exports_external.number().optional().describe("Max messages to return (default 20)"),
32530
+ unread_only: exports_external.boolean().optional().describe("Only unread messages")
32342
32531
  }
32343
32532
  }, async (opts) => {
32344
32533
  const messages = readMessages(opts);
@@ -32348,7 +32537,7 @@ var init_mcp2 = __esm(() => {
32348
32537
  });
32349
32538
  server.registerTool("list_sessions", {
32350
32539
  title: "List Sessions",
32351
- description: "List conversation sessions, optionally filtered to a specific agent.",
32540
+ description: "List sessions, optionally filtered by agent.",
32352
32541
  inputSchema: {
32353
32542
  agent: exports_external.string().optional().describe("Filter sessions involving this agent")
32354
32543
  }
@@ -32360,7 +32549,7 @@ var init_mcp2 = __esm(() => {
32360
32549
  });
32361
32550
  server.registerTool("reply", {
32362
32551
  title: "Reply to Message",
32363
- description: "Reply to a message by its ID. Automatically uses the same session and sends to the original sender.",
32552
+ description: "Reply to a message (same session, original sender).",
32364
32553
  inputSchema: {
32365
32554
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32366
32555
  message_id: exports_external.number().describe("ID of the message to reply to"),
@@ -32392,7 +32581,7 @@ var init_mcp2 = __esm(() => {
32392
32581
  });
32393
32582
  server.registerTool("mark_read", {
32394
32583
  title: "Mark Read",
32395
- description: "Mark message IDs as read for the current agent. Set 'all' to true to mark all unread messages as read.",
32584
+ description: "Mark messages as read. Provide IDs or set 'all' to true.",
32396
32585
  inputSchema: {
32397
32586
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32398
32587
  ids: exports_external.array(exports_external.number()).optional().describe("Message IDs to mark as read"),
@@ -32407,7 +32596,7 @@ var init_mcp2 = __esm(() => {
32407
32596
  count = markRead(ids, agent);
32408
32597
  } else {
32409
32598
  return {
32410
- content: [{ type: "text", text: "Provide message IDs or set 'all' to true." }],
32599
+ content: [{ type: "text", text: "provide ids or set all=true" }],
32411
32600
  isError: true
32412
32601
  };
32413
32602
  }
@@ -32417,13 +32606,13 @@ var init_mcp2 = __esm(() => {
32417
32606
  });
32418
32607
  server.registerTool("search_messages", {
32419
32608
  title: "Search Messages",
32420
- description: "Full-text search across message content. Returns matching messages ordered by newest first.",
32609
+ description: "Full-text search across message content, newest first.",
32421
32610
  inputSchema: {
32422
- query: exports_external.string().describe("Search query string"),
32423
- space: exports_external.string().optional().describe("Filter by space name"),
32424
- from: exports_external.string().optional().describe("Filter by sender agent ID"),
32425
- to: exports_external.string().optional().describe("Filter by recipient agent ID"),
32426
- limit: exports_external.number().optional().describe("Max results to return (default 50)")
32611
+ query: exports_external.string().describe("Search query"),
32612
+ space: exports_external.string().optional().describe("Filter by space"),
32613
+ from: exports_external.string().optional().describe("Filter by sender"),
32614
+ to: exports_external.string().optional().describe("Filter by recipient"),
32615
+ limit: exports_external.number().optional().describe("Max results (default 20)")
32427
32616
  }
32428
32617
  }, async ({ query, space, from, to, limit }) => {
32429
32618
  const messages = searchMessages({ query, space, from, to, limit });
@@ -32435,11 +32624,11 @@ var init_mcp2 = __esm(() => {
32435
32624
  title: "Export Messages",
32436
32625
  description: "Export messages as JSON or CSV with optional filters.",
32437
32626
  inputSchema: {
32438
- space: exports_external.string().optional().describe("Filter by space name"),
32627
+ space: exports_external.string().optional().describe("Filter by space"),
32439
32628
  session_id: exports_external.string().optional().describe("Filter by session ID"),
32440
- from: exports_external.string().optional().describe("Filter by sender agent ID"),
32441
- since: exports_external.string().optional().describe("Messages after this ISO date"),
32442
- until: exports_external.string().optional().describe("Messages before this ISO date"),
32629
+ from: exports_external.string().optional().describe("Filter by sender"),
32630
+ since: exports_external.string().optional().describe("ISO date lower bound"),
32631
+ until: exports_external.string().optional().describe("ISO date upper bound"),
32443
32632
  format: exports_external.enum(["json", "csv"]).optional().describe("Output format (default: json)")
32444
32633
  }
32445
32634
  }, async ({ space, session_id, from, since, until, format }) => {
@@ -32450,13 +32639,13 @@ var init_mcp2 = __esm(() => {
32450
32639
  });
32451
32640
  server.registerTool("create_space", {
32452
32641
  title: "Create Space",
32453
- description: "Create a new space. The creator is auto-joined. Spaces can be nested (max 3 levels) and associated with a project.",
32642
+ description: "Create a space. Auto-joined. Supports nesting and projects.",
32454
32643
  inputSchema: {
32455
32644
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32456
- name: exports_external.string().describe("Space name (e.g. 'deployments', 'code-review')"),
32645
+ name: exports_external.string().describe("Space name"),
32457
32646
  description: exports_external.string().optional().describe("Space description"),
32458
- parent_id: exports_external.string().optional().describe("Parent space name for nesting (max 3 levels deep)"),
32459
- project_id: exports_external.string().optional().describe("Project ID to associate this space with")
32647
+ parent_id: exports_external.string().optional().describe("Parent space name (max 3 levels deep)"),
32648
+ project_id: exports_external.string().optional().describe("Project ID to associate with")
32460
32649
  }
32461
32650
  }, async ({ from: fromParam, name, description, parent_id, project_id }) => {
32462
32651
  const agent = resolveIdentity(fromParam);
@@ -32468,7 +32657,7 @@ var init_mcp2 = __esm(() => {
32468
32657
  } catch (e) {
32469
32658
  if (e.message?.includes("UNIQUE constraint")) {
32470
32659
  return {
32471
- content: [{ type: "text", text: `Space #${name} already exists` }],
32660
+ content: [{ type: "text", text: `space "${name}" already exists` }],
32472
32661
  isError: true
32473
32662
  };
32474
32663
  }
@@ -32480,11 +32669,11 @@ var init_mcp2 = __esm(() => {
32480
32669
  });
32481
32670
  server.registerTool("list_spaces", {
32482
32671
  title: "List Spaces",
32483
- description: "List all available spaces with member and message counts. Can filter by project or parent. Archived spaces are excluded by default.",
32672
+ description: "List spaces with member/message counts.",
32484
32673
  inputSchema: {
32485
32674
  project_id: exports_external.string().optional().describe("Filter by project ID"),
32486
- parent_id: exports_external.string().optional().describe("Filter by parent space name. Use 'null' for top-level only."),
32487
- include_archived: exports_external.boolean().optional().describe("Include archived spaces (default: false)")
32675
+ parent_id: exports_external.string().optional().describe("Filter by parent space. Use 'null' for top-level only."),
32676
+ include_archived: exports_external.boolean().optional().describe("Include archived spaces")
32488
32677
  }
32489
32678
  }, async ({ project_id, parent_id, include_archived }) => {
32490
32679
  const opts = {};
@@ -32510,14 +32699,14 @@ var init_mcp2 = __esm(() => {
32510
32699
  space: exports_external.string().describe("Space name"),
32511
32700
  content: exports_external.string().describe("Message content"),
32512
32701
  priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority"),
32513
- blocking: exports_external.boolean().optional().describe("Send as a blocking message. All space members must acknowledge.")
32702
+ blocking: exports_external.boolean().optional().describe("Blocking message \u2014 all space members must acknowledge")
32514
32703
  }
32515
32704
  }, async ({ from: fromParam, space, content, priority, blocking }) => {
32516
32705
  const from = resolveIdentity(fromParam);
32517
32706
  const sp = getSpace(space);
32518
32707
  if (!sp) {
32519
32708
  return {
32520
- content: [{ type: "text", text: `Space #${space} not found` }],
32709
+ content: [{ type: "text", text: `space "${space}" not found` }],
32521
32710
  isError: true
32522
32711
  };
32523
32712
  }
@@ -32539,7 +32728,7 @@ var init_mcp2 = __esm(() => {
32539
32728
  description: "Read messages from a space.",
32540
32729
  inputSchema: {
32541
32730
  space: exports_external.string().describe("Space name"),
32542
- since: exports_external.string().optional().describe("Messages after this ISO timestamp"),
32731
+ since: exports_external.string().optional().describe("ISO timestamp lower bound"),
32543
32732
  limit: exports_external.number().optional().describe("Max messages to return")
32544
32733
  }
32545
32734
  }, async ({ space, since, limit }) => {
@@ -32560,7 +32749,7 @@ var init_mcp2 = __esm(() => {
32560
32749
  const ok = joinSpace(space, agent);
32561
32750
  if (!ok) {
32562
32751
  return {
32563
- content: [{ type: "text", text: `Space #${space} not found` }],
32752
+ content: [{ type: "text", text: `space "${space}" not found` }],
32564
32753
  isError: true
32565
32754
  };
32566
32755
  }
@@ -32584,12 +32773,12 @@ var init_mcp2 = __esm(() => {
32584
32773
  });
32585
32774
  server.registerTool("update_space", {
32586
32775
  title: "Update Space",
32587
- description: "Update a space's description, parent, or project association.",
32776
+ description: "Update a space's description, parent, or project.",
32588
32777
  inputSchema: {
32589
- name: exports_external.string().describe("Space name to update"),
32778
+ name: exports_external.string().describe("Space name"),
32590
32779
  description: exports_external.string().optional().describe("New description"),
32591
- parent_id: exports_external.string().optional().describe("New parent space name (use 'null' to remove parent)"),
32592
- project_id: exports_external.string().optional().describe("New project ID (use 'null' to remove project)")
32780
+ parent_id: exports_external.string().optional().describe("New parent space (use 'null' to remove)"),
32781
+ project_id: exports_external.string().optional().describe("New project ID (use 'null' to remove)")
32593
32782
  }
32594
32783
  }, async ({ name, description, parent_id, project_id }) => {
32595
32784
  const updates = {};
@@ -32613,7 +32802,7 @@ var init_mcp2 = __esm(() => {
32613
32802
  });
32614
32803
  server.registerTool("archive_space", {
32615
32804
  title: "Archive Space",
32616
- description: "Archive a space. Archived spaces are hidden from list by default.",
32805
+ description: "Archive a space. Hidden from list by default.",
32617
32806
  inputSchema: {
32618
32807
  name: exports_external.string().describe("Space name to archive")
32619
32808
  }
@@ -32651,16 +32840,16 @@ var init_mcp2 = __esm(() => {
32651
32840
  });
32652
32841
  server.registerTool("create_project", {
32653
32842
  title: "Create Project",
32654
- description: "Create a new project. Projects organize spaces and provide context for agent collaboration.",
32843
+ description: "Create a project for spaces and agent collaboration.",
32655
32844
  inputSchema: {
32656
32845
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32657
32846
  name: exports_external.string().describe("Project name (unique)"),
32658
32847
  description: exports_external.string().optional().describe("Project description"),
32659
- path: exports_external.string().optional().describe("Absolute path to project on disk"),
32848
+ path: exports_external.string().optional().describe("Absolute path on disk"),
32660
32849
  repository: exports_external.string().optional().describe("Repository URL"),
32661
- tags: exports_external.string().optional().describe(`JSON array of tags (e.g. '["backend", "api"]')`),
32662
- metadata: exports_external.string().optional().describe("JSON metadata string"),
32663
- settings: exports_external.string().optional().describe("JSON settings string")
32850
+ tags: exports_external.string().optional().describe("JSON array of tags"),
32851
+ metadata: exports_external.string().optional().describe("JSON metadata"),
32852
+ settings: exports_external.string().optional().describe("JSON settings")
32664
32853
  }
32665
32854
  }, async ({ from: fromParam, name, description, path, repository, tags, metadata, settings }) => {
32666
32855
  const agent = resolveIdentity(fromParam);
@@ -32670,7 +32859,7 @@ var init_mcp2 = __esm(() => {
32670
32859
  parsedTags = JSON.parse(tags);
32671
32860
  } catch {
32672
32861
  return {
32673
- content: [{ type: "text", text: "Invalid tags JSON. Expected array of strings." }],
32862
+ content: [{ type: "text", text: "invalid tags JSON (expected array)" }],
32674
32863
  isError: true
32675
32864
  };
32676
32865
  }
@@ -32681,7 +32870,7 @@ var init_mcp2 = __esm(() => {
32681
32870
  parsedMetadata = JSON.parse(metadata);
32682
32871
  } catch {
32683
32872
  return {
32684
- content: [{ type: "text", text: "Invalid metadata JSON." }],
32873
+ content: [{ type: "text", text: "invalid JSON" }],
32685
32874
  isError: true
32686
32875
  };
32687
32876
  }
@@ -32692,7 +32881,7 @@ var init_mcp2 = __esm(() => {
32692
32881
  parsedSettings = JSON.parse(settings);
32693
32882
  } catch {
32694
32883
  return {
32695
- content: [{ type: "text", text: "Invalid settings JSON." }],
32884
+ content: [{ type: "text", text: "invalid JSON" }],
32696
32885
  isError: true
32697
32886
  };
32698
32887
  }
@@ -32714,7 +32903,7 @@ var init_mcp2 = __esm(() => {
32714
32903
  } catch (e) {
32715
32904
  if (e.message?.includes("UNIQUE constraint")) {
32716
32905
  return {
32717
- content: [{ type: "text", text: `Project "${name}" already exists` }],
32906
+ content: [{ type: "text", text: `project "${name}" already exists` }],
32718
32907
  isError: true
32719
32908
  };
32720
32909
  }
@@ -32728,7 +32917,7 @@ var init_mcp2 = __esm(() => {
32728
32917
  title: "List Projects",
32729
32918
  description: "List all registered projects.",
32730
32919
  inputSchema: {
32731
- status: exports_external.enum(["active", "archived"]).optional().describe("Filter by project status")
32920
+ status: exports_external.enum(["active", "archived"]).optional().describe("Filter by status")
32732
32921
  }
32733
32922
  }, async ({ status }) => {
32734
32923
  const projects = listProjects(status ? { status } : undefined);
@@ -32749,7 +32938,7 @@ var init_mcp2 = __esm(() => {
32749
32938
  }
32750
32939
  if (!project) {
32751
32940
  return {
32752
- content: [{ type: "text", text: `Project "${id}" not found` }],
32941
+ content: [{ type: "text", text: `project "${id}" not found` }],
32753
32942
  isError: true
32754
32943
  };
32755
32944
  }
@@ -32762,14 +32951,14 @@ var init_mcp2 = __esm(() => {
32762
32951
  description: "Update a project's fields.",
32763
32952
  inputSchema: {
32764
32953
  id: exports_external.string().describe("Project ID (UUID)"),
32765
- name: exports_external.string().optional().describe("New project name"),
32954
+ name: exports_external.string().optional().describe("New name"),
32766
32955
  description: exports_external.string().optional().describe("New description"),
32767
32956
  path: exports_external.string().optional().describe("New path"),
32768
32957
  status: exports_external.enum(["active", "archived"]).optional().describe("New status"),
32769
32958
  repository: exports_external.string().optional().describe("New repository URL"),
32770
32959
  tags: exports_external.string().optional().describe("JSON array of tags"),
32771
- metadata: exports_external.string().optional().describe("JSON metadata string"),
32772
- settings: exports_external.string().optional().describe("JSON settings string")
32960
+ metadata: exports_external.string().optional().describe("JSON metadata"),
32961
+ settings: exports_external.string().optional().describe("JSON settings")
32773
32962
  }
32774
32963
  }, async ({ id, name, description, path, status, repository, tags, metadata, settings }) => {
32775
32964
  const updates = {};
@@ -32788,7 +32977,7 @@ var init_mcp2 = __esm(() => {
32788
32977
  updates.tags = JSON.parse(tags);
32789
32978
  } catch {
32790
32979
  return {
32791
- content: [{ type: "text", text: "Invalid tags JSON." }],
32980
+ content: [{ type: "text", text: "invalid tags JSON" }],
32792
32981
  isError: true
32793
32982
  };
32794
32983
  }
@@ -32798,7 +32987,7 @@ var init_mcp2 = __esm(() => {
32798
32987
  updates.metadata = JSON.parse(metadata);
32799
32988
  } catch {
32800
32989
  return {
32801
- content: [{ type: "text", text: "Invalid metadata JSON." }],
32990
+ content: [{ type: "text", text: "invalid JSON" }],
32802
32991
  isError: true
32803
32992
  };
32804
32993
  }
@@ -32808,7 +32997,7 @@ var init_mcp2 = __esm(() => {
32808
32997
  updates.settings = JSON.parse(settings);
32809
32998
  } catch {
32810
32999
  return {
32811
- content: [{ type: "text", text: "Invalid settings JSON." }],
33000
+ content: [{ type: "text", text: "invalid JSON" }],
32812
33001
  isError: true
32813
33002
  };
32814
33003
  }
@@ -32827,7 +33016,7 @@ var init_mcp2 = __esm(() => {
32827
33016
  });
32828
33017
  server.registerTool("delete_project", {
32829
33018
  title: "Delete Project",
32830
- description: "Delete a project permanently. Fails if spaces still reference it.",
33019
+ description: "Delete a project permanently. Fails if spaces reference it.",
32831
33020
  inputSchema: {
32832
33021
  id: exports_external.string().describe("Project ID (UUID)")
32833
33022
  }
@@ -32836,7 +33025,7 @@ var init_mcp2 = __esm(() => {
32836
33025
  const deleted = deleteProject(id);
32837
33026
  if (!deleted) {
32838
33027
  return {
32839
- content: [{ type: "text", text: `Project "${id}" not found` }],
33028
+ content: [{ type: "text", text: `project "${id}" not found` }],
32840
33029
  isError: true
32841
33030
  };
32842
33031
  }
@@ -32852,7 +33041,7 @@ var init_mcp2 = __esm(() => {
32852
33041
  });
32853
33042
  server.registerTool("delete_message", {
32854
33043
  title: "Delete Message",
32855
- description: "Delete a message. Only the sender can delete their own messages.",
33044
+ description: "Delete a message. Sender only.",
32856
33045
  inputSchema: {
32857
33046
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32858
33047
  id: exports_external.number().describe("Message ID to delete")
@@ -32862,7 +33051,7 @@ var init_mcp2 = __esm(() => {
32862
33051
  const deleted = deleteMessage(id, agent);
32863
33052
  if (!deleted) {
32864
33053
  return {
32865
- content: [{ type: "text", text: `Message #${id} not found or not your message` }],
33054
+ content: [{ type: "text", text: `not found or forbidden` }],
32866
33055
  isError: true
32867
33056
  };
32868
33057
  }
@@ -32872,7 +33061,7 @@ var init_mcp2 = __esm(() => {
32872
33061
  });
32873
33062
  server.registerTool("edit_message", {
32874
33063
  title: "Edit Message",
32875
- description: "Edit a message's content. Only the sender can edit their own messages.",
33064
+ description: "Edit a message's content. Sender only.",
32876
33065
  inputSchema: {
32877
33066
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32878
33067
  id: exports_external.number().describe("Message ID to edit"),
@@ -32883,7 +33072,7 @@ var init_mcp2 = __esm(() => {
32883
33072
  const msg = editMessage(id, agent, content);
32884
33073
  if (!msg) {
32885
33074
  return {
32886
- content: [{ type: "text", text: `Message #${id} not found or not your message` }],
33075
+ content: [{ type: "text", text: `not found or forbidden` }],
32887
33076
  isError: true
32888
33077
  };
32889
33078
  }
@@ -32893,7 +33082,7 @@ var init_mcp2 = __esm(() => {
32893
33082
  });
32894
33083
  server.registerTool("pin_message", {
32895
33084
  title: "Pin Message",
32896
- description: "Pin a message. Pinned messages can be retrieved with get_pinned_messages.",
33085
+ description: "Pin a message in a space or session.",
32897
33086
  inputSchema: {
32898
33087
  id: exports_external.number().describe("Message ID to pin")
32899
33088
  }
@@ -32901,7 +33090,7 @@ var init_mcp2 = __esm(() => {
32901
33090
  const msg = pinMessage(id);
32902
33091
  if (!msg) {
32903
33092
  return {
32904
- content: [{ type: "text", text: `Message #${id} not found` }],
33093
+ content: [{ type: "text", text: `message #${id} not found` }],
32905
33094
  isError: true
32906
33095
  };
32907
33096
  }
@@ -32919,7 +33108,7 @@ var init_mcp2 = __esm(() => {
32919
33108
  const msg = unpinMessage(id);
32920
33109
  if (!msg) {
32921
33110
  return {
32922
- content: [{ type: "text", text: `Message #${id} not found` }],
33111
+ content: [{ type: "text", text: `message #${id} not found` }],
32923
33112
  isError: true
32924
33113
  };
32925
33114
  }
@@ -32929,9 +33118,9 @@ var init_mcp2 = __esm(() => {
32929
33118
  });
32930
33119
  server.registerTool("get_pinned_messages", {
32931
33120
  title: "Get Pinned Messages",
32932
- description: "Retrieve pinned messages, optionally filtered by space or session.",
33121
+ description: "Get pinned messages, filtered by space or session.",
32933
33122
  inputSchema: {
32934
- space: exports_external.string().optional().describe("Filter by space name"),
33123
+ space: exports_external.string().optional().describe("Filter by space"),
32935
33124
  session_id: exports_external.string().optional().describe("Filter by session ID"),
32936
33125
  limit: exports_external.number().optional().describe("Max messages to return")
32937
33126
  }
@@ -32943,7 +33132,7 @@ var init_mcp2 = __esm(() => {
32943
33132
  });
32944
33133
  server.registerTool("heartbeat", {
32945
33134
  title: "Heartbeat",
32946
- description: "Send a heartbeat to indicate agent is alive. Optionally set a status.",
33135
+ description: "Send heartbeat. Optionally set agent status.",
32947
33136
  inputSchema: {
32948
33137
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32949
33138
  status: exports_external.string().optional().describe("Agent status (e.g. 'online', 'busy', 'idle'). Defaults to 'online'.")
@@ -32957,9 +33146,9 @@ var init_mcp2 = __esm(() => {
32957
33146
  });
32958
33147
  server.registerTool("list_agents", {
32959
33148
  title: "List Agents",
32960
- description: "List all agents with their presence status. Returns agent name, status, last seen time, and whether they are online.",
33149
+ description: "List agents with presence status.",
32961
33150
  inputSchema: {
32962
- online_only: exports_external.boolean().optional().describe("Only return agents that are currently online (seen within last 60 seconds)")
33151
+ online_only: exports_external.boolean().optional().describe("Only return agents online within last 60s")
32963
33152
  }
32964
33153
  }, async ({ online_only }) => {
32965
33154
  const agents = listAgents({ online_only });
@@ -32969,7 +33158,7 @@ var init_mcp2 = __esm(() => {
32969
33158
  });
32970
33159
  server.registerTool("get_blockers", {
32971
33160
  title: "Get Blockers",
32972
- description: "Check for unread blocking messages targeting you. Returns messages that must be acknowledged before continuing.",
33161
+ description: "Check for unread blocking messages. Must acknowledge.",
32973
33162
  inputSchema: {
32974
33163
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var.")
32975
33164
  }
@@ -32982,7 +33171,7 @@ var init_mcp2 = __esm(() => {
32982
33171
  });
32983
33172
  server.registerTool("remove_agent", {
32984
33173
  title: "Remove Agent",
32985
- description: "Remove an agent from the presence list. Only the agent itself should remove its own presence.",
33174
+ description: "Remove an agent from the presence list.",
32986
33175
  inputSchema: {
32987
33176
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32988
33177
  agent: exports_external.string().optional().describe("Agent to remove (defaults to yourself)")
@@ -32993,7 +33182,7 @@ var init_mcp2 = __esm(() => {
32993
33182
  const removed = removePresence(agent);
32994
33183
  if (!removed) {
32995
33184
  return {
32996
- content: [{ type: "text", text: `Agent "${agent}" not found` }],
33185
+ content: [{ type: "text", text: `agent "${agent}" not found` }],
32997
33186
  isError: true
32998
33187
  };
32999
33188
  }
@@ -33003,7 +33192,7 @@ var init_mcp2 = __esm(() => {
33003
33192
  });
33004
33193
  server.registerTool("rename_agent", {
33005
33194
  title: "Rename Agent",
33006
- description: "Rename an agent in the presence list. By default renames yourself.",
33195
+ description: "Rename an agent in the presence list.",
33007
33196
  inputSchema: {
33008
33197
  from: exports_external.string().optional().describe("Your current agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
33009
33198
  new_name: exports_external.string().describe("The new name for the agent")
@@ -33013,7 +33202,7 @@ var init_mcp2 = __esm(() => {
33013
33202
  const newName = new_name.trim();
33014
33203
  if (!newName) {
33015
33204
  return {
33016
- content: [{ type: "text", text: "New name cannot be empty" }],
33205
+ content: [{ type: "text", text: "new name cannot be empty" }],
33017
33206
  isError: true
33018
33207
  };
33019
33208
  }
@@ -33021,7 +33210,7 @@ var init_mcp2 = __esm(() => {
33021
33210
  const renamed = renameAgent(oldName, newName);
33022
33211
  if (!renamed) {
33023
33212
  return {
33024
- content: [{ type: "text", text: `Agent "${oldName}" not found in presence list` }],
33213
+ content: [{ type: "text", text: `agent "${oldName}" not found` }],
33025
33214
  isError: true
33026
33215
  };
33027
33216
  }
@@ -33035,6 +33224,78 @@ var init_mcp2 = __esm(() => {
33035
33224
  };
33036
33225
  }
33037
33226
  });
33227
+ server.registerTool("search_tools", {
33228
+ title: "Search Tools",
33229
+ description: "List tool names, optionally filtered by keyword.",
33230
+ inputSchema: {
33231
+ query: exports_external.string().optional().describe("Keyword filter")
33232
+ }
33233
+ }, async ({ query }) => {
33234
+ const all = [
33235
+ "send_message",
33236
+ "read_messages",
33237
+ "list_sessions",
33238
+ "reply",
33239
+ "mark_read",
33240
+ "search_messages",
33241
+ "export_messages",
33242
+ "create_space",
33243
+ "list_spaces",
33244
+ "send_to_space",
33245
+ "read_space",
33246
+ "join_space",
33247
+ "leave_space",
33248
+ "update_space",
33249
+ "archive_space",
33250
+ "unarchive_space",
33251
+ "create_project",
33252
+ "list_projects",
33253
+ "get_project",
33254
+ "update_project",
33255
+ "delete_project",
33256
+ "delete_message",
33257
+ "edit_message",
33258
+ "pin_message",
33259
+ "unpin_message",
33260
+ "get_pinned_messages",
33261
+ "heartbeat",
33262
+ "list_agents",
33263
+ "get_blockers",
33264
+ "remove_agent",
33265
+ "rename_agent",
33266
+ "search_tools",
33267
+ "describe_tools"
33268
+ ];
33269
+ const q = query?.toLowerCase();
33270
+ const matches = q ? all.filter((n) => n.includes(q)) : all;
33271
+ return { content: [{ type: "text", text: matches.join(", ") }] };
33272
+ });
33273
+ server.registerTool("describe_tools", {
33274
+ title: "Describe Tools",
33275
+ description: "Get descriptions for specific tools by name.",
33276
+ inputSchema: {
33277
+ names: exports_external.array(exports_external.string()).describe("Tool names from search_tools")
33278
+ }
33279
+ }, async ({ names }) => {
33280
+ const descriptions = {
33281
+ send_message: "Send DM to agent. Params: to, content, from?, priority?",
33282
+ read_messages: "Read messages. Params: space?, from?, to?, unread_only?, limit?",
33283
+ list_sessions: "List sessions. Params: agent?",
33284
+ reply: "Reply to message. Params: id, content, from?",
33285
+ send_to_space: "Send message to space. Params: space, content, from?",
33286
+ read_space: "Read space messages. Params: space, limit?, since?",
33287
+ join_space: "Join a space. Params: space, from?",
33288
+ create_space: "Create space. Params: name, description?, parent_id?",
33289
+ list_spaces: "List spaces with counts. No required params.",
33290
+ heartbeat: "Send heartbeat. Params: from?, status?",
33291
+ list_agents: "List agents with presence. No required params.",
33292
+ get_blockers: "Check for blocking messages. Params: name?",
33293
+ search_messages: "Search messages. Params: query, space?, limit?"
33294
+ };
33295
+ const result = names.map((n) => `${n}: ${descriptions[n] || "See tool schema"}`).join(`
33296
+ `);
33297
+ return { content: [{ type: "text", text: result }] };
33298
+ });
33038
33299
  isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp.js") || process.argv[1]?.endsWith("mcp.ts");
33039
33300
  if (isDirectRun) {
33040
33301
  startMcpServer().catch((error48) => {
@@ -33049,7 +33310,7 @@ var exports_serve = {};
33049
33310
  __export(exports_serve, {
33050
33311
  startDashboardServer: () => startDashboardServer
33051
33312
  });
33052
- import { join as join4, resolve, sep } from "path";
33313
+ import { join as join5, resolve, sep } from "path";
33053
33314
  import { existsSync } from "fs";
33054
33315
  function securityHeaders(base) {
33055
33316
  const headers = new Headers(base);
@@ -33120,7 +33381,7 @@ function isSameOrigin(req) {
33120
33381
  function startDashboardServer(port = 0, host) {
33121
33382
  const resolvedPort = normalizePort(port, 0);
33122
33383
  const resolvedHost = normalizeHost(host ?? process.env.CONVERSATIONS_DASHBOARD_HOST);
33123
- const dashboardDist = join4(import.meta.dir, "../../dashboard/dist");
33384
+ const dashboardDist = join5(import.meta.dir, "../../dashboard/dist");
33124
33385
  const hasDist = existsSync(dashboardDist);
33125
33386
  const server2 = Bun.serve({
33126
33387
  port: resolvedPort,
@@ -33504,7 +33765,7 @@ function startDashboardServer(port = 0, host) {
33504
33765
  headers.set("Content-Type", file2.type);
33505
33766
  return new Response(file2, { headers });
33506
33767
  }
33507
- file2 = Bun.file(join4(dashboardDist, "index.html"));
33768
+ file2 = Bun.file(join5(dashboardDist, "index.html"));
33508
33769
  if (await file2.exists()) {
33509
33770
  const headers = securityHeaders();
33510
33771
  if (file2.type)
@@ -33560,7 +33821,8 @@ init_projects();
33560
33821
  init_db();
33561
33822
  init_identity();
33562
33823
  init_presence();
33563
- import chalk2 from "chalk";
33824
+ init_terminal_markdown();
33825
+ import chalk3 from "chalk";
33564
33826
  import { render } from "ink";
33565
33827
  import React8 from "react";
33566
33828
 
@@ -33571,7 +33833,7 @@ import { Box as Box6, Text as Text7, useApp, useInput as useInput5 } from "ink";
33571
33833
  // node_modules/ink-text-input/build/index.js
33572
33834
  import React, { useState, useEffect } from "react";
33573
33835
  import { Text, useInput } from "ink";
33574
- import chalk from "chalk";
33836
+ import chalk2 from "chalk";
33575
33837
  function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
33576
33838
  const [state, setState] = useState({
33577
33839
  cursorOffset: (originalValue || "").length,
@@ -33596,17 +33858,17 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
33596
33858
  const cursorActualWidth = highlightPastedText ? cursorWidth : 0;
33597
33859
  const value = mask ? mask.repeat(originalValue.length) : originalValue;
33598
33860
  let renderedValue = value;
33599
- let renderedPlaceholder = placeholder ? chalk.grey(placeholder) : undefined;
33861
+ let renderedPlaceholder = placeholder ? chalk2.grey(placeholder) : undefined;
33600
33862
  if (showCursor && focus) {
33601
- renderedPlaceholder = placeholder.length > 0 ? chalk.inverse(placeholder[0]) + chalk.grey(placeholder.slice(1)) : chalk.inverse(" ");
33602
- renderedValue = value.length > 0 ? "" : chalk.inverse(" ");
33863
+ renderedPlaceholder = placeholder.length > 0 ? chalk2.inverse(placeholder[0]) + chalk2.grey(placeholder.slice(1)) : chalk2.inverse(" ");
33864
+ renderedValue = value.length > 0 ? "" : chalk2.inverse(" ");
33603
33865
  let i = 0;
33604
33866
  for (const char of value) {
33605
- renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ? chalk.inverse(char) : char;
33867
+ renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ? chalk2.inverse(char) : char;
33606
33868
  i++;
33607
33869
  }
33608
33870
  if (value.length > 0 && cursorOffset === value.length) {
33609
- renderedValue += chalk.inverse(" ");
33871
+ renderedValue += chalk2.inverse(" ");
33610
33872
  }
33611
33873
  }
33612
33874
  useInput((input, key) => {
@@ -34507,15 +34769,15 @@ program2.command("send").description("Send a message to an agent").argument("<me
34507
34769
  const content = typeof message === "string" ? message : "";
34508
34770
  const session = typeof opts.session === "string" && opts.session.trim() ? opts.session.trim() : undefined;
34509
34771
  if (!from) {
34510
- console.error(chalk2.red("Sender identity is required."));
34772
+ console.error(chalk3.red("Sender identity is required."));
34511
34773
  process.exit(1);
34512
34774
  }
34513
34775
  if (!to) {
34514
- console.error(chalk2.red("Recipient is required."));
34776
+ console.error(chalk3.red("Recipient is required."));
34515
34777
  process.exit(1);
34516
34778
  }
34517
34779
  if (!content.trim()) {
34518
- console.error(chalk2.red("Message content cannot be empty."));
34780
+ console.error(chalk3.red("Message content cannot be empty."));
34519
34781
  process.exit(1);
34520
34782
  }
34521
34783
  let metadata;
@@ -34523,7 +34785,7 @@ program2.command("send").description("Send a message to an agent").argument("<me
34523
34785
  try {
34524
34786
  metadata = JSON.parse(opts.metadata);
34525
34787
  } catch {
34526
- console.error(chalk2.red("Invalid --metadata JSON."));
34788
+ console.error(chalk3.red("Invalid --metadata JSON."));
34527
34789
  process.exit(1);
34528
34790
  }
34529
34791
  }
@@ -34542,7 +34804,7 @@ program2.command("send").description("Send a message to an agent").argument("<me
34542
34804
  if (opts.json) {
34543
34805
  console.log(JSON.stringify(msg, null, 2));
34544
34806
  } else {
34545
- console.log(chalk2.green(`Message sent`) + chalk2.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
34807
+ console.log(chalk3.green(`Message sent`) + chalk3.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
34546
34808
  }
34547
34809
  closeDb();
34548
34810
  });
@@ -34572,15 +34834,20 @@ program2.command("read").description("Read messages").option("--session <id>", "
34572
34834
  console.log(JSON.stringify(messages, null, 2));
34573
34835
  } else {
34574
34836
  if (messages.length === 0) {
34575
- console.log(chalk2.dim("No messages found."));
34837
+ console.log(chalk3.dim("No messages found."));
34576
34838
  } else {
34577
34839
  for (const msg of messages) {
34578
- const time3 = chalk2.dim(msg.created_at.slice(11, 19));
34579
- const from = chalk2.cyan(msg.from_agent);
34580
- const to = msg.space ? chalk2.magenta(`#${msg.space}`) : chalk2.yellow(msg.to_agent);
34581
- const priority = msg.priority !== "normal" ? chalk2.red(` [${msg.priority}]`) : "";
34582
- const unread = !msg.read_at ? chalk2.green(" *") : "";
34583
- console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}: ${msg.content}`);
34840
+ const time3 = chalk3.dim(msg.created_at.slice(11, 19));
34841
+ const from = chalk3.cyan(msg.from_agent);
34842
+ const to = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow(msg.to_agent);
34843
+ const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
34844
+ const unread = !msg.read_at ? chalk3.green(" *") : "";
34845
+ console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}`);
34846
+ const rendered = renderContent(msg.content);
34847
+ const indented = rendered.split(`
34848
+ `).map((l) => " " + l).join(`
34849
+ `);
34850
+ console.log(indented);
34584
34851
  }
34585
34852
  }
34586
34853
  }
@@ -34589,7 +34856,7 @@ program2.command("read").description("Read messages").option("--session <id>", "
34589
34856
  program2.command("search").description("Search messages by content").argument("<query>", "Search query string").option("--space <name>", "Filter by space").option("--from <agent>", "Filter by sender").option("--to <agent>", "Filter by recipient").option("--limit <n>", "Max results to return", parseInt).option("--json", "Output as JSON").action((query, opts) => {
34590
34857
  const q = typeof query === "string" ? query.trim() : "";
34591
34858
  if (!q) {
34592
- console.error(chalk2.red("Search query cannot be empty."));
34859
+ console.error(chalk3.red("Search query cannot be empty."));
34593
34860
  process.exit(1);
34594
34861
  }
34595
34862
  const messages = searchMessages({
@@ -34603,16 +34870,16 @@ program2.command("search").description("Search messages by content").argument("<
34603
34870
  console.log(JSON.stringify(messages, null, 2));
34604
34871
  } else {
34605
34872
  if (messages.length === 0) {
34606
- console.log(chalk2.dim("No messages found."));
34873
+ console.log(chalk3.dim("No messages found."));
34607
34874
  } else {
34608
- console.log(chalk2.dim(`Found ${messages.length} result(s) for "${q}":
34875
+ console.log(chalk3.dim(`Found ${messages.length} result(s) for "${q}":
34609
34876
  `));
34610
34877
  for (const msg of messages) {
34611
- const time3 = chalk2.dim(msg.created_at.slice(11, 19));
34612
- const from = chalk2.cyan(msg.from_agent);
34613
- const to = msg.space ? chalk2.magenta(`#${msg.space}`) : chalk2.yellow(msg.to_agent);
34614
- const priority = msg.priority !== "normal" ? chalk2.red(` [${msg.priority}]`) : "";
34615
- const unread = !msg.read_at ? chalk2.green(" *") : "";
34878
+ const time3 = chalk3.dim(msg.created_at.slice(11, 19));
34879
+ const from = chalk3.cyan(msg.from_agent);
34880
+ const to = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow(msg.to_agent);
34881
+ const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
34882
+ const unread = !msg.read_at ? chalk3.green(" *") : "";
34616
34883
  console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}: ${msg.content}`);
34617
34884
  }
34618
34885
  }
@@ -34625,12 +34892,12 @@ program2.command("sessions").description("List conversation sessions").option("-
34625
34892
  console.log(JSON.stringify(sessions, null, 2));
34626
34893
  } else {
34627
34894
  if (sessions.length === 0) {
34628
- console.log(chalk2.dim("No sessions found."));
34895
+ console.log(chalk3.dim("No sessions found."));
34629
34896
  } else {
34630
34897
  for (const s of sessions) {
34631
- const unread = s.unread_count > 0 ? chalk2.green(` (${s.unread_count} unread)`) : "";
34898
+ const unread = s.unread_count > 0 ? chalk3.green(` (${s.unread_count} unread)`) : "";
34632
34899
  const participants = s.participants.join(", ");
34633
- console.log(`${chalk2.bold(s.session_id)} \u2014 ${participants} \u2014 ${s.message_count} messages${unread}`);
34900
+ console.log(`${chalk3.bold(s.session_id)} \u2014 ${participants} \u2014 ${s.message_count} messages${unread}`);
34634
34901
  }
34635
34902
  }
34636
34903
  }
@@ -34639,17 +34906,17 @@ program2.command("sessions").description("List conversation sessions").option("-
34639
34906
  program2.command("reply").description("Reply to a message (uses same session)").argument("<message>", "Reply content").requiredOption("--to <message-id>", "Message ID to reply to", parseInt).option("--from <agent>", "Sender agent ID").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--json", "Output as JSON").action((message, opts) => {
34640
34907
  const original = getMessageById(opts.to);
34641
34908
  if (!original) {
34642
- console.error(chalk2.red(`Message #${opts.to} not found.`));
34909
+ console.error(chalk3.red(`Message #${opts.to} not found.`));
34643
34910
  process.exit(1);
34644
34911
  }
34645
34912
  const from = resolveIdentity(opts.from).trim();
34646
34913
  const content = typeof message === "string" ? message : "";
34647
34914
  if (!from) {
34648
- console.error(chalk2.red("Sender identity is required."));
34915
+ console.error(chalk3.red("Sender identity is required."));
34649
34916
  process.exit(1);
34650
34917
  }
34651
34918
  if (!content.trim()) {
34652
- console.error(chalk2.red("Reply content cannot be empty."));
34919
+ console.error(chalk3.red("Reply content cannot be empty."));
34653
34920
  process.exit(1);
34654
34921
  }
34655
34922
  const space = original.space || (original.session_id?.startsWith("space:") ? original.session_id.slice(6) : undefined);
@@ -34665,7 +34932,7 @@ program2.command("reply").description("Reply to a message (uses same session)").
34665
34932
  if (opts.json) {
34666
34933
  console.log(JSON.stringify(msg, null, 2));
34667
34934
  } else {
34668
- console.log(chalk2.green(`Reply sent`) + chalk2.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
34935
+ console.log(chalk3.green(`Reply sent`) + chalk3.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
34669
34936
  }
34670
34937
  closeDb();
34671
34938
  });
@@ -34681,13 +34948,13 @@ program2.command("mark-read").description("Mark messages as read").argument("[id
34681
34948
  } else if (ids.length > 0) {
34682
34949
  count = markRead(ids.map(Number), agent);
34683
34950
  } else {
34684
- console.error(chalk2.red("Provide message IDs, --all, --session, or --space flag."));
34951
+ console.error(chalk3.red("Provide message IDs, --all, --session, or --space flag."));
34685
34952
  process.exit(1);
34686
34953
  }
34687
34954
  if (opts.json) {
34688
34955
  console.log(JSON.stringify({ marked_read: count }));
34689
34956
  } else {
34690
- console.log(chalk2.green(`Marked ${count} message(s) as read.`));
34957
+ console.log(chalk3.green(`Marked ${count} message(s) as read.`));
34691
34958
  }
34692
34959
  closeDb();
34693
34960
  });
@@ -34723,7 +34990,7 @@ program2.command("status").description("Show database stats").option("--json", "
34723
34990
  if (opts.json) {
34724
34991
  console.log(JSON.stringify(stats, null, 2));
34725
34992
  } else {
34726
- console.log(chalk2.bold("Conversations Status"));
34993
+ console.log(chalk3.bold("Conversations Status"));
34727
34994
  console.log(` DB Path: ${stats.db_path}`);
34728
34995
  console.log(` Messages: ${stats.total_messages}`);
34729
34996
  console.log(` Sessions: ${stats.total_sessions}`);
@@ -34745,7 +35012,7 @@ program2.command("update").description("Check for and install updates").option("
34745
35012
  if (opts.json) {
34746
35013
  console.log(JSON.stringify({ error: "Failed to check npm registry" }));
34747
35014
  } else {
34748
- console.error(chalk2.red("Failed to check npm registry for updates."));
35015
+ console.error(chalk3.red("Failed to check npm registry for updates."));
34749
35016
  }
34750
35017
  process.exit(1);
34751
35018
  }
@@ -34754,18 +35021,18 @@ program2.command("update").description("Check for and install updates").option("
34754
35021
  if (opts.json) {
34755
35022
  console.log(JSON.stringify({ current, latest, updateAvailable }));
34756
35023
  } else if (updateAvailable) {
34757
- console.log(`Current version: ${chalk2.yellow(current)}`);
34758
- console.log(`Latest version: ${chalk2.green(latest)}`);
34759
- console.log(chalk2.cyan(`Run ${chalk2.bold("conversations update")} to install.`));
35024
+ console.log(`Current version: ${chalk3.yellow(current)}`);
35025
+ console.log(`Latest version: ${chalk3.green(latest)}`);
35026
+ console.log(chalk3.cyan(`Run ${chalk3.bold("conversations update")} to install.`));
34760
35027
  } else {
34761
- console.log(chalk2.green(`Already on latest version (${current})`));
35028
+ console.log(chalk3.green(`Already on latest version (${current})`));
34762
35029
  }
34763
35030
  return;
34764
35031
  }
34765
35032
  if (opts.json) {
34766
35033
  console.log(JSON.stringify({ current, latest, updateAvailable, status: "updating" }));
34767
35034
  } else {
34768
- console.log(`Updating from ${chalk2.yellow(current)} to ${chalk2.green(latest)}...`);
35035
+ console.log(`Updating from ${chalk3.yellow(current)} to ${chalk3.green(latest)}...`);
34769
35036
  }
34770
35037
  const proc = Bun.spawn(["bun", "install", "-g", `@hasna/conversations@${latest}`], {
34771
35038
  stdout: "inherit",
@@ -34774,14 +35041,14 @@ program2.command("update").description("Check for and install updates").option("
34774
35041
  const exitCode = await proc.exited;
34775
35042
  if (exitCode === 0) {
34776
35043
  if (!opts.json) {
34777
- console.log(chalk2.green(`
35044
+ console.log(chalk3.green(`
34778
35045
  Successfully updated to v${latest}`));
34779
35046
  }
34780
35047
  } else {
34781
35048
  if (opts.json) {
34782
35049
  console.log(JSON.stringify({ error: "Update failed", exitCode }));
34783
35050
  } else {
34784
- console.error(chalk2.red(`
35051
+ console.error(chalk3.red(`
34785
35052
  Update failed (exit code ${exitCode})`));
34786
35053
  }
34787
35054
  process.exit(1);
@@ -34792,11 +35059,11 @@ space.command("create").description("Create a new space").argument("<name>", "Sp
34792
35059
  const agent = resolveIdentity(opts.from).trim();
34793
35060
  const spaceName = typeof name === "string" ? name.trim() : "";
34794
35061
  if (!agent) {
34795
- console.error(chalk2.red("Creator identity is required."));
35062
+ console.error(chalk3.red("Creator identity is required."));
34796
35063
  process.exit(1);
34797
35064
  }
34798
35065
  if (!spaceName) {
34799
- console.error(chalk2.red("Space name cannot be empty."));
35066
+ console.error(chalk3.red("Space name cannot be empty."));
34800
35067
  process.exit(1);
34801
35068
  }
34802
35069
  try {
@@ -34809,14 +35076,14 @@ space.command("create").description("Create a new space").argument("<name>", "Sp
34809
35076
  if (opts.json) {
34810
35077
  console.log(JSON.stringify(sp, null, 2));
34811
35078
  } else {
34812
- console.log(chalk2.green(`Space #${sp.name} created`) + (sp.description ? chalk2.dim(` \u2014 ${sp.description}`) : ""));
35079
+ console.log(chalk3.green(`Space #${sp.name} created`) + (sp.description ? chalk3.dim(` \u2014 ${sp.description}`) : ""));
34813
35080
  }
34814
35081
  } catch (e) {
34815
35082
  if (e.message?.includes("UNIQUE constraint")) {
34816
- console.error(chalk2.red(`Space #${spaceName} already exists.`));
35083
+ console.error(chalk3.red(`Space #${spaceName} already exists.`));
34817
35084
  process.exit(1);
34818
35085
  }
34819
- console.error(chalk2.red(e.message));
35086
+ console.error(chalk3.red(e.message));
34820
35087
  process.exit(1);
34821
35088
  }
34822
35089
  closeDb();
@@ -34837,13 +35104,13 @@ space.command("list").description("List all spaces").option("--project <id>", "F
34837
35104
  console.log(JSON.stringify(spaces, null, 2));
34838
35105
  } else {
34839
35106
  if (spaces.length === 0) {
34840
- console.log(chalk2.dim("No spaces found."));
35107
+ console.log(chalk3.dim("No spaces found."));
34841
35108
  } else {
34842
35109
  for (const sp of spaces) {
34843
- const desc = sp.description ? chalk2.dim(` \u2014 ${sp.description}`) : "";
34844
- const parent = sp.parent_id ? chalk2.dim(` (child of ${sp.parent_id})`) : "";
34845
- const archived = sp.archived_at ? chalk2.yellow(" [archived]") : "";
34846
- console.log(`${chalk2.magenta(`#${sp.name}`)}${desc}${parent}${archived} ${sp.member_count} members, ${sp.message_count} messages`);
35110
+ const desc = sp.description ? chalk3.dim(` \u2014 ${sp.description}`) : "";
35111
+ const parent = sp.parent_id ? chalk3.dim(` (child of ${sp.parent_id})`) : "";
35112
+ const archived = sp.archived_at ? chalk3.yellow(" [archived]") : "";
35113
+ console.log(`${chalk3.magenta(`#${sp.name}`)}${desc}${parent}${archived} ${sp.member_count} members, ${sp.message_count} messages`);
34847
35114
  }
34848
35115
  }
34849
35116
  }
@@ -34852,7 +35119,7 @@ space.command("list").description("List all spaces").option("--project <id>", "F
34852
35119
  space.command("update").description("Update a space").argument("<name>", "Space name").option("--description <text>", "New description").option("--parent <name>", "New parent space name").option("--project <id>", "New project ID").option("--json", "Output as JSON").action((name, opts) => {
34853
35120
  const spaceName = typeof name === "string" ? name.trim() : "";
34854
35121
  if (!spaceName) {
34855
- console.error(chalk2.red("Space name cannot be empty."));
35122
+ console.error(chalk3.red("Space name cannot be empty."));
34856
35123
  process.exit(1);
34857
35124
  }
34858
35125
  const updates = {};
@@ -34867,10 +35134,10 @@ space.command("update").description("Update a space").argument("<name>", "Space
34867
35134
  if (opts.json) {
34868
35135
  console.log(JSON.stringify(sp, null, 2));
34869
35136
  } else {
34870
- console.log(chalk2.green(`Space #${sp.name} updated.`));
35137
+ console.log(chalk3.green(`Space #${sp.name} updated.`));
34871
35138
  }
34872
35139
  } catch (e) {
34873
- console.error(chalk2.red(e.message));
35140
+ console.error(chalk3.red(e.message));
34874
35141
  process.exit(1);
34875
35142
  }
34876
35143
  closeDb();
@@ -34878,7 +35145,7 @@ space.command("update").description("Update a space").argument("<name>", "Space
34878
35145
  space.command("archive").description("Archive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
34879
35146
  const spaceName = typeof name === "string" ? name.trim() : "";
34880
35147
  if (!spaceName) {
34881
- console.error(chalk2.red("Space name cannot be empty."));
35148
+ console.error(chalk3.red("Space name cannot be empty."));
34882
35149
  process.exit(1);
34883
35150
  }
34884
35151
  try {
@@ -34886,10 +35153,10 @@ space.command("archive").description("Archive a space").argument("<name>", "Spac
34886
35153
  if (opts.json) {
34887
35154
  console.log(JSON.stringify(sp, null, 2));
34888
35155
  } else {
34889
- console.log(chalk2.green(`Space #${sp.name} archived.`));
35156
+ console.log(chalk3.green(`Space #${sp.name} archived.`));
34890
35157
  }
34891
35158
  } catch (e) {
34892
- console.error(chalk2.red(e.message));
35159
+ console.error(chalk3.red(e.message));
34893
35160
  process.exit(1);
34894
35161
  }
34895
35162
  closeDb();
@@ -34897,7 +35164,7 @@ space.command("archive").description("Archive a space").argument("<name>", "Spac
34897
35164
  space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
34898
35165
  const spaceName = typeof name === "string" ? name.trim() : "";
34899
35166
  if (!spaceName) {
34900
- console.error(chalk2.red("Space name cannot be empty."));
35167
+ console.error(chalk3.red("Space name cannot be empty."));
34901
35168
  process.exit(1);
34902
35169
  }
34903
35170
  try {
@@ -34905,10 +35172,10 @@ space.command("unarchive").description("Unarchive a space").argument("<name>", "
34905
35172
  if (opts.json) {
34906
35173
  console.log(JSON.stringify(sp, null, 2));
34907
35174
  } else {
34908
- console.log(chalk2.green(`Space #${sp.name} unarchived.`));
35175
+ console.log(chalk3.green(`Space #${sp.name} unarchived.`));
34909
35176
  }
34910
35177
  } catch (e) {
34911
- console.error(chalk2.red(e.message));
35178
+ console.error(chalk3.red(e.message));
34912
35179
  process.exit(1);
34913
35180
  }
34914
35181
  closeDb();
@@ -34918,20 +35185,20 @@ space.command("send").description("Send a message to a space").argument("<space>
34918
35185
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
34919
35186
  const content = typeof message === "string" ? message : "";
34920
35187
  if (!from) {
34921
- console.error(chalk2.red("Sender identity is required."));
35188
+ console.error(chalk3.red("Sender identity is required."));
34922
35189
  process.exit(1);
34923
35190
  }
34924
35191
  if (!spaceArg) {
34925
- console.error(chalk2.red("Space name cannot be empty."));
35192
+ console.error(chalk3.red("Space name cannot be empty."));
34926
35193
  process.exit(1);
34927
35194
  }
34928
35195
  if (!content.trim()) {
34929
- console.error(chalk2.red("Message content cannot be empty."));
35196
+ console.error(chalk3.red("Message content cannot be empty."));
34930
35197
  process.exit(1);
34931
35198
  }
34932
35199
  const sp = getSpace(spaceArg);
34933
35200
  if (!sp) {
34934
- console.error(chalk2.red(`Space #${spaceArg} not found.`));
35201
+ console.error(chalk3.red(`Space #${spaceArg} not found.`));
34935
35202
  process.exit(1);
34936
35203
  }
34937
35204
  const msg = sendMessage({
@@ -34945,14 +35212,14 @@ space.command("send").description("Send a message to a space").argument("<space>
34945
35212
  if (opts.json) {
34946
35213
  console.log(JSON.stringify(msg, null, 2));
34947
35214
  } else {
34948
- console.log(chalk2.green(`Message sent to #${spaceArg}`) + chalk2.dim(` (id: ${msg.id})`));
35215
+ console.log(chalk3.green(`Message sent to #${spaceArg}`) + chalk3.dim(` (id: ${msg.id})`));
34949
35216
  }
34950
35217
  closeDb();
34951
35218
  });
34952
35219
  space.command("read").description("Read messages from a space").argument("<space>", "Space name").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to return", parseInt).option("--json", "Output as JSON").action((spaceName, opts) => {
34953
35220
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
34954
35221
  if (!spaceArg) {
34955
- console.error(chalk2.red("Space name cannot be empty."));
35222
+ console.error(chalk3.red("Space name cannot be empty."));
34956
35223
  process.exit(1);
34957
35224
  }
34958
35225
  const messages = readMessages({
@@ -34964,13 +35231,18 @@ space.command("read").description("Read messages from a space").argument("<space
34964
35231
  console.log(JSON.stringify(messages, null, 2));
34965
35232
  } else {
34966
35233
  if (messages.length === 0) {
34967
- console.log(chalk2.dim(`No messages in #${spaceArg}.`));
35234
+ console.log(chalk3.dim(`No messages in #${spaceArg}.`));
34968
35235
  } else {
34969
35236
  for (const msg of messages) {
34970
- const time3 = chalk2.dim(msg.created_at.slice(11, 19));
34971
- const from = chalk2.cyan(msg.from_agent);
34972
- const priority = msg.priority !== "normal" ? chalk2.red(` [${msg.priority}]`) : "";
34973
- console.log(`${time3} ${from} \u2192 ${chalk2.magenta(`#${spaceArg}`)}${priority}: ${msg.content}`);
35237
+ const time3 = chalk3.dim(msg.created_at.slice(11, 19));
35238
+ const from = chalk3.cyan(msg.from_agent);
35239
+ const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
35240
+ console.log(`${time3} ${from} \u2192 ${chalk3.magenta(`#${spaceArg}`)}${priority}`);
35241
+ const rendered = renderContent(msg.content);
35242
+ const indented = rendered.split(`
35243
+ `).map((l) => " " + l).join(`
35244
+ `);
35245
+ console.log(indented);
34974
35246
  }
34975
35247
  }
34976
35248
  }
@@ -34980,22 +35252,22 @@ space.command("join").description("Join a space").argument("<space>", "Space nam
34980
35252
  const agent = resolveIdentity(opts.from).trim();
34981
35253
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
34982
35254
  if (!agent) {
34983
- console.error(chalk2.red("Agent identity is required."));
35255
+ console.error(chalk3.red("Agent identity is required."));
34984
35256
  process.exit(1);
34985
35257
  }
34986
35258
  if (!spaceArg) {
34987
- console.error(chalk2.red("Space name cannot be empty."));
35259
+ console.error(chalk3.red("Space name cannot be empty."));
34988
35260
  process.exit(1);
34989
35261
  }
34990
35262
  const ok = joinSpace(spaceArg, agent);
34991
35263
  if (!ok) {
34992
- console.error(chalk2.red(`Space #${spaceArg} not found.`));
35264
+ console.error(chalk3.red(`Space #${spaceArg} not found.`));
34993
35265
  process.exit(1);
34994
35266
  }
34995
35267
  if (opts.json) {
34996
35268
  console.log(JSON.stringify({ space: spaceArg, agent, joined: true }));
34997
35269
  } else {
34998
- console.log(chalk2.green(`${agent} joined #${spaceArg}`));
35270
+ console.log(chalk3.green(`${agent} joined #${spaceArg}`));
34999
35271
  }
35000
35272
  closeDb();
35001
35273
  });
@@ -35003,11 +35275,11 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
35003
35275
  const agent = resolveIdentity(opts.from).trim();
35004
35276
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
35005
35277
  if (!agent) {
35006
- console.error(chalk2.red("Agent identity is required."));
35278
+ console.error(chalk3.red("Agent identity is required."));
35007
35279
  process.exit(1);
35008
35280
  }
35009
35281
  if (!spaceArg) {
35010
- console.error(chalk2.red("Space name cannot be empty."));
35282
+ console.error(chalk3.red("Space name cannot be empty."));
35011
35283
  process.exit(1);
35012
35284
  }
35013
35285
  const ok = leaveSpace(spaceArg, agent);
@@ -35015,9 +35287,9 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
35015
35287
  console.log(JSON.stringify({ space: spaceArg, agent, left: ok }));
35016
35288
  } else {
35017
35289
  if (ok) {
35018
- console.log(chalk2.green(`${agent} left #${spaceArg}`));
35290
+ console.log(chalk3.green(`${agent} left #${spaceArg}`));
35019
35291
  } else {
35020
- console.log(chalk2.dim(`${agent} was not a member of #${spaceArg}`));
35292
+ console.log(chalk3.dim(`${agent} was not a member of #${spaceArg}`));
35021
35293
  }
35022
35294
  }
35023
35295
  closeDb();
@@ -35025,7 +35297,7 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
35025
35297
  space.command("members").description("List space members").argument("<space>", "Space name").option("--json", "Output as JSON").action((spaceName, opts) => {
35026
35298
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
35027
35299
  if (!spaceArg) {
35028
- console.error(chalk2.red("Space name cannot be empty."));
35300
+ console.error(chalk3.red("Space name cannot be empty."));
35029
35301
  process.exit(1);
35030
35302
  }
35031
35303
  const members = getSpaceMembers(spaceArg);
@@ -35033,11 +35305,11 @@ space.command("members").description("List space members").argument("<space>", "
35033
35305
  console.log(JSON.stringify(members, null, 2));
35034
35306
  } else {
35035
35307
  if (members.length === 0) {
35036
- console.log(chalk2.dim(`No members in #${spaceArg}.`));
35308
+ console.log(chalk3.dim(`No members in #${spaceArg}.`));
35037
35309
  } else {
35038
- console.log(chalk2.magenta(`#${spaceArg}`) + chalk2.dim(` \u2014 ${members.length} member(s)`));
35310
+ console.log(chalk3.magenta(`#${spaceArg}`) + chalk3.dim(` \u2014 ${members.length} member(s)`));
35039
35311
  for (const m of members) {
35040
- console.log(` ${chalk2.cyan(m.agent)} ${chalk2.dim(`joined ${m.joined_at.slice(0, 10)}`)}`);
35312
+ console.log(` ${chalk3.cyan(m.agent)} ${chalk3.dim(`joined ${m.joined_at.slice(0, 10)}`)}`);
35041
35313
  }
35042
35314
  }
35043
35315
  }
@@ -35048,11 +35320,11 @@ project.command("create").description("Create a new project").argument("<name>",
35048
35320
  const agent = resolveIdentity(opts.from).trim();
35049
35321
  const projectName = typeof name === "string" ? name.trim() : "";
35050
35322
  if (!agent) {
35051
- console.error(chalk2.red("Creator identity is required."));
35323
+ console.error(chalk3.red("Creator identity is required."));
35052
35324
  process.exit(1);
35053
35325
  }
35054
35326
  if (!projectName) {
35055
- console.error(chalk2.red("Project name cannot be empty."));
35327
+ console.error(chalk3.red("Project name cannot be empty."));
35056
35328
  process.exit(1);
35057
35329
  }
35058
35330
  let tags;
@@ -35060,7 +35332,7 @@ project.command("create").description("Create a new project").argument("<name>",
35060
35332
  try {
35061
35333
  tags = JSON.parse(opts.tags);
35062
35334
  } catch {
35063
- console.error(chalk2.red("Invalid --tags JSON. Expected array of strings."));
35335
+ console.error(chalk3.red("Invalid --tags JSON. Expected array of strings."));
35064
35336
  process.exit(1);
35065
35337
  }
35066
35338
  }
@@ -35076,14 +35348,14 @@ project.command("create").description("Create a new project").argument("<name>",
35076
35348
  if (opts.json) {
35077
35349
  console.log(JSON.stringify(p, null, 2));
35078
35350
  } else {
35079
- console.log(chalk2.green(`Project "${p.name}" created`) + chalk2.dim(` (id: ${p.id})`));
35351
+ console.log(chalk3.green(`Project "${p.name}" created`) + chalk3.dim(` (id: ${p.id})`));
35080
35352
  }
35081
35353
  } catch (e) {
35082
35354
  if (e.message?.includes("UNIQUE constraint")) {
35083
- console.error(chalk2.red(`Project "${projectName}" already exists.`));
35355
+ console.error(chalk3.red(`Project "${projectName}" already exists.`));
35084
35356
  process.exit(1);
35085
35357
  }
35086
- console.error(chalk2.red(e.message));
35358
+ console.error(chalk3.red(e.message));
35087
35359
  process.exit(1);
35088
35360
  }
35089
35361
  closeDb();
@@ -35095,12 +35367,12 @@ project.command("list").description("List all projects").option("--status <statu
35095
35367
  console.log(JSON.stringify(projects, null, 2));
35096
35368
  } else {
35097
35369
  if (projects.length === 0) {
35098
- console.log(chalk2.dim("No projects found."));
35370
+ console.log(chalk3.dim("No projects found."));
35099
35371
  } else {
35100
35372
  for (const p of projects) {
35101
- const desc = p.description ? chalk2.dim(` \u2014 ${p.description}`) : "";
35102
- const statusBadge = p.status === "archived" ? chalk2.yellow(" [archived]") : "";
35103
- console.log(`${chalk2.bold(p.name)}${desc}${statusBadge} ${p.space_count} spaces`);
35373
+ const desc = p.description ? chalk3.dim(` \u2014 ${p.description}`) : "";
35374
+ const statusBadge = p.status === "archived" ? chalk3.yellow(" [archived]") : "";
35375
+ console.log(`${chalk3.bold(p.name)}${desc}${statusBadge} ${p.space_count} spaces`);
35104
35376
  }
35105
35377
  }
35106
35378
  }
@@ -35111,13 +35383,13 @@ project.command("get").description("Get project details").argument("<id-or-name>
35111
35383
  if (!p)
35112
35384
  p = getProjectByName(idOrName);
35113
35385
  if (!p) {
35114
- console.error(chalk2.red(`Project "${idOrName}" not found.`));
35386
+ console.error(chalk3.red(`Project "${idOrName}" not found.`));
35115
35387
  process.exit(1);
35116
35388
  }
35117
35389
  if (opts.json) {
35118
35390
  console.log(JSON.stringify(p, null, 2));
35119
35391
  } else {
35120
- console.log(chalk2.bold(p.name));
35392
+ console.log(chalk3.bold(p.name));
35121
35393
  if (p.description)
35122
35394
  console.log(` Description: ${p.description}`);
35123
35395
  if (p.path)
@@ -35148,7 +35420,7 @@ project.command("update").description("Update a project").argument("<id>", "Proj
35148
35420
  try {
35149
35421
  updates.tags = JSON.parse(opts.tags);
35150
35422
  } catch {
35151
- console.error(chalk2.red("Invalid --tags JSON."));
35423
+ console.error(chalk3.red("Invalid --tags JSON."));
35152
35424
  process.exit(1);
35153
35425
  }
35154
35426
  }
@@ -35157,10 +35429,10 @@ project.command("update").description("Update a project").argument("<id>", "Proj
35157
35429
  if (opts.json) {
35158
35430
  console.log(JSON.stringify(p, null, 2));
35159
35431
  } else {
35160
- console.log(chalk2.green(`Project "${p.name}" updated.`));
35432
+ console.log(chalk3.green(`Project "${p.name}" updated.`));
35161
35433
  }
35162
35434
  } catch (e) {
35163
- console.error(chalk2.red(e.message));
35435
+ console.error(chalk3.red(e.message));
35164
35436
  process.exit(1);
35165
35437
  }
35166
35438
  closeDb();
@@ -35169,16 +35441,16 @@ project.command("delete").description("Delete a project").argument("<id>", "Proj
35169
35441
  try {
35170
35442
  const deleted = deleteProject(id);
35171
35443
  if (!deleted) {
35172
- console.error(chalk2.red(`Project "${id}" not found.`));
35444
+ console.error(chalk3.red(`Project "${id}" not found.`));
35173
35445
  process.exit(1);
35174
35446
  }
35175
35447
  if (opts.json) {
35176
35448
  console.log(JSON.stringify({ id, deleted: true }));
35177
35449
  } else {
35178
- console.log(chalk2.green(`Project deleted.`));
35450
+ console.log(chalk3.green(`Project deleted.`));
35179
35451
  }
35180
35452
  } catch (e) {
35181
- console.error(chalk2.red(e.message));
35453
+ console.error(chalk3.red(e.message));
35182
35454
  process.exit(1);
35183
35455
  }
35184
35456
  closeDb();
@@ -35186,7 +35458,7 @@ project.command("delete").description("Delete a project").argument("<id>", "Proj
35186
35458
  program2.command("delete").description("Delete a message (only sender can delete)").argument("<id>", "Message ID", parseInt).option("--from <agent>", "Sender agent ID").option("--json", "Output as JSON").action((id, opts) => {
35187
35459
  const agent = resolveIdentity(opts.from).trim();
35188
35460
  if (!agent) {
35189
- console.error(chalk2.red("Agent identity is required."));
35461
+ console.error(chalk3.red("Agent identity is required."));
35190
35462
  process.exit(1);
35191
35463
  }
35192
35464
  const result = deleteMessage(id, agent);
@@ -35194,9 +35466,9 @@ program2.command("delete").description("Delete a message (only sender can delete
35194
35466
  console.log(JSON.stringify({ id, deleted: result }));
35195
35467
  } else {
35196
35468
  if (result) {
35197
- console.log(chalk2.green(`Message #${id} deleted.`));
35469
+ console.log(chalk3.green(`Message #${id} deleted.`));
35198
35470
  } else {
35199
- console.error(chalk2.red(`Message #${id} not found or not your message.`));
35471
+ console.error(chalk3.red(`Message #${id} not found or not your message.`));
35200
35472
  process.exit(1);
35201
35473
  }
35202
35474
  }
@@ -35206,11 +35478,11 @@ program2.command("edit").description("Edit a message (only sender can edit)").ar
35206
35478
  const agent = resolveIdentity(opts.from).trim();
35207
35479
  const content = typeof newContent === "string" ? newContent : "";
35208
35480
  if (!agent) {
35209
- console.error(chalk2.red("Agent identity is required."));
35481
+ console.error(chalk3.red("Agent identity is required."));
35210
35482
  process.exit(1);
35211
35483
  }
35212
35484
  if (!content.trim()) {
35213
- console.error(chalk2.red("New content cannot be empty."));
35485
+ console.error(chalk3.red("New content cannot be empty."));
35214
35486
  process.exit(1);
35215
35487
  }
35216
35488
  const msg = editMessage(id, agent, content);
@@ -35218,9 +35490,9 @@ program2.command("edit").description("Edit a message (only sender can edit)").ar
35218
35490
  console.log(JSON.stringify(msg, null, 2));
35219
35491
  } else {
35220
35492
  if (msg) {
35221
- console.log(chalk2.green(`Message #${id} edited.`));
35493
+ console.log(chalk3.green(`Message #${id} edited.`));
35222
35494
  } else {
35223
- console.error(chalk2.red(`Message #${id} not found or not your message.`));
35495
+ console.error(chalk3.red(`Message #${id} not found or not your message.`));
35224
35496
  process.exit(1);
35225
35497
  }
35226
35498
  }
@@ -35232,9 +35504,9 @@ program2.command("pin").description("Pin a message").argument("<id>", "Message I
35232
35504
  console.log(JSON.stringify(msg, null, 2));
35233
35505
  } else {
35234
35506
  if (msg) {
35235
- console.log(chalk2.green(`Message #${id} pinned.`));
35507
+ console.log(chalk3.green(`Message #${id} pinned.`));
35236
35508
  } else {
35237
- console.error(chalk2.red(`Message #${id} not found.`));
35509
+ console.error(chalk3.red(`Message #${id} not found.`));
35238
35510
  process.exit(1);
35239
35511
  }
35240
35512
  }
@@ -35246,9 +35518,9 @@ program2.command("unpin").description("Unpin a message").argument("<id>", "Messa
35246
35518
  console.log(JSON.stringify(msg, null, 2));
35247
35519
  } else {
35248
35520
  if (msg) {
35249
- console.log(chalk2.green(`Message #${id} unpinned.`));
35521
+ console.log(chalk3.green(`Message #${id} unpinned.`));
35250
35522
  } else {
35251
- console.error(chalk2.red(`Message #${id} not found.`));
35523
+ console.error(chalk3.red(`Message #${id} not found.`));
35252
35524
  process.exit(1);
35253
35525
  }
35254
35526
  }
@@ -35263,13 +35535,13 @@ agents.command("list").description("List all agents with their presence status")
35263
35535
  console.log(JSON.stringify(agentsList, null, 2));
35264
35536
  } else {
35265
35537
  if (agentsList.length === 0) {
35266
- console.log(chalk2.dim("No agents found."));
35538
+ console.log(chalk3.dim("No agents found."));
35267
35539
  } else {
35268
35540
  for (const a of agentsList) {
35269
- const status = a.online ? chalk2.green("online") : chalk2.dim("offline");
35270
- const lastSeen = chalk2.dim(a.last_seen_at.slice(0, 19));
35271
- const agentName = a.agent === agent ? chalk2.cyan(`${a.agent} (you)`) : chalk2.cyan(a.agent);
35272
- console.log(` ${agentName} ${status} ${chalk2.dim(a.status)} ${lastSeen}`);
35541
+ const status = a.online ? chalk3.green("online") : chalk3.dim("offline");
35542
+ const lastSeen = chalk3.dim(a.last_seen_at.slice(0, 19));
35543
+ const agentName = a.agent === agent ? chalk3.cyan(`${a.agent} (you)`) : chalk3.cyan(a.agent);
35544
+ console.log(` ${agentName} ${status} ${chalk3.dim(a.status)} ${lastSeen}`);
35273
35545
  }
35274
35546
  }
35275
35547
  }
@@ -35278,7 +35550,7 @@ agents.command("list").description("List all agents with their presence status")
35278
35550
  agents.command("remove").description("Remove an agent from the presence list").argument("<name>", "Agent name to remove").option("--json", "Output as JSON").action((name, opts) => {
35279
35551
  const agentName = typeof name === "string" ? name.trim() : "";
35280
35552
  if (!agentName) {
35281
- console.error(chalk2.red("Agent name cannot be empty."));
35553
+ console.error(chalk3.red("Agent name cannot be empty."));
35282
35554
  process.exit(1);
35283
35555
  }
35284
35556
  const removed = removePresence(agentName);
@@ -35286,9 +35558,9 @@ agents.command("remove").description("Remove an agent from the presence list").a
35286
35558
  console.log(JSON.stringify({ agent: agentName, removed }));
35287
35559
  } else {
35288
35560
  if (removed) {
35289
- console.log(chalk2.green(`Agent "${agentName}" removed.`));
35561
+ console.log(chalk3.green(`Agent "${agentName}" removed.`));
35290
35562
  } else {
35291
- console.error(chalk2.red(`Agent "${agentName}" not found.`));
35563
+ console.error(chalk3.red(`Agent "${agentName}" not found.`));
35292
35564
  process.exit(1);
35293
35565
  }
35294
35566
  }
@@ -35298,22 +35570,22 @@ agents.command("rename").description("Rename an agent in the presence list").arg
35298
35570
  const old = typeof oldName === "string" ? oldName.trim() : "";
35299
35571
  const renamed = typeof newName === "string" ? newName.trim() : "";
35300
35572
  if (!old || !renamed) {
35301
- console.error(chalk2.red("Both old and new names are required."));
35573
+ console.error(chalk3.red("Both old and new names are required."));
35302
35574
  process.exit(1);
35303
35575
  }
35304
35576
  try {
35305
35577
  const ok = renameAgent(old, renamed);
35306
35578
  if (!ok) {
35307
- console.error(chalk2.red(`Agent "${old}" not found.`));
35579
+ console.error(chalk3.red(`Agent "${old}" not found.`));
35308
35580
  process.exit(1);
35309
35581
  }
35310
35582
  if (opts.json) {
35311
35583
  console.log(JSON.stringify({ old_name: old, new_name: renamed, renamed: true }));
35312
35584
  } else {
35313
- console.log(chalk2.green(`Agent "${old}" renamed to "${renamed}".`));
35585
+ console.log(chalk3.green(`Agent "${old}" renamed to "${renamed}".`));
35314
35586
  }
35315
35587
  } catch (e) {
35316
- console.error(chalk2.red(e.message));
35588
+ console.error(chalk3.red(e.message));
35317
35589
  process.exit(1);
35318
35590
  }
35319
35591
  closeDb();
@@ -35327,9 +35599,9 @@ program2.command("whoami").description("Show current agent identity and online s
35327
35599
  } else if (envValue) {
35328
35600
  source = "env var (CONVERSATIONS_AGENT_ID)";
35329
35601
  } else {
35330
- const { join: join5 } = __require("path");
35331
- const { homedir: homedir4 } = __require("os");
35332
- const agentIdFile = join5(homedir4(), ".conversations", "agent-id");
35602
+ const { join: join6 } = __require("path");
35603
+ const { homedir: homedir5 } = __require("os");
35604
+ const agentIdFile = join6(homedir5(), ".conversations", "agent-id");
35333
35605
  source = `auto-generated (${agentIdFile})`;
35334
35606
  }
35335
35607
  const presence = getPresence(agent);
@@ -35339,15 +35611,15 @@ program2.command("whoami").description("Show current agent identity and online s
35339
35611
  const agoMs = Date.now() - lastSeenMs;
35340
35612
  const agoSec = Math.floor(agoMs / 1000);
35341
35613
  const agoStr = agoSec < 60 ? `${agoSec}s ago` : `${Math.floor(agoSec / 60)}m ago`;
35342
- onlineStatus = chalk2.green(`yes`) + chalk2.dim(` (last seen ${agoStr})`);
35614
+ onlineStatus = chalk3.green(`yes`) + chalk3.dim(` (last seen ${agoStr})`);
35343
35615
  } else if (presence) {
35344
- onlineStatus = chalk2.red("no") + chalk2.dim(` (last seen ${presence.last_seen_at})`);
35616
+ onlineStatus = chalk3.red("no") + chalk3.dim(` (last seen ${presence.last_seen_at})`);
35345
35617
  } else {
35346
- onlineStatus = chalk2.red("no") + chalk2.dim(" (no presence record)");
35618
+ onlineStatus = chalk3.red("no") + chalk3.dim(" (no presence record)");
35347
35619
  }
35348
- console.log(` ${chalk2.bold("Agent:")} ${chalk2.cyan(agent)}`);
35349
- console.log(` ${chalk2.bold("Source:")} ${source}`);
35350
- console.log(` ${chalk2.bold("Online:")} ${onlineStatus}`);
35620
+ console.log(` ${chalk3.bold("Agent:")} ${chalk3.cyan(agent)}`);
35621
+ console.log(` ${chalk3.bold("Source:")} ${source}`);
35622
+ console.log(` ${chalk3.bold("Online:")} ${onlineStatus}`);
35351
35623
  closeDb();
35352
35624
  });
35353
35625
  program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("--json", "Output as JSON").action((opts) => {
@@ -35357,16 +35629,16 @@ program2.command("blockers").description("Check for unread blocking messages").o
35357
35629
  console.log(JSON.stringify(blockers, null, 2));
35358
35630
  } else {
35359
35631
  if (blockers.length === 0) {
35360
- console.log(chalk2.dim("No blocking messages."));
35632
+ console.log(chalk3.dim("No blocking messages."));
35361
35633
  } else {
35362
- console.log(chalk2.red.bold(`${blockers.length} blocking message(s):
35634
+ console.log(chalk3.red.bold(`${blockers.length} blocking message(s):
35363
35635
  `));
35364
35636
  for (const b of blockers) {
35365
- const where = b.space ? chalk2.magenta(`#${b.space}`) : chalk2.yellow("DM");
35366
- const time3 = chalk2.dim(b.created_at.slice(11, 19));
35367
- console.log(` ${chalk2.red(`[#${b.id}]`)} ${time3} ${chalk2.cyan(b.from_agent)} ${where}: ${b.content}`);
35637
+ const where = b.space ? chalk3.magenta(`#${b.space}`) : chalk3.yellow("DM");
35638
+ const time3 = chalk3.dim(b.created_at.slice(11, 19));
35639
+ console.log(` ${chalk3.red(`[#${b.id}]`)} ${time3} ${chalk3.cyan(b.from_agent)} ${where}: ${b.content}`);
35368
35640
  }
35369
- console.log(chalk2.dim(`
35641
+ console.log(chalk3.dim(`
35370
35642
  Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}`));
35371
35643
  }
35372
35644
  }
@@ -35385,49 +35657,12 @@ program2.command("watch").description("Watch for new messages with desktop notif
35385
35657
  }
35386
35658
  const modeLabel = opts.all ? `DMs + ${agentSpaces.length} space(s)` : opts.space ? `Space: #${opts.space}` : "All DMs";
35387
35659
  console.log("");
35388
- console.log(chalk2.bold(` Conversations`) + chalk2.dim(` \u2014 watching as ${chalk2.cyan(agent)}`));
35389
- console.log(chalk2.dim(` ${modeLabel} \xB7 Poll: ${interval}ms \xB7 Ctrl+C to stop`));
35390
- console.log(chalk2.dim(" " + "\u2500".repeat(cols - 4)));
35660
+ console.log(chalk3.bold(` Conversations`) + chalk3.dim(` \u2014 watching as ${chalk3.cyan(agent)}`));
35661
+ console.log(chalk3.dim(` ${modeLabel} \xB7 Poll: ${interval}ms \xB7 Ctrl+C to stop`));
35662
+ console.log(chalk3.dim(" " + "\u2500".repeat(cols - 4)));
35391
35663
  console.log("");
35392
35664
  const { startPolling: startPolling2 } = (init_poll(), __toCommonJS(exports_poll));
35393
- const renderContent = (content) => {
35394
- const lines = content.split(`
35395
- `);
35396
- const rendered = [];
35397
- for (const line of lines) {
35398
- let l = line;
35399
- const h = l.match(/^(#{1,3})\s+(.+)/);
35400
- if (h) {
35401
- rendered.push(chalk2.bold(h[2]));
35402
- continue;
35403
- }
35404
- if (/^\s*[-*+]\s/.test(l)) {
35405
- rendered.push(" " + chalk2.dim("\u2022") + " " + renderInline(l.replace(/^\s*[-*+]\s/, "")));
35406
- continue;
35407
- }
35408
- const ol = l.match(/^\s*(\d+)[.)]\s(.*)/);
35409
- if (ol) {
35410
- rendered.push(" " + chalk2.dim(ol[1] + ".") + " " + renderInline(ol[2]));
35411
- continue;
35412
- }
35413
- if (l.startsWith(">")) {
35414
- rendered.push(chalk2.dim(" \u2502 ") + chalk2.italic(renderInline(l.replace(/^>\s?/, ""))));
35415
- continue;
35416
- }
35417
- if (l.trimStart().startsWith("```"))
35418
- continue;
35419
- if (l.trim() === "") {
35420
- rendered.push("");
35421
- continue;
35422
- }
35423
- rendered.push(renderInline(l));
35424
- }
35425
- return rendered.join(`
35426
- `);
35427
- };
35428
- const renderInline = (text) => {
35429
- return text.replace(/`([^`]+)`/g, (_, code) => chalk2.bgGray.white(` ${code} `)).replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => chalk2.bold.italic(t)).replace(/\*\*(.+?)\*\*/g, (_, t) => chalk2.bold(t)).replace(/\*(.+?)\*/g, (_, t) => chalk2.italic(t)).replace(/~~(.+?)~~/g, (_, t) => chalk2.strikethrough(t));
35430
- };
35665
+ const { renderContent: renderContent2 } = (init_terminal_markdown(), __toCommonJS(exports_terminal_markdown));
35431
35666
  const desktopNotify = (title, body) => {
35432
35667
  if (process.platform === "darwin") {
35433
35668
  try {
@@ -35439,18 +35674,18 @@ program2.command("watch").description("Watch for new messages with desktop notif
35439
35674
  }
35440
35675
  };
35441
35676
  const renderMessage = (msg) => {
35442
- const time3 = chalk2.dim(msg.created_at.slice(11, 19));
35443
- const where = msg.space ? chalk2.magenta(`#${msg.space}`) : chalk2.yellow("DM");
35444
- const priority = msg.priority !== "normal" ? msg.priority === "urgent" ? chalk2.red.bold(` [${msg.priority}]`) : msg.priority === "high" ? chalk2.yellow(` [${msg.priority}]`) : chalk2.dim(` [${msg.priority}]`) : "";
35445
- const blocking = msg.blocking ? chalk2.red.bold(" \u26A0 BLOCKER") : "";
35446
- const sender = chalk2.cyan.bold(msg.from_agent);
35677
+ const time3 = chalk3.dim(msg.created_at.slice(11, 19));
35678
+ const where = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow("DM");
35679
+ const priority = msg.priority !== "normal" ? msg.priority === "urgent" ? chalk3.red.bold(` [${msg.priority}]`) : msg.priority === "high" ? chalk3.yellow(` [${msg.priority}]`) : chalk3.dim(` [${msg.priority}]`) : "";
35680
+ const blocking = msg.blocking ? chalk3.red.bold(" \u26A0 BLOCKER") : "";
35681
+ const sender = chalk3.cyan.bold(msg.from_agent);
35447
35682
  console.log(` ${sender} ${where} ${time3}${priority}${blocking}`);
35448
- const content = renderContent(msg.content);
35683
+ const content = renderContent2(msg.content);
35449
35684
  const indented = content.split(`
35450
35685
  `).map((l) => " " + l).join(`
35451
35686
  `);
35452
35687
  console.log(indented);
35453
- console.log(chalk2.dim(" " + "\xB7".repeat(Math.min(cols - 8, 60))));
35688
+ console.log(chalk3.dim(" " + "\xB7".repeat(Math.min(cols - 8, 60))));
35454
35689
  console.log("");
35455
35690
  };
35456
35691
  if (opts.all) {
@@ -35461,12 +35696,12 @@ program2.command("watch").description("Watch for new messages with desktop notif
35461
35696
  }
35462
35697
  const recent = [...dmRecent, ...spaceRecent].sort((a, b) => a.created_at.localeCompare(b.created_at)).slice(-20);
35463
35698
  if (recent.length > 0) {
35464
- console.log(chalk2.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
35699
+ console.log(chalk3.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
35465
35700
  `));
35466
35701
  for (const msg of recent) {
35467
35702
  renderMessage(msg);
35468
35703
  }
35469
- console.log(chalk2.dim(` \u2500\u2500 Live \u2500\u2500
35704
+ console.log(chalk3.dim(` \u2500\u2500 Live \u2500\u2500
35470
35705
  `));
35471
35706
  }
35472
35707
  } else {
@@ -35477,12 +35712,12 @@ program2.command("watch").description("Watch for new messages with desktop notif
35477
35712
  order: "asc"
35478
35713
  });
35479
35714
  if (recent.length > 0) {
35480
- console.log(chalk2.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
35715
+ console.log(chalk3.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
35481
35716
  `));
35482
35717
  for (const msg of recent) {
35483
35718
  renderMessage(msg);
35484
35719
  }
35485
- console.log(chalk2.dim(` \u2500\u2500 Live \u2500\u2500
35720
+ console.log(chalk3.dim(` \u2500\u2500 Live \u2500\u2500
35486
35721
  `));
35487
35722
  }
35488
35723
  }
@@ -35510,7 +35745,7 @@ program2.command("watch").description("Watch for new messages with desktop notif
35510
35745
  });
35511
35746
  }
35512
35747
  process.on("SIGINT", () => {
35513
- console.log(chalk2.dim(`
35748
+ console.log(chalk3.dim(`
35514
35749
  Stopped watching.`));
35515
35750
  closeDb();
35516
35751
  process.exit(0);
@@ -35531,8 +35766,8 @@ program2.command("dashboard").description("Start web dashboard").option("--port
35531
35766
  });
35532
35767
  program2.action(() => {
35533
35768
  if (!process.stdin.isTTY) {
35534
- console.error(chalk2.red("Interactive mode requires a TTY terminal."));
35535
- console.error(chalk2.dim("Use subcommands (send, read, sessions, etc.) for non-interactive use."));
35769
+ console.error(chalk3.red("Interactive mode requires a TTY terminal."));
35770
+ console.error(chalk3.dim("Use subcommands (send, read, sessions, etc.) for non-interactive use."));
35536
35771
  process.exit(1);
35537
35772
  }
35538
35773
  const agent = resolveIdentity();