@clipbus/plugin-sdk 0.8.7 → 0.9.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/API.md +65 -6
- package/README.md +41 -8
- package/SPECIFICATION.md +12 -1
- package/dist/generated/capabilityClients.generated.d.ts +27 -1
- package/dist/generated/data.generated.d.ts +37 -3
- package/dist/generated/hostBootstrap.generated.d.ts +2 -1
- package/dist/generated/hostClients.generated.d.ts +3 -1
- package/dist/generated/runtime.actionResult.generated.d.ts +8 -0
- package/dist/generated/runtime.host.generated.d.ts +3 -1
- package/dist/generated/topicSubscribers.generated.d.ts +3 -1
- package/dist/generated/ui.bootstrap.generated.d.ts +2 -1
- package/dist/generated/ui.clipbus.generated.d.ts +8 -2
- package/dist/preview/index.cjs +12 -0
- package/dist/preview/index.js +12 -0
- package/dist/preview/inputPanel.d.ts +3 -3
- package/dist/preview/types.d.ts +3 -1
- package/dist/preview/wire.d.ts +2 -1
- package/dist/runtime/index.cjs +7 -1
- package/dist/runtime/index.js +7 -1
- package/dist/ui/index.cjs +16 -1
- package/dist/ui/index.js +16 -1
- package/dist/validate/index.cjs +32 -13
- package/dist/validate/index.d.cts +2 -2
- package/dist/validate/index.d.ts +2 -2
- package/dist/validate/index.js +32 -13
- package/docs/authoring.md +34 -4
- package/docs/capability-detection.md +2 -2
- package/docs/entry.md +2 -2
- package/docs/item-context.md +36 -6
- package/docs/manifest.md +13 -5
- package/docs/permissions.md +1 -1
- package/package.json +1 -1
package/dist/preview/index.js
CHANGED
|
@@ -1330,6 +1330,10 @@ function emitActionBootstrap(p) {
|
|
|
1330
1330
|
globalThis["__CLIPBUS_PLUGIN_DRAFT__"] = p.draft;
|
|
1331
1331
|
globalThis.dispatchEvent(new CustomEvent("clipbus-plugin-draft", { detail: p.draft }));
|
|
1332
1332
|
}
|
|
1333
|
+
if (p.actionInput !== void 0) {
|
|
1334
|
+
globalThis["__CLIPBUS_PLUGIN_ACTION_INPUT__"] = p.actionInput;
|
|
1335
|
+
globalThis.dispatchEvent(new CustomEvent("clipbus-plugin-action-input", { detail: p.actionInput }));
|
|
1336
|
+
}
|
|
1333
1337
|
if (p.theme !== void 0) {
|
|
1334
1338
|
globalThis["__CLIPBUS_PLUGIN_THEME__"] = p.theme;
|
|
1335
1339
|
globalThis.dispatchEvent(new CustomEvent("clipbus-plugin-theme", { detail: p.theme }));
|
|
@@ -1367,6 +1371,7 @@ function computeWirePayloads(scenario, themeKey = DEFAULT_THEME_KEY) {
|
|
|
1367
1371
|
context,
|
|
1368
1372
|
item: scenario.item,
|
|
1369
1373
|
draft: scenario.draft ?? {},
|
|
1374
|
+
actionInput: scenario.actionInput,
|
|
1370
1375
|
theme,
|
|
1371
1376
|
locale
|
|
1372
1377
|
};
|
|
@@ -1385,6 +1390,7 @@ function injectWire(_target, payloads) {
|
|
|
1385
1390
|
context: payloads.context,
|
|
1386
1391
|
item: payloads.item,
|
|
1387
1392
|
draft: payloads.draft,
|
|
1393
|
+
actionInput: payloads.actionInput,
|
|
1388
1394
|
theme: payloads.theme,
|
|
1389
1395
|
locale: payloads.locale
|
|
1390
1396
|
});
|
|
@@ -1441,6 +1447,12 @@ function classifyWireSections(payloads) {
|
|
|
1441
1447
|
defaultOpen: true,
|
|
1442
1448
|
value: payloads.draft
|
|
1443
1449
|
});
|
|
1450
|
+
sections.push({
|
|
1451
|
+
key: "actionInput",
|
|
1452
|
+
kind: "content",
|
|
1453
|
+
defaultOpen: true,
|
|
1454
|
+
value: payloads.actionInput
|
|
1455
|
+
});
|
|
1444
1456
|
}
|
|
1445
1457
|
sections.push({
|
|
1446
1458
|
key: "theme",
|
|
@@ -16,7 +16,7 @@ import type { WirePayloads } from './wire.js';
|
|
|
16
16
|
export interface WireSection {
|
|
17
17
|
/** The payload key name (e.g. 'context', 'item', 'attachment'). */
|
|
18
18
|
key: string;
|
|
19
|
-
/** content = item + attachment/draft (user-facing data; open by default).
|
|
19
|
+
/** content = item + attachment/draft/actionInput (user-facing data; open by default).
|
|
20
20
|
* infra = context + theme + locale (plumbing; collapsed by default). */
|
|
21
21
|
kind: 'content' | 'infra';
|
|
22
22
|
/** Whether the section is expanded when first rendered. */
|
|
@@ -27,8 +27,8 @@ export interface WireSection {
|
|
|
27
27
|
/**
|
|
28
28
|
* Classify wire payload sections into display order with open/collapsed defaults.
|
|
29
29
|
*
|
|
30
|
-
* Fixed order: context · item · attachment(renderer)/draft(action) · theme · locale
|
|
31
|
-
* content: item + attachment/draft — defaultOpen true
|
|
30
|
+
* Fixed order: context · item · attachment(renderer)/draft+actionInput(action) · theme · locale
|
|
31
|
+
* content: item + attachment/draft/actionInput — defaultOpen true
|
|
32
32
|
* infra: context + theme + locale — defaultOpen false (plumbing, low signal)
|
|
33
33
|
*/
|
|
34
34
|
export declare function classifyWireSections(payloads: WirePayloads): WireSection[];
|
package/dist/preview/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginActionUIInput, PluginAttachmentPayload, PluginClipboardItem } from '../generated/data.generated.js';
|
|
2
2
|
export interface PreviewViewport {
|
|
3
3
|
/** Initial viewport width (px). Defaults to the per-mode width when omitted. */
|
|
4
4
|
width?: number;
|
|
@@ -27,6 +27,8 @@ export interface PreviewScenario {
|
|
|
27
27
|
attachment?: PluginAttachmentPayload;
|
|
28
28
|
/** Action mode draft payload. */
|
|
29
29
|
draft?: Record<string, unknown>;
|
|
30
|
+
/** Sanitized current Action value; never include real filesystem paths. */
|
|
31
|
+
actionInput?: PluginActionUIInput;
|
|
30
32
|
buttons?: {
|
|
31
33
|
id: string;
|
|
32
34
|
title: string;
|
package/dist/preview/wire.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PluginThemeTokenSnapshot } from '../generated/data.generated.js';
|
|
2
2
|
import type { PluginContextPayload, PluginLocalePayload } from '../generated/hostBootstrap.generated.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { PluginActionUIInput, PluginAttachmentPayload, PluginClipboardItem } from '../generated/data.generated.js';
|
|
4
4
|
import type { PreviewScenario } from './types.js';
|
|
5
5
|
/**
|
|
6
6
|
* Backward-compat alias. Now accepts any preset key string ('graphite', 'ember',
|
|
@@ -13,6 +13,7 @@ export interface WirePayloads {
|
|
|
13
13
|
item: PluginClipboardItem;
|
|
14
14
|
attachment?: PluginAttachmentPayload;
|
|
15
15
|
draft?: Record<string, unknown>;
|
|
16
|
+
actionInput?: PluginActionUIInput;
|
|
16
17
|
theme: PluginThemeTokenSnapshot;
|
|
17
18
|
locale: PluginLocalePayload;
|
|
18
19
|
}
|
package/dist/runtime/index.cjs
CHANGED
|
@@ -79,7 +79,9 @@ var host = {
|
|
|
79
79
|
openFilePath: (payload) => ipcBus.request("navigation.openFilePath", payload)
|
|
80
80
|
},
|
|
81
81
|
action: {
|
|
82
|
-
allocateImageTempPath: (payload) => ipcBus.request("action.allocateImageTempPath", payload)
|
|
82
|
+
allocateImageTempPath: (payload) => ipcBus.request("action.allocateImageTempPath", payload),
|
|
83
|
+
materializeInputImagePath: () => ipcBus.request("action.materializeInputImagePath", {}),
|
|
84
|
+
allocateOutputFilePath: (payload) => ipcBus.request("action.allocateOutputFilePath", payload)
|
|
83
85
|
},
|
|
84
86
|
settings: {
|
|
85
87
|
get: (payload) => ipcBus.request("settings.get", payload),
|
|
@@ -132,6 +134,10 @@ var actionResult = {
|
|
|
132
134
|
result: { resultKind: "image", imageTempPath, ...options && "imageFormatHint" in options ? { imageFormatHint: options.imageFormatHint } : {} },
|
|
133
135
|
userMessage: options?.userMessage
|
|
134
136
|
}),
|
|
137
|
+
path_reference: (entries, options) => ({
|
|
138
|
+
result: { resultKind: "path_reference", entries },
|
|
139
|
+
userMessage: options?.userMessage
|
|
140
|
+
}),
|
|
135
141
|
none: (options) => ({
|
|
136
142
|
result: { resultKind: "none" },
|
|
137
143
|
userMessage: options?.userMessage
|
package/dist/runtime/index.js
CHANGED
|
@@ -49,7 +49,9 @@ var host = {
|
|
|
49
49
|
openFilePath: (payload) => ipcBus.request("navigation.openFilePath", payload)
|
|
50
50
|
},
|
|
51
51
|
action: {
|
|
52
|
-
allocateImageTempPath: (payload) => ipcBus.request("action.allocateImageTempPath", payload)
|
|
52
|
+
allocateImageTempPath: (payload) => ipcBus.request("action.allocateImageTempPath", payload),
|
|
53
|
+
materializeInputImagePath: () => ipcBus.request("action.materializeInputImagePath", {}),
|
|
54
|
+
allocateOutputFilePath: (payload) => ipcBus.request("action.allocateOutputFilePath", payload)
|
|
53
55
|
},
|
|
54
56
|
settings: {
|
|
55
57
|
get: (payload) => ipcBus.request("settings.get", payload),
|
|
@@ -102,6 +104,10 @@ var actionResult = {
|
|
|
102
104
|
result: { resultKind: "image", imageTempPath, ...options && "imageFormatHint" in options ? { imageFormatHint: options.imageFormatHint } : {} },
|
|
103
105
|
userMessage: options?.userMessage
|
|
104
106
|
}),
|
|
107
|
+
path_reference: (entries, options) => ({
|
|
108
|
+
result: { resultKind: "path_reference", entries },
|
|
109
|
+
userMessage: options?.userMessage
|
|
110
|
+
}),
|
|
105
111
|
none: (options) => ({
|
|
106
112
|
result: { resultKind: "none" },
|
|
107
113
|
userMessage: options?.userMessage
|
package/dist/ui/index.cjs
CHANGED
|
@@ -132,6 +132,8 @@ async function callPluginMethod(method, payload) {
|
|
|
132
132
|
var callItemReadAttachment = (payload) => callPluginMethod("item.readAttachment", payload);
|
|
133
133
|
var callAssetCurrentItemImageUrl = () => callPluginMethod("asset.currentItemImageUrl", {});
|
|
134
134
|
var callAssetPathReferenceImageUrl = (payload) => callPluginMethod("asset.pathReferenceImageUrl", payload);
|
|
135
|
+
var callAssetCurrentActionInputImageUrl = () => callPluginMethod("asset.currentActionInputImageUrl", {});
|
|
136
|
+
var callAssetCurrentActionInputPathReferenceImageUrl = (payload) => callPluginMethod("asset.currentActionInputPathReferenceImageUrl", payload);
|
|
135
137
|
var callClipboardCopyText = (payload) => callPluginMethod("clipboard.copyText", payload);
|
|
136
138
|
var callNavigationOpenUrl = (payload) => callPluginMethod("navigation.openUrl", payload);
|
|
137
139
|
var callNavigationRevealInFinder = (payload) => callPluginMethod("navigation.revealInFinder", payload);
|
|
@@ -212,6 +214,11 @@ function onDraft(listener) {
|
|
|
212
214
|
globalThis.addEventListener("clipbus-plugin-draft", handler);
|
|
213
215
|
return () => globalThis.removeEventListener("clipbus-plugin-draft", handler);
|
|
214
216
|
}
|
|
217
|
+
function onActionInput(listener) {
|
|
218
|
+
const handler = (e) => listener(e.detail);
|
|
219
|
+
globalThis.addEventListener("clipbus-plugin-action-input", handler);
|
|
220
|
+
return () => globalThis.removeEventListener("clipbus-plugin-action-input", handler);
|
|
221
|
+
}
|
|
215
222
|
function onTheme(listener) {
|
|
216
223
|
const handler = (e) => listener(e.detail);
|
|
217
224
|
globalThis.addEventListener("clipbus-plugin-theme", handler);
|
|
@@ -252,6 +259,8 @@ var _itemAttachmentTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_ATTACH
|
|
|
252
259
|
onAttachment((p) => _itemAttachmentTopic.set(p));
|
|
253
260
|
var _actionDraftTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_DRAFT__"));
|
|
254
261
|
onDraft((p) => _actionDraftTopic.set(p));
|
|
262
|
+
var _actionInputTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_ACTION_INPUT__"));
|
|
263
|
+
onActionInput((p) => _actionInputTopic.set(p));
|
|
255
264
|
var _themeTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_THEME__"));
|
|
256
265
|
onTheme((p) => _themeTopic.set(p));
|
|
257
266
|
var _attachmentRendererOnHostInvokeStream = createStream();
|
|
@@ -299,7 +308,9 @@ var clipbus = {
|
|
|
299
308
|
},
|
|
300
309
|
asset: {
|
|
301
310
|
currentItemImageUrl: () => callAssetCurrentItemImageUrl(),
|
|
302
|
-
pathReferenceImageUrl: (payload) => callAssetPathReferenceImageUrl(payload)
|
|
311
|
+
pathReferenceImageUrl: (payload) => callAssetPathReferenceImageUrl(payload),
|
|
312
|
+
currentActionInputImageUrl: guardContext("action", () => callAssetCurrentActionInputImageUrl()),
|
|
313
|
+
currentActionInputPathReferenceImageUrl: guardContext("action", (payload) => callAssetCurrentActionInputPathReferenceImageUrl(payload))
|
|
303
314
|
},
|
|
304
315
|
clipboard: {
|
|
305
316
|
copyText: (payload) => callClipboardCopyText(payload)
|
|
@@ -316,6 +327,10 @@ var clipbus = {
|
|
|
316
327
|
current: () => _actionDraftTopic.current(),
|
|
317
328
|
on: (fn) => _actionDraftTopic.on(fn)
|
|
318
329
|
},
|
|
330
|
+
input: {
|
|
331
|
+
current: () => _actionInputTopic.current(),
|
|
332
|
+
on: (fn) => _actionInputTopic.on(fn)
|
|
333
|
+
},
|
|
319
334
|
onHostInvoke: {
|
|
320
335
|
on: (fn) => _actionOnHostInvokeStream.on(fn)
|
|
321
336
|
}
|
package/dist/ui/index.js
CHANGED
|
@@ -103,6 +103,8 @@ async function callPluginMethod(method, payload) {
|
|
|
103
103
|
var callItemReadAttachment = (payload) => callPluginMethod("item.readAttachment", payload);
|
|
104
104
|
var callAssetCurrentItemImageUrl = () => callPluginMethod("asset.currentItemImageUrl", {});
|
|
105
105
|
var callAssetPathReferenceImageUrl = (payload) => callPluginMethod("asset.pathReferenceImageUrl", payload);
|
|
106
|
+
var callAssetCurrentActionInputImageUrl = () => callPluginMethod("asset.currentActionInputImageUrl", {});
|
|
107
|
+
var callAssetCurrentActionInputPathReferenceImageUrl = (payload) => callPluginMethod("asset.currentActionInputPathReferenceImageUrl", payload);
|
|
106
108
|
var callClipboardCopyText = (payload) => callPluginMethod("clipboard.copyText", payload);
|
|
107
109
|
var callNavigationOpenUrl = (payload) => callPluginMethod("navigation.openUrl", payload);
|
|
108
110
|
var callNavigationRevealInFinder = (payload) => callPluginMethod("navigation.revealInFinder", payload);
|
|
@@ -183,6 +185,11 @@ function onDraft(listener) {
|
|
|
183
185
|
globalThis.addEventListener("clipbus-plugin-draft", handler);
|
|
184
186
|
return () => globalThis.removeEventListener("clipbus-plugin-draft", handler);
|
|
185
187
|
}
|
|
188
|
+
function onActionInput(listener) {
|
|
189
|
+
const handler = (e) => listener(e.detail);
|
|
190
|
+
globalThis.addEventListener("clipbus-plugin-action-input", handler);
|
|
191
|
+
return () => globalThis.removeEventListener("clipbus-plugin-action-input", handler);
|
|
192
|
+
}
|
|
186
193
|
function onTheme(listener) {
|
|
187
194
|
const handler = (e) => listener(e.detail);
|
|
188
195
|
globalThis.addEventListener("clipbus-plugin-theme", handler);
|
|
@@ -223,6 +230,8 @@ var _itemAttachmentTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_ATTACH
|
|
|
223
230
|
onAttachment((p) => _itemAttachmentTopic.set(p));
|
|
224
231
|
var _actionDraftTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_DRAFT__"));
|
|
225
232
|
onDraft((p) => _actionDraftTopic.set(p));
|
|
233
|
+
var _actionInputTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_ACTION_INPUT__"));
|
|
234
|
+
onActionInput((p) => _actionInputTopic.set(p));
|
|
226
235
|
var _themeTopic = createTopic(readWindowGlobal("__CLIPBUS_PLUGIN_THEME__"));
|
|
227
236
|
onTheme((p) => _themeTopic.set(p));
|
|
228
237
|
var _attachmentRendererOnHostInvokeStream = createStream();
|
|
@@ -270,7 +279,9 @@ var clipbus = {
|
|
|
270
279
|
},
|
|
271
280
|
asset: {
|
|
272
281
|
currentItemImageUrl: () => callAssetCurrentItemImageUrl(),
|
|
273
|
-
pathReferenceImageUrl: (payload) => callAssetPathReferenceImageUrl(payload)
|
|
282
|
+
pathReferenceImageUrl: (payload) => callAssetPathReferenceImageUrl(payload),
|
|
283
|
+
currentActionInputImageUrl: guardContext("action", () => callAssetCurrentActionInputImageUrl()),
|
|
284
|
+
currentActionInputPathReferenceImageUrl: guardContext("action", (payload) => callAssetCurrentActionInputPathReferenceImageUrl(payload))
|
|
274
285
|
},
|
|
275
286
|
clipboard: {
|
|
276
287
|
copyText: (payload) => callClipboardCopyText(payload)
|
|
@@ -287,6 +298,10 @@ var clipbus = {
|
|
|
287
298
|
current: () => _actionDraftTopic.current(),
|
|
288
299
|
on: (fn) => _actionDraftTopic.on(fn)
|
|
289
300
|
},
|
|
301
|
+
input: {
|
|
302
|
+
current: () => _actionInputTopic.current(),
|
|
303
|
+
on: (fn) => _actionInputTopic.on(fn)
|
|
304
|
+
},
|
|
290
305
|
onHostInvoke: {
|
|
291
306
|
on: (fn) => _actionOnHostInvokeStream.on(fn)
|
|
292
307
|
}
|
package/dist/validate/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ var MANIFEST_VALIDATION_CODES = [
|
|
|
46
46
|
"duplicateDetectorID",
|
|
47
47
|
"duplicateActionID",
|
|
48
48
|
"emptyPluginID",
|
|
49
|
+
"invalidPluginID",
|
|
49
50
|
"emptyPluginTitle",
|
|
50
51
|
"installEntryMissing",
|
|
51
52
|
"installEntryOutsideRoot",
|
|
@@ -58,11 +59,11 @@ var MANIFEST_VALIDATION_CODES = [
|
|
|
58
59
|
"detectorAttachmentTypeOutsideNamespace",
|
|
59
60
|
"rendererUIEntryMissing",
|
|
60
61
|
"rendererUIEntryOutsideRoot",
|
|
61
|
-
"
|
|
62
|
+
"actionMissingSupportedInputKinds",
|
|
62
63
|
"actionUIEntryMissing",
|
|
63
64
|
"actionUIEntryOutsideRoot",
|
|
64
65
|
"detectorInvalidSupportedInputKind",
|
|
65
|
-
"
|
|
66
|
+
"actionInvalidSupportedInputKind"
|
|
66
67
|
];
|
|
67
68
|
var CANONICAL_ITEM_TYPES = ["text", "image", "path_reference"];
|
|
68
69
|
function asRecord(val) {
|
|
@@ -89,25 +90,41 @@ function isInsideRoot(entryRelative, rootAbsolute) {
|
|
|
89
90
|
const resolvedEntry = import_node_path.default.resolve(rootAbsolute, entryRelative);
|
|
90
91
|
return resolvedEntry === rootAbsolute || resolvedEntry.startsWith(rootAbsolute + import_node_path.default.sep);
|
|
91
92
|
}
|
|
93
|
+
var PLUGIN_ID_MAX_LENGTH = 128;
|
|
94
|
+
var PLUGIN_ID_PATTERN = /^[a-z0-9._-]+$/;
|
|
95
|
+
function isValidPluginID(id) {
|
|
96
|
+
if (id.length === 0 || id.length > PLUGIN_ID_MAX_LENGTH) return false;
|
|
97
|
+
if (id.startsWith(".") || id.includes("..")) return false;
|
|
98
|
+
return PLUGIN_ID_PATTERN.test(id);
|
|
99
|
+
}
|
|
92
100
|
function validateSchemaVersion(raw, issues) {
|
|
93
101
|
const version = typeof raw["schemaVersion"] === "number" ? raw["schemaVersion"] : 0;
|
|
94
|
-
if (version !==
|
|
102
|
+
if (version !== 3) {
|
|
95
103
|
issues.push(issue("unsupportedSchemaVersion", `Unsupported plugin schema version: ${version}`));
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
var LEGACY_RENDERER_FIELDS = ["displayName", "defaultEnabled", "defaultOrderKey", "actions"];
|
|
99
107
|
var LEGACY_DETECTOR_FIELDS = ["displayName", "capabilityID", "defaultEnabled", "timeoutMs"];
|
|
100
|
-
var LEGACY_ACTION_FIELDS = [
|
|
108
|
+
var LEGACY_ACTION_FIELDS = [
|
|
109
|
+
"displayName",
|
|
110
|
+
"actionID",
|
|
111
|
+
"defaultEnabled",
|
|
112
|
+
"defaultOrderKey",
|
|
113
|
+
"revealButtons",
|
|
114
|
+
"supportedItemTypes",
|
|
115
|
+
"inputConstraints",
|
|
116
|
+
"possibleResultKinds"
|
|
117
|
+
];
|
|
101
118
|
function validateLegacyFields(raw, issues) {
|
|
102
119
|
const plugin = asRecord(raw["plugin"]);
|
|
103
120
|
if (plugin && "displayName" in plugin) {
|
|
104
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
121
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: plugin.displayName`));
|
|
105
122
|
}
|
|
106
123
|
const renderers = asRecordArray(raw["attachmentRenderers"]);
|
|
107
124
|
for (let i = 0; i < renderers.length; i++) {
|
|
108
125
|
for (const field of LEGACY_RENDERER_FIELDS) {
|
|
109
126
|
if (field in renderers[i]) {
|
|
110
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
127
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: attachmentRenderers[${i}].${field}`));
|
|
111
128
|
}
|
|
112
129
|
}
|
|
113
130
|
}
|
|
@@ -115,7 +132,7 @@ function validateLegacyFields(raw, issues) {
|
|
|
115
132
|
for (let i = 0; i < detectors.length; i++) {
|
|
116
133
|
for (const field of LEGACY_DETECTOR_FIELDS) {
|
|
117
134
|
if (field in detectors[i]) {
|
|
118
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
135
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: detectors[${i}].${field}`));
|
|
119
136
|
}
|
|
120
137
|
}
|
|
121
138
|
}
|
|
@@ -123,7 +140,7 @@ function validateLegacyFields(raw, issues) {
|
|
|
123
140
|
for (let i = 0; i < actions.length; i++) {
|
|
124
141
|
for (const field of LEGACY_ACTION_FIELDS) {
|
|
125
142
|
if (field in actions[i]) {
|
|
126
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
143
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: actions[${i}].${field}`));
|
|
127
144
|
}
|
|
128
145
|
}
|
|
129
146
|
}
|
|
@@ -139,9 +156,9 @@ function validateCanonicalItemTypeSpellings(raw, issues) {
|
|
|
139
156
|
}
|
|
140
157
|
for (const action of asRecordArray(raw["actions"])) {
|
|
141
158
|
const actionID = asString(action["id"]) ?? "";
|
|
142
|
-
for (const value of asStringArray(action["
|
|
159
|
+
for (const value of asStringArray(action["supportedInputKinds"])) {
|
|
143
160
|
if (!CANONICAL_ITEM_TYPES.includes(value)) {
|
|
144
|
-
issues.push(issue("
|
|
161
|
+
issues.push(issue("actionInvalidSupportedInputKind", `Action supported input kinds contain unsupported value: ${actionID} -> ${value}`));
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
}
|
|
@@ -190,9 +207,9 @@ function validateActions(actions, issues) {
|
|
|
190
207
|
if (title.trim().length === 0) {
|
|
191
208
|
issues.push(issue("actionTitleEmpty", `Action title is empty: ${id}`));
|
|
192
209
|
}
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
issues.push(issue("
|
|
210
|
+
const supportedInputKinds = asStringArray(action["supportedInputKinds"]);
|
|
211
|
+
if (supportedInputKinds.length === 0) {
|
|
212
|
+
issues.push(issue("actionMissingSupportedInputKinds", `Action is missing supported input kinds: ${id}`));
|
|
196
213
|
}
|
|
197
214
|
}
|
|
198
215
|
}
|
|
@@ -240,6 +257,8 @@ function validateManifest(manifest, options = {}) {
|
|
|
240
257
|
const pluginTitle = asString(plugin["title"]) ?? "";
|
|
241
258
|
if (pluginID.trim().length === 0) {
|
|
242
259
|
issues.push(issue("emptyPluginID", "Plugin id is empty"));
|
|
260
|
+
} else if (!isValidPluginID(pluginID)) {
|
|
261
|
+
issues.push(issue("invalidPluginID", `Invalid plugin id: ${pluginID}`));
|
|
243
262
|
}
|
|
244
263
|
if (pluginTitle.trim().length === 0) {
|
|
245
264
|
issues.push(issue("emptyPluginTitle", "Plugin title is empty"));
|
|
@@ -31,10 +31,10 @@ export interface ValidateManifestOptions {
|
|
|
31
31
|
rootDir?: string;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* All
|
|
34
|
+
* All validation error codes, verbatim camelCase mirror of Swift ValidationError cases.
|
|
35
35
|
* Parity with native is enforced by scripts/checks/check-plugin-manifest-validator-parity.sh.
|
|
36
36
|
*/
|
|
37
|
-
export declare const MANIFEST_VALIDATION_CODES: readonly ["unsupportedSchemaVersion", "missingManifest", "missingRuntimeEntry", "missingUIRoot", "legacyFieldNotSupported", "duplicateAttachmentRendererID", "duplicateDetectorID", "duplicateActionID", "emptyPluginID", "emptyPluginTitle", "installEntryMissing", "installEntryOutsideRoot", "rendererTitleEmpty", "detectorTitleEmpty", "actionTitleEmpty", "detectorMissingSupportedInputKinds", "detectorAttachmentTypesEmpty", "detectorAttachmentTypeNotRenderable", "detectorAttachmentTypeOutsideNamespace", "rendererUIEntryMissing", "rendererUIEntryOutsideRoot", "
|
|
37
|
+
export declare const MANIFEST_VALIDATION_CODES: readonly ["unsupportedSchemaVersion", "missingManifest", "missingRuntimeEntry", "missingUIRoot", "legacyFieldNotSupported", "duplicateAttachmentRendererID", "duplicateDetectorID", "duplicateActionID", "emptyPluginID", "invalidPluginID", "emptyPluginTitle", "installEntryMissing", "installEntryOutsideRoot", "rendererTitleEmpty", "detectorTitleEmpty", "actionTitleEmpty", "detectorMissingSupportedInputKinds", "detectorAttachmentTypesEmpty", "detectorAttachmentTypeNotRenderable", "detectorAttachmentTypeOutsideNamespace", "rendererUIEntryMissing", "rendererUIEntryOutsideRoot", "actionMissingSupportedInputKinds", "actionUIEntryMissing", "actionUIEntryOutsideRoot", "detectorInvalidSupportedInputKind", "actionInvalidSupportedInputKind"];
|
|
38
38
|
/**
|
|
39
39
|
* Validate a parsed manifest JSON object against the Clipbus plugin manifest rules.
|
|
40
40
|
*
|
package/dist/validate/index.d.ts
CHANGED
|
@@ -31,10 +31,10 @@ export interface ValidateManifestOptions {
|
|
|
31
31
|
rootDir?: string;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* All
|
|
34
|
+
* All validation error codes, verbatim camelCase mirror of Swift ValidationError cases.
|
|
35
35
|
* Parity with native is enforced by scripts/checks/check-plugin-manifest-validator-parity.sh.
|
|
36
36
|
*/
|
|
37
|
-
export declare const MANIFEST_VALIDATION_CODES: readonly ["unsupportedSchemaVersion", "missingManifest", "missingRuntimeEntry", "missingUIRoot", "legacyFieldNotSupported", "duplicateAttachmentRendererID", "duplicateDetectorID", "duplicateActionID", "emptyPluginID", "emptyPluginTitle", "installEntryMissing", "installEntryOutsideRoot", "rendererTitleEmpty", "detectorTitleEmpty", "actionTitleEmpty", "detectorMissingSupportedInputKinds", "detectorAttachmentTypesEmpty", "detectorAttachmentTypeNotRenderable", "detectorAttachmentTypeOutsideNamespace", "rendererUIEntryMissing", "rendererUIEntryOutsideRoot", "
|
|
37
|
+
export declare const MANIFEST_VALIDATION_CODES: readonly ["unsupportedSchemaVersion", "missingManifest", "missingRuntimeEntry", "missingUIRoot", "legacyFieldNotSupported", "duplicateAttachmentRendererID", "duplicateDetectorID", "duplicateActionID", "emptyPluginID", "invalidPluginID", "emptyPluginTitle", "installEntryMissing", "installEntryOutsideRoot", "rendererTitleEmpty", "detectorTitleEmpty", "actionTitleEmpty", "detectorMissingSupportedInputKinds", "detectorAttachmentTypesEmpty", "detectorAttachmentTypeNotRenderable", "detectorAttachmentTypeOutsideNamespace", "rendererUIEntryMissing", "rendererUIEntryOutsideRoot", "actionMissingSupportedInputKinds", "actionUIEntryMissing", "actionUIEntryOutsideRoot", "detectorInvalidSupportedInputKind", "actionInvalidSupportedInputKind"];
|
|
38
38
|
/**
|
|
39
39
|
* Validate a parsed manifest JSON object against the Clipbus plugin manifest rules.
|
|
40
40
|
*
|
package/dist/validate/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var MANIFEST_VALIDATION_CODES = [
|
|
|
11
11
|
"duplicateDetectorID",
|
|
12
12
|
"duplicateActionID",
|
|
13
13
|
"emptyPluginID",
|
|
14
|
+
"invalidPluginID",
|
|
14
15
|
"emptyPluginTitle",
|
|
15
16
|
"installEntryMissing",
|
|
16
17
|
"installEntryOutsideRoot",
|
|
@@ -23,11 +24,11 @@ var MANIFEST_VALIDATION_CODES = [
|
|
|
23
24
|
"detectorAttachmentTypeOutsideNamespace",
|
|
24
25
|
"rendererUIEntryMissing",
|
|
25
26
|
"rendererUIEntryOutsideRoot",
|
|
26
|
-
"
|
|
27
|
+
"actionMissingSupportedInputKinds",
|
|
27
28
|
"actionUIEntryMissing",
|
|
28
29
|
"actionUIEntryOutsideRoot",
|
|
29
30
|
"detectorInvalidSupportedInputKind",
|
|
30
|
-
"
|
|
31
|
+
"actionInvalidSupportedInputKind"
|
|
31
32
|
];
|
|
32
33
|
var CANONICAL_ITEM_TYPES = ["text", "image", "path_reference"];
|
|
33
34
|
function asRecord(val) {
|
|
@@ -54,25 +55,41 @@ function isInsideRoot(entryRelative, rootAbsolute) {
|
|
|
54
55
|
const resolvedEntry = path.resolve(rootAbsolute, entryRelative);
|
|
55
56
|
return resolvedEntry === rootAbsolute || resolvedEntry.startsWith(rootAbsolute + path.sep);
|
|
56
57
|
}
|
|
58
|
+
var PLUGIN_ID_MAX_LENGTH = 128;
|
|
59
|
+
var PLUGIN_ID_PATTERN = /^[a-z0-9._-]+$/;
|
|
60
|
+
function isValidPluginID(id) {
|
|
61
|
+
if (id.length === 0 || id.length > PLUGIN_ID_MAX_LENGTH) return false;
|
|
62
|
+
if (id.startsWith(".") || id.includes("..")) return false;
|
|
63
|
+
return PLUGIN_ID_PATTERN.test(id);
|
|
64
|
+
}
|
|
57
65
|
function validateSchemaVersion(raw, issues) {
|
|
58
66
|
const version = typeof raw["schemaVersion"] === "number" ? raw["schemaVersion"] : 0;
|
|
59
|
-
if (version !==
|
|
67
|
+
if (version !== 3) {
|
|
60
68
|
issues.push(issue("unsupportedSchemaVersion", `Unsupported plugin schema version: ${version}`));
|
|
61
69
|
}
|
|
62
70
|
}
|
|
63
71
|
var LEGACY_RENDERER_FIELDS = ["displayName", "defaultEnabled", "defaultOrderKey", "actions"];
|
|
64
72
|
var LEGACY_DETECTOR_FIELDS = ["displayName", "capabilityID", "defaultEnabled", "timeoutMs"];
|
|
65
|
-
var LEGACY_ACTION_FIELDS = [
|
|
73
|
+
var LEGACY_ACTION_FIELDS = [
|
|
74
|
+
"displayName",
|
|
75
|
+
"actionID",
|
|
76
|
+
"defaultEnabled",
|
|
77
|
+
"defaultOrderKey",
|
|
78
|
+
"revealButtons",
|
|
79
|
+
"supportedItemTypes",
|
|
80
|
+
"inputConstraints",
|
|
81
|
+
"possibleResultKinds"
|
|
82
|
+
];
|
|
66
83
|
function validateLegacyFields(raw, issues) {
|
|
67
84
|
const plugin = asRecord(raw["plugin"]);
|
|
68
85
|
if (plugin && "displayName" in plugin) {
|
|
69
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
86
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: plugin.displayName`));
|
|
70
87
|
}
|
|
71
88
|
const renderers = asRecordArray(raw["attachmentRenderers"]);
|
|
72
89
|
for (let i = 0; i < renderers.length; i++) {
|
|
73
90
|
for (const field of LEGACY_RENDERER_FIELDS) {
|
|
74
91
|
if (field in renderers[i]) {
|
|
75
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
92
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: attachmentRenderers[${i}].${field}`));
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
95
|
}
|
|
@@ -80,7 +97,7 @@ function validateLegacyFields(raw, issues) {
|
|
|
80
97
|
for (let i = 0; i < detectors.length; i++) {
|
|
81
98
|
for (const field of LEGACY_DETECTOR_FIELDS) {
|
|
82
99
|
if (field in detectors[i]) {
|
|
83
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
100
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: detectors[${i}].${field}`));
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
103
|
}
|
|
@@ -88,7 +105,7 @@ function validateLegacyFields(raw, issues) {
|
|
|
88
105
|
for (let i = 0; i < actions.length; i++) {
|
|
89
106
|
for (const field of LEGACY_ACTION_FIELDS) {
|
|
90
107
|
if (field in actions[i]) {
|
|
91
|
-
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in
|
|
108
|
+
issues.push(issue("legacyFieldNotSupported", `Legacy manifest field is not supported in v3: actions[${i}].${field}`));
|
|
92
109
|
}
|
|
93
110
|
}
|
|
94
111
|
}
|
|
@@ -104,9 +121,9 @@ function validateCanonicalItemTypeSpellings(raw, issues) {
|
|
|
104
121
|
}
|
|
105
122
|
for (const action of asRecordArray(raw["actions"])) {
|
|
106
123
|
const actionID = asString(action["id"]) ?? "";
|
|
107
|
-
for (const value of asStringArray(action["
|
|
124
|
+
for (const value of asStringArray(action["supportedInputKinds"])) {
|
|
108
125
|
if (!CANONICAL_ITEM_TYPES.includes(value)) {
|
|
109
|
-
issues.push(issue("
|
|
126
|
+
issues.push(issue("actionInvalidSupportedInputKind", `Action supported input kinds contain unsupported value: ${actionID} -> ${value}`));
|
|
110
127
|
}
|
|
111
128
|
}
|
|
112
129
|
}
|
|
@@ -155,9 +172,9 @@ function validateActions(actions, issues) {
|
|
|
155
172
|
if (title.trim().length === 0) {
|
|
156
173
|
issues.push(issue("actionTitleEmpty", `Action title is empty: ${id}`));
|
|
157
174
|
}
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
160
|
-
issues.push(issue("
|
|
175
|
+
const supportedInputKinds = asStringArray(action["supportedInputKinds"]);
|
|
176
|
+
if (supportedInputKinds.length === 0) {
|
|
177
|
+
issues.push(issue("actionMissingSupportedInputKinds", `Action is missing supported input kinds: ${id}`));
|
|
161
178
|
}
|
|
162
179
|
}
|
|
163
180
|
}
|
|
@@ -205,6 +222,8 @@ function validateManifest(manifest, options = {}) {
|
|
|
205
222
|
const pluginTitle = asString(plugin["title"]) ?? "";
|
|
206
223
|
if (pluginID.trim().length === 0) {
|
|
207
224
|
issues.push(issue("emptyPluginID", "Plugin id is empty"));
|
|
225
|
+
} else if (!isValidPluginID(pluginID)) {
|
|
226
|
+
issues.push(issue("invalidPluginID", `Invalid plugin id: ${pluginID}`));
|
|
208
227
|
}
|
|
209
228
|
if (pluginTitle.trim().length === 0) {
|
|
210
229
|
issues.push(issue("emptyPluginTitle", "Plugin title is empty"));
|
package/docs/authoring.md
CHANGED
|
@@ -156,9 +156,9 @@ UI 端完整 topic/verb 列表见 [API.md](../API.md)。
|
|
|
156
156
|
### resolveSession 入参
|
|
157
157
|
|
|
158
158
|
```ts
|
|
159
|
-
input.
|
|
159
|
+
input.sourceItem // 原始 PluginClipboardItem 身份
|
|
160
160
|
input.content // PluginContentEnvelope
|
|
161
|
-
input.attachments //
|
|
161
|
+
input.attachments // SDK 0.9.0 中 Action 当前固定为 []
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
### resolveSession 返回值
|
|
@@ -179,11 +179,16 @@ return {
|
|
|
179
179
|
### runAutoAction 入参
|
|
180
180
|
|
|
181
181
|
```ts
|
|
182
|
-
input.
|
|
182
|
+
input.sourceItem // 原始 PluginClipboardItem 身份
|
|
183
183
|
input.content // PluginContentEnvelope
|
|
184
|
-
input.attachments //
|
|
184
|
+
input.attachments // SDK 0.9.0 中 Action 当前固定为 []
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
+
`sourceItem` 始终指向打开 Action Panel 时的原始 item;`content` 是当前
|
|
188
|
+
级联值,可能已经从 text 变成 image 或 path_reference。Action 的适用性
|
|
189
|
+
和处理逻辑必须以 `content.kind` 为准,item mutation 仍作用于
|
|
190
|
+
`sourceItem.id`。
|
|
191
|
+
|
|
187
192
|
### runAutoAction 返回值(用 `actionResult`)
|
|
188
193
|
|
|
189
194
|
```ts
|
|
@@ -196,6 +201,12 @@ actionResult.text('hello world', { userMessage: 'Copied' });
|
|
|
196
201
|
// image 结果(注意:第一个参数是 imageTempPath 字符串,不是对象)
|
|
197
202
|
actionResult.image(imageTempPath, { imageFormatHint: 'png', userMessage: 'Saved' });
|
|
198
203
|
|
|
204
|
+
// path_reference:复用当前输入,或返回 host 分配的文件
|
|
205
|
+
actionResult.path_reference([
|
|
206
|
+
{ source: 'input', inputIndex: 0 },
|
|
207
|
+
{ source: 'allocated_file', path: outputPath, displayName: 'result.txt' },
|
|
208
|
+
]);
|
|
209
|
+
|
|
199
210
|
// 仅副作用,无输出
|
|
200
211
|
actionResult.none({ userMessage: 'Applied' });
|
|
201
212
|
```
|
|
@@ -205,6 +216,7 @@ actionResult.none({ userMessage: 'Applied' });
|
|
|
205
216
|
```ts
|
|
206
217
|
actionResult.text(text: string, options?: { userMessage?: string })
|
|
207
218
|
actionResult.image(imageTempPath: string, options?: { imageFormatHint?: string; userMessage?: string })
|
|
219
|
+
actionResult.path_reference(entries: PluginActionPathResultEntry[], options?: { userMessage?: string })
|
|
208
220
|
actionResult.none(options?: { userMessage?: string })
|
|
209
221
|
```
|
|
210
222
|
|
|
@@ -221,6 +233,9 @@ interface MyDraft { subject: string; note: string; }
|
|
|
221
233
|
const initial = clipbus.action.draft.current() as MyDraft | undefined;
|
|
222
234
|
const form = reactive({ subject: initial?.subject ?? '', note: initial?.note ?? '' });
|
|
223
235
|
|
|
236
|
+
// 当前级联输入;path_reference 只含 kind/displayName,不暴露 path
|
|
237
|
+
const currentInput = clipbus.action.input.current();
|
|
238
|
+
|
|
224
239
|
// 订阅 host 推送的后续更新(罕见;通常 initialDraft 之后就由 UI 接管)
|
|
225
240
|
clipbus.action.draft.on(next => {
|
|
226
241
|
Object.assign(form, next);
|
|
@@ -247,6 +262,9 @@ async function handleApply() {
|
|
|
247
262
|
}
|
|
248
263
|
```
|
|
249
264
|
|
|
265
|
+
Draft 完成后宿主展示结果供复制或关闭,但不会把结果移交到下一个 Action;
|
|
266
|
+
只有 auto-run Action 的非 `none` 成功结果可以继续级联。
|
|
267
|
+
|
|
250
268
|
### Draft Action:UI 需要 runtime 协助时
|
|
251
269
|
|
|
252
270
|
`clipbus.action.complete` 接收 `{result: {resultKind: 'text' | 'image' | 'none', …}}`。**image 结果的 `imageTempPath` 必须由 runtime 端通过 `host.action.allocateImageTempPath` 分配**(UI 端没有这个能力),所以图片类 draft 的典型流程是:
|
|
@@ -285,4 +303,16 @@ async function handleApplyImage(prompt: string) {
|
|
|
285
303
|
|
|
286
304
|
> **不要**尝试通过 `runtime.invoke` 把图片字节传回 UI。postMessage 经 base64 + JSON 双重序列化,几 MB 图片就会卡顿数百 ms。让 runtime 直接写文件、只把路径返回给 UI。
|
|
287
305
|
|
|
306
|
+
### Action 当前图片与安全文件结果
|
|
307
|
+
|
|
308
|
+
读取当前 Action 图片使用 `ctx.host.action.materializeInputImagePath()`,不要
|
|
309
|
+
用 `ctx.host.item.materializeImagePath()`:后者读取原始 item 图片,而级联
|
|
310
|
+
后的当前值可能来自上一步 Action。
|
|
311
|
+
|
|
312
|
+
普通文件结果必须先调用
|
|
313
|
+
`ctx.host.action.allocateOutputFilePath({suggestedName})`,写入返回路径,再
|
|
314
|
+
通过 `{source: 'allocated_file', path, displayName}` 返回。若只是保留当前
|
|
315
|
+
path_reference 的某一项,使用 `{source: 'input', inputIndex}`。任意绝对
|
|
316
|
+
路径不会被宿主接受。
|
|
317
|
+
|
|
288
318
|
RPC 机制(`defineMessage` / `messageHandlers`)的完整说明见 [rpc.md](./rpc.md)。入参结构(`PluginContentEnvelope`、`PluginClipboardItem`)详见 [item-context.md](./item-context.md)。
|
|
@@ -60,7 +60,7 @@ import type { PluginActionHandler } from '@clipbus/plugin-sdk/runtime';
|
|
|
60
60
|
const action: PluginActionHandler = {
|
|
61
61
|
async runAutoAction(input, ctx) {
|
|
62
62
|
if (ctx.host.capabilities.has('item.setTags')) {
|
|
63
|
-
await ctx.host.item.setTags({
|
|
63
|
+
await ctx.host.item.setTags({ tags: ['processed'] });
|
|
64
64
|
}
|
|
65
65
|
// 不支持时跳过,不报错
|
|
66
66
|
},
|
|
@@ -73,7 +73,7 @@ Node 侧错误来自**跨进程 IPC**,抛出的是反序列化的普通对象
|
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
75
|
try {
|
|
76
|
-
await ctx.host.item.setTags({
|
|
76
|
+
await ctx.host.item.setTags({ tags: ['processed'] });
|
|
77
77
|
} catch (err: unknown) {
|
|
78
78
|
const e = err as { name?: string; data?: { capability?: string } };
|
|
79
79
|
if (e.name === 'PluginCapabilityUnsupported') {
|
package/docs/entry.md
CHANGED
|
@@ -34,10 +34,10 @@ import { PluginContextError } from '@clipbus/plugin-sdk/ui';
|
|
|
34
34
|
| Namespace | 形态 | 说明 |
|
|
35
35
|
|---|---|---|
|
|
36
36
|
| `clipbus.item` | Topic | `current()`, `on()`, `readAttachment()`,子 OptionalTopic `clipbus.item.attachment` |
|
|
37
|
-
| `clipbus.asset` | Verb | `currentItemImageUrl()
|
|
37
|
+
| `clipbus.asset` | Verb | renderer 使用 `currentItemImageUrl()` / `pathReferenceImageUrl({index})`;Action 使用 `currentActionInputImageUrl()` / `currentActionInputPathReferenceImageUrl({index})`。均返回不透明 `clipbus-asset://` URL |
|
|
38
38
|
| `clipbus.theme` | Topic | `current()`, `on()` |
|
|
39
39
|
| `clipbus.pluginContext` | Topic | `current()`, `on()`,返回 `{mode, pluginID}` |
|
|
40
|
-
| `clipbus.action` | Verb +
|
|
40
|
+
| `clipbus.action` | Verb + Topic | action 上下文专属;`setButtons`、`complete`、`draft`、`input`、`onHostInvoke` |
|
|
41
41
|
| `clipbus.attachmentRenderer` | Verb + Stream | attachment 上下文专属;`setButtons`、`onHostInvoke` |
|
|
42
42
|
| `clipbus.window` | Verb | `setHeight`, `autoFit` |
|
|
43
43
|
| `clipbus.clipboard` | Verb | `copyText` |
|