husteno-o feat(ai): implement AI Code Copilot & Reviewer suite (/ai review, summarize, bugfix, explain) Β· 9/6/2026
98f25a0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
} from "discord.js";
import { NF } from "./icons.js";
export function createRepoNavButtons(
owner: string,
repo: string,
activeTab = "overview",
): ActionRowBuilder<ButtonBuilder>[] {
const row1 = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(`repo:overview:${owner}:${repo}`)
.setLabel("π¦ Overview")
.setStyle(activeTab === "overview" ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`repo:prs:${owner}:${repo}`)
.setLabel("π Pull Requests")
.setStyle(activeTab === "prs" ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`repo:issues:${owner}:${repo}`)
.setLabel("π Issues")
.setStyle(activeTab === "issues" ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`repo:commits:${owner}:${repo}`)
.setLabel("π Commits")
.setStyle(activeTab === "commits" ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`repo:releases:${owner}:${repo}`)
.setLabel("π·οΈ Releases")
.setStyle(activeTab === "releases" ? ButtonStyle.Primary : ButtonStyle.Secondary),
);
return [row1];
}
export function createPrActionButtons(
owner: string,
repo: string,
prNumber: number,
prUrl: string,
): ActionRowBuilder<ButtonBuilder>[] {
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(`pr:approve:${owner}:${repo}:${prNumber}`)
.setLabel(`${NF.check} Approve`)
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId(`pr:request_changes:${owner}:${repo}:${prNumber}`)
.setLabel(`${NF.warning} Request Changes`)
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId(`pr:merge:${owner}:${repo}:${prNumber}`)
.setLabel(`${NF.gitMerge} Merge`)
.setStyle(ButtonStyle.Primary),
new ButtonBuilder().setLabel("π Open GitHub β").setStyle(ButtonStyle.Link).setURL(prUrl),
);
return [row];
}
export function createHomeNavButtons(): ActionRowBuilder<ButtonBuilder>[] {
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId("home:nav:repos")
.setLabel("π¦ Repositories")
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId("home:nav:prs")
.setLabel("π Pull Requests")
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId("home:nav:issues")
.setLabel("π Issues")
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId("home:nav:activity")
.setLabel("π Activity")
.setStyle(ButtonStyle.Secondary),
);
return [row];
}
export function createDeleteSecretButton(messageId: string): ActionRowBuilder<ButtonBuilder> {
return new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(`secret:delete:${messageId}`)
.setLabel("ποΈ Delete Leaked Secret")
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setLabel("π‘οΈ Security Guide β")
.setStyle(ButtonStyle.Link)
.setURL(
"https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation",
),
);
}
export function createAiReviewActionButtons(
owner: string,
repo: string,
prNumber: number,
prUrl: string,
approvedForMerge: boolean,
): ActionRowBuilder<ButtonBuilder>[] {
const row = new ActionRowBuilder<ButtonBuilder>();
if (approvedForMerge) {
row.addComponents(
new ButtonBuilder()
.setCustomId(`pr:merge:${owner}:${repo}:${prNumber}`)
.setLabel(`${NF.gitMerge} Fast-Forward Merge`)
.setStyle(ButtonStyle.Success),
);
}
row.addComponents(
new ButtonBuilder()
.setCustomId(`pr:approve:${owner}:${repo}:${prNumber}`)
.setLabel(`${NF.check} Approve PR`)
.setStyle(ButtonStyle.Primary),
new ButtonBuilder().setLabel("π View on GitHub β").setStyle(ButtonStyle.Link).setURL(prUrl),
);
return [row];
}
export function createAiBugfixActionButtons(
_owner: string,
_repo: string,
_issueNumber: number,
issueUrl: string,
): ActionRowBuilder<ButtonBuilder>[] {
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setLabel("π View Issue on GitHub β")
.setStyle(ButtonStyle.Link)
.setURL(issueUrl),
);
return [row];
}
export function createHelpSelect(): ActionRowBuilder<StringSelectMenuBuilder> {
const menu = new StringSelectMenuBuilder()
.setCustomId("help:category_select")
.setPlaceholder("Select a GitHub developer suite...")
.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.github} 1. Repository Intelligence (/repo)`)
.setDescription("Health score, growth, dependencies, metrics")
.setValue("repo"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.gitPullRequest} 2. Pull Request Tools (/pr)`)
.setDescription("Stale detection, CI checks, diffs, 1-click merge")
.setValue("pr"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.sparkle} 3. AI Copilot & Reviewer (/ai)`)
.setDescription("Automated code reviews, standup summaries, bugfixes")
.setValue("ai"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.search} 4. GitHub Search Engine (/search)`)
.setDescription("Code, issues, PRs, repos, commits qualifiers")
.setValue("search"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.terminal} 5. Code Intelligence (/code & /why)`)
.setDescription("File inspection, blame, PR link tracing")
.setValue("code"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.speedometer} 6. Investigation (/investigate)`)
.setDescription("Lifecycle timeline: Issue -> Commit -> PR -> Release")
.setValue("investigate"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.robot} 7. Actions Control Center (/actions)`)
.setDescription("Visual tree, run inspection, rerun & cancel")
.setValue("actions"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.shield} 8. Security Center (/security)`)
.setDescription("Dependabot alerts, advisories, CVE breakdown")
.setValue("security"),
new StringSelectMenuOptionBuilder()
.setLabel(`${NF.warning} 9. Watchtower Alerts (/watch)`)
.setDescription("Automated Discord alerts for releases, PRs, issues")
.setValue("watch"),
);
return new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu);
}