@plotday/twister 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/bin/commands/build.js +108 -0
  4. package/bin/commands/build.js.map +1 -0
  5. package/bin/commands/create.js +230 -0
  6. package/bin/commands/create.js.map +1 -0
  7. package/bin/commands/deploy.js +292 -0
  8. package/bin/commands/deploy.js.map +1 -0
  9. package/bin/commands/generate.js +301 -0
  10. package/bin/commands/generate.js.map +1 -0
  11. package/bin/commands/lint.js +69 -0
  12. package/bin/commands/lint.js.map +1 -0
  13. package/bin/commands/login.js +140 -0
  14. package/bin/commands/login.js.map +1 -0
  15. package/bin/commands/priority-create.js +102 -0
  16. package/bin/commands/priority-create.js.map +1 -0
  17. package/bin/commands/priority-list.js +47 -0
  18. package/bin/commands/priority-list.js.map +1 -0
  19. package/bin/commands/twist-logs.js +187 -0
  20. package/bin/commands/twist-logs.js.map +1 -0
  21. package/bin/index.js +129 -0
  22. package/bin/index.js.map +1 -0
  23. package/bin/package.json +3 -0
  24. package/bin/plot.cjs +3 -0
  25. package/bin/templates/AGENTS.template.md +403 -0
  26. package/bin/templates/CLAUDE.template.md +1 -0
  27. package/bin/templates/README.template.md +189 -0
  28. package/bin/utils/bundle.js +106 -0
  29. package/bin/utils/bundle.js.map +1 -0
  30. package/bin/utils/output.js +133 -0
  31. package/bin/utils/output.js.map +1 -0
  32. package/bin/utils/packageManager.js +65 -0
  33. package/bin/utils/packageManager.js.map +1 -0
  34. package/bin/utils/sse.js +100 -0
  35. package/bin/utils/sse.js.map +1 -0
  36. package/bin/utils/token.js +75 -0
  37. package/bin/utils/token.js.map +1 -0
  38. package/cli/templates/AGENTS.template.md +403 -0
  39. package/cli/templates/CLAUDE.template.md +1 -0
  40. package/cli/templates/README.template.md +189 -0
  41. package/dist/common/calendar.d.ts +144 -0
  42. package/dist/common/calendar.d.ts.map +1 -0
  43. package/dist/common/calendar.js +2 -0
  44. package/dist/common/calendar.js.map +1 -0
  45. package/dist/common/messaging.d.ts +84 -0
  46. package/dist/common/messaging.d.ts.map +1 -0
  47. package/dist/common/messaging.js +2 -0
  48. package/dist/common/messaging.js.map +1 -0
  49. package/dist/creator-docs.d.ts +11 -0
  50. package/dist/creator-docs.d.ts.map +1 -0
  51. package/dist/creator-docs.js +27 -0
  52. package/dist/creator-docs.js.map +1 -0
  53. package/dist/docs/.nojekyll +1 -0
  54. package/dist/docs/assets/favicon.svg +8 -0
  55. package/dist/docs/assets/hierarchy.js +1 -0
  56. package/dist/docs/assets/highlight.css +134 -0
  57. package/dist/docs/assets/icons.js +18 -0
  58. package/dist/docs/assets/icons.svg +1 -0
  59. package/dist/docs/assets/main.js +60 -0
  60. package/dist/docs/assets/navigation.js +1 -0
  61. package/dist/docs/assets/search.js +1 -0
  62. package/dist/docs/assets/style.css +1633 -0
  63. package/dist/docs/classes/tool.ITool.html +4 -0
  64. package/dist/docs/classes/tool.Tool.html +116 -0
  65. package/dist/docs/classes/tools_ai.AI.html +27 -0
  66. package/dist/docs/classes/tools_callbacks.Callbacks.html +45 -0
  67. package/dist/docs/classes/tools_integrations.Integrations.html +26 -0
  68. package/dist/docs/classes/tools_network.Network.html +68 -0
  69. package/dist/docs/classes/tools_plot.Plot.html +82 -0
  70. package/dist/docs/classes/tools_store.Store.html +53 -0
  71. package/dist/docs/classes/tools_tasks.Tasks.html +39 -0
  72. package/dist/docs/classes/tools_twists.Twists.html +59 -0
  73. package/dist/docs/classes/twist.Twist.html +96 -0
  74. package/dist/docs/documents/Advanced.html +91 -0
  75. package/dist/docs/documents/Building_Custom_Tools.html +200 -0
  76. package/dist/docs/documents/Built-in_Tools.html +170 -0
  77. package/dist/docs/documents/CLI_Reference.html +193 -0
  78. package/dist/docs/documents/Core_Concepts.html +163 -0
  79. package/dist/docs/documents/Getting_Started.html +94 -0
  80. package/dist/docs/documents/Runtime_Environment.html +128 -0
  81. package/dist/docs/enums/plot.ActivityLinkType.html +12 -0
  82. package/dist/docs/enums/plot.ActivityType.html +10 -0
  83. package/dist/docs/enums/plot.ActorType.html +10 -0
  84. package/dist/docs/enums/plot.ConferencingProvider.html +14 -0
  85. package/dist/docs/enums/tag.Tag.html +45 -0
  86. package/dist/docs/enums/tools_ai.AIModel.html +31 -0
  87. package/dist/docs/enums/tools_integrations.AuthLevel.html +7 -0
  88. package/dist/docs/enums/tools_integrations.AuthProvider.html +24 -0
  89. package/dist/docs/enums/tools_plot.ActivityAccess.html +8 -0
  90. package/dist/docs/enums/tools_plot.ContactAccess.html +5 -0
  91. package/dist/docs/enums/tools_plot.PriorityAccess.html +8 -0
  92. package/dist/docs/hierarchy.html +1 -0
  93. package/dist/docs/index.html +100 -0
  94. package/dist/docs/interfaces/common_calendar.Calendar.html +13 -0
  95. package/dist/docs/interfaces/common_calendar.CalendarTool.html +49 -0
  96. package/dist/docs/interfaces/common_calendar.SyncOptions.html +8 -0
  97. package/dist/docs/interfaces/tools_ai.AIRequest.html +46 -0
  98. package/dist/docs/interfaces/tools_ai.AIResponse.html +19 -0
  99. package/dist/docs/interfaces/tools_ai.FilePart.html +14 -0
  100. package/dist/docs/interfaces/tools_ai.ImagePart.html +11 -0
  101. package/dist/docs/interfaces/tools_ai.ReasoningPart.html +7 -0
  102. package/dist/docs/interfaces/tools_ai.RedactedReasoningPart.html +5 -0
  103. package/dist/docs/interfaces/tools_ai.TextPart.html +5 -0
  104. package/dist/docs/interfaces/tools_ai.ToolCallPart.html +9 -0
  105. package/dist/docs/interfaces/tools_ai.ToolExecutionOptions.html +9 -0
  106. package/dist/docs/interfaces/tools_ai.ToolResultPart.html +9 -0
  107. package/dist/docs/interfaces/tools_twists.TwistSource.html +13 -0
  108. package/dist/docs/interfaces/utils_types.ToolShed.html +11 -0
  109. package/dist/docs/modules/common_calendar.html +1 -0
  110. package/dist/docs/modules/index.html +1 -0
  111. package/dist/docs/modules/plot.html +1 -0
  112. package/dist/docs/modules/tag.html +1 -0
  113. package/dist/docs/modules/tool.html +1 -0
  114. package/dist/docs/modules/tools_ai.html +1 -0
  115. package/dist/docs/modules/tools_callbacks.html +1 -0
  116. package/dist/docs/modules/tools_integrations.html +1 -0
  117. package/dist/docs/modules/tools_network.html +1 -0
  118. package/dist/docs/modules/tools_plot.html +1 -0
  119. package/dist/docs/modules/tools_store.html +1 -0
  120. package/dist/docs/modules/tools_tasks.html +1 -0
  121. package/dist/docs/modules/tools_twists.html +1 -0
  122. package/dist/docs/modules/twist.html +1 -0
  123. package/dist/docs/modules/utils_types.html +1 -0
  124. package/dist/docs/modules.html +1 -0
  125. package/dist/docs/types/common_calendar.CalendarAuth.html +7 -0
  126. package/dist/docs/types/plot.Activity.html +64 -0
  127. package/dist/docs/types/plot.ActivityLink.html +22 -0
  128. package/dist/docs/types/plot.ActivityMeta.html +11 -0
  129. package/dist/docs/types/plot.ActivityUpdate.html +13 -0
  130. package/dist/docs/types/plot.Actor.html +15 -0
  131. package/dist/docs/types/plot.ActorId.html +4 -0
  132. package/dist/docs/types/plot.NewActivity.html +16 -0
  133. package/dist/docs/types/plot.NewContact.html +13 -0
  134. package/dist/docs/types/plot.NewPriority.html +5 -0
  135. package/dist/docs/types/plot.NoteType.html +1 -0
  136. package/dist/docs/types/plot.PickPriorityConfig.html +22 -0
  137. package/dist/docs/types/plot.Priority.html +8 -0
  138. package/dist/docs/types/tools_ai.AIAssistantMessage.html +4 -0
  139. package/dist/docs/types/tools_ai.AIMessage.html +3 -0
  140. package/dist/docs/types/tools_ai.AISource.html +11 -0
  141. package/dist/docs/types/tools_ai.AISystemMessage.html +7 -0
  142. package/dist/docs/types/tools_ai.AITool.html +19 -0
  143. package/dist/docs/types/tools_ai.AIToolMessage.html +4 -0
  144. package/dist/docs/types/tools_ai.AIToolSet.html +1 -0
  145. package/dist/docs/types/tools_ai.AIUsage.html +10 -0
  146. package/dist/docs/types/tools_ai.AIUserMessage.html +4 -0
  147. package/dist/docs/types/tools_ai.DataContent.html +2 -0
  148. package/dist/docs/types/tools_ai.ModelPreferences.html +24 -0
  149. package/dist/docs/types/tools_callbacks.Callback.html +8 -0
  150. package/dist/docs/types/tools_integrations.AuthToken.html +16 -0
  151. package/dist/docs/types/tools_integrations.Authorization.html +10 -0
  152. package/dist/docs/types/tools_network.WebhookRequest.html +15 -0
  153. package/dist/docs/types/tools_plot.ActivityIntentHandler.html +9 -0
  154. package/dist/docs/types/tools_twists.Log.html +6 -0
  155. package/dist/docs/types/tools_twists.TwistPermissions.html +12 -0
  156. package/dist/docs/types/utils_types.BuiltInTools.html +5 -0
  157. package/dist/docs/types/utils_types.CallbackMethods.html +3 -0
  158. package/dist/docs/types/utils_types.ExtractBuildReturn.html +2 -0
  159. package/dist/docs/types/utils_types.InferOptions.html +2 -0
  160. package/dist/docs/types/utils_types.InferTools.html +3 -0
  161. package/dist/docs/types/utils_types.NoFunctions.html +3 -0
  162. package/dist/docs/types/utils_types.NonFunction.html +2 -0
  163. package/dist/docs/types/utils_types.PromiseValues.html +3 -0
  164. package/dist/docs/types/utils_types.ToolBuilder.html +3 -0
  165. package/dist/index.d.ts +7 -0
  166. package/dist/index.d.ts.map +1 -0
  167. package/dist/index.js +7 -0
  168. package/dist/index.js.map +1 -0
  169. package/dist/llm-docs/common/calendar.d.ts +9 -0
  170. package/dist/llm-docs/common/calendar.d.ts.map +1 -0
  171. package/dist/llm-docs/common/calendar.js +8 -0
  172. package/dist/llm-docs/common/calendar.js.map +1 -0
  173. package/dist/llm-docs/common/messaging.d.ts +9 -0
  174. package/dist/llm-docs/common/messaging.d.ts.map +1 -0
  175. package/dist/llm-docs/common/messaging.js +8 -0
  176. package/dist/llm-docs/common/messaging.js.map +1 -0
  177. package/dist/llm-docs/creator-docs.d.ts +9 -0
  178. package/dist/llm-docs/creator-docs.d.ts.map +1 -0
  179. package/dist/llm-docs/creator-docs.js +8 -0
  180. package/dist/llm-docs/creator-docs.js.map +1 -0
  181. package/dist/llm-docs/index.d.ts +11 -0
  182. package/dist/llm-docs/index.d.ts.map +1 -0
  183. package/dist/llm-docs/index.js +42 -0
  184. package/dist/llm-docs/index.js.map +1 -0
  185. package/dist/llm-docs/plot.d.ts +9 -0
  186. package/dist/llm-docs/plot.d.ts.map +1 -0
  187. package/dist/llm-docs/plot.js +8 -0
  188. package/dist/llm-docs/plot.js.map +1 -0
  189. package/dist/llm-docs/tag.d.ts +9 -0
  190. package/dist/llm-docs/tag.d.ts.map +1 -0
  191. package/dist/llm-docs/tag.js +8 -0
  192. package/dist/llm-docs/tag.js.map +1 -0
  193. package/dist/llm-docs/tool.d.ts +9 -0
  194. package/dist/llm-docs/tool.d.ts.map +1 -0
  195. package/dist/llm-docs/tool.js +8 -0
  196. package/dist/llm-docs/tool.js.map +1 -0
  197. package/dist/llm-docs/tools/ai.d.ts +9 -0
  198. package/dist/llm-docs/tools/ai.d.ts.map +1 -0
  199. package/dist/llm-docs/tools/ai.js +8 -0
  200. package/dist/llm-docs/tools/ai.js.map +1 -0
  201. package/dist/llm-docs/tools/callbacks.d.ts +9 -0
  202. package/dist/llm-docs/tools/callbacks.d.ts.map +1 -0
  203. package/dist/llm-docs/tools/callbacks.js +8 -0
  204. package/dist/llm-docs/tools/callbacks.js.map +1 -0
  205. package/dist/llm-docs/tools/integrations.d.ts +9 -0
  206. package/dist/llm-docs/tools/integrations.d.ts.map +1 -0
  207. package/dist/llm-docs/tools/integrations.js +8 -0
  208. package/dist/llm-docs/tools/integrations.js.map +1 -0
  209. package/dist/llm-docs/tools/network.d.ts +9 -0
  210. package/dist/llm-docs/tools/network.d.ts.map +1 -0
  211. package/dist/llm-docs/tools/network.js +8 -0
  212. package/dist/llm-docs/tools/network.js.map +1 -0
  213. package/dist/llm-docs/tools/plot.d.ts +9 -0
  214. package/dist/llm-docs/tools/plot.d.ts.map +1 -0
  215. package/dist/llm-docs/tools/plot.js +8 -0
  216. package/dist/llm-docs/tools/plot.js.map +1 -0
  217. package/dist/llm-docs/tools/store.d.ts +9 -0
  218. package/dist/llm-docs/tools/store.d.ts.map +1 -0
  219. package/dist/llm-docs/tools/store.js +8 -0
  220. package/dist/llm-docs/tools/store.js.map +1 -0
  221. package/dist/llm-docs/tools/tasks.d.ts +9 -0
  222. package/dist/llm-docs/tools/tasks.d.ts.map +1 -0
  223. package/dist/llm-docs/tools/tasks.js +8 -0
  224. package/dist/llm-docs/tools/tasks.js.map +1 -0
  225. package/dist/llm-docs/tools/twists.d.ts +9 -0
  226. package/dist/llm-docs/tools/twists.d.ts.map +1 -0
  227. package/dist/llm-docs/tools/twists.js +8 -0
  228. package/dist/llm-docs/tools/twists.js.map +1 -0
  229. package/dist/llm-docs/twist-guide-template.d.ts +9 -0
  230. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -0
  231. package/dist/llm-docs/twist-guide-template.js +8 -0
  232. package/dist/llm-docs/twist-guide-template.js.map +1 -0
  233. package/dist/llm-docs/twist.d.ts +9 -0
  234. package/dist/llm-docs/twist.d.ts.map +1 -0
  235. package/dist/llm-docs/twist.js +8 -0
  236. package/dist/llm-docs/twist.js.map +1 -0
  237. package/dist/plot.d.ts +463 -0
  238. package/dist/plot.d.ts.map +1 -0
  239. package/dist/plot.js +68 -0
  240. package/dist/plot.js.map +1 -0
  241. package/dist/tag.d.ts +47 -0
  242. package/dist/tag.d.ts.map +1 -0
  243. package/dist/tag.js +51 -0
  244. package/dist/tag.js.map +1 -0
  245. package/dist/tool.d.ts +242 -0
  246. package/dist/tool.d.ts.map +1 -0
  247. package/dist/tool.js +283 -0
  248. package/dist/tool.js.map +1 -0
  249. package/dist/tools/ai.d.ts +697 -0
  250. package/dist/tools/ai.d.ts.map +1 -0
  251. package/dist/tools/ai.js +104 -0
  252. package/dist/tools/ai.js.map +1 -0
  253. package/dist/tools/callbacks.d.ts +96 -0
  254. package/dist/tools/callbacks.d.ts.map +1 -0
  255. package/dist/tools/callbacks.js +40 -0
  256. package/dist/tools/callbacks.js.map +1 -0
  257. package/dist/tools/index.d.ts +9 -0
  258. package/dist/tools/index.d.ts.map +1 -0
  259. package/dist/tools/index.js +9 -0
  260. package/dist/tools/index.js.map +1 -0
  261. package/dist/tools/integrations.d.ts +142 -0
  262. package/dist/tools/integrations.d.ts.map +1 -0
  263. package/dist/tools/integrations.js +79 -0
  264. package/dist/tools/integrations.js.map +1 -0
  265. package/dist/tools/network.d.ts +188 -0
  266. package/dist/tools/network.d.ts.map +1 -0
  267. package/dist/tools/network.js +87 -0
  268. package/dist/tools/network.js.map +1 -0
  269. package/dist/tools/plot.d.ts +252 -0
  270. package/dist/tools/plot.d.ts.map +1 -0
  271. package/dist/tools/plot.js +72 -0
  272. package/dist/tools/plot.js.map +1 -0
  273. package/dist/tools/store.d.ts +90 -0
  274. package/dist/tools/store.d.ts.map +1 -0
  275. package/dist/tools/store.js +48 -0
  276. package/dist/tools/store.js.map +1 -0
  277. package/dist/tools/tasks.d.ts +93 -0
  278. package/dist/tools/tasks.d.ts.map +1 -0
  279. package/dist/tools/tasks.js +58 -0
  280. package/dist/tools/tasks.js.map +1 -0
  281. package/dist/tools/twists.d.ts +213 -0
  282. package/dist/tools/twists.d.ts.map +1 -0
  283. package/dist/tools/twists.js +26 -0
  284. package/dist/tools/twists.js.map +1 -0
  285. package/dist/twist-guide.d.ts +2 -0
  286. package/dist/twist-guide.d.ts.map +1 -0
  287. package/dist/twist-guide.js +9 -0
  288. package/dist/twist-guide.js.map +1 -0
  289. package/dist/twist.d.ts +204 -0
  290. package/dist/twist.d.ts.map +1 -0
  291. package/dist/twist.js +216 -0
  292. package/dist/twist.js.map +1 -0
  293. package/dist/utils/types.d.ts +91 -0
  294. package/dist/utils/types.d.ts.map +1 -0
  295. package/dist/utils/types.js +2 -0
  296. package/dist/utils/types.js.map +1 -0
  297. package/package.json +206 -0
  298. package/tsconfig.base.json +28 -0
@@ -0,0 +1,200 @@
1
+ <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Building Custom Tools | Creating Plot Twists</title><link rel="icon" href="../assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for Creating Plot Twists"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="/" class="title">Creating Plot Twists</a><div id="tsd-toolbar-links"><a href="https://plot.day">Plot</a><a href="https://github.com/plotday/plot">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister">NPM</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">Building Custom Tools</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="building-custom-tools" class="tsd-anchor-link">Building Custom Tools<a href="#building-custom-tools" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Custom tools let you create reusable functionality that can be shared across twists or published for others to use. This guide covers everything you need to know about building tools.</p>
2
+ <h2 id="table-of-contents" class="tsd-anchor-link">Table of Contents<a href="#table-of-contents" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
3
+ <li><a href="#why-build-tools">Why Build Tools?</a></li>
4
+ <li><a href="#tool-basics">Tool Basics</a></li>
5
+ <li><a href="#tool-structure">Tool Structure</a></li>
6
+ <li><a href="#lifecycle-methods">Lifecycle Methods</a></li>
7
+ <li><a href="#dependencies">Dependencies</a></li>
8
+ <li><a href="#options-and-configuration">Options and Configuration</a></li>
9
+ <li><a href="#complete-examples">Complete Examples</a></li>
10
+ <li><a href="#testing-tools">Testing Tools</a></li>
11
+ <li><a href="#publishing-tools">Publishing Tools</a></li>
12
+ <li><a href="#best-practices">Best Practices</a></li>
13
+ </ul>
14
+ <hr>
15
+ <h2 id="why-build-tools" class="tsd-anchor-link">Why Build Tools?<a href="#why-build-tools" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Build custom tools when you need to:</p>
16
+ <ul>
17
+ <li><strong>Integrate external services</strong> - GitHub, Slack, Notion, etc.</li>
18
+ <li><strong>Encapsulate complex logic</strong> - Reusable business logic</li>
19
+ <li><strong>Share functionality</strong> - Between multiple twists</li>
20
+ <li><strong>Abstract implementation details</strong> - Clean interfaces for common operations</li>
21
+ </ul>
22
+ <h3 id="built-in-vs-custom-tools" class="tsd-anchor-link">Built-in vs. Custom Tools<a href="#built-in-vs-custom-tools" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table>
23
+ <thead>
24
+ <tr>
25
+ <th>Built-in Tools</th>
26
+ <th>Custom Tools</th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <tr>
31
+ <td>Plot, Store, AI, Network, etc.</td>
32
+ <td>Your integrations and utilities</td>
33
+ </tr>
34
+ <tr>
35
+ <td>Access to Plot internals</td>
36
+ <td>Built on top of built-in tools</td>
37
+ </tr>
38
+ <tr>
39
+ <td>Provided by twist Builder</td>
40
+ <td>Created by you or installed from npm</td>
41
+ </tr>
42
+ <tr>
43
+ <td>Always available</td>
44
+ <td>Declared as dependencies</td>
45
+ </tr>
46
+ </tbody>
47
+ </table>
48
+ <hr>
49
+ <h2 id="tool-basics" class="tsd-anchor-link">Tool Basics<a href="#tool-basics" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Tools extend the <code>Tool&lt;T&gt;</code> base class and can access other tools through dependencies.</p>
50
+ <h3 id="minimal-tool-example" class="tsd-anchor-link">Minimal Tool Example<a href="#minimal-tool-example" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">HelloTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">HelloTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">sayHello</span><span class="hl-1">(</span><span class="hl-2">name</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-3">`Hello, </span><span class="hl-4">${</span><span class="hl-2">name</span><span class="hl-4">}</span><span class="hl-3">!`</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
51
+ </code><button type="button">Copy</button></pre>
52
+
53
+ <h3 id="using-your-tool" class="tsd-anchor-link">Using Your Tool<a href="#using-your-tool" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">twist</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">HelloTool</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;./tools/hello&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-0">default</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">twist</span><span class="hl-1">&lt;</span><span class="hl-5">MyTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">hello:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">HelloTool</span><span class="hl-1">),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">message</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">hello</span><span class="hl-1">.</span><span class="hl-6">sayHello</span><span class="hl-1">(</span><span class="hl-3">&quot;World&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-2">message</span><span class="hl-1">); </span><span class="hl-7">// &quot;Hello, World!&quot;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
54
+ </code><button type="button">Copy</button></pre>
55
+
56
+ <hr>
57
+ <h2 id="tool-structure" class="tsd-anchor-link">Tool Structure<a href="#tool-structure" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="class-definition" class="tsd-anchor-link">Class Definition<a href="#class-definition" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-7">// Tool class with type parameter</span><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">MyTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Constructor receives id, options, and toolShed</span><br/><span class="hl-1"> </span><span class="hl-4">constructor</span><span class="hl-1">(</span><span class="hl-2">id</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">, </span><span class="hl-2">options</span><span class="hl-1">: </span><span class="hl-5">InferOptions</span><span class="hl-1">&lt;</span><span class="hl-5">MyTool</span><span class="hl-1">&gt;, </span><span class="hl-2">toolShed</span><span class="hl-1">: </span><span class="hl-5">ToolShed</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-4">super</span><span class="hl-1">(</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">options</span><span class="hl-1">, </span><span class="hl-2">toolShed</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Public methods</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">myMethod</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Implementation</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
58
+ </code><button type="button">Copy</button></pre>
59
+
60
+ <h3 id="type-parameter" class="tsd-anchor-link">Type Parameter<a href="#type-parameter" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>The type parameter <code>&lt;MyTool&gt;</code> enables:</p>
61
+ <ul>
62
+ <li>Type-safe options inference</li>
63
+ <li>Type-safe tool dependencies</li>
64
+ <li>Proper TypeScript autocomplete</li>
65
+ </ul>
66
+ <hr>
67
+ <h2 id="lifecycle-methods" class="tsd-anchor-link">Lifecycle Methods<a href="#lifecycle-methods" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Tools have lifecycle methods that run at specific times during the twist lifecycle.</p>
68
+ <h3 id="preactivatepriority" class="tsd-anchor-link">preActivate(priority)<a href="#preactivatepriority" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>before</strong> the twist's <code>activate()</code> method, depth-first.</p>
69
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">preActivate</span><span class="hl-1">(</span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-2">Priority</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Setup that needs to happen before twist activation</span><br/><span class="hl-1"> console.log(</span><span class="hl-3">&quot;Tool preparing for activation&quot;</span><span class="hl-2">);</span><br/><br/><span class="hl-2"> </span><span class="hl-7">// Initialize connections, validate configuration, etc.</span><br/><span class="hl-2">}</span>
70
+ </code><button type="button">Copy</button></pre>
71
+
72
+ <p><strong>Use for:</strong></p>
73
+ <ul>
74
+ <li>Validating configuration</li>
75
+ <li>Setting up connections</li>
76
+ <li>Preparing resources</li>
77
+ </ul>
78
+ <h3 id="postactivatepriority" class="tsd-anchor-link">postActivate(priority)<a href="#postactivatepriority" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>after</strong> the twist's <code>activate()</code> method, reverse order.</p>
79
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">postActivate</span><span class="hl-1">(</span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-2">Priority</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Finalization after twist is activated</span><br/><span class="hl-1"> console.log(</span><span class="hl-3">&quot;Tool finalizing activation&quot;</span><span class="hl-2">);</span><br/><br/><span class="hl-2"> </span><span class="hl-7">// Start background processes, register webhooks, etc.</span><br/><span class="hl-2">}</span>
80
+ </code><button type="button">Copy</button></pre>
81
+
82
+ <p><strong>Use for:</strong></p>
83
+ <ul>
84
+ <li>Starting background processes</li>
85
+ <li>Registering webhooks</li>
86
+ <li>Final initialization</li>
87
+ </ul>
88
+ <h3 id="preupgrade" class="tsd-anchor-link">preUpgrade()<a href="#preupgrade" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>before</strong> the twist's <code>upgrade()</code> method.</p>
89
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">preUpgrade</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Prepare for upgrade</span><br/><span class="hl-1"> const </span><span class="hl-2">version</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt;(</span><span class="hl-3">&quot;tool_version&quot;</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (</span><span class="hl-2">version</span><span class="hl-1"> === </span><span class="hl-3">&quot;1.0.0&quot;</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// Migrate data</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
90
+ </code><button type="button">Copy</button></pre>
91
+
92
+ <h3 id="postupgrade" class="tsd-anchor-link">postUpgrade()<a href="#postupgrade" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>after</strong> the twist's <code>upgrade()</code> method.</p>
93
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">postUpgrade</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Finalize upgrade</span><br/><span class="hl-1"> await this.set(</span><span class="hl-3">&quot;tool_version&quot;</span><span class="hl-1">, </span><span class="hl-3">&quot;2.0.0&quot;</span><span class="hl-2">);</span><br/><span class="hl-2">}</span>
94
+ </code><button type="button">Copy</button></pre>
95
+
96
+ <h3 id="predeactivate" class="tsd-anchor-link">preDeactivate()<a href="#predeactivate" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>before</strong> the twist's <code>deactivate()</code> method.</p>
97
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">preDeactivate</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Cleanup before deactivation</span><br/><span class="hl-1"> await this.stopBackgroundProcesses();</span><br/><span class="hl-1">}</span>
98
+ </code><button type="button">Copy</button></pre>
99
+
100
+ <h3 id="postdeactivate" class="tsd-anchor-link">postDeactivate()<a href="#postdeactivate" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Called <strong>after</strong> the twist's <code>deactivate()</code> method.</p>
101
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">postDeactivate</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Final cleanup</span><br/><span class="hl-1"> await this.clearAll();</span><br/><span class="hl-1">}</span>
102
+ </code><button type="button">Copy</button></pre>
103
+
104
+ <h3 id="execution-order" class="tsd-anchor-link">Execution Order<a href="#execution-order" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-2">twist</span><span class="hl-1"> </span><span class="hl-14">Activation</span><span class="hl-1">:</span><br/><span class="hl-1"> </span><span class="hl-12">1.</span><span class="hl-1"> </span><span class="hl-2">Tool</span><span class="hl-1">.</span><span class="hl-6">preActivate</span><span class="hl-1">() (</span><span class="hl-2">deepest</span><span class="hl-1"> </span><span class="hl-2">dependencies</span><span class="hl-1"> </span><span class="hl-2">first</span><span class="hl-1">)</span><br/><span class="hl-1"> </span><span class="hl-12">2.</span><span class="hl-1"> </span><span class="hl-2">twist</span><span class="hl-1">.</span><span class="hl-6">activate</span><span class="hl-1">()</span><br/><span class="hl-1"> </span><span class="hl-12">3.</span><span class="hl-1"> </span><span class="hl-2">Tool</span><span class="hl-1">.</span><span class="hl-6">postActivate</span><span class="hl-1">() (</span><span class="hl-2">top</span><span class="hl-1">-</span><span class="hl-2">level</span><span class="hl-1"> </span><span class="hl-2">tools</span><span class="hl-1"> </span><span class="hl-2">first</span><span class="hl-1">)</span><br/><br/><span class="hl-2">twist</span><span class="hl-1"> </span><span class="hl-14">Deactivation</span><span class="hl-1">:</span><br/><span class="hl-1"> </span><span class="hl-12">1.</span><span class="hl-1"> </span><span class="hl-2">Tool</span><span class="hl-1">.</span><span class="hl-6">preDeactivate</span><span class="hl-1">() (</span><span class="hl-2">deepest</span><span class="hl-1"> </span><span class="hl-2">dependencies</span><span class="hl-1"> </span><span class="hl-2">first</span><span class="hl-1">)</span><br/><span class="hl-1"> </span><span class="hl-12">2.</span><span class="hl-1"> </span><span class="hl-2">twist</span><span class="hl-1">.</span><span class="hl-6">deactivate</span><span class="hl-1">()</span><br/><span class="hl-1"> </span><span class="hl-12">3.</span><span class="hl-1"> </span><span class="hl-2">Tool</span><span class="hl-1">.</span><span class="hl-6">postDeactivate</span><span class="hl-1">() (</span><span class="hl-2">top</span><span class="hl-1">-</span><span class="hl-2">level</span><span class="hl-1"> </span><span class="hl-2">tools</span><span class="hl-1"> </span><span class="hl-2">first</span><span class="hl-1">)</span>
105
+ </code><button>Copy</button></pre>
106
+
107
+ <hr>
108
+ <h2 id="dependencies" class="tsd-anchor-link">Dependencies<a href="#dependencies" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Tools can depend on other tools, including built-in tools.</p>
109
+ <h3 id="declaring-dependencies" class="tsd-anchor-link">Declaring Dependencies<a href="#declaring-dependencies" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Network</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/network&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Store</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/store&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">GitHubTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">GitHubTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Declare dependencies</span><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">network:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Network</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">urls:</span><span class="hl-1"> [</span><span class="hl-3">&quot;https://api.github.com/*&quot;</span><span class="hl-1">],</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> </span><span class="hl-2">store:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Store</span><span class="hl-1">),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Access dependencies</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getRepository</span><span class="hl-1">(</span><span class="hl-2">owner</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">, </span><span class="hl-2">repo</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">response</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-6">fetch</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-3">`https://api.github.com/repos/</span><span class="hl-4">${</span><span class="hl-2">owner</span><span class="hl-4">}</span><span class="hl-3">/</span><span class="hl-4">${</span><span class="hl-2">repo</span><span class="hl-4">}</span><span class="hl-3">`</span><br/><span class="hl-1"> );</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">response</span><span class="hl-1">.</span><span class="hl-6">json</span><span class="hl-1">();</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
110
+ </code><button type="button">Copy</button></pre>
111
+
112
+ <h3 id="accessing-dependencies" class="tsd-anchor-link">Accessing Dependencies<a href="#accessing-dependencies" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Use <code>this.tools</code> to access declared dependencies:</p>
113
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">fetchData</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">// Tools are fully typed</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">data</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">network</span><span class="hl-1">.</span><span class="hl-6">fetch</span><span class="hl-1">(</span><span class="hl-3">&quot;https://api.example.com/data&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">store</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">&quot;cached_data&quot;</span><span class="hl-1">, </span><span class="hl-2">data</span><span class="hl-1">);</span><br/><span class="hl-1">}</span>
114
+ </code><button type="button">Copy</button></pre>
115
+
116
+ <h3 id="built-in-tool-access" class="tsd-anchor-link">Built-in Tool Access<a href="#built-in-tool-access" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Tools have direct access to Store, Tasks, and Callbacks methods:</p>
117
+ <pre><code class="typescript"><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">MyTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">doWork</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">// Store</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">&quot;key&quot;</span><span class="hl-1">, </span><span class="hl-3">&quot;value&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">value</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt;(</span><span class="hl-3">&quot;key&quot;</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Tasks</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">callback</span><span class="hl-1">(</span><span class="hl-3">&quot;processData&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Callbacks</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">deleteCallback</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
118
+ </code><button type="button">Copy</button></pre>
119
+
120
+ <hr>
121
+ <h2 id="options-and-configuration" class="tsd-anchor-link">Options and Configuration<a href="#options-and-configuration" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Tools can accept configuration options when declared.</p>
122
+ <h3 id="defining-options" class="tsd-anchor-link">Defining Options<a href="#defining-options" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">InferOptions</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">SlackTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">SlackTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Define static Options type</span><br/><span class="hl-1"> </span><span class="hl-4">static</span><span class="hl-1"> </span><span class="hl-2">Options</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-2">workspaceId:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> defaultChannel?</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1"> | </span><span class="hl-5">undefined</span><span class="hl-1">,</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Access via this.options</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">postMessage</span><span class="hl-1">(</span><span class="hl-2">message</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">, </span><span class="hl-2">channel</span><span class="hl-1">?: </span><span class="hl-5">string</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">targetChannel</span><span class="hl-1"> = </span><span class="hl-2">channel</span><span class="hl-1"> || </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">defaultChannel</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">targetChannel</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">throw</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Error</span><span class="hl-1">(</span><span class="hl-3">&quot;No channel specified&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-3">`Posting to </span><span class="hl-4">${</span><span class="hl-2">targetChannel</span><span class="hl-4">}</span><span class="hl-3"> in </span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">workspaceId</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">// Post message...</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
123
+ </code><button type="button">Copy</button></pre>
124
+
125
+ <h3 id="using-options" class="tsd-anchor-link">Using Options<a href="#using-options" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-2">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">slack:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">SlackTool</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">workspaceId:</span><span class="hl-1"> </span><span class="hl-3">&quot;T1234567&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">defaultChannel:</span><span class="hl-1"> </span><span class="hl-3">&quot;#general&quot;</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1">}</span>
126
+ </code><button type="button">Copy</button></pre>
127
+
128
+ <h3 id="required-vs-optional-options" class="tsd-anchor-link">Required vs. Optional Options<a href="#required-vs-optional-options" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-2">static</span><span class="hl-1"> </span><span class="hl-2">Options</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-7">// Required - no default value, not undefined</span><br/><span class="hl-1"> </span><span class="hl-2">apiKey:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">workspaceId:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Optional - has undefined as possible value</span><br/><span class="hl-1"> defaultChannel?</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1"> | </span><span class="hl-5">undefined</span><span class="hl-1">,</span><br/><span class="hl-1"> timeout?</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-12">0</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">number</span><span class="hl-1"> | </span><span class="hl-5">undefined</span><span class="hl-1">,</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Optional with default</span><br/><span class="hl-1"> </span><span class="hl-2">retryCount:</span><span class="hl-1"> </span><span class="hl-12">3</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">number</span><span class="hl-1">,</span><br/><span class="hl-1">};</span>
129
+ </code><button type="button">Copy</button></pre>
130
+
131
+ <hr>
132
+ <h2 id="complete-examples" class="tsd-anchor-link">Complete Examples<a href="#complete-examples" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="example-1-github-integration-tool" class="tsd-anchor-link">Example 1: GitHub Integration Tool<a href="#example-1-github-integration-tool" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>A complete GitHub integration with webhooks and issue management.</p>
133
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">Priority</span><span class="hl-1">, </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">ActivityLinkType</span><span class="hl-1">, </span><span class="hl-2">ActivityType</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Network</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">WebhookRequest</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/network&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Plot</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/plot&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">GitHubTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">GitHubTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">static</span><span class="hl-1"> </span><span class="hl-2">Options</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-2">owner:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">repo:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">token:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">network:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Network</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">urls:</span><span class="hl-1"> [</span><span class="hl-3">&quot;https://api.github.com/*&quot;</span><span class="hl-1">],</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> </span><span class="hl-2">plot:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Plot</span><span class="hl-1">),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">postActivate</span><span class="hl-1">(</span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-5">Priority</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Set up webhook for issue updates</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">webhookUrl</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">network</span><span class="hl-1">.</span><span class="hl-6">createWebhook</span><span class="hl-1">(</span><span class="hl-3">&quot;onIssueUpdate&quot;</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">priorityId:</span><span class="hl-1"> </span><span class="hl-2">priority</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">&quot;webhook_url&quot;</span><span class="hl-1">, </span><span class="hl-2">webhookUrl</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Register webhook with GitHub</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">registerWebhook</span><span class="hl-1">(</span><span class="hl-2">webhookUrl</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">preDeactivate</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Cleanup webhook</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">webhookUrl</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt;(</span><span class="hl-3">&quot;webhook_url&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">webhookUrl</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">unregisterWebhook</span><span class="hl-1">(</span><span class="hl-2">webhookUrl</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">network</span><span class="hl-1">.</span><span class="hl-6">deleteWebhook</span><span class="hl-1">(</span><span class="hl-2">webhookUrl</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getIssues</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">any</span><span class="hl-1">[]&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">response</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-6">fetch</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-3">`https://api.github.com/repos/</span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">owner</span><span class="hl-4">}</span><span class="hl-3">/</span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">repo</span><span class="hl-4">}</span><span class="hl-3">/issues`</span><span class="hl-1">,</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">headers:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">Authorization:</span><span class="hl-1"> </span><span class="hl-3">`Bearer </span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">token</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">Accept:</span><span class="hl-1"> </span><span class="hl-3">&quot;application/vnd.github.v3+json&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> );</span><br/><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">response</span><span class="hl-1">.</span><span class="hl-6">json</span><span class="hl-1">();</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">syncIssues</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">issues</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">getIssues</span><span class="hl-1">();</span><br/><br/><span class="hl-1"> </span><span class="hl-0">for</span><span class="hl-1"> (</span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">issue</span><span class="hl-1"> </span><span class="hl-4">of</span><span class="hl-1"> </span><span class="hl-2">issues</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Task</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">title</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">note:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">body</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">meta:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">github_issue_id:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">.</span><span class="hl-6">toString</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-2">github_number:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">number</span><span class="hl-1">.</span><span class="hl-6">toString</span><span class="hl-1">(),</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">links:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityLinkType</span><span class="hl-1">.</span><span class="hl-2">external</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&quot;View on GitHub&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">url:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">html_url</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">onIssueUpdate</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-2">request</span><span class="hl-1">: </span><span class="hl-5">WebhookRequest</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">context</span><span class="hl-1">: { </span><span class="hl-2">priorityId</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1"> }</span><br/><span class="hl-1"> ): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> { </span><span class="hl-8">action</span><span class="hl-1">, </span><span class="hl-8">issue</span><span class="hl-1"> } = </span><span class="hl-2">request</span><span class="hl-1">.</span><span class="hl-2">body</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">action</span><span class="hl-1"> === </span><span class="hl-3">&quot;opened&quot;</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// Create new activity for new issue</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">createActivity</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActivityType</span><span class="hl-1">.</span><span class="hl-2">Task</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">title</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">meta:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">github_issue_id:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">.</span><span class="hl-6">toString</span><span class="hl-1">(),</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> } </span><span class="hl-0">else</span><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">action</span><span class="hl-1"> === </span><span class="hl-3">&quot;closed&quot;</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// Mark activity as done</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">activity</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">getActivityByMeta</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">github_issue_id:</span><span class="hl-1"> </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">.</span><span class="hl-6">toString</span><span class="hl-1">(),</span><br/><span class="hl-1"> });</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">activity</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">plot</span><span class="hl-1">.</span><span class="hl-6">updateActivity</span><span class="hl-1">(</span><span class="hl-2">activity</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">doneAt:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(),</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">private</span><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">registerWebhook</span><span class="hl-1">(</span><span class="hl-2">url</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-6">fetch</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-3">`https://api.github.com/repos/</span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">owner</span><span class="hl-4">}</span><span class="hl-3">/</span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">repo</span><span class="hl-4">}</span><span class="hl-3">/hooks`</span><span class="hl-1">,</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">method:</span><span class="hl-1"> </span><span class="hl-3">&quot;POST&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">headers:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">Authorization:</span><span class="hl-1"> </span><span class="hl-3">`Bearer </span><span class="hl-4">${</span><span class="hl-4">this</span><span class="hl-13">.</span><span class="hl-2">options</span><span class="hl-13">.</span><span class="hl-2">token</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">Accept:</span><span class="hl-1"> </span><span class="hl-3">&quot;application/vnd.github.v3+json&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">body:</span><span class="hl-1"> </span><span class="hl-8">JSON</span><span class="hl-1">.</span><span class="hl-6">stringify</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">config:</span><span class="hl-1"> { </span><span class="hl-2">url</span><span class="hl-1">, </span><span class="hl-2">content_type:</span><span class="hl-1"> </span><span class="hl-3">&quot;json&quot;</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">events:</span><span class="hl-1"> [</span><span class="hl-3">&quot;issues&quot;</span><span class="hl-1">],</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> );</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">private</span><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">unregisterWebhook</span><span class="hl-1">(</span><span class="hl-2">url</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Implementation to remove webhook from GitHub</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
134
+ </code><button type="button">Copy</button></pre>
135
+
136
+ <h3 id="example-2-slack-notification-tool" class="tsd-anchor-link">Example 2: Slack Notification Tool<a href="#example-2-slack-notification-tool" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>A tool for sending Slack notifications.</p>
137
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Tool</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Network</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/network&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">SlackTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">SlackTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">static</span><span class="hl-1"> </span><span class="hl-2">Options</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-2">webhookUrl:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1">,</span><br/><span class="hl-1"> defaultChannel?</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-5">string</span><span class="hl-1"> | </span><span class="hl-5">undefined</span><span class="hl-1">,</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">network:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Network</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">urls:</span><span class="hl-1"> [</span><span class="hl-3">&quot;https://hooks.slack.com/*&quot;</span><span class="hl-1">]</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">sendMessage</span><span class="hl-1">(</span><span class="hl-2">options</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-2">text</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">channel</span><span class="hl-1">?: </span><span class="hl-5">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">username</span><span class="hl-1">?: </span><span class="hl-5">string</span><span class="hl-1">;</span><br/><span class="hl-1"> }): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">payload</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-2">text:</span><span class="hl-1"> </span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">text</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">channel:</span><span class="hl-1"> </span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">channel</span><span class="hl-1"> || </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">defaultChannel</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">username:</span><span class="hl-1"> </span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">username</span><span class="hl-1"> || </span><span class="hl-3">&quot;Plot Bot&quot;</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">response</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-6">fetch</span><span class="hl-1">(</span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">webhookUrl</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">method:</span><span class="hl-1"> </span><span class="hl-3">&quot;POST&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">headers:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">&quot;Content-Type&quot;</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">&quot;application/json&quot;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">body:</span><span class="hl-1"> </span><span class="hl-8">JSON</span><span class="hl-1">.</span><span class="hl-6">stringify</span><span class="hl-1">(</span><span class="hl-2">payload</span><span class="hl-1">)</span><br/><span class="hl-1"> });</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">response</span><span class="hl-1">.</span><span class="hl-2">ok</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">throw</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Error</span><span class="hl-1">(</span><span class="hl-3">`Slack API error: </span><span class="hl-4">${</span><span class="hl-2">response</span><span class="hl-13">.</span><span class="hl-2">statusText</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">sendAlert</span><span class="hl-1">(</span><span class="hl-2">message</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">sendMessage</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">text:</span><span class="hl-1"> </span><span class="hl-3">`:warning: </span><span class="hl-4">${</span><span class="hl-2">message</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">channel:</span><span class="hl-1"> </span><span class="hl-3">&quot;#alerts&quot;</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
138
+ </code><button type="button">Copy</button></pre>
139
+
140
+ <hr>
141
+ <h2 id="testing-tools" class="tsd-anchor-link">Testing Tools<a href="#testing-tools" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="unit-testing" class="tsd-anchor-link">Unit Testing<a href="#unit-testing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">beforeEach</span><span class="hl-1">, </span><span class="hl-2">describe</span><span class="hl-1">, </span><span class="hl-2">expect</span><span class="hl-1">, </span><span class="hl-2">it</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;vitest&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">GitHubTool</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;./github-tool&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-6">describe</span><span class="hl-1">(</span><span class="hl-3">&quot;GitHubTool&quot;</span><span class="hl-1">, () </span><span class="hl-4">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">let</span><span class="hl-1"> </span><span class="hl-2">tool</span><span class="hl-1">: </span><span class="hl-5">GitHubTool</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-6">beforeEach</span><span class="hl-1">(() </span><span class="hl-4">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">tool</span><span class="hl-1"> = </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">GitHubTool</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-3">&quot;test-id&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">owner:</span><span class="hl-1"> </span><span class="hl-3">&quot;test-owner&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">repo:</span><span class="hl-1"> </span><span class="hl-3">&quot;test-repo&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">token:</span><span class="hl-1"> </span><span class="hl-3">&quot;test-token&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">mockToolShed</span><br/><span class="hl-1"> );</span><br/><span class="hl-1"> });</span><br/><br/><span class="hl-1"> </span><span class="hl-6">it</span><span class="hl-1">(</span><span class="hl-3">&quot;fetches issues&quot;</span><span class="hl-1">, </span><span class="hl-4">async</span><span class="hl-1"> () </span><span class="hl-4">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">issues</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">tool</span><span class="hl-1">.</span><span class="hl-6">getIssues</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-6">expect</span><span class="hl-1">(</span><span class="hl-2">issues</span><span class="hl-1">).</span><span class="hl-6">toBeInstanceOf</span><span class="hl-1">(</span><span class="hl-2">Array</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><br/><span class="hl-1"> </span><span class="hl-6">it</span><span class="hl-1">(</span><span class="hl-3">&quot;validates configuration&quot;</span><span class="hl-1">, () </span><span class="hl-4">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">expect</span><span class="hl-1">(</span><span class="hl-2">tool</span><span class="hl-1">.</span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">owner</span><span class="hl-1">).</span><span class="hl-6">toBe</span><span class="hl-1">(</span><span class="hl-3">&quot;test-owner&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-6">expect</span><span class="hl-1">(</span><span class="hl-2">tool</span><span class="hl-1">.</span><span class="hl-2">options</span><span class="hl-1">.</span><span class="hl-2">repo</span><span class="hl-1">).</span><span class="hl-6">toBe</span><span class="hl-1">(</span><span class="hl-3">&quot;test-repo&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">});</span>
142
+ </code><button type="button">Copy</button></pre>
143
+
144
+ <h3 id="integration-testing" class="tsd-anchor-link">Integration Testing<a href="#integration-testing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Test your tool with a real twist:</p>
145
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">twist</span><span class="hl-1">, </span><span class="hl-0">type</span><span class="hl-1"> </span><span class="hl-2">ToolBuilder</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Plot</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister/tools/plot&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">GitHubTool</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;./github-tool&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">TestTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">twist</span><span class="hl-1">&lt;</span><span class="hl-5">TestTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">build</span><span class="hl-1">: </span><span class="hl-5">ToolBuilder</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">plot:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">Plot</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-2">github:</span><span class="hl-1"> </span><span class="hl-6">build</span><span class="hl-1">(</span><span class="hl-2">GitHubTool</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">owner:</span><span class="hl-1"> </span><span class="hl-3">&quot;plotday&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">repo:</span><span class="hl-1"> </span><span class="hl-3">&quot;plot&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">token:</span><span class="hl-1"> </span><span class="hl-2">process</span><span class="hl-1">.</span><span class="hl-2">env</span><span class="hl-1">.</span><span class="hl-8">GITHUB_TOKEN</span><span class="hl-1">!,</span><br/><span class="hl-1"> }),</span><br/><span class="hl-1"> };</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">// Test syncing</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">tools</span><span class="hl-1">.</span><span class="hl-2">github</span><span class="hl-1">.</span><span class="hl-6">syncIssues</span><span class="hl-1">();</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
146
+ </code><button type="button">Copy</button></pre>
147
+
148
+ <hr>
149
+ <h2 id="publishing-tools" class="tsd-anchor-link">Publishing Tools<a href="#publishing-tools" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="package-structure" class="tsd-anchor-link">Package Structure<a href="#package-structure" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-2">my</span><span class="hl-1">-</span><span class="hl-2">plot</span><span class="hl-1">-</span><span class="hl-2">tool</span><span class="hl-1">/</span><br/><span class="hl-1">├── </span><span class="hl-2">src</span><span class="hl-1">/</span><br/><span class="hl-1">│ └── </span><span class="hl-2">index</span><span class="hl-1">.</span><span class="hl-2">ts</span><span class="hl-1"> # </span><span class="hl-2">Tool</span><span class="hl-1"> </span><span class="hl-2">implementation</span><br/><span class="hl-1">├── </span><span class="hl-2">package</span><span class="hl-1">.</span><span class="hl-2">json</span><br/><span class="hl-1">├── </span><span class="hl-2">tsconfig</span><span class="hl-1">.</span><span class="hl-2">json</span><br/><span class="hl-1">├── </span><span class="hl-8">README</span><span class="hl-1">.</span><span class="hl-2">md</span><br/><span class="hl-1">└── </span><span class="hl-8">LICENSE</span>
150
+ </code><button>Copy</button></pre>
151
+
152
+ <h3 id="packagejson" class="tsd-anchor-link">package.json<a href="#packagejson" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;@mycompany/plot-github-tool&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;version&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;1.0.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;description&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;GitHub integration tool for Plot twists&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;main&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;./dist/index.js&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;types&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;./dist/index.d.ts&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;scripts&quot;</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;build&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;tsc&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;test&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;vitest&quot;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;peerDependencies&quot;</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;@plotday/twister&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;^0.16.0&quot;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;devDependencies&quot;</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;@plotday/twister&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;^0.16.0&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-11">&quot;typescript&quot;</span><span class="hl-1">: </span><span class="hl-3">&quot;^5.0.0&quot;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
153
+ </code><button type="button">Copy</button></pre>
154
+
155
+ <h3 id="publishing" class="tsd-anchor-link">Publishing<a href="#publishing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="bash"><span class="hl-7"># Build</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">build</span><br/><br/><span class="hl-7"># Test</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">test</span><br/><br/><span class="hl-7"># Publish</span><br/><span class="hl-6">npm</span><span class="hl-1"> </span><span class="hl-3">publish</span>
156
+ </code><button type="button">Copy</button></pre>
157
+
158
+ <h3 id="documentation" class="tsd-anchor-link">Documentation<a href="#documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Include comprehensive README with:</p>
159
+ <ul>
160
+ <li>Installation instructions</li>
161
+ <li>Configuration options</li>
162
+ <li>Usage examples</li>
163
+ <li>API reference</li>
164
+ </ul>
165
+ <hr>
166
+ <h2 id="best-practices" class="tsd-anchor-link">Best Practices<a href="#best-practices" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="1-single-responsibility" class="tsd-anchor-link">1. Single Responsibility<a href="#1-single-responsibility" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Each tool should have a single, well-defined purpose:</p>
167
+ <pre><code class="typescript"><span class="hl-7">// ✅ GOOD - Focused on GitHub</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">GitHubTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">GitHubTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getIssues</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">/* ... */</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">createIssue</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">/* ... */</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-7">// ❌ BAD - Mixed concerns</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">IntegrationTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">IntegrationTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getGitHubIssues</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">/* ... */</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">sendSlackMessage</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">/* ... */</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">createJiraTicket</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">/* ... */</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
168
+ </code><button type="button">Copy</button></pre>
169
+
170
+ <h3 id="2-type-safety" class="tsd-anchor-link">2. Type Safety<a href="#2-type-safety" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Use TypeScript features for type safety:</p>
171
+ <pre><code class="typescript"><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-5">GitHubIssue</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">id</span><span class="hl-1">: </span><span class="hl-5">number</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">title</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">body</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">state</span><span class="hl-1">: </span><span class="hl-3">&quot;open&quot;</span><span class="hl-1"> | </span><span class="hl-3">&quot;closed&quot;</span><span class="hl-1">;</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">GitHubTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">GitHubTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getIssues</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-5">GitHubIssue</span><span class="hl-1">[]&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Return type is enforced</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
172
+ </code><button type="button">Copy</button></pre>
173
+
174
+ <h3 id="3-error-handling" class="tsd-anchor-link">3. Error Handling<a href="#3-error-handling" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Handle errors gracefully:</p>
175
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">fetchData</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">Data</span><span class="hl-1"> | </span><span class="hl-4">null</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> try {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">response</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-6">fetch</span><span class="hl-1">(</span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">apiUrl</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">response</span><span class="hl-1">.</span><span class="hl-2">ok</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">error</span><span class="hl-1">(</span><span class="hl-3">`API error: </span><span class="hl-4">${</span><span class="hl-2">response</span><span class="hl-13">.</span><span class="hl-2">status</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-4">null</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">response</span><span class="hl-1">.</span><span class="hl-6">json</span><span class="hl-1">();</span><br/><span class="hl-1"> } catch (error) {</span><br/><span class="hl-1"> console.</span><span class="hl-6">error</span><span class="hl-1">(</span><span class="hl-3">&quot;Network error:&quot;</span><span class="hl-1">, </span><span class="hl-2">error</span><span class="hl-1">);</span><br/><span class="hl-1"> return null;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
176
+ </code><button type="button">Copy</button></pre>
177
+
178
+ <h3 id="4-configuration-validation" class="tsd-anchor-link">4. Configuration Validation<a href="#4-configuration-validation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Validate options in preActivate:</p>
179
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">preActivate</span><span class="hl-1">(</span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-2">Priority</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (!this.options.apiKey) {</span><br/><span class="hl-1"> </span><span class="hl-0">throw</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Error</span><span class="hl-1">(</span><span class="hl-3">&quot;API key is required&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (!this.options.workspaceId.startsWith(</span><span class="hl-3">&quot;T&quot;</span><span class="hl-1">)) {</span><br/><span class="hl-1"> </span><span class="hl-0">throw</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Error</span><span class="hl-1">(</span><span class="hl-3">&quot;Invalid workspace ID format&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
180
+ </code><button type="button">Copy</button></pre>
181
+
182
+ <h3 id="5-resource-cleanup" class="tsd-anchor-link">5. Resource Cleanup<a href="#5-resource-cleanup" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Always clean up resources in deactivation:</p>
183
+ <pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">postDeactivate</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Cancel pending tasks</span><br/><span class="hl-1"> await this.cancelAllTasks();</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Delete callbacks</span><br/><span class="hl-1"> await this.deleteAllCallbacks();</span><br/><br/><span class="hl-1"> </span><span class="hl-7">// Clear stored data</span><br/><span class="hl-1"> await this.clearAll();</span><br/><span class="hl-1">}</span>
184
+ </code><button type="button">Copy</button></pre>
185
+
186
+ <h3 id="6-avoid-instance-state" class="tsd-anchor-link">6. Avoid Instance State<a href="#6-avoid-instance-state" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Use Store instead of instance variables:</p>
187
+ <pre><code class="typescript"><span class="hl-7">// ❌ WRONG - Instance state doesn&#39;t persist</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">MyTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">private</span><span class="hl-1"> </span><span class="hl-2">cache</span><span class="hl-1">: </span><span class="hl-5">Map</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">, </span><span class="hl-5">any</span><span class="hl-1">&gt; = </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Map</span><span class="hl-1">();</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-7">// ✅ CORRECT - Use Store</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTool</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Tool</span><span class="hl-1">&lt;</span><span class="hl-5">MyTool</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">getFromCache</span><span class="hl-1">(</span><span class="hl-2">key</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">get</span><span class="hl-1">&lt;</span><span class="hl-5">any</span><span class="hl-1">&gt;(</span><span class="hl-3">`cache:</span><span class="hl-4">${</span><span class="hl-2">key</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">setInCache</span><span class="hl-1">(</span><span class="hl-2">key</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1">, </span><span class="hl-2">value</span><span class="hl-1">: </span><span class="hl-5">any</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">set</span><span class="hl-1">(</span><span class="hl-3">`cache:</span><span class="hl-4">${</span><span class="hl-2">key</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, </span><span class="hl-2">value</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
188
+ </code><button type="button">Copy</button></pre>
189
+
190
+ <h3 id="7-document-your-api" class="tsd-anchor-link">7. Document Your API<a href="#7-document-your-api" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Add JSDoc comments for documentation:</p>
191
+ <pre><code class="typescript"><span class="hl-7">/**</span><br/><span class="hl-7"> * Fetches all open issues from the GitHub repository.</span><br/><span class="hl-7"> *</span><br/><span class="hl-7"> * </span><span class="hl-4">@returns</span><span class="hl-7"> Promise resolving to array of GitHub issues</span><br/><span class="hl-7"> * </span><span class="hl-4">@throws</span><span class="hl-7"> Error if GitHub API is unavailable</span><br/><span class="hl-7"> *</span><br/><span class="hl-7"> * </span><span class="hl-4">@example</span><br/><span class="hl-7"> * ```typescript</span><br/><span class="hl-7"> * const issues = await this.tools.github.getIssues();</span><br/><span class="hl-7"> * ```</span><br/><span class="hl-7"> */</span><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">getIssues</span><span class="hl-1">(): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">GitHubIssue</span><span class="hl-1">[]&gt; {</span><br/><span class="hl-1"> </span><span class="hl-7">// Implementation</span><br/><span class="hl-1">}</span>
192
+ </code><button type="button">Copy</button></pre>
193
+
194
+ <hr>
195
+ <h2 id="next-steps" class="tsd-anchor-link">Next Steps<a href="#next-steps" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
196
+ <li><strong><a href="Built-in_Tools.html">Built-in Tools Guide</a></strong> - Learn from built-in tool patterns</li>
197
+ <li><strong><a href="Advanced.html">Advanced Topics</a></strong> - Complex tool patterns</li>
198
+ <li><strong>API Reference</strong> - Explore the Tool class API</li>
199
+ </ul>
200
+ </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#building-custom-tools"><span>Building <wbr/>Custom <wbr/>Tools</span></a><ul><li><a href="#table-of-contents"><span>Table of <wbr/>Contents</span></a></li><li><a href="#why-build-tools"><span>Why <wbr/>Build <wbr/>Tools?</span></a></li><li><ul><li><a href="#built-in-vs-custom-tools"><span>Built-<wbr/>in vs. <wbr/>Custom <wbr/>Tools</span></a></li></ul></li><li><a href="#tool-basics"><span>Tool <wbr/>Basics</span></a></li><li><ul><li><a href="#minimal-tool-example"><span>Minimal <wbr/>Tool <wbr/>Example</span></a></li><li><a href="#using-your-tool"><span>Using <wbr/>Your <wbr/>Tool</span></a></li></ul></li><li><a href="#tool-structure"><span>Tool <wbr/>Structure</span></a></li><li><ul><li><a href="#class-definition"><span>Class <wbr/>Definition</span></a></li><li><a href="#type-parameter"><span>Type <wbr/>Parameter</span></a></li></ul></li><li><a href="#lifecycle-methods"><span>Lifecycle <wbr/>Methods</span></a></li><li><ul><li><a href="#preactivatepriority"><span>pre<wbr/>Activate(priority)</span></a></li><li><a href="#postactivatepriority"><span>post<wbr/>Activate(priority)</span></a></li><li><a href="#preupgrade"><span>pre<wbr/>Upgrade()</span></a></li><li><a href="#postupgrade"><span>post<wbr/>Upgrade()</span></a></li><li><a href="#predeactivate"><span>pre<wbr/>Deactivate()</span></a></li><li><a href="#postdeactivate"><span>post<wbr/>Deactivate()</span></a></li><li><a href="#execution-order"><span>Execution <wbr/>Order</span></a></li></ul></li><li><a href="#dependencies"><span>Dependencies</span></a></li><li><ul><li><a href="#declaring-dependencies"><span>Declaring <wbr/>Dependencies</span></a></li><li><a href="#accessing-dependencies"><span>Accessing <wbr/>Dependencies</span></a></li><li><a href="#built-in-tool-access"><span>Built-<wbr/>in <wbr/>Tool <wbr/>Access</span></a></li></ul></li><li><a href="#options-and-configuration"><span>Options and <wbr/>Configuration</span></a></li><li><ul><li><a href="#defining-options"><span>Defining <wbr/>Options</span></a></li><li><a href="#using-options"><span>Using <wbr/>Options</span></a></li><li><a href="#required-vs-optional-options"><span>Required vs. <wbr/>Optional <wbr/>Options</span></a></li></ul></li><li><a href="#complete-examples"><span>Complete <wbr/>Examples</span></a></li><li><ul><li><a href="#example-1-github-integration-tool"><span>Example 1: <wbr/>Git<wbr/>Hub <wbr/>Integration <wbr/>Tool</span></a></li><li><a href="#example-2-slack-notification-tool"><span>Example 2: <wbr/>Slack <wbr/>Notification <wbr/>Tool</span></a></li></ul></li><li><a href="#testing-tools"><span>Testing <wbr/>Tools</span></a></li><li><ul><li><a href="#unit-testing"><span>Unit <wbr/>Testing</span></a></li><li><a href="#integration-testing"><span>Integration <wbr/>Testing</span></a></li></ul></li><li><a href="#publishing-tools"><span>Publishing <wbr/>Tools</span></a></li><li><ul><li><a href="#package-structure"><span>Package <wbr/>Structure</span></a></li><li><a href="#packagejson"><span>package.json</span></a></li><li><a href="#publishing"><span>Publishing</span></a></li><li><a href="#documentation"><span>Documentation</span></a></li></ul></li><li><a href="#best-practices"><span>Best <wbr/>Practices</span></a></li><li><ul><li><a href="#1-single-responsibility"><span>1. <wbr/>Single <wbr/>Responsibility</span></a></li><li><a href="#2-type-safety"><span>2. <wbr/>Type <wbr/>Safety</span></a></li><li><a href="#3-error-handling"><span>3. <wbr/>Error <wbr/>Handling</span></a></li><li><a href="#4-configuration-validation"><span>4. <wbr/>Configuration <wbr/>Validation</span></a></li><li><a href="#5-resource-cleanup"><span>5. <wbr/>Resource <wbr/>Cleanup</span></a></li><li><a href="#6-avoid-instance-state"><span>6. <wbr/>Avoid <wbr/>Instance <wbr/>State</span></a></li><li><a href="#7-document-your-api"><span>7. <wbr/>Document <wbr/>Your <wbr/>API</span></a></li></ul></li><li><a href="#next-steps"><span>Next <wbr/>Steps</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>