@glassly/engine 0.4.0-dev.1038 → 0.4.0-dev.1039

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 (113) hide show
  1. package/build/engine.d.ts +1 -1
  2. package/build/engine.d.ts.map +1 -1
  3. package/build/engine.js +1 -1
  4. package/build/engine.js.map +1 -1
  5. package/build/facades/glasses.js +1 -1
  6. package/build/facades/glasses.js.map +1 -1
  7. package/build/facades/providerKeys.d.ts +1 -1
  8. package/build/facades/providerKeys.js +1 -1
  9. package/build/facades/providerKeys.js.map +1 -1
  10. package/build/generated/releaseMetadata.js +3 -3
  11. package/build/generated/releaseMetadata.js.map +1 -1
  12. package/build/react/useMentraLiveOta.d.ts.map +1 -1
  13. package/build/react/useMentraLiveOta.js.map +1 -1
  14. package/build/runtime/config.d.ts.map +1 -1
  15. package/build/runtime/config.js.map +1 -1
  16. package/build/services/AiTierResolution.d.ts +1 -1
  17. package/build/services/AiTierResolution.d.ts.map +1 -1
  18. package/build/services/AiTierResolution.js.map +1 -1
  19. package/build/services/AutomaticReportResult.d.ts.map +1 -1
  20. package/build/services/AutomaticReportResult.js.map +1 -1
  21. package/build/services/GestureDotsService.js +1 -1
  22. package/build/services/GestureDotsService.js.map +1 -1
  23. package/build/services/HotspotOtaTransport.d.ts.map +1 -1
  24. package/build/services/HotspotOtaTransport.js.map +1 -1
  25. package/build/services/LocalMiniappRuntime.d.ts +5 -2
  26. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  27. package/build/services/LocalMiniappRuntime.js +53 -22
  28. package/build/services/LocalMiniappRuntime.js.map +1 -1
  29. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  30. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  31. package/build/services/NativeNavigationService.d.ts.map +1 -1
  32. package/build/services/NativeNavigationService.js.map +1 -1
  33. package/build/services/NavigationHandlers.d.ts +1 -1
  34. package/build/services/NavigationHandlers.js +2 -2
  35. package/build/services/NavigationHandlers.js.map +1 -1
  36. package/build/services/NavigationService.d.ts +2 -2
  37. package/build/services/NavigationService.d.ts.map +1 -1
  38. package/build/services/NavigationService.js +11 -11
  39. package/build/services/NavigationService.js.map +1 -1
  40. package/build/services/PairingIdentity.d.ts.map +1 -1
  41. package/build/services/PairingIdentity.js.map +1 -1
  42. package/build/services/PhoneCalendarService.d.ts.map +1 -1
  43. package/build/services/PhoneCalendarService.js.map +1 -1
  44. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  45. package/build/services/PhoneNotificationsSync.js +2 -1
  46. package/build/services/PhoneNotificationsSync.js.map +1 -1
  47. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  48. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  49. package/build/services/ProviderKeyValidation.d.ts +1 -1
  50. package/build/services/ProviderKeyValidation.js +1 -1
  51. package/build/services/ProviderKeyValidation.js.map +1 -1
  52. package/build/services/STTModelManager.d.ts.map +1 -1
  53. package/build/services/STTModelManager.js +1 -6
  54. package/build/services/STTModelManager.js.map +1 -1
  55. package/build/services/TranscriptionRouting.d.ts +3 -0
  56. package/build/services/TranscriptionRouting.d.ts.map +1 -1
  57. package/build/services/TranscriptionRouting.js +14 -0
  58. package/build/services/TranscriptionRouting.js.map +1 -1
  59. package/build/services/UIRouter.d.ts.map +1 -1
  60. package/build/services/UIRouter.js.map +1 -1
  61. package/build/services/gestureDotGlyphs.d.ts.map +1 -1
  62. package/build/services/gestureDotGlyphs.js.map +1 -1
  63. package/build/services/manifestActions.d.ts.map +1 -1
  64. package/build/services/manifestActions.js.map +1 -1
  65. package/build/services/notificationAppPayload.d.ts +14 -0
  66. package/build/services/notificationAppPayload.d.ts.map +1 -0
  67. package/build/services/notificationAppPayload.js +15 -0
  68. package/build/services/notificationAppPayload.js.map +1 -0
  69. package/build/services/settingsBridge.d.ts.map +1 -1
  70. package/build/services/settingsBridge.js.map +1 -1
  71. package/build/stores/appVisibility.d.ts.map +1 -1
  72. package/build/stores/appVisibility.js.map +1 -1
  73. package/build/stores/gallerySync.d.ts.map +1 -1
  74. package/build/stores/gallerySync.js.map +1 -1
  75. package/build/stores/settings.js +1 -1
  76. package/build/stores/settings.js.map +1 -1
  77. package/build/utils/display/scene/svgPath.js.map +1 -1
  78. package/build/utils/memory/search.d.ts.map +1 -1
  79. package/build/utils/memory/search.js +17 -7
  80. package/build/utils/memory/search.js.map +1 -1
  81. package/package.json +7 -7
  82. package/src/engine.ts +1 -1
  83. package/src/facades/glasses.ts +1 -1
  84. package/src/facades/providerKeys.ts +1 -1
  85. package/src/generated/releaseMetadata.ts +3 -3
  86. package/src/react/useMentraLiveOta.ts +1 -4
  87. package/src/runtime/config.ts +1 -6
  88. package/src/services/AiTierResolution.ts +1 -1
  89. package/src/services/AutomaticReportResult.ts +1 -3
  90. package/src/services/GestureDotsService.ts +1 -1
  91. package/src/services/HotspotOtaTransport.ts +1 -4
  92. package/src/services/LocalMiniappRuntime.ts +65 -23
  93. package/src/services/LocalSttFallbackCoordinator.ts +1 -5
  94. package/src/services/NativeNavigationService.ts +1 -2
  95. package/src/services/NavigationHandlers.ts +2 -2
  96. package/src/services/NavigationService.ts +12 -11
  97. package/src/services/PairingIdentity.ts +1 -3
  98. package/src/services/PhoneCalendarService.ts +1 -3
  99. package/src/services/PhoneNotificationsSync.ts +2 -1
  100. package/src/services/PhoneStreamCoordinator.ts +1 -2
  101. package/src/services/ProviderKeyValidation.ts +1 -1
  102. package/src/services/STTModelManager.ts +1 -6
  103. package/src/services/TranscriptionRouting.ts +18 -0
  104. package/src/services/UIRouter.ts +3 -9
  105. package/src/services/gestureDotGlyphs.ts +10 -5
  106. package/src/services/manifestActions.ts +2 -1
  107. package/src/services/notificationAppPayload.ts +15 -0
  108. package/src/services/settingsBridge.ts +1 -2
  109. package/src/stores/appVisibility.ts +2 -5
  110. package/src/stores/gallerySync.ts +1 -7
  111. package/src/stores/settings.ts +1 -1
  112. package/src/utils/display/scene/svgPath.ts +1 -1
  113. package/src/utils/memory/search.ts +17 -7
@@ -1 +1 @@
1
- {"version":3,"file":"svgPath.js","sourceRoot":"","sources":["../../../../src/utils/display/scene/svgPath.ts"],"names":[],"mappings":"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","sourcesContent":["/** SVG path compiler shared by scene validation and native wire encoding.\n * Ported from g2flash revision 21; no DOM, Node or mobile-platform dependencies. */\nconst u16 = (v: number) => [v & 255, (v >>> 8) & 255]\nfunction integer(v: number, min: number, max: number, name: string): number {\n if (!Number.isInteger(v) || v < min || v > max) throw new Error(`${name} outside ${min}..${max}: ${v}`)\n return v\n}\n/** SVG d subset: absolute/relative M L H V Q C S T Z; implicit repetitions.\n * Unsupported syntax is rejected. Each filled contour must explicitly close. */\nexport function svgPath(d: string): number[] {\n const tokens = d.match(/[a-zA-Z]|[-+]?(?:\\d*\\.\\d+|\\d+\\.?\\d*)(?:[eE][-+]?\\d+)?/g) ?? []\n const residue = d.replace(/[a-zA-Z]|[-+]?(?:\\d*\\.\\d+|\\d+\\.?\\d*)(?:[eE][-+]?\\d+)?/g, \"\")\n if (/[^\\s,]/.test(residue)) throw new Error(\"Invalid SVG path syntax\")\n let i = 0,\n cmd = \"\",\n x = 0,\n y = 0,\n sx = 0,\n sy = 0,\n open = false,\n previous = \"\"\n let cx = 0,\n cy = 0\n const out: number[] = []\n const emit = (op: number, ...coords: number[]) => {\n out.push(op, ...coords.flatMap((v) => u16(integer(Math.round(v * 16), -32768, 32767, \"Q4 coordinate\"))))\n }\n const number = () => {\n if (i >= tokens.length || /^[a-z]$/i.test(tokens[i])) throw new Error(\"Missing SVG coordinate\")\n const v = Number(tokens[i++])\n if (!Number.isFinite(v)) throw new Error(\"Invalid number\")\n return v\n }\n while (i < tokens.length) {\n if (/^[a-z]$/i.test(tokens[i])) cmd = tokens[i++]\n if (!cmd || !/^[MLHVQCSTZ]$/i.test(cmd)) throw new Error(`Unsupported SVG command: ${cmd}`)\n const op = cmd.toUpperCase(),\n rel = cmd !== op\n const pair = (): [number, number] => [number() + (rel ? x : 0), number() + (rel ? y : 0)]\n if (op === \"Z\") {\n if (!open) throw new Error(\"Z without an open contour\")\n emit(4)\n x = sx\n y = sy\n open = false\n previous = \"Z\"\n cmd = \"\"\n continue\n }\n if (op !== \"M\" && !open) throw new Error(\"Path must start with M\")\n if (op === \"M\") {\n if (open) throw new Error(\"Filled contours must close with Z before another M\")\n ;[x, y] = pair()\n sx = x\n sy = y\n open = true\n emit(0, x, y)\n cmd = rel ? \"l\" : \"L\"\n } else if (op === \"L\" || op === \"H\" || op === \"V\") {\n if (op === \"L\") [x, y] = pair()\n else if (op === \"H\") x = number() + (rel ? x : 0)\n else y = number() + (rel ? y : 0)\n emit(1, x, y)\n } else if (op === \"Q\" || op === \"T\") {\n const c = op === \"Q\" ? pair() : previous === \"Q\" || previous === \"T\" ? [2 * x - cx, 2 * y - cy] : [x, y]\n const end = pair()\n emit(2, ...c, ...end)\n ;[cx, cy] = c\n ;[x, y] = end\n } else {\n const a = op === \"C\" ? pair() : previous === \"C\" || previous === \"S\" ? [2 * x - cx, 2 * y - cy] : [x, y]\n const b = pair(),\n end = pair()\n emit(3, ...a, ...b, ...end)\n ;[cx, cy] = b\n ;[x, y] = end\n }\n previous = op\n }\n if (open || !out.length) throw new Error(\"Expected explicitly closed filled path\")\n return out\n}\n\n/** Check the same fixed-point subdivision and budgets as revision 21 firmware. */\nexport function compileSvgPath(d: string): {commands: number[]; edges: number} {\n if (typeof d !== \"string\" || d.length > 65536) throw new Error(\"Invalid SVG path data\")\n const commands = svgPath(d)\n if (commands.length > 8192) throw new Error(\"SVG path exceeds 8192 command bytes\")\n let edges = 0,\n count = 0,\n x = 0,\n y = 0,\n sx = 0,\n sy = 0\n const edge = (ax: number, ay: number, bx: number, by: number) => {\n if ((ax !== bx || ay !== by) && ++edges > 512) throw new Error(\"SVG path exceeds 512 compiled edges\")\n }\n const curve = (p: number[], depth: number): void => {\n const u = [\n 3 * p[2] - 2 * p[0] - p[6],\n 3 * p[3] - 2 * p[1] - p[7],\n 3 * p[4] - 2 * p[6] - p[0],\n 3 * p[5] - 2 * p[7] - p[1],\n ]\n if (u.every((v) => Math.abs(v) <= 16)) {\n edge(p[0], p[1], p[6], p[7])\n return\n }\n if (depth === 8) throw new Error(\"SVG curve exceeds subdivision limit\")\n const a = new Array<number>(8),\n b = new Array<number>(8)\n for (let k = 0; k < 2; k++) {\n const ab = Math.trunc((p[k] + p[k + 2]) / 2),\n bc = Math.trunc((p[k + 2] + p[k + 4]) / 2),\n cd = Math.trunc((p[k + 4] + p[k + 6]) / 2)\n const abc = Math.trunc((ab + bc) / 2),\n bcd = Math.trunc((bc + cd) / 2),\n mid = Math.trunc((abc + bcd) / 2)\n a[k] = p[k]\n a[k + 2] = ab\n a[k + 4] = abc\n a[k + 6] = mid\n b[k] = mid\n b[k + 2] = bcd\n b[k + 4] = cd\n b[k + 6] = p[k + 6]\n }\n curve(a, depth + 1)\n curve(b, depth + 1)\n }\n for (let i = 0; i < commands.length; ) {\n const op = commands[i++],\n pairs = op === 4 ? 0 : op === 3 ? 3 : op === 2 ? 2 : 1\n if (++count > 1024) throw new Error(\"SVG path exceeds 1024 commands\")\n const p = [x, y]\n for (let k = 0; k < pairs * 2; k++, i += 2) p.push(((commands[i] | (commands[i + 1] << 8)) << 16) >> 16)\n if (op === 0) {\n x = sx = p[2]\n y = sy = p[3]\n } else if (op === 4) {\n edge(x, y, sx, sy)\n x = sx\n y = sy\n } else if (op === 1) {\n edge(x, y, p[2], p[3])\n x = p[2]\n y = p[3]\n } else {\n if (op === 2) {\n p[6] = p[4]\n p[7] = p[5]\n for (let k = 0; k < 2; k++) {\n p[k + 4] = Math.trunc((p[k + 6] + 2 * p[k + 2]) / 3)\n p[k + 2] = Math.trunc((p[k] + 2 * p[k + 2]) / 3)\n }\n }\n curve(p, 0)\n x = p[6]\n y = p[7]\n }\n }\n return {commands, edges}\n}\n"]}
1
+ {"version":3,"file":"svgPath.js","sourceRoot":"","sources":["../../../../src/utils/display/scene/svgPath.ts"],"names":[],"mappings":"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","sourcesContent":["/** SVG path compiler shared by scene validation and native wire encoding.\n * Ported from g2flash revision 21; no DOM, Node or mobile-platform dependencies. */\nconst u16 = (v: number) => [v & 255, (v >>> 8) & 255]\nfunction integer(v: number, min: number, max: number, name: string): number {\n if (!Number.isInteger(v) || v < min || v > max) throw new Error(`${name} outside ${min}..${max}: ${v}`)\n return v\n}\n/** SVG d subset: absolute/relative M L H V Q C S T Z; implicit repetitions.\n * Unsupported syntax is rejected. Each filled contour must explicitly close. */\nexport function svgPath(d: string): number[] {\n const tokens = d.match(/[a-zA-Z]|[-+]?(?:\\d*\\.\\d+|\\d+\\.?\\d*)(?:[eE][-+]?\\d+)?/g) ?? []\n const residue = d.replace(/[a-zA-Z]|[-+]?(?:\\d*\\.\\d+|\\d+\\.?\\d*)(?:[eE][-+]?\\d+)?/g, \"\")\n if (/[^\\s,]/.test(residue)) throw new Error(\"Invalid SVG path syntax\")\n let i = 0,\n cmd = \"\",\n x = 0,\n y = 0,\n sx = 0,\n sy = 0,\n open = false,\n previous = \"\"\n let cx = 0,\n cy = 0\n const out: number[] = []\n const emit = (op: number, ...coords: number[]) => {\n out.push(op, ...coords.flatMap((v) => u16(integer(Math.round(v * 16), -32768, 32767, \"Q4 coordinate\"))))\n }\n const number = () => {\n if (i >= tokens.length || /^[a-z]$/i.test(tokens[i])) throw new Error(\"Missing SVG coordinate\")\n const v = Number(tokens[i++])\n if (!Number.isFinite(v)) throw new Error(\"Invalid number\")\n return v\n }\n while (i < tokens.length) {\n if (/^[a-z]$/i.test(tokens[i])) cmd = tokens[i++]\n if (!cmd || !/^[MLHVQCSTZ]$/i.test(cmd)) throw new Error(`Unsupported SVG command: ${cmd}`)\n const op = cmd.toUpperCase(),\n rel = cmd !== op\n const pair = (): [number, number] => [number() + (rel ? x : 0), number() + (rel ? y : 0)]\n if (op === \"Z\") {\n if (!open) throw new Error(\"Z without an open contour\")\n emit(4)\n x = sx\n y = sy\n open = false\n previous = \"Z\"\n cmd = \"\"\n continue\n }\n if (op !== \"M\" && !open) throw new Error(\"Path must start with M\")\n if (op === \"M\") {\n if (open) throw new Error(\"Filled contours must close with Z before another M\")\n ;[x, y] = pair()\n sx = x\n sy = y\n open = true\n emit(0, x, y)\n cmd = rel ? \"l\" : \"L\"\n } else if (op === \"L\" || op === \"H\" || op === \"V\") {\n if (op === \"L\") [x, y] = pair()\n else if (op === \"H\") x = number() + (rel ? x : 0)\n else y = number() + (rel ? y : 0)\n emit(1, x, y)\n } else if (op === \"Q\" || op === \"T\") {\n const c = op === \"Q\" ? pair() : previous === \"Q\" || previous === \"T\" ? [2 * x - cx, 2 * y - cy] : [x, y]\n const end = pair()\n emit(2, ...c, ...end)\n ;[cx, cy] = c\n ;[x, y] = end\n } else {\n const a = op === \"C\" ? pair() : previous === \"C\" || previous === \"S\" ? [2 * x - cx, 2 * y - cy] : [x, y]\n const b = pair(),\n end = pair()\n emit(3, ...a, ...b, ...end)\n ;[cx, cy] = b\n ;[x, y] = end\n }\n previous = op\n }\n if (open || !out.length) throw new Error(\"Expected explicitly closed filled path\")\n return out\n}\n\n/** Check the same fixed-point subdivision and budgets as revision 21 firmware. */\nexport function compileSvgPath(d: string): {commands: number[]; edges: number} {\n if (typeof d !== \"string\" || d.length > 65536) throw new Error(\"Invalid SVG path data\")\n const commands = svgPath(d)\n if (commands.length > 8192) throw new Error(\"SVG path exceeds 8192 command bytes\")\n let edges = 0,\n count = 0,\n x = 0,\n y = 0,\n sx = 0,\n sy = 0\n const edge = (ax: number, ay: number, bx: number, by: number) => {\n if ((ax !== bx || ay !== by) && ++edges > 512) throw new Error(\"SVG path exceeds 512 compiled edges\")\n }\n const curve = (p: number[], depth: number): void => {\n const u = [\n 3 * p[2] - 2 * p[0] - p[6],\n 3 * p[3] - 2 * p[1] - p[7],\n 3 * p[4] - 2 * p[6] - p[0],\n 3 * p[5] - 2 * p[7] - p[1],\n ]\n if (u.every((v) => Math.abs(v) <= 16)) {\n edge(p[0], p[1], p[6], p[7])\n return\n }\n if (depth === 8) throw new Error(\"SVG curve exceeds subdivision limit\")\n const a = new Array<number>(8),\n b = new Array<number>(8)\n for (let k = 0; k < 2; k++) {\n const ab = Math.trunc((p[k] + p[k + 2]) / 2),\n bc = Math.trunc((p[k + 2] + p[k + 4]) / 2),\n cd = Math.trunc((p[k + 4] + p[k + 6]) / 2)\n const abc = Math.trunc((ab + bc) / 2),\n bcd = Math.trunc((bc + cd) / 2),\n mid = Math.trunc((abc + bcd) / 2)\n a[k] = p[k]\n a[k + 2] = ab\n a[k + 4] = abc\n a[k + 6] = mid\n b[k] = mid\n b[k + 2] = bcd\n b[k + 4] = cd\n b[k + 6] = p[k + 6]\n }\n curve(a, depth + 1)\n curve(b, depth + 1)\n }\n for (let i = 0; i < commands.length;) {\n const op = commands[i++],\n pairs = op === 4 ? 0 : op === 3 ? 3 : op === 2 ? 2 : 1\n if (++count > 1024) throw new Error(\"SVG path exceeds 1024 commands\")\n const p = [x, y]\n for (let k = 0; k < pairs * 2; k++, i += 2) p.push(((commands[i] | (commands[i + 1] << 8)) << 16) >> 16)\n if (op === 0) {\n x = sx = p[2]\n y = sy = p[3]\n } else if (op === 4) {\n edge(x, y, sx, sy)\n x = sx\n y = sy\n } else if (op === 1) {\n edge(x, y, p[2], p[3])\n x = p[2]\n y = p[3]\n } else {\n if (op === 2) {\n p[6] = p[4]\n p[7] = p[5]\n for (let k = 0; k < 2; k++) {\n p[k + 4] = Math.trunc((p[k + 6] + 2 * p[k + 2]) / 3)\n p[k + 2] = Math.trunc((p[k] + 2 * p[k + 2]) / 3)\n }\n }\n curve(p, 0)\n x = p[6]\n y = p[7]\n }\n }\n return {commands, edges}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/utils/memory/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,qEAAqE;IACrE,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAKD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,qBAAqB,EACjE,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,CAAC,EAAE,iBAAiB,GACnB,kBAAkB,CAAC,CAAC,CAAC,CAqBvB;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAO5D;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAO/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAqB7E;AAWD,+CAA+C;AAC/C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc5C"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/utils/memory/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,qEAAqE;IACrE,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAKD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,qBAAqB,EACjE,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,CAAC,EAAE,iBAAiB,GACnB,kBAAkB,CAAC,CAAC,CAAC,CAmBvB;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAO5D;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAO/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAqB7E;AAuBD,+CAA+C;AAC/C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc5C"}
@@ -31,9 +31,7 @@ export function searchMemoryEntries(entries, q) {
31
31
  const hi = upperBound(entries, until); // exclusive
32
32
  const windowCount = Math.max(0, hi - lo);
33
33
  const needle = q.contains?.trim().toLowerCase() || null;
34
- const termWords = (q.terms ?? [])
35
- .map((t) => tokenize(t))
36
- .filter((words) => words.length > 0);
34
+ const termWords = (q.terms ?? []).map((t) => tokenize(t)).filter((words) => words.length > 0);
37
35
  const picked = [];
38
36
  for (let i = hi - 1; i >= lo && picked.length < q.limit; i--) {
39
37
  const e = entries[i];
@@ -123,11 +121,23 @@ export function editDistanceAtMost(a, b, max) {
123
121
  return prev[b.length] <= max;
124
122
  }
125
123
  const SOUNDEX_CODES = {
126
- b: "1", f: "1", p: "1", v: "1",
127
- c: "2", g: "2", j: "2", k: "2", q: "2", s: "2", x: "2", z: "2",
128
- d: "3", t: "3",
124
+ b: "1",
125
+ f: "1",
126
+ p: "1",
127
+ v: "1",
128
+ c: "2",
129
+ g: "2",
130
+ j: "2",
131
+ k: "2",
132
+ q: "2",
133
+ s: "2",
134
+ x: "2",
135
+ z: "2",
136
+ d: "3",
137
+ t: "3",
129
138
  l: "4",
130
- m: "5", n: "5",
139
+ m: "5",
140
+ n: "5",
131
141
  r: "6",
132
142
  };
133
143
  /** Classic Soundex. Empty input returns "". */
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/utils/memory/search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure memory-timeline search — the matching engine behind MemoryStore.query\n * and the assistant's get_transcripts tool.\n *\n * Lives outside MemoryStore so it is unit-testable and importable by the\n * assistant's eval harness (which replays the exact host semantics against a\n * mock corpus). Keep it dependency-free and runtime-neutral: it also runs\n * under bun for tests.\n *\n * TWO MATCH MODES, deliberately different:\n * - `contains`: exact case-insensitive substring — the pre-existing contract,\n * kept verbatim for callers that need precision (codes, URLs, exact phrases).\n * - `terms`: ANY-of term matching with per-word fuzziness. Speech-to-text\n * mangles proper nouns (\"Sompo\" for \"Sampo\", \"Korwin\" for \"Corwin\"), so a\n * term word matches a transcript token on exact/substring, small edit\n * distance, OR same Soundex key. A multi-word term (\"ring size\") requires\n * all of its words to match somewhere in the entry.\n *\n * The scan walks BACKWARDS from the newest in-window entry and stops at\n * `limit` matches: the caller keeps the most recent matches anyway, and the\n * common \"last 90 minutes\" query then touches dozens of entries instead of\n * the full 4000-entry timeline. Window bounds are found by binary search on\n * `at` (the timeline is maintained time-sorted).\n */\n\nexport interface MemorySearchableEntry {\n text: string\n at: number\n}\n\nexport interface MemorySearchQuery {\n /** Epoch ms lower bound (inclusive). */\n sinceMs?: number\n /** Epoch ms upper bound (inclusive). */\n untilMs?: number\n /** Exact case-insensitive substring filter. */\n contains?: string\n /** Fuzzy any-of terms (see file header). Combined with `contains` as AND. */\n terms?: string[]\n /** Max matches kept (newest win). Caller enforces its own cap. */\n limit: number\n}\n\nexport interface MemorySearchResult<T> {\n /** Matches in chronological order (newest last), at most `limit`. */\n entries: T[]\n /**\n * Entries inside the TIME window before keyword filtering. Lets the caller\n * tell \"keyword matched nothing\" apart from \"window itself is empty\" — the\n * distinction that saves an LLM a blind retry round.\n */\n windowCount: number\n}\n\n/** Tokenized lowercase text per entry, cached for the entry object's lifetime. */\nconst tokenCache = new WeakMap<object, string[]>()\n\nexport function searchMemoryEntries<T extends MemorySearchableEntry>(\n entries: readonly T[],\n q: MemorySearchQuery,\n): MemorySearchResult<T> {\n const since = q.sinceMs ?? 0\n const until = q.untilMs ?? Number.MAX_SAFE_INTEGER\n const lo = lowerBound(entries, since)\n const hi = upperBound(entries, until) // exclusive\n const windowCount = Math.max(0, hi - lo)\n\n const needle = q.contains?.trim().toLowerCase() || null\n const termWords = (q.terms ?? [])\n .map((t) => tokenize(t))\n .filter((words) => words.length > 0)\n\n const picked: T[] = []\n for (let i = hi - 1; i >= lo && picked.length < q.limit; i--) {\n const e = entries[i]\n if (needle && !e.text.toLowerCase().includes(needle)) continue\n if (termWords.length > 0 && !matchesAnyTerm(e, termWords)) continue\n picked.push(e)\n }\n picked.reverse()\n return {entries: picked, windowCount}\n}\n\n/** True when any term matches — a term matches iff ALL its words match a token. */\nfunction matchesAnyTerm(entry: MemorySearchableEntry, termWords: string[][]): boolean {\n let tokens = tokenCache.get(entry)\n if (!tokens) {\n tokens = tokenize(entry.text)\n tokenCache.set(entry, tokens)\n }\n outer: for (const words of termWords) {\n for (const word of words) {\n if (!tokens.some((tok) => fuzzyWordMatch(word, tok))) continue outer\n }\n return true\n }\n return false\n}\n\n/**\n * Does query word `w` match transcript token `t`?\n * - exact, or substring for w of 3+ chars (\"kestrel\" in \"kestrels\")\n * - for words of 5+ chars: bounded edit distance (1, or 2 for 7+ chars)\n * — catches one-vowel STT swaps (\"sompo\"/\"sampo\", \"korwin\"/\"corwin\").\n * 5 is the floor because at 4 chars a one-edit radius swallows unrelated\n * common words (\"code\"→\"mode\"); mistranscribed NAMES are almost always 5+.\n * - same Soundex key with similar length — catches phonetic respellings that\n * edit distance misses (\"warryn\"/\"warren\" style doublings)\n */\nexport function fuzzyWordMatch(w: string, t: string): boolean {\n if (w === t) return true\n if (w.length >= 3 && t.includes(w)) return true\n if (w.length < 5 || t.length < 4) return false\n const maxDist = w.length >= 7 ? 2 : 1\n if (Math.abs(w.length - t.length) <= maxDist && editDistanceAtMost(w, t, maxDist)) return true\n return Math.abs(w.length - t.length) <= 2 && soundex(w) === soundex(t)\n}\n\n/** Lowercase, strip diacritics, split on non-alphanumerics. */\nexport function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 0)\n}\n\n/**\n * Optimal-string-alignment edit distance, early-exited: returns whether\n * dist(a, b) <= max. Transpositions count as one edit (common in STT output).\n */\nexport function editDistanceAtMost(a: string, b: string, max: number): boolean {\n if (Math.abs(a.length - b.length) > max) return false\n let prev2: number[] | null = null\n let prev = Array.from({length: b.length + 1}, (_, j) => j)\n for (let i = 1; i <= a.length; i++) {\n const cur = [i]\n let rowMin = i\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\n let v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost)\n if (prev2 && i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n v = Math.min(v, prev2[j - 2] + 1)\n }\n cur.push(v)\n if (v < rowMin) rowMin = v\n }\n if (rowMin > max) return false\n prev2 = prev\n prev = cur\n }\n return prev[b.length] <= max\n}\n\nconst SOUNDEX_CODES: Record<string, string> = {\n b: \"1\", f: \"1\", p: \"1\", v: \"1\",\n c: \"2\", g: \"2\", j: \"2\", k: \"2\", q: \"2\", s: \"2\", x: \"2\", z: \"2\",\n d: \"3\", t: \"3\",\n l: \"4\",\n m: \"5\", n: \"5\",\n r: \"6\",\n}\n\n/** Classic Soundex. Empty input returns \"\". */\nexport function soundex(word: string): string {\n const w = word.toLowerCase().replace(/[^a-z]/g, \"\")\n if (!w) return \"\"\n let out = w[0].toUpperCase()\n let lastCode = SOUNDEX_CODES[w[0]] ?? \"\"\n for (let i = 1; i < w.length && out.length < 4; i++) {\n const ch = w[i]\n const code = SOUNDEX_CODES[ch] ?? \"\"\n // h/w are transparent: they don't reset the adjacent-duplicate rule.\n if (ch === \"h\" || ch === \"w\") continue\n if (code && code !== lastCode) out += code\n lastCode = code\n }\n return out.padEnd(4, \"0\")\n}\n\n/** First index with at >= value (entries time-sorted ascending). */\nfunction lowerBound(entries: readonly MemorySearchableEntry[], value: number): number {\n let lo = 0\n let hi = entries.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (entries[mid].at < value) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\n/** First index with at > value (i.e. exclusive end for an inclusive bound). */\nfunction upperBound(entries: readonly MemorySearchableEntry[], value: number): number {\n let lo = 0\n let hi = entries.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (entries[mid].at <= value) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n"]}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/utils/memory/search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure memory-timeline search — the matching engine behind MemoryStore.query\n * and the assistant's get_transcripts tool.\n *\n * Lives outside MemoryStore so it is unit-testable and importable by the\n * assistant's eval harness (which replays the exact host semantics against a\n * mock corpus). Keep it dependency-free and runtime-neutral: it also runs\n * under bun for tests.\n *\n * TWO MATCH MODES, deliberately different:\n * - `contains`: exact case-insensitive substring — the pre-existing contract,\n * kept verbatim for callers that need precision (codes, URLs, exact phrases).\n * - `terms`: ANY-of term matching with per-word fuzziness. Speech-to-text\n * mangles proper nouns (\"Sompo\" for \"Sampo\", \"Korwin\" for \"Corwin\"), so a\n * term word matches a transcript token on exact/substring, small edit\n * distance, OR same Soundex key. A multi-word term (\"ring size\") requires\n * all of its words to match somewhere in the entry.\n *\n * The scan walks BACKWARDS from the newest in-window entry and stops at\n * `limit` matches: the caller keeps the most recent matches anyway, and the\n * common \"last 90 minutes\" query then touches dozens of entries instead of\n * the full 4000-entry timeline. Window bounds are found by binary search on\n * `at` (the timeline is maintained time-sorted).\n */\n\nexport interface MemorySearchableEntry {\n text: string\n at: number\n}\n\nexport interface MemorySearchQuery {\n /** Epoch ms lower bound (inclusive). */\n sinceMs?: number\n /** Epoch ms upper bound (inclusive). */\n untilMs?: number\n /** Exact case-insensitive substring filter. */\n contains?: string\n /** Fuzzy any-of terms (see file header). Combined with `contains` as AND. */\n terms?: string[]\n /** Max matches kept (newest win). Caller enforces its own cap. */\n limit: number\n}\n\nexport interface MemorySearchResult<T> {\n /** Matches in chronological order (newest last), at most `limit`. */\n entries: T[]\n /**\n * Entries inside the TIME window before keyword filtering. Lets the caller\n * tell \"keyword matched nothing\" apart from \"window itself is empty\" — the\n * distinction that saves an LLM a blind retry round.\n */\n windowCount: number\n}\n\n/** Tokenized lowercase text per entry, cached for the entry object's lifetime. */\nconst tokenCache = new WeakMap<object, string[]>()\n\nexport function searchMemoryEntries<T extends MemorySearchableEntry>(\n entries: readonly T[],\n q: MemorySearchQuery,\n): MemorySearchResult<T> {\n const since = q.sinceMs ?? 0\n const until = q.untilMs ?? Number.MAX_SAFE_INTEGER\n const lo = lowerBound(entries, since)\n const hi = upperBound(entries, until) // exclusive\n const windowCount = Math.max(0, hi - lo)\n\n const needle = q.contains?.trim().toLowerCase() || null\n const termWords = (q.terms ?? []).map((t) => tokenize(t)).filter((words) => words.length > 0)\n\n const picked: T[] = []\n for (let i = hi - 1; i >= lo && picked.length < q.limit; i--) {\n const e = entries[i]\n if (needle && !e.text.toLowerCase().includes(needle)) continue\n if (termWords.length > 0 && !matchesAnyTerm(e, termWords)) continue\n picked.push(e)\n }\n picked.reverse()\n return {entries: picked, windowCount}\n}\n\n/** True when any term matches — a term matches iff ALL its words match a token. */\nfunction matchesAnyTerm(entry: MemorySearchableEntry, termWords: string[][]): boolean {\n let tokens = tokenCache.get(entry)\n if (!tokens) {\n tokens = tokenize(entry.text)\n tokenCache.set(entry, tokens)\n }\n outer: for (const words of termWords) {\n for (const word of words) {\n if (!tokens.some((tok) => fuzzyWordMatch(word, tok))) continue outer\n }\n return true\n }\n return false\n}\n\n/**\n * Does query word `w` match transcript token `t`?\n * - exact, or substring for w of 3+ chars (\"kestrel\" in \"kestrels\")\n * - for words of 5+ chars: bounded edit distance (1, or 2 for 7+ chars)\n * — catches one-vowel STT swaps (\"sompo\"/\"sampo\", \"korwin\"/\"corwin\").\n * 5 is the floor because at 4 chars a one-edit radius swallows unrelated\n * common words (\"code\"→\"mode\"); mistranscribed NAMES are almost always 5+.\n * - same Soundex key with similar length — catches phonetic respellings that\n * edit distance misses (\"warryn\"/\"warren\" style doublings)\n */\nexport function fuzzyWordMatch(w: string, t: string): boolean {\n if (w === t) return true\n if (w.length >= 3 && t.includes(w)) return true\n if (w.length < 5 || t.length < 4) return false\n const maxDist = w.length >= 7 ? 2 : 1\n if (Math.abs(w.length - t.length) <= maxDist && editDistanceAtMost(w, t, maxDist)) return true\n return Math.abs(w.length - t.length) <= 2 && soundex(w) === soundex(t)\n}\n\n/** Lowercase, strip diacritics, split on non-alphanumerics. */\nexport function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 0)\n}\n\n/**\n * Optimal-string-alignment edit distance, early-exited: returns whether\n * dist(a, b) <= max. Transpositions count as one edit (common in STT output).\n */\nexport function editDistanceAtMost(a: string, b: string, max: number): boolean {\n if (Math.abs(a.length - b.length) > max) return false\n let prev2: number[] | null = null\n let prev = Array.from({length: b.length + 1}, (_, j) => j)\n for (let i = 1; i <= a.length; i++) {\n const cur = [i]\n let rowMin = i\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\n let v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost)\n if (prev2 && i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n v = Math.min(v, prev2[j - 2] + 1)\n }\n cur.push(v)\n if (v < rowMin) rowMin = v\n }\n if (rowMin > max) return false\n prev2 = prev\n prev = cur\n }\n return prev[b.length] <= max\n}\n\nconst SOUNDEX_CODES: Record<string, string> = {\n b: \"1\",\n f: \"1\",\n p: \"1\",\n v: \"1\",\n c: \"2\",\n g: \"2\",\n j: \"2\",\n k: \"2\",\n q: \"2\",\n s: \"2\",\n x: \"2\",\n z: \"2\",\n d: \"3\",\n t: \"3\",\n l: \"4\",\n m: \"5\",\n n: \"5\",\n r: \"6\",\n}\n\n/** Classic Soundex. Empty input returns \"\". */\nexport function soundex(word: string): string {\n const w = word.toLowerCase().replace(/[^a-z]/g, \"\")\n if (!w) return \"\"\n let out = w[0].toUpperCase()\n let lastCode = SOUNDEX_CODES[w[0]] ?? \"\"\n for (let i = 1; i < w.length && out.length < 4; i++) {\n const ch = w[i]\n const code = SOUNDEX_CODES[ch] ?? \"\"\n // h/w are transparent: they don't reset the adjacent-duplicate rule.\n if (ch === \"h\" || ch === \"w\") continue\n if (code && code !== lastCode) out += code\n lastCode = code\n }\n return out.padEnd(4, \"0\")\n}\n\n/** First index with at >= value (entries time-sorted ascending). */\nfunction lowerBound(entries: readonly MemorySearchableEntry[], value: number): number {\n let lo = 0\n let hi = entries.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (entries[mid].at < value) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\n/** First index with at > value (i.e. exclusive end for an inclusive bound). */\nfunction upperBound(entries: readonly MemorySearchableEntry[], value: number): number {\n let lo = 0\n let hi = entries.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (entries[mid].at <= value) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/engine",
3
- "version": "0.4.0-dev.1038",
3
+ "version": "0.4.0-dev.1039",
4
4
  "description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -97,17 +97,17 @@
97
97
  "registry": "https://registry.npmjs.org/"
98
98
  },
99
99
  "dependencies": {
100
- "@glassly/bluetooth-sdk": "0.4.0-dev.1038",
101
- "@glassly/cloud-client": "0.4.0-dev.1038",
102
- "@glassly/cloud-protocol": "0.4.0-dev.1038",
103
- "@glassly/crust": "0.4.0-dev.1038",
104
- "@glassly/miniapp": "0.4.0-dev.1038",
100
+ "@glassly/bluetooth-sdk": "0.4.0-dev.1039",
101
+ "@glassly/cloud-client": "0.4.0-dev.1039",
102
+ "@glassly/cloud-protocol": "0.4.0-dev.1039",
103
+ "@glassly/crust": "0.4.0-dev.1039",
104
+ "@glassly/miniapp": "0.4.0-dev.1039",
105
105
  "buffer": "^6.0.3",
106
106
  "events": "^3.3.0",
107
107
  "react-native-marked": "8.3.2",
108
108
  "semver": "^7.7.4",
109
109
  "typesafe-ts": "^1.7.1",
110
- "@glassly/llm-providers": "0.4.0-dev.1038",
110
+ "@glassly/llm-providers": "0.4.0-dev.1039",
111
111
  "@huggingface/jinja": "^0.5.9",
112
112
  "jsonrepair": "^3.12.0"
113
113
  },
package/src/engine.ts CHANGED
@@ -239,7 +239,7 @@ export const engine = {
239
239
  backup,
240
240
  /** Device-local voice profiles for on-device speaker ID (Settings > Speakers). */
241
241
  speakers,
242
- /** AI/voice provider key validation — user-supplied keys (Settings > API Keys). */
242
+ /** AI/voice provider key validation — user-supplied keys (Settings > Privacy > API Keys). */
243
243
  providerKeys,
244
244
  display,
245
245
  }
@@ -114,7 +114,7 @@ function projectKeyboardStatus() {
114
114
  const s = useGlassesStore.getState()
115
115
  return {
116
116
  /** Connected glasses run a firmware that can host a keyboard (G2 Glassly CFW 39+). */
117
- available: s.keyboardBridge === true,
117
+ available: isGlassesReady(s.connection) && s.keyboardBridge === true,
118
118
  connected: s.keyboardConnected === true,
119
119
  name: s.keyboardName ?? "",
120
120
  /** A keyboard is remembered and reconnects automatically. */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * providerKeys facade — `engine.providerKeys.{anthropic,gemini,openai,deepseek,elevenlabs}`:
3
3
  * validate-before-save probes for the user-supplied AI/voice provider keys
4
- * (Settings > API Keys). Same per-provider shape as `engine.maps.mapbox` /
4
+ * (Settings > Privacy > API Keys). Same per-provider shape as `engine.maps.mapbox` /
5
5
  * `engine.speech.sonioxDirect` so the Keys screen treats providers uniformly.
6
6
  */
7
7
  import {
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
12
12
  export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "0.4.0",
15
- "releaseIdentity": "0.4.0-dev.1038",
16
- "releaseSetId": "glassly-0.4.0-dev.1038",
17
- "sourceCommit": "ae63dd717fbe5800f13e130cd76aab56af631015",
15
+ "releaseIdentity": "0.4.0-dev.1039",
16
+ "releaseSetId": "glassly-0.4.0-dev.1039",
17
+ "sourceCommit": "daea71d3a5f3ab0c53c092cb2484c28b2b8d8493",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })
@@ -48,10 +48,7 @@ export type MentraLiveOtaScreen =
48
48
  | "disconnected"
49
49
 
50
50
  export type MentraLiveOtaErrorCode =
51
- | "check_failed"
52
- | "update_info_unavailable"
53
- | "install_failed"
54
- | "bes_restart_required"
51
+ "check_failed" | "update_info_unavailable" | "install_failed" | "bes_restart_required"
55
52
 
56
53
  export type MentraLiveOtaError = {
57
54
  code: MentraLiveOtaErrorCode
@@ -66,12 +66,7 @@ export type NavErrorEvent = {kind: "error"; message: string}
66
66
  /** Synthesized by the host when the trip is cancelled outside the miniapp (e.g. wearer exited nav mode on the glasses). */
67
67
  export type NavCancelledEvent = {kind: "cancelled"; reason?: string}
68
68
  export type NavUpdate =
69
- | NavManeuverEvent
70
- | NavOffRouteEvent
71
- | NavReroutingEvent
72
- | NavArrivedEvent
73
- | NavErrorEvent
74
- | NavCancelledEvent
69
+ NavManeuverEvent | NavOffRouteEvent | NavReroutingEvent | NavArrivedEvent | NavErrorEvent | NavCancelledEvent
75
70
 
76
71
  export type NavLocation = {
77
72
  lat: number
@@ -51,7 +51,7 @@ export const TIER_MODEL_OPTIONS: Record<AiTier, TierModelOption[]> = {
51
51
  ],
52
52
  }
53
53
 
54
- /** Which providers currently have a user key saved (Settings > API Keys). */
54
+ /** Which providers currently have a user key saved (Settings > Privacy > API Keys). */
55
55
  export type SavedLlmKeys = Record<AiTierProvider, boolean>
56
56
 
57
57
  /**
@@ -1,9 +1,7 @@
1
1
  import type {ReportSubmitResult} from "../facades/reports"
2
2
 
3
3
  export type AutomaticReportSubmissionStatus =
4
- | {status: "filed"; reportId: string}
5
- | {status: "skipped"; reason: string}
6
- | {status: "failed"; error: string}
4
+ {status: "filed"; reportId: string} | {status: "skipped"; reason: string} | {status: "failed"; error: string}
7
5
 
8
6
  export function toAutomaticReportSubmissionStatus(result: ReportSubmitResult): AutomaticReportSubmissionStatus {
9
7
  if (result.status === "submitted") {
@@ -50,7 +50,7 @@ const MIDDLE_FINGER_GLYPHS: Partial<Record<GestureDotGlyph, GestureDotGlyph>> =
50
50
 
51
51
  /** `glyph` as `finger` draws it: the middle finger's shapes are hollow. */
52
52
  function fingerGlyph(glyph: GestureDotGlyph, finger: number): GestureDotGlyph {
53
- return finger === 1 ? MIDDLE_FINGER_GLYPHS[glyph] ?? glyph : glyph
53
+ return finger === 1 ? (MIDDLE_FINGER_GLYPHS[glyph] ?? glyph) : glyph
54
54
  }
55
55
 
56
56
  function fingerKey(controllerId: string | undefined, finger: number): string {
@@ -24,10 +24,7 @@ export type HotspotOtaProgress = {
24
24
  }
25
25
 
26
26
  export type HotspotOtaErrorCode =
27
- | "hotspot_wifi_permission_denied"
28
- | "hotspot_start_failed"
29
- | "hotspot_join_failed"
30
- | "hotspot_server_failed"
27
+ "hotspot_wifi_permission_denied" | "hotspot_start_failed" | "hotspot_join_failed" | "hotspot_server_failed"
31
28
 
32
29
  export class HotspotOtaTransportError extends Error {
33
30
  constructor(
@@ -141,6 +141,7 @@ import {phoneStreamCoordinator} from "./PhoneStreamCoordinator"
141
141
  import {phoneVideoCoordinator} from "./PhoneVideoCoordinator"
142
142
  import {runSentenceTtsPipeline} from "./SentenceTtsPipeline"
143
143
  import {
144
+ matchesTranscriptionSubscription,
144
145
  summarizeTranscriptionRoutes,
145
146
  transcriptionDeliveryRoute,
146
147
  type TranscriptionDeliveryRoute,
@@ -433,7 +434,7 @@ const PERMISSION_TYPE_TO_CANONICAL: Record<string, string> = {
433
434
  }
434
435
 
435
436
  /**
436
- * User API keys (Settings > API Keys) a miniapp may read via
437
+ * User API keys (Settings > Privacy > API Keys) a miniapp may read via
437
438
  * session.keys.get(), mapped provider → settings-store key. Explicit
438
439
  * allowlist: the Soniox key is deliberately absent — it gates the
439
440
  * phone→Soniox direct transcription path and is not exposed to miniapps.
@@ -477,9 +478,9 @@ function directLlmProvider(name: AiTierProvider): LlmProviderImpl {
477
478
  }
478
479
 
479
480
  const QUOTA_EXCEEDED_MESSAGE =
480
- "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > API Keys."
481
+ "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > Privacy > API Keys."
481
482
 
482
- /** The user's saved key (Settings > API Keys) for an LLM provider, "" if none. */
483
+ /** The user's saved key (Settings > Privacy > API Keys) for an LLM provider, "" if none. */
483
484
  function userLlmKey(provider: AiTierProvider): string {
484
485
  const raw = useSettingsStore.getState().getSetting(MINIAPP_READABLE_API_KEYS[provider])
485
486
  return typeof raw === "string" ? raw.trim() : ""
@@ -4149,7 +4150,7 @@ class LocalMiniappRuntime {
4149
4150
  }
4150
4151
 
4151
4152
  // ---------------------------------------------------------------------------
4152
- // User API keys (Settings > API Keys)
4153
+ // User API keys (Settings > Privacy > API Keys)
4153
4154
  // ---------------------------------------------------------------------------
4154
4155
 
4155
4156
  /**
@@ -4217,7 +4218,7 @@ class LocalMiniappRuntime {
4217
4218
  * The request names a TIER; this handler resolves it to a provider+model
4218
4219
  * (Settings > AI Models dropdowns, or auto from saved keys) and then picks
4219
4220
  * one of two transport paths, decided by whether the user saved a key for
4220
- * the resolved provider (Settings > API Keys) — the phone is where both
4221
+ * the resolved provider (Settings > Privacy > API Keys) — the phone is where both
4221
4222
  * settings live, so this is the only place the choice can be made:
4222
4223
  *
4223
4224
  * - User key saved → the phone calls the vendor DIRECTLY via
@@ -4490,7 +4491,7 @@ class LocalMiniappRuntime {
4490
4491
  this.sendResult(packageName, requestId, false, undefined, {
4491
4492
  code: MiniappErrorCode.QUOTA_EXCEEDED,
4492
4493
  message:
4493
- "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > API Keys.",
4494
+ "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > Privacy > API Keys.",
4494
4495
  })
4495
4496
  return
4496
4497
  }
@@ -4744,7 +4745,11 @@ class LocalMiniappRuntime {
4744
4745
  * session.system.webLogin — host in-app browser sheet. Same contract as
4745
4746
  * scanQr: the seam presents a Modal and never clears miniapp foreground.
4746
4747
  */
4747
- private async handleWebLogin(packageName: string, payload: Record<string, unknown>, requestId?: string): Promise<void> {
4748
+ private async handleWebLogin(
4749
+ packageName: string,
4750
+ payload: Record<string, unknown>,
4751
+ requestId?: string,
4752
+ ): Promise<void> {
4748
4753
  try {
4749
4754
  const result = await invokeWebLoginSeam(getUiSeams().webLogin, payload, packageName)
4750
4755
  this.sendResult(packageName, requestId, true, result)
@@ -5385,6 +5390,9 @@ class LocalMiniappRuntime {
5385
5390
  */
5386
5391
  private buildCloudAudioSubscriptions(cloudStreams: Set<string>): AudioSubscription[] {
5387
5392
  const subs: AudioSubscription[] = []
5393
+ // One auto recognizer serves every transcription listener. Explicit-language
5394
+ // listeners are filtered at delivery; translations still need their own jobs.
5395
+ const hasAutoTranscription = cloudStreams.has("transcription:auto")
5388
5396
  // Union of every connected app's TRANSCRIPTION_CONFIG hints. Hints only
5389
5397
  // apply to the auto-mode TRANSCRIPTION subscription (the wire schema has
5390
5398
  // no hints field on specific-language sources — the language IS the hint
@@ -5395,6 +5403,7 @@ class LocalMiniappRuntime {
5395
5403
  for (const stream of cloudStreams) {
5396
5404
  if (stream.startsWith("transcription:")) {
5397
5405
  const lang = stream.substring("transcription:".length)
5406
+ if (hasAutoTranscription && lang !== "auto") continue
5398
5407
  const source = langSource(lang)
5399
5408
  subs.push({
5400
5409
  kind: "transcription",
@@ -5527,6 +5536,12 @@ class LocalMiniappRuntime {
5527
5536
  }
5528
5537
 
5529
5538
  private handleTranscriptionData(d: TranscriptionData): void {
5539
+ const expectsAuto = [...(this.streamSubscribers.get("transcription:auto") ?? [])].some(
5540
+ (packageName) => this.appTranscriptionRoutesForSubscription(packageName, "transcription:auto").cloud,
5541
+ )
5542
+ // Subscription replacement is asynchronous. Ignore late results from the
5543
+ // old pipeline while switching between auto and language-specific jobs.
5544
+ if ((d.subscription.language.mode === "auto") !== expectsAuto) return
5530
5545
  const receivedAt = Date.now()
5531
5546
  if (TRANSCRIPT_TIMING_TELEMETRY) {
5532
5547
  console.log(
@@ -5565,6 +5580,8 @@ class LocalMiniappRuntime {
5565
5580
  __hostReceivedAt: receivedAt,
5566
5581
  },
5567
5582
  "cloud",
5583
+ undefined,
5584
+ d.subscription,
5568
5585
  )
5569
5586
  }
5570
5587
 
@@ -5642,8 +5659,7 @@ class LocalMiniappRuntime {
5642
5659
  /** Model profile + runtime overrides (the G2 CFW scene canvas) for the default wearable. */
5643
5660
  private currentCapabilities(): Capabilities {
5644
5661
  const defaultWearable = useSettingsStore.getState().getSetting(ISLAND_SETTINGS_KEYS.defaultWearable) as
5645
- | DeviceTypes
5646
- | undefined
5662
+ DeviceTypes | undefined
5647
5663
  return getEffectiveCapabilities(defaultWearable || DeviceTypes.NONE)
5648
5664
  }
5649
5665
 
@@ -5790,6 +5806,8 @@ class LocalMiniappRuntime {
5790
5806
  transcriptionSource?: TranscriptionEventSource,
5791
5807
  /** Deliver to this subscriber alone (the designated dashboard app's gestures while it shows). */
5792
5808
  only?: string,
5809
+ /** Producing cloud/direct subscription; auto results also serve matching language listeners. */
5810
+ transcriptionSubscription?: TranscriptionData["subscription"],
5793
5811
  ): void {
5794
5812
  // Paused miniapps (glasses disconnected) hear no streams. The resume push
5795
5813
  // lands before the reconnect's own glasses_connection event, so nothing
@@ -5801,6 +5819,12 @@ class LocalMiniappRuntime {
5801
5819
  if (transcriptionSource === "local") markTranscriptSourceRecent("local")
5802
5820
  // Translate cloud event names to miniapp protocol stream types
5803
5821
  const normalizedStream = this.normalizeStreamType(streamType)
5822
+ const transcriptionStreams =
5823
+ transcriptionSource === "cloud" && transcriptionSubscription
5824
+ ? [...this.streamSubscribers.keys()].filter((stream) =>
5825
+ matchesTranscriptionSubscription(stream, normalizedStream, transcriptionSubscription),
5826
+ )
5827
+ : undefined
5804
5828
 
5805
5829
  // Passive memory capture happens HERE, before subscriber fan-out, so the
5806
5830
  // timeline reflects what was said around the user regardless of which
@@ -5809,10 +5833,10 @@ class LocalMiniappRuntime {
5809
5833
  // recorded while it was open.)
5810
5834
  this.captureTranscriptToMemory(normalizedStream, data)
5811
5835
 
5812
- // Collect all subscribers: exact match, plus wildcard matches for streams
5813
- // that carry a language tag. A miniapp subscribed to "transcription:auto"
5814
- // should receive any "transcription:<lang>" event (the detected language
5815
- // is conveyed in the event data, not the stream key).
5836
+ // Auto cloud/direct results serve auto listeners and listeners requesting
5837
+ // the detected language. Specific jobs serve only their own subscription.
5838
+ // Local/legacy events have no producing subscription and retain wildcard
5839
+ // matching so one on-device recognizer can serve auto and explicit listeners.
5816
5840
  //
5817
5841
  // Translation streams support cloud v3's wildcard patterns. Incoming
5818
5842
  // events are keyed `translation:<source>:<target>` and we match against
@@ -5824,11 +5848,13 @@ class LocalMiniappRuntime {
5824
5848
  // translation:auto — back-compat alias for *:*
5825
5849
  const matchedSubs = new Set<string>()
5826
5850
  let translationPatterns: string[] = []
5827
- const exact = this.streamSubscribers.get(normalizedStream)
5828
- if (exact) for (const p of exact) matchedSubs.add(p)
5851
+ for (const stream of transcriptionStreams ?? [normalizedStream]) {
5852
+ const exact = this.streamSubscribers.get(stream)
5853
+ if (exact) for (const p of exact) matchedSubs.add(p)
5854
+ }
5829
5855
 
5830
5856
  if (normalizedStream.startsWith("transcription:")) {
5831
- const autoSubs = this.streamSubscribers.get("transcription:auto")
5857
+ const autoSubs = transcriptionStreams ? undefined : this.streamSubscribers.get("transcription:auto")
5832
5858
  if (autoSubs) for (const p of autoSubs) matchedSubs.add(p)
5833
5859
  } else if (normalizedStream.startsWith("translation:")) {
5834
5860
  // translation:<source>:<target> — match each wildcard variant.
@@ -5907,8 +5933,18 @@ class LocalMiniappRuntime {
5907
5933
  // The wearer's touches reach a widget-only app through its host's widget events alone.
5908
5934
  if (normalizedStream === MiniappStreamType.TOUCH_EVENT && miniappWidgetMode.isWidgetOnly(packageName)) continue
5909
5935
  let transcriptionRoute: TranscriptionDeliveryRoute | undefined
5936
+ let outboundStream = normalizedStream
5910
5937
  if (normalizedStream.startsWith("transcription:") && transcriptionSource) {
5911
- const routes = this.appTranscriptionRoutesForEvent(packageName, normalizedStream)
5938
+ const cloudStreams = transcriptionStreams?.filter(
5939
+ (stream) => this.appTranscriptionRoutesForSubscription(packageName, stream).cloud,
5940
+ )
5941
+ const routes = cloudStreams
5942
+ ? {cloud: cloudStreams.length > 0, forceLocal: false}
5943
+ : this.appTranscriptionRoutesForEvent(packageName, normalizedStream)
5944
+ // Existing miniapp bundles dispatch explicit listeners by their BCP-47
5945
+ // subscription key, while providers detect bare codes (es vs es-ES).
5946
+ // Send one envelope per app, even when it also subscribes to auto.
5947
+ outboundStream = cloudStreams?.find((stream) => stream !== "transcription:auto") ?? normalizedStream
5912
5948
  transcriptionRoute =
5913
5949
  transcriptionDeliveryRoute(transcriptionSource, routes, this.transcriptionPrimaryUp()) ?? undefined
5914
5950
  if (!transcriptionRoute) continue
@@ -5937,7 +5973,7 @@ class LocalMiniappRuntime {
5937
5973
  }
5938
5974
  this.sendToMiniapp(packageName, {
5939
5975
  type: MiniappResponseType.EVENT,
5940
- streamType: normalizedStream,
5976
+ streamType: outboundStream,
5941
5977
  data: outboundData,
5942
5978
  ...(transcriptionRoute ? {transcriptionRoute} : {}),
5943
5979
  })
@@ -6538,7 +6574,12 @@ class LocalMiniappRuntime {
6538
6574
  // and an unplace racing it cannot stop the provider early. A provider the
6539
6575
  // store already runs (a wearer's launch still spawning, say) stays a
6540
6576
  // normal run; the registry alone lags that launch.
6541
- this.widgetPlacements = placeWidget(this.widgetPlacements, {hostPackageName, providerPackageName: provider, widgetId, box})
6577
+ this.widgetPlacements = placeWidget(this.widgetPlacements, {
6578
+ hostPackageName,
6579
+ providerPackageName: provider,
6580
+ widgetId,
6581
+ box,
6582
+ })
6542
6583
  miniappWidgetMode.setPlaced(provider, true)
6543
6584
  if (!app.running && !miniappRunningRegistry.has(provider)) miniappWidgetMode.setWidgetOnly(provider, true)
6544
6585
  try {
@@ -6575,7 +6616,10 @@ class LocalMiniappRuntime {
6575
6616
  this.widgetPlacements = unplaceWidget(this.widgetPlacements, hostPackageName, provider, target.widgetId)
6576
6617
  this.sendResult(hostPackageName, requestId, true)
6577
6618
  if (!had) return
6578
- if (this.connectedApps.has(provider) && widgetHostsOf(this.widgetPlacements, provider, target.widgetId).length === 0) {
6619
+ if (
6620
+ this.connectedApps.has(provider) &&
6621
+ widgetHostsOf(this.widgetPlacements, provider, target.widgetId).length === 0
6622
+ ) {
6579
6623
  this.sendWidgetCall(provider, target.widgetId, {kind: "box", box: null})
6580
6624
  }
6581
6625
  await this.settleWidgetProvider(provider)
@@ -6706,9 +6750,7 @@ class LocalMiniappRuntime {
6706
6750
  if (!widget) return
6707
6751
  const view: WidgetView = payload.view === "expanded" ? "expanded" : "card"
6708
6752
  if (view === "expanded" && !widget.expandable) {
6709
- console.warn(
6710
- `${LOG_TAG}: dropping expanded frame from ${providerPackageName}/${widgetId}: it does not list EX`,
6711
- )
6753
+ console.warn(`${LOG_TAG}: dropping expanded frame from ${providerPackageName}/${widgetId}: it does not list EX`)
6712
6754
  return
6713
6755
  }
6714
6756
  const cap =
@@ -28,11 +28,7 @@ import sttModelManager from "./STTModelManager"
28
28
  * `force_local` (a forced subscription would keep local STT on either way).
29
29
  */
30
30
  export type LocalSttFallbackReason =
31
- | "force_local"
32
- | "cloud_disconnected"
33
- | "cloud_disabled"
34
- | "stt_quota"
35
- | "provider_unreachable"
31
+ "force_local" | "cloud_disconnected" | "cloud_disabled" | "stt_quota" | "provider_unreachable"
36
32
 
37
33
  class LocalSttFallbackCoordinator {
38
34
  private static instance: LocalSttFallbackCoordinator
@@ -61,8 +61,7 @@ class NativeNavigationService {
61
61
  */
62
62
  public isSupported(): boolean {
63
63
  const defaultWearable = useSettingsStore.getState().getSetting(ISLAND_SETTINGS_KEYS.defaultWearable) as
64
- | DeviceTypes
65
- | undefined
64
+ DeviceTypes | undefined
66
65
  // Effective, not model: custom firmware drops hasNativeNavigation so the
67
66
  // miniapp's scene HUD owns the display (see effectiveCapabilities).
68
67
  const capabilities = getEffectiveCapabilities(defaultWearable || DeviceTypes.NONE)
@@ -364,7 +364,7 @@ export class NavigationHandlers {
364
364
 
365
365
  async handleComputeRoute(packageName: string, payload: Record<string, unknown>, requestId?: string): Promise<void> {
366
366
  try {
367
- // With the user's own Mapbox key (Settings > API Keys), compute
367
+ // With the user's own Mapbox key (Settings > Privacy > API Keys), compute
368
368
  // on-device so routing works without the cloud and bills their account.
369
369
  // Without one, go through the v2 cloud maps proxy — org-token Mapbox
370
370
  // usage only ever happens cloud-side.
@@ -437,7 +437,7 @@ export class NavigationHandlers {
437
437
 
438
438
  /**
439
439
  * Type-ahead place search. Runs on-device against Mapbox Search Box when the
440
- * user saved their own key (Settings > API Keys) — that key exists precisely
440
+ * user saved their own key (Settings > Privacy > API Keys) — that key exists precisely
441
441
  * so search works without the cloud — and falls back to the v2 cloud maps
442
442
  * service otherwise. Resolves `{ok: true, suggestions}` — an empty query or no
443
443
  * matches is `{ok: true, suggestions: []}`, not an error.