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.
Files changed (127) hide show
  1. package/.claude/settings.local.json +23 -3
  2. package/.env.local +12 -0
  3. package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
  4. package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
  5. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
  6. package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
  7. package/dist/commands/workflow/executors/phase-executor.js +1 -3
  8. package/dist/commands/workflow/phase-orchestrator.js +1 -3
  9. package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
  10. package/dist/commands/workflow/pipeline-runner.js +393 -0
  11. package/dist/commands/workflow/runner.d.ts +26 -0
  12. package/dist/commands/workflow/runner.js +119 -0
  13. package/dist/commands/workflow/workflow-runner.d.ts +26 -0
  14. package/dist/commands/workflow/workflow-runner.js +119 -0
  15. package/dist/index.js +2 -2
  16. package/dist/phases/app-store-generation/index.js +1 -3
  17. package/dist/phases/branch-planning/index.js +1 -3
  18. package/dist/phases/bug-fixing/analyzer.js +1 -3
  19. package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
  20. package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
  21. package/dist/phases/code-implementation/analyzer.d.ts +32 -0
  22. package/dist/phases/code-implementation/analyzer.js +629 -0
  23. package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
  24. package/dist/phases/code-implementation/context-fetcher.js +86 -0
  25. package/dist/phases/code-implementation/index.js +1 -3
  26. package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
  27. package/dist/phases/code-implementation/mcp-server.js +93 -0
  28. package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
  29. package/dist/phases/code-implementation/prompts-improvement.js +108 -0
  30. package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
  31. package/dist/phases/code-implementation-verification/verifier.js +196 -0
  32. package/dist/phases/code-refine/analyzer.d.ts +41 -0
  33. package/dist/phases/code-refine/analyzer.js +561 -0
  34. package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
  35. package/dist/phases/code-refine/context-fetcher.js +423 -0
  36. package/dist/phases/code-refine/index.js +1 -3
  37. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
  38. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
  39. package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
  40. package/dist/phases/code-refine-verification/verifier.js +597 -0
  41. package/dist/phases/code-review/analyzer.d.ts +29 -0
  42. package/dist/phases/code-review/analyzer.js +363 -0
  43. package/dist/phases/code-review/context-fetcher.d.ts +92 -0
  44. package/dist/phases/code-review/context-fetcher.js +296 -0
  45. package/dist/phases/code-review/index.js +1 -3
  46. package/dist/phases/code-testing/analyzer.js +1 -3
  47. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
  48. package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
  49. package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
  50. package/dist/phases/feature-analysis/analyzer.js +208 -0
  51. package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
  52. package/dist/phases/feature-analysis/context-fetcher.js +134 -0
  53. package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
  54. package/dist/phases/feature-analysis/http-fallback.js +95 -0
  55. package/dist/phases/feature-analysis/index.js +1 -3
  56. package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
  57. package/dist/phases/feature-analysis/mcp-server.js +144 -0
  58. package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
  59. package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
  60. package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
  61. package/dist/phases/feature-analysis-verification/verifier.js +147 -0
  62. package/dist/phases/functional-testing/analyzer.js +1 -3
  63. package/dist/phases/growth-analysis/index.js +1 -3
  64. package/dist/phases/pr-execution/file-assigner.js +20 -12
  65. package/dist/phases/pr-execution/index.js +59 -1
  66. package/dist/phases/pr-resolve/prompts.js +2 -1
  67. package/dist/phases/pr-resolve/workspace.d.ts +1 -1
  68. package/dist/phases/pr-resolve/workspace.js +1 -1
  69. package/dist/phases/pr-review/__tests__/review-comments.test.js +4 -2
  70. package/dist/phases/pr-review/index.js +1 -3
  71. package/dist/phases/pr-shared/agent-utils.js +0 -1
  72. package/dist/phases/pr-shared/context.d.ts +1 -1
  73. package/dist/phases/pr-splitting/index.js +1 -3
  74. package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
  75. package/dist/phases/technical-design/analyzer-helpers.js +39 -0
  76. package/dist/phases/technical-design/analyzer.d.ts +21 -0
  77. package/dist/phases/technical-design/analyzer.js +461 -0
  78. package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
  79. package/dist/phases/technical-design/context-fetcher.js +39 -0
  80. package/dist/phases/technical-design/http-fallback.d.ts +17 -0
  81. package/dist/phases/technical-design/http-fallback.js +151 -0
  82. package/dist/phases/technical-design/index.js +1 -3
  83. package/dist/phases/technical-design/mcp-server.d.ts +1 -0
  84. package/dist/phases/technical-design/mcp-server.js +157 -0
  85. package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
  86. package/dist/phases/technical-design/prompts-improvement.js +93 -0
  87. package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
  88. package/dist/phases/technical-design-verification/verifier.js +170 -0
  89. package/dist/phases/test-cases-analysis/index.js +1 -3
  90. package/dist/phases/user-stories-analysis/index.js +1 -3
  91. package/dist/services/feature-branches.d.ts +77 -0
  92. package/dist/services/feature-branches.js +205 -0
  93. package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
  94. package/dist/workflow-runner/config/phase-configs.js +120 -0
  95. package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
  96. package/dist/workflow-runner/core/feature-filter.js +46 -0
  97. package/dist/workflow-runner/core/index.d.ts +8 -0
  98. package/dist/workflow-runner/core/index.js +12 -0
  99. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
  100. package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
  101. package/dist/workflow-runner/core/state-manager.d.ts +24 -0
  102. package/dist/workflow-runner/core/state-manager.js +42 -0
  103. package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
  104. package/dist/workflow-runner/core/workflow-logger.js +65 -0
  105. package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
  106. package/dist/workflow-runner/executors/phase-executor.js +248 -0
  107. package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
  108. package/dist/workflow-runner/feature-workflow-runner.js +119 -0
  109. package/dist/workflow-runner/index.d.ts +2 -0
  110. package/dist/workflow-runner/index.js +2 -0
  111. package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
  112. package/dist/workflow-runner/pipeline-runner.js +393 -0
  113. package/dist/workflow-runner/workflow-processor.d.ts +54 -0
  114. package/dist/workflow-runner/workflow-processor.js +170 -0
  115. package/package.json +1 -1
  116. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
  117. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
  118. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
  119. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
  120. package/dist/services/lifecycle-agent/index.d.ts +0 -24
  121. package/dist/services/lifecycle-agent/index.js +0 -25
  122. package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
  123. package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
  124. package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
  125. package/dist/services/lifecycle-agent/transition-rules.js +0 -184
  126. package/dist/services/lifecycle-agent/types.d.ts +0 -190
  127. 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
- for await (const message of query({
90
- prompt: userMessage(),
91
- options: {
92
- model: DEFAULT_MODEL,
93
- maxTurns: 1,
94
- permissionMode: 'bypassPermissions',
95
- },
96
- })) {
97
- if (message.type === 'assistant' && message.message?.content) {
98
- for (const item of message.message.content) {
99
- if (item.type === 'text') {
100
- responseText += `${item.text}\n`;
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, verbose?: boolean): boolean;
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, verbose) {
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>;