@xiongtao.xt/tau-plugins 0.31.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +2 -2
- package/client/{chunk-ECEBBIHP.js → chunk-SVY5LBAT.js} +44 -0
- package/docs/README.md +43 -0
- package/docs/ai.md +169 -0
- package/docs/backend.md +168 -0
- package/docs/editor.md +457 -0
- package/docs/excerpts.md +126 -0
- package/docs/flashcards.md +127 -0
- package/docs/getting-started.md +134 -0
- package/docs/mcp.md +173 -0
- package/docs/plugin-basics.md +209 -0
- package/docs/providers/README.md +108 -0
- package/docs/providers/images.md +65 -0
- package/docs/providers/publish.md +144 -0
- package/docs/providers/sync.md +75 -0
- package/docs/providers/tts.md +62 -0
- package/docs/providers/upload.md +77 -0
- package/docs/providers/video.md +118 -0
- package/docs/release.md +130 -0
- package/docs/services.md +159 -0
- package/docs/site-data.md +90 -0
- package/docs/skills.md +129 -0
- package/docs/storage-and-network.md +62 -0
- package/docs/ui.md +335 -0
- package/docs/user-data.md +389 -0
- package/docs/whiteboard.md +290 -0
- package/package.js +1 -1
- package/package.json +1 -1
- package/publish-artifacts.js +1 -1
- package/types/packages/plugins/src/categories.d.ts +3 -0
- package/types/packages/plugins/src/contract.d.ts +0 -2
- package/types/packages/plugins/src/index.d.ts +0 -1
- package/types/packages/plugins/src/package.d.ts +2 -0
- package/types/packages/ui/src/primitives/Tabs.d.ts +1 -3
- package/AI.md +0 -116
- package/API.md +0 -881
- package/BACKEND.md +0 -68
- package/DEVELOPMENT.md +0 -173
- package/EDITOR.md +0 -192
- package/FLASHCARDS.md +0 -92
- package/IMAGES.md +0 -16
- package/MCP.md +0 -118
- package/NOTIFICATIONS.md +0 -48
- package/PUBLISH-DATA.md +0 -48
- package/PUBLISH.md +0 -50
- package/SERVICES.md +0 -119
- package/SYNC.md +0 -37
- package/TTS.md +0 -20
- package/UPLOAD.md +0 -35
- package/VIDEO.md +0 -65
- package/WHITEBOARD.md +0 -115
- package/types/packages/plugins/src/skills.d.ts +0 -8
package/docs/release.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# 发布与更新
|
|
2
|
+
|
|
3
|
+
插件写好之后,发布到[插件中心](https://plugins.taunote.app),用户就能在 Tau 中搜索、安装和更新它。这一篇介绍发布前的准备、第一次发布、之后的版本更新,以及如何升级 SDK。
|
|
4
|
+
|
|
5
|
+
## 发布前的准备
|
|
6
|
+
|
|
7
|
+
### 插件详情页的内容
|
|
8
|
+
|
|
9
|
+
插件中心和 Tau 中的插件详情页,内容都来自插件包本身,不需要在网站上另外填写:
|
|
10
|
+
|
|
11
|
+
| 显示的内容 | 来自 |
|
|
12
|
+
| ---------------- | --------------------------------------------------- |
|
|
13
|
+
| 名称、简介、版本 | `manifest.json` 的 `name`、`description`、`version` |
|
|
14
|
+
| 分类、搜索关键词 | `manifest.json` 的 `categories`、`keywords` |
|
|
15
|
+
| 「说明」 | `README.md` |
|
|
16
|
+
| 「更新日志」 | `CHANGELOG.md` |
|
|
17
|
+
|
|
18
|
+
### README:写给使用者
|
|
19
|
+
|
|
20
|
+
`README.md` 会原样显示给用户。写清楚三件事:
|
|
21
|
+
|
|
22
|
+
- 插件能做什么。
|
|
23
|
+
- 怎么开始用:在哪里找到入口、需要哪些设置。
|
|
24
|
+
- 常见问题:例如需要在第三方服务做的准备、常见的错误提示。
|
|
25
|
+
|
|
26
|
+
不要写开发过程、内部实现或代码结构,用户不关心这些。
|
|
27
|
+
|
|
28
|
+
### CHANGELOG:写给使用者
|
|
29
|
+
|
|
30
|
+
`CHANGELOG.md` 显示在插件详情的「更新日志」里,发布时也会作为 GitHub Release 的说明。
|
|
31
|
+
|
|
32
|
+
- 每个版本以 `## 版本号` 开头,下面逐条列出。
|
|
33
|
+
- 写用户能感知的变化:多了什么功能、修好了什么问题、升级后要注意什么。用界面上的叫法,比如「设置 → 同步」。
|
|
34
|
+
- 不写 SDK 版本、构建方式、重构、测试之类的内部变化。确实没有可感知的变化时,写「维护更新,使用上没有变化」。
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
## 1.2.0
|
|
38
|
+
|
|
39
|
+
- 书架可以按「有笔记」筛选了。
|
|
40
|
+
- 修复同步中途断网后,部分划线不显示的问题。
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 自查清单
|
|
44
|
+
|
|
45
|
+
- 在 Tau 中完整试过:启用、使用每项功能、保存数据、停用、重启后再用。
|
|
46
|
+
- 申请的权限都是功能需要的,并在 README 中说明了用途。
|
|
47
|
+
- 源码和插件包里没有密钥、令牌或你机器上的路径。
|
|
48
|
+
- `manifest.json` 和 `package.json` 的版本一致。
|
|
49
|
+
|
|
50
|
+
## 自动发布
|
|
51
|
+
|
|
52
|
+
模板自带的 `.github/workflows/release.yml` 会在你推送版本 tag 后自动构建插件,把 ZIP 发布到 GitHub Release,并提交到插件中心。整个过程不需要配置任何密钥。
|
|
53
|
+
|
|
54
|
+
### 发布一个版本
|
|
55
|
+
|
|
56
|
+
先修改 `manifest.json` 和 `package.json` 中的版本号并提交,然后打 tag 推送:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
git add manifest.json package.json CHANGELOG.md
|
|
60
|
+
git commit -m "chore: release 1.1.0"
|
|
61
|
+
git tag v1.1.0
|
|
62
|
+
git push origin HEAD
|
|
63
|
+
git push origin v1.1.0
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- tag 可以写成 `v1.1.0` 或 `1.1.0`,必须与两个文件中的版本一致,否则发布失败。
|
|
67
|
+
- 只在本地打 tag 不会触发发布,必须推送到 GitHub。
|
|
68
|
+
- 仓库需要启用 GitHub Actions,并允许工作流申请 `contents: write` 权限。
|
|
69
|
+
|
|
70
|
+
工作流会依次:安装依赖、运行 `test` 脚本(如果定义了)、构建,然后把 `dist/<插件ID>-<版本>.zip` 上传到同名的 GitHub Release,说明取自 `CHANGELOG.md` 中对应版本的小节(没有时使用 GitHub 自动生成的提交列表),最后把同一个 ZIP 提交到插件中心。
|
|
71
|
+
|
|
72
|
+
### 第一次发布
|
|
73
|
+
|
|
74
|
+
第一次需要在[插件中心](https://plugins.taunote.app)网页上传一次 ZIP 并提交,把插件 ID 绑定到你的 GitHub 仓库。绑定之前,工作流提交到插件中心这一步只会给出提醒,不会让发布失败。
|
|
75
|
+
|
|
76
|
+
### 之后的版本
|
|
77
|
+
|
|
78
|
+
绑定后,每次推送 tag,新版本都会自动进入插件中心的审核队列,不需要再打开网页。插件中心通过 GitHub Actions 的身份令牌确认提交来自已绑定的仓库,其他仓库(包括 fork)无法冒充。
|
|
79
|
+
|
|
80
|
+
- 带[本机后台](backend.md)或 [Skill 脚本](skills.md#附带文件与脚本)的版本会在用户本机执行代码,必须由插件中心人工审核后才会上架,不会自动通过。
|
|
81
|
+
- `v1.1.0-beta.1` 这样的预发布版本只发布到 GitHub Release,标记为 Pre-release,不提交插件中心。
|
|
82
|
+
- 同一个 tag 重新运行是安全的。同一个版本号换了内容会被插件中心拒绝,需要提高版本号。
|
|
83
|
+
- 发布结果和失败日志在仓库的 Actions 页面查看。临时性错误修复后可以重新运行失败的任务;代码有问题时,提高版本号发布新的 tag,不要移动已发布的 tag。
|
|
84
|
+
|
|
85
|
+
## 用户如何更新
|
|
86
|
+
|
|
87
|
+
- 用户从插件中心更新插件。新版本在用户下次完全退出并重新打开 Tau 后生效,生效前可以取消。
|
|
88
|
+
- 新版本启用失败时,用户可以「恢复上一版」。恢复只换回代码,不会回退数据。
|
|
89
|
+
|
|
90
|
+
所以改变存储的数据结构时,要让新版本能读懂旧数据,也尽量让旧版本读到新数据时不出错,见[存储与网络](storage-and-network.md#使用要点)。
|
|
91
|
+
|
|
92
|
+
**插件 ID 永远不要改**。改了 ID,就成了另一个插件:用户需要重新安装,原来保存的数据也读不到。
|
|
93
|
+
|
|
94
|
+
## 升级 SDK
|
|
95
|
+
|
|
96
|
+
模板锁定了 `@tau/plugins` 和 `@tau/ui` 的精确版本。需要使用新版 SDK 提供的能力时再升级。
|
|
97
|
+
|
|
98
|
+
### 1. 允许安装新版本
|
|
99
|
+
|
|
100
|
+
模板的 `pnpm-workspace.yaml` 启用了 pnpm 的发布时间保护,刚发布的包需要等待一段时间才能安装。把要升级的版本加进 `minimumReleaseAgeExclude`,先保留旧版本的条目:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
minimumReleaseAgeExclude:
|
|
104
|
+
- "@xiongtao.xt/tau-plugins@0.29.0" # 旧版本,升级完成后再删
|
|
105
|
+
- "@xiongtao.xt/tau-plugins@<新版本>"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
只为你确认过的版本添加例外,不要关闭整个保护。
|
|
109
|
+
|
|
110
|
+
### 2. 更新依赖
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
pnpm add @tau/plugins@npm:@xiongtao.xt/tau-plugins@<新版本> --save-exact
|
|
114
|
+
pnpm install --frozen-lockfile
|
|
115
|
+
pnpm build
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. 清理
|
|
119
|
+
|
|
120
|
+
构建通过后,从 `minimumReleaseAgeExclude` 中删除旧版本的条目,再运行一次 `pnpm install --frozen-lockfile`。提交 `package.json`、`pnpm-lock.yaml` 和 `pnpm-workspace.yaml`。
|
|
121
|
+
|
|
122
|
+
各版本的变化见已安装包中的 `node_modules/@tau/plugins/CHANGELOG.md`。
|
|
123
|
+
|
|
124
|
+
- React 保持模板锁定的版本,它由 Tau 提供,版本不一致可能导致插件无法运行。
|
|
125
|
+
- 新能力需要用户的 Tau 版本支持时,同时提高 manifest 的 `minAppVersion`。
|
|
126
|
+
- 升级后在 Tau 中重新验证一遍主要功能。
|
|
127
|
+
|
|
128
|
+
### 同步模板的更新
|
|
129
|
+
|
|
130
|
+
用模板创建的仓库不会自动跟随模板更新。需要时,对照[上游模板](https://github.com/LastKnightCoder/tau-plugin-template)手动同步 `build.mjs`、`install-local.mjs`、`.github/workflows/release.yml` 和 `docs/`,保留你自己的插件 ID、源码、README 和更新日志。同步前先提交或备份自己的改动。
|
package/docs/services.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# 编译与转换服务
|
|
2
|
+
|
|
3
|
+
`context.services` 提供几种由 Tau 执行的编译与转换能力:
|
|
4
|
+
|
|
5
|
+
| 服务 | 用途 |
|
|
6
|
+
| ------------------------ | ------------------------------------------------------------------ |
|
|
7
|
+
| `tailwind.compile` | 从源码中提取 Tailwind 类名,生成 CSS |
|
|
8
|
+
| `markdown.deserialize` | Markdown → 编辑器节点 |
|
|
9
|
+
| `markdown.serialize` | 编辑器节点 → Markdown |
|
|
10
|
+
| `markdown.render` | Markdown → HTML |
|
|
11
|
+
| `ffmpeg.run` | 用 FFmpeg 处理音视频 |
|
|
12
|
+
| `videoExtractor.probe` | 查询视频网页的标题与可下载格式,见[视频提供方](providers/video.md) |
|
|
13
|
+
| `git.publishSnapshot` 等 | 博客发布用的 Git 服务,见[发布提供方](providers/publish.md) |
|
|
14
|
+
|
|
15
|
+
这些服务只处理你传入的数据并返回结果:不读写用户的笔记,不弹出文件选择,也不会自动把样式注入页面。
|
|
16
|
+
|
|
17
|
+
## 取消与错误
|
|
18
|
+
|
|
19
|
+
所有服务都是异步方法,最后一个参数可以传 `{ signal }`:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
try {
|
|
24
|
+
const { css } = await context.services.tailwind.compile(
|
|
25
|
+
{ source: '<div class="p-4">Hello</div>', language: "html" },
|
|
26
|
+
{ signal: controller.signal }
|
|
27
|
+
);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
// 用户点击「取消」时:controller.abort()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- 插件停用时,进行中的任务会自动取消,不需要另外传 `context.signal`。
|
|
36
|
+
- 失败时抛出 `Error`,`message` 是可以展示给用户的错误信息。不要根据错误文字的内容决定程序流程。
|
|
37
|
+
|
|
38
|
+
## Tailwind
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const { css } = await context.services.tailwind.compile({
|
|
42
|
+
source: '<section class="p-4 rounded-tau-md bg-surface text-ink-1">Hello</section>',
|
|
43
|
+
language: "html",
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- 使用 Tailwind 4,支持 Tau 的语义类(如 `bg-surface`、`text-ink-1`)。
|
|
48
|
+
- `language` 可选 `html`、`tsx`、`jsx`。源码只用来提取类名,不会被执行或编译成 React。
|
|
49
|
+
- 返回的 CSS 只包含主题与工具类,不包含基础样式重置(preflight)。
|
|
50
|
+
- 类名要完整写在源码里,拼接出来的类名提取不到。
|
|
51
|
+
- Tau 语义类依赖 Tau 的 `--tau-*` 主题变量。在 Tau 之外的页面使用这些 CSS 时,需要自己提供这些变量。
|
|
52
|
+
|
|
53
|
+
插件自身固定的界面样式应该在构建时编译好。这个服务适合运行时才知道内容的场景,比如用户写的组件代码。返回的 CSS 由你自己挂到页面上,并在不需要时移除。
|
|
54
|
+
|
|
55
|
+
## Markdown 与编辑器节点
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import type { Descendant } from "@tau/plugins";
|
|
59
|
+
|
|
60
|
+
const parsed = await context.services.markdown.deserialize("# 标题\n\n- [x] 已完成");
|
|
61
|
+
const nodes: Descendant[] = parsed.nodes;
|
|
62
|
+
|
|
63
|
+
const { markdown } = await context.services.markdown.serialize(nodes);
|
|
64
|
+
const { html, css } = await context.services.markdown.render(markdown, { theme: "light" });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- 语法与 Tau 编辑器一致:标题、列表与任务列表、表格、代码、数学公式、图片与媒体、Tau 的扩展语法等。
|
|
68
|
+
- 节点只是数据,与任何一篇笔记都没有关联,也不会写进编辑器。
|
|
69
|
+
- 每次解析可能生成新的节点 ID,不要依赖反复解析保留节点身份。
|
|
70
|
+
- 自己构造节点时按 SDK 的类型来:文本节点是 `{ type: "formatted", text: "..." }`,不是只有 `{ text }`。
|
|
71
|
+
|
|
72
|
+
### 转换结果中的警告
|
|
73
|
+
|
|
74
|
+
三个方法都返回 `warnings`,每项包含 `code`、`message` 和可选的节点路径 `path`。它报告无法识别的节点、HTML 中已知的降级等,但不是完整的无损检查。
|
|
75
|
+
|
|
76
|
+
### 自定义节点
|
|
77
|
+
|
|
78
|
+
服务默认只认识 Tau 内置的节点。要转换你自己的节点,在单次调用中传入 `codecs`(格式见[编辑器扩展 · Markdown 导入导出](editor.md#markdown-导入导出)):
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const result = await context.services.markdown.serialize(nodes, {
|
|
82
|
+
codecs: [
|
|
83
|
+
{
|
|
84
|
+
type: "yourname.note",
|
|
85
|
+
serializer: { toMarkdown: (_node: unknown, children: string) => `> ${children}` },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`codecs` 只对这一次调用生效。插件 `editorCodecs` 中声明的 codec 不会自动加入,需要时显式传入。
|
|
92
|
+
|
|
93
|
+
### HTML 渲染
|
|
94
|
+
|
|
95
|
+
`render` 生成的 HTML:
|
|
96
|
+
|
|
97
|
+
- 不会执行图表、公式排版等需要编译的内容,这些节点可能显示为源码,并返回 `DISPLAY_FALLBACK` 警告;音视频可能显示为链接。
|
|
98
|
+
- 保留原始 HTML 和外部资源链接,**不是经过净化的安全 HTML**。展示来源不可信的内容前,自己做净化。
|
|
99
|
+
- `css` 是这段内容需要的样式,不包含完整的 Tau 页面主题,也不会打包图片附件。
|
|
100
|
+
|
|
101
|
+
## FFmpeg
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const result = await context.services.ffmpeg.run(
|
|
105
|
+
{
|
|
106
|
+
files: [{ name: "input.wav", data: audioBlob }],
|
|
107
|
+
args: ["-i", "input.wav", "-c:a", "pcm_s16le", "output.wav"],
|
|
108
|
+
outputs: [{ name: "output.wav", mimeType: "audio/wav" }],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
onProgress: ({ time }) => console.log("已处理", time, "秒"),
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
const output = result.files[0].data;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| 字段 | 说明 |
|
|
118
|
+
| --------- | ----------------------------------------------------------------------------- |
|
|
119
|
+
| `files` | 输入文件,`{ name, data: Blob }`。`name` 只是这次任务内的文件名,不是本机路径 |
|
|
120
|
+
| `args` | FFmpeg 参数,不包含程序名。含空格的参数作为一个数组元素,不要加 Shell 引号 |
|
|
121
|
+
| `outputs` | 要取回的输出文件,名称与 `args` 中的输出一致,`mimeType` 需要与实际格式相符 |
|
|
122
|
+
|
|
123
|
+
- 文件名不能重复,目录用 `/` 分隔。
|
|
124
|
+
- 文件全部经过内存传输,适合能放进内存的素材,不支持大文件流式处理。
|
|
125
|
+
- `onProgress` 的 `time` 是已经处理的媒体时长(秒),不是百分比。
|
|
126
|
+
- 不要覆盖 `-progress` 参数,也不要依赖交互式输入。
|
|
127
|
+
- 声明的输出文件没有生成,或 FFmpeg 以非零状态退出时,调用失败,不返回部分结果。
|
|
128
|
+
- 返回的 `log` 保留最后 64 KiB 的诊断输出,失败时可以帮助排查。
|
|
129
|
+
- 第一次使用时,Tau 可能需要联网下载 FFmpeg,之后会复用。
|
|
130
|
+
|
|
131
|
+
## 在编辑器块中使用服务
|
|
132
|
+
|
|
133
|
+
[编辑器块](editor.md)的渲染组件不在 `activate` 中,拿不到 `context`。在组件里用 `usePluginServices()` 获取同一组服务:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { useEffect, useState } from "react";
|
|
137
|
+
import { usePluginServices } from "@tau/plugins";
|
|
138
|
+
|
|
139
|
+
function Preview({ source }: { source: string }) {
|
|
140
|
+
const services = usePluginServices();
|
|
141
|
+
const [html, setHtml] = useState<string>();
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (!services) return;
|
|
145
|
+
const controller = new AbortController();
|
|
146
|
+
services.markdown
|
|
147
|
+
.render(source, { signal: controller.signal })
|
|
148
|
+
.then(result => setHtml(result.html))
|
|
149
|
+
.catch(() => undefined);
|
|
150
|
+
return () => controller.abort();
|
|
151
|
+
}, [services, source]);
|
|
152
|
+
|
|
153
|
+
return html ? <div dangerouslySetInnerHTML={{ __html: html }} /> : <pre>{source}</pre>;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- 在博客等不运行插件的地方,`usePluginServices()` 返回 `undefined`。这时显示已保存的结果或源码。
|
|
158
|
+
- 组件卸载或输入变化时,用自己的 `AbortController` 取消过期的调用。
|
|
159
|
+
- 不要把服务对象存进模块级变量。
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# 站点数据
|
|
2
|
+
|
|
3
|
+
用户在 Tau 中发布博客时,Tau 会生成一组数据文件:站点信息、内容列表、每篇内容的正文和搜索索引。博客模板和独立站点读取这些数据来渲染页面。
|
|
4
|
+
|
|
5
|
+
这一篇面向两类开发者:
|
|
6
|
+
|
|
7
|
+
- **开发博客模板**:推荐直接使用 `@tau/blog`(npm 包 `@xiongtao.xt/tau-blog`)。它包含数据读取、搜索、正文渲染,以及内容插件(如[编辑器扩展](editor.md)中的自定义块)的接入,用法见该包的 README。
|
|
8
|
+
- **只想读取数据、自己渲染的站点**:使用 SDK 中的 `@tau/plugins/publish-client` 和 `@tau/plugins/publish-data`,见下文。
|
|
9
|
+
|
|
10
|
+
把文件送到远端的[发布提供方](providers/publish.md)是另一回事,与本篇无关。
|
|
11
|
+
|
|
12
|
+
## 读取数据
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createClient } from "@tau/plugins/publish-client";
|
|
16
|
+
|
|
17
|
+
const client = createClient({ manifestUrl: "https://example.com/data/site.<摘要>.json" });
|
|
18
|
+
const manifest = await client.readManifest();
|
|
19
|
+
|
|
20
|
+
const item = manifest.items[0];
|
|
21
|
+
if (item) {
|
|
22
|
+
const result = await client.readData({ key: item.key });
|
|
23
|
+
console.log(result);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`publish-client` 只负责读取数据、校验文件摘要、取消和搜索,不包含 React、渲染器、路由或界面。类型定义在 `@tau/plugins/publish-data` 中。
|
|
28
|
+
|
|
29
|
+
## 数据结构
|
|
30
|
+
|
|
31
|
+
### 清单
|
|
32
|
+
|
|
33
|
+
清单文件 `site.<摘要>.json` 是入口,包含:
|
|
34
|
+
|
|
35
|
+
- `site`:站点信息,见下文。
|
|
36
|
+
- 全部内容的 `key` 及对应的数据文件、搜索索引的引用。
|
|
37
|
+
- 只出现一次的站点级数据:`settings`(发布外观设置)、`collections`(项目列表)、`cardTagTree`(卡片标签树)、`projectTrees`(按项目 ID 组织的文档目录)。
|
|
38
|
+
|
|
39
|
+
`readData` 返回内容时会一并带上 `settings`。
|
|
40
|
+
|
|
41
|
+
### 站点信息与模板字段
|
|
42
|
+
|
|
43
|
+
`site` 包含 Tau 提供的 `title`、`basePath`,以及可选的 `publicUrl`、`favicon`。
|
|
44
|
+
|
|
45
|
+
站点的其他配置(描述、副标题、布局开关等)由**博客模板**自己声明:在模板的 manifest 中写 `template.siteFields`,用户在「站点设置 · 博客模板」中填写,发布时以 `site.fields[key]` 交给模板。
|
|
46
|
+
|
|
47
|
+
- 字段类型有 `text`、`textarea`、`url`、`select`、`switch`,最多 32 个。
|
|
48
|
+
- `fields` 只包含已声明的字段。用户没填时取字段的 `default`;没有默认值时,文本类为空字符串,开关为 `false`,下拉为第一个选项。
|
|
49
|
+
- 首页数据只有时间线和统计,介绍区等由模板根据自己的字段渲染。
|
|
50
|
+
|
|
51
|
+
### 内容文件
|
|
52
|
+
|
|
53
|
+
每篇内容一个数据文件,包含 `key`、`meta`、`content`,以及可选的:
|
|
54
|
+
|
|
55
|
+
| 字段 | 说明 |
|
|
56
|
+
| ----------------- | -------------------------------------- |
|
|
57
|
+
| `links` | 正文中指向其他已发布内容的站内链接目标 |
|
|
58
|
+
| `pluginRenderers` | 正文中用到的内容插件产物 |
|
|
59
|
+
| `contentStyles` | 正文中 HTML 节点需要的 Tailwind 样式 |
|
|
60
|
+
|
|
61
|
+
正文中的图片等资源,以所属数据文件的地址为基准解析相对路径。
|
|
62
|
+
|
|
63
|
+
### 路由与站内链接
|
|
64
|
+
|
|
65
|
+
公开页面的路由完全由模板决定,数据里没有 URL,只有内容引用 `{ key, type, id? }`。
|
|
66
|
+
|
|
67
|
+
- 使用 `@tau/blog` 时,它按 `links` 渲染站内链接,模板只需要提供 `hrefFor`,把内容引用转成页面地址。
|
|
68
|
+
- 自己渲染正文时,按 `links` 的键(格式为 `${contentType}:${refId}`)查找目标;查不到说明目标没有发布,显示为普通文字即可。
|
|
69
|
+
|
|
70
|
+
### 正文样式
|
|
71
|
+
|
|
72
|
+
`contentStyles` 包含 `:root` 上的主题变量和全局类名,正文显示期间对整个页面生效。如果你的模板自定义了同名的 Tailwind 主题变量,正文显示时可能被这些值覆盖,命名时注意避开。
|
|
73
|
+
|
|
74
|
+
## 内容插件产物
|
|
75
|
+
|
|
76
|
+
`@tau/plugins/publish-artifacts` 校验 `pluginRenderers` 中的插件产物、加载插件定义并检查节点归属。它只处理数据协议,不提供界面和模块加载。`@tau/blog` 已经内置了这部分,使用它时不需要关心。
|
|
77
|
+
|
|
78
|
+
## 构建时的注意事项
|
|
79
|
+
|
|
80
|
+
| 入口 | 内容 | 在独立站点中 |
|
|
81
|
+
| ---------------------------------------------- | ------------------------ | --------------------------------------------- |
|
|
82
|
+
| `@tau/plugins`、`@tau/ui` | 插件接口与界面组件 | 只有类型,运行实现由 Tau 提供,不能打包进站点 |
|
|
83
|
+
| `@tau/plugins/whiteboard`、`@tau/plugins/sync` | 白板与同步的类型 | 只用 `import type` |
|
|
84
|
+
| `@tau/plugins/publish-data` | 发布数据的类型 | 只用 `import type` |
|
|
85
|
+
| `@tau/plugins/publish-client` | 数据读取、摘要校验与搜索 | 有实现,可以打包进站点 |
|
|
86
|
+
| `@tau/plugins/publish-artifacts` | 插件产物协议 | 有实现,可以打包进站点 |
|
|
87
|
+
|
|
88
|
+
`@tau/plugins` 的根入口在普通浏览器或 Node.js 中执行会直接报错,这是有意的:它的实现只存在于 Tau 中。
|
|
89
|
+
|
|
90
|
+
独立站点用自己的构建工具,不要复用插件模板的 `build.mjs` 和本地安装脚本,它们是为运行在 Tau 中的插件准备的。
|
package/docs/skills.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Skill
|
|
2
|
+
|
|
3
|
+
Skill 是给 Tau 的 AI 助手看的使用说明:什么时候该做什么、按什么步骤做,必要时还可以附带参考资料和脚本。Tau 的 Skill 使用通用的 Agent Skills 目录格式,和 Claude Code、Codex 等工具里的 Skill 是同一种东西。
|
|
4
|
+
|
|
5
|
+
你可以用两种方式分发 Skill:
|
|
6
|
+
|
|
7
|
+
| 方式 | 适合 | 用户看到的 |
|
|
8
|
+
| ----------------------------------- | ------------------------------------------------ | -------------------------------- |
|
|
9
|
+
| [随插件附带](#随插件附带) | 插件提供了块、工具或页面,需要教 AI 怎么配合使用 | Skill 随插件启用出现,停用后消失 |
|
|
10
|
+
| [独立的 Skill 包](#独立的-skill-包) | 一套写作规范、工作流程等,不需要任何插件代码 | 从插件中心安装后,Skill 直接可用 |
|
|
11
|
+
|
|
12
|
+
两种方式的 Skill 目录写法完全相同。
|
|
13
|
+
|
|
14
|
+
## 一个 Skill 目录
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
skills/
|
|
18
|
+
chart-authoring/
|
|
19
|
+
SKILL.md # 必需:说明正文
|
|
20
|
+
references/ # 可选:参考资料,AI 需要时再读
|
|
21
|
+
chart-types.md
|
|
22
|
+
scripts/ # 可选:AI 可以执行的脚本
|
|
23
|
+
validate.py
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- `skills/` 下的每个子目录是一个 Skill,目录名就是 Skill 的 ID,只能使用字母、数字、点、横线和下划线。
|
|
27
|
+
- 一个包最多 32 个 Skill。
|
|
28
|
+
- 目录里的文件会原样打进插件包。以 `.` 开头的文件、`node_modules` 和 `__pycache__` 会被忽略;不能包含符号链接。
|
|
29
|
+
|
|
30
|
+
### SKILL.md
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
---
|
|
34
|
+
name: 图表写作
|
|
35
|
+
description: 用户要在文档里插入或修改图表块时加载,说明图表块的数据格式和常见写法
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# 图表写作
|
|
39
|
+
|
|
40
|
+
## 什么时候用
|
|
41
|
+
|
|
42
|
+
……
|
|
43
|
+
|
|
44
|
+
## 步骤
|
|
45
|
+
|
|
46
|
+
1. ……
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
开头的 front matter 决定 Skill 在 Tau 中如何显示和调用:
|
|
50
|
+
|
|
51
|
+
| 字段 | 说明 |
|
|
52
|
+
| -------------------------- | -------------------------------------------------------------- |
|
|
53
|
+
| `name` | 可选。Skill 页显示的名称,省略时使用目录名 |
|
|
54
|
+
| `description` | 必需。AI 根据它判断什么时候加载这份 Skill |
|
|
55
|
+
| `disable-model-invocation` | 可选。为 `true` 时 AI 不会自动加载,只在用户用 `$` 点名时使用 |
|
|
56
|
+
| `allowed-tools` | 可选。与 Claude Code 的同名字段一致,列出 Skill 建议使用的工具 |
|
|
57
|
+
|
|
58
|
+
缺少 `description` 时构建会失败,插件中心也会拒绝提交。
|
|
59
|
+
|
|
60
|
+
### 附带文件与脚本
|
|
61
|
+
|
|
62
|
+
- **参考资料**:AI 加载 Skill 后,可以按需读取目录里的其他文件。在 SKILL.md 里写清楚什么情况下该读哪个文件,比把所有内容塞进 SKILL.md 更省上下文。
|
|
63
|
+
- **脚本**:AI 可以执行目录里的脚本,工作目录就是这个 Skill 目录。按扩展名选择解释器:`.py` 用 python3,`.js`、`.mjs`、`.cjs` 用 Node.js,`.sh` 用 bash,`.ts` 用 tsx;其他文件需要有可执行权限。
|
|
64
|
+
- 每次执行脚本前,Tau 都会请用户确认。单次执行最长 120 秒,输出最多保留 64 KiB。
|
|
65
|
+
- 脚本以用户身份运行,没有沙箱。Tau 不会替用户安装 Python 等运行环境,需要时在 README 里写清楚。
|
|
66
|
+
- **带脚本的版本需要插件中心人工审核**(包括 `scripts/` 下的任何文件,以及目录里的 `.js`、`.mjs`、`.cjs`、`.ts`、`.py`、`.sh` 文件),不能通过自动发布直接上架。只含文档的 Skill 不受此限制。
|
|
67
|
+
|
|
68
|
+
## 随插件附带
|
|
69
|
+
|
|
70
|
+
在插件项目根目录建一个 `skills/` 目录,放进你的 Skill,然后照常 `pnpm build`:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
my-plugin/
|
|
74
|
+
manifest.json
|
|
75
|
+
src/index.tsx
|
|
76
|
+
skills/
|
|
77
|
+
chart-authoring/
|
|
78
|
+
SKILL.md
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
构建脚本会把 `skills/` 下的每个目录打进插件包,并在打包后的 manifest 中自动写入 `skills` 字段和文件摘要,你不需要改 manifest 或插件代码。
|
|
82
|
+
|
|
83
|
+
- 插件启用后,Skill 出现在 Tau 的 Skill 页,标注「插件 · 插件名」;插件停用后自动消失。
|
|
84
|
+
- 用户可以在 Skill 页调整它的调用方式(自动、仅手动、停用),或者复制一份到自己的 Skill 目录修改。
|
|
85
|
+
- AI 引用它时使用 `插件ID:目录名`,例如 `yourname.chart:chart-authoring`。
|
|
86
|
+
- 你的插件提供了 [MCP 工具](mcp.md)时,可以在 SKILL.md 里说明什么时候调用哪个工具、参数怎么填。
|
|
87
|
+
|
|
88
|
+
## 独立的 Skill 包
|
|
89
|
+
|
|
90
|
+
不需要任何插件代码时,把 Skill 单独做成一个包。用插件模板创建项目,删掉 `src/` 目录,把 `manifest.json` 改成:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"formatVersion": 1,
|
|
95
|
+
"id": "yourname.writing-style",
|
|
96
|
+
"name": "写作风格",
|
|
97
|
+
"description": "让 AI 按统一的风格写文章和卡片。",
|
|
98
|
+
"categories": ["skill"],
|
|
99
|
+
"keywords": ["写作", "风格"],
|
|
100
|
+
"version": "1.0.0",
|
|
101
|
+
"minAppVersion": "0.59.0",
|
|
102
|
+
"apiVersion": 1,
|
|
103
|
+
"platform": "desktop"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
和代码插件相比,Skill 包**没有** `main`、`format`,也不能声明 `permissions`、`backend`、`editor`、`whiteboard`。构建脚本看到 manifest 里没有 `main`,就会跳过代码打包,只打包 `skills/` 目录。
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
writing-style/
|
|
111
|
+
manifest.json
|
|
112
|
+
README.md
|
|
113
|
+
skills/
|
|
114
|
+
writing-style/
|
|
115
|
+
SKILL.md
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- `pnpm build` 和 `pnpm install:local` 的用法与代码插件相同。安装后在插件页点「重新扫描」,Skill 就会出现在 Skill 页,标注「Skill 包 · 包名」。
|
|
119
|
+
- Skill 包不参与插件启停,用户在 Skill 页逐个调整调用方式或停用。
|
|
120
|
+
- 发布流程与代码插件完全相同,见[发布与更新](release.md)。分类建议填 `skill`。
|
|
121
|
+
- README 照样是给用户看的:这套 Skill 能让 AI 做什么,用户怎么点名使用。
|
|
122
|
+
|
|
123
|
+
## 写好一份 Skill
|
|
124
|
+
|
|
125
|
+
- **`description` 决定 AI 会不会在合适的时候用它**。写"在什么情况下加载",而不是"这份文档是什么"。例如"用户要求生成周报时加载",而不是"周报指南"。
|
|
126
|
+
- **正文写给 AI 看**:什么时候用、具体步骤、参数含义、正确与错误的例子。
|
|
127
|
+
- **只写与这件事相关的内容**。通用的写作建议对 AI 没有帮助,反而占用上下文。
|
|
128
|
+
- **大段参考资料放进单独的文件**,在 SKILL.md 中说明何时读取。
|
|
129
|
+
- **脚本要能独立运行**:参数通过命令行传入,结果打印到标准输出,失败时以非 0 退出码结束,并输出可读的错误信息。
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# 存储与网络
|
|
2
|
+
|
|
3
|
+
## 私有存储
|
|
4
|
+
|
|
5
|
+
`context.storage` 是插件自己的键值存储,适合保存设置、进度、缓存等小块数据。
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const saved = await context.storage.get("count");
|
|
9
|
+
const count = typeof saved === "number" ? saved : 0;
|
|
10
|
+
await context.storage.set("count", count + 1);
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| 方法 | 说明 |
|
|
14
|
+
| ----------------- | ------------------------------ |
|
|
15
|
+
| `get(key)` | 读取,不存在时返回 `undefined` |
|
|
16
|
+
| `set(key, value)` | 保存或覆盖 |
|
|
17
|
+
| `delete(key)` | 删除 |
|
|
18
|
+
|
|
19
|
+
### 数据保存在哪里
|
|
20
|
+
|
|
21
|
+
- 按插件和工作区隔离:同一个插件在不同工作区读到的是各自的数据,也读不到其他插件的数据。
|
|
22
|
+
- 保存在工作区的笔记库里,随云同步。用户换一台设备,也能读到同样的数据。
|
|
23
|
+
- 停用、重启、更新插件都不会删除数据。用户卸载插件时可以选择是否一并删除。
|
|
24
|
+
- 数据跟随插件 ID。改了 ID,就成了另一个插件,读不到原来的数据。
|
|
25
|
+
|
|
26
|
+
### 能存什么
|
|
27
|
+
|
|
28
|
+
值必须是 JSON:`null`、布尔值、字符串、有限数字,以及由它们组成的数组和普通对象。不能存 `undefined`、函数、`Date`、`Map`、`NaN`、`Infinity` 或循环引用;日期先转成字符串或时间戳。
|
|
29
|
+
|
|
30
|
+
单个值不超过 1 MB。更大的内容(比如一篇长文)放进[插件内容](user-data.md#插件内容)的正文里。
|
|
31
|
+
|
|
32
|
+
### 使用要点
|
|
33
|
+
|
|
34
|
+
- **读取后校验**。`get` 返回的是 `JsonValue`,不带类型保证。数据可能来自旧版本的插件,也可能在其他设备上被修改过,使用前先检查结构,不符合时用默认值或提示错误。
|
|
35
|
+
- **改了要保存**。修改 `get` 返回的对象不会自动写回,必须再调用 `set`。
|
|
36
|
+
- **读写不是原子的**。"先 `get` 再 `set`"之间如果有另一次写入,后写的会覆盖先写的。保存期间禁用重复提交,模板的计数器按钮就是这样做的。
|
|
37
|
+
- **兼顾新旧版本**。用户可以把插件恢复到上一版,但数据不会跟着回退。改变数据结构时,让新版本能读懂旧数据,也尽量让旧版本读到新数据时不出错(例如只新增字段,不改已有字段的含义)。
|
|
38
|
+
- **不要存凭据**。账号、Token 这类配置会随笔记库同步,不应放在这里。服务提供方的账号配置使用专门的配置保存接口,见[服务提供方](providers/README.md)。
|
|
39
|
+
|
|
40
|
+
## 网络请求
|
|
41
|
+
|
|
42
|
+
用 `context.fetch` 发起网络请求。它的参数和返回值与标准的 `fetch` 相同:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const response = await context.fetch("https://api.example.com/status", {
|
|
46
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) throw new Error(`请求失败:${response.status}`);
|
|
49
|
+
const data: unknown = await response.json();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
与直接调用浏览器的 `fetch` 相比:
|
|
53
|
+
|
|
54
|
+
- 请求由 Tau 代为发出,不受浏览器跨域(CORS)限制,也不会携带浏览器的 Cookie。需要认证时,自己在请求头里提供。
|
|
55
|
+
- 插件停用时,进行中的请求会被自动取消。你也可以照常传入自己的 `signal`,两者任一中止都会取消请求。
|
|
56
|
+
|
|
57
|
+
注意:
|
|
58
|
+
|
|
59
|
+
- 和标准 `fetch` 一样,HTTP 4xx、5xx 不会抛出异常,要检查 `response.ok`。
|
|
60
|
+
- 响应数据先校验再使用,尤其是写入存储之前。
|
|
61
|
+
- 不要把私人的 API Key 写进源码。需要用户自己的凭据时,让用户在设置中填写。
|
|
62
|
+
- 能读到的用户数据都可以通过网络发送出去。只在功能确实需要时这样做,并在 README 里向用户说明。
|