- Início
- Documentation
- Extensões
- Mecanismos internos do gerenciador e instalador de plugins
Mecanismos internos do gerenciador e instalador de plugins
Este documento descreve como as operações xcsh plugin modificam o estado dos plugins em disco e como os plugins instalados se tornam capacidades de tempo de execução (ferramentas atualmente, resolução de caminho para hooks/comandos disponível).
Escopo e arquitetura
Seção intitulada “Escopo e arquitetura”Existem duas implementações de gerenciamento de plugins na base de código:
- Caminho ativo usado pelos comandos CLI:
PluginManager(src/extensibility/plugins/manager.ts) - Módulo auxiliar legado: funções de instalação (
src/extensibility/plugins/installer.ts)
A execução do comando xcsh plugin ... passa pelo PluginManager.
O installer.ts ainda documenta verificações de segurança importantes e comportamento do sistema de arquivos, mas não é o caminho utilizado por src/commands/plugin.ts + src/cli/plugin-cli.ts.
Ciclo de vida: da invocação da CLI à disponibilidade em tempo de execução
Seção intitulada “Ciclo de vida: da invocação da CLI à disponibilidade em tempo de execução”xcsh plugin <action> ... -> src/commands/plugin.ts -> runPluginCommand(...) in src/cli/plugin-cli.ts -> PluginManager method (install/list/uninstall/link/...) -> mutate ~/.xcsh/plugins/{package.json,node_modules,xcsh-plugins.lock.json} -> runtime discovery: discoverAndLoadCustomTools(...) -> getAllPluginToolPaths(cwd) -> custom tool loader imports tool modulesPontos de entrada de comando
Seção intitulada “Pontos de entrada de comando”src/commands/plugin.tsdefine o comando/flags e encaminha pararunPluginCommand.src/cli/plugin-cli.tsmapeia subcomandos para métodos doPluginManager:install,uninstall,list,link,doctor,features,config,enable,disable
- Não existe uma ação
updateexplícita; a atualização é feita executando novamenteinstallcom uma especificação de pacote/versão nova.
Modelo em disco
Seção intitulada “Modelo em disco”O estado global dos plugins reside em ~/.xcsh/plugins:
package.json— manifesto de dependências usado porbun install/bun uninstallnode_modules/— pacotes de plugins instalados ou links simbólicosxcsh-plugins.lock.json— estado de tempo de execução:- habilitado/desabilitado por plugin
- conjunto de funcionalidades selecionadas por plugin
- configurações persistidas do plugin
Substituições locais do projeto residem em:
<cwd>/.xcsh/plugin-overrides.json
As substituições são somente leitura da perspectiva do gerenciador/carregador (sem caminho de escrita aqui) e podem desabilitar plugins ou substituir funcionalidades/configurações para este projeto.
Análise de especificações de plugins e interpretação de metadados
Seção intitulada “Análise de especificações de plugins e interpretação de metadados”Gramática da especificação de instalação
Seção intitulada “Gramática da especificação de instalação”parsePluginSpec (parser.ts) suporta:
pkg->features: null(comportamento padrão)pkg[*]-> habilitar todas as funcionalidades do manifestopkg[]-> não habilitar funcionalidades opcionaispkg[a,b]-> habilitar funcionalidades nomeadas@scope/pkg@1.2.3[feat]-> pacote com escopo + versão com seleção explícita de funcionalidade
extractPackageName remove o sufixo de versão para busca de caminho em disco após a instalação.
Fonte do manifesto e campos obrigatórios
Seção intitulada “Fonte do manifesto e campos obrigatórios”O manifesto é resolvido como:
package.json.xcsh- fallback
package.json.pi - fallback
{ version: package.version }
Implicações:
- Não há validação de esquema estrita no gerenciador/carregador.
- Um pacote sem manifesto
xcsh/piainda pode ser instalado e listado. - O carregamento de plugins em tempo de execução (
getEnabledPlugins) ignora pacotes sem manifestoxcsh/pi. manifest.versioné sempre sobrescrito a partir daversiondo pacote.
JSON malformado em package.json é uma falha crítica no momento da leitura; uma estrutura de manifesto malformada pode falhar posteriormente apenas quando campos específicos são consumidos.
Fluxo de instalação/atualização (PluginManager.install)
Seção intitulada “Fluxo de instalação/atualização (PluginManager.install)”- Analisar a sintaxe de colchetes de funcionalidades da especificação de instalação.
- Validar o nome do pacote contra regex + lista de negação de metacaracteres de shell.
- Garantir que o
package.jsondo plugin exista (xcsh-plugins, mapa de dependências privadas). - Executar
bun install <packageSpec>em~/.xcsh/plugins. - Ler o
package.jsondo pacote instalado emnode_modules/<name>/package.json. - Resolver o manifesto e calcular
enabledFeatures:[*]: todas as funcionalidades declaradas (ounullse não houver mapa de funcionalidades)[a,b]: valida que cada funcionalidade existe no mapa de funcionalidades do manifesto[]: lista de funcionalidades vazia- especificação básica:
null(usar política de padrões posteriormente no carregador)
- Inserir ou atualizar o estado de tempo de execução no arquivo de lock:
{ version, enabledFeatures, enabled: true }.
Semântica de atualização
Seção intitulada “Semântica de atualização”Como a atualização é orientada pela instalação:
xcsh plugin install pkg@newVersionatualiza a dependência e a versão no arquivo de lock.- As configurações existentes são preservadas; a entrada de estado é sobrescrita para versão/funcionalidades/habilitado.
- Não existe lógica separada de “verificar atualizações” ou migração transacional.
Fluxo de remoção (PluginManager.uninstall)
Seção intitulada “Fluxo de remoção (PluginManager.uninstall)”- Validar o nome do pacote.
- Executar
bun uninstall <name>no diretório de plugins. - Remover o estado de tempo de execução do plugin do arquivo de lock:
config.plugins[name]config.settings[name]
Se o comando de desinstalação falhar, o estado de tempo de execução não é alterado.
Fluxo de listagem (PluginManager.list)
Seção intitulada “Fluxo de listagem (PluginManager.list)”- Ler o mapa de dependências de plugins de
~/.xcsh/plugins/package.json. - Carregar a configuração de tempo de execução do arquivo de lock (arquivo ausente -> padrões vazios).
- Carregar substituições do projeto (
<cwd>/.xcsh/plugin-overrides.json, erros de análise/leitura -> objeto vazio com aviso). - Para cada dependência com um
package.jsonresolvível:- construir registro
InstalledPlugin - mesclar estado de funcionalidade/habilitação:
- base do arquivo de lock (ou padrões)
- substituições do projeto podem substituir a seleção de funcionalidades
- lista
disableddo projeto mascara o plugin como desabilitado
- construir registro
Este é o estado efetivo usado pela saída de status da CLI e pelas operações de configurações/funcionalidades.
Fluxo de link (PluginManager.link)
Seção intitulada “Fluxo de link (PluginManager.link)”link suporta o desenvolvimento local de plugins criando um link simbólico de um pacote local em ~/.xcsh/plugins/node_modules/<pkg.name>.
Comportamento:
- Resolver
localPathem relação ao cwd do gerenciador. - Exigir
package.jsonlocal e camponame. - Garantir que os diretórios de plugins existam.
- Para nomes com escopo, criar o diretório de escopo.
- Remover o caminho existente no local do link de destino.
- Criar link simbólico.
- Adicionar entrada no arquivo de lock de tempo de execução habilitada com funcionalidades padrão (
null).
Ressalva: o PluginManager.link atual não impõe a verificação de limite de caminho cwd presente no installer.ts legado (normalizedPath.startsWith(normalizedCwd)), portanto a confiança é responsabilidade do chamador.
Carregamento em tempo de execução: do plugin instalado às capacidades invocáveis
Seção intitulada “Carregamento em tempo de execução: do plugin instalado às capacidades invocáveis”Porta de descoberta
Seção intitulada “Porta de descoberta”getEnabledPlugins(cwd) (plugins/loader.ts) lê:
- manifesto de dependências de plugins (
package.json) - estado de tempo de execução do arquivo de lock
- substituições do projeto via
getConfigDirPaths("plugin-overrides.json", { user: false, cwd })
Filtragem:
- ignorar se não houver
package.jsondo plugin - ignorar se o manifesto (
xcsh/pi) estiver ausente - ignorar se globalmente desabilitado no arquivo de lock
- ignorar se desabilitado pelo projeto
Resolução de caminho de capacidades
Seção intitulada “Resolução de caminho de capacidades”Para cada plugin habilitado:
resolvePluginToolPaths(plugin)resolvePluginHookPaths(plugin)resolvePluginCommandPaths(plugin)
Cada resolvedor inclui entradas base mais entradas de funcionalidades:
- lista explícita de funcionalidades -> apenas funcionalidades selecionadas
enabledFeatures === null-> habilitar funcionalidades marcadas comdefault: true
Arquivos ausentes são ignorados silenciosamente (guarda existsSync).
Diferenças atuais no roteamento em tempo de execução
Seção intitulada “Diferenças atuais no roteamento em tempo de execução”- As ferramentas estão roteadas no tempo de execução hoje via
discoverAndLoadCustomTools(custom-tools/loader.ts), que chamagetAllPluginToolPaths(cwd). - Os caminhos são desduplicados por caminho absoluto resolvido na descoberta de ferramentas personalizadas (conjunto
seen, o primeiro caminho vence). - Os resolvedores de hooks/comandos existem e são exportados, mas este caminho de código não os conecta atualmente a um registro de tempo de execução da mesma forma que as ferramentas são conectadas.
Detalhes de gerenciamento de lock/estado
Seção intitulada “Detalhes de gerenciamento de lock/estado”PluginManager armazena em cache a configuração de tempo de execução em memória por instância (#runtimeConfig) e carrega preguiçosamente uma vez.
Comportamento de carregamento:
- arquivo de lock ausente ->
{ plugins: {}, settings: {} } - falha na leitura/análise do arquivo de lock -> aviso + mesmos padrões vazios
Comportamento de salvamento:
- escreve o JSON completo do arquivo de lock com formatação a cada mutação
Não existe bloqueio entre processos nem estratégia de mesclagem; escritores concorrentes podem sobrescrever uns aos outros.
Verificações de segurança e limites de confiança
Seção intitulada “Verificações de segurança e limites de confiança”Validação de entrada/pacote
Seção intitulada “Validação de entrada/pacote”O caminho ativo do gerenciador impõe validação de nome de pacote:
- regex para especificações de pacote com e sem escopo (opcionalmente com versão)
- lista de negação explícita de metacaracteres de shell (
[;&|$(){}[]<>\]`)
Isso limita o risco de injeção de comandos ao invocar bun install/uninstall.
Limite de confiança do sistema de arquivos
Seção intitulada “Limite de confiança do sistema de arquivos”- O código do plugin é executado em processo quando os módulos de ferramentas personalizadas são importados; sem sandboxing.
- Os caminhos relativos do manifesto são unidos ao diretório do pacote do plugin e apenas verificados quanto à existência.
- O próprio pacote do plugin é código confiável após a instalação.
Verificações exclusivas do instalador legado
Seção intitulada “Verificações exclusivas do instalador legado”installer.ts inclui verificações adicionais em tempo de link não espelhadas em PluginManager.link:
- o caminho local deve ser resolvido dentro do cwd do projeto
- guardas adicionais de travessia de nome de pacote/caminho para nomeação do destino do link simbólico
Como a CLI usa PluginManager, essas guardas de link mais estritas não estão atualmente no caminho principal.
Comportamento de falha, sucesso parcial e reversão
Seção intitulada “Comportamento de falha, sucesso parcial e reversão”O gerenciador de plugins não é transacional.
| Estágio da operação | Comportamento em caso de falha | Reversão |
|---|---|---|
bun install falha | instalação é abortada com stderr | N/A (sem gravações de estado ainda) |
| Instalação bem-sucedida, então validação de manifesto/funcionalidade falha | comando falha | Sem reversão de desinstalação; a dependência pode permanecer em node_modules/package.json |
| Instalação bem-sucedida, então gravação do arquivo de lock falha | comando falha | Sem reversão do pacote instalado |
bun uninstall bem-sucedido, gravação do arquivo de lock falha | comando falha | Pacote removido, estado de tempo de execução obsoleto pode permanecer |
link remove o destino antigo e então a criação do link simbólico falha | comando falha | Sem restauração do link/diretório anterior |
Operacionalmente, doctor --fix pode corrigir alguma divergência (execução de bun install, limpeza de configuração órfã, limpeza de funcionalidades inválidas), mas é uma operação de melhor esforço.
Resumo do comportamento com manifesto malformado/ausente
Seção intitulada “Resumo do comportamento com manifesto malformado/ausente”- Campo
xcsh/piausente:- instalação/listagem: tolerado (manifesto mínimo)
- descoberta de plugins habilitados em tempo de execução: ignorado como não-plugin
- Funcionalidade ausente referenciada pela especificação de instalação ou
features --set/--enable: erro crítico com lista de funcionalidades disponíveis plugin-overrides.jsoninválido: ignorado com fallback para{}nos caminhos do gerenciador e do carregador- Caminhos de arquivos de ferramentas/hooks/comandos referenciados pelo manifesto ausentes: ignorados silenciosamente durante a expansão do resolvedor; sinalizados como erros apenas pelo
doctor
Diferenças de modo e precedência
Seção intitulada “Diferenças de modo e precedência”--dry-run(install): retorna resultado de instalação sintético, sem gravações em sistema de arquivos/rede/estado.--json: apenas formatação de saída, sem alteração de comportamento.- As substituições do projeto sempre têm precedência sobre o arquivo de lock global para visualização de funcionalidades/configurações.
- A habilitação efetiva é
runtimeEnabled && !projectDisabled.
Arquivos de implementação
Seção intitulada “Arquivos de implementação”src/commands/plugin.ts— declaração do comando CLI e mapeamento de flagssrc/cli/plugin-cli.ts— despacho de ações, manipuladores de comandos voltados ao usuáriosrc/extensibility/plugins/manager.ts— implementação ativa de install/remove/list/link/state/doctorsrc/extensibility/plugins/installer.ts— auxiliares do instalador legado e verificações adicionais de segurança de linksrc/extensibility/plugins/loader.ts— descoberta de plugins habilitados e resolução de caminhos de ferramentas/hooks/comandossrc/extensibility/plugins/parser.ts— auxiliares de análise de especificação de instalação e nome de pacotesrc/extensibility/plugins/types.ts— contratos de tipos de manifesto/tempo de execução/substituiçãosrc/extensibility/custom-tools/loader.ts— roteamento em tempo de execução para módulos de ferramentas fornecidos por plugins