@fractary/faber-cli 1.4.4 → 1.5.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,213 @@
1
+ /**
2
+ * Migrate command - Convert .fractary/settings.json to .fractary/config.yaml
3
+ *
4
+ * Migrates old FABER configuration to the unified config format.
5
+ * After migration, settings.json is backed up and all FABER commands use config.yaml.
6
+ */
7
+ import { Command } from 'commander';
8
+ import chalk from 'chalk';
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+ import * as yaml from 'js-yaml';
12
+ import { loadYamlConfig, writeYamlConfig, findProjectRoot, configExists, oldSettingsExists, getOldSettingsPath, getConfigPath } from '../lib/yaml-config.js';
13
+ export function createMigrateCommand() {
14
+ return new Command('migrate')
15
+ .description('Migrate from .fractary/settings.json to .fractary/config.yaml')
16
+ .option('--dry-run', 'Show what would be migrated without making changes')
17
+ .option('--no-backup', 'Do not create backup of old settings.json')
18
+ .option('--json', 'Output as JSON')
19
+ .action(async (options) => {
20
+ try {
21
+ const projectRoot = findProjectRoot();
22
+ const settingsPath = getOldSettingsPath(projectRoot);
23
+ const configPath = getConfigPath(projectRoot);
24
+ // Step 1: Check if settings.json exists
25
+ if (!oldSettingsExists(projectRoot)) {
26
+ if (options.json) {
27
+ console.log(JSON.stringify({
28
+ status: 'error',
29
+ error: {
30
+ message: 'No .fractary/settings.json found to migrate',
31
+ recommendation: 'If starting fresh, run: fractary-core:init'
32
+ }
33
+ }));
34
+ }
35
+ else {
36
+ console.error(chalk.red('Error: No .fractary/settings.json found to migrate'));
37
+ console.log();
38
+ console.log('If you\'re starting fresh, run:');
39
+ console.log(chalk.cyan(' fractary-core:init'));
40
+ console.log();
41
+ }
42
+ process.exit(1);
43
+ }
44
+ // Step 2: Load old settings
45
+ let oldSettings;
46
+ try {
47
+ const content = await fs.readFile(settingsPath, 'utf-8');
48
+ oldSettings = JSON.parse(content);
49
+ }
50
+ catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ if (options.json) {
53
+ console.log(JSON.stringify({
54
+ status: 'error',
55
+ error: { message: `Failed to parse settings.json: ${message}` }
56
+ }));
57
+ }
58
+ else {
59
+ console.error(chalk.red(`Error: Failed to parse settings.json: ${message}`));
60
+ }
61
+ process.exit(1);
62
+ }
63
+ // Step 3: Load existing config.yaml (if exists)
64
+ let config;
65
+ const configExistsAlready = configExists(projectRoot);
66
+ if (configExistsAlready) {
67
+ config = loadYamlConfig({ projectRoot }) || { version: '2.0' };
68
+ if (!options.json) {
69
+ console.log(chalk.yellow('Note: Existing config.yaml found - will merge settings'));
70
+ }
71
+ }
72
+ else {
73
+ config = { version: '2.0' };
74
+ }
75
+ // Step 4: Build migrated config
76
+ // Map old structure to new unified structure
77
+ if (oldSettings.anthropic) {
78
+ config.anthropic = {
79
+ ...config.anthropic,
80
+ ...oldSettings.anthropic
81
+ };
82
+ // Convert hardcoded API key to env var reference if present
83
+ if (config.anthropic?.api_key && !config.anthropic.api_key.startsWith('${')) {
84
+ if (!options.json) {
85
+ console.log(chalk.yellow('⚠️ Found hardcoded Anthropic API key'));
86
+ console.log(' Recommendation: Set ANTHROPIC_API_KEY environment variable');
87
+ console.log(' and use ${ANTHROPIC_API_KEY} in config.yaml');
88
+ console.log();
89
+ }
90
+ }
91
+ }
92
+ if (oldSettings.github) {
93
+ config.github = {
94
+ ...config.github,
95
+ ...oldSettings.github
96
+ };
97
+ // Warn about hardcoded tokens
98
+ if (config.github?.token && !config.github.token.startsWith('${')) {
99
+ if (!options.json) {
100
+ console.log(chalk.yellow('⚠️ Found hardcoded GitHub token'));
101
+ console.log(' Recommendation: Set GITHUB_TOKEN environment variable');
102
+ console.log(' and use ${GITHUB_TOKEN} in config.yaml');
103
+ console.log();
104
+ }
105
+ }
106
+ }
107
+ // Move FABER-specific settings to faber section
108
+ if (oldSettings.worktree || oldSettings.workflow || oldSettings.backlog_management) {
109
+ // Validate and convert backlog_management.default_order_by
110
+ let backlogManagement;
111
+ if (oldSettings.backlog_management) {
112
+ const validOrderBy = ['priority', 'created', 'updated', 'none'];
113
+ const orderBy = oldSettings.backlog_management.default_order_by;
114
+ backlogManagement = {
115
+ ...oldSettings.backlog_management,
116
+ default_order_by: orderBy && validOrderBy.includes(orderBy)
117
+ ? orderBy
118
+ : undefined
119
+ };
120
+ }
121
+ config.faber = {
122
+ ...config.faber,
123
+ ...(oldSettings.worktree && { worktree: oldSettings.worktree }),
124
+ ...(oldSettings.workflow && { workflow: oldSettings.workflow }),
125
+ ...(backlogManagement && { backlog_management: backlogManagement })
126
+ };
127
+ }
128
+ // Step 5: Handle dry-run
129
+ if (options.dryRun) {
130
+ const yamlContent = yaml.dump(config, {
131
+ indent: 2,
132
+ lineWidth: 100,
133
+ noRefs: true,
134
+ sortKeys: false,
135
+ });
136
+ if (options.json) {
137
+ console.log(JSON.stringify({
138
+ status: 'dry-run',
139
+ wouldWrite: configPath,
140
+ wouldBackup: options.backup !== false ? `${settingsPath}.backup` : null,
141
+ config: config
142
+ }, null, 2));
143
+ }
144
+ else {
145
+ console.log(chalk.cyan('Dry run - would write to config.yaml:'));
146
+ console.log();
147
+ console.log(yamlContent);
148
+ console.log();
149
+ if (options.backup !== false) {
150
+ console.log(chalk.gray(`Would backup: ${settingsPath} → ${settingsPath}.backup`));
151
+ }
152
+ }
153
+ return;
154
+ }
155
+ // Step 6: Write new config
156
+ writeYamlConfig(config, projectRoot);
157
+ // Step 7: Backup old settings
158
+ if (options.backup !== false) {
159
+ const backupPath = `${settingsPath}.backup`;
160
+ await fs.rename(settingsPath, backupPath);
161
+ if (options.json) {
162
+ console.log(JSON.stringify({
163
+ status: 'success',
164
+ configPath,
165
+ backupPath,
166
+ message: 'Successfully migrated to config.yaml'
167
+ }));
168
+ }
169
+ else {
170
+ console.log(chalk.green('✓ Successfully migrated to .fractary/config.yaml'));
171
+ console.log(chalk.green(`✓ Backup created at ${path.relative(projectRoot, backupPath)}`));
172
+ }
173
+ }
174
+ else {
175
+ // Delete old settings without backup
176
+ await fs.unlink(settingsPath);
177
+ if (options.json) {
178
+ console.log(JSON.stringify({
179
+ status: 'success',
180
+ configPath,
181
+ message: 'Successfully migrated to config.yaml (no backup)'
182
+ }));
183
+ }
184
+ else {
185
+ console.log(chalk.green('✓ Successfully migrated to .fractary/config.yaml'));
186
+ console.log(chalk.yellow('⚠️ Old settings.json deleted (no backup)'));
187
+ }
188
+ }
189
+ if (!options.json) {
190
+ console.log();
191
+ console.log('Next steps:');
192
+ console.log(' 1. Review .fractary/config.yaml');
193
+ console.log(' 2. Replace any hardcoded secrets with environment variable references');
194
+ console.log(' Example: api_key: ${ANTHROPIC_API_KEY}');
195
+ console.log(' 3. Consider running ' + chalk.cyan('fractary-core:init') + ' to set up other plugins');
196
+ console.log();
197
+ }
198
+ }
199
+ catch (error) {
200
+ const message = error instanceof Error ? error.message : String(error);
201
+ if (options.json) {
202
+ console.error(JSON.stringify({
203
+ status: 'error',
204
+ error: { message }
205
+ }));
206
+ }
207
+ else {
208
+ console.error(chalk.red('Error:'), message);
209
+ }
210
+ process.exit(1);
211
+ }
212
+ });
213
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA4IxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA4IxC"}
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import { createRepoCommand } from './commands/repo/index.js';
13
13
  import { createSpecCommand } from './commands/spec/index.js';
14
14
  import { createLogsCommand } from './commands/logs/index.js';
15
15
  import { createInitCommand } from './commands/init.js';
16
+ import { createMigrateCommand } from './commands/migrate.js';
16
17
  import { createPlanCommand } from './commands/plan/index.js';
17
18
  import { createAuthCommand } from './commands/auth/index.js';
18
19
  // Force unbuffered output to prevent buffering issues in terminals
@@ -32,9 +33,10 @@ export function createFaberCLI() {
32
33
  .enablePositionalOptions();
33
34
  // Global options
34
35
  program.option('--debug', 'Enable debug output');
35
- // Workflow commands (top-level) - NEW NAMES
36
- program.addCommand(createInitCommand()); // workflow-init
37
- program.addCommand(createPlanCommand()); // plan - NEW
36
+ // Workflow commands (top-level)
37
+ program.addCommand(createInitCommand()); // init
38
+ program.addCommand(createMigrateCommand()); // migrate
39
+ program.addCommand(createPlanCommand()); // plan
38
40
  program.addCommand(createRunCommand()); // workflow-run
39
41
  program.addCommand(createStatusCommand()); // workflow-status
40
42
  program.addCommand(createResumeCommand()); // workflow-resume
@@ -46,13 +48,12 @@ export function createFaberCLI() {
46
48
  console.warn(chalk.yellow(`\n⚠️ DEPRECATED: "${oldName}" → use "${newName}"\n`));
47
49
  };
48
50
  program
49
- .command('init')
50
- .description('(DEPRECATED: Use workflow-init)')
51
- .option('--preset <name>', 'Use a preset configuration', 'default')
51
+ .command('workflow-init')
52
+ .description('(DEPRECATED: Use init)')
52
53
  .option('--force', 'Overwrite existing configuration')
53
54
  .option('--json', 'Output as JSON')
54
55
  .action((options) => {
55
- showDeprecationWarning('init', 'workflow-init');
56
+ showDeprecationWarning('workflow-init', 'init');
56
57
  const initCmd = createInitCommand();
57
58
  initCmd.parse(['', '', ...Object.entries(options).flatMap(([k, v]) => typeof v === 'boolean' && v ? [`--${k}`] : typeof v === 'string' ? [`--${k}`, v] : [])], { from: 'user' });
58
59
  });
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generates workflow plans via Claude API
5
5
  */
6
- import type { FaberConfig } from '../types/config.js';
6
+ import type { LoadedFaberConfig } from '../types/config.js';
7
7
  interface GeneratePlanInput {
8
8
  workflow: string;
9
9
  issueTitle: string;
@@ -35,7 +35,7 @@ export declare class AnthropicClient {
35
35
  private git;
36
36
  private ajv;
37
37
  private planSchema;
38
- constructor(config: FaberConfig);
38
+ constructor(config: LoadedFaberConfig);
39
39
  /**
40
40
  * Load plan JSON schema for validation
41
41
  */
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-client.d.ts","sourceRoot":"","sources":["../../src/lib/anthropic-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,UAAU,CAAM;gBAEZ,MAAM,EAAE,WAAW;IAe/B;;OAEG;YACW,cAAc;IAiB5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6DnE;;OAEG;YACW,kBAAkB;IAchC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqD/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgB/B;;OAEG;YACW,eAAe;CAqB9B"}
1
+ {"version":3,"file":"anthropic-client.d.ts","sourceRoot":"","sources":["../../src/lib/anthropic-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAK5D,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,UAAU,CAAM;gBAEZ,MAAM,EAAE,iBAAiB;IAerC;;OAEG;YACW,cAAc;IAiB5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6DnE;;OAEG;YACW,kBAAkB;IAchC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqD/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgB/B;;OAEG;YACW,eAAe;CAqB9B"}
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Configuration Manager
3
3
  *
4
- * Loads FABER CLI configuration and respects Claude Code settings
4
+ * Loads FABER CLI configuration from unified .fractary/config.yaml
5
+ * and respects Claude Code settings
5
6
  */
6
- import type { FaberConfig } from '../types/config.js';
7
+ import type { FaberConfig, AnthropicConfig, GitHubConfig } from '../types/config.js';
7
8
  /**
8
9
  * Configuration Manager
9
10
  */
@@ -11,9 +12,13 @@ export declare class ConfigManager {
11
12
  private config;
12
13
  private constructor();
13
14
  /**
14
- * Load configuration
15
+ * Load configuration from unified .fractary/config.yaml
16
+ * Returns a FaberConfig structure with all necessary settings
15
17
  */
16
- static load(): Promise<FaberConfig>;
18
+ static load(): Promise<FaberConfig & {
19
+ anthropic?: AnthropicConfig;
20
+ github?: GitHubConfig;
21
+ }>;
17
22
  /**
18
23
  * Find config file by searching upwards from current directory
19
24
  * Similar to how git finds .git directory
@@ -1 +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;IAoFzC;;;OAGG;mBACkB,cAAc;IAwBnC;;OAEG;mBACkB,8BAA8B;IAoBnD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAyBnC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,WAAW,GAAG,GAAG;CAGjC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAiB,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGpG;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO;IAIP;;;OAGG;WACU,IAAI,IAAI,OAAO,CAAC,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,eAAe,CAAC;QAAC,MAAM,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;IAiGlG;;;OAGG;mBACkB,cAAc;IAwBnC;;OAEG;mBACkB,8BAA8B;IAoBnD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAyBnC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,WAAW,GAAG,GAAG;CAGjC"}
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Configuration Manager
3
3
  *
4
- * Loads FABER CLI configuration and respects Claude Code settings
4
+ * Loads FABER CLI configuration from unified .fractary/config.yaml
5
+ * and respects Claude Code settings
5
6
  */
6
7
  import fs from 'fs/promises';
7
8
  import path from 'path';
8
9
  import os from 'os';
10
+ import { loadYamlConfig, oldSettingsExists, getOldSettingsPath } from './yaml-config.js';
9
11
  /**
10
12
  * Configuration Manager
11
13
  */
@@ -14,41 +16,48 @@ export class ConfigManager {
14
16
  this.config = config;
15
17
  }
16
18
  /**
17
- * Load configuration
19
+ * Load configuration from unified .fractary/config.yaml
20
+ * Returns a FaberConfig structure with all necessary settings
18
21
  */
19
22
  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 - search upwards from current directory
29
- try {
30
- const faberConfigPath = await ConfigManager.findConfigFile('.fractary', 'settings.json');
31
- if (faberConfigPath) {
32
- const faberConfigContent = await fs.readFile(faberConfigPath, 'utf-8');
33
- const faberConfig = JSON.parse(faberConfigContent);
34
- // Merge with config
35
- if (faberConfig.anthropic) {
36
- config.anthropic = { ...config.anthropic, ...faberConfig.anthropic };
37
- }
38
- if (faberConfig.github) {
39
- config.github = { ...config.github, ...faberConfig.github };
40
- }
41
- if (faberConfig.worktree) {
42
- config.worktree = { ...config.worktree, ...faberConfig.worktree };
43
- }
44
- if (faberConfig.workflow) {
45
- config.workflow = { ...config.workflow, ...faberConfig.workflow };
46
- }
47
- }
23
+ // Check if old settings.json exists and show error
24
+ if (oldSettingsExists()) {
25
+ const oldPath = getOldSettingsPath();
26
+ throw new Error(`Found old configuration at ${oldPath}\n\n` +
27
+ `This version requires .fractary/config.yaml format.\n` +
28
+ `Run: fractary-faber migrate\n\n` +
29
+ `This will convert your settings to the new unified config format.`);
48
30
  }
49
- catch (error) {
50
- // FABER config not found, use defaults
31
+ // Load unified config from YAML
32
+ const unifiedConfig = loadYamlConfig({ warnMissingEnvVars: true });
33
+ if (!unifiedConfig) {
34
+ throw new Error('No .fractary/config.yaml found.\n' +
35
+ 'Run `fractary-core:init` first to initialize shared configuration.');
51
36
  }
37
+ // Extract anthropic config (from top level)
38
+ let anthropic = {
39
+ api_key: process.env.ANTHROPIC_API_KEY || unifiedConfig.anthropic?.api_key,
40
+ model: unifiedConfig.anthropic?.model,
41
+ max_tokens: unifiedConfig.anthropic?.max_tokens,
42
+ };
43
+ // Extract github config (from top level)
44
+ let github = {
45
+ token: process.env.GITHUB_TOKEN || unifiedConfig.github?.token,
46
+ organization: unifiedConfig.github?.organization,
47
+ project: unifiedConfig.github?.project,
48
+ repo: unifiedConfig.github?.repo,
49
+ app: unifiedConfig.github?.app,
50
+ };
51
+ // Extract FABER-specific config
52
+ const faberConfig = unifiedConfig.faber || {};
53
+ // Build the result config (keeping anthropic and github for backward compatibility)
54
+ const config = {
55
+ anthropic,
56
+ github,
57
+ worktree: faberConfig.worktree,
58
+ workflow: faberConfig.workflow,
59
+ backlog_management: faberConfig.backlog_management,
60
+ };
52
61
  // Read Claude Code configuration for worktree location
53
62
  if (!config.worktree?.location || config.worktree?.inherit_from_claude !== false) {
54
63
  const claudeWorktreeLocation = await ConfigManager.readClaudeCodeWorktreeLocation();
@@ -5,7 +5,7 @@
5
5
  * Supports both PAT and GitHub App authentication methods.
6
6
  */
7
7
  import { WorkManager, RepoManager } from '@fractary/core';
8
- import type { FaberConfig } from '../types/config.js';
8
+ import type { LoadedFaberConfig } from '../types/config.js';
9
9
  interface Issue {
10
10
  id: string;
11
11
  number: number;
@@ -51,7 +51,7 @@ export declare class RepoClient {
51
51
  * @param config - FABER CLI configuration
52
52
  * @returns Promise resolving to RepoClient instance
53
53
  */
54
- static create(config: FaberConfig): Promise<RepoClient>;
54
+ static create(config: LoadedFaberConfig): Promise<RepoClient>;
55
55
  /**
56
56
  * Create a RepoClient instance
57
57
  *
@@ -59,7 +59,7 @@ export declare class RepoClient {
59
59
  * @param workManager - Optional pre-initialized WorkManager (for async factory)
60
60
  * @param repoManager - Optional pre-initialized RepoManager (for async factory)
61
61
  */
62
- constructor(config: FaberConfig, workManager?: WorkManager, repoManager?: RepoManager);
62
+ constructor(config: LoadedFaberConfig, workManager?: WorkManager, repoManager?: RepoManager);
63
63
  /**
64
64
  * Fetch specific issues by ID
65
65
  *
@@ -1 +1 @@
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"}
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,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,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,CAAoB;IAClC,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,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAmBnE;;;;;;OAMG;gBACS,MAAM,EAAE,iBAAiB,EAAE,WAAW,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW;IA0C3F;;;;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"}
@@ -4,7 +4,7 @@
4
4
  * Converts FABER CLI configuration to @fractary/core SDK configuration format
5
5
  * Supports both PAT and GitHub App authentication methods.
6
6
  */
7
- import type { FaberConfig } from '../types/config.js';
7
+ import type { LoadedFaberConfig } from '../types/config.js';
8
8
  import type { WorkConfig, RepoConfig } from '@fractary/core';
9
9
  import { TokenProvider } from './github-app-auth.js';
10
10
  /**
@@ -14,7 +14,7 @@ import { TokenProvider } from './github-app-auth.js';
14
14
  * @param faberConfig - FABER CLI configuration
15
15
  * @returns Promise resolving to the current token
16
16
  */
17
- export declare function getToken(faberConfig: FaberConfig): Promise<string>;
17
+ export declare function getToken(faberConfig: LoadedFaberConfig): Promise<string>;
18
18
  /**
19
19
  * Get the token provider for dynamic token refresh
20
20
  * Useful for long-running operations that need fresh tokens
@@ -22,21 +22,21 @@ export declare function getToken(faberConfig: FaberConfig): Promise<string>;
22
22
  * @param faberConfig - FABER CLI configuration
23
23
  * @returns TokenProvider instance
24
24
  */
25
- export declare function getTokenProviderInstance(faberConfig: FaberConfig): TokenProvider;
25
+ export declare function getTokenProviderInstance(faberConfig: LoadedFaberConfig): TokenProvider;
26
26
  /**
27
27
  * Validate GitHub authentication configuration
28
28
  *
29
29
  * @param faberConfig - FABER CLI configuration
30
30
  * @throws Error if configuration is invalid
31
31
  */
32
- export declare function validateGitHubAuth(faberConfig: FaberConfig): Promise<void>;
32
+ export declare function validateGitHubAuth(faberConfig: LoadedFaberConfig): Promise<void>;
33
33
  /**
34
34
  * Check if GitHub App authentication is configured
35
35
  *
36
36
  * @param faberConfig - FABER CLI configuration
37
37
  * @returns true if GitHub App is configured
38
38
  */
39
- export declare function isGitHubAppConfigured(faberConfig: FaberConfig): boolean;
39
+ export declare function isGitHubAppConfigured(faberConfig: LoadedFaberConfig): boolean;
40
40
  /**
41
41
  * Create WorkConfig for WorkManager from FaberConfig
42
42
  *
@@ -44,7 +44,7 @@ export declare function isGitHubAppConfigured(faberConfig: FaberConfig): boolean
44
44
  * @returns WorkConfig for @fractary/core WorkManager
45
45
  * @throws Error if required fields are missing
46
46
  */
47
- export declare function createWorkConfig(faberConfig: FaberConfig): WorkConfig;
47
+ export declare function createWorkConfig(faberConfig: LoadedFaberConfig): WorkConfig;
48
48
  /**
49
49
  * Create WorkConfig for WorkManager from FaberConfig (async version)
50
50
  *
@@ -54,7 +54,7 @@ export declare function createWorkConfig(faberConfig: FaberConfig): WorkConfig;
54
54
  * @returns Promise resolving to WorkConfig for @fractary/core WorkManager
55
55
  * @throws Error if required fields are missing
56
56
  */
57
- export declare function createWorkConfigAsync(faberConfig: FaberConfig): Promise<WorkConfig>;
57
+ export declare function createWorkConfigAsync(faberConfig: LoadedFaberConfig): Promise<WorkConfig>;
58
58
  /**
59
59
  * Create RepoConfig for RepoManager from FaberConfig
60
60
  *
@@ -62,7 +62,7 @@ export declare function createWorkConfigAsync(faberConfig: FaberConfig): Promise
62
62
  * @returns RepoConfig for @fractary/core RepoManager
63
63
  * @throws Error if required fields are missing
64
64
  */
65
- export declare function createRepoConfig(faberConfig: FaberConfig): RepoConfig;
65
+ export declare function createRepoConfig(faberConfig: LoadedFaberConfig): RepoConfig;
66
66
  /**
67
67
  * Create RepoConfig for RepoManager from FaberConfig (async version)
68
68
  *
@@ -72,5 +72,5 @@ export declare function createRepoConfig(faberConfig: FaberConfig): RepoConfig;
72
72
  * @returns Promise resolving to RepoConfig for @fractary/core RepoManager
73
73
  * @throws Error if required fields are missing
74
74
  */
75
- export declare function createRepoConfigAsync(faberConfig: FaberConfig): Promise<RepoConfig>;
75
+ export declare function createRepoConfigAsync(faberConfig: LoadedFaberConfig): Promise<RepoConfig>;
76
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;;;;;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"}
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;AA2D9B;;;;;;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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Unified YAML Configuration Loader for FABER CLI
3
+ *
4
+ * Loads and parses `.fractary/config.yaml` with environment variable substitution.
5
+ * Provides access to shared configuration for FABER and fractary-core plugins.
6
+ */
7
+ export type { AnthropicConfig, GitHubAppConfig, GitHubConfig, WorktreeConfig, WorkflowConfig, BacklogManagementConfig, FaberConfig, UnifiedConfig, ConfigLoadOptions, } from '../types/config.js';
8
+ import type { UnifiedConfig, ConfigLoadOptions } from '../types/config.js';
9
+ /**
10
+ * Load and parse `.fractary/config.yaml` with environment variable substitution
11
+ *
12
+ * @param options Configuration loading options
13
+ * @returns Parsed configuration object or null if not found
14
+ * @throws Error if config is invalid or throwIfMissing is true and file doesn't exist
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const config = loadYamlConfig();
19
+ * if (config?.github) {
20
+ * console.log('GitHub config:', config.github);
21
+ * }
22
+ * ```
23
+ */
24
+ export declare function loadYamlConfig(options?: ConfigLoadOptions): UnifiedConfig | null;
25
+ /**
26
+ * Write unified configuration to `.fractary/config.yaml`
27
+ *
28
+ * @param config Configuration object to write
29
+ * @param projectRoot Project root directory (auto-detected if not provided)
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * writeYamlConfig({
34
+ * version: '2.0',
35
+ * github: {
36
+ * organization: 'myorg',
37
+ * project: 'myrepo'
38
+ * }
39
+ * });
40
+ * ```
41
+ */
42
+ export declare function writeYamlConfig(config: UnifiedConfig, projectRoot?: string): void;
43
+ /**
44
+ * Substitute ${ENV_VAR} placeholders with actual environment variables
45
+ *
46
+ * Supports:
47
+ * - ${VAR_NAME} - Replace with env var value
48
+ * - ${VAR_NAME:-default} - Replace with env var value or default if not set
49
+ *
50
+ * Security: Default values are limited to 1000 characters to prevent abuse.
51
+ * Variable names must match pattern: [A-Z_][A-Z0-9_]*
52
+ *
53
+ * @param content Content with environment variable placeholders
54
+ * @param warnMissing Whether to warn about missing environment variables
55
+ * @returns Content with substituted values
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const content = 'token: ${GITHUB_TOKEN}';
60
+ * const result = substituteEnvVars(content);
61
+ * // result: 'token: ghp_xxxxx'
62
+ * ```
63
+ */
64
+ export declare function substituteEnvVars(content: string, warnMissing?: boolean): string;
65
+ /**
66
+ * Find project root by looking for .fractary directory or .git
67
+ *
68
+ * Walks up the directory tree from startDir until it finds:
69
+ * - A directory containing `.fractary/`
70
+ * - A directory containing `.git/`
71
+ * - The filesystem root
72
+ *
73
+ * Security: Normalizes paths and prevents traversal outside filesystem boundaries.
74
+ * Maximum of 100 directory levels to prevent infinite loops.
75
+ *
76
+ * @param startDir Directory to start searching from (default: current working directory)
77
+ * @returns Project root directory (normalized absolute path)
78
+ */
79
+ export declare function findProjectRoot(startDir?: string): string;
80
+ /**
81
+ * Check if a valid configuration file exists
82
+ *
83
+ * @param projectRoot Project root directory (auto-detected if not provided)
84
+ * @returns true if config exists at .fractary/config.yaml
85
+ */
86
+ export declare function configExists(projectRoot?: string): boolean;
87
+ /**
88
+ * Get the configuration file path
89
+ *
90
+ * @param projectRoot Project root directory (auto-detected if not provided)
91
+ * @returns Full path to configuration file
92
+ */
93
+ export declare function getConfigPath(projectRoot?: string): string;
94
+ /**
95
+ * Check if old settings.json exists (for migration)
96
+ *
97
+ * @param projectRoot Project root directory (auto-detected if not provided)
98
+ * @returns true if old settings.json exists
99
+ */
100
+ export declare function oldSettingsExists(projectRoot?: string): boolean;
101
+ /**
102
+ * Get the old settings.json file path
103
+ *
104
+ * @param projectRoot Project root directory (auto-detected if not provided)
105
+ * @returns Full path to old settings.json file
106
+ */
107
+ export declare function getOldSettingsPath(projectRoot?: string): string;
108
+ //# sourceMappingURL=yaml-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-config.d.ts","sourceRoot":"","sources":["../../src/lib/yaml-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,YAAY,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA8F3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,aAAa,GAAG,IAAI,CAoDpF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAkBN;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,UAAO,GAAG,MAAM,CAgD7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAoDxE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAI/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/D"}