claudemesh-cli 1.34.7 → 1.34.8

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.
@@ -104,7 +104,7 @@ __export(exports_urls, {
104
104
  VERSION: () => VERSION,
105
105
  URLS: () => URLS
106
106
  });
107
- var URLS, VERSION = "1.34.7", env;
107
+ var URLS, VERSION = "1.34.8", env;
108
108
  var init_urls = __esm(() => {
109
109
  URLS = {
110
110
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -4052,11 +4052,18 @@ async function tryListPeersViaDaemon(mesh) {
4052
4052
  return null;
4053
4053
  }
4054
4054
  }
4055
- async function tryListInboxViaDaemon(mesh, limit = 100) {
4055
+ async function tryListInboxViaDaemon(mesh, limit = 100, opts = {}) {
4056
4056
  if (!await daemonReachable())
4057
4057
  return null;
4058
4058
  try {
4059
- const path = `/v1/inbox${meshQuery(mesh)}${meshQuery(mesh) ? "&" : "?"}limit=${limit}`;
4059
+ const params = [`limit=${limit}`];
4060
+ if (mesh)
4061
+ params.push(`mesh=${encodeURIComponent(mesh)}`);
4062
+ if (opts.unreadOnly)
4063
+ params.push("unread_only=true");
4064
+ if (opts.markSeen === false)
4065
+ params.push("mark_seen=false");
4066
+ const path = `/v1/inbox?${params.join("&")}`;
4060
4067
  const res = await ipc({ path, timeoutMs: 3000 });
4061
4068
  if (res.status !== 200)
4062
4069
  return null;
@@ -8380,7 +8387,10 @@ function formatMessage(msg, includeMesh) {
8380
8387
  }
8381
8388
  async function runInbox(flags) {
8382
8389
  const meshSlug = flags.mesh;
8383
- const items = await tryListInboxViaDaemon(meshSlug, flags.limit ?? 100);
8390
+ const items = await tryListInboxViaDaemon(meshSlug, flags.limit ?? 100, {
8391
+ unreadOnly: flags.unread === true,
8392
+ markSeen: true
8393
+ });
8384
8394
  if (items === null) {
8385
8395
  if (flags.json) {
8386
8396
  process.stdout.write(`[]
@@ -8397,10 +8407,12 @@ async function runInbox(flags) {
8397
8407
  }
8398
8408
  if (items.length === 0) {
8399
8409
  const scope = meshSlug ? `mesh "${meshSlug}"` : "any mesh";
8400
- render.info(dim(`No messages on ${scope}.`));
8410
+ const filter = flags.unread ? "unread " : "";
8411
+ render.info(dim(`No ${filter}messages on ${scope}.`));
8401
8412
  return;
8402
8413
  }
8403
- const heading = meshSlug ? `inbox — ${meshSlug} (${items.length} message${items.length === 1 ? "" : "s"})` : `inbox (${items.length} message${items.length === 1 ? "" : "s"})`;
8414
+ const filterTag = flags.unread ? " unread" : "";
8415
+ const heading = meshSlug ? `inbox — ${meshSlug} (${items.length}${filterTag} message${items.length === 1 ? "" : "s"})` : `inbox (${items.length}${filterTag} message${items.length === 1 ? "" : "s"})`;
8404
8416
  render.section(heading);
8405
8417
  for (const msg of items) {
8406
8418
  process.stdout.write(formatMessage(msg, !meshSlug) + `
@@ -9582,6 +9594,11 @@ function migrateInbox(db) {
9582
9594
  CREATE INDEX IF NOT EXISTS inbox_topic ON inbox(topic);
9583
9595
  CREATE INDEX IF NOT EXISTS inbox_sender ON inbox(sender_pubkey);
9584
9596
  `);
9597
+ const cols = db.prepare(`PRAGMA table_info(inbox)`).all();
9598
+ if (!cols.some((c) => c.name === "seen_at")) {
9599
+ db.exec(`ALTER TABLE inbox ADD COLUMN seen_at INTEGER`);
9600
+ db.exec(`CREATE INDEX IF NOT EXISTS inbox_seen_at ON inbox(seen_at)`);
9601
+ }
9585
9602
  }
9586
9603
  function insertIfNew(db, row) {
9587
9604
  const before = db.prepare(`SELECT id FROM inbox WHERE client_message_id = ?`).get(row.client_message_id);
@@ -9616,9 +9633,12 @@ function listInbox(db, p) {
9616
9633
  where.push("mesh = ?");
9617
9634
  args.push(p.mesh);
9618
9635
  }
9636
+ if (p.unreadOnly === true) {
9637
+ where.push("seen_at IS NULL");
9638
+ }
9619
9639
  const sql = `
9620
9640
  SELECT id, client_message_id, broker_message_id, mesh, topic,
9621
- sender_pubkey, sender_name, body, meta, received_at, reply_to_id
9641
+ sender_pubkey, sender_name, body, meta, received_at, reply_to_id, seen_at
9622
9642
  FROM inbox
9623
9643
  ${where.length ? "WHERE " + where.join(" AND ") : ""}
9624
9644
  ORDER BY received_at DESC
@@ -9627,6 +9647,17 @@ function listInbox(db, p) {
9627
9647
  args.push(Math.min(Math.max(p.limit ?? 100, 1), 1000));
9628
9648
  return db.prepare(sql).all(...args);
9629
9649
  }
9650
+ function markInboxSeen(db, ids, now = Date.now()) {
9651
+ if (ids.length === 0)
9652
+ return 0;
9653
+ const placeholders = ids.map(() => "?").join(",");
9654
+ const r = db.prepare(`UPDATE inbox SET seen_at = ? WHERE seen_at IS NULL AND id IN (${placeholders})`).run(now, ...ids);
9655
+ return Number(r.changes);
9656
+ }
9657
+ function pruneInboxBefore(db, cutoffMs) {
9658
+ const r = db.prepare(`DELETE FROM inbox WHERE received_at < ?`).run(cutoffMs);
9659
+ return Number(r.changes);
9660
+ }
9630
9661
  function deleteInboxRow(db, id) {
9631
9662
  const r = db.prepare(`DELETE FROM inbox WHERE id = ?`).run(id);
9632
9663
  return Number(r.changes) > 0;
@@ -10387,13 +10418,23 @@ function makeHandler(opts) {
10387
10418
  const limitRaw = url.searchParams.get("limit");
10388
10419
  const limit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;
10389
10420
  const meshFilter = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
10421
+ const unreadOnly = url.searchParams.get("unread_only") === "true";
10422
+ const markSeen = url.searchParams.get("mark_seen") !== "false";
10390
10423
  const rows = listInbox(opts.inboxDb, {
10391
10424
  since: Number.isFinite(since) ? since : undefined,
10392
10425
  topic,
10393
10426
  fromPubkey,
10394
10427
  ...meshFilter ? { mesh: meshFilter } : {},
10428
+ unreadOnly,
10395
10429
  limit: Number.isFinite(limit ?? NaN) ? limit : undefined
10396
10430
  });
10431
+ let flippedCount = 0;
10432
+ if (markSeen) {
10433
+ const unreadIds = rows.filter((r) => r.seen_at == null).map((r) => r.id);
10434
+ if (unreadIds.length > 0) {
10435
+ flippedCount = markInboxSeen(opts.inboxDb, unreadIds);
10436
+ }
10437
+ }
10397
10438
  respond(res, 200, {
10398
10439
  items: rows.map((r) => ({
10399
10440
  id: r.id,
@@ -10405,11 +10446,32 @@ function makeHandler(opts) {
10405
10446
  sender_name: r.sender_name,
10406
10447
  body: r.body,
10407
10448
  received_at: new Date(r.received_at).toISOString(),
10408
- reply_to_id: r.reply_to_id
10409
- }))
10449
+ reply_to_id: r.reply_to_id,
10450
+ seen_at: r.seen_at ? new Date(r.seen_at).toISOString() : null
10451
+ })),
10452
+ marked_seen: flippedCount
10410
10453
  });
10411
10454
  return;
10412
10455
  }
10456
+ if (req.method === "POST" && url.pathname === "/v1/inbox/seen") {
10457
+ if (!opts.inboxDb) {
10458
+ respond(res, 503, { error: "inbox not initialised" });
10459
+ return;
10460
+ }
10461
+ try {
10462
+ const body = await readJsonBody(req, 64 * 1024);
10463
+ const ids = Array.isArray(body?.ids) ? body.ids.filter((x) => typeof x === "string") : [];
10464
+ if (ids.length === 0) {
10465
+ respond(res, 400, { error: "missing 'ids' (string[])" });
10466
+ return;
10467
+ }
10468
+ const flipped = markInboxSeen(opts.inboxDb, ids);
10469
+ respond(res, 200, { marked_seen: flipped });
10470
+ } catch (e) {
10471
+ respond(res, 400, { error: String(e) });
10472
+ }
10473
+ return;
10474
+ }
10413
10475
  if (req.method === "DELETE" && url.pathname === "/v1/inbox") {
10414
10476
  if (!opts.inboxDb) {
10415
10477
  respond(res, 503, { error: "inbox not initialised" });
@@ -11376,6 +11438,11 @@ class SessionBrokerClient {
11376
11438
  return;
11377
11439
  }
11378
11440
  if (msg.type === "push" || msg.type === "inbound") {
11441
+ const senderPubkey = String(msg.senderPubkey ?? "").toLowerCase();
11442
+ if (senderPubkey && senderPubkey === this.opts.sessionPubkey.toLowerCase()) {
11443
+ this.log("info", "self_echo_dropped", { sender: senderPubkey.slice(0, 12) });
11444
+ return;
11445
+ }
11379
11446
  this.opts.onPush?.(msg);
11380
11447
  return;
11381
11448
  }
@@ -11667,6 +11734,46 @@ function defaultLog4(level, msg, meta) {
11667
11734
  var POLL_INTERVAL_MS = 500, MAX_ATTEMPTS_PER_ROW = 25, BACKOFF_BASE_MS = 500, BACKOFF_CAP_MS = 30000;
11668
11735
  var init_drain = () => {};
11669
11736
 
11737
+ // src/daemon/inbox-pruner.ts
11738
+ function startInboxPruner(opts) {
11739
+ const retentionMs = opts.retentionMs ?? DEFAULT_RETENTION_MS;
11740
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
11741
+ const log2 = opts.log ?? defaultLog5;
11742
+ const tick = () => {
11743
+ try {
11744
+ const cutoff = Date.now() - retentionMs;
11745
+ const removed = pruneInboxBefore(opts.db, cutoff);
11746
+ if (removed > 0) {
11747
+ log2("info", "inbox_prune_completed", {
11748
+ removed,
11749
+ retention_days: Math.round(retentionMs / (24 * 60 * 60 * 1000))
11750
+ });
11751
+ }
11752
+ } catch (e) {
11753
+ log2("warn", "inbox_prune_failed", { err: String(e) });
11754
+ }
11755
+ };
11756
+ tick();
11757
+ const handle = setInterval(tick, intervalMs);
11758
+ if (typeof handle.unref === "function")
11759
+ handle.unref();
11760
+ return { stop: () => clearInterval(handle) };
11761
+ }
11762
+ function defaultLog5(level, msg, meta) {
11763
+ const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
11764
+ if (level === "info")
11765
+ process.stdout.write(line + `
11766
+ `);
11767
+ else
11768
+ process.stderr.write(line + `
11769
+ `);
11770
+ }
11771
+ var DEFAULT_RETENTION_MS, DEFAULT_INTERVAL_MS;
11772
+ var init_inbox_pruner = __esm(() => {
11773
+ DEFAULT_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
11774
+ DEFAULT_INTERVAL_MS = 60 * 60 * 1000;
11775
+ });
11776
+
11670
11777
  // src/daemon/inbound.ts
11671
11778
  import { randomUUID as randomUUID4 } from "node:crypto";
11672
11779
  async function handleBrokerPush(msg, ctx) {
@@ -11983,6 +12090,12 @@ async function runDaemon(opts = {}) {
11983
12090
  bus.publish("broker_status", { mesh: mesh.slug, status: s });
11984
12091
  },
11985
12092
  onPush: (m) => {
12093
+ const senderMemberPk = String(m.senderMemberPubkey ?? "").toLowerCase();
12094
+ const senderPubkey = String(m.senderPubkey ?? "").toLowerCase();
12095
+ const ownMember = mesh.pubkey.toLowerCase();
12096
+ if (senderMemberPk && senderMemberPk === ownMember && senderPubkey === ownMember) {
12097
+ return;
12098
+ }
11986
12099
  handleBrokerPush(m, {
11987
12100
  db: inboxDb,
11988
12101
  bus,
@@ -12004,6 +12117,7 @@ async function runDaemon(opts = {}) {
12004
12117
  brokers,
12005
12118
  getSessionBrokerByPubkey: (pubkey) => sessionBrokersByPubkey.get(pubkey)
12006
12119
  });
12120
+ const inboxPruner = startInboxPruner({ db: inboxDb });
12007
12121
  setRegistryHooks({
12008
12122
  onRegister: (info) => {
12009
12123
  if (!info.presence)
@@ -12107,6 +12221,7 @@ async function runDaemon(opts = {}) {
12107
12221
  shuttingDown = true;
12108
12222
  process.stdout.write(JSON.stringify({ msg: "daemon_shutdown", signal: sig, ts: new Date().toISOString() }) + `
12109
12223
  `);
12224
+ inboxPruner.stop();
12110
12225
  if (drain)
12111
12226
  await drain.close();
12112
12227
  for (const b of brokers.values()) {
@@ -12143,6 +12258,7 @@ var init_run = __esm(() => {
12143
12258
  init_broker();
12144
12259
  init_session_broker();
12145
12260
  init_drain();
12261
+ init_inbox_pruner();
12146
12262
  init_inbound();
12147
12263
  init_identity();
12148
12264
  init_facade();
@@ -16270,7 +16386,8 @@ claudemesh message send <p> "..." --priority low # pull-only
16270
16386
  claudemesh inbox # all attached meshes, last 100
16271
16387
  claudemesh inbox --mesh <slug> # scoped to one mesh
16272
16388
  claudemesh inbox --mesh <slug> --limit 20 # custom cap
16273
- claudemesh inbox --json # full row (sender_pubkey, mesh, body, received_at, …)
16389
+ claudemesh inbox --json # full row (sender_pubkey, mesh, body, received_at, seen_at, …)
16390
+ claudemesh inbox --unread # 1.34.8+ only rows whose seen_at IS NULL
16274
16391
 
16275
16392
  # inbox flush + delete — 1.34.7+
16276
16393
  claudemesh inbox flush --mesh <slug> # delete all rows on one mesh
@@ -16286,6 +16403,12 @@ claudemesh message status <message-id> --json
16286
16403
 
16287
16404
  **Inbox source (1.34.0+):** \`claudemesh inbox\` queries the daemon's persistent \`~/.claudemesh/daemon/inbox.db\` over IPC — it is NOT a fresh broker-WS buffer drain. Rows survive daemon restarts. Sender attribution is the actual session pubkey of the launched session that originated the send (NOT the stable member pubkey of the sender's daemon), so two sibling sessions of the same human appear as distinct rows.
16288
16405
 
16406
+ **Read-state (1.34.8+):** every inbox row carries a \`seen_at\` timestamp. \`null\` = never surfaced; an ISO string = first surfaced at that moment. The flag flips automatically when (a) the row is returned by an interactive \`claudemesh inbox\` listing, or (b) the MCP server emits a live \`<channel>\` reminder for it. The launch welcome push uses \`unread_only=true\` to surface only rows the user hasn't seen — so a session relaunched a day later sees what it actually missed, not the same 24h batch every time. Use \`claudemesh inbox --unread\` to get the same filter from the CLI.
16407
+
16408
+ **Self-echo guard (1.34.8+):** broker fan-out paths sometimes mirror an outbound DM back to the originating session-WS. The daemon now drops those at the WS boundary (matching on \`senderPubkey === own.session_pubkey\`), so the sender no longer sees their own \`claudemesh send\` arrive as a \`← claudemesh: <self>: ...\` channel push immediately after dispatching it.
16409
+
16410
+ **Inbox TTL (1.34.8+):** the daemon runs an hourly prune that deletes rows older than 30 days. Without this the inbox grew unbounded; now it self-trims while preserving "I went on holiday and want to see what I missed" recovery for a generous window. No CLI knob — it's a built-in retention policy. To override, manually \`claudemesh inbox flush --before <iso>\`.
16411
+
16289
16412
  \`send\` JSON output: \`{"ok": true, "messageId": "...", "target": "..."}\`. Errors: \`{"ok": false, "error": "..."}\`.
16290
16413
 
16291
16414
  ### \`state\` — shared per-mesh key-value store
@@ -18389,6 +18512,32 @@ function daemonGet(path2, opts = {}) {
18389
18512
  req.end();
18390
18513
  });
18391
18514
  }
18515
+ function daemonMarkSeen(ids, sessionToken) {
18516
+ return new Promise((resolve3) => {
18517
+ if (ids.length === 0) {
18518
+ resolve3();
18519
+ return;
18520
+ }
18521
+ const body = JSON.stringify({ ids });
18522
+ const headers = {
18523
+ "Content-Type": "application/json",
18524
+ "Content-Length": String(Buffer.byteLength(body))
18525
+ };
18526
+ if (sessionToken)
18527
+ headers.Authorization = `ClaudeMesh-Session ${sessionToken}`;
18528
+ const req = httpRequest2({ socketPath: DAEMON_PATHS.SOCK_FILE, path: "/v1/inbox/seen", method: "POST", timeout: 3000, headers }, (res) => {
18529
+ res.on("data", () => {});
18530
+ res.on("end", () => resolve3());
18531
+ });
18532
+ req.on("error", () => resolve3());
18533
+ req.on("timeout", () => {
18534
+ req.destroy();
18535
+ resolve3();
18536
+ });
18537
+ req.write(body);
18538
+ req.end();
18539
+ });
18540
+ }
18392
18541
  function subscribeEvents(onEvent) {
18393
18542
  let active = true;
18394
18543
  let req = null;
@@ -18601,6 +18750,8 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
18601
18750
  } catch {}
18602
18751
  };
18603
18752
  mcpLog("mcp_started", { version: VERSION });
18753
+ const { readSessionTokenFromEnv: readSessionTokenFromEnv2 } = await Promise.resolve().then(() => (init_token(), exports_token));
18754
+ const sessionTokenForSeen = readSessionTokenFromEnv2();
18604
18755
  const sub = subscribeEvents(async (ev) => {
18605
18756
  mcpLog("sse_event_received", { kind: ev.kind });
18606
18757
  if (ev.kind === "message") {
@@ -18633,6 +18784,10 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
18633
18784
  }
18634
18785
  });
18635
18786
  mcpLog("channel_emitted", { content_preview: content.slice(0, 80), mesh: String(d.mesh ?? "") });
18787
+ const inboxRowId = String(d.id ?? "");
18788
+ if (inboxRowId) {
18789
+ daemonMarkSeen([inboxRowId], sessionTokenForSeen).catch(() => {});
18790
+ }
18636
18791
  } catch (err) {
18637
18792
  mcpLog("channel_emit_failed", { err: String(err) });
18638
18793
  process.stderr.write(`[claudemesh-mcp] channel emit failed: ${err}
@@ -18732,8 +18887,7 @@ async function emitMeshWelcome(server, mcpLog) {
18732
18887
  } catch (e) {
18733
18888
  mcpLog("welcome_peers_lookup_failed", { err: String(e) });
18734
18889
  }
18735
- const sinceIso = new Date(Date.now() - 86400000).toISOString();
18736
- const inboxPath = selfMeshSlug ? `/v1/inbox?mesh=${encodeURIComponent(selfMeshSlug)}&since=${encodeURIComponent(sinceIso)}&limit=20` : `/v1/inbox?since=${encodeURIComponent(sinceIso)}&limit=20`;
18890
+ const inboxPath = selfMeshSlug ? `/v1/inbox?mesh=${encodeURIComponent(selfMeshSlug)}&unread_only=true&mark_seen=false&limit=50` : `/v1/inbox?unread_only=true&mark_seen=false&limit=50`;
18737
18891
  let inboxItems = [];
18738
18892
  try {
18739
18893
  const { status, body } = await daemonGet(inboxPath, { sessionToken });
@@ -18757,9 +18911,9 @@ async function emitMeshWelcome(server, mcpLog) {
18757
18911
  lines.push(`\uD83D\uDC65 Peer list unavailable (daemon query failed).`);
18758
18912
  }
18759
18913
  if (inboxItems.length === 0) {
18760
- lines.push(`\uD83D\uDCE5 Inbox is empty (last 24h).`);
18914
+ lines.push(`\uD83D\uDCE5 No unread messages.`);
18761
18915
  } else {
18762
- lines.push(`\uD83D\uDCE5 ${inboxItems.length} message${inboxItems.length === 1 ? "" : "s"} in inbox (last 24h):`);
18916
+ lines.push(`\uD83D\uDCE5 ${inboxItems.length} unread message${inboxItems.length === 1 ? "" : "s"}:`);
18763
18917
  for (const it of inboxItems.slice(0, 3)) {
18764
18918
  const sender = String(it.sender_name ?? "unknown");
18765
18919
  const senderPub = String(it.sender_pubkey ?? "").slice(0, 8);
@@ -18798,6 +18952,12 @@ async function emitMeshWelcome(server, mcpLog) {
18798
18952
  peer_count: peerCount,
18799
18953
  unread_count: inboxItems.length
18800
18954
  });
18955
+ if (inboxItems.length > 0) {
18956
+ const ids = inboxItems.map((it) => String(it.id ?? "")).filter(Boolean);
18957
+ if (ids.length > 0) {
18958
+ daemonMarkSeen(ids, sessionToken).catch(() => {});
18959
+ }
18960
+ }
18801
18961
  } catch (err) {
18802
18962
  mcpLog("welcome_emit_failed", { err: String(err) });
18803
18963
  }
@@ -19060,7 +19220,8 @@ var BOOLEAN_FLAGS = new Set([
19060
19220
  "force",
19061
19221
  "dry-run",
19062
19222
  "verbose",
19063
- "skip-service"
19223
+ "skip-service",
19224
+ "unread"
19064
19225
  ]);
19065
19226
  function parseArgv(argv) {
19066
19227
  const args = argv.slice(2);
@@ -19673,8 +19834,10 @@ Message (resource form)
19673
19834
  fans out to every sibling session of your member)
19674
19835
  [--json] (machine-readable result)
19675
19836
  claudemesh message inbox read persisted inbox (alias: inbox)
19676
- flags: [--mesh <slug>] [--limit N] [--json]
19837
+ flags: [--mesh <slug>] [--limit N] [--unread] [--json]
19677
19838
  reads ~/.claudemesh/daemon/inbox.db via daemon
19839
+ --unread → only rows never surfaced before (seen_at IS NULL);
19840
+ listing stamps returned rows seen as a side effect
19678
19841
  claudemesh inbox flush bulk-delete inbox rows
19679
19842
  flags: [--mesh <slug>] [--before <iso-timestamp>] [--all]
19680
19843
  --all required when neither --mesh nor --before is set
@@ -20052,7 +20215,8 @@ async function main() {
20052
20215
  await runInbox2({
20053
20216
  mesh: flags.mesh,
20054
20217
  json: !!flags.json,
20055
- limit: typeof flags.limit === "number" ? flags.limit : typeof flags.limit === "string" ? Number.parseInt(flags.limit, 10) : undefined
20218
+ limit: typeof flags.limit === "number" ? flags.limit : typeof flags.limit === "string" ? Number.parseInt(flags.limit, 10) : undefined,
20219
+ unread: !!flags.unread
20056
20220
  });
20057
20221
  }
20058
20222
  break;
@@ -20325,7 +20489,8 @@ async function main() {
20325
20489
  await runInbox2({
20326
20490
  mesh: flags.mesh,
20327
20491
  json: !!flags.json,
20328
- limit: typeof flags.limit === "number" ? flags.limit : typeof flags.limit === "string" ? Number.parseInt(flags.limit, 10) : undefined
20492
+ limit: typeof flags.limit === "number" ? flags.limit : typeof flags.limit === "string" ? Number.parseInt(flags.limit, 10) : undefined,
20493
+ unread: !!flags.unread
20329
20494
  });
20330
20495
  }
20331
20496
  } else if (sub === "status") {
@@ -20880,4 +21045,4 @@ main().catch((err) => {
20880
21045
  process.exit(EXIT.INTERNAL_ERROR);
20881
21046
  });
20882
21047
 
20883
- //# debugId=FB01D4AF897A4CD164756E2164756E21
21048
+ //# debugId=99681AB539B313DF64756E2164756E21