@hivemoot-dev/cli 0.1.3 → 0.1.4
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/dist/index.js +72 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -244,7 +244,7 @@ async function resolveRepo(repoFlag) {
|
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
// src/github/issues.ts
|
|
247
|
-
async function fetchIssues(repo) {
|
|
247
|
+
async function fetchIssues(repo, limit = 200) {
|
|
248
248
|
const json = await gh([
|
|
249
249
|
"issue",
|
|
250
250
|
"list",
|
|
@@ -255,7 +255,7 @@ async function fetchIssues(repo) {
|
|
|
255
255
|
"--json",
|
|
256
256
|
"number,title,labels,assignees,author,comments,createdAt,updatedAt,url",
|
|
257
257
|
"--limit",
|
|
258
|
-
|
|
258
|
+
String(limit)
|
|
259
259
|
]);
|
|
260
260
|
let parsed;
|
|
261
261
|
try {
|
|
@@ -278,7 +278,7 @@ async function fetchIssues(repo) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// src/github/pulls.ts
|
|
281
|
-
async function fetchPulls(repo) {
|
|
281
|
+
async function fetchPulls(repo, limit = 200) {
|
|
282
282
|
const json = await gh([
|
|
283
283
|
"pr",
|
|
284
284
|
"list",
|
|
@@ -289,7 +289,7 @@ async function fetchPulls(repo) {
|
|
|
289
289
|
"--json",
|
|
290
290
|
"number,title,state,author,labels,comments,reviews,createdAt,updatedAt,url,isDraft,reviewDecision,mergeable,statusCheckRollup,closingIssuesReferences",
|
|
291
291
|
"--limit",
|
|
292
|
-
|
|
292
|
+
String(limit)
|
|
293
293
|
]);
|
|
294
294
|
let parsed;
|
|
295
295
|
try {
|
|
@@ -333,6 +333,27 @@ function hasLabel(labels, keyword) {
|
|
|
333
333
|
function hasExactLabel(labels, labelName) {
|
|
334
334
|
return labels.some((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
335
335
|
}
|
|
336
|
+
function timeAgo(dateStr, now) {
|
|
337
|
+
const ms = now.getTime() - new Date(dateStr).getTime();
|
|
338
|
+
if (ms < 0) return "just now";
|
|
339
|
+
const minutes = Math.floor(ms / 6e4);
|
|
340
|
+
const hours = Math.floor(ms / 36e5);
|
|
341
|
+
const days = Math.floor(ms / 864e5);
|
|
342
|
+
if (minutes < 1) return "just now";
|
|
343
|
+
if (minutes === 1) return "1 minute ago";
|
|
344
|
+
if (minutes < 60) return `${minutes} minutes ago`;
|
|
345
|
+
if (hours === 1) return "1 hour ago";
|
|
346
|
+
if (hours < 24) return `${hours} hours ago`;
|
|
347
|
+
if (days === 1) return "yesterday";
|
|
348
|
+
if (days < 7) return `${days} days ago`;
|
|
349
|
+
if (days < 14) return "1 week ago";
|
|
350
|
+
if (days < 30) return `${Math.floor(days / 7)} weeks ago`;
|
|
351
|
+
if (days < 60) return "1 month ago";
|
|
352
|
+
if (days < 365) return `${Math.floor(days / 30)} months ago`;
|
|
353
|
+
const years = Math.floor(days / 365);
|
|
354
|
+
if (years === 1) return "1 year ago";
|
|
355
|
+
return `${years} years ago`;
|
|
356
|
+
}
|
|
336
357
|
function daysSince(dateStr, now) {
|
|
337
358
|
const diff = now.getTime() - new Date(dateStr).getTime();
|
|
338
359
|
return Math.max(0, Math.floor(diff / (1e3 * 60 * 60 * 24)));
|
|
@@ -361,18 +382,27 @@ function mergeStatus(pr) {
|
|
|
361
382
|
if (pr.mergeable === "MERGEABLE") return "no conflicts";
|
|
362
383
|
return null;
|
|
363
384
|
}
|
|
364
|
-
function
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
latestByAuthor.set(review.author.login, review.state);
|
|
385
|
+
function latestReviewByAuthor(pr) {
|
|
386
|
+
const map = /* @__PURE__ */ new Map();
|
|
387
|
+
for (const review of pr.reviews ?? []) {
|
|
388
|
+
map.set(review.author?.login ?? "ghost", review.state);
|
|
369
389
|
}
|
|
390
|
+
return map;
|
|
391
|
+
}
|
|
392
|
+
function approvalCount(pr) {
|
|
370
393
|
let count = 0;
|
|
371
|
-
for (const state of
|
|
394
|
+
for (const state of latestReviewByAuthor(pr).values()) {
|
|
372
395
|
if (state === "APPROVED") count++;
|
|
373
396
|
}
|
|
374
397
|
return count;
|
|
375
398
|
}
|
|
399
|
+
function changesRequestedCount(pr) {
|
|
400
|
+
let count = 0;
|
|
401
|
+
for (const state of latestReviewByAuthor(pr).values()) {
|
|
402
|
+
if (state === "CHANGES_REQUESTED") count++;
|
|
403
|
+
}
|
|
404
|
+
return count;
|
|
405
|
+
}
|
|
376
406
|
|
|
377
407
|
// src/summary/alerts.ts
|
|
378
408
|
var STALE_DISCUSSION_DAYS = 3;
|
|
@@ -430,12 +460,6 @@ function generateAlerts(issues, prs, now = /* @__PURE__ */ new Date()) {
|
|
|
430
460
|
}
|
|
431
461
|
|
|
432
462
|
// src/summary/builder.ts
|
|
433
|
-
function timeAgo(dateStr, now) {
|
|
434
|
-
const days = daysSince(dateStr, now);
|
|
435
|
-
if (days === 0) return "today";
|
|
436
|
-
if (days === 1) return "1 day old";
|
|
437
|
-
return `${days} days old`;
|
|
438
|
-
}
|
|
439
463
|
function compactChecks(raw) {
|
|
440
464
|
if (raw === null) return null;
|
|
441
465
|
if (raw === "checks failing") return "failing";
|
|
@@ -453,7 +477,7 @@ function classifyIssue(issue, now) {
|
|
|
453
477
|
const age = timeAgo(issue.createdAt, now);
|
|
454
478
|
const assigned = issue.assignees.length > 0 ? issue.assignees.map((a) => a.login).join(", ") : void 0;
|
|
455
479
|
const tags = issue.labels.map((l) => l.name);
|
|
456
|
-
const author = issue.author
|
|
480
|
+
const author = issue.author?.login ?? "ghost";
|
|
457
481
|
const comments = issue.comments.length;
|
|
458
482
|
const base = {
|
|
459
483
|
number: issue.number,
|
|
@@ -492,12 +516,15 @@ function classifyIssue(issue, now) {
|
|
|
492
516
|
function classifyPR(pr, now) {
|
|
493
517
|
const age = timeAgo(pr.createdAt, now);
|
|
494
518
|
const tags = pr.labels.map((l) => l.name);
|
|
495
|
-
const author = pr.author
|
|
519
|
+
const author = pr.author?.login ?? "ghost";
|
|
496
520
|
const comments = pr.comments.length;
|
|
497
521
|
const ciFailing = hasCIFailure(pr);
|
|
498
522
|
const checks = compactChecks(checkStatus(pr));
|
|
499
523
|
const merge = compactMergeable(mergeStatus(pr));
|
|
500
|
-
const
|
|
524
|
+
const review = {
|
|
525
|
+
approvals: approvalCount(pr),
|
|
526
|
+
changesRequested: changesRequestedCount(pr)
|
|
527
|
+
};
|
|
501
528
|
if (pr.isDraft || ciFailing || pr.reviewDecision === "CHANGES_REQUESTED") {
|
|
502
529
|
let status2;
|
|
503
530
|
if (pr.isDraft) status2 = "draft";
|
|
@@ -505,20 +532,20 @@ function classifyPR(pr, now) {
|
|
|
505
532
|
else status2 = "waiting";
|
|
506
533
|
return {
|
|
507
534
|
bucket: "addressFeedback",
|
|
508
|
-
item: { number: pr.number, title: pr.title, tags, author, comments, age, status: status2, checks, mergeable: merge,
|
|
535
|
+
item: { number: pr.number, title: pr.title, tags, author, comments, age, status: status2, checks, mergeable: merge, review }
|
|
509
536
|
};
|
|
510
537
|
}
|
|
511
538
|
const status = pr.reviewDecision === "APPROVED" ? "approved" : "waiting";
|
|
512
539
|
return {
|
|
513
540
|
bucket: "reviewPRs",
|
|
514
|
-
item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge,
|
|
541
|
+
item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge, review }
|
|
515
542
|
};
|
|
516
543
|
}
|
|
517
544
|
function buildCompetitionMap(prs, currentUser) {
|
|
518
545
|
const map = /* @__PURE__ */ new Map();
|
|
519
546
|
for (const pr of prs) {
|
|
520
547
|
if (!hasLabel(pr.labels, "implementation")) continue;
|
|
521
|
-
if (pr.author
|
|
548
|
+
if (pr.author?.login === currentUser) continue;
|
|
522
549
|
for (const ref of pr.closingIssuesReferences) {
|
|
523
550
|
map.set(ref.number, (map.get(ref.number) ?? 0) + 1);
|
|
524
551
|
}
|
|
@@ -590,7 +617,8 @@ function buildSummary(repo, issues, prs, currentUser, now = /* @__PURE__ */ new
|
|
|
590
617
|
implement,
|
|
591
618
|
reviewPRs: filteredReviewPRs,
|
|
592
619
|
addressFeedback: filteredAddressFeedback,
|
|
593
|
-
alerts
|
|
620
|
+
alerts,
|
|
621
|
+
notes: []
|
|
594
622
|
};
|
|
595
623
|
}
|
|
596
624
|
|
|
@@ -616,20 +644,20 @@ function formatMeta(item, sectionType, currentUser) {
|
|
|
616
644
|
if (sectionType === "implement") {
|
|
617
645
|
parts.push(kv("assigned", item.assigned ?? "--"));
|
|
618
646
|
parts.push(kv("comments", item.comments));
|
|
619
|
-
parts.push(kv("
|
|
647
|
+
parts.push(kv("created", item.age));
|
|
620
648
|
if (item.competingPRs !== void 0) {
|
|
621
649
|
parts.push(kv("competing", item.competingPRs));
|
|
622
650
|
}
|
|
623
651
|
} else if (sectionType === "vote" || sectionType === "discuss" || sectionType === "driveDiscussion") {
|
|
624
652
|
parts.push(kv("comments", item.comments));
|
|
625
|
-
parts.push(kv("
|
|
653
|
+
parts.push(kv("created", item.age));
|
|
626
654
|
} else {
|
|
627
655
|
if (item.status !== void 0) parts.push(kv("status", item.status));
|
|
628
656
|
if (item.checks !== void 0 && item.checks !== null) parts.push(kv("checks", item.checks));
|
|
629
657
|
if (item.mergeable !== void 0 && item.mergeable !== null) parts.push(kv("merge", item.mergeable));
|
|
630
|
-
if (item.
|
|
658
|
+
if (item.review) parts.push(kv("review", `${item.review.approvals} approved, ${item.review.changesRequested} changes-requested`));
|
|
631
659
|
parts.push(kv("comments", item.comments));
|
|
632
|
-
parts.push(kv("
|
|
660
|
+
parts.push(kv("created", item.age));
|
|
633
661
|
}
|
|
634
662
|
return parts.join(" ");
|
|
635
663
|
}
|
|
@@ -675,6 +703,9 @@ function formatSummaryBody(summary, limit) {
|
|
|
675
703
|
formatSection("ADDRESS FEEDBACK PRs", summary.addressFeedback, u, "addressFeedback", limit)
|
|
676
704
|
].filter(Boolean)
|
|
677
705
|
);
|
|
706
|
+
if (summary.notes.length > 0) {
|
|
707
|
+
sections.push(summary.notes.map((n) => chalk.dim(` ${n}`)).join("\n"));
|
|
708
|
+
}
|
|
678
709
|
if (sections.length === 0) {
|
|
679
710
|
return chalk.dim(" No open issues or PRs.");
|
|
680
711
|
}
|
|
@@ -736,7 +767,8 @@ function jsonBuzz(roleName, role, summary) {
|
|
|
736
767
|
implement: summary.implement,
|
|
737
768
|
reviewPRs: summary.reviewPRs,
|
|
738
769
|
addressFeedback: summary.addressFeedback,
|
|
739
|
-
alerts: summary.alerts
|
|
770
|
+
alerts: summary.alerts,
|
|
771
|
+
notes: summary.notes
|
|
740
772
|
}
|
|
741
773
|
},
|
|
742
774
|
null,
|
|
@@ -755,7 +787,8 @@ function jsonStatus(summary) {
|
|
|
755
787
|
implement: summary.implement,
|
|
756
788
|
reviewPRs: summary.reviewPRs,
|
|
757
789
|
addressFeedback: summary.addressFeedback,
|
|
758
|
-
alerts: summary.alerts
|
|
790
|
+
alerts: summary.alerts,
|
|
791
|
+
notes: summary.notes
|
|
759
792
|
},
|
|
760
793
|
null,
|
|
761
794
|
2
|
|
@@ -772,12 +805,19 @@ function jsonRoles(teamConfig) {
|
|
|
772
805
|
// src/commands/buzz.ts
|
|
773
806
|
async function buzzCommand(options) {
|
|
774
807
|
const repo = await resolveRepo(options.repo);
|
|
808
|
+
const fetchLimit = options.fetchLimit ?? 200;
|
|
775
809
|
const [issues, prs, currentUser] = await Promise.all([
|
|
776
|
-
fetchIssues(repo),
|
|
777
|
-
fetchPulls(repo),
|
|
810
|
+
fetchIssues(repo, fetchLimit),
|
|
811
|
+
fetchPulls(repo, fetchLimit),
|
|
778
812
|
fetchCurrentUser()
|
|
779
813
|
]);
|
|
780
814
|
const summary = buildSummary(repo, issues, prs, currentUser);
|
|
815
|
+
if (issues.length >= fetchLimit) {
|
|
816
|
+
summary.notes.push(`Only the first ${fetchLimit} issues were fetched. Use --fetch-limit to increase.`);
|
|
817
|
+
}
|
|
818
|
+
if (prs.length >= fetchLimit) {
|
|
819
|
+
summary.notes.push(`Only the first ${fetchLimit} PRs were fetched. Use --fetch-limit to increase.`);
|
|
820
|
+
}
|
|
781
821
|
if (options.role) {
|
|
782
822
|
const teamConfig = await loadTeamConfig(repo);
|
|
783
823
|
if (!Object.hasOwn(teamConfig.roles, options.role)) {
|
|
@@ -877,7 +917,7 @@ program.hook("preAction", () => {
|
|
|
877
917
|
setGhToken(token);
|
|
878
918
|
}
|
|
879
919
|
});
|
|
880
|
-
program.command("buzz").description("Get role instructions and repo work summary (omit --role for summary only)").option("--role <role>", "Role to assume (e.g. engineer, tech_lead)").option("--json", "Output as JSON").option("--limit <n>", "Max items per section", parseLimit).option("--repo <owner/repo>", "Target repository (default: detect from git)").action(buzzCommand);
|
|
920
|
+
program.command("buzz").description("Get role instructions and repo work summary (omit --role for summary only)").option("--role <role>", "Role to assume (e.g. engineer, tech_lead)").option("--json", "Output as JSON").option("--limit <n>", "Max items per section", parseLimit).option("--fetch-limit <n>", "Max issues/PRs to fetch from GitHub (default: 200)", parseLimit).option("--repo <owner/repo>", "Target repository (default: detect from git)").action(buzzCommand);
|
|
881
921
|
program.command("roles").description("List available roles from team config").option("--json", "Output as JSON").option("--repo <owner/repo>", "Target repository (default: detect from git)").action(rolesCommand);
|
|
882
922
|
program.command("init").description("Print a sample .github/hivemoot.yml template").action(initCommand);
|
|
883
923
|
program.exitOverride();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config/types.ts","../src/config/loader.ts","../src/github/client.ts","../src/github/repo.ts","../src/github/issues.ts","../src/github/pulls.ts","../src/github/user.ts","../src/summary/utils.ts","../src/summary/alerts.ts","../src/summary/builder.ts","../src/output/formatter.ts","../src/output/json.ts","../src/commands/buzz.ts","../src/commands/roles.ts","../src/commands/init.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { buzzCommand } from \"./commands/buzz.js\";\nimport { rolesCommand } from \"./commands/roles.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { CliError } from \"./config/types.js\";\nimport { setGhToken } from \"./github/client.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nfunction parseLimit(value: string): number {\n const n = parseInt(value, 10);\n if (isNaN(n) || n <= 0) {\n throw new InvalidArgumentError(\"Must be a positive integer.\");\n }\n return n;\n}\n\nconst program = new Command();\n\nprogram\n .name(\"hivemoot\")\n .description(\"CLI for Hivemoot agents — role instructions and repo work summaries\")\n .version(version)\n .option(\"--github-token <token>\", \"GitHub personal access token (or set GITHUB_TOKEN env var)\");\n\nprogram.hook(\"preAction\", () => {\n const token = program.opts().githubToken as string | undefined;\n if (token) {\n setGhToken(token);\n }\n});\n\nprogram\n .command(\"buzz\")\n .description(\"Get role instructions and repo work summary (omit --role for summary only)\")\n .option(\"--role <role>\", \"Role to assume (e.g. engineer, tech_lead)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--limit <n>\", \"Max items per section\", parseLimit)\n .option(\"--repo <owner/repo>\", \"Target repository (default: detect from git)\")\n .action(buzzCommand);\n\nprogram\n .command(\"roles\")\n .description(\"List available roles from team config\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--repo <owner/repo>\", \"Target repository (default: detect from git)\")\n .action(rolesCommand);\n\nprogram\n .command(\"init\")\n .description(\"Print a sample .github/hivemoot.yml template\")\n .action(initCommand);\n\n// Global error handler\nprogram.exitOverride();\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n if (err instanceof CliError) {\n // Check if parent command requested --json output\n const isJson = process.argv.includes(\"--json\");\n if (isJson) {\n console.log(JSON.stringify({ error: { code: err.code, message: err.message } }, null, 2));\n } else {\n console.error(`Error: ${err.message}`);\n }\n process.exit(err.exitCode);\n }\n\n // Commander exits for --help, --version, etc.\n if (err instanceof Error && \"exitCode\" in err) {\n const exitCode = (err as Error & { exitCode: number }).exitCode;\n process.exit(exitCode);\n }\n\n console.error(\"Unexpected error:\", err);\n process.exit(1);\n}\n","// ── YAML Config Types ──────────────────────────────────────────────\n\nexport interface RoleConfig {\n description: string;\n instructions: string;\n}\n\nexport interface TeamConfig {\n name?: string;\n roles: Record<string, RoleConfig>;\n}\n\nexport interface HivemootConfig {\n version?: number;\n governance?: unknown;\n team?: TeamConfig;\n}\n\n// ── GitHub Data Types ──────────────────────────────────────────────\n\nexport interface GitHubIssue {\n number: number;\n title: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n author: { login: string };\n comments: Array<{ createdAt: string }>;\n createdAt: string;\n updatedAt: string;\n url: string;\n}\n\nexport interface StatusCheck {\n context: string;\n state: string | undefined;\n conclusion: string | null;\n}\n\nexport interface PRReview {\n state: string;\n author: { login: string };\n}\n\nexport interface GitHubPR {\n number: number;\n title: string;\n state: string;\n author: { login: string };\n labels: Array<{ name: string }>;\n comments: Array<{ createdAt: string }>;\n reviews: PRReview[];\n createdAt: string;\n updatedAt: string;\n url: string;\n isDraft: boolean;\n reviewDecision: string;\n mergeable: string;\n statusCheckRollup: StatusCheck[] | null;\n closingIssuesReferences: Array<{ number: number }>;\n}\n\n// ── Repo Identity ──────────────────────────────────────────────────\n\nexport interface RepoRef {\n owner: string;\n repo: string;\n}\n\n// ── Summary Types ──────────────────────────────────────────────────\n\nexport interface SummaryItem {\n number: number;\n title: string;\n tags: string[];\n author: string;\n // Common fields\n comments: number;\n age: string; // \"today\" | \"1 day old\" | \"3 days old\"\n // Issue-specific\n assigned?: string; // comma-separated logins, or undefined (= unassigned)\n competingPRs?: number; // only on implement items with competing PRs\n // PR-specific\n status?: string; // \"waiting\" | \"approved\" | \"changes-requested\" | \"draft\"\n checks?: string | null; // \"passing\" | \"failing\" | \"pending\" | null\n mergeable?: string | null; // \"clean\" | \"conflicts\" | null\n approvals?: number;\n}\n\nexport interface Alert {\n icon: string;\n message: string;\n}\n\nexport interface RepoSummary {\n repo: RepoRef;\n currentUser: string;\n driveDiscussion: SummaryItem[];\n driveImplementation: SummaryItem[];\n voteOn: SummaryItem[];\n discuss: SummaryItem[];\n implement: SummaryItem[];\n reviewPRs: SummaryItem[];\n addressFeedback: SummaryItem[];\n alerts: Alert[];\n}\n\n// ── CLI Options ────────────────────────────────────────────────────\n\nexport interface BuzzOptions {\n role?: string;\n json?: boolean;\n limit?: number;\n repo?: string;\n}\n\nexport interface RolesOptions {\n json?: boolean;\n repo?: string;\n}\n\n// ── Error Types ────────────────────────────────────────────────────\n\nexport type ErrorCode =\n | \"GH_NOT_FOUND\"\n | \"GH_NOT_AUTHENTICATED\"\n | \"NOT_GIT_REPO\"\n | \"CONFIG_NOT_FOUND\"\n | \"NO_TEAM_CONFIG\"\n | \"ROLE_NOT_FOUND\"\n | \"INVALID_CONFIG\"\n | \"RATE_LIMITED\"\n | \"GH_ERROR\";\n\nexport class CliError extends Error {\n constructor(\n message: string,\n public readonly code: ErrorCode,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"CliError\";\n }\n}\n","import yaml from \"js-yaml\";\nimport { gh } from \"../github/client.js\";\nimport type { HivemootConfig, TeamConfig, RepoRef, RoleConfig } from \"./types.js\";\nimport { CliError } from \"./types.js\";\n\nconst ROLE_SLUG_RE = /^[a-z][a-z0-9_]{0,49}$/;\nconst MAX_DESCRIPTION_LENGTH = 500;\nconst MAX_INSTRUCTIONS_LENGTH = 10_000;\n\nfunction validateTeamConfig(raw: HivemootConfig): TeamConfig {\n if (!raw.team) {\n throw new CliError(\n \"No team config in .github/hivemoot.yml. Run: hivemoot init\",\n \"NO_TEAM_CONFIG\",\n 1,\n );\n }\n\n const { team } = raw;\n\n if (!team.roles || typeof team.roles !== \"object\" || Object.keys(team.roles).length === 0) {\n throw new CliError(\n \"Config error: team.roles must contain at least one role\",\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n const validatedRoles: Record<string, RoleConfig> = {};\n\n for (const [slug, role] of Object.entries(team.roles)) {\n if (!ROLE_SLUG_RE.test(slug)) {\n throw new CliError(\n `Config error: invalid role slug \"${slug}\" — must match /^[a-z][a-z0-9_]{0,49}$/`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof role !== \"object\" || role === null) {\n throw new CliError(\n `Config error: role \"${slug}\" must be an object`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n const r = role as unknown as Record<string, unknown>;\n\n if (typeof r.description !== \"string\" || r.description.length === 0) {\n throw new CliError(\n `Config error: role \"${slug}\" is missing a description`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (r.description.length > MAX_DESCRIPTION_LENGTH) {\n throw new CliError(\n `Config error: role \"${slug}\" description exceeds ${MAX_DESCRIPTION_LENGTH} characters`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof r.instructions !== \"string\" || r.instructions.length === 0) {\n throw new CliError(\n `Config error: role \"${slug}\" is missing instructions`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (r.instructions.length > MAX_INSTRUCTIONS_LENGTH) {\n throw new CliError(\n `Config error: role \"${slug}\" instructions exceeds ${MAX_INSTRUCTIONS_LENGTH} characters`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n validatedRoles[slug] = {\n description: r.description,\n instructions: r.instructions,\n };\n }\n\n return {\n name: typeof team.name === \"string\" ? team.name : undefined,\n roles: validatedRoles,\n };\n}\n\nexport async function loadTeamConfig(repo: RepoRef): Promise<TeamConfig> {\n let rawJson: string;\n\n try {\n rawJson = await gh([\n \"api\",\n `repos/${repo.owner}/${repo.repo}/contents/.github/hivemoot.yml`,\n ]);\n } catch (err) {\n if (err instanceof Error && /404|Not Found/i.test(err.message)) {\n throw new CliError(\n \"No .github/hivemoot.yml found. Run: hivemoot init\",\n \"CONFIG_NOT_FOUND\",\n 1,\n );\n }\n throw err;\n }\n\n let content: string;\n try {\n const parsed = JSON.parse(rawJson);\n content = Buffer.from(parsed.content, \"base64\").toString(\"utf-8\");\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : \"\";\n throw new CliError(\n `Config error: failed to decode .github/hivemoot.yml content${detail}`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n let config: HivemootConfig;\n try {\n config = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as HivemootConfig;\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : \"\";\n throw new CliError(\n `Config error: invalid YAML in .github/hivemoot.yml${detail}`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof config !== \"object\" || config === null) {\n throw new CliError(\n \"Config error: .github/hivemoot.yml must be a YAML object\",\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n return validateTeamConfig(config);\n}\n","import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport { CliError } from \"../config/types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nlet ghToken: string | undefined;\n\n/** Set the GitHub token used for all subsequent `gh` calls. */\nexport function setGhToken(token: string): void {\n ghToken = token;\n}\n\n/**\n * Execute a `gh` CLI command and return stdout.\n * All GitHub I/O goes through this single function.\n */\nexport async function gh(args: string[]): Promise<string> {\n try {\n const opts: { timeout: number; env?: NodeJS.ProcessEnv } = {\n timeout: 30_000,\n };\n if (ghToken) {\n opts.env = { ...process.env, GH_TOKEN: ghToken };\n }\n const { stdout } = await execFileAsync(\"gh\", args, opts);\n return stdout.trim();\n } catch (err: unknown) {\n const error = err as NodeJS.ErrnoException & {\n stderr?: string;\n code?: string | number;\n };\n\n if (error.code === \"ENOENT\") {\n throw new CliError(\n \"gh CLI not found. Install: https://cli.github.com\",\n \"GH_NOT_FOUND\",\n 2,\n );\n }\n\n const stderr = error.stderr ?? error.message ?? \"\";\n\n if (/gh auth login|not logged in|authentication required/i.test(stderr)) {\n throw new CliError(\n \"Not authenticated. Pass --github-token <token>, set GITHUB_TOKEN, or run: gh auth login\",\n \"GH_NOT_AUTHENTICATED\",\n 2,\n );\n }\n\n if (/rate.?limit|API rate limit/i.test(stderr)) {\n throw new CliError(\n \"GitHub rate limited. Try again later.\",\n \"RATE_LIMITED\",\n 3,\n );\n }\n\n throw new CliError(stderr || \"gh command failed\", \"GH_ERROR\", 1);\n }\n}\n","import { CliError, type RepoRef } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nconst GITHUB_NAME_RE = /^[a-zA-Z0-9._-]+$/;\n\nexport async function resolveRepo(repoFlag?: string): Promise<RepoRef> {\n if (repoFlag) {\n const parts = repoFlag.split(\"/\");\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n throw new CliError(\n `Invalid repo format: \"${repoFlag}\". Expected OWNER/REPO`,\n \"GH_ERROR\",\n 1,\n );\n }\n if (!GITHUB_NAME_RE.test(parts[0]) || !GITHUB_NAME_RE.test(parts[1])) {\n throw new CliError(\n `Invalid repo name: \"${repoFlag}\". Owner and repo must match ${GITHUB_NAME_RE}`,\n \"GH_ERROR\",\n 1,\n );\n }\n return { owner: parts[0], repo: parts[1] };\n }\n\n try {\n const json = await gh([\"repo\", \"view\", \"--json\", \"owner,name\"]);\n let data: { owner?: { login?: string } | string; name?: string };\n try {\n data = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse repo info from gh CLI. Use --repo OWNER/REPO\",\n \"GH_ERROR\",\n 1,\n );\n }\n // gh returns owner as an object { login: \"...\" } not a plain string\n const owner =\n typeof data.owner === \"object\" && data.owner !== null\n ? data.owner.login\n : data.owner;\n const name = data.name;\n if (typeof owner !== \"string\" || !owner || typeof name !== \"string\" || !name) {\n throw new CliError(\n \"Could not detect repo owner/name. Use --repo OWNER/REPO\",\n \"NOT_GIT_REPO\",\n 2,\n );\n }\n return { owner, repo: name };\n } catch (err) {\n if (err instanceof CliError) {\n throw err;\n }\n throw new CliError(\n \"Not in a git repository. Use --repo OWNER/REPO\",\n \"NOT_GIT_REPO\",\n 2,\n );\n }\n}\n","import type { GitHubIssue, RepoRef } from \"../config/types.js\";\nimport { CliError } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nexport async function fetchIssues(repo: RepoRef): Promise<GitHubIssue[]> {\n const json = await gh([\n \"issue\",\n \"list\",\n \"-R\",\n `${repo.owner}/${repo.repo}`,\n \"--state\",\n \"open\",\n \"--json\",\n \"number,title,labels,assignees,author,comments,createdAt,updatedAt,url\",\n \"--limit\",\n \"200\",\n ]);\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse issues response from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new CliError(\n \"Unexpected issues response format from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n return parsed as GitHubIssue[];\n}\n","import type { GitHubPR, RepoRef } from \"../config/types.js\";\nimport { CliError } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nexport async function fetchPulls(repo: RepoRef): Promise<GitHubPR[]> {\n const json = await gh([\n \"pr\",\n \"list\",\n \"-R\",\n `${repo.owner}/${repo.repo}`,\n \"--state\",\n \"open\",\n \"--json\",\n \"number,title,state,author,labels,comments,reviews,createdAt,updatedAt,url,isDraft,reviewDecision,mergeable,statusCheckRollup,closingIssuesReferences\",\n \"--limit\",\n \"200\",\n ]);\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse pull requests response from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new CliError(\n \"Unexpected pull requests response format from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n return parsed as GitHubPR[];\n}\n","import { gh } from \"./client.js\";\nimport { CliError } from \"../config/types.js\";\n\n/**\n * Return the login of the currently authenticated GitHub user.\n */\nexport async function fetchCurrentUser(): Promise<string> {\n const login = await gh([\"api\", \"user\", \"--jq\", \".login\"]);\n if (!login) {\n throw new CliError(\n \"Could not determine GitHub username. Pass --github-token <token>, set GITHUB_TOKEN, or run: gh auth login\",\n \"GH_NOT_AUTHENTICATED\",\n 2,\n );\n }\n return login;\n}\n","import type { GitHubPR } from \"../config/types.js\";\n\nexport function hasLabel(labels: Array<{ name: string }>, keyword: string): boolean {\n return labels.some((l) =>\n l.name.toLowerCase().split(/[:\\-_]/).some((seg) => seg === keyword),\n );\n}\n\nexport function hasExactLabel(labels: Array<{ name: string }>, labelName: string): boolean {\n return labels.some((l) => l.name.toLowerCase() === labelName.toLowerCase());\n}\n\nexport function daysSince(dateStr: string, now: Date): number {\n const diff = now.getTime() - new Date(dateStr).getTime();\n return Math.max(0, Math.floor(diff / (1000 * 60 * 60 * 24)));\n}\n\nexport function hasCIFailure(pr: GitHubPR): boolean {\n if (!pr.statusCheckRollup) return false;\n return pr.statusCheckRollup.some((check) => {\n const conclusion = check.conclusion?.toUpperCase();\n const state = check.state?.toUpperCase();\n return conclusion === \"FAILURE\" || state === \"FAILURE\";\n });\n}\n\n/**\n * Summarize all status checks into a single label.\n * Returns null when there are no checks to report.\n */\nexport function checkStatus(pr: GitHubPR): string | null {\n if (!pr.statusCheckRollup || pr.statusCheckRollup.length === 0) return null;\n\n const hasFailing = hasCIFailure(pr);\n if (hasFailing) return \"checks failing\";\n\n const hasPending = pr.statusCheckRollup.some((c) => {\n const s = c.state?.toUpperCase();\n return s === \"PENDING\" || s === \"QUEUED\" || s === \"IN_PROGRESS\";\n });\n if (hasPending) return \"checks pending\";\n\n return \"checks passing\";\n}\n\n/**\n * Return a merge-conflict label, or null if no conflict info.\n */\nexport function mergeStatus(pr: GitHubPR): string | null {\n if (pr.mergeable === \"CONFLICTING\") return \"has conflicts\";\n if (pr.mergeable === \"MERGEABLE\") return \"no conflicts\";\n return null;\n}\n\n/**\n * Count unique approvals (latest review per author).\n */\nexport function approvalCount(pr: GitHubPR): number {\n if (!pr.reviews || pr.reviews.length === 0) return 0;\n const latestByAuthor = new Map<string, string>();\n for (const review of pr.reviews) {\n latestByAuthor.set(review.author.login, review.state);\n }\n let count = 0;\n for (const state of latestByAuthor.values()) {\n if (state === \"APPROVED\") count++;\n }\n return count;\n}\n","import type { GitHubIssue, GitHubPR, Alert } from \"../config/types.js\";\nimport { hasLabel, hasExactLabel, daysSince, hasCIFailure } from \"./utils.js\";\n\nconst STALE_DISCUSSION_DAYS = 3;\nconst PR_WAITING_REVIEW_DAYS = 2;\n\nfunction lastCommentDate(issue: GitHubIssue): string | null {\n if (issue.comments.length === 0) return null;\n return issue.comments.reduce((latest, c) =>\n c.createdAt > latest.createdAt ? c : latest,\n ).createdAt;\n}\n\nexport function generateAlerts(\n issues: GitHubIssue[],\n prs: GitHubPR[],\n now: Date = new Date(),\n): Alert[] {\n const alerts: Alert[] = [];\n\n // Stale discussions: discuss-labeled issues with no recent comments\n for (const issue of issues) {\n if (!hasLabel(issue.labels, \"discuss\") && !hasExactLabel(issue.labels, \"phase:discussion\")) continue;\n const lastComment = lastCommentDate(issue);\n const referenceDate = lastComment ?? issue.createdAt;\n const days = daysSince(referenceDate, now);\n if (days >= STALE_DISCUSSION_DAYS) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `#${issue.number} in discussion ${days} days, no recent comments`,\n });\n }\n }\n\n // Issues needing human attention\n for (const issue of issues) {\n if (hasExactLabel(issue.labels, \"needs:human\")) {\n alerts.push({\n icon: \"\\ud83d\\uded1\",\n message: `#${issue.number} needs human attention`,\n });\n }\n }\n\n // Only PRs in the governance intake (with \"implementation\" label) generate attention items\n const intakePRs = prs.filter((pr) => hasExactLabel(pr.labels, \"implementation\"));\n\n // PRs waiting on review too long (skip approved/changes-requested/drafts)\n for (const pr of intakePRs) {\n if (pr.isDraft) continue;\n if (pr.reviewDecision === \"APPROVED\" || pr.reviewDecision === \"CHANGES_REQUESTED\") continue;\n const days = daysSince(pr.createdAt, now);\n if (days >= PR_WAITING_REVIEW_DAYS) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `PR #${pr.number} waiting on review ${days} days`,\n });\n }\n }\n\n // CI failures on non-draft PRs\n for (const pr of intakePRs) {\n if (pr.isDraft) continue;\n if (hasCIFailure(pr)) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `PR #${pr.number} has CI failures`,\n });\n }\n }\n\n return alerts;\n}\n","import type {\n GitHubIssue,\n GitHubPR,\n RepoRef,\n RepoSummary,\n SummaryItem,\n} from \"../config/types.js\";\nimport { generateAlerts } from \"./alerts.js\";\nimport { hasLabel, hasExactLabel, daysSince, hasCIFailure, checkStatus, mergeStatus, approvalCount } from \"./utils.js\";\n\nfunction timeAgo(dateStr: string, now: Date): string {\n const days = daysSince(dateStr, now);\n if (days === 0) return \"today\";\n if (days === 1) return \"1 day old\";\n return `${days} days old`;\n}\n\n/** Map verbose check labels to compact values for structured output. */\nfunction compactChecks(raw: string | null): string | null {\n if (raw === null) return null;\n if (raw === \"checks failing\") return \"failing\";\n if (raw === \"checks pending\") return \"pending\";\n if (raw === \"checks passing\") return \"passing\";\n return raw;\n}\n\n/** Map verbose merge labels to compact values for structured output. */\nfunction compactMergeable(raw: string | null): string | null {\n if (raw === null) return null;\n if (raw === \"has conflicts\") return \"conflicts\";\n if (raw === \"no conflicts\") return \"clean\";\n return raw;\n}\n\nfunction classifyIssue(\n issue: GitHubIssue,\n now: Date,\n): { bucket: \"voteOn\" | \"discuss\" | \"implement\" | \"needsHuman\"; item: SummaryItem } {\n const age = timeAgo(issue.createdAt, now);\n const assigned =\n issue.assignees.length > 0\n ? issue.assignees.map((a) => a.login).join(\", \")\n : undefined;\n\n const tags = issue.labels.map((l) => l.name);\n const author = issue.author.login;\n const comments = issue.comments.length;\n\n const base: SummaryItem = {\n number: issue.number,\n title: issue.title,\n tags,\n author,\n comments,\n age,\n };\n\n // Issues needing human attention are excluded from all actionable buckets\n if (hasExactLabel(issue.labels, \"needs:human\")) {\n return {\n bucket: \"needsHuman\",\n item: { ...base, assigned },\n };\n }\n\n // Bot governance labels (exact match)\n if (hasExactLabel(issue.labels, \"phase:voting\") || hasExactLabel(issue.labels, \"phase:extended-voting\")) {\n return { bucket: \"voteOn\", item: base };\n }\n if (hasExactLabel(issue.labels, \"phase:discussion\")) {\n return { bucket: \"discuss\", item: base };\n }\n if (hasExactLabel(issue.labels, \"phase:ready-to-implement\")) {\n return { bucket: \"implement\", item: { ...base, assigned } };\n }\n\n // Keyword fallback (repos without the bot)\n if (hasLabel(issue.labels, \"vote\")) {\n return { bucket: \"voteOn\", item: base };\n }\n if (hasLabel(issue.labels, \"discuss\")) {\n return { bucket: \"discuss\", item: base };\n }\n\n return {\n bucket: \"implement\",\n item: { ...base, assigned },\n };\n}\n\nfunction classifyPR(\n pr: GitHubPR,\n now: Date,\n): { bucket: \"reviewPRs\" | \"addressFeedback\"; item: SummaryItem } {\n const age = timeAgo(pr.createdAt, now);\n const tags = pr.labels.map((l) => l.name);\n const author = pr.author.login;\n const comments = pr.comments.length;\n const ciFailing = hasCIFailure(pr);\n const checks = compactChecks(checkStatus(pr));\n const merge = compactMergeable(mergeStatus(pr));\n const approvals = approvalCount(pr);\n\n if (pr.isDraft || ciFailing || pr.reviewDecision === \"CHANGES_REQUESTED\") {\n let status: string;\n if (pr.isDraft) status = \"draft\";\n else if (pr.reviewDecision === \"CHANGES_REQUESTED\") status = \"changes-requested\";\n else status = \"waiting\";\n\n return {\n bucket: \"addressFeedback\",\n item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge, approvals },\n };\n }\n\n const status = pr.reviewDecision === \"APPROVED\" ? \"approved\" : \"waiting\";\n\n return {\n bucket: \"reviewPRs\",\n item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge, approvals },\n };\n}\n\nfunction buildCompetitionMap(prs: GitHubPR[], currentUser: string): Map<number, number> {\n const map = new Map<number, number>();\n for (const pr of prs) {\n if (!hasLabel(pr.labels, \"implementation\")) continue;\n if (pr.author.login === currentUser) continue;\n for (const ref of pr.closingIssuesReferences) {\n map.set(ref.number, (map.get(ref.number) ?? 0) + 1);\n }\n }\n return map;\n}\n\nexport function buildSummary(\n repo: RepoRef,\n issues: GitHubIssue[],\n prs: GitHubPR[],\n currentUser: string,\n now: Date = new Date(),\n): RepoSummary {\n const voteOn: SummaryItem[] = [];\n const discuss: SummaryItem[] = [];\n const implement: SummaryItem[] = [];\n const reviewPRs: SummaryItem[] = [];\n const addressFeedback: SummaryItem[] = [];\n\n for (const issue of issues) {\n const { bucket, item } = classifyIssue(issue, now);\n if (bucket === \"voteOn\") voteOn.push(item);\n else if (bucket === \"discuss\") discuss.push(item);\n else if (bucket === \"implement\") implement.push(item);\n // \"needsHuman\" issues intentionally excluded from all buckets\n }\n\n // Annotate implement items with competing PR counts\n const competitionMap = buildCompetitionMap(prs, currentUser);\n for (const item of implement) {\n const count = competitionMap.get(item.number) ?? 0;\n if (count > 0) {\n item.competingPRs = count;\n }\n }\n\n for (const pr of prs) {\n const { bucket, item } = classifyPR(pr, now);\n if (bucket === \"reviewPRs\") reviewPRs.push(item);\n else addressFeedback.push(item);\n }\n\n const alerts = generateAlerts(issues, prs, now);\n\n // Extract authored items into \"drive\" buckets so the agent knows what it owns\n const driveDiscussion: SummaryItem[] = [];\n const driveImplementation: SummaryItem[] = [];\n\n const filteredDiscuss = discuss.filter((item) => {\n if (item.author === currentUser) { driveDiscussion.push(item); return false; }\n return true;\n });\n\n const filteredVoteOn = voteOn.filter((item) => {\n if (item.author === currentUser && item.tags.includes(\"phase:extended-voting\")) {\n driveDiscussion.push(item);\n return false;\n }\n return true;\n });\n\n const filteredReviewPRs = reviewPRs.filter((item) => {\n if (item.author === currentUser) { driveImplementation.push(item); return false; }\n return true;\n });\n\n const filteredAddressFeedback = addressFeedback.filter((item) => {\n if (item.author === currentUser) { driveImplementation.push(item); return false; }\n return true;\n });\n\n return {\n repo,\n currentUser,\n driveDiscussion,\n driveImplementation,\n voteOn: filteredVoteOn,\n discuss: filteredDiscuss,\n implement,\n reviewPRs: filteredReviewPRs,\n addressFeedback: filteredAddressFeedback,\n alerts,\n };\n}\n","import chalk from \"chalk\";\nimport type { RepoSummary, RoleConfig, SummaryItem, TeamConfig } from \"../config/types.js\";\n\nconst DIVIDER_WIDTH = 50;\n\n// Section types determine which metadata keys appear on the second line\ntype SectionType = \"vote\" | \"discuss\" | \"implement\" | \"reviewPRs\" | \"addressFeedback\" | \"driveDiscussion\" | \"driveImplementation\";\n\nfunction sectionDivider(title: string, count: number): string {\n const label = ` ${title} (${count}) `;\n const remaining = Math.max(0, DIVIDER_WIDTH - label.length - 2);\n return chalk.dim(\"──\") + chalk.bold(label) + chalk.dim(\"─\".repeat(remaining));\n}\n\nfunction formatTags(tags: string[]): string {\n if (tags.length === 0) return \"\";\n return \" \" + tags.map((t) => chalk.magenta(`[${t}]`)).join(\" \");\n}\n\nfunction kv(key: string, value: string | number): string {\n return `${key}: ${chalk.dim(String(value))}`;\n}\n\nfunction formatMeta(item: SummaryItem, sectionType: SectionType, currentUser: string): string {\n const isYou = item.author === currentUser;\n const authorVal = isYou ? chalk.green(`${item.author} (you)`) : chalk.dim(item.author);\n const parts: string[] = [`by: ${authorVal}`];\n\n if (sectionType === \"implement\") {\n parts.push(kv(\"assigned\", item.assigned ?? \"--\"));\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"age\", item.age));\n if (item.competingPRs !== undefined) {\n parts.push(kv(\"competing\", item.competingPRs));\n }\n } else if (sectionType === \"vote\" || sectionType === \"discuss\" || sectionType === \"driveDiscussion\") {\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"age\", item.age));\n } else {\n // PR sections: reviewPRs, addressFeedback, driveImplementation\n if (item.status !== undefined) parts.push(kv(\"status\", item.status));\n if (item.checks !== undefined && item.checks !== null) parts.push(kv(\"checks\", item.checks));\n if (item.mergeable !== undefined && item.mergeable !== null) parts.push(kv(\"merge\", item.mergeable));\n if (item.approvals !== undefined) parts.push(kv(\"approvals\", item.approvals));\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"age\", item.age));\n }\n\n return parts.join(\" \");\n}\n\nfunction formatItem(item: SummaryItem, currentUser: string, sectionType: SectionType): string {\n const isYou = item.author === currentUser;\n const prefix = isYou ? chalk.green(\"★\") : \" \";\n const num = chalk.cyan(`#${item.number}`);\n const tags = formatTags(item.tags);\n\n const titleLine = `${prefix} ${num} ${item.title}${tags}`;\n const metaLine = ` ${formatMeta(item, sectionType, currentUser)}`;\n\n return `${titleLine}\\n${metaLine}`;\n}\n\nfunction formatSection(\n title: string,\n items: SummaryItem[],\n currentUser: string,\n sectionType: SectionType,\n limit?: number,\n): string {\n if (items.length === 0) return \"\";\n\n const displayed = limit ? items.slice(0, limit) : items;\n const header = sectionDivider(title, items.length);\n const itemBlocks = displayed.map((item) => formatItem(item, currentUser, sectionType));\n\n const parts = [header, ...itemBlocks];\n\n if (limit && items.length > limit) {\n parts.push(chalk.dim(` ... and ${items.length - limit} more`));\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction formatSummaryBody(summary: RepoSummary, limit?: number): string {\n const u = summary.currentUser;\n const sections: string[] = [];\n\n // Attention items at the top\n if (summary.alerts.length > 0) {\n const alertLines = [\n sectionDivider(\"REQUIRES YOUR ATTENTION\", summary.alerts.length),\n ...summary.alerts.map((a) => ` ${a.icon} ${chalk.yellow(a.message)}`),\n ];\n sections.push(alertLines.join(\"\\n\"));\n }\n\n sections.push(\n ...[\n formatSection(\"DRIVE THE DISCUSSION\", summary.driveDiscussion, u, \"driveDiscussion\", limit),\n formatSection(\"DRIVE THE IMPLEMENTATION\", summary.driveImplementation, u, \"driveImplementation\", limit),\n formatSection(\"VOTE ON ISSUES\", summary.voteOn, u, \"vote\", limit),\n formatSection(\"DISCUSS ISSUES\", summary.discuss, u, \"discuss\", limit),\n formatSection(\"READY TO IMPLEMENT ISSUES\", summary.implement, u, \"implement\", limit),\n formatSection(\"REVIEW PRs\", summary.reviewPRs, u, \"reviewPRs\", limit),\n formatSection(\"ADDRESS FEEDBACK PRs\", summary.addressFeedback, u, \"addressFeedback\", limit),\n ].filter(Boolean),\n );\n\n if (sections.length === 0) {\n return chalk.dim(\" No open issues or PRs.\");\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nexport function formatBuzz(\n roleName: string,\n role: RoleConfig,\n summary: RepoSummary,\n limit?: number,\n): string {\n const lines = [\n chalk.bold(`ROLE: ${roleName}`) + ` — ${role.description}`,\n \"\",\n chalk.bold(\"INSTRUCTIONS:\"),\n role.instructions.trimEnd(),\n \"\",\n `You are working on ${chalk.bold(`${summary.repo.owner}/${summary.repo.repo}`)}, logged in as ${chalk.green(summary.currentUser)}`,\n \"\",\n formatSummaryBody(summary, limit),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function formatStatus(summary: RepoSummary, limit?: number): string {\n const lines = [\n `You are working on ${chalk.bold(`${summary.repo.owner}/${summary.repo.repo}`)}, logged in as ${chalk.green(summary.currentUser)}`,\n \"\",\n formatSummaryBody(summary, limit),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function formatRoles(teamConfig: TeamConfig, repoFullName: string): string {\n const nameLabel = teamConfig.name ? ` (${teamConfig.name})` : \"\";\n const lines = [\n chalk.bold(`ROLES — ${repoFullName}${nameLabel}`),\n \"\",\n ];\n\n const slugs = Object.keys(teamConfig.roles);\n const maxLen = Math.max(...slugs.map((s) => s.length));\n\n for (const slug of slugs) {\n const role = teamConfig.roles[slug];\n const padded = slug.padEnd(maxLen + 2);\n lines.push(` ${chalk.cyan(padded)}${role.description}`);\n }\n\n return lines.join(\"\\n\");\n}\n","import type { RepoSummary, RoleConfig, TeamConfig } from \"../config/types.js\";\n\nexport function jsonBuzz(\n roleName: string,\n role: RoleConfig,\n summary: RepoSummary,\n): string {\n return JSON.stringify(\n {\n role: {\n name: roleName,\n description: role.description,\n instructions: role.instructions,\n },\n summary: {\n repo: `${summary.repo.owner}/${summary.repo.repo}`,\n currentUser: summary.currentUser,\n driveDiscussion: summary.driveDiscussion,\n driveImplementation: summary.driveImplementation,\n voteOn: summary.voteOn,\n discuss: summary.discuss,\n implement: summary.implement,\n reviewPRs: summary.reviewPRs,\n addressFeedback: summary.addressFeedback,\n alerts: summary.alerts,\n },\n },\n null,\n 2,\n );\n}\n\nexport function jsonStatus(summary: RepoSummary): string {\n return JSON.stringify(\n {\n repo: `${summary.repo.owner}/${summary.repo.repo}`,\n currentUser: summary.currentUser,\n driveDiscussion: summary.driveDiscussion,\n driveImplementation: summary.driveImplementation,\n voteOn: summary.voteOn,\n discuss: summary.discuss,\n implement: summary.implement,\n reviewPRs: summary.reviewPRs,\n addressFeedback: summary.addressFeedback,\n alerts: summary.alerts,\n },\n null,\n 2,\n );\n}\n\nexport function jsonRoles(teamConfig: TeamConfig): string {\n const roles = Object.entries(teamConfig.roles).map(([slug, role]) => ({\n name: slug,\n description: role.description,\n }));\n\n return JSON.stringify({ roles }, null, 2);\n}\n","import { CliError, type BuzzOptions } from \"../config/types.js\";\nimport { loadTeamConfig } from \"../config/loader.js\";\nimport { resolveRepo } from \"../github/repo.js\";\nimport { fetchIssues } from \"../github/issues.js\";\nimport { fetchPulls } from \"../github/pulls.js\";\nimport { fetchCurrentUser } from \"../github/user.js\";\nimport { buildSummary } from \"../summary/builder.js\";\nimport { formatBuzz, formatStatus } from \"../output/formatter.js\";\nimport { jsonBuzz, jsonStatus } from \"../output/json.js\";\n\nexport async function buzzCommand(options: BuzzOptions): Promise<void> {\n const repo = await resolveRepo(options.repo);\n\n const [issues, prs, currentUser] = await Promise.all([\n fetchIssues(repo),\n fetchPulls(repo),\n fetchCurrentUser(),\n ]);\n\n const summary = buildSummary(repo, issues, prs, currentUser);\n\n if (options.role) {\n const teamConfig = await loadTeamConfig(repo);\n if (!Object.hasOwn(teamConfig.roles, options.role)) {\n const available = Object.keys(teamConfig.roles).join(\", \");\n throw new CliError(\n `Role '${options.role}' not found. Available: ${available}. Run: hivemoot roles`,\n \"ROLE_NOT_FOUND\",\n 1,\n );\n }\n const roleConfig = teamConfig.roles[options.role];\n\n if (options.json) {\n console.log(jsonBuzz(options.role, roleConfig, summary));\n } else {\n console.log(formatBuzz(options.role, roleConfig, summary, options.limit));\n }\n } else {\n if (options.json) {\n console.log(jsonStatus(summary));\n } else {\n console.log(formatStatus(summary, options.limit));\n }\n }\n}\n","import type { RolesOptions } from \"../config/types.js\";\nimport { loadTeamConfig } from \"../config/loader.js\";\nimport { resolveRepo } from \"../github/repo.js\";\nimport { formatRoles } from \"../output/formatter.js\";\nimport { jsonRoles } from \"../output/json.js\";\n\nexport async function rolesCommand(options: RolesOptions): Promise<void> {\n const repo = await resolveRepo(options.repo);\n const teamConfig = await loadTeamConfig(repo);\n\n if (options.json) {\n console.log(jsonRoles(teamConfig));\n } else {\n console.log(formatRoles(teamConfig, `${repo.owner}/${repo.repo}`));\n }\n}\n","export async function initCommand(): Promise<void> {\n const template = `# Hivemoot team configuration\n# Place this file at .github/hivemoot.yml in your repository.\n#\n# Roles define personas (who the agent is), not workflow.\n# Workflow details belong in .agent/skills/.\n\nteam:\n roles:\n pm:\n description: \"Product manager focused on user value and clarity\"\n instructions: |\n You think from the user's perspective.\n Evaluate ideas by the problem they solve and who benefits.\n Push for clear requirements and well-scoped proposals.\n Ask \"why does this matter?\" before \"how do we build it?\"\n\n engineer:\n description: \"Software engineer focused on clean implementation\"\n instructions: |\n You care about code quality, patterns, and maintainability.\n Favor simple, proven approaches over clever solutions.\n Write clean code with good test coverage.\n Build on existing conventions in the codebase.\n\n architect:\n description: \"Architect focused on system design and long-term health\"\n instructions: |\n You think about how pieces fit together.\n Evaluate proposals for scalability, consistency, and technical debt.\n Guard the system's boundaries and abstractions.\n Push back when short-term wins create long-term problems.\n\n qa:\n description: \"QA engineer focused on reliability and edge cases\"\n instructions: |\n You think about what can go wrong.\n Find edge cases, race conditions, and failure modes others miss.\n Push for thorough error handling and defensive design.\n Ask \"what happens when this fails?\" about everything.\n`;\n\n console.log(template);\n}\n"],"mappings":"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","names":["status","require"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config/types.ts","../src/config/loader.ts","../src/github/client.ts","../src/github/repo.ts","../src/github/issues.ts","../src/github/pulls.ts","../src/github/user.ts","../src/summary/utils.ts","../src/summary/alerts.ts","../src/summary/builder.ts","../src/output/formatter.ts","../src/output/json.ts","../src/commands/buzz.ts","../src/commands/roles.ts","../src/commands/init.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { buzzCommand } from \"./commands/buzz.js\";\nimport { rolesCommand } from \"./commands/roles.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { CliError } from \"./config/types.js\";\nimport { setGhToken } from \"./github/client.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nfunction parseLimit(value: string): number {\n const n = parseInt(value, 10);\n if (isNaN(n) || n <= 0) {\n throw new InvalidArgumentError(\"Must be a positive integer.\");\n }\n return n;\n}\n\nconst program = new Command();\n\nprogram\n .name(\"hivemoot\")\n .description(\"CLI for Hivemoot agents — role instructions and repo work summaries\")\n .version(version)\n .option(\"--github-token <token>\", \"GitHub personal access token (or set GITHUB_TOKEN env var)\");\n\nprogram.hook(\"preAction\", () => {\n const token = program.opts().githubToken as string | undefined;\n if (token) {\n setGhToken(token);\n }\n});\n\nprogram\n .command(\"buzz\")\n .description(\"Get role instructions and repo work summary (omit --role for summary only)\")\n .option(\"--role <role>\", \"Role to assume (e.g. engineer, tech_lead)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--limit <n>\", \"Max items per section\", parseLimit)\n .option(\"--fetch-limit <n>\", \"Max issues/PRs to fetch from GitHub (default: 200)\", parseLimit)\n .option(\"--repo <owner/repo>\", \"Target repository (default: detect from git)\")\n .action(buzzCommand);\n\nprogram\n .command(\"roles\")\n .description(\"List available roles from team config\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--repo <owner/repo>\", \"Target repository (default: detect from git)\")\n .action(rolesCommand);\n\nprogram\n .command(\"init\")\n .description(\"Print a sample .github/hivemoot.yml template\")\n .action(initCommand);\n\n// Global error handler\nprogram.exitOverride();\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n if (err instanceof CliError) {\n // Check if parent command requested --json output\n const isJson = process.argv.includes(\"--json\");\n if (isJson) {\n console.log(JSON.stringify({ error: { code: err.code, message: err.message } }, null, 2));\n } else {\n console.error(`Error: ${err.message}`);\n }\n process.exit(err.exitCode);\n }\n\n // Commander exits for --help, --version, etc.\n if (err instanceof Error && \"exitCode\" in err) {\n const exitCode = (err as Error & { exitCode: number }).exitCode;\n process.exit(exitCode);\n }\n\n console.error(\"Unexpected error:\", err);\n process.exit(1);\n}\n","// ── YAML Config Types ──────────────────────────────────────────────\n\nexport interface RoleConfig {\n description: string;\n instructions: string;\n}\n\nexport interface TeamConfig {\n name?: string;\n roles: Record<string, RoleConfig>;\n}\n\nexport interface HivemootConfig {\n version?: number;\n governance?: unknown;\n team?: TeamConfig;\n}\n\n// ── GitHub Data Types ──────────────────────────────────────────────\n\nexport interface GitHubIssue {\n number: number;\n title: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n author: { login: string } | null;\n comments: Array<{ createdAt: string }>;\n createdAt: string;\n updatedAt: string;\n url: string;\n}\n\nexport interface StatusCheck {\n context: string;\n state: string | undefined;\n conclusion: string | null;\n}\n\nexport interface PRReview {\n state: string;\n author: { login: string } | null;\n}\n\nexport interface GitHubPR {\n number: number;\n title: string;\n state: string;\n author: { login: string } | null;\n labels: Array<{ name: string }>;\n comments: Array<{ createdAt: string }>;\n reviews: PRReview[];\n createdAt: string;\n updatedAt: string;\n url: string;\n isDraft: boolean;\n reviewDecision: string;\n mergeable: string;\n statusCheckRollup: StatusCheck[] | null;\n closingIssuesReferences: Array<{ number: number }>;\n}\n\n// ── Repo Identity ──────────────────────────────────────────────────\n\nexport interface RepoRef {\n owner: string;\n repo: string;\n}\n\n// ── Summary Types ──────────────────────────────────────────────────\n\nexport interface ReviewSummary {\n approvals: number;\n changesRequested: number;\n}\n\nexport interface SummaryItem {\n number: number;\n title: string;\n tags: string[];\n author: string;\n // Common fields\n comments: number;\n age: string; // \"just now\" | \"5 minutes ago\" | \"2 hours ago\" | \"3 days ago\"\n // Issue-specific\n assigned?: string; // comma-separated logins, or undefined (= unassigned)\n competingPRs?: number; // only on implement items with competing PRs\n // PR-specific\n status?: string; // \"waiting\" | \"approved\" | \"changes-requested\" | \"draft\"\n checks?: string | null; // \"passing\" | \"failing\" | \"pending\" | null\n mergeable?: string | null; // \"clean\" | \"conflicts\" | null\n review?: ReviewSummary;\n}\n\nexport interface Alert {\n icon: string;\n message: string;\n}\n\nexport interface RepoSummary {\n repo: RepoRef;\n currentUser: string;\n driveDiscussion: SummaryItem[];\n driveImplementation: SummaryItem[];\n voteOn: SummaryItem[];\n discuss: SummaryItem[];\n implement: SummaryItem[];\n reviewPRs: SummaryItem[];\n addressFeedback: SummaryItem[];\n alerts: Alert[];\n notes: string[];\n}\n\n// ── CLI Options ────────────────────────────────────────────────────\n\nexport interface BuzzOptions {\n role?: string;\n json?: boolean;\n limit?: number;\n fetchLimit?: number;\n repo?: string;\n}\n\nexport interface RolesOptions {\n json?: boolean;\n repo?: string;\n}\n\n// ── Error Types ────────────────────────────────────────────────────\n\nexport type ErrorCode =\n | \"GH_NOT_FOUND\"\n | \"GH_NOT_AUTHENTICATED\"\n | \"NOT_GIT_REPO\"\n | \"CONFIG_NOT_FOUND\"\n | \"NO_TEAM_CONFIG\"\n | \"ROLE_NOT_FOUND\"\n | \"INVALID_CONFIG\"\n | \"RATE_LIMITED\"\n | \"GH_ERROR\";\n\nexport class CliError extends Error {\n constructor(\n message: string,\n public readonly code: ErrorCode,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"CliError\";\n }\n}\n","import yaml from \"js-yaml\";\nimport { gh } from \"../github/client.js\";\nimport type { HivemootConfig, TeamConfig, RepoRef, RoleConfig } from \"./types.js\";\nimport { CliError } from \"./types.js\";\n\nconst ROLE_SLUG_RE = /^[a-z][a-z0-9_]{0,49}$/;\nconst MAX_DESCRIPTION_LENGTH = 500;\nconst MAX_INSTRUCTIONS_LENGTH = 10_000;\n\nfunction validateTeamConfig(raw: HivemootConfig): TeamConfig {\n if (!raw.team) {\n throw new CliError(\n \"No team config in .github/hivemoot.yml. Run: hivemoot init\",\n \"NO_TEAM_CONFIG\",\n 1,\n );\n }\n\n const { team } = raw;\n\n if (!team.roles || typeof team.roles !== \"object\" || Object.keys(team.roles).length === 0) {\n throw new CliError(\n \"Config error: team.roles must contain at least one role\",\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n const validatedRoles: Record<string, RoleConfig> = {};\n\n for (const [slug, role] of Object.entries(team.roles)) {\n if (!ROLE_SLUG_RE.test(slug)) {\n throw new CliError(\n `Config error: invalid role slug \"${slug}\" — must match /^[a-z][a-z0-9_]{0,49}$/`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof role !== \"object\" || role === null) {\n throw new CliError(\n `Config error: role \"${slug}\" must be an object`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n const r = role as unknown as Record<string, unknown>;\n\n if (typeof r.description !== \"string\" || r.description.length === 0) {\n throw new CliError(\n `Config error: role \"${slug}\" is missing a description`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (r.description.length > MAX_DESCRIPTION_LENGTH) {\n throw new CliError(\n `Config error: role \"${slug}\" description exceeds ${MAX_DESCRIPTION_LENGTH} characters`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof r.instructions !== \"string\" || r.instructions.length === 0) {\n throw new CliError(\n `Config error: role \"${slug}\" is missing instructions`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (r.instructions.length > MAX_INSTRUCTIONS_LENGTH) {\n throw new CliError(\n `Config error: role \"${slug}\" instructions exceeds ${MAX_INSTRUCTIONS_LENGTH} characters`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n validatedRoles[slug] = {\n description: r.description,\n instructions: r.instructions,\n };\n }\n\n return {\n name: typeof team.name === \"string\" ? team.name : undefined,\n roles: validatedRoles,\n };\n}\n\nexport async function loadTeamConfig(repo: RepoRef): Promise<TeamConfig> {\n let rawJson: string;\n\n try {\n rawJson = await gh([\n \"api\",\n `repos/${repo.owner}/${repo.repo}/contents/.github/hivemoot.yml`,\n ]);\n } catch (err) {\n if (err instanceof Error && /404|Not Found/i.test(err.message)) {\n throw new CliError(\n \"No .github/hivemoot.yml found. Run: hivemoot init\",\n \"CONFIG_NOT_FOUND\",\n 1,\n );\n }\n throw err;\n }\n\n let content: string;\n try {\n const parsed = JSON.parse(rawJson);\n content = Buffer.from(parsed.content, \"base64\").toString(\"utf-8\");\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : \"\";\n throw new CliError(\n `Config error: failed to decode .github/hivemoot.yml content${detail}`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n let config: HivemootConfig;\n try {\n config = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as HivemootConfig;\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : \"\";\n throw new CliError(\n `Config error: invalid YAML in .github/hivemoot.yml${detail}`,\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n if (typeof config !== \"object\" || config === null) {\n throw new CliError(\n \"Config error: .github/hivemoot.yml must be a YAML object\",\n \"INVALID_CONFIG\",\n 1,\n );\n }\n\n return validateTeamConfig(config);\n}\n","import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport { CliError } from \"../config/types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nlet ghToken: string | undefined;\n\n/** Set the GitHub token used for all subsequent `gh` calls. */\nexport function setGhToken(token: string): void {\n ghToken = token;\n}\n\n/**\n * Execute a `gh` CLI command and return stdout.\n * All GitHub I/O goes through this single function.\n */\nexport async function gh(args: string[]): Promise<string> {\n try {\n const opts: { timeout: number; env?: NodeJS.ProcessEnv } = {\n timeout: 30_000,\n };\n if (ghToken) {\n opts.env = { ...process.env, GH_TOKEN: ghToken };\n }\n const { stdout } = await execFileAsync(\"gh\", args, opts);\n return stdout.trim();\n } catch (err: unknown) {\n const error = err as NodeJS.ErrnoException & {\n stderr?: string;\n code?: string | number;\n };\n\n if (error.code === \"ENOENT\") {\n throw new CliError(\n \"gh CLI not found. Install: https://cli.github.com\",\n \"GH_NOT_FOUND\",\n 2,\n );\n }\n\n const stderr = error.stderr ?? error.message ?? \"\";\n\n if (/gh auth login|not logged in|authentication required/i.test(stderr)) {\n throw new CliError(\n \"Not authenticated. Pass --github-token <token>, set GITHUB_TOKEN, or run: gh auth login\",\n \"GH_NOT_AUTHENTICATED\",\n 2,\n );\n }\n\n if (/rate.?limit|API rate limit/i.test(stderr)) {\n throw new CliError(\n \"GitHub rate limited. Try again later.\",\n \"RATE_LIMITED\",\n 3,\n );\n }\n\n throw new CliError(stderr || \"gh command failed\", \"GH_ERROR\", 1);\n }\n}\n","import { CliError, type RepoRef } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nconst GITHUB_NAME_RE = /^[a-zA-Z0-9._-]+$/;\n\nexport async function resolveRepo(repoFlag?: string): Promise<RepoRef> {\n if (repoFlag) {\n const parts = repoFlag.split(\"/\");\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n throw new CliError(\n `Invalid repo format: \"${repoFlag}\". Expected OWNER/REPO`,\n \"GH_ERROR\",\n 1,\n );\n }\n if (!GITHUB_NAME_RE.test(parts[0]) || !GITHUB_NAME_RE.test(parts[1])) {\n throw new CliError(\n `Invalid repo name: \"${repoFlag}\". Owner and repo must match ${GITHUB_NAME_RE}`,\n \"GH_ERROR\",\n 1,\n );\n }\n return { owner: parts[0], repo: parts[1] };\n }\n\n try {\n const json = await gh([\"repo\", \"view\", \"--json\", \"owner,name\"]);\n let data: { owner?: { login?: string } | string; name?: string };\n try {\n data = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse repo info from gh CLI. Use --repo OWNER/REPO\",\n \"GH_ERROR\",\n 1,\n );\n }\n // gh returns owner as an object { login: \"...\" } not a plain string\n const owner =\n typeof data.owner === \"object\" && data.owner !== null\n ? data.owner.login\n : data.owner;\n const name = data.name;\n if (typeof owner !== \"string\" || !owner || typeof name !== \"string\" || !name) {\n throw new CliError(\n \"Could not detect repo owner/name. Use --repo OWNER/REPO\",\n \"NOT_GIT_REPO\",\n 2,\n );\n }\n return { owner, repo: name };\n } catch (err) {\n if (err instanceof CliError) {\n throw err;\n }\n throw new CliError(\n \"Not in a git repository. Use --repo OWNER/REPO\",\n \"NOT_GIT_REPO\",\n 2,\n );\n }\n}\n","import type { GitHubIssue, RepoRef } from \"../config/types.js\";\nimport { CliError } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nexport async function fetchIssues(repo: RepoRef, limit = 200): Promise<GitHubIssue[]> {\n const json = await gh([\n \"issue\",\n \"list\",\n \"-R\",\n `${repo.owner}/${repo.repo}`,\n \"--state\",\n \"open\",\n \"--json\",\n \"number,title,labels,assignees,author,comments,createdAt,updatedAt,url\",\n \"--limit\",\n String(limit),\n ]);\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse issues response from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new CliError(\n \"Unexpected issues response format from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n return parsed as GitHubIssue[];\n}\n","import type { GitHubPR, RepoRef } from \"../config/types.js\";\nimport { CliError } from \"../config/types.js\";\nimport { gh } from \"./client.js\";\n\nexport async function fetchPulls(repo: RepoRef, limit = 200): Promise<GitHubPR[]> {\n const json = await gh([\n \"pr\",\n \"list\",\n \"-R\",\n `${repo.owner}/${repo.repo}`,\n \"--state\",\n \"open\",\n \"--json\",\n \"number,title,state,author,labels,comments,reviews,createdAt,updatedAt,url,isDraft,reviewDecision,mergeable,statusCheckRollup,closingIssuesReferences\",\n \"--limit\",\n String(limit),\n ]);\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n throw new CliError(\n \"Failed to parse pull requests response from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new CliError(\n \"Unexpected pull requests response format from gh CLI\",\n \"GH_ERROR\",\n 1,\n );\n }\n return parsed as GitHubPR[];\n}\n","import { gh } from \"./client.js\";\nimport { CliError } from \"../config/types.js\";\n\n/**\n * Return the login of the currently authenticated GitHub user.\n */\nexport async function fetchCurrentUser(): Promise<string> {\n const login = await gh([\"api\", \"user\", \"--jq\", \".login\"]);\n if (!login) {\n throw new CliError(\n \"Could not determine GitHub username. Pass --github-token <token>, set GITHUB_TOKEN, or run: gh auth login\",\n \"GH_NOT_AUTHENTICATED\",\n 2,\n );\n }\n return login;\n}\n","import type { GitHubPR } from \"../config/types.js\";\n\nexport function hasLabel(labels: Array<{ name: string }>, keyword: string): boolean {\n return labels.some((l) =>\n l.name.toLowerCase().split(/[:\\-_]/).some((seg) => seg === keyword),\n );\n}\n\nexport function hasExactLabel(labels: Array<{ name: string }>, labelName: string): boolean {\n return labels.some((l) => l.name.toLowerCase() === labelName.toLowerCase());\n}\n\n/** Human-relative time string (\"just now\", \"5 minutes ago\", \"yesterday\", etc.). */\nexport function timeAgo(dateStr: string, now: Date): string {\n const ms = now.getTime() - new Date(dateStr).getTime();\n if (ms < 0) return \"just now\"; // future date — clock skew or bad data\n\n const minutes = Math.floor(ms / 60_000);\n const hours = Math.floor(ms / 3_600_000);\n const days = Math.floor(ms / 86_400_000);\n\n if (minutes < 1) return \"just now\";\n if (minutes === 1) return \"1 minute ago\";\n if (minutes < 60) return `${minutes} minutes ago`;\n if (hours === 1) return \"1 hour ago\";\n if (hours < 24) return `${hours} hours ago`;\n if (days === 1) return \"yesterday\";\n if (days < 7) return `${days} days ago`;\n if (days < 14) return \"1 week ago\";\n if (days < 30) return `${Math.floor(days / 7)} weeks ago`;\n if (days < 60) return \"1 month ago\";\n if (days < 365) return `${Math.floor(days / 30)} months ago`;\n const years = Math.floor(days / 365);\n if (years === 1) return \"1 year ago\";\n return `${years} years ago`;\n}\n\nexport function daysSince(dateStr: string, now: Date): number {\n const diff = now.getTime() - new Date(dateStr).getTime();\n return Math.max(0, Math.floor(diff / (1000 * 60 * 60 * 24)));\n}\n\nexport function hasCIFailure(pr: GitHubPR): boolean {\n if (!pr.statusCheckRollup) return false;\n return pr.statusCheckRollup.some((check) => {\n const conclusion = check.conclusion?.toUpperCase();\n const state = check.state?.toUpperCase();\n return conclusion === \"FAILURE\" || state === \"FAILURE\";\n });\n}\n\n/**\n * Summarize all status checks into a single label.\n * Returns null when there are no checks to report.\n */\nexport function checkStatus(pr: GitHubPR): string | null {\n if (!pr.statusCheckRollup || pr.statusCheckRollup.length === 0) return null;\n\n const hasFailing = hasCIFailure(pr);\n if (hasFailing) return \"checks failing\";\n\n const hasPending = pr.statusCheckRollup.some((c) => {\n const s = c.state?.toUpperCase();\n return s === \"PENDING\" || s === \"QUEUED\" || s === \"IN_PROGRESS\";\n });\n if (hasPending) return \"checks pending\";\n\n return \"checks passing\";\n}\n\n/**\n * Return a merge-conflict label, or null if no conflict info.\n */\nexport function mergeStatus(pr: GitHubPR): string | null {\n if (pr.mergeable === \"CONFLICTING\") return \"has conflicts\";\n if (pr.mergeable === \"MERGEABLE\") return \"no conflicts\";\n return null;\n}\n\n/** Collapse reviews to the latest state per author. */\nfunction latestReviewByAuthor(pr: GitHubPR): Map<string, string> {\n const map = new Map<string, string>();\n for (const review of pr.reviews ?? []) {\n map.set(review.author?.login ?? \"ghost\", review.state);\n }\n return map;\n}\n\n/** Count unique approvals (latest review per author). */\nexport function approvalCount(pr: GitHubPR): number {\n let count = 0;\n for (const state of latestReviewByAuthor(pr).values()) {\n if (state === \"APPROVED\") count++;\n }\n return count;\n}\n\n/**\n * Count unique changes-requested reviews (latest review per author).\n * If an author requests changes then later approves, they are no longer counted.\n */\nexport function changesRequestedCount(pr: GitHubPR): number {\n let count = 0;\n for (const state of latestReviewByAuthor(pr).values()) {\n if (state === \"CHANGES_REQUESTED\") count++;\n }\n return count;\n}\n","import type { GitHubIssue, GitHubPR, Alert } from \"../config/types.js\";\nimport { hasLabel, hasExactLabel, daysSince, hasCIFailure } from \"./utils.js\";\n\nconst STALE_DISCUSSION_DAYS = 3;\nconst PR_WAITING_REVIEW_DAYS = 2;\n\nfunction lastCommentDate(issue: GitHubIssue): string | null {\n if (issue.comments.length === 0) return null;\n return issue.comments.reduce((latest, c) =>\n c.createdAt > latest.createdAt ? c : latest,\n ).createdAt;\n}\n\nexport function generateAlerts(\n issues: GitHubIssue[],\n prs: GitHubPR[],\n now: Date = new Date(),\n): Alert[] {\n const alerts: Alert[] = [];\n\n // Stale discussions: discuss-labeled issues with no recent comments\n for (const issue of issues) {\n if (!hasLabel(issue.labels, \"discuss\") && !hasExactLabel(issue.labels, \"phase:discussion\")) continue;\n const lastComment = lastCommentDate(issue);\n const referenceDate = lastComment ?? issue.createdAt;\n const days = daysSince(referenceDate, now);\n if (days >= STALE_DISCUSSION_DAYS) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `#${issue.number} in discussion ${days} days, no recent comments`,\n });\n }\n }\n\n // Issues needing human attention\n for (const issue of issues) {\n if (hasExactLabel(issue.labels, \"needs:human\")) {\n alerts.push({\n icon: \"\\ud83d\\uded1\",\n message: `#${issue.number} needs human attention`,\n });\n }\n }\n\n // Only PRs in the governance intake (with \"implementation\" label) generate attention items\n const intakePRs = prs.filter((pr) => hasExactLabel(pr.labels, \"implementation\"));\n\n // PRs waiting on review too long (skip approved/changes-requested/drafts)\n for (const pr of intakePRs) {\n if (pr.isDraft) continue;\n if (pr.reviewDecision === \"APPROVED\" || pr.reviewDecision === \"CHANGES_REQUESTED\") continue;\n const days = daysSince(pr.createdAt, now);\n if (days >= PR_WAITING_REVIEW_DAYS) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `PR #${pr.number} waiting on review ${days} days`,\n });\n }\n }\n\n // CI failures on non-draft PRs\n for (const pr of intakePRs) {\n if (pr.isDraft) continue;\n if (hasCIFailure(pr)) {\n alerts.push({\n icon: \"\\u26a0\\ufe0f\",\n message: `PR #${pr.number} has CI failures`,\n });\n }\n }\n\n return alerts;\n}\n","import type {\n GitHubIssue,\n GitHubPR,\n RepoRef,\n RepoSummary,\n SummaryItem,\n} from \"../config/types.js\";\nimport { generateAlerts } from \"./alerts.js\";\nimport { hasLabel, hasExactLabel, hasCIFailure, checkStatus, mergeStatus, approvalCount, changesRequestedCount, timeAgo } from \"./utils.js\";\n\n/** Map verbose check labels to compact values for structured output. */\nfunction compactChecks(raw: string | null): string | null {\n if (raw === null) return null;\n if (raw === \"checks failing\") return \"failing\";\n if (raw === \"checks pending\") return \"pending\";\n if (raw === \"checks passing\") return \"passing\";\n return raw;\n}\n\n/** Map verbose merge labels to compact values for structured output. */\nfunction compactMergeable(raw: string | null): string | null {\n if (raw === null) return null;\n if (raw === \"has conflicts\") return \"conflicts\";\n if (raw === \"no conflicts\") return \"clean\";\n return raw;\n}\n\nfunction classifyIssue(\n issue: GitHubIssue,\n now: Date,\n): { bucket: \"voteOn\" | \"discuss\" | \"implement\" | \"needsHuman\"; item: SummaryItem } {\n const age = timeAgo(issue.createdAt, now);\n const assigned =\n issue.assignees.length > 0\n ? issue.assignees.map((a) => a.login).join(\", \")\n : undefined;\n\n const tags = issue.labels.map((l) => l.name);\n const author = issue.author?.login ?? \"ghost\";\n const comments = issue.comments.length;\n\n const base: SummaryItem = {\n number: issue.number,\n title: issue.title,\n tags,\n author,\n comments,\n age,\n };\n\n // Issues needing human attention are excluded from all actionable buckets\n if (hasExactLabel(issue.labels, \"needs:human\")) {\n return {\n bucket: \"needsHuman\",\n item: { ...base, assigned },\n };\n }\n\n // Bot governance labels (exact match)\n if (hasExactLabel(issue.labels, \"phase:voting\") || hasExactLabel(issue.labels, \"phase:extended-voting\")) {\n return { bucket: \"voteOn\", item: base };\n }\n if (hasExactLabel(issue.labels, \"phase:discussion\")) {\n return { bucket: \"discuss\", item: base };\n }\n if (hasExactLabel(issue.labels, \"phase:ready-to-implement\")) {\n return { bucket: \"implement\", item: { ...base, assigned } };\n }\n\n // Keyword fallback (repos without the bot)\n if (hasLabel(issue.labels, \"vote\")) {\n return { bucket: \"voteOn\", item: base };\n }\n if (hasLabel(issue.labels, \"discuss\")) {\n return { bucket: \"discuss\", item: base };\n }\n\n return {\n bucket: \"implement\",\n item: { ...base, assigned },\n };\n}\n\nfunction classifyPR(\n pr: GitHubPR,\n now: Date,\n): { bucket: \"reviewPRs\" | \"addressFeedback\"; item: SummaryItem } {\n const age = timeAgo(pr.createdAt, now);\n const tags = pr.labels.map((l) => l.name);\n const author = pr.author?.login ?? \"ghost\";\n const comments = pr.comments.length;\n const ciFailing = hasCIFailure(pr);\n const checks = compactChecks(checkStatus(pr));\n const merge = compactMergeable(mergeStatus(pr));\n const review = {\n approvals: approvalCount(pr),\n changesRequested: changesRequestedCount(pr),\n };\n\n if (pr.isDraft || ciFailing || pr.reviewDecision === \"CHANGES_REQUESTED\") {\n let status: string;\n if (pr.isDraft) status = \"draft\";\n else if (pr.reviewDecision === \"CHANGES_REQUESTED\") status = \"changes-requested\";\n else status = \"waiting\";\n\n return {\n bucket: \"addressFeedback\",\n item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge, review },\n };\n }\n\n const status = pr.reviewDecision === \"APPROVED\" ? \"approved\" : \"waiting\";\n\n return {\n bucket: \"reviewPRs\",\n item: { number: pr.number, title: pr.title, tags, author, comments, age, status, checks, mergeable: merge, review },\n };\n}\n\nfunction buildCompetitionMap(prs: GitHubPR[], currentUser: string): Map<number, number> {\n const map = new Map<number, number>();\n for (const pr of prs) {\n if (!hasLabel(pr.labels, \"implementation\")) continue;\n if (pr.author?.login === currentUser) continue;\n for (const ref of pr.closingIssuesReferences) {\n map.set(ref.number, (map.get(ref.number) ?? 0) + 1);\n }\n }\n return map;\n}\n\nexport function buildSummary(\n repo: RepoRef,\n issues: GitHubIssue[],\n prs: GitHubPR[],\n currentUser: string,\n now: Date = new Date(),\n): RepoSummary {\n const voteOn: SummaryItem[] = [];\n const discuss: SummaryItem[] = [];\n const implement: SummaryItem[] = [];\n const reviewPRs: SummaryItem[] = [];\n const addressFeedback: SummaryItem[] = [];\n\n for (const issue of issues) {\n const { bucket, item } = classifyIssue(issue, now);\n if (bucket === \"voteOn\") voteOn.push(item);\n else if (bucket === \"discuss\") discuss.push(item);\n else if (bucket === \"implement\") implement.push(item);\n // \"needsHuman\" issues intentionally excluded from all buckets\n }\n\n // Annotate implement items with competing PR counts\n const competitionMap = buildCompetitionMap(prs, currentUser);\n for (const item of implement) {\n const count = competitionMap.get(item.number) ?? 0;\n if (count > 0) {\n item.competingPRs = count;\n }\n }\n\n for (const pr of prs) {\n const { bucket, item } = classifyPR(pr, now);\n if (bucket === \"reviewPRs\") reviewPRs.push(item);\n else addressFeedback.push(item);\n }\n\n const alerts = generateAlerts(issues, prs, now);\n\n // Extract authored items into \"drive\" buckets so the agent knows what it owns\n const driveDiscussion: SummaryItem[] = [];\n const driveImplementation: SummaryItem[] = [];\n\n const filteredDiscuss = discuss.filter((item) => {\n if (item.author === currentUser) { driveDiscussion.push(item); return false; }\n return true;\n });\n\n const filteredVoteOn = voteOn.filter((item) => {\n if (item.author === currentUser && item.tags.includes(\"phase:extended-voting\")) {\n driveDiscussion.push(item);\n return false;\n }\n return true;\n });\n\n const filteredReviewPRs = reviewPRs.filter((item) => {\n if (item.author === currentUser) { driveImplementation.push(item); return false; }\n return true;\n });\n\n const filteredAddressFeedback = addressFeedback.filter((item) => {\n if (item.author === currentUser) { driveImplementation.push(item); return false; }\n return true;\n });\n\n return {\n repo,\n currentUser,\n driveDiscussion,\n driveImplementation,\n voteOn: filteredVoteOn,\n discuss: filteredDiscuss,\n implement,\n reviewPRs: filteredReviewPRs,\n addressFeedback: filteredAddressFeedback,\n alerts,\n notes: [],\n };\n}\n","import chalk from \"chalk\";\nimport type { RepoSummary, RoleConfig, SummaryItem, TeamConfig } from \"../config/types.js\";\n\nconst DIVIDER_WIDTH = 50;\n\n// Section types determine which metadata keys appear on the second line\ntype SectionType = \"vote\" | \"discuss\" | \"implement\" | \"reviewPRs\" | \"addressFeedback\" | \"driveDiscussion\" | \"driveImplementation\";\n\nfunction sectionDivider(title: string, count: number): string {\n const label = ` ${title} (${count}) `;\n const remaining = Math.max(0, DIVIDER_WIDTH - label.length - 2);\n return chalk.dim(\"──\") + chalk.bold(label) + chalk.dim(\"─\".repeat(remaining));\n}\n\nfunction formatTags(tags: string[]): string {\n if (tags.length === 0) return \"\";\n return \" \" + tags.map((t) => chalk.magenta(`[${t}]`)).join(\" \");\n}\n\nfunction kv(key: string, value: string | number): string {\n return `${key}: ${chalk.dim(String(value))}`;\n}\n\nfunction formatMeta(item: SummaryItem, sectionType: SectionType, currentUser: string): string {\n const isYou = item.author === currentUser;\n const authorVal = isYou ? chalk.green(`${item.author} (you)`) : chalk.dim(item.author);\n const parts: string[] = [`by: ${authorVal}`];\n\n if (sectionType === \"implement\") {\n parts.push(kv(\"assigned\", item.assigned ?? \"--\"));\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"created\", item.age));\n if (item.competingPRs !== undefined) {\n parts.push(kv(\"competing\", item.competingPRs));\n }\n } else if (sectionType === \"vote\" || sectionType === \"discuss\" || sectionType === \"driveDiscussion\") {\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"created\", item.age));\n } else {\n // PR sections: reviewPRs, addressFeedback, driveImplementation\n if (item.status !== undefined) parts.push(kv(\"status\", item.status));\n if (item.checks !== undefined && item.checks !== null) parts.push(kv(\"checks\", item.checks));\n if (item.mergeable !== undefined && item.mergeable !== null) parts.push(kv(\"merge\", item.mergeable));\n if (item.review) parts.push(kv(\"review\", `${item.review.approvals} approved, ${item.review.changesRequested} changes-requested`));\n parts.push(kv(\"comments\", item.comments));\n parts.push(kv(\"created\", item.age));\n }\n\n return parts.join(\" \");\n}\n\nfunction formatItem(item: SummaryItem, currentUser: string, sectionType: SectionType): string {\n const isYou = item.author === currentUser;\n const prefix = isYou ? chalk.green(\"★\") : \" \";\n const num = chalk.cyan(`#${item.number}`);\n const tags = formatTags(item.tags);\n\n const titleLine = `${prefix} ${num} ${item.title}${tags}`;\n const metaLine = ` ${formatMeta(item, sectionType, currentUser)}`;\n\n return `${titleLine}\\n${metaLine}`;\n}\n\nfunction formatSection(\n title: string,\n items: SummaryItem[],\n currentUser: string,\n sectionType: SectionType,\n limit?: number,\n): string {\n if (items.length === 0) return \"\";\n\n const displayed = limit ? items.slice(0, limit) : items;\n const header = sectionDivider(title, items.length);\n const itemBlocks = displayed.map((item) => formatItem(item, currentUser, sectionType));\n\n const parts = [header, ...itemBlocks];\n\n if (limit && items.length > limit) {\n parts.push(chalk.dim(` ... and ${items.length - limit} more`));\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction formatSummaryBody(summary: RepoSummary, limit?: number): string {\n const u = summary.currentUser;\n const sections: string[] = [];\n\n // Attention items at the top\n if (summary.alerts.length > 0) {\n const alertLines = [\n sectionDivider(\"REQUIRES YOUR ATTENTION\", summary.alerts.length),\n ...summary.alerts.map((a) => ` ${a.icon} ${chalk.yellow(a.message)}`),\n ];\n sections.push(alertLines.join(\"\\n\"));\n }\n\n sections.push(\n ...[\n formatSection(\"DRIVE THE DISCUSSION\", summary.driveDiscussion, u, \"driveDiscussion\", limit),\n formatSection(\"DRIVE THE IMPLEMENTATION\", summary.driveImplementation, u, \"driveImplementation\", limit),\n formatSection(\"VOTE ON ISSUES\", summary.voteOn, u, \"vote\", limit),\n formatSection(\"DISCUSS ISSUES\", summary.discuss, u, \"discuss\", limit),\n formatSection(\"READY TO IMPLEMENT ISSUES\", summary.implement, u, \"implement\", limit),\n formatSection(\"REVIEW PRs\", summary.reviewPRs, u, \"reviewPRs\", limit),\n formatSection(\"ADDRESS FEEDBACK PRs\", summary.addressFeedback, u, \"addressFeedback\", limit),\n ].filter(Boolean),\n );\n\n if (summary.notes.length > 0) {\n sections.push(summary.notes.map((n) => chalk.dim(` ${n}`)).join(\"\\n\"));\n }\n\n if (sections.length === 0) {\n return chalk.dim(\" No open issues or PRs.\");\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nexport function formatBuzz(\n roleName: string,\n role: RoleConfig,\n summary: RepoSummary,\n limit?: number,\n): string {\n const lines = [\n chalk.bold(`ROLE: ${roleName}`) + ` — ${role.description}`,\n \"\",\n chalk.bold(\"INSTRUCTIONS:\"),\n role.instructions.trimEnd(),\n \"\",\n `You are working on ${chalk.bold(`${summary.repo.owner}/${summary.repo.repo}`)}, logged in as ${chalk.green(summary.currentUser)}`,\n \"\",\n formatSummaryBody(summary, limit),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function formatStatus(summary: RepoSummary, limit?: number): string {\n const lines = [\n `You are working on ${chalk.bold(`${summary.repo.owner}/${summary.repo.repo}`)}, logged in as ${chalk.green(summary.currentUser)}`,\n \"\",\n formatSummaryBody(summary, limit),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function formatRoles(teamConfig: TeamConfig, repoFullName: string): string {\n const nameLabel = teamConfig.name ? ` (${teamConfig.name})` : \"\";\n const lines = [\n chalk.bold(`ROLES — ${repoFullName}${nameLabel}`),\n \"\",\n ];\n\n const slugs = Object.keys(teamConfig.roles);\n const maxLen = Math.max(...slugs.map((s) => s.length));\n\n for (const slug of slugs) {\n const role = teamConfig.roles[slug];\n const padded = slug.padEnd(maxLen + 2);\n lines.push(` ${chalk.cyan(padded)}${role.description}`);\n }\n\n return lines.join(\"\\n\");\n}\n","import type { RepoSummary, RoleConfig, TeamConfig } from \"../config/types.js\";\n\nexport function jsonBuzz(\n roleName: string,\n role: RoleConfig,\n summary: RepoSummary,\n): string {\n return JSON.stringify(\n {\n role: {\n name: roleName,\n description: role.description,\n instructions: role.instructions,\n },\n summary: {\n repo: `${summary.repo.owner}/${summary.repo.repo}`,\n currentUser: summary.currentUser,\n driveDiscussion: summary.driveDiscussion,\n driveImplementation: summary.driveImplementation,\n voteOn: summary.voteOn,\n discuss: summary.discuss,\n implement: summary.implement,\n reviewPRs: summary.reviewPRs,\n addressFeedback: summary.addressFeedback,\n alerts: summary.alerts,\n notes: summary.notes,\n },\n },\n null,\n 2,\n );\n}\n\nexport function jsonStatus(summary: RepoSummary): string {\n return JSON.stringify(\n {\n repo: `${summary.repo.owner}/${summary.repo.repo}`,\n currentUser: summary.currentUser,\n driveDiscussion: summary.driveDiscussion,\n driveImplementation: summary.driveImplementation,\n voteOn: summary.voteOn,\n discuss: summary.discuss,\n implement: summary.implement,\n reviewPRs: summary.reviewPRs,\n addressFeedback: summary.addressFeedback,\n alerts: summary.alerts,\n notes: summary.notes,\n },\n null,\n 2,\n );\n}\n\nexport function jsonRoles(teamConfig: TeamConfig): string {\n const roles = Object.entries(teamConfig.roles).map(([slug, role]) => ({\n name: slug,\n description: role.description,\n }));\n\n return JSON.stringify({ roles }, null, 2);\n}\n","import { CliError, type BuzzOptions } from \"../config/types.js\";\nimport { loadTeamConfig } from \"../config/loader.js\";\nimport { resolveRepo } from \"../github/repo.js\";\nimport { fetchIssues } from \"../github/issues.js\";\nimport { fetchPulls } from \"../github/pulls.js\";\nimport { fetchCurrentUser } from \"../github/user.js\";\nimport { buildSummary } from \"../summary/builder.js\";\nimport { formatBuzz, formatStatus } from \"../output/formatter.js\";\nimport { jsonBuzz, jsonStatus } from \"../output/json.js\";\n\nexport async function buzzCommand(options: BuzzOptions): Promise<void> {\n const repo = await resolveRepo(options.repo);\n const fetchLimit = options.fetchLimit ?? 200;\n\n const [issues, prs, currentUser] = await Promise.all([\n fetchIssues(repo, fetchLimit),\n fetchPulls(repo, fetchLimit),\n fetchCurrentUser(),\n ]);\n\n const summary = buildSummary(repo, issues, prs, currentUser);\n\n if (issues.length >= fetchLimit) {\n summary.notes.push(`Only the first ${fetchLimit} issues were fetched. Use --fetch-limit to increase.`);\n }\n if (prs.length >= fetchLimit) {\n summary.notes.push(`Only the first ${fetchLimit} PRs were fetched. Use --fetch-limit to increase.`);\n }\n\n if (options.role) {\n const teamConfig = await loadTeamConfig(repo);\n if (!Object.hasOwn(teamConfig.roles, options.role)) {\n const available = Object.keys(teamConfig.roles).join(\", \");\n throw new CliError(\n `Role '${options.role}' not found. Available: ${available}. Run: hivemoot roles`,\n \"ROLE_NOT_FOUND\",\n 1,\n );\n }\n const roleConfig = teamConfig.roles[options.role];\n\n if (options.json) {\n console.log(jsonBuzz(options.role, roleConfig, summary));\n } else {\n console.log(formatBuzz(options.role, roleConfig, summary, options.limit));\n }\n } else {\n if (options.json) {\n console.log(jsonStatus(summary));\n } else {\n console.log(formatStatus(summary, options.limit));\n }\n }\n}\n","import type { RolesOptions } from \"../config/types.js\";\nimport { loadTeamConfig } from \"../config/loader.js\";\nimport { resolveRepo } from \"../github/repo.js\";\nimport { formatRoles } from \"../output/formatter.js\";\nimport { jsonRoles } from \"../output/json.js\";\n\nexport async function rolesCommand(options: RolesOptions): Promise<void> {\n const repo = await resolveRepo(options.repo);\n const teamConfig = await loadTeamConfig(repo);\n\n if (options.json) {\n console.log(jsonRoles(teamConfig));\n } else {\n console.log(formatRoles(teamConfig, `${repo.owner}/${repo.repo}`));\n }\n}\n","export async function initCommand(): Promise<void> {\n const template = `# Hivemoot team configuration\n# Place this file at .github/hivemoot.yml in your repository.\n#\n# Roles define personas (who the agent is), not workflow.\n# Workflow details belong in .agent/skills/.\n\nteam:\n roles:\n pm:\n description: \"Product manager focused on user value and clarity\"\n instructions: |\n You think from the user's perspective.\n Evaluate ideas by the problem they solve and who benefits.\n Push for clear requirements and well-scoped proposals.\n Ask \"why does this matter?\" before \"how do we build it?\"\n\n engineer:\n description: \"Software engineer focused on clean implementation\"\n instructions: |\n You care about code quality, patterns, and maintainability.\n Favor simple, proven approaches over clever solutions.\n Write clean code with good test coverage.\n Build on existing conventions in the codebase.\n\n architect:\n description: \"Architect focused on system design and long-term health\"\n instructions: |\n You think about how pieces fit together.\n Evaluate proposals for scalability, consistency, and technical debt.\n Guard the system's boundaries and abstractions.\n Push back when short-term wins create long-term problems.\n\n qa:\n description: \"QA engineer focused on reliability and edge cases\"\n instructions: |\n You think about what can go wrong.\n Find edge cases, race conditions, and failure modes others miss.\n Push for thorough error handling and defensive design.\n Ask \"what happens when this fails?\" about everything.\n`;\n\n console.log(template);\n}\n"],"mappings":"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","names":["status","require"]}
|