@glassly/engine 0.4.0-beta.1025 → 0.4.0-beta.1045
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/build/engine.d.ts +2 -1
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +6 -4
- package/build/engine.js.map +1 -1
- package/build/facades/glasses.js +1 -1
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/providerKeys.d.ts +1 -1
- package/build/facades/providerKeys.js +1 -1
- package/build/facades/providerKeys.js.map +1 -1
- package/build/facades/reports.d.ts +15 -0
- package/build/facades/reports.d.ts.map +1 -1
- package/build/facades/reports.js +37 -0
- package/build/facades/reports.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/runtime/config.d.ts.map +1 -1
- package/build/runtime/config.js.map +1 -1
- package/build/services/AiTierResolution.d.ts +1 -1
- package/build/services/AiTierResolution.d.ts.map +1 -1
- package/build/services/AiTierResolution.js.map +1 -1
- package/build/services/AutomaticReportResult.d.ts.map +1 -1
- package/build/services/AutomaticReportResult.js.map +1 -1
- package/build/services/CloudClientService.d.ts +7 -5
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +17 -14
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts.map +1 -1
- package/build/services/DisplayProcessor.js +2 -1
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/GestureDotsService.js +1 -1
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts.map +1 -1
- package/build/services/HotspotOtaTransport.js +0 -1
- package/build/services/HotspotOtaTransport.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +5 -2
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +54 -23
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/NativeNavigationService.d.ts.map +1 -1
- package/build/services/NativeNavigationService.js.map +1 -1
- package/build/services/NavigationHandlers.d.ts +1 -1
- package/build/services/NavigationHandlers.js +2 -2
- package/build/services/NavigationHandlers.js.map +1 -1
- package/build/services/NavigationService.d.ts +2 -2
- package/build/services/NavigationService.d.ts.map +1 -1
- package/build/services/NavigationService.js +11 -11
- package/build/services/NavigationService.js.map +1 -1
- package/build/services/PairingIdentity.d.ts.map +1 -1
- package/build/services/PairingIdentity.js.map +1 -1
- package/build/services/PhoneCalendarService.d.ts.map +1 -1
- package/build/services/PhoneCalendarService.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +2 -1
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/ProviderKeyValidation.d.ts +1 -1
- package/build/services/ProviderKeyValidation.js +1 -1
- package/build/services/ProviderKeyValidation.js.map +1 -1
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +1 -6
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/SupportProfileSync.d.ts.map +1 -1
- package/build/services/SupportProfileSync.js +3 -0
- package/build/services/SupportProfileSync.js.map +1 -1
- package/build/services/TranscriptionRouting.d.ts +3 -0
- package/build/services/TranscriptionRouting.d.ts.map +1 -1
- package/build/services/TranscriptionRouting.js +14 -0
- package/build/services/TranscriptionRouting.js.map +1 -1
- package/build/services/UIRouter.d.ts.map +1 -1
- package/build/services/UIRouter.js.map +1 -1
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +1 -0
- package/build/services/controllers.js.map +1 -1
- package/build/services/effectiveCapabilities.js +3 -2
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/services/gestureDotGlyphs.d.ts.map +1 -1
- package/build/services/gestureDotGlyphs.js.map +1 -1
- package/build/services/manifestActions.d.ts.map +1 -1
- package/build/services/manifestActions.js.map +1 -1
- package/build/services/notificationAppPayload.d.ts +14 -0
- package/build/services/notificationAppPayload.d.ts.map +1 -0
- package/build/services/notificationAppPayload.js +15 -0
- package/build/services/notificationAppPayload.js.map +1 -0
- package/build/services/settingsBridge.d.ts.map +1 -1
- package/build/services/settingsBridge.js.map +1 -1
- package/build/stores/appVisibility.d.ts.map +1 -1
- package/build/stores/appVisibility.js.map +1 -1
- package/build/stores/gallerySync.d.ts.map +1 -1
- package/build/stores/gallerySync.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +1 -0
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +5 -3
- package/build/stores/settings.js.map +1 -1
- package/build/types/capabilities/nimo.d.ts.map +1 -1
- package/build/types/capabilities/nimo.js +19 -7
- package/build/types/capabilities/nimo.js.map +1 -1
- package/build/types/enums.d.ts +2 -1
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -0
- package/build/types/enums.js.map +1 -1
- package/build/utils/display/index.d.ts +1 -0
- package/build/utils/display/index.d.ts.map +1 -1
- package/build/utils/display/index.js +2 -2
- package/build/utils/display/index.js.map +1 -1
- package/build/utils/display/profiles/index.d.ts +1 -0
- package/build/utils/display/profiles/index.d.ts.map +1 -1
- package/build/utils/display/profiles/index.js +1 -0
- package/build/utils/display/profiles/index.js.map +1 -1
- package/build/utils/display/profiles/nimo.d.ts +2 -0
- package/build/utils/display/profiles/nimo.d.ts.map +1 -0
- package/build/utils/display/profiles/nimo.js +3 -0
- package/build/utils/display/profiles/nimo.js.map +1 -0
- package/build/utils/display/scene/svgPath.js.map +1 -1
- package/build/utils/memory/search.d.ts.map +1 -1
- package/build/utils/memory/search.js +17 -7
- package/build/utils/memory/search.js.map +1 -1
- package/package.json +7 -7
- package/src/engine.ts +9 -7
- package/src/facades/glasses.ts +1 -1
- package/src/facades/providerKeys.ts +1 -1
- package/src/facades/reports.ts +41 -0
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/react/useMentraLiveOta.ts +1 -4
- package/src/runtime/config.ts +1 -6
- package/src/services/AiTierResolution.ts +1 -1
- package/src/services/AutomaticReportResult.ts +1 -3
- package/src/services/CloudClientService.ts +17 -11
- package/src/services/DisplayProcessor.ts +2 -0
- package/src/services/GestureDotsService.ts +1 -1
- package/src/services/HotspotOtaTransport.ts +1 -5
- package/src/services/LocalMiniappRuntime.ts +66 -24
- package/src/services/LocalSttFallbackCoordinator.ts +1 -5
- package/src/services/NativeNavigationService.ts +1 -2
- package/src/services/NavigationHandlers.ts +2 -2
- package/src/services/NavigationService.ts +12 -11
- package/src/services/PairingIdentity.ts +1 -3
- package/src/services/PhoneCalendarService.ts +1 -3
- package/src/services/PhoneNotificationsSync.ts +2 -1
- package/src/services/PhoneStreamCoordinator.ts +1 -2
- package/src/services/ProviderKeyValidation.ts +1 -1
- package/src/services/STTModelManager.ts +1 -6
- package/src/services/SupportProfileSync.ts +2 -0
- package/src/services/TranscriptionRouting.ts +18 -0
- package/src/services/UIRouter.ts +3 -9
- package/src/services/controllers.ts +1 -0
- package/src/services/effectiveCapabilities.ts +3 -2
- package/src/services/gestureDotGlyphs.ts +10 -5
- package/src/services/manifestActions.ts +2 -1
- package/src/services/notificationAppPayload.ts +15 -0
- package/src/services/settingsBridge.ts +1 -2
- package/src/stores/appVisibility.ts +2 -5
- package/src/stores/gallerySync.ts +1 -7
- package/src/stores/glasses.ts +1 -0
- package/src/stores/settings.ts +5 -3
- package/src/types/capabilities/nimo.ts +20 -7
- package/src/types/enums.ts +1 -0
- package/src/utils/display/index.ts +2 -2
- package/src/utils/display/profiles/index.ts +2 -0
- package/src/utils/display/profiles/nimo.ts +2 -0
- package/src/utils/display/scene/svgPath.ts +1 -1
- package/src/utils/memory/search.ts +17 -7
package/build/types/enums.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare enum ControllerTypes {
|
|
|
22
22
|
GAMEBRICK = "IINE Gamebrick",
|
|
23
23
|
IINE_ANANKE = "IINE Ananke Gen 2",
|
|
24
24
|
ZERO2 = "8BitDo Zero 2",
|
|
25
|
-
MICRO = "8BitDo Micro"
|
|
25
|
+
MICRO = "8BitDo Micro",
|
|
26
|
+
CRKD_ATOM_PLUS = "CRKD ATOM+"
|
|
26
27
|
}
|
|
27
28
|
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;IACvB,YAAY,iBAAiB;CAC9B;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;IAC5B,WAAW,sBAAsB;IACjC,KAAK,kBAAkB;IACvB,KAAK,iBAAiB;
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;IACvB,YAAY,iBAAiB;CAC9B;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;IAC5B,WAAW,sBAAsB;IACjC,KAAK,kBAAkB;IACvB,KAAK,iBAAiB;IACtB,cAAc,eAAe;CAC9B"}
|
package/build/types/enums.js
CHANGED
|
@@ -25,5 +25,6 @@ export var ControllerTypes;
|
|
|
25
25
|
ControllerTypes["IINE_ANANKE"] = "IINE Ananke Gen 2";
|
|
26
26
|
ControllerTypes["ZERO2"] = "8BitDo Zero 2";
|
|
27
27
|
ControllerTypes["MICRO"] = "8BitDo Micro";
|
|
28
|
+
ControllerTypes["CRKD_ATOM_PLUS"] = "CRKD ATOM+";
|
|
28
29
|
})(ControllerTypes || (ControllerTypes = {}));
|
|
29
30
|
//# sourceMappingURL=enums.js.map
|
package/build/types/enums.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAcX;AAdD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;IACvB,4CAA6B,CAAA;AAC/B,CAAC,EAdW,WAAW,KAAX,WAAW,QActB;AAED,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAcX;AAdD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;IACvB,4CAA6B,CAAA;AAC/B,CAAC,EAdW,WAAW,KAAX,WAAW,QActB;AAED,MAAM,CAAN,IAAY,eAUX;AAVD,WAAY,eAAe;IACzB,2CAAwB,CAAA;IACxB,mDAAgC,CAAA;IAChC,8CAA2B,CAAA;IAC3B,4CAAyB,CAAA;IACzB,+CAA4B,CAAA;IAC5B,oDAAiC,CAAA;IACjC,0CAAuB,CAAA;IACvB,yCAAsB,CAAA;IACtB,gDAA6B,CAAA;AAC/B,CAAC,EAVW,eAAe,KAAf,eAAe,QAU1B","sourcesContent":["export {HardwareType, HardwareRequirementLevel} from \"@glassly/miniapp/hardware\"\n\nexport enum DeviceTypes {\n NONE = \"None\",\n SIMULATED = \"Simulated Glasses\",\n AR99 = \"AR99\",\n G1 = \"Even Realities G1\",\n G2 = \"Even Realities G2\",\n LIVE = \"Mentra Live\",\n MACH1 = \"Mentra Mach1\",\n Z100 = \"Vuzix Z100\",\n NEX = \"Mentra Display\",\n NIMO = \"NIMO\",\n FRAME = \"Brilliant Frame\",\n RAYNEO_IO = \"RayNeo iO\",\n MEMOMIND_ONE = \"MemoMind One\",\n}\n\nexport enum ControllerTypes {\n R1 = \"Even Realities R1\",\n NEURAL_BAND = \"Meta Neural Band\",\n APPLE_WATCH = \"Apple Watch\",\n WEAR_OS = \"Wear OS Watch\",\n GAMEBRICK = \"IINE Gamebrick\",\n IINE_ANANKE = \"IINE Ananke Gen 2\",\n ZERO2 = \"8BitDo Zero 2\",\n MICRO = \"8BitDo Micro\",\n CRKD_ATOM_PLUS = \"CRKD ATOM+\",\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAaH,OAAO,EAAC,YAAY,EAAC,MAAM,YAAY,CAAA;AACvC,OAAO,EAAC,WAAW,EAAC,MAAM,WAAW,CAAA;AACrC,OAAO,EAAC,cAAc,EAAC,MAAM,WAAW,CAAA;AACxC,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
// Profiles - Hardware configurations for different glasses
|
|
35
35
|
// =============================================================================
|
|
36
36
|
// Import for factory functions
|
|
37
|
-
import { G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE } from "./profiles";
|
|
37
|
+
import { G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE, G1_PROFILE } from "./profiles";
|
|
38
38
|
// =============================================================================
|
|
39
39
|
// Convenience factory functions
|
|
40
40
|
// =============================================================================
|
|
@@ -42,7 +42,6 @@ import { TextMeasurer } from "./measurer";
|
|
|
42
42
|
import { TextWrapper } from "./wrapper";
|
|
43
43
|
import { DisplayHelpers } from "./helpers";
|
|
44
44
|
import { ColumnComposer } from "./composer";
|
|
45
|
-
import { G1_PROFILE } from "./profiles";
|
|
46
45
|
export { G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX } from "./profiles";
|
|
47
46
|
// G2 Profile
|
|
48
47
|
export { G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX } from "./profiles";
|
|
@@ -188,4 +187,5 @@ export function createNexToolkit() {
|
|
|
188
187
|
});
|
|
189
188
|
}
|
|
190
189
|
export { MEMOMIND_ONE_PROFILE } from "./profiles";
|
|
190
|
+
export { NIMO_PROFILE } from "./profiles";
|
|
191
191
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @glassly/display-utils\n *\n * Glasses-agnostic, pixel-accurate text measurement and wrapping library\n * for smart glasses displays.\n *\n * Key features:\n * - Pixel-perfect measurement (no abstract units or averages)\n * - Multiple break modes (character, word, strict-word)\n * - Full script support (Latin, CJK, Korean, Cyrillic)\n * - Configurable display profiles for different glasses hardware\n *\n * @example\n * ```typescript\n * import {\n * TextMeasurer,\n * TextWrapper,\n * DisplayHelpers,\n * G1_PROFILE\n * } from '@glassly/display-utils'\n *\n * // Create measurer and wrapper for G1 glasses\n * const measurer = new TextMeasurer(G1_PROFILE)\n * const wrapper = new TextWrapper(measurer, { breakMode: 'character' })\n * const helpers = new DisplayHelpers(measurer, wrapper)\n *\n * // Wrap text for display\n * const result = wrapper.wrap(\"Hello, world! This is a long text.\")\n * console.log(result.lines)\n * // [\"Hello, world! This is a long text th-\", \"at needs wrapping.\"]\n * ```\n */\n\n// =============================================================================\n// Profiles - Hardware configurations for different glasses\n// =============================================================================\n\n// Import for factory functions\nimport {G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE} from \"./profiles\"\n\n// =============================================================================\n// Convenience factory functions\n// =============================================================================\n\nimport {TextMeasurer} from \"./measurer\"\nimport {TextWrapper} from \"./wrapper\"\nimport {DisplayHelpers} from \"./helpers\"\nimport {ColumnComposer} from \"./composer\"\nimport {G1_PROFILE} from \"./profiles\"\nimport type {DisplayProfile} from \"./profiles\"\nimport type {WrapOptions} from \"./wrapper\"\n\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./profiles\"\n\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./profiles\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./profiles\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from \"./profiles\"\n\n// =============================================================================\n// Measurer - Pixel-accurate text measurement\n// =============================================================================\n\nexport {TextMeasurer} from \"./measurer\"\nexport type {CharMeasurement, TextMeasurement} from \"./measurer\"\n\n// Script detection utilities\nexport {\n detectScript,\n isCJKCharacter,\n isKoreanCharacter,\n isUniformWidthScript,\n isUnsupportedScript,\n needsHyphenForBreak,\n SCRIPT_RANGES,\n} from \"./measurer\"\n\n// =============================================================================\n// Wrapper - Text wrapping with multiple break modes\n// =============================================================================\n\nexport {TextWrapper} from \"./wrapper\"\nexport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./wrapper\"\nexport {DEFAULT_WRAP_OPTIONS} from \"./wrapper\"\n\n// =============================================================================\n// Helpers - Optional convenience utilities\n// =============================================================================\n\nexport {DisplayHelpers, ScrollView} from \"./helpers\"\nexport type {TruncateResult, Page, Chunk, ScrollPosition, ScrollViewport} from \"./helpers\"\n\n// =============================================================================\n// Composer - Multi-column layout composition\n// =============================================================================\n\nexport {ColumnComposer, createColumnComposer} from \"./composer\"\nexport type {ColumnConfig, ComposeOptions, ComposeResult} from \"./composer\"\n\n/**\n * Create a complete display toolkit for a given profile.\n *\n * @param profile - Display profile (defaults to G1)\n * @param wrapOptions - Default wrap options\n * @returns Object with measurer, wrapper, and helpers\n *\n * @example\n * ```typescript\n * const { measurer, wrapper, helpers } = createDisplayToolkit()\n * const lines = wrapper.wrapToLines(\"Hello, world!\")\n * ```\n */\nexport function createDisplayToolkit(\n profile: DisplayProfile = G1_PROFILE,\n wrapOptions?: WrapOptions,\n): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n const measurer = new TextMeasurer(profile)\n const wrapper = new TextWrapper(measurer, wrapOptions)\n const helpers = new DisplayHelpers(measurer, wrapper)\n const composer = new ColumnComposer(profile, wrapOptions?.breakMode || \"word\")\n\n return {\n measurer,\n wrapper,\n helpers,\n composer,\n profile,\n }\n}\n\n/**\n * Create a G1-configured display toolkit with character breaking.\n * This is the recommended setup for captions and similar high-utilization use cases.\n *\n * @returns Object with measurer, wrapper, and helpers configured for G1\n *\n * @example\n * ```typescript\n * const { wrapper, composer } = createG1Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * const columns = composer.composeDoubleTextWall(\"Left\", \"Right\")\n * ```\n */\nexport function createG1Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G1-configured display toolkit for LEGACY mobile clients.\n *\n * Use this when the mobile client has old wrapping logic that re-wraps\n * text received from the cloud. This profile uses a reduced display width\n * (~522px instead of 576px) to prevent double-wrapping overflow.\n *\n * @returns Object with measurer, wrapper, and helpers configured for legacy G1 clients\n *\n * @example\n * ```typescript\n * // For old mobile clients that double-wrap\n * const { wrapper } = createG1LegacyToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * // Lines will be shorter to account for mobile re-wrapping\n * ```\n */\nexport function createG1LegacyToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE_LEGACY, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G2-configured display toolkit with character breaking.\n * G2 uses EvenHub protocol with the same display hardware as G1.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Even G2\n *\n * @example\n * ```typescript\n * const { wrapper } = createG2Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createG2Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G2_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Z100-configured display toolkit with character breaking.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Vuzix Z100\n *\n * @example\n * ```typescript\n * const { wrapper } = createZ100Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createZ100Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(Z100_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Mentra Nex-configured display toolkit with character breaking.\n * Also known as \"Mentra Display\".\n *\n * @returns Object with measurer, wrapper, and helpers configured for Mentra Nex\n *\n * @example\n * ```typescript\n * const { wrapper } = createNexToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createNexToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(NEX_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\nexport {MEMOMIND_ONE_PROFILE} from \"./profiles\"\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @glassly/display-utils\n *\n * Glasses-agnostic, pixel-accurate text measurement and wrapping library\n * for smart glasses displays.\n *\n * Key features:\n * - Pixel-perfect measurement (no abstract units or averages)\n * - Multiple break modes (character, word, strict-word)\n * - Full script support (Latin, CJK, Korean, Cyrillic)\n * - Configurable display profiles for different glasses hardware\n *\n * @example\n * ```typescript\n * import {\n * TextMeasurer,\n * TextWrapper,\n * DisplayHelpers,\n * G1_PROFILE\n * } from '@glassly/display-utils'\n *\n * // Create measurer and wrapper for G1 glasses\n * const measurer = new TextMeasurer(G1_PROFILE)\n * const wrapper = new TextWrapper(measurer, { breakMode: 'character' })\n * const helpers = new DisplayHelpers(measurer, wrapper)\n *\n * // Wrap text for display\n * const result = wrapper.wrap(\"Hello, world! This is a long text.\")\n * console.log(result.lines)\n * // [\"Hello, world! This is a long text th-\", \"at needs wrapping.\"]\n * ```\n */\n\n// =============================================================================\n// Profiles - Hardware configurations for different glasses\n// =============================================================================\n\n// Import for factory functions\nimport {G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE, G1_PROFILE} from \"./profiles\"\n\n// =============================================================================\n// Convenience factory functions\n// =============================================================================\n\nimport {TextMeasurer} from \"./measurer\"\nimport {TextWrapper} from \"./wrapper\"\nimport {DisplayHelpers} from \"./helpers\"\nimport {ColumnComposer} from \"./composer\"\nimport type {DisplayProfile} from \"./profiles\"\nimport type {WrapOptions} from \"./wrapper\"\n\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./profiles\"\n\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./profiles\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./profiles\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from \"./profiles\"\n\n// =============================================================================\n// Measurer - Pixel-accurate text measurement\n// =============================================================================\n\nexport {TextMeasurer} from \"./measurer\"\nexport type {CharMeasurement, TextMeasurement} from \"./measurer\"\n\n// Script detection utilities\nexport {\n detectScript,\n isCJKCharacter,\n isKoreanCharacter,\n isUniformWidthScript,\n isUnsupportedScript,\n needsHyphenForBreak,\n SCRIPT_RANGES,\n} from \"./measurer\"\n\n// =============================================================================\n// Wrapper - Text wrapping with multiple break modes\n// =============================================================================\n\nexport {TextWrapper} from \"./wrapper\"\nexport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./wrapper\"\nexport {DEFAULT_WRAP_OPTIONS} from \"./wrapper\"\n\n// =============================================================================\n// Helpers - Optional convenience utilities\n// =============================================================================\n\nexport {DisplayHelpers, ScrollView} from \"./helpers\"\nexport type {TruncateResult, Page, Chunk, ScrollPosition, ScrollViewport} from \"./helpers\"\n\n// =============================================================================\n// Composer - Multi-column layout composition\n// =============================================================================\n\nexport {ColumnComposer, createColumnComposer} from \"./composer\"\nexport type {ColumnConfig, ComposeOptions, ComposeResult} from \"./composer\"\n\n/**\n * Create a complete display toolkit for a given profile.\n *\n * @param profile - Display profile (defaults to G1)\n * @param wrapOptions - Default wrap options\n * @returns Object with measurer, wrapper, and helpers\n *\n * @example\n * ```typescript\n * const { measurer, wrapper, helpers } = createDisplayToolkit()\n * const lines = wrapper.wrapToLines(\"Hello, world!\")\n * ```\n */\nexport function createDisplayToolkit(\n profile: DisplayProfile = G1_PROFILE,\n wrapOptions?: WrapOptions,\n): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n const measurer = new TextMeasurer(profile)\n const wrapper = new TextWrapper(measurer, wrapOptions)\n const helpers = new DisplayHelpers(measurer, wrapper)\n const composer = new ColumnComposer(profile, wrapOptions?.breakMode || \"word\")\n\n return {\n measurer,\n wrapper,\n helpers,\n composer,\n profile,\n }\n}\n\n/**\n * Create a G1-configured display toolkit with character breaking.\n * This is the recommended setup for captions and similar high-utilization use cases.\n *\n * @returns Object with measurer, wrapper, and helpers configured for G1\n *\n * @example\n * ```typescript\n * const { wrapper, composer } = createG1Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * const columns = composer.composeDoubleTextWall(\"Left\", \"Right\")\n * ```\n */\nexport function createG1Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G1-configured display toolkit for LEGACY mobile clients.\n *\n * Use this when the mobile client has old wrapping logic that re-wraps\n * text received from the cloud. This profile uses a reduced display width\n * (~522px instead of 576px) to prevent double-wrapping overflow.\n *\n * @returns Object with measurer, wrapper, and helpers configured for legacy G1 clients\n *\n * @example\n * ```typescript\n * // For old mobile clients that double-wrap\n * const { wrapper } = createG1LegacyToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * // Lines will be shorter to account for mobile re-wrapping\n * ```\n */\nexport function createG1LegacyToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE_LEGACY, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G2-configured display toolkit with character breaking.\n * G2 uses EvenHub protocol with the same display hardware as G1.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Even G2\n *\n * @example\n * ```typescript\n * const { wrapper } = createG2Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createG2Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G2_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Z100-configured display toolkit with character breaking.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Vuzix Z100\n *\n * @example\n * ```typescript\n * const { wrapper } = createZ100Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createZ100Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(Z100_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Mentra Nex-configured display toolkit with character breaking.\n * Also known as \"Mentra Display\".\n *\n * @returns Object with measurer, wrapper, and helpers configured for Mentra Nex\n *\n * @example\n * ```typescript\n * const { wrapper } = createNexToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createNexToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(NEX_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\nexport {MEMOMIND_ONE_PROFILE} from \"./profiles\"\nexport {NIMO_PROFILE} from \"./profiles\"\n"]}
|
|
@@ -11,4 +11,5 @@ export { G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX } from "./g2";
|
|
|
11
11
|
export { NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX } from "./nex";
|
|
12
12
|
export { RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX, } from "./rayneo-io";
|
|
13
13
|
export { MEMOMIND_ONE_PROFILE } from "@glassly/miniapp/display";
|
|
14
|
+
export { NIMO_PROFILE } from "./nimo";
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,UAAU,GACX,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGzF,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAG9E,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGtE,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAG1E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,UAAU,GACX,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGzF,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAG9E,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGtE,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAG1E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA;AAE7D,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAA"}
|
|
@@ -15,4 +15,5 @@ export { NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX } from "./nex";
|
|
|
15
15
|
// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)
|
|
16
16
|
export { RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX, } from "./rayneo-io";
|
|
17
17
|
export { MEMOMIND_ONE_PROFILE } from "@glassly/miniapp/display";
|
|
18
|
+
export { NIMO_PROFILE } from "./nimo";
|
|
18
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,cAAc;AACd,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEzF,eAAe;AACf,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAE9E,aAAa;AACb,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEtE,6CAA6C;AAC7C,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAE1E,mEAAmE;AACnE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA","sourcesContent":["/**\n * Display Profiles\n *\n * Hardware-specific configurations for smart glasses displays.\n * Each profile defines display dimensions, font metrics, and constraints.\n */\n\n// Types\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./types\"\n\n// G1 Profiles\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./g1\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./z100\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./g2\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./nex\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {\n RAYNEO_IO_PROFILE,\n RAYNEO_IO_CFW_PROFILE,\n RAYNEO_IO_HYPHEN_WIDTH_PX,\n RAYNEO_IO_SPACE_WIDTH_PX,\n} from \"./rayneo-io\"\n\nexport {MEMOMIND_ONE_PROFILE} from \"@glassly/miniapp/display\"\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,cAAc;AACd,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEzF,eAAe;AACf,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAE9E,aAAa;AACb,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEtE,6CAA6C;AAC7C,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAE1E,mEAAmE;AACnE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA;AAE7D,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAA","sourcesContent":["/**\n * Display Profiles\n *\n * Hardware-specific configurations for smart glasses displays.\n * Each profile defines display dimensions, font metrics, and constraints.\n */\n\n// Types\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./types\"\n\n// G1 Profiles\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./g1\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./z100\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./g2\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./nex\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {\n RAYNEO_IO_PROFILE,\n RAYNEO_IO_CFW_PROFILE,\n RAYNEO_IO_HYPHEN_WIDTH_PX,\n RAYNEO_IO_SPACE_WIDTH_PX,\n} from \"./rayneo-io\"\n\nexport {MEMOMIND_ONE_PROFILE} from \"@glassly/miniapp/display\"\n\nexport {NIMO_PROFILE} from \"./nimo\"\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nimo.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/nimo.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nimo.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/nimo.ts"],"names":[],"mappings":"AAAA,+IAA+I;AAC/I,OAAO,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAA","sourcesContent":["// Moved into the SDK (@glassly/miniapp/display) so miniapps lay text out the way the host measures it; this path re-exports it for the engine.\nexport {NIMO_PROFILE} from \"@glassly/miniapp/display\"\n"]}
|
|
@@ -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,
|
|
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",
|
|
127
|
-
|
|
128
|
-
|
|
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",
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA+BH,kFAAkF;AAClF,MAAM,UAAU,GAAG,IAAI,OAAO,EAAoB,CAAA;AAElD,MAAM,UAAU,mBAAmB,CACjC,OAAqB,EACrB,CAAoB;IAEpB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAA;IAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,gBAAgB,CAAA;IAClD,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACrC,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA,CAAC,YAAY;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;IAExC,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,IAAI,CAAA;IACvD,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAE7F,MAAM,MAAM,GAAQ,EAAE,CAAA;IACtB,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7D,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACpB,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAQ;QAC9D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,SAAS,CAAC;YAAE,SAAQ;QACnE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAChB,CAAC;IACD,MAAM,CAAC,OAAO,EAAE,CAAA;IAChB,OAAO,EAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAC,CAAA;AACvC,CAAC;AAED,mFAAmF;AACnF,SAAS,cAAc,CAAC,KAA4B,EAAE,SAAqB;IACzE,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7B,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC/B,CAAC;IACD,KAAK,EAAE,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAAE,SAAS,KAAK,CAAA;QACtE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS,EAAE,CAAS;IACjD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACxB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAC/C,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,OAAO,IAAI,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IAC9F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS,EAAE,CAAS,EAAE,GAAW;IAClE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA;IACrD,IAAI,KAAK,GAAoB,IAAI,CAAA;IACjC,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;QACf,IAAI,MAAM,GAAG,CAAC,CAAA;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1C,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;YACjE,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC9E,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACnC,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACX,IAAI,CAAC,GAAG,MAAM;gBAAE,MAAM,GAAG,CAAC,CAAA;QAC5B,CAAC;QACD,IAAI,MAAM,GAAG,GAAG;YAAE,OAAO,KAAK,CAAA;QAC9B,KAAK,GAAG,IAAI,CAAA;QACZ,IAAI,GAAG,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,CAAA;AAC9B,CAAC;AAED,MAAM,aAAa,GAA2B;IAC5C,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;CACP,CAAA;AAED,+CAA+C;AAC/C,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACnD,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IAC5B,IAAI,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACpD,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACf,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,CAAA;QACpC,qEAAqE;QACrE,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG;YAAE,SAAQ;QACtC,IAAI,IAAI,IAAI,IAAI,KAAK,QAAQ;YAAE,GAAG,IAAI,IAAI,CAAA;QAC1C,QAAQ,GAAG,IAAI,CAAA;IACjB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAC3B,CAAC;AAED,oEAAoE;AACpE,SAAS,UAAU,CAAC,OAAyC,EAAE,KAAa;IAC1E,IAAI,EAAE,GAAG,CAAC,CAAA;IACV,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IACvB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK;YAAE,EAAE,GAAG,GAAG,GAAG,CAAC,CAAA;;YACpC,EAAE,GAAG,GAAG,CAAA;IACf,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,+EAA+E;AAC/E,SAAS,UAAU,CAAC,OAAyC,EAAE,KAAa;IAC1E,IAAI,EAAE,GAAG,CAAC,CAAA;IACV,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IACvB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK;YAAE,EAAE,GAAG,GAAG,GAAG,CAAC,CAAA;;YACrC,EAAE,GAAG,GAAG,CAAA;IACf,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC","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-beta.
|
|
3
|
+
"version": "0.4.0-beta.1045",
|
|
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-beta.
|
|
101
|
-
"@glassly/cloud-client": "0.4.0-beta.
|
|
102
|
-
"@glassly/cloud-protocol": "0.4.0-beta.
|
|
103
|
-
"@glassly/crust": "0.4.0-beta.
|
|
104
|
-
"@glassly/miniapp": "0.4.0-beta.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.4.0-beta.1045",
|
|
101
|
+
"@glassly/cloud-client": "0.4.0-beta.1045",
|
|
102
|
+
"@glassly/cloud-protocol": "0.4.0-beta.1045",
|
|
103
|
+
"@glassly/crust": "0.4.0-beta.1045",
|
|
104
|
+
"@glassly/miniapp": "0.4.0-beta.1045",
|
|
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-beta.
|
|
110
|
+
"@glassly/llm-providers": "0.4.0-beta.1045",
|
|
111
111
|
"@huggingface/jinja": "^0.5.9",
|
|
112
112
|
"jsonrepair": "^3.12.0"
|
|
113
113
|
},
|
package/src/engine.ts
CHANGED
|
@@ -129,12 +129,14 @@ export const engine = {
|
|
|
129
129
|
// Not awaited: the exchange behind it is a Core round trip with no client
|
|
130
130
|
// deadline, and start() must resolve offline. The glasses get the token
|
|
131
131
|
// when it lands; identity resolution joins the same single-flight exchange.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
if (!cloudClientService.isCloudDisabled()) {
|
|
133
|
+
void cloudClientService.syncCoreTokenToBluetooth().catch((error) => {
|
|
134
|
+
console.warn(
|
|
135
|
+
"engine.start: initial Cloud core token sync failed:",
|
|
136
|
+
error instanceof Error ? error.message : error,
|
|
137
|
+
)
|
|
138
|
+
})
|
|
139
|
+
}
|
|
138
140
|
startSupportProfileSync()
|
|
139
141
|
// Push device-setting changes to the glasses for ANY host, so
|
|
140
142
|
// engine.glasses.settings.set() reaches the device (not just the Glassly app).
|
|
@@ -237,7 +239,7 @@ export const engine = {
|
|
|
237
239
|
backup,
|
|
238
240
|
/** Device-local voice profiles for on-device speaker ID (Settings > Speakers). */
|
|
239
241
|
speakers,
|
|
240
|
-
/** AI/voice provider key validation — user-supplied keys (Settings > API Keys). */
|
|
242
|
+
/** AI/voice provider key validation — user-supplied keys (Settings > Privacy > API Keys). */
|
|
241
243
|
providerKeys,
|
|
242
244
|
display,
|
|
243
245
|
}
|
package/src/facades/glasses.ts
CHANGED
|
@@ -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 {
|
package/src/facades/reports.ts
CHANGED
|
@@ -169,10 +169,51 @@ async function submitReportInternal(input: InternalSubmitReportInput): Promise<R
|
|
|
169
169
|
return {status: "submitted", reportId, reportStatus}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/** A debug-console log upload: the report it went to, and whether it replaced an earlier upload. */
|
|
173
|
+
export type LogUploadResult =
|
|
174
|
+
| {status: "created" | "updated"; reportId: string}
|
|
175
|
+
| {status: "busy"}
|
|
176
|
+
| {status: "failed"; error: string}
|
|
177
|
+
|
|
178
|
+
/** Uploads within this window after a report's creation replace its phone logs. */
|
|
179
|
+
export const LOG_UPLOAD_WINDOW_MS = 5 * 60_000
|
|
180
|
+
let logUpload: {reportId: string; createdAt: number} | null = null
|
|
181
|
+
let logUploadInFlight = false
|
|
182
|
+
|
|
183
|
+
/** Phone logs only, as a manual bug report; repeated taps cannot spam reports. */
|
|
184
|
+
async function uploadLogs(): Promise<LogUploadResult> {
|
|
185
|
+
if (logUploadInFlight) return {status: "busy"}
|
|
186
|
+
logUploadInFlight = true
|
|
187
|
+
try {
|
|
188
|
+
const logs = logBuffer.getRecentLogs()
|
|
189
|
+
const now = Date.now()
|
|
190
|
+
if (logUpload && now - logUpload.createdAt < LOG_UPLOAD_WINDOW_MS) {
|
|
191
|
+
await cloudClientService.core.reports.addLogs(logUpload.reportId, "phone", logs, {replace: true})
|
|
192
|
+
return {status: "updated", reportId: logUpload.reportId}
|
|
193
|
+
}
|
|
194
|
+
const context = await collectDiagnosticContext()
|
|
195
|
+
const res = await cloudClientService.core.reports.submit({
|
|
196
|
+
kind: "bug",
|
|
197
|
+
trigger: {type: "manual", source: "debug_console", reason: "log_upload"},
|
|
198
|
+
report: {actualBehavior: "Debug console log upload"},
|
|
199
|
+
context,
|
|
200
|
+
})
|
|
201
|
+
logUpload = {reportId: res.reportId, createdAt: now}
|
|
202
|
+
if (logs.length > 0) await cloudClientService.core.reports.addLogs(res.reportId, "phone", logs)
|
|
203
|
+
await cloudClientService.core.reports.complete(res.reportId)
|
|
204
|
+
return {status: "created", reportId: res.reportId}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return {status: "failed", error: error instanceof Error ? error.message : String(error)}
|
|
207
|
+
} finally {
|
|
208
|
+
logUploadInFlight = false
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
172
212
|
export const reports = {
|
|
173
213
|
submit(input: EngineSubmitReportInput): Promise<ReportSubmitResult> {
|
|
174
214
|
return submitReportInternal(input)
|
|
175
215
|
},
|
|
216
|
+
uploadLogs,
|
|
176
217
|
}
|
|
177
218
|
|
|
178
219
|
export function submitAutomaticReport(input: EngineSubmitAutomaticReportInput): Promise<ReportSubmitResult> {
|
|
@@ -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-beta.
|
|
16
|
-
"releaseSetId": "glassly-0.4.0-beta.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.4.0-beta.1045",
|
|
16
|
+
"releaseSetId": "glassly-0.4.0-beta.1045",
|
|
17
|
+
"sourceCommit": "45448a401fb63f86017f0044a2837836b087644d",
|
|
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
|
-
| "
|
|
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
|
package/src/runtime/config.ts
CHANGED
|
@@ -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
|
-
|
|
|
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
|
-
|
|
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") {
|