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¶
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:
- O
plugin.jsoné analisado corretamente, tem umid, oapiVersioncoincide com o do editor, oentryé"python"e omoduleestá presente. - 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. - Depois da extração em um diretório temporário, o
<module>.pydeclarado existe e declara umdef 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
idjá 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:
- Incluídos — ao lado do executável, em
<exe-dir>/Plugins/. Plugins integrados (por exemplo,HelloPython) ficam aqui. - 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:
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
pyRequiresse 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.