@attalabs/vinaya 0.18.0 → 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 +2 -0
- 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 +60 -13
- 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 +60 -13
- package/dist/checks/bin/check-dead-branch-push.js +57 -12
- package/dist/checks/bin/check-dispatch-readiness.js +127 -40
- package/dist/checks/bin/check-doc-coverage-push.js +60 -13
- package/dist/checks/bin/check-doc-coverage.js +60 -13
- package/dist/checks/bin/check-evidence-fresh.js +57 -12
- package/dist/checks/bin/check-first-push-dispatch.js +128 -41
- 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 +60 -13
- 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 +663 -37
- 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]__0z47hfl._.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/{2myi4phnshkfw.js → 2r36w820aqwb9.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{415k4k1rf3swg.js → 2xoclb4g7d9n7.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3z3a3gb6he23i.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/{8tXGbArNoU7_MriIVYvN0 → RISz5nirLr1mUfMqzSaFS}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → RISz5nirLr1mUfMqzSaFS}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → 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) }),
|
|
@@ -3207,6 +3253,7 @@ var BriefSectionSchema = z.union([
|
|
|
3207
3253
|
var BriefSchemaSchema = z.object({
|
|
3208
3254
|
pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3209
3255
|
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3256
|
+
milestone: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3210
3257
|
ack: z.array(z.enum(BRIEF_BUILTINS)).optional()
|
|
3211
3258
|
});
|
|
3212
3259
|
function isSafeRepoRelPath(p) {
|
|
@@ -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) }),
|
|
@@ -3205,6 +3251,7 @@ var BriefSectionSchema = z2.union([
|
|
|
3205
3251
|
var BriefSchemaSchema = z2.object({
|
|
3206
3252
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3207
3253
|
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3254
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3208
3255
|
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3209
3256
|
});
|
|
3210
3257
|
function isSafeRepoRelPath(p) {
|
|
@@ -3317,11 +3364,74 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3317
3364
|
}
|
|
3318
3365
|
}
|
|
3319
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
|
+
|
|
3320
3430
|
// src/checks/bin/check-first-push-dispatch.ts
|
|
3321
3431
|
var CHECK_NAME = "first-push-dispatch";
|
|
3322
3432
|
function git(args) {
|
|
3323
3433
|
try {
|
|
3324
|
-
return
|
|
3434
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3325
3435
|
} catch {
|
|
3326
3436
|
return "";
|
|
3327
3437
|
}
|
|
@@ -3344,7 +3454,7 @@ function resolveRepo2() {
|
|
|
3344
3454
|
}
|
|
3345
3455
|
function prExistsFor(branch) {
|
|
3346
3456
|
try {
|
|
3347
|
-
const out =
|
|
3457
|
+
const out = execFileSync4("gh", ["pr", "list", "--head", branch, "--state", "all", "--json", "number", "--limit", "1"], {
|
|
3348
3458
|
encoding: "utf8",
|
|
3349
3459
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3350
3460
|
});
|
|
@@ -3354,29 +3464,6 @@ function prExistsFor(branch) {
|
|
|
3354
3464
|
return false;
|
|
3355
3465
|
}
|
|
3356
3466
|
}
|
|
3357
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3358
|
-
const target = taskById.get(id);
|
|
3359
|
-
if (target) {
|
|
3360
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3361
|
-
return {
|
|
3362
|
-
issue: target.issue,
|
|
3363
|
-
merged: facts?.prState === "merged",
|
|
3364
|
-
open: facts?.prState === "open",
|
|
3365
|
-
issueState: facts?.issueState ?? null,
|
|
3366
|
-
stateReason: facts?.stateReason ?? null,
|
|
3367
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3368
|
-
};
|
|
3369
|
-
}
|
|
3370
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3371
|
-
return {
|
|
3372
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3373
|
-
merged: false,
|
|
3374
|
-
open: false,
|
|
3375
|
-
issueState: null,
|
|
3376
|
-
stateReason: null,
|
|
3377
|
-
closedByActor: null
|
|
3378
|
-
};
|
|
3379
|
-
}
|
|
3380
3467
|
async function classifyReadiness(trancheSlug, taskId) {
|
|
3381
3468
|
const repo = resolveRepo2();
|
|
3382
3469
|
if (!repo)
|
|
@@ -3404,7 +3491,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3404
3491
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3405
3492
|
const factsByTaskId = snapshot.facts;
|
|
3406
3493
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3407
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3494
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3408
3495
|
return {
|
|
3409
3496
|
id: dep,
|
|
3410
3497
|
issue: r.issue,
|
|
@@ -3415,7 +3502,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3415
3502
|
};
|
|
3416
3503
|
});
|
|
3417
3504
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3418
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3505
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3419
3506
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3420
3507
|
});
|
|
3421
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 {
|
|
@@ -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 {
|