@hasna/conversations 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -4,6 +4,7 @@ var __create = Object.create;
4
4
  var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
9
  var __toESM = (mod, isNodeMode, target) => {
9
10
  target = mod != null ? __create(__getProtoOf(mod)) : {};
@@ -16,6 +17,20 @@ var __toESM = (mod, isNodeMode, target) => {
16
17
  });
17
18
  return to;
18
19
  };
20
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
21
+ var __toCommonJS = (from) => {
22
+ var entry = __moduleCache.get(from), desc;
23
+ if (entry)
24
+ return entry;
25
+ entry = __defProp({}, "__esModule", { value: true });
26
+ if (from && typeof from === "object" || typeof from === "function")
27
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
28
+ get: () => from[key],
29
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
30
+ }));
31
+ __moduleCache.set(from, entry);
32
+ return entry;
33
+ };
19
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
35
  var __export = (target, all) => {
21
36
  for (var name in all)
@@ -1869,6 +1884,12 @@ var require_commander = __commonJS((exports) => {
1869
1884
  });
1870
1885
 
1871
1886
  // src/lib/db.ts
1887
+ var exports_db = {};
1888
+ __export(exports_db, {
1889
+ getDbPath: () => getDbPath,
1890
+ getDb: () => getDb,
1891
+ closeDb: () => closeDb
1892
+ });
1872
1893
  import { Database } from "bun:sqlite";
1873
1894
  import { mkdirSync } from "fs";
1874
1895
  import { join, dirname } from "path";
@@ -2006,6 +2027,10 @@ function getDb() {
2006
2027
  db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
2007
2028
  db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
2008
2029
  }
2030
+ if (!colNames2.includes("blocking")) {
2031
+ db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
2032
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
2033
+ }
2009
2034
  return db;
2010
2035
  }
2011
2036
  function closeDb() {
@@ -2030,7 +2055,8 @@ function parseMessage(row) {
2030
2055
  }
2031
2056
  return {
2032
2057
  ...row,
2033
- metadata
2058
+ metadata,
2059
+ blocking: !!row.blocking
2034
2060
  };
2035
2061
  }
2036
2062
  function sendMessage(opts) {
@@ -2039,12 +2065,13 @@ function sendMessage(opts) {
2039
2065
  const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID().slice(0, 8)}`);
2040
2066
  const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
2041
2067
  const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
2068
+ const blocking = opts.blocking ? 1 : 0;
2042
2069
  const stmt = db2.prepare(`
2043
- INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata)
2044
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2070
+ INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
2071
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2045
2072
  RETURNING *
2046
2073
  `);
2047
- 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);
2074
+ 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);
2048
2075
  return parseMessage(row);
2049
2076
  }
2050
2077
  function readMessages(opts = {}) {
@@ -2213,6 +2240,19 @@ function getPinnedMessages(opts) {
2213
2240
  const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY pinned_at DESC, id DESC ${limit}`).all(...params);
2214
2241
  return rows.map(parseMessage);
2215
2242
  }
2243
+ function getUnreadBlockers(agent) {
2244
+ const db2 = getDb();
2245
+ const rows = db2.prepare(`
2246
+ SELECT * FROM messages
2247
+ WHERE blocking = 1 AND read_at IS NULL
2248
+ AND (
2249
+ to_agent = ?
2250
+ OR space IN (SELECT space FROM space_members WHERE agent = ?)
2251
+ )
2252
+ ORDER BY created_at ASC, id ASC
2253
+ `).all(agent, agent);
2254
+ return rows.map(parseMessage);
2255
+ }
2216
2256
  function searchMessages(opts) {
2217
2257
  const db2 = getDb();
2218
2258
  const conditions = ["content LIKE ?"];
@@ -2975,6 +3015,16 @@ var init_names = __esm(() => {
2975
3015
  import { readFileSync, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
2976
3016
  import { join as join2, dirname as dirname2 } from "path";
2977
3017
  import { homedir as homedir2 } from "os";
3018
+ function isNameTaken(name) {
3019
+ try {
3020
+ const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
3021
+ const db2 = getDb2();
3022
+ const row = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(name);
3023
+ return !!row;
3024
+ } catch {
3025
+ return false;
3026
+ }
3027
+ }
2978
3028
  function getAutoName() {
2979
3029
  if (cachedAutoName)
2980
3030
  return cachedAutoName;
@@ -2985,7 +3035,14 @@ function getAutoName() {
2985
3035
  return name2;
2986
3036
  }
2987
3037
  } catch {}
2988
- const name = AGENT_NAMES[Math.floor(Math.random() * AGENT_NAMES.length)];
3038
+ const shuffled = [...AGENT_NAMES].sort(() => Math.random() - 0.5);
3039
+ let name = shuffled[0];
3040
+ for (const candidate of shuffled) {
3041
+ if (!isNameTaken(candidate)) {
3042
+ name = candidate;
3043
+ break;
3044
+ }
3045
+ }
2989
3046
  cachedAutoName = name;
2990
3047
  try {
2991
3048
  mkdirSync2(dirname2(AGENT_ID_FILE), { recursive: true });
@@ -3080,12 +3137,13 @@ var init_presence = __esm(() => {
3080
3137
  var require_package = __commonJS((exports, module) => {
3081
3138
  module.exports = {
3082
3139
  name: "@hasna/conversations",
3083
- version: "0.1.5",
3140
+ version: "0.1.6",
3084
3141
  description: "Real-time CLI messaging for AI agents",
3085
3142
  type: "module",
3086
3143
  bin: {
3087
3144
  conversations: "bin/index.js",
3088
- "conversations-mcp": "bin/mcp.js"
3145
+ "conversations-mcp": "bin/mcp.js",
3146
+ "conversations-hook": "bin/hook.js"
3089
3147
  },
3090
3148
  exports: {
3091
3149
  ".": {
@@ -3103,7 +3161,7 @@ var require_package = __commonJS((exports, module) => {
3103
3161
  main: "./dist/index.js",
3104
3162
  types: "./dist/index.d.ts",
3105
3163
  scripts: {
3106
- build: "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
3164
+ build: "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/hooks/blocker-hook.ts --outfile ./bin/hook.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
3107
3165
  "build:dashboard": "cd dashboard && bun install && bun run build",
3108
3166
  test: "bun test",
3109
3167
  dev: "bun run ./src/cli/index.tsx",
@@ -32057,9 +32115,10 @@ var init_mcp2 = __esm(() => {
32057
32115
  working_dir: exports_external.string().optional().describe("Working directory context"),
32058
32116
  repository: exports_external.string().optional().describe("Repository context"),
32059
32117
  branch: exports_external.string().optional().describe("Branch context"),
32060
- metadata: exports_external.string().optional().describe("JSON metadata string")
32118
+ metadata: exports_external.string().optional().describe("JSON metadata string"),
32119
+ blocking: exports_external.boolean().optional().describe("Send as a blocking message. Recipients must acknowledge before continuing.")
32061
32120
  }
32062
- }, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata }) => {
32121
+ }, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata, blocking }) => {
32063
32122
  const from = resolveIdentity(fromParam);
32064
32123
  let parsedMetadata;
32065
32124
  if (metadata) {
@@ -32081,7 +32140,8 @@ var init_mcp2 = __esm(() => {
32081
32140
  working_dir,
32082
32141
  repository,
32083
32142
  branch,
32084
- metadata: parsedMetadata
32143
+ metadata: parsedMetadata,
32144
+ blocking
32085
32145
  });
32086
32146
  return {
32087
32147
  content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
@@ -32268,9 +32328,10 @@ var init_mcp2 = __esm(() => {
32268
32328
  from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
32269
32329
  space: exports_external.string().describe("Space name"),
32270
32330
  content: exports_external.string().describe("Message content"),
32271
- priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority")
32331
+ priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority"),
32332
+ blocking: exports_external.boolean().optional().describe("Send as a blocking message. All space members must acknowledge.")
32272
32333
  }
32273
- }, async ({ from: fromParam, space, content, priority }) => {
32334
+ }, async ({ from: fromParam, space, content, priority, blocking }) => {
32274
32335
  const from = resolveIdentity(fromParam);
32275
32336
  const sp = getSpace(space);
32276
32337
  if (!sp) {
@@ -32285,7 +32346,8 @@ var init_mcp2 = __esm(() => {
32285
32346
  content,
32286
32347
  space,
32287
32348
  session_id: `space:${space}`,
32288
- priority
32349
+ priority,
32350
+ blocking
32289
32351
  });
32290
32352
  return {
32291
32353
  content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
@@ -32724,6 +32786,19 @@ var init_mcp2 = __esm(() => {
32724
32786
  content: [{ type: "text", text: JSON.stringify(agents, null, 2) }]
32725
32787
  };
32726
32788
  });
32789
+ server.registerTool("get_blockers", {
32790
+ title: "Get Blockers",
32791
+ description: "Check for unread blocking messages targeting you. Returns messages that must be acknowledged before continuing.",
32792
+ inputSchema: {
32793
+ from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var.")
32794
+ }
32795
+ }, async ({ from: fromParam }) => {
32796
+ const agent = resolveIdentity(fromParam);
32797
+ const blockers = getUnreadBlockers(agent);
32798
+ return {
32799
+ content: [{ type: "text", text: JSON.stringify(blockers, null, 2) }]
32800
+ };
32801
+ });
32727
32802
  server.registerTool("remove_agent", {
32728
32803
  title: "Remove Agent",
32729
32804
  description: "Remove an agent from the presence list. Only the agent itself should remove its own presence.",
@@ -34298,7 +34373,7 @@ function App({ agent }) {
34298
34373
  var import__package2 = __toESM(require_package(), 1);
34299
34374
  var program2 = new Command;
34300
34375
  program2.name("conversations").description("Real-time CLI messaging for AI agents").version(import__package2.default.version);
34301
- program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").requiredOption("--to <agent>", "Recipient agent ID").option("--from <agent>", "Sender agent ID").option("--session <id>", "Session ID (auto-generated if omitted)").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--working-dir <path>", "Working directory context").option("--repository <repo>", "Repository context").option("--branch <branch>", "Branch context").option("--metadata <json>", "JSON metadata string").option("--json", "Output as JSON").action((message, opts) => {
34376
+ program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").requiredOption("--to <agent>", "Recipient agent ID").option("--from <agent>", "Sender agent ID").option("--session <id>", "Session ID (auto-generated if omitted)").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--working-dir <path>", "Working directory context").option("--repository <repo>", "Repository context").option("--branch <branch>", "Branch context").option("--metadata <json>", "JSON metadata string").option("--blocking", "Send as a blocking message (recipient must acknowledge)").option("--json", "Output as JSON").action((message, opts) => {
34302
34377
  const from = resolveIdentity(opts.from).trim();
34303
34378
  const to = typeof opts.to === "string" ? opts.to.trim() : "";
34304
34379
  const content = typeof message === "string" ? message : "";
@@ -34333,7 +34408,8 @@ program2.command("send").description("Send a message to an agent").argument("<me
34333
34408
  working_dir: opts.workingDir,
34334
34409
  repository: opts.repository,
34335
34410
  branch: opts.branch,
34336
- metadata
34411
+ metadata,
34412
+ blocking: opts.blocking
34337
34413
  });
34338
34414
  if (opts.json) {
34339
34415
  console.log(JSON.stringify(msg, null, 2));
@@ -35114,6 +35190,28 @@ agents.command("rename").description("Rename an agent in the presence list").arg
35114
35190
  }
35115
35191
  closeDb();
35116
35192
  });
35193
+ program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("--json", "Output as JSON").action((opts) => {
35194
+ const agent = resolveIdentity(opts.from);
35195
+ const blockers = getUnreadBlockers(agent);
35196
+ if (opts.json) {
35197
+ console.log(JSON.stringify(blockers, null, 2));
35198
+ } else {
35199
+ if (blockers.length === 0) {
35200
+ console.log(chalk2.dim("No blocking messages."));
35201
+ } else {
35202
+ console.log(chalk2.red.bold(`${blockers.length} blocking message(s):
35203
+ `));
35204
+ for (const b of blockers) {
35205
+ const where = b.space ? chalk2.magenta(`#${b.space}`) : chalk2.yellow("DM");
35206
+ const time3 = chalk2.dim(b.created_at.slice(11, 19));
35207
+ console.log(` ${chalk2.red(`[#${b.id}]`)} ${time3} ${chalk2.cyan(b.from_agent)} ${where}: ${b.content}`);
35208
+ }
35209
+ console.log(chalk2.dim(`
35210
+ Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}`));
35211
+ }
35212
+ }
35213
+ closeDb();
35214
+ });
35117
35215
  program2.command("mcp").description("Start MCP server").action(async () => {
35118
35216
  const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
35119
35217
  await startMcpServer2();