@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.
Files changed (87) hide show
  1. package/README.md +2 -0
  2. package/aeg-root/contracts/architect-planner.md +72 -0
  3. package/aeg-root/roles/architect.md +91 -0
  4. package/aeg-root/roles/planner.md +14 -15
  5. package/aeg-root/tranche-model.md +9 -1
  6. package/dist/checks/bin/check-body-bare-digits.js +60 -13
  7. package/dist/checks/bin/check-branch-topology.js +57 -12
  8. package/dist/checks/bin/check-brief-shape.js +57 -12
  9. package/dist/checks/bin/check-closes-n.js +57 -12
  10. package/dist/checks/bin/check-coherence.js +60 -13
  11. package/dist/checks/bin/check-dead-branch-push.js +57 -12
  12. package/dist/checks/bin/check-dispatch-readiness.js +127 -40
  13. package/dist/checks/bin/check-doc-coverage-push.js +60 -13
  14. package/dist/checks/bin/check-doc-coverage.js +60 -13
  15. package/dist/checks/bin/check-evidence-fresh.js +57 -12
  16. package/dist/checks/bin/check-first-push-dispatch.js +128 -41
  17. package/dist/checks/bin/check-issue-assignment.js +57 -12
  18. package/dist/checks/bin/check-no-disk-state.js +57 -12
  19. package/dist/checks/bin/check-reader-resolvable-prose.js +57 -12
  20. package/dist/checks/bin/check-registry-gates.js +57 -12
  21. package/dist/checks/bin/check-review-gate.js +60 -13
  22. package/dist/checks/bin/check-single-plan-pr.js +57 -12
  23. package/dist/checks/bin/check-test-plan.js +57 -12
  24. package/dist/index.js +663 -37
  25. package/package.json +1 -1
  26. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  27. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  28. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  29. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  30. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  31. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  32. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  33. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  34. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  35. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  36. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  37. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  38. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  39. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  40. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  41. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  42. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  43. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  44. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  45. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  46. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  47. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  48. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  49. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  50. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  51. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  52. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  53. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  54. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
  63. 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
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
  66. 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
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +5 -5
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  81. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2myi4phnshkfw.js → 2r36w820aqwb9.js} +1 -1
  82. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{415k4k1rf3swg.js → 2xoclb4g7d9n7.js} +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3z3a3gb6he23i.js → 3ocvtlhgckh81.js} +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
  85. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → RISz5nirLr1mUfMqzSaFS}/_buildManifest.js +0 -0
  86. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → RISz5nirLr1mUfMqzSaFS}/_clientMiddlewareManifest.js +0 -0
  87. /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 execFileSync3 } from "node:child_process";
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 execFileSync3("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
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) {