@fractary/faber-cli 1.3.2 → 1.3.3

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.
@@ -2,7 +2,10 @@
2
2
  * Repo Client
3
3
  *
4
4
  * Integrates with @fractary/core SDK for repository and work tracking operations
5
+ * Supports both PAT and GitHub App authentication methods.
5
6
  */
7
+ import { WorkManager, RepoManager } from '@fractary/core';
8
+ import type { FaberConfig } from '../types/config.js';
6
9
  interface Issue {
7
10
  id: string;
8
11
  number: number;
@@ -31,7 +34,7 @@ interface IssueUpdateOptions {
31
34
  * Repo Client - integrates with @fractary/core SDK
32
35
  *
33
36
  * Provides repository and work tracking operations using WorkManager and RepoManager
34
- * from the @fractary/core SDK. Replaces the previous CLI-based approach.
37
+ * from the @fractary/core SDK. Supports both PAT and GitHub App authentication.
35
38
  */
36
39
  export declare class RepoClient {
37
40
  private config;
@@ -39,7 +42,24 @@ export declare class RepoClient {
39
42
  private repoManager;
40
43
  private organization;
41
44
  private project;
42
- constructor(config: any);
45
+ /**
46
+ * Create a RepoClient instance (async factory method)
47
+ *
48
+ * Use this method to create RepoClient instances as it supports
49
+ * both PAT and GitHub App authentication.
50
+ *
51
+ * @param config - FABER CLI configuration
52
+ * @returns Promise resolving to RepoClient instance
53
+ */
54
+ static create(config: FaberConfig): Promise<RepoClient>;
55
+ /**
56
+ * Create a RepoClient instance
57
+ *
58
+ * @param config - FABER CLI configuration
59
+ * @param workManager - Optional pre-initialized WorkManager (for async factory)
60
+ * @param repoManager - Optional pre-initialized RepoManager (for async factory)
61
+ */
62
+ constructor(config: FaberConfig, workManager?: WorkManager, repoManager?: RepoManager);
43
63
  /**
44
64
  * Fetch specific issues by ID
45
65
  *
@@ -1 +1 @@
1
- {"version":3,"file":"repo-client.d.ts","sourceRoot":"","sources":["../../src/lib/repo-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,GAAG;IA6BvB;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAclD;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAetD;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrD;;;;OAIG;IACG,cAAc,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA+BzF;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CA0B9D"}
1
+ {"version":3,"file":"repo-client.d.ts","sourceRoot":"","sources":["../../src/lib/repo-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAS1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IAExB;;;;;;;;OAQG;WACU,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAmB7D;;;;;;OAMG;gBACS,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW;IA0CrF;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAclD;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAetD;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrD;;;;OAIG;IACG,cAAc,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA+BzF;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CA0B9D"}
@@ -2,29 +2,73 @@
2
2
  * Repo Client
3
3
  *
4
4
  * Integrates with @fractary/core SDK for repository and work tracking operations
5
+ * Supports both PAT and GitHub App authentication methods.
5
6
  */
6
7
  import { WorkManager, RepoManager } from '@fractary/core';
7
- import { createWorkConfig, createRepoConfig } from './sdk-config-adapter.js';
8
+ import { createWorkConfig, createRepoConfig, createWorkConfigAsync, createRepoConfigAsync, isGitHubAppConfigured, } from './sdk-config-adapter.js';
8
9
  import { sdkIssueToCLIIssue, sdkWorktreeToCLIWorktreeResult } from './sdk-type-adapter.js';
9
10
  import os from 'os';
10
11
  /**
11
12
  * Repo Client - integrates with @fractary/core SDK
12
13
  *
13
14
  * Provides repository and work tracking operations using WorkManager and RepoManager
14
- * from the @fractary/core SDK. Replaces the previous CLI-based approach.
15
+ * from the @fractary/core SDK. Supports both PAT and GitHub App authentication.
15
16
  */
16
17
  export class RepoClient {
17
- constructor(config) {
18
+ /**
19
+ * Create a RepoClient instance (async factory method)
20
+ *
21
+ * Use this method to create RepoClient instances as it supports
22
+ * both PAT and GitHub App authentication.
23
+ *
24
+ * @param config - FABER CLI configuration
25
+ * @returns Promise resolving to RepoClient instance
26
+ */
27
+ static async create(config) {
28
+ // Use async config methods for GitHub App support
29
+ const workConfig = await createWorkConfigAsync(config);
30
+ const repoConfig = await createRepoConfigAsync(config);
31
+ try {
32
+ const workManager = new WorkManager(workConfig);
33
+ const repoManager = new RepoManager(repoConfig);
34
+ // Create client with pre-initialized managers
35
+ return new RepoClient(config, workManager, repoManager);
36
+ }
37
+ catch (error) {
38
+ if (error instanceof Error) {
39
+ throw new Error(`Failed to initialize SDK managers: ${error.message}`);
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ /**
45
+ * Create a RepoClient instance
46
+ *
47
+ * @param config - FABER CLI configuration
48
+ * @param workManager - Optional pre-initialized WorkManager (for async factory)
49
+ * @param repoManager - Optional pre-initialized RepoManager (for async factory)
50
+ */
51
+ constructor(config, workManager, repoManager) {
18
52
  this.config = config;
19
- // Validate GitHub token
53
+ this.organization = config.github?.organization || 'unknown';
54
+ this.project = config.github?.project || 'unknown';
55
+ // If managers are provided (from static create), use them
56
+ if (workManager && repoManager) {
57
+ this.workManager = workManager;
58
+ this.repoManager = repoManager;
59
+ return;
60
+ }
61
+ // Synchronous initialization - only works with PAT
62
+ if (isGitHubAppConfigured(config)) {
63
+ throw new Error('GitHub App authentication requires async initialization. ' +
64
+ 'Use RepoClient.create() instead of new RepoClient().');
65
+ }
66
+ // Validate GitHub token for PAT auth
20
67
  const token = config.github?.token;
21
68
  if (!token) {
22
69
  throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable.');
23
70
  }
24
- // Extract organization and project
25
- this.organization = config.github?.organization || 'unknown';
26
- this.project = config.github?.project || 'unknown';
27
- // Create SDK configurations
71
+ // Create SDK configurations (PAT only)
28
72
  const workConfig = createWorkConfig(config);
29
73
  const repoConfig = createRepoConfig(config);
30
74
  // Initialize SDK managers
@@ -2,9 +2,41 @@
2
2
  * SDK Configuration Adapter
3
3
  *
4
4
  * Converts FABER CLI configuration to @fractary/core SDK configuration format
5
+ * Supports both PAT and GitHub App authentication methods.
5
6
  */
6
7
  import type { FaberConfig } from '../types/config.js';
7
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: FaberConfig): 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: FaberConfig): 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: FaberConfig): 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: FaberConfig): boolean;
8
40
  /**
9
41
  * Create WorkConfig for WorkManager from FaberConfig
10
42
  *
@@ -13,6 +45,16 @@ import type { WorkConfig, RepoConfig } from '@fractary/core';
13
45
  * @throws Error if required fields are missing
14
46
  */
15
47
  export declare function createWorkConfig(faberConfig: FaberConfig): 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: FaberConfig): Promise<WorkConfig>;
16
58
  /**
17
59
  * Create RepoConfig for RepoManager from FaberConfig
18
60
  *
@@ -21,4 +63,14 @@ export declare function createWorkConfig(faberConfig: FaberConfig): WorkConfig;
21
63
  * @throws Error if required fields are missing
22
64
  */
23
65
  export declare function createRepoConfig(faberConfig: FaberConfig): 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: FaberConfig): Promise<RepoConfig>;
24
76
  //# sourceMappingURL=sdk-config-adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-config-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-config-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAuBrE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAiBrE"}
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,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAEL,aAAa,EAGd,MAAM,sBAAsB,CAAC;AA2D9B;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,CAEhF;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAGvE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAmCrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAkBzF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAyBrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAYzF"}
@@ -2,7 +2,107 @@
2
2
  * SDK Configuration Adapter
3
3
  *
4
4
  * Converts FABER CLI configuration to @fractary/core SDK configuration format
5
+ * Supports both PAT and GitHub App authentication methods.
5
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/settings.json:\n' +
46
+ ' {\n' +
47
+ ' "github": {\n' +
48
+ ' "app": {\n' +
49
+ ' "id": "<app-id>",\n' +
50
+ ' "installation_id": "<installation-id>",\n' +
51
+ ' "private_key_path": "~/.github/your-app.pem"\n' +
52
+ ' }\n' +
53
+ ' }\n' +
54
+ ' }');
55
+ }
56
+ /**
57
+ * Get the current token from the provider
58
+ * Used internally and for SDK configuration
59
+ *
60
+ * @param faberConfig - FABER CLI configuration
61
+ * @returns Promise resolving to the current token
62
+ */
63
+ export async function getToken(faberConfig) {
64
+ const provider = getTokenProvider(faberConfig);
65
+ return provider.getToken();
66
+ }
67
+ /**
68
+ * Get the token provider for dynamic token refresh
69
+ * Useful for long-running operations that need fresh tokens
70
+ *
71
+ * @param faberConfig - FABER CLI configuration
72
+ * @returns TokenProvider instance
73
+ */
74
+ export function getTokenProviderInstance(faberConfig) {
75
+ return getTokenProvider(faberConfig);
76
+ }
77
+ /**
78
+ * Validate GitHub authentication configuration
79
+ *
80
+ * @param faberConfig - FABER CLI configuration
81
+ * @throws Error if configuration is invalid
82
+ */
83
+ export async function validateGitHubAuth(faberConfig) {
84
+ const appConfig = faberConfig.github?.app;
85
+ if (appConfig?.id && appConfig?.installation_id) {
86
+ // Validate GitHub App configuration
87
+ const auth = new GitHubAppAuth(appConfig);
88
+ await auth.validate();
89
+ return;
90
+ }
91
+ // Validate PAT
92
+ if (!faberConfig.github?.token) {
93
+ throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/settings.json');
94
+ }
95
+ }
96
+ /**
97
+ * Check if GitHub App authentication is configured
98
+ *
99
+ * @param faberConfig - FABER CLI configuration
100
+ * @returns true if GitHub App is configured
101
+ */
102
+ export function isGitHubAppConfigured(faberConfig) {
103
+ const appConfig = faberConfig.github?.app;
104
+ return !!(appConfig?.id && appConfig?.installation_id);
105
+ }
6
106
  /**
7
107
  * Create WorkConfig for WorkManager from FaberConfig
8
108
  *
@@ -11,15 +111,49 @@
11
111
  * @throws Error if required fields are missing
12
112
  */
13
113
  export function createWorkConfig(faberConfig) {
14
- const token = faberConfig.github?.token;
15
114
  const owner = faberConfig.github?.organization;
16
115
  const repo = faberConfig.github?.project;
17
- if (!token) {
18
- throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/settings.json');
116
+ if (!owner || !repo) {
117
+ throw new Error('GitHub organization and project must be configured in .fractary/settings.json');
118
+ }
119
+ // Get token provider (validates auth config)
120
+ const provider = getTokenProvider(faberConfig);
121
+ // For SDK config, we need a synchronous token
122
+ // The SDK will use this initially; for long-running operations,
123
+ // use createWorkConfigAsync or the token provider directly
124
+ let token;
125
+ if (provider instanceof StaticTokenProvider) {
126
+ // For PAT, we can get token synchronously via internal access
127
+ token = faberConfig.github?.token || '';
19
128
  }
129
+ else {
130
+ // For GitHub App, throw helpful error - use async version
131
+ throw new Error('GitHub App authentication requires async initialization. ' +
132
+ 'Use createWorkConfigAsync() instead of createWorkConfig().');
133
+ }
134
+ return {
135
+ platform: 'github',
136
+ owner,
137
+ repo,
138
+ token,
139
+ };
140
+ }
141
+ /**
142
+ * Create WorkConfig for WorkManager from FaberConfig (async version)
143
+ *
144
+ * This version supports both PAT and GitHub App authentication.
145
+ *
146
+ * @param faberConfig - FABER CLI configuration
147
+ * @returns Promise resolving to WorkConfig for @fractary/core WorkManager
148
+ * @throws Error if required fields are missing
149
+ */
150
+ export async function createWorkConfigAsync(faberConfig) {
151
+ const owner = faberConfig.github?.organization;
152
+ const repo = faberConfig.github?.project;
20
153
  if (!owner || !repo) {
21
154
  throw new Error('GitHub organization and project must be configured in .fractary/settings.json');
22
155
  }
156
+ const token = await getToken(faberConfig);
23
157
  return {
24
158
  platform: 'github',
25
159
  owner,
@@ -35,12 +169,39 @@ export function createWorkConfig(faberConfig) {
35
169
  * @throws Error if required fields are missing
36
170
  */
37
171
  export function createRepoConfig(faberConfig) {
38
- const token = faberConfig.github?.token;
39
172
  const owner = faberConfig.github?.organization;
40
173
  const repo = faberConfig.github?.project;
41
- if (!token) {
42
- throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/settings.json');
174
+ // Get token provider (validates auth config)
175
+ const provider = getTokenProvider(faberConfig);
176
+ // For SDK config, we need a synchronous token
177
+ let token;
178
+ if (provider instanceof StaticTokenProvider) {
179
+ token = faberConfig.github?.token || '';
43
180
  }
181
+ else {
182
+ throw new Error('GitHub App authentication requires async initialization. ' +
183
+ 'Use createRepoConfigAsync() instead of createRepoConfig().');
184
+ }
185
+ return {
186
+ platform: 'github',
187
+ owner,
188
+ repo,
189
+ token,
190
+ };
191
+ }
192
+ /**
193
+ * Create RepoConfig for RepoManager from FaberConfig (async version)
194
+ *
195
+ * This version supports both PAT and GitHub App authentication.
196
+ *
197
+ * @param faberConfig - FABER CLI configuration
198
+ * @returns Promise resolving to RepoConfig for @fractary/core RepoManager
199
+ * @throws Error if required fields are missing
200
+ */
201
+ export async function createRepoConfigAsync(faberConfig) {
202
+ const owner = faberConfig.github?.organization;
203
+ const repo = faberConfig.github?.project;
204
+ const token = await getToken(faberConfig);
44
205
  return {
45
206
  platform: 'github',
46
207
  owner,
@@ -6,11 +6,23 @@
6
6
  export interface AnthropicConfig {
7
7
  api_key?: string;
8
8
  }
9
+ /**
10
+ * GitHub App authentication configuration
11
+ */
12
+ export interface GitHubAppConfig {
13
+ id: string;
14
+ installation_id: string;
15
+ private_key_path?: string;
16
+ private_key_env_var?: string;
17
+ created_via?: 'manifest-flow' | 'manual';
18
+ created_at?: string;
19
+ }
9
20
  export interface GitHubConfig {
10
21
  token?: string;
11
22
  organization?: string;
12
23
  project?: string;
13
24
  repo?: string;
25
+ app?: GitHubAppConfig;
14
26
  }
15
27
  export interface WorktreeConfig {
16
28
  location?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,eAAe,GAAG,QAAQ,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Helper utilities for GitHub App Manifest flow
3
+ */
4
+ /**
5
+ * Parse code parameter from GitHub redirect URL or direct code input
6
+ *
7
+ * @param input - Either a full GitHub URL or just the code
8
+ * @returns The extracted code, or null if invalid
9
+ */
10
+ export declare function parseCodeFromUrl(input: string): string | null;
11
+ /**
12
+ * Validate manifest code format
13
+ *
14
+ * GitHub manifest codes are typically long alphanumeric strings
15
+ * with underscores and hyphens, at least 20 characters long.
16
+ *
17
+ * @param code - The code to validate
18
+ * @returns true if code appears valid
19
+ */
20
+ export declare function validateManifestCode(code: string): boolean;
21
+ /**
22
+ * Detect GitHub context from git remote
23
+ *
24
+ * Parses the git remote URL to extract organization and repository names.
25
+ * Supports both HTTPS and SSH URL formats.
26
+ *
27
+ * @returns Object with org and repo, or null if not detectable
28
+ */
29
+ export declare function detectGitHubContext(): {
30
+ org: string;
31
+ repo: string;
32
+ } | null;
33
+ /**
34
+ * Validate if current directory is a git repository
35
+ *
36
+ * @returns true if current directory is a git repository
37
+ */
38
+ export declare function isGitRepository(): boolean;
39
+ //# sourceMappingURL=github-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-manifest.d.ts","sourceRoot":"","sources":["../../src/utils/github-manifest.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoB7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB1E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAQzC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Helper utilities for GitHub App Manifest flow
3
+ */
4
+ import { Git } from '@fractary/faber';
5
+ /**
6
+ * Parse code parameter from GitHub redirect URL or direct code input
7
+ *
8
+ * @param input - Either a full GitHub URL or just the code
9
+ * @returns The extracted code, or null if invalid
10
+ */
11
+ export function parseCodeFromUrl(input) {
12
+ const trimmed = input.trim();
13
+ // Try to parse as URL first
14
+ try {
15
+ const url = new URL(trimmed);
16
+ const code = url.searchParams.get('code');
17
+ if (code) {
18
+ return code;
19
+ }
20
+ }
21
+ catch {
22
+ // Not a valid URL, check if it's just the code itself
23
+ }
24
+ // Check if input looks like a code (alphanumeric, underscores, hyphens)
25
+ if (/^[a-zA-Z0-9_-]+$/.test(trimmed)) {
26
+ return trimmed;
27
+ }
28
+ return null;
29
+ }
30
+ /**
31
+ * Validate manifest code format
32
+ *
33
+ * GitHub manifest codes are typically long alphanumeric strings
34
+ * with underscores and hyphens, at least 20 characters long.
35
+ *
36
+ * @param code - The code to validate
37
+ * @returns true if code appears valid
38
+ */
39
+ export function validateManifestCode(code) {
40
+ return /^[a-zA-Z0-9_-]{20,}$/.test(code);
41
+ }
42
+ /**
43
+ * Detect GitHub context from git remote
44
+ *
45
+ * Parses the git remote URL to extract organization and repository names.
46
+ * Supports both HTTPS and SSH URL formats.
47
+ *
48
+ * @returns Object with org and repo, or null if not detectable
49
+ */
50
+ export function detectGitHubContext() {
51
+ try {
52
+ const git = new Git();
53
+ const remoteUrl = git.exec('remote get-url origin').trim();
54
+ // Parse various GitHub URL formats
55
+ // HTTPS: https://github.com/org/repo.git
56
+ // SSH: git@github.com:org/repo.git
57
+ const match = remoteUrl.match(/github\.com[/:]([^/]+)\/([^/]+?)(\.git)?$/);
58
+ if (match) {
59
+ const org = match[1];
60
+ const repo = match[2].replace(/\.git$/, '');
61
+ return { org, repo };
62
+ }
63
+ return null;
64
+ }
65
+ catch {
66
+ // Not a git repository or no origin remote
67
+ return null;
68
+ }
69
+ }
70
+ /**
71
+ * Validate if current directory is a git repository
72
+ *
73
+ * @returns true if current directory is a git repository
74
+ */
75
+ export function isGitRepository() {
76
+ try {
77
+ const git = new Git();
78
+ git.exec('rev-parse --git-dir');
79
+ return true;
80
+ }
81
+ catch {
82
+ return false;
83
+ }
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fractary/faber-cli",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "FABER CLI - Command-line interface for FABER development toolkit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -40,10 +40,12 @@
40
40
  "@fractary/faber": "^2.1.1",
41
41
  "ajv": "^8.12.0",
42
42
  "chalk": "^5.0.0",
43
- "commander": "^12.0.0"
43
+ "commander": "^12.0.0",
44
+ "jsonwebtoken": "^9.0.0"
44
45
  },
45
46
  "devDependencies": {
46
47
  "@types/jest": "^30.0.0",
48
+ "@types/jsonwebtoken": "^9.0.0",
47
49
  "@types/node": "^20.19.26",
48
50
  "@typescript-eslint/eslint-plugin": "^6.19.0",
49
51
  "@typescript-eslint/parser": "^6.19.0",