擴充功能
套件佈局、spiritExtension 欄位、啟動 API,以及在官方註冊表中的列出方式。
擴充功能是一個包含 package.json 的資料夾,其中含有 spiritExtension。Spirit 會為每個使用者和每個主機安裝它,而不是放在工作區的 .spirit/ 目錄下。
| 主機 | 路徑 |
|---|---|
| Desktop | {spiritDataDir}/extensions/desktop/ |
| CLI | {spiritDataDir}/extensions/cli/ |
這與 Skills (SKILL.md 資料夾)、MCP (外部伺服器) 和 Hooks (hooks.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.json 的 name 是擴充功能 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、工具執行或系統提示時為必要 |
main、spiritExtension.icon、CSS 路徑和 CLI 鉤子路徑必須是相對的,且必須位於套件內部。
spiritExtension
| 欄位 | 描述 |
|---|---|
schemaVersion | 選用。預設為 1。僅支援 1 |
displayName | 必要。使用者可見名稱 |
icon | 選用。相對於套件根目錄的路徑 |
supportedHosts | 必要。非空的 cli 和/或 desktop 陣列 |
activationEvents | 選用。請參閱 啟動事件 |
requestedCapabilities | 選用。請參閱 功能 |
contributes | 選用。tools、desktop 和/或 cli |
settingsSchema | 選用。設定定義 |
secretSlots | 選用。密鑰槽定義 |
功能
| 值 | 執行環境 |
|---|---|
tool-definitions | 需要搭配 tool-execution 才能將 contributes.tools 暴露給模型 |
tool-execution | 需要搭配 tool-definitions 才能執行那些工具 |
system-prompt | 需要搭配 main 才能貢獻系統提示片段 |
desktop-ui | 必須與 contributes.desktop 配對 |
cli-ui | 必須與 contributes.cli 配對 |
approval-flow | 僅宣告。核准由每個工具的 approvalMode 驅動 |
questions-flow | 僅宣告。問題由 approvalMode: need-questions 驅動 |
settings | 僅宣告。設定來自 settingsSchema |
secret-storage | 與 secretSlots 搭配使用 |
structured-results | 僅宣告 |
desktop-ui / cli-ui 和對應的 contributes 區塊必須同時存在或同時不存在。
啟動事件
| 事件 | 觸發時機 |
|---|---|
onStartup | 主機預熱 |
onExtensionInstalled | 在 ZIP 或 marketplace 安裝之後 |
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 | 選填。allowed、need-approval 或 need-questions |
executionMode | 選填。foreground 或 background |
模型不會直接看到 name。主機會建構一個呼叫名稱,例如 extension__{id}__{tool}__{hash}。
contributes.desktop
需要 desktop-ui。
| 欄位 | 描述 |
|---|---|
css[].path | 必填。相對於套件根目錄的 CSS 檔案 |
css[].media | 選填。CSS media query |
settingsPage | 選填。true、{} 或 { title } — 新增 Desktop 設定項目 |
contributes.cli
需要 cli-ui。hooks 是帶有 path 的物件,不是內聯陣列:
{
"hooks": { "path": "cli-hooks.json" }
}檔案必須是 { "hooks": [ ... ] }。
| 欄位 | 說明 |
|---|---|
slot | 必要。下列插槽之一 |
variant | 選用。default、accented、muted、warning、success、danger |
tokens | 選用。{ foreground?, border?, accent? } |
prefix | 選用。字串 |
suffix | 選用。字串 |
插槽:message.user、message.assistant、message.tool、assistant.thinking、input.frame、bottom_form、bottom_form.section、slash_suggestions、approval.panel、questions.panel。
Token 角色:default、primary、secondary、muted、accent、success、warning、danger。
{
"hooks": [
{
"slot": "input.frame",
"variant": "accented",
"tokens": { "border": "accent" },
"prefix": "[",
"suffix": "]"
}
]
}settingsSchema
| 欄位 | 說明 |
|---|---|
key | 必要。與工具名稱的模式相同 |
type | 必要。string、boolean、number 或 select |
title | 必要。UI 標籤 |
description | 選用 |
placeholder | 選用 |
required | 選用。布林值 |
defaultValue | 選用。必須符合 type |
options | select 必填。{ value, label, description? } 的陣列 |
值為 string、number、boolean 或 null。null 會清除非必要設定。
secretSlots
| 欄位 | 說明 |
|---|---|
key | 必要 |
title | 必要 |
description | 選用 |
required | 選用。布林值 |
Desktop 將秘密儲存在作業系統鑰匙圈中。在 CLI 守護程式路徑下,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 |
settings | get(key)、getAll()、set(key, value)、setAll(values) |
secrets | get(key)、has(key)、set(key, value)、delete(key) — 金鑰必須在 secretSlots 中宣告 |
activationEvent | 可選。{ type, detail? } |
回傳值
回傳一個物件,或從模組匯出相同的欄位。
| 欄位 | 描述 |
|---|---|
tools | Record<string, (ctx) => unknown>。鍵為 manifest 工具名稱 |
invokeTool | (ctx) => unknown。當存在時,用來取代 tools[name] |
systemPrompt | 靜態系統片段 |
getSystemPrompt | () => string | Promise<string>。當存在時,用來取代 systemPrompt |
onEvent | (event) => void |
dispose | () => void。在移除或重新載入時呼叫 |
工具處理器 ctx
| 欄位 | 描述 |
|---|---|
extension | 與 activate 相同的執行時期資訊 |
host | 相同的主機 API |
toolName | Manifest 工具名稱 |
arguments | 來自模型的物件 |
log | 相同的記錄器 |
settings | 相同的設定存取器 |
secrets | 相同的密鑰存取器 |
toolCallId | 可選 |
questionsResult | 可選。當 approvalMode 為 need-questions 時設定 |
string 結果會直接傳遞。其他值會轉為 JSON.stringify(value, null, 2)。undefined 變成 ""。
Desktop host.showMessageBox
| 欄位 | 描述 |
|---|---|
title | 必填。字串 |
message | 必填。字串 |
detail | 可選。字串 |
buttons | 可選。字串陣列 |
cancelId | 可選。數字 |
defaultId | 可選。數字 |
noLink | 可選。布林值 |
type | 可選。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");
},
};
}安裝
- ZIP — 壓縮檔必須恰好包含一個
package.json(它可以位於子目錄中)。使用spirit extension import ./extension.zip或 設定 → 擴充功能 匯入。 - Marketplace tarball — 壓縮檔根目錄必須包含
package/目錄。
supportedHosts 必須包含目前的主機。相同 id 的第二次安裝預設不會取代現有副本。有關頻道和安裝介面,請參閱 Marketplace。
發布到官方登錄檔
SpiritAgents/registry 儲存庫是 marketplace 索引。它不託管擴充功能原始碼、dist、ZIP 檔案或 tarball。
請依序執行下列步驟:
- 發布一個公開的 npm 套件。
- 開啟一個列出該套件的 pull request。
1. 發布 npm 套件
發布的 package.json 是主要依據,尤其是 spiritExtension。註冊表建置器需要:
spiritExtension.schemaVersionspiritExtension.displayNamespiritExtension.supportedHostsspiritExtension.requestedCapabilities
它也會讀取 name、version、description、author、repository、homepage、keywords 以及選用的 spiritExtension.icon。如果您設定了 icon,請將該檔案包含在發布的套件中。缺少 spiritExtension 物件會導致該版本的註冊表建置失敗。
官方範例:@spiritagent/extension-system-message-demo(spiritagent.system-message-demo)。
2. 列出套件
建立 registry/extensions/<extension-id>/,內容包含:
| 檔案 | 說明 |
|---|---|
entry.json | 市集治理 |
README.md | 市集詳細資訊文字 |
請勿手動編輯這些(請重新產生):
registry/catalog.jsonregistry/extensions/<extension-id>/detail.json
extensionId 需要至少兩個以點分隔的區段,使用小寫字母和數字,區段內可包含點或連字號。範例:spiritagent.system-message-demo、yourteam.some-extension。packageName 和 extensionId 在儲存庫中必須是唯一的。
entry.json
| 欄位 | 說明 |
|---|---|
schemaVersion | 必要。1 |
extensionId | 必要。請參閱上述規則 |
packageName | 必要。npm 套件名稱 |
status | 必要。listed、hidden、deprecated 或 blocked |
featured | 必要。布林值 |
defaultVersion | 必要。預設版本字串 |
defaultReviewStatus | 必要。unverified、verified 或 revoked |
versions | 必要。至少一個項目 |
每個 versions[] 項目:
| 欄位 | 說明 |
|---|---|
version | 必要 |
channel | 必要。stable、preview 或 experimental |
reviewStatus | 必要。unverified、verified 或 revoked |
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 上公開的版本。準確設定 reviewStatus 和 channel。新版本通常以 unverified 開始。
請勿提交擴充功能原始碼樹、dist、ZIP 檔案、tarball 或其他二進位成品。
開啟 pull request 並不保證會上架。在版本獲得核准或驗證之前,審查可能會要求變更。