@fractary/faber-cli 1.1.0 → 1.2.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.
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Anthropic API Client
3
+ *
4
+ * Generates workflow plans via Claude API
5
+ */
6
+ import Anthropic from '@anthropic-ai/sdk';
7
+ import Ajv from 'ajv';
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { Git } from '@fractary/faber';
12
+ import { validateJsonSize } from '../utils/validation.js';
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ /**
16
+ * Anthropic API Client
17
+ */
18
+ export class AnthropicClient {
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.git = new Git();
22
+ this.ajv = new Ajv({ strict: false }); // Allow additional properties
23
+ const apiKey = config.anthropic?.api_key;
24
+ if (!apiKey) {
25
+ throw new Error('Anthropic API key not found. Set ANTHROPIC_API_KEY environment variable.');
26
+ }
27
+ this.client = new Anthropic({
28
+ apiKey,
29
+ });
30
+ }
31
+ /**
32
+ * Load plan JSON schema for validation
33
+ */
34
+ async loadPlanSchema() {
35
+ if (this.planSchema) {
36
+ return; // Already loaded
37
+ }
38
+ try {
39
+ // Schema path relative to this file
40
+ const schemaPath = path.resolve(__dirname, '../../../plugins/faber/config/schemas/plan.schema.json');
41
+ const schemaContent = await fs.readFile(schemaPath, 'utf8');
42
+ this.planSchema = JSON.parse(schemaContent);
43
+ }
44
+ catch (error) {
45
+ // Schema not found or invalid - log warning but don't fail
46
+ console.warn('Warning: Could not load plan schema for validation:', error instanceof Error ? error.message : 'Unknown error');
47
+ this.planSchema = null;
48
+ }
49
+ }
50
+ /**
51
+ * Validate plan JSON against schema
52
+ */
53
+ validatePlan(plan) {
54
+ if (!this.planSchema) {
55
+ // Schema not loaded - skip validation
56
+ return;
57
+ }
58
+ const validate = this.ajv.compile(this.planSchema);
59
+ const valid = validate(plan);
60
+ if (!valid) {
61
+ const errors = validate.errors?.map(e => `${e.instancePath} ${e.message}`).join(', ') || 'Unknown validation errors';
62
+ throw new Error(`Plan JSON validation failed: ${errors}`);
63
+ }
64
+ }
65
+ /**
66
+ * Generate workflow plan via Claude API
67
+ */
68
+ async generatePlan(input) {
69
+ // Load plan schema for validation
70
+ await this.loadPlanSchema();
71
+ // Load workflow configuration
72
+ const workflowConfig = await this.loadWorkflowConfig(input.workflow);
73
+ // Generate plan ID
74
+ const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d+Z/, '').replace('T', '-');
75
+ const planId = `fractary-faber-${input.issueNumber}-${timestamp}`;
76
+ // Construct prompt for Claude
77
+ const prompt = this.constructPlanningPrompt(input, workflowConfig);
78
+ // Call Claude API
79
+ const response = await this.client.messages.create({
80
+ model: 'claude-sonnet-4-5-20250929',
81
+ max_tokens: 8192,
82
+ messages: [
83
+ {
84
+ role: 'user',
85
+ content: prompt,
86
+ },
87
+ ],
88
+ });
89
+ // Extract plan JSON from response
90
+ const content = response.content[0];
91
+ if (content.type !== 'text') {
92
+ throw new Error('Unexpected response type from Claude API');
93
+ }
94
+ // Validate response size (prevent DoS)
95
+ validateJsonSize(content.text, 1024 * 1024); // 1MB limit
96
+ const planJson = this.extractJsonFromResponse(content.text);
97
+ // Add metadata
98
+ const { organization, project } = await this.extractRepoInfo();
99
+ const plan = {
100
+ ...planJson,
101
+ plan_id: planId,
102
+ created_by: 'cli',
103
+ cli_version: '1.0.0',
104
+ created_at: new Date().toISOString(),
105
+ issue: {
106
+ source: 'github',
107
+ id: input.issueNumber.toString(),
108
+ url: `https://github.com/${organization}/${project}/issues/${input.issueNumber}`,
109
+ },
110
+ branch: `feature/${input.issueNumber}`,
111
+ worktree: `~/.claude-worktrees/${organization}-${project}-${input.issueNumber}`,
112
+ workflow: input.workflow,
113
+ };
114
+ // Validate plan against schema
115
+ this.validatePlan(plan);
116
+ return plan;
117
+ }
118
+ /**
119
+ * Load workflow configuration
120
+ */
121
+ async loadWorkflowConfig(workflow) {
122
+ const workflowPath = path.join(this.config.workflow?.config_path || './plugins/faber/config/workflows', `${workflow}.json`);
123
+ try {
124
+ const content = await fs.readFile(workflowPath, 'utf-8');
125
+ return JSON.parse(content);
126
+ }
127
+ catch (error) {
128
+ throw new Error(`Failed to load workflow config: ${workflow} (${workflowPath})`);
129
+ }
130
+ }
131
+ /**
132
+ * Construct planning prompt for Claude
133
+ */
134
+ constructPlanningPrompt(input, workflowConfig) {
135
+ return `You are a workflow planning assistant for the FABER system. Your task is to generate a structured workflow plan based on the provided issue and workflow configuration.
136
+
137
+ **Issue Information:**
138
+ - Number: #${input.issueNumber}
139
+ - Title: ${input.issueTitle}
140
+ - Description: ${input.issueDescription}
141
+
142
+ **Workflow Type:** ${input.workflow}
143
+
144
+ **Workflow Configuration:**
145
+ ${JSON.stringify(workflowConfig, null, 2)}
146
+
147
+ **Your Task:**
148
+ Generate a complete workflow plan that includes:
149
+ 1. All phases from the workflow configuration
150
+ 2. Specific steps for each phase based on the issue requirements
151
+ 3. Success criteria for each phase
152
+ 4. Estimated complexity
153
+
154
+ **Output Format:**
155
+ Return ONLY a valid JSON object with the following structure:
156
+
157
+ \`\`\`json
158
+ {
159
+ "phases": [
160
+ {
161
+ "phase": "phase_name",
162
+ "description": "What this phase accomplishes",
163
+ "steps": [
164
+ {
165
+ "action": "specific action to take",
166
+ "details": "additional context or requirements"
167
+ }
168
+ ],
169
+ "success_criteria": [
170
+ "criterion 1",
171
+ "criterion 2"
172
+ ],
173
+ "complexity": "low|medium|high"
174
+ }
175
+ ],
176
+ "overall_complexity": "low|medium|high",
177
+ "estimated_phases": 4,
178
+ "special_considerations": [
179
+ "Any special notes or warnings"
180
+ ]
181
+ }
182
+ \`\`\`
183
+
184
+ Generate the plan now:`;
185
+ }
186
+ /**
187
+ * Extract JSON from Claude response
188
+ */
189
+ extractJsonFromResponse(text) {
190
+ // Try to find JSON in code blocks
191
+ const jsonBlockMatch = text.match(/```json\s*\n([\s\S]*?)\n```/);
192
+ if (jsonBlockMatch) {
193
+ return JSON.parse(jsonBlockMatch[1]);
194
+ }
195
+ // Try to find JSON in the text
196
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
197
+ if (jsonMatch) {
198
+ return JSON.parse(jsonMatch[0]);
199
+ }
200
+ throw new Error('Could not extract JSON from Claude response');
201
+ }
202
+ /**
203
+ * Extract repository organization and project name using SDK Git class
204
+ */
205
+ async extractRepoInfo() {
206
+ try {
207
+ const remoteUrl = this.git.exec('remote get-url origin');
208
+ // Parse git@github.com:organization/project.git or https://github.com/organization/project.git
209
+ const match = remoteUrl.match(/[:/]([^/]+)\/([^/]+?)(?:\.git)?$/);
210
+ if (match) {
211
+ return {
212
+ organization: match[1],
213
+ project: match[2],
214
+ };
215
+ }
216
+ }
217
+ catch (error) {
218
+ // Fall back to config or defaults
219
+ }
220
+ return {
221
+ organization: this.config.github?.organization || 'unknown',
222
+ project: this.config.github?.project || 'unknown',
223
+ };
224
+ }
225
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Configuration Manager
3
+ *
4
+ * Loads FABER CLI configuration and respects Claude Code settings
5
+ */
6
+ import type { FaberConfig } from '../types/config.js';
7
+ /**
8
+ * Configuration Manager
9
+ */
10
+ export declare class ConfigManager {
11
+ private config;
12
+ private constructor();
13
+ /**
14
+ * Load configuration
15
+ */
16
+ static load(): Promise<FaberConfig>;
17
+ /**
18
+ * Read Claude Code configuration for worktree location
19
+ */
20
+ private static readClaudeCodeWorktreeLocation;
21
+ /**
22
+ * Get Claude Code configuration paths by platform
23
+ */
24
+ private static getClaudeConfigPaths;
25
+ /**
26
+ * Get configuration value
27
+ */
28
+ get(key: keyof FaberConfig): any;
29
+ }
30
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,oBAAoB,CAAC;AAEpE;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO;IAIP;;OAEG;WACU,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAgEzC;;OAEG;mBACkB,8BAA8B;IAoBnD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAyBnC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,WAAW,GAAG,GAAG;CAGjC"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Configuration Manager
3
+ *
4
+ * Loads FABER CLI configuration and respects Claude Code settings
5
+ */
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import os from 'os';
9
+ /**
10
+ * Configuration Manager
11
+ */
12
+ export class ConfigManager {
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ /**
17
+ * Load configuration
18
+ */
19
+ static async load() {
20
+ const config = {};
21
+ // Load from environment variables
22
+ config.anthropic = {
23
+ api_key: process.env.ANTHROPIC_API_KEY,
24
+ };
25
+ config.github = {
26
+ token: process.env.GITHUB_TOKEN,
27
+ };
28
+ // Load from FABER config file
29
+ try {
30
+ const faberConfigPath = path.join(process.cwd(), '.fractary', 'settings.json');
31
+ const faberConfigContent = await fs.readFile(faberConfigPath, 'utf-8');
32
+ const faberConfig = JSON.parse(faberConfigContent);
33
+ // Merge with config
34
+ if (faberConfig.anthropic) {
35
+ config.anthropic = { ...config.anthropic, ...faberConfig.anthropic };
36
+ }
37
+ if (faberConfig.github) {
38
+ config.github = { ...config.github, ...faberConfig.github };
39
+ }
40
+ if (faberConfig.worktree) {
41
+ config.worktree = { ...config.worktree, ...faberConfig.worktree };
42
+ }
43
+ if (faberConfig.workflow) {
44
+ config.workflow = { ...config.workflow, ...faberConfig.workflow };
45
+ }
46
+ }
47
+ catch (error) {
48
+ // FABER config not found, use defaults
49
+ }
50
+ // Read Claude Code configuration for worktree location
51
+ if (!config.worktree?.location || config.worktree?.inherit_from_claude !== false) {
52
+ const claudeWorktreeLocation = await ConfigManager.readClaudeCodeWorktreeLocation();
53
+ if (claudeWorktreeLocation) {
54
+ if (!config.worktree) {
55
+ config.worktree = {};
56
+ }
57
+ config.worktree.location = claudeWorktreeLocation;
58
+ }
59
+ }
60
+ // Set defaults
61
+ if (!config.worktree?.location) {
62
+ config.worktree = {
63
+ ...config.worktree,
64
+ location: path.join(os.homedir(), '.claude-worktrees'),
65
+ };
66
+ }
67
+ if (!config.workflow?.config_path) {
68
+ config.workflow = {
69
+ ...config.workflow,
70
+ config_path: path.join(process.cwd(), 'plugins', 'faber', 'config', 'workflows'),
71
+ };
72
+ }
73
+ return config;
74
+ }
75
+ /**
76
+ * Read Claude Code configuration for worktree location
77
+ */
78
+ static async readClaudeCodeWorktreeLocation() {
79
+ const configPaths = ConfigManager.getClaudeConfigPaths();
80
+ for (const configPath of configPaths) {
81
+ try {
82
+ const content = await fs.readFile(configPath, 'utf-8');
83
+ const config = JSON.parse(content);
84
+ if (config.worktree?.directory) {
85
+ return config.worktree.directory;
86
+ }
87
+ }
88
+ catch (error) {
89
+ // Config file not found or not readable, try next
90
+ continue;
91
+ }
92
+ }
93
+ return null;
94
+ }
95
+ /**
96
+ * Get Claude Code configuration paths by platform
97
+ */
98
+ static getClaudeConfigPaths() {
99
+ const homeDir = os.homedir();
100
+ const platform = os.platform();
101
+ switch (platform) {
102
+ case 'linux':
103
+ return [
104
+ path.join(homeDir, '.config', 'claude', 'config.json'),
105
+ path.join(homeDir, '.claude', 'config.json'),
106
+ ];
107
+ case 'darwin': // macOS
108
+ return [
109
+ path.join(homeDir, 'Library', 'Application Support', 'Claude', 'config.json'),
110
+ path.join(homeDir, '.config', 'claude', 'config.json'),
111
+ ];
112
+ case 'win32': // Windows
113
+ return [
114
+ path.join(process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming'), 'Claude', 'config.json'),
115
+ path.join(homeDir, '.claude', 'config.json'),
116
+ ];
117
+ default:
118
+ return [path.join(homeDir, '.claude', 'config.json')];
119
+ }
120
+ }
121
+ /**
122
+ * Get configuration value
123
+ */
124
+ get(key) {
125
+ return this.config[key];
126
+ }
127
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Repo Client
3
+ *
4
+ * Wrapper for fractary-repo plugin commands (CLI-based)
5
+ */
6
+ interface Issue {
7
+ id: string;
8
+ number: number;
9
+ title: string;
10
+ description: string;
11
+ labels: string[];
12
+ url: string;
13
+ state: string;
14
+ }
15
+ interface WorktreeResult {
16
+ path: string;
17
+ absolute_path: string;
18
+ branch: string;
19
+ created_at: string;
20
+ organization: string;
21
+ project: string;
22
+ work_id: string;
23
+ }
24
+ interface IssueUpdateOptions {
25
+ id: string;
26
+ comment?: string;
27
+ addLabel?: string;
28
+ removeLabel?: string;
29
+ }
30
+ /**
31
+ * Repo Client - wraps fractary-repo plugin CLI operations
32
+ *
33
+ * Note: This calls fractary-repo CLI commands as specified in SPEC-00030.
34
+ * These commands must be implemented in the fractary-repo plugin.
35
+ */
36
+ export declare class RepoClient {
37
+ private config;
38
+ constructor(config: any);
39
+ /**
40
+ * Fetch specific issues by ID
41
+ *
42
+ * Calls: fractary-repo issue-fetch --ids 258,259,260 --format json
43
+ */
44
+ fetchIssues(ids: string[]): Promise<Issue[]>;
45
+ /**
46
+ * Search issues by labels
47
+ *
48
+ * Calls: fractary-repo issue-search --labels "workflow:etl,status:approved" --format json
49
+ */
50
+ searchIssues(labels: string[]): Promise<Issue[]>;
51
+ /**
52
+ * Create a git branch
53
+ *
54
+ * Calls: fractary-repo branch-create <branch-name> --format json
55
+ */
56
+ createBranch(branchName: string): Promise<void>;
57
+ /**
58
+ * Create a git worktree
59
+ *
60
+ * Calls: fractary-repo worktree-create --work-id 258 --format json
61
+ */
62
+ createWorktree(options: {
63
+ workId: string;
64
+ path?: string;
65
+ }): Promise<WorktreeResult>;
66
+ /**
67
+ * Update GitHub issue
68
+ *
69
+ * Calls: fractary-repo issue-update --id 258 --comment "..." --add-label "..."
70
+ */
71
+ updateIssue(options: IssueUpdateOptions): Promise<void>;
72
+ /**
73
+ * Call fractary-repo CLI command
74
+ *
75
+ * This will be implemented to spawn fractary-repo CLI process safely.
76
+ * For now, this is a placeholder showing the intended interface.
77
+ */
78
+ private callRepoCommand;
79
+ }
80
+ export {};
81
+ //# sourceMappingURL=repo-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-client.d.ts","sourceRoot":"","sources":["../../src/lib/repo-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,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;gBAER,MAAM,EAAE,GAAG;IASvB;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAQlD;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAQtD;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrD;;;;OAIG;IACG,cAAc,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAazF;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7D;;;;;OAKG;YACW,eAAe;CAU9B"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Repo Client
3
+ *
4
+ * Wrapper for fractary-repo plugin commands (CLI-based)
5
+ */
6
+ /**
7
+ * Repo Client - wraps fractary-repo plugin CLI operations
8
+ *
9
+ * Note: This calls fractary-repo CLI commands as specified in SPEC-00030.
10
+ * These commands must be implemented in the fractary-repo plugin.
11
+ */
12
+ export class RepoClient {
13
+ constructor(config) {
14
+ this.config = config;
15
+ const token = config.github?.token;
16
+ if (!token) {
17
+ throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable.');
18
+ }
19
+ }
20
+ /**
21
+ * Fetch specific issues by ID
22
+ *
23
+ * Calls: fractary-repo issue-fetch --ids 258,259,260 --format json
24
+ */
25
+ async fetchIssues(ids) {
26
+ // TODO: Call fractary-repo CLI when available
27
+ // const result = await this.callRepoCommand('issue-fetch', ['--ids', ids.join(','), '--format', 'json']);
28
+ // Placeholder implementation
29
+ throw new Error('fractary-repo issue-fetch command not yet implemented. See SPEC-00030.');
30
+ }
31
+ /**
32
+ * Search issues by labels
33
+ *
34
+ * Calls: fractary-repo issue-search --labels "workflow:etl,status:approved" --format json
35
+ */
36
+ async searchIssues(labels) {
37
+ // TODO: Call fractary-repo CLI when available
38
+ // const result = await this.callRepoCommand('issue-search', ['--labels', labels.join(','), '--format', 'json']);
39
+ // Placeholder implementation
40
+ throw new Error('fractary-repo issue-search command not yet implemented. See SPEC-00030.');
41
+ }
42
+ /**
43
+ * Create a git branch
44
+ *
45
+ * Calls: fractary-repo branch-create <branch-name> --format json
46
+ */
47
+ async createBranch(branchName) {
48
+ // TODO: Call fractary-repo CLI when available
49
+ // await this.callRepoCommand('branch-create', [branchName, '--format', 'json']);
50
+ // Placeholder implementation
51
+ throw new Error('fractary-repo branch-create command not yet implemented. See SPEC-00030.');
52
+ }
53
+ /**
54
+ * Create a git worktree
55
+ *
56
+ * Calls: fractary-repo worktree-create --work-id 258 --format json
57
+ */
58
+ async createWorktree(options) {
59
+ // TODO: Call fractary-repo CLI when available
60
+ // const args = ['--work-id', options.workId, '--format', 'json'];
61
+ // if (options.path) {
62
+ // args.push('--path', options.path);
63
+ // }
64
+ // const result = await this.callRepoCommand('worktree-create', args);
65
+ // return result;
66
+ // Placeholder implementation
67
+ throw new Error('fractary-repo worktree-create command not yet implemented. See SPEC-00030.');
68
+ }
69
+ /**
70
+ * Update GitHub issue
71
+ *
72
+ * Calls: fractary-repo issue-update --id 258 --comment "..." --add-label "..."
73
+ */
74
+ async updateIssue(options) {
75
+ // TODO: Call fractary-repo CLI when available
76
+ // const args = ['--id', options.id];
77
+ // if (options.comment) {
78
+ // args.push('--comment', options.comment);
79
+ // }
80
+ // if (options.addLabel) {
81
+ // args.push('--add-label', options.addLabel);
82
+ // }
83
+ // if (options.removeLabel) {
84
+ // args.push('--remove-label', options.removeLabel);
85
+ // }
86
+ // await this.callRepoCommand('issue-update', args);
87
+ // Placeholder implementation
88
+ throw new Error('fractary-repo issue-update command not yet implemented. See SPEC-00030.');
89
+ }
90
+ /**
91
+ * Call fractary-repo CLI command
92
+ *
93
+ * This will be implemented to spawn fractary-repo CLI process safely.
94
+ * For now, this is a placeholder showing the intended interface.
95
+ */
96
+ async callRepoCommand(command, args) {
97
+ // Implementation will use safe process spawning to call:
98
+ // fractary-repo <command> [args...]
99
+ //
100
+ // Example: fractary-repo issue-fetch --ids 258,259 --format json
101
+ //
102
+ // The command will return JSON which we parse and return.
103
+ throw new Error(`fractary-repo ${command} not yet implemented`);
104
+ }
105
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * FABER CLI Configuration Types
3
+ *
4
+ * Type definitions for configuration objects
5
+ */
6
+ export interface AnthropicConfig {
7
+ api_key?: string;
8
+ }
9
+ export interface GitHubConfig {
10
+ token?: string;
11
+ organization?: string;
12
+ project?: string;
13
+ repo?: string;
14
+ }
15
+ export interface WorktreeConfig {
16
+ location?: string;
17
+ inherit_from_claude?: boolean;
18
+ }
19
+ export interface WorkflowConfig {
20
+ default?: string;
21
+ config_path?: string;
22
+ }
23
+ export interface FaberConfig {
24
+ anthropic?: AnthropicConfig;
25
+ github?: GitHubConfig;
26
+ worktree?: WorktreeConfig;
27
+ workflow?: WorkflowConfig;
28
+ }
29
+ export interface ClaudeConfig {
30
+ worktree?: {
31
+ directory?: string;
32
+ };
33
+ }
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * FABER CLI Configuration Types
3
+ *
4
+ * Type definitions for configuration objects
5
+ */
6
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Simple prompt utility for CLI input
3
+ */
4
+ /**
5
+ * Prompt user for input
6
+ */
7
+ export declare function prompt(question: string): Promise<string>;
8
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYxD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Simple prompt utility for CLI input
3
+ */
4
+ import * as readline from 'readline';
5
+ /**
6
+ * Prompt user for input
7
+ */
8
+ export function prompt(question) {
9
+ const rl = readline.createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout,
12
+ });
13
+ return new Promise((resolve) => {
14
+ rl.question(question, (answer) => {
15
+ rl.close();
16
+ resolve(answer.trim());
17
+ });
18
+ });
19
+ }