@hasna/conversations 0.2.33 → 0.2.34

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
@@ -14928,7 +14928,7 @@ var init_presence = __esm(() => {
14928
14928
  var require_package = __commonJS((exports, module) => {
14929
14929
  module.exports = {
14930
14930
  name: "@hasna/conversations",
14931
- version: "0.2.33",
14931
+ version: "0.2.34",
14932
14932
  description: "Real-time CLI messaging for AI agents",
14933
14933
  type: "module",
14934
14934
  bin: {
@@ -15769,7 +15769,7 @@ async function tmuxSend(target, message, opts = {}) {
15769
15769
  }
15770
15770
  function registerTmuxCommands(program2) {
15771
15771
  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) => {
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("-j, --json", "Output result as JSON").action(async (opts) => {
15773
15773
  const target = opts.target.trim();
15774
15774
  const message = opts.message;
15775
15775
  if (!target) {
@@ -15804,7 +15804,7 @@ function registerTmuxCommands(program2) {
15804
15804
  process.exit(1);
15805
15805
  }
15806
15806
  });
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) => {
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("-j, --json", "Output results as JSON").action(async (opts) => {
15808
15808
  const targets = opts.targets.split(",").map((t) => t.trim()).filter(Boolean);
15809
15809
  const message = opts.message;
15810
15810
  const stagger = Number.isFinite(opts.stagger) && opts.stagger >= 0 ? opts.stagger : 500;
@@ -48835,7 +48835,7 @@ init_presence();
48835
48835
  init_db();
48836
48836
  import chalk4 from "chalk";
48837
48837
  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) => {
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("-j, --json", "Output as JSON").action((message, opts) => {
48839
48839
  const from = resolveIdentity(opts.from).trim();
48840
48840
  const to = typeof opts.to === "string" ? opts.to.trim() : "";
48841
48841
  const space = typeof opts.space === "string" ? opts.space.trim() : "";
@@ -48884,7 +48884,7 @@ function registerMessagingCommands(program2) {
48884
48884
  }
48885
48885
  closeDb();
48886
48886
  });
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) => {
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("-j, --json", "Output as JSON").action((opts) => {
48888
48888
  const messages = readMessages({
48889
48889
  session_id: opts.session,
48890
48890
  from: opts.from,
@@ -48929,7 +48929,7 @@ function registerMessagingCommands(program2) {
48929
48929
  }
48930
48930
  closeDb();
48931
48931
  });
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) => {
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("-j, --json", "Output as JSON").action((spaceArg, opts) => {
48933
48933
  const result = readDigest({
48934
48934
  space: spaceArg || undefined,
48935
48935
  since: opts.since,
@@ -48956,7 +48956,7 @@ function registerMessagingCommands(program2) {
48956
48956
  }
48957
48957
  closeDb();
48958
48958
  });
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) => {
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("-j, --json", "Output as JSON").action((query, opts) => {
48960
48960
  const q = typeof query === "string" ? query.trim() : "";
48961
48961
  if (!q) {
48962
48962
  console.error(chalk4.red("Search query cannot be empty."));
@@ -48989,7 +48989,7 @@ function registerMessagingCommands(program2) {
48989
48989
  }
48990
48990
  closeDb();
48991
48991
  });
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) => {
48992
+ 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
48993
  const match = duration.match(/^(\d+)([mhd])$/);
48994
48994
  if (!match) {
48995
48995
  console.error(chalk4.red(`Invalid duration "${duration}". Use format: 30m, 2h, 1d`));
@@ -49023,7 +49023,7 @@ function registerMessagingCommands(program2) {
49023
49023
  }
49024
49024
  closeDb();
49025
49025
  });
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) => {
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("-j, --json", "Output as JSON").action((message, opts) => {
49027
49027
  const original = getMessageById(opts.to);
49028
49028
  if (!original) {
49029
49029
  console.error(chalk4.red(`Message #${opts.to} not found.`));
@@ -49056,7 +49056,7 @@ function registerMessagingCommands(program2) {
49056
49056
  }
49057
49057
  closeDb();
49058
49058
  });
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) => {
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("-j, --json", "Output as JSON").action((ids, opts) => {
49060
49060
  const agent = resolveIdentity(opts.agent);
49061
49061
  let count = 0;
49062
49062
  if (opts.all) {
@@ -49091,7 +49091,7 @@ function registerMessagingCommands(program2) {
49091
49091
  console.log(result);
49092
49092
  closeDb();
49093
49093
  });
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) => {
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("-j, --json", "Output as JSON").action((id, newContent, opts) => {
49095
49095
  const agent = resolveIdentity(opts.from).trim();
49096
49096
  const content = typeof newContent === "string" ? newContent : "";
49097
49097
  if (!agent) {
@@ -49115,7 +49115,7 @@ function registerMessagingCommands(program2) {
49115
49115
  }
49116
49116
  closeDb();
49117
49117
  });
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) => {
49118
+ 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
49119
  const agent = resolveIdentity(opts.from).trim();
49120
49120
  if (!agent) {
49121
49121
  console.error(chalk4.red("Agent identity is required."));
@@ -49134,7 +49134,7 @@ function registerMessagingCommands(program2) {
49134
49134
  }
49135
49135
  closeDb();
49136
49136
  });
49137
- program2.command("pin").description("Pin a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
49137
+ program2.command("pin").description("Pin a message").argument("<id>", "Message ID", parseInt).option("-j, --json", "Output as JSON").action((id, opts) => {
49138
49138
  const msg = pinMessage(id);
49139
49139
  if (opts.json) {
49140
49140
  console.log(JSON.stringify(msg, null, 2));
@@ -49148,7 +49148,7 @@ function registerMessagingCommands(program2) {
49148
49148
  }
49149
49149
  closeDb();
49150
49150
  });
49151
- program2.command("unpin").description("Unpin a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
49151
+ program2.command("unpin").description("Unpin a message").argument("<id>", "Message ID", parseInt).option("-j, --json", "Output as JSON").action((id, opts) => {
49152
49152
  const msg = unpinMessage(id);
49153
49153
  if (opts.json) {
49154
49154
  console.log(JSON.stringify(msg, null, 2));
@@ -49162,7 +49162,7 @@ function registerMessagingCommands(program2) {
49162
49162
  }
49163
49163
  closeDb();
49164
49164
  });
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) => {
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("-j, --json", "Output as JSON").action((opts) => {
49166
49166
  const messages = getPinnedMessages({ space: opts.space, session_id: opts.session, limit: opts.limit });
49167
49167
  if (opts.json) {
49168
49168
  console.log(JSON.stringify(messages, null, 2));
@@ -49182,7 +49182,7 @@ function registerMessagingCommands(program2) {
49182
49182
  }
49183
49183
  closeDb();
49184
49184
  });
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) => {
49185
+ 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
49186
  const agent = resolveIdentity(opts.from);
49187
49187
  const blockers = getUnreadBlockers(agent);
49188
49188
  if (opts.json) {
@@ -49311,7 +49311,7 @@ Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}
49311
49311
  process.exit(0);
49312
49312
  });
49313
49313
  });
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) => {
49314
+ 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
49315
  const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
49316
49316
  const current = pkg.version;
49317
49317
  let latest;
@@ -49376,7 +49376,7 @@ init_terminal_markdown();
49376
49376
  import chalk5 from "chalk";
49377
49377
  function registerSpaceCommands(program2) {
49378
49378
  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) => {
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("-j, --json", "Output as JSON").action((name, opts) => {
49380
49380
  const agent = resolveIdentity(opts.from).trim();
49381
49381
  const spaceName = typeof name === "string" ? name.trim() : "";
49382
49382
  if (!agent) {
@@ -49409,7 +49409,7 @@ function registerSpaceCommands(program2) {
49409
49409
  }
49410
49410
  closeDb();
49411
49411
  });
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) => {
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("-j, --json", "Output as JSON").action((opts) => {
49413
49413
  const listOpts = {};
49414
49414
  if (opts.project)
49415
49415
  listOpts.project_id = opts.project;
@@ -49437,7 +49437,7 @@ function registerSpaceCommands(program2) {
49437
49437
  }
49438
49438
  closeDb();
49439
49439
  });
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) => {
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("-j, --json", "Output as JSON").action((name, opts) => {
49441
49441
  const spaceName = typeof name === "string" ? name.trim() : "";
49442
49442
  if (!spaceName) {
49443
49443
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49463,7 +49463,7 @@ function registerSpaceCommands(program2) {
49463
49463
  }
49464
49464
  closeDb();
49465
49465
  });
49466
- space.command("archive").description("Archive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
49466
+ space.command("archive").description("Archive a space").argument("<name>", "Space name").option("-j, --json", "Output as JSON").action((name, opts) => {
49467
49467
  const spaceName = typeof name === "string" ? name.trim() : "";
49468
49468
  if (!spaceName) {
49469
49469
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49482,7 +49482,7 @@ function registerSpaceCommands(program2) {
49482
49482
  }
49483
49483
  closeDb();
49484
49484
  });
49485
- space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
49485
+ space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("-j, --json", "Output as JSON").action((name, opts) => {
49486
49486
  const spaceName = typeof name === "string" ? name.trim() : "";
49487
49487
  if (!spaceName) {
49488
49488
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49501,7 +49501,7 @@ function registerSpaceCommands(program2) {
49501
49501
  }
49502
49502
  closeDb();
49503
49503
  });
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) => {
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("-j, --json", "Output as JSON").action((spaceName, message, opts) => {
49505
49505
  const from = resolveIdentity(opts.from).trim();
49506
49506
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49507
49507
  const content = typeof message === "string" ? message : "";
@@ -49537,7 +49537,7 @@ function registerSpaceCommands(program2) {
49537
49537
  }
49538
49538
  closeDb();
49539
49539
  });
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) => {
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("-j, --json", "Output as JSON").action((spaceName, opts) => {
49541
49541
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49542
49542
  if (!spaceArg) {
49543
49543
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49569,7 +49569,7 @@ function registerSpaceCommands(program2) {
49569
49569
  }
49570
49570
  closeDb();
49571
49571
  });
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) => {
49572
+ 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
49573
  const agent = resolveIdentity(opts.from).trim();
49574
49574
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49575
49575
  if (!agent) {
@@ -49592,7 +49592,7 @@ function registerSpaceCommands(program2) {
49592
49592
  }
49593
49593
  closeDb();
49594
49594
  });
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) => {
49595
+ 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
49596
  const agent = resolveIdentity(opts.from).trim();
49597
49597
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49598
49598
  if (!agent) {
@@ -49615,7 +49615,7 @@ function registerSpaceCommands(program2) {
49615
49615
  }
49616
49616
  closeDb();
49617
49617
  });
49618
- space.command("members").description("List space members").argument("<space>", "Space name").option("--json", "Output as JSON").action((spaceName, opts) => {
49618
+ space.command("members").description("List space members").argument("<space>", "Space name").option("-j, --json", "Output as JSON").action((spaceName, opts) => {
49619
49619
  const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
49620
49620
  if (!spaceArg) {
49621
49621
  console.error(chalk5.red("Space name cannot be empty."));
@@ -49648,9 +49648,20 @@ function requireDeleteConfirmation(confirmed) {
49648
49648
  throw new Error("Project deletion requires --yes confirmation");
49649
49649
  }
49650
49650
  }
49651
+ function parseProjectListPagination(limitInput, offsetInput) {
49652
+ if (limitInput !== undefined && (!Number.isFinite(limitInput) || Number(limitInput) <= 0)) {
49653
+ throw new Error("--limit must be a positive integer.");
49654
+ }
49655
+ if (offsetInput !== undefined && (!Number.isFinite(offsetInput) || Number(offsetInput) < 0)) {
49656
+ throw new Error("--offset must be a non-negative integer.");
49657
+ }
49658
+ const limit = Number.isFinite(limitInput) ? Math.floor(Number(limitInput)) : undefined;
49659
+ const offset = Number.isFinite(offsetInput) ? Math.floor(Number(offsetInput)) : undefined;
49660
+ return { limit, offset };
49661
+ }
49651
49662
  function registerProjectCommands(program2) {
49652
49663
  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) => {
49664
+ 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
49665
  const agent = resolveIdentity(opts.from).trim();
49655
49666
  const projectName = typeof name === "string" ? name.trim() : "";
49656
49667
  if (!agent) {
@@ -49694,10 +49705,16 @@ function registerProjectCommands(program2) {
49694
49705
  }
49695
49706
  closeDb();
49696
49707
  });
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) => {
49708
+ 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
49709
  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;
49710
+ let limit;
49711
+ let offset;
49712
+ try {
49713
+ ({ limit, offset } = parseProjectListPagination(opts.limit, opts.offset));
49714
+ } catch (e) {
49715
+ console.error(chalk6.red(e.message));
49716
+ process.exit(1);
49717
+ }
49701
49718
  const projects = listProjects({
49702
49719
  ...status ? { status } : {},
49703
49720
  ...limit !== undefined ? { limit } : {},
@@ -49718,7 +49735,7 @@ function registerProjectCommands(program2) {
49718
49735
  }
49719
49736
  closeDb();
49720
49737
  });
49721
- project.command("get").description("Get project details").argument("<id-or-name>", "Project ID or name").option("--json", "Output as JSON").action((idOrName, opts) => {
49738
+ 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
49739
  let p = getProject(idOrName);
49723
49740
  if (!p)
49724
49741
  p = getProjectByName(idOrName);
@@ -49744,7 +49761,7 @@ function registerProjectCommands(program2) {
49744
49761
  }
49745
49762
  closeDb();
49746
49763
  });
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) => {
49764
+ 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
49765
  const updates = {};
49749
49766
  if (opts.name)
49750
49767
  updates.name = opts.name;
@@ -49779,7 +49796,7 @@ function registerProjectCommands(program2) {
49779
49796
  }
49780
49797
  closeDb();
49781
49798
  });
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) => {
49799
+ 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
49800
  try {
49784
49801
  requireDeleteConfirmation(opts.yes);
49785
49802
  const isUuid = /^[0-9a-f-]{36}$/i.test(id);
@@ -49834,7 +49851,7 @@ function buildWhoamiPayload(agent, source, presence, nowMs = Date.now()) {
49834
49851
  }
49835
49852
  function registerAgentCommands(program2) {
49836
49853
  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) => {
49854
+ 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
49855
  const agent = resolveIdentity();
49839
49856
  heartbeat(agent);
49840
49857
  const agentsList = listAgents({ online_only: opts.online });
@@ -49854,7 +49871,7 @@ function registerAgentCommands(program2) {
49854
49871
  }
49855
49872
  closeDb();
49856
49873
  });
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) => {
49874
+ 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
49875
  const agentName = typeof name === "string" ? name.trim() : "";
49859
49876
  if (!agentName) {
49860
49877
  console.error(chalk7.red("Agent name cannot be empty."));
@@ -49873,7 +49890,7 @@ function registerAgentCommands(program2) {
49873
49890
  }
49874
49891
  closeDb();
49875
49892
  });
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) => {
49893
+ 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
49894
  const old = typeof oldName === "string" ? oldName.trim() : "";
49878
49895
  const renamed = typeof newName === "string" ? newName.trim() : "";
49879
49896
  if (!old || !renamed) {
@@ -49897,7 +49914,7 @@ function registerAgentCommands(program2) {
49897
49914
  }
49898
49915
  closeDb();
49899
49916
  });
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) => {
49917
+ 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
49918
  const agentName = (typeof name === "string" ? name : "").trim();
49902
49919
  if (!agentName) {
49903
49920
  console.error(chalk7.red("Agent name is required."));
@@ -49922,7 +49939,7 @@ function registerAgentCommands(program2) {
49922
49939
  }
49923
49940
  closeDb();
49924
49941
  });
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) => {
49942
+ 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
49943
  const agent = resolveIdentity(opts.from);
49927
49944
  const status = opts.status || "online";
49928
49945
  heartbeat(agent, status);
@@ -49934,7 +49951,7 @@ function registerAgentCommands(program2) {
49934
49951
  closeDb();
49935
49952
  });
49936
49953
  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) => {
49954
+ 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
49955
  const agent = resolveIdentity(opts.from);
49939
49956
  const project = getProject(projectArg) || getProjectByName(projectArg);
49940
49957
  if (!project) {
@@ -49949,7 +49966,7 @@ function registerAgentCommands(program2) {
49949
49966
  }
49950
49967
  closeDb();
49951
49968
  });
49952
- focus.command("clear").description("Clear your project focus").option("--from <agent>", "Agent identity").option("--json", "Output as JSON").action((opts) => {
49969
+ focus.command("clear").description("Clear your project focus").option("--from <agent>", "Agent identity").option("-j, --json", "Output as JSON").action((opts) => {
49953
49970
  const agent = resolveIdentity(opts.from);
49954
49971
  getDb().prepare("UPDATE agent_presence SET project_id = NULL WHERE agent = ?").run(agent);
49955
49972
  if (opts.json) {
@@ -49959,7 +49976,7 @@ function registerAgentCommands(program2) {
49959
49976
  }
49960
49977
  closeDb();
49961
49978
  });
49962
- focus.command("get").description("Show current project focus").option("--from <agent>", "Agent identity").option("--json", "Output as JSON").action((opts) => {
49979
+ focus.command("get").description("Show current project focus").option("--from <agent>", "Agent identity").option("-j, --json", "Output as JSON").action((opts) => {
49963
49980
  const agent = resolveIdentity(opts.from);
49964
49981
  const presence = getPresence(agent);
49965
49982
  const projectId = presence?.project_id ?? null;
@@ -49976,7 +49993,7 @@ function registerAgentCommands(program2) {
49976
49993
  }
49977
49994
  closeDb();
49978
49995
  });
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) => {
49996
+ 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
49997
  const envValue = process.env.CONVERSATIONS_AGENT_ID?.trim();
49981
49998
  const agent = resolveIdentity(opts.from);
49982
49999
  let source;
@@ -50030,7 +50047,7 @@ var import__package = __toESM(require_package(), 1);
50030
50047
  import chalk8 from "chalk";
50031
50048
  function registerAnalyticsCommands(program2) {
50032
50049
  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) => {
50050
+ graph.command("build").description("Build/rebuild knowledge graph from messages, spaces, projects").option("-j, --json", "Output as JSON").action((opts) => {
50034
50051
  const result = buildGraph();
50035
50052
  if (opts.json) {
50036
50053
  console.log(JSON.stringify(result, null, 2));
@@ -50039,7 +50056,7 @@ function registerAnalyticsCommands(program2) {
50039
50056
  }
50040
50057
  closeDb();
50041
50058
  });
50042
- graph.command("stats").description("Show knowledge graph statistics").option("--json", "Output as JSON").action((opts) => {
50059
+ graph.command("stats").description("Show knowledge graph statistics").option("-j, --json", "Output as JSON").action((opts) => {
50043
50060
  const stats = getGraphStats();
50044
50061
  if (opts.json) {
50045
50062
  console.log(JSON.stringify(stats, null, 2));
@@ -50052,7 +50069,7 @@ function registerAnalyticsCommands(program2) {
50052
50069
  }
50053
50070
  closeDb();
50054
50071
  });
50055
- graph.command("agent").description("Show an agent's communication network").argument("<name>", "Agent name").option("--json", "Output as JSON").action((name, opts) => {
50072
+ graph.command("agent").description("Show an agent's communication network").argument("<name>", "Agent name").option("-j, --json", "Output as JSON").action((name, opts) => {
50056
50073
  const network = getAgentNetwork(name);
50057
50074
  if (opts.json) {
50058
50075
  console.log(JSON.stringify(network, null, 2));
@@ -50077,7 +50094,7 @@ function registerAnalyticsCommands(program2) {
50077
50094
  }
50078
50095
  closeDb();
50079
50096
  });
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) => {
50097
+ 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
50098
  const summary = getConversationSummary(target);
50082
50099
  if (!summary) {
50083
50100
  console.error(chalk8.red(`No messages found for "${target}"`));
@@ -50113,7 +50130,7 @@ function registerAnalyticsCommands(program2) {
50113
50130
  }
50114
50131
  closeDb();
50115
50132
  });
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) => {
50133
+ 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
50134
  let topics;
50118
50135
  if (opts.space) {
50119
50136
  topics = getSpaceTopics(opts.space);
@@ -50139,7 +50156,7 @@ function registerAnalyticsCommands(program2) {
50139
50156
  }
50140
50157
  closeDb();
50141
50158
  });
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) => {
50159
+ 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
50160
  const sessions = listHotSessions({
50144
50161
  limit: opts.limit ?? 10,
50145
50162
  min_score: opts.minScore,
@@ -50165,7 +50182,7 @@ function registerAnalyticsCommands(program2) {
50165
50182
  }
50166
50183
  closeDb();
50167
50184
  });
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) => {
50185
+ 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
50186
  const agent = resolveIdentity();
50170
50187
  heartbeat(agent);
50171
50188
  const db2 = getDb();
@@ -50212,7 +50229,7 @@ function registerAnalyticsCommands(program2) {
50212
50229
  }
50213
50230
  closeDb();
50214
50231
  });
50215
- program2.command("sessions").description("List conversation sessions").option("--agent <id>", "Filter sessions involving this agent").option("--json", "Output as JSON").action((opts) => {
50232
+ program2.command("sessions").description("List conversation sessions").option("--agent <id>", "Filter sessions involving this agent").option("-j, --json", "Output as JSON").action((opts) => {
50216
50233
  const sessions = listSessions(opts.agent);
50217
50234
  if (opts.json) {
50218
50235
  console.log(JSON.stringify(sessions, null, 2));
@@ -50229,7 +50246,7 @@ function registerAnalyticsCommands(program2) {
50229
50246
  }
50230
50247
  closeDb();
50231
50248
  });
50232
- program2.command("status").description("Show database stats").option("--json", "Output as JSON").action((opts) => {
50249
+ program2.command("status").description("Show database stats").option("-j, --json", "Output as JSON").action((opts) => {
50233
50250
  const db2 = getDb();
50234
50251
  const dbPath = getDbPath2();
50235
50252
  const totalMessages = db2.prepare("SELECT COUNT(*) as count FROM messages").get().count;
@@ -50258,7 +50275,7 @@ function registerAnalyticsCommands(program2) {
50258
50275
  }
50259
50276
  closeDb();
50260
50277
  });
50261
- program2.command("doctor").description("Check conversations setup and health").option("--json", "Output as JSON").action(async (opts) => {
50278
+ program2.command("doctor").description("Check conversations setup and health").option("-j, --json", "Output as JSON").action(async (opts) => {
50262
50279
  const checks = [];
50263
50280
  try {
50264
50281
  const db2 = getDb();
@@ -50332,7 +50349,7 @@ function registerAnalyticsCommands(program2) {
50332
50349
  }
50333
50350
  }
50334
50351
  });
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) => {
50352
+ 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
50353
  const agent = resolveIdentity(opts.from);
50337
50354
  const reaction = addReaction(id, agent, emoji);
50338
50355
  if (opts.json) {
@@ -50342,7 +50359,7 @@ function registerAnalyticsCommands(program2) {
50342
50359
  }
50343
50360
  closeDb();
50344
50361
  });
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) => {
50362
+ 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
50363
  const agent = resolveIdentity(opts.from);
50347
50364
  const removed = removeReaction(id, agent, emoji);
50348
50365
  if (opts.json) {
@@ -50356,7 +50373,7 @@ function registerAnalyticsCommands(program2) {
50356
50373
  }
50357
50374
  closeDb();
50358
50375
  });
50359
- program2.command("reactions").description("Show emoji reactions on a message").argument("<id>", "Message ID", parseInt).option("--json", "Output as JSON").action((id, opts) => {
50376
+ 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
50377
  const summary = getReactionSummary(id);
50361
50378
  if (opts.json) {
50362
50379
  console.log(JSON.stringify(summary, null, 2));
package/bin/mcp.js CHANGED
@@ -44269,7 +44269,7 @@ function registerTmuxTools(server) {
44269
44269
  // package.json
44270
44270
  var package_default = {
44271
44271
  name: "@hasna/conversations",
44272
- version: "0.2.33",
44272
+ version: "0.2.34",
44273
44273
  description: "Real-time CLI messaging for AI agents",
44274
44274
  type: "module",
44275
44275
  bin: {
@@ -1,3 +1,7 @@
1
1
  import type { Command } from "commander";
2
2
  export declare function requireDeleteConfirmation(confirmed?: boolean): void;
3
+ export declare function parseProjectListPagination(limitInput: unknown, offsetInput: unknown): {
4
+ limit: number | undefined;
5
+ offset: number | undefined;
6
+ };
3
7
  export declare function registerProjectCommands(program: Command): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/conversations",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
4
4
  "description": "Real-time CLI messaging for AI agents",
5
5
  "type": "module",
6
6
  "bin": {