@clipbus/plugin-sdk 0.9.9 → 0.10.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.
Files changed (49) hide show
  1. package/API.md +94 -27
  2. package/CHANGELOG.md +84 -0
  3. package/README.md +11 -3
  4. package/SPECIFICATION.md +3 -2
  5. package/dist/dom/index.cjs +29 -34
  6. package/dist/dom/index.js +29 -34
  7. package/dist/dom/topicAdapter.d.ts +1 -1
  8. package/dist/generated/capabilities.generated.d.ts +355 -0
  9. package/dist/generated/data.generated.d.ts +33 -0
  10. package/dist/generated/hostClients.generated.d.ts +8 -5
  11. package/dist/generated/hostEvents.generated.d.ts +68 -0
  12. package/dist/generated/nodeIPC.generated.d.ts +106 -0
  13. package/dist/generated/{runtime.definePlugin.generated.d.ts → runtime.registry.generated.d.ts} +2 -2
  14. package/dist/generated/ui.clipbus.generated.d.ts +19 -20
  15. package/dist/generated/wireConstants.generated.d.ts +21 -0
  16. package/dist/internal/capabilities.d.ts +1 -1
  17. package/dist/internal/hostEvents.d.ts +15 -0
  18. package/dist/internal/pluginCall.d.ts +11 -0
  19. package/dist/internal/pluginContext.d.ts +6 -0
  20. package/dist/preview/index.cjs +41 -48
  21. package/dist/preview/index.js +41 -48
  22. package/dist/preview/wire.d.ts +2 -2
  23. package/dist/runtime/defineMessage.d.ts +1 -1
  24. package/dist/runtime/definePlugin.d.ts +2 -0
  25. package/dist/runtime/index.cjs +10 -82
  26. package/dist/runtime/index.d.cts +7 -1
  27. package/dist/runtime/index.d.ts +7 -1
  28. package/dist/runtime/index.js +9 -80
  29. package/dist/ui/index.cjs +107 -169
  30. package/dist/ui/index.d.cts +5 -1
  31. package/dist/ui/index.d.ts +5 -1
  32. package/dist/ui/index.js +107 -169
  33. package/dist/validate/index.d.cts +5 -4
  34. package/dist/validate/index.d.ts +5 -4
  35. package/docs/authoring.md +1 -1
  36. package/docs/capability-detection.md +2 -2
  37. package/docs/entry.md +4 -3
  38. package/docs/item-context.md +5 -3
  39. package/docs/permissions.md +1 -1
  40. package/package.json +6 -4
  41. package/dist/generated/INDEX.runtime.generated.d.ts +0 -6
  42. package/dist/generated/INDEX.ui.generated.d.ts +0 -4
  43. package/dist/generated/capabilityClients.generated.d.ts +0 -231
  44. package/dist/generated/hostBootstrap.generated.d.ts +0 -23
  45. package/dist/generated/runtime.host.generated.d.ts +0 -39
  46. package/dist/generated/topicSubscribers.generated.d.ts +0 -39
  47. package/dist/generated/ui.bootstrap.generated.d.ts +0 -17
  48. package/dist/internal/ipcBus.d.ts +0 -48
  49. package/dist/internal/runtimeInvokeClient.d.ts +0 -3
package/API.md CHANGED
@@ -9,10 +9,10 @@ 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**: 33
12
+ - **Capabilities**: 35
13
13
  - **Host events**: 11
14
14
  - **Node IPC methods**: 6
15
- - **Named types**: 31
15
+ - **Named types**: 40
16
16
 
17
17
  ## 2. Capabilities
18
18
 
@@ -92,6 +92,14 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
92
92
  - **Payload**: { index: `int` }
93
93
  - **Response**: { url?: `string` }
94
94
 
95
+ #### `asset.allocateImageTempPath`
96
+
97
+ - **Side**: runtime
98
+ - **Context**: any
99
+ - **Path**: `asset.allocateImageTempPath`
100
+ - **Payload**: { formatHint: `string` }
101
+ - **Response**: { path: `string` }
102
+
95
103
  #### `asset.registerImage`
96
104
 
97
105
  - **Side**: runtime
@@ -130,6 +138,14 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
130
138
  - **Payload**: { level: [`PluginConsoleLogLevel`](#pluginconsoleloglevel), message: `string` }
131
139
  - **Response**: { }
132
140
 
141
+ #### `console.diagnostic`
142
+
143
+ - **Side**: both
144
+ - **Context**: any
145
+ - **Path**: `console.diagnostic`
146
+ - **Payload**: { level: [`PluginConsoleLogLevel`](#pluginconsoleloglevel), event: [`PluginDiagnosticEvent`](#plugindiagnosticevent), reason: [`PluginDiagnosticReason`](#plugindiagnosticreason), count: `int`, durationMs: `int` }
147
+ - **Response**: { }
148
+
133
149
  ### infoPanel
134
150
 
135
151
  #### `infoPanel.open`
@@ -311,26 +327,27 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
311
327
  | Capability | UI path | Runtime path | Context |
312
328
  | --- | --- | --- | --- |
313
329
  | `runtime.invoke` | `clipbus.runtime.invoke` | — | any |
314
- | `item.setTags` | — | `host.item.setTags` | any |
315
- | `item.addTags` | — | `host.item.addTags` | any |
316
- | `item.removeTags` | — | `host.item.removeTags` | any |
317
- | `item.setPinned` | — | `host.item.setPinned` | any |
318
- | `item.setAttachments` | — | `host.item.setAttachments` | any |
319
- | `item.setSearchExtension` | — | `host.item.setSearchExtension` | any |
320
- | `item.materializeImagePath` | — | `host.item.materializeImagePath` | any |
321
- | `item.readAttachment` | `clipbus.item.readAttachment` | `host.item.readAttachment` | any |
330
+ | `item.setTags` | — | `ctx.host.item.setTags` | any |
331
+ | `item.addTags` | — | `ctx.host.item.addTags` | any |
332
+ | `item.removeTags` | — | `ctx.host.item.removeTags` | any |
333
+ | `item.setPinned` | — | `ctx.host.item.setPinned` | any |
334
+ | `item.setAttachments` | — | `ctx.host.item.setAttachments` | any |
335
+ | `item.setSearchExtension` | — | `ctx.host.item.setSearchExtension` | any |
336
+ | `item.materializeImagePath` | — | `ctx.host.item.materializeImagePath` | any |
337
+ | `item.readAttachment` | `clipbus.item.readAttachment` | `ctx.host.item.readAttachment` | any |
322
338
  | `asset.currentItemImageUrl` | `clipbus.asset.currentItemImageUrl` | — | any |
323
339
  | `asset.pathReferenceImageUrl` | `clipbus.asset.pathReferenceImageUrl` | — | any |
324
340
  | `asset.currentActionInputImageUrl` | `clipbus.asset.currentActionInputImageUrl` | — | action |
325
341
  | `asset.currentActionInputPathReferenceImageUrl` | `clipbus.asset.currentActionInputPathReferenceImageUrl` | — | action |
326
- | `asset.registerImage` | — | `host.asset.registerImage` | any |
327
- | `clipboard.copyText` | `clipbus.clipboard.copyText` | `host.clipboard.copyText` | any |
328
- | `navigation.openUrl` | `clipbus.navigation.openUrl` | `host.navigation.openUrl` | any |
329
- | `navigation.revealInFinder` | `clipbus.navigation.revealInFinder` | `host.navigation.revealInFinder` | any |
330
- | `navigation.openFilePath` | `clipbus.navigation.openFilePath` | `host.navigation.openFilePath` | any |
331
- | `action.allocateImageTempPath` | — | `host.action.allocateImageTempPath` | action |
332
- | `action.materializeInputImagePath` | — | `host.action.materializeInputImagePath` | action |
333
- | `action.allocateOutputFilePath` | — | `host.action.allocateOutputFilePath` | action |
342
+ | `asset.allocateImageTempPath` | — | `ctx.host.asset.allocateImageTempPath` | any |
343
+ | `asset.registerImage` | — | `ctx.host.asset.registerImage` | any |
344
+ | `clipboard.copyText` | `clipbus.clipboard.copyText` | `ctx.host.clipboard.copyText` | any |
345
+ | `navigation.openUrl` | `clipbus.navigation.openUrl` | `ctx.host.navigation.openUrl` | any |
346
+ | `navigation.revealInFinder` | `clipbus.navigation.revealInFinder` | `ctx.host.navigation.revealInFinder` | any |
347
+ | `navigation.openFilePath` | `clipbus.navigation.openFilePath` | `ctx.host.navigation.openFilePath` | any |
348
+ | `action.allocateImageTempPath` | — | `ctx.host.action.allocateImageTempPath` | action |
349
+ | `action.materializeInputImagePath` | — | `ctx.host.action.materializeInputImagePath` | action |
350
+ | `action.allocateOutputFilePath` | — | `ctx.host.action.allocateOutputFilePath` | action |
334
351
  | `action.setButtons` | `clipbus.action.setButtons` | — | action |
335
352
  | `action.complete` | `clipbus.action.complete` | — | action |
336
353
  | `attachmentRenderer.setButtons` | `clipbus.attachmentRenderer.setButtons` | — | attachmentRenderer |
@@ -338,11 +355,12 @@ Every entry below maps 1:1 to a catalog descriptor — there is no hidden surfac
338
355
  | `window.autoFit` | `clipbus.window.autoFit` | — | any |
339
356
  | `infoPanel.open` | `clipbus.infoPanel.open` | — | any |
340
357
  | `infoPanel.close` | `clipbus.infoPanel.close` | — | any |
341
- | `settings.get` | `clipbus.settings.get` | `host.settings.get` | any |
342
- | `settings.getAll` | `clipbus.settings.getAll` | `host.settings.getAll` | any |
343
- | `console.log` | `clipbus.console.log` | `host.console.log` | any |
358
+ | `settings.get` | `clipbus.settings.get` | `ctx.host.settings.get` | any |
359
+ | `settings.getAll` | `clipbus.settings.getAll` | `ctx.host.settings.getAll` | any |
360
+ | `console.log` | `clipbus.console.log` | `ctx.host.console.log` | any |
361
+ | `console.diagnostic` | `clipbus.console.diagnostic` | `ctx.host.console.diagnostic` | any |
344
362
  | `textInput.stateChanged` | `clipbus.textInput.stateChanged` | — | any |
345
- | `locale.get` | — | `host.locale.get` | any |
363
+ | `locale.get` | — | `ctx.host.locale.get` | any |
346
364
 
347
365
  ## 4. Host Events
348
366
 
@@ -560,6 +578,14 @@ Discriminated union on `type`: { type: `'label'`, text: `string` } | { type: `'t
560
578
 
561
579
  Union: `'debug'` | `'info'` | `'warn'` | `'error'`
562
580
 
581
+ ### `PluginDiagnosticEvent`
582
+
583
+ Union: `'action_started'` | `'action_completed'` | `'action_failed'` | `'renderer_ready'` | `'renderer_failed'` | `'detector_completed'` | `'detector_failed'` | `'runtime_ready'` | `'runtime_failed'`
584
+
585
+ ### `PluginDiagnosticReason`
586
+
587
+ Union: `'none'` | `'invalid_input'` | `'unsupported'` | `'timeout'` | `'unavailable'` | `'failed'`
588
+
563
589
  ### `PluginClipboardItem`
564
590
 
565
591
  - `id`: `string`
@@ -689,6 +715,46 @@ Discriminated union on `kind`: { kind: `'text'`, text: `string` } | { kind: `'im
689
715
  - `result`: [`PluginActionResult`](#pluginactionresult)
690
716
  - `userMessage?`: `string`
691
717
 
718
+ ### `PluginNodeIPCRequestFrame`
719
+
720
+ - `id`: `string`
721
+ - `method`: `string`
722
+ - `request`: `json`
723
+
724
+ ### `PluginNodeIPCResponseFrame`
725
+
726
+ - `id?`: `string`
727
+ - `response?`: `json`
728
+ - `error?`: `json`
729
+
730
+ ### `PluginNodeIPCErrorFrame`
731
+
732
+ - `name`: `string`
733
+ - `message`: `string`
734
+ - `data?`: `json`
735
+
736
+ ### `PluginRuntimePluginDescriptor`
737
+
738
+ - `id`: `string`
739
+ - `title`: `string`
740
+ - `version`: `string`
741
+
742
+ ### `PluginRuntimeHostPlatform`
743
+
744
+ Union: `'macos'` | `'windows'`
745
+
746
+ ### `PluginRuntimeHostDescriptor`
747
+
748
+ - `platform`: [`PluginRuntimeHostPlatform`](#pluginruntimehostplatform)
749
+ - `hostVersion`: `string`
750
+ - `devMode`: `bool`
751
+
752
+ ### `PluginRuntimeLaunchContext`
753
+
754
+ - `plugin`: [`PluginRuntimePluginDescriptor`](#pluginruntimeplugindescriptor)
755
+ - `host`: [`PluginRuntimeHostDescriptor`](#pluginruntimehostdescriptor)
756
+ - `supportedCapabilities`: `string`[]
757
+
692
758
  ## 9. Wire Constants
693
759
 
694
760
  - `__clipbus_structured_error__:` — prefix used by the runtime error envelope.
@@ -709,11 +775,12 @@ Discriminated union on `kind`: { kind: `'text'`, text: `string` } | { kind: `'im
709
775
 
710
776
  | Concept | Generated file (TS) | Generated file (Swift) |
711
777
  | --- | --- | --- |
712
- | Capability payload/response types | `capabilityClients.generated.ts` | `PluginCapabilityPayloads.generated.swift` |
778
+ | Capability payload/response types + method map | `capabilities.generated.ts` | `PluginCapabilityPayloads.generated.swift` |
713
779
  | UI capability tree | `ui.clipbus.generated.ts` | — |
714
- | Runtime host tree | `runtime.host.generated.ts`, `hostClients.generated.ts` | — |
715
- | Host event subscribers | `topicSubscribers.generated.ts` | `PluginHostTopicEmitter.generated.swift` |
716
- | Node IPC server | `nodeIPCServer.generated.ts` | `PluginNodeIPCClient.generated.swift` |
780
+ | Runtime host client (`ctx.host`) | `hostClients.generated.ts` | — |
781
+ | Host events (payloads, window globals, bootstrap sets) | `hostEvents.generated.ts` | `PluginHostTopicEmitter.generated.swift` |
782
+ | Node IPC types + handler routes | `nodeIPC.generated.ts` | `PluginNodeIPCClient.generated.swift` |
717
783
  | Named types | `data.generated.ts` | `PluginCommonTypes.generated.swift` |
718
784
  | Handler interfaces | `runtime.handlers.generated.ts` | `PluginUIHostHandler.generated.swift`, `PluginRuntimeHostHandler.generated.swift` |
719
- | `definePlugin` + registry | `runtime.definePlugin.generated.ts` | — |
785
+ | Registry / setup types | `runtime.registry.generated.ts` | — |
786
+ | Wire constants | `wireConstants.generated.ts` | `PluginWireConstants.generated.swift` |
package/CHANGELOG.md ADDED
@@ -0,0 +1,84 @@
1
+ # Changelog
2
+
3
+ Release notes for `@clipbus/plugin-sdk`, newest first. Each version is also published at https://github.com/scubers/clipbus-release/releases?q=%22Clipbus+Plugin+SDK%22&expanded=true
4
+
5
+ ## 0.10.0
6
+
7
+ ### New
8
+
9
+ - **Session-owned temporary paths for generated images**: `ctx.host.asset.allocateImageTempPath({ formatHint })` allocates an image path owned by the current session in any runtime context. Write the image there, then call `ctx.host.asset.registerImage({ path })` to get a URL the WebView can render. The path expires with its owning session; neither method is callable from the WebView.
10
+ - **Structured diagnostics**: `clipbus.console.diagnostic(...)` (UI) and `ctx.host.console.diagnostic(...)` (runtime) take `{ level, event, reason, count, durationMs }`, where `event` and `reason` come from the closed `PluginDiagnosticEvent` / `PluginDiagnosticReason` vocabularies. Use it for anything you need to see in the Log Console:
11
+
12
+ ```ts
13
+ await clipbus.console.diagnostic({ level: 'info', event: 'action_completed', reason: 'none', count: 1, durationMs: 42 });
14
+ ```
15
+
16
+ Hosts that support it record only the level and byte count of `console.log`, not the message text. Diagnostic volume is bounded and excess calls may be rejected.
17
+ - **Runtime type exports**: `@clipbus/plugin-sdk/runtime` now exports `PluginRegistry`, `PluginSetup`, `MessageHandler`, `MessageHandlerContext`, `HostClient` (the type of `ctx.host`) and `PluginRuntimeLaunchContext`. The `context` argument of `definePlugin({ setup(context) { ... } })` is now typed and carries `plugin`, `host` and `supportedCapabilities`.
18
+
19
+ ### Breaking changes
20
+
21
+ - **The `host` export of `@clipbus/plugin-sdk/runtime` is removed.** It was never connected to the Host and threw on every call. Use `ctx.host` from the handler context instead; in ESM, a remaining `import { host }` makes the module fail to load.
22
+
23
+ ```ts
24
+ // Before
25
+ import { host } from '@clipbus/plugin-sdk/runtime';
26
+ await host.clipboard.copyText({ text });
27
+
28
+ // After
29
+ async runAutoAction(input, ctx) {
30
+ await ctx?.host?.clipboard.copyText({ text });
31
+ // ...
32
+ }
33
+ ```
34
+
35
+ ### Compatibility
36
+
37
+ - `asset.allocateImageTempPath` and `console.diagnostic` require Clipbus for macOS 1.6.0 or Clipbus for Windows 0.1.0 or later. Older Hosts reject them with `CapabilityUnsupportedError`; check `clipbus.capabilities.has(...)` or the launch context's `supportedCapabilities` first.
38
+ - Everything else takes effect by upgrading the npm package.
39
+
40
+ ### Other
41
+
42
+ - The npm package now ships `CHANGELOG.md`, and every version's notes are published as [Plugin SDK releases](https://github.com/scubers/clipbus-release/releases?q=%22Clipbus+Plugin+SDK%22&expanded=true). The package `homepage` and `repository` now point to that release repository.
43
+
44
+ <details>
45
+ <summary>简体中文</summary>
46
+
47
+ ### 新增
48
+
49
+ - **运行时生成图片的会话临时路径**:`ctx.host.asset.allocateImageTempPath({ formatHint })` 在任意运行时上下文中分配一个归属当前会话的图片路径,写入图片后再调用 `ctx.host.asset.registerImage({ path })` 获得 WebView 可渲染的 URL。路径随所属会话一起失效;WebView 侧不能调用这两个方法。
50
+ - **结构化诊断日志**:新增 `clipbus.console.diagnostic(...)`(UI)与 `ctx.host.console.diagnostic(...)`(运行时),参数为 `{ level, event, reason, count, durationMs }`,`event` / `reason` 取自封闭枚举 `PluginDiagnosticEvent` / `PluginDiagnosticReason`。需要在 Log Console 中查看的信息请改用它:
51
+
52
+ ```ts
53
+ await clipbus.console.diagnostic({ level: 'info', event: 'action_completed', reason: 'none', count: 1, durationMs: 42 });
54
+ ```
55
+
56
+ 支持该能力的 Host 只记录 `console.log` 的级别与字节数,不记录消息正文;诊断调用量有上限,超出可能被拒绝。
57
+ - **运行时类型导出**:`@clipbus/plugin-sdk/runtime` 现在导出 `PluginRegistry`、`PluginSetup`、`MessageHandler`、`MessageHandlerContext`、`HostClient`(即 `ctx.host` 的类型)以及 `PluginRuntimeLaunchContext`。`definePlugin({ setup(context) { ... } })` 中的 `context` 有了类型,包含 `plugin`、`host` 与 `supportedCapabilities`。
58
+
59
+ ### 不兼容变更
60
+
61
+ - **移除 `@clipbus/plugin-sdk/runtime` 的 `host` 导出**。该对象从未接通 Host,任何调用都会抛错。请改用处理函数上下文中的 `ctx.host`;在 ESM 中保留 `import { host }` 会导致模块加载失败。
62
+
63
+ ```ts
64
+ // 之前
65
+ import { host } from '@clipbus/plugin-sdk/runtime';
66
+ await host.clipboard.copyText({ text });
67
+
68
+ // 之后
69
+ async runAutoAction(input, ctx) {
70
+ await ctx?.host?.clipboard.copyText({ text });
71
+ // ...
72
+ }
73
+ ```
74
+
75
+ ### 兼容性
76
+
77
+ - `asset.allocateImageTempPath` 与 `console.diagnostic` 需要 Clipbus macOS 1.6.0 或 Windows 0.1.0 及以上版本。较旧的 Host 会以 `CapabilityUnsupportedError` 拒绝,可先用 `clipbus.capabilities.has(...)` 或启动上下文中的 `supportedCapabilities` 检测。
78
+ - 其余变更只需升级 npm 包即可生效。
79
+
80
+ ### 其他
81
+
82
+ - npm 包内新增 `CHANGELOG.md`,各版本说明同时发布在 [Plugin SDK releases](https://github.com/scubers/clipbus-release/releases?q=%22Clipbus+Plugin+SDK%22&expanded=true);包的 `homepage` 与 `repository` 改为指向该发布仓库。
83
+
84
+ </details>
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Standalone, publishable SDK for Clipbus plugins. Provides typed helpers for the runtime (Node.js) and UI (WebView) sides of a plugin.
4
4
 
5
+ Release notes for every version are published as [Plugin SDK releases](https://github.com/scubers/clipbus-release/releases?q=%22Clipbus+Plugin+SDK%22&expanded=true) and ship in this package as `CHANGELOG.md`.
6
+
5
7
  ## Installation
6
8
 
7
9
  Install from npm:
@@ -288,7 +290,7 @@ Returns opaque `clipbus-asset://` URLs so a WebView can render local images in `
288
290
  | `clipbus.asset.currentActionInputImageUrl()` | `Verb → {url?: string}` | Action-context URL for the current image value, independent of `sourceItem.type`. |
289
291
  | `clipbus.asset.currentActionInputPathReferenceImageUrl({index})` | `Verb → {url?: string}` | Action-context URL for a current path-reference entry. |
290
292
 
291
- Arbitrary / generated images are minted only on the runtime side via `ctx.host.asset.registerImage({path})` (see above), so a WebView XSS cannot turn an arbitrary file into a renderable URL.
293
+ Generated images are minted only on the runtime side: allocate a session-owned path with `ctx.host.asset.allocateImageTempPath({formatHint})`, write the image, then call `ctx.host.asset.registerImage({path})`. The WebView cannot call either method or mint a URL for a local file.
292
294
 
293
295
  ```ts
294
296
  import { clipbus } from '@clipbus/plugin-sdk/ui';
@@ -462,18 +464,21 @@ clipbus.infoPanel.onClose.on(({ panelID }) => { /* clean up */ });
462
464
 
463
465
  | Member | Shape | Description |
464
466
  |---|---|---|
465
- | `clipbus.console.log({level, message})` | `Verb` | Write a log line to the host log (`level: 'debug' \| 'info' \| 'warn' \| 'error'`) |
467
+ | `clipbus.console.log({level, message})` | `Verb` | Send legacy console output; the host records only level and UTF-8 byte count, not the message text |
468
+ | `clipbus.console.diagnostic({level, event, reason, count, durationMs})` | `Verb` | Record a structured, privacy-safe diagnostic using the closed event/reason vocabulary in `API.md` |
466
469
  | `clipbus.textInput.stateChanged({isFocused, isComposing})` | `Verb` | Notify host that a text input's focus / IME state changed |
467
470
  | `clipbus.pluginContext.current()` | Topic | `{ mode: 'attachmentRenderer' \| 'action', pluginID }` — read which kind of WebView this code is running in |
468
471
  | `clipbus.pluginContext.on(fn)` | Topic | Subscribe (rare; context doesn't normally change after bootstrap) |
469
472
 
470
473
  > Strict wire shape: every verb takes a single object parameter (`{text}`, `{url}`, etc.), never a bare value. The single source of truth for every payload / response shape is [API.md](./API.md), generated from `protocol/plugin/src/catalog.ts`.
471
474
 
475
+ Use `console.diagnostic` for information you need in the Log Console. For example, `await clipbus.console.diagnostic({ level: 'info', event: 'action_completed', reason: 'none', count: 1, durationMs: 42 })`. Do not put clipboard content, paths, identifiers, or secrets into log messages; the structured channel has no field for them. The host bounds diagnostic volume and may reject excess calls.
476
+
472
477
  ---
473
478
 
474
479
  ## Types
475
480
 
476
- All public types live in the generated `data.generated.ts` / `capabilityClients.generated.ts` and carry the `Plugin` prefix. The pre-`plugin-api-shrink` aliases without the prefix have been removed.
481
+ All public types live in the generated `data.generated.ts` / `capabilities.generated.ts` (plus `hostClients.generated.ts` and `runtime.registry.generated.ts` for the runtime entry) and carry the `Plugin` prefix. The pre-`plugin-api-shrink` aliases without the prefix have been removed.
477
482
 
478
483
  ```ts
479
484
  // Data types — re-exported from both /runtime and /ui
@@ -513,8 +518,11 @@ import type {
513
518
  // definePlugin types — runtime side only
514
519
  import type {
515
520
  PluginRegistry,
521
+ PluginSetup,
522
+ PluginRuntimeLaunchContext, // setup(context) argument
516
523
  MessageHandler,
517
524
  MessageHandlerContext,
525
+ HostClient, // the type of ctx.host
518
526
  } from '@clipbus/plugin-sdk/runtime';
519
527
  ```
520
528
 
package/SPECIFICATION.md CHANGED
@@ -179,6 +179,7 @@ Capabilities are split by catalog `surface.side`: runtime capabilities are expos
179
179
  | Replace action button list | `action.setButtons` | — | `clipbus.action.setButtons({buttons})` | Verb; buttons have `isEnabled?: boolean` field |
180
180
  | Submit draft result | `action.complete` | — | `clipbus.action.complete({result, userMessage?})` | Verb; draft lifecycle only; value results can be explicitly advanced by the user, `none` cannot |
181
181
  | Allocate image temp path | `action.allocateImageTempPath` | `ctx.host.action.allocateImageTempPath({formatHint?})` | — | Verb; runtime-only via user RPC bridge; removed from UI in plugin-api-shrink |
182
+ | Allocate session image path | `asset.allocateImageTempPath` | `ctx.host.asset.allocateImageTempPath({formatHint})` | — | Runtime-only, any context with a temporary-resource owner; path expires with that owner |
182
183
  | Materialize current Action image | `action.materializeInputImagePath` | `ctx.host.action.materializeInputImagePath()` | — | Reads current cascade image, not the original item |
183
184
  | Allocate Action output file | `action.allocateOutputFilePath` | `ctx.host.action.allocateOutputFilePath({suggestedName?})` | — | Path may only be returned as an `allocated_file` result entry |
184
185
  | Current Action input | action input host event | input param | `clipbus.action.input.current()` | Sanitized Topic; path values omit real paths |
@@ -273,7 +274,7 @@ The plugin wire is fully codegen-driven. Choosing between `defineCapability` and
273
274
 
274
275
  6. **Test** — add host bridge tests for the new method. Do not write pure UI unit tests; codegen snapshot tests cover the surface.
275
276
 
276
- 7. **Verify locally** — `./scripts/checks/check-plugin-contract.sh` and the host platform test flow must both exit 0.
277
+ 7. **Verify locally** — `cd protocol/plugin && npm test`, `./scripts/checks/check-plugin-contract.sh` and the host platform test flow must all exit 0.
277
278
 
278
279
  8. **PR** — see Chapter 5 for the PR checklist.
279
280
 
@@ -366,7 +367,7 @@ Before merging any PR that touches `sdk/`:
366
367
  - [ ] `npm run build` passes in `sdk/`
367
368
  - [ ] `npm test` passes in `sdk/` (runtime + ui + surface)
368
369
  - [ ] Surface snapshot updated with `SNAPSHOT_UPDATE=1` and golden files committed
369
- - [ ] No references to host-internal paths, WebKit handler names, or host implementation class names in any `*.md` file under `sdk/` (run the doc-grep CI step to verify)
370
+ - [ ] No references to host-internal paths, WebKit handler names, or host implementation class names in any `*.md` file under `sdk/` (checked in review)
370
371
  - [ ] PR description cites the SPECIFICATION.md chapter number justifying shape choice
371
372
  - [ ] `npm test` passes in `plugins/template-plugin/` (template plugin integration tests)
372
373
  - [ ] `./scripts/checks/check-plugin-contract.sh` exits 0
@@ -30,6 +30,14 @@ module.exports = __toCommonJS(index_exports);
30
30
  // src/generated/wireConstants.generated.ts
31
31
  var STRUCTURED_ERROR_PREFIX = "__clipbus_structured_error__:";
32
32
  var CAPABILITY_UNSUPPORTED_ERROR_NAME = "PluginCapabilityUnsupported";
33
+ var PLUGIN_CALL_HANDLER_NAME = "clipbusPluginCall";
34
+ var WIRE_ERROR_NAMES = {
35
+ methodNotFound: "PluginRuntimeMethodNotFound",
36
+ handlerNotFound: "PluginRuntimeHandlerNotFound",
37
+ invocationExpired: "PluginRuntimeInvocationExpired",
38
+ hostCallLimitExceeded: "PluginRuntimeHostCallLimitExceeded",
39
+ hostBridgeUnavailable: "PluginHostBridgeUnavailable"
40
+ };
33
41
 
34
42
  // src/internal/capabilities.ts
35
43
  var CapabilityUnsupportedError = class extends Error {
@@ -51,20 +59,29 @@ function mapToCapabilityError(err, unsupportedName) {
51
59
  return err;
52
60
  }
53
61
 
54
- // src/internal/runtimeInvokeClient.ts
62
+ // src/internal/pluginCall.ts
63
+ async function callPluginMethod(method, payload) {
64
+ const handler = globalThis.webkit?.messageHandlers?.[PLUGIN_CALL_HANDLER_NAME];
65
+ if (!handler) {
66
+ const err = new Error("clipbus." + method + " is only available inside a Clipbus plugin WebView");
67
+ err.name = WIRE_ERROR_NAMES.hostBridgeUnavailable;
68
+ throw err;
69
+ }
70
+ const normalized = JSON.parse(JSON.stringify(payload));
71
+ try {
72
+ return await handler.postMessage({ method, payload: normalized });
73
+ } catch (err) {
74
+ throw parseReplyError(err);
75
+ }
76
+ }
55
77
  function parseReplyError(raw) {
56
78
  const message = extractMessage(raw);
57
79
  if (message.startsWith(STRUCTURED_ERROR_PREFIX)) {
58
- const json = message.slice(STRUCTURED_ERROR_PREFIX.length);
59
80
  try {
60
- const parsed = JSON.parse(json);
81
+ const parsed = JSON.parse(message.slice(STRUCTURED_ERROR_PREFIX.length));
61
82
  const err = new Error(typeof parsed.message === "string" ? parsed.message : "");
62
- if (typeof parsed.name === "string" && parsed.name.length > 0) {
63
- err.name = parsed.name;
64
- }
65
- if (parsed.data !== void 0) {
66
- err.data = parsed.data;
67
- }
83
+ if (typeof parsed.name === "string" && parsed.name.length > 0) err.name = parsed.name;
84
+ if (parsed.data !== void 0) err.data = parsed.data;
68
85
  return mapToCapabilityError(err, CAPABILITY_UNSUPPORTED_ERROR_NAME);
69
86
  } catch {
70
87
  return new Error(message);
@@ -82,28 +99,6 @@ function extractMessage(raw) {
82
99
  return String(raw);
83
100
  }
84
101
 
85
- // src/generated/capabilityClients.generated.ts
86
- var HANDLER_NAME = "clipbusPluginCall";
87
- async function callPluginMethod(method, payload) {
88
- const handler = globalThis.webkit?.messageHandlers?.[HANDLER_NAME];
89
- if (!handler) {
90
- const err = new Error("clipbus." + method + " is only available inside a Clipbus plugin WebView");
91
- err.name = "PluginHostBridgeUnavailable";
92
- throw err;
93
- }
94
- const normalized = JSON.parse(JSON.stringify(payload));
95
- let reply;
96
- try {
97
- reply = await handler.postMessage({ method, payload: normalized });
98
- } catch (err) {
99
- throw parseReplyError(err);
100
- }
101
- return reply;
102
- }
103
- var callWindowSetHeight = (payload) => callPluginMethod("window.setHeight", payload);
104
- var callConsoleLog = (payload) => callPluginMethod("console.log", payload);
105
- var callTextInputStateChanged = (payload) => callPluginMethod("textInput.stateChanged", payload);
106
-
107
102
  // src/internal/internalConsole.ts
108
103
  function pick(method) {
109
104
  if (typeof globalThis === "undefined") return () => {
@@ -137,7 +132,7 @@ function autoFit(options) {
137
132
  pending = false;
138
133
  const raw = target.scrollHeight;
139
134
  const clamped = Math.min(max, Math.max(min, raw));
140
- callWindowSetHeight({ height: clamped }).catch((err) => {
135
+ callPluginMethod("window.setHeight", { height: clamped }).catch((err) => {
141
136
  internalConsole.warn("[clipbus-sdk] autoFit: window.setHeight failed:", err);
142
137
  });
143
138
  });
@@ -163,7 +158,7 @@ function patchConsole() {
163
158
  original(...args);
164
159
  if (_inFlight > 0) return;
165
160
  _inFlight++;
166
- Promise.resolve().then(() => callConsoleLog({ level, message: args.map(String).join(" ") })).catch((err) => {
161
+ Promise.resolve().then(() => callPluginMethod("console.log", { level, message: args.map(String).join(" ") })).catch((err) => {
167
162
  internalConsole.warn("[clipbus-sdk] consolePatch: forward to host failed:", err);
168
163
  }).finally(() => {
169
164
  _inFlight--;
@@ -182,7 +177,7 @@ function patchTextInputState() {
182
177
  let isFocused = false;
183
178
  let isComposing = false;
184
179
  function post() {
185
- callTextInputStateChanged({ isFocused, isComposing }).catch((err) => {
180
+ callPluginMethod("textInput.stateChanged", { isFocused, isComposing }).catch((err) => {
186
181
  internalConsole.warn("[clipbus-sdk] textInputState: dispatch failed:", err);
187
182
  });
188
183
  }
package/dist/dom/index.js CHANGED
@@ -1,6 +1,14 @@
1
1
  // src/generated/wireConstants.generated.ts
2
2
  var STRUCTURED_ERROR_PREFIX = "__clipbus_structured_error__:";
3
3
  var CAPABILITY_UNSUPPORTED_ERROR_NAME = "PluginCapabilityUnsupported";
4
+ var PLUGIN_CALL_HANDLER_NAME = "clipbusPluginCall";
5
+ var WIRE_ERROR_NAMES = {
6
+ methodNotFound: "PluginRuntimeMethodNotFound",
7
+ handlerNotFound: "PluginRuntimeHandlerNotFound",
8
+ invocationExpired: "PluginRuntimeInvocationExpired",
9
+ hostCallLimitExceeded: "PluginRuntimeHostCallLimitExceeded",
10
+ hostBridgeUnavailable: "PluginHostBridgeUnavailable"
11
+ };
4
12
 
5
13
  // src/internal/capabilities.ts
6
14
  var CapabilityUnsupportedError = class extends Error {
@@ -22,20 +30,29 @@ function mapToCapabilityError(err, unsupportedName) {
22
30
  return err;
23
31
  }
24
32
 
25
- // src/internal/runtimeInvokeClient.ts
33
+ // src/internal/pluginCall.ts
34
+ async function callPluginMethod(method, payload) {
35
+ const handler = globalThis.webkit?.messageHandlers?.[PLUGIN_CALL_HANDLER_NAME];
36
+ if (!handler) {
37
+ const err = new Error("clipbus." + method + " is only available inside a Clipbus plugin WebView");
38
+ err.name = WIRE_ERROR_NAMES.hostBridgeUnavailable;
39
+ throw err;
40
+ }
41
+ const normalized = JSON.parse(JSON.stringify(payload));
42
+ try {
43
+ return await handler.postMessage({ method, payload: normalized });
44
+ } catch (err) {
45
+ throw parseReplyError(err);
46
+ }
47
+ }
26
48
  function parseReplyError(raw) {
27
49
  const message = extractMessage(raw);
28
50
  if (message.startsWith(STRUCTURED_ERROR_PREFIX)) {
29
- const json = message.slice(STRUCTURED_ERROR_PREFIX.length);
30
51
  try {
31
- const parsed = JSON.parse(json);
52
+ const parsed = JSON.parse(message.slice(STRUCTURED_ERROR_PREFIX.length));
32
53
  const err = new Error(typeof parsed.message === "string" ? parsed.message : "");
33
- if (typeof parsed.name === "string" && parsed.name.length > 0) {
34
- err.name = parsed.name;
35
- }
36
- if (parsed.data !== void 0) {
37
- err.data = parsed.data;
38
- }
54
+ if (typeof parsed.name === "string" && parsed.name.length > 0) err.name = parsed.name;
55
+ if (parsed.data !== void 0) err.data = parsed.data;
39
56
  return mapToCapabilityError(err, CAPABILITY_UNSUPPORTED_ERROR_NAME);
40
57
  } catch {
41
58
  return new Error(message);
@@ -53,28 +70,6 @@ function extractMessage(raw) {
53
70
  return String(raw);
54
71
  }
55
72
 
56
- // src/generated/capabilityClients.generated.ts
57
- var HANDLER_NAME = "clipbusPluginCall";
58
- async function callPluginMethod(method, payload) {
59
- const handler = globalThis.webkit?.messageHandlers?.[HANDLER_NAME];
60
- if (!handler) {
61
- const err = new Error("clipbus." + method + " is only available inside a Clipbus plugin WebView");
62
- err.name = "PluginHostBridgeUnavailable";
63
- throw err;
64
- }
65
- const normalized = JSON.parse(JSON.stringify(payload));
66
- let reply;
67
- try {
68
- reply = await handler.postMessage({ method, payload: normalized });
69
- } catch (err) {
70
- throw parseReplyError(err);
71
- }
72
- return reply;
73
- }
74
- var callWindowSetHeight = (payload) => callPluginMethod("window.setHeight", payload);
75
- var callConsoleLog = (payload) => callPluginMethod("console.log", payload);
76
- var callTextInputStateChanged = (payload) => callPluginMethod("textInput.stateChanged", payload);
77
-
78
73
  // src/internal/internalConsole.ts
79
74
  function pick(method) {
80
75
  if (typeof globalThis === "undefined") return () => {
@@ -108,7 +103,7 @@ function autoFit(options) {
108
103
  pending = false;
109
104
  const raw = target.scrollHeight;
110
105
  const clamped = Math.min(max, Math.max(min, raw));
111
- callWindowSetHeight({ height: clamped }).catch((err) => {
106
+ callPluginMethod("window.setHeight", { height: clamped }).catch((err) => {
112
107
  internalConsole.warn("[clipbus-sdk] autoFit: window.setHeight failed:", err);
113
108
  });
114
109
  });
@@ -134,7 +129,7 @@ function patchConsole() {
134
129
  original(...args);
135
130
  if (_inFlight > 0) return;
136
131
  _inFlight++;
137
- Promise.resolve().then(() => callConsoleLog({ level, message: args.map(String).join(" ") })).catch((err) => {
132
+ Promise.resolve().then(() => callPluginMethod("console.log", { level, message: args.map(String).join(" ") })).catch((err) => {
138
133
  internalConsole.warn("[clipbus-sdk] consolePatch: forward to host failed:", err);
139
134
  }).finally(() => {
140
135
  _inFlight--;
@@ -153,7 +148,7 @@ function patchTextInputState() {
153
148
  let isFocused = false;
154
149
  let isComposing = false;
155
150
  function post() {
156
- callTextInputStateChanged({ isFocused, isComposing }).catch((err) => {
151
+ callPluginMethod("textInput.stateChanged", { isFocused, isComposing }).catch((err) => {
157
152
  internalConsole.warn("[clipbus-sdk] textInputState: dispatch failed:", err);
158
153
  });
159
154
  }
@@ -2,7 +2,7 @@
2
2
  * Framework-agnostic helper for binding a SDK topic to any reactive state
3
3
  * system (Vue, React, Svelte, plain callbacks, …).
4
4
  *
5
- * `Topic<T>` is the interface from sdk/src/internal/topic.ts.
5
+ * `Topic<T>` is the interface from src/internal/topic.ts.
6
6
  * We intentionally replicate the minimal shape here (structural typing) so this
7
7
  * file has zero runtime imports — it works equally well in Node test runners and
8
8
  * browser bundles.