@zibby/skills 0.1.40 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gitlab.d.ts +76 -0
- package/dist/gitlab.js +5 -2
- package/dist/index.js +79 -76
- package/dist/notion.d.ts +21 -4
- package/dist/notion.js +5 -5
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/notion.d.ts
CHANGED
|
@@ -23,15 +23,32 @@ export function notionApi(path: any, opts?: {}): Promise<any>;
|
|
|
23
23
|
export namespace notionSkill {
|
|
24
24
|
let id: string;
|
|
25
25
|
let serverName: string;
|
|
26
|
+
let allowedTools: string[];
|
|
26
27
|
let requiresIntegration: "notion";
|
|
27
28
|
let description: string;
|
|
28
29
|
let promptFragment: string;
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* Spawn the GENERIC skill MCP server (bin/mcp-skill.mjs) pointing at this
|
|
32
|
+
* module's notionSkill export, so the AGENT gets real mcp__notion__* tools
|
|
33
|
+
* and can pull a referenced page itself (the agent-driven code-review flow).
|
|
34
|
+
*
|
|
35
|
+
* Previously this returned null (no MCP server) because Notion was only ever
|
|
36
|
+
* called by deterministic node code via handleToolCall — there was no agent
|
|
37
|
+
* tool surface. Now the review agent gathers context itself, so it needs the
|
|
38
|
+
* tools. The bin imports ../dist/notion.js (resolved relative to bin/, like
|
|
39
|
+
* mcp-sentry.mjs) and dispatches through handleToolCall; auth flows through
|
|
40
|
+
* the INHERITED env (PROJECT_API_TOKEN → resolveIntegrationToken('notion')),
|
|
41
|
+
* so no provider-specific env keys are needed here. When unconnected,
|
|
42
|
+
* handleToolCall returns { ok:false, error } — the agent tolerates it.
|
|
33
43
|
*/
|
|
34
|
-
function resolve():
|
|
44
|
+
function resolve(): {
|
|
45
|
+
type: string;
|
|
46
|
+
command: string;
|
|
47
|
+
args: any[];
|
|
48
|
+
env: {};
|
|
49
|
+
description: string;
|
|
50
|
+
alwaysLoad: boolean;
|
|
51
|
+
};
|
|
35
52
|
function handleToolCall(name: any, args: any): Promise<string>;
|
|
36
53
|
let tools: ({
|
|
37
54
|
name: string;
|
package/dist/notion.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{resolveIntegrationToken as
|
|
1
|
+
import{existsSync as $}from"fs";import{fileURLToPath as A}from"url";import{dirname as w,resolve as x}from"path";import{resolveIntegrationToken as I,clearTokenCache as O}from"@zibby/core/backend-client.js";var g=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",PLANE:"plane",LINEAR:"linear",FIGMA:"figma"}),j=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"},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"}});function R(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let t=w(A(import.meta.url)),a=x(t,"..","bin","mcp-skill.mjs");return $(a)?a:null}var S="2022-06-28",T="https://api.notion.com/v1",f=2e4,b=25,v=25;function _(t){if(!t||typeof t!="string")return null;let i=t.trim().split(/[?#]/)[0],e=i.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(e)return e[0].toLowerCase();let n=i.match(/[0-9a-fA-F]{32}/g);if(n&&n.length){let o=n[n.length-1].toLowerCase();return`${o.slice(0,8)}-${o.slice(8,12)}-${o.slice(12,16)}-${o.slice(16,20)}-${o.slice(20)}`}return null}async function h(t,a={}){let i=async()=>{let{token:e}=await I("notion");if(typeof e!="string"||!e)throw new Error(`Invalid notion token type: ${typeof e}`);let n=await fetch(`${T}${t}`,{method:a.method||"GET",headers:{Authorization:`Bearer ${e}`,"Notion-Version":S,Accept:"application/json",...a.body?{"Content-Type":"application/json"}:{},...a.headers},body:a.body?JSON.stringify(a.body):void 0});if(!n.ok){let s=await n.text().catch(()=>"");throw new Error(`Notion API ${n.status}: ${s.slice(0,300)}`)}let o=await n.text().catch(()=>"");if(!o||!o.trim())return{};try{return JSON.parse(o)}catch{return{raw:o}}};try{return await i()}catch(e){let n=String(e?.message||e||"").toLowerCase();if(!(n.includes("token")||n.includes("401")||n.includes("unauthorized")))throw e;return O("notion"),i()}}function p(t){if(!Array.isArray(t))return"";let a="";for(let i of t){let e=i?.plain_text??i?.text?.content??"";if(!e)continue;let n=i.annotations||{};n.code&&(e=`\`${e}\``),n.bold&&(e=`**${e}**`),n.italic&&(e=`_${e}_`),n.strikethrough&&(e=`~~${e}~~`);let o=i?.href||i?.text?.link?.url;o&&(e=`[${e}](${o})`),a+=e}return a}function L(t,a,i){let e=t?.type,n=t?.[e]||{},o=" ".repeat(Math.max(0,a)),s=(c="rich_text")=>p(n[c]),r;switch(e){case"paragraph":r=s();break;case"heading_1":r=`# ${s()}`;break;case"heading_2":r=`## ${s()}`;break;case"heading_3":r=`### ${s()}`;break;case"bulleted_list_item":r=`${o}- ${s()}`;break;case"numbered_list_item":r=`${o}1. ${s()}`;break;case"to_do":r=`${o}- [${n.checked?"x":" "}] ${s()}`;break;case"toggle":r=`${o}- ${s()}`;break;case"quote":r=`> ${s()}`;break;case"callout":{r=`> ${n.icon?.emoji?`${n.icon.emoji} `:""}${s()}`;break}case"code":{r=`\`\`\`${n.language||""}
|
|
2
2
|
${s()}
|
|
3
|
-
\`\`\``;break}case"divider":r="---";break;case"child_page":r=`[child page: ${
|
|
4
|
-
`)}async function y(
|
|
5
|
-
`)}function
|
|
3
|
+
\`\`\``;break}case"divider":r="---";break;case"child_page":r=`[child page: ${n.title||""}]`;break;case"child_database":r=`[child database: ${n.title||""}]`;break;case"bookmark":case"embed":case"link_preview":r=n.url?`<${n.url}>`:"";break;case"equation":r=n.expression?`$${n.expression}$`:"";break;case"table":case"column_list":case"column":r="";break;case"table_row":{let c=(n.cells||[]).map(d=>p(d).trim());r=`${o}| ${c.join(" | ")} |`;break}default:r=s();break}let l=[];return r&&r.trim()&&l.push(r),i&&i.trim()&&l.push(i),l.join(`
|
|
4
|
+
`)}async function y(t,a,i){let e=[],n,o=0;do{if(i.used>=f)break;let s=new URLSearchParams({page_size:"100"});n&&s.set("start_cursor",n);let r=await h(`/blocks/${t}/children?${s.toString()}`),l=Array.isArray(r.results)?r.results:[];for(let c of l){let d="";c.has_children&&(d=await y(c.id,a+1,i));let u=L(c,a,d);if(u&&(e.push(u),i.used+=u.length+1),i.used>=f)break}n=r.has_more?r.next_cursor:void 0,o+=1}while(n&&o<v);return e.join(`
|
|
5
|
+
`)}function k(t){let a=t?.properties||{};for(let i of Object.values(a))if(i?.type==="title"){let e=p(i.title).trim();if(e)return e}return""}function P(t){if(!t||!t.type)return"";switch(t.type){case"title":return p(t.title).trim();case"rich_text":return p(t.rich_text).trim();case"number":return t.number==null?"":String(t.number);case"select":return t.select?.name||"";case"status":return t.status?.name||"";case"multi_select":return(t.multi_select||[]).map(i=>i.name).join(", ");case"checkbox":return t.checkbox?"true":"false";case"url":return t.url||"";case"email":return t.email||"";case"phone_number":return t.phone_number||"";case"date":return t.date?.start||"";case"people":return(t.people||[]).map(i=>i.name||i.id).join(", ");default:return""}}var B={id:"notion",serverName:"notion",allowedTools:["mcp__notion__*"],requiresIntegration:g.NOTION,description:"Notion read-only context (pull a page/database as markdown)",promptFragment:`## Notion (connected, read-only context)
|
|
6
6
|
You can pull a referenced Notion page in as extra context. This is OPTIONAL \u2014 only use it when the task references a Notion page/URL (e.g. an engineering-standards or design doc to review against).
|
|
7
7
|
- 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.
|
|
8
8
|
- 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.
|
|
9
|
-
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" and continue.`,resolve(){return null},async handleToolCall(
|
|
9
|
+
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" and continue.`,resolve(){let t=R();return t?{type:"stdio",command:"node",args:[t,"../dist/notion.js","notionSkill"],env:{},description:this.description,alwaysLoad:!0}:null},async handleToolCall(t,a){try{switch(t){case"notion_get_page":{let i=a?.pageId||a?.page||a?.url||a?.id,e=_(i);if(!e)return JSON.stringify({ok:!1,error:"A valid Notion page id or URL is required"});let n=await h(`/pages/${e}`),o=k(n),s=n?.url||`https://www.notion.so/${e.replace(/-/g,"")}`,l=await y(e,0,{used:0}),c=!1;return l.length>f&&(l=l.slice(0,f),c=!0),JSON.stringify({ok:!0,id:e,title:o,url:s,text:l,...c?{truncated:!0}:{}})}case"notion_query_database":{let i=a?.databaseId||a?.database||a?.url||a?.id,e=_(i);if(!e)return JSON.stringify({ok:!1,error:"A valid Notion database id or URL is required"});let o={page_size:Math.max(1,Math.min(Number(a?.maxResults)||b,b))};a?.filter&&typeof a.filter=="object"&&(o.filter=a.filter);let s=await h(`/databases/${e}/query`,{method:"POST",body:o}),l=(Array.isArray(s.results)?s.results:[]).map(c=>{let d={};for(let[u,N]of Object.entries(c.properties||{})){let m=P(N);m&&(d[u]=m)}return{id:c.id,title:k(c),url:c.url||`https://www.notion.so/${String(c.id||"").replace(/-/g,"")}`,props:d}});return JSON.stringify({ok:!0,id:e,count:l.length,hasMore:!!s.has_more,rows:l})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${t}`})}}catch(i){return JSON.stringify({ok:!1,error:i.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"]}}]};export{h as notionApi,B as notionSkill,_ as parseNotionId};
|
package/dist/package.json
CHANGED