@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
|
@@ -270,6 +270,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
270
270
|
"200"
|
|
271
271
|
];
|
|
272
272
|
}
|
|
273
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
274
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
275
|
+
}
|
|
273
276
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
274
277
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
275
278
|
}
|
|
@@ -285,18 +288,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
285
288
|
return dedupeByNumber(perLabel.flat());
|
|
286
289
|
}
|
|
287
290
|
|
|
288
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
289
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
290
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
291
|
-
const match = milestones.find((m) => m.title === slug);
|
|
292
|
-
if (!match)
|
|
293
|
-
return null;
|
|
294
|
-
return {
|
|
295
|
-
goal: match.description ?? "",
|
|
296
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
|
|
300
291
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
301
292
|
var LABELS = [
|
|
302
293
|
{
|
|
@@ -539,6 +530,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
539
530
|
return { trancheSlug, taskId };
|
|
540
531
|
}
|
|
541
532
|
|
|
533
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
534
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
535
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
536
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
537
|
+
function intentGoalForSlug(description, slug) {
|
|
538
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
539
|
+
const start = text.match(INTENTS_HEADING);
|
|
540
|
+
if (!start || start.index === undefined)
|
|
541
|
+
return "";
|
|
542
|
+
const rest = text.slice(start.index + start[0].length);
|
|
543
|
+
const next = rest.match(NEXT_HEADING);
|
|
544
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
545
|
+
for (const line of section.split(`
|
|
546
|
+
`)) {
|
|
547
|
+
const trimmed = line.trim();
|
|
548
|
+
if (trimmed.length === 0)
|
|
549
|
+
continue;
|
|
550
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
551
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
552
|
+
return (m[2] ?? "").trim();
|
|
553
|
+
}
|
|
554
|
+
return "";
|
|
555
|
+
}
|
|
556
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
557
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
558
|
+
}
|
|
559
|
+
function factsFromLegacyMilestone(milestone) {
|
|
560
|
+
return {
|
|
561
|
+
goal: milestone.description ?? "",
|
|
562
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
function lifecycleFromIssues(issues) {
|
|
566
|
+
if (issues.length === 0)
|
|
567
|
+
return "planned";
|
|
568
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
569
|
+
}
|
|
570
|
+
function goalFromMilestones(milestones, slug) {
|
|
571
|
+
for (const m of milestones) {
|
|
572
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
573
|
+
if (goal)
|
|
574
|
+
return goal;
|
|
575
|
+
}
|
|
576
|
+
return "";
|
|
577
|
+
}
|
|
578
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
579
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
580
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
581
|
+
if (legacy)
|
|
582
|
+
return factsFromLegacyMilestone(legacy);
|
|
583
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
584
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
585
|
+
}
|
|
586
|
+
|
|
542
587
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
543
588
|
function trancheFromIssues(slug, issues, known) {
|
|
544
589
|
return {
|
|
@@ -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 {
|
|
@@ -276,6 +276,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
276
276
|
"200"
|
|
277
277
|
];
|
|
278
278
|
}
|
|
279
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
280
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
281
|
+
}
|
|
279
282
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
280
283
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
281
284
|
}
|
|
@@ -291,18 +294,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
291
294
|
return dedupeByNumber(perLabel.flat());
|
|
292
295
|
}
|
|
293
296
|
|
|
294
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
295
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
296
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
297
|
-
const match = milestones.find((m) => m.title === slug);
|
|
298
|
-
if (!match)
|
|
299
|
-
return null;
|
|
300
|
-
return {
|
|
301
|
-
goal: match.description ?? "",
|
|
302
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
297
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
307
298
|
var LABELS = [
|
|
308
299
|
{
|
|
@@ -545,6 +536,60 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
545
536
|
return { trancheSlug, taskId };
|
|
546
537
|
}
|
|
547
538
|
|
|
539
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
540
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
541
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
542
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
543
|
+
function intentGoalForSlug(description, slug) {
|
|
544
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
545
|
+
const start = text.match(INTENTS_HEADING);
|
|
546
|
+
if (!start || start.index === undefined)
|
|
547
|
+
return "";
|
|
548
|
+
const rest = text.slice(start.index + start[0].length);
|
|
549
|
+
const next = rest.match(NEXT_HEADING);
|
|
550
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
551
|
+
for (const line of section.split(`
|
|
552
|
+
`)) {
|
|
553
|
+
const trimmed = line.trim();
|
|
554
|
+
if (trimmed.length === 0)
|
|
555
|
+
continue;
|
|
556
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
557
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
558
|
+
return (m[2] ?? "").trim();
|
|
559
|
+
}
|
|
560
|
+
return "";
|
|
561
|
+
}
|
|
562
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
563
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
564
|
+
}
|
|
565
|
+
function factsFromLegacyMilestone(milestone) {
|
|
566
|
+
return {
|
|
567
|
+
goal: milestone.description ?? "",
|
|
568
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function lifecycleFromIssues(issues) {
|
|
572
|
+
if (issues.length === 0)
|
|
573
|
+
return "planned";
|
|
574
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
575
|
+
}
|
|
576
|
+
function goalFromMilestones(milestones, slug) {
|
|
577
|
+
for (const m of milestones) {
|
|
578
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
579
|
+
if (goal)
|
|
580
|
+
return goal;
|
|
581
|
+
}
|
|
582
|
+
return "";
|
|
583
|
+
}
|
|
584
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
585
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
586
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
587
|
+
if (legacy)
|
|
588
|
+
return factsFromLegacyMilestone(legacy);
|
|
589
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
590
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
591
|
+
}
|
|
592
|
+
|
|
548
593
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
549
594
|
function trancheFromIssues(slug, issues, known) {
|
|
550
595
|
return {
|
|
@@ -3197,7 +3242,8 @@ var BRIEF_BUILTINS = [
|
|
|
3197
3242
|
"for",
|
|
3198
3243
|
"closesN",
|
|
3199
3244
|
"premiseCoverage",
|
|
3200
|
-
"issueRationale"
|
|
3245
|
+
"issueRationale",
|
|
3246
|
+
"milestoneShape"
|
|
3201
3247
|
];
|
|
3202
3248
|
var BriefSectionSchema = z2.union([
|
|
3203
3249
|
z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
|
|
@@ -3207,7 +3253,9 @@ var BriefSectionSchema = z2.union([
|
|
|
3207
3253
|
]);
|
|
3208
3254
|
var BriefSchemaSchema = z2.object({
|
|
3209
3255
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3210
|
-
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional()
|
|
3256
|
+
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3257
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3258
|
+
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3211
3259
|
});
|
|
3212
3260
|
function isSafeRepoRelPath(p) {
|
|
3213
3261
|
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-dispatch-readiness.ts
|
|
4
|
-
import { execFile as execFile4, execFileSync as
|
|
4
|
+
import { execFile as execFile4, execFileSync as execFileSync4 } from "node:child_process";
|
|
5
5
|
import { promisify as promisify4 } from "node:util";
|
|
6
6
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
7
7
|
function maskCode(body) {
|
|
@@ -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 {
|
|
@@ -3195,7 +3240,8 @@ var BRIEF_BUILTINS = [
|
|
|
3195
3240
|
"for",
|
|
3196
3241
|
"closesN",
|
|
3197
3242
|
"premiseCoverage",
|
|
3198
|
-
"issueRationale"
|
|
3243
|
+
"issueRationale",
|
|
3244
|
+
"milestoneShape"
|
|
3199
3245
|
];
|
|
3200
3246
|
var BriefSectionSchema = z2.union([
|
|
3201
3247
|
z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
|
|
@@ -3205,7 +3251,9 @@ var BriefSectionSchema = z2.union([
|
|
|
3205
3251
|
]);
|
|
3206
3252
|
var BriefSchemaSchema = z2.object({
|
|
3207
3253
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3208
|
-
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional()
|
|
3254
|
+
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3255
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3256
|
+
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3209
3257
|
});
|
|
3210
3258
|
function isSafeRepoRelPath(p) {
|
|
3211
3259
|
if (p.length === 0)
|
|
@@ -3317,12 +3365,75 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3317
3365
|
}
|
|
3318
3366
|
}
|
|
3319
3367
|
|
|
3368
|
+
// src/checks/edge-resolve.ts
|
|
3369
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3370
|
+
var DIRECT_ISSUE_REF = /#(\d+)/;
|
|
3371
|
+
var issueCache = new Map;
|
|
3372
|
+
function fetchIssueState(num, repo) {
|
|
3373
|
+
const key = `${repo.owner}/${repo.repo}#${num}`;
|
|
3374
|
+
if (issueCache.has(key))
|
|
3375
|
+
return issueCache.get(key) ?? null;
|
|
3376
|
+
let out = null;
|
|
3377
|
+
try {
|
|
3378
|
+
const raw = execFileSync3("gh", [
|
|
3379
|
+
"issue",
|
|
3380
|
+
"view",
|
|
3381
|
+
String(num),
|
|
3382
|
+
"-R",
|
|
3383
|
+
`${repo.owner}/${repo.repo}`,
|
|
3384
|
+
"--json",
|
|
3385
|
+
"state,stateReason,closedByPullRequestsReferences"
|
|
3386
|
+
], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3387
|
+
out = JSON.parse(raw);
|
|
3388
|
+
} catch {
|
|
3389
|
+
out = null;
|
|
3390
|
+
}
|
|
3391
|
+
issueCache.set(key, out);
|
|
3392
|
+
return out;
|
|
3393
|
+
}
|
|
3394
|
+
function edgeFromIssueJson(num, json) {
|
|
3395
|
+
if (json === null) {
|
|
3396
|
+
return { issue: num, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3397
|
+
}
|
|
3398
|
+
const state = json.state === "CLOSED" ? "closed" : json.state === "OPEN" ? "open" : null;
|
|
3399
|
+
const reason = json.stateReason === "COMPLETED" ? "completed" : json.stateReason === "NOT_PLANNED" ? "not_planned" : null;
|
|
3400
|
+
const closedByMergedPr = (json.closedByPullRequestsReferences ?? []).length > 0;
|
|
3401
|
+
return {
|
|
3402
|
+
issue: num,
|
|
3403
|
+
merged: state === "closed" && closedByMergedPr,
|
|
3404
|
+
open: false,
|
|
3405
|
+
issueState: state,
|
|
3406
|
+
stateReason: reason,
|
|
3407
|
+
closedByActor: null
|
|
3408
|
+
};
|
|
3409
|
+
}
|
|
3410
|
+
function resolveEdge(id, taskById, factsByTaskId, repo) {
|
|
3411
|
+
const target = taskById.get(id);
|
|
3412
|
+
if (target) {
|
|
3413
|
+
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3414
|
+
return {
|
|
3415
|
+
issue: target.issue,
|
|
3416
|
+
merged: facts?.prState === "merged",
|
|
3417
|
+
open: facts?.prState === "open",
|
|
3418
|
+
issueState: facts?.issueState ?? null,
|
|
3419
|
+
stateReason: facts?.stateReason ?? null,
|
|
3420
|
+
closedByActor: facts?.closedByActor ?? null
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
const direct = id.match(DIRECT_ISSUE_REF);
|
|
3424
|
+
if (direct) {
|
|
3425
|
+
const num = Number(direct[1]);
|
|
3426
|
+
return edgeFromIssueJson(num, fetchIssueState(num, repo));
|
|
3427
|
+
}
|
|
3428
|
+
return { issue: null, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3320
3431
|
// src/checks/bin/check-dispatch-readiness.ts
|
|
3321
3432
|
var CHECK_NAME = "dispatch-readiness";
|
|
3322
3433
|
var execFileAsync4 = promisify4(execFile4);
|
|
3323
3434
|
function git(args) {
|
|
3324
3435
|
try {
|
|
3325
|
-
return
|
|
3436
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3326
3437
|
} catch {
|
|
3327
3438
|
return "";
|
|
3328
3439
|
}
|
|
@@ -3369,29 +3480,6 @@ function fail(message, prompt) {
|
|
|
3369
3480
|
});
|
|
3370
3481
|
process.exit(1);
|
|
3371
3482
|
}
|
|
3372
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3373
|
-
const target = taskById.get(id);
|
|
3374
|
-
if (target) {
|
|
3375
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3376
|
-
return {
|
|
3377
|
-
issue: target.issue,
|
|
3378
|
-
merged: facts?.prState === "merged",
|
|
3379
|
-
open: facts?.prState === "open",
|
|
3380
|
-
issueState: facts?.issueState ?? null,
|
|
3381
|
-
stateReason: facts?.stateReason ?? null,
|
|
3382
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3383
|
-
};
|
|
3384
|
-
}
|
|
3385
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3386
|
-
return {
|
|
3387
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3388
|
-
merged: false,
|
|
3389
|
-
open: false,
|
|
3390
|
-
issueState: null,
|
|
3391
|
-
stateReason: null,
|
|
3392
|
-
closedByActor: null
|
|
3393
|
-
};
|
|
3394
|
-
}
|
|
3395
3483
|
async function main() {
|
|
3396
3484
|
const branch = currentBranch();
|
|
3397
3485
|
const m = branch.match(/^task\/([^/]+)\/(.+)$/);
|
|
@@ -3432,7 +3520,7 @@ async function main() {
|
|
|
3432
3520
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3433
3521
|
const factsByTaskId = snapshot.facts;
|
|
3434
3522
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3435
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3523
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3436
3524
|
return {
|
|
3437
3525
|
id: dep,
|
|
3438
3526
|
issue: r.issue,
|
|
@@ -3443,7 +3531,7 @@ async function main() {
|
|
|
3443
3531
|
};
|
|
3444
3532
|
});
|
|
3445
3533
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3446
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3534
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3447
3535
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3448
3536
|
});
|
|
3449
3537
|
const priorTrancheArchival = [];
|