agent4discord 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +134 -0
- package/README.md +170 -0
- package/dist/bot.d.ts +1 -0
- package/dist/bot.js +114 -0
- package/dist/bot.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.js +44 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +152 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/model.d.ts +5 -0
- package/dist/commands/model.js +65 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/resume.d.ts +6 -0
- package/dist/commands/resume.js +113 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/dist/formatters/chunker.d.ts +5 -0
- package/dist/formatters/chunker.js +46 -0
- package/dist/formatters/chunker.js.map +1 -0
- package/dist/formatters/embedBuilder.d.ts +28 -0
- package/dist/formatters/embedBuilder.js +32 -0
- package/dist/formatters/embedBuilder.js.map +1 -0
- package/dist/formatters/toolFormatter.d.ts +4 -0
- package/dist/formatters/toolFormatter.js +90 -0
- package/dist/formatters/toolFormatter.js.map +1 -0
- package/dist/guild.d.ts +22 -0
- package/dist/guild.js +41 -0
- package/dist/guild.js.map +1 -0
- package/dist/interactions/directoryBrowser.d.ts +61 -0
- package/dist/interactions/directoryBrowser.js +611 -0
- package/dist/interactions/directoryBrowser.js.map +1 -0
- package/dist/interactions/index.d.ts +5 -0
- package/dist/interactions/index.js +92 -0
- package/dist/interactions/index.js.map +1 -0
- package/dist/interactions/permissionHandler.d.ts +11 -0
- package/dist/interactions/permissionHandler.js +107 -0
- package/dist/interactions/permissionHandler.js.map +1 -0
- package/dist/interactions/sessionControls.d.ts +9 -0
- package/dist/interactions/sessionControls.js +95 -0
- package/dist/interactions/sessionControls.js.map +1 -0
- package/dist/sessions/eventHandler.d.ts +3 -0
- package/dist/sessions/eventHandler.js +209 -0
- package/dist/sessions/eventHandler.js.map +1 -0
- package/dist/sessions/sessionManager.d.ts +29 -0
- package/dist/sessions/sessionManager.js +203 -0
- package/dist/sessions/sessionManager.js.map +1 -0
- package/dist/sessions/sessionStore.d.ts +4 -0
- package/dist/sessions/sessionStore.js +29 -0
- package/dist/sessions/sessionStore.js.map +1 -0
- package/dist/sessions/streamHandler.d.ts +18 -0
- package/dist/sessions/streamHandler.js +119 -0
- package/dist/sessions/streamHandler.js.map +1 -0
- package/dist/sessions/toolProgress.d.ts +14 -0
- package/dist/sessions/toolProgress.js +65 -0
- package/dist/sessions/toolProgress.js.map +1 -0
- package/dist/sessions/usageTracker.d.ts +12 -0
- package/dist/sessions/usageTracker.js +222 -0
- package/dist/sessions/usageTracker.js.map +1 -0
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +101 -0
- package/dist/setup.js.map +1 -0
- package/dist/utils/filesystem.d.ts +11 -0
- package/dist/utils/filesystem.js +26 -0
- package/dist/utils/filesystem.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.js +3 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/plugins.d.ts +6 -0
- package/dist/utils/plugins.js +66 -0
- package/dist/utils/plugins.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { handleDirectoryBrowse, handleDirectoryCancel, handleDirectoryNext, handleDirectoryParent, handleDirectoryPrev, handleModelCancel, handleModelConfirm, handleModelSelect, handleResumeBack, handleResumeBrowse, handleResumeSession, handleResumeStart, handleSessionStart, } from './directoryBrowser.js';
|
|
2
|
+
import { handlePermission } from './permissionHandler.js';
|
|
3
|
+
import { handleSessionStop, handleSessionArchive } from './sessionControls.js';
|
|
4
|
+
/**
|
|
5
|
+
* Route component interactions (buttons, select menus) based on customId prefix.
|
|
6
|
+
*/
|
|
7
|
+
export async function routeInteraction(interaction) {
|
|
8
|
+
const customId = interaction.customId;
|
|
9
|
+
if (customId.startsWith('a4d:dir:')) {
|
|
10
|
+
switch (customId) {
|
|
11
|
+
case 'a4d:dir:browse':
|
|
12
|
+
await handleDirectoryBrowse(interaction);
|
|
13
|
+
return;
|
|
14
|
+
case 'a4d:dir:parent':
|
|
15
|
+
await handleDirectoryParent(interaction);
|
|
16
|
+
return;
|
|
17
|
+
case 'a4d:dir:start':
|
|
18
|
+
await handleSessionStart(interaction);
|
|
19
|
+
return;
|
|
20
|
+
case 'a4d:dir:resume':
|
|
21
|
+
await handleResumeSession(interaction);
|
|
22
|
+
return;
|
|
23
|
+
case 'a4d:dir:cancel':
|
|
24
|
+
await handleDirectoryCancel(interaction);
|
|
25
|
+
return;
|
|
26
|
+
case 'a4d:dir:prev':
|
|
27
|
+
await handleDirectoryPrev(interaction);
|
|
28
|
+
return;
|
|
29
|
+
case 'a4d:dir:next':
|
|
30
|
+
await handleDirectoryNext(interaction);
|
|
31
|
+
return;
|
|
32
|
+
case 'a4d:dir:pageinfo':
|
|
33
|
+
await interaction.deferUpdate();
|
|
34
|
+
return;
|
|
35
|
+
default:
|
|
36
|
+
await interaction.reply({ content: 'Unknown directory browser action.', ephemeral: true });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (customId.startsWith('a4d:model:')) {
|
|
41
|
+
switch (customId) {
|
|
42
|
+
case 'a4d:model:select':
|
|
43
|
+
await handleModelSelect(interaction);
|
|
44
|
+
return;
|
|
45
|
+
case 'a4d:model:confirm':
|
|
46
|
+
await handleModelConfirm(interaction);
|
|
47
|
+
return;
|
|
48
|
+
case 'a4d:model:cancel':
|
|
49
|
+
await handleModelCancel(interaction);
|
|
50
|
+
return;
|
|
51
|
+
default:
|
|
52
|
+
await interaction.reply({ content: 'Unknown model selection action.', ephemeral: true });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (customId.startsWith('a4d:session:')) {
|
|
57
|
+
switch (customId) {
|
|
58
|
+
case 'a4d:session:stop':
|
|
59
|
+
await handleSessionStop(interaction);
|
|
60
|
+
return;
|
|
61
|
+
case 'a4d:session:archive':
|
|
62
|
+
await handleSessionArchive(interaction);
|
|
63
|
+
return;
|
|
64
|
+
default:
|
|
65
|
+
await interaction.reply({ content: 'Unknown session control action.', ephemeral: true });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (customId.startsWith('a4d:perm:')) {
|
|
70
|
+
await handlePermission(interaction);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (customId.startsWith('a4d:resume:')) {
|
|
74
|
+
switch (customId) {
|
|
75
|
+
case 'a4d:resume:browse':
|
|
76
|
+
await handleResumeBrowse(interaction);
|
|
77
|
+
return;
|
|
78
|
+
case 'a4d:resume:back':
|
|
79
|
+
await handleResumeBack(interaction);
|
|
80
|
+
return;
|
|
81
|
+
case 'a4d:resume:start':
|
|
82
|
+
await handleResumeStart(interaction);
|
|
83
|
+
return;
|
|
84
|
+
default:
|
|
85
|
+
await interaction.reply({ content: 'Unknown resume action.', ephemeral: true });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.warn(`[interactions] Unknown customId: ${customId}`);
|
|
90
|
+
await interaction.reply({ content: 'Unknown interaction.', ephemeral: true });
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interactions/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ButtonInteraction, type TextChannel } from 'discord.js';
|
|
2
|
+
import type { PermissionResult } from '@anthropic-ai/claude-agent-sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Request tool permission via Discord buttons.
|
|
5
|
+
* Returns a promise that resolves when the user clicks Allow/Deny or times out.
|
|
6
|
+
*/
|
|
7
|
+
export declare function requestPermission(channel: TextChannel, userId: string, toolName: string, toolInput: Record<string, unknown>): Promise<PermissionResult>;
|
|
8
|
+
/**
|
|
9
|
+
* Handle permission button interactions.
|
|
10
|
+
*/
|
|
11
|
+
export declare function handlePermission(interaction: ButtonInteraction): Promise<void>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, MessageFlags, } from 'discord.js';
|
|
3
|
+
import { COLORS } from '../formatters/embedBuilder.js';
|
|
4
|
+
import { formatToolInput, getToolEmoji } from '../formatters/toolFormatter.js';
|
|
5
|
+
// Auto-allow these safe tools
|
|
6
|
+
const AUTO_ALLOW_TOOLS = new Set(['Read', 'Glob', 'Grep', 'LSP']);
|
|
7
|
+
const pendingPermissions = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Request tool permission via Discord buttons.
|
|
10
|
+
* Returns a promise that resolves when the user clicks Allow/Deny or times out.
|
|
11
|
+
*/
|
|
12
|
+
export async function requestPermission(channel, userId, toolName, toolInput) {
|
|
13
|
+
// Auto-allow safe tools
|
|
14
|
+
if (AUTO_ALLOW_TOOLS.has(toolName)) {
|
|
15
|
+
return { behavior: 'allow', updatedInput: {} };
|
|
16
|
+
}
|
|
17
|
+
const requestId = randomUUID().slice(0, 8); // short ID for customId limit
|
|
18
|
+
// Build permission embed
|
|
19
|
+
const emoji = getToolEmoji(toolName);
|
|
20
|
+
const inputPreview = formatToolInput(toolName, toolInput);
|
|
21
|
+
const embed = new EmbedBuilder()
|
|
22
|
+
.setTitle(`${emoji} Permission Request`)
|
|
23
|
+
.setDescription(`**Tool:** ${toolName}\n\n${inputPreview.slice(0, 3000)}`)
|
|
24
|
+
.setColor(COLORS.PERMISSION)
|
|
25
|
+
.setFooter({ text: `Expires in 60 seconds` });
|
|
26
|
+
// Build buttons
|
|
27
|
+
const row = new ActionRowBuilder().addComponents(new ButtonBuilder()
|
|
28
|
+
.setCustomId(`a4d:perm:${requestId}:allow`)
|
|
29
|
+
.setLabel('Allow')
|
|
30
|
+
.setStyle(ButtonStyle.Success), new ButtonBuilder()
|
|
31
|
+
.setCustomId(`a4d:perm:${requestId}:deny`)
|
|
32
|
+
.setLabel('Deny')
|
|
33
|
+
.setStyle(ButtonStyle.Danger), new ButtonBuilder()
|
|
34
|
+
.setCustomId(`a4d:perm:${requestId}:details`)
|
|
35
|
+
.setLabel('Details')
|
|
36
|
+
.setStyle(ButtonStyle.Secondary));
|
|
37
|
+
const msg = await channel.send({ embeds: [embed], components: [row] });
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const timeout = setTimeout(() => {
|
|
40
|
+
pendingPermissions.delete(requestId);
|
|
41
|
+
const timedOutEmbed = EmbedBuilder.from(embed)
|
|
42
|
+
.setTitle(`${emoji} Permission Request (Timed Out)`)
|
|
43
|
+
.setColor(COLORS.STOPPED);
|
|
44
|
+
const disabledRow = buildDisabledRow();
|
|
45
|
+
msg.edit({ embeds: [timedOutEmbed], components: [disabledRow] }).catch(() => { });
|
|
46
|
+
resolve({ behavior: 'deny', message: 'Permission request timed out' });
|
|
47
|
+
}, 60_000);
|
|
48
|
+
pendingPermissions.set(requestId, {
|
|
49
|
+
resolve: (result) => {
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
pendingPermissions.delete(requestId);
|
|
52
|
+
resolve(result);
|
|
53
|
+
},
|
|
54
|
+
channelId: channel.id,
|
|
55
|
+
messageId: msg.id,
|
|
56
|
+
userId,
|
|
57
|
+
toolInput,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Handle permission button interactions.
|
|
63
|
+
*/
|
|
64
|
+
export async function handlePermission(interaction) {
|
|
65
|
+
const parts = interaction.customId.split(':');
|
|
66
|
+
// a4d:perm:{requestId}:{action}
|
|
67
|
+
const requestId = parts[2];
|
|
68
|
+
const action = parts[3];
|
|
69
|
+
const pending = pendingPermissions.get(requestId);
|
|
70
|
+
if (!pending) {
|
|
71
|
+
await interaction.reply({ content: 'This permission request has expired.', flags: MessageFlags.Ephemeral });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Only session owner can approve/deny
|
|
75
|
+
if (interaction.user.id !== pending.userId) {
|
|
76
|
+
await interaction.reply({ content: 'Only the session owner can approve or deny this.', flags: MessageFlags.Ephemeral });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (action === 'details') {
|
|
80
|
+
// Show full input as ephemeral (don't resolve/delete)
|
|
81
|
+
const fullInput = JSON.stringify(pending.toolInput, null, 2);
|
|
82
|
+
const truncated = fullInput.length > 1900 ? fullInput.slice(0, 1900) + '\n...' : fullInput;
|
|
83
|
+
await interaction.reply({
|
|
84
|
+
content: `\`\`\`json\n${truncated}\n\`\`\``,
|
|
85
|
+
flags: MessageFlags.Ephemeral,
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (action === 'allow') {
|
|
90
|
+
const embed = EmbedBuilder.from(interaction.message.embeds[0])
|
|
91
|
+
.setTitle('Permission Granted')
|
|
92
|
+
.setColor(COLORS.IDLE);
|
|
93
|
+
await interaction.update({ embeds: [embed], components: [buildDisabledRow()] });
|
|
94
|
+
pending.resolve({ behavior: 'allow', updatedInput: {} });
|
|
95
|
+
}
|
|
96
|
+
else if (action === 'deny') {
|
|
97
|
+
const embed = EmbedBuilder.from(interaction.message.embeds[0])
|
|
98
|
+
.setTitle('Permission Denied')
|
|
99
|
+
.setColor(COLORS.STOPPED);
|
|
100
|
+
await interaction.update({ embeds: [embed], components: [buildDisabledRow()] });
|
|
101
|
+
pending.resolve({ behavior: 'deny', message: 'User denied via Discord' });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function buildDisabledRow() {
|
|
105
|
+
return new ActionRowBuilder().addComponents(new ButtonBuilder().setCustomId('a4d:perm:x:allow').setLabel('Allow').setStyle(ButtonStyle.Success).setDisabled(true), new ButtonBuilder().setCustomId('a4d:perm:x:deny').setLabel('Deny').setStyle(ButtonStyle.Danger).setDisabled(true), new ButtonBuilder().setCustomId('a4d:perm:x:details').setLabel('Details').setStyle(ButtonStyle.Secondary).setDisabled(true));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=permissionHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionHandler.js","sourceRoot":"","sources":["../../src/interactions/permissionHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,GAIb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE/E,8BAA8B;AAC9B,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAUlE,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAoB,EACpB,MAAc,EACd,QAAgB,EAChB,SAAkC;IAElC,wBAAwB;IACxB,IAAI,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,8BAA8B;IAE1E,yBAAyB;IACzB,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAgC,CAAC,CAAC;IACjF,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE;SAC7B,QAAQ,CAAC,GAAG,KAAK,qBAAqB,CAAC;SACvC,cAAc,CAAC,aAAa,QAAQ,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;SACzE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC;SAC3B,SAAS,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAEhD,gBAAgB;IAChB,MAAM,GAAG,GAAG,IAAI,gBAAgB,EAAoC,CAAC,aAAa,CAChF,IAAI,aAAa,EAAE;SAChB,WAAW,CAAC,YAAY,SAAS,QAAQ,CAAC;SAC1C,QAAQ,CAAC,OAAO,CAAC;SACjB,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,EAChC,IAAI,aAAa,EAAE;SAChB,WAAW,CAAC,YAAY,SAAS,OAAO,CAAC;SACzC,QAAQ,CAAC,MAAM,CAAC;SAChB,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,EAC/B,IAAI,aAAa,EAAE;SAChB,WAAW,CAAC,YAAY,SAAS,UAAU,CAAC;SAC5C,QAAQ,CAAC,SAAS,CAAC;SACnB,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CACnC,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEvE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;iBAC3C,QAAQ,CAAC,GAAG,KAAK,iCAAiC,CAAC;iBACnD,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC5B,MAAM,WAAW,GAAG,gBAAgB,EAAE,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACjF,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,CAAC;QACzE,CAAC,EAAE,MAAM,CAAC,CAAC;QAEX,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE;YAChC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;gBAClB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;YACD,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,SAAS,EAAE,GAAG,CAAC,EAAE;YACjB,MAAM;YACN,SAAS;SACV,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAA8B;IACnE,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9C,gCAAgC;IAChC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAExB,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,sCAAsC,EAAE,KAAK,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QAC5G,OAAO;IACT,CAAC;IAED,sCAAsC;IACtC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,kDAAkD,EAAE,KAAK,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QACxH,OAAO;IACT,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,sDAAsD;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3F,MAAM,WAAW,CAAC,KAAK,CAAC;YACtB,OAAO,EAAE,eAAe,SAAS,UAAU;YAC3C,KAAK,EAAE,YAAY,CAAC,SAAS;SAC9B,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aAC3D,QAAQ,CAAC,oBAAoB,CAAC;aAC9B,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;SAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aAC3D,QAAQ,CAAC,mBAAmB,CAAC;aAC7B,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,IAAI,gBAAgB,EAAoC,CAAC,aAAa,CAC3E,IAAI,aAAa,EAAE,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EACrH,IAAI,aAAa,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAClH,IAAI,aAAa,EAAE,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAC5H,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ButtonInteraction } from 'discord.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle the Stop button for a session channel.
|
|
4
|
+
*/
|
|
5
|
+
export declare function handleSessionStop(interaction: ButtonInteraction): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Handle the Archive button for a session channel.
|
|
8
|
+
*/
|
|
9
|
+
export declare function handleSessionArchive(interaction: ButtonInteraction): Promise<void>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Session control handlers (Stop / Archive) -- AGE-018
|
|
2
|
+
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, } from 'discord.js';
|
|
3
|
+
import { sessionManager } from '../sessions/sessionManager.js';
|
|
4
|
+
import { removeSessionFromGuild } from '../sessions/sessionStore.js';
|
|
5
|
+
import { buildStatusEmbed, COLORS } from '../formatters/embedBuilder.js';
|
|
6
|
+
/**
|
|
7
|
+
* Find the pinned status embed message in a channel.
|
|
8
|
+
*/
|
|
9
|
+
async function findStatusMessage(channel) {
|
|
10
|
+
const pinned = await channel.messages.fetchPinned();
|
|
11
|
+
return pinned.find((m) => m.author.id === channel.client.user?.id && m.embeds.length > 0) ?? null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build disabled control row (used after stop/archive).
|
|
15
|
+
*/
|
|
16
|
+
function buildDisabledControlRow() {
|
|
17
|
+
return new ActionRowBuilder().addComponents(new ButtonBuilder()
|
|
18
|
+
.setCustomId('a4d:session:stop')
|
|
19
|
+
.setLabel('Stop')
|
|
20
|
+
.setStyle(ButtonStyle.Danger)
|
|
21
|
+
.setDisabled(true), new ButtonBuilder()
|
|
22
|
+
.setCustomId('a4d:session:archive')
|
|
23
|
+
.setLabel('Archive')
|
|
24
|
+
.setStyle(ButtonStyle.Secondary)
|
|
25
|
+
.setDisabled(true));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Handle the Stop button for a session channel.
|
|
29
|
+
*/
|
|
30
|
+
export async function handleSessionStop(interaction) {
|
|
31
|
+
const channelId = interaction.channelId;
|
|
32
|
+
const session = sessionManager.getSession(channelId);
|
|
33
|
+
if (!session) {
|
|
34
|
+
await interaction.reply({ content: 'No active session in this channel.', ephemeral: true });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await interaction.deferUpdate();
|
|
38
|
+
sessionManager.stopSession(channelId);
|
|
39
|
+
removeSessionFromGuild(session.guildId, channelId);
|
|
40
|
+
// Update the pinned status embed
|
|
41
|
+
const textChannel = interaction.channel;
|
|
42
|
+
const statusMsg = await findStatusMessage(textChannel);
|
|
43
|
+
if (statusMsg) {
|
|
44
|
+
const updatedEmbed = buildStatusEmbed({
|
|
45
|
+
status: 'Session Stopped',
|
|
46
|
+
color: COLORS.STOPPED,
|
|
47
|
+
cwd: statusMsg.embeds[0]?.fields.find((f) => f.name === 'Directory')?.value ?? session.cwd,
|
|
48
|
+
model: statusMsg.embeds[0]?.fields.find((f) => f.name === 'Model')?.value ?? 'opus',
|
|
49
|
+
sessionId: session.sessionId || 'pending',
|
|
50
|
+
costUsd: session.totalCostUsd,
|
|
51
|
+
startedAt: session.createdAt,
|
|
52
|
+
});
|
|
53
|
+
await statusMsg.edit({ embeds: [updatedEmbed], components: [buildDisabledControlRow()] });
|
|
54
|
+
}
|
|
55
|
+
await textChannel.send('Session stopped by user.');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle the Archive button for a session channel.
|
|
59
|
+
*/
|
|
60
|
+
export async function handleSessionArchive(interaction) {
|
|
61
|
+
const channelId = interaction.channelId;
|
|
62
|
+
const session = sessionManager.getSession(channelId);
|
|
63
|
+
await interaction.deferUpdate();
|
|
64
|
+
// Stop session if it is still running
|
|
65
|
+
if (session) {
|
|
66
|
+
if (session.state !== 'stopped' && session.state !== 'archived') {
|
|
67
|
+
sessionManager.stopSession(channelId);
|
|
68
|
+
}
|
|
69
|
+
removeSessionFromGuild(session.guildId, channelId);
|
|
70
|
+
}
|
|
71
|
+
const textChannel = interaction.channel;
|
|
72
|
+
// Update the pinned status embed
|
|
73
|
+
const statusMsg = await findStatusMessage(textChannel);
|
|
74
|
+
if (statusMsg) {
|
|
75
|
+
const updatedEmbed = buildStatusEmbed({
|
|
76
|
+
status: 'Session Archived',
|
|
77
|
+
color: COLORS.ARCHIVED,
|
|
78
|
+
cwd: statusMsg.embeds[0]?.fields.find((f) => f.name === 'Directory')?.value ?? session?.cwd ?? 'unknown',
|
|
79
|
+
model: statusMsg.embeds[0]?.fields.find((f) => f.name === 'Model')?.value ?? 'opus',
|
|
80
|
+
sessionId: session?.sessionId || statusMsg.embeds[0]?.fields.find((f) => f.name === 'Session ID')?.value || 'unknown',
|
|
81
|
+
costUsd: session?.totalCostUsd ?? 0,
|
|
82
|
+
startedAt: session?.createdAt ?? statusMsg.embeds[0]?.fields.find((f) => f.name === 'Started')?.value ?? 'unknown',
|
|
83
|
+
});
|
|
84
|
+
await statusMsg.edit({ embeds: [updatedEmbed], components: [buildDisabledControlRow()] });
|
|
85
|
+
}
|
|
86
|
+
// Set channel to read-only: deny SendMessages for @everyone
|
|
87
|
+
const guild = interaction.guild;
|
|
88
|
+
if (guild) {
|
|
89
|
+
await textChannel.permissionOverwrites.edit(guild.roles.everyone, {
|
|
90
|
+
SendMessages: false,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
await textChannel.send('Session archived. This channel is now read-only.');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=sessionControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionControls.js","sourceRoot":"","sources":["../../src/interactions/sessionControls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { sessionManager } from './sessionManager.js';
|
|
2
|
+
import { chunkMessage } from '../formatters/chunker.js';
|
|
3
|
+
import { buildStatusEmbed, COLORS } from '../formatters/embedBuilder.js';
|
|
4
|
+
import { StreamHandler } from './streamHandler.js';
|
|
5
|
+
import { ToolProgressHandler } from './toolProgress.js';
|
|
6
|
+
import { formatThreadName, formatToolInput } from '../formatters/toolFormatter.js';
|
|
7
|
+
// Track active stream handlers per channel (keyed by "channelId:text" or "channelId:thinking")
|
|
8
|
+
const activeStreams = new Map();
|
|
9
|
+
// Track active tool progress handlers per channel
|
|
10
|
+
const activeToolProgress = new Map();
|
|
11
|
+
// Channels where StreamHandler.finalize() just sent the final text,
|
|
12
|
+
// so the 'assistant' handler should skip re-sending it.
|
|
13
|
+
const recentlyFinalized = new Set();
|
|
14
|
+
// Track tool-call threads per channel for the current turn
|
|
15
|
+
const turnThreads = new Map();
|
|
16
|
+
function trackThread(channelId, threadId) {
|
|
17
|
+
const threads = turnThreads.get(channelId) || [];
|
|
18
|
+
threads.push(threadId);
|
|
19
|
+
turnThreads.set(channelId, threads);
|
|
20
|
+
}
|
|
21
|
+
export function getAndClearTurnThreads(channelId) {
|
|
22
|
+
const threads = turnThreads.get(channelId) || [];
|
|
23
|
+
turnThreads.delete(channelId);
|
|
24
|
+
return threads;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Finalize and clean up all active stream handlers for a given channel.
|
|
28
|
+
*/
|
|
29
|
+
async function finalizeStreamsForChannel(channelId) {
|
|
30
|
+
// Collect and remove from map FIRST to prevent re-entrant double-finalize
|
|
31
|
+
const toFinalize = [];
|
|
32
|
+
for (const [key, handler] of activeStreams) {
|
|
33
|
+
if (key.startsWith(channelId + ':')) {
|
|
34
|
+
toFinalize.push({ key, handler });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
for (const { key } of toFinalize) {
|
|
38
|
+
activeStreams.delete(key);
|
|
39
|
+
}
|
|
40
|
+
let hadTextStream = false;
|
|
41
|
+
for (const { key, handler } of toFinalize) {
|
|
42
|
+
if (key.endsWith(':text'))
|
|
43
|
+
hadTextStream = true;
|
|
44
|
+
await handler.finalize();
|
|
45
|
+
}
|
|
46
|
+
if (hadTextStream) {
|
|
47
|
+
recentlyFinalized.add(channelId);
|
|
48
|
+
setTimeout(() => recentlyFinalized.delete(channelId), 5000);
|
|
49
|
+
}
|
|
50
|
+
return hadTextStream;
|
|
51
|
+
}
|
|
52
|
+
let handlersRegistered = false;
|
|
53
|
+
export function setupEventHandlers(client) {
|
|
54
|
+
if (handlersRegistered)
|
|
55
|
+
return;
|
|
56
|
+
handlersRegistered = true;
|
|
57
|
+
// --- Stream events (text / thinking deltas) ---
|
|
58
|
+
sessionManager.on('stream_event', async (channelId, msg) => {
|
|
59
|
+
const channel = client.channels.cache.get(channelId);
|
|
60
|
+
if (!channel?.isTextBased())
|
|
61
|
+
return;
|
|
62
|
+
const textChannel = channel;
|
|
63
|
+
// msg may wrap the event in different shapes depending on SDK version
|
|
64
|
+
const event = msg.event || msg;
|
|
65
|
+
if (event.type === 'content_block_start') {
|
|
66
|
+
const blockType = event.content_block?.type;
|
|
67
|
+
if (blockType === 'text' || blockType === 'thinking') {
|
|
68
|
+
const handler = new StreamHandler(textChannel, blockType);
|
|
69
|
+
activeStreams.set(`${channelId}:${blockType}`, handler);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (event.type === 'content_block_delta') {
|
|
73
|
+
if (event.delta?.type === 'text_delta') {
|
|
74
|
+
const handler = activeStreams.get(`${channelId}:text`);
|
|
75
|
+
handler?.push(event.delta.text);
|
|
76
|
+
}
|
|
77
|
+
if (event.delta?.type === 'thinking_delta') {
|
|
78
|
+
const handler = activeStreams.get(`${channelId}:thinking`);
|
|
79
|
+
handler?.push(event.delta.thinking);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (event.type === 'content_block_stop') {
|
|
83
|
+
// Finalize all handlers for this channel whose block just stopped
|
|
84
|
+
await finalizeStreamsForChannel(channelId);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// --- Tool progress events ---
|
|
88
|
+
sessionManager.on('tool_progress', async (channelId, msg) => {
|
|
89
|
+
const channel = client.channels.cache.get(channelId);
|
|
90
|
+
if (!channel?.isTextBased())
|
|
91
|
+
return;
|
|
92
|
+
const textChannel = channel;
|
|
93
|
+
const toolName = msg.tool_name || msg.name || 'tool';
|
|
94
|
+
if (!activeToolProgress.has(channelId)) {
|
|
95
|
+
const handler = new ToolProgressHandler(textChannel, toolName);
|
|
96
|
+
activeToolProgress.set(channelId, handler);
|
|
97
|
+
}
|
|
98
|
+
activeToolProgress.get(channelId).update();
|
|
99
|
+
});
|
|
100
|
+
// --- Assistant messages ---
|
|
101
|
+
sessionManager.on('assistant', async (channelId, msg) => {
|
|
102
|
+
const channel = client.channels.cache.get(channelId);
|
|
103
|
+
if (!channel?.isTextBased())
|
|
104
|
+
return;
|
|
105
|
+
const textChannel = channel;
|
|
106
|
+
if (msg.message?.content) {
|
|
107
|
+
const contentBlocks = msg.message.content;
|
|
108
|
+
// Text blocks are handled by StreamHandler via stream_event.
|
|
109
|
+
// Only send text here as a fallback if NO stream handler was active.
|
|
110
|
+
const hadStream = recentlyFinalized.has(channelId) ||
|
|
111
|
+
activeStreams.has(`${channelId}:text`);
|
|
112
|
+
if (!hadStream) {
|
|
113
|
+
for (const block of contentBlocks) {
|
|
114
|
+
if (block.type === 'text' && block.text) {
|
|
115
|
+
const chunks = chunkMessage(block.text);
|
|
116
|
+
for (const chunk of chunks) {
|
|
117
|
+
await textChannel.send(chunk);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Handle tool_use blocks -- create threads for each
|
|
123
|
+
const toolUseBlocks = contentBlocks.filter((b) => b.type === 'tool_use');
|
|
124
|
+
if (toolUseBlocks.length > 0) {
|
|
125
|
+
if (toolUseBlocks.length > 1) {
|
|
126
|
+
await textChannel.send(`\uD83D\uDD27 Executing ${toolUseBlocks.length} tool calls...`);
|
|
127
|
+
}
|
|
128
|
+
for (const block of toolUseBlocks) {
|
|
129
|
+
const threadName = formatThreadName(block.name || 'unknown', block.input || {});
|
|
130
|
+
const thread = await textChannel.threads.create({
|
|
131
|
+
name: threadName,
|
|
132
|
+
autoArchiveDuration: 60,
|
|
133
|
+
reason: `A4D tool call: ${block.name || 'unknown'}`,
|
|
134
|
+
});
|
|
135
|
+
const inputText = formatToolInput(block.name || 'unknown', block.input || {});
|
|
136
|
+
await thread.send(inputText);
|
|
137
|
+
trackThread(channelId, thread.id);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// --- Result events ---
|
|
143
|
+
sessionManager.on('result', async (channelId, _msg) => {
|
|
144
|
+
// Clean up any lingering stream handlers
|
|
145
|
+
await finalizeStreamsForChannel(channelId);
|
|
146
|
+
// Clean up any lingering tool progress handlers
|
|
147
|
+
const toolHandler = activeToolProgress.get(channelId);
|
|
148
|
+
if (toolHandler) {
|
|
149
|
+
await toolHandler.finalize();
|
|
150
|
+
activeToolProgress.delete(channelId);
|
|
151
|
+
}
|
|
152
|
+
// Remove hourglass, add checkmark on the last user message
|
|
153
|
+
const channel = client.channels.cache.get(channelId);
|
|
154
|
+
if (!channel?.isTextBased())
|
|
155
|
+
return;
|
|
156
|
+
const session = sessionManager.getSession(channelId);
|
|
157
|
+
if (!session)
|
|
158
|
+
return;
|
|
159
|
+
const textChannel = channel;
|
|
160
|
+
// Update the pinned status embed with new cost
|
|
161
|
+
try {
|
|
162
|
+
const pinned = await textChannel.messages.fetchPinned();
|
|
163
|
+
const statusMsg = pinned.find((m) => m.author.id === client.user?.id && m.embeds.length > 0);
|
|
164
|
+
if (statusMsg) {
|
|
165
|
+
const embed = statusMsg.embeds[0];
|
|
166
|
+
const updatedEmbed = buildStatusEmbed({
|
|
167
|
+
status: 'Session Active',
|
|
168
|
+
color: COLORS.IDLE,
|
|
169
|
+
cwd: embed?.fields.find((f) => f.name === 'Directory')?.value ?? session.cwd,
|
|
170
|
+
model: embed?.fields.find((f) => f.name === 'Model')?.value ?? 'opus',
|
|
171
|
+
sessionId: session.sessionId || 'pending',
|
|
172
|
+
costUsd: session.totalCostUsd,
|
|
173
|
+
startedAt: session.createdAt,
|
|
174
|
+
});
|
|
175
|
+
await statusMsg.edit({ embeds: [updatedEmbed] });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Status embed update is best-effort
|
|
180
|
+
}
|
|
181
|
+
// Find the most recent user message to update reactions
|
|
182
|
+
try {
|
|
183
|
+
const messages = await textChannel.messages.fetch({ limit: 20 });
|
|
184
|
+
const userMsg = messages.find((m) => !m.author.bot && m.reactions.cache.has('\u23f3'));
|
|
185
|
+
if (userMsg) {
|
|
186
|
+
await userMsg.reactions.cache.get('\u23f3')?.users.remove(client.user.id).catch(() => { });
|
|
187
|
+
await userMsg.react('\u2705').catch(() => { });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Reaction cleanup is best-effort
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
sessionManager.on('error', async (channelId, _err) => {
|
|
195
|
+
// Clean up any active handlers on error
|
|
196
|
+
await finalizeStreamsForChannel(channelId);
|
|
197
|
+
const toolHandler = activeToolProgress.get(channelId);
|
|
198
|
+
if (toolHandler) {
|
|
199
|
+
await toolHandler.finalize();
|
|
200
|
+
activeToolProgress.delete(channelId);
|
|
201
|
+
}
|
|
202
|
+
const channel = client.channels.cache.get(channelId);
|
|
203
|
+
if (!channel?.isTextBased())
|
|
204
|
+
return;
|
|
205
|
+
const textChannel = channel;
|
|
206
|
+
await textChannel.send('An error occurred in this session. The session may have stopped.');
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=eventHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventHandler.js","sourceRoot":"","sources":["../../src/sessions/eventHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type CanUseTool, type Query, type SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
3
|
+
export type SessionState = 'idle' | 'running' | 'stopped' | 'archived';
|
|
4
|
+
export interface ActiveSession {
|
|
5
|
+
query: Query;
|
|
6
|
+
channelId: string;
|
|
7
|
+
guildId: string;
|
|
8
|
+
userId: string;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
cwd: string;
|
|
11
|
+
state: SessionState;
|
|
12
|
+
totalCostUsd: number;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
resolveNext: ((msg: SDKUserMessage) => void) | null;
|
|
15
|
+
abortController: AbortController;
|
|
16
|
+
}
|
|
17
|
+
declare class SessionManager extends EventEmitter {
|
|
18
|
+
private sessions;
|
|
19
|
+
createSession(guildId: string, userId: string, channelId: string, cwd: string, model?: string, canUseTool?: CanUseTool): ActiveSession;
|
|
20
|
+
resumeSession(guildId: string, userId: string, channelId: string, sessionId: string, cwd: string, model?: string, canUseTool?: CanUseTool): ActiveSession;
|
|
21
|
+
sendMessage(channelId: string, content: string): void;
|
|
22
|
+
getSession(channelId: string): ActiveSession | null;
|
|
23
|
+
stopSession(channelId: string): void;
|
|
24
|
+
removeSession(channelId: string): void;
|
|
25
|
+
getAllSessions(): ActiveSession[];
|
|
26
|
+
private _processEvents;
|
|
27
|
+
}
|
|
28
|
+
export declare const sessionManager: SessionManager;
|
|
29
|
+
export {};
|