@loopstack/github-oauth-example 0.3.1 → 0.4.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/README.md +3 -4
- package/dist/tools/authenticate-github-task.tool.d.ts +13 -5
- package/dist/tools/authenticate-github-task.tool.d.ts.map +1 -1
- package/dist/tools/authenticate-github-task.tool.js +17 -17
- package/dist/tools/authenticate-github-task.tool.js.map +1 -1
- package/dist/workflows/github-agent.ui.yaml +6 -16
- package/dist/workflows/github-agent.workflow.d.ts +44 -40
- package/dist/workflows/github-agent.workflow.d.ts.map +1 -1
- package/dist/workflows/github-agent.workflow.js +143 -195
- package/dist/workflows/github-agent.workflow.js.map +1 -1
- package/dist/workflows/github-repos-overview.workflow.d.ts +31 -28
- package/dist/workflows/github-repos-overview.workflow.d.ts.map +1 -1
- package/dist/workflows/github-repos-overview.workflow.js +92 -115
- package/dist/workflows/github-repos-overview.workflow.js.map +1 -1
- package/package.json +6 -7
- package/src/tools/authenticate-github-task.tool.ts +30 -18
- package/src/workflows/__tests__/github-repos-overview-workflow.spec.ts +18 -44
- package/src/workflows/github-agent.ui.yaml +6 -16
- package/src/workflows/github-agent.workflow.ts +134 -128
- package/src/workflows/github-repos-overview.workflow.ts +103 -150
- package/dist/workflows/github-repos-overview.ui.yaml +0 -17
- package/src/workflows/github-repos-overview.ui.yaml +0 -17
|
@@ -2,17 +2,13 @@ import { z } from 'zod';
|
|
|
2
2
|
import {
|
|
3
3
|
BaseWorkflow,
|
|
4
4
|
CallbackSchema,
|
|
5
|
-
Final,
|
|
6
5
|
Guard,
|
|
7
|
-
Initial,
|
|
8
|
-
InjectTool,
|
|
9
|
-
InjectWorkflow,
|
|
10
6
|
LinkDocument,
|
|
11
7
|
MarkdownDocument,
|
|
12
|
-
ToolResult,
|
|
13
8
|
Transition,
|
|
14
9
|
Workflow,
|
|
15
10
|
} from '@loopstack/common';
|
|
11
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
16
12
|
import {
|
|
17
13
|
GitHubGetAuthenticatedUserTool,
|
|
18
14
|
GitHubGetRepoTool,
|
|
@@ -26,17 +22,13 @@ import {
|
|
|
26
22
|
} from '@loopstack/github-module';
|
|
27
23
|
import { OAuthWorkflow } from '@loopstack/oauth-module';
|
|
28
24
|
|
|
29
|
-
interface
|
|
30
|
-
|
|
25
|
+
interface GitHubReposOverviewState {
|
|
26
|
+
owner: string;
|
|
27
|
+
repo: string;
|
|
28
|
+
requiresAuthentication?: boolean;
|
|
31
29
|
user?: { login: string; name: string | null; htmlUrl: string; publicRepos: number };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface GitHubOrgsResult {
|
|
35
|
-
orgs: Array<{ login: string; description: string | null }>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface GitHubRepoResult {
|
|
39
|
-
repo: {
|
|
30
|
+
orgs?: Array<{ login: string; description: string | null }>;
|
|
31
|
+
repoDetails?: {
|
|
40
32
|
fullName: string;
|
|
41
33
|
description: string | null;
|
|
42
34
|
language: string | null;
|
|
@@ -46,18 +38,9 @@ interface GitHubRepoResult {
|
|
|
46
38
|
defaultBranch: string;
|
|
47
39
|
htmlUrl: string;
|
|
48
40
|
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
branches: Array<{ name: string; protected: boolean }>;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface GitHubIssuesResult {
|
|
56
|
-
issues: Array<{ number: number; title: string; state: string; user: string; htmlUrl: string }>;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface GitHubPullRequestsResult {
|
|
60
|
-
pullRequests: Array<{
|
|
41
|
+
branches?: Array<{ name: string; protected: boolean }>;
|
|
42
|
+
issues?: Array<{ number: number; title: string; state: string; user: string; htmlUrl: string }>;
|
|
43
|
+
pullRequests?: Array<{
|
|
61
44
|
number: number;
|
|
62
45
|
title: string;
|
|
63
46
|
state: string;
|
|
@@ -65,30 +48,22 @@ interface GitHubPullRequestsResult {
|
|
|
65
48
|
draft: boolean;
|
|
66
49
|
htmlUrl: string;
|
|
67
50
|
}>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
interface GitHubDirectoryResult {
|
|
71
|
-
entries: Array<{ name: string; type: string; path: string }>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface GitHubWorkflowRunsResult {
|
|
75
|
-
totalCount: number;
|
|
76
|
-
runs: Array<{
|
|
51
|
+
directoryEntries?: Array<{ name: string; type: string; path: string }>;
|
|
52
|
+
workflowRuns?: Array<{
|
|
77
53
|
id: number;
|
|
78
54
|
name: string;
|
|
79
55
|
status: string;
|
|
80
56
|
conclusion: string | null;
|
|
81
57
|
htmlUrl: string;
|
|
82
58
|
}>;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
interface GitHubSearchCodeResult {
|
|
86
|
-
totalCount: number;
|
|
87
|
-
results: Array<{ name: string; path: string; repository: string }>;
|
|
59
|
+
searchResults?: Array<{ name: string; path: string; repository: string }>;
|
|
88
60
|
}
|
|
89
61
|
|
|
90
62
|
@Workflow({
|
|
91
|
-
|
|
63
|
+
title: 'GitHub Repository Overview',
|
|
64
|
+
description:
|
|
65
|
+
'Comprehensive GitHub example that exercises every GitHub tool.\nFetches user info, repository details, issues, pull requests, branches,\ndirectory contents, workflow runs, and search results for a given repository.\nIf not authenticated, launches the OAuth sub-workflow and retries.',
|
|
66
|
+
name: 'github_repos_overview',
|
|
92
67
|
schema: z
|
|
93
68
|
.object({
|
|
94
69
|
owner: z.string().default('octocat'),
|
|
@@ -96,75 +71,50 @@ interface GitHubSearchCodeResult {
|
|
|
96
71
|
})
|
|
97
72
|
.strict(),
|
|
98
73
|
})
|
|
99
|
-
export class GitHubReposOverviewWorkflow extends BaseWorkflow<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
74
|
+
export class GitHubReposOverviewWorkflow extends BaseWorkflow<
|
|
75
|
+
{ owner: string; repo: string },
|
|
76
|
+
GitHubReposOverviewState
|
|
77
|
+
> {
|
|
78
|
+
constructor(
|
|
79
|
+
private readonly gitHubGetAuthenticatedUser: GitHubGetAuthenticatedUserTool,
|
|
80
|
+
private readonly gitHubListUserOrgs: GitHubListUserOrgsTool,
|
|
81
|
+
private readonly gitHubGetRepo: GitHubGetRepoTool,
|
|
82
|
+
private readonly gitHubListBranches: GitHubListBranchesTool,
|
|
83
|
+
private readonly gitHubListIssues: GitHubListIssuesTool,
|
|
84
|
+
private readonly gitHubListPullRequests: GitHubListPullRequestsTool,
|
|
85
|
+
private readonly gitHubListDirectory: GitHubListDirectoryTool,
|
|
86
|
+
private readonly gitHubListWorkflowRuns: GitHubListWorkflowRunsTool,
|
|
87
|
+
private readonly gitHubSearchCode: GitHubSearchCodeTool,
|
|
88
|
+
private readonly oAuthWorkflow: OAuthWorkflow,
|
|
89
|
+
) {
|
|
90
|
+
super();
|
|
91
|
+
}
|
|
112
92
|
|
|
113
|
-
owner!: string;
|
|
114
|
-
repo!: string;
|
|
115
|
-
requiresAuthentication?: boolean;
|
|
116
|
-
user?: { login: string; name: string | null; htmlUrl: string; publicRepos: number };
|
|
117
|
-
orgs?: Array<{ login: string; description: string | null }>;
|
|
118
|
-
repoDetails?: {
|
|
119
|
-
fullName: string;
|
|
120
|
-
description: string | null;
|
|
121
|
-
language: string | null;
|
|
122
|
-
stars: number;
|
|
123
|
-
forks: number;
|
|
124
|
-
openIssues: number;
|
|
125
|
-
defaultBranch: string;
|
|
126
|
-
htmlUrl: string;
|
|
127
|
-
};
|
|
128
|
-
branches?: Array<{ name: string; protected: boolean }>;
|
|
129
|
-
issues?: Array<{ number: number; title: string; state: string; user: string; htmlUrl: string }>;
|
|
130
|
-
pullRequests?: Array<{
|
|
131
|
-
number: number;
|
|
132
|
-
title: string;
|
|
133
|
-
state: string;
|
|
134
|
-
user: string;
|
|
135
|
-
draft: boolean;
|
|
136
|
-
htmlUrl: string;
|
|
137
|
-
}>;
|
|
138
|
-
directoryEntries?: Array<{ name: string; type: string; path: string }>;
|
|
139
|
-
workflowRuns?: Array<{
|
|
140
|
-
id: number;
|
|
141
|
-
name: string;
|
|
142
|
-
status: string;
|
|
143
|
-
conclusion: string | null;
|
|
144
|
-
htmlUrl: string;
|
|
145
|
-
}>;
|
|
146
|
-
searchResults?: Array<{ name: string; path: string; repository: string }>;
|
|
147
93
|
// --- Step 1: Fetch authenticated user ---
|
|
148
94
|
|
|
149
|
-
@
|
|
150
|
-
async fetchUser(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
95
|
+
@Transition({ to: 'user_fetched' })
|
|
96
|
+
async fetchUser(state: GitHubReposOverviewState, ctx: LoopstackContext): Promise<GitHubReposOverviewState> {
|
|
97
|
+
const args = ctx.args as { owner: string; repo: string };
|
|
98
|
+
const result = await this.gitHubGetAuthenticatedUser.call();
|
|
99
|
+
return {
|
|
100
|
+
...state,
|
|
101
|
+
owner: args.owner,
|
|
102
|
+
repo: args.repo,
|
|
103
|
+
requiresAuthentication: result.data!.error === 'unauthorized',
|
|
104
|
+
user: result.data!.user,
|
|
105
|
+
};
|
|
156
106
|
}
|
|
157
107
|
|
|
158
108
|
// If unauthorized -> launch OAuth
|
|
159
109
|
@Transition({ from: 'user_fetched', to: 'awaiting_auth', priority: 10 })
|
|
160
110
|
@Guard('needsAuth')
|
|
161
|
-
async authRequired() {
|
|
162
|
-
const result = await this.
|
|
111
|
+
async authRequired(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
112
|
+
const result = await this.oAuthWorkflow.run(
|
|
163
113
|
{ provider: 'github', scopes: ['repo', 'read:org', 'workflow'] },
|
|
164
|
-
{
|
|
114
|
+
{ callback: { transition: 'authCompleted' } },
|
|
165
115
|
);
|
|
166
116
|
|
|
167
|
-
await this.
|
|
117
|
+
await this.documentStore.save(
|
|
168
118
|
LinkDocument,
|
|
169
119
|
{
|
|
170
120
|
label: 'GitHub authentication required',
|
|
@@ -174,10 +124,11 @@ export class GitHubReposOverviewWorkflow extends BaseWorkflow<{ owner: string; r
|
|
|
174
124
|
},
|
|
175
125
|
{ id: `link_${result.workflowId}` },
|
|
176
126
|
);
|
|
127
|
+
return state;
|
|
177
128
|
}
|
|
178
129
|
|
|
179
|
-
needsAuth(): boolean {
|
|
180
|
-
return !!
|
|
130
|
+
needsAuth(state: GitHubReposOverviewState): boolean {
|
|
131
|
+
return !!state.requiresAuthentication;
|
|
181
132
|
}
|
|
182
133
|
|
|
183
134
|
// Auth completed -> retry from start
|
|
@@ -187,8 +138,11 @@ export class GitHubReposOverviewWorkflow extends BaseWorkflow<{ owner: string; r
|
|
|
187
138
|
wait: true,
|
|
188
139
|
schema: CallbackSchema,
|
|
189
140
|
})
|
|
190
|
-
async authCompleted(
|
|
191
|
-
|
|
141
|
+
async authCompleted(
|
|
142
|
+
state: GitHubReposOverviewState,
|
|
143
|
+
payload: { workflowId: string },
|
|
144
|
+
): Promise<GitHubReposOverviewState> {
|
|
145
|
+
await this.documentStore.save(
|
|
192
146
|
LinkDocument,
|
|
193
147
|
{
|
|
194
148
|
status: 'success',
|
|
@@ -199,99 +153,98 @@ export class GitHubReposOverviewWorkflow extends BaseWorkflow<{ owner: string; r
|
|
|
199
153
|
},
|
|
200
154
|
{ id: `link_${payload.workflowId}` },
|
|
201
155
|
);
|
|
156
|
+
return state;
|
|
202
157
|
}
|
|
203
158
|
|
|
204
159
|
// --- Step 2: Fetch user orgs ---
|
|
205
160
|
|
|
206
161
|
@Transition({ from: 'user_fetched', to: 'orgs_fetched' })
|
|
207
|
-
async fetchOrgs() {
|
|
208
|
-
const result
|
|
209
|
-
|
|
162
|
+
async fetchOrgs(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
163
|
+
const result = await this.gitHubListUserOrgs.call({ perPage: 10 });
|
|
164
|
+
return { ...state, orgs: result.data!.orgs };
|
|
210
165
|
}
|
|
211
166
|
|
|
212
167
|
// --- Step 3: Fetch repo details and branches ---
|
|
213
168
|
|
|
214
169
|
@Transition({ from: 'orgs_fetched', to: 'repo_fetched' })
|
|
215
|
-
async fetchRepoDetails() {
|
|
216
|
-
const repoResult
|
|
217
|
-
owner:
|
|
218
|
-
repo:
|
|
170
|
+
async fetchRepoDetails(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
171
|
+
const repoResult = await this.gitHubGetRepo.call({
|
|
172
|
+
owner: state.owner,
|
|
173
|
+
repo: state.repo,
|
|
219
174
|
});
|
|
220
|
-
this.repoDetails = repoResult.data!.repo;
|
|
221
175
|
|
|
222
|
-
const branchesResult
|
|
223
|
-
owner:
|
|
224
|
-
repo:
|
|
176
|
+
const branchesResult = await this.gitHubListBranches.call({
|
|
177
|
+
owner: state.owner,
|
|
178
|
+
repo: state.repo,
|
|
225
179
|
});
|
|
226
|
-
|
|
180
|
+
return { ...state, repoDetails: repoResult.data!.repo, branches: branchesResult.data!.branches };
|
|
227
181
|
}
|
|
228
182
|
|
|
229
183
|
// --- Step 4: Fetch issues and PRs ---
|
|
230
184
|
|
|
231
185
|
@Transition({ from: 'repo_fetched', to: 'issues_prs_fetched' })
|
|
232
|
-
async fetchIssuesPrs() {
|
|
233
|
-
const issuesResult
|
|
234
|
-
owner:
|
|
235
|
-
repo:
|
|
186
|
+
async fetchIssuesPrs(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
187
|
+
const issuesResult = await this.gitHubListIssues.call({
|
|
188
|
+
owner: state.owner,
|
|
189
|
+
repo: state.repo,
|
|
236
190
|
state: 'open',
|
|
237
191
|
perPage: 10,
|
|
238
192
|
});
|
|
239
|
-
this.issues = issuesResult.data!.issues;
|
|
240
193
|
|
|
241
|
-
const prsResult
|
|
242
|
-
owner:
|
|
243
|
-
repo:
|
|
194
|
+
const prsResult = await this.gitHubListPullRequests.call({
|
|
195
|
+
owner: state.owner,
|
|
196
|
+
repo: state.repo,
|
|
244
197
|
state: 'open',
|
|
245
198
|
perPage: 10,
|
|
246
199
|
});
|
|
247
|
-
|
|
200
|
+
return { ...state, issues: issuesResult.data!.issues, pullRequests: prsResult.data!.pullRequests };
|
|
248
201
|
}
|
|
249
202
|
|
|
250
203
|
// --- Step 5: Fetch directory listing and workflow runs ---
|
|
251
204
|
|
|
252
205
|
@Transition({ from: 'issues_prs_fetched', to: 'content_actions_fetched' })
|
|
253
|
-
async fetchContentActions() {
|
|
254
|
-
const dirResult
|
|
255
|
-
owner:
|
|
256
|
-
repo:
|
|
206
|
+
async fetchContentActions(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
207
|
+
const dirResult = await this.gitHubListDirectory.call({
|
|
208
|
+
owner: state.owner,
|
|
209
|
+
repo: state.repo,
|
|
257
210
|
});
|
|
258
|
-
this.directoryEntries = dirResult.data!.entries;
|
|
259
211
|
|
|
260
|
-
const runsResult
|
|
261
|
-
owner:
|
|
262
|
-
repo:
|
|
212
|
+
const runsResult = await this.gitHubListWorkflowRuns.call({
|
|
213
|
+
owner: state.owner,
|
|
214
|
+
repo: state.repo,
|
|
263
215
|
perPage: 5,
|
|
264
216
|
});
|
|
265
|
-
|
|
217
|
+
return { ...state, directoryEntries: dirResult.data!.entries, workflowRuns: runsResult.data!.runs };
|
|
266
218
|
}
|
|
267
219
|
|
|
268
220
|
// --- Step 6: Search code in the repo ---
|
|
269
221
|
|
|
270
222
|
@Transition({ from: 'content_actions_fetched', to: 'search_done' })
|
|
271
|
-
async fetchSearch() {
|
|
272
|
-
const result
|
|
273
|
-
query: `repo:${
|
|
223
|
+
async fetchSearch(state: GitHubReposOverviewState): Promise<GitHubReposOverviewState> {
|
|
224
|
+
const result = await this.gitHubSearchCode.call({
|
|
225
|
+
query: `repo:${state.owner}/${state.repo}`,
|
|
274
226
|
perPage: 5,
|
|
275
227
|
});
|
|
276
|
-
|
|
228
|
+
return { ...state, searchResults: result.data!.results };
|
|
277
229
|
}
|
|
278
230
|
|
|
279
231
|
// --- Display all results ---
|
|
280
232
|
|
|
281
|
-
@
|
|
282
|
-
async displayResults() {
|
|
283
|
-
await this.
|
|
233
|
+
@Transition({ from: 'search_done', to: 'end' })
|
|
234
|
+
async displayResults(state: GitHubReposOverviewState): Promise<unknown> {
|
|
235
|
+
await this.documentStore.save(MarkdownDocument, {
|
|
284
236
|
markdown: this.render(__dirname + '/templates/repoOverview.md', {
|
|
285
|
-
user:
|
|
286
|
-
orgs:
|
|
287
|
-
repo:
|
|
288
|
-
branches:
|
|
289
|
-
issues:
|
|
290
|
-
pullRequests:
|
|
291
|
-
directoryEntries:
|
|
292
|
-
workflowRuns:
|
|
293
|
-
searchResults:
|
|
237
|
+
user: state.user,
|
|
238
|
+
orgs: state.orgs,
|
|
239
|
+
repo: state.repoDetails,
|
|
240
|
+
branches: state.branches,
|
|
241
|
+
issues: state.issues,
|
|
242
|
+
pullRequests: state.pullRequests,
|
|
243
|
+
directoryEntries: state.directoryEntries,
|
|
244
|
+
workflowRuns: state.workflowRuns,
|
|
245
|
+
searchResults: state.searchResults,
|
|
294
246
|
}),
|
|
295
247
|
});
|
|
248
|
+
return {};
|
|
296
249
|
}
|
|
297
250
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
title: 'GitHub Repository Overview'
|
|
2
|
-
|
|
3
|
-
description: |
|
|
4
|
-
Comprehensive GitHub example that exercises every GitHub tool.
|
|
5
|
-
Fetches user info, repository details, issues, pull requests, branches,
|
|
6
|
-
directory contents, workflow runs, and search results for a given repository.
|
|
7
|
-
If not authenticated, launches the OAuth sub-workflow and retries.
|
|
8
|
-
|
|
9
|
-
ui:
|
|
10
|
-
form:
|
|
11
|
-
properties:
|
|
12
|
-
owner:
|
|
13
|
-
title: 'Repository Owner'
|
|
14
|
-
placeholder: 'octocat'
|
|
15
|
-
repo:
|
|
16
|
-
title: 'Repository Name'
|
|
17
|
-
placeholder: 'Hello-World'
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
title: 'GitHub Repository Overview'
|
|
2
|
-
|
|
3
|
-
description: |
|
|
4
|
-
Comprehensive GitHub example that exercises every GitHub tool.
|
|
5
|
-
Fetches user info, repository details, issues, pull requests, branches,
|
|
6
|
-
directory contents, workflow runs, and search results for a given repository.
|
|
7
|
-
If not authenticated, launches the OAuth sub-workflow and retries.
|
|
8
|
-
|
|
9
|
-
ui:
|
|
10
|
-
form:
|
|
11
|
-
properties:
|
|
12
|
-
owner:
|
|
13
|
-
title: 'Repository Owner'
|
|
14
|
-
placeholder: 'octocat'
|
|
15
|
-
repo:
|
|
16
|
-
title: 'Repository Name'
|
|
17
|
-
placeholder: 'Hello-World'
|