@fractary/faber-cli 1.5.29 → 1.5.31
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/changelog/index.d.ts +11 -0
- package/dist/commands/changelog/index.d.ts.map +1 -0
- package/dist/commands/changelog/index.js +201 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Changelog subcommand - Machine-readable changelog management
|
|
3
|
+
*
|
|
4
|
+
* Provides emit, query, aggregate, and read-run operations via ChangelogManager SDK.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
/**
|
|
8
|
+
* Create the changelog command tree
|
|
9
|
+
*/
|
|
10
|
+
export declare function createChangelogCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/changelog/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Changelog subcommand - Machine-readable changelog management
|
|
3
|
+
*
|
|
4
|
+
* Provides emit, query, aggregate, and read-run operations via ChangelogManager SDK.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { ChangelogManager } from '@fractary/faber';
|
|
9
|
+
/**
|
|
10
|
+
* Create the changelog command tree
|
|
11
|
+
*/
|
|
12
|
+
export function createChangelogCommand() {
|
|
13
|
+
const changelog = new Command('changelog')
|
|
14
|
+
.description('Machine-readable changelog management');
|
|
15
|
+
changelog.addCommand(createChangelogEmitCommand());
|
|
16
|
+
changelog.addCommand(createChangelogQueryCommand());
|
|
17
|
+
changelog.addCommand(createChangelogAggregateCommand());
|
|
18
|
+
changelog.addCommand(createChangelogReadRunCommand());
|
|
19
|
+
return changelog;
|
|
20
|
+
}
|
|
21
|
+
function createChangelogEmitCommand() {
|
|
22
|
+
return new Command('emit')
|
|
23
|
+
.description('Emit a changelog entry for a completed step')
|
|
24
|
+
.requiredOption('--run-id <id>', 'Run identifier')
|
|
25
|
+
.requiredOption('--step-id <id>', 'Step identifier')
|
|
26
|
+
.requiredOption('--step-name <name>', 'Human-readable step name')
|
|
27
|
+
.requiredOption('--phase <phase>', 'FABER phase')
|
|
28
|
+
.requiredOption('--status <status>', 'Step status (success, warning, failure, skipped)')
|
|
29
|
+
.requiredOption('--event-type <type>', 'Semantic event type (e.g., CODE_MERGED)')
|
|
30
|
+
.requiredOption('--workflow-id <id>', 'Workflow identifier')
|
|
31
|
+
.requiredOption('--work-id <id>', 'Work item identifier')
|
|
32
|
+
.option('--target <target>', 'Target branch/environment/resource')
|
|
33
|
+
.option('--environment <env>', 'Target environment (test, prod)')
|
|
34
|
+
.option('--message <msg>', 'Human-readable description')
|
|
35
|
+
.option('--duration-ms <ms>', 'Step duration in milliseconds')
|
|
36
|
+
.option('--metadata <json>', 'Step-specific metadata (JSON string)')
|
|
37
|
+
.option('--custom <json>', 'Project-specific custom data (JSON string)')
|
|
38
|
+
.option('--json', 'Output as JSON')
|
|
39
|
+
.action(async (options) => {
|
|
40
|
+
try {
|
|
41
|
+
const manager = new ChangelogManager();
|
|
42
|
+
const entry = manager.emit({
|
|
43
|
+
run_id: options.runId,
|
|
44
|
+
step_id: options.stepId,
|
|
45
|
+
step_name: options.stepName,
|
|
46
|
+
phase: options.phase,
|
|
47
|
+
status: options.status,
|
|
48
|
+
event_type: options.eventType,
|
|
49
|
+
workflow_id: options.workflowId,
|
|
50
|
+
work_id: options.workId,
|
|
51
|
+
target: options.target,
|
|
52
|
+
environment: options.environment,
|
|
53
|
+
message: options.message,
|
|
54
|
+
duration_ms: options.durationMs ? parseInt(options.durationMs, 10) : undefined,
|
|
55
|
+
metadata: options.metadata ? JSON.parse(options.metadata) : undefined,
|
|
56
|
+
custom: options.custom ? JSON.parse(options.custom) : undefined,
|
|
57
|
+
});
|
|
58
|
+
if (options.json) {
|
|
59
|
+
console.log(JSON.stringify({ status: 'success', data: entry }, null, 2));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log(chalk.green(`Emitted changelog entry: ${entry.event_type}`));
|
|
63
|
+
console.log(chalk.gray(` Event ID: ${entry.event_id}`));
|
|
64
|
+
console.log(chalk.gray(` Step: ${entry.step_name}`));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
handleChangelogError(error, options);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function createChangelogQueryCommand() {
|
|
73
|
+
return new Command('query')
|
|
74
|
+
.description('Query the project-level changelog')
|
|
75
|
+
.option('--event-type <type>', 'Filter by event type')
|
|
76
|
+
.option('--target <target>', 'Filter by target')
|
|
77
|
+
.option('--phase <phase>', 'Filter by phase')
|
|
78
|
+
.option('--status <status>', 'Filter by status')
|
|
79
|
+
.option('--work-id <id>', 'Filter by work item ID')
|
|
80
|
+
.option('--since <date>', 'Filter entries after this date (ISO 8601)')
|
|
81
|
+
.option('--until <date>', 'Filter entries before this date (ISO 8601)')
|
|
82
|
+
.option('--limit <n>', 'Maximum entries to return')
|
|
83
|
+
.option('--json', 'Output as JSON')
|
|
84
|
+
.action(async (options) => {
|
|
85
|
+
try {
|
|
86
|
+
const manager = new ChangelogManager();
|
|
87
|
+
const result = manager.query({
|
|
88
|
+
event_type: options.eventType,
|
|
89
|
+
target: options.target,
|
|
90
|
+
phase: options.phase,
|
|
91
|
+
status: options.status,
|
|
92
|
+
work_id: options.workId,
|
|
93
|
+
since: options.since,
|
|
94
|
+
until: options.until,
|
|
95
|
+
limit: options.limit ? parseInt(options.limit, 10) : undefined,
|
|
96
|
+
});
|
|
97
|
+
if (options.json) {
|
|
98
|
+
console.log(JSON.stringify({ status: 'success', data: result }, null, 2));
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
if (result.entries.length === 0) {
|
|
102
|
+
console.log(chalk.yellow('No changelog entries found'));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log(chalk.bold(`Changelog entries (${result.entries.length} of ${result.total}):\n`));
|
|
106
|
+
for (const entry of result.entries) {
|
|
107
|
+
const statusColor = entry.status === 'success' ? chalk.green
|
|
108
|
+
: entry.status === 'failure' ? chalk.red
|
|
109
|
+
: entry.status === 'warning' ? chalk.yellow
|
|
110
|
+
: chalk.gray;
|
|
111
|
+
console.log(`${statusColor(entry.status.padEnd(8))} ${chalk.cyan(entry.event_type.padEnd(22))} ${entry.step_name}`);
|
|
112
|
+
console.log(chalk.gray(` ${entry.timestamp} phase:${entry.phase} work:${entry.work_id}${entry.environment ? ' env:' + entry.environment : ''}`));
|
|
113
|
+
if (entry.message) {
|
|
114
|
+
console.log(chalk.gray(` ${entry.message}`));
|
|
115
|
+
}
|
|
116
|
+
console.log('');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
handleChangelogError(error, options);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function createChangelogAggregateCommand() {
|
|
127
|
+
return new Command('aggregate')
|
|
128
|
+
.description('Aggregate per-run changelog to project-level file')
|
|
129
|
+
.requiredOption('--run-id <id>', 'Run identifier to aggregate')
|
|
130
|
+
.option('--json', 'Output as JSON')
|
|
131
|
+
.action(async (options) => {
|
|
132
|
+
try {
|
|
133
|
+
const manager = new ChangelogManager();
|
|
134
|
+
const result = manager.aggregate(options.runId);
|
|
135
|
+
if (options.json) {
|
|
136
|
+
console.log(JSON.stringify({ status: 'success', data: result }, null, 2));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
if (result.entries_aggregated === 0) {
|
|
140
|
+
console.log(chalk.yellow('No entries to aggregate'));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(chalk.green(`Aggregated ${result.entries_aggregated} changelog entries`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
handleChangelogError(error, options);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function createChangelogReadRunCommand() {
|
|
153
|
+
return new Command('read-run')
|
|
154
|
+
.description('Read changelog entries for a specific run')
|
|
155
|
+
.requiredOption('--run-id <id>', 'Run identifier')
|
|
156
|
+
.option('--json', 'Output as JSON')
|
|
157
|
+
.action(async (options) => {
|
|
158
|
+
try {
|
|
159
|
+
const manager = new ChangelogManager();
|
|
160
|
+
const entries = manager.readRun(options.runId);
|
|
161
|
+
if (options.json) {
|
|
162
|
+
console.log(JSON.stringify({ status: 'success', data: { entries, total: entries.length } }, null, 2));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
if (entries.length === 0) {
|
|
166
|
+
console.log(chalk.yellow('No changelog entries for this run'));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(chalk.bold(`Run changelog (${entries.length} entries):\n`));
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
const statusColor = entry.status === 'success' ? chalk.green
|
|
172
|
+
: entry.status === 'failure' ? chalk.red
|
|
173
|
+
: entry.status === 'warning' ? chalk.yellow
|
|
174
|
+
: chalk.gray;
|
|
175
|
+
console.log(`${statusColor(entry.status.padEnd(8))} ${chalk.cyan(entry.event_type.padEnd(22))} ${entry.step_name}`);
|
|
176
|
+
if (entry.message) {
|
|
177
|
+
console.log(chalk.gray(` ${entry.message}`));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
handleChangelogError(error, options);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// Error handling
|
|
189
|
+
function handleChangelogError(error, options) {
|
|
190
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
191
|
+
if (options.json) {
|
|
192
|
+
console.error(JSON.stringify({
|
|
193
|
+
status: 'error',
|
|
194
|
+
error: { code: 'CHANGELOG_ERROR', message },
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
console.error(chalk.red('Error:'), message);
|
|
199
|
+
}
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,wBAAgB,mBAAmB,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,wBAAgB,mBAAmB,IAAI,OAAO,CAkf7C"}
|
package/dist/commands/config.js
CHANGED
|
@@ -127,6 +127,7 @@ export function createConfigCommand() {
|
|
|
127
127
|
.option('--default-workflow <id>', 'Default workflow ID', 'default')
|
|
128
128
|
.option('--autonomy <level>', 'Autonomy level (dry-run|assisted|guarded|autonomous)', 'guarded')
|
|
129
129
|
.option('--runs-path <path>', 'Directory for run artifacts', '.fractary/faber/runs')
|
|
130
|
+
.option('--changelog-path <path>', 'Path for project-level changelog file', '.fractary/changelog.ndjson')
|
|
130
131
|
.option('--force', 'Overwrite existing configuration')
|
|
131
132
|
.action(async (options) => {
|
|
132
133
|
try {
|
|
@@ -155,6 +156,9 @@ export function createConfigCommand() {
|
|
|
155
156
|
runs: {
|
|
156
157
|
path: options.runsPath,
|
|
157
158
|
},
|
|
159
|
+
changelog: {
|
|
160
|
+
path: options.changelogPath,
|
|
161
|
+
},
|
|
158
162
|
};
|
|
159
163
|
// Load existing config or create empty
|
|
160
164
|
let config = loadYamlConfig({ warnMissingEnvVars: false }) || { version: '2.0' };
|
|
@@ -197,6 +201,7 @@ ${yaml.dump(manifest, { indent: 2, lineWidth: 100 })}`;
|
|
|
197
201
|
console.log(` Default workflow: ${options.defaultWorkflow}`);
|
|
198
202
|
console.log(` Autonomy: ${options.autonomy}`);
|
|
199
203
|
console.log(` Runs path: ${options.runsPath}`);
|
|
204
|
+
console.log(` Changelog path: ${options.changelogPath}`);
|
|
200
205
|
}
|
|
201
206
|
catch (error) {
|
|
202
207
|
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
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;AAqBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAsDxC"}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { createSessionLoadCommand, createSessionSaveCommand } from './commands/s
|
|
|
15
15
|
import { createWorkCommand } from './commands/work/index.js';
|
|
16
16
|
import { createRepoCommand } from './commands/repo/index.js';
|
|
17
17
|
import { createLogsCommand } from './commands/logs/index.js';
|
|
18
|
+
import { createChangelogCommand } from './commands/changelog/index.js';
|
|
18
19
|
import { createMigrateCommand } from './commands/migrate.js';
|
|
19
20
|
import { createPlanCommand } from './commands/plan/index.js';
|
|
20
21
|
import { createAuthCommand } from './commands/auth/index.js';
|
|
@@ -59,6 +60,7 @@ export function createFaberCLI() {
|
|
|
59
60
|
program.addCommand(createWorkCommand());
|
|
60
61
|
program.addCommand(createRepoCommand());
|
|
61
62
|
program.addCommand(createLogsCommand());
|
|
63
|
+
program.addCommand(createChangelogCommand());
|
|
62
64
|
// Help command
|
|
63
65
|
program.addCommand(new Command('help')
|
|
64
66
|
.description('Show help for all commands')
|