pi-discord-bot 0.1.3 → 0.1.31

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.
@@ -1,4 +1,10 @@
1
1
  import * as log from "./log.js";
2
+ function clearByPrefix(registry, prefix) {
3
+ for (const key of registry.keys()) {
4
+ if (key.startsWith(prefix))
5
+ registry.delete(key);
6
+ }
7
+ }
2
8
  async function rejectForeignInteraction(interaction, message) {
3
9
  await interaction.reply({ content: message, ephemeral: true });
4
10
  return true;
@@ -9,6 +15,7 @@ export async function handleSelectMenuInteraction(interaction, state) {
9
15
  if (interaction.user.id !== modelRequest.userId)
10
16
  return rejectForeignInteraction(interaction, "This selector belongs to another user.");
11
17
  state.pendingModelSelections.delete(interaction.customId);
18
+ clearByPrefix(state.pendingModelPages, interaction.customId.replace(/:select$/, ":"));
12
19
  await interaction.update({ content: `Selected model: ${interaction.values[0]}`, embeds: [], components: [] });
13
20
  modelRequest.resolve(interaction.values[0] ?? null);
14
21
  return true;
@@ -18,6 +25,7 @@ export async function handleSelectMenuInteraction(interaction, state) {
18
25
  if (interaction.user.id !== scopedRequest.userId)
19
26
  return rejectForeignInteraction(interaction, "This selector belongs to another user.");
20
27
  state.pendingScopedSelections.delete(interaction.customId);
28
+ clearByPrefix(state.pendingScopedPages, interaction.customId.replace(/:select$/, ":"));
21
29
  await interaction.update({ content: interaction.values.length > 0 ? `Scoped models updated (${interaction.values.length} selected).` : "Scoped models cleared.", embeds: [], components: [] });
22
30
  scopedRequest.resolve(interaction.values);
23
31
  return true;
@@ -27,6 +35,7 @@ export async function handleSelectMenuInteraction(interaction, state) {
27
35
  if (interaction.user.id !== treeRequest.userId)
28
36
  return rejectForeignInteraction(interaction, "This tree browser belongs to another user.");
29
37
  state.pendingTreeSelections.delete(interaction.customId);
38
+ clearByPrefix(state.pendingTreePages, interaction.customId.replace(/:select$/, ":"));
30
39
  await interaction.update({ content: `Navigating to ${interaction.values[0]}...`, embeds: [], components: [] });
31
40
  log.info(`tree navigate selected by ${interaction.user.username}: ${interaction.values[0]}`);
32
41
  treeRequest.resolve(interaction.values[0] ?? null);
package/dist/discord.js CHANGED
@@ -7,6 +7,10 @@ import { buildSlashCommands, isAllowedDiscordMessage, loadDiscordPolicy } from "
7
7
  import * as log from "./log.js";
8
8
  import { buildApprovalCard, buildModelSelectionCard, buildScopedModelSelectionCard, buildSessionCard, buildSettingsCard, buildTreeSelectionCard, } from "./discord-ui.js";
9
9
  import { clearPending, registerManyPending, registerPending, resolveOnTimeout } from "./discord-registry.js";
10
+ function isImmediateCommandText(text) {
11
+ const command = text.trim().split(/\s+/)[0];
12
+ return new Set(["/help", "/session", "/tree", "/model", "/settings"]).has(command);
13
+ }
10
14
  class ChannelQueue {
11
15
  queue = [];
12
16
  processing = false;
@@ -168,7 +172,12 @@ export class DiscordBot {
168
172
  text: cleanedText,
169
173
  attachments: attachments,
170
174
  };
171
- this.queueFor(conversationKey).enqueue(() => this.handler.handleEvent(event, this));
175
+ if (isImmediateCommandText(cleanedText)) {
176
+ void this.handler.handleEvent(event, this);
177
+ }
178
+ else {
179
+ this.queueFor(conversationKey).enqueue(() => this.handler.handleEvent(event, this));
180
+ }
172
181
  }
173
182
  async onSelectMenu(interaction) {
174
183
  await handleSelectMenuInteraction(interaction, this.interactionState);
@@ -191,7 +200,12 @@ export class DiscordBot {
191
200
  this.pendingSlashInteractions.set(interaction.id, interaction);
192
201
  const event = buildSlashEvent(interaction, text);
193
202
  const key = this.getConversationKeyFromIds(event.guildId, event.channelId, event.threadId, event.userId);
194
- this.queueFor(key).enqueue(() => this.handler.handleEvent(event, this));
203
+ if (isImmediateCommandText(text)) {
204
+ void this.handler.handleEvent(event, this);
205
+ }
206
+ else {
207
+ this.queueFor(key).enqueue(() => this.handler.handleEvent(event, this));
208
+ }
195
209
  }
196
210
  getConversationKey(message) {
197
211
  return this.getConversationKeyFromIds(message.guildId ?? undefined, message.channel.id, message.channel.isThread() ? message.channel.id : undefined, message.author.id);
package/dist/main.js CHANGED
@@ -82,6 +82,15 @@ function isUiCommand(command) {
82
82
  "/exit",
83
83
  ]).has(command);
84
84
  }
85
+ function isImmediateCommand(command) {
86
+ return new Set([
87
+ "/help",
88
+ "/session",
89
+ "/tree",
90
+ "/model",
91
+ "/settings",
92
+ ]).has(command);
93
+ }
85
94
  async function handleCommand(event, transport) {
86
95
  const text = event.text.trim();
87
96
  if (!text.startsWith("/"))
@@ -93,7 +102,7 @@ async function handleCommand(event, transport) {
93
102
  if (event.source === "slash" && isUiCommand(command)) {
94
103
  await ctx.setWorking(false);
95
104
  }
96
- if (state.running && command !== "/stop") {
105
+ if (state.running && command !== "/stop" && !isImmediateCommand(command)) {
97
106
  await ctx.replaceMessage("Already working. Use /stop first, then retry your command.");
98
107
  return true;
99
108
  }
@@ -127,7 +136,6 @@ async function handleCommand(event, transport) {
127
136
  while (true) {
128
137
  const selected = await transport.promptTreeSelection(event, { ...browser, page });
129
138
  if (!selected || selected === "close") {
130
- await ctx.replaceMessage(state.runner.getTreeSummary());
131
139
  return true;
132
140
  }
133
141
  if (selected === "prev") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-discord-bot",
3
- "version": "0.1.3",
3
+ "version": "0.1.31",
4
4
  "description": "A small Discord harness built around Pi primitives.",
5
5
  "license": "MIT",
6
6
  "type": "module",