git-workspace-service 0.1.0
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 +416 -0
- package/dist/index.cjs +2425 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1518 -0
- package/dist/index.d.ts +1518 -0
- package/dist/index.js +2377 -0
- package/dist/index.js.map +1 -0
- package/package.json +82 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Workspace Service Types
|
|
3
|
+
*
|
|
4
|
+
* Types for git workspace provisioning and credential management.
|
|
5
|
+
*/
|
|
6
|
+
type GitProvider = 'github' | 'gitlab' | 'bitbucket' | 'azure_devops' | 'self_hosted';
|
|
7
|
+
type CredentialType = 'github_app' | 'oauth' | 'deploy_key' | 'pat' | 'ssh_key';
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for creating a new branch
|
|
10
|
+
*/
|
|
11
|
+
interface BranchConfig {
|
|
12
|
+
/**
|
|
13
|
+
* Execution or context ID this branch belongs to
|
|
14
|
+
*/
|
|
15
|
+
executionId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Role or task identifier
|
|
18
|
+
*/
|
|
19
|
+
role: string;
|
|
20
|
+
/**
|
|
21
|
+
* Optional slug for human readability
|
|
22
|
+
*/
|
|
23
|
+
slug?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Base branch to create from
|
|
26
|
+
*/
|
|
27
|
+
baseBranch: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Information about a created branch
|
|
31
|
+
*/
|
|
32
|
+
interface BranchInfo {
|
|
33
|
+
/**
|
|
34
|
+
* Full branch name (e.g., "parallax/exec-abc123/engineer-auth")
|
|
35
|
+
*/
|
|
36
|
+
name: string;
|
|
37
|
+
/**
|
|
38
|
+
* Execution this branch belongs to
|
|
39
|
+
*/
|
|
40
|
+
executionId: string;
|
|
41
|
+
/**
|
|
42
|
+
* Base branch it was created from
|
|
43
|
+
*/
|
|
44
|
+
baseBranch: string;
|
|
45
|
+
/**
|
|
46
|
+
* When the branch was created
|
|
47
|
+
*/
|
|
48
|
+
createdAt: Date;
|
|
49
|
+
/**
|
|
50
|
+
* Associated PR if one exists
|
|
51
|
+
*/
|
|
52
|
+
pullRequest?: PullRequestInfo;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Token-based credentials (PAT or OAuth)
|
|
56
|
+
*/
|
|
57
|
+
interface TokenCredentials {
|
|
58
|
+
/**
|
|
59
|
+
* Type of credential
|
|
60
|
+
*/
|
|
61
|
+
type: 'pat' | 'oauth';
|
|
62
|
+
/**
|
|
63
|
+
* The credential token
|
|
64
|
+
*/
|
|
65
|
+
token: string;
|
|
66
|
+
/**
|
|
67
|
+
* Git provider this credential is for (defaults to 'github')
|
|
68
|
+
*/
|
|
69
|
+
provider?: GitProvider;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* SSH-based credentials using system SSH agent
|
|
73
|
+
*/
|
|
74
|
+
interface SshCredentials {
|
|
75
|
+
/**
|
|
76
|
+
* Type of credential
|
|
77
|
+
*/
|
|
78
|
+
type: 'ssh';
|
|
79
|
+
/**
|
|
80
|
+
* Git provider this credential is for (defaults to 'github')
|
|
81
|
+
*/
|
|
82
|
+
provider?: GitProvider;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* User-provided credentials passed at execution time.
|
|
86
|
+
* Allows users to supply their own PAT, OAuth token, or use system SSH.
|
|
87
|
+
*/
|
|
88
|
+
type UserProvidedCredentials = TokenCredentials | SshCredentials;
|
|
89
|
+
/**
|
|
90
|
+
* Context for credential requests (for audit trails)
|
|
91
|
+
*/
|
|
92
|
+
interface CredentialContext {
|
|
93
|
+
executionId: string;
|
|
94
|
+
taskId?: string;
|
|
95
|
+
agentId?: string;
|
|
96
|
+
userId?: string;
|
|
97
|
+
reason?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Request for git credentials
|
|
101
|
+
*/
|
|
102
|
+
interface GitCredentialRequest {
|
|
103
|
+
/**
|
|
104
|
+
* Repository URL or identifier
|
|
105
|
+
*/
|
|
106
|
+
repo: string;
|
|
107
|
+
/**
|
|
108
|
+
* Required access level
|
|
109
|
+
*/
|
|
110
|
+
access: 'read' | 'write';
|
|
111
|
+
/**
|
|
112
|
+
* Context for audit trail
|
|
113
|
+
*/
|
|
114
|
+
context: CredentialContext;
|
|
115
|
+
/**
|
|
116
|
+
* Requested TTL in seconds (max enforced by policy)
|
|
117
|
+
*/
|
|
118
|
+
ttlSeconds?: number;
|
|
119
|
+
/**
|
|
120
|
+
* User-provided credentials (PAT or OAuth token)
|
|
121
|
+
* If provided, these are used instead of managed credentials
|
|
122
|
+
*/
|
|
123
|
+
userProvided?: UserProvidedCredentials;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A git credential grant
|
|
127
|
+
*/
|
|
128
|
+
interface GitCredential {
|
|
129
|
+
/**
|
|
130
|
+
* Unique ID for this credential grant
|
|
131
|
+
*/
|
|
132
|
+
id: string;
|
|
133
|
+
/**
|
|
134
|
+
* How to authenticate
|
|
135
|
+
*/
|
|
136
|
+
type: CredentialType;
|
|
137
|
+
/**
|
|
138
|
+
* The credential value (token, key, etc.)
|
|
139
|
+
*/
|
|
140
|
+
token: string;
|
|
141
|
+
/**
|
|
142
|
+
* Repository this credential is scoped to
|
|
143
|
+
*/
|
|
144
|
+
repo: string;
|
|
145
|
+
/**
|
|
146
|
+
* Permissions granted
|
|
147
|
+
*/
|
|
148
|
+
permissions: string[];
|
|
149
|
+
/**
|
|
150
|
+
* When this credential expires
|
|
151
|
+
*/
|
|
152
|
+
expiresAt: Date;
|
|
153
|
+
/**
|
|
154
|
+
* Git provider
|
|
155
|
+
*/
|
|
156
|
+
provider: GitProvider;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Record of a credential grant for auditing
|
|
160
|
+
*/
|
|
161
|
+
interface CredentialGrant {
|
|
162
|
+
id: string;
|
|
163
|
+
type: CredentialType;
|
|
164
|
+
repo: string;
|
|
165
|
+
provider: GitProvider;
|
|
166
|
+
grantedTo: {
|
|
167
|
+
executionId: string;
|
|
168
|
+
taskId?: string;
|
|
169
|
+
agentId?: string;
|
|
170
|
+
};
|
|
171
|
+
permissions: string[];
|
|
172
|
+
createdAt: Date;
|
|
173
|
+
expiresAt: Date;
|
|
174
|
+
revokedAt?: Date;
|
|
175
|
+
lastUsedAt?: Date;
|
|
176
|
+
}
|
|
177
|
+
type BranchStrategy = 'feature_branch' | 'fork' | 'direct';
|
|
178
|
+
type WorkspaceStatus = 'provisioning' | 'ready' | 'in_use' | 'finalizing' | 'cleaned_up' | 'error';
|
|
179
|
+
/**
|
|
180
|
+
* Configuration for provisioning a workspace
|
|
181
|
+
*/
|
|
182
|
+
interface WorkspaceConfig {
|
|
183
|
+
/**
|
|
184
|
+
* Repository to clone
|
|
185
|
+
*/
|
|
186
|
+
repo: string;
|
|
187
|
+
/**
|
|
188
|
+
* Git provider
|
|
189
|
+
*/
|
|
190
|
+
provider?: GitProvider;
|
|
191
|
+
/**
|
|
192
|
+
* Branch strategy
|
|
193
|
+
*/
|
|
194
|
+
branchStrategy: BranchStrategy;
|
|
195
|
+
/**
|
|
196
|
+
* Base branch to create feature branches from
|
|
197
|
+
*/
|
|
198
|
+
baseBranch: string;
|
|
199
|
+
/**
|
|
200
|
+
* Execution context
|
|
201
|
+
*/
|
|
202
|
+
execution: {
|
|
203
|
+
id: string;
|
|
204
|
+
patternName: string;
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Task/role requesting the workspace
|
|
208
|
+
*/
|
|
209
|
+
task: {
|
|
210
|
+
id: string;
|
|
211
|
+
role: string;
|
|
212
|
+
slug?: string;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* User context for credential resolution
|
|
216
|
+
*/
|
|
217
|
+
user?: {
|
|
218
|
+
id: string;
|
|
219
|
+
oauthToken?: string;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* User-provided credentials (PAT or OAuth token)
|
|
223
|
+
* If provided, these are used instead of managed credentials
|
|
224
|
+
*/
|
|
225
|
+
userCredentials?: UserProvidedCredentials;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* A provisioned git workspace
|
|
229
|
+
*/
|
|
230
|
+
interface Workspace {
|
|
231
|
+
/**
|
|
232
|
+
* Unique workspace ID
|
|
233
|
+
*/
|
|
234
|
+
id: string;
|
|
235
|
+
/**
|
|
236
|
+
* Local filesystem path
|
|
237
|
+
*/
|
|
238
|
+
path: string;
|
|
239
|
+
/**
|
|
240
|
+
* Repository URL
|
|
241
|
+
*/
|
|
242
|
+
repo: string;
|
|
243
|
+
/**
|
|
244
|
+
* Branch created for this workspace
|
|
245
|
+
*/
|
|
246
|
+
branch: BranchInfo;
|
|
247
|
+
/**
|
|
248
|
+
* Credential for this workspace
|
|
249
|
+
*/
|
|
250
|
+
credential: GitCredential;
|
|
251
|
+
/**
|
|
252
|
+
* When the workspace was provisioned
|
|
253
|
+
*/
|
|
254
|
+
provisionedAt: Date;
|
|
255
|
+
/**
|
|
256
|
+
* Current status
|
|
257
|
+
*/
|
|
258
|
+
status: WorkspaceStatus;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Options for finalizing a workspace (push, PR creation, cleanup)
|
|
262
|
+
*/
|
|
263
|
+
interface WorkspaceFinalization {
|
|
264
|
+
/**
|
|
265
|
+
* Whether to push the branch
|
|
266
|
+
*/
|
|
267
|
+
push: boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Whether to create a PR
|
|
270
|
+
*/
|
|
271
|
+
createPr: boolean;
|
|
272
|
+
/**
|
|
273
|
+
* PR configuration
|
|
274
|
+
*/
|
|
275
|
+
pr?: {
|
|
276
|
+
title: string;
|
|
277
|
+
body: string;
|
|
278
|
+
targetBranch: string;
|
|
279
|
+
draft?: boolean;
|
|
280
|
+
labels?: string[];
|
|
281
|
+
reviewers?: string[];
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Whether to clean up the workspace after finalization
|
|
285
|
+
*/
|
|
286
|
+
cleanup: boolean;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Information about a pull request
|
|
290
|
+
*/
|
|
291
|
+
interface PullRequestInfo {
|
|
292
|
+
/**
|
|
293
|
+
* PR number
|
|
294
|
+
*/
|
|
295
|
+
number: number;
|
|
296
|
+
/**
|
|
297
|
+
* PR URL
|
|
298
|
+
*/
|
|
299
|
+
url: string;
|
|
300
|
+
/**
|
|
301
|
+
* PR state
|
|
302
|
+
*/
|
|
303
|
+
state: 'open' | 'closed' | 'merged';
|
|
304
|
+
/**
|
|
305
|
+
* Source branch
|
|
306
|
+
*/
|
|
307
|
+
sourceBranch: string;
|
|
308
|
+
/**
|
|
309
|
+
* Target branch
|
|
310
|
+
*/
|
|
311
|
+
targetBranch: string;
|
|
312
|
+
/**
|
|
313
|
+
* Title
|
|
314
|
+
*/
|
|
315
|
+
title: string;
|
|
316
|
+
/**
|
|
317
|
+
* Associated execution ID
|
|
318
|
+
*/
|
|
319
|
+
executionId: string;
|
|
320
|
+
/**
|
|
321
|
+
* Created timestamp
|
|
322
|
+
*/
|
|
323
|
+
createdAt: Date;
|
|
324
|
+
/**
|
|
325
|
+
* Merged timestamp if merged
|
|
326
|
+
*/
|
|
327
|
+
mergedAt?: Date;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Issue state
|
|
331
|
+
*/
|
|
332
|
+
type IssueState = 'open' | 'closed';
|
|
333
|
+
/**
|
|
334
|
+
* Information about an issue
|
|
335
|
+
*/
|
|
336
|
+
interface IssueInfo {
|
|
337
|
+
/**
|
|
338
|
+
* Issue number
|
|
339
|
+
*/
|
|
340
|
+
number: number;
|
|
341
|
+
/**
|
|
342
|
+
* Issue URL
|
|
343
|
+
*/
|
|
344
|
+
url: string;
|
|
345
|
+
/**
|
|
346
|
+
* Issue state
|
|
347
|
+
*/
|
|
348
|
+
state: IssueState;
|
|
349
|
+
/**
|
|
350
|
+
* Issue title
|
|
351
|
+
*/
|
|
352
|
+
title: string;
|
|
353
|
+
/**
|
|
354
|
+
* Issue body/description
|
|
355
|
+
*/
|
|
356
|
+
body: string;
|
|
357
|
+
/**
|
|
358
|
+
* Labels on the issue
|
|
359
|
+
*/
|
|
360
|
+
labels: string[];
|
|
361
|
+
/**
|
|
362
|
+
* Assignees
|
|
363
|
+
*/
|
|
364
|
+
assignees: string[];
|
|
365
|
+
/**
|
|
366
|
+
* Created timestamp
|
|
367
|
+
*/
|
|
368
|
+
createdAt: Date;
|
|
369
|
+
/**
|
|
370
|
+
* Closed timestamp if closed
|
|
371
|
+
*/
|
|
372
|
+
closedAt?: Date;
|
|
373
|
+
/**
|
|
374
|
+
* Associated execution ID (if managed)
|
|
375
|
+
*/
|
|
376
|
+
executionId?: string;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Options for creating an issue
|
|
380
|
+
*/
|
|
381
|
+
interface CreateIssueOptions {
|
|
382
|
+
/**
|
|
383
|
+
* Issue title
|
|
384
|
+
*/
|
|
385
|
+
title: string;
|
|
386
|
+
/**
|
|
387
|
+
* Issue body/description
|
|
388
|
+
*/
|
|
389
|
+
body: string;
|
|
390
|
+
/**
|
|
391
|
+
* Labels to add
|
|
392
|
+
*/
|
|
393
|
+
labels?: string[];
|
|
394
|
+
/**
|
|
395
|
+
* Assignees (usernames)
|
|
396
|
+
*/
|
|
397
|
+
assignees?: string[];
|
|
398
|
+
/**
|
|
399
|
+
* Milestone number
|
|
400
|
+
*/
|
|
401
|
+
milestone?: number;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Options for commenting on an issue
|
|
405
|
+
*/
|
|
406
|
+
interface IssueCommentOptions {
|
|
407
|
+
/**
|
|
408
|
+
* Comment body
|
|
409
|
+
*/
|
|
410
|
+
body: string;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Information about an issue comment
|
|
414
|
+
*/
|
|
415
|
+
interface IssueComment {
|
|
416
|
+
/**
|
|
417
|
+
* Comment ID
|
|
418
|
+
*/
|
|
419
|
+
id: number;
|
|
420
|
+
/**
|
|
421
|
+
* Comment URL
|
|
422
|
+
*/
|
|
423
|
+
url: string;
|
|
424
|
+
/**
|
|
425
|
+
* Comment body
|
|
426
|
+
*/
|
|
427
|
+
body: string;
|
|
428
|
+
/**
|
|
429
|
+
* Author username
|
|
430
|
+
*/
|
|
431
|
+
author: string;
|
|
432
|
+
/**
|
|
433
|
+
* Created timestamp
|
|
434
|
+
*/
|
|
435
|
+
createdAt: Date;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Permission level for a resource
|
|
439
|
+
*/
|
|
440
|
+
type PermissionLevel = 'none' | 'read' | 'write';
|
|
441
|
+
/**
|
|
442
|
+
* Repository access scope
|
|
443
|
+
*/
|
|
444
|
+
type RepositoryScope = {
|
|
445
|
+
type: 'all';
|
|
446
|
+
} | {
|
|
447
|
+
type: 'public';
|
|
448
|
+
} | {
|
|
449
|
+
type: 'selected';
|
|
450
|
+
repos: string[];
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Permissions that an agent can request/receive.
|
|
454
|
+
* Designed to be restrictive by default - dangerous operations require explicit opt-in.
|
|
455
|
+
*/
|
|
456
|
+
interface AgentPermissions {
|
|
457
|
+
/**
|
|
458
|
+
* Which repositories the agent can access
|
|
459
|
+
*/
|
|
460
|
+
repositories: RepositoryScope;
|
|
461
|
+
/**
|
|
462
|
+
* Permission for repository contents (code, files)
|
|
463
|
+
*/
|
|
464
|
+
contents: PermissionLevel;
|
|
465
|
+
/**
|
|
466
|
+
* Permission for pull requests
|
|
467
|
+
*/
|
|
468
|
+
pullRequests: PermissionLevel;
|
|
469
|
+
/**
|
|
470
|
+
* Permission for issues
|
|
471
|
+
*/
|
|
472
|
+
issues: PermissionLevel;
|
|
473
|
+
/**
|
|
474
|
+
* Permission for metadata (repo info, branches, tags)
|
|
475
|
+
*/
|
|
476
|
+
metadata: PermissionLevel;
|
|
477
|
+
/**
|
|
478
|
+
* Can delete branches (for cleanup after merge)
|
|
479
|
+
* @default false
|
|
480
|
+
*/
|
|
481
|
+
canDeleteBranch?: boolean;
|
|
482
|
+
/**
|
|
483
|
+
* Can force push to branches
|
|
484
|
+
* @default false - Almost never needed, can destroy history
|
|
485
|
+
*/
|
|
486
|
+
canForcePush?: boolean;
|
|
487
|
+
/**
|
|
488
|
+
* Can delete repositories
|
|
489
|
+
* @default false - Should NEVER be true for agents
|
|
490
|
+
*/
|
|
491
|
+
canDeleteRepository?: boolean;
|
|
492
|
+
/**
|
|
493
|
+
* Can modify repository settings/webhooks
|
|
494
|
+
* @default false
|
|
495
|
+
*/
|
|
496
|
+
canAdminister?: boolean;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Default safe permissions for agents
|
|
500
|
+
*/
|
|
501
|
+
declare const DEFAULT_AGENT_PERMISSIONS: AgentPermissions;
|
|
502
|
+
/**
|
|
503
|
+
* Read-only permissions for agents that only need to inspect
|
|
504
|
+
*/
|
|
505
|
+
declare const READONLY_AGENT_PERMISSIONS: AgentPermissions;
|
|
506
|
+
/**
|
|
507
|
+
* OAuth token with metadata
|
|
508
|
+
*/
|
|
509
|
+
interface OAuthToken {
|
|
510
|
+
/**
|
|
511
|
+
* Access token for API calls
|
|
512
|
+
*/
|
|
513
|
+
accessToken: string;
|
|
514
|
+
/**
|
|
515
|
+
* Token type (usually "bearer")
|
|
516
|
+
*/
|
|
517
|
+
tokenType: string;
|
|
518
|
+
/**
|
|
519
|
+
* Scopes granted by the token
|
|
520
|
+
*/
|
|
521
|
+
scopes: string[];
|
|
522
|
+
/**
|
|
523
|
+
* When the token expires
|
|
524
|
+
*/
|
|
525
|
+
expiresAt?: Date;
|
|
526
|
+
/**
|
|
527
|
+
* Refresh token for obtaining new access tokens
|
|
528
|
+
*/
|
|
529
|
+
refreshToken?: string;
|
|
530
|
+
/**
|
|
531
|
+
* Provider this token is for
|
|
532
|
+
*/
|
|
533
|
+
provider: GitProvider;
|
|
534
|
+
/**
|
|
535
|
+
* Permissions associated with this token
|
|
536
|
+
*/
|
|
537
|
+
permissions: AgentPermissions;
|
|
538
|
+
/**
|
|
539
|
+
* When the token was created
|
|
540
|
+
*/
|
|
541
|
+
createdAt: Date;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Device code response from OAuth provider
|
|
545
|
+
*/
|
|
546
|
+
interface DeviceCodeResponse {
|
|
547
|
+
/**
|
|
548
|
+
* Code to poll for authorization
|
|
549
|
+
*/
|
|
550
|
+
deviceCode: string;
|
|
551
|
+
/**
|
|
552
|
+
* Code for user to enter
|
|
553
|
+
*/
|
|
554
|
+
userCode: string;
|
|
555
|
+
/**
|
|
556
|
+
* URL for user to visit
|
|
557
|
+
*/
|
|
558
|
+
verificationUri: string;
|
|
559
|
+
/**
|
|
560
|
+
* Full URL with code pre-filled (if supported)
|
|
561
|
+
*/
|
|
562
|
+
verificationUriComplete?: string;
|
|
563
|
+
/**
|
|
564
|
+
* Seconds until codes expire
|
|
565
|
+
*/
|
|
566
|
+
expiresIn: number;
|
|
567
|
+
/**
|
|
568
|
+
* Seconds between poll requests
|
|
569
|
+
*/
|
|
570
|
+
interval: number;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Auth prompt for user interaction
|
|
574
|
+
*/
|
|
575
|
+
interface AuthPrompt {
|
|
576
|
+
/**
|
|
577
|
+
* Provider requiring auth
|
|
578
|
+
*/
|
|
579
|
+
provider: GitProvider;
|
|
580
|
+
/**
|
|
581
|
+
* URL to visit
|
|
582
|
+
*/
|
|
583
|
+
verificationUri: string;
|
|
584
|
+
/**
|
|
585
|
+
* Code to enter
|
|
586
|
+
*/
|
|
587
|
+
userCode: string;
|
|
588
|
+
/**
|
|
589
|
+
* Seconds until code expires
|
|
590
|
+
*/
|
|
591
|
+
expiresIn: number;
|
|
592
|
+
/**
|
|
593
|
+
* Permissions being requested
|
|
594
|
+
*/
|
|
595
|
+
requestedPermissions: AgentPermissions;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Result of auth flow
|
|
599
|
+
*/
|
|
600
|
+
interface AuthResult {
|
|
601
|
+
/**
|
|
602
|
+
* Whether auth succeeded
|
|
603
|
+
*/
|
|
604
|
+
success: boolean;
|
|
605
|
+
/**
|
|
606
|
+
* Provider that was authenticated
|
|
607
|
+
*/
|
|
608
|
+
provider: GitProvider;
|
|
609
|
+
/**
|
|
610
|
+
* Username/identity if successful
|
|
611
|
+
*/
|
|
612
|
+
username?: string;
|
|
613
|
+
/**
|
|
614
|
+
* Error message if failed
|
|
615
|
+
*/
|
|
616
|
+
error?: string;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Callback interface for auth prompts
|
|
620
|
+
*/
|
|
621
|
+
interface AuthPromptEmitter {
|
|
622
|
+
/**
|
|
623
|
+
* Called when user action is required for authentication
|
|
624
|
+
*/
|
|
625
|
+
onAuthRequired(prompt: AuthPrompt): void;
|
|
626
|
+
/**
|
|
627
|
+
* Called when authentication completes (success or failure)
|
|
628
|
+
*/
|
|
629
|
+
onAuthComplete(result: AuthResult): void;
|
|
630
|
+
/**
|
|
631
|
+
* Called periodically while waiting for auth (optional)
|
|
632
|
+
*/
|
|
633
|
+
onAuthPending?(secondsRemaining: number): void;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* GitHub App configuration
|
|
637
|
+
*/
|
|
638
|
+
interface GitHubAppConfig {
|
|
639
|
+
appId: string;
|
|
640
|
+
privateKey: string;
|
|
641
|
+
webhookSecret?: string;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* GitHub App installation info
|
|
645
|
+
*/
|
|
646
|
+
interface GitHubAppInstallation {
|
|
647
|
+
installationId: number;
|
|
648
|
+
accountLogin: string;
|
|
649
|
+
accountType: 'User' | 'Organization';
|
|
650
|
+
repositories: string[];
|
|
651
|
+
permissions: Record<string, string>;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Configuration for the workspace service
|
|
655
|
+
*/
|
|
656
|
+
interface WorkspaceServiceConfig {
|
|
657
|
+
/**
|
|
658
|
+
* Base directory for workspace storage
|
|
659
|
+
*/
|
|
660
|
+
baseDir: string;
|
|
661
|
+
/**
|
|
662
|
+
* Default TTL for credentials in seconds
|
|
663
|
+
*/
|
|
664
|
+
defaultCredentialTtl?: number;
|
|
665
|
+
/**
|
|
666
|
+
* Maximum TTL for credentials in seconds
|
|
667
|
+
*/
|
|
668
|
+
maxCredentialTtl?: number;
|
|
669
|
+
/**
|
|
670
|
+
* Default branch naming prefix
|
|
671
|
+
*/
|
|
672
|
+
branchPrefix?: string;
|
|
673
|
+
/**
|
|
674
|
+
* GitHub App configuration (optional)
|
|
675
|
+
*/
|
|
676
|
+
githubApp?: GitHubAppConfig;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Configuration for the credential service
|
|
680
|
+
*/
|
|
681
|
+
interface CredentialServiceConfig {
|
|
682
|
+
/**
|
|
683
|
+
* Default TTL for credentials in seconds
|
|
684
|
+
*/
|
|
685
|
+
defaultTtl?: number;
|
|
686
|
+
/**
|
|
687
|
+
* Maximum TTL for credentials in seconds
|
|
688
|
+
*/
|
|
689
|
+
maxTtl?: number;
|
|
690
|
+
/**
|
|
691
|
+
* GitHub App configuration
|
|
692
|
+
*/
|
|
693
|
+
githubApp?: GitHubAppConfig;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Interface for git provider implementations
|
|
697
|
+
*/
|
|
698
|
+
interface GitProviderAdapter {
|
|
699
|
+
/**
|
|
700
|
+
* Provider name
|
|
701
|
+
*/
|
|
702
|
+
readonly name: GitProvider;
|
|
703
|
+
/**
|
|
704
|
+
* Get credentials for a repository
|
|
705
|
+
*/
|
|
706
|
+
getCredentials(request: GitCredentialRequest): Promise<GitCredential>;
|
|
707
|
+
/**
|
|
708
|
+
* Revoke a credential
|
|
709
|
+
*/
|
|
710
|
+
revokeCredential(credentialId: string): Promise<void>;
|
|
711
|
+
/**
|
|
712
|
+
* Create a pull request
|
|
713
|
+
*/
|
|
714
|
+
createPullRequest(options: {
|
|
715
|
+
repo: string;
|
|
716
|
+
sourceBranch: string;
|
|
717
|
+
targetBranch: string;
|
|
718
|
+
title: string;
|
|
719
|
+
body: string;
|
|
720
|
+
draft?: boolean;
|
|
721
|
+
labels?: string[];
|
|
722
|
+
reviewers?: string[];
|
|
723
|
+
credential: GitCredential;
|
|
724
|
+
}): Promise<PullRequestInfo>;
|
|
725
|
+
/**
|
|
726
|
+
* Check if a branch exists
|
|
727
|
+
*/
|
|
728
|
+
branchExists(repo: string, branch: string, credential: GitCredential): Promise<boolean>;
|
|
729
|
+
/**
|
|
730
|
+
* Get the default branch for a repository
|
|
731
|
+
*/
|
|
732
|
+
getDefaultBranch(repo: string, credential: GitCredential): Promise<string>;
|
|
733
|
+
}
|
|
734
|
+
type WorkspaceEventType = 'workspace:provisioning' | 'workspace:ready' | 'workspace:error' | 'workspace:finalizing' | 'workspace:cleaned_up' | 'credential:granted' | 'credential:revoked' | 'pr:created' | 'pr:merged';
|
|
735
|
+
interface WorkspaceEvent {
|
|
736
|
+
type: WorkspaceEventType;
|
|
737
|
+
workspaceId?: string;
|
|
738
|
+
credentialId?: string;
|
|
739
|
+
executionId: string;
|
|
740
|
+
timestamp: Date;
|
|
741
|
+
data?: Record<string, unknown>;
|
|
742
|
+
error?: string;
|
|
743
|
+
}
|
|
744
|
+
type WorkspaceEventHandler = (event: WorkspaceEvent) => void | Promise<void>;
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* OAuth Device Code Flow
|
|
748
|
+
*
|
|
749
|
+
* Implements the OAuth 2.0 Device Authorization Grant (RFC 8628)
|
|
750
|
+
* for authenticating CLI/agent applications without browser control.
|
|
751
|
+
*
|
|
752
|
+
* Flow:
|
|
753
|
+
* 1. Request device code from provider
|
|
754
|
+
* 2. Display verification URL and user code to user
|
|
755
|
+
* 3. Poll for authorization while user completes in browser
|
|
756
|
+
* 4. Receive access token on success
|
|
757
|
+
*/
|
|
758
|
+
|
|
759
|
+
interface OAuthDeviceFlowConfig {
|
|
760
|
+
/**
|
|
761
|
+
* OAuth Client ID
|
|
762
|
+
*/
|
|
763
|
+
clientId: string;
|
|
764
|
+
/**
|
|
765
|
+
* OAuth Client Secret (optional for public clients)
|
|
766
|
+
*/
|
|
767
|
+
clientSecret?: string;
|
|
768
|
+
/**
|
|
769
|
+
* Provider (defaults to 'github')
|
|
770
|
+
*/
|
|
771
|
+
provider?: GitProvider;
|
|
772
|
+
/**
|
|
773
|
+
* Permissions to request
|
|
774
|
+
*/
|
|
775
|
+
permissions?: AgentPermissions;
|
|
776
|
+
/**
|
|
777
|
+
* Auth prompt emitter for user interaction
|
|
778
|
+
*/
|
|
779
|
+
promptEmitter?: AuthPromptEmitter;
|
|
780
|
+
/**
|
|
781
|
+
* Timeout in seconds for the auth flow (default: 900 = 15 min)
|
|
782
|
+
*/
|
|
783
|
+
timeout?: number;
|
|
784
|
+
}
|
|
785
|
+
interface OAuthDeviceFlowLogger {
|
|
786
|
+
info(data: Record<string, unknown>, message: string): void;
|
|
787
|
+
warn(data: Record<string, unknown>, message: string): void;
|
|
788
|
+
error(data: Record<string, unknown>, message: string): void;
|
|
789
|
+
debug(data: Record<string, unknown>, message: string): void;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* OAuth Device Code Flow implementation for GitHub
|
|
793
|
+
*/
|
|
794
|
+
declare class OAuthDeviceFlow {
|
|
795
|
+
private readonly clientId;
|
|
796
|
+
private readonly clientSecret?;
|
|
797
|
+
private readonly provider;
|
|
798
|
+
private readonly permissions;
|
|
799
|
+
private readonly promptEmitter?;
|
|
800
|
+
private readonly timeout;
|
|
801
|
+
private readonly logger?;
|
|
802
|
+
constructor(config: OAuthDeviceFlowConfig, logger?: OAuthDeviceFlowLogger);
|
|
803
|
+
/**
|
|
804
|
+
* Start the device code flow and wait for authorization
|
|
805
|
+
*/
|
|
806
|
+
authorize(): Promise<OAuthToken>;
|
|
807
|
+
/**
|
|
808
|
+
* Request a device code from GitHub
|
|
809
|
+
*/
|
|
810
|
+
requestDeviceCode(): Promise<DeviceCodeResponse>;
|
|
811
|
+
/**
|
|
812
|
+
* Poll for the access token until authorized or timeout
|
|
813
|
+
*/
|
|
814
|
+
pollForToken(deviceCode: DeviceCodeResponse): Promise<OAuthToken>;
|
|
815
|
+
/**
|
|
816
|
+
* Exchange device code for access token
|
|
817
|
+
*/
|
|
818
|
+
private exchangeDeviceCode;
|
|
819
|
+
/**
|
|
820
|
+
* Refresh an expired token
|
|
821
|
+
*/
|
|
822
|
+
refreshToken(refreshTokenValue: string): Promise<OAuthToken>;
|
|
823
|
+
/**
|
|
824
|
+
* Convert AgentPermissions to GitHub OAuth scopes
|
|
825
|
+
*/
|
|
826
|
+
private permissionsToScopes;
|
|
827
|
+
/**
|
|
828
|
+
* Print auth prompt to console (default behavior)
|
|
829
|
+
*/
|
|
830
|
+
private printAuthPrompt;
|
|
831
|
+
private sleep;
|
|
832
|
+
private log;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Token Store
|
|
837
|
+
*
|
|
838
|
+
* Securely stores and manages OAuth tokens with support for:
|
|
839
|
+
* - Expiry checking
|
|
840
|
+
* - Automatic refresh triggers
|
|
841
|
+
* - Multiple storage backends (file, memory, keychain)
|
|
842
|
+
*/
|
|
843
|
+
|
|
844
|
+
interface TokenStoreOptions {
|
|
845
|
+
/**
|
|
846
|
+
* Encryption key for file-based storage
|
|
847
|
+
* If not provided, tokens are stored in plaintext (not recommended for production)
|
|
848
|
+
*/
|
|
849
|
+
encryptionKey?: string;
|
|
850
|
+
/**
|
|
851
|
+
* Directory to store tokens (for FileTokenStore)
|
|
852
|
+
* Default: ~/.parallax/tokens
|
|
853
|
+
*/
|
|
854
|
+
directory?: string;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Token store interface
|
|
858
|
+
*/
|
|
859
|
+
declare abstract class TokenStore {
|
|
860
|
+
/**
|
|
861
|
+
* Save a token for a provider
|
|
862
|
+
*/
|
|
863
|
+
abstract save(provider: GitProvider, token: OAuthToken): Promise<void>;
|
|
864
|
+
/**
|
|
865
|
+
* Get a token for a provider
|
|
866
|
+
*/
|
|
867
|
+
abstract get(provider: GitProvider): Promise<OAuthToken | null>;
|
|
868
|
+
/**
|
|
869
|
+
* Clear a token for a provider (or all tokens)
|
|
870
|
+
*/
|
|
871
|
+
abstract clear(provider?: GitProvider): Promise<void>;
|
|
872
|
+
/**
|
|
873
|
+
* List all stored providers
|
|
874
|
+
*/
|
|
875
|
+
abstract list(): Promise<GitProvider[]>;
|
|
876
|
+
/**
|
|
877
|
+
* Check if a token is expired
|
|
878
|
+
*/
|
|
879
|
+
isExpired(token: OAuthToken): boolean;
|
|
880
|
+
/**
|
|
881
|
+
* Check if a token needs refresh (expired or close to expiry)
|
|
882
|
+
*/
|
|
883
|
+
needsRefresh(token: OAuthToken): boolean;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* In-memory token store (for testing and short-lived processes)
|
|
887
|
+
*/
|
|
888
|
+
declare class MemoryTokenStore extends TokenStore {
|
|
889
|
+
private tokens;
|
|
890
|
+
save(provider: GitProvider, token: OAuthToken): Promise<void>;
|
|
891
|
+
get(provider: GitProvider): Promise<OAuthToken | null>;
|
|
892
|
+
clear(provider?: GitProvider): Promise<void>;
|
|
893
|
+
list(): Promise<GitProvider[]>;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* File-based token store with optional encryption
|
|
897
|
+
*/
|
|
898
|
+
declare class FileTokenStore extends TokenStore {
|
|
899
|
+
private readonly directory;
|
|
900
|
+
private readonly encryptionKey?;
|
|
901
|
+
constructor(options?: TokenStoreOptions);
|
|
902
|
+
save(provider: GitProvider, token: OAuthToken): Promise<void>;
|
|
903
|
+
get(provider: GitProvider): Promise<OAuthToken | null>;
|
|
904
|
+
clear(provider?: GitProvider): Promise<void>;
|
|
905
|
+
list(): Promise<GitProvider[]>;
|
|
906
|
+
private getTokenPath;
|
|
907
|
+
private ensureDirectory;
|
|
908
|
+
private encrypt;
|
|
909
|
+
private decrypt;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Git Credential Service
|
|
914
|
+
*
|
|
915
|
+
* Manages credentials for private repository access.
|
|
916
|
+
* Supports GitHub App, OAuth device flow, deploy keys, and PATs.
|
|
917
|
+
*
|
|
918
|
+
* Credential priority:
|
|
919
|
+
* 1. User-provided (PAT, OAuth token, SSH)
|
|
920
|
+
* 2. Cached OAuth token (from TokenStore)
|
|
921
|
+
* 3. Provider adapter (GitHub App, etc.)
|
|
922
|
+
* 4. OAuth device flow (interactive)
|
|
923
|
+
*/
|
|
924
|
+
|
|
925
|
+
interface CredentialServiceLogger {
|
|
926
|
+
info(data: Record<string, unknown>, message: string): void;
|
|
927
|
+
warn(data: Record<string, unknown>, message: string): void;
|
|
928
|
+
error(data: Record<string, unknown>, message: string): void;
|
|
929
|
+
}
|
|
930
|
+
interface CredentialGrantStore {
|
|
931
|
+
create(grant: CredentialGrant & {
|
|
932
|
+
reason?: string;
|
|
933
|
+
}): Promise<void>;
|
|
934
|
+
findById(id: string): Promise<CredentialGrant | null>;
|
|
935
|
+
findByExecutionId(executionId: string): Promise<CredentialGrant[]>;
|
|
936
|
+
revoke(id: string): Promise<void>;
|
|
937
|
+
revokeForExecution(executionId: string): Promise<number>;
|
|
938
|
+
}
|
|
939
|
+
interface OAuthConfig {
|
|
940
|
+
/**
|
|
941
|
+
* OAuth Client ID (required for device flow)
|
|
942
|
+
*/
|
|
943
|
+
clientId: string;
|
|
944
|
+
/**
|
|
945
|
+
* OAuth Client Secret (optional for public clients)
|
|
946
|
+
*/
|
|
947
|
+
clientSecret?: string;
|
|
948
|
+
/**
|
|
949
|
+
* Default permissions to request
|
|
950
|
+
*/
|
|
951
|
+
permissions?: AgentPermissions;
|
|
952
|
+
/**
|
|
953
|
+
* Callback for auth prompts (for PTY integration)
|
|
954
|
+
*/
|
|
955
|
+
promptEmitter?: AuthPromptEmitter;
|
|
956
|
+
}
|
|
957
|
+
interface CredentialServiceOptions {
|
|
958
|
+
/**
|
|
959
|
+
* Default TTL for credentials in seconds
|
|
960
|
+
*/
|
|
961
|
+
defaultTtlSeconds?: number;
|
|
962
|
+
/**
|
|
963
|
+
* Maximum TTL allowed
|
|
964
|
+
*/
|
|
965
|
+
maxTtlSeconds?: number;
|
|
966
|
+
/**
|
|
967
|
+
* Provider adapters keyed by provider name
|
|
968
|
+
*/
|
|
969
|
+
providers?: Map<GitProvider, GitProviderAdapter>;
|
|
970
|
+
/**
|
|
971
|
+
* Optional persistent store for grants
|
|
972
|
+
*/
|
|
973
|
+
grantStore?: CredentialGrantStore;
|
|
974
|
+
/**
|
|
975
|
+
* Token store for cached OAuth tokens
|
|
976
|
+
* Default: MemoryTokenStore
|
|
977
|
+
*/
|
|
978
|
+
tokenStore?: TokenStore;
|
|
979
|
+
/**
|
|
980
|
+
* OAuth configuration for device flow authentication
|
|
981
|
+
* If provided, enables interactive OAuth as a fallback
|
|
982
|
+
*/
|
|
983
|
+
oauth?: OAuthConfig;
|
|
984
|
+
/**
|
|
985
|
+
* Optional logger
|
|
986
|
+
*/
|
|
987
|
+
logger?: CredentialServiceLogger;
|
|
988
|
+
}
|
|
989
|
+
declare class CredentialService {
|
|
990
|
+
private grants;
|
|
991
|
+
private readonly defaultTtl;
|
|
992
|
+
private readonly maxTtl;
|
|
993
|
+
private readonly providers;
|
|
994
|
+
private readonly grantStore?;
|
|
995
|
+
private readonly tokenStore;
|
|
996
|
+
private readonly oauthConfig?;
|
|
997
|
+
private readonly logger?;
|
|
998
|
+
constructor(options?: CredentialServiceOptions);
|
|
999
|
+
/**
|
|
1000
|
+
* Get the token store (for external access to cached tokens)
|
|
1001
|
+
*/
|
|
1002
|
+
getTokenStore(): TokenStore;
|
|
1003
|
+
/**
|
|
1004
|
+
* Register a provider adapter
|
|
1005
|
+
*/
|
|
1006
|
+
registerProvider(provider: GitProviderAdapter): void;
|
|
1007
|
+
/**
|
|
1008
|
+
* Get a provider adapter
|
|
1009
|
+
*/
|
|
1010
|
+
getProvider(name: GitProvider): GitProviderAdapter | undefined;
|
|
1011
|
+
/**
|
|
1012
|
+
* Request credentials for a repository
|
|
1013
|
+
*/
|
|
1014
|
+
getCredentials(request: GitCredentialRequest): Promise<GitCredential>;
|
|
1015
|
+
/**
|
|
1016
|
+
* Revoke a credential grant
|
|
1017
|
+
*/
|
|
1018
|
+
revokeCredential(grantId: string): Promise<void>;
|
|
1019
|
+
/**
|
|
1020
|
+
* Revoke all credentials for an execution
|
|
1021
|
+
*/
|
|
1022
|
+
revokeForExecution(executionId: string): Promise<number>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Check if a credential is valid
|
|
1025
|
+
*/
|
|
1026
|
+
isValid(grantId: string): boolean;
|
|
1027
|
+
/**
|
|
1028
|
+
* Get grant info for audit
|
|
1029
|
+
*/
|
|
1030
|
+
getGrant(grantId: string): Promise<CredentialGrant | null>;
|
|
1031
|
+
/**
|
|
1032
|
+
* List all grants for an execution
|
|
1033
|
+
*/
|
|
1034
|
+
getGrantsForExecution(executionId: string): Promise<CredentialGrant[]>;
|
|
1035
|
+
private detectProvider;
|
|
1036
|
+
/**
|
|
1037
|
+
* Create a GitCredential from user-provided credentials (PAT or OAuth token)
|
|
1038
|
+
*/
|
|
1039
|
+
private createUserProvidedCredential;
|
|
1040
|
+
/**
|
|
1041
|
+
* Check for a cached OAuth token and create credential from it
|
|
1042
|
+
*/
|
|
1043
|
+
private getCachedOAuthCredential;
|
|
1044
|
+
/**
|
|
1045
|
+
* Initiate interactive OAuth device flow
|
|
1046
|
+
*/
|
|
1047
|
+
private getOAuthCredentialViaDeviceFlow;
|
|
1048
|
+
/**
|
|
1049
|
+
* Refresh an OAuth token
|
|
1050
|
+
*/
|
|
1051
|
+
private refreshOAuthToken;
|
|
1052
|
+
/**
|
|
1053
|
+
* Create a GitCredential from an OAuthToken
|
|
1054
|
+
*/
|
|
1055
|
+
private createOAuthCredential;
|
|
1056
|
+
private log;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Workspace Service
|
|
1061
|
+
*
|
|
1062
|
+
* Provisions and manages git workspaces for agent tasks.
|
|
1063
|
+
* Handles cloning, branching, and PR creation.
|
|
1064
|
+
*/
|
|
1065
|
+
|
|
1066
|
+
interface WorkspaceServiceLogger {
|
|
1067
|
+
info(data: Record<string, unknown>, message: string): void;
|
|
1068
|
+
warn(data: Record<string, unknown>, message: string): void;
|
|
1069
|
+
error(data: Record<string, unknown>, message: string): void;
|
|
1070
|
+
debug(data: Record<string, unknown>, message: string): void;
|
|
1071
|
+
}
|
|
1072
|
+
interface WorkspaceServiceOptions {
|
|
1073
|
+
/**
|
|
1074
|
+
* Configuration
|
|
1075
|
+
*/
|
|
1076
|
+
config: WorkspaceServiceConfig;
|
|
1077
|
+
/**
|
|
1078
|
+
* Credential service for managing git credentials
|
|
1079
|
+
*/
|
|
1080
|
+
credentialService: CredentialService;
|
|
1081
|
+
/**
|
|
1082
|
+
* Optional logger
|
|
1083
|
+
*/
|
|
1084
|
+
logger?: WorkspaceServiceLogger;
|
|
1085
|
+
}
|
|
1086
|
+
declare class WorkspaceService {
|
|
1087
|
+
private workspaces;
|
|
1088
|
+
private readonly baseDir;
|
|
1089
|
+
private readonly branchPrefix;
|
|
1090
|
+
private readonly credentialService;
|
|
1091
|
+
private readonly logger?;
|
|
1092
|
+
private readonly eventHandlers;
|
|
1093
|
+
constructor(options: WorkspaceServiceOptions);
|
|
1094
|
+
/**
|
|
1095
|
+
* Initialize the workspace service
|
|
1096
|
+
*/
|
|
1097
|
+
initialize(): Promise<void>;
|
|
1098
|
+
/**
|
|
1099
|
+
* Register an event handler
|
|
1100
|
+
*/
|
|
1101
|
+
onEvent(handler: WorkspaceEventHandler): () => void;
|
|
1102
|
+
/**
|
|
1103
|
+
* Provision a new workspace for a task
|
|
1104
|
+
*/
|
|
1105
|
+
provision(config: WorkspaceConfig): Promise<Workspace>;
|
|
1106
|
+
/**
|
|
1107
|
+
* Finalize a workspace (push, create PR, cleanup)
|
|
1108
|
+
*/
|
|
1109
|
+
finalize(workspaceId: string, options: WorkspaceFinalization): Promise<PullRequestInfo | void>;
|
|
1110
|
+
/**
|
|
1111
|
+
* Get a workspace by ID
|
|
1112
|
+
*/
|
|
1113
|
+
get(workspaceId: string): Workspace | null;
|
|
1114
|
+
/**
|
|
1115
|
+
* Get all workspaces for an execution
|
|
1116
|
+
*/
|
|
1117
|
+
getForExecution(executionId: string): Workspace[];
|
|
1118
|
+
/**
|
|
1119
|
+
* Clean up a workspace
|
|
1120
|
+
*/
|
|
1121
|
+
cleanup(workspaceId: string): Promise<void>;
|
|
1122
|
+
/**
|
|
1123
|
+
* Clean up all workspaces for an execution
|
|
1124
|
+
*/
|
|
1125
|
+
cleanupForExecution(executionId: string): Promise<void>;
|
|
1126
|
+
private cloneRepo;
|
|
1127
|
+
private createBranch;
|
|
1128
|
+
private configureGit;
|
|
1129
|
+
private pushBranch;
|
|
1130
|
+
private createPullRequest;
|
|
1131
|
+
private parseRepo;
|
|
1132
|
+
private buildAuthenticatedUrl;
|
|
1133
|
+
private execInDir;
|
|
1134
|
+
private log;
|
|
1135
|
+
private emitEvent;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* GitHub Provider
|
|
1140
|
+
*
|
|
1141
|
+
* Handles GitHub App authentication and API operations.
|
|
1142
|
+
* Requires @octokit/rest and @octokit/auth-app as peer dependencies.
|
|
1143
|
+
*/
|
|
1144
|
+
|
|
1145
|
+
interface GitHubProviderConfig {
|
|
1146
|
+
/**
|
|
1147
|
+
* GitHub App ID
|
|
1148
|
+
*/
|
|
1149
|
+
appId: string;
|
|
1150
|
+
/**
|
|
1151
|
+
* GitHub App private key (PEM format)
|
|
1152
|
+
*/
|
|
1153
|
+
privateKey: string;
|
|
1154
|
+
/**
|
|
1155
|
+
* Webhook secret for verifying webhooks
|
|
1156
|
+
*/
|
|
1157
|
+
webhookSecret?: string;
|
|
1158
|
+
/**
|
|
1159
|
+
* GitHub API base URL (for GitHub Enterprise)
|
|
1160
|
+
*/
|
|
1161
|
+
baseUrl?: string;
|
|
1162
|
+
}
|
|
1163
|
+
interface GitHubProviderLogger {
|
|
1164
|
+
info(data: Record<string, unknown>, message: string): void;
|
|
1165
|
+
warn(data: Record<string, unknown>, message: string): void;
|
|
1166
|
+
error(data: Record<string, unknown>, message: string): void;
|
|
1167
|
+
debug(data: Record<string, unknown>, message: string): void;
|
|
1168
|
+
}
|
|
1169
|
+
declare class GitHubProvider implements GitProviderAdapter {
|
|
1170
|
+
private readonly config;
|
|
1171
|
+
private readonly logger?;
|
|
1172
|
+
readonly name: "github";
|
|
1173
|
+
private appOctokit;
|
|
1174
|
+
private installations;
|
|
1175
|
+
private installationOctokits;
|
|
1176
|
+
private initialized;
|
|
1177
|
+
constructor(config: GitHubProviderConfig, logger?: GitHubProviderLogger | undefined);
|
|
1178
|
+
/**
|
|
1179
|
+
* Initialize provider - fetch all installations
|
|
1180
|
+
*/
|
|
1181
|
+
initialize(): Promise<void>;
|
|
1182
|
+
/**
|
|
1183
|
+
* Register an installation (called on webhook or init)
|
|
1184
|
+
*/
|
|
1185
|
+
registerInstallation(installationId: number): Promise<GitHubAppInstallation>;
|
|
1186
|
+
/**
|
|
1187
|
+
* Get installation for a repository
|
|
1188
|
+
*/
|
|
1189
|
+
getInstallationForRepo(owner: string, repo: string): GitHubAppInstallation | null;
|
|
1190
|
+
/**
|
|
1191
|
+
* Get credentials for a repository (implements GitProviderAdapter)
|
|
1192
|
+
*/
|
|
1193
|
+
getCredentials(request: GitCredentialRequest): Promise<GitCredential>;
|
|
1194
|
+
/**
|
|
1195
|
+
* Get credentials for a repository by owner/repo
|
|
1196
|
+
*/
|
|
1197
|
+
getCredentialsForRepo(owner: string, repo: string, access: 'read' | 'write', ttlSeconds?: number): Promise<GitCredential>;
|
|
1198
|
+
/**
|
|
1199
|
+
* Revoke a credential (no-op for GitHub App tokens - they expire automatically)
|
|
1200
|
+
*/
|
|
1201
|
+
revokeCredential(_credentialId: string): Promise<void>;
|
|
1202
|
+
/**
|
|
1203
|
+
* Create a pull request (implements GitProviderAdapter)
|
|
1204
|
+
*/
|
|
1205
|
+
createPullRequest(options: {
|
|
1206
|
+
repo: string;
|
|
1207
|
+
sourceBranch: string;
|
|
1208
|
+
targetBranch: string;
|
|
1209
|
+
title: string;
|
|
1210
|
+
body: string;
|
|
1211
|
+
draft?: boolean;
|
|
1212
|
+
labels?: string[];
|
|
1213
|
+
reviewers?: string[];
|
|
1214
|
+
credential: GitCredential;
|
|
1215
|
+
}): Promise<PullRequestInfo>;
|
|
1216
|
+
/**
|
|
1217
|
+
* Create a pull request by owner/repo
|
|
1218
|
+
*/
|
|
1219
|
+
createPullRequestForRepo(owner: string, repo: string, options: {
|
|
1220
|
+
title: string;
|
|
1221
|
+
body: string;
|
|
1222
|
+
head: string;
|
|
1223
|
+
base: string;
|
|
1224
|
+
draft?: boolean;
|
|
1225
|
+
labels?: string[];
|
|
1226
|
+
reviewers?: string[];
|
|
1227
|
+
}): Promise<PullRequestInfo>;
|
|
1228
|
+
/**
|
|
1229
|
+
* Check if a branch exists (implements GitProviderAdapter)
|
|
1230
|
+
*/
|
|
1231
|
+
branchExists(repo: string, branch: string, _credential: GitCredential): Promise<boolean>;
|
|
1232
|
+
/**
|
|
1233
|
+
* Get the default branch for a repository (implements GitProviderAdapter)
|
|
1234
|
+
*/
|
|
1235
|
+
getDefaultBranch(repo: string, _credential: GitCredential): Promise<string>;
|
|
1236
|
+
/**
|
|
1237
|
+
* Get pull request status
|
|
1238
|
+
*/
|
|
1239
|
+
getPullRequest(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo>;
|
|
1240
|
+
/**
|
|
1241
|
+
* Delete a branch
|
|
1242
|
+
*/
|
|
1243
|
+
deleteBranch(owner: string, repo: string, branch: string): Promise<void>;
|
|
1244
|
+
/**
|
|
1245
|
+
* List all managed branches for a repo
|
|
1246
|
+
*/
|
|
1247
|
+
listManagedBranches(owner: string, repo: string, prefix?: string): Promise<string[]>;
|
|
1248
|
+
/**
|
|
1249
|
+
* Create an issue
|
|
1250
|
+
*/
|
|
1251
|
+
createIssue(owner: string, repo: string, options: CreateIssueOptions): Promise<IssueInfo>;
|
|
1252
|
+
/**
|
|
1253
|
+
* Get an issue by number
|
|
1254
|
+
*/
|
|
1255
|
+
getIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1256
|
+
/**
|
|
1257
|
+
* List issues with optional filters
|
|
1258
|
+
*/
|
|
1259
|
+
listIssues(owner: string, repo: string, options?: {
|
|
1260
|
+
state?: IssueState | 'all';
|
|
1261
|
+
labels?: string[];
|
|
1262
|
+
assignee?: string;
|
|
1263
|
+
since?: Date;
|
|
1264
|
+
}): Promise<IssueInfo[]>;
|
|
1265
|
+
/**
|
|
1266
|
+
* Update an issue (labels, state, assignees, etc.)
|
|
1267
|
+
*/
|
|
1268
|
+
updateIssue(owner: string, repo: string, issueNumber: number, options: {
|
|
1269
|
+
title?: string;
|
|
1270
|
+
body?: string;
|
|
1271
|
+
state?: IssueState;
|
|
1272
|
+
labels?: string[];
|
|
1273
|
+
assignees?: string[];
|
|
1274
|
+
}): Promise<IssueInfo>;
|
|
1275
|
+
/**
|
|
1276
|
+
* Add labels to an issue
|
|
1277
|
+
*/
|
|
1278
|
+
addLabels(owner: string, repo: string, issueNumber: number, labels: string[]): Promise<void>;
|
|
1279
|
+
/**
|
|
1280
|
+
* Remove a label from an issue
|
|
1281
|
+
*/
|
|
1282
|
+
removeLabel(owner: string, repo: string, issueNumber: number, label: string): Promise<void>;
|
|
1283
|
+
/**
|
|
1284
|
+
* Add a comment to an issue
|
|
1285
|
+
*/
|
|
1286
|
+
addComment(owner: string, repo: string, issueNumber: number, options: IssueCommentOptions): Promise<IssueComment>;
|
|
1287
|
+
/**
|
|
1288
|
+
* List comments on an issue
|
|
1289
|
+
*/
|
|
1290
|
+
listComments(owner: string, repo: string, issueNumber: number): Promise<IssueComment[]>;
|
|
1291
|
+
/**
|
|
1292
|
+
* Close an issue
|
|
1293
|
+
*/
|
|
1294
|
+
closeIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1295
|
+
/**
|
|
1296
|
+
* Reopen an issue
|
|
1297
|
+
*/
|
|
1298
|
+
reopenIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1299
|
+
private getInstallationOctokit;
|
|
1300
|
+
private parseRepo;
|
|
1301
|
+
private log;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* GitHub PAT Client
|
|
1306
|
+
*
|
|
1307
|
+
* Simple GitHub API client using a Personal Access Token.
|
|
1308
|
+
* Useful for testing and simple integrations without GitHub App setup.
|
|
1309
|
+
*/
|
|
1310
|
+
|
|
1311
|
+
interface GitHubPatClientOptions {
|
|
1312
|
+
/**
|
|
1313
|
+
* Personal Access Token
|
|
1314
|
+
*/
|
|
1315
|
+
token: string;
|
|
1316
|
+
/**
|
|
1317
|
+
* GitHub API base URL (for GitHub Enterprise)
|
|
1318
|
+
*/
|
|
1319
|
+
baseUrl?: string;
|
|
1320
|
+
}
|
|
1321
|
+
interface GitHubPatClientLogger {
|
|
1322
|
+
info(data: Record<string, unknown>, message: string): void;
|
|
1323
|
+
warn(data: Record<string, unknown>, message: string): void;
|
|
1324
|
+
error(data: Record<string, unknown>, message: string): void;
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* Simple GitHub client using a Personal Access Token.
|
|
1328
|
+
* Provides PR and Issue management without GitHub App complexity.
|
|
1329
|
+
*/
|
|
1330
|
+
declare class GitHubPatClient {
|
|
1331
|
+
private octokit;
|
|
1332
|
+
private readonly logger?;
|
|
1333
|
+
constructor(options: GitHubPatClientOptions, logger?: GitHubPatClientLogger);
|
|
1334
|
+
/**
|
|
1335
|
+
* Create a pull request
|
|
1336
|
+
*/
|
|
1337
|
+
createPullRequest(owner: string, repo: string, options: {
|
|
1338
|
+
title: string;
|
|
1339
|
+
body: string;
|
|
1340
|
+
head: string;
|
|
1341
|
+
base: string;
|
|
1342
|
+
draft?: boolean;
|
|
1343
|
+
labels?: string[];
|
|
1344
|
+
reviewers?: string[];
|
|
1345
|
+
}): Promise<PullRequestInfo>;
|
|
1346
|
+
/**
|
|
1347
|
+
* Get a pull request
|
|
1348
|
+
*/
|
|
1349
|
+
getPullRequest(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo>;
|
|
1350
|
+
/**
|
|
1351
|
+
* Create an issue
|
|
1352
|
+
*/
|
|
1353
|
+
createIssue(owner: string, repo: string, options: CreateIssueOptions): Promise<IssueInfo>;
|
|
1354
|
+
/**
|
|
1355
|
+
* Get an issue
|
|
1356
|
+
*/
|
|
1357
|
+
getIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1358
|
+
/**
|
|
1359
|
+
* List issues
|
|
1360
|
+
*/
|
|
1361
|
+
listIssues(owner: string, repo: string, options?: {
|
|
1362
|
+
state?: IssueState | 'all';
|
|
1363
|
+
labels?: string[];
|
|
1364
|
+
assignee?: string;
|
|
1365
|
+
}): Promise<IssueInfo[]>;
|
|
1366
|
+
/**
|
|
1367
|
+
* Update an issue
|
|
1368
|
+
*/
|
|
1369
|
+
updateIssue(owner: string, repo: string, issueNumber: number, options: {
|
|
1370
|
+
title?: string;
|
|
1371
|
+
body?: string;
|
|
1372
|
+
state?: IssueState;
|
|
1373
|
+
labels?: string[];
|
|
1374
|
+
assignees?: string[];
|
|
1375
|
+
}): Promise<IssueInfo>;
|
|
1376
|
+
/**
|
|
1377
|
+
* Add labels to an issue
|
|
1378
|
+
*/
|
|
1379
|
+
addLabels(owner: string, repo: string, issueNumber: number, labels: string[]): Promise<void>;
|
|
1380
|
+
/**
|
|
1381
|
+
* Remove a label from an issue
|
|
1382
|
+
*/
|
|
1383
|
+
removeLabel(owner: string, repo: string, issueNumber: number, label: string): Promise<void>;
|
|
1384
|
+
/**
|
|
1385
|
+
* Add a comment to an issue or PR
|
|
1386
|
+
*/
|
|
1387
|
+
addComment(owner: string, repo: string, issueNumber: number, options: IssueCommentOptions): Promise<IssueComment>;
|
|
1388
|
+
/**
|
|
1389
|
+
* List comments on an issue or PR
|
|
1390
|
+
*/
|
|
1391
|
+
listComments(owner: string, repo: string, issueNumber: number): Promise<IssueComment[]>;
|
|
1392
|
+
/**
|
|
1393
|
+
* Close an issue
|
|
1394
|
+
*/
|
|
1395
|
+
closeIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1396
|
+
/**
|
|
1397
|
+
* Reopen an issue
|
|
1398
|
+
*/
|
|
1399
|
+
reopenIssue(owner: string, repo: string, issueNumber: number): Promise<IssueInfo>;
|
|
1400
|
+
/**
|
|
1401
|
+
* Delete a branch
|
|
1402
|
+
*/
|
|
1403
|
+
deleteBranch(owner: string, repo: string, branch: string): Promise<void>;
|
|
1404
|
+
/**
|
|
1405
|
+
* Check if a branch exists
|
|
1406
|
+
*/
|
|
1407
|
+
branchExists(owner: string, repo: string, branch: string): Promise<boolean>;
|
|
1408
|
+
private mapIssue;
|
|
1409
|
+
private log;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* Branch Naming Service
|
|
1414
|
+
*
|
|
1415
|
+
* Generates and parses managed branch names.
|
|
1416
|
+
* Format: {prefix}/{execution-id}/{role}-{slug}
|
|
1417
|
+
*/
|
|
1418
|
+
|
|
1419
|
+
declare const DEFAULT_BRANCH_PREFIX = "parallax";
|
|
1420
|
+
interface BranchNamingOptions {
|
|
1421
|
+
/**
|
|
1422
|
+
* Maximum length for the slug portion
|
|
1423
|
+
*/
|
|
1424
|
+
maxSlugLength?: number;
|
|
1425
|
+
/**
|
|
1426
|
+
* Custom prefix (defaults to 'parallax')
|
|
1427
|
+
*/
|
|
1428
|
+
prefix?: string;
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Generate a branch name from configuration
|
|
1432
|
+
*/
|
|
1433
|
+
declare function generateBranchName(config: BranchConfig, options?: BranchNamingOptions): string;
|
|
1434
|
+
/**
|
|
1435
|
+
* Parse a branch name into its components
|
|
1436
|
+
*/
|
|
1437
|
+
declare function parseBranchName(branchName: string, options?: BranchNamingOptions): {
|
|
1438
|
+
executionId: string;
|
|
1439
|
+
role: string;
|
|
1440
|
+
slug?: string;
|
|
1441
|
+
} | null;
|
|
1442
|
+
/**
|
|
1443
|
+
* Check if a branch name is a managed branch
|
|
1444
|
+
*/
|
|
1445
|
+
declare function isManagedBranch(branchName: string, options?: BranchNamingOptions): boolean;
|
|
1446
|
+
/**
|
|
1447
|
+
* Get all branches for a specific execution
|
|
1448
|
+
*/
|
|
1449
|
+
declare function filterBranchesByExecution(branches: string[], executionId: string, options?: BranchNamingOptions): string[];
|
|
1450
|
+
/**
|
|
1451
|
+
* Generate branch info object
|
|
1452
|
+
*/
|
|
1453
|
+
declare function createBranchInfo(config: BranchConfig, options?: BranchNamingOptions): BranchInfo;
|
|
1454
|
+
/**
|
|
1455
|
+
* Generate a slug from a task description
|
|
1456
|
+
*/
|
|
1457
|
+
declare function generateSlug(description: string, maxLength?: number): string;
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Git Credential Helper
|
|
1461
|
+
*
|
|
1462
|
+
* This module provides a Git credential helper that integrates with the
|
|
1463
|
+
* workspace service. It can be used in two modes:
|
|
1464
|
+
*
|
|
1465
|
+
* 1. Script mode: Run as a standalone script that Git calls
|
|
1466
|
+
* 2. Embedded mode: Used within the workspace service to configure git
|
|
1467
|
+
*
|
|
1468
|
+
* Git credential helpers receive input on stdin in the format:
|
|
1469
|
+
* protocol=https
|
|
1470
|
+
* host=github.com
|
|
1471
|
+
* path=owner/repo
|
|
1472
|
+
*
|
|
1473
|
+
* And respond with:
|
|
1474
|
+
* username=x-access-token
|
|
1475
|
+
* password=<token>
|
|
1476
|
+
*/
|
|
1477
|
+
/**
|
|
1478
|
+
* Credential context stored per-workspace
|
|
1479
|
+
* This is written to a file that the helper reads
|
|
1480
|
+
*/
|
|
1481
|
+
interface CredentialHelperContext {
|
|
1482
|
+
workspaceId: string;
|
|
1483
|
+
executionId: string;
|
|
1484
|
+
repo: string;
|
|
1485
|
+
token: string;
|
|
1486
|
+
expiresAt: string;
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Create the credential helper script content (Node.js version)
|
|
1490
|
+
*/
|
|
1491
|
+
declare function createNodeCredentialHelperScript(contextFilePath: string): string;
|
|
1492
|
+
/**
|
|
1493
|
+
* Create a shell-based credential helper script (more portable)
|
|
1494
|
+
*/
|
|
1495
|
+
declare function createShellCredentialHelperScript(contextFilePath: string): string;
|
|
1496
|
+
/**
|
|
1497
|
+
* Configure git to use the credential helper in a workspace
|
|
1498
|
+
*/
|
|
1499
|
+
declare function configureCredentialHelper(workspacePath: string, context: CredentialHelperContext): Promise<string>;
|
|
1500
|
+
/**
|
|
1501
|
+
* Update credentials for an existing workspace
|
|
1502
|
+
* Called when credentials are refreshed
|
|
1503
|
+
*/
|
|
1504
|
+
declare function updateCredentials(workspacePath: string, newToken: string, newExpiresAt: string): Promise<void>;
|
|
1505
|
+
/**
|
|
1506
|
+
* Clean up credential files from a workspace
|
|
1507
|
+
*/
|
|
1508
|
+
declare function cleanupCredentialFiles(workspacePath: string): Promise<void>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Get the git config commands to configure the credential helper
|
|
1511
|
+
*/
|
|
1512
|
+
declare function getGitCredentialConfig(helperScriptPath: string): string[];
|
|
1513
|
+
/**
|
|
1514
|
+
* Output credentials to stdout in Git format
|
|
1515
|
+
*/
|
|
1516
|
+
declare function outputCredentials(username: string, password: string): void;
|
|
1517
|
+
|
|
1518
|
+
export { type AgentPermissions, type AuthPrompt, type AuthPromptEmitter, type AuthResult, type BranchConfig, type BranchInfo, type BranchNamingOptions, type BranchStrategy, type CreateIssueOptions, type CredentialContext, type CredentialGrant, type CredentialGrantStore, type CredentialHelperContext, CredentialService, type CredentialServiceConfig, type CredentialServiceLogger, type CredentialServiceOptions, type CredentialType, DEFAULT_AGENT_PERMISSIONS, DEFAULT_BRANCH_PREFIX, type DeviceCodeResponse, FileTokenStore, type GitCredential, type GitCredentialRequest, type GitHubAppConfig, type GitHubAppInstallation, GitHubPatClient, type GitHubPatClientLogger, type GitHubPatClientOptions, GitHubProvider, type GitHubProviderConfig, type GitHubProviderLogger, type GitProvider, type GitProviderAdapter, type IssueComment, type IssueCommentOptions, type IssueInfo, type IssueState, MemoryTokenStore, OAuthDeviceFlow, type OAuthDeviceFlowConfig, type OAuthDeviceFlowLogger, type OAuthToken, type PermissionLevel, type PullRequestInfo, READONLY_AGENT_PERMISSIONS, type RepositoryScope, type SshCredentials, type TokenCredentials, TokenStore, type TokenStoreOptions, type UserProvidedCredentials, type Workspace, type WorkspaceConfig, type WorkspaceEvent, type WorkspaceEventHandler, type WorkspaceEventType, type WorkspaceFinalization, WorkspaceService, type WorkspaceServiceConfig, type WorkspaceServiceLogger, type WorkspaceServiceOptions, type WorkspaceStatus, cleanupCredentialFiles, configureCredentialHelper, createBranchInfo, createNodeCredentialHelperScript, createShellCredentialHelperScript, filterBranchesByExecution, generateBranchName, generateSlug, getGitCredentialConfig, isManagedBranch, outputCredentials, parseBranchName, updateCredentials };
|