@fractary/faber-cli 1.5.48 → 1.5.50
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/LICENSE +190 -21
- package/README.md +0 -0
- package/dist/__mocks__/chalk.d.ts +0 -0
- package/dist/__mocks__/chalk.d.ts.map +0 -0
- package/dist/__mocks__/chalk.js +0 -0
- package/dist/commands/auth/index.d.ts +0 -0
- package/dist/commands/auth/index.d.ts.map +0 -0
- package/dist/commands/auth/index.js +0 -0
- package/dist/commands/changelog/index.d.ts +0 -0
- package/dist/commands/changelog/index.d.ts.map +0 -0
- package/dist/commands/changelog/index.js +0 -0
- package/dist/commands/config.d.ts +0 -0
- package/dist/commands/config.d.ts.map +0 -0
- package/dist/commands/config.js +0 -0
- package/dist/commands/logs/index.d.ts +0 -0
- package/dist/commands/logs/index.d.ts.map +0 -0
- package/dist/commands/logs/index.js +0 -0
- package/dist/commands/migrate.d.ts +0 -0
- package/dist/commands/migrate.d.ts.map +0 -0
- package/dist/commands/migrate.js +0 -0
- package/dist/commands/plan/index.d.ts +0 -0
- package/dist/commands/plan/index.d.ts.map +0 -0
- package/dist/commands/plan/index.js +0 -0
- package/dist/commands/repo/index.d.ts +0 -0
- package/dist/commands/repo/index.d.ts.map +0 -0
- package/dist/commands/repo/index.js +0 -0
- package/dist/commands/runs.d.ts +0 -0
- package/dist/commands/runs.d.ts.map +0 -0
- package/dist/commands/runs.js +0 -0
- package/dist/commands/session.d.ts +0 -0
- package/dist/commands/session.d.ts.map +0 -0
- package/dist/commands/session.js +0 -0
- package/dist/commands/work/index.d.ts +0 -0
- package/dist/commands/work/index.d.ts.map +0 -0
- package/dist/commands/work/index.js +0 -0
- package/dist/commands/workflow/index.d.ts +0 -0
- package/dist/commands/workflow/index.d.ts.map +0 -0
- package/dist/commands/workflow/index.js +0 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.d.ts.map +0 -0
- package/dist/lib/anthropic-client.d.ts +0 -0
- package/dist/lib/anthropic-client.d.ts.map +0 -0
- package/dist/lib/anthropic-client.js +0 -0
- package/dist/lib/config.d.ts +0 -0
- package/dist/lib/config.d.ts.map +0 -0
- package/dist/lib/config.js +0 -0
- package/dist/lib/github-app-setup.d.ts +0 -0
- package/dist/lib/github-app-setup.d.ts.map +0 -0
- package/dist/lib/github-app-setup.js +0 -0
- package/dist/lib/repo-client.d.ts +0 -0
- package/dist/lib/repo-client.d.ts.map +1 -1
- package/dist/lib/repo-client.js +2 -0
- package/dist/lib/sdk-type-adapter.d.ts +0 -0
- package/dist/lib/sdk-type-adapter.d.ts.map +0 -0
- package/dist/lib/sdk-type-adapter.js +0 -0
- package/dist/lib/yaml-config.d.ts +0 -0
- package/dist/lib/yaml-config.d.ts.map +0 -0
- package/dist/lib/yaml-config.js +0 -0
- package/dist/types/config.d.ts +1 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +0 -0
- package/dist/utils/errors.d.ts +0 -0
- package/dist/utils/errors.d.ts.map +0 -0
- package/dist/utils/errors.js +0 -0
- package/dist/utils/github-manifest.d.ts +0 -0
- package/dist/utils/github-manifest.d.ts.map +0 -0
- package/dist/utils/github-manifest.js +0 -0
- package/dist/utils/labels.d.ts +0 -0
- package/dist/utils/labels.d.ts.map +0 -0
- package/dist/utils/labels.js +0 -0
- package/dist/utils/output.d.ts +0 -0
- package/dist/utils/output.d.ts.map +0 -0
- package/dist/utils/output.js +0 -0
- package/dist/utils/prompt.d.ts +0 -0
- package/dist/utils/prompt.d.ts.map +0 -0
- package/dist/utils/prompt.js +0 -0
- package/dist/utils/sorting.d.ts +0 -0
- package/dist/utils/sorting.d.ts.map +0 -0
- package/dist/utils/sorting.js +0 -0
- package/dist/utils/validation.d.ts +0 -0
- package/dist/utils/validation.d.ts.map +0 -0
- package/dist/utils/validation.js +0 -0
- package/package.json +2 -2
- package/schemas/plan.schema.json +0 -0
- package/dist/commands/init.d.ts +0 -9
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -161
- package/dist/commands/spec/index.d.ts +0 -11
- package/dist/commands/spec/index.d.ts.map +0 -1
- package/dist/commands/spec/index.js +0 -280
- package/dist/lib/github-app-auth.d.ts +0 -122
- package/dist/lib/github-app-auth.d.ts.map +0 -1
- package/dist/lib/github-app-auth.js +0 -300
- package/dist/lib/sdk-config-adapter.d.ts +0 -76
- package/dist/lib/sdk-config-adapter.d.ts.map +0 -1
- package/dist/lib/sdk-config-adapter.js +0 -207
package/dist/commands/init.js
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Init command - Initialize FABER section in unified config.yaml
|
|
3
|
-
*
|
|
4
|
-
* This command ONLY manages the faber: section of .fractary/config.yaml
|
|
5
|
-
* It assumes shared configuration (github, anthropic) is already set up via fractary-core:init
|
|
6
|
-
*/
|
|
7
|
-
import { Command } from 'commander';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
|
-
import * as readline from 'readline/promises';
|
|
10
|
-
import os from 'os';
|
|
11
|
-
import path from 'path';
|
|
12
|
-
import { loadYamlConfig, writeYamlConfig, configExists, oldSettingsExists, getConfigPath, getOldSettingsPath } from '../lib/yaml-config.js';
|
|
13
|
-
export function createInitCommand() {
|
|
14
|
-
return new Command('configure')
|
|
15
|
-
.description('Initialize FABER section in unified config.yaml')
|
|
16
|
-
.option('--force', 'Overwrite existing FABER configuration')
|
|
17
|
-
.option('--json', 'Output as JSON')
|
|
18
|
-
.action(async (options) => {
|
|
19
|
-
try {
|
|
20
|
-
if (!options.json) {
|
|
21
|
-
console.log(chalk.cyan('Initializing FABER configuration...'));
|
|
22
|
-
console.log();
|
|
23
|
-
}
|
|
24
|
-
// Step 1: Check for old settings.json and suggest migration
|
|
25
|
-
if (oldSettingsExists()) {
|
|
26
|
-
const oldPath = getOldSettingsPath();
|
|
27
|
-
if (options.json) {
|
|
28
|
-
console.log(JSON.stringify({
|
|
29
|
-
status: 'error',
|
|
30
|
-
error: {
|
|
31
|
-
message: 'Old settings.json found',
|
|
32
|
-
oldPath,
|
|
33
|
-
migration: 'Run: fractary-faber migrate'
|
|
34
|
-
}
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
console.log(chalk.yellow('⚠️ Detected old .fractary/settings.json'));
|
|
39
|
-
console.log(`Found: ${chalk.gray(oldPath)}`);
|
|
40
|
-
console.log();
|
|
41
|
-
console.log('Run this command to migrate to the new format:');
|
|
42
|
-
console.log(chalk.cyan(' fractary-faber migrate'));
|
|
43
|
-
console.log();
|
|
44
|
-
}
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
// Step 2: Check if config.yaml exists
|
|
48
|
-
if (!configExists()) {
|
|
49
|
-
if (options.json) {
|
|
50
|
-
console.log(JSON.stringify({
|
|
51
|
-
status: 'error',
|
|
52
|
-
error: {
|
|
53
|
-
message: 'No .fractary/config.yaml found',
|
|
54
|
-
recommendation: 'Run fractary-core:init first'
|
|
55
|
-
}
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
console.error(chalk.red('Error: No .fractary/config.yaml found'));
|
|
60
|
-
console.log();
|
|
61
|
-
console.log('FABER requires shared configuration to be set up first.');
|
|
62
|
-
console.log();
|
|
63
|
-
console.log('Please run one of the following:');
|
|
64
|
-
console.log(chalk.cyan(' 1. fractary-core:init') + ' - Initialize unified config with GitHub/Anthropic settings');
|
|
65
|
-
console.log(chalk.cyan(' 2. fractary-faber migrate') + ' - Migrate from old .fractary/settings.json');
|
|
66
|
-
console.log();
|
|
67
|
-
}
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
// Step 3: Load existing config
|
|
71
|
-
const config = loadYamlConfig();
|
|
72
|
-
if (!config) {
|
|
73
|
-
throw new Error('Failed to load .fractary/config.yaml');
|
|
74
|
-
}
|
|
75
|
-
// Step 4: Check if FABER section already exists
|
|
76
|
-
if (config.faber && !options.force) {
|
|
77
|
-
if (options.json) {
|
|
78
|
-
console.log(JSON.stringify({
|
|
79
|
-
status: 'exists',
|
|
80
|
-
path: getConfigPath(),
|
|
81
|
-
message: 'FABER section already configured'
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
console.log(chalk.yellow('FABER section already exists in config.yaml'));
|
|
86
|
-
console.log();
|
|
87
|
-
console.log('Use --force to overwrite existing configuration.');
|
|
88
|
-
console.log();
|
|
89
|
-
}
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
// Step 5: Validate shared sections and warn if missing
|
|
93
|
-
const warnings = [];
|
|
94
|
-
if (!config.github) {
|
|
95
|
-
warnings.push('Missing \'github\' section - FABER needs GitHub authentication');
|
|
96
|
-
}
|
|
97
|
-
if (!config.anthropic) {
|
|
98
|
-
warnings.push('Missing \'anthropic\' section - FABER needs Anthropic API key');
|
|
99
|
-
}
|
|
100
|
-
if (warnings.length > 0 && !options.json) {
|
|
101
|
-
console.log(chalk.yellow('⚠️ Configuration warnings:'));
|
|
102
|
-
warnings.forEach(w => console.log(chalk.yellow(` - ${w}`)));
|
|
103
|
-
console.log();
|
|
104
|
-
console.log(chalk.bold('Recommendation:') + ' Run ' + chalk.cyan('fractary-core:init') + ' to set up shared configuration');
|
|
105
|
-
console.log();
|
|
106
|
-
// Ask if user wants to continue
|
|
107
|
-
const rl = readline.createInterface({
|
|
108
|
-
input: process.stdin,
|
|
109
|
-
output: process.stdout,
|
|
110
|
-
});
|
|
111
|
-
const answer = await rl.question('Continue with FABER initialization? (y/N) ');
|
|
112
|
-
rl.close();
|
|
113
|
-
console.log();
|
|
114
|
-
if (answer.toLowerCase() !== 'y') {
|
|
115
|
-
console.log('Initialization cancelled.');
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// Step 6: Initialize FABER section
|
|
120
|
-
config.faber = {
|
|
121
|
-
worktree: {
|
|
122
|
-
location: path.join(os.homedir(), '.claude-worktrees'),
|
|
123
|
-
inherit_from_claude: true
|
|
124
|
-
},
|
|
125
|
-
workflow: {
|
|
126
|
-
config_path: path.join('.fractary', 'faber', 'workflows')
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
// Step 7: Write config back
|
|
130
|
-
writeYamlConfig(config);
|
|
131
|
-
if (options.json) {
|
|
132
|
-
console.log(JSON.stringify({
|
|
133
|
-
status: 'success',
|
|
134
|
-
path: getConfigPath()
|
|
135
|
-
}));
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
console.log(chalk.green('✓ FABER configuration initialized in .fractary/config.yaml'));
|
|
139
|
-
console.log();
|
|
140
|
-
console.log('Next steps:');
|
|
141
|
-
console.log(' 1. Set up GitHub App authentication: ' + chalk.cyan('fractary-faber auth setup'));
|
|
142
|
-
console.log(' 2. Create workflow configuration files in .fractary/faber/workflows/');
|
|
143
|
-
console.log(' 3. Run your first workflow: ' + chalk.cyan('fractary-faber workflow plan <issue-number>'));
|
|
144
|
-
console.log();
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
149
|
-
if (options.json) {
|
|
150
|
-
console.error(JSON.stringify({
|
|
151
|
-
status: 'error',
|
|
152
|
-
error: { message }
|
|
153
|
-
}));
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
console.error(chalk.red('Error:'), message);
|
|
157
|
-
}
|
|
158
|
-
process.exit(1);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec subcommand - Specification management
|
|
3
|
-
*
|
|
4
|
-
* Provides spec operations via @fractary/faber SpecManager.
|
|
5
|
-
*/
|
|
6
|
-
import { Command } from 'commander';
|
|
7
|
-
/**
|
|
8
|
-
* Create the spec command tree
|
|
9
|
-
*/
|
|
10
|
-
export declare function createSpecCommand(): Command;
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/fractary-faber-spec/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAc3C"}
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec subcommand - Specification management
|
|
3
|
-
*
|
|
4
|
-
* Provides spec operations via @fractary/faber SpecManager.
|
|
5
|
-
*/
|
|
6
|
-
import { Command } from 'commander';
|
|
7
|
-
import chalk from 'chalk';
|
|
8
|
-
import { SpecManager } from '@fractary/faber';
|
|
9
|
-
/**
|
|
10
|
-
* Create the spec command tree
|
|
11
|
-
*/
|
|
12
|
-
export function createSpecCommand() {
|
|
13
|
-
const spec = new Command('spec')
|
|
14
|
-
.description('Specification management');
|
|
15
|
-
spec.addCommand(createSpecCreateCommand());
|
|
16
|
-
spec.addCommand(createSpecGetCommand());
|
|
17
|
-
spec.addCommand(createSpecListCommand());
|
|
18
|
-
spec.addCommand(createSpecUpdateCommand());
|
|
19
|
-
spec.addCommand(createSpecValidateCommand());
|
|
20
|
-
spec.addCommand(createSpecRefineCommand());
|
|
21
|
-
spec.addCommand(createSpecDeleteCommand());
|
|
22
|
-
spec.addCommand(createSpecTemplatesCommand());
|
|
23
|
-
return spec;
|
|
24
|
-
}
|
|
25
|
-
function createSpecCreateCommand() {
|
|
26
|
-
return new Command('create')
|
|
27
|
-
.description('Create a new specification')
|
|
28
|
-
.argument('<title>', 'Specification title')
|
|
29
|
-
.option('--template <type>', 'Specification template (feature, bugfix, refactor)', 'feature')
|
|
30
|
-
.option('--work-id <id>', 'Associated work item ID')
|
|
31
|
-
.option('--json', 'Output as JSON')
|
|
32
|
-
.action(async (title, options) => {
|
|
33
|
-
try {
|
|
34
|
-
const specManager = new SpecManager();
|
|
35
|
-
const spec = specManager.createSpec(title, {
|
|
36
|
-
template: options.template,
|
|
37
|
-
workId: options.workId,
|
|
38
|
-
});
|
|
39
|
-
if (options.json) {
|
|
40
|
-
console.log(JSON.stringify({ status: 'success', data: spec }, null, 2));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
console.log(chalk.green(`✓ Created specification: ${spec.title}`));
|
|
44
|
-
console.log(chalk.gray(` ID: ${spec.id}`));
|
|
45
|
-
console.log(chalk.gray(` Path: ${spec.path}`));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
handleSpecError(error, options);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function createSpecGetCommand() {
|
|
54
|
-
return new Command('get')
|
|
55
|
-
.description('Get a specification by ID or path')
|
|
56
|
-
.argument('<id>', 'Specification ID or path')
|
|
57
|
-
.option('--json', 'Output as JSON')
|
|
58
|
-
.action(async (id, options) => {
|
|
59
|
-
try {
|
|
60
|
-
const specManager = new SpecManager();
|
|
61
|
-
const spec = specManager.getSpec(id);
|
|
62
|
-
if (!spec) {
|
|
63
|
-
if (options.json) {
|
|
64
|
-
console.error(JSON.stringify({
|
|
65
|
-
status: 'error',
|
|
66
|
-
error: { code: 'SPEC_NOT_FOUND', message: `Specification not found: ${id}` },
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
console.error(chalk.red(`Specification not found: ${id}`));
|
|
71
|
-
}
|
|
72
|
-
process.exit(5);
|
|
73
|
-
}
|
|
74
|
-
if (options.json) {
|
|
75
|
-
console.log(JSON.stringify({ status: 'success', data: spec }, null, 2));
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.log(chalk.bold(`${spec.title}`));
|
|
79
|
-
console.log(chalk.gray(`ID: ${spec.id}`));
|
|
80
|
-
console.log(chalk.gray(`Status: ${spec.metadata.validation_status || 'not_validated'}`));
|
|
81
|
-
console.log(chalk.gray(`Work ID: ${spec.workId || 'N/A'}`));
|
|
82
|
-
console.log('\n' + spec.content);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
handleSpecError(error, options);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
function createSpecListCommand() {
|
|
91
|
-
return new Command('list')
|
|
92
|
-
.description('List specifications')
|
|
93
|
-
.option('--status <status>', 'Filter by status (draft, validated, needs_revision)')
|
|
94
|
-
.option('--work-id <id>', 'Filter by work item ID')
|
|
95
|
-
.option('--json', 'Output as JSON')
|
|
96
|
-
.action(async (options) => {
|
|
97
|
-
try {
|
|
98
|
-
const specManager = new SpecManager();
|
|
99
|
-
const specs = specManager.listSpecs({
|
|
100
|
-
status: options.status,
|
|
101
|
-
workId: options.workId,
|
|
102
|
-
});
|
|
103
|
-
if (options.json) {
|
|
104
|
-
console.log(JSON.stringify({ status: 'success', data: specs }, null, 2));
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
if (specs.length === 0) {
|
|
108
|
-
console.log(chalk.yellow('No specifications found'));
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
specs.forEach((spec) => {
|
|
112
|
-
const status = spec.metadata.validation_status || 'not_validated';
|
|
113
|
-
const statusColor = status === 'complete' ? chalk.green :
|
|
114
|
-
status === 'failed' ? chalk.red :
|
|
115
|
-
status === 'partial' ? chalk.yellow : chalk.gray;
|
|
116
|
-
console.log(`${spec.id} ${spec.title} [${statusColor(status)}]`);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
handleSpecError(error, options);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
function createSpecUpdateCommand() {
|
|
127
|
-
return new Command('update')
|
|
128
|
-
.description('Update a specification')
|
|
129
|
-
.argument('<id>', 'Specification ID or path')
|
|
130
|
-
.option('--title <title>', 'New title')
|
|
131
|
-
.option('--content <content>', 'New content')
|
|
132
|
-
.option('--work-id <id>', 'Associated work item ID')
|
|
133
|
-
.option('--status <status>', 'Validation status')
|
|
134
|
-
.option('--json', 'Output as JSON')
|
|
135
|
-
.action(async (id, options) => {
|
|
136
|
-
try {
|
|
137
|
-
const specManager = new SpecManager();
|
|
138
|
-
const spec = specManager.updateSpec(id, {
|
|
139
|
-
title: options.title,
|
|
140
|
-
content: options.content,
|
|
141
|
-
workId: options.workId,
|
|
142
|
-
validationStatus: options.status,
|
|
143
|
-
});
|
|
144
|
-
if (options.json) {
|
|
145
|
-
console.log(JSON.stringify({ status: 'success', data: spec }, null, 2));
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
console.log(chalk.green(`✓ Updated specification: ${spec.title}`));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
handleSpecError(error, options);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function createSpecValidateCommand() {
|
|
157
|
-
return new Command('validate')
|
|
158
|
-
.description('Validate a specification')
|
|
159
|
-
.argument('<id>', 'Specification ID or path')
|
|
160
|
-
.option('--json', 'Output as JSON')
|
|
161
|
-
.action(async (id, options) => {
|
|
162
|
-
try {
|
|
163
|
-
const specManager = new SpecManager();
|
|
164
|
-
const result = specManager.validateSpec(id);
|
|
165
|
-
if (options.json) {
|
|
166
|
-
console.log(JSON.stringify({ status: 'success', data: result }, null, 2));
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
const statusColor = result.status === 'pass' ? chalk.green :
|
|
170
|
-
result.status === 'fail' ? chalk.red : chalk.yellow;
|
|
171
|
-
console.log(`Validation: ${statusColor(result.status.toUpperCase())}`);
|
|
172
|
-
console.log(chalk.gray(` Score: ${result.score}%`));
|
|
173
|
-
// Show check results
|
|
174
|
-
console.log(chalk.yellow('\nChecks:'));
|
|
175
|
-
const { requirements, acceptanceCriteria } = result.checks;
|
|
176
|
-
console.log(` Requirements: ${requirements.completed}/${requirements.total} [${requirements.status}]`);
|
|
177
|
-
console.log(` Acceptance Criteria: ${acceptanceCriteria.met}/${acceptanceCriteria.total} [${acceptanceCriteria.status}]`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch (error) {
|
|
181
|
-
handleSpecError(error, options);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
function createSpecRefineCommand() {
|
|
186
|
-
return new Command('refine')
|
|
187
|
-
.description('Generate refinement questions for a specification')
|
|
188
|
-
.argument('<id>', 'Specification ID or path')
|
|
189
|
-
.option('--json', 'Output as JSON')
|
|
190
|
-
.action(async (id, options) => {
|
|
191
|
-
try {
|
|
192
|
-
const specManager = new SpecManager();
|
|
193
|
-
const questions = specManager.generateRefinementQuestions(id);
|
|
194
|
-
if (options.json) {
|
|
195
|
-
console.log(JSON.stringify({ status: 'success', data: questions }, null, 2));
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
if (questions.length === 0) {
|
|
199
|
-
console.log(chalk.green('✓ Specification appears complete, no refinement questions'));
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
console.log(chalk.yellow('Refinement Questions:'));
|
|
203
|
-
questions.forEach((q, i) => {
|
|
204
|
-
const priorityColor = q.priority === 'high' ? chalk.red :
|
|
205
|
-
q.priority === 'medium' ? chalk.yellow : chalk.gray;
|
|
206
|
-
console.log(`\n${i + 1}. [${priorityColor(q.priority)}] ${q.category}`);
|
|
207
|
-
console.log(` ${q.question}`);
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
catch (error) {
|
|
213
|
-
handleSpecError(error, options);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
function createSpecDeleteCommand() {
|
|
218
|
-
return new Command('delete')
|
|
219
|
-
.description('Delete a specification')
|
|
220
|
-
.argument('<id>', 'Specification ID or path')
|
|
221
|
-
.option('--json', 'Output as JSON')
|
|
222
|
-
.action(async (id, options) => {
|
|
223
|
-
try {
|
|
224
|
-
const specManager = new SpecManager();
|
|
225
|
-
const deleted = specManager.deleteSpec(id);
|
|
226
|
-
if (options.json) {
|
|
227
|
-
console.log(JSON.stringify({ status: 'success', data: { deleted } }, null, 2));
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
if (deleted) {
|
|
231
|
-
console.log(chalk.green(`✓ Deleted specification: ${id}`));
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
console.log(chalk.yellow(`Specification not found: ${id}`));
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
catch (error) {
|
|
239
|
-
handleSpecError(error, options);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
function createSpecTemplatesCommand() {
|
|
244
|
-
return new Command('templates')
|
|
245
|
-
.description('List available specification templates')
|
|
246
|
-
.option('--json', 'Output as JSON')
|
|
247
|
-
.action(async (options) => {
|
|
248
|
-
try {
|
|
249
|
-
const specManager = new SpecManager();
|
|
250
|
-
const templates = specManager.getTemplates();
|
|
251
|
-
if (options.json) {
|
|
252
|
-
console.log(JSON.stringify({ status: 'success', data: templates }, null, 2));
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
console.log(chalk.bold('Available Templates:'));
|
|
256
|
-
templates.forEach((t) => {
|
|
257
|
-
console.log(` ${chalk.cyan(t.id)} - ${t.name}`);
|
|
258
|
-
console.log(chalk.gray(` ${t.description}`));
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
catch (error) {
|
|
263
|
-
handleSpecError(error, options);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
// Error handling
|
|
268
|
-
function handleSpecError(error, options) {
|
|
269
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
270
|
-
if (options.json) {
|
|
271
|
-
console.error(JSON.stringify({
|
|
272
|
-
status: 'error',
|
|
273
|
-
error: { code: 'SPEC_ERROR', message },
|
|
274
|
-
}));
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
console.error(chalk.red('Error:'), message);
|
|
278
|
-
}
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub App Authentication Module
|
|
3
|
-
*
|
|
4
|
-
* Provides JWT generation, installation token exchange, and token caching
|
|
5
|
-
* for GitHub App authentication in FABER CLI.
|
|
6
|
-
*/
|
|
7
|
-
import type { GitHubAppConfig } from '../types/config.js';
|
|
8
|
-
/**
|
|
9
|
-
* Private Key Loader
|
|
10
|
-
*
|
|
11
|
-
* Loads private keys from file path or environment variable
|
|
12
|
-
*/
|
|
13
|
-
export declare class PrivateKeyLoader {
|
|
14
|
-
/**
|
|
15
|
-
* Load private key from configured sources.
|
|
16
|
-
* Priority: env var > file path
|
|
17
|
-
*
|
|
18
|
-
* @param config - GitHub App configuration
|
|
19
|
-
* @returns The private key content
|
|
20
|
-
* @throws Error if private key cannot be loaded
|
|
21
|
-
*/
|
|
22
|
-
static load(config: GitHubAppConfig): Promise<string>;
|
|
23
|
-
/**
|
|
24
|
-
* Validate private key format.
|
|
25
|
-
*
|
|
26
|
-
* @param key - The private key content
|
|
27
|
-
* @returns true if valid PEM format
|
|
28
|
-
*/
|
|
29
|
-
static validate(key: string): boolean;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* GitHub App Authentication
|
|
33
|
-
*
|
|
34
|
-
* Handles JWT generation, installation token exchange, and caching
|
|
35
|
-
*/
|
|
36
|
-
export declare class GitHubAppAuth {
|
|
37
|
-
private cache;
|
|
38
|
-
private config;
|
|
39
|
-
private refreshPromise;
|
|
40
|
-
private static readonly REFRESH_THRESHOLD_MS;
|
|
41
|
-
private static readonly JWT_EXPIRY_SECONDS;
|
|
42
|
-
private static readonly GITHUB_API_URL;
|
|
43
|
-
constructor(config: GitHubAppConfig);
|
|
44
|
-
/**
|
|
45
|
-
* Get a valid installation token.
|
|
46
|
-
* Returns cached token if still valid, otherwise generates new one.
|
|
47
|
-
*
|
|
48
|
-
* @returns Installation access token
|
|
49
|
-
*/
|
|
50
|
-
getToken(): Promise<string>;
|
|
51
|
-
/**
|
|
52
|
-
* Force refresh the token.
|
|
53
|
-
*
|
|
54
|
-
* @returns New installation access token
|
|
55
|
-
*/
|
|
56
|
-
refreshToken(): Promise<string>;
|
|
57
|
-
/**
|
|
58
|
-
* Check if token needs refresh (within 5 minutes of expiration).
|
|
59
|
-
*
|
|
60
|
-
* @returns true if token should be refreshed
|
|
61
|
-
*/
|
|
62
|
-
isTokenExpiringSoon(): boolean;
|
|
63
|
-
/**
|
|
64
|
-
* Validate the configuration and private key.
|
|
65
|
-
*
|
|
66
|
-
* @throws Error if configuration is invalid
|
|
67
|
-
*/
|
|
68
|
-
validate(): Promise<void>;
|
|
69
|
-
/**
|
|
70
|
-
* Perform the actual token refresh
|
|
71
|
-
*/
|
|
72
|
-
private doRefresh;
|
|
73
|
-
/**
|
|
74
|
-
* Generate a JWT for GitHub App authentication
|
|
75
|
-
*/
|
|
76
|
-
private generateJWT;
|
|
77
|
-
/**
|
|
78
|
-
* Exchange JWT for installation access token
|
|
79
|
-
*/
|
|
80
|
-
private exchangeForInstallationToken;
|
|
81
|
-
/**
|
|
82
|
-
* Check if token is expired
|
|
83
|
-
*/
|
|
84
|
-
private isExpired;
|
|
85
|
-
/**
|
|
86
|
-
* Check if token is expiring soon
|
|
87
|
-
*/
|
|
88
|
-
private isExpiringSoon;
|
|
89
|
-
/**
|
|
90
|
-
* Trigger background token refresh (non-blocking)
|
|
91
|
-
*/
|
|
92
|
-
private triggerBackgroundRefresh;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Token Provider Interface
|
|
96
|
-
*
|
|
97
|
-
* Abstract interface for getting tokens, supporting both PAT and GitHub App
|
|
98
|
-
*/
|
|
99
|
-
export interface TokenProvider {
|
|
100
|
-
getToken(): Promise<string>;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Static Token Provider
|
|
104
|
-
*
|
|
105
|
-
* Simple provider for static PAT tokens
|
|
106
|
-
*/
|
|
107
|
-
export declare class StaticTokenProvider implements TokenProvider {
|
|
108
|
-
private token;
|
|
109
|
-
constructor(token: string);
|
|
110
|
-
getToken(): Promise<string>;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* GitHub App Token Provider
|
|
114
|
-
*
|
|
115
|
-
* Provider that uses GitHubAppAuth for dynamic token generation
|
|
116
|
-
*/
|
|
117
|
-
export declare class GitHubAppTokenProvider implements TokenProvider {
|
|
118
|
-
private auth;
|
|
119
|
-
constructor(auth: GitHubAppAuth);
|
|
120
|
-
getToken(): Promise<string>;
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=github-app-auth.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github-app-auth.d.ts","sourceRoot":"","sources":["../../src/lib/github-app-auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAqB1D;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;;OAOG;WACU,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAiD3D;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAUtC;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,cAAc,CAAgC;IAGtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAiB;IAE7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IAEjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAA4B;gBAEtD,MAAM,EAAE,eAAe;IAInC;;;;;OAKG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBjC;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAerC;;;;OAIG;IACH,mBAAmB,IAAI,OAAO;IAK9B;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B;;OAEG;YACW,SAAS;IAmBvB;;OAEG;YACW,WAAW;IAoBzB;;OAEG;YACW,4BAA4B;IAyD1C;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,wBAAwB;CAUjC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAC3C,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,MAAM;IAE3B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAGlC;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,aAAa;IAC9C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,aAAa;IAEjC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAGlC"}
|