squads-cli 0.6.2 → 0.7.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 (112) hide show
  1. package/README.md +196 -1152
  2. package/dist/auth-YW3UPFSB.js +23 -0
  3. package/dist/autonomy-BWTVDEAT.js +102 -0
  4. package/dist/autonomy-BWTVDEAT.js.map +1 -0
  5. package/dist/chunk-3KCWNZWW.js +401 -0
  6. package/dist/chunk-3KCWNZWW.js.map +1 -0
  7. package/dist/chunk-67RO2HKR.js +174 -0
  8. package/dist/chunk-67RO2HKR.js.map +1 -0
  9. package/dist/chunk-7JVD7RD4.js +275 -0
  10. package/dist/chunk-7JVD7RD4.js.map +1 -0
  11. package/dist/chunk-BODLDQY7.js +452 -0
  12. package/dist/chunk-BODLDQY7.js.map +1 -0
  13. package/dist/chunk-FFFCFZ6A.js +121 -0
  14. package/dist/chunk-FFFCFZ6A.js.map +1 -0
  15. package/dist/chunk-FIWT2NMM.js +165 -0
  16. package/dist/chunk-FIWT2NMM.js.map +1 -0
  17. package/dist/chunk-L6GQCHDF.js +222 -0
  18. package/dist/chunk-L6GQCHDF.js.map +1 -0
  19. package/dist/{chunk-O7UV3FWI.js → chunk-LDM62TIX.js} +2 -2
  20. package/dist/chunk-LDM62TIX.js.map +1 -0
  21. package/dist/chunk-LOA3KWYJ.js +294 -0
  22. package/dist/chunk-LOA3KWYJ.js.map +1 -0
  23. package/dist/chunk-NA45DFXY.js +616 -0
  24. package/dist/chunk-NA45DFXY.js.map +1 -0
  25. package/dist/{chunk-4CMAEQQY.js → chunk-NQN6JPI7.js} +4 -3
  26. package/dist/chunk-NQN6JPI7.js.map +1 -0
  27. package/dist/chunk-OQJHPULO.js +103 -0
  28. package/dist/chunk-OQJHPULO.js.map +1 -0
  29. package/dist/chunk-QHNUMM4V.js +87 -0
  30. package/dist/chunk-QHNUMM4V.js.map +1 -0
  31. package/dist/chunk-RM6BWILN.js +74 -0
  32. package/dist/chunk-RM6BWILN.js.map +1 -0
  33. package/dist/chunk-WBR5J7EX.js +90 -0
  34. package/dist/chunk-WBR5J7EX.js.map +1 -0
  35. package/dist/chunk-Z2UKDBNL.js +162 -0
  36. package/dist/chunk-Z2UKDBNL.js.map +1 -0
  37. package/dist/cli.js +2136 -12600
  38. package/dist/cli.js.map +1 -1
  39. package/dist/context-M2A2DOFV.js +291 -0
  40. package/dist/context-M2A2DOFV.js.map +1 -0
  41. package/dist/context-feed-JMNW4GAM.js +391 -0
  42. package/dist/context-feed-JMNW4GAM.js.map +1 -0
  43. package/dist/cost-N37I4UTA.js +274 -0
  44. package/dist/cost-N37I4UTA.js.map +1 -0
  45. package/dist/create-554W5HNU.js +286 -0
  46. package/dist/create-554W5HNU.js.map +1 -0
  47. package/dist/daemon-XWPQPPPN.js +546 -0
  48. package/dist/daemon-XWPQPPPN.js.map +1 -0
  49. package/dist/dashboard-L7YKVQEB.js +945 -0
  50. package/dist/dashboard-L7YKVQEB.js.map +1 -0
  51. package/dist/dashboard-MFNRLCEE.js +794 -0
  52. package/dist/dashboard-MFNRLCEE.js.map +1 -0
  53. package/dist/doctor-RG75M5RO.js +346 -0
  54. package/dist/doctor-RG75M5RO.js.map +1 -0
  55. package/dist/env-config-KCLDBKYX.js +21 -0
  56. package/dist/exec-JQKBF7BL.js +197 -0
  57. package/dist/exec-JQKBF7BL.js.map +1 -0
  58. package/dist/feedback-KA2UYBZG.js +229 -0
  59. package/dist/feedback-KA2UYBZG.js.map +1 -0
  60. package/dist/github-UQTM5KMS.js +23 -0
  61. package/dist/goal-EOPC5ZCD.js +168 -0
  62. package/dist/goal-EOPC5ZCD.js.map +1 -0
  63. package/dist/health-3FZDOSR5.js +209 -0
  64. package/dist/health-3FZDOSR5.js.map +1 -0
  65. package/dist/history-TFVXJEDH.js +229 -0
  66. package/dist/history-TFVXJEDH.js.map +1 -0
  67. package/dist/index.js +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/init-UOWTNMIE.js +747 -0
  70. package/dist/init-UOWTNMIE.js.map +1 -0
  71. package/dist/kpi-2SQ2WCVT.js +413 -0
  72. package/dist/kpi-2SQ2WCVT.js.map +1 -0
  73. package/dist/learn-6ERTERAO.js +269 -0
  74. package/dist/learn-6ERTERAO.js.map +1 -0
  75. package/dist/list-KSOMUBMB.js +92 -0
  76. package/dist/list-KSOMUBMB.js.map +1 -0
  77. package/dist/login-ST6PAXYE.js +155 -0
  78. package/dist/login-ST6PAXYE.js.map +1 -0
  79. package/dist/memory-3CSNKXIL.js +562 -0
  80. package/dist/memory-3CSNKXIL.js.map +1 -0
  81. package/dist/progress-FKG4V2VH.js +202 -0
  82. package/dist/progress-FKG4V2VH.js.map +1 -0
  83. package/dist/providers-66PDCORB.js +65 -0
  84. package/dist/providers-66PDCORB.js.map +1 -0
  85. package/dist/results-2MJFLWEO.js +224 -0
  86. package/dist/results-2MJFLWEO.js.map +1 -0
  87. package/dist/run-72OQLH5A.js +2685 -0
  88. package/dist/run-72OQLH5A.js.map +1 -0
  89. package/dist/session-6H67XPAQ.js +64 -0
  90. package/dist/session-6H67XPAQ.js.map +1 -0
  91. package/dist/{chunk-NHGLXN2F.js → sessions-GVQIMN4W.js} +23 -459
  92. package/dist/sessions-GVQIMN4W.js.map +1 -0
  93. package/dist/{squad-parser-4BI3G4RS.js → squad-parser-CM3HOIWM.js} +2 -2
  94. package/dist/squad-parser-CM3HOIWM.js.map +1 -0
  95. package/dist/stats-ONZI557Q.js +335 -0
  96. package/dist/stats-ONZI557Q.js.map +1 -0
  97. package/dist/status-FYH42FTB.js +346 -0
  98. package/dist/status-FYH42FTB.js.map +1 -0
  99. package/dist/sync-HJZJNXHW.js +800 -0
  100. package/dist/sync-HJZJNXHW.js.map +1 -0
  101. package/dist/update-B4WMUOPO.js +83 -0
  102. package/dist/update-B4WMUOPO.js.map +1 -0
  103. package/dist/{update-ALJKFFM7.js → update-L7FGHN6W.js} +2 -2
  104. package/dist/update-L7FGHN6W.js.map +1 -0
  105. package/package.json +18 -10
  106. package/dist/chunk-4CMAEQQY.js.map +0 -1
  107. package/dist/chunk-NHGLXN2F.js.map +0 -1
  108. package/dist/chunk-O7UV3FWI.js.map +0 -1
  109. package/dist/sessions-6PB7ALCE.js +0 -16
  110. /package/dist/{sessions-6PB7ALCE.js.map → auth-YW3UPFSB.js.map} +0 -0
  111. /package/dist/{squad-parser-4BI3G4RS.js.map → env-config-KCLDBKYX.js.map} +0 -0
  112. /package/dist/{update-ALJKFFM7.js.map → github-UQTM5KMS.js.map} +0 -0
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ clearSession,
4
+ getEmailDomain,
5
+ isLoggedIn,
6
+ isPersonalEmail,
7
+ loadSession,
8
+ saveSession,
9
+ startAuthCallbackServer,
10
+ verifyToken
11
+ } from "./chunk-Z2UKDBNL.js";
12
+ import "./chunk-7OCVIDC7.js";
13
+ export {
14
+ clearSession,
15
+ getEmailDomain,
16
+ isLoggedIn,
17
+ isPersonalEmail,
18
+ loadSession,
19
+ saveSession,
20
+ startAuthCallbackServer,
21
+ verifyToken
22
+ };
23
+ //# sourceMappingURL=auth-YW3UPFSB.js.map
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Events,
4
+ track
5
+ } from "./chunk-L6GQCHDF.js";
6
+ import {
7
+ RESET,
8
+ bold,
9
+ colors,
10
+ gradient,
11
+ icons,
12
+ writeLine
13
+ } from "./chunk-N7KDWU4W.js";
14
+ import "./chunk-7OCVIDC7.js";
15
+
16
+ // src/commands/autonomy.ts
17
+ async function autonomyCommand(options = {}) {
18
+ const bridgeUrl = process.env.SQUADS_BRIDGE_URL || "http://localhost:8088";
19
+ const period = options.period || "today";
20
+ await track(Events.CLI_STATUS, { command: "autonomy", period, squad: options.squad });
21
+ try {
22
+ const params = new URLSearchParams({ period });
23
+ if (options.squad) params.append("squad", options.squad);
24
+ const response = await fetch(`${bridgeUrl}/api/autonomy/score?${params}`);
25
+ const data = await response.json();
26
+ if (options.json) {
27
+ console.log(JSON.stringify(data, null, 2));
28
+ return;
29
+ }
30
+ writeLine();
31
+ writeLine(` ${gradient("squads")} ${colors.dim}autonomy${RESET}`);
32
+ writeLine();
33
+ const score = data.overall_score;
34
+ const confidence = data.confidence_level;
35
+ const scoreColor = score >= 75 ? colors.green : score >= 50 ? colors.yellow : colors.red;
36
+ const confidenceIcon = confidence === "high" ? icons.success : confidence === "medium" ? icons.warning : icons.error;
37
+ writeLine(` ${bold}Overall Score${RESET} ${scoreColor}${score}%${RESET} ${confidenceIcon} ${confidence} confidence`);
38
+ writeLine();
39
+ const barWidth = 40;
40
+ const filled = Math.round(score / 100 * barWidth);
41
+ const bar = `${scoreColor}${"\u2588".repeat(filled)}${colors.dim}${"\u2591".repeat(barWidth - filled)}${RESET}`;
42
+ writeLine(` ${bar}`);
43
+ writeLine();
44
+ writeLine(` ${bold}Components${RESET}`);
45
+ writeLine();
46
+ const components = [
47
+ { name: "Quota Compliance", score: data.components.quota_compliance, weight: "25%" },
48
+ { name: "Success Rate", score: data.components.success_rate, weight: "25%" },
49
+ { name: "Quality Score", score: data.components.quality_score, weight: "20%" },
50
+ { name: "Cooldown Compliance", score: data.components.cooldown_compliance, weight: "15%" },
51
+ { name: "Learning Utilization", score: data.components.learning_utilization, weight: "15%" }
52
+ ];
53
+ for (const comp of components) {
54
+ const compColor = comp.score >= 75 ? colors.green : comp.score >= 50 ? colors.yellow : colors.red;
55
+ const compBar = `${compColor}${"\u2588".repeat(Math.round(comp.score / 5))}${colors.dim}${"\u2591".repeat(20 - Math.round(comp.score / 5))}${RESET}`;
56
+ writeLine(` ${comp.name.padEnd(22)} ${compBar} ${compColor}${comp.score}%${RESET} ${colors.dim}(${comp.weight})${RESET}`);
57
+ }
58
+ writeLine();
59
+ writeLine(` ${bold}Stats${RESET} ${colors.dim}(${period})${RESET}`);
60
+ writeLine();
61
+ writeLine(` ${colors.dim}Tasks:${RESET} ${data.execution_stats.successful_tasks}/${data.execution_stats.total_tasks} successful`);
62
+ writeLine(` ${colors.dim}Quota:${RESET} $${data.execution_stats.monthly_used}/$${data.execution_stats.monthly_quota}/mo (${data.execution_stats.quota_pct}%)`);
63
+ writeLine(` ${colors.dim}Learnings:${RESET} ${data.execution_stats.learning_count} captured`);
64
+ if (options.squad) {
65
+ writeLine(` ${colors.dim}Squad:${RESET} ${options.squad}`);
66
+ }
67
+ writeLine();
68
+ if (score < 75) {
69
+ writeLine(` ${bold}Recommendations${RESET}`);
70
+ writeLine();
71
+ if (data.components.learning_utilization < 50) {
72
+ writeLine(` ${icons.empty} Capture more learnings: ${colors.dim}squads learn "..."${RESET}`);
73
+ }
74
+ if (data.components.quality_score < 70) {
75
+ writeLine(` ${icons.empty} Add feedback after runs: ${colors.dim}squads feedback add <squad> <1-5>${RESET}`);
76
+ }
77
+ if (data.components.quota_compliance < 80) {
78
+ writeLine(` ${icons.empty} Approaching monthly quota limit - consider upgrading plan`);
79
+ }
80
+ if (data.execution_stats.total_tasks === 0) {
81
+ writeLine(` ${icons.empty} Run some agents: ${colors.dim}squads run <squad> --execute${RESET}`);
82
+ }
83
+ writeLine();
84
+ }
85
+ writeLine(` ${colors.dim}$${RESET} squads autonomy --period=week ${colors.dim}Weekly view${RESET}`);
86
+ writeLine(` ${colors.dim}$${RESET} squads memory sync --dimensions ${colors.dim}Sync to Postgres${RESET}`);
87
+ writeLine();
88
+ } catch (error) {
89
+ writeLine();
90
+ writeLine(` ${gradient("squads")} ${colors.dim}autonomy${RESET}`);
91
+ writeLine();
92
+ writeLine(` ${icons.error} ${colors.red}Failed to fetch autonomy score${RESET}`);
93
+ writeLine(` ${colors.dim}${error}${RESET}`);
94
+ writeLine();
95
+ writeLine(` ${colors.dim}Is the bridge running? Check: curl ${bridgeUrl}/health${RESET}`);
96
+ writeLine();
97
+ }
98
+ }
99
+ export {
100
+ autonomyCommand
101
+ };
102
+ //# sourceMappingURL=autonomy-BWTVDEAT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/autonomy.ts"],"sourcesContent":["import {\n colors,\n RESET,\n gradient,\n icons,\n writeLine,\n bold,\n} from '../lib/terminal.js';\nimport { track, Events } from '../lib/telemetry.js';\n\ninterface AutonomyOptions {\n squad?: string;\n period?: 'today' | 'week' | 'month';\n json?: boolean;\n}\n\ninterface AutonomyScore {\n overall_score: number;\n confidence_level: string;\n period: string;\n squad: string | null;\n components: {\n quota_compliance: number;\n cooldown_compliance: number;\n quality_score: number;\n success_rate: number;\n learning_utilization: number;\n };\n execution_stats: {\n total_tasks: number;\n successful_tasks: number;\n monthly_used: number;\n monthly_quota: number;\n quota_pct: number;\n learning_count: number;\n };\n error?: string;\n}\n\n/**\n * Display autonomy score and confidence metrics.\n * Shows how ready the system is for autonomous operation.\n */\nexport async function autonomyCommand(options: AutonomyOptions = {}): Promise<void> {\n const bridgeUrl = process.env.SQUADS_BRIDGE_URL || 'http://localhost:8088';\n const period = options.period || 'today';\n\n await track(Events.CLI_STATUS, { command: 'autonomy', period, squad: options.squad });\n\n try {\n const params = new URLSearchParams({ period });\n if (options.squad) params.append('squad', options.squad);\n\n const response = await fetch(`${bridgeUrl}/api/autonomy/score?${params}`);\n const data = await response.json() as AutonomyScore;\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}autonomy${RESET}`);\n writeLine();\n\n // Overall score with visual indicator\n const score = data.overall_score;\n const confidence = data.confidence_level;\n const scoreColor = score >= 75 ? colors.green : score >= 50 ? colors.yellow : colors.red;\n const confidenceIcon = confidence === 'high' ? icons.success : confidence === 'medium' ? icons.warning : icons.error;\n\n writeLine(` ${bold}Overall Score${RESET} ${scoreColor}${score}%${RESET} ${confidenceIcon} ${confidence} confidence`);\n writeLine();\n\n // Progress bar\n const barWidth = 40;\n const filled = Math.round((score / 100) * barWidth);\n const bar = `${scoreColor}${'█'.repeat(filled)}${colors.dim}${'░'.repeat(barWidth - filled)}${RESET}`;\n writeLine(` ${bar}`);\n writeLine();\n\n // Component scores\n writeLine(` ${bold}Components${RESET}`);\n writeLine();\n\n const components = [\n { name: 'Quota Compliance', score: data.components.quota_compliance, weight: '25%' },\n { name: 'Success Rate', score: data.components.success_rate, weight: '25%' },\n { name: 'Quality Score', score: data.components.quality_score, weight: '20%' },\n { name: 'Cooldown Compliance', score: data.components.cooldown_compliance, weight: '15%' },\n { name: 'Learning Utilization', score: data.components.learning_utilization, weight: '15%' },\n ];\n\n for (const comp of components) {\n const compColor = comp.score >= 75 ? colors.green : comp.score >= 50 ? colors.yellow : colors.red;\n const compBar = `${compColor}${'█'.repeat(Math.round(comp.score / 5))}${colors.dim}${'░'.repeat(20 - Math.round(comp.score / 5))}${RESET}`;\n writeLine(` ${comp.name.padEnd(22)} ${compBar} ${compColor}${comp.score}%${RESET} ${colors.dim}(${comp.weight})${RESET}`);\n }\n\n writeLine();\n\n // Execution stats\n writeLine(` ${bold}Stats${RESET} ${colors.dim}(${period})${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}Tasks:${RESET} ${data.execution_stats.successful_tasks}/${data.execution_stats.total_tasks} successful`);\n writeLine(` ${colors.dim}Quota:${RESET} $${data.execution_stats.monthly_used}/$${data.execution_stats.monthly_quota}/mo (${data.execution_stats.quota_pct}%)`);\n writeLine(` ${colors.dim}Learnings:${RESET} ${data.execution_stats.learning_count} captured`);\n\n if (options.squad) {\n writeLine(` ${colors.dim}Squad:${RESET} ${options.squad}`);\n }\n\n writeLine();\n\n // Recommendations\n if (score < 75) {\n writeLine(` ${bold}Recommendations${RESET}`);\n writeLine();\n\n if (data.components.learning_utilization < 50) {\n writeLine(` ${icons.empty} Capture more learnings: ${colors.dim}squads learn \"...\"${RESET}`);\n }\n if (data.components.quality_score < 70) {\n writeLine(` ${icons.empty} Add feedback after runs: ${colors.dim}squads feedback add <squad> <1-5>${RESET}`);\n }\n if (data.components.quota_compliance < 80) {\n writeLine(` ${icons.empty} Approaching monthly quota limit - consider upgrading plan`);\n }\n if (data.execution_stats.total_tasks === 0) {\n writeLine(` ${icons.empty} Run some agents: ${colors.dim}squads run <squad> --execute${RESET}`);\n }\n\n writeLine();\n }\n\n // Next steps\n writeLine(` ${colors.dim}$${RESET} squads autonomy --period=week ${colors.dim}Weekly view${RESET}`);\n writeLine(` ${colors.dim}$${RESET} squads memory sync --dimensions ${colors.dim}Sync to Postgres${RESET}`);\n writeLine();\n\n } catch (error) {\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}autonomy${RESET}`);\n writeLine();\n writeLine(` ${icons.error} ${colors.red}Failed to fetch autonomy score${RESET}`);\n writeLine(` ${colors.dim}${error}${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}Is the bridge running? Check: curl ${bridgeUrl}/health${RESET}`);\n writeLine();\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/git.ts
4
+ import { execSync, exec } from "child_process";
5
+ import { existsSync } from "fs";
6
+ import { join } from "path";
7
+ import { promisify } from "util";
8
+ var execAsync = promisify(exec);
9
+ function checkGitStatus(cwd = process.cwd()) {
10
+ const status = {
11
+ isGitRepo: false,
12
+ hasRemote: false,
13
+ isDirty: false,
14
+ uncommittedCount: 0
15
+ };
16
+ if (!existsSync(join(cwd, ".git"))) {
17
+ return status;
18
+ }
19
+ status.isGitRepo = true;
20
+ try {
21
+ const combined = execSync(
22
+ 'echo "BRANCH:" && git rev-parse --abbrev-ref HEAD && echo "REMOTES:" && git remote -v && echo "STATUS:" && git status --porcelain',
23
+ { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
24
+ );
25
+ const branchMatch = combined.match(/BRANCH:\n(.+)\n/);
26
+ if (branchMatch) {
27
+ status.branch = branchMatch[1].trim();
28
+ }
29
+ const remotesMatch = combined.match(/REMOTES:\n([\s\S]*?)STATUS:/);
30
+ if (remotesMatch) {
31
+ const remotes = remotesMatch[1].trim();
32
+ if (remotes) {
33
+ status.hasRemote = true;
34
+ const lines = remotes.split("\n");
35
+ if (lines.length > 0) {
36
+ const parts = lines[0].split(/\s+/);
37
+ status.remoteName = parts[0];
38
+ status.remoteUrl = parts[1];
39
+ }
40
+ }
41
+ }
42
+ const statusMatch = combined.match(/STATUS:\n([\s\S]*?)$/);
43
+ if (statusMatch) {
44
+ const statusOutput = statusMatch[1].trim();
45
+ if (statusOutput) {
46
+ status.isDirty = true;
47
+ status.uncommittedCount = statusOutput.split("\n").filter((l) => l.trim()).length;
48
+ }
49
+ }
50
+ } catch {
51
+ }
52
+ return status;
53
+ }
54
+ function getRepoName(remoteUrl) {
55
+ if (!remoteUrl) return null;
56
+ const match = remoteUrl.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
57
+ return match ? match[1] : null;
58
+ }
59
+ var SQUAD_REPOS = ["hq", "agents-squads-web", "squads-cli", "company", "product", "engineering", "research", "intelligence", "customer", "finance", "marketing"];
60
+ var SQUAD_REPO_MAP = {
61
+ website: ["agents-squads-web"],
62
+ product: ["squads-cli"],
63
+ engineering: ["hq", "squads-cli"],
64
+ research: ["research"],
65
+ intelligence: ["intelligence"],
66
+ customer: ["customer"],
67
+ finance: ["finance"],
68
+ company: ["company", "hq"],
69
+ marketing: ["marketing", "agents-squads-web"]
70
+ };
71
+ var SQUAD_LABELS = {
72
+ website: ["website", "web", "frontend", "ui"],
73
+ product: ["product", "cli", "feature"],
74
+ engineering: ["engineering", "infra", "backend", "bug"],
75
+ research: ["research", "analysis"],
76
+ intelligence: ["intel", "monitoring"],
77
+ customer: ["customer", "sales", "lead"],
78
+ finance: ["finance", "cost", "billing"],
79
+ company: ["company", "strategy"],
80
+ marketing: ["marketing", "content", "seo"]
81
+ };
82
+ function getGitHubStatsOptimized(basePath, days = 30) {
83
+ const stats = {
84
+ prsOpened: 0,
85
+ prsMerged: 0,
86
+ issuesClosed: 0,
87
+ issuesOpen: 0,
88
+ bySquad: /* @__PURE__ */ new Map()
89
+ };
90
+ for (const squad of Object.keys(SQUAD_REPO_MAP)) {
91
+ stats.bySquad.set(squad, {
92
+ prsOpened: 0,
93
+ prsMerged: 0,
94
+ issuesClosed: 0,
95
+ issuesOpen: 0,
96
+ commits: 0,
97
+ recentIssues: [],
98
+ recentPRs: []
99
+ });
100
+ }
101
+ const repos = ["hq", "agents-squads-web"];
102
+ const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
103
+ const results = [];
104
+ for (const repo of repos) {
105
+ const repoPath = join(basePath, repo);
106
+ if (!existsSync(repoPath)) continue;
107
+ try {
108
+ const output = execSync(
109
+ `echo '{"prs":' && gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null && echo ',"issues":' && gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null && echo '}'`,
110
+ { cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
111
+ );
112
+ const prsMatch = output.match(/"prs":(\[.*?\]),"issues":/s);
113
+ const issuesMatch = output.match(/"issues":(\[.*?\])\s*\}/s);
114
+ const prs = prsMatch ? JSON.parse(prsMatch[1]) : [];
115
+ const issues = issuesMatch ? JSON.parse(issuesMatch[1]) : [];
116
+ results.push({ repo, prs, issues });
117
+ } catch {
118
+ try {
119
+ const prsOutput = execSync(
120
+ `gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null`,
121
+ { cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
122
+ );
123
+ const issuesOutput = execSync(
124
+ `gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null`,
125
+ { cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
126
+ );
127
+ results.push({
128
+ repo,
129
+ prs: JSON.parse(prsOutput || "[]"),
130
+ issues: JSON.parse(issuesOutput || "[]")
131
+ });
132
+ } catch {
133
+ }
134
+ }
135
+ }
136
+ for (const { repo, prs, issues } of results) {
137
+ for (const pr of prs) {
138
+ const created = new Date(pr.createdAt);
139
+ if (created < new Date(since)) continue;
140
+ stats.prsOpened++;
141
+ if (pr.mergedAt) stats.prsMerged++;
142
+ const squad = detectSquadFromPR(pr, repo);
143
+ const squadStats = stats.bySquad.get(squad);
144
+ if (squadStats) {
145
+ squadStats.prsOpened++;
146
+ if (pr.mergedAt) squadStats.prsMerged++;
147
+ if (squadStats.recentPRs.length < 3) {
148
+ squadStats.recentPRs.push({
149
+ title: pr.title,
150
+ number: pr.number,
151
+ merged: !!pr.mergedAt
152
+ });
153
+ }
154
+ }
155
+ }
156
+ for (const issue of issues) {
157
+ const squad = detectSquadFromIssue(issue, repo);
158
+ const squadStats = stats.bySquad.get(squad);
159
+ if (issue.state === "CLOSED") {
160
+ const closed = new Date(issue.closedAt || 0);
161
+ if (closed >= new Date(since)) {
162
+ stats.issuesClosed++;
163
+ if (squadStats) {
164
+ squadStats.issuesClosed++;
165
+ }
166
+ }
167
+ } else {
168
+ stats.issuesOpen++;
169
+ if (squadStats) {
170
+ squadStats.issuesOpen++;
171
+ if (squadStats.recentIssues.length < 3) {
172
+ squadStats.recentIssues.push({
173
+ title: issue.title,
174
+ number: issue.number,
175
+ state: issue.state
176
+ });
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ return stats;
183
+ }
184
+ function detectSquadFromPR(pr, repo) {
185
+ for (const label of pr.labels || []) {
186
+ const labelLower = label.name.toLowerCase();
187
+ for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {
188
+ if (patterns.some((p) => labelLower.includes(p))) {
189
+ return squad;
190
+ }
191
+ }
192
+ }
193
+ const titleLower = pr.title.toLowerCase();
194
+ for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {
195
+ if (patterns.some((p) => titleLower.includes(p))) {
196
+ return squad;
197
+ }
198
+ }
199
+ if (repo === "agents-squads-web") return "website";
200
+ if (repo === "squads-cli") return "product";
201
+ return "engineering";
202
+ }
203
+ function detectSquadFromIssue(issue, repo) {
204
+ for (const label of issue.labels || []) {
205
+ const labelLower = label.name.toLowerCase();
206
+ if (labelLower.startsWith("squad:")) {
207
+ return labelLower.replace("squad:", "");
208
+ }
209
+ for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {
210
+ if (patterns.some((p) => labelLower.includes(p))) {
211
+ return squad;
212
+ }
213
+ }
214
+ }
215
+ const titleLower = issue.title.toLowerCase();
216
+ for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {
217
+ if (patterns.some((p) => titleLower.includes(p))) {
218
+ return squad;
219
+ }
220
+ }
221
+ if (repo === "agents-squads-web") return "website";
222
+ if (repo === "squads-cli") return "product";
223
+ return "engineering";
224
+ }
225
+ async function getMultiRepoGitStats(basePath, days = 30) {
226
+ const stats = {
227
+ totalCommits: 0,
228
+ commitsByDay: /* @__PURE__ */ new Map(),
229
+ commitsByAuthor: /* @__PURE__ */ new Map(),
230
+ commitsByRepo: /* @__PURE__ */ new Map(),
231
+ activeDays: 0,
232
+ avgCommitsPerDay: 0,
233
+ peakDay: null,
234
+ repos: [],
235
+ recentCommits: []
236
+ };
237
+ const allCommits = [];
238
+ const validRepos = SQUAD_REPOS.filter((repo) => {
239
+ const repoPath = join(basePath, repo);
240
+ return existsSync(repoPath) && existsSync(join(repoPath, ".git"));
241
+ });
242
+ const repoResults = await Promise.all(
243
+ validRepos.map(async (repo) => {
244
+ const repoPath = join(basePath, repo);
245
+ try {
246
+ const { stdout } = await execAsync(
247
+ `git log --since="${days} days ago" --format="%H|%aN|%ad|%s" --date=short 2>/dev/null`,
248
+ { cwd: repoPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
249
+ );
250
+ return { repo, repoPath, output: stdout.trim() };
251
+ } catch {
252
+ return { repo, repoPath, output: "" };
253
+ }
254
+ })
255
+ );
256
+ for (const { repo, repoPath, output } of repoResults) {
257
+ if (!output) continue;
258
+ const commits = output.split("\n").filter((l) => l.trim());
259
+ const authors = /* @__PURE__ */ new Set();
260
+ let lastCommit = "";
261
+ for (const line of commits) {
262
+ const parts = line.split("|");
263
+ const [hash, author, date, ...messageParts] = parts;
264
+ const message = messageParts.join("|");
265
+ if (!hash) continue;
266
+ stats.totalCommits++;
267
+ authors.add(author);
268
+ if (!lastCommit) lastCommit = date;
269
+ const dayCount = stats.commitsByDay.get(date) || 0;
270
+ stats.commitsByDay.set(date, dayCount + 1);
271
+ const authorCount = stats.commitsByAuthor.get(author) || 0;
272
+ stats.commitsByAuthor.set(author, authorCount + 1);
273
+ const repoCount = stats.commitsByRepo.get(repo) || 0;
274
+ stats.commitsByRepo.set(repo, repoCount + 1);
275
+ allCommits.push({ hash, author, date, message, repo });
276
+ }
277
+ stats.repos.push({
278
+ name: repo,
279
+ path: repoPath,
280
+ commits: commits.length,
281
+ lastCommit,
282
+ authors: Array.from(authors)
283
+ });
284
+ }
285
+ stats.activeDays = stats.commitsByDay.size;
286
+ stats.avgCommitsPerDay = stats.activeDays > 0 ? Math.round(stats.totalCommits / days * 10) / 10 : 0;
287
+ let peakCount = 0;
288
+ let peakDate = "";
289
+ for (const [date, count] of stats.commitsByDay) {
290
+ if (count > peakCount) {
291
+ peakCount = count;
292
+ peakDate = date;
293
+ }
294
+ }
295
+ if (peakDate) {
296
+ stats.peakDay = { date: peakDate, count: peakCount };
297
+ }
298
+ stats.recentCommits = allCommits.sort((a, b) => b.date.localeCompare(a.date) || b.hash.localeCompare(a.hash)).slice(0, 5);
299
+ return stats;
300
+ }
301
+ function fetchOperationalStatus(repos) {
302
+ const result = { milestones: [], openPRs: [], error: null };
303
+ if (repos.length === 0) {
304
+ return result;
305
+ }
306
+ try {
307
+ execSync("gh auth status 2>/dev/null", { stdio: "pipe", timeout: 3e3 });
308
+ } catch {
309
+ result.error = "gh not authenticated";
310
+ return result;
311
+ }
312
+ for (const fullRepo of repos) {
313
+ const repoShort = fullRepo.split("/").pop() || fullRepo;
314
+ try {
315
+ const msOutput = execSync(
316
+ `gh api "repos/${fullRepo}/milestones?state=open" --jq '.[] | [.title, .open_issues, .closed_issues, .due_on] | @tsv' 2>/dev/null`,
317
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 8e3 }
318
+ ).trim();
319
+ for (const line of msOutput.split("\n").filter((l) => l.trim())) {
320
+ const [title, open, closed, dueOn] = line.split(" ");
321
+ const openIssues = parseInt(open) || 0;
322
+ const closedIssues = parseInt(closed) || 0;
323
+ const totalIssues = openIssues + closedIssues;
324
+ result.milestones.push({
325
+ repo: repoShort,
326
+ title,
327
+ openIssues,
328
+ closedIssues,
329
+ totalIssues,
330
+ percent: totalIssues > 0 ? Math.floor(closedIssues / totalIssues * 100) : 0,
331
+ dueOn: dueOn && dueOn !== "null" ? dueOn : null
332
+ });
333
+ }
334
+ } catch {
335
+ }
336
+ try {
337
+ const prOutput = execSync(
338
+ `gh pr list --repo "${fullRepo}" --state open --json number,title,baseRefName --jq '.[] | [.number, .baseRefName, .title] | @tsv' 2>/dev/null`,
339
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 8e3 }
340
+ ).trim();
341
+ for (const line of prOutput.split("\n").filter((l) => l.trim())) {
342
+ const [num, base, ...titleParts] = line.split(" ");
343
+ result.openPRs.push({
344
+ repo: repoShort,
345
+ number: parseInt(num) || 0,
346
+ title: titleParts.join(" "),
347
+ base
348
+ });
349
+ }
350
+ } catch {
351
+ }
352
+ }
353
+ return result;
354
+ }
355
+ async function getActivitySparkline(basePath, days = 7) {
356
+ const activity = [];
357
+ const now = /* @__PURE__ */ new Date();
358
+ for (let i = days - 1; i >= 0; i--) {
359
+ activity.push(0);
360
+ }
361
+ const validRepos = SQUAD_REPOS.filter((repo) => {
362
+ const repoPath = join(basePath, repo);
363
+ return existsSync(repoPath) && existsSync(join(repoPath, ".git"));
364
+ });
365
+ const results = await Promise.all(
366
+ validRepos.map(async (repo) => {
367
+ const repoPath = join(basePath, repo);
368
+ try {
369
+ const { stdout } = await execAsync(
370
+ `git log --since="${days} days ago" --format="%ad" --date=short 2>/dev/null`,
371
+ { cwd: repoPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
372
+ );
373
+ return stdout.trim();
374
+ } catch {
375
+ return "";
376
+ }
377
+ })
378
+ );
379
+ for (const output of results) {
380
+ if (!output) continue;
381
+ for (const dateStr of output.split("\n")) {
382
+ const commitDate = new Date(dateStr);
383
+ const daysAgo = Math.floor((now.getTime() - commitDate.getTime()) / (1e3 * 60 * 60 * 24));
384
+ const index = days - 1 - daysAgo;
385
+ if (index >= 0 && index < days) {
386
+ activity[index]++;
387
+ }
388
+ }
389
+ }
390
+ return activity;
391
+ }
392
+
393
+ export {
394
+ checkGitStatus,
395
+ getRepoName,
396
+ getGitHubStatsOptimized,
397
+ getMultiRepoGitStats,
398
+ fetchOperationalStatus,
399
+ getActivitySparkline
400
+ };
401
+ //# sourceMappingURL=chunk-3KCWNZWW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/git.ts"],"sourcesContent":["import { execSync, exec } from 'child_process';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\nexport interface GitStatus {\n isGitRepo: boolean;\n hasRemote: boolean;\n remoteName?: string;\n remoteUrl?: string;\n branch?: string;\n isDirty: boolean;\n uncommittedCount: number;\n}\n\n/**\n * Check git status - synchronous version for backwards compatibility\n */\nexport function checkGitStatus(cwd: string = process.cwd()): GitStatus {\n const status: GitStatus = {\n isGitRepo: false,\n hasRemote: false,\n isDirty: false,\n uncommittedCount: 0,\n };\n\n // Check if .git directory exists\n if (!existsSync(join(cwd, '.git'))) {\n return status;\n }\n\n status.isGitRepo = true;\n\n try {\n // Run all git commands in parallel using a single combined command\n // This reduces 3 sequential execSync calls to 1\n const combined = execSync(\n 'echo \"BRANCH:\" && git rev-parse --abbrev-ref HEAD && echo \"REMOTES:\" && git remote -v && echo \"STATUS:\" && git status --porcelain',\n { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000 }\n );\n\n // Parse combined output\n const branchMatch = combined.match(/BRANCH:\\n(.+)\\n/);\n if (branchMatch) {\n status.branch = branchMatch[1].trim();\n }\n\n const remotesMatch = combined.match(/REMOTES:\\n([\\s\\S]*?)STATUS:/);\n if (remotesMatch) {\n const remotes = remotesMatch[1].trim();\n if (remotes) {\n status.hasRemote = true;\n const lines = remotes.split('\\n');\n if (lines.length > 0) {\n const parts = lines[0].split(/\\s+/);\n status.remoteName = parts[0];\n status.remoteUrl = parts[1];\n }\n }\n }\n\n const statusMatch = combined.match(/STATUS:\\n([\\s\\S]*?)$/);\n if (statusMatch) {\n const statusOutput = statusMatch[1].trim();\n if (statusOutput) {\n status.isDirty = true;\n status.uncommittedCount = statusOutput.split('\\n').filter(l => l.trim()).length;\n }\n }\n\n } catch {\n // Git commands failed, but we know it's a git repo\n }\n\n return status;\n}\n\n/**\n * Check git status - async version with parallel git commands\n */\nexport async function checkGitStatusAsync(cwd: string = process.cwd()): Promise<GitStatus> {\n const status: GitStatus = {\n isGitRepo: false,\n hasRemote: false,\n isDirty: false,\n uncommittedCount: 0,\n };\n\n // Check if .git directory exists\n if (!existsSync(join(cwd, '.git'))) {\n return status;\n }\n\n status.isGitRepo = true;\n\n try {\n // Run all git commands in parallel\n const [branchResult, remotesResult, statusResult] = await Promise.all([\n execAsync('git rev-parse --abbrev-ref HEAD', { cwd, timeout: 5000 }).catch(() => ({ stdout: '' })),\n execAsync('git remote -v', { cwd, timeout: 5000 }).catch(() => ({ stdout: '' })),\n execAsync('git status --porcelain', { cwd, timeout: 5000 }).catch(() => ({ stdout: '' })),\n ]);\n\n status.branch = branchResult.stdout.trim();\n\n const remotes = remotesResult.stdout.trim();\n if (remotes) {\n status.hasRemote = true;\n const lines = remotes.split('\\n');\n if (lines.length > 0) {\n const parts = lines[0].split(/\\s+/);\n status.remoteName = parts[0];\n status.remoteUrl = parts[1];\n }\n }\n\n const statusOutput = statusResult.stdout.trim();\n if (statusOutput) {\n status.isDirty = true;\n status.uncommittedCount = statusOutput.split('\\n').filter(l => l.trim()).length;\n }\n\n } catch {\n // Git commands failed, but we know it's a git repo\n }\n\n return status;\n}\n\nexport function initGitRepo(cwd: string = process.cwd()): boolean {\n try {\n execSync('git init', { cwd, stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getRepoName(remoteUrl?: string): string | null {\n if (!remoteUrl) return null;\n\n // Handle various remote URL formats\n // git@github.com:user/repo.git\n // https://github.com/user/repo.git\n const match = remoteUrl.match(/[:/]([^/]+\\/[^/]+?)(?:\\.git)?$/);\n return match ? match[1] : null;\n}\n\n// Multi-repo git performance stats\nexport interface GitPerformanceStats {\n totalCommits: number;\n commitsByDay: Map<string, number>; // date string -> count\n commitsByAuthor: Map<string, number>;\n commitsByRepo: Map<string, number>;\n activeDays: number;\n avgCommitsPerDay: number;\n peakDay: { date: string; count: number } | null;\n repos: RepoStats[];\n recentCommits: CommitInfo[]; // Most recent commits across all repos\n}\n\nexport interface RepoStats {\n name: string;\n path: string;\n commits: number;\n lastCommit: string;\n authors: string[];\n}\n\nexport interface CommitInfo {\n hash: string;\n author: string;\n date: string;\n message: string;\n repo: string;\n}\n\nconst SQUAD_REPOS = ['hq', 'agents-squads-web', 'squads-cli', 'company', 'product', 'engineering', 'research', 'intelligence', 'customer', 'finance', 'marketing'];\n\n// Squad to repo mapping for GitHub stats\nconst SQUAD_REPO_MAP: Record<string, string[]> = {\n website: ['agents-squads-web'],\n product: ['squads-cli'],\n engineering: ['hq', 'squads-cli'],\n research: ['research'],\n intelligence: ['intelligence'],\n customer: ['customer'],\n finance: ['finance'],\n company: ['company', 'hq'],\n marketing: ['marketing', 'agents-squads-web'],\n};\n\n// Label patterns that map to squads\nconst SQUAD_LABELS: Record<string, string[]> = {\n website: ['website', 'web', 'frontend', 'ui'],\n product: ['product', 'cli', 'feature'],\n engineering: ['engineering', 'infra', 'backend', 'bug'],\n research: ['research', 'analysis'],\n intelligence: ['intel', 'monitoring'],\n customer: ['customer', 'sales', 'lead'],\n finance: ['finance', 'cost', 'billing'],\n company: ['company', 'strategy'],\n marketing: ['marketing', 'content', 'seo'],\n};\n\nexport interface GitHubStats {\n prsOpened: number;\n prsMerged: number;\n issuesClosed: number;\n issuesOpen: number;\n bySquad: Map<string, SquadGitHubStats>;\n}\n\nexport interface SquadGitHubStats {\n prsOpened: number;\n prsMerged: number;\n issuesClosed: number;\n issuesOpen: number;\n commits: number;\n recentIssues: { title: string; number: number; state: string }[];\n recentPRs: { title: string; number: number; merged: boolean }[];\n}\n\nexport async function getGitHubStats(basePath: string, days: number = 30): Promise<GitHubStats> {\n const stats: GitHubStats = {\n prsOpened: 0,\n prsMerged: 0,\n issuesClosed: 0,\n issuesOpen: 0,\n bySquad: new Map(),\n };\n\n // Initialize squad stats\n for (const squad of Object.keys(SQUAD_REPO_MAP)) {\n stats.bySquad.set(squad, {\n prsOpened: 0,\n prsMerged: 0,\n issuesClosed: 0,\n issuesOpen: 0,\n commits: 0,\n recentIssues: [],\n recentPRs: [],\n });\n }\n\n const repos = ['hq', 'agents-squads-web'];\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();\n\n for (const repo of repos) {\n const repoPath = join(basePath, repo);\n if (!existsSync(repoPath)) continue;\n\n try {\n // Get PRs\n const prsOutput = execSync(\n `gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 100 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n );\n const prs = JSON.parse(prsOutput || '[]');\n\n for (const pr of prs) {\n const created = new Date(pr.createdAt);\n if (created < new Date(since)) continue;\n\n stats.prsOpened++;\n if (pr.mergedAt) stats.prsMerged++;\n\n // Detect squad from labels or title\n const squad = detectSquadFromPR(pr, repo);\n const squadStats = stats.bySquad.get(squad);\n if (squadStats) {\n squadStats.prsOpened++;\n if (pr.mergedAt) squadStats.prsMerged++;\n if (squadStats.recentPRs.length < 3) {\n squadStats.recentPRs.push({\n title: pr.title,\n number: pr.number,\n merged: !!pr.mergedAt,\n });\n }\n }\n }\n\n // Get Issues\n const issuesOutput = execSync(\n `gh issue list --state all --json number,title,state,closedAt,labels --limit 100 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n );\n const issues = JSON.parse(issuesOutput || '[]');\n\n for (const issue of issues) {\n const squad = detectSquadFromIssue(issue, repo);\n const squadStats = stats.bySquad.get(squad);\n\n if (issue.state === 'CLOSED') {\n const closed = new Date(issue.closedAt);\n if (closed >= new Date(since)) {\n stats.issuesClosed++;\n if (squadStats) {\n squadStats.issuesClosed++;\n }\n }\n } else {\n stats.issuesOpen++;\n if (squadStats) {\n squadStats.issuesOpen++;\n if (squadStats.recentIssues.length < 3) {\n squadStats.recentIssues.push({\n title: issue.title,\n number: issue.number,\n state: issue.state,\n });\n }\n }\n }\n }\n } catch {\n // gh not available or not in repo\n }\n }\n\n // Add commit counts per squad\n const gitStats = await getMultiRepoGitStats(basePath, days);\n for (const [repo, commits] of gitStats.commitsByRepo) {\n // Map repo to squad\n for (const [squad, repos] of Object.entries(SQUAD_REPO_MAP)) {\n if (repos.includes(repo)) {\n const squadStats = stats.bySquad.get(squad);\n if (squadStats) {\n squadStats.commits += commits;\n }\n }\n }\n }\n\n return stats;\n}\n\n/**\n * Optimized GitHub stats - fetches PRs and issues in parallel across repos\n * Uses a single combined gh api call per repo for better performance\n */\nexport function getGitHubStatsOptimized(basePath: string, days: number = 30): GitHubStats {\n const stats: GitHubStats = {\n prsOpened: 0,\n prsMerged: 0,\n issuesClosed: 0,\n issuesOpen: 0,\n bySquad: new Map(),\n };\n\n // Initialize squad stats\n for (const squad of Object.keys(SQUAD_REPO_MAP)) {\n stats.bySquad.set(squad, {\n prsOpened: 0,\n prsMerged: 0,\n issuesClosed: 0,\n issuesOpen: 0,\n commits: 0,\n recentIssues: [],\n recentPRs: [],\n });\n }\n\n const repos = ['hq', 'agents-squads-web'];\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();\n\n // Fetch all data in parallel using a single combined command\n const results: { repo: string; prs: unknown[]; issues: unknown[] }[] = [];\n\n for (const repo of repos) {\n const repoPath = join(basePath, repo);\n if (!existsSync(repoPath)) continue;\n\n try {\n // Use a single shell command to get both PRs and issues\n // This reduces the number of gh CLI invocations from 4 to 2\n const output = execSync(\n `echo '{\"prs\":' && gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null && echo ',\"issues\":' && gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null && echo '}'`,\n { cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000 }\n );\n\n // Parse the combined output (handle edge cases)\n const prsMatch = output.match(/\"prs\":(\\[.*?\\]),\"issues\":/s);\n const issuesMatch = output.match(/\"issues\":(\\[.*?\\])\\s*\\}/s);\n\n const prs = prsMatch ? JSON.parse(prsMatch[1]) : [];\n const issues = issuesMatch ? JSON.parse(issuesMatch[1]) : [];\n\n results.push({ repo, prs, issues });\n } catch {\n // Fallback: try individual calls with short timeout\n try {\n const prsOutput = execSync(\n `gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000 }\n );\n const issuesOutput = execSync(\n `gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000 }\n );\n results.push({\n repo,\n prs: JSON.parse(prsOutput || '[]'),\n issues: JSON.parse(issuesOutput || '[]'),\n });\n } catch {\n // Skip this repo\n }\n }\n }\n\n // Process results\n for (const { repo, prs, issues } of results) {\n // Process PRs\n for (const pr of prs as { createdAt: string; mergedAt?: string; title: string; number: number; labels: { name: string }[] }[]) {\n const created = new Date(pr.createdAt);\n if (created < new Date(since)) continue;\n\n stats.prsOpened++;\n if (pr.mergedAt) stats.prsMerged++;\n\n const squad = detectSquadFromPR(pr, repo);\n const squadStats = stats.bySquad.get(squad);\n if (squadStats) {\n squadStats.prsOpened++;\n if (pr.mergedAt) squadStats.prsMerged++;\n if (squadStats.recentPRs.length < 3) {\n squadStats.recentPRs.push({\n title: pr.title,\n number: pr.number,\n merged: !!pr.mergedAt,\n });\n }\n }\n }\n\n // Process Issues\n for (const issue of issues as { state: string; closedAt?: string; title: string; number: number; labels: { name: string }[] }[]) {\n const squad = detectSquadFromIssue(issue, repo);\n const squadStats = stats.bySquad.get(squad);\n\n if (issue.state === 'CLOSED') {\n const closed = new Date(issue.closedAt || 0);\n if (closed >= new Date(since)) {\n stats.issuesClosed++;\n if (squadStats) {\n squadStats.issuesClosed++;\n }\n }\n } else {\n stats.issuesOpen++;\n if (squadStats) {\n squadStats.issuesOpen++;\n if (squadStats.recentIssues.length < 3) {\n squadStats.recentIssues.push({\n title: issue.title,\n number: issue.number,\n state: issue.state,\n });\n }\n }\n }\n }\n }\n\n // Note: commit counts are added separately by the caller using cached git stats\n return stats;\n}\n\nfunction detectSquadFromPR(pr: { title: string; labels: { name: string }[] }, repo: string): string {\n // Check labels first\n for (const label of pr.labels || []) {\n const labelLower = label.name.toLowerCase();\n for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {\n if (patterns.some(p => labelLower.includes(p))) {\n return squad;\n }\n }\n }\n\n // Check title\n const titleLower = pr.title.toLowerCase();\n for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {\n if (patterns.some(p => titleLower.includes(p))) {\n return squad;\n }\n }\n\n // Default based on repo\n if (repo === 'agents-squads-web') return 'website';\n if (repo === 'squads-cli') return 'product';\n return 'engineering';\n}\n\nfunction detectSquadFromIssue(issue: { title: string; labels: { name: string }[] }, repo: string): string {\n // Check labels first\n for (const label of issue.labels || []) {\n const labelLower = label.name.toLowerCase();\n\n // Direct squad label match\n if (labelLower.startsWith('squad:')) {\n return labelLower.replace('squad:', '');\n }\n\n for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {\n if (patterns.some(p => labelLower.includes(p))) {\n return squad;\n }\n }\n }\n\n // Check title\n const titleLower = issue.title.toLowerCase();\n for (const [squad, patterns] of Object.entries(SQUAD_LABELS)) {\n if (patterns.some(p => titleLower.includes(p))) {\n return squad;\n }\n }\n\n // Default based on repo\n if (repo === 'agents-squads-web') return 'website';\n if (repo === 'squads-cli') return 'product';\n return 'engineering';\n}\n\nexport async function getMultiRepoGitStats(basePath: string, days: number = 30): Promise<GitPerformanceStats> {\n const stats: GitPerformanceStats = {\n totalCommits: 0,\n commitsByDay: new Map(),\n commitsByAuthor: new Map(),\n commitsByRepo: new Map(),\n activeDays: 0,\n avgCommitsPerDay: 0,\n peakDay: null,\n repos: [],\n recentCommits: [],\n };\n\n // Collect all commits with full info for sorting\n const allCommits: CommitInfo[] = [];\n\n // Build list of valid repos\n const validRepos = SQUAD_REPOS.filter(repo => {\n const repoPath = join(basePath, repo);\n return existsSync(repoPath) && existsSync(join(repoPath, '.git'));\n });\n\n // Fetch git logs from all repos in parallel\n const repoResults = await Promise.all(\n validRepos.map(async (repo) => {\n const repoPath = join(basePath, repo);\n try {\n const { stdout } = await execAsync(\n `git log --since=\"${days} days ago\" --format=\"%H|%aN|%ad|%s\" --date=short 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }\n );\n return { repo, repoPath, output: stdout.trim() };\n } catch {\n return { repo, repoPath, output: '' };\n }\n })\n );\n\n // Process results\n for (const { repo, repoPath, output } of repoResults) {\n if (!output) continue;\n\n const commits = output.split('\\n').filter(l => l.trim());\n const authors = new Set<string>();\n let lastCommit = '';\n\n for (const line of commits) {\n const parts = line.split('|');\n const [hash, author, date, ...messageParts] = parts;\n const message = messageParts.join('|'); // Handle | in commit messages\n if (!hash) continue;\n\n stats.totalCommits++;\n authors.add(author);\n if (!lastCommit) lastCommit = date;\n\n // By day\n const dayCount = stats.commitsByDay.get(date) || 0;\n stats.commitsByDay.set(date, dayCount + 1);\n\n // By author\n const authorCount = stats.commitsByAuthor.get(author) || 0;\n stats.commitsByAuthor.set(author, authorCount + 1);\n\n // By repo\n const repoCount = stats.commitsByRepo.get(repo) || 0;\n stats.commitsByRepo.set(repo, repoCount + 1);\n\n // Collect for recent commits\n allCommits.push({ hash, author, date, message, repo });\n }\n\n stats.repos.push({\n name: repo,\n path: repoPath,\n commits: commits.length,\n lastCommit,\n authors: Array.from(authors),\n });\n }\n\n // Calculate derived stats\n stats.activeDays = stats.commitsByDay.size;\n stats.avgCommitsPerDay = stats.activeDays > 0\n ? Math.round((stats.totalCommits / days) * 10) / 10\n : 0;\n\n // Find peak day\n let peakCount = 0;\n let peakDate = '';\n for (const [date, count] of stats.commitsByDay) {\n if (count > peakCount) {\n peakCount = count;\n peakDate = date;\n }\n }\n if (peakDate) {\n stats.peakDay = { date: peakDate, count: peakCount };\n }\n\n // Sort commits by date (most recent first) and take top 5\n stats.recentCommits = allCommits\n .sort((a, b) => b.date.localeCompare(a.date) || b.hash.localeCompare(a.hash))\n .slice(0, 5);\n\n return stats;\n}\n\nexport interface MilestoneInfo {\n repo: string;\n title: string;\n openIssues: number;\n closedIssues: number;\n totalIssues: number;\n percent: number;\n dueOn: string | null;\n}\n\nexport interface OpenPR {\n repo: string;\n number: number;\n title: string;\n base: string;\n}\n\nexport interface OperationalStatus {\n milestones: MilestoneInfo[];\n openPRs: OpenPR[];\n error: string | null;\n}\n\n/**\n * Fetch operational status: milestones + open PRs across repos.\n * Repos are discovered from squad definitions (SQUAD.md `repo` field).\n * Uses gh CLI — gracefully returns empty if gh is unavailable.\n *\n * @param repos - Array of \"owner/repo\" strings (e.g., [\"agents-squads/squads-cli\"])\n */\nexport function fetchOperationalStatus(repos: string[]): OperationalStatus {\n const result: OperationalStatus = { milestones: [], openPRs: [], error: null };\n\n if (repos.length === 0) {\n return result;\n }\n\n try {\n execSync('gh auth status 2>/dev/null', { stdio: 'pipe', timeout: 3000 });\n } catch {\n result.error = 'gh not authenticated';\n return result;\n }\n\n for (const fullRepo of repos) {\n const repoShort = fullRepo.split('/').pop() || fullRepo;\n\n // Fetch milestones\n try {\n const msOutput = execSync(\n `gh api \"repos/${fullRepo}/milestones?state=open\" --jq '.[] | [.title, .open_issues, .closed_issues, .due_on] | @tsv' 2>/dev/null`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 8000 }\n ).trim();\n\n for (const line of msOutput.split('\\n').filter(l => l.trim())) {\n const [title, open, closed, dueOn] = line.split('\\t');\n const openIssues = parseInt(open) || 0;\n const closedIssues = parseInt(closed) || 0;\n const totalIssues = openIssues + closedIssues;\n result.milestones.push({\n repo: repoShort,\n title,\n openIssues,\n closedIssues,\n totalIssues,\n percent: totalIssues > 0 ? Math.floor((closedIssues / totalIssues) * 100) : 0,\n dueOn: dueOn && dueOn !== 'null' ? dueOn : null,\n });\n }\n } catch { /* skip repo */ }\n\n // Fetch open PRs (try develop first, then main)\n try {\n const prOutput = execSync(\n `gh pr list --repo \"${fullRepo}\" --state open --json number,title,baseRefName --jq '.[] | [.number, .baseRefName, .title] | @tsv' 2>/dev/null`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 8000 }\n ).trim();\n\n for (const line of prOutput.split('\\n').filter(l => l.trim())) {\n const [num, base, ...titleParts] = line.split('\\t');\n result.openPRs.push({\n repo: repoShort,\n number: parseInt(num) || 0,\n title: titleParts.join('\\t'),\n base,\n });\n }\n } catch { /* skip repo */ }\n }\n\n return result;\n}\n\n// Get recent activity sparkline data (last 7 days)\nexport async function getActivitySparkline(basePath: string, days: number = 7): Promise<number[]> {\n const activity: number[] = [];\n const now = new Date();\n\n // Initialize activity array with zeros for each day\n for (let i = days - 1; i >= 0; i--) {\n activity.push(0);\n }\n\n // Build list of valid repos\n const validRepos = SQUAD_REPOS.filter(repo => {\n const repoPath = join(basePath, repo);\n return existsSync(repoPath) && existsSync(join(repoPath, '.git'));\n });\n\n // Fetch git logs from all repos in parallel\n const results = await Promise.all(\n validRepos.map(async (repo) => {\n const repoPath = join(basePath, repo);\n try {\n const { stdout } = await execAsync(\n `git log --since=\"${days} days ago\" --format=\"%ad\" --date=short 2>/dev/null`,\n { cwd: repoPath, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }\n );\n return stdout.trim();\n } catch {\n return '';\n }\n })\n );\n\n // Process results\n for (const output of results) {\n if (!output) continue;\n\n for (const dateStr of output.split('\\n')) {\n const commitDate = new Date(dateStr);\n const daysAgo = Math.floor((now.getTime() - commitDate.getTime()) / (1000 * 60 * 60 * 24));\n const index = days - 1 - daysAgo;\n if (index >= 0 && index < days) {\n activity[index]++;\n }\n }\n }\n\n return activity;\n}\n"],"mappings":"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","names":[]}