@plotday/twister 0.55.0 → 0.57.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 (85) hide show
  1. package/dist/connector.d.ts +6 -2
  2. package/dist/connector.d.ts.map +1 -1
  3. package/dist/connector.js.map +1 -1
  4. package/dist/docs/assets/hierarchy.js +1 -1
  5. package/dist/docs/assets/navigation.js +1 -1
  6. package/dist/docs/assets/search.js +1 -1
  7. package/dist/docs/classes/index.Connector.html +25 -25
  8. package/dist/docs/classes/index.FileNotFoundError.html +1 -1
  9. package/dist/docs/classes/index.Files.html +1 -1
  10. package/dist/docs/classes/index.Imap.html +1 -1
  11. package/dist/docs/classes/index.Options.html +1 -1
  12. package/dist/docs/classes/index.Smtp.html +1 -1
  13. package/dist/docs/classes/tools_ai.AI.html +1 -1
  14. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  15. package/dist/docs/classes/tools_integrations.Integrations.html +30 -11
  16. package/dist/docs/classes/tools_network.Network.html +25 -16
  17. package/dist/docs/classes/tools_plot.Plot.html +1 -1
  18. package/dist/docs/classes/tools_store.Store.html +1 -1
  19. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  20. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  21. package/dist/docs/enums/plot.ActorType.html +4 -4
  22. package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
  23. package/dist/docs/hierarchy.html +1 -1
  24. package/dist/docs/modules/index.html +1 -1
  25. package/dist/docs/modules/tools_integrations.html +1 -1
  26. package/dist/docs/types/index.CreateLinkDraft.html +10 -8
  27. package/dist/docs/types/index.OptionalScopeGroup.html +6 -6
  28. package/dist/docs/types/index.ScopeConfig.html +3 -3
  29. package/dist/docs/types/plot.Actor.html +5 -5
  30. package/dist/docs/types/plot.Contact.html +4 -4
  31. package/dist/docs/types/plot.ContentType.html +1 -1
  32. package/dist/docs/types/plot.Link.html +20 -16
  33. package/dist/docs/types/plot.LinkUpdate.html +1 -1
  34. package/dist/docs/types/plot.NewActor.html +1 -1
  35. package/dist/docs/types/plot.NewContact.html +1 -1
  36. package/dist/docs/types/plot.NewLink.html +18 -2
  37. package/dist/docs/types/plot.NewLinkWithNotes.html +13 -2
  38. package/dist/docs/types/plot.NewNote.html +7 -1
  39. package/dist/docs/types/plot.NoteUpdate.html +1 -1
  40. package/dist/docs/types/plot.PlanOperation.html +1 -1
  41. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  42. package/dist/docs/types/tools_integrations.ArchiveNotesFilter.html +5 -0
  43. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  44. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  45. package/dist/docs/types/tools_integrations.Channel.html +6 -6
  46. package/dist/docs/types/tools_integrations.ComposeConfig.html +7 -5
  47. package/dist/docs/types/tools_integrations.ContactRoleConfig.html +5 -5
  48. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +25 -21
  49. package/dist/docs/types/tools_integrations.NewCustomEmoji.html +18 -0
  50. package/dist/docs/types/tools_integrations.StatusIcon.html +4 -0
  51. package/dist/docs/types/tools_integrations.SyncContext.html +15 -3
  52. package/dist/llm-docs/connector.d.ts +1 -1
  53. package/dist/llm-docs/connector.d.ts.map +1 -1
  54. package/dist/llm-docs/connector.js +1 -1
  55. package/dist/llm-docs/connector.js.map +1 -1
  56. package/dist/llm-docs/plot.d.ts +1 -1
  57. package/dist/llm-docs/plot.d.ts.map +1 -1
  58. package/dist/llm-docs/plot.js +1 -1
  59. package/dist/llm-docs/plot.js.map +1 -1
  60. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  61. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  62. package/dist/llm-docs/tools/integrations.js +1 -1
  63. package/dist/llm-docs/tools/integrations.js.map +1 -1
  64. package/dist/llm-docs/tools/network.d.ts +1 -1
  65. package/dist/llm-docs/tools/network.d.ts.map +1 -1
  66. package/dist/llm-docs/tools/network.js +1 -1
  67. package/dist/llm-docs/tools/network.js.map +1 -1
  68. package/dist/plot.d.ts +58 -0
  69. package/dist/plot.d.ts.map +1 -1
  70. package/dist/plot.js.map +1 -1
  71. package/dist/tools/integrations.d.ts +88 -2
  72. package/dist/tools/integrations.d.ts.map +1 -1
  73. package/dist/tools/integrations.js.map +1 -1
  74. package/dist/tools/network.d.ts +27 -15
  75. package/dist/tools/network.d.ts.map +1 -1
  76. package/dist/tools/network.js.map +1 -1
  77. package/package.json +1 -1
  78. package/src/connector.ts +6 -2
  79. package/src/llm-docs/connector.ts +1 -1
  80. package/src/llm-docs/plot.ts +1 -1
  81. package/src/llm-docs/tools/integrations.ts +1 -1
  82. package/src/llm-docs/tools/network.ts +1 -1
  83. package/src/plot.ts +59 -0
  84. package/src/tools/integrations.ts +106 -1
  85. package/src/tools/network.ts +27 -15
package/src/plot.ts CHANGED
@@ -788,6 +788,16 @@ export type NewNote = Partial<
788
788
  * - `undefined` (omitted): not a reply
789
789
  */
790
790
  reNote?: { id: Uuid } | { key: string } | null;
791
+
792
+ /**
793
+ * A link carried by this note (note-attached, NOT a thread-level canonical
794
+ * link). Use for augmenter content (e.g. Granola meeting notes) that should
795
+ * attach to an existing canonical thread without becoming its primary link.
796
+ * The runtime creates the link note-scoped, binds `note.link_id` to it, and
797
+ * — when `thread: { source }` resolves to no existing thread — find-or-creates
798
+ * the thread by that source so a later canonical sync can fill the primary.
799
+ */
800
+ link?: NewLink;
791
801
  };
792
802
 
793
803
  /**
@@ -1025,6 +1035,12 @@ export type Link = {
1025
1035
  * meeting-notes connector can bundle by setting the same alias.
1026
1036
  */
1027
1037
  sources: string[];
1038
+ /**
1039
+ * Connector-supplied ranking used by clients to choose the single displayed
1040
+ * (primary) canonical link when a thread has more than one. Higher wins;
1041
+ * ties break on earliest creation. Default 0.
1042
+ */
1043
+ priority: number;
1028
1044
  };
1029
1045
 
1030
1046
  /**
@@ -1082,12 +1098,36 @@ export type NewLink = Partial<
1082
1098
  * - undefined (default): Preserve current archive state
1083
1099
  */
1084
1100
  archived?: boolean;
1101
+ /**
1102
+ * Mark the thread as the connection owner's to-do at create time.
1103
+ * - true: the thread is added to the owner's to-do (active) bucket and
1104
+ * their per-user archive is lifted, atomically with the save — no
1105
+ * separate `integrations.setThreadToDo()` round-trip needed.
1106
+ * - false: the owner's thread_state is marked read (cleared from to-do).
1107
+ * - undefined (omitted, default): leave to-do state untouched.
1108
+ *
1109
+ * Use for messaging-style "saved for later" flags (e.g. a starred Slack
1110
+ * thread). This is the first-class replacement for overloading a
1111
+ * `statuses[]` entry with `active: true`.
1112
+ */
1113
+ todo?: boolean;
1114
+ /**
1115
+ * The to-do date used when `todo` is true. Defaults to the "Now"
1116
+ * sentinel (today's bucket) when omitted. Ignored when `todo` is not true.
1117
+ */
1118
+ todoDate?: Date | string;
1085
1119
  /**
1086
1120
  * Explicit focus (disables automatic focus matching).
1087
1121
  * Only used when the link creates a new thread. When omitted, the
1088
1122
  * server classifies the thread using the user's focus rules.
1089
1123
  */
1090
1124
  focus?: Pick<Focus, "id">;
1125
+ /**
1126
+ * Primary-link ranking for this canonical link (default 0). Set higher on
1127
+ * the connection that "owns" the external item (e.g. the calendar that owns
1128
+ * an event vs a subscribed copy) so clients display it as the primary.
1129
+ */
1130
+ priority?: number;
1091
1131
  };
1092
1132
 
1093
1133
  /**
@@ -1109,6 +1149,25 @@ export type NewLinkWithNotes = NewLink & {
1109
1149
  schedules?: Array<Omit<NewSchedule, "threadId">>;
1110
1150
  /** Schedule occurrence overrides */
1111
1151
  scheduleOccurrences?: NewScheduleOccurrence[];
1152
+ /**
1153
+ * For `onCreateLink` only: binds the thread's opening note (the message the
1154
+ * user composed in Plot, which this hook just posted to the external system)
1155
+ * to its external counterpart. Mirrors the `NoteWriteBackResult` a reply
1156
+ * returns from `onNoteCreated` — `key` is the external message id and
1157
+ * `externalContent` is the post-write content baseline. Without this the
1158
+ * opening note stays keyless, so reactions and edits on it can't be routed
1159
+ * back to the external system. Ignored outside `onCreateLink`.
1160
+ */
1161
+ originatingNote?: {
1162
+ /** External message id; set as the opening note's `key`. */
1163
+ key?: string;
1164
+ /**
1165
+ * Content as the external system stored it post-write, for the sync
1166
+ * baseline. Must equal what your sync-in path emits as this note's
1167
+ * `content` on re-ingest (same contract as `NoteWriteBackResult.externalContent`).
1168
+ */
1169
+ externalContent?: string;
1170
+ };
1112
1171
  };
1113
1172
 
1114
1173
  /**
@@ -3,6 +3,7 @@ import {
3
3
  type ActorId,
4
4
  type NewContact,
5
5
  type NewLinkWithNotes,
6
+ type NewNote,
6
7
  ITool,
7
8
  } from "..";
8
9
  import type { JSONValue } from "../utils/types";
@@ -43,6 +44,21 @@ export type Channel = {
43
44
  linkTypes?: LinkTypeConfig[];
44
45
  };
45
46
 
47
+ /**
48
+ * Curated status-icon vocabulary. Connectors map each declared status to the
49
+ * closest icon; clients render a single glyph per value. Required on every
50
+ * status so the UI always has something to show.
51
+ */
52
+ export type StatusIcon =
53
+ | "backlog"
54
+ | "todo"
55
+ | "inProgress"
56
+ | "blocked"
57
+ | "done"
58
+ | "cancelled"
59
+ | "confirmed"
60
+ | "tentative";
61
+
46
62
  /**
47
63
  * Describes a link type that a connector creates.
48
64
  * Used for display in the UI (icons, labels).
@@ -93,6 +109,14 @@ export type LinkTypeConfig = {
93
109
  status: string;
94
110
  /** Human-readable label (e.g., "Open", "Done") */
95
111
  label: string;
112
+ /** Curated icon for this status (required so the UI always has a glyph). */
113
+ icon: StatusIcon;
114
+ /**
115
+ * Suppress this status's icon on the feed row (ThreadWidget) while still
116
+ * showing it in the ThreadPage header. Use for a "resting" default state
117
+ * that would otherwise clutter the feed (e.g. calendar "Confirmed").
118
+ */
119
+ hiddenDefault?: boolean;
96
120
  /** Whether this status represents completion (done, closed, merged, cancelled, etc.) */
97
121
  done?: boolean;
98
122
  /**
@@ -227,8 +251,11 @@ export type ComposeConfig = {
227
251
  * `onCreateLink` resolves itself (e.g. Linear's `"unstarted"` category is
228
252
  * resolved per-team to a state UUID inside the connector — see
229
253
  * `connectors/linear/src/linear.ts`).
254
+ *
255
+ * Omit for status-less link types (e.g. messaging connectors that don't
256
+ * model a status): composed links are created with no status.
230
257
  */
231
- status: string;
258
+ status?: string;
232
259
  /**
233
260
  * Optional override for the picker chip / "Create new …" copy. Defaults
234
261
  * to the parent linkType's `label`. Use to disambiguate compose entries
@@ -297,6 +324,22 @@ export type SyncContext = {
297
324
  * overwrites stored state rather than appending to it.
298
325
  */
299
326
  recovering?: boolean;
327
+
328
+ /**
329
+ * True when the channel is being observed because the user composed a Plot
330
+ * thread INTO it (via `onCreateLink`), not because they explicitly enabled
331
+ * it. The connector should register webhooks / mark the channel observed so
332
+ * inbound events (replies, reactions) on the composed thread sync back —
333
+ * but must NOT backfill history. Only go-forward events matter; pulling the
334
+ * channel's existing content would be surprising for a channel the user
335
+ * only posted one thread into.
336
+ *
337
+ * Connectors whose `onChannelEnabled` already skips historical backfill can
338
+ * ignore this flag. Connectors that initial-sync on enable MUST short-
339
+ * circuit that backfill when `observeOnly` is true (still set up webhooks
340
+ * and any go-forward state).
341
+ */
342
+ observeOnly?: boolean;
300
343
  };
301
344
 
302
345
  /**
@@ -410,6 +453,28 @@ export abstract class Integrations extends ITool {
410
453
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
411
454
  abstract saveLinks(links: NewLinkWithNotes[]): Promise<(Uuid | null)[]>;
412
455
 
456
+ /**
457
+ * Save one or more notes. Unlike saveLink (which creates a thread-level
458
+ * canonical link), these notes attach to an EXISTING thread — addressed by
459
+ * `note.thread: { id }` or `{ source }` — and may carry their own
460
+ * note-attached link via `note.link` (a note-scoped link, NOT a thread-level
461
+ * canonical link). When `{ source }` resolves to no thread yet, the runtime
462
+ * find-or-creates the thread by that source. Use for augmenter content
463
+ * (e.g. meeting notes attached to a calendar event).
464
+ */
465
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
466
+ abstract saveNotes(notes: NewNote[]): Promise<(Uuid | null)[]>;
467
+ /** Save a single note. See {@link saveNotes}. */
468
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
469
+ abstract saveNote(note: NewNote): Promise<Uuid | null>;
470
+ /**
471
+ * Archive every note this connector created (optionally scoped to a channel),
472
+ * plus their note-attached links. Mirror of {@link archiveLinks} for the
473
+ * note-attached content model. Use in `onChannelDisabled`.
474
+ */
475
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
476
+ abstract archiveNotes(filter: ArchiveNotesFilter): Promise<void>;
477
+
413
478
  /**
414
479
  * Upserts contacts into the connector's focus without requiring a Link.
415
480
  *
@@ -499,6 +564,15 @@ export abstract class Integrations extends ITool {
499
564
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
500
565
  abstract markNeedsReauth(channelId: string): Promise<void>;
501
566
 
567
+ /**
568
+ * Upsert workspace custom emoji into Plot's shared cache so reactions using
569
+ * `provider:workspace/name` refs render as images and round-trip. Idempotent;
570
+ * keyed on `id`. Pass `archived: true` to mark an emoji removed. Workspace-
571
+ * scoped (shared across all users of that workspace).
572
+ */
573
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
574
+ abstract saveCustomEmoji(emoji: NewCustomEmoji[]): Promise<void>;
575
+
502
576
  }
503
577
 
504
578
  /**
@@ -516,6 +590,37 @@ export type ArchiveLinkFilter = {
516
590
  meta?: Record<string, JSONValue>;
517
591
  };
518
592
 
593
+ /**
594
+ * Filter criteria for archiving notes (and their note-attached links).
595
+ * All fields are optional; only provided fields are used for matching.
596
+ */
597
+ export type ArchiveNotesFilter = {
598
+ /** Restrict to notes whose note-attached link is on this channel. */
599
+ channelId?: string;
600
+ };
601
+
602
+ /**
603
+ * A workspace custom emoji to cache so Plot can render and round-trip it as a
604
+ * reaction. `id` is the provider-scoped ref stored on reactions, of the form
605
+ * `<provider>:<workspace>/<name>` (e.g. `slack:T0123ABC/party_parrot`).
606
+ */
607
+ export type NewCustomEmoji = {
608
+ /** Provider-scoped ref: `<provider>:<workspace>/<name>`. The reaction value. */
609
+ id: string;
610
+ /** e.g. "slack". */
611
+ provider: string;
612
+ /** Provider workspace/team id (e.g. Slack team id `T0123ABC`). */
613
+ workspace: string;
614
+ /** Bare emoji name without colons (e.g. "party_parrot"). */
615
+ name: string;
616
+ /** Image URL to render, or null for an alias (see `aliasOf`). */
617
+ imageUrl: string | null;
618
+ /** When this emoji aliases another, the target ref (`id` of the canonical emoji); else null. */
619
+ aliasOf: string | null;
620
+ /** True to mark the emoji removed (archive it) rather than upsert it. */
621
+ archived: boolean;
622
+ };
623
+
519
624
  /**
520
625
  * Enumeration of supported OAuth providers.
521
626
  *
@@ -133,27 +133,27 @@ export abstract class Network extends ITool {
133
133
  *
134
134
  * **Provider-Specific Behavior:**
135
135
  * - **Slack**: Uses provider-specific routing via team_id. Requires `authorization` parameter.
136
- * - **Gmail** (Google with Gmail scopes): Returns a Google Pub/Sub topic name instead of a webhook URL.
137
- * The topic name (e.g., "projects/plot-prod/topics/gmail-webhook-abc123") should be passed
138
- * to the Gmail API's `users.watch` endpoint. Requires `authorization` parameter with Gmail scopes.
139
- * - **Pub/Sub** (`pubsub: true`): Returns a Google Pub/Sub topic name instead of a webhook URL.
140
- * Use this for services that deliver events via Pub/Sub (e.g., Google Workspace Events API).
141
- * A Pub/Sub topic and push subscription are created automatically; the returned topic name
142
- * can be passed to any Google API that accepts a Pub/Sub notification endpoint.
136
+ * - **Pub/Sub** (`pubsub: "gmail" | "workspace"`): Returns a Google Pub/Sub topic name instead
137
+ * of a webhook URL. `"gmail"` targets Gmail `users.watch` (set this only on the Gmail
138
+ * connector); `"workspace"` targets Google Workspace Events (Chat, etc.). A Pub/Sub topic and
139
+ * push subscription are created automatically; the returned topic name (e.g.
140
+ * "projects/plot-prod/topics/gmail-abc123") is passed to the relevant Google API. Other Google
141
+ * connectors (Calendar, Drive) omit `pubsub` and use the default HTTPS webhook.
143
142
  * - **Default**: Returns a standard webhook URL for all other cases.
144
143
  *
145
144
  * @param options - Webhook creation options
146
145
  * @param options.provider - Optional provider for provider-specific webhook routing
147
- * @param options.authorization - Optional authorization for provider-specific webhooks (required for Slack and Gmail)
146
+ * @param options.authorization - Optional authorization for provider-specific webhooks (required for Slack)
147
+ * @param options.pubsub - Optional Google Pub/Sub push product ("gmail" | "workspace")
148
148
  * @param callback - Function receiving (request, ...extraArgs)
149
149
  * @param extraArgs - Additional arguments to pass to the callback (type-checked, no functions allowed)
150
- * @returns Promise resolving to the webhook URL, or for Gmail/Pub/Sub, a Pub/Sub topic name
150
+ * @returns Promise resolving to the webhook URL, or for Pub/Sub, a Pub/Sub topic name
151
151
  *
152
152
  * @example
153
153
  * ```typescript
154
- * // Pub/Sub webhook for Workspace Events API
154
+ * // Pub/Sub webhook for Workspace Events API (Chat, etc.)
155
155
  * const topicName = await this.tools.network.createWebhook(
156
- * { pubsub: true },
156
+ * { pubsub: "workspace" },
157
157
  * this.onEventReceived,
158
158
  * channelId
159
159
  * );
@@ -165,9 +165,9 @@ export abstract class Network extends ITool {
165
165
  *
166
166
  * @example
167
167
  * ```typescript
168
- * // Gmail webhook - auto-detected from scopes, returns Pub/Sub topic name
168
+ * // Gmail webhook - returns a Gmail Pub/Sub topic name for users.watch
169
169
  * const topicName = await this.tools.network.createWebhook(
170
- * {},
170
+ * { pubsub: "gmail" },
171
171
  * this.onGmailNotification,
172
172
  * "inbox"
173
173
  * );
@@ -180,8 +180,20 @@ export abstract class Network extends ITool {
180
180
  options: {
181
181
  provider?: AuthProvider;
182
182
  authorization?: Authorization;
183
- /** When true, creates a Google Pub/Sub topic instead of a webhook URL. */
184
- pubsub?: boolean;
183
+ /**
184
+ * Create a Google Pub/Sub topic instead of a webhook URL, and return
185
+ * the topic name. Selects the push product:
186
+ *
187
+ * - `"gmail"` — Gmail `users.watch` (topic published to by
188
+ * `gmail-api-push`). Set this only on the Gmail connector.
189
+ * - `"workspace"` — Google Workspace Events (Chat, etc.).
190
+ *
191
+ * This opt-in must be explicit. Other Google connectors (Calendar,
192
+ * Drive) omit it and receive a standard HTTPS webhook URL — they must
193
+ * never be routed to a Pub/Sub topic, which `events.watch` /
194
+ * `files.watch` reject as non-HTTPS.
195
+ */
196
+ pubsub?: "gmail" | "workspace";
185
197
  /**
186
198
  * Controls whether the returned webhook URL runs callbacks synchronously
187
199
  * or asynchronously.