@fractary/faber-cli 1.5.13 → 1.5.15

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.
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Config command - Read FABER configuration from unified config.yaml
2
+ * Config command - Manage FABER configuration
3
3
  *
4
- * This command provides access to configuration values for scripts and tools.
5
- * It uses the SDK's config loading logic, ensuring consistency across all tools.
4
+ * Provides commands for reading, writing, and migrating FABER configuration.
5
+ * Uses the SDK's ConfigInitializer for all operations to ensure consistency.
6
6
  */
7
7
  import { Command } from 'commander';
8
8
  export declare function createConfigCommand(): Command;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8BpC,wBAAgB,mBAAmB,IAAI,OAAO,CAkF7C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC,wBAAgB,mBAAmB,IAAI,OAAO,CA+c7C"}
@@ -1,11 +1,14 @@
1
1
  /**
2
- * Config command - Read FABER configuration from unified config.yaml
2
+ * Config command - Manage FABER configuration
3
3
  *
4
- * This command provides access to configuration values for scripts and tools.
5
- * It uses the SDK's config loading logic, ensuring consistency across all tools.
4
+ * Provides commands for reading, writing, and migrating FABER configuration.
5
+ * Uses the SDK's ConfigInitializer for all operations to ensure consistency.
6
6
  */
7
7
  import { Command } from 'commander';
8
- import { loadYamlConfig, configExists, getConfigPath, } from '../lib/yaml-config.js';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import * as yaml from 'js-yaml';
11
+ import { loadYamlConfig, configExists, getConfigPath, writeYamlConfig, findProjectRoot, } from '../lib/yaml-config.js';
9
12
  /**
10
13
  * Get a nested value from an object using dot notation
11
14
  * @param obj The object to search
@@ -102,5 +105,358 @@ export function createConfigCommand() {
102
105
  .action(() => {
103
106
  process.exit(configExists() ? 0 : 1);
104
107
  });
108
+ // =========================================================================
109
+ // Config Init Command
110
+ // =========================================================================
111
+ configCmd
112
+ .command('init')
113
+ .description('Initialize FABER configuration with minimal defaults')
114
+ .option('--workflows-path <path>', 'Directory for workflow files', '.fractary/faber/workflows')
115
+ .option('--default-workflow <id>', 'Default workflow ID', 'default')
116
+ .option('--autonomy <level>', 'Autonomy level (dry-run|assisted|guarded|autonomous)', 'guarded')
117
+ .option('--runs-path <path>', 'Directory for run artifacts', '.fractary/faber/runs')
118
+ .option('--force', 'Overwrite existing configuration')
119
+ .action(async (options) => {
120
+ try {
121
+ const projectRoot = findProjectRoot();
122
+ const configPath = getConfigPath(projectRoot);
123
+ // Check if config already exists
124
+ if (configExists(projectRoot) && !options.force) {
125
+ console.error('Configuration already exists at:', configPath);
126
+ console.error('Use --force to overwrite');
127
+ process.exit(1);
128
+ }
129
+ // Validate autonomy level
130
+ const validAutonomy = ['dry-run', 'assisted', 'guarded', 'autonomous'];
131
+ if (!validAutonomy.includes(options.autonomy)) {
132
+ console.error(`Invalid autonomy level: ${options.autonomy}`);
133
+ console.error(`Valid values: ${validAutonomy.join(', ')}`);
134
+ process.exit(1);
135
+ }
136
+ // Build faber config section
137
+ const faberConfig = {
138
+ workflows: {
139
+ path: options.workflowsPath,
140
+ default: options.defaultWorkflow,
141
+ autonomy: options.autonomy,
142
+ },
143
+ runs: {
144
+ path: options.runsPath,
145
+ },
146
+ };
147
+ // Load existing config or create empty
148
+ let config = loadYamlConfig({ warnMissingEnvVars: false }) || { version: '2.0' };
149
+ // Update faber section (preserves other sections)
150
+ config = { ...config, faber: faberConfig };
151
+ // Write config
152
+ writeYamlConfig(config, projectRoot);
153
+ // Create directories
154
+ const workflowsDir = path.isAbsolute(options.workflowsPath)
155
+ ? options.workflowsPath
156
+ : path.join(projectRoot, options.workflowsPath);
157
+ const runsDir = path.isAbsolute(options.runsPath)
158
+ ? options.runsPath
159
+ : path.join(projectRoot, options.runsPath);
160
+ fs.mkdirSync(workflowsDir, { recursive: true });
161
+ fs.mkdirSync(runsDir, { recursive: true });
162
+ // Create workflow manifest if it doesn't exist
163
+ const manifestPath = path.join(workflowsDir, 'workflows.yaml');
164
+ if (!fs.existsSync(manifestPath)) {
165
+ const manifest = {
166
+ workflows: [
167
+ {
168
+ id: 'default',
169
+ file: 'default.yaml',
170
+ description: 'Default FABER workflow for software development',
171
+ },
172
+ ],
173
+ };
174
+ const manifestContent = `# Workflow Registry - Lists available FABER workflows
175
+ # Each workflow is defined in a separate file in this directory
176
+
177
+ ${yaml.dump(manifest, { indent: 2, lineWidth: 100 })}`;
178
+ fs.writeFileSync(manifestPath, manifestContent, 'utf-8');
179
+ console.log('Created workflow manifest:', manifestPath);
180
+ }
181
+ console.log('Configuration initialized:', configPath);
182
+ console.log('');
183
+ console.log('Settings:');
184
+ console.log(` Workflows path: ${options.workflowsPath}`);
185
+ console.log(` Default workflow: ${options.defaultWorkflow}`);
186
+ console.log(` Autonomy: ${options.autonomy}`);
187
+ console.log(` Runs path: ${options.runsPath}`);
188
+ }
189
+ catch (error) {
190
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
191
+ process.exit(1);
192
+ }
193
+ });
194
+ // =========================================================================
195
+ // Config Set Command
196
+ // =========================================================================
197
+ configCmd
198
+ .command('set')
199
+ .description('Set a configuration value')
200
+ .argument('<key>', 'Configuration key path (e.g., faber.workflows.autonomy)')
201
+ .argument('<value>', 'Value to set')
202
+ .action(async (key, value) => {
203
+ try {
204
+ const projectRoot = findProjectRoot();
205
+ if (!configExists(projectRoot)) {
206
+ console.error('Configuration not found. Run: fractary-faber config init');
207
+ process.exit(1);
208
+ }
209
+ // Load existing config
210
+ const config = loadYamlConfig({ warnMissingEnvVars: false });
211
+ if (!config) {
212
+ console.error('Failed to load configuration');
213
+ process.exit(1);
214
+ }
215
+ // Parse value (handle booleans, numbers, etc.)
216
+ let parsedValue = value;
217
+ if (value === 'true')
218
+ parsedValue = true;
219
+ else if (value === 'false')
220
+ parsedValue = false;
221
+ else if (/^-?\d+$/.test(value))
222
+ parsedValue = parseInt(value, 10);
223
+ else if (/^-?\d+\.\d+$/.test(value))
224
+ parsedValue = parseFloat(value);
225
+ // Set nested value
226
+ setNestedValue(config, key, parsedValue);
227
+ // Write config
228
+ writeYamlConfig(config, projectRoot);
229
+ console.log(`Set ${key} = ${JSON.stringify(parsedValue)}`);
230
+ }
231
+ catch (error) {
232
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
233
+ process.exit(1);
234
+ }
235
+ });
236
+ // =========================================================================
237
+ // Config Migrate Command
238
+ // =========================================================================
239
+ configCmd
240
+ .command('migrate')
241
+ .description('Migrate legacy configuration to new simplified format')
242
+ .option('--dry-run', 'Show what would be migrated without making changes')
243
+ .action(async (options) => {
244
+ try {
245
+ const projectRoot = findProjectRoot();
246
+ const configPath = getConfigPath(projectRoot);
247
+ if (!configExists(projectRoot)) {
248
+ console.error('Configuration not found. Nothing to migrate.');
249
+ process.exit(1);
250
+ }
251
+ // Load config
252
+ const configContent = fs.readFileSync(configPath, 'utf-8');
253
+ const config = yaml.load(configContent);
254
+ const faber = config?.['faber'];
255
+ if (!faber) {
256
+ console.log('No faber section found. Nothing to migrate.');
257
+ return;
258
+ }
259
+ // Check for legacy fields
260
+ const legacyFields = [];
261
+ if (Array.isArray(faber['workflows'])) {
262
+ legacyFields.push('workflows (array format)');
263
+ }
264
+ if (faber['workflow']?.['config_path']) {
265
+ legacyFields.push('workflow.config_path');
266
+ }
267
+ if (faber['repository']) {
268
+ legacyFields.push('repository');
269
+ }
270
+ if (faber['logging']) {
271
+ legacyFields.push('logging');
272
+ }
273
+ if (faber['state']) {
274
+ legacyFields.push('state');
275
+ }
276
+ if (legacyFields.length === 0) {
277
+ console.log('Configuration is already in the new format. Nothing to migrate.');
278
+ return;
279
+ }
280
+ console.log('Legacy fields detected:');
281
+ legacyFields.forEach((f) => console.log(` - ${f}`));
282
+ console.log('');
283
+ if (options.dryRun) {
284
+ console.log('Dry run - no changes made.');
285
+ console.log('');
286
+ console.log('Would migrate to:');
287
+ // Show what the migrated config would look like
288
+ const workflow = faber['workflow'];
289
+ const state = faber['state'];
290
+ const newConfig = {
291
+ workflows: {
292
+ path: workflow?.['config_path'] || '.fractary/faber/workflows',
293
+ default: 'default',
294
+ autonomy: workflow?.['autonomy'] || 'guarded',
295
+ },
296
+ runs: {
297
+ path: state?.['runs_dir'] || '.fractary/faber/runs',
298
+ },
299
+ };
300
+ console.log(yaml.dump({ faber: newConfig }, { indent: 2 }));
301
+ return;
302
+ }
303
+ // Create backup
304
+ const backupDir = path.join(projectRoot, '.fractary/backups');
305
+ fs.mkdirSync(backupDir, { recursive: true });
306
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
307
+ const backupPath = path.join(backupDir, `config-${timestamp}.yaml`);
308
+ fs.copyFileSync(configPath, backupPath);
309
+ console.log('Created backup:', backupPath);
310
+ // Migrate
311
+ const workflow = faber['workflow'];
312
+ const state = faber['state'];
313
+ const newFaberConfig = {
314
+ workflows: {
315
+ path: workflow?.['config_path'] || '.fractary/faber/workflows',
316
+ default: 'default',
317
+ autonomy: workflow?.['autonomy'] || 'guarded',
318
+ },
319
+ runs: {
320
+ path: state?.['runs_dir'] || '.fractary/faber/runs',
321
+ },
322
+ };
323
+ // Update config
324
+ config['faber'] = newFaberConfig;
325
+ // Write config
326
+ const yamlContent = yaml.dump(config, {
327
+ indent: 2,
328
+ lineWidth: 100,
329
+ noRefs: true,
330
+ sortKeys: false,
331
+ });
332
+ fs.writeFileSync(configPath, yamlContent, 'utf-8');
333
+ console.log('Migration complete:', configPath);
334
+ console.log('');
335
+ console.log('New configuration:');
336
+ console.log(yaml.dump({ faber: newFaberConfig }, { indent: 2 }));
337
+ }
338
+ catch (error) {
339
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
340
+ process.exit(1);
341
+ }
342
+ });
343
+ // =========================================================================
344
+ // Config Validate Command
345
+ // =========================================================================
346
+ configCmd
347
+ .command('validate')
348
+ .description('Validate FABER configuration')
349
+ .action(async () => {
350
+ try {
351
+ const projectRoot = findProjectRoot();
352
+ const configPath = getConfigPath(projectRoot);
353
+ if (!configExists(projectRoot)) {
354
+ console.error('Configuration not found at:', configPath);
355
+ console.error('Run: fractary-faber config init');
356
+ process.exit(1);
357
+ }
358
+ // Load and validate config
359
+ const config = loadYamlConfig({ warnMissingEnvVars: false });
360
+ if (!config) {
361
+ console.error('Failed to load configuration');
362
+ process.exit(1);
363
+ }
364
+ const faber = config.faber;
365
+ const errors = [];
366
+ const warnings = [];
367
+ // Check for faber section
368
+ if (!faber) {
369
+ errors.push('Missing faber section');
370
+ }
371
+ else {
372
+ // Check for required fields
373
+ const workflows = faber['workflows'];
374
+ const runs = faber['runs'];
375
+ // Legacy format warnings
376
+ if (Array.isArray(faber['workflows'])) {
377
+ warnings.push('Using deprecated workflows array format');
378
+ }
379
+ if (faber['workflow']?.['config_path']) {
380
+ warnings.push('Using deprecated workflow.config_path');
381
+ }
382
+ if (faber['repository']) {
383
+ warnings.push('Using deprecated repository section');
384
+ }
385
+ if (faber['logging']) {
386
+ warnings.push('Using deprecated logging section');
387
+ }
388
+ if (faber['state']) {
389
+ warnings.push('Using deprecated state section');
390
+ }
391
+ // Validate new format fields
392
+ if (workflows && typeof workflows === 'object' && !Array.isArray(workflows)) {
393
+ const autonomy = workflows['autonomy'];
394
+ if (autonomy && !['dry-run', 'assisted', 'guarded', 'autonomous'].includes(autonomy)) {
395
+ errors.push(`Invalid autonomy level: ${autonomy}`);
396
+ }
397
+ }
398
+ // Check if directories exist
399
+ const workflowsPath = workflows?.['path'] || '.fractary/faber/workflows';
400
+ const runsPath = runs?.['path'] || '.fractary/faber/runs';
401
+ const workflowsDir = path.isAbsolute(workflowsPath)
402
+ ? workflowsPath
403
+ : path.join(projectRoot, workflowsPath);
404
+ const runsDir = path.isAbsolute(runsPath) ? runsPath : path.join(projectRoot, runsPath);
405
+ if (!fs.existsSync(workflowsDir)) {
406
+ warnings.push(`Workflows directory does not exist: ${workflowsDir}`);
407
+ }
408
+ if (!fs.existsSync(runsDir)) {
409
+ warnings.push(`Runs directory does not exist: ${runsDir}`);
410
+ }
411
+ // Check for workflow manifest
412
+ const manifestPath = path.join(workflowsDir, 'workflows.yaml');
413
+ if (fs.existsSync(workflowsDir) && !fs.existsSync(manifestPath)) {
414
+ warnings.push('Workflow manifest not found: workflows.yaml');
415
+ }
416
+ }
417
+ // Output results
418
+ if (errors.length === 0 && warnings.length === 0) {
419
+ console.log('Configuration is valid.');
420
+ return;
421
+ }
422
+ if (errors.length > 0) {
423
+ console.error('Errors:');
424
+ errors.forEach((e) => console.error(` - ${e}`));
425
+ }
426
+ if (warnings.length > 0) {
427
+ console.warn('Warnings:');
428
+ warnings.forEach((w) => console.warn(` - ${w}`));
429
+ if (warnings.some((w) => w.includes('deprecated'))) {
430
+ console.warn('');
431
+ console.warn('Run: fractary-faber config migrate');
432
+ }
433
+ }
434
+ if (errors.length > 0) {
435
+ process.exit(1);
436
+ }
437
+ }
438
+ catch (error) {
439
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
440
+ process.exit(1);
441
+ }
442
+ });
105
443
  return configCmd;
106
444
  }
445
+ /**
446
+ * Set a nested value in an object using dot notation
447
+ */
448
+ function setNestedValue(obj, path, value) {
449
+ const parts = path.split('.');
450
+ let current = obj;
451
+ for (let i = 0; i < parts.length - 1; i++) {
452
+ const part = parts[i];
453
+ if (current[part] === undefined || current[part] === null) {
454
+ current[part] = {};
455
+ }
456
+ if (typeof current[part] !== 'object') {
457
+ throw new Error(`Cannot set nested value: ${parts.slice(0, i + 1).join('.')} is not an object`);
458
+ }
459
+ current = current[part];
460
+ }
461
+ current[parts[parts.length - 1]] = value;
462
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Runs command - Query FABER run paths
3
+ *
4
+ * This command provides access to run directory and file paths for scripts and tools.
5
+ * It uses the SDK's centralized path definitions, ensuring consistency across all tools.
6
+ *
7
+ * All run files are stored in: .fractary/faber/runs/{run_id}/
8
+ * - plan.json: The execution plan
9
+ * - state.json: The workflow state
10
+ */
11
+ import { Command } from 'commander';
12
+ export declare function createRunsCommand(): Command;
13
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,iBAAiB,IAAI,OAAO,CAkH3C"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Runs command - Query FABER run paths
3
+ *
4
+ * This command provides access to run directory and file paths for scripts and tools.
5
+ * It uses the SDK's centralized path definitions, ensuring consistency across all tools.
6
+ *
7
+ * All run files are stored in: .fractary/faber/runs/{run_id}/
8
+ * - plan.json: The execution plan
9
+ * - state.json: The workflow state
10
+ */
11
+ import { Command } from 'commander';
12
+ import { FABER_RUNS_DIR, getRunsDir, getRunDir, getPlanPath, getStatePath, RELATIVE_PATHS, } from '@fractary/faber';
13
+ export function createRunsCommand() {
14
+ const runsCmd = new Command('runs')
15
+ .description('Query FABER run paths');
16
+ runsCmd
17
+ .command('dir')
18
+ .description('Show runs directory path or specific run directory')
19
+ .argument('[run_id]', 'Run ID (optional - omit for base runs directory)')
20
+ .option('--relative', 'Output relative path instead of absolute')
21
+ .option('--json', 'Output as JSON')
22
+ .action((runId, options) => {
23
+ try {
24
+ if (runId) {
25
+ // Specific run directory
26
+ const absPath = getRunDir(runId);
27
+ const relPath = `${FABER_RUNS_DIR}/${runId}`;
28
+ if (options.json) {
29
+ console.log(JSON.stringify({
30
+ run_id: runId,
31
+ absolute: absPath,
32
+ relative: relPath,
33
+ }, null, 2));
34
+ }
35
+ else {
36
+ console.log(options.relative ? relPath : absPath);
37
+ }
38
+ }
39
+ else {
40
+ // Base runs directory
41
+ const absPath = getRunsDir();
42
+ if (options.json) {
43
+ console.log(JSON.stringify({
44
+ absolute: absPath,
45
+ relative: FABER_RUNS_DIR,
46
+ }, null, 2));
47
+ }
48
+ else {
49
+ console.log(options.relative ? FABER_RUNS_DIR : absPath);
50
+ }
51
+ }
52
+ }
53
+ catch (error) {
54
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
55
+ process.exit(1);
56
+ }
57
+ });
58
+ runsCmd
59
+ .command('plan-path')
60
+ .description('Show plan file path for a run')
61
+ .argument('<run_id>', 'Run ID')
62
+ .option('--relative', 'Output relative path instead of absolute')
63
+ .option('--json', 'Output as JSON')
64
+ .action((runId, options) => {
65
+ try {
66
+ const absPath = getPlanPath(runId);
67
+ const relPath = `${FABER_RUNS_DIR}/${runId}/plan.json`;
68
+ if (options.json) {
69
+ console.log(JSON.stringify({
70
+ run_id: runId,
71
+ absolute: absPath,
72
+ relative: relPath,
73
+ }, null, 2));
74
+ }
75
+ else {
76
+ console.log(options.relative ? relPath : absPath);
77
+ }
78
+ }
79
+ catch (error) {
80
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
81
+ process.exit(1);
82
+ }
83
+ });
84
+ runsCmd
85
+ .command('state-path')
86
+ .description('Show state file path for a run')
87
+ .argument('<run_id>', 'Run ID')
88
+ .option('--relative', 'Output relative path instead of absolute')
89
+ .option('--json', 'Output as JSON')
90
+ .action((runId, options) => {
91
+ try {
92
+ const absPath = getStatePath(runId);
93
+ const relPath = `${FABER_RUNS_DIR}/${runId}/state.json`;
94
+ if (options.json) {
95
+ console.log(JSON.stringify({
96
+ run_id: runId,
97
+ absolute: absPath,
98
+ relative: relPath,
99
+ }, null, 2));
100
+ }
101
+ else {
102
+ console.log(options.relative ? relPath : absPath);
103
+ }
104
+ }
105
+ catch (error) {
106
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
107
+ process.exit(1);
108
+ }
109
+ });
110
+ runsCmd
111
+ .command('paths')
112
+ .description('Show all path templates')
113
+ .option('--json', 'Output as JSON')
114
+ .action((options) => {
115
+ if (options.json) {
116
+ console.log(JSON.stringify(RELATIVE_PATHS, null, 2));
117
+ }
118
+ else {
119
+ console.log('FABER Run Path Templates:');
120
+ console.log(` Runs Directory: ${RELATIVE_PATHS.RUNS_DIR}`);
121
+ console.log(` Run Directory: ${RELATIVE_PATHS.RUN_DIR_TEMPLATE}`);
122
+ console.log(` Plan File: ${RELATIVE_PATHS.PLAN_PATH_TEMPLATE}`);
123
+ console.log(` State File: ${RELATIVE_PATHS.STATE_PATH_TEMPLATE}`);
124
+ }
125
+ });
126
+ return runsCmd;
127
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA0KxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA2KxC"}
package/dist/index.js CHANGED
@@ -19,11 +19,12 @@ import { createMigrateCommand } from './commands/migrate.js';
19
19
  import { createPlanCommand } from './commands/plan/index.js';
20
20
  import { createAuthCommand } from './commands/auth/index.js';
21
21
  import { createConfigCommand } from './commands/config.js';
22
+ import { createRunsCommand } from './commands/runs.js';
22
23
  // Force unbuffered output to prevent buffering issues in terminals
23
24
  if (process.stdout.isTTY) {
24
25
  process.stdout._handle?.setBlocking?.(true);
25
26
  }
26
- const version = '1.5.13';
27
+ const version = '1.5.15';
27
28
  /**
28
29
  * Create and configure the main CLI program
29
30
  */
@@ -39,6 +40,7 @@ export function createFaberCLI() {
39
40
  program.addCommand(createInitCommand()); // init
40
41
  program.addCommand(createMigrateCommand()); // migrate
41
42
  program.addCommand(createConfigCommand()); // config get/path/exists
43
+ program.addCommand(createRunsCommand()); // runs dir/plan-path/state-path
42
44
  program.addCommand(createPlanCommand()); // plan
43
45
  program.addCommand(createRunCommand()); // workflow-run
44
46
  program.addCommand(createStatusCommand()); // run-inspect
@@ -51,11 +51,21 @@ export interface BacklogManagementConfig {
51
51
  /**
52
52
  * FABER-specific configuration (v2.0: only FABER-specific settings)
53
53
  * Note: anthropic and github are now at the top level of UnifiedConfig
54
+ *
55
+ * Supports both legacy format and new simplified format (v2.1)
54
56
  */
55
57
  export interface FaberConfig {
56
58
  worktree?: WorktreeConfig;
57
59
  workflow?: WorkflowConfig;
58
60
  backlog_management?: BacklogManagementConfig;
61
+ workflows?: {
62
+ path?: string;
63
+ default?: string;
64
+ autonomy?: AutonomyLevel;
65
+ };
66
+ runs?: {
67
+ path?: string;
68
+ };
59
69
  }
60
70
  /**
61
71
  * Loaded FABER configuration including shared authentication
@@ -109,4 +119,8 @@ export interface ConfigLoadOptions {
109
119
  /** Throw error if config file doesn't exist (default: false) */
110
120
  throwIfMissing?: boolean;
111
121
  }
122
+ /**
123
+ * Autonomy levels for FABER workflows
124
+ */
125
+ export type AutonomyLevel = 'dry-run' | 'assisted' | 'guarded' | 'autonomous';
112
126
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;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;;GAEG;AACH,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,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/D,eAAe,CAAC,EAAE;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC5C,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fractary/faber-cli",
3
- "version": "1.5.13",
3
+ "version": "1.5.15",
4
4
  "description": "FABER CLI - Command-line interface for FABER development toolkit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@fractary/core": "^0.5.0",
41
- "@fractary/faber": "^2.3.0",
41
+ "@fractary/faber": "^2.4.0",
42
42
  "ajv": "^8.12.0",
43
43
  "chalk": "^5.0.0",
44
44
  "commander": "^12.0.0",