From ff989b3352b085f04063ed8e5a267e3bc2599e0e Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 21:58:46 +0200 Subject: [PATCH 1/9] Move extensions init to function --- public/script.js | 3 ++- public/scripts/extensions.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/script.js b/public/script.js index 8bfbe5a64..cb750e915 100644 --- a/public/script.js +++ b/public/script.js @@ -158,7 +158,7 @@ import { } from './scripts/utils.js'; import { debounce_timeout } from './scripts/constants.js'; -import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js'; +import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, initExtensions, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js'; import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js'; import { tag_map, @@ -956,6 +956,7 @@ async function firstLoadInit() { initCfg(); initLogprobs(); initInputMarkdown(); + initExtensions(); doDailyExtensionUpdatesCheck(); await hideLoader(); await fixViewport(); diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 1d19e82db..182d6ed64 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -1041,7 +1041,7 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { await installExtension(url); } -jQuery(async function () { +export async function initExtensions() { await addExtensionsButtonAndMenu(); $('#extensionsMenuButton').css('display', 'flex'); @@ -1060,4 +1060,4 @@ jQuery(async function () { * @listens #third_party_extension_button#click - The click event of the '#third_party_extension_button' element. */ $('#third_party_extension_button').on('click', () => openThirdPartyExtensionMenu()); -}); +} From eda7493a33785e949b7e04b40512515269a8defd Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 22:46:19 +0200 Subject: [PATCH 2/9] Add extension enable/disable commands - /extension-enable - /extension-disable - Optional "reload" parameter - /reload-page --- public/scripts/extensions.js | 140 ++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 182d6ed64..56a176497 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -1,8 +1,14 @@ import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; -import { hideLoader, showLoader } from './loader.js'; +import { showLoader } from './loader.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; +import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; +import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; +import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { renderTemplate, renderTemplateAsync } from './templates.js'; -import { isSubsetOf, setValueByPath } from './utils.js'; +import { equalsIgnoreCaseAndAccents, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; export { getContext, getApiUrl, @@ -14,7 +20,9 @@ export { ModuleWorkerWrapper, }; +/** @type {string[]} */ export let extensionNames = []; + let manifests = {}; const defaultUrl = 'http://localhost:5100'; @@ -1041,7 +1049,135 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { await installExtension(url); } +/** + * @param {boolean} enable - Whether to enable or disable the extension + * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise} + */ +function getExtensionToggleCallback(enable) { + return async (args, extensionName) => { + if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); + if (!extensionName) { + toastr.warning(`Extension name must be provided as an argument to ${enable ? 'enable' : 'disable'} this extension.`); + return ''; + } + + const reload = isTrueBoolean(args?.reload); + + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + if (enable === !extension_settings.disabledExtensions.includes(internalExtensionName)) { + toastr.info(`Extension ${extensionName} is already ${enable ? 'enabled' : 'disabled'}.`); + return internalExtensionName; + } + + reload && toastr.info(`${enable ? 'Enabling' : 'Disabling'} extension ${extensionName} and reloading...`); + await enableExtension(internalExtensionName, reload); + toastr.success(`Extension ${extensionName} ${enable ? 'enabled' : 'disabled'}.`); + + return internalExtensionName; + }; +} + +function registerExtensionSlashCommands() { + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-enable', + callback: getExtensionToggleCallback(true), + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after enabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Enables a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-enable Summarize
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-disable', + callback: getExtensionToggleCallback(false), + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after disabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Disables a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-disable Summarize
    +
  • +
+
+ `, + })); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reload-page', + callback: async () => { + toastr.info('Reloading the page...'); + location.reload(); + return ''; + }, + helpString: 'Reloads the current page. All further commands will not be processed.', + })); +} + export async function initExtensions() { + registerExtensionSlashCommands(); + await addExtensionsButtonAndMenu(); $('#extensionsMenuButton').css('display', 'flex'); From a6445aee1b1399d0f0de27b0d0cff1037e236cdb Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 23:05:34 +0200 Subject: [PATCH 3/9] Add /extension-toggle --- public/scripts/extensions.js | 99 +++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 56a176497..c99255713 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -8,7 +8,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { renderTemplate, renderTemplateAsync } from './templates.js'; -import { equalsIgnoreCaseAndAccents, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; +import { equalsIgnoreCaseAndAccents, isFalseBoolean, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; export { getContext, getApiUrl, @@ -1050,33 +1050,50 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { } /** - * @param {boolean} enable - Whether to enable or disable the extension + * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise} */ -function getExtensionToggleCallback(enable) { +function getExtensionActionCallback(action) { return async (args, extensionName) => { if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); if (!extensionName) { - toastr.warning(`Extension name must be provided as an argument to ${enable ? 'enable' : 'disable'} this extension.`); + toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); return ''; } const reload = isTrueBoolean(args?.reload); - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); if (!internalExtensionName) { toastr.warning(`Extension ${extensionName} does not exist.`); return ''; } - if (enable === !extension_settings.disabledExtensions.includes(internalExtensionName)) { - toastr.info(`Extension ${extensionName} is already ${enable ? 'enabled' : 'disabled'}.`); + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + + if (action === 'enable' && isEnabled) { + toastr.info(`Extension ${extensionName} is already enabled.`); return internalExtensionName; } - reload && toastr.info(`${enable ? 'Enabling' : 'Disabling'} extension ${extensionName} and reloading...`); - await enableExtension(internalExtensionName, reload); - toastr.success(`Extension ${extensionName} ${enable ? 'enabled' : 'disabled'}.`); + if (action === 'disable' && !isEnabled) { + toastr.info(`Extension ${extensionName} is already disabled.`); + return internalExtensionName; + } + + if (action === 'toggle') { + action = isEnabled ? 'disable' : 'enable'; + } + + reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); + + if (action === 'enable') { + await enableExtension(internalExtensionName, reload); + } else { + await disableExtension(internalExtensionName, reload); + } + + toastr.success(`Extension ${extensionName} ${action}d.`); return internalExtensionName; }; @@ -1085,7 +1102,7 @@ function getExtensionToggleCallback(enable) { function registerExtensionSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'extension-enable', - callback: getExtensionToggleCallback(true), + callback: getExtensionActionCallback('enable'), namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'reload', @@ -1125,7 +1142,7 @@ function registerExtensionSlashCommands() { })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'extension-disable', - callback: getExtensionToggleCallback(false), + callback: getExtensionActionCallback('enable'), namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'reload', @@ -1163,6 +1180,64 @@ function registerExtensionSlashCommands() { `, })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-toggle', + callback: async (args, extensionName) => { + if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); + + const action = isTrueBoolean(args?.state) ? 'enable' : + isFalseBoolean(args?.state) ? 'disable' : + 'toggle'; + + return await getExtensionActionCallback(action)(args, extensionName); + }, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after toggling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'state', + description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', + typeList: [ARGUMENT_TYPE.BOOLEAN], + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Toggles the state of a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-toggle Summarize
    +
  • +
  • +
    /extension-toggle Summarize state=true
    +
  • +
+
+ `, + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'reload-page', From 1a6f0c0922b263dbdcac7904996cfe4fce47805a Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 23:10:00 +0200 Subject: [PATCH 4/9] Add /extension-exists and /extension-state --- public/scripts/extensions.js | 71 +++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index c99255713..6c72c78e6 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -1056,7 +1056,7 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { function getExtensionActionCallback(action) { return async (args, extensionName) => { if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); - if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); if (!extensionName) { toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); return ''; @@ -1184,7 +1184,7 @@ function registerExtensionSlashCommands() { name: 'extension-toggle', callback: async (args, extensionName) => { if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); - if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); const action = isTrueBoolean(args?.state) ? 'enable' : isFalseBoolean(args?.state) ? 'disable' : @@ -1238,6 +1238,73 @@ function registerExtensionSlashCommands() { `, })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-state', + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + return String(isEnabled); + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Returns the state of a specified extension (true if enabled, false if disabled). +
+
+ Example: +
    +
  • +
    /extension-state Summarize
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-exists', + aliases: ['extension-installed'], + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; + return exists ? 'true' : 'false'; + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Checks if a specified extension exists. +
+
+ Example: +
    +
  • +
    /extension-exists LALib
    +
  • +
+
+ `, + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'reload-page', From 169504aa68b243178050bccaaef63c5ef7e29f27 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 23:18:37 +0200 Subject: [PATCH 5/9] Refactor extension slash commands into own file - Weird circle imports again with the slash command classes --- public/script.js | 2 + public/scripts/extensions-slashcommands.js | 276 ++++++++++++++++++++ public/scripts/extensions.js | 280 +-------------------- 3 files changed, 281 insertions(+), 277 deletions(-) create mode 100644 public/scripts/extensions-slashcommands.js diff --git a/public/script.js b/public/script.js index cb750e915..0e675e3e6 100644 --- a/public/script.js +++ b/public/script.js @@ -244,6 +244,7 @@ import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCo import { initInputMarkdown } from './scripts/input-md-formatting.js'; import { AbortReason } from './scripts/util/AbortReason.js'; import { initSystemPrompts } from './scripts/sysprompt.js'; +import { registerExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; //exporting functions and vars for mods export { @@ -957,6 +958,7 @@ async function firstLoadInit() { initLogprobs(); initInputMarkdown(); initExtensions(); + registerExtensionSlashCommands(); doDailyExtensionUpdatesCheck(); await hideLoader(); await fixViewport(); diff --git a/public/scripts/extensions-slashcommands.js b/public/scripts/extensions-slashcommands.js new file mode 100644 index 000000000..62d2e8374 --- /dev/null +++ b/public/scripts/extensions-slashcommands.js @@ -0,0 +1,276 @@ +import { disableExtension, enableExtension, extension_settings, extensionNames } from './extensions.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; +import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; +import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; +import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean } from './utils.js'; + +/** + * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension + * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise} + */ +function getExtensionActionCallback(action) { + return async (args, extensionName) => { + if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + if (!extensionName) { + toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); + return ''; + } + + const reload = isTrueBoolean(args?.reload); + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + + if (action === 'enable' && isEnabled) { + toastr.info(`Extension ${extensionName} is already enabled.`); + return internalExtensionName; + } + + if (action === 'disable' && !isEnabled) { + toastr.info(`Extension ${extensionName} is already disabled.`); + return internalExtensionName; + } + + if (action === 'toggle') { + action = isEnabled ? 'disable' : 'enable'; + } + + reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); + + if (action === 'enable') { + await enableExtension(internalExtensionName, reload); + } else { + await disableExtension(internalExtensionName, reload); + } + + toastr.success(`Extension ${extensionName} ${action}d.`); + + return internalExtensionName; + }; +} + +export function registerExtensionSlashCommands() { + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-enable', + callback: getExtensionActionCallback('enable'), + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after enabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Enables a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-enable Summarize
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-disable', + callback: getExtensionActionCallback('enable'), + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after disabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Disables a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-disable Summarize
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-toggle', + callback: async (args, extensionName) => { + if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + + const action = isTrueBoolean(args?.state) ? 'enable' : + isFalseBoolean(args?.state) ? 'disable' : + 'toggle'; + + return await getExtensionActionCallback(action)(args, extensionName); + }, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after toggling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'state', + description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', + typeList: [ARGUMENT_TYPE.BOOLEAN], + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Toggles the state of a specified extension. +
+
+ By default, the page will be reloaded automatically, stopping any further commands.
+ If reload=false named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
+
+ Example: +
    +
  • +
    /extension-toggle Summarize
    +
  • +
  • +
    /extension-toggle Summarize state=true
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-state', + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + return String(isEnabled); + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Returns the state of a specified extension (true if enabled, false if disabled). +
+
+ Example: +
    +
  • +
    /extension-state Summarize
    +
  • +
+
+ `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-exists', + aliases: ['extension-installed'], + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; + return exists ? 'true' : 'false'; + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + forceEnum: true, + }), + ], + helpString: ` +
+ Checks if a specified extension exists. +
+
+ Example: +
    +
  • +
    /extension-exists LALib
    +
  • +
+
+ `, + })); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reload-page', + callback: async () => { + toastr.info('Reloading the page...'); + location.reload(); + return ''; + }, + helpString: 'Reloads the current page. All further commands will not be processed.', + })); +} diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 6c72c78e6..8b49c5ec5 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -1,14 +1,8 @@ import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; import { showLoader } from './loader.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; -import { SlashCommand } from './slash-commands/SlashCommand.js'; -import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; -import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; -import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; -import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; -import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { renderTemplate, renderTemplateAsync } from './templates.js'; -import { equalsIgnoreCaseAndAccents, isFalseBoolean, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; +import { isSubsetOf, setValueByPath } from './utils.js'; export { getContext, getApiUrl, @@ -249,7 +243,7 @@ function onEnableExtensionClick() { enableExtension(name, false); } -async function enableExtension(name, reload = true) { +export async function enableExtension(name, reload = true) { extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); stateChanged = true; await saveSettings(); @@ -260,7 +254,7 @@ async function enableExtension(name, reload = true) { } } -async function disableExtension(name, reload = true) { +export async function disableExtension(name, reload = true) { extension_settings.disabledExtensions.push(name); stateChanged = true; await saveSettings(); @@ -1049,277 +1043,9 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { await installExtension(url); } -/** - * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension - * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise} - */ -function getExtensionActionCallback(action) { - return async (args, extensionName) => { - if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - if (!extensionName) { - toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); - return ''; - } - const reload = isTrueBoolean(args?.reload); - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); - if (!internalExtensionName) { - toastr.warning(`Extension ${extensionName} does not exist.`); - return ''; - } - - const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); - - if (action === 'enable' && isEnabled) { - toastr.info(`Extension ${extensionName} is already enabled.`); - return internalExtensionName; - } - - if (action === 'disable' && !isEnabled) { - toastr.info(`Extension ${extensionName} is already disabled.`); - return internalExtensionName; - } - - if (action === 'toggle') { - action = isEnabled ? 'disable' : 'enable'; - } - - reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); - - if (action === 'enable') { - await enableExtension(internalExtensionName, reload); - } else { - await disableExtension(internalExtensionName, reload); - } - - toastr.success(`Extension ${extensionName} ${action}d.`); - - return internalExtensionName; - }; -} - -function registerExtensionSlashCommands() { - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'extension-enable', - callback: getExtensionActionCallback('enable'), - namedArgumentList: [ - SlashCommandNamedArgument.fromProps({ - name: 'reload', - description: 'Whether to reload the page after enabling the extension', - typeList: [ARGUMENT_TYPE.BOOLEAN], - defaultValue: 'true', - enumList: commonEnumProviders.boolean('trueFalse')(), - }), - ], - unnamedArgumentList: [ - SlashCommandArgument.fromProps({ - description: 'Extension name', - typeList: [ARGUMENT_TYPE.STRING], - isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, - }), - ], - helpString: ` -
- Enables a specified extension. -
-
- By default, the page will be reloaded automatically, stopping any further commands.
- If reload=false named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. - The page either needs to be refreshed, or /reload-page has to be called. -
-
- Example: -
    -
  • -
    /extension-enable Summarize
    -
  • -
-
- `, - })); - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'extension-disable', - callback: getExtensionActionCallback('enable'), - namedArgumentList: [ - SlashCommandNamedArgument.fromProps({ - name: 'reload', - description: 'Whether to reload the page after disabling the extension', - typeList: [ARGUMENT_TYPE.BOOLEAN], - defaultValue: 'true', - enumList: commonEnumProviders.boolean('trueFalse')(), - }), - ], - unnamedArgumentList: [ - SlashCommandArgument.fromProps({ - description: 'Extension name', - typeList: [ARGUMENT_TYPE.STRING], - isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, - }), - ], - helpString: ` -
- Disables a specified extension. -
-
- By default, the page will be reloaded automatically, stopping any further commands.
- If reload=false named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. - The page either needs to be refreshed, or /reload-page has to be called. -
-
- Example: -
    -
  • -
    /extension-disable Summarize
    -
  • -
-
- `, - })); - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'extension-toggle', - callback: async (args, extensionName) => { - if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - - const action = isTrueBoolean(args?.state) ? 'enable' : - isFalseBoolean(args?.state) ? 'disable' : - 'toggle'; - - return await getExtensionActionCallback(action)(args, extensionName); - }, - namedArgumentList: [ - SlashCommandNamedArgument.fromProps({ - name: 'reload', - description: 'Whether to reload the page after toggling the extension', - typeList: [ARGUMENT_TYPE.BOOLEAN], - defaultValue: 'true', - enumList: commonEnumProviders.boolean('trueFalse')(), - }), - SlashCommandNamedArgument.fromProps({ - name: 'state', - description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', - typeList: [ARGUMENT_TYPE.BOOLEAN], - enumList: commonEnumProviders.boolean('trueFalse')(), - }), - ], - unnamedArgumentList: [ - SlashCommandArgument.fromProps({ - description: 'Extension name', - typeList: [ARGUMENT_TYPE.STRING], - isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, - }), - ], - helpString: ` -
- Toggles the state of a specified extension. -
-
- By default, the page will be reloaded automatically, stopping any further commands.
- If reload=false named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. - The page either needs to be refreshed, or /reload-page has to be called. -
-
- Example: -
    -
  • -
    /extension-toggle Summarize
    -
  • -
  • -
    /extension-toggle Summarize state=true
    -
  • -
-
- `, - })); - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'extension-state', - callback: async (_, extensionName) => { - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); - if (!internalExtensionName) { - toastr.warning(`Extension ${extensionName} does not exist.`); - return ''; - } - - const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); - return String(isEnabled); - }, - unnamedArgumentList: [ - SlashCommandArgument.fromProps({ - description: 'Extension name', - typeList: [ARGUMENT_TYPE.STRING], - isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, - }), - ], - helpString: ` -
- Returns the state of a specified extension (true if enabled, false if disabled). -
-
- Example: -
    -
  • -
    /extension-state Summarize
    -
  • -
-
- `, - })); - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'extension-exists', - aliases: ['extension-installed'], - callback: async (_, extensionName) => { - if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; - return exists ? 'true' : 'false'; - }, - unnamedArgumentList: [ - SlashCommandArgument.fromProps({ - description: 'Extension name', - typeList: [ARGUMENT_TYPE.STRING], - isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, - }), - ], - helpString: ` -
- Checks if a specified extension exists. -
-
- Example: -
    -
  • -
    /extension-exists LALib
    -
  • -
-
- `, - })); - - SlashCommandParser.addCommandObject(SlashCommand.fromProps({ - name: 'reload-page', - callback: async () => { - toastr.info('Reloading the page...'); - location.reload(); - return ''; - }, - helpString: 'Reloads the current page. All further commands will not be processed.', - })); -} export async function initExtensions() { - registerExtensionSlashCommands(); - await addExtensionsButtonAndMenu(); $('#extensionsMenuButton').css('display', 'flex'); From 9fbcb1221020c9b3bfc81b9853c7ea7c1abab3ea Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 23:33:00 +0200 Subject: [PATCH 6/9] Fix third party extension findings + enum provider - Allow extension names without the "third-party/" prefix - Expand enum provider to show what third-party extensions are --- public/script.js | 4 +- public/scripts/extensions-slashcommands.js | 48 +++++++++++++++++----- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/public/script.js b/public/script.js index 0e675e3e6..7875de32f 100644 --- a/public/script.js +++ b/public/script.js @@ -244,7 +244,7 @@ import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCo import { initInputMarkdown } from './scripts/input-md-formatting.js'; import { AbortReason } from './scripts/util/AbortReason.js'; import { initSystemPrompts } from './scripts/sysprompt.js'; -import { registerExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; +import { registerExtensionSlashCommands as initExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; //exporting functions and vars for mods export { @@ -958,7 +958,7 @@ async function firstLoadInit() { initLogprobs(); initInputMarkdown(); initExtensions(); - registerExtensionSlashCommands(); + initExtensionSlashCommands(); doDailyExtensionUpdatesCheck(); await hideLoader(); await fixViewport(); diff --git a/public/scripts/extensions-slashcommands.js b/public/scripts/extensions-slashcommands.js index 62d2e8374..499b86ecb 100644 --- a/public/scripts/extensions-slashcommands.js +++ b/public/scripts/extensions-slashcommands.js @@ -3,7 +3,7 @@ import { SlashCommand } from './slash-commands/SlashCommand.js'; import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; -import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; +import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean } from './utils.js'; @@ -21,7 +21,7 @@ function getExtensionActionCallback(action) { } const reload = isTrueBoolean(args?.reload); - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + const internalExtensionName = findExtension(extensionName); if (!internalExtensionName) { toastr.warning(`Extension ${extensionName} does not exist.`); return ''; @@ -57,6 +57,33 @@ function getExtensionActionCallback(action) { }; } +/** + * Finds an extension by name, allowing omission of the "third-party/" prefix. + * + * @param {string} name - The name of the extension to find + * @returns {string?} - The matched extension name or undefined if not found + */ +function findExtension(name) { + return extensionNames.find(extName => { + return equalsIgnoreCaseAndAccents(extName, name) || equalsIgnoreCaseAndAccents(extName, `third-party/${name}`); + }); +} + +/** + * Provides an array of SlashCommandEnumValue objects based on the extension names. + * Each object contains the name of the extension and a description indicating if it is a third-party extension. + * + * @returns {SlashCommandEnumValue[]} An array of SlashCommandEnumValue objects + */ +const extensionNamesEnumProvider = () => extensionNames.map(name => { + const isThirdParty = name.startsWith('third-party/'); + if (isThirdParty) name = name.slice('third-party/'.length); + + const description = isThirdParty ? 'third party extension' : null; + + return new SlashCommandEnumValue(name, description, !isThirdParty ? enumTypes.name : enumTypes.enum); +}); + export function registerExtensionSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'extension-enable', @@ -75,7 +102,7 @@ export function registerExtensionSlashCommands() { description: 'Extension name', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + enumProvider: extensionNamesEnumProvider, forceEnum: true, }), ], @@ -115,7 +142,7 @@ export function registerExtensionSlashCommands() { description: 'Extension name', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + enumProvider: extensionNamesEnumProvider, forceEnum: true, }), ], @@ -170,7 +197,7 @@ export function registerExtensionSlashCommands() { description: 'Extension name', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + enumProvider: extensionNamesEnumProvider, forceEnum: true, }), ], @@ -200,7 +227,7 @@ export function registerExtensionSlashCommands() { name: 'extension-state', callback: async (_, extensionName) => { if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); + const internalExtensionName = findExtension(extensionName); if (!internalExtensionName) { toastr.warning(`Extension ${extensionName} does not exist.`); return ''; @@ -214,7 +241,7 @@ export function registerExtensionSlashCommands() { description: 'Extension name', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), + enumProvider: extensionNamesEnumProvider, forceEnum: true, }), ], @@ -237,7 +264,7 @@ export function registerExtensionSlashCommands() { aliases: ['extension-installed'], callback: async (_, extensionName) => { if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); - const exists = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)) !== undefined; + const exists = findExtension(extensionName) !== undefined; return exists ? 'true' : 'false'; }, unnamedArgumentList: [ @@ -245,8 +272,7 @@ export function registerExtensionSlashCommands() { description: 'Extension name', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, - enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), - forceEnum: true, + enumProvider: extensionNamesEnumProvider, }), ], helpString: ` @@ -257,7 +283,7 @@ export function registerExtensionSlashCommands() { Example:
  • -
    /extension-exists LALib
    +
    /extension-exists SillyTavern-LALib
From 15bc0e4dba7ffd8ad250061b765424e838bf3099 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Wed, 25 Sep 2024 23:53:26 +0200 Subject: [PATCH 7/9] Squish the last bugs --- public/scripts/extensions-slashcommands.js | 24 +++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/public/scripts/extensions-slashcommands.js b/public/scripts/extensions-slashcommands.js index 499b86ecb..c8bfa96f3 100644 --- a/public/scripts/extensions-slashcommands.js +++ b/public/scripts/extensions-slashcommands.js @@ -20,7 +20,7 @@ function getExtensionActionCallback(action) { return ''; } - const reload = isTrueBoolean(args?.reload); + const reload = !isFalseBoolean(args?.reload); const internalExtensionName = findExtension(extensionName); if (!internalExtensionName) { toastr.warning(`Extension ${extensionName} does not exist.`); @@ -43,7 +43,14 @@ function getExtensionActionCallback(action) { action = isEnabled ? 'disable' : 'enable'; } - reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); + if (reload) { + toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); + + // Clear input, so it doesn't stay because the command didn't "finish", + // and wait for a bit to both show the toast and let the clear bubble through. + $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); + await new Promise(resolve => setTimeout(resolve, 100)); + } if (action === 'enable') { await enableExtension(internalExtensionName, reload); @@ -53,6 +60,12 @@ function getExtensionActionCallback(action) { toastr.success(`Extension ${extensionName} ${action}d.`); + + console.info(`Extension ${action}ed: ${extensionName}`); + if (!reload) { + console.info('Reload not requested, so page needs to be reloaded manually for changes to take effect.'); + } + return internalExtensionName; }; } @@ -88,6 +101,7 @@ export function registerExtensionSlashCommands() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'extension-enable', callback: getExtensionActionCallback('enable'), + returns: 'The internal extension name', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'reload', @@ -127,7 +141,8 @@ export function registerExtensionSlashCommands() { })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'extension-disable', - callback: getExtensionActionCallback('enable'), + callback: getExtensionActionCallback('disable'), + returns: 'The internal extension name', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'reload', @@ -177,6 +192,7 @@ export function registerExtensionSlashCommands() { return await getExtensionActionCallback(action)(args, extensionName); }, + returns: 'The internal extension name', namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'reload', @@ -236,6 +252,7 @@ export function registerExtensionSlashCommands() { const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); return String(isEnabled); }, + returns: 'true/false - The state of the extension, whether it is enabled.', unnamedArgumentList: [ SlashCommandArgument.fromProps({ description: 'Extension name', @@ -267,6 +284,7 @@ export function registerExtensionSlashCommands() { const exists = findExtension(extensionName) !== undefined; return exists ? 'true' : 'false'; }, + returns: 'true/false - Whether the extension exists and is installed.', unnamedArgumentList: [ SlashCommandArgument.fromProps({ description: 'Extension name', From cf2c9a8296e6aa0ff40fc943398016d879708937 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 27 Sep 2024 01:13:44 +0300 Subject: [PATCH 8/9] Returns doesn't support HTML --- public/scripts/extensions-slashcommands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions-slashcommands.js b/public/scripts/extensions-slashcommands.js index c8bfa96f3..2853375b2 100644 --- a/public/scripts/extensions-slashcommands.js +++ b/public/scripts/extensions-slashcommands.js @@ -284,7 +284,7 @@ export function registerExtensionSlashCommands() { const exists = findExtension(extensionName) !== undefined; return exists ? 'true' : 'false'; }, - returns: 'true/false - Whether the extension exists and is installed.', + returns: 'Whether the extension exists and is installed.', unnamedArgumentList: [ SlashCommandArgument.fromProps({ description: 'Extension name', From 0fd57a4c1c5c33fa240a55b66c049a8849997584 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 27 Sep 2024 01:19:45 +0300 Subject: [PATCH 9/9] Returns doesn't support HTML, ditto --- public/scripts/extensions-slashcommands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions-slashcommands.js b/public/scripts/extensions-slashcommands.js index 2853375b2..f86919823 100644 --- a/public/scripts/extensions-slashcommands.js +++ b/public/scripts/extensions-slashcommands.js @@ -252,7 +252,7 @@ export function registerExtensionSlashCommands() { const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); return String(isEnabled); }, - returns: 'true/false - The state of the extension, whether it is enabled.', + returns: 'The state of the extension, whether it is enabled.', unnamedArgumentList: [ SlashCommandArgument.fromProps({ description: 'Extension name',