@ycodium-ai/plugin-api 0.1.0 → 0.2.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/README.md +52 -9
- package/css/ui.css +180 -0
- package/dist/conversation.d.ts +1594 -0
- package/dist/conversation.d.ts.map +1 -0
- package/dist/conversation.js +39 -0
- package/dist/conversation.js.map +1 -0
- package/dist/index.d.ts +11 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/tool-display.d.ts +91 -0
- package/dist/tool-display.d.ts.map +1 -0
- package/dist/tool-display.js +14 -0
- package/dist/tool-display.js.map +1 -0
- package/dist/ui.d.ts +168 -3
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +37 -1
- package/dist/ui.js.map +1 -1
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -12,7 +12,15 @@ own state across restarts.
|
|
|
12
12
|
npm install --save-dev @ycodium-ai/plugin-api
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Types are erased at build time. Runtime exports such as `definePlugin` come from the
|
|
16
|
+
Ycodium host's shared copy; keep this package external when bundling your plugin.
|
|
17
|
+
|
|
18
|
+
The CSS subpath `@ycodium-ai/plugin-api/ui.css` is the public Tailwind preset for
|
|
19
|
+
plugin pages: control-axis utilities, semantic colors, status animations, and
|
|
20
|
+
`surface-glass`. It does not reset browser defaults. Host `index.css` and first-party plugin
|
|
21
|
+
stylesheets import this same file. It does not reset browser defaults. Token _values_ still come from the host
|
|
22
|
+
document (`:root` and `applyTheme`). Chart series colors are host CSS variables
|
|
23
|
+
`--provider-*`, not a second copy of the palette.
|
|
16
24
|
|
|
17
25
|
## A plugin is an npm package
|
|
18
26
|
|
|
@@ -37,11 +45,11 @@ Declare the entry file under `ycodium.plugin`:
|
|
|
37
45
|
And export the definition:
|
|
38
46
|
|
|
39
47
|
```ts
|
|
40
|
-
import { definePlugin
|
|
48
|
+
import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
41
49
|
|
|
42
50
|
export default definePlugin({
|
|
43
51
|
id: "my-plugin",
|
|
44
|
-
apiVersion:
|
|
52
|
+
apiVersion: 2,
|
|
45
53
|
activate: (ctx) => {
|
|
46
54
|
ctx.log.info("hello");
|
|
47
55
|
|
|
@@ -69,12 +77,45 @@ ycodium plugin add my-ycodium-plugin
|
|
|
69
77
|
|
|
70
78
|
## Bundle your entry file
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
Bundle your own code and private dependencies into an ESM entry. Keep
|
|
81
|
+
`@ycodium-ai/plugin-api` and its subpaths external. For esbuild:
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
external: ["@ycodium-ai/plugin-api", "@ycodium-ai/plugin-api/*"];
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The host resolves these imports to its shared API module, including for bundled official
|
|
88
|
+
plugins, npm installations, local directories, and temporary plugins. Plugins do not need
|
|
89
|
+
to copy the API into their package or depend on a particular installation directory.
|
|
90
|
+
|
|
91
|
+
Browser bundles use the same rule. Map runtime API imports to the host's module table,
|
|
92
|
+
`window.__ycodiumPluginHost.modules`, as you map React to the host's React instance.
|
|
93
|
+
For example, an alias module for a UI helper can re-export the host value:
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
const api = window.__ycodiumPluginHost.modules?.["@ycodium-ai/plugin-api/ui"];
|
|
97
|
+
if (!api) throw new Error("This plugin needs a newer Ycodium app. Update the app.");
|
|
98
|
+
export const { pluginUiHostHasCapability } = api;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The table also exposes `@ycodium-ai/plugin-api`. Keep API implementations out of page bundles;
|
|
102
|
+
type-only imports need no alias. Web and embedded plugin pages provide the same module table.
|
|
103
|
+
|
|
104
|
+
## Embedded views and host controls
|
|
105
|
+
|
|
106
|
+
`register(bridge)` can return an optional `views` map alongside `pages` and `panels`.
|
|
107
|
+
A view has no navigation entry. Its caller supplies the agreed props; the host loads it
|
|
108
|
+
from the same machine-scoped bundle and translation context as the full page. This lets
|
|
109
|
+
an embedded detail and its full page share one implementation. Missing or unloaded views
|
|
110
|
+
show an unavailable state.
|
|
75
111
|
|
|
76
|
-
|
|
77
|
-
|
|
112
|
+
The host UI surface includes `InputGroup`, `InputGroupAddon`, `InputGroupInput`,
|
|
113
|
+
`DocumentPanel`, and `MasterDetail`. `DocumentPanel` accepts `PluginUiDocumentTab` descriptors,
|
|
114
|
+
an active id, close/activate callbacks, and a `widthStorageKey`; the host supplies its tab
|
|
115
|
+
strip, menus, resize handle, and stored width. `MasterDetail` takes the list as children,
|
|
116
|
+
a `detail`, an `onBack` callback, and `onMasterVisibilityChange`. Stop hidden list observers
|
|
117
|
+
when that callback reports `false`. The list stays mounted to retain its scroll position.
|
|
118
|
+
`useLinkContextMenu` supplies the host's copy/open menu for a link.
|
|
78
119
|
|
|
79
120
|
## Permissions
|
|
80
121
|
|
|
@@ -96,7 +137,9 @@ shows up there without anyone registering it.
|
|
|
96
137
|
|
|
97
138
|
## THERE WILL BE COMPATIBILITY-BREAKING CHANGES
|
|
98
139
|
|
|
99
|
-
`
|
|
140
|
+
The definition's `apiVersion` is checked for **exact equality**. Declare the version your
|
|
141
|
+
plugin targets as a literal; do not read the host's `PLUGIN_API_VERSION` to make the declaration
|
|
142
|
+
automatically match. The current API is 2. Plugins targeting
|
|
100
143
|
API 1 are refused before activation. API 2 replaces the Teams-specific host methods with generic
|
|
101
144
|
execution ownership, command receipts, notifications, and plugin contributions. Update plugins
|
|
102
145
|
against the current types and republish; there is no compatibility layer.
|
package/css/ui.css
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/* 宿主与插件共用工具类注册;令牌值由宿主主题提供,不重置浏览器默认样式。
|
|
2
|
+
插件在自己的 @scope 下生成工具类,不依赖宿主恰好产出的同名类。 */
|
|
3
|
+
|
|
4
|
+
@theme inline {
|
|
5
|
+
--spacing-control-1: var(--control-h-1);
|
|
6
|
+
--spacing-control-2: var(--control-h-2);
|
|
7
|
+
--spacing-control-3: var(--control-h-3);
|
|
8
|
+
--spacing-control-4: var(--control-h-4);
|
|
9
|
+
--spacing-control-5: var(--control-h-5);
|
|
10
|
+
--spacing-nested-1: var(--control-h-nested-1);
|
|
11
|
+
--spacing-nested-2: var(--control-h-nested-2);
|
|
12
|
+
--spacing-nested-3: var(--control-h-nested-3);
|
|
13
|
+
--spacing-nested-4: var(--control-h-nested-4);
|
|
14
|
+
--spacing-nested-5: var(--control-h-nested-5);
|
|
15
|
+
--spacing-icon-1: var(--control-icon-1);
|
|
16
|
+
--spacing-icon-2: var(--control-icon-2);
|
|
17
|
+
--spacing-icon-3: var(--control-icon-3);
|
|
18
|
+
--spacing-icon-4: var(--control-icon-4);
|
|
19
|
+
--spacing-icon-5: var(--control-icon-5);
|
|
20
|
+
--radius-control-1: var(--control-radius-1);
|
|
21
|
+
--radius-control-2: var(--control-radius-2);
|
|
22
|
+
--radius-control-3: var(--control-radius-3);
|
|
23
|
+
--radius-control-4: var(--control-radius-4);
|
|
24
|
+
--radius-control-5: var(--control-radius-5);
|
|
25
|
+
--text-control-1: var(--control-text-1);
|
|
26
|
+
--text-control-1--line-height: var(--control-leading-1);
|
|
27
|
+
--text-control-2: var(--control-text-2);
|
|
28
|
+
--text-control-2--line-height: var(--control-leading-2);
|
|
29
|
+
--text-control-3: var(--control-text-3);
|
|
30
|
+
--text-control-3--line-height: var(--control-leading-3);
|
|
31
|
+
--text-control-4: var(--control-text-4);
|
|
32
|
+
--text-control-4--line-height: var(--control-leading-4);
|
|
33
|
+
--text-control-5: var(--control-text-5);
|
|
34
|
+
--text-control-5--line-height: var(--control-leading-5);
|
|
35
|
+
|
|
36
|
+
--animate-skeleton: skeleton 2s infinite linear;
|
|
37
|
+
/* Duty-cycled indicator animations: long holds with stepped ramps, so the
|
|
38
|
+
compositor updates discrete frames instead of every vsync. */
|
|
39
|
+
--animate-status-pulse: status-pulse 2s infinite;
|
|
40
|
+
--animate-ghost-pulse: ghost-pulse 2.4s infinite;
|
|
41
|
+
--animate-status-ping: status-ping 2s infinite;
|
|
42
|
+
--animate-status-spin: status-spin 0.9s infinite steps(3);
|
|
43
|
+
--animate-tab-run-breathe: tab-run-breathe 1.8s ease-in-out infinite;
|
|
44
|
+
|
|
45
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
46
|
+
--color-warning: var(--warning);
|
|
47
|
+
--color-warning-surface: var(--warning-surface);
|
|
48
|
+
--color-error-foreground: var(--error-foreground);
|
|
49
|
+
--color-error: var(--error);
|
|
50
|
+
--color-error-surface: var(--error-surface);
|
|
51
|
+
--color-update-foreground: var(--update-foreground);
|
|
52
|
+
--color-update: var(--update);
|
|
53
|
+
--color-update-surface: var(--update-surface);
|
|
54
|
+
--color-success-foreground: var(--success-foreground);
|
|
55
|
+
--color-success: var(--success);
|
|
56
|
+
--color-info-foreground: var(--info-foreground);
|
|
57
|
+
--color-info: var(--info);
|
|
58
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
59
|
+
--color-ring: var(--ring);
|
|
60
|
+
--color-input: var(--contrast-input);
|
|
61
|
+
--color-border: var(--contrast-border);
|
|
62
|
+
--color-destructive: var(--destructive);
|
|
63
|
+
--color-accent-foreground: var(--contrast-accent-foreground);
|
|
64
|
+
--color-accent: var(--accent);
|
|
65
|
+
--color-accent-pressed: var(--accent-pressed);
|
|
66
|
+
--color-muted-foreground: var(--contrast-muted-foreground);
|
|
67
|
+
--color-muted: var(--muted);
|
|
68
|
+
--color-placeholder: var(--contrast-placeholder);
|
|
69
|
+
--color-secondary-label: var(--contrast-secondary-label);
|
|
70
|
+
--color-icon-muted: var(--contrast-icon-muted);
|
|
71
|
+
--color-secondary-foreground: var(--contrast-secondary-foreground);
|
|
72
|
+
--color-secondary: var(--secondary);
|
|
73
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
74
|
+
--color-primary: var(--primary);
|
|
75
|
+
--color-popover-foreground: var(--contrast-popover-foreground);
|
|
76
|
+
--color-popover: var(--popover);
|
|
77
|
+
--color-card-foreground: var(--contrast-card-foreground);
|
|
78
|
+
--color-card: var(--card);
|
|
79
|
+
--color-foreground: var(--contrast-foreground);
|
|
80
|
+
--color-background: var(--background);
|
|
81
|
+
|
|
82
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
83
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
84
|
+
--radius-lg: var(--radius);
|
|
85
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
86
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
87
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
88
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
89
|
+
|
|
90
|
+
@keyframes skeleton {
|
|
91
|
+
/* Transform-only so the highlight sweep stays on the compositor, then a
|
|
92
|
+
long hold with the band parked off-screen instead of a constant shimmer. */
|
|
93
|
+
0% {
|
|
94
|
+
transform: translateX(-100%);
|
|
95
|
+
}
|
|
96
|
+
60%,
|
|
97
|
+
100% {
|
|
98
|
+
transform: translateX(100%);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
@keyframes ghost-pulse {
|
|
102
|
+
/* The loading ghosts' breath. Stepped like the status indicators, so however many bars a
|
|
103
|
+
ghost holds, the compositor draws a handful of discrete frames per cycle rather than one
|
|
104
|
+
per vsync — which on a 120Hz display is the difference between ~14 and ~288 updates. */
|
|
105
|
+
0%,
|
|
106
|
+
42% {
|
|
107
|
+
opacity: 1;
|
|
108
|
+
animation-timing-function: steps(4);
|
|
109
|
+
}
|
|
110
|
+
50%,
|
|
111
|
+
92% {
|
|
112
|
+
opacity: 0.55;
|
|
113
|
+
animation-timing-function: steps(4);
|
|
114
|
+
}
|
|
115
|
+
100% {
|
|
116
|
+
opacity: 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
@keyframes status-pulse {
|
|
120
|
+
0%,
|
|
121
|
+
40% {
|
|
122
|
+
opacity: 1;
|
|
123
|
+
animation-timing-function: steps(6);
|
|
124
|
+
}
|
|
125
|
+
50%,
|
|
126
|
+
90% {
|
|
127
|
+
opacity: 0.5;
|
|
128
|
+
animation-timing-function: steps(6);
|
|
129
|
+
}
|
|
130
|
+
100% {
|
|
131
|
+
opacity: 1;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/* 只转 45° 就回到起点:消费者是 8 段等距的虚线圈,转满一格跟自己完全重合,
|
|
135
|
+
所以循环点无缝,不必真的转满 360°。steps(3) 让一圈只有三帧——分步是这里的
|
|
136
|
+
全部意义,连续旋转会在高刷屏上每 vsync 重绘一次。 */
|
|
137
|
+
@keyframes status-spin {
|
|
138
|
+
to {
|
|
139
|
+
transform: rotate(45deg);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/* 会话运行点的呼吸。**只动 opacity**,别加 `transform: scale`——实测在 DPR 1.5
|
|
143
|
+
的屏幕上 Blink 不把 transform 动画交给合成器,每帧回主线程做一次全局样式
|
|
144
|
+
重算:5 秒 810 次(无动画时 27 次)。rotate 与 scale 都一样,跟元素大小无关,
|
|
145
|
+
4px 的点加了 scale 照样 810 次。只淡入淡出是 80 次。 */
|
|
146
|
+
@keyframes tab-run-breathe {
|
|
147
|
+
0%,
|
|
148
|
+
100% {
|
|
149
|
+
opacity: 1;
|
|
150
|
+
}
|
|
151
|
+
50% {
|
|
152
|
+
opacity: 0.35;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
@keyframes status-ping {
|
|
156
|
+
/* Burst first (immediate feedback for click ripples), then hold
|
|
157
|
+
invisible for the rest of the cycle. Mirrors animate-ping's
|
|
158
|
+
75%-scale start. */
|
|
159
|
+
0% {
|
|
160
|
+
opacity: 0.9;
|
|
161
|
+
scale: 0.75;
|
|
162
|
+
animation-timing-function: steps(8);
|
|
163
|
+
}
|
|
164
|
+
40%,
|
|
165
|
+
100% {
|
|
166
|
+
opacity: 0;
|
|
167
|
+
scale: 2;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@utility surface-glass {
|
|
173
|
+
background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent);
|
|
174
|
+
-webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation));
|
|
175
|
+
backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation));
|
|
176
|
+
|
|
177
|
+
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
|
|
178
|
+
background: var(--background) !important;
|
|
179
|
+
}
|
|
180
|
+
}
|