@zibby/skills 2.0.14 → 2.0.16
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/index.js +121 -121
- package/dist/larkDocs.d.ts +19 -6
- package/dist/larkDocs.js +3 -3
- package/dist/package.json +4 -4
- package/package.json +4 -4
package/dist/larkDocs.d.ts
CHANGED
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
* (block == document_id == the doc root) → append blocks at the end
|
|
30
30
|
* GET /open-apis/wiki/v2/spaces/get_node?token={t} → { node:{obj_token,obj_type} }
|
|
31
31
|
*
|
|
32
|
+
* Bitable v1 API (Base / 多维表格 — requires bitable:app:readonly):
|
|
33
|
+
* GET /open-apis/bitable/v1/apps/{app} → { app:{name,...} }
|
|
34
|
+
* GET /open-apis/bitable/v1/apps/{app}/tables?page_size=100 → { items:[{table_id,name}] }
|
|
35
|
+
* GET /open-apis/bitable/v1/apps/{app}/tables/{t}/fields → { items:[{field_name,type}] }
|
|
36
|
+
* POST /open-apis/bitable/v1/apps/{app}/tables/{t}/records/search?page_size=500
|
|
37
|
+
* body { view_id?, field_names? } → { items:[{record_id,fields}], has_more, page_token, total }
|
|
38
|
+
* A Base is NOT a docx: a /wiki/ node fronting one resolves to obj_type
|
|
39
|
+
* 'bitable', which the docx path rejects by design (see resolveDocumentId).
|
|
40
|
+
*
|
|
32
41
|
* Wiki v2 API (write support — requires wiki:node:create / wiki:space:read):
|
|
33
42
|
* GET /open-apis/wiki/v2/spaces?page_size=50[&page_token] → { items:[{space_id,name}], has_more, page_token }
|
|
34
43
|
* POST /open-apis/wiki/v2/spaces/{space_id}/nodes → { node:{node_token,obj_token,obj_type} }
|
|
@@ -57,14 +66,14 @@ export declare function wikiWebUrl(host: any, nodeToken: any): string;
|
|
|
57
66
|
/**
|
|
58
67
|
* Parse a Lark/Feishu doc reference (raw token OR URL) into { type, token }.
|
|
59
68
|
* - .../docx/<token> → { type:'docx', token }
|
|
60
|
-
* - .../wiki/<token> → { type:'wiki', token } (resolved to its
|
|
69
|
+
* - .../wiki/<token> → { type:'wiki', token } (resolved to its backing object)
|
|
70
|
+
* - .../base/<token> → { type:'base', token } (a Base / 多维表格)
|
|
61
71
|
* - bare token → { type:'docx', token }
|
|
62
|
-
*
|
|
72
|
+
* A /base/ or /wiki/ URL additionally carries { tableId?, viewId? } when its
|
|
73
|
+
* query names them. Returns null when nothing usable can be extracted.
|
|
74
|
+
* Pure + side-effect-free.
|
|
63
75
|
*/
|
|
64
|
-
export declare function parseLarkDocRef(ref: any):
|
|
65
|
-
type: string;
|
|
66
|
-
token: string;
|
|
67
|
-
};
|
|
76
|
+
export declare function parseLarkDocRef(ref: any): any;
|
|
68
77
|
/**
|
|
69
78
|
* Map a small, common subset of markdown into Lark Docx block objects.
|
|
70
79
|
* Each block is a single line: headings (#/##/### → heading1/2/3), bullets
|
|
@@ -74,5 +83,9 @@ export declare function parseLarkDocRef(ref: any): {
|
|
|
74
83
|
* blocks). Bounded by the caller's chunking to MAX_BLOCK_CHILDREN per request.
|
|
75
84
|
*/
|
|
76
85
|
export declare function markdownToLarkBlocks(markdown: any): any[];
|
|
86
|
+
/**
|
|
87
|
+
* Derive the human-facing Base web URL (same region logic as docWebUrl).
|
|
88
|
+
*/
|
|
89
|
+
export declare function baseWebUrl(host: any, appToken: any, tableId?: any, viewId?: any): string;
|
|
77
90
|
export declare const larkDocsSkill: any;
|
|
78
91
|
export declare function _resetLarkDocsTokenCache(): void;
|
package/dist/larkDocs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`),n=[];for(let
|
|
3
|
-
`)){let r=o.replace(/\s+$/,"");if(!r.trim())continue;let i=/^(#{1,3})\s+(.*)$/.exec(r),a=/^\s*[-*]\s+(.*)$/.exec(r),s=/^\s*\d+[.)]\s+(.*)$/.exec(r),c,d,p;if(i){let u=i[1].length;c=`heading${u}`,d=2+u,p=i[2]}else a?(c="bullet",d=12,p=a[1]):s?(c="ordered",d=13,p=s[1]):(c="text",d=2,p=r);n.push({block_type:d,[c]:{elements:[{text_run:{content:p}}],style:{}}})}return n}function I(t){let e=typeof t?.markdown=="string"?t.markdown:null,n=typeof t?.text=="string"?t.text:null;return e??n}async function x(t,e){let n;for(let o=0;o<e.length;o+=P){let r=e.slice(o,o+P);n=(await l("POST",`/open-apis/docx/v1/documents/${t}/blocks/${t}/children?document_revision_id=-1`,{children:r})).host}return n}function oe(t){let e=typeof t=="string"?t.trim():"";if(!e)throw new Error("imagePath is required");if(!M(e)||!G(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 n=q(e);if(n.length>Q)throw new Error(`image is ${(n.length/(1024*1024)).toFixed(1)}MB \u2014 max 10MB`);return n}async function re({fileName:t,parentNode:e,bytes:n}){let{token:o,host:r}=await U(),i=new FormData;i.set("file_name",t),i.set("parent_type","docx_image"),i.set("parent_node",e),i.set("size",String(n.length)),i.set("file",new Blob([n]),t);let s=await(await w(`${r}/open-apis/drive/v1/medias/upload_all`,{method:"POST",headers:{Authorization:`Bearer ${o}`},body:i},{kind:"transfer",what:"Lark Docx image upload"})).json();if(s.code!==0)throw new Error(`Lark media upload_all error: ${s.msg||s.code}`);let c=s.data?.file_token;if(!c)throw new Error("Lark media upload_all returned no file_token");return c}var ie="docx",ae=50;function D(t){return[{type:"text_run",text_run:{text:String(t??"")}}]}function se(t){return Array.isArray(t)?t.map(e=>e?.text_run?.text??e?.docs_link?.url??(e?.person?`@${e.person.user_id||""}`:"")).join(""):""}function ce(t){let e=Array.isArray(t?.reply_list?.replies)?t.reply_list.replies:[];return{commentId:t?.comment_id||"",resolved:!!t?.is_solved,replies:e.map(n=>({replyId:n?.reply_id||"",author:n?.user_id||"",text:se(n?.content?.elements),createTime:n?.create_time||""}))}}function O(t){return typeof t?.fileType=="string"&&t.fileType.trim()?t.fileType.trim():ie}var Se={id:"lark-docs",callsBackend:!0,serverName:"larkdocs",allowedTools:["mcp__larkdocs__*"],requiresIntegration:[_.LARK_DOCS,_.LARK],description:"Lark / Feishu Docs \u2014 read, create, append, and insert images into Lark documents (docx).",envKeys:["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV",...te],promptFragment:'## Lark Docs\nYou can read, create, and append Lark/Feishu documents (docx), and read/post/reply to their comments. This runs on the connected Lark Docs app (the chat app is used when no separate docs app is connected). Each `larkdoc_*` / `larkwiki_*` tool documents its own params and return shape in its tool description \u2014 they are not restated here.\nThese tools return { ok:false, error } on failure \u2014 treat an unavailable Lark connection as "cannot read/deliver to Lark Docs" and continue rather than blocking the task.',resolve(){let t=V();if(!t)return null;let e={};for(let n of this.envKeys)process.env[n]&&(e[n]=process.env[n]);return{type:"stdio",command:"node",args:[t,"../dist/larkDocs.js","larkDocsSkill"],env:e,description:this.description}},async handleToolCall(t,e){try{switch(t){case"larkdoc_get":{let n=e?.documentId||e?.url||e?.id,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let r=await h(o),i="";try{i=(await l("GET",`/open-apis/docx/v1/documents/${r}`)).data?.document?.title||""}catch{}let{data:a,host:s}=await l("GET",`/open-apis/docx/v1/documents/${r}/raw_content?lang=0`),c=String(a?.content||""),d=!1;return c.length>R&&(c=c.slice(0,R),d=!0),JSON.stringify({ok:!0,documentId:r,title:i,url:g(s,r),text:c,...d?{truncated:!0}:{}})}case"larkdoc_create":{let n=typeof e?.title=="string"&&e.title.trim()?e.title.trim():null;if(!n)return JSON.stringify({ok:!1,error:"title is required"});let o=typeof e?.wikiSpaceId=="string"&&e.wikiSpaceId.trim()?e.wikiSpaceId.trim():null;if(o){let c=typeof e?.parentNodeToken=="string"&&e.parentNodeToken.trim()?e.parentNodeToken.trim():null,{data:d,host:p}=await l("POST",`/open-apis/wiki/v2/spaces/${encodeURIComponent(o)}/nodes`,{obj_type:"docx",node_type:"origin",title:n,...c?{parent_node_token:c}:{}}),u=d?.node||{},m=u.obj_token;if(!m)return JSON.stringify({ok:!1,error:"Lark wiki node create returned no obj_token"});let k=I(e);if(k&&k.trim()){let S=T(k);S.length&&await x(m,S)}return JSON.stringify({ok:!0,documentId:m,title:n,wikiSpaceId:o,wikiNodeToken:u.node_token||"",url:u.node_token?ne(p,u.node_token):g(p,m)})}let{data:r,host:i}=await l("POST","/open-apis/docx/v1/documents",{title:n,...e?.folderToken?{folder_token:String(e.folderToken)}:{}}),a=r?.document?.document_id;if(!a)return JSON.stringify({ok:!1,error:"Lark Docs create returned no document_id"});let s=I(e);if(s&&s.trim()){let c=T(s);c.length&&await x(a,c)}return JSON.stringify({ok:!0,documentId:a,title:n,url:g(i,a)})}case"larkdoc_append":{let n=e?.documentId||e?.url||e?.id,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let r=I(e);if(!r||!r.trim())return JSON.stringify({ok:!1,error:"markdown or text content is required"});let i=await h(o),a=T(r);if(!a.length)return JSON.stringify({ok:!1,error:"no non-empty content to append"});let s=await x(i,a);return JSON.stringify({ok:!0,documentId:i,url:g(s,i)})}case"larkdoc_insert_image":{let n=e?.documentId||e?.url||e?.id,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});if(!e?.imagePath||typeof e.imagePath!="string"||!e.imagePath.trim())return JSON.stringify({ok:!1,error:"imagePath is required"});let r=await h(o),i=e.imagePath.trim(),a=oe(i),s=H(i),d=(await l("POST",`/open-apis/docx/v1/documents/${r}/blocks/${r}/children?document_revision_id=-1`,{children:[{block_type:27,image:{}}]})).data?.children?.[0]?.block_id;if(!d)return JSON.stringify({ok:!1,error:"Lark image block create returned no block_id"});let p=await re({fileName:s,parentNode:d,bytes:a}),u={token:p},m=Number(e?.width),k=Number(e?.height);Number.isFinite(m)&&m>0&&(u.width=Math.round(m)),Number.isFinite(k)&&k>0&&(u.height=Math.round(k));let{host:S}=await l("PATCH",`/open-apis/docx/v1/documents/${r}/blocks/${d}?document_revision_id=-1`,{replace_image:u});return JSON.stringify({ok:!0,documentId:r,blockId:d,fileToken:p,url:g(S,r)})}case"larkwiki_list_spaces":{let n=[],o=null;for(let r=0;r<Z;r++){let i=new URLSearchParams({page_size:String(X)});o&&i.set("page_token",o);let{data:a}=await l("GET",`/open-apis/wiki/v2/spaces?${i.toString()}`),s=Array.isArray(a?.items)?a.items:[];for(let c of s)n.push({spaceId:String(c?.space_id||""),name:String(c?.name||"")});if(!a?.has_more||!a?.page_token)break;o=a.page_token}return JSON.stringify({ok:!0,count:n.length,spaces:n})}case"larkdoc_list_comments":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let r=await h(o),i=O(e),a=new URLSearchParams({file_type:i,page_size:String(ae)}),{data:s}=await l("GET",`/open-apis/drive/v1/files/${r}/comments?${a.toString()}`),d=(Array.isArray(s?.items)?s.items:[]).map(ce);return JSON.stringify({ok:!0,documentId:r,count:d.length,comments:d})}case"larkdoc_add_comment":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let r=I({text:e?.text??e?.body});if(!r||!r.trim())return JSON.stringify({ok:!1,error:"text is required"});let i=await h(o),a=O(e),{data:s}=await l("POST",`/open-apis/drive/v1/files/${i}/comments?file_type=${encodeURIComponent(a)}`,{reply_list:{replies:[{content:{elements:D(r)}}]}});return JSON.stringify({ok:!0,documentId:i,commentId:s?.comment_id||""})}case"larkdoc_reply_comment":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,o=f(n);if(!o)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let r=e?.commentId||e?.comment_id;if(!r)return JSON.stringify({ok:!1,error:"commentId is required"});let i=I({text:e?.text??e?.body});if(!i||!i.trim())return JSON.stringify({ok:!1,error:"text is required"});let a=await h(o),s=O(e),{data:c}=await l("POST",`/open-apis/drive/v1/files/${a}/comments/${encodeURIComponent(r)}/replies?file_type=${encodeURIComponent(s)}`,{content:{elements:D(i)}});return JSON.stringify({ok:!0,documentId:a,commentId:String(r),replyId:c?.reply_id||""})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${t}`})}}catch(n){return JSON.stringify({ok:!1,error:n.message})}},tools:[{name:"larkdoc_get",description:"Read a Lark/Feishu document (docx) as plain text, for use as reference context. Accepts a raw doc id OR a full Lark doc URL (a /docx/ or /wiki/ link \u2014 wiki links are resolved to their backing docx). Returns { ok, documentId, title, url, text }. Text is truncated to ~20k chars.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL (/docx/\u2026 or /wiki/\u2026)."}},required:["documentId"]}},{name:"larkdoc_create",description:"Create a new Lark/Feishu document (docx) with a title and optional content (markdown: #/##/### headings, - bullets, 1. ordered; or plain text). Pass wikiSpaceId (from larkwiki_list_spaces) to create the doc INSIDE a wiki space instead of as a standalone doc \u2014 optionally nested under parentNodeToken. Returns { ok, documentId, url } (plus wikiNodeToken when created in a wiki) \u2014 share the url with the user.",input_schema:{type:"object",properties:{title:{type:"string",description:"Document title."},markdown:{type:"string",description:"Document body as markdown (preferred)."},text:{type:"string",description:"Document body as plain text (used when markdown is absent)."},folderToken:{type:"string",description:"Optional Lark drive folder token to create the doc in. Absent = the app root. Ignored when wikiSpaceId is set."},wikiSpaceId:{type:"string",description:"Optional wiki space id (from larkwiki_list_spaces) \u2014 create the doc as a node inside this wiki space."},parentNodeToken:{type:"string",description:"Optional wiki node token to nest the new doc under (only with wikiSpaceId). Absent = the space root."}},required:["title"]}},{name:"larkwiki_list_spaces",description:"List the Lark/Feishu wiki spaces visible to the connected app. Returns { ok, count, spaces:[{ spaceId, name }] }. Use to discover the wikiSpaceId for larkdoc_create.",input_schema:{type:"object",properties:{}}},{name:"larkdoc_append",description:"Append markdown/text content to the END of an existing Lark/Feishu document (docx). Accepts a documentId or a full Lark doc URL. Returns { ok, documentId, url }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},markdown:{type:"string",description:"Content to append, as markdown (preferred)."},text:{type:"string",description:"Content to append, as plain text (used when markdown is absent)."}},required:["documentId"]}},{name:"larkdoc_insert_image",description:"Append a LOCAL image file (png/jpg, max 10MB) to the END of an existing Lark/Feishu document (docx). Accepts a documentId or full doc URL plus a local file path. Optional width/height in pixels. Returns { ok, documentId, blockId, fileToken, url }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},imagePath:{type:"string",description:"Local filesystem path to a .png or .jpg/.jpeg image (max 10MB)."},width:{type:"number",description:"Optional display width in pixels."},height:{type:"number",description:"Optional display height in pixels."}},required:["documentId","imagePath"]}},{name:"larkdoc_list_comments",description:"List the comment threads on a Lark/Feishu document. Accepts a documentId or full doc URL. Returns { ok, comments:[{ commentId, replies:[{ replyId, author, text }] }] }. Use to read the thread you are replying to.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'. Only change for non-docx files (doc/sheet/bitable/file/slides)."}},required:["documentId"]}},{name:"larkdoc_add_comment",description:"Post a NEW top-level comment on a Lark/Feishu document. Accepts a documentId or full doc URL plus text. Returns { ok, documentId, commentId }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},text:{type:"string",description:"The comment body (plain text)."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'."}},required:["documentId","text"]}},{name:"larkdoc_reply_comment",description:"Reply INSIDE an existing comment thread on a Lark/Feishu document. Pass { documentId, commentId, text }. Use to answer a user who @mentioned Zibby in a doc comment (reply in the same commentId). Returns { ok, documentId, commentId, replyId }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},commentId:{type:"string",description:"The comment_id of the thread to reply into (from larkdoc_list_comments or the webhook event)."},text:{type:"string",description:"The reply body (plain text)."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'."}},required:["documentId","commentId","text"]}}]};function Le(){y=null}export{te as LARK_DOCS_APP_ENV_KEYS,Le as _resetLarkDocsTokenCache,g as docWebUrl,Se as larkDocsSkill,T as markdownToLarkBlocks,f as parseLarkDocRef,ne as wikiWebUrl};
|
|
1
|
+
import{existsSync as H,statSync as re,readFileSync as ie}from"fs";import{fileURLToPath as ae}from"url";import{basename as se,dirname as ce,resolve as de}from"path";var g=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",LARK_DOCS:"lark_docs",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",VIKUNJA:"vikunja",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),Pe=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 Chat",connectPath:"/integrations?provider=lark"},lark_docs:{id:"lark_docs",name:"Lark App",connectPath:"/integrations?provider=lark_docs"},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"},vikunja:{id:"vikunja",name:"Vikunja",connectPath:"/integrations?provider=vikunja"},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"}});import{resolveIntegrationToken as D}from"@zibby/core/backend-client.js";var Z="https://open.larksuite.com",j=Object.freeze([Object.freeze({appId:"LARK_DOCS_APP_ID",appSecret:"LARK_DOCS_APP_SECRET",host:"LARK_DOCS_HOST"}),Object.freeze({appId:"LARK_APP_ID",appSecret:"LARK_APP_SECRET",host:"LARK_HOST"})]),C=Object.freeze(j.flatMap(t=>[t.appId,t.appSecret,t.host]));function x(t){let e=String(t||"").trim().replace(/\/+$/,"");return e?/^https?:\/\//i.test(e)?e:`https://${e}`:Z}function V(t){let e=String(process.env[t.appId]||"").trim(),n=String(process.env[t.appSecret]||"").trim();return!e||!n?null:{appId:e,appSecret:n,host:x(process.env[t.host])}}async function K(){for(let t of j){let e=V(t);if(e)return e}try{let t=await D(g.LARK_DOCS);return{appId:t?.appId,appSecret:t?.appSecret,host:x(t?.host)}}catch(t){if(!/unknown provider/i.test(String(t?.message||"")))throw t;let e=await D(g.LARK);return{appId:e?.appId,appSecret:e?.appSecret,host:x(e?.host)}}}var T={api:{knob:"SKILL_API_TIMEOUT_MS",fallback:3e4},transfer:{knob:"SKILL_TRANSFER_TIMEOUT_MS",fallback:12e4},job:{knob:"SKILL_JOB_TIMEOUT_MS",fallback:3e5}};function Q(t,e,n=process.env){let r=Number(n?.[t]);return Number.isFinite(r)&&r>0?Math.min(6e5,Math.max(1e3,Math.floor(r))):e}function ee(t="api",e=process.env){let n=T[t]||T.api;return Q(n.knob,n.fallback,e)}function te(t){return t?.name==="TimeoutError"||t?.name==="AbortError"}function ne(t){try{return new URL(String(t?.url??t)).host||"unknown host"}catch{return"unknown host"}}function oe(t,e){if(!t)return e;let n=new AbortController,r=a=>{n.signal.aborted||n.abort(a)},o=()=>r(t.reason),i=()=>r(e.reason);return n.signal.addEventListener("abort",()=>{t.removeEventListener("abort",o),e.removeEventListener("abort",i)},{once:!0}),t.aborted?r(t.reason):e.aborted?r(e.reason):(t.addEventListener("abort",o,{once:!0}),e.addEventListener("abort",i,{once:!0})),n.signal}async function A(t,e={},n={}){let r=n.kind||"api",o=(T[r]||T.api).knob,i=n.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(n.timeoutMs))):ee(r),a=e?.signal;if(a?.aborted)throw a.reason??new DOMException("This operation was aborted","AbortError");let s=AbortSignal.timeout(i),c=oe(a,s);try{return await fetch(t,{...e,signal:c})}catch(d){throw s.aborted&&te(d)?new Error(`${n.what||"request"} TIMED OUT after ${i}ms against ${ne(t)} (${o})`):d}}function le(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let t=ce(ae(import.meta.url)),e=de(t,"..","bin","mcp-skill.mjs");return H(e)?e:null}var F=2e4,J=50,pe=50,ue=20,me=500,ke=200,fe=1e3,Y=100,N=20,he=3e4,_e=new Set([5,1001,1002]),be=10*1024*1024,ye=6e3*1e3,I=null,ge=C;async function P(){let{appId:t,appSecret:e,host:n}=await K();if(I&&I.appId===t&&I.expiresAt>Date.now())return{token:I.token,host:n};let o=await(await A(`${n}/open-apis/auth/v3/tenant_access_token/internal`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({app_id:t,app_secret:e})},{kind:"api",what:"Lark tenant_access_token"})).json();if(o.code!==0)throw new Error(`Lark tenant_access_token failed: ${o.msg||o.code}`);return I={token:o.tenant_access_token,expiresAt:Date.now()+ye,appId:t},{token:o.tenant_access_token,host:n}}async function u(t,e,n){let{token:r,host:o}=await P(),i={method:t,headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json; charset=utf-8"}};t!=="GET"&&n!==void 0&&(i.body=JSON.stringify(n));let s=await(await A(`${o}${e}`,i,{kind:"api",what:`Lark Docx ${t} ${e}`})).json();if(s.code!==0)throw new Error(`Lark Docx API ${e} error: ${s.msg||s.code}`);return{data:s.data||{},host:o}}function S(t,e){return String(t||"").includes("feishu")?`https://feishu.cn/docx/${e}`:`https://www.larksuite.com/docx/${e}`}function we(t,e){return String(t||"").includes("feishu")?`https://feishu.cn/wiki/${e}`:`https://www.larksuite.com/wiki/${e}`}function Ie(t){let e=t.indexOf("?");if(e<0)return{};let n=t.slice(e+1).split("#")[0],r=new URLSearchParams(n),o={},i=r.get("table"),a=r.get("view");return i&&/^tbl[A-Za-z0-9]+$/.test(i)&&(o.tableId=i),a&&/^vew[A-Za-z0-9]+$/.test(a)&&(o.viewId=a),o}function b(t){if(!t||typeof t!="string")return null;let e=t.trim();if(!e)return null;let n=e.match(/\/(docx|wiki|base)\/([A-Za-z0-9]+)/);return n?{type:n[1],token:n[2],...Ie(e)}:/^[A-Za-z0-9]{10,}$/.test(e)?{type:"docx",token:e}:null}async function w(t){let e=typeof t=="string"?b(t):t;if(!e)throw new Error("A valid Lark doc id or URL is required");if(e.type==="docx")return e.token;let{data:n}=await u("GET",`/open-apis/wiki/v2/spaces/get_node?token=${encodeURIComponent(e.token)}`),r=n?.node||{};if(r.obj_type!=="docx"||!r.obj_token){let o=r.obj_type||"unknown";throw o==="bitable"?new Error("This Lark wiki link is a Base / \u591A\u7EF4\u8868\u683C (obj_type=bitable), not a document \u2014 read it with larkbitable_read_records (larkbitable_list_tables lists its tables)"):new Error(`Wiki node is not a docx document (obj_type=${o})`)}return r.obj_token}function O(t){let e=String(t??"").replace(/\r\n/g,`
|
|
2
|
+
`),n=[];for(let r of e.split(`
|
|
3
|
+
`)){let o=r.replace(/\s+$/,"");if(!o.trim())continue;let i=/^(#{1,3})\s+(.*)$/.exec(o),a=/^\s*[-*]\s+(.*)$/.exec(o),s=/^\s*\d+[.)]\s+(.*)$/.exec(o),c,d,l;if(i){let m=i[1].length;c=`heading${m}`,d=2+m,l=i[2]}else a?(c="bullet",d=12,l=a[1]):s?(c="ordered",d=13,l=s[1]):(c="text",d=2,l=o);n.push({block_type:d,[c]:{elements:[{text_run:{content:l}}],style:{}}})}return n}function L(t){let e=typeof t?.markdown=="string"?t.markdown:null,n=typeof t?.text=="string"?t.text:null;return e??n}async function E(t,e){let n;for(let r=0;r<e.length;r+=J){let o=e.slice(r,r+J);n=(await u("POST",`/open-apis/docx/v1/documents/${t}/blocks/${t}/children?document_revision_id=-1`,{children:o})).host}return n}function Se(t){let e=typeof t=="string"?t.trim():"";if(!e)throw new Error("imagePath is required");if(!H(e)||!re(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 n=ie(e);if(n.length>be)throw new Error(`image is ${(n.length/(1024*1024)).toFixed(1)}MB \u2014 max 10MB`);return n}async function Le({fileName:t,parentNode:e,bytes:n}){let{token:r,host:o}=await P(),i=new FormData;i.set("file_name",t),i.set("parent_type","docx_image"),i.set("parent_node",e),i.set("size",String(n.length)),i.set("file",new Blob([n]),t);let s=await(await A(`${o}/open-apis/drive/v1/medias/upload_all`,{method:"POST",headers:{Authorization:`Bearer ${r}`},body:i},{kind:"transfer",what:"Lark Docx image upload"})).json();if(s.code!==0)throw new Error(`Lark media upload_all error: ${s.msg||s.code}`);let c=s.data?.file_token;if(!c)throw new Error("Lark media upload_all returned no file_token");return c}var Te="docx",Ae=50;function q(t){return[{type:"text_run",text_run:{text:String(t??"")}}]}function xe(t){return Array.isArray(t)?t.map(e=>e?.text_run?.text??e?.docs_link?.url??(e?.person?`@${e.person.user_id||""}`:"")).join(""):""}function Oe(t){let e=Array.isArray(t?.reply_list?.replies)?t.reply_list.replies:[];return{commentId:t?.comment_id||"",resolved:!!t?.is_solved,replies:e.map(n=>({replyId:n?.reply_id||"",author:n?.user_id||"",text:xe(n?.content?.elements),createTime:n?.create_time||""}))}}function R(t){return typeof t?.fileType=="string"&&t.fileType.trim()?t.fileType.trim():Te}function G(t,e,n,r){let i=String(t||"").includes("feishu")?"https://feishu.cn":"https://www.larksuite.com",a=new URLSearchParams;n&&a.set("table",n),r&&a.set("view",r);let s=a.toString();return`${i}/base/${e}${s?`?${s}`:""}`}async function z(t){let e=typeof t=="string"?b(t):t;if(!e)throw new Error("A valid Lark Base id or URL is required");let n={tableId:e.tableId||null,viewId:e.viewId||null};if(e.type!=="wiki")return{appToken:e.token,...n};let{data:r}=await u("GET",`/open-apis/wiki/v2/spaces/get_node?token=${encodeURIComponent(e.token)}`),o=r?.node||{};if(o.obj_type!=="bitable"||!o.obj_token)throw o.obj_type==="docx"?new Error("This Lark wiki link is a document (obj_type=docx), not a Base / \u591A\u7EF4\u8868\u683C \u2014 read it with larkdoc_get"):new Error(`Wiki node is not a Base / \u591A\u7EF4\u8868\u683C (obj_type=${o.obj_type||"unknown"})`);return{appToken:o.obj_token,...n}}function v(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return String(t);if(Array.isArray(t))return t.map(v).filter(e=>e!=="").join(", ");if(typeof t=="object"){let e=t;return typeof e.text=="string"&&e.text?e.text:typeof e.name=="string"&&e.name?e.name:typeof e.en_name=="string"&&e.en_name?e.en_name:typeof e.full_address=="string"&&e.full_address?e.full_address:typeof e.link=="string"&&e.link?e.link:e.value!==void 0?v(e.value):JSON.stringify(e)}return String(t)}function Ee(t,e){if(_e.has(Number(e))){let n=Number(Array.isArray(t)?t[0]:t);if(Number.isFinite(n)&&n>0)return new Date(n).toISOString()}return v(t)}async function W(t){let e=[],n=null;for(let r=0;r<N;r++){let o=new URLSearchParams({page_size:String(Y)});n&&o.set("page_token",n);let{data:i}=await u("GET",`/open-apis/bitable/v1/apps/${encodeURIComponent(t)}/tables?${o.toString()}`);for(let a of Array.isArray(i?.items)?i.items:[])e.push({tableId:String(a?.table_id||""),name:String(a?.name||"")});if(!i?.has_more||!i?.page_token)break;n=i.page_token}return e}async function Re(t,e){let n=[],r=null;for(let o=0;o<N;o++){let i=new URLSearchParams({page_size:String(Y)});r&&i.set("page_token",r);let{data:a}=await u("GET",`/open-apis/bitable/v1/apps/${encodeURIComponent(t)}/tables/${encodeURIComponent(e)}/fields?${i.toString()}`);for(let s of Array.isArray(a?.items)?a.items:[])n.push({name:String(s?.field_name||""),type:Number(s?.type)||0});if(!a?.has_more||!a?.page_token)break;r=a.page_token}return n}async function ve({appToken:t,tableId:e}){if(e)return e;let n=await W(t);if(n.length===1)return n[0].tableId;if(!n.length)throw new Error("This Lark Base has no tables");let r=n.map(o=>`${o.name} (${o.tableId})`).join("; ");throw new Error(`tableId is required \u2014 this Base has ${n.length} tables: ${r}`)}async function Ne({appToken:t,tableId:e,viewId:n,fieldNames:r,maxRecords:o,pageToken:i}){let a=await Re(t,e),s=new Map(a.map(k=>[k.name,k.type]));if(r?.length){let k=r.filter(_=>!s.has(_));if(k.length){let _=k.flatMap(h=>a.filter(y=>y.name.trim()===String(h).trim()).map(y=>JSON.stringify(y.name)));throw new Error(`unknown column(s): ${k.map(h=>JSON.stringify(h)).join(", ")}`+(_.length?` \u2014 did you mean ${_.join(", ")}? (names can carry spaces)`:"")+`. This table's columns: ${a.map(h=>JSON.stringify(h.name)).join(", ")}`)}}let c=[],d=0,l=i||null,m=!1,p=0,f=!1;for(let k=0;k<N;k++){let _=new URLSearchParams({page_size:String(Math.min(me,o))});l&&_.set("page_token",l);let{data:h}=await u("POST",`/open-apis/bitable/v1/apps/${encodeURIComponent(t)}/tables/${encodeURIComponent(e)}/records/search?${_.toString()}`,{...n?{view_id:n}:{},...r?.length?{field_names:r}:{}});p=Number(h?.total)||p,m=!!h?.has_more,l=h?.page_token||null;for(let y of Array.isArray(h?.items)?h.items:[]){let U={};for(let[M,X]of Object.entries(y?.fields||{}))U[M]=Ee(X,s.get(M));let $={recordId:String(y?.record_id||""),fields:U},B=JSON.stringify($).length;if(c.length&&d+B>he){f=!0;break}if(d+=B,c.push($),c.length>=o)break}if(f||c.length>=o||!m||!l)break}return{columns:a,records:c,total:p,hasMore:m||f,nextPageToken:l||"",truncated:f,...f&&!l?{note:"stopped at the character budget, and these rows have no resume token \u2014 re-read with fieldNames set to the few columns you need (see columns[])."}:{}}}var Ge={id:"lark-docs",callsBackend:!0,serverName:"larkdocs",allowedTools:["mcp__larkdocs__*"],requiresIntegration:[g.LARK_DOCS,g.LARK],description:"Lark / Feishu Docs \u2014 read, create, append, and insert images into Lark documents (docx), and read Lark Bases (\u591A\u7EF4\u8868\u683C / bitable).",envKeys:["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV",...ge],promptFragment:'## Lark Docs\nYou can read, create, and append Lark/Feishu documents (docx), read/post/reply to their comments, and READ Lark Bases (\u591A\u7EF4\u8868\u683C / bitable). This runs on the connected Lark Docs app (the chat app is used when no separate docs app is connected). Each `larkdoc_*` / `larkwiki_*` / `larkbitable_*` tool documents its own params and return shape in its tool description \u2014 they are not restated here.\nA Lark link is not always a document: a `/base/\u2026` link, or a `/wiki/\u2026` link carrying `?table=tbl\u2026`, is a Base \u2014 read it with `larkbitable_read_records`, NOT `larkdoc_get` (which refuses it, since a Base has no document body). Base reads need the `bitable:app:readonly` scope on the connected app.\nThese tools return { ok:false, error } on failure \u2014 treat an unavailable Lark connection as "cannot read/deliver to Lark Docs" and continue rather than blocking the task.',resolve(){let t=le();if(!t)return null;let e={};for(let n of this.envKeys)process.env[n]&&(e[n]=process.env[n]);return{type:"stdio",command:"node",args:[t,"../dist/larkDocs.js","larkDocsSkill"],env:e,description:this.description}},async handleToolCall(t,e){try{switch(t){case"larkdoc_get":{let n=e?.documentId||e?.url||e?.id,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let o=await w(r),i="";try{i=(await u("GET",`/open-apis/docx/v1/documents/${o}`)).data?.document?.title||""}catch{}let{data:a,host:s}=await u("GET",`/open-apis/docx/v1/documents/${o}/raw_content?lang=0`),c=String(a?.content||""),d=!1;return c.length>F&&(c=c.slice(0,F),d=!0),JSON.stringify({ok:!0,documentId:o,title:i,url:S(s,o),text:c,...d?{truncated:!0}:{}})}case"larkdoc_create":{let n=typeof e?.title=="string"&&e.title.trim()?e.title.trim():null;if(!n)return JSON.stringify({ok:!1,error:"title is required"});let r=typeof e?.wikiSpaceId=="string"&&e.wikiSpaceId.trim()?e.wikiSpaceId.trim():null;if(r){let c=typeof e?.parentNodeToken=="string"&&e.parentNodeToken.trim()?e.parentNodeToken.trim():null,{data:d,host:l}=await u("POST",`/open-apis/wiki/v2/spaces/${encodeURIComponent(r)}/nodes`,{obj_type:"docx",node_type:"origin",title:n,...c?{parent_node_token:c}:{}}),m=d?.node||{},p=m.obj_token;if(!p)return JSON.stringify({ok:!1,error:"Lark wiki node create returned no obj_token"});let f=L(e);if(f&&f.trim()){let k=O(f);k.length&&await E(p,k)}return JSON.stringify({ok:!0,documentId:p,title:n,wikiSpaceId:r,wikiNodeToken:m.node_token||"",url:m.node_token?we(l,m.node_token):S(l,p)})}let{data:o,host:i}=await u("POST","/open-apis/docx/v1/documents",{title:n,...e?.folderToken?{folder_token:String(e.folderToken)}:{}}),a=o?.document?.document_id;if(!a)return JSON.stringify({ok:!1,error:"Lark Docs create returned no document_id"});let s=L(e);if(s&&s.trim()){let c=O(s);c.length&&await E(a,c)}return JSON.stringify({ok:!0,documentId:a,title:n,url:S(i,a)})}case"larkdoc_append":{let n=e?.documentId||e?.url||e?.id,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let o=L(e);if(!o||!o.trim())return JSON.stringify({ok:!1,error:"markdown or text content is required"});let i=await w(r),a=O(o);if(!a.length)return JSON.stringify({ok:!1,error:"no non-empty content to append"});let s=await E(i,a);return JSON.stringify({ok:!0,documentId:i,url:S(s,i)})}case"larkdoc_insert_image":{let n=e?.documentId||e?.url||e?.id,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});if(!e?.imagePath||typeof e.imagePath!="string"||!e.imagePath.trim())return JSON.stringify({ok:!1,error:"imagePath is required"});let o=await w(r),i=e.imagePath.trim(),a=Se(i),s=se(i),d=(await u("POST",`/open-apis/docx/v1/documents/${o}/blocks/${o}/children?document_revision_id=-1`,{children:[{block_type:27,image:{}}]})).data?.children?.[0]?.block_id;if(!d)return JSON.stringify({ok:!1,error:"Lark image block create returned no block_id"});let l=await Le({fileName:s,parentNode:d,bytes:a}),m={token:l},p=Number(e?.width),f=Number(e?.height);Number.isFinite(p)&&p>0&&(m.width=Math.round(p)),Number.isFinite(f)&&f>0&&(m.height=Math.round(f));let{host:k}=await u("PATCH",`/open-apis/docx/v1/documents/${o}/blocks/${d}?document_revision_id=-1`,{replace_image:m});return JSON.stringify({ok:!0,documentId:o,blockId:d,fileToken:l,url:S(k,o)})}case"larkwiki_list_spaces":{let n=[],r=null;for(let o=0;o<ue;o++){let i=new URLSearchParams({page_size:String(pe)});r&&i.set("page_token",r);let{data:a}=await u("GET",`/open-apis/wiki/v2/spaces?${i.toString()}`),s=Array.isArray(a?.items)?a.items:[];for(let c of s)n.push({spaceId:String(c?.space_id||""),name:String(c?.name||"")});if(!a?.has_more||!a?.page_token)break;r=a.page_token}return JSON.stringify({ok:!0,count:n.length,spaces:n})}case"larkbitable_list_tables":{let n=e?.baseId||e?.url||e?.documentId||e?.id,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark Base id or URL is required"});let{appToken:o,tableId:i,viewId:a}=await z(r),s=await W(o),c="",d="";try{let l=await u("GET",`/open-apis/bitable/v1/apps/${encodeURIComponent(o)}`);c=l.data?.app?.name||"",d=l.host}catch{}return JSON.stringify({ok:!0,appToken:o,name:c,...d?{url:G(d,o,i,a)}:{},...i?{linkedTableId:i}:{},...a?{linkedViewId:a}:{},count:s.length,tables:s})}case"larkbitable_read_records":{let n=e?.baseId||e?.url||e?.documentId||e?.id,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark Base id or URL is required"});let o=await z(r),i=o.appToken,a=await ve({appToken:i,tableId:typeof e?.tableId=="string"&&e.tableId.trim()?e.tableId.trim():o.tableId}),s=typeof e?.viewId=="string"&&e.viewId.trim()?e.viewId.trim():o.viewId,c=Array.isArray(e?.fieldNames)?e.fieldNames.map(_=>String(_)).filter(Boolean):null,d=Number(e?.maxRecords),l=Number.isFinite(d)&&d>0?Math.min(Math.round(d),fe):ke,m=typeof e?.pageToken=="string"&&e.pageToken.trim()?e.pageToken.trim():null,p=await Ne({appToken:i,tableId:a,viewId:s,fieldNames:c,maxRecords:l,pageToken:m}),{host:f}=await P(),k="";try{k=(await u("GET",`/open-apis/bitable/v1/apps/${encodeURIComponent(i)}`)).data?.app?.name||""}catch{}return JSON.stringify({ok:!0,appToken:i,name:k,tableId:a,...s?{viewId:s}:{},url:G(f,i,a,s),total:p.total,count:p.records.length,columns:p.columns,records:p.records,hasMore:p.hasMore,...p.nextPageToken?{nextPageToken:p.nextPageToken}:{},...p.truncated?{truncated:!0}:{},...p.note?{note:p.note}:{}})}case"larkdoc_list_comments":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let o=await w(r),i=R(e),a=new URLSearchParams({file_type:i,page_size:String(Ae)}),{data:s}=await u("GET",`/open-apis/drive/v1/files/${o}/comments?${a.toString()}`),d=(Array.isArray(s?.items)?s.items:[]).map(Oe);return JSON.stringify({ok:!0,documentId:o,count:d.length,comments:d})}case"larkdoc_add_comment":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let o=L({text:e?.text??e?.body});if(!o||!o.trim())return JSON.stringify({ok:!1,error:"text is required"});let i=await w(r),a=R(e),{data:s}=await u("POST",`/open-apis/drive/v1/files/${i}/comments?file_type=${encodeURIComponent(a)}`,{reply_list:{replies:[{content:{elements:q(o)}}]}});return JSON.stringify({ok:!0,documentId:i,commentId:s?.comment_id||""})}case"larkdoc_reply_comment":{let n=e?.documentId||e?.url||e?.id||e?.fileToken,r=b(n);if(!r)return JSON.stringify({ok:!1,error:"A valid Lark doc id or URL is required"});let o=e?.commentId||e?.comment_id;if(!o)return JSON.stringify({ok:!1,error:"commentId is required"});let i=L({text:e?.text??e?.body});if(!i||!i.trim())return JSON.stringify({ok:!1,error:"text is required"});let a=await w(r),s=R(e),{data:c}=await u("POST",`/open-apis/drive/v1/files/${a}/comments/${encodeURIComponent(o)}/replies?file_type=${encodeURIComponent(s)}`,{content:{elements:q(i)}});return JSON.stringify({ok:!0,documentId:a,commentId:String(o),replyId:c?.reply_id||""})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${t}`})}}catch(n){return JSON.stringify({ok:!1,error:n.message})}},tools:[{name:"larkdoc_get",description:"Read a Lark/Feishu document (docx) as plain text, for use as reference context. Accepts a raw doc id OR a full Lark doc URL (a /docx/ or /wiki/ link \u2014 wiki links are resolved to their backing docx). Returns { ok, documentId, title, url, text }. Text is truncated to ~20k chars.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL (/docx/\u2026 or /wiki/\u2026)."}},required:["documentId"]}},{name:"larkdoc_create",description:"Create a new Lark/Feishu document (docx) with a title and optional content (markdown: #/##/### headings, - bullets, 1. ordered; or plain text). Pass wikiSpaceId (from larkwiki_list_spaces) to create the doc INSIDE a wiki space instead of as a standalone doc \u2014 optionally nested under parentNodeToken. Returns { ok, documentId, url } (plus wikiNodeToken when created in a wiki) \u2014 share the url with the user.",input_schema:{type:"object",properties:{title:{type:"string",description:"Document title."},markdown:{type:"string",description:"Document body as markdown (preferred)."},text:{type:"string",description:"Document body as plain text (used when markdown is absent)."},folderToken:{type:"string",description:"Optional Lark drive folder token to create the doc in. Absent = the app root. Ignored when wikiSpaceId is set."},wikiSpaceId:{type:"string",description:"Optional wiki space id (from larkwiki_list_spaces) \u2014 create the doc as a node inside this wiki space."},parentNodeToken:{type:"string",description:"Optional wiki node token to nest the new doc under (only with wikiSpaceId). Absent = the space root."}},required:["title"]}},{name:"larkwiki_list_spaces",description:"List the Lark/Feishu wiki spaces visible to the connected app. Returns { ok, count, spaces:[{ spaceId, name }] }. Use to discover the wikiSpaceId for larkdoc_create.",input_schema:{type:"object",properties:{}}},{name:"larkdoc_append",description:"Append markdown/text content to the END of an existing Lark/Feishu document (docx). Accepts a documentId or a full Lark doc URL. Returns { ok, documentId, url }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},markdown:{type:"string",description:"Content to append, as markdown (preferred)."},text:{type:"string",description:"Content to append, as plain text (used when markdown is absent)."}},required:["documentId"]}},{name:"larkdoc_insert_image",description:"Append a LOCAL image file (png/jpg, max 10MB) to the END of an existing Lark/Feishu document (docx). Accepts a documentId or full doc URL plus a local file path. Optional width/height in pixels. Returns { ok, documentId, blockId, fileToken, url }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},imagePath:{type:"string",description:"Local filesystem path to a .png or .jpg/.jpeg image (max 10MB)."},width:{type:"number",description:"Optional display width in pixels."},height:{type:"number",description:"Optional display height in pixels."}},required:["documentId","imagePath"]}},{name:"larkbitable_list_tables",description:"List the tables in a Lark/Feishu Base (\u591A\u7EF4\u8868\u683C / bitable). Accepts a Base URL (a /base/\u2026 link, or a /wiki/\u2026 link whose node IS a Base) or a raw app token. Returns { ok, appToken, name, tables:[{ tableId, name }] } plus linkedTableId/linkedViewId when the URL pinned them. A Base is NOT a document \u2014 larkdoc_get cannot read one; use this and larkbitable_read_records instead.",input_schema:{type:"object",properties:{baseId:{type:"string",description:"Lark Base app token OR a full Base/wiki URL (/base/\u2026 or /wiki/\u2026)."}},required:["baseId"]}},{name:"larkbitable_read_records",description:"Read the rows of one table in a Lark/Feishu Base (\u591A\u7EF4\u8868\u683C / bitable) as flat text. Accepts a Base URL (/base/\u2026 or a /wiki/\u2026 link fronting a Base) or app token; the table and view are taken from the URL's table=/view= when present, and tableId may be omitted when the Base has exactly one table. Optionally restrict to viewId or fieldNames. Returns { ok, appToken, name, tableId, total, count, columns:[{name,type}], records:[{ recordId, fields:{ <column>: <text> } }], hasMore, nextPageToken }. Every cell is a STRING (dates as ISO). Defaults to 200 records; pass maxRecords (max 1000) and pageToken to page through a bigger table. A WIDE table (dozens of columns) hits a character budget before the row cap: the reply then carries truncated:true, hasMore:true and a note, and the fix is fieldNames, not paging. Column names are matched EXACTLY and real ones can carry a leading space or a ' (1)' suffix \u2014 an unknown name is refused with this table's actual column list, so read columns[] (or one small call) before naming any.",input_schema:{type:"object",properties:{baseId:{type:"string",description:"Lark Base app token OR a full Base/wiki URL (/base/\u2026 or /wiki/\u2026)."},tableId:{type:"string",description:"Table id (tbl\u2026). Optional when the URL carries table= or the Base has exactly one table; larkbitable_list_tables lists them."},viewId:{type:"string",description:"Optional view id (vew\u2026) \u2014 restricts the read to that view's rows and order."},fieldNames:{type:"array",items:{type:"string"},description:"Optional column names to return. Absent = every column."},maxRecords:{type:"number",description:"Max records to return (default 200, hard cap 1000)."},pageToken:{type:"string",description:"Resume token from a previous call's nextPageToken."}},required:["baseId"]}},{name:"larkdoc_list_comments",description:"List the comment threads on a Lark/Feishu document. Accepts a documentId or full doc URL. Returns { ok, comments:[{ commentId, replies:[{ replyId, author, text }] }] }. Use to read the thread you are replying to.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'. Only change for non-docx files (doc/sheet/bitable/file/slides)."}},required:["documentId"]}},{name:"larkdoc_add_comment",description:"Post a NEW top-level comment on a Lark/Feishu document. Accepts a documentId or full doc URL plus text. Returns { ok, documentId, commentId }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},text:{type:"string",description:"The comment body (plain text)."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'."}},required:["documentId","text"]}},{name:"larkdoc_reply_comment",description:"Reply INSIDE an existing comment thread on a Lark/Feishu document. Pass { documentId, commentId, text }. Use to answer a user who @mentioned Zibby in a doc comment (reply in the same commentId). Returns { ok, documentId, commentId, replyId }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Lark doc id (docx token) OR a full Lark/Feishu doc URL."},commentId:{type:"string",description:"The comment_id of the thread to reply into (from larkdoc_list_comments or the webhook event)."},text:{type:"string",description:"The reply body (plain text)."},fileType:{type:"string",description:"Drive file type \u2014 defaults to 'docx'."}},required:["documentId","commentId","text"]}}]};function ze(){I=null}export{ge as LARK_DOCS_APP_ENV_KEYS,ze as _resetLarkDocsTokenCache,G as baseWebUrl,S as docWebUrl,Ge as larkDocsSkill,O as markdownToLarkBlocks,b as parseLarkDocRef,we as wikiWebUrl};
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/skills",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.16",
|
|
4
4
|
"description": "Built-in skill definitions for the Zibby agent-workflow framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -117,10 +117,10 @@
|
|
|
117
117
|
"dependencies": {
|
|
118
118
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
119
119
|
"@resvg/resvg-js": "^2.6.2",
|
|
120
|
-
"@zibby/agent-workflow": "2.0.
|
|
120
|
+
"@zibby/agent-workflow": "2.0.16",
|
|
121
121
|
"@zibby/bin-oxlint": "^1.73.0",
|
|
122
122
|
"@zibby/bin-semgrep": "^1.169.0",
|
|
123
|
-
"@zibby/skill-ids": "2.0.
|
|
123
|
+
"@zibby/skill-ids": "2.0.16",
|
|
124
124
|
"echarts": "^6.1.0",
|
|
125
125
|
"mem0ai": "npm:@zibby/mem0ai@^3.0.5",
|
|
126
126
|
"zod": "^3.23.0 || ^4.0.0"
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
"optionalDependencies": {
|
|
138
|
-
"@zibby/mcp-browser": "2.0.
|
|
138
|
+
"@zibby/mcp-browser": "2.0.16",
|
|
139
139
|
"@zibby/mcp-memory": "*"
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/skills",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.16",
|
|
4
4
|
"description": "Built-in skill definitions for the Zibby agent-workflow framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -117,10 +117,10 @@
|
|
|
117
117
|
"dependencies": {
|
|
118
118
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
119
119
|
"@resvg/resvg-js": "^2.6.2",
|
|
120
|
-
"@zibby/agent-workflow": "2.0.
|
|
120
|
+
"@zibby/agent-workflow": "2.0.16",
|
|
121
121
|
"@zibby/bin-oxlint": "^1.73.0",
|
|
122
122
|
"@zibby/bin-semgrep": "^1.169.0",
|
|
123
|
-
"@zibby/skill-ids": "2.0.
|
|
123
|
+
"@zibby/skill-ids": "2.0.16",
|
|
124
124
|
"echarts": "^6.1.0",
|
|
125
125
|
"mem0ai": "npm:@zibby/mem0ai@^3.0.5",
|
|
126
126
|
"zod": "^3.23.0 || ^4.0.0"
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
"optionalDependencies": {
|
|
138
|
-
"@zibby/mcp-browser": "2.0.
|
|
138
|
+
"@zibby/mcp-browser": "2.0.16",
|
|
139
139
|
"@zibby/mcp-memory": "*"
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|