@fractary/faber-cli 1.5.47 → 1.5.49
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/LICENSE +190 -21
- package/README.md +0 -0
- package/dist/__mocks__/chalk.d.ts +0 -0
- package/dist/__mocks__/chalk.d.ts.map +0 -0
- package/dist/__mocks__/chalk.js +0 -0
- package/dist/commands/auth/index.d.ts +0 -0
- package/dist/commands/auth/index.d.ts.map +0 -0
- package/dist/commands/auth/index.js +0 -0
- package/dist/commands/changelog/index.d.ts +0 -0
- package/dist/commands/changelog/index.d.ts.map +0 -0
- package/dist/commands/changelog/index.js +0 -0
- package/dist/commands/config.d.ts +0 -0
- package/dist/commands/config.d.ts.map +0 -0
- package/dist/commands/config.js +0 -0
- package/dist/commands/logs/index.d.ts +0 -0
- package/dist/commands/logs/index.d.ts.map +0 -0
- package/dist/commands/logs/index.js +0 -0
- package/dist/commands/migrate.d.ts +0 -0
- package/dist/commands/migrate.d.ts.map +0 -0
- package/dist/commands/migrate.js +0 -0
- package/dist/commands/plan/index.d.ts +0 -0
- package/dist/commands/plan/index.d.ts.map +0 -0
- package/dist/commands/plan/index.js +0 -0
- package/dist/commands/repo/index.d.ts +0 -0
- package/dist/commands/repo/index.d.ts.map +0 -0
- package/dist/commands/repo/index.js +0 -0
- package/dist/commands/runs.d.ts +0 -0
- package/dist/commands/runs.d.ts.map +0 -0
- package/dist/commands/runs.js +0 -0
- package/dist/commands/session.d.ts +0 -0
- package/dist/commands/session.d.ts.map +0 -0
- package/dist/commands/session.js +0 -0
- package/dist/commands/work/index.d.ts +0 -0
- package/dist/commands/work/index.d.ts.map +0 -0
- package/dist/commands/work/index.js +0 -0
- package/dist/commands/workflow/index.d.ts +0 -0
- package/dist/commands/workflow/index.d.ts.map +0 -0
- package/dist/commands/workflow/index.js +0 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.d.ts.map +0 -0
- package/dist/index.js +1 -1
- package/dist/lib/anthropic-client.d.ts +0 -0
- package/dist/lib/anthropic-client.d.ts.map +0 -0
- package/dist/lib/anthropic-client.js +0 -0
- package/dist/lib/config.d.ts +0 -0
- package/dist/lib/config.d.ts.map +0 -0
- package/dist/lib/config.js +0 -0
- package/dist/lib/github-app-setup.d.ts +0 -0
- package/dist/lib/github-app-setup.d.ts.map +0 -0
- package/dist/lib/github-app-setup.js +0 -0
- package/dist/lib/repo-client.d.ts +0 -0
- package/dist/lib/repo-client.d.ts.map +0 -0
- package/dist/lib/repo-client.js +0 -0
- package/dist/lib/sdk-type-adapter.d.ts +0 -0
- package/dist/lib/sdk-type-adapter.d.ts.map +0 -0
- package/dist/lib/sdk-type-adapter.js +0 -0
- package/dist/lib/yaml-config.d.ts +0 -0
- package/dist/lib/yaml-config.d.ts.map +0 -0
- package/dist/lib/yaml-config.js +0 -0
- package/dist/types/config.d.ts +0 -0
- package/dist/types/config.d.ts.map +0 -0
- package/dist/types/config.js +0 -0
- package/dist/utils/errors.d.ts +0 -0
- package/dist/utils/errors.d.ts.map +0 -0
- package/dist/utils/errors.js +0 -0
- package/dist/utils/github-manifest.d.ts +0 -0
- package/dist/utils/github-manifest.d.ts.map +0 -0
- package/dist/utils/github-manifest.js +0 -0
- package/dist/utils/labels.d.ts +0 -0
- package/dist/utils/labels.d.ts.map +0 -0
- package/dist/utils/labels.js +0 -0
- package/dist/utils/output.d.ts +0 -0
- package/dist/utils/output.d.ts.map +0 -0
- package/dist/utils/output.js +0 -0
- package/dist/utils/prompt.d.ts +0 -0
- package/dist/utils/prompt.d.ts.map +0 -0
- package/dist/utils/prompt.js +0 -0
- package/dist/utils/sorting.d.ts +0 -0
- package/dist/utils/sorting.d.ts.map +0 -0
- package/dist/utils/sorting.js +0 -0
- package/dist/utils/validation.d.ts +0 -0
- package/dist/utils/validation.d.ts.map +0 -0
- package/dist/utils/validation.js +0 -0
- package/package.json +2 -2
- package/schemas/plan.schema.json +0 -0
- package/dist/commands/init.d.ts +0 -9
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -161
- package/dist/commands/spec/index.d.ts +0 -11
- package/dist/commands/spec/index.d.ts.map +0 -1
- package/dist/commands/spec/index.js +0 -280
- package/dist/lib/github-app-auth.d.ts +0 -122
- package/dist/lib/github-app-auth.d.ts.map +0 -1
- package/dist/lib/github-app-auth.js +0 -300
- package/dist/lib/sdk-config-adapter.d.ts +0 -76
- package/dist/lib/sdk-config-adapter.d.ts.map +0 -1
- package/dist/lib/sdk-config-adapter.js +0 -207
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub App Authentication Module
|
|
3
|
-
*
|
|
4
|
-
* Provides JWT generation, installation token exchange, and token caching
|
|
5
|
-
* for GitHub App authentication in FABER CLI.
|
|
6
|
-
*/
|
|
7
|
-
import jwt from 'jsonwebtoken';
|
|
8
|
-
import fs from 'fs/promises';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import os from 'os';
|
|
11
|
-
/**
|
|
12
|
-
* Private Key Loader
|
|
13
|
-
*
|
|
14
|
-
* Loads private keys from file path or environment variable
|
|
15
|
-
*/
|
|
16
|
-
export class PrivateKeyLoader {
|
|
17
|
-
/**
|
|
18
|
-
* Load private key from configured sources.
|
|
19
|
-
* Priority: env var > file path
|
|
20
|
-
*
|
|
21
|
-
* @param config - GitHub App configuration
|
|
22
|
-
* @returns The private key content
|
|
23
|
-
* @throws Error if private key cannot be loaded
|
|
24
|
-
*/
|
|
25
|
-
static async load(config) {
|
|
26
|
-
// Try environment variable first (priority)
|
|
27
|
-
if (config.private_key_env_var) {
|
|
28
|
-
const envValue = process.env[config.private_key_env_var];
|
|
29
|
-
if (envValue) {
|
|
30
|
-
try {
|
|
31
|
-
// Decode base64-encoded key
|
|
32
|
-
const decoded = Buffer.from(envValue, 'base64').toString('utf-8');
|
|
33
|
-
if (PrivateKeyLoader.validate(decoded)) {
|
|
34
|
-
return decoded;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// Invalid base64, fall through to file path
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// Try file path
|
|
43
|
-
if (config.private_key_path) {
|
|
44
|
-
try {
|
|
45
|
-
// Expand ~ to home directory
|
|
46
|
-
const expandedPath = config.private_key_path.startsWith('~')
|
|
47
|
-
? config.private_key_path.replace('~', os.homedir())
|
|
48
|
-
: config.private_key_path;
|
|
49
|
-
const resolvedPath = path.resolve(expandedPath);
|
|
50
|
-
const key = await fs.readFile(resolvedPath, 'utf-8');
|
|
51
|
-
if (PrivateKeyLoader.validate(key)) {
|
|
52
|
-
return key;
|
|
53
|
-
}
|
|
54
|
-
throw new Error('Invalid private key format. Expected PEM-encoded RSA private key');
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
if (error instanceof Error && error.message.includes('ENOENT')) {
|
|
58
|
-
throw new Error(`GitHub App private key not found at '${config.private_key_path}'. ` +
|
|
59
|
-
`Check 'private_key_path' in config or set ${config.private_key_env_var || 'GITHUB_APP_PRIVATE_KEY'} env var`);
|
|
60
|
-
}
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw new Error('GitHub App private key not found. ' +
|
|
65
|
-
"Configure 'private_key_path' in .fractary/config.yaml or set GITHUB_APP_PRIVATE_KEY env var");
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Validate private key format.
|
|
69
|
-
*
|
|
70
|
-
* @param key - The private key content
|
|
71
|
-
* @returns true if valid PEM format
|
|
72
|
-
*/
|
|
73
|
-
static validate(key) {
|
|
74
|
-
// Check for PEM format (RSA or PKCS#8)
|
|
75
|
-
const trimmed = key.trim();
|
|
76
|
-
return ((trimmed.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
|
|
77
|
-
trimmed.endsWith('-----END RSA PRIVATE KEY-----')) ||
|
|
78
|
-
(trimmed.startsWith('-----BEGIN PRIVATE KEY-----') &&
|
|
79
|
-
trimmed.endsWith('-----END PRIVATE KEY-----')));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* GitHub App Authentication
|
|
84
|
-
*
|
|
85
|
-
* Handles JWT generation, installation token exchange, and caching
|
|
86
|
-
*/
|
|
87
|
-
export class GitHubAppAuth {
|
|
88
|
-
constructor(config) {
|
|
89
|
-
this.cache = new Map();
|
|
90
|
-
this.refreshPromise = null;
|
|
91
|
-
this.config = config;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get a valid installation token.
|
|
95
|
-
* Returns cached token if still valid, otherwise generates new one.
|
|
96
|
-
*
|
|
97
|
-
* @returns Installation access token
|
|
98
|
-
*/
|
|
99
|
-
async getToken() {
|
|
100
|
-
const cacheKey = this.config.installation_id;
|
|
101
|
-
const cached = this.cache.get(cacheKey);
|
|
102
|
-
if (cached && !this.isExpired(cached) && !this.isExpiringSoon(cached)) {
|
|
103
|
-
return cached.token;
|
|
104
|
-
}
|
|
105
|
-
// If token is expiring soon but still valid, trigger background refresh
|
|
106
|
-
if (cached && !this.isExpired(cached) && this.isExpiringSoon(cached)) {
|
|
107
|
-
this.triggerBackgroundRefresh();
|
|
108
|
-
return cached.token;
|
|
109
|
-
}
|
|
110
|
-
// Token expired or missing, must refresh synchronously
|
|
111
|
-
return this.refreshToken();
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Force refresh the token.
|
|
115
|
-
*
|
|
116
|
-
* @returns New installation access token
|
|
117
|
-
*/
|
|
118
|
-
async refreshToken() {
|
|
119
|
-
// Deduplicate concurrent refresh requests
|
|
120
|
-
if (this.refreshPromise) {
|
|
121
|
-
return this.refreshPromise;
|
|
122
|
-
}
|
|
123
|
-
this.refreshPromise = this.doRefresh();
|
|
124
|
-
try {
|
|
125
|
-
return await this.refreshPromise;
|
|
126
|
-
}
|
|
127
|
-
finally {
|
|
128
|
-
this.refreshPromise = null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Check if token needs refresh (within 5 minutes of expiration).
|
|
133
|
-
*
|
|
134
|
-
* @returns true if token should be refreshed
|
|
135
|
-
*/
|
|
136
|
-
isTokenExpiringSoon() {
|
|
137
|
-
const cached = this.cache.get(this.config.installation_id);
|
|
138
|
-
return cached ? this.isExpiringSoon(cached) : true;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Validate the configuration and private key.
|
|
142
|
-
*
|
|
143
|
-
* @throws Error if configuration is invalid
|
|
144
|
-
*/
|
|
145
|
-
async validate() {
|
|
146
|
-
// Validate required fields
|
|
147
|
-
if (!this.config.id) {
|
|
148
|
-
throw new Error("GitHub App ID is required. Configure 'app.id' in .fractary/config.yaml");
|
|
149
|
-
}
|
|
150
|
-
if (!this.config.installation_id) {
|
|
151
|
-
throw new Error("GitHub App Installation ID is required. Configure 'app.installation_id' in .fractary/config.yaml");
|
|
152
|
-
}
|
|
153
|
-
// Validate private key can be loaded
|
|
154
|
-
await PrivateKeyLoader.load(this.config);
|
|
155
|
-
// Attempt to generate JWT to validate key
|
|
156
|
-
await this.generateJWT();
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Perform the actual token refresh
|
|
160
|
-
*/
|
|
161
|
-
async doRefresh() {
|
|
162
|
-
console.error('[DEBUG] GitHub App auth - App ID:', this.config.id);
|
|
163
|
-
console.error('[DEBUG] GitHub App auth - Installation ID:', this.config.installation_id);
|
|
164
|
-
console.error('[DEBUG] GitHub App auth - Private key path:', this.config.private_key_path);
|
|
165
|
-
const jwtToken = await this.generateJWT();
|
|
166
|
-
console.error('[DEBUG] GitHub App auth - JWT generated successfully');
|
|
167
|
-
const installationToken = await this.exchangeForInstallationToken(jwtToken);
|
|
168
|
-
console.error('[DEBUG] GitHub App auth - Installation token received');
|
|
169
|
-
// Cache the token
|
|
170
|
-
this.cache.set(this.config.installation_id, {
|
|
171
|
-
token: installationToken.token,
|
|
172
|
-
expires_at: new Date(installationToken.expires_at),
|
|
173
|
-
installation_id: this.config.installation_id,
|
|
174
|
-
});
|
|
175
|
-
return installationToken.token;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Generate a JWT for GitHub App authentication
|
|
179
|
-
*/
|
|
180
|
-
async generateJWT() {
|
|
181
|
-
const privateKey = await PrivateKeyLoader.load(this.config);
|
|
182
|
-
const now = Math.floor(Date.now() / 1000);
|
|
183
|
-
const payload = {
|
|
184
|
-
iat: now - 60, // Issued 60 seconds ago to allow for clock drift
|
|
185
|
-
exp: now + GitHubAppAuth.JWT_EXPIRY_SECONDS,
|
|
186
|
-
iss: this.config.id,
|
|
187
|
-
};
|
|
188
|
-
try {
|
|
189
|
-
return jwt.sign(payload, privateKey, { algorithm: 'RS256' });
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
if (error instanceof Error) {
|
|
193
|
-
throw new Error(`Failed to generate JWT: ${error.message}`);
|
|
194
|
-
}
|
|
195
|
-
throw error;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Exchange JWT for installation access token
|
|
200
|
-
*/
|
|
201
|
-
async exchangeForInstallationToken(jwtToken) {
|
|
202
|
-
const url = `${GitHubAppAuth.GITHUB_API_URL}/app/installations/${this.config.installation_id}/access_tokens`;
|
|
203
|
-
let response;
|
|
204
|
-
try {
|
|
205
|
-
response = await fetch(url, {
|
|
206
|
-
method: 'POST',
|
|
207
|
-
headers: {
|
|
208
|
-
Accept: 'application/vnd.github+json',
|
|
209
|
-
Authorization: `Bearer ${jwtToken}`,
|
|
210
|
-
'X-GitHub-Api-Version': '2022-11-28',
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
if (error instanceof Error) {
|
|
216
|
-
throw new Error(`Failed to connect to GitHub API: ${error.message}`);
|
|
217
|
-
}
|
|
218
|
-
throw error;
|
|
219
|
-
}
|
|
220
|
-
if (!response.ok) {
|
|
221
|
-
const errorBody = await response.text().catch(() => 'Unknown error');
|
|
222
|
-
console.error('[DEBUG] GitHub API error:', response.status, errorBody);
|
|
223
|
-
if (response.status === 401) {
|
|
224
|
-
throw new Error(`Failed to authenticate with GitHub App. Status: ${response.status}, Response: ${errorBody}`);
|
|
225
|
-
}
|
|
226
|
-
if (response.status === 404) {
|
|
227
|
-
throw new Error(`GitHub App installation not found (ID: ${this.config.installation_id}). ` +
|
|
228
|
-
'Verify the Installation ID is correct and the app is installed.');
|
|
229
|
-
}
|
|
230
|
-
if (response.status === 403) {
|
|
231
|
-
// Check for rate limiting
|
|
232
|
-
const rateLimitRemaining = response.headers.get('x-ratelimit-remaining');
|
|
233
|
-
const rateLimitReset = response.headers.get('x-ratelimit-reset');
|
|
234
|
-
if (rateLimitRemaining === '0' && rateLimitReset) {
|
|
235
|
-
const resetTime = new Date(parseInt(rateLimitReset) * 1000);
|
|
236
|
-
const secondsUntilReset = Math.ceil((resetTime.getTime() - Date.now()) / 1000);
|
|
237
|
-
throw new Error(`GitHub API rate limited. Retry after ${secondsUntilReset} seconds.`);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
throw new Error(`Failed to get installation token: ${response.status} ${errorBody}`);
|
|
241
|
-
}
|
|
242
|
-
return response.json();
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Check if token is expired
|
|
246
|
-
*/
|
|
247
|
-
isExpired(cached) {
|
|
248
|
-
return cached.expires_at.getTime() <= Date.now();
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Check if token is expiring soon
|
|
252
|
-
*/
|
|
253
|
-
isExpiringSoon(cached) {
|
|
254
|
-
return cached.expires_at.getTime() - Date.now() < GitHubAppAuth.REFRESH_THRESHOLD_MS;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Trigger background token refresh (non-blocking)
|
|
258
|
-
*/
|
|
259
|
-
triggerBackgroundRefresh() {
|
|
260
|
-
if (this.refreshPromise) {
|
|
261
|
-
return; // Already refreshing
|
|
262
|
-
}
|
|
263
|
-
// Fire and forget - errors logged but not thrown
|
|
264
|
-
this.refreshToken().catch(error => {
|
|
265
|
-
console.error('[GitHubAppAuth] Background token refresh failed:', error.message);
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
// Token refresh threshold (5 minutes before expiration)
|
|
270
|
-
GitHubAppAuth.REFRESH_THRESHOLD_MS = 5 * 60 * 1000;
|
|
271
|
-
// JWT validity period (reduced to 5 minutes to handle clock skew)
|
|
272
|
-
GitHubAppAuth.JWT_EXPIRY_SECONDS = 300;
|
|
273
|
-
// GitHub API base URL
|
|
274
|
-
GitHubAppAuth.GITHUB_API_URL = 'https://api.github.com';
|
|
275
|
-
/**
|
|
276
|
-
* Static Token Provider
|
|
277
|
-
*
|
|
278
|
-
* Simple provider for static PAT tokens
|
|
279
|
-
*/
|
|
280
|
-
export class StaticTokenProvider {
|
|
281
|
-
constructor(token) {
|
|
282
|
-
this.token = token;
|
|
283
|
-
}
|
|
284
|
-
async getToken() {
|
|
285
|
-
return this.token;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* GitHub App Token Provider
|
|
290
|
-
*
|
|
291
|
-
* Provider that uses GitHubAppAuth for dynamic token generation
|
|
292
|
-
*/
|
|
293
|
-
export class GitHubAppTokenProvider {
|
|
294
|
-
constructor(auth) {
|
|
295
|
-
this.auth = auth;
|
|
296
|
-
}
|
|
297
|
-
async getToken() {
|
|
298
|
-
return this.auth.getToken();
|
|
299
|
-
}
|
|
300
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SDK Configuration Adapter
|
|
3
|
-
*
|
|
4
|
-
* Converts FABER CLI configuration to @fractary/core SDK configuration format
|
|
5
|
-
* Supports both PAT and GitHub App authentication methods.
|
|
6
|
-
*/
|
|
7
|
-
import type { LoadedFaberConfig } from '../types/config.js';
|
|
8
|
-
import type { WorkConfig, RepoConfig } from '@fractary/core';
|
|
9
|
-
import { TokenProvider } from './github-app-auth.js';
|
|
10
|
-
/**
|
|
11
|
-
* Get the current token from the provider
|
|
12
|
-
* Used internally and for SDK configuration
|
|
13
|
-
*
|
|
14
|
-
* @param faberConfig - FABER CLI configuration
|
|
15
|
-
* @returns Promise resolving to the current token
|
|
16
|
-
*/
|
|
17
|
-
export declare function getToken(faberConfig: LoadedFaberConfig): Promise<string>;
|
|
18
|
-
/**
|
|
19
|
-
* Get the token provider for dynamic token refresh
|
|
20
|
-
* Useful for long-running operations that need fresh tokens
|
|
21
|
-
*
|
|
22
|
-
* @param faberConfig - FABER CLI configuration
|
|
23
|
-
* @returns TokenProvider instance
|
|
24
|
-
*/
|
|
25
|
-
export declare function getTokenProviderInstance(faberConfig: LoadedFaberConfig): TokenProvider;
|
|
26
|
-
/**
|
|
27
|
-
* Validate GitHub authentication configuration
|
|
28
|
-
*
|
|
29
|
-
* @param faberConfig - FABER CLI configuration
|
|
30
|
-
* @throws Error if configuration is invalid
|
|
31
|
-
*/
|
|
32
|
-
export declare function validateGitHubAuth(faberConfig: LoadedFaberConfig): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* Check if GitHub App authentication is configured
|
|
35
|
-
*
|
|
36
|
-
* @param faberConfig - FABER CLI configuration
|
|
37
|
-
* @returns true if GitHub App is configured
|
|
38
|
-
*/
|
|
39
|
-
export declare function isGitHubAppConfigured(faberConfig: LoadedFaberConfig): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Create WorkConfig for WorkManager from FaberConfig
|
|
42
|
-
*
|
|
43
|
-
* @param faberConfig - FABER CLI configuration
|
|
44
|
-
* @returns WorkConfig for @fractary/core WorkManager
|
|
45
|
-
* @throws Error if required fields are missing
|
|
46
|
-
*/
|
|
47
|
-
export declare function createWorkConfig(faberConfig: LoadedFaberConfig): WorkConfig;
|
|
48
|
-
/**
|
|
49
|
-
* Create WorkConfig for WorkManager from FaberConfig (async version)
|
|
50
|
-
*
|
|
51
|
-
* This version supports both PAT and GitHub App authentication.
|
|
52
|
-
*
|
|
53
|
-
* @param faberConfig - FABER CLI configuration
|
|
54
|
-
* @returns Promise resolving to WorkConfig for @fractary/core WorkManager
|
|
55
|
-
* @throws Error if required fields are missing
|
|
56
|
-
*/
|
|
57
|
-
export declare function createWorkConfigAsync(faberConfig: LoadedFaberConfig): Promise<WorkConfig>;
|
|
58
|
-
/**
|
|
59
|
-
* Create RepoConfig for RepoManager from FaberConfig
|
|
60
|
-
*
|
|
61
|
-
* @param faberConfig - FABER CLI configuration
|
|
62
|
-
* @returns RepoConfig for @fractary/core RepoManager
|
|
63
|
-
* @throws Error if required fields are missing
|
|
64
|
-
*/
|
|
65
|
-
export declare function createRepoConfig(faberConfig: LoadedFaberConfig): RepoConfig;
|
|
66
|
-
/**
|
|
67
|
-
* Create RepoConfig for RepoManager from FaberConfig (async version)
|
|
68
|
-
*
|
|
69
|
-
* This version supports both PAT and GitHub App authentication.
|
|
70
|
-
*
|
|
71
|
-
* @param faberConfig - FABER CLI configuration
|
|
72
|
-
* @returns Promise resolving to RepoConfig for @fractary/core RepoManager
|
|
73
|
-
* @throws Error if required fields are missing
|
|
74
|
-
*/
|
|
75
|
-
export declare function createRepoConfigAsync(faberConfig: LoadedFaberConfig): Promise<RepoConfig>;
|
|
76
|
-
//# sourceMappingURL=sdk-config-adapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-config-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-config-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAmB,MAAM,oBAAoB,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAEL,aAAa,EAGd,MAAM,sBAAsB,CAAC;AAuD9B;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAG9E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,iBAAiB,GAAG,aAAa,CAEtF;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBtF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAG7E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,GAAG,UAAU,CAmC3E;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkB/F;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,GAAG,UAAU,CAyB3E;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAY/F"}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SDK Configuration Adapter
|
|
3
|
-
*
|
|
4
|
-
* Converts FABER CLI configuration to @fractary/core SDK configuration format
|
|
5
|
-
* Supports both PAT and GitHub App authentication methods.
|
|
6
|
-
*/
|
|
7
|
-
import { GitHubAppAuth, StaticTokenProvider, GitHubAppTokenProvider, } from './github-app-auth.js';
|
|
8
|
-
// Singleton token provider for reuse across SDK instances
|
|
9
|
-
let tokenProvider = null;
|
|
10
|
-
let tokenProviderConfig = null;
|
|
11
|
-
/**
|
|
12
|
-
* Get or create a token provider based on configuration
|
|
13
|
-
*
|
|
14
|
-
* @param faberConfig - FABER CLI configuration
|
|
15
|
-
* @returns TokenProvider instance
|
|
16
|
-
*/
|
|
17
|
-
function getTokenProvider(faberConfig) {
|
|
18
|
-
const appConfig = faberConfig.github?.app;
|
|
19
|
-
const patToken = faberConfig.github?.token;
|
|
20
|
-
// Determine which auth method to use
|
|
21
|
-
// GitHub App takes precedence over PAT if configured
|
|
22
|
-
if (appConfig?.id && appConfig?.installation_id) {
|
|
23
|
-
// Check if we can reuse existing provider
|
|
24
|
-
if (tokenProvider && tokenProviderConfig === appConfig) {
|
|
25
|
-
return tokenProvider;
|
|
26
|
-
}
|
|
27
|
-
// Create new GitHub App token provider
|
|
28
|
-
const auth = new GitHubAppAuth(appConfig);
|
|
29
|
-
tokenProvider = new GitHubAppTokenProvider(auth);
|
|
30
|
-
tokenProviderConfig = appConfig;
|
|
31
|
-
return tokenProvider;
|
|
32
|
-
}
|
|
33
|
-
// Fall back to PAT
|
|
34
|
-
if (patToken) {
|
|
35
|
-
// Check if we can reuse existing provider
|
|
36
|
-
if (tokenProvider && tokenProviderConfig === patToken) {
|
|
37
|
-
return tokenProvider;
|
|
38
|
-
}
|
|
39
|
-
tokenProvider = new StaticTokenProvider(patToken);
|
|
40
|
-
tokenProviderConfig = patToken;
|
|
41
|
-
return tokenProvider;
|
|
42
|
-
}
|
|
43
|
-
throw new Error('GitHub authentication not configured. Either:\n' +
|
|
44
|
-
' 1. Set GITHUB_TOKEN environment variable, or\n' +
|
|
45
|
-
' 2. Configure GitHub App in .fractary/config.yaml:\n' +
|
|
46
|
-
' github:\n' +
|
|
47
|
-
' app:\n' +
|
|
48
|
-
' id: "<app-id>"\n' +
|
|
49
|
-
' installation_id: "<installation-id>"\n' +
|
|
50
|
-
' private_key_path: "~/.github/your-app.pem"');
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Get the current token from the provider
|
|
54
|
-
* Used internally and for SDK configuration
|
|
55
|
-
*
|
|
56
|
-
* @param faberConfig - FABER CLI configuration
|
|
57
|
-
* @returns Promise resolving to the current token
|
|
58
|
-
*/
|
|
59
|
-
export async function getToken(faberConfig) {
|
|
60
|
-
const provider = getTokenProvider(faberConfig);
|
|
61
|
-
return provider.getToken();
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Get the token provider for dynamic token refresh
|
|
65
|
-
* Useful for long-running operations that need fresh tokens
|
|
66
|
-
*
|
|
67
|
-
* @param faberConfig - FABER CLI configuration
|
|
68
|
-
* @returns TokenProvider instance
|
|
69
|
-
*/
|
|
70
|
-
export function getTokenProviderInstance(faberConfig) {
|
|
71
|
-
return getTokenProvider(faberConfig);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Validate GitHub authentication configuration
|
|
75
|
-
*
|
|
76
|
-
* @param faberConfig - FABER CLI configuration
|
|
77
|
-
* @throws Error if configuration is invalid
|
|
78
|
-
*/
|
|
79
|
-
export async function validateGitHubAuth(faberConfig) {
|
|
80
|
-
const appConfig = faberConfig.github?.app;
|
|
81
|
-
if (appConfig?.id && appConfig?.installation_id) {
|
|
82
|
-
// Validate GitHub App configuration
|
|
83
|
-
const auth = new GitHubAppAuth(appConfig);
|
|
84
|
-
await auth.validate();
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
// Validate PAT
|
|
88
|
-
if (!faberConfig.github?.token) {
|
|
89
|
-
throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/config.yaml');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Check if GitHub App authentication is configured
|
|
94
|
-
*
|
|
95
|
-
* @param faberConfig - FABER CLI configuration
|
|
96
|
-
* @returns true if GitHub App is configured
|
|
97
|
-
*/
|
|
98
|
-
export function isGitHubAppConfigured(faberConfig) {
|
|
99
|
-
const appConfig = faberConfig.github?.app;
|
|
100
|
-
return !!(appConfig?.id && appConfig?.installation_id);
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Create WorkConfig for WorkManager from FaberConfig
|
|
104
|
-
*
|
|
105
|
-
* @param faberConfig - FABER CLI configuration
|
|
106
|
-
* @returns WorkConfig for @fractary/core WorkManager
|
|
107
|
-
* @throws Error if required fields are missing
|
|
108
|
-
*/
|
|
109
|
-
export function createWorkConfig(faberConfig) {
|
|
110
|
-
const owner = faberConfig.github?.organization;
|
|
111
|
-
const repo = faberConfig.github?.project;
|
|
112
|
-
if (!owner || !repo) {
|
|
113
|
-
throw new Error('GitHub organization and project must be configured in .fractary/config.yaml');
|
|
114
|
-
}
|
|
115
|
-
// Get token provider (validates auth config)
|
|
116
|
-
const provider = getTokenProvider(faberConfig);
|
|
117
|
-
// For SDK config, we need a synchronous token
|
|
118
|
-
// The SDK will use this initially; for long-running operations,
|
|
119
|
-
// use createWorkConfigAsync or the token provider directly
|
|
120
|
-
let token;
|
|
121
|
-
if (provider instanceof StaticTokenProvider) {
|
|
122
|
-
// For PAT, we can get token synchronously via internal access
|
|
123
|
-
token = faberConfig.github?.token || '';
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
// For GitHub App, throw helpful error - use async version
|
|
127
|
-
throw new Error('GitHub App authentication requires async initialization. ' +
|
|
128
|
-
'Use createWorkConfigAsync() instead of createWorkConfig().');
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
platform: 'github',
|
|
132
|
-
owner,
|
|
133
|
-
repo,
|
|
134
|
-
token,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Create WorkConfig for WorkManager from FaberConfig (async version)
|
|
139
|
-
*
|
|
140
|
-
* This version supports both PAT and GitHub App authentication.
|
|
141
|
-
*
|
|
142
|
-
* @param faberConfig - FABER CLI configuration
|
|
143
|
-
* @returns Promise resolving to WorkConfig for @fractary/core WorkManager
|
|
144
|
-
* @throws Error if required fields are missing
|
|
145
|
-
*/
|
|
146
|
-
export async function createWorkConfigAsync(faberConfig) {
|
|
147
|
-
const owner = faberConfig.github?.organization;
|
|
148
|
-
const repo = faberConfig.github?.project;
|
|
149
|
-
if (!owner || !repo) {
|
|
150
|
-
throw new Error('GitHub organization and project must be configured in .fractary/config.yaml');
|
|
151
|
-
}
|
|
152
|
-
const token = await getToken(faberConfig);
|
|
153
|
-
return {
|
|
154
|
-
platform: 'github',
|
|
155
|
-
owner,
|
|
156
|
-
repo,
|
|
157
|
-
token,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Create RepoConfig for RepoManager from FaberConfig
|
|
162
|
-
*
|
|
163
|
-
* @param faberConfig - FABER CLI configuration
|
|
164
|
-
* @returns RepoConfig for @fractary/core RepoManager
|
|
165
|
-
* @throws Error if required fields are missing
|
|
166
|
-
*/
|
|
167
|
-
export function createRepoConfig(faberConfig) {
|
|
168
|
-
const owner = faberConfig.github?.organization;
|
|
169
|
-
const repo = faberConfig.github?.project;
|
|
170
|
-
// Get token provider (validates auth config)
|
|
171
|
-
const provider = getTokenProvider(faberConfig);
|
|
172
|
-
// For SDK config, we need a synchronous token
|
|
173
|
-
let token;
|
|
174
|
-
if (provider instanceof StaticTokenProvider) {
|
|
175
|
-
token = faberConfig.github?.token || '';
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
throw new Error('GitHub App authentication requires async initialization. ' +
|
|
179
|
-
'Use createRepoConfigAsync() instead of createRepoConfig().');
|
|
180
|
-
}
|
|
181
|
-
return {
|
|
182
|
-
platform: 'github',
|
|
183
|
-
owner,
|
|
184
|
-
repo,
|
|
185
|
-
token,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Create RepoConfig for RepoManager from FaberConfig (async version)
|
|
190
|
-
*
|
|
191
|
-
* This version supports both PAT and GitHub App authentication.
|
|
192
|
-
*
|
|
193
|
-
* @param faberConfig - FABER CLI configuration
|
|
194
|
-
* @returns Promise resolving to RepoConfig for @fractary/core RepoManager
|
|
195
|
-
* @throws Error if required fields are missing
|
|
196
|
-
*/
|
|
197
|
-
export async function createRepoConfigAsync(faberConfig) {
|
|
198
|
-
const owner = faberConfig.github?.organization;
|
|
199
|
-
const repo = faberConfig.github?.project;
|
|
200
|
-
const token = await getToken(faberConfig);
|
|
201
|
-
return {
|
|
202
|
-
platform: 'github',
|
|
203
|
-
owner,
|
|
204
|
-
repo,
|
|
205
|
-
token,
|
|
206
|
-
};
|
|
207
|
-
}
|