synomem 0.9.6 → 0.10.0

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.
Files changed (118) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +5 -3
  3. package/dist/actor-directory.d.ts +34 -0
  4. package/dist/actor-directory.d.ts.map +1 -0
  5. package/dist/actor-directory.js +52 -0
  6. package/dist/actor-directory.js.map +1 -0
  7. package/dist/backend.d.ts +3 -0
  8. package/dist/backend.d.ts.map +1 -1
  9. package/dist/backend.js +26 -3
  10. package/dist/backend.js.map +1 -1
  11. package/dist/bookmarks.d.ts +30 -0
  12. package/dist/bookmarks.d.ts.map +1 -0
  13. package/dist/bookmarks.js +87 -0
  14. package/dist/bookmarks.js.map +1 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +291 -61
  17. package/dist/cli.js.map +1 -1
  18. package/dist/client.d.ts +115 -4
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +854 -138
  21. package/dist/client.js.map +1 -1
  22. package/dist/cursors.d.ts +30 -0
  23. package/dist/cursors.d.ts.map +1 -0
  24. package/dist/cursors.js +101 -0
  25. package/dist/cursors.js.map +1 -0
  26. package/dist/errors.d.ts +1 -1
  27. package/dist/errors.d.ts.map +1 -1
  28. package/dist/errors.js +2 -0
  29. package/dist/errors.js.map +1 -1
  30. package/dist/import.d.ts +605 -39
  31. package/dist/import.d.ts.map +1 -1
  32. package/dist/index.d.ts +19 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +11 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp/index.d.ts +1 -1
  37. package/dist/mcp/index.d.ts.map +1 -1
  38. package/dist/mcp/index.js +329 -22
  39. package/dist/mcp/index.js.map +1 -1
  40. package/dist/mutation-receipts.d.ts +8 -0
  41. package/dist/mutation-receipts.d.ts.map +1 -0
  42. package/dist/mutation-receipts.js +2 -0
  43. package/dist/mutation-receipts.js.map +1 -0
  44. package/dist/notifications.d.ts +73 -0
  45. package/dist/notifications.d.ts.map +1 -0
  46. package/dist/notifications.js +309 -0
  47. package/dist/notifications.js.map +1 -0
  48. package/dist/participation-repository.d.ts +46 -0
  49. package/dist/participation-repository.d.ts.map +1 -0
  50. package/dist/participation-repository.js +296 -0
  51. package/dist/participation-repository.js.map +1 -0
  52. package/dist/participation.d.ts +97 -0
  53. package/dist/participation.d.ts.map +1 -0
  54. package/dist/participation.js +10 -0
  55. package/dist/participation.js.map +1 -0
  56. package/dist/policy.d.ts +31 -0
  57. package/dist/policy.d.ts.map +1 -0
  58. package/dist/policy.js +71 -0
  59. package/dist/policy.js.map +1 -0
  60. package/dist/ports/repository.d.ts +23 -0
  61. package/dist/ports/repository.d.ts.map +1 -1
  62. package/dist/profiles.d.ts +12 -0
  63. package/dist/profiles.d.ts.map +1 -1
  64. package/dist/profiles.js +2 -1
  65. package/dist/profiles.js.map +1 -1
  66. package/dist/projections.d.ts.map +1 -1
  67. package/dist/projections.js +29 -11
  68. package/dist/projections.js.map +1 -1
  69. package/dist/remote.d.ts +79 -0
  70. package/dist/remote.d.ts.map +1 -1
  71. package/dist/remote.js +65 -6
  72. package/dist/remote.js.map +1 -1
  73. package/dist/schemas.d.ts +746 -58
  74. package/dist/schemas.d.ts.map +1 -1
  75. package/dist/schemas.js +114 -16
  76. package/dist/schemas.js.map +1 -1
  77. package/dist/search.d.ts +25 -0
  78. package/dist/search.d.ts.map +1 -0
  79. package/dist/search.js +2 -0
  80. package/dist/search.js.map +1 -0
  81. package/dist/service.d.ts +89 -0
  82. package/dist/service.d.ts.map +1 -1
  83. package/dist/storage.d.ts +38 -3
  84. package/dist/storage.d.ts.map +1 -1
  85. package/dist/storage.js +494 -365
  86. package/dist/storage.js.map +1 -1
  87. package/dist/types.d.ts +65 -34
  88. package/dist/types.d.ts.map +1 -1
  89. package/docs/cli.md +6 -0
  90. package/docs/human-participation.md +20 -0
  91. package/docs/mcp.md +2 -0
  92. package/docs/storage-format.md +4 -15
  93. package/openapi/synomem-v1.yaml +187 -10
  94. package/package.json +2 -1
  95. package/skills/synomem/SKILL.md +2 -0
  96. package/src/actor-directory.ts +87 -0
  97. package/src/backend.ts +29 -3
  98. package/src/bookmarks.ts +127 -0
  99. package/src/cli.ts +941 -546
  100. package/src/client.ts +1143 -279
  101. package/src/cursors.ts +132 -0
  102. package/src/errors.ts +2 -0
  103. package/src/index.ts +50 -0
  104. package/src/mcp/index.ts +412 -96
  105. package/src/mutation-receipts.ts +7 -0
  106. package/src/notifications.ts +483 -0
  107. package/src/participation-repository.ts +406 -0
  108. package/src/participation.ts +103 -0
  109. package/src/policy.ts +109 -0
  110. package/src/ports/repository.ts +33 -0
  111. package/src/profiles.ts +2 -1
  112. package/src/projections.ts +49 -48
  113. package/src/remote.ts +227 -37
  114. package/src/schemas.ts +116 -16
  115. package/src/search.ts +24 -0
  116. package/src/service.ts +122 -8
  117. package/src/storage.ts +1039 -697
  118. package/src/types.ts +67 -32
@@ -21,7 +21,6 @@ import type {
21
21
  TaskRecord,
22
22
  TodoRecord,
23
23
  } from './types.js';
24
-
25
24
  /**
26
25
  * The instant a deadline has passed.
27
26
  *
@@ -34,13 +33,10 @@ export function dueInstant(due: TaskDue | undefined): string | undefined {
34
33
  if (!due) return undefined;
35
34
  return due.kind === 'date' ? `${due.date}T23:59:59.999Z` : due.datetime;
36
35
  }
37
-
38
36
  const generatedMarker = '<!-- Generated by Synomem. Rebuild with `synomem rebuild`. -->';
39
-
40
37
  function manifestPath(home: string, path: string): string {
41
38
  return relative(home, path).split(sep).join('/');
42
39
  }
43
-
44
40
  export function escapeMarkdown(value: string): string {
45
41
  return value
46
42
  .replaceAll('&', '&amp;')
@@ -49,13 +45,11 @@ export function escapeMarkdown(value: string): string {
49
45
  .replace(/([\\`*_{}[\]()#+!|])/g, '\\$1')
50
46
  .replace(/^(\s*)(-|\d+\.)\s/gm, '$1\\$2 ');
51
47
  }
52
-
53
48
  function evidenceLine(evidence: EvidenceReference): string {
54
49
  const kind = evidence.kind.replace('-', ' ');
55
50
  const label = evidence.label ? `${escapeMarkdown(evidence.label)} — ` : '';
56
51
  return `- **${escapeMarkdown(kind[0]?.toUpperCase() + kind.slice(1))}:** ${label}${escapeMarkdown(evidence.value)}`;
57
52
  }
58
-
59
53
  function recordMarkdown(record: KudosRecord, includeTitle = true): string {
60
54
  const event = record.event;
61
55
  const lines = [
@@ -75,7 +69,6 @@ function recordMarkdown(record: KudosRecord, includeTitle = true): string {
75
69
  lines.push(`**Kudos ID:** \`${event.id}\``, '');
76
70
  return lines.join('\n');
77
71
  }
78
-
79
72
  function winsMarkdown(profile: AgentProfile, records: KudosRecord[], rebuiltAt: string): string {
80
73
  const active = records.filter((record) => !record.revocation);
81
74
  const lines = [
@@ -101,7 +94,6 @@ function winsMarkdown(profile: AgentProfile, records: KudosRecord[], rebuiltAt:
101
94
  }
102
95
  return `${lines.join('\n')}\n`;
103
96
  }
104
-
105
97
  function inboxMarkdown(record: KudosRecord): string {
106
98
  return `${[
107
99
  generatedMarker,
@@ -111,7 +103,6 @@ function inboxMarkdown(record: KudosRecord): string {
111
103
  recordMarkdown(record, false),
112
104
  ].join('\n')}\n`;
113
105
  }
114
-
115
106
  function memoInboxMarkdown(record: MemoRecord): string {
116
107
  return `${[
117
108
  generatedMarker,
@@ -126,7 +117,6 @@ function memoInboxMarkdown(record: MemoRecord): string {
126
117
  '',
127
118
  ].join('\n')}\n`;
128
119
  }
129
-
130
120
  function taskInboxMarkdown(record: TaskRecord): string {
131
121
  const due =
132
122
  record.current.due?.kind === 'date'
@@ -147,7 +137,6 @@ function taskInboxMarkdown(record: TaskRecord): string {
147
137
  ...(record.current.description ? [escapeMarkdown(record.current.description), ''] : []),
148
138
  ].join('\n')}\n`;
149
139
  }
150
-
151
140
  function memoryMarkdown(profile: AgentProfile, records: NoteRecord[], rebuiltAt: string): string {
152
141
  const active = records.filter((record) => record.status === 'active');
153
142
  const lines = [
@@ -172,7 +161,6 @@ function memoryMarkdown(profile: AgentProfile, records: NoteRecord[], rebuiltAt:
172
161
  }
173
162
  return `${lines.join('\n')}\n`;
174
163
  }
175
-
176
164
  function tasksMarkdown(profile: AgentProfile, records: TaskRecord[], rebuiltAt: string): string {
177
165
  const lines = [
178
166
  generatedMarker,
@@ -202,7 +190,6 @@ function tasksMarkdown(profile: AgentProfile, records: TaskRecord[], rebuiltAt:
202
190
  }
203
191
  return `${lines.join('\n')}\n`;
204
192
  }
205
-
206
193
  export function recordsFromEvents(events: SynomemEvent[]): KudosRecord[] {
207
194
  const acknowledgments = new Map<string, KudosRecord['acknowledgment']>();
208
195
  const revocations = new Map<string, KudosRecord['revocation']>();
@@ -232,7 +219,6 @@ export function recordsFromEvents(events: SynomemEvent[]): KudosRecord[] {
232
219
  b.event.createdAt.localeCompare(a.event.createdAt) || b.event.id.localeCompare(a.event.id),
233
220
  );
234
221
  }
235
-
236
222
  export function memoRecordsFromEvents(events: SynomemEvent[]): MemoRecord[] {
237
223
  const records = new Map<string, MemoRecord>();
238
224
  for (const event of events) {
@@ -254,7 +240,6 @@ export function memoRecordsFromEvents(events: SynomemEvent[]): MemoRecord[] {
254
240
  }
255
241
  return [...records.values()].sort((a, b) => b.event.createdAt.localeCompare(a.event.createdAt));
256
242
  }
257
-
258
243
  /**
259
244
  * Rebuilds posts from their events, acknowledgements included.
260
245
  *
@@ -269,6 +254,7 @@ export function postRecordsFromEvents(events: SynomemEvent[]): PostRecord[] {
269
254
  records.set(event.id, {
270
255
  event,
271
256
  edits: [],
257
+ mentions: event.mentions ?? [],
272
258
  acknowledgments: [],
273
259
  status: 'active',
274
260
  title: event.title,
@@ -286,6 +272,7 @@ export function postRecordsFromEvents(events: SynomemEvent[]): PostRecord[] {
286
272
  const record = records.get(event.postId);
287
273
  if (record) {
288
274
  record.edits.push(event);
275
+ record.mentions = event.mentions ?? [];
289
276
  record.title = event.title;
290
277
  record.body = event.body;
291
278
  if (event.tags) record.tags = event.tags;
@@ -323,7 +310,6 @@ export function postRecordsFromEvents(events: SynomemEvent[]): PostRecord[] {
323
310
  }
324
311
  return [...records.values()];
325
312
  }
326
-
327
313
  export function noteRecordsFromEvents(events: SynomemEvent[]): NoteRecord[] {
328
314
  const records = new Map<string, NoteRecord>();
329
315
  for (const event of events) {
@@ -364,7 +350,6 @@ export function noteRecordsFromEvents(events: SynomemEvent[]): NoteRecord[] {
364
350
  }
365
351
  return [...records.values()].sort((a, b) => b.event.createdAt.localeCompare(a.event.createdAt));
366
352
  }
367
-
368
353
  /**
369
354
  * Builds private Todo records.
370
355
  *
@@ -431,7 +416,6 @@ export function todoRecordsFromEvents(events: SynomemEvent[]): TodoRecord[] {
431
416
  }
432
417
  return [...records.values()];
433
418
  }
434
-
435
419
  export function taskRecordsFromEvents(events: SynomemEvent[]): TaskRecord[] {
436
420
  const records = new Map<string, TaskRecord>();
437
421
  for (const event of events) {
@@ -466,6 +450,14 @@ export function taskRecordsFromEvents(events: SynomemEvent[]): TaskRecord[] {
466
450
  version: event.aggregateVersion,
467
451
  };
468
452
  }
453
+ } else if (event.type === 'task.decision_overridden') {
454
+ const record = records.get(event.taskId);
455
+ if (record) {
456
+ record.status = event.nextStatus;
457
+ record.current.version = event.aggregateVersion;
458
+ record.overrides = [...(record.overrides ?? []), event];
459
+ delete record.terminal;
460
+ }
469
461
  } else if (event.type === 'task.accepted') {
470
462
  const record = records.get(event.taskId);
471
463
  if (record) {
@@ -513,7 +505,6 @@ export function taskRecordsFromEvents(events: SynomemEvent[]): TaskRecord[] {
513
505
  }
514
506
  return [...records.values()].sort((a, b) => b.event.createdAt.localeCompare(a.event.createdAt));
515
507
  }
516
-
517
508
  /** Render a portable human-readable export without reading generated projections. */
518
509
  export function renderMarkdownExport(events: SynomemEvent[]): string {
519
510
  const sections = [
@@ -536,16 +527,18 @@ export function renderMarkdownExport(events: SynomemEvent[]): string {
536
527
  ];
537
528
  return `${sections.join('\n\n')}\n`;
538
529
  }
539
-
540
530
  export class ProjectionManager implements ProjectionWriter {
541
531
  constructor(private readonly storage: SynomemStorage) {}
542
-
543
- rebuild(): { generated: string[]; removed: string[] } {
532
+ rebuild(): {
533
+ generated: string[];
534
+ removed: string[];
535
+ } {
544
536
  this.storage.assertWritable();
545
537
  const events = this.storage.getEvents();
546
538
  this.storage.transactionSync(() => {
547
539
  this.storage.rebuildKudosCurrentIndex();
548
540
  this.storage.rebuildItemsCurrentIndex();
541
+ this.storage.rebuildParticipationCurrentIndex();
549
542
  });
550
543
  const profiles = this.storage.listAgents();
551
544
  const records = recordsFromEvents(events);
@@ -554,7 +547,6 @@ export class ProjectionManager implements ProjectionWriter {
554
547
  const tasks = taskRecordsFromEvents(events);
555
548
  const rebuiltAt = events.at(-1)?.createdAt ?? new Date(0).toISOString();
556
549
  const generated: string[] = [];
557
-
558
550
  for (const profile of profiles) {
559
551
  const agentDirectory = join(this.storage.home, profile.handle);
560
552
  assertNoSymlinkEscape(this.storage.home, agentDirectory);
@@ -571,7 +563,6 @@ export class ProjectionManager implements ProjectionWriter {
571
563
  ensureDirectory(kudosInboxDirectory);
572
564
  ensureDirectory(memoInboxDirectory);
573
565
  ensureDirectory(taskInboxDirectory);
574
-
575
566
  atomicWriteDerivedFile(
576
567
  profilePath,
577
568
  `${JSON.stringify({ _generatedBy: 'synomem', ...profile }, null, 2)}\n`,
@@ -583,19 +574,26 @@ export class ProjectionManager implements ProjectionWriter {
583
574
  `# Notes — ${profile.displayName}\n\n<!-- Human-owned. Synomem will never overwrite this file. -->\n`,
584
575
  );
585
576
  }
586
-
587
- const agentRecords = records.filter((record) => record.event.recipientAgentId === profile.id);
577
+ const agentRecords = records.filter(
578
+ (record) =>
579
+ record.event.recipient?.kind === 'agent' && record.event.recipient.id === profile.id,
580
+ );
588
581
  if (this.storage.config.projection.writeWinsMarkdown) {
589
582
  atomicWriteDerivedFile(winsPath, winsMarkdown(profile, agentRecords, rebuiltAt));
590
583
  generated.push(manifestPath(this.storage.home, winsPath));
591
584
  }
592
- const agentNotes = notes.filter((record) => record.event.ownerAgentId === profile.id);
585
+ const agentNotes = notes.filter(
586
+ (record) => record.event.owner?.kind === 'agent' && record.event.owner.id === profile.id,
587
+ );
593
588
  if (this.storage.config.projection.writeMemoryMarkdown) {
594
589
  const memoryPath = join(agentDirectory, 'MEMORY.md');
595
590
  atomicWriteDerivedFile(memoryPath, memoryMarkdown(profile, agentNotes, rebuiltAt));
596
591
  generated.push(manifestPath(this.storage.home, memoryPath));
597
592
  }
598
- const agentTasks = tasks.filter((record) => record.event.assigneeAgentId === profile.id);
593
+ const agentTasks = tasks.filter(
594
+ (record) =>
595
+ record.event.assignee?.kind === 'agent' && record.event.assignee.id === profile.id,
596
+ );
599
597
  if (this.storage.config.projection.writeTasksMarkdown) {
600
598
  const tasksPath = join(agentDirectory, 'TASKS.md');
601
599
  atomicWriteDerivedFile(tasksPath, tasksMarkdown(profile, agentTasks, rebuiltAt));
@@ -610,7 +608,10 @@ export class ProjectionManager implements ProjectionWriter {
610
608
  generated.push(manifestPath(this.storage.home, inboxPath));
611
609
  }
612
610
  for (const record of memos.filter(
613
- (item) => item.event.recipientAgentId === profile.id && item.status === 'unread',
611
+ (item) =>
612
+ item.event.recipient?.kind === 'agent' &&
613
+ item.event.recipient.id === profile.id &&
614
+ item.status === 'unread',
614
615
  )) {
615
616
  const inboxPath = join(memoInboxDirectory, `${record.event.id}.md`);
616
617
  atomicWriteDerivedFile(inboxPath, memoInboxMarkdown(record));
@@ -625,7 +626,6 @@ export class ProjectionManager implements ProjectionWriter {
625
626
  }
626
627
  }
627
628
  }
628
-
629
629
  const keep = new Set(generated);
630
630
  const removed: string[] = [];
631
631
  for (const stale of this.storage.projectionManifest()) {
@@ -643,7 +643,6 @@ export class ProjectionManager implements ProjectionWriter {
643
643
  this.storage.replaceProjectionManifest(generated, rebuiltAt);
644
644
  return { generated: generated.sort(), removed: removed.sort() };
645
645
  }
646
-
647
646
  /**
648
647
  * Move an agent's directory when its handle changes.
649
648
  *
@@ -680,23 +679,28 @@ export class ProjectionManager implements ProjectionWriter {
680
679
  renameSync(from, to);
681
680
  this.storage.renameProjectionManifestPrefix(previousHandle, nextHandle);
682
681
  }
683
-
684
- syncAgent(agentId: string): { generated: string[]; removed: string[] } {
682
+ syncAgent(agentId: string): {
683
+ generated: string[];
684
+ removed: string[];
685
+ } {
685
686
  this.storage.assertWritable();
686
687
  const profile = this.storage.getAgent(agentId);
687
688
  if (!profile) throw new SynomemError('AGENT_NOT_FOUND', `Unknown agent: ${agentId}`);
688
689
  const events = this.storage.getEvents();
689
690
  const records = recordsFromEvents(events).filter(
690
- (record) => record.event.recipientAgentId === profile.id,
691
+ (record) =>
692
+ record.event.recipient?.kind === 'agent' && record.event.recipient.id === profile.id,
691
693
  );
692
694
  const memos = memoRecordsFromEvents(events).filter(
693
- (record) => record.event.recipientAgentId === profile.id,
695
+ (record) =>
696
+ record.event.recipient?.kind === 'agent' && record.event.recipient.id === profile.id,
694
697
  );
695
698
  const notes = noteRecordsFromEvents(events).filter(
696
- (record) => record.event.ownerAgentId === profile.id,
699
+ (record) => record.event.owner?.kind === 'agent' && record.event.owner.id === profile.id,
697
700
  );
698
701
  const tasks = taskRecordsFromEvents(events).filter(
699
- (record) => record.event.assigneeAgentId === profile.id,
702
+ (record) =>
703
+ record.event.assignee?.kind === 'agent' && record.event.assignee.id === profile.id,
700
704
  );
701
705
  const rebuiltAt = events.at(-1)?.createdAt ?? new Date(0).toISOString();
702
706
  const agentDirectory = join(this.storage.home, profile.handle);
@@ -711,7 +715,6 @@ export class ProjectionManager implements ProjectionWriter {
711
715
  ensureDirectory(kudosInboxDirectory);
712
716
  ensureDirectory(memoInboxDirectory);
713
717
  ensureDirectory(taskInboxDirectory);
714
-
715
718
  const generated: string[] = [];
716
719
  const profilePath = join(agentDirectory, 'profile.json');
717
720
  atomicWriteDerivedFile(
@@ -719,7 +722,6 @@ export class ProjectionManager implements ProjectionWriter {
719
722
  `${JSON.stringify({ _generatedBy: 'synomem', ...profile }, null, 2)}\n`,
720
723
  );
721
724
  generated.push(manifestPath(this.storage.home, profilePath));
722
-
723
725
  const notesPath = join(agentDirectory, 'NOTES.md');
724
726
  if (!existsSync(notesPath)) {
725
727
  atomicWriteFile(
@@ -727,25 +729,21 @@ export class ProjectionManager implements ProjectionWriter {
727
729
  `# Notes — ${profile.displayName}\n\n<!-- Human-owned. Synomem will never overwrite this file. -->\n`,
728
730
  );
729
731
  }
730
-
731
732
  if (this.storage.config.projection.writeWinsMarkdown) {
732
733
  const winsPath = join(agentDirectory, 'WINS.md');
733
734
  atomicWriteDerivedFile(winsPath, winsMarkdown(profile, records, rebuiltAt));
734
735
  generated.push(manifestPath(this.storage.home, winsPath));
735
736
  }
736
-
737
737
  if (this.storage.config.projection.writeMemoryMarkdown) {
738
738
  const memoryPath = join(agentDirectory, 'MEMORY.md');
739
739
  atomicWriteDerivedFile(memoryPath, memoryMarkdown(profile, notes, rebuiltAt));
740
740
  generated.push(manifestPath(this.storage.home, memoryPath));
741
741
  }
742
-
743
742
  if (this.storage.config.projection.writeTasksMarkdown) {
744
743
  const tasksPath = join(agentDirectory, 'TASKS.md');
745
744
  atomicWriteDerivedFile(tasksPath, tasksMarkdown(profile, tasks, rebuiltAt));
746
745
  generated.push(manifestPath(this.storage.home, tasksPath));
747
746
  }
748
-
749
747
  if (this.storage.config.projection.writeInboxEntries) {
750
748
  for (const record of records.filter(
751
749
  (item) => item.status === 'unacknowledged' && item.revocationStatus === 'active',
@@ -770,7 +768,6 @@ export class ProjectionManager implements ProjectionWriter {
770
768
  generated.push(relativePath);
771
769
  }
772
770
  }
773
-
774
771
  const keep = new Set(generated);
775
772
  const prefixes = [`${profile.handle}/`, `${profile.handle}\\`];
776
773
  const removed: string[] = [];
@@ -791,7 +788,6 @@ export class ProjectionManager implements ProjectionWriter {
791
788
  this.storage.replaceAgentProjectionManifest(profile.handle, generated, rebuiltAt);
792
789
  return { generated: generated.sort(), removed: removed.sort() };
793
790
  }
794
-
795
791
  /*
796
792
  * The paths a rebuild would produce, for comparison against the manifest.
797
793
  *
@@ -817,20 +813,25 @@ export class ProjectionManager implements ProjectionWriter {
817
813
  if (this.storage.config.projection.writeInboxEntries) {
818
814
  for (const record of records.filter(
819
815
  (item) =>
820
- item.event.recipientAgentId === profile.id &&
816
+ item.event.recipient?.kind === 'agent' &&
817
+ item.event.recipient.id === profile.id &&
821
818
  item.status === 'unacknowledged' &&
822
819
  item.revocationStatus === 'active',
823
820
  )) {
824
821
  paths.push(`${profile.handle}/inbox/kudos/${record.event.id}.md`);
825
822
  }
826
823
  for (const record of memos.filter(
827
- (item) => item.event.recipientAgentId === profile.id && item.status === 'unread',
824
+ (item) =>
825
+ item.event.recipient?.kind === 'agent' &&
826
+ item.event.recipient.id === profile.id &&
827
+ item.status === 'unread',
828
828
  )) {
829
829
  paths.push(`${profile.handle}/inbox/memos/${record.event.id}.md`);
830
830
  }
831
831
  for (const record of tasks.filter(
832
832
  (item) =>
833
- item.event.assigneeAgentId === profile.id &&
833
+ item.event.assignee?.kind === 'agent' &&
834
+ item.event.assignee.id === profile.id &&
834
835
  (item.status === 'open' || item.status === 'assigned'),
835
836
  )) {
836
837
  paths.push(`${profile.handle}/inbox/tasks/${record.event.id}.md`);