@ateam-ai-mobile/plugin-runtime 0.1.20 → 0.1.21

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/src/sdk/types.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { DeviceState, DeviceBridgeDomain } from './device-state';
8
8
  import type { VoiceAPI } from './voice';
9
+ import type { AiLiveAPI } from './aiLive';
9
10
 
10
11
  // ── Plugin Context ──────────────────────────────────────────
11
12
 
@@ -258,11 +259,16 @@ export interface BluetoothDevice {
258
259
  // deviceState.visual.getSnapshot() → "is there a current frame, how old"
259
260
  // native.vision.readText(frame) → "what does the sign say"
260
261
  //
261
- // FRAMES NEVER LEAVE THE PHONE. That is Arie's decision (2026-08-15) and it is
262
- // the whole reason this is a platform capability rather than an API call from
263
- // a plugin: analysis runs on-device, so there is no per-frame cost and no image
264
- // on anyone's server. An implementation that POSTs the frame somewhere would
265
- // satisfy the types and violate the design.
262
+ // FRAMES STAY ON THE PHONE UNLESS TWO PEOPLE SAY YES. Arie's decision
263
+ // (2026-08-15: frames never leave the phone) is the default and the reason this
264
+ // is a platform capability rather than an API call from a plugin: analysis runs
265
+ // on-device, so there is no per-frame cost and no image on anyone's server.
266
+ // Amended 2026-10-25: a picture MAY leave only when the solution's developer
267
+ // declares `picturesToAi` AND the person on the phone allowed it in the host's
268
+ // settings. `mayPicturesLeavePhone()` (host.ts) is the one check; any path that
269
+ // sends a picture off the phone must call it and refuse when it says no. No
270
+ // such path exists yet. An implementation that POSTs a frame without that check
271
+ // would satisfy the types and violate the design.
266
272
  //
267
273
  // IT TAKES A HANDLE, NOT PIXELS. `MediaHandle.id` from a VisualFrameRef — the
268
274
  // core rule that media crosses by reference. A plugin never holds bytes.
@@ -595,6 +601,11 @@ export interface NativeCapabilities {
595
601
  nfc?: boolean;
596
602
  /** Real biometric auth (Face ID / Touch ID / fingerprint). */
597
603
  biometricsV2?: boolean;
604
+ /** The developer's half of "camera pictures may go to an AI service off the
605
+ * phone". Declaring it grants nothing by itself: the person on the phone must
606
+ * also allow it in the host's settings. Both are checked together by
607
+ * `mayPicturesLeavePhone()`. Not declared = pictures never leave. */
608
+ picturesToAi?: boolean;
598
609
  }
599
610
 
600
611
  // ── Lifecycle hooks ─────────────────────────────────────────
@@ -677,6 +688,14 @@ export interface PluginProps {
677
688
  * plugin gets a refusal (reads say so, actions throw) — never a fake `idle`.
678
689
  */
679
690
  voice: VoiceAPI;
691
+ /**
692
+ * The workspace's CHOSEN AI watching the phone camera, live — gated to plugins
693
+ * that declared `capabilities: { picturesToAi: true }` AND used only when the
694
+ * person on the phone allowed "Pictures to AI". The screen gets episodes
695
+ * ("drinking" started), never pictures; "Sending to AI" is platform-owned.
696
+ * REQUIRED like `voice`: an undeclared plugin gets a refusal, never a fake idle.
697
+ */
698
+ aiLive: AiLiveAPI;
680
699
  theme: ThemeTokens;
681
700
  context: PluginContext;
682
701
  /** Engine-supplied props from `sys.focusUiPlugin(pluginId, props)`.