Pular para conteúdo

Empacotamento e instalação

Um plugin Python é uma pasta com um plugin.json e um módulo Python. Você pode instalar um de duas formas: empacotá-lo como um arquivo .mteplugin e usar o instalador do editor (recomendado), ou colocar a pasta manualmente em um diretório de plugins.

Comece pelo modelo

Um ponto de partida pronto para copiar fica em Python/templates/plugin-template-python/ no repositório — três arquivos (plugin.json, main.py, README.md) mais um CLAUDE.md voltado ao Claude. Renomeie a pasta com o nome curto do seu plugin, edite quatro campos no plugin.json e comece a escrever register(ctx). O SDK instalado traz o mesmo modelo em share/MTEPluginSDK/plugin-template-python/.

Layout da pasta do plugin

hello/
├── plugin.json      # required
└── main.py          # required; module name from plugin.json.module

Tudo de que o plugin precisa tem de estar dentro desta pasta. Subimportações funcionam, mas precisam ser planas — nomes de module com pontos no plugin.json são uma extensão futura.

Você pode acrescentar arquivos extras (README, LICENSE) — o host ignora o que não reconhece.

Pacotes .mteplugin (recomendado)

Compacte os arquivos do plugin e dê ao arquivo a extensão .mteplugin (um .zip simples também funciona). As duas formas são aceitas:

hello.mteplugin              hello.mteplugin
├── plugin.json              └── hello-1.0.0/        # any folder name
└── main.py                      ├── plugin.json
                                 └── main.py

A pasta envoltória única — o resultado natural de compactar uma pasta — é normalizada e desaparece: o plugin sempre é instalado em <Plugins>/<id>/, identificado pelo id do manifesto, nunca pelo nome da pasta do arquivo compactado. É também por isso que instalar a versão 2 de um plugin substitui a versão 1, em vez de ficar ao lado dela.

Instale-o por Preferências → Plug-ins → Instalar um plug-in... e reinicie o editor.

Instale apenas pacotes em que você confia

O instalador verifica se um pacote é estruturalmente sólido (veja abaixo) — ele não torna seguro executar um plugin em que você não confia. Uma vez carregado, um plugin roda com o mesmo acesso aos seus arquivos, configurações e rede que o editor, e não é isolado. A sondagem estática de register(...) não executa código na hora da instalação, mas o código do plugin roda na próxima inicialização. Trate um .mteplugin (e quaisquer arquivos de configuração ou JSON que ele distribua) como um programa desconhecido: instale-o apenas de uma fonte em que você confia. Veja Plugins para o aviso completo.

O que o instalador valida

O pacote é totalmente validado contra uma cópia descartável antes de qualquer coisa no disco ser tocada — um pacote ruim nunca pode perturbar uma instalação existente:

  1. O plugin.json é analisado corretamente, tem um id, o apiVersion coincide com o do editor, o entry é "python" e o module está presente.
  2. A listagem do arquivo compactado é segura: nenhum caminho de entrada absoluto ou com .., no máximo 10 000 entradas, no máximo 256 MiB descompactado, e ao menos um arquivo .py.
  3. Depois da extração em um diretório temporário, o <module>.py declarado existe e declara um def register(...) de nível superior — a mesma sondagem estática que a descoberta usa. Nenhum código Python é executado na hora da instalação.

Qualquer falha produz uma caixa de diálogo de erro legível e deixa os plugins do editor intocados.

Atualizando e desinstalando

  • Instalar um pacote cujo id já está instalado o substitui. Se aquele plugin estiver carregado no momento, a atualização é preparada e aplicada na próxima inicialização.
  • Desinstale pela mesma página de Preferências; a remoção também acontece na próxima inicialização, enquanto nada está carregado.
  • Plugins incluídos (integrados) não podem ser substituídos por um pacote instalado com o mesmo id.

Instalando manualmente (colocando a pasta)

O editor descobre plugins em dois diretórios a cada inicialização:

  1. Incluídos — ao lado do executável, em <exe-dir>/Plugins/. Plugins integrados (por exemplo, HelloPython) ficam aqui.
  2. Usuário — por usuário, gravável. No Windows é %LOCALAPPDATA%/MTE/Plugins/, no macOS ~/Library/Application Support/MTE/Plugins/, no Linux ~/.local/share/MTE/Plugins/.

Os dois diretórios são varridos. Se o mesmo id aparecer nos dois, a primeira ocorrência vence (os incluídos têm precedência). Reinicie o editor para captar pastas novas — recarga a quente não é suportada.

Dois layouts aceitáveis

A varredura procura o plugin.json diretamente no diretório de plugins (solto) ou dentro de um nível de subdiretório imediato (pasta por plugin):

Plugins/
├── plugin.json         # loose -- one plugin at the top level
├── main.py
└── hello/              # per-plugin folder -- one plugin
    ├── plugin.json
    └── main.py

A pasta por plugin é o layout recomendado; é o formato que o instalador produz.

Dependências (pyRequires)

O plugin.json pode declarar requisitos do pip como um array em linha:

"pyRequires": ["requests>=2.31"]

Na primeira inicialização do plugin, o editor provisiona um ambiente virtual em <AppLocalData>/PluginVenv/<id>/ (python -m venv + pip install, o que exige acesso à rede aquela única vez) e executa o trabalhador do plugin sob o interpretador daquele ambiente. As inicializações seguintes o reaproveitam; alterar o pyRequires provisiona de novo automaticamente (o ambiente carrega um carimbo dos requisitos para os quais foi construído).

  • Falhas de provisionamento (sem rede, um requisito com erro de digitação) deixam o plugin listado, mas não carregado, com o erro do pip no log; a próxima inicialização tenta de novo.
  • Desinstalar um plugin remove o ambiente virtual dele junto com a pasta do plugin (um ambiente virtual é dado derivado — ele é reconstruído a partir do pyRequires se você algum dia reinstalar).

Máquinas offline / restritas

Distribua um ambiente virtual pré-construído dentro do pacote, como uma pasta venv/ na raiz do plugin. Quando presente, ele vence tudo — o pip nunca roda. Construa-o em uma máquina com o mesmo sistema operacional/arquitetura, já que ambientes virtuais não são portáteis entre plataformas.

Embutindo o código (dependências pequenas de Python puro)

Para um único módulo de Python puro, embuti-lo dentro da pasta do plugin ainda funciona e evita por completo a maquinaria do ambiente virtual:

# main.py
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "vendor"))

import your_dep

Permissões declaradas

O plugin.json pode carregar um array permissions (por exemplo, ["network"]). A página de Preferências de Plugins o exibe em uma coluna Permissões somente leitura, para que os usuários vejam o que um plugin declara sobre si mesmo. É uma declaração, não uma imposição — o isolamento é trabalho futuro.

Para onde vão os dados graváveis

O diretório de plugins guarda código. Dados de tempo de execução (caches, configuração por usuário, índices) vão para um diretório de dados separado por plugin, gerenciado pelo host — ctx.data_dir() devolve o caminho absoluto dele. NÃO grave no diretório de plugins a partir do seu .py em tempo de execução; a desinstalação remove toda a pasta <Plugins>/<id>/, e gravações feitas em outros pontos da árvore de plugins nunca são limpas.

Implantando em outras máquinas

Distribua o arquivo .mteplugin — ele é autocontido e validado na ponta receptora. Um zip/tarball/clone de git da pasta no diretório de plugins por usuário também funciona.

Ativar / desativar

A página de Preferências de Plugins lista todos os plugins descobertos (nativos + Python, juntos) com as mesmas colunas de origem/status. Desativar um plugin o mantém listado, mas impede que a fábrica dele seja invocada na inicialização — nenhum trabalhador é gerado. Reative e reinicie para trazê-lo de volta.