@zibby/skills 2.0.5 → 2.0.6
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/artifact.js +7 -7
- package/dist/chat-notify.js +4 -4
- package/dist/chatProgress.js +4 -4
- package/dist/datasetStore.js +2 -2
- package/dist/discord.js +3 -3
- package/dist/figma.js +2 -2
- package/dist/git-write.js +9 -9
- package/dist/github.js +5 -5
- package/dist/gitlab.js +5 -5
- package/dist/googleDocs.js +9 -9
- package/dist/hubspot.js +1 -1
- package/dist/index.js +179 -181
- package/dist/jira.d.ts +19 -9
- package/dist/jira.js +22 -20
- package/dist/kvMemory.js +2 -2
- package/dist/lark.js +2 -2
- package/dist/larkAttendance.js +1 -1
- package/dist/larkDocs.js +3 -3
- package/dist/lib/http-deadline.d.ts +117 -0
- package/dist/lib/http-deadline.js +1 -0
- package/dist/lib/markup.d.ts +158 -0
- package/dist/lib/markup.js +22 -0
- package/dist/linear.js +15 -15
- package/dist/linkedin.js +2 -2
- package/dist/llm-billing.js +1 -1
- package/dist/notion.js +7 -7
- package/dist/opendesign.js +2 -2
- package/dist/package.json +6 -5
- package/dist/report.d.ts +42 -42
- package/dist/review.js +4 -4
- package/dist/reviewMemoryIo.js +1 -1
- package/dist/sentry.js +2 -2
- package/dist/skill-installer.js +3 -3
- package/dist/slack.js +2 -2
- package/dist/trackers/github-adapter.js +5 -5
- package/dist/trackers/index.js +46 -44
- package/dist/trackers/jira-adapter.js +24 -22
- package/dist/trackers/linear-adapter.js +19 -19
- package/dist/trackers/plane-adapter.js +1 -1
- package/dist/triggerAgent.js +1 -1
- package/dist/vikunja.d.ts +8 -1
- package/dist/vikunja.js +22 -7
- package/docs/templates/catalog-metadata.md +1 -1
- package/package.json +6 -5
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/skills",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Built-in skill definitions for the Zibby agent-workflow framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
"./review": {
|
|
74
74
|
"types": "./dist/review.d.ts",
|
|
75
75
|
"default": "./dist/review.js"
|
|
76
|
-
}
|
|
76
|
+
},
|
|
77
|
+
"./markup": {"types": "./dist/lib/markup.d.ts", "default": "./dist/lib/markup.js"}
|
|
77
78
|
},
|
|
78
79
|
"scripts": {
|
|
79
80
|
"build": "node ../scripts/build.mjs && npm run build:types",
|
|
@@ -116,10 +117,10 @@
|
|
|
116
117
|
"dependencies": {
|
|
117
118
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
118
119
|
"@resvg/resvg-js": "^2.6.2",
|
|
119
|
-
"@zibby/agent-workflow": "2.0.
|
|
120
|
+
"@zibby/agent-workflow": "2.0.6",
|
|
120
121
|
"@zibby/bin-oxlint": "^1.73.0",
|
|
121
122
|
"@zibby/bin-semgrep": "^1.169.0",
|
|
122
|
-
"@zibby/skill-ids": "2.0.
|
|
123
|
+
"@zibby/skill-ids": "2.0.6",
|
|
123
124
|
"echarts": "^6.1.0",
|
|
124
125
|
"mem0ai": "npm:@zibby/mem0ai@^3.0.5",
|
|
125
126
|
"zod": "^3.23.0 || ^4.0.0"
|
|
@@ -134,7 +135,7 @@
|
|
|
134
135
|
}
|
|
135
136
|
},
|
|
136
137
|
"optionalDependencies": {
|
|
137
|
-
"@zibby/mcp-browser": "2.0.
|
|
138
|
+
"@zibby/mcp-browser": "2.0.6",
|
|
138
139
|
"@zibby/mcp-memory": "*"
|
|
139
140
|
},
|
|
140
141
|
"devDependencies": {
|
package/dist/report.d.ts
CHANGED
|
@@ -72,16 +72,16 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
72
72
|
severity: z.ZodOptional<z.ZodEnum<["ok", "info", "warn", "critical"]>>;
|
|
73
73
|
}, "strip", z.ZodTypeAny, {
|
|
74
74
|
values?: number[];
|
|
75
|
+
kind?: "trend";
|
|
75
76
|
title?: string;
|
|
76
77
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
77
|
-
kind?: "trend";
|
|
78
78
|
labels?: string[];
|
|
79
79
|
highlight?: "none" | "last" | "max" | "min";
|
|
80
80
|
}, {
|
|
81
81
|
values?: number[];
|
|
82
|
+
kind?: "trend";
|
|
82
83
|
title?: string;
|
|
83
84
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
84
|
-
kind?: "trend";
|
|
85
85
|
labels?: string[];
|
|
86
86
|
highlight?: "none" | "last" | "max" | "min";
|
|
87
87
|
}>, z.ZodObject<{
|
|
@@ -90,13 +90,13 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
90
90
|
headers: z.ZodArray<z.ZodString, "many">;
|
|
91
91
|
rows: z.ZodArray<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "many">, "many">;
|
|
92
92
|
}, "strip", z.ZodTypeAny, {
|
|
93
|
-
title?: string;
|
|
94
93
|
kind?: "table";
|
|
94
|
+
title?: string;
|
|
95
95
|
headers?: string[];
|
|
96
96
|
rows?: (string | number)[][];
|
|
97
97
|
}, {
|
|
98
|
-
title?: string;
|
|
99
98
|
kind?: "table";
|
|
99
|
+
title?: string;
|
|
100
100
|
headers?: string[];
|
|
101
101
|
rows?: (string | number)[][];
|
|
102
102
|
}>, z.ZodObject<{
|
|
@@ -105,15 +105,15 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
105
105
|
tone: z.ZodOptional<z.ZodDefault<z.ZodEnum<["ok", "info", "warn", "critical"]>>>;
|
|
106
106
|
items: z.ZodArray<z.ZodString, "many">;
|
|
107
107
|
}, "strip", z.ZodTypeAny, {
|
|
108
|
-
title?: string;
|
|
109
108
|
kind?: "callouts";
|
|
110
|
-
|
|
109
|
+
title?: string;
|
|
111
110
|
items?: string[];
|
|
111
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
112
112
|
}, {
|
|
113
|
-
title?: string;
|
|
114
113
|
kind?: "callouts";
|
|
115
|
-
|
|
114
|
+
title?: string;
|
|
116
115
|
items?: string[];
|
|
116
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
117
117
|
}>, z.ZodObject<{
|
|
118
118
|
kind: z.ZodLiteral<"breakdown">;
|
|
119
119
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -134,8 +134,8 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
134
134
|
value?: string;
|
|
135
135
|
}>, "many">;
|
|
136
136
|
}, "strip", z.ZodTypeAny, {
|
|
137
|
-
title?: string;
|
|
138
137
|
kind?: "breakdown";
|
|
138
|
+
title?: string;
|
|
139
139
|
rows?: {
|
|
140
140
|
label?: string;
|
|
141
141
|
sub?: string;
|
|
@@ -143,8 +143,8 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
143
143
|
value?: string;
|
|
144
144
|
}[];
|
|
145
145
|
}, {
|
|
146
|
-
title?: string;
|
|
147
146
|
kind?: "breakdown";
|
|
147
|
+
title?: string;
|
|
148
148
|
rows?: {
|
|
149
149
|
label?: string;
|
|
150
150
|
sub?: string;
|
|
@@ -156,33 +156,33 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
156
156
|
title: z.ZodOptional<z.ZodString>;
|
|
157
157
|
text: z.ZodString;
|
|
158
158
|
}, "strip", z.ZodTypeAny, {
|
|
159
|
+
kind?: "paragraph";
|
|
159
160
|
text?: string;
|
|
160
161
|
title?: string;
|
|
161
|
-
kind?: "paragraph";
|
|
162
162
|
}, {
|
|
163
|
+
kind?: "paragraph";
|
|
163
164
|
text?: string;
|
|
164
165
|
title?: string;
|
|
165
|
-
kind?: "paragraph";
|
|
166
166
|
}>]>, "many">>, ({
|
|
167
167
|
values?: number[];
|
|
168
|
+
kind?: "trend";
|
|
168
169
|
title?: string;
|
|
169
170
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
170
|
-
kind?: "trend";
|
|
171
171
|
labels?: string[];
|
|
172
172
|
highlight?: "none" | "last" | "max" | "min";
|
|
173
173
|
} | {
|
|
174
|
-
title?: string;
|
|
175
174
|
kind?: "table";
|
|
175
|
+
title?: string;
|
|
176
176
|
headers?: string[];
|
|
177
177
|
rows?: (string | number)[][];
|
|
178
178
|
} | {
|
|
179
|
-
title?: string;
|
|
180
179
|
kind?: "callouts";
|
|
181
|
-
|
|
180
|
+
title?: string;
|
|
182
181
|
items?: string[];
|
|
182
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
183
183
|
} | {
|
|
184
|
-
title?: string;
|
|
185
184
|
kind?: "breakdown";
|
|
185
|
+
title?: string;
|
|
186
186
|
rows?: {
|
|
187
187
|
label?: string;
|
|
188
188
|
sub?: string;
|
|
@@ -190,29 +190,29 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
190
190
|
value?: string;
|
|
191
191
|
}[];
|
|
192
192
|
} | {
|
|
193
|
+
kind?: "paragraph";
|
|
193
194
|
text?: string;
|
|
194
195
|
title?: string;
|
|
195
|
-
kind?: "paragraph";
|
|
196
196
|
})[], ({
|
|
197
197
|
values?: number[];
|
|
198
|
+
kind?: "trend";
|
|
198
199
|
title?: string;
|
|
199
200
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
200
|
-
kind?: "trend";
|
|
201
201
|
labels?: string[];
|
|
202
202
|
highlight?: "none" | "last" | "max" | "min";
|
|
203
203
|
} | {
|
|
204
|
-
title?: string;
|
|
205
204
|
kind?: "table";
|
|
205
|
+
title?: string;
|
|
206
206
|
headers?: string[];
|
|
207
207
|
rows?: (string | number)[][];
|
|
208
208
|
} | {
|
|
209
|
-
title?: string;
|
|
210
209
|
kind?: "callouts";
|
|
211
|
-
|
|
210
|
+
title?: string;
|
|
212
211
|
items?: string[];
|
|
212
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
213
213
|
} | {
|
|
214
|
-
title?: string;
|
|
215
214
|
kind?: "breakdown";
|
|
215
|
+
title?: string;
|
|
216
216
|
rows?: {
|
|
217
217
|
label?: string;
|
|
218
218
|
sub?: string;
|
|
@@ -220,9 +220,9 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
220
220
|
value?: string;
|
|
221
221
|
}[];
|
|
222
222
|
} | {
|
|
223
|
+
kind?: "paragraph";
|
|
223
224
|
text?: string;
|
|
224
225
|
title?: string;
|
|
225
|
-
kind?: "paragraph";
|
|
226
226
|
})[]>;
|
|
227
227
|
footer: z.ZodOptional<z.ZodObject<{
|
|
228
228
|
viewUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -236,6 +236,10 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
236
236
|
}>>;
|
|
237
237
|
}, "strip", z.ZodTypeAny, {
|
|
238
238
|
title?: string;
|
|
239
|
+
footer?: {
|
|
240
|
+
viewUrl?: string;
|
|
241
|
+
rerunUrl?: string;
|
|
242
|
+
};
|
|
239
243
|
subtitle?: string;
|
|
240
244
|
headline?: {
|
|
241
245
|
summary?: string;
|
|
@@ -248,24 +252,24 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
248
252
|
};
|
|
249
253
|
sections?: ({
|
|
250
254
|
values?: number[];
|
|
255
|
+
kind?: "trend";
|
|
251
256
|
title?: string;
|
|
252
257
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
253
|
-
kind?: "trend";
|
|
254
258
|
labels?: string[];
|
|
255
259
|
highlight?: "none" | "last" | "max" | "min";
|
|
256
260
|
} | {
|
|
257
|
-
title?: string;
|
|
258
261
|
kind?: "table";
|
|
262
|
+
title?: string;
|
|
259
263
|
headers?: string[];
|
|
260
264
|
rows?: (string | number)[][];
|
|
261
265
|
} | {
|
|
262
|
-
title?: string;
|
|
263
266
|
kind?: "callouts";
|
|
264
|
-
|
|
267
|
+
title?: string;
|
|
265
268
|
items?: string[];
|
|
269
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
266
270
|
} | {
|
|
267
|
-
title?: string;
|
|
268
271
|
kind?: "breakdown";
|
|
272
|
+
title?: string;
|
|
269
273
|
rows?: {
|
|
270
274
|
label?: string;
|
|
271
275
|
sub?: string;
|
|
@@ -273,16 +277,16 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
273
277
|
value?: string;
|
|
274
278
|
}[];
|
|
275
279
|
} | {
|
|
280
|
+
kind?: "paragraph";
|
|
276
281
|
text?: string;
|
|
277
282
|
title?: string;
|
|
278
|
-
kind?: "paragraph";
|
|
279
283
|
})[];
|
|
284
|
+
}, {
|
|
285
|
+
title?: string;
|
|
280
286
|
footer?: {
|
|
281
287
|
viewUrl?: string;
|
|
282
288
|
rerunUrl?: string;
|
|
283
289
|
};
|
|
284
|
-
}, {
|
|
285
|
-
title?: string;
|
|
286
290
|
subtitle?: string;
|
|
287
291
|
headline?: {
|
|
288
292
|
summary?: string;
|
|
@@ -295,24 +299,24 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
295
299
|
};
|
|
296
300
|
sections?: ({
|
|
297
301
|
values?: number[];
|
|
302
|
+
kind?: "trend";
|
|
298
303
|
title?: string;
|
|
299
304
|
severity?: "warn" | "info" | "critical" | "ok";
|
|
300
|
-
kind?: "trend";
|
|
301
305
|
labels?: string[];
|
|
302
306
|
highlight?: "none" | "last" | "max" | "min";
|
|
303
307
|
} | {
|
|
304
|
-
title?: string;
|
|
305
308
|
kind?: "table";
|
|
309
|
+
title?: string;
|
|
306
310
|
headers?: string[];
|
|
307
311
|
rows?: (string | number)[][];
|
|
308
312
|
} | {
|
|
309
|
-
title?: string;
|
|
310
313
|
kind?: "callouts";
|
|
311
|
-
|
|
314
|
+
title?: string;
|
|
312
315
|
items?: string[];
|
|
316
|
+
tone?: "warn" | "info" | "critical" | "ok";
|
|
313
317
|
} | {
|
|
314
|
-
title?: string;
|
|
315
318
|
kind?: "breakdown";
|
|
319
|
+
title?: string;
|
|
316
320
|
rows?: {
|
|
317
321
|
label?: string;
|
|
318
322
|
sub?: string;
|
|
@@ -320,14 +324,10 @@ export declare const reportObjectSchema: z.ZodObject<{
|
|
|
320
324
|
value?: string;
|
|
321
325
|
}[];
|
|
322
326
|
} | {
|
|
327
|
+
kind?: "paragraph";
|
|
323
328
|
text?: string;
|
|
324
329
|
title?: string;
|
|
325
|
-
kind?: "paragraph";
|
|
326
330
|
})[];
|
|
327
|
-
footer?: {
|
|
328
|
-
viewUrl?: string;
|
|
329
|
-
rerunUrl?: string;
|
|
330
|
-
};
|
|
331
331
|
}>;
|
|
332
332
|
/**
|
|
333
333
|
* Convert a report-object → Slack Block-Kit `blocks` array.
|
package/dist/review.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
2
|
-
${e.legacyNote}`;let
|
|
3
|
-
${
|
|
4
|
-
`)}import{existsSync as
|
|
1
|
+
var h=1,d="review-record",v=204800,A=2e3,k=["blocker","should-fix","nit"],S={blocker:0,"should-fix":1,nit:2},I=["open","conceded","held","resolved"];function O(e){let n=String(e??"").trim().toLowerCase();return n?n.includes("\u{1F534}")||n.includes("blocker")||n.includes("critical")||n.includes("high")?"blocker":n.includes("\u{1F7E2}")||n.includes("nit")||n.includes("minor")||n.includes("low")||n.includes("info")?"nit":(n.includes("\u{1F7E1}")||n.includes("should")||n.includes("medium")||n.includes("warn"),"should-fix"):"should-fix"}var a=(e,n)=>{let t=e==null?"":String(e);return t.length>n?t.slice(0,n):t},R=e=>typeof Buffer<"u"&&typeof Buffer.byteLength=="function"?Buffer.byteLength(e,"utf8"):new TextEncoder().encode(e).length;function N({headSha:e=null,verdict:n="COMMENT",objectivesChecked:t=!1,findings:r=[],nowIso:o=null}={}){let s=Array.isArray(r)?r:[];return{schemaVersion:1,kind:d,headSha:e||null,verdict:String(n||"COMMENT"),objectivesChecked:!!t,reviewedAt:o||null,findings:s.map((i,c)=>({id:`f${c+1}`,file:a(i?.file,512),line:i?.line==null?null:i.line,severity:O(i?.severity),category:a(i?.category,64),claim:a(i?.claim,2e3),evidence:a(i?.evidence,2e3),suggestion:a(i?.suggestion,2e3),confidence:typeof i?.confidence=="number"?i.confidence:null,status:"open"}))}}function L(e,{findingId:n,status:t,note:r}={}){if(!e||!Array.isArray(e.findings))return e;let o=I.includes(t)?t:"held";return{...e,findings:e.findings.map(s=>s.id===n?{...s,status:o,replyNote:a(r,2e3)}:s)}}function _(e){if(!e)return"";let n=[...e.findings||[]].sort((s,i)=>{let c=(S[s.severity]??9)-(S[i.severity]??9);if(c!==0)return c;let l=s.file||"",u=i.file||"";if(l!==u)return l<u?-1:1;let y=Number(s.line)||0,E=Number(i.line)||0;return y!==E?y-E:(s.id||"")<(i.id||"")?-1:1}),t={...e,findings:n},r=JSON.stringify(t);if(R(r)<=204800)return r;let o=[...n];for(t={...e,findings:o,truncated:!0};o.length>0&&R(JSON.stringify(t))>204800;)o.pop(),t={...e,findings:o,truncated:!0};return JSON.stringify(t)}var T=e=>e&&typeof e=="object"&&!Array.isArray(e)&&e.kind===d;function m(e){if(e==null)return{kind:"empty"};if(typeof e=="object"){if(!Array.isArray(e)&&typeof e.error=="string")return{kind:"empty"};if(T(e)){let r=Number(e.schemaVersion)>1;return{kind:"record",record:e,future:r}}return{kind:"legacy",legacyNote:g(e)}}if(typeof e!="string")return{kind:"empty"};let n=e.trim();if(!n)return{kind:"empty"};let t;try{t=JSON.parse(n)}catch{return{kind:"legacy",legacyNote:n}}if(t&&typeof t=="object"&&typeof t.error=="string")return{kind:"empty"};if(T(t)){let r=Number(t.schemaVersion)>1;return{kind:"record",record:t,future:r}}return{kind:"legacy",legacyNote:n}}function g(e){try{return JSON.stringify(e)}catch{return String(e)}}function w(e){if(!e||e.kind==="empty")return"";if(e.kind==="legacy")return`Prior review memory (legacy note, advisory only):
|
|
2
|
+
${e.legacyNote}`;let n=e.record||{};if(e.future)return`Prior review memory (newer format ${n.schemaVersion} \u2014 advisory; verify against the live thread):
|
|
3
|
+
${g(n).slice(0,2e3)}`;let t=[`Prior review of this change (verdict: ${n.verdict||"COMMENT"}${n.headSha?`, commit ${n.headSha}`:""}):`],r=(n.findings||[]).map(o=>{let s=o.file?`${o.file}${o.line!=null?`:${o.line}`:""}`:"(general)",i=o.status&&o.status!=="open"?` [${o.status}]`:"";return`- [${o.severity}] ${s} \u2014 ${o.claim||""}${i}`});return n.truncated&&r.push("- (\u2026older/lower-severity findings were truncated to fit memory)"),[...t,...r].join(`
|
|
4
|
+
`)}import{existsSync as F,readFileSync as K}from"node:fs";import{homedir as B}from"node:os";import{join as P}from"node:path";var f={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 x(e,n,t=process.env){let r=Number(t?.[e]);return Number.isFinite(r)&&r>0?Math.min(6e5,Math.max(1e3,Math.floor(r))):n}function C(e="api",n=process.env){let t=f[e]||f.api;return x(t.knob,t.fallback,n)}function D(e){return e?.name==="TimeoutError"||e?.name==="AbortError"}function $(e){try{return new URL(String(e?.url??e)).host||"unknown host"}catch{return"unknown host"}}function U(e,n){if(!e)return n;let t=new AbortController,r=i=>{t.signal.aborted||t.abort(i)},o=()=>r(e.reason),s=()=>r(n.reason);return t.signal.addEventListener("abort",()=>{e.removeEventListener("abort",o),n.removeEventListener("abort",s)},{once:!0}),e.aborted?r(e.reason):n.aborted?r(n.reason):(e.addEventListener("abort",o,{once:!0}),n.addEventListener("abort",s,{once:!0})),t.signal}async function M(e,n={},t={}){let r=t.kind||"api",o=(f[r]||f.api).knob,s=t.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(t.timeoutMs))):C(r),i=n?.signal;if(i?.aborted)throw i.reason??new DOMException("This operation was aborted","AbortError");let c=AbortSignal.timeout(s),l=U(i,c);try{return await fetch(e,{...n,signal:l})}catch(u){throw c.aborted&&D(u)?new Error(`${t.what||"request"} TIMED OUT after ${s}ms against ${$(e)} (${o})`):u}}function V(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let e=P(B(),".zibby","config.json");return F(e)&&JSON.parse(K(e,"utf-8")).sessionToken||null}catch{return null}}function Y(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function W(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function p(e){return`${W()}:${e}`}async function b(e,n){let t=V();if(!t)return{__noToken:!0};let r=`${Y()}/credits/review-memory`,o=await M(r,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify({op:e,...n})},{kind:"api",what:`review-memory ${e}`});if(!o.ok){let s=await o.text().catch(()=>"");throw new Error(`review-memory ${e} failed (${o.status}): ${s.slice(0,300)}`)}return o.json()}async function H(e,n){try{let t=_(n);if(!t)return{ok:!1,reason:"empty-record"};let r=await b("store",{scope:p(e),content:t});return r&&r.__noToken?{ok:!1,reason:"no-token"}:{ok:!0}}catch(t){return{ok:!1,reason:t?.message||"store-error"}}}async function J(e){try{let n=await b("recall",{scope:p(e)});if(!n||n.__noToken)return{kind:"empty"};let t=n.found&&n.memory?n.memory:null;if(!t)return{kind:"empty"};let r=t.content!=null?t.content:t.metadata!=null?t.metadata:null;return m(r)}catch{return{kind:"empty"}}}export{v as CONTENT_MAX_BYTES,A as FIELD_MAX_CHARS,I as FINDING_STATUSES,d as REVIEW_RECORD_KIND,h as REVIEW_RECORD_SCHEMA_VERSION,k as SEVERITY_TIERS,N as buildReviewRecord,O as normalizeSeverity,m as parseReviewMemory,J as recallReviewRecord,p as scopeForReviewMemory,_ as serializeReviewRecord,H as storeReviewRecord,w as summarizeForPrompt,L as upsertReplyOutcome};
|
package/dist/reviewMemoryIo.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as v,readFileSync as A}from"node:fs";import{homedir as N}from"node:os";import{join as L}from"node:path";var b="review-record";var p={blocker:0,"should-fix":1,nit:2};var y=e=>typeof Buffer<"u"&&typeof Buffer.byteLength=="function"?Buffer.byteLength(e,"utf8"):new TextEncoder().encode(e).length;function _(e){if(!e)return"";let t=[...e.findings||[]].sort((i,s)=>{let c=(p[i.severity]??9)-(p[s.severity]??9);if(c!==0)return c;let u=i.file||"",a=s.file||"";if(u!==a)return u<a?-1:1;let f=Number(i.line)||0,d=Number(s.line)||0;return f!==d?f-d:(i.id||"")<(s.id||"")?-1:1}),n={...e,findings:t},r=JSON.stringify(n);if(y(r)<=204800)return r;let o=[...t];for(n={...e,findings:o,truncated:!0};o.length>0&&y(JSON.stringify(n))>204800;)o.pop(),n={...e,findings:o,truncated:!0};return JSON.stringify(n)}var m=e=>e&&typeof e=="object"&&!Array.isArray(e)&&e.kind===b;function E(e){if(e==null)return{kind:"empty"};if(typeof e=="object"){if(!Array.isArray(e)&&typeof e.error=="string")return{kind:"empty"};if(m(e)){let r=Number(e.schemaVersion)>1;return{kind:"record",record:e,future:r}}return{kind:"legacy",legacyNote:O(e)}}if(typeof e!="string")return{kind:"empty"};let t=e.trim();if(!t)return{kind:"empty"};let n;try{n=JSON.parse(t)}catch{return{kind:"legacy",legacyNote:t}}if(n&&typeof n=="object"&&typeof n.error=="string")return{kind:"empty"};if(m(n)){let r=Number(n.schemaVersion)>1;return{kind:"record",record:n,future:r}}return{kind:"legacy",legacyNote:t}}function O(e){try{return JSON.stringify(e)}catch{return String(e)}}var l={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 h(e,t,n=process.env){let r=Number(n?.[e]);return Number.isFinite(r)&&r>0?Math.min(6e5,Math.max(1e3,Math.floor(r))):t}function I(e="api",t=process.env){let n=l[e]||l.api;return h(n.knob,n.fallback,t)}function M(e){return e?.name==="TimeoutError"||e?.name==="AbortError"}function R(e){try{return new URL(String(e?.url??e)).host||"unknown host"}catch{return"unknown host"}}function k(e,t){if(!e)return t;let n=new AbortController,r=s=>{n.signal.aborted||n.abort(s)},o=()=>r(e.reason),i=()=>r(t.reason);return n.signal.addEventListener("abort",()=>{e.removeEventListener("abort",o),t.removeEventListener("abort",i)},{once:!0}),e.aborted?r(e.reason):t.aborted?r(t.reason):(e.addEventListener("abort",o,{once:!0}),t.addEventListener("abort",i,{once:!0})),n.signal}async function S(e,t={},n={}){let r=n.kind||"api",o=(l[r]||l.api).knob,i=n.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(n.timeoutMs))):I(r),s=t?.signal;if(s?.aborted)throw s.reason??new DOMException("This operation was aborted","AbortError");let c=AbortSignal.timeout(i),u=k(s,c);try{return await fetch(e,{...t,signal:u})}catch(a){throw c.aborted&&M(a)?new Error(`${n.what||"request"} TIMED OUT after ${i}ms against ${R(e)} (${o})`):a}}function w(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let e=L(N(),".zibby","config.json");return v(e)&&JSON.parse(A(e,"utf-8")).sessionToken||null}catch{return null}}function x(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function C(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function T(e){return`${C()}:${e}`}async function g(e,t){let n=w();if(!n)return{__noToken:!0};let r=`${x()}/credits/review-memory`,o=await S(r,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({op:e,...t})},{kind:"api",what:`review-memory ${e}`});if(!o.ok){let i=await o.text().catch(()=>"");throw new Error(`review-memory ${e} failed (${o.status}): ${i.slice(0,300)}`)}return o.json()}async function V(e,t){try{let n=_(t);if(!n)return{ok:!1,reason:"empty-record"};let r=await g("store",{scope:T(e),content:n});return r&&r.__noToken?{ok:!1,reason:"no-token"}:{ok:!0}}catch(n){return{ok:!1,reason:n?.message||"store-error"}}}async function Y(e){try{let t=await g("recall",{scope:T(e)});if(!t||t.__noToken)return{kind:"empty"};let n=t.found&&t.memory?t.memory:null;if(!n)return{kind:"empty"};let r=n.content!=null?n.content:n.metadata!=null?n.metadata:null;return E(r)}catch{return{kind:"empty"}}}export{Y as recallReviewRecord,T as scopeForReviewMemory,V as storeReviewRecord};
|
package/dist/sentry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as E}from"fs";import{fileURLToPath as w}from"url";import{dirname as O,resolve as v}from"path";import{resolveIntegrationToken as u}from"@zibby/core/backend-client.js";var _=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"}),U=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"}});var p={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 I(n,e,t=process.env){let r=Number(t?.[n]);return Number.isFinite(r)&&r>0?Math.min(6e5,Math.max(1e3,Math.floor(r))):e}function f(n="api",e=process.env){let t=p[n]||p.api;return I(t.knob,t.fallback,e)}function b(n){return n?.name==="TimeoutError"||n?.name==="AbortError"}function k(n){try{return new URL(String(n?.url??n)).host||"unknown host"}catch{return"unknown host"}}function T(n,e){if(!n)return e;let t=new AbortController,r=o=>{t.signal.aborted||t.abort(o)},i=()=>r(n.reason),s=()=>r(e.reason);return t.signal.addEventListener("abort",()=>{n.removeEventListener("abort",i),e.removeEventListener("abort",s)},{once:!0}),n.aborted?r(n.reason):e.aborted?r(e.reason):(n.addEventListener("abort",i,{once:!0}),e.addEventListener("abort",s,{once:!0})),t.signal}async function c(n,e={},t={}){let r=t.kind||"api",i=(p[r]||p.api).knob,s=t.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(t.timeoutMs))):f(r),o=e?.signal;if(o?.aborted)throw o.reason??new DOMException("This operation was aborted","AbortError");let a=AbortSignal.timeout(s),d=T(o,a);try{return await fetch(n,{...e,signal:d})}catch(y){throw a.aborted&&b(y)?new Error(`${t.what||"request"} TIMED OUT after ${s}ms against ${k(n)} (${i})`):y}}function A(){if(process.env.MCP_SENTRY_PATH)return process.env.MCP_SENTRY_PATH;let n=O(w(import.meta.url)),e=v(n,"..","bin","mcp-sentry.mjs");return E(e)?e:null}function l(n){return(n||process.env.SENTRY_URL||"https://sentry.io").trim().replace(/\/+$/,"")}function h(n){let e=n||process.env.SENTRY_ORG;if(!e)throw new Error('Sentry organization not resolved \u2014 reconnect Sentry, or set SENTRY_ORG (self-hosted; the default org slug is "sentry").');return e}async function S(n,e={}){let{token:t,organizationSlug:r,baseUrl:i}=await u("sentry"),s=`${l(i)}/api/0/organizations/${h(r)}${n}`,o={method:e.method||"GET",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"}};e.body!=null&&(o.body=typeof e.body=="string"?e.body:JSON.stringify(e.body));let a=await c(s,o,{kind:"api",what:`Sentry ${e.method||"GET"} ${n}`});if(!a.ok){let d=await a.text().catch(()=>"");throw new Error(`Sentry API ${a.status}: ${d.slice(0,300)}`)}return a.json()}async function L(){return S("/projects/?per_page=50")}async function N({query:n="is:unresolved",sort:e="date",project:t,limit:r=25}={}){let i=`/issues/?query=${encodeURIComponent(n)}&sort=${e}&per_page=${r}`;return t&&(i+=`&project=${encodeURIComponent(t)}`),S(i)}async function m(n){let e=String(n??"").trim();if(!e)throw new Error("resolveSentryIssueId: issueRef is required");if(/^\d+$/.test(e))return e;let{token:t,organizationSlug:r,baseUrl:i}=await u("sentry"),s=await c(`${l(i)}/api/0/organizations/${h(r)}/shortids/${encodeURIComponent(e)}/`,{headers:{Authorization:`Bearer ${t}`}},{kind:"api",what:"Sentry GET shortids"});if(!s.ok){let d=await s.text().catch(()=>"");throw new Error(`Sentry API ${s.status} resolving shortId "${e}": ${d.slice(0,200)}`)}let o=await s.json(),a=o.groupId||o.group&&o.group.id;if(!a)throw new Error(`Sentry shortId "${e}" did not resolve to a numeric issue id`);return String(a)}async function P(n){if(!n)throw new Error("sentryGetIssue: issueId is required");let e=await m(n),{token:t,baseUrl:r}=await u("sentry"),i=await c(`${l(r)}/api/0/issues/${e}/`,{headers:{Authorization:`Bearer ${t}`}},{kind:"api",what:`Sentry GET issue ${e}`});if(!i.ok){let s=await i.text().catch(()=>"");throw new Error(`Sentry API ${i.status}: ${s.slice(0,300)}`)}return i.json()}async function R(n,e={}){if(!n)throw new Error("sentryUpdateIssue: issueId is required");let t={};for(let a of["status","statusDetails","assignedTo","isBookmarked","hasSeen"])e[a]!==void 0&&(t[a]=e[a]);if(Object.keys(t).length===0)throw new Error("sentryUpdateIssue: nothing to update (pass status / statusDetails / assignedTo / isBookmarked / hasSeen)");let r=await m(n),{token:i,baseUrl:s}=await u("sentry"),o=await c(`${l(s)}/api/0/issues/${r}/`,{method:"PUT",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},body:JSON.stringify(t)},{kind:"api",what:`Sentry PUT issue ${r}`});if(!o.ok){let a=await o.text().catch(()=>"");throw o.status===403?new Error(`Sentry API 403 updating issue ${n}: ${a.slice(0,200)}. The connected Sentry integration likely lacks the \`event:write\` scope \u2014 reconnect Sentry with write access to let Zibby resolve/comment on issues.`):new Error(`Sentry API ${o.status} updating issue ${n}: ${a.slice(0,300)}`)}return o.json()}async function $(n,e){if(!n)throw new Error("sentryAddComment: issueId is required");if(!e||!String(e).trim())throw new Error("sentryAddComment: text is required");let t=await m(n),{token:r,baseUrl:i}=await u("sentry"),s=await c(`${l(i)}/api/0/issues/${t}/comments/`,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},body:JSON.stringify({text:String(e)})},{kind:"api",what:`Sentry POST issue ${t} comment`});if(!s.ok){let o=await s.text().catch(()=>"");throw s.status===403?new Error(`Sentry API 403 commenting on issue ${n}: ${o.slice(0,200)}. The connected Sentry integration likely lacks the \`event:write\` scope \u2014 reconnect Sentry with write access.`):new Error(`Sentry API ${s.status} commenting on issue ${n}: ${o.slice(0,300)}`)}return s.json()}var g={id:"sentry",callsBackend:!0,serverName:"sentry",allowedTools:["mcp__sentry__*"],requiresIntegration:_.SENTRY,description:"Sentry error tracking \u2014 projects, issues, events",envKeys:[],tools:[],promptFragment:`## Sentry
|
|
2
2
|
You have access to the user's Sentry. Use these tools:
|
|
3
3
|
- sentry_list_projects: List projects in the organization
|
|
4
4
|
- sentry_list_issues: List errors/issues (supports Sentry search query, project filter, sort)
|
|
5
5
|
- sentry_get_issue: Get detailed info about a specific issue (requires issueId)
|
|
6
6
|
- sentry_update_issue: Change an issue's status (resolved / resolvedInNextRelease / ignored / unresolved / muted), assignment, or bookmark (requires issueId; needs write scope)
|
|
7
|
-
- sentry_add_comment: Post a comment/note on an issue (requires issueId + text; needs write scope)`,resolve(){let n=
|
|
7
|
+
- sentry_add_comment: Post a comment/note on an issue (requires issueId + text; needs write scope)`,resolve(){let n=A();if(!n)return null;let e={};for(let t of["PROJECT_API_TOKEN","ZIBBY_USER_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","PROGRESS_API_URL","EXECUTION_ID","PROJECT_ID","STAGE","ZIBBY_SELF_HOST","SENTRY_URL","SENTRY_ORG","SENTRY_AUTH_TOKEN"])process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[n],env:e,alwaysLoad:!0}},async handleToolCall(n,e={}){try{switch(n){case"sentry_list_projects":{let t=await L();return JSON.stringify({projects:t.map(r=>({slug:r.slug,name:r.name,platform:r.platform}))})}case"sentry_list_issues":{let t=await N({query:e.query,sort:e.sort,project:e.project,limit:e.limit});return JSON.stringify({issues:t.map(r=>({id:r.id,title:r.title,culprit:r.culprit,count:r.count,firstSeen:r.firstSeen,lastSeen:r.lastSeen,level:r.level,status:r.status}))})}case"sentry_get_issue":{let t=await P(e.issueId);return JSON.stringify({id:t.id,title:t.title,culprit:t.culprit,metadata:t.metadata,count:t.count,userCount:t.userCount,firstSeen:t.firstSeen,lastSeen:t.lastSeen,level:t.level,status:t.status,project:{slug:t.project?.slug,name:t.project?.name}})}case"sentry_update_issue":{let t=await R(e.issueId,{status:e.status,statusDetails:e.statusDetails,assignedTo:e.assignedTo,isBookmarked:e.isBookmarked,hasSeen:e.hasSeen});return JSON.stringify({ok:!0,id:t.id??e.issueId,status:t.status,assignedTo:t.assignedTo,isBookmarked:t.isBookmarked})}case"sentry_add_comment":{let t=await $(e.issueId,e.text);return JSON.stringify({ok:!0,id:t.id,issueId:e.issueId})}default:return JSON.stringify({error:`Unknown tool: ${n}`})}}catch(t){return JSON.stringify({error:t.message})}},toolsForAssistant:[{name:"sentry_list_projects",description:"List Sentry projects",input_schema:{type:"object",properties:{}}},{name:"sentry_list_issues",description:"List Sentry issues (errors)",input_schema:{type:"object",properties:{project:{type:"string",description:"Project slug (optional)"},query:{type:"string",description:"Sentry search query (default: is:unresolved)"},sort:{type:"string",description:"Sort order: date, new, priority, freq, user (default: date)"},limit:{type:"number",description:"Max issues to return (default 25)"}}}},{name:"sentry_get_issue",description:"Get details of a specific Sentry issue",input_schema:{type:"object",properties:{issueId:{type:"string",description:"Sentry issue ID"}},required:["issueId"]}},{name:"sentry_update_issue",description:"Update a Sentry issue's status, assignment, or bookmark (needs event:write scope)",input_schema:{type:"object",properties:{issueId:{type:"string",description:"Sentry issue ID"},status:{type:"string",description:"resolved | resolvedInNextRelease | unresolved | ignored | muted"},statusDetails:{type:"object",description:'Optional status details, e.g. { "inRelease": "latest" }'},assignedTo:{type:"string",description:'Assignee actor id, e.g. "user:123" or "team:456" (optional)'},isBookmarked:{type:"boolean",description:"Bookmark/unbookmark the issue (optional)"},hasSeen:{type:"boolean",description:"Mark the issue seen/unseen (optional)"}},required:["issueId"]}},{name:"sentry_add_comment",description:"Post a comment/note on a Sentry issue (needs event:write scope)",input_schema:{type:"object",properties:{issueId:{type:"string",description:"Sentry issue ID"},text:{type:"string",description:"Comment body (markdown)"}},required:["issueId","text"]}}]};g.tools=g.toolsForAssistant;export{m as resolveSentryIssueId,$ as sentryAddComment,S as sentryFetch,P as sentryGetIssue,N as sentryListIssues,L as sentryListProjects,g as sentrySkill,R as sentryUpdateIssue};
|
package/dist/skill-installer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as O,readFileSync as w}from"fs";import{homedir as E}from"os";import{join as M}from"path";import{spawn as L}from"child_process";var f={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 I(t,e,n=process.env){let i=Number(n?.[t]);return Number.isFinite(i)&&i>0?Math.min(6e5,Math.max(1e3,Math.floor(i))):e}function _(t="api",e=process.env){let n=f[t]||f.api;return I(n.knob,n.fallback,e)}function S(t){return t?.name==="TimeoutError"||t?.name==="AbortError"}function v(t){try{return new URL(String(t?.url??t)).host||"unknown host"}catch{return"unknown host"}}function T(t,e){if(!t)return e;let n=new AbortController,i=o=>{n.signal.aborted||n.abort(o)},a=()=>i(t.reason),s=()=>i(e.reason);return n.signal.addEventListener("abort",()=>{t.removeEventListener("abort",a),e.removeEventListener("abort",s)},{once:!0}),t.aborted?i(t.reason):e.aborted?i(e.reason):(t.addEventListener("abort",a,{once:!0}),e.addEventListener("abort",s,{once:!0})),n.signal}async function g(t,e={},n={}){let i=n.kind||"api",a=(f[i]||f.api).knob,s=n.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(n.timeoutMs))):_(i),o=e?.signal;if(o?.aborted)throw o.reason??new DOMException("This operation was aborted","AbortError");let r=AbortSignal.timeout(s),p=T(o,r);try{return await fetch(t,{...e,signal:p})}catch(l){throw r.aborted&&S(l)?new Error(`${n.what||"request"} TIMED OUT after ${s}ms against ${v(t)} (${a})`):l}}var c={jira:{description:"Jira issue search, details, comments, transitions",integrationProvider:"jira",envKeys:[],setupInstructions:`To connect Jira:
|
|
2
2
|
1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
|
|
3
3
|
2. Click "Connect Jira" and authorize via Atlassian OAuth
|
|
4
4
|
3. After OAuth completes, ask me to install Jira again`},github:{description:"GitHub issues, PRs, repository management",integrationProvider:"github",envKeys:[],setupInstructions:`To connect GitHub:
|
|
@@ -10,5 +10,5 @@ import{existsSync as m,readFileSync as b}from"fs";import{homedir as v}from"os";i
|
|
|
10
10
|
3. After OAuth completes, ask me to install Slack again`},sentry:{description:"Sentry error tracking \u2014 projects, issues, events",integrationProvider:"sentry",envKeys:[],setupInstructions:`To connect Sentry:
|
|
11
11
|
1. Go to Settings \u2192 Integrations (https://studio.zibby.dev/integrations)
|
|
12
12
|
2. Click "Connect Sentry" and authorize
|
|
13
|
-
3. After OAuth completes, ask me to install Sentry again`},runner:{description:"Run zibby test workflows from chat (parallel supported)",envKeys:[],setupInstructions:"Ready to use. Runs zibby test workflows as background processes \u2014 each with its own browser and session."},browser:{description:"Playwright browser automation (navigate, click, fill, screenshot)",envKeys:[],setupInstructions:"Ready to use. Starts a Playwright browser for web automation."},memory:{description:"Test memory database (Dolt) \u2014 history, selectors, insights",envKeys:[],setupInstructions:"Ready to use. Requires Dolt (https://docs.dolthub.com/introduction/installation) and a memory DB via `zibby init --mem`."},"chat-memory":{description:"Persistent chat memory \u2014 remembers facts, decisions, and task history across sessions (Dolt-backed)",envKeys:[],setupInstructions:'Ready to use. Requires Dolt installed. Tables auto-create on first use. Install with: "add chat memory" or "install chat-memory".'},git:{description:"Clone and explore git repositories locally for codebase analysis",envKeys:[],setupInstructions:"Ready to use. Clone repos with git_checkout, explore with git_explore. Auto-authenticates with GitHub/GitLab tokens."}};function
|
|
14
|
-
`)}function
|
|
13
|
+
3. After OAuth completes, ask me to install Sentry again`},runner:{description:"Run zibby test workflows from chat (parallel supported)",envKeys:[],setupInstructions:"Ready to use. Runs zibby test workflows as background processes \u2014 each with its own browser and session."},browser:{description:"Playwright browser automation (navigate, click, fill, screenshot)",envKeys:[],setupInstructions:"Ready to use. Starts a Playwright browser for web automation."},memory:{description:"Test memory database (Dolt) \u2014 history, selectors, insights",envKeys:[],setupInstructions:"Ready to use. Requires Dolt (https://docs.dolthub.com/introduction/installation) and a memory DB via `zibby init --mem`."},"chat-memory":{description:"Persistent chat memory \u2014 remembers facts, decisions, and task history across sessions (Dolt-backed)",envKeys:[],setupInstructions:'Ready to use. Requires Dolt installed. Tables auto-create on first use. Install with: "add chat memory" or "install chat-memory".'},git:{description:"Clone and explore git repositories locally for codebase analysis",envKeys:[],setupInstructions:"Ready to use. Clone repos with git_checkout, explore with git_explore. Auto-authenticates with GitHub/GitLab tokens."}};function A(){let t=["## Available Skills"];for(let[e,n]of Object.entries(c)){let i=n.integrationProvider?`integration: ${n.integrationProvider}`:"ready";t.push(`- ${e}: ${n.description} [${i}]`)}return t.push(""),t.push("Use the install_skill / uninstall_skill / list_available_skills tools to manage skills."),t.push(`Zibby third party Integration settings page: ${h()}`),t.push(""),t.push("## Tool-First Policy (mandatory)"),t.push("CRITICAL RULES \u2014 follow these strictly:"),t.push("1. When user asks to do something and a matching skill is available but not installed, IMMEDIATELY call install_skill. Never ask for credentials or confirmation first."),t.push(`2. If install_skill succeeds, the skill's tools are now available. Use them RIGHT AWAY in the same turn \u2014 don't just say "it's connected", actually call the tools.`),t.push("3. If install_skill reports needsIntegration, tell the user to connect via the integration URL and try again after."),t.push("4. When the relevant skill is already installed, use its tools directly \u2014 don't ask for IDs or keys. Each skill's own instructions explain the workflow."),t.push("5. If a task needs multiple skills (e.g. data from one + execution from another), install all of them, then follow each skill's workflow instructions."),t.join(`
|
|
14
|
+
`)}function R(){if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let t=M(E(),".zibby","config.json");return O(t)&&JSON.parse(w(t,"utf-8")).sessionToken||null}catch{return null}}function U(){return(process.env.ZIBBY_API_URL||process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app").replace(/\/$/,"")}function h(){return`${(process.env.ZIBBY_FRONTEND_URL||process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.dev").replace(/\/$/,"")}/integrations`}function $(t){try{let e=process.platform;return L(e==="darwin"?"open":e==="win32"?"cmd":"xdg-open",e==="win32"?["/c","start","",t]:[t],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}async function P(){let t=R();if(!t)return{checked:!1,statuses:null,reason:"no-session-token"};try{let e=await g(`${U()}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${t}`}},{kind:"api",what:"Zibby GET /integrations/status"});return e.ok?{checked:!0,statuses:await e.json()||{},reason:null}:{checked:!1,statuses:null,reason:`status-${e.status}`}}catch{return{checked:!1,statuses:null,reason:"network-error"}}}function m(t,e){if(!e||!t)return{connected:null};let n=t[e];return!n||typeof n.connected!="boolean"?{connected:null,details:n||null}:{connected:n.connected,details:n}}var C={id:"skill-installer",description:"Live skill installation for chat sessions",envKeys:[],catalog:c,promptFragment:A,tools:[{name:"install_skill",description:"Install a skill into the current chat session so its tools become available",input_schema:{type:"object",properties:{skillId:{type:"string",description:'Skill identifier to install (e.g. "jira", "github", "browser", "memory")'}},required:["skillId"]}},{name:"uninstall_skill",description:"Remove a skill from the current chat session",input_schema:{type:"object",properties:{skillId:{type:"string",description:"Skill identifier to remove"}},required:["skillId"]}},{name:"list_available_skills",description:"List all skills that can be installed, with their env-var readiness status",input_schema:{type:"object",properties:{}}}],async handleToolCall(t,e,n){let{activeSkills:i}=n,a=await P();if(t==="list_available_skills"){let s=Object.entries(c).map(([o,r])=>{let p=i.includes(o),l=m(a.statuses,r.integrationProvider);return{id:o,description:r.description,installed:p,integrationProvider:r.integrationProvider||void 0,integrationConnected:l.connected,setupInstructions:l.connected===!1?r.setupInstructions:void 0}});return JSON.stringify({skills:s})}if(t==="install_skill"){let{skillId:s}=e;if(!s)return JSON.stringify({ok:!1,error:"skillId is required"});if(i.includes(s)){let u=c[s],{getSkill:d}=await import("@zibby/agent-workflow"),b=(d(s)?.tools||[]).map(y=>y.name);return JSON.stringify({ok:!0,alreadyInstalled:!0,skillId:s,description:u?.description,availableTools:b,integrationUrl:u?.integrationProvider?h():void 0,hint:`${s} is already active. Tools available: ${b.join(", ")}. Use them directly.`})}if(!c[s])return JSON.stringify({ok:!1,error:`Unknown skill "${s}". Available: ${Object.keys(c).join(", ")}`});let o=c[s];if(o.integrationProvider){let u=m(a.statuses,o.integrationProvider),d=h();if(a.checked&&u.connected===!1){let k=$(d);return JSON.stringify({ok:!1,error:`${o.integrationProvider} is not connected for this Zibby account yet`,needsIntegration:!0,integrationUrl:d,openedBrowser:k,setupInstructions:`Please connect ${o.integrationProvider} first at ${d}. After you finish OAuth, ask me to install ${s} again.`})}}i.push(s);let{getSkill:r}=await import("@zibby/agent-workflow"),l=(r(s)?.tools||[]).map(u=>u.name);return JSON.stringify({ok:!0,installed:s,description:o.description,availableTools:l,hint:`${s} is now active. You now have these tools: ${l.join(", ")}. Use them immediately to help the user \u2014 don't just confirm installation.`})}if(t==="uninstall_skill"){let{skillId:s}=e;if(!s)return JSON.stringify({ok:!1,error:"skillId is required"});if(s==="skill-installer")return JSON.stringify({ok:!1,error:"Cannot uninstall the skill installer"});let o=i.indexOf(s);return o===-1?JSON.stringify({ok:!1,error:`${s} is not installed`}):(i.splice(o,1),JSON.stringify({ok:!0,uninstalled:s}))}return JSON.stringify({error:`Unknown tool: ${t}`})},resolve(){return null}};export{C as skillInstallerSkill};
|
package/dist/slack.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as I}from"fs";import{fileURLToPath as O}from"url";import{dirname as T,resolve as N}from"path";import{resolveIntegrationToken as E}from"@zibby/core/backend-client.js";var h=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"}),v=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"}});var _={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 k(r,t,e=process.env){let n=Number(e?.[r]);return Number.isFinite(n)&&n>0?Math.min(6e5,Math.max(1e3,Math.floor(n))):t}function f(r="api",t=process.env){let e=_[r]||_.api;return k(e.knob,e.fallback,t)}function b(r){return r?.name==="TimeoutError"||r?.name==="AbortError"}function y(r){try{return new URL(String(r?.url??r)).host||"unknown host"}catch{return"unknown host"}}function S(r,t){if(!r)return t;let e=new AbortController,n=l=>{e.signal.aborted||e.abort(l)},c=()=>n(r.reason),a=()=>n(t.reason);return e.signal.addEventListener("abort",()=>{r.removeEventListener("abort",c),t.removeEventListener("abort",a)},{once:!0}),r.aborted?n(r.reason):t.aborted?n(t.reason):(r.addEventListener("abort",c,{once:!0}),t.addEventListener("abort",a,{once:!0})),e.signal}async function g(r,t={},e={}){let n=e.kind||"api",c=(_[n]||_.api).knob,a=e.timeoutMs?Math.min(6e5,Math.max(1e3,Math.floor(e.timeoutMs))):f(n),l=t?.signal;if(l?.aborted)throw l.reason??new DOMException("This operation was aborted","AbortError");let p=AbortSignal.timeout(a),i=S(l,p);try{return await fetch(r,{...t,signal:i})}catch(s){throw p.aborted&&b(s)?new Error(`${e.what||"request"} TIMED OUT after ${a}ms against ${y(r)} (${c})`):s}}function L(){if(process.env.MCP_SLACK_PATH)return process.env.MCP_SLACK_PATH;let r=T(O(import.meta.url)),t=N(r,"..","bin","mcp-slack.mjs");return I(t)?t:null}async function o(r,t={}){let{token:e}=await E("slack"),n=["conversations.list","users.list","users.profile.get","users.lookupByEmail","usergroups.list","usergroups.users.list","conversations.history","conversations.replies"].includes(r),c=`https://slack.com/api/${r}`,a={Authorization:`Bearer ${e}`},l;if(n){let s=new URLSearchParams(t).toString();s&&(c+=`?${s}`)}else a["Content-Type"]="application/json; charset=utf-8",l=JSON.stringify(t);let i=await(await g(c,{method:n?"GET":"POST",headers:a,body:l},{kind:"api",what:`Slack ${r}`})).json();if(!i.ok)throw new Error(`Slack API error: ${i.error}`);return i}var U={id:"slack",callsBackend:!0,serverName:"slack",allowedTools:["mcp__slack__*"],requiresIntegration:h.SLACK,envKeys:["SLACK_BOT_TOKEN","SLACK_TEAM_ID"],description:"Slack MCP Server",promptFragment:`## Slack
|
|
2
2
|
You have access to the user's Slack workspace. Use these tools:
|
|
3
3
|
- slack_list_channels, slack_post_message, slack_reply_to_thread
|
|
4
4
|
- slack_add_reaction, slack_get_channel_history, slack_get_thread_replies
|
|
5
5
|
- slack_get_users, slack_get_user_profile
|
|
6
6
|
- slack_lookup_user_by_email (precise email\u2192user_id, prefer this over scanning slack_get_users)
|
|
7
|
-
- slack_list_usergroups, slack_get_usergroup_members (workspace-defined teams like @oncall, @platform)`,resolve(){let
|
|
7
|
+
- slack_list_usergroups, slack_get_usergroup_members (workspace-defined teams like @oncall, @platform)`,resolve(){let r=L();if(!r)return null;let t={};for(let e of["PROJECT_API_TOKEN","ZIBBY_USER_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","PROGRESS_API_URL","EXECUTION_ID","PROJECT_ID","STAGE"])process.env[e]&&(t[e]=process.env[e]);for(let e of this.envKeys)process.env[e]&&(t[e]=process.env[e]);return{type:"stdio",command:"node",args:[r],env:t,alwaysLoad:!0}},async handleToolCall(r,t){try{switch(r){case"slack_list_channels":{let e=await o("conversations.list",{types:"public_channel",limit:100});return JSON.stringify({channels:(e.channels||[]).map(n=>({id:n.id,name:n.name,topic:n.topic?.value}))})}case"slack_post_message":{if(!t.channel||!t.text)return JSON.stringify({error:"channel and text are required"});let e=await o("chat.postMessage",{channel:t.channel,text:t.text,...t.blocks?{blocks:t.blocks}:{}});return JSON.stringify({ok:!0,ts:e.ts,channel:e.channel})}case"slack_reply_to_thread":{if(!t.channel||!t.thread_ts||!t.text)return JSON.stringify({error:"channel, thread_ts, and text are required"});let e=await o("chat.postMessage",{channel:t.channel,thread_ts:t.thread_ts,text:t.text});return JSON.stringify({ok:!0,ts:e.ts})}case"slack_add_reaction":return!t.channel||!t.timestamp||!t.reaction?JSON.stringify({error:"channel, timestamp, and reaction are required"}):(await o("reactions.add",{channel:t.channel,timestamp:t.timestamp,name:t.reaction}),JSON.stringify({ok:!0}));case"slack_get_channel_history":{if(!t.channel)return JSON.stringify({error:"channel is required"});let e=await o("conversations.history",{channel:t.channel,limit:t.limit||20});return JSON.stringify({messages:(e.messages||[]).map(n=>({user:n.user,text:n.text,ts:n.ts}))})}case"slack_get_thread_replies":{if(!t.channel||!t.thread_ts)return JSON.stringify({error:"channel and thread_ts are required"});let e=await o("conversations.replies",{channel:t.channel,ts:t.thread_ts});return JSON.stringify({messages:(e.messages||[]).map(n=>({user:n.user,text:n.text,ts:n.ts}))})}case"slack_get_users":{let e=await o("users.list",{limit:100});return JSON.stringify({users:(e.members||[]).filter(n=>!n.is_bot&&!n.deleted).map(n=>({id:n.id,name:n.real_name||n.name}))})}case"slack_get_user_profile":{if(!t.user_id)return JSON.stringify({error:"user_id is required"});let e=await o("users.profile.get",{user:t.user_id});return JSON.stringify({profile:e.profile})}case"slack_lookup_user_by_email":{if(!t.email)return JSON.stringify({error:"email is required"});try{let e=await o("users.lookupByEmail",{email:t.email});return JSON.stringify({ok:!0,user:{id:e.user?.id,name:e.user?.real_name||e.user?.name,email:e.user?.profile?.email||t.email}})}catch(e){if(/users_not_found/.test(e.message))return JSON.stringify({ok:!1,reason:"users_not_found"});throw e}}case"slack_list_usergroups":{let e=await o("usergroups.list",{});return JSON.stringify({usergroups:(e.usergroups||[]).map(n=>({id:n.id,handle:n.handle,name:n.name,description:n.description||"",user_count:Number(n.user_count||0)}))})}case"slack_get_usergroup_members":{if(!t.usergroup)return JSON.stringify({error:"usergroup id is required"});let e=await o("usergroups.users.list",{usergroup:t.usergroup});return JSON.stringify({users:e.users||[]})}case"slack_search_users":{if(!t.query||typeof t.query!="string")return JSON.stringify({error:"query is required"});let e=t.query.trim().toLowerCase();if(!e)return JSON.stringify({ok:!0,matches:[]});let n=Math.max(1,Math.min(Number(t.limit)||5,25)),c=[],a,l=5;for(let i=0;i<l;i+=1){let s={limit:200};a&&(s.cursor=a);let u=await o("users.list",s);for(let d of u.members||[])d.deleted||d.is_bot||c.push(d);if(a=u.response_metadata?.next_cursor,!a)break}let p=[];for(let i of c){let s=(i.real_name||"").toLowerCase(),u=(i.profile?.display_name||"").toLowerCase(),d=(i.name||"").toLowerCase(),m=0;s.includes(e)&&(m+=100-Math.abs(s.length-e.length)),u.includes(e)&&(m+=60-Math.abs(u.length-e.length)),d.includes(e)&&(m+=30-Math.abs(d.length-e.length)),(s===e||u===e)&&(m+=200),m>0&&p.push({id:i.id,name:i.real_name||i.profile?.display_name||i.name,email:i.profile?.email||void 0,_score:m})}return p.sort((i,s)=>s._score-i._score),JSON.stringify({ok:!0,matches:p.slice(0,n).map(({_score:i,...s})=>s),scanned:c.length})}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(e){return JSON.stringify({error:e.message})}},tools:[{name:"slack_list_channels",description:"List public channels in the workspace",input_schema:{type:"object",properties:{}}},{name:"slack_post_message",description:"Post a message to a Slack channel or DM. Pass `blocks` (Block Kit) for a rich card; `text` is the required notification fallback.",input_schema:{type:"object",properties:{channel:{type:"string",description:"Channel ID or name"},text:{type:"string",description:"Notification/fallback text (required)"},blocks:{type:"array",description:"Block Kit blocks for rich formatting (optional). Each block is a Slack Block Kit object (header/section/divider/context). section blocks may carry a button accessory with a url."}},required:["channel","text"]}},{name:"slack_reply_to_thread",description:"Reply to a specific message thread",input_schema:{type:"object",properties:{channel:{type:"string",description:"Channel ID"},thread_ts:{type:"string",description:"Thread timestamp"},text:{type:"string",description:"Reply text"}},required:["channel","thread_ts","text"]}},{name:"slack_add_reaction",description:"Add an emoji reaction to a message",input_schema:{type:"object",properties:{channel:{type:"string",description:"Channel ID"},timestamp:{type:"string",description:"Message timestamp"},reaction:{type:"string",description:"Emoji name without colons"}},required:["channel","timestamp","reaction"]}},{name:"slack_get_channel_history",description:"Get recent messages from a channel",input_schema:{type:"object",properties:{channel:{type:"string",description:"Channel ID"},limit:{type:"number",description:"Number of messages"}},required:["channel"]}},{name:"slack_get_thread_replies",description:"Get all replies in a message thread",input_schema:{type:"object",properties:{channel:{type:"string",description:"Channel ID"},thread_ts:{type:"string",description:"Thread timestamp"}},required:["channel","thread_ts"]}},{name:"slack_get_users",description:"List workspace users with basic profiles",input_schema:{type:"object",properties:{}}},{name:"slack_get_user_profile",description:"Get detailed profile for a specific user",input_schema:{type:"object",properties:{user_id:{type:"string",description:"Slack user ID"}},required:["user_id"]}},{name:"slack_lookup_user_by_email",description:"Find a Slack user by email. Returns { ok:true, user:{id,name,email} } on hit, { ok:false } when no user has that email. Prefer this over slack_get_users for email-based routing \u2014 single API call, exact match.",input_schema:{type:"object",properties:{email:{type:"string",description:"Email address to look up"}},required:["email"]}},{name:"slack_list_usergroups",description:"List workspace-defined user groups (e.g. @oncall, @platform). Each item has { id, handle, name, description, user_count }. Use the id with slack_get_usergroup_members to expand the membership.",input_schema:{type:"object",properties:{}}},{name:"slack_get_usergroup_members",description:"List user IDs that belong to a Slack usergroup. Pair with slack_post_message to DM each member, or use the group id directly in a channel message as <!subteam^ID> to @-mention.",input_schema:{type:"object",properties:{usergroup:{type:"string",description:"Usergroup id, e.g. S012ABC"}},required:["usergroup"]}},{name:"slack_search_users",description:'Fuzzy-search workspace users by display name or real name. Use when the user said something like "send to Sam" without an email. Returns up to `limit` ranked matches { id, name, email }. Slack has no native name-search API \u2014 this scans paginated users.list + does substring scoring (real_name > display_name > name). For large workspaces consider higher limit + ask the user to confirm if multiple hit.',input_schema:{type:"object",properties:{query:{type:"string",description:"Substring to match against names (case-insensitive)"},limit:{type:"number",description:"Max matches to return (default 5, max 25)"}},required:["query"]}}]};export{U as slackSkill};
|