@openacp/cli 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -16
- package/dist/action-detect-6M5GCGAU.js +15 -0
- package/dist/admin-IKPS5PFC.js +16 -0
- package/dist/agents-55NX3DHM.js +14 -0
- package/dist/{api-client-UN7BXQOQ.js → api-client-BH2JFHQW.js} +4 -2
- package/dist/{autostart-K73RQZVV.js → autostart-A7JRU4WJ.js} +6 -2
- package/dist/{chunk-ECBD5I5R.js → chunk-2KJC3ILH.js} +123 -16
- package/dist/chunk-2KJC3ILH.js.map +1 -0
- package/dist/{chunk-2Z2XPUD5.js → chunk-4LFDEW22.js} +53 -5
- package/dist/chunk-4LFDEW22.js.map +1 -0
- package/dist/{chunk-Z46LGZ7R.js → chunk-4TR5Y3MP.js} +18 -1
- package/dist/chunk-4TR5Y3MP.js.map +1 -0
- package/dist/chunk-7G5QKLLF.js +105 -0
- package/dist/chunk-7G5QKLLF.js.map +1 -0
- package/dist/{chunk-IURZ4QHG.js → chunk-7QJS2XBD.js} +2 -1
- package/dist/chunk-7QJS2XBD.js.map +1 -0
- package/dist/chunk-AKIU4JBF.js +145 -0
- package/dist/chunk-AKIU4JBF.js.map +1 -0
- package/dist/{chunk-KSIQZC3J.js → chunk-EVFJW45N.js} +1 -1
- package/dist/chunk-EVFJW45N.js.map +1 -0
- package/dist/chunk-GINCOFNW.js +134 -0
- package/dist/chunk-GINCOFNW.js.map +1 -0
- package/dist/chunk-H7ZMPBZC.js +203 -0
- package/dist/chunk-H7ZMPBZC.js.map +1 -0
- package/dist/chunk-I7WC6E5S.js +71 -0
- package/dist/chunk-I7WC6E5S.js.map +1 -0
- package/dist/{chunk-6DAZSKE5.js → chunk-IMILOCR5.js} +2 -2
- package/dist/chunk-LGQYTK55.js +442 -0
- package/dist/chunk-LGQYTK55.js.map +1 -0
- package/dist/{chunk-X6LLG7XN.js → chunk-PMGNLNSH.js} +15 -6
- package/dist/chunk-PMGNLNSH.js.map +1 -0
- package/dist/{chunk-LCJIPE5S.js → chunk-R3UJUOXI.js} +889 -591
- package/dist/chunk-R3UJUOXI.js.map +1 -0
- package/dist/chunk-SM3G6UAX.js +122 -0
- package/dist/chunk-SM3G6UAX.js.map +1 -0
- package/dist/chunk-T22OLSET.js +265 -0
- package/dist/chunk-T22OLSET.js.map +1 -0
- package/dist/chunk-THBR6OXH.js +62 -0
- package/dist/chunk-THBR6OXH.js.map +1 -0
- package/dist/{chunk-5KYLXEG3.js → chunk-TOZQ3JFN.js} +52 -9
- package/dist/chunk-TOZQ3JFN.js.map +1 -0
- package/dist/{chunk-IQIPQTQT.js → chunk-UB7XUO7C.js} +171 -26
- package/dist/chunk-UB7XUO7C.js.map +1 -0
- package/dist/{chunk-OORPX73T.js → chunk-W3EYKZNQ.js} +17 -2
- package/dist/chunk-W3EYKZNQ.js.map +1 -0
- package/dist/{chunk-K53OZH5Y.js → chunk-ZCHNAM3B.js} +76 -2
- package/dist/chunk-ZCHNAM3B.js.map +1 -0
- package/dist/cli.js +30 -29
- package/dist/cli.js.map +1 -1
- package/dist/{config-OH26EIWN.js → config-AK2W3E67.js} +2 -2
- package/dist/config-editor-VIA7A72X.js +12 -0
- package/dist/{config-registry-SNKA2EH2.js → config-registry-QQOJ2GQP.js} +2 -2
- package/dist/{daemon-VKCONJUY.js → daemon-G27YZUWB.js} +3 -3
- package/dist/discord-2DKRH45T.js +2044 -0
- package/dist/discord-2DKRH45T.js.map +1 -0
- package/dist/doctor-AN6AZ3PF.js +9 -0
- package/dist/doctor-CHCYUTV5.js +14 -0
- package/dist/doctor-CHCYUTV5.js.map +1 -0
- package/dist/index.d.ts +331 -6
- package/dist/index.js +21 -11
- package/dist/{main-NEYPQHB4.js → main-56SPFYW4.js} +32 -24
- package/dist/main-56SPFYW4.js.map +1 -0
- package/dist/{menu-J5YVH665.js → menu-XR2GET2B.js} +2 -2
- package/dist/menu-XR2GET2B.js.map +1 -0
- package/dist/new-session-DRRP2J7E.js +16 -0
- package/dist/new-session-DRRP2J7E.js.map +1 -0
- package/dist/session-FVFLBREJ.js +19 -0
- package/dist/session-FVFLBREJ.js.map +1 -0
- package/dist/settings-LPOLJ6SA.js +12 -0
- package/dist/settings-LPOLJ6SA.js.map +1 -0
- package/dist/{setup-ZCWGOEAH.js → setup-IPWJCIJM.js} +9 -5
- package/dist/setup-IPWJCIJM.js.map +1 -0
- package/dist/{version-VC5CPXBX.js → version-ALWGGVKM.js} +2 -2
- package/dist/version-ALWGGVKM.js.map +1 -0
- package/package.json +2 -1
- package/dist/chunk-2Z2XPUD5.js.map +0 -1
- package/dist/chunk-5KYLXEG3.js.map +0 -1
- package/dist/chunk-ECBD5I5R.js.map +0 -1
- package/dist/chunk-IQIPQTQT.js.map +0 -1
- package/dist/chunk-IURZ4QHG.js.map +0 -1
- package/dist/chunk-K53OZH5Y.js.map +0 -1
- package/dist/chunk-KSIQZC3J.js.map +0 -1
- package/dist/chunk-LCJIPE5S.js.map +0 -1
- package/dist/chunk-OORPX73T.js.map +0 -1
- package/dist/chunk-X6LLG7XN.js.map +0 -1
- package/dist/chunk-Z46LGZ7R.js.map +0 -1
- package/dist/config-editor-5TICUK3K.js +0 -12
- package/dist/doctor-X6UCE7GQ.js +0 -9
- package/dist/main-NEYPQHB4.js.map +0 -1
- /package/dist/{api-client-UN7BXQOQ.js.map → action-detect-6M5GCGAU.js.map} +0 -0
- /package/dist/{autostart-K73RQZVV.js.map → admin-IKPS5PFC.js.map} +0 -0
- /package/dist/{config-OH26EIWN.js.map → agents-55NX3DHM.js.map} +0 -0
- /package/dist/{config-editor-5TICUK3K.js.map → api-client-BH2JFHQW.js.map} +0 -0
- /package/dist/{config-registry-SNKA2EH2.js.map → autostart-A7JRU4WJ.js.map} +0 -0
- /package/dist/{chunk-6DAZSKE5.js.map → chunk-IMILOCR5.js.map} +0 -0
- /package/dist/{daemon-VKCONJUY.js.map → config-AK2W3E67.js.map} +0 -0
- /package/dist/{doctor-X6UCE7GQ.js.map → config-editor-VIA7A72X.js.map} +0 -0
- /package/dist/{menu-J5YVH665.js.map → config-registry-QQOJ2GQP.js.map} +0 -0
- /package/dist/{setup-ZCWGOEAH.js.map → daemon-G27YZUWB.js.map} +0 -0
- /package/dist/{version-VC5CPXBX.js.map → doctor-AN6AZ3PF.js.map} +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DoctorEngine
|
|
3
|
+
} from "./chunk-ZCHNAM3B.js";
|
|
4
|
+
import {
|
|
5
|
+
log
|
|
6
|
+
} from "./chunk-ESOPMQAY.js";
|
|
7
|
+
|
|
8
|
+
// src/adapters/discord/commands/doctor.ts
|
|
9
|
+
import {
|
|
10
|
+
ActionRowBuilder,
|
|
11
|
+
ButtonBuilder,
|
|
12
|
+
ButtonStyle
|
|
13
|
+
} from "discord.js";
|
|
14
|
+
var pendingFixesStore = /* @__PURE__ */ new Map();
|
|
15
|
+
function renderReport(report) {
|
|
16
|
+
const icons = { pass: "\u2705", warn: "\u26A0\uFE0F", fail: "\u274C" };
|
|
17
|
+
const lines = ["\u{1FA7A} **OpenACP Doctor**\n"];
|
|
18
|
+
for (const category of report.categories) {
|
|
19
|
+
lines.push(`**${category.name}**`);
|
|
20
|
+
for (const result of category.results) {
|
|
21
|
+
lines.push(` ${icons[result.status]} ${result.message}`);
|
|
22
|
+
}
|
|
23
|
+
lines.push("");
|
|
24
|
+
}
|
|
25
|
+
const { passed, warnings, failed, fixed } = report.summary;
|
|
26
|
+
const fixedStr = fixed > 0 ? `, ${fixed} fixed` : "";
|
|
27
|
+
lines.push(`**Result:** ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`);
|
|
28
|
+
const components = [];
|
|
29
|
+
if (report.pendingFixes.length > 0) {
|
|
30
|
+
const row = new ActionRowBuilder();
|
|
31
|
+
for (let i = 0; i < Math.min(report.pendingFixes.length, 5); i++) {
|
|
32
|
+
row.addComponents(
|
|
33
|
+
new ButtonBuilder().setCustomId(`m:doctor:fix:${i}`).setLabel(`\u{1F527} Fix: ${report.pendingFixes[i].message.slice(0, 30)}`).setStyle(ButtonStyle.Primary)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
components.push(row);
|
|
37
|
+
}
|
|
38
|
+
return { content: lines.join("\n"), components };
|
|
39
|
+
}
|
|
40
|
+
async function handleDoctor(interaction, _adapter) {
|
|
41
|
+
await interaction.deferReply({ ephemeral: true });
|
|
42
|
+
try {
|
|
43
|
+
const engine = new DoctorEngine();
|
|
44
|
+
const report = await engine.runAll();
|
|
45
|
+
const { content, components } = renderReport(report);
|
|
46
|
+
const storeKey = `${interaction.guildId}:${interaction.channelId}`;
|
|
47
|
+
if (report.pendingFixes.length > 0) {
|
|
48
|
+
pendingFixesStore.set(storeKey, report.pendingFixes);
|
|
49
|
+
}
|
|
50
|
+
await interaction.editReply({ content, components });
|
|
51
|
+
} catch (err) {
|
|
52
|
+
log.error({ err }, "[discord-doctor] Doctor command failed");
|
|
53
|
+
await interaction.editReply(
|
|
54
|
+
`\u274C Doctor failed: ${err instanceof Error ? err.message : String(err)}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function runDoctorInline(interaction, _adapter) {
|
|
59
|
+
try {
|
|
60
|
+
const engine = new DoctorEngine();
|
|
61
|
+
const report = await engine.runAll();
|
|
62
|
+
const { content, components } = renderReport(report);
|
|
63
|
+
const storeKey = `${interaction.guildId}:${interaction.channelId}`;
|
|
64
|
+
if (report.pendingFixes.length > 0) {
|
|
65
|
+
pendingFixesStore.set(storeKey, report.pendingFixes);
|
|
66
|
+
}
|
|
67
|
+
await interaction.followUp({ content, components, ephemeral: true });
|
|
68
|
+
} catch (err) {
|
|
69
|
+
log.error({ err }, "[discord-doctor] Doctor inline failed");
|
|
70
|
+
await interaction.followUp({
|
|
71
|
+
content: `\u274C Doctor failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
72
|
+
ephemeral: true
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function handleDoctorButton(interaction, _adapter) {
|
|
77
|
+
const { customId } = interaction;
|
|
78
|
+
if (customId === "m:doctor") {
|
|
79
|
+
try {
|
|
80
|
+
await interaction.deferUpdate();
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
await runDoctorInline(interaction, _adapter);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (customId.startsWith("m:doctor:fix:")) {
|
|
87
|
+
const index = parseInt(customId.replace("m:doctor:fix:", ""), 10);
|
|
88
|
+
const storeKey = `${interaction.guildId}:${interaction.channelId}`;
|
|
89
|
+
const fixes = pendingFixesStore.get(storeKey);
|
|
90
|
+
try {
|
|
91
|
+
await interaction.deferUpdate();
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
if (!fixes || index < 0 || index >= fixes.length) {
|
|
95
|
+
try {
|
|
96
|
+
await interaction.followUp({ content: "\u26A0\uFE0F Fix no longer available.", ephemeral: true });
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const pending = fixes[index];
|
|
102
|
+
try {
|
|
103
|
+
const result = await pending.fix();
|
|
104
|
+
if (result.success) {
|
|
105
|
+
const engine = new DoctorEngine();
|
|
106
|
+
const report = await engine.runAll();
|
|
107
|
+
const { content, components } = renderReport(report);
|
|
108
|
+
if (report.pendingFixes.length > 0) {
|
|
109
|
+
pendingFixesStore.set(storeKey, report.pendingFixes);
|
|
110
|
+
} else {
|
|
111
|
+
pendingFixesStore.delete(storeKey);
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await interaction.followUp({ content, components, ephemeral: true });
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
try {
|
|
119
|
+
await interaction.followUp({ content: `\u274C Fix failed: ${result.message}`, ephemeral: true });
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
log.error({ err, index }, "[discord-doctor] Doctor fix callback failed");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
handleDoctor,
|
|
131
|
+
runDoctorInline,
|
|
132
|
+
handleDoctorButton
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=chunk-GINCOFNW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/discord/commands/doctor.ts"],"sourcesContent":["import {\n ActionRowBuilder,\n ButtonBuilder,\n ButtonStyle,\n} from 'discord.js'\nimport type { ChatInputCommandInteraction, ButtonInteraction } from 'discord.js'\nimport { DoctorEngine } from '../../../core/doctor/index.js'\nimport type { DoctorReport, PendingFix } from '../../../core/doctor/types.js'\nimport { log } from '../../../core/log.js'\n\n// TODO: Replace `any` with DiscordAdapter once Task 12 is implemented\n\n// In-memory store of pending fixes keyed by \"guildId:channelId:messageId\"\nconst pendingFixesStore = new Map<string, PendingFix[]>()\n\nfunction renderReport(report: DoctorReport): {\n content: string\n components: ActionRowBuilder<ButtonBuilder>[]\n} {\n const icons = { pass: '✅', warn: '⚠️', fail: '❌' }\n const lines: string[] = ['🩺 **OpenACP Doctor**\\n']\n\n for (const category of report.categories) {\n lines.push(`**${category.name}**`)\n for (const result of category.results) {\n lines.push(` ${icons[result.status]} ${result.message}`)\n }\n lines.push('')\n }\n\n const { passed, warnings, failed, fixed } = report.summary\n const fixedStr = fixed > 0 ? `, ${fixed} fixed` : ''\n lines.push(`**Result:** ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`)\n\n const components: ActionRowBuilder<ButtonBuilder>[] = []\n\n if (report.pendingFixes.length > 0) {\n const row = new ActionRowBuilder<ButtonBuilder>()\n for (let i = 0; i < Math.min(report.pendingFixes.length, 5); i++) {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`m:doctor:fix:${i}`)\n .setLabel(`🔧 Fix: ${report.pendingFixes[i].message.slice(0, 30)}`)\n .setStyle(ButtonStyle.Primary),\n )\n }\n components.push(row)\n }\n\n return { content: lines.join('\\n'), components }\n}\n\nexport async function handleDoctor(\n interaction: ChatInputCommandInteraction,\n _adapter: any,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n try {\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n // Store pending fixes for button callbacks\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n }\n\n await interaction.editReply({ content, components })\n } catch (err) {\n log.error({ err }, '[discord-doctor] Doctor command failed')\n await interaction.editReply(\n `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport async function runDoctorInline(\n interaction: ButtonInteraction,\n _adapter: any,\n): Promise<void> {\n try {\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n }\n\n await interaction.followUp({ content, components, ephemeral: true })\n } catch (err) {\n log.error({ err }, '[discord-doctor] Doctor inline failed')\n await interaction.followUp({\n content: `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n ephemeral: true,\n })\n }\n}\n\nexport async function handleDoctorButton(\n interaction: ButtonInteraction,\n _adapter: any,\n): Promise<void> {\n const { customId } = interaction\n\n if (customId === 'm:doctor') {\n try { await interaction.deferUpdate() } catch { /* ignore */ }\n await runDoctorInline(interaction, _adapter)\n return\n }\n\n if (customId.startsWith('m:doctor:fix:')) {\n const index = parseInt(customId.replace('m:doctor:fix:', ''), 10)\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n const fixes = pendingFixesStore.get(storeKey)\n\n try { await interaction.deferUpdate() } catch { /* ignore */ }\n\n if (!fixes || index < 0 || index >= fixes.length) {\n try { await interaction.followUp({ content: '⚠️ Fix no longer available.', ephemeral: true }) } catch { /* */ }\n return\n }\n\n const pending = fixes[index]\n try {\n const result = await pending.fix()\n if (result.success) {\n // Re-run doctor to show updated status\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n } else {\n pendingFixesStore.delete(storeKey)\n }\n\n try { await interaction.followUp({ content, components, ephemeral: true }) } catch { /* ignore */ }\n } else {\n try { await interaction.followUp({ content: `❌ Fix failed: ${result.message}`, ephemeral: true }) } catch { /* */ }\n }\n } catch (err) {\n log.error({ err, index }, '[discord-doctor] Doctor fix callback failed')\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
log
|
|
3
|
+
} from "./chunk-ESOPMQAY.js";
|
|
4
|
+
|
|
5
|
+
// src/adapters/discord/commands/agents.ts
|
|
6
|
+
import {
|
|
7
|
+
ActionRowBuilder,
|
|
8
|
+
ButtonBuilder,
|
|
9
|
+
ButtonStyle
|
|
10
|
+
} from "discord.js";
|
|
11
|
+
var AGENTS_PER_PAGE = 5;
|
|
12
|
+
function buildProgressBar(percent) {
|
|
13
|
+
const filled = Math.round(percent / 10);
|
|
14
|
+
const empty = 10 - filled;
|
|
15
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
16
|
+
}
|
|
17
|
+
function truncate(text, maxLen) {
|
|
18
|
+
if (text.length <= maxLen) return text;
|
|
19
|
+
return text.slice(0, maxLen - 1) + "\u2026";
|
|
20
|
+
}
|
|
21
|
+
async function handleAgents(interaction, adapter, page = 0) {
|
|
22
|
+
await interaction.deferReply({ ephemeral: true });
|
|
23
|
+
const { content, components } = buildAgentsContent(adapter, page);
|
|
24
|
+
await interaction.editReply({ content, components });
|
|
25
|
+
}
|
|
26
|
+
async function showAgentsList(interaction, adapter, page = 0) {
|
|
27
|
+
const { content, components } = buildAgentsContent(adapter, page);
|
|
28
|
+
await interaction.followUp({ content, components, ephemeral: true });
|
|
29
|
+
}
|
|
30
|
+
function buildAgentsContent(adapter, page) {
|
|
31
|
+
const catalog = adapter.core.agentCatalog;
|
|
32
|
+
const items = catalog.getAvailable();
|
|
33
|
+
const installed = items.filter((i) => i.installed);
|
|
34
|
+
const available = items.filter((i) => !i.installed);
|
|
35
|
+
let content = "**\u{1F916} Agents**\n\n";
|
|
36
|
+
if (installed.length > 0) {
|
|
37
|
+
content += "**Installed:**\n";
|
|
38
|
+
for (const item of installed) {
|
|
39
|
+
content += `\u2705 **${item.name}**`;
|
|
40
|
+
if (item.description) content += ` \u2014 *${truncate(item.description, 50)}*`;
|
|
41
|
+
content += "\n";
|
|
42
|
+
}
|
|
43
|
+
content += "\n";
|
|
44
|
+
}
|
|
45
|
+
const components = [];
|
|
46
|
+
if (available.length > 0) {
|
|
47
|
+
const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);
|
|
48
|
+
const safePage = Math.max(0, Math.min(page, totalPages - 1));
|
|
49
|
+
const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);
|
|
50
|
+
content += `**Available to install:**`;
|
|
51
|
+
if (totalPages > 1) content += ` (${safePage + 1}/${totalPages})`;
|
|
52
|
+
content += "\n";
|
|
53
|
+
for (const item of pageItems) {
|
|
54
|
+
if (item.available) {
|
|
55
|
+
content += `\u2B07\uFE0F **${item.name}**`;
|
|
56
|
+
} else {
|
|
57
|
+
const deps = item.missingDeps?.join(", ") ?? "requirements not met";
|
|
58
|
+
content += `\u26A0\uFE0F **${item.name}** *(needs: ${deps})*`;
|
|
59
|
+
}
|
|
60
|
+
if (item.description) content += `
|
|
61
|
+
*${truncate(item.description, 60)}*`;
|
|
62
|
+
content += "\n";
|
|
63
|
+
}
|
|
64
|
+
const installable = pageItems.filter((i) => i.available);
|
|
65
|
+
if (installable.length > 0) {
|
|
66
|
+
const installRow = new ActionRowBuilder();
|
|
67
|
+
for (const item of installable) {
|
|
68
|
+
installRow.addComponents(
|
|
69
|
+
new ButtonBuilder().setCustomId(`ag:install:${item.key}`).setLabel(`\u2B07\uFE0F ${item.name}`).setStyle(ButtonStyle.Secondary)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
components.push(installRow);
|
|
73
|
+
}
|
|
74
|
+
if (totalPages > 1) {
|
|
75
|
+
const pageRow = new ActionRowBuilder();
|
|
76
|
+
if (safePage > 0) {
|
|
77
|
+
pageRow.addComponents(
|
|
78
|
+
new ButtonBuilder().setCustomId(`ag:page:${safePage - 1}`).setLabel("\u25C0\uFE0F Prev").setStyle(ButtonStyle.Secondary)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (safePage < totalPages - 1) {
|
|
82
|
+
pageRow.addComponents(
|
|
83
|
+
new ButtonBuilder().setCustomId(`ag:page:${safePage + 1}`).setLabel("Next \u25B6\uFE0F").setStyle(ButtonStyle.Secondary)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (pageRow.components.length > 0) components.push(pageRow);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
content += "*All agents are already installed!*";
|
|
90
|
+
}
|
|
91
|
+
return { content, components };
|
|
92
|
+
}
|
|
93
|
+
async function handleInstall(interaction, adapter) {
|
|
94
|
+
await interaction.deferReply({ ephemeral: true });
|
|
95
|
+
const nameOrId = interaction.options.getString("name", true);
|
|
96
|
+
await installAgentWithProgress(interaction, adapter, nameOrId);
|
|
97
|
+
}
|
|
98
|
+
async function handleAgentButton(interaction, adapter) {
|
|
99
|
+
const { customId } = interaction;
|
|
100
|
+
if (customId.startsWith("ag:install:")) {
|
|
101
|
+
const nameOrId = customId.replace("ag:install:", "");
|
|
102
|
+
try {
|
|
103
|
+
await interaction.deferReply({ ephemeral: true });
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
await installAgentWithProgress(interaction, adapter, nameOrId);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (customId.startsWith("ag:page:")) {
|
|
110
|
+
const page = parseInt(customId.replace("ag:page:", ""), 10);
|
|
111
|
+
const { content, components } = buildAgentsContent(adapter, page);
|
|
112
|
+
try {
|
|
113
|
+
await interaction.update({ content, components });
|
|
114
|
+
} catch (err) {
|
|
115
|
+
log.warn({ err }, "[discord-agents] Failed to update page");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function installAgentWithProgress(interaction, adapter, nameOrId) {
|
|
120
|
+
const catalog = adapter.core.agentCatalog;
|
|
121
|
+
let statusText = `\u23F3 Installing **${nameOrId}**...`;
|
|
122
|
+
let lastEdit = 0;
|
|
123
|
+
const EDIT_THROTTLE_MS = 1500;
|
|
124
|
+
const editStatus = async (text) => {
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
if (now - lastEdit > EDIT_THROTTLE_MS) {
|
|
127
|
+
lastEdit = now;
|
|
128
|
+
statusText = text;
|
|
129
|
+
try {
|
|
130
|
+
if (interaction.deferred || interaction.replied) {
|
|
131
|
+
await interaction.editReply(text);
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
statusText = text;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
try {
|
|
140
|
+
if (interaction.deferred || interaction.replied) {
|
|
141
|
+
await interaction.editReply(statusText);
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
const progress = {
|
|
146
|
+
onStart(_id, _name) {
|
|
147
|
+
},
|
|
148
|
+
async onStep(step) {
|
|
149
|
+
await editStatus(`\u23F3 **${nameOrId}**: ${step}`);
|
|
150
|
+
},
|
|
151
|
+
async onDownloadProgress(percent) {
|
|
152
|
+
const bar = buildProgressBar(percent);
|
|
153
|
+
await editStatus(`\u23F3 **${nameOrId}**
|
|
154
|
+
Downloading... ${bar} ${percent}%`);
|
|
155
|
+
},
|
|
156
|
+
async onSuccess(name) {
|
|
157
|
+
const row = new ActionRowBuilder().addComponents(
|
|
158
|
+
new ButtonBuilder().setCustomId(`na:${nameOrId}`).setLabel(`\u{1F680} Start session with ${name}`).setStyle(ButtonStyle.Primary)
|
|
159
|
+
);
|
|
160
|
+
try {
|
|
161
|
+
if (interaction.deferred || interaction.replied) {
|
|
162
|
+
await interaction.editReply({
|
|
163
|
+
content: `\u2705 **${name}** installed!`,
|
|
164
|
+
components: [row]
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
async onError(error) {
|
|
171
|
+
try {
|
|
172
|
+
if (interaction.deferred || interaction.replied) {
|
|
173
|
+
await interaction.editReply(`\u274C ${error}`);
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const result = await catalog.install(nameOrId, progress);
|
|
180
|
+
if (result.ok && result.setupSteps?.length) {
|
|
181
|
+
let setupText = `\u{1F4CB} **Setup for ${result.agentKey}:**
|
|
182
|
+
|
|
183
|
+
`;
|
|
184
|
+
for (const step of result.setupSteps) {
|
|
185
|
+
setupText += `\u2192 ${step}
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
setupText += `
|
|
189
|
+
*Run in terminal: \`openacp agents info ${result.agentKey}\`*`;
|
|
190
|
+
try {
|
|
191
|
+
await interaction.followUp({ content: setupText, ephemeral: true });
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export {
|
|
198
|
+
handleAgents,
|
|
199
|
+
showAgentsList,
|
|
200
|
+
handleInstall,
|
|
201
|
+
handleAgentButton
|
|
202
|
+
};
|
|
203
|
+
//# sourceMappingURL=chunk-H7ZMPBZC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/discord/commands/agents.ts"],"sourcesContent":["import {\n ActionRowBuilder,\n ButtonBuilder,\n ButtonStyle,\n} from 'discord.js'\nimport type { ChatInputCommandInteraction, ButtonInteraction } from 'discord.js'\nimport { log } from '../../../core/log.js'\nimport type { InstallProgress } from '../../../core/types.js'\n\n// TODO: Replace `any` with DiscordAdapter once Task 12 is implemented\n\nconst AGENTS_PER_PAGE = 5\n\nfunction buildProgressBar(percent: number): string {\n const filled = Math.round(percent / 10)\n const empty = 10 - filled\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text\n return text.slice(0, maxLen - 1) + '…'\n}\n\nexport async function handleAgents(\n interaction: ChatInputCommandInteraction,\n adapter: any,\n page = 0,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n const { content, components } = buildAgentsContent(adapter, page)\n await interaction.editReply({ content, components })\n}\n\nexport async function showAgentsList(\n interaction: ButtonInteraction,\n adapter: any,\n page = 0,\n): Promise<void> {\n const { content, components } = buildAgentsContent(adapter, page)\n await interaction.followUp({ content, components, ephemeral: true })\n}\n\nfunction buildAgentsContent(\n adapter: any,\n page: number,\n): { content: string; components: ActionRowBuilder<ButtonBuilder>[] } {\n const catalog = adapter.core.agentCatalog\n const items = catalog.getAvailable()\n\n const installed = items.filter((i: any) => i.installed)\n const available = items.filter((i: any) => !i.installed)\n\n let content = '**🤖 Agents**\\n\\n'\n\n if (installed.length > 0) {\n content += '**Installed:**\\n'\n for (const item of installed) {\n content += `✅ **${item.name}**`\n if (item.description) content += ` — *${truncate(item.description, 50)}*`\n content += '\\n'\n }\n content += '\\n'\n }\n\n const components: ActionRowBuilder<ButtonBuilder>[] = []\n\n if (available.length > 0) {\n const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE)\n const safePage = Math.max(0, Math.min(page, totalPages - 1))\n const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE)\n\n content += `**Available to install:**`\n if (totalPages > 1) content += ` (${safePage + 1}/${totalPages})`\n content += '\\n'\n\n for (const item of pageItems) {\n if (item.available) {\n content += `⬇️ **${item.name}**`\n } else {\n const deps = item.missingDeps?.join(', ') ?? 'requirements not met'\n content += `⚠️ **${item.name}** *(needs: ${deps})*`\n }\n if (item.description) content += `\\n *${truncate(item.description, 60)}*`\n content += '\\n'\n }\n\n // Install buttons row\n const installable = pageItems.filter((i: any) => i.available)\n if (installable.length > 0) {\n const installRow = new ActionRowBuilder<ButtonBuilder>()\n for (const item of installable) {\n installRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:install:${item.key}`)\n .setLabel(`⬇️ ${item.name}`)\n .setStyle(ButtonStyle.Secondary),\n )\n }\n components.push(installRow)\n }\n\n // Pagination row\n if (totalPages > 1) {\n const pageRow = new ActionRowBuilder<ButtonBuilder>()\n if (safePage > 0) {\n pageRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:page:${safePage - 1}`)\n .setLabel('◀️ Prev')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n if (safePage < totalPages - 1) {\n pageRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:page:${safePage + 1}`)\n .setLabel('Next ▶️')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n if (pageRow.components.length > 0) components.push(pageRow)\n }\n } else {\n content += '*All agents are already installed!*'\n }\n\n return { content, components }\n}\n\nexport async function handleInstall(\n interaction: ChatInputCommandInteraction,\n adapter: any,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n const nameOrId = interaction.options.getString('name', true)\n await installAgentWithProgress(interaction, adapter, nameOrId)\n}\n\nexport async function handleAgentButton(\n interaction: ButtonInteraction,\n adapter: any,\n): Promise<void> {\n const { customId } = interaction\n\n if (customId.startsWith('ag:install:')) {\n const nameOrId = customId.replace('ag:install:', '')\n try { await interaction.deferReply({ ephemeral: true }) } catch { /* ignore */ }\n await installAgentWithProgress(interaction, adapter, nameOrId)\n return\n }\n\n if (customId.startsWith('ag:page:')) {\n const page = parseInt(customId.replace('ag:page:', ''), 10)\n const { content, components } = buildAgentsContent(adapter, page)\n try {\n await interaction.update({ content, components })\n } catch (err) {\n log.warn({ err }, '[discord-agents] Failed to update page')\n }\n }\n}\n\nasync function installAgentWithProgress(\n interaction: ChatInputCommandInteraction | ButtonInteraction,\n adapter: any,\n nameOrId: string,\n): Promise<void> {\n const catalog = adapter.core.agentCatalog\n\n // Track the latest status for periodic edits\n let statusText = `⏳ Installing **${nameOrId}**...`\n let lastEdit = 0\n const EDIT_THROTTLE_MS = 1500\n\n const editStatus = async (text: string) => {\n const now = Date.now()\n if (now - lastEdit > EDIT_THROTTLE_MS) {\n lastEdit = now\n statusText = text\n try {\n if ((interaction as any).deferred || (interaction as any).replied) {\n await interaction.editReply(text)\n }\n } catch { /* rate limit or unchanged */ }\n } else {\n statusText = text\n }\n }\n\n // Set initial message\n try {\n if ((interaction as any).deferred || (interaction as any).replied) {\n await interaction.editReply(statusText)\n }\n } catch { /* ignore */ }\n\n const progress: InstallProgress = {\n onStart(_id, _name) { /* initial message already sent */ },\n async onStep(step) { await editStatus(`⏳ **${nameOrId}**: ${step}`) },\n async onDownloadProgress(percent) {\n const bar = buildProgressBar(percent)\n await editStatus(`⏳ **${nameOrId}**\\nDownloading... ${bar} ${percent}%`)\n },\n async onSuccess(name) {\n const row = new ActionRowBuilder<ButtonBuilder>().addComponents(\n new ButtonBuilder()\n .setCustomId(`na:${nameOrId}`)\n .setLabel(`🚀 Start session with ${name}`)\n .setStyle(ButtonStyle.Primary),\n )\n try {\n if ((interaction as any).deferred || (interaction as any).replied) {\n await interaction.editReply({\n content: `✅ **${name}** installed!`,\n components: [row],\n })\n }\n } catch { /* ignore */ }\n },\n async onError(error) {\n try {\n if ((interaction as any).deferred || (interaction as any).replied) {\n await interaction.editReply(`❌ ${error}`)\n }\n } catch { /* ignore */ }\n },\n }\n\n const result = await catalog.install(nameOrId, progress)\n\n // Show setup steps as a follow-up message\n if (result.ok && result.setupSteps?.length) {\n let setupText = `📋 **Setup for ${result.agentKey}:**\\n\\n`\n for (const step of result.setupSteps) {\n setupText += `→ ${step}\\n`\n }\n setupText += `\\n*Run in terminal: \\`openacp agents info ${result.agentKey}\\`*`\n try {\n await interaction.followUp({ content: setupText, ephemeral: true })\n } catch { /* ignore */ }\n }\n}\n"],"mappings":";;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAOP,IAAM,kBAAkB;AAExB,SAAS,iBAAiB,SAAyB;AACjD,QAAM,SAAS,KAAK,MAAM,UAAU,EAAE;AACtC,QAAM,QAAQ,KAAK;AACnB,SAAO,SAAI,OAAO,MAAM,IAAI,SAAI,OAAO,KAAK;AAC9C;AAEA,SAAS,SAAS,MAAc,QAAwB;AACtD,MAAI,KAAK,UAAU,OAAQ,QAAO;AAClC,SAAO,KAAK,MAAM,GAAG,SAAS,CAAC,IAAI;AACrC;AAEA,eAAsB,aACpB,aACA,SACA,OAAO,GACQ;AACf,QAAM,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,EAAE,SAAS,WAAW,IAAI,mBAAmB,SAAS,IAAI;AAChE,QAAM,YAAY,UAAU,EAAE,SAAS,WAAW,CAAC;AACrD;AAEA,eAAsB,eACpB,aACA,SACA,OAAO,GACQ;AACf,QAAM,EAAE,SAAS,WAAW,IAAI,mBAAmB,SAAS,IAAI;AAChE,QAAM,YAAY,SAAS,EAAE,SAAS,YAAY,WAAW,KAAK,CAAC;AACrE;AAEA,SAAS,mBACP,SACA,MACoE;AACpE,QAAM,UAAU,QAAQ,KAAK;AAC7B,QAAM,QAAQ,QAAQ,aAAa;AAEnC,QAAM,YAAY,MAAM,OAAO,CAAC,MAAW,EAAE,SAAS;AACtD,QAAM,YAAY,MAAM,OAAO,CAAC,MAAW,CAAC,EAAE,SAAS;AAEvD,MAAI,UAAU;AAEd,MAAI,UAAU,SAAS,GAAG;AACxB,eAAW;AACX,eAAW,QAAQ,WAAW;AAC5B,iBAAW,YAAO,KAAK,IAAI;AAC3B,UAAI,KAAK,YAAa,YAAW,YAAO,SAAS,KAAK,aAAa,EAAE,CAAC;AACtE,iBAAW;AAAA,IACb;AACA,eAAW;AAAA,EACb;AAEA,QAAM,aAAgD,CAAC;AAEvD,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,aAAa,KAAK,KAAK,UAAU,SAAS,eAAe;AAC/D,UAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,aAAa,CAAC,CAAC;AAC3D,UAAM,YAAY,UAAU,MAAM,WAAW,kBAAkB,WAAW,KAAK,eAAe;AAE9F,eAAW;AACX,QAAI,aAAa,EAAG,YAAW,KAAK,WAAW,CAAC,IAAI,UAAU;AAC9D,eAAW;AAEX,eAAW,QAAQ,WAAW;AAC5B,UAAI,KAAK,WAAW;AAClB,mBAAW,kBAAQ,KAAK,IAAI;AAAA,MAC9B,OAAO;AACL,cAAM,OAAO,KAAK,aAAa,KAAK,IAAI,KAAK;AAC7C,mBAAW,kBAAQ,KAAK,IAAI,eAAe,IAAI;AAAA,MACjD;AACA,UAAI,KAAK,YAAa,YAAW;AAAA,MAAS,SAAS,KAAK,aAAa,EAAE,CAAC;AACxE,iBAAW;AAAA,IACb;AAGA,UAAM,cAAc,UAAU,OAAO,CAAC,MAAW,EAAE,SAAS;AAC5D,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,aAAa,IAAI,iBAAgC;AACvD,iBAAW,QAAQ,aAAa;AAC9B,mBAAW;AAAA,UACT,IAAI,cAAc,EACf,YAAY,cAAc,KAAK,GAAG,EAAE,EACpC,SAAS,gBAAM,KAAK,IAAI,EAAE,EAC1B,SAAS,YAAY,SAAS;AAAA,QACnC;AAAA,MACF;AACA,iBAAW,KAAK,UAAU;AAAA,IAC5B;AAGA,QAAI,aAAa,GAAG;AAClB,YAAM,UAAU,IAAI,iBAAgC;AACpD,UAAI,WAAW,GAAG;AAChB,gBAAQ;AAAA,UACN,IAAI,cAAc,EACf,YAAY,WAAW,WAAW,CAAC,EAAE,EACrC,SAAS,mBAAS,EAClB,SAAS,YAAY,SAAS;AAAA,QACnC;AAAA,MACF;AACA,UAAI,WAAW,aAAa,GAAG;AAC7B,gBAAQ;AAAA,UACN,IAAI,cAAc,EACf,YAAY,WAAW,WAAW,CAAC,EAAE,EACrC,SAAS,mBAAS,EAClB,SAAS,YAAY,SAAS;AAAA,QACnC;AAAA,MACF;AACA,UAAI,QAAQ,WAAW,SAAS,EAAG,YAAW,KAAK,OAAO;AAAA,IAC5D;AAAA,EACF,OAAO;AACL,eAAW;AAAA,EACb;AAEA,SAAO,EAAE,SAAS,WAAW;AAC/B;AAEA,eAAsB,cACpB,aACA,SACe;AACf,QAAM,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAEhD,QAAM,WAAW,YAAY,QAAQ,UAAU,QAAQ,IAAI;AAC3D,QAAM,yBAAyB,aAAa,SAAS,QAAQ;AAC/D;AAEA,eAAsB,kBACpB,aACA,SACe;AACf,QAAM,EAAE,SAAS,IAAI;AAErB,MAAI,SAAS,WAAW,aAAa,GAAG;AACtC,UAAM,WAAW,SAAS,QAAQ,eAAe,EAAE;AACnD,QAAI;AAAE,YAAM,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAAE,QAAQ;AAAA,IAAe;AAC/E,UAAM,yBAAyB,aAAa,SAAS,QAAQ;AAC7D;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,UAAU,GAAG;AACnC,UAAM,OAAO,SAAS,SAAS,QAAQ,YAAY,EAAE,GAAG,EAAE;AAC1D,UAAM,EAAE,SAAS,WAAW,IAAI,mBAAmB,SAAS,IAAI;AAChE,QAAI;AACF,YAAM,YAAY,OAAO,EAAE,SAAS,WAAW,CAAC;AAAA,IAClD,SAAS,KAAK;AACZ,UAAI,KAAK,EAAE,IAAI,GAAG,wCAAwC;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,eAAe,yBACb,aACA,SACA,UACe;AACf,QAAM,UAAU,QAAQ,KAAK;AAG7B,MAAI,aAAa,uBAAkB,QAAQ;AAC3C,MAAI,WAAW;AACf,QAAM,mBAAmB;AAEzB,QAAM,aAAa,OAAO,SAAiB;AACzC,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,MAAM,WAAW,kBAAkB;AACrC,iBAAW;AACX,mBAAa;AACb,UAAI;AACF,YAAK,YAAoB,YAAa,YAAoB,SAAS;AACjE,gBAAM,YAAY,UAAU,IAAI;AAAA,QAClC;AAAA,MACF,QAAQ;AAAA,MAAgC;AAAA,IAC1C,OAAO;AACL,mBAAa;AAAA,IACf;AAAA,EACF;AAGA,MAAI;AACF,QAAK,YAAoB,YAAa,YAAoB,SAAS;AACjE,YAAM,YAAY,UAAU,UAAU;AAAA,IACxC;AAAA,EACF,QAAQ;AAAA,EAAe;AAEvB,QAAM,WAA4B;AAAA,IAChC,QAAQ,KAAK,OAAO;AAAA,IAAqC;AAAA,IACzD,MAAM,OAAO,MAAM;AAAE,YAAM,WAAW,YAAO,QAAQ,OAAO,IAAI,EAAE;AAAA,IAAE;AAAA,IACpE,MAAM,mBAAmB,SAAS;AAChC,YAAM,MAAM,iBAAiB,OAAO;AACpC,YAAM,WAAW,YAAO,QAAQ;AAAA,iBAAsB,GAAG,IAAI,OAAO,GAAG;AAAA,IACzE;AAAA,IACA,MAAM,UAAU,MAAM;AACpB,YAAM,MAAM,IAAI,iBAAgC,EAAE;AAAA,QAChD,IAAI,cAAc,EACf,YAAY,MAAM,QAAQ,EAAE,EAC5B,SAAS,gCAAyB,IAAI,EAAE,EACxC,SAAS,YAAY,OAAO;AAAA,MACjC;AACA,UAAI;AACF,YAAK,YAAoB,YAAa,YAAoB,SAAS;AACjE,gBAAM,YAAY,UAAU;AAAA,YAC1B,SAAS,YAAO,IAAI;AAAA,YACpB,YAAY,CAAC,GAAG;AAAA,UAClB,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAAe;AAAA,IACzB;AAAA,IACA,MAAM,QAAQ,OAAO;AACnB,UAAI;AACF,YAAK,YAAoB,YAAa,YAAoB,SAAS;AACjE,gBAAM,YAAY,UAAU,UAAK,KAAK,EAAE;AAAA,QAC1C;AAAA,MACF,QAAQ;AAAA,MAAe;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,QAAQ,QAAQ,UAAU,QAAQ;AAGvD,MAAI,OAAO,MAAM,OAAO,YAAY,QAAQ;AAC1C,QAAI,YAAY,yBAAkB,OAAO,QAAQ;AAAA;AAAA;AACjD,eAAW,QAAQ,OAAO,YAAY;AACpC,mBAAa,UAAK,IAAI;AAAA;AAAA,IACxB;AACA,iBAAa;AAAA,0CAA6C,OAAO,QAAQ;AACzE,QAAI;AACF,YAAM,YAAY,SAAS,EAAE,SAAS,WAAW,WAAW,KAAK,CAAC;AAAA,IACpE,QAAQ;AAAA,IAAe;AAAA,EACzB;AACF;","names":[]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/adapters/discord/action-detect.ts
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
|
+
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
|
|
4
|
+
var CMD_NEW_RE = /\/new(?:\s+([^\s\u0080-\uFFFF]+)(?:\s+([^\s\u0080-\uFFFF]+))?)?/;
|
|
5
|
+
var CMD_CANCEL_RE = /\/cancel\b/;
|
|
6
|
+
var KW_NEW_RE = /(?:create|new)\s+session/i;
|
|
7
|
+
var KW_CANCEL_RE = /(?:cancel|stop)\s+session/i;
|
|
8
|
+
function detectAction(text) {
|
|
9
|
+
if (!text) return null;
|
|
10
|
+
const cancelCmd = CMD_CANCEL_RE.exec(text);
|
|
11
|
+
if (cancelCmd) return { type: "cancel_session" };
|
|
12
|
+
const newCmd = CMD_NEW_RE.exec(text);
|
|
13
|
+
if (newCmd) {
|
|
14
|
+
return {
|
|
15
|
+
type: "new_session",
|
|
16
|
+
agent: newCmd[1] || void 0,
|
|
17
|
+
workspace: newCmd[2] || void 0
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (KW_CANCEL_RE.test(text)) return { type: "cancel_session" };
|
|
21
|
+
if (KW_NEW_RE.test(text)) return { type: "new_session", agent: void 0, workspace: void 0 };
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
var ACTION_TTL_MS = 5 * 60 * 1e3;
|
|
25
|
+
var actionMap = /* @__PURE__ */ new Map();
|
|
26
|
+
function storeAction(action) {
|
|
27
|
+
const id = nanoid(8);
|
|
28
|
+
actionMap.set(id, { action, createdAt: Date.now() });
|
|
29
|
+
for (const [key, entry] of actionMap) {
|
|
30
|
+
if (Date.now() - entry.createdAt > ACTION_TTL_MS) {
|
|
31
|
+
actionMap.delete(key);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
function getAction(id) {
|
|
37
|
+
const entry = actionMap.get(id);
|
|
38
|
+
if (!entry) return void 0;
|
|
39
|
+
if (Date.now() - entry.createdAt > ACTION_TTL_MS) {
|
|
40
|
+
actionMap.delete(id);
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
return entry.action;
|
|
44
|
+
}
|
|
45
|
+
function removeAction(id) {
|
|
46
|
+
actionMap.delete(id);
|
|
47
|
+
}
|
|
48
|
+
function buildActionKeyboard(actionId, action) {
|
|
49
|
+
const row = new ActionRowBuilder();
|
|
50
|
+
if (action.type === "new_session") {
|
|
51
|
+
row.addComponents(
|
|
52
|
+
new ButtonBuilder().setCustomId(`a:${actionId}`).setLabel("\u2705 Create session").setStyle(ButtonStyle.Success),
|
|
53
|
+
new ButtonBuilder().setCustomId(`a:dismiss:${actionId}`).setLabel("\u274C Cancel").setStyle(ButtonStyle.Secondary)
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
row.addComponents(
|
|
57
|
+
new ButtonBuilder().setCustomId(`a:${actionId}`).setLabel("\u26D4 Cancel session").setStyle(ButtonStyle.Danger),
|
|
58
|
+
new ButtonBuilder().setCustomId(`a:dismiss:${actionId}`).setLabel("\u274C No").setStyle(ButtonStyle.Secondary)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return row;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export {
|
|
65
|
+
detectAction,
|
|
66
|
+
storeAction,
|
|
67
|
+
getAction,
|
|
68
|
+
removeAction,
|
|
69
|
+
buildActionKeyboard
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=chunk-I7WC6E5S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/discord/action-detect.ts"],"sourcesContent":["import { nanoid } from 'nanoid'\nimport { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js'\n\nexport interface DetectedAction {\n type: 'new_session' | 'cancel_session'\n agent?: string\n workspace?: string\n}\n\n// Command patterns: /new [agent] [workspace], /cancel\n// Agent and workspace are ASCII-only tokens (no Unicode letters) to avoid matching non-ASCII words\nconst CMD_NEW_RE = /\\/new(?:\\s+([^\\s\\u0080-\\uFFFF]+)(?:\\s+([^\\s\\u0080-\\uFFFF]+))?)?/\nconst CMD_CANCEL_RE = /\\/cancel\\b/\n\n// Keyword patterns (compound phrases only to avoid false positives)\nconst KW_NEW_RE = /(?:create|new)\\s+session/i\nconst KW_CANCEL_RE = /(?:cancel|stop)\\s+session/i\n\nexport function detectAction(text: string): DetectedAction | null {\n if (!text) return null\n\n // Priority 1: command pattern\n const cancelCmd = CMD_CANCEL_RE.exec(text)\n if (cancelCmd) return { type: 'cancel_session' }\n\n const newCmd = CMD_NEW_RE.exec(text)\n if (newCmd) {\n return {\n type: 'new_session',\n agent: newCmd[1] || undefined,\n workspace: newCmd[2] || undefined,\n }\n }\n\n // Priority 2: keyword matching\n if (KW_CANCEL_RE.test(text)) return { type: 'cancel_session' }\n if (KW_NEW_RE.test(text)) return { type: 'new_session', agent: undefined, workspace: undefined }\n\n return null\n}\n\n// --- TTL action map ---\n\nconst ACTION_TTL_MS = 5 * 60 * 1000 // 5 minutes\nconst actionMap: Map<string, { action: DetectedAction; createdAt: number }> = new Map()\n\nexport function storeAction(action: DetectedAction): string {\n const id = nanoid(8)\n actionMap.set(id, { action, createdAt: Date.now() })\n // Cleanup expired entries\n for (const [key, entry] of actionMap) {\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(key)\n }\n }\n return id\n}\n\nexport function getAction(id: string): DetectedAction | undefined {\n const entry = actionMap.get(id)\n if (!entry) return undefined\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(id)\n return undefined\n }\n return entry.action\n}\n\nexport function removeAction(id: string): void {\n actionMap.delete(id)\n}\n\nexport function buildActionKeyboard(\n actionId: string,\n action: DetectedAction,\n): ActionRowBuilder<ButtonBuilder> {\n const row = new ActionRowBuilder<ButtonBuilder>()\n\n if (action.type === 'new_session') {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`a:${actionId}`)\n .setLabel('✅ Create session')\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId(`a:dismiss:${actionId}`)\n .setLabel('❌ Cancel')\n .setStyle(ButtonStyle.Secondary),\n )\n } else {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`a:${actionId}`)\n .setLabel('⛔ Cancel session')\n .setStyle(ButtonStyle.Danger),\n new ButtonBuilder()\n .setCustomId(`a:dismiss:${actionId}`)\n .setLabel('❌ No')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n\n return row\n}\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,SAAS,kBAAkB,eAAe,mBAAmB;AAU7D,IAAM,aAAa;AACnB,IAAM,gBAAgB;AAGtB,IAAM,YAAY;AAClB,IAAM,eAAe;AAEd,SAAS,aAAa,MAAqC;AAChE,MAAI,CAAC,KAAM,QAAO;AAGlB,QAAM,YAAY,cAAc,KAAK,IAAI;AACzC,MAAI,UAAW,QAAO,EAAE,MAAM,iBAAiB;AAE/C,QAAM,SAAS,WAAW,KAAK,IAAI;AACnC,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,OAAO,CAAC,KAAK;AAAA,MACpB,WAAW,OAAO,CAAC,KAAK;AAAA,IAC1B;AAAA,EACF;AAGA,MAAI,aAAa,KAAK,IAAI,EAAG,QAAO,EAAE,MAAM,iBAAiB;AAC7D,MAAI,UAAU,KAAK,IAAI,EAAG,QAAO,EAAE,MAAM,eAAe,OAAO,QAAW,WAAW,OAAU;AAE/F,SAAO;AACT;AAIA,IAAM,gBAAgB,IAAI,KAAK;AAC/B,IAAM,YAAwE,oBAAI,IAAI;AAE/E,SAAS,YAAY,QAAgC;AAC1D,QAAM,KAAK,OAAO,CAAC;AACnB,YAAU,IAAI,IAAI,EAAE,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;AAEnD,aAAW,CAAC,KAAK,KAAK,KAAK,WAAW;AACpC,QAAI,KAAK,IAAI,IAAI,MAAM,YAAY,eAAe;AAChD,gBAAU,OAAO,GAAG;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,UAAU,IAAwC;AAChE,QAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,YAAY,eAAe;AAChD,cAAU,OAAO,EAAE;AACnB,WAAO;AAAA,EACT;AACA,SAAO,MAAM;AACf;AAEO,SAAS,aAAa,IAAkB;AAC7C,YAAU,OAAO,EAAE;AACrB;AAEO,SAAS,oBACd,UACA,QACiC;AACjC,QAAM,MAAM,IAAI,iBAAgC;AAEhD,MAAI,OAAO,SAAS,eAAe;AACjC,QAAI;AAAA,MACF,IAAI,cAAc,EACf,YAAY,KAAK,QAAQ,EAAE,EAC3B,SAAS,uBAAkB,EAC3B,SAAS,YAAY,OAAO;AAAA,MAC/B,IAAI,cAAc,EACf,YAAY,aAAa,QAAQ,EAAE,EACnC,SAAS,eAAU,EACnB,SAAS,YAAY,SAAS;AAAA,IACnC;AAAA,EACF,OAAO;AACL,QAAI;AAAA,MACF,IAAI,cAAc,EACf,YAAY,KAAK,QAAQ,EAAE,EAC3B,SAAS,uBAAkB,EAC3B,SAAS,YAAY,MAAM;AAAA,MAC9B,IAAI,cAAc,EACf,YAAY,aAAa,QAAQ,EAAE,EACnC,SAAS,WAAM,EACf,SAAS,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PLUGINS_DIR
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4LFDEW22.js";
|
|
4
4
|
import {
|
|
5
5
|
createChildLogger
|
|
6
6
|
} from "./chunk-ESOPMQAY.js";
|
|
@@ -60,4 +60,4 @@ export {
|
|
|
60
60
|
listPlugins,
|
|
61
61
|
loadAdapterFactory
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=chunk-
|
|
63
|
+
//# sourceMappingURL=chunk-IMILOCR5.js.map
|