@burmese/plugin-sdk 3.1.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.
@@ -0,0 +1,858 @@
1
+ /**
2
+ * Type definitions for OpenPets plugins — SDK v3 ("SuperPlugins").
3
+ *
4
+ * This package ships **types only**. There is no runtime to import — the
5
+ * OpenPets desktop app injects the `OpenPetsPlugin` global into the plugin
6
+ * sandbox and passes your `start(ctx)` handler an {@link OpenPetsContext}.
7
+ *
8
+ * In a plain JavaScript plugin, reference these types for editor IntelliSense:
9
+ *
10
+ * ```js
11
+ * /// <reference types="@burmese/plugin-sdk" />
12
+ *
13
+ * OpenPetsPlugin.register({
14
+ * async start(ctx) {
15
+ * const bubble = await ctx.ui.bubble({ text: "Hello!", sticky: true })
16
+ * bubble.onAction(() => bubble.dismiss())
17
+ * },
18
+ * })
19
+ * ```
20
+ *
21
+ * SDK v3 reframes a pet as a programmable surface: the API is organized into
22
+ * subsystems (`ui`, `pets`, `events`, `audio`, `ai`, …) instead of one flat
23
+ * `ctx.pet` namespace. The v2 surface (`ctx.pet.speak`, `ctx.http.fetch`, …)
24
+ * keeps working unchanged.
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+ /** Capabilities a plugin can request in its manifest's `permissions` array. */
29
+ export type OpenPetsPermission = "pet:speak" | "pet:reaction" | "pet:move" | "schedule" | "storage" | "status" | "commands" | "network" | "pet:interact" | "pet:pin" | "pet:animate" | "pet:speak:dynamic" | "pet:drop" | "pets:read" | "pets:manage" | "audio" | "events" | "ui:toast" | "ui:panel" | "notify" | "bus" | "ai" | "secrets" | "voice:speak" | "voice:listen" | "auth" | "files" | "system:openExternal" | "system:metrics" | "clipboard" | "network:write";
30
+ /**
31
+ * Reaction name passed to {@link OpenPetsPetHandle.react}. Common values are
32
+ * listed for autocomplete; any string the host accepts is allowed.
33
+ */
34
+ export type OpenPetsReaction = "idle" | "thinking" | "working" | "editing" | "running" | "testing" | "waiting" | "waving" | "success" | "error" | "celebrating" | (string & {});
35
+ /** Tone shown alongside a plugin's status line or bubble. */
36
+ export type OpenPetsStatusTone = "info" | "success" | "warning" | "error";
37
+ /** A status line, either a bare string or text plus a {@link OpenPetsStatusTone}. */
38
+ export type OpenPetsStatus = string | {
39
+ text: string;
40
+ tone?: OpenPetsStatusTone;
41
+ };
42
+ /** A point in screen coordinates. */
43
+ export interface OpenPetsPoint {
44
+ x: number;
45
+ y: number;
46
+ }
47
+ /** A rectangle in screen coordinates. */
48
+ export interface OpenPetsRect {
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ height: number;
53
+ }
54
+ /**
55
+ * An opaque reference to an asset bundled with the plugin and declared in the
56
+ * manifest's `assets` block. Obtained from {@link OpenPetsAssetsApi}; never
57
+ * constructed by hand. Plugins pass references, never raw bytes or markup.
58
+ */
59
+ export interface OpenPetsAssetRef {
60
+ readonly kind: "icon" | "image" | "svg" | "sprite" | "sound";
61
+ readonly name: string;
62
+ }
63
+ /** A named host icon (curated set) or a bundled icon asset reference. */
64
+ export type OpenPetsIconRef = string | OpenPetsAssetRef;
65
+ /** A JSON-safe reference to a user-imported sound. */
66
+ export interface OpenPetsUserSoundRef {
67
+ readonly kind: "user-sound";
68
+ readonly id: string;
69
+ readonly name?: string;
70
+ }
71
+ /** A named host sound, bundled sound asset, or user-imported sound reference. */
72
+ export type OpenPetsSoundRef = string | OpenPetsAssetRef | OpenPetsUserSoundRef;
73
+ /** Resolve manifest-declared assets to opaque references. */
74
+ export interface OpenPetsAssetsApi {
75
+ /** Resolve a manifest-declared icon. */
76
+ icon(name: string): OpenPetsAssetRef;
77
+ /** Resolve a manifest-declared raster image. */
78
+ image(name: string): OpenPetsAssetRef;
79
+ /** Resolve a manifest-declared, install-time-sanitized SVG. */
80
+ svg(name: string): OpenPetsAssetRef;
81
+ /** Resolve a manifest-declared spritesheet. */
82
+ sprite(name: string): OpenPetsAssetRef;
83
+ /** Resolve a manifest-declared sound. */
84
+ sound(name: string): OpenPetsAssetRef;
85
+ }
86
+ /** A button rendered inside a bubble. Requires `pet:interact`. */
87
+ export interface OpenPetsBubbleAction {
88
+ /** Short, stable id (`[A-Za-z0-9._:-]`, 1–64 chars). */
89
+ id: string;
90
+ label: string;
91
+ style?: "default" | "primary" | "danger";
92
+ icon?: OpenPetsIconRef;
93
+ /** Dismiss the bubble when this action fires. Default true. */
94
+ dismissesBubble?: boolean;
95
+ }
96
+ /** An inline input rendered inside a bubble. Requires `pet:interact`. */
97
+ export interface OpenPetsBubbleInput {
98
+ id: string;
99
+ type: "text" | "number" | "select";
100
+ placeholder?: string;
101
+ default?: string | number;
102
+ /** Options for `select` inputs. */
103
+ options?: Array<{
104
+ value: string;
105
+ label: string;
106
+ }>;
107
+ submitLabel?: string;
108
+ }
109
+ /** A HUD item shown in the host-rendered pinned mini-HUD bubble. */
110
+ export interface OpenPetsBubbleHudItem {
111
+ /** Named host icon or bundled icon asset reference. */
112
+ icon: OpenPetsIconRef;
113
+ /** Numeric value between 0 and 100 inclusive. */
114
+ value: number;
115
+ /** Optional short display label. */
116
+ label?: string;
117
+ /** Optional theme color tone for the bar/indicator. */
118
+ tone?: "amber" | "blue" | "green" | "pink" | "slate" | "red";
119
+ }
120
+ /** Descriptor for a host-rendered mini HUD layout, used in pinned bubbles. */
121
+ export interface OpenPetsBubbleHud {
122
+ /** List of HUD items (usually up to 4 items). */
123
+ items: OpenPetsBubbleHudItem[];
124
+ }
125
+ /**
126
+ * A structured, host-rendered bubble descriptor. The plugin describes; the
127
+ * host renders — no raw HTML or live DOM ever crosses the SDK boundary.
128
+ */
129
+ export interface OpenPetsBubble {
130
+ /** Host-rendered mini HUD layout for pinned bubbles. */
131
+ hud?: OpenPetsBubbleHud;
132
+ /** Plain text, length-capped, content-filtered. */
133
+ text?: string;
134
+ /** Limited markdown (bold/italic/code/line breaks), host-sanitized. */
135
+ markdown?: string;
136
+ /** Named host icon or a bundled icon asset. Body media is icon-only; use `indicator` for icon + message. */
137
+ icon?: OpenPetsIconRef;
138
+ /** Bundled, install-time-sanitized SVG. Body media is icon-only; use `indicator` for icon + message. */
139
+ svg?: OpenPetsAssetRef;
140
+ /** Bundled raster image. Body media is icon-only; use `indicator` for icon + message. */
141
+ image?: OpenPetsAssetRef;
142
+ tone?: OpenPetsStatusTone;
143
+ /** Optional top-row indicator/header. Intended primarily for alerts. */
144
+ indicator?: OpenPetsAlertIndicator | false;
145
+ /** Theme-token name, not a raw color string. */
146
+ accent?: string;
147
+ /**
148
+ * Marks content as model-generated. Requires `pet:speak:dynamic` and the
149
+ * global "allow AI speech" setting; uses the relaxed dynamic screen instead
150
+ * of the static ambient filter (§13.1).
151
+ */
152
+ dynamic?: boolean;
153
+ /** Auto-dismiss after N ms; omit for the host default. */
154
+ durationMs?: number;
155
+ /** Ignore duration; stay until dismissed or replaced. */
156
+ sticky?: boolean;
157
+ /** Occupy the persistent pinned slot (max 1 per pet). Requires `pet:pin`. */
158
+ pin?: boolean;
159
+ dismissOn?: Array<"timeout" | "click" | "petClick" | "action" | "outsideClick">;
160
+ /** Feeds the bubble arbiter. Default "normal". */
161
+ priority?: "low" | "normal" | "high" | "urgent";
162
+ actions?: OpenPetsBubbleAction[];
163
+ input?: OpenPetsBubbleInput;
164
+ }
165
+ /** Why a bubble went away. */
166
+ export type OpenPetsBubbleDismissReason = "timeout" | "click" | "replaced" | "manual" | "unpinned";
167
+ /**
168
+ * Live handle to a shown bubble. Lets the plugin update it in place
169
+ * (progress, countdowns, streamed tokens) and receive interaction callbacks.
170
+ */
171
+ export interface OpenPetsBubbleHandle {
172
+ readonly id: string;
173
+ update(patch: Partial<OpenPetsBubble>): Promise<void>;
174
+ dismiss(): Promise<void>;
175
+ /** Promote this bubble to the pinned slot (§1.5). Requires `pet:pin`. */
176
+ pin(): Promise<void>;
177
+ /** Release the pinned slot. */
178
+ unpin(): Promise<void>;
179
+ onAction(handler: (actionId: string) => void | Promise<void>): void;
180
+ onSubmit(handler: (values: Record<string, string | number>) => void | Promise<void>): void;
181
+ onDismiss(handler: (reason: OpenPetsBubbleDismissReason) => void): void;
182
+ }
183
+ /** Options for opening a sandboxed plugin panel (§7.2). Requires `ui:panel`. */
184
+ export interface OpenPetsPanelOptions {
185
+ /** Name of a manifest-declared panel page (`panels` block). */
186
+ panel: string;
187
+ title?: string;
188
+ width?: number;
189
+ height?: number;
190
+ }
191
+ /** Handle to a sandboxed plugin panel window. */
192
+ export interface OpenPetsPanelHandle {
193
+ readonly id: string;
194
+ show(): Promise<void>;
195
+ hide(): Promise<void>;
196
+ /** Host -> panel. Payload must be clone-safe data. */
197
+ postMessage(msg: unknown): Promise<void>;
198
+ /** Panel -> plugin, clone-safe. */
199
+ onMessage(handler: (msg: unknown) => void): void;
200
+ close(): Promise<void>;
201
+ }
202
+ /** Alert header indicator rendered above alert text. Custom art must be a manifest-declared asset. */
203
+ export interface OpenPetsAlertIndicator {
204
+ /** Visible/accessibility label shown next to the icon. */
205
+ label?: string;
206
+ /** Named host icon or manifest-declared icon asset (`ctx.assets.icon(...)`). */
207
+ icon?: OpenPetsIconRef;
208
+ /** Manifest-declared sanitized SVG asset (`ctx.assets.svg(...)`). */
209
+ svg?: OpenPetsAssetRef;
210
+ /** Manifest-declared raster/icon image asset. */
211
+ image?: OpenPetsAssetRef;
212
+ tone?: OpenPetsStatusTone;
213
+ /** Safe CSS color for the icon/SVG (`#hex`, `rgb(a)`, or `hsl(a)`). */
214
+ color?: string;
215
+ /** Safe CSS background color for the circular icon well. */
216
+ background?: string;
217
+ /** Alias for `background`. */
218
+ backgroundColor?: string;
219
+ /** Safe CSS border color for the circular icon well. */
220
+ borderColor?: string;
221
+ }
222
+ /**
223
+ * Must-not-miss pet alert. Alerts render as sticky high-priority bubbles and
224
+ * may also request best-effort sound and OS notification delivery.
225
+ */
226
+ export interface OpenPetsAlert extends Omit<OpenPetsBubble, "sticky" | "priority"> {
227
+ /** Optional sound to play with the alert. Requires `audio` only when set. */
228
+ sound?: OpenPetsSoundRef;
229
+ /** Optional OS notification. Requires `notify` only when set. */
230
+ notify?: {
231
+ title: string;
232
+ body?: string;
233
+ sound?: boolean;
234
+ };
235
+ }
236
+ /** Handle to a live alert bubble. */
237
+ export interface OpenPetsAlertHandle extends OpenPetsBubbleHandle {
238
+ /** Mark the alert acknowledged and dismiss it. */
239
+ acknowledge(): Promise<void>;
240
+ }
241
+ /** Bubbles, toasts, panels, and the dynamic context-menu section. */
242
+ export interface OpenPetsUiApi {
243
+ /** Show a bubble on the default pet. Requires `pet:speak`. */
244
+ bubble(spec: string | OpenPetsBubble): Promise<OpenPetsBubbleHandle>;
245
+ /** Show a transient host toast. Requires `ui:toast`. */
246
+ toast(spec: {
247
+ text: string;
248
+ tone?: OpenPetsStatusTone;
249
+ durationMs?: number;
250
+ }): Promise<void>;
251
+ /** Show a sticky high-priority alert bubble. Requires `pet:speak`. */
252
+ alert(spec: OpenPetsAlert): Promise<OpenPetsAlertHandle>;
253
+ /** Open a sandboxed plugin webview panel. Requires `ui:panel`. */
254
+ panel(spec: OpenPetsPanelOptions): Promise<OpenPetsPanelHandle>;
255
+ /** Fully dynamic context-menu section. Requires `commands`. */
256
+ menu: OpenPetsMenuApi;
257
+ }
258
+ /** OS notifications. Requires `notify`. */
259
+ export interface OpenPetsNotifyApi {
260
+ notify(spec: {
261
+ title: string;
262
+ body?: string;
263
+ sound?: boolean;
264
+ }): Promise<void>;
265
+ }
266
+ /** Play named host sounds or bundled plugin sounds. Requires `audio`. */
267
+ export interface OpenPetsAudioApi {
268
+ /**
269
+ * Play a sound. Named host sounds (`"chime"`, `"pop"`, `"nom"`, `"alert"`,
270
+ * `"level-up"`) need no assets; bundled sounds come from
271
+ * {@link OpenPetsAssetsApi.sound}. Gated by the global sound toggle and
272
+ * quiet hours.
273
+ */
274
+ play(sound: OpenPetsSoundRef, options?: {
275
+ volume?: number;
276
+ }): Promise<void>;
277
+ /** Import a user-picked sound into plugin-owned host storage. Requires `audio` and `files`. */
278
+ importUserSound(file: OpenPetsPickedFile, opts?: {
279
+ name?: string;
280
+ }): Promise<OpenPetsUserSoundRef>;
281
+ /** Forget a previously imported user sound. Requires `audio`. */
282
+ forgetUserSound(ref: OpenPetsUserSoundRef): Promise<void>;
283
+ stop(handle?: string): Promise<void>;
284
+ }
285
+ /** Curated, read-only host event names. */
286
+ export type OpenPetsEventName = "pet:clicked" | "pet:doubleClicked" | "pet:dragStart" | "pet:dragEnd" | "pet:hover" | "pet:drop" | "idle:enter" | "idle:exit" | "agent:activity" | "config:changed" | "screen:locked" | "screen:unlocked" | "power:battery-low" | "power:charging" | "display:changed" | "online" | "offline" | "day:partChanged";
287
+ /** A file delivered by an explicit user drop onto the pet (§13.7). */
288
+ export interface OpenPetsDroppedFile {
289
+ name: string;
290
+ sizeBytes: number;
291
+ /** One-shot, size-capped read of the dropped file's text content. */
292
+ readText(): Promise<string>;
293
+ }
294
+ /** Payload for `pet:drop`. */
295
+ export interface OpenPetsDropEvent {
296
+ kind: "text" | "files";
297
+ text?: string;
298
+ files?: OpenPetsDroppedFile[];
299
+ petId: string;
300
+ }
301
+ /** Payload shapes per event. Unlisted events carry a small data record. */
302
+ export interface OpenPetsEventPayloads {
303
+ "pet:clicked": {
304
+ petId: string;
305
+ };
306
+ "pet:doubleClicked": {
307
+ petId: string;
308
+ };
309
+ "pet:dragStart": {
310
+ petId: string;
311
+ };
312
+ "pet:dragEnd": {
313
+ petId: string;
314
+ };
315
+ "pet:hover": {
316
+ petId: string;
317
+ };
318
+ "pet:drop": OpenPetsDropEvent;
319
+ "idle:enter": {
320
+ idleSeconds: number;
321
+ };
322
+ "idle:exit": {
323
+ idleSeconds: number;
324
+ };
325
+ "agent:activity": {
326
+ kind: string;
327
+ reaction?: string;
328
+ active: boolean;
329
+ petId: string;
330
+ };
331
+ "config:changed": Record<string, unknown>;
332
+ "screen:locked": Record<string, never>;
333
+ "screen:unlocked": Record<string, never>;
334
+ "power:battery-low": {
335
+ percent?: number;
336
+ };
337
+ "power:charging": {
338
+ charging: boolean;
339
+ };
340
+ "display:changed": {
341
+ displays: number;
342
+ };
343
+ online: Record<string, never>;
344
+ offline: Record<string, never>;
345
+ "day:partChanged": {
346
+ part: "morning" | "afternoon" | "evening" | "night";
347
+ };
348
+ }
349
+ export type OpenPetsEvent<E extends OpenPetsEventName> = OpenPetsEventPayloads[E];
350
+ /**
351
+ * Subscribe to the curated host event stream. Requires `events`
352
+ * (`pet:drop` additionally requires `pet:drop`).
353
+ *
354
+ * The event set is explicitly bounded: no keystrokes, no screen contents, no
355
+ * other apps' window titles, no clipboard, no ambient filesystem watching.
356
+ */
357
+ export interface OpenPetsEventsApi {
358
+ on<E extends OpenPetsEventName>(event: E, handler: (e: OpenPetsEvent<E>) => void): () => void;
359
+ }
360
+ /** Options for {@link OpenPetsPetHandle.moveBy}. */
361
+ export interface OpenPetsMoveByOptions {
362
+ x: number;
363
+ y: number;
364
+ durationMs?: number;
365
+ }
366
+ /** Options for {@link OpenPetsPetHandle.wander}. */
367
+ export interface OpenPetsWanderOptions {
368
+ distance?: number;
369
+ durationMs?: number;
370
+ }
371
+ /** Beyond named reactions: a bundled spritesheet animation (§5). */
372
+ export type OpenPetsAnimationState = OpenPetsReaction | {
373
+ sprite: OpenPetsAssetRef;
374
+ loop?: boolean;
375
+ fps?: number;
376
+ };
377
+ /** Self-perception snapshot returned by {@link OpenPetsPetHandle.getState}. */
378
+ export interface OpenPetsPetState {
379
+ position: OpenPetsPoint;
380
+ bounds: OpenPetsRect;
381
+ currentAnimation: string;
382
+ visible: boolean;
383
+ dragging: boolean;
384
+ }
385
+ export interface OpenPetsPetInfo {
386
+ id: string;
387
+ name: string;
388
+ kind: "default" | "agent" | "plugin";
389
+ visible: boolean;
390
+ }
391
+ export interface OpenPetsReactOptions {
392
+ /** Set false to animate without showing the built-in reaction/status message. */
393
+ showMessage?: boolean;
394
+ }
395
+ /** Addressable handle to a single pet. */
396
+ export interface OpenPetsPetHandle {
397
+ readonly id: string;
398
+ /** Requires `pet:speak`. Accepts plain text or a full bubble descriptor. */
399
+ speak(spec: string | OpenPetsBubble): Promise<OpenPetsBubbleHandle>;
400
+ /** Requires `pet:reaction`. */
401
+ react(reaction: OpenPetsReaction, options?: OpenPetsReactOptions): Promise<void>;
402
+ /** Requires `pet:animate` for sprite states; named reactions need `pet:reaction`. */
403
+ setAnimation(state: OpenPetsAnimationState): Promise<void>;
404
+ /** Bounded by the host (0.5–2). Requires `pet:animate`. */
405
+ setScale(scale: number): Promise<void>;
406
+ /** Show a status reaction (or clear with null). Requires `pet:reaction`. */
407
+ setStatusReaction(reaction: OpenPetsReaction | null): Promise<void>;
408
+ /** Requires `pet:move`. Movement is bounded to the work area. */
409
+ moveBy(options: OpenPetsMoveByOptions): Promise<void>;
410
+ /** Requires `pet:move`. */
411
+ wander(options?: OpenPetsWanderOptions): Promise<void>;
412
+ /** Requires `pet:move`. */
413
+ moveToHome(): Promise<void>;
414
+ /** Animated absolute move. Requires `pet:move`. */
415
+ moveTo(point: OpenPetsPoint, opts?: {
416
+ durationMs?: number;
417
+ easing?: string;
418
+ }): Promise<void>;
419
+ /** Continuous cursor following with lag. Requires `pet:move`. */
420
+ followCursor(opts?: {
421
+ enabled: boolean;
422
+ lag?: number;
423
+ }): Promise<void>;
424
+ /** Lightweight physics (gravity/bounce). Requires `pet:move`. */
425
+ physics(opts?: {
426
+ gravity?: boolean;
427
+ bounce?: number;
428
+ climbEdges?: boolean;
429
+ }): Promise<void>;
430
+ /**
431
+ * Continuous behavior loop — host-driven, throttled, auto-paused while the
432
+ * pet is hidden or being dragged. The brain loop for "alive" pets.
433
+ * Requires `events`. Returns an unsubscribe function.
434
+ */
435
+ onTick(handler: (dtMs: number) => void): () => void;
436
+ /** Self-perception. Requires `pets:read`. */
437
+ getState(): Promise<OpenPetsPetState>;
438
+ /** Requires `pets:manage`. */
439
+ show(): Promise<void>;
440
+ /** Requires `pets:manage`. */
441
+ hide(): Promise<void>;
442
+ /** Close an ephemeral/spawned pet. Requires `pets:manage`. */
443
+ close(): Promise<void>;
444
+ }
445
+ /** Multi-pet registry: list, target, spawn. */
446
+ export interface OpenPetsPetsApi {
447
+ readonly default: OpenPetsPetHandle;
448
+ /** Requires `pets:read`. */
449
+ list(): Promise<OpenPetsPetInfo[]>;
450
+ get(petId: string): OpenPetsPetHandle;
451
+ /** Spawn an ephemeral pet window. Requires `pets:manage`. */
452
+ spawn(spec: {
453
+ petId: string;
454
+ name?: string;
455
+ position?: OpenPetsPoint;
456
+ ephemeral?: boolean;
457
+ }): Promise<OpenPetsPetHandle>;
458
+ /** Requires `pets:read`. Returns an unsubscribe function. */
459
+ onChange(handler: (pets: OpenPetsPetInfo[]) => void): () => void;
460
+ }
461
+ /** A single field in a command's input form (extended in v3, §8.1). */
462
+ export interface OpenPetsCommandFormField {
463
+ /** Identifier for this field; the submitted value is keyed by it. */
464
+ id: string;
465
+ type: "text" | "textarea" | "number" | "boolean" | "select" | "multiselect" | "time" | "date" | "list";
466
+ label: string;
467
+ default?: string | number | boolean | string[];
468
+ options?: Array<{
469
+ label: string;
470
+ value: string;
471
+ }>;
472
+ /** Minimum value (number fields only). */
473
+ min?: number;
474
+ /** Maximum value (number fields only). */
475
+ max?: number;
476
+ /** Maximum length (text/textarea fields only). */
477
+ maxLength?: number;
478
+ required?: boolean;
479
+ }
480
+ /** Optional input form attached to a command. */
481
+ export interface OpenPetsCommandForm {
482
+ fields: OpenPetsCommandFormField[];
483
+ submitLabel?: string;
484
+ }
485
+ /** A right-click pet action registered via {@link OpenPetsCommandsApi.register}. */
486
+ export interface OpenPetsCommand {
487
+ /** Short, stable id (`[A-Za-z0-9._:-]`, 1–64 chars). */
488
+ id: string;
489
+ title: string;
490
+ description?: string;
491
+ icon?: OpenPetsIconRef;
492
+ /** When present, the host opens a dialog and passes validated values to the handler. */
493
+ form?: OpenPetsCommandForm;
494
+ /** Top-level item vs grouped plugin submenu. Default "submenu". */
495
+ placement?: "top" | "submenu";
496
+ /** Ordering within its group (higher first). */
497
+ priority?: number;
498
+ featured?: boolean;
499
+ }
500
+ /** A dynamic context-menu item set via {@link OpenPetsMenuApi.setItems}. */
501
+ export interface OpenPetsMenuItem {
502
+ id: string;
503
+ title: string;
504
+ enabled?: boolean;
505
+ checked?: boolean;
506
+ }
507
+ /** Fully dynamic context-menu section. Requires `commands`. */
508
+ export interface OpenPetsMenuApi {
509
+ setItems(items: OpenPetsMenuItem[]): Promise<void>;
510
+ onSelect(handler: (id: string) => void | Promise<void>): () => void;
511
+ }
512
+ /** Handler invoked when a command runs, with validated form values when present. */
513
+ export type OpenPetsCommandHandler = (values?: Record<string, unknown>) => void | Promise<void>;
514
+ /** Register right-click pet actions. Requires `commands`. */
515
+ export interface OpenPetsCommandsApi {
516
+ register(command: OpenPetsCommand, handler: OpenPetsCommandHandler): Promise<void>;
517
+ unregister(id: string): Promise<void>;
518
+ }
519
+ /** A daily schedule time, optionally restricted to specific weekdays. */
520
+ export type OpenPetsDailySpec = string | {
521
+ time: string;
522
+ days?: number[];
523
+ };
524
+ /** A callback fired by a schedule. */
525
+ export type OpenPetsScheduleHandler = () => void | Promise<void>;
526
+ /**
527
+ * Run callbacks once, on an interval, daily, on a cron expression, or at an
528
+ * absolute time. Wall-clock aware: schedules re-arm after sleep/wake.
529
+ * Requires `schedule`.
530
+ */
531
+ export interface OpenPetsScheduleApi {
532
+ /** Fire once after `delayMs`. */
533
+ once(id: string, delayMs: number, handler: OpenPetsScheduleHandler): Promise<void>;
534
+ /** Fire repeatedly every `intervalMs` (a minimum interval is enforced). */
535
+ every(id: string, intervalMs: number, handler: OpenPetsScheduleHandler): Promise<void>;
536
+ /** Fire daily at `HH:mm`, optionally only on the given weekdays (0–6, Sunday = 0). */
537
+ daily(id: string, spec: OpenPetsDailySpec, handler: OpenPetsScheduleHandler): Promise<void>;
538
+ /** Fire on a 5-field cron expression (`m h dom mon dow`). */
539
+ cron(id: string, expr: string, handler: OpenPetsScheduleHandler): Promise<void>;
540
+ /** Fire once at an absolute ISO-8601 timestamp. Past timestamps fire immediately. */
541
+ at(id: string, isoTimestamp: string, handler: OpenPetsScheduleHandler): Promise<void>;
542
+ list(): Promise<Array<{
543
+ id: string;
544
+ nextRunMs: number;
545
+ }>>;
546
+ cancel(id: string): Promise<void>;
547
+ cancelAll(): Promise<void>;
548
+ }
549
+ /** Persist per-plugin state across restarts (quota: a few MB). Requires `storage`. */
550
+ export interface OpenPetsStorageApi {
551
+ get<T = unknown>(key: string): Promise<T | undefined>;
552
+ set(key: string, value: unknown): Promise<void>;
553
+ delete(key: string): Promise<void>;
554
+ keys(): Promise<string[]>;
555
+ /** Reactive subscription to a key. Returns an unsubscribe function. */
556
+ subscribe(key: string, handler: (value: unknown) => void): () => void;
557
+ }
558
+ /** Read user configuration and react to changes. Always available. */
559
+ export interface OpenPetsConfigApi {
560
+ get<T = Record<string, unknown>>(): Promise<T>;
561
+ /** Subscribe to config changes. Returns an unsubscribe function. */
562
+ onChange<T = Record<string, unknown>>(handler: (config: T) => void | Promise<void>): () => void;
563
+ }
564
+ /** Inter-plugin pub/sub. Topics should be namespaced `pluginId/topic`. Requires `bus`. */
565
+ export interface OpenPetsBusApi {
566
+ /** Publish a clone-safe payload. Rate- and size-capped by the host. */
567
+ publish(topic: string, payload: unknown): Promise<void>;
568
+ subscribe(topic: string, handler: (payload: unknown) => void): () => void;
569
+ }
570
+ /** Options for {@link OpenPetsNetApi.fetch}. Non-GET methods require `network:write`. */
571
+ export interface OpenPetsNetFetchOptions {
572
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
573
+ headers?: Record<string, string>;
574
+ body?: string;
575
+ timeoutMs?: number;
576
+ }
577
+ /** Response returned by {@link OpenPetsNetApi.fetch}. */
578
+ export interface OpenPetsHttpResponse {
579
+ status: number;
580
+ ok: boolean;
581
+ headers: Record<string, string>;
582
+ text: string;
583
+ json?: unknown;
584
+ }
585
+ /**
586
+ * HTTPS fetch to manifest-declared, user-approved hosts. Requires `network`.
587
+ * HTTPS-only with redirect, response-size, and private-IP/SSRF guards.
588
+ */
589
+ export interface OpenPetsNetApi {
590
+ fetch(url: string, options?: OpenPetsNetFetchOptions): Promise<OpenPetsHttpResponse>;
591
+ /** Streaming fetch (SSE/chunked) for LLM-style responses. */
592
+ stream(url: string, options: OpenPetsNetFetchOptions, onChunk: (chunk: string) => void): Promise<{
593
+ status: number;
594
+ ok: boolean;
595
+ }>;
596
+ }
597
+ /** v2 GET-only fetch options, kept for back-compat (`ctx.http`). */
598
+ export interface OpenPetsHttpOptions {
599
+ method?: "GET";
600
+ headers?: Record<string, string>;
601
+ timeoutMs?: number;
602
+ }
603
+ /** v2 HTTP namespace, kept for back-compat. Requires `network`. */
604
+ export interface OpenPetsHttpApi {
605
+ fetch(url: string, options?: OpenPetsHttpOptions): Promise<OpenPetsHttpResponse>;
606
+ }
607
+ /** A tool the model may call (host AI gateway function calling). */
608
+ export interface OpenPetsAiTool {
609
+ name: string;
610
+ description?: string;
611
+ /** JSON Schema for the tool's input. */
612
+ inputSchema: Record<string, unknown>;
613
+ }
614
+ /** A tool call requested by the model. */
615
+ export interface OpenPetsAiToolCall {
616
+ name: string;
617
+ input: Record<string, unknown>;
618
+ }
619
+ /** Request for {@link OpenPetsAiApi.complete} / {@link OpenPetsAiApi.stream}. */
620
+ export interface OpenPetsAiRequest {
621
+ system?: string;
622
+ messages: Array<{
623
+ role: "user" | "assistant";
624
+ content: string;
625
+ }>;
626
+ maxTokens?: number;
627
+ temperature?: number;
628
+ tools?: OpenPetsAiTool[];
629
+ }
630
+ /**
631
+ * Host AI gateway backed by the user's one configured provider/model.
632
+ * Keys live in host config, never in plugin code. Requires `ai`.
633
+ */
634
+ export interface OpenPetsAiApi {
635
+ /** Whether a provider is configured. */
636
+ available(): Promise<boolean>;
637
+ complete(req: OpenPetsAiRequest): Promise<{
638
+ text: string;
639
+ toolCalls?: OpenPetsAiToolCall[];
640
+ }>;
641
+ stream(req: OpenPetsAiRequest, onToken: (chunk: string) => void): Promise<{
642
+ text: string;
643
+ }>;
644
+ }
645
+ /** Encrypted per-plugin credentials (OS keychain / safeStorage). Requires `secrets`. */
646
+ export interface OpenPetsSecretsApi {
647
+ set(key: string, value: string): Promise<void>;
648
+ /** Returned only to the owning plugin. */
649
+ get(key: string): Promise<string | undefined>;
650
+ delete(key: string): Promise<void>;
651
+ has(key: string): Promise<boolean>;
652
+ }
653
+ /** TTS out (`voice:speak`) and opt-in, push-to-talk STT in (`voice:listen`). */
654
+ export interface OpenPetsVoiceApi {
655
+ speak(text: string, opts?: {
656
+ voice?: string;
657
+ rate?: number;
658
+ }): Promise<void>;
659
+ /**
660
+ * One-shot speech-to-text. Off by default, never ambient, clearly
661
+ * indicated. Requires `voice:listen` (sensitive) and a configured
662
+ * transcription-capable AI provider.
663
+ */
664
+ listen(opts?: {
665
+ timeoutMs?: number;
666
+ }): Promise<{
667
+ text: string;
668
+ }>;
669
+ }
670
+ /** Host-mediated OAuth configuration (PKCE by default; no client secret). */
671
+ export interface OpenPetsOauthConfig {
672
+ provider?: "google" | "microsoft" | "github" | "generic";
673
+ authorizationUrl: string;
674
+ tokenUrl: string;
675
+ clientId: string;
676
+ scopes: string[];
677
+ /** Default true. */
678
+ pkce?: boolean;
679
+ redirect?: "loopback" | "appProtocol";
680
+ }
681
+ /** Tokens returned by the host after running the OAuth dance. */
682
+ export interface OpenPetsOauthTokens {
683
+ accessToken: string;
684
+ refreshToken?: string;
685
+ expiresAt?: number;
686
+ }
687
+ /** Host-mediated OAuth: the host opens the system browser and runs PKCE. Requires `auth`. */
688
+ export interface OpenPetsAuthApi {
689
+ oauth(config: OpenPetsOauthConfig): Promise<OpenPetsOauthTokens>;
690
+ refresh(provider: string): Promise<{
691
+ accessToken: string;
692
+ expiresAt?: number;
693
+ }>;
694
+ signOut(provider: string): Promise<void>;
695
+ }
696
+ /** A user-picked file. Reads are size-capped; no plugin-chosen paths. */
697
+ export interface OpenPetsPickedFile {
698
+ name: string;
699
+ sizeBytes: number;
700
+ readText(): Promise<string>;
701
+ readBytes(): Promise<Uint8Array>;
702
+ }
703
+ /** User-initiated file access behind OS dialogs. Requires `files`. */
704
+ export interface OpenPetsFilesApi {
705
+ pick(opts?: {
706
+ accept?: string[];
707
+ multiple?: boolean;
708
+ }): Promise<OpenPetsPickedFile[]>;
709
+ save(opts: {
710
+ suggestedName: string;
711
+ data: string | Uint8Array;
712
+ }): Promise<void>;
713
+ }
714
+ /** Read-only environment info. Always non-sensitive. */
715
+ export interface OpenPetsSystemInfo {
716
+ platform: "mac" | "win" | "linux";
717
+ locale: string;
718
+ timezone: string;
719
+ theme: "light" | "dark";
720
+ appVersion: string;
721
+ online: boolean;
722
+ }
723
+ /** Aggregate machine metrics — never per-process or per-app data. */
724
+ export interface OpenPetsSystemMetrics {
725
+ /** 0–100, recent average. */
726
+ cpuPercent: number;
727
+ /** 0–100. */
728
+ memUsedPercent: number;
729
+ battery?: {
730
+ percent: number;
731
+ charging: boolean;
732
+ };
733
+ }
734
+ /** Read-only environment + open-external + gated clipboard. */
735
+ export interface OpenPetsSystemApi {
736
+ /** Always available. */
737
+ info(): Promise<OpenPetsSystemInfo>;
738
+ /** Requires `system:metrics`. */
739
+ metrics(): Promise<OpenPetsSystemMetrics>;
740
+ /** HTTPS-only; opens the user's real browser. Requires `system:openExternal`. */
741
+ openExternal(url: string): Promise<void>;
742
+ /**
743
+ * Allowed only from inside a user-invoked command handler, never ambient.
744
+ * Requires `clipboard` (sensitive).
745
+ */
746
+ readClipboardText(): Promise<string>;
747
+ /** Requires `clipboard`. */
748
+ writeClipboardText(text: string): Promise<void>;
749
+ }
750
+ /** Show a short status line in the Plugins window. Requires `status`. */
751
+ export interface OpenPetsStatusApi {
752
+ set(status: OpenPetsStatus): Promise<void>;
753
+ clear(): Promise<void>;
754
+ }
755
+ /** Write to the desktop app log under the `plugin` scope. Always available. */
756
+ export interface OpenPetsLogApi {
757
+ debug(...args: unknown[]): Promise<void>;
758
+ info(...args: unknown[]): Promise<void>;
759
+ warn(...args: unknown[]): Promise<void>;
760
+ error(...args: unknown[]): Promise<void>;
761
+ }
762
+ /**
763
+ * The capability object passed to {@link OpenPetsPluginDefinition.start}.
764
+ *
765
+ * Each namespace is only functional when the matching permission is approved
766
+ * in the manifest. `config`, `log`, `assets`, and `system.info` are always
767
+ * available.
768
+ *
769
+ * `pet` is an alias for `pets.default` (back-compat + convenience); the v2
770
+ * surface (`ctx.pet.speak(text)`, `ctx.http.fetch`) keeps working.
771
+ */
772
+ export interface OpenPetsContext {
773
+ pets: OpenPetsPetsApi;
774
+ pet: OpenPetsPetHandle;
775
+ ui: OpenPetsUiApi;
776
+ audio: OpenPetsAudioApi;
777
+ events: OpenPetsEventsApi;
778
+ assets: OpenPetsAssetsApi;
779
+ bus: OpenPetsBusApi;
780
+ schedule: OpenPetsScheduleApi;
781
+ storage: OpenPetsStorageApi;
782
+ config: OpenPetsConfigApi;
783
+ net: OpenPetsNetApi;
784
+ notify: OpenPetsNotifyApi;
785
+ ai: OpenPetsAiApi;
786
+ secrets: OpenPetsSecretsApi;
787
+ voice: OpenPetsVoiceApi;
788
+ auth: OpenPetsAuthApi;
789
+ files: OpenPetsFilesApi;
790
+ system: OpenPetsSystemApi;
791
+ commands: OpenPetsCommandsApi;
792
+ status: OpenPetsStatusApi;
793
+ /** v2 alias of `net` (GET-only). */
794
+ http: OpenPetsHttpApi;
795
+ log: OpenPetsLogApi;
796
+ /**
797
+ * Translate a key against the plugin's own `locales/<locale>.json` catalogs
798
+ * for the active host locale, falling back to the plugin's `en` catalog and
799
+ * then to the raw key. `{var}` placeholders are interpolated from `vars`.
800
+ *
801
+ * Use this for strings the plugin *composes at runtime* (bubble/notify/status
802
+ * bodies). Static manifest strings (`name`, `description`, `configSchema`
803
+ * labels, command titles) should instead use the `$t:key` reference form,
804
+ * which the host resolves at display time.
805
+ *
806
+ * ```ts
807
+ * await ctx.ui.bubble({ text: ctx.t("reminder.fire", { message: "Stretch" }) })
808
+ * // locales/ja.json: { "reminder.fire": "リマインダー: {message}" } -> "リマインダー: Stretch"
809
+ * ```
810
+ */
811
+ t: (key: string, vars?: Record<string, string | number>) => string;
812
+ /**
813
+ * The active host locale string (e.g. `"en"`, `"ja"`, `"pt-BR"`, `"zh-Hans"`).
814
+ * Read it to branch on language at runtime; `ctx.t` already follows it.
815
+ *
816
+ * ```ts
817
+ * if (ctx.locale.startsWith("ja")) { /* ... *\/ }
818
+ * ```
819
+ */
820
+ readonly locale: string;
821
+ }
822
+ /** The object you pass to {@link OpenPetsPluginApi.register}. */
823
+ export interface OpenPetsPluginDefinition {
824
+ /** Runs when the plugin is enabled or the app launches. */
825
+ start(ctx: OpenPetsContext): void | Promise<void>;
826
+ /** Optional cleanup. Schedules, commands, bubbles, and subscriptions are torn down for you. */
827
+ stop?(ctx?: OpenPetsContext): void | Promise<void>;
828
+ }
829
+ /** The injected global used to register a plugin. */
830
+ export interface OpenPetsPluginApi {
831
+ register(definition: OpenPetsPluginDefinition): void;
832
+ }
833
+ /**
834
+ * The signature of an exported `register` function — the testable plugin
835
+ * style used by the official plugins:
836
+ *
837
+ * ```ts
838
+ * export function register(OpenPetsPlugin: OpenPetsPluginApi) {
839
+ * OpenPetsPlugin.register({ async start(ctx) {} })
840
+ * }
841
+ * ```
842
+ */
843
+ export type OpenPetsPluginEntry = (api: OpenPetsPluginApi) => void | Promise<void>;
844
+ /** Field types supported by `configSchema` in the manifest. */
845
+ export type OpenPetsConfigFieldType = "text" | "textarea" | "number" | "boolean" | "select" | "time" | "date" | "list" | "multiselect" | "sound"
846
+ /** Masked input, encrypted at rest, never logged or echoed (v3). */
847
+ | "secret";
848
+ /** v2 alias: the old flat pet namespace shape. */
849
+ export type OpenPetsPetApi = Pick<OpenPetsPetHandle, "speak" | "react" | "moveBy" | "wander" | "moveToHome">;
850
+ declare global {
851
+ /**
852
+ * Injected by the OpenPets runtime. Call once at the top level of your
853
+ * entry file to register your plugin.
854
+ */
855
+ const OpenPetsPlugin: OpenPetsPluginApi;
856
+ }
857
+ export {};
858
+ //# sourceMappingURL=index.d.ts.map