@fractary/faber-cli 1.0.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.
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +163 -0
- package/dist/commands/logs/index.d.ts +11 -0
- package/dist/commands/logs/index.d.ts.map +1 -0
- package/dist/commands/logs/index.js +330 -0
- package/dist/commands/repo/index.d.ts +11 -0
- package/dist/commands/repo/index.d.ts.map +1 -0
- package/dist/commands/repo/index.js +612 -0
- package/dist/commands/spec/index.d.ts +11 -0
- package/dist/commands/spec/index.d.ts.map +1 -0
- package/dist/commands/spec/index.js +280 -0
- package/dist/commands/work/index.d.ts +11 -0
- package/dist/commands/work/index.d.ts.map +1 -0
- package/dist/commands/work/index.js +748 -0
- package/dist/commands/workflow/index.d.ts +31 -0
- package/dist/commands/workflow/index.d.ts.map +1 -0
- package/dist/commands/workflow/index.js +298 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/utils/errors.d.ts +14 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +44 -0
- package/dist/utils/output.d.ts +18 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +39 -0
- package/dist/utils/validation.d.ts +30 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +49 -0
- package/package.json +66 -0
|
@@ -0,0 +1,280 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work subcommand - Work tracking operations
|
|
3
|
+
*
|
|
4
|
+
* Provides issue, comment, label, and milestone operations via @fractary/faber WorkManager.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
/**
|
|
8
|
+
* Create the work command tree
|
|
9
|
+
*/
|
|
10
|
+
export declare function createWorkCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/work/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CA+C3C"}
|