Spirit Agent
下载

扩展

包结构、spiritExtension 字段、activate API,以及上架官方 registry。

扩展是带 package.json 且含 spiritExtension 的文件夹。Spirit 按用户、按宿主安装,不放在工作区 .spirit/ 下。

宿主路径
Desktop{spiritDataDir}/extensions/desktop/
CLI{spiritDataDir}/extensions/cli/

这与 SkillsSKILL.md 文件夹)、MCP(外部 server)、Hookshooks.json 脚本)不同。contributes.cli.hooks 用来给 CLI TUI 槽位加样式,不是 hooks.json

没有按扩展的启用开关。安装后即参与贡献。CLI 面板里的切换是占位。

包结构

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
      }
    ]
  }
}

package.jsonname 就是扩展 id。须匹配 ^(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$

package.json 字段

参数说明
name必填。npm 包名;用作扩展 id
version必填。版本字符串
spiritExtension必填。对象。见下方
description可选。字符串
author可选。字符串或 { name }
homepage可选。字符串
main可选。activate 入口的相对路径。使用 activationEvents、工具执行或 system prompt 时必填

mainspiritExtension.icon、CSS 路径和 CLI hook 路径必须是相对路径,且须留在包内。

spiritExtension

参数说明
schemaVersion可选。默认 1。仅支持 1
displayName必填。用户可见名称
icon可选。相对包根的路径
supportedHosts必填。非空数组,值为 cli 和/或 desktop
activationEvents可选。见激活事件
requestedCapabilities可选。见能力
contributes可选。toolsdesktop 和/或 cli
settingsSchema可选。设置项定义
secretSlots可选。密钥槽定义

能力

运行时
tool-definitions须与 tool-execution 同时声明,才会把 contributes.tools 暴露给模型
tool-execution须与 tool-definitions 同时声明,才会执行这些工具
system-prompt须与 main 同时具备,才会贡献 system 片段
desktop-ui必须与 contributes.desktop 成对出现
cli-ui必须与 contributes.cli 成对出现
approval-flow仅声明。审批由各工具的 approvalMode 驱动
questions-flow仅声明。问卷由 approvalMode: need-questions 驱动
settings仅声明。设置来自 settingsSchema
secret-storagesecretSlots 一起使用
structured-results仅声明

desktop-ui / cli-ui 与对应的 contributes 块必须同时有或同时没有。

激活事件

事件何时触发
onStartup宿主预热
onExtensionInstalledZIP 或市场安装之后
onSessionOpened会话变为活动
onSessionReset会话重置
onUserMessage用户提交消息
onToolCall工具即将运行
onToolResult工具结果可用
onApprovalResolved审批决定已解析

扩展列出该事件且有可读的 main 时,宿主会调用 activate

contributes.tools

参数说明
name必填。[a-z0-9]+(?:[._-][a-z0-9]+)*
description必填。展示给模型
inputSchema必填。JSON Schema 对象
outputSchema可选。JSON Schema 对象
approvalMode可选。allowedneed-approvalneed-questions
executionMode可选。foregroundbackground

模型看到的不是原始 name。宿主会生成形如 extension__{id}__{tool}__{hash} 的调用名。

contributes.desktop

需要 desktop-ui

参数说明
css[].path必填。相对包根的 CSS 文件
css[].media可选。CSS media query
settingsPage可选。true{}{ title } — 在 Desktop 设置中增加入口

contributes.cli

需要 cli-uihooks 是带 path 的对象,不是内联数组:

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

该文件必须是 { "hooks": [ ... ] }

参数说明
slot必填。下列槽位之一
variant可选。defaultaccentedmutedwarningsuccessdanger
tokens可选。{ foreground?, border?, accent? }
prefix可选。字符串
suffix可选。字符串

槽位:message.usermessage.assistantmessage.toolassistant.thinkinginput.framebottom_formbottom_form.sectionslash_suggestionsapproval.panelquestions.panel

Token 角色:defaultprimarysecondarymutedaccentsuccesswarningdanger

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

settingsSchema

参数说明
key必填。与工具名相同的模式
type必填。stringbooleannumberselect
title必填。UI 标签
description可选
placeholder可选
required可选。布尔值
defaultValue可选。须与 type 匹配
optionsselect 时必填。{ value, label, description? } 数组

值为 stringnumberbooleannullnull 会清空非必填项。

secretSlots

参数说明
key必填
title必填
description可选
required可选。布尔值

Desktop 把密钥存在操作系统钥匙串。在 CLI daemon 路径上,secrets.set / secrets.delete 可能不可用。

activate

main 通过动态 import 加载。导出以下之一:

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

ctx

参数说明
extension{ id, name, version, directoryPath, manifestPath, main }
host宿主 API。Desktop 实现 showMessageBox。CLI 为 {}
log(message: string) => void
settingsget(key)getAll()set(key, value)setAll(values)
secretsget(key)has(key)set(key, value)delete(key) — 键必须在 secretSlots 中声明
activationEvent可选。{ type, detail? }

返回值

返回一个对象,或从模块导出相同字段。

参数说明
toolsRecord<string, (ctx) => unknown>。键是清单里的工具名
invokeTool(ctx) => unknown。存在时优先于 tools[name]
systemPrompt静态 system 片段
getSystemPrompt() => string | Promise<string>。存在时优先于 systemPrompt
onEvent(event) => void
dispose() => void。卸载或重载时调用

工具处理函数的 ctx

参数说明
extensionactivate 相同的运行时信息
host同一宿主 API
toolName清单中的工具名
arguments模型传入的对象
log同一日志函数
settings同一设置访问器
secrets同一密钥访问器
toolCallId可选
questionsResult可选。approvalModeneed-questions 时由宿主注入

string 结果原样返回。其他值会 JSON.stringify(value, null, 2)undefined 变成 ""

Desktop host.showMessageBox

参数说明
title必填。字符串
message必填。字符串
detail可选。字符串
buttons可选。字符串数组
cancelId可选。数字
defaultId可选。数字
noLink可选。布尔值
type可选。noneinfoerrorquestionwarning
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");
    },
  };
}

安装

  • ZIP — 压缩包里必须恰好有一个 package.json(可以在子目录中)。用 spirit extension import ./extension.zip设置 → 扩展 导入。
  • 市场 tarball — 压缩包根目录下必须有 package/ 目录。

supportedHosts 必须包含当前宿主。默认不会用同 id 的第二次安装覆盖已有副本。通道和安装界面见市场

上架官方扩展注册处

SpiritAgents/registry 仓库是市场索引。它不托管扩展源码、dist、ZIP 或 tarball。

按此顺序:

  1. 公开发布 npm 包。
  2. 提交将该包列入索引的 pull request。

1. 发布 npm 包

已发布的 package.json 是元数据来源,尤其是 spiritExtension。registry 构建会读取:

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

同时会读 nameversiondescriptionauthorrepositoryhomepagekeywords,以及可选的 spiritExtension.icon。若设置了 icon,须把该文件打进发布包。缺少 spiritExtension 时,该版本的 registry 构建会失败。

官方示例:@spiritagent/extension-system-message-demospiritagent.system-message-demo)。

2. 列入索引

registry/extensions/<extension-id>/ 下创建:

文件说明
entry.json市场治理数据
README.md市场详情文案

不要手改这些文件(重新生成):

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

extensionId 至少两段、用点分隔,小写字母和数字,段内可用点或连字符。例如:spiritagent.system-message-demoyourteam.some-extensionpackageNameextensionId 在仓库内都必须唯一。

entry.json

参数说明
schemaVersion必填。1
extensionId必填。见上方规则
packageName必填。npm 包名
status必填。listedhiddendeprecatedblocked
featured必填。布尔值
defaultVersion必填。默认版本字符串
defaultReviewStatus必填。unverifiedverifiedrevoked
versions必填。至少一项

每条 versions[]

参数说明
version必填
channel必填。stablepreviewexperimental
reviewStatus必填。unverifiedverifiedrevoked
changelog可选。{ summary, body } — 出现时两者都必填
{
  "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."
      }
    }
  ]
}

市场 README 应说明扩展做什么、包名、默认批准版本、宿主与能力兼容性,以及市场读者需要看到的备注。

在本地重新生成派生文件:

./scripts/build-registry.ps1

脚本会拉取所列版本的 npm 元数据,重建 catalog.json 和各 detail.json,然后校验一致性。

Pull request

包含 entry.json、市场 README.md,以及重新生成的 catalog.json / detail.json。只列入已在 npm 上公开的版本。准确填写 reviewStatuschannel。新版本通常从 unverified 开始。

不要提交扩展源码树、dist、ZIP、tarball 或其他二进制产物。

提交 pull request 不保证上架。审核可能在批准或 verified 之前要求修改。