edsger 0.45.1 → 0.46.0
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/commands/workflow/executors/phase-executor.js +3 -1
- package/dist/commands/workflow/phase-orchestrator.js +1 -2
- package/dist/phases/app-store-generation/index.js +1 -2
- package/dist/phases/branch-planning/index.js +1 -2
- package/dist/phases/bug-fixing/analyzer.js +1 -2
- package/dist/phases/code-implementation/index.js +1 -2
- package/dist/phases/code-refine/index.js +1 -2
- package/dist/phases/code-review/index.js +1 -2
- package/dist/phases/code-testing/analyzer.js +1 -2
- package/dist/phases/feature-analysis/index.js +1 -2
- package/dist/phases/functional-testing/analyzer.js +1 -2
- package/dist/phases/growth-analysis/index.js +1 -2
- package/dist/phases/pr-execution/index.js +1 -0
- package/dist/phases/pr-splitting/index.js +1 -2
- package/dist/phases/run-sheet/index.js +7 -7
- package/dist/phases/run-sheet/render.js +3 -1
- package/dist/phases/smoke-test/agent.js +2 -4
- package/dist/phases/smoke-test/index.js +11 -6
- package/dist/phases/technical-design/index.js +1 -2
- package/dist/phases/test-cases-analysis/index.js +1 -2
- package/dist/phases/user-stories-analysis/index.js +1 -2
- package/package.json +1 -1
|
@@ -130,7 +130,9 @@ async function validateAndLogChecklists(options, name, checklistContext, feature
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
// Higher-order function for phase execution
|
|
133
|
-
export const createPhaseRunner = (phaseConfig) =>
|
|
133
|
+
export const createPhaseRunner = (phaseConfig) =>
|
|
134
|
+
// eslint-disable-next-line complexity
|
|
135
|
+
async (options, config) => {
|
|
134
136
|
const { featureId, verbose } = options;
|
|
135
137
|
const { name, execute } = phaseConfig;
|
|
136
138
|
// Track phase duration for logging
|
|
@@ -36,9 +36,8 @@ const logAndMarkPhaseCompleted = async (result, verbose) => {
|
|
|
36
36
|
* Orchestrate phase execution based on execution mode
|
|
37
37
|
* Routes to appropriate phase sequence based on mode (only_*, from_*, full_pipeline)
|
|
38
38
|
*/
|
|
39
|
-
export const runPipelineByMode = async (options, config, executionMode
|
|
40
39
|
// eslint-disable-next-line complexity
|
|
41
|
-
) => {
|
|
40
|
+
export const runPipelineByMode = async (options, config, executionMode) => {
|
|
42
41
|
const { featureId, verbose } = options;
|
|
43
42
|
if (verbose) {
|
|
44
43
|
logInfo(`🚀 Starting pipeline with mode: ${executionMode} for feature: ${featureId}`);
|
|
@@ -13,9 +13,8 @@ function truncateKeywords(keywords) {
|
|
|
13
13
|
}
|
|
14
14
|
return keywords.slice(0, 100).replace(/,[^,]*$/, '');
|
|
15
15
|
}
|
|
16
|
-
export const generateAppStoreAssets = async (options, config
|
|
17
16
|
// eslint-disable-next-line complexity
|
|
18
|
-
) => {
|
|
17
|
+
export const generateAppStoreAssets = async (options, config) => {
|
|
19
18
|
const { productId, targetStore, screenshotsOnly, listingsOnly, verbose } = options;
|
|
20
19
|
if (verbose) {
|
|
21
20
|
logInfo(`Starting app store generation for product: ${productId}`);
|
|
@@ -116,9 +116,8 @@ async function persistBranches(sortedBranches, featureId, verbose) {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
export const planFeatureBranches = async (options, config
|
|
120
119
|
// eslint-disable-next-line complexity
|
|
121
|
-
) => {
|
|
120
|
+
export const planFeatureBranches = async (options, config) => {
|
|
122
121
|
const { featureId, verbose, replaceExisting } = options;
|
|
123
122
|
if (verbose) {
|
|
124
123
|
logInfo(`Starting branch planning for feature ID: ${featureId}`);
|
|
@@ -32,9 +32,8 @@ async function* prompt(bugFixPrompt) {
|
|
|
32
32
|
setTimeout(res, 10000);
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
export const fixTestFailures = async (options, config
|
|
36
35
|
// eslint-disable-next-line complexity
|
|
37
|
-
) => {
|
|
36
|
+
export const fixTestFailures = async (options, config) => {
|
|
38
37
|
const { featureId, testErrors, attemptNumber = 1, verbose } = options;
|
|
39
38
|
if (verbose) {
|
|
40
39
|
logInfo(`Starting bug fixing for feature ID: ${featureId} (Attempt ${attemptNumber})`);
|
|
@@ -170,9 +170,8 @@ message, lastAssistantResponse, featureId, verbose
|
|
|
170
170
|
}
|
|
171
171
|
return null;
|
|
172
172
|
}
|
|
173
|
-
export const implementFeatureCode = async (options, config, checklistContext
|
|
174
173
|
// eslint-disable-next-line complexity
|
|
175
|
-
) => {
|
|
174
|
+
export const implementFeatureCode = async (options, config, checklistContext) => {
|
|
176
175
|
const { featureId, verbose, baseBranch = 'main' } = options;
|
|
177
176
|
if (verbose) {
|
|
178
177
|
logInfo(`Starting code implementation for feature ID: ${featureId}`);
|
|
@@ -41,9 +41,8 @@ export const MAX_REFINE_ITERATIONS = 10;
|
|
|
41
41
|
* Similar to technical-design, this includes an iterative improvement cycle:
|
|
42
42
|
* refine → verification → improve → re-refine (if needed)
|
|
43
43
|
*/
|
|
44
|
-
export const refineCodeFromPRFeedback = async (options, config, checklistContext
|
|
45
44
|
// eslint-disable-next-line complexity
|
|
46
|
-
) => {
|
|
45
|
+
export const refineCodeFromPRFeedback = async (options, config, checklistContext) => {
|
|
47
46
|
const { featureId, githubToken, verbose } = options;
|
|
48
47
|
if (verbose) {
|
|
49
48
|
logInfo(`Starting code refine for feature ID: ${featureId}`);
|
|
@@ -67,9 +67,8 @@ baseBranchInfo, baseBranchForRebase, originalBaseBranchForRebase, verbose) {
|
|
|
67
67
|
/**
|
|
68
68
|
* Main code review function
|
|
69
69
|
*/
|
|
70
|
-
export const reviewPullRequest = async (options, config, checklistContext
|
|
71
70
|
// eslint-disable-next-line complexity
|
|
72
|
-
) => {
|
|
71
|
+
export const reviewPullRequest = async (options, config, checklistContext) => {
|
|
73
72
|
const { featureId, githubToken, verbose } = options;
|
|
74
73
|
if (verbose) {
|
|
75
74
|
logInfo(`Starting code review for feature ID: ${featureId}`);
|
|
@@ -31,9 +31,8 @@ async function* prompt(testingPrompt) {
|
|
|
31
31
|
setTimeout(res, 10000);
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
export const writeCodeTests = async (options, config
|
|
35
34
|
// eslint-disable-next-line complexity
|
|
36
|
-
) => {
|
|
35
|
+
export const writeCodeTests = async (options, config) => {
|
|
37
36
|
const { featureId, verbose } = options;
|
|
38
37
|
if (verbose) {
|
|
39
38
|
logInfo(`Starting code testing phase for feature ID: ${featureId}`);
|
|
@@ -6,9 +6,8 @@ import { executeAnalysisQuery, parseAnalysisResult } from './agent.js';
|
|
|
6
6
|
import { prepareAnalysisContext } from './context.js';
|
|
7
7
|
import { buildAnalysisResult, deleteArtifacts, deleteSpecificArtifacts, getAllDraftArtifactIds, resetReadyArtifactsToDraft, saveAnalysisArtifactsAsDraft, updateArtifactsToReady, } from './outcome.js';
|
|
8
8
|
import { createFeatureAnalysisSystemPrompt } from './prompts.js';
|
|
9
|
-
export const analyseFeature = async (options, config, checklistContext
|
|
10
9
|
// eslint-disable-next-line complexity
|
|
11
|
-
) => {
|
|
10
|
+
export const analyseFeature = async (options, config, checklistContext) => {
|
|
12
11
|
const { featureId, verbose } = options;
|
|
13
12
|
if (verbose) {
|
|
14
13
|
logInfo(`Starting feature analysis for feature ID: ${featureId}`);
|
|
@@ -326,9 +326,8 @@ async function saveTestResults(featureId, testStatus, structuredTestResult, last
|
|
|
326
326
|
}
|
|
327
327
|
return testReportResult;
|
|
328
328
|
}
|
|
329
|
-
export const runFunctionalTesting = async (options, config, checklistContext
|
|
330
329
|
// eslint-disable-next-line complexity
|
|
331
|
-
) => {
|
|
330
|
+
export const runFunctionalTesting = async (options, config, checklistContext) => {
|
|
332
331
|
const { featureId, verbose } = options;
|
|
333
332
|
if (verbose) {
|
|
334
333
|
logInfo(`Starting functional testing for feature ID: ${featureId}`);
|
|
@@ -49,9 +49,8 @@ contentSuggestions) {
|
|
|
49
49
|
}
|
|
50
50
|
return plans;
|
|
51
51
|
}
|
|
52
|
-
export const analyseGrowth = async (options, config
|
|
53
52
|
// eslint-disable-next-line complexity
|
|
54
|
-
) => {
|
|
53
|
+
export const analyseGrowth = async (options, config) => {
|
|
55
54
|
const { productId, verbose, guidance, analysisId } = options;
|
|
56
55
|
if (verbose) {
|
|
57
56
|
logInfo(`Starting growth analysis for product ID: ${productId}`);
|
|
@@ -33,6 +33,7 @@ async function* prompt(executionPrompt) {
|
|
|
33
33
|
*
|
|
34
34
|
* GitHub PRs are created manually by the user via compare URLs in the UI.
|
|
35
35
|
*/
|
|
36
|
+
// eslint-disable-next-line complexity
|
|
36
37
|
export const executeFeaturePRs = async (options, config) => {
|
|
37
38
|
const { featureId, verbose } = options;
|
|
38
39
|
if (verbose) {
|
|
@@ -27,9 +27,8 @@ 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
30
|
// eslint-disable-next-line complexity
|
|
32
|
-
) => {
|
|
31
|
+
export const splitFeatureIntoPRs = async (options, config) => {
|
|
33
32
|
const { featureId, verbose, replaceExisting } = options;
|
|
34
33
|
if (verbose) {
|
|
35
34
|
logInfo(`Starting PR splitting for feature ID: ${featureId}`);
|
|
@@ -69,7 +69,8 @@ function isLockStale(lockPath) {
|
|
|
69
69
|
const raw = readFileSync(lockPath, 'utf-8').trim();
|
|
70
70
|
let ts;
|
|
71
71
|
try {
|
|
72
|
-
|
|
72
|
+
;
|
|
73
|
+
({ ts } = JSON.parse(raw));
|
|
73
74
|
}
|
|
74
75
|
catch {
|
|
75
76
|
ts = Number(raw);
|
|
@@ -134,6 +135,7 @@ function runSheetIsFresh(existing, template, tag) {
|
|
|
134
135
|
}
|
|
135
136
|
return true;
|
|
136
137
|
}
|
|
138
|
+
// eslint-disable-next-line complexity -- orchestration with cache, clone, lock, render
|
|
137
139
|
export async function runRunSheet(options) {
|
|
138
140
|
const { releaseId, force, verbose } = options;
|
|
139
141
|
let release;
|
|
@@ -170,7 +172,7 @@ export async function runRunSheet(options) {
|
|
|
170
172
|
// Short-circuit cache: identical template + tag, no prior clone error.
|
|
171
173
|
if (!force) {
|
|
172
174
|
const existing = await getRunSheetByRelease(releaseId, verbose).catch(() => null);
|
|
173
|
-
if (runSheetIsFresh(existing, template, release.tag)) {
|
|
175
|
+
if (existing && runSheetIsFresh(existing, template, release.tag)) {
|
|
174
176
|
logInfo(`Run sheet for ${release.tag} is already up-to-date (template unchanged).`);
|
|
175
177
|
return {
|
|
176
178
|
status: 'cached',
|
|
@@ -193,10 +195,8 @@ export async function runRunSheet(options) {
|
|
|
193
195
|
let commits = '';
|
|
194
196
|
let commitsTruncated = false;
|
|
195
197
|
let lockPath = null;
|
|
196
|
-
if (repoConfigured) {
|
|
197
|
-
const owner = gh
|
|
198
|
-
const repo = gh.repo;
|
|
199
|
-
const token = gh.token;
|
|
198
|
+
if (repoConfigured && gh.owner && gh.repo && gh.token) {
|
|
199
|
+
const { owner, repo, token } = gh;
|
|
200
200
|
// Serialise concurrent CLI invocations for the *same release* by
|
|
201
201
|
// taking a file lock next to the clone dir. Different releases get
|
|
202
202
|
// different lock files (per-release workspace).
|
|
@@ -250,7 +250,7 @@ export async function runRunSheet(options) {
|
|
|
250
250
|
previous_tag: release.previous_tag,
|
|
251
251
|
previous_published_at: release.previous_published_at,
|
|
252
252
|
diff_summary: release.diff_summary,
|
|
253
|
-
diff_stats:
|
|
253
|
+
diff_stats: release.diff_stats ?? {},
|
|
254
254
|
}, repoDir, commits);
|
|
255
255
|
try {
|
|
256
256
|
const saved = await upsertRunSheet({
|
|
@@ -38,7 +38,8 @@ export async function safeReadRepoFile(repoDir, relPath, remainingBudget) {
|
|
|
38
38
|
if (!stat.isFile()) {
|
|
39
39
|
return { content: null, bytes: 0, reason: 'not a file' };
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
;
|
|
42
|
+
({ size } = stat);
|
|
42
43
|
}
|
|
43
44
|
catch {
|
|
44
45
|
return { content: null, bytes: 0, reason: 'not found' };
|
|
@@ -72,6 +73,7 @@ export async function safeReadRepoFile(repoDir, relPath, remainingBudget) {
|
|
|
72
73
|
export function normalizeTemplate(template) {
|
|
73
74
|
return template.replace(/\{\{([^}]*)\}\}/g, (_match, inner) => `{{${inner.replace(/\\([_.\-\\/])/g, '$1')}}}`);
|
|
74
75
|
}
|
|
76
|
+
// eslint-disable-next-line complexity -- template expansion branches per placeholder type
|
|
75
77
|
export async function renderTemplate(template, product, release, repoDir, commits) {
|
|
76
78
|
const missing = [];
|
|
77
79
|
const stats = release.diff_stats ?? {};
|
|
@@ -66,11 +66,9 @@ export async function executeSmokeTestQuery(systemPrompt, userPrompt, config, ve
|
|
|
66
66
|
lastAssistant += `${content.text}\n`;
|
|
67
67
|
logDebug(content.text, verbose);
|
|
68
68
|
}
|
|
69
|
-
else if (content.type === 'tool_use') {
|
|
69
|
+
else if (content.type === 'tool_use' && verbose) {
|
|
70
70
|
const desc = content.input?.description || content.input?.command || 'Running...';
|
|
71
|
-
|
|
72
|
-
logInfo(`[Turn ${turnCount}] ${content.name}: ${typeof desc === 'string' ? desc.slice(0, 120) : 'Running...'}`);
|
|
73
|
-
}
|
|
71
|
+
logInfo(`[Turn ${turnCount}] ${content.name}: ${typeof desc === 'string' ? desc.slice(0, 120) : 'Running...'}`);
|
|
74
72
|
}
|
|
75
73
|
}
|
|
76
74
|
}
|
|
@@ -17,7 +17,15 @@ import { buildSmokeTestUserPrompt, createSmokeTestSystemPrompt, } from './prompt
|
|
|
17
17
|
function isSnapshotRelease(release) {
|
|
18
18
|
return !release.published_at && !release.url;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
function describeReleaseContext(release, isSnapshot) {
|
|
21
|
+
if (isSnapshot) {
|
|
22
|
+
return ` (snapshot ahead of ${release.previous_tag ?? 'first release'})`;
|
|
23
|
+
}
|
|
24
|
+
if (release.previous_tag) {
|
|
25
|
+
return ` (vs ${release.previous_tag})`;
|
|
26
|
+
}
|
|
27
|
+
return ' (first release)';
|
|
28
|
+
}
|
|
21
29
|
export async function runSmokeTest(options, config) {
|
|
22
30
|
const { releaseId, verbose } = options;
|
|
23
31
|
if (verbose) {
|
|
@@ -216,11 +224,8 @@ async function runSmokeTestInner(ctx) {
|
|
|
216
224
|
diff_stats: diffStats,
|
|
217
225
|
generation_error: null,
|
|
218
226
|
}, verbose);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
: release.previous_tag
|
|
222
|
-
? ` (vs ${release.previous_tag})`
|
|
223
|
-
: ' (first release)'}`);
|
|
227
|
+
const suffix = describeReleaseContext(release, isSnapshot);
|
|
228
|
+
logSuccess(`Generated ${casesCount} smoke-test cases for ${release.tag}${suffix}`);
|
|
224
229
|
return {
|
|
225
230
|
status: 'success',
|
|
226
231
|
releaseId: release.id,
|
|
@@ -24,9 +24,8 @@ async function* prompt(analysisPrompt) {
|
|
|
24
24
|
setTimeout(res, 10000);
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
export const generateTechnicalDesign = async (options, config, checklistContext
|
|
28
27
|
// eslint-disable-next-line complexity
|
|
29
|
-
) => {
|
|
28
|
+
export const generateTechnicalDesign = async (options, config, checklistContext) => {
|
|
30
29
|
const { featureId, verbose } = options;
|
|
31
30
|
if (verbose) {
|
|
32
31
|
logInfo(`Starting technical design generation for feature ID: ${featureId}`);
|
|
@@ -6,9 +6,8 @@ import { executeTestCasesAnalysisQuery, parseAnalysisResult } from './agent.js';
|
|
|
6
6
|
import { prepareTestCasesAnalysisContext } from './context.js';
|
|
7
7
|
import { buildTestCasesAnalysisResult, deleteSpecificTestCases, deleteTestCaseArtifacts, getAllDraftTestCaseIds, resetReadyTestCasesToDraft, saveTestCasesAsDraft, updateTestCasesToReady, } from './outcome.js';
|
|
8
8
|
import { createTestCasesAnalysisSystemPrompt } from './prompts.js';
|
|
9
|
-
export const analyseTestCases = async (options, config, checklistContext
|
|
10
9
|
// eslint-disable-next-line complexity
|
|
11
|
-
) => {
|
|
10
|
+
export const analyseTestCases = async (options, config, checklistContext) => {
|
|
12
11
|
const { featureId, verbose } = options;
|
|
13
12
|
if (verbose) {
|
|
14
13
|
logInfo(`Starting test cases analysis for feature ID: ${featureId}`);
|
|
@@ -6,9 +6,8 @@ import { executeUserStoriesAnalysisQuery, parseAnalysisResult, } from './agent.j
|
|
|
6
6
|
import { prepareUserStoriesAnalysisContext } from './context.js';
|
|
7
7
|
import { buildUserStoriesAnalysisResult, deleteSpecificUserStories, deleteUserStoryArtifacts, getAllDraftUserStoryIds, resetReadyUserStoriesToDraft, saveUserStoriesAsDraft, updateUserStoriesToReady, } from './outcome.js';
|
|
8
8
|
import { createUserStoriesAnalysisSystemPrompt } from './prompts.js';
|
|
9
|
-
export const analyseUserStories = async (options, config, checklistContext
|
|
10
9
|
// eslint-disable-next-line complexity
|
|
11
|
-
) => {
|
|
10
|
+
export const analyseUserStories = async (options, config, checklistContext) => {
|
|
12
11
|
const { featureId, verbose } = options;
|
|
13
12
|
if (verbose) {
|
|
14
13
|
logInfo(`Starting user stories analysis for feature ID: ${featureId}`);
|