@fenixforce/edition-mobile 0.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.
Files changed (41) hide show
  1. package/dist/index.js +230 -0
  2. package/dist/lib/agent.d.ts +44 -0
  3. package/dist/lib/app-context.d.ts +31 -0
  4. package/dist/lib/boot.d.ts +22 -0
  5. package/dist/lib/entry.d.ts +48 -0
  6. package/dist/lib/providers/hybrid-router.d.ts +60 -0
  7. package/dist/lib/providers/local-inference.d.ts +31 -0
  8. package/dist/lib/storage/identity-store.d.ts +13 -0
  9. package/dist/lib/storage/memory-search.d.ts +30 -0
  10. package/dist/lib/storage/sqlite-adapter.d.ts +22 -0
  11. package/dist/lib/sync/client.d.ts +81 -0
  12. package/dist/lib/sync/triggers.d.ts +59 -0
  13. package/dist/lib/tools/calendar.d.ts +76 -0
  14. package/dist/lib/tools/camera.d.ts +40 -0
  15. package/dist/lib/tools/contacts.d.ts +59 -0
  16. package/dist/lib/tools/location.d.ts +58 -0
  17. package/dist/lib/tools/notifications.d.ts +79 -0
  18. package/dist/lib/tools/registry.d.ts +26 -0
  19. package/dist/lib/tools/reminders.d.ts +65 -0
  20. package/dist/platforms/android-xr/XRAgentService.d.ts +27 -0
  21. package/dist/platforms/android-xr/XRContextCapture.d.ts +47 -0
  22. package/dist/platforms/android-xr/XRGestureHandler.d.ts +41 -0
  23. package/dist/platforms/android-xr/XRNotificationBridge.d.ts +35 -0
  24. package/dist/platforms/android-xr/XRVoiceInterface.d.ts +72 -0
  25. package/dist/platforms/android-xr/display/ConversationOverlay.d.ts +20 -0
  26. package/dist/platforms/android-xr/display/DisplayManager.d.ts +44 -0
  27. package/dist/platforms/android-xr/display/GlanceCard.d.ts +21 -0
  28. package/dist/platforms/android-xr/display/MemoryHUD.d.ts +22 -0
  29. package/dist/platforms/android-xr/display/NotificationPill.d.ts +13 -0
  30. package/dist/platforms/android-xr/xr-entry.d.ts +23 -0
  31. package/dist/platforms/quest/QuestAdapter.d.ts +66 -0
  32. package/dist/platforms/quest/QuestPanelConfig.d.ts +45 -0
  33. package/dist/platforms/quest/quest-entry.d.ts +29 -0
  34. package/dist/platforms/visionos/AgentBridge.d.ts +39 -0
  35. package/dist/platforms/visionos/VisionToolAdapters.d.ts +53 -0
  36. package/dist/platforms/visionos/VisionVoiceInterface.d.ts +32 -0
  37. package/dist/platforms/visionos/visionos-entry.d.ts +24 -0
  38. package/dist/src/hil/push-notifier.d.ts +25 -0
  39. package/dist/src/index.d.ts +72 -0
  40. package/dist/watch/WatchBridge.d.ts +63 -0
  41. package/package.json +51 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Sync Client — bidirectional sync between Mobile (client) and Pro (server).
3
+ * Protocol: GET /sync/status → POST /sync/push → GET /sync/pull?since= → POST /sync/ack
4
+ * Conflicts: higher syncVersion wins. Ties broken by most recent updatedAt.
5
+ */
6
+ import type { SQLiteDB } from "../storage/sqlite-adapter.js";
7
+ export interface SyncStatus {
8
+ lastSync: string;
9
+ pendingLocal: number;
10
+ pendingRemote: number;
11
+ connected: boolean;
12
+ }
13
+ export interface MemoryFact {
14
+ id: string;
15
+ content: string;
16
+ category: string;
17
+ confidence: number;
18
+ syncVersion: number;
19
+ updatedAt: string;
20
+ }
21
+ export interface SyncMessage {
22
+ id: string;
23
+ conversationId: string;
24
+ role: string;
25
+ content: string;
26
+ syncVersion: number;
27
+ createdAt: string;
28
+ }
29
+ export interface IdentityPush {
30
+ fileName: string;
31
+ content: string;
32
+ updatedAt: string;
33
+ }
34
+ export interface LocalChanges {
35
+ facts: MemoryFact[];
36
+ messages: SyncMessage[];
37
+ identity?: IdentityPush[];
38
+ }
39
+ export interface PushResult {
40
+ accepted: number;
41
+ conflicts: ConflictRecord[];
42
+ serverTime: string;
43
+ }
44
+ export interface PullResult {
45
+ facts: MemoryFact[];
46
+ messages: SyncMessage[];
47
+ identity: IdentityPush[];
48
+ serverTime: string;
49
+ }
50
+ export interface ConflictRecord {
51
+ entityType: "fact" | "message" | "identity";
52
+ entityId: string;
53
+ localVersion: number;
54
+ remoteVersion: number;
55
+ localUpdatedAt: string;
56
+ remoteUpdatedAt: string;
57
+ resolvedTo: "local" | "remote";
58
+ }
59
+ export interface SyncClient {
60
+ status(): Promise<SyncStatus>;
61
+ push(changes: LocalChanges): Promise<PushResult>;
62
+ pull(since: string): Promise<PullResult>;
63
+ ack(receivedUpTo: string): Promise<void>;
64
+ fullSync(): Promise<{
65
+ pushed: PushResult;
66
+ pulled: PullResult;
67
+ }>;
68
+ }
69
+ export interface SyncClientConfig {
70
+ /** Base URL of the Pro server (e.g. https://fenix.example.com). */
71
+ serverUrl: string;
72
+ /** Bearer token for authentication (stored in expo-secure-store). */
73
+ authToken: string;
74
+ /** SQLite database handle for reading local changes and storing conflicts. */
75
+ db: SQLiteDB;
76
+ /** Override fetch for testing. */
77
+ fetchFn?: typeof globalThis.fetch;
78
+ /** Maximum retries on network failure. */
79
+ maxRetries?: number;
80
+ }
81
+ export declare function createSyncClient(config: SyncClientConfig): SyncClient;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Sync Triggers — manages when sync runs. Sync does not run continuously.
3
+ *
4
+ * Trigger points:
5
+ * 1. App foreground — check status, sync if pending
6
+ * 2. Post-conversation — after 5 min inactivity or chat close
7
+ * 3. Manual — user taps "Sync Now"
8
+ * 4. Background — periodic via expo-task-manager (30 min, WiFi + charging)
9
+ * 5. Push notification — silent push from Pro triggers pull
10
+ *
11
+ * Each trigger checks connectivity before attempting sync.
12
+ * Failed syncs are retried on the next trigger (no exponential backoff
13
+ * since triggers are already infrequent).
14
+ */
15
+ import type { SyncClient } from "./client.js";
16
+ export type TriggerSource = "foreground" | "post_conversation" | "manual" | "background" | "push";
17
+ export interface SyncTriggerConfig {
18
+ syncClient: SyncClient;
19
+ isOnline: () => boolean;
20
+ /** Post-conversation debounce interval in ms. Default 5 minutes. */
21
+ debounceMs?: number;
22
+ /** Background sync interval in ms. Default 30 minutes. */
23
+ backgroundIntervalMs?: number;
24
+ /** Called before sync starts. Return false to cancel. */
25
+ onSyncStart?: (source: TriggerSource) => boolean | void;
26
+ /** Called after sync completes or fails. */
27
+ onSyncEnd?: (source: TriggerSource, result: SyncResult) => void;
28
+ /** Register the background task. Null in test environments. */
29
+ registerBackgroundTask?: (taskName: string, intervalMs: number) => Promise<void>;
30
+ /** Unregister the background task. */
31
+ unregisterBackgroundTask?: (taskName: string) => Promise<void>;
32
+ }
33
+ export interface SyncResult {
34
+ success: boolean;
35
+ source: TriggerSource;
36
+ pushed?: number;
37
+ pulled?: number;
38
+ error?: string;
39
+ }
40
+ export interface SyncTriggers {
41
+ /** Fire when app comes to foreground. */
42
+ onForeground(): Promise<SyncResult>;
43
+ /** Fire when a conversation ends or goes idle. Debounced. */
44
+ onConversationIdle(): void;
45
+ /** Fire for manual "Sync Now" from settings. */
46
+ syncNow(): Promise<SyncResult>;
47
+ /** Fire from silent push notification. */
48
+ onPushNotification(): Promise<SyncResult>;
49
+ /** Register background task. Call once at boot. */
50
+ registerBackground(): Promise<void>;
51
+ /** Unregister background task. Call on teardown. */
52
+ unregisterBackground(): Promise<void>;
53
+ /** Execute the sync cycle (used by background task runner). */
54
+ executeSync(source: TriggerSource): Promise<SyncResult>;
55
+ /** Cancel any pending debounce timer. */
56
+ dispose(): void;
57
+ }
58
+ export declare const SYNC_TASK_NAME = "fenix-background-sync";
59
+ export declare function createSyncTriggers(config: SyncTriggerConfig): SyncTriggers;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Calendar tool adapter — wraps expo-calendar for the kernel's ToolHandler.
3
+ * Requests permission on first use, not at app launch.
4
+ */
5
+ export interface CalendarAdapter {
6
+ requestPermissions(): Promise<{
7
+ status: string;
8
+ }>;
9
+ getCalendarsAsync(): Promise<Array<{
10
+ id: string;
11
+ title: string;
12
+ }>>;
13
+ getEventsAsync(calendarIds: string[], startDate: Date, endDate: Date): Promise<CalendarEvent[]>;
14
+ createEventAsync(calendarId: string, details: Record<string, unknown>): Promise<string>;
15
+ }
16
+ export interface CalendarEvent {
17
+ id: string;
18
+ title: string;
19
+ startDate: string;
20
+ endDate: string;
21
+ location?: string;
22
+ notes?: string;
23
+ }
24
+ export declare function createCalendarTool(calendar: CalendarAdapter): {
25
+ name: "device.calendar";
26
+ description: string;
27
+ parameters: {
28
+ action: {
29
+ type: "string";
30
+ description: string;
31
+ required: boolean;
32
+ };
33
+ startDate: {
34
+ type: "string";
35
+ description: string;
36
+ };
37
+ endDate: {
38
+ type: "string";
39
+ description: string;
40
+ };
41
+ title: {
42
+ type: "string";
43
+ description: string;
44
+ };
45
+ location: {
46
+ type: "string";
47
+ description: string;
48
+ };
49
+ query: {
50
+ type: "string";
51
+ description: string;
52
+ };
53
+ };
54
+ handler: (params: Record<string, unknown>) => Promise<{
55
+ error: string;
56
+ events?: undefined;
57
+ created?: undefined;
58
+ eventId?: undefined;
59
+ } | {
60
+ events: {
61
+ id: string;
62
+ title: string;
63
+ start: string;
64
+ end: string;
65
+ location: string | undefined;
66
+ }[];
67
+ error?: undefined;
68
+ created?: undefined;
69
+ eventId?: undefined;
70
+ } | {
71
+ created: boolean;
72
+ eventId: string;
73
+ error?: undefined;
74
+ events?: undefined;
75
+ }>;
76
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Camera tool adapter — wraps expo-camera for the kernel's ToolHandler.
3
+ */
4
+ export interface CameraAdapter {
5
+ requestCameraPermissions(): Promise<{
6
+ status: string;
7
+ }>;
8
+ takePicture(): Promise<{
9
+ uri: string;
10
+ width: number;
11
+ height: number;
12
+ }>;
13
+ pickImage(): Promise<{
14
+ uri: string;
15
+ width: number;
16
+ height: number;
17
+ } | null>;
18
+ }
19
+ export declare function createCameraTool(camera: CameraAdapter): {
20
+ name: "device.camera";
21
+ description: string;
22
+ parameters: {
23
+ action: {
24
+ type: "string";
25
+ description: string;
26
+ required: boolean;
27
+ };
28
+ };
29
+ handler: (params: Record<string, unknown>) => Promise<{
30
+ error: string;
31
+ uri?: undefined;
32
+ width?: undefined;
33
+ height?: undefined;
34
+ } | {
35
+ uri: string;
36
+ width: number;
37
+ height: number;
38
+ error?: undefined;
39
+ }>;
40
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Contacts tool adapter — wraps expo-contacts for the kernel's ToolHandler.
3
+ */
4
+ export interface ContactsAdapter {
5
+ requestPermissions(): Promise<{
6
+ status: string;
7
+ }>;
8
+ getContactsAsync(opts: {
9
+ fields: string[];
10
+ pageSize?: number;
11
+ }): Promise<{
12
+ data: Contact[];
13
+ }>;
14
+ }
15
+ export interface Contact {
16
+ id: string;
17
+ name?: string;
18
+ firstName?: string;
19
+ lastName?: string;
20
+ phoneNumbers?: Array<{
21
+ number: string;
22
+ label?: string;
23
+ }>;
24
+ emails?: Array<{
25
+ email: string;
26
+ label?: string;
27
+ }>;
28
+ }
29
+ export declare function createContactsTool(contacts: ContactsAdapter): {
30
+ name: "device.contacts";
31
+ description: string;
32
+ parameters: {
33
+ action: {
34
+ type: "string";
35
+ description: string;
36
+ required: boolean;
37
+ };
38
+ query: {
39
+ type: "string";
40
+ description: string;
41
+ };
42
+ limit: {
43
+ type: "number";
44
+ description: string;
45
+ };
46
+ };
47
+ handler: (params: Record<string, unknown>) => Promise<{
48
+ error: string;
49
+ contacts?: undefined;
50
+ } | {
51
+ contacts: {
52
+ id: string;
53
+ name: string;
54
+ phone: string | null;
55
+ email: string | null;
56
+ }[];
57
+ error?: undefined;
58
+ }>;
59
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Location tool adapter — wraps expo-location for the kernel's ToolHandler.
3
+ */
4
+ export interface LocationAdapter {
5
+ requestForegroundPermissions(): Promise<{
6
+ status: string;
7
+ }>;
8
+ getCurrentPosition(): Promise<{
9
+ coords: {
10
+ latitude: number;
11
+ longitude: number;
12
+ altitude: number | null;
13
+ };
14
+ }>;
15
+ reverseGeocode(lat: number, lng: number): Promise<Array<{
16
+ city: string | null;
17
+ region: string | null;
18
+ country: string | null;
19
+ street: string | null;
20
+ }>>;
21
+ }
22
+ export declare function createLocationTool(location: LocationAdapter): {
23
+ name: "device.location";
24
+ description: string;
25
+ parameters: {
26
+ action: {
27
+ type: "string";
28
+ description: string;
29
+ required: boolean;
30
+ };
31
+ latitude: {
32
+ type: "number";
33
+ description: string;
34
+ };
35
+ longitude: {
36
+ type: "number";
37
+ description: string;
38
+ };
39
+ };
40
+ handler: (params: Record<string, unknown>) => Promise<{
41
+ city: string | null;
42
+ region: string | null;
43
+ country: string | null;
44
+ street: string | null;
45
+ } | {
46
+ error: string;
47
+ latitude?: undefined;
48
+ longitude?: undefined;
49
+ altitude?: undefined;
50
+ address?: undefined;
51
+ } | {
52
+ latitude: number;
53
+ longitude: number;
54
+ altitude: number | null;
55
+ address: string | null;
56
+ error?: undefined;
57
+ }>;
58
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Notifications tool adapter — wraps expo-notifications for the kernel's ToolHandler.
3
+ */
4
+ export interface NotificationsAdapter {
5
+ requestPermissions(): Promise<{
6
+ status: string;
7
+ }>;
8
+ scheduleNotification(content: {
9
+ title: string;
10
+ body: string;
11
+ data?: Record<string, unknown>;
12
+ }, trigger: {
13
+ seconds: number;
14
+ } | null): Promise<string>;
15
+ cancelNotification(id: string): Promise<void>;
16
+ getPendingNotifications(): Promise<Array<{
17
+ identifier: string;
18
+ content: {
19
+ title: string;
20
+ body: string;
21
+ };
22
+ }>>;
23
+ }
24
+ export declare function createNotificationsTool(notifications: NotificationsAdapter): {
25
+ name: "device.notifications";
26
+ description: string;
27
+ parameters: {
28
+ action: {
29
+ type: "string";
30
+ description: string;
31
+ required: boolean;
32
+ };
33
+ title: {
34
+ type: "string";
35
+ description: string;
36
+ };
37
+ body: {
38
+ type: "string";
39
+ description: string;
40
+ };
41
+ delaySeconds: {
42
+ type: "number";
43
+ description: string;
44
+ };
45
+ notificationId: {
46
+ type: "string";
47
+ description: string;
48
+ };
49
+ };
50
+ handler: (params: Record<string, unknown>) => Promise<{
51
+ error: string;
52
+ scheduled?: undefined;
53
+ notificationId?: undefined;
54
+ notifications?: undefined;
55
+ cancelled?: undefined;
56
+ } | {
57
+ scheduled: boolean;
58
+ notificationId: string;
59
+ error?: undefined;
60
+ notifications?: undefined;
61
+ cancelled?: undefined;
62
+ } | {
63
+ notifications: {
64
+ id: string;
65
+ title: string;
66
+ body: string;
67
+ }[];
68
+ error?: undefined;
69
+ scheduled?: undefined;
70
+ notificationId?: undefined;
71
+ cancelled?: undefined;
72
+ } | {
73
+ cancelled: boolean;
74
+ error?: undefined;
75
+ scheduled?: undefined;
76
+ notificationId?: undefined;
77
+ notifications?: undefined;
78
+ }>;
79
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Mobile tool registry — registers the mobile-specific tool set.
3
+ * Checks connectivity before exposing online-only tools.
4
+ */
5
+ export interface MobileTool {
6
+ name: string;
7
+ description: string;
8
+ parameters?: Record<string, {
9
+ type: string;
10
+ description?: string;
11
+ required?: boolean;
12
+ }>;
13
+ handler: (params: Record<string, unknown>) => Promise<unknown>;
14
+ /** If true, this tool requires network connectivity. */
15
+ requiresNetwork?: boolean;
16
+ }
17
+ export interface MobileToolRegistryConfig {
18
+ tools: MobileTool[];
19
+ isOnline?: () => boolean;
20
+ }
21
+ export declare function createMobileToolRegistry(config: MobileToolRegistryConfig): {
22
+ listAvailable: () => MobileTool[];
23
+ get: (name: string) => MobileTool | undefined;
24
+ isExcluded: (name: string) => boolean;
25
+ EXCLUDED: string[];
26
+ };
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Reminders tool adapter — wraps expo-calendar reminders API (iOS).
3
+ */
4
+ export interface RemindersAdapter {
5
+ requestRemindersPermissions(): Promise<{
6
+ status: string;
7
+ }>;
8
+ getRemindersAsync(calendarIds: string[]): Promise<Reminder[]>;
9
+ createReminderAsync(calendarId: string, details: Record<string, unknown>): Promise<string>;
10
+ getCalendarsAsync(entityType: string): Promise<Array<{
11
+ id: string;
12
+ title: string;
13
+ }>>;
14
+ }
15
+ export interface Reminder {
16
+ id: string;
17
+ title: string;
18
+ dueDate?: string;
19
+ completed: boolean;
20
+ notes?: string;
21
+ }
22
+ export declare function createRemindersTool(reminders: RemindersAdapter): {
23
+ name: "device.reminders";
24
+ description: string;
25
+ parameters: {
26
+ action: {
27
+ type: "string";
28
+ description: string;
29
+ required: boolean;
30
+ };
31
+ title: {
32
+ type: "string";
33
+ description: string;
34
+ };
35
+ dueDate: {
36
+ type: "string";
37
+ description: string;
38
+ };
39
+ notes: {
40
+ type: "string";
41
+ description: string;
42
+ };
43
+ };
44
+ handler: (params: Record<string, unknown>) => Promise<{
45
+ error: string;
46
+ reminders?: undefined;
47
+ created?: undefined;
48
+ reminderId?: undefined;
49
+ } | {
50
+ reminders: {
51
+ id: string;
52
+ title: string;
53
+ dueDate: string | null;
54
+ completed: boolean;
55
+ }[];
56
+ error?: undefined;
57
+ created?: undefined;
58
+ reminderId?: undefined;
59
+ } | {
60
+ created: boolean;
61
+ reminderId: string;
62
+ error?: undefined;
63
+ reminders?: undefined;
64
+ }>;
65
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * XR Agent Service — persistent background service running the agent loop
3
+ * on Android XR glasses. Coordinates voice, vision, gestures, notifications,
4
+ * and the display adapter.
5
+ */
6
+ import { type VoiceInterfaceConfig, type VoiceInterface } from "./XRVoiceInterface.js";
7
+ import { type ContextCaptureConfig, type ContextCapture } from "./XRContextCapture.js";
8
+ import { type GestureHandlerConfig, type GestureHandler } from "./XRGestureHandler.js";
9
+ import { type NotificationBridgeConfig, type NotificationBridge } from "./XRNotificationBridge.js";
10
+ export interface XRAgentServiceConfig {
11
+ voice: VoiceInterfaceConfig;
12
+ context: ContextCaptureConfig;
13
+ gesture?: GestureHandlerConfig;
14
+ notification?: NotificationBridgeConfig;
15
+ /** Process a text query through the agent and return a response. */
16
+ processQuery: (text: string, imageData?: string) => Promise<string>;
17
+ }
18
+ export interface XRAgentService {
19
+ start(): void;
20
+ stop(): void;
21
+ isRunning(): boolean;
22
+ voice: VoiceInterface;
23
+ context: ContextCapture;
24
+ gesture: GestureHandler;
25
+ notification: NotificationBridge;
26
+ }
27
+ export declare function createXRAgentService(config: XRAgentServiceConfig): XRAgentService;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * XR Context Capture — camera frame capture for vision queries.
3
+ * "What am I looking at?" captures the current frame and routes
4
+ * through the vision provider.
5
+ */
6
+ export interface CameraFrame {
7
+ /** Base64-encoded JPEG image data. */
8
+ data: string;
9
+ /** Image width in pixels. */
10
+ width: number;
11
+ /** Image height in pixels. */
12
+ height: number;
13
+ /** Capture timestamp (ISO 8601). */
14
+ timestamp: string;
15
+ /** Camera source. */
16
+ source: "main" | "wide" | "depth";
17
+ }
18
+ export interface VisionProvider {
19
+ /** Describe what's in the image. */
20
+ describe(frame: CameraFrame, prompt?: string): Promise<string>;
21
+ /** Whether this provider works offline. */
22
+ isOffline: boolean;
23
+ }
24
+ export interface CameraAccess {
25
+ /** Capture a single frame from the glasses camera. */
26
+ captureFrame(source?: "main" | "wide"): Promise<CameraFrame>;
27
+ /** Check if camera permission is granted. */
28
+ hasPermission(): boolean;
29
+ /** Request camera permission. */
30
+ requestPermission(): Promise<boolean>;
31
+ }
32
+ export interface ContextCaptureConfig {
33
+ camera: CameraAccess;
34
+ visionProvider: VisionProvider;
35
+ /** Offline fallback vision provider (on-device model). */
36
+ offlineVisionProvider?: VisionProvider;
37
+ isOnline?: () => boolean;
38
+ }
39
+ export interface ContextCapture {
40
+ /** Capture current view and describe it. */
41
+ describeView(prompt?: string): Promise<string>;
42
+ /** Capture a frame without description (for later processing). */
43
+ captureFrame(): Promise<CameraFrame>;
44
+ /** Check if vision queries are available. */
45
+ isAvailable(): boolean;
46
+ }
47
+ export declare function createContextCapture(config: ContextCaptureConfig): ContextCapture;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * XR Gesture Handler — touchpad and head gesture input for Android XR glasses.
3
+ *
4
+ * Android XR glasses hardware:
5
+ * - Touchpad: right temple, swipe (up/down/left/right) + tap + long press
6
+ * - Camera button: short press = photo, long press = agent activation
7
+ * - Power button: press = sleep/wake
8
+ * - Head gestures: nod (yes), shake (no), tilt (dismiss)
9
+ */
10
+ export type TouchpadGesture = "tap" | "double_tap" | "long_press" | "swipe_up" | "swipe_down" | "swipe_left" | "swipe_right";
11
+ export type HeadGesture = "nod" | "shake" | "tilt_left" | "tilt_right";
12
+ export type HardwareButton = "camera_short" | "camera_long";
13
+ export type XRInputEvent = {
14
+ source: "touchpad";
15
+ gesture: TouchpadGesture;
16
+ timestamp: number;
17
+ } | {
18
+ source: "head";
19
+ gesture: HeadGesture;
20
+ timestamp: number;
21
+ } | {
22
+ source: "button";
23
+ gesture: HardwareButton;
24
+ timestamp: number;
25
+ };
26
+ export type XRAction = "activate_agent" | "send_message" | "cancel" | "scroll_up" | "scroll_down" | "dismiss" | "confirm" | "deny" | "pin_card" | "none";
27
+ export interface GestureMapping {
28
+ touchpad: Record<TouchpadGesture, XRAction>;
29
+ head: Record<HeadGesture, XRAction>;
30
+ button: Record<HardwareButton, XRAction>;
31
+ }
32
+ export interface GestureHandlerConfig {
33
+ mapping?: Partial<GestureMapping>;
34
+ onAction?: (action: XRAction, event: XRInputEvent) => void;
35
+ }
36
+ export interface GestureHandler {
37
+ handleEvent(event: XRInputEvent): XRAction;
38
+ getMapping(): GestureMapping;
39
+ setMapping(updates: Partial<GestureMapping>): void;
40
+ }
41
+ export declare function createGestureHandler(config?: GestureHandlerConfig): GestureHandler;