Refactor plugin host

This commit is contained in:
qianlifeng 2024-12-22 22:24:04 +08:00
parent 6feb7cfb15
commit ccfdbc5e4a
No known key found for this signature in database
52 changed files with 1411 additions and 1230 deletions

18
.cursorrules Normal file
View File

@ -0,0 +1,18 @@
项目基本结构如下:
wox.core Go实现的Wox后端,通过websocket与http与wox.ui.flutter通信
wox.core/setting wox.core的设置相关定义
wox.core/plugin wox.core的API定义与实现
wox.plugin.python python插件需要引用的类库
wox.plugin.host.python python插件的host,通过websocket与wox.core通信,负责加载python插件
wox.plugin.nodejs nodejs插件需要引用的类库
wox.plugin.host.nodejs nodejs插件的host,通过websocket与wox.core通信,负责加载nodejs插件
wox.ui.flutter flutter实现的Wox前端,通过websocket与wox.core通信
所有的插件类库(wox.plugin.python,wox.plugin.nodejs)的定义都必须对齐wox.core的定义, 例如:
wox.core/plugin/api.go 定义了API接口, 所有的插件类库都必须定义这些接口, 且名称,类型,参数,返回值必须完全一致
本项目中所有的python项目都使用如下类库:
* orjson进行数据序列化, 请参考wox.plugin.python/src/wox_plugin/models/query.py
* dataclass进行数据模型定义, 请参考wox.plugin.python/src/wox_plugin/models/query.py

4
.gitignore vendored
View File

@ -15,4 +15,6 @@ __debug_bin*
wox.core/log/ wox.core/log/
wox.plugin.python/dist/ wox.plugin.python/dist/
wox.plugin.python/wox_plugin.egg-info/ wox.plugin.python/wox_plugin.egg-info/
.venv/ .venv/
.ruff_cache/
.mypy_cache/

4
.vscode/launch.json vendored
View File

@ -9,14 +9,14 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}/Wox", "program": "${workspaceFolder}/wox.core",
"env": { "env": {
"CGO_ENABLED": "1" "CGO_ENABLED": "1"
} }
}, },
{ {
"name": "Run Flutter", "name": "Run Flutter",
"cwd": "Wox.UI.Flutter/wox", "cwd": "${workspaceFolder}/wox.ui.flutter/wox",
"request": "launch", "request": "launch",
"type": "dart", "type": "dart",
// "flutterMode": "release" // "flutterMode": "release"

34
.vscode/settings.json vendored
View File

@ -1,26 +1,4 @@
{ {
"dart.lineLength": 200,
"python.languageServer": "Pylance",
"python.analysis.typeCheckingMode": "strict",
"python.analysis.diagnosticMode": "workspace",
"python.analysis.inlayHints.functionReturnTypes": true,
"python.analysis.inlayHints.variableTypes": true,
"python.analysis.autoFormatStrings": true,
"python.analysis.autoImportCompletions": true,
"python.analysis.diagnosticSeverityOverrides": {
"reportUnknownMemberType": "error",
"reportUnknownVariableType": "error",
"reportUnknownArgumentType": "error",
"reportUnknownParameterType": "error",
"reportMissingTypeStubs": "error",
"reportUnknownLambdaType": "error",
"reportOptionalCall": "error",
"reportOptionalMemberAccess": "error",
"reportOptionalSubscript": "error",
"reportOptionalIterable": "error",
"reportOptionalContextManager": "error",
"reportOptionalOperand": "error"
},
"files.exclude": { "files.exclude": {
"wox.plugin.host.nodejs": true, "wox.plugin.host.nodejs": true,
"wox.plugin.host.python": true, "wox.plugin.host.python": true,
@ -28,5 +6,13 @@
"wox.plugin.python": true, "wox.plugin.python": true,
"wox.ui.flutter": true, "wox.ui.flutter": true,
"wox.core": true "wox.core": true
} },
} "[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.defaultFormatter": "charliermarsh.ruff"
},
}

View File

@ -30,7 +30,8 @@
} }
], ],
"settings": { "settings": {
"python.languageServer": "Pylance" "python.languageServer": "Default",
"makefile.configureOnOpen": false
}, },
"extensions": { "extensions": {
"recommendations": [ "recommendations": [
@ -38,8 +39,8 @@
"golang.go", "golang.go",
// for python // for python
"ms-python.python", "ms-python.python",
"ms-python.vscode-pylance", "charliermarsh.ruff",
"ms-python.black-formatter", "ms-python.mypy-type-checker",
// for flutter // for flutter
"dart-code.flutter", "dart-code.flutter",
// for js // for js

View File

@ -101,7 +101,6 @@ func (m *Manager) TranslatePlugin(ctx context.Context, key string, pluginDirecto
jsonPath := path.Join(pluginDirectory, "lang", fmt.Sprintf("%s.json", m.currentLangCode)) jsonPath := path.Join(pluginDirectory, "lang", fmt.Sprintf("%s.json", m.currentLangCode))
if _, err := os.Stat(jsonPath); os.IsNotExist(err) { if _, err := os.Stat(jsonPath); os.IsNotExist(err) {
util.GetLogger().Error(ctx, fmt.Sprintf("lang file not found: %s", jsonPath))
return key return key
} }

View File

@ -9,7 +9,6 @@ import (
"wox/ai" "wox/ai"
"wox/i18n" "wox/i18n"
"wox/setting" "wox/setting"
"wox/setting/definition"
"wox/share" "wox/share"
"wox/util" "wox/util"
@ -36,7 +35,7 @@ type API interface {
GetSetting(ctx context.Context, key string) string GetSetting(ctx context.Context, key string) string
SaveSetting(ctx context.Context, key string, value string, isPlatformSpecific bool) SaveSetting(ctx context.Context, key string, value string, isPlatformSpecific bool)
OnSettingChanged(ctx context.Context, callback func(key string, value string)) OnSettingChanged(ctx context.Context, callback func(key string, value string))
OnGetDynamicSetting(ctx context.Context, callback func(key string) definition.PluginSettingDefinitionItem) OnGetDynamicSetting(ctx context.Context, callback func(key string) string)
OnDeepLink(ctx context.Context, callback func(arguments map[string]string)) OnDeepLink(ctx context.Context, callback func(arguments map[string]string))
OnUnload(ctx context.Context, callback func()) OnUnload(ctx context.Context, callback func())
RegisterQueryCommands(ctx context.Context, commands []MetadataCommand) RegisterQueryCommands(ctx context.Context, commands []MetadataCommand)
@ -148,7 +147,7 @@ func (a *APIImpl) OnSettingChanged(ctx context.Context, callback func(key string
a.pluginInstance.SettingChangeCallbacks = append(a.pluginInstance.SettingChangeCallbacks, callback) a.pluginInstance.SettingChangeCallbacks = append(a.pluginInstance.SettingChangeCallbacks, callback)
} }
func (a *APIImpl) OnGetDynamicSetting(ctx context.Context, callback func(key string) definition.PluginSettingDefinitionItem) { func (a *APIImpl) OnGetDynamicSetting(ctx context.Context, callback func(key string) string) {
a.pluginInstance.DynamicSettingCallbacks = append(a.pluginInstance.DynamicSettingCallbacks, callback) a.pluginInstance.DynamicSettingCallbacks = append(a.pluginInstance.DynamicSettingCallbacks, callback)
} }

View File

@ -3,12 +3,13 @@ package host
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/Masterminds/semver/v3"
"github.com/mitchellh/go-homedir"
"path" "path"
"strings" "strings"
"wox/plugin" "wox/plugin"
"wox/util" "wox/util"
"github.com/Masterminds/semver/v3"
"github.com/mitchellh/go-homedir"
) )
func init() { func init() {
@ -29,7 +30,7 @@ func (n *NodejsHost) GetRuntime(ctx context.Context) plugin.Runtime {
} }
func (n *NodejsHost) Start(ctx context.Context) error { func (n *NodejsHost) Start(ctx context.Context) error {
return n.websocketHost.StartHost(ctx, n.findNodejsPath(ctx), path.Join(util.GetLocation().GetHostDirectory(), "node-host.js")) return n.websocketHost.StartHost(ctx, n.findNodejsPath(ctx), path.Join(util.GetLocation().GetHostDirectory(), "node-host.js"), nil)
} }
func (n *NodejsHost) findNodejsPath(ctx context.Context) string { func (n *NodejsHost) findNodejsPath(ctx context.Context) string {

View File

@ -30,7 +30,7 @@ func (n *PythonHost) GetRuntime(ctx context.Context) plugin.Runtime {
} }
func (n *PythonHost) Start(ctx context.Context) error { func (n *PythonHost) Start(ctx context.Context) error {
return n.websocketHost.StartHost(ctx, n.findPythonPath(ctx), path.Join(util.GetLocation().GetHostDirectory(), "python-host.pyz")) return n.websocketHost.StartHost(ctx, n.findPythonPath(ctx), path.Join(util.GetLocation().GetHostDirectory(), "python-host.pyz"), []string{"SHIV_ROOT=" + util.GetLocation().GetCacheDirectory()})
} }
func (n *PythonHost) findPythonPath(ctx context.Context) string { func (n *PythonHost) findPythonPath(ctx context.Context) string {

View File

@ -28,7 +28,7 @@ func (w *WebsocketHost) getHostName(ctx context.Context) string {
return fmt.Sprintf("%s Host Impl", w.host.GetRuntime(ctx)) return fmt.Sprintf("%s Host Impl", w.host.GetRuntime(ctx))
} }
func (w *WebsocketHost) StartHost(ctx context.Context, executablePath string, entry string, executableArgs ...string) error { func (w *WebsocketHost) StartHost(ctx context.Context, executablePath string, entry string, envs []string, executableArgs ...string) error {
port, portErr := util.GetAvailableTcpPort(ctx) port, portErr := util.GetAvailableTcpPort(ctx)
if portErr != nil { if portErr != nil {
return fmt.Errorf("failed to get available port: %w", portErr) return fmt.Errorf("failed to get available port: %w", portErr)
@ -44,7 +44,7 @@ func (w *WebsocketHost) StartHost(ctx context.Context, executablePath string, en
args = append(args, executableArgs...) args = append(args, executableArgs...)
args = append(args, entry, fmt.Sprintf("%d", port), util.GetLocation().GetLogHostsDirectory(), fmt.Sprintf("%d", os.Getpid())) args = append(args, entry, fmt.Sprintf("%d", port), util.GetLocation().GetLogHostsDirectory(), fmt.Sprintf("%d", os.Getpid()))
cmd, err := util.ShellRun(executablePath, args...) cmd, err := util.ShellRunWithEnv(executablePath, envs, args...)
if err != nil { if err != nil {
return fmt.Errorf("failed to start host: %w", err) return fmt.Errorf("failed to start host: %w", err)
} }
@ -98,7 +98,7 @@ func (w *WebsocketHost) UnloadPlugin(ctx context.Context, metadata plugin.Metada
} }
func (w *WebsocketHost) invokeMethod(ctx context.Context, metadata plugin.Metadata, method string, params map[string]string) (result any, err error) { func (w *WebsocketHost) invokeMethod(ctx context.Context, metadata plugin.Metadata, method string, params map[string]string) (result any, err error) {
if !w.ws.IsConnected() { if w.ws == nil || !w.ws.IsConnected() {
return "", fmt.Errorf("host is not connected") return "", fmt.Errorf("host is not connected")
} }
@ -342,34 +342,45 @@ func (w *WebsocketHost) handleRequestFromPlugin(ctx context.Context, request Jso
} }
metadata := pluginInstance.Metadata metadata := pluginInstance.Metadata
pluginInstance.API.OnGetDynamicSetting(ctx, func(key string) definition.PluginSettingDefinitionItem { pluginInstance.API.OnGetDynamicSetting(ctx, func(key string) string {
result, err := w.invokeMethod(ctx, metadata, "onGetDynamicSetting", map[string]string{ result, err := w.invokeMethod(ctx, metadata, "onGetDynamicSetting", map[string]string{
"CallbackId": callbackId, "CallbackId": callbackId,
"Key": key, "Key": key,
}) })
if err != nil { if err != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to get dynamic setting: %s", request.PluginName, err)) util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to get dynamic setting: %s", request.PluginName, err))
return definition.PluginSettingDefinitionItem{ settingJson, marshalErr := json.Marshal(definition.PluginSettingDefinitionItem{
Type: definition.PluginSettingDefinitionTypeLabel, Type: definition.PluginSettingDefinitionTypeLabel,
Value: &definition.PluginSettingValueLabel{ Value: &definition.PluginSettingValueLabel{
Content: fmt.Sprintf("failed to get dynamic setting: %s", err), Content: fmt.Sprintf("failed to get dynamic setting: %s", err),
}, },
})
if marshalErr != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to marshal dynamic setting: %s", request.PluginName, marshalErr))
return ""
} }
return string(settingJson)
} }
// validate the result is a valid definition.PluginSettingDefinitionItem json string
var setting definition.PluginSettingDefinitionItem var setting definition.PluginSettingDefinitionItem
unmarshalErr := json.Unmarshal([]byte(result.(string)), &setting) unmarshalErr := json.Unmarshal([]byte(result.(string)), &setting)
if unmarshalErr != nil { if unmarshalErr != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to unmarshal dynamic setting: %s", request.PluginName, unmarshalErr)) util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to unmarshal dynamic setting: %s", request.PluginName, unmarshalErr))
return definition.PluginSettingDefinitionItem{ settingJson, marshalErr := json.Marshal(definition.PluginSettingDefinitionItem{
Type: definition.PluginSettingDefinitionTypeLabel, Type: definition.PluginSettingDefinitionTypeLabel,
Value: &definition.PluginSettingValueLabel{ Value: &definition.PluginSettingValueLabel{
Content: fmt.Sprintf("failed to unmarshal dynamic setting: %s", unmarshalErr), Content: fmt.Sprintf("failed to unmarshal dynamic setting: %s", unmarshalErr),
}, },
})
if marshalErr != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("[%s] failed to marshal dynamic setting: %s", request.PluginName, marshalErr))
return ""
} }
return string(settingJson)
} }
return setting return result.(string)
}) })
w.sendResponseToHost(ctx, request, "") w.sendResponseToHost(ctx, request, "")
case "OnDeepLink": case "OnDeepLink":

View File

@ -3,7 +3,6 @@ package plugin
import ( import (
"context" "context"
"wox/setting" "wox/setting"
"wox/setting/definition"
) )
type Instance struct { type Instance struct {
@ -17,7 +16,7 @@ type Instance struct {
Host Host // plugin host to run this plugin Host Host // plugin host to run this plugin
Setting *setting.PluginSetting // setting for this plugin Setting *setting.PluginSetting // setting for this plugin
DynamicSettingCallbacks []func(key string) definition.PluginSettingDefinitionItem // dynamic setting callbacks DynamicSettingCallbacks []func(key string) string // dynamic setting callbacks
SettingChangeCallbacks []func(key string, value string) SettingChangeCallbacks []func(key string, value string)
DeepLinkCallbacks []func(arguments map[string]string) DeepLinkCallbacks []func(arguments map[string]string)
UnloadCallbacks []func() UnloadCallbacks []func()

View File

@ -589,7 +589,7 @@ func (m *Manager) PolishResult(ctx context.Context, pluginInstance *Instance, qu
// store preview for ui invoke later // store preview for ui invoke later
// because preview may contain some heavy data (E.g. image or large text), we will store preview in cache and only send preview to ui when user select the result // because preview may contain some heavy data (E.g. image or large text), we will store preview in cache and only send preview to ui when user select the result
if result.Preview.PreviewType != "" && result.Preview.PreviewType != WoxPreviewTypeRemote { if result.Preview.PreviewType != "" && result.Preview.PreviewData != "" && result.Preview.PreviewType != WoxPreviewTypeRemote {
resultCache.Preview = result.Preview resultCache.Preview = result.Preview
result.Preview = WoxPreview{ result.Preview = WoxPreview{
PreviewType: WoxPreviewTypeRemote, PreviewType: WoxPreviewTypeRemote,

View File

@ -5,7 +5,6 @@ import (
"testing" "testing"
"wox/ai" "wox/ai"
"wox/plugin" "wox/plugin"
"wox/setting/definition"
"wox/share" "wox/share"
"wox/util" "wox/util"
@ -15,7 +14,7 @@ import (
type emptyAPIImpl struct { type emptyAPIImpl struct {
} }
func (e emptyAPIImpl) OnGetDynamicSetting(ctx context.Context, callback func(key string) definition.PluginSettingDefinitionItem) { func (e emptyAPIImpl) OnGetDynamicSetting(ctx context.Context, callback func(key string) string) {
} }
func (e emptyAPIImpl) ChangeQuery(ctx context.Context, query share.PlainQuery) { func (e emptyAPIImpl) ChangeQuery(ctx context.Context, query share.PlainQuery) {

View File

@ -4,8 +4,9 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/tidwall/gjson"
"wox/util" "wox/util"
"github.com/tidwall/gjson"
) )
type PluginSettingDefinitionType string type PluginSettingDefinitionType string

View File

@ -189,7 +189,13 @@ func convertPluginDto(ctx context.Context, pluginDto dto.PluginDto, pluginInstan
if settingDefinition.Type == definition.PluginSettingDefinitionTypeDynamic { if settingDefinition.Type == definition.PluginSettingDefinitionTypeDynamic {
replaced := false replaced := false
for _, callback := range pluginInstance.DynamicSettingCallbacks { for _, callback := range pluginInstance.DynamicSettingCallbacks {
newSettingDefinition := callback(settingDefinition.Value.GetKey()) newSettingDefinitionJson := callback(settingDefinition.Value.GetKey())
var newSettingDefinition definition.PluginSettingDefinitionItem
unmarshalErr := json.Unmarshal([]byte(newSettingDefinitionJson), &newSettingDefinition)
if unmarshalErr != nil {
logger.Error(ctx, fmt.Sprintf("failed to unmarshal dynamic setting: %s", unmarshalErr.Error()))
continue
}
if newSettingDefinition.Value != nil && newSettingDefinition.Type != definition.PluginSettingDefinitionTypeDynamic { if newSettingDefinition.Value != nil && newSettingDefinition.Type != definition.PluginSettingDefinitionTypeDynamic {
logger.Debug(ctx, fmt.Sprintf("dynamic setting replaced: %s(%s) -> %s(%s)", settingDefinition.Value.GetKey(), settingDefinition.Type, newSettingDefinition.Value.GetKey(), newSettingDefinition.Type)) logger.Debug(ctx, fmt.Sprintf("dynamic setting replaced: %s(%s) -> %s(%s)", settingDefinition.Value.GetKey(), settingDefinition.Type, newSettingDefinition.Value.GetKey(), newSettingDefinition.Type))
pluginDto.SettingDefinitions[i] = newSettingDefinition pluginDto.SettingDefinitions[i] = newSettingDefinition

View File

@ -2,11 +2,12 @@ package util
import ( import (
"fmt" "fmt"
"github.com/mitchellh/go-homedir"
"os" "os"
"path" "path"
"strings" "strings"
"sync" "sync"
"github.com/mitchellh/go-homedir"
) )
var locationInstance *Location var locationInstance *Location

View File

@ -2,6 +2,7 @@ package util
import ( import (
"fmt" "fmt"
"os"
"os/exec" "os/exec"
) )
@ -21,6 +22,23 @@ func ShellRun(name string, arg ...string) (*exec.Cmd, error) {
return cmd, nil return cmd, nil
} }
func ShellRunWithEnv(name string, envs []string, arg ...string) (*exec.Cmd, error) {
if len(envs) == 0 {
return ShellRun(name, arg...)
}
cmd := exec.Command(name, arg...)
cmd.Stdout = GetLogger().GetWriter()
cmd.Stderr = GetLogger().GetWriter()
cmd.Env = append(os.Environ(), envs...)
cmdErr := cmd.Start()
if cmdErr != nil {
return nil, cmdErr
}
return cmd, nil
}
func ShellRunOutput(name string, arg ...string) ([]byte, error) { func ShellRunOutput(name string, arg ...string) ([]byte, error) {
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()

View File

@ -3,9 +3,10 @@ package util
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/gorilla/websocket"
"sync" "sync"
"time" "time"
"github.com/gorilla/websocket"
) )
type WebsocketClient struct { type WebsocketClient struct {

View File

@ -1 +1 @@
3.10 3.10

View File

@ -7,22 +7,22 @@ help:
@echo " make clean - Remove build artifacts and cache files" @echo " make clean - Remove build artifacts and cache files"
@echo " make build - Build Python host" @echo " make build - Build Python host"
@echo " make install - Install development dependencies" @echo " make install - Install development dependencies"
@echo " make lint - Run linting"
@echo " make format - Run formatting"
clean: clean:
rm -rf python-host.pyz .venv/ __pycache__/ *.pyc python-host/ rm -rf python-host.pyz python-host/
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type f -name "*.pyc" -delete
install: install:
uv cache clean uv cache clean
uv sync --all-extras uv sync --all-extras
build: install clean lint:
uv pip freeze > requirements.txt uv run ruff check src
uv pip install -r requirements.txt --target python-host uv run mypy src
rm requirements.txt
cp -r src/wox_plugin_host/*.py python-host/ format:
uv run python -m zipapp -p "interpreter" python-host uv run ruff format src
rm -rf python-host
mkdir -p $(HOSTS_DIR) build: clean install lint format
mv python-host.pyz $(HOSTS_DIR)/python-host.pyz uv run shiv --compressed -c run -o $(HOSTS_DIR)/python-host.pyz .

View File

@ -4,17 +4,19 @@ version = "0.0.1"
description = "Python host for Wox plugins" description = "Python host for Wox plugins"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
license = "MIT" license = "GPL-3.0"
authors = [{ name = "Wox Team", email = "qianlifeng@gmail.com" }] authors = [{ name = "Wox Team", email = "qianlifeng@gmail.com" }]
dependencies = ["loguru", "websockets", "wox-plugin==0.0.30"] dependencies = ["loguru", "websockets", "wox-plugin==0.0.45"]
[project.scripts]
run = "wox_plugin_host.__main__:run"
[project.optional-dependencies] [project.optional-dependencies]
dev = ["black"] dev = ["shiv", "ruff", "mypy"]
[build-system] [build-system]
requires = ["hatchling"] requires = ["hatchling"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[tool.black] [tool.ruff]
line-length = 100 line-length = 140
target-version = ["py310"]

View File

@ -0,0 +1,3 @@
from .__main__ import run
__all__ = ["run"]

View File

@ -3,11 +3,11 @@ import sys
import uuid import uuid
import os import os
import logger from . import logger
from host import start_websocket from .host import start_websocket
if len(sys.argv) != 4: if len(sys.argv) != 4:
print('Usage: python python-host.pyz <port> <logDirectory> <woxPid>') print("Usage: python python-host.pyz <port> <logDirectory> <woxPid>")
sys.exit(1) sys.exit(1)
port = int(sys.argv[1]) port = int(sys.argv[1])
@ -18,6 +18,7 @@ trace_id = str(uuid.uuid4())
host_id = f"python-{uuid.uuid4()}" host_id = f"python-{uuid.uuid4()}"
logger.update_log_directory(log_directory) logger.update_log_directory(log_directory)
def check_wox_process(): def check_wox_process():
"""Check if Wox process is still alive""" """Check if Wox process is still alive"""
try: try:
@ -26,6 +27,7 @@ def check_wox_process():
except OSError: except OSError:
return False return False
async def monitor_wox_process(): async def monitor_wox_process():
"""Monitor Wox process and exit if it's not alive""" """Monitor Wox process and exit if it's not alive"""
await logger.info(trace_id, "start monitor wox process") await logger.info(trace_id, "start monitor wox process")
@ -35,17 +37,21 @@ async def monitor_wox_process():
sys.exit(1) sys.exit(1)
await asyncio.sleep(1) await asyncio.sleep(1)
async def main(): async def main():
"""Main function""" """Main function"""
# Log startup information # Log startup information
await logger.info(trace_id, "----------------------------------------") await logger.info(trace_id, "----------------------------------------")
await logger.info(trace_id, f"start python host: {host_id}") await logger.info(trace_id, f"start python host: {host_id}")
await logger.info(trace_id, f"port: {port}") await logger.info(trace_id, f"port: {port}")
await logger.info(trace_id, f"wox pid: {wox_pid}") await logger.info(trace_id, f"wox pid: {wox_pid}")
# Start tasks # Start tasks
monitor_task = asyncio.create_task(monitor_wox_process()) monitor_task = asyncio.create_task(monitor_wox_process())
websocket_task = asyncio.create_task(start_websocket(port)) websocket_task = asyncio.create_task(start_websocket(port))
await asyncio.gather(monitor_task, websocket_task) await asyncio.gather(monitor_task, websocket_task)
asyncio.run(main())
def run():
asyncio.run(main())

View File

@ -2,4 +2,4 @@
PLUGIN_JSONRPC_TYPE_REQUEST = "WOX_JSONRPC_REQUEST" PLUGIN_JSONRPC_TYPE_REQUEST = "WOX_JSONRPC_REQUEST"
PLUGIN_JSONRPC_TYPE_RESPONSE = "WOX_JSONRPC_RESPONSE" PLUGIN_JSONRPC_TYPE_RESPONSE = "WOX_JSONRPC_RESPONSE"
PLUGIN_JSONRPC_TYPE_SYSTEM_LOG = "WOX_JSONRPC_SYSTEM_LOG" PLUGIN_JSONRPC_TYPE_SYSTEM_LOG = "WOX_JSONRPC_SYSTEM_LOG"

View File

@ -1,19 +1,49 @@
#!/usr/bin/env python
import asyncio import asyncio
import json import json
import uuid import uuid
from typing import Dict, Any
import traceback import traceback
from wox_plugin import Context
import websockets import websockets
import logger
from wox_plugin import Context, new_context_with_value
from constants import PLUGIN_JSONRPC_TYPE_REQUEST, PLUGIN_JSONRPC_TYPE_RESPONSE
from plugin_manager import waiting_for_response
from jsonrpc import handle_request_from_wox
async def handle_message(ws: websockets.WebSocketServerProtocol, message: str): from . import logger
from .constants import PLUGIN_JSONRPC_TYPE_REQUEST, PLUGIN_JSONRPC_TYPE_RESPONSE
from .plugin_manager import waiting_for_response
from .jsonrpc import handle_request_from_wox
def _clean_for_serialization(obj):
"""Remove non-serializable properties from any object recursively"""
if obj is None:
return obj
if isinstance(obj, (str, int, float, bool)):
return obj
if isinstance(obj, (list, tuple)):
return [_clean_for_serialization(item) for item in obj]
if isinstance(obj, dict):
return {k: _clean_for_serialization(v) for k, v in obj.items()}
# Handle custom objects
if hasattr(obj, "__dict__"):
# Create a copy of the object's dict
obj_dict = obj.__dict__.copy()
# Remove callable (methods/functions) and handle nested objects
cleaned_dict = {}
for k, v in obj_dict.items():
if callable(v):
continue
cleaned_dict[k] = _clean_for_serialization(v)
return cleaned_dict
# If we can't handle it, just return None
return None
async def handle_message(ws: websockets.asyncio.server.ServerConnection, message: str):
"""Handle incoming WebSocket message""" """Handle incoming WebSocket message"""
trace_id = str(uuid.uuid4()) trace_id = str(uuid.uuid4())
@ -22,7 +52,7 @@ async def handle_message(ws: websockets.WebSocketServerProtocol, message: str):
if msg_data.get("TraceId"): if msg_data.get("TraceId"):
trace_id = msg_data.get("TraceId") trace_id = msg_data.get("TraceId")
ctx = new_context_with_value("traceId", trace_id) ctx = Context.new_with_value("TraceId", trace_id)
if PLUGIN_JSONRPC_TYPE_RESPONSE in message: if PLUGIN_JSONRPC_TYPE_RESPONSE in message:
# Handle response from Wox # Handle response from Wox
@ -37,14 +67,17 @@ async def handle_message(ws: websockets.WebSocketServerProtocol, message: str):
# Handle request from Wox # Handle request from Wox
try: try:
result = await handle_request_from_wox(ctx, msg_data, ws) result = await handle_request_from_wox(ctx, msg_data, ws)
# Clean result for serialization
cleaned_result = _clean_for_serialization(result)
response = { response = {
"TraceId": trace_id, "TraceId": trace_id,
"Id": msg_data["Id"], "Id": msg_data["Id"],
"Method": msg_data["Method"], "Method": msg_data["Method"],
"Type": PLUGIN_JSONRPC_TYPE_RESPONSE, "Type": PLUGIN_JSONRPC_TYPE_RESPONSE,
"Result": result "Result": cleaned_result,
} }
await ws.send(json.dumps(response, default=lambda o: '<not serializable>')) await ws.send(json.dumps(response))
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
error_response = { error_response = {
@ -52,25 +85,29 @@ async def handle_message(ws: websockets.WebSocketServerProtocol, message: str):
"Id": msg_data["Id"], "Id": msg_data["Id"],
"Method": msg_data["Method"], "Method": msg_data["Method"],
"Type": PLUGIN_JSONRPC_TYPE_RESPONSE, "Type": PLUGIN_JSONRPC_TYPE_RESPONSE,
"Error": str(e) "Error": str(e),
} }
await logger.error(trace_id, f"handle request failed: {str(e)}\nStack trace:\n{error_stack}") await logger.error(trace_id, f"handle request failed: {str(e)}\nStack trace:\n{error_stack}")
await ws.send(json.dumps(error_response, default=lambda o: '<not serializable>')) await ws.send(json.dumps(error_response))
else: else:
await logger.error(trace_id, f"unknown message type: {message}") await logger.error(trace_id, f"unknown message type: {message}")
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error(trace_id, f"receive and handle msg error: {message}, err: {str(e)}\nStack trace:\n{error_stack}") await logger.error(
trace_id,
f"receive and handle msg error: {message}, err: {str(e)}\nStack trace:\n{error_stack}",
)
async def handler(websocket: websockets.WebSocketServerProtocol):
async def handler(websocket: websockets.asyncio.server.ServerConnection):
"""WebSocket connection handler""" """WebSocket connection handler"""
logger.update_websocket(websocket) logger.update_websocket(websocket)
try: try:
while True: while True:
try: try:
message = await websocket.recv() message = await websocket.recv()
asyncio.create_task(handle_message(websocket, message)) asyncio.create_task(handle_message(websocket, str(message)))
except websockets.exceptions.ConnectionClosed: except websockets.exceptions.ConnectionClosed:
await logger.info(str(uuid.uuid4()), "connection closed") await logger.info(str(uuid.uuid4()), "connection closed")
break break
@ -80,8 +117,9 @@ async def handler(websocket: websockets.WebSocketServerProtocol):
finally: finally:
logger.update_websocket(None) logger.update_websocket(None)
async def start_websocket(websocket_port: int): async def start_websocket(websocket_port: int):
"""Start WebSocket server""" """Start WebSocket server"""
await logger.info(str(uuid.uuid4()), "start websocket server") await logger.info(str(uuid.uuid4()), "start websocket server")
async with websockets.serve(handler, "", websocket_port): async with websockets.serve(handler, "", websocket_port):
await asyncio.Future() # run forever await asyncio.Future() # run forever

View File

@ -5,37 +5,27 @@ import sys
from typing import Any, Dict from typing import Any, Dict
import uuid import uuid
import websockets import websockets
import logger from . import logger
from wox_plugin.types import ( from wox_plugin import (
Context, Context,
Query, Query,
QueryType,
Selection,
QueryEnv,
RefreshableResult, RefreshableResult,
WoxImage,
WoxPreview,
ResultTail,
ResultAction,
PluginInitParams, PluginInitParams,
ActionContext, ActionContext,
Result,
) )
from plugin_manager import plugin_instances, PluginInstance from .plugin_manager import plugin_instances, PluginInstance
from plugin_api import PluginAPI from .plugin_api import PluginAPI
import traceback import traceback
import asyncio import asyncio
async def handle_request_from_wox( async def handle_request_from_wox(ctx: Context, request: Dict[str, Any], ws: websockets.asyncio.server.ServerConnection) -> Any:
ctx: Context, request: Dict[str, Any], ws: websockets.WebSocketServerProtocol
) -> Any:
"""Handle incoming request from Wox""" """Handle incoming request from Wox"""
method = request.get("Method") method = request.get("Method")
plugin_name = request.get("PluginName") plugin_name = request.get("PluginName")
await logger.info( await logger.info(ctx.get_trace_id(), f"invoke <{plugin_name}> method: {method}")
ctx["Values"]["traceId"], f"invoke <{plugin_name}> method: {method}"
)
if method == "loadPlugin": if method == "loadPlugin":
return await load_plugin(ctx, request) return await load_plugin(ctx, request)
@ -50,19 +40,20 @@ async def handle_request_from_wox(
elif method == "unloadPlugin": elif method == "unloadPlugin":
return await unload_plugin(ctx, request) return await unload_plugin(ctx, request)
else: else:
await logger.info(ctx["Values"]["traceId"], f"unknown method handler: {method}") await logger.info(ctx.get_trace_id(), f"unknown method handler: {method}")
raise Exception(f"unknown method handler: {method}") raise Exception(f"unknown method handler: {method}")
async def load_plugin(ctx: Context, request: Dict[str, Any]) -> None: async def load_plugin(ctx: Context, request: Dict[str, Any]) -> None:
"""Load a plugin""" """Load a plugin"""
plugin_directory: str = request.get("Params", {}).get("PluginDirectory", "") params: Dict[str, str] = request.get("Params", {})
entry: str = request.get("Params", {}).get("Entry", "") plugin_directory: str = params.get("PluginDirectory", "")
entry: str = params.get("Entry", "")
plugin_id: str = request.get("PluginId", "") plugin_id: str = request.get("PluginId", "")
plugin_name: str = request.get("PluginName", "") plugin_name: str = request.get("PluginName", "")
await logger.info( await logger.info(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> load plugin, directory: {plugin_directory}, entry: {entry}", f"<{plugin_name}> load plugin, directory: {plugin_directory}, entry: {entry}",
) )
@ -94,27 +85,23 @@ async def load_plugin(ctx: Context, request: Dict[str, Any]) -> None:
plugin_instances[plugin_id] = PluginInstance( plugin_instances[plugin_id] = PluginInstance(
plugin=module.plugin, plugin=module.plugin,
api=None, # type: ignore , Will be set in init_plugin api=None,
module_path=full_entry_path, module_path=full_entry_path,
actions={}, actions={},
refreshes={}, refreshes={},
) )
await logger.info( await logger.info(ctx.get_trace_id(), f"<{plugin_name}> load plugin successfully")
ctx["Values"]["traceId"], f"<{plugin_name}> load plugin successfully"
)
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> load plugin failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> load plugin failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e
async def init_plugin( async def init_plugin(ctx: Context, request: Dict[str, Any], ws: websockets.asyncio.server.ServerConnection) -> None:
ctx: Context, request: Dict[str, Any], ws: websockets.WebSocketServerProtocol
) -> None:
"""Initialize a plugin""" """Initialize a plugin"""
plugin_id = request.get("PluginId", "") plugin_id = request.get("PluginId", "")
plugin_name = request.get("PluginName", "") plugin_name = request.get("PluginName", "")
@ -126,26 +113,24 @@ async def init_plugin(
# Create plugin API instance # Create plugin API instance
api = PluginAPI(ws, plugin_id, plugin_name) api = PluginAPI(ws, plugin_id, plugin_name)
plugin_instance.api = api plugin_instance.api = api
params: Dict[str, str] = request.get("Params", {})
plugin_directory: str = params.get("PluginDirectory", "")
# Call plugin's init method # Call plugin's init method
init_params = PluginInitParams( init_params = PluginInitParams(api=api, plugin_directory=plugin_directory)
API=api, PluginDirectory=request.get("Params", {}).get("PluginDirectory")
)
await plugin_instance.plugin.init(ctx, init_params) await plugin_instance.plugin.init(ctx, init_params)
await logger.info( await logger.info(ctx.get_trace_id(), f"<{plugin_name}> init plugin successfully")
ctx["Values"]["traceId"], f"<{plugin_name}> init plugin successfully"
)
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> init plugin failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> init plugin failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e
async def query(ctx: Context, request: Dict[str, Any]) -> list[Any]: async def query(ctx: Context, request: Dict[str, Any]) -> list[Result]:
"""Handle query request""" """Handle query request"""
plugin_id = request.get("PluginId", "") plugin_id = request.get("PluginId", "")
plugin_name = request.get("PluginName", "") plugin_name = request.get("PluginName", "")
@ -158,50 +143,36 @@ async def query(ctx: Context, request: Dict[str, Any]) -> list[Any]:
plugin_instance.actions.clear() plugin_instance.actions.clear()
plugin_instance.refreshes.clear() plugin_instance.refreshes.clear()
params = request.get("Params", {}) params: Dict[str, str] = request.get("Params", {})
results = await plugin_instance.plugin.query( results = await plugin_instance.plugin.query(ctx, Query.from_json(json.dumps(params)))
ctx,
Query(
Type=QueryType(params.get("Type")),
RawQuery=params.get("RawQuery"),
TriggerKeyword=params.get("TriggerKeyword"),
Command=params.get("Command"),
Search=params.get("Search"),
Selection=Selection(**json.loads(params.get("Selection"))),
Env=QueryEnv(**json.loads(params.get("Env"))),
),
)
# Ensure each result has an ID and cache actions and refreshes # Ensure each result has an ID and cache actions and refreshes
if results: if results:
for result in results: for result in results:
if not result.Id: if not result.id:
result.Id = str(uuid.uuid4()) result.id = str(uuid.uuid4())
if result.Actions: if result.actions:
for action in result.Actions: for action in result.actions:
if not action.Id: if action.action:
action.Id = str(uuid.uuid4()) if not action.id:
# Cache action action.id = str(uuid.uuid4())
plugin_instance.actions[action.Id] = action.Action # Cache action
plugin_instance.actions[action.id] = action.action
# Cache refresh callback if exists # Cache refresh callback if exists
if ( if result.refresh_interval and result.refresh_interval > 0 and result.on_refresh:
result.RefreshInterval plugin_instance.refreshes[result.id] = result.on_refresh
and result.RefreshInterval > 0
and result.OnRefresh
):
plugin_instance.refreshes[result.Id] = result.OnRefresh
return [result.to_dict() for result in results] return results
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> query failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> query failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e
async def action(ctx: Context, request: Dict[str, Any]) -> Any: async def action(ctx: Context, request: Dict[str, Any]) -> None:
"""Handle action request""" """Handle action request"""
plugin_id = request.get("PluginId", "") plugin_id = request.get("PluginId", "")
plugin_name = request.get("PluginName", "") plugin_name = request.get("PluginName", "")
@ -210,29 +181,28 @@ async def action(ctx: Context, request: Dict[str, Any]) -> Any:
raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?") raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?")
try: try:
params = request.get("Params", {}) params: Dict[str, str] = request.get("Params", {})
action_id = params.get("ActionId") action_id = params.get("ActionId", "")
context_data = params.get("ContextData") context_data = params.get("ContextData", "")
# Get action from cache # Get action from cache
action_func = plugin_instance.actions.get(action_id) action_func = plugin_instance.actions.get(action_id)
if action_func: if action_func:
# Handle both coroutine and regular functions # Handle both coroutine and regular functions
result = action_func(ActionContext(ContextData=context_data)) result = action_func(ActionContext(context_data=context_data))
if asyncio.iscoroutine(result): if asyncio.iscoroutine(result):
asyncio.create_task(result) asyncio.create_task(result)
return None
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> action failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> action failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e
async def refresh(ctx: Context, request: Dict[str, Any]) -> Any: async def refresh(ctx: Context, request: Dict[str, Any]) -> RefreshableResult:
"""Handle refresh request""" """Handle refresh request"""
plugin_id = request.get("PluginId", "") plugin_id = request.get("PluginId", "")
plugin_name = request.get("PluginName", "") plugin_name = request.get("PluginName", "")
@ -241,50 +211,37 @@ async def refresh(ctx: Context, request: Dict[str, Any]) -> Any:
raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?") raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?")
try: try:
params = request.get("Params", {}) params: Dict[str, str] = request.get("Params", {})
result_id = params.get("ResultId") result_id = params.get("ResultId", "")
refreshable_result_dict = json.loads(params.get("RefreshableResult")) refreshable_result_dict = json.loads(params.get("RefreshableResult", ""))
# Convert dict to RefreshableResult object # Convert dict to RefreshableResult object
refreshable_result = RefreshableResult( refreshable_result = RefreshableResult.from_json(json.dumps(refreshable_result_dict))
Title=refreshable_result_dict.get("Title"),
SubTitle=refreshable_result_dict.get("SubTitle", ""),
Icon=WoxImage.from_dict(refreshable_result_dict.get("Icon", {})),
Preview=WoxPreview.from_dict(refreshable_result_dict.get("Preview", {})),
Tails=[
ResultTail.from_dict(tail)
for tail in refreshable_result_dict.get("Tails", [])
],
ContextData=refreshable_result_dict.get("ContextData", ""),
RefreshInterval=refreshable_result_dict.get("RefreshInterval", 0),
Actions=[
ResultAction.from_dict(action)
for action in refreshable_result_dict.get("Actions", [])
],
)
# replace action with cached action # replace action with cached action
for action in refreshable_result.Actions: for action in refreshable_result.actions:
action.Action = plugin_instance.actions.get(action.Id) action.action = plugin_instance.actions.get(action.id)
refresh_func = plugin_instance.refreshes.get(result_id) refresh_func = plugin_instance.refreshes.get(result_id)
if refresh_func: if refresh_func:
refreshed_result = await refresh_func(refreshable_result) refreshed_result = await refresh_func(refreshable_result)
# Cache any new actions from the refreshed result # Cache any new actions from the refreshed result
if refreshed_result.Actions: if refreshed_result.actions:
for action in refreshed_result.Actions: for action in refreshed_result.actions:
if not action.Id: if not action.id:
action.Id = str(uuid.uuid4()) action.id = str(uuid.uuid4())
plugin_instance.actions[action.Id] = action.Action
return refreshed_result.to_dict() if action.action:
plugin_instance.actions[action.id] = action.action
return None return refreshed_result
raise Exception(f"refresh function not found for result id: {result_id}")
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> refresh failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> refresh failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e
@ -292,8 +249,8 @@ async def refresh(ctx: Context, request: Dict[str, Any]) -> Any:
async def unload_plugin(ctx: Context, request: Dict[str, Any]) -> None: async def unload_plugin(ctx: Context, request: Dict[str, Any]) -> None:
"""Unload a plugin""" """Unload a plugin"""
plugin_id = request.get("PluginId") plugin_id = request.get("PluginId", "")
plugin_name = request.get("PluginName") plugin_name = request.get("PluginName", "")
plugin_instance = plugin_instances.get(plugin_id) plugin_instance = plugin_instances.get(plugin_id)
if not plugin_instance: if not plugin_instance:
raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?") raise Exception(f"plugin not found: {plugin_name}, forget to load plugin?")
@ -307,13 +264,11 @@ async def unload_plugin(ctx: Context, request: Dict[str, Any]) -> None:
if plugin_dir in sys.path: if plugin_dir in sys.path:
sys.path.remove(plugin_dir) sys.path.remove(plugin_dir)
await logger.info( await logger.info(ctx.get_trace_id(), f"<{plugin_name}> unload plugin successfully")
ctx["Values"]["traceId"], f"<{plugin_name}> unload plugin successfully"
)
except Exception as e: except Exception as e:
error_stack = traceback.format_exc() error_stack = traceback.format_exc()
await logger.error( await logger.error(
ctx["Values"]["traceId"], ctx.get_trace_id(),
f"<{plugin_name}> unload plugin failed: {str(e)}\nStack trace:\n{error_stack}", f"<{plugin_name}> unload plugin failed: {str(e)}\nStack trace:\n{error_stack}",
) )
raise e raise e

View File

@ -1,41 +1,51 @@
import json import json
from typing import Optional from typing import Optional
import websockets
from loguru import logger from loguru import logger
from websockets.asyncio.server import ServerConnection
PLUGIN_JSONRPC_TYPE_SYSTEM_LOG = "WOX_JSONRPC_SYSTEM_LOG" PLUGIN_JSONRPC_TYPE_SYSTEM_LOG = "WOX_JSONRPC_SYSTEM_LOG"
websocket: Optional[websockets.WebSocketServerProtocol] = None websocket: Optional[ServerConnection] = None
def update_log_directory(log_directory: str): def update_log_directory(log_directory: str):
"""Update the log directory for the logger""" """Update the log directory for the logger"""
logger.remove() logger.remove()
logger.add(f"{log_directory}/python.log", format="{time} {message}") logger.add(f"{log_directory}/python.log", format="{time} {message}")
def update_websocket(ws: Optional[websockets.WebSocketServerProtocol]):
def update_websocket(ws: Optional[ServerConnection]):
"""Update the websocket connection for logging""" """Update the websocket connection for logging"""
global websocket global websocket
websocket = ws websocket = ws
async def log(trace_id: str, level: str, msg: str): async def log(trace_id: str, level: str, msg: str):
"""Log a message to both file and websocket if available""" """Log a message to both file and websocket if available"""
logger.log(level.upper(), f"{trace_id} [{level}] {msg}") logger.log(level.upper(), f"{trace_id} [{level}] {msg}")
if websocket: if websocket:
try: try:
await websocket.send(json.dumps({ await websocket.send(
"Type": PLUGIN_JSONRPC_TYPE_SYSTEM_LOG, json.dumps(
"TraceId": trace_id, {
"Level": level, "Type": PLUGIN_JSONRPC_TYPE_SYSTEM_LOG,
"Message": msg "TraceId": trace_id,
})) "Level": level,
"Message": msg,
}
)
)
except Exception as e: except Exception as e:
logger.error(f"Failed to send log message through websocket: {e}") logger.error(f"Failed to send log message through websocket: {e}")
async def debug(trace_id: str, msg: str): async def debug(trace_id: str, msg: str):
await log(trace_id, "debug", msg) await log(trace_id, "debug", msg)
async def info(trace_id: str, msg: str): async def info(trace_id: str, msg: str):
await log(trace_id, "info", msg) await log(trace_id, "info", msg)
async def error(trace_id: str, msg: str): async def error(trace_id: str, msg: str):
await log(trace_id, "error", msg) await log(trace_id, "error", msg)

View File

@ -3,42 +3,35 @@ import json
import uuid import uuid
from typing import Any, Dict, Callable from typing import Any, Dict, Callable
import websockets import websockets
import logger from . import logger
from wox_plugin.types import ( from wox_plugin import (
Context, Context,
PublicAPI, PublicAPI,
ChangeQueryParam, ChangeQueryParam,
MetadataCommand, MetadataCommand,
PluginSettingDefinitionItem,
MapString,
Conversation, Conversation,
ChatStreamFunc, AIModel,
ChatStreamCallback,
) )
from constants import PLUGIN_JSONRPC_TYPE_REQUEST from .constants import PLUGIN_JSONRPC_TYPE_REQUEST
from plugin_manager import waiting_for_response from .plugin_manager import waiting_for_response
class PluginAPI(PublicAPI): class PluginAPI(PublicAPI):
def __init__( def __init__(self, ws: websockets.asyncio.server.ServerConnection, plugin_id: str, plugin_name: str):
self, ws: websockets.WebSocketServerProtocol, plugin_id: str, plugin_name: str
):
self.ws = ws self.ws = ws
self.plugin_id = plugin_id self.plugin_id = plugin_id
self.plugin_name = plugin_name self.plugin_name = plugin_name
self.setting_change_callbacks: Dict[str, Callable[[str, str], None]] = {} self.setting_change_callbacks: Dict[str, Callable[[str, str], None]] = {}
self.get_dynamic_setting_callbacks: Dict[ self.get_dynamic_setting_callbacks: Dict[str, Callable[[str], str]] = {}
str, Callable[[str], PluginSettingDefinitionItem] self.deep_link_callbacks: Dict[str, Callable[[Dict[str, str]], None]] = {}
] = {}
self.deep_link_callbacks: Dict[str, Callable[[MapString], None]] = {}
self.unload_callbacks: Dict[str, Callable[[], None]] = {} self.unload_callbacks: Dict[str, Callable[[], None]] = {}
self.llm_stream_callbacks: Dict[str, ChatStreamFunc] = {} self.llm_stream_callbacks: Dict[str, ChatStreamCallback] = {}
async def invoke_method( async def invoke_method(self, ctx: Context, method: str, params: Dict[str, Any]) -> Any:
self, ctx: Context, method: str, params: Dict[str, Any]
) -> Any:
"""Invoke a method on Wox""" """Invoke a method on Wox"""
request_id = str(uuid.uuid4()) request_id = str(uuid.uuid4())
trace_id = ctx["Values"]["traceId"] trace_id = ctx.get_trace_id()
if method != "Log": if method != "Log":
await logger.info( await logger.info(
@ -71,11 +64,9 @@ class PluginAPI(PublicAPI):
async def change_query(self, ctx: Context, query: ChangeQueryParam) -> None: async def change_query(self, ctx: Context, query: ChangeQueryParam) -> None:
"""Change the query in Wox""" """Change the query in Wox"""
params = { params = {
"QueryType": query.QueryType, "QueryType": query.query_type,
"QueryText": query.QueryText, "QueryText": query.query_text,
"QuerySelection": ( "QuerySelection": (query.query_selection.__dict__ if query.query_selection else None),
query.QuerySelection.__dict__ if query.QuerySelection else None
),
} }
await self.invoke_method(ctx, "ChangeQuery", params) await self.invoke_method(ctx, "ChangeQuery", params)
@ -105,9 +96,7 @@ class PluginAPI(PublicAPI):
result = await self.invoke_method(ctx, "GetSetting", {"key": key}) result = await self.invoke_method(ctx, "GetSetting", {"key": key})
return str(result) if result is not None else "" return str(result) if result is not None else ""
async def save_setting( async def save_setting(self, ctx: Context, key: str, value: str, is_platform_specific: bool) -> None:
self, ctx: Context, key: str, value: str, is_platform_specific: bool
) -> None:
"""Save a setting value""" """Save a setting value"""
await self.invoke_method( await self.invoke_method(
ctx, ctx,
@ -115,27 +104,19 @@ class PluginAPI(PublicAPI):
{"key": key, "value": value, "isPlatformSpecific": is_platform_specific}, {"key": key, "value": value, "isPlatformSpecific": is_platform_specific},
) )
async def on_setting_changed( async def on_setting_changed(self, ctx: Context, callback: Callable[[str, str], None]) -> None:
self, ctx: Context, callback: Callable[[str, str], None]
) -> None:
"""Register setting changed callback""" """Register setting changed callback"""
callback_id = str(uuid.uuid4()) callback_id = str(uuid.uuid4())
self.setting_change_callbacks[callback_id] = callback self.setting_change_callbacks[callback_id] = callback
await self.invoke_method(ctx, "OnSettingChanged", {"callbackId": callback_id}) await self.invoke_method(ctx, "OnSettingChanged", {"callbackId": callback_id})
async def on_get_dynamic_setting( async def on_get_dynamic_setting(self, ctx: Context, callback: Callable[[str], str]) -> None:
self, ctx: Context, callback: Callable[[str], PluginSettingDefinitionItem]
) -> None:
"""Register dynamic setting callback""" """Register dynamic setting callback"""
callback_id = str(uuid.uuid4()) callback_id = str(uuid.uuid4())
self.get_dynamic_setting_callbacks[callback_id] = callback self.get_dynamic_setting_callbacks[callback_id] = callback
await self.invoke_method( await self.invoke_method(ctx, "OnGetDynamicSetting", {"callbackId": callback_id})
ctx, "OnGetDynamicSetting", {"callbackId": callback_id}
)
async def on_deep_link( async def on_deep_link(self, ctx: Context, callback: Callable[[Dict[str, str]], None]) -> None:
self, ctx: Context, callback: Callable[[MapString], None]
) -> None:
"""Register deep link callback""" """Register deep link callback"""
callback_id = str(uuid.uuid4()) callback_id = str(uuid.uuid4())
self.deep_link_callbacks[callback_id] = callback self.deep_link_callbacks[callback_id] = callback
@ -147,9 +128,7 @@ class PluginAPI(PublicAPI):
self.unload_callbacks[callback_id] = callback self.unload_callbacks[callback_id] = callback
await self.invoke_method(ctx, "OnUnload", {"callbackId": callback_id}) await self.invoke_method(ctx, "OnUnload", {"callbackId": callback_id})
async def register_query_commands( async def register_query_commands(self, ctx: Context, commands: list[MetadataCommand]) -> None:
self, ctx: Context, commands: list[MetadataCommand]
) -> None:
"""Register query commands""" """Register query commands"""
await self.invoke_method( await self.invoke_method(
ctx, ctx,
@ -157,8 +136,12 @@ class PluginAPI(PublicAPI):
{"commands": json.dumps([command.__dict__ for command in commands])}, {"commands": json.dumps([command.__dict__ for command in commands])},
) )
async def llm_stream( async def ai_chat_stream(
self, ctx: Context, conversations: list[Conversation], callback: ChatStreamFunc self,
ctx: Context,
model: AIModel,
conversations: list[Conversation],
callback: ChatStreamCallback,
) -> None: ) -> None:
"""Chat using LLM""" """Chat using LLM"""
callback_id = str(uuid.uuid4()) callback_id = str(uuid.uuid4())

View File

@ -1,18 +1,18 @@
from typing import Dict, TypeVar, Callable from typing import Dict, Any, Callable, Optional, Awaitable
from dataclasses import dataclass from dataclasses import dataclass
import asyncio import asyncio
from wox_plugin import PublicAPI, Plugin, RefreshableResult, ActionContext from wox_plugin import PublicAPI, Plugin, RefreshableResult, ActionContext
@dataclass @dataclass
class PluginInstance: class PluginInstance:
plugin: Plugin plugin: Plugin
api: PublicAPI api: Optional[PublicAPI]
module_path: str module_path: str
actions: Dict[str, Callable[[ActionContext], None]] actions: Dict[str, Callable[[ActionContext], Awaitable[None]]]
refreshes: Dict[str, Callable[[RefreshableResult], RefreshableResult]] refreshes: Dict[str, Callable[[RefreshableResult], Awaitable[RefreshableResult]]]
T = TypeVar('T')
# Global state with strong typing # Global state with strong typing
plugin_instances: Dict[str, PluginInstance] = {} plugin_instances: Dict[str, PluginInstance] = {}
waiting_for_response: Dict[str, asyncio.Future[T]] = {} waiting_for_response: Dict[str, asyncio.Future[Any]] = {}

View File

@ -1,49 +1,6 @@
version = 1 version = 1
requires-python = ">=3.10" requires-python = ">=3.10"
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
]
[[package]]
name = "black"
version = "24.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "mypy-extensions" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "platformdirs" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 },
{ url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 },
{ url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 },
{ url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 },
{ url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 },
{ url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 },
{ url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 },
{ url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 },
{ url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 },
{ url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 },
{ url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 },
{ url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 },
{ url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 },
{ url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 },
{ url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 },
{ url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 },
{ url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 },
]
[[package]] [[package]]
name = "click" name = "click"
version = "8.1.7" version = "8.1.7"
@ -78,6 +35,40 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595 }, { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595 },
] ]
[[package]]
name = "mypy"
version = "1.14.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/7b/08046ef9330735f536a09a2e31b00f42bccdb2795dcd979636ba43bb2d63/mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6", size = 3215684 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/97/f00ded038482230e0beaaa08f9c5483a54530b362ad1b0d752d5d2b2f211/mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87", size = 11207956 },
{ url = "https://files.pythonhosted.org/packages/68/67/8b4db0da19c9e3fa6264e948f1c135ab4dd45bede1809f4fdb613dc119f6/mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179", size = 10363681 },
{ url = "https://files.pythonhosted.org/packages/f5/00/56b1619ff1f3fcad2d411eccda60d74d20e73bda39c218d5ad2769980682/mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e", size = 12832976 },
{ url = "https://files.pythonhosted.org/packages/e7/8b/9247838774b0bd865f190cc221822212091317f16310305ef924d9772532/mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3", size = 13013704 },
{ url = "https://files.pythonhosted.org/packages/b2/69/0c0868a6f3d9761d2f704d1fb6ef84d75998c27d342738a8b20f109a411f/mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44", size = 9782230 },
{ url = "https://files.pythonhosted.org/packages/34/c1/b9dd3e955953aec1c728992545b7877c9f6fa742a623ce4c200da0f62540/mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a", size = 11121032 },
{ url = "https://files.pythonhosted.org/packages/ee/96/c52d5d516819ab95bf41f4a1ada828a3decc302f8c152ff4fc5feb0e4529/mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc", size = 10286294 },
{ url = "https://files.pythonhosted.org/packages/69/2c/3dbe51877a24daa467f8d8631f9ffd1aabbf0f6d9367a01c44a59df81fe0/mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015", size = 12746528 },
{ url = "https://files.pythonhosted.org/packages/a1/a8/eb20cde4ba9c4c3e20d958918a7c5d92210f4d1a0200c27de9a641f70996/mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb", size = 12883489 },
{ url = "https://files.pythonhosted.org/packages/91/17/a1fc6c70f31d52c99299320cf81c3cb2c6b91ec7269414e0718a6d138e34/mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc", size = 9780113 },
{ url = "https://files.pythonhosted.org/packages/fe/d8/0e72175ee0253217f5c44524f5e95251c02e95ba9749fb87b0e2074d203a/mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd", size = 11269011 },
{ url = "https://files.pythonhosted.org/packages/e9/6d/4ea13839dabe5db588dc6a1b766da16f420d33cf118a7b7172cdf6c7fcb2/mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1", size = 10253076 },
{ url = "https://files.pythonhosted.org/packages/3e/38/7db2c5d0f4d290e998f7a52b2e2616c7bbad96b8e04278ab09d11978a29e/mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63", size = 12862786 },
{ url = "https://files.pythonhosted.org/packages/bf/4b/62d59c801b34141040989949c2b5c157d0408b45357335d3ec5b2845b0f6/mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d", size = 12971568 },
{ url = "https://files.pythonhosted.org/packages/f1/9c/e0f281b32d70c87b9e4d2939e302b1ff77ada4d7b0f2fb32890c144bc1d6/mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba", size = 9879477 },
{ url = "https://files.pythonhosted.org/packages/13/33/8380efd0ebdfdfac7fc0bf065f03a049800ca1e6c296ec1afc634340d992/mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741", size = 11251509 },
{ url = "https://files.pythonhosted.org/packages/15/6d/4e1c21c60fee11af7d8e4f2902a29886d1387d6a836be16229eb3982a963/mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7", size = 10244282 },
{ url = "https://files.pythonhosted.org/packages/8b/cf/7a8ae5c0161edae15d25c2c67c68ce8b150cbdc45aefc13a8be271ee80b2/mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8", size = 12867676 },
{ url = "https://files.pythonhosted.org/packages/9c/d0/71f7bbdcc7cfd0f2892db5b13b1e8857673f2cc9e0c30e3e4340523dc186/mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc", size = 12964189 },
{ url = "https://files.pythonhosted.org/packages/a7/40/fb4ad65d6d5f8c51396ecf6305ec0269b66013a5bf02d0e9528053640b4a/mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f", size = 9888247 },
{ url = "https://files.pythonhosted.org/packages/39/32/0214608af400cdf8f5102144bb8af10d880675c65ed0b58f7e0e77175d50/mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab", size = 2752803 },
]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
@ -88,119 +79,60 @@ wheels = [
] ]
[[package]] [[package]]
name = "packaging" name = "pip"
version = "24.2" version = "24.3.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 },
] ]
[[package]] [[package]]
name = "pathspec" name = "ruff"
version = "0.12.1" version = "0.8.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } sdist = { url = "https://files.pythonhosted.org/packages/34/37/9c02181ef38d55b77d97c68b78e705fd14c0de0e5d085202bb2b52ce5be9/ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8", size = 3402103 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, { url = "https://files.pythonhosted.org/packages/05/67/f480bf2f2723b2e49af38ed2be75ccdb2798fca7d56279b585c8f553aaab/ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60", size = 10546415 },
{ url = "https://files.pythonhosted.org/packages/eb/7a/5aba20312c73f1ce61814e520d1920edf68ca3b9c507bd84d8546a8ecaa8/ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac", size = 10346113 },
{ url = "https://files.pythonhosted.org/packages/76/f4/c41de22b3728486f0aa95383a44c42657b2db4062f3234ca36fc8cf52d8b/ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296", size = 9943564 },
{ url = "https://files.pythonhosted.org/packages/0e/f0/afa0d2191af495ac82d4cbbfd7a94e3df6f62a04ca412033e073b871fc6d/ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643", size = 10805522 },
{ url = "https://files.pythonhosted.org/packages/12/57/5d1e9a0fd0c228e663894e8e3a8e7063e5ee90f8e8e60cf2085f362bfa1a/ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e", size = 10306763 },
{ url = "https://files.pythonhosted.org/packages/04/df/f069fdb02e408be8aac6853583572a2873f87f866fe8515de65873caf6b8/ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3", size = 11359574 },
{ url = "https://files.pythonhosted.org/packages/d3/04/37c27494cd02e4a8315680debfc6dfabcb97e597c07cce0044db1f9dfbe2/ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f", size = 12094851 },
{ url = "https://files.pythonhosted.org/packages/81/b1/c5d7fb68506cab9832d208d03ea4668da9a9887a4a392f4f328b1bf734ad/ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604", size = 11655539 },
{ url = "https://files.pythonhosted.org/packages/ef/38/8f8f2c8898dc8a7a49bc340cf6f00226917f0f5cb489e37075bcb2ce3671/ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf", size = 12912805 },
{ url = "https://files.pythonhosted.org/packages/06/dd/fa6660c279f4eb320788876d0cff4ea18d9af7d9ed7216d7bd66877468d0/ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720", size = 11205976 },
{ url = "https://files.pythonhosted.org/packages/a8/d7/de94cc89833b5de455750686c17c9e10f4e1ab7ccdc5521b8fe911d1477e/ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae", size = 10792039 },
{ url = "https://files.pythonhosted.org/packages/6d/15/3e4906559248bdbb74854af684314608297a05b996062c9d72e0ef7c7097/ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7", size = 10400088 },
{ url = "https://files.pythonhosted.org/packages/a2/21/9ed4c0e8133cb4a87a18d470f534ad1a8a66d7bec493bcb8bda2d1a5d5be/ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111", size = 10900814 },
{ url = "https://files.pythonhosted.org/packages/0d/5d/122a65a18955bd9da2616b69bc839351f8baf23b2805b543aa2f0aed72b5/ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8", size = 11268828 },
{ url = "https://files.pythonhosted.org/packages/43/a9/1676ee9106995381e3d34bccac5bb28df70194167337ed4854c20f27c7ba/ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835", size = 8805621 },
{ url = "https://files.pythonhosted.org/packages/10/98/ed6b56a30ee76771c193ff7ceeaf1d2acc98d33a1a27b8479cbdb5c17a23/ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d", size = 9660086 },
{ url = "https://files.pythonhosted.org/packages/13/9f/026e18ca7d7766783d779dae5e9c656746c6ede36ef73c6d934aaf4a6dec/ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08", size = 9074500 },
] ]
[[package]] [[package]]
name = "platformdirs" name = "setuptools"
version = "4.3.6" version = "75.6.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } sdist = { url = "https://files.pythonhosted.org/packages/43/54/292f26c208734e9a7f067aea4a7e282c080750c4546559b58e2e45413ca0/setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", size = 1337429 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, { url = "https://files.pythonhosted.org/packages/55/21/47d163f615df1d30c094f6c8bbb353619274edccf0327b185cc2493c2c33/setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d", size = 1224032 },
] ]
[[package]] [[package]]
name = "pydantic" name = "shiv"
version = "2.10.4" version = "1.0.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "annotated-types" }, { name = "click" },
{ name = "pydantic-core" }, { name = "pip" },
{ name = "typing-extensions" }, { name = "setuptools" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094 } sdist = { url = "https://files.pythonhosted.org/packages/06/85/004e7123b4821c64be6d9bfed27f63147b4dde929a1cd848f137befeada4/shiv-1.0.8.tar.gz", hash = "sha256:2a68d69e98ce81cb5b8fdafbfc1e27efa93e6d89ca14bfae33482e4176f561d6", size = 32806 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765 }, { url = "https://files.pythonhosted.org/packages/e7/ec/afbb46f7c1ab071a50d92424daf149420ca1f0e02dc51239485747151d6c/shiv-1.0.8-py2.py3-none-any.whl", hash = "sha256:a60e4b05a2d2f8b820d567b1d89ee59af731759771c32c282d03c4ceae6aba24", size = 20516 },
]
[[package]]
name = "pydantic-core"
version = "2.27.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 },
{ url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 },
{ url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 },
{ url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 },
{ url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 },
{ url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 },
{ url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 },
{ url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 },
{ url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 },
{ url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 },
{ url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 },
{ url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 },
{ url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 },
{ url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 },
{ url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 },
{ url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 },
{ url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 },
{ url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 },
{ url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 },
{ url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 },
{ url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 },
{ url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 },
{ url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 },
{ url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 },
{ url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 },
{ url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 },
{ url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 },
{ url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 },
{ url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 },
{ url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 },
{ url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 },
{ url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 },
{ url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 },
{ url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 },
{ url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 },
{ url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 },
{ url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 },
{ url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 },
{ url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
{ url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
{ url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
{ url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
{ url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
{ url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
{ url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 },
{ url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 },
{ url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 },
{ url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 },
{ url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 },
{ url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 },
{ url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 },
{ url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 },
{ url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 },
{ url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 },
{ url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
{ url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 },
{ url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 },
{ url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 },
{ url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 },
{ url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 },
{ url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 },
{ url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 },
{ url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 },
{ url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 },
] ]
[[package]] [[package]]
@ -321,14 +253,11 @@ wheels = [
[[package]] [[package]]
name = "wox-plugin" name = "wox-plugin"
version = "0.0.30" version = "0.0.45"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ sdist = { url = "https://files.pythonhosted.org/packages/55/0f/88e083cda63dfeda66bf4a506322bfa161789cb268f9f7e5d366a6982860/wox_plugin-0.0.45.tar.gz", hash = "sha256:38a543336b2eb32a22cbd85b5b288e63d38c5e67c977f02c6ac8f59c7ba6ca8e", size = 34974 }
{ name = "pydantic" },
]
sdist = { url = "https://files.pythonhosted.org/packages/30/58/c09cc97cee3b3253dd1d332fe95c828b241e8f788b5d81dbda6e38767568/wox_plugin-0.0.30.tar.gz", hash = "sha256:e23d7b85ba2845f11047b3fa049edf08ebc6d5435ecd6aa486cbfdcb0b1dd3c0", size = 46011 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/22/a418ccaea3dfaa7f25b03ed9012ae9fa0ca94b2c8fdd7710342862555093/wox_plugin-0.0.30-py3-none-any.whl", hash = "sha256:deea70fce050fc969ed90584d3635fde96ea76e3c562fca0a1a5b83cf634791e", size = 7850 }, { url = "https://files.pythonhosted.org/packages/dd/9f/1f0a833675292b77a6fa3276749125ea4100f5caccdd3cb4584e00878ad5/wox_plugin-0.0.45-py3-none-any.whl", hash = "sha256:2ac9d1fd84e73be0c3af6ba5f9b2f551052196543d9d6b60ae2e6b2ddeb3f8f9", size = 10304 },
] ]
[[package]] [[package]]
@ -343,13 +272,17 @@ dependencies = [
[package.optional-dependencies] [package.optional-dependencies]
dev = [ dev = [
{ name = "black" }, { name = "mypy" },
{ name = "ruff" },
{ name = "shiv" },
] ]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "black", marker = "extra == 'dev'" },
{ name = "loguru" }, { name = "loguru" },
{ name = "mypy", marker = "extra == 'dev'" },
{ name = "ruff", marker = "extra == 'dev'" },
{ name = "shiv", marker = "extra == 'dev'" },
{ name = "websockets" }, { name = "websockets" },
{ name = "wox-plugin", specifier = "==0.0.30" }, { name = "wox-plugin", specifier = "==0.0.45" },
] ]

View File

@ -1,264 +1,264 @@
import {MetadataCommand, PluginSettingDefinitionItem} from "./setting.js" import { MetadataCommand, PluginSettingDefinitionItem } from "./setting.js"
import {AI} from "./ai.js" import { AI } from "./ai.js"
export type MapString = { [key: string]: string } export type MapString = { [key: string]: string }
export type Platform = "windows" | "darwin" | "linux" export type Platform = "windows" | "darwin" | "linux"
export interface Plugin { export interface Plugin {
init: (ctx: Context, initParams: PluginInitParams) => Promise<void> init: (ctx: Context, initParams: PluginInitParams) => Promise<void>
query: (ctx: Context, query: Query) => Promise<Result[]> query: (ctx: Context, query: Query) => Promise<Result[]>
} }
export interface Selection { export interface Selection {
Type: "text" | "file" Type: "text" | "file"
// Only available when Type is text // Only available when Type is text
Text: string Text: string
// Only available when Type is file // Only available when Type is file
FilePaths: string[] FilePaths: string[]
} }
export interface QueryEnv { export interface QueryEnv {
/** /**
* Active window title when user query * Active window title when user query
*/ */
ActiveWindowTitle: string ActiveWindowTitle: string
/** /**
* Active window pid when user query, 0 if not available * Active window pid when user query, 0 if not available
*/ */
ActiveWindowPid: number ActiveWindowPid: number
// active browser url when user query // active browser url when user query
// Only available when active window is browser and https://github.com/Wox-launcher/Wox.Chrome.Extension is installed // Only available when active window is browser and https://github.com/Wox-launcher/Wox.Chrome.Extension is installed
ActiveBrowserUrl: string ActiveBrowserUrl: string
} }
export interface Query { export interface Query {
/** /**
* By default, Wox will only pass input query to plugin. * By default, Wox will only pass input query to plugin.
* plugin author need to enable MetadataFeatureQuerySelection feature to handle selection query * plugin author need to enable MetadataFeatureQuerySelection feature to handle selection query
*/ */
Type: "input" | "selection" Type: "input" | "selection"
/** /**
* Raw query, this includes trigger keyword if it has * Raw query, this includes trigger keyword if it has
* We didn't recommend use this property directly. You should always use Search property. * We didn't recommend use this property directly. You should always use Search property.
* *
* NOTE: Only available when query type is input * NOTE: Only available when query type is input
*/ */
RawQuery: string RawQuery: string
/** /**
* Trigger keyword of a query. It can be empty if user is using global trigger keyword. * Trigger keyword of a query. It can be empty if user is using global trigger keyword.
* *
* NOTE: Only available when query type is input * NOTE: Only available when query type is input
*/ */
TriggerKeyword?: string TriggerKeyword?: string
/** /**
* Command part of a query. * Command part of a query.
* *
* NOTE: Only available when query type is input * NOTE: Only available when query type is input
*/ */
Command?: string Command?: string
/** /**
* Search part of a query. * Search part of a query.
* *
* NOTE: Only available when query type is input * NOTE: Only available when query type is input
*/ */
Search: string Search: string
/** /**
* User selected or drag-drop data, can be text or file or image etc * User selected or drag-drop data, can be text or file or image etc
* *
* NOTE: Only available when query type is selection * NOTE: Only available when query type is selection
*/ */
Selection: Selection Selection: Selection
/** /**
* Additional query environment data * Additional query environment data
* expose more context env data to plugin, E.g. plugin A only show result when active window title is "Chrome" * expose more context env data to plugin, E.g. plugin A only show result when active window title is "Chrome"
*/ */
Env: QueryEnv Env: QueryEnv
/** /**
* Whether current query is global query * Whether current query is global query
*/ */
IsGlobalQuery(): boolean IsGlobalQuery(): boolean
} }
export interface Result { export interface Result {
Id?: string Id?: string
Title: string Title: string
SubTitle?: string SubTitle?: string
Icon: WoxImage Icon: WoxImage
Preview?: WoxPreview Preview?: WoxPreview
Score?: number Score?: number
Group?: string Group?: string
GroupScore?: number GroupScore?: number
Tails?: ResultTail[] Tails?: ResultTail[]
ContextData?: string ContextData?: string
Actions?: ResultAction[] Actions?: ResultAction[]
// refresh result after specified interval, in milliseconds. If this value is 0, Wox will not refresh this result // refresh result after specified interval, in milliseconds. If this value is 0, Wox will not refresh this result
// interval can only divisible by 100, if not, Wox will use the nearest number which is divisible by 100 // interval can only divisible by 100, if not, Wox will use the nearest number which is divisible by 100
// E.g. if you set 123, Wox will use 200, if you set 1234, Wox will use 1300 // E.g. if you set 123, Wox will use 200, if you set 1234, Wox will use 1300
RefreshInterval?: number RefreshInterval?: number
// refresh result by calling OnRefresh function // refresh result by calling OnRefresh function
OnRefresh?: (current: RefreshableResult) => Promise<RefreshableResult> OnRefresh?: (current: RefreshableResult) => Promise<RefreshableResult>
} }
export interface ResultTail { export interface ResultTail {
Type: "text" | "image" Type: "text" | "image"
Text?: string Text?: string
Image?: WoxImage Image?: WoxImage
} }
export interface RefreshableResult { export interface RefreshableResult {
Title: string Title: string
SubTitle: string SubTitle: string
Icon: WoxImage Icon: WoxImage
Preview: WoxPreview Preview: WoxPreview
Tails: ResultTail[] Tails: ResultTail[]
ContextData: string ContextData: string
RefreshInterval: number RefreshInterval: number
Actions: ResultAction[] Actions: ResultAction[]
} }
export interface ResultAction { export interface ResultAction {
/** /**
* Result id, should be unique. It's optional, if you don't set it, Wox will assign a random id for you * Result id, should be unique. It's optional, if you don't set it, Wox will assign a random id for you
*/ */
Id?: string Id?: string
Name: string Name: string
Icon?: WoxImage Icon?: WoxImage
/** /**
* If true, Wox will use this action as default action. There can be only one default action in results * If true, Wox will use this action as default action. There can be only one default action in results
* This can be omitted, if you don't set it, Wox will use the first action as default action * This can be omitted, if you don't set it, Wox will use the first action as default action
*/ */
IsDefault?: boolean IsDefault?: boolean
/** /**
* If true, Wox will not hide after user select this result * If true, Wox will not hide after user select this result
*/ */
PreventHideAfterAction?: boolean PreventHideAfterAction?: boolean
Action: (actionContext: ActionContext) => Promise<void> Action: (actionContext: ActionContext) => Promise<void>
/** /**
* Hotkey to trigger this action. E.g. "ctrl+Shift+Space", "Ctrl+1", "Command+K" * Hotkey to trigger this action. E.g. "ctrl+Shift+Space", "Ctrl+1", "Command+K"
* Case insensitive, space insensitive * Case insensitive, space insensitive
* *
* If IsDefault is true, Hotkey will be set to enter key by default * If IsDefault is true, Hotkey will be set to enter key by default
*/ */
Hotkey?: string Hotkey?: string
} }
export interface ActionContext { export interface ActionContext {
ContextData: string ContextData: string
} }
export interface PluginInitParams { export interface PluginInitParams {
API: PublicAPI API: PublicAPI
PluginDirectory: string PluginDirectory: string
} }
export interface ChangeQueryParam { export interface ChangeQueryParam {
QueryType: "input" | "selection" QueryType: "input" | "selection"
QueryText?: string QueryText?: string
QuerySelection?: Selection QuerySelection?: Selection
} }
export interface PublicAPI { export interface PublicAPI {
/** /**
* Change Wox query * Change Wox query
*/ */
ChangeQuery: (ctx: Context, query: ChangeQueryParam) => Promise<void> ChangeQuery: (ctx: Context, query: ChangeQueryParam) => Promise<void>
/** /**
* Hide Wox * Hide Wox
*/ */
HideApp: (ctx: Context) => Promise<void> HideApp: (ctx: Context) => Promise<void>
/** /**
* Show Wox * Show Wox
*/ */
ShowApp: (ctx: Context) => Promise<void> ShowApp: (ctx: Context) => Promise<void>
/** /**
* Notify message * Notify message
*/ */
Notify: (ctx: Context, message: string) => Promise<void> Notify: (ctx: Context, message: string) => Promise<void>
/** /**
* Write log * Write log
*/ */
Log: (ctx: Context, level: "Info" | "Error" | "Debug" | "Warning", msg: string) => Promise<void> Log: (ctx: Context, level: "Info" | "Error" | "Debug" | "Warning", msg: string) => Promise<void>
/** /**
* Get translation of current language * Get translation of current language
*/ */
GetTranslation: (ctx: Context, key: string) => Promise<string> GetTranslation: (ctx: Context, key: string) => Promise<string>
/** /**
* Get customized setting * Get customized setting
* *
* will try to get platform specific setting first, if not found, will try to get global setting * will try to get platform specific setting first, if not found, will try to get global setting
*/ */
GetSetting: (ctx: Context, key: string) => Promise<string> GetSetting: (ctx: Context, key: string) => Promise<string>
/** /**
* Save customized setting * Save customized setting
* *
* @isPlatformSpecific If true, setting will be only saved in current platform. If false, setting will be available in all platforms * @isPlatformSpecific If true, setting will be only saved in current platform. If false, setting will be available in all platforms
*/ */
SaveSetting: (ctx: Context, key: string, value: string, isPlatformSpecific: boolean) => Promise<void> SaveSetting: (ctx: Context, key: string, value: string, isPlatformSpecific: boolean) => Promise<void>
/** /**
* Register setting changed callback * Register setting changed callback
*/ */
OnSettingChanged: (ctx: Context, callback: (key: string, value: string) => void) => Promise<void> OnSettingChanged: (ctx: Context, callback: (key: string, value: string) => void) => Promise<void>
/** /**
* Get dynamic setting definition * Get dynamic setting definition
*/ */
OnGetDynamicSetting: (ctx: Context, callback: (key: string) => PluginSettingDefinitionItem) => Promise<void> OnGetDynamicSetting: (ctx: Context, callback: (key: string) => string) => Promise<void>
/** /**
* Register deep link callback * Register deep link callback
*/ */
OnDeepLink: (ctx: Context, callback: (arguments: MapString) => void) => Promise<void> OnDeepLink: (ctx: Context, callback: (arguments: MapString) => void) => Promise<void>
/** /**
* Register on load event * Register on load event
*/ */
OnUnload: (ctx: Context, callback: () => Promise<void>) => Promise<void> OnUnload: (ctx: Context, callback: () => Promise<void>) => Promise<void>
/** /**
* Register query commands * Register query commands
*/ */
RegisterQueryCommands: (ctx: Context, commands: MetadataCommand[]) => Promise<void> RegisterQueryCommands: (ctx: Context, commands: MetadataCommand[]) => Promise<void>
/** /**
* Chat using LLM * Chat using LLM
*/ */
LLMStream: (ctx: Context, conversations: AI.Conversation[], callback: AI.ChatStreamFunc) => Promise<void> LLMStream: (ctx: Context, conversations: AI.Conversation[], callback: AI.ChatStreamFunc) => Promise<void>
} }
export type WoxImageType = "absolute" | "relative" | "base64" | "svg" | "url" | "emoji" | "lottie" export type WoxImageType = "absolute" | "relative" | "base64" | "svg" | "url" | "emoji" | "lottie"
export interface WoxImage { export interface WoxImage {
ImageType: WoxImageType ImageType: WoxImageType
ImageData: string ImageData: string
} }
export type WoxPreviewType = "markdown" | "text" | "image" | "url" | "file" export type WoxPreviewType = "markdown" | "text" | "image" | "url" | "file"
export interface WoxPreview { export interface WoxPreview {
PreviewType: WoxPreviewType PreviewType: WoxPreviewType
PreviewData: string PreviewData: string
PreviewProperties: Record<string, string> PreviewProperties: Record<string, string>
} }
export declare interface Context { export declare interface Context {
Values: { [key: string]: string } Values: { [key: string]: string }
Get: (key: string) => string | undefined Get: (key: string) => string | undefined
Set: (key: string, value: string) => void Set: (key: string, value: string) => void
Exists: (key: string) => boolean Exists: (key: string) => boolean
} }
export function NewContext(): Context export function NewContext(): Context

View File

@ -1 +1 @@
3.12 3.10

View File

@ -9,6 +9,8 @@ help:
@echo " make build - Build package" @echo " make build - Build package"
@echo " make publish - Publish package to PyPI" @echo " make publish - Publish package to PyPI"
@echo " make install - Install development dependencies" @echo " make install - Install development dependencies"
@echo " make lint - Run linting"
@echo " make format - Run formatting"
clean: clean:
rm -rf dist/ build/ *.egg-info/ rm -rf dist/ build/ *.egg-info/
@ -16,7 +18,14 @@ clean:
install: install:
uv sync --all-extras uv sync --all-extras
build: install clean lint:
uv run ruff check src
uv run mypy src
format:
uv run ruff format src
build: install clean lint format
uv run hatchling build uv run hatchling build
publish: build publish: build

View File

@ -1,33 +1,26 @@
[project] [project]
name = "wox-plugin" name = "wox-plugin"
version = "0.0.30" version = "0.0.45"
description = "Python plugin SDK for Wox launcher" description = "Python plugin SDK for Wox launcher"
authors = [{ name = "Wox Team" }]
dependencies = ["pydantic>=2.0.0"]
requires-python = ">=3.8"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10"
license = { text = "GPL-3.0" } license = { text = "GPL-3.0" }
authors = [{ name = "Wox Team" }]
dependencies = []
[project.urls] [project.urls]
Homepage = "https://github.com/Wox-launcher/Wox" Homepage = "https://github.com/Wox-launcher/Wox"
Repository = "https://github.com/Wox-launcher/Wox" Repository = "https://github.com/Wox-launcher/Wox"
[project.optional-dependencies] [project.optional-dependencies]
dev = ["black>=23.0.0", "hatchling>=1.18.0", "twine>=4.0.0"] dev = ["hatchling", "twine", "ruff", "mypy"]
[build-system] [build-system]
requires = ["hatchling"] requires = ["hatchling"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[tool.black]
line-length = 88
target-version = ['py38']
[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.setuptools] [tool.setuptools]
package-data = { "wox_plugin" = ["py.typed"] } package-data = { "wox_plugin" = ["py.typed"] }
[tool.ruff]
line-length = 140

View File

@ -6,47 +6,43 @@ This package provides the SDK for developing Wox plugins in Python.
from typing import List from typing import List
from .plugin import Plugin, BasePlugin, PluginInitParams from .plugin import Plugin, PluginInitParams
from .api import PublicAPI from .api import PublicAPI, ChatStreamCallback
from .models.context import Context from .models.context import Context
from .models.query import Query, QueryEnv, Selection from .models.query import (
Query,
QueryEnv,
Selection,
ChangeQueryParam,
QueryType,
SelectionType,
MetadataCommand,
)
from .models.result import ( from .models.result import (
Result, Result,
WoxImage,
WoxPreview,
ResultTail, ResultTail,
ResultAction, ResultAction,
ActionContext, ActionContext,
RefreshableResult, RefreshableResult,
)
from .models.settings import (
PluginSettingDefinitionItem,
PluginSettingDefinitionValue,
PluginSettingValueStyle,
MetadataCommand,
)
from .types import (
Platform,
SelectionType,
QueryType,
WoxImageType,
WoxPreviewType,
ResultTailType, ResultTailType,
)
from .models.ai import (
AIModel,
Conversation,
ConversationRole, ConversationRole,
ChatStreamDataType, ChatStreamDataType,
PluginSettingDefinitionType,
) )
from .utils.helpers import new_base64_wox_image from .models.image import WoxImage, WoxImageType
from .exceptions import WoxPluginError, InvalidQueryError, PluginInitError, APIError from .models.preview import WoxPreview, WoxPreviewType, WoxPreviewScrollPosition
__version__: str = "0.1.0"
__all__: List[str] = [ __all__: List[str] = [
# Plugin # Plugin
"Plugin", "Plugin",
"BasePlugin",
"PluginInitParams", "PluginInitParams",
# API # API
"PublicAPI", "PublicAPI",
"ChatStreamCallback",
# Models # Models
"Context", "Context",
"Query", "Query",
@ -59,25 +55,33 @@ __all__: List[str] = [
"ResultAction", "ResultAction",
"ActionContext", "ActionContext",
"RefreshableResult", "RefreshableResult",
"PluginSettingDefinitionItem",
"PluginSettingDefinitionValue",
"PluginSettingValueStyle",
"MetadataCommand", "MetadataCommand",
# Types "PluginSettingDefinitionItem",
"Platform", "PluginSettingValueStyle",
"SelectionType", # AI
"QueryType", "AIModel",
"WoxImageType", "Conversation",
"WoxPreviewType",
"ResultTailType",
"ConversationRole", "ConversationRole",
"ChatStreamDataType", "ChatStreamDataType",
"PluginSettingDefinitionType", "user_message",
# Utils "ai_message",
"new_base64_wox_image", # Query
"ChangeQueryParam",
"QueryType",
"Selection",
"SelectionType",
# Exceptions # Exceptions
"WoxPluginError", "WoxPluginError",
"InvalidQueryError", "InvalidQueryError",
"PluginInitError", "PluginInitError",
"APIError", "APIError",
# Image
"WoxImage",
"WoxImageType",
# Preview
"WoxPreview",
"WoxPreviewType",
"WoxPreviewScrollPosition",
# Result
"ResultTailType",
] ]

View File

@ -1,17 +1,16 @@
from typing import Protocol, List, Callable from typing import Protocol, Callable, Dict, List
from .types import MapString, ChatStreamFunc from .models.query import MetadataCommand
from .models.context import Context from .models.context import Context
from .models.query import ChangeQueryParam from .models.query import ChangeQueryParam
from .models.settings import MetadataCommand, PluginSettingDefinitionItem from .models.ai import AIModel, Conversation, ChatStreamCallback
from .models.result import Conversation
class PublicAPI(Protocol): class PublicAPI(Protocol):
"""Public API interface for Wox plugins""" """Public API interface for Wox plugins"""
async def change_query(self, ctx: Context, query: ChangeQueryParam) -> None: async def change_query(self, ctx: Context, query: ChangeQueryParam) -> None:
"""Change the current query""" """Change the current query in Wox"""
... ...
async def hide_app(self, ctx: Context) -> None: async def hide_app(self, ctx: Context) -> None:
@ -23,11 +22,11 @@ class PublicAPI(Protocol):
... ...
async def notify(self, ctx: Context, message: str) -> None: async def notify(self, ctx: Context, message: str) -> None:
"""Show a notification""" """Show a notification message"""
... ...
async def log(self, ctx: Context, level: str, msg: str) -> None: async def log(self, ctx: Context, level: str, msg: str) -> None:
"""Log a message""" """Write log message"""
... ...
async def get_translation(self, ctx: Context, key: str) -> str: async def get_translation(self, ctx: Context, key: str) -> str:
@ -38,27 +37,19 @@ class PublicAPI(Protocol):
"""Get setting value""" """Get setting value"""
... ...
async def save_setting( async def save_setting(self, ctx: Context, key: str, value: str, is_platform_specific: bool) -> None:
self, ctx: Context, key: str, value: str, is_platform_specific: bool
) -> None:
"""Save setting value""" """Save setting value"""
... ...
async def on_setting_changed( async def on_setting_changed(self, ctx: Context, callback: Callable[[str, str], None]) -> None:
self, ctx: Context, callback: Callable[[str, str], None]
) -> None:
"""Register setting change callback""" """Register setting change callback"""
... ...
async def on_get_dynamic_setting( async def on_get_dynamic_setting(self, ctx: Context, callback: Callable[[str], str]) -> None:
self, ctx: Context, callback: Callable[[str], PluginSettingDefinitionItem]
) -> None:
"""Register dynamic setting callback""" """Register dynamic setting callback"""
... ...
async def on_deep_link( async def on_deep_link(self, ctx: Context, callback: Callable[[Dict[str, str]], None]) -> None:
self, ctx: Context, callback: Callable[[MapString], None]
) -> None:
"""Register deep link callback""" """Register deep link callback"""
... ...
@ -66,14 +57,27 @@ class PublicAPI(Protocol):
"""Register unload callback""" """Register unload callback"""
... ...
async def register_query_commands( async def register_query_commands(self, ctx: Context, commands: List[MetadataCommand]) -> None:
self, ctx: Context, commands: List[MetadataCommand]
) -> None:
"""Register query commands""" """Register query commands"""
... ...
async def llm_stream( async def ai_chat_stream(
self, ctx: Context, conversations: List[Conversation], callback: ChatStreamFunc self,
ctx: Context,
model: AIModel,
conversations: List[Conversation],
callback: ChatStreamCallback,
) -> None: ) -> None:
"""Stream LLM responses""" """
Start an AI chat stream.
Args:
ctx: Context
model: AI model to use
conversations: Conversation history
callback: Stream callback function to receive AI responses
The callback takes two parameters:
- stream_type: ChatStreamDataType, indicates the stream status
- data: str, the stream content
"""
... ...

View File

@ -1,22 +0,0 @@
class WoxPluginError(Exception):
"""Base exception for Wox plugin errors"""
pass
class InvalidQueryError(WoxPluginError):
"""Raised when query is invalid"""
pass
class PluginInitError(WoxPluginError):
"""Raised when plugin initialization fails"""
pass
class APIError(WoxPluginError):
"""Raised when API call fails"""
pass

View File

@ -0,0 +1,98 @@
from enum import Enum
from typing import List, Callable, Optional
import time
from dataclasses import dataclass, field
import json
class ConversationRole(str, Enum):
"""Role in the conversation"""
USER = "user"
AI = "ai"
class ChatStreamDataType(str, Enum):
"""Type of chat stream data"""
STREAMING = "streaming" # Currently streaming
FINISHED = "finished" # Stream completed
ERROR = "error" # Error occurred
ChatStreamCallback = Callable[[ChatStreamDataType, str], None]
@dataclass
class AIModel:
"""AI model definition"""
name: str
provider: str
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Name": self.name,
"Provider": self.provider,
}
)
@classmethod
def from_json(cls, json_str: str) -> "AIModel":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
name=data.get("Name", ""),
provider=data.get("Provider", ""),
)
@dataclass
class Conversation:
"""Conversation content"""
role: ConversationRole
text: str
images: List[bytes] = field(default_factory=list) # PNG format image data
timestamp: int = field(default_factory=lambda: int(time.time() * 1000))
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Role": self.role,
"Text": self.text,
"Images": [image.hex() for image in self.images] if self.images else [],
"Timestamp": self.timestamp,
}
)
@classmethod
def from_json(cls, json_str: str) -> "Conversation":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
role=ConversationRole(data.get("Role", ConversationRole.USER)),
text=data.get("Text", ""),
images=[bytes.fromhex(img) for img in data.get("Images", [])] if data.get("Images") else [],
timestamp=data.get("Timestamp", int(time.time() * 1000)),
)
@classmethod
def new_user_message(cls, text: str, images: Optional[List[bytes]] = None) -> "Conversation":
"""Create a user message"""
return cls(
role=ConversationRole.USER,
text=text,
images=images if images is not None else [],
)
@classmethod
def new_ai_message(cls, text: str) -> "Conversation":
"""Create an AI message"""
return cls(
role=ConversationRole.AI,
text=text,
)

View File

@ -1,27 +1,45 @@
import uuid import uuid
from dataclasses import dataclass, field
from typing import Dict from typing import Dict
from pydantic import BaseModel import json
class Context(BaseModel): @dataclass
class Context:
""" """
Context object that carries request-scoped values across the plugin execution Context object that carries request-scoped values across the plugin execution
""" """
Values: Dict[str, str] values: Dict[str, str] = field(default_factory=dict)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Values": self.values,
}
)
@classmethod
def from_json(cls, json_str: str) -> "Context":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
values=data.get("Values", {}),
)
def get_trace_id(self) -> str: def get_trace_id(self) -> str:
"""Get the trace ID from context""" """Get the trace ID from context"""
return self.Values["traceId"] return self.values.get("TraceId", "")
@staticmethod @classmethod
def new() -> "Context": def new(cls) -> "Context":
"""Create a new context with a random trace ID""" """Create a new context with a random trace ID"""
return Context(Values={"traceId": str(uuid.uuid4())}) return cls(values={"TraceId": str(uuid.uuid4())})
@staticmethod @classmethod
def new_with_value(key: str, value: str) -> "Context": def new_with_value(cls, key: str, value: str) -> "Context":
"""Create a new context with a specific key-value pair""" """Create a new context with a specific key-value pair"""
ctx = Context.new() ctx = cls.new()
ctx.Values[key] = value ctx.values[key] = value
return ctx return ctx

View File

@ -0,0 +1,86 @@
from dataclasses import dataclass, field
from enum import Enum
import json
class WoxImageType(str, Enum):
"""Image type enum for Wox"""
ABSOLUTE = "absolute"
RELATIVE = "relative"
BASE64 = "base64"
SVG = "svg"
LOTTIE = "lottie" # only support lottie json data
EMOJI = "emoji"
URL = "url"
THEME = "theme"
@dataclass
class WoxImage:
"""Image model for Wox"""
image_type: WoxImageType = field(default=WoxImageType.ABSOLUTE)
image_data: str = field(default="")
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Data": self.image_data,
"Type": self.image_type,
}
)
@classmethod
def from_json(cls, json_str: str) -> "WoxImage":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
image_type=WoxImageType(data.get("Type", WoxImageType.ABSOLUTE)),
image_data=data.get("Data", ""),
)
@classmethod
def new_base64(cls, data: str) -> "WoxImage":
"""Create a new base64 image"""
return cls(image_type=WoxImageType.BASE64, image_data=data)
@classmethod
def new_svg(cls, data: str) -> "WoxImage":
"""Create a new svg image"""
return cls(image_type=WoxImageType.SVG, image_data=data)
@classmethod
def new_lottie(cls, data: str) -> "WoxImage":
"""Create a new lottie image"""
return cls(image_type=WoxImageType.LOTTIE, image_data=data)
@classmethod
def new_emoji(cls, data: str) -> "WoxImage":
"""Create a new emoji image"""
return cls(image_type=WoxImageType.EMOJI, image_data=data)
@classmethod
def new_url(cls, data: str) -> "WoxImage":
"""Create a new url image"""
return cls(image_type=WoxImageType.URL, image_data=data)
@classmethod
def new_absolute(cls, data: str) -> "WoxImage":
"""Create a new absolute image"""
return cls(image_type=WoxImageType.ABSOLUTE, image_data=data)
@classmethod
def new_relative(cls, data: str) -> "WoxImage":
"""Create a new relative image"""
return cls(image_type=WoxImageType.RELATIVE, image_data=data)
@classmethod
def new_theme(cls, data: str) -> "WoxImage":
"""Create a new theme image"""
return cls(image_type=WoxImageType.THEME, image_data=data)
def __str__(self) -> str:
"""Convert image to string"""
return f"{self.image_type}:{self.image_data}"

View File

@ -0,0 +1,53 @@
from typing import Dict
from dataclasses import dataclass, field
from enum import Enum
import json
class WoxPreviewType(str, Enum):
"""Preview type enum for Wox"""
MARKDOWN = "markdown"
TEXT = "text"
IMAGE = "image" # when type is image, data should be WoxImage.String()
URL = "url"
FILE = "file" # when type is file(can be *.md, *.jpg, *.pdf and so on), data should be url/filepath
REMOTE = "remote" # when type is remote, data should be url to load WoxPreview
class WoxPreviewScrollPosition(str, Enum):
"""Preview scroll position enum for Wox"""
BOTTOM = "bottom" # scroll to bottom after preview first show
@dataclass
class WoxPreview:
"""Preview model for Wox results"""
preview_type: WoxPreviewType = field(default=WoxPreviewType.TEXT)
preview_data: str = field(default="")
preview_properties: Dict[str, str] = field(default_factory=dict)
scroll_position: WoxPreviewScrollPosition = field(default=WoxPreviewScrollPosition.BOTTOM)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"PreviewType": self.preview_type,
"PreviewData": self.preview_data,
"PreviewProperties": self.preview_properties,
"ScrollPosition": self.scroll_position,
}
)
@classmethod
def from_json(cls, json_str: str) -> "WoxPreview":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
preview_type=WoxPreviewType(data.get("PreviewType", WoxPreviewType.TEXT)),
preview_data=data.get("PreviewData", ""),
preview_properties=data.get("PreviewProperties", {}),
scroll_position=WoxPreviewScrollPosition(data.get("ScrollPosition", WoxPreviewScrollPosition.BOTTOM)),
)

View File

@ -1,48 +1,212 @@
from typing import Optional, List from typing import List
from pydantic import BaseModel from dataclasses import dataclass, field
from enum import Enum
from ..types import SelectionType, QueryType import json
class Selection(BaseModel): class SelectionType(str, Enum):
"""Selection type enum"""
TEXT = "text"
FILE = "file"
class QueryType(str, Enum):
"""Query type enum"""
INPUT = "input"
SELECTION = "selection"
@dataclass
class MetadataCommand:
"""Metadata command"""
command: str
description: str
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Command": self.command,
"Description": self.description,
}
)
@classmethod
def from_json(cls, json_str: str) -> "MetadataCommand":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
command=data.get("Command", ""),
description=data.get("Description", ""),
)
@dataclass
class Selection:
"""Selection model representing text or file selection""" """Selection model representing text or file selection"""
Type: SelectionType type: SelectionType = field(default=SelectionType.TEXT)
Text: Optional[str] = None text: str = field(default="")
FilePaths: Optional[List[str]] = None file_paths: List[str] = field(default_factory=list)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Type": self.type,
"Text": self.text,
"FilePaths": self.file_paths,
}
)
@classmethod
def from_json(cls, json_str: str) -> "Selection":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
if data.get("Type", "") == "":
data["Type"] = SelectionType.TEXT
return cls(
type=SelectionType(data.get("Type", SelectionType.TEXT)),
text=data.get("Text", ""),
file_paths=data.get("FilePaths", []),
)
def __str__(self) -> str:
"""Convert selection to string"""
if self.type == SelectionType.TEXT and self.text:
return self.text
elif self.type == SelectionType.FILE and self.file_paths:
return ",".join(self.file_paths)
return ""
class QueryEnv(BaseModel): @dataclass
class QueryEnv:
""" """
Query environment information Query environment information
""" """
ActiveWindowTitle: str active_window_title: str = field(default="")
"""Active window title when user query""" """Active window title when user query"""
ActiveWindowPid: int active_window_pid: int = field(default=0)
"""Active window pid when user query, 0 if not available""" """Active window pid when user query, 0 if not available"""
ActiveBrowserUrl: str active_browser_url: str = field(default="")
""" """
Active browser url when user query Active browser url when user query
Only available when active window is browser and https://github.com/Wox-launcher/Wox.Chrome.Extension is installed Only available when active window is browser and https://github.com/Wox-launcher/Wox.Chrome.Extension is installed
""" """
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"ActiveWindowTitle": self.active_window_title,
"ActiveWindowPid": self.active_window_pid,
"ActiveBrowserUrl": self.active_browser_url,
}
)
class Query(BaseModel): @classmethod
def from_json(cls, json_str: str) -> "QueryEnv":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
active_window_title=data.get("ActiveWindowTitle", ""),
active_window_pid=data.get("ActiveWindowPid", 0),
active_browser_url=data.get("ActiveBrowserUrl", ""),
)
@dataclass
class Query:
""" """
Query model representing a user query Query model representing a user query
""" """
Type: QueryType type: QueryType
RawQuery: str raw_query: str
TriggerKeyword: Optional[str] selection: Selection
Command: Optional[str] env: QueryEnv
Search: str trigger_keyword: str = field(default="")
Selection: Selection command: str = field(default="")
Env: QueryEnv search: str = field(default="")
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Type": self.type,
"RawQuery": self.raw_query,
"Selection": json.loads(self.selection.to_json()),
"Env": json.loads(self.env.to_json()),
"TriggerKeyword": self.trigger_keyword,
"Command": self.command,
"Search": self.search,
}
)
@classmethod
def from_json(cls, json_str: str) -> "Query":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
if data.get("Type", "") == "":
data["Type"] = QueryType.INPUT
return cls(
type=QueryType(data.get("Type", QueryType.INPUT)),
raw_query=data.get("RawQuery", ""),
selection=Selection.from_json(data.get("Selection", Selection().to_json())),
env=QueryEnv.from_json(data.get("Env", QueryEnv().to_json())),
trigger_keyword=data.get("TriggerKeyword", ""),
command=data.get("Command", ""),
search=data.get("Search", ""),
)
def is_global_query(self) -> bool: def is_global_query(self) -> bool:
"""Check if this is a global query without trigger keyword""" """Check if this is a global query without trigger keyword"""
return self.Type == QueryType.INPUT and not self.TriggerKeyword return self.type == QueryType.INPUT and not self.trigger_keyword
def __str__(self) -> str:
"""Convert query to string"""
if self.type == QueryType.INPUT:
return self.raw_query
elif self.type == QueryType.SELECTION:
return str(self.selection)
return ""
@dataclass
class ChangeQueryParam:
"""Change query parameter"""
query_type: QueryType
query_text: str = field(default="")
query_selection: Selection = field(default_factory=Selection)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
data = {
"QueryType": self.query_type,
"QueryText": self.query_text,
}
if self.query_selection:
data["QuerySelection"] = json.loads(self.query_selection.to_json())
return json.dumps(data)
@classmethod
def from_json(cls, json_str: str) -> "ChangeQueryParam":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
query_type=QueryType(data.get("QueryType", QueryType.INPUT)),
query_text=data.get("QueryText", ""),
query_selection=Selection.from_json(data.get("QuerySelection", Selection().to_json())),
)

View File

@ -1,87 +1,223 @@
from typing import Optional, List, Dict, Callable, Awaitable from typing import List, Callable, Awaitable, Optional
from pydantic import BaseModel from dataclasses import dataclass, field
from enum import Enum
from ..types import WoxImageType, WoxPreviewType, ResultTailType import json
from .image import WoxImage
from .preview import WoxPreview
class WoxImage(BaseModel): class ResultTailType(str, Enum):
"""Image model for Wox""" """Result tail type enum for Wox"""
ImageType: WoxImageType TEXT = "text" # string type
ImageData: str IMAGE = "image" # WoxImage type
class WoxPreview(BaseModel): @dataclass
"""Preview model for Wox results""" class ResultTail:
PreviewType: WoxPreviewType
PreviewData: str
PreviewProperties: Dict[str, str]
class ResultTail(BaseModel):
"""Tail model for Wox results""" """Tail model for Wox results"""
Type: ResultTailType type: ResultTailType = field(default=ResultTailType.TEXT)
Text: Optional[str] = None text: str = field(default="")
Image: Optional[WoxImage] = None image: WoxImage = field(default_factory=WoxImage)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Type": self.type,
"Text": self.text,
"Image": json.loads(self.image.to_json()),
}
)
@classmethod
def from_json(cls, json_str: str) -> "ResultTail":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
image = WoxImage()
if "Image" in data:
image = WoxImage.from_json(json.dumps(data["Image"]))
return cls(
type=ResultTailType(data.get("Type", ResultTailType.TEXT)),
text=data.get("Text", ""),
image=image,
)
class ActionContext(BaseModel): @dataclass
class ActionContext:
"""Context for result actions""" """Context for result actions"""
ContextData: str context_data: str
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"ContextData": self.context_data,
}
)
@classmethod
def from_json(cls, json_str: str) -> "ActionContext":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
context_data=data.get("ContextData", ""),
)
class ResultAction(BaseModel): @dataclass
class ResultAction:
"""Action model for Wox results""" """Action model for Wox results"""
Name: str name: str
Action: Callable[[ActionContext], Awaitable[None]] action: Optional[Callable[[ActionContext], Awaitable[None]]] = None
Id: Optional[str] = None id: str = field(default="")
Icon: Optional[WoxImage] = None icon: WoxImage = field(default_factory=WoxImage)
IsDefault: Optional[bool] = None is_default: bool = field(default=False)
PreventHideAfterAction: Optional[bool] = None prevent_hide_after_action: bool = field(default=False)
Hotkey: Optional[str] = None hotkey: str = field(default="")
class Config: def to_json(self) -> str:
arbitrary_types_allowed = True """Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Name": self.name,
"Id": self.id,
"IsDefault": self.is_default,
"PreventHideAfterAction": self.prevent_hide_after_action,
"Hotkey": self.hotkey,
"Icon": json.loads(self.icon.to_json()),
}
)
@classmethod
def from_json(cls, json_str: str) -> "ResultAction":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
name=data.get("Name", ""),
id=data.get("Id", ""),
icon=WoxImage.from_json(json.dumps(data.get("Icon", {}))),
is_default=data.get("IsDefault", False),
prevent_hide_after_action=data.get("PreventHideAfterAction", False),
hotkey=data.get("Hotkey", ""),
)
class Result(BaseModel): @dataclass
class Result:
"""Result model for Wox""" """Result model for Wox"""
Title: str title: str
Icon: WoxImage icon: WoxImage
Id: Optional[str] = None id: str = field(default="")
SubTitle: Optional[str] = None sub_title: str = field(default="")
Preview: Optional[WoxPreview] = None preview: WoxPreview = field(default_factory=WoxPreview)
Score: Optional[float] = None score: float = field(default=0.0)
Group: Optional[str] = None group: str = field(default="")
GroupScore: Optional[float] = None group_score: float = field(default=0.0)
Tails: Optional[List[ResultTail]] = None tails: List[ResultTail] = field(default_factory=list)
ContextData: Optional[str] = None context_data: str = field(default="")
Actions: Optional[List[ResultAction]] = None actions: List[ResultAction] = field(default_factory=list)
RefreshInterval: Optional[int] = None refresh_interval: int = field(default=0)
OnRefresh: Optional[ on_refresh: Optional[Callable[["RefreshableResult"], Awaitable["RefreshableResult"]]] = None
Callable[["RefreshableResult"], Awaitable["RefreshableResult"]]
] = None
class Config: def to_json(self) -> str:
arbitrary_types_allowed = True """Convert to JSON string with camelCase naming"""
data = {
"Title": self.title,
"Icon": json.loads(self.icon.to_json()),
"Id": self.id,
"SubTitle": self.sub_title,
"Score": self.score,
"Group": self.group,
"GroupScore": self.group_score,
"ContextData": self.context_data,
"RefreshInterval": self.refresh_interval,
}
if self.preview:
data["Preview"] = json.loads(self.preview.to_json())
if self.tails:
data["Tails"] = [json.loads(tail.to_json()) for tail in self.tails]
if self.actions:
data["Actions"] = [json.loads(action.to_json()) for action in self.actions]
return json.dumps(data)
@classmethod
def from_json(cls, json_str: str) -> "Result":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
preview = WoxPreview.from_json(json.dumps(data["Preview"]))
tails = []
if "Tails" in data:
tails = [ResultTail.from_json(json.dumps(tail)) for tail in data["Tails"]]
actions = []
if "Actions" in data:
actions = [ResultAction.from_json(json.dumps(action)) for action in data["Actions"]]
return cls(
title=data.get("Title", ""),
icon=WoxImage.from_json(json.dumps(data.get("Icon", {}))),
id=data.get("Id", ""),
sub_title=data.get("SubTitle", ""),
preview=preview,
score=data.get("Score", 0.0),
group=data.get("Group", ""),
group_score=data.get("GroupScore", 0.0),
tails=tails,
context_data=data.get("ContextData", ""),
actions=actions,
refresh_interval=data.get("RefreshInterval", 0),
)
class RefreshableResult(BaseModel): @dataclass
class RefreshableResult:
"""Result that can be refreshed periodically""" """Result that can be refreshed periodically"""
Title: str title: str
SubTitle: str sub_title: str
Icon: WoxImage icon: WoxImage
Preview: WoxPreview preview: WoxPreview
Tails: List[ResultTail] tails: List[ResultTail] = field(default_factory=list)
ContextData: str context_data: str = field(default="")
RefreshInterval: int refresh_interval: int = field(default=0)
Actions: List[ResultAction] actions: List[ResultAction] = field(default_factory=list)
def to_json(self) -> str:
"""Convert to JSON string with camelCase naming"""
return json.dumps(
{
"Title": self.title,
"SubTitle": self.sub_title,
"Icon": json.loads(self.icon.to_json()),
"Preview": json.loads(self.preview.to_json()),
"Tails": [json.loads(tail.to_json()) for tail in self.tails],
"ContextData": self.context_data,
"RefreshInterval": self.refresh_interval,
"Actions": [json.loads(action.to_json()) for action in self.actions],
}
)
@classmethod
def from_json(cls, json_str: str) -> "RefreshableResult":
"""Create from JSON string with camelCase naming"""
data = json.loads(json_str)
return cls(
title=data["Title"],
sub_title=data["SubTitle"],
icon=WoxImage.from_json(json.dumps(data.get("Icon", {}))),
preview=WoxPreview.from_json(json.dumps(data.get("Preview", {}))),
tails=[ResultTail.from_json(json.dumps(tail)) for tail in data.get("Tails", [])],
context_data=data.get("ContextData", ""),
refresh_interval=data.get("RefreshInterval", 0),
actions=[ResultAction.from_json(json.dumps(action)) for action in data["Actions"]],
)
def __await__(self): def __await__(self):
# Make RefreshableResult awaitable by returning itself # Make RefreshableResult awaitable by returning itself

View File

@ -1,48 +0,0 @@
from typing import List, Callable
from pydantic import BaseModel
from ..types import Platform, PluginSettingDefinitionType
from .context import Context
class PluginSettingValueStyle(BaseModel):
"""Style configuration for plugin settings"""
PaddingLeft: int
PaddingTop: int
PaddingRight: int
PaddingBottom: int
Width: int
LabelWidth: int
class PluginSettingDefinitionValue(BaseModel):
"""Base class for plugin setting definition values"""
def get_key(self) -> str:
"""Get the key of the setting"""
raise NotImplementedError
def get_default_value(self) -> str:
"""Get the default value of the setting"""
raise NotImplementedError
def translate(self, translator: Callable[[Context, str], str]) -> None:
"""Translate the setting using the provided translator"""
raise NotImplementedError
class PluginSettingDefinitionItem(BaseModel):
"""Plugin setting definition item"""
Type: PluginSettingDefinitionType
Value: PluginSettingDefinitionValue
DisabledInPlatforms: List[Platform]
IsPlatformSpecific: bool
class MetadataCommand(BaseModel):
"""Metadata for plugin commands"""
Command: str
Description: str

View File

@ -1,4 +1,5 @@
from typing import Protocol, List from typing import Protocol, List
from dataclasses import dataclass
from .models.context import Context from .models.context import Context
from .models.query import Query from .models.query import Query
@ -6,11 +7,12 @@ from .models.result import Result
from .api import PublicAPI from .api import PublicAPI
@dataclass
class PluginInitParams: class PluginInitParams:
"""Parameters for plugin initialization""" """Parameters for plugin initialization"""
API: PublicAPI api: PublicAPI
PluginDirectory: str plugin_directory: str
class Plugin(Protocol): class Plugin(Protocol):
@ -23,20 +25,3 @@ class Plugin(Protocol):
async def query(self, ctx: Context, query: Query) -> List[Result]: async def query(self, ctx: Context, query: Query) -> List[Result]:
"""Handle user query""" """Handle user query"""
... ...
class BasePlugin:
"""Base implementation of Plugin with common functionality"""
def __init__(self):
self.api: PublicAPI = None
self.plugin_dir: str = None
async def init(self, ctx: Context, init_params: PluginInitParams) -> None:
"""Initialize the plugin with API and plugin directory"""
self.api = init_params.API
self.plugin_dir = init_params.PluginDirectory
async def query(self, ctx: Context, query: Query) -> List[Result]:
"""Handle user query - must be implemented by subclasses"""
raise NotImplementedError("Subclasses must implement query method")

View File

@ -1,70 +0,0 @@
from enum import StrEnum
from typing import Dict, Callable
# Basic types
MapString = Dict[str, str]
class Platform(StrEnum):
WINDOWS = "windows"
DARWIN = "darwin"
LINUX = "linux"
class SelectionType(StrEnum):
TEXT = "text"
FILE = "file"
class QueryType(StrEnum):
INPUT = "input"
SELECTION = "selection"
class WoxImageType(StrEnum):
ABSOLUTE = "absolute"
RELATIVE = "relative"
BASE64 = "base64"
SVG = "svg"
URL = "url"
EMOJI = "emoji"
LOTTIE = "lottie"
class WoxPreviewType(StrEnum):
MARKDOWN = "markdown"
TEXT = "text"
IMAGE = "image"
URL = "url"
FILE = "file"
class ResultTailType(StrEnum):
TEXT = "text"
IMAGE = "image"
class ConversationRole(StrEnum):
USER = "user"
SYSTEM = "system"
class ChatStreamDataType(StrEnum):
STREAMING = "streaming"
FINISHED = "finished"
ERROR = "error"
class PluginSettingDefinitionType(StrEnum):
HEAD = "head"
TEXTBOX = "textbox"
CHECKBOX = "checkbox"
SELECT = "select"
LABEL = "label"
NEWLINE = "newline"
TABLE = "table"
DYNAMIC = "dynamic"
# Type aliases
ChatStreamFunc = Callable[[ChatStreamDataType, str], None]

View File

@ -1,7 +0,0 @@
from ..models.result import WoxImage
from ..types import WoxImageType
def new_base64_wox_image(image_data: str) -> WoxImage:
"""Create a new WoxImage with BASE64 type"""
return WoxImage(ImageType=WoxImageType.BASE64, ImageData=image_data)

View File

@ -1,17 +1,5 @@
version = 1 version = 1
requires-python = ">=3.8" requires-python = ">=3.10"
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
]
[[package]] [[package]]
name = "backports-tarfile" name = "backports-tarfile"
@ -22,44 +10,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181 }, { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181 },
] ]
[[package]]
name = "black"
version = "24.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "mypy-extensions" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "platformdirs" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/04/b0/46fb0d4e00372f4a86a6f8efa3cb193c9f64863615e39010b1477e010578/black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", size = 644810 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/47/6e/74e29edf1fba3887ed7066930a87f698ffdcd52c5dbc263eabb06061672d/black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", size = 1632092 },
{ url = "https://files.pythonhosted.org/packages/ab/49/575cb6c3faee690b05c9d11ee2e8dba8fbd6d6c134496e644c1feb1b47da/black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", size = 1457529 },
{ url = "https://files.pythonhosted.org/packages/7a/b4/d34099e95c437b53d01c4aa37cf93944b233066eb034ccf7897fa4e5f286/black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", size = 1757443 },
{ url = "https://files.pythonhosted.org/packages/87/a0/6d2e4175ef364b8c4b64f8441ba041ed65c63ea1db2720d61494ac711c15/black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", size = 1418012 },
{ url = "https://files.pythonhosted.org/packages/08/a6/0a3aa89de9c283556146dc6dbda20cd63a9c94160a6fbdebaf0918e4a3e1/black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1", size = 1615080 },
{ url = "https://files.pythonhosted.org/packages/db/94/b803d810e14588bb297e565821a947c108390a079e21dbdcb9ab6956cd7a/black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", size = 1438143 },
{ url = "https://files.pythonhosted.org/packages/a5/b5/f485e1bbe31f768e2e5210f52ea3f432256201289fd1a3c0afda693776b0/black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", size = 1738774 },
{ url = "https://files.pythonhosted.org/packages/a8/69/a000fc3736f89d1bdc7f4a879f8aaf516fb03613bb51a0154070383d95d9/black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", size = 1427503 },
{ url = "https://files.pythonhosted.org/packages/a2/a8/05fb14195cfef32b7c8d4585a44b7499c2a4b205e1662c427b941ed87054/black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", size = 1646132 },
{ url = "https://files.pythonhosted.org/packages/41/77/8d9ce42673e5cb9988f6df73c1c5c1d4e9e788053cccd7f5fb14ef100982/black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", size = 1448665 },
{ url = "https://files.pythonhosted.org/packages/cc/94/eff1ddad2ce1d3cc26c162b3693043c6b6b575f538f602f26fe846dfdc75/black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", size = 1762458 },
{ url = "https://files.pythonhosted.org/packages/28/ea/18b8d86a9ca19a6942e4e16759b2fa5fc02bbc0eb33c1b866fcd387640ab/black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", size = 1436109 },
{ url = "https://files.pythonhosted.org/packages/9f/d4/ae03761ddecc1a37d7e743b89cccbcf3317479ff4b88cfd8818079f890d0/black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", size = 1617322 },
{ url = "https://files.pythonhosted.org/packages/14/4b/4dfe67eed7f9b1ddca2ec8e4418ea74f0d1dc84d36ea874d618ffa1af7d4/black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", size = 1442108 },
{ url = "https://files.pythonhosted.org/packages/97/14/95b3f91f857034686cae0e73006b8391d76a8142d339b42970eaaf0416ea/black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", size = 1745786 },
{ url = "https://files.pythonhosted.org/packages/95/54/68b8883c8aa258a6dde958cd5bdfada8382bec47c5162f4a01e66d839af1/black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", size = 1426754 },
{ url = "https://files.pythonhosted.org/packages/13/b2/b3f24fdbb46f0e7ef6238e131f13572ee8279b70f237f221dd168a9dba1a/black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", size = 1631706 },
{ url = "https://files.pythonhosted.org/packages/d9/35/31010981e4a05202a84a3116423970fd1a59d2eda4ac0b3570fbb7029ddc/black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", size = 1457429 },
{ url = "https://files.pythonhosted.org/packages/27/25/3f706b4f044dd569a20a4835c3b733dedea38d83d2ee0beb8178a6d44945/black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", size = 1756488 },
{ url = "https://files.pythonhosted.org/packages/63/72/79375cd8277cbf1c5670914e6bd4c1b15dea2c8f8e906dc21c448d0535f0/black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", size = 1417721 },
{ url = "https://files.pythonhosted.org/packages/27/1e/83fa8a787180e1632c3d831f7e58994d7aaf23a0961320d21e84f922f919/black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", size = 206504 },
]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2024.12.14" version = "2024.12.14"
@ -108,19 +58,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
{ url = "https://files.pythonhosted.org/packages/c2/5b/f1523dd545f92f7df468e5f653ffa4df30ac222f3c884e51e139878f1cb5/cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", size = 425932 },
{ url = "https://files.pythonhosted.org/packages/53/93/7e547ab4105969cc8c93b38a667b82a835dd2cc78f3a7dad6130cfd41e1d/cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", size = 448585 },
{ url = "https://files.pythonhosted.org/packages/56/c4/a308f2c332006206bb511de219efeff090e9d63529ba0a77aae72e82248b/cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", size = 456268 },
{ url = "https://files.pythonhosted.org/packages/ca/5b/b63681518265f2f4060d2b60755c1c77ec89e5e045fc3773b72735ddaad5/cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", size = 436592 },
{ url = "https://files.pythonhosted.org/packages/bb/19/b51af9f4a4faa4a8ac5a0e5d5c2522dcd9703d07fac69da34a36c4d960d3/cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", size = 446512 },
{ url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 },
{ url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200 },
{ url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565 },
{ url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635 },
{ url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218 },
{ url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486 },
{ url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911 },
{ url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632 },
] ]
[[package]] [[package]]
@ -189,60 +126,9 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 },
{ url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 },
{ url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 },
{ url = "https://files.pythonhosted.org/packages/86/f4/ccab93e631e7293cca82f9f7ba39783c967f823a0000df2d8dd743cad74f/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", size = 193961 },
{ url = "https://files.pythonhosted.org/packages/94/d4/2b21cb277bac9605026d2d91a4a8872bc82199ed11072d035dc674c27223/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", size = 124507 },
{ url = "https://files.pythonhosted.org/packages/9a/e0/a7c1fcdff20d9c667342e0391cfeb33ab01468d7d276b2c7914b371667cc/charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", size = 119298 },
{ url = "https://files.pythonhosted.org/packages/70/de/1538bb2f84ac9940f7fa39945a5dd1d22b295a89c98240b262fc4b9fcfe0/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", size = 139328 },
{ url = "https://files.pythonhosted.org/packages/e9/ca/288bb1a6bc2b74fb3990bdc515012b47c4bc5925c8304fc915d03f94b027/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", size = 149368 },
{ url = "https://files.pythonhosted.org/packages/aa/75/58374fdaaf8406f373e508dab3486a31091f760f99f832d3951ee93313e8/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", size = 141944 },
{ url = "https://files.pythonhosted.org/packages/32/c8/0bc558f7260db6ffca991ed7166494a7da4fda5983ee0b0bfc8ed2ac6ff9/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", size = 143326 },
{ url = "https://files.pythonhosted.org/packages/0e/dd/7f6fec09a1686446cee713f38cf7d5e0669e0bcc8288c8e2924e998cf87d/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", size = 146171 },
{ url = "https://files.pythonhosted.org/packages/4c/a8/440f1926d6d8740c34d3ca388fbd718191ec97d3d457a0677eb3aa718fce/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", size = 139711 },
{ url = "https://files.pythonhosted.org/packages/e9/7f/4b71e350a3377ddd70b980bea1e2cc0983faf45ba43032b24b2578c14314/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", size = 148348 },
{ url = "https://files.pythonhosted.org/packages/1e/70/17b1b9202531a33ed7ef41885f0d2575ae42a1e330c67fddda5d99ad1208/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", size = 151290 },
{ url = "https://files.pythonhosted.org/packages/44/30/574b5b5933d77ecb015550aafe1c7d14a8cd41e7e6c4dcea5ae9e8d496c3/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", size = 149114 },
{ url = "https://files.pythonhosted.org/packages/0b/11/ca7786f7e13708687443082af20d8341c02e01024275a28bc75032c5ce5d/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", size = 143856 },
{ url = "https://files.pythonhosted.org/packages/f9/c2/1727c1438256c71ed32753b23ec2e6fe7b6dff66a598f6566cfe8139305e/charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", size = 94333 },
{ url = "https://files.pythonhosted.org/packages/09/c8/0e17270496a05839f8b500c1166e3261d1226e39b698a735805ec206967b/charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", size = 101454 },
{ url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 },
{ url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 },
{ url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 },
{ url = "https://files.pythonhosted.org/packages/a4/23/65af317914a0308495133b2d654cf67b11bbd6ca16637c4e8a38f80a5a69/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", size = 140135 },
{ url = "https://files.pythonhosted.org/packages/f2/41/6190102ad521a8aa888519bb014a74251ac4586cde9b38e790901684f9ab/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", size = 150413 },
{ url = "https://files.pythonhosted.org/packages/7b/ab/f47b0159a69eab9bd915591106859f49670c75f9a19082505ff16f50efc0/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", size = 142992 },
{ url = "https://files.pythonhosted.org/packages/28/89/60f51ad71f63aaaa7e51a2a2ad37919985a341a1d267070f212cdf6c2d22/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", size = 144871 },
{ url = "https://files.pythonhosted.org/packages/0c/48/0050550275fea585a6e24460b42465020b53375017d8596c96be57bfabca/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", size = 146756 },
{ url = "https://files.pythonhosted.org/packages/dc/b5/47f8ee91455946f745e6c9ddbb0f8f50314d2416dd922b213e7d5551ad09/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", size = 141034 },
{ url = "https://files.pythonhosted.org/packages/84/79/5c731059ebab43e80bf61fa51666b9b18167974b82004f18c76378ed31a3/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", size = 149434 },
{ url = "https://files.pythonhosted.org/packages/ca/f3/0719cd09fc4dc42066f239cb3c48ced17fc3316afca3e2a30a4756fe49ab/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", size = 152443 },
{ url = "https://files.pythonhosted.org/packages/f7/0e/c6357297f1157c8e8227ff337e93fd0a90e498e3d6ab96b2782204ecae48/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", size = 150294 },
{ url = "https://files.pythonhosted.org/packages/54/9a/acfa96dc4ea8c928040b15822b59d0863d6e1757fba8bd7de3dc4f761c13/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", size = 145314 },
{ url = "https://files.pythonhosted.org/packages/73/1c/b10a63032eaebb8d7bcb8544f12f063f41f5f463778ac61da15d9985e8b6/charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", size = 94724 },
{ url = "https://files.pythonhosted.org/packages/c5/77/3a78bf28bfaa0863f9cfef278dbeadf55efe064eafff8c7c424ae3c4c1bf/charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", size = 102159 },
{ url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 },
] ]
[[package]]
name = "click"
version = "8.1.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "platform_system == 'Windows'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "44.0.0" version = "44.0.0"
@ -318,18 +204,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 },
] ]
[[package]]
name = "importlib-resources"
version = "6.4.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "zipp", marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115 },
]
[[package]] [[package]]
name = "jaraco-classes" name = "jaraco-classes"
version = "3.4.0" version = "3.4.0"
@ -381,7 +255,6 @@ version = "25.5.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "importlib-metadata", marker = "python_full_version < '3.12'" }, { name = "importlib-metadata", marker = "python_full_version < '3.12'" },
{ name = "importlib-resources", marker = "python_full_version < '3.9'" },
{ name = "jaraco-classes" }, { name = "jaraco-classes" },
{ name = "jaraco-context" }, { name = "jaraco-context" },
{ name = "jaraco-functools" }, { name = "jaraco-functools" },
@ -424,6 +297,40 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952 }, { url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952 },
] ]
[[package]]
name = "mypy"
version = "1.14.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/7b/08046ef9330735f536a09a2e31b00f42bccdb2795dcd979636ba43bb2d63/mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6", size = 3215684 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/97/f00ded038482230e0beaaa08f9c5483a54530b362ad1b0d752d5d2b2f211/mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87", size = 11207956 },
{ url = "https://files.pythonhosted.org/packages/68/67/8b4db0da19c9e3fa6264e948f1c135ab4dd45bede1809f4fdb613dc119f6/mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179", size = 10363681 },
{ url = "https://files.pythonhosted.org/packages/f5/00/56b1619ff1f3fcad2d411eccda60d74d20e73bda39c218d5ad2769980682/mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e", size = 12832976 },
{ url = "https://files.pythonhosted.org/packages/e7/8b/9247838774b0bd865f190cc221822212091317f16310305ef924d9772532/mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3", size = 13013704 },
{ url = "https://files.pythonhosted.org/packages/b2/69/0c0868a6f3d9761d2f704d1fb6ef84d75998c27d342738a8b20f109a411f/mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44", size = 9782230 },
{ url = "https://files.pythonhosted.org/packages/34/c1/b9dd3e955953aec1c728992545b7877c9f6fa742a623ce4c200da0f62540/mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a", size = 11121032 },
{ url = "https://files.pythonhosted.org/packages/ee/96/c52d5d516819ab95bf41f4a1ada828a3decc302f8c152ff4fc5feb0e4529/mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc", size = 10286294 },
{ url = "https://files.pythonhosted.org/packages/69/2c/3dbe51877a24daa467f8d8631f9ffd1aabbf0f6d9367a01c44a59df81fe0/mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015", size = 12746528 },
{ url = "https://files.pythonhosted.org/packages/a1/a8/eb20cde4ba9c4c3e20d958918a7c5d92210f4d1a0200c27de9a641f70996/mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb", size = 12883489 },
{ url = "https://files.pythonhosted.org/packages/91/17/a1fc6c70f31d52c99299320cf81c3cb2c6b91ec7269414e0718a6d138e34/mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc", size = 9780113 },
{ url = "https://files.pythonhosted.org/packages/fe/d8/0e72175ee0253217f5c44524f5e95251c02e95ba9749fb87b0e2074d203a/mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd", size = 11269011 },
{ url = "https://files.pythonhosted.org/packages/e9/6d/4ea13839dabe5db588dc6a1b766da16f420d33cf118a7b7172cdf6c7fcb2/mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1", size = 10253076 },
{ url = "https://files.pythonhosted.org/packages/3e/38/7db2c5d0f4d290e998f7a52b2e2616c7bbad96b8e04278ab09d11978a29e/mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63", size = 12862786 },
{ url = "https://files.pythonhosted.org/packages/bf/4b/62d59c801b34141040989949c2b5c157d0408b45357335d3ec5b2845b0f6/mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d", size = 12971568 },
{ url = "https://files.pythonhosted.org/packages/f1/9c/e0f281b32d70c87b9e4d2939e302b1ff77ada4d7b0f2fb32890c144bc1d6/mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba", size = 9879477 },
{ url = "https://files.pythonhosted.org/packages/13/33/8380efd0ebdfdfac7fc0bf065f03a049800ca1e6c296ec1afc634340d992/mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741", size = 11251509 },
{ url = "https://files.pythonhosted.org/packages/15/6d/4e1c21c60fee11af7d8e4f2902a29886d1387d6a836be16229eb3982a963/mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7", size = 10244282 },
{ url = "https://files.pythonhosted.org/packages/8b/cf/7a8ae5c0161edae15d25c2c67c68ce8b150cbdc45aefc13a8be271ee80b2/mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8", size = 12867676 },
{ url = "https://files.pythonhosted.org/packages/9c/d0/71f7bbdcc7cfd0f2892db5b13b1e8857673f2cc9e0c30e3e4340523dc186/mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc", size = 12964189 },
{ url = "https://files.pythonhosted.org/packages/a7/40/fb4ad65d6d5f8c51396ecf6305ec0269b66013a5bf02d0e9528053640b4a/mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f", size = 9888247 },
{ url = "https://files.pythonhosted.org/packages/39/32/0214608af400cdf8f5102144bb8af10d880675c65ed0b58f7e0e77175d50/mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab", size = 2752803 },
]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
@ -491,15 +398,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/21/11/4af184fbd8ae13daa13953212b27a212f4e63772ca8a0dd84d08b60ed206/pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088", size = 32322 }, { url = "https://files.pythonhosted.org/packages/21/11/4af184fbd8ae13daa13953212b27a212f4e63772ca8a0dd84d08b60ed206/pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088", size = 32322 },
] ]
[[package]]
name = "platformdirs"
version = "4.3.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 },
]
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.5.0" version = "1.5.0"
@ -518,130 +416,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 },
] ]
[[package]]
name = "pydantic"
version = "2.10.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/45/0f/27908242621b14e649a84e62b133de45f84c255eecb350ab02979844a788/pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9", size = 786486 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/51/72c18c55cf2f46ff4f91ebcc8f75aa30f7305f3d726be3f4ebffb4ae972b/pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d", size = 456997 },
]
[[package]]
name = "pydantic-core"
version = "2.27.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a6/9f/7de1f19b6aea45aeb441838782d68352e71bfa98ee6fa048d5041991b33e/pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", size = 412785 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6e/ce/60fd96895c09738648c83f3f00f595c807cb6735c70d3306b548cc96dd49/pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a", size = 1897984 },
{ url = "https://files.pythonhosted.org/packages/fd/b9/84623d6b6be98cc209b06687d9bca5a7b966ffed008d15225dd0d20cce2e/pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b", size = 1807491 },
{ url = "https://files.pythonhosted.org/packages/01/72/59a70165eabbc93b1111d42df9ca016a4aa109409db04304829377947028/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278", size = 1831953 },
{ url = "https://files.pythonhosted.org/packages/7c/0c/24841136476adafd26f94b45bb718a78cb0500bd7b4f8d667b67c29d7b0d/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05", size = 1856071 },
{ url = "https://files.pythonhosted.org/packages/53/5e/c32957a09cceb2af10d7642df45d1e3dbd8596061f700eac93b801de53c0/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4", size = 2038439 },
{ url = "https://files.pythonhosted.org/packages/e4/8f/979ab3eccd118b638cd6d8f980fea8794f45018255a36044dea40fe579d4/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f", size = 2787416 },
{ url = "https://files.pythonhosted.org/packages/02/1d/00f2e4626565b3b6d3690dab4d4fe1a26edd6a20e53749eb21ca892ef2df/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08", size = 2134548 },
{ url = "https://files.pythonhosted.org/packages/9d/46/3112621204128b90898adc2e721a3cd6cf5626504178d6f32c33b5a43b79/pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6", size = 1989882 },
{ url = "https://files.pythonhosted.org/packages/49/ec/557dd4ff5287ffffdf16a31d08d723de6762bb1b691879dc4423392309bc/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807", size = 1995829 },
{ url = "https://files.pythonhosted.org/packages/6e/b2/610dbeb74d8d43921a7234555e4c091cb050a2bdb8cfea86d07791ce01c5/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c", size = 2091257 },
{ url = "https://files.pythonhosted.org/packages/8c/7f/4bf8e9d26a9118521c80b229291fa9558a07cdd9a968ec2d5c1026f14fbc/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206", size = 2143894 },
{ url = "https://files.pythonhosted.org/packages/1f/1c/875ac7139c958f4390f23656fe696d1acc8edf45fb81e4831960f12cd6e4/pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c", size = 1816081 },
{ url = "https://files.pythonhosted.org/packages/d7/41/55a117acaeda25ceae51030b518032934f251b1dac3704a53781383e3491/pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17", size = 1981109 },
{ url = "https://files.pythonhosted.org/packages/27/39/46fe47f2ad4746b478ba89c561cafe4428e02b3573df882334bd2964f9cb/pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8", size = 1895553 },
{ url = "https://files.pythonhosted.org/packages/1c/00/0804e84a78b7fdb394fff4c4f429815a10e5e0993e6ae0e0b27dd20379ee/pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330", size = 1807220 },
{ url = "https://files.pythonhosted.org/packages/01/de/df51b3bac9820d38371f5a261020f505025df732ce566c2a2e7970b84c8c/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52", size = 1829727 },
{ url = "https://files.pythonhosted.org/packages/5f/d9/c01d19da8f9e9fbdb2bf99f8358d145a312590374d0dc9dd8dbe484a9cde/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4", size = 1854282 },
{ url = "https://files.pythonhosted.org/packages/5f/84/7db66eb12a0dc88c006abd6f3cbbf4232d26adfd827a28638c540d8f871d/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c", size = 2037437 },
{ url = "https://files.pythonhosted.org/packages/34/ac/a2537958db8299fbabed81167d58cc1506049dba4163433524e06a7d9f4c/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de", size = 2780899 },
{ url = "https://files.pythonhosted.org/packages/4a/c1/3e38cd777ef832c4fdce11d204592e135ddeedb6c6f525478a53d1c7d3e5/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025", size = 2135022 },
{ url = "https://files.pythonhosted.org/packages/7a/69/b9952829f80fd555fe04340539d90e000a146f2a003d3fcd1e7077c06c71/pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e", size = 1987969 },
{ url = "https://files.pythonhosted.org/packages/05/72/257b5824d7988af43460c4e22b63932ed651fe98804cc2793068de7ec554/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919", size = 1994625 },
{ url = "https://files.pythonhosted.org/packages/73/c3/78ed6b7f3278a36589bcdd01243189ade7fc9b26852844938b4d7693895b/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c", size = 2090089 },
{ url = "https://files.pythonhosted.org/packages/8d/c8/b4139b2f78579960353c4cd987e035108c93a78371bb19ba0dc1ac3b3220/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc", size = 2142496 },
{ url = "https://files.pythonhosted.org/packages/3e/f8/171a03e97eb36c0b51981efe0f78460554a1d8311773d3d30e20c005164e/pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9", size = 1811758 },
{ url = "https://files.pythonhosted.org/packages/6a/fe/4e0e63c418c1c76e33974a05266e5633e879d4061f9533b1706a86f77d5b/pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5", size = 1980864 },
{ url = "https://files.pythonhosted.org/packages/50/fc/93f7238a514c155a8ec02fc7ac6376177d449848115e4519b853820436c5/pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89", size = 1864327 },
{ url = "https://files.pythonhosted.org/packages/be/51/2e9b3788feb2aebff2aa9dfbf060ec739b38c05c46847601134cc1fed2ea/pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f", size = 1895239 },
{ url = "https://files.pythonhosted.org/packages/7b/9e/f8063952e4a7d0127f5d1181addef9377505dcce3be224263b25c4f0bfd9/pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02", size = 1805070 },
{ url = "https://files.pythonhosted.org/packages/2c/9d/e1d6c4561d262b52e41b17a7ef8301e2ba80b61e32e94520271029feb5d8/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c", size = 1828096 },
{ url = "https://files.pythonhosted.org/packages/be/65/80ff46de4266560baa4332ae3181fffc4488ea7d37282da1a62d10ab89a4/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac", size = 1857708 },
{ url = "https://files.pythonhosted.org/packages/d5/ca/3370074ad758b04d9562b12ecdb088597f4d9d13893a48a583fb47682cdf/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb", size = 2037751 },
{ url = "https://files.pythonhosted.org/packages/b1/e2/4ab72d93367194317b99d051947c071aef6e3eb95f7553eaa4208ecf9ba4/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529", size = 2733863 },
{ url = "https://files.pythonhosted.org/packages/8a/c6/8ae0831bf77f356bb73127ce5a95fe115b10f820ea480abbd72d3cc7ccf3/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35", size = 2161161 },
{ url = "https://files.pythonhosted.org/packages/f1/f4/b2fe73241da2429400fc27ddeaa43e35562f96cf5b67499b2de52b528cad/pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089", size = 1993294 },
{ url = "https://files.pythonhosted.org/packages/77/29/4bb008823a7f4cc05828198153f9753b3bd4c104d93b8e0b1bfe4e187540/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381", size = 2001468 },
{ url = "https://files.pythonhosted.org/packages/f2/a9/0eaceeba41b9fad851a4107e0cf999a34ae8f0d0d1f829e2574f3d8897b0/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb", size = 2091413 },
{ url = "https://files.pythonhosted.org/packages/d8/36/eb8697729725bc610fd73940f0d860d791dc2ad557faaefcbb3edbd2b349/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae", size = 2154735 },
{ url = "https://files.pythonhosted.org/packages/52/e5/4f0fbd5c5995cc70d3afed1b5c754055bb67908f55b5cb8000f7112749bf/pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c", size = 1833633 },
{ url = "https://files.pythonhosted.org/packages/ee/f2/c61486eee27cae5ac781305658779b4a6b45f9cc9d02c90cb21b940e82cc/pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16", size = 1986973 },
{ url = "https://files.pythonhosted.org/packages/df/a6/e3f12ff25f250b02f7c51be89a294689d175ac76e1096c32bf278f29ca1e/pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e", size = 1883215 },
{ url = "https://files.pythonhosted.org/packages/0f/d6/91cb99a3c59d7b072bded9959fbeab0a9613d5a4935773c0801f1764c156/pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", size = 1895033 },
{ url = "https://files.pythonhosted.org/packages/07/42/d35033f81a28b27dedcade9e967e8a40981a765795c9ebae2045bcef05d3/pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", size = 1807542 },
{ url = "https://files.pythonhosted.org/packages/41/c2/491b59e222ec7e72236e512108ecad532c7f4391a14e971c963f624f7569/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", size = 1827854 },
{ url = "https://files.pythonhosted.org/packages/e3/f3/363652651779113189cefdbbb619b7b07b7a67ebb6840325117cc8cc3460/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737", size = 1857389 },
{ url = "https://files.pythonhosted.org/packages/5f/97/be804aed6b479af5a945daec7538d8bf358d668bdadde4c7888a2506bdfb/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2", size = 2037934 },
{ url = "https://files.pythonhosted.org/packages/42/01/295f0bd4abf58902917e342ddfe5f76cf66ffabfc57c2e23c7681a1a1197/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107", size = 2735176 },
{ url = "https://files.pythonhosted.org/packages/9d/a0/cd8e9c940ead89cc37812a1a9f310fef59ba2f0b22b4e417d84ab09fa970/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51", size = 2160720 },
{ url = "https://files.pythonhosted.org/packages/73/ae/9d0980e286627e0aeca4c352a60bd760331622c12d576e5ea4441ac7e15e/pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a", size = 1992972 },
{ url = "https://files.pythonhosted.org/packages/bf/ba/ae4480bc0292d54b85cfb954e9d6bd226982949f8316338677d56541b85f/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc", size = 2001477 },
{ url = "https://files.pythonhosted.org/packages/55/b7/e26adf48c2f943092ce54ae14c3c08d0d221ad34ce80b18a50de8ed2cba8/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960", size = 2091186 },
{ url = "https://files.pythonhosted.org/packages/ba/cc/8491fff5b608b3862eb36e7d29d36a1af1c945463ca4c5040bf46cc73f40/pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23", size = 2154429 },
{ url = "https://files.pythonhosted.org/packages/78/d8/c080592d80edd3441ab7f88f865f51dae94a157fc64283c680e9f32cf6da/pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", size = 1833713 },
{ url = "https://files.pythonhosted.org/packages/83/84/5ab82a9ee2538ac95a66e51f6838d6aba6e0a03a42aa185ad2fe404a4e8f/pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", size = 1987897 },
{ url = "https://files.pythonhosted.org/packages/df/c3/b15fb833926d91d982fde29c0624c9f225da743c7af801dace0d4e187e71/pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", size = 1882983 },
{ url = "https://files.pythonhosted.org/packages/97/bb/c62074a65a32ed279bef44862e89fabb5ab1a81df8a9d383bddb4f49a1e0/pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62", size = 1901535 },
{ url = "https://files.pythonhosted.org/packages/9b/59/e224c93f95ffd4f5d37f1d148c569eda8ae23446ab8daf3a211ac0533e08/pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab", size = 1781287 },
{ url = "https://files.pythonhosted.org/packages/11/e2/33629134e577543b9335c5ca9bbfd2348f5023fda956737777a7a3b86788/pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864", size = 1834575 },
{ url = "https://files.pythonhosted.org/packages/fe/16/82e0849b3c6deb0330c07f1a8d55708d003ec8b1fd38ac84c7a830e25252/pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067", size = 1857948 },
{ url = "https://files.pythonhosted.org/packages/6b/4e/cdee588a7440bc58b6351e8b8dc2432e38b1144b5ae6625bfbdfb7fa76d9/pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd", size = 2041138 },
{ url = "https://files.pythonhosted.org/packages/1d/0e/73e0d1dff37a29c31e5b3e8587d228ced736cc7af9f81f6d7d06aa47576c/pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5", size = 2783820 },
{ url = "https://files.pythonhosted.org/packages/9a/b1/f164d05be347b99b91327ea9dd1118562951d2c86e1ea943ef73636b0810/pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78", size = 2138035 },
{ url = "https://files.pythonhosted.org/packages/72/44/cf1f20d3036d7e1545eafde0af4f3172075573a407a3a20313115c8990ff/pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f", size = 1991778 },
{ url = "https://files.pythonhosted.org/packages/5d/4c/486d8ddd595892e7d791f26dfd3e51bd8abea478eb7747fe2bbe890a2177/pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36", size = 1996644 },
{ url = "https://files.pythonhosted.org/packages/33/2a/9a1cd4c8aca242816be431583a3250797f2932fad32d35ad5aefcea179bc/pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a", size = 2091778 },
{ url = "https://files.pythonhosted.org/packages/8f/61/03576dac806c49e76a714c23f501420b0aeee80f97b995fc4b28fe63a010/pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b", size = 2146020 },
{ url = "https://files.pythonhosted.org/packages/72/82/e236d762052d24949aabad3952bc2c8635a470d6f3cbdd69498692afa679/pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618", size = 1819443 },
{ url = "https://files.pythonhosted.org/packages/6e/89/26816cad528ca5d4af9be33aa91507504c4576100e53b371b5bc6d3c797b/pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4", size = 1979478 },
{ url = "https://files.pythonhosted.org/packages/bc/6a/d741ce0c7da75ce9b394636a406aace00ad992ae417935ef2ad2e67fb970/pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967", size = 1898376 },
{ url = "https://files.pythonhosted.org/packages/bd/68/6ba18e30f10c7051bc55f1dffeadbee51454b381c91846104892a6d3b9cd/pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60", size = 1777246 },
{ url = "https://files.pythonhosted.org/packages/36/b8/6f1b7c5f068c00dfe179b8762bc1d32c75c0e9f62c9372174b1b64a74aa8/pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854", size = 1832148 },
{ url = "https://files.pythonhosted.org/packages/d9/83/83ff64d599847f080a93df119e856e3bd93063cced04b9a27eb66d863831/pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9", size = 1856371 },
{ url = "https://files.pythonhosted.org/packages/72/e9/974e6c73f59627c446833ecc306cadd199edab40abcfa093372a5a5c0156/pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd", size = 2038686 },
{ url = "https://files.pythonhosted.org/packages/5e/bb/5e912d02dcf29aebb2da35e5a1a26088c39ffc0b1ea81242ee9db6f1f730/pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be", size = 2785725 },
{ url = "https://files.pythonhosted.org/packages/85/d7/936846087424c882d89c853711687230cd60179a67c79c34c99b64f92625/pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e", size = 2135177 },
{ url = "https://files.pythonhosted.org/packages/82/72/5a386e5ce8d3e933c3f283e61357474181c39383f38afffc15a6152fa1c5/pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792", size = 1989877 },
{ url = "https://files.pythonhosted.org/packages/ce/5c/b1c417a5fd67ce132d78d16a6ba7629dc7f188dbd4f7c30ef58111ee5147/pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01", size = 1996006 },
{ url = "https://files.pythonhosted.org/packages/dd/04/4e18f2c42b29929882f30e4c09a3a039555158995a4ac730a73585198a66/pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9", size = 2091441 },
{ url = "https://files.pythonhosted.org/packages/06/84/5a332345b7efb5ab361f916eaf7316ef010e72417e8c7dd3d34462ee9840/pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131", size = 2144471 },
{ url = "https://files.pythonhosted.org/packages/54/58/23caa58c35d36627156789c0fb562264c12cfdb451c75eb275535188a96f/pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3", size = 1816563 },
{ url = "https://files.pythonhosted.org/packages/f7/9c/e83f08adc8e222b43c7f11d98b27eba08f21bcb259bcbf74743ce903c49c/pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c", size = 1983137 },
{ url = "https://files.pythonhosted.org/packages/7c/60/e5eb2d462595ba1f622edbe7b1d19531e510c05c405f0b87c80c1e89d5b1/pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6", size = 1894016 },
{ url = "https://files.pythonhosted.org/packages/61/20/da7059855225038c1c4326a840908cc7ca72c7198cb6addb8b92ec81c1d6/pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676", size = 1771648 },
{ url = "https://files.pythonhosted.org/packages/8f/fc/5485cf0b0bb38da31d1d292160a4d123b5977841ddc1122c671a30b76cfd/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d", size = 1826929 },
{ url = "https://files.pythonhosted.org/packages/a1/ff/fb1284a210e13a5f34c639efc54d51da136074ffbe25ec0c279cf9fbb1c4/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c", size = 1980591 },
{ url = "https://files.pythonhosted.org/packages/f1/14/77c1887a182d05af74f6aeac7b740da3a74155d3093ccc7ee10b900cc6b5/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27", size = 1981326 },
{ url = "https://files.pythonhosted.org/packages/06/aa/6f1b2747f811a9c66b5ef39d7f02fbb200479784c75e98290d70004b1253/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f", size = 1989205 },
{ url = "https://files.pythonhosted.org/packages/7a/d2/8ce2b074d6835f3c88d85f6d8a399790043e9fdb3d0e43455e72d19df8cc/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed", size = 2079616 },
{ url = "https://files.pythonhosted.org/packages/65/71/af01033d4e58484c3db1e5d13e751ba5e3d6b87cc3368533df4c50932c8b/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f", size = 2133265 },
{ url = "https://files.pythonhosted.org/packages/33/72/f881b5e18fbb67cf2fb4ab253660de3c6899dbb2dba409d0b757e3559e3d/pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c", size = 2001864 },
{ url = "https://files.pythonhosted.org/packages/85/3e/f6f75ba36678fee11dd07a7729e9ed172ecf31e3f50a5d636e9605eee2af/pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f", size = 1894250 },
{ url = "https://files.pythonhosted.org/packages/d3/2d/a40578918e2eb5b4ee0d206a4fb6c4040c2bf14e28d29fba9bd7e7659d16/pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31", size = 1772035 },
{ url = "https://files.pythonhosted.org/packages/7f/ee/0377e9f4ca5a47e8885f670a65c0a647ddf9ce98d50bf7547cf8e1ee5771/pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3", size = 1827025 },
{ url = "https://files.pythonhosted.org/packages/fe/0b/a24d9ef762d05bebdfafd6d5d176b990728fa9ec8ea7b6040d6fb5f3caaa/pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154", size = 1980927 },
{ url = "https://files.pythonhosted.org/packages/00/bd/deadc1722eb7dfdf787a3bbcd32eabbdcc36931fd48671a850e1b9f2cd77/pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd", size = 1980918 },
{ url = "https://files.pythonhosted.org/packages/f0/05/5d09d0b0e92053d538927308ea1d35cb25ab543d9c3e2eb2d7653bc73690/pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a", size = 1989990 },
{ url = "https://files.pythonhosted.org/packages/5b/7e/f7191346d1c3ac66049f618ee331359f8552a8b68a2daf916003c30b6dc8/pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97", size = 2079871 },
{ url = "https://files.pythonhosted.org/packages/f3/65/2caf4f7ad65413a137d43cb9578c54d1abd3224be786ad840263c1bf9e0f/pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2", size = 2133569 },
{ url = "https://files.pythonhosted.org/packages/fd/ab/718d9a1c41bb8d3e0e04d15b68b8afc135f8fcf552705b62f226225065c7/pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840", size = 2002035 },
]
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.18.0" version = "2.18.0"
@ -724,6 +498,31 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
] ]
[[package]]
name = "ruff"
version = "0.8.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/34/37/9c02181ef38d55b77d97c68b78e705fd14c0de0e5d085202bb2b52ce5be9/ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8", size = 3402103 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/05/67/f480bf2f2723b2e49af38ed2be75ccdb2798fca7d56279b585c8f553aaab/ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60", size = 10546415 },
{ url = "https://files.pythonhosted.org/packages/eb/7a/5aba20312c73f1ce61814e520d1920edf68ca3b9c507bd84d8546a8ecaa8/ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac", size = 10346113 },
{ url = "https://files.pythonhosted.org/packages/76/f4/c41de22b3728486f0aa95383a44c42657b2db4062f3234ca36fc8cf52d8b/ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296", size = 9943564 },
{ url = "https://files.pythonhosted.org/packages/0e/f0/afa0d2191af495ac82d4cbbfd7a94e3df6f62a04ca412033e073b871fc6d/ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643", size = 10805522 },
{ url = "https://files.pythonhosted.org/packages/12/57/5d1e9a0fd0c228e663894e8e3a8e7063e5ee90f8e8e60cf2085f362bfa1a/ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e", size = 10306763 },
{ url = "https://files.pythonhosted.org/packages/04/df/f069fdb02e408be8aac6853583572a2873f87f866fe8515de65873caf6b8/ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3", size = 11359574 },
{ url = "https://files.pythonhosted.org/packages/d3/04/37c27494cd02e4a8315680debfc6dfabcb97e597c07cce0044db1f9dfbe2/ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f", size = 12094851 },
{ url = "https://files.pythonhosted.org/packages/81/b1/c5d7fb68506cab9832d208d03ea4668da9a9887a4a392f4f328b1bf734ad/ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604", size = 11655539 },
{ url = "https://files.pythonhosted.org/packages/ef/38/8f8f2c8898dc8a7a49bc340cf6f00226917f0f5cb489e37075bcb2ce3671/ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf", size = 12912805 },
{ url = "https://files.pythonhosted.org/packages/06/dd/fa6660c279f4eb320788876d0cff4ea18d9af7d9ed7216d7bd66877468d0/ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720", size = 11205976 },
{ url = "https://files.pythonhosted.org/packages/a8/d7/de94cc89833b5de455750686c17c9e10f4e1ab7ccdc5521b8fe911d1477e/ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae", size = 10792039 },
{ url = "https://files.pythonhosted.org/packages/6d/15/3e4906559248bdbb74854af684314608297a05b996062c9d72e0ef7c7097/ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7", size = 10400088 },
{ url = "https://files.pythonhosted.org/packages/a2/21/9ed4c0e8133cb4a87a18d470f534ad1a8a66d7bec493bcb8bda2d1a5d5be/ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111", size = 10900814 },
{ url = "https://files.pythonhosted.org/packages/0d/5d/122a65a18955bd9da2616b69bc839351f8baf23b2805b543aa2f0aed72b5/ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8", size = 11268828 },
{ url = "https://files.pythonhosted.org/packages/43/a9/1676ee9106995381e3d34bccac5bb28df70194167337ed4854c20f27c7ba/ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835", size = 8805621 },
{ url = "https://files.pythonhosted.org/packages/10/98/ed6b56a30ee76771c193ff7ceeaf1d2acc98d33a1a27b8479cbdb5c17a23/ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d", size = 9660086 },
{ url = "https://files.pythonhosted.org/packages/13/9f/026e18ca7d7766783d779dae5e9c656746c6ede36ef73c6d934aaf4a6dec/ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08", size = 9074500 },
]
[[package]] [[package]]
name = "secretstorage" name = "secretstorage"
version = "3.3.3" version = "3.3.3"
@ -790,7 +589,6 @@ name = "twine"
version = "6.0.1" version = "6.0.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "importlib-metadata", marker = "python_full_version < '3.10'" },
{ name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" }, { name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" },
{ name = "packaging" }, { name = "packaging" },
{ name = "pkginfo" }, { name = "pkginfo" },
@ -826,25 +624,23 @@ wheels = [
[[package]] [[package]]
name = "wox-plugin" name = "wox-plugin"
version = "0.0.30" version = "0.0.45"
source = { editable = "." } source = { editable = "." }
dependencies = [
{ name = "pydantic" },
]
[package.optional-dependencies] [package.optional-dependencies]
dev = [ dev = [
{ name = "black" },
{ name = "hatchling" }, { name = "hatchling" },
{ name = "mypy" },
{ name = "ruff" },
{ name = "twine" }, { name = "twine" },
] ]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" }, { name = "hatchling", marker = "extra == 'dev'" },
{ name = "hatchling", marker = "extra == 'dev'", specifier = ">=1.18.0" }, { name = "mypy", marker = "extra == 'dev'" },
{ name = "pydantic", specifier = ">=2.0.0" }, { name = "ruff", marker = "extra == 'dev'" },
{ name = "twine", marker = "extra == 'dev'", specifier = ">=4.0.0" }, { name = "twine", marker = "extra == 'dev'" },
] ]
[[package]] [[package]]

View File

@ -5,9 +5,11 @@
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.build/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.swiftpm/
migrate_working_dir/ migrate_working_dir/
# IntelliJ related # IntelliJ related

View File

@ -0,0 +1,3 @@
{
"dart.lineLength": 180
}

View File

@ -201,7 +201,7 @@ class WoxLauncherController extends GetxController {
// on windows, it is somehow necessary to invoke show twice to make the window show // on windows, it is somehow necessary to invoke show twice to make the window show
// otherwise, the window will not show up if it is the first time to invoke showApp // otherwise, the window will not show up if it is the first time to invoke showApp
await windowManager.show(); await windowManager.show();
} }
await windowManager.focus(); await windowManager.focus();
queryBoxFocusNode.requestFocus(); queryBoxFocusNode.requestFocus();
@ -491,7 +491,9 @@ class WoxLauncherController extends GetxController {
if (activeResultIndex.value < prevResultIndex) { if (activeResultIndex.value < prevResultIndex) {
resultScrollerController.jumpTo(0); resultScrollerController.jumpTo(0);
} else { } else {
bool shouldJump = deviceType == WoxEventDeviceTypeEnum.WOX_EVENT_DEVEICE_TYPE_KEYBOARD.code ? isResultItemAtBottom(activeResultIndex.value - 1) : !isResultItemAtBottom(results.length - 1); bool shouldJump = deviceType == WoxEventDeviceTypeEnum.WOX_EVENT_DEVEICE_TYPE_KEYBOARD.code
? isResultItemAtBottom(activeResultIndex.value - 1)
: !isResultItemAtBottom(results.length - 1);
if (shouldJump) { if (shouldJump) {
resultScrollerController.jumpTo(resultScrollerController.offset.ceil() + WoxThemeUtil.instance.getResultItemHeight() * (activeResultIndex.value - prevResultIndex).abs()); resultScrollerController.jumpTo(resultScrollerController.offset.ceil() + WoxThemeUtil.instance.getResultItemHeight() * (activeResultIndex.value - prevResultIndex).abs());
} }
@ -592,7 +594,8 @@ class WoxLauncherController extends GetxController {
RenderBox? renderBox = resultGlobalKeys[index].currentContext?.findRenderObject() as RenderBox?; RenderBox? renderBox = resultGlobalKeys[index].currentContext?.findRenderObject() as RenderBox?;
if (renderBox == null) return false; if (renderBox == null) return false;
if (renderBox.localToGlobal(Offset.zero).dy.ceil() >= WoxThemeUtil.instance.getQueryBoxHeight() + WoxThemeUtil.instance.getResultListViewHeightByCount(MAX_LIST_VIEW_ITEM_COUNT - 1)) { if (renderBox.localToGlobal(Offset.zero).dy.ceil() >=
WoxThemeUtil.instance.getQueryBoxHeight() + WoxThemeUtil.instance.getResultListViewHeightByCount(MAX_LIST_VIEW_ITEM_COUNT - 1)) {
return true; return true;
} }
return false; return false;
@ -774,7 +777,8 @@ class WoxLauncherController extends GetxController {
return; return;
} }
Logger.instance.info(traceId, "update active actions, reason: $reason, current active result: ${activeQueryResult.title.value}, active action: ${activeQueryResult.actions.first.name.value}"); Logger.instance.info(
traceId, "update active actions, reason: $reason, current active result: ${activeQueryResult.title.value}, active action: ${activeQueryResult.actions.first.name.value}");
String? previousActionName; String? previousActionName;
if (remainIndex && actions.isNotEmpty && activeActionIndex.value >= 0 && activeActionIndex.value < actions.length) { if (remainIndex && actions.isNotEmpty && activeActionIndex.value >= 0 && activeActionIndex.value < actions.length) {
@ -870,6 +874,7 @@ class WoxLauncherController extends GetxController {
final resultIndex = results.indexWhere((element) => element.id == result.id); final resultIndex = results.indexWhere((element) => element.id == result.id);
if (isResultActiveByIndex(resultIndex)) { if (isResultActiveByIndex(resultIndex)) {
currentPreview.value = result.preview; currentPreview.value = result.preview;
isShowPreviewPanel.value = currentPreview.value.previewData != "";
resetActiveAction(traceId, "refresh active result", remainIndex: true); resetActiveAction(traceId, "refresh active result", remainIndex: true);
} }

View File

@ -77,10 +77,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.19.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -417,18 +417,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.5" version: "10.0.7"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.8"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
@ -705,7 +705,7 @@ packages:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -726,10 +726,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.1" version: "1.12.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -742,10 +742,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
syncfusion_flutter_core: syncfusion_flutter_core:
dependency: transitive dependency: transitive
description: description:
@ -822,10 +822,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.7.3"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:
@ -958,10 +958,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "14.3.0"
web: web:
dependency: transitive dependency: transitive
description: description: