@plotday/twister 0.53.0 → 0.54.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/dist/connector.d.ts +19 -4
- package/dist/connector.d.ts.map +1 -1
- 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 +25 -25
- package/dist/docs/classes/index.FileNotFoundError.html +1 -1
- package/dist/docs/classes/index.Files.html +2 -2
- package/dist/docs/classes/index.Imap.html +1 -1
- package/dist/docs/classes/index.Options.html +1 -1
- package/dist/docs/classes/index.Smtp.html +1 -1
- package/dist/docs/classes/tools_ai.AI.html +7 -5
- package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
- package/dist/docs/classes/tools_integrations.Integrations.html +11 -11
- package/dist/docs/classes/tools_network.Network.html +1 -1
- package/dist/docs/classes/tools_plot.Plot.html +62 -56
- package/dist/docs/classes/tools_store.Store.html +1 -1
- package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
- package/dist/docs/classes/tools_twists.Twists.html +2 -2
- package/dist/docs/classes/twist.Twist.html +3 -3
- 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 +1 -1
- package/dist/docs/enums/tools_ai.AIModel.html +2 -2
- package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
- package/dist/docs/enums/{tools_plot.PriorityAccess.html → tools_plot.FocusAccess.html} +6 -6
- package/dist/docs/enums/tools_plot.ThreadAccess.html +1 -1
- package/dist/docs/hierarchy.html +1 -1
- package/dist/docs/interfaces/tools_ai.AIRequest.html +27 -11
- 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/media/AGENTS.md +1 -1
- package/dist/docs/modules/index.html +1 -1
- package/dist/docs/modules/plot.html +1 -1
- package/dist/docs/modules/tools_plot.html +1 -1
- package/dist/docs/types/index.CreateLinkDraft.html +14 -13
- package/dist/docs/types/index.ResolvedRecipient.html +13 -2
- package/dist/docs/types/index.Schedule.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.Contact.html +4 -4
- package/dist/docs/types/plot.ContentType.html +1 -1
- package/dist/docs/types/plot.Focus.html +18 -0
- package/dist/docs/types/plot.FocusUpdate.html +3 -0
- package/dist/docs/types/plot.Link.html +16 -16
- 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 +13 -0
- package/dist/docs/types/plot.NewLink.html +6 -6
- package/dist/docs/types/plot.NewLinkWithNotes.html +1 -1
- package/dist/docs/types/plot.NewNote.html +2 -2
- 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 +4 -4
- package/dist/docs/types/plot.NewThreadWithNotes.html +1 -1
- package/dist/docs/types/plot.Note.html +2 -2
- package/dist/docs/types/plot.NoteUpdate.html +1 -1
- package/dist/docs/types/plot.PlanOperation.html +6 -6
- package/dist/docs/types/plot.Reaction.html +1 -1
- 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 +3 -3
- 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 +4 -4
- 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 +7 -3
- 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 +10 -9
- 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 +4 -4
- package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
- package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
- package/dist/docs/types/tools_integrations.Authorization.html +4 -4
- 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 +14 -23
- package/dist/docs/types/tools_integrations.SyncContext.html +3 -3
- package/dist/docs/types/tools_plot.SearchOptions.html +5 -6
- package/dist/docs/types/tools_twists.TwistPermissions.html +1 -1
- 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/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/schedule.d.ts +1 -1
- package/dist/llm-docs/schedule.d.ts.map +1 -1
- package/dist/llm-docs/schedule.js +1 -1
- package/dist/llm-docs/schedule.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/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/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/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/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.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 +62 -82
- package/dist/plot.d.ts.map +1 -1
- package/dist/plot.js +1 -1
- package/dist/plot.js.map +1 -1
- package/dist/schedule.d.ts +1 -1
- package/dist/tools/ai.d.ts +46 -10
- package/dist/tools/ai.d.ts.map +1 -1
- package/dist/tools/ai.js.map +1 -1
- package/dist/tools/files.d.ts +1 -1
- package/dist/tools/integrations.d.ts +7 -23
- package/dist/tools/integrations.d.ts.map +1 -1
- package/dist/tools/integrations.js.map +1 -1
- package/dist/tools/plot.d.ts +66 -56
- package/dist/tools/plot.d.ts.map +1 -1
- package/dist/tools/plot.js +14 -14
- package/dist/tools/plot.js.map +1 -1
- package/dist/tools/twists.d.ts +2 -2
- package/dist/twist.d.ts +3 -3
- package/dist/twist.js +3 -3
- package/package.json +1 -1
- package/src/connector.ts +19 -4
- package/src/llm-docs/connector.ts +1 -1
- package/src/llm-docs/plot.ts +1 -1
- package/src/llm-docs/schedule.ts +1 -1
- package/src/llm-docs/tools/ai.ts +1 -1
- package/src/llm-docs/tools/files.ts +1 -1
- package/src/llm-docs/tools/integrations.ts +1 -1
- package/src/llm-docs/tools/plot.ts +1 -1
- package/src/llm-docs/tools/twists.ts +1 -1
- package/src/llm-docs/twist.ts +1 -1
- package/src/plot.ts +63 -72
- package/src/schedule.ts +1 -1
- package/src/tools/ai.ts +46 -10
- package/src/tools/files.ts +1 -1
- package/src/tools/integrations.ts +7 -23
- package/src/tools/plot.ts +69 -59
- package/src/tools/twists.ts +2 -2
- package/src/twist.ts +3 -3
- package/dist/docs/types/plot.NewPriority.html +0 -15
- package/dist/docs/types/plot.Priority.html +0 -15
- package/dist/docs/types/plot.PriorityUpdate.html +0 -5
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* Generated from: prebuild.ts
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export default "import {\n type Action,\n type Thread,\n type ThreadUpdate,\n type Actor,\n type ActorId,\n ITool,\n type Link,\n type LinkUpdate,\n type NewThread,\n type NewThreadWithNotes,\n type NewNote,\n type NewPriority,\n type Note,\n type NoteUpdate,\n type PlanOperation,\n type Priority,\n type PriorityUpdate,\n Uuid,\n} from \"..\";\nimport {\n type Schedule,\n type NewSchedule,\n} from \"../schedule\";\nimport type { Callback } from \"./callbacks\";\n\nexport enum ThreadAccess {\n /**\n * Create new Note on a Thread where the twist was mentioned.\n * Add/remove tags on Thread or Note where the twist was mentioned.\n */\n Respond,\n /**\n * Create new Thread.\n * Create new Note in a Thread the twist created.\n * All Respond permissions.\n */\n Create,\n /**\n * List/query all Threads owned by the twist's user.\n * Update any Thread (title, tags, archived, type, priority) regardless of creator.\n * Create Notes on any Thread (not just own or mentioned).\n * All Create permissions.\n */\n Full,\n}\n\nexport enum PriorityAccess {\n /**\n * Create new Priorities under the twist owner's priority tree.\n * Update Priorities created by the twist.\n */\n Create,\n /**\n * Read all Priorities owned by the twist's user.\n * Create new Priorities under the twist owner's priority tree.\n * Update and archive any Priority owned by the twist's user.\n */\n Full,\n}\n\nexport enum ContactAccess {\n /** Read existing contact details. Without this, only the ID will be provided. */\n Read,\n}\n\nexport enum LinkAccess {\n /** Read links on any thread owned by the twist's user. */\n Read,\n /** Read + update links, including moving links between threads owned by the twist's user. */\n Full,\n}\n\n/**\n * Intent handler for thread mentions.\n * Defines how the twist should respond when mentioned in a thread.\n */\nexport type NoteIntentHandler = {\n /** Human-readable description of what this intent handles */\n description: string;\n /** Example phrases or activity content that would match this intent */\n examples: string[];\n /** The function to call when this intent is matched */\n handler: (note: Note) => Promise<void>;\n};\n\n/**\n * Filter for querying links from connected source channels.\n */\nexport type LinkFilter = {\n /** Only return links from these channel IDs. */\n channelIds?: string[];\n /** Only return links created/updated after this date. */\n since?: Date;\n /** Only return links of this type. */\n type?: string;\n /** Maximum number of links to return. */\n limit?: number;\n};\n\ntype SearchResultBase = {\n thread: { id: string; title: string | null };\n priority: { id: string; title: string | null };\n similarity: number;\n};\n\nexport type NoteSearchResult = SearchResultBase & {\n type: 'note';\n id: string;\n content: string | null;\n};\n\nexport type LinkSearchResult = SearchResultBase & {\n type: 'link';\n id: string;\n title: string | null;\n sourceUrl: string | null;\n content: string | null;\n};\n\nexport type SearchResult = NoteSearchResult | LinkSearchResult;\n\n/** Default number of search results returned */\nexport const SEARCH_DEFAULT_LIMIT = 10;\n/** Maximum number of search results allowed */\nexport const SEARCH_MAX_LIMIT = 30;\n\nexport type SearchOptions = {\n /** Max results to return (default: 10, max: 30) */\n limit?: number;\n /** Minimum similarity score 0-1 (default: 0.3) */\n threshold?: number;\n /**\n * Scope search to this priority + descendants. Must be owned by the twist\n * owner. When omitted, the server scopes the search to the owner's entire\n * priority tree.\n */\n priorityId?: string;\n};\n\n/**\n * Built-in tool for interacting with the core Plot data layer.\n *\n * The Plot tool provides twists with the ability to create and manage threads,\n * priorities, and contacts within the Plot system. This is the primary interface\n * for twists to persist data and interact with the Plot database.\n *\n * @example\n * ```typescript\n * class MyTwist extends Twist {\n * private plot: Plot;\n *\n * constructor(id: string, tools: ToolBuilder) {\n * super();\n * this.plot = tools.get(Plot);\n * }\n *\n * async activate() {\n * // Create a welcome thread\n * await this.plot.createThread({\n * title: \"Welcome to Plot!\",\n * actions: [{\n * title: \"Get Started\",\n * type: ActionType.external,\n * url: \"https://plot.day/docs\"\n * }]\n * });\n * }\n * }\n * ```\n */\nexport abstract class Plot extends ITool {\n /**\n * Configuration options for the Plot tool.\n *\n * **Important**: All permissions must be explicitly requested. There are no default permissions.\n *\n * @example\n * ```typescript\n * // Minimal configuration with required permissions\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot, {\n * thread: {\n * access: ThreadAccess.Create\n * }\n * })\n * };\n * }\n *\n * // Full configuration with callbacks\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot, {\n * thread: {\n * access: ThreadAccess.Create,\n * },\n * note: {\n * intents: [{\n * description: \"Schedule meetings\",\n * examples: [\"Schedule a meeting tomorrow\"],\n * handler: this.onSchedulingIntent\n * }],\n * },\n * link: true,\n * priority: {\n * access: PriorityAccess.Full\n * },\n * contact: {\n * access: ContactAccess.Read\n * }\n * })\n * };\n * }\n * ```\n */\n static readonly Options: {\n thread?: {\n /**\n * Capability to create Notes and modify tags.\n * Must be explicitly set to grant permissions.\n */\n access?: ThreadAccess;\n /** When true, auto-mention this twist on new notes in threads where it authored content. */\n defaultMention?: boolean;\n };\n note?: {\n /** When true, auto-mention this twist on new notes in threads where it was @-mentioned. */\n defaultMention?: boolean;\n /**\n * Respond to mentions in notes.\n *\n * When a note mentions this twist, the system will match the note\n * content against these intents and call the matching handler.\n *\n * @example\n * ```typescript\n * intents: [{\n * description: \"Schedule or reschedule calendar events\",\n * examples: [\"Schedule a meeting tomorrow at 2pm\", \"Move my 3pm meeting to 4pm\"],\n * handler: this.onSchedulingRequest\n * }, {\n * description: \"Find available meeting times\",\n * examples: [\"When am I free this week?\", \"Find time for a 1 hour meeting\"],\n * handler: this.onAvailabilityRequest\n * }]\n * ```\n */\n intents?: NoteIntentHandler[];\n };\n /** Enable link processing from connected source channels. */\n link?: true | {\n /** Access level for links. When omitted with `link: true`, only source channel links are accessible. */\n access?: LinkAccess;\n };\n priority?: {\n access?: PriorityAccess;\n };\n contact?: {\n access?: ContactAccess;\n };\n /** Enable semantic search across notes and links owned by the twist's user. */\n search?: true;\n /**\n * When true, admin write operations (on threads/notes/links/priorities not created by this twist)\n * require user approval via plan actions instead of executing immediately.\n * Read operations and operations on the twist's own content still work directly.\n */\n requireApproval?: boolean;\n };\n\n /**\n * Creates a new thread in the Plot system.\n *\n * The thread will be automatically assigned an ID and author information\n * based on the current execution context. All other fields from NewThread\n * will be preserved in the created thread.\n *\n * @param thread - The thread data to create\n * @returns Promise resolving to the created thread's ID\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createThread(\n thread: NewThread | NewThreadWithNotes\n ): Promise<Uuid>;\n\n /**\n * Creates multiple threads in a single batch operation.\n *\n * This method efficiently creates multiple threads at once, which is\n * more performant than calling createThread() multiple times individually.\n * All threads are created with the same author and access control rules.\n *\n * @param threads - Array of thread data to create\n * @returns Promise resolving to array of created thread IDs\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createThreads(\n threads: (NewThread | NewThreadWithNotes)[]\n ): Promise<Uuid[]>;\n\n /**\n * Updates an existing thread in the Plot system.\n *\n * **Important**: This method only updates existing threads. It will throw an error\n * if the thread does not exist. Use `createThread()` to create or update (upsert)\n * threads.\n *\n * Only the fields provided in the update object will be modified - all other fields\n * remain unchanged. This enables partial updates without needing to fetch and resend\n * the entire thread object.\n *\n * For tags, provide a Record<number, boolean> where true adds a tag and false removes it.\n * Tags not included in the update remain unchanged.\n *\n * When updating the parent, the thread's path will be automatically recalculated to\n * maintain the correct hierarchical structure.\n *\n * Scheduling is handled separately via `createSchedule()` / `updateSchedule()`.\n *\n * @param thread - The thread update containing the ID or source and fields to change\n * @returns Promise that resolves when the update is complete\n * @throws Error if the thread does not exist\n *\n * @example\n * ```typescript\n * // Mark a task as complete\n * await this.plot.updateThread({\n * id: \"task-123\",\n * done: new Date()\n * });\n *\n * // Add and remove tags\n * await this.plot.updateThread({\n * id: \"thread-789\",\n * tags: {\n * 1: true, // Add tag with ID 1\n * 2: false // Remove tag with ID 2\n * }\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateThread(thread: ThreadUpdate): Promise<void>;\n\n /**\n * Retrieves all notes within a thread.\n *\n * Notes are detailed entries within a thread, ordered by creation time.\n * Each note can contain markdown content, actions, and other detailed information\n * related to the parent thread.\n *\n * @param thread - The thread whose notes to retrieve\n * @returns Promise resolving to array of notes in the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getNotes(thread: Thread): Promise<Note[]>;\n\n /**\n * Creates a new note in a thread.\n *\n * Notes provide detailed content within a thread, supporting markdown,\n * actions, and other rich content. The note will be automatically assigned\n * an ID and author information based on the current execution context.\n *\n * @param note - The note data to create\n * @returns Promise resolving to the created note's ID\n *\n * @example\n * ```typescript\n * // Create a note with content\n * await this.plot.createNote({\n * thread: { id: \"thread-123\" },\n * note: \"Discussion notes from the meeting...\",\n * contentType: \"markdown\"\n * });\n *\n * // Create a note with actions\n * await this.plot.createNote({\n * thread: { id: \"thread-456\" },\n * note: \"Meeting recording available\",\n * actions: [{\n * type: ActionType.external,\n * title: \"View Recording\",\n * url: \"https://example.com/recording\"\n * }]\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createNote(note: NewNote): Promise<Uuid>;\n\n /**\n * Creates multiple notes in a single batch operation.\n *\n * This method efficiently creates multiple notes at once, which is\n * more performant than calling createNote() multiple times individually.\n * All notes are created with the same author and access control rules.\n *\n * @param notes - Array of note data to create\n * @returns Promise resolving to array of created note IDs\n *\n * @example\n * ```typescript\n * // Create multiple notes in one batch\n * await this.plot.createNotes([\n * {\n * thread: { id: \"thread-123\" },\n * note: \"First message in thread\"\n * },\n * {\n * thread: { id: \"thread-123\" },\n * note: \"Second message in thread\"\n * }\n * ]);\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createNotes(notes: NewNote[]): Promise<Uuid[]>;\n\n /**\n * Updates an existing note in the Plot system.\n *\n * **Important**: This method only updates existing notes. It will throw an error\n * if the note does not exist. Use `createNote()` to create or update (upsert) notes.\n *\n * Only the fields provided in the update object will be modified - all other fields\n * remain unchanged. This enables partial updates without needing to fetch and resend\n * the entire note object.\n *\n * @param note - The note update containing the ID or key and fields to change\n * @returns Promise that resolves when the update is complete\n * @throws Error if the note does not exist\n *\n * @example\n * ```typescript\n * // Update note content\n * await this.plot.updateNote({\n * id: \"note-123\",\n * note: \"Updated content with more details\"\n * });\n *\n * // Add tags to a note\n * await this.plot.updateNote({\n * id: \"note-456\",\n * twistTags: {\n * [Tag.Important]: true\n * }\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateNote(note: NoteUpdate): Promise<void>;\n\n /**\n * Retrieves a thread by ID or source.\n *\n * This method enables lookup of threads either by their unique ID or by their\n * source identifier (canonical URL from an external system). Archived threads\n * are included in the results.\n *\n * @param thread - Thread lookup by ID or source\n * @returns Promise resolving to the matching thread or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getThread(\n thread: { id: Uuid } | { source: string }\n ): Promise<Thread | null>;\n\n /**\n * Retrieves a note by ID or key.\n *\n * This method enables lookup of notes either by their unique ID or by their\n * key (unique identifier within the thread). Archived notes are included\n * in the results.\n *\n * @param note - Note lookup by ID or key\n * @returns Promise resolving to the matching note or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getNote(note: { id: Uuid } | { key: string }): Promise<Note | null>;\n\n /**\n * Creates a new priority in the Plot system.\n *\n * Priorities serve as organizational containers for threads and twists.\n * The created priority will be automatically assigned a unique ID.\n *\n * @param priority - The priority data to create\n * @returns Promise resolving to the complete created priority\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createPriority(priority: NewPriority): Promise<Priority & { created: boolean }>;\n\n /**\n * Retrieves a priority by ID or key.\n *\n * Archived priorities are included in the results.\n *\n * @param priority - Priority lookup by ID or key\n * @returns Promise resolving to the matching priority or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getPriority(\n priority: { id: Uuid } | { key: string }\n ): Promise<Priority | null>;\n\n /**\n * Updates an existing priority in the Plot system.\n *\n * The priority is identified by either its ID or key.\n * Only the fields specified in the update will be changed.\n *\n * @param update - Priority update containing ID/key and fields to change\n * @returns Promise that resolves when the update is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updatePriority(update: PriorityUpdate): Promise<void>;\n\n /**\n * Retrieves actors by their IDs.\n *\n * Actors represent users, contacts, or twists in the Plot system.\n * This method requires ContactAccess.Read permission.\n *\n * @param ids - Array of actor IDs to retrieve\n * @returns Promise resolving to array of actors\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getActors(ids: ActorId[]): Promise<Actor[]>;\n\n /**\n * Returns the full Actor for the user who installed this twist.\n * Useful for per-user operations like schedule creation, or when\n * the owner's name or email is needed.\n */\n abstract getOwner(): Promise<Actor>;\n\n /**\n * Returns the user ID (`twist_instance.owner_id`) that installed this\n * twist. This is the same value exposed on Twist via `this.userId`.\n */\n abstract getUserId(): Promise<string>;\n\n /**\n * Creates a new schedule for a thread.\n *\n * Schedules define when a thread occurs in time. A thread can have\n * multiple schedules (shared and per-user).\n *\n * @param schedule - The schedule data to create\n * @returns Promise resolving to the created schedule\n *\n * @example\n * ```typescript\n * // Schedule a timed event\n * const threadId = await this.plot.createThread({\n * title: \"Team standup\"\n * });\n * await this.plot.createSchedule({\n * threadId,\n * start: new Date(\"2025-01-15T10:00:00Z\"),\n * end: new Date(\"2025-01-15T10:30:00Z\"),\n * recurrenceRule: \"FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR\"\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createSchedule(schedule: NewSchedule): Promise<Schedule>;\n\n /**\n * Retrieves all schedules for a thread.\n *\n * @param threadId - The thread whose schedules to retrieve\n * @returns Promise resolving to array of schedules for the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getSchedules(threadId: Uuid): Promise<Schedule[]>;\n\n /**\n * Retrieves links from connected source channels.\n *\n * Requires `link: true` in Plot options.\n *\n * @param filter - Optional filter criteria for links\n * @returns Promise resolving to array of links with their notes\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getLinks(filter?: LinkFilter): Promise<Array<{ link: Link; notes: Note[] }>>;\n\n /**\n * Searches notes and links using semantic similarity.\n *\n * Requires `search: true` in Plot options.\n *\n * @param query - The search query text\n * @param options - Optional search configuration\n * @returns Promise resolving to array of search results ordered by similarity\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract search(query: string, options?: SearchOptions): Promise<SearchResult[]>;\n\n /**\n * Lists threads owned by the twist's user.\n *\n * Requires `ThreadAccess.Full`.\n *\n * @param options - Query options for filtering threads\n * @returns Promise resolving to array of threads\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getThreads(options?: {\n /**\n * Priority to list threads from. Must be owned by the twist owner.\n * When omitted, defaults to the owner's root priority.\n */\n priorityId?: Uuid;\n /** Include threads from descendant priorities. Default: true. */\n includeDescendants?: boolean;\n /** Include archived threads. Default: false. */\n includeArchived?: boolean;\n /** Maximum number of threads to return. Default: 50, max: 200. */\n limit?: number;\n /** Number of threads to skip for pagination. Default: 0. */\n offset?: number;\n }): Promise<Thread[]>;\n\n /**\n * Lists priorities owned by the twist's user.\n *\n * Requires `PriorityAccess.Full`.\n *\n * @param options - Query options for filtering priorities\n * @returns Promise resolving to array of priorities\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getPriorities(options?: {\n /**\n * Parent priority to list children of. Must be owned by the twist\n * owner. When omitted, defaults to the owner's root priority.\n */\n parentId?: Uuid;\n /** Include all descendants, not just direct children. Default: false. */\n includeDescendants?: boolean;\n /** Include archived priorities. Default: false. */\n includeArchived?: boolean;\n }): Promise<Priority[]>;\n\n /**\n * Updates a link.\n *\n * Requires `LinkAccess.Full`. Set `threadId` to move the link to a different thread.\n *\n * @param link - The link update containing the ID and fields to change\n * @returns Promise that resolves when the update is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateLink(link: LinkUpdate): Promise<void>;\n\n /**\n * Creates a plan of operations for user approval.\n *\n * Returns an Action that can be attached to a note. The user can approve,\n * deny, or request changes. On approval, operations are executed by the API.\n *\n * Requires `requireApproval: true` in Plot options.\n *\n * @param options - Plan configuration\n * @returns An Action of type `plan` to attach to a note\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createPlan(options: {\n /** Human-readable title summarizing the plan */\n title: string;\n /** Array of operations to execute on approval */\n operations: PlanOperation[];\n /** Callback invoked with (action, approved: boolean) when the user responds */\n callback: Callback;\n }): Action;\n}\n";
|
|
8
|
+
export default "import {\n type Action,\n type Thread,\n type ThreadUpdate,\n type Actor,\n type ActorId,\n ITool,\n type Link,\n type LinkUpdate,\n type NewThread,\n type NewThreadWithNotes,\n type NewNote,\n type NewFocus,\n type Note,\n type NoteUpdate,\n type PlanOperation,\n type Focus,\n type FocusUpdate,\n Uuid,\n} from \"..\";\nimport {\n type Schedule,\n type NewSchedule,\n} from \"../schedule\";\nimport type { Callback } from \"./callbacks\";\n\nexport enum ThreadAccess {\n /**\n * Create new Note on a Thread where the twist was mentioned.\n * Add/remove tags on Thread or Note where the twist was mentioned.\n */\n Respond,\n /**\n * Create new Thread.\n * Create new Note in a Thread the twist created.\n * All Respond permissions.\n */\n Create,\n /**\n * List/query all Threads owned by the twist's user.\n * Update any Thread (title, tags, archived, type, focus) regardless of creator.\n * Create Notes on any Thread (not just own or mentioned).\n * All Create permissions.\n */\n Full,\n}\n\nexport enum FocusAccess {\n /**\n * Create new Focuses for the twist owner.\n * Update Focuses created by the twist.\n */\n Create,\n /**\n * Read all Focuses owned by the twist's user.\n * Create new Focuses for the twist owner.\n * Update and archive any Focus owned by the twist's user.\n */\n Full,\n}\n\nexport enum ContactAccess {\n /** Read existing contact details. Without this, only the ID will be provided. */\n Read,\n}\n\nexport enum LinkAccess {\n /** Read links on any thread owned by the twist's user. */\n Read,\n /** Read + update links, including moving links between threads owned by the twist's user. */\n Full,\n}\n\n/**\n * Intent handler for thread mentions.\n * Defines how the twist should respond when mentioned in a thread.\n */\nexport type NoteIntentHandler = {\n /** Human-readable description of what this intent handles */\n description: string;\n /** Example phrases or activity content that would match this intent */\n examples: string[];\n /** The function to call when this intent is matched */\n handler: (note: Note) => Promise<void>;\n};\n\n/**\n * Filter for querying links from connected source channels.\n */\nexport type LinkFilter = {\n /** Only return links from these channel IDs. */\n channelIds?: string[];\n /** Only return links created/updated after this date. */\n since?: Date;\n /** Only return links of this type. */\n type?: string;\n /** Maximum number of links to return. */\n limit?: number;\n};\n\ntype SearchResultBase = {\n thread: { id: string; title: string | null };\n focus: { id: string; title: string | null };\n similarity: number;\n};\n\nexport type NoteSearchResult = SearchResultBase & {\n type: 'note';\n id: string;\n content: string | null;\n};\n\nexport type LinkSearchResult = SearchResultBase & {\n type: 'link';\n id: string;\n title: string | null;\n sourceUrl: string | null;\n content: string | null;\n};\n\nexport type SearchResult = NoteSearchResult | LinkSearchResult;\n\n/** Default number of search results returned */\nexport const SEARCH_DEFAULT_LIMIT = 10;\n/** Maximum number of search results allowed */\nexport const SEARCH_MAX_LIMIT = 30;\n\nexport type SearchOptions = {\n /** Max results to return (default: 10, max: 30) */\n limit?: number;\n /** Minimum similarity score 0-1 (default: 0.3) */\n threshold?: number;\n /**\n * Scope search to this focus. Must be owned by the twist owner. When\n * omitted, the server scopes the search across all of the owner's focuses.\n */\n focusId?: string;\n};\n\n/**\n * Built-in tool for interacting with the core Plot data layer.\n *\n * The Plot tool provides twists with the ability to create and manage threads,\n * focuses, and contacts within the Plot system. This is the primary interface\n * for twists to persist data and interact with the Plot database.\n *\n * @example\n * ```typescript\n * class MyTwist extends Twist {\n * private plot: Plot;\n *\n * constructor(id: string, tools: ToolBuilder) {\n * super();\n * this.plot = tools.get(Plot);\n * }\n *\n * async activate() {\n * // Create a welcome thread\n * await this.plot.createThread({\n * title: \"Welcome to Plot!\",\n * actions: [{\n * title: \"Get Started\",\n * type: ActionType.external,\n * url: \"https://plot.day/docs\"\n * }]\n * });\n * }\n * }\n * ```\n */\nexport abstract class Plot extends ITool {\n /**\n * Configuration options for the Plot tool.\n *\n * **Important**: All permissions must be explicitly requested. There are no default permissions.\n *\n * @example\n * ```typescript\n * // Minimal configuration with required permissions\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot, {\n * thread: {\n * access: ThreadAccess.Create\n * }\n * })\n * };\n * }\n *\n * // Full configuration with callbacks\n * build(build: ToolBuilder) {\n * return {\n * plot: build(Plot, {\n * thread: {\n * access: ThreadAccess.Create,\n * },\n * note: {\n * intents: [{\n * description: \"Schedule meetings\",\n * examples: [\"Schedule a meeting tomorrow\"],\n * handler: this.onSchedulingIntent\n * }],\n * },\n * link: true,\n * focus: {\n * access: FocusAccess.Full\n * },\n * contact: {\n * access: ContactAccess.Read\n * }\n * })\n * };\n * }\n * ```\n */\n static readonly Options: {\n thread?: {\n /**\n * Capability to create Notes and modify tags.\n * Must be explicitly set to grant permissions.\n */\n access?: ThreadAccess;\n /** When true, auto-mention this twist on new notes in threads where it authored content. */\n defaultMention?: boolean;\n };\n note?: {\n /** When true, auto-mention this twist on new notes in threads where it was @-mentioned. */\n defaultMention?: boolean;\n /**\n * Respond to mentions in notes.\n *\n * When a note mentions this twist, the system will match the note\n * content against these intents and call the matching handler.\n *\n * @example\n * ```typescript\n * intents: [{\n * description: \"Schedule or reschedule calendar events\",\n * examples: [\"Schedule a meeting tomorrow at 2pm\", \"Move my 3pm meeting to 4pm\"],\n * handler: this.onSchedulingRequest\n * }, {\n * description: \"Find available meeting times\",\n * examples: [\"When am I free this week?\", \"Find time for a 1 hour meeting\"],\n * handler: this.onAvailabilityRequest\n * }]\n * ```\n */\n intents?: NoteIntentHandler[];\n /**\n * Single conversational handler for mentions.\n *\n * When set, EVERY mention of this twist is routed directly to this\n * handler — intent matching (and the built-in \"What can you do?\" /\n * \"Remove yourself\" intents) is skipped. Use this to build a\n * general-purpose conversational assistant that responds to any\n * request, rather than classifying into a fixed set of `intents`.\n *\n * `handler` and `intents` are mutually exclusive; when both are\n * present, `handler` takes precedence and `intents` is ignored.\n *\n * @example\n * ```typescript\n * note: {\n * defaultMention: true,\n * handler: this.respond, // (note: Note) => Promise<void>\n * }\n * ```\n */\n handler?: (note: Note) => Promise<void>;\n };\n /** Enable link processing from connected source channels. */\n link?: true | {\n /** Access level for links. When omitted with `link: true`, only source channel links are accessible. */\n access?: LinkAccess;\n };\n focus?: {\n access?: FocusAccess;\n };\n contact?: {\n access?: ContactAccess;\n };\n /** Enable semantic search across notes and links owned by the twist's user. */\n search?: true;\n /**\n * When true, admin write operations (on threads/notes/links/focuses not created by this twist)\n * require user approval via plan actions instead of executing immediately.\n * Read operations and operations on the twist's own content still work directly.\n */\n requireApproval?: boolean;\n };\n\n /**\n * Creates a new thread in the Plot system.\n *\n * The thread will be automatically assigned an ID and author information\n * based on the current execution context. All other fields from NewThread\n * will be preserved in the created thread.\n *\n * @param thread - The thread data to create\n * @returns Promise resolving to the created thread's ID\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createThread(\n thread: NewThread | NewThreadWithNotes\n ): Promise<Uuid>;\n\n /**\n * Creates multiple threads in a single batch operation.\n *\n * This method efficiently creates multiple threads at once, which is\n * more performant than calling createThread() multiple times individually.\n * All threads are created with the same author and access control rules.\n *\n * @param threads - Array of thread data to create\n * @returns Promise resolving to array of created thread IDs\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createThreads(\n threads: (NewThread | NewThreadWithNotes)[]\n ): Promise<Uuid[]>;\n\n /**\n * Updates an existing thread in the Plot system.\n *\n * **Important**: This method only updates existing threads. It will throw an error\n * if the thread does not exist. Use `createThread()` to create or update (upsert)\n * threads.\n *\n * Only the fields provided in the update object will be modified - all other fields\n * remain unchanged. This enables partial updates without needing to fetch and resend\n * the entire thread object.\n *\n * For tags, provide a Record<number, boolean> where true adds a tag and false removes it.\n * Tags not included in the update remain unchanged.\n *\n * Set `focus` to move the thread to a different focus.\n *\n * Scheduling is handled separately via `createSchedule()` / `updateSchedule()`.\n *\n * @param thread - The thread update containing the ID or source and fields to change\n * @returns Promise that resolves when the update is complete\n * @throws Error if the thread does not exist\n *\n * @example\n * ```typescript\n * // Mark a task as complete\n * await this.plot.updateThread({\n * id: \"task-123\",\n * done: new Date()\n * });\n *\n * // Add and remove tags\n * await this.plot.updateThread({\n * id: \"thread-789\",\n * tags: {\n * 1: true, // Add tag with ID 1\n * 2: false // Remove tag with ID 2\n * }\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateThread(thread: ThreadUpdate): Promise<void>;\n\n /**\n * Retrieves all notes within a thread.\n *\n * Notes are detailed entries within a thread, ordered by creation time.\n * Each note can contain markdown content, actions, and other detailed information\n * related to the parent thread.\n *\n * @param thread - The thread whose notes to retrieve\n * @returns Promise resolving to array of notes in the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getNotes(thread: Thread): Promise<Note[]>;\n\n /**\n * Creates a new note in a thread.\n *\n * Notes provide detailed content within a thread, supporting markdown,\n * actions, and other rich content. The note will be automatically assigned\n * an ID and author information based on the current execution context.\n *\n * @param note - The note data to create\n * @returns Promise resolving to the created note's ID\n *\n * @example\n * ```typescript\n * // Create a note with content\n * await this.plot.createNote({\n * thread: { id: \"thread-123\" },\n * note: \"Discussion notes from the meeting...\",\n * contentType: \"markdown\"\n * });\n *\n * // Create a note with actions\n * await this.plot.createNote({\n * thread: { id: \"thread-456\" },\n * note: \"Meeting recording available\",\n * actions: [{\n * type: ActionType.external,\n * title: \"View Recording\",\n * url: \"https://example.com/recording\"\n * }]\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createNote(note: NewNote): Promise<Uuid>;\n\n /**\n * Creates multiple notes in a single batch operation.\n *\n * This method efficiently creates multiple notes at once, which is\n * more performant than calling createNote() multiple times individually.\n * All notes are created with the same author and access control rules.\n *\n * @param notes - Array of note data to create\n * @returns Promise resolving to array of created note IDs\n *\n * @example\n * ```typescript\n * // Create multiple notes in one batch\n * await this.plot.createNotes([\n * {\n * thread: { id: \"thread-123\" },\n * note: \"First message in thread\"\n * },\n * {\n * thread: { id: \"thread-123\" },\n * note: \"Second message in thread\"\n * }\n * ]);\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createNotes(notes: NewNote[]): Promise<Uuid[]>;\n\n /**\n * Updates an existing note in the Plot system.\n *\n * **Important**: This method only updates existing notes. It will throw an error\n * if the note does not exist. Use `createNote()` to create or update (upsert) notes.\n *\n * Only the fields provided in the update object will be modified - all other fields\n * remain unchanged. This enables partial updates without needing to fetch and resend\n * the entire note object.\n *\n * @param note - The note update containing the ID or key and fields to change\n * @returns Promise that resolves when the update is complete\n * @throws Error if the note does not exist\n *\n * @example\n * ```typescript\n * // Update note content\n * await this.plot.updateNote({\n * id: \"note-123\",\n * note: \"Updated content with more details\"\n * });\n *\n * // Add tags to a note\n * await this.plot.updateNote({\n * id: \"note-456\",\n * twistTags: {\n * [Tag.Important]: true\n * }\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateNote(note: NoteUpdate): Promise<void>;\n\n /**\n * Retrieves a thread by ID or source.\n *\n * This method enables lookup of threads either by their unique ID or by their\n * source identifier (canonical URL from an external system). Archived threads\n * are included in the results.\n *\n * @param thread - Thread lookup by ID or source\n * @returns Promise resolving to the matching thread or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getThread(\n thread: { id: Uuid } | { source: string }\n ): Promise<Thread | null>;\n\n /**\n * Retrieves a note by ID or key.\n *\n * This method enables lookup of notes either by their unique ID or by their\n * key (unique identifier within the thread). Archived notes are included\n * in the results.\n *\n * @param note - Note lookup by ID or key\n * @returns Promise resolving to the matching note or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getNote(note: { id: Uuid } | { key: string }): Promise<Note | null>;\n\n /**\n * Creates a new focus in the Plot system.\n *\n * Focuses serve as organizational containers for threads and twists.\n * The created focus will be automatically assigned a unique ID.\n *\n * @param focus - The focus data to create\n * @returns Promise resolving to the complete created focus\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createFocus(focus: NewFocus): Promise<Focus & { created: boolean }>;\n\n /**\n * Retrieves a focus by ID or key.\n *\n * Archived focuses are included in the results.\n *\n * @param focus - Focus lookup by ID or key\n * @returns Promise resolving to the matching focus or null if not found\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getFocus(\n focus: { id: Uuid } | { key: string }\n ): Promise<Focus | null>;\n\n /**\n * Updates an existing focus in the Plot system.\n *\n * The focus is identified by either its ID or key.\n * Only the fields specified in the update will be changed.\n *\n * @param update - Focus update containing ID/key and fields to change\n * @returns Promise that resolves when the update is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateFocus(update: FocusUpdate): Promise<void>;\n\n /**\n * Retrieves actors by their IDs.\n *\n * Actors represent users, contacts, or twists in the Plot system.\n * This method requires ContactAccess.Read permission.\n *\n * @param ids - Array of actor IDs to retrieve\n * @returns Promise resolving to array of actors\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getActors(ids: ActorId[]): Promise<Actor[]>;\n\n /**\n * Returns the full Actor for the user who installed this twist.\n * Useful for per-user operations like schedule creation, or when\n * the owner's name or email is needed.\n */\n abstract getOwner(): Promise<Actor>;\n\n /**\n * Returns the user ID (`twist_instance.owner_id`) that installed this\n * twist. This is the same value exposed on Twist via `this.userId`.\n */\n abstract getUserId(): Promise<string>;\n\n /**\n * Creates a new schedule for a thread.\n *\n * Schedules define when a thread occurs in time. A thread can have\n * multiple schedules (shared and per-user).\n *\n * @param schedule - The schedule data to create\n * @returns Promise resolving to the created schedule\n *\n * @example\n * ```typescript\n * // Schedule a timed event\n * const threadId = await this.plot.createThread({\n * title: \"Team standup\"\n * });\n * await this.plot.createSchedule({\n * threadId,\n * start: new Date(\"2025-01-15T10:00:00Z\"),\n * end: new Date(\"2025-01-15T10:30:00Z\"),\n * recurrenceRule: \"FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR\"\n * });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createSchedule(schedule: NewSchedule): Promise<Schedule>;\n\n /**\n * Retrieves all schedules for a thread.\n *\n * @param threadId - The thread whose schedules to retrieve\n * @returns Promise resolving to array of schedules for the thread\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getSchedules(threadId: Uuid): Promise<Schedule[]>;\n\n /**\n * Retrieves links from connected source channels.\n *\n * Requires `link: true` in Plot options.\n *\n * @param filter - Optional filter criteria for links\n * @returns Promise resolving to array of links with their notes\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getLinks(filter?: LinkFilter): Promise<Array<{ link: Link; notes: Note[] }>>;\n\n /**\n * Searches notes and links using semantic similarity.\n *\n * Requires `search: true` in Plot options.\n *\n * @param query - The search query text\n * @param options - Optional search configuration\n * @returns Promise resolving to array of search results ordered by similarity\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract search(query: string, options?: SearchOptions): Promise<SearchResult[]>;\n\n /**\n * Lists threads owned by the twist's user.\n *\n * Requires `ThreadAccess.Full`.\n *\n * @param options - Query options for filtering threads\n * @returns Promise resolving to array of threads\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getThreads(options?: {\n /**\n * Focus to list threads from. Must be owned by the twist owner.\n * When omitted, defaults to the owner's Inbox.\n */\n focusId?: Uuid;\n /** Include archived threads. Default: false. */\n includeArchived?: boolean;\n /** Maximum number of threads to return. Default: 50, max: 200. */\n limit?: number;\n /** Number of threads to skip for pagination. Default: 0. */\n offset?: number;\n }): Promise<Thread[]>;\n\n /**\n * Lists focuses owned by the twist's user.\n *\n * Requires `FocusAccess.Full`.\n *\n * @param options - Query options for filtering focuses\n * @returns Promise resolving to array of focuses\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract getFocuses(options?: {\n /** Include archived focuses. Default: false. */\n includeArchived?: boolean;\n }): Promise<Focus[]>;\n\n /**\n * Updates a link.\n *\n * Requires `LinkAccess.Full`. Set `threadId` to move the link to a different thread.\n *\n * @param link - The link update containing the ID and fields to change\n * @returns Promise that resolves when the update is complete\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract updateLink(link: LinkUpdate): Promise<void>;\n\n /**\n * Creates a plan of operations for user approval.\n *\n * Returns an Action that can be attached to a note. The user can approve,\n * deny, or request changes. On approval, operations are executed by the API.\n *\n * Requires `requireApproval: true` in Plot options.\n *\n * @param options - Plan configuration\n * @returns An Action of type `plan` to attach to a note\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract createPlan(options: {\n /** Human-readable title summarizing the plan */\n title: string;\n /** Array of operations to execute on approval */\n operations: PlanOperation[];\n /** Callback invoked with (action, approved: boolean) when the user responds */\n callback: Callback;\n }): Action;\n}\n";
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* Generated from: prebuild.ts
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export default "import { type Callback, ITool } from \"..\";\n\n/**\n * Twist source code structure containing dependencies and source files.\n */\nexport interface TwistSource {\n /**\n * Package dependencies with version specifiers\n * @example { \"@plotday/twister\": \"workspace:^\", \"@plotday/tool-google-calendar\": \"^1.0.0\" }\n */\n dependencies: Record<string, string>;\n\n /**\n * Source files with their content\n * Must include \"index.ts\" as the entry point\n * @example { \"index.ts\": \"export default class MyTwist extends Twist {...}\" }\n */\n files: Record<string, string>;\n}\n\n/**\n * Represents a log entry from a twist execution.\n */\nexport type Log = {\n timestamp: Date;\n environment: \"personal\" | \"private\" | \"review\" | \"public\";\n severity: \"log\" | \"error\" | \"warn\" | \"info\";\n message: string;\n};\n\n/**\n * Twist permissions returned after deployment.\n * Nested structure mapping domains to entities to permission flags.\n *\n * Format: { domain: { entity: flags[] } }\n * - domain: Tool name (e.g., \"network\", \"plot\")\n * - entity: Domain-specific identifier (e.g., URL pattern, resource type)\n * - flags: Array of permission flags (\"read\", \"write\", \"update\", \"use\")\n *\n * @example\n * ```typescript\n * {\n * \"network\": {\n * \"https://api.example.com/*\": [\"use\"],\n * \"https://googleapis.com/*\": [\"use\"]\n * },\n * \"plot\": {\n * \"thread:mentioned\": [\"read\", \"write\", \"update\"],\n * \"
|
|
8
|
+
export default "import { type Callback, ITool } from \"..\";\n\n/**\n * Twist source code structure containing dependencies and source files.\n */\nexport interface TwistSource {\n /**\n * Package dependencies with version specifiers\n * @example { \"@plotday/twister\": \"workspace:^\", \"@plotday/tool-google-calendar\": \"^1.0.0\" }\n */\n dependencies: Record<string, string>;\n\n /**\n * Source files with their content\n * Must include \"index.ts\" as the entry point\n * @example { \"index.ts\": \"export default class MyTwist extends Twist {...}\" }\n */\n files: Record<string, string>;\n}\n\n/**\n * Represents a log entry from a twist execution.\n */\nexport type Log = {\n timestamp: Date;\n environment: \"personal\" | \"private\" | \"review\" | \"public\";\n severity: \"log\" | \"error\" | \"warn\" | \"info\";\n message: string;\n};\n\n/**\n * Twist permissions returned after deployment.\n * Nested structure mapping domains to entities to permission flags.\n *\n * Format: { domain: { entity: flags[] } }\n * - domain: Tool name (e.g., \"network\", \"plot\")\n * - entity: Domain-specific identifier (e.g., URL pattern, resource type)\n * - flags: Array of permission flags (\"read\", \"write\", \"update\", \"use\")\n *\n * @example\n * ```typescript\n * {\n * \"network\": {\n * \"https://api.example.com/*\": [\"use\"],\n * \"https://googleapis.com/*\": [\"use\"]\n * },\n * \"plot\": {\n * \"thread:mentioned\": [\"read\", \"write\", \"update\"],\n * \"focus\": [\"read\", \"write\", \"update\"]\n * }\n * }\n * ```\n */\nexport type TwistPermissions = Record<string, Record<string, string[]>>;\n\n/**\n * Built-in tool for managing twists and deployments.\n *\n * The Twists tool provides twists with the ability to create twist IDs\n * and programmatically deploy twists.\n *\n * @example\n * ```typescript\n * class TwistBuilderTwist extends Twist {\n * build(build: ToolBuilder) {\n * return {\n * twists: build.get(Twists)\n * }\n * }\n *\n * async activate() {\n * const twistId = await this.tools.twists.create();\n * // Display twist ID to user\n * }\n * }\n * ```\n */\nexport abstract class Twists extends ITool {\n /**\n * Creates a new twist ID and grants access to people in the current focus.\n *\n * @returns Promise resolving to the generated twist ID\n * @throws When twist creation fails\n *\n * @example\n * ```typescript\n * const twistId = await twist.create();\n * console.log(`Your twist ID: ${twistId}`);\n * ```\n */\n abstract create(): Promise<string>;\n\n /**\n * Generates twist source code from a specification using AI.\n *\n * This method uses Claude AI to generate TypeScript source code and dependencies\n * from a markdown specification. The generated source is validated by attempting\n * to build it, with iterative error correction (up to 3 attempts).\n *\n * @param spec - Markdown specification describing the twist functionality\n * @returns Promise resolving to twist source (dependencies and files)\n * @throws When generation fails after maximum attempts\n *\n * @example\n * ```typescript\n * const source = await twist.generate(`\n * # Calendar Sync Twist\n *\n * This twist syncs Google Calendar events to Plot activities.\n *\n * ## Features\n * - Authenticate with Google\n * - Sync calendar events\n * - Create activities from events\n * `);\n *\n * // source.dependencies: { \"@plotday/twister\": \"workspace:^\", ... }\n * // source.files: { \"index.ts\": \"export default class...\" }\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract generate(spec: string): Promise<TwistSource>;\n\n /**\n * Deploys a twist programmatically.\n *\n * This method provides the same functionality as the plot deploy CLI\n * command, but can be called from within a twist. Accepts either:\n * - A pre-bundled module (JavaScript code)\n * - A source object (dependencies + files) which is built in a sandbox\n *\n * @param options - Deployment configuration\n * @param options.twistId - Twist ID for deployment\n * @param options.module - Pre-bundled twist module code (mutually exclusive with source)\n * @param options.source - Twist source code with dependencies (mutually exclusive with module)\n * @param options.environment - Target environment (defaults to \"personal\")\n * @param options.name - Optional twist name (required for first deploy)\n * @param options.description - Optional twist description (required for first deploy)\n * @param options.dryRun - If true, validates without deploying (returns errors if any)\n * @returns Promise resolving to deployment result with version and optional errors\n * @throws When deployment fails or user lacks access\n *\n * @example\n * ```typescript\n * // Deploy with a module\n * const result = await twist.deploy({\n * twistId: 'abc-123-...',\n * module: 'export default class MyTwist extends Twist {...}',\n * environment: 'personal',\n * name: 'My Twist',\n * description: 'Does something cool'\n * });\n * console.log(`Deployed version ${result.version}`);\n *\n * // Deploy with source\n * const source = await twist.generate(spec);\n * const result = await twist.deploy({\n * twistId: 'abc-123-...',\n * source,\n * environment: 'personal',\n * name: 'My Twist',\n * });\n *\n * // Validate with dryRun\n * const result = await twist.deploy({\n * twistId: 'abc-123-...',\n * source,\n * dryRun: true,\n * });\n * if (result.errors?.length) {\n * console.error('Build errors:', result.errors);\n * }\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract deploy(\n options: {\n twistId: string;\n environment?: \"personal\" | \"private\" | \"review\";\n name?: string;\n description?: string;\n dryRun?: boolean;\n } & (\n | {\n module: string;\n }\n | {\n source: TwistSource;\n }\n )\n ): Promise<{\n version: string;\n permissions: TwistPermissions;\n errors?: string[];\n }>;\n\n /**\n * Subscribes to logs from a twist.\n *\n * This method registers a callback to receive batches of logs from twist executions.\n * The callback will be invoked with an array of logs whenever new logs are captured\n * from the twist's console output.\n *\n * @param twistId - Twist ID (root ID) to watch logs for\n * @param callback - Callback token created via CallbackTool that will receive log batches\n * @returns Promise that resolves when the subscription is created\n * @throws When subscription fails\n *\n * @example\n * ```typescript\n * // Create twist and callback\n * const twistId = await this.twist.create();\n * const callback = await this.callback.create(\"onLogs\");\n *\n * // Subscribe to logs\n * await this.twist.watchLogs(twistId, callback);\n *\n * // Implement handler\n * async onLogs(logs: Log[]) {\n * for (const log of logs) {\n * console.log(`[${log.environment}] ${log.severity}: ${log.message}`);\n * }\n * }\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract watchLogs(twistId: string, callback: Callback): Promise<void>;\n}\n";
|
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 priority scope: threads, notes, and\n * links it creates are filed against the owner's priorities, with automatic\n * priority 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<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";
|
package/src/plot.ts
CHANGED
|
@@ -11,13 +11,13 @@ export { type AuthProvider } from "./tools/integrations";
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @fileoverview
|
|
14
|
-
* Core Plot entity types for working with threads, notes,
|
|
14
|
+
* Core Plot entity types for working with threads, notes, focuses, and contacts.
|
|
15
15
|
*
|
|
16
16
|
* ## Type Pattern: Null vs Undefined Semantics
|
|
17
17
|
*
|
|
18
18
|
* Plot entity types use a consistent pattern to distinguish between missing, unset, and explicitly cleared values:
|
|
19
19
|
*
|
|
20
|
-
* ### Entity Types (Thread,
|
|
20
|
+
* ### Entity Types (Thread, Focus, Note, Actor)
|
|
21
21
|
* - **Required fields**: No `?`, cannot be `undefined`
|
|
22
22
|
* - Example: `id: Uuid`, `title: string`
|
|
23
23
|
* - **Nullable fields**: Use `| null` to allow explicit clearing
|
|
@@ -30,10 +30,10 @@ export { type AuthProvider } from "./tools/integrations";
|
|
|
30
30
|
* - `null` = field included but not set
|
|
31
31
|
* - Value = field has a value
|
|
32
32
|
*
|
|
33
|
-
* ### New* Types (NewThread, NewNote,
|
|
33
|
+
* ### New* Types (NewThread, NewNote, NewFocus)
|
|
34
34
|
* Used for creating or updating entities. Support partial updates by distinguishing omitted vs cleared fields:
|
|
35
35
|
* - **Required fields**: Must be provided (no `?`)
|
|
36
|
-
* - Example: `title: string` in
|
|
36
|
+
* - Example: `title: string` in NewFocus
|
|
37
37
|
* - **Optional fields**: Use `?` to make them optional
|
|
38
38
|
* - Example: `title?: string`, `author?: NewActor`
|
|
39
39
|
* - `undefined` (omitted) = don't set/update this field
|
|
@@ -76,7 +76,7 @@ export { type AuthProvider } from "./tools/integrations";
|
|
|
76
76
|
export type ActorId = string & { readonly __brand: "ActorId" };
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Theme colors for
|
|
79
|
+
* Theme colors for focuses.
|
|
80
80
|
*/
|
|
81
81
|
export enum ThemeColor {
|
|
82
82
|
/** Catalyst - Green */
|
|
@@ -98,73 +98,67 @@ export enum ThemeColor {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Represents a
|
|
101
|
+
* Represents a focus within Plot.
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
103
|
+
* A focus is similar to a project or area-of-life. All Activity is in a Focus.
|
|
104
|
+
* Focuses are flat — they have no parent and no children. Threads not matched
|
|
105
|
+
* to any focus live in the Inbox.
|
|
105
106
|
*/
|
|
106
|
-
export type
|
|
107
|
-
/** Unique identifier for the
|
|
107
|
+
export type Focus = {
|
|
108
|
+
/** Unique identifier for the focus */
|
|
108
109
|
id: Uuid;
|
|
109
|
-
/** Human-readable title for the
|
|
110
|
+
/** Human-readable title for the focus */
|
|
110
111
|
title: string;
|
|
111
|
-
/** Whether this
|
|
112
|
+
/** Whether this focus has been archived */
|
|
112
113
|
archived: boolean;
|
|
113
114
|
/**
|
|
114
|
-
* Optional key for referencing this
|
|
115
|
-
* Keys are unique per
|
|
115
|
+
* Optional key for referencing this focus.
|
|
116
|
+
* Keys are unique per user.
|
|
116
117
|
*/
|
|
117
118
|
key: string | null;
|
|
118
|
-
/** Optional theme color for the
|
|
119
|
+
/** Optional theme color for the focus (0-7). Defaults to 7 (Resolution) when not set. */
|
|
119
120
|
color: ThemeColor | null;
|
|
121
|
+
/** Optional icon for the focus (a curated icon key). Defaults to the focus icon when not set. */
|
|
122
|
+
icon: string | null;
|
|
120
123
|
};
|
|
121
124
|
|
|
122
125
|
/**
|
|
123
|
-
* Type for creating new
|
|
126
|
+
* Type for creating new focuses.
|
|
124
127
|
*
|
|
125
128
|
* Supports multiple creation patterns:
|
|
126
|
-
* - Provide a specific UUID for the
|
|
127
|
-
* - Provide a key for upsert within the user's
|
|
129
|
+
* - Provide a specific UUID for the focus
|
|
130
|
+
* - Provide a key for upsert within the user's focuses
|
|
128
131
|
* - Omit both to auto-generate a new UUID
|
|
129
|
-
*
|
|
130
|
-
* Optionally specify a parent priority by ID or key for hierarchical structures.
|
|
131
132
|
*/
|
|
132
|
-
export type
|
|
133
|
-
Partial<Omit<
|
|
133
|
+
export type NewFocus = Pick<Focus, "title"> &
|
|
134
|
+
Partial<Omit<Focus, "id" | "title">> &
|
|
134
135
|
(
|
|
135
136
|
| {
|
|
136
137
|
/**
|
|
137
|
-
* Unique identifier for the
|
|
138
|
-
* Specifying an ID allows tools to track and upsert
|
|
138
|
+
* Unique identifier for the focus, generated by Uuid.Generate().
|
|
139
|
+
* Specifying an ID allows tools to track and upsert focuses.
|
|
139
140
|
*/
|
|
140
141
|
id: Uuid;
|
|
141
142
|
}
|
|
142
143
|
| {
|
|
143
144
|
/**
|
|
144
|
-
* Unique key for the
|
|
145
|
+
* Unique key for the focus within the user's focuses.
|
|
145
146
|
* Can be used to upsert without knowing the UUID.
|
|
146
|
-
* For example, "@plot" identifies the Plot
|
|
147
|
+
* For example, "@plot" identifies the Plot focus.
|
|
147
148
|
*/
|
|
148
149
|
key: string;
|
|
149
150
|
}
|
|
150
151
|
| {
|
|
151
152
|
/* Neither id nor key is required. An id will be generated and returned. */
|
|
152
153
|
}
|
|
153
|
-
)
|
|
154
|
-
/** Add the new priority as the child of another priority */
|
|
155
|
-
parent?: { id: Uuid } | { key: string };
|
|
156
|
-
};
|
|
154
|
+
);
|
|
157
155
|
|
|
158
156
|
/**
|
|
159
|
-
* Type for updating existing
|
|
160
|
-
* Must provide either id or key to identify the
|
|
161
|
-
* Set `parent` to move the priority under a new parent (requires PriorityAccess.Full).
|
|
157
|
+
* Type for updating existing focuses.
|
|
158
|
+
* Must provide either id or key to identify the focus to update.
|
|
162
159
|
*/
|
|
163
|
-
export type
|
|
164
|
-
Partial<Pick<
|
|
165
|
-
/** Move the priority under a new parent. Requires PriorityAccess.Full. */
|
|
166
|
-
parent?: { id: Uuid } | { key: string };
|
|
167
|
-
};
|
|
160
|
+
export type FocusUpdate = ({ id: Uuid } | { key: string }) &
|
|
161
|
+
Partial<Pick<Focus, "title" | "archived">>;
|
|
168
162
|
|
|
169
163
|
/**
|
|
170
164
|
* Enumeration of supported action types.
|
|
@@ -375,9 +369,9 @@ export type ThreadMeta = {
|
|
|
375
369
|
|
|
376
370
|
/**
|
|
377
371
|
* Thread sub-type that determines the thread's icon and category.
|
|
378
|
-
* Available types depend on whether the
|
|
379
|
-
* - Private
|
|
380
|
-
* - Shared
|
|
372
|
+
* Available types depend on whether the focus is shared:
|
|
373
|
+
* - Private focuses: "action" (default for tasks), "notes" (default), "idea", "goal", "decision"
|
|
374
|
+
* - Shared focuses: all above plus "discussion" (default), "announcement", "ask"
|
|
381
375
|
*/
|
|
382
376
|
export type ThreadType =
|
|
383
377
|
| "action"
|
|
@@ -430,8 +424,8 @@ export type NewReactions = Record<Reaction, NewActor[]>;
|
|
|
430
424
|
|
|
431
425
|
/**
|
|
432
426
|
* Thread access level determining visibility.
|
|
433
|
-
* - "public": Visible to all users with
|
|
434
|
-
* - "members": Visible to
|
|
427
|
+
* - "public": Visible to all users with focus access
|
|
428
|
+
* - "members": Visible to focus members (default for shared focuses)
|
|
435
429
|
* - "private": Visible only to creator and contacts listed in accessContacts
|
|
436
430
|
*/
|
|
437
431
|
export type ThreadAccessLevel = "public" | "members" | "private";
|
|
@@ -469,8 +463,8 @@ export type ThreadCommon = {
|
|
|
469
463
|
type ThreadFields = ThreadCommon & {
|
|
470
464
|
/** The display title/summary of the thread */
|
|
471
465
|
title: string;
|
|
472
|
-
/** The
|
|
473
|
-
|
|
466
|
+
/** The focus context this thread belongs to */
|
|
467
|
+
focus: Focus;
|
|
474
468
|
/** The thread's sub-type/category. Determines the displayed icon. */
|
|
475
469
|
type: ThreadType | null;
|
|
476
470
|
/** Thread access level: "public", "members", or "private" */
|
|
@@ -506,7 +500,7 @@ export type NewThreadWithNotes = NewThread & {
|
|
|
506
500
|
* ```
|
|
507
501
|
*/
|
|
508
502
|
export type NewThread = Partial<
|
|
509
|
-
Omit<ThreadFields, "
|
|
503
|
+
Omit<ThreadFields, "focus" | "tags" | "reactions" | "id" | "accessContacts">
|
|
510
504
|
> &
|
|
511
505
|
(
|
|
512
506
|
| {
|
|
@@ -518,8 +512,8 @@ export type NewThread = Partial<
|
|
|
518
512
|
}
|
|
519
513
|
) &
|
|
520
514
|
{
|
|
521
|
-
/** Explicit
|
|
522
|
-
|
|
515
|
+
/** Explicit focus - disables automatic focus matching. When omitted, the server classifies the thread using the user's focus rules. */
|
|
516
|
+
focus?: Pick<Focus, "id">;
|
|
523
517
|
} & {
|
|
524
518
|
/**
|
|
525
519
|
* All tags to set on the new thread.
|
|
@@ -550,7 +544,7 @@ export type NewThread = Partial<
|
|
|
550
544
|
* - undefined/omitted (default): Thread is unread for users, except auto-marked
|
|
551
545
|
* as read for the author if they are the twist owner (user)
|
|
552
546
|
* - true: Thread is explicitly unread for ALL users (use sparingly)
|
|
553
|
-
* - false: Thread is marked as read for all users in the
|
|
547
|
+
* - false: Thread is marked as read for all users in the focus at creation time
|
|
554
548
|
*/
|
|
555
549
|
unread?: boolean;
|
|
556
550
|
|
|
@@ -638,10 +632,10 @@ type ThreadSingleUpdateFields = ThreadBulkUpdateFields & {
|
|
|
638
632
|
preview?: string | null;
|
|
639
633
|
|
|
640
634
|
/**
|
|
641
|
-
* Move the thread to a different
|
|
642
|
-
* The target
|
|
635
|
+
* Move the thread to a different focus. Requires ThreadAccess.Full.
|
|
636
|
+
* The target focus must be owned by the twist's user.
|
|
643
637
|
*/
|
|
644
|
-
|
|
638
|
+
focus?: Pick<Focus, "id">;
|
|
645
639
|
};
|
|
646
640
|
|
|
647
641
|
export type ThreadUpdate =
|
|
@@ -699,7 +693,7 @@ export type Note = ThreadCommon & {
|
|
|
699
693
|
* When set (even to []), the note is private to the listed contacts plus the creator.
|
|
700
694
|
*/
|
|
701
695
|
accessContacts: ActorId[] | null;
|
|
702
|
-
/**
|
|
696
|
+
/** Focus twist IDs (twists/connectors) mentioned for dispatch routing. Does not include user contacts. */
|
|
703
697
|
mentions: ActorId[];
|
|
704
698
|
};
|
|
705
699
|
|
|
@@ -771,7 +765,7 @@ export type NewNote = Partial<
|
|
|
771
765
|
* - undefined/omitted (default): Thread is unread for users, except auto-marked
|
|
772
766
|
* as read for the author if they are the twist owner (user)
|
|
773
767
|
* - true: Thread is explicitly unread for ALL users (use sparingly)
|
|
774
|
-
* - false: Thread is marked as read for all users in the
|
|
768
|
+
* - false: Thread is marked as read for all users in the focus at note creation time
|
|
775
769
|
*
|
|
776
770
|
* For the default behavior, omit this field entirely.
|
|
777
771
|
* Use false for initial sync to avoid marking historical items as unread.
|
|
@@ -1044,7 +1038,7 @@ export type NewLink = Partial<
|
|
|
1044
1038
|
> & {
|
|
1045
1039
|
/**
|
|
1046
1040
|
* Canonical ID for the item in an external system.
|
|
1047
|
-
* When set, uniquely identifies the link
|
|
1041
|
+
* When set, uniquely identifies the link for the user. This performs
|
|
1048
1042
|
* an upsert.
|
|
1049
1043
|
*
|
|
1050
1044
|
* @deprecated Pass `sources: [...]` instead. Both fields can be set during
|
|
@@ -1078,7 +1072,7 @@ export type NewLink = Partial<
|
|
|
1078
1072
|
* Whether the thread should be marked as unread for users.
|
|
1079
1073
|
* - undefined/omitted (default): Thread is unread for users, except auto-marked
|
|
1080
1074
|
* as read for the author if they are the twist owner (user)
|
|
1081
|
-
* - false: Thread is marked as read for all users in the
|
|
1075
|
+
* - false: Thread is marked as read for all users in the focus at creation time
|
|
1082
1076
|
*/
|
|
1083
1077
|
unread?: boolean;
|
|
1084
1078
|
/**
|
|
@@ -1089,11 +1083,11 @@ export type NewLink = Partial<
|
|
|
1089
1083
|
*/
|
|
1090
1084
|
archived?: boolean;
|
|
1091
1085
|
/**
|
|
1092
|
-
* Explicit
|
|
1086
|
+
* Explicit focus (disables automatic focus matching).
|
|
1093
1087
|
* Only used when the link creates a new thread. When omitted, the
|
|
1094
|
-
* server classifies the thread using the user's
|
|
1088
|
+
* server classifies the thread using the user's focus rules.
|
|
1095
1089
|
*/
|
|
1096
|
-
|
|
1090
|
+
focus?: Pick<Focus, "id">;
|
|
1097
1091
|
};
|
|
1098
1092
|
|
|
1099
1093
|
/**
|
|
@@ -1141,8 +1135,8 @@ export type PlanOperation =
|
|
|
1141
1135
|
/** Current thread title for display */
|
|
1142
1136
|
threadTitle: string;
|
|
1143
1137
|
changes: Partial<Pick<ThreadFields, "archived" | "title" | "type">> & {
|
|
1144
|
-
/** Move to this
|
|
1145
|
-
|
|
1138
|
+
/** Move to this focus */
|
|
1139
|
+
focus?: { id: Uuid; title: string };
|
|
1146
1140
|
};
|
|
1147
1141
|
}
|
|
1148
1142
|
| {
|
|
@@ -1159,9 +1153,9 @@ export type PlanOperation =
|
|
|
1159
1153
|
| {
|
|
1160
1154
|
type: "createThread";
|
|
1161
1155
|
title: string;
|
|
1162
|
-
|
|
1163
|
-
/**
|
|
1164
|
-
|
|
1156
|
+
focusId: Uuid;
|
|
1157
|
+
/** Focus title for display */
|
|
1158
|
+
focusTitle: string;
|
|
1165
1159
|
}
|
|
1166
1160
|
| {
|
|
1167
1161
|
type: "createNote";
|
|
@@ -1171,12 +1165,9 @@ export type PlanOperation =
|
|
|
1171
1165
|
content: string;
|
|
1172
1166
|
}
|
|
1173
1167
|
| {
|
|
1174
|
-
type: "
|
|
1175
|
-
|
|
1176
|
-
/** Current
|
|
1177
|
-
|
|
1178
|
-
changes: Partial<Pick<
|
|
1179
|
-
/** Move under this parent */
|
|
1180
|
-
parent?: { id: Uuid; title: string };
|
|
1181
|
-
};
|
|
1168
|
+
type: "updateFocus";
|
|
1169
|
+
focusId: Uuid;
|
|
1170
|
+
/** Current focus title for display */
|
|
1171
|
+
focusTitle: string;
|
|
1172
|
+
changes: Partial<Pick<Focus, "title" | "archived">>;
|
|
1182
1173
|
};
|
package/src/schedule.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { Uuid } from "./utils/uuid";
|
|
|
14
14
|
* Represents a schedule entry for a thread.
|
|
15
15
|
*
|
|
16
16
|
* Schedules define when a thread occurs in time. A thread may have zero or more schedules:
|
|
17
|
-
* - Shared schedules (userId is null): visible to all members of the thread's
|
|
17
|
+
* - Shared schedules (userId is null): visible to all members of the thread's focus
|
|
18
18
|
* - Per-user schedules (userId set): private ordering/scheduling for a specific user
|
|
19
19
|
*
|
|
20
20
|
* For recurring events in the SDK, start/end represent the first occurrence's
|