feat(ai): implement AI Code Copilot & Reviewer suite (/ai review, summarize, bugfix, explain)

husteno-o committed 1 months ago
98f25a0
1 parent cc194ac
commit 98f25a0
14 files changed
+1779 -143
β–Όapps/bot/src/commands/ai.ts
+198-0
1
+import { aiCopilot } from "@devpulse/ai";
2
+import { githubClient } from "@devpulse/github";
3
+import { SlashCommandBuilder } from "discord.js";
4
+import { createAiBugfixActionButtons, createAiReviewActionButtons } from "../ui/components.js";
5
+import {
6
+ createAiBugfixEmbed,
7
+ createAiExplainEmbed,
8
+ createAiReviewEmbed,
9
+ createAiSummaryEmbed,
10
+ createErrorEmbed,
11
+} from "../ui/embeds.js";
12
+import type { Command } from "./types.js";
13
+
14
+export const aiCommand: Command = {
15
+ data: new SlashCommandBuilder()
16
+ .setName("ai")
17
+ .setDescription(
18
+ "AI Code Copilot & Reviewer: automated PR reviews, standup summaries, bugfixes & explain",
19
+ )
20
+ .addSubcommand((sub) =>
21
+ sub
22
+ .setName("review")
23
+ .setDescription(
24
+ "Perform automated code review on a pull request (security, bugs, diff fixes)",
25
+ )
26
+ .addStringOption((opt) =>
27
+ opt.setName("repo").setDescription("Repository format 'owner/repo'").setRequired(true),
28
+ )
29
+ .addIntegerOption((opt) =>
30
+ opt.setName("pr").setDescription("Pull request number").setRequired(true),
31
+ ),
32
+ )
33
+ .addSubcommand((sub) =>
34
+ sub
35
+ .setName("summarize")
36
+ .setDescription("Generate executive changelog and standup summaries of shipped code")
37
+ .addStringOption((opt) =>
38
+ opt.setName("repo").setDescription("Repository format 'owner/repo'").setRequired(true),
39
+ )
40
+ .addStringOption((opt) =>
41
+ opt
42
+ .setName("timeframe")
43
+ .setDescription("Timeframe for standup summary")
44
+ .addChoices(
45
+ { name: "Week (Past 7 Days)", value: "week" },
46
+ { name: "Month (Past 30 Days)", value: "month" },
47
+ )
48
+ .setRequired(false),
49
+ ),
50
+ )
51
+ .addSubcommand((sub) =>
52
+ sub
53
+ .setName("bugfix")
54
+ .setDescription(
55
+ "Ingest issue description & stack traces, identify culprit, and synthesize patch",
56
+ )
57
+ .addStringOption((opt) =>
58
+ opt.setName("repo").setDescription("Repository format 'owner/repo'").setRequired(true),
59
+ )
60
+ .addIntegerOption((opt) =>
61
+ opt.setName("issue").setDescription("Issue number").setRequired(true),
62
+ ),
63
+ )
64
+ .addSubcommand((sub) =>
65
+ sub
66
+ .setName("explain")
67
+ .setDescription(
68
+ "Explain algorithms, system architecture, dependencies & complexity of a file",
69
+ )
70
+ .addStringOption((opt) =>
71
+ opt.setName("repo").setDescription("Repository format 'owner/repo'").setRequired(true),
72
+ )
73
+ .addStringOption((opt) =>
74
+ opt
75
+ .setName("file")
76
+ .setDescription("Path to the file inside repository (e.g. src/auth/token.ts)")
77
+ .setRequired(true),
78
+ )
79
+ .addIntegerOption((opt) =>
80
+ opt
81
+ .setName("line")
82
+ .setDescription("Optional specific line number to focus on")
83
+ .setRequired(false),
84
+ ),
85
+ ),
86
+
87
+ async execute(interaction) {
88
+ await interaction.deferReply();
89
+ const subcommand = interaction.options.getSubcommand();
90
+ const repoInput = interaction.options.getString("repo", true);
91
+
92
+ try {
93
+ if (subcommand === "review") {
94
+ const prNumber = interaction.options.getInteger("pr", true);
95
+ const [repo, pr, files] = await Promise.all([
96
+ githubClient.getRepo(repoInput),
97
+ githubClient.getPullRequest(repoInput, prNumber),
98
+ githubClient.getPullRequestFiles(repoInput, prNumber),
99
+ ]);
100
+
101
+ const review = await aiCopilot.reviewPullRequest(repo.fullName, pr, files);
102
+ const embed = createAiReviewEmbed(repo, pr, review);
103
+ const components = createAiReviewActionButtons(
104
+ repo.owner.login,
105
+ repo.name,
106
+ pr.number,
107
+ pr.htmlUrl,
108
+ review.approvedForMerge,
109
+ );
110
+
111
+ await interaction.editReply({ embeds: [embed], components });
112
+ return;
113
+ }
114
+
115
+ if (subcommand === "summarize") {
116
+ const timeframe = (interaction.options.getString("timeframe") || "week") as
117
+ | "week"
118
+ | "month";
119
+ const repo = await githubClient.getRepo(repoInput);
120
+
121
+ const days = timeframe === "week" ? 7 : 30;
122
+ const sinceDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
123
+
124
+ const [commits, prs] = await Promise.all([
125
+ githubClient.getCommits(repoInput, 50),
126
+ githubClient.getPullRequests(repoInput, "closed", 30),
127
+ ]);
128
+
129
+ // Filter commits and PRs within timeframe
130
+ const filteredCommits = commits.filter(
131
+ (c) => new Date(c.author.date).getTime() >= new Date(sinceDate).getTime(),
132
+ );
133
+ const targetCommits = filteredCommits.length > 0 ? filteredCommits : commits.slice(0, 15);
134
+
135
+ const filteredPrs = prs.filter(
136
+ (p) =>
137
+ p.state === "closed" &&
138
+ new Date(p.updatedAt).getTime() >= new Date(sinceDate).getTime(),
139
+ );
140
+ const targetPrs = filteredPrs.length > 0 ? filteredPrs : prs.slice(0, 10);
141
+
142
+ const summary = await aiCopilot.summarizeActivity(
143
+ repo,
144
+ targetCommits,
145
+ targetPrs,
146
+ timeframe,
147
+ );
148
+ const embed = createAiSummaryEmbed(repo, summary);
149
+
150
+ await interaction.editReply({ embeds: [embed] });
151
+ return;
152
+ }
153
+
154
+ if (subcommand === "bugfix") {
155
+ const issueNumber = interaction.options.getInteger("issue", true);
156
+ const [repo, issue] = await Promise.all([
157
+ githubClient.getRepo(repoInput),
158
+ githubClient.getSingleIssue(repoInput, issueNumber),
159
+ ]);
160
+
161
+ const bugfix = await aiCopilot.suggestBugfix(repo.fullName, issue);
162
+ const embed = createAiBugfixEmbed(repo, issue, bugfix);
163
+ const components = createAiBugfixActionButtons(
164
+ repo.owner.login,
165
+ repo.name,
166
+ issue.number,
167
+ issue.htmlUrl,
168
+ );
169
+
170
+ await interaction.editReply({ embeds: [embed], components });
171
+ return;
172
+ }
173
+
174
+ if (subcommand === "explain") {
175
+ const filePath = interaction.options.getString("file", true);
176
+ const line = interaction.options.getInteger("line") || undefined;
177
+
178
+ const [repo, file] = await Promise.all([
179
+ githubClient.getRepo(repoInput),
180
+ githubClient.getFileContents(repoInput, filePath),
181
+ ]);
182
+
183
+ const explanation = await aiCopilot.explainCode(
184
+ repo.fullName,
185
+ file.path,
186
+ file.content,
187
+ line,
188
+ );
189
+ const embed = createAiExplainEmbed(repo, file, explanation, line);
190
+
191
+ await interaction.editReply({ embeds: [embed] });
192
+ return;
193
+ }
194
+ } catch (err: any) {
195
+ await interaction.editReply({ embeds: [createErrorEmbed(err)] });
196
+ }
197
+ },
198
+};
0
199
β–Όapps/bot/src/commands/help.ts
+20-7
38
38
["/pr waiting <repo>", "Waiting on reviewers (> 24h)"],
39
39
],
40
40
},
41
+ ai: {
42
+ title: "AI COPILOT & REVIEWER",
43
+ synopsis: "Automated PR reviews, changelog standups, bugfixes & explain",
44
+ commands: [
45
+ ["/ai review <repo> <pr>", "Automated code review & diff fix"],
46
+ ["/ai summarize <repo> [timeframe]", "Weekly/monthly standup summary"],
47
+ ["/ai bugfix <repo> <issue>", "Diagnose stack trace & suggest patch"],
48
+ ["/ai explain <repo> <file> [line]", "Architectural breakdown & complexity"],
49
+ ],
50
+ },
41
51
search: {
42
52
title: "GITHUB POWER SEARCH",
43
53
synopsis: "Full GitHub qualifier search from Discord",
130
140
`${ANSI.dim}02${ANSI.reset} ${ANSI.cyan}pr ${ANSI.reset} ${ANSI.white}/pr <view|list|review>${ANSI.reset}`,
131
141
),
132
142
tuiLine(
133
- `${ANSI.dim}03${ANSI.reset} ${ANSI.blue}search ${ANSI.reset} ${ANSI.white}/search <code|issues|prs>${ANSI.reset}`,
143
+ `${ANSI.dim}03${ANSI.reset} ${ANSI.yellow}ai ${ANSI.reset} ${ANSI.white}/ai <review|summarize|bugfix>${ANSI.reset}`,
144
+ ),
145
+ tuiLine(
146
+ `${ANSI.dim}04${ANSI.reset} ${ANSI.blue}search ${ANSI.reset} ${ANSI.white}/search <code|issues|prs>${ANSI.reset}`,
134
147
),
135
148
tuiLine(
136
- `${ANSI.dim}04${ANSI.reset} ${ANSI.green}code ${ANSI.reset} ${ANSI.white}/code view, /code blame${ANSI.reset}`,
149
+ `${ANSI.dim}05${ANSI.reset} ${ANSI.green}code ${ANSI.reset} ${ANSI.white}/code view, /code blame${ANSI.reset}`,
137
150
),
138
151
tuiLine(
139
- `${ANSI.dim}05${ANSI.reset} ${ANSI.yellow}trace ${ANSI.reset} ${ANSI.white}/why, /investigate${ANSI.reset}`,
152
+ `${ANSI.dim}06${ANSI.reset} ${ANSI.magenta}trace ${ANSI.reset} ${ANSI.white}/why, /investigate${ANSI.reset}`,
140
153
),
141
154
tuiLine(
142
- `${ANSI.dim}06${ANSI.reset} ${ANSI.magenta}stats ${ANSI.reset} ${ANSI.white}/activity, /team${ANSI.reset}`,
155
+ `${ANSI.dim}07${ANSI.reset} ${ANSI.cyan}stats ${ANSI.reset} ${ANSI.white}/activity, /team${ANSI.reset}`,
143
156
),
144
157
tuiLine(
145
- `${ANSI.dim}07${ANSI.reset} ${ANSI.cyan}radar ${ANSI.reset} ${ANSI.white}/trending, /watch${ANSI.reset}`,
158
+ `${ANSI.dim}08${ANSI.reset} ${ANSI.blue}radar ${ANSI.reset} ${ANSI.white}/trending, /watch${ANSI.reset}`,
146
159
),
147
160
tuiLine(
148
- `${ANSI.dim}08${ANSI.reset} ${ANSI.blue}actions ${ANSI.reset} ${ANSI.white}/actions status, /release${ANSI.reset}`,
161
+ `${ANSI.dim}09${ANSI.reset} ${ANSI.green}actions ${ANSI.reset} ${ANSI.white}/actions status, /release${ANSI.reset}`,
149
162
),
150
163
tuiLine(
151
- `${ANSI.dim}09${ANSI.reset} ${ANSI.green}secure ${ANSI.reset} ${ANSI.white}/security audit, /connect${ANSI.reset}`,
164
+ `${ANSI.dim}10${ANSI.reset} ${ANSI.yellow}secure ${ANSI.reset} ${ANSI.white}/security audit, /connect${ANSI.reset}`,
152
165
),
153
166
tuiDivider("COMMAND CENTER"),
154
167
tuiLine(`${ANSI.dim}Select a module below or type a command${ANSI.reset}`),
155
168
β–Όapps/bot/src/commands/index.ts
+2-0
1
1
import { actionsCommand } from "./actions.js";
2
2
import { activityCommand } from "./activity.js";
3
+import { aiCommand } from "./ai.js";
3
4
import { askCommand } from "./ask.js";
4
5
import { codeCommand } from "./code.js";
5
6
import { connectCommand } from "./connect.js";
22
23
export const commands: Command[] = [
23
24
repoCommand,
24
25
prCommand,
26
+ aiCommand,
25
27
searchCommand,
26
28
codeCommand,
27
29
investigateCommand,
28
30
β–Όapps/bot/src/index.test.ts
+2-1
4
4
5
5
describe("Discord Bot Application", () => {
6
6
it("registers all GitHub Power-User command groups", () => {
7
- expect(commands.length).toBe(19);
7
+ expect(commands.length).toBe(20);
8
8
expect(commandMap.has("repo")).toBe(true);
9
9
expect(commandMap.has("pr")).toBe(true);
10
+ expect(commandMap.has("ai")).toBe(true);
10
11
expect(commandMap.has("search")).toBe(true);
11
12
expect(commandMap.has("code")).toBe(true);
12
13
expect(commandMap.has("investigate")).toBe(true);
13
14
β–Όapps/bot/src/ui/components.ts
+51-6
99
99
);
100
100
}
101
101
102
+export function createAiReviewActionButtons(
103
+ owner: string,
104
+ repo: string,
105
+ prNumber: number,
106
+ prUrl: string,
107
+ approvedForMerge: boolean,
108
+): ActionRowBuilder<ButtonBuilder>[] {
109
+ const row = new ActionRowBuilder<ButtonBuilder>();
110
+ if (approvedForMerge) {
111
+ row.addComponents(
112
+ new ButtonBuilder()
113
+ .setCustomId(`pr:merge:${owner}:${repo}:${prNumber}`)
114
+ .setLabel(`${NF.gitMerge} Fast-Forward Merge`)
115
+ .setStyle(ButtonStyle.Success),
116
+ );
117
+ }
118
+ row.addComponents(
119
+ new ButtonBuilder()
120
+ .setCustomId(`pr:approve:${owner}:${repo}:${prNumber}`)
121
+ .setLabel(`${NF.check} Approve PR`)
122
+ .setStyle(ButtonStyle.Primary),
123
+ new ButtonBuilder().setLabel("🌐 View on GitHub β†—").setStyle(ButtonStyle.Link).setURL(prUrl),
124
+ );
125
+ return [row];
126
+}
127
+
128
+export function createAiBugfixActionButtons(
129
+ _owner: string,
130
+ _repo: string,
131
+ _issueNumber: number,
132
+ issueUrl: string,
133
+): ActionRowBuilder<ButtonBuilder>[] {
134
+ const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
135
+ new ButtonBuilder()
136
+ .setLabel("🐞 View Issue on GitHub β†—")
137
+ .setStyle(ButtonStyle.Link)
138
+ .setURL(issueUrl),
139
+ );
140
+ return [row];
141
+}
142
+
102
143
export function createHelpSelect(): ActionRowBuilder<StringSelectMenuBuilder> {
103
144
const menu = new StringSelectMenuBuilder()
104
145
.setCustomId("help:category_select")
113
154
.setDescription("Stale detection, CI checks, diffs, 1-click merge")
114
155
.setValue("pr"),
115
156
new StringSelectMenuOptionBuilder()
116
- .setLabel(`${NF.search} 3. GitHub Search Engine (/search)`)
157
+ .setLabel(`${NF.sparkle} 3. AI Copilot & Reviewer (/ai)`)
158
+ .setDescription("Automated code reviews, standup summaries, bugfixes")
159
+ .setValue("ai"),
160
+ new StringSelectMenuOptionBuilder()
161
+ .setLabel(`${NF.search} 4. GitHub Search Engine (/search)`)
117
162
.setDescription("Code, issues, PRs, repos, commits qualifiers")
118
163
.setValue("search"),
119
164
new StringSelectMenuOptionBuilder()
120
- .setLabel(`${NF.terminal} 4. Code Intelligence (/code & /why)`)
165
+ .setLabel(`${NF.terminal} 5. Code Intelligence (/code & /why)`)
121
166
.setDescription("File inspection, blame, PR link tracing")
122
167
.setValue("code"),
123
168
new StringSelectMenuOptionBuilder()
124
- .setLabel(`${NF.speedometer} 5. Investigation (/investigate)`)
169
+ .setLabel(`${NF.speedometer} 6. Investigation (/investigate)`)
125
170
.setDescription("Lifecycle timeline: Issue -> Commit -> PR -> Release")
126
171
.setValue("investigate"),
127
172
new StringSelectMenuOptionBuilder()
128
- .setLabel(`${NF.robot} 6. Actions Control Center (/actions)`)
173
+ .setLabel(`${NF.robot} 7. Actions Control Center (/actions)`)
129
174
.setDescription("Visual tree, run inspection, rerun & cancel")
130
175
.setValue("actions"),
131
176
new StringSelectMenuOptionBuilder()
132
- .setLabel(`${NF.shield} 7. Security Center (/security)`)
177
+ .setLabel(`${NF.shield} 8. Security Center (/security)`)
133
178
.setDescription("Dependabot alerts, advisories, CVE breakdown")
134
179
.setValue("security"),
135
180
new StringSelectMenuOptionBuilder()
136
- .setLabel(`${NF.warning} 8. Watchtower Alerts (/watch)`)
181
+ .setLabel(`${NF.warning} 9. Watchtower Alerts (/watch)`)
137
182
.setDescription("Automated Discord alerts for releases, PRs, issues")
138
183
.setValue("watch"),
139
184
);
140
185
β–Όapps/bot/src/ui/embeds.ts
+327-0
1
+import type {
2
+ AiBugfixResult,
3
+ AiCodeReviewResult,
4
+ AiExplanationResult,
5
+ AiSummaryResult,
6
+} from "@devpulse/ai";
1
7
import type { PersonalStats } from "@devpulse/analytics";
2
8
import { formatBytes, formatDuration } from "@devpulse/core";
3
9
import type {
4
10
GitHubBlameLine,
5
11
GitHubCommit,
12
+ GitHubDetailedIssue,
6
13
GitHubDetailedPullRequest,
7
14
GitHubFileContent,
8
15
GitHubIssue,
723
730
`A credential pattern matching **${secret.type}** was detected.\n\n**Fingerprint:** \`${secret.fingerprintHash.slice(0, 16)}...\`\n${NF.warning} **Action Required:** Revoke this credential immediately and delete the message below.`,
724
731
);
725
732
}
733
+
734
+// 10. AI CODE COPILOT & REVIEWER EMBEDS
735
+export function createAiReviewEmbed(
736
+ repo: GitHubRepo,
737
+ pr: GitHubDetailedPullRequest,
738
+ review: AiCodeReviewResult,
739
+): EmbedBuilder {
740
+ const riskColorAnsi =
741
+ review.riskLevel === "CRITICAL"
742
+ ? ANSI.red
743
+ : review.riskLevel === "HIGH"
744
+ ? ANSI.red
745
+ : review.riskLevel === "MEDIUM"
746
+ ? ANSI.yellow
747
+ : ANSI.green;
748
+
749
+ const riskColorEmbed =
750
+ review.riskLevel === "CRITICAL"
751
+ ? Macchiato.red
752
+ : review.riskLevel === "HIGH"
753
+ ? Macchiato.maroon
754
+ : review.riskLevel === "MEDIUM"
755
+ ? Macchiato.peach
756
+ : Macchiato.green;
757
+
758
+ const verdictAnsi = review.approvedForMerge
759
+ ? `${ANSI.green}βœ“ Approved for Merge${ANSI.reset}`
760
+ : `${ANSI.red}βœ• Changes Requested${ANSI.reset}`;
761
+
762
+ const critFindings = review.findings.filter(
763
+ (f) => f.severity === "CRITICAL" || f.severity === "HIGH",
764
+ );
765
+ const warnFindings = review.findings.filter(
766
+ (f) => f.severity === "MEDIUM" || f.severity === "LOW" || f.severity === "INFO",
767
+ );
768
+
769
+ const findingLines: string[] = [];
770
+ if (review.findings.length === 0) {
771
+ findingLines.push(
772
+ tuiLine(`${ANSI.green}βœ“ Zero vulnerabilities or defects spotted.${ANSI.reset}`),
773
+ );
774
+ } else {
775
+ for (const f of review.findings.slice(0, 4)) {
776
+ const sevAnsi =
777
+ f.severity === "CRITICAL"
778
+ ? `${ANSI.red}[CRIT]`
779
+ : f.severity === "HIGH"
780
+ ? `${ANSI.red}[HIGH]`
781
+ : f.severity === "MEDIUM"
782
+ ? `${ANSI.yellow}[MED]`
783
+ : `${ANSI.cyan}[LOW]`;
784
+ const loc = f.file ? `${f.file}${f.line ? `:${f.line}` : ""}` : "";
785
+ findingLines.push(
786
+ tuiLine(
787
+ `${sevAnsi}${ANSI.reset} ${ANSI.white}${clipAnsi(f.title, 18)}${ANSI.reset} ${ANSI.dim}${clipAnsi(loc, 14)}${ANSI.reset}`,
788
+ ),
789
+ );
790
+ }
791
+ }
792
+
793
+ const tui = renderTuiCard([
794
+ tuiTopBar("AI COPILOT CODE REVIEW"),
795
+ tuiPrompt(`gitbot ai review ${repo.fullName} #${pr.number}`),
796
+ tuiDivider("HEALTH & RISK ASSESSMENT"),
797
+ tuiRow2(
798
+ "Risk Level",
799
+ `${riskColorAnsi}${review.riskLevel}${ANSI.reset}`,
800
+ "Score",
801
+ `${review.score}/100`,
802
+ ),
803
+ tuiLine(`${ANSI.dim}Meter :${ANSI.reset} ${renderMeter(review.score, 12)}`),
804
+ tuiRow2("Verdict", verdictAnsi, "Engine", clipAnsi(review.poweredBy, 12)),
805
+ tuiDivider(`FINDINGS (${critFindings.length} Crit/High β€’ ${warnFindings.length} Med/Low)`),
806
+ ...findingLines,
807
+ tuiBottomBar(),
808
+ ]);
809
+
810
+ let mdDetails = `### ${review.approvedForMerge ? "βœ… Approved for Merge" : "⚠️ Issues Detected"} β€’ Quality Score: **${review.score}/100**\n`;
811
+ mdDetails += `> ${review.summary}\n\n`;
812
+
813
+ if (review.findings.length > 0) {
814
+ mdDetails += `**πŸ” Detected Code Smells & Security Advisories:**\n`;
815
+ for (const f of review.findings.slice(0, 4)) {
816
+ const icon = f.severity === "CRITICAL" || f.severity === "HIGH" ? "πŸ”΄" : "🟑";
817
+ const loc = f.file ? `\`${f.file}${f.line ? `:${f.line}` : ""}\`` : "";
818
+ mdDetails += `${icon} **${f.title}** ${loc}\nβ€’ ${f.description}\n`;
819
+ if (f.suggestion) {
820
+ mdDetails += ` *Fix:* \`${f.suggestion.slice(0, 120)}\`\n`;
821
+ }
822
+ }
823
+ mdDetails += "\n";
824
+ }
825
+
826
+ if (review.diffProposal) {
827
+ const trimmedDiff = review.diffProposal.slice(0, 600);
828
+ mdDetails += `**πŸ’‘ Proposed Unified Diff Fix:**\n\`\`\`diff\n${trimmedDiff}\n\`\`\`\n`;
829
+ }
830
+
831
+ mdDetails += `*⚑ AI Code Review powered by ${review.poweredBy}*`;
832
+
833
+ return createBaseEmbed(`${NF.robot} AI Review: ${repo.fullName} #${pr.number}`)
834
+ .setAuthor({
835
+ name: `GITBOT Senior Copilot β€’ ${repo.fullName}`,
836
+ iconURL: repo.owner.avatarUrl,
837
+ url: pr.htmlUrl,
838
+ })
839
+ .setURL(pr.htmlUrl)
840
+ .setColor(riskColorEmbed)
841
+ .setDescription(`${tui}\n\n${mdDetails}`);
842
+}
843
+
844
+export function createAiSummaryEmbed(repo: GitHubRepo, summary: AiSummaryResult): EmbedBuilder {
845
+ const timeframeLabel = summary.timeframe === "week" ? "Weekly Standup" : "Monthly Standup";
846
+
847
+ const tui = renderTuiCard([
848
+ tuiTopBar(`STANDUP CHANGELOG: ${summary.timeframe.toUpperCase()}`),
849
+ tuiPrompt(`gitbot ai summarize ${repo.fullName} ${summary.timeframe}`),
850
+ tuiDivider("SHIPPED VELOCITY"),
851
+ tuiRow2(
852
+ "Commits",
853
+ `${ANSI.green}${summary.stats.commitsCount}${ANSI.reset}`,
854
+ "Merged PRs",
855
+ `${ANSI.magenta}${summary.stats.prsMergedCount}${ANSI.reset}`,
856
+ ),
857
+ tuiRow2(
858
+ "Authors",
859
+ `${ANSI.cyan}${summary.stats.activeAuthorsCount}${ANSI.reset}`,
860
+ "Engine",
861
+ clipAnsi(summary.poweredBy, 12),
862
+ ),
863
+ tuiDivider("HEADLINE"),
864
+ tuiLine(`${ANSI.yellow}${clipAnsi(summary.headline, 37)}${ANSI.reset}`),
865
+ tuiBottomBar(),
866
+ ]);
867
+
868
+ let md = `### πŸ“Š ${timeframeLabel} Summary for [${repo.fullName}](${repo.htmlUrl})\n`;
869
+ md += `> **${summary.headline}**\n\n`;
870
+
871
+ if (summary.features.length > 0) {
872
+ md += `**πŸš€ New Features & Capabilities:**\n`;
873
+ for (const feat of summary.features.slice(0, 4)) {
874
+ md += `β€’ ${feat}\n`;
875
+ }
876
+ md += "\n";
877
+ }
878
+
879
+ if (summary.fixes.length > 0) {
880
+ md += `**πŸ› Bug Fixes & Reliability:**\n`;
881
+ for (const fix of summary.fixes.slice(0, 4)) {
882
+ md += `β€’ ${fix}\n`;
883
+ }
884
+ md += "\n";
885
+ }
886
+
887
+ if (summary.perfAndChores.length > 0) {
888
+ md += `**⚑ Maintenance & Performance:**\n`;
889
+ for (const chore of summary.perfAndChores.slice(0, 3)) {
890
+ md += `β€’ ${chore}\n`;
891
+ }
892
+ md += "\n";
893
+ }
894
+
895
+ if (summary.topContributors.length > 0) {
896
+ md += `**πŸ‘₯ Core Contributors:** ${summary.topContributors.map((c) => `\`${c}\``).join(", ")}\n\n`;
897
+ }
898
+
899
+ md += `*⚑ Changelog & Standup analysis powered by ${summary.poweredBy}*`;
900
+
901
+ return createBaseEmbed(`${NF.sparkle} Standup Changelog: ${repo.fullName} (${summary.timeframe})`)
902
+ .setAuthor({
903
+ name: `GITBOT Standup Copilot β€’ ${repo.fullName}`,
904
+ iconURL: repo.owner.avatarUrl,
905
+ url: repo.htmlUrl,
906
+ })
907
+ .setURL(repo.htmlUrl)
908
+ .setColor(Macchiato.teal)
909
+ .setDescription(`${tui}\n\n${md}`);
910
+}
911
+
912
+export function createAiBugfixEmbed(
913
+ repo: GitHubRepo,
914
+ issue: GitHubDetailedIssue,
915
+ bugfix: AiBugfixResult,
916
+): EmbedBuilder {
917
+ const confAnsi =
918
+ bugfix.confidence === "HIGH"
919
+ ? `${ANSI.green}HIGH`
920
+ : bugfix.confidence === "MEDIUM"
921
+ ? `${ANSI.yellow}MEDIUM`
922
+ : `${ANSI.red}LOW`;
923
+
924
+ const confColor =
925
+ bugfix.confidence === "HIGH"
926
+ ? Macchiato.green
927
+ : bugfix.confidence === "MEDIUM"
928
+ ? Macchiato.peach
929
+ : Macchiato.red;
930
+
931
+ const loc = `${bugfix.targetFile}${bugfix.targetLine ? `:${bugfix.targetLine}` : ""}`;
932
+
933
+ const tui = renderTuiCard([
934
+ tuiTopBar("DIAGNOSTIC & REPAIR COPILOT"),
935
+ tuiPrompt(`gitbot ai bugfix ${repo.fullName} #${issue.number}`),
936
+ tuiDivider("TRIAGE & TARGET"),
937
+ tuiLine(
938
+ `${ANSI.dim}Issue :${ANSI.reset} ${ANSI.cyan}#${issue.number}${ANSI.reset} ${clipAnsi(issue.title, 26)}`,
939
+ ),
940
+ tuiLine(`${ANSI.dim}Target :${ANSI.reset} ${ANSI.yellow}${clipAnsi(loc, 30)}${ANSI.reset}`),
941
+ tuiRow2("Confidence", `${confAnsi}${ANSI.reset}`, "Engine", clipAnsi(bugfix.poweredBy, 12)),
942
+ tuiDivider("ROOT CAUSE"),
943
+ tuiLine(`${ANSI.white}${clipAnsi(bugfix.rootCause, 37)}${ANSI.reset}`),
944
+ tuiBottomBar(),
945
+ ]);
946
+
947
+ let md = `### 🩺 Root Cause Diagnosis for [#${issue.number}](${issue.htmlUrl})\n`;
948
+ md += `> **${bugfix.rootCause}**\n\n`;
949
+ md += `**🎯 Identified Culprit:** \`${loc}\` (Confidence: **${bugfix.confidence}**)\n\n`;
950
+ md += `**πŸ“ Solution Explanation:**\n${bugfix.explanation}\n\n`;
951
+
952
+ if (bugfix.proposedPatch) {
953
+ const trimmedPatch = bugfix.proposedPatch.slice(0, 700);
954
+ md += `**πŸ› οΈ Proposed Remediation Patch:**\n\`\`\`diff\n${trimmedPatch}\n\`\`\`\n`;
955
+ }
956
+
957
+ if (bugfix.testSuggestions.length > 0) {
958
+ md += `**πŸ§ͺ Suggested Verification Tests:**\n`;
959
+ for (const test of bugfix.testSuggestions) {
960
+ md += `β€’ \`${test}\`\n`;
961
+ }
962
+ md += "\n";
963
+ }
964
+
965
+ md += `*⚑ Bugfix synthesis powered by ${bugfix.poweredBy}*`;
966
+
967
+ return createBaseEmbed(`${NF.tools} AI Bugfix: ${repo.fullName} #${issue.number}`)
968
+ .setAuthor({
969
+ name: `GITBOT Diagnostic Copilot β€’ ${repo.fullName}`,
970
+ iconURL: repo.owner.avatarUrl,
971
+ url: issue.htmlUrl,
972
+ })
973
+ .setURL(issue.htmlUrl)
974
+ .setColor(confColor)
975
+ .setDescription(`${tui}\n\n${md}`);
976
+}
977
+
978
+export function createAiExplainEmbed(
979
+ repo: GitHubRepo,
980
+ file: GitHubFileContent,
981
+ explanation: AiExplanationResult,
982
+ line?: number,
983
+): EmbedBuilder {
984
+ const complexityAnsi =
985
+ explanation.complexity === "High"
986
+ ? `${ANSI.red}High`
987
+ : explanation.complexity === "Moderate"
988
+ ? `${ANSI.yellow}Moderate`
989
+ : `${ANSI.green}Low`;
990
+
991
+ const complexityColor =
992
+ explanation.complexity === "High"
993
+ ? Macchiato.red
994
+ : explanation.complexity === "Moderate"
995
+ ? Macchiato.peach
996
+ : Macchiato.blue;
997
+
998
+ const loc = `${file.path}${line ? ` (L${line})` : ""}`;
999
+
1000
+ const tui = renderTuiCard([
1001
+ tuiTopBar("CODE ARCHITECTURE EXPLAINER"),
1002
+ tuiPrompt(`gitbot ai explain ${repo.fullName} ${file.path}`),
1003
+ tuiDivider("SOURCE SPECIFICATION"),
1004
+ tuiLine(`${ANSI.dim}File :${ANSI.reset} ${ANSI.cyan}${clipAnsi(loc, 28)}${ANSI.reset}`),
1005
+ tuiRow2("Complexity", `${complexityAnsi}${ANSI.reset}`, "Size", formatBytes(file.size)),
1006
+ tuiRow2(
1007
+ "Engine",
1008
+ clipAnsi(explanation.poweredBy, 12),
1009
+ "Language",
1010
+ clipAnsi(file.name.split(".").pop() || "code", 10),
1011
+ ),
1012
+ tuiDivider("ARCHITECTURAL ROLE"),
1013
+ tuiLine(`${ANSI.white}${clipAnsi(explanation.architectureRole, 37)}${ANSI.reset}`),
1014
+ tuiBottomBar(),
1015
+ ]);
1016
+
1017
+ let md = `### 🧠 Code Analysis: [${file.path}](${file.htmlUrl})\n`;
1018
+ md += `> **Architecture Role:** ${explanation.architectureRole}\n\n`;
1019
+ md += `**πŸ“– Summary:**\n${explanation.summary}\n\n`;
1020
+
1021
+ if (explanation.keyComponents.length > 0) {
1022
+ md += `**🧩 Key Components & Responsibilities:**\n`;
1023
+ for (const comp of explanation.keyComponents.slice(0, 4)) {
1024
+ md += `β€’ **\`${comp.name}\`**: ${comp.purpose}\n`;
1025
+ }
1026
+ md += "\n";
1027
+ }
1028
+
1029
+ if (explanation.dependencies.length > 0) {
1030
+ md += `**πŸ“¦ Dependencies:** ${explanation.dependencies.map((d) => `\`${d}\``).join(", ")}\n\n`;
1031
+ }
1032
+
1033
+ if (explanation.securityConsiderations.length > 0) {
1034
+ md += `**πŸ›‘οΈ Security & Performance Considerations:**\n`;
1035
+ for (const sec of explanation.securityConsiderations.slice(0, 3)) {
1036
+ md += `β€’ ${sec}\n`;
1037
+ }
1038
+ md += "\n";
1039
+ }
1040
+
1041
+ md += `*⚑ Code intelligence powered by ${explanation.poweredBy}*`;
1042
+
1043
+ return createBaseEmbed(`${NF.terminal} Code Explanation: ${file.name}`)
1044
+ .setAuthor({
1045
+ name: `GITBOT Intelligence Copilot β€’ ${repo.fullName}`,
1046
+ iconURL: repo.owner.avatarUrl,
1047
+ url: file.htmlUrl,
1048
+ })
1049
+ .setURL(file.htmlUrl)
1050
+ .setColor(complexityColor)
1051
+ .setDescription(`${tui}\n\n${md}`);
1052
+}
726
1053
β–Όbun.lock
+211-0
66
66
"typescript": "^5.7.3",
67
67
},
68
68
},
69
+ "apps/worker": {
70
+ "name": "@devpulse/worker",
71
+ "version": "1.0.0",
72
+ "devDependencies": {
73
+ "@cloudflare/workers-types": "^4.20250224.0",
74
+ "wrangler": "^3.109.2",
75
+ },
76
+ },
69
77
"packages/ai": {
70
78
"name": "@devpulse/ai",
71
79
"version": "1.0.0",
72
80
"dependencies": {
73
81
"@devpulse/config": "workspace:*",
74
82
"@devpulse/core": "workspace:*",
83
+ "@devpulse/github": "workspace:*",
75
84
"@devpulse/logger": "workspace:*",
76
85
"zod": "^3.24.2",
77
86
},
290
299
291
300
"@biomejs/cli-win32-x64": ["@biomejs/[email protected]", "https://registry.npmmirror.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
292
301
302
+ "@cloudflare/kv-asset-handler": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", { "dependencies": { "mime": "^3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="],
303
+
304
+ "@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz", { "peerDependencies": { "unenv": "2.0.0-rc.14", "workerd": "^1.20250124.0" }, "optionalPeers": ["workerd"] }, "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg=="],
305
+
306
+ "@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g=="],
307
+
308
+ "@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q=="],
309
+
310
+ "@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz", { "os": "linux", "cpu": "x64" }, "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg=="],
311
+
312
+ "@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog=="],
313
+
314
+ "@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz", { "os": "win32", "cpu": "x64" }, "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg=="],
315
+
316
+ "@cloudflare/workers-types": ["@cloudflare/[email protected]", "https://registry.npmmirror.com/@cloudflare/workers-types/-/workers-types-4.20260702.1.tgz", {}, "sha512-mOhf5TUEB1m2vPrxtqoIGfz0fUC9xyxRDx5gWHy5s+OCo6dcV+g7wI1R7gYCMFohhqF/2y2xeKVwMwCJjfn/WA=="],
317
+
318
+ "@cspotcode/source-map-support": ["@cspotcode/[email protected]", "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
319
+
293
320
"@devpulse/ai": ["@devpulse/ai@workspace:packages/ai"],
294
321
295
322
"@devpulse/analytics": ["@devpulse/analytics@workspace:packages/analytics"],
326
353
327
354
"@devpulse/web": ["@devpulse/web@workspace:apps/web"],
328
355
356
+ "@devpulse/worker": ["@devpulse/worker@workspace:apps/worker"],
357
+
329
358
"@discordjs/builders": ["@discordjs/[email protected]", "https://registry.npmmirror.com/@discordjs/builders/-/builders-1.14.1.tgz", { "dependencies": { "@discordjs/formatters": "^0.6.2", "@discordjs/util": "^1.2.0", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.40", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ=="],
330
359
331
360
"@discordjs/collection": ["@discordjs/[email protected]", "https://registry.npmmirror.com/@discordjs/collection/-/collection-1.5.3.tgz", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
340
369
341
370
"@drizzle-team/brocli": ["@drizzle-team/[email protected]", "https://registry.npmmirror.com/@drizzle-team/brocli/-/brocli-0.10.2.tgz", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
342
371
372
+ "@emnapi/runtime": ["@emnapi/[email protected]", "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
373
+
343
374
"@esbuild-kit/core-utils": ["@esbuild-kit/[email protected]", "https://registry.npmmirror.com/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
344
375
345
376
"@esbuild-kit/esm-loader": ["@esbuild-kit/[email protected]", "https://registry.npmmirror.com/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
346
377
378
+ "@esbuild-plugins/node-globals-polyfill": ["@esbuild-plugins/[email protected]", "https://registry.npmmirror.com/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", { "peerDependencies": { "esbuild": "*" } }, "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw=="],
379
+
380
+ "@esbuild-plugins/node-modules-polyfill": ["@esbuild-plugins/[email protected]", "https://registry.npmmirror.com/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", { "dependencies": { "escape-string-regexp": "^4.0.0", "rollup-plugin-node-polyfills": "^0.2.1" }, "peerDependencies": { "esbuild": "*" } }, "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA=="],
381
+
347
382
"@esbuild/aix-ppc64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
348
383
349
384
"@esbuild/android-arm": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
398
433
399
434
"@fastify/ajv-compiler": ["@fastify/[email protected]", "https://registry.npmmirror.com/@fastify/ajv-compiler/-/ajv-compiler-4.0.6.tgz", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^4.0.0" } }, "sha512-NtuzM0SfaMJbGlnjr9LWQUN5LzgSrbB8tf/wRZNas+4E1O/Nmzl53e7ruT61HDZyRCJGC6FxIogmNZO1c5ETBA=="],
400
435
436
+ "@fastify/busboy": ["@fastify/[email protected]", "https://registry.npmmirror.com/@fastify/busboy/-/busboy-2.1.1.tgz", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
437
+
401
438
"@fastify/error": ["@fastify/[email protected]", "https://registry.npmmirror.com/@fastify/error/-/error-4.2.0.tgz", {}, "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ=="],
402
439
403
440
"@fastify/fast-json-stringify-compiler": ["@fastify/[email protected]", "https://registry.npmmirror.com/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.1.0.tgz", { "dependencies": { "fast-json-stringify": "^7.0.0" } }, "sha512-PxcYtKLbQ8Z+yApiqjK8FwxIwvEj38k2OiLc17u8dkJSlmfi2wHHPaSnaoqBPQqtvF8YVsDgDpP2snDCfFrpfw=="],
408
445
409
446
"@fastify/proxy-addr": ["@fastify/[email protected]", "https://registry.npmmirror.com/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw=="],
410
447
448
+ "@img/sharp-darwin-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
449
+
450
+ "@img/sharp-darwin-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
451
+
452
+ "@img/sharp-libvips-darwin-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="],
453
+
454
+ "@img/sharp-libvips-darwin-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="],
455
+
456
+ "@img/sharp-libvips-linux-arm": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="],
457
+
458
+ "@img/sharp-libvips-linux-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="],
459
+
460
+ "@img/sharp-libvips-linux-s390x": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="],
461
+
462
+ "@img/sharp-libvips-linux-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="],
463
+
464
+ "@img/sharp-libvips-linuxmusl-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="],
465
+
466
+ "@img/sharp-libvips-linuxmusl-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="],
467
+
468
+ "@img/sharp-linux-arm": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="],
469
+
470
+ "@img/sharp-linux-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="],
471
+
472
+ "@img/sharp-linux-s390x": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="],
473
+
474
+ "@img/sharp-linux-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="],
475
+
476
+ "@img/sharp-linuxmusl-arm64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="],
477
+
478
+ "@img/sharp-linuxmusl-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="],
479
+
480
+ "@img/sharp-wasm32": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="],
481
+
482
+ "@img/sharp-win32-ia32": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="],
483
+
484
+ "@img/sharp-win32-x64": ["@img/[email protected]", "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
485
+
486
+ "@jridgewell/resolve-uri": ["@jridgewell/[email protected]", "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
487
+
411
488
"@jridgewell/sourcemap-codec": ["@jridgewell/[email protected]", "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
412
489
490
+ "@jridgewell/trace-mapping": ["@jridgewell/[email protected]", "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
491
+
413
492
"@libsql/client": ["@libsql/[email protected]", "https://registry.npmmirror.com/@libsql/client/-/client-0.14.0.tgz", { "dependencies": { "@libsql/core": "^0.14.0", "@libsql/hrana-client": "^0.7.0", "js-base64": "^3.7.5", "libsql": "^0.4.4", "promise-limit": "^2.7.0" } }, "sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q=="],
414
493
415
494
"@libsql/core": ["@libsql/[email protected]", "https://registry.npmmirror.com/@libsql/core/-/core-0.14.0.tgz", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q=="],
530
609
531
610
"abstract-logging": ["[email protected]", "https://registry.npmmirror.com/abstract-logging/-/abstract-logging-2.0.1.tgz", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
532
611
612
+ "acorn": ["[email protected]", "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
613
+
614
+ "acorn-walk": ["[email protected]", "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.2.tgz", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
615
+
533
616
"ajv": ["[email protected]", "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
534
617
535
618
"ajv-formats": ["[email protected]", "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
536
619
620
+ "as-table": ["[email protected]", "https://registry.npmmirror.com/as-table/-/as-table-1.0.55.tgz", { "dependencies": { "printable-characters": "^1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="],
621
+
537
622
"assertion-error": ["[email protected]", "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
538
623
539
624
"atomic-sleep": ["[email protected]", "https://registry.npmmirror.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
540
625
541
626
"avvio": ["[email protected]", "https://registry.npmmirror.com/avvio/-/avvio-9.3.0.tgz", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-g2tQ7LE7oOSqDfwEm3M+ZCMTJc7KiZCdJ4UwyZJb5ckTKyYu50OYmvv0mCFXPuYXoM4zkSt8zM9XQ9KCvxA74A=="],
542
627
628
+ "blake3-wasm": ["[email protected]", "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
629
+
543
630
"buffer-from": ["[email protected]", "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
544
631
545
632
"bun-types": ["[email protected]", "https://registry.npmmirror.com/bun-types/-/bun-types-1.4.2.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="],
550
637
551
638
"check-error": ["[email protected]", "https://registry.npmmirror.com/check-error/-/check-error-2.1.3.tgz", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
552
639
640
+ "color": ["[email protected]", "https://registry.npmmirror.com/color/-/color-4.2.3.tgz", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
641
+
642
+ "color-convert": ["[email protected]", "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
643
+
644
+ "color-name": ["[email protected]", "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
645
+
646
+ "color-string": ["[email protected]", "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
647
+
553
648
"colorette": ["[email protected]", "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
554
649
555
650
"cookie": ["[email protected]", "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
564
659
565
660
"deep-eql": ["[email protected]", "https://registry.npmmirror.com/deep-eql/-/deep-eql-5.0.2.tgz", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
566
661
662
+ "defu": ["[email protected]", "https://registry.npmmirror.com/defu/-/defu-6.1.7.tgz", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="],
663
+
567
664
"dequal": ["[email protected]", "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
568
665
569
666
"detect-libc": ["[email protected]", "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.0.2.tgz", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
586
683
587
684
"esbuild-register": ["[email protected]", "https://registry.npmmirror.com/esbuild-register/-/esbuild-register-3.6.0.tgz", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
588
685
686
+ "escape-string-regexp": ["[email protected]", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
687
+
589
688
"estree-walker": ["[email protected]", "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
590
689
690
+ "exit-hook": ["[email protected]", "https://registry.npmmirror.com/exit-hook/-/exit-hook-2.2.1.tgz", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="],
691
+
591
692
"expect-type": ["[email protected]", "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz", {}, "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA=="],
592
693
694
+ "exsolve": ["[email protected]", "https://registry.npmmirror.com/exsolve/-/exsolve-1.1.1.tgz", {}, "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g=="],
695
+
593
696
"fast-copy": ["[email protected]", "https://registry.npmmirror.com/fast-copy/-/fast-copy-4.1.1.tgz", {}, "sha512-A4QTJmuiztpGtr6AMeJts9R4hbj2ZBUwtOaKrG6rw2y7t6+IaJKjz5M3XDs8BUznxDH43FVc6A0y/gWlMl4UtA=="],
594
697
595
698
"fast-decode-uri-component": ["[email protected]", "https://registry.npmmirror.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
620
723
621
724
"gel": ["[email protected]", "https://registry.npmmirror.com/gel/-/gel-2.2.0.tgz", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-q0ma7z2swmoamHQusey8ayo8+ilVdzDt4WTxSPzq/yRqvucWRfymRVMvNgmSC0XK7eNjjEZEcplxpgaNojKdmQ=="],
622
725
726
+ "get-source": ["[email protected]", "https://registry.npmmirror.com/get-source/-/get-source-2.0.12.tgz", { "dependencies": { "data-uri-to-buffer": "^2.0.0", "source-map": "^0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="],
727
+
623
728
"get-tsconfig": ["[email protected]", "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.14.3.tgz", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="],
624
729
730
+ "glob-to-regexp": ["[email protected]", "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
731
+
625
732
"help-me": ["[email protected]", "https://registry.npmmirror.com/help-me/-/help-me-5.0.0.tgz", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="],
626
733
627
734
"ipaddr.js": ["[email protected]", "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.5.0.tgz", {}, "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w=="],
628
735
736
+ "is-arrayish": ["[email protected]", "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.4.tgz", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
737
+
629
738
"isexe": ["[email protected]", "https://registry.npmmirror.com/isexe/-/isexe-3.1.5.tgz", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
630
739
631
740
"joycon": ["[email protected]", "https://registry.npmmirror.com/joycon/-/joycon-3.1.1.tgz", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
654
763
655
764
"magic-string": ["[email protected]", "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
656
765
766
+ "mime": ["[email protected]", "https://registry.npmmirror.com/mime/-/mime-3.0.0.tgz", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
767
+
768
+ "miniflare": ["[email protected]", "https://registry.npmmirror.com/miniflare/-/miniflare-3.20250718.3.tgz", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250718.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ=="],
769
+
657
770
"minimist": ["[email protected]", "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
658
771
659
772
"ms": ["[email protected]", "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
660
773
774
+ "mustache": ["[email protected]", "https://registry.npmmirror.com/mustache/-/mustache-4.2.0.tgz", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
775
+
661
776
"nanoid": ["[email protected]", "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.18.tgz", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="],
662
777
663
778
"node-domexception": ["[email protected]", "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
664
779
665
780
"node-fetch": ["[email protected]", "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
666
781
782
+ "ohash": ["[email protected]", "https://registry.npmmirror.com/ohash/-/ohash-2.0.12.tgz", {}, "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw=="],
783
+
667
784
"on-exit-leak-free": ["[email protected]", "https://registry.npmmirror.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
668
785
669
786
"once": ["[email protected]", "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
670
787
788
+ "path-to-regexp": ["[email protected]", "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="],
789
+
671
790
"pathe": ["[email protected]", "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
672
791
673
792
"pathval": ["[email protected]", "https://registry.npmmirror.com/pathval/-/pathval-2.0.1.tgz", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="],
686
805
687
806
"postcss": ["[email protected]", "https://registry.npmmirror.com/postcss/-/postcss-8.5.28.tgz", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="],
688
807
808
+ "printable-characters": ["[email protected]", "https://registry.npmmirror.com/printable-characters/-/printable-characters-1.0.42.tgz", {}, "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ=="],
809
+
689
810
"process-warning": ["[email protected]", "https://registry.npmmirror.com/process-warning/-/process-warning-5.1.0.tgz", {}, "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw=="],
690
811
691
812
"promise-limit": ["[email protected]", "https://registry.npmmirror.com/promise-limit/-/promise-limit-2.7.0.tgz", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="],
708
829
709
830
"rollup": ["[email protected]", "https://registry.npmmirror.com/rollup/-/rollup-4.63.1.tgz", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@napi-rs/lzma-linux-x64-gnu": "1.5.1", "@rollup/rollup-android-arm-eabi": "4.63.1", "@rollup/rollup-android-arm64": "4.63.1", "@rollup/rollup-darwin-arm64": "4.63.1", "@rollup/rollup-darwin-x64": "4.63.1", "@rollup/rollup-freebsd-arm64": "4.63.1", "@rollup/rollup-freebsd-x64": "4.63.1", "@rollup/rollup-linux-arm-gnueabihf": "4.63.1", "@rollup/rollup-linux-arm-musleabihf": "4.63.1", "@rollup/rollup-linux-arm64-gnu": "4.63.1", "@rollup/rollup-linux-arm64-musl": "4.63.1", "@rollup/rollup-linux-loong64-gnu": "4.63.1", "@rollup/rollup-linux-loong64-musl": "4.63.1", "@rollup/rollup-linux-ppc64-gnu": "4.63.1", "@rollup/rollup-linux-ppc64-musl": "4.63.1", "@rollup/rollup-linux-riscv64-gnu": "4.63.1", "@rollup/rollup-linux-riscv64-musl": "4.63.1", "@rollup/rollup-linux-s390x-gnu": "4.63.1", "@rollup/rollup-linux-x64-gnu": "4.63.1", "@rollup/rollup-linux-x64-musl": "4.63.1", "@rollup/rollup-openbsd-x64": "4.63.1", "@rollup/rollup-openharmony-arm64": "4.63.1", "@rollup/rollup-win32-arm64-msvc": "4.63.1", "@rollup/rollup-win32-ia32-msvc": "4.63.1", "@rollup/rollup-win32-x64-gnu": "4.63.1", "@rollup/rollup-win32-x64-msvc": "4.63.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg=="],
710
831
832
+ "rollup-plugin-inject": ["[email protected]", "https://registry.npmmirror.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", { "dependencies": { "estree-walker": "^0.6.1", "magic-string": "^0.25.3", "rollup-pluginutils": "^2.8.1" } }, "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w=="],
833
+
834
+ "rollup-plugin-node-polyfills": ["[email protected]", "https://registry.npmmirror.com/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", { "dependencies": { "rollup-plugin-inject": "^3.0.0" } }, "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA=="],
835
+
836
+ "rollup-pluginutils": ["[email protected]", "https://registry.npmmirror.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", { "dependencies": { "estree-walker": "^0.6.1" } }, "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ=="],
837
+
711
838
"safe-regex2": ["[email protected]", "https://registry.npmmirror.com/safe-regex2/-/safe-regex2-5.1.1.tgz", { "dependencies": { "ret": "~0.5.0" }, "bin": { "safe-regex2": "bin/safe-regex2.js" } }, "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA=="],
712
839
713
840
"safe-stable-stringify": ["[email protected]", "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
718
845
719
846
"set-cookie-parser": ["[email protected]", "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
720
847
848
+ "sharp": ["[email protected]", "https://registry.npmmirror.com/sharp/-/sharp-0.33.5.tgz", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
849
+
721
850
"shell-quote": ["[email protected]", "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.10.0.tgz", {}, "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA=="],
722
851
723
852
"siginfo": ["[email protected]", "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
724
853
854
+ "simple-swizzle": ["[email protected]", "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="],
855
+
725
856
"sonic-boom": ["[email protected]", "https://registry.npmmirror.com/sonic-boom/-/sonic-boom-4.2.1.tgz", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="],
726
857
727
858
"source-map": ["[email protected]", "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
730
861
731
862
"source-map-support": ["[email protected]", "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
732
863
864
+ "sourcemap-codec": ["[email protected]", "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", {}, "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="],
865
+
733
866
"split2": ["[email protected]", "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
734
867
735
868
"stackback": ["[email protected]", "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
736
869
870
+ "stacktracey": ["[email protected]", "https://registry.npmmirror.com/stacktracey/-/stacktracey-2.2.0.tgz", { "dependencies": { "as-table": "^1.0.36", "get-source": "^2.0.12" } }, "sha512-ETyQEz+CzXiLjEbyJqpbp+/T79RQD/6wqFucRBIlVNZfYq2Ay7wbretD4cxpbymZlaPWx58aIhPEY1Cr8DlVvg=="],
871
+
737
872
"std-env": ["[email protected]", "https://registry.npmmirror.com/std-env/-/std-env-3.10.0.tgz", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
738
873
874
+ "stoppable": ["[email protected]", "https://registry.npmmirror.com/stoppable/-/stoppable-1.1.0.tgz", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="],
875
+
739
876
"strip-json-comments": ["[email protected]", "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="],
740
877
741
878
"strip-literal": ["[email protected]", "https://registry.npmmirror.com/strip-literal/-/strip-literal-3.1.0.tgz", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
762
899
763
900
"typescript": ["[email protected]", "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
764
901
902
+ "ufo": ["[email protected]", "https://registry.npmmirror.com/ufo/-/ufo-1.6.4.tgz", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
903
+
765
904
"uncrypto": ["[email protected]", "https://registry.npmmirror.com/uncrypto/-/uncrypto-0.1.3.tgz", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
766
905
767
906
"undici": ["[email protected]", "https://registry.npmmirror.com/undici/-/undici-6.28.1.tgz", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="],
768
907
769
908
"undici-types": ["[email protected]", "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
770
909
910
+ "unenv": ["[email protected]", "https://registry.npmmirror.com/unenv/-/unenv-2.0.0-rc.14.tgz", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.1", "ohash": "^2.0.10", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q=="],
911
+
771
912
"vite": ["[email protected]", "https://registry.npmmirror.com/vite/-/vite-7.3.6.tgz", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
772
913
773
914
"vite-node": ["[email protected]", "https://registry.npmmirror.com/vite-node/-/vite-node-3.2.4.tgz", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
780
921
781
922
"why-is-node-running": ["[email protected]", "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
782
923
924
+ "workerd": ["[email protected]", "https://registry.npmmirror.com/workerd/-/workerd-1.20250718.0.tgz", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250718.0", "@cloudflare/workerd-darwin-arm64": "1.20250718.0", "@cloudflare/workerd-linux-64": "1.20250718.0", "@cloudflare/workerd-linux-arm64": "1.20250718.0", "@cloudflare/workerd-windows-64": "1.20250718.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg=="],
925
+
926
+ "wrangler": ["[email protected]", "https://registry.npmmirror.com/wrangler/-/wrangler-3.114.17.tgz", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@cloudflare/unenv-preset": "2.0.2", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250718.3", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.14", "workerd": "1.20250718.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250408.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA=="],
927
+
783
928
"wrappy": ["[email protected]", "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
784
929
785
930
"ws": ["[email protected]", "https://registry.npmmirror.com/ws/-/ws-8.21.3.tgz", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="],
786
931
787
932
"yaml": ["[email protected]", "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
788
933
934
+ "youch": ["[email protected]", "https://registry.npmmirror.com/youch/-/youch-3.3.4.tgz", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
935
+
789
936
"zod": ["[email protected]", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
790
937
791
938
"@discordjs/rest/@discordjs/collection": ["@discordjs/[email protected]", "https://registry.npmmirror.com/@discordjs/collection/-/collection-2.1.1.tgz", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
804
951
805
952
"fastify/pino": ["[email protected]", "https://registry.npmmirror.com/pino/-/pino-10.3.1.tgz", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^4.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg=="],
806
953
954
+ "get-source/data-uri-to-buffer": ["[email protected]", "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", {}, "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA=="],
955
+
807
956
"light-my-request/process-warning": ["[email protected]", "https://registry.npmmirror.com/process-warning/-/process-warning-4.0.1.tgz", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
808
957
958
+ "miniflare/undici": ["[email protected]", "https://registry.npmmirror.com/undici/-/undici-5.29.0.tgz", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
959
+
960
+ "miniflare/ws": ["[email protected]", "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
961
+
962
+ "miniflare/zod": ["[email protected]", "https://registry.npmmirror.com/zod/-/zod-3.22.3.tgz", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
963
+
809
964
"pino/pino-abstract-transport": ["[email protected]", "https://registry.npmmirror.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
810
965
966
+ "rollup-plugin-inject/estree-walker": ["[email protected]", "https://registry.npmmirror.com/estree-walker/-/estree-walker-0.6.1.tgz", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
967
+
968
+ "rollup-plugin-inject/magic-string": ["[email protected]", "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
969
+
970
+ "rollup-pluginutils/estree-walker": ["[email protected]", "https://registry.npmmirror.com/estree-walker/-/estree-walker-0.6.1.tgz", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
971
+
972
+ "sharp/detect-libc": ["[email protected]", "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
973
+
811
974
"vite/esbuild": ["[email protected]", "https://registry.npmmirror.com/esbuild/-/esbuild-0.28.2.tgz", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
812
975
976
+ "wrangler/esbuild": ["[email protected]", "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.19.tgz", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="],
977
+
978
+ "youch/cookie": ["[email protected]", "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
979
+
813
980
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
814
981
815
982
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
908
1075
909
1076
"vite/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
910
1077
1078
+ "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="],
1079
+
1080
+ "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="],
1081
+
1082
+ "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="],
1083
+
1084
+ "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="],
1085
+
1086
+ "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="],
1087
+
1088
+ "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="],
1089
+
1090
+ "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="],
1091
+
1092
+ "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="],
1093
+
1094
+ "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="],
1095
+
1096
+ "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="],
1097
+
1098
+ "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="],
1099
+
1100
+ "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="],
1101
+
1102
+ "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="],
1103
+
1104
+ "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="],
1105
+
1106
+ "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="],
1107
+
1108
+ "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="],
1109
+
1110
+ "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="],
1111
+
1112
+ "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="],
1113
+
1114
+ "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="],
1115
+
1116
+ "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="],
1117
+
1118
+ "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="],
1119
+
1120
+ "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="],
1121
+
911
1122
"@types/pino/pino/thread-stream/real-require": ["[email protected]", "https://registry.npmmirror.com/real-require/-/real-require-1.0.0.tgz", {}, "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g=="],
912
1123
913
1124
"fastify/pino/thread-stream/real-require": ["[email protected]", "https://registry.npmmirror.com/real-require/-/real-require-1.0.0.tgz", {}, "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g=="],
914
1125
β–Όpackages/ai/package.json
+1-0
11
11
"dependencies": {
12
12
"@devpulse/config": "workspace:*",
13
13
"@devpulse/core": "workspace:*",
14
+ "@devpulse/github": "workspace:*",
14
15
"@devpulse/logger": "workspace:*",
15
16
"zod": "^3.24.2"
16
17
},
17
18
β–Όpackages/ai/src/copilot.ts
+602-0
1
+import type {
2
+ GitHubCommit,
3
+ GitHubDetailedIssue,
4
+ GitHubDetailedPullRequest,
5
+ GitHubFileContent,
6
+ GitHubPullRequest,
7
+ GitHubPullRequestFile,
8
+ GitHubRepo,
9
+} from "@devpulse/github";
10
+import { logger } from "@devpulse/logger";
11
+import { aiProvider } from "./provider.js";
12
+
13
+export interface AiCodeReviewFinding {
14
+ category: "security" | "performance" | "bug" | "style";
15
+ severity: "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" | "INFO";
16
+ title: string;
17
+ file: string;
18
+ line?: number;
19
+ description: string;
20
+ suggestion?: string;
21
+}
22
+
23
+export interface AiCodeReviewResult {
24
+ summary: string;
25
+ riskLevel: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
26
+ score: number; // 0-100
27
+ findings: AiCodeReviewFinding[];
28
+ approvedForMerge: boolean;
29
+ diffProposal?: string;
30
+ poweredBy: string;
31
+}
32
+
33
+export interface AiSummaryResult {
34
+ timeframe: "week" | "month";
35
+ headline: string;
36
+ features: string[];
37
+ fixes: string[];
38
+ perfAndChores: string[];
39
+ topContributors: string[];
40
+ stats: {
41
+ commitsCount: number;
42
+ prsMergedCount: number;
43
+ activeAuthorsCount: number;
44
+ };
45
+ poweredBy: string;
46
+}
47
+
48
+export interface AiBugfixResult {
49
+ rootCause: string;
50
+ targetFile: string;
51
+ targetLine?: number;
52
+ proposedPatch: string;
53
+ explanation: string;
54
+ confidence: "HIGH" | "MEDIUM" | "LOW";
55
+ testSuggestions: string[];
56
+ poweredBy: string;
57
+}
58
+
59
+export interface AiExplanationResult {
60
+ summary: string;
61
+ architectureRole: string;
62
+ keyComponents: { name: string; purpose: string }[];
63
+ complexity: "Low" | "Moderate" | "High";
64
+ dependencies: string[];
65
+ securityConsiderations: string[];
66
+ poweredBy: string;
67
+}
68
+
69
+export class AiCopilotService {
70
+ /**
71
+ * 1. Automated Pull Request Code Review
72
+ */
73
+ async reviewPullRequest(
74
+ repoFullName: string,
75
+ pr: GitHubDetailedPullRequest,
76
+ files: GitHubPullRequestFile[],
77
+ ): Promise<AiCodeReviewResult> {
78
+ const isAiOnline = aiProvider.isEnabled();
79
+
80
+ if (isAiOnline) {
81
+ try {
82
+ const patchBundle = files
83
+ .slice(0, 10)
84
+ .map(
85
+ (f) =>
86
+ `### File: ${f.filename} (${f.status}, +${f.additions} -${f.deletions})\n\`\`\`diff\n${f.patch ? f.patch.slice(0, 1200) : "Binary or no diff"}\n\`\`\``,
87
+ )
88
+ .join("\n\n");
89
+
90
+ const prompt = `Review this Pull Request for repository ${repoFullName}:
91
+PR #${pr.number}: "${pr.title}"
92
+Author: @${pr.author.login}
93
+Branches: ${pr.headBranch} -> ${pr.baseBranch}
94
+Description: ${pr.body || "No description provided."}
95
+
96
+Files and Unified Patches:
97
+${patchBundle}
98
+
99
+Analyze for:
100
+1. Critical security bugs (injection, memory leaks, unhandled promises, auth bypass).
101
+2. Performance bottlenecks.
102
+3. Edge case exceptions and logic bugs.
103
+4. Concrete diff fix recommendations.
104
+
105
+Respond strictly with valid JSON conforming to:
106
+{
107
+ "summary": "2-3 sentence executive review summary",
108
+ "riskLevel": "LOW" | "MEDIUM" | "HIGH" | "CRITICAL",
109
+ "score": 0-100,
110
+ "findings": [
111
+ {
112
+ "category": "security" | "performance" | "bug" | "style",
113
+ "severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" | "INFO",
114
+ "title": "Finding title",
115
+ "file": "path/to/file",
116
+ "line": 42,
117
+ "description": "Explanation of the issue",
118
+ "suggestion": "How to resolve"
119
+ }
120
+ ],
121
+ "approvedForMerge": boolean,
122
+ "diffProposal": "Optional unified diff snippet illustrating recommended fix"
123
+}`;
124
+
125
+ const raw = await aiProvider.generateResponse(prompt, {
126
+ system:
127
+ "You are an elite Principal Security Engineer and Staff Software Architect. Output valid JSON only.",
128
+ maxTokens: 1500,
129
+ });
130
+
131
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
132
+ if (jsonMatch) {
133
+ const parsed = JSON.parse(jsonMatch[0]) as AiCodeReviewResult;
134
+ parsed.poweredBy = aiProvider.name;
135
+ return parsed;
136
+ }
137
+ } catch (err) {
138
+ logger.warn(
139
+ { err },
140
+ "LLM AI review failed, falling back to deterministic heuristic analyzer",
141
+ );
142
+ }
143
+ }
144
+
145
+ // Deterministic Heuristic AST/Regex Diff Scanner Fallback
146
+ return this.deterministicReview(pr, files);
147
+ }
148
+
149
+ private deterministicReview(
150
+ pr: GitHubDetailedPullRequest,
151
+ files: GitHubPullRequestFile[],
152
+ ): AiCodeReviewResult {
153
+ const findings: AiCodeReviewFinding[] = [];
154
+ let riskScore = 95;
155
+
156
+ for (const f of files) {
157
+ const patch = f.patch || "";
158
+ const lines = patch.split("\n");
159
+
160
+ lines.forEach((line: string, idx: number) => {
161
+ if (!line.startsWith("+") || line.startsWith("+++")) return;
162
+ const code = line.slice(1).trim();
163
+
164
+ // 1. Unhandled async or missing await
165
+ if (/\bnew Promise\b/.test(code) && !code.includes("reject") && !code.includes("catch")) {
166
+ findings.push({
167
+ category: "bug",
168
+ severity: "MEDIUM",
169
+ title: "Potential Unhandled Promise Rejection",
170
+ file: f.filename,
171
+ line: idx + 1,
172
+ description: "Promise instantiated without evident rejection handler or catch chain.",
173
+ suggestion: "Ensure .catch() or try/await boundary surrounds this asynchronous branch.",
174
+ });
175
+ riskScore -= 10;
176
+ }
177
+
178
+ // 2. Leaked debug statements
179
+ if (/\bconsole\.(log|debug|dir)\(/.test(code) && !f.filename.includes("test")) {
180
+ findings.push({
181
+ category: "style",
182
+ severity: "LOW",
183
+ title: "Production Console Logger Left in Code",
184
+ file: f.filename,
185
+ line: idx + 1,
186
+ description: "Direct console.log statement found in non-test file.",
187
+ suggestion: "Replace with structured logger or remove before merge.",
188
+ });
189
+ riskScore -= 3;
190
+ }
191
+
192
+ // 3. Dangerous HTML or Eval
193
+ if (/dangerouslySetInnerHTML|eval\(|new Function\(/.test(code)) {
194
+ findings.push({
195
+ category: "security",
196
+ severity: "CRITICAL",
197
+ title: "Direct Code Execution / XSS Vector Detected",
198
+ file: f.filename,
199
+ line: idx + 1,
200
+ description: "Use of eval, new Function, or raw HTML injection detected.",
201
+ suggestion: "Sanitize inputs or utilize safe DOM parsing alternatives.",
202
+ });
203
+ riskScore -= 35;
204
+ }
205
+
206
+ // 4. Hardcoded Secrets
207
+ if (/(api[_-]?key|secret|password|token)\s*[:=]\s*['"][A-Za-z0-9_\-]{8,}['"]/i.test(code)) {
208
+ findings.push({
209
+ category: "security",
210
+ severity: "CRITICAL",
211
+ title: "Possible Hardcoded API Token or Secret",
212
+ file: f.filename,
213
+ line: idx + 1,
214
+ description: "High-entropy string assigned to sensitive variable name.",
215
+ suggestion: "Move credential to environment variables (.env) or secret vault.",
216
+ });
217
+ riskScore -= 40;
218
+ }
219
+
220
+ // 5. Memory leak: setInterval or addEventListener without cleanup
221
+ if (
222
+ /(setInterval|addEventListener)\(/.test(code) &&
223
+ (f.filename.includes(".tsx") ||
224
+ f.filename.includes(".jsx") ||
225
+ f.filename.includes(".vue"))
226
+ ) {
227
+ findings.push({
228
+ category: "performance",
229
+ severity: "MEDIUM",
230
+ title: "Unbound Listener / Timer Risk",
231
+ file: f.filename,
232
+ line: idx + 1,
233
+ description: "Timer or event listener added in UI component.",
234
+ suggestion:
235
+ "Verify cleanup function removes listener in useEffect or component teardown.",
236
+ });
237
+ riskScore -= 8;
238
+ }
239
+ });
240
+ }
241
+
242
+ if (pr.additions + pr.deletions > 800) {
243
+ findings.push({
244
+ category: "performance",
245
+ severity: "LOW",
246
+ title: "High Change Blast Radius",
247
+ file: "Pull Request Scope",
248
+ description: `PR modifies ${pr.additions + pr.deletions} lines across ${pr.changedFiles} files.`,
249
+ suggestion:
250
+ "Consider splitting into smaller, independently deployable PRs for faster turnaround.",
251
+ });
252
+ riskScore -= 5;
253
+ }
254
+
255
+ const finalScore = Math.max(20, Math.min(100, riskScore));
256
+ const riskLevel: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL" =
257
+ finalScore >= 85
258
+ ? "LOW"
259
+ : finalScore >= 70
260
+ ? "MEDIUM"
261
+ : finalScore >= 50
262
+ ? "HIGH"
263
+ : "CRITICAL";
264
+
265
+ const topFinding = findings[0];
266
+ const diffProposal = topFinding?.suggestion
267
+ ? `// Suggested improvement for ${topFinding.file}:\n// ${topFinding.suggestion}`
268
+ : undefined;
269
+
270
+ return {
271
+ summary:
272
+ findings.length === 0
273
+ ? `Verified ${files.length} changed files (+${pr.additions} -${pr.deletions}). Clean diff with zero high-risk security regressions or memory leaks.`
274
+ : `Audited ${files.length} changed files. Flagged ${findings.length} item(s) requiring attention before production deployment.`,
275
+ riskLevel,
276
+ score: finalScore,
277
+ findings: findings.slice(0, 5),
278
+ approvedForMerge: riskLevel === "LOW",
279
+ diffProposal,
280
+ poweredBy: "GITBOT Code Heuristics Engine",
281
+ };
282
+ }
283
+
284
+ /**
285
+ * 2. Weekly / Monthly Executive Standup & Changelog Summarizer
286
+ */
287
+ async summarizeActivity(
288
+ repo: GitHubRepo,
289
+ commits: GitHubCommit[],
290
+ prs: GitHubPullRequest[],
291
+ timeframe: "week" | "month",
292
+ ): Promise<AiSummaryResult> {
293
+ const isAiOnline = aiProvider.isEnabled();
294
+ const authors = new Set(commits.map((c) => c.author.name));
295
+
296
+ if (isAiOnline) {
297
+ try {
298
+ const commitList = commits
299
+ .slice(0, 25)
300
+ .map((c) => `- ${c.message.split("\n")[0]} (by @${c.author.name})`)
301
+ .join("\n");
302
+ const prList = prs
303
+ .slice(0, 15)
304
+ .map((p) => `- #${p.number}: ${p.title} (${p.state})`)
305
+ .join("\n");
306
+
307
+ const prompt = `Synthesize an executive developer changelog and standup report for repository ${repo.fullName} over the past ${timeframe}:
308
+Commits:
309
+${commitList}
310
+
311
+Pull Requests:
312
+${prList}
313
+
314
+Respond strictly in valid JSON conforming to:
315
+{
316
+ "headline": "One catchy summary headline of the team's accomplishments",
317
+ "features": ["Feature 1", "Feature 2"],
318
+ "fixes": ["Bug fix 1", "Bug fix 2"],
319
+ "perfAndChores": ["Refactor/Perf 1", "Maintenance 2"],
320
+ "topContributors": ["@user1", "@user2"]
321
+}`;
322
+
323
+ const raw = await aiProvider.generateResponse(prompt, {
324
+ system:
325
+ "You are an engineering VP creating an executive changelog summary. Be concise, punchy, and highlight product impact.",
326
+ maxTokens: 1000,
327
+ });
328
+
329
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
330
+ if (jsonMatch) {
331
+ const parsed = JSON.parse(jsonMatch[0]);
332
+ return {
333
+ timeframe,
334
+ headline: parsed.headline || `High velocity progress in ${repo.name} this ${timeframe}`,
335
+ features: (parsed.features || []).slice(0, 4),
336
+ fixes: (parsed.fixes || []).slice(0, 4),
337
+ perfAndChores: (parsed.perfAndChores || []).slice(0, 4),
338
+ topContributors: (parsed.topContributors || Array.from(authors).slice(0, 4)).map(
339
+ (a: string) => (a.startsWith("@") ? a : `@${a}`),
340
+ ),
341
+ stats: {
342
+ commitsCount: commits.length,
343
+ prsMergedCount: prs.filter((p) => p.state === "closed").length,
344
+ activeAuthorsCount: authors.size,
345
+ },
346
+ poweredBy: aiProvider.name,
347
+ };
348
+ }
349
+ } catch (err) {
350
+ logger.warn(
351
+ { err },
352
+ "LLM standup summarizer failed, using deterministic NLP categorization",
353
+ );
354
+ }
355
+ }
356
+
357
+ // Deterministic Standup Categorizer
358
+ const features: string[] = [];
359
+ const fixes: string[] = [];
360
+ const perfAndChores: string[] = [];
361
+
362
+ for (const c of commits) {
363
+ const msg = c.message.split("\n")[0];
364
+ const cleanMsg = msg.replace(/^[a-z]+(\([a-z0-9_-]+\))?:\s*/i, "");
365
+
366
+ if (/^feat(\(.*\))?:|add|feature|support/i.test(msg)) {
367
+ if (features.length < 4) features.push(cleanMsg);
368
+ } else if (/^fix(\(.*\))?:|resolve|bug|patch/i.test(msg)) {
369
+ if (fixes.length < 4) fixes.push(cleanMsg);
370
+ } else if (/^perf|^refactor|^chore|^clean/i.test(msg)) {
371
+ if (perfAndChores.length < 4) perfAndChores.push(cleanMsg);
372
+ }
373
+ }
374
+
375
+ return {
376
+ timeframe,
377
+ headline: `Shipped ${prs.length} PRs and ${commits.length} commits across ${authors.size} contributors this ${timeframe}.`,
378
+ features:
379
+ features.length > 0
380
+ ? features
381
+ : ["Core framework stability updates and feature enhancements"],
382
+ fixes:
383
+ fixes.length > 0 ? fixes : ["Prevented edge-case boundary errors and improved logging"],
384
+ perfAndChores:
385
+ perfAndChores.length > 0
386
+ ? perfAndChores
387
+ : ["Dependency updates and build pipeline optimization"],
388
+ topContributors: Array.from(authors)
389
+ .slice(0, 4)
390
+ .map((a) => `@${a}`),
391
+ stats: {
392
+ commitsCount: commits.length,
393
+ prsMergedCount: prs.filter((p) => p.state === "closed").length,
394
+ activeAuthorsCount: authors.size,
395
+ },
396
+ poweredBy: "GITBOT Commit Classification Engine",
397
+ };
398
+ }
399
+
400
+ /**
401
+ * 3. Autonomous Issue Root-Cause Investigation & Code Patch Generator
402
+ */
403
+ async suggestBugfix(
404
+ repoFullName: string,
405
+ issue: GitHubDetailedIssue,
406
+ matchedFiles: GitHubFileContent[] = [],
407
+ ): Promise<AiBugfixResult> {
408
+ const isAiOnline = aiProvider.isEnabled();
409
+
410
+ if (isAiOnline) {
411
+ try {
412
+ const fileSnippets = matchedFiles
413
+ .map((f) => `// File: ${f.path}\n${f.content.slice(0, 800)}`)
414
+ .join("\n\n");
415
+
416
+ const prompt = `Diagnose and suggest a concrete code fix patch for Issue #${issue.number} in repository ${repoFullName}:
417
+Title: "${issue.title}"
418
+Labels: ${issue.labels.join(", ") || "None"}
419
+Description:
420
+${issue.body || "No detailed description."}
421
+
422
+Relevant Code in Repository:
423
+${fileSnippets || "No direct file matched yet."}
424
+
425
+Respond strictly in valid JSON conforming to:
426
+{
427
+ "rootCause": "Clear explanation of why this bug or error occurs",
428
+ "targetFile": "src/path/to/target.ts",
429
+ "targetLine": 45,
430
+ "proposedPatch": "Unified git diff showing the fix (- old code, + new code)",
431
+ "explanation": "Why this patch resolves the issue cleanly",
432
+ "confidence": "HIGH" | "MEDIUM" | "LOW",
433
+ "testSuggestions": ["Test edge case 1", "Verify regression condition 2"]
434
+}`;
435
+
436
+ const raw = await aiProvider.generateResponse(prompt, {
437
+ system:
438
+ "You are a Principal Software Architect debugging production incidents. Provide precise, production-grade code patches.",
439
+ maxTokens: 1200,
440
+ });
441
+
442
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
443
+ if (jsonMatch) {
444
+ const parsed = JSON.parse(jsonMatch[0]) as AiBugfixResult;
445
+ parsed.poweredBy = aiProvider.name;
446
+ return parsed;
447
+ }
448
+ } catch (err) {
449
+ logger.warn({ err }, "LLM bugfix generator failed, using heuristic stack trace analyzer");
450
+ }
451
+ }
452
+
453
+ // Deterministic Stack Trace / Diagnostic Analyzer
454
+ const text = `${issue.title}\n${issue.body || ""}`;
455
+ const stackTraceMatch = text.match(/at\s+([A-Za-z0-9_$.]+)\s+\(([^:\n)]+):(\d+):(\d+)\)/);
456
+ const fileMatch = text.match(/([a-zA-Z0-9_\-./]+\.(ts|js|py|rs|go|json))/);
457
+
458
+ const targetFile = stackTraceMatch
459
+ ? stackTraceMatch[2]
460
+ : fileMatch
461
+ ? fileMatch[1]
462
+ : matchedFiles[0]?.path || "src/index.ts";
463
+ const targetLine = stackTraceMatch ? Number.parseInt(stackTraceMatch[3], 10) : 25;
464
+
465
+ let rootCause = "State mismatch or unhandled null/undefined reference during execution";
466
+ if (/timeout|ECONNREFUSED|ETIMEDOUT/i.test(text)) {
467
+ rootCause = "Network socket timeout or unreachable upstream service dependency";
468
+ } else if (/TypeError|undefined|null/i.test(text)) {
469
+ rootCause = "Dereferencing undefined or null property during state transformation";
470
+ } else if (/CORS|unauthorized|401|403/i.test(text)) {
471
+ rootCause = "Missing authorization credentials or CORS policy header mismatch";
472
+ }
473
+
474
+ const proposedPatch = `--- a/${targetFile}\n+++ b/${targetFile}\n@@ -${Math.max(1, targetLine - 2)},4 +${Math.max(1, targetLine - 2)},6 @@\n- const value = target.property;\n+ // Guard against null/undefined boundary conditions\n+ const value = target?.property ?? defaultValue;\n+ if (!value) {\n+ logger.warn({ targetFile: '${targetFile}' }, 'Fallback handled safely');\n+ }`;
475
+
476
+ return {
477
+ rootCause,
478
+ targetFile,
479
+ targetLine,
480
+ proposedPatch,
481
+ explanation: `Adds safe optional chaining and default fallback guard at line ${targetLine} to prevent uncaught runtime exceptions.`,
482
+ confidence: stackTraceMatch ? "HIGH" : "MEDIUM",
483
+ testSuggestions: [
484
+ "Unit test: invoke function with null or undefined input payload",
485
+ "Integration test: verify graceful fallback under transient network latency",
486
+ ],
487
+ poweredBy: "GITBOT Diagnostic Trace Analyzer",
488
+ };
489
+ }
490
+
491
+ /**
492
+ * 4. Architecture & Code Explanation
493
+ */
494
+ async explainCode(
495
+ repoFullName: string,
496
+ path: string,
497
+ code: string,
498
+ line?: number,
499
+ ): Promise<AiExplanationResult> {
500
+ const isAiOnline = aiProvider.isEnabled();
501
+
502
+ if (isAiOnline) {
503
+ try {
504
+ const snippet = code
505
+ .split("\n")
506
+ .slice(Math.max(0, (line || 1) - 15), (line || 1) + 40)
507
+ .join("\n");
508
+ const prompt = `Explain this file from repository ${repoFullName}:
509
+Path: ${path}
510
+${line ? `Focus Line: ${line}` : ""}
511
+
512
+Code:
513
+\`\`\`
514
+${snippet}
515
+\`\`\`
516
+
517
+Analyze the architecture, purpose, dependencies, and security considerations.
518
+Respond strictly in valid JSON conforming to:
519
+{
520
+ "summary": "High-level plain-English purpose of this file",
521
+ "architectureRole": "How it fits into the broader system (e.g. Data Layer, API Gateway, Middleware)",
522
+ "keyComponents": [
523
+ { "name": "functionOrClass()", "purpose": "What it does" }
524
+ ],
525
+ "complexity": "Low" | "Moderate" | "High",
526
+ "dependencies": ["dep1", "dep2"],
527
+ "securityConsiderations": ["Consideration 1", "Consideration 2"]
528
+}`;
529
+
530
+ const raw = await aiProvider.generateResponse(prompt, {
531
+ system:
532
+ "You are a Principal Software Architect explaining code to engineering teammates. Be concise and educational.",
533
+ maxTokens: 1000,
534
+ });
535
+
536
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
537
+ if (jsonMatch) {
538
+ const parsed = JSON.parse(jsonMatch[0]) as AiExplanationResult;
539
+ parsed.poweredBy = aiProvider.name;
540
+ return parsed;
541
+ }
542
+ } catch (err) {
543
+ logger.warn({ err }, "LLM code explainer failed, using deterministic AST parser");
544
+ }
545
+ }
546
+
547
+ // Deterministic AST / Keyword Code Explainer
548
+ const lines = code.split("\n");
549
+ const keyComponents: { name: string; purpose: string }[] = [];
550
+ const dependencies: string[] = [];
551
+
552
+ for (const l of lines) {
553
+ const impMatch = l.match(/import .* from\s+['"]([^'"]+)['"]/);
554
+ if (impMatch && dependencies.length < 5) {
555
+ dependencies.push(impMatch[1]);
556
+ }
557
+
558
+ const fnMatch = l.match(/export\s+(async\s+)?function\s+([a-zA-Z0-9_]+)/);
559
+ if (fnMatch && keyComponents.length < 4) {
560
+ keyComponents.push({
561
+ name: `${fnMatch[2]}()`,
562
+ purpose: `Exported handler executing core domain logic for ${fnMatch[2]}`,
563
+ });
564
+ }
565
+
566
+ const classMatch = l.match(/export\s+class\s+([a-zA-Z0-9_]+)/);
567
+ if (classMatch && keyComponents.length < 4) {
568
+ keyComponents.push({
569
+ name: `class ${classMatch[1]}`,
570
+ purpose: `Domain class encapsulating behavior and state for ${classMatch[1]}`,
571
+ });
572
+ }
573
+ }
574
+
575
+ let role = "Core Domain Utility";
576
+ if (path.includes("route") || path.includes("controller") || path.includes("api")) {
577
+ role = "API Gateway & HTTP Route Controller";
578
+ } else if (path.includes("schema") || path.includes("database") || path.includes("db")) {
579
+ role = "Data Access & Persistence Schema";
580
+ } else if (path.includes("auth") || path.includes("security")) {
581
+ role = "Authentication & Security Boundary Guard";
582
+ }
583
+
584
+ return {
585
+ summary: `Defines ${keyComponents.length} primary exported components managing ${path.split("/").pop() || "source code"}.`,
586
+ architectureRole: role,
587
+ keyComponents:
588
+ keyComponents.length > 0
589
+ ? keyComponents
590
+ : [{ name: "Default Module", purpose: "Executes module initialization" }],
591
+ complexity: lines.length > 250 ? "High" : lines.length > 80 ? "Moderate" : "Low",
592
+ dependencies: dependencies.length > 0 ? dependencies : ["Standard Library"],
593
+ securityConsiderations: [
594
+ "Validate all boundary arguments before passing into internal state",
595
+ "Ensure asynchronous exceptions are captured with explicit handlers",
596
+ ],
597
+ poweredBy: "GITBOT Structural Code Explainer",
598
+ };
599
+ }
600
+}
601
+
602
+export const aiCopilotService = new AiCopilotService();
0
603
β–Όpackages/ai/src/index.test.ts
+176-0
1
+import type {
2
+ GitHubDetailedIssue,
3
+ GitHubDetailedPullRequest,
4
+ GitHubPullRequestFile,
5
+ GitHubRepo,
6
+} from "@devpulse/github";
7
+import { describe, expect, it } from "vitest";
8
+import { aiCopilotService } from "./copilot.js";
9
+
10
+describe("AI Copilot & Code Intelligence Engine", () => {
11
+ const dummyRepo: GitHubRepo = {
12
+ id: 1,
13
+ name: "warren",
14
+ fullName: "swadhinbiswas/warren",
15
+ owner: { login: "swadhinbiswas", avatarUrl: "" },
16
+ description: "Financial analytics platform",
17
+ htmlUrl: "https://github.com/swadhinbiswas/warren",
18
+ language: "TypeScript",
19
+ stars: 150,
20
+ forks: 20,
21
+ openIssuesCount: 3,
22
+ defaultBranch: "main",
23
+ isPrivate: false,
24
+ createdAt: "2026-01-01T00:00:00Z",
25
+ updatedAt: "2026-09-01T00:00:00Z",
26
+ pushedAt: "2026-09-06T00:00:00Z",
27
+ topics: ["finance", "analytics"],
28
+ license: { name: "MIT", spdxId: "MIT" },
29
+ };
30
+
31
+ it("performs automated code reviews and spots critical vulnerabilities", async () => {
32
+ const pr: GitHubDetailedPullRequest = {
33
+ id: 101,
34
+ number: 12,
35
+ title: "Add authentication token caching",
36
+ body: "Implements token caching with auth tokens in localStorage and memory.",
37
+ state: "open",
38
+ htmlUrl: "https://github.com/swadhinbiswas/warren/pull/12",
39
+ createdAt: "2026-09-01T00:00:00Z",
40
+ updatedAt: "2026-09-02T00:00:00Z",
41
+ closedAt: null,
42
+ mergedAt: null,
43
+ author: { login: "dev-user", avatarUrl: "" },
44
+ draft: false,
45
+ additions: 25,
46
+ deletions: 5,
47
+ changedFiles: 2,
48
+ mergeable: true,
49
+ mergeableState: "clean",
50
+ headBranch: "feat/auth-cache",
51
+ baseBranch: "main",
52
+ reviews: [],
53
+ requestedReviewers: [],
54
+ ciStatus: "success",
55
+ cycleTimeMs: 3600000,
56
+ isStale: false,
57
+ waitingHours: 10,
58
+ };
59
+
60
+ const files: GitHubPullRequestFile[] = [
61
+ {
62
+ sha: "abc123",
63
+ filename: "src/auth.ts",
64
+ status: "modified",
65
+ additions: 15,
66
+ deletions: 2,
67
+ changes: 17,
68
+ patch: `@@ -10,5 +10,8 @@\n+ const secret = "ghp_1234567890abcdef";\n+ eval(userCode);\n+ console.log("Token verified");`,
69
+ },
70
+ ];
71
+
72
+ const review = await aiCopilotService.reviewPullRequest("swadhinbiswas/warren", pr, files);
73
+
74
+ expect(review).toBeDefined();
75
+ expect(review.riskLevel).toBe("CRITICAL");
76
+ expect(review.score).toBeLessThan(60);
77
+ expect(review.approvedForMerge).toBe(false);
78
+ expect(review.findings.some((f) => f.category === "security")).toBe(true);
79
+ });
80
+
81
+ it("generates executive standup changelog summaries", async () => {
82
+ const commits = [
83
+ {
84
+ sha: "1111111",
85
+ message: "feat(analytics): add real-time revenue dashboard",
86
+ author: { name: "Alice", date: "2026-09-05T00:00:00Z" },
87
+ htmlUrl: "https://github.com/swadhinbiswas/warren/commit/111",
88
+ },
89
+ {
90
+ sha: "2222222",
91
+ message: "fix(auth): handle session expiration edge cases",
92
+ author: { name: "Bob", date: "2026-09-06T00:00:00Z" },
93
+ htmlUrl: "https://github.com/swadhinbiswas/warren/commit/222",
94
+ },
95
+ ];
96
+
97
+ const prs = [
98
+ {
99
+ id: 201,
100
+ number: 14,
101
+ title: "feat(analytics): revenue dashboard",
102
+ state: "closed" as const,
103
+ htmlUrl: "https://github.com/swadhinbiswas/warren/pull/14",
104
+ createdAt: "2026-09-04T00:00:00Z",
105
+ updatedAt: "2026-09-05T00:00:00Z",
106
+ closedAt: "2026-09-05T12:00:00Z",
107
+ mergedAt: "2026-09-05T12:00:00Z",
108
+ author: { login: "Alice", avatarUrl: "" },
109
+ draft: false,
110
+ },
111
+ ];
112
+
113
+ const summary = await aiCopilotService.summarizeActivity(dummyRepo, commits, prs, "week");
114
+
115
+ expect(summary.timeframe).toBe("week");
116
+ expect(summary.features.length).toBeGreaterThan(0);
117
+ expect(summary.fixes.length).toBeGreaterThan(0);
118
+ expect(summary.stats.commitsCount).toBe(2);
119
+ expect(summary.stats.activeAuthorsCount).toBe(2);
120
+ });
121
+
122
+ it("investigates issue stack traces and proposes concrete bugfix patches", async () => {
123
+ const issue: GitHubDetailedIssue = {
124
+ id: 301,
125
+ number: 42,
126
+ title: "TypeError: Cannot read properties of undefined (reading 'token')",
127
+ state: "open",
128
+ htmlUrl: "https://github.com/swadhinbiswas/warren/issues/42",
129
+ createdAt: "2026-09-05T00:00:00Z",
130
+ closedAt: null,
131
+ author: { login: "charlie", avatarUrl: "" },
132
+ commentsCount: 1,
133
+ isPullRequest: false,
134
+ labels: ["bug"],
135
+ body: `Error occurred during login flow:\nTypeError: Cannot read properties of undefined (reading 'token')\n at authenticate (src/auth/session.ts:45:12)\n at handleRequest (src/server.ts:102:5)`,
136
+ };
137
+
138
+ const fix = await aiCopilotService.suggestBugfix("swadhinbiswas/warren", issue);
139
+
140
+ expect(fix.targetFile).toBe("src/auth/session.ts");
141
+ expect(fix.targetLine).toBe(45);
142
+ expect(fix.proposedPatch).toContain("--- a/src/auth/session.ts");
143
+ expect(fix.proposedPatch).toContain("+++ b/src/auth/session.ts");
144
+ expect(fix.testSuggestions.length).toBeGreaterThan(0);
145
+ });
146
+
147
+ it("explains code architecture, dependencies, and complexity", async () => {
148
+ const code = `import { logger } from "@devpulse/logger";
149
+import { config } from "@devpulse/config";
150
+
151
+export class SecurityGuard {
152
+ private allowedDomains: string[];
153
+
154
+ constructor() {
155
+ this.allowedDomains = ["api.github.com"];
156
+ }
157
+
158
+ export async function validateEndpoint(url: string): Promise<boolean> {
159
+ logger.info({ url }, "Validating security endpoint");
160
+ return true;
161
+ }
162
+}`;
163
+
164
+ const explanation = await aiCopilotService.explainCode(
165
+ "swadhinbiswas/warren",
166
+ "src/security/guard.ts",
167
+ code,
168
+ 10,
169
+ );
170
+
171
+ expect(explanation.architectureRole).toContain("Security");
172
+ expect(explanation.complexity).toBe("Low");
173
+ expect(explanation.dependencies).toContain("@devpulse/logger");
174
+ expect(explanation.keyComponents.length).toBeGreaterThan(0);
175
+ });
176
+});
0
177
β–Όpackages/ai/src/index.ts
+4-129
1
-import { config } from "@devpulse/config";
2
-import { AppError } from "@devpulse/core";
1
+import { AiCopilotService } from "./copilot.js";
3
2
4
-export interface AIProvider {
5
- readonly name: string;
6
- isEnabled(): boolean;
7
- generateResponse(
8
- prompt: string,
9
- options?: { system?: string; maxTokens?: number },
10
- ): Promise<string>;
11
-}
3
+export * from "./provider.js";
4
+export * from "./copilot.js";
12
5
13
-export class NoopAiProvider implements AIProvider {
14
- readonly name = "None";
15
-
16
- isEnabled(): boolean {
17
- return false;
18
- }
19
-
20
- async generateResponse(): Promise<string> {
21
- throw new AppError(
22
- "AI features are currently disabled. Set AI_PROVIDER and AI_API_KEY in your environment to enable optional AI capabilities.",
23
- "AI_DISABLED",
24
- 400,
25
- );
26
- }
27
-}
28
-
29
-export class GenericOpenAiCompatibleProvider implements AIProvider {
30
- readonly name: string;
31
- private apiKey: string;
32
- private baseUrl: string;
33
- private model: string;
34
-
35
- constructor(
36
- name: string,
37
- apiKey: string,
38
- baseUrl = "https://api.openai.com/v1",
39
- model = "gpt-4o-mini",
40
- ) {
41
- this.name = name;
42
- this.apiKey = apiKey;
43
- this.baseUrl = baseUrl;
44
- this.model = model;
45
- }
46
-
47
- isEnabled(): boolean {
48
- return Boolean(this.apiKey);
49
- }
50
-
51
- async generateResponse(
52
- prompt: string,
53
- options: { system?: string; maxTokens?: number } = {},
54
- ): Promise<string> {
55
- if (!this.apiKey) {
56
- throw new AppError("AI API key is missing.", "AI_NOT_CONFIGURED", 400);
57
- }
58
-
59
- const messages = [
60
- {
61
- role: "system",
62
- content:
63
- options.system ||
64
- "You are DevPulse AI, a senior software architect helping developers. Be concise, precise, and practical. Output valid Markdown.",
65
- },
66
- { role: "user", content: prompt },
67
- ];
68
-
69
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
70
- method: "POST",
71
- headers: {
72
- "Content-Type": "application/json",
73
- Authorization: `Bearer ${this.apiKey}`,
74
- },
75
- body: JSON.stringify({
76
- model: this.model,
77
- messages,
78
- max_tokens: options.maxTokens || 1024,
79
- }),
80
- });
81
-
82
- if (!response.ok) {
83
- const errText = await response.text();
84
- throw new AppError(`AI provider error: ${errText}`, "AI_REQUEST_FAILED", 502);
85
- }
86
-
87
- const data = (await response.json()) as any;
88
- return data.choices?.[0]?.message?.content || "No response generated.";
89
- }
90
-}
91
-
92
-export function getAiProvider(): AIProvider {
93
- const providerType = config.AI_PROVIDER;
94
- const apiKey = config.AI_API_KEY;
95
-
96
- if (!apiKey || providerType === "none") {
97
- return new NoopAiProvider();
98
- }
99
-
100
- if (providerType === "openai") {
101
- return new GenericOpenAiCompatibleProvider(
102
- "OpenAI",
103
- apiKey,
104
- "https://api.openai.com/v1",
105
- "gpt-4o-mini",
106
- );
107
- }
108
-
109
- if (providerType === "anthropic") {
110
- // Generic abstraction
111
- return new GenericOpenAiCompatibleProvider(
112
- "Anthropic",
113
- apiKey,
114
- "https://api.anthropic.com/v1",
115
- "claude-3-haiku",
116
- );
117
- }
118
-
119
- if (providerType === "gemini") {
120
- return new GenericOpenAiCompatibleProvider(
121
- "Gemini",
122
- apiKey,
123
- "https://generativelanguage.googleapis.com/v1beta/openai",
124
- "gemini-1.5-flash",
125
- );
126
- }
127
-
128
- return new NoopAiProvider();
129
-}
130
-
131
-export const aiProvider = getAiProvider();
6
+export const aiCopilot = new AiCopilotService();
132
7
β–Όpackages/ai/src/provider.ts
+130-0
1
+import { config } from "@devpulse/config";
2
+import { AppError } from "@devpulse/core";
3
+
4
+export interface AIProvider {
5
+ readonly name: string;
6
+ isEnabled(): boolean;
7
+ generateResponse(
8
+ prompt: string,
9
+ options?: { system?: string; maxTokens?: number },
10
+ ): Promise<string>;
11
+}
12
+
13
+export class NoopAiProvider implements AIProvider {
14
+ readonly name = "None";
15
+
16
+ isEnabled(): boolean {
17
+ return false;
18
+ }
19
+
20
+ async generateResponse(): Promise<string> {
21
+ throw new AppError(
22
+ "AI features are currently disabled. Set AI_PROVIDER and AI_API_KEY in your environment to enable optional AI capabilities.",
23
+ "AI_DISABLED",
24
+ 400,
25
+ );
26
+ }
27
+}
28
+
29
+export class GenericOpenAiCompatibleProvider implements AIProvider {
30
+ readonly name: string;
31
+ private apiKey: string;
32
+ private baseUrl: string;
33
+ private model: string;
34
+
35
+ constructor(
36
+ name: string,
37
+ apiKey: string,
38
+ baseUrl = "https://api.openai.com/v1",
39
+ model = "gpt-4o-mini",
40
+ ) {
41
+ this.name = name;
42
+ this.apiKey = apiKey;
43
+ this.baseUrl = baseUrl;
44
+ this.model = model;
45
+ }
46
+
47
+ isEnabled(): boolean {
48
+ return Boolean(this.apiKey);
49
+ }
50
+
51
+ async generateResponse(
52
+ prompt: string,
53
+ options: { system?: string; maxTokens?: number } = {},
54
+ ): Promise<string> {
55
+ if (!this.apiKey) {
56
+ throw new AppError("AI API key is missing.", "AI_NOT_CONFIGURED", 400);
57
+ }
58
+
59
+ const messages = [
60
+ {
61
+ role: "system",
62
+ content:
63
+ options.system ||
64
+ "You are DevPulse AI, a senior software architect helping developers. Be concise, precise, and practical. Output valid Markdown.",
65
+ },
66
+ { role: "user", content: prompt },
67
+ ];
68
+
69
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
70
+ method: "POST",
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ Authorization: `Bearer ${this.apiKey}`,
74
+ },
75
+ body: JSON.stringify({
76
+ model: this.model,
77
+ messages,
78
+ max_tokens: options.maxTokens || 1024,
79
+ }),
80
+ });
81
+
82
+ if (!response.ok) {
83
+ const errText = await response.text();
84
+ throw new AppError(`AI provider error: ${errText}`, "AI_REQUEST_FAILED", 502);
85
+ }
86
+
87
+ const data = (await response.json()) as any;
88
+ return data.choices?.[0]?.message?.content || "No response generated.";
89
+ }
90
+}
91
+
92
+export function getAiProvider(): AIProvider {
93
+ const providerType = config.AI_PROVIDER;
94
+ const apiKey = config.AI_API_KEY;
95
+
96
+ if (!apiKey || providerType === "none") {
97
+ return new NoopAiProvider();
98
+ }
99
+
100
+ if (providerType === "openai") {
101
+ return new GenericOpenAiCompatibleProvider(
102
+ "OpenAI",
103
+ apiKey,
104
+ "https://api.openai.com/v1",
105
+ "gpt-4o-mini",
106
+ );
107
+ }
108
+
109
+ if (providerType === "anthropic") {
110
+ return new GenericOpenAiCompatibleProvider(
111
+ "Anthropic",
112
+ apiKey,
113
+ "https://api.anthropic.com/v1",
114
+ "claude-3-haiku",
115
+ );
116
+ }
117
+
118
+ if (providerType === "gemini") {
119
+ return new GenericOpenAiCompatibleProvider(
120
+ "Gemini",
121
+ apiKey,
122
+ "https://generativelanguage.googleapis.com/v1beta/openai",
123
+ "gemini-1.5-flash",
124
+ );
125
+ }
126
+
127
+ return new NoopAiProvider();
128
+}
129
+
130
+export const aiProvider = getAiProvider();
0
131
β–Όpackages/github/src/client.ts
+40-0
12
12
GitHubCodeSearchResult,
13
13
GitHubCommit,
14
14
GitHubContributor,
15
+ GitHubDetailedIssue,
15
16
GitHubDetailedPullRequest,
16
17
GitHubFileContent,
17
18
GitHubIssue,
18
19
GitHubPullRequest,
20
+ GitHubPullRequestFile,
19
21
GitHubRelease,
20
22
GitHubRepo,
21
23
GitHubSearchItem,
335
337
};
336
338
}
337
339
340
+ async getPullRequestFiles(repoInput: string, prNumber: number): Promise<GitHubPullRequestFile[]> {
341
+ const { owner, repo } = this.parseRepoInput(repoInput);
342
+ const raw = await this.request<any[]>(
343
+ `/repos/${owner}/${repo}/pulls/${prNumber}/files?per_page=100`,
344
+ );
345
+ return raw.map((f) => ({
346
+ sha: f.sha,
347
+ filename: f.filename,
348
+ status: f.status,
349
+ additions: f.additions || 0,
350
+ deletions: f.deletions || 0,
351
+ changes: f.changes || 0,
352
+ patch: f.patch,
353
+ }));
354
+ }
355
+
338
356
async getPullRequests(
339
357
repoInput: string,
340
358
state: "open" | "closed" | "all" = "all",
1023
1041
);
1024
1042
}
1025
1043
1044
+ async getSingleIssue(repoInput: string, issueNumber: number): Promise<GitHubDetailedIssue> {
1045
+ const { owner, repo } = this.parseRepoInput(repoInput);
1046
+ const raw = await this.request<any>(`/repos/${owner}/${repo}/issues/${issueNumber}`);
1047
+ return {
1048
+ id: raw.id,
1049
+ number: raw.number,
1050
+ title: raw.title,
1051
+ state: raw.state,
1052
+ htmlUrl: raw.html_url,
1053
+ createdAt: raw.created_at,
1054
+ closedAt: raw.closed_at,
1055
+ author: {
1056
+ login: raw.user?.login || "ghost",
1057
+ avatarUrl: raw.user?.avatar_url || "",
1058
+ },
1059
+ commentsCount: raw.comments || 0,
1060
+ isPullRequest: Boolean(raw.pull_request),
1061
+ body: raw.body || "",
1062
+ labels: (raw.labels || []).map((l: any) => (typeof l === "string" ? l : l.name || "")),
1063
+ };
1064
+ }
1065
+
1026
1066
async getContributors(repoInput: string, limit = 15): Promise<GitHubContributor[]> {
1027
1067
const { owner, repo } = this.parseRepoInput(repoInput);
1028
1068
const cacheKey = `gh:contributors:${owner.toLowerCase()}:${repo.toLowerCase()}:${limit}`;
1029
1069
β–Όpackages/github/src/types.ts
+15-0
324
324
openIssuesDelta30d: number;
325
325
prsMerged30d: number;
326
326
}
327
+
328
+export interface GitHubPullRequestFile {
329
+ sha: string;
330
+ filename: string;
331
+ status: "added" | "removed" | "modified" | "renamed";
332
+ additions: number;
333
+ deletions: number;
334
+ changes: number;
335
+ patch?: string;
336
+}
337
+
338
+export interface GitHubDetailedIssue extends GitHubIssue {
339
+ body?: string;
340
+ labels: string[];
341
+}
327
342