@plotday/twister 0.27.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.
- package/README.md +10 -4
- package/bin/templates/AGENTS.template.md +91 -29
- package/cli/templates/AGENTS.template.md +91 -29
- package/dist/common/calendar.d.ts +18 -21
- package/dist/common/calendar.d.ts.map +1 -1
- package/dist/common/messaging.d.ts +14 -5
- package/dist/common/messaging.d.ts.map +1 -1
- package/dist/common/projects.d.ts +20 -10
- package/dist/common/projects.d.ts.map +1 -1
- package/dist/docs/assets/hierarchy.js +1 -1
- package/dist/docs/assets/search.js +1 -1
- package/dist/docs/classes/tool.Tool.html +20 -15
- package/dist/docs/classes/tools_ai.AI.html +1 -1
- package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
- package/dist/docs/classes/tools_integrations.Integrations.html +1 -1
- package/dist/docs/classes/tools_network.Network.html +1 -1
- package/dist/docs/classes/tools_plot.Plot.html +2 -2
- package/dist/docs/classes/tools_store.Store.html +13 -4
- package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
- package/dist/docs/classes/tools_twists.Twists.html +1 -1
- package/dist/docs/documents/Building_Custom_Tools.html +8 -2
- package/dist/docs/documents/Built-in_Tools.html +19 -8
- package/dist/docs/documents/Core_Concepts.html +14 -6
- package/dist/docs/documents/Getting_Started.html +11 -4
- package/dist/docs/enums/plot.ActorType.html +4 -4
- package/dist/docs/enums/tools_plot.ContactAccess.html +1 -1
- package/dist/docs/hierarchy.html +1 -1
- package/dist/docs/index.html +10 -0
- package/dist/docs/interfaces/common_calendar.CalendarTool.html +19 -11
- package/dist/docs/media/SYNC_STRATEGIES.md +651 -0
- package/dist/docs/types/plot.Activity.html +16 -7
- package/dist/docs/types/plot.ActivityCommon.html +4 -4
- package/dist/docs/types/plot.ActivityUpdate.html +4 -2
- package/dist/docs/types/plot.ActivityWithNotes.html +1 -1
- package/dist/docs/types/plot.Actor.html +5 -5
- package/dist/docs/types/plot.ContentType.html +1 -1
- package/dist/docs/types/plot.NewActivity.html +26 -12
- package/dist/docs/types/plot.NewActivityWithNotes.html +1 -1
- package/dist/docs/types/plot.NewActor.html +1 -1
- package/dist/docs/types/plot.NewContact.html +4 -4
- package/dist/docs/types/plot.NewNote.html +9 -4
- package/dist/docs/types/plot.Note.html +6 -3
- package/dist/docs/types/plot.NoteUpdate.html +4 -3
- package/dist/docs/types/plot.PickPriorityConfig.html +2 -2
- package/dist/docs/types/plot.SyncUpdate.html +1 -1
- package/dist/llm-docs/common/calendar.d.ts +1 -1
- package/dist/llm-docs/common/calendar.d.ts.map +1 -1
- package/dist/llm-docs/common/calendar.js +1 -1
- package/dist/llm-docs/common/calendar.js.map +1 -1
- package/dist/llm-docs/common/messaging.d.ts +1 -1
- package/dist/llm-docs/common/messaging.d.ts.map +1 -1
- package/dist/llm-docs/common/messaging.js +1 -1
- package/dist/llm-docs/common/messaging.js.map +1 -1
- package/dist/llm-docs/common/projects.d.ts +1 -1
- package/dist/llm-docs/common/projects.d.ts.map +1 -1
- package/dist/llm-docs/common/projects.js +1 -1
- package/dist/llm-docs/common/projects.js.map +1 -1
- package/dist/llm-docs/plot.d.ts +1 -1
- package/dist/llm-docs/plot.d.ts.map +1 -1
- package/dist/llm-docs/plot.js +1 -1
- package/dist/llm-docs/plot.js.map +1 -1
- package/dist/llm-docs/tool.d.ts +1 -1
- package/dist/llm-docs/tool.d.ts.map +1 -1
- package/dist/llm-docs/tool.js +1 -1
- package/dist/llm-docs/tool.js.map +1 -1
- package/dist/llm-docs/tools/plot.d.ts +1 -1
- package/dist/llm-docs/tools/plot.d.ts.map +1 -1
- package/dist/llm-docs/tools/plot.js +1 -1
- package/dist/llm-docs/tools/plot.js.map +1 -1
- package/dist/llm-docs/tools/store.d.ts +1 -1
- package/dist/llm-docs/tools/store.d.ts.map +1 -1
- package/dist/llm-docs/tools/store.js +1 -1
- package/dist/llm-docs/tools/store.js.map +1 -1
- package/dist/llm-docs/twist-guide-template.d.ts +1 -1
- package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
- package/dist/llm-docs/twist-guide-template.js +1 -1
- package/dist/llm-docs/twist-guide-template.js.map +1 -1
- package/dist/plot.d.ts +109 -44
- package/dist/plot.d.ts.map +1 -1
- package/dist/plot.js.map +1 -1
- package/dist/tool.d.ts +16 -2
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +16 -2
- package/dist/tool.js.map +1 -1
- package/dist/tools/plot.d.ts +2 -2
- package/dist/tools/plot.d.ts.map +1 -1
- package/dist/tools/plot.js +1 -1
- package/dist/tools/plot.js.map +1 -1
- package/dist/tools/store.d.ts +16 -0
- package/dist/tools/store.d.ts.map +1 -1
- package/dist/tools/store.js.map +1 -1
- package/dist/twist-guide.d.ts +1 -1
- package/dist/twist-guide.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,17 +136,21 @@ Twist tools provide capabilities to twists. They are usually unopinionated and d
|
|
|
136
136
|
|
|
137
137
|
Think of an **Activity as a thread** and **Notes as messages in that thread**. Always create activities with an initial note, and add notes for updates rather than creating new activities.
|
|
138
138
|
|
|
139
|
+
**Data sync:** When syncing from external systems, use `Activity.source` (canonical URL) and `Note.key` for automatic upserts without manual ID tracking. See the [Sync Strategies guide](https://twist.plot.day/documents/Sync_Strategies.html) for detailed patterns.
|
|
140
|
+
|
|
139
141
|
**Action scheduling:** When creating Actions (tasks), omitting the `start` field defaults to "Do Now" (current time). For most integrations, explicitly set `start: null` to create backlog items ("Do Someday"), only using "Do Now" for urgent or in-progress tasks.
|
|
140
142
|
|
|
141
143
|
```typescript
|
|
142
|
-
// Create an activity with
|
|
144
|
+
// Create an activity with source for automatic deduplication
|
|
143
145
|
await this.tools.plot.createActivity({
|
|
146
|
+
source: "https://github.com/org/repo/pull/123", // Enables automatic upserts
|
|
144
147
|
type: ActivityType.Action,
|
|
145
148
|
title: "Review pull request",
|
|
146
149
|
start: null, // "Do Someday" - backlog item (recommended default)
|
|
147
|
-
// Tracked via UUID mapping
|
|
148
150
|
notes: [
|
|
149
151
|
{
|
|
152
|
+
activity: { source: "https://github.com/org/repo/pull/123" },
|
|
153
|
+
key: "description", // Use key for upsertable notes
|
|
150
154
|
content: "New PR ready for review",
|
|
151
155
|
links: [
|
|
152
156
|
{
|
|
@@ -159,9 +163,10 @@ await this.tools.plot.createActivity({
|
|
|
159
163
|
],
|
|
160
164
|
});
|
|
161
165
|
|
|
162
|
-
// Add a note
|
|
166
|
+
// Add or update a note using key (upserts if key exists)
|
|
163
167
|
await this.tools.plot.createNote({
|
|
164
|
-
activity: {
|
|
168
|
+
activity: { source: "https://github.com/org/repo/pull/123" },
|
|
169
|
+
key: "approval", // Using key enables upserts
|
|
165
170
|
content: "LGTM! Approved ✅",
|
|
166
171
|
});
|
|
167
172
|
```
|
|
@@ -199,6 +204,7 @@ plot priority create # Create new priority
|
|
|
199
204
|
|
|
200
205
|
- [Getting Started](https://twist.plot.day/documents/Getting_Started.html) - Complete walkthrough
|
|
201
206
|
- [Core Concepts](https://twist.plot.day/documents/Core_Concepts.html) - Twists, tools, and architecture
|
|
207
|
+
- [Sync Strategies](https://twist.plot.day/documents/Sync_Strategies.html) - Data synchronization patterns (upserts, deduplication, ID management)
|
|
202
208
|
- [Built-in Tools](https://twist.plot.day/documents/Built-in_Tools.html) - Plot, Store, AI, and more
|
|
203
209
|
- [Building Custom Tools](https://twist.plot.day/documents/Building_Custom_Tools.html) - Create reusable twist tools
|
|
204
210
|
- [Runtime Environment](https://twist.plot.day/documents/Runtime_Environment.html) - Execution constraints and optimization
|
|
@@ -27,10 +27,30 @@ 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. **
|
|
31
|
-
4. **
|
|
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?
|
|
@@ -269,7 +289,9 @@ async onAuthComplete(authResult: { authToken: string }, provider: string) {
|
|
|
269
289
|
|
|
270
290
|
## Sync Pattern
|
|
271
291
|
|
|
272
|
-
|
|
292
|
+
### Recommended: Upsert via Source/Key (Strategy 2)
|
|
293
|
+
|
|
294
|
+
Pattern for syncing external data using automatic upserts - **no manual ID tracking needed**:
|
|
273
295
|
|
|
274
296
|
```typescript
|
|
275
297
|
async startSync(calendarId: string): Promise<void> {
|
|
@@ -284,6 +306,57 @@ async startSync(calendarId: string): Promise<void> {
|
|
|
284
306
|
}
|
|
285
307
|
|
|
286
308
|
async handleEvent(
|
|
309
|
+
event: ExternalEvent,
|
|
310
|
+
calendarId: string
|
|
311
|
+
): Promise<void> {
|
|
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
|
+
};
|
|
321
|
+
|
|
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
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
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);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async stopSync(calendarId: string): Promise<void> {
|
|
349
|
+
const authToken = await this.get<string>("auth_token");
|
|
350
|
+
await this.tools.calendarTool.stopSync(authToken, calendarId);
|
|
351
|
+
}
|
|
352
|
+
```
|
|
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(
|
|
287
360
|
incomingActivity: NewActivityWithNotes,
|
|
288
361
|
calendarId: string
|
|
289
362
|
): Promise<void> {
|
|
@@ -320,11 +393,6 @@ async handleEvent(
|
|
|
320
393
|
id: activityId,
|
|
321
394
|
});
|
|
322
395
|
}
|
|
323
|
-
|
|
324
|
-
async stopSync(calendarId: string): Promise<void> {
|
|
325
|
-
const authToken = await this.get<string>("auth_token");
|
|
326
|
-
await this.tools.calendarTool.stopSync(authToken, calendarId);
|
|
327
|
-
}
|
|
328
396
|
```
|
|
329
397
|
|
|
330
398
|
## Calendar Selection Pattern
|
|
@@ -419,24 +487,18 @@ async syncBatch(args: any, resourceId: string): Promise<void> {
|
|
|
419
487
|
// Process one batch (keep under time limit)
|
|
420
488
|
const result = await this.fetchBatch(state.nextPageToken);
|
|
421
489
|
|
|
422
|
-
// Process results (
|
|
490
|
+
// Process results using source/key pattern (automatic upserts, no manual tracking)
|
|
423
491
|
for (const item of result.items) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
id: activityId,
|
|
435
|
-
type: ActivityType.Note,
|
|
436
|
-
title: item.title,
|
|
437
|
-
notes: [{ id: Uuid.Generate(), content: item.description }],
|
|
438
|
-
});
|
|
439
|
-
}
|
|
492
|
+
await this.tools.plot.createActivity({
|
|
493
|
+
source: item.url, // Use item's canonical URL for automatic deduplication
|
|
494
|
+
type: ActivityType.Note,
|
|
495
|
+
title: item.title,
|
|
496
|
+
notes: [{
|
|
497
|
+
activity: { source: item.url },
|
|
498
|
+
key: "description", // Use key for upsertable notes
|
|
499
|
+
content: item.description,
|
|
500
|
+
}],
|
|
501
|
+
});
|
|
440
502
|
}
|
|
441
503
|
|
|
442
504
|
if (result.nextPageToken) {
|
|
@@ -495,9 +557,9 @@ try {
|
|
|
495
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.
|
|
496
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.
|
|
497
559
|
- **Always create Activities with Notes** - See "Understanding Activities and Notes" section above for the thread/message pattern and decision tree.
|
|
498
|
-
- **Use correct Activity types** - Most should be `ActivityType.Note`. Only use `Action` for tasks with `
|
|
499
|
-
- **
|
|
500
|
-
- **Add Notes to existing Activities** -
|
|
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.
|
|
501
563
|
- Tools are declared in the `build` method and accessed via `this.tools.toolName` in twist methods.
|
|
502
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.
|
|
503
565
|
- **Always use Callbacks tool for persistent references** - Direct function references don't survive worker restarts.
|
|
@@ -27,10 +27,30 @@ 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. **
|
|
31
|
-
4. **
|
|
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?
|
|
@@ -269,7 +289,9 @@ async onAuthComplete(authResult: { authToken: string }, provider: string) {
|
|
|
269
289
|
|
|
270
290
|
## Sync Pattern
|
|
271
291
|
|
|
272
|
-
|
|
292
|
+
### Recommended: Upsert via Source/Key (Strategy 2)
|
|
293
|
+
|
|
294
|
+
Pattern for syncing external data using automatic upserts - **no manual ID tracking needed**:
|
|
273
295
|
|
|
274
296
|
```typescript
|
|
275
297
|
async startSync(calendarId: string): Promise<void> {
|
|
@@ -284,6 +306,57 @@ async startSync(calendarId: string): Promise<void> {
|
|
|
284
306
|
}
|
|
285
307
|
|
|
286
308
|
async handleEvent(
|
|
309
|
+
event: ExternalEvent,
|
|
310
|
+
calendarId: string
|
|
311
|
+
): Promise<void> {
|
|
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
|
+
};
|
|
321
|
+
|
|
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
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
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);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async stopSync(calendarId: string): Promise<void> {
|
|
349
|
+
const authToken = await this.get<string>("auth_token");
|
|
350
|
+
await this.tools.calendarTool.stopSync(authToken, calendarId);
|
|
351
|
+
}
|
|
352
|
+
```
|
|
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(
|
|
287
360
|
incomingActivity: NewActivityWithNotes,
|
|
288
361
|
calendarId: string
|
|
289
362
|
): Promise<void> {
|
|
@@ -320,11 +393,6 @@ async handleEvent(
|
|
|
320
393
|
id: activityId,
|
|
321
394
|
});
|
|
322
395
|
}
|
|
323
|
-
|
|
324
|
-
async stopSync(calendarId: string): Promise<void> {
|
|
325
|
-
const authToken = await this.get<string>("auth_token");
|
|
326
|
-
await this.tools.calendarTool.stopSync(authToken, calendarId);
|
|
327
|
-
}
|
|
328
396
|
```
|
|
329
397
|
|
|
330
398
|
## Calendar Selection Pattern
|
|
@@ -419,24 +487,18 @@ async syncBatch(args: any, resourceId: string): Promise<void> {
|
|
|
419
487
|
// Process one batch (keep under time limit)
|
|
420
488
|
const result = await this.fetchBatch(state.nextPageToken);
|
|
421
489
|
|
|
422
|
-
// Process results (
|
|
490
|
+
// Process results using source/key pattern (automatic upserts, no manual tracking)
|
|
423
491
|
for (const item of result.items) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
id: activityId,
|
|
435
|
-
type: ActivityType.Note,
|
|
436
|
-
title: item.title,
|
|
437
|
-
notes: [{ id: Uuid.Generate(), content: item.description }],
|
|
438
|
-
});
|
|
439
|
-
}
|
|
492
|
+
await this.tools.plot.createActivity({
|
|
493
|
+
source: item.url, // Use item's canonical URL for automatic deduplication
|
|
494
|
+
type: ActivityType.Note,
|
|
495
|
+
title: item.title,
|
|
496
|
+
notes: [{
|
|
497
|
+
activity: { source: item.url },
|
|
498
|
+
key: "description", // Use key for upsertable notes
|
|
499
|
+
content: item.description,
|
|
500
|
+
}],
|
|
501
|
+
});
|
|
440
502
|
}
|
|
441
503
|
|
|
442
504
|
if (result.nextPageToken) {
|
|
@@ -495,9 +557,9 @@ try {
|
|
|
495
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.
|
|
496
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.
|
|
497
559
|
- **Always create Activities with Notes** - See "Understanding Activities and Notes" section above for the thread/message pattern and decision tree.
|
|
498
|
-
- **Use correct Activity types** - Most should be `ActivityType.Note`. Only use `Action` for tasks with `
|
|
499
|
-
- **
|
|
500
|
-
- **Add Notes to existing Activities** -
|
|
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.
|
|
501
563
|
- Tools are declared in the `build` method and accessed via `this.tools.toolName` in twist methods.
|
|
502
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.
|
|
503
565
|
- **Always use Callbacks tool for persistent references** - Direct function references don't survive worker restarts.
|
|
@@ -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
|
*
|
|
@@ -89,21 +93,10 @@ export interface SyncOptions {
|
|
|
89
93
|
* syncUpdate: SyncUpdate,
|
|
90
94
|
* syncMeta: { initialSync: boolean }
|
|
91
95
|
* ) {
|
|
92
|
-
* // Step 4: Process synced events
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* await this.plot.updateActivity(syncUpdate.update);
|
|
97
|
-
* }
|
|
98
|
-
* if (syncUpdate.notes) {
|
|
99
|
-
* for (const note of syncUpdate.notes) {
|
|
100
|
-
* await this.plot.createNote(note);
|
|
101
|
-
* }
|
|
102
|
-
* }
|
|
103
|
-
* } else {
|
|
104
|
-
* // Create new activity
|
|
105
|
-
* await this.plot.createActivity(syncUpdate);
|
|
106
|
-
* }
|
|
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);
|
|
107
100
|
* }
|
|
108
101
|
* }
|
|
109
102
|
* ```
|
|
@@ -136,13 +129,17 @@ export interface CalendarTool {
|
|
|
136
129
|
* event import and ongoing change notifications. The callback function
|
|
137
130
|
* will be invoked for each synced event.
|
|
138
131
|
*
|
|
139
|
-
*
|
|
140
|
-
* -
|
|
141
|
-
* -
|
|
142
|
-
* -
|
|
143
|
-
* - Send
|
|
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)
|
|
144
137
|
* - Set activity.unread = false for initial sync, true for incremental updates
|
|
145
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
|
|
142
|
+
*
|
|
146
143
|
* @param authToken - Authorization token for calendar access
|
|
147
144
|
* @param calendarId - ID of the calendar to sync
|
|
148
145
|
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced event
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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"}
|
|
@@ -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
|
/**
|
|
@@ -64,13 +68,18 @@ export interface MessagingTool {
|
|
|
64
68
|
* Email threads and chat conversations are converted to SyncUpdate objects,
|
|
65
69
|
* which can be either new items or updates to existing items.
|
|
66
70
|
*
|
|
67
|
-
*
|
|
68
|
-
* -
|
|
69
|
-
* -
|
|
70
|
-
* -
|
|
71
|
-
* -
|
|
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)
|
|
72
77
|
* - Set activity.unread = false for initial sync, true for incremental updates
|
|
73
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
|
|
82
|
+
*
|
|
74
83
|
* @param authToken - Authorization token for access
|
|
75
84
|
* @param channelId - ID of the channel (e.g., channel, inbox) to sync
|
|
76
85
|
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced conversation
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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"}
|
|
@@ -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
|
/**
|
|
@@ -64,14 +68,20 @@ export interface ProjectTool {
|
|
|
64
68
|
* Issues and tasks are converted to SyncUpdate objects, which can be either
|
|
65
69
|
* new items or updates to existing items.
|
|
66
70
|
*
|
|
67
|
-
*
|
|
68
|
-
* -
|
|
69
|
-
* -
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
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)
|
|
73
79
|
* - Set activity.unread = false for initial sync, true for incremental updates
|
|
74
80
|
*
|
|
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
|
|
84
|
+
*
|
|
75
85
|
* @param authToken - Authorization token for access
|
|
76
86
|
* @param projectId - ID of the project to sync
|
|
77
87
|
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced issue
|
|
@@ -95,10 +105,10 @@ export interface ProjectTool {
|
|
|
95
105
|
* sync activity updates back to the external service.
|
|
96
106
|
*
|
|
97
107
|
* The update object contains only the fields that changed, plus id and source.
|
|
98
|
-
* Uses the combination of start and
|
|
99
|
-
* -
|
|
100
|
-
* -
|
|
101
|
-
* -
|
|
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
|
|
102
112
|
*
|
|
103
113
|
* @param authToken - Authorization token for access
|
|
104
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,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
|
|
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 = "
|
|
1
|
+
window.hierarchyData = "eJyNkj1PwzAQhv/LzVfTJq2/toqpC0KCDVXIpIZGcWNkH+pQ5b8jJ4DMZC8e7Ofe506+GwTvKYJ+EZsjQrDvznbU+zGCvoHYpHM0FwsaDs/eO0AY+vEEetNIhK/gQEPnTIw23pH3js0UO9MlofMLaKB4WqWy1XKB0J17dwp2TN4ttlxhqxTuZIN8LZHzLYq1RCEkCsWPE4LYZp1UNVLRx4TQcpUHX/tIsRQdX2nm2IJXSFQu2R/KAtOz/aEcvJNNFnxvnHsz3VAxQPeLsr+iso2vZb4OI9mPYJZdKQr7jGZ5aYWW53//YOnqw1A2jgvIfgrKHvFvvEfnqSz5dJ5YQiviRR7/RD7Ycn5MGJvhCoPi+S6bWLMJlDA2wyXDNH0Dl09cpw=="
|