@bradtaylorsf/alpha-loop 1.15.0 → 1.15.1
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/README.md +42 -18
- package/dist/cli.js +9 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.js +102 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/roadmap.js +29 -21
- package/dist/commands/roadmap.js.map +1 -1
- package/dist/commands/run.d.ts +4 -0
- package/dist/commands/run.js +240 -54
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/triage.js +168 -23
- package/dist/commands/triage.js.map +1 -1
- package/dist/lib/cli-args.d.ts +9 -0
- package/dist/lib/cli-args.js +14 -0
- package/dist/lib/cli-args.js.map +1 -0
- package/dist/lib/epics.d.ts +15 -0
- package/dist/lib/epics.js +55 -0
- package/dist/lib/epics.js.map +1 -1
- package/dist/lib/github.d.ts +40 -3
- package/dist/lib/github.js +112 -13
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/pipeline.d.ts +6 -2
- package/dist/lib/pipeline.js +38 -42
- package/dist/lib/pipeline.js.map +1 -1
- package/dist/lib/planning.d.ts +40 -1
- package/dist/lib/planning.js +220 -11
- package/dist/lib/planning.js.map +1 -1
- package/dist/lib/prompts.d.ts +32 -1
- package/dist/lib/prompts.js +127 -18
- package/dist/lib/prompts.js.map +1 -1
- package/dist/lib/verify.d.ts +3 -0
- package/dist/lib/verify.js +4 -1
- package/dist/lib/verify.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roadmap.js","sourceRoot":"","sources":["../../src/commands/roadmap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,
|
|
1
|
+
{"version":3,"file":"roadmap.js","sourceRoot":"","sources":["../../src/commands/roadmap.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Milestone, type Issue } from '../lib/github.js';
|
|
1
2
|
export type RunOptions = {
|
|
2
3
|
dryRun?: boolean;
|
|
3
4
|
model?: string;
|
|
@@ -23,12 +24,15 @@ export type PickTargetResult = {
|
|
|
23
24
|
type: 'epic';
|
|
24
25
|
epicNum: number;
|
|
25
26
|
epicTitle: string;
|
|
27
|
+
epic: Issue;
|
|
26
28
|
} | {
|
|
27
29
|
type: 'milestone';
|
|
28
30
|
title: string;
|
|
29
31
|
} | {
|
|
30
32
|
type: 'all';
|
|
31
33
|
};
|
|
34
|
+
export declare function formatEpicPickerMeta(epic: Issue): string;
|
|
35
|
+
export declare function formatMilestonePickerMeta(milestone: Milestone, epics: Issue[]): string;
|
|
32
36
|
/**
|
|
33
37
|
* Run the main loop: poll for issues, process them, finalize session.
|
|
34
38
|
*/
|
package/dist/commands/run.js
CHANGED
|
@@ -7,7 +7,7 @@ import { log } from '../lib/logger.js';
|
|
|
7
7
|
import { exec } from '../lib/shell.js';
|
|
8
8
|
import { loadConfig, assertSafeShellArg } from '../lib/config.js';
|
|
9
9
|
import { pollIssues, listMilestones, listEpics, getEpicSubIssues, getIssueWithComments, getMergedPRForIssue, updateEpicChecklist, commentIssue, closeIssue, labelIssue, } from '../lib/github.js';
|
|
10
|
-
import { buildEpicSummary } from '../lib/epics.js';
|
|
10
|
+
import { buildEpicSummary, parseSubIssues } from '../lib/epics.js';
|
|
11
11
|
import { verifyEpic } from '../lib/verify-epic.js';
|
|
12
12
|
import { processIssue, processBatch } from '../lib/pipeline.js';
|
|
13
13
|
import { createSession, finalizeSession } from '../lib/session.js';
|
|
@@ -118,6 +118,28 @@ function askChoice(prompt, max) {
|
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
+
function hasEpicLabel(issue) {
|
|
122
|
+
return issue.labels.some((label) => label.toLowerCase() === 'epic');
|
|
123
|
+
}
|
|
124
|
+
export function formatEpicPickerMeta(epic) {
|
|
125
|
+
const summary = buildEpicSummary(epic);
|
|
126
|
+
const progress = summary.totalCount > 0
|
|
127
|
+
? `${summary.doneCount}/${summary.totalCount} done`
|
|
128
|
+
: 'no sub-issues';
|
|
129
|
+
const milestone = epic.milestone ? ` · milestone ${epic.milestone}` : '';
|
|
130
|
+
return `${progress}${milestone}`;
|
|
131
|
+
}
|
|
132
|
+
export function formatMilestonePickerMeta(milestone, epics) {
|
|
133
|
+
const progress = milestone.openIssues + milestone.closedIssues > 0
|
|
134
|
+
? `${milestone.closedIssues}/${milestone.openIssues + milestone.closedIssues} done`
|
|
135
|
+
: 'empty';
|
|
136
|
+
const due = milestone.dueOn ? ` · due ${milestone.dueOn.split('T')[0]}` : '';
|
|
137
|
+
const scheduledEpicCount = epics.filter((epic) => epic.milestone === milestone.title).length;
|
|
138
|
+
const scheduled = scheduledEpicCount > 0
|
|
139
|
+
? ` · ${scheduledEpicCount} scheduled epic${scheduledEpicCount === 1 ? '' : 's'}`
|
|
140
|
+
: '';
|
|
141
|
+
return `${milestone.openIssues} open, ${progress}${due}${scheduled}`;
|
|
142
|
+
}
|
|
121
143
|
/**
|
|
122
144
|
* Show open epics + milestones and let the user pick one, or choose "all in order".
|
|
123
145
|
* Epics are listed first (they're typically what the user actually wants).
|
|
@@ -140,7 +162,7 @@ async function pickTarget(repo, opts) {
|
|
|
140
162
|
if (opts.preferEpics && epics.length === 1) {
|
|
141
163
|
const only = epics[0];
|
|
142
164
|
log.info(`preferEpics: auto-selecting sole open epic #${only.number}`);
|
|
143
|
-
return { type: 'epic', epicNum: only.number, epicTitle: only.title };
|
|
165
|
+
return { type: 'epic', epicNum: only.number, epicTitle: only.title, epic: only };
|
|
144
166
|
}
|
|
145
167
|
const BOLD = '\x1b[1m';
|
|
146
168
|
const DIM = '\x1b[2m';
|
|
@@ -151,11 +173,7 @@ async function pickTarget(repo, opts) {
|
|
|
151
173
|
console.error('');
|
|
152
174
|
for (let i = 0; i < epics.length; i++) {
|
|
153
175
|
const e = epics[i];
|
|
154
|
-
|
|
155
|
-
const progress = summary.totalCount > 0
|
|
156
|
-
? `${summary.doneCount}/${summary.totalCount} done`
|
|
157
|
-
: 'no sub-issues';
|
|
158
|
-
console.error(` ${BOLD}${i + 1}${NC} ${e.title} #${e.number} ${DIM}(${progress})${NC}`);
|
|
176
|
+
console.error(` ${BOLD}${i + 1}${NC} ${e.title} #${e.number} ${DIM}(${formatEpicPickerMeta(e)})${NC}`);
|
|
159
177
|
}
|
|
160
178
|
console.error('');
|
|
161
179
|
}
|
|
@@ -164,11 +182,7 @@ async function pickTarget(repo, opts) {
|
|
|
164
182
|
console.error('');
|
|
165
183
|
for (let i = 0; i < milestones.length; i++) {
|
|
166
184
|
const m = milestones[i];
|
|
167
|
-
|
|
168
|
-
? `${m.closedIssues}/${m.openIssues + m.closedIssues} done`
|
|
169
|
-
: 'empty';
|
|
170
|
-
const due = m.dueOn ? ` · due ${m.dueOn.split('T')[0]}` : '';
|
|
171
|
-
console.error(` ${BOLD}${epics.length + i + 1}${NC} ${m.title} ${DIM}(${m.openIssues} open, ${progress}${due})${NC}`);
|
|
185
|
+
console.error(` ${BOLD}${epics.length + i + 1}${NC} ${m.title} ${DIM}(${formatMilestonePickerMeta(m, epics)})${NC}`);
|
|
172
186
|
}
|
|
173
187
|
console.error('');
|
|
174
188
|
}
|
|
@@ -183,13 +197,83 @@ async function pickTarget(repo, opts) {
|
|
|
183
197
|
if (choice <= epics.length) {
|
|
184
198
|
const selected = epics[choice - 1];
|
|
185
199
|
log.success(`Epic selected: ${selected.title} (#${selected.number})`);
|
|
186
|
-
return { type: 'epic', epicNum: selected.number, epicTitle: selected.title };
|
|
200
|
+
return { type: 'epic', epicNum: selected.number, epicTitle: selected.title, epic: selected };
|
|
187
201
|
}
|
|
188
202
|
const milestoneIdx = choice - epics.length - 1;
|
|
189
203
|
const selected = milestones[milestoneIdx];
|
|
190
204
|
log.success(`Milestone selected: ${selected.title} (${selected.openIssues} open issues)`);
|
|
191
205
|
return { type: 'milestone', title: selected.title };
|
|
192
206
|
}
|
|
207
|
+
async function resolveRunTarget(config, options) {
|
|
208
|
+
let activeMilestone = config.milestone;
|
|
209
|
+
// --epic <N> overrides everything except --verify-only
|
|
210
|
+
if (options.epic !== undefined) {
|
|
211
|
+
if (typeof options.epic !== 'number' || !Number.isFinite(options.epic) || options.epic <= 0) {
|
|
212
|
+
log.error('--epic requires a positive integer issue number (e.g. --epic 165)');
|
|
213
|
+
process.exit(1);
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const epic = getIssueWithComments(config.repo, options.epic);
|
|
217
|
+
if (!epic) {
|
|
218
|
+
log.error(`Could not fetch epic #${options.epic}`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
if (!hasEpicLabel(epic)) {
|
|
223
|
+
log.error(`Issue #${options.epic} is not labeled 'epic'. Add the epic label before running --epic.`);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
activeEpic: epic.number,
|
|
229
|
+
activeEpicTitle: epic.title,
|
|
230
|
+
activeEpicIssue: epic,
|
|
231
|
+
activeMilestone: '',
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (activeMilestone && options.skipEpic !== true) {
|
|
235
|
+
const scheduledEpics = listEpics(config.repo, { milestone: activeMilestone });
|
|
236
|
+
if (scheduledEpics.length === 1) {
|
|
237
|
+
const epic = scheduledEpics[0];
|
|
238
|
+
log.info(`Milestone '${activeMilestone}' has one scheduled epic; processing epic #${epic.number}: ${epic.title}`);
|
|
239
|
+
return {
|
|
240
|
+
activeEpic: epic.number,
|
|
241
|
+
activeEpicTitle: epic.title,
|
|
242
|
+
activeEpicIssue: epic,
|
|
243
|
+
activeMilestone: '',
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (scheduledEpics.length > 1) {
|
|
247
|
+
log.error(`Milestone '${activeMilestone}' has multiple scheduled epics:`);
|
|
248
|
+
for (const epic of scheduledEpics) {
|
|
249
|
+
log.error(` #${epic.number} ${epic.title}`);
|
|
250
|
+
}
|
|
251
|
+
log.error(`Use --epic <N> to choose one, or --skip-epic --milestone ${JSON.stringify(activeMilestone)} to process flat issues.`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
log.info(`No open epics scheduled for milestone '${activeMilestone}' — using flat milestone issue flow`);
|
|
256
|
+
}
|
|
257
|
+
// Interactive picker when TTY and nothing preset
|
|
258
|
+
if (!activeMilestone && !config.dryRun && process.stdin.isTTY) {
|
|
259
|
+
const target = await pickTarget(config.repo, {
|
|
260
|
+
preferEpics: config.preferEpics,
|
|
261
|
+
hideEpics: options.skipEpic === true,
|
|
262
|
+
});
|
|
263
|
+
if (target.type === 'epic') {
|
|
264
|
+
return {
|
|
265
|
+
activeEpic: target.epicNum,
|
|
266
|
+
activeEpicTitle: target.epicTitle,
|
|
267
|
+
activeEpicIssue: target.epic,
|
|
268
|
+
activeMilestone: '',
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (target.type === 'milestone') {
|
|
272
|
+
activeMilestone = target.title;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return { activeMilestone };
|
|
276
|
+
}
|
|
193
277
|
/**
|
|
194
278
|
* Run the verification pass on an epic: fetch sub-issues + merged PRs, evaluate
|
|
195
279
|
* AC via the review model, post a summary comment, and close the epic on pass
|
|
@@ -203,6 +287,11 @@ async function runEpicVerificationFlow(epicNum, config, session) {
|
|
|
203
287
|
log.error(`Could not fetch epic #${epicNum}`);
|
|
204
288
|
return;
|
|
205
289
|
}
|
|
290
|
+
if (!hasEpicLabel(epic)) {
|
|
291
|
+
log.error(`Issue #${epicNum} is not labeled 'epic'. Add the epic label before running epic verification.`);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
206
295
|
const refs = getEpicSubIssues(config.repo, epicNum);
|
|
207
296
|
if (refs.length === 0) {
|
|
208
297
|
log.warn(`Epic #${epicNum} has no sub-issues in its checklist — nothing to verify`);
|
|
@@ -239,6 +328,108 @@ async function runEpicVerificationFlow(epicNum, config, session) {
|
|
|
239
328
|
log.warn(`Epic #${epicNum} needs human review: verdict=${result.verdict}`);
|
|
240
329
|
}
|
|
241
330
|
}
|
|
331
|
+
const MAX_EPIC_BODY_SUMMARY_CHARS = 1200;
|
|
332
|
+
function extractChecklistTitle(line, issueNum) {
|
|
333
|
+
const marker = `#${issueNum}`;
|
|
334
|
+
const idx = line.indexOf(marker);
|
|
335
|
+
if (idx === -1)
|
|
336
|
+
return undefined;
|
|
337
|
+
const suffix = line.slice(idx + marker.length).trim().replace(/^[-:]\s*/, '').trim();
|
|
338
|
+
return suffix || undefined;
|
|
339
|
+
}
|
|
340
|
+
function parseEpicChecklistForPrompt(body) {
|
|
341
|
+
const lines = body.split('\n');
|
|
342
|
+
return parseSubIssues(body).map((ref) => ({
|
|
343
|
+
issueNum: ref.number,
|
|
344
|
+
checked: ref.checked,
|
|
345
|
+
title: extractChecklistTitle(lines[ref.lineIndex] ?? '', ref.number),
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
function findMarkdownSection(body, headingPattern) {
|
|
349
|
+
const lines = body.split('\n');
|
|
350
|
+
const section = [];
|
|
351
|
+
let inSection = false;
|
|
352
|
+
for (const line of lines) {
|
|
353
|
+
const heading = /^#{1,6}\s+(.+?)\s*$/.exec(line.trim());
|
|
354
|
+
if (heading) {
|
|
355
|
+
if (inSection)
|
|
356
|
+
break;
|
|
357
|
+
inSection = headingPattern.test(heading[1]);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (inSection)
|
|
361
|
+
section.push(line);
|
|
362
|
+
}
|
|
363
|
+
return section;
|
|
364
|
+
}
|
|
365
|
+
function removeMarkdownSection(body, headingPattern) {
|
|
366
|
+
const lines = body.split('\n');
|
|
367
|
+
const kept = [];
|
|
368
|
+
let skip = false;
|
|
369
|
+
for (const line of lines) {
|
|
370
|
+
const heading = /^#{1,6}\s+(.+?)\s*$/.exec(line.trim());
|
|
371
|
+
if (heading) {
|
|
372
|
+
if (skip && !headingPattern.test(heading[1])) {
|
|
373
|
+
skip = false;
|
|
374
|
+
}
|
|
375
|
+
else if (headingPattern.test(heading[1])) {
|
|
376
|
+
skip = true;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (!skip)
|
|
381
|
+
kept.push(line);
|
|
382
|
+
}
|
|
383
|
+
return kept.join('\n');
|
|
384
|
+
}
|
|
385
|
+
function extractEpicAcceptanceCriteria(body) {
|
|
386
|
+
const section = findMarkdownSection(body, /acceptance criteria/i);
|
|
387
|
+
if (section.length === 0)
|
|
388
|
+
return [];
|
|
389
|
+
const listItems = section
|
|
390
|
+
.map((line) => line.trim())
|
|
391
|
+
.filter((line) => /^[-*]\s+/.test(line));
|
|
392
|
+
if (listItems.length > 0)
|
|
393
|
+
return listItems;
|
|
394
|
+
return section
|
|
395
|
+
.map((line) => line.trim())
|
|
396
|
+
.filter(Boolean);
|
|
397
|
+
}
|
|
398
|
+
function summarizeEpicBody(body) {
|
|
399
|
+
const checklistLines = new Set(parseSubIssues(body).map((ref) => ref.lineIndex));
|
|
400
|
+
const withoutChecklist = body
|
|
401
|
+
.split('\n')
|
|
402
|
+
.filter((_, index) => !checklistLines.has(index))
|
|
403
|
+
.join('\n');
|
|
404
|
+
const withoutAcceptance = removeMarkdownSection(withoutChecklist, /acceptance criteria/i);
|
|
405
|
+
const compact = withoutAcceptance
|
|
406
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
407
|
+
.trim();
|
|
408
|
+
if (compact.length <= MAX_EPIC_BODY_SUMMARY_CHARS)
|
|
409
|
+
return compact;
|
|
410
|
+
return `${compact.slice(0, MAX_EPIC_BODY_SUMMARY_CHARS).trimEnd()}\n...(truncated)`;
|
|
411
|
+
}
|
|
412
|
+
function buildEpicPromptContextFromIssue(epic, checklist) {
|
|
413
|
+
return {
|
|
414
|
+
number: epic.number,
|
|
415
|
+
title: epic.title,
|
|
416
|
+
bodySummary: summarizeEpicBody(epic.body),
|
|
417
|
+
acceptanceCriteria: extractEpicAcceptanceCriteria(epic.body),
|
|
418
|
+
subIssues: checklist.map((item) => ({
|
|
419
|
+
issueNum: item.issueNum,
|
|
420
|
+
title: item.title,
|
|
421
|
+
checked: item.checked,
|
|
422
|
+
})),
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function markEpicChecklistItem(checklist, context, issueNum, checked) {
|
|
426
|
+
const item = checklist.find((entry) => entry.issueNum === issueNum);
|
|
427
|
+
if (item)
|
|
428
|
+
item.checked = checked;
|
|
429
|
+
const contextItem = context?.subIssues.find((entry) => entry.issueNum === issueNum);
|
|
430
|
+
if (contextItem)
|
|
431
|
+
contextItem.checked = checked;
|
|
432
|
+
}
|
|
242
433
|
/**
|
|
243
434
|
* Run the main loop: poll for issues, process them, finalize session.
|
|
244
435
|
*/
|
|
@@ -283,38 +474,13 @@ export async function runCommand(options) {
|
|
|
283
474
|
return;
|
|
284
475
|
}
|
|
285
476
|
// --- Target selection (epic or milestone) — must happen before session creation ---
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
process.exit(1);
|
|
294
|
-
}
|
|
295
|
-
const epic = getIssueWithComments(config.repo, options.epic);
|
|
296
|
-
if (!epic) {
|
|
297
|
-
log.error(`Could not fetch epic #${options.epic}`);
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
activeEpic = epic.number;
|
|
301
|
-
activeEpicTitle = epic.title;
|
|
302
|
-
activeMilestone = '';
|
|
303
|
-
}
|
|
304
|
-
// Interactive picker when TTY and nothing preset
|
|
305
|
-
if (activeEpic === undefined && !activeMilestone && !config.dryRun && process.stdin.isTTY) {
|
|
306
|
-
const target = await pickTarget(config.repo, {
|
|
307
|
-
preferEpics: config.preferEpics,
|
|
308
|
-
hideEpics: options.skipEpic === true,
|
|
309
|
-
});
|
|
310
|
-
if (target.type === 'epic') {
|
|
311
|
-
activeEpic = target.epicNum;
|
|
312
|
-
activeEpicTitle = target.epicTitle;
|
|
313
|
-
}
|
|
314
|
-
else if (target.type === 'milestone') {
|
|
315
|
-
activeMilestone = target.title;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
477
|
+
const target = await resolveRunTarget(config, options);
|
|
478
|
+
if (!target)
|
|
479
|
+
return;
|
|
480
|
+
let activeEpic = target.activeEpic;
|
|
481
|
+
let activeEpicTitle = target.activeEpicTitle;
|
|
482
|
+
let activeEpicIssue = target.activeEpicIssue;
|
|
483
|
+
const activeMilestone = target.activeMilestone;
|
|
318
484
|
if (activeEpic !== undefined) {
|
|
319
485
|
log.info(`Processing epic #${activeEpic}${activeEpicTitle ? ': ' + activeEpicTitle : ''}`);
|
|
320
486
|
}
|
|
@@ -427,19 +593,31 @@ export async function runCommand(options) {
|
|
|
427
593
|
// Otherwise, fetch via the usual project/label/milestone path and exclude
|
|
428
594
|
// epic-labeled issues (AC #2: epics never picked up by the normal `ready` flow).
|
|
429
595
|
let issues;
|
|
596
|
+
let epicChecklist = [];
|
|
597
|
+
let epicPromptContext;
|
|
430
598
|
if (activeEpic !== undefined) {
|
|
431
599
|
log.info(`Fetching sub-issues of epic #${activeEpic} in checklist order...`);
|
|
432
|
-
|
|
600
|
+
if (!activeEpicIssue) {
|
|
601
|
+
const epic = getIssueWithComments(config.repo, activeEpic);
|
|
602
|
+
if (!epic) {
|
|
603
|
+
log.error(`Could not fetch epic #${activeEpic}`);
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
activeEpicIssue = epic;
|
|
607
|
+
activeEpicTitle = epic.title;
|
|
608
|
+
}
|
|
609
|
+
epicChecklist = parseEpicChecklistForPrompt(activeEpicIssue.body);
|
|
433
610
|
issues = [];
|
|
434
|
-
for (const ref of
|
|
611
|
+
for (const ref of epicChecklist) {
|
|
435
612
|
if (ref.checked)
|
|
436
613
|
continue; // already done
|
|
437
|
-
const sub = getIssueWithComments(config.repo, ref.
|
|
614
|
+
const sub = getIssueWithComments(config.repo, ref.issueNum);
|
|
438
615
|
if (!sub) {
|
|
439
|
-
log.warn(`Sub-issue #${ref.
|
|
616
|
+
log.warn(`Sub-issue #${ref.issueNum} skipped: could not fetch`);
|
|
440
617
|
continue;
|
|
441
618
|
}
|
|
442
|
-
|
|
619
|
+
ref.title = ref.title ?? sub.title;
|
|
620
|
+
if (hasEpicLabel(sub)) {
|
|
443
621
|
log.warn(`Sub-issue #${sub.number} skipped: is itself an epic (nested epics unsupported in v1)`);
|
|
444
622
|
continue;
|
|
445
623
|
}
|
|
@@ -449,6 +627,7 @@ export async function runCommand(options) {
|
|
|
449
627
|
}
|
|
450
628
|
issues.push(sub);
|
|
451
629
|
}
|
|
630
|
+
epicPromptContext = buildEpicPromptContextFromIssue(activeEpicIssue, epicChecklist);
|
|
452
631
|
}
|
|
453
632
|
else {
|
|
454
633
|
const milestoneMsg = activeMilestone ? ` in milestone '${activeMilestone}'` : '';
|
|
@@ -457,7 +636,7 @@ export async function runCommand(options) {
|
|
|
457
636
|
project: config.project,
|
|
458
637
|
repoOwner: config.repoOwner,
|
|
459
638
|
milestone: activeMilestone || undefined,
|
|
460
|
-
}).filter((iss) => !iss
|
|
639
|
+
}).filter((iss) => !hasEpicLabel(iss));
|
|
461
640
|
}
|
|
462
641
|
// When set mid-loop, skip post-loop epic verification (e.g. checklist body inconsistency).
|
|
463
642
|
let epicAbort = false;
|
|
@@ -525,7 +704,9 @@ export async function runCommand(options) {
|
|
|
525
704
|
log.info('==========================================');
|
|
526
705
|
activeIssueNum = batchIssues[0].number;
|
|
527
706
|
try {
|
|
528
|
-
const results =
|
|
707
|
+
const results = epicPromptContext
|
|
708
|
+
? await processBatch(batchIssues, config, session, { epicContext: epicPromptContext })
|
|
709
|
+
: await processBatch(batchIssues, config, session);
|
|
529
710
|
session.results.push(...results);
|
|
530
711
|
// Flip epic checklist for each successful sub-issue.
|
|
531
712
|
// Skipped in dry-run: `processIssue` returns status='success' when tests are
|
|
@@ -537,6 +718,7 @@ export async function runCommand(options) {
|
|
|
537
718
|
continue;
|
|
538
719
|
try {
|
|
539
720
|
updateEpicChecklist(config.repo, activeEpic, r.issueNum, true);
|
|
721
|
+
markEpicChecklistItem(epicChecklist, epicPromptContext, r.issueNum, true);
|
|
540
722
|
}
|
|
541
723
|
catch (err) {
|
|
542
724
|
log.error(`Epic #${activeEpic} checklist update failed for sub-issue #${r.issueNum}: ${err instanceof Error ? err.message : err}`);
|
|
@@ -586,7 +768,9 @@ export async function runCommand(options) {
|
|
|
586
768
|
log.info('==========================================');
|
|
587
769
|
activeIssueNum = issue.number;
|
|
588
770
|
try {
|
|
589
|
-
const result =
|
|
771
|
+
const result = epicPromptContext
|
|
772
|
+
? await processIssue(issue.number, issue.title, issue.body, config, session, { epicContext: epicPromptContext })
|
|
773
|
+
: await processIssue(issue.number, issue.title, issue.body, config, session);
|
|
590
774
|
session.results.push(result);
|
|
591
775
|
// Flip the epic checklist box when this sub-issue succeeded.
|
|
592
776
|
// Skipped in dry-run: `processIssue` stubs tests in dry-run and returns success,
|
|
@@ -594,6 +778,7 @@ export async function runCommand(options) {
|
|
|
594
778
|
if (activeEpic !== undefined && result.status === 'success' && !config.dryRun) {
|
|
595
779
|
try {
|
|
596
780
|
updateEpicChecklist(config.repo, activeEpic, issue.number, true);
|
|
781
|
+
markEpicChecklistItem(epicChecklist, epicPromptContext, issue.number, true);
|
|
597
782
|
}
|
|
598
783
|
catch (err) {
|
|
599
784
|
log.error(`Epic #${activeEpic} checklist update failed for sub-issue #${issue.number}: ${err instanceof Error ? err.message : err}`);
|
|
@@ -622,7 +807,7 @@ export async function runCommand(options) {
|
|
|
622
807
|
// --- Epic completion check: verify and close if all sub-issues are now done ---
|
|
623
808
|
if (activeEpic !== undefined && !epicAbort && !config.dryRun) {
|
|
624
809
|
try {
|
|
625
|
-
const remaining =
|
|
810
|
+
const remaining = epicChecklist.filter((r) => !r.checked);
|
|
626
811
|
if (remaining.length === 0) {
|
|
627
812
|
log.step(`All sub-issues of epic #${activeEpic} are complete — running verification pass`);
|
|
628
813
|
await runEpicVerificationFlow(activeEpic, config, session);
|
|
@@ -695,6 +880,7 @@ export async function runCommand(options) {
|
|
|
695
880
|
testsPassing: r.testsPassing,
|
|
696
881
|
})),
|
|
697
882
|
includeSecurityScan: !config.skipPostSessionSecurity,
|
|
883
|
+
epicContext: epicPromptContext,
|
|
698
884
|
visionContext,
|
|
699
885
|
});
|
|
700
886
|
// Trace review prompt
|