mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-17 01:50:47 -04:00
fixe?
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
// Chat Command Result Formatter
|
||||
// Purpose: Converts command reply payloads into readable web-chat text.
|
||||
// Scope: Keeps web chat rendering local instead of routing command output through Discord bridge messages.
|
||||
|
||||
function normalizeText(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function embedToText(embed) {
|
||||
const data = embed?.data || embed || {};
|
||||
const lines = [];
|
||||
if (data.title) lines.push(String(data.title));
|
||||
if (data.description) lines.push(String(data.description));
|
||||
(Array.isArray(data.fields) ? data.fields : []).forEach((field) => {
|
||||
if (!field) return;
|
||||
// Discord embeds are the main structured result shape produced by existing
|
||||
// commands. Web chat is plain text, so only flatten the human-readable
|
||||
// fields instead of preserving Discord presentation concerns.
|
||||
lines.push(`${field.name || 'Field'}\n${field.value || ''}`.trim());
|
||||
});
|
||||
if (data.footer?.text) lines.push(String(data.footer.text));
|
||||
return lines.map(normalizeText).filter(Boolean).join('\n\n');
|
||||
}
|
||||
|
||||
function commandReplyToText(payload) {
|
||||
if (typeof payload === 'string') return normalizeText(payload);
|
||||
if (!payload || typeof payload !== 'object') return '';
|
||||
const parts = [];
|
||||
if (payload.content) parts.push(String(payload.content));
|
||||
(Array.isArray(payload.embeds) ? payload.embeds : []).forEach((embed) => {
|
||||
const text = embedToText(embed);
|
||||
if (text) parts.push(text);
|
||||
});
|
||||
(Array.isArray(payload.files) ? payload.files : []).forEach((file) => {
|
||||
const name = file?.name || file?.filename || 'attachment';
|
||||
parts.push(String(name));
|
||||
});
|
||||
return parts.map(normalizeText).filter(Boolean).join('\n\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
commandReplyToText,
|
||||
embedToText,
|
||||
};
|
||||
@@ -55,7 +55,7 @@ function createHandlers({ sendSystemMessage }) {
|
||||
// messages. Running the command after broadcast preserves the user-visible
|
||||
// transcript while keeping permissions and command execution entirely on
|
||||
// the server.
|
||||
const ranCommand = await runChatTextCommand({ text: clean, socket });
|
||||
const ranCommand = await runChatTextCommand({ text: clean, socket, sendSystemMessage });
|
||||
cb({ success: true, command: ranCommand });
|
||||
return;
|
||||
} catch (err) {
|
||||
|
||||
@@ -20,6 +20,7 @@ const { publishEvent } = require('../eventBus');
|
||||
const assignmentService = require('../assignmentService');
|
||||
const { loadConfig } = require('../../helpers/configLoader');
|
||||
const { createCommandHandlers } = require('../discordBotService/commands');
|
||||
const { commandReplyToText } = require('./commandResultFormatter');
|
||||
const {
|
||||
buildReplayJobId,
|
||||
buildReplayTitle,
|
||||
@@ -45,7 +46,7 @@ function buildRequesterLabel(socket) {
|
||||
return getNickname(socket) || socket?.data?.user?.username || socket?.id || 'unknown';
|
||||
}
|
||||
|
||||
function createWebReplayTextCommand(socket, replayApi) {
|
||||
function createWebReplayTextCommand(socket, sendSystemMessage, replayApi) {
|
||||
return function createReplayHandler({
|
||||
rovers,
|
||||
getReplaySources: getAllReplaySources,
|
||||
@@ -106,12 +107,12 @@ function createWebReplayTextCommand(socket, replayApi) {
|
||||
},
|
||||
});
|
||||
const title = buildReplayTitle({ explicitTitle: '', sources: resolved.sources || [] });
|
||||
await message.reply({ content: `Replay accepted: ${title}` });
|
||||
sendSystemMessage(`Replay accepted: ${title}`, { nickname: 'Rover bot', bot: true });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function createChatCommandMessage({ socket, text }) {
|
||||
function createChatCommandMessage({ socket, text, sendSystemMessage }) {
|
||||
const nickname = buildRequesterLabel(socket);
|
||||
return {
|
||||
content: String(text || '').trim(),
|
||||
@@ -124,32 +125,20 @@ function createChatCommandMessage({ socket, text }) {
|
||||
nickname,
|
||||
},
|
||||
reply: async (payload) => {
|
||||
const replyPayload = typeof payload === 'string'
|
||||
? { content: sanitizeMentions(payload) }
|
||||
: {
|
||||
content: sanitizeMentions(payload?.content || ''),
|
||||
options: {
|
||||
embeds: payload?.embeds || undefined,
|
||||
files: payload?.files || undefined,
|
||||
},
|
||||
};
|
||||
// Web chat does not get a private shortcut for command results. The bot
|
||||
// posts the Discord-shaped reply into the configured bridge channel, and
|
||||
// the normal bridge inbound path decides how that Discord message appears
|
||||
// in web chat.
|
||||
publishEvent({ source: 'chatCommand', type: 'discord.bridgeSend', payload: replyPayload });
|
||||
return null;
|
||||
const response = sanitizeMentions(commandReplyToText(payload));
|
||||
if (!response) return null;
|
||||
return sendSystemMessage(response, { nickname: 'Rover bot', bot: true });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function runChatTextCommand({ text, socket }) {
|
||||
async function runChatTextCommand({ text, socket, sendSystemMessage }) {
|
||||
if (!isTextCommand(text)) return false;
|
||||
// ReplayEngineV2 has startup side effects by design. Loading it lazily here
|
||||
// keeps ordinary chatService initialization from changing the service boot
|
||||
// order, while still letting `rs replay` use the existing replay pipeline.
|
||||
const replayApi = require('../replayEngineV2');
|
||||
const message = createChatCommandMessage({ socket, text });
|
||||
const message = createChatCommandMessage({ socket, text, sendSystemMessage });
|
||||
const commands = createCommandHandlers({
|
||||
logger: null,
|
||||
client: null,
|
||||
@@ -189,20 +178,17 @@ async function runChatTextCommand({ text, socket }) {
|
||||
isLockdownAdminUser: (id) => String(id) === String(socket.id) && isLockdownAdmin(socket),
|
||||
discordConfig,
|
||||
config,
|
||||
createReplayTextCommand: createWebReplayTextCommand(socket, replayApi),
|
||||
createReplayTextCommand: createWebReplayTextCommand(socket, sendSystemMessage, replayApi),
|
||||
});
|
||||
|
||||
// Let the shared router perform normal command permission checks. Site chat
|
||||
// has already broadcast the user's command text; any command reply is posted
|
||||
// into Discord and returns to web chat through the ordinary bridge inbound path.
|
||||
// has already broadcast the user's command text, so command replies become a
|
||||
// local bot chat message instead of being routed through Discord as an
|
||||
// internal transport.
|
||||
try {
|
||||
await commands.handleCommand(message);
|
||||
} catch (err) {
|
||||
publishEvent({
|
||||
source: 'chatCommand',
|
||||
type: 'discord.bridgeSend',
|
||||
payload: { content: sanitizeMentions(`Command failed: ${err.message || 'unknown error'}`) },
|
||||
});
|
||||
sendSystemMessage(`Command failed: ${sanitizeMentions(err.message || 'unknown error')}`, { nickname: 'Rover bot', bot: true });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user