@plotday/twister 0.36.0 → 0.38.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 (243) hide show
  1. package/README.md +4 -2
  2. package/bin/commands/create.js +37 -3
  3. package/bin/commands/create.js.map +1 -1
  4. package/bin/commands/deploy.js +4 -0
  5. package/bin/commands/deploy.js.map +1 -1
  6. package/bin/index.js +1 -0
  7. package/bin/index.js.map +1 -1
  8. package/bin/templates/AGENTS.template.md +101 -189
  9. package/bin/templates/README.template.md +2 -23
  10. package/cli/templates/AGENTS.template.md +101 -189
  11. package/cli/templates/README.template.md +2 -23
  12. package/dist/docs/assets/hierarchy.js +1 -1
  13. package/dist/docs/assets/navigation.js +1 -1
  14. package/dist/docs/assets/search.js +1 -1
  15. package/dist/docs/classes/index.Options.html +1 -1
  16. package/dist/docs/classes/index.Source.html +200 -0
  17. package/dist/docs/classes/tool.ITool.html +1 -1
  18. package/dist/docs/classes/tool.Tool.html +21 -21
  19. package/dist/docs/classes/tools_ai.AI.html +1 -1
  20. package/dist/docs/classes/tools_callbacks.Callbacks.html +2 -2
  21. package/dist/docs/classes/tools_integrations.Integrations.html +45 -16
  22. package/dist/docs/classes/tools_network.Network.html +1 -1
  23. package/dist/docs/classes/tools_plot.Plot.html +93 -60
  24. package/dist/docs/classes/tools_store.Store.html +1 -1
  25. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  26. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  27. package/dist/docs/classes/twist.Twist.html +42 -10
  28. package/dist/docs/documents/Building_Sources.html +137 -0
  29. package/dist/docs/documents/Built-in_Tools.html +11 -2
  30. package/dist/docs/documents/Core_Concepts.html +5 -10
  31. package/dist/docs/documents/Getting_Started.html +1 -1
  32. package/dist/docs/enums/{plot.ActivityLinkType.html → plot.ActionType.html} +10 -8
  33. package/dist/docs/enums/plot.ActorType.html +7 -7
  34. package/dist/docs/enums/plot.ConferencingProvider.html +6 -6
  35. package/dist/docs/enums/plot.ThemeColor.html +9 -9
  36. package/dist/docs/enums/tag.Tag.html +3 -10
  37. package/dist/docs/enums/tools_integrations.AuthProvider.html +11 -11
  38. package/dist/docs/enums/tools_plot.ContactAccess.html +3 -3
  39. package/dist/docs/enums/tools_plot.PriorityAccess.html +3 -3
  40. package/dist/docs/enums/{tools_plot.ActivityAccess.html → tools_plot.ThreadAccess.html} +6 -6
  41. package/dist/docs/hierarchy.html +1 -1
  42. package/dist/docs/index.html +5 -6
  43. package/dist/docs/media/AGENTS.md +910 -0
  44. package/dist/docs/media/MULTI_USER_AUTH.md +111 -0
  45. package/dist/docs/media/SYNC_STRATEGIES.md +7 -7
  46. package/dist/docs/modules/index.html +1 -1
  47. package/dist/docs/modules/plot.html +1 -1
  48. package/dist/docs/modules/tool.html +1 -1
  49. package/dist/docs/modules/tools_integrations.html +1 -1
  50. package/dist/docs/modules/tools_plot.html +1 -1
  51. package/dist/docs/modules.html +1 -1
  52. package/dist/docs/types/index.NewSchedule.html +33 -0
  53. package/dist/docs/types/index.NewScheduleContact.html +5 -0
  54. package/dist/docs/types/index.NewScheduleOccurrence.html +6 -0
  55. package/dist/docs/types/index.Schedule.html +37 -0
  56. package/dist/docs/types/index.ScheduleContact.html +5 -0
  57. package/dist/docs/types/index.ScheduleContactRole.html +1 -0
  58. package/dist/docs/types/index.ScheduleContactStatus.html +1 -0
  59. package/dist/docs/types/index.ScheduleOccurrence.html +17 -0
  60. package/dist/docs/types/index.ScheduleOccurrenceUpdate.html +2 -0
  61. package/dist/docs/types/plot.Action.html +28 -0
  62. package/dist/docs/types/plot.Actor.html +6 -6
  63. package/dist/docs/types/plot.ActorId.html +1 -1
  64. package/dist/docs/types/plot.ContentType.html +1 -1
  65. package/dist/docs/types/plot.Link.html +36 -0
  66. package/dist/docs/types/plot.NewActor.html +1 -1
  67. package/dist/docs/types/plot.NewContact.html +5 -5
  68. package/dist/docs/types/plot.NewLink.html +26 -0
  69. package/dist/docs/types/plot.NewLinkWithNotes.html +7 -0
  70. package/dist/docs/types/plot.NewNote.html +10 -10
  71. package/dist/docs/types/plot.NewPriority.html +1 -1
  72. package/dist/docs/types/plot.NewTags.html +1 -1
  73. package/dist/docs/types/plot.NewThread.html +27 -0
  74. package/dist/docs/types/plot.NewThreadWithNotes.html +1 -0
  75. package/dist/docs/types/plot.Note.html +9 -8
  76. package/dist/docs/types/plot.NoteUpdate.html +2 -2
  77. package/dist/docs/types/plot.PickPriorityConfig.html +8 -10
  78. package/dist/docs/types/plot.Priority.html +6 -6
  79. package/dist/docs/types/plot.PriorityUpdate.html +1 -1
  80. package/dist/docs/types/plot.Tags.html +1 -1
  81. package/dist/docs/types/plot.Thread.html +1 -0
  82. package/dist/docs/types/plot.ThreadCommon.html +17 -0
  83. package/dist/docs/types/plot.ThreadFilter.html +2 -0
  84. package/dist/docs/types/plot.ThreadMeta.html +11 -0
  85. package/dist/docs/types/plot.ThreadUpdate.html +3 -0
  86. package/dist/docs/types/plot.ThreadWithNotes.html +1 -0
  87. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +11 -0
  88. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  89. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  90. package/dist/docs/types/tools_integrations.Channel.html +11 -0
  91. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +17 -0
  92. package/dist/docs/types/tools_plot.LinkFilter.html +10 -0
  93. package/dist/docs/types/tools_plot.LinkSearchResult.html +1 -0
  94. package/dist/docs/types/tools_plot.NoteIntentHandler.html +6 -6
  95. package/dist/docs/types/tools_plot.NoteSearchResult.html +1 -0
  96. package/dist/docs/types/tools_plot.SearchOptions.html +7 -0
  97. package/dist/docs/types/tools_plot.SearchResult.html +1 -0
  98. package/dist/docs/types/tools_twists.TwistPermissions.html +1 -1
  99. package/dist/docs/variables/tools_plot.SEARCH_DEFAULT_LIMIT.html +2 -0
  100. package/dist/docs/variables/tools_plot.SEARCH_MAX_LIMIT.html +2 -0
  101. package/dist/index.d.ts +2 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +2 -0
  104. package/dist/index.js.map +1 -1
  105. package/dist/llm-docs/index.d.ts.map +1 -1
  106. package/dist/llm-docs/index.js +4 -8
  107. package/dist/llm-docs/index.js.map +1 -1
  108. package/dist/llm-docs/plot.d.ts +1 -1
  109. package/dist/llm-docs/plot.d.ts.map +1 -1
  110. package/dist/llm-docs/plot.js +1 -1
  111. package/dist/llm-docs/plot.js.map +1 -1
  112. package/dist/llm-docs/schedule.d.ts +9 -0
  113. package/dist/llm-docs/schedule.d.ts.map +1 -0
  114. package/dist/llm-docs/schedule.js +8 -0
  115. package/dist/llm-docs/schedule.js.map +1 -0
  116. package/dist/llm-docs/source.d.ts +9 -0
  117. package/dist/llm-docs/source.d.ts.map +1 -0
  118. package/dist/llm-docs/source.js +8 -0
  119. package/dist/llm-docs/source.js.map +1 -0
  120. package/dist/llm-docs/tag.d.ts +1 -1
  121. package/dist/llm-docs/tag.d.ts.map +1 -1
  122. package/dist/llm-docs/tag.js +1 -1
  123. package/dist/llm-docs/tag.js.map +1 -1
  124. package/dist/llm-docs/tool.d.ts +1 -1
  125. package/dist/llm-docs/tool.d.ts.map +1 -1
  126. package/dist/llm-docs/tool.js +1 -1
  127. package/dist/llm-docs/tool.js.map +1 -1
  128. package/dist/llm-docs/tools/callbacks.d.ts +1 -1
  129. package/dist/llm-docs/tools/callbacks.d.ts.map +1 -1
  130. package/dist/llm-docs/tools/callbacks.js +1 -1
  131. package/dist/llm-docs/tools/callbacks.js.map +1 -1
  132. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  133. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  134. package/dist/llm-docs/tools/integrations.js +1 -1
  135. package/dist/llm-docs/tools/integrations.js.map +1 -1
  136. package/dist/llm-docs/tools/plot.d.ts +1 -1
  137. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  138. package/dist/llm-docs/tools/plot.js +1 -1
  139. package/dist/llm-docs/tools/plot.js.map +1 -1
  140. package/dist/llm-docs/tools/twists.d.ts +1 -1
  141. package/dist/llm-docs/tools/twists.d.ts.map +1 -1
  142. package/dist/llm-docs/tools/twists.js +1 -1
  143. package/dist/llm-docs/tools/twists.js.map +1 -1
  144. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  145. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  146. package/dist/llm-docs/twist-guide-template.js +1 -1
  147. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  148. package/dist/llm-docs/twist.d.ts +1 -1
  149. package/dist/llm-docs/twist.d.ts.map +1 -1
  150. package/dist/llm-docs/twist.js +1 -1
  151. package/dist/llm-docs/twist.js.map +1 -1
  152. package/dist/plot.d.ts +264 -589
  153. package/dist/plot.d.ts.map +1 -1
  154. package/dist/plot.js +18 -49
  155. package/dist/plot.js.map +1 -1
  156. package/dist/schedule.d.ts +172 -0
  157. package/dist/schedule.d.ts.map +1 -0
  158. package/dist/schedule.js +2 -0
  159. package/dist/schedule.js.map +1 -0
  160. package/dist/source.d.ts +158 -0
  161. package/dist/source.d.ts.map +1 -0
  162. package/dist/source.js +144 -0
  163. package/dist/source.js.map +1 -0
  164. package/dist/tag.d.ts +3 -10
  165. package/dist/tag.d.ts.map +1 -1
  166. package/dist/tag.js +2 -11
  167. package/dist/tag.js.map +1 -1
  168. package/dist/tool.d.ts +1 -15
  169. package/dist/tool.d.ts.map +1 -1
  170. package/dist/tool.js.map +1 -1
  171. package/dist/tools/callbacks.d.ts +1 -1
  172. package/dist/tools/callbacks.js +1 -1
  173. package/dist/tools/integrations.d.ts +119 -52
  174. package/dist/tools/integrations.d.ts.map +1 -1
  175. package/dist/tools/integrations.js +23 -22
  176. package/dist/tools/integrations.js.map +1 -1
  177. package/dist/tools/plot.d.ts +182 -117
  178. package/dist/tools/plot.d.ts.map +1 -1
  179. package/dist/tools/plot.js +23 -21
  180. package/dist/tools/plot.js.map +1 -1
  181. package/dist/tools/twists.d.ts +1 -1
  182. package/dist/twist-guide.d.ts +1 -1
  183. package/dist/twist-guide.d.ts.map +1 -1
  184. package/dist/twist.d.ts +66 -11
  185. package/dist/twist.d.ts.map +1 -1
  186. package/dist/twist.js +79 -10
  187. package/dist/twist.js.map +1 -1
  188. package/package.json +11 -41
  189. package/dist/common/calendar.d.ts +0 -135
  190. package/dist/common/calendar.d.ts.map +0 -1
  191. package/dist/common/calendar.js +0 -2
  192. package/dist/common/calendar.js.map +0 -1
  193. package/dist/common/documents.d.ts +0 -122
  194. package/dist/common/documents.d.ts.map +0 -1
  195. package/dist/common/documents.js +0 -2
  196. package/dist/common/documents.js.map +0 -1
  197. package/dist/common/messaging.d.ts +0 -84
  198. package/dist/common/messaging.d.ts.map +0 -1
  199. package/dist/common/messaging.js +0 -2
  200. package/dist/common/messaging.js.map +0 -1
  201. package/dist/common/projects.d.ts +0 -112
  202. package/dist/common/projects.d.ts.map +0 -1
  203. package/dist/common/projects.js +0 -2
  204. package/dist/common/projects.js.map +0 -1
  205. package/dist/docs/documents/Building_Custom_Tools.html +0 -215
  206. package/dist/docs/enums/plot.ActivityKind.html +0 -14
  207. package/dist/docs/enums/plot.ActivityType.html +0 -10
  208. package/dist/docs/modules/common_calendar.html +0 -1
  209. package/dist/docs/types/common_calendar.Calendar.html +0 -13
  210. package/dist/docs/types/common_calendar.CalendarTool.html +0 -81
  211. package/dist/docs/types/common_calendar.SyncOptions.html +0 -24
  212. package/dist/docs/types/plot.Activity.html +0 -2
  213. package/dist/docs/types/plot.ActivityCommon.html +0 -20
  214. package/dist/docs/types/plot.ActivityFilter.html +0 -3
  215. package/dist/docs/types/plot.ActivityLink.html +0 -26
  216. package/dist/docs/types/plot.ActivityMeta.html +0 -11
  217. package/dist/docs/types/plot.ActivityOccurrence.html +0 -22
  218. package/dist/docs/types/plot.ActivityOccurrenceUpdate.html +0 -3
  219. package/dist/docs/types/plot.ActivityUpdate.html +0 -3
  220. package/dist/docs/types/plot.ActivityWithNotes.html +0 -1
  221. package/dist/docs/types/plot.NewActivity.html +0 -81
  222. package/dist/docs/types/plot.NewActivityOccurrence.html +0 -24
  223. package/dist/docs/types/plot.NewActivityWithNotes.html +0 -1
  224. package/dist/docs/types/tool.SyncToolOptions.html +0 -9
  225. package/dist/docs/types/tools_integrations.IntegrationOptions.html +0 -4
  226. package/dist/docs/types/tools_integrations.IntegrationProviderConfig.html +0 -13
  227. package/dist/docs/types/tools_integrations.Syncable.html +0 -9
  228. package/dist/llm-docs/common/calendar.d.ts +0 -9
  229. package/dist/llm-docs/common/calendar.d.ts.map +0 -1
  230. package/dist/llm-docs/common/calendar.js +0 -8
  231. package/dist/llm-docs/common/calendar.js.map +0 -1
  232. package/dist/llm-docs/common/documents.d.ts +0 -9
  233. package/dist/llm-docs/common/documents.d.ts.map +0 -1
  234. package/dist/llm-docs/common/documents.js +0 -8
  235. package/dist/llm-docs/common/documents.js.map +0 -1
  236. package/dist/llm-docs/common/messaging.d.ts +0 -9
  237. package/dist/llm-docs/common/messaging.d.ts.map +0 -1
  238. package/dist/llm-docs/common/messaging.js +0 -8
  239. package/dist/llm-docs/common/messaging.js.map +0 -1
  240. package/dist/llm-docs/common/projects.d.ts +0 -9
  241. package/dist/llm-docs/common/projects.d.ts.map +0 -1
  242. package/dist/llm-docs/common/projects.js +0 -8
  243. package/dist/llm-docs/common/projects.js.map +0 -1
@@ -19,78 +19,72 @@ Plot Twists are TypeScript classes that extend the `Twist` base class. Twists in
19
19
  - **Store intermediate state**: Use the Store tool to persist state between batches
20
20
  - **Examples**: Syncing large datasets, processing many API calls, or performing batch operations
21
21
 
22
- ## Understanding Activities and Notes
22
+ ## Understanding Threads and Notes
23
23
 
24
- **CRITICAL CONCEPT**: An **Activity** represents something done or to be done (a task, event, or conversation), while **Notes** represent the updates and details on that activity.
24
+ **CRITICAL CONCEPT**: A **Thread** represents something done or to be done (a task, event, or conversation), while **Notes** represent the updates and details on that thread.
25
25
 
26
- **Think of an Activity as a thread** on a messaging platform, and **Notes as the messages in that thread**.
26
+ **Think of a Thread as a thread** on a messaging platform, and **Notes as the messages in that thread**.
27
27
 
28
28
  ### Key Guidelines
29
29
 
30
- 1. **Always create Activities with an initial Note** - The title is just a summary; detailed content goes in Notes
31
- 2. **Add Notes to existing Activities for updates** - Don't create a new Activity for each related message
32
- 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.
33
- 4. **For advanced cases, use generated UUIDs** - Only when you need multiple Plot activities per external item (see SYNC_STRATEGIES.md)
34
- 5. **Most Activities should be `ActivityType.Note`** - Use `Action` only for tasks with `done`, use `Event` only for items with `start`/`end`
30
+ 1. **Always create Threads with an initial Note** - The title is just a summary; detailed content goes in Notes
31
+ 2. **Add Notes to existing Threads for updates** - Don't create a new Thread for each related message
32
+ 3. **Use Thread.source and Note.key for automatic upserts (Recommended)** - Set Thread.source to the external item's URL for deduplication, and use Note.key for upsertable note content. No manual ID tracking needed.
33
+ 4. **For advanced cases, use generated UUIDs** - Only when you need multiple Plot threads per external item (see SYNC_STRATEGIES.md)
34
+ 5. **Most Threads should be `ThreadType.Note`** - Use `Action` only for tasks with `done`, use `Event` only for items with `start`/`end`
35
35
 
36
36
  ### Recommended Decision Tree (Strategy 2: Upsert via Source/Key)
37
37
 
38
38
  ```
39
39
  New event/task/conversation from external system?
40
40
  ├─ Has stable URL or ID?
41
- │ └─ Yes → Set Activity.source to the canonical URL/ID
42
- │ Create Activity (Plot handles deduplication automatically)
41
+ │ └─ Yes → Set Thread.source to the canonical URL/ID
42
+ │ Create Thread (Plot handles deduplication automatically)
43
43
  │ Use Note.key for different note types:
44
44
  │ - "description" for main content
45
45
  │ - "metadata" for status/priority/assignee
46
46
  │ - "comment-{id}" for individual comments
47
47
 
48
- └─ No stable identifier OR need multiple Plot activities per external item?
48
+ └─ No stable identifier OR need multiple Plot threads per external item?
49
49
  └─ Use Advanced Pattern (Strategy 3: Generate and Store IDs)
50
50
  See SYNC_STRATEGIES.md for details
51
51
  ```
52
52
 
53
53
  ### Advanced Decision Tree (Strategy 3: Generate and Store IDs)
54
54
 
55
- Only use when source/key upserts aren't sufficient (e.g., creating multiple activities from one external item):
55
+ Only use when source/key upserts aren't sufficient (e.g., creating multiple threads from one external item):
56
56
 
57
57
  ```
58
58
  New event/task/conversation?
59
59
  ├─ Yes → Generate UUID with Uuid.Generate()
60
- │ Create new Activity with that UUID
61
- │ Store mapping: external_id → activity_uuid
60
+ │ Create new Thread with that UUID
61
+ │ Store mapping: external_id → thread_uuid
62
62
 
63
63
  └─ No (update/reply/comment) → Look up mapping by external_id
64
- ├─ Found → Add Note to existing Activity using stored UUID
65
- └─ Not found → Create new Activity with UUID + store mapping
64
+ ├─ Found → Add Note to existing Thread using stored UUID
65
+ └─ Not found → Create new Thread with UUID + store mapping
66
66
  ```
67
67
 
68
68
  ## Twist Structure Pattern
69
69
 
70
70
  ```typescript
71
71
  import {
72
- type Activity,
73
- type NewActivityWithNotes,
74
- type ActivityFilter,
72
+ type Thread,
73
+ type NewThreadWithNotes,
74
+ type ThreadFilter,
75
75
  type Priority,
76
76
  type ToolBuilder,
77
77
  Twist,
78
- ActivityType,
78
+ ThreadType,
79
79
  } from "@plotday/twister";
80
- import { ActivityAccess, Plot } from "@plotday/twister/tools/plot";
81
- // Import your tools:
82
- // import { GoogleCalendar } from "@plotday/tool-google-calendar";
83
- // import { Linear } from "@plotday/tool-linear";
80
+ import { ThreadAccess, Plot } from "@plotday/twister/tools/plot";
81
+ // Import your sources or tools as needed
84
82
 
85
83
  export default class MyTwist extends Twist<MyTwist> {
86
84
  build(build: ToolBuilder) {
87
85
  return {
88
- // myTool: build(MyTool, {
89
- // onItem: this.handleItem,
90
- // onSyncableDisabled: this.onSyncableDisabled,
91
- // }),
92
86
  plot: build(Plot, {
93
- activity: { access: ActivityAccess.Create },
87
+ thread: { access: ThreadAccess.Create },
94
88
  }),
95
89
  };
96
90
  }
@@ -98,14 +92,6 @@ export default class MyTwist extends Twist<MyTwist> {
98
92
  async activate(_priority: Pick<Priority, "id">) {
99
93
  // Auth and resource selection handled in the twist edit modal.
100
94
  }
101
-
102
- async handleItem(activity: NewActivityWithNotes): Promise<void> {
103
- await this.tools.plot.createActivity(activity);
104
- }
105
-
106
- async onSyncableDisabled(filter: ActivityFilter): Promise<void> {
107
- await this.tools.plot.updateActivity({ match: filter, archived: true });
108
- }
109
95
  }
110
96
  ```
111
97
 
@@ -145,31 +131,6 @@ For complete API documentation of built-in tools including all methods, types, a
145
131
 
146
132
  **Critical**: Never use instance variables for state. They are lost after function execution. Always use Store methods.
147
133
 
148
- ### External Tools (Add to package.json)
149
-
150
- Add tool dependencies to `package.json`:
151
-
152
- ```json
153
- {
154
- "dependencies": {
155
- "@plotday/twister": "workspace:^",
156
- "@plotday/tool-google-calendar": "workspace:^"
157
- }
158
- }
159
- ```
160
-
161
- #### Available External Tools
162
-
163
- - `@plotday/tool-google-calendar`: Google Calendar sync (CalendarTool)
164
- - `@plotday/tool-outlook-calendar`: Outlook Calendar sync (CalendarTool)
165
- - `@plotday/tool-google-contacts`: Google Contacts sync (supporting tool)
166
- - `@plotday/tool-google-drive`: Google Drive sync (DocumentTool)
167
- - `@plotday/tool-gmail`: Gmail sync (MessagingTool)
168
- - `@plotday/tool-slack`: Slack sync (MessagingTool)
169
- - `@plotday/tool-linear`: Linear sync (ProjectTool)
170
- - `@plotday/tool-jira`: Jira sync (ProjectTool)
171
- - `@plotday/tool-asana`: Asana sync (ProjectTool)
172
-
173
134
  ## Lifecycle Methods
174
135
 
175
136
  ### activate(priority: Pick<Priority, "id">)
@@ -185,18 +146,18 @@ async activate(_priority: Pick<Priority, "id">) {
185
146
  }
186
147
  ```
187
148
 
188
- **Store Parent Activity for Later (optional):**
149
+ **Store Parent Thread for Later (optional):**
189
150
 
190
151
  ```typescript
191
152
  async activate(_priority: Pick<Priority, "id">) {
192
- const activityId = await this.tools.plot.createActivity({
193
- type: ActivityType.Note,
153
+ const threadId = await this.tools.plot.createThread({
154
+ type: ThreadType.Note,
194
155
  title: "Setup complete",
195
156
  notes: [{
196
- content: "Your twist is ready. Activities will appear as they sync.",
157
+ content: "Your twist is ready. Threads will appear as they sync.",
197
158
  }],
198
159
  });
199
- await this.set("setup_activity_id", activityId);
160
+ await this.set("setup_thread_id", threadId);
200
161
  }
201
162
  ```
202
163
 
@@ -204,44 +165,22 @@ async activate(_priority: Pick<Priority, "id">) {
204
165
 
205
166
  Twists respond to events through callbacks declared in `build()`:
206
167
 
207
- **Receive synced items from a tool (most common):**
208
-
209
- ```typescript
210
- build(build: ToolBuilder) {
211
- return {
212
- myTool: build(MyTool, {
213
- onItem: this.handleItem,
214
- onSyncableDisabled: this.onSyncableDisabled,
215
- }),
216
- plot: build(Plot, { activity: { access: ActivityAccess.Create } }),
217
- };
218
- }
219
-
220
- async handleItem(activity: NewActivityWithNotes): Promise<void> {
221
- await this.tools.plot.createActivity(activity);
222
- }
223
-
224
- async onSyncableDisabled(filter: ActivityFilter): Promise<void> {
225
- await this.tools.plot.updateActivity({ match: filter, archived: true });
226
- }
227
- ```
228
-
229
- **React to activity changes (for two-way sync):**
168
+ **React to thread changes (for two-way sync):**
230
169
 
231
170
  ```typescript
232
171
  plot: build(Plot, {
233
- activity: {
234
- access: ActivityAccess.Create,
235
- updated: this.onActivityUpdated,
172
+ thread: {
173
+ access: ThreadAccess.Create,
174
+ updated: this.onThreadUpdated,
236
175
  },
237
176
  note: {
238
177
  created: this.onNoteCreated,
239
178
  },
240
179
  }),
241
180
 
242
- async onActivityUpdated(activity: Activity, changes: { tagsAdded, tagsRemoved }): Promise<void> {
243
- const tool = this.getToolForActivity(activity);
244
- if (tool?.updateIssue) await tool.updateIssue(activity);
181
+ async onThreadUpdated(thread: Thread, changes: { tagsAdded, tagsRemoved }): Promise<void> {
182
+ const tool = this.getToolForThread(thread);
183
+ if (tool?.updateIssue) await tool.updateIssue(thread);
245
184
  }
246
185
 
247
186
  async onNoteCreated(note: Note): Promise<void> {
@@ -254,7 +193,7 @@ async onNoteCreated(note: Note): Promise<void> {
254
193
 
255
194
  ```typescript
256
195
  plot: build(Plot, {
257
- activity: { access: ActivityAccess.Respond },
196
+ thread: { access: ThreadAccess.Respond },
258
197
  note: {
259
198
  intents: [{
260
199
  description: "Respond to general questions",
@@ -265,43 +204,43 @@ plot: build(Plot, {
265
204
  }),
266
205
  ```
267
206
 
268
- ## Activity Links
207
+ ## Actions
269
208
 
270
- Activity links enable user interaction:
209
+ Actions enable user interaction:
271
210
 
272
211
  ```typescript
273
- import { type ActivityLink, ActivityLinkType } from "@plotday/twister";
212
+ import { type Action, ActionType } from "@plotday/twister";
274
213
 
275
- // External URL link
276
- const urlLink: ActivityLink = {
214
+ // External URL action
215
+ const urlAction: Action = {
277
216
  title: "Open website",
278
- type: ActivityLinkType.external,
217
+ type: ActionType.external,
279
218
  url: "https://example.com",
280
219
  };
281
220
 
282
- // Callback link (uses Callbacks tool — use linkCallback, not callback)
283
- const token = await this.linkCallback(this.onLinkClicked, "context");
284
- const callbackLink: ActivityLink = {
221
+ // Callback action (uses Callbacks tool — use linkCallback, not callback)
222
+ const token = await this.linkCallback(this.onActionClicked, "context");
223
+ const callbackAction: Action = {
285
224
  title: "Click me",
286
- type: ActivityLinkType.callback,
225
+ type: ActionType.callback,
287
226
  callback: token,
288
227
  };
289
228
 
290
- // Add to activity note
291
- await this.tools.plot.createActivity({
292
- type: ActivityType.Note,
293
- title: "Task with links",
229
+ // Add to thread note
230
+ await this.tools.plot.createThread({
231
+ type: ThreadType.Note,
232
+ title: "Task with actions",
294
233
  notes: [
295
234
  {
296
- content: "Click the links below to take action.",
297
- links: [urlLink, callbackLink],
235
+ content: "Click the actions below to take action.",
236
+ actions: [urlAction, callbackAction],
298
237
  },
299
238
  ],
300
239
  });
301
240
 
302
- // Callback handler receives the ActivityLink as first argument
303
- async onLinkClicked(link: ActivityLink, context: string): Promise<void> {
304
- // Handle link click
241
+ // Callback handler receives the Action as first argument
242
+ async onActionClicked(action: Action, context: string): Promise<void> {
243
+ // Handle action click
305
244
  }
306
245
  ```
307
246
 
@@ -317,9 +256,9 @@ build(build: ToolBuilder) {
317
256
  providers: [{
318
257
  provider: AuthProvider.Google,
319
258
  scopes: ["https://www.googleapis.com/auth/calendar"],
320
- getSyncables: this.getSyncables, // List available resources after auth
321
- onSyncEnabled: this.onSyncEnabled, // User enabled a resource
322
- onSyncDisabled: this.onSyncDisabled, // User disabled a resource
259
+ getChannels: this.getChannels, // List available resources after auth
260
+ onChannelEnabled: this.onChannelEnabled, // User enabled a resource
261
+ onChannelDisabled: this.onChannelDisabled, // User disabled a resource
323
262
  }],
324
263
  }),
325
264
  // ...
@@ -327,7 +266,7 @@ build(build: ToolBuilder) {
327
266
  }
328
267
 
329
268
  // Get a token for API calls:
330
- const token = await this.tools.integrations.get(AuthProvider.Google, syncableId);
269
+ const token = await this.tools.integrations.get(AuthProvider.Google, channelId);
331
270
  if (!token) throw new Error("No auth token available");
332
271
  const client = new ApiClient({ accessToken: token.token });
333
272
  ```
@@ -338,7 +277,7 @@ For per-user write-backs (e.g., RSVP, comments attributed to the acting user):
338
277
  await this.tools.integrations.actAs(
339
278
  AuthProvider.Google,
340
279
  actorId, // The user who performed the action
341
- activityId, // Activity to prompt for auth if needed
280
+ threadId, // Thread to prompt for auth if needed
342
281
  this.performWriteBack,
343
282
  ...extraArgs
344
283
  );
@@ -346,70 +285,43 @@ await this.tools.integrations.actAs(
346
285
 
347
286
  ## Sync Pattern
348
287
 
349
- ### Recommended: Using External Tools with SyncToolOptions
350
-
351
- Most twists use external tools (CalendarTool, ProjectTool, etc.) that handle sync internally. The twist just receives `NewActivityWithNotes` objects and saves them:
352
-
353
- ```typescript
354
- build(build: ToolBuilder) {
355
- return {
356
- calendarTool: build(GoogleCalendar, {
357
- onItem: this.handleEvent, // Receives synced items
358
- onSyncableDisabled: this.onSyncableDisabled, // Clean up when disabled
359
- }),
360
- plot: build(Plot, { activity: { access: ActivityAccess.Create } }),
361
- };
362
- }
363
-
364
- // Tools deliver NewActivityWithNotes — twist saves them
365
- async handleEvent(activity: NewActivityWithNotes): Promise<void> {
366
- await this.tools.plot.createActivity(activity);
367
- }
368
-
369
- async onSyncableDisabled(filter: ActivityFilter): Promise<void> {
370
- await this.tools.plot.updateActivity({ match: filter, archived: true });
371
- }
372
- ```
373
-
374
- ### Custom Sync: Upsert via Source/Key (Strategy 2)
288
+ ### Upsert via Source/Key (Strategy 2)
375
289
 
376
- For direct API integration without an external tool, use source/key for automatic upserts:
290
+ Use source/key for automatic upserts:
377
291
 
378
292
  ```typescript
379
293
  async handleEvent(event: ExternalEvent): Promise<void> {
380
- const activity: NewActivityWithNotes = {
294
+ const thread: NewThreadWithNotes = {
381
295
  source: event.htmlLink, // Canonical URL for automatic deduplication
382
- type: ActivityType.Event,
296
+ type: ThreadType.Event,
383
297
  title: event.summary || "(No title)",
384
- start: event.start?.dateTime || event.start?.date || null,
385
- end: event.end?.dateTime || event.end?.date || null,
386
298
  notes: [],
387
299
  };
388
300
 
389
301
  if (event.description) {
390
- activity.notes.push({
391
- activity: { source: event.htmlLink },
302
+ thread.notes.push({
303
+ thread: { source: event.htmlLink },
392
304
  key: "description", // This key enables note-level upserts
393
305
  content: event.description,
394
306
  });
395
307
  }
396
308
 
397
309
  // Create or update — Plot handles deduplication automatically
398
- await this.tools.plot.createActivity(activity);
310
+ await this.tools.plot.createThread(thread);
399
311
  }
400
312
  ```
401
313
 
402
314
  ### Advanced: Generate and Store IDs (Strategy 3)
403
315
 
404
- 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.
316
+ Only use this pattern when you need to create multiple Plot threads from a single external item, or when the external system doesn't provide stable identifiers. See SYNC_STRATEGIES.md for details.
405
317
 
406
318
  ```typescript
407
319
  async handleEventAdvanced(
408
- incomingActivity: NewActivityWithNotes,
320
+ incomingThread: NewThreadWithNotes,
409
321
  calendarId: string
410
322
  ): Promise<void> {
411
323
  // Extract external event ID from meta (adapt based on your tool's data)
412
- const externalId = incomingActivity.meta?.eventId;
324
+ const externalId = incomingThread.meta?.eventId;
413
325
 
414
326
  if (!externalId) {
415
327
  console.error("Event missing external ID");
@@ -418,38 +330,38 @@ async handleEventAdvanced(
418
330
 
419
331
  // Check if we've already synced this event
420
332
  const mappingKey = `event_mapping:${calendarId}:${externalId}`;
421
- const existingActivityId = await this.get<Uuid>(mappingKey);
333
+ const existingThreadId = await this.get<Uuid>(mappingKey);
422
334
 
423
- if (existingActivityId) {
335
+ if (existingThreadId) {
424
336
  // Event already exists - add update as a Note (add message to thread)
425
- if (incomingActivity.notes?.[0]?.content) {
337
+ if (incomingThread.notes?.[0]?.content) {
426
338
  await this.tools.plot.createNote({
427
- activity: { id: existingActivityId },
428
- content: incomingActivity.notes[0].content,
339
+ thread: { id: existingThreadId },
340
+ content: incomingThread.notes[0].content,
429
341
  });
430
342
  }
431
343
  return;
432
344
  }
433
345
 
434
346
  // New event - generate UUID and store mapping
435
- const activityId = Uuid.Generate();
436
- await this.set(mappingKey, activityId);
347
+ const threadId = Uuid.Generate();
348
+ await this.set(mappingKey, threadId);
437
349
 
438
- // Create new Activity with initial Note (new thread with first message)
439
- await this.tools.plot.createActivity({
440
- ...incomingActivity,
441
- id: activityId,
350
+ // Create new Thread with initial Note (new thread with first message)
351
+ await this.tools.plot.createThread({
352
+ ...incomingThread,
353
+ id: threadId,
442
354
  });
443
355
  }
444
356
  ```
445
357
 
446
358
  ## Resource Selection
447
359
 
448
- Resource selection (calendars, projects, channels) is handled automatically in the twist edit modal via the Integrations tool. Users see a list of available resources returned by your tool's `getSyncables()` method and toggle them on/off. You do **not** need to build custom selection UI.
360
+ Resource selection (calendars, projects, channels) is handled automatically in the twist edit modal via the Integrations tool. Users see a list of available resources returned by your tool's `getChannels()` method and toggle them on/off. You do **not** need to build custom selection UI.
449
361
 
450
362
  ```typescript
451
363
  // In your tool:
452
- async getSyncables(_auth: Authorization, token: AuthToken): Promise<Syncable[]> {
364
+ async getChannels(_auth: Authorization, token: AuthToken): Promise<Channel[]> {
453
365
  const client = new ApiClient({ accessToken: token.token });
454
366
  const calendars = await client.listCalendars();
455
367
  return calendars.map(c => ({
@@ -501,10 +413,10 @@ async syncBatch(resourceId: string): Promise<void> {
501
413
  // Process results using source/key pattern (automatic upserts, no manual tracking)
502
414
  // If each item makes ~10 requests, keep batch size ≤ 100 items to stay under limit
503
415
  for (const item of result.items) {
504
- // Each createActivity may make ~5-10 requests depending on notes/links
505
- await this.tools.plot.createActivity({
416
+ // Each createThread may make ~5-10 requests depending on notes/links
417
+ await this.tools.plot.createThread({
506
418
  source: item.url, // Use item's canonical URL for automatic deduplication
507
- type: ActivityType.Note,
419
+ type: ThreadType.Note,
508
420
  title: item.title,
509
421
  notes: [{
510
422
  activity: { source: item.url },
@@ -533,8 +445,8 @@ async syncBatch(resourceId: string): Promise<void> {
533
445
  await this.clear(`sync_state_${resourceId}`);
534
446
 
535
447
  // Optionally notify user of completion
536
- await this.tools.plot.createActivity({
537
- type: ActivityType.Note,
448
+ await this.tools.plot.createThread({
449
+ type: ThreadType.Note,
538
450
  title: "Sync complete",
539
451
  notes: [
540
452
  {
@@ -546,9 +458,9 @@ async syncBatch(resourceId: string): Promise<void> {
546
458
  }
547
459
  ```
548
460
 
549
- ## Activity Sync Best Practices
461
+ ## Thread Sync Best Practices
550
462
 
551
- When syncing activities from external systems, follow these patterns for optimal user experience:
463
+ When syncing threads from external systems, follow these patterns for optimal user experience:
552
464
 
553
465
  ### The `initialSync` Flag
554
466
 
@@ -561,8 +473,8 @@ All sync-based tools should distinguish between initial sync (first import) and
561
473
 
562
474
  **Example:**
563
475
  ```typescript
564
- const activity: NewActivity = {
565
- type: ActivityType.Event,
476
+ const thread: NewThread = {
477
+ type: ThreadType.Event,
566
478
  source: event.url,
567
479
  title: event.title,
568
480
  ...(initialSync ? { unread: false } : {}), // false for initial, omit for incremental
@@ -577,9 +489,9 @@ const activity: NewActivity = {
577
489
 
578
490
  ### Two-Way Sync: Avoiding Race Conditions
579
491
 
580
- When implementing two-way sync where items created in Plot are pushed to an external system (e.g. Notes becoming comments), a race condition can occur: the external system may send a webhook for the newly created item before you've updated the Activity/Note with the external key. The webhook handler won't find the item by external key and may create a duplicate.
492
+ When implementing two-way sync where items created in Plot are pushed to an external system (e.g. Notes becoming comments), a race condition can occur: the external system may send a webhook for the newly created item before you've updated the Thread/Note with the external key. The webhook handler won't find the item by external key and may create a duplicate.
581
493
 
582
- **Solution:** Embed the Plot `Activity.id` / `Note.id` in the external item's metadata when creating it, and update `Activity.source` / `Note.key` after creation. When processing webhooks, check for the Plot ID in metadata first.
494
+ **Solution:** Embed the Plot `Thread.id` / `Note.id` in the external item's metadata when creating it, and update `Thread.source` / `Note.key` after creation. When processing webhooks, check for the Plot ID in metadata first.
583
495
 
584
496
  ```typescript
585
497
  async pushNoteAsComment(note: Note, externalItemId: string): Promise<void> {
@@ -622,8 +534,8 @@ try {
622
534
  } catch (error) {
623
535
  console.error("Operation failed:", error);
624
536
 
625
- await this.tools.plot.createActivity({
626
- type: ActivityType.Note,
537
+ await this.tools.plot.createThread({
538
+ type: ThreadType.Note,
627
539
  title: "Operation failed",
628
540
  notes: [
629
541
  {
@@ -637,11 +549,11 @@ try {
637
549
  ## Common Pitfalls
638
550
 
639
551
  - **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.
640
- - **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.
641
- - **Always create Activities with Notes** - See "Understanding Activities and Notes" section above for the thread/message pattern and decision tree.
642
- - **Use correct Activity types** - Most should be `ActivityType.Note`. Only use `Action` for tasks with `done`, and `Event` for items with `start`/`end`.
643
- - **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).
644
- - **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.
552
+ - **Processing self-created threads** - Other users may change a Thread created by the twist, resulting in a callback. Be sure to check the `changes === null` and/or `thread.author.id !== this.id` to avoid re-processing.
553
+ - **Always create Threads with Notes** - See "Understanding Threads and Notes" section above for the thread/message pattern and decision tree.
554
+ - **Use correct Thread types** - Most should be `ThreadType.Note`. Only use `Action` for tasks with `done`, and `Event` for items with `start`/`end`.
555
+ - **Use Thread.source and Note.key for automatic upserts (Recommended)** - Set Thread.source to the external item's URL for automatic deduplication. Only use UUID generation and storage for advanced cases (see SYNC_STRATEGIES.md).
556
+ - **Add Notes to existing Threads** - For source/key pattern, reference threads by source. For UUID pattern, look up stored mappings before creating new Threads. Think thread replies, not new threads.
645
557
  - Tools are declared in the `build` method and accessed via `this.tools.toolName` in twist methods.
646
558
  - **Don't forget request limits** - Each execution has ~1000 requests (HTTP requests, tool calls). Break long loops into batches with `this.runTask()` to get fresh request limits. Calculate requests per item to determine safe batch size (e.g., if each item needs ~10 requests, batch size = ~100 items).
647
559
  - **Always use Callbacks tool for persistent references** - Direct function references don't survive worker restarts.
@@ -68,30 +68,9 @@ build(build: ToolBuilder) {
68
68
  - **Callbacks**: Create persistent function references for webhooks
69
69
  - **Network**: HTTP access permissions and webhook management
70
70
 
71
- #### External Tools
71
+ #### Sources
72
72
 
73
- Add external tool dependencies to `package.json`:
74
-
75
- ```json
76
- {
77
- "dependencies": {
78
- "@plotday/twister": "workspace:^",
79
- "@plotday/tool-google-calendar": "workspace:^"
80
- }
81
- }
82
- ```
83
-
84
- Then use them in your twist:
85
-
86
- ```typescript
87
- import GoogleCalendarTool from "@plotday/tool-google-calendar";
88
-
89
- build(build: ToolBuilder) {
90
- return {
91
- googleCalendar: build(GoogleCalendarTool),
92
- };
93
- }
94
- ```
73
+ External service integrations (Google Calendar, Slack, Linear, etc.) are built as Sources. See the [Building Sources](https://twist.plot.day/documents/Building_Sources.html) guide.
95
74
 
96
75
  ### Activity Types
97
76
 
@@ -1 +1 @@
1
- window.hierarchyData = "eJyNkz1vwyAQhv/LzRdq4i/sLerkpa3UblVUUZs2KAQioEqlyP+9wk4rOsFkCT/3PgccV7DGeAf9Ky3YHsGKDyVGL4120F+BFix8ND8J6GF4MUYBwlHqCXq6ZQhfVkEPo+LOCXfnjVFkocjBnwK6/IEevJs2oWyzLiCMB6kmK3QwU4pVV2O9rbEtGLasRFbWyNoGu6bEjlVIadfsZwRKadRQVj8Z7cwIVVfHwRfpvEtFuze/cGTF05J6G0t2Q1rAJdkN6eD23z3dc6Xe+XjM2MD4i5K/ogwbK+Op0F58Wr7OTFIoI5rEpWktK+PTexD+YuwxbdQrSG4FGZ62iTxPyvi05KyMJwFNx3dNfHrP3liRzncBIwucYWBVPMvc5UyCDxhZ4LQhPMdI8XhO3r7Uk/gmNzAlmOcfZBd90w=="
1
+ window.hierarchyData = "eJyVkz1PwzAQhv/LzVdjB6f52CqmLIDUbqhCITE0qhtXtqsiVfnvyHFBhqE2S4bkufc5ny8X0EpZA/ULy3KstghavEvR2UGNBuoLVO4xtgcBNWzOg7GAsB/GHmqWlQgnLaGGTrbGCHNnHUBmjOzsQQL6T1CDNf3C1S38C4RuN8hei9GpaUW3EwLL8sDWbJSSN21KSTJT/5JlJfKywJwVWFCKxbLAknOsGENG6T0ymnFknDHfUhkOIKWjhIYmBF4WfydrYtHmdR6w8RM2cUnOQsmqiQvagayaeHBBaRD80Er51nb7hAN03yj5KUqwLcNjNKMVH7r1GxoVDgFNwtK4tuQ80D4Ke1Z6HzeOHiTXgrinYizwPEt1+x+bJUepLHFoPN4tdZC/tkqLuMA4jMxwiiILR7VpTcouWIeRGU5RVOHKrdVJdzePMYy9+CSeS4jnvy7h6RhdL59/BWOCafoCnurACQ=="
@@ -1 +1 @@
1
- window.navigationData = "eJytnG1z2zYSx7+KR32bnpM0zbl556rJVXeO47GU9kXHo4Ep2MKZBFQCtOze9LvfgOADQCywK0dvjT9/u1w8EMCu/Mf/ZoY/mdmH2b8aseF69mpWbEW5qbmcffhjbOTGCHl/sjSsNnwzezXbMbOdfZhtVNFUXBp92knWneQfW1OVs1ezByE3sw9nP5ydvX999vergThXNT+ZK1nwndEQzwrWvQCj/dyI0nwv5MlKqRLE9Yp1q6DwNvaF5402qspjrXDthDT6/GJxcs3veM1lwcF3v1isBwFGu26kERU/+SgfRa2kJUDMTrb2ZDD5xmN/VpumTI6KQlWVkqcFK7ncsHq0WrnHTp1g3QtCe29h6Op5x0/OS8F00u48Mmied4C5OWz39U//fPPjW+8tl8+y+LIzQkmNIT0pRu2t2yFB9dRqYe5N0C9CbvhTHO/2z6Qoz0um0wGOglE4eWcADMCbt+HQIfTjkpe8ML/wu2l4nJmhGYv0ij+lKV0jxrhsqlteJylDM8b5WamSM5kEje0YyUU5CRqaaRy9LLa8YjlWJ8F411yr8pFvEjPGEScidAbyWrBS/MVuS54aDKMCo31txAam2JbU/PLGAqu43rEiOXBDA+Hsi028gyGfGln0EYS/uZLXzHjxuOuf8E31stDm+3ftinET9Fv3QUkZXLH73JLynWnbu3d689O7H16/8/D/Xn65/I2VDc8y/quVfOxUKdJ5Y7ZXtXoUGw58UzwYa8x2NwqTvMKoepHsMIeymrZTU5TVlld8rkqV98lYWdHJUqyrWqhamOcsaTeKUpxLviehJN8TaD3q624TDLuMb00vzcRePArzbL8GWAe0QuOEGO8/tp3Ce3BCjHch5APZx1LIB8TPuZJutgl5TxrLhfcAbUwPfpN9JvA+c8NIvMoJk7OF3WtsMdH5kY0iJN8jlP6t5u12i/ReRS/FmCQagfO7MNtLZXj+XXvgXpit7NSZ2B0Gl3x/CL+HfymKpp6cYTKuK19O8J2I95wnWYjxhPUutoCufFeieOhXVLsaiPzHdSeKh35VLXo5IUrU2BAi8kmUBvvidtK7XooxD4gtGlE7kPOvq/LP8z2O4HuMogxlxFgK5euIbCdYp8iPBATihkGW00IoH0BVI1++S76fK2lYYTCfikGW+YoaLg3qV+F0iGf2cN3e1yCD3ChV3g66FM3eBFhidAwCiPpZFpaqBm2KughvCwCWME6Re0v09XIjYZEfAiLz7Ge14eVV7R800qTKineBOO1TS0YcqzpNmnLN/2y4zg9MJupBlSPpnZIamS6iHmVp1vJZG1595lqzewyoW201aNPUr5rXNGajeU0hnmsttGHS0LCsl1PYdtTSsHb4Uog0Gi2SlBhilKVqamynJHQvSs5u/mSuWJ0fwla7c6IU5xdmWLe6ZlEbZlgx6JKrVsXuOeqWsCrEr0+ixEF3osQ415xpJe3hC4PVvRIlblhh+OYQsnuCasHOgTkrS7x/lSoLVpYE3jXXTUkYMUqVdSslMD8+8aKxHzLKp8+Sef8A/v07xz+ADPsCOsaSY+u8xWie3X+wsrxlRf6EXYwijJMPVeGpcruO8JI0sd3oRMkZKw2/r5ntjv56gnBIEeNT/R0FelbxLFHGi2eCsFsaxWRqdvQ1Zqtq8VcrRK8efWWOuFIPHKeZTpUi/c5vt0o9ULYweyfF9zGX3OxVnR/ectBgZ73zouCado3Beil2F0lg9qdmlNkdSwjI7mSCEu1ZcNF+HH9lclMi5wp7JBStejuok+9fqnwf75wguU4YVSOLRKdI3+BpZL0ynSJJ2AttCNseY3XozudC5demUuVWodaXK15XQmv8m2XFu0Cc5RJoKANHZGeLqoTmbfoFmyyt8rFXpogfn0zNCtMel6+5aer8AsadvD011708xW5LMRZyUlMBUC3OCGk6YforcMdrnCasjMSifafueI1/odqdyJbncxWtU04UcsIE3g5cE+xfj1VYEWXKXO60NdG1YbnXOB/lMfpGNBkP5bU8jtdO9Wd6ZQd45SQYEM68hIEaBFRYmHYBYFaAlkEECRMPYhsIIU8+37VRX2aabQFex0mowCyKCgFSIQBtUBHiRSNDQqrPUAoEcHqUHeA1wgaVh/udmXYpMTqjM4kVf1ZHsgOCg4WEGohpSgV4fSehAgnxpEUxzIT4b6kID08zKWGUSAggjTLxgrweq2SEFRrYOIES9TgJEuU8QkzXjIHAhIdH8trxMqaPsqn4eOgF9wRAUQuXTdV/OIbm0NoZMDJDnz2IL8AxYWEHgLECHBPXcwCoXpTG5cs4PCQkzHo5zbaF7rnWKeDbq7mGzSJSzAUXuI1PN022VipTCzYyvr0UbGRlK8HCXbSB4mLY9OsAB5UypXy+61VLX00tnE39Au89TVwQ/JKC3smtal/O29IXcdGxreVNZRSDZ+FHDy0DTmVS3cLXGppo8MUPnx+5bPAQ9mwyOO5AfdrmRwGaXjNxhI70s7N+T7T480W+L+xVVX2XqWsFMqRieMa308kmL/TjeyRHmoI5XY4W570gVq/KkYBcFYQaZDlWnK2CUL0qR0pklSBcIM0zsxkrmA08ku0XMGcF9o2nxIhQ1irFHLUYNZ23SrGnT8QWDlzq0gUS41rXWp8K0V1wqopgwp3ocCxYRhBBPRWOTNcRRNypFIeDhQQR11PhSBx3QDSxOJIw00v1uJNbAQYCiwAmLE9DCz4SdRokSN6CnCVP+HPgCSgqLeq2bF7n2nZ876ZPi3SW1+EGwRE2AkBKOdwPjMbmsNkX7NTifLjfN7HFVA/FsRPZTK7j+5pj7IlBk2EQA5OLpP0XbnqhXzsBdnspNnUIOf2kjeSzBxjN7N/T1og/EEtk5pMWAj0FPknSZ8Gt9jirD3i+9ZegyHjqdgGaVTKV33fsrvkIcykqJAinUW/oEjL4gsmTqoXwe623GWrpKxKcbXNscs4tH7UwyR+GzN1hR3ZeEKxMkYIfr+HaNdAeZ5QnCkT8cR5czDlh+v4sVR0SAUNh9p4PKg2JeIGOMgM1XIfhkG3jEcbRpNgjHEjOyDI25YZS7LKBCz8crW08gsuT6pLQZWdkFZtKupyowuhwbesxnJ6YmXjtzKwAawdfxIClM9Ep1bcI7vgPP6AGVTb+8tDZulDojiBdagPwpmLS+gzXy7R/PlYvA53c4lexkXhQNkaU+nTL9Db2sm1b2zaSq9iPxP9sRPHwa2Bp/JW4Z2vQhVbfTy8xnettR6V8bxtJzuPDPKqO8ca4b60XfvP4TlRKuZHpWwyE2JDPVUvF6FiN8eGKqZjs6/CNe1w1FRNHFYmXOAJEROKuH7yjj5GeDCMCmamYN4iOkGaA/7NFakZ9p0N5nG+4+fvm/5RhFFA="
1
+ window.navigationData = "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"