@fractary/faber-cli 1.6.3 → 1.6.4
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 +0 -0
- package/README.md +0 -7
- 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 +8 -17
- package/dist/commands/workflow/index.d.ts.map +1 -1
- package/dist/commands/workflow/index.js +9 -388
- package/dist/index.d.ts +0 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- 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 +0 -0
- package/dist/lib/repo-client.js +2 -2
- 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 +0 -0
- package/dist/types/config.d.ts.map +0 -0
- 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 +1 -1
- package/schemas/plan.schema.json +0 -0
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -62,17 +62,10 @@ fractary-faber config init --autonomy guarded
|
|
|
62
62
|
# Plan a workflow (creates plan, branch, worktree)
|
|
63
63
|
fractary-faber workflow-plan --work-id 123
|
|
64
64
|
|
|
65
|
-
# Start a FABER workflow
|
|
66
|
-
fractary-faber workflow-run --work-id 123
|
|
67
|
-
|
|
68
65
|
# Check workflow status
|
|
69
66
|
fractary-faber run-inspect
|
|
70
67
|
fractary-faber run-inspect --work-id 123
|
|
71
68
|
|
|
72
|
-
# Pause/resume workflows
|
|
73
|
-
fractary-faber workflow-pause <workflow-id>
|
|
74
|
-
fractary-faber workflow-resume <workflow-id>
|
|
75
|
-
|
|
76
69
|
# Recover from checkpoint
|
|
77
70
|
fractary-faber workflow-recover <workflow-id>
|
|
78
71
|
|
|
File without changes
|
|
File without changes
|
package/dist/__mocks__/chalk.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/commands/config.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/commands/migrate.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/commands/runs.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/commands/runs.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/commands/session.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workflow commands - FABER workflow
|
|
2
|
+
* Workflow commands - FABER workflow management
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides run-inspect, workflow-create, workflow-update, workflow-inspect,
|
|
5
|
+
* workflow-resolve, workflow-debug, workflow-execute, and workflow-batch-plan commands.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: workflow-run, workflow-resume, workflow-pause, and workflow-batch-run
|
|
8
|
+
* have been removed. Workflow execution should go through the
|
|
9
|
+
* fractary-faber-workflow-run skill, not the CLI.
|
|
5
10
|
*/
|
|
6
11
|
import { Command } from 'commander';
|
|
7
12
|
/**
|
|
8
|
-
* Create the
|
|
9
|
-
*/
|
|
10
|
-
export declare function createRunCommand(): Command;
|
|
13
|
+
* Create the run-inspect command
|
|
11
14
|
/**
|
|
12
15
|
* Create the run-inspect command
|
|
13
16
|
*/
|
|
14
17
|
export declare function createStatusCommand(): Command;
|
|
15
|
-
/**
|
|
16
|
-
* Create the workflow-resume command
|
|
17
|
-
*/
|
|
18
|
-
export declare function createResumeCommand(): Command;
|
|
19
|
-
/**
|
|
20
|
-
* Create the workflow-pause command
|
|
21
|
-
*/
|
|
22
|
-
export declare function createPauseCommand(): Command;
|
|
23
18
|
/**
|
|
24
19
|
* Create the workflow-recover command
|
|
25
20
|
*/
|
|
@@ -61,10 +56,6 @@ export declare function createWorkflowDebugCommand(): Command;
|
|
|
61
56
|
* Create the workflow-batch-plan command
|
|
62
57
|
*/
|
|
63
58
|
export declare function createBatchPlanCommand(): Command;
|
|
64
|
-
/**
|
|
65
|
-
* Create the workflow-batch-run command
|
|
66
|
-
*/
|
|
67
|
-
export declare function createBatchRunCommand(): Command;
|
|
68
59
|
/**
|
|
69
60
|
* Create the workflow-execute command (multi-model CLI-native execution)
|
|
70
61
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/workflow/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/workflow/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAiF7C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CA2B9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CA8B9C;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAoCrD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CA4BrD;AAED;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CA0CtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAkDtD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAkDpD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAehD;AA4LD;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAuHtD"}
|
|
@@ -1,156 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workflow commands - FABER workflow
|
|
2
|
+
* Workflow commands - FABER workflow management
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides run-inspect, workflow-create, workflow-update, workflow-inspect,
|
|
5
|
+
* workflow-resolve, workflow-debug, workflow-execute, and workflow-batch-plan commands.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: workflow-run, workflow-resume, workflow-pause, and workflow-batch-run
|
|
8
|
+
* have been removed. Workflow execution should go through the
|
|
9
|
+
* fractary-faber-workflow-run skill, not the CLI.
|
|
5
10
|
*/
|
|
6
11
|
import { Command } from 'commander';
|
|
7
12
|
import chalk from 'chalk';
|
|
8
13
|
import { FaberWorkflow, StateManager, createWorkflow, updateWorkflow, inspectWorkflow, debugWorkflow, WorkflowResolver, ExecutorRegistry, WorkflowExecutor, } from '@fractary/faber';
|
|
9
14
|
import { parsePositiveInteger } from '../../utils/validation.js';
|
|
10
15
|
/**
|
|
11
|
-
* Create the
|
|
12
|
-
*/
|
|
13
|
-
export function createRunCommand() {
|
|
14
|
-
return new Command('workflow-run')
|
|
15
|
-
.description('Run FABER workflow (supports comma-separated work IDs for batch execution)')
|
|
16
|
-
.requiredOption('--work-id <ids>', 'Work item ID(s) to process (comma-separated for batch, e.g., "258,259,260")')
|
|
17
|
-
.option('--autonomy <level>', 'Autonomy level: supervised|assisted|autonomous', 'supervised')
|
|
18
|
-
.option('--phase <phases>', 'Execute only specified phase(s) - comma-separated')
|
|
19
|
-
.option('--force-new', 'Force fresh start, bypass auto-resume')
|
|
20
|
-
.option('--resume-batch', 'Resume a previously interrupted batch')
|
|
21
|
-
.option('--json', 'Output as JSON')
|
|
22
|
-
.action(async (options) => {
|
|
23
|
-
try {
|
|
24
|
-
const workIds = options.workId.split(',').map((id) => id.trim()).filter(Boolean);
|
|
25
|
-
const isBatch = workIds.length > 1;
|
|
26
|
-
if (isBatch) {
|
|
27
|
-
// Batch mode: sequential execution
|
|
28
|
-
if (!options.json) {
|
|
29
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
30
|
-
console.log(chalk.blue.bold(' BATCH MODE: Sequential Multi-Workflow Execution'));
|
|
31
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
32
|
-
console.log(chalk.gray(`Work IDs: ${workIds.join(', ')}`));
|
|
33
|
-
console.log(chalk.gray(`Autonomy: ${options.autonomy}`));
|
|
34
|
-
if (options.phase)
|
|
35
|
-
console.log(chalk.gray(`Phases: ${options.phase}`));
|
|
36
|
-
console.log(chalk.gray(`Total workflows: ${workIds.length}`));
|
|
37
|
-
console.log('');
|
|
38
|
-
}
|
|
39
|
-
const results = [];
|
|
40
|
-
for (let i = 0; i < workIds.length; i++) {
|
|
41
|
-
const workId = workIds[i];
|
|
42
|
-
if (!options.json) {
|
|
43
|
-
console.log(chalk.blue(`\n═══ Workflow ${i + 1}/${workIds.length}: #${workId} ═══`));
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
const workflow = new FaberWorkflow();
|
|
47
|
-
workflow.addEventListener((event, data) => {
|
|
48
|
-
if (options.json)
|
|
49
|
-
return;
|
|
50
|
-
switch (event) {
|
|
51
|
-
case 'phase:start':
|
|
52
|
-
console.log(chalk.cyan(`\n→ Starting phase: ${String(data.phase || '').toUpperCase()}`));
|
|
53
|
-
break;
|
|
54
|
-
case 'phase:complete':
|
|
55
|
-
console.log(chalk.green(` ✓ Completed phase: ${data.phase}`));
|
|
56
|
-
break;
|
|
57
|
-
case 'workflow:fail':
|
|
58
|
-
case 'phase:fail':
|
|
59
|
-
console.error(chalk.red(` ✗ Error: ${data.error || 'Unknown error'}`));
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
const result = await workflow.run({
|
|
64
|
-
workId,
|
|
65
|
-
autonomy: options.autonomy,
|
|
66
|
-
phase: options.phase,
|
|
67
|
-
forceNew: options.forceNew,
|
|
68
|
-
});
|
|
69
|
-
results.push({ workId, status: result.status });
|
|
70
|
-
if (!options.json) {
|
|
71
|
-
console.log(chalk.green(`✓ Workflow ${i + 1}/${workIds.length} completed: #${workId}`));
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
-
results.push({ workId, status: 'failed', error: message });
|
|
77
|
-
if (!options.json) {
|
|
78
|
-
console.error(chalk.red(`✗ Workflow ${i + 1}/${workIds.length} FAILED: #${workId}`));
|
|
79
|
-
console.error(chalk.red(` Error: ${message}`));
|
|
80
|
-
console.error(chalk.yellow('\nBatch stopped due to error. Remaining workflows not executed.'));
|
|
81
|
-
}
|
|
82
|
-
break; // Stop batch on error
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Batch summary
|
|
86
|
-
if (options.json) {
|
|
87
|
-
console.log(JSON.stringify({ status: 'success', data: { batch: true, results } }, null, 2));
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
const completed = results.filter(r => r.status !== 'failed');
|
|
91
|
-
const failed = results.filter(r => r.status === 'failed');
|
|
92
|
-
console.log(chalk.blue.bold('\n═══════════════════════════════════════════════'));
|
|
93
|
-
console.log(chalk.blue.bold(' BATCH COMPLETE'));
|
|
94
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
95
|
-
console.log(`Total: ${workIds.length} | Completed: ${completed.length} | Failed: ${failed.length}`);
|
|
96
|
-
for (const r of results) {
|
|
97
|
-
if (r.status === 'failed') {
|
|
98
|
-
console.log(chalk.red(` ✗ #${r.workId} — ${r.error}`));
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
console.log(chalk.green(` ✓ #${r.workId} — ${r.status}`));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (results.some(r => r.status === 'failed')) {
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
// Single mode: original behavior
|
|
111
|
-
const workflow = new FaberWorkflow();
|
|
112
|
-
if (!options.json) {
|
|
113
|
-
console.log(chalk.blue(`Starting FABER workflow for work item #${workIds[0]}`));
|
|
114
|
-
console.log(chalk.gray(`Autonomy: ${options.autonomy}`));
|
|
115
|
-
}
|
|
116
|
-
workflow.addEventListener((event, data) => {
|
|
117
|
-
if (options.json)
|
|
118
|
-
return;
|
|
119
|
-
switch (event) {
|
|
120
|
-
case 'phase:start':
|
|
121
|
-
console.log(chalk.cyan(`\n→ Starting phase: ${String(data.phase || '').toUpperCase()}`));
|
|
122
|
-
break;
|
|
123
|
-
case 'phase:complete':
|
|
124
|
-
console.log(chalk.green(` ✓ Completed phase: ${data.phase}`));
|
|
125
|
-
break;
|
|
126
|
-
case 'workflow:fail':
|
|
127
|
-
case 'phase:fail':
|
|
128
|
-
console.error(chalk.red(` ✗ Error: ${data.error || 'Unknown error'}`));
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
const result = await workflow.run({
|
|
133
|
-
workId: workIds[0],
|
|
134
|
-
autonomy: options.autonomy,
|
|
135
|
-
phase: options.phase,
|
|
136
|
-
forceNew: options.forceNew,
|
|
137
|
-
});
|
|
138
|
-
if (options.json) {
|
|
139
|
-
console.log(JSON.stringify({ status: 'success', data: result }, null, 2));
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
console.log(chalk.green(`\n✓ Workflow ${result.status}`));
|
|
143
|
-
console.log(chalk.gray(` Workflow ID: ${result.workflow_id}`));
|
|
144
|
-
console.log(chalk.gray(` Duration: ${result.duration_ms}ms`));
|
|
145
|
-
console.log(chalk.gray(` Phases: ${result.phases.map((p) => p.phase).join(' → ')}`));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
handleWorkflowError(error, options);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
16
|
+
* Create the run-inspect command
|
|
154
17
|
/**
|
|
155
18
|
* Create the run-inspect command
|
|
156
19
|
*/
|
|
@@ -238,58 +101,6 @@ export function createStatusCommand() {
|
|
|
238
101
|
}
|
|
239
102
|
});
|
|
240
103
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Create the workflow-resume command
|
|
243
|
-
*/
|
|
244
|
-
export function createResumeCommand() {
|
|
245
|
-
return new Command('workflow-resume')
|
|
246
|
-
.description('Resume a paused workflow')
|
|
247
|
-
.argument('<workflow_id>', 'Workflow ID to resume')
|
|
248
|
-
.option('--json', 'Output as JSON')
|
|
249
|
-
.action(async (workflowId, options) => {
|
|
250
|
-
try {
|
|
251
|
-
const workflow = new FaberWorkflow();
|
|
252
|
-
if (!options.json) {
|
|
253
|
-
console.log(chalk.blue(`Resuming workflow: ${workflowId}`));
|
|
254
|
-
}
|
|
255
|
-
const result = await workflow.resume(workflowId);
|
|
256
|
-
if (options.json) {
|
|
257
|
-
console.log(JSON.stringify({ status: 'success', data: result }, null, 2));
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
console.log(chalk.green(`\n✓ Workflow ${result.status}`));
|
|
261
|
-
console.log(chalk.gray(` Duration: ${result.duration_ms}ms`));
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
catch (error) {
|
|
265
|
-
handleWorkflowError(error, options);
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Create the workflow-pause command
|
|
271
|
-
*/
|
|
272
|
-
export function createPauseCommand() {
|
|
273
|
-
return new Command('workflow-pause')
|
|
274
|
-
.description('Pause a running workflow')
|
|
275
|
-
.argument('<workflow_id>', 'Workflow ID to pause')
|
|
276
|
-
.option('--json', 'Output as JSON')
|
|
277
|
-
.action(async (workflowId, options) => {
|
|
278
|
-
try {
|
|
279
|
-
const workflow = new FaberWorkflow();
|
|
280
|
-
workflow.pause(workflowId);
|
|
281
|
-
if (options.json) {
|
|
282
|
-
console.log(JSON.stringify({ status: 'success', data: { paused: workflowId } }, null, 2));
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
console.log(chalk.green(`✓ Paused workflow: ${workflowId}`));
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
handleWorkflowError(error, options);
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
104
|
/**
|
|
294
105
|
* Create the workflow-recover command
|
|
295
106
|
*/
|
|
@@ -610,27 +421,6 @@ export function createBatchPlanCommand() {
|
|
|
610
421
|
}
|
|
611
422
|
});
|
|
612
423
|
}
|
|
613
|
-
/**
|
|
614
|
-
* Create the workflow-batch-run command
|
|
615
|
-
*/
|
|
616
|
-
export function createBatchRunCommand() {
|
|
617
|
-
return new Command('workflow-batch-run')
|
|
618
|
-
.description('Execute a planned FABER batch sequentially with state tracking')
|
|
619
|
-
.requiredOption('--batch <batch-id>', 'Batch ID to execute (from workflow-batch-plan)')
|
|
620
|
-
.option('--autonomous', 'Auto-skip failed items without prompting (for overnight unattended runs)')
|
|
621
|
-
.option('--resume', 'Skip already-completed items (safe to re-run after interruption)')
|
|
622
|
-
.option('--phase <phases>', 'Execute only specified phase(s) - comma-separated')
|
|
623
|
-
.option('--force-new', 'Force fresh start for each item, bypass auto-resume')
|
|
624
|
-
.option('--json', 'Output as JSON')
|
|
625
|
-
.action(async (options) => {
|
|
626
|
-
try {
|
|
627
|
-
await executeBatchRunCommand(options);
|
|
628
|
-
}
|
|
629
|
-
catch (error) {
|
|
630
|
-
handleWorkflowError(error, options);
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
424
|
// ─── Batch Implementation ───────────────────────────────────────────────────
|
|
635
425
|
import fs from 'fs/promises';
|
|
636
426
|
import path from 'path';
|
|
@@ -643,11 +433,6 @@ function generateBatchId() {
|
|
|
643
433
|
const ts = now.toISOString().replace(/:/g, '-').replace(/\.\d{3}Z$/, 'Z');
|
|
644
434
|
return `batch-${ts}`;
|
|
645
435
|
}
|
|
646
|
-
async function readBatchState(batchId) {
|
|
647
|
-
const statePath = path.join(getBatchDir(batchId), 'state.json');
|
|
648
|
-
const content = await fs.readFile(statePath, 'utf-8');
|
|
649
|
-
return JSON.parse(content);
|
|
650
|
-
}
|
|
651
436
|
async function writeBatchState(batchId, state) {
|
|
652
437
|
state.updated_at = new Date().toISOString();
|
|
653
438
|
const statePath = path.join(getBatchDir(batchId), 'state.json');
|
|
@@ -765,174 +550,10 @@ async function executeBatchPlanCommand(options) {
|
|
|
765
550
|
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
766
551
|
console.log(`Total: ${workIds.length} | Planned: ${planned} | Failed: ${failed}`);
|
|
767
552
|
console.log('');
|
|
768
|
-
console.log(chalk.cyan('To run this batch
|
|
769
|
-
console.log(chalk.white(` fractary-faber workflow-batch-run --batch ${batchId} --autonomous`));
|
|
770
|
-
console.log('');
|
|
771
|
-
console.log(chalk.cyan('Or in Claude Code:'));
|
|
553
|
+
console.log(chalk.cyan('To run this batch, use the workflow-batch-run skill:'));
|
|
772
554
|
console.log(chalk.white(` /fractary-faber-workflow-batch-run --batch ${batchId} --autonomous`));
|
|
773
555
|
}
|
|
774
556
|
}
|
|
775
|
-
async function executeBatchRunCommand(options) {
|
|
776
|
-
const batchId = options.batch;
|
|
777
|
-
const batchDir = getBatchDir(batchId);
|
|
778
|
-
// Verify batch exists
|
|
779
|
-
try {
|
|
780
|
-
await fs.access(batchDir);
|
|
781
|
-
}
|
|
782
|
-
catch {
|
|
783
|
-
throw new Error(`Batch '${batchId}' not found.\nExpected: ${batchDir}\n\nCreate a batch first:\n fractary-faber workflow-batch-plan --work-id <ids> --name ${batchId}`);
|
|
784
|
-
}
|
|
785
|
-
// Load state
|
|
786
|
-
let state = await readBatchState(batchId);
|
|
787
|
-
if (state.status === 'completed') {
|
|
788
|
-
if (options.json) {
|
|
789
|
-
console.log(JSON.stringify({ status: 'success', data: { batch_id: batchId, message: 'already completed', state } }, null, 2));
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
console.log(chalk.green(`✓ Batch '${batchId}' already completed. Nothing to do.`));
|
|
793
|
-
const done = state.items.filter(i => i.status === 'completed').length;
|
|
794
|
-
console.log(chalk.gray(` Completed: ${done}/${state.items.length}`));
|
|
795
|
-
console.log(chalk.gray('\nTo re-run, edit state.json and reset items to "pending".'));
|
|
796
|
-
}
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
// Filter items to process
|
|
800
|
-
const toProcess = options.resume
|
|
801
|
-
? state.items.filter(i => i.status !== 'completed' && i.status !== 'skipped')
|
|
802
|
-
: state.items.filter(i => i.status !== 'completed' && i.status !== 'skipped');
|
|
803
|
-
if (!options.json) {
|
|
804
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
805
|
-
console.log(chalk.blue.bold(' FABER BATCH RUN'));
|
|
806
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
807
|
-
console.log(chalk.gray(`Batch ID: ${batchId}`));
|
|
808
|
-
console.log(chalk.gray(`Mode: ${options.autonomous ? 'autonomous (unattended)' : 'interactive'}`));
|
|
809
|
-
if (options.resume) {
|
|
810
|
-
const completed = state.items.filter(i => i.status === 'completed').length;
|
|
811
|
-
console.log(chalk.gray(`Resume: ${completed}/${state.items.length} already completed`));
|
|
812
|
-
}
|
|
813
|
-
if (options.phase)
|
|
814
|
-
console.log(chalk.gray(`Phase filter: ${options.phase}`));
|
|
815
|
-
if (options.forceNew)
|
|
816
|
-
console.log(chalk.gray('Force new: yes'));
|
|
817
|
-
console.log(chalk.gray(`Remaining: ${toProcess.length} item(s)`));
|
|
818
|
-
console.log('');
|
|
819
|
-
}
|
|
820
|
-
const results = [];
|
|
821
|
-
for (let i = 0; i < toProcess.length; i++) {
|
|
822
|
-
const item = toProcess[i];
|
|
823
|
-
const workId = item.work_id;
|
|
824
|
-
const globalIndex = state.items.findIndex(s => s.work_id === workId);
|
|
825
|
-
if (!options.json) {
|
|
826
|
-
console.log(chalk.blue(`\n═══ Workflow ${i + 1}/${toProcess.length}: #${workId} ═══`));
|
|
827
|
-
}
|
|
828
|
-
// Mark in progress
|
|
829
|
-
state.items[globalIndex].status = 'in_progress';
|
|
830
|
-
state.items[globalIndex].started_at = new Date().toISOString();
|
|
831
|
-
await writeBatchState(batchId, state);
|
|
832
|
-
try {
|
|
833
|
-
const workflow = new FaberWorkflow();
|
|
834
|
-
workflow.addEventListener((event, data) => {
|
|
835
|
-
if (options.json)
|
|
836
|
-
return;
|
|
837
|
-
switch (event) {
|
|
838
|
-
case 'phase:start':
|
|
839
|
-
console.log(chalk.cyan(`\n → Phase: ${String(data.phase || '').toUpperCase()}`));
|
|
840
|
-
break;
|
|
841
|
-
case 'phase:complete':
|
|
842
|
-
console.log(chalk.green(` ✓ Phase: ${data.phase}`));
|
|
843
|
-
break;
|
|
844
|
-
case 'workflow:fail':
|
|
845
|
-
case 'phase:fail':
|
|
846
|
-
console.error(chalk.red(` ✗ Error: ${data.error || 'Unknown error'}`));
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
const result = await workflow.run({
|
|
851
|
-
workId,
|
|
852
|
-
autonomy: options.autonomous ? 'autonomous' : 'guarded',
|
|
853
|
-
phase: options.phase,
|
|
854
|
-
forceNew: options.forceNew,
|
|
855
|
-
});
|
|
856
|
-
state.items[globalIndex].status = 'completed';
|
|
857
|
-
state.items[globalIndex].run_id = result.run_id || null;
|
|
858
|
-
state.items[globalIndex].completed_at = new Date().toISOString();
|
|
859
|
-
await writeBatchState(batchId, state);
|
|
860
|
-
results.push({ workId, status: 'completed' });
|
|
861
|
-
if (!options.json) {
|
|
862
|
-
console.log(chalk.green(`✓ Completed: #${workId}`));
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
catch (error) {
|
|
866
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
867
|
-
state.items[globalIndex].status = 'failed';
|
|
868
|
-
state.items[globalIndex].skipped = true;
|
|
869
|
-
state.items[globalIndex].error = message;
|
|
870
|
-
state.items[globalIndex].completed_at = new Date().toISOString();
|
|
871
|
-
await writeBatchState(batchId, state);
|
|
872
|
-
results.push({ workId, status: 'failed', error: message });
|
|
873
|
-
if (!options.json) {
|
|
874
|
-
console.error(chalk.red(`✗ Failed: #${workId} — ${message}`));
|
|
875
|
-
}
|
|
876
|
-
if (!options.autonomous) {
|
|
877
|
-
// Non-autonomous: stop on first failure
|
|
878
|
-
if (!options.json) {
|
|
879
|
-
console.error(chalk.yellow('\nBatch stopped. Use --autonomous to auto-skip failures.'));
|
|
880
|
-
console.error(chalk.gray(`Resume with: fractary-faber workflow-batch-run --batch ${batchId} --autonomous --resume`));
|
|
881
|
-
}
|
|
882
|
-
break;
|
|
883
|
-
}
|
|
884
|
-
// Autonomous: continue to next item
|
|
885
|
-
if (!options.json) {
|
|
886
|
-
console.log(chalk.yellow(' → Auto-skipping (autonomous mode). Continuing...'));
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
// Final state
|
|
891
|
-
const allCompleted = state.items.every(i => i.status === 'completed');
|
|
892
|
-
const anyFailed = state.items.some(i => i.status === 'failed');
|
|
893
|
-
state.status = allCompleted ? 'completed' : anyFailed ? 'completed_with_failures' : 'paused';
|
|
894
|
-
await writeBatchState(batchId, state);
|
|
895
|
-
if (options.json) {
|
|
896
|
-
const completed = state.items.filter(i => i.status === 'completed').length;
|
|
897
|
-
const failedCount = state.items.filter(i => i.status === 'failed').length;
|
|
898
|
-
console.log(JSON.stringify({
|
|
899
|
-
status: 'success',
|
|
900
|
-
data: { batch_id: batchId, total: state.items.length, completed, failed: failedCount, results },
|
|
901
|
-
}, null, 2));
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
const completed = state.items.filter(i => i.status === 'completed').length;
|
|
905
|
-
const failedCount = state.items.filter(i => i.status === 'failed').length;
|
|
906
|
-
console.log('');
|
|
907
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
908
|
-
console.log(chalk.blue.bold(' BATCH RUN COMPLETE'));
|
|
909
|
-
console.log(chalk.blue.bold('═══════════════════════════════════════════════'));
|
|
910
|
-
console.log(`Total: ${state.items.length} | Completed: ${completed} | Failed: ${failedCount}`);
|
|
911
|
-
console.log('');
|
|
912
|
-
for (const item of state.items) {
|
|
913
|
-
if (item.status === 'completed') {
|
|
914
|
-
console.log(chalk.green(` ✓ #${item.work_id} — completed`));
|
|
915
|
-
}
|
|
916
|
-
else if (item.status === 'failed') {
|
|
917
|
-
console.log(chalk.red(` ✗ #${item.work_id} — failed: ${item.error}`));
|
|
918
|
-
}
|
|
919
|
-
else if (item.status === 'skipped') {
|
|
920
|
-
console.log(chalk.yellow(` ○ #${item.work_id} — skipped`));
|
|
921
|
-
}
|
|
922
|
-
else {
|
|
923
|
-
console.log(chalk.gray(` ○ #${item.work_id} — ${item.status}`));
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
if (failedCount > 0) {
|
|
927
|
-
console.log('');
|
|
928
|
-
console.log(chalk.cyan('To retry failed items:'));
|
|
929
|
-
console.log(chalk.white(` fractary-faber workflow-batch-run --batch ${batchId} --autonomous --resume`));
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
if (anyFailed && !options.autonomous) {
|
|
933
|
-
process.exit(1);
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
557
|
/**
|
|
937
558
|
* Create the workflow-execute command (multi-model CLI-native execution)
|
|
938
559
|
*/
|
package/dist/index.d.ts
CHANGED
|
File without changes
|
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;AAqBpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,
|
|
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
|
@@ -10,7 +10,7 @@ import dotenv from 'dotenv';
|
|
|
10
10
|
dotenv.config();
|
|
11
11
|
import { Command } from 'commander';
|
|
12
12
|
import chalk from 'chalk';
|
|
13
|
-
import {
|
|
13
|
+
import { createStatusCommand, createRecoverCommand, createCleanupCommand, createWorkflowCreateCommand, createWorkflowUpdateCommand, createWorkflowInspectCommand, createWorkflowResolveCommand, createWorkflowDebugCommand, createBatchPlanCommand, createWorkflowExecuteCommand } from './commands/workflow/index.js';
|
|
14
14
|
import { createSessionLoadCommand, createSessionSaveCommand } from './commands/session.js';
|
|
15
15
|
import { createWorkCommand } from './commands/work/index.js';
|
|
16
16
|
import { createRepoCommand } from './commands/repo/index.js';
|
|
@@ -43,10 +43,7 @@ export function createFaberCLI() {
|
|
|
43
43
|
// Workflow commands (top-level)
|
|
44
44
|
program.addCommand(createRunsCommand()); // runs dir/plan-path/state-path
|
|
45
45
|
program.addCommand(createPlanCommand()); // workflow-plan
|
|
46
|
-
program.addCommand(createRunCommand()); // workflow-run
|
|
47
46
|
program.addCommand(createStatusCommand()); // run-inspect
|
|
48
|
-
program.addCommand(createResumeCommand()); // workflow-resume
|
|
49
|
-
program.addCommand(createPauseCommand()); // workflow-pause
|
|
50
47
|
program.addCommand(createRecoverCommand()); // workflow-recover
|
|
51
48
|
program.addCommand(createCleanupCommand()); // workflow-cleanup
|
|
52
49
|
program.addCommand(createWorkflowCreateCommand()); // workflow-create
|
|
@@ -55,7 +52,6 @@ export function createFaberCLI() {
|
|
|
55
52
|
program.addCommand(createWorkflowResolveCommand()); // workflow-resolve (full inheritance + bundled defaults)
|
|
56
53
|
program.addCommand(createWorkflowDebugCommand()); // workflow-debug
|
|
57
54
|
program.addCommand(createBatchPlanCommand()); // workflow-batch-plan
|
|
58
|
-
program.addCommand(createBatchRunCommand()); // workflow-batch-run
|
|
59
55
|
program.addCommand(createWorkflowExecuteCommand()); // workflow-execute (multi-model CLI-native)
|
|
60
56
|
program.addCommand(createSessionLoadCommand()); // session-load
|
|
61
57
|
program.addCommand(createSessionSaveCommand()); // session-save
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/lib/config.d.ts
CHANGED
|
File without changes
|
package/dist/lib/config.d.ts.map
CHANGED
|
File without changes
|
package/dist/lib/config.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/lib/repo-client.js
CHANGED
|
@@ -72,14 +72,14 @@ export class RepoClient {
|
|
|
72
72
|
owner: organization.trim(),
|
|
73
73
|
repo: project.trim(),
|
|
74
74
|
token,
|
|
75
|
-
host: config.github
|
|
75
|
+
...(config.github?.host ? { host: config.github.host } : {}),
|
|
76
76
|
});
|
|
77
77
|
const repoManager = new RepoManager({
|
|
78
78
|
platform: 'github',
|
|
79
79
|
owner: organization.trim(),
|
|
80
80
|
repo: project.trim(),
|
|
81
81
|
token,
|
|
82
|
-
host: config.github
|
|
82
|
+
...(config.github?.host ? { host: config.github.host } : {}),
|
|
83
83
|
});
|
|
84
84
|
return new RepoClient(workManager, repoManager, organization.trim(), project.trim());
|
|
85
85
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/lib/yaml-config.js
CHANGED
|
File without changes
|
package/dist/types/config.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/types/config.js
CHANGED
|
File without changes
|
package/dist/utils/errors.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/utils/errors.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/utils/labels.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/utils/labels.js
CHANGED
|
File without changes
|
package/dist/utils/output.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/utils/output.js
CHANGED
|
File without changes
|
package/dist/utils/prompt.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/utils/prompt.js
CHANGED
|
File without changes
|
package/dist/utils/sorting.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/utils/sorting.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/utils/validation.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/schemas/plan.schema.json
CHANGED
|
File without changes
|