@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.
- package/dist/commands/config.d.ts +3 -3
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +360 -4
- package/dist/commands/runs.d.ts +13 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +127 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/types/config.d.ts +14 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Config command -
|
|
2
|
+
* Config command - Manage FABER configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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;
|
|
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"}
|
package/dist/commands/config.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Config command -
|
|
2
|
+
* Config command - Manage FABER configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
+
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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.
|
|
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
|
package/dist/types/config.d.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
41
|
+
"@fractary/faber": "^2.4.0",
|
|
42
42
|
"ajv": "^8.12.0",
|
|
43
43
|
"chalk": "^5.0.0",
|
|
44
44
|
"commander": "^12.0.0",
|