---
title: 资源打包与分发
description: 将员工、团队、应用或 SKILL 的定义和文件整理成可接收的包。
lastVerified: 2026-10-22
---

# 6.9 资源打包与分发

本篇说明四类资源共用的文件组织和打包方法。先完成[员工](https://docs.teloa.ai/v/0.2.6/markdown/develop/employees.md)、[团队](https://docs.teloa.ai/v/0.2.6/markdown/develop/teams.md)、[应用](https://docs.teloa.ai/v/0.2.6/markdown/develop/apps.md)或[SKILL](https://docs.teloa.ai/v/0.2.6/markdown/develop/skills.md)中的一个例子，再按这里的步骤更新和分发。

## 先看两层文件

| 文件 | 用来做什么 |
| --- | --- |
| `employee.json`、`team.json`、`app.json` 或 `skill.json` | 接收方选择导入的分享文件，包含实际文件正文 |
| `sources/teloa.json` | 内部资源清单，列出资源、固定版本、文件路径和关系 |
| `sources/roles/`、`skills/` 等 | 作者修改的源文件，重新打包后进入分享文件 |

[下载四类资源示例](https://docs.teloa.ai/v/0.2.6/markdown/guides/sharing.md#%E7%A6%BB%E7%BA%BF%E5%88%86%E4%BA%AB)，每份 ZIP 已带完整 JSON、`sources/` 与 `pack.mjs`。分享文件和内部清单不是同一份 JSON。

## 一份完整的内部清单

应用示例的 `sources/teloa.json` 只声明一项技能：

```json
{
  "format": "teloa.business-package/v2",
  "id": "example-app-brief",
  "version": "1.0.1",
  "title": "Evidence brief app",
  "description": "A local authoring example with no account connection or automatic execution.",
  "domain": "general",
  "scope": "general",
  "resources": [
    {
      "id": "evidence-brief",
      "kind": "skill",
      "title": "evidence-brief",
      "version": "1.0.1",
      "required": true,
      "source": {
        "kind": "local",
        "path": "skills/evidence-brief/SKILL.md"
      }
    }
  ],
  "relations": [],
  "entrypoints": [
    "evidence-brief"
  ]
}
```

对应正文位于 `sources/skills/evidence-brief/SKILL.md`。员工和团队再添加 `role` 资源，并用 `role-skill` 关系连接方法；其他资源和版本字段见[格式参考](https://docs.teloa.ai/v/0.2.6/markdown/develop/formats.md)。

代码里的 `teloa.business-package` 是清单格式名，不是第五类产品。外层用 `subject` 指明 AI 员工、AI 团队、应用或 SKILL：员工恰好一位，团队至少两位，应用不含员工，独立 SKILL 恰好一项技能。

## 修改后重新打包

例如修改员工说明后，在解压目录运行：

```sh
node pack.mjs employee.json
```

应用、团队和技能分别把参数换成 `app.json`、`team.json`、`skill.json`。脚本读取外层已列出的文件，将 `sources/` 正文写回分享文件：

```js
import {readFile, writeFile, realpath} from 'node:fs/promises'
import {resolve, sep} from 'node:path'
const file = process.argv[2]
if (!file) throw Error('Usage: node pack.mjs employee.json')
const share = JSON.parse(await readFile(file, 'utf8'))
const sourceRoot = await realpath('sources')
for (const item of share.files) {
  if (typeof item.path !== 'string' || item.path.includes('\\') ||
      /[\x00-\x1f\x7f]/.test(item.path) ||
      item.path.split('/').some(part => !part || part === '.' || part === '..')) {
    throw Error('Unsafe source path')
  }
  const source = await realpath(resolve(sourceRoot, item.path))
  if (!source.startsWith(sourceRoot + sep)) throw Error('Source escapes the package')
  item.text = await readFile(source, 'utf8')
}
const manifest = JSON.parse(share.files.find(f => f.path === 'teloa.json').text)
share.id = manifest.id
share.version = manifest.version
await writeFile(file, JSON.stringify(share, null, 2) + '\n')
```

新增资源时，同时修改内部 `resources`、`relations` 和外层 `files` 列表，并创建相应源文件。修改实际内容后提高包版本；改变了资源定义时也更新该资源版本与固定引用。脚本同步外层与内部的包身份和版本，不自动决定所有资源的版本。

## 格式检查 {#validate-authoring-examples}

在已准备依赖的 Teloa 源码根目录，将要检查的分享 JSON 复制到当前目录，再运行。检查单份文件时只在数组中列出这一份；以下例子检查四份：

```sh
node --input-type=module <<'JS'
import {readFileSync} from 'node:fs'
import {readTemplateShare} from './packages/contract/src/template-share.mjs'
for (const subject of ['employee', 'team', 'app', 'skill']) {
  const value = JSON.parse(readFileSync(`${subject}.json`, 'utf8'))
  console.log(readTemplateShare(value).subject)
}
JS
```

应输出 `employee`、`team`、`app`、`skill`。这是格式读取检查，不会添加或执行资源。没有源码环境时，可直接在员工页的 **导入模板** 中选择分享 JSON 查看预览。

## 接收与分发

检查预览中的成员、技能、资料和来源，再明确添加到测试业务。员工默认暂停；按实际状态配置模型、安装能力、连接账号和授权。完成原教程的小任务后，再通过[离线文件或在线链接](https://docs.teloa.ai/v/0.2.6/markdown/guides/sharing.md)分发。

分享 JSON 最多 8 MiB，单份文件正文最多 2 MiB。密码、模型密钥、账号会话和执行授权不放进包里；发布前检查随附资料和正文是否有权公开。

## 需要完整业务配置时

内部清单 v2 组织常规资源，v3 增加固定模型依赖，v4 增加完整业务配置。它们是按所需能力选择的格式，不是要求作者把版本号逐级升级。完整配置包含对象、视图、页面与看板；不能把真实业务记录、同步账号或默认动作授权一起分发。字段与导入限制见[格式参考](https://docs.teloa.ai/v/0.2.6/markdown/develop/formats.md)。

若直接导入内部资源目录或 ZIP，使用市场的 **创建 > 导入模板** 流程，选择清单与随附文件；若接收本篇的分享 JSON，使用员工页的 **导入模板**。两种入口读取的文件结构不同。
