diff --git a/packages/extension/src/background_script.ts b/packages/extension/src/background_script.ts index 01170493..ea41b3df 100644 --- a/packages/extension/src/background_script.ts +++ b/packages/extension/src/background_script.ts @@ -21,6 +21,7 @@ import { PopupAutoClose } from "@/services/popupAutoClose" import { isSearchCommand, isPageActionCommand, + isAiPromptCommand, findMatchingPageRule, } from "@/lib/utils" import { execute } from "@/action/background" @@ -161,6 +162,7 @@ const commandFuncs = { const params = JSON.parse(param.command) const isSearch = isSearchCommand(params) const isPageAction = isPageActionCommand(params) + const isAiPrompt = isAiPromptCommand(params) const sourceType = (params as { sourceType?: unknown }).sourceType const sourceId = (params as { sourceId?: unknown }).sourceId const normalizedSourceType = Object.values(COMMAND_SOURCE_TYPE).includes( @@ -185,17 +187,27 @@ const commandFuncs = { spaceEncoding: params.spaceEncoding, popupOption: PopupOption, } - : isPageAction + : isAiPrompt ? { id: params.id, title: params.title, iconUrl: params.iconUrl, ...sourceInfo, openMode: params.openMode, - pageActionOption: params.pageActionOption, + aiPromptOption: params.aiPromptOption, popupOption: PopupOption, } - : null + : isPageAction + ? { + id: params.id, + title: params.title, + iconUrl: params.iconUrl, + ...sourceInfo, + openMode: params.openMode, + pageActionOption: params.pageActionOption, + popupOption: PopupOption, + } + : null if (!cmd) { console.error("invalid command", param.command) diff --git a/packages/extension/src/components/commandHub/DownloadButton.tsx b/packages/extension/src/components/commandHub/DownloadButton.tsx index 41171685..f9561ac2 100644 --- a/packages/extension/src/components/commandHub/DownloadButton.tsx +++ b/packages/extension/src/components/commandHub/DownloadButton.tsx @@ -121,6 +121,71 @@ export const DownloadButton = (): JSX.Element => { return () => clearTimeout(timer) }, [open]) + /** + * External postMessage API for adding/deleting commands from the Hub. + * + * This content script listens for messages from the Hub page (origin must match HUB_URL). + * The message object must have the following shape: + * + * --- AddCommand --- + * { + * action: "AddCommand", + * command: string // JSON-stringified command object (see below) + * } + * + * The `command` field is a JSON string representing a SearchCommand, an AiPromptCommand, or a PageActionCommand. + * + * SearchCommand (openMode is one of "popup" | "tab" | "window" | "backgroundTab" | "sidePanel"): + * { + * id: string, // Unique command identifier + * title: string, // Display name of the command + * searchUrl: string, // Search URL template (%s is replaced with selected text) + * iconUrl: string, // URL of the command icon + * openMode: string, // How to open the result: "popup" | "tab" | "window" | "backgroundTab" | "sidePanel" + * openModeSecondary?: string, // Secondary open mode (optional) + * spaceEncoding?: string, // Space encoding in URL: "plus" | "percent" (optional) + * sourceType?: string, // Origin of the command: "default" | "selfCreated" | "hubCommunity" | "unknown" (optional) + * sourceId?: string // Identifier of the source (optional) + * } + * + * AiPromptCommand (openMode is "aiPrompt"): + * { + * id: string, // Unique command identifier + * title: string, // Display name of the command + * iconUrl: string, // URL of the command icon + * openMode: "aiPrompt", // Must be "aiPrompt" for AI prompt commands + * aiPromptOption: { + * serviceId: string, // ID of the AI service to use (see hub/public/data/ai-services.json) + * prompt: string, // Prompt text sent to the AI service (supports variable placeholders) + * openMode: string // How to open the AI service result: "popup" | "tab" | "window" | etc. + * }, + * sourceType?: string, // Origin of the command: "default" | "selfCreated" | "hubCommunity" | "unknown" (optional) + * sourceId?: string // Identifier of the source (optional) + * } + * + * PageActionCommand (openMode is "pageAction"): + * { + * id: string, // Unique command identifier + * title: string, // Display name of the command + * iconUrl: string, // URL of the command icon + * openMode: "pageAction", // Must be "pageAction" for page action commands + * pageActionOption: { + * startUrl: string, // URL to open when executing the page action + * pageUrl?: string, // URL pattern for command enablement (currentTab mode only, optional) + * openMode: string, // How to open the page: "none" | "popup" | "tab" | "backgroundTab" | "window" | "currentTab" + * steps: Array, // Sequence of automation steps to execute + * userVariables?: Array<{ name: string, value: string }> // User-defined variables (optional) + * }, + * sourceType?: string, // Origin of the command: "default" | "selfCreated" | "hubCommunity" | "unknown" (optional) + * sourceId?: string // Identifier of the source (optional) + * } + * + * --- DeleteCommand --- + * { + * action: "DeleteCommand", + * id: string // ID of the command to remove + * } + */ useEffect(() => { const hubOrigin = new URL(HUB_URL).origin const handleMessage = (event: MessageEvent) => {