@zibby/skills 0.1.95 → 0.2.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 (78) hide show
  1. package/README.md +1 -1
  2. package/dist/artifact.d.ts +1 -115
  3. package/dist/browser.d.ts +10 -19
  4. package/dist/chartRender.d.ts +46 -57
  5. package/dist/chartRender.js +1 -1
  6. package/dist/chat-memory.d.ts +26 -330
  7. package/dist/chat-notify.d.ts +30 -409
  8. package/dist/chat-notify.js +3 -3
  9. package/dist/chatProgress.d.ts +28 -47
  10. package/dist/code-scan.d.ts +52 -58
  11. package/dist/codeStats.d.ts +36 -136
  12. package/dist/codeStats.js +1 -1
  13. package/dist/codebaseMemory.d.ts +52 -32
  14. package/dist/codebaseMemory.js +2 -2
  15. package/dist/core-tools.d.ts +10 -131
  16. package/dist/datasetStore.d.ts +52 -179
  17. package/dist/datasetStore.js +12 -3
  18. package/dist/discord.d.ts +32 -68
  19. package/dist/figma.d.ts +5 -408
  20. package/dist/function-skill.d.ts +23 -135
  21. package/dist/function-skill.js +1 -1
  22. package/dist/gbrain.d.ts +46 -114
  23. package/dist/git-write.d.ts +45 -137
  24. package/dist/git-write.js +6 -6
  25. package/dist/git.d.ts +2 -73
  26. package/dist/github.d.ts +2 -1202
  27. package/dist/gitlab.d.ts +55 -1059
  28. package/dist/gitlab.js +2 -2
  29. package/dist/googleDocs.d.ts +39 -175
  30. package/dist/hubspot.d.ts +1 -381
  31. package/dist/index.d.ts +19 -12
  32. package/dist/index.js +157 -148
  33. package/dist/integrations.d.ts +2 -2
  34. package/dist/jira.d.ts +2 -532
  35. package/dist/jira.js +4 -4
  36. package/dist/kvMemory.d.ts +47 -78
  37. package/dist/lark.d.ts +2 -161
  38. package/dist/lark.js +1 -1
  39. package/dist/larkDocs.d.ts +35 -236
  40. package/dist/linear.d.ts +36 -343
  41. package/dist/linkedin.d.ts +10 -120
  42. package/dist/llm-billing.d.ts +92 -180
  43. package/dist/llm-billing.js +1 -1
  44. package/dist/memory.d.ts +11 -137
  45. package/dist/notion.d.ts +28 -276
  46. package/dist/notion.js +4 -4
  47. package/dist/opendesign.d.ts +24 -202
  48. package/dist/opendesign.js +2 -2
  49. package/dist/package.json +3 -2
  50. package/dist/plane.d.ts +40 -24
  51. package/dist/report.d.ts +153 -110
  52. package/dist/review-dedup.d.ts +8 -8
  53. package/dist/review.d.ts +12 -2
  54. package/dist/reviewMemoryIo.d.ts +37 -3
  55. package/dist/reviewRecord.d.ts +41 -47
  56. package/dist/sentry.d.ts +25 -22
  57. package/dist/skill-installer.d.ts +11 -86
  58. package/dist/slack.d.ts +1 -284
  59. package/dist/socialCard.d.ts +35 -89
  60. package/dist/test-runner.d.ts +1 -220
  61. package/dist/trackers/github-adapter.d.ts +39 -94
  62. package/dist/trackers/index.d.ts +25 -18
  63. package/dist/trackers/jira-adapter.d.ts +20 -88
  64. package/dist/trackers/linear-adapter.d.ts +24 -87
  65. package/dist/trackers/plane-adapter.d.ts +29 -85
  66. package/dist/trackers/plane-adapter.js +1 -1
  67. package/dist/trackers/types.d.ts +1 -186
  68. package/dist/triggerAgent.d.ts +26 -42
  69. package/dist/triggerAgent.js +1 -1
  70. package/dist/workflow-builder.d.ts +11 -245
  71. package/docs/cli-reference.md +33 -0
  72. package/docs/concepts/designing-agents.md +201 -0
  73. package/docs/self-host/backup-restore.md +52 -0
  74. package/docs/self-host/index.md +75 -0
  75. package/docs/self-host/storage.md +50 -0
  76. package/docs/self-host/troubleshooting.md +48 -0
  77. package/docs/self-host/upgrade.md +81 -0
  78. package/package.json +3 -2
package/dist/notion.d.ts CHANGED
@@ -1,3 +1,27 @@
1
+ /**
2
+ * Notion skill — read context + write pages/blocks/images.
3
+ *
4
+ * Historically read-only (pull a page/database as markdown context for a
5
+ * downstream agent, e.g. a code-review agent reading an
6
+ * engineering-standards page). It now ALSO delivers content: create pages,
7
+ * append blocks, and insert images — the Notion twin of googleDocs.js /
8
+ * larkDocs.js for the report-delivery channels.
9
+ *
10
+ * Modelled on jira.js:
11
+ * - resolveIntegrationToken('notion') is the SINGLE auth chokepoint
12
+ * (via the notionApi() helper below). Don't re-resolve at call sites.
13
+ * - handleToolCall() dispatches the tools and NEVER throws — any HTTP
14
+ * or parse failure is returned as { ok:false, error } so an optional
15
+ * context source can't crash the review.
16
+ *
17
+ * Token shape (GET /integrations/token/notion → resolveIntegrationToken):
18
+ * { provider:'notion', token, workspaceId, workspaceName, botId, expiresInSec }
19
+ * We only need `token` here — it's a long-lived Notion bearer (no refresh).
20
+ *
21
+ * Served over MCP via the generic bin/mcp-skill.mjs (resolve() below) so
22
+ * the agent gets real mcp__notion__* tools; deterministic node code can
23
+ * also call handleToolCall directly, same as jira/slack.
24
+ */
1
25
  /**
2
26
  * Extract a 32-char Notion id from a raw id OR a Notion URL.
3
27
  *
@@ -11,7 +35,7 @@
11
35
  * Returns the dashed UUID form (which the Notion REST API accepts), or
12
36
  * null if no id can be found.
13
37
  */
14
- export function parseNotionId(ref: any): string;
38
+ export declare function parseNotionId(ref: any): string;
15
39
  /**
16
40
  * Low-level Notion REST helper. Resolves the bearer via
17
41
  * resolveIntegrationToken('notion'), sets the required Notion-Version
@@ -22,7 +46,7 @@ export function parseNotionId(ref: any): string;
22
46
  * multipart/form-data, not JSON) — fetch sets the multipart boundary itself,
23
47
  * so no Content-Type is set for it.
24
48
  */
25
- export function notionApi(path: any, opts?: {}): Promise<any>;
49
+ export declare function notionApi(path: any, opts?: any): Promise<any>;
26
50
  /**
27
51
  * Map a small, common subset of markdown into Notion block objects.
28
52
  * Each block is a single line: headings (#/##/### → heading_1/2/3), bullets
@@ -30,277 +54,5 @@ export function notionApi(path: any, opts?: {}): Promise<any>;
30
54
  * as literal text (content preserved; no annotation parsing — honest +
31
55
  * robust). Empty lines are skipped. Mirrors larkDocs.js markdownToLarkBlocks.
32
56
  */
33
- export function markdownToNotionBlocks(markdown: any): {
34
- [x: string]: string | {
35
- rich_text: {
36
- type: string;
37
- text: {
38
- content: string;
39
- };
40
- }[];
41
- };
42
- object: string;
43
- type: string;
44
- }[];
45
- export namespace notionSkill {
46
- let id: string;
47
- let serverName: string;
48
- let allowedTools: string[];
49
- let requiresIntegration: "notion";
50
- let description: string;
51
- let promptFragment: string;
52
- /**
53
- * Spawn the GENERIC skill MCP server (bin/mcp-skill.mjs) pointing at this
54
- * module's notionSkill export, so the AGENT gets real mcp__notion__* tools
55
- * and can pull a referenced page itself (the agent-driven code-review flow).
56
- *
57
- * Previously this returned null (no MCP server) because Notion was only ever
58
- * called by deterministic node code via handleToolCall — there was no agent
59
- * tool surface. Now the review agent gathers context itself, so it needs the
60
- * tools. The bin imports ../dist/notion.js (resolved relative to bin/, like
61
- * mcp-sentry.mjs) and dispatches through handleToolCall; auth flows through
62
- * the INHERITED env (PROJECT_API_TOKEN → resolveIntegrationToken('notion')),
63
- * so no provider-specific env keys are needed here. When unconnected,
64
- * handleToolCall returns { ok:false, error } — the agent tolerates it.
65
- */
66
- function resolve(): {
67
- type: string;
68
- command: string;
69
- args: any[];
70
- env: {};
71
- description: string;
72
- alwaysLoad: boolean;
73
- };
74
- function handleToolCall(name: any, args: any): Promise<string>;
75
- let tools: ({
76
- name: string;
77
- description: string;
78
- input_schema: {
79
- type: string;
80
- properties: {
81
- pageId: {
82
- type: string;
83
- description: string;
84
- };
85
- databaseId?: undefined;
86
- filter?: undefined;
87
- maxResults?: undefined;
88
- parentPageId?: undefined;
89
- title?: undefined;
90
- markdown?: undefined;
91
- blocks?: undefined;
92
- imagePath?: undefined;
93
- imageUrl?: undefined;
94
- caption?: undefined;
95
- blockId?: undefined;
96
- discussionId?: undefined;
97
- text?: undefined;
98
- };
99
- required: string[];
100
- };
101
- } | {
102
- name: string;
103
- description: string;
104
- input_schema: {
105
- type: string;
106
- properties: {
107
- databaseId: {
108
- type: string;
109
- description: string;
110
- };
111
- filter: {
112
- type: string;
113
- description: string;
114
- additionalProperties: boolean;
115
- };
116
- maxResults: {
117
- type: string;
118
- description: string;
119
- };
120
- pageId?: undefined;
121
- parentPageId?: undefined;
122
- title?: undefined;
123
- markdown?: undefined;
124
- blocks?: undefined;
125
- imagePath?: undefined;
126
- imageUrl?: undefined;
127
- caption?: undefined;
128
- blockId?: undefined;
129
- discussionId?: undefined;
130
- text?: undefined;
131
- };
132
- required: string[];
133
- };
134
- } | {
135
- name: string;
136
- description: string;
137
- input_schema: {
138
- type: string;
139
- properties: {
140
- parentPageId: {
141
- type: string;
142
- description: string;
143
- };
144
- databaseId: {
145
- type: string;
146
- description: string;
147
- };
148
- title: {
149
- type: string;
150
- description: string;
151
- };
152
- markdown: {
153
- type: string;
154
- description: string;
155
- };
156
- blocks: {
157
- type: string;
158
- description: string;
159
- items: {
160
- type: string;
161
- additionalProperties: boolean;
162
- };
163
- };
164
- pageId?: undefined;
165
- filter?: undefined;
166
- maxResults?: undefined;
167
- imagePath?: undefined;
168
- imageUrl?: undefined;
169
- caption?: undefined;
170
- blockId?: undefined;
171
- discussionId?: undefined;
172
- text?: undefined;
173
- };
174
- required: string[];
175
- };
176
- } | {
177
- name: string;
178
- description: string;
179
- input_schema: {
180
- type: string;
181
- properties: {
182
- pageId: {
183
- type: string;
184
- description: string;
185
- };
186
- markdown: {
187
- type: string;
188
- description: string;
189
- };
190
- blocks: {
191
- type: string;
192
- description: string;
193
- items: {
194
- type: string;
195
- additionalProperties: boolean;
196
- };
197
- };
198
- databaseId?: undefined;
199
- filter?: undefined;
200
- maxResults?: undefined;
201
- parentPageId?: undefined;
202
- title?: undefined;
203
- imagePath?: undefined;
204
- imageUrl?: undefined;
205
- caption?: undefined;
206
- blockId?: undefined;
207
- discussionId?: undefined;
208
- text?: undefined;
209
- };
210
- required: string[];
211
- };
212
- } | {
213
- name: string;
214
- description: string;
215
- input_schema: {
216
- type: string;
217
- properties: {
218
- pageId: {
219
- type: string;
220
- description: string;
221
- };
222
- imagePath: {
223
- type: string;
224
- description: string;
225
- };
226
- imageUrl: {
227
- type: string;
228
- description: string;
229
- };
230
- caption: {
231
- type: string;
232
- description: string;
233
- };
234
- databaseId?: undefined;
235
- filter?: undefined;
236
- maxResults?: undefined;
237
- parentPageId?: undefined;
238
- title?: undefined;
239
- markdown?: undefined;
240
- blocks?: undefined;
241
- blockId?: undefined;
242
- discussionId?: undefined;
243
- text?: undefined;
244
- };
245
- required: string[];
246
- };
247
- } | {
248
- name: string;
249
- description: string;
250
- input_schema: {
251
- type: string;
252
- properties: {
253
- blockId: {
254
- type: string;
255
- description: string;
256
- };
257
- pageId?: undefined;
258
- databaseId?: undefined;
259
- filter?: undefined;
260
- maxResults?: undefined;
261
- parentPageId?: undefined;
262
- title?: undefined;
263
- markdown?: undefined;
264
- blocks?: undefined;
265
- imagePath?: undefined;
266
- imageUrl?: undefined;
267
- caption?: undefined;
268
- discussionId?: undefined;
269
- text?: undefined;
270
- };
271
- required: string[];
272
- };
273
- } | {
274
- name: string;
275
- description: string;
276
- input_schema: {
277
- type: string;
278
- properties: {
279
- discussionId: {
280
- type: string;
281
- description: string;
282
- };
283
- pageId: {
284
- type: string;
285
- description: string;
286
- };
287
- text: {
288
- type: string;
289
- description: string;
290
- };
291
- databaseId?: undefined;
292
- filter?: undefined;
293
- maxResults?: undefined;
294
- parentPageId?: undefined;
295
- title?: undefined;
296
- markdown?: undefined;
297
- blocks?: undefined;
298
- imagePath?: undefined;
299
- imageUrl?: undefined;
300
- caption?: undefined;
301
- blockId?: undefined;
302
- };
303
- required: string[];
304
- };
305
- })[];
306
- }
57
+ export declare function markdownToNotionBlocks(markdown: any): any[];
58
+ export declare const notionSkill: any;
package/dist/notion.js CHANGED
@@ -1,10 +1,10 @@
1
- import{existsSync as R,statSync as A,readFileSync as L}from"fs";import{fileURLToPath as $}from"url";import{basename as U,dirname as T,resolve as v}from"path";import{resolveIntegrationToken as j,clearTokenCache as E}from"@zibby/core/backend-client.js";var y=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),X=Object.freeze({sentry:{id:"sentry",name:"Sentry",connectPath:"/integrations?provider=sentry"},jira:{id:"jira",name:"Jira",connectPath:"/integrations?provider=jira"},github:{id:"github",name:"GitHub",connectPath:"/integrations?provider=github"},gitlab:{id:"gitlab",name:"GitLab",connectPath:"/integrations?provider=gitlab"},slack:{id:"slack",name:"Slack",connectPath:"/integrations?provider=slack"},lark:{id:"lark",name:"Lark",connectPath:"/integrations?provider=lark"},openai_billing:{id:"openai_billing",name:"OpenAI Admin",connectPath:"/integrations?provider=openai_billing"},anthropic_billing:{id:"anthropic_billing",name:"Anthropic Admin",connectPath:"/integrations?provider=anthropic_billing"},cursor_admin:{id:"cursor_admin",name:"Cursor Admin",connectPath:"/integrations?provider=cursor_admin"},notion:{id:"notion",name:"Notion",connectPath:"/integrations?provider=notion"},google:{id:"google",name:"Google Docs",connectPath:"/integrations?provider=google"},plane:{id:"plane",name:"Plane",connectPath:"/integrations?provider=plane"},linear:{id:"linear",name:"Linear",connectPath:"/integrations?provider=linear"},figma:{id:"figma",name:"Figma",connectPath:"/integrations?provider=figma"},hubspot:{id:"hubspot",name:"HubSpot",connectPath:"/integrations?provider=hubspot"},open_design:{id:"open_design",name:"OpenDesign",connectPath:"/integrations?provider=open_design"},linkedin_personal:{id:"linkedin_personal",name:"LinkedIn (Personal)",connectPath:"/integrations?provider=linkedin_personal"},linkedin_business:{id:"linkedin_business",name:"LinkedIn (Business)",connectPath:"/integrations?provider=linkedin_business"},discord:{id:"discord",name:"Discord",connectPath:"/integrations?provider=discord"}});function q(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let i=T($(import.meta.url)),e=v(i,"..","bin","mcp-skill.mjs");return R(e)?e:null}var B="2022-06-28",C="https://api.notion.com/v1",h=2e4,I=25,D=25,b=100,N=500,J=20*1024*1024;function u(i){if(!i||typeof i!="string")return null;let t=i.trim().split(/[?#]/)[0],n=t.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/);if(n)return n[0].toLowerCase();let o=t.match(/[0-9a-fA-F]{32}/g);if(o&&o.length){let r=o[o.length-1].toLowerCase();return`${r.slice(0,8)}-${r.slice(8,12)}-${r.slice(12,16)}-${r.slice(16,20)}-${r.slice(20)}`}return null}async function p(i,e={}){let t=async()=>{let{token:n}=await j("notion");if(typeof n!="string"||!n)throw new Error(`Invalid notion token type: ${typeof n}`);let o=await fetch(`${C}${i}`,{method:e.method||"GET",headers:{Authorization:`Bearer ${n}`,"Notion-Version":B,Accept:"application/json",...e.body&&!e.formData?{"Content-Type":"application/json"}:{},...e.headers},body:e.formData?e.formData:e.body?JSON.stringify(e.body):void 0});if(!o.ok){let s=await o.text().catch(()=>"");throw new Error(`Notion API ${o.status}: ${s.slice(0,300)}`)}let r=await o.text().catch(()=>"");if(!r||!r.trim())return{};try{return JSON.parse(r)}catch{return{raw:r}}};try{return await t()}catch(n){let o=String(n?.message||n||"").toLowerCase();if(!(o.includes("token")||o.includes("401")||o.includes("unauthorized")))throw n;return E("notion"),t()}}function g(i){if(!Array.isArray(i))return"";let e="";for(let t of i){let n=t?.plain_text??t?.text?.content??"";if(!n)continue;let o=t.annotations||{};o.code&&(n=`\`${n}\``),o.bold&&(n=`**${n}**`),o.italic&&(n=`_${n}_`),o.strikethrough&&(n=`~~${n}~~`);let r=t?.href||t?.text?.link?.url;r&&(n=`[${n}](${r})`),e+=n}return e}function M(i,e,t){let n=i?.type,o=i?.[n]||{},r=" ".repeat(Math.max(0,e)),s=(c="rich_text")=>g(o[c]),a;switch(n){case"paragraph":a=s();break;case"heading_1":a=`# ${s()}`;break;case"heading_2":a=`## ${s()}`;break;case"heading_3":a=`### ${s()}`;break;case"bulleted_list_item":a=`${r}- ${s()}`;break;case"numbered_list_item":a=`${r}1. ${s()}`;break;case"to_do":a=`${r}- [${o.checked?"x":" "}] ${s()}`;break;case"toggle":a=`${r}- ${s()}`;break;case"quote":a=`> ${s()}`;break;case"callout":{a=`> ${o.icon?.emoji?`${o.icon.emoji} `:""}${s()}`;break}case"code":{a=`\`\`\`${o.language||""}
1
+ import{existsSync as R,statSync as A,readFileSync as L}from"fs";import{fileURLToPath as $}from"url";import{basename as U,dirname as T,resolve as v}from"path";import{resolveIntegrationToken as j,clearTokenCache as E}from"@zibby/core/backend-client.js";var _=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),X=Object.freeze({sentry:{id:"sentry",name:"Sentry",connectPath:"/integrations?provider=sentry"},jira:{id:"jira",name:"Jira",connectPath:"/integrations?provider=jira"},github:{id:"github",name:"GitHub",connectPath:"/integrations?provider=github"},gitlab:{id:"gitlab",name:"GitLab",connectPath:"/integrations?provider=gitlab"},slack:{id:"slack",name:"Slack",connectPath:"/integrations?provider=slack"},lark:{id:"lark",name:"Lark",connectPath:"/integrations?provider=lark"},openai_billing:{id:"openai_billing",name:"OpenAI Admin",connectPath:"/integrations?provider=openai_billing"},anthropic_billing:{id:"anthropic_billing",name:"Anthropic Admin",connectPath:"/integrations?provider=anthropic_billing"},cursor_admin:{id:"cursor_admin",name:"Cursor Admin",connectPath:"/integrations?provider=cursor_admin"},notion:{id:"notion",name:"Notion",connectPath:"/integrations?provider=notion"},google:{id:"google",name:"Google Docs",connectPath:"/integrations?provider=google"},plane:{id:"plane",name:"Plane",connectPath:"/integrations?provider=plane"},linear:{id:"linear",name:"Linear",connectPath:"/integrations?provider=linear"},figma:{id:"figma",name:"Figma",connectPath:"/integrations?provider=figma"},hubspot:{id:"hubspot",name:"HubSpot",connectPath:"/integrations?provider=hubspot"},open_design:{id:"open_design",name:"OpenDesign",connectPath:"/integrations?provider=open_design"},linkedin_personal:{id:"linkedin_personal",name:"LinkedIn (Personal)",connectPath:"/integrations?provider=linkedin_personal"},linkedin_business:{id:"linkedin_business",name:"LinkedIn (Business)",connectPath:"/integrations?provider=linkedin_business"},discord:{id:"discord",name:"Discord",connectPath:"/integrations?provider=discord"}});function q(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let i=T($(import.meta.url)),e=v(i,"..","bin","mcp-skill.mjs");return R(e)?e:null}var B="2022-06-28",C="https://api.notion.com/v1",h=2e4,I=25,D=25,b=100,N=500,J=20*1024*1024;function u(i){if(!i||typeof i!="string")return null;let t=i.trim().split(/[?#]/)[0],n=t.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/);if(n)return n[0].toLowerCase();let o=t.match(/[0-9a-fA-F]{32}/g);if(o&&o.length){let r=o[o.length-1].toLowerCase();return`${r.slice(0,8)}-${r.slice(8,12)}-${r.slice(12,16)}-${r.slice(16,20)}-${r.slice(20)}`}return null}async function p(i,e={}){let t=async()=>{let{token:n}=await j("notion");if(typeof n!="string"||!n)throw new Error(`Invalid notion token type: ${typeof n}`);let o=await fetch(`${C}${i}`,{method:e.method||"GET",headers:{Authorization:`Bearer ${n}`,"Notion-Version":B,Accept:"application/json",...e.body&&!e.formData?{"Content-Type":"application/json"}:{},...e.headers},body:e.formData?e.formData:e.body?JSON.stringify(e.body):void 0});if(!o.ok){let s=await o.text().catch(()=>"");throw new Error(`Notion API ${o.status}: ${s.slice(0,300)}`)}let r=await o.text().catch(()=>"");if(!r||!r.trim())return{};try{return JSON.parse(r)}catch{return{raw:r}}};try{return await t()}catch(n){let o=String(n?.message||n||"").toLowerCase();if(!(o.includes("token")||o.includes("401")||o.includes("unauthorized")))throw n;return E("notion"),t()}}function g(i){if(!Array.isArray(i))return"";let e="";for(let t of i){let n=t?.plain_text??t?.text?.content??"";if(!n)continue;let o=t.annotations||{};o.code&&(n=`\`${n}\``),o.bold&&(n=`**${n}**`),o.italic&&(n=`_${n}_`),o.strikethrough&&(n=`~~${n}~~`);let r=t?.href||t?.text?.link?.url;r&&(n=`[${n}](${r})`),e+=n}return e}function M(i,e,t){let n=i?.type,o=i?.[n]||{},r=" ".repeat(Math.max(0,e)),s=(c="rich_text")=>g(o[c]),a;switch(n){case"paragraph":a=s();break;case"heading_1":a=`# ${s()}`;break;case"heading_2":a=`## ${s()}`;break;case"heading_3":a=`### ${s()}`;break;case"bulleted_list_item":a=`${r}- ${s()}`;break;case"numbered_list_item":a=`${r}1. ${s()}`;break;case"to_do":a=`${r}- [${o.checked?"x":" "}] ${s()}`;break;case"toggle":a=`${r}- ${s()}`;break;case"quote":a=`> ${s()}`;break;case"callout":{a=`> ${o.icon?.emoji?`${o.icon.emoji} `:""}${s()}`;break}case"code":{a=`\`\`\`${o.language||""}
2
2
  ${s()}
3
3
  \`\`\``;break}case"divider":a="---";break;case"child_page":a=`[child page: ${o.title||""}]`;break;case"child_database":a=`[child database: ${o.title||""}]`;break;case"bookmark":case"embed":case"link_preview":a=o.url?`<${o.url}>`:"";break;case"equation":a=o.expression?`$${o.expression}$`:"";break;case"table":case"column_list":case"column":a="";break;case"table_row":{let c=(o.cells||[]).map(l=>g(l).trim());a=`${r}| ${c.join(" | ")} |`;break}default:a=s();break}let d=[];return a&&a.trim()&&d.push(a),t&&t.trim()&&d.push(t),d.join(`
4
4
  `)}async function S(i,e,t){let n=[],o,r=0;do{if(t.used>=h)break;let s=new URLSearchParams({page_size:"100"});o&&s.set("start_cursor",o);let a=await p(`/blocks/${i}/children?${s.toString()}`),d=Array.isArray(a.results)?a.results:[];for(let c of d){let l="";c.has_children&&(l=await S(c.id,e+1,t));let m=M(c,e,l);if(m&&(n.push(m),t.used+=m.length+1),t.used>=h)break}o=a.has_more?a.next_cursor:void 0,r+=1}while(o&&r<D);return n.join(`
5
- `)}function w(i){let e=i?.properties||{};for(let t of Object.values(e))if(t?.type==="title"){let n=g(t.title).trim();if(n)return n}return""}function f(i){let e=String(i??"");if(!e)return[{type:"text",text:{content:""}}];let t=[];for(let n=0;n<e.length;n+=2e3)t.push({type:"text",text:{content:e.slice(n,n+2e3)}});return t}function G(i){return{id:i?.id||"",discussionId:i?.discussion_id||"",text:g(i?.rich_text).trim(),author:i?.created_by?.id||"",createdTime:i?.created_time||""}}function F(i){if(!i||!i.type)return"";switch(i.type){case"title":return g(i.title).trim();case"rich_text":return g(i.rich_text).trim();case"number":return i.number==null?"":String(i.number);case"select":return i.select?.name||"";case"status":return i.status?.name||"";case"multi_select":return(i.multi_select||[]).map(t=>t.name).join(", ");case"checkbox":return i.checkbox?"true":"false";case"url":return i.url||"";case"email":return i.email||"";case"phone_number":return i.phone_number||"";case"date":return i.date?.start||"";case"people":return(i.people||[]).map(t=>t.name||t.id).join(", ");default:return""}}function k(i){return`https://www.notion.so/${String(i||"").replace(/-/g,"")}`}function H(i){let e=String(i??"").replace(/\r\n/g,`
5
+ `)}function w(i){let e=i?.properties||{};for(let t of Object.values(e))if(t?.type==="title"){let n=g(t.title).trim();if(n)return n}return""}function f(i){let e=String(i??"");if(!e)return[{type:"text",text:{content:""}}];let t=[];for(let n=0;n<e.length;n+=2e3)t.push({type:"text",text:{content:e.slice(n,n+2e3)}});return t}function G(i){return{id:i?.id||"",discussionId:i?.discussion_id||"",text:g(i?.rich_text).trim(),author:i?.created_by?.id||"",createdTime:i?.created_time||""}}function F(i){if(!i||!i.type)return"";switch(i.type){case"title":return g(i.title).trim();case"rich_text":return g(i.rich_text).trim();case"number":return i.number==null?"":String(i.number);case"select":return i.select?.name||"";case"status":return i.status?.name||"";case"multi_select":return(i.multi_select||[]).map(t=>t.name).join(", ");case"checkbox":return i.checkbox?"true":"false";case"url":return i.url||"";case"email":return i.email||"";case"phone_number":return i.phone_number||"";case"date":return i.date?.start||"";case"people":return(i.people||[]).map(t=>t.name||t.id).join(", ");default:return""}}function y(i){return`https://www.notion.so/${String(i||"").replace(/-/g,"")}`}function H(i){let e=String(i??"").replace(/\r\n/g,`
6
6
  `),t=[];for(let n of e.split(`
7
- `)){let o=n.replace(/\s+$/,"");if(!o.trim())continue;let r=/^(#{1,3})\s+(.*)$/.exec(o),s=/^\s*[-*]\s+(.*)$/.exec(o),a=/^\s*\d+[.)]\s+(.*)$/.exec(o),d,c;r?(d=`heading_${r[1].length}`,c=r[2]):s?(d="bulleted_list_item",c=s[1]):a?(d="numbered_list_item",c=a[1]):(d="paragraph",c=o),t.push({object:"block",type:d,[d]:{rich_text:f(c)}})}return t}function x(i){return Array.isArray(i?.blocks)&&i.blocks.length?i.blocks.slice(0,N):typeof i?.markdown=="string"&&i.markdown.trim()?H(i.markdown).slice(0,N):null}async function P(i,e){for(let t=0;t<e.length;t+=b)await p(`/blocks/${i}/children`,{method:"PATCH",body:{children:e.slice(t,t+b)}})}function z(i){let e=typeof i=="string"?i.trim():"";if(!e)throw new Error("imagePath is required");if(!R(e)||!A(e).isFile())throw new Error(`imagePath not found (or not a file): ${e}`);if(!/\.(png|jpe?g)$/i.test(e))throw new Error("imagePath must be a .png or .jpg/.jpeg file");let t=L(e);if(t.length>J)throw new Error(`image is ${(t.length/(1024*1024)).toFixed(1)}MB \u2014 max 20MB (Notion single_part upload cap)`);return t}async function K(i){let e=z(i),t=U(i.trim()),n=/\.png$/i.test(t)?"image/png":"image/jpeg",r=(await p("/file_uploads",{method:"POST",body:{mode:"single_part",filename:t}}))?.id;if(!r)throw new Error("Notion file upload create returned no id");let s=new FormData;return s.set("file",new Blob([e],{type:n}),t),await p(`/file_uploads/${r}/send`,{method:"POST",formData:s}),r}var te={id:"notion",serverName:"notion",allowedTools:["mcp__notion__*"],requiresIntegration:y.NOTION,description:"Notion \u2014 read pages/databases as context + create pages, append blocks, and insert images",promptFragment:`## Notion (connected)
7
+ `)){let o=n.replace(/\s+$/,"");if(!o.trim())continue;let r=/^(#{1,3})\s+(.*)$/.exec(o),s=/^\s*[-*]\s+(.*)$/.exec(o),a=/^\s*\d+[.)]\s+(.*)$/.exec(o),d,c;r?(d=`heading_${r[1].length}`,c=r[2]):s?(d="bulleted_list_item",c=s[1]):a?(d="numbered_list_item",c=a[1]):(d="paragraph",c=o),t.push({object:"block",type:d,[d]:{rich_text:f(c)}})}return t}function x(i){return Array.isArray(i?.blocks)&&i.blocks.length?i.blocks.slice(0,N):typeof i?.markdown=="string"&&i.markdown.trim()?H(i.markdown).slice(0,N):null}async function P(i,e){for(let t=0;t<e.length;t+=b)await p(`/blocks/${i}/children`,{method:"PATCH",body:{children:e.slice(t,t+b)}})}function z(i){let e=typeof i=="string"?i.trim():"";if(!e)throw new Error("imagePath is required");if(!R(e)||!A(e).isFile())throw new Error(`imagePath not found (or not a file): ${e}`);if(!/\.(png|jpe?g)$/i.test(e))throw new Error("imagePath must be a .png or .jpg/.jpeg file");let t=L(e);if(t.length>J)throw new Error(`image is ${(t.length/(1024*1024)).toFixed(1)}MB \u2014 max 20MB (Notion single_part upload cap)`);return t}async function K(i){let e=z(i),t=U(i.trim()),n=/\.png$/i.test(t)?"image/png":"image/jpeg",r=(await p("/file_uploads",{method:"POST",body:{mode:"single_part",filename:t}}))?.id;if(!r)throw new Error("Notion file upload create returned no id");let s=new FormData;return s.set("file",new Blob([e],{type:n}),t),await p(`/file_uploads/${r}/send`,{method:"POST",formData:s}),r}var te={id:"notion",serverName:"notion",allowedTools:["mcp__notion__*"],requiresIntegration:_.NOTION,description:"Notion \u2014 read pages/databases as context + create pages, append blocks, and insert images",promptFragment:`## Notion (connected)
8
8
  You can read Notion content as context AND write to Notion (create pages, append blocks, insert images).
9
9
  - notion_get_page: pass a Notion page id OR a full Notion URL; returns { id, title, url, text } where text is the page flattened to markdown (truncated to ~20k chars). Use the text as reference context.
10
10
  - notion_query_database: pass a database id/URL; returns a small list of rows ({ id, title, url, props }). Use to find a specific page, then notion_get_page it.
@@ -13,4 +13,4 @@ You can read Notion content as context AND write to Notion (create pages, append
13
13
  - notion_insert_image: append an image block to a page. Pass { pageId, imagePath } for a LOCAL png/jpg file (\u226420MB, uploaded via Notion's File Upload API) or { pageId, imageUrl } for an external, publicly reachable image URL. Optional caption. Returns { ok, pageId, url }.
14
14
  - notion_list_comments: pass a page/block id OR URL; returns the open comment discussions on it ({ id, discussionId, text, author }). Use to read the comment thread you are replying to.
15
15
  - notion_add_comment: post a comment. To REPLY in an existing discussion pass { discussionId, text }; to start a NEW top-level comment on a page pass { pageId, text }. Returns { ok, id, discussionId }. Use this to answer a user who @mentioned Zibby in a Notion comment \u2014 reply in the SAME discussionId.
16
- Do not block the task if Notion is unavailable \u2014 these tools return { ok:false, error } on failure; treat a missing page as "no extra context" / "cannot deliver to Notion" and continue.`,resolve(){let i=q();return i?{type:"stdio",command:"node",args:[i,"../dist/notion.js","notionSkill"],env:{},description:this.description,alwaysLoad:!0}:null},async handleToolCall(i,e){try{switch(i){case"notion_get_page":{let t=e?.pageId||e?.page||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let o=await p(`/pages/${n}`),r=w(o),s=o?.url||`https://www.notion.so/${n.replace(/-/g,"")}`,d=await S(n,0,{used:0}),c=!1;return d.length>h&&(d=d.slice(0,h),c=!0),JSON.stringify({ok:!0,id:n,title:r,url:s,text:d,...c?{truncated:!0}:{}})}case"notion_query_database":{let t=e?.databaseId||e?.database||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion database id or URL is required"});let r={page_size:Math.max(1,Math.min(Number(e?.maxResults)||I,I))};e?.filter&&typeof e.filter=="object"&&(r.filter=e.filter);let s=await p(`/databases/${n}/query`,{method:"POST",body:r}),d=(Array.isArray(s.results)?s.results:[]).map(c=>{let l={};for(let[m,O]of Object.entries(c.properties||{})){let _=F(O);_&&(l[m]=_)}return{id:c.id,title:w(c),url:c.url||`https://www.notion.so/${String(c.id||"").replace(/-/g,"")}`,props:l}});return JSON.stringify({ok:!0,id:n,count:d.length,hasMore:!!s.has_more,rows:d})}case"notion_create_page":{let t=typeof e?.title=="string"&&e.title.trim()?e.title.trim():null;if(!t)return JSON.stringify({ok:!1,error:"title is required"});let n=e?.databaseId?u(e.databaseId):null,o=e?.parentPageId?u(e.parentPageId):u(e?.parent||e?.pageId);if(!n&&!o)return JSON.stringify({ok:!1,error:"A valid parentPageId or databaseId is required"});let r=n?{database_id:n}:{page_id:o},s={title:{title:f(t)}},a=x(e)||[],d=a.slice(0,b),c=await p("/pages",{method:"POST",body:{parent:r,properties:s,...d.length?{children:d}:{}}}),l=c?.id;if(!l)return JSON.stringify({ok:!1,error:"Notion page create returned no id"});let m=a.slice(b);return m.length&&await P(l,m),JSON.stringify({ok:!0,pageId:l,url:c?.url||k(l)})}case"notion_append_blocks":{let t=u(e?.pageId||e?.blockId||e?.url||e?.id);if(!t)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let n=x(e);return!n||!n.length?JSON.stringify({ok:!1,error:"markdown or blocks content is required"}):(await P(t,n),JSON.stringify({ok:!0,pageId:t,url:k(t)}))}case"notion_insert_image":{let t=u(e?.pageId||e?.url||e?.id);if(!t)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let n=typeof e?.caption=="string"&&e.caption.trim()?f(e.caption.trim()):null,o,r;if(typeof e?.imagePath=="string"&&e.imagePath.trim())r=await K(e.imagePath),o={type:"file_upload",file_upload:{id:r}};else if(typeof e?.imageUrl=="string"&&e.imageUrl.trim())o={type:"external",external:{url:e.imageUrl.trim()}};else return JSON.stringify({ok:!1,error:"imagePath (local png/jpg) or imageUrl is required"});return n&&(o.caption=n),await p(`/blocks/${t}/children`,{method:"PATCH",body:{children:[{object:"block",type:"image",image:o}]}}),JSON.stringify({ok:!0,pageId:t,url:k(t),...r?{fileUploadId:r}:{}})}case"notion_list_comments":{let t=e?.blockId||e?.pageId||e?.block||e?.page||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion page/block id or URL is required"});let o=new URLSearchParams({block_id:n,page_size:"100"}),r=await p(`/comments?${o.toString()}`),a=(Array.isArray(r.results)?r.results:[]).map(G);return JSON.stringify({ok:!0,id:n,count:a.length,comments:a})}case"notion_add_comment":{let t=typeof e?.text=="string"?e.text:typeof e?.body=="string"?e.body:"";if(!t||!t.trim())return JSON.stringify({ok:!1,error:"text is required"});let n=e?.discussionId||e?.discussion_id||null,o;if(n)o={discussion_id:String(n),rich_text:f(t)};else{let s=e?.pageId||e?.page||e?.url||e?.id,a=u(s);if(!a)return JSON.stringify({ok:!1,error:"Either discussionId (to reply) or a valid pageId (to start a comment) is required"});o={parent:{page_id:a},rich_text:f(t)}}let r=await p("/comments",{method:"POST",body:o});return JSON.stringify({ok:!0,id:r?.id||"",discussionId:r?.discussion_id||n||""})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${i}`})}}catch(t){return JSON.stringify({ok:!1,error:t.message})}},tools:[{name:"notion_get_page",description:"Fetch a Notion page and its content flattened to markdown, for use as read-only context. Accepts a raw page id OR a full Notion URL. Returns { ok, id, title, url, text }. Text is truncated to ~20k chars.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."}},required:["pageId"]}},{name:"notion_query_database",description:"Query a Notion database and return a bounded list of rows (id, title, url, key props). Accepts a database id OR full Notion URL. Optional Notion filter object. Returns at most 25 rows.",input_schema:{type:"object",properties:{databaseId:{type:"string",description:"Notion database id (dashed UUID or 32-char) OR a full Notion database URL."},filter:{type:"object",description:"Optional Notion filter object (Notion query filter syntax).",additionalProperties:!0},maxResults:{type:"number",description:"Max rows to return (default 25, max 25)."}},required:["databaseId"]}},{name:"notion_create_page",description:"Create a new Notion page under a parent page (parentPageId) OR in a database (databaseId) \u2014 exactly one parent is required. Body from markdown (#/##/### headings, - bullets, 1. ordered lists; inline marks kept as literal text) or raw Notion block objects. Long bodies are chunked automatically (Notion caps 100 blocks/request). Returns { ok, pageId, url } \u2014 share the url with the user.",input_schema:{type:"object",properties:{parentPageId:{type:"string",description:"Parent PAGE id/URL to create the page under (used when databaseId is absent)."},databaseId:{type:"string",description:"Parent DATABASE id/URL to create the page in (title goes into the title property)."},title:{type:"string",description:"Page title."},markdown:{type:"string",description:"Page body as markdown (preferred)."},blocks:{type:"array",description:"Raw Notion block objects (advanced; used instead of markdown, max 500).",items:{type:"object",additionalProperties:!0}}},required:["title"]}},{name:"notion_append_blocks",description:"Append markdown (or raw Notion blocks) to the END of an existing Notion page. Accepts a page id or full Notion URL. Chunks automatically at Notion's 100-blocks-per-request cap. Returns { ok, pageId, url }.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."},markdown:{type:"string",description:"Content to append, as markdown (preferred)."},blocks:{type:"array",description:"Raw Notion block objects (advanced; used instead of markdown, max 500).",items:{type:"object",additionalProperties:!0}}},required:["pageId"]}},{name:"notion_insert_image",description:"Append an image block to a Notion page. Pass imagePath for a LOCAL .png/.jpg file (max 20MB \u2014 uploaded via Notion's File Upload API, stored by Notion) or imageUrl for an external publicly-reachable image URL. Optional caption. Returns { ok, pageId, url }.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."},imagePath:{type:"string",description:"Local filesystem path to a .png or .jpg/.jpeg image (max 20MB). Preferred for locally rendered charts."},imageUrl:{type:"string",description:"External image URL (must be publicly reachable; used when imagePath is absent)."},caption:{type:"string",description:"Optional image caption."}},required:["pageId"]}},{name:"notion_list_comments",description:"List the open comment discussions on a Notion page/block. Accepts a page/block id OR a full Notion URL. Returns { ok, comments:[{ id, discussionId, text, author }] }. Use to read the comment thread you are replying to.",input_schema:{type:"object",properties:{blockId:{type:"string",description:"Notion page or block id (dashed UUID or 32-char) OR a full Notion URL."}},required:["blockId"]}},{name:"notion_add_comment",description:"Post a comment on Notion. To REPLY within an existing discussion, pass { discussionId, text }. To start a NEW top-level comment on a page, pass { pageId, text }. Returns { ok, id, discussionId }. Use this to answer a user who @mentioned Zibby in a Notion comment (reply in the same discussionId).",input_schema:{type:"object",properties:{discussionId:{type:"string",description:"The discussion_id to reply into (from notion_list_comments). Preferred for replies."},pageId:{type:"string",description:"Page id/URL to start a NEW top-level comment on (used when discussionId is absent)."},text:{type:"string",description:"The comment body (plain text)."}},required:["text"]}}]};export{H as markdownToNotionBlocks,p as notionApi,te as notionSkill,u as parseNotionId};
16
+ Do not block the task if Notion is unavailable \u2014 these tools return { ok:false, error } on failure; treat a missing page as "no extra context" / "cannot deliver to Notion" and continue.`,resolve(){let i=q();return i?{type:"stdio",command:"node",args:[i,"../dist/notion.js","notionSkill"],env:{},description:this.description,alwaysLoad:!0}:null},async handleToolCall(i,e){try{switch(i){case"notion_get_page":{let t=e?.pageId||e?.page||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let o=await p(`/pages/${n}`),r=w(o),s=o?.url||`https://www.notion.so/${n.replace(/-/g,"")}`,d=await S(n,0,{used:0}),c=!1;return d.length>h&&(d=d.slice(0,h),c=!0),JSON.stringify({ok:!0,id:n,title:r,url:s,text:d,...c?{truncated:!0}:{}})}case"notion_query_database":{let t=e?.databaseId||e?.database||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion database id or URL is required"});let r={page_size:Math.max(1,Math.min(Number(e?.maxResults)||I,I))};e?.filter&&typeof e.filter=="object"&&(r.filter=e.filter);let s=await p(`/databases/${n}/query`,{method:"POST",body:r}),d=(Array.isArray(s.results)?s.results:[]).map(c=>{let l={};for(let[m,O]of Object.entries(c.properties||{})){let k=F(O);k&&(l[m]=k)}return{id:c.id,title:w(c),url:c.url||`https://www.notion.so/${String(c.id||"").replace(/-/g,"")}`,props:l}});return JSON.stringify({ok:!0,id:n,count:d.length,hasMore:!!s.has_more,rows:d})}case"notion_create_page":{let t=typeof e?.title=="string"&&e.title.trim()?e.title.trim():null;if(!t)return JSON.stringify({ok:!1,error:"title is required"});let n=e?.databaseId?u(e.databaseId):null,o=e?.parentPageId?u(e.parentPageId):u(e?.parent||e?.pageId);if(!n&&!o)return JSON.stringify({ok:!1,error:"A valid parentPageId or databaseId is required"});let r=n?{database_id:n}:{page_id:o},s={title:{title:f(t)}},a=x(e)||[],d=a.slice(0,b),c=await p("/pages",{method:"POST",body:{parent:r,properties:s,...d.length?{children:d}:{}}}),l=c?.id;if(!l)return JSON.stringify({ok:!1,error:"Notion page create returned no id"});let m=a.slice(b);return m.length&&await P(l,m),JSON.stringify({ok:!0,pageId:l,url:c?.url||y(l)})}case"notion_append_blocks":{let t=u(e?.pageId||e?.blockId||e?.url||e?.id);if(!t)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let n=x(e);return!n||!n.length?JSON.stringify({ok:!1,error:"markdown or blocks content is required"}):(await P(t,n),JSON.stringify({ok:!0,pageId:t,url:y(t)}))}case"notion_insert_image":{let t=u(e?.pageId||e?.url||e?.id);if(!t)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let n=typeof e?.caption=="string"&&e.caption.trim()?f(e.caption.trim()):null,o,r;if(typeof e?.imagePath=="string"&&e.imagePath.trim())r=await K(e.imagePath),o={type:"file_upload",file_upload:{id:r}};else if(typeof e?.imageUrl=="string"&&e.imageUrl.trim())o={type:"external",external:{url:e.imageUrl.trim()}};else return JSON.stringify({ok:!1,error:"imagePath (local png/jpg) or imageUrl is required"});return n&&(o.caption=n),await p(`/blocks/${t}/children`,{method:"PATCH",body:{children:[{object:"block",type:"image",image:o}]}}),JSON.stringify({ok:!0,pageId:t,url:y(t),...r?{fileUploadId:r}:{}})}case"notion_list_comments":{let t=e?.blockId||e?.pageId||e?.block||e?.page||e?.url||e?.id,n=u(t);if(!n)return JSON.stringify({ok:!1,error:"A valid Notion page/block id or URL is required"});let o=new URLSearchParams({block_id:n,page_size:"100"}),r=await p(`/comments?${o.toString()}`),a=(Array.isArray(r.results)?r.results:[]).map(G);return JSON.stringify({ok:!0,id:n,count:a.length,comments:a})}case"notion_add_comment":{let t=typeof e?.text=="string"?e.text:typeof e?.body=="string"?e.body:"";if(!t||!t.trim())return JSON.stringify({ok:!1,error:"text is required"});let n=e?.discussionId||e?.discussion_id||null,o;if(n)o={discussion_id:String(n),rich_text:f(t)};else{let s=e?.pageId||e?.page||e?.url||e?.id,a=u(s);if(!a)return JSON.stringify({ok:!1,error:"Either discussionId (to reply) or a valid pageId (to start a comment) is required"});o={parent:{page_id:a},rich_text:f(t)}}let r=await p("/comments",{method:"POST",body:o});return JSON.stringify({ok:!0,id:r?.id||"",discussionId:r?.discussion_id||n||""})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${i}`})}}catch(t){return JSON.stringify({ok:!1,error:t.message})}},tools:[{name:"notion_get_page",description:"Fetch a Notion page and its content flattened to markdown, for use as read-only context. Accepts a raw page id OR a full Notion URL. Returns { ok, id, title, url, text }. Text is truncated to ~20k chars.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."}},required:["pageId"]}},{name:"notion_query_database",description:"Query a Notion database and return a bounded list of rows (id, title, url, key props). Accepts a database id OR full Notion URL. Optional Notion filter object. Returns at most 25 rows.",input_schema:{type:"object",properties:{databaseId:{type:"string",description:"Notion database id (dashed UUID or 32-char) OR a full Notion database URL."},filter:{type:"object",description:"Optional Notion filter object (Notion query filter syntax).",additionalProperties:!0},maxResults:{type:"number",description:"Max rows to return (default 25, max 25)."}},required:["databaseId"]}},{name:"notion_create_page",description:"Create a new Notion page under a parent page (parentPageId) OR in a database (databaseId) \u2014 exactly one parent is required. Body from markdown (#/##/### headings, - bullets, 1. ordered lists; inline marks kept as literal text) or raw Notion block objects. Long bodies are chunked automatically (Notion caps 100 blocks/request). Returns { ok, pageId, url } \u2014 share the url with the user.",input_schema:{type:"object",properties:{parentPageId:{type:"string",description:"Parent PAGE id/URL to create the page under (used when databaseId is absent)."},databaseId:{type:"string",description:"Parent DATABASE id/URL to create the page in (title goes into the title property)."},title:{type:"string",description:"Page title."},markdown:{type:"string",description:"Page body as markdown (preferred)."},blocks:{type:"array",description:"Raw Notion block objects (advanced; used instead of markdown, max 500).",items:{type:"object",additionalProperties:!0}}},required:["title"]}},{name:"notion_append_blocks",description:"Append markdown (or raw Notion blocks) to the END of an existing Notion page. Accepts a page id or full Notion URL. Chunks automatically at Notion's 100-blocks-per-request cap. Returns { ok, pageId, url }.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."},markdown:{type:"string",description:"Content to append, as markdown (preferred)."},blocks:{type:"array",description:"Raw Notion block objects (advanced; used instead of markdown, max 500).",items:{type:"object",additionalProperties:!0}}},required:["pageId"]}},{name:"notion_insert_image",description:"Append an image block to a Notion page. Pass imagePath for a LOCAL .png/.jpg file (max 20MB \u2014 uploaded via Notion's File Upload API, stored by Notion) or imageUrl for an external publicly-reachable image URL. Optional caption. Returns { ok, pageId, url }.",input_schema:{type:"object",properties:{pageId:{type:"string",description:"Notion page id (dashed UUID or 32-char) OR a full Notion page URL."},imagePath:{type:"string",description:"Local filesystem path to a .png or .jpg/.jpeg image (max 20MB). Preferred for locally rendered charts."},imageUrl:{type:"string",description:"External image URL (must be publicly reachable; used when imagePath is absent)."},caption:{type:"string",description:"Optional image caption."}},required:["pageId"]}},{name:"notion_list_comments",description:"List the open comment discussions on a Notion page/block. Accepts a page/block id OR a full Notion URL. Returns { ok, comments:[{ id, discussionId, text, author }] }. Use to read the comment thread you are replying to.",input_schema:{type:"object",properties:{blockId:{type:"string",description:"Notion page or block id (dashed UUID or 32-char) OR a full Notion URL."}},required:["blockId"]}},{name:"notion_add_comment",description:"Post a comment on Notion. To REPLY within an existing discussion, pass { discussionId, text }. To start a NEW top-level comment on a page, pass { pageId, text }. Returns { ok, id, discussionId }. Use this to answer a user who @mentioned Zibby in a Notion comment (reply in the same discussionId).",input_schema:{type:"object",properties:{discussionId:{type:"string",description:"The discussion_id to reply into (from notion_list_comments). Preferred for replies."},pageId:{type:"string",description:"Page id/URL to start a NEW top-level comment on (used when discussionId is absent)."},text:{type:"string",description:"The comment body (plain text)."}},required:["text"]}}]};export{H as markdownToNotionBlocks,p as notionApi,te as notionSkill,u as parseNotionId};
@@ -1,202 +1,24 @@
1
- export namespace opendesignSkill {
2
- let id: string;
3
- let serverName: string;
4
- let allowedTools: string[];
5
- let envKeys: any[];
6
- let description: string;
7
- let promptFragment: string;
8
- function resolve(): {
9
- command: any;
10
- args: any[];
11
- env: {};
12
- description: string;
13
- type?: undefined;
14
- alwaysLoad?: undefined;
15
- } | {
16
- type: string;
17
- command: string;
18
- args: any[];
19
- env: {};
20
- description: string;
21
- alwaysLoad: boolean;
22
- };
23
- function handleToolCall(name: any, args: any): Promise<string>;
24
- let tools: ({
25
- name: string;
26
- description: string;
27
- input_schema: {
28
- type: string;
29
- properties: {
30
- id?: undefined;
31
- projectId?: undefined;
32
- fileName?: undefined;
33
- title?: undefined;
34
- deck?: undefined;
35
- path?: undefined;
36
- agentId?: undefined;
37
- message?: undefined;
38
- conversationId?: undefined;
39
- model?: undefined;
40
- };
41
- required?: undefined;
42
- };
43
- } | {
44
- name: string;
45
- description: string;
46
- input_schema: {
47
- type: string;
48
- properties: {
49
- id: {
50
- type: string;
51
- description: string;
52
- };
53
- projectId?: undefined;
54
- fileName?: undefined;
55
- title?: undefined;
56
- deck?: undefined;
57
- path?: undefined;
58
- agentId?: undefined;
59
- message?: undefined;
60
- conversationId?: undefined;
61
- model?: undefined;
62
- };
63
- required: string[];
64
- };
65
- } | {
66
- name: string;
67
- description: string;
68
- input_schema: {
69
- type: string;
70
- properties: {
71
- projectId: {
72
- type: string;
73
- description: string;
74
- };
75
- id?: undefined;
76
- fileName?: undefined;
77
- title?: undefined;
78
- deck?: undefined;
79
- path?: undefined;
80
- agentId?: undefined;
81
- message?: undefined;
82
- conversationId?: undefined;
83
- model?: undefined;
84
- };
85
- required: string[];
86
- };
87
- } | {
88
- name: string;
89
- description: string;
90
- input_schema: {
91
- type: string;
92
- properties: {
93
- id: {
94
- type: string;
95
- description: string;
96
- };
97
- projectId: {
98
- type: string;
99
- description: string;
100
- };
101
- fileName?: undefined;
102
- title?: undefined;
103
- deck?: undefined;
104
- path?: undefined;
105
- agentId?: undefined;
106
- message?: undefined;
107
- conversationId?: undefined;
108
- model?: undefined;
109
- };
110
- required: string[];
111
- };
112
- } | {
113
- name: string;
114
- description: string;
115
- input_schema: {
116
- type: string;
117
- properties: {
118
- projectId: {
119
- type: string;
120
- description: string;
121
- };
122
- fileName: {
123
- type: string;
124
- description: string;
125
- };
126
- title: {
127
- type: string;
128
- description: string;
129
- };
130
- deck: {
131
- description: string;
132
- };
133
- id?: undefined;
134
- path?: undefined;
135
- agentId?: undefined;
136
- message?: undefined;
137
- conversationId?: undefined;
138
- model?: undefined;
139
- };
140
- required: string[];
141
- };
142
- } | {
143
- name: string;
144
- description: string;
145
- input_schema: {
146
- type: string;
147
- properties: {
148
- projectId: {
149
- type: string;
150
- description: string;
151
- };
152
- path: {
153
- type: string;
154
- description: string;
155
- };
156
- id?: undefined;
157
- fileName?: undefined;
158
- title?: undefined;
159
- deck?: undefined;
160
- agentId?: undefined;
161
- message?: undefined;
162
- conversationId?: undefined;
163
- model?: undefined;
164
- };
165
- required: string[];
166
- };
167
- } | {
168
- name: string;
169
- description: string;
170
- input_schema: {
171
- type: string;
172
- properties: {
173
- agentId: {
174
- type: string;
175
- description: string;
176
- };
177
- message: {
178
- type: string;
179
- description: string;
180
- };
181
- projectId: {
182
- type: string;
183
- description: string;
184
- };
185
- conversationId: {
186
- type: string;
187
- description: string;
188
- };
189
- model: {
190
- type: string;
191
- description: string;
192
- };
193
- id?: undefined;
194
- fileName?: undefined;
195
- title?: undefined;
196
- deck?: undefined;
197
- path?: undefined;
198
- };
199
- required: string[];
200
- };
201
- })[];
202
- }
1
+ /**
2
+ * OpenDesign skill — design/deck authoring + export over the OpenDesign REST
3
+ * API (the Zibby-managed `open-design` app, catalog appType === 'open-design').
4
+ *
5
+ * Mirrors figma.js / linear.js: a hand-written `tools[]` array + a
6
+ * `handleToolCall` switch, served over MCP by bin/mcp-skill.mjs (the generic
7
+ * skill server). There is NO upstream MCP server — we talk to the OpenDesign
8
+ * REST API directly.
9
+ *
10
+ * Auth: OpenDesign is a PASTE-TOKEN + base URL integration (same {token,
11
+ * baseUrl} shape as plane). The credential is resolved per-call via
12
+ * resolveIntegrationToken('open_design') — the backend returns
13
+ * { token: string, baseUrl: string }
14
+ * where baseUrl is "https://<host>" (no trailing slash). Every API path is
15
+ * under `${baseUrl}/api`. All calls send `Authorization: Bearer <token>`
16
+ * EXCEPT GET /api/health, which is an open connectivity probe (no auth).
17
+ *
18
+ * IMPORTANT: this skill is OPTIONAL. requiresIntegration is intentionally
19
+ * NOT set, so declaring SKILLS.OPEN_DESIGN on a node must NEVER gate deploy
20
+ * on a connected integration (it is not added to any required-integration
21
+ * map). A workflow can list it and still deploy without OpenDesign connected;
22
+ * the tools simply error at call time if the credential is missing.
23
+ */
24
+ export declare const opendesignSkill: any;