@plotday/twister 0.57.0 → 0.58.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 +53 -44
- package/bin/commands/create.js +9 -14
- package/bin/commands/create.js.map +1 -1
- package/bin/commands/deploy.js +2 -0
- package/bin/commands/deploy.js.map +1 -1
- package/bin/commands/generate.js +8 -5
- package/bin/commands/generate.js.map +1 -1
- package/bin/index.js +2 -2
- package/bin/index.js.map +1 -1
- package/bin/templates/AGENTS.template.md +110 -94
- package/bin/templates/README.template.md +36 -33
- package/cli/templates/AGENTS.template.md +110 -94
- package/cli/templates/README.template.md +36 -33
- package/dist/connector.d.ts +24 -17
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js +19 -12
- package/dist/connector.js.map +1 -1
- package/dist/docs/assets/hierarchy.js +1 -1
- package/dist/docs/assets/navigation.js +1 -1
- package/dist/docs/assets/search.js +1 -1
- package/dist/docs/classes/index.Connector.html +66 -60
- package/dist/docs/classes/index.FileNotFoundError.html +2 -2
- package/dist/docs/classes/index.Files.html +4 -4
- package/dist/docs/classes/index.Imap.html +10 -10
- package/dist/docs/classes/index.Options.html +2 -2
- package/dist/docs/classes/index.Smtp.html +6 -6
- package/dist/docs/classes/tool.ITool.html +2 -2
- package/dist/docs/classes/tool.Tool.html +23 -23
- package/dist/docs/classes/tools_ai.AI.html +5 -5
- package/dist/docs/classes/tools_callbacks.Callbacks.html +8 -8
- package/dist/docs/classes/tools_integrations.Integrations.html +15 -15
- package/dist/docs/classes/tools_network.Network.html +9 -9
- package/dist/docs/classes/tools_plot.Plot.html +34 -33
- package/dist/docs/classes/tools_store.Store.html +8 -8
- package/dist/docs/classes/tools_tasks.Tasks.html +6 -6
- package/dist/docs/classes/tools_twists.Twists.html +12 -11
- package/dist/docs/classes/twist.Twist.html +28 -28
- package/dist/docs/documents/Building_Connectors.html +42 -28
- package/dist/docs/documents/Built-in_Tools.html +170 -67
- package/dist/docs/documents/CLI_Reference.html +68 -47
- package/dist/docs/documents/Core_Concepts.html +52 -81
- package/dist/docs/documents/Getting_Started.html +28 -31
- package/dist/docs/documents/MULTI_USER_AUTH.html +45 -0
- package/dist/docs/documents/Runtime_Environment.html +13 -12
- package/dist/docs/documents/SYNC_STRATEGIES.html +373 -0
- package/dist/docs/enums/plot.ActionType.html +9 -9
- package/dist/docs/enums/plot.ActorType.html +4 -4
- package/dist/docs/enums/plot.ConferencingProvider.html +6 -6
- package/dist/docs/enums/plot.ThemeColor.html +9 -9
- package/dist/docs/enums/tag.Tag.html +3 -3
- package/dist/docs/enums/tools_ai.AIModel.html +3 -3
- package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
- package/dist/docs/enums/tools_plot.ContactAccess.html +2 -2
- package/dist/docs/enums/tools_plot.FocusAccess.html +3 -3
- package/dist/docs/enums/tools_plot.LinkAccess.html +3 -3
- package/dist/docs/enums/tools_plot.ThreadAccess.html +4 -4
- package/dist/docs/functions/index.Uuid.Generate.html +1 -1
- package/dist/docs/functions/utils_hash.quickHash.html +1 -1
- package/dist/docs/hierarchy.html +1 -1
- package/dist/docs/index.html +7 -8
- package/dist/docs/interfaces/tools_ai.AIRequest.html +13 -13
- package/dist/docs/interfaces/tools_ai.AIResponse.html +9 -9
- package/dist/docs/interfaces/tools_ai.FilePart.html +5 -5
- package/dist/docs/interfaces/tools_ai.ImagePart.html +4 -4
- package/dist/docs/interfaces/tools_ai.ReasoningPart.html +4 -4
- package/dist/docs/interfaces/tools_ai.RedactedReasoningPart.html +3 -3
- package/dist/docs/interfaces/tools_ai.TextPart.html +3 -3
- package/dist/docs/interfaces/tools_ai.ToolCallPart.html +5 -5
- package/dist/docs/interfaces/tools_ai.ToolExecutionOptions.html +4 -4
- package/dist/docs/interfaces/tools_ai.ToolResultPart.html +5 -5
- package/dist/docs/interfaces/tools_twists.TwistSource.html +3 -3
- package/dist/docs/interfaces/utils_types.ToolShed.html +5 -5
- package/dist/docs/media/AGENTS.md +101 -74
- package/dist/docs/modules.html +1 -1
- package/dist/docs/types/index.BooleanDef.html +2 -2
- package/dist/docs/types/index.CreateLinkDraft.html +9 -9
- package/dist/docs/types/index.ImapAddress.html +3 -3
- package/dist/docs/types/index.ImapConnectOptions.html +6 -6
- package/dist/docs/types/index.ImapFetchOptions.html +4 -4
- package/dist/docs/types/index.ImapFlagOperation.html +1 -1
- package/dist/docs/types/index.ImapMailbox.html +5 -5
- package/dist/docs/types/index.ImapMailboxStatus.html +7 -7
- package/dist/docs/types/index.ImapMessage.html +14 -14
- package/dist/docs/types/index.ImapSearchCriteria.html +9 -9
- package/dist/docs/types/index.ImapSession.html +1 -1
- package/dist/docs/types/index.NewSchedule.html +13 -13
- package/dist/docs/types/index.NewScheduleContact.html +2 -2
- package/dist/docs/types/index.NewScheduleOccurrence.html +1 -1
- package/dist/docs/types/index.NoteWriteBackResult.html +3 -3
- package/dist/docs/types/index.NumberDef.html +2 -2
- package/dist/docs/types/index.OptionDef.html +1 -1
- package/dist/docs/types/index.OptionalScopeGroup.html +6 -6
- package/dist/docs/types/index.OptionsSchema.html +1 -1
- package/dist/docs/types/index.ReactionCapabilities.html +1 -1
- package/dist/docs/types/index.ResolvedOptions.html +1 -1
- package/dist/docs/types/index.ResolvedRecipient.html +5 -5
- package/dist/docs/types/index.Schedule.html +12 -12
- package/dist/docs/types/index.ScheduleContact.html +2 -2
- package/dist/docs/types/index.ScheduleContactRole.html +1 -1
- package/dist/docs/types/index.ScheduleContactStatus.html +1 -1
- package/dist/docs/types/index.ScheduleOccurrence.html +6 -6
- package/dist/docs/types/index.ScheduleOccurrenceUpdate.html +1 -1
- package/dist/docs/types/index.ScopeConfig.html +3 -3
- package/dist/docs/types/index.SelectDef.html +2 -2
- package/dist/docs/types/index.Serializable.html +1 -1
- package/dist/docs/types/index.SmtpAddress.html +3 -3
- package/dist/docs/types/index.SmtpConnectOptions.html +7 -7
- package/dist/docs/types/index.SmtpMessage.html +12 -12
- package/dist/docs/types/index.SmtpSendResult.html +4 -4
- package/dist/docs/types/index.SmtpSession.html +1 -1
- package/dist/docs/types/index.TextDef.html +2 -2
- package/dist/docs/types/index.Uuid.html +1 -1
- package/dist/docs/types/plot.Action.html +1 -1
- package/dist/docs/types/plot.Actor.html +5 -5
- package/dist/docs/types/plot.ActorId.html +4 -4
- package/dist/docs/types/plot.Contact.html +4 -4
- package/dist/docs/types/plot.ContentType.html +1 -1
- package/dist/docs/types/plot.Focus.html +8 -8
- package/dist/docs/types/plot.FocusUpdate.html +1 -1
- package/dist/docs/types/plot.Link.html +17 -17
- package/dist/docs/types/plot.LinkUpdate.html +1 -1
- package/dist/docs/types/plot.NewActor.html +1 -1
- package/dist/docs/types/plot.NewContact.html +1 -1
- package/dist/docs/types/plot.NewFocus.html +1 -1
- package/dist/docs/types/plot.NewLink.html +5 -2
- package/dist/docs/types/plot.NewLinkWithNotes.html +1 -1
- package/dist/docs/types/plot.NewNote.html +1 -1
- package/dist/docs/types/plot.NewReactions.html +1 -1
- package/dist/docs/types/plot.NewTags.html +1 -1
- package/dist/docs/types/plot.NewThread.html +1 -1
- package/dist/docs/types/plot.NewThreadWithNotes.html +1 -1
- package/dist/docs/types/plot.Note.html +1 -1
- package/dist/docs/types/plot.NoteUpdate.html +1 -1
- package/dist/docs/types/plot.PlanOperation.html +1 -1
- package/dist/docs/types/plot.Reaction.html +3 -3
- package/dist/docs/types/plot.Reactions.html +1 -1
- package/dist/docs/types/plot.Tags.html +1 -1
- package/dist/docs/types/plot.Thread.html +1 -1
- package/dist/docs/types/plot.ThreadAccessLevel.html +1 -1
- package/dist/docs/types/plot.ThreadCommon.html +6 -6
- package/dist/docs/types/plot.ThreadFilter.html +2 -2
- package/dist/docs/types/plot.ThreadMeta.html +1 -1
- package/dist/docs/types/plot.ThreadType.html +1 -1
- package/dist/docs/types/plot.ThreadUpdate.html +1 -1
- package/dist/docs/types/plot.ThreadWithNotes.html +1 -1
- package/dist/docs/types/tools_ai.AIAssistantMessage.html +2 -2
- package/dist/docs/types/tools_ai.AICapabilities.html +4 -4
- package/dist/docs/types/tools_ai.AIMessage.html +1 -1
- package/dist/docs/types/tools_ai.AIOptions.html +2 -2
- package/dist/docs/types/tools_ai.AISource.html +1 -1
- package/dist/docs/types/tools_ai.AISystemMessage.html +2 -2
- package/dist/docs/types/tools_ai.AITool.html +1 -1
- package/dist/docs/types/tools_ai.AIToolMessage.html +2 -2
- package/dist/docs/types/tools_ai.AIToolSet.html +1 -1
- package/dist/docs/types/tools_ai.AIUsage.html +5 -5
- package/dist/docs/types/tools_ai.AIUserMessage.html +2 -2
- package/dist/docs/types/tools_ai.DataContent.html +1 -1
- package/dist/docs/types/tools_ai.ModelPreferences.html +5 -5
- package/dist/docs/types/tools_callbacks.Callback.html +2 -2
- package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
- package/dist/docs/types/tools_integrations.ArchiveNotesFilter.html +2 -2
- package/dist/docs/types/tools_integrations.AuthToken.html +6 -5
- package/dist/docs/types/tools_integrations.Authorization.html +4 -4
- package/dist/docs/types/tools_integrations.Channel.html +6 -6
- package/dist/docs/types/tools_integrations.ComposeConfig.html +4 -4
- package/dist/docs/types/tools_integrations.ContactRoleConfig.html +5 -5
- package/dist/docs/types/tools_integrations.LinkTypeConfig.html +21 -21
- package/dist/docs/types/tools_integrations.NewCustomEmoji.html +8 -8
- package/dist/docs/types/tools_integrations.StatusIcon.html +1 -1
- package/dist/docs/types/tools_integrations.SyncContext.html +4 -4
- package/dist/docs/types/tools_network.WebhookRequest.html +6 -6
- package/dist/docs/types/tools_plot.LinkFilter.html +5 -5
- package/dist/docs/types/tools_plot.LinkSearchResult.html +1 -1
- package/dist/docs/types/tools_plot.NoteIntentHandler.html +4 -4
- package/dist/docs/types/tools_plot.NoteSearchResult.html +1 -1
- package/dist/docs/types/tools_plot.SearchOptions.html +4 -4
- package/dist/docs/types/tools_plot.SearchResult.html +1 -1
- package/dist/docs/types/tools_twists.Log.html +2 -2
- package/dist/docs/types/tools_twists.TwistPermissions.html +1 -1
- package/dist/docs/types/utils_types.BuiltInTools.html +2 -2
- package/dist/docs/types/utils_types.ExtractBuildReturn.html +1 -1
- package/dist/docs/types/utils_types.InferOptions.html +1 -1
- package/dist/docs/types/utils_types.InferTools.html +1 -1
- package/dist/docs/types/utils_types.JSONValue.html +1 -1
- package/dist/docs/types/utils_types.PromiseValues.html +1 -1
- package/dist/docs/types/utils_types.ToolBuilder.html +1 -1
- package/dist/docs/variables/tools_plot.SEARCH_DEFAULT_LIMIT.html +1 -1
- package/dist/docs/variables/tools_plot.SEARCH_MAX_LIMIT.html +1 -1
- package/dist/facets.d.ts +30 -0
- package/dist/facets.d.ts.map +1 -0
- package/dist/facets.js +16 -0
- package/dist/facets.js.map +1 -0
- package/dist/llm-docs/connector.d.ts +1 -1
- package/dist/llm-docs/connector.d.ts.map +1 -1
- package/dist/llm-docs/connector.js +1 -1
- package/dist/llm-docs/connector.js.map +1 -1
- package/dist/llm-docs/facets.d.ts +9 -0
- package/dist/llm-docs/facets.d.ts.map +1 -0
- package/dist/llm-docs/facets.js +8 -0
- package/dist/llm-docs/facets.js.map +1 -0
- package/dist/llm-docs/index.d.ts.map +1 -1
- package/dist/llm-docs/index.js +2 -0
- package/dist/llm-docs/index.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/ai.d.ts +1 -1
- package/dist/llm-docs/tools/ai.d.ts.map +1 -1
- package/dist/llm-docs/tools/ai.js +1 -1
- package/dist/llm-docs/tools/ai.js.map +1 -1
- package/dist/llm-docs/tools/callbacks.d.ts +1 -1
- package/dist/llm-docs/tools/callbacks.d.ts.map +1 -1
- package/dist/llm-docs/tools/callbacks.js +1 -1
- package/dist/llm-docs/tools/callbacks.js.map +1 -1
- package/dist/llm-docs/tools/files.d.ts +1 -1
- package/dist/llm-docs/tools/files.d.ts.map +1 -1
- package/dist/llm-docs/tools/files.js +1 -1
- package/dist/llm-docs/tools/files.js.map +1 -1
- package/dist/llm-docs/tools/imap.d.ts +1 -1
- package/dist/llm-docs/tools/imap.d.ts.map +1 -1
- package/dist/llm-docs/tools/imap.js +1 -1
- package/dist/llm-docs/tools/imap.js.map +1 -1
- package/dist/llm-docs/tools/integrations.d.ts +1 -1
- package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
- package/dist/llm-docs/tools/integrations.js +1 -1
- package/dist/llm-docs/tools/integrations.js.map +1 -1
- package/dist/llm-docs/tools/network.d.ts +1 -1
- package/dist/llm-docs/tools/network.d.ts.map +1 -1
- package/dist/llm-docs/tools/network.js +1 -1
- package/dist/llm-docs/tools/network.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/smtp.d.ts +1 -1
- package/dist/llm-docs/tools/smtp.d.ts.map +1 -1
- package/dist/llm-docs/tools/smtp.js +1 -1
- package/dist/llm-docs/tools/smtp.js.map +1 -1
- package/dist/llm-docs/tools/tasks.d.ts +1 -1
- package/dist/llm-docs/tools/tasks.d.ts.map +1 -1
- package/dist/llm-docs/tools/tasks.js +1 -1
- package/dist/llm-docs/tools/tasks.js.map +1 -1
- package/dist/llm-docs/tools/twists.d.ts +1 -1
- package/dist/llm-docs/tools/twists.d.ts.map +1 -1
- package/dist/llm-docs/tools/twists.js +1 -1
- package/dist/llm-docs/tools/twists.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/llm-docs/twist.d.ts +1 -1
- package/dist/llm-docs/twist.d.ts.map +1 -1
- package/dist/llm-docs/twist.js +1 -1
- package/dist/llm-docs/twist.js.map +1 -1
- package/dist/plot.d.ts +15 -8
- package/dist/plot.d.ts.map +1 -1
- package/dist/plot.js.map +1 -1
- package/dist/tool.d.ts +4 -4
- package/dist/tool.js +4 -4
- package/dist/tools/ai.d.ts +12 -13
- package/dist/tools/ai.d.ts.map +1 -1
- package/dist/tools/ai.js +8 -9
- package/dist/tools/ai.js.map +1 -1
- package/dist/tools/callbacks.d.ts +1 -1
- package/dist/tools/files.d.ts +2 -2
- package/dist/tools/imap.d.ts +1 -1
- package/dist/tools/imap.js +1 -1
- package/dist/tools/integrations.d.ts +2 -1
- package/dist/tools/integrations.d.ts.map +1 -1
- package/dist/tools/network.d.ts +5 -5
- package/dist/tools/plot.d.ts +42 -37
- package/dist/tools/plot.d.ts.map +1 -1
- package/dist/tools/plot.js +16 -12
- package/dist/tools/plot.js.map +1 -1
- package/dist/tools/smtp.d.ts +1 -1
- package/dist/tools/smtp.js +1 -1
- package/dist/tools/tasks.d.ts +6 -8
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +5 -7
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/twists.d.ts +15 -14
- package/dist/tools/twists.d.ts.map +1 -1
- package/dist/tools/twists.js +2 -2
- package/dist/tools/twists.js.map +1 -1
- package/dist/twist-guide.d.ts +1 -1
- package/dist/twist-guide.d.ts.map +1 -1
- package/dist/twist.d.ts +2 -2
- package/dist/twist.js +2 -2
- package/package.json +6 -1
- package/src/connector.ts +23 -16
- package/src/facets.ts +40 -0
- package/src/llm-docs/connector.ts +1 -1
- package/src/llm-docs/facets.ts +8 -0
- package/src/llm-docs/index.ts +2 -0
- package/src/llm-docs/plot.ts +1 -1
- package/src/llm-docs/tool.ts +1 -1
- package/src/llm-docs/tools/ai.ts +1 -1
- package/src/llm-docs/tools/callbacks.ts +1 -1
- package/src/llm-docs/tools/files.ts +1 -1
- package/src/llm-docs/tools/imap.ts +1 -1
- package/src/llm-docs/tools/integrations.ts +1 -1
- package/src/llm-docs/tools/network.ts +1 -1
- package/src/llm-docs/tools/plot.ts +1 -1
- package/src/llm-docs/tools/smtp.ts +1 -1
- package/src/llm-docs/tools/tasks.ts +1 -1
- package/src/llm-docs/tools/twists.ts +1 -1
- package/src/llm-docs/twist-guide-template.ts +1 -1
- package/src/llm-docs/twist.ts +1 -1
- package/src/plot.ts +15 -8
- package/src/tool.ts +4 -4
- package/src/tools/ai.ts +12 -13
- package/src/tools/callbacks.ts +1 -1
- package/src/tools/files.ts +2 -2
- package/src/tools/imap.ts +1 -1
- package/src/tools/integrations.ts +2 -1
- package/src/tools/network.ts +5 -5
- package/src/tools/plot.ts +42 -37
- package/src/tools/smtp.ts +1 -1
- package/src/tools/tasks.ts +6 -8
- package/src/tools/twists.ts +15 -14
- package/src/twist.ts +2 -2
- package/dist/docs/media/MULTI_USER_AUTH.md +0 -116
- package/dist/docs/media/SYNC_STRATEGIES.md +0 -818
package/src/llm-docs/twist.ts
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* Generated from: prebuild.ts
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export default "import type { NoteWriteBackResult } from \"./connector\";\nimport { type Action, type Actor, type ActorId, type Link, type Note, type Thread, Uuid } from \"./plot\";\nimport type { Tag } from \"./tag\";\nimport { type ITool } from \"./tool\";\nimport type { Callback } from \"./tools/callbacks\";\nimport type { Serializable } from \"./utils/serializable\";\nimport type { InferTools, ToolBuilder, ToolShed } from \"./utils/types\";\n\n/**\n * Base class for all twists.\n *\n * A twist is installed at the workspace level and is owned by a single user\n * (see `this.userId`). It has no inherent focus scope: threads, notes, and\n * links it creates are filed against the owner's focuses, with automatic\n * focus matching when no explicit target is provided.\n *\n * Override `build()` to declare tool dependencies and lifecycle methods to\n * handle events.\n *\n * @example\n * ```typescript\n * class FlatteringTwist extends Twist<FlatteringTwist> {\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot),\n * };\n * }\n *\n * async activate() {\n * await this.tools.plot.createThread({\n * title: \"Hello, good looking!\",\n * });\n * }\n * }\n * ```\n */\nexport abstract class Twist<TSelf> {\n /**\n * When `true`, users may install multiple instances of this twist within\n * the same scope (personal workspace or team). Each instance must have a\n * distinct name.\n *\n * Defaults to `false` (single instance per scope).\n *\n * @example\n * ```typescript\n * class WorkflowTwist extends Twist<WorkflowTwist> {\n * static readonly multipleInstances = true;\n * // ...\n * }\n * ```\n */\n static readonly multipleInstances?: boolean;\n\n /**\n * The user ID (`twist_instance.owner_id`) that installed this twist.\n * Populated by the runtime before any lifecycle method runs.\n */\n protected userId!: Uuid;\n\n constructor(protected id: Uuid, private toolShed: ToolShed) {}\n\n /**\n * Gets the initialized tools for this twist.\n * @throws Error if called before initialization is complete\n */\n protected get tools(): InferTools<TSelf> {\n return this.toolShed.getTools<InferTools<TSelf>>();\n }\n\n /**\n * Declares tool dependencies for this twist.\n * Return an object mapping tool names to build() promises.\n *\n * @param build - The build function to use for declaring dependencies\n * @returns Object mapping tool names to tool promises\n *\n * @example\n * ```typescript\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot),\n * calendar: build(GoogleCalendar, { apiKey: \"...\" }),\n * };\n * }\n * ```\n */\n abstract build(build: ToolBuilder): Record<string, Promise<ITool>>;\n\n /**\n * Creates a persistent callback to a method on this twist.\n *\n * ExtraArgs are strongly typed to match the method's signature. They must be serializable.\n *\n * @param fn - The method to callback\n * @param extraArgs - Additional arguments to pass (type-checked, must be serializable)\n * @returns Promise resolving to a persistent callback token\n *\n * @example\n * ```typescript\n * const callback = await this.callback(this.onWebhook, \"calendar\", 123);\n * ```\n */\n protected callback<\n TArgs extends Serializable[],\n Fn extends (...args: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback>;\n // Overload when caller provides the first argument\n protected callback<\n TArgs extends Serializable[],\n Fn extends (arg1: any, ...extraArgs: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback>;\n protected async callback<\n TArgs extends Serializable[],\n Fn extends (...args: any[]) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback> {\n return this.tools.callbacks.create(fn, ...extraArgs);\n }\n\n /**\n * Like callback(), but for an Action, which receives the action as the first argument.\n *\n * @param fn - The method to callback\n * @param extraArgs - Additional arguments to pass after the action\n * @returns Promise resolving to a persistent callback token\n *\n * @example\n * ```typescript\n * const callback = await this.actionCallback(this.doSomething, 123);\n * const action: Action = {\n * type: ActionType.callback,\n * title: \"Do Something\",\n * callback,\n * };\n * ```\n */\n protected async actionCallback<\n TArgs extends Serializable[],\n Fn extends (action: Action, ...extraArgs: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback> {\n return this.tools.callbacks.create(fn, ...extraArgs);\n }\n\n /**\n * Deletes a specific callback by its token.\n *\n * @param token - The callback token to delete\n * @returns Promise that resolves when the callback is deleted\n */\n protected async deleteCallback(token: Callback): Promise<void> {\n return this.tools.callbacks.delete(token);\n }\n\n /**\n * Deletes all callbacks for this twist.\n *\n * @returns Promise that resolves when all callbacks are deleted\n */\n protected async deleteAllCallbacks(): Promise<void> {\n return this.tools.callbacks.deleteAll();\n }\n\n /**\n * Executes a callback by its token inline in the current execution.\n *\n * **Use `this.runTask()` instead for batch continuations and long-running work.**\n * `this.run()` executes inline, sharing the current request count (~1000 limit)\n * and blocking the HTTP response. This causes timeouts when used in lifecycle\n * methods like `onChannelEnabled` or `syncBatch` continuations.\n *\n * `this.run()` is appropriate when you need the callback's **return value** —\n * e.g., running a parent callback token that returns data. For fire-and-forget\n * work, always prefer `this.runTask()`.\n *\n * @param token - The callback token to execute\n * @param args - Optional arguments to pass to the callback\n * @returns Promise resolving to the callback result\n */\n protected async run(token: Callback, ...args: []): Promise<any> {\n return this.tools.callbacks.run(token, ...args);\n }\n\n /**\n * Retrieves a value from persistent storage by key.\n *\n * Values are automatically deserialized using SuperJSON, which\n * properly restores Date objects, Maps, Sets, and other complex types.\n *\n * @template T - The expected type of the stored value (must be Serializable)\n * @param key - The storage key to retrieve\n * @returns Promise resolving to the stored value or null\n */\n protected async get<T extends import(\"./index\").Serializable>(\n key: string\n ): Promise<T | null> {\n return this.tools.store.get(key);\n }\n\n /**\n * Stores a value in persistent storage.\n *\n * The value will be serialized using SuperJSON and stored persistently.\n * SuperJSON automatically handles Date objects, Maps, Sets, undefined values,\n * and other complex types that standard JSON doesn't support.\n *\n * **Important**: Functions and Symbols cannot be stored.\n * **For function references**: Use callbacks instead of storing functions directly.\n *\n * @example\n * ```typescript\n * // ✅ Date objects are preserved\n * await this.set(\"sync_state\", {\n * lastSync: new Date(),\n * minDate: new Date(2024, 0, 1)\n * });\n *\n * // ✅ undefined is now supported\n * await this.set(\"data\", { name: \"test\", optional: undefined });\n *\n * // ❌ WRONG: Cannot store functions directly\n * await this.set(\"handler\", this.myHandler);\n *\n * // ✅ CORRECT: Create a callback token first\n * const token = await this.callback(this.myHandler, \"arg1\", \"arg2\");\n * await this.set(\"handler_token\", token);\n *\n * // Later, execute the callback\n * const token = await this.get<string>(\"handler_token\");\n * await this.run(token, args);\n * ```\n *\n * @template T - The type of value being stored (must be Serializable)\n * @param key - The storage key to use\n * @param value - The value to store (must be SuperJSON-serializable)\n * @returns Promise that resolves when the value is stored\n */\n protected async set<T extends import(\"./index\").Serializable>(\n key: string,\n value: T\n ): Promise<void> {\n return this.tools.store.set(key, value);\n }\n\n /**\n * Removes a specific key from persistent storage.\n *\n * @param key - The storage key to remove\n * @returns Promise that resolves when the key is removed\n */\n protected async clear(key: string): Promise<void> {\n return this.tools.store.clear(key);\n }\n\n /**\n * Removes all keys from this twist's storage.\n *\n * @returns Promise that resolves when all keys are removed\n */\n protected async clearAll(): Promise<void> {\n return this.tools.store.clearAll();\n }\n\n /**\n * Queues a callback to execute in a separate worker context.\n *\n * @param callback - The callback token created with `this.callback()`\n * @param options - Optional configuration for the execution\n * @param options.runAt - If provided, schedules execution at this time; otherwise runs immediately\n * @returns Promise resolving to a cancellation token (only for scheduled executions)\n */\n protected async runTask(\n callback: Callback,\n options?: { runAt?: Date }\n ): Promise<string | void> {\n return this.tools.tasks.runTask(callback, options);\n }\n\n /**\n * Cancels a previously scheduled execution.\n *\n * @param token - The cancellation token returned by runTask() with runAt option\n * @returns Promise that resolves when the cancellation is processed\n */\n protected async cancelTask(token: string): Promise<void> {\n return this.tools.tasks.cancelTask(token);\n }\n\n /**\n * Cancels all scheduled executions for this twist.\n *\n * @returns Promise that resolves when all cancellations are processed\n */\n protected async cancelAllTasks(): Promise<void> {\n return this.tools.tasks.cancelAllTasks();\n }\n\n /**\n * Called when the twist is installed by a user.\n *\n * This method should contain initialization logic such as seeding\n * initial threads, configuring webhooks, or establishing external\n * connections. When it runs, `this.userId` is already populated with\n * the installing user's ID.\n *\n * @param context - Optional context containing the actor who triggered activation\n * @returns Promise that resolves when activation is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n activate(context?: { actor: Actor }): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a new version of the twist is deployed.\n *\n * This method should contain migration logic for updating old data structures\n * or setting up new resources that weren't needed by the previous version.\n * It is called once per active twist_instance with the new version.\n *\n * @returns Promise that resolves when upgrade is complete\n */\n upgrade(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when the twist's options configuration changes.\n *\n * Override to react to option changes, e.g. archiving items when a sync\n * type is toggled off, or starting sync when a type is toggled on.\n *\n * @param oldOptions - The previously resolved options\n * @param newOptions - The newly resolved options\n * @returns Promise that resolves when the change is handled\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onOptionsChanged(\n oldOptions: Record<string, any>,\n newOptions: Record<string, any>\n ): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when the twist is uninstalled.\n *\n * This method should contain cleanup logic such as removing webhooks,\n * cleaning up external resources, or performing final data operations.\n *\n * @returns Promise that resolves when deactivation is complete\n */\n deactivate(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a thread created by this twist is updated.\n * Override to implement two-way sync with an external system.\n *\n * @param thread - The updated thread\n * @param changes - Tag additions and removals on the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onThreadUpdated(\n thread: Thread,\n changes: {\n tagsAdded: Record<Tag, ActorId[]>;\n tagsRemoved: Record<Tag, ActorId[]>;\n }\n ): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a note is created on a thread created by this twist.\n * Override to implement two-way sync (e.g. syncing notes as comments).\n *\n * Notes created by the twist itself are filtered out to prevent loops.\n *\n * Returning a string sets the note's `key` for future upsert matching,\n * linking the Plot note to its external counterpart so that subsequent\n * syncs (reactions, edits) update the existing note instead of creating duplicates.\n *\n * @param note - The newly created note\n * @returns Optional note key for external deduplication\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onNoteCreated(note: Note, ...args: any[]): Promise<string | NoteWriteBackResult | void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a link is created in a connected source channel.\n * Requires `link: true` in Plot options.\n *\n * @param link - The newly created link\n * @param notes - Notes on the link's thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkCreated(link: Link, notes: Note[]): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a link in a connected source channel is updated.\n * Requires `link: true` in Plot options.\n *\n * @param link - The updated link\n * @param notes - Notes on the link's thread (optional)\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkUpdated(link: Link, notes?: Note[]): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a note is created on a thread with a link from a connected channel.\n * Requires `link: true` in Plot options.\n *\n * @param note - The newly created note\n * @param link - The link associated with the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkNoteCreated(note: Note, link: Link): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Waits for tool initialization to complete.\n * Called automatically by the entrypoint before lifecycle methods.\n * @internal\n */\n async waitForReady(): Promise<void> {\n await this.toolShed.waitForReady();\n }\n}\n";
|
|
8
|
+
export default "import type { NoteWriteBackResult } from \"./connector\";\nimport { type Action, type Actor, type ActorId, type Link, type Note, type Thread, Uuid } from \"./plot\";\nimport type { Tag } from \"./tag\";\nimport { type ITool } from \"./tool\";\nimport type { Callback } from \"./tools/callbacks\";\nimport type { Serializable } from \"./utils/serializable\";\nimport type { InferTools, ToolBuilder, ToolShed } from \"./utils/types\";\n\n/**\n * Base class for all twists.\n *\n * A twist is installed at the workspace level and is owned by a single user\n * (see `this.userId`). It has no inherent focus scope: threads, notes, and\n * links it creates are filed against the owner's focuses, with automatic\n * focus matching when no explicit target is provided.\n *\n * Override `build()` to declare tool dependencies and lifecycle methods to\n * handle events.\n *\n * @example\n * ```typescript\n * class FlatteringTwist extends Twist<FlatteringTwist> {\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot),\n * };\n * }\n *\n * async activate() {\n * await this.tools.plot.createThread({\n * title: \"Hello, good looking!\",\n * });\n * }\n * }\n * ```\n */\nexport abstract class Twist<TSelf> {\n /**\n * When `true`, users may install multiple instances of this twist within\n * the same scope (personal workspace or team). Each instance must have a\n * distinct name.\n *\n * Defaults to `false` (single instance per scope).\n *\n * @example\n * ```typescript\n * class WorkflowTwist extends Twist<WorkflowTwist> {\n * static readonly multipleInstances = true;\n * // ...\n * }\n * ```\n */\n static readonly multipleInstances?: boolean;\n\n /**\n * The user ID (`twist_instance.owner_id`) that installed this twist.\n * Populated by the runtime before any lifecycle method runs.\n */\n protected userId!: Uuid;\n\n constructor(protected id: Uuid, private toolShed: ToolShed) {}\n\n /**\n * Gets the initialized tools for this twist.\n * @throws Error if called before initialization is complete\n */\n protected get tools(): InferTools<TSelf> {\n return this.toolShed.getTools<InferTools<TSelf>>();\n }\n\n /**\n * Declares tool dependencies for this twist.\n * Return an object mapping tool names to build() promises.\n *\n * @param build - The build function to use for declaring dependencies\n * @returns Object mapping tool names to tool promises\n *\n * @example\n * ```typescript\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot),\n * calendar: build(GoogleCalendar, { apiKey: \"...\" }),\n * };\n * }\n * ```\n */\n abstract build(build: ToolBuilder): Record<string, Promise<ITool>>;\n\n /**\n * Creates a persistent callback to a method on this twist.\n *\n * ExtraArgs are strongly typed to match the method's signature. They must be serializable.\n *\n * @param fn - The method to callback\n * @param extraArgs - Additional arguments to pass (type-checked, must be serializable)\n * @returns Promise resolving to a persistent callback token\n *\n * @example\n * ```typescript\n * const callback = await this.callback(this.onWebhook, \"calendar\", 123);\n * ```\n */\n protected callback<\n TArgs extends Serializable[],\n Fn extends (...args: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback>;\n // Overload when caller provides the first argument\n protected callback<\n TArgs extends Serializable[],\n Fn extends (arg1: any, ...extraArgs: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback>;\n protected async callback<\n TArgs extends Serializable[],\n Fn extends (...args: any[]) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback> {\n return this.tools.callbacks.create(fn, ...extraArgs);\n }\n\n /**\n * Like callback(), but for an Action, which receives the action as the first argument.\n *\n * @param fn - The method to callback\n * @param extraArgs - Additional arguments to pass after the action\n * @returns Promise resolving to a persistent callback token\n *\n * @example\n * ```typescript\n * const callback = await this.actionCallback(this.doSomething, 123);\n * const action: Action = {\n * type: ActionType.callback,\n * title: \"Do Something\",\n * callback,\n * };\n * ```\n */\n protected async actionCallback<\n TArgs extends Serializable[],\n Fn extends (action: Action, ...extraArgs: TArgs) => any\n >(fn: Fn, ...extraArgs: TArgs): Promise<Callback> {\n return this.tools.callbacks.create(fn, ...extraArgs);\n }\n\n /**\n * Deletes a specific callback by its token.\n *\n * @param token - The callback token to delete\n * @returns Promise that resolves when the callback is deleted\n */\n protected async deleteCallback(token: Callback): Promise<void> {\n return this.tools.callbacks.delete(token);\n }\n\n /**\n * Deletes all callbacks for this twist.\n *\n * @returns Promise that resolves when all callbacks are deleted\n */\n protected async deleteAllCallbacks(): Promise<void> {\n return this.tools.callbacks.deleteAll();\n }\n\n /**\n * Executes a callback by its token inline in the current execution.\n *\n * **Use `this.runTask()` instead for batch continuations and long-running work.**\n * `this.run()` executes inline, sharing the current request count (~1000 limit)\n * and blocking the HTTP response. This causes timeouts when used in lifecycle\n * methods like `onChannelEnabled` or `syncBatch` continuations.\n *\n * `this.run()` is appropriate when you need the callback's **return value** —\n * e.g., running a parent callback token that returns data. For fire-and-forget\n * work, always prefer `this.runTask()`.\n *\n * @param token - The callback token to execute\n * @param args - Optional arguments to pass to the callback\n * @returns Promise resolving to the callback result\n */\n protected async run(token: Callback, ...args: []): Promise<any> {\n return this.tools.callbacks.run(token, ...args);\n }\n\n /**\n * Retrieves a value from persistent storage by key.\n *\n * Values are automatically deserialized using SuperJSON, which\n * properly restores Date objects, Maps, Sets, and other complex types.\n *\n * @template T - The expected type of the stored value (must be Serializable)\n * @param key - The storage key to retrieve\n * @returns Promise resolving to the stored value or null\n */\n protected async get<T extends import(\"./index\").Serializable>(\n key: string\n ): Promise<T | null> {\n return this.tools.store.get(key);\n }\n\n /**\n * Stores a value in persistent storage.\n *\n * The value will be serialized using SuperJSON and stored persistently.\n * SuperJSON automatically handles Date objects, Maps, Sets, undefined values,\n * and other complex types that standard JSON doesn't support.\n *\n * **Important**: Functions and Symbols cannot be stored.\n * **For function references**: Use callbacks instead of storing functions directly.\n *\n * @example\n * ```typescript\n * // ✅ Date objects are preserved\n * await this.set(\"sync_state\", {\n * lastSync: new Date(),\n * minDate: new Date(2024, 0, 1)\n * });\n *\n * // ✅ undefined is now supported\n * await this.set(\"data\", { name: \"test\", optional: undefined });\n *\n * // ❌ WRONG: Cannot store functions directly\n * await this.set(\"handler\", this.myHandler);\n *\n * // ✅ CORRECT: Create a callback token first\n * const token = await this.callback(this.myHandler, \"arg1\", \"arg2\");\n * await this.set(\"handler_token\", token);\n *\n * // Later, execute the callback\n * const token = await this.get<Callback>(\"handler_token\");\n * await this.run(token);\n * ```\n *\n * @template T - The type of value being stored (must be Serializable)\n * @param key - The storage key to use\n * @param value - The value to store (must be SuperJSON-serializable)\n * @returns Promise that resolves when the value is stored\n */\n protected async set<T extends import(\"./index\").Serializable>(\n key: string,\n value: T\n ): Promise<void> {\n return this.tools.store.set(key, value);\n }\n\n /**\n * Removes a specific key from persistent storage.\n *\n * @param key - The storage key to remove\n * @returns Promise that resolves when the key is removed\n */\n protected async clear(key: string): Promise<void> {\n return this.tools.store.clear(key);\n }\n\n /**\n * Removes all keys from this twist's storage.\n *\n * @returns Promise that resolves when all keys are removed\n */\n protected async clearAll(): Promise<void> {\n return this.tools.store.clearAll();\n }\n\n /**\n * Queues a callback to execute in a separate worker context.\n *\n * @param callback - The callback token created with `this.callback()`\n * @param options - Optional configuration for the execution\n * @param options.runAt - If provided, schedules execution at this time; otherwise runs immediately\n * @returns Promise resolving to a cancellation token (only for scheduled executions)\n */\n protected async runTask(\n callback: Callback,\n options?: { runAt?: Date }\n ): Promise<string | void> {\n return this.tools.tasks.runTask(callback, options);\n }\n\n /**\n * Cancels a previously scheduled execution.\n *\n * @param token - The cancellation token returned by runTask() with runAt option\n * @returns Promise that resolves when the cancellation is processed\n */\n protected async cancelTask(token: string): Promise<void> {\n return this.tools.tasks.cancelTask(token);\n }\n\n /**\n * Cancels all scheduled executions for this twist.\n *\n * @returns Promise that resolves when all cancellations are processed\n */\n protected async cancelAllTasks(): Promise<void> {\n return this.tools.tasks.cancelAllTasks();\n }\n\n /**\n * Called when the twist is installed by a user.\n *\n * This method should contain initialization logic such as seeding\n * initial threads, configuring webhooks, or establishing external\n * connections. When it runs, `this.userId` is already populated with\n * the installing user's ID.\n *\n * @param context - Optional context containing the actor who triggered activation\n * @returns Promise that resolves when activation is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n activate(context?: { actor: Actor }): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a new version of the twist is deployed.\n *\n * This method should contain migration logic for updating old data structures\n * or setting up new resources that weren't needed by the previous version.\n * It is called once per active twist_instance with the new version.\n *\n * @returns Promise that resolves when upgrade is complete\n */\n upgrade(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when the twist's options configuration changes.\n *\n * Override to react to option changes, e.g. archiving items when a sync\n * type is toggled off, or starting sync when a type is toggled on.\n *\n * @param oldOptions - The previously resolved options\n * @param newOptions - The newly resolved options\n * @returns Promise that resolves when the change is handled\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onOptionsChanged(\n oldOptions: Record<string, any>,\n newOptions: Record<string, any>\n ): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when the twist is uninstalled.\n *\n * This method should contain cleanup logic such as removing webhooks,\n * cleaning up external resources, or performing final data operations.\n *\n * @returns Promise that resolves when deactivation is complete\n */\n deactivate(): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a thread created by this twist is updated.\n * Override to implement two-way sync with an external system.\n *\n * @param thread - The updated thread\n * @param changes - Tag additions and removals on the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onThreadUpdated(\n thread: Thread,\n changes: {\n tagsAdded: Record<Tag, ActorId[]>;\n tagsRemoved: Record<Tag, ActorId[]>;\n }\n ): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a note is created on a thread created by this twist.\n * Override to implement two-way sync (e.g. syncing notes as comments).\n *\n * Notes created by the twist itself are filtered out to prevent loops.\n *\n * Returning a string sets the note's `key` for future upsert matching,\n * linking the Plot note to its external counterpart so that subsequent\n * syncs (reactions, edits) update the existing note instead of creating duplicates.\n *\n * @param note - The newly created note\n * @returns Optional note key for external deduplication\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onNoteCreated(note: Note, ...args: any[]): Promise<string | NoteWriteBackResult | void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a link is created in a connected source channel.\n * Requires `link: true` in Plot options.\n *\n * @param link - The newly created link\n * @param notes - Notes on the link's thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkCreated(link: Link, notes: Note[]): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a link in a connected source channel is updated.\n * Requires `link: true` in Plot options.\n *\n * @param link - The updated link\n * @param notes - Notes on the link's thread (optional)\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkUpdated(link: Link, notes?: Note[]): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Called when a note is created on a thread with a link from a connected channel.\n * Requires `link: true` in Plot options.\n *\n * @param note - The newly created note\n * @param link - The link associated with the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkNoteCreated(note: Note, link: Link): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Waits for tool initialization to complete.\n * Called automatically by the entrypoint before lifecycle methods.\n * @internal\n */\n async waitForReady(): Promise<void> {\n await this.toolShed.waitForReady();\n }\n}\n";
|
package/src/plot.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ThreadFacets } from "./facets";
|
|
1
2
|
import type { NewSchedule, NewScheduleOccurrence, Schedule } from "./schedule";
|
|
2
3
|
import { type Tag } from "./tag";
|
|
3
4
|
import { type Callback } from "./tools/callbacks";
|
|
@@ -21,7 +22,7 @@ export { type AuthProvider } from "./tools/integrations";
|
|
|
21
22
|
* - **Required fields**: No `?`, cannot be `undefined`
|
|
22
23
|
* - Example: `id: Uuid`, `title: string`
|
|
23
24
|
* - **Nullable fields**: Use `| null` to allow explicit clearing
|
|
24
|
-
* - Example: `
|
|
25
|
+
* - Example: `key: string | null`, `status: string | null`
|
|
25
26
|
* - `null` = field is explicitly unset/cleared
|
|
26
27
|
* - Non-null value = field has a value
|
|
27
28
|
* - **Optional nullable fields**: Use `?` with `| null` for permission-based access
|
|
@@ -68,9 +69,9 @@ export { type AuthProvider } from "./tools/integrations";
|
|
|
68
69
|
* Represents a unique user, contact, or twist in Plot.
|
|
69
70
|
*
|
|
70
71
|
* ActorIds are used throughout Plot for:
|
|
71
|
-
* -
|
|
72
|
-
* - Tag creators (actor_id in
|
|
73
|
-
* - Mentions in
|
|
72
|
+
* - Thread and note authors, link assignees
|
|
73
|
+
* - Tag creators (actor_id in thread_tag/note_tag)
|
|
74
|
+
* - Mentions in notes
|
|
74
75
|
* - Any entity that can perform actions in Plot
|
|
75
76
|
*/
|
|
76
77
|
export type ActorId = string & { readonly __brand: "ActorId" };
|
|
@@ -100,7 +101,7 @@ export enum ThemeColor {
|
|
|
100
101
|
/**
|
|
101
102
|
* Represents a focus within Plot.
|
|
102
103
|
*
|
|
103
|
-
* A focus is similar to a project or area-of-life.
|
|
104
|
+
* A focus is similar to a project or area-of-life. Every thread is in a focus.
|
|
104
105
|
* Focuses are flat — they have no parent and no children. Threads not matched
|
|
105
106
|
* to any focus live in the Inbox.
|
|
106
107
|
*/
|
|
@@ -402,8 +403,8 @@ export type NewTags = { [K in Tag]?: NewActor[] };
|
|
|
402
403
|
* Anything matching a known provider prefix is treated as a custom-emoji
|
|
403
404
|
* reference; everything else is rendered as the Unicode it contains.
|
|
404
405
|
*
|
|
405
|
-
* Reactions are the open-set
|
|
406
|
-
* (`1000+`). Use reactions for emoji that round-trip with chat platforms;
|
|
406
|
+
* Reactions are the open-set replacement for {@link Tag}'s retired count
|
|
407
|
+
* range (`1000+`). Use reactions for emoji that round-trip with chat platforms;
|
|
407
408
|
* use tags for Plot-managed compute/toggle state (todo, pinned, urgent,
|
|
408
409
|
* ...).
|
|
409
410
|
*/
|
|
@@ -921,7 +922,7 @@ export enum ActorType {
|
|
|
921
922
|
* Represents contact information for creating a new contact.
|
|
922
923
|
*
|
|
923
924
|
* Contacts are used throughout Plot for representing people associated
|
|
924
|
-
* with
|
|
925
|
+
* with threads, such as event attendees or task assignees.
|
|
925
926
|
*
|
|
926
927
|
* @example
|
|
927
928
|
* ```typescript
|
|
@@ -1069,6 +1070,12 @@ export type NewLink = Partial<
|
|
|
1069
1070
|
* thread that includes `icaluid:<uid>` in its own `sources`.
|
|
1070
1071
|
*/
|
|
1071
1072
|
sources?: string[];
|
|
1073
|
+
/**
|
|
1074
|
+
* Heuristic facets describing this item (format / automation / reach),
|
|
1075
|
+
* used as internal classifier signal. Omit a dimension (or set null) when
|
|
1076
|
+
* no heuristic is confident. See `@plotday/twister/facets`.
|
|
1077
|
+
*/
|
|
1078
|
+
facets?: ThreadFacets;
|
|
1072
1079
|
/** The person that created the item. By default, it will be the twist itself. */
|
|
1073
1080
|
author?: NewActor;
|
|
1074
1081
|
/** The person assigned to the item. */
|
package/src/tool.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
export type { ToolBuilder };
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Abstract parent for both built-in tools and regular Tools.
|
|
17
17
|
* Regular tools extend Tool.
|
|
18
18
|
*/
|
|
19
19
|
export abstract class ITool {}
|
|
@@ -194,8 +194,8 @@ export abstract class Tool<TSelf> implements ITool {
|
|
|
194
194
|
* await this.set("handler_token", token);
|
|
195
195
|
*
|
|
196
196
|
* // Later, execute the callback
|
|
197
|
-
* const token = await this.get<
|
|
198
|
-
* await this.run(token
|
|
197
|
+
* const token = await this.get<Callback>("handler_token");
|
|
198
|
+
* await this.run(token);
|
|
199
199
|
* ```
|
|
200
200
|
*
|
|
201
201
|
* @template T - The type of value being stored (must be Serializable)
|
|
@@ -257,7 +257,7 @@ export abstract class Tool<TSelf> implements ITool {
|
|
|
257
257
|
* @example
|
|
258
258
|
* ```typescript
|
|
259
259
|
* // Break large loop into batches
|
|
260
|
-
* const callback = await this.callback(
|
|
260
|
+
* const callback = await this.callback(this.processBatch, 1);
|
|
261
261
|
* await this.runTask(callback); // New execution with fresh request limit
|
|
262
262
|
* ```
|
|
263
263
|
*/
|
package/src/tools/ai.ts
CHANGED
|
@@ -21,12 +21,11 @@ import { ITool } from "..";
|
|
|
21
21
|
* ```typescript
|
|
22
22
|
* import { Type } from "typebox";
|
|
23
23
|
*
|
|
24
|
-
* class SmartEmailTool extends Tool {
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* this.ai = tools.get(AI);
|
|
24
|
+
* class SmartEmailTool extends Tool<SmartEmailTool> {
|
|
25
|
+
* build(build: ToolBuilder) {
|
|
26
|
+
* return {
|
|
27
|
+
* ai: build(AI),
|
|
28
|
+
* };
|
|
30
29
|
* }
|
|
31
30
|
*
|
|
32
31
|
* async categorizeEmail(emailContent: string) {
|
|
@@ -42,7 +41,7 @@ import { ITool } from "..";
|
|
|
42
41
|
* reasoning: Type.Optional(Type.String())
|
|
43
42
|
* });
|
|
44
43
|
*
|
|
45
|
-
* const response = await this.ai.prompt({
|
|
44
|
+
* const response = await this.tools.ai.prompt({
|
|
46
45
|
* model: { speed: "fast", cost: "medium" },
|
|
47
46
|
* system: "Classify emails into categories: work, personal, spam, or promotional.",
|
|
48
47
|
* prompt: `Categorize this email: ${emailContent}`,
|
|
@@ -53,7 +52,7 @@ import { ITool } from "..";
|
|
|
53
52
|
* }
|
|
54
53
|
*
|
|
55
54
|
* async generateResponse(emailContent: string) {
|
|
56
|
-
* const response = await this.ai.prompt({
|
|
55
|
+
* const response = await this.tools.ai.prompt({
|
|
57
56
|
* model: { speed: "fast", cost: "medium" },
|
|
58
57
|
* system: "Generate professional email responses that are helpful and concise.",
|
|
59
58
|
* prompt: `Write a response to: ${emailContent}`
|
|
@@ -67,7 +66,7 @@ import { ITool } from "..";
|
|
|
67
66
|
export abstract class AI extends ITool {
|
|
68
67
|
/**
|
|
69
68
|
* Returns which AI capabilities are currently available.
|
|
70
|
-
* Check this before calling prompt()
|
|
69
|
+
* Check this before calling prompt() to gracefully
|
|
71
70
|
* handle cases where AI is disabled by the user.
|
|
72
71
|
*
|
|
73
72
|
* Built-in tools are accessed as RPC stubs, so from a twist this call
|
|
@@ -195,7 +194,7 @@ export type AICapabilities = {
|
|
|
195
194
|
* prompt: "Analyze this data..."
|
|
196
195
|
* });
|
|
197
196
|
*
|
|
198
|
-
* // Most capable - uses Claude Sonnet 4.
|
|
197
|
+
* // Most capable - uses models like GPT-5, Claude Sonnet 4.6, or Gemini 2.5 Pro
|
|
199
198
|
* const response = await ai.prompt({
|
|
200
199
|
* model: { speed: "capable", cost: "high" },
|
|
201
200
|
* prompt: "Solve this complex reasoning problem..."
|
|
@@ -203,7 +202,7 @@ export type AICapabilities = {
|
|
|
203
202
|
*
|
|
204
203
|
* // Request a specific model with a hint
|
|
205
204
|
* const response = await ai.prompt({
|
|
206
|
-
* model: { speed: "balanced", cost: "medium", hint: AIModel.
|
|
205
|
+
* model: { speed: "balanced", cost: "medium", hint: AIModel.CLAUDE_SONNET_46 },
|
|
207
206
|
* prompt: "..."
|
|
208
207
|
* });
|
|
209
208
|
* ```
|
|
@@ -238,7 +237,7 @@ export type ModelPreferences = {
|
|
|
238
237
|
* Models are organized by provider:
|
|
239
238
|
* - **OpenAI**: Latest GPT models via AI Gateway
|
|
240
239
|
* - **Anthropic**: Claude models via AI Gateway (prefix with "anthropic/")
|
|
241
|
-
* - **Google**: Gemini models via AI Gateway (prefix with "google
|
|
240
|
+
* - **Google**: Gemini models via AI Gateway (prefix with "google/")
|
|
242
241
|
* - **Workers AI**: Models running on Cloudflare's network (free/low cost)
|
|
243
242
|
*/
|
|
244
243
|
export enum AIModel {
|
|
@@ -513,7 +512,7 @@ export type AIUsage = {
|
|
|
513
512
|
*/
|
|
514
513
|
outputTokens?: number;
|
|
515
514
|
/**
|
|
516
|
-
* The total number of tokens used (
|
|
515
|
+
* The total number of tokens used (inputTokens + outputTokens).
|
|
517
516
|
*/
|
|
518
517
|
totalTokens?: number;
|
|
519
518
|
/**
|
package/src/tools/callbacks.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { Serializable } from "../utils/types";
|
|
|
7
7
|
* Callbacks enable tools and twists to create persistent references to functions
|
|
8
8
|
* that can survive worker restarts and be invoked across different execution contexts.
|
|
9
9
|
*
|
|
10
|
-
* This is a branded
|
|
10
|
+
* This is a branded string
|
|
11
11
|
* type to prevent mixing callback tokens with regular strings.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
package/src/tools/files.ts
CHANGED
|
@@ -14,8 +14,8 @@ import { ITool } from "..";
|
|
|
14
14
|
*/
|
|
15
15
|
export abstract class Files extends ITool {
|
|
16
16
|
/**
|
|
17
|
-
* Read a file uploaded by a client and attached to a note
|
|
18
|
-
*
|
|
17
|
+
* Read a file uploaded by a client and attached to a note on a thread
|
|
18
|
+
* in one of the twist owner's focuses.
|
|
19
19
|
*
|
|
20
20
|
* @param fileId The id from an ActionType.file action.
|
|
21
21
|
* @returns Bytes plus original metadata.
|
package/src/tools/imap.ts
CHANGED
|
@@ -129,7 +129,7 @@ export type ImapFlagOperation = "add" | "remove" | "set";
|
|
|
129
129
|
* @example
|
|
130
130
|
* ```typescript
|
|
131
131
|
* class AppleMailConnector extends Connector<AppleMailConnector> {
|
|
132
|
-
* build(build:
|
|
132
|
+
* build(build: ToolBuilder) {
|
|
133
133
|
* return {
|
|
134
134
|
* options: build(Options, {
|
|
135
135
|
* email: { type: "text", label: "Apple ID Email", default: "" },
|
|
@@ -685,8 +685,9 @@ export type AuthToken = {
|
|
|
685
685
|
*
|
|
686
686
|
* For Slack (AuthProvider.Slack):
|
|
687
687
|
* - authed_user_id: The authenticated user's Slack ID
|
|
688
|
-
* -
|
|
688
|
+
* - team_id: The Slack workspace/team ID
|
|
689
689
|
* - team_name: The Slack workspace/team name
|
|
690
|
+
* - enterprise_id: The Enterprise Grid org ID (when applicable)
|
|
690
691
|
*/
|
|
691
692
|
provider?: Record<string, string>;
|
|
692
693
|
};
|
package/src/tools/network.ts
CHANGED
|
@@ -233,9 +233,9 @@ export abstract class Network extends ITool {
|
|
|
233
233
|
* Deletes an existing webhook endpoint.
|
|
234
234
|
*
|
|
235
235
|
* Removes the webhook endpoint and stops processing requests.
|
|
236
|
-
* Works with all webhook types (standard, Slack, and
|
|
236
|
+
* Works with all webhook types (standard, Slack, and Pub/Sub).
|
|
237
237
|
*
|
|
238
|
-
* **For Gmail
|
|
238
|
+
* **For Pub/Sub webhooks (Gmail and Workspace Events):** Also deletes the associated Google Pub/Sub topic and subscription.
|
|
239
239
|
*
|
|
240
240
|
* **For Slack webhooks:** Removes the callback registration for the specific team.
|
|
241
241
|
*
|
|
@@ -243,9 +243,9 @@ export abstract class Network extends ITool {
|
|
|
243
243
|
* to the deleted webhook will return 404.
|
|
244
244
|
*
|
|
245
245
|
* @param url - The webhook identifier returned from `createWebhook()`.
|
|
246
|
-
* This can be a URL (standard webhooks), a Pub/Sub topic name
|
|
247
|
-
* or an opaque identifier (Slack).
|
|
248
|
-
* from `createWebhook()`.
|
|
246
|
+
* This can be a URL (standard webhooks), a Pub/Sub topic name
|
|
247
|
+
* (Gmail/Workspace Events), or an opaque identifier (Slack).
|
|
248
|
+
* Always pass the exact value returned from `createWebhook()`.
|
|
249
249
|
* @returns Promise that resolves when the webhook is deleted
|
|
250
250
|
*/
|
|
251
251
|
abstract deleteWebhook(url: string): Promise<void>;
|
package/src/tools/plot.ts
CHANGED
|
@@ -146,22 +146,26 @@ export type SearchOptions = {
|
|
|
146
146
|
*
|
|
147
147
|
* @example
|
|
148
148
|
* ```typescript
|
|
149
|
-
* class MyTwist extends Twist {
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
149
|
+
* class MyTwist extends Twist<MyTwist> {
|
|
150
|
+
* build(build: ToolBuilder) {
|
|
151
|
+
* return {
|
|
152
|
+
* plot: build(Plot, {
|
|
153
|
+
* thread: { access: ThreadAccess.Create },
|
|
154
|
+
* }),
|
|
155
|
+
* };
|
|
155
156
|
* }
|
|
156
157
|
*
|
|
157
158
|
* async activate() {
|
|
158
|
-
* // Create a welcome thread
|
|
159
|
-
* await this.plot.createThread({
|
|
159
|
+
* // Create a welcome thread with an opening note
|
|
160
|
+
* await this.tools.plot.createThread({
|
|
160
161
|
* title: "Welcome to Plot!",
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
162
|
+
* notes: [{
|
|
163
|
+
* content: "Get started with Plot:",
|
|
164
|
+
* actions: [{
|
|
165
|
+
* type: ActionType.external,
|
|
166
|
+
* title: "Get Started",
|
|
167
|
+
* url: "https://plot.day/docs"
|
|
168
|
+
* }]
|
|
165
169
|
* }]
|
|
166
170
|
* });
|
|
167
171
|
* }
|
|
@@ -330,8 +334,9 @@ export abstract class Plot extends ITool {
|
|
|
330
334
|
* remain unchanged. This enables partial updates without needing to fetch and resend
|
|
331
335
|
* the entire thread object.
|
|
332
336
|
*
|
|
333
|
-
* For
|
|
334
|
-
*
|
|
337
|
+
* For the twist's own tags, use `twistTags`: a record mapping tag ID to a
|
|
338
|
+
* boolean, where true adds the tag and false removes it. Tags not included
|
|
339
|
+
* in the update remain unchanged.
|
|
335
340
|
*
|
|
336
341
|
* Set `focus` to move the thread to a different focus.
|
|
337
342
|
*
|
|
@@ -343,18 +348,18 @@ export abstract class Plot extends ITool {
|
|
|
343
348
|
*
|
|
344
349
|
* @example
|
|
345
350
|
* ```typescript
|
|
346
|
-
* //
|
|
347
|
-
* await this.plot.updateThread({
|
|
348
|
-
* id:
|
|
349
|
-
*
|
|
351
|
+
* // Archive a thread
|
|
352
|
+
* await this.tools.plot.updateThread({
|
|
353
|
+
* id: threadId,
|
|
354
|
+
* archived: true
|
|
350
355
|
* });
|
|
351
356
|
*
|
|
352
|
-
* // Add and remove tags
|
|
353
|
-
* await this.plot.updateThread({
|
|
354
|
-
* id:
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
357
|
+
* // Add and remove the twist's tags
|
|
358
|
+
* await this.tools.plot.updateThread({
|
|
359
|
+
* id: threadId,
|
|
360
|
+
* twistTags: {
|
|
361
|
+
* [Tag.Todo]: true, // Add the to-do tag
|
|
362
|
+
* [Tag.Done]: false // Remove the done tag
|
|
358
363
|
* }
|
|
359
364
|
* });
|
|
360
365
|
* ```
|
|
@@ -388,16 +393,16 @@ export abstract class Plot extends ITool {
|
|
|
388
393
|
* @example
|
|
389
394
|
* ```typescript
|
|
390
395
|
* // Create a note with content
|
|
391
|
-
* await this.plot.createNote({
|
|
396
|
+
* await this.tools.plot.createNote({
|
|
392
397
|
* thread: { id: "thread-123" },
|
|
393
|
-
*
|
|
398
|
+
* content: "Discussion notes from the meeting...",
|
|
394
399
|
* contentType: "markdown"
|
|
395
400
|
* });
|
|
396
401
|
*
|
|
397
402
|
* // Create a note with actions
|
|
398
|
-
* await this.plot.createNote({
|
|
403
|
+
* await this.tools.plot.createNote({
|
|
399
404
|
* thread: { id: "thread-456" },
|
|
400
|
-
*
|
|
405
|
+
* content: "Meeting recording available",
|
|
401
406
|
* actions: [{
|
|
402
407
|
* type: ActionType.external,
|
|
403
408
|
* title: "View Recording",
|
|
@@ -422,14 +427,14 @@ export abstract class Plot extends ITool {
|
|
|
422
427
|
* @example
|
|
423
428
|
* ```typescript
|
|
424
429
|
* // Create multiple notes in one batch
|
|
425
|
-
* await this.plot.createNotes([
|
|
430
|
+
* await this.tools.plot.createNotes([
|
|
426
431
|
* {
|
|
427
432
|
* thread: { id: "thread-123" },
|
|
428
|
-
*
|
|
433
|
+
* content: "First message in thread"
|
|
429
434
|
* },
|
|
430
435
|
* {
|
|
431
436
|
* thread: { id: "thread-123" },
|
|
432
|
-
*
|
|
437
|
+
* content: "Second message in thread"
|
|
433
438
|
* }
|
|
434
439
|
* ]);
|
|
435
440
|
* ```
|
|
@@ -454,16 +459,16 @@ export abstract class Plot extends ITool {
|
|
|
454
459
|
* @example
|
|
455
460
|
* ```typescript
|
|
456
461
|
* // Update note content
|
|
457
|
-
* await this.plot.updateNote({
|
|
462
|
+
* await this.tools.plot.updateNote({
|
|
458
463
|
* id: "note-123",
|
|
459
|
-
*
|
|
464
|
+
* content: "Updated content with more details"
|
|
460
465
|
* });
|
|
461
466
|
*
|
|
462
467
|
* // Add tags to a note
|
|
463
|
-
* await this.plot.updateNote({
|
|
468
|
+
* await this.tools.plot.updateNote({
|
|
464
469
|
* id: "note-456",
|
|
465
470
|
* twistTags: {
|
|
466
|
-
* [Tag.
|
|
471
|
+
* [Tag.Todo]: true
|
|
467
472
|
* }
|
|
468
473
|
* });
|
|
469
474
|
* ```
|
|
@@ -573,10 +578,10 @@ export abstract class Plot extends ITool {
|
|
|
573
578
|
* @example
|
|
574
579
|
* ```typescript
|
|
575
580
|
* // Schedule a timed event
|
|
576
|
-
* const threadId = await this.plot.createThread({
|
|
581
|
+
* const threadId = await this.tools.plot.createThread({
|
|
577
582
|
* title: "Team standup"
|
|
578
583
|
* });
|
|
579
|
-
* await this.plot.createSchedule({
|
|
584
|
+
* await this.tools.plot.createSchedule({
|
|
580
585
|
* threadId,
|
|
581
586
|
* start: new Date("2025-01-15T10:00:00Z"),
|
|
582
587
|
* end: new Date("2025-01-15T10:30:00Z"),
|
package/src/tools/smtp.ts
CHANGED
|
@@ -76,7 +76,7 @@ export type SmtpSendResult = {
|
|
|
76
76
|
* @example
|
|
77
77
|
* ```typescript
|
|
78
78
|
* class AppleMailConnector extends Connector<AppleMailConnector> {
|
|
79
|
-
* build(build:
|
|
79
|
+
* build(build: ToolBuilder) {
|
|
80
80
|
* return {
|
|
81
81
|
* options: build(Options, {
|
|
82
82
|
* email: { type: "text", label: "Apple ID Email", default: "" },
|
package/src/tools/tasks.ts
CHANGED
|
@@ -30,18 +30,18 @@ import type { Callback } from "./callbacks";
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```typescript
|
|
33
|
-
* class SyncTool extends Tool {
|
|
33
|
+
* class SyncTool extends Tool<SyncTool> {
|
|
34
34
|
* async startBatchSync(totalItems: number) {
|
|
35
35
|
* // Store initial state using built-in set method
|
|
36
36
|
* await this.set("sync_progress", { processed: 0, total: totalItems });
|
|
37
37
|
*
|
|
38
38
|
* // Create callback and queue first batch
|
|
39
|
-
* const callback = await this.callback(
|
|
39
|
+
* const callback = await this.callback(this.processBatch, 1);
|
|
40
40
|
* // runTask creates NEW execution with fresh ~1000 request limit
|
|
41
41
|
* await this.runTask(callback);
|
|
42
42
|
* }
|
|
43
43
|
*
|
|
44
|
-
* async processBatch(
|
|
44
|
+
* async processBatch(batchNumber: number) {
|
|
45
45
|
* // Process one batch of items (sized to stay under request limit)
|
|
46
46
|
* const progress = await this.get("sync_progress");
|
|
47
47
|
*
|
|
@@ -61,9 +61,7 @@ import type { Callback } from "./callbacks";
|
|
|
61
61
|
*
|
|
62
62
|
* if (progress.processed < progress.total) {
|
|
63
63
|
* // Queue next batch - creates NEW execution with fresh request limit
|
|
64
|
-
* const callback = await this.callback(
|
|
65
|
-
* batchNumber: context.batchNumber + 1
|
|
66
|
-
* });
|
|
64
|
+
* const callback = await this.callback(this.processBatch, batchNumber + 1);
|
|
67
65
|
* await this.runTask(callback);
|
|
68
66
|
* }
|
|
69
67
|
* }
|
|
@@ -72,7 +70,7 @@ import type { Callback } from "./callbacks";
|
|
|
72
70
|
* const tomorrow = new Date();
|
|
73
71
|
* tomorrow.setDate(tomorrow.getDate() + 1);
|
|
74
72
|
*
|
|
75
|
-
* const callback = await this.callback(
|
|
73
|
+
* const callback = await this.callback(this.cleanupOldData);
|
|
76
74
|
* // Schedule for future execution
|
|
77
75
|
* return await this.runTask(callback, { runAt: tomorrow });
|
|
78
76
|
* }
|
|
@@ -103,7 +101,7 @@ export abstract class Tasks extends ITool {
|
|
|
103
101
|
* @example
|
|
104
102
|
* ```typescript
|
|
105
103
|
* // Break large loop into batches to stay under request limit
|
|
106
|
-
* const callback = await this.callback(
|
|
104
|
+
* const callback = await this.callback(this.syncBatch, 1);
|
|
107
105
|
* await this.runTask(callback); // Fresh execution with ~1000 requests
|
|
108
106
|
* ```
|
|
109
107
|
*/
|
package/src/tools/twists.ts
CHANGED
|
@@ -61,10 +61,10 @@ export type TwistPermissions = Record<string, Record<string, string[]>>;
|
|
|
61
61
|
*
|
|
62
62
|
* @example
|
|
63
63
|
* ```typescript
|
|
64
|
-
* class TwistBuilderTwist extends Twist {
|
|
64
|
+
* class TwistBuilderTwist extends Twist<TwistBuilderTwist> {
|
|
65
65
|
* build(build: ToolBuilder) {
|
|
66
66
|
* return {
|
|
67
|
-
* twists: build
|
|
67
|
+
* twists: build(Twists)
|
|
68
68
|
* }
|
|
69
69
|
* }
|
|
70
70
|
*
|
|
@@ -77,14 +77,15 @@ export type TwistPermissions = Record<string, Record<string, string[]>>;
|
|
|
77
77
|
*/
|
|
78
78
|
export abstract class Twists extends ITool {
|
|
79
79
|
/**
|
|
80
|
-
* Creates a new twist ID
|
|
80
|
+
* Creates a new twist package ID. Ownership of the ID is claimed lazily
|
|
81
|
+
* on first deploy — no upfront registration happens beyond generating it.
|
|
81
82
|
*
|
|
82
83
|
* @returns Promise resolving to the generated twist ID
|
|
83
84
|
* @throws When twist creation fails
|
|
84
85
|
*
|
|
85
86
|
* @example
|
|
86
87
|
* ```typescript
|
|
87
|
-
* const twistId = await
|
|
88
|
+
* const twistId = await this.tools.twists.create();
|
|
88
89
|
* console.log(`Your twist ID: ${twistId}`);
|
|
89
90
|
* ```
|
|
90
91
|
*/
|
|
@@ -103,15 +104,15 @@ export abstract class Twists extends ITool {
|
|
|
103
104
|
*
|
|
104
105
|
* @example
|
|
105
106
|
* ```typescript
|
|
106
|
-
* const source = await
|
|
107
|
+
* const source = await this.tools.twists.generate(`
|
|
107
108
|
* # Calendar Sync Twist
|
|
108
109
|
*
|
|
109
|
-
* This twist syncs Google Calendar events to Plot
|
|
110
|
+
* This twist syncs Google Calendar events to Plot threads.
|
|
110
111
|
*
|
|
111
112
|
* ## Features
|
|
112
113
|
* - Authenticate with Google
|
|
113
114
|
* - Sync calendar events
|
|
114
|
-
* - Create
|
|
115
|
+
* - Create threads from events
|
|
115
116
|
* `);
|
|
116
117
|
*
|
|
117
118
|
* // source.dependencies: { "@plotday/twister": "workspace:^", ... }
|
|
@@ -143,7 +144,7 @@ export abstract class Twists extends ITool {
|
|
|
143
144
|
* @example
|
|
144
145
|
* ```typescript
|
|
145
146
|
* // Deploy with a module
|
|
146
|
-
* const result = await
|
|
147
|
+
* const result = await this.tools.twists.deploy({
|
|
147
148
|
* twistId: 'abc-123-...',
|
|
148
149
|
* module: 'export default class MyTwist extends Twist {...}',
|
|
149
150
|
* environment: 'personal',
|
|
@@ -153,8 +154,8 @@ export abstract class Twists extends ITool {
|
|
|
153
154
|
* console.log(`Deployed version ${result.version}`);
|
|
154
155
|
*
|
|
155
156
|
* // Deploy with source
|
|
156
|
-
* const source = await
|
|
157
|
-
* const result = await
|
|
157
|
+
* const source = await this.tools.twists.generate(spec);
|
|
158
|
+
* const result = await this.tools.twists.deploy({
|
|
158
159
|
* twistId: 'abc-123-...',
|
|
159
160
|
* source,
|
|
160
161
|
* environment: 'personal',
|
|
@@ -162,7 +163,7 @@ export abstract class Twists extends ITool {
|
|
|
162
163
|
* });
|
|
163
164
|
*
|
|
164
165
|
* // Validate with dryRun
|
|
165
|
-
* const result = await
|
|
166
|
+
* const result = await this.tools.twists.deploy({
|
|
166
167
|
* twistId: 'abc-123-...',
|
|
167
168
|
* source,
|
|
168
169
|
* dryRun: true,
|
|
@@ -209,11 +210,11 @@ export abstract class Twists extends ITool {
|
|
|
209
210
|
* @example
|
|
210
211
|
* ```typescript
|
|
211
212
|
* // Create twist and callback
|
|
212
|
-
* const twistId = await this.
|
|
213
|
-
* const callback = await this.callback.
|
|
213
|
+
* const twistId = await this.tools.twists.create();
|
|
214
|
+
* const callback = await this.callback(this.onLogs);
|
|
214
215
|
*
|
|
215
216
|
* // Subscribe to logs
|
|
216
|
-
* await this.
|
|
217
|
+
* await this.tools.twists.watchLogs(twistId, callback);
|
|
217
218
|
*
|
|
218
219
|
* // Implement handler
|
|
219
220
|
* async onLogs(logs: Log[]) {
|
package/src/twist.ts
CHANGED
|
@@ -225,8 +225,8 @@ export abstract class Twist<TSelf> {
|
|
|
225
225
|
* await this.set("handler_token", token);
|
|
226
226
|
*
|
|
227
227
|
* // Later, execute the callback
|
|
228
|
-
* const token = await this.get<
|
|
229
|
-
* await this.run(token
|
|
228
|
+
* const token = await this.get<Callback>("handler_token");
|
|
229
|
+
* await this.run(token);
|
|
230
230
|
* ```
|
|
231
231
|
*
|
|
232
232
|
* @template T - The type of value being stored (must be Serializable)
|