@clipbus/plugin-sdk 0.8.1 → 0.8.3

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/API.md CHANGED
@@ -9,8 +9,8 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
9
9
 
10
10
  ## 1. Overview
11
11
 
12
- - **Capabilities**: 28
13
- - **Host events**: 9
12
+ - **Capabilities**: 29
13
+ - **Host events**: 10
14
14
  - **Node IPC methods**: 6
15
15
  - **Named types**: 28
16
16
 
@@ -182,6 +182,16 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
182
182
  - **Payload**: { attachmentType: `string`, attachmentKey: `string` }
183
183
  - **Response**: { payloadJson?: `string` }
184
184
 
185
+ ### locale
186
+
187
+ #### `locale.get`
188
+
189
+ - **Side**: runtime
190
+ - **Context**: any
191
+ - **Path**: `locale.get`
192
+ - **Payload**: { }
193
+ - **Response**: { locale: `string` }
194
+
185
195
  ### navigation
186
196
 
187
197
  #### `navigation.openUrl`
@@ -296,6 +306,7 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
296
306
  | `settings.getAll` | `clipbus.settings.getAll` | `host.settings.getAll` | any |
297
307
  | `console.log` | `clipbus.console.log` | `host.console.log` | any |
298
308
  | `textInput.stateChanged` | `clipbus.textInput.stateChanged` | — | any |
309
+ | `locale.get` | — | `host.locale.get` | any |
299
310
 
300
311
  ## 4. Host Events
301
312
 
@@ -367,6 +378,14 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
367
378
  - **Context**: any
368
379
  - **Payload**: { panelID: `string` }
369
380
 
381
+ ### `clipbus-plugin-locale`
382
+
383
+ - **Window global**: `__CLIPBUS_PLUGIN_LOCALE__`
384
+ - **Topic**: `locale`
385
+ - **Shape**: topic
386
+ - **Context**: any
387
+ - **Payload**: { locale: `string` }
388
+
370
389
  ## 5. Host Event Matrix
371
390
 
372
391
  | Event | Topic | Shape | Window global | Context |
@@ -380,6 +399,7 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
380
399
  | `clipbus-plugin-action-host-invoke` | action.onHostInvoke | stream | — | action |
381
400
  | `clipbus-plugin-info-panel-on-action` | infoPanel.onAction | stream | — | any |
382
401
  | `clipbus-plugin-info-panel-on-close` | infoPanel.onClose | stream | — | any |
402
+ | `clipbus-plugin-locale` | locale | topic | `__CLIPBUS_PLUGIN_LOCALE__` | any |
383
403
 
384
404
  ## 6. Node IPC
385
405
 
@@ -626,6 +646,7 @@ Discriminated union on `kind`: { kind: `'text'`, text: `string` } | { kind: `'im
626
646
  | `__CLIPBUS_PLUGIN_ATTACHMENT__` | `clipbus-plugin-attachment` |
627
647
  | `__CLIPBUS_PLUGIN_DRAFT__` | `clipbus-plugin-draft` |
628
648
  | `__CLIPBUS_PLUGIN_THEME__` | `clipbus-plugin-theme` |
649
+ | `__CLIPBUS_PLUGIN_LOCALE__` | `clipbus-plugin-locale` |
629
650
 
630
651
  ## 11. Generated Symbol Map
631
652
 
package/README.md CHANGED
@@ -161,6 +161,12 @@ These verbs are available on the `ctx.host` object passed to every runtime handl
161
161
  | `settings.get({key})` | `Promise<{value: string \| null}>` | Read a single plugin setting |
162
162
  | `settings.getAll()` | `Promise<{settings: Record<string, string>}>` | Read all plugin settings |
163
163
 
164
+ #### `ctx.host.locale`
165
+
166
+ | Method | Returns | Description |
167
+ |---|---|---|
168
+ | `locale.get()` | `Promise<{locale: string}>` | Read the host's current interface locale. Values: `"en"`, `"ja"`, `"zh-Hans"`. Wrap in try/catch when targeting older hosts that may not support this capability. |
169
+
164
170
  ---
165
171
 
166
172
  ## DOM utilities (`@clipbus/plugin-sdk/dom`)
@@ -232,6 +238,19 @@ There is **no** `clipbus.theme.refresh()` or `clipbus.theme.getThemeSnapshot()`
232
238
 
233
239
  ---
234
240
 
241
+ ### `clipbus.locale` — Topic\<PluginLocalePayload\>
242
+
243
+ | Member | Shape | Description |
244
+ |---|---|---|
245
+ | `clipbus.locale.current()` | `() → PluginLocalePayload \| undefined` | Read current locale. The host injects `__CLIPBUS_PLUGIN_LOCALE__` at WebView startup, so this is synchronously available in practice. |
246
+ | `clipbus.locale.on(fn)` | `(fn) → Unsubscribe` | Subscribe to the `clipbus-plugin-locale` host event. The host locale is fixed per app session (changing it requires a restart), so this rarely fires after the initial value — it exists for parity with other topics. |
247
+
248
+ Locale values: `"en"`, `"ja"`, `"zh-Hans"` (the host's current interface language).
249
+
250
+ `current()` may return `undefined` when the host has not yet injected the value. Defend with a fallback at the call site: `clipbus.locale.current()?.locale ?? 'en'`.
251
+
252
+ ---
253
+
235
254
  ### `clipbus.asset` — local image URLs for `<img>` (any context)
236
255
 
237
256
  Returns opaque `clipbus-asset://` URLs so a WebView can render local images in `<img>` without ever seeing a real file path (the WebView sandbox blocks `file://`). The host resolves the token internally; tokens are session-scoped and invalidated when the owner is released.
package/SPECIFICATION.md CHANGED
@@ -176,6 +176,7 @@ Capabilities are split by catalog `surface.side`: runtime capabilities are expos
176
176
  | Open file | `navigation.openFilePath` | `ctx.host.navigation.openFilePath({path})` | `clipbus.navigation.openFilePath({path})` | Verb; strict wire shape |
177
177
  | Settings get | `settings.get` | `ctx.host.settings.get({key})` | `clipbus.settings.get({key})` | Verb; strict wire shape |
178
178
  | Settings get all | `settings.getAll` | `ctx.host.settings.getAll()` | `clipbus.settings.getAll()` | Verb |
179
+ | Locale get | `locale.get` | `ctx.host.locale.get()` | — | Verb; returns `{ locale: string }`, values: `"en" \| "ja" \| "zh-Hans"`; runtime-only |
179
180
 
180
181
  ### 2.1 `side:'both'` symmetry
181
182
 
@@ -219,6 +220,7 @@ Host events declared in the catalog drive every state Topic / Stream the SDK exp
219
220
  | `clipbus-plugin-attachment` | `clipbus.item.attachment` | `__CLIPBUS_PLUGIN_ATTACHMENT__` | topic | attachmentRenderer | `PluginAttachmentPayload` |
220
221
  | `clipbus-plugin-draft` | `clipbus.action.draft` | `__CLIPBUS_PLUGIN_DRAFT__` | topic | action | `Record<string, unknown>` |
221
222
  | `clipbus-plugin-theme` | `clipbus.theme` | `__CLIPBUS_PLUGIN_THEME__` | topic | any | `PluginThemeTokenSnapshot` |
223
+ | `clipbus-plugin-locale` | `clipbus.locale` | `__CLIPBUS_PLUGIN_LOCALE__` | topic | any | `PluginLocalePayload` |
222
224
  | `clipbus-plugin-attachment-host-invoke` | `clipbus.attachmentRenderer.onHostInvoke` | — | stream | attachmentRenderer | `{ buttonID: string }` |
223
225
  | `clipbus-plugin-action-host-invoke` | `clipbus.action.onHostInvoke` | — | stream | action | `{ buttonID: string }` |
224
226
 
@@ -167,7 +167,12 @@ export interface PluginTextInputStateChangedPayload {
167
167
  }
168
168
  export interface PluginTextInputStateChangedResponse {
169
169
  }
170
- export declare const CAPABILITY_METHOD_NAMES: readonly ["runtime.invoke", "item.setTags", "item.addTags", "item.removeTags", "item.setPinned", "item.setAttachments", "item.setSearchExtension", "item.materializeImagePath", "item.readAttachment", "asset.currentItemImageUrl", "asset.pathReferenceImageUrl", "asset.registerImage", "clipboard.copyText", "navigation.openUrl", "navigation.revealInFinder", "navigation.openFilePath", "action.allocateImageTempPath", "action.setButtons", "action.complete", "attachmentRenderer.setButtons", "window.setHeight", "window.autoFit", "infoPanel.open", "infoPanel.close", "settings.get", "settings.getAll", "console.log", "textInput.stateChanged"];
170
+ export interface PluginLocaleGetPayload {
171
+ }
172
+ export interface PluginLocaleGetResponse {
173
+ locale: string;
174
+ }
175
+ export declare const CAPABILITY_METHOD_NAMES: readonly ["runtime.invoke", "item.setTags", "item.addTags", "item.removeTags", "item.setPinned", "item.setAttachments", "item.setSearchExtension", "item.materializeImagePath", "item.readAttachment", "asset.currentItemImageUrl", "asset.pathReferenceImageUrl", "asset.registerImage", "clipboard.copyText", "navigation.openUrl", "navigation.revealInFinder", "navigation.openFilePath", "action.allocateImageTempPath", "action.setButtons", "action.complete", "attachmentRenderer.setButtons", "window.setHeight", "window.autoFit", "infoPanel.open", "infoPanel.close", "settings.get", "settings.getAll", "console.log", "textInput.stateChanged", "locale.get"];
171
176
  export type CapabilityMethodName = (typeof CAPABILITY_METHOD_NAMES)[number];
172
177
  export declare const callRuntimeInvoke: (payload: PluginRuntimeInvokePayload) => Promise<PluginRuntimeInvokeResponse>;
173
178
  export declare const callItemSetTags: (payload: PluginItemSetTagsPayload) => Promise<PluginItemSetTagsResponse>;
@@ -197,3 +202,4 @@ export declare const callSettingsGet: (payload: PluginSettingsGetPayload) => Pro
197
202
  export declare const callSettingsGetAll: () => Promise<PluginSettingsGetAllResponse>;
198
203
  export declare const callConsoleLog: (payload: PluginConsoleLogPayload) => Promise<PluginConsoleLogResponse>;
199
204
  export declare const callTextInputStateChanged: (payload: PluginTextInputStateChangedPayload) => Promise<PluginTextInputStateChangedResponse>;
205
+ export declare const callLocaleGet: () => Promise<PluginLocaleGetResponse>;
@@ -1,4 +1,4 @@
1
- import type { PluginActionAllocateImageTempPathPayload, PluginActionAllocateImageTempPathResponse, PluginAssetRegisterImagePayload, PluginAssetRegisterImageResponse, PluginClipboardCopyTextPayload, PluginClipboardCopyTextResponse, PluginConsoleLogPayload, PluginConsoleLogResponse, PluginItemAddTagsPayload, PluginItemAddTagsResponse, PluginItemMaterializeImagePathResponse, PluginItemReadAttachmentPayload, PluginItemReadAttachmentResponse, PluginItemRemoveTagsPayload, PluginItemRemoveTagsResponse, PluginItemSetAttachmentsPayload, PluginItemSetAttachmentsResponse, PluginItemSetPinnedPayload, PluginItemSetPinnedResponse, PluginItemSetSearchExtensionPayload, PluginItemSetSearchExtensionResponse, PluginItemSetTagsPayload, PluginItemSetTagsResponse, PluginNavigationOpenFilePathPayload, PluginNavigationOpenFilePathResponse, PluginNavigationOpenUrlPayload, PluginNavigationOpenUrlResponse, PluginNavigationRevealInFinderPayload, PluginNavigationRevealInFinderResponse, PluginSettingsGetAllResponse, PluginSettingsGetPayload, PluginSettingsGetResponse } from './capabilityClients.generated.js';
1
+ import type { PluginActionAllocateImageTempPathPayload, PluginActionAllocateImageTempPathResponse, PluginAssetRegisterImagePayload, PluginAssetRegisterImageResponse, PluginClipboardCopyTextPayload, PluginClipboardCopyTextResponse, PluginConsoleLogPayload, PluginConsoleLogResponse, PluginItemAddTagsPayload, PluginItemAddTagsResponse, PluginItemMaterializeImagePathResponse, PluginItemReadAttachmentPayload, PluginItemReadAttachmentResponse, PluginItemRemoveTagsPayload, PluginItemRemoveTagsResponse, PluginItemSetAttachmentsPayload, PluginItemSetAttachmentsResponse, PluginItemSetPinnedPayload, PluginItemSetPinnedResponse, PluginItemSetSearchExtensionPayload, PluginItemSetSearchExtensionResponse, PluginItemSetTagsPayload, PluginItemSetTagsResponse, PluginLocaleGetResponse, PluginNavigationOpenFilePathPayload, PluginNavigationOpenFilePathResponse, PluginNavigationOpenUrlPayload, PluginNavigationOpenUrlResponse, PluginNavigationRevealInFinderPayload, PluginNavigationRevealInFinderResponse, PluginSettingsGetAllResponse, PluginSettingsGetPayload, PluginSettingsGetResponse } from './capabilityClients.generated.js';
2
2
  export interface IPCBus {
3
3
  request<Req, Resp>(method: string, payload: Req): Promise<Resp>;
4
4
  }
@@ -25,6 +25,9 @@ export interface HostClient {
25
25
  materializeImagePath(): Promise<PluginItemMaterializeImagePathResponse>;
26
26
  readAttachment(payload: PluginItemReadAttachmentPayload): Promise<PluginItemReadAttachmentResponse>;
27
27
  };
28
+ locale: {
29
+ get(): Promise<PluginLocaleGetResponse>;
30
+ };
28
31
  navigation: {
29
32
  openUrl(payload: PluginNavigationOpenUrlPayload): Promise<PluginNavigationOpenUrlResponse>;
30
33
  revealInFinder(payload: PluginNavigationRevealInFinderPayload): Promise<PluginNavigationRevealInFinderResponse>;
@@ -1,4 +1,4 @@
1
- import type { PluginActionAllocateImageTempPathPayload, PluginActionAllocateImageTempPathResponse, PluginAssetRegisterImagePayload, PluginAssetRegisterImageResponse, PluginClipboardCopyTextPayload, PluginClipboardCopyTextResponse, PluginConsoleLogPayload, PluginConsoleLogResponse, PluginItemAddTagsPayload, PluginItemAddTagsResponse, PluginItemMaterializeImagePathResponse, PluginItemReadAttachmentPayload, PluginItemReadAttachmentResponse, PluginItemRemoveTagsPayload, PluginItemRemoveTagsResponse, PluginItemSetAttachmentsPayload, PluginItemSetAttachmentsResponse, PluginItemSetPinnedPayload, PluginItemSetPinnedResponse, PluginItemSetSearchExtensionPayload, PluginItemSetSearchExtensionResponse, PluginItemSetTagsPayload, PluginItemSetTagsResponse, PluginNavigationOpenFilePathPayload, PluginNavigationOpenFilePathResponse, PluginNavigationOpenUrlPayload, PluginNavigationOpenUrlResponse, PluginNavigationRevealInFinderPayload, PluginNavigationRevealInFinderResponse, PluginSettingsGetAllResponse, PluginSettingsGetPayload, PluginSettingsGetResponse } from './capabilityClients.generated.js';
1
+ import type { PluginActionAllocateImageTempPathPayload, PluginActionAllocateImageTempPathResponse, PluginAssetRegisterImagePayload, PluginAssetRegisterImageResponse, PluginClipboardCopyTextPayload, PluginClipboardCopyTextResponse, PluginConsoleLogPayload, PluginConsoleLogResponse, PluginItemAddTagsPayload, PluginItemAddTagsResponse, PluginItemMaterializeImagePathResponse, PluginItemReadAttachmentPayload, PluginItemReadAttachmentResponse, PluginItemRemoveTagsPayload, PluginItemRemoveTagsResponse, PluginItemSetAttachmentsPayload, PluginItemSetAttachmentsResponse, PluginItemSetPinnedPayload, PluginItemSetPinnedResponse, PluginItemSetSearchExtensionPayload, PluginItemSetSearchExtensionResponse, PluginItemSetTagsPayload, PluginItemSetTagsResponse, PluginLocaleGetResponse, PluginNavigationOpenFilePathPayload, PluginNavigationOpenFilePathResponse, PluginNavigationOpenUrlPayload, PluginNavigationOpenUrlResponse, PluginNavigationRevealInFinderPayload, PluginNavigationRevealInFinderResponse, PluginSettingsGetAllResponse, PluginSettingsGetPayload, PluginSettingsGetResponse } from './capabilityClients.generated.js';
2
2
  export declare const host: {
3
3
  item: {
4
4
  setTags: (payload: PluginItemSetTagsPayload) => Promise<PluginItemSetTagsResponse>;
@@ -31,4 +31,7 @@ export declare const host: {
31
31
  console: {
32
32
  log: (payload: PluginConsoleLogPayload) => Promise<PluginConsoleLogResponse>;
33
33
  };
34
+ locale: {
35
+ get: () => Promise<PluginLocaleGetResponse>;
36
+ };
34
37
  };
@@ -30,3 +30,8 @@ export interface PluginInfoPanelOnClosePayload {
30
30
  panelID: string;
31
31
  }
32
32
  export declare function onInfoPanelOnClose(listener: (payload: PluginInfoPanelOnClosePayload) => void): () => void;
33
+ export interface PluginLocalePayload {
34
+ locale: string;
35
+ }
36
+ export declare function onLocale(listener: (payload: PluginLocalePayload) => void): () => void;
37
+ export declare function getLocaleSnapshot(): PluginLocalePayload | undefined;
@@ -1,5 +1,5 @@
1
1
  import type { PluginAttachmentPayload, PluginClipboardItem, PluginThemeTokenSnapshot } from './data.generated.js';
2
- import type { PluginActionHostInvokePayload, PluginAttachmentHostInvokePayload, PluginContextPayload, PluginInfoPanelOnActionPayload, PluginInfoPanelOnClosePayload } from './topicSubscribers.generated.js';
2
+ import type { PluginActionHostInvokePayload, PluginAttachmentHostInvokePayload, PluginContextPayload, PluginInfoPanelOnActionPayload, PluginInfoPanelOnClosePayload, PluginLocalePayload } from './topicSubscribers.generated.js';
3
3
  export declare const _pluginContextTopic: import("../internal/topic.js").MutableTopic<PluginContextPayload>;
4
4
  export declare const _itemTopic: import("../internal/topic.js").MutableTopic<PluginClipboardItem>;
5
5
  export declare const _itemAttachmentTopic: import("../internal/topic.js").MutableTopic<PluginAttachmentPayload>;
@@ -9,6 +9,7 @@ export declare const _attachmentRendererOnHostInvokeStream: import("../internal/
9
9
  export declare const _actionOnHostInvokeStream: import("../internal/topic.js").MutableStream<PluginActionHostInvokePayload>;
10
10
  export declare const _infoPanelOnActionStream: import("../internal/topic.js").MutableStream<PluginInfoPanelOnActionPayload>;
11
11
  export declare const _infoPanelOnCloseStream: import("../internal/topic.js").MutableStream<PluginInfoPanelOnClosePayload>;
12
+ export declare const _localeTopic: import("../internal/topic.js").MutableTopic<PluginLocalePayload>;
12
13
  export declare class PluginContextError extends Error {
13
14
  constructor(message: string);
14
15
  }
@@ -1,6 +1,6 @@
1
1
  import type { PluginActionCompletePayload, PluginActionCompleteResponse, PluginActionSetButtonsPayload, PluginActionSetButtonsResponse, PluginAssetCurrentItemImageUrlResponse, PluginAssetPathReferenceImageUrlPayload, PluginAssetPathReferenceImageUrlResponse, PluginAttachmentRendererSetButtonsPayload, PluginAttachmentRendererSetButtonsResponse, PluginClipboardCopyTextPayload, PluginClipboardCopyTextResponse, PluginConsoleLogPayload, PluginConsoleLogResponse, PluginInfoPanelClosePayload, PluginInfoPanelCloseResponse, PluginInfoPanelOpenPayload, PluginInfoPanelOpenResponse, PluginItemReadAttachmentPayload, PluginItemReadAttachmentResponse, PluginNavigationOpenFilePathPayload, PluginNavigationOpenFilePathResponse, PluginNavigationOpenUrlPayload, PluginNavigationOpenUrlResponse, PluginNavigationRevealInFinderPayload, PluginNavigationRevealInFinderResponse, PluginRuntimeInvokePayload, PluginSettingsGetAllResponse, PluginSettingsGetPayload, PluginSettingsGetResponse, PluginTextInputStateChangedPayload, PluginTextInputStateChangedResponse, PluginWindowAutoFitResponse, PluginWindowSetHeightPayload, PluginWindowSetHeightResponse } from './capabilityClients.generated.js';
2
2
  import type { PluginAttachmentPayload, PluginClipboardItem, PluginThemeTokenSnapshot } from './data.generated.js';
3
- import type { PluginActionHostInvokePayload, PluginAttachmentHostInvokePayload, PluginContextPayload, PluginInfoPanelOnActionPayload, PluginInfoPanelOnClosePayload } from './topicSubscribers.generated.js';
3
+ import type { PluginActionHostInvokePayload, PluginAttachmentHostInvokePayload, PluginContextPayload, PluginInfoPanelOnActionPayload, PluginInfoPanelOnClosePayload, PluginLocalePayload } from './topicSubscribers.generated.js';
4
4
  export declare const clipbus: {
5
5
  capabilities: import("../internal/capabilities.js").CapabilitiesApi;
6
6
  runtime: {
@@ -76,4 +76,8 @@ export declare const clipbus: {
76
76
  current: () => PluginThemeTokenSnapshot | undefined;
77
77
  on: (fn: (payload: PluginThemeTokenSnapshot) => void) => import("../internal/topic.js").Unsubscribe;
78
78
  };
79
+ locale: {
80
+ current: () => PluginLocalePayload | undefined;
81
+ on: (fn: (payload: PluginLocalePayload) => void) => import("../internal/topic.js").Unsubscribe;
82
+ };
79
83
  };
@@ -87,6 +87,9 @@ var host = {
87
87
  },
88
88
  console: {
89
89
  log: (payload) => ipcBus.request("console.log", payload)
90
+ },
91
+ locale: {
92
+ get: () => ipcBus.request("locale.get", {})
90
93
  }
91
94
  };
92
95
 
@@ -57,6 +57,9 @@ var host = {
57
57
  },
58
58
  console: {
59
59
  log: (payload) => ipcBus.request("console.log", payload)
60
+ },
61
+ locale: {
62
+ get: () => ipcBus.request("locale.get", {})
60
63
  }
61
64
  };
62
65
 
package/dist/ui/index.cjs CHANGED
@@ -237,6 +237,11 @@ function onInfoPanelOnClose(listener) {
237
237
  globalThis.addEventListener("clipbus-plugin-info-panel-on-close", handler);
238
238
  return () => globalThis.removeEventListener("clipbus-plugin-info-panel-on-close", handler);
239
239
  }
240
+ function onLocale(listener) {
241
+ const handler = (e) => listener(e.detail);
242
+ globalThis.addEventListener("clipbus-plugin-locale", handler);
243
+ return () => globalThis.removeEventListener("clipbus-plugin-locale", handler);
244
+ }
240
245
 
241
246
  // src/generated/ui.bootstrap.generated.ts
242
247
  var _pluginContextTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_CONTEXT__"));
@@ -257,6 +262,8 @@ var _infoPanelOnActionStream = createStream();
257
262
  onInfoPanelOnAction((p) => _infoPanelOnActionStream.emit(p));
258
263
  var _infoPanelOnCloseStream = createStream();
259
264
  onInfoPanelOnClose((p) => _infoPanelOnCloseStream.emit(p));
265
+ var _localeTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_LOCALE__"));
266
+ onLocale((p) => _localeTopic.set(p));
260
267
  var PluginContextError = class extends Error {
261
268
  constructor(message) {
262
269
  super(message);
@@ -350,6 +357,10 @@ var clipbus = {
350
357
  theme: {
351
358
  current: () => _themeTopic.current(),
352
359
  on: (fn) => _themeTopic.on(fn)
360
+ },
361
+ locale: {
362
+ current: () => _localeTopic.current(),
363
+ on: (fn) => _localeTopic.on(fn)
353
364
  }
354
365
  };
355
366
 
package/dist/ui/index.js CHANGED
@@ -208,6 +208,11 @@ function onInfoPanelOnClose(listener) {
208
208
  globalThis.addEventListener("clipbus-plugin-info-panel-on-close", handler);
209
209
  return () => globalThis.removeEventListener("clipbus-plugin-info-panel-on-close", handler);
210
210
  }
211
+ function onLocale(listener) {
212
+ const handler = (e) => listener(e.detail);
213
+ globalThis.addEventListener("clipbus-plugin-locale", handler);
214
+ return () => globalThis.removeEventListener("clipbus-plugin-locale", handler);
215
+ }
211
216
 
212
217
  // src/generated/ui.bootstrap.generated.ts
213
218
  var _pluginContextTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_CONTEXT__"));
@@ -228,6 +233,8 @@ var _infoPanelOnActionStream = createStream();
228
233
  onInfoPanelOnAction((p) => _infoPanelOnActionStream.emit(p));
229
234
  var _infoPanelOnCloseStream = createStream();
230
235
  onInfoPanelOnClose((p) => _infoPanelOnCloseStream.emit(p));
236
+ var _localeTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_LOCALE__"));
237
+ onLocale((p) => _localeTopic.set(p));
231
238
  var PluginContextError = class extends Error {
232
239
  constructor(message) {
233
240
  super(message);
@@ -321,6 +328,10 @@ var clipbus = {
321
328
  theme: {
322
329
  current: () => _themeTopic.current(),
323
330
  on: (fn) => _themeTopic.on(fn)
331
+ },
332
+ locale: {
333
+ current: () => _localeTopic.current(),
334
+ on: (fn) => _localeTopic.on(fn)
324
335
  }
325
336
  };
326
337
 
@@ -286,7 +286,11 @@ function validateManifest(manifest, options = {}) {
286
286
  issues.push(issue("missingRuntimeEntry", `Missing runtime entry: ${nodeEntry}`));
287
287
  }
288
288
  const uiRootAbs = import_node_path.default.resolve(rootDir, uiRoot);
289
- if (!(0, import_node_fs.existsSync)(uiRootAbs)) {
289
+ const declaresUISurface = renderers.length > 0 || asRecordArray(raw["actions"]).some((a) => {
290
+ const entry = asString(a["uiEntry"])?.trim();
291
+ return entry !== void 0 && entry.length > 0;
292
+ });
293
+ if (declaresUISurface && !(0, import_node_fs.existsSync)(uiRootAbs)) {
290
294
  issues.push(issue("missingUIRoot", `Missing UI root: ${uiRoot}`));
291
295
  }
292
296
  for (const renderer of renderers) {
@@ -251,7 +251,11 @@ function validateManifest(manifest, options = {}) {
251
251
  issues.push(issue("missingRuntimeEntry", `Missing runtime entry: ${nodeEntry}`));
252
252
  }
253
253
  const uiRootAbs = path.resolve(rootDir, uiRoot);
254
- if (!existsSync(uiRootAbs)) {
254
+ const declaresUISurface = renderers.length > 0 || asRecordArray(raw["actions"]).some((a) => {
255
+ const entry = asString(a["uiEntry"])?.trim();
256
+ return entry !== void 0 && entry.length > 0;
257
+ });
258
+ if (declaresUISurface && !existsSync(uiRootAbs)) {
255
259
  issues.push(issue("missingUIRoot", `Missing UI root: ${uiRoot}`));
256
260
  }
257
261
  for (const renderer of renderers) {
package/docs/manifest.md CHANGED
@@ -47,6 +47,8 @@
47
47
  | `runtime.nodeEntry` | `string` | 是 | Node runtime 入口(编译后 `.cjs`) |
48
48
  | `runtime.uiRoot` | `string` | 是 | UI 根目录;所有 `uiEntry` 相对此目录 |
49
49
 
50
+ > **关于 `uiRoot` 目录存在性**:`uiRoot` 是必填*声明*,但其指向目录(如 `dist/ui`)只在插件声明 UI 面时才需在磁盘存在——即有任意 `attachmentRenderers`,或任意带 `uiEntry` 的 `action`。纯 auto-run-action 插件(无 renderer / detector / action uiEntry)构建后无需产出 `dist/ui`,`clipbus-validate-manifest --runtime` 与宿主加载期都不会因其缺失而失败。
51
+
50
52
  ---
51
53
 
52
54
  ## `permissions`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipbus/plugin-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "type": "module",
5
5
  "description": "Typed SDK for authoring Clipbus plugins — runtime (Node.js) and UI (WebView) helpers generated from the Clipbus plugin wire contract.",
6
6
  "keywords": [