@plumeai/plugin-sdk 0.0.0-stage → 0.1.2
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/LICENSE +21 -0
- package/bin/plume-plugin.mjs +70 -0
- package/dist/client/styles/src/index.d.ts +123 -0
- package/dist/client/ui/src/avatar/AgentAvatar.d.ts +42 -0
- package/dist/client/ui/src/avatar/AvatarPile.d.ts +36 -0
- package/dist/client/ui/src/avatar/AvatarStack.d.ts +26 -0
- package/dist/client/ui/src/avatar/art.d.ts +32 -0
- package/dist/client/ui/src/fileIcon.d.ts +33 -0
- package/dist/client/ui/src/hooks/useCopied.d.ts +16 -0
- package/dist/client/ui/src/hooks/useLiveRefresh.d.ts +22 -0
- package/dist/client/ui/src/hooks/useNarrow.d.ts +16 -0
- package/dist/client/ui/src/i18n/context.d.ts +17 -0
- package/dist/client/ui/src/i18n/index.d.ts +2 -0
- package/dist/client/ui/src/i18n/list.d.ts +20 -0
- package/dist/client/ui/src/i18n/locales.d.ts +10 -0
- package/dist/client/ui/src/i18n/messages/en.d.ts +1418 -0
- package/dist/client/ui/src/i18n/messages/index.d.ts +6 -0
- package/dist/client/ui/src/i18n/messages/zh-CN.d.ts +1263 -0
- package/dist/client/ui/src/i18n/plural.d.ts +16 -0
- package/dist/client/ui/src/i18n/translate.d.ts +43 -0
- package/dist/client/ui/src/icons/index.d.ts +5 -0
- package/dist/client/ui/src/image/AnnotateCanvas.d.ts +29 -0
- package/dist/client/ui/src/image/AnnotateToolbar.d.ts +73 -0
- package/dist/client/ui/src/image/Annotator.d.ts +154 -0
- package/dist/client/ui/src/image/annotate.d.ts +227 -0
- package/dist/client/ui/src/image/paint.d.ts +35 -0
- package/dist/client/ui/src/image/screenshot-geometry.d.ts +112 -0
- package/dist/client/ui/src/image/useBarDrag.d.ts +31 -0
- package/dist/client/ui/src/image/useMovableBar.d.ts +26 -0
- package/dist/client/ui/src/image/useToolbarPlacement.d.ts +42 -0
- package/dist/client/ui/src/index.d.ts +140 -0
- package/dist/client/ui/src/inputs/ColorField.d.ts +9 -0
- package/dist/client/ui/src/inputs/ComposerToggle.d.ts +23 -0
- package/dist/client/ui/src/inputs/DateRangeField.d.ts +25 -0
- package/dist/client/ui/src/inputs/NativeField.d.ts +5 -0
- package/dist/client/ui/src/inputs/SearchField.d.ts +21 -0
- package/dist/client/ui/src/inputs/Segmented.d.ts +23 -0
- package/dist/client/ui/src/inputs/Select.d.ts +32 -0
- package/dist/client/ui/src/inputs/ShortcutRecorder.d.ts +8 -0
- package/dist/client/ui/src/inputs/Slider.d.ts +13 -0
- package/dist/client/ui/src/inputs/TextArea.d.ts +30 -0
- package/dist/client/ui/src/inputs/Toggle.d.ts +10 -0
- package/dist/client/ui/src/inputs/WorktreeToggle.d.ts +19 -0
- package/dist/client/ui/src/inputs/day-range.d.ts +57 -0
- package/dist/client/ui/src/inputs/pickers.d.ts +40 -0
- package/dist/client/ui/src/inputs/useFieldFade.d.ts +1 -0
- package/dist/client/ui/src/keyboard.d.ts +21 -0
- package/dist/client/ui/src/layout/ApprovalFrame.d.ts +33 -0
- package/dist/client/ui/src/layout/Collapse.d.ts +9 -0
- package/dist/client/ui/src/layout/CopyMark.d.ts +19 -0
- package/dist/client/ui/src/layout/Disclosure.d.ts +66 -0
- package/dist/client/ui/src/layout/ErrorBoundary.d.ts +26 -0
- package/dist/client/ui/src/layout/PageTopRow.d.ts +19 -0
- package/dist/client/ui/src/layout/PanelEmpty.d.ts +17 -0
- package/dist/client/ui/src/layout/ResizeHandle.d.ts +24 -0
- package/dist/client/ui/src/layout/RetainedViews.d.ts +32 -0
- package/dist/client/ui/src/layout/Settings.d.ts +41 -0
- package/dist/client/ui/src/layout/Splitter.d.ts +25 -0
- package/dist/client/ui/src/lib/agent-avatar.d.ts +58 -0
- package/dist/client/ui/src/lib/code/font-stack.d.ts +12 -0
- package/dist/client/ui/src/lib/code/themes.d.ts +35 -0
- package/dist/client/ui/src/lib/date-format.d.ts +8 -0
- package/dist/client/ui/src/lib/dispatches.d.ts +8 -0
- package/dist/client/ui/src/lib/hour-style.d.ts +13 -0
- package/dist/client/ui/src/lib/number-draft.d.ts +24 -0
- package/dist/client/ui/src/lib/relative-time.d.ts +18 -0
- package/dist/client/ui/src/lib/tiling.d.ts +89 -0
- package/dist/client/ui/src/lib/typing.d.ts +19 -0
- package/dist/client/ui/src/motion/RollWords.d.ts +26 -0
- package/dist/client/ui/src/motion/RollingText.d.ts +43 -0
- package/dist/client/ui/src/motion/TypedText.d.ts +9 -0
- package/dist/client/ui/src/motion/freeze.d.ts +22 -0
- package/dist/client/ui/src/motion/held.d.ts +17 -0
- package/dist/client/ui/src/motion/loaders.d.ts +65 -0
- package/dist/client/ui/src/motion/reduced.d.ts +13 -0
- package/dist/client/ui/src/motion/ticked.d.ts +24 -0
- package/dist/client/ui/src/motion/ticker.d.ts +31 -0
- package/dist/client/ui/src/motion/tokens.d.ts +29 -0
- package/dist/client/ui/src/motion/useNow.d.ts +6 -0
- package/dist/client/ui/src/overlay/Confirm.d.ts +96 -0
- package/dist/client/ui/src/overlay/ContextMenu.d.ts +40 -0
- package/dist/client/ui/src/overlay/Dialog.d.ts +60 -0
- package/dist/client/ui/src/overlay/Menu.d.ts +90 -0
- package/dist/client/ui/src/overlay/Overlay.d.ts +17 -0
- package/dist/client/ui/src/overlay/Popover.d.ts +127 -0
- package/dist/client/ui/src/overlay/Tooltip.d.ts +14 -0
- package/dist/client/ui/src/overlay/afterimage.d.ts +20 -0
- package/dist/client/ui/src/overlay/chrome-top.d.ts +8 -0
- package/dist/client/ui/src/overlay/hover-layers.d.ts +41 -0
- package/dist/client/ui/src/overlay/portal.d.ts +21 -0
- package/dist/client/ui/src/overlay/scrims.d.ts +20 -0
- package/dist/client/ui/src/overlay/tooltip-attribute.d.ts +62 -0
- package/dist/client/ui/src/primitives/Button.d.ts +64 -0
- package/dist/client/ui/src/primitives/Caret.d.ts +25 -0
- package/dist/client/ui/src/primitives/ChoiceMark.d.ts +12 -0
- package/dist/client/ui/src/primitives/ClosableTab.d.ts +23 -0
- package/dist/client/ui/src/primitives/CountUp.d.ts +21 -0
- package/dist/client/ui/src/primitives/GitHubMark.d.ts +12 -0
- package/dist/client/ui/src/primitives/IconButton.d.ts +55 -0
- package/dist/client/ui/src/primitives/MarkNumber.d.ts +12 -0
- package/dist/client/ui/src/primitives/RowDeleteButton.d.ts +6 -0
- package/dist/client/ui/src/primitives/Skeleton.d.ts +36 -0
- package/dist/client/ui/src/primitives/TabStrip.d.ts +29 -0
- package/dist/client/ui/src/primitives/Text.d.ts +341 -0
- package/dist/client/ui/src/primitives/TimeAgo.d.ts +13 -0
- package/dist/client/ui/src/primitives/useCountUp.d.ts +23 -0
- package/dist/client/ui/src/row/FlowRow.d.ts +31 -0
- package/dist/client/ui/src/row/HoverRow.d.ts +28 -0
- package/dist/client/ui/src/scroll/BackToLatest.d.ts +19 -0
- package/dist/client/ui/src/scroll/OverlayScrollbar.d.ts +9 -0
- package/dist/client/ui/src/scroll/ScrollText.d.ts +24 -0
- package/dist/client/ui/src/scroll/Scroller.d.ts +66 -0
- package/dist/client/ui/src/scroll/Sideways.d.ts +30 -0
- package/dist/client/ui/src/scroll/fade.d.ts +2 -0
- package/dist/client/ui/src/scroll/follow.d.ts +157 -0
- package/dist/client/ui/src/scroll/measure-batch.d.ts +13 -0
- package/dist/client/ui/src/scroll/memory.d.ts +22 -0
- package/dist/client/ui/src/scroll/signature.d.ts +24 -0
- package/dist/client/ui/src/scroll/useFollowBottom.d.ts +80 -0
- package/dist/client/ui/src/scroll/useSideways.d.ts +29 -0
- package/dist/contract/src/app.d.ts +16 -0
- package/dist/contract/src/changes.d.ts +50 -0
- package/dist/contract/src/diagnostics.d.ts +86 -0
- package/dist/contract/src/index.d.ts +18 -0
- package/dist/contract/src/plugin.d.ts +1391 -0
- package/dist/contract/src/resources.d.ts +79 -0
- package/dist/contract/src/service.d.ts +806 -0
- package/dist/contract/src/ui.d.ts +1039 -0
- package/dist/contract/src/usage.d.ts +102 -0
- package/dist/core/llm/ai/anthropic-messages-request.d.ts +82 -0
- package/dist/core/llm/ai/anthropic-messages.d.ts +43 -0
- package/dist/core/llm/ai/cache-routing.d.ts +53 -0
- package/dist/core/llm/ai/chat-delta.d.ts +107 -0
- package/dist/core/llm/ai/compat-key.d.ts +19 -0
- package/dist/core/llm/ai/endpoint.d.ts +57 -0
- package/dist/core/llm/ai/failure.d.ts +181 -0
- package/dist/core/llm/ai/index.d.ts +16 -0
- package/dist/core/llm/ai/openai-chat-completions-request.d.ts +49 -0
- package/dist/core/llm/ai/openai-chat-completions.d.ts +37 -0
- package/dist/core/llm/ai/openai-responses-request.d.ts +63 -0
- package/dist/core/llm/ai/openai-responses.d.ts +11 -0
- package/dist/core/llm/ai/prefix-fingerprint.d.ts +20 -0
- package/dist/core/llm/ai/reasoning-compat.d.ts +69 -0
- package/dist/core/llm/ai/request-params-compat.d.ts +39 -0
- package/dist/core/llm/ai/retry.d.ts +130 -0
- package/dist/core/llm/ai/sanitize-history.d.ts +23 -0
- package/dist/core/llm/ai/think-tag.d.ts +37 -0
- package/dist/core/llm/ai/thinking-options.d.ts +35 -0
- package/dist/core/llm/ai/tool-names.d.ts +17 -0
- package/dist/core/llm/ai/tool-pairing-compat.d.ts +53 -0
- package/dist/core/llm/ai/tool-result-images-compat.d.ts +24 -0
- package/dist/core/llm/ai/tool-schema.d.ts +20 -0
- package/dist/core/llm/ai/usage-fields.d.ts +30 -0
- package/dist/core/llm/ai/vendors/index.d.ts +20 -0
- package/dist/core/llm/ai/vendors/thinking.d.ts +39 -0
- package/dist/core/llm/ai/vendors/types.d.ts +47 -0
- package/dist/core/llm/config/image-models.d.ts +34 -0
- package/dist/core/llm/config/retry-policy.d.ts +35 -0
- package/dist/core/llm/images/chat-images.d.ts +11 -0
- package/dist/core/llm/images/dimensions.d.ts +15 -0
- package/dist/core/llm/images/generate.d.ts +15 -0
- package/dist/core/llm/images/openai-images.d.ts +11 -0
- package/dist/core/llm/images/quota.d.ts +9 -0
- package/dist/core/llm/images/shape.d.ts +44 -0
- package/dist/core/llm/images/types.d.ts +118 -0
- package/dist/core/llm/model-catalog-format.d.ts +50 -0
- package/dist/core/llm/model-catalog.d.ts +51 -0
- package/dist/core/llm/types/message.d.ts +450 -0
- package/dist/core/llm/types/provider.d.ts +169 -0
- package/dist/core/llm/types/tool.d.ts +23 -0
- package/dist/core/llm/types.d.ts +10 -0
- package/dist/core/llm/utils/pricing.d.ts +18 -0
- package/dist/core/llm/utils/record.d.ts +2 -0
- package/dist/core/llm/utils/sse.d.ts +69 -0
- package/dist/infra/rpc/src/endpoint.d.ts +36 -0
- package/dist/infra/rpc/src/index.d.ts +2 -0
- package/dist/infra/rpc/src/rpc.d.ts +54 -0
- package/dist/theme.css +336 -0
- package/dist/ui.d.ts +2 -0
- package/lib/build.mjs +143 -0
- package/lib/check.mjs +23 -0
- package/lib/dev.mjs +52 -0
- package/lib/icons.mjs +2 -0
- package/lib/init.mjs +109 -0
- package/lib/install.mjs +80 -0
- package/lib/link.mjs +44 -0
- package/lib/lint/i18n.mjs +149 -0
- package/lib/lint/imports.mjs +83 -0
- package/lib/lint/index.mjs +54 -0
- package/lib/lint/styles.mjs +160 -0
- package/lib/manifest.d.mts +9 -0
- package/lib/manifest.mjs +99 -0
- package/lib/targets.mjs +60 -0
- package/package.json +34 -4
- package/skill/SKILL.md +150 -0
- package/skill/references/components.md +2830 -0
- package/skill/references/logic.md +526 -0
- package/skill/references/style-i18n.md +70 -0
- package/skill/references/ui.md +532 -0
- package/template/AGENTS.md +17 -0
- package/template/CLAUDE.md +1 -0
- package/template/README.md +12 -0
- package/template/gitignore +2 -0
- package/template/src/index.ts +28 -0
- package/template/src/messages.ts +16 -0
- package/template/src/types.ts +8 -0
- package/template/src/ui.tsx +30 -0
- package/template/tsconfig.json +7 -0
- package/tsconfig.json +25 -0
- package/README.md +0 -3
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Minimal SSE reader. Yields one parsed frame per `data:` payload. */
|
|
2
|
+
export interface SseFrame {
|
|
3
|
+
event?: string;
|
|
4
|
+
data: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 同一条 SSE 流,加一个空闲闸。
|
|
8
|
+
*
|
|
9
|
+
* `readSse` 只接一个 AbortSignal,没有计时器:上游把连接挂住不再发帧时,那个 `await reader.read()`
|
|
10
|
+
* 就一直等下去,界面上是一个永远转着的圈,用户只能按停。计时另起一个控制器加在外面,和调用方那个
|
|
11
|
+
* 信号并起来交给它,每收到一块字节把计时拨回去。**默认行为一个字节都不变**——正常流里唯一多出来的事是
|
|
12
|
+
* 一次 `clearTimeout` + 一次 `setTimeout`。
|
|
13
|
+
*
|
|
14
|
+
* 住在这里而不是某一条链里:三条链的上游都会挂住,而这个函数本来写着「它被三条链共用」的注释,却
|
|
15
|
+
* 只有 Anthropic 那条接了——两条 OpenAI 链一直是裸的 `readSse`,挂住就无限等。共用的东西放在共用的
|
|
16
|
+
* 地方,是这件事不会再走岔的唯一办法。
|
|
17
|
+
*
|
|
18
|
+
* 取舍两点,都记在这里:
|
|
19
|
+
*
|
|
20
|
+
* - 计时是**字节级**的,不是帧级的。只按帧算时,`: keepalive`、OpenRouter 的 `: OPENROUTER PROCESSING`
|
|
21
|
+
* 这类注释行保活不产出帧、不拨计时,一条一直在发保活的长思考会被当成死流闸掉。代价是一个只滴字节
|
|
22
|
+
* 不成帧的上游闸不掉——那种上游没见过,而保活是天天在跑的。
|
|
23
|
+
* - `readSse` 收到 abort 之后走的是 `reader.cancel()`,那个生成器会**正常结束**而不是抛。所以闸掉
|
|
24
|
+
* 这件事得另外写在 `state.tripped` 上让调用方看——不看的话,一条挂死的流会被当成「模型没话说」,
|
|
25
|
+
* 或者更糟:一个截断了的回答被当成完整的。
|
|
26
|
+
*/
|
|
27
|
+
export declare function readSseWithIdleTimeout(response: Response, signal: AbortSignal | undefined, idleMs: number, state: {
|
|
28
|
+
tripped: boolean;
|
|
29
|
+
}): AsyncGenerator<SseFrame>;
|
|
30
|
+
/**
|
|
31
|
+
* 一条流安静多久算它已经死了。
|
|
32
|
+
*
|
|
33
|
+
* 十分钟,不是一个延迟指标而是一个死锁闸:生成期间各家都会周期性地发 `ping` 之类的保活帧,任何一帧
|
|
34
|
+
* 都把计时重新拨回去。所以走到这个阈值意味着**一帧都没有**,那不是「在想」。
|
|
35
|
+
*/
|
|
36
|
+
export declare const STREAM_IDLE_TIMEOUT_MS = 600000;
|
|
37
|
+
/**
|
|
38
|
+
* 底层 HTTP 客户端的超时,宿主进程启动时装到全局 dispatcher 上(desktop `electron/main.ts`、cli `src/main.ts`)。
|
|
39
|
+
*
|
|
40
|
+
* Node 内置 fetch(undici)默认 `bodyTimeout` / `headersTimeout` 各 300 秒,比上面这个闸短一半:一条合法
|
|
41
|
+
* 沉默五分钟的流会先被 undici 以 `terminated`(`UND_ERR_BODY_TIMEOUT`)切断,再当成断线整轮重发——闸
|
|
42
|
+
* 形同虚设,钱付两遍。所以底层必须比闸长,留一分钟让闸先落、报出能看懂的那句话。
|
|
43
|
+
*/
|
|
44
|
+
export declare const TRANSPORT_TIMEOUT_MS: number;
|
|
45
|
+
/**
|
|
46
|
+
* Parse tool-call arguments that may be truncated mid-stream.
|
|
47
|
+
*
|
|
48
|
+
* A model that hits the output limit leaves `{"path": "/a/b` on the wire. Returning `{}` there
|
|
49
|
+
* would hand the tool a silently empty argument set, so callers get `null` and fail the call
|
|
50
|
+
* instead of executing something wrong.
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* 一段工具参数,变成能往字符串上接的样子。
|
|
54
|
+
*
|
|
55
|
+
* 协议写的是「参数按 JSON 字符串分片流式发来」,两条 OpenAI 链的解码器都照这个写:`raw += 片段`。
|
|
56
|
+
* 有的宿主不这么发——它一次给一个**完整的对象**(Google 的 `part.functionCall.args` 就是,中转站转译时
|
|
57
|
+
* 也会变成这样)。对象碰上 `+` 会被 JS 悄悄转成 `"[object Object]"`,于是模型明明说了参数,工具收到的
|
|
58
|
+
* 是这么一串东西:
|
|
59
|
+
*
|
|
60
|
+
* "tool_calls": [{ "function": { "name": "calc", "arguments": "[object Object]" } }]
|
|
61
|
+
*
|
|
62
|
+
* 这一条特别难查,因为它不报错:请求发得出去,工具照跑,只是参数没了。真实端点上量到过一次,
|
|
63
|
+
* `deepseek-v4-flash:0731` 经中转站走 Chat Completions,第二轮的错是上游解析那串东西时报的
|
|
64
|
+
* 「Value looks like object, but can't find closing」——离真正的原因隔了一整个来回。
|
|
65
|
+
*
|
|
66
|
+
* 对象序列化成 JSON;字符串原样。其余(数字、布尔)按空处理:那不是参数分片,接上去只会污染缓冲区。
|
|
67
|
+
*/
|
|
68
|
+
export declare function argumentFragment(value: unknown): string;
|
|
69
|
+
export declare function parseToolArguments(text: string): Record<string, unknown> | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 在 RpcChannel 上暴露一个对象、调用对端的对象。消息是 `{ method, args }`。
|
|
3
|
+
*
|
|
4
|
+
* 约定:
|
|
5
|
+
* - 被调方法的最后一个参数是 CallContext,由这里追加,调用方不用传。需要响应取消的方法把参数个数写死。
|
|
6
|
+
* - 方法返回异步迭代器(如 async generator)时,每个值作为中间值推给调用方,迭代器的 return 值是最终结果。
|
|
7
|
+
*/
|
|
8
|
+
import { type RpcChannel } from "./rpc.ts";
|
|
9
|
+
/** 被调方法收到的最后一个参数。 */
|
|
10
|
+
export interface CallContext {
|
|
11
|
+
/** 调用方取消、超时或通道关闭时中止。 */
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 一次远程调用。`await` 拿最终结果;方法返回异步迭代器时,还可以 `for await` 逐个拿中间值。
|
|
16
|
+
*/
|
|
17
|
+
export interface RemoteCall<Y, R> extends PromiseLike<R>, AsyncIterable<Y> {
|
|
18
|
+
then<A = R, B = never>(onfulfilled?: ((value: R) => A | PromiseLike<A>) | null, onrejected?: ((reason: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;
|
|
19
|
+
catch<E = never>(onrejected?: ((reason: unknown) => E | PromiseLike<E>) | null): Promise<R | E>;
|
|
20
|
+
finally(onfinally?: (() => void) | null): Promise<R>;
|
|
21
|
+
/** 取消这次调用:对端收到中止信号,本地以 E_CANCELLED 失败。 */
|
|
22
|
+
cancel(): void;
|
|
23
|
+
}
|
|
24
|
+
type RemoteMethod<F> = F extends (...args: infer A) => infer R ? (...args: A extends [...infer Head, CallContext] ? Head : A) => R extends AsyncIterable<infer Y> ? RemoteCall<Y, AsyncReturn<R>> : RemoteCall<never, Awaited<R>> : never;
|
|
25
|
+
type AsyncReturn<R> = R extends AsyncGenerator<unknown, infer Return, unknown> ? Return : undefined;
|
|
26
|
+
/** 远端对象的代理:每个方法都变成 RemoteCall,末尾的 CallContext 参数由对端补上。 */
|
|
27
|
+
export type Remote<T> = {
|
|
28
|
+
[K in keyof T]: RemoteMethod<T[K]>;
|
|
29
|
+
};
|
|
30
|
+
/** 把 target 暴露在通道上。target 是函数时每次调用现取,适合会被替换的对象。 */
|
|
31
|
+
export declare function serve(channel: RpcChannel, target: object | (() => object)): void;
|
|
32
|
+
/** 对端对象的代理。signal 中止时取消这个代理上所有进行中的调用。 */
|
|
33
|
+
export declare function remote<T extends object>(channel: RpcChannel, options?: {
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}): Remote<T>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 两个进程之间的双向 RPC。只依赖一个能收发结构化克隆消息的 Port,
|
|
3
|
+
* 所以 utilityProcess 的 parentPort、渲染进程的 MessagePort、测试里的内存管道都能用同一套。
|
|
4
|
+
* 不依赖任何第三方库:它会被打进渲染进程。
|
|
5
|
+
*/
|
|
6
|
+
export type ErrorCode = "E_NOT_FOUND" | "E_TIMEOUT" | "E_CANCELLED" | "E_CLOSED" | "E_HANDLER";
|
|
7
|
+
export interface Port {
|
|
8
|
+
post(message: unknown): void;
|
|
9
|
+
/** 返回取消监听的函数。 */
|
|
10
|
+
listen(listener: (message: unknown) => void): () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare class RpcError extends Error {
|
|
13
|
+
readonly code: ErrorCode;
|
|
14
|
+
constructor(code: ErrorCode, message: string);
|
|
15
|
+
}
|
|
16
|
+
export declare function toRpcError(error: unknown, fallback?: ErrorCode): RpcError;
|
|
17
|
+
export interface RequestOptions {
|
|
18
|
+
/** 不填表示不限时。 */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
/** 中止时向对端发取消,本地以 E_CANCELLED 失败。 */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
/** 收到中间值时调用。 */
|
|
23
|
+
onChunk?(value: unknown): void;
|
|
24
|
+
}
|
|
25
|
+
/** 处理方看到的这次调用。 */
|
|
26
|
+
export interface IncomingCall {
|
|
27
|
+
/** 发起方取消、超时或通道关闭时中止。 */
|
|
28
|
+
signal: AbortSignal;
|
|
29
|
+
/** 推送一个中间值给发起方。 */
|
|
30
|
+
emit(value: unknown): void;
|
|
31
|
+
}
|
|
32
|
+
export interface RpcHandlers {
|
|
33
|
+
request?(payload: unknown, call: IncomingCall): unknown;
|
|
34
|
+
note?(payload: unknown): void;
|
|
35
|
+
}
|
|
36
|
+
export declare class RpcChannel {
|
|
37
|
+
private readonly port;
|
|
38
|
+
private handlers;
|
|
39
|
+
private seq;
|
|
40
|
+
private readonly pending;
|
|
41
|
+
private readonly incoming;
|
|
42
|
+
private readonly unlisten;
|
|
43
|
+
private closedWith;
|
|
44
|
+
constructor(port: Port, handlers?: RpcHandlers);
|
|
45
|
+
setHandlers(handlers: RpcHandlers): void;
|
|
46
|
+
get closed(): boolean;
|
|
47
|
+
request(payload: unknown, options?: RequestOptions): Promise<unknown>;
|
|
48
|
+
notify(payload: unknown): void;
|
|
49
|
+
/** 关闭通道:挂起的请求全部以 E_CLOSED 失败,正在处理的请求被中止,之后的收发都被忽略。 */
|
|
50
|
+
close(reason?: string): void;
|
|
51
|
+
private settle;
|
|
52
|
+
private receive;
|
|
53
|
+
private answer;
|
|
54
|
+
}
|
package/dist/theme.css
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 设计 token。每一处界面都从这里挑,不写临时的色值、字号、圆角。
|
|
3
|
+
*
|
|
4
|
+
* 颜色只有三个种子:背景 --plume-bg、前景 --plume-fg、强调色 --plume-accent,加一个对比度 --plume-contrast(0–1)。
|
|
5
|
+
* 其余色阶都由种子推出来:面从背景往前景走,字从背景往前景走得更远,都乘对比度。
|
|
6
|
+
* 换一个背景也不会得到看不清的字或看不见的线;皮肤通常只改种子,个别 token 不满意再单独覆盖。
|
|
7
|
+
*
|
|
8
|
+
* - 产品和 @plume/ui 用 Tailwind 工具类(bg-card、text-ink-muted、border-line……),由下面的 @theme 映射到 token;
|
|
9
|
+
* Tailwind 自带的色板、字号清空了,只能用这里的;圆角用 Tailwind 的刻度加这里几档有语义的。可复用的类名组合在同一个包的 index.ts。
|
|
10
|
+
* - 每个 token 用在哪、什么时候加新的,见 spec/tech/tokens.md;写法规则见 spec/tech/styling.md。
|
|
11
|
+
* - 插件的界面入口单独构建,产品的 Tailwind 扫不到它们自己写的类名:插件用 @plume/ui 的组件、
|
|
12
|
+
* @plume/styles 导出的类名组合,要自己写样式时用 var(--plume-*),深浅色和皮肤都自动跟着变。
|
|
13
|
+
* - 皮肤插件经 ui.skin 覆盖这些变量;token 有增减时同步 @plume/contract/ui 的 SkinToken。
|
|
14
|
+
*
|
|
15
|
+
* 改了默认背景记得同步 apps/desktop/src/main/index.ts 里窗口的 backgroundColor。
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
color-scheme: light dark;
|
|
20
|
+
|
|
21
|
+
/* ── 种子 ── */
|
|
22
|
+
--plume-bg: #f8f8f8;
|
|
23
|
+
--plume-fg: #262626;
|
|
24
|
+
--plume-accent: #339cff;
|
|
25
|
+
/* 0–1,每一档推导都乘 0.5 + 它,也就是 0.5×–1.5×。 */
|
|
26
|
+
--plume-contrast: 0.6;
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* 推导的系数,按深浅色不同。不是 token,皮肤不改。
|
|
30
|
+
*
|
|
31
|
+
* 浅色下面和线分开算:面贴近页面(0.45×),线离页面远(1.7×)。共用一条曲线时线会比它要分隔的卡片还浅,
|
|
32
|
+
* 每一层只能靠变灰来分开,叠三层整个界面就是灰的。深色下面变亮和字变亮是同一个方向,共用一条曲线(1×)。
|
|
33
|
+
*/
|
|
34
|
+
--plume-k: calc(0.5 + var(--plume-contrast));
|
|
35
|
+
--plume-k-surface: 0.45;
|
|
36
|
+
--plume-k-rule: 1.7;
|
|
37
|
+
/* 最浅那档字:浅色 52%、深色 56%,在最浅的面上也有 3:1。 */
|
|
38
|
+
--plume-k-faint: 52%;
|
|
39
|
+
|
|
40
|
+
/* ── 面 ── */
|
|
41
|
+
/* 窗口底色。 */
|
|
42
|
+
--plume-shell: var(--plume-bg);
|
|
43
|
+
/* 窗口最外层,数据皮肤可将它与正文区分开。 */
|
|
44
|
+
--plume-root: var(--plume-shell);
|
|
45
|
+
/* 强调色弱底;数据皮肤可直接指定,不再从强调色透明度推导。 */
|
|
46
|
+
--plume-accent-dim: color-mix(in srgb, var(--plume-accent) 10%, transparent);
|
|
47
|
+
--plume-sidebar: color-mix(in srgb, var(--plume-fg) calc(4.2% * var(--plume-k) * var(--plume-k-surface)), var(--plume-bg));
|
|
48
|
+
/* 卡片:工具卡片、用户消息。 */
|
|
49
|
+
--plume-card: color-mix(in srgb, var(--plume-fg) calc(6% * var(--plume-k) * var(--plume-k-surface)), var(--plume-bg));
|
|
50
|
+
/* 悬停、选中:前景色的一层薄纱,压在什么上面都看得出来。 */
|
|
51
|
+
--plume-card-hover: color-mix(in srgb, var(--plume-fg) 5%, transparent);
|
|
52
|
+
--plume-elevated: color-mix(in srgb, var(--plume-fg) 8.5%, transparent);
|
|
53
|
+
/* 输入框像纸:浅色下比页面更亮,往白走,而不是往前景走成灰的。 */
|
|
54
|
+
--plume-input: color-mix(in srgb, #fff 65%, var(--plume-bg));
|
|
55
|
+
/* 浮在最上面的:菜单、弹层。比它盖住的东西亮。 */
|
|
56
|
+
--plume-float: color-mix(in srgb, #fff 80%, var(--plume-bg));
|
|
57
|
+
/* 开关的圆点。深色下也是白的:灰圆点压在打开时的强调色上像脏了一块,开关最该清楚的时候反而最不清楚。 */
|
|
58
|
+
--plume-knob: #fff;
|
|
59
|
+
/*
|
|
60
|
+
* 纯黑,只按透明度用(color-mix 到 transparent):对话框的遮罩、白色旋钮的描边。深色下也是黑的:
|
|
61
|
+
* 遮罩压暗的是窗口,从前景推出来的话深色下会变成一层灰雾。
|
|
62
|
+
*/
|
|
63
|
+
--plume-shade: #000;
|
|
64
|
+
/* 毛玻璃窗口的底:盖在系统材质上的半透明一层。浅色往页面色,深色往浮层色(比页面亮),材质透出来的颜色不会压过字。 */
|
|
65
|
+
--plume-window-tint: color-mix(in srgb, var(--plume-shell) 70%, transparent);
|
|
66
|
+
|
|
67
|
+
/* ── 线 ── */
|
|
68
|
+
--plume-line: color-mix(in srgb, var(--plume-fg) calc(7.5% * var(--plume-k) * var(--plume-k-rule)), var(--plume-bg));
|
|
69
|
+
--plume-line-soft: color-mix(in srgb, var(--plume-fg) calc(5% * var(--plume-k) * var(--plume-k-rule)), var(--plume-bg));
|
|
70
|
+
/* 画在浮层上的线:按前景的透明度算,落在什么面上都同样高出一档。 */
|
|
71
|
+
--plume-line-float: color-mix(in srgb, var(--plume-fg) 10%, transparent);
|
|
72
|
+
|
|
73
|
+
/* ── 字 ── */
|
|
74
|
+
--plume-ink: var(--plume-fg);
|
|
75
|
+
/* 次要文字在每一种面上 ≥4.5:1,最浅那档 ≥3:1。 */
|
|
76
|
+
--plume-ink-muted: color-mix(in srgb, var(--plume-fg) 70%, var(--plume-bg));
|
|
77
|
+
--plume-ink-faint: color-mix(in srgb, var(--plume-fg) var(--plume-k-faint), var(--plume-bg));
|
|
78
|
+
|
|
79
|
+
/* ── 状态 ── 浅底用透明度修饰(bg-danger/10),不另设 token。 */
|
|
80
|
+
--plume-ok: #3ecf8e;
|
|
81
|
+
/* 浅色单独一档更深的红:深色那档放到白底上,压在它自己 10% 的浅粉底上只有 3:1。 */
|
|
82
|
+
--plume-danger: #c92a30;
|
|
83
|
+
--plume-warning: #d97706;
|
|
84
|
+
/* 第二种色相:运行中的呼吸灯在 accent 和它之间走,不表示状态。 */
|
|
85
|
+
--plume-violet: #b18cf5;
|
|
86
|
+
/* 压在 accent 实色上的字(未读数这种小圆标),深浅色都是白的。 */
|
|
87
|
+
--plume-on-accent: #fff;
|
|
88
|
+
/* 图表:accent、violet、ok 之后再要几种排在一起分得开的色相(使用统计按模型拆的柱和列表)。不表示状态。 */
|
|
89
|
+
--plume-chart-2: #0d9488;
|
|
90
|
+
--plume-chart-3: #d97706;
|
|
91
|
+
--plume-chart-4: #9333ea;
|
|
92
|
+
--plume-chart-5: #e11d48;
|
|
93
|
+
--plume-chart-6: #65a30d;
|
|
94
|
+
|
|
95
|
+
/* ── 代码 ── 代码画在页面底色上;diff 是两层浅底,字仍是正文色。 */
|
|
96
|
+
--plume-code-bg: var(--plume-bg);
|
|
97
|
+
--plume-code-fg: var(--plume-ink);
|
|
98
|
+
--plume-code-line-height: 1.6;
|
|
99
|
+
--plume-code-tracking: 0em;
|
|
100
|
+
--plume-inline-code-bg: var(--plume-card-hover);
|
|
101
|
+
--plume-inline-code-fg: var(--plume-ink);
|
|
102
|
+
--plume-inline-code-ring: transparent;
|
|
103
|
+
--plume-diff-add: rgb(51 128 63 / 0.12);
|
|
104
|
+
--plume-diff-remove: rgb(200 64 47 / 0.1);
|
|
105
|
+
/*
|
|
106
|
+
* 语法配色:回复里代码块的关键字、字符串这些,只经 var() 用在高亮样式里。按读代码时最常找的东西分档:
|
|
107
|
+
* 被定义的名字(function)、类型(type)、字面量(string、number),注释最淡。变量名和没有规则认领的字是正文色。
|
|
108
|
+
*/
|
|
109
|
+
--plume-syntax-keyword: #2b62c6;
|
|
110
|
+
--plume-syntax-string: #0f7d78;
|
|
111
|
+
--plume-syntax-number: #9a6a00;
|
|
112
|
+
--plume-syntax-comment: #8a8a8a;
|
|
113
|
+
--plume-syntax-function: #8a45a5;
|
|
114
|
+
--plume-syntax-type: #33803f;
|
|
115
|
+
--plume-syntax-variable: var(--plume-ink);
|
|
116
|
+
--plume-syntax-operator: var(--plume-syntax-punctuation);
|
|
117
|
+
--plume-syntax-punctuation: #5f5f5f;
|
|
118
|
+
--plume-syntax-tag: #2b62c6;
|
|
119
|
+
--plume-syntax-attribute: #9a6a00;
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* ── 圆角 ── 其余用 Tailwind 的刻度(lg 8、2xl 16、full……),落在两档中间的往小取。这里是有语义的几档。
|
|
123
|
+
*/
|
|
124
|
+
/* 面板:一整块内容区。 */
|
|
125
|
+
--plume-radius-panel: 12px;
|
|
126
|
+
/* 输入框、按钮共用一个,一排按钮挨着输入框不会像两套控件拼在一起。 */
|
|
127
|
+
--plume-radius-field: 8px;
|
|
128
|
+
/* 菜单里的行。 */
|
|
129
|
+
--plume-radius-item: 6px;
|
|
130
|
+
/* 浮起的菜单卡片。行是 item 6px,卡片 10px,中间留 menu-inset 4px。 */
|
|
131
|
+
--plume-radius-menu: 10px;
|
|
132
|
+
|
|
133
|
+
/* ── 尺寸 ── 输入框、下拉的高度。按钮是 32(h-8),一排里控件高度只有这两种。不给皮肤改。 */
|
|
134
|
+
--plume-control: 34px;
|
|
135
|
+
/* 菜单:卡片四边的内衬一样宽,悬停底色离左右边一样近;一行 32。 */
|
|
136
|
+
--plume-menu-inset: 4px;
|
|
137
|
+
--plume-menu-row: 32px;
|
|
138
|
+
/*
|
|
139
|
+
* 主输入框:in 是卡片里所有上下内边距(字、附件条、工具栏底边),x 是左右内边距,
|
|
140
|
+
* out 是卡片到窗格两边和窗口底边的外边距,control 是工具栏上每个按钮的边长。
|
|
141
|
+
*/
|
|
142
|
+
--plume-composer-in: 12px;
|
|
143
|
+
--plume-composer-x: 16px;
|
|
144
|
+
--plume-composer-out: 24px;
|
|
145
|
+
--plume-composer-control: 28px;
|
|
146
|
+
/*
|
|
147
|
+
* 对话那一列的最大宽度:对话、审批卡、输入框共用。定值,窄窗格里铺满、宽了只居中,侧栏和面板开合时
|
|
148
|
+
* 正文只平移、不重新断行。
|
|
149
|
+
*/
|
|
150
|
+
--plume-content: 864px;
|
|
151
|
+
/* 窗格外框:工作区围着窗格的内边距,和卡片里面离窗口边多远(内边距 + 窗格间距 + 1px 描边)。 */
|
|
152
|
+
--plume-frame-pad: 2px;
|
|
153
|
+
--plume-pane-chrome: 5px;
|
|
154
|
+
|
|
155
|
+
/* ── 字体 ── 不打包字体;等宽栈在 monospace 前加中文字体,否则 Windows 上代码里的中文落到宋体。 */
|
|
156
|
+
--plume-font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
157
|
+
--plume-font-mono:
|
|
158
|
+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC",
|
|
159
|
+
"Noto Sans CJK SC", monospace;
|
|
160
|
+
/* 字号都从这两个算:界面一个,代码一个。 */
|
|
161
|
+
--plume-ui-size: 14px;
|
|
162
|
+
--plume-code-size: 12px;
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* ── 动效 ── 时长按「什么在动」分档:quick 是状态变化(悬停、按下),base 是位置和尺寸,slow 是新出现的东西。
|
|
166
|
+
* 曲线按方向:out 减速落定,用于出现;in 是它的镜像,用于离开;soft 用于原地变化。
|
|
167
|
+
*/
|
|
168
|
+
--plume-t-quick: 150ms;
|
|
169
|
+
--plume-t-base: 220ms;
|
|
170
|
+
--plume-t-reveal: 260ms;
|
|
171
|
+
--plume-t-slow: 340ms;
|
|
172
|
+
--plume-e-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
173
|
+
--plume-e-in: cubic-bezier(0.55, 0, 1, 0.45);
|
|
174
|
+
--plume-e-soft: cubic-bezier(0.4, 0, 0.2, 1);
|
|
175
|
+
|
|
176
|
+
/* ── 阴影 ── 按用途分档。rest:贴在页面上的卡片,比如主输入框。 */
|
|
177
|
+
--plume-shadow-rest: 0 20px 25px -5px rgb(0 0 0 / 0.05), 0 8px 10px -6px rgb(0 0 0 / 0.05);
|
|
178
|
+
/* 菜单、弹层卡片。 */
|
|
179
|
+
--plume-shadow-menu: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
180
|
+
/* 悬停提示。 */
|
|
181
|
+
--plume-shadow-tip: 0 4px 14px -4px rgb(0 0 0 / 0.3);
|
|
182
|
+
/* 对话框。 */
|
|
183
|
+
--plume-shadow-dialog: 0 18px 60px rgb(0 0 0 / 0.16), 0 2px 8px rgb(0 0 0 / 0.06);
|
|
184
|
+
/* 压在图片上的深色浮条:底下是什么不知道,所以重。 */
|
|
185
|
+
--plume-shadow-overlay: 0 8px 32px rgb(0 0 0 / 0.45);
|
|
186
|
+
/* 开关和分段控件的旋钮。 */
|
|
187
|
+
--plume-shadow-knob: 0 1px 2.5px rgb(0 0 0 / 0.16);
|
|
188
|
+
/* 半透明浮层:顶边一道内高光,像玻璃有厚度。 */
|
|
189
|
+
--plume-shadow-glass: inset 0 1px 0 rgb(255 255 255 / 0.4), 0 6px 20px -6px rgb(0 0 0 / 0.13), 0 1px 5px -2px rgb(0 0 0 / 0.09);
|
|
190
|
+
/* 提示条。浅色下和玻璃一样;深色下见下面。 */
|
|
191
|
+
--plume-shadow-toast: var(--plume-shadow-glass);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@media (prefers-color-scheme: dark) {
|
|
195
|
+
:root {
|
|
196
|
+
--plume-bg: #171717;
|
|
197
|
+
--plume-fg: #d4d4d4;
|
|
198
|
+
|
|
199
|
+
--plume-k-surface: 1;
|
|
200
|
+
--plume-k-rule: 1;
|
|
201
|
+
--plume-k-faint: 56%;
|
|
202
|
+
|
|
203
|
+
--plume-card-hover: color-mix(in srgb, var(--plume-fg) 6.2%, transparent);
|
|
204
|
+
--plume-elevated: color-mix(in srgb, var(--plume-fg) 10%, transparent);
|
|
205
|
+
/* 深色下输入框和浮层也往前景走(变亮),和其他面同一个方向。 */
|
|
206
|
+
--plume-input: color-mix(in srgb, var(--plume-fg) calc(3.5% * var(--plume-k)), var(--plume-bg));
|
|
207
|
+
--plume-float: color-mix(in srgb, var(--plume-fg) calc(10% * var(--plume-k)), var(--plume-bg));
|
|
208
|
+
--plume-window-tint: color-mix(in srgb, var(--plume-float) 60%, transparent);
|
|
209
|
+
|
|
210
|
+
--plume-danger: #f2555a;
|
|
211
|
+
--plume-warning: #fbbf24;
|
|
212
|
+
--plume-chart-2: #2dd4bf;
|
|
213
|
+
--plume-chart-3: #fbbf24;
|
|
214
|
+
--plume-chart-4: #c084fc;
|
|
215
|
+
--plume-chart-5: #fb7185;
|
|
216
|
+
--plume-chart-6: #a3e635;
|
|
217
|
+
|
|
218
|
+
--plume-diff-add: rgb(127 201 138 / 0.14);
|
|
219
|
+
--plume-diff-remove: rgb(240 113 113 / 0.13);
|
|
220
|
+
|
|
221
|
+
--plume-syntax-keyword: #79b8ff;
|
|
222
|
+
--plume-syntax-string: #6fd2c8;
|
|
223
|
+
--plume-syntax-number: #e3c07b;
|
|
224
|
+
--plume-syntax-comment: #6b6b6b;
|
|
225
|
+
--plume-syntax-function: #c39ac9;
|
|
226
|
+
--plume-syntax-type: #7fc98a;
|
|
227
|
+
--plume-syntax-punctuation: #a0a0a0;
|
|
228
|
+
--plume-syntax-tag: #79b8ff;
|
|
229
|
+
--plume-syntax-attribute: #e3c07b;
|
|
230
|
+
|
|
231
|
+
/* 深底上同样的投影看不见,旋钮像贴在轨道上;玻璃的内高光要压暗,否则是一道亮线。 */
|
|
232
|
+
--plume-shadow-knob: 0 1px 3px rgb(0 0 0 / 0.55);
|
|
233
|
+
--plume-shadow-glass: inset 0 1px 0 rgb(255 255 255 / 0.07), 0 8px 24px -6px rgb(0 0 0 / 0.5), 0 1px 6px -2px rgb(0 0 0 / 0.38);
|
|
234
|
+
/* 深底上一圈大范围的黑晕加顶边高光,提示条像悬在半空;只留一道贴边的影子,靠浮层底和描边分层。 */
|
|
235
|
+
--plume-shadow-toast: 0 1px 2px rgb(0 0 0 / 0.28);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@theme {
|
|
240
|
+
--color-*: initial;
|
|
241
|
+
--text-*: initial;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@theme inline {
|
|
245
|
+
--color-shell: var(--plume-shell);
|
|
246
|
+
--color-root: var(--plume-root);
|
|
247
|
+
--color-accent-dim: var(--plume-accent-dim);
|
|
248
|
+
--color-sidebar: var(--plume-sidebar);
|
|
249
|
+
--color-card: var(--plume-card);
|
|
250
|
+
--color-card-hover: var(--plume-card-hover);
|
|
251
|
+
--color-elevated: var(--plume-elevated);
|
|
252
|
+
--color-input: var(--plume-input);
|
|
253
|
+
--color-float: var(--plume-float);
|
|
254
|
+
--color-knob: var(--plume-knob);
|
|
255
|
+
--color-shade: var(--plume-shade);
|
|
256
|
+
--color-window-tint: var(--plume-window-tint);
|
|
257
|
+
--color-line: var(--plume-line);
|
|
258
|
+
--color-line-soft: var(--plume-line-soft);
|
|
259
|
+
--color-line-float: var(--plume-line-float);
|
|
260
|
+
--color-ink: var(--plume-ink);
|
|
261
|
+
--color-ink-muted: var(--plume-ink-muted);
|
|
262
|
+
--color-ink-faint: var(--plume-ink-faint);
|
|
263
|
+
--color-accent: var(--plume-accent);
|
|
264
|
+
--color-ok: var(--plume-ok);
|
|
265
|
+
--color-danger: var(--plume-danger);
|
|
266
|
+
--color-warning: var(--plume-warning);
|
|
267
|
+
--color-violet: var(--plume-violet);
|
|
268
|
+
--color-chart-2: var(--plume-chart-2);
|
|
269
|
+
--color-chart-3: var(--plume-chart-3);
|
|
270
|
+
--color-chart-4: var(--plume-chart-4);
|
|
271
|
+
--color-chart-5: var(--plume-chart-5);
|
|
272
|
+
--color-chart-6: var(--plume-chart-6);
|
|
273
|
+
--color-on-accent: var(--plume-on-accent);
|
|
274
|
+
--color-code-bg: var(--plume-code-bg);
|
|
275
|
+
--color-code-fg: var(--plume-code-fg);
|
|
276
|
+
--color-diff-add: var(--plume-diff-add);
|
|
277
|
+
--color-diff-remove: var(--plume-diff-remove);
|
|
278
|
+
|
|
279
|
+
--radius-panel: var(--plume-radius-panel);
|
|
280
|
+
--radius-field: var(--plume-radius-field);
|
|
281
|
+
--radius-item: var(--plume-radius-item);
|
|
282
|
+
--radius-menu: var(--plume-radius-menu);
|
|
283
|
+
|
|
284
|
+
--spacing-control: var(--plume-control);
|
|
285
|
+
|
|
286
|
+
--font-sans: var(--plume-font-sans);
|
|
287
|
+
--font-mono: var(--plume-font-mono);
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
* 字号七档加代码一档,都是界面字号的 calc,改一个数整套一起动。档与档至少差 1px,各自带行高和字距:
|
|
291
|
+
* 字越大字距越紧。字重不放进档里,和字号配对写在用的地方(title 用 medium,heading、display 用 semibold)。
|
|
292
|
+
*/
|
|
293
|
+
--text-caption: calc(var(--plume-ui-size) - 2px);
|
|
294
|
+
--text-caption--line-height: 1.45;
|
|
295
|
+
--text-detail: calc(var(--plume-ui-size) - 1px);
|
|
296
|
+
--text-detail--line-height: 1.5;
|
|
297
|
+
/* 工作字号:行、控件、表格,大部分界面。 */
|
|
298
|
+
--text-label: var(--plume-ui-size);
|
|
299
|
+
--text-label--line-height: 1.5;
|
|
300
|
+
/* 正文:比控件松,句子是顺着读的。 */
|
|
301
|
+
--text-body: calc(var(--plume-ui-size) + 1px);
|
|
302
|
+
--text-body--line-height: 1.7;
|
|
303
|
+
--text-title: calc(var(--plume-ui-size) + 3px);
|
|
304
|
+
--text-title--line-height: 1.4;
|
|
305
|
+
--text-title--letter-spacing: -0.01em;
|
|
306
|
+
--text-heading: calc(var(--plume-ui-size) + 7px);
|
|
307
|
+
--text-heading--line-height: 1.3;
|
|
308
|
+
--text-heading--letter-spacing: -0.015em;
|
|
309
|
+
--text-display: calc(var(--plume-ui-size) + 16px);
|
|
310
|
+
--text-display--line-height: 1.2;
|
|
311
|
+
--text-display--letter-spacing: -0.022em;
|
|
312
|
+
/* 代码另起一档:另一种字体,按列读;行高 1.6 比正文紧,缩进和括号的形状不被拉散。 */
|
|
313
|
+
--text-code: var(--plume-code-size);
|
|
314
|
+
--text-code--line-height: var(--plume-code-line-height);
|
|
315
|
+
--text-code--letter-spacing: var(--plume-code-tracking);
|
|
316
|
+
/* 角标里的数字:图标按钮角上的计数 9px、小圆标里的未读数 10px。只给数字用,不放字。 */
|
|
317
|
+
--text-badge: calc(var(--plume-ui-size) - 5px);
|
|
318
|
+
--text-badge--line-height: 1;
|
|
319
|
+
--text-mark: calc(var(--plume-ui-size) - 4px);
|
|
320
|
+
--text-mark--line-height: 1;
|
|
321
|
+
|
|
322
|
+
--ease-out: var(--plume-e-out);
|
|
323
|
+
--ease-in: var(--plume-e-in);
|
|
324
|
+
--ease-soft: var(--plume-e-soft);
|
|
325
|
+
--default-transition-duration: var(--plume-t-quick);
|
|
326
|
+
--default-transition-timing-function: var(--plume-e-soft);
|
|
327
|
+
|
|
328
|
+
--shadow-rest: var(--plume-shadow-rest);
|
|
329
|
+
--shadow-menu: var(--plume-shadow-menu);
|
|
330
|
+
--shadow-tip: var(--plume-shadow-tip);
|
|
331
|
+
--shadow-dialog: var(--plume-shadow-dialog);
|
|
332
|
+
--shadow-overlay: var(--plume-shadow-overlay);
|
|
333
|
+
--shadow-knob: var(--plume-shadow-knob);
|
|
334
|
+
--shadow-glass: var(--plume-shadow-glass);
|
|
335
|
+
--shadow-toast: var(--plume-shadow-toast);
|
|
336
|
+
}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** @plume/ui 对插件开放的部分:packages/client/ui/plugin-api.json 里的名字。由 scripts/build-types.mjs 生成。 */
|
|
2
|
+
export { Text, Button, IconButton, Input, Textarea, TextArea, Select, InlineSelect, Toggle, ComposerToggle, WorktreeToggle, Segmented, TabStrip, SearchField, NumberField, Slider, ColorField, TimeField, ShortcutRecorder, useFieldFade, ChoiceMark, Popover, ContextMenu, MenuItem, MenuSeparator, MenuLabel, Dialog, DialogAction, Confirm, useConfirmer, useConfirmGate, Tooltip, usePopover, MenuBody, MenuSearch, MENU_MAX_HEIGHT, Overlay, Card, CodeBlock, DiffView, ApprovalFrame, ApprovalExpiry, SettingsSectionTitle, SettingsCard, SettingsRow, SettingsNotice, PanelEmpty, RetainedViews, useNarrow, useLiveRefresh, PageTopRow, ActionSpinner, BreatheLoader, SkeletonList, SkeletonBar, useSlowLoad, HoverRow, HoverRowMark, HoverRowReveal, hoverSlot, Caret, MarkNumber, FlowRow, lookFor, iconColour, Scroller, OverlayScrollbar, ScrollText, Sideways, useI18n, relativeTime, TimeAgo, macKeyboard, composingKey, shortcutLetter, shortcutLabel, acceleratorLabel, motionReduced, CountUp, useRolled, RollingText, useNow, Collapse, Disclosure, AgentAvatar, AvatarPile, assignAvatars, AVATAR_SHAPES, AVATAR_COLORS, COLOR_ART, parseAvatar, formatAvatar, freshAvatar, withHanFallback, useAnnotator, AnnotateCanvas, AnnotateToolbar, useToolbarPlacement, HANDLES, HANDLE_CURSOR, handlePoint, hitHandle, insideRect, rectFromPoints, resizeRect, moveRect, clampRect } from "./client/ui/src/index.d.ts";
|
package/lib/build.mjs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 构建一个插件:src/index.ts 打成逻辑入口 dist/index.mjs;有 src/ui.tsx 的再打出界面入口 dist/ui.mjs。
|
|
3
|
+
* `plume-plugin build` 和仓库的 scripts/build-plugins.mjs 都调它,插件只有这一种构建方式。
|
|
4
|
+
*
|
|
5
|
+
* - 逻辑入口:Node 平台的 ESM,依赖全部打进去(宿主的接口只有类型)。package.json 的 dependencies 例外:
|
|
6
|
+
* 打不进去的(node-pty 这类原生模块)写在那里,不打包,原样复制进 dist/node_modules,运行时按 Node 的解析找到。
|
|
7
|
+
* 一并复制实际安装的运行依赖闭包;按平台分的预编译(`os`/`cpu` 分包、prebuilds/<平台>-<架构>)带上 targets.mjs 里
|
|
8
|
+
* 那几个平台、架构装了的每一份:dist/ 会进 Plume 的多架构安装包,打包时再按目标裁(见 targets.mjs)。
|
|
9
|
+
* - 界面入口:浏览器 ESM;react、react/jsx-runtime、@plume/ui、@plume/styles 留作外部,运行时经宿主的 import map 用产品的实例。
|
|
10
|
+
* 只认这几个模块名本身:@plume/ui/icons 不在 import map 里,指到 SDK 自带的图标库打进插件(只打用到的那几个图标)。
|
|
11
|
+
* 引入的 .css 是一段文字,插件自己挂到页面上(宿主不加载插件的样式表)。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { cp, readFile, realpath, rm } from "node:fs/promises";
|
|
16
|
+
import { createRequire } from "node:module";
|
|
17
|
+
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
18
|
+
import { build } from "esbuild";
|
|
19
|
+
import { forTarget, TARGETS } from "./targets.mjs";
|
|
20
|
+
|
|
21
|
+
const UI_SHARED = ["react", "react/jsx-runtime", "@plume/ui", "@plume/styles"];
|
|
22
|
+
const ICONS = join(import.meta.dirname, "icons.mjs");
|
|
23
|
+
|
|
24
|
+
/** esbuild 的 external 写包名会连子路径一起算外部,这里按整个模块名匹配。 */
|
|
25
|
+
const shared = {
|
|
26
|
+
name: "plume-shared",
|
|
27
|
+
setup(build) {
|
|
28
|
+
const filter = new RegExp(`^(?:${UI_SHARED.map((name) => name.replace(/[/.]/g, "\\$&")).join("|")})$`);
|
|
29
|
+
build.onResolve({ filter }, (args) => ({ path: args.path, external: true }));
|
|
30
|
+
build.onResolve({ filter: /^@plume\/ui\/icons$/ }, () => ({ path: ICONS }));
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const HOST = `${process.platform}-${process.arch}`;
|
|
34
|
+
|
|
35
|
+
/** 复制实际安装的运行依赖,顶层同名冲突时放到依赖它的包下面。 */
|
|
36
|
+
async function copyDependencies(dir, names) {
|
|
37
|
+
const target = join(dir, "dist/node_modules");
|
|
38
|
+
await rm(target, { recursive: true, force: true });
|
|
39
|
+
const placed = new Map();
|
|
40
|
+
const copied = new Set();
|
|
41
|
+
|
|
42
|
+
async function locate(from, name, required) {
|
|
43
|
+
const require = createRequire(join(from, "package.json"));
|
|
44
|
+
for (const modules of require.resolve.paths(name) ?? []) {
|
|
45
|
+
let file;
|
|
46
|
+
try {
|
|
47
|
+
// 不经 exports,且从实路径解析下一级,保留 pnpm 安装时的版本和 peer 上下文。
|
|
48
|
+
file = await realpath(join(modules, name, "package.json"));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error.code === "ENOENT") continue;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
const manifest = JSON.parse(await readFile(file, "utf8"));
|
|
54
|
+
// 必需的依赖要能在构建机上跑;可选的(按平台分的预编译包)只要合 TARGETS 里的一个就带上。
|
|
55
|
+
if (required ? !forTarget(manifest, HOST) : !TARGETS.some((target) => forTarget(manifest, target))) {
|
|
56
|
+
if (!required) return null;
|
|
57
|
+
throw new Error(`运行依赖 ${name} 不支持 ${HOST}(${from})`);
|
|
58
|
+
}
|
|
59
|
+
return { source: dirname(file), manifest };
|
|
60
|
+
}
|
|
61
|
+
if (!required) return null;
|
|
62
|
+
throw new Error(`找不到运行依赖 ${name}(${from})`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function copyPackage(pkg, destination) {
|
|
66
|
+
if (copied.has(destination)) return;
|
|
67
|
+
copied.add(destination);
|
|
68
|
+
const prebuilds = join(pkg.source, "prebuilds") + sep;
|
|
69
|
+
await cp(pkg.source, destination, {
|
|
70
|
+
recursive: true,
|
|
71
|
+
dereference: true,
|
|
72
|
+
filter: (path) => basename(path) !== "node_modules" && (!path.startsWith(prebuilds) || TARGETS.includes(path.slice(prebuilds.length).split(sep)[0])),
|
|
73
|
+
});
|
|
74
|
+
const dependencies = {
|
|
75
|
+
...Object.fromEntries(Object.keys(pkg.manifest.peerDependencies ?? {}).map((name) => [name, false])),
|
|
76
|
+
...Object.fromEntries(Object.keys(pkg.manifest.dependencies ?? {}).map((name) => [name, true])),
|
|
77
|
+
...Object.fromEntries(Object.keys(pkg.manifest.optionalDependencies ?? {}).map((name) => [name, false])),
|
|
78
|
+
};
|
|
79
|
+
for (const [name, required] of Object.entries(dependencies)) {
|
|
80
|
+
const dependency = await locate(pkg.source, name, required);
|
|
81
|
+
if (!dependency) continue;
|
|
82
|
+
const require = createRequire(join(destination, "package.json"));
|
|
83
|
+
const visible = require.resolve
|
|
84
|
+
.paths(name)
|
|
85
|
+
.map((modules) => join(modules, name))
|
|
86
|
+
.find((path) => placed.has(path));
|
|
87
|
+
// 只复用 Node 当前能找到且源实路径一致的包,不能只看包名或版本号。
|
|
88
|
+
let next = visible;
|
|
89
|
+
if (!visible || placed.get(visible) !== dependency.source) {
|
|
90
|
+
next = placed.has(join(target, name)) ? join(destination, "node_modules", name) : join(target, name);
|
|
91
|
+
placed.set(next, dependency.source);
|
|
92
|
+
}
|
|
93
|
+
await copyPackage(dependency, next);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 先预留直接依赖的位置,免得先遍历的传递依赖抢占插件入口要用的版本。
|
|
98
|
+
const roots = [];
|
|
99
|
+
for (const name of names) {
|
|
100
|
+
const pkg = await locate(dir, name, true);
|
|
101
|
+
const destination = join(target, name);
|
|
102
|
+
placed.set(destination, pkg.source);
|
|
103
|
+
roots.push({ pkg, destination });
|
|
104
|
+
}
|
|
105
|
+
for (const { pkg, destination } of roots) await copyPackage(pkg, destination);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 构建 target 这个插件。成功返回打出来的文件说明(给命令行打印),失败抛错;esbuild 的报错它自己已经打过了。
|
|
110
|
+
* @param {string} target 插件目录(有 package.json 和 src/index.ts)
|
|
111
|
+
* @returns {Promise<string>}
|
|
112
|
+
*/
|
|
113
|
+
export async function buildPlugin(target) {
|
|
114
|
+
const dir = resolve(target);
|
|
115
|
+
const logic = join(dir, "src/index.ts");
|
|
116
|
+
const ui = join(dir, "src/ui.tsx");
|
|
117
|
+
if (!existsSync(logic)) throw new Error("找不到 src/index.ts");
|
|
118
|
+
const manifest = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
|
|
119
|
+
const native = Object.keys(manifest.dependencies ?? {});
|
|
120
|
+
const common = { bundle: true, format: "esm", sourcemap: "inline", logLevel: "warning", absWorkingDir: dir };
|
|
121
|
+
|
|
122
|
+
// 打进来的 CommonJS 依赖(MCP SDK 用的 cross-spawn 这类)会 `require("child_process")`;ESM 里没有 `require`,
|
|
123
|
+
// esbuild 的垫片找不到它就在加载时抛错,所以在文件头上给一个。
|
|
124
|
+
const banner = { js: 'import { createRequire as __plumeCreateRequire } from "node:module";\nconst require = __plumeCreateRequire(import.meta.url);' };
|
|
125
|
+
await build({ ...common, entryPoints: [logic], outfile: join(dir, "dist/index.mjs"), platform: "node", target: "node24", external: native, banner });
|
|
126
|
+
await copyDependencies(dir, native);
|
|
127
|
+
const outputs = [`dist/index.mjs${native.length > 0 ? `(带上 ${native.join("、")})` : ""}`];
|
|
128
|
+
if (existsSync(ui)) {
|
|
129
|
+
await build({
|
|
130
|
+
...common,
|
|
131
|
+
entryPoints: [ui],
|
|
132
|
+
outfile: join(dir, "dist/ui.mjs"),
|
|
133
|
+
platform: "browser",
|
|
134
|
+
target: "chrome156",
|
|
135
|
+
jsx: "automatic",
|
|
136
|
+
plugins: [shared],
|
|
137
|
+
loader: { ".css": "text" },
|
|
138
|
+
define: { "process.env.NODE_ENV": '"production"' },
|
|
139
|
+
});
|
|
140
|
+
outputs.push("dist/ui.mjs");
|
|
141
|
+
}
|
|
142
|
+
return outputs.join("、");
|
|
143
|
+
}
|