@meetopenbot/github 0.0.1 → 0.1.1

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/src/index.ts DELETED
@@ -1,418 +0,0 @@
1
- import {
2
- definePlugin,
3
- shouldHandleInvoke,
4
- agentOutput,
5
- uiWidget,
6
- type ToolActionEvent,
7
- } from '@meetopenbot/plugin-sdk';
8
- import { Octokit } from '@octokit/rest';
9
- import { generateText, stepCountIs, tool } from 'ai';
10
- import { createOpenAI } from '@ai-sdk/openai';
11
- import { z } from 'zod';
12
-
13
- const listReposSchema = z.object({
14
- limit: z.number().optional().describe('Maximum number of repositories to return'),
15
- visibility: z.enum(['all', 'public', 'private']).optional().describe('Filter by repository visibility'),
16
- sort: z.enum(['created', 'updated', 'pushed', 'full_name']).optional().describe('How to sort the repositories'),
17
- });
18
-
19
- const getRepoSchema = z.object({
20
- owner: z.string().describe('The owner of the repository (user or organization)'),
21
- repo: z.string().describe('The name of the repository'),
22
- });
23
-
24
- const createRepoSchema = z.object({
25
- name: z.string().describe('The name of the repository'),
26
- org: z.string().optional().describe('The organization to create the repository in. If not provided, it will be created for the authenticated user.'),
27
- description: z.string().optional().describe('A short description of the repository'),
28
- private: z.boolean().optional().describe('Whether the repository is private'),
29
- autoInit: z.boolean().optional().describe('Whether to create an initial commit with an empty README'),
30
- });
31
-
32
- export default definePlugin({
33
- id: 'github',
34
- name: 'GitHub',
35
- description: 'Manage your GitHub repositories',
36
- configSchema: {
37
- type: 'object',
38
- properties: {
39
- githubToken: {
40
- type: 'string',
41
- description: 'GitHub Personal Access Token',
42
- format: 'password',
43
- },
44
- openaiApiKey: {
45
- type: 'string',
46
- description: 'OpenAI API Key (optional if provided via environment)',
47
- format: 'password',
48
- },
49
- },
50
- required: ['githubToken'],
51
- },
52
- toolDefinitions: {
53
- list_repos: {
54
- description: 'List repositories for the authenticated user',
55
- inputSchema: {
56
- type: 'object',
57
- properties: {
58
- limit: { type: 'number', description: 'Maximum number of repositories to return' },
59
- visibility: { type: 'string', enum: ['all', 'public', 'private'], description: 'Filter by repository visibility' },
60
- sort: { type: 'string', enum: ['created', 'updated', 'pushed', 'full_name'], description: 'How to sort the repositories' },
61
- },
62
- },
63
- },
64
- get_repo: {
65
- description: 'Get details of a specific repository',
66
- inputSchema: {
67
- type: 'object',
68
- properties: {
69
- owner: { type: 'string', description: 'The owner of the repository' },
70
- repo: { type: 'string', description: 'The name of the repository' },
71
- },
72
- required: ['owner', 'repo'],
73
- },
74
- },
75
- create_repo: {
76
- description: 'Create a new repository',
77
- inputSchema: {
78
- type: 'object',
79
- properties: {
80
- name: { type: 'string', description: 'The name of the repository' },
81
- org: { type: 'string', description: 'The organization to create the repository in' },
82
- description: { type: 'string', description: 'A short description of the repository' },
83
- private: { type: 'boolean', description: 'Whether the repository is private' },
84
- autoInit: { type: 'boolean', description: 'Whether to create an initial commit with an empty README' },
85
- },
86
- required: ['name'],
87
- },
88
- },
89
- },
90
- factory: (context) => {
91
- const getCredentials = async () => {
92
- const config = context.config as { githubToken: string; openaiApiKey?: string };
93
- const env = process.env;
94
- const variables = await context.storage.getVariables();
95
-
96
- const getVal = (key: string, envKey: string) => {
97
- if (config[key as keyof typeof config]) return config[key as keyof typeof config] as string;
98
- if (env[envKey]) return env[envKey] as string;
99
- const v = variables[envKey];
100
- return typeof v === 'string' ? v : v?.value;
101
- };
102
-
103
- return {
104
- githubToken: config.githubToken,
105
- openaiApiKey: getVal('openaiApiKey', 'OPENAI_API_KEY'),
106
- };
107
- };
108
-
109
- const getOctokit = (githubToken: string) => {
110
- return new Octokit({
111
- auth: githubToken,
112
- headers: {
113
- 'X-GitHub-Api-Version': '2022-11-28',
114
- },
115
- });
116
- };
117
-
118
- return (builder) => {
119
- // Handle agent:invoke for natural language queries
120
- builder.on('agent:invoke', async function* (event) {
121
- if (!shouldHandleInvoke(event, context.agentId)) return;
122
-
123
- const userMessage = event.data?.content || '';
124
- const threadId = event.meta?.threadId;
125
-
126
- if (!userMessage) return;
127
-
128
- const { githubToken, openaiApiKey } = await getCredentials();
129
-
130
- if (!openaiApiKey) {
131
- yield agentOutput({
132
- agentId: context.agentId,
133
- content: 'I need an OpenAI API key to help you manage GitHub. Please provide it below:',
134
- threadId,
135
- });
136
-
137
- yield uiWidget({
138
- agentId: context.agentId,
139
- threadId,
140
- widget: {
141
- kind: 'form',
142
- widgetId: 'github-config-form',
143
- title: 'OpenAI Configuration',
144
- description: 'Enter your OpenAI API key to get started.',
145
- fields: [
146
- {
147
- id: 'openaiApiKey',
148
- label: 'OpenAI API Key',
149
- type: 'text',
150
- placeholder: 'sk-...',
151
- required: true,
152
- },
153
- ],
154
- submitLabel: 'Save Configuration',
155
- },
156
- });
157
- return;
158
- }
159
-
160
- const octokit = getOctokit(githubToken);
161
- const openai = createOpenAI({ apiKey: openaiApiKey });
162
-
163
- try {
164
- const { text, steps } = await generateText({
165
- model: openai('gpt-4o'),
166
- stopWhen: stepCountIs(5),
167
- system: `You are a GitHub management assistant. Help users manage their repositories.
168
- - Use list_repos to see the authenticated user's repositories.
169
- - Use get_repo to get details about a repository.
170
- - Use create_repo to create a new repository.
171
- When a tool requires an owner and repo, parse them from the "owner/repo" format the user provides.
172
- If a tool returns an error, explain it to the user or try an alternative approach if appropriate.
173
- Be concise and helpful.`,
174
- prompt: userMessage,
175
- tools: {
176
- list_repos: tool({
177
- description: 'List repositories for the authenticated user',
178
- inputSchema: listReposSchema,
179
- execute: async ({ limit, visibility, sort }: z.infer<typeof listReposSchema>) => {
180
- try {
181
- const result = await octokit.repos.listForAuthenticatedUser({
182
- per_page: limit || 20,
183
- visibility: visibility || 'all',
184
- sort: sort || 'updated',
185
- });
186
- return result.data;
187
- } catch (error: any) {
188
- return { error: error.message, status: error.status };
189
- }
190
- },
191
- }),
192
- get_repo: tool({
193
- description: 'Get details of a specific repository',
194
- inputSchema: getRepoSchema,
195
- execute: async ({ owner, repo }: z.infer<typeof getRepoSchema>) => {
196
- try {
197
- const result = await octokit.repos.get({ owner, repo });
198
- return result.data;
199
- } catch (error: any) {
200
- return { error: error.message, status: error.status };
201
- }
202
- },
203
- }),
204
- create_repo: tool({
205
- description: 'Create a new repository',
206
- inputSchema: createRepoSchema,
207
- execute: async ({ name, org, description, private: isPrivate, autoInit }: z.infer<typeof createRepoSchema>) => {
208
- try {
209
- const params = {
210
- name,
211
- description,
212
- private: isPrivate,
213
- auto_init: autoInit,
214
- };
215
- const result = org
216
- ? await octokit.repos.createInOrg({ ...params, org })
217
- : await octokit.repos.createForAuthenticatedUser(params);
218
- return result.data;
219
- } catch (error: any) {
220
- return {
221
- error: error.message,
222
- status: error.status,
223
- details: error.response?.data,
224
- };
225
- }
226
- },
227
- }),
228
- },
229
- });
230
-
231
- if (text.trim()) {
232
- yield agentOutput({
233
- agentId: context.agentId,
234
- content: text,
235
- threadId,
236
- });
237
- }
238
-
239
- for (const step of steps) {
240
- for (const toolResult of step.toolResults) {
241
- if (toolResult.toolName === 'list_repos') {
242
- const repos = toolResult.output as any[];
243
- yield uiWidget({
244
- agentId: context.agentId,
245
- threadId,
246
- widget: {
247
- kind: 'list',
248
- title: 'GitHub Repositories',
249
- items: (repos || []).map((r: any) => ({
250
- id: String(r.id),
251
- label: r.full_name,
252
- description: r.description || (r.private ? 'Private' : 'Public'),
253
- status: 'done',
254
- })),
255
- },
256
- });
257
- }
258
- }
259
- }
260
- } catch (error: any) {
261
- yield agentOutput({
262
- agentId: context.agentId,
263
- content: `I encountered an error: ${error.message}`,
264
- threadId,
265
- });
266
- }
267
- });
268
-
269
- builder.on('client:ui:widget:response', async function* (event) {
270
- if (event.data?.widgetId !== 'github-config-form') return;
271
-
272
- const { openaiApiKey } = event.data.values || {};
273
- if (openaiApiKey) {
274
- await context.storage.createVariable({
275
- key: 'OPENAI_API_KEY',
276
- value: openaiApiKey as string,
277
- secret: true,
278
- });
279
-
280
- yield agentOutput({
281
- agentId: context.agentId,
282
- content: "OpenAI API key saved! I'm now ready to help you with GitHub.",
283
- threadId: event.meta?.threadId,
284
- });
285
- }
286
- });
287
-
288
- // Handle tool calls
289
- builder.on('action:list_repos', async function* (event: ToolActionEvent) {
290
- const { githubToken } = await getCredentials();
291
- const octokit = getOctokit(githubToken);
292
- const { limit, visibility, sort } = (event.data || {}) as {
293
- limit?: number;
294
- visibility?: 'all' | 'public' | 'private';
295
- sort?: 'created' | 'updated' | 'pushed' | 'full_name';
296
- };
297
-
298
- try {
299
- const result = await octokit.repos.listForAuthenticatedUser({
300
- per_page: limit || 20,
301
- visibility: visibility || 'all',
302
- sort: sort || 'updated',
303
- });
304
-
305
- yield uiWidget({
306
- agentId: context.agentId,
307
- threadId: event.meta?.threadId,
308
- widget: {
309
- kind: 'list',
310
- title: 'GitHub Repositories',
311
- items: result.data.map((r: any) => ({
312
- id: String(r.id),
313
- label: r.full_name,
314
- description: r.description || (r.private ? 'Private' : 'Public'),
315
- status: 'done',
316
- })),
317
- },
318
- });
319
-
320
- yield {
321
- type: 'action:list_repos:result',
322
- data: {
323
- ...result.data,
324
- output: `Successfully listed ${result.data.length} repositories.`,
325
- },
326
- meta: event.meta,
327
- };
328
- } catch (error: any) {
329
- yield {
330
- type: 'action:list_repos:result',
331
- data: {
332
- error: error.message,
333
- status: error.status,
334
- details: error.response?.data,
335
- output: `Failed to list repositories: ${error.message}`,
336
- },
337
- meta: event.meta,
338
- };
339
- }
340
- });
341
-
342
- builder.on('action:get_repo', async function* (event: ToolActionEvent) {
343
- const { githubToken } = await getCredentials();
344
- const octokit = getOctokit(githubToken);
345
- const { owner, repo } = (event.data || {}) as { owner: string; repo: string };
346
-
347
- try {
348
- const result = await octokit.repos.get({ owner, repo });
349
- yield {
350
- type: 'action:get_repo:result',
351
- data: {
352
- ...result.data,
353
- output: `Successfully retrieved details for ${owner}/${repo}.`,
354
- },
355
- meta: event.meta,
356
- };
357
- } catch (error: any) {
358
- yield {
359
- type: 'action:get_repo:result',
360
- data: {
361
- error: error.message,
362
- status: error.status,
363
- details: error.response?.data,
364
- output: `Failed to get repository ${owner}/${repo}: ${error.message}`,
365
- },
366
- meta: event.meta,
367
- };
368
- }
369
- });
370
-
371
- builder.on('action:create_repo', async function* (event: ToolActionEvent) {
372
- console.log('action:create_repo', event);
373
-
374
- const { githubToken } = await getCredentials();
375
- const octokit = getOctokit(githubToken);
376
- const { name, org, description, private: isPrivate, autoInit } = (event.data || {}) as {
377
- name: string;
378
- org?: string;
379
- description?: string;
380
- private?: boolean;
381
- autoInit?: boolean;
382
- };
383
-
384
- try {
385
- const params = {
386
- name,
387
- description,
388
- private: isPrivate,
389
- auto_init: autoInit,
390
- };
391
- const result = org
392
- ? await octokit.repos.createInOrg({ ...params, org })
393
- : await octokit.repos.createForAuthenticatedUser(params);
394
-
395
- yield {
396
- type: 'action:create_repo:result',
397
- data: {
398
- ...result.data,
399
- output: `Successfully created repository ${result.data.full_name}.`,
400
- },
401
- meta: event.meta,
402
- };
403
- } catch (error: any) {
404
- yield {
405
- type: 'action:create_repo:result',
406
- data: {
407
- error: error.message,
408
- status: error.status,
409
- details: error.response?.data,
410
- output: `Failed to create repository ${name}: ${error.message}`,
411
- },
412
- meta: event.meta,
413
- };
414
- }
415
- });
416
- };
417
- },
418
- });
package/tsconfig.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "Node16",
5
- "moduleResolution": "Node16",
6
- "esModuleInterop": true,
7
- "forceConsistentCasingInFileNames": true,
8
- "strict": true,
9
- "skipLibCheck": true,
10
- "outDir": "dist",
11
- "rootDir": "src",
12
- "types": ["node"]
13
- },
14
- "include": ["src/**/*"]
15
- }