@xiongtao.xt/tau-plugins 0.29.0 → 0.31.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/AI.md +116 -116
- package/API.md +881 -881
- package/BACKEND.md +68 -68
- package/CHANGELOG.md +120 -114
- package/DEVELOPMENT.md +173 -173
- package/EDITOR.md +192 -192
- package/FLASHCARDS.md +92 -92
- package/IMAGES.md +16 -16
- package/LICENSE +21 -21
- package/NOTIFICATIONS.md +48 -48
- package/PUBLISH-DATA.md +48 -47
- package/PUBLISH.md +50 -48
- package/SERVICES.md +119 -119
- package/SYNC.md +37 -37
- package/TTS.md +20 -20
- package/UPLOAD.md +35 -35
- package/VIDEO.md +65 -65
- package/WHITEBOARD.md +115 -115
- package/client/{chunk-R3YIHOWT.js → chunk-ECEBBIHP.js} +1 -1
- package/package.js +1 -1
- package/package.json +1 -1
- package/publish-artifacts.js +1 -1
- package/types/packages/plugins/src/categories.d.ts +1 -1
- package/types/packages/plugins/src/publish-data.d.ts +2 -5
- package/types/packages/ui/src/index.d.ts +1 -0
- package/types/packages/ui/src/patterns/SettingRow.d.ts +14 -0
package/EDITOR.md
CHANGED
|
@@ -1,192 +1,192 @@
|
|
|
1
|
-
# 编辑器扩展
|
|
2
|
-
|
|
3
|
-
在文档中添加自己的块:比如交互演示、图表、特殊格式的卡片。本文还介绍源码预览块和插件 Skill。需要 Tau 0.59.0 或更高版本。
|
|
4
|
-
|
|
5
|
-
## 定义一个块
|
|
6
|
-
|
|
7
|
-
先在 `manifest.json` 中加入 `"editor": true`(完整示例见下文),然后在插件定义里声明 `editorExtensions`:
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
import { useState } from "react";
|
|
11
|
-
import { definePlugin, defineEditorElement, defineEditorExtension } from "@tau/plugins";
|
|
12
|
-
|
|
13
|
-
interface CounterElement {
|
|
14
|
-
type: "example.counter";
|
|
15
|
-
initial: number;
|
|
16
|
-
children: { type: "formatted"; text: string }[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
declare module "@tau/plugins" {
|
|
20
|
-
interface EditorElementMap {
|
|
21
|
-
"example.counter": CounterElement;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function Counter({ initial }: { initial: number }) {
|
|
26
|
-
const [count, setCount] = useState(initial);
|
|
27
|
-
return (
|
|
28
|
-
<div contentEditable={false}>
|
|
29
|
-
<button onMouseDown={event => event.preventDefault()} onClick={() => setCount(n => n + 1)}>
|
|
30
|
-
计数:{count}
|
|
31
|
-
</button>
|
|
32
|
-
</div>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default definePlugin({
|
|
37
|
-
id: "example.counter",
|
|
38
|
-
name: "计数块",
|
|
39
|
-
version: "1.0.0",
|
|
40
|
-
editorExtensions: [
|
|
41
|
-
defineEditorExtension({
|
|
42
|
-
id: "example.counter",
|
|
43
|
-
elements: [
|
|
44
|
-
defineEditorElement<CounterElement>({
|
|
45
|
-
type: "example.counter",
|
|
46
|
-
kind: "block",
|
|
47
|
-
isVoid: true,
|
|
48
|
-
render: ({ attributes, element, children }) => (
|
|
49
|
-
<div {...attributes}>
|
|
50
|
-
<Counter initial={element.initial} />
|
|
51
|
-
{children}
|
|
52
|
-
</div>
|
|
53
|
-
),
|
|
54
|
-
}),
|
|
55
|
-
],
|
|
56
|
-
}),
|
|
57
|
-
],
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
几点说明:
|
|
62
|
-
|
|
63
|
-
- 节点上的字段(如 `initial`)是文档数据,会随文档保存;组件里的 `useState` 只是本次显示的状态,不会改动原文。不要把文档内容放进插件私有存储。
|
|
64
|
-
- `editorExtensions` 与插件定义一起静态导出。只提供编辑器扩展的插件可以省略 `create`;同时有命令、页面或设置时照常提供 `create/activate`。
|
|
65
|
-
- 扩展可声明 `elements`、`commands`、`hotkeys`、`menu`、`blockPanel`、`behaviorsFor`,至少包含一个节点类型。`blockPanel` 的 `onClick` 会收到当前编辑器,可用来插入节点。
|
|
66
|
-
- 节点类型和扩展 ID 使用自己的命名空间(如 `yourname.chart`),不要与内置或其他插件的类型重名。
|
|
67
|
-
|
|
68
|
-
完整的 manifest 示例:
|
|
69
|
-
|
|
70
|
-
```json
|
|
71
|
-
{
|
|
72
|
-
"formatVersion": 1,
|
|
73
|
-
"id": "example.counter",
|
|
74
|
-
"name": "计数块",
|
|
75
|
-
"description": "在文档中放入交互计数块。",
|
|
76
|
-
"version": "1.0.0",
|
|
77
|
-
"minAppVersion": "0.59.0",
|
|
78
|
-
"apiVersion": 1,
|
|
79
|
-
"platform": "desktop",
|
|
80
|
-
"format": "cjs",
|
|
81
|
-
"main": "main.js",
|
|
82
|
-
"editor": true
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
`styles`、`integrity` 由构建脚本生成,不用手写。
|
|
87
|
-
|
|
88
|
-
## 启用、停用与卸载
|
|
89
|
-
|
|
90
|
-
- 编辑器插件的启用、停用和升级在完整重启 Tau 后生效。
|
|
91
|
-
- 停用后,文档里已有的节点会保留,并显示为不可用占位,不会被删除;重新启用后恢复显示。
|
|
92
|
-
- 卸载正在使用的编辑器插件前,需要先停用并重启。
|
|
93
|
-
|
|
94
|
-
## 块会在哪里显示
|
|
95
|
-
|
|
96
|
-
块显示在桌面编辑器和用户发布的博客中,两处直接使用 `elements.render` 中的同一个组件,不需要另写入口。移动端与浏览器扩展不加载插件,遇到插件节点保留原数据并显示通用占位。因此渲染代码要满足:
|
|
97
|
-
|
|
98
|
-
- 模块顶层和渲染组件能在浏览器中运行,不导入 Electron、Node 或 Tau 客户端内部路径。
|
|
99
|
-
- 不依赖 `activate` 中才赋值的变量,也不调用 `context` 的存储、页面、服务等桌面能力。
|
|
100
|
-
- React、ReactDOM、`@tau/plugins`、`@tau/ui` 由 Tau 提供,保持模板的 external 配置;其他浏览器兼容的 npm 依赖会打进 `main.js`。
|
|
101
|
-
- JS 与 CSS 自包含,图片等静态资源内联为 data URL。
|
|
102
|
-
- 样式使用插件自己的类名前缀,不覆盖 `body` 或 Tau 自身组件的样式。
|
|
103
|
-
- 只读场景下文档不可编辑,但组件自己的交互(按钮、图表缩放等)照常可用。
|
|
104
|
-
|
|
105
|
-
## Markdown
|
|
106
|
-
|
|
107
|
-
在插件定义中提供 `editorCodecs`(类型为 `EditorMarkdownCodec[]`),让自定义节点支持 Markdown 导入导出、复制和搜索摘要。序列化与反序列化需要成对设计,只写输出函数不会自动获得导入能力。
|
|
108
|
-
|
|
109
|
-
codec 会在后台转换时单独加载,不经过 `create/activate`,所以必须是纯转换函数,模块顶层不能访问 `window`、`document` 或激活后的上下文。
|
|
110
|
-
|
|
111
|
-
## 源码预览块
|
|
112
|
-
|
|
113
|
-
`SourceBlockEditor` 复用 Tau 的源码预览组件,包括编辑、全屏、错误条、删除与相邻块导航。它不是第二份渲染入口,放在同一 `elements.render` 组件中使用。
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
import type { ReactNode } from "react";
|
|
117
|
-
import { SourceBlockEditor, useSourceBlock } from "@tau/plugins";
|
|
118
|
-
import { Code } from "lucide-react";
|
|
119
|
-
|
|
120
|
-
interface SourceElement {
|
|
121
|
-
type: "example.source";
|
|
122
|
-
content: string;
|
|
123
|
-
children: { type: "formatted"; text: string }[];
|
|
124
|
-
}
|
|
125
|
-
declare module "@tau/plugins" {
|
|
126
|
-
interface EditorElementMap {
|
|
127
|
-
"example.source": SourceElement;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function SourceView({ element, children }: { element: SourceElement; children: ReactNode }) {
|
|
132
|
-
const { update } = useSourceBlock(element);
|
|
133
|
-
return (
|
|
134
|
-
<SourceBlockEditor
|
|
135
|
-
element={element}
|
|
136
|
-
mode="jsx"
|
|
137
|
-
title="示例"
|
|
138
|
-
icon={Code}
|
|
139
|
-
initValue={element.content}
|
|
140
|
-
onChange={content => update({ content })}
|
|
141
|
-
>
|
|
142
|
-
{children}
|
|
143
|
-
</SourceBlockEditor>
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
| API | 用途 |
|
|
149
|
-
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
150
|
-
| `SourceBlockEditor` | `element/mode/title/icon/initValue/onChange` 为必填;`center/extend/fluid` 控制预览布局,`children` 是预览内容 |
|
|
151
|
-
| `useSourceBlock(element)` | 返回当前主题 `theme`、可选样式编译器 `compiler` 与节点字段更新函数 `update`;只能在编辑器内调用 |
|
|
152
|
-
| `useReportPreviewError(message, {stale})` | 向源码预览块上报错误,传 null 清除;stale 表示是否保留了上次预览 |
|
|
153
|
-
| `insertSourceBlock(editor, element, line?)` | 插入或替换空段落并聚焦源码,返回插入路径;不能插入时返回 undefined |
|
|
154
|
-
| `sourceBlockParagraphBehavior(type)` | 放入扩展 `behaviorsFor.paragraph`,支持段首退格聚焦前一源码块 |
|
|
155
|
-
|
|
156
|
-
`theme` 提供 `isDark` 和 `token(word)`,渲染应响应主题变化。`compiler.compile({source, language})` 返回 Tailwind CSS,language 为 html 或 tsx;它只在桌面编辑器中可用,其他场景读不到编译器,需配合下文的 `styleSources` 使用。这些组件和 hook 由 Tau 提供,不要打包自己的编辑器、Slate React 或源码编辑器实例。
|
|
157
|
-
|
|
158
|
-
## 动态样式与静态导出
|
|
159
|
-
|
|
160
|
-
SDK 0.17.0 提供 `useInlineSource(element)`:返回 readOnly、可选 compiler、update(properties) 与 remove(),只读、停驻、卸载及旧目标回调不会写入文档。行内源码组件通过 `InlineSourceBoundary` 复用宿主的浏览器边界处理;菜单用 `insertInlineSource(editor, element)` 插入节点。行内输入弹层由插件通过公共 UI 组件承载,只读时只显示预览,不打开编辑器。
|
|
161
|
-
|
|
162
|
-
静态导出也按 styleSources 编译节点字段并向导出 CSS 收集器提供样式;插件只负责把节点序列化为 HTML,宿主不维护具体节点类型的样式名单。
|
|
163
|
-
|
|
164
|
-
若节点源码中包含动态 Tailwind 类名,在同一个扩展上声明字段:
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
defineEditorExtension({
|
|
168
|
-
id: "example.demo",
|
|
169
|
-
elements: [/* 当前扩展的元素定义 */],
|
|
170
|
-
styleSources: [{ type: "example.demo", field: "content", language: "tsx" }],
|
|
171
|
-
});
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
在无法运行时编译的场景(如发布的网页),Tau 会据此读取这些节点的 `content` 字段,预先生成样式。源码字段须为字符串,只能登记本插件声明的节点类型。拼接出来的类名(如 `` `bg-${color}` ``)扫描不到,类名要完整写在源码里。
|
|
175
|
-
|
|
176
|
-
可选 `htmlSerializers: [{type, toHtml(element)}]` 用于复制 HTML、HTML/EPUB 等静态导出,返回 HTML 字符串并自行转义文本。它只用于静态导出,网页显示仍使用 `elements.render`。不声明时按未知节点的默认规则导出,交互式组件在 EPUB 中不会执行。
|
|
177
|
-
|
|
178
|
-
## 插件 Skill
|
|
179
|
-
|
|
180
|
-
在 `definePlugin` 的 `skills` 数组中声明 `{id, name, description, content, invocation?}`,为 AI 提供与你的插件配套的写作规范:
|
|
181
|
-
|
|
182
|
-
| 字段 | 说明 |
|
|
183
|
-
| ------------- | ------------------------------------------------------ |
|
|
184
|
-
| `id` | 插件内唯一标识;AI 以 `插件ID:技能ID` 引用 |
|
|
185
|
-
| `name` | Skill 页面显示的名称 |
|
|
186
|
-
| `description` | AI 据此判断何时加载,写清适用场景 |
|
|
187
|
-
| `content` | 完整的 SKILL.md 正文 |
|
|
188
|
-
| `invocation` | 默认 `auto`(AI 自行加载),设为 `manual` 则仅手动点名 |
|
|
189
|
-
|
|
190
|
-
插件启用后 Skill 才可用,停用时自动移除。Skill 页面会标明它来自你的插件,用户可以调整调用方式、停用或复制到自己的 Skill 目录。目前每个 Skill 只有一份正文,不支持脚本和附件。
|
|
191
|
-
|
|
192
|
-
正文可以写在单独的 SKILL.md 中,构建时用 esbuild 的 `.md: text` loader 作为字符串导入。
|
|
1
|
+
# 编辑器扩展
|
|
2
|
+
|
|
3
|
+
在文档中添加自己的块:比如交互演示、图表、特殊格式的卡片。本文还介绍源码预览块和插件 Skill。需要 Tau 0.59.0 或更高版本。
|
|
4
|
+
|
|
5
|
+
## 定义一个块
|
|
6
|
+
|
|
7
|
+
先在 `manifest.json` 中加入 `"editor": true`(完整示例见下文),然后在插件定义里声明 `editorExtensions`:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { useState } from "react";
|
|
11
|
+
import { definePlugin, defineEditorElement, defineEditorExtension } from "@tau/plugins";
|
|
12
|
+
|
|
13
|
+
interface CounterElement {
|
|
14
|
+
type: "example.counter";
|
|
15
|
+
initial: number;
|
|
16
|
+
children: { type: "formatted"; text: string }[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module "@tau/plugins" {
|
|
20
|
+
interface EditorElementMap {
|
|
21
|
+
"example.counter": CounterElement;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function Counter({ initial }: { initial: number }) {
|
|
26
|
+
const [count, setCount] = useState(initial);
|
|
27
|
+
return (
|
|
28
|
+
<div contentEditable={false}>
|
|
29
|
+
<button onMouseDown={event => event.preventDefault()} onClick={() => setCount(n => n + 1)}>
|
|
30
|
+
计数:{count}
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default definePlugin({
|
|
37
|
+
id: "example.counter",
|
|
38
|
+
name: "计数块",
|
|
39
|
+
version: "1.0.0",
|
|
40
|
+
editorExtensions: [
|
|
41
|
+
defineEditorExtension({
|
|
42
|
+
id: "example.counter",
|
|
43
|
+
elements: [
|
|
44
|
+
defineEditorElement<CounterElement>({
|
|
45
|
+
type: "example.counter",
|
|
46
|
+
kind: "block",
|
|
47
|
+
isVoid: true,
|
|
48
|
+
render: ({ attributes, element, children }) => (
|
|
49
|
+
<div {...attributes}>
|
|
50
|
+
<Counter initial={element.initial} />
|
|
51
|
+
{children}
|
|
52
|
+
</div>
|
|
53
|
+
),
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
几点说明:
|
|
62
|
+
|
|
63
|
+
- 节点上的字段(如 `initial`)是文档数据,会随文档保存;组件里的 `useState` 只是本次显示的状态,不会改动原文。不要把文档内容放进插件私有存储。
|
|
64
|
+
- `editorExtensions` 与插件定义一起静态导出。只提供编辑器扩展的插件可以省略 `create`;同时有命令、页面或设置时照常提供 `create/activate`。
|
|
65
|
+
- 扩展可声明 `elements`、`commands`、`hotkeys`、`menu`、`blockPanel`、`behaviorsFor`,至少包含一个节点类型。`blockPanel` 的 `onClick` 会收到当前编辑器,可用来插入节点。
|
|
66
|
+
- 节点类型和扩展 ID 使用自己的命名空间(如 `yourname.chart`),不要与内置或其他插件的类型重名。
|
|
67
|
+
|
|
68
|
+
完整的 manifest 示例:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"formatVersion": 1,
|
|
73
|
+
"id": "example.counter",
|
|
74
|
+
"name": "计数块",
|
|
75
|
+
"description": "在文档中放入交互计数块。",
|
|
76
|
+
"version": "1.0.0",
|
|
77
|
+
"minAppVersion": "0.59.0",
|
|
78
|
+
"apiVersion": 1,
|
|
79
|
+
"platform": "desktop",
|
|
80
|
+
"format": "cjs",
|
|
81
|
+
"main": "main.js",
|
|
82
|
+
"editor": true
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`styles`、`integrity` 由构建脚本生成,不用手写。
|
|
87
|
+
|
|
88
|
+
## 启用、停用与卸载
|
|
89
|
+
|
|
90
|
+
- 编辑器插件的启用、停用和升级在完整重启 Tau 后生效。
|
|
91
|
+
- 停用后,文档里已有的节点会保留,并显示为不可用占位,不会被删除;重新启用后恢复显示。
|
|
92
|
+
- 卸载正在使用的编辑器插件前,需要先停用并重启。
|
|
93
|
+
|
|
94
|
+
## 块会在哪里显示
|
|
95
|
+
|
|
96
|
+
块显示在桌面编辑器和用户发布的博客中,两处直接使用 `elements.render` 中的同一个组件,不需要另写入口。移动端与浏览器扩展不加载插件,遇到插件节点保留原数据并显示通用占位。因此渲染代码要满足:
|
|
97
|
+
|
|
98
|
+
- 模块顶层和渲染组件能在浏览器中运行,不导入 Electron、Node 或 Tau 客户端内部路径。
|
|
99
|
+
- 不依赖 `activate` 中才赋值的变量,也不调用 `context` 的存储、页面、服务等桌面能力。
|
|
100
|
+
- React、ReactDOM、`@tau/plugins`、`@tau/ui` 由 Tau 提供,保持模板的 external 配置;其他浏览器兼容的 npm 依赖会打进 `main.js`。
|
|
101
|
+
- JS 与 CSS 自包含,图片等静态资源内联为 data URL。
|
|
102
|
+
- 样式使用插件自己的类名前缀,不覆盖 `body` 或 Tau 自身组件的样式。
|
|
103
|
+
- 只读场景下文档不可编辑,但组件自己的交互(按钮、图表缩放等)照常可用。
|
|
104
|
+
|
|
105
|
+
## Markdown
|
|
106
|
+
|
|
107
|
+
在插件定义中提供 `editorCodecs`(类型为 `EditorMarkdownCodec[]`),让自定义节点支持 Markdown 导入导出、复制和搜索摘要。序列化与反序列化需要成对设计,只写输出函数不会自动获得导入能力。
|
|
108
|
+
|
|
109
|
+
codec 会在后台转换时单独加载,不经过 `create/activate`,所以必须是纯转换函数,模块顶层不能访问 `window`、`document` 或激活后的上下文。
|
|
110
|
+
|
|
111
|
+
## 源码预览块
|
|
112
|
+
|
|
113
|
+
`SourceBlockEditor` 复用 Tau 的源码预览组件,包括编辑、全屏、错误条、删除与相邻块导航。它不是第二份渲染入口,放在同一 `elements.render` 组件中使用。
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import type { ReactNode } from "react";
|
|
117
|
+
import { SourceBlockEditor, useSourceBlock } from "@tau/plugins";
|
|
118
|
+
import { Code } from "lucide-react";
|
|
119
|
+
|
|
120
|
+
interface SourceElement {
|
|
121
|
+
type: "example.source";
|
|
122
|
+
content: string;
|
|
123
|
+
children: { type: "formatted"; text: string }[];
|
|
124
|
+
}
|
|
125
|
+
declare module "@tau/plugins" {
|
|
126
|
+
interface EditorElementMap {
|
|
127
|
+
"example.source": SourceElement;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function SourceView({ element, children }: { element: SourceElement; children: ReactNode }) {
|
|
132
|
+
const { update } = useSourceBlock(element);
|
|
133
|
+
return (
|
|
134
|
+
<SourceBlockEditor
|
|
135
|
+
element={element}
|
|
136
|
+
mode="jsx"
|
|
137
|
+
title="示例"
|
|
138
|
+
icon={Code}
|
|
139
|
+
initValue={element.content}
|
|
140
|
+
onChange={content => update({ content })}
|
|
141
|
+
>
|
|
142
|
+
{children}
|
|
143
|
+
</SourceBlockEditor>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
| API | 用途 |
|
|
149
|
+
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
150
|
+
| `SourceBlockEditor` | `element/mode/title/icon/initValue/onChange` 为必填;`center/extend/fluid` 控制预览布局,`children` 是预览内容 |
|
|
151
|
+
| `useSourceBlock(element)` | 返回当前主题 `theme`、可选样式编译器 `compiler` 与节点字段更新函数 `update`;只能在编辑器内调用 |
|
|
152
|
+
| `useReportPreviewError(message, {stale})` | 向源码预览块上报错误,传 null 清除;stale 表示是否保留了上次预览 |
|
|
153
|
+
| `insertSourceBlock(editor, element, line?)` | 插入或替换空段落并聚焦源码,返回插入路径;不能插入时返回 undefined |
|
|
154
|
+
| `sourceBlockParagraphBehavior(type)` | 放入扩展 `behaviorsFor.paragraph`,支持段首退格聚焦前一源码块 |
|
|
155
|
+
|
|
156
|
+
`theme` 提供 `isDark` 和 `token(word)`,渲染应响应主题变化。`compiler.compile({source, language})` 返回 Tailwind CSS,language 为 html 或 tsx;它只在桌面编辑器中可用,其他场景读不到编译器,需配合下文的 `styleSources` 使用。这些组件和 hook 由 Tau 提供,不要打包自己的编辑器、Slate React 或源码编辑器实例。
|
|
157
|
+
|
|
158
|
+
## 动态样式与静态导出
|
|
159
|
+
|
|
160
|
+
SDK 0.17.0 提供 `useInlineSource(element)`:返回 readOnly、可选 compiler、update(properties) 与 remove(),只读、停驻、卸载及旧目标回调不会写入文档。行内源码组件通过 `InlineSourceBoundary` 复用宿主的浏览器边界处理;菜单用 `insertInlineSource(editor, element)` 插入节点。行内输入弹层由插件通过公共 UI 组件承载,只读时只显示预览,不打开编辑器。
|
|
161
|
+
|
|
162
|
+
静态导出也按 styleSources 编译节点字段并向导出 CSS 收集器提供样式;插件只负责把节点序列化为 HTML,宿主不维护具体节点类型的样式名单。
|
|
163
|
+
|
|
164
|
+
若节点源码中包含动态 Tailwind 类名,在同一个扩展上声明字段:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
defineEditorExtension({
|
|
168
|
+
id: "example.demo",
|
|
169
|
+
elements: [/* 当前扩展的元素定义 */],
|
|
170
|
+
styleSources: [{ type: "example.demo", field: "content", language: "tsx" }],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
在无法运行时编译的场景(如发布的网页),Tau 会据此读取这些节点的 `content` 字段,预先生成样式。源码字段须为字符串,只能登记本插件声明的节点类型。拼接出来的类名(如 `` `bg-${color}` ``)扫描不到,类名要完整写在源码里。
|
|
175
|
+
|
|
176
|
+
可选 `htmlSerializers: [{type, toHtml(element)}]` 用于复制 HTML、HTML/EPUB 等静态导出,返回 HTML 字符串并自行转义文本。它只用于静态导出,网页显示仍使用 `elements.render`。不声明时按未知节点的默认规则导出,交互式组件在 EPUB 中不会执行。
|
|
177
|
+
|
|
178
|
+
## 插件 Skill
|
|
179
|
+
|
|
180
|
+
在 `definePlugin` 的 `skills` 数组中声明 `{id, name, description, content, invocation?}`,为 AI 提供与你的插件配套的写作规范:
|
|
181
|
+
|
|
182
|
+
| 字段 | 说明 |
|
|
183
|
+
| ------------- | ------------------------------------------------------ |
|
|
184
|
+
| `id` | 插件内唯一标识;AI 以 `插件ID:技能ID` 引用 |
|
|
185
|
+
| `name` | Skill 页面显示的名称 |
|
|
186
|
+
| `description` | AI 据此判断何时加载,写清适用场景 |
|
|
187
|
+
| `content` | 完整的 SKILL.md 正文 |
|
|
188
|
+
| `invocation` | 默认 `auto`(AI 自行加载),设为 `manual` 则仅手动点名 |
|
|
189
|
+
|
|
190
|
+
插件启用后 Skill 才可用,停用时自动移除。Skill 页面会标明它来自你的插件,用户可以调整调用方式、停用或复制到自己的 Skill 目录。目前每个 Skill 只有一份正文,不支持脚本和附件。
|
|
191
|
+
|
|
192
|
+
正文可以写在单独的 SKILL.md 中,构建时用 esbuild 的 `.md: text` loader 作为字符串导入。
|
package/FLASHCARDS.md
CHANGED
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
# 闪卡能力
|
|
2
|
-
|
|
3
|
-
本文对应 SDK 0.27.0 和支持闪卡接口的 Tau 0.59.0 客户端构建。能力通过激活时的 `context.flashcards` 使用,绑定本次激活的数据库;停用、切库后旧调用失效。旧客户端可用 `if (!context.flashcards)` 检查是否支持。
|
|
4
|
-
|
|
5
|
-
## 权限与 AI 配置
|
|
6
|
-
|
|
7
|
-
直接查询卡组需在 manifest 声明 `flashcards:read`,直接创建卡组、闪卡及自动保存需声明 `flashcards:write`;使用时由用户授权,可在插件详情页撤销。引用已有正文还需对应实体的读取权限;本插件自有正文沿用免业务权限规则。打开宿主窗口必须来自用户点击或按键,窗口内的创建由用户确认,不需要闪卡读写权限。
|
|
8
|
-
|
|
9
|
-
AI 制卡直接复用应用「闪卡生成」已分配的模型,不需要声明插件自己的 AI 功能或再次选择模型。在 manifest 中声明要申请的能力:
|
|
10
|
-
|
|
11
|
-
```json
|
|
12
|
-
{ "permissions": ["flashcards:read", "flashcards:write", "ai:flashcardGeneration"] }
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
内部通过通用的 `context.ai.requestCapability("flashcardGeneration")` 申请“使用闪卡制作 AI”,可在插件的「权限」页撤销,撤权会取消在途生成。主进程读取应用现有模型分配,按插件身份记录用量并限制并发和每日额度;额度可在插件 AI 设置中调整。应用未配置闪卡模型时明确报错。申请其他内置模型分配或声明自己的 AI 功能见 AI.md。
|
|
16
|
-
|
|
17
|
-
## 打开宿主制卡窗口
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
const result = await context.flashcards.openCreate({
|
|
21
|
-
mode: "ai", // manual 为手动制卡,缺省为 manual
|
|
22
|
-
content: "牛顿第二定律:F = ma。", // Markdown 或 Descendant[]
|
|
23
|
-
title: "力学笔记",
|
|
24
|
-
// deckId: 123, // 可选;省略时先选择卡组,也可以现场新建卡组
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// result.status 为 completed 或 cancelled;cards 包含本次窗口已经保存的记录。
|
|
28
|
-
// 取消不会撤销「保存并新建」等已提交的记录。
|
|
29
|
-
console.log(
|
|
30
|
-
result.status,
|
|
31
|
-
result.cards.map(card => card.id)
|
|
32
|
-
);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
AI 模式自动开始生成并展示预览,可选择、编辑后保存;手动模式预填题干和参考资料,支持连续创建。未指定 references 时,content 作为自定义参考资料保存,title 用于来源标题;指定 `references: []` 可省略来源。
|
|
36
|
-
|
|
37
|
-
引用 Tau 中已有正文时,显式传入来源,避免复制正文作为参考资料:
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
await context.flashcards.openCreate({
|
|
41
|
-
mode: "ai",
|
|
42
|
-
content: sourceContent,
|
|
43
|
-
references: [{ refType: "content", contentRef: sourceContentRef, title: "原文" }],
|
|
44
|
-
});
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
`sourceContentRef` 来自 `context.data` 的实体或 `context.entities`,不可解析或用正文数字 ID 代替。宿主核对正文身份与读取权限,失效或未获准的引用拒绝保存。
|
|
48
|
-
|
|
49
|
-
窗口操作返回的 Promise 等待用户完成。必须在按钮或其他用户操作中调用;后台和定时器调用会被拒绝,不要在 `activate()` 中等待用户操作。同一窗口仅允许一个制卡会话,重复打开明确报错。
|
|
50
|
-
|
|
51
|
-
所有创建方式返回的卡片都沿用 `PluginFlashcardDraft` 的字段:自定义参考正文为 `references[].customContent`,已有正文引用为 `references[].contentRef`。可以将返回卡片传给 `createCard` 创建副本,仍需写入和来源读取权限;已失效的引用不会出现在返回结果中。创建后来源窗口的卡组、闪卡和计数会自动刷新。
|
|
52
|
-
|
|
53
|
-
## 直接创建卡组与闪卡
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
const decks = await context.flashcards.listDecks();
|
|
57
|
-
const deck = await context.flashcards.createDeck({ name: "力学", description: "基础概念" });
|
|
58
|
-
const card = await context.flashcards.createCard({
|
|
59
|
-
deckId: deck.id,
|
|
60
|
-
type: "qa",
|
|
61
|
-
prompt: [{ type: "paragraph", children: [{ text: "牛顿第二定律的表达式是什么?" }] }],
|
|
62
|
-
data: { answer: "F = ma" },
|
|
63
|
-
tags: ["力学"],
|
|
64
|
-
difficulty: "foundation",
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
题型包括 `qa/boolean/cloze/single-choice/multiple-choice`,答案结构见 `PluginFlashcardData`。调用前必须确认用户意图;这些方法直接写入用户当前数据库,记录属于用户,不随插件卸载删除。API 不提供删除或修改已有闪卡的权限。
|
|
69
|
-
|
|
70
|
-
## 生成草稿与自动保存
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
// 只生成,插件可进一步筛选,再逐张 createCard。
|
|
74
|
-
const drafts = await context.flashcards.generate({
|
|
75
|
-
content: "需要学习的内容",
|
|
76
|
-
title: "资料",
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// 只有明确调用此方法才绕过预览,直接保存。
|
|
80
|
-
const result = await context.flashcards.generateAndSave({
|
|
81
|
-
content: "需要学习的内容",
|
|
82
|
-
title: "资料",
|
|
83
|
-
deckId: deck.id,
|
|
84
|
-
});
|
|
85
|
-
// result.cards:成功保存的记录;result.failed:失败项的零基下标和 message。
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
AI 沿用应用的闪卡制作模型,不读取或导出密钥。没有模型配置、未授权、额度不足或内容为空时明确失败,不自动选择其他模型;AI 模型变更后下一次调用使用新分配,已经进入准备过程的请求若发现分配改变会拒绝并要求重试。
|
|
89
|
-
|
|
90
|
-
自动保存先校验全部草稿,再逐张写入;不承诺整批事务。不要对整个自动保存调用盲目重试,否则会重复创建成功项。需要精确重试时,使用 `generate` 保留草稿并逐张 `createCard`。取消与切库阻止后续写入,已发出的写入可能已在原库提交,不能将取消理解为事务回滚。
|
|
91
|
-
|
|
92
|
-
这些 API 面向已激活的桌面插件;静态内容组件、博客与移动端没有此宿主能力。
|
|
1
|
+
# 闪卡能力
|
|
2
|
+
|
|
3
|
+
本文对应 SDK 0.27.0 和支持闪卡接口的 Tau 0.59.0 客户端构建。能力通过激活时的 `context.flashcards` 使用,绑定本次激活的数据库;停用、切库后旧调用失效。旧客户端可用 `if (!context.flashcards)` 检查是否支持。
|
|
4
|
+
|
|
5
|
+
## 权限与 AI 配置
|
|
6
|
+
|
|
7
|
+
直接查询卡组需在 manifest 声明 `flashcards:read`,直接创建卡组、闪卡及自动保存需声明 `flashcards:write`;使用时由用户授权,可在插件详情页撤销。引用已有正文还需对应实体的读取权限;本插件自有正文沿用免业务权限规则。打开宿主窗口必须来自用户点击或按键,窗口内的创建由用户确认,不需要闪卡读写权限。
|
|
8
|
+
|
|
9
|
+
AI 制卡直接复用应用「闪卡生成」已分配的模型,不需要声明插件自己的 AI 功能或再次选择模型。在 manifest 中声明要申请的能力:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{ "permissions": ["flashcards:read", "flashcards:write", "ai:flashcardGeneration"] }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
内部通过通用的 `context.ai.requestCapability("flashcardGeneration")` 申请“使用闪卡制作 AI”,可在插件的「权限」页撤销,撤权会取消在途生成。主进程读取应用现有模型分配,按插件身份记录用量并限制并发和每日额度;额度可在插件 AI 设置中调整。应用未配置闪卡模型时明确报错。申请其他内置模型分配或声明自己的 AI 功能见 AI.md。
|
|
16
|
+
|
|
17
|
+
## 打开宿主制卡窗口
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
const result = await context.flashcards.openCreate({
|
|
21
|
+
mode: "ai", // manual 为手动制卡,缺省为 manual
|
|
22
|
+
content: "牛顿第二定律:F = ma。", // Markdown 或 Descendant[]
|
|
23
|
+
title: "力学笔记",
|
|
24
|
+
// deckId: 123, // 可选;省略时先选择卡组,也可以现场新建卡组
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// result.status 为 completed 或 cancelled;cards 包含本次窗口已经保存的记录。
|
|
28
|
+
// 取消不会撤销「保存并新建」等已提交的记录。
|
|
29
|
+
console.log(
|
|
30
|
+
result.status,
|
|
31
|
+
result.cards.map(card => card.id)
|
|
32
|
+
);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
AI 模式自动开始生成并展示预览,可选择、编辑后保存;手动模式预填题干和参考资料,支持连续创建。未指定 references 时,content 作为自定义参考资料保存,title 用于来源标题;指定 `references: []` 可省略来源。
|
|
36
|
+
|
|
37
|
+
引用 Tau 中已有正文时,显式传入来源,避免复制正文作为参考资料:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await context.flashcards.openCreate({
|
|
41
|
+
mode: "ai",
|
|
42
|
+
content: sourceContent,
|
|
43
|
+
references: [{ refType: "content", contentRef: sourceContentRef, title: "原文" }],
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`sourceContentRef` 来自 `context.data` 的实体或 `context.entities`,不可解析或用正文数字 ID 代替。宿主核对正文身份与读取权限,失效或未获准的引用拒绝保存。
|
|
48
|
+
|
|
49
|
+
窗口操作返回的 Promise 等待用户完成。必须在按钮或其他用户操作中调用;后台和定时器调用会被拒绝,不要在 `activate()` 中等待用户操作。同一窗口仅允许一个制卡会话,重复打开明确报错。
|
|
50
|
+
|
|
51
|
+
所有创建方式返回的卡片都沿用 `PluginFlashcardDraft` 的字段:自定义参考正文为 `references[].customContent`,已有正文引用为 `references[].contentRef`。可以将返回卡片传给 `createCard` 创建副本,仍需写入和来源读取权限;已失效的引用不会出现在返回结果中。创建后来源窗口的卡组、闪卡和计数会自动刷新。
|
|
52
|
+
|
|
53
|
+
## 直接创建卡组与闪卡
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const decks = await context.flashcards.listDecks();
|
|
57
|
+
const deck = await context.flashcards.createDeck({ name: "力学", description: "基础概念" });
|
|
58
|
+
const card = await context.flashcards.createCard({
|
|
59
|
+
deckId: deck.id,
|
|
60
|
+
type: "qa",
|
|
61
|
+
prompt: [{ type: "paragraph", children: [{ text: "牛顿第二定律的表达式是什么?" }] }],
|
|
62
|
+
data: { answer: "F = ma" },
|
|
63
|
+
tags: ["力学"],
|
|
64
|
+
difficulty: "foundation",
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
题型包括 `qa/boolean/cloze/single-choice/multiple-choice`,答案结构见 `PluginFlashcardData`。调用前必须确认用户意图;这些方法直接写入用户当前数据库,记录属于用户,不随插件卸载删除。API 不提供删除或修改已有闪卡的权限。
|
|
69
|
+
|
|
70
|
+
## 生成草稿与自动保存
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// 只生成,插件可进一步筛选,再逐张 createCard。
|
|
74
|
+
const drafts = await context.flashcards.generate({
|
|
75
|
+
content: "需要学习的内容",
|
|
76
|
+
title: "资料",
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 只有明确调用此方法才绕过预览,直接保存。
|
|
80
|
+
const result = await context.flashcards.generateAndSave({
|
|
81
|
+
content: "需要学习的内容",
|
|
82
|
+
title: "资料",
|
|
83
|
+
deckId: deck.id,
|
|
84
|
+
});
|
|
85
|
+
// result.cards:成功保存的记录;result.failed:失败项的零基下标和 message。
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
AI 沿用应用的闪卡制作模型,不读取或导出密钥。没有模型配置、未授权、额度不足或内容为空时明确失败,不自动选择其他模型;AI 模型变更后下一次调用使用新分配,已经进入准备过程的请求若发现分配改变会拒绝并要求重试。
|
|
89
|
+
|
|
90
|
+
自动保存先校验全部草稿,再逐张写入;不承诺整批事务。不要对整个自动保存调用盲目重试,否则会重复创建成功项。需要精确重试时,使用 `generate` 保留草稿并逐张 `createCard`。取消与切库阻止后续写入,已发出的写入可能已在原库提交,不能将取消理解为事务回滚。
|
|
91
|
+
|
|
92
|
+
这些 API 面向已激活的桌面插件;静态内容组件、博客与移动端没有此宿主能力。
|
package/IMAGES.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# 图片生成与编辑提供方
|
|
2
|
-
|
|
3
|
-
需要 SDK 0.18.0 和支持图片插件接口的客户端。通过 `context.images.register({ id: context.pluginId, name, create })` 注册,每个插件一个提供方,可由用户配置多个账号实例。
|
|
4
|
-
|
|
5
|
-
`create(config, modelId)` 同步创建任务实例,不发网络请求。配置结构由插件解释和校验,不读取宿主 store,也不将账号凭据放进插件共享 storage。实例至少实现一个方法:
|
|
6
|
-
|
|
7
|
-
- `generate({ prompt, options? }, signal)`:文本生成图片。
|
|
8
|
-
- `edit({ prompt, options?, images }, signal)`:基于一张或多张参考图编辑。
|
|
9
|
-
|
|
10
|
-
输入图片为 `{ name, mimeType, content: Uint8Array }`。输出为相同结构的数组,可附加 `revisedPrompt`。宿主支持 PNG/JPEG/WebP,单次最多 16 张、输入和输出总大小分别不超过 128 MiB。提供方返回临时 URL 时自行下载为字节,下载时不要将 API 凭据自动传给其他域名。
|
|
11
|
-
|
|
12
|
-
`options` 包含 `size/quality/outputFormat/background/count`,仅在显式传入时映射到服务商请求。无法等价支持的参数应报告错误,不忽略、不隐式多次调用凑数量。协议、鉴权、超时、重试和轮询由插件负责;网络使用 `context.fetch` 并传入方法的 signal,轮询等待也响应取消。宿主负责文件解析、最终资源上传和正文插入。
|
|
13
|
-
|
|
14
|
-
配置视图通过 `context.settings.register({ id, title, target: "images", component })` 注册。组件接收 `PluginSettingsProps.imageConfig`:`instanceId`、`value`、`modelId`、`save(value, modelId)`。字段、布局、验证和错误提示由插件决定;保存失败保留草稿,成功后才提示已保存。模型标识也由插件表单填写。不要把正在编辑的账号误当成全局当前账号。
|
|
15
|
-
|
|
16
|
-
生成和编辑仍使用用户选择的同一个当前账号;不支持的方法不显示对应入口。停用、重载、切库或调用窗口退出会关闭任务,后续上传和保存不得接收迟到结果。取消不保证撤销远端已发生的任务或费用。图片插件不自动安装、启用或切换资源存储。
|
|
1
|
+
# 图片生成与编辑提供方
|
|
2
|
+
|
|
3
|
+
需要 SDK 0.18.0 和支持图片插件接口的客户端。通过 `context.images.register({ id: context.pluginId, name, create })` 注册,每个插件一个提供方,可由用户配置多个账号实例。
|
|
4
|
+
|
|
5
|
+
`create(config, modelId)` 同步创建任务实例,不发网络请求。配置结构由插件解释和校验,不读取宿主 store,也不将账号凭据放进插件共享 storage。实例至少实现一个方法:
|
|
6
|
+
|
|
7
|
+
- `generate({ prompt, options? }, signal)`:文本生成图片。
|
|
8
|
+
- `edit({ prompt, options?, images }, signal)`:基于一张或多张参考图编辑。
|
|
9
|
+
|
|
10
|
+
输入图片为 `{ name, mimeType, content: Uint8Array }`。输出为相同结构的数组,可附加 `revisedPrompt`。宿主支持 PNG/JPEG/WebP,单次最多 16 张、输入和输出总大小分别不超过 128 MiB。提供方返回临时 URL 时自行下载为字节,下载时不要将 API 凭据自动传给其他域名。
|
|
11
|
+
|
|
12
|
+
`options` 包含 `size/quality/outputFormat/background/count`,仅在显式传入时映射到服务商请求。无法等价支持的参数应报告错误,不忽略、不隐式多次调用凑数量。协议、鉴权、超时、重试和轮询由插件负责;网络使用 `context.fetch` 并传入方法的 signal,轮询等待也响应取消。宿主负责文件解析、最终资源上传和正文插入。
|
|
13
|
+
|
|
14
|
+
配置视图通过 `context.settings.register({ id, title, target: "images", component })` 注册。组件接收 `PluginSettingsProps.imageConfig`:`instanceId`、`value`、`modelId`、`save(value, modelId)`。字段、布局、验证和错误提示由插件决定;保存失败保留草稿,成功后才提示已保存。模型标识也由插件表单填写。不要把正在编辑的账号误当成全局当前账号。
|
|
15
|
+
|
|
16
|
+
生成和编辑仍使用用户选择的同一个当前账号;不支持的方法不显示对应入口。停用、重载、切库或调用窗口退出会关闭任务,后续上传和保存不得接收迟到结果。取消不保证撤销远端已发生的任务或费用。图片插件不自动安装、启用或切换资源存储。
|