@attalabs/vinaya 0.17.1 → 0.19.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/README.md +37 -1
- package/aeg-root/contracts/architect-planner.md +72 -0
- package/aeg-root/roles/architect.md +91 -0
- package/aeg-root/roles/planner.md +14 -15
- package/aeg-root/tranche-model.md +9 -1
- package/dist/checks/bin/check-body-bare-digits.js +62 -14
- package/dist/checks/bin/check-branch-topology.js +57 -12
- package/dist/checks/bin/check-brief-shape.js +57 -12
- package/dist/checks/bin/check-closes-n.js +57 -12
- package/dist/checks/bin/check-coherence.js +62 -14
- package/dist/checks/bin/check-dead-branch-push.js +57 -12
- package/dist/checks/bin/check-dispatch-readiness.js +129 -41
- package/dist/checks/bin/check-doc-coverage-push.js +62 -14
- package/dist/checks/bin/check-doc-coverage.js +62 -14
- package/dist/checks/bin/check-evidence-fresh.js +57 -12
- package/dist/checks/bin/check-first-push-dispatch.js +130 -42
- package/dist/checks/bin/check-issue-assignment.js +57 -12
- package/dist/checks/bin/check-no-disk-state.js +57 -12
- package/dist/checks/bin/check-reader-resolvable-prose.js +57 -12
- package/dist/checks/bin/check-registry-gates.js +57 -12
- package/dist/checks/bin/check-review-gate.js +62 -14
- package/dist/checks/bin/check-single-plan-pr.js +57 -12
- package/dist/checks/bin/check-test-plan.js +57 -12
- package/dist/index.js +889 -109
- package/package.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1ccgndq._.js → [root-of-the-server]__0ulzsom._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +5 -5
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{40x7f5hm7a5tk.js → 2r36w820aqwb9.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0ojfbn3yvy-8_.js → 2xoclb4g7d9n7.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0l_vubs1ephe5.js → 3ocvtlhgckh81.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{p5sWGp4ANwORiaX4Kk6U2 → RISz5nirLr1mUfMqzSaFS}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{p5sWGp4ANwORiaX4Kk6U2 → RISz5nirLr1mUfMqzSaFS}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{p5sWGp4ANwORiaX4Kk6U2 → RISz5nirLr1mUfMqzSaFS}/_ssgManifest.js +0 -0
|
@@ -274,6 +274,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
274
274
|
"200"
|
|
275
275
|
];
|
|
276
276
|
}
|
|
277
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
278
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
279
|
+
}
|
|
277
280
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
278
281
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
279
282
|
}
|
|
@@ -289,18 +292,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
289
292
|
return dedupeByNumber(perLabel.flat());
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
293
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
294
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
295
|
-
const match = milestones.find((m) => m.title === slug);
|
|
296
|
-
if (!match)
|
|
297
|
-
return null;
|
|
298
|
-
return {
|
|
299
|
-
goal: match.description ?? "",
|
|
300
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
295
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
305
296
|
var LABELS = [
|
|
306
297
|
{
|
|
@@ -543,6 +534,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
543
534
|
return { trancheSlug, taskId };
|
|
544
535
|
}
|
|
545
536
|
|
|
537
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
538
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
539
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
540
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
541
|
+
function intentGoalForSlug(description, slug) {
|
|
542
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
543
|
+
const start = text.match(INTENTS_HEADING);
|
|
544
|
+
if (!start || start.index === undefined)
|
|
545
|
+
return "";
|
|
546
|
+
const rest = text.slice(start.index + start[0].length);
|
|
547
|
+
const next = rest.match(NEXT_HEADING);
|
|
548
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
549
|
+
for (const line of section.split(`
|
|
550
|
+
`)) {
|
|
551
|
+
const trimmed = line.trim();
|
|
552
|
+
if (trimmed.length === 0)
|
|
553
|
+
continue;
|
|
554
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
555
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
556
|
+
return (m[2] ?? "").trim();
|
|
557
|
+
}
|
|
558
|
+
return "";
|
|
559
|
+
}
|
|
560
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
561
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
562
|
+
}
|
|
563
|
+
function factsFromLegacyMilestone(milestone) {
|
|
564
|
+
return {
|
|
565
|
+
goal: milestone.description ?? "",
|
|
566
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function lifecycleFromIssues(issues) {
|
|
570
|
+
if (issues.length === 0)
|
|
571
|
+
return "planned";
|
|
572
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
573
|
+
}
|
|
574
|
+
function goalFromMilestones(milestones, slug) {
|
|
575
|
+
for (const m of milestones) {
|
|
576
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
577
|
+
if (goal)
|
|
578
|
+
return goal;
|
|
579
|
+
}
|
|
580
|
+
return "";
|
|
581
|
+
}
|
|
582
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
583
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
584
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
585
|
+
if (legacy)
|
|
586
|
+
return factsFromLegacyMilestone(legacy);
|
|
587
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
588
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
589
|
+
}
|
|
590
|
+
|
|
546
591
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
547
592
|
function trancheFromIssues(slug, issues, known) {
|
|
548
593
|
return {
|
|
@@ -3196,7 +3241,8 @@ var BRIEF_BUILTINS = [
|
|
|
3196
3241
|
"for",
|
|
3197
3242
|
"closesN",
|
|
3198
3243
|
"premiseCoverage",
|
|
3199
|
-
"issueRationale"
|
|
3244
|
+
"issueRationale",
|
|
3245
|
+
"milestoneShape"
|
|
3200
3246
|
];
|
|
3201
3247
|
var BriefSectionSchema = z.union([
|
|
3202
3248
|
z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
|
|
@@ -3206,7 +3252,9 @@ var BriefSectionSchema = z.union([
|
|
|
3206
3252
|
]);
|
|
3207
3253
|
var BriefSchemaSchema = z.object({
|
|
3208
3254
|
pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3209
|
-
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional()
|
|
3255
|
+
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3256
|
+
milestone: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3257
|
+
ack: z.array(z.enum(BRIEF_BUILTINS)).optional()
|
|
3210
3258
|
});
|
|
3211
3259
|
function isSafeRepoRelPath(p) {
|
|
3212
3260
|
if (p.length === 0)
|
|
@@ -274,6 +274,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
274
274
|
"200"
|
|
275
275
|
];
|
|
276
276
|
}
|
|
277
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
278
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
279
|
+
}
|
|
277
280
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
278
281
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
279
282
|
}
|
|
@@ -289,18 +292,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
289
292
|
return dedupeByNumber(perLabel.flat());
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
293
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
294
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
295
|
-
const match = milestones.find((m) => m.title === slug);
|
|
296
|
-
if (!match)
|
|
297
|
-
return null;
|
|
298
|
-
return {
|
|
299
|
-
goal: match.description ?? "",
|
|
300
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
295
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
305
296
|
var LABELS = [
|
|
306
297
|
{
|
|
@@ -543,6 +534,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
543
534
|
return { trancheSlug, taskId };
|
|
544
535
|
}
|
|
545
536
|
|
|
537
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
538
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
539
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
540
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
541
|
+
function intentGoalForSlug(description, slug) {
|
|
542
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
543
|
+
const start = text.match(INTENTS_HEADING);
|
|
544
|
+
if (!start || start.index === undefined)
|
|
545
|
+
return "";
|
|
546
|
+
const rest = text.slice(start.index + start[0].length);
|
|
547
|
+
const next = rest.match(NEXT_HEADING);
|
|
548
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
549
|
+
for (const line of section.split(`
|
|
550
|
+
`)) {
|
|
551
|
+
const trimmed = line.trim();
|
|
552
|
+
if (trimmed.length === 0)
|
|
553
|
+
continue;
|
|
554
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
555
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
556
|
+
return (m[2] ?? "").trim();
|
|
557
|
+
}
|
|
558
|
+
return "";
|
|
559
|
+
}
|
|
560
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
561
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
562
|
+
}
|
|
563
|
+
function factsFromLegacyMilestone(milestone) {
|
|
564
|
+
return {
|
|
565
|
+
goal: milestone.description ?? "",
|
|
566
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function lifecycleFromIssues(issues) {
|
|
570
|
+
if (issues.length === 0)
|
|
571
|
+
return "planned";
|
|
572
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
573
|
+
}
|
|
574
|
+
function goalFromMilestones(milestones, slug) {
|
|
575
|
+
for (const m of milestones) {
|
|
576
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
577
|
+
if (goal)
|
|
578
|
+
return goal;
|
|
579
|
+
}
|
|
580
|
+
return "";
|
|
581
|
+
}
|
|
582
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
583
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
584
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
585
|
+
if (legacy)
|
|
586
|
+
return factsFromLegacyMilestone(legacy);
|
|
587
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
588
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
589
|
+
}
|
|
590
|
+
|
|
546
591
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
547
592
|
function trancheFromIssues(slug, issues, known) {
|
|
548
593
|
return {
|
|
@@ -3196,7 +3241,8 @@ var BRIEF_BUILTINS = [
|
|
|
3196
3241
|
"for",
|
|
3197
3242
|
"closesN",
|
|
3198
3243
|
"premiseCoverage",
|
|
3199
|
-
"issueRationale"
|
|
3244
|
+
"issueRationale",
|
|
3245
|
+
"milestoneShape"
|
|
3200
3246
|
];
|
|
3201
3247
|
var BriefSectionSchema = z.union([
|
|
3202
3248
|
z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
|
|
@@ -3206,7 +3252,9 @@ var BriefSectionSchema = z.union([
|
|
|
3206
3252
|
]);
|
|
3207
3253
|
var BriefSchemaSchema = z.object({
|
|
3208
3254
|
pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3209
|
-
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional()
|
|
3255
|
+
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3256
|
+
milestone: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3257
|
+
ack: z.array(z.enum(BRIEF_BUILTINS)).optional()
|
|
3210
3258
|
});
|
|
3211
3259
|
function isSafeRepoRelPath(p) {
|
|
3212
3260
|
if (p.length === 0)
|
|
@@ -273,6 +273,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
273
273
|
"200"
|
|
274
274
|
];
|
|
275
275
|
}
|
|
276
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
277
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
278
|
+
}
|
|
276
279
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
277
280
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
278
281
|
}
|
|
@@ -288,18 +291,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
288
291
|
return dedupeByNumber(perLabel.flat());
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
292
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
293
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
294
|
-
const match = milestones.find((m) => m.title === slug);
|
|
295
|
-
if (!match)
|
|
296
|
-
return null;
|
|
297
|
-
return {
|
|
298
|
-
goal: match.description ?? "",
|
|
299
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
294
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
304
295
|
var LABELS = [
|
|
305
296
|
{
|
|
@@ -542,6 +533,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
542
533
|
return { trancheSlug, taskId };
|
|
543
534
|
}
|
|
544
535
|
|
|
536
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
537
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
538
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
539
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
540
|
+
function intentGoalForSlug(description, slug) {
|
|
541
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
542
|
+
const start = text.match(INTENTS_HEADING);
|
|
543
|
+
if (!start || start.index === undefined)
|
|
544
|
+
return "";
|
|
545
|
+
const rest = text.slice(start.index + start[0].length);
|
|
546
|
+
const next = rest.match(NEXT_HEADING);
|
|
547
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
548
|
+
for (const line of section.split(`
|
|
549
|
+
`)) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (trimmed.length === 0)
|
|
552
|
+
continue;
|
|
553
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
554
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
555
|
+
return (m[2] ?? "").trim();
|
|
556
|
+
}
|
|
557
|
+
return "";
|
|
558
|
+
}
|
|
559
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
560
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
561
|
+
}
|
|
562
|
+
function factsFromLegacyMilestone(milestone) {
|
|
563
|
+
return {
|
|
564
|
+
goal: milestone.description ?? "",
|
|
565
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function lifecycleFromIssues(issues) {
|
|
569
|
+
if (issues.length === 0)
|
|
570
|
+
return "planned";
|
|
571
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
572
|
+
}
|
|
573
|
+
function goalFromMilestones(milestones, slug) {
|
|
574
|
+
for (const m of milestones) {
|
|
575
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
576
|
+
if (goal)
|
|
577
|
+
return goal;
|
|
578
|
+
}
|
|
579
|
+
return "";
|
|
580
|
+
}
|
|
581
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
582
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
583
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
584
|
+
if (legacy)
|
|
585
|
+
return factsFromLegacyMilestone(legacy);
|
|
586
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
587
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
588
|
+
}
|
|
589
|
+
|
|
545
590
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
546
591
|
function trancheFromIssues(slug, issues, known) {
|
|
547
592
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/checks/bin/check-first-push-dispatch.ts
|
|
4
|
-
import { execFileSync as
|
|
4
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
5
5
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
6
6
|
function maskCode(body) {
|
|
7
7
|
const fill = (line) => " ".repeat(line.length);
|
|
@@ -273,6 +273,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
273
273
|
"200"
|
|
274
274
|
];
|
|
275
275
|
}
|
|
276
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
277
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
278
|
+
}
|
|
276
279
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
277
280
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
278
281
|
}
|
|
@@ -288,18 +291,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
288
291
|
return dedupeByNumber(perLabel.flat());
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
292
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
293
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
294
|
-
const match = milestones.find((m) => m.title === slug);
|
|
295
|
-
if (!match)
|
|
296
|
-
return null;
|
|
297
|
-
return {
|
|
298
|
-
goal: match.description ?? "",
|
|
299
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
294
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
304
295
|
var LABELS = [
|
|
305
296
|
{
|
|
@@ -542,6 +533,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
542
533
|
return { trancheSlug, taskId };
|
|
543
534
|
}
|
|
544
535
|
|
|
536
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
537
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
538
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
539
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
540
|
+
function intentGoalForSlug(description, slug) {
|
|
541
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
542
|
+
const start = text.match(INTENTS_HEADING);
|
|
543
|
+
if (!start || start.index === undefined)
|
|
544
|
+
return "";
|
|
545
|
+
const rest = text.slice(start.index + start[0].length);
|
|
546
|
+
const next = rest.match(NEXT_HEADING);
|
|
547
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
548
|
+
for (const line of section.split(`
|
|
549
|
+
`)) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (trimmed.length === 0)
|
|
552
|
+
continue;
|
|
553
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
554
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
555
|
+
return (m[2] ?? "").trim();
|
|
556
|
+
}
|
|
557
|
+
return "";
|
|
558
|
+
}
|
|
559
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
560
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
561
|
+
}
|
|
562
|
+
function factsFromLegacyMilestone(milestone) {
|
|
563
|
+
return {
|
|
564
|
+
goal: milestone.description ?? "",
|
|
565
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function lifecycleFromIssues(issues) {
|
|
569
|
+
if (issues.length === 0)
|
|
570
|
+
return "planned";
|
|
571
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
572
|
+
}
|
|
573
|
+
function goalFromMilestones(milestones, slug) {
|
|
574
|
+
for (const m of milestones) {
|
|
575
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
576
|
+
if (goal)
|
|
577
|
+
return goal;
|
|
578
|
+
}
|
|
579
|
+
return "";
|
|
580
|
+
}
|
|
581
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
582
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
583
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
584
|
+
if (legacy)
|
|
585
|
+
return factsFromLegacyMilestone(legacy);
|
|
586
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
587
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
588
|
+
}
|
|
589
|
+
|
|
545
590
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
546
591
|
function trancheFromIssues(slug, issues, known) {
|
|
547
592
|
return {
|
|
@@ -3194,7 +3239,8 @@ var BRIEF_BUILTINS = [
|
|
|
3194
3239
|
"for",
|
|
3195
3240
|
"closesN",
|
|
3196
3241
|
"premiseCoverage",
|
|
3197
|
-
"issueRationale"
|
|
3242
|
+
"issueRationale",
|
|
3243
|
+
"milestoneShape"
|
|
3198
3244
|
];
|
|
3199
3245
|
var BriefSectionSchema = z2.union([
|
|
3200
3246
|
z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
|
|
@@ -3204,7 +3250,9 @@ var BriefSectionSchema = z2.union([
|
|
|
3204
3250
|
]);
|
|
3205
3251
|
var BriefSchemaSchema = z2.object({
|
|
3206
3252
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3207
|
-
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional()
|
|
3253
|
+
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3254
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3255
|
+
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3208
3256
|
});
|
|
3209
3257
|
function isSafeRepoRelPath(p) {
|
|
3210
3258
|
if (p.length === 0)
|
|
@@ -3316,11 +3364,74 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3316
3364
|
}
|
|
3317
3365
|
}
|
|
3318
3366
|
|
|
3367
|
+
// src/checks/edge-resolve.ts
|
|
3368
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3369
|
+
var DIRECT_ISSUE_REF = /#(\d+)/;
|
|
3370
|
+
var issueCache = new Map;
|
|
3371
|
+
function fetchIssueState(num, repo) {
|
|
3372
|
+
const key = `${repo.owner}/${repo.repo}#${num}`;
|
|
3373
|
+
if (issueCache.has(key))
|
|
3374
|
+
return issueCache.get(key) ?? null;
|
|
3375
|
+
let out = null;
|
|
3376
|
+
try {
|
|
3377
|
+
const raw = execFileSync3("gh", [
|
|
3378
|
+
"issue",
|
|
3379
|
+
"view",
|
|
3380
|
+
String(num),
|
|
3381
|
+
"-R",
|
|
3382
|
+
`${repo.owner}/${repo.repo}`,
|
|
3383
|
+
"--json",
|
|
3384
|
+
"state,stateReason,closedByPullRequestsReferences"
|
|
3385
|
+
], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3386
|
+
out = JSON.parse(raw);
|
|
3387
|
+
} catch {
|
|
3388
|
+
out = null;
|
|
3389
|
+
}
|
|
3390
|
+
issueCache.set(key, out);
|
|
3391
|
+
return out;
|
|
3392
|
+
}
|
|
3393
|
+
function edgeFromIssueJson(num, json) {
|
|
3394
|
+
if (json === null) {
|
|
3395
|
+
return { issue: num, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3396
|
+
}
|
|
3397
|
+
const state = json.state === "CLOSED" ? "closed" : json.state === "OPEN" ? "open" : null;
|
|
3398
|
+
const reason = json.stateReason === "COMPLETED" ? "completed" : json.stateReason === "NOT_PLANNED" ? "not_planned" : null;
|
|
3399
|
+
const closedByMergedPr = (json.closedByPullRequestsReferences ?? []).length > 0;
|
|
3400
|
+
return {
|
|
3401
|
+
issue: num,
|
|
3402
|
+
merged: state === "closed" && closedByMergedPr,
|
|
3403
|
+
open: false,
|
|
3404
|
+
issueState: state,
|
|
3405
|
+
stateReason: reason,
|
|
3406
|
+
closedByActor: null
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
function resolveEdge(id, taskById, factsByTaskId, repo) {
|
|
3410
|
+
const target = taskById.get(id);
|
|
3411
|
+
if (target) {
|
|
3412
|
+
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3413
|
+
return {
|
|
3414
|
+
issue: target.issue,
|
|
3415
|
+
merged: facts?.prState === "merged",
|
|
3416
|
+
open: facts?.prState === "open",
|
|
3417
|
+
issueState: facts?.issueState ?? null,
|
|
3418
|
+
stateReason: facts?.stateReason ?? null,
|
|
3419
|
+
closedByActor: facts?.closedByActor ?? null
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
const direct = id.match(DIRECT_ISSUE_REF);
|
|
3423
|
+
if (direct) {
|
|
3424
|
+
const num = Number(direct[1]);
|
|
3425
|
+
return edgeFromIssueJson(num, fetchIssueState(num, repo));
|
|
3426
|
+
}
|
|
3427
|
+
return { issue: null, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3319
3430
|
// src/checks/bin/check-first-push-dispatch.ts
|
|
3320
3431
|
var CHECK_NAME = "first-push-dispatch";
|
|
3321
3432
|
function git(args) {
|
|
3322
3433
|
try {
|
|
3323
|
-
return
|
|
3434
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3324
3435
|
} catch {
|
|
3325
3436
|
return "";
|
|
3326
3437
|
}
|
|
@@ -3343,7 +3454,7 @@ function resolveRepo2() {
|
|
|
3343
3454
|
}
|
|
3344
3455
|
function prExistsFor(branch) {
|
|
3345
3456
|
try {
|
|
3346
|
-
const out =
|
|
3457
|
+
const out = execFileSync4("gh", ["pr", "list", "--head", branch, "--state", "all", "--json", "number", "--limit", "1"], {
|
|
3347
3458
|
encoding: "utf8",
|
|
3348
3459
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3349
3460
|
});
|
|
@@ -3353,29 +3464,6 @@ function prExistsFor(branch) {
|
|
|
3353
3464
|
return false;
|
|
3354
3465
|
}
|
|
3355
3466
|
}
|
|
3356
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3357
|
-
const target = taskById.get(id);
|
|
3358
|
-
if (target) {
|
|
3359
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3360
|
-
return {
|
|
3361
|
-
issue: target.issue,
|
|
3362
|
-
merged: facts?.prState === "merged",
|
|
3363
|
-
open: facts?.prState === "open",
|
|
3364
|
-
issueState: facts?.issueState ?? null,
|
|
3365
|
-
stateReason: facts?.stateReason ?? null,
|
|
3366
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3367
|
-
};
|
|
3368
|
-
}
|
|
3369
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3370
|
-
return {
|
|
3371
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3372
|
-
merged: false,
|
|
3373
|
-
open: false,
|
|
3374
|
-
issueState: null,
|
|
3375
|
-
stateReason: null,
|
|
3376
|
-
closedByActor: null
|
|
3377
|
-
};
|
|
3378
|
-
}
|
|
3379
3467
|
async function classifyReadiness(trancheSlug, taskId) {
|
|
3380
3468
|
const repo = resolveRepo2();
|
|
3381
3469
|
if (!repo)
|
|
@@ -3403,7 +3491,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3403
3491
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3404
3492
|
const factsByTaskId = snapshot.facts;
|
|
3405
3493
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3406
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3494
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3407
3495
|
return {
|
|
3408
3496
|
id: dep,
|
|
3409
3497
|
issue: r.issue,
|
|
@@ -3414,7 +3502,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3414
3502
|
};
|
|
3415
3503
|
});
|
|
3416
3504
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3417
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3505
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3418
3506
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3419
3507
|
});
|
|
3420
3508
|
const input = {
|
|
@@ -273,6 +273,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
273
273
|
"200"
|
|
274
274
|
];
|
|
275
275
|
}
|
|
276
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
277
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
278
|
+
}
|
|
276
279
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
277
280
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
278
281
|
}
|
|
@@ -288,18 +291,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
288
291
|
return dedupeByNumber(perLabel.flat());
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
292
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
293
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
294
|
-
const match = milestones.find((m) => m.title === slug);
|
|
295
|
-
if (!match)
|
|
296
|
-
return null;
|
|
297
|
-
return {
|
|
298
|
-
goal: match.description ?? "",
|
|
299
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
294
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
304
295
|
var LABELS = [
|
|
305
296
|
{
|
|
@@ -542,6 +533,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
542
533
|
return { trancheSlug, taskId };
|
|
543
534
|
}
|
|
544
535
|
|
|
536
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
537
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
538
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
539
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
540
|
+
function intentGoalForSlug(description, slug) {
|
|
541
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
542
|
+
const start = text.match(INTENTS_HEADING);
|
|
543
|
+
if (!start || start.index === undefined)
|
|
544
|
+
return "";
|
|
545
|
+
const rest = text.slice(start.index + start[0].length);
|
|
546
|
+
const next = rest.match(NEXT_HEADING);
|
|
547
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
548
|
+
for (const line of section.split(`
|
|
549
|
+
`)) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (trimmed.length === 0)
|
|
552
|
+
continue;
|
|
553
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
554
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
555
|
+
return (m[2] ?? "").trim();
|
|
556
|
+
}
|
|
557
|
+
return "";
|
|
558
|
+
}
|
|
559
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
560
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
561
|
+
}
|
|
562
|
+
function factsFromLegacyMilestone(milestone) {
|
|
563
|
+
return {
|
|
564
|
+
goal: milestone.description ?? "",
|
|
565
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function lifecycleFromIssues(issues) {
|
|
569
|
+
if (issues.length === 0)
|
|
570
|
+
return "planned";
|
|
571
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
572
|
+
}
|
|
573
|
+
function goalFromMilestones(milestones, slug) {
|
|
574
|
+
for (const m of milestones) {
|
|
575
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
576
|
+
if (goal)
|
|
577
|
+
return goal;
|
|
578
|
+
}
|
|
579
|
+
return "";
|
|
580
|
+
}
|
|
581
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
582
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
583
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
584
|
+
if (legacy)
|
|
585
|
+
return factsFromLegacyMilestone(legacy);
|
|
586
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
587
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
588
|
+
}
|
|
589
|
+
|
|
545
590
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
546
591
|
function trancheFromIssues(slug, issues, known) {
|
|
547
592
|
return {
|