@plotday/twister 0.60.0 → 0.62.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 (97) hide show
  1. package/dist/connector.d.ts +58 -1
  2. package/dist/connector.d.ts.map +1 -1
  3. package/dist/connector.js +35 -0
  4. package/dist/connector.js.map +1 -1
  5. package/dist/docs/assets/hierarchy.js +1 -1
  6. package/dist/docs/assets/navigation.js +1 -1
  7. package/dist/docs/assets/search.js +1 -1
  8. package/dist/docs/classes/index.Connector.html +89 -36
  9. package/dist/docs/classes/index.FileNotFoundError.html +1 -1
  10. package/dist/docs/classes/index.Files.html +1 -1
  11. package/dist/docs/classes/index.Imap.html +1 -1
  12. package/dist/docs/classes/index.Options.html +1 -1
  13. package/dist/docs/classes/index.Smtp.html +1 -1
  14. package/dist/docs/classes/tool.ITool.html +1 -1
  15. package/dist/docs/classes/tool.Tool.html +33 -7
  16. package/dist/docs/classes/tools_ai.AI.html +1 -1
  17. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  18. package/dist/docs/classes/tools_integrations.Integrations.html +1 -1
  19. package/dist/docs/classes/tools_network.Network.html +1 -1
  20. package/dist/docs/classes/tools_plot.Plot.html +1 -1
  21. package/dist/docs/classes/tools_store.Store.html +1 -1
  22. package/dist/docs/classes/tools_tasks.Tasks.html +58 -2
  23. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  24. package/dist/docs/classes/twist.Twist.html +37 -11
  25. package/dist/docs/documents/Built-in_Tools.html +17 -1
  26. package/dist/docs/documents/Runtime_Environment.html +14 -4
  27. package/dist/docs/enums/plot.ActorType.html +4 -4
  28. package/dist/docs/hierarchy.html +1 -1
  29. package/dist/docs/media/AGENTS.md +48 -2
  30. package/dist/docs/modules/index.html +1 -1
  31. package/dist/docs/modules/plot.html +1 -1
  32. package/dist/docs/types/index.CreateLinkDraft.html +9 -9
  33. package/dist/docs/types/index.NoteWriteBackResult.html +21 -2
  34. package/dist/docs/types/index.OptionalScopeGroup.html +6 -6
  35. package/dist/docs/types/index.ResolvedRecipient.html +5 -5
  36. package/dist/docs/types/index.ScopeConfig.html +2 -2
  37. package/dist/docs/types/plot.Actor.html +5 -5
  38. package/dist/docs/types/plot.AutoThreadConfig.html +9 -0
  39. package/dist/docs/types/plot.AutoThreadMode.html +14 -0
  40. package/dist/docs/types/plot.Contact.html +4 -4
  41. package/dist/docs/types/plot.ContentType.html +1 -1
  42. package/dist/docs/types/plot.DeliveryError.html +17 -0
  43. package/dist/docs/types/plot.Link.html +17 -17
  44. package/dist/docs/types/plot.LinkUpdate.html +1 -1
  45. package/dist/docs/types/plot.NewActor.html +1 -1
  46. package/dist/docs/types/plot.NewContact.html +1 -1
  47. package/dist/docs/types/plot.NewLink.html +12 -2
  48. package/dist/docs/types/plot.NewLinkWithNotes.html +11 -3
  49. package/dist/docs/types/plot.NewNote.html +1 -1
  50. package/dist/docs/types/plot.Note.html +2 -5
  51. package/dist/docs/types/plot.NoteUpdate.html +1 -1
  52. package/dist/docs/types/plot.PlanOperation.html +1 -1
  53. package/dist/llm-docs/connector.d.ts +1 -1
  54. package/dist/llm-docs/connector.d.ts.map +1 -1
  55. package/dist/llm-docs/connector.js +1 -1
  56. package/dist/llm-docs/connector.js.map +1 -1
  57. package/dist/llm-docs/plot.d.ts +1 -1
  58. package/dist/llm-docs/plot.d.ts.map +1 -1
  59. package/dist/llm-docs/plot.js +1 -1
  60. package/dist/llm-docs/plot.js.map +1 -1
  61. package/dist/llm-docs/tool.d.ts +1 -1
  62. package/dist/llm-docs/tool.d.ts.map +1 -1
  63. package/dist/llm-docs/tool.js +1 -1
  64. package/dist/llm-docs/tool.js.map +1 -1
  65. package/dist/llm-docs/tools/tasks.d.ts +1 -1
  66. package/dist/llm-docs/tools/tasks.d.ts.map +1 -1
  67. package/dist/llm-docs/tools/tasks.js +1 -1
  68. package/dist/llm-docs/tools/tasks.js.map +1 -1
  69. package/dist/llm-docs/twist.d.ts +1 -1
  70. package/dist/llm-docs/twist.d.ts.map +1 -1
  71. package/dist/llm-docs/twist.js +1 -1
  72. package/dist/llm-docs/twist.js.map +1 -1
  73. package/dist/plot.d.ts +77 -0
  74. package/dist/plot.d.ts.map +1 -1
  75. package/dist/plot.js.map +1 -1
  76. package/dist/tool.d.ts +41 -0
  77. package/dist/tool.d.ts.map +1 -1
  78. package/dist/tool.js +42 -0
  79. package/dist/tool.js.map +1 -1
  80. package/dist/tools/tasks.d.ts +92 -0
  81. package/dist/tools/tasks.d.ts.map +1 -1
  82. package/dist/tools/tasks.js.map +1 -1
  83. package/dist/twist.d.ts +41 -0
  84. package/dist/twist.d.ts.map +1 -1
  85. package/dist/twist.js +42 -0
  86. package/dist/twist.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/connector.ts +61 -1
  89. package/src/llm-docs/connector.ts +1 -1
  90. package/src/llm-docs/plot.ts +1 -1
  91. package/src/llm-docs/tool.ts +1 -1
  92. package/src/llm-docs/tools/tasks.ts +1 -1
  93. package/src/llm-docs/twist.ts +1 -1
  94. package/src/plot.ts +80 -0
  95. package/src/tool.ts +53 -0
  96. package/src/tools/tasks.ts +101 -0
  97. package/src/twist.ts +53 -0
@@ -132,4 +132,105 @@ export abstract class Tasks extends ITool {
132
132
  * @returns Promise that resolves when all cancellations are processed
133
133
  */
134
134
  abstract cancelAllTasks(): Promise<void>;
135
+
136
+ /**
137
+ * Schedules a **one-shot singleton** task identified by `key`: scheduling
138
+ * under a key that already has a pending task atomically cancels the existing
139
+ * one and replaces it. At most one scheduled task per `key` is ever live.
140
+ *
141
+ * Use this for **one-shot keyed deferred work** — a single future task whose
142
+ * pending occurrence should be atomically replaced if re-scheduled (e.g.
143
+ * a deferred cleanup, a one-time expiry action, a single future send).
144
+ *
145
+ * For **recurring/self-renewing jobs** (watch renewals, polling loops,
146
+ * periodic syncs, self-heal checks), use {@link scheduleRecurring} instead.
147
+ * It owns the cadence on the platform side, so the chain survives dropped
148
+ * runs, suspensions, and deploys without the callback needing to reschedule
149
+ * itself.
150
+ *
151
+ * Replacement is atomic on the server, so concurrent executions racing to
152
+ * schedule the same key converge on a single task rather than leaking.
153
+ *
154
+ * @param key - Stable identifier for this logical task. Scope it to what it
155
+ * renews, e.g. `` `watch-renewal:${folderId}` ``.
156
+ * @param callback - Callback created with `this.callback()`
157
+ * @param options.runAt - When to run. Required: keying only applies to
158
+ * scheduled tasks (immediate tasks go straight to the queue).
159
+ * @returns Promise resolving to the cancellation token for the scheduled task
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * const cb = await this.callback(this.renewWatch, folderId);
164
+ * await this.scheduleTask(`watch-renewal:${folderId}`, cb, { runAt });
165
+ * // ...later, on disable:
166
+ * await this.cancelScheduledTask(`watch-renewal:${folderId}`);
167
+ * ```
168
+ */
169
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
170
+ abstract scheduleTask(
171
+ key: string,
172
+ callback: Callback,
173
+ options: { runAt: Date }
174
+ ): Promise<string | void>;
175
+
176
+ /**
177
+ * Cancels the singleton task previously scheduled under `key` (if any).
178
+ *
179
+ * No error is thrown if no task exists for the key or it has already run.
180
+ * Pair this with {@link scheduleTask} in teardown paths (e.g.
181
+ * `onChannelDisabled`, `stopSync`).
182
+ *
183
+ * @param key - The same key passed to {@link scheduleTask}
184
+ * @returns Promise that resolves when the cancellation is processed
185
+ */
186
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
187
+ abstract cancelScheduledTask(key: string): Promise<void>;
188
+
189
+ /**
190
+ * Schedules a **durable recurring** task identified by `key`. Unlike
191
+ * {@link scheduleTask} (one-shot, deleted when it fires), a recurring task's
192
+ * next occurrence is owned by the platform: the runtime re-arms it every
193
+ * `intervalMs` automatically, so the chain survives a dropped queue message,
194
+ * a suspension, a deploy/eviction, or a callback that throws before it could
195
+ * reschedule. The callback just does the work, idempotently — it does NOT
196
+ * need to reschedule itself.
197
+ *
198
+ * `intervalMs` is a **safety ceiling** (the maximum gap between fires). For
199
+ * data-dependent cadence (e.g. renew 24h before a provider-returned expiry),
200
+ * pass `firstRunAt` for the precise next fire and re-call `scheduleRecurring`
201
+ * with the same key on each run to keep tightening it; the ceiling guarantees
202
+ * the chain still fires if a run is lost. `firstRunAt` can pull the next fire
203
+ * earlier than the ceiling but never later.
204
+ *
205
+ * Recurring tasks are keyed/singleton: re-scheduling under the same key
206
+ * atomically replaces the pending occurrence (one live task per key). Tear
207
+ * down with {@link cancelScheduledTask}.
208
+ *
209
+ * @param key - Stable identifier, scoped to what it maintains, e.g.
210
+ * `` `watch-renewal:${folderId}` `` or `"mailbox-self-heal"`.
211
+ * @param callback - Callback created with `this.callback()`.
212
+ * @param options.intervalMs - Safety-ceiling cadence in milliseconds.
213
+ * @param options.firstRunAt - Optional precise time for the next fire
214
+ * (clamped to no later than now + intervalMs).
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * // Fixed cadence (self-heal, polling): register once, never reschedule.
219
+ * const cb = await this.callback(this.selfHealCheck);
220
+ * await this.scheduleRecurring("mailbox-self-heal", cb, { intervalMs: 60 * 60 * 1000 });
221
+ *
222
+ * // Variable cadence (watch renewal): precise firstRunAt + safety ceiling.
223
+ * const renew = await this.callback(this.renewWatch, folderId);
224
+ * await this.scheduleRecurring(`watch-renewal:${folderId}`, renew, {
225
+ * intervalMs: 3.5 * 24 * 60 * 60 * 1000, // ceiling: half the 7-day watch
226
+ * firstRunAt: new Date(expiry.getTime() - 24 * 60 * 60 * 1000),
227
+ * });
228
+ * ```
229
+ */
230
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
231
+ abstract scheduleRecurring(
232
+ key: string,
233
+ callback: Callback,
234
+ options: { intervalMs: number; firstRunAt?: Date }
235
+ ): Promise<void>;
135
236
  }
package/src/twist.ts CHANGED
@@ -294,6 +294,59 @@ export abstract class Twist<TSelf> {
294
294
  return this.tools.tasks.cancelAllTasks();
295
295
  }
296
296
 
297
+ /**
298
+ * Schedules a **singleton** task keyed by `key`: re-scheduling under the same
299
+ * key atomically replaces any pending task, so at most one is ever live.
300
+ *
301
+ * Prefer this over `runTask({ runAt })` for recurring/self-renewing jobs
302
+ * (watch renewals, polling, deferred cleanup) — it removes the error-prone
303
+ * "store token, cancel before re-scheduling" bookkeeping that otherwise leaks
304
+ * parallel task chains. See {@link Tasks.scheduleTask}.
305
+ *
306
+ * @param key - Stable identifier scoped to what the task renews
307
+ * @param callback - The callback token created with `this.callback()`
308
+ * @param options.runAt - When to run (required)
309
+ * @returns Promise resolving to the scheduled task's cancellation token
310
+ */
311
+ protected async scheduleTask(
312
+ key: string,
313
+ callback: Callback,
314
+ options: { runAt: Date }
315
+ ): Promise<string | void> {
316
+ return this.tools.tasks.scheduleTask(key, callback, options);
317
+ }
318
+
319
+ /**
320
+ * Cancels the singleton task previously scheduled under `key` (if any).
321
+ * No-op if none exists or it already ran. See {@link Tasks.cancelScheduledTask}.
322
+ *
323
+ * @param key - The same key passed to {@link scheduleTask}
324
+ * @returns Promise that resolves when the cancellation is processed
325
+ */
326
+ protected async cancelScheduledTask(key: string): Promise<void> {
327
+ return this.tools.tasks.cancelScheduledTask(key);
328
+ }
329
+
330
+ /**
331
+ * Schedules a durable recurring task under a stable key. The platform
332
+ * re-arms the task every `intervalMs` automatically — the callback does NOT
333
+ * need to reschedule itself. Re-scheduling under the same key atomically
334
+ * replaces the pending occurrence (at most one live task per key). Tear down
335
+ * with {@link cancelScheduledTask}. See {@link Tasks.scheduleRecurring}.
336
+ *
337
+ * @param key - Stable identifier, e.g. `"mailbox-self-heal"`
338
+ * @param callback - Callback token created with `this.callback()`
339
+ * @param options.intervalMs - Safety-ceiling cadence in milliseconds
340
+ * @param options.firstRunAt - Optional precise time for the next fire
341
+ */
342
+ protected async scheduleRecurring(
343
+ key: string,
344
+ callback: Callback,
345
+ options: { intervalMs: number; firstRunAt?: Date }
346
+ ): Promise<void> {
347
+ return this.tools.tasks.scheduleRecurring(key, callback, options);
348
+ }
349
+
297
350
  /**
298
351
  * Called when the twist is installed by a user.
299
352
  *