@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
|
@@ -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) }),
|
|
@@ -3208,6 +3254,7 @@ var BriefSectionSchema = z2.union([
|
|
|
3208
3254
|
var BriefSchemaSchema = z2.object({
|
|
3209
3255
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3210
3256
|
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3257
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3211
3258
|
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3212
3259
|
});
|
|
3213
3260
|
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-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) }),
|
|
@@ -3206,6 +3252,7 @@ var BriefSectionSchema = z2.union([
|
|
|
3206
3252
|
var BriefSchemaSchema = z2.object({
|
|
3207
3253
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3208
3254
|
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3255
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3209
3256
|
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3210
3257
|
});
|
|
3211
3258
|
function isSafeRepoRelPath(p) {
|
|
@@ -3318,12 +3365,75 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3318
3365
|
}
|
|
3319
3366
|
}
|
|
3320
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
|
+
|
|
3321
3431
|
// src/checks/bin/check-dispatch-readiness.ts
|
|
3322
3432
|
var CHECK_NAME = "dispatch-readiness";
|
|
3323
3433
|
var execFileAsync4 = promisify4(execFile4);
|
|
3324
3434
|
function git(args) {
|
|
3325
3435
|
try {
|
|
3326
|
-
return
|
|
3436
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3327
3437
|
} catch {
|
|
3328
3438
|
return "";
|
|
3329
3439
|
}
|
|
@@ -3370,29 +3480,6 @@ function fail(message, prompt) {
|
|
|
3370
3480
|
});
|
|
3371
3481
|
process.exit(1);
|
|
3372
3482
|
}
|
|
3373
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3374
|
-
const target = taskById.get(id);
|
|
3375
|
-
if (target) {
|
|
3376
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3377
|
-
return {
|
|
3378
|
-
issue: target.issue,
|
|
3379
|
-
merged: facts?.prState === "merged",
|
|
3380
|
-
open: facts?.prState === "open",
|
|
3381
|
-
issueState: facts?.issueState ?? null,
|
|
3382
|
-
stateReason: facts?.stateReason ?? null,
|
|
3383
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3384
|
-
};
|
|
3385
|
-
}
|
|
3386
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3387
|
-
return {
|
|
3388
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3389
|
-
merged: false,
|
|
3390
|
-
open: false,
|
|
3391
|
-
issueState: null,
|
|
3392
|
-
stateReason: null,
|
|
3393
|
-
closedByActor: null
|
|
3394
|
-
};
|
|
3395
|
-
}
|
|
3396
3483
|
async function main() {
|
|
3397
3484
|
const branch = currentBranch();
|
|
3398
3485
|
const m = branch.match(/^task\/([^/]+)\/(.+)$/);
|
|
@@ -3433,7 +3520,7 @@ async function main() {
|
|
|
3433
3520
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3434
3521
|
const factsByTaskId = snapshot.facts;
|
|
3435
3522
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3436
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3523
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3437
3524
|
return {
|
|
3438
3525
|
id: dep,
|
|
3439
3526
|
issue: r.issue,
|
|
@@ -3444,7 +3531,7 @@ async function main() {
|
|
|
3444
3531
|
};
|
|
3445
3532
|
});
|
|
3446
3533
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3447
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3534
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3448
3535
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3449
3536
|
});
|
|
3450
3537
|
const priorTrancheArchival = [];
|
|
@@ -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) {
|