@hasna/conversations 0.2.33 → 0.2.35

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
@@ -6,60 +6,39 @@ var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- function __accessProp(key) {
10
- return this[key];
11
- }
12
- var __toESMCache_node;
13
- var __toESMCache_esm;
14
9
  var __toESM = (mod, isNodeMode, target) => {
15
- var canCache = mod != null && typeof mod === "object";
16
- if (canCache) {
17
- var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
18
- var cached = cache.get(mod);
19
- if (cached)
20
- return cached;
21
- }
22
10
  target = mod != null ? __create(__getProtoOf(mod)) : {};
23
11
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
24
12
  for (let key of __getOwnPropNames(mod))
25
13
  if (!__hasOwnProp.call(to, key))
26
14
  __defProp(to, key, {
27
- get: __accessProp.bind(mod, key),
15
+ get: () => mod[key],
28
16
  enumerable: true
29
17
  });
30
- if (canCache)
31
- cache.set(mod, to);
32
18
  return to;
33
19
  };
20
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
34
21
  var __toCommonJS = (from) => {
35
- var entry = (__moduleCache ??= new WeakMap).get(from), desc;
22
+ var entry = __moduleCache.get(from), desc;
36
23
  if (entry)
37
24
  return entry;
38
25
  entry = __defProp({}, "__esModule", { value: true });
39
- if (from && typeof from === "object" || typeof from === "function") {
40
- for (var key of __getOwnPropNames(from))
41
- if (!__hasOwnProp.call(entry, key))
42
- __defProp(entry, key, {
43
- get: __accessProp.bind(from, key),
44
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
45
- });
46
- }
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
+ }));
47
31
  __moduleCache.set(from, entry);
48
32
  return entry;
49
33
  };
50
- var __moduleCache;
51
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
52
- var __returnValue = (v) => v;
53
- function __exportSetter(name, newValue) {
54
- this[name] = __returnValue.bind(null, newValue);
55
- }
56
35
  var __export = (target, all) => {
57
36
  for (var name in all)
58
37
  __defProp(target, name, {
59
38
  get: all[name],
60
39
  enumerable: true,
61
40
  configurable: true,
62
- set: __exportSetter.bind(all, name)
41
+ set: (newValue) => all[name] = () => newValue
63
42
  });
64
43
  };
65
44
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -2256,7 +2235,7 @@ var init_names = __esm(() => {
2256
2235
  ];
2257
2236
  });
2258
2237
 
2259
- // node_modules/@hasna/cloud/dist/index.js
2238
+ // ../../../../node_modules/@hasna/cloud/dist/index.js
2260
2239
  var exports_dist = {};
2261
2240
  __export(exports_dist, {
2262
2241
  translateSql: () => translateSql,
@@ -2351,11 +2330,11 @@ import { join as join5 } from "path";
2351
2330
  import { join as join6, dirname } from "path";
2352
2331
  import { existsSync as existsSync6, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
2353
2332
  import { homedir as homedir5, platform } from "os";
2354
- function __accessProp2(key) {
2333
+ function __accessProp(key) {
2355
2334
  return this[key];
2356
2335
  }
2357
- function __exportSetter2(name, newValue) {
2358
- this[name] = __returnValue2.bind(null, newValue);
2336
+ function __exportSetter(name, newValue) {
2337
+ this[name] = __returnValue.bind(null, newValue);
2359
2338
  }
2360
2339
  function translateSql(sql, dialect) {
2361
2340
  if (dialect === "sqlite")
@@ -3668,9 +3647,9 @@ async function syncTransfer(source, target, options, _direction) {
3668
3647
  const batch = rows.slice(offset, offset + batchSize);
3669
3648
  try {
3670
3649
  if (isAsyncAdapter(target)) {
3671
- await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
3650
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
3672
3651
  } else {
3673
- batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
3652
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
3674
3653
  }
3675
3654
  result.rowsWritten += batch.length;
3676
3655
  } catch (err) {
@@ -3717,7 +3696,7 @@ async function syncTransfer(source, target, options, _direction) {
3717
3696
  }
3718
3697
  return results;
3719
3698
  }
3720
- async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
3699
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
3721
3700
  if (batch.length === 0)
3722
3701
  return;
3723
3702
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -3727,20 +3706,22 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, ba
3727
3706
  }).join(", ");
3728
3707
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
3729
3708
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
3709
+ const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
3730
3710
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
3731
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
3711
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
3732
3712
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
3733
3713
  await target.run(sql, ...params);
3734
3714
  }
3735
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
3715
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
3736
3716
  if (batch.length === 0)
3737
3717
  return;
3738
3718
  const colList = columns.map((c) => `"${c}"`).join(", ");
3739
3719
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
3740
3720
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
3741
3721
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
3722
+ const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
3742
3723
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
3743
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
3724
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
3744
3725
  const params = batch.flatMap((row) => columns.map((c) => coerceForSqlite(row[c])));
3745
3726
  target.run(sql, ...params);
3746
3727
  }
@@ -4810,7 +4791,7 @@ async function ensureAllPgDatabases() {
4810
4791
  }
4811
4792
  return results;
4812
4793
  }
4813
- function registerCloudTools(server, serviceName) {
4794
+ function registerCloudTools(server, serviceName, opts = {}) {
4814
4795
  server.tool(`${serviceName}_cloud_status`, "Show cloud configuration and connection health", {}, async () => {
4815
4796
  const config = getCloudConfig();
4816
4797
  const lines = [
@@ -4843,8 +4824,13 @@ function registerCloudTools(server, serviceName) {
4843
4824
  isError: true
4844
4825
  };
4845
4826
  }
4846
- const local = new SqliteAdapter(getDbPath(serviceName));
4827
+ const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
4847
4828
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
4829
+ if (opts.migrations?.length) {
4830
+ for (const sql of opts.migrations) {
4831
+ await cloud.run(sql);
4832
+ }
4833
+ }
4848
4834
  const tableList = tablesStr ? tablesStr.split(",").map((t) => t.trim()) : listSqliteTables(local);
4849
4835
  const results = await syncPush(local, cloud, { tables: tableList });
4850
4836
  local.close();
@@ -4866,7 +4852,7 @@ function registerCloudTools(server, serviceName) {
4866
4852
  isError: true
4867
4853
  };
4868
4854
  }
4869
- const local = new SqliteAdapter(getDbPath(serviceName));
4855
+ const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
4870
4856
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
4871
4857
  let tableList;
4872
4858
  if (tablesStr) {
@@ -4989,10 +4975,10 @@ function registerCloudCommands(program2, serviceName) {
4989
4975
  }
4990
4976
  });
4991
4977
  }
4992
- var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
4978
+ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node, __toESMCache_esm, __toESM2 = (mod, isNodeMode, target) => {
4993
4979
  var canCache = mod != null && typeof mod === "object";
4994
4980
  if (canCache) {
4995
- var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap;
4981
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
4996
4982
  var cached = cache.get(mod);
4997
4983
  if (cached)
4998
4984
  return cached;
@@ -5002,19 +4988,19 @@ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __t
5002
4988
  for (let key of __getOwnPropNames2(mod))
5003
4989
  if (!__hasOwnProp2.call(to, key))
5004
4990
  __defProp2(to, key, {
5005
- get: __accessProp2.bind(mod, key),
4991
+ get: __accessProp.bind(mod, key),
5006
4992
  enumerable: true
5007
4993
  });
5008
4994
  if (canCache)
5009
4995
  cache.set(mod, to);
5010
4996
  return to;
5011
- }, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue2 = (v) => v, __export2 = (target, all) => {
4997
+ }, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue = (v) => v, __export2 = (target, all) => {
5012
4998
  for (var name in all)
5013
4999
  __defProp2(target, name, {
5014
5000
  get: all[name],
5015
5001
  enumerable: true,
5016
5002
  configurable: true,
5017
- set: __exportSetter2.bind(all, name)
5003
+ set: __exportSetter.bind(all, name)
5018
5004
  });
5019
5005
  }, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), __require2, require_postgres_array, require_arrayParser, require_postgres_date, require_mutable, require_postgres_interval, require_postgres_bytea, require_textParsers, require_pg_int8, require_binaryParsers, require_builtins, require_pg_types, require_defaults, require_utils, require_utils_legacy, require_utils_webcrypto, require_utils2, require_cert_signatures, require_sasl, require_type_overrides, require_pg_connection_string, require_connection_parameters, require_result, require_query, require_messages, require_buffer_writer, require_serializer, require_buffer_reader, require_parser, require_dist, require_empty, require_stream, require_connection, require_split2, require_helper, require_lib, require_client, require_pg_pool, require_query2, require_client2, require_lib2, import_lib, Client, Pool, Connection, types, Query, DatabaseError, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default, init_esm, init_adapter, util, objectUtil, ZodParsedType, getParsedType = (data) => {
5020
5006
  const t = typeof data;
@@ -14928,7 +14914,7 @@ var init_presence = __esm(() => {
14928
14914
  var require_package = __commonJS((exports, module) => {
14929
14915
  module.exports = {
14930
14916
  name: "@hasna/conversations",
14931
- version: "0.2.33",
14917
+ version: "0.2.35",
14932
14918
  description: "Real-time CLI messaging for AI agents",
14933
14919
  type: "module",
14934
14920
  bin: {
@@ -15769,7 +15755,7 @@ async function tmuxSend(target, message, opts = {}) {
15769
15755
  }
15770
15756
  function registerTmuxCommands(program2) {
15771
15757
  const tmux = program2.command("tmux").description("Dispatch messages to tmux windows (Claude Code sessions)");
15772
- tmux.command("send").description("Send a message to a tmux window with paste+wait+Enter+verify").requiredOption("--target <target>", "Tmux target: session:window or session:window.pane").requiredOption("--message <text>", "Message text to send").option("--delay <ms>", "Wait time (ms) after paste before hitting Enter (default: adaptive 25-1500ms)", parseInt).option("--retries <n>", "Max retry attempts (default: 3)", parseInt).option("--no-verify", "Skip verification after sending").option("--json", "Output result as JSON").action(async (opts) => {
15758
+ tmux.command("send").description("Send a message to a tmux window with paste+wait+Enter+verify").requiredOption("--target <target>", "Tmux target: session:window or session:window.pane").requiredOption("--message <text>", "Message text to send").option("--delay <ms>", "Wait time (ms) after paste before hitting Enter (default: adaptive 25-1500ms)", parseInt).option("--retries <n>", "Max retry attempts (default: 3)", parseInt).option("--no-verify", "Skip verification after sending").option("-j, --json", "Output result as JSON").action(async (opts) => {
15773
15759
  const target = opts.target.trim();
15774
15760
  const message = opts.message;
15775
15761
  if (!target) {
@@ -15804,7 +15790,7 @@ function registerTmuxCommands(program2) {
15804
15790
  process.exit(1);
15805
15791
  }
15806
15792
  });
15807
- tmux.command("broadcast").description("Send the same message to multiple tmux windows").requiredOption("--targets <list>", "Comma-separated list of tmux targets").requiredOption("--message <text>", "Message text to send").option("--delay <ms>", "Wait time (ms) after paste before Enter (default: adaptive 25-1500ms)", parseInt).option("--stagger <ms>", "Delay (ms) between each target (default: 500)", parseInt).option("--retries <n>", "Max retry attempts per target (default: 3)", parseInt).option("--no-verify", "Skip verification after sending").option("--json", "Output results as JSON").action(async (opts) => {
15793
+ tmux.command("broadcast").description("Send the same message to multiple tmux windows").requiredOption("--targets <list>", "Comma-separated list of tmux targets").requiredOption("--message <text>", "Message text to send").option("--delay <ms>", "Wait time (ms) after paste before Enter (default: adaptive 25-1500ms)", parseInt).option("--stagger <ms>", "Delay (ms) between each target (default: 500)", parseInt).option("--retries <n>", "Max retry attempts per target (default: 3)", parseInt).option("--no-verify", "Skip verification after sending").option("-j, --json", "Output results as JSON").action(async (opts) => {
15808
15794
  const targets = opts.targets.split(",").map((t) => t.trim()).filter(Boolean);
15809
15795
  const message = opts.message;
15810
15796
  const stagger = Number.isFinite(opts.stagger) && opts.stagger >= 0 ? opts.stagger : 500;
@@ -43146,7 +43132,7 @@ var require_formats = __commonJS((exports) => {
43146
43132
  }
43147
43133
  var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
43148
43134
  function getTime(strictTimeZone) {
43149
- return function time3(str) {
43135
+ return function time(str) {
43150
43136
  const matches = TIME.exec(str);
43151
43137
  if (!matches)
43152
43138
  return false;
@@ -44725,25 +44711,49 @@ var init_stdio2 = __esm(() => {
44725
44711
  // src/mcp/tools/messaging.ts
44726
44712
  function registerMessagingTools(server, resolveProjectId) {
44727
44713
  server.registerTool("send_message", {
44728
- description: "Send a DM to an agent.",
44714
+ description: "Send a DM to an agent by name, or to a specific agent-claude session by ID. When target_session_id is provided, the message is routed to that exact session and auto-injected into its conversation.",
44729
44715
  inputSchema: {
44730
- to: exports_external2.string(),
44716
+ to: exports_external2.string().describe("Agent name to send to, OR use target_session_id instead for session targeting"),
44731
44717
  content: exports_external2.string(),
44732
44718
  from: exports_external2.string().optional(),
44733
44719
  priority: exports_external2.string().optional(),
44734
44720
  blocking: exports_external2.coerce.boolean().optional(),
44735
- project_id: exports_external2.string().optional()
44721
+ project_id: exports_external2.string().optional(),
44722
+ target_session_id: exports_external2.string().optional().describe("If provided, sends to a specific agent-claude session ID (UUID). The message auto-injects into that session's conversation.")
44736
44723
  }
44737
44724
  }, async (args) => {
44738
- const { from: fromParam, to, content, priority, blocking, project_id } = args;
44725
+ const { from: fromParam, to, content, priority, blocking, project_id, target_session_id } = args;
44739
44726
  const from = resolveIdentity(fromParam);
44740
44727
  const msg = sendMessage({
44741
44728
  from,
44742
- to,
44729
+ to: target_session_id ? `session:${target_session_id}` : to,
44743
44730
  content,
44744
44731
  priority,
44745
44732
  blocking,
44746
- project_id
44733
+ project_id,
44734
+ metadata: target_session_id ? { target_session_id } : undefined
44735
+ });
44736
+ return {
44737
+ content: [{ type: "text", text: JSON.stringify(msg) }]
44738
+ };
44739
+ });
44740
+ server.registerTool("send_to_session", {
44741
+ description: "Send a message to a specific agent-claude session by its session ID. The message will be auto-injected into that session's conversation via the channel bridge.",
44742
+ inputSchema: {
44743
+ target_session_id: exports_external2.string().describe("The agent-claude session ID (UUID) to send the message to"),
44744
+ content: exports_external2.string().describe("Message content to inject into the target session"),
44745
+ from: exports_external2.string().optional().describe("Sender agent name (defaults to CONVERSATIONS_AGENT_ID)"),
44746
+ priority: exports_external2.string().optional()
44747
+ }
44748
+ }, async (args) => {
44749
+ const { target_session_id, content, from: fromParam, priority } = args;
44750
+ const from = resolveIdentity(fromParam);
44751
+ const msg = sendMessage({
44752
+ from,
44753
+ to: `session:${target_session_id}`,
44754
+ content,
44755
+ priority,
44756
+ metadata: { target_session_id }
44747
44757
  });
44748
44758
  return {
44749
44759
  content: [{ type: "text", text: JSON.stringify(msg) }]
@@ -46918,55 +46928,73 @@ var init_cloud = __esm(() => {
46918
46928
  });
46919
46929
 
46920
46930
  // src/mcp/channel.ts
46921
- function registerChannelBridge(server, getAgentId) {
46931
+ function registerChannelBridge(server, getAgentId, getSessionId) {
46922
46932
  server.server.registerCapabilities({
46923
46933
  experimental: {
46924
46934
  "claude/channel": {}
46925
46935
  }
46926
46936
  });
46927
46937
  let lastSeenId = 0;
46938
+ let lastSeenSessionId = 0;
46928
46939
  let pollTimer = null;
46929
- function seedLastSeen(agentId) {
46930
- const latest = readMessages({
46931
- to: agentId,
46932
- order: "desc",
46933
- limit: 1
46940
+ function seedLastSeen(agentId, sessionId) {
46941
+ const latestAgent = readMessages({ to: agentId, order: "desc", limit: 1 });
46942
+ if (latestAgent.length > 0)
46943
+ lastSeenId = latestAgent[0].id;
46944
+ if (sessionId) {
46945
+ const latestSession = readMessages({ to: `session:${sessionId}`, order: "desc", limit: 1 });
46946
+ if (latestSession.length > 0)
46947
+ lastSeenSessionId = latestSession[0].id;
46948
+ }
46949
+ }
46950
+ function pushNotification(msg) {
46951
+ server.server.notification({
46952
+ method: "notifications/claude/channel",
46953
+ params: {
46954
+ content: msg.content,
46955
+ meta: {
46956
+ from: msg.from_agent,
46957
+ session_id: msg.session_id,
46958
+ ...msg.space ? { space: msg.space } : {},
46959
+ ...msg.priority && msg.priority !== "normal" ? { priority: msg.priority } : {}
46960
+ }
46961
+ }
46934
46962
  });
46935
- if (latest.length > 0) {
46936
- lastSeenId = latest[0].id;
46937
- }
46938
46963
  }
46939
46964
  function startPolling2() {
46940
46965
  if (pollTimer)
46941
46966
  return;
46942
46967
  const agentId = getAgentId();
46943
- if (!agentId)
46968
+ const sessionId = getSessionId();
46969
+ if (!agentId && !sessionId)
46944
46970
  return;
46945
- seedLastSeen(agentId);
46971
+ if (agentId)
46972
+ seedLastSeen(agentId, sessionId);
46946
46973
  pollTimer = setInterval(() => {
46947
- const currentAgent = getAgentId();
46948
- if (!currentAgent)
46949
- return;
46950
46974
  try {
46951
- const newMessages = readMessages({
46952
- to: currentAgent,
46953
- order: "asc",
46954
- limit: 20
46955
- }).filter((m) => m.id > lastSeenId);
46956
- for (const msg of newMessages) {
46957
- lastSeenId = msg.id;
46958
- server.server.notification({
46959
- method: "notifications/claude/channel",
46960
- params: {
46961
- content: msg.content,
46962
- meta: {
46963
- from: msg.from_agent,
46964
- session_id: msg.session_id,
46965
- ...msg.space ? { space: msg.space } : {},
46966
- ...msg.priority !== "normal" ? { priority: msg.priority } : {}
46967
- }
46968
- }
46969
- });
46975
+ const currentAgent = getAgentId();
46976
+ const currentSession = getSessionId();
46977
+ if (currentAgent) {
46978
+ const newAgentMsgs = readMessages({
46979
+ to: currentAgent,
46980
+ order: "asc",
46981
+ limit: 20
46982
+ }).filter((m) => m.id > lastSeenId);
46983
+ for (const msg of newAgentMsgs) {
46984
+ lastSeenId = msg.id;
46985
+ pushNotification(msg);
46986
+ }
46987
+ }
46988
+ if (currentSession) {
46989
+ const newSessionMsgs = readMessages({
46990
+ to: `session:${currentSession}`,
46991
+ order: "asc",
46992
+ limit: 20
46993
+ }).filter((m) => m.id > lastSeenSessionId);
46994
+ for (const msg of newSessionMsgs) {
46995
+ lastSeenSessionId = msg.id;
46996
+ pushNotification(msg);
46997
+ }
46970
46998
  }
46971
46999
  } catch {}
46972
47000
  }, POLL_INTERVAL_MS);
@@ -47131,7 +47159,7 @@ var init_mcp2 = __esm(() => {
47131
47159
  registerAgentTools(server, agentFocus, getAgentFocus);
47132
47160
  registerAdvancedTools(server, import__package2.default.version);
47133
47161
  registerTmuxTools(server);
47134
- registerChannelBridge(server, () => process.env.CONVERSATIONS_AGENT_ID ?? null);
47162
+ registerChannelBridge(server, () => process.env.CONVERSATIONS_AGENT_ID ?? null, () => process.env.CONVERSATIONS_SESSION_ID ?? null);
47135
47163
  isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp.js") || process.argv[1]?.endsWith("mcp.ts");
47136
47164
  if (isDirectRun) {
47137
47165
  startMcpServer().catch((error48) => {
@@ -48835,7 +48863,7 @@ init_presence();
48835
48863
  init_db();
48836
48864
  import chalk4 from "chalk";
48837
48865
  function registerMessagingCommands(program2) {
48838
- program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").option("--to <agent>", "Recipient agent ID (required unless --space is used)").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("--space <name>", "Send to a space instead of a specific agent").option("--blocking", "Send as a blocking message (recipient must acknowledge)").option("--json", "Output as JSON").action((message, opts) => {
48866
+ program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").option("--to <agent>", "Recipient agent ID (required unless --space is used)").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("--space <name>", "Send to a space instead of a specific agent").option("--blocking", "Send as a blocking message (recipient must acknowledge)").option("-j, --json", "Output as JSON").action((message, opts) => {
48839
48867
  const from = resolveIdentity(opts.from).trim();
48840
48868
  const to = typeof opts.to === "string" ? opts.to.trim() : "";
48841
48869
  const space = typeof opts.space === "string" ? opts.space.trim() : "";
@@ -48884,7 +48912,7 @@ function registerMessagingCommands(program2) {
48884
48912
  }
48885
48913
  closeDb();
48886
48914
  });
48887
- program2.command("read").description("Read messages").option("--session <id>", "Filter by session ID").option("--from <agent>", "Filter by sender").option("--to <agent>", "Filter by recipient").option("--space <name>", "Filter by space").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to return", parseInt).option("--unread", "Only unread messages").option("--mark-read", "Mark returned messages as read").option("--json", "Output as JSON").action((opts) => {
48915
+ program2.command("read").description("Read messages").option("--session <id>", "Filter by session ID").option("--from <agent>", "Filter by sender").option("--to <agent>", "Filter by recipient").option("--space <name>", "Filter by space").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to return", parseInt).option("--unread", "Only unread messages").option("--mark-read", "Mark returned messages as read").option("-j, --json", "Output as JSON").action((opts) => {
48888
48916
  const messages = readMessages({
48889
48917
  session_id: opts.session,
48890
48918
  from: opts.from,
@@ -48929,7 +48957,7 @@ function registerMessagingCommands(program2) {
48929
48957
  }
48930
48958
  closeDb();
48931
48959
  });
48932
- program2.command("digest").description("Show unread message digest (preview only, auto-marks read)").argument("[space]", "Space name to digest (omit for DMs)").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to show", parseInt).option("--to <agent>", "Filter by recipient (for DMs)").option("--json", "Output as JSON").action((spaceArg, opts) => {
48960
+ program2.command("digest").description("Show unread message digest (preview only, auto-marks read)").argument("[space]", "Space name to digest (omit for DMs)").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to show", parseInt).option("--to <agent>", "Filter by recipient (for DMs)").option("-j, --json", "Output as JSON").action((spaceArg, opts) => {
48933
48961
  const result = readDigest({
48934
48962
  space: spaceArg || undefined,
48935
48963
  since: opts.since,
@@ -48956,7 +48984,7 @@ function registerMessagingCommands(program2) {
48956
48984
  }
48957
48985
  closeDb();
48958
48986
  });
48959
- 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) => {
48987
+ 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("-j, --json", "Output as JSON").action((query, opts) => {
48960
48988
  const q = typeof query === "string" ? query.trim() : "";
48961
48989
  if (!q) {
48962
48990
  console.error(chalk4.red("Search query cannot be empty."));
@@ -48989,7 +49017,7 @@ function registerMessagingCommands(program2) {
48989
49017
  }
48990
49018
  closeDb();
48991
49019
  });
48992
- program2.command("since").description("Show all activity (DMs + spaces) since a duration ago").argument("<duration>", "Duration: e.g. 30m, 2h, 1d").option("--json", "Output as JSON").action((duration, opts) => {
49020
+ program2.command("since").description("Show all activity (DMs + spaces) since a duration ago").argument("<duration>", "Duration: e.g. 30m, 2h, 1d").option("-j, --json", "Output as JSON").action((duration, opts) => {
48993
49021
  const match = duration.match(/^(\d+)([mhd])$/);
48994
49022
  if (!match) {
48995
49023
  console.error(chalk4.red(`Invalid duration "${duration}". Use format: 30m, 2h, 1d`));
@@ -49023,7 +49051,7 @@ function registerMessagingCommands(program2) {
49023
49051
  }
49024
49052
  closeDb();
49025
49053
  });
49026
- 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) => {
49054
+ 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("-j, --json", "Output as JSON").action((message, opts) => {
49027
49055
  const original = getMessageById(opts.to);
49028
49056
  if (!original) {
49029
49057
  console.error(chalk4.red(`Message #${opts.to} not found.`));
@@ -49056,7 +49084,7 @@ function registerMessagingCommands(program2) {
49056
49084
  }
49057
49085
  closeDb();
49058
49086
  });
49059
- program2.command("mark-read").description("Mark messages as read").argument("[ids...]", "Message IDs to mark as read").option("--all", "Mark all messages as read").option("--session <id>", "Mark all messages in session as read").option("--space <name>", "Mark all messages in space as read").option("--agent <id>", "Agent marking messages as read").option("--json", "Output as JSON").action((ids, opts) => {
49087
+ program2.command("mark-read").description("Mark messages as read").argument("[ids...]", "Message IDs to mark as read").option("--all", "Mark all messages as read").option("--session <id>", "Mark all messages in session as read").option("--space <name>", "Mark all messages in space as read").option("--agent <id>", "Agent marking messages as read").option("-j, --json", "Output as JSON").action((ids, opts) => {
49060
49088
  const agent = resolveIdentity(opts.agent);
49061
49089
  let count = 0;
49062
49090
  if (opts.all) {
@@ -49091,7 +49119,7 @@ function registerMessagingCommands(program2) {
49091
49119
  console.log(result);
49092
49120
  closeDb();
49093
49121
  });
49094
- program2.command("edit").description("Edit a message (only sender can edit)").argument("<id>", "Message ID", parseInt).argument("<new-content>", "New message content").option("--from <agent>", "Sender agent ID").option("--json", "Output as JSON").action((id, newContent, opts) => {
49122
+ program2.command("edit").description("Edit a message (only sender can edit)").argument("<id>", "Message ID", parseInt).argument("<new-content>", "New message content").option("--from <agent>", "Sender agent ID").option("-j, --json", "Output as JSON").action((id, newContent, opts) => {
49095
49123
  const agent = resolveIdentity(opts.from).trim();
49096
49124
  const content = typeof newContent === "string" ? newContent : "";
49097
49125
  if (!agent) {
@@ -49115,7 +49143,7 @@ function registerMessagingCommands(program2) {
49115
49143
  }
49116
49144
  closeDb();
49117
49145
  });
49118
- 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) => {
49146
+ program2.command("delete").description("Delete a message (only sender can delete)").argument("<id>", "Message ID", parseInt).option("--from <agent>", "Sender agent ID").option("-j, --json", "Output as JSON").action((id, opts) => {
49119
49147
  const agent = resolveIdentity(opts.from).trim();
49120
49148
  if (!agent) {
49121
49149
  console.error(chalk4.red("Agent identity is required."));
@@ -49134,7 +49162,7 @@ function registerMessagingCommands(program2) {
49134
49162
  }
49135
49163
  closeDb();
49136
49164
  });
49137
- program2.command("pin").description("Pin a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
49165
+ program2.command("pin").description("Pin a message").argument("<id>", "Message ID", parseInt).option("-j, --json", "Output as JSON").action((id, opts) => {
49138
49166
  const msg = pinMessage(id);
49139
49167
  if (opts.json) {
49140
49168
  console.log(JSON.stringify(msg, null, 2));
@@ -49148,7 +49176,7 @@ function registerMessagingCommands(program2) {
49148
49176
  }
49149
49177
  closeDb();
49150
49178
  });
49151
- program2.command("unpin").description("Unpin a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
49179
+ program2.command("unpin").description("Unpin a message").argument("<id>", "Message ID", parseInt).option("-j, --json", "Output as JSON").action((id, opts) => {
49152
49180
  const msg = unpinMessage(id);
49153
49181
  if (opts.json) {
49154
49182
  console.log(JSON.stringify(msg, null, 2));
@@ -49162,7 +49190,7 @@ function registerMessagingCommands(program2) {
49162
49190
  }
49163
49191
  closeDb();
49164
49192
  });
49165
- program2.command("pinned").description("List pinned messages").option("--space <name>", "Filter by space").option("--session <id>", "Filter by session ID").option("--limit <n>", "Max results", parseInt).option("--json", "Output as JSON").action((opts) => {
49193
+ program2.command("pinned").description("List pinned messages").option("--space <name>", "Filter by space").option("--session <id>", "Filter by session ID").option("--limit <n>", "Max results", parseInt).option("-j, --json", "Output as JSON").action((opts) => {
49166
49194
  const messages = getPinnedMessages({ space: opts.space, session_id: opts.session, limit: opts.limit });
49167
49195
  if (opts.json) {
49168
49196
  console.log(JSON.stringify(messages, null, 2));
@@ -49182,7 +49210,7 @@ function registerMessagingCommands(program2) {
49182
49210
  }
49183
49211
  closeDb();
49184
49212
  });
49185
- program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("--json", "Output as JSON").action((opts) => {
49213
+ program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("-j, --json", "Output as JSON").action((opts) => {
49186
49214
  const agent = resolveIdentity(opts.from);
49187
49215
  const blockers = getUnreadBlockers(agent);
49188
49216
  if (opts.json) {
@@ -49311,7 +49339,7 @@ Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}
49311
49339
  process.exit(0);
49312
49340
  });
49313
49341
  });
49314
- program2.command("update").description("Check for and install updates").option("--check", "Only check for updates, don't install").option("--json", "Output as JSON").action(async (opts) => {
49342
+ program2.command("update").description("Check for and install updates").option("--check", "Only check for updates, don't install").option("-j, --json", "Output as JSON").action(async (opts) => {
49315
49343
  const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
49316
49344
  const current = pkg.version;
49317
49345
  let latest;
@@ -49376,7 +49404,7 @@ init_terminal_markdown();
49376
49404
  import chalk5 from "chalk";
49377
49405
  function registerSpaceCommands(program2) {
49378
49406
  const space = program2.command("space").description("Manage spaces");
49379
- space.command("create").description("Create a new space").argument("<name>", "Space name").option("--description <text>", "Space description").option("--parent <name>", "Parent space name (for nesting)").option("--project <id>", "Project ID to associate with").option("--from <agent>", "Creator agent ID").option("--json", "Output as JSON").action((name, opts) => {
49407
+ space.command("create").description("Create a new space").argument("<name>", "Space name").option("--description <text>", "Space description").option("--parent <name>", "Parent space name (for nesting)").option("--project <id>", "Project ID to associate with").option("--from <agent>", "Creator agent ID").option("-j, --json", "Output as JSON").action((name, opts) => {
49380
49408
  const agent = resolveIdentity(opts.from).trim();
49381
49409
  const spaceName = typeof name === "string" ? name.trim() : "";
49382
49410
  if (!agent) {
@@ -49409,7 +49437,7 @@ function registerSpaceCommands(program2) {
49409
49437
  }
49410
49438
  closeDb();
49411
49439
  });
49412
- space.command("list").description("List all spaces").option("--project <id>", "Filter by project ID").option("--parent <name>", "Filter by parent space name").option("--top-level", "Show only top-level spaces").option("--archived", "Include archived spaces").option("--json", "Output as JSON").action((opts) => {
49440
+ space.command("list").description("List all spaces").option("--project <id>", "Filter by project ID").option("--parent <name>", "Filter by parent space name").option("--top-level", "Show only top-level spaces").option("--archived", "Include archived spaces").option("-j, --json", "Output as JSON").action((opts) => {
49413
49441
  const listOpts = {};
49414
49442
  if (opts.project)
49415
49443
  listOpts.project_id = opts.project;
@@ -49437,7 +49465,7 @@ function registerSpaceCommands(program2) {
49437
49465
  }
49438
49466
  closeDb();
49439
49467
  });
49440
- 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) => {
49468
+ 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("-j, --json", "Output as JSON").action((name, opts) => {
49441
49469
  const spaceName = typeof name === "string" ? name.trim() : "";
49442
49470
  if (!spaceName) {
49443
49471
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49463,7 +49491,7 @@ function registerSpaceCommands(program2) {
49463
49491
  }
49464
49492
  closeDb();
49465
49493
  });
49466
- space.command("archive").description("Archive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
49494
+ space.command("archive").description("Archive a space").argument("<name>", "Space name").option("-j, --json", "Output as JSON").action((name, opts) => {
49467
49495
  const spaceName = typeof name === "string" ? name.trim() : "";
49468
49496
  if (!spaceName) {
49469
49497
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49482,7 +49510,7 @@ function registerSpaceCommands(program2) {
49482
49510
  }
49483
49511
  closeDb();
49484
49512
  });
49485
- space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
49513
+ space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("-j, --json", "Output as JSON").action((name, opts) => {
49486
49514
  const spaceName = typeof name === "string" ? name.trim() : "";
49487
49515
  if (!spaceName) {
49488
49516
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49501,7 +49529,7 @@ function registerSpaceCommands(program2) {
49501
49529
  }
49502
49530
  closeDb();
49503
49531
  });
49504
- space.command("send").description("Send a message to a space").argument("<space>", "Space name").argument("<message>", "Message content").option("--from <agent>", "Sender agent ID").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--json", "Output as JSON").action((spaceName, message, opts) => {
49532
+ space.command("send").description("Send a message to a space").argument("<space>", "Space name").argument("<message>", "Message content").option("--from <agent>", "Sender agent ID").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("-j, --json", "Output as JSON").action((spaceName, message, opts) => {
49505
49533
  const from = resolveIdentity(opts.from).trim();
49506
49534
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49507
49535
  const content = typeof message === "string" ? message : "";
@@ -49537,7 +49565,7 @@ function registerSpaceCommands(program2) {
49537
49565
  }
49538
49566
  closeDb();
49539
49567
  });
49540
- 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) => {
49568
+ 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("-j, --json", "Output as JSON").action((spaceName, opts) => {
49541
49569
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49542
49570
  if (!spaceArg) {
49543
49571
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49569,7 +49597,7 @@ function registerSpaceCommands(program2) {
49569
49597
  }
49570
49598
  closeDb();
49571
49599
  });
49572
- space.command("join").description("Join a space").argument("<space>", "Space name").option("--from <agent>", "Agent ID").option("--json", "Output as JSON").action((spaceName, opts) => {
49600
+ space.command("join").description("Join a space").argument("<space>", "Space name").option("--from <agent>", "Agent ID").option("-j, --json", "Output as JSON").action((spaceName, opts) => {
49573
49601
  const agent = resolveIdentity(opts.from).trim();
49574
49602
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49575
49603
  if (!agent) {
@@ -49592,7 +49620,7 @@ function registerSpaceCommands(program2) {
49592
49620
  }
49593
49621
  closeDb();
49594
49622
  });
49595
- space.command("leave").description("Leave a space").argument("<space>", "Space name").option("--from <agent>", "Agent ID").option("--json", "Output as JSON").action((spaceName, opts) => {
49623
+ space.command("leave").description("Leave a space").argument("<space>", "Space name").option("--from <agent>", "Agent ID").option("-j, --json", "Output as JSON").action((spaceName, opts) => {
49596
49624
  const agent = resolveIdentity(opts.from).trim();
49597
49625
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49598
49626
  if (!agent) {
@@ -49615,7 +49643,7 @@ function registerSpaceCommands(program2) {
49615
49643
  }
49616
49644
  closeDb();
49617
49645
  });
49618
- space.command("members").description("List space members").argument("<space>", "Space name").option("--json", "Output as JSON").action((spaceName, opts) => {
49646
+ space.command("members").description("List space members").argument("<space>", "Space name").option("-j, --json", "Output as JSON").action((spaceName, opts) => {
49619
49647
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49620
49648
  if (!spaceArg) {
49621
49649
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49648,9 +49676,20 @@ function requireDeleteConfirmation(confirmed) {
49648
49676
  throw new Error("Project deletion requires --yes confirmation");
49649
49677
  }
49650
49678
  }
49679
+ function parseProjectListPagination(limitInput, offsetInput) {
49680
+ if (limitInput !== undefined && (!Number.isFinite(limitInput) || Number(limitInput) <= 0)) {
49681
+ throw new Error("--limit must be a positive integer.");
49682
+ }
49683
+ if (offsetInput !== undefined && (!Number.isFinite(offsetInput) || Number(offsetInput) < 0)) {
49684
+ throw new Error("--offset must be a non-negative integer.");
49685
+ }
49686
+ const limit = Number.isFinite(limitInput) ? Math.floor(Number(limitInput)) : undefined;
49687
+ const offset = Number.isFinite(offsetInput) ? Math.floor(Number(offsetInput)) : undefined;
49688
+ return { limit, offset };
49689
+ }
49651
49690
  function registerProjectCommands(program2) {
49652
49691
  const project = program2.command("project").description("Manage projects");
49653
- project.command("create").description("Create a new project").argument("<name>", "Project name").option("--description <text>", "Project description").option("--path <path>", "Project path on disk").option("--repository <url>", "Repository URL").option("--tags <json>", "JSON array of tags").option("--from <agent>", "Creator agent ID").option("--json", "Output as JSON").action((name, opts) => {
49692
+ project.command("create").description("Create a new project").argument("<name>", "Project name").option("--description <text>", "Project description").option("--path <path>", "Project path on disk").option("--repository <url>", "Repository URL").option("--tags <json>", "JSON array of tags").option("--from <agent>", "Creator agent ID").option("-j, --json", "Output as JSON").action((name, opts) => {
49654
49693
  const agent = resolveIdentity(opts.from).trim();
49655
49694
  const projectName = typeof name === "string" ? name.trim() : "";
49656
49695
  if (!agent) {
@@ -49694,10 +49733,16 @@ function registerProjectCommands(program2) {
49694
49733
  }
49695
49734
  closeDb();
49696
49735
  });
49697
- project.command("list").description("List all projects").option("--status <status>", "Filter by status (active/archived)").option("--limit <n>", "Limit results", parseInt).option("--offset <n>", "Skip first N results", parseInt).option("--json", "Output as JSON").action((opts) => {
49736
+ project.command("list").description("List all projects").option("--status <status>", "Filter by status (active/archived)").option("--limit <n>", "Limit results", parseInt).option("--offset <n>", "Skip first N results", parseInt).option("-j, --json", "Output as JSON").action((opts) => {
49698
49737
  const status = opts.status === "active" || opts.status === "archived" ? opts.status : undefined;
49699
- const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? opts.limit : undefined;
49700
- const offset = Number.isFinite(opts.offset) && opts.offset >= 0 ? opts.offset : undefined;
49738
+ let limit;
49739
+ let offset;
49740
+ try {
49741
+ ({ limit, offset } = parseProjectListPagination(opts.limit, opts.offset));
49742
+ } catch (e) {
49743
+ console.error(chalk6.red(e.message));
49744
+ process.exit(1);
49745
+ }
49701
49746
  const projects = listProjects({
49702
49747
  ...status ? { status } : {},
49703
49748
  ...limit !== undefined ? { limit } : {},
@@ -49718,7 +49763,7 @@ function registerProjectCommands(program2) {
49718
49763
  }
49719
49764
  closeDb();
49720
49765
  });
49721
- project.command("get").description("Get project details").argument("<id-or-name>", "Project ID or name").option("--json", "Output as JSON").action((idOrName, opts) => {
49766
+ project.command("get").description("Get project details").argument("<id-or-name>", "Project ID or name").option("-j, --json", "Output as JSON").action((idOrName, opts) => {
49722
49767
  let p = getProject(idOrName);
49723
49768
  if (!p)
49724
49769
  p = getProjectByName(idOrName);
@@ -49744,7 +49789,7 @@ function registerProjectCommands(program2) {
49744
49789
  }
49745
49790
  closeDb();
49746
49791
  });
49747
- project.command("update").description("Update a project").argument("<id-or-name>", "Project ID or name").option("--name <name>", "New name").option("--description <text>", "New description").option("--path <path>", "New path").option("--status <status>", "New status (active/archived)").option("--repository <url>", "New repository URL").option("--tags <json>", "New tags (JSON array)").option("--json", "Output as JSON").action((id, opts) => {
49792
+ project.command("update").description("Update a project").argument("<id-or-name>", "Project ID or name").option("--name <name>", "New name").option("--description <text>", "New description").option("--path <path>", "New path").option("--status <status>", "New status (active/archived)").option("--repository <url>", "New repository URL").option("--tags <json>", "New tags (JSON array)").option("-j, --json", "Output as JSON").action((id, opts) => {
49748
49793
  const updates = {};
49749
49794
  if (opts.name)
49750
49795
  updates.name = opts.name;
@@ -49779,7 +49824,7 @@ function registerProjectCommands(program2) {
49779
49824
  }
49780
49825
  closeDb();
49781
49826
  });
49782
- project.command("delete").description("Delete a project").argument("<id-or-name>", "Project ID or name").option("--yes", "Confirm project deletion").option("--json", "Output as JSON").action((id, opts) => {
49827
+ project.command("delete").description("Delete a project").argument("<id-or-name>", "Project ID or name").option("--yes", "Confirm project deletion").option("-j, --json", "Output as JSON").action((id, opts) => {
49783
49828
  try {
49784
49829
  requireDeleteConfirmation(opts.yes);
49785
49830
  const isUuid = /^[0-9a-f-]{36}$/i.test(id);
@@ -49834,7 +49879,7 @@ function buildWhoamiPayload(agent, source, presence, nowMs = Date.now()) {
49834
49879
  }
49835
49880
  function registerAgentCommands(program2) {
49836
49881
  const agents = program2.command("agents").description("Manage agents");
49837
- agents.command("list").description("List all agents with their presence status").option("--online", "Only show online agents").option("--json", "Output as JSON").action((opts) => {
49882
+ agents.command("list").description("List all agents with their presence status").option("--online", "Only show online agents").option("-j, --json", "Output as JSON").action((opts) => {
49838
49883
  const agent = resolveIdentity();
49839
49884
  heartbeat(agent);
49840
49885
  const agentsList = listAgents({ online_only: opts.online });
@@ -49854,7 +49899,7 @@ function registerAgentCommands(program2) {
49854
49899
  }
49855
49900
  closeDb();
49856
49901
  });
49857
- 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) => {
49902
+ agents.command("remove").description("Remove an agent from the presence list").argument("<name>", "Agent name to remove").option("-j, --json", "Output as JSON").action((name, opts) => {
49858
49903
  const agentName = typeof name === "string" ? name.trim() : "";
49859
49904
  if (!agentName) {
49860
49905
  console.error(chalk7.red("Agent name cannot be empty."));
@@ -49873,7 +49918,7 @@ function registerAgentCommands(program2) {
49873
49918
  }
49874
49919
  closeDb();
49875
49920
  });
49876
- agents.command("rename").description("Rename an agent in the presence list").argument("<old-name>", "Current agent name").argument("<new-name>", "New agent name").option("--json", "Output as JSON").action((oldName, newName, opts) => {
49921
+ agents.command("rename").description("Rename an agent in the presence list").argument("<old-name>", "Current agent name").argument("<new-name>", "New agent name").option("-j, --json", "Output as JSON").action((oldName, newName, opts) => {
49877
49922
  const old = typeof oldName === "string" ? oldName.trim() : "";
49878
49923
  const renamed = typeof newName === "string" ? newName.trim() : "";
49879
49924
  if (!old || !renamed) {
@@ -49897,7 +49942,7 @@ function registerAgentCommands(program2) {
49897
49942
  }
49898
49943
  closeDb();
49899
49944
  });
49900
- agents.command("register").description("Register an agent with conflict detection (30 min active window)").argument("<name>", "Agent name to register").option("--session <id>", "Session ID (default: random UUID)").option("--role <role>", "Agent role (default: agent)").option("--project <id>", "Project ID to lock agent to").option("--force", "Force takeover even if another session is active").option("--json", "Output as JSON").action((name, opts) => {
49945
+ agents.command("register").description("Register an agent with conflict detection (30 min active window)").argument("<name>", "Agent name to register").option("--session <id>", "Session ID (default: random UUID)").option("--role <role>", "Agent role (default: agent)").option("--project <id>", "Project ID to lock agent to").option("--force", "Force takeover even if another session is active").option("-j, --json", "Output as JSON").action((name, opts) => {
49901
49946
  const agentName = (typeof name === "string" ? name : "").trim();
49902
49947
  if (!agentName) {
49903
49948
  console.error(chalk7.red("Agent name is required."));
@@ -49922,7 +49967,7 @@ function registerAgentCommands(program2) {
49922
49967
  }
49923
49968
  closeDb();
49924
49969
  });
49925
- agents.command("heartbeat").description("Send a presence heartbeat to mark yourself as active").option("--from <agent>", "Agent identity (default: CONVERSATIONS_AGENT_ID or auto)").option("--status <status>", "Status: online, busy, idle (default: online)").option("--json", "Output as JSON").action((opts) => {
49970
+ agents.command("heartbeat").description("Send a presence heartbeat to mark yourself as active").option("--from <agent>", "Agent identity (default: CONVERSATIONS_AGENT_ID or auto)").option("--status <status>", "Status: online, busy, idle (default: online)").option("-j, --json", "Output as JSON").action((opts) => {
49926
49971
  const agent = resolveIdentity(opts.from);
49927
49972
  const status = opts.status || "online";
49928
49973
  heartbeat(agent, status);
@@ -49934,7 +49979,7 @@ function registerAgentCommands(program2) {
49934
49979
  closeDb();
49935
49980
  });
49936
49981
  const focus = program2.command("focus").description("Manage agent project focus");
49937
- focus.command("set").description("Set your project focus \u2014 scopes read operations to this project").argument("<project>", "Project ID or name").option("--from <agent>", "Agent identity").option("--json", "Output as JSON").action((projectArg, opts) => {
49982
+ focus.command("set").description("Set your project focus \u2014 scopes read operations to this project").argument("<project>", "Project ID or name").option("--from <agent>", "Agent identity").option("-j, --json", "Output as JSON").action((projectArg, opts) => {
49938
49983
  const agent = resolveIdentity(opts.from);
49939
49984
  const project = getProject(projectArg) || getProjectByName(projectArg);
49940
49985
  if (!project) {
@@ -49949,7 +49994,7 @@ function registerAgentCommands(program2) {
49949
49994
  }
49950
49995
  closeDb();
49951
49996
  });
49952
- focus.command("clear").description("Clear your project focus").option("--from <agent>", "Agent identity").option("--json", "Output as JSON").action((opts) => {
49997
+ focus.command("clear").description("Clear your project focus").option("--from <agent>", "Agent identity").option("-j, --json", "Output as JSON").action((opts) => {
49953
49998
  const agent = resolveIdentity(opts.from);
49954
49999
  getDb().prepare("UPDATE agent_presence SET project_id = NULL WHERE agent = ?").run(agent);
49955
50000
  if (opts.json) {
@@ -49959,7 +50004,7 @@ function registerAgentCommands(program2) {
49959
50004
  }
49960
50005
  closeDb();
49961
50006
  });
49962
- focus.command("get").description("Show current project focus").option("--from <agent>", "Agent identity").option("--json", "Output as JSON").action((opts) => {
50007
+ focus.command("get").description("Show current project focus").option("--from <agent>", "Agent identity").option("-j, --json", "Output as JSON").action((opts) => {
49963
50008
  const agent = resolveIdentity(opts.from);
49964
50009
  const presence = getPresence(agent);
49965
50010
  const projectId = presence?.project_id ?? null;
@@ -49976,7 +50021,7 @@ function registerAgentCommands(program2) {
49976
50021
  }
49977
50022
  closeDb();
49978
50023
  });
49979
- program2.command("whoami").description("Show current agent identity and online status").option("--from <agent>", "Explicit agent identity").option("--json", "Output as JSON").action((opts) => {
50024
+ program2.command("whoami").description("Show current agent identity and online status").option("--from <agent>", "Explicit agent identity").option("-j, --json", "Output as JSON").action((opts) => {
49980
50025
  const envValue = process.env.CONVERSATIONS_AGENT_ID?.trim();
49981
50026
  const agent = resolveIdentity(opts.from);
49982
50027
  let source;
@@ -50030,7 +50075,7 @@ var import__package = __toESM(require_package(), 1);
50030
50075
  import chalk8 from "chalk";
50031
50076
  function registerAnalyticsCommands(program2) {
50032
50077
  const graph = program2.command("graph").description("Knowledge graph operations");
50033
- graph.command("build").description("Build/rebuild knowledge graph from messages, spaces, projects").option("--json", "Output as JSON").action((opts) => {
50078
+ graph.command("build").description("Build/rebuild knowledge graph from messages, spaces, projects").option("-j, --json", "Output as JSON").action((opts) => {
50034
50079
  const result = buildGraph();
50035
50080
  if (opts.json) {
50036
50081
  console.log(JSON.stringify(result, null, 2));
@@ -50039,7 +50084,7 @@ function registerAnalyticsCommands(program2) {
50039
50084
  }
50040
50085
  closeDb();
50041
50086
  });
50042
- graph.command("stats").description("Show knowledge graph statistics").option("--json", "Output as JSON").action((opts) => {
50087
+ graph.command("stats").description("Show knowledge graph statistics").option("-j, --json", "Output as JSON").action((opts) => {
50043
50088
  const stats = getGraphStats();
50044
50089
  if (opts.json) {
50045
50090
  console.log(JSON.stringify(stats, null, 2));
@@ -50052,7 +50097,7 @@ function registerAnalyticsCommands(program2) {
50052
50097
  }
50053
50098
  closeDb();
50054
50099
  });
50055
- graph.command("agent").description("Show an agent's communication network").argument("<name>", "Agent name").option("--json", "Output as JSON").action((name, opts) => {
50100
+ graph.command("agent").description("Show an agent's communication network").argument("<name>", "Agent name").option("-j, --json", "Output as JSON").action((name, opts) => {
50056
50101
  const network = getAgentNetwork(name);
50057
50102
  if (opts.json) {
50058
50103
  console.log(JSON.stringify(network, null, 2));
@@ -50077,7 +50122,7 @@ function registerAnalyticsCommands(program2) {
50077
50122
  }
50078
50123
  closeDb();
50079
50124
  });
50080
- program2.command("summary").description("Get a structured summary of a conversation").argument("<target>", "Session ID or space name").option("--json", "Output as JSON").action((target, opts) => {
50125
+ program2.command("summary").description("Get a structured summary of a conversation").argument("<target>", "Session ID or space name").option("-j, --json", "Output as JSON").action((target, opts) => {
50081
50126
  const summary = getConversationSummary(target);
50082
50127
  if (!summary) {
50083
50128
  console.error(chalk8.red(`No messages found for "${target}"`));
@@ -50113,7 +50158,7 @@ function registerAnalyticsCommands(program2) {
50113
50158
  }
50114
50159
  closeDb();
50115
50160
  });
50116
- program2.command("topics").description("Extract topics from a space, session, or trending globally").option("--space <name>", "Topics for a specific space").option("--session <id>", "Topics for a specific session").option("--hours <n>", "Trending topics in last N hours", parseInt).option("--json", "Output as JSON").action((opts) => {
50161
+ program2.command("topics").description("Extract topics from a space, session, or trending globally").option("--space <name>", "Topics for a specific space").option("--session <id>", "Topics for a specific session").option("--hours <n>", "Trending topics in last N hours", parseInt).option("-j, --json", "Output as JSON").action((opts) => {
50117
50162
  let topics;
50118
50163
  if (opts.space) {
50119
50164
  topics = getSpaceTopics(opts.space);
@@ -50139,7 +50184,7 @@ function registerAnalyticsCommands(program2) {
50139
50184
  }
50140
50185
  closeDb();
50141
50186
  });
50142
- program2.command("hot").description("Show hot conversations ranked by activity").option("--limit <n>", "Max results", parseInt).option("--min-score <n>", "Minimum hotness score", parseInt).option("--space <name>", "Filter by space").option("--json", "Output as JSON").action((opts) => {
50187
+ program2.command("hot").description("Show hot conversations ranked by activity").option("--limit <n>", "Max results", parseInt).option("--min-score <n>", "Minimum hotness score", parseInt).option("--space <name>", "Filter by space").option("-j, --json", "Output as JSON").action((opts) => {
50143
50188
  const sessions = listHotSessions({
50144
50189
  limit: opts.limit ?? 10,
50145
50190
  min_score: opts.minScore,
@@ -50165,7 +50210,7 @@ function registerAnalyticsCommands(program2) {
50165
50210
  }
50166
50211
  closeDb();
50167
50212
  });
50168
- program2.command("context").description("One-shot session boot context for agents: online agents, unread DMs, spaces, recent activity").option("--json", "Output as JSON").action((opts) => {
50213
+ program2.command("context").description("One-shot session boot context for agents: online agents, unread DMs, spaces, recent activity").option("-j, --json", "Output as JSON").action((opts) => {
50169
50214
  const agent = resolveIdentity();
50170
50215
  heartbeat(agent);
50171
50216
  const db2 = getDb();
@@ -50212,7 +50257,7 @@ function registerAnalyticsCommands(program2) {
50212
50257
  }
50213
50258
  closeDb();
50214
50259
  });
50215
- program2.command("sessions").description("List conversation sessions").option("--agent <id>", "Filter sessions involving this agent").option("--json", "Output as JSON").action((opts) => {
50260
+ program2.command("sessions").description("List conversation sessions").option("--agent <id>", "Filter sessions involving this agent").option("-j, --json", "Output as JSON").action((opts) => {
50216
50261
  const sessions = listSessions(opts.agent);
50217
50262
  if (opts.json) {
50218
50263
  console.log(JSON.stringify(sessions, null, 2));
@@ -50229,7 +50274,7 @@ function registerAnalyticsCommands(program2) {
50229
50274
  }
50230
50275
  closeDb();
50231
50276
  });
50232
- program2.command("status").description("Show database stats").option("--json", "Output as JSON").action((opts) => {
50277
+ program2.command("status").description("Show database stats").option("-j, --json", "Output as JSON").action((opts) => {
50233
50278
  const db2 = getDb();
50234
50279
  const dbPath = getDbPath2();
50235
50280
  const totalMessages = db2.prepare("SELECT COUNT(*) as count FROM messages").get().count;
@@ -50258,7 +50303,7 @@ function registerAnalyticsCommands(program2) {
50258
50303
  }
50259
50304
  closeDb();
50260
50305
  });
50261
- program2.command("doctor").description("Check conversations setup and health").option("--json", "Output as JSON").action(async (opts) => {
50306
+ program2.command("doctor").description("Check conversations setup and health").option("-j, --json", "Output as JSON").action(async (opts) => {
50262
50307
  const checks = [];
50263
50308
  try {
50264
50309
  const db2 = getDb();
@@ -50332,7 +50377,7 @@ function registerAnalyticsCommands(program2) {
50332
50377
  }
50333
50378
  }
50334
50379
  });
50335
- program2.command("react").description("Add an emoji reaction to a message").argument("<id>", "Message ID", parseInt).argument("<emoji>", "Emoji to react with").option("--from <agent>", "Agent identity override").option("--json", "Output as JSON").action((id, emoji, opts) => {
50380
+ program2.command("react").description("Add an emoji reaction to a message").argument("<id>", "Message ID", parseInt).argument("<emoji>", "Emoji to react with").option("--from <agent>", "Agent identity override").option("-j, --json", "Output as JSON").action((id, emoji, opts) => {
50336
50381
  const agent = resolveIdentity(opts.from);
50337
50382
  const reaction = addReaction(id, agent, emoji);
50338
50383
  if (opts.json) {
@@ -50342,7 +50387,7 @@ function registerAnalyticsCommands(program2) {
50342
50387
  }
50343
50388
  closeDb();
50344
50389
  });
50345
- program2.command("unreact").description("Remove an emoji reaction from a message").argument("<id>", "Message ID", parseInt).argument("<emoji>", "Emoji to remove").option("--from <agent>", "Agent identity override").option("--json", "Output as JSON").action((id, emoji, opts) => {
50390
+ program2.command("unreact").description("Remove an emoji reaction from a message").argument("<id>", "Message ID", parseInt).argument("<emoji>", "Emoji to remove").option("--from <agent>", "Agent identity override").option("-j, --json", "Output as JSON").action((id, emoji, opts) => {
50346
50391
  const agent = resolveIdentity(opts.from);
50347
50392
  const removed = removeReaction(id, agent, emoji);
50348
50393
  if (opts.json) {
@@ -50356,7 +50401,7 @@ function registerAnalyticsCommands(program2) {
50356
50401
  }
50357
50402
  closeDb();
50358
50403
  });
50359
- program2.command("reactions").description("Show emoji reactions on a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
50404
+ program2.command("reactions").description("Show emoji reactions on a message").argument("<id>", "Message ID", parseInt).option("-j, --json", "Output as JSON").action((id, opts) => {
50360
50405
  const summary = getReactionSummary(id);
50361
50406
  if (opts.json) {
50362
50407
  console.log(JSON.stringify(summary, null, 2));