@holon-run/agentinbox 1.0.0 → 1.0.2

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/dist/src/cli.js CHANGED
@@ -355,9 +355,31 @@ async function main() {
355
355
  return;
356
356
  }
357
357
  if (command === "agent" && normalized[1] === "register") {
358
+ const agentId = takeFlagValue(normalized, "--agent-id") ?? undefined;
359
+ const notifyLeaseMs = parseOptionalNumber(takeFlagValue(normalized, "--notify-lease-ms")) ?? undefined;
360
+ const minUnackedItems = parseOptionalNumber(takeFlagValue(normalized, "--min-unacked-items")) ?? undefined;
361
+ const webhookUrl = takeFlagValue(normalized, "--webhook-url");
362
+ if (webhookUrl) {
363
+ if (!agentId) {
364
+ throw new Error("usage: agentinbox agent register --agent-id ID --webhook-url URL [--webhook-activation-mode MODE] [--webhook-notify-lease-ms N] [--webhook-min-unacked-items N]");
365
+ }
366
+ const webhookNotifyLeaseMs = parseOptionalNumber(takeFlagValue(normalized, "--webhook-notify-lease-ms")) ?? notifyLeaseMs;
367
+ const webhookMinUnackedItems = parseOptionalNumber(takeFlagValue(normalized, "--webhook-min-unacked-items")) ?? minUnackedItems;
368
+ await printRemote(client, "/agents", {
369
+ agentId,
370
+ forceRebind: normalized.includes("--force-rebind"),
371
+ webhook: {
372
+ url: webhookUrl,
373
+ activationMode: takeFlagValue(normalized, "--webhook-activation-mode") ?? undefined,
374
+ notifyLeaseMs: webhookNotifyLeaseMs,
375
+ minUnackedItems: webhookMinUnackedItems,
376
+ },
377
+ });
378
+ return;
379
+ }
358
380
  const detected = (0, terminal_1.detectTerminalContext)(process.env);
359
381
  await printRemote(client, "/agents", {
360
- agentId: takeFlagValue(normalized, "--agent-id") ?? undefined,
382
+ agentId,
361
383
  forceRebind: normalized.includes("--force-rebind"),
362
384
  backend: detected.backend,
363
385
  runtimeKind: detected.runtimeKind,
@@ -367,8 +389,8 @@ async function main() {
367
389
  tty: detected.tty ?? undefined,
368
390
  termProgram: detected.termProgram ?? undefined,
369
391
  itermSessionId: detected.itermSessionId ?? undefined,
370
- notifyLeaseMs: parseOptionalNumber(takeFlagValue(normalized, "--notify-lease-ms")) ?? undefined,
371
- minUnackedItems: parseOptionalNumber(takeFlagValue(normalized, "--min-unacked-items")) ?? undefined,
392
+ notifyLeaseMs,
393
+ minUnackedItems,
372
394
  });
373
395
  return;
374
396
  }
@@ -1297,6 +1319,7 @@ Usage:
1297
1319
 
1298
1320
  Usage:
1299
1321
  agentinbox agent register [--agent-id ID] [--force-rebind] [--notify-lease-ms N] [--min-unacked-items N]
1322
+ agentinbox agent register --agent-id ID --webhook-url URL [--webhook-activation-mode MODE] [--webhook-notify-lease-ms N] [--webhook-min-unacked-items N]
1300
1323
  agentinbox agent list
1301
1324
  agentinbox agent current
1302
1325
  agentinbox agent show <agentId>
package/dist/src/http.js CHANGED
@@ -772,11 +772,34 @@ function buildFastifyServer(service) {
772
772
  body: {
773
773
  type: "object",
774
774
  additionalProperties: false,
775
- required: ["backend"],
775
+ oneOf: [
776
+ {
777
+ required: ["backend"],
778
+ properties: {
779
+ backend: { type: "string", enum: ["tmux", "iterm2"] },
780
+ },
781
+ },
782
+ {
783
+ required: ["agentId", "webhook"],
784
+ properties: {
785
+ webhook: {
786
+ type: "object",
787
+ additionalProperties: false,
788
+ required: ["url"],
789
+ properties: {
790
+ url: { type: "string", minLength: 1 },
791
+ activationMode: { type: "string", enum: ["activation_only", "activation_with_items"] },
792
+ notifyLeaseMs: { type: "integer", minimum: 1 },
793
+ minUnackedItems: { type: "integer", minimum: 1 },
794
+ },
795
+ },
796
+ },
797
+ },
798
+ ],
776
799
  properties: {
777
800
  agentId: { type: "string" },
778
801
  forceRebind: { type: "boolean" },
779
- backend: { type: "string", minLength: 1 },
802
+ backend: { type: "string", enum: ["tmux", "iterm2"] },
780
803
  runtimeKind: { type: "string" },
781
804
  runtimeSessionId: { type: "string" },
782
805
  runtimePid: { type: "integer", minimum: 1 },
@@ -786,6 +809,17 @@ function buildFastifyServer(service) {
786
809
  itermSessionId: { type: "string" },
787
810
  notifyLeaseMs: { type: "integer", minimum: 1 },
788
811
  minUnackedItems: { type: "integer", minimum: 1 },
812
+ webhook: {
813
+ type: "object",
814
+ additionalProperties: false,
815
+ required: ["url"],
816
+ properties: {
817
+ url: { type: "string", minLength: 1 },
818
+ activationMode: { type: "string", enum: ["activation_only", "activation_with_items"] },
819
+ notifyLeaseMs: { type: "integer", minimum: 1 },
820
+ minUnackedItems: { type: "integer", minimum: 1 },
821
+ },
822
+ },
789
823
  },
790
824
  },
791
825
  response: {
@@ -795,10 +829,11 @@ function buildFastifyServer(service) {
795
829
  },
796
830
  }, async (request) => {
797
831
  const body = request.body;
832
+ const webhookBody = body.webhook;
798
833
  return service.registerAgent({
799
834
  agentId: optionalString(body.agentId) ?? null,
800
835
  forceRebind: body.forceRebind === true,
801
- backend: String(body.backend),
836
+ backend: optionalString(body.backend),
802
837
  runtimeKind: optionalString(body.runtimeKind),
803
838
  runtimeSessionId: optionalString(body.runtimeSessionId),
804
839
  runtimePid: typeof body.runtimePid === "number" ? body.runtimePid : null,
@@ -809,6 +844,14 @@ function buildFastifyServer(service) {
809
844
  itermSessionId: optionalString(body.itermSessionId),
810
845
  notifyLeaseMs: typeof body.notifyLeaseMs === "number" ? body.notifyLeaseMs : null,
811
846
  minUnackedItems: typeof body.minUnackedItems === "number" ? body.minUnackedItems : null,
847
+ webhook: webhookBody
848
+ ? {
849
+ url: String(webhookBody.url),
850
+ activationMode: optionalString(webhookBody.activationMode),
851
+ notifyLeaseMs: typeof webhookBody.notifyLeaseMs === "number" ? webhookBody.notifyLeaseMs : null,
852
+ minUnackedItems: typeof webhookBody.minUnackedItems === "number" ? webhookBody.minUnackedItems : null,
853
+ }
854
+ : null,
812
855
  });
813
856
  });
814
857
  app.get("/agents/:agentId", {
@@ -1747,6 +1790,8 @@ function isBadRequestError(message) {
1747
1790
  message.startsWith("expected boolean") ||
1748
1791
  message.startsWith("expected integer") ||
1749
1792
  message.startsWith("expected positive integer") ||
1793
+ message.startsWith("webhook agent registration requires") ||
1794
+ message.startsWith("agent registration requires either") ||
1750
1795
  message.startsWith("notifyLeaseMs must be a positive integer") ||
1751
1796
  message.startsWith("minUnackedItems must be a positive integer") ||
1752
1797
  message.startsWith("invalid webhook activation target") ||
@@ -516,18 +516,23 @@ class AgentInboxService {
516
516
  registerAgent(input) {
517
517
  validateNotifyLeaseMs(input.notifyLeaseMs);
518
518
  validateMinUnackedItems(input.minUnackedItems);
519
- validateTerminalRegistration(input);
519
+ validateRegisterAgentInput(input);
520
+ const webhookInput = input.webhook ?? null;
520
521
  const runtimeKind = input.runtimeKind ?? "unknown";
521
- const agentId = input.agentId ?? this.resolveAutoAgentId({
522
- runtimeKind,
523
- runtimeSessionId: input.runtimeSessionId ?? null,
524
- backend: input.backend,
525
- tmuxPaneId: input.tmuxPaneId ?? null,
526
- itermSessionId: input.itermSessionId ?? null,
527
- tty: input.tty ?? null,
528
- });
522
+ const agentId = webhookInput
523
+ ? input.agentId
524
+ : input.agentId ?? this.resolveAutoAgentId({
525
+ runtimeKind,
526
+ runtimeSessionId: input.runtimeSessionId ?? null,
527
+ backend: input.backend,
528
+ tmuxPaneId: input.tmuxPaneId ?? null,
529
+ itermSessionId: input.itermSessionId ?? null,
530
+ tty: input.tty ?? null,
531
+ });
529
532
  const now = (0, util_1.nowIso)();
530
- this.handleAgentRegistrationConflicts(agentId, input);
533
+ if (!webhookInput) {
534
+ this.handleAgentRegistrationConflicts(agentId, input);
535
+ }
531
536
  const existingAgent = this.store.getAgent(agentId);
532
537
  const agent = existingAgent
533
538
  ? this.store.updateAgent(agentId, {
@@ -552,11 +557,21 @@ class AgentInboxService {
552
557
  this.store.insertAgent(created);
553
558
  return created;
554
559
  })();
555
- const terminalTarget = this.upsertTerminalActivationTarget(agent.agentId, input, now);
560
+ let terminalTarget = null;
561
+ let webhookTarget = null;
562
+ if (webhookInput) {
563
+ webhookTarget = this.upsertWebhookActivationTarget(agent.agentId, webhookInput, now);
564
+ this.removeTerminalActivationTargets(agent.agentId);
565
+ }
566
+ else {
567
+ terminalTarget = this.upsertTerminalActivationTarget(agent.agentId, input, now);
568
+ }
556
569
  const inbox = this.ensureInboxForAgent(agent.agentId);
557
570
  return {
558
571
  agent,
559
572
  terminalTarget,
573
+ webhookTarget,
574
+ activationChannel: webhookTarget ? "webhook" : terminalTarget ? "terminal" : null,
560
575
  inbox,
561
576
  };
562
577
  }
@@ -1197,7 +1212,7 @@ class AgentInboxService {
1197
1212
  subscriptionIds: [],
1198
1213
  });
1199
1214
  this.notifyInboxWatchers(agentId, [entry]);
1200
- const targets = this.store.listActivationTargetsForAgent(agentId).filter((target) => target.status === "active");
1215
+ const targets = this.listEffectiveActiveActivationTargets(agentId);
1201
1216
  for (const target of targets) {
1202
1217
  this.enqueueActivationTarget(target, {
1203
1218
  agentId,
@@ -1466,7 +1481,7 @@ class AgentInboxService {
1466
1481
  limit: DEFAULT_SUBSCRIPTION_POLL_LIMIT,
1467
1482
  });
1468
1483
  const inbox = this.ensureInboxForAgent(subscription.agentId);
1469
- const targets = this.store.listActivationTargetsForAgent(subscription.agentId).filter((target) => target.status === "active");
1484
+ const targets = this.listEffectiveActiveActivationTargets(subscription.agentId);
1470
1485
  let matched = 0;
1471
1486
  let inboxItemsCreated = 0;
1472
1487
  let lastProcessedOffset = null;
@@ -1796,6 +1811,12 @@ class AgentInboxService {
1796
1811
  throw new Error("unable to derive a unique agentId from terminal context");
1797
1812
  }
1798
1813
  handleAgentRegistrationConflicts(agentId, input) {
1814
+ const activeWebhookTarget = this.store
1815
+ .listActivationTargetsForAgent(agentId)
1816
+ .find((target) => target.kind === "webhook" && target.status === "active");
1817
+ if (activeWebhookTarget) {
1818
+ throw new Error(`agent register conflict: agent ${agentId} already has active webhook target ${activeWebhookTarget.targetId}; terminal registration is disabled while webhook is active`);
1819
+ }
1799
1820
  const currentTarget = findExistingTerminalActivationTarget(this.store, input);
1800
1821
  if (currentTarget && currentTarget.agentId !== agentId) {
1801
1822
  if (!input.forceRebind) {
@@ -1817,6 +1838,34 @@ class AgentInboxService {
1817
1838
  }
1818
1839
  }
1819
1840
  }
1841
+ upsertWebhookActivationTarget(agentId, input, now) {
1842
+ validateNotifyLeaseMs(input.notifyLeaseMs);
1843
+ validateMinUnackedItems(input.minUnackedItems);
1844
+ const mode = normalizeWebhookActivationMode(input.activationMode);
1845
+ const targets = this.store
1846
+ .listActivationTargetsForAgent(agentId)
1847
+ .filter((target) => target.kind === "webhook");
1848
+ const matching = targets.find((target) => target.url === input.url);
1849
+ const existing = matching ?? targets[0] ?? null;
1850
+ if (existing) {
1851
+ const target = this.store.updateWebhookActivationTarget(existing.targetId, {
1852
+ url: input.url,
1853
+ mode,
1854
+ notifyLeaseMs: input.notifyLeaseMs ?? existing.notifyLeaseMs,
1855
+ minUnackedItems: input.minUnackedItems ?? existing.minUnackedItems ?? null,
1856
+ updatedAt: now,
1857
+ lastSeenAt: now,
1858
+ });
1859
+ for (const duplicate of targets) {
1860
+ if (duplicate.targetId !== target.targetId) {
1861
+ this.store.deleteActivationTarget(agentId, duplicate.targetId);
1862
+ }
1863
+ }
1864
+ this.markAgentActive(agentId);
1865
+ return target;
1866
+ }
1867
+ return this.addWebhookActivationTarget(agentId, input);
1868
+ }
1820
1869
  upsertTerminalActivationTarget(agentId, input, now) {
1821
1870
  const existing = findExistingTerminalActivationTarget(this.store, input);
1822
1871
  if (existing) {
@@ -1872,6 +1921,21 @@ class AgentInboxService {
1872
1921
  this.markAgentActive(agentId);
1873
1922
  return target;
1874
1923
  }
1924
+ removeTerminalActivationTargets(agentId) {
1925
+ const targets = this.store
1926
+ .listActivationTargetsForAgent(agentId)
1927
+ .filter((target) => target.kind === "terminal");
1928
+ for (const target of targets) {
1929
+ this.store.deleteActivationTarget(agentId, target.targetId);
1930
+ }
1931
+ }
1932
+ listEffectiveActiveActivationTargets(agentId) {
1933
+ const targets = this.store.listActivationTargetsForAgent(agentId).filter((target) => target.status === "active");
1934
+ return effectiveActiveTargets(targets);
1935
+ }
1936
+ isEffectiveActiveTarget(agentId, targetId) {
1937
+ return this.listEffectiveActiveActivationTargets(agentId).some((target) => target.targetId === targetId);
1938
+ }
1875
1939
  enqueueActivationTarget(target, input) {
1876
1940
  const key = notificationBufferKey(target.agentId, target.targetId);
1877
1941
  let buffer = this.notificationBuffers.get(key);
@@ -2108,6 +2172,10 @@ class AgentInboxService {
2108
2172
  this.store.deleteActivationDispatchState(agentId, targetId);
2109
2173
  return;
2110
2174
  }
2175
+ if (!this.isEffectiveActiveTarget(agentId, targetId)) {
2176
+ this.store.deleteActivationDispatchState(agentId, targetId);
2177
+ return;
2178
+ }
2111
2179
  const inbox = this.ensureInboxForAgent(agentId);
2112
2180
  const unacked = this.store.listInboxEntries(inbox.inboxId, { includeAcked: false }).length;
2113
2181
  if (unacked === 0) {
@@ -2181,9 +2249,18 @@ class AgentInboxService {
2181
2249
  if (target.status === "offline") {
2182
2250
  return "offline";
2183
2251
  }
2252
+ if (!this.isEffectiveActiveTarget(input.agentId, input.targetId)) {
2253
+ this.logger.debug("activation.dispatch_suppressed", {
2254
+ agentId: input.agentId,
2255
+ targetId: target.targetId,
2256
+ reason: "non_effective_target",
2257
+ targetKind: target.kind,
2258
+ });
2259
+ return "suppressed";
2260
+ }
2184
2261
  const state = this.store.getActivationDispatchState(input.agentId, input.targetId);
2185
2262
  const inbox = this.ensureInboxForAgent(input.agentId);
2186
- const summary = summarizeActivation(inbox.inboxId, input.newItemCount, input.summary);
2263
+ const summary = summarizeActivation(input.agentId, input.newItemCount, input.summary);
2187
2264
  const totalUnackedCount = input.totalUnackedCount ?? this.store.listInboxEntries(inbox.inboxId, { includeAcked: false }).length;
2188
2265
  const notificationPolicy = notificationPolicyForTarget(target);
2189
2266
  if (!meetsNotificationThreshold(notificationPolicy, totalUnackedCount)) {
@@ -2240,7 +2317,7 @@ class AgentInboxService {
2240
2317
  this.reconcileAgentStatus(target.agentId);
2241
2318
  return "offline";
2242
2319
  }
2243
- const reminder = await this.buildTerminalReminder(target, inbox.inboxId, totalUnackedCount, input.summary, input.entries);
2320
+ const reminder = await this.buildTerminalReminder(target, totalUnackedCount, input.summary, input.entries);
2244
2321
  if (!this.activationTargetExists(input.agentId, input.targetId)) {
2245
2322
  return "offline";
2246
2323
  }
@@ -2459,7 +2536,7 @@ class AgentInboxService {
2459
2536
  updatedAt: (0, util_1.nowIso)(),
2460
2537
  });
2461
2538
  }
2462
- async buildTerminalReminder(target, inboxId, totalUnackedCount, summary, entries) {
2539
+ async buildTerminalReminder(target, totalUnackedCount, summary, entries) {
2463
2540
  let preview = null;
2464
2541
  if (totalUnackedCount === 1 && entries.length === 1 && entries[0]?.kind === "item") {
2465
2542
  const singleItem = entries[0].item;
@@ -2476,7 +2553,7 @@ class AgentInboxService {
2476
2553
  preview ??= (0, terminal_1.deriveInlineItemPreview)(singleItem, summary);
2477
2554
  }
2478
2555
  const prompt = (0, terminal_1.renderAgentPrompt)({
2479
- inboxId,
2556
+ agentId: target.agentId,
2480
2557
  totalUnackedCount,
2481
2558
  summary,
2482
2559
  preview,
@@ -2781,7 +2858,7 @@ class AgentInboxService {
2781
2858
  continue;
2782
2859
  }
2783
2860
  this.notifyInboxWatchers(inbox.ownerAgentId, [entry]);
2784
- const targets = this.store.listActivationTargetsForAgent(inbox.ownerAgentId).filter((target) => target.status === "active");
2861
+ const targets = this.listEffectiveActiveActivationTargets(inbox.ownerAgentId);
2785
2862
  for (const target of targets) {
2786
2863
  this.enqueueActivationTarget(target, {
2787
2864
  agentId: inbox.ownerAgentId,
@@ -3259,7 +3336,13 @@ class ActivationDispatcher {
3259
3336
  }
3260
3337
  }
3261
3338
  exports.ActivationDispatcher = ActivationDispatcher;
3262
- function validateTerminalRegistration(input) {
3339
+ function validateRegisterAgentInput(input) {
3340
+ if (input.webhook) {
3341
+ if (!input.agentId) {
3342
+ throw new Error("webhook agent registration requires agentId");
3343
+ }
3344
+ return;
3345
+ }
3263
3346
  if (input.backend === "tmux") {
3264
3347
  if (!input.tmuxPaneId) {
3265
3348
  throw new Error("tmux agent registration requires tmuxPaneId");
@@ -3272,7 +3355,10 @@ function validateTerminalRegistration(input) {
3272
3355
  }
3273
3356
  return;
3274
3357
  }
3275
- throw new Error(`unsupported terminal backend: ${String(input.backend)}`);
3358
+ if (input.backend) {
3359
+ throw new Error(`unsupported terminal backend: ${input.backend}`);
3360
+ }
3361
+ throw new Error("agent registration requires either a terminal backend or webhook");
3276
3362
  }
3277
3363
  function validateNotifyLeaseMs(value) {
3278
3364
  if (value == null) {
@@ -3360,6 +3446,9 @@ function normalizeWebhookActivationMode(mode) {
3360
3446
  return resolved;
3361
3447
  }
3362
3448
  function findExistingTerminalActivationTarget(store, input) {
3449
+ if (!input.backend) {
3450
+ return null;
3451
+ }
3363
3452
  if (input.runtimeSessionId) {
3364
3453
  const target = store.getTerminalActivationTargetByRuntimeSession(input.runtimeKind ?? "unknown", input.runtimeSessionId);
3365
3454
  if (target) {
@@ -3379,6 +3468,13 @@ function findExistingTerminalActivationTarget(store, input) {
3379
3468
  }
3380
3469
  return null;
3381
3470
  }
3471
+ function effectiveActiveTargets(targets) {
3472
+ const activeWebhookTargets = targets.filter((target) => target.kind === "webhook" && target.status === "active");
3473
+ if (activeWebhookTargets.length > 0) {
3474
+ return activeWebhookTargets;
3475
+ }
3476
+ return targets.filter((target) => target.status === "active");
3477
+ }
3382
3478
  function isSameTerminalIdentity(target, input) {
3383
3479
  if (input.runtimeSessionId && target.runtimeKind === (input.runtimeKind ?? "unknown") && target.runtimeSessionId === input.runtimeSessionId) {
3384
3480
  return true;
@@ -3405,12 +3501,12 @@ function uniqueSortedNullable(values) {
3405
3501
  function notificationBufferKey(agentId, targetId) {
3406
3502
  return `${agentId}::${targetId}`;
3407
3503
  }
3408
- function summarizeActivation(inboxId, newItemCount, firstSummary) {
3504
+ function summarizeActivation(agentId, newItemCount, firstSummary) {
3409
3505
  const itemWord = newItemCount === 1 ? "item" : "items";
3410
3506
  if (firstSummary) {
3411
- return `${newItemCount} new ${itemWord} in ${inboxId} from ${firstSummary}`;
3507
+ return `${newItemCount} new ${itemWord} for agent ${agentId} from ${firstSummary}`;
3412
3508
  }
3413
- return `${newItemCount} new ${itemWord} in ${inboxId}`;
3509
+ return `${newItemCount} new ${itemWord} for agent ${agentId}`;
3414
3510
  }
3415
3511
  function latestEntryIdForNotification(entries) {
3416
3512
  return entries.length > 0 ? entries[entries.length - 1]?.entryId ?? null : null;
package/dist/src/store.js CHANGED
@@ -777,6 +777,28 @@ class AgentInboxStore {
777
777
  }
778
778
  return target;
779
779
  }
780
+ updateWebhookActivationTarget(targetId, input) {
781
+ this.db.run(`
782
+ update activation_targets
783
+ set kind = 'webhook', status = 'active', offline_since = null, last_error = null, consecutive_failures = 0,
784
+ mode = ?, notify_lease_ms = ?, min_unacked_items = ?, url = ?, updated_at = ?, last_seen_at = ?
785
+ where target_id = ? and kind = 'webhook'
786
+ `, [
787
+ input.mode,
788
+ input.notifyLeaseMs,
789
+ input.minUnackedItems,
790
+ input.url,
791
+ input.updatedAt,
792
+ input.lastSeenAt,
793
+ targetId,
794
+ ]);
795
+ this.persist();
796
+ const target = this.getActivationTarget(targetId);
797
+ if (!target || target.kind !== "webhook") {
798
+ throw new Error(`unknown webhook activation target: ${targetId}`);
799
+ }
800
+ return target;
801
+ }
780
802
  updateActivationTargetRuntime(targetId, input) {
781
803
  const current = this.getActivationTarget(targetId);
782
804
  if (!current) {
@@ -72,7 +72,14 @@ function detectTerminalContext(env = process.env) {
72
72
  function renderAgentPrompt(input) {
73
73
  const totalUnackedCount = input.totalUnackedCount;
74
74
  const itemWord = totalUnackedCount === 1 ? "item" : "items";
75
- const base = `AgentInbox: ${totalUnackedCount} unacked ${itemWord} in inbox ${input.inboxId}.`;
75
+ const agentId = normalizeOptionalString(input.agentId ?? null);
76
+ const inboxId = normalizeOptionalString(input.inboxId ?? null);
77
+ const targetLabel = agentId
78
+ ? `for agent ${agentId}`
79
+ : inboxId
80
+ ? `in inbox ${inboxId}`
81
+ : "in inbox";
82
+ const base = `AgentInbox: ${totalUnackedCount} unacked ${itemWord} ${targetLabel}.`;
76
83
  const latestEntryIdSuffix = input.latestEntryId ? ` Latest entryId: ${input.latestEntryId}.` : "";
77
84
  if (totalUnackedCount === 1 && input.preview) {
78
85
  const suffix = /(?:[.!?…]|\.{3})$/.test(input.preview) ? "" : ".";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holon-run/agentinbox",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Local event subscription and delivery service for agents.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {