edsger 0.41.1 → 0.41.3
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/.claude/settings.local.json +23 -3
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/commands/workflow/executors/phase-executor.js +1 -3
- package/dist/commands/workflow/phase-orchestrator.js +1 -3
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/index.js +2 -2
- package/dist/phases/app-store-generation/index.js +1 -3
- package/dist/phases/branch-planning/index.js +1 -3
- package/dist/phases/bug-fixing/analyzer.js +1 -3
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/index.js +1 -3
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine/index.js +1 -3
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/code-review/index.js +1 -3
- package/dist/phases/code-testing/analyzer.js +1 -3
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/index.js +1 -3
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/functional-testing/analyzer.js +1 -3
- package/dist/phases/growth-analysis/index.js +1 -3
- package/dist/phases/pr-execution/file-assigner.js +20 -12
- package/dist/phases/pr-execution/index.js +59 -1
- package/dist/phases/pr-resolve/prompts.js +2 -1
- package/dist/phases/pr-resolve/workspace.d.ts +1 -1
- package/dist/phases/pr-resolve/workspace.js +1 -1
- package/dist/phases/pr-review/__tests__/review-comments.test.js +4 -2
- package/dist/phases/pr-review/index.js +1 -3
- package/dist/phases/pr-shared/agent-utils.js +0 -1
- package/dist/phases/pr-shared/context.d.ts +1 -1
- package/dist/phases/pr-splitting/index.js +1 -3
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/index.js +1 -3
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/phases/test-cases-analysis/index.js +1 -3
- package/dist/phases/user-stories-analysis/index.js +1 -3
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +1 -1
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checklist verification agent for feature analysis
|
|
3
|
+
* This agent independently reviews checklist compliance to ensure objectivity
|
|
4
|
+
*/
|
|
5
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
6
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
7
|
+
import { createChecklistVerificationPrompt, createChecklistVerificationSystemPrompt, } from './prompts.js';
|
|
8
|
+
function userMessage(content) {
|
|
9
|
+
return {
|
|
10
|
+
type: 'user',
|
|
11
|
+
message: { role: 'user', content: content },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function* prompt(verificationPrompt) {
|
|
15
|
+
yield userMessage(verificationPrompt);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Verify checklist compliance using an independent AI agent
|
|
19
|
+
* This agent acts as a "challenger" to validate the claims made by the analysis agent
|
|
20
|
+
*/
|
|
21
|
+
export async function verifyChecklistCompliance(options, config) {
|
|
22
|
+
const { checklistContext, analysisContext, createdUserStories, createdTestCases, verbose, } = options;
|
|
23
|
+
const totalChecklistItems = checklistContext.checklists.reduce((sum, checklist) => sum + checklist.items.length, 0);
|
|
24
|
+
if (verbose) {
|
|
25
|
+
logInfo('🔍 Starting checklist verification...');
|
|
26
|
+
logInfo(` Verifying ${totalChecklistItems} checklist items`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const systemPrompt = createChecklistVerificationSystemPrompt(config);
|
|
30
|
+
const verificationPrompt = createChecklistVerificationPrompt({
|
|
31
|
+
checklistContext,
|
|
32
|
+
analysisContext,
|
|
33
|
+
createdUserStories,
|
|
34
|
+
createdTestCases,
|
|
35
|
+
});
|
|
36
|
+
let lastAssistantResponse = '';
|
|
37
|
+
let verificationResult = null;
|
|
38
|
+
if (verbose) {
|
|
39
|
+
logInfo('🤖 Starting verification agent query...');
|
|
40
|
+
}
|
|
41
|
+
// Use Claude Code SDK for verification
|
|
42
|
+
for await (const message of query({
|
|
43
|
+
prompt: prompt(verificationPrompt),
|
|
44
|
+
options: {
|
|
45
|
+
appendSystemPrompt: systemPrompt,
|
|
46
|
+
model: config.claude.model || 'sonnet',
|
|
47
|
+
maxTurns: 100,
|
|
48
|
+
permissionMode: 'bypassPermissions',
|
|
49
|
+
},
|
|
50
|
+
})) {
|
|
51
|
+
if (verbose) {
|
|
52
|
+
logInfo(` Received message type: ${message.type}`);
|
|
53
|
+
}
|
|
54
|
+
// Capture assistant responses
|
|
55
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
56
|
+
for (const content of message.message.content) {
|
|
57
|
+
if (content.type === 'text') {
|
|
58
|
+
lastAssistantResponse += content.text + '\n';
|
|
59
|
+
if (verbose) {
|
|
60
|
+
console.log(`\n🔍 ${content.text}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (message.type === 'result') {
|
|
66
|
+
if (message.subtype === 'success') {
|
|
67
|
+
logInfo('\n✅ Verification completed, parsing results...');
|
|
68
|
+
try {
|
|
69
|
+
const responseText = message.result || lastAssistantResponse;
|
|
70
|
+
// Try to extract JSON from markdown code block
|
|
71
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
72
|
+
let jsonResult = null;
|
|
73
|
+
if (jsonBlockMatch) {
|
|
74
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
jsonResult = JSON.parse(responseText);
|
|
78
|
+
}
|
|
79
|
+
if (jsonResult && jsonResult.verification) {
|
|
80
|
+
verificationResult = jsonResult.verification;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw new Error('Invalid verification JSON structure');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logError(`Failed to parse verification result: ${error}`);
|
|
88
|
+
// Return default "uncertain" result
|
|
89
|
+
verificationResult = createUncertainVerificationResult(checklistContext, 'Failed to parse verification response');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
logError(`\n⚠️ Verification incomplete: ${message.subtype}`);
|
|
94
|
+
verificationResult = createUncertainVerificationResult(checklistContext, `Verification incomplete: ${message.subtype}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!verificationResult) {
|
|
99
|
+
verificationResult = createUncertainVerificationResult(checklistContext, 'No verification result received');
|
|
100
|
+
}
|
|
101
|
+
if (verbose) {
|
|
102
|
+
logInfo('\n📊 Verification Summary:');
|
|
103
|
+
logInfo(` Total items: ${verificationResult.total_items}`);
|
|
104
|
+
logInfo(` ✅ Confirmed: ${verificationResult.confirmed_count}`);
|
|
105
|
+
logInfo(` ❌ Rejected: ${verificationResult.rejected_count}`);
|
|
106
|
+
logInfo(` ⚠️ Uncertain: ${verificationResult.uncertain_count}`);
|
|
107
|
+
logInfo(` Summary: ${verificationResult.summary}`);
|
|
108
|
+
if (verificationResult.rejected_count > 0) {
|
|
109
|
+
logInfo('\n❌ Rejected items:');
|
|
110
|
+
verificationResult.item_verifications
|
|
111
|
+
.filter((v) => v.verification_status === 'rejected')
|
|
112
|
+
.forEach((v) => {
|
|
113
|
+
logInfo(` - ${v.checklist_item_id}`);
|
|
114
|
+
logInfo(` Reason: ${v.verification_reason}`);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return verificationResult;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
logError(`Checklist verification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
122
|
+
return createUncertainVerificationResult(checklistContext, `Verification error: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create a default "uncertain" verification result when verification fails
|
|
127
|
+
*/
|
|
128
|
+
function createUncertainVerificationResult(checklistContext, reason) {
|
|
129
|
+
// Get all checklist items
|
|
130
|
+
const allItems = checklistContext.checklists.flatMap((checklist) => checklist.items.map((item) => ({
|
|
131
|
+
checklist_item_id: item.id,
|
|
132
|
+
})));
|
|
133
|
+
return {
|
|
134
|
+
all_verified: false,
|
|
135
|
+
total_items: allItems.length,
|
|
136
|
+
confirmed_count: 0,
|
|
137
|
+
rejected_count: 0,
|
|
138
|
+
uncertain_count: allItems.length,
|
|
139
|
+
item_verifications: allItems.map((item) => ({
|
|
140
|
+
checklist_item_id: item.checklist_item_id,
|
|
141
|
+
is_satisfied: false,
|
|
142
|
+
verification_status: 'uncertain',
|
|
143
|
+
verification_reason: reason,
|
|
144
|
+
})),
|
|
145
|
+
summary: `Verification could not be completed: ${reason}`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -326,9 +326,7 @@ async function saveTestResults(featureId, testStatus, structuredTestResult, last
|
|
|
326
326
|
}
|
|
327
327
|
return testReportResult;
|
|
328
328
|
}
|
|
329
|
-
export const runFunctionalTesting = async (options, config, checklistContext
|
|
330
|
-
// eslint-disable-next-line complexity -- orchestration function coordinating functional test execution and result processing
|
|
331
|
-
) => {
|
|
329
|
+
export const runFunctionalTesting = async (options, config, checklistContext) => {
|
|
332
330
|
const { featureId, verbose } = options;
|
|
333
331
|
if (verbose) {
|
|
334
332
|
logInfo(`Starting functional testing for feature ID: ${featureId}`);
|
|
@@ -49,9 +49,7 @@ contentSuggestions) {
|
|
|
49
49
|
}
|
|
50
50
|
return plans;
|
|
51
51
|
}
|
|
52
|
-
export const analyseGrowth = async (options, config
|
|
53
|
-
// eslint-disable-next-line complexity -- orchestration function with context assembly, agent execution, and result processing
|
|
54
|
-
) => {
|
|
52
|
+
export const analyseGrowth = async (options, config) => {
|
|
55
53
|
const { productId, verbose, guidance, analysisId } = options;
|
|
56
54
|
if (verbose) {
|
|
57
55
|
logInfo(`Starting growth analysis for product ID: ${productId}`);
|
|
@@ -86,22 +86,30 @@ async function callLLMForAssignment(prompt, verbose) {
|
|
|
86
86
|
message: { role: 'user', content: prompt },
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
89
|
+
try {
|
|
90
|
+
for await (const message of query({
|
|
91
|
+
prompt: userMessage(),
|
|
92
|
+
options: {
|
|
93
|
+
model: DEFAULT_MODEL,
|
|
94
|
+
maxTurns: 5,
|
|
95
|
+
permissionMode: 'bypassPermissions',
|
|
96
|
+
},
|
|
97
|
+
})) {
|
|
98
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
99
|
+
for (const item of message.message.content) {
|
|
100
|
+
if (item.type === 'text') {
|
|
101
|
+
responseText += `${item.text}\n`;
|
|
102
|
+
}
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
106
|
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (verbose) {
|
|
109
|
+
logError(`LLM query failed during file assignment: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
105
113
|
const parsed = extractJsonFromResponse(responseText, '"assignments"');
|
|
106
114
|
if (!parsed || !Array.isArray(parsed.assignments)) {
|
|
107
115
|
if (verbose) {
|
|
@@ -2,7 +2,7 @@ import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
3
|
import { DEFAULT_MODEL } from '../../constants.js';
|
|
4
4
|
import { logFeaturePhaseEvent } from '../../services/audit-logs.js';
|
|
5
|
-
import { getPullRequests } from '../../services/pull-requests.js';
|
|
5
|
+
import { getPullRequests, } from '../../services/pull-requests.js';
|
|
6
6
|
import { getCurrentBranch, returnToMainBranch, } from '../../utils/git-branch-manager.js';
|
|
7
7
|
import { logDebug, logError, logInfo } from '../../utils/logger.js';
|
|
8
8
|
import { fetchPRExecutionContext } from './context.js';
|
|
@@ -98,6 +98,18 @@ export const executeFeaturePRs = async (options, config) => {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
// ======================================
|
|
101
|
+
// Filter to only the next eligible PR
|
|
102
|
+
// ======================================
|
|
103
|
+
// Only process the first pending PR whose predecessor is merged/closed.
|
|
104
|
+
// Already-executed PRs (branch_created, pr_opened, etc.) are included for sync.
|
|
105
|
+
activePullRequests = filterToEligiblePRs(activePullRequests, verbose);
|
|
106
|
+
if (activePullRequests.length === 0) {
|
|
107
|
+
if (verbose) {
|
|
108
|
+
logInfo('No eligible PRs to process — waiting for current PR to be merged or closed.');
|
|
109
|
+
}
|
|
110
|
+
return buildNoChangeResult(featureId, context.pullRequests.length);
|
|
111
|
+
}
|
|
112
|
+
// ======================================
|
|
101
113
|
// Agent: Create/Update branches
|
|
102
114
|
// ======================================
|
|
103
115
|
if (verbose) {
|
|
@@ -285,6 +297,52 @@ export const executeFeaturePRs = async (options, config) => {
|
|
|
285
297
|
return buildExecutionErrorResult(featureId, errorMessage);
|
|
286
298
|
}
|
|
287
299
|
};
|
|
300
|
+
/**
|
|
301
|
+
* Filter PRs to only include the next eligible pending PR.
|
|
302
|
+
*
|
|
303
|
+
* - Already-executed PRs (branch_created, pr_opened, in_review, approved) are
|
|
304
|
+
* kept for incremental sync.
|
|
305
|
+
* - Merged/closed PRs are excluded (no branch work needed).
|
|
306
|
+
* - Only the first pending PR is included, and only if the PR immediately
|
|
307
|
+
* before it (by sequence) is merged or closed (or it's the first PR).
|
|
308
|
+
* - All other pending PRs are blocked until the current one completes.
|
|
309
|
+
*/
|
|
310
|
+
function filterToEligiblePRs(pullRequests, verbose) {
|
|
311
|
+
const sorted = [...pullRequests].sort((a, b) => a.sequence - b.sequence);
|
|
312
|
+
const eligible = [];
|
|
313
|
+
let foundPendingToProcess = false;
|
|
314
|
+
let blockedCount = 0;
|
|
315
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
316
|
+
const pr = sorted[i];
|
|
317
|
+
if (pr.status === 'merged' || pr.status === 'closed') {
|
|
318
|
+
// Done — no branch work needed
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (pr.status !== 'pending') {
|
|
322
|
+
// Already executed but not done — include for incremental sync
|
|
323
|
+
eligible.push(pr);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
// PR is pending
|
|
327
|
+
if (foundPendingToProcess) {
|
|
328
|
+
blockedCount++;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
// Check if the previous PR (by sequence) is merged or closed
|
|
332
|
+
const prevPR = i > 0 ? sorted[i - 1] : null;
|
|
333
|
+
if (!prevPR || prevPR.status === 'merged' || prevPR.status === 'closed') {
|
|
334
|
+
eligible.push(pr);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
blockedCount++;
|
|
338
|
+
}
|
|
339
|
+
foundPendingToProcess = true;
|
|
340
|
+
}
|
|
341
|
+
if (blockedCount > 0 && verbose) {
|
|
342
|
+
logInfo(`⏳ ${blockedCount} pending PR(s) waiting for previous PR to be merged or closed`);
|
|
343
|
+
}
|
|
344
|
+
return eligible;
|
|
345
|
+
}
|
|
288
346
|
/**
|
|
289
347
|
* Execute an agent query for branch creation/update
|
|
290
348
|
*/
|
|
@@ -73,8 +73,9 @@ export function createResolveUserPrompt(unresolvedThreads) {
|
|
|
73
73
|
let commentIndex = 0;
|
|
74
74
|
for (const thread of unresolvedThreads) {
|
|
75
75
|
const firstComment = thread.comments.nodes[0];
|
|
76
|
-
if (!firstComment)
|
|
76
|
+
if (!firstComment) {
|
|
77
77
|
continue;
|
|
78
|
+
}
|
|
78
79
|
commentIndex++;
|
|
79
80
|
const commentId = `comment_${commentIndex}`;
|
|
80
81
|
commentIdToThreadId.set(commentId, thread.id);
|
|
@@ -18,7 +18,7 @@ export declare function prepareWorkspace(owner: string, repo: string, headRef: s
|
|
|
18
18
|
/**
|
|
19
19
|
* Push changes from workspace back to remote.
|
|
20
20
|
*/
|
|
21
|
-
export declare function pushChanges(repoPath: string, headRef: string, token: string,
|
|
21
|
+
export declare function pushChanges(repoPath: string, headRef: string, token: string, _verbose?: boolean): boolean;
|
|
22
22
|
/**
|
|
23
23
|
* Check if there are uncommitted changes in the workspace.
|
|
24
24
|
*/
|
|
@@ -98,7 +98,7 @@ export function prepareWorkspace(owner, repo, headRef, prNumber, token, verbose)
|
|
|
98
98
|
/**
|
|
99
99
|
* Push changes from workspace back to remote.
|
|
100
100
|
*/
|
|
101
|
-
export function pushChanges(repoPath, headRef, token,
|
|
101
|
+
export function pushChanges(repoPath, headRef, token, _verbose) {
|
|
102
102
|
const gitCredentialArgs = buildCredentialArgs(token);
|
|
103
103
|
try {
|
|
104
104
|
execFileSync('git', [...gitCredentialArgs, 'push', 'origin', headRef], {
|
|
@@ -17,11 +17,13 @@ function mapCommentsToReviewPayload(agentComments, files) {
|
|
|
17
17
|
const result = [];
|
|
18
18
|
for (const comment of agentComments) {
|
|
19
19
|
const lineToPosition = fileLineToPosition.get(comment.file);
|
|
20
|
-
if (!lineToPosition)
|
|
20
|
+
if (!lineToPosition) {
|
|
21
21
|
continue;
|
|
22
|
+
}
|
|
22
23
|
const positionResult = findClosestPosition(comment.line, lineToPosition);
|
|
23
|
-
if (!positionResult)
|
|
24
|
+
if (!positionResult) {
|
|
24
25
|
continue;
|
|
26
|
+
}
|
|
25
27
|
let body = comment.comment;
|
|
26
28
|
if (positionResult.actualLine !== comment.line) {
|
|
27
29
|
body = `**Note**: Comment originally for line ${comment.line}, adjusted to line ${positionResult.actualLine} (nearest line in diff).\n\n${body}`;
|
|
@@ -14,9 +14,7 @@ import { createStandaloneReviewSystemPrompt, createStandaloneReviewUserPrompt, }
|
|
|
14
14
|
/**
|
|
15
15
|
* Review a standalone PR and post comments to GitHub.
|
|
16
16
|
*/
|
|
17
|
-
export async function reviewStandalonePR(options
|
|
18
|
-
// eslint-disable-next-line complexity
|
|
19
|
-
) {
|
|
17
|
+
export async function reviewStandalonePR(options) {
|
|
20
18
|
const { pullRequestUrl, githubToken, verbose, prId } = options;
|
|
21
19
|
logInfo(`Starting standalone PR review: ${pullRequestUrl}`);
|
|
22
20
|
try {
|
|
@@ -24,7 +24,6 @@ export async function* createPromptGenerator(prompt) {
|
|
|
24
24
|
/**
|
|
25
25
|
* Extract text content from assistant message content array.
|
|
26
26
|
*/
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
27
|
export function extractTextFromContent(
|
|
29
28
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
29
|
content, verbose) {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Reuses GitHub API utilities from code-review/context.ts without feature dependencies.
|
|
4
4
|
*/
|
|
5
5
|
import { type PRCommit, type PRData, type PRFile } from '../code-review/context.js';
|
|
6
|
-
export { parsePullRequestUrl } from '../code-review/context.js';
|
|
7
6
|
export type { PRCommit, PRData, PRFile } from '../code-review/context.js';
|
|
7
|
+
export { parsePullRequestUrl } from '../code-review/context.js';
|
|
8
8
|
export interface StandalonePRContext {
|
|
9
9
|
pullRequestUrl: string;
|
|
10
10
|
pullRequestNumber: number;
|
|
@@ -27,9 +27,7 @@ async function* prompt(analysisPrompt) {
|
|
|
27
27
|
* then uses AI to produce a PR split plan saved to the database.
|
|
28
28
|
* Human review is expected before running the pr-execution phase.
|
|
29
29
|
*/
|
|
30
|
-
export const splitFeatureIntoPRs = async (options, config
|
|
31
|
-
// eslint-disable-next-line complexity -- orchestration function with context fetching, agent execution, and result processing
|
|
32
|
-
) => {
|
|
30
|
+
export const splitFeatureIntoPRs = async (options, config) => {
|
|
33
31
|
const { featureId, verbose, replaceExisting } = options;
|
|
34
32
|
if (verbose) {
|
|
35
33
|
logInfo(`Starting PR splitting for feature ID: ${featureId}`);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ChecklistVerificationResult } from '../technical-design-verification/agent.js';
|
|
2
|
+
export interface TechnicalDesignResult {
|
|
3
|
+
featureId: string;
|
|
4
|
+
technicalDesign: string | null;
|
|
5
|
+
status: 'success' | 'error';
|
|
6
|
+
summary: string;
|
|
7
|
+
verificationResult?: ChecklistVerificationResult;
|
|
8
|
+
iterations?: number;
|
|
9
|
+
data?: {
|
|
10
|
+
checklist_item_results?: any[];
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build successful design result
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildDesignResult(featureId: string, technicalDesign: string, summary: string, iterations: number, checklistItemResults?: any[]): TechnicalDesignResult;
|
|
18
|
+
/**
|
|
19
|
+
* Build verification failure result
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildVerificationFailureResult(featureId: string, technicalDesign: string, verificationResult: ChecklistVerificationResult, iterations: number): TechnicalDesignResult;
|
|
22
|
+
/**
|
|
23
|
+
* Build error result when no design was generated
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildNoResultsError(featureId: string): TechnicalDesignResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build successful design result
|
|
3
|
+
*/
|
|
4
|
+
export function buildDesignResult(featureId, technicalDesign, summary, iterations, checklistItemResults) {
|
|
5
|
+
return {
|
|
6
|
+
featureId,
|
|
7
|
+
technicalDesign,
|
|
8
|
+
status: 'success',
|
|
9
|
+
summary,
|
|
10
|
+
iterations,
|
|
11
|
+
data: checklistItemResults
|
|
12
|
+
? { checklist_item_results: checklistItemResults }
|
|
13
|
+
: undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build verification failure result
|
|
18
|
+
*/
|
|
19
|
+
export function buildVerificationFailureResult(featureId, technicalDesign, verificationResult, iterations) {
|
|
20
|
+
return {
|
|
21
|
+
featureId,
|
|
22
|
+
technicalDesign,
|
|
23
|
+
status: 'error',
|
|
24
|
+
summary: `Checklist verification failed after ${iterations} iterations: ${verificationResult.summary}`,
|
|
25
|
+
verificationResult,
|
|
26
|
+
iterations,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build error result when no design was generated
|
|
31
|
+
*/
|
|
32
|
+
export function buildNoResultsError(featureId) {
|
|
33
|
+
return {
|
|
34
|
+
featureId,
|
|
35
|
+
technicalDesign: null,
|
|
36
|
+
status: 'error',
|
|
37
|
+
summary: 'Failed to generate technical design - no valid result received',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
import { ChecklistPhaseContext } from '../../services/checklist.js';
|
|
3
|
+
export interface TechnicalDesignOptions {
|
|
4
|
+
featureId: string;
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
maxVerificationIterations?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TechnicalDesignResult {
|
|
9
|
+
featureId: string;
|
|
10
|
+
technicalDesign: string | null;
|
|
11
|
+
status: 'success' | 'error';
|
|
12
|
+
summary: string;
|
|
13
|
+
verificationResult?: any;
|
|
14
|
+
iterations?: number;
|
|
15
|
+
savedViaHttp?: boolean;
|
|
16
|
+
data?: {
|
|
17
|
+
checklist_item_results?: any[];
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const generateTechnicalDesign: (options: TechnicalDesignOptions, config: EdsgerConfig, checklistContext?: ChecklistPhaseContext | null) => Promise<TechnicalDesignResult>;
|