@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
@@ -275,6 +275,9 @@ function issueListByLabelArgs(owner, repo, label) {
275
275
  "200"
276
276
  ];
277
277
  }
278
+ function ghIssueListByLabel(owner, repo, label) {
279
+ return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
280
+ }
278
281
  async function ghIssueListByLabelAsync(owner, repo, label) {
279
282
  return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
280
283
  }
@@ -290,18 +293,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
290
293
  return dedupeByNumber(perLabel.flat());
291
294
  }
292
295
 
293
- // ../../packages/aeg-forge-state/src/fetch-milestone.ts
294
- function findMilestoneForSlug(owner, repo, slug) {
295
- const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
296
- const match = milestones.find((m) => m.title === slug);
297
- if (!match)
298
- return null;
299
- return {
300
- goal: match.description ?? "",
301
- lifecycle: match.state === "closed" ? "complete" : "active"
302
- };
303
- }
304
-
305
296
  // ../../packages/aeg-forge-state/src/labels.ts
306
297
  var LABELS = [
307
298
  {
@@ -544,6 +535,60 @@ function resolveTaskIssueRef(title, labels) {
544
535
  return { trancheSlug, taskId };
545
536
  }
546
537
 
538
+ // ../../packages/aeg-forge-state/src/fetch-milestone.ts
539
+ var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
540
+ var NEXT_HEADING = /^#{1,6}\s+\S/m;
541
+ var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
542
+ function intentGoalForSlug(description, slug) {
543
+ const text = stripCode(description, { inlineSpans: "keep" });
544
+ const start = text.match(INTENTS_HEADING);
545
+ if (!start || start.index === undefined)
546
+ return "";
547
+ const rest = text.slice(start.index + start[0].length);
548
+ const next = rest.match(NEXT_HEADING);
549
+ const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
550
+ for (const line of section.split(`
551
+ `)) {
552
+ const trimmed = line.trim();
553
+ if (trimmed.length === 0)
554
+ continue;
555
+ const m = trimmed.match(INTENT_BULLET);
556
+ if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
557
+ return (m[2] ?? "").trim();
558
+ }
559
+ return "";
560
+ }
561
+ function matchesLegacyMilestone(milestones, slug) {
562
+ return milestones.find((m) => m.title === slug) ?? null;
563
+ }
564
+ function factsFromLegacyMilestone(milestone) {
565
+ return {
566
+ goal: milestone.description ?? "",
567
+ lifecycle: milestone.state === "closed" ? "complete" : "active"
568
+ };
569
+ }
570
+ function lifecycleFromIssues(issues) {
571
+ if (issues.length === 0)
572
+ return "planned";
573
+ return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
574
+ }
575
+ function goalFromMilestones(milestones, slug) {
576
+ for (const m of milestones) {
577
+ const goal = intentGoalForSlug(m.description ?? "", slug);
578
+ if (goal)
579
+ return goal;
580
+ }
581
+ return "";
582
+ }
583
+ function findMilestoneForSlug(owner, repo, slug) {
584
+ const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
585
+ const legacy = matchesLegacyMilestone(milestones, slug);
586
+ if (legacy)
587
+ return factsFromLegacyMilestone(legacy);
588
+ const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
589
+ return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
590
+ }
591
+
547
592
  // ../../packages/aeg-forge-state/src/derive-from-forge.ts
548
593
  function trancheFromIssues(slug, issues, known) {
549
594
  return {
@@ -275,6 +275,9 @@ function issueListByLabelArgs(owner, repo, label) {
275
275
  "200"
276
276
  ];
277
277
  }
278
+ function ghIssueListByLabel(owner, repo, label) {
279
+ return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
280
+ }
278
281
  async function ghIssueListByLabelAsync(owner, repo, label) {
279
282
  return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
280
283
  }
@@ -290,18 +293,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
290
293
  return dedupeByNumber(perLabel.flat());
291
294
  }
292
295
 
293
- // ../../packages/aeg-forge-state/src/fetch-milestone.ts
294
- function findMilestoneForSlug(owner, repo, slug) {
295
- const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
296
- const match = milestones.find((m) => m.title === slug);
297
- if (!match)
298
- return null;
299
- return {
300
- goal: match.description ?? "",
301
- lifecycle: match.state === "closed" ? "complete" : "active"
302
- };
303
- }
304
-
305
296
  // ../../packages/aeg-forge-state/src/labels.ts
306
297
  var LABELS = [
307
298
  {
@@ -544,6 +535,60 @@ function resolveTaskIssueRef(title, labels) {
544
535
  return { trancheSlug, taskId };
545
536
  }
546
537
 
538
+ // ../../packages/aeg-forge-state/src/fetch-milestone.ts
539
+ var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
540
+ var NEXT_HEADING = /^#{1,6}\s+\S/m;
541
+ var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
542
+ function intentGoalForSlug(description, slug) {
543
+ const text = stripCode(description, { inlineSpans: "keep" });
544
+ const start = text.match(INTENTS_HEADING);
545
+ if (!start || start.index === undefined)
546
+ return "";
547
+ const rest = text.slice(start.index + start[0].length);
548
+ const next = rest.match(NEXT_HEADING);
549
+ const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
550
+ for (const line of section.split(`
551
+ `)) {
552
+ const trimmed = line.trim();
553
+ if (trimmed.length === 0)
554
+ continue;
555
+ const m = trimmed.match(INTENT_BULLET);
556
+ if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
557
+ return (m[2] ?? "").trim();
558
+ }
559
+ return "";
560
+ }
561
+ function matchesLegacyMilestone(milestones, slug) {
562
+ return milestones.find((m) => m.title === slug) ?? null;
563
+ }
564
+ function factsFromLegacyMilestone(milestone) {
565
+ return {
566
+ goal: milestone.description ?? "",
567
+ lifecycle: milestone.state === "closed" ? "complete" : "active"
568
+ };
569
+ }
570
+ function lifecycleFromIssues(issues) {
571
+ if (issues.length === 0)
572
+ return "planned";
573
+ return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
574
+ }
575
+ function goalFromMilestones(milestones, slug) {
576
+ for (const m of milestones) {
577
+ const goal = intentGoalForSlug(m.description ?? "", slug);
578
+ if (goal)
579
+ return goal;
580
+ }
581
+ return "";
582
+ }
583
+ function findMilestoneForSlug(owner, repo, slug) {
584
+ const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
585
+ const legacy = matchesLegacyMilestone(milestones, slug);
586
+ if (legacy)
587
+ return factsFromLegacyMilestone(legacy);
588
+ const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
589
+ return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
590
+ }
591
+
547
592
  // ../../packages/aeg-forge-state/src/derive-from-forge.ts
548
593
  function trancheFromIssues(slug, issues, known) {
549
594
  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 {
@@ -3180,7 +3225,8 @@ var BRIEF_BUILTINS = [
3180
3225
  "for",
3181
3226
  "closesN",
3182
3227
  "premiseCoverage",
3183
- "issueRationale"
3228
+ "issueRationale",
3229
+ "milestoneShape"
3184
3230
  ];
3185
3231
  var BriefSectionSchema = z.union([
3186
3232
  z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
@@ -3191,6 +3237,7 @@ var BriefSectionSchema = z.union([
3191
3237
  var BriefSchemaSchema = z.object({
3192
3238
  pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
3193
3239
  issue: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
3240
+ milestone: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
3194
3241
  ack: z.array(z.enum(BRIEF_BUILTINS)).optional()
3195
3242
  });
3196
3243
  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 {
@@ -270,6 +270,9 @@ function issueListByLabelArgs(owner, repo, label) {
270
270
  "200"
271
271
  ];
272
272
  }
273
+ function ghIssueListByLabel(owner, repo, label) {
274
+ return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
275
+ }
273
276
  async function ghIssueListByLabelAsync(owner, repo, label) {
274
277
  return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
275
278
  }
@@ -285,18 +288,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
285
288
  return dedupeByNumber(perLabel.flat());
286
289
  }
287
290
 
288
- // ../../packages/aeg-forge-state/src/fetch-milestone.ts
289
- function findMilestoneForSlug(owner, repo, slug) {
290
- const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
291
- const match = milestones.find((m) => m.title === slug);
292
- if (!match)
293
- return null;
294
- return {
295
- goal: match.description ?? "",
296
- lifecycle: match.state === "closed" ? "complete" : "active"
297
- };
298
- }
299
-
300
291
  // ../../packages/aeg-forge-state/src/labels.ts
301
292
  var LABELS = [
302
293
  {
@@ -539,6 +530,60 @@ function resolveTaskIssueRef(title, labels) {
539
530
  return { trancheSlug, taskId };
540
531
  }
541
532
 
533
+ // ../../packages/aeg-forge-state/src/fetch-milestone.ts
534
+ var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
535
+ var NEXT_HEADING = /^#{1,6}\s+\S/m;
536
+ var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
537
+ function intentGoalForSlug(description, slug) {
538
+ const text = stripCode(description, { inlineSpans: "keep" });
539
+ const start = text.match(INTENTS_HEADING);
540
+ if (!start || start.index === undefined)
541
+ return "";
542
+ const rest = text.slice(start.index + start[0].length);
543
+ const next = rest.match(NEXT_HEADING);
544
+ const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
545
+ for (const line of section.split(`
546
+ `)) {
547
+ const trimmed = line.trim();
548
+ if (trimmed.length === 0)
549
+ continue;
550
+ const m = trimmed.match(INTENT_BULLET);
551
+ if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
552
+ return (m[2] ?? "").trim();
553
+ }
554
+ return "";
555
+ }
556
+ function matchesLegacyMilestone(milestones, slug) {
557
+ return milestones.find((m) => m.title === slug) ?? null;
558
+ }
559
+ function factsFromLegacyMilestone(milestone) {
560
+ return {
561
+ goal: milestone.description ?? "",
562
+ lifecycle: milestone.state === "closed" ? "complete" : "active"
563
+ };
564
+ }
565
+ function lifecycleFromIssues(issues) {
566
+ if (issues.length === 0)
567
+ return "planned";
568
+ return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
569
+ }
570
+ function goalFromMilestones(milestones, slug) {
571
+ for (const m of milestones) {
572
+ const goal = intentGoalForSlug(m.description ?? "", slug);
573
+ if (goal)
574
+ return goal;
575
+ }
576
+ return "";
577
+ }
578
+ function findMilestoneForSlug(owner, repo, slug) {
579
+ const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
580
+ const legacy = matchesLegacyMilestone(milestones, slug);
581
+ if (legacy)
582
+ return factsFromLegacyMilestone(legacy);
583
+ const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
584
+ return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
585
+ }
586
+
542
587
  // ../../packages/aeg-forge-state/src/derive-from-forge.ts
543
588
  function trancheFromIssues(slug, issues, known) {
544
589
  return {