@fractary/faber-cli 1.5.48 → 1.5.50

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.
Files changed (96) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +0 -0
  3. package/dist/__mocks__/chalk.d.ts +0 -0
  4. package/dist/__mocks__/chalk.d.ts.map +0 -0
  5. package/dist/__mocks__/chalk.js +0 -0
  6. package/dist/commands/auth/index.d.ts +0 -0
  7. package/dist/commands/auth/index.d.ts.map +0 -0
  8. package/dist/commands/auth/index.js +0 -0
  9. package/dist/commands/changelog/index.d.ts +0 -0
  10. package/dist/commands/changelog/index.d.ts.map +0 -0
  11. package/dist/commands/changelog/index.js +0 -0
  12. package/dist/commands/config.d.ts +0 -0
  13. package/dist/commands/config.d.ts.map +0 -0
  14. package/dist/commands/config.js +0 -0
  15. package/dist/commands/logs/index.d.ts +0 -0
  16. package/dist/commands/logs/index.d.ts.map +0 -0
  17. package/dist/commands/logs/index.js +0 -0
  18. package/dist/commands/migrate.d.ts +0 -0
  19. package/dist/commands/migrate.d.ts.map +0 -0
  20. package/dist/commands/migrate.js +0 -0
  21. package/dist/commands/plan/index.d.ts +0 -0
  22. package/dist/commands/plan/index.d.ts.map +0 -0
  23. package/dist/commands/plan/index.js +0 -0
  24. package/dist/commands/repo/index.d.ts +0 -0
  25. package/dist/commands/repo/index.d.ts.map +0 -0
  26. package/dist/commands/repo/index.js +0 -0
  27. package/dist/commands/runs.d.ts +0 -0
  28. package/dist/commands/runs.d.ts.map +0 -0
  29. package/dist/commands/runs.js +0 -0
  30. package/dist/commands/session.d.ts +0 -0
  31. package/dist/commands/session.d.ts.map +0 -0
  32. package/dist/commands/session.js +0 -0
  33. package/dist/commands/work/index.d.ts +0 -0
  34. package/dist/commands/work/index.d.ts.map +0 -0
  35. package/dist/commands/work/index.js +0 -0
  36. package/dist/commands/workflow/index.d.ts +0 -0
  37. package/dist/commands/workflow/index.d.ts.map +0 -0
  38. package/dist/commands/workflow/index.js +0 -0
  39. package/dist/index.d.ts +0 -0
  40. package/dist/index.d.ts.map +0 -0
  41. package/dist/lib/anthropic-client.d.ts +0 -0
  42. package/dist/lib/anthropic-client.d.ts.map +0 -0
  43. package/dist/lib/anthropic-client.js +0 -0
  44. package/dist/lib/config.d.ts +0 -0
  45. package/dist/lib/config.d.ts.map +0 -0
  46. package/dist/lib/config.js +0 -0
  47. package/dist/lib/github-app-setup.d.ts +0 -0
  48. package/dist/lib/github-app-setup.d.ts.map +0 -0
  49. package/dist/lib/github-app-setup.js +0 -0
  50. package/dist/lib/repo-client.d.ts +0 -0
  51. package/dist/lib/repo-client.d.ts.map +1 -1
  52. package/dist/lib/repo-client.js +2 -0
  53. package/dist/lib/sdk-type-adapter.d.ts +0 -0
  54. package/dist/lib/sdk-type-adapter.d.ts.map +0 -0
  55. package/dist/lib/sdk-type-adapter.js +0 -0
  56. package/dist/lib/yaml-config.d.ts +0 -0
  57. package/dist/lib/yaml-config.d.ts.map +0 -0
  58. package/dist/lib/yaml-config.js +0 -0
  59. package/dist/types/config.d.ts +1 -0
  60. package/dist/types/config.d.ts.map +1 -1
  61. package/dist/types/config.js +0 -0
  62. package/dist/utils/errors.d.ts +0 -0
  63. package/dist/utils/errors.d.ts.map +0 -0
  64. package/dist/utils/errors.js +0 -0
  65. package/dist/utils/github-manifest.d.ts +0 -0
  66. package/dist/utils/github-manifest.d.ts.map +0 -0
  67. package/dist/utils/github-manifest.js +0 -0
  68. package/dist/utils/labels.d.ts +0 -0
  69. package/dist/utils/labels.d.ts.map +0 -0
  70. package/dist/utils/labels.js +0 -0
  71. package/dist/utils/output.d.ts +0 -0
  72. package/dist/utils/output.d.ts.map +0 -0
  73. package/dist/utils/output.js +0 -0
  74. package/dist/utils/prompt.d.ts +0 -0
  75. package/dist/utils/prompt.d.ts.map +0 -0
  76. package/dist/utils/prompt.js +0 -0
  77. package/dist/utils/sorting.d.ts +0 -0
  78. package/dist/utils/sorting.d.ts.map +0 -0
  79. package/dist/utils/sorting.js +0 -0
  80. package/dist/utils/validation.d.ts +0 -0
  81. package/dist/utils/validation.d.ts.map +0 -0
  82. package/dist/utils/validation.js +0 -0
  83. package/package.json +2 -2
  84. package/schemas/plan.schema.json +0 -0
  85. package/dist/commands/init.d.ts +0 -9
  86. package/dist/commands/init.d.ts.map +0 -1
  87. package/dist/commands/init.js +0 -161
  88. package/dist/commands/spec/index.d.ts +0 -11
  89. package/dist/commands/spec/index.d.ts.map +0 -1
  90. package/dist/commands/spec/index.js +0 -280
  91. package/dist/lib/github-app-auth.d.ts +0 -122
  92. package/dist/lib/github-app-auth.d.ts.map +0 -1
  93. package/dist/lib/github-app-auth.js +0 -300
  94. package/dist/lib/sdk-config-adapter.d.ts +0 -76
  95. package/dist/lib/sdk-config-adapter.d.ts.map +0 -1
  96. 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
- }