@syntesseraai/opencode-feature-factory 0.1.12 → 0.1.13
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/package.json +1 -1
- package/src/stop-quality-gate.ts +94 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@syntesseraai/opencode-feature-factory",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.13",
|
|
5
5
|
"description": "OpenCode plugin for Feature Factory agents - provides planning, implementation, review, testing, and validation agents",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
package/src/stop-quality-gate.ts
CHANGED
|
@@ -261,23 +261,66 @@ async function runCommand(
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Progress callback for real-time feedback
|
|
266
|
+
*/
|
|
267
|
+
type ProgressCallback = (params: {
|
|
268
|
+
type: 'started' | 'step-complete' | 'step-failed' | 'completed';
|
|
269
|
+
step?: string;
|
|
270
|
+
stepIndex?: number;
|
|
271
|
+
totalSteps?: number;
|
|
272
|
+
exitCode?: number;
|
|
273
|
+
results?: StepResult[];
|
|
274
|
+
}) => Promise<void>;
|
|
275
|
+
|
|
264
276
|
/**
|
|
265
277
|
* Run all command steps sequentially, stopping on first failure
|
|
266
|
-
*
|
|
278
|
+
* Provides real-time progress feedback via callback
|
|
267
279
|
*/
|
|
268
280
|
async function runAllCommands(
|
|
269
281
|
$: BunShell,
|
|
270
282
|
steps: { step: string; cmd: string }[],
|
|
271
|
-
cwd: string
|
|
283
|
+
cwd: string,
|
|
284
|
+
onProgress: ProgressCallback
|
|
272
285
|
): Promise<StepResult[]> {
|
|
273
286
|
const results: StepResult[] = [];
|
|
274
287
|
|
|
275
|
-
|
|
288
|
+
// Report started before running any commands
|
|
289
|
+
await onProgress({
|
|
290
|
+
type: 'started',
|
|
291
|
+
totalSteps: steps.length,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
for (let i = 0; i < steps.length; i++) {
|
|
295
|
+
const { step, cmd } = steps[i];
|
|
276
296
|
const { exitCode, output } = await runCommand($, cmd, cwd);
|
|
277
|
-
|
|
297
|
+
const result = { step, cmd, exitCode, output };
|
|
298
|
+
results.push(result);
|
|
299
|
+
|
|
300
|
+
if (exitCode !== 0) {
|
|
301
|
+
await onProgress({
|
|
302
|
+
type: 'step-failed',
|
|
303
|
+
step,
|
|
304
|
+
stepIndex: i + 1,
|
|
305
|
+
totalSteps: steps.length,
|
|
306
|
+
exitCode,
|
|
307
|
+
});
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
await onProgress({
|
|
312
|
+
type: 'step-complete',
|
|
313
|
+
step,
|
|
314
|
+
stepIndex: i + 1,
|
|
315
|
+
totalSteps: steps.length,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
278
318
|
|
|
279
|
-
|
|
280
|
-
|
|
319
|
+
if (results.every((r) => r.exitCode === 0)) {
|
|
320
|
+
await onProgress({
|
|
321
|
+
type: 'completed',
|
|
322
|
+
results,
|
|
323
|
+
});
|
|
281
324
|
}
|
|
282
325
|
|
|
283
326
|
return results;
|
|
@@ -437,7 +480,51 @@ export async function createQualityGateHooks(input: PluginInput): Promise<Partia
|
|
|
437
480
|
|
|
438
481
|
if (state.dirty || cacheExpired || results.length === 0) {
|
|
439
482
|
const startTime = Date.now();
|
|
440
|
-
results = await runAllCommands($, plan, cwd)
|
|
483
|
+
results = await runAllCommands($, plan, cwd, async (progress) => {
|
|
484
|
+
switch (progress.type) {
|
|
485
|
+
case 'started':
|
|
486
|
+
await client.session.prompt({
|
|
487
|
+
path: { id: sessionId },
|
|
488
|
+
body: {
|
|
489
|
+
parts: [
|
|
490
|
+
{
|
|
491
|
+
type: 'text',
|
|
492
|
+
text: `## Running quality gate${progress.totalSteps ? ` (${progress.totalSteps} steps)` : ''}...`,
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
},
|
|
496
|
+
});
|
|
497
|
+
break;
|
|
498
|
+
case 'step-complete':
|
|
499
|
+
await client.session.prompt({
|
|
500
|
+
path: { id: sessionId },
|
|
501
|
+
body: {
|
|
502
|
+
parts: [
|
|
503
|
+
{
|
|
504
|
+
type: 'text',
|
|
505
|
+
text: `## Quality gate progress: ${progress.step} ✓ (${progress.stepIndex}/${progress.totalSteps})`,
|
|
506
|
+
},
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
break;
|
|
511
|
+
case 'step-failed':
|
|
512
|
+
await client.session.prompt({
|
|
513
|
+
path: { id: sessionId },
|
|
514
|
+
body: {
|
|
515
|
+
parts: [
|
|
516
|
+
{
|
|
517
|
+
type: 'text',
|
|
518
|
+
text: `## Quality gate failed: ${progress.step} ✗ (${progress.stepIndex}/${progress.totalSteps})`,
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
break;
|
|
524
|
+
case 'completed':
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
});
|
|
441
528
|
const durationMs = Date.now() - startTime;
|
|
442
529
|
|
|
443
530
|
state.lastResults = results;
|