vibeman 0.0.1 → 0.0.2
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/index.js +5 -7
- package/dist/runtime/api/.tsbuildinfo +1 -1
- package/dist/runtime/api/agent/agent-service.d.ts +11 -13
- package/dist/runtime/api/agent/agent-service.js +25 -31
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +2 -2
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +25 -36
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +48 -14
- package/dist/runtime/api/agent/ai-providers/types.d.ts +2 -0
- package/dist/runtime/api/agent/codex-cli-provider.test.js +37 -0
- package/dist/runtime/api/agent/parsers.d.ts +1 -0
- package/dist/runtime/api/agent/parsers.js +75 -8
- package/dist/runtime/api/agent/prompt-service.d.ts +14 -1
- package/dist/runtime/api/agent/prompt-service.js +123 -14
- package/dist/runtime/api/agent/prompt-service.test.d.ts +1 -0
- package/dist/runtime/api/agent/prompt-service.test.js +230 -0
- package/dist/runtime/api/agent/routing-policy.d.ts +14 -14
- package/dist/runtime/api/api/routers/ai.d.ts +6 -6
- package/dist/runtime/api/api/routers/ai.js +2 -17
- package/dist/runtime/api/api/routers/executions.d.ts +5 -5
- package/dist/runtime/api/api/routers/executions.js +12 -21
- package/dist/runtime/api/api/routers/provider-config.d.ts +165 -0
- package/dist/runtime/api/api/routers/provider-config.js +252 -0
- package/dist/runtime/api/api/routers/tasks.d.ts +10 -10
- package/dist/runtime/api/api/routers/workflows.d.ts +15 -16
- package/dist/runtime/api/api/routers/workflows.js +28 -26
- package/dist/runtime/api/api/routers/worktrees.d.ts +4 -5
- package/dist/runtime/api/api/routers/worktrees.js +11 -11
- package/dist/runtime/api/api/trpc.d.ts +18 -18
- package/dist/runtime/api/index.js +2 -10
- package/dist/runtime/api/lib/local-config.d.ts +245 -0
- package/dist/runtime/api/lib/local-config.js +288 -0
- package/dist/runtime/api/lib/provider-detection.d.ts +59 -0
- package/dist/runtime/api/lib/provider-detection.js +244 -0
- package/dist/runtime/api/lib/server/bootstrap.d.ts +38 -0
- package/dist/runtime/api/lib/server/bootstrap.js +197 -0
- package/dist/runtime/api/lib/server/project-root.js +24 -1
- package/dist/runtime/api/lib/trpc/server.d.ts +124 -31
- package/dist/runtime/api/lib/trpc/server.js +8 -8
- package/dist/runtime/api/lib/trpc/ws-server.js +2 -2
- package/dist/runtime/api/router.d.ts +125 -32
- package/dist/runtime/api/router.js +9 -31
- package/dist/runtime/api/settings-service.js +2 -0
- package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +8 -3
- package/dist/runtime/api/workflows/vibing-orchestrator.js +182 -183
- package/dist/runtime/web/.next/BUILD_ID +1 -1
- package/dist/runtime/web/.next/app-build-manifest.json +2 -2
- package/dist/runtime/web/.next/build-manifest.json +2 -2
- package/dist/runtime/web/.next/prerender-manifest.json +3 -3
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/_not-found.html +2 -2
- package/dist/runtime/web/.next/server/app/_not-found.rsc +5 -5
- package/dist/runtime/web/.next/server/app/api/health/route.js +1 -1
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/index.html +2 -2
- package/dist/runtime/web/.next/server/app/index.rsc +6 -6
- package/dist/runtime/web/.next/server/app/page.js +3 -3
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/chunks/458.js +1 -1
- package/dist/runtime/web/.next/server/pages/404.html +2 -2
- package/dist/runtime/web/.next/server/pages/500.html +1 -1
- package/dist/runtime/web/.next/server/pages-manifest.json +1 -1
- package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -1
- package/dist/runtime/web/.next/static/chunks/app/{layout-dc0cfd29075b2160.js → layout-8435322f09fd0975.js} +1 -1
- package/dist/runtime/web/.next/static/chunks/app/page-8c3ba579efc6f918.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -1
- package/dist/runtime/web/.next/static/chunks/app/page-f34a8b196b18850b.js +0 -1
- /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_buildManifest.js +0 -0
- /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_ssgManifest.js +0 -0
|
@@ -313,10 +313,11 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
313
313
|
}
|
|
314
314
|
return res;
|
|
315
315
|
}
|
|
316
|
-
async
|
|
317
|
-
const res = await this.agentService.
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
async aiReviewCode(taskId, reviewContext, options) {
|
|
317
|
+
const res = await this.agentService.aiReviewCode(taskId, reviewContext, {
|
|
318
|
+
overrides: options?.overrides,
|
|
319
|
+
workflowId: options?.workflowId,
|
|
320
|
+
executionId: options?.executionId,
|
|
320
321
|
});
|
|
321
322
|
const wfId = options?.workflowId;
|
|
322
323
|
if (wfId) {
|
|
@@ -338,17 +339,15 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
338
339
|
return res;
|
|
339
340
|
}
|
|
340
341
|
async aiMerge(taskId, options) {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
return res;
|
|
342
|
+
const overrides = options?.provider || options?.model
|
|
343
|
+
? { provider: options?.provider, model: options?.model }
|
|
344
|
+
: undefined;
|
|
345
|
+
return await this.agentService.aiMerge(taskId, {
|
|
346
|
+
baseBranch: options?.baseBranch,
|
|
347
|
+
workflowId: options?.workflowId,
|
|
348
|
+
executionId: options?.executionId,
|
|
349
|
+
overrides,
|
|
350
|
+
});
|
|
352
351
|
}
|
|
353
352
|
// Worktree façade
|
|
354
353
|
async listWorktrees() {
|
|
@@ -702,27 +701,7 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
702
701
|
metrics.totalDurationMs = Object.values(metrics.durationsMs || {}).reduce((a, b) => a + (b || 0), 0);
|
|
703
702
|
}
|
|
704
703
|
workflow.lastUpdatedAt = now;
|
|
705
|
-
|
|
706
|
-
// can expose review controls (instead of a placeholder that hides actions)
|
|
707
|
-
if (newPhase === 'awaiting-review') {
|
|
708
|
-
const hasReal = Array.isArray(workflow.timeline)
|
|
709
|
-
? workflow.timeline.some((t) => t.phase === 'awaiting-review' && !t.placeholder)
|
|
710
|
-
: false;
|
|
711
|
-
if (!hasReal) {
|
|
712
|
-
workflow.timeline = this.buildTimeline(workflow, {
|
|
713
|
-
id: `awaiting-review:${now}`,
|
|
714
|
-
label: PHASE_LABELS['awaiting-review'],
|
|
715
|
-
phase: 'awaiting-review',
|
|
716
|
-
startTime: now,
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
else {
|
|
720
|
-
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
else {
|
|
724
|
-
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
725
|
-
}
|
|
704
|
+
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
726
705
|
log.info('Workflow phase transition', { workflowId, oldPhase, newPhase }, 'vibing-orchestrator');
|
|
727
706
|
await this.saveWorkflow(workflow);
|
|
728
707
|
this.emit('workflowPhaseChanged', { workflowId, oldPhase, newPhase, workflow });
|
|
@@ -773,6 +752,7 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
773
752
|
}
|
|
774
753
|
: undefined,
|
|
775
754
|
providerOverride: providerOverride || workflow.metadata?.aiRoutingOverrides?.execute_task,
|
|
755
|
+
workflowConfig: workflow.metadata,
|
|
776
756
|
})
|
|
777
757
|
.catch((err) => log.error('Agent execution failed to start (implementation phase)', err, 'vibing-orchestrator'));
|
|
778
758
|
const executionId = await createdPromise;
|
|
@@ -851,29 +831,26 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
851
831
|
await this.executeImplementation(workflowId);
|
|
852
832
|
return;
|
|
853
833
|
case 'validating':
|
|
854
|
-
await this.transitionToPhase(workflowId, 'validating');
|
|
855
834
|
await this.executeValidation(workflowId);
|
|
856
835
|
return;
|
|
857
836
|
case 'ai-reviewing':
|
|
858
|
-
await this.transitionToPhase(workflowId, 'ai-reviewing');
|
|
859
837
|
await this.executeAiReviewPhase(workflowId);
|
|
860
838
|
return;
|
|
839
|
+
case 'awaiting-review':
|
|
840
|
+
await this.executeAwaitingReview(workflowId);
|
|
841
|
+
return;
|
|
861
842
|
case 'merging':
|
|
862
|
-
await this.transitionToPhase(workflowId, 'merging');
|
|
863
843
|
await this.executeMerge(workflowId);
|
|
864
844
|
return;
|
|
865
845
|
case 'approved':
|
|
866
846
|
// Failure after approval typically means merge failed; try merging again
|
|
867
|
-
await this.transitionToPhase(workflowId, 'approved');
|
|
868
847
|
await this.executeMerge(workflowId);
|
|
869
848
|
return;
|
|
870
849
|
case 'cleaning':
|
|
871
|
-
await this.transitionToPhase(workflowId, 'cleaning');
|
|
872
850
|
await this.executeCleanup(workflowId);
|
|
873
851
|
return;
|
|
874
852
|
default:
|
|
875
853
|
// For other phases, restart implementation as a safe default
|
|
876
|
-
await this.transitionToPhase(workflowId, 'implementing');
|
|
877
854
|
await this.executeImplementation(workflowId);
|
|
878
855
|
return;
|
|
879
856
|
}
|
|
@@ -944,20 +921,24 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
944
921
|
/**
|
|
945
922
|
* Perform AI code review of implemented changes
|
|
946
923
|
*/
|
|
947
|
-
async performAICodeReview(workflowId) {
|
|
924
|
+
async performAICodeReview(workflowId, providedExecutionId) {
|
|
948
925
|
const workflow = this.workflows.get(workflowId);
|
|
949
926
|
if (!workflow)
|
|
950
|
-
return false;
|
|
927
|
+
return { passed: false };
|
|
951
928
|
try {
|
|
952
929
|
log.info('Running AI code review', { taskId: workflow.taskId }, 'vibing-orchestrator');
|
|
953
930
|
// Get worktree info for the task
|
|
954
931
|
const worktree = this.agentService.getWorktreeInfo(workflow.taskId);
|
|
955
932
|
if (!worktree) {
|
|
956
933
|
log.warn('No worktree found for AI code review, skipping', undefined, 'vibing-orchestrator');
|
|
957
|
-
return
|
|
934
|
+
return { passed: true, executionId: providedExecutionId };
|
|
958
935
|
}
|
|
959
936
|
// Execute AI code review via agent service
|
|
960
|
-
const review = await this.agentService.
|
|
937
|
+
const review = await this.agentService.aiReviewCode(workflow.taskId, 'Automated AI code review triggered by workflow orchestrator', {
|
|
938
|
+
overrides: workflow.metadata?.aiRoutingOverrides?.ai_codereview,
|
|
939
|
+
executionId: providedExecutionId,
|
|
940
|
+
workflowId,
|
|
941
|
+
});
|
|
961
942
|
// Persist review result into workflow metadata
|
|
962
943
|
const timestamp = new Date().toISOString();
|
|
963
944
|
workflow.metadata = {
|
|
@@ -965,10 +946,13 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
965
946
|
aiReviewResult: { ...review, timestamp },
|
|
966
947
|
};
|
|
967
948
|
// Track execution ID under ai-reviewing for observability
|
|
968
|
-
|
|
949
|
+
const executionId = providedExecutionId ?? review?.executionId;
|
|
950
|
+
if (executionId) {
|
|
969
951
|
workflow.executionIds = workflow.executionIds || {};
|
|
970
952
|
const list = workflow.executionIds['ai-reviewing'] || [];
|
|
971
|
-
|
|
953
|
+
if (!list.includes(executionId)) {
|
|
954
|
+
workflow.executionIds['ai-reviewing'] = [...list, executionId];
|
|
955
|
+
}
|
|
972
956
|
}
|
|
973
957
|
await this.saveWorkflow(workflow);
|
|
974
958
|
// Gate by minimum score from settings
|
|
@@ -977,10 +961,11 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
977
961
|
const msg = `AI code review score too low (${review.qualityScore} < ${minScore})`;
|
|
978
962
|
log.warn('AI code review score too low', { score: review.qualityScore, minScore }, 'vibing-orchestrator');
|
|
979
963
|
workflow.error = msg;
|
|
980
|
-
return false;
|
|
964
|
+
return { passed: false, executionId };
|
|
981
965
|
}
|
|
982
966
|
log.info('AI code review passed', { score: review.qualityScore }, 'vibing-orchestrator');
|
|
983
|
-
|
|
967
|
+
workflow.error = undefined;
|
|
968
|
+
return { passed: true, executionId };
|
|
984
969
|
}
|
|
985
970
|
catch (error) {
|
|
986
971
|
log.warn('AI code review failed', error, 'vibing-orchestrator');
|
|
@@ -989,7 +974,7 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
989
974
|
if (workflowRef) {
|
|
990
975
|
workflowRef.error = `AI code review failed: ${msg}`;
|
|
991
976
|
}
|
|
992
|
-
return false;
|
|
977
|
+
return { passed: false, executionId: providedExecutionId };
|
|
993
978
|
}
|
|
994
979
|
}
|
|
995
980
|
/**
|
|
@@ -999,26 +984,42 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
999
984
|
const workflow = this.workflows.get(workflowId);
|
|
1000
985
|
if (!workflow)
|
|
1001
986
|
return;
|
|
987
|
+
await this.transitionToPhase(workflowId, 'ai-reviewing');
|
|
1002
988
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
989
|
+
const attemptList = workflow.executionIds?.['ai-reviewing'] || [];
|
|
990
|
+
const attempt = attemptList.length + 1;
|
|
991
|
+
const execId = generateId('review');
|
|
992
|
+
workflow.executionIds = workflow.executionIds || {};
|
|
993
|
+
const aiList = workflow.executionIds['ai-reviewing'] || [];
|
|
994
|
+
workflow.executionIds['ai-reviewing'] = [...aiList, execId];
|
|
995
|
+
workflow.timeline = this.buildTimeline(workflow, {
|
|
996
|
+
id: execId,
|
|
997
|
+
label: attempt > 1 ? `AI Review – Retry #${attempt}` : 'AI Review',
|
|
998
|
+
phase: 'ai-reviewing',
|
|
999
|
+
attempt,
|
|
1000
|
+
executionId: execId,
|
|
1001
|
+
startTime: new Date().toISOString(),
|
|
1002
|
+
});
|
|
1003
|
+
await this.saveWorkflow(workflow);
|
|
1004
|
+
this.emit('workflowExecutionStarted', {
|
|
1005
|
+
workflowId,
|
|
1006
|
+
executionId: execId,
|
|
1007
|
+
phase: 'ai-reviewing',
|
|
1008
|
+
workflow,
|
|
1009
|
+
});
|
|
1010
|
+
const { passed } = await this.performAICodeReview(workflowId, execId);
|
|
1011
|
+
const latest = this.workflows.get(workflowId);
|
|
1012
|
+
if (latest) {
|
|
1013
|
+
const timeline = (latest.timeline || []);
|
|
1014
|
+
const item = timeline.find((t) => t.executionId === execId);
|
|
1015
|
+
if (item) {
|
|
1016
|
+
item.endTime = new Date().toISOString();
|
|
1017
|
+
if (!passed) {
|
|
1018
|
+
item.reason = latest.error || 'AI review did not pass the quality threshold';
|
|
1019
|
+
}
|
|
1020
|
+
latest.timeline = this.computeVisibleTimeline(latest);
|
|
1021
|
+
await this.saveWorkflow(latest);
|
|
1022
|
+
}
|
|
1022
1023
|
}
|
|
1023
1024
|
if (!passed) {
|
|
1024
1025
|
const reason = workflow.error || 'AI review did not pass the quality threshold';
|
|
@@ -1033,10 +1034,10 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1033
1034
|
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1034
1035
|
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
1035
1036
|
await this.saveWorkflow(workflow);
|
|
1036
|
-
await this.transitionToPhase(workflowId, 'awaiting-review');
|
|
1037
1037
|
workflow.status = 'awaiting-review';
|
|
1038
1038
|
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1039
1039
|
await this.saveWorkflow(workflow);
|
|
1040
|
+
await this.executeAwaitingReview(workflowId);
|
|
1040
1041
|
const wf = this.workflows.get(workflowId);
|
|
1041
1042
|
if (wf?.metadata.stepByStepMode) {
|
|
1042
1043
|
log.info('Manual step mode – AI review passed; waiting for Continue', { workflowId }, 'vibing-orchestrator');
|
|
@@ -1046,6 +1047,25 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1046
1047
|
await this.handlePhaseFailure(workflowId, 'ai-reviewing', error);
|
|
1047
1048
|
}
|
|
1048
1049
|
}
|
|
1050
|
+
async executeAwaitingReview(workflowId) {
|
|
1051
|
+
const workflow = this.workflows.get(workflowId);
|
|
1052
|
+
if (!workflow)
|
|
1053
|
+
return;
|
|
1054
|
+
await this.transitionToPhase(workflowId, 'awaiting-review');
|
|
1055
|
+
const hasReal = Array.isArray(workflow.timeline)
|
|
1056
|
+
? workflow.timeline.some((t) => t.phase === 'awaiting-review' && !t.placeholder)
|
|
1057
|
+
: false;
|
|
1058
|
+
if (!hasReal) {
|
|
1059
|
+
workflow.timeline = this.buildTimeline(workflow, {
|
|
1060
|
+
id: `awaiting-review:${new Date().toISOString()}`,
|
|
1061
|
+
label: PHASE_LABELS['awaiting-review'],
|
|
1062
|
+
phase: 'awaiting-review',
|
|
1063
|
+
startTime: new Date().toISOString(),
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
1067
|
+
await this.saveWorkflow(workflow);
|
|
1068
|
+
}
|
|
1049
1069
|
/**
|
|
1050
1070
|
* Execute validation phase with quality checks
|
|
1051
1071
|
*/
|
|
@@ -1056,51 +1076,10 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1056
1076
|
await this.transitionToPhase(workflowId, 'validating');
|
|
1057
1077
|
try {
|
|
1058
1078
|
if (!workflow.metadata.autoQualityChecks) {
|
|
1059
|
-
|
|
1060
|
-
// Create a generic execution for consistency/observability
|
|
1061
|
-
const worktree = this.agentService.getWorktreeInfo(workflow.taskId);
|
|
1062
|
-
const workingDirectory = worktree?.path || process.cwd();
|
|
1063
|
-
const execId = await this.agentService.startGenericExecution(workflow.taskId, {
|
|
1064
|
-
workflowId,
|
|
1065
|
-
workingDirectory,
|
|
1066
|
-
});
|
|
1067
|
-
// Track execution id for validating phase and timeline
|
|
1068
|
-
workflow.executionIds = workflow.executionIds || {};
|
|
1069
|
-
const list = workflow.executionIds['validating'] || [];
|
|
1070
|
-
workflow.executionIds['validating'] = [...list, execId];
|
|
1071
|
-
workflow.timeline = this.buildTimeline(workflow, {
|
|
1072
|
-
id: execId,
|
|
1073
|
-
label: list.length >= 1 ? `Validation – Retry #${list.length + 1}` : 'Validation',
|
|
1074
|
-
phase: 'validating',
|
|
1075
|
-
attempt: list.length + 1,
|
|
1076
|
-
executionId: execId,
|
|
1077
|
-
startTime: new Date().toISOString(),
|
|
1078
|
-
endTime: new Date().toISOString(),
|
|
1079
|
-
reason: 'Auto quality checks disabled; skipping validation',
|
|
1080
|
-
});
|
|
1081
|
-
await this.agentService.logGenericExecution(execId, '[validation] Auto quality checks disabled; skipping validation.');
|
|
1082
|
-
await this.agentService.completeGenericExecution(execId, 'completed');
|
|
1083
|
-
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
1084
|
-
await this.saveWorkflow(workflow);
|
|
1085
|
-
// Mark checkpoint as validated even when skipping checks
|
|
1086
|
-
workflow.status = 'validated';
|
|
1087
|
-
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1088
|
-
await this.saveWorkflow(workflow);
|
|
1089
|
-
await this.transitionToPhase(workflowId, 'awaiting-review');
|
|
1090
|
-
const wf = this.workflows.get(workflowId);
|
|
1091
|
-
if (wf?.metadata.stepByStepMode) {
|
|
1092
|
-
log.info('Manual step mode – validation skipped; waiting for Continue (awaiting-review)', { workflowId }, 'vibing-orchestrator');
|
|
1093
|
-
}
|
|
1079
|
+
// TODO implement later
|
|
1094
1080
|
return;
|
|
1095
1081
|
}
|
|
1096
1082
|
log.info('Running quality checks', { taskId: workflow.taskId }, 'vibing-orchestrator');
|
|
1097
|
-
// Timeline: start validation
|
|
1098
|
-
workflow.timeline = this.buildTimeline(workflow, {
|
|
1099
|
-
id: `validation:${new Date().toISOString()}`,
|
|
1100
|
-
label: 'Validation',
|
|
1101
|
-
phase: 'validating',
|
|
1102
|
-
startTime: new Date().toISOString(),
|
|
1103
|
-
});
|
|
1104
1083
|
// Get worktree path for quality checks
|
|
1105
1084
|
const worktree = this.agentService.getWorktreeInfo(workflow.taskId);
|
|
1106
1085
|
const workingDirectory = worktree?.path || process.cwd();
|
|
@@ -1112,17 +1091,13 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1112
1091
|
workflow.executionIds = workflow.executionIds || {};
|
|
1113
1092
|
const valList = workflow.executionIds['validating'] || [];
|
|
1114
1093
|
workflow.executionIds['validating'] = [...valList, execId];
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
t.executionId = execId;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
workflow.timeline = this.computeVisibleTimeline(workflow);
|
|
1094
|
+
workflow.timeline = this.buildTimeline(workflow, {
|
|
1095
|
+
id: `validation:${new Date().toISOString()}`,
|
|
1096
|
+
label: 'Validation',
|
|
1097
|
+
phase: 'validating',
|
|
1098
|
+
startTime: new Date().toISOString(),
|
|
1099
|
+
executionId: execId,
|
|
1100
|
+
});
|
|
1126
1101
|
await this.saveWorkflow(workflow);
|
|
1127
1102
|
// Notify listeners that a validation execution has started
|
|
1128
1103
|
this.emit('workflowExecutionStarted', {
|
|
@@ -1158,14 +1133,12 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1158
1133
|
});
|
|
1159
1134
|
workflow.qualityResults = qualityResults;
|
|
1160
1135
|
// Timeline: end validation
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
break;
|
|
1168
|
-
}
|
|
1136
|
+
const timeline = workflow.timeline;
|
|
1137
|
+
for (let i = timeline.length - 1; i >= 0; i--) {
|
|
1138
|
+
const t = timeline[i];
|
|
1139
|
+
if (t.phase === 'validating' && !t.endTime) {
|
|
1140
|
+
t.endTime = new Date().toISOString();
|
|
1141
|
+
break;
|
|
1169
1142
|
}
|
|
1170
1143
|
}
|
|
1171
1144
|
// Mark execution complete (completed even if checks failed; workflow handles failure)
|
|
@@ -1184,37 +1157,17 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1184
1157
|
}
|
|
1185
1158
|
log.info('Quality checks passed', { taskId: workflow.taskId }, 'vibing-orchestrator');
|
|
1186
1159
|
// Update checkpoint status
|
|
1160
|
+
await this.transitionToPhase(workflowId, 'validated');
|
|
1187
1161
|
workflow.status = 'validated';
|
|
1188
1162
|
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1189
1163
|
await this.saveWorkflow(workflow);
|
|
1190
|
-
// Move to AI review phase or directly to reviewing
|
|
1191
1164
|
if (workflow.metadata.aiCodeReview) {
|
|
1192
|
-
await this.transitionToPhase(workflowId, 'ai-reviewing');
|
|
1193
1165
|
if (workflow.metadata.stepByStepMode) {
|
|
1194
1166
|
log.info('Manual step mode – waiting for Continue to run AI review', { workflowId }, 'vibing-orchestrator');
|
|
1195
1167
|
}
|
|
1196
1168
|
else {
|
|
1197
1169
|
await this.executeAiReviewPhase(workflowId);
|
|
1198
1170
|
}
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1201
|
-
await this.transitionToPhase(workflowId, 'validated');
|
|
1202
|
-
// If manual step mode is off and human approval not required, auto-approve
|
|
1203
|
-
if (!workflow.metadata.stepByStepMode && !workflow.metadata.requireHumanApproval) {
|
|
1204
|
-
log.info('Auto-approving workflow (human approval disabled)', { workflowId }, 'vibing-orchestrator');
|
|
1205
|
-
// Update checkpoint to approved
|
|
1206
|
-
workflow.status = 'approved';
|
|
1207
|
-
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1208
|
-
await this.saveWorkflow(workflow);
|
|
1209
|
-
await this.approveWorkflow(workflowId);
|
|
1210
|
-
}
|
|
1211
|
-
else {
|
|
1212
|
-
// Move into awaiting-review phase so UI shows review actions
|
|
1213
|
-
await this.transitionToPhase(workflowId, 'awaiting-review');
|
|
1214
|
-
workflow.status = 'awaiting-review';
|
|
1215
|
-
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1216
|
-
await this.saveWorkflow(workflow);
|
|
1217
|
-
this.emit('workflowReadyForReview', workflow);
|
|
1218
1171
|
}
|
|
1219
1172
|
}
|
|
1220
1173
|
catch (error) {
|
|
@@ -1238,57 +1191,102 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1238
1191
|
if (!workflow)
|
|
1239
1192
|
return;
|
|
1240
1193
|
await this.transitionToPhase(workflowId, 'merging');
|
|
1194
|
+
let executionId;
|
|
1241
1195
|
try {
|
|
1242
1196
|
log.info('AI merging changes', { taskId: workflow.taskId }, 'vibing-orchestrator');
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1197
|
+
const mergeList = workflow.executionIds?.['merging'] || [];
|
|
1198
|
+
const attempt = mergeList.length + 1;
|
|
1199
|
+
executionId = generateId('merge');
|
|
1200
|
+
const startTime = new Date().toISOString();
|
|
1245
1201
|
workflow.executionIds = workflow.executionIds || {};
|
|
1246
|
-
const mergeList = workflow.executionIds['merging'] || [];
|
|
1247
1202
|
workflow.executionIds['merging'] = [...mergeList, executionId];
|
|
1248
|
-
// Timeline: record merge attempt start
|
|
1249
1203
|
workflow.timeline = this.buildTimeline(workflow, {
|
|
1250
1204
|
id: executionId,
|
|
1251
|
-
label:
|
|
1205
|
+
label: attempt > 1 ? `Merge – Retry #${attempt}` : 'Merge',
|
|
1252
1206
|
phase: 'merging',
|
|
1253
|
-
attempt
|
|
1207
|
+
attempt,
|
|
1254
1208
|
executionId,
|
|
1255
|
-
startTime
|
|
1209
|
+
startTime,
|
|
1256
1210
|
});
|
|
1211
|
+
workflow.lastUpdatedAt = startTime;
|
|
1257
1212
|
await this.saveWorkflow(workflow);
|
|
1258
|
-
|
|
1213
|
+
this.emit('workflowUpdated', workflow);
|
|
1259
1214
|
this.emit('workflowExecutionStarted', {
|
|
1260
1215
|
workflowId,
|
|
1261
1216
|
executionId,
|
|
1262
1217
|
phase: 'merging',
|
|
1263
1218
|
workflow,
|
|
1264
1219
|
});
|
|
1265
|
-
|
|
1266
|
-
|
|
1220
|
+
await this.agentService.aiMerge(workflow.taskId, {
|
|
1221
|
+
baseBranch: 'main',
|
|
1222
|
+
executionId,
|
|
1223
|
+
workflowId,
|
|
1224
|
+
overrides: providerOverride || workflow.metadata?.aiRoutingOverrides?.ai_merge,
|
|
1225
|
+
});
|
|
1267
1226
|
const mergeExec = this.agentService.getExecutionStatus(executionId);
|
|
1268
1227
|
if (!mergeExec || mergeExec.status !== 'completed') {
|
|
1269
1228
|
throw new Error(`AI merge failed: ${mergeExec?.error || 'Unknown error'}`);
|
|
1270
1229
|
}
|
|
1271
|
-
|
|
1272
|
-
const
|
|
1230
|
+
const latest = this.workflows.get(workflowId) || workflow;
|
|
1231
|
+
const timeline = (latest.timeline || []);
|
|
1232
|
+
const tMerge = timeline.find((t) => t.executionId === executionId);
|
|
1273
1233
|
if (tMerge) {
|
|
1274
1234
|
tMerge.endTime = mergeExec.endTime || new Date().toISOString();
|
|
1275
1235
|
tMerge.usage = mergeExec.usage;
|
|
1276
|
-
|
|
1277
|
-
|
|
1236
|
+
latest.timeline = this.computeVisibleTimeline(latest);
|
|
1237
|
+
latest.lastUpdatedAt = new Date().toISOString();
|
|
1238
|
+
await this.saveWorkflow(latest);
|
|
1278
1239
|
}
|
|
1279
|
-
// Update task status to done (after merge)
|
|
1280
1240
|
await this.taskService.updateTask(workflow.taskId, { status: 'done' });
|
|
1281
|
-
// Move to cleanup phase; final completion is after cleanup
|
|
1282
1241
|
await this.transitionToPhase(workflowId, 'merged');
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1242
|
+
const mergedWorkflow = this.workflows.get(workflowId);
|
|
1243
|
+
if (mergedWorkflow) {
|
|
1244
|
+
mergedWorkflow.status = 'merged';
|
|
1245
|
+
mergedWorkflow.lastUpdatedAt = new Date().toISOString();
|
|
1246
|
+
await this.saveWorkflow(mergedWorkflow);
|
|
1247
|
+
}
|
|
1248
|
+
if (workflow.metadata.stepByStepMode) {
|
|
1249
|
+
log.info('Manual step mode – merge completed; waiting for Continue', { workflowId }, 'vibing-orchestrator');
|
|
1250
|
+
}
|
|
1251
|
+
else {
|
|
1252
|
+
await this.updateCleanupStatus(workflowId);
|
|
1253
|
+
}
|
|
1286
1254
|
log.info('Merge completed, ready for cleanup', { taskId: workflow.taskId }, 'vibing-orchestrator');
|
|
1287
1255
|
}
|
|
1288
1256
|
catch (error) {
|
|
1257
|
+
const latest = this.workflows.get(workflowId) || workflow;
|
|
1258
|
+
if (executionId && latest) {
|
|
1259
|
+
const timeline = (latest.timeline || []);
|
|
1260
|
+
const pending = timeline.find((t) => t.executionId === executionId);
|
|
1261
|
+
if (pending && !pending.endTime) {
|
|
1262
|
+
pending.endTime = new Date().toISOString();
|
|
1263
|
+
if (!pending.reason) {
|
|
1264
|
+
pending.reason = error instanceof Error ? error.message : String(error);
|
|
1265
|
+
}
|
|
1266
|
+
latest.timeline = this.computeVisibleTimeline(latest);
|
|
1267
|
+
latest.lastUpdatedAt = new Date().toISOString();
|
|
1268
|
+
await this.saveWorkflow(latest);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1289
1271
|
await this.handlePhaseFailure(workflowId, 'merging', error);
|
|
1290
1272
|
}
|
|
1291
1273
|
}
|
|
1274
|
+
async updateCleanupStatus(workflowId) {
|
|
1275
|
+
const workflow = this.workflows.get(workflowId);
|
|
1276
|
+
if (!workflow)
|
|
1277
|
+
return;
|
|
1278
|
+
await this.transitionToPhase(workflowId, 'cleaning');
|
|
1279
|
+
workflow.status = 'cleaning';
|
|
1280
|
+
workflow.lastUpdatedAt = new Date().toISOString();
|
|
1281
|
+
workflow.timeline = this.buildTimeline(workflow, {
|
|
1282
|
+
id: `cleaning:${new Date().toISOString()}`,
|
|
1283
|
+
label: 'Cleaning',
|
|
1284
|
+
phase: 'cleaning',
|
|
1285
|
+
startTime: new Date().toISOString(),
|
|
1286
|
+
});
|
|
1287
|
+
await this.saveWorkflow(workflow);
|
|
1288
|
+
this.emit('workflowUpdated', workflow);
|
|
1289
|
+
}
|
|
1292
1290
|
/**
|
|
1293
1291
|
* Public: run merge phase on demand
|
|
1294
1292
|
* This will attempt merge regardless of current phase.
|
|
@@ -1297,10 +1295,7 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1297
1295
|
const workflow = this.workflows.get(workflowId);
|
|
1298
1296
|
if (!workflow)
|
|
1299
1297
|
throw new Error(`Workflow ${workflowId} not found`);
|
|
1300
|
-
await this.
|
|
1301
|
-
// If not already approved/reviewing, proceed anyway to merge attempt
|
|
1302
|
-
await this.executeMerge(workflowId, options);
|
|
1303
|
-
await this.transitionToPhase(workflowId, 'merged');
|
|
1298
|
+
await this.executeMerge(workflowId, { provider: options?.provider, model: options?.model });
|
|
1304
1299
|
}
|
|
1305
1300
|
/**
|
|
1306
1301
|
* Execute cleanup phase: remove worktree/branch and finalize workflow
|
|
@@ -1434,11 +1429,18 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1434
1429
|
*/
|
|
1435
1430
|
async waitForExecution(executionId, timeoutMs = 30 * 60 * 1000) {
|
|
1436
1431
|
const startTime = Date.now();
|
|
1432
|
+
let missingStatusWarned = false;
|
|
1437
1433
|
while (Date.now() - startTime < timeoutMs) {
|
|
1438
1434
|
const execution = this.agentService.getExecutionStatus(executionId);
|
|
1439
1435
|
if (!execution) {
|
|
1440
|
-
|
|
1436
|
+
if (!missingStatusWarned) {
|
|
1437
|
+
log.debug('Execution status not yet available; waiting for agent to register', { executionId }, 'vibing-orchestrator');
|
|
1438
|
+
missingStatusWarned = true;
|
|
1439
|
+
}
|
|
1440
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1441
|
+
continue;
|
|
1441
1442
|
}
|
|
1443
|
+
missingStatusWarned = false;
|
|
1442
1444
|
if (['completed', 'failed', 'cancelled'].includes(execution.status)) {
|
|
1443
1445
|
return;
|
|
1444
1446
|
}
|
|
@@ -1623,7 +1625,6 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1623
1625
|
await this.rerunImplementation(workflowId);
|
|
1624
1626
|
}
|
|
1625
1627
|
else {
|
|
1626
|
-
await this.transitionToPhase(workflowId, 'implementing');
|
|
1627
1628
|
await this.executeImplementation(workflowId);
|
|
1628
1629
|
}
|
|
1629
1630
|
return;
|
|
@@ -1636,23 +1637,21 @@ export class VibingOrchestrator extends EventEmitter {
|
|
|
1636
1637
|
}
|
|
1637
1638
|
switch (next) {
|
|
1638
1639
|
case 'implementing':
|
|
1639
|
-
await this.transitionToPhase(workflowId, 'implementing');
|
|
1640
1640
|
await this.executeImplementation(workflowId);
|
|
1641
1641
|
return;
|
|
1642
1642
|
case 'validating':
|
|
1643
|
-
await this.transitionToPhase(workflowId, 'validating');
|
|
1644
1643
|
await this.executeValidation(workflowId);
|
|
1645
1644
|
return;
|
|
1646
1645
|
case 'ai-reviewing':
|
|
1647
|
-
await this.transitionToPhase(workflowId, 'ai-reviewing');
|
|
1648
1646
|
await this.executeAiReviewPhase(workflowId);
|
|
1649
1647
|
return;
|
|
1648
|
+
case 'awaiting-review':
|
|
1649
|
+
await this.executeAwaitingReview(workflowId);
|
|
1650
|
+
return;
|
|
1650
1651
|
case 'merging':
|
|
1651
|
-
await this.transitionToPhase(workflowId, 'merging');
|
|
1652
1652
|
await this.executeMerge(workflowId);
|
|
1653
1653
|
return;
|
|
1654
1654
|
case 'cleaning':
|
|
1655
|
-
await this.transitionToPhase(workflowId, 'cleaning');
|
|
1656
1655
|
await this.executeCleanup(workflowId);
|
|
1657
1656
|
return;
|
|
1658
1657
|
default:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
mRpNgPfbYR_0wrODzlg_4
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"static/chunks/cac567b0-5b77dd12911823cd.js",
|
|
33
33
|
"static/chunks/575-e2478287c27da87b.js",
|
|
34
34
|
"static/chunks/765-e838910065b50c3d.js",
|
|
35
|
-
"static/chunks/app/layout-
|
|
35
|
+
"static/chunks/app/layout-8435322f09fd0975.js"
|
|
36
36
|
],
|
|
37
37
|
"/api/upload/route": [
|
|
38
38
|
"static/chunks/webpack-c8de37305b4635cf.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"static/chunks/8bb4d8db-3e2aa02b0a2384b9.js",
|
|
54
54
|
"static/chunks/575-e2478287c27da87b.js",
|
|
55
55
|
"static/chunks/277-0142a939f08738c3.js",
|
|
56
|
-
"static/chunks/app/page-
|
|
56
|
+
"static/chunks/app/page-8c3ba579efc6f918.js"
|
|
57
57
|
]
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"ampDevFiles": [],
|
|
7
7
|
"lowPriorityFiles": [
|
|
8
|
-
"static/
|
|
9
|
-
"static/
|
|
8
|
+
"static/mRpNgPfbYR_0wrODzlg_4/_buildManifest.js",
|
|
9
|
+
"static/mRpNgPfbYR_0wrODzlg_4/_ssgManifest.js"
|
|
10
10
|
],
|
|
11
11
|
"rootMainFiles": [
|
|
12
12
|
"static/chunks/webpack-c8de37305b4635cf.js",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"dynamicRoutes": {},
|
|
55
55
|
"notFoundRoutes": [],
|
|
56
56
|
"preview": {
|
|
57
|
-
"previewModeId": "
|
|
58
|
-
"previewModeSigningKey": "
|
|
59
|
-
"previewModeEncryptionKey": "
|
|
57
|
+
"previewModeId": "03a9b538fba39124f8691ffda05da8fa",
|
|
58
|
+
"previewModeSigningKey": "7af5b8d11e26e2288ce29c591de1c6dfb0afa5d616b2b87cdff307f8c516c426",
|
|
59
|
+
"previewModeEncryptionKey": "a19958cfa9716d3f3eab68594cebb7e760a891f19851604a0378b92c3f1985d9"
|
|
60
60
|
}
|
|
61
61
|
}
|