@medeo-plugin/sdk 0.0.0-stage → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ export { installStyles, uiStyles } from './ui/styles.js';
2
+ export interface Identified {
3
+ testid: string;
4
+ }
5
+ export interface CardOptions extends Identified {
6
+ title: string;
7
+ description?: string;
8
+ }
9
+ export interface PillOptions extends Identified {
10
+ label: string;
11
+ tone?: 'neutral' | 'info' | 'error';
12
+ }
13
+ export interface ToggleOptions extends Identified {
14
+ label: string;
15
+ checked: boolean;
16
+ disabled?: boolean;
17
+ onChange: (checked: boolean) => void;
18
+ }
19
+ export interface Segment<T extends string = string> {
20
+ value: T;
21
+ label: string;
22
+ disabled?: boolean;
23
+ }
24
+ export interface SegmentedOptions<T extends string = string> extends Identified {
25
+ label: string;
26
+ options: readonly Segment<T>[];
27
+ value: T;
28
+ disabled?: boolean;
29
+ onChange: (value: T) => void;
30
+ }
31
+ export interface ListOptions extends Identified {
32
+ label: string;
33
+ }
34
+ export type Child = Node | string | number | null | undefined | false;
35
+ export declare function card(options: CardOptions, ...children: Child[]): HTMLElement;
36
+ export declare function pill(options: PillOptions): HTMLSpanElement;
37
+ /** Native checkbox keyboard behavior (Space), with switch semantics. */
38
+ export declare function toggle(options: ToggleOptions): HTMLLabelElement & {
39
+ input: HTMLInputElement;
40
+ };
41
+ /** Shared radio keyboard navigation; disabled choices are skipped, edges wrap. */
42
+ export declare function segmentTarget<T extends string>(options: readonly Segment<T>[], index: number, key: string, rtl?: boolean): number | undefined;
43
+ export declare function segmentTabIndex<T extends string>(options: readonly Segment<T>[], value: T, index: number): number;
44
+ export declare function segmented<T extends string>(options: SegmentedOptions<T>): HTMLDivElement & {
45
+ setValue(value: T): void;
46
+ setDisabled(disabled: boolean): void;
47
+ };
48
+ /** Each child becomes one semantic list item; caller owns empty-state wording. */
49
+ export declare function list(options: ListOptions, ...items: Child[]): HTMLUListElement;
50
+ export declare function emptyState(options: CardOptions): HTMLElement;
package/dist/ui.js ADDED
@@ -0,0 +1,115 @@
1
+ export { installStyles, uiStyles } from './ui/styles.js';
2
+ function node(tag, className, testid, text) {
3
+ const el = document.createElement(tag);
4
+ el.className = className;
5
+ if (testid !== undefined)
6
+ el.dataset.testid = testid;
7
+ if (text !== undefined)
8
+ el.textContent = text;
9
+ return el;
10
+ }
11
+ function append(el, children) {
12
+ for (const child of children)
13
+ if (child !== null && child !== undefined && child !== false)
14
+ el.append(typeof child === 'number' ? String(child) : child);
15
+ }
16
+ export function card(options, ...children) {
17
+ const root = node('section', 'medeo-ui medeo-card', options.testid);
18
+ root.setAttribute('aria-label', options.title);
19
+ root.append(node('h2', '', `${options.testid}.title`, options.title));
20
+ if (options.description !== undefined)
21
+ root.append(node('p', 'medeo-description', undefined, options.description));
22
+ append(root, children);
23
+ return root;
24
+ }
25
+ export function pill(options) {
26
+ const root = node('span', 'medeo-ui medeo-pill', options.testid, options.label);
27
+ root.dataset.tone = options.tone ?? 'info';
28
+ return root;
29
+ }
30
+ /** Native checkbox keyboard behavior (Space), with switch semantics. */
31
+ export function toggle(options) {
32
+ const root = node('label', 'medeo-ui medeo-toggle', `${options.testid}.root`);
33
+ const input = node('input', '', options.testid);
34
+ input.type = 'checkbox';
35
+ input.setAttribute('role', 'switch');
36
+ input.checked = options.checked;
37
+ input.disabled = options.disabled ?? false;
38
+ input.addEventListener('change', () => options.onChange(input.checked));
39
+ root.append(input, node('span', '', undefined, options.label));
40
+ return Object.assign(root, { input });
41
+ }
42
+ /** Shared radio keyboard navigation; disabled choices are skipped, edges wrap. */
43
+ export function segmentTarget(options, index, key, rtl = false) {
44
+ const enabled = options.map((o, i) => o.disabled ? -1 : i).filter(i => i >= 0);
45
+ if (!enabled.length)
46
+ return undefined;
47
+ if (key === 'Home')
48
+ return enabled[0];
49
+ if (key === 'End')
50
+ return enabled[enabled.length - 1];
51
+ let direction = key === 'ArrowDown' ? 1 : key === 'ArrowUp' ? -1 : key === 'ArrowRight' ? (rtl ? -1 : 1) : key === 'ArrowLeft' ? (rtl ? 1 : -1) : 0;
52
+ if (!direction)
53
+ return undefined;
54
+ return enabled[(enabled.indexOf(index) + direction + enabled.length) % enabled.length];
55
+ }
56
+ export function segmentTabIndex(options, value, index) {
57
+ let active = options.findIndex(o => o.value === value && !o.disabled);
58
+ if (active < 0)
59
+ active = options.findIndex(o => !o.disabled);
60
+ return index === active ? 0 : -1;
61
+ }
62
+ export function segmented(options) {
63
+ const root = node('div', 'medeo-ui medeo-segmented', options.testid);
64
+ root.setAttribute('role', 'radiogroup');
65
+ root.setAttribute('aria-label', options.label);
66
+ let value = options.value, disabled = options.disabled ?? false;
67
+ const buttons = options.options.map((option, index) => {
68
+ const button = node('button', '', `${options.testid}.${index}`, option.label);
69
+ button.type = 'button';
70
+ button.setAttribute('role', 'radio');
71
+ button.addEventListener('click', () => {
72
+ if (disabled || option.disabled)
73
+ return;
74
+ value = option.value;
75
+ render();
76
+ options.onChange(value);
77
+ });
78
+ button.addEventListener('keydown', event => {
79
+ if (disabled)
80
+ return;
81
+ const target = segmentTarget(options.options, index, event.key, getComputedStyle(root).direction === 'rtl');
82
+ if (target === undefined)
83
+ return;
84
+ event.preventDefault();
85
+ buttons[target].focus();
86
+ buttons[target].click();
87
+ });
88
+ return button;
89
+ });
90
+ function render() {
91
+ buttons.forEach((button, index) => {
92
+ button.disabled = disabled || !!options.options[index].disabled;
93
+ button.tabIndex = disabled ? -1 : segmentTabIndex(options.options, value, index);
94
+ button.setAttribute('aria-checked', String(options.options[index].value === value));
95
+ });
96
+ }
97
+ root.append(...buttons);
98
+ render();
99
+ return Object.assign(root, { setValue(next) { value = next; render(); }, setDisabled(next) { disabled = next; render(); } });
100
+ }
101
+ /** Each child becomes one semantic list item; caller owns empty-state wording. */
102
+ export function list(options, ...items) {
103
+ const root = node('ul', 'medeo-ui medeo-list', options.testid);
104
+ root.setAttribute('aria-label', options.label);
105
+ items.forEach((item, index) => { const li = node('li', '', `${options.testid}.${index}`); append(li, [item]); root.append(li); });
106
+ return root;
107
+ }
108
+ export function emptyState(options) {
109
+ const root = node('section', 'medeo-ui medeo-empty', options.testid);
110
+ root.setAttribute('aria-label', options.title);
111
+ root.append(node('h2', '', undefined, options.title));
112
+ if (options.description !== undefined)
113
+ root.append(node('p', 'medeo-description', undefined, options.description));
114
+ return root;
115
+ }
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@medeo-plugin/sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.8.0",
4
+ "description": "TypeScript SDK for Medeo desktop plugins: one import for the sandboxed worker, its windows and Node plugins.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/one2x-ai/medeo-desktop-plugin-sdk.git",
9
+ "directory": "packages/plugin-sdk"
10
+ },
11
+ "homepage": "https://github.com/one2x-ai/medeo-desktop-plugin-sdk#readme",
12
+ "keywords": [
13
+ "medeo",
14
+ "plugin",
15
+ "sdk"
16
+ ],
17
+ "type": "module",
18
+ "sideEffects": false,
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./rpc": {
26
+ "types": "./dist/rpc.d.ts",
27
+ "import": "./dist/rpc.js",
28
+ "default": "./dist/rpc.js"
29
+ },
30
+ "./testing": {
31
+ "types": "./dist/testing.d.ts",
32
+ "import": "./dist/testing.js",
33
+ "default": "./dist/testing.js"
34
+ },
35
+ "./ui": {
36
+ "types": "./dist/ui.d.ts",
37
+ "import": "./dist/ui.js",
38
+ "default": "./dist/ui.js"
39
+ },
40
+ "./ui/react": {
41
+ "types": "./dist/react.d.ts",
42
+ "import": "./dist/react.js",
43
+ "default": "./dist/react.js"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "types": "./dist/index.d.ts",
48
+ "files": [
49
+ "dist",
50
+ "src",
51
+ "README.md"
52
+ ],
53
+ "scripts": {
54
+ "build": "tsc -p tsconfig.build.json",
55
+ "prepack": "npm run build"
56
+ },
57
+ "peerDependencies": {
58
+ "react": "^18.0.0 || ^19.0.0"
59
+ },
60
+ "peerDependenciesMeta": {
61
+ "react": {
62
+ "optional": true
63
+ }
64
+ },
65
+ "engines": {
66
+ "node": ">=22"
67
+ }
68
+ }
@@ -0,0 +1,158 @@
1
+ // Generated by platform-contract; do not edit.
2
+ export type JsonValue = number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null;
3
+ export type Permission = "storage" | "creation_open" | { "file_access": Array<string> } | { "file_full_access": Array<string> } | { "network": Array<string> } | "agent_api" | "clipboard_read" | "clipboard_write" | "screen_capture" | "camera" | "microphone" | "system_audio" | "applications" | "global_shortcuts" | "notifications" | "tray" | "app_windows" | "accessibility" | "input_method" | { "external_open": Array<string> } | { "browser_view": Array<string> } | "system_info" | "secrets" | "background_tasks" | "power" | { "process_spawn": Array<string> } | "local_server" | "printing" | "contacts" | "calendar" | "location" | "device_access" | { "approvals": Array<string> } | "node";
4
+ export type PluginCommand = { id: string, title: string, };
5
+ export type PluginLocalization = { default_locale: string, catalogs: { [key in string]?: string }, };
6
+ export type Runtime = "sandbox" | "node";
7
+ export type GrantScope = "once" | "run" | "always";
8
+ export type ApprovalRule = { action: string,
9
+ /**
10
+ * The rule key, or a prefix ending in `*`.
11
+ */
12
+ pattern: string, allow: boolean,
13
+ /**
14
+ * `run` rules belong to the running instance; `always` rules are stored.
15
+ */
16
+ scope: GrantScope, };
17
+ export type ApprovalRecord = { action: string, rule_key: string,
18
+ /**
19
+ * `allow` or `deny`.
20
+ */
21
+ decision: string,
22
+ /**
23
+ * `once`, `run`, `always`, or `rule` when a remembered rule decided.
24
+ */
25
+ scope: string, time_ms: number, };
26
+ export type TargetPlatform = "macos" | "windows";
27
+ export type Engines = { medeo?: string, };
28
+ export type InstallSourceKind = "file" | "folder" | "github" | "npm" | "dev";
29
+ export type InstallSource = { kind: InstallSourceKind,
30
+ /**
31
+ * A file path, folder path, `owner/repo[#tag-prefix]` or npm package name.
32
+ */
33
+ locator: string,
34
+ /**
35
+ * The release tag or npm version the package was taken from.
36
+ */
37
+ version?: string, };
38
+ export type ConfigType = "string" | "number" | "boolean";
39
+ export type ConfigProperty = { type: ConfigType, default: JsonValue, title: string, description?: string,
40
+ /**
41
+ * Allowed values; the plugin center shows a choice.
42
+ */
43
+ enum?: Array<JsonValue>, };
44
+ export type Configuration = { properties: { [key in string]?: ConfigProperty }, };
45
+ export type Keybinding = { command: string, key: string, };
46
+ export type Menus = {
47
+ /**
48
+ * Command ids shown in the main window's Plugins menu.
49
+ */
50
+ app?: Array<string>, };
51
+ export type Contributes = { configuration?: Configuration, keybindings?: Array<Keybinding>, menus?: Menus, };
52
+ export type Manifest = { localization?: PluginLocalization, id: string, name: string,
53
+ /**
54
+ * One sentence the plugin center shows under the name; translated as
55
+ * `plugin.description` in the plugin's catalogs.
56
+ */
57
+ description?: string,
58
+ /**
59
+ * The plugin's icon, at the package root: `icon.svg` or `icon.png`.
60
+ */
61
+ icon?: string, version: string, api_version: number, worker: string, ui: string | null, permissions: Array<Permission>, commands: Array<PluginCommand>, runtime?: Runtime,
62
+ /**
63
+ * When Medeo starts the plugin: `onStartup`, `onCommand:<id>`,
64
+ * `onSchedule`, `onShortcut`. Without any, it starts when used.
65
+ */
66
+ activation_events?: Array<string>, contributes?: Contributes,
67
+ /**
68
+ * Operating systems the plugin runs on; empty means all.
69
+ */
70
+ platforms?: Array<TargetPlatform>,
71
+ /**
72
+ * The Medeo versions the plugin needs; absent means any that loads format 2.
73
+ */
74
+ engines?: Engines, };
75
+ export type PackageFile = { size: number, sha256: string, };
76
+ export type PackageIndex = { manifest: Manifest, files: { [key in string]?: PackageFile }, };
77
+ export type Asset = { mime: string, path: string, size: number, sha256: string, };
78
+ export type PackageSignature = { format: number, public_key: string, signature: string, index: string, };
79
+ export type PackageInfo = { manifest: Manifest, digest: string, publisher: string,
80
+ /**
81
+ * Bytes of all signed files, i.e. the installed size. Records written
82
+ * before this field existed are backfilled at start.
83
+ */
84
+ size: number,
85
+ /**
86
+ * What this build accepted but does not understand (`unknown_contribution:<key>`);
87
+ * shown at install and in the developer log, never a reason to refuse.
88
+ */
89
+ warnings?: Array<string>, };
90
+ export type CapabilityDescriptor = { permission: string, group: string, version: number, scoped: boolean, methods: Array<string>, available_methods: Array<string>, granted: boolean, declared: boolean, os_authorization: string, };
91
+ export type DirectoryGrant = { id: string, name: string, available: boolean,
92
+ /**
93
+ * Full access: view and move to the Trash without a Host confirmation.
94
+ */
95
+ full: boolean, };
96
+ export type NetworkOrigin = { origin: string, declared: boolean, allowed: boolean, };
97
+ export type InstalledPlugin = { localization: JsonValue, id: string, active: string | null, versions: Array<PackageInfo>, grants: Array<Permission>, directories: Array<DirectoryGrant>, network_origins: Array<NetworkOrigin>,
98
+ /**
99
+ * For resident (`onStartup`) plugins: whether the user lets it run in
100
+ * the background. Other plugins run only while in use and ignore it.
101
+ */
102
+ enabled: boolean, resident: boolean,
103
+ /**
104
+ * User-owned macOS Dock launcher preference; plugins cannot modify it.
105
+ */
106
+ dock: boolean,
107
+ /**
108
+ * User-owned: whether the plugin's menu-bar icon (`tray`) is shown; plugins cannot modify it.
109
+ */
110
+ menu_bar: boolean, instance: string | null,
111
+ /**
112
+ * Permission ids granted to the running instance only (`run` scope).
113
+ */
114
+ session_grants: Array<string>,
115
+ /**
116
+ * Permission ids the user refused with "don't ask again".
117
+ */
118
+ denied: Array<string>,
119
+ /**
120
+ * Remembered `approvals.request` answers.
121
+ */
122
+ approval_rules: Array<ApprovalRule>,
123
+ /**
124
+ * The active version's icon as a `data:` URL, when the package has one.
125
+ */
126
+ icon?: string,
127
+ /**
128
+ * Where the plugin was installed from, when Main recorded it.
129
+ */
130
+ source?: InstallSource, };
131
+ export type Instance = { id: string, plugin_id: string, digest: string, manifest: Manifest, };
132
+ export type Task = { id: string, plugin_id: string, instance: string, command: string, status: string, result: JsonValue | null,
133
+ /**
134
+ * Unix milliseconds; absent for rows written before times were recorded.
135
+ */
136
+ created_ms: number | null, finished_ms: number | null, };
137
+ export type Snapshot = { protocol: number, plugins: Array<InstalledPlugin>, tasks: Array<Task>, };
138
+ export type HostEvent = { "type": "operation", instance: string, id: string, method: string, status: string, revision?: number, } | { "type": "signal", instance: string, channel: string, } | { "type": "wake", plugin_id: string, };
139
+ export type Command = { "op": "ping" } | { "op": "shortcuts_list" } | { "op": "shortcut_validate", target: string, accelerator: string, } | { "op": "shortcut_save", target: string, accelerator: string, } | { "op": "shortcut_remove", target: string, } | { "op": "system_locale", locale: string, } | { "op": "plugin_locale", plugin_id: string, locale: string, } | { "op": "approve", instance: string, ticket: string, approved: boolean,
140
+ /**
141
+ * Without it an approval is stored (`always`) and a refusal asks again next time.
142
+ */
143
+ scope?: GrantScope, } | { "op": "capture_stop", id: string, } | { "op": "capture_asset", instance: string, id: string, } | { "op": "media_asset", instance: string, id: string, } | { "op": "agent_settings" } | { "op": "agent_configure", endpoint: string, model: string, encrypted_key: string | null, key: string, persist: boolean, } | { "op": "agent_remove" } | { "op": "agent_test", action: string, id: string | null, } | { "op": "snapshot" } | { "op": "capability_catalog" } | { "op": "grant_permission", plugin_id: string, digest: string, permission: string, } | { "op": "forget_approval_rule", plugin_id: string, action: string, pattern: string, } | { "op": "approval_log", plugin_id: string, } | { "op": "revoke_permission", plugin_id: string, permission: string, } | { "op": "network_origin_revoke", plugin_id: string, origin: string, } | { "op": "configure_capabilities", methods: Array<string>, } | { "op": "capability_result", instance: string, ticket: string, result: JsonValue | null, error: string | null, } | { "op": "quiesce", plugin_id: string, } | { "op": "resource_grant", instance: string, directories: Array<string>, full: boolean, } | { "op": "resource_revoke", plugin_id: string, grant_id: string, } | { "op": "inspect", package_file: string, } | { "op": "install", package_file: string, digest: string, grants: Array<Permission>,
144
+ /**
145
+ * Recorded with the plugin (plugin center "Source"); absent for older callers.
146
+ */
147
+ source?: InstallSource, } | { "op": "pack_dir", directory: string, key_file: string, output: string,
148
+ /**
149
+ * Stamp a content-derived `-dev.h<hash>` version like the toolchain's `dev` does.
150
+ */
151
+ development: boolean, } | { "op": "prepare", plugin_id: string, digest: string, } | { "op": "commit", instance: string, } | { "op": "abort", instance: string, } | { "op": "stop", plugin_id: string, } | { "op": "busy", plugin_id: string, } | { "op": "deactivate", plugin_id: string, } | { "op": "dock_set", plugin_id: string, enabled: boolean, } | { "op": "menu_bar_set", plugin_id: string, enabled: boolean, } | { "op": "keep_running", plugin_id: string, enabled: boolean, } | { "op": "uninstall", plugin_id: string, } | { "op": "config_state", plugin_id: string, } | { "op": "config_set", plugin_id: string, key: string, value: JsonValue, } | { "op": "package_dir", instance: string, } | { "op": "remove_version", plugin_id: string, digest: string, } | { "op": "grants", plugin_id: string, grants: Array<Permission>, } | { "op": "asset", instance: string, path: string, } | { "op": "invoke", instance: string, method: string, args: JsonValue,
152
+ /**
153
+ * Main sets this when the caller is one of the plugin's windows rather
154
+ * than its background worker; `ui` methods require it.
155
+ */
156
+ ui?: boolean, } | { "op": "task_start", instance: string, command: string, } | { "op": "task_finish", instance: string, task: string, result: JsonValue | null, failed: boolean, } | { "op": "labels", locale: string, };
157
+ export type Request = { version: number, id: number, command: Command, };
158
+ export type Response = { id: number, result: JsonValue | null, error: string | null, };