Wox/docs/full_featured_plugin_guide.md

8.8 KiB

Full-featured Plugin Development Guide (Generated by AI)

Full-featured plugins are comprehensive plugins that run in dedicated host processes and communicate with Wox via WebSocket. They provide the full power of the Wox plugin system with rich APIs, persistent state, and advanced features.

Overview

Full-featured plugins are designed for complex applications that require:

  • Persistent state management
  • High-performance query processing
  • Advanced Wox API integration (AI, settings, previews)
  • Complex async operations
  • Professional-grade plugin development

Supported Languages

Python Plugins

Requirements:

  • Python >= 3.8 (Python 3.12 recommended)
  • wox-plugin SDK

Installation:

# Using pip
pip install wox-plugin

# Using uv (recommended)
uv add wox-plugin

Basic Structure:

from wox_plugin import Plugin, Query, Result, Context, PluginInitParams

class MyPlugin(Plugin):
    async def init(self, ctx: Context, params: PluginInitParams) -> None:
        self.api = params.api
        self.plugin_dir = params.plugin_directory
        
    async def query(self, ctx: Context, query: Query) -> list[Result]:
        # Your plugin logic here
        results = []
        results.append(
            Result(
                title="Hello Wox",
                subtitle="This is a sample result",
                icon="path/to/icon.png",
                score=100
            )
        )
        return results

# MUST HAVE! The plugin class will be automatically loaded by Wox
plugin = MyPlugin()

Node.js Plugins

Requirements:

  • Node.js >= 16
  • @wox-launcher/wox-plugin SDK

Installation:

npm install @wox-launcher/wox-plugin
# or
pnpm add @wox-launcher/wox-plugin

Basic Structure:

import { Plugin, Query, Result, Context, PluginInitParams } from '@wox-launcher/wox-plugin'

class MyPlugin implements Plugin {
  private api: any
  private pluginDir: string

  async init(ctx: Context, params: PluginInitParams): Promise<void> {
    this.api = params.API
    this.pluginDir = params.PluginDirectory
  }

  async query(ctx: Context, query: Query): Promise<Result[]> {
    // Your plugin logic here
    return [
      {
        Title: "Hello Wox",
        SubTitle: "This is a sample result",
        Icon: "path/to/icon.png",
        Score: 100
      }
    ]
  }
}

// MUST HAVE! Export the plugin instance
export const plugin = new MyPlugin()

Plugin Architecture

Plugin Host System

Full-featured plugins run in dedicated host processes:

  • Python Host: wox.plugin.host.python manages Python plugins
  • Node.js Host: wox.plugin.host.nodejs manages Node.js plugins

Communication Flow

  1. Wox CorePlugin Host (WebSocket)
  2. Plugin HostPlugin Instance (Direct method calls)

Plugin Lifecycle

  1. Load: Plugin host loads the plugin module
  2. Init: Plugin initialization with API access
  3. Query: Handle user queries (multiple times)
  4. Unload: Plugin cleanup when disabled/uninstalled

Rich API Features

Core APIs

# Change query
await self.api.change_query(ctx, ChangeQueryParam(query="new query"))

# Show/hide app
await self.api.show_app(ctx)
await self.api.hide_app(ctx)

# Notifications
await self.api.notify(ctx, "Hello from plugin!")

# Logging
await self.api.log(ctx, "info", "Plugin message")

# Settings
value = await self.api.get_setting(ctx, "setting_key")

# Translations
text = await self.api.get_translation(ctx, "i18n_key")

AI Integration

# Chat with AI
conversation = [
    ai_message("You are a helpful assistant"),
    user_message("What is 2+2?")
]

async def stream_callback(data):
    # Handle streaming response
    print(data.content)

response = await self.api.ai_chat(ctx, conversation, stream_callback)

Advanced Result Features

# Result with preview
Result(
    title="Document",
    subtitle="Click to preview",
    preview=WoxPreview(
        preview_type=WoxPreviewType.TEXT,
        preview_data="Document content here..."
    )
)

# Refreshable result
Result(
    title="Live Data",
    subtitle="Updates automatically",
    on_refresh=self.refresh_data
)

# Result with custom actions
Result(
    title="File",
    subtitle="Multiple actions available",
    actions=[
        ResultAction(name="Open", action=self.open_file),
        ResultAction(name="Delete", action=self.delete_file)
    ]
)

Plugin Configuration

plugin.json

{
  "Id": "my-awesome-plugin",
  "Name": "My Awesome Plugin",
  "Author": "Your Name",
  "Version": "1.0.0",
  "MinWoxVersion": "2.0.0",
  "Runtime": "Python",
  "Entry": "main.py",
  "TriggerKeywords": ["awesome", "ap"],
  "Commands": [
    {
      "Command": "config",
      "Description": "Configure plugin settings"
    }
  ],
  "Settings": [
    {
      "Type": "textbox",
      "Key": "api_key",
      "Title": "API Key",
      "Description": "Enter your API key"
    }
  ]
}

Settings Definition

from wox_plugin import PluginSettingDefinitionItem

settings = [
    PluginSettingDefinitionItem(
        type="textbox",
        key="api_key",
        title="API Key",
        description="Enter your API key",
        value=""
    ),
    PluginSettingDefinitionItem(
        type="checkbox",
        key="enable_cache",
        title="Enable Cache",
        description="Cache results for better performance",
        value="true"
    )
]

Performance Optimization

Async Operations

import asyncio
import aiohttp

async def query(self, ctx: Context, query: Query) -> list[Result]:
    # Concurrent API calls
    async with aiohttp.ClientSession() as session:
        tasks = [
            self.fetch_data(session, url1),
            self.fetch_data(session, url2),
            self.fetch_data(session, url3)
        ]
        results = await asyncio.gather(*tasks)
    
    return self.process_results(results)

Caching

from functools import lru_cache
import time

class MyPlugin(Plugin):
    def __init__(self):
        self.cache = {}
        self.cache_ttl = 300  # 5 minutes
    
    async def query(self, ctx: Context, query: Query) -> list[Result]:
        cache_key = f"query:{query.search}"
        
        # Check cache
        if cache_key in self.cache:
            data, timestamp = self.cache[cache_key]
            if time.time() - timestamp < self.cache_ttl:
                return data
        
        # Fetch new data
        results = await self.fetch_results(query.search)
        
        # Update cache
        self.cache[cache_key] = (results, time.time())
        
        return results

Error Handling

from wox_plugin import WoxPluginError, APIError

async def query(self, ctx: Context, query: Query) -> list[Result]:
    try:
        # Your plugin logic
        return await self.process_query(query)
    except APIError as e:
        await self.api.log(ctx, "error", f"API error: {e}")
        return [Result(
            title="API Error",
            subtitle="Please check your settings",
            score=0
        )]
    except Exception as e:
        await self.api.log(ctx, "error", f"Unexpected error: {e}")
        return []

Testing

Unit Testing

import pytest
from unittest.mock import AsyncMock
from your_plugin import MyPlugin

@pytest.mark.asyncio
async def test_query():
    plugin = MyPlugin()
    
    # Mock API
    mock_api = AsyncMock()
    await plugin.init(mock_context, PluginInitParams(
        api=mock_api,
        plugin_directory="/test"
    ))
    
    # Test query
    results = await plugin.query(mock_context, Query(search="test"))
    
    assert len(results) > 0
    assert results[0].title == "Expected Title"

Best Practices

  1. Use Async/Await: Leverage async operations for better performance
  2. Handle Errors Gracefully: Always catch and log exceptions
  3. Implement Caching: Cache expensive operations when appropriate
  4. Provide Good UX: Use meaningful titles, subtitles, and icons
  5. Follow Naming Conventions: Use clear, descriptive names
  6. Document Your Code: Add docstrings and comments
  7. Test Thoroughly: Write unit tests for your plugin logic

Migration from Script Plugin

If you have a script plugin that needs more features:

  1. Create Plugin Structure: Set up proper plugin directory with plugin.json
  2. Install SDK: Add the appropriate SDK dependency
  3. Convert Logic: Move your script logic to the plugin class
  4. Add State Management: Utilize persistent state if needed
  5. Enhance with APIs: Add AI, settings, or other advanced features
  6. Optimize Performance: Implement caching and async operations

Publishing

  1. Test Locally: Ensure your plugin works correctly
  2. Create Package: Follow the plugin packaging guidelines
  3. Submit to Store: Use the plugin submission process
  4. Maintain: Keep your plugin updated and respond to user feedback