@plotday/twister 0.26.0 → 0.28.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 (120) hide show
  1. package/README.md +10 -4
  2. package/bin/commands/deploy.js +15 -7
  3. package/bin/commands/deploy.js.map +1 -1
  4. package/bin/templates/AGENTS.template.md +119 -33
  5. package/bin/utils/sse.js +19 -1
  6. package/bin/utils/sse.js.map +1 -1
  7. package/cli/templates/AGENTS.template.md +119 -33
  8. package/dist/common/calendar.d.ts +23 -11
  9. package/dist/common/calendar.d.ts.map +1 -1
  10. package/dist/common/messaging.d.ts +21 -6
  11. package/dist/common/messaging.d.ts.map +1 -1
  12. package/dist/common/projects.d.ts +25 -17
  13. package/dist/common/projects.d.ts.map +1 -1
  14. package/dist/docs/assets/hierarchy.js +1 -1
  15. package/dist/docs/assets/navigation.js +1 -1
  16. package/dist/docs/assets/search.js +1 -1
  17. package/dist/docs/classes/tool.Tool.html +20 -15
  18. package/dist/docs/classes/tools_ai.AI.html +1 -1
  19. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  20. package/dist/docs/classes/tools_integrations.Integrations.html +1 -1
  21. package/dist/docs/classes/tools_network.Network.html +1 -1
  22. package/dist/docs/classes/tools_plot.Plot.html +2 -2
  23. package/dist/docs/classes/tools_store.Store.html +13 -4
  24. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  25. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  26. package/dist/docs/documents/Building_Custom_Tools.html +8 -2
  27. package/dist/docs/documents/Built-in_Tools.html +19 -8
  28. package/dist/docs/documents/Core_Concepts.html +14 -6
  29. package/dist/docs/documents/Getting_Started.html +11 -4
  30. package/dist/docs/documents/Runtime_Environment.html +1 -1
  31. package/dist/docs/enums/plot.ActivityLinkType.html +5 -5
  32. package/dist/docs/enums/plot.ActivityType.html +4 -4
  33. package/dist/docs/enums/plot.ActorType.html +4 -4
  34. package/dist/docs/enums/plot.ConferencingProvider.html +6 -6
  35. package/dist/docs/enums/tools_plot.ContactAccess.html +1 -1
  36. package/dist/docs/functions/index.Uuid.Generate.html +1 -0
  37. package/dist/docs/hierarchy.html +1 -1
  38. package/dist/docs/index.html +10 -0
  39. package/dist/docs/interfaces/common_calendar.CalendarTool.html +23 -13
  40. package/dist/docs/media/SYNC_STRATEGIES.md +651 -0
  41. package/dist/docs/modules/index.Uuid.html +1 -0
  42. package/dist/docs/modules/index.html +1 -1
  43. package/dist/docs/modules/plot.html +1 -1
  44. package/dist/docs/types/index.Uuid.html +1 -0
  45. package/dist/docs/types/plot.Activity.html +17 -15
  46. package/dist/docs/types/plot.ActivityCommon.html +16 -16
  47. package/dist/docs/types/plot.ActivityLink.html +1 -1
  48. package/dist/docs/types/plot.ActivityMeta.html +5 -25
  49. package/dist/docs/types/plot.ActivityUpdate.html +5 -4
  50. package/dist/docs/types/plot.ActivityWithNotes.html +1 -1
  51. package/dist/docs/types/plot.Actor.html +5 -5
  52. package/dist/docs/types/plot.ActorId.html +1 -1
  53. package/dist/docs/types/plot.ContentType.html +1 -1
  54. package/dist/docs/types/plot.NewActivity.html +32 -14
  55. package/dist/docs/types/plot.NewActivityWithNotes.html +1 -1
  56. package/dist/docs/types/plot.NewActor.html +3 -0
  57. package/dist/docs/types/plot.NewContact.html +4 -4
  58. package/dist/docs/types/plot.NewNote.html +14 -4
  59. package/dist/docs/types/plot.NewPriority.html +1 -1
  60. package/dist/docs/types/plot.NewTags.html +2 -0
  61. package/dist/docs/types/plot.Note.html +6 -3
  62. package/dist/docs/types/plot.NoteUpdate.html +7 -6
  63. package/dist/docs/types/plot.PickPriorityConfig.html +2 -2
  64. package/dist/docs/types/plot.Priority.html +3 -3
  65. package/dist/docs/types/plot.SyncUpdate.html +15 -0
  66. package/dist/docs/types/plot.Tags.html +2 -1
  67. package/dist/llm-docs/common/calendar.d.ts +1 -1
  68. package/dist/llm-docs/common/calendar.d.ts.map +1 -1
  69. package/dist/llm-docs/common/calendar.js +1 -1
  70. package/dist/llm-docs/common/calendar.js.map +1 -1
  71. package/dist/llm-docs/common/messaging.d.ts +1 -1
  72. package/dist/llm-docs/common/messaging.d.ts.map +1 -1
  73. package/dist/llm-docs/common/messaging.js +1 -1
  74. package/dist/llm-docs/common/messaging.js.map +1 -1
  75. package/dist/llm-docs/common/projects.d.ts +1 -1
  76. package/dist/llm-docs/common/projects.d.ts.map +1 -1
  77. package/dist/llm-docs/common/projects.js +1 -1
  78. package/dist/llm-docs/common/projects.js.map +1 -1
  79. package/dist/llm-docs/plot.d.ts +1 -1
  80. package/dist/llm-docs/plot.d.ts.map +1 -1
  81. package/dist/llm-docs/plot.js +1 -1
  82. package/dist/llm-docs/plot.js.map +1 -1
  83. package/dist/llm-docs/tool.d.ts +1 -1
  84. package/dist/llm-docs/tool.d.ts.map +1 -1
  85. package/dist/llm-docs/tool.js +1 -1
  86. package/dist/llm-docs/tool.js.map +1 -1
  87. package/dist/llm-docs/tools/plot.d.ts +1 -1
  88. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  89. package/dist/llm-docs/tools/plot.js +1 -1
  90. package/dist/llm-docs/tools/plot.js.map +1 -1
  91. package/dist/llm-docs/tools/store.d.ts +1 -1
  92. package/dist/llm-docs/tools/store.d.ts.map +1 -1
  93. package/dist/llm-docs/tools/store.js +1 -1
  94. package/dist/llm-docs/tools/store.js.map +1 -1
  95. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  96. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  97. package/dist/llm-docs/twist-guide-template.js +1 -1
  98. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  99. package/dist/plot.d.ts +230 -149
  100. package/dist/plot.d.ts.map +1 -1
  101. package/dist/plot.js +1 -0
  102. package/dist/plot.js.map +1 -1
  103. package/dist/tool.d.ts +16 -2
  104. package/dist/tool.d.ts.map +1 -1
  105. package/dist/tool.js +16 -2
  106. package/dist/tool.js.map +1 -1
  107. package/dist/tools/plot.d.ts +2 -2
  108. package/dist/tools/plot.d.ts.map +1 -1
  109. package/dist/tools/plot.js +1 -1
  110. package/dist/tools/plot.js.map +1 -1
  111. package/dist/tools/store.d.ts +16 -0
  112. package/dist/tools/store.d.ts.map +1 -1
  113. package/dist/tools/store.js.map +1 -1
  114. package/dist/twist-guide.d.ts +1 -1
  115. package/dist/twist-guide.d.ts.map +1 -1
  116. package/dist/utils/uuid.d.ts +7 -0
  117. package/dist/utils/uuid.d.ts.map +1 -0
  118. package/dist/utils/uuid.js +9 -0
  119. package/dist/utils/uuid.js.map +1 -0
  120. package/package.json +9 -2
@@ -27,19 +27,40 @@ Plot Twists are TypeScript classes that extend the `Twist` base class. Twists in
27
27
 
28
28
  1. **Always create Activities with an initial Note** - The title is just a summary; detailed content goes in Notes
29
29
  2. **Add Notes to existing Activities for updates** - Don't create a new Activity for each related message
30
- 3. **Use `source` field for deduplication** - Enables safe, idempotent sync from external systems
31
- 4. **Most Activities should be `ActivityType.Note`** - Use `Action` only for tasks with `doneAt`, use `Event` only for items with `start`/`end`
30
+ 3. **Use Activity.source and Note.key for automatic upserts (Recommended)** - Set Activity.source to the external item's URL for deduplication, and use Note.key for upsertable note content. No manual ID tracking needed.
31
+ 4. **For advanced cases, use generated UUIDs** - Only when you need multiple Plot activities per external item (see SYNC_STRATEGIES.md)
32
+ 5. **Most Activities should be `ActivityType.Note`** - Use `Action` only for tasks with `done`, use `Event` only for items with `start`/`end`
32
33
 
33
- ### Decision Tree
34
+ ### Recommended Decision Tree (Strategy 2: Upsert via Source/Key)
35
+
36
+ ```
37
+ New event/task/conversation from external system?
38
+ ├─ Has stable URL or ID?
39
+ │ └─ Yes → Set Activity.source to the canonical URL/ID
40
+ │ Create Activity (Plot handles deduplication automatically)
41
+ │ Use Note.key for different note types:
42
+ │ - "description" for main content
43
+ │ - "metadata" for status/priority/assignee
44
+ │ - "comment-{id}" for individual comments
45
+
46
+ └─ No stable identifier OR need multiple Plot activities per external item?
47
+ └─ Use Advanced Pattern (Strategy 3: Generate and Store IDs)
48
+ See SYNC_STRATEGIES.md for details
49
+ ```
50
+
51
+ ### Advanced Decision Tree (Strategy 3: Generate and Store IDs)
52
+
53
+ Only use when source/key upserts aren't sufficient (e.g., creating multiple activities from one external item):
34
54
 
35
55
  ```
36
56
  New event/task/conversation?
37
- ├─ Yes → Create new Activity with initial Note
38
- Include `source` field for deduplication
57
+ ├─ Yes → Generate UUID with Uuid.Generate()
58
+ Create new Activity with that UUID
59
+ │ Store mapping: external_id → activity_uuid
39
60
 
40
- └─ No (update/reply/comment) → Check for existing Activity
41
- ├─ Found → Add Note to existing Activity
42
- └─ Not found → Create new Activity with initial Note
61
+ └─ No (update/reply/comment) → Look up mapping by external_id
62
+ ├─ Found → Add Note to existing Activity using stored UUID
63
+ └─ Not found → Create new Activity with UUID + store mapping
43
64
  ```
44
65
 
45
66
  ## Twist Structure Pattern
@@ -52,6 +73,7 @@ import {
52
73
  twist,
53
74
  } from "@plotday/twister";
54
75
  import { Plot } from "@plotday/twister/tools/plot";
76
+ import { Uuid } from "@plotday/twister/utils/uuid";
55
77
 
56
78
  export default class MyTwist extends Twist<MyTwist> {
57
79
  build(build: ToolBuilder) {
@@ -267,7 +289,9 @@ async onAuthComplete(authResult: { authToken: string }, provider: string) {
267
289
 
268
290
  ## Sync Pattern
269
291
 
270
- Pattern for syncing external data - demonstrates adding Notes to existing Activities:
292
+ ### Recommended: Upsert via Source/Key (Strategy 2)
293
+
294
+ Pattern for syncing external data using automatic upserts - **no manual ID tracking needed**:
271
295
 
272
296
  ```typescript
273
297
  async startSync(calendarId: string): Promise<void> {
@@ -282,29 +306,43 @@ async startSync(calendarId: string): Promise<void> {
282
306
  }
283
307
 
284
308
  async handleEvent(
285
- incomingActivity: NewActivityWithNotes,
309
+ event: ExternalEvent,
286
310
  calendarId: string
287
311
  ): Promise<void> {
288
- // Check if this activity already exists (using source for deduplication)
289
- if (incomingActivity.source) {
290
- const existing = await this.tools.plot.getActivityBySource(
291
- incomingActivity.source
292
- );
312
+ // Use the event's canonical URL as the source for automatic deduplication
313
+ const activity: NewActivityWithNotes = {
314
+ source: event.htmlLink, // or event.url, depending on your external system
315
+ type: ActivityType.Event,
316
+ title: event.summary || "(No title)",
317
+ start: event.start?.dateTime || event.start?.date || null,
318
+ end: event.end?.dateTime || event.end?.date || null,
319
+ notes: [],
320
+ };
293
321
 
294
- if (existing) {
295
- // Add update as a Note to existing Activity (add message to thread)
296
- if (incomingActivity.notes?.[0]?.content) {
297
- await this.tools.plot.createNote({
298
- activity: { id: existing.id },
299
- content: incomingActivity.notes[0].content,
300
- });
301
- }
302
- return;
303
- }
322
+ // Add description as an upsertable note
323
+ if (event.description) {
324
+ activity.notes.push({
325
+ activity: { source: event.htmlLink },
326
+ key: "description", // This key enables upserts - same key updates the note
327
+ content: event.description,
328
+ });
304
329
  }
305
330
 
306
- // Create new Activity with initial Note (new thread with first message)
307
- await this.tools.plot.createActivity(incomingActivity);
331
+ // Add attendees as an upsertable note
332
+ if (event.attendees?.length) {
333
+ const attendeeList = event.attendees
334
+ .map(a => `- ${a.email}${a.displayName ? ` (${a.displayName})` : ''}`)
335
+ .join('\n');
336
+
337
+ activity.notes.push({
338
+ activity: { source: event.htmlLink },
339
+ key: "attendees", // Different key for different note types
340
+ content: `## Attendees\n${attendeeList}`,
341
+ });
342
+ }
343
+
344
+ // Create or update - Plot automatically handles deduplication based on source
345
+ await this.tools.plot.createActivity(activity);
308
346
  }
309
347
 
310
348
  async stopSync(calendarId: string): Promise<void> {
@@ -313,6 +351,50 @@ async stopSync(calendarId: string): Promise<void> {
313
351
  }
314
352
  ```
315
353
 
354
+ ### Advanced: Generate and Store IDs (Strategy 3)
355
+
356
+ Only use this pattern when you need to create multiple Plot activities from a single external item, or when the external system doesn't provide stable identifiers. See SYNC_STRATEGIES.md for details.
357
+
358
+ ```typescript
359
+ async handleEventAdvanced(
360
+ incomingActivity: NewActivityWithNotes,
361
+ calendarId: string
362
+ ): Promise<void> {
363
+ // Extract external event ID from meta (adapt based on your tool's data)
364
+ const externalId = incomingActivity.meta?.eventId;
365
+
366
+ if (!externalId) {
367
+ console.error("Event missing external ID");
368
+ return;
369
+ }
370
+
371
+ // Check if we've already synced this event
372
+ const mappingKey = `event_mapping:${calendarId}:${externalId}`;
373
+ const existingActivityId = await this.get<Uuid>(mappingKey);
374
+
375
+ if (existingActivityId) {
376
+ // Event already exists - add update as a Note (add message to thread)
377
+ if (incomingActivity.notes?.[0]?.content) {
378
+ await this.tools.plot.createNote({
379
+ activity: { id: existingActivityId },
380
+ content: incomingActivity.notes[0].content,
381
+ });
382
+ }
383
+ return;
384
+ }
385
+
386
+ // New event - generate UUID and store mapping
387
+ const activityId = Uuid.Generate();
388
+ await this.set(mappingKey, activityId);
389
+
390
+ // Create new Activity with initial Note (new thread with first message)
391
+ await this.tools.plot.createActivity({
392
+ ...incomingActivity,
393
+ id: activityId,
394
+ });
395
+ }
396
+ ```
397
+
316
398
  ## Calendar Selection Pattern
317
399
 
318
400
  Pattern for letting users select from multiple calendars/accounts:
@@ -405,13 +487,17 @@ async syncBatch(args: any, resourceId: string): Promise<void> {
405
487
  // Process one batch (keep under time limit)
406
488
  const result = await this.fetchBatch(state.nextPageToken);
407
489
 
408
- // Process results (create activities with Notes)
490
+ // Process results using source/key pattern (automatic upserts, no manual tracking)
409
491
  for (const item of result.items) {
410
492
  await this.tools.plot.createActivity({
493
+ source: item.url, // Use item's canonical URL for automatic deduplication
411
494
  type: ActivityType.Note,
412
495
  title: item.title,
413
- source: `external:${item.id}`, // For deduplication
414
- notes: [{ content: item.description }],
496
+ notes: [{
497
+ activity: { source: item.url },
498
+ key: "description", // Use key for upsertable notes
499
+ content: item.description,
500
+ }],
415
501
  });
416
502
  }
417
503
 
@@ -471,9 +557,9 @@ try {
471
557
  - **Don't use instance variables for state** - Anything stored in memory is lost after function execution. Always use the Store tool for data that needs to persist.
472
558
  - **Processing self-created activities** - Other users may change an Activity created by the twist, resulting in an \`activity\` call. Be sure to check the \`changes === null\` and/or \`activity.author.id !== this.id\` to avoid re-processing.
473
559
  - **Always create Activities with Notes** - See "Understanding Activities and Notes" section above for the thread/message pattern and decision tree.
474
- - **Use correct Activity types** - Most should be `ActivityType.Note`. Only use `Action` for tasks with `doneAt`, and `Event` for items with `start`/`end`.
475
- - **Use `source` field for deduplication** - Always include `source` when syncing external data to enable safe, idempotent operations.
476
- - **Add Notes to existing Activities** - Check for existing Activities with `getActivityBySource()` before creating new ones. Think thread replies, not new threads.
560
+ - **Use correct Activity types** - Most should be `ActivityType.Note`. Only use `Action` for tasks with `done`, and `Event` for items with `start`/`end`.
561
+ - **Use Activity.source and Note.key for automatic upserts (Recommended)** - Set Activity.source to the external item's URL for automatic deduplication. Only use UUID generation and storage for advanced cases (see SYNC_STRATEGIES.md).
562
+ - **Add Notes to existing Activities** - For source/key pattern, reference activities by source. For UUID pattern, look up stored mappings before creating new Activities. Think thread replies, not new threads.
477
563
  - Tools are declared in the `build` method and accessed via `this.tools.toolName` in twist methods.
478
564
  - **Don't forget runtime limits** - Each execution has ~10 seconds. Break long operations into batches with the Tasks tool. Process enough items per batch to be efficient, but few enough to stay under time limits.
479
565
  - **Always use Callbacks tool for persistent references** - Direct function references don't survive worker restarts.
@@ -1,4 +1,4 @@
1
- import type { ActivityLink, NewActivityWithNotes } from "../index";
1
+ import type { ActivityLink, SyncUpdate } from "../index";
2
2
  /**
3
3
  * Represents successful calendar authorization.
4
4
  *
@@ -54,9 +54,13 @@ export interface SyncOptions {
54
54
  * 5. Start sync for selected calendars
55
55
  * 6. Process incoming events via callbacks
56
56
  *
57
+ * **Recommended Data Sync Strategy:**
58
+ * Use Activity.source and Note.key for automatic upserts without manual ID tracking.
59
+ * See SYNC_STRATEGIES.md for detailed patterns and when to use alternative approaches.
60
+ *
57
61
  * @example
58
62
  * ```typescript
59
- * // Typical calendar integration flow
63
+ * // Typical calendar integration flow using source/key upserts
60
64
  * class MyCalendarTwist extends Twist {
61
65
  * private googleCalendar: GoogleCalendar;
62
66
  *
@@ -86,11 +90,13 @@ export interface SyncOptions {
86
90
  * }
87
91
  *
88
92
  * async onCalendarEvent(
89
- * activity: NewActivityWithNotes,
93
+ * syncUpdate: SyncUpdate,
90
94
  * syncMeta: { initialSync: boolean }
91
95
  * ) {
92
- * // Step 4: Process synced events
93
- * await this.plot.createActivity(activity);
96
+ * // Step 4: Process synced events using source/key pattern
97
+ * // The sync update will automatically use the event's URL as the source
98
+ * // for deduplication - no manual ID tracking needed
99
+ * await this.plot.createActivity(syncUpdate);
94
100
  * }
95
101
  * }
96
102
  * ```
@@ -123,19 +129,25 @@ export interface CalendarTool {
123
129
  * event import and ongoing change notifications. The callback function
124
130
  * will be invoked for each synced event.
125
131
  *
126
- * Tools implementing this should set activity.unread based on sync type:
127
- * - Initial sync (historical data): Set activity.unread = false
128
- * - Incremental updates (webhooks): Set activity.unread = true or leave undefined
132
+ * **Recommended Implementation** (Strategy 2 - Upsert via Source/Key):
133
+ * - Set Activity.source to the event's canonical URL (e.g., event.htmlLink)
134
+ * - Use Note.key for event details (description, attendees, etc.) to enable upserts
135
+ * - No manual ID tracking needed - Plot handles deduplication automatically
136
+ * - Send NewActivityWithNotes for all events (creates new or updates existing)
137
+ * - Set activity.unread = false for initial sync, true for incremental updates
138
+ *
139
+ * **Alternative** (Strategy 3 - Advanced cases):
140
+ * - Use Uuid.Generate() and store ID mappings when creating multiple activities per event
141
+ * - See SYNC_STRATEGIES.md for when this is appropriate
129
142
  *
130
143
  * @param authToken - Authorization token for calendar access
131
144
  * @param calendarId - ID of the calendar to sync
132
- * @param callback - Function receiving (activity, ...extraArgs) for each synced event.
133
- * The activity.unread field indicates whether this is from initial sync.
145
+ * @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced event
134
146
  * @param extraArgs - Additional arguments to pass to the callback (type-checked)
135
147
  * @returns Promise that resolves when sync setup is complete
136
148
  * @throws When auth token is invalid or calendar doesn't exist
137
149
  */
138
- startSync<TCallback extends (activity: NewActivityWithNotes, ...args: any[]) => any>(authToken: string, calendarId: string, callback: TCallback, ...extraArgs: TCallback extends (activity: any, ...rest: infer R) => any ? R : []): Promise<void>;
150
+ startSync<TCallback extends (syncUpdate: SyncUpdate, ...args: any[]) => any>(authToken: string, calendarId: string, callback: TCallback, ...extraArgs: TCallback extends (syncUpdate: any, ...rest: infer R) => any ? R : []): Promise<void>;
139
151
  /**
140
152
  * Stops synchronizing events from a specific calendar.
141
153
  *
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../src/common/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACvE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErD;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CACP,SAAS,SAAS,CAChB,QAAQ,EAAE,oBAAoB,EAC9B,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,EAER,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAC9B,QAAQ,EAAE,GAAG,EACb,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,GAAG,GACJ,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE"}
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../src/common/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAE/E;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACvE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,SAAS,CACP,SAAS,SAAS,CAChB,UAAU,EAAE,UAAU,EACtB,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,EAER,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAC9B,UAAU,EAAE,GAAG,EACf,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,GAAG,GACJ,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE"}
@@ -1,4 +1,4 @@
1
- import type { ActivityLink, NewActivityWithNotes } from "../index";
1
+ import type { ActivityLink, SyncUpdate } from "../index";
2
2
  /**
3
3
  * Represents a successful messaging service authorization.
4
4
  *
@@ -41,6 +41,10 @@ export interface MessageSyncOptions {
41
41
  *
42
42
  * All synced messages/emails are converted to ActivityWithNotes objects.
43
43
  * Each email thread or chat conversation becomes an Activity with Notes for each message.
44
+ *
45
+ * **Recommended Data Sync Strategy:**
46
+ * Use Activity.source (thread URL or ID) and Note.key (message ID) for automatic upserts.
47
+ * See SYNC_STRATEGIES.md for detailed patterns.
44
48
  */
45
49
  export interface MessagingTool {
46
50
  /**
@@ -61,18 +65,29 @@ export interface MessagingTool {
61
65
  /**
62
66
  * Begins synchronizing messages from a specific channel.
63
67
  *
64
- * Email threads and chat conversations are converted to ActivityWithNotes objects.
65
- * Each object contains an Activity (with subject/title) and Notes array (one per message).
66
- * The Activity.id can be used as a stable conversation identifier.
68
+ * Email threads and chat conversations are converted to SyncUpdate objects,
69
+ * which can be either new items or updates to existing items.
70
+ *
71
+ * **Recommended Implementation** (Strategy 2 - Upsert via Source/Key):
72
+ * - Set Activity.source to the thread/conversation URL or stable ID (e.g., "slack:{channelId}:{threadTs}")
73
+ * - Use Note.key for individual messages (e.g., "message-{messageId}")
74
+ * - Each message becomes a separate note with unique key for upserts
75
+ * - No manual ID tracking needed - Plot handles deduplication automatically
76
+ * - Send NewActivityWithNotes for all threads (creates new or updates existing)
77
+ * - Set activity.unread = false for initial sync, true for incremental updates
78
+ *
79
+ * **Alternative** (Strategy 3 - Advanced cases):
80
+ * - Use Uuid.Generate() and store ID mappings when creating multiple activities per thread
81
+ * - See SYNC_STRATEGIES.md for when this is appropriate
67
82
  *
68
83
  * @param authToken - Authorization token for access
69
84
  * @param channelId - ID of the channel (e.g., channel, inbox) to sync
70
- * @param callback - Function receiving (thread, ...extraArgs) for each synced conversation
85
+ * @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced conversation
71
86
  * @param options - Optional configuration for limiting the sync scope (e.g., time range)
72
87
  * @param extraArgs - Additional arguments to pass to the callback (type-checked)
73
88
  * @returns Promise that resolves when sync setup is complete
74
89
  */
75
- startSync<TCallback extends (thread: NewActivityWithNotes, ...args: any[]) => any>(authToken: string, channelId: string, callback: TCallback, options?: MessageSyncOptions, ...extraArgs: TCallback extends (thread: any, ...rest: infer R) => any ? R : []): Promise<void>;
90
+ startSync<TCallback extends (syncUpdate: SyncUpdate, ...args: any[]) => any>(authToken: string, channelId: string, callback: TCallback, options?: MessageSyncOptions, ...extraArgs: TCallback extends (syncUpdate: any, ...rest: infer R) => any ? R : []): Promise<void>;
76
91
  /**
77
92
  * Stops synchronizing messages from a specific channel.
78
93
  *
@@ -1 +1 @@
1
- {"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../../src/common/messaging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAE1D;;;;;;;;;;;;;OAaG;IACH,SAAS,CACP,SAAS,SAAS,CAAC,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAEvE,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAClE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D"}
1
+ {"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../../src/common/messaging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAE/E;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAE1D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,SAAS,CACP,SAAS,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAEjE,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GACtE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D"}
@@ -1,4 +1,4 @@
1
- import type { ActivityLink, ActivityUpdate, NewActivityWithNotes } from "../index";
1
+ import type { ActivityLink, ActivityUpdate, SyncUpdate } from "../index";
2
2
  /**
3
3
  * Represents a successful project management service authorization.
4
4
  *
@@ -41,6 +41,10 @@ export interface ProjectSyncOptions {
41
41
  *
42
42
  * All synced issues/tasks are converted to ActivityWithNotes objects.
43
43
  * Each issue becomes an Activity with Notes for the description and comments.
44
+ *
45
+ * **Recommended Data Sync Strategy:**
46
+ * Use Activity.source (issue URL) and Note.key for automatic upserts.
47
+ * See SYNC_STRATEGIES.md for detailed patterns.
44
48
  */
45
49
  export interface ProjectTool {
46
50
  /**
@@ -61,27 +65,31 @@ export interface ProjectTool {
61
65
  /**
62
66
  * Begins synchronizing issues from a specific project.
63
67
  *
64
- * Issues and tasks are converted to ActivityWithNotes objects.
65
- * Each object contains an Activity (with issue title and metadata) and Notes array
66
- * (description as first note, followed by comments).
67
- * The Activity.source should be set for deduplication.
68
+ * Issues and tasks are converted to SyncUpdate objects, which can be either
69
+ * new items or updates to existing items.
68
70
  *
69
- * When an issue is updated, tools should check for existing Activity using
70
- * getActivityBySource() and add a Note rather than creating a new Activity.
71
+ * **Recommended Implementation** (Strategy 2 - Upsert via Source/Key):
72
+ * - Set Activity.source to the issue's canonical URL (e.g., Linear issue URL, Jira issue URL)
73
+ * - Use Note.key for issue details:
74
+ * - key: "description" for issue description (upserts on changes)
75
+ * - key: "metadata" for status, priority, assignee, etc.
76
+ * - key: "comment-{commentId}" for individual comments (unique per comment)
77
+ * - No manual ID tracking needed - Plot handles deduplication automatically
78
+ * - Send NewActivityWithNotes for all issues (creates new or updates existing)
79
+ * - Set activity.unread = false for initial sync, true for incremental updates
71
80
  *
72
- * Tools implementing this should set issue.unread based on sync type:
73
- * - Initial sync (historical data): Set issue.unread = false
74
- * - Incremental updates (webhooks): Set issue.unread = true or leave undefined
81
+ * **Alternative** (Strategy 3 - Advanced cases):
82
+ * - Use Uuid.Generate() and store ID mappings when creating multiple activities per issue
83
+ * - See SYNC_STRATEGIES.md for when this is appropriate
75
84
  *
76
85
  * @param authToken - Authorization token for access
77
86
  * @param projectId - ID of the project to sync
78
- * @param callback - Function receiving (issue, ...extraArgs) for each synced issue.
79
- * The issue.unread field indicates whether this is from initial sync.
87
+ * @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced issue
80
88
  * @param options - Optional configuration for limiting the sync scope (e.g., time range)
81
89
  * @param extraArgs - Additional arguments to pass to the callback (type-checked)
82
90
  * @returns Promise that resolves when sync setup is complete
83
91
  */
84
- startSync<TCallback extends (issue: NewActivityWithNotes, ...args: any[]) => any>(authToken: string, projectId: string, callback: TCallback, options?: ProjectSyncOptions, ...extraArgs: TCallback extends (issue: any, ...rest: infer R) => any ? R : []): Promise<void>;
92
+ startSync<TCallback extends (syncUpdate: SyncUpdate, ...args: any[]) => any>(authToken: string, projectId: string, callback: TCallback, options?: ProjectSyncOptions, ...extraArgs: TCallback extends (syncUpdate: any, ...rest: infer R) => any ? R : []): Promise<void>;
85
93
  /**
86
94
  * Stops synchronizing issues from a specific project.
87
95
  *
@@ -97,10 +105,10 @@ export interface ProjectTool {
97
105
  * sync activity updates back to the external service.
98
106
  *
99
107
  * The update object contains only the fields that changed, plus id and source.
100
- * Uses the combination of start and doneAt to determine workflow state:
101
- * - doneAt set → Completed/Done state
102
- * - doneAt null + start set → In Progress/Active state
103
- * - doneAt null + start null → Backlog/Todo state
108
+ * Uses the combination of start and done to determine workflow state:
109
+ * - done set → Completed/Done state
110
+ * - done null + start set → In Progress/Active state
111
+ * - done null + start null → Backlog/Todo state
104
112
  *
105
113
  * @param authToken - Authorization token for access
106
114
  * @param update - ActivityUpdate with changed fields (includes id and source)
@@ -1 +1 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/common/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAElB;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gFAAgF;IAChF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACtE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEnD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,SAAS,CACP,SAAS,SAAS,CAChB,KAAK,EAAE,oBAAoB,EAC3B,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,EAER,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,GAAG,SAAS,EAAE,SAAS,SAAS,CAC9B,KAAK,EAAE,GAAG,EACV,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,GAAG,GACJ,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvE;;;;;;;;;;OAUG;IACH,eAAe,CAAC,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/common/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EAEd,UAAU,EACX,MAAM,UAAU,CAAC;AAElB;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gFAAgF;IAChF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACtE,QAAQ,EAAE,SAAS,EACnB,GAAG,SAAS,EAAE,SAAS,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAChE,CAAC,GACD,EAAE,GACL,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,SAAS,CACP,SAAS,SAAS,CAChB,UAAU,EAAE,UAAU,EACtB,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,EAER,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,GAAG,SAAS,EAAE,SAAS,SAAS,CAC9B,UAAU,EAAE,GAAG,EACf,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,GAAG,GACJ,CAAC,GACD,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvE;;;;;;;;;;OAUG;IACH,eAAe,CAAC,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
@@ -1 +1 @@
1
- window.hierarchyData = "eJyNkrFuwyAQht/l5guVbTCNt6iTl6pSu1VRRW3aIBNTwVUZIr97hd1WZIKFAb7//w7pruCdowDdq6yOCF5/WD2QcXOA7gqyiueszho66F+cs4AwmXmErqrvEb69hQ4Gq0LQ4Y6cs2yl2InOEV1foAMK4y7GdtsFwnAydvR6jl6OTVNj09YouEAhK2xria2sUPIKpdgfFwTJk0mKBimYY0FomjotvphAIVcd3mjl2IYXSNpUcujzAmXYoc8XCy6S4gdl7bsapoIPDH8o+w8V2G7XYSb96dW2K1mhSWiWRvPatpaJ9lHTxfkpb5w3kP0GCjw333uyjvKSL+uIRTRfL3la/0zO63x/iBhb4QKD2Ke7rELJJlDE2ArnDMvyA843XGE="
1
+ window.hierarchyData = "eJyNkj1PwzAQhv/LzVfTJq2/toqpC0KCDVXIpIZGcWNkH+pQ5b8jJ4DMZC8e7Ofe506+GwTvKYJ+EZsjQrDvznbU+zGCvoHYpHM0FwsaDs/eO0AY+vEEetNIhK/gQEPnTIw23pH3js0UO9MlofMLaKB4WqWy1XKB0J17dwp2TN4ttlxhqxTuZIN8LZHzLYq1RCEkCsWPE4LYZp1UNVLRx4TQcpUHX/tIsRQdX2nm2IJXSFQu2R/KAtOz/aEcvJNNFnxvnHsz3VAxQPeLsr+iso2vZb4OI9mPYJZdKQr7jGZ5aYWW53//YOnqw1A2jgvIfgrKHvFvvEfnqSz5dJ5YQiviRR7/RD7Ycn5MGJvhCoPi+S6bWLMJlDA2wyXDNH0Dl09cpw=="
@@ -1 +1 @@
1
- window.navigationData = "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"
1
+ window.navigationData = "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"