@zibby/skills 0.1.64 → 0.1.68
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/chat-notify.js +3 -3
- package/dist/discord.d.ts +77 -0
- package/dist/discord.js +5 -0
- package/dist/figma.js +2 -2
- package/dist/git-write.js +1 -1
- package/dist/github.js +3 -3
- package/dist/gitlab.js +1 -1
- package/dist/googleDocs.d.ts +225 -0
- package/dist/googleDocs.js +12 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +120 -105
- package/dist/integrations.d.ts +12 -0
- package/dist/integrations.js +1 -1
- package/dist/jira.js +2 -2
- package/dist/lark.js +2 -2
- package/dist/linear.js +3 -3
- package/dist/linkedin.d.ts +29 -0
- package/dist/linkedin.js +2 -2
- package/dist/llm-billing.js +1 -1
- package/dist/notion.js +5 -5
- package/dist/opendesign.js +2 -2
- package/dist/package.json +1 -1
- package/dist/plane.js +2 -2
- package/dist/sentry.js +1 -1
- package/dist/slack.js +2 -2
- package/dist/trackers/github-adapter.js +2 -2
- package/dist/trackers/index.js +1 -1
- package/dist/trackers/jira-adapter.js +7 -7
- package/dist/trackers/linear-adapter.js +9 -9
- package/package.json +1 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* INJECTED-TOKEN fast path (Zibby Copilot per-turn credential injection) +
|
|
3
|
+
* NON-OWNER SAFETY GATE — the Google twin of linkedin.js injectedPersonalToken.
|
|
4
|
+
*
|
|
5
|
+
* The Zibby Copilot is ONE shared chat bot backed by ONE project's
|
|
6
|
+
* PROJECT_API_TOKEN. resolveIntegrationToken('google') authenticates with that
|
|
7
|
+
* PAT, so the account is inferred SERVER-SIDE from the PAT — meaning the shared
|
|
8
|
+
* bot would only ever see the PROJECT OWNER's Google (their readable Docs, their
|
|
9
|
+
* Drive), never the (different) person who actually sent the chat message.
|
|
10
|
+
*
|
|
11
|
+
* Two per-turn env signals, set + restored by the copilot-runtime (a TRUSTED
|
|
12
|
+
* backend service that already KMS-decrypts tenants' creds directly):
|
|
13
|
+
* - ZIBBY_INJECTED_GOOGLE_TOKEN (+ _EMAIL): the EMAIL-VERIFIED sender's OWN
|
|
14
|
+
* `google` integration access token (auto-refreshed server-side). When
|
|
15
|
+
* present it takes PRECEDENCE over resolveIntegrationToken, so every gdocs
|
|
16
|
+
* call runs against the SENDER's own Google.
|
|
17
|
+
* - ZIBBY_SENDER_IS_NON_OWNER=1: the verified sender's account differs from
|
|
18
|
+
* the PAT/tenant account. With NO injected token this is a HARD REFUSAL
|
|
19
|
+
* gate: the skill must NEVER fall through to the owner's token on a
|
|
20
|
+
* colleague's behalf (privacy: the owner's readable docs would be exposed
|
|
21
|
+
* and created docs would land in the owner's Drive). Every tool returns
|
|
22
|
+
* { ok:false, error } telling the sender to connect their own Google.
|
|
23
|
+
*
|
|
24
|
+
* Absent both (owner/self turns, Fargate workflows, self-host — no
|
|
25
|
+
* sender-identity context) → the normal PAT chokepoint runs unchanged.
|
|
26
|
+
*/
|
|
27
|
+
export function injectedGoogleToken(): {
|
|
28
|
+
token: string;
|
|
29
|
+
email: string;
|
|
30
|
+
};
|
|
31
|
+
/** True when the runtime flagged this turn's verified sender as NOT the tenant owner. */
|
|
32
|
+
export function senderIsNonOwner(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* STRICT CHAT-TURN INVARIANT (fail-CLOSED) — ZIBBY_CHAT_STRICT_PERSONAL=1.
|
|
35
|
+
*
|
|
36
|
+
* Set UNCONDITIONALLY by the Copilot runtime for EVERY chat turn (Slack +
|
|
37
|
+
* Lark, owner or not). Under it, personal-tier providers (google here) must
|
|
38
|
+
* NEVER fall through to the PAT-resolved project-owner token: the ONLY
|
|
39
|
+
* accepted credential is the per-turn injected sender token
|
|
40
|
+
* (ZIBBY_INJECTED_GOOGLE_TOKEN — the runtime injects the OWNER's own Google
|
|
41
|
+
* through the same path, so the owner keeps working). No injected token →
|
|
42
|
+
* HARD REFUSE, for ANY sender: verified non-owners, same-account colleagues,
|
|
43
|
+
* UNVERIFIED senders (users.info failure / no email match — the exact class
|
|
44
|
+
* the old ZIBBY_SENDER_IS_NON_OWNER flag failed OPEN on), and even the owner
|
|
45
|
+
* when their own Google isn't connected. The non-owner flag stays as
|
|
46
|
+
* belt-and-braces; this strict flag is the primary gate.
|
|
47
|
+
*
|
|
48
|
+
* Absent both flags (Fargate workflows, self-host, direct tool use — no chat
|
|
49
|
+
* sender context) → the normal PAT chokepoint runs unchanged.
|
|
50
|
+
*/
|
|
51
|
+
export function chatStrictPersonal(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Extract a Google Docs document id from a raw id OR a Docs URL
|
|
54
|
+
* (https://docs.google.com/document/d/<id>/edit...). Returns the id string
|
|
55
|
+
* or null.
|
|
56
|
+
*/
|
|
57
|
+
export function parseDocId(ref: any): string;
|
|
58
|
+
/**
|
|
59
|
+
* Low-level Google REST helper. Resolves the bearer via
|
|
60
|
+
* resolveIntegrationToken('google'), retries once on transient auth errors
|
|
61
|
+
* (clearing the client-side token cache so the backend re-refreshes), and
|
|
62
|
+
* returns parsed JSON.
|
|
63
|
+
*
|
|
64
|
+
* Keep this the single auth chokepoint — don't resolve tokens at call sites.
|
|
65
|
+
*/
|
|
66
|
+
export function googleApi(url: any, opts?: {}): Promise<any>;
|
|
67
|
+
/**
|
|
68
|
+
* Parse ONE markdown line's inline marks (bold `**x**`, links `[t](u)`,
|
|
69
|
+
* inline code `` `x` ``) into { text, styles } where `styles` are ranges
|
|
70
|
+
* RELATIVE to the returned plain text.
|
|
71
|
+
*/
|
|
72
|
+
export function parseInlineMarkdown(line: any): {
|
|
73
|
+
text: string;
|
|
74
|
+
styles: ({
|
|
75
|
+
start: number;
|
|
76
|
+
end: number;
|
|
77
|
+
link: string;
|
|
78
|
+
bold?: undefined;
|
|
79
|
+
code?: undefined;
|
|
80
|
+
} | {
|
|
81
|
+
start: number;
|
|
82
|
+
end: number;
|
|
83
|
+
bold: boolean;
|
|
84
|
+
link?: undefined;
|
|
85
|
+
code?: undefined;
|
|
86
|
+
} | {
|
|
87
|
+
start: number;
|
|
88
|
+
end: number;
|
|
89
|
+
code: boolean;
|
|
90
|
+
link?: undefined;
|
|
91
|
+
bold?: undefined;
|
|
92
|
+
})[];
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Convert a small, common subset of markdown (headings #/##/###, bullet
|
|
96
|
+
* lists -/*, numbered lists `1.`, bold, links, inline code) into Google Docs
|
|
97
|
+
* batchUpdate requests that insert the content at `startIndex`.
|
|
98
|
+
*
|
|
99
|
+
* Strategy: ONE insertText request carrying the whole plain text (every line
|
|
100
|
+
* newline-terminated → each becomes its own paragraph), followed by
|
|
101
|
+
* updateParagraphStyle (headings), createParagraphBullets (consecutive list
|
|
102
|
+
* runs) and updateTextStyle (bold/link/code) requests over the computed
|
|
103
|
+
* ranges. Indices are UTF-16 code units — JS string .length matches the Docs
|
|
104
|
+
* API's index space exactly.
|
|
105
|
+
*
|
|
106
|
+
* Returns { requests, endIndex }. Plain text (no markdown) passes through as
|
|
107
|
+
* plain paragraphs — the converter is safe for the `text` input too.
|
|
108
|
+
*/
|
|
109
|
+
export function markdownToRequests(markdown: any, startIndex: any): {
|
|
110
|
+
requests: {
|
|
111
|
+
insertText: {
|
|
112
|
+
location: {
|
|
113
|
+
index: any;
|
|
114
|
+
};
|
|
115
|
+
text: string;
|
|
116
|
+
};
|
|
117
|
+
}[];
|
|
118
|
+
endIndex: any;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Flatten a documents.get body into plain text (paragraph text runs joined,
|
|
122
|
+
* newline-separated — table cells + nested content included via recursion).
|
|
123
|
+
* Bounded by MAX_TEXT_CHARS.
|
|
124
|
+
*/
|
|
125
|
+
export function extractPlainText(body: any): string;
|
|
126
|
+
export const NON_OWNER_REFUSAL: "You haven't connected your own Google account \u2014 connect it at https://studio.zibby.dev/integrations (Google Docs). For privacy, I can't use anyone else's Google (including the project owner's) on your behalf.";
|
|
127
|
+
export namespace googleDocsSkill {
|
|
128
|
+
let id: string;
|
|
129
|
+
let serverName: string;
|
|
130
|
+
let allowedTools: string[];
|
|
131
|
+
let requiresIntegration: "google";
|
|
132
|
+
let description: string;
|
|
133
|
+
let promptFragment: string;
|
|
134
|
+
/**
|
|
135
|
+
* Spawn the GENERIC skill MCP server (bin/mcp-skill.mjs) pointing at this
|
|
136
|
+
* module's googleDocsSkill export, so the AGENT gets real mcp__gdocs__*
|
|
137
|
+
* tools. Auth flows through the INHERITED env (PROJECT_API_TOKEN →
|
|
138
|
+
* resolveIntegrationToken('google')), so no provider-specific env keys are
|
|
139
|
+
* needed here. When unconnected, handleToolCall returns { ok:false, error }
|
|
140
|
+
* — the agent tolerates it.
|
|
141
|
+
*/
|
|
142
|
+
function resolve(): {
|
|
143
|
+
type: string;
|
|
144
|
+
command: string;
|
|
145
|
+
args: any[];
|
|
146
|
+
env: {};
|
|
147
|
+
description: string;
|
|
148
|
+
alwaysLoad: boolean;
|
|
149
|
+
};
|
|
150
|
+
function handleToolCall(name: any, args: any): Promise<string>;
|
|
151
|
+
let tools: ({
|
|
152
|
+
name: string;
|
|
153
|
+
description: string;
|
|
154
|
+
input_schema: {
|
|
155
|
+
type: string;
|
|
156
|
+
properties: {
|
|
157
|
+
title: {
|
|
158
|
+
type: string;
|
|
159
|
+
description: string;
|
|
160
|
+
};
|
|
161
|
+
markdown: {
|
|
162
|
+
type: string;
|
|
163
|
+
description: string;
|
|
164
|
+
};
|
|
165
|
+
text: {
|
|
166
|
+
type: string;
|
|
167
|
+
description: string;
|
|
168
|
+
};
|
|
169
|
+
documentId?: undefined;
|
|
170
|
+
};
|
|
171
|
+
required: string[];
|
|
172
|
+
};
|
|
173
|
+
} | {
|
|
174
|
+
name: string;
|
|
175
|
+
description: string;
|
|
176
|
+
input_schema: {
|
|
177
|
+
type: string;
|
|
178
|
+
properties: {
|
|
179
|
+
documentId: {
|
|
180
|
+
type: string;
|
|
181
|
+
description: string;
|
|
182
|
+
};
|
|
183
|
+
markdown: {
|
|
184
|
+
type: string;
|
|
185
|
+
description: string;
|
|
186
|
+
};
|
|
187
|
+
text: {
|
|
188
|
+
type: string;
|
|
189
|
+
description: string;
|
|
190
|
+
};
|
|
191
|
+
title?: undefined;
|
|
192
|
+
};
|
|
193
|
+
required: string[];
|
|
194
|
+
};
|
|
195
|
+
} | {
|
|
196
|
+
name: string;
|
|
197
|
+
description: string;
|
|
198
|
+
input_schema: {
|
|
199
|
+
type: string;
|
|
200
|
+
properties: {
|
|
201
|
+
documentId: {
|
|
202
|
+
type: string;
|
|
203
|
+
description: string;
|
|
204
|
+
};
|
|
205
|
+
title?: undefined;
|
|
206
|
+
markdown?: undefined;
|
|
207
|
+
text?: undefined;
|
|
208
|
+
};
|
|
209
|
+
required: string[];
|
|
210
|
+
};
|
|
211
|
+
} | {
|
|
212
|
+
name: string;
|
|
213
|
+
description: string;
|
|
214
|
+
input_schema: {
|
|
215
|
+
type: string;
|
|
216
|
+
properties: {
|
|
217
|
+
title?: undefined;
|
|
218
|
+
markdown?: undefined;
|
|
219
|
+
text?: undefined;
|
|
220
|
+
documentId?: undefined;
|
|
221
|
+
};
|
|
222
|
+
required?: undefined;
|
|
223
|
+
};
|
|
224
|
+
})[];
|
|
225
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import{existsSync as A}from"fs";import{fileURLToPath as v}from"url";import{dirname as R,resolve as L}from"path";import{resolveIntegrationToken as G,clearTokenCache as D}from"@zibby/core/backend-client.js";var w=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",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),Y=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"},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 P(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=R(v(import.meta.url)),t=L(r,"..","bin","mcp-skill.mjs");return A(t)?t:null}var g="https://docs.googleapis.com/v1",C="https://www.googleapis.com/drive/v3";function B(){let r=String(process.env.ZIBBY_INJECTED_GOOGLE_TOKEN||"").trim();if(!r)return null;let t=String(process.env.ZIBBY_INJECTED_GOOGLE_EMAIL||"").trim();return{token:r,email:t}}function $(){return String(process.env.ZIBBY_SENDER_IS_NON_OWNER||"").trim()==="1"}function U(){return String(process.env.ZIBBY_CHAT_STRICT_PERSONAL||"").trim()==="1"}var q="You haven't connected your own Google account \u2014 connect it at https://studio.zibby.dev/integrations (Google Docs). For privacy, I can't use anyone else's Google (including the project owner's) on your behalf.",I=2e4,J=25;function x(r){if(!r||typeof r!="string")return null;let t=r.trim(),e=t.match(/\/document\/(?:u\/\d+\/)?d\/([a-zA-Z0-9_-]+)/);return e?e[1]:/^[a-zA-Z0-9_-]{20,}$/.test(t)?t:null}async function p(r,t={}){let e=async()=>{let o,n=B();if(n)o=n.token;else{if(U()||$())throw new Error(q);({token:o}=await G("google"))}if(typeof o!="string"||!o)throw new Error(`Invalid google token type: ${typeof o}`);let i=await fetch(r,{method:t.method||"GET",headers:{Authorization:`Bearer ${o}`,Accept:"application/json",...t.body?{"Content-Type":"application/json"}:{},...t.headers},body:t.body?JSON.stringify(t.body):void 0});if(!i.ok){let d=await i.text().catch(()=>"");throw new Error(`Google API ${i.status}: ${d.slice(0,300)}`)}let c=await i.text().catch(()=>"");if(!c||!c.trim())return{};try{return JSON.parse(c)}catch{return{raw:c}}};try{return await e()}catch(o){let n=String(o?.message||o||"").toLowerCase();if(!(n.includes("token")||n.includes("401")||n.includes("unauthorized")))throw o;return D("google"),e()}}function j(r){let t=[],e="",o=0;for(;o<r.length;){let n=/^\[([^\]]+)\]\(([^)\s]+)\)/.exec(r.slice(o));if(n){t.push({start:e.length,end:e.length+n[1].length,link:n[2]}),e+=n[1],o+=n[0].length;continue}let i=/^\*\*([^*]+)\*\*/.exec(r.slice(o));if(i){t.push({start:e.length,end:e.length+i[1].length,bold:!0}),e+=i[1],o+=i[0].length;continue}let c=/^`([^`]+)`/.exec(r.slice(o));if(c){t.push({start:e.length,end:e.length+c[1].length,code:!0}),e+=c[1],o+=c[0].length;continue}e+=r[o],o+=1}return{text:e,styles:t}}function N(r,t){let e=String(r??"").replace(/\r\n/g,`
|
|
2
|
+
`);if(!e.trim())return{requests:[],endIndex:t};let o=e.split(`
|
|
3
|
+
`),n="",i=[],c=[];for(let s of o){let l=s,k=null,m=null,f=/^(#{1,3})\s+(.*)$/.exec(l),b=/^\s*[-*]\s+(.*)$/.exec(l),S=/^\s*\d+[.)]\s+(.*)$/.exec(l);f?(k=`HEADING_${f[1].length}`,l=f[2]):b?(m="BULLET_DISC_CIRCLE_SQUARE",l=b[1]):S&&(m="NUMBERED_DECIMAL_ALPHA_ROMAN",l=S[1]);let{text:O,styles:T}=j(l),y=t+n.length;for(let _ of T)c.push({..._,start:y+_.start,end:y+_.end});n+=`${O}
|
|
4
|
+
`,i.push({start:y,end:t+n.length,named:k,bullet:m})}if(!n)return{requests:[],endIndex:t};let d=[{insertText:{location:{index:t},text:n}}];for(let s of i)s.named&&d.push({updateParagraphStyle:{range:{startIndex:s.start,endIndex:s.end},paragraphStyle:{namedStyleType:s.named},fields:"namedStyleType"}});let a=null,u=()=>{a&&(d.push({createParagraphBullets:{range:{startIndex:a.start,endIndex:a.end},bulletPreset:a.preset}}),a=null)};for(let s of i)s.bullet?a&&a.preset===s.bullet?a.end=s.end:(u(),a={start:s.start,end:s.end,preset:s.bullet}):u();u();for(let s of c)s.end<=s.start||(s.bold?d.push({updateTextStyle:{range:{startIndex:s.start,endIndex:s.end},textStyle:{bold:!0},fields:"bold"}}):s.link?d.push({updateTextStyle:{range:{startIndex:s.start,endIndex:s.end},textStyle:{link:{url:s.link}},fields:"link"}}):s.code&&d.push({updateTextStyle:{range:{startIndex:s.start,endIndex:s.end},textStyle:{weightedFontFamily:{fontFamily:"Courier New"}},fields:"weightedFontFamily"}}));return{requests:d,endIndex:t+n.length}}function M(r){let t="",e=o=>{for(let n of Array.isArray(o)?o:[]){if(t.length>=I)return;if(n.paragraph)for(let i of n.paragraph.elements||[])t+=i?.textRun?.content||"";else if(n.table)for(let i of n.table.tableRows||[])for(let c of i.tableCells||[])e(c.content);else n.tableOfContents&&e(n.tableOfContents.content)}};return e(r?.content),t.slice(0,I)}var h=r=>`https://docs.google.com/document/d/${r}/edit`,E=r=>{let t=typeof r?.markdown=="string"?r.markdown:null,e=typeof r?.text=="string"?r.text:null;return t??e},W={id:"google-docs",serverName:"gdocs",allowedTools:["mcp__gdocs__*"],requiresIntegration:w.GOOGLE,description:"Google Docs \u2014 create, append to, and read Google Docs (drive.file scoped)",promptFragment:`## Google Docs (connected)
|
|
5
|
+
You can create and edit Google Docs for the user. IMPORTANT visibility caveat: the integration uses Google's per-file drive.file scope, so you can only see docs this app CREATED (or the user explicitly picked) \u2014 not the user's whole Drive.
|
|
6
|
+
Docs access is PER-USER: each teammate connects their OWN Google account (Integrations \u2192 Google Docs). In shared-chat contexts the runtime routes these tools to the SENDER's own Google; a teammate who hasn't connected their own Google gets { ok:false } with connect instructions \u2014 for privacy the project owner's Google is NEVER used on someone else's behalf. Relay those instructions rather than retrying.
|
|
7
|
+
- gdocs_create_doc: create a new Google Doc from a title + markdown (headings/bold/bullets/links supported) or plain text; returns { documentId, url }. Share the url with the user.
|
|
8
|
+
- gdocs_append: append markdown/text to the end of a doc you created earlier (pass the documentId or doc URL).
|
|
9
|
+
- gdocs_get: read a doc back as plain text (works for app-created/user-picked docs; arbitrary docs need the extended documents.readonly connection).
|
|
10
|
+
- gdocs_list_created: list the Google Docs visible to this app (drive.file \u2192 only docs it created or the user picked).
|
|
11
|
+
These tools return { ok:false, error } on failure \u2014 treat an unavailable Google connection as "cannot deliver to Docs" and report it rather than blocking the task.`,resolve(){let r=P();if(!r)return null;let t={};for(let e of["ZIBBY_INJECTED_GOOGLE_TOKEN","ZIBBY_INJECTED_GOOGLE_EMAIL","ZIBBY_SENDER_IS_NON_OWNER","ZIBBY_CHAT_STRICT_PERSONAL"])process.env[e]&&(t[e]=process.env[e]);return{type:"stdio",command:"node",args:[r,"../dist/googleDocs.js","googleDocsSkill"],env:t,description:this.description,alwaysLoad:!0}},async handleToolCall(r,t){try{switch(r){case"gdocs_create_doc":{let e=typeof t?.title=="string"&&t.title.trim()?t.title.trim():null;if(!e)return JSON.stringify({ok:!1,error:"title is required"});let n=(await p(`${g}/documents`,{method:"POST",body:{title:e}}))?.documentId;if(!n)return JSON.stringify({ok:!1,error:"Google Docs create returned no documentId"});let i=E(t);if(i&&i.trim()){let{requests:c}=N(i,1);c.length&&await p(`${g}/documents/${n}:batchUpdate`,{method:"POST",body:{requests:c}})}return JSON.stringify({ok:!0,documentId:n,title:e,url:h(n)})}case"gdocs_append":{let e=x(t?.documentId||t?.url||t?.id);if(!e)return JSON.stringify({ok:!1,error:"A valid Google Docs documentId or URL is required"});let o=E(t);if(!o||!o.trim())return JSON.stringify({ok:!1,error:"markdown or text content is required"});let i=(await p(`${g}/documents/${e}`))?.body,c=Array.isArray(i?.content)?i.content:[],d=c.length&&c[c.length-1].endIndex||2,a=Math.max(1,d-1),u=[],s=a;a>1&&(u.push({insertText:{location:{index:a},text:`
|
|
12
|
+
`}}),s=a+1);let l=N(o,s);return u.push(...l.requests),await p(`${g}/documents/${e}:batchUpdate`,{method:"POST",body:{requests:u}}),JSON.stringify({ok:!0,documentId:e,url:h(e)})}case"gdocs_get":{let e=x(t?.documentId||t?.url||t?.id);if(!e)return JSON.stringify({ok:!1,error:"A valid Google Docs documentId or URL is required"});let o=await p(`${g}/documents/${e}`),n=M(o?.body);return JSON.stringify({ok:!0,documentId:e,title:o?.title||"",url:h(e),text:n,...n.length>=I?{truncated:!0}:{}})}case"gdocs_list_created":{let e=new URLSearchParams({q:"'me' in owners and mimeType='application/vnd.google-apps.document' and trashed=false",fields:"files(id,name,modifiedTime,webViewLink)",pageSize:String(J),orderBy:"modifiedTime desc"}),o=await p(`${C}/files?${e.toString()}`),n=(Array.isArray(o?.files)?o.files:[]).map(i=>({documentId:i.id,title:i.name,modifiedTime:i.modifiedTime,url:i.webViewLink||h(i.id)}));return JSON.stringify({ok:!0,count:n.length,files:n})}default:return JSON.stringify({ok:!1,error:`Unknown tool: ${r}`})}}catch(e){return JSON.stringify({ok:!1,error:e.message})}},tools:[{name:"gdocs_create_doc",description:"Create a new Google Doc with a title and optional content (markdown: #/##/### headings, - bullets, 1. numbered lists, **bold**, [links](url), `code`; or plain text). Returns { ok, documentId, url } \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)."}},required:["title"]}},{name:"gdocs_append",description:"Append markdown/text content to the END of an existing Google Doc. Only works on docs this app created or the user explicitly picked (drive.file scope). Accepts a documentId or a full docs.google.com URL. Returns { ok, documentId, url }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Google Docs documentId OR a full https://docs.google.com/document/d/... 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:"gdocs_get",description:"Read a Google Doc back as plain text (truncated to ~20k chars). Under the default drive.file scope this works ONLY for docs this app created or the user explicitly picked; reading arbitrary docs requires the extended documents.readonly connection. Returns { ok, documentId, title, url, text }.",input_schema:{type:"object",properties:{documentId:{type:"string",description:"Google Docs documentId OR a full https://docs.google.com/document/d/... URL."}},required:["documentId"]}},{name:"gdocs_list_created",description:"List the Google Docs visible to this integration, newest first (max 25). NOTE: under the drive.file scope this lists ONLY docs the app created or the user explicitly picked \u2014 it is NOT a full Drive search. Returns { ok, count, files:[{ documentId, title, modifiedTime, url }] }.",input_schema:{type:"object",properties:{}}}]};export{q as NON_OWNER_REFUSAL,U as chatStrictPersonal,M as extractPlainText,p as googleApi,W as googleDocsSkill,B as injectedGoogleToken,N as markdownToRequests,x as parseDocId,j as parseInlineMarkdown,$ as senderIsNonOwner};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,9 @@ export namespace SKILLS {
|
|
|
11
11
|
let GIT_WRITE: string;
|
|
12
12
|
let SLACK: string;
|
|
13
13
|
let LARK: string;
|
|
14
|
+
let DISCORD: string;
|
|
14
15
|
let NOTION: string;
|
|
16
|
+
let GOOGLE_DOCS: string;
|
|
15
17
|
let LINKEDIN: string;
|
|
16
18
|
let CHAT_NOTIFY: string;
|
|
17
19
|
let SENTRY: string;
|
|
@@ -42,8 +44,10 @@ import { gitSkill } from './git.js';
|
|
|
42
44
|
import { gitWriteSkill } from './git-write.js';
|
|
43
45
|
import { slackSkill } from './slack.js';
|
|
44
46
|
import { larkSkill } from './lark.js';
|
|
47
|
+
import { discordSkill } from './discord.js';
|
|
45
48
|
import { notionSkill } from './notion.js';
|
|
46
49
|
import { linkedinSkill } from './linkedin.js';
|
|
50
|
+
import { googleDocsSkill } from './googleDocs.js';
|
|
47
51
|
import { chatNotifySkill } from './chat-notify.js';
|
|
48
52
|
import { sentrySkill } from './sentry.js';
|
|
49
53
|
import { memorySkill } from './memory.js';
|
|
@@ -55,7 +59,7 @@ import { testRunnerSkill } from './test-runner.js';
|
|
|
55
59
|
import { skillInstallerSkill } from './skill-installer.js';
|
|
56
60
|
import { coreToolsSkill } from './core-tools.js';
|
|
57
61
|
import { workflowBuilderSkill } from './workflow-builder.js';
|
|
58
|
-
export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, notionSkill, linkedinSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, datasetStoreSkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
|
|
62
|
+
export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, discordSkill, notionSkill, linkedinSkill, googleDocsSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, datasetStoreSkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
|
|
59
63
|
export { openaiBillingSkill, anthropicBillingSkill, cursorAdminSkill, fetchOpenAICosts, fetchOpenAIProjects, fetchAnthropicCosts, fetchAnthropicWorkspaces, fetchCursorSpend, fetchAllProviders, groupByKey, meanStddev } from "./llm-billing.js";
|
|
60
64
|
export { reportObjectSchema, reportToBlockKit, reportToLarkCard, SEVERITIES as REPORT_SEVERITIES } from "./report.js";
|
|
61
65
|
export { skill, functionSkill } from "./function-skill.js";
|