Spirit Agent
Baixar

Extensões

Layout do pacote, campos spiritExtension, API de ativação e listagem no registro oficial.

Uma extensão é uma pasta com um package.json que contém spiritExtension. O Spirit a instala por usuário e por host, não no diretório .spirit/ do workspace.

HostCaminho
Desktop{spiritDataDir}/extensions/desktop/
CLI{spiritDataDir}/extensions/cli/

Isso é diferente de Skills (pastas SKILL.md), MCP (servidores externos) e Hooks (scripts hooks.json). contributes.cli.hooks estiliza os slots da TUI do CLI. Não é hooks.json.

Não há chave de ativação por extensão. Após a instalação, a extensão contribui. A alternância no painel do CLI é um espaço reservado.

Layout do pacote

example-extension/
  package.json
  dist/index.js
  assets/icon.svg
  styles/desktop.css
  cli-hooks.json
{
  "name": "@example/spirit-extension",
  "version": "0.1.0",
  "description": "Example Spirit Agent extension.",
  "author": { "name": "example" },
  "homepage": "https://example.com/spirit-extension",
  "main": "dist/index.js",
  "spiritExtension": {
    "schemaVersion": 1,
    "displayName": "Example extension",
    "icon": "assets/icon.svg",
    "supportedHosts": ["cli", "desktop"],
    "activationEvents": ["onStartup", "onUserMessage"],
    "requestedCapabilities": [
      "tool-definitions",
      "tool-execution",
      "system-prompt",
      "settings",
      "secret-storage",
      "desktop-ui",
      "cli-ui"
    ],
    "contributes": {
      "tools": [
        {
          "name": "lookup_item",
          "description": "Look up an item by id.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "id": { "type": "string" }
            },
            "required": ["id"]
          },
          "approvalMode": "allowed",
          "executionMode": "foreground"
        }
      ],
      "desktop": {
        "css": [{ "path": "styles/desktop.css" }],
        "settingsPage": { "title": "Example extension" }
      },
      "cli": {
        "hooks": { "path": "cli-hooks.json" }
      }
    },
    "settingsSchema": [
      {
        "key": "region",
        "type": "select",
        "title": "Region",
        "required": true,
        "defaultValue": "us",
        "options": [
          { "value": "us", "label": "US" },
          { "value": "eu", "label": "EU" }
        ]
      }
    ],
    "secretSlots": [
      {
        "key": "api_token",
        "title": "API token",
        "required": true
      }
    ]
  }
}

O name no package.json é o id da extensão. Deve corresponder a ^(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$.

Campos do package.json

CampoDescrição
nameObrigatório. Nome do pacote npm; usado como id da extensão
versionObrigatório. String de versão
spiritExtensionObrigatório. Objeto. Veja abaixo
descriptionOpcional. String
authorOpcional. String ou { name }
homepageOpcional. String
mainOpcional. Caminho relativo para o ponto de entrada activate. Necessário quando a extensão usa activationEvents, execução de ferramentas ou um prompt de sistema

main, spiritExtension.icon, caminhos CSS e caminhos de gancho CLI devem ser relativos e permanecer dentro do pacote.

spiritExtension

CampoDescrição
schemaVersionOpcional. Padrão é 1. Apenas 1 é suportado
displayNameObrigatório. Nome visível ao usuário
iconOpcional. Caminho relativo à raiz do pacote
supportedHostsObrigatório. Matriz não vazia de cli e/ou desktop
activationEventsOpcional. Veja Eventos de ativação
requestedCapabilitiesOpcional. Veja Capacidades
contributesOpcional. tools, desktop e/ou cli
settingsSchemaOpcional. Definições de configurações
secretSlotsOpcional. Definições de slots de segredos

Capacidades

ValorRuntime
tool-definitionsNecessário com tool-execution para expor contributes.tools ao modelo
tool-executionNecessário com tool-definitions para executar essas ferramentas
system-promptNecessário com main para contribuir com um fragmento de prompt de sistema
desktop-uiDeve ser emparelhado com contributes.desktop
cli-uiDeve ser emparelhado com contributes.cli
approval-flowSomente declarado. A aprovação é conduzida pelo approvalMode de cada ferramenta
questions-flowSomente declarado. As perguntas são conduzidas por approvalMode: need-questions
settingsSomente declarado. As configurações vêm de settingsSchema
secret-storageUsado com secretSlots
structured-resultsSomente declarado

desktop-ui / cli-ui e o bloco contributes correspondente devem estar ambos presentes ou ambos ausentes.

Eventos de ativação

EventoQuando dispara
onStartupAquecimento do host
onExtensionInstalledApós instalação via ZIP ou marketplace
onSessionOpenedSessão se torna ativa
onSessionResetReset da sessão
onUserMessageUsuário envia uma mensagem
onToolCallUma ferramenta está prestes a ser executada
onToolResultUm resultado de ferramenta está disponível
onApprovalResolvedUma decisão de aprovação é resolvida

O host chama activate quando a extensão lista o evento e tem um main legível.

contributes.tools

CampoDescrição
nameObrigatório. [a-z0-9]+(?:[._-][a-z0-9]+)*
descriptionObrigatório. Mostrado ao modelo
inputSchemaObrigatório. Objeto JSON Schema
outputSchemaOpcional. Objeto JSON Schema
approvalModeOpcional. allowed, need-approval ou need-questions
executionModeOpcional. foreground ou background

O modelo não vê name como está. O host constrói um nome de invocação como extension__{id}__{tool}__{hash}.

contributes.desktop

Requer desktop-ui.

CampoDescrição
css[].pathObrigatório. Arquivo CSS relativo à raiz do pacote
css[].mediaOpcional. Media query CSS
settingsPageOpcional. true, {} ou { title } — adiciona uma entrada de configurações no Desktop

contributes.cli

Requer cli-ui. hooks é um objeto com path, não um array inline:

{
  "hooks": { "path": "cli-hooks.json" }
}

O arquivo deve ser { "hooks": [ ... ] }.

CampoDescrição
slotObrigatório. Um dos slots abaixo
variantOpcional. default, accented, muted, warning, success, danger
tokensOpcional. { foreground?, border?, accent? }
prefixOpcional. String
suffixOpcional. String

Slots: message.user, message.assistant, message.tool, assistant.thinking, input.frame, bottom_form, bottom_form.section, slash_suggestions, approval.panel, questions.panel.

Papéis de token: default, primary, secondary, muted, accent, success, warning, danger.

{
  "hooks": [
    {
      "slot": "input.frame",
      "variant": "accented",
      "tokens": { "border": "accent" },
      "prefix": "[",
      "suffix": "]"
    }
  ]
}

settingsSchema

CampoDescrição
keyObrigatório. Mesmo padrão dos nomes de ferramentas
typeObrigatório. string, boolean, number ou select
titleObrigatório. Rótulo da interface
descriptionOpcional
placeholderOpcional
requiredOpcional. Booleano
defaultValueOpcional. Deve corresponder ao type
optionsObrigatório para select. Matriz de { value, label, description? }

Os valores são string, number, boolean ou null. null limpa uma configuração não obrigatória.

secretSlots

CampoDescrição
keyObrigatório
titleObrigatório
descriptionOpcional
requiredOpcional. Booleano

Desktop armazena segredos no chaveiro do sistema operacional. No caminho do daemon CLI, secrets.set / secrets.delete pode não estar disponível.

activate

main é carregado com import dinâmico. Exporte um dos seguintes:

  • export function activate(ctx) { ... }
  • export default function activate(ctx) { ... }
  • export default { activate }

ctx

CampoDescrição
extension{ id, name, version, directoryPath, manifestPath, main }
hostAPI do host. Desktop implementa showMessageBox. CLI é {}
log(message: string) => void
settingsget(key), getAll(), set(key, value), setAll(values)
secretsget(key), has(key), set(key, value), delete(key) — as chaves devem ser declaradas em secretSlots
activationEventOpcional. { type, detail? }

Valor de retorno

Retorne um objeto, ou exporte os mesmos campos do módulo.

CampoDescrição
toolsRecord<string, (ctx) => unknown>. As chaves são nomes de ferramentas do manifesto
invokeTool(ctx) => unknown. Usado no lugar de tools[name] quando presente
systemPromptFragmento de sistema estático
getSystemPrompt() => string | Promise<string>. Usado no lugar de systemPrompt quando presente
onEvent(event) => void
dispose() => void. Chamado na remoção ou recarga

Manipulador de ferramenta ctx

CampoDescrição
extensionMesma informação de tempo de execução que activate
hostMesma API do host
toolNameNome da ferramenta no manifesto
argumentsObjeto do modelo
logMesmo logger
settingsMesmo acessador de configurações
secretsMesmo acessador de segredos
toolCallIdOpcional
questionsResultOpcional. Definido quando approvalMode é need-questions

Um resultado string é repassado. Outros valores são JSON.stringify(value, null, 2). undefined vira "".

host.showMessageBox no Desktop

CampoDescrição
titleObrigatório. String
messageObrigatório. String
detailOpcional. String
buttonsOpcional. Matriz de strings
cancelIdOpcional. Número
defaultIdOpcional. Número
noLinkOpcional. Booleano
typeOpcional. none, info, error, question, warning
export function activate(ctx) {
  return {
    systemPrompt: "Use lookup_item when the user asks for an item by id.",
    async invokeTool({ toolName, arguments: args, settings, secrets }) {
      if (toolName !== "lookup_item") {
        throw new Error(`Unknown tool: ${toolName}`);
      }
      const region = await settings.get("region");
      const token = await secrets.get("api_token");
      return { id: args.id, region, hasToken: Boolean(token) };
    },
    dispose() {
      ctx.log("example-extension disposed");
    },
  };
}

Instalação

  • ZIP — o arquivo deve conter exatamente um package.json (pode estar em um subdiretório). Importe com spirit extension import ./extension.zip ou Configurações → Extensões.
  • Tarball do Marketplace — a raiz do arquivo deve conter um diretório package/.

supportedHosts deve incluir o host atual. Uma segunda instalação do mesmo id não substitui a cópia existente por padrão. Consulte Marketplace para canais e a interface de instalação.

Publicar no registro oficial

O repositório SpiritAgents/registry é um índice de marketplace. Ele não hospeda fonte de extensões, dist, arquivos ZIP ou tarballs.

Execute estas etapas em ordem:

  1. Publique um pacote npm público.
  2. Abra um pull request que liste esse pacote.

1. Publique o pacote npm

O package.json publicado é a fonte da verdade, especialmente spiritExtension. O construtor do registro requer:

  • spiritExtension.schemaVersion
  • spiritExtension.displayName
  • spiritExtension.supportedHosts
  • spiritExtension.requestedCapabilities

Ele também lê name, version, description, author, repository, homepage, keywords e o opcional spiritExtension.icon. Se você definir icon, inclua esse arquivo no pacote publicado. Um objeto spiritExtension ausente faz a construção do registro falhar para essa versão.

Exemplo oficial: @spiritagent/extension-system-message-demo (spiritagent.system-message-demo).

2. Liste o pacote

Crie registry/extensions/<extension-id>/ com:

ArquivoDescrição
entry.jsonGovernança do marketplace
README.mdTexto de detalhes do marketplace

Não edite estes manualmente (regere-os):

  • registry/catalog.json
  • registry/extensions/<extension-id>/detail.json

extensionId precisa de pelo menos dois segmentos separados por pontos, letras minúsculas e dígitos, com pontos ou hífens dentro de um segmento. Exemplos: spiritagent.system-message-demo, yourteam.some-extension. packageName e extensionId devem ser únicos no repositório.

entry.json

CampoDescrição
schemaVersionObrigatório. 1
extensionIdObrigatório. Consulte as regras acima
packageNameObrigatório. Nome do pacote npm
statusObrigatório. listed, hidden, deprecated ou blocked
featuredObrigatório. Booleano
defaultVersionObrigatório. String de versão padrão
defaultReviewStatusObrigatório. unverified, verified ou revoked
versionsObrigatório. Pelo menos um item

Cada item de versions[]:

CampoDescrição
versionObrigatório
channelObrigatório. stable, preview ou experimental
reviewStatusObrigatório. unverified, verified ou revoked
changelogOpcional. { summary, body } — ambos obrigatórios quando presentes
{
  "schemaVersion": 1,
  "extensionId": "example.spirit-extension",
  "packageName": "@example/spirit-extension",
  "status": "listed",
  "featured": false,
  "defaultVersion": "0.1.0",
  "defaultReviewStatus": "unverified",
  "versions": [
    {
      "version": "0.1.0",
      "channel": "stable",
      "reviewStatus": "unverified",
      "changelog": {
        "summary": "Initial public release.",
        "body": "- Initial public release."
      }
    }
  ]
}

O README do marketplace deve cobrir o que a extensão faz, o nome do pacote, a versão padrão aprovada, a compatibilidade de host e capacidade e notas para os leitores do marketplace.

Gere arquivos derivados localmente:

./scripts/build-registry.ps1

O script busca metadados do npm para as versões listadas, reconstrói catalog.json e cada detail.json e valida a consistência.

Pull request

Inclua entry.json, o README.md do marketplace e os catalog.json / detail.json regenerados. Liste apenas versões que já são públicas no npm. Defina reviewStatus e channel com precisão. Novas versões geralmente começam como unverified.

Não faça commit de árvores de origem de extensões, dist, arquivos ZIP, tarballs ou outros artefatos binários.

Abrir um pull request não garante a listagem. A revisão pode solicitar alterações antes que uma versão seja aprovada ou verificada.