@ateam-ai-mobile/plugin-runtime 0.1.0 → 0.1.1
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/dist/index.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1707 -1669
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1756 -1719
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/bridge/native.ts +1 -1
- package/src/bundles/bundleManager.ts +14 -1
- package/src/host.ts +45 -1
- package/src/index.ts +1 -0
- package/src/sdk/usePluginTheme.ts +7 -2
package/dist/index.js
CHANGED
|
@@ -64,6 +64,7 @@ __export(index_exports, {
|
|
|
64
64
|
View: () => import_react_native.View,
|
|
65
65
|
bundleManager: () => bundleManager,
|
|
66
66
|
createNativeBridge: () => createNativeBridge,
|
|
67
|
+
gatePluginNative: () => gatePluginNative,
|
|
67
68
|
getHaptics: () => getHaptics,
|
|
68
69
|
getNativeBundleHash: () => getNativeBundleHash,
|
|
69
70
|
getNativeBundleUrl: () => getNativeBundleUrl,
|
|
@@ -410,6 +411,7 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
410
411
|
|
|
411
412
|
// src/sdk/usePluginTheme.ts
|
|
412
413
|
var import_react2 = require("react");
|
|
414
|
+
var import_react_native3 = require("react-native");
|
|
413
415
|
var import_core = require("@ateam-ai-mobile/core");
|
|
414
416
|
var adaColors = {
|
|
415
417
|
bg: import_core.ada.paper,
|
|
@@ -432,7 +434,7 @@ var adaColors = {
|
|
|
432
434
|
purpleSoft: import_core.ada.orangeSoft
|
|
433
435
|
};
|
|
434
436
|
var _colors = adaColors;
|
|
435
|
-
var _isDark =
|
|
437
|
+
var _isDark = null;
|
|
436
438
|
var _subscribers = /* @__PURE__ */ new Set();
|
|
437
439
|
function setPluginThemeColors(colors, opts) {
|
|
438
440
|
_colors = { ...adaColors, ...colors };
|
|
@@ -447,7 +449,9 @@ function subscribe(fn) {
|
|
|
447
449
|
}
|
|
448
450
|
function usePluginTheme() {
|
|
449
451
|
const colors = (0, import_react2.useSyncExternalStore)(subscribe, () => _colors);
|
|
450
|
-
const
|
|
452
|
+
const hostIsDark = (0, import_react2.useSyncExternalStore)(subscribe, () => _isDark);
|
|
453
|
+
const scheme = (0, import_react_native3.useColorScheme)();
|
|
454
|
+
const isDark = hostIsDark ?? scheme === "dark";
|
|
451
455
|
return (0, import_react2.useMemo)(() => ({
|
|
452
456
|
colors,
|
|
453
457
|
spacing: {
|
|
@@ -548,6 +552,34 @@ function setPluginNativeProvider(native) {
|
|
|
548
552
|
function getPluginNative() {
|
|
549
553
|
return _pluginNative;
|
|
550
554
|
}
|
|
555
|
+
function blocked(api) {
|
|
556
|
+
return new Proxy({}, {
|
|
557
|
+
get: (_t, method) => {
|
|
558
|
+
if (typeof method !== "string") return void 0;
|
|
559
|
+
return () => {
|
|
560
|
+
console.warn(`[adas] native.${api}.${method} blocked \u2014 capability '${api}' not declared in the plugin manifest`);
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
function gatePluginNative(native, declared) {
|
|
566
|
+
const caps = declared || {};
|
|
567
|
+
return {
|
|
568
|
+
camera: caps.camera ? native.camera : blocked("camera"),
|
|
569
|
+
location: caps.location ? native.location : blocked("location"),
|
|
570
|
+
storage: caps.offline ? native.storage : blocked("storage"),
|
|
571
|
+
biometrics: caps.biometrics ? native.biometrics : blocked("biometrics"),
|
|
572
|
+
biometricsV2: caps.biometricsV2 ? native.biometricsV2 : blocked("biometricsV2"),
|
|
573
|
+
notifications: caps.notifications ? native.notifications : blocked("notifications"),
|
|
574
|
+
haptics: caps.haptics ? native.haptics : blocked("haptics"),
|
|
575
|
+
connectivity: native.connectivity,
|
|
576
|
+
fileSystem: caps.fileSystem ? native.fileSystem : blocked("fileSystem"),
|
|
577
|
+
cookies: caps.cookies ? native.cookies : blocked("cookies"),
|
|
578
|
+
sharing: caps.sharing ? native.sharing : blocked("sharing"),
|
|
579
|
+
scanner: caps.scanner ? native.scanner : blocked("scanner"),
|
|
580
|
+
nfc: caps.nfc ? native.nfc : blocked("nfc")
|
|
581
|
+
};
|
|
582
|
+
}
|
|
551
583
|
var _nativeRegistry = /* @__PURE__ */ new Map();
|
|
552
584
|
function registerNativePlugin(id, plugin) {
|
|
553
585
|
_nativeRegistry.set(id, plugin);
|
|
@@ -584,1741 +616,1746 @@ function resolveBundleModule(name) {
|
|
|
584
616
|
}
|
|
585
617
|
|
|
586
618
|
// src/bundles/bundleManager.ts
|
|
587
|
-
var
|
|
588
|
-
var
|
|
619
|
+
var import_react8 = __toESM(require("react"));
|
|
620
|
+
var import_react9 = require("react");
|
|
589
621
|
var ReactNative = __toESM(require("react-native"));
|
|
622
|
+
var import_core6 = require("@ateam-ai-mobile/core");
|
|
623
|
+
|
|
624
|
+
// src/surfaces/SurfaceDrawer.tsx
|
|
625
|
+
var import_react5 = require("react");
|
|
626
|
+
var import_react_native5 = require("react-native");
|
|
627
|
+
var import_react_native_svg2 = __toESM(require("react-native-svg"));
|
|
590
628
|
var import_core2 = require("@ateam-ai-mobile/core");
|
|
591
629
|
|
|
592
|
-
// src/
|
|
593
|
-
var
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
buf[len - 3] = bitLen >>> 16 & 255;
|
|
672
|
-
buf[len - 2] = bitLen >>> 8 & 255;
|
|
673
|
-
buf[len - 1] = bitLen & 255;
|
|
674
|
-
const h = new Uint32Array([
|
|
675
|
-
1779033703,
|
|
676
|
-
3144134277,
|
|
677
|
-
1013904242,
|
|
678
|
-
2773480762,
|
|
679
|
-
1359893119,
|
|
680
|
-
2600822924,
|
|
681
|
-
528734635,
|
|
682
|
-
1541459225
|
|
683
|
-
]);
|
|
684
|
-
const w = new Uint32Array(64);
|
|
685
|
-
for (let i = 0; i < buf.length; i += 64) {
|
|
686
|
-
for (let t = 0; t < 16; t++) {
|
|
687
|
-
const j = i + t * 4;
|
|
688
|
-
w[t] = buf[j] << 24 | buf[j + 1] << 16 | buf[j + 2] << 8 | buf[j + 3];
|
|
689
|
-
}
|
|
690
|
-
for (let t = 16; t < 64; t++) {
|
|
691
|
-
const s0 = rotr(7, w[t - 15]) ^ rotr(18, w[t - 15]) ^ w[t - 15] >>> 3;
|
|
692
|
-
const s1 = rotr(17, w[t - 2]) ^ rotr(19, w[t - 2]) ^ w[t - 2] >>> 10;
|
|
693
|
-
w[t] = w[t - 16] + s0 + w[t - 7] + s1 | 0;
|
|
694
|
-
}
|
|
695
|
-
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];
|
|
696
|
-
for (let t = 0; t < 64; t++) {
|
|
697
|
-
const S1 = rotr(6, e) ^ rotr(11, e) ^ rotr(25, e);
|
|
698
|
-
const ch = e & f ^ ~e & g;
|
|
699
|
-
const temp1 = hh + S1 + ch + K[t] + w[t] | 0;
|
|
700
|
-
const S0 = rotr(2, a) ^ rotr(13, a) ^ rotr(22, a);
|
|
701
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
702
|
-
const temp2 = S0 + maj | 0;
|
|
703
|
-
hh = g;
|
|
704
|
-
g = f;
|
|
705
|
-
f = e;
|
|
706
|
-
e = d + temp1 | 0;
|
|
707
|
-
d = c;
|
|
708
|
-
c = b;
|
|
709
|
-
b = a;
|
|
710
|
-
a = temp1 + temp2 | 0;
|
|
630
|
+
// src/surfaces/AdaOrb.tsx
|
|
631
|
+
var import_react4 = require("react");
|
|
632
|
+
var import_react_native4 = require("react-native");
|
|
633
|
+
var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
|
|
634
|
+
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
635
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
636
|
+
var AnimatedCircle = import_react_native_reanimated.default.createAnimatedComponent(import_react_native_svg.Circle);
|
|
637
|
+
function AdaOrb({ size = 120, state = "idle", inscription = true }) {
|
|
638
|
+
const showInscription = inscription && size >= 60;
|
|
639
|
+
const center = size / 2;
|
|
640
|
+
const coreR = size * 0.32;
|
|
641
|
+
const innerHaloR = size * 0.42;
|
|
642
|
+
const outerHaloR = size * 0.5;
|
|
643
|
+
const coreScale = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
644
|
+
const innerScale = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
645
|
+
const outerScale = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
646
|
+
const outerOpacity = (0, import_react_native_reanimated.useSharedValue)(0.55);
|
|
647
|
+
const rippleCycle = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
648
|
+
const orbit1 = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
649
|
+
const orbit2 = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
650
|
+
const orbit3 = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
651
|
+
const beat = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
652
|
+
(0, import_react4.useEffect)(() => {
|
|
653
|
+
(0, import_react_native_reanimated.cancelAnimation)(coreScale);
|
|
654
|
+
(0, import_react_native_reanimated.cancelAnimation)(innerScale);
|
|
655
|
+
(0, import_react_native_reanimated.cancelAnimation)(outerScale);
|
|
656
|
+
(0, import_react_native_reanimated.cancelAnimation)(outerOpacity);
|
|
657
|
+
(0, import_react_native_reanimated.cancelAnimation)(rippleCycle);
|
|
658
|
+
(0, import_react_native_reanimated.cancelAnimation)(orbit1);
|
|
659
|
+
(0, import_react_native_reanimated.cancelAnimation)(orbit2);
|
|
660
|
+
(0, import_react_native_reanimated.cancelAnimation)(orbit3);
|
|
661
|
+
(0, import_react_native_reanimated.cancelAnimation)(beat);
|
|
662
|
+
rippleCycle.value = 0;
|
|
663
|
+
orbit1.value = 0;
|
|
664
|
+
orbit2.value = 0;
|
|
665
|
+
orbit3.value = 0;
|
|
666
|
+
beat.value = 1;
|
|
667
|
+
let breathMs = 3600;
|
|
668
|
+
let breathAmount = 0.025;
|
|
669
|
+
if (state === "listening") {
|
|
670
|
+
breathMs = 2e3;
|
|
671
|
+
breathAmount = 0.05;
|
|
672
|
+
rippleCycle.value = (0, import_react_native_reanimated.withRepeat)(
|
|
673
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 2e3, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
|
|
674
|
+
-1,
|
|
675
|
+
false
|
|
676
|
+
);
|
|
677
|
+
} else if (state === "thinking") {
|
|
678
|
+
breathMs = 2400;
|
|
679
|
+
breathAmount = 0.04;
|
|
680
|
+
orbit1.value = (0, import_react_native_reanimated.withRepeat)(
|
|
681
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 1100, easing: import_react_native_reanimated.Easing.linear }),
|
|
682
|
+
-1,
|
|
683
|
+
false
|
|
684
|
+
);
|
|
685
|
+
orbit2.value = (0, import_react_native_reanimated.withRepeat)(
|
|
686
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 1900, easing: import_react_native_reanimated.Easing.linear }),
|
|
687
|
+
-1,
|
|
688
|
+
false
|
|
689
|
+
);
|
|
690
|
+
orbit3.value = (0, import_react_native_reanimated.withRepeat)(
|
|
691
|
+
(0, import_react_native_reanimated.withTiming)(-1, { duration: 2700, easing: import_react_native_reanimated.Easing.linear }),
|
|
692
|
+
-1,
|
|
693
|
+
false
|
|
694
|
+
);
|
|
695
|
+
} else if (state === "speaking") {
|
|
696
|
+
breathMs = 700;
|
|
697
|
+
breathAmount = 0.13;
|
|
698
|
+
beat.value = (0, import_react_native_reanimated.withRepeat)(
|
|
699
|
+
(0, import_react_native_reanimated.withSequence)(
|
|
700
|
+
(0, import_react_native_reanimated.withTiming)(1.08, { duration: 90, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
|
|
701
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 130, easing: import_react_native_reanimated.Easing.in(import_react_native_reanimated.Easing.quad) }),
|
|
702
|
+
(0, import_react_native_reanimated.withTiming)(1.05, { duration: 80, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
|
|
703
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 200, easing: import_react_native_reanimated.Easing.in(import_react_native_reanimated.Easing.quad) }),
|
|
704
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: 280 })
|
|
705
|
+
),
|
|
706
|
+
-1,
|
|
707
|
+
false
|
|
708
|
+
);
|
|
711
709
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
};
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
return _storage;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// src/bundles/bundleManager.ts
|
|
765
|
-
var ReactShim = {
|
|
766
|
-
__esModule: true,
|
|
767
|
-
default: import_react4.default,
|
|
768
|
-
...import_react4.default,
|
|
769
|
-
// Explicitly include hooks (React 19 may not have them as own enumerable props)
|
|
770
|
-
useState: import_react5.useState,
|
|
771
|
-
useEffect: import_react5.useEffect,
|
|
772
|
-
useCallback: import_react5.useCallback,
|
|
773
|
-
useMemo: import_react5.useMemo,
|
|
774
|
-
useRef: import_react5.useRef,
|
|
775
|
-
useContext: import_react5.useContext,
|
|
776
|
-
useReducer: import_react5.useReducer,
|
|
777
|
-
useLayoutEffect: import_react5.useLayoutEffect,
|
|
778
|
-
useImperativeHandle: import_react5.useImperativeHandle,
|
|
779
|
-
useDebugValue: import_react5.useDebugValue,
|
|
780
|
-
createElement: import_react4.default.createElement,
|
|
781
|
-
Fragment: import_react4.default.Fragment,
|
|
782
|
-
Component: import_react4.default.Component,
|
|
783
|
-
PureComponent: import_react4.default.PureComponent,
|
|
784
|
-
createContext: import_react4.default.createContext,
|
|
785
|
-
forwardRef: import_react4.default.forwardRef,
|
|
786
|
-
memo: import_react4.default.memo,
|
|
787
|
-
Children: import_react4.default.Children,
|
|
788
|
-
cloneElement: import_react4.default.cloneElement,
|
|
789
|
-
isValidElement: import_react4.default.isValidElement,
|
|
790
|
-
createRef: import_react4.default.createRef,
|
|
791
|
-
lazy: import_react4.default.lazy,
|
|
792
|
-
Suspense: import_react4.default.Suspense
|
|
793
|
-
};
|
|
794
|
-
var PluginSDKShim = Object.freeze({
|
|
795
|
-
...sdk_exports,
|
|
796
|
-
PluginSDK: Object.freeze({
|
|
797
|
-
...PluginSDK,
|
|
798
|
-
register: PluginSDK.register
|
|
799
|
-
}),
|
|
800
|
-
register
|
|
801
|
-
});
|
|
802
|
-
var requireShim = (name) => {
|
|
803
|
-
if (name === "react") return ReactShim;
|
|
804
|
-
if (name === "react-native") return ReactNative;
|
|
805
|
-
if (name === "@adas/plugin-sdk") return PluginSDKShim;
|
|
806
|
-
const hostModule = resolveBundleModule(name);
|
|
807
|
-
if (hostModule !== void 0) return hostModule;
|
|
808
|
-
console.warn(`[BundleManager] Unknown module: ${name} \u2014 register it via registerBundleModules()`);
|
|
809
|
-
return {};
|
|
810
|
-
};
|
|
811
|
-
var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
812
|
-
var BundleManager = class {
|
|
813
|
-
constructor() {
|
|
814
|
-
/** In-memory module cache: bundleUrl → evaluated module.exports */
|
|
815
|
-
this.modules = /* @__PURE__ */ new Map();
|
|
816
|
-
/** In-flight download deduplication: bundleUrl → Promise */
|
|
817
|
-
this.inflight = /* @__PURE__ */ new Map();
|
|
818
|
-
}
|
|
819
|
-
// ── Public API ──────────────────────────────────────────────
|
|
820
|
-
/**
|
|
821
|
-
* Load a plugin component. Returns the RegisteredUIPlugin object.
|
|
822
|
-
* Handles: in-memory cache → disk cache → download → evaluate → extract.
|
|
823
|
-
*
|
|
824
|
-
* `expectedHash` (SHA-256 hex from cp.getContextPlugin manifest) MUST be
|
|
825
|
-
* provided for any bundle the user has not previously verified — without
|
|
826
|
-
* it, a tampered bundle is `eval`'d as JS with full RN runtime + every
|
|
827
|
-
* native capability the manifest declares.
|
|
828
|
-
*/
|
|
829
|
-
async load(pluginId, bundleUrl, version, expectedHash) {
|
|
830
|
-
const cached = this.getComponentFromMemory(pluginId, bundleUrl);
|
|
831
|
-
if (cached) return cached;
|
|
832
|
-
let modulePromise = this.inflight.get(bundleUrl);
|
|
833
|
-
if (!modulePromise) {
|
|
834
|
-
modulePromise = this.loadModule(bundleUrl, version, expectedHash);
|
|
835
|
-
this.inflight.set(bundleUrl, modulePromise);
|
|
836
|
-
modulePromise.catch(() => {
|
|
837
|
-
}).finally(() => this.inflight.delete(bundleUrl));
|
|
838
|
-
}
|
|
839
|
-
await modulePromise;
|
|
840
|
-
const component = this.getComponentFromMemory(pluginId, bundleUrl);
|
|
841
|
-
if (!component) {
|
|
842
|
-
throw new Error(
|
|
843
|
-
`Bundle loaded from ${bundleUrl} but no component found for "${pluginId}". Available exports: ${this.describeModule(this.modules.get(bundleUrl))}`
|
|
844
|
-
);
|
|
845
|
-
}
|
|
846
|
-
return component;
|
|
847
|
-
}
|
|
848
|
-
/**
|
|
849
|
-
* Prewarm: load every plugin bundle in the background after app boot, so a
|
|
850
|
-
* later open is instant (in-memory hit) instead of round-tripping the
|
|
851
|
-
* network. Errors are swallowed per-plugin — one bad bundle shouldn't
|
|
852
|
-
* block others. Concurrency capped at 3.
|
|
853
|
-
*/
|
|
854
|
-
async prewarmAll(items) {
|
|
855
|
-
const queue = [...items];
|
|
856
|
-
const concurrency = Math.min(3, queue.length);
|
|
857
|
-
const start = Date.now();
|
|
858
|
-
let okCount = 0;
|
|
859
|
-
let failCount = 0;
|
|
860
|
-
const worker = async () => {
|
|
861
|
-
while (queue.length > 0) {
|
|
862
|
-
const it = queue.shift();
|
|
863
|
-
if (!it) return;
|
|
864
|
-
try {
|
|
865
|
-
await this.load(it.pluginId, it.bundleUrl, it.version, it.bundleHash);
|
|
866
|
-
okCount++;
|
|
867
|
-
} catch (err) {
|
|
868
|
-
failCount++;
|
|
869
|
-
console.log(`[prewarm] ${it.pluginId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
710
|
+
const breathEasing = state === "speaking" ? import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) : import_react_native_reanimated.Easing.inOut(import_react_native_reanimated.Easing.sin);
|
|
711
|
+
coreScale.value = (0, import_react_native_reanimated.withRepeat)(
|
|
712
|
+
(0, import_react_native_reanimated.withSequence)(
|
|
713
|
+
(0, import_react_native_reanimated.withTiming)(1 + breathAmount, { duration: breathMs, easing: breathEasing }),
|
|
714
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: breathMs, easing: breathEasing })
|
|
715
|
+
),
|
|
716
|
+
-1,
|
|
717
|
+
false
|
|
718
|
+
);
|
|
719
|
+
innerScale.value = (0, import_react_native_reanimated.withRepeat)(
|
|
720
|
+
(0, import_react_native_reanimated.withSequence)(
|
|
721
|
+
(0, import_react_native_reanimated.withTiming)(1 + breathAmount * 1.4, { duration: breathMs * 1.15, easing: breathEasing }),
|
|
722
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: breathMs * 1.15, easing: breathEasing })
|
|
723
|
+
),
|
|
724
|
+
-1,
|
|
725
|
+
false
|
|
726
|
+
);
|
|
727
|
+
outerScale.value = (0, import_react_native_reanimated.withRepeat)(
|
|
728
|
+
(0, import_react_native_reanimated.withSequence)(
|
|
729
|
+
(0, import_react_native_reanimated.withTiming)(1 + breathAmount * 1.8, { duration: breathMs * 1.3, easing: breathEasing }),
|
|
730
|
+
(0, import_react_native_reanimated.withTiming)(1, { duration: breathMs * 1.3, easing: breathEasing })
|
|
731
|
+
),
|
|
732
|
+
-1,
|
|
733
|
+
false
|
|
734
|
+
);
|
|
735
|
+
outerOpacity.value = (0, import_react_native_reanimated.withRepeat)(
|
|
736
|
+
(0, import_react_native_reanimated.withSequence)(
|
|
737
|
+
(0, import_react_native_reanimated.withTiming)(state === "idle" ? 0.55 : 0.8, { duration: breathMs * 1.3, easing: breathEasing }),
|
|
738
|
+
(0, import_react_native_reanimated.withTiming)(0.35, { duration: breathMs * 1.3, easing: breathEasing })
|
|
739
|
+
),
|
|
740
|
+
-1,
|
|
741
|
+
false
|
|
742
|
+
);
|
|
743
|
+
}, [state]);
|
|
744
|
+
const coreProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
745
|
+
r: coreR * coreScale.value * beat.value
|
|
746
|
+
}));
|
|
747
|
+
const innerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
748
|
+
r: innerHaloR * innerScale.value * beat.value
|
|
749
|
+
}));
|
|
750
|
+
const outerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
751
|
+
r: outerHaloR * outerScale.value,
|
|
752
|
+
opacity: outerOpacity.value
|
|
753
|
+
}));
|
|
754
|
+
const ripple1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
755
|
+
const t = rippleCycle.value;
|
|
756
|
+
return {
|
|
757
|
+
r: outerHaloR * (1 + t * 0.55),
|
|
758
|
+
opacity: state === "listening" ? 0.55 * (1 - t) : 0
|
|
872
759
|
};
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
760
|
+
});
|
|
761
|
+
const ripple2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
762
|
+
const t = (rippleCycle.value + 0.34) % 1;
|
|
763
|
+
return {
|
|
764
|
+
r: outerHaloR * (1 + t * 0.55),
|
|
765
|
+
opacity: state === "listening" ? 0.45 * (1 - t) : 0
|
|
766
|
+
};
|
|
767
|
+
});
|
|
768
|
+
const ripple3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
769
|
+
const t = (rippleCycle.value + 0.67) % 1;
|
|
770
|
+
return {
|
|
771
|
+
r: outerHaloR * (1 + t * 0.55),
|
|
772
|
+
opacity: state === "listening" ? 0.35 * (1 - t) : 0
|
|
773
|
+
};
|
|
774
|
+
});
|
|
775
|
+
const spark1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
776
|
+
const angle = orbit1.value * Math.PI * 2 - Math.PI / 2;
|
|
777
|
+
const r = coreR * 0.55;
|
|
778
|
+
return {
|
|
779
|
+
cx: center + Math.cos(angle) * r,
|
|
780
|
+
cy: center + Math.sin(angle) * r,
|
|
781
|
+
opacity: state === "thinking" ? 1 : 0
|
|
782
|
+
};
|
|
783
|
+
});
|
|
784
|
+
const spark2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
785
|
+
const angle = orbit2.value * Math.PI * 2 + Math.PI * 0.6;
|
|
786
|
+
const r = coreR * 0.85;
|
|
787
|
+
return {
|
|
788
|
+
cx: center + Math.cos(angle) * r,
|
|
789
|
+
cy: center + Math.sin(angle) * r,
|
|
790
|
+
opacity: state === "thinking" ? 0.9 : 0
|
|
791
|
+
};
|
|
792
|
+
});
|
|
793
|
+
const spark3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
794
|
+
const angle = orbit3.value * Math.PI * 2 + Math.PI * 1.3;
|
|
795
|
+
const r = coreR * 1.05;
|
|
796
|
+
return {
|
|
797
|
+
cx: center + Math.cos(angle) * r,
|
|
798
|
+
cy: center + Math.sin(angle) * r,
|
|
799
|
+
opacity: state === "thinking" ? 0.7 : 0
|
|
800
|
+
};
|
|
801
|
+
});
|
|
802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.View, { style: [styles2.wrap, { width: size, height: size }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.default, { width: size, height: size, children: [
|
|
803
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.Defs, { children: [
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaCore", cx: "36%", cy: "30%", r: "70%", children: [
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FFE0B0", stopOpacity: "1" }),
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "28%", stopColor: "#FFA85A", stopOpacity: "1" }),
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "65%", stopColor: "#FF7A28", stopOpacity: "1" }),
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#B8410A", stopOpacity: "1" })
|
|
809
|
+
] }),
|
|
810
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaInner", cx: "50%", cy: "50%", r: "50%", children: [
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FF8A3C", stopOpacity: "0.55" }),
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FF7028", stopOpacity: "0" })
|
|
813
|
+
] }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaOuter", cx: "50%", cy: "50%", r: "50%", children: [
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FF7A28", stopOpacity: "0.4" }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FF6018", stopOpacity: "0" })
|
|
817
|
+
] }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaSpark", cx: "50%", cy: "50%", r: "50%", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FFFAEB", stopOpacity: "1" }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "60%", stopColor: "#FFD095", stopOpacity: "0.9" }),
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FFA85A", stopOpacity: "0" })
|
|
822
|
+
] })
|
|
823
|
+
] }),
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
825
|
+
AnimatedCircle,
|
|
826
|
+
{
|
|
827
|
+
cx: center,
|
|
828
|
+
cy: center,
|
|
829
|
+
stroke: "#FF7A28",
|
|
830
|
+
strokeWidth: 1.5,
|
|
831
|
+
fill: "none",
|
|
832
|
+
animatedProps: ripple1Props
|
|
901
833
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
if (entry.bundleUrl === bundleUrl && entry.version === version) {
|
|
913
|
-
const age = Date.now() - entry.timestamp;
|
|
914
|
-
const hashOk = expectedLc && entry.bundleHash && entry.bundleHash.toLowerCase() === expectedLc;
|
|
915
|
-
if (age < CACHE_TTL && hashOk) {
|
|
916
|
-
content = await storage.readBundle(entry.localPath);
|
|
917
|
-
if (content) break;
|
|
918
|
-
}
|
|
834
|
+
),
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
836
|
+
AnimatedCircle,
|
|
837
|
+
{
|
|
838
|
+
cx: center,
|
|
839
|
+
cy: center,
|
|
840
|
+
stroke: "#FF7A28",
|
|
841
|
+
strokeWidth: 1.5,
|
|
842
|
+
fill: "none",
|
|
843
|
+
animatedProps: ripple2Props
|
|
919
844
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
timestamp: Date.now(),
|
|
931
|
-
bundleUrl,
|
|
932
|
-
bundleHash: downloaded.sha256
|
|
933
|
-
};
|
|
934
|
-
await storage.saveIndex(index);
|
|
935
|
-
} catch (err) {
|
|
936
|
-
console.warn("[BundleManager] Cache write error:", err);
|
|
845
|
+
),
|
|
846
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
847
|
+
AnimatedCircle,
|
|
848
|
+
{
|
|
849
|
+
cx: center,
|
|
850
|
+
cy: center,
|
|
851
|
+
stroke: "#FF7A28",
|
|
852
|
+
strokeWidth: 1.5,
|
|
853
|
+
fill: "none",
|
|
854
|
+
animatedProps: ripple3Props
|
|
937
855
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
*/
|
|
949
|
-
async download(bundleUrl, expectedHash) {
|
|
950
|
-
const cacheBust = `${bundleUrl}${bundleUrl.includes("?") ? "&" : "?"}t=${Date.now()}`;
|
|
951
|
-
const response = await (0, import_core2.apiFetchRaw)(cacheBust);
|
|
952
|
-
if (!response.ok) {
|
|
953
|
-
const body = await response.text().catch(() => "");
|
|
954
|
-
throw new Error(`Download failed: ${response.status} ${response.statusText} \u2014 ${body.substring(0, 200)}`);
|
|
955
|
-
}
|
|
956
|
-
const content = await response.text();
|
|
957
|
-
if (content.length < 50 || content.trimStart().startsWith("<!")) {
|
|
958
|
-
throw new Error("Bundle content is empty or HTML \u2014 server may have returned an error page");
|
|
959
|
-
}
|
|
960
|
-
const headerHash = (response.headers.get("x-bundle-sha256") || "").toLowerCase();
|
|
961
|
-
const computed = sha256Hex(content);
|
|
962
|
-
if (expectedHash) {
|
|
963
|
-
if (computed !== expectedHash) {
|
|
964
|
-
throw new Error(
|
|
965
|
-
`Bundle integrity FAIL: expected sha256=${expectedHash.slice(0, 12)}... got ${computed.slice(0, 12)}.... Refusing to evaluate.`
|
|
966
|
-
);
|
|
856
|
+
),
|
|
857
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaOuter)", animatedProps: outerProps }),
|
|
858
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaInner)", animatedProps: innerProps }),
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaCore)", animatedProps: coreProps }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
861
|
+
AnimatedCircle,
|
|
862
|
+
{
|
|
863
|
+
r: Math.max(3, size * 0.05),
|
|
864
|
+
fill: "url(#adaSpark)",
|
|
865
|
+
animatedProps: spark1Props
|
|
967
866
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
867
|
+
),
|
|
868
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
869
|
+
AnimatedCircle,
|
|
870
|
+
{
|
|
871
|
+
r: Math.max(2.5, size * 0.04),
|
|
872
|
+
fill: "url(#adaSpark)",
|
|
873
|
+
animatedProps: spark2Props
|
|
972
874
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
)
|
|
875
|
+
),
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
877
|
+
AnimatedCircle,
|
|
878
|
+
{
|
|
879
|
+
r: Math.max(2, size * 0.032),
|
|
880
|
+
fill: "url(#adaSpark)",
|
|
881
|
+
animatedProps: spark3Props
|
|
978
882
|
}
|
|
979
|
-
|
|
883
|
+
),
|
|
884
|
+
showInscription && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
885
|
+
import_react_native_svg.Text,
|
|
886
|
+
{
|
|
887
|
+
x: center,
|
|
888
|
+
y: center + size * 0.11,
|
|
889
|
+
fontSize: size * 0.34,
|
|
890
|
+
fontWeight: "600",
|
|
891
|
+
fill: "#FFF5E0",
|
|
892
|
+
textAnchor: "middle",
|
|
893
|
+
letterSpacing: -size * 5e-3,
|
|
894
|
+
children: "iA"
|
|
895
|
+
}
|
|
896
|
+
)
|
|
897
|
+
] }) });
|
|
898
|
+
}
|
|
899
|
+
var styles2 = import_react_native4.StyleSheet.create({
|
|
900
|
+
wrap: {
|
|
901
|
+
alignItems: "center",
|
|
902
|
+
justifyContent: "center"
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
// src/surfaces/SurfaceDrawer.tsx
|
|
907
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
908
|
+
var SCREEN_H = import_react_native5.Dimensions.get("window").height;
|
|
909
|
+
var fontFam = import_react_native5.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
910
|
+
function SurfaceDrawer({
|
|
911
|
+
visible,
|
|
912
|
+
onClose,
|
|
913
|
+
title,
|
|
914
|
+
subtitle,
|
|
915
|
+
privacy,
|
|
916
|
+
showOrb = true,
|
|
917
|
+
heightRatio = 0.85,
|
|
918
|
+
children
|
|
919
|
+
}) {
|
|
920
|
+
const sheetH = Math.round(SCREEN_H * heightRatio);
|
|
921
|
+
const fadeAnim = (0, import_react5.useRef)(new import_react_native5.Animated.Value(0)).current;
|
|
922
|
+
const slideAnim = (0, import_react5.useRef)(new import_react_native5.Animated.Value(sheetH)).current;
|
|
923
|
+
(0, import_react5.useEffect)(() => {
|
|
924
|
+
if (visible) {
|
|
925
|
+
import_react_native5.Animated.parallel([
|
|
926
|
+
import_react_native5.Animated.timing(fadeAnim, { toValue: 1, duration: 220, useNativeDriver: true }),
|
|
927
|
+
import_react_native5.Animated.spring(slideAnim, { toValue: 0, useNativeDriver: true, tension: 80, friction: 12 })
|
|
928
|
+
]).start();
|
|
980
929
|
} else {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
);
|
|
930
|
+
fadeAnim.setValue(0);
|
|
931
|
+
slideAnim.setValue(sheetH);
|
|
984
932
|
}
|
|
985
|
-
|
|
933
|
+
}, [visible]);
|
|
934
|
+
const close = () => {
|
|
935
|
+
import_react_native5.Animated.parallel([
|
|
936
|
+
import_react_native5.Animated.timing(fadeAnim, { toValue: 0, duration: 160, useNativeDriver: true }),
|
|
937
|
+
import_react_native5.Animated.timing(slideAnim, { toValue: sheetH, duration: 200, useNativeDriver: true })
|
|
938
|
+
]).start(() => onClose());
|
|
939
|
+
};
|
|
940
|
+
if (!visible) return null;
|
|
941
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native5.Animated.View, { style: [styles3.overlay, { opacity: fadeAnim }], pointerEvents: "auto", children: [
|
|
942
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.Pressable, { style: import_react_native5.StyleSheet.absoluteFill, onPress: close }),
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
944
|
+
import_react_native5.Animated.View,
|
|
945
|
+
{
|
|
946
|
+
style: [
|
|
947
|
+
styles3.sheet,
|
|
948
|
+
{ height: sheetH, transform: [{ translateY: slideAnim }] }
|
|
949
|
+
],
|
|
950
|
+
children: [
|
|
951
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.View, { style: styles3.handle }),
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native5.View, { style: styles3.header, children: [
|
|
953
|
+
showOrb ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.View, { style: styles3.headerOrb, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AdaOrb, { size: 36, state: "idle" }) }) : null,
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native5.View, { style: { flex: 1 }, children: [
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.Text, { style: styles3.title, children: title }),
|
|
956
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.Text, { style: styles3.subtitle, children: subtitle }) : null,
|
|
957
|
+
privacy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native5.View, { style: styles3.privacyPill, children: [
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg2.default, { width: 11, height: 11, viewBox: "0 0 24 24", fill: "none", stroke: import_core2.ada.inkSoft, strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2z" }),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M7 11V7a5 5 0 0110 0v4" })
|
|
961
|
+
] }),
|
|
962
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.Text, { style: styles3.privacyText, children: "Only you can see this" })
|
|
963
|
+
] }) : null
|
|
964
|
+
] }),
|
|
965
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
966
|
+
import_react_native5.Pressable,
|
|
967
|
+
{
|
|
968
|
+
accessibilityRole: "button",
|
|
969
|
+
accessibilityLabel: "Close",
|
|
970
|
+
style: styles3.closeBtn,
|
|
971
|
+
onPress: close,
|
|
972
|
+
hitSlop: 12,
|
|
973
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: import_core2.ada.inkSoft, strokeWidth: 2.2, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M18 6L6 18M6 6l12 12" }) })
|
|
974
|
+
}
|
|
975
|
+
)
|
|
976
|
+
] }),
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native5.View, { style: styles3.body, children })
|
|
978
|
+
]
|
|
979
|
+
}
|
|
980
|
+
)
|
|
981
|
+
] });
|
|
982
|
+
}
|
|
983
|
+
var styles3 = import_react_native5.StyleSheet.create({
|
|
984
|
+
overlay: {
|
|
985
|
+
position: "absolute",
|
|
986
|
+
top: 0,
|
|
987
|
+
left: 0,
|
|
988
|
+
right: 0,
|
|
989
|
+
bottom: 0,
|
|
990
|
+
backgroundColor: "rgba(26, 20, 16, 0.35)",
|
|
991
|
+
justifyContent: "flex-end",
|
|
992
|
+
zIndex: 999,
|
|
993
|
+
elevation: 999
|
|
994
|
+
},
|
|
995
|
+
sheet: {
|
|
996
|
+
backgroundColor: import_core2.ada.paper,
|
|
997
|
+
borderTopLeftRadius: 28,
|
|
998
|
+
borderTopRightRadius: 28,
|
|
999
|
+
overflow: "hidden"
|
|
1000
|
+
},
|
|
1001
|
+
handle: {
|
|
1002
|
+
width: 40,
|
|
1003
|
+
height: 4,
|
|
1004
|
+
borderRadius: 2,
|
|
1005
|
+
backgroundColor: import_core2.ada.inkMuted,
|
|
1006
|
+
opacity: 0.3,
|
|
1007
|
+
alignSelf: "center",
|
|
1008
|
+
marginTop: 10,
|
|
1009
|
+
marginBottom: 6
|
|
1010
|
+
},
|
|
1011
|
+
header: {
|
|
1012
|
+
flexDirection: "row",
|
|
1013
|
+
alignItems: "center",
|
|
1014
|
+
paddingHorizontal: 22,
|
|
1015
|
+
paddingVertical: 16,
|
|
1016
|
+
gap: 12,
|
|
1017
|
+
borderBottomWidth: 1,
|
|
1018
|
+
borderBottomColor: import_core2.ada.border
|
|
1019
|
+
},
|
|
1020
|
+
headerOrb: {
|
|
1021
|
+
width: 36,
|
|
1022
|
+
height: 36,
|
|
1023
|
+
alignItems: "center",
|
|
1024
|
+
justifyContent: "center"
|
|
1025
|
+
},
|
|
1026
|
+
title: {
|
|
1027
|
+
fontSize: 17,
|
|
1028
|
+
fontWeight: "600",
|
|
1029
|
+
color: import_core2.ada.ink,
|
|
1030
|
+
letterSpacing: -0.2,
|
|
1031
|
+
fontFamily: fontFam
|
|
1032
|
+
},
|
|
1033
|
+
subtitle: {
|
|
1034
|
+
fontSize: 13,
|
|
1035
|
+
fontWeight: "400",
|
|
1036
|
+
color: import_core2.ada.inkSoft,
|
|
1037
|
+
marginTop: 2,
|
|
1038
|
+
letterSpacing: -0.1,
|
|
1039
|
+
fontFamily: fontFam
|
|
1040
|
+
},
|
|
1041
|
+
privacyPill: {
|
|
1042
|
+
flexDirection: "row",
|
|
1043
|
+
alignItems: "center",
|
|
1044
|
+
gap: 5,
|
|
1045
|
+
marginTop: 4
|
|
1046
|
+
},
|
|
1047
|
+
privacyText: {
|
|
1048
|
+
fontSize: 11,
|
|
1049
|
+
fontWeight: "500",
|
|
1050
|
+
color: import_core2.ada.inkSoft,
|
|
1051
|
+
letterSpacing: 0.2,
|
|
1052
|
+
fontFamily: fontFam
|
|
1053
|
+
},
|
|
1054
|
+
closeBtn: {
|
|
1055
|
+
width: 32,
|
|
1056
|
+
height: 32,
|
|
1057
|
+
borderRadius: 16,
|
|
1058
|
+
backgroundColor: import_core2.ada.paperSoft,
|
|
1059
|
+
justifyContent: "center",
|
|
1060
|
+
alignItems: "center"
|
|
1061
|
+
},
|
|
1062
|
+
body: {
|
|
1063
|
+
flex: 1
|
|
986
1064
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
// src/surfaces/SurfaceCard.tsx
|
|
1068
|
+
var import_react_native6 = require("react-native");
|
|
1069
|
+
var import_core3 = require("@ateam-ai-mobile/core");
|
|
1070
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1071
|
+
var fontFam2 = import_react_native6.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1072
|
+
function SurfaceCard({
|
|
1073
|
+
icon,
|
|
1074
|
+
title,
|
|
1075
|
+
subtitle,
|
|
1076
|
+
onPress,
|
|
1077
|
+
onLongPress,
|
|
1078
|
+
showArrow,
|
|
1079
|
+
children
|
|
1080
|
+
}) {
|
|
1081
|
+
const arrow = showArrow ?? !!onPress;
|
|
1082
|
+
const handlePress = () => {
|
|
1083
|
+
if (!onPress) return;
|
|
1084
|
+
getHaptics()?.impact("light");
|
|
1085
|
+
onPress();
|
|
1086
|
+
};
|
|
1087
|
+
const handleLongPress = () => {
|
|
1088
|
+
if (!onLongPress) return;
|
|
1089
|
+
getHaptics()?.impact("medium");
|
|
1090
|
+
onLongPress();
|
|
1091
|
+
};
|
|
1092
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1093
|
+
import_react_native6.Pressable,
|
|
1094
|
+
{
|
|
1095
|
+
accessibilityRole: "button",
|
|
1096
|
+
accessibilityLabel: [icon, title, subtitle].filter(Boolean).join(", "),
|
|
1097
|
+
accessibilityHint: onLongPress ? "Long-press for more options" : void 0,
|
|
1098
|
+
style: styles4.card,
|
|
1099
|
+
onPress: onPress ? handlePress : void 0,
|
|
1100
|
+
onLongPress: onLongPress ? handleLongPress : void 0,
|
|
1101
|
+
disabled: !onPress && !onLongPress,
|
|
1102
|
+
children: [
|
|
1103
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles4.row, children: [
|
|
1104
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles4.icon, children: icon }) : null,
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: { flex: 1 }, children: [
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles4.title, children: title }),
|
|
1107
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles4.subtitle, children: subtitle }) : null
|
|
1108
|
+
] }),
|
|
1109
|
+
arrow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles4.arrow, children: "\u2192" }) : null
|
|
1110
|
+
] }),
|
|
1111
|
+
children ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: styles4.body, children }) : null
|
|
1112
|
+
]
|
|
1017
1113
|
}
|
|
1018
|
-
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
var styles4 = import_react_native6.StyleSheet.create({
|
|
1117
|
+
card: {
|
|
1118
|
+
backgroundColor: import_core3.ada.paperSoft,
|
|
1119
|
+
borderWidth: 1,
|
|
1120
|
+
borderColor: import_core3.ada.border,
|
|
1121
|
+
borderRadius: import_core3.borderRadius.xl,
|
|
1122
|
+
paddingHorizontal: 16,
|
|
1123
|
+
paddingVertical: 14
|
|
1124
|
+
},
|
|
1125
|
+
row: {
|
|
1126
|
+
flexDirection: "row",
|
|
1127
|
+
alignItems: "center",
|
|
1128
|
+
gap: 14
|
|
1129
|
+
},
|
|
1130
|
+
icon: {
|
|
1131
|
+
fontSize: 22
|
|
1132
|
+
},
|
|
1133
|
+
title: {
|
|
1134
|
+
fontSize: 15,
|
|
1135
|
+
fontWeight: "600",
|
|
1136
|
+
color: import_core3.ada.ink,
|
|
1137
|
+
letterSpacing: -0.2,
|
|
1138
|
+
fontFamily: fontFam2
|
|
1139
|
+
},
|
|
1140
|
+
subtitle: {
|
|
1141
|
+
fontSize: 13,
|
|
1142
|
+
fontWeight: "400",
|
|
1143
|
+
color: import_core3.ada.inkMuted,
|
|
1144
|
+
marginTop: 2,
|
|
1145
|
+
letterSpacing: -0.1,
|
|
1146
|
+
fontFamily: fontFam2
|
|
1147
|
+
},
|
|
1148
|
+
arrow: {
|
|
1149
|
+
fontSize: 18,
|
|
1150
|
+
color: import_core3.ada.inkMuted,
|
|
1151
|
+
fontWeight: "400"
|
|
1152
|
+
},
|
|
1153
|
+
body: {
|
|
1154
|
+
marginTop: 10,
|
|
1155
|
+
paddingTop: 10,
|
|
1156
|
+
borderTopWidth: 1,
|
|
1157
|
+
borderTopColor: import_core3.ada.border
|
|
1019
1158
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
// src/surfaces/SurfaceFullscreen.tsx
|
|
1162
|
+
var import_react6 = require("react");
|
|
1163
|
+
var import_react_native7 = require("react-native");
|
|
1164
|
+
var import_react_native_svg3 = __toESM(require("react-native-svg"));
|
|
1165
|
+
var import_core4 = require("@ateam-ai-mobile/core");
|
|
1166
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1167
|
+
var fontFam3 = import_react_native7.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1168
|
+
function SurfaceFullscreen({
|
|
1169
|
+
visible,
|
|
1170
|
+
onClose,
|
|
1171
|
+
status,
|
|
1172
|
+
hero,
|
|
1173
|
+
children,
|
|
1174
|
+
showWordmark = true,
|
|
1175
|
+
closeIcon = "x",
|
|
1176
|
+
closeLabel = "Close"
|
|
1177
|
+
}) {
|
|
1178
|
+
const fadeAnim = (0, import_react6.useRef)(new import_react_native7.Animated.Value(0)).current;
|
|
1179
|
+
const heroScale = (0, import_react6.useRef)(new import_react_native7.Animated.Value(0.6)).current;
|
|
1180
|
+
(0, import_react6.useEffect)(() => {
|
|
1181
|
+
if (visible) {
|
|
1182
|
+
import_react_native7.Animated.parallel([
|
|
1183
|
+
import_react_native7.Animated.timing(fadeAnim, { toValue: 1, duration: 280, useNativeDriver: true }),
|
|
1184
|
+
import_react_native7.Animated.spring(heroScale, { toValue: 1, useNativeDriver: true, tension: 60, friction: 11 })
|
|
1185
|
+
]).start();
|
|
1186
|
+
} else {
|
|
1187
|
+
fadeAnim.setValue(0);
|
|
1188
|
+
heroScale.setValue(0.6);
|
|
1035
1189
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1190
|
+
}, [visible]);
|
|
1191
|
+
const close = () => {
|
|
1192
|
+
import_react_native7.Animated.parallel([
|
|
1193
|
+
import_react_native7.Animated.timing(fadeAnim, { toValue: 0, duration: 180, useNativeDriver: true }),
|
|
1194
|
+
import_react_native7.Animated.timing(heroScale, { toValue: 0.6, duration: 180, useNativeDriver: true })
|
|
1195
|
+
]).start(() => onClose());
|
|
1196
|
+
};
|
|
1197
|
+
if (!visible) return null;
|
|
1198
|
+
const renderCloseIcon = () => {
|
|
1199
|
+
if (closeIcon === "hangup") {
|
|
1200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: import_core4.ada.paper, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.Path, { d: "M3.68 16.07l3.92-3.11c.28-.23.68-.28 1.01-.14l2.77 1.15c.36.15.61.5.61.89v2.82c4.34-.76 7.93-4.35 8.69-8.69h-2.82c-.39 0-.74-.25-.89-.61L16.12 5.6c-.13-.33-.09-.73.14-1.01l3.11-3.92c.29-.37.81-.41 1.15-.08l3.24 3.24c.2.2.31.47.31.76C24 14.44 14.44 24 4.59 24c-.29 0-.56-.11-.76-.31L.59 20.45c-.33-.34-.29-.86.09-1.15z" }) });
|
|
1038
1201
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (val && typeof val === "object" && val.id === shortName && typeof val.Component === "function") {
|
|
1042
|
-
return val;
|
|
1043
|
-
}
|
|
1202
|
+
if (closeIcon === "x") {
|
|
1203
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core4.ada.paper, strokeWidth: 2.5, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.Path, { d: "M18 6L6 18M6 6l12 12" }) });
|
|
1044
1204
|
}
|
|
1045
|
-
return
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1205
|
+
return closeIcon;
|
|
1206
|
+
};
|
|
1207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Animated.View, { style: [styles5.overlay, { opacity: fadeAnim }], pointerEvents: "auto", children: [
|
|
1208
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles5.topBar, children: [
|
|
1209
|
+
showWordmark ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles5.wordmark, children: "ada" }) : null,
|
|
1210
|
+
status ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles5.status, children: status }) : null
|
|
1211
|
+
] }),
|
|
1212
|
+
hero ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles5.heroWrap, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Animated.View, { style: { transform: [{ scale: heroScale }] }, children: hero }) }) : null,
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles5.body, children }),
|
|
1214
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles5.bottomBar, children: [
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1216
|
+
import_react_native7.Pressable,
|
|
1217
|
+
{
|
|
1218
|
+
accessibilityRole: "button",
|
|
1219
|
+
accessibilityLabel: closeLabel,
|
|
1220
|
+
style: styles5.closeBtn,
|
|
1221
|
+
onPress: close,
|
|
1222
|
+
hitSlop: 12,
|
|
1223
|
+
children: renderCloseIcon()
|
|
1224
|
+
}
|
|
1225
|
+
),
|
|
1226
|
+
closeLabel ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles5.closeLabel, children: closeLabel }) : null
|
|
1227
|
+
] })
|
|
1228
|
+
] });
|
|
1229
|
+
}
|
|
1230
|
+
var styles5 = import_react_native7.StyleSheet.create({
|
|
1231
|
+
overlay: {
|
|
1232
|
+
position: "absolute",
|
|
1233
|
+
top: 0,
|
|
1234
|
+
left: 0,
|
|
1235
|
+
right: 0,
|
|
1236
|
+
bottom: 0,
|
|
1237
|
+
backgroundColor: import_core4.ada.paper,
|
|
1238
|
+
zIndex: 1e3,
|
|
1239
|
+
elevation: 1e3
|
|
1240
|
+
},
|
|
1241
|
+
topBar: {
|
|
1242
|
+
paddingTop: import_react_native7.Platform.OS === "ios" ? 64 : 36,
|
|
1243
|
+
paddingHorizontal: 24,
|
|
1244
|
+
alignItems: "center",
|
|
1245
|
+
gap: 6
|
|
1246
|
+
},
|
|
1247
|
+
wordmark: {
|
|
1248
|
+
fontSize: 14,
|
|
1249
|
+
fontFamily: fontFam3,
|
|
1250
|
+
fontWeight: "500",
|
|
1251
|
+
color: import_core4.ada.inkMuted,
|
|
1252
|
+
letterSpacing: 4
|
|
1253
|
+
},
|
|
1254
|
+
status: {
|
|
1255
|
+
fontSize: 17,
|
|
1256
|
+
fontFamily: fontFam3,
|
|
1257
|
+
fontWeight: "500",
|
|
1258
|
+
color: import_core4.ada.ink,
|
|
1259
|
+
letterSpacing: -0.2
|
|
1260
|
+
},
|
|
1261
|
+
heroWrap: {
|
|
1262
|
+
paddingTop: 24,
|
|
1263
|
+
paddingBottom: 12,
|
|
1264
|
+
alignItems: "center",
|
|
1265
|
+
justifyContent: "center"
|
|
1266
|
+
},
|
|
1267
|
+
body: {
|
|
1268
|
+
flex: 1
|
|
1269
|
+
},
|
|
1270
|
+
bottomBar: {
|
|
1271
|
+
paddingBottom: import_react_native7.Platform.OS === "ios" ? 48 : 32,
|
|
1272
|
+
paddingTop: 12,
|
|
1273
|
+
alignItems: "center",
|
|
1274
|
+
gap: 8
|
|
1275
|
+
},
|
|
1276
|
+
closeBtn: {
|
|
1277
|
+
width: 64,
|
|
1278
|
+
height: 64,
|
|
1279
|
+
borderRadius: 32,
|
|
1280
|
+
backgroundColor: import_core4.ada.ink,
|
|
1281
|
+
justifyContent: "center",
|
|
1282
|
+
alignItems: "center",
|
|
1283
|
+
shadowColor: import_core4.ada.ink,
|
|
1284
|
+
shadowOffset: { width: 0, height: 8 },
|
|
1285
|
+
shadowOpacity: 0.18,
|
|
1286
|
+
shadowRadius: 14,
|
|
1287
|
+
elevation: 8
|
|
1288
|
+
},
|
|
1289
|
+
closeLabel: {
|
|
1290
|
+
fontSize: 13,
|
|
1291
|
+
fontFamily: fontFam3,
|
|
1292
|
+
fontWeight: "500",
|
|
1293
|
+
color: import_core4.ada.inkMuted,
|
|
1294
|
+
letterSpacing: 0.3
|
|
1054
1295
|
}
|
|
1055
|
-
};
|
|
1056
|
-
var bundleManager = new BundleManager();
|
|
1296
|
+
});
|
|
1057
1297
|
|
|
1058
|
-
// src/
|
|
1059
|
-
var
|
|
1060
|
-
var
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
const onInit = (0, import_react6.useCallback)((cb) => {
|
|
1080
|
-
initCallbackRef.current = cb;
|
|
1081
|
-
setTimeout(fireInit, 0);
|
|
1082
|
-
}, [fireInit]);
|
|
1083
|
-
const mcpCall = (0, import_react6.useCallback)(async (toolOrConnector, argsOrTool, cIdOrArgs) => {
|
|
1084
|
-
let tool;
|
|
1085
|
-
let args;
|
|
1086
|
-
let cId;
|
|
1087
|
-
if (typeof argsOrTool === "string") {
|
|
1088
|
-
cId = toolOrConnector;
|
|
1089
|
-
tool = argsOrTool;
|
|
1090
|
-
args = cIdOrArgs || {};
|
|
1091
|
-
} else {
|
|
1092
|
-
tool = toolOrConnector;
|
|
1093
|
-
args = argsOrTool;
|
|
1094
|
-
cId = typeof cIdOrArgs === "string" ? cIdOrArgs : void 0;
|
|
1095
|
-
}
|
|
1096
|
-
const targetConnector = cId || connectorId;
|
|
1097
|
-
if (!targetConnector) {
|
|
1098
|
-
console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2014 no connectorId. tool=${tool}`);
|
|
1099
|
-
throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
|
|
1100
|
-
}
|
|
1101
|
-
try {
|
|
1102
|
-
const data = await (0, import_core3.connectorCall)(targetConnector, tool, args);
|
|
1103
|
-
if (!data.ok && data.error) {
|
|
1104
|
-
throw new Error(data.error);
|
|
1105
|
-
}
|
|
1106
|
-
return (0, import_core3.unwrapMcpResult)(data.result);
|
|
1107
|
-
} catch (err) {
|
|
1108
|
-
console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2192 connector=${targetConnector} tool=${tool}:`, err?.message || err);
|
|
1109
|
-
throw err;
|
|
1298
|
+
// src/registry/store.ts
|
|
1299
|
+
var import_zustand = require("zustand");
|
|
1300
|
+
var useSurfaceStore = (0, import_zustand.create)((set, get) => ({
|
|
1301
|
+
manifests: {},
|
|
1302
|
+
activeDrawer: null,
|
|
1303
|
+
activeFullscreen: null,
|
|
1304
|
+
activeProps: {},
|
|
1305
|
+
mountKey: 0,
|
|
1306
|
+
register: (manifest) => set((s) => ({ manifests: { ...s.manifests, [manifest.id]: manifest } })),
|
|
1307
|
+
unregister: (id) => set((s) => {
|
|
1308
|
+
const next = { ...s.manifests };
|
|
1309
|
+
delete next[id];
|
|
1310
|
+
const nextProps = { ...s.activeProps };
|
|
1311
|
+
delete nextProps[id];
|
|
1312
|
+
return { manifests: next, activeProps: nextProps };
|
|
1313
|
+
}),
|
|
1314
|
+
show: (id, props) => {
|
|
1315
|
+
const m = get().manifests[id];
|
|
1316
|
+
if (!m) {
|
|
1317
|
+
console.warn("[SurfaceStore] show: unknown surface id", id);
|
|
1318
|
+
return;
|
|
1110
1319
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1320
|
+
set((s) => {
|
|
1321
|
+
const nextProps = props !== void 0 ? { ...s.activeProps, [id]: props } : s.activeProps;
|
|
1322
|
+
const mountKey = s.mountKey + 1;
|
|
1323
|
+
if (m.type === "drawer") return { activeDrawer: id, activeProps: nextProps, mountKey };
|
|
1324
|
+
if (m.type === "fullscreen") return { activeFullscreen: id, activeProps: nextProps, mountKey };
|
|
1325
|
+
return { mountKey };
|
|
1326
|
+
});
|
|
1327
|
+
},
|
|
1328
|
+
hide: (id) => {
|
|
1329
|
+
const s = get();
|
|
1330
|
+
if (!id) {
|
|
1331
|
+
const cleanup2 = { ...s.activeProps };
|
|
1332
|
+
if (s.activeDrawer) delete cleanup2[s.activeDrawer];
|
|
1333
|
+
if (s.activeFullscreen) delete cleanup2[s.activeFullscreen];
|
|
1334
|
+
set({ activeDrawer: null, activeFullscreen: null, activeProps: cleanup2 });
|
|
1118
1335
|
return;
|
|
1119
1336
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
if (
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1337
|
+
const cleanup = { ...s.activeProps };
|
|
1338
|
+
delete cleanup[id];
|
|
1339
|
+
const patch = { activeProps: cleanup };
|
|
1340
|
+
if (s.activeDrawer === id) patch.activeDrawer = null;
|
|
1341
|
+
if (s.activeFullscreen === id) patch.activeFullscreen = null;
|
|
1342
|
+
set(patch);
|
|
1343
|
+
},
|
|
1344
|
+
list: (filter) => {
|
|
1345
|
+
const all = Object.values(get().manifests);
|
|
1346
|
+
return all.filter((m) => {
|
|
1347
|
+
if (filter?.type && m.type !== filter.type) return false;
|
|
1348
|
+
if (filter?.visibility && !filter.visibility.includes(m.visibility)) return false;
|
|
1349
|
+
if (filter?.placement) {
|
|
1350
|
+
if (filter.placement === "unset") {
|
|
1351
|
+
if (m.placement) return false;
|
|
1352
|
+
} else if (m.placement !== filter.placement) {
|
|
1353
|
+
return false;
|
|
1134
1354
|
}
|
|
1135
1355
|
}
|
|
1136
|
-
|
|
1137
|
-
}
|
|
1138
|
-
for (const cmd of import_core3.pluginCommandEmitter.drainPluginCommands(pluginId)) {
|
|
1139
|
-
try {
|
|
1140
|
-
cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1141
|
-
} catch {
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
return () => {
|
|
1145
|
-
commandListenersRef.current.delete(cb);
|
|
1146
|
-
};
|
|
1147
|
-
}, [pluginId, commandBufferRef]);
|
|
1148
|
-
(0, import_react6.useEffect)(() => {
|
|
1149
|
-
const unsub = import_core3.pluginCommandEmitter.on("plugin-command", (cmd) => {
|
|
1150
|
-
if (cmd.pluginId !== pluginId) return;
|
|
1151
|
-
if (cmd.command === "__focus") return;
|
|
1152
|
-
commandListenersRef.current.forEach((fn) => {
|
|
1153
|
-
try {
|
|
1154
|
-
fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1155
|
-
} catch {
|
|
1156
|
-
}
|
|
1157
|
-
});
|
|
1356
|
+
return true;
|
|
1158
1357
|
});
|
|
1159
|
-
return unsub;
|
|
1160
|
-
}, [pluginId]);
|
|
1161
|
-
(0, import_react6.useEffect)(() => {
|
|
1162
|
-
const timer = setTimeout(() => {
|
|
1163
|
-
const dispatch = (cmd) => {
|
|
1164
|
-
commandListenersRef.current.forEach((fn) => {
|
|
1165
|
-
try {
|
|
1166
|
-
fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1167
|
-
} catch {
|
|
1168
|
-
}
|
|
1169
|
-
});
|
|
1170
|
-
};
|
|
1171
|
-
if (commandBufferRef) {
|
|
1172
|
-
const remaining = [];
|
|
1173
|
-
for (const cmd of commandBufferRef.current) {
|
|
1174
|
-
if (cmd.pluginId === pluginId && cmd.command !== "__focus") dispatch(cmd);
|
|
1175
|
-
else remaining.push(cmd);
|
|
1176
|
-
}
|
|
1177
|
-
commandBufferRef.current = remaining;
|
|
1178
|
-
}
|
|
1179
|
-
for (const cmd of import_core3.pluginCommandEmitter.drainPluginCommands(pluginId)) {
|
|
1180
|
-
dispatch(cmd);
|
|
1181
|
-
}
|
|
1182
|
-
}, 500);
|
|
1183
|
-
return () => clearTimeout(timer);
|
|
1184
|
-
}, [pluginId, commandBufferRef]);
|
|
1185
|
-
(0, import_react6.useEffect)(() => {
|
|
1186
|
-
return () => {
|
|
1187
|
-
commandListenersRef.current.clear();
|
|
1188
|
-
initializedRef.current = false;
|
|
1189
|
-
};
|
|
1190
|
-
}, []);
|
|
1191
|
-
const close = (0, import_react6.useCallback)(() => {
|
|
1192
|
-
import_core3.pluginCommandEmitter.emit("plugin-close", { pluginId });
|
|
1193
|
-
}, [pluginId]);
|
|
1194
|
-
const sendMessage = (0, import_react6.useCallback)((text) => {
|
|
1195
|
-
const t = (text || "").trim();
|
|
1196
|
-
if (!t) return;
|
|
1197
|
-
try {
|
|
1198
|
-
import_core3.useChatStore.getState().sendMessage(t);
|
|
1199
|
-
} catch (err) {
|
|
1200
|
-
console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
|
|
1201
|
-
}
|
|
1202
|
-
}, []);
|
|
1203
|
-
const prepareMessage = (0, import_react6.useCallback)((text) => {
|
|
1204
|
-
const t = (text || "").trim();
|
|
1205
|
-
if (!t) return;
|
|
1206
|
-
import_core3.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
|
|
1207
|
-
}, []);
|
|
1208
|
-
return (0, import_react6.useMemo)(
|
|
1209
|
-
() => ({ onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage }),
|
|
1210
|
-
[onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage]
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1213
|
-
function createNativeBridge(pluginId, connectorId) {
|
|
1214
|
-
const commandListeners = /* @__PURE__ */ new Set();
|
|
1215
|
-
return {
|
|
1216
|
-
onInit(cb) {
|
|
1217
|
-
setTimeout(() => {
|
|
1218
|
-
cb(buildContext(pluginId, connectorId));
|
|
1219
|
-
}, 0);
|
|
1220
|
-
},
|
|
1221
|
-
async mcpCall(tool, args, cId) {
|
|
1222
|
-
const targetConnector = cId || connectorId;
|
|
1223
|
-
if (!targetConnector) {
|
|
1224
|
-
throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
|
|
1225
|
-
}
|
|
1226
|
-
const data = await (0, import_core3.connectorCall)(targetConnector, tool, args);
|
|
1227
|
-
if (!data.ok && data.error) throw new Error(data.error);
|
|
1228
|
-
return (0, import_core3.unwrapMcpResult)(data.result);
|
|
1229
|
-
},
|
|
1230
|
-
async mcpFetch(body) {
|
|
1231
|
-
return (0, import_core3.mcpFetch)(body);
|
|
1232
|
-
},
|
|
1233
|
-
sendCommand(_type, _payload) {
|
|
1234
|
-
},
|
|
1235
|
-
onCommand(cb) {
|
|
1236
|
-
commandListeners.add(cb);
|
|
1237
|
-
return () => {
|
|
1238
|
-
commandListeners.delete(cb);
|
|
1239
|
-
};
|
|
1240
|
-
},
|
|
1241
|
-
close() {
|
|
1242
|
-
import_core3.pluginCommandEmitter.emit("plugin-close", { pluginId });
|
|
1243
|
-
},
|
|
1244
|
-
sendMessage(text) {
|
|
1245
|
-
const t = (text || "").trim();
|
|
1246
|
-
if (!t) return;
|
|
1247
|
-
try {
|
|
1248
|
-
import_core3.useChatStore.getState().sendMessage(t);
|
|
1249
|
-
} catch (err) {
|
|
1250
|
-
console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
|
|
1251
|
-
}
|
|
1252
|
-
},
|
|
1253
|
-
prepareMessage(text) {
|
|
1254
|
-
const t = (text || "").trim();
|
|
1255
|
-
if (!t) return;
|
|
1256
|
-
import_core3.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
|
|
1257
|
-
}
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
// src/hooks/usePlugin.ts
|
|
1262
|
-
var import_react7 = require("react");
|
|
1263
|
-
function extractBundleUrl(pluginId, manifest) {
|
|
1264
|
-
const render = manifest.render;
|
|
1265
|
-
if (!render || typeof render !== "object") return { url: null, source: "none" };
|
|
1266
|
-
const injected = manifest.bundleUrl || render.bundleUrl || render.reactNative?.bundleUrl || null;
|
|
1267
|
-
const hasNativeComponent = !!(render.reactNative?.component || render.component);
|
|
1268
|
-
if (hasNativeComponent) {
|
|
1269
|
-
return {
|
|
1270
|
-
url: `/api/ui-plugins/${encodeURIComponent(pluginId)}/bundle.js`,
|
|
1271
|
-
source: injected ? "ignored-explicit" : "derived-default",
|
|
1272
|
-
...injected && { ignored: injected }
|
|
1273
|
-
};
|
|
1274
1358
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
if (manifest.bundleHash) return manifest.bundleHash;
|
|
1279
|
-
const render = manifest.render;
|
|
1280
|
-
if (!render || typeof render !== "object") return void 0;
|
|
1281
|
-
if (render.bundleHash) return render.bundleHash;
|
|
1282
|
-
if (render.reactNative?.bundleHash) return render.reactNative.bundleHash;
|
|
1283
|
-
return void 0;
|
|
1359
|
+
}));
|
|
1360
|
+
function isMountSurface(m) {
|
|
1361
|
+
return m.type === "drawer" || m.type === "fullscreen";
|
|
1284
1362
|
}
|
|
1285
|
-
function
|
|
1286
|
-
|
|
1287
|
-
if (!render || typeof render !== "object") return null;
|
|
1288
|
-
return render.component || render.reactNative?.component || null;
|
|
1363
|
+
function isInlineSurface(m) {
|
|
1364
|
+
return m.type === "card" || m.type === "header" || m.type === "ambient" || m.type === "nudge";
|
|
1289
1365
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
}
|
|
1366
|
+
|
|
1367
|
+
// src/registry/SurfaceDispatcher.tsx
|
|
1368
|
+
var import_react7 = require("react");
|
|
1369
|
+
var import_core5 = require("@ateam-ai-mobile/core");
|
|
1370
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1371
|
+
function SurfaceDispatcher() {
|
|
1372
|
+
const manifests = useSurfaceStore((s) => s.manifests);
|
|
1373
|
+
const activeDrawer = useSurfaceStore((s) => s.activeDrawer);
|
|
1374
|
+
const activeFullscreen = useSurfaceStore((s) => s.activeFullscreen);
|
|
1375
|
+
const activeProps = useSurfaceStore((s) => s.activeProps);
|
|
1376
|
+
const mountKey = useSurfaceStore((s) => s.mountKey);
|
|
1377
|
+
const hide = useSurfaceStore((s) => s.hide);
|
|
1303
1378
|
(0, import_react7.useEffect)(() => {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
if (cancelled) return;
|
|
1310
|
-
if (!registered) {
|
|
1311
|
-
throw new Error(`Local plugin not found: ${lookupId}`);
|
|
1312
|
-
}
|
|
1313
|
-
if (registered.type === "service") {
|
|
1314
|
-
throw new Error(`Plugin ${lookupId} is a service plugin and cannot be rendered`);
|
|
1315
|
-
}
|
|
1316
|
-
setPlugin(registered);
|
|
1317
|
-
setLoading(false);
|
|
1318
|
-
return;
|
|
1319
|
-
}
|
|
1320
|
-
if (bundleUrl) {
|
|
1321
|
-
try {
|
|
1322
|
-
const component = await bundleManager.load(pluginId, bundleUrl, version, bundleHash);
|
|
1323
|
-
if (cancelled) return;
|
|
1324
|
-
setPlugin(component);
|
|
1325
|
-
setLoading(false);
|
|
1326
|
-
return;
|
|
1327
|
-
} catch (bundleErr) {
|
|
1328
|
-
const msg = bundleErr instanceof Error ? bundleErr.message : String(bundleErr);
|
|
1329
|
-
console.warn(`[usePlugin] ${pluginId}: Bundle load failed, falling back to WebView:`, msg);
|
|
1330
|
-
if (!cancelled) {
|
|
1331
|
-
setBundleMissing(true);
|
|
1332
|
-
setLoading(false);
|
|
1333
|
-
}
|
|
1334
|
-
return;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
const iframeUrl = manifest?.render?.iframeUrl || manifest?.render?.mode === "adaptive" && manifest?.render?.iframe?.iframeUrl;
|
|
1338
|
-
if (iframeUrl) {
|
|
1339
|
-
if (!cancelled) {
|
|
1340
|
-
setBundleMissing(true);
|
|
1341
|
-
setLoading(false);
|
|
1342
|
-
}
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
throw new Error(
|
|
1346
|
-
`Plugin "${manifest.name || pluginId}" has no bundle URL and is not in the local registry. Check that the solution definition includes a valid render.reactNative.bundleUrl.`
|
|
1347
|
-
);
|
|
1348
|
-
} catch (err) {
|
|
1349
|
-
if (cancelled) return;
|
|
1350
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1351
|
-
console.error(`[usePlugin] Failed to load ${pluginId}:`, msg);
|
|
1352
|
-
setError(msg);
|
|
1353
|
-
setLoading(false);
|
|
1379
|
+
const unsub = import_core5.pluginCommandEmitter.on("plugin-close", ({ pluginId } = {}) => {
|
|
1380
|
+
if (!pluginId) return;
|
|
1381
|
+
const s = useSurfaceStore.getState();
|
|
1382
|
+
if (s.activeDrawer === pluginId || s.activeFullscreen === pluginId) {
|
|
1383
|
+
s.hide(pluginId);
|
|
1354
1384
|
}
|
|
1355
|
-
})
|
|
1356
|
-
return
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1385
|
+
});
|
|
1386
|
+
return unsub;
|
|
1387
|
+
}, []);
|
|
1388
|
+
const drawer = activeDrawer ? manifests[activeDrawer] : null;
|
|
1389
|
+
const fullscreen = activeFullscreen ? manifests[activeFullscreen] : null;
|
|
1390
|
+
const drawerProps = activeDrawer ? activeProps[activeDrawer] : void 0;
|
|
1391
|
+
const fullscreenProps = activeFullscreen ? activeProps[activeFullscreen] : void 0;
|
|
1392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1393
|
+
drawer && drawer.type === "drawer" && drawer.Component ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1394
|
+
drawer.Component,
|
|
1395
|
+
{
|
|
1396
|
+
dismiss: () => hide(drawer.id),
|
|
1397
|
+
props: drawerProps
|
|
1398
|
+
},
|
|
1399
|
+
`drawer-${drawer.id}-${mountKey}`
|
|
1400
|
+
) : null,
|
|
1401
|
+
fullscreen && fullscreen.type === "fullscreen" && fullscreen.Component ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1402
|
+
fullscreen.Component,
|
|
1403
|
+
{
|
|
1404
|
+
dismiss: () => hide(fullscreen.id),
|
|
1405
|
+
props: fullscreenProps
|
|
1406
|
+
},
|
|
1407
|
+
`fullscreen-${fullscreen.id}-${mountKey}`
|
|
1408
|
+
) : null
|
|
1409
|
+
] });
|
|
1361
1410
|
}
|
|
1362
1411
|
|
|
1363
|
-
// src/
|
|
1364
|
-
var
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1412
|
+
// src/utils/sha256.ts
|
|
1413
|
+
var K = new Uint32Array([
|
|
1414
|
+
1116352408,
|
|
1415
|
+
1899447441,
|
|
1416
|
+
3049323471,
|
|
1417
|
+
3921009573,
|
|
1418
|
+
961987163,
|
|
1419
|
+
1508970993,
|
|
1420
|
+
2453635748,
|
|
1421
|
+
2870763221,
|
|
1422
|
+
3624381080,
|
|
1423
|
+
310598401,
|
|
1424
|
+
607225278,
|
|
1425
|
+
1426881987,
|
|
1426
|
+
1925078388,
|
|
1427
|
+
2162078206,
|
|
1428
|
+
2614888103,
|
|
1429
|
+
3248222580,
|
|
1430
|
+
3835390401,
|
|
1431
|
+
4022224774,
|
|
1432
|
+
264347078,
|
|
1433
|
+
604807628,
|
|
1434
|
+
770255983,
|
|
1435
|
+
1249150122,
|
|
1436
|
+
1555081692,
|
|
1437
|
+
1996064986,
|
|
1438
|
+
2554220882,
|
|
1439
|
+
2821834349,
|
|
1440
|
+
2952996808,
|
|
1441
|
+
3210313671,
|
|
1442
|
+
3336571891,
|
|
1443
|
+
3584528711,
|
|
1444
|
+
113926993,
|
|
1445
|
+
338241895,
|
|
1446
|
+
666307205,
|
|
1447
|
+
773529912,
|
|
1448
|
+
1294757372,
|
|
1449
|
+
1396182291,
|
|
1450
|
+
1695183700,
|
|
1451
|
+
1986661051,
|
|
1452
|
+
2177026350,
|
|
1453
|
+
2456956037,
|
|
1454
|
+
2730485921,
|
|
1455
|
+
2820302411,
|
|
1456
|
+
3259730800,
|
|
1457
|
+
3345764771,
|
|
1458
|
+
3516065817,
|
|
1459
|
+
3600352804,
|
|
1460
|
+
4094571909,
|
|
1461
|
+
275423344,
|
|
1462
|
+
430227734,
|
|
1463
|
+
506948616,
|
|
1464
|
+
659060556,
|
|
1465
|
+
883997877,
|
|
1466
|
+
958139571,
|
|
1467
|
+
1322822218,
|
|
1468
|
+
1537002063,
|
|
1469
|
+
1747873779,
|
|
1470
|
+
1955562222,
|
|
1471
|
+
2024104815,
|
|
1472
|
+
2227730452,
|
|
1473
|
+
2361852424,
|
|
1474
|
+
2428436474,
|
|
1475
|
+
2756734187,
|
|
1476
|
+
3204031479,
|
|
1477
|
+
3329325298
|
|
1478
|
+
]);
|
|
1479
|
+
var rotr = (n, x) => x >>> n | x << 32 - n;
|
|
1480
|
+
function sha256Hex(message) {
|
|
1481
|
+
const utf8 = unescape(encodeURIComponent(message));
|
|
1482
|
+
const bytes = new Uint8Array(utf8.length);
|
|
1483
|
+
for (let i = 0; i < utf8.length; i++) bytes[i] = utf8.charCodeAt(i);
|
|
1484
|
+
const bitLen = bytes.length * 8;
|
|
1485
|
+
const padLen = (56 - (bytes.length + 1) % 64 + 64) % 64;
|
|
1486
|
+
const buf = new Uint8Array(bytes.length + 1 + padLen + 8);
|
|
1487
|
+
buf.set(bytes);
|
|
1488
|
+
buf[bytes.length] = 128;
|
|
1489
|
+
const len = buf.length;
|
|
1490
|
+
buf[len - 4] = bitLen >>> 24 & 255;
|
|
1491
|
+
buf[len - 3] = bitLen >>> 16 & 255;
|
|
1492
|
+
buf[len - 2] = bitLen >>> 8 & 255;
|
|
1493
|
+
buf[len - 1] = bitLen & 255;
|
|
1494
|
+
const h = new Uint32Array([
|
|
1495
|
+
1779033703,
|
|
1496
|
+
3144134277,
|
|
1497
|
+
1013904242,
|
|
1498
|
+
2773480762,
|
|
1499
|
+
1359893119,
|
|
1500
|
+
2600822924,
|
|
1501
|
+
528734635,
|
|
1502
|
+
1541459225
|
|
1503
|
+
]);
|
|
1504
|
+
const w = new Uint32Array(64);
|
|
1505
|
+
for (let i = 0; i < buf.length; i += 64) {
|
|
1506
|
+
for (let t = 0; t < 16; t++) {
|
|
1507
|
+
const j = i + t * 4;
|
|
1508
|
+
w[t] = buf[j] << 24 | buf[j + 1] << 16 | buf[j + 2] << 8 | buf[j + 3];
|
|
1414
1509
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1510
|
+
for (let t = 16; t < 64; t++) {
|
|
1511
|
+
const s0 = rotr(7, w[t - 15]) ^ rotr(18, w[t - 15]) ^ w[t - 15] >>> 3;
|
|
1512
|
+
const s1 = rotr(17, w[t - 2]) ^ rotr(19, w[t - 2]) ^ w[t - 2] >>> 10;
|
|
1513
|
+
w[t] = w[t - 16] + s0 + w[t - 7] + s1 | 0;
|
|
1514
|
+
}
|
|
1515
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];
|
|
1516
|
+
for (let t = 0; t < 64; t++) {
|
|
1517
|
+
const S1 = rotr(6, e) ^ rotr(11, e) ^ rotr(25, e);
|
|
1518
|
+
const ch = e & f ^ ~e & g;
|
|
1519
|
+
const temp1 = hh + S1 + ch + K[t] + w[t] | 0;
|
|
1520
|
+
const S0 = rotr(2, a) ^ rotr(13, a) ^ rotr(22, a);
|
|
1521
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
1522
|
+
const temp2 = S0 + maj | 0;
|
|
1523
|
+
hh = g;
|
|
1524
|
+
g = f;
|
|
1525
|
+
f = e;
|
|
1526
|
+
e = d + temp1 | 0;
|
|
1527
|
+
d = c;
|
|
1528
|
+
c = b;
|
|
1529
|
+
b = a;
|
|
1530
|
+
a = temp1 + temp2 | 0;
|
|
1531
|
+
}
|
|
1532
|
+
h[0] = h[0] + a | 0;
|
|
1533
|
+
h[1] = h[1] + b | 0;
|
|
1534
|
+
h[2] = h[2] + c | 0;
|
|
1535
|
+
h[3] = h[3] + d | 0;
|
|
1536
|
+
h[4] = h[4] + e | 0;
|
|
1537
|
+
h[5] = h[5] + f | 0;
|
|
1538
|
+
h[6] = h[6] + g | 0;
|
|
1539
|
+
h[7] = h[7] + hh | 0;
|
|
1540
|
+
}
|
|
1541
|
+
let out = "";
|
|
1542
|
+
for (let i = 0; i < 8; i++) {
|
|
1543
|
+
out += h[i].toString(16).padStart(8, "0");
|
|
1544
|
+
}
|
|
1545
|
+
return out;
|
|
1431
1546
|
}
|
|
1432
1547
|
|
|
1433
|
-
// src/
|
|
1434
|
-
var
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
return mode === "react-native" || mode === "adaptive";
|
|
1439
|
-
}
|
|
1440
|
-
function getNativeComponentId(manifest) {
|
|
1441
|
-
if (manifest.render?.mode === "react-native") return manifest.render.component;
|
|
1442
|
-
if (manifest.render?.mode === "adaptive") return manifest.render.reactNative?.component;
|
|
1443
|
-
return null;
|
|
1444
|
-
}
|
|
1445
|
-
function getNativeBundleUrl(manifest) {
|
|
1446
|
-
const direct = manifest.bundleUrl;
|
|
1447
|
-
if (direct) return direct;
|
|
1448
|
-
const render = manifest.render;
|
|
1449
|
-
if (render.mode === "react-native") return render.bundleUrl || null;
|
|
1450
|
-
if (render.mode === "adaptive") return render.reactNative?.bundleUrl || null;
|
|
1451
|
-
return null;
|
|
1452
|
-
}
|
|
1453
|
-
function getNativeBundleHash(manifest) {
|
|
1454
|
-
const direct = manifest.bundleHash;
|
|
1455
|
-
if (direct) return direct;
|
|
1456
|
-
const render = manifest.render;
|
|
1457
|
-
if (render.mode === "react-native") return render.bundleHash || null;
|
|
1458
|
-
if (render.mode === "adaptive") return render.reactNative?.bundleHash || null;
|
|
1459
|
-
return null;
|
|
1460
|
-
}
|
|
1461
|
-
function supportsWebView(manifest) {
|
|
1462
|
-
return manifest.render?.mode === "iframe" || manifest.render?.mode === "adaptive";
|
|
1463
|
-
}
|
|
1464
|
-
async function listPlugins() {
|
|
1465
|
-
const res = await (0, import_core5.apiFetch)("/mcp", {
|
|
1466
|
-
method: "POST",
|
|
1467
|
-
body: JSON.stringify({
|
|
1468
|
-
jsonrpc: "2.0",
|
|
1469
|
-
id: Date.now(),
|
|
1470
|
-
method: "tools/call",
|
|
1471
|
-
params: {
|
|
1472
|
-
name: "cp.listContextPlugins",
|
|
1473
|
-
arguments: {}
|
|
1474
|
-
}
|
|
1475
|
-
})
|
|
1476
|
-
});
|
|
1477
|
-
const structured = res.result?.structuredContent?.plugins;
|
|
1478
|
-
if (structured) return structured;
|
|
1479
|
-
const text = res.result?.content?.[0]?.text;
|
|
1480
|
-
if (!text) return [];
|
|
1481
|
-
try {
|
|
1482
|
-
const parsed = JSON.parse(text);
|
|
1483
|
-
return parsed.plugins || parsed || [];
|
|
1484
|
-
} catch {
|
|
1485
|
-
return [];
|
|
1548
|
+
// src/bundles/storage.ts
|
|
1549
|
+
var MemoryBundleStorage = class {
|
|
1550
|
+
constructor() {
|
|
1551
|
+
this.index = {};
|
|
1552
|
+
this.files = /* @__PURE__ */ new Map();
|
|
1486
1553
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const res = await (0, import_core5.apiFetch)("/mcp", {
|
|
1490
|
-
method: "POST",
|
|
1491
|
-
body: JSON.stringify({
|
|
1492
|
-
jsonrpc: "2.0",
|
|
1493
|
-
id: Date.now(),
|
|
1494
|
-
method: "tools/call",
|
|
1495
|
-
params: {
|
|
1496
|
-
name: "cp.getContextPlugin",
|
|
1497
|
-
arguments: { id: pluginId }
|
|
1498
|
-
// Backend expects { id }, NOT { pluginId }
|
|
1499
|
-
}
|
|
1500
|
-
})
|
|
1501
|
-
});
|
|
1502
|
-
if (res.result?.structuredContent) return res.result.structuredContent;
|
|
1503
|
-
const text = res.result?.content?.[0]?.text;
|
|
1504
|
-
if (!text) return null;
|
|
1505
|
-
try {
|
|
1506
|
-
const parsed = JSON.parse(text);
|
|
1507
|
-
if (parsed.error) {
|
|
1508
|
-
console.warn("[getPlugin] Backend error:", parsed.error);
|
|
1509
|
-
return null;
|
|
1510
|
-
}
|
|
1511
|
-
return parsed;
|
|
1512
|
-
} catch {
|
|
1513
|
-
return null;
|
|
1554
|
+
async loadIndex() {
|
|
1555
|
+
return this.index;
|
|
1514
1556
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
const render = manifest.render;
|
|
1518
|
-
let url;
|
|
1519
|
-
if (render?.mode === "iframe") {
|
|
1520
|
-
url = render.iframeUrl;
|
|
1521
|
-
} else if (render?.mode === "adaptive") {
|
|
1522
|
-
url = render.iframeUrl || render.iframe?.iframeUrl;
|
|
1557
|
+
async saveIndex(index) {
|
|
1558
|
+
this.index = index;
|
|
1523
1559
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
const sep = url.includes("?") ? "&" : "?";
|
|
1527
|
-
return tenant ? `${url}${sep}tenant=${encodeURIComponent(tenant)}` : url;
|
|
1560
|
+
async readBundle(localPath) {
|
|
1561
|
+
return this.files.get(localPath) ?? null;
|
|
1528
1562
|
}
|
|
1529
|
-
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1563
|
+
async writeBundle(key, content) {
|
|
1564
|
+
const localPath = `memory://${key}`;
|
|
1565
|
+
this.files.set(localPath, content);
|
|
1566
|
+
return localPath;
|
|
1532
1567
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1568
|
+
async deleteBundle(localPath) {
|
|
1569
|
+
this.files.delete(localPath);
|
|
1570
|
+
}
|
|
1571
|
+
async clearAll() {
|
|
1572
|
+
this.index = {};
|
|
1573
|
+
this.files.clear();
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
var _storage = new MemoryBundleStorage();
|
|
1577
|
+
function setBundleStorage(storage) {
|
|
1578
|
+
_storage = storage;
|
|
1579
|
+
}
|
|
1580
|
+
function getBundleStorage() {
|
|
1581
|
+
return _storage;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// src/bundles/bundleManager.ts
|
|
1585
|
+
var ReactShim = {
|
|
1586
|
+
__esModule: true,
|
|
1587
|
+
default: import_react8.default,
|
|
1588
|
+
...import_react8.default,
|
|
1589
|
+
// Explicitly include hooks (React 19 may not have them as own enumerable props)
|
|
1590
|
+
useState: import_react9.useState,
|
|
1591
|
+
useEffect: import_react9.useEffect,
|
|
1592
|
+
useCallback: import_react9.useCallback,
|
|
1593
|
+
useMemo: import_react9.useMemo,
|
|
1594
|
+
useRef: import_react9.useRef,
|
|
1595
|
+
useContext: import_react9.useContext,
|
|
1596
|
+
useReducer: import_react9.useReducer,
|
|
1597
|
+
useLayoutEffect: import_react9.useLayoutEffect,
|
|
1598
|
+
useImperativeHandle: import_react9.useImperativeHandle,
|
|
1599
|
+
useDebugValue: import_react9.useDebugValue,
|
|
1600
|
+
createElement: import_react8.default.createElement,
|
|
1601
|
+
Fragment: import_react8.default.Fragment,
|
|
1602
|
+
Component: import_react8.default.Component,
|
|
1603
|
+
PureComponent: import_react8.default.PureComponent,
|
|
1604
|
+
createContext: import_react8.default.createContext,
|
|
1605
|
+
forwardRef: import_react8.default.forwardRef,
|
|
1606
|
+
memo: import_react8.default.memo,
|
|
1607
|
+
Children: import_react8.default.Children,
|
|
1608
|
+
cloneElement: import_react8.default.cloneElement,
|
|
1609
|
+
isValidElement: import_react8.default.isValidElement,
|
|
1610
|
+
createRef: import_react8.default.createRef,
|
|
1611
|
+
lazy: import_react8.default.lazy,
|
|
1612
|
+
Suspense: import_react8.default.Suspense
|
|
1613
|
+
};
|
|
1614
|
+
var PluginSDKShim = Object.freeze({
|
|
1615
|
+
...sdk_exports,
|
|
1616
|
+
SurfaceDrawer,
|
|
1617
|
+
SurfaceCard,
|
|
1618
|
+
SurfaceFullscreen,
|
|
1619
|
+
useSurfaceStore,
|
|
1620
|
+
SurfaceDispatcher,
|
|
1621
|
+
PluginSDK: Object.freeze({
|
|
1622
|
+
...PluginSDK,
|
|
1623
|
+
register: PluginSDK.register
|
|
1624
|
+
}),
|
|
1625
|
+
register
|
|
1626
|
+
});
|
|
1627
|
+
var requireShim = (name) => {
|
|
1628
|
+
if (name === "react") return ReactShim;
|
|
1629
|
+
if (name === "react-native") return ReactNative;
|
|
1630
|
+
if (name === "@adas/plugin-sdk") return PluginSDKShim;
|
|
1631
|
+
const hostModule = resolveBundleModule(name);
|
|
1632
|
+
if (hostModule !== void 0) return hostModule;
|
|
1633
|
+
console.warn(`[BundleManager] Unknown module: ${name} \u2014 register it via registerBundleModules()`);
|
|
1634
|
+
return {};
|
|
1635
|
+
};
|
|
1636
|
+
var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
1637
|
+
var BundleManager = class {
|
|
1638
|
+
constructor() {
|
|
1639
|
+
/** In-memory module cache: bundleUrl → evaluated module.exports */
|
|
1640
|
+
this.modules = /* @__PURE__ */ new Map();
|
|
1641
|
+
/** In-flight download deduplication: bundleUrl → Promise */
|
|
1642
|
+
this.inflight = /* @__PURE__ */ new Map();
|
|
1643
|
+
}
|
|
1644
|
+
// ── Public API ──────────────────────────────────────────────
|
|
1645
|
+
/**
|
|
1646
|
+
* Load a plugin component. Returns the RegisteredUIPlugin object.
|
|
1647
|
+
* Handles: in-memory cache → disk cache → download → evaluate → extract.
|
|
1648
|
+
*
|
|
1649
|
+
* `expectedHash` (SHA-256 hex from cp.getContextPlugin manifest) MUST be
|
|
1650
|
+
* provided for any bundle the user has not previously verified — without
|
|
1651
|
+
* it, a tampered bundle is `eval`'d as JS with full RN runtime + every
|
|
1652
|
+
* native capability the manifest declares.
|
|
1653
|
+
*/
|
|
1654
|
+
async load(pluginId, bundleUrl, version, expectedHash) {
|
|
1655
|
+
const cached = this.getComponentFromMemory(pluginId, bundleUrl);
|
|
1656
|
+
if (cached) return cached;
|
|
1657
|
+
let modulePromise = this.inflight.get(bundleUrl);
|
|
1658
|
+
if (!modulePromise) {
|
|
1659
|
+
modulePromise = this.loadModule(bundleUrl, version, expectedHash);
|
|
1660
|
+
this.inflight.set(bundleUrl, modulePromise);
|
|
1661
|
+
modulePromise.catch(() => {
|
|
1662
|
+
}).finally(() => this.inflight.delete(bundleUrl));
|
|
1663
|
+
}
|
|
1664
|
+
await modulePromise;
|
|
1665
|
+
const component = this.getComponentFromMemory(pluginId, bundleUrl);
|
|
1666
|
+
if (!component) {
|
|
1667
|
+
throw new Error(
|
|
1668
|
+
`Bundle loaded from ${bundleUrl} but no component found for "${pluginId}". Available exports: ${this.describeModule(this.modules.get(bundleUrl))}`
|
|
1620
1669
|
);
|
|
1621
1670
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
(0, import_react_native_reanimated.withSequence)(
|
|
1649
|
-
(0, import_react_native_reanimated.withTiming)(state === "idle" ? 0.55 : 0.8, { duration: breathMs * 1.3, easing: breathEasing }),
|
|
1650
|
-
(0, import_react_native_reanimated.withTiming)(0.35, { duration: breathMs * 1.3, easing: breathEasing })
|
|
1651
|
-
),
|
|
1652
|
-
-1,
|
|
1653
|
-
false
|
|
1654
|
-
);
|
|
1655
|
-
}, [state]);
|
|
1656
|
-
const coreProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
1657
|
-
r: coreR * coreScale.value * beat.value
|
|
1658
|
-
}));
|
|
1659
|
-
const innerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
1660
|
-
r: innerHaloR * innerScale.value * beat.value
|
|
1661
|
-
}));
|
|
1662
|
-
const outerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
|
|
1663
|
-
r: outerHaloR * outerScale.value,
|
|
1664
|
-
opacity: outerOpacity.value
|
|
1665
|
-
}));
|
|
1666
|
-
const ripple1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1667
|
-
const t = rippleCycle.value;
|
|
1668
|
-
return {
|
|
1669
|
-
r: outerHaloR * (1 + t * 0.55),
|
|
1670
|
-
opacity: state === "listening" ? 0.55 * (1 - t) : 0
|
|
1671
|
-
};
|
|
1672
|
-
});
|
|
1673
|
-
const ripple2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1674
|
-
const t = (rippleCycle.value + 0.34) % 1;
|
|
1675
|
-
return {
|
|
1676
|
-
r: outerHaloR * (1 + t * 0.55),
|
|
1677
|
-
opacity: state === "listening" ? 0.45 * (1 - t) : 0
|
|
1678
|
-
};
|
|
1679
|
-
});
|
|
1680
|
-
const ripple3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1681
|
-
const t = (rippleCycle.value + 0.67) % 1;
|
|
1682
|
-
return {
|
|
1683
|
-
r: outerHaloR * (1 + t * 0.55),
|
|
1684
|
-
opacity: state === "listening" ? 0.35 * (1 - t) : 0
|
|
1685
|
-
};
|
|
1686
|
-
});
|
|
1687
|
-
const spark1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1688
|
-
const angle = orbit1.value * Math.PI * 2 - Math.PI / 2;
|
|
1689
|
-
const r = coreR * 0.55;
|
|
1690
|
-
return {
|
|
1691
|
-
cx: center + Math.cos(angle) * r,
|
|
1692
|
-
cy: center + Math.sin(angle) * r,
|
|
1693
|
-
opacity: state === "thinking" ? 1 : 0
|
|
1694
|
-
};
|
|
1695
|
-
});
|
|
1696
|
-
const spark2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1697
|
-
const angle = orbit2.value * Math.PI * 2 + Math.PI * 0.6;
|
|
1698
|
-
const r = coreR * 0.85;
|
|
1699
|
-
return {
|
|
1700
|
-
cx: center + Math.cos(angle) * r,
|
|
1701
|
-
cy: center + Math.sin(angle) * r,
|
|
1702
|
-
opacity: state === "thinking" ? 0.9 : 0
|
|
1703
|
-
};
|
|
1704
|
-
});
|
|
1705
|
-
const spark3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
|
|
1706
|
-
const angle = orbit3.value * Math.PI * 2 + Math.PI * 1.3;
|
|
1707
|
-
const r = coreR * 1.05;
|
|
1708
|
-
return {
|
|
1709
|
-
cx: center + Math.cos(angle) * r,
|
|
1710
|
-
cy: center + Math.sin(angle) * r,
|
|
1711
|
-
opacity: state === "thinking" ? 0.7 : 0
|
|
1671
|
+
return component;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Prewarm: load every plugin bundle in the background after app boot, so a
|
|
1675
|
+
* later open is instant (in-memory hit) instead of round-tripping the
|
|
1676
|
+
* network. Errors are swallowed per-plugin — one bad bundle shouldn't
|
|
1677
|
+
* block others. Concurrency capped at 3.
|
|
1678
|
+
*/
|
|
1679
|
+
async prewarmAll(items) {
|
|
1680
|
+
const queue = [...items];
|
|
1681
|
+
const concurrency = Math.min(3, queue.length);
|
|
1682
|
+
const start = Date.now();
|
|
1683
|
+
let okCount = 0;
|
|
1684
|
+
let failCount = 0;
|
|
1685
|
+
const worker = async () => {
|
|
1686
|
+
while (queue.length > 0) {
|
|
1687
|
+
const it = queue.shift();
|
|
1688
|
+
if (!it) return;
|
|
1689
|
+
try {
|
|
1690
|
+
await this.load(it.pluginId, it.bundleUrl, it.version, it.bundleHash);
|
|
1691
|
+
okCount++;
|
|
1692
|
+
} catch (err) {
|
|
1693
|
+
failCount++;
|
|
1694
|
+
console.log(`[prewarm] ${it.pluginId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1712
1697
|
};
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
{
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1698
|
+
await Promise.all(Array.from({ length: concurrency }, worker));
|
|
1699
|
+
console.log(`[prewarm] ${okCount} loaded, ${failCount} failed in ${Date.now() - start}ms`);
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Clear all caches (in-memory + storage).
|
|
1703
|
+
*/
|
|
1704
|
+
async clearAll() {
|
|
1705
|
+
this.modules.clear();
|
|
1706
|
+
try {
|
|
1707
|
+
await getBundleStorage().clearAll();
|
|
1708
|
+
} catch (err) {
|
|
1709
|
+
console.warn("[BundleManager] clearAll error:", err);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Clear cache for a specific plugin/bundle.
|
|
1714
|
+
*/
|
|
1715
|
+
async clearPlugin(pluginId) {
|
|
1716
|
+
const storage = getBundleStorage();
|
|
1717
|
+
const index = await storage.loadIndex();
|
|
1718
|
+
const entry = index[pluginId];
|
|
1719
|
+
if (entry) {
|
|
1720
|
+
this.modules.delete(entry.bundleUrl);
|
|
1721
|
+
delete index[pluginId];
|
|
1722
|
+
await storage.saveIndex(index);
|
|
1723
|
+
try {
|
|
1724
|
+
await storage.deleteBundle(entry.localPath);
|
|
1725
|
+
} catch {
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
// ── Private: module loading pipeline ────────────────────────
|
|
1730
|
+
async loadModule(bundleUrl, version, expectedHash) {
|
|
1731
|
+
if (this.modules.has(bundleUrl)) return;
|
|
1732
|
+
const storage = getBundleStorage();
|
|
1733
|
+
const index = await storage.loadIndex();
|
|
1734
|
+
const expectedLc = expectedHash ? expectedHash.toLowerCase() : null;
|
|
1735
|
+
let content = null;
|
|
1736
|
+
for (const entry of Object.values(index)) {
|
|
1737
|
+
if (entry.bundleUrl === bundleUrl && entry.version === version) {
|
|
1738
|
+
const age = Date.now() - entry.timestamp;
|
|
1739
|
+
const hashOk = expectedLc && entry.bundleHash && entry.bundleHash.toLowerCase() === expectedLc;
|
|
1740
|
+
if (age < CACHE_TTL && hashOk) {
|
|
1741
|
+
content = await storage.readBundle(entry.localPath);
|
|
1742
|
+
if (content) break;
|
|
1743
|
+
}
|
|
1745
1744
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1745
|
+
}
|
|
1746
|
+
if (!content) {
|
|
1747
|
+
const downloaded = await this.download(bundleUrl, expectedLc);
|
|
1748
|
+
content = downloaded.content;
|
|
1749
|
+
const safeName = bundleUrl.replace(/[^a-zA-Z0-9]/g, "_").slice(-80);
|
|
1750
|
+
try {
|
|
1751
|
+
const localPath = await storage.writeBundle(`${safeName}@${version}.js`, content);
|
|
1752
|
+
index[bundleUrl] = {
|
|
1753
|
+
localPath,
|
|
1754
|
+
version,
|
|
1755
|
+
timestamp: Date.now(),
|
|
1756
|
+
bundleUrl,
|
|
1757
|
+
bundleHash: downloaded.sha256
|
|
1758
|
+
};
|
|
1759
|
+
await storage.saveIndex(index);
|
|
1760
|
+
} catch (err) {
|
|
1761
|
+
console.warn("[BundleManager] Cache write error:", err);
|
|
1756
1762
|
}
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1763
|
+
}
|
|
1764
|
+
const mod = this.evaluate(content, bundleUrl);
|
|
1765
|
+
this.modules.set(bundleUrl, mod);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Download + integrity-verify a bundle. Refuses to return when:
|
|
1769
|
+
* - manifest hash and computed hash disagree
|
|
1770
|
+
* - server's `X-Bundle-SHA256` disagrees with manifest hash
|
|
1771
|
+
* - no expected hash AND no server hash header (cannot prove the bundle
|
|
1772
|
+
* wasn't tampered with — fail closed rather than trust the wire).
|
|
1773
|
+
*/
|
|
1774
|
+
async download(bundleUrl, expectedHash) {
|
|
1775
|
+
const cacheBust = `${bundleUrl}${bundleUrl.includes("?") ? "&" : "?"}t=${Date.now()}`;
|
|
1776
|
+
const response = await (0, import_core6.apiFetchRaw)(cacheBust);
|
|
1777
|
+
if (!response.ok) {
|
|
1778
|
+
const body = await response.text().catch(() => "");
|
|
1779
|
+
throw new Error(`Download failed: ${response.status} ${response.statusText} \u2014 ${body.substring(0, 200)}`);
|
|
1780
|
+
}
|
|
1781
|
+
const content = await response.text();
|
|
1782
|
+
if (content.length < 50 || content.trimStart().startsWith("<!")) {
|
|
1783
|
+
throw new Error("Bundle content is empty or HTML \u2014 server may have returned an error page");
|
|
1784
|
+
}
|
|
1785
|
+
const headerHash = (response.headers.get("x-bundle-sha256") || "").toLowerCase();
|
|
1786
|
+
const computed = sha256Hex(content);
|
|
1787
|
+
if (expectedHash) {
|
|
1788
|
+
if (computed !== expectedHash) {
|
|
1789
|
+
throw new Error(
|
|
1790
|
+
`Bundle integrity FAIL: expected sha256=${expectedHash.slice(0, 12)}... got ${computed.slice(0, 12)}.... Refusing to evaluate.`
|
|
1791
|
+
);
|
|
1767
1792
|
}
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1773
|
-
AnimatedCircle,
|
|
1774
|
-
{
|
|
1775
|
-
r: Math.max(3, size * 0.05),
|
|
1776
|
-
fill: "url(#adaSpark)",
|
|
1777
|
-
animatedProps: spark1Props
|
|
1793
|
+
if (headerHash && headerHash !== expectedHash) {
|
|
1794
|
+
throw new Error(
|
|
1795
|
+
`Bundle hash mismatch: manifest=${expectedHash.slice(0, 12)}... server=${headerHash.slice(0, 12)}.... Refusing to evaluate.`
|
|
1796
|
+
);
|
|
1778
1797
|
}
|
|
1779
|
-
)
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
fill: "url(#adaSpark)",
|
|
1785
|
-
animatedProps: spark2Props
|
|
1798
|
+
} else if (headerHash) {
|
|
1799
|
+
if (computed !== headerHash) {
|
|
1800
|
+
throw new Error(
|
|
1801
|
+
`Bundle body sha256 (${computed.slice(0, 12)}...) does not match server's X-Bundle-SHA256 (${headerHash.slice(0, 12)}...).`
|
|
1802
|
+
);
|
|
1786
1803
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1804
|
+
console.warn(`[BundleManager] No manifest bundleHash \u2014 verified via X-Bundle-SHA256 header only`);
|
|
1805
|
+
} else {
|
|
1806
|
+
throw new Error(
|
|
1807
|
+
`No bundleHash in manifest and no X-Bundle-SHA256 header from server. Refusing to evaluate untrusted bundle.`
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
return { content, sha256: computed };
|
|
1811
|
+
}
|
|
1812
|
+
evaluate(content, bundleUrl) {
|
|
1813
|
+
let cleaned = content.replace(
|
|
1814
|
+
/__toESM\(require\(("[^"]+")\)(?:,\s*\d+)?\)/g,
|
|
1815
|
+
"require($1)"
|
|
1816
|
+
);
|
|
1817
|
+
cleaned = cleaned.replace(
|
|
1818
|
+
/module\.exports\s*=\s*__toCommonJS\((\w+)\)/g,
|
|
1819
|
+
"module.exports = $1"
|
|
1820
|
+
);
|
|
1821
|
+
const mod = { exports: {} };
|
|
1822
|
+
try {
|
|
1823
|
+
const factory = new Function(
|
|
1824
|
+
"module",
|
|
1825
|
+
"exports",
|
|
1826
|
+
"require",
|
|
1827
|
+
"__filename",
|
|
1828
|
+
"__dirname",
|
|
1829
|
+
cleaned
|
|
1830
|
+
);
|
|
1831
|
+
factory(mod, mod.exports, requireShim, bundleUrl, "adas-plugin-bundles");
|
|
1832
|
+
} catch (err) {
|
|
1833
|
+
throw new Error(`Bundle evaluation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1834
|
+
}
|
|
1835
|
+
const raw = mod.exports;
|
|
1836
|
+
const materialized = {};
|
|
1837
|
+
for (const key of Object.getOwnPropertyNames(raw)) {
|
|
1838
|
+
try {
|
|
1839
|
+
materialized[key] = raw[key];
|
|
1840
|
+
} catch {
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
return materialized;
|
|
1844
|
+
}
|
|
1845
|
+
// ── Private: component extraction ───────────────────────────
|
|
1846
|
+
/**
|
|
1847
|
+
* Find a plugin component in a loaded module.
|
|
1848
|
+
* Handles: default export, direct key match, multi-plugin .id match.
|
|
1849
|
+
*/
|
|
1850
|
+
getComponentFromMemory(pluginId, bundleUrl) {
|
|
1851
|
+
const mod = this.modules.get(bundleUrl);
|
|
1852
|
+
if (!mod) return null;
|
|
1853
|
+
const shortName = pluginId.includes(":") ? pluginId.split(":").pop() : pluginId;
|
|
1854
|
+
if (mod[pluginId] && typeof mod[pluginId].Component === "function") {
|
|
1855
|
+
return mod[pluginId];
|
|
1856
|
+
}
|
|
1857
|
+
const pascal = shortName.replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase());
|
|
1858
|
+
if (mod[pascal] && typeof mod[pascal] === "object" && typeof mod[pascal].Component === "function") {
|
|
1859
|
+
return mod[pascal];
|
|
1860
|
+
}
|
|
1861
|
+
if (mod.default && typeof mod.default === "object" && typeof mod.default.Component === "function") {
|
|
1862
|
+
return mod.default;
|
|
1863
|
+
}
|
|
1864
|
+
for (const key of Object.keys(mod)) {
|
|
1865
|
+
const val = mod[key];
|
|
1866
|
+
if (val && typeof val === "object" && val.id === shortName && typeof val.Component === "function") {
|
|
1867
|
+
return val;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
return null;
|
|
1871
|
+
}
|
|
1872
|
+
describeModule(mod) {
|
|
1873
|
+
if (!mod) return "(empty)";
|
|
1874
|
+
return Object.keys(mod).map((k) => {
|
|
1875
|
+
const v = mod[k];
|
|
1876
|
+
if (v && typeof v === "object" && v.id) return `${k}(id="${v.id}")`;
|
|
1877
|
+
return k;
|
|
1878
|
+
}).join(", ");
|
|
1879
|
+
}
|
|
1880
|
+
};
|
|
1881
|
+
var bundleManager = new BundleManager();
|
|
1882
|
+
|
|
1883
|
+
// src/bridge/native.ts
|
|
1884
|
+
var import_react10 = require("react");
|
|
1885
|
+
var import_core7 = require("@ateam-ai-mobile/core");
|
|
1886
|
+
function buildContext(pluginId, connectorId) {
|
|
1887
|
+
const user = (0, import_core7.getUser)();
|
|
1888
|
+
return {
|
|
1889
|
+
tenant: (0, import_core7.getTenant)(),
|
|
1890
|
+
pluginId,
|
|
1891
|
+
connectorId,
|
|
1892
|
+
user: user ? { id: user.actorId || "", name: user.name || "", roles: user.roles || [] } : void 0
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
function useNativeBridge(pluginId, connectorId, commandBufferRef) {
|
|
1896
|
+
const initCallbackRef = (0, import_react10.useRef)(null);
|
|
1897
|
+
const commandListenersRef = (0, import_react10.useRef)(/* @__PURE__ */ new Set());
|
|
1898
|
+
const initializedRef = (0, import_react10.useRef)(false);
|
|
1899
|
+
const fireInit = (0, import_react10.useCallback)(() => {
|
|
1900
|
+
if (initializedRef.current || !initCallbackRef.current) return;
|
|
1901
|
+
initCallbackRef.current(buildContext(pluginId, connectorId));
|
|
1902
|
+
initializedRef.current = true;
|
|
1903
|
+
}, [pluginId, connectorId]);
|
|
1904
|
+
const onInit = (0, import_react10.useCallback)((cb) => {
|
|
1905
|
+
initCallbackRef.current = cb;
|
|
1906
|
+
setTimeout(fireInit, 0);
|
|
1907
|
+
}, [fireInit]);
|
|
1908
|
+
const mcpCall = (0, import_react10.useCallback)(async (toolOrConnector, argsOrTool, cIdOrArgs) => {
|
|
1909
|
+
let tool;
|
|
1910
|
+
let args;
|
|
1911
|
+
let cId;
|
|
1912
|
+
if (typeof argsOrTool === "string") {
|
|
1913
|
+
cId = toolOrConnector;
|
|
1914
|
+
tool = argsOrTool;
|
|
1915
|
+
args = cIdOrArgs || {};
|
|
1916
|
+
} else {
|
|
1917
|
+
tool = toolOrConnector;
|
|
1918
|
+
args = argsOrTool;
|
|
1919
|
+
cId = typeof cIdOrArgs === "string" ? cIdOrArgs : void 0;
|
|
1920
|
+
}
|
|
1921
|
+
const targetConnector = cId || connectorId;
|
|
1922
|
+
if (!targetConnector) {
|
|
1923
|
+
console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2014 no connectorId. tool=${tool}`);
|
|
1924
|
+
throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
|
|
1925
|
+
}
|
|
1926
|
+
try {
|
|
1927
|
+
const data = await (0, import_core7.connectorCall)(targetConnector, tool, args);
|
|
1928
|
+
if (!data.ok && data.error) {
|
|
1929
|
+
throw new Error(data.error);
|
|
1930
|
+
}
|
|
1931
|
+
return (0, import_core7.unwrapMcpResult)(data.result);
|
|
1932
|
+
} catch (err) {
|
|
1933
|
+
console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2192 connector=${targetConnector} tool=${tool}:`, err?.message || err);
|
|
1934
|
+
throw err;
|
|
1935
|
+
}
|
|
1936
|
+
}, [pluginId, connectorId]);
|
|
1937
|
+
const mcpFetch = (0, import_react10.useCallback)(async (body) => {
|
|
1938
|
+
return (0, import_core7.mcpFetch)(body);
|
|
1939
|
+
}, []);
|
|
1940
|
+
const sendCommand = (0, import_react10.useCallback)((type, payload) => {
|
|
1941
|
+
if (type === "plugin.command.result" && payload?.correlationId) {
|
|
1942
|
+
(0, import_core7.postCommandResult)(payload.correlationId, payload.result, payload.error);
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
}, [pluginId]);
|
|
1946
|
+
const onCommand = (0, import_react10.useCallback)((cb) => {
|
|
1947
|
+
commandListenersRef.current.add(cb);
|
|
1948
|
+
if (commandBufferRef) {
|
|
1949
|
+
const buf = commandBufferRef.current;
|
|
1950
|
+
const remaining = [];
|
|
1951
|
+
for (const cmd of buf) {
|
|
1952
|
+
if (cmd.pluginId === pluginId && cmd.command !== "__focus") {
|
|
1953
|
+
try {
|
|
1954
|
+
cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1955
|
+
} catch {
|
|
1956
|
+
}
|
|
1957
|
+
} else {
|
|
1958
|
+
remaining.push(cmd);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
commandBufferRef.current = remaining;
|
|
1962
|
+
}
|
|
1963
|
+
for (const cmd of import_core7.pluginCommandEmitter.drainPluginCommands(pluginId)) {
|
|
1964
|
+
try {
|
|
1965
|
+
cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1966
|
+
} catch {
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return () => {
|
|
1970
|
+
commandListenersRef.current.delete(cb);
|
|
1971
|
+
};
|
|
1972
|
+
}, [pluginId, commandBufferRef]);
|
|
1973
|
+
(0, import_react10.useEffect)(() => {
|
|
1974
|
+
const unsub = import_core7.pluginCommandEmitter.on("plugin-command", (cmd) => {
|
|
1975
|
+
if (cmd.pluginId !== pluginId) return;
|
|
1976
|
+
if (cmd.command === "__focus") return;
|
|
1977
|
+
commandListenersRef.current.forEach((fn) => {
|
|
1978
|
+
try {
|
|
1979
|
+
fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1980
|
+
} catch {
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
});
|
|
1984
|
+
return unsub;
|
|
1985
|
+
}, [pluginId]);
|
|
1986
|
+
(0, import_react10.useEffect)(() => {
|
|
1987
|
+
const timer = setTimeout(() => {
|
|
1988
|
+
const dispatch = (cmd) => {
|
|
1989
|
+
commandListenersRef.current.forEach((fn) => {
|
|
1990
|
+
try {
|
|
1991
|
+
fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
};
|
|
1996
|
+
if (commandBufferRef) {
|
|
1997
|
+
const remaining = [];
|
|
1998
|
+
for (const cmd of commandBufferRef.current) {
|
|
1999
|
+
if (cmd.pluginId === pluginId && cmd.command !== "__focus") dispatch(cmd);
|
|
2000
|
+
else remaining.push(cmd);
|
|
2001
|
+
}
|
|
2002
|
+
commandBufferRef.current = remaining;
|
|
1794
2003
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
import_react_native_svg.Text,
|
|
1798
|
-
{
|
|
1799
|
-
x: center,
|
|
1800
|
-
y: center + size * 0.11,
|
|
1801
|
-
fontSize: size * 0.34,
|
|
1802
|
-
fontWeight: "600",
|
|
1803
|
-
fill: "#FFF5E0",
|
|
1804
|
-
textAnchor: "middle",
|
|
1805
|
-
letterSpacing: -size * 5e-3,
|
|
1806
|
-
children: "iA"
|
|
2004
|
+
for (const cmd of import_core7.pluginCommandEmitter.drainPluginCommands(pluginId)) {
|
|
2005
|
+
dispatch(cmd);
|
|
1807
2006
|
}
|
|
1808
|
-
)
|
|
1809
|
-
|
|
1810
|
-
}
|
|
1811
|
-
var styles2 = import_react_native3.StyleSheet.create({
|
|
1812
|
-
wrap: {
|
|
1813
|
-
alignItems: "center",
|
|
1814
|
-
justifyContent: "center"
|
|
1815
|
-
}
|
|
1816
|
-
});
|
|
1817
|
-
|
|
1818
|
-
// src/surfaces/SurfaceDrawer.tsx
|
|
1819
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1820
|
-
var SCREEN_H = import_react_native4.Dimensions.get("window").height;
|
|
1821
|
-
var fontFam = import_react_native4.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1822
|
-
function SurfaceDrawer({
|
|
1823
|
-
visible,
|
|
1824
|
-
onClose,
|
|
1825
|
-
title,
|
|
1826
|
-
subtitle,
|
|
1827
|
-
privacy,
|
|
1828
|
-
showOrb = true,
|
|
1829
|
-
heightRatio = 0.85,
|
|
1830
|
-
children
|
|
1831
|
-
}) {
|
|
1832
|
-
const sheetH = Math.round(SCREEN_H * heightRatio);
|
|
1833
|
-
const fadeAnim = (0, import_react10.useRef)(new import_react_native4.Animated.Value(0)).current;
|
|
1834
|
-
const slideAnim = (0, import_react10.useRef)(new import_react_native4.Animated.Value(sheetH)).current;
|
|
2007
|
+
}, 500);
|
|
2008
|
+
return () => clearTimeout(timer);
|
|
2009
|
+
}, [pluginId, commandBufferRef]);
|
|
1835
2010
|
(0, import_react10.useEffect)(() => {
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
2011
|
+
return () => {
|
|
2012
|
+
commandListenersRef.current.clear();
|
|
2013
|
+
initializedRef.current = false;
|
|
2014
|
+
};
|
|
2015
|
+
}, []);
|
|
2016
|
+
const close = (0, import_react10.useCallback)(() => {
|
|
2017
|
+
import_core7.pluginCommandEmitter.emit("plugin-close", { pluginId });
|
|
2018
|
+
}, [pluginId]);
|
|
2019
|
+
const sendMessage = (0, import_react10.useCallback)((text) => {
|
|
2020
|
+
const t = (text || "").trim();
|
|
2021
|
+
if (!t) return;
|
|
2022
|
+
try {
|
|
2023
|
+
import_core7.useChatStore.getState().sendMessage(t);
|
|
2024
|
+
} catch (err) {
|
|
2025
|
+
console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
|
|
1844
2026
|
}
|
|
1845
|
-
}, [
|
|
1846
|
-
const
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1856
|
-
import_react_native4.Animated.View,
|
|
1857
|
-
{
|
|
1858
|
-
style: [
|
|
1859
|
-
styles3.sheet,
|
|
1860
|
-
{ height: sheetH, transform: [{ translateY: slideAnim }] }
|
|
1861
|
-
],
|
|
1862
|
-
children: [
|
|
1863
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.handle }),
|
|
1864
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles3.header, children: [
|
|
1865
|
-
showOrb ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.headerOrb, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AdaOrb, { size: 36, state: "idle" }) }) : null,
|
|
1866
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: { flex: 1 }, children: [
|
|
1867
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.title, children: title }),
|
|
1868
|
-
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.subtitle, children: subtitle }) : null,
|
|
1869
|
-
privacy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles3.privacyPill, children: [
|
|
1870
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg2.default, { width: 11, height: 11, viewBox: "0 0 24 24", fill: "none", stroke: import_core7.ada.inkSoft, strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1871
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2z" }),
|
|
1872
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M7 11V7a5 5 0 0110 0v4" })
|
|
1873
|
-
] }),
|
|
1874
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.privacyText, children: "Only you can see this" })
|
|
1875
|
-
] }) : null
|
|
1876
|
-
] }),
|
|
1877
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1878
|
-
import_react_native4.Pressable,
|
|
1879
|
-
{
|
|
1880
|
-
accessibilityRole: "button",
|
|
1881
|
-
accessibilityLabel: "Close",
|
|
1882
|
-
style: styles3.closeBtn,
|
|
1883
|
-
onPress: close,
|
|
1884
|
-
hitSlop: 12,
|
|
1885
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: import_core7.ada.inkSoft, strokeWidth: 2.2, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M18 6L6 18M6 6l12 12" }) })
|
|
1886
|
-
}
|
|
1887
|
-
)
|
|
1888
|
-
] }),
|
|
1889
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.body, children })
|
|
1890
|
-
]
|
|
1891
|
-
}
|
|
1892
|
-
)
|
|
1893
|
-
] });
|
|
2027
|
+
}, []);
|
|
2028
|
+
const prepareMessage = (0, import_react10.useCallback)((text) => {
|
|
2029
|
+
const t = (text || "").trim();
|
|
2030
|
+
if (!t) return;
|
|
2031
|
+
import_core7.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
|
|
2032
|
+
}, []);
|
|
2033
|
+
return (0, import_react10.useMemo)(
|
|
2034
|
+
() => ({ onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage }),
|
|
2035
|
+
[onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage]
|
|
2036
|
+
);
|
|
1894
2037
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
fontSize: 17,
|
|
1940
|
-
fontWeight: "600",
|
|
1941
|
-
color: import_core7.ada.ink,
|
|
1942
|
-
letterSpacing: -0.2,
|
|
1943
|
-
fontFamily: fontFam
|
|
1944
|
-
},
|
|
1945
|
-
subtitle: {
|
|
1946
|
-
fontSize: 13,
|
|
1947
|
-
fontWeight: "400",
|
|
1948
|
-
color: import_core7.ada.inkSoft,
|
|
1949
|
-
marginTop: 2,
|
|
1950
|
-
letterSpacing: -0.1,
|
|
1951
|
-
fontFamily: fontFam
|
|
1952
|
-
},
|
|
1953
|
-
privacyPill: {
|
|
1954
|
-
flexDirection: "row",
|
|
1955
|
-
alignItems: "center",
|
|
1956
|
-
gap: 5,
|
|
1957
|
-
marginTop: 4
|
|
1958
|
-
},
|
|
1959
|
-
privacyText: {
|
|
1960
|
-
fontSize: 11,
|
|
1961
|
-
fontWeight: "500",
|
|
1962
|
-
color: import_core7.ada.inkSoft,
|
|
1963
|
-
letterSpacing: 0.2,
|
|
1964
|
-
fontFamily: fontFam
|
|
1965
|
-
},
|
|
1966
|
-
closeBtn: {
|
|
1967
|
-
width: 32,
|
|
1968
|
-
height: 32,
|
|
1969
|
-
borderRadius: 16,
|
|
1970
|
-
backgroundColor: import_core7.ada.paperSoft,
|
|
1971
|
-
justifyContent: "center",
|
|
1972
|
-
alignItems: "center"
|
|
1973
|
-
},
|
|
1974
|
-
body: {
|
|
1975
|
-
flex: 1
|
|
1976
|
-
}
|
|
1977
|
-
});
|
|
1978
|
-
|
|
1979
|
-
// src/surfaces/SurfaceCard.tsx
|
|
1980
|
-
var import_react_native5 = require("react-native");
|
|
1981
|
-
var import_core8 = require("@ateam-ai-mobile/core");
|
|
1982
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1983
|
-
var fontFam2 = import_react_native5.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1984
|
-
function SurfaceCard({
|
|
1985
|
-
icon,
|
|
1986
|
-
title,
|
|
1987
|
-
subtitle,
|
|
1988
|
-
onPress,
|
|
1989
|
-
onLongPress,
|
|
1990
|
-
showArrow,
|
|
1991
|
-
children
|
|
1992
|
-
}) {
|
|
1993
|
-
const arrow = showArrow ?? !!onPress;
|
|
1994
|
-
const handlePress = () => {
|
|
1995
|
-
if (!onPress) return;
|
|
1996
|
-
getHaptics()?.impact("light");
|
|
1997
|
-
onPress();
|
|
1998
|
-
};
|
|
1999
|
-
const handleLongPress = () => {
|
|
2000
|
-
if (!onLongPress) return;
|
|
2001
|
-
getHaptics()?.impact("medium");
|
|
2002
|
-
onLongPress();
|
|
2003
|
-
};
|
|
2004
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2005
|
-
import_react_native5.Pressable,
|
|
2006
|
-
{
|
|
2007
|
-
accessibilityRole: "button",
|
|
2008
|
-
accessibilityLabel: [icon, title, subtitle].filter(Boolean).join(", "),
|
|
2009
|
-
accessibilityHint: onLongPress ? "Long-press for more options" : void 0,
|
|
2010
|
-
style: styles4.card,
|
|
2011
|
-
onPress: onPress ? handlePress : void 0,
|
|
2012
|
-
onLongPress: onLongPress ? handleLongPress : void 0,
|
|
2013
|
-
disabled: !onPress && !onLongPress,
|
|
2014
|
-
children: [
|
|
2015
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native5.View, { style: styles4.row, children: [
|
|
2016
|
-
icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.icon, children: icon }) : null,
|
|
2017
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native5.View, { style: { flex: 1 }, children: [
|
|
2018
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.title, children: title }),
|
|
2019
|
-
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.subtitle, children: subtitle }) : null
|
|
2020
|
-
] }),
|
|
2021
|
-
arrow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.arrow, children: "\u2192" }) : null
|
|
2022
|
-
] }),
|
|
2023
|
-
children ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.View, { style: styles4.body, children }) : null
|
|
2024
|
-
]
|
|
2038
|
+
function createNativeBridge(pluginId, connectorId) {
|
|
2039
|
+
const commandListeners = /* @__PURE__ */ new Set();
|
|
2040
|
+
return {
|
|
2041
|
+
onInit(cb) {
|
|
2042
|
+
setTimeout(() => {
|
|
2043
|
+
cb(buildContext(pluginId, connectorId));
|
|
2044
|
+
}, 0);
|
|
2045
|
+
},
|
|
2046
|
+
async mcpCall(tool, args, cId) {
|
|
2047
|
+
const targetConnector = cId || connectorId;
|
|
2048
|
+
if (!targetConnector) {
|
|
2049
|
+
throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
|
|
2050
|
+
}
|
|
2051
|
+
const data = await (0, import_core7.connectorCall)(targetConnector, tool, args);
|
|
2052
|
+
if (!data.ok && data.error) throw new Error(data.error);
|
|
2053
|
+
return (0, import_core7.unwrapMcpResult)(data.result);
|
|
2054
|
+
},
|
|
2055
|
+
async mcpFetch(body) {
|
|
2056
|
+
return (0, import_core7.mcpFetch)(body);
|
|
2057
|
+
},
|
|
2058
|
+
sendCommand(_type, _payload) {
|
|
2059
|
+
},
|
|
2060
|
+
onCommand(cb) {
|
|
2061
|
+
commandListeners.add(cb);
|
|
2062
|
+
return () => {
|
|
2063
|
+
commandListeners.delete(cb);
|
|
2064
|
+
};
|
|
2065
|
+
},
|
|
2066
|
+
close() {
|
|
2067
|
+
import_core7.pluginCommandEmitter.emit("plugin-close", { pluginId });
|
|
2068
|
+
},
|
|
2069
|
+
sendMessage(text) {
|
|
2070
|
+
const t = (text || "").trim();
|
|
2071
|
+
if (!t) return;
|
|
2072
|
+
try {
|
|
2073
|
+
import_core7.useChatStore.getState().sendMessage(t);
|
|
2074
|
+
} catch (err) {
|
|
2075
|
+
console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
|
|
2076
|
+
}
|
|
2077
|
+
},
|
|
2078
|
+
prepareMessage(text) {
|
|
2079
|
+
const t = (text || "").trim();
|
|
2080
|
+
if (!t) return;
|
|
2081
|
+
import_core7.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
|
|
2025
2082
|
}
|
|
2026
|
-
|
|
2083
|
+
};
|
|
2027
2084
|
}
|
|
2028
|
-
var styles4 = import_react_native5.StyleSheet.create({
|
|
2029
|
-
card: {
|
|
2030
|
-
backgroundColor: import_core8.ada.paperSoft,
|
|
2031
|
-
borderWidth: 1,
|
|
2032
|
-
borderColor: import_core8.ada.border,
|
|
2033
|
-
borderRadius: import_core8.borderRadius.xl,
|
|
2034
|
-
paddingHorizontal: 16,
|
|
2035
|
-
paddingVertical: 14
|
|
2036
|
-
},
|
|
2037
|
-
row: {
|
|
2038
|
-
flexDirection: "row",
|
|
2039
|
-
alignItems: "center",
|
|
2040
|
-
gap: 14
|
|
2041
|
-
},
|
|
2042
|
-
icon: {
|
|
2043
|
-
fontSize: 22
|
|
2044
|
-
},
|
|
2045
|
-
title: {
|
|
2046
|
-
fontSize: 15,
|
|
2047
|
-
fontWeight: "600",
|
|
2048
|
-
color: import_core8.ada.ink,
|
|
2049
|
-
letterSpacing: -0.2,
|
|
2050
|
-
fontFamily: fontFam2
|
|
2051
|
-
},
|
|
2052
|
-
subtitle: {
|
|
2053
|
-
fontSize: 13,
|
|
2054
|
-
fontWeight: "400",
|
|
2055
|
-
color: import_core8.ada.inkMuted,
|
|
2056
|
-
marginTop: 2,
|
|
2057
|
-
letterSpacing: -0.1,
|
|
2058
|
-
fontFamily: fontFam2
|
|
2059
|
-
},
|
|
2060
|
-
arrow: {
|
|
2061
|
-
fontSize: 18,
|
|
2062
|
-
color: import_core8.ada.inkMuted,
|
|
2063
|
-
fontWeight: "400"
|
|
2064
|
-
},
|
|
2065
|
-
body: {
|
|
2066
|
-
marginTop: 10,
|
|
2067
|
-
paddingTop: 10,
|
|
2068
|
-
borderTopWidth: 1,
|
|
2069
|
-
borderTopColor: import_core8.ada.border
|
|
2070
|
-
}
|
|
2071
|
-
});
|
|
2072
2085
|
|
|
2073
|
-
// src/
|
|
2086
|
+
// src/hooks/usePlugin.ts
|
|
2074
2087
|
var import_react11 = require("react");
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
closeLabel = "Close"
|
|
2089
|
-
}) {
|
|
2090
|
-
const fadeAnim = (0, import_react11.useRef)(new import_react_native6.Animated.Value(0)).current;
|
|
2091
|
-
const heroScale = (0, import_react11.useRef)(new import_react_native6.Animated.Value(0.6)).current;
|
|
2092
|
-
(0, import_react11.useEffect)(() => {
|
|
2093
|
-
if (visible) {
|
|
2094
|
-
import_react_native6.Animated.parallel([
|
|
2095
|
-
import_react_native6.Animated.timing(fadeAnim, { toValue: 1, duration: 280, useNativeDriver: true }),
|
|
2096
|
-
import_react_native6.Animated.spring(heroScale, { toValue: 1, useNativeDriver: true, tension: 60, friction: 11 })
|
|
2097
|
-
]).start();
|
|
2098
|
-
} else {
|
|
2099
|
-
fadeAnim.setValue(0);
|
|
2100
|
-
heroScale.setValue(0.6);
|
|
2101
|
-
}
|
|
2102
|
-
}, [visible]);
|
|
2103
|
-
const close = () => {
|
|
2104
|
-
import_react_native6.Animated.parallel([
|
|
2105
|
-
import_react_native6.Animated.timing(fadeAnim, { toValue: 0, duration: 180, useNativeDriver: true }),
|
|
2106
|
-
import_react_native6.Animated.timing(heroScale, { toValue: 0.6, duration: 180, useNativeDriver: true })
|
|
2107
|
-
]).start(() => onClose());
|
|
2108
|
-
};
|
|
2109
|
-
if (!visible) return null;
|
|
2110
|
-
const renderCloseIcon = () => {
|
|
2111
|
-
if (closeIcon === "hangup") {
|
|
2112
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: import_core9.ada.paper, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.Path, { d: "M3.68 16.07l3.92-3.11c.28-.23.68-.28 1.01-.14l2.77 1.15c.36.15.61.5.61.89v2.82c4.34-.76 7.93-4.35 8.69-8.69h-2.82c-.39 0-.74-.25-.89-.61L16.12 5.6c-.13-.33-.09-.73.14-1.01l3.11-3.92c.29-.37.81-.41 1.15-.08l3.24 3.24c.2.2.31.47.31.76C24 14.44 14.44 24 4.59 24c-.29 0-.56-.11-.76-.31L.59 20.45c-.33-.34-.29-.86.09-1.15z" }) });
|
|
2113
|
-
}
|
|
2114
|
-
if (closeIcon === "x") {
|
|
2115
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core9.ada.paper, strokeWidth: 2.5, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.Path, { d: "M18 6L6 18M6 6l12 12" }) });
|
|
2116
|
-
}
|
|
2117
|
-
return closeIcon;
|
|
2118
|
-
};
|
|
2119
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.Animated.View, { style: [styles5.overlay, { opacity: fadeAnim }], pointerEvents: "auto", children: [
|
|
2120
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.View, { style: styles5.topBar, children: [
|
|
2121
|
-
showWordmark ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.wordmark, children: "ada" }) : null,
|
|
2122
|
-
status ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.status, children: status }) : null
|
|
2123
|
-
] }),
|
|
2124
|
-
hero ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, { style: styles5.heroWrap, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Animated.View, { style: { transform: [{ scale: heroScale }] }, children: hero }) }) : null,
|
|
2125
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, { style: styles5.body, children }),
|
|
2126
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.View, { style: styles5.bottomBar, children: [
|
|
2127
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2128
|
-
import_react_native6.Pressable,
|
|
2129
|
-
{
|
|
2130
|
-
accessibilityRole: "button",
|
|
2131
|
-
accessibilityLabel: closeLabel,
|
|
2132
|
-
style: styles5.closeBtn,
|
|
2133
|
-
onPress: close,
|
|
2134
|
-
hitSlop: 12,
|
|
2135
|
-
children: renderCloseIcon()
|
|
2136
|
-
}
|
|
2137
|
-
),
|
|
2138
|
-
closeLabel ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.closeLabel, children: closeLabel }) : null
|
|
2139
|
-
] })
|
|
2140
|
-
] });
|
|
2088
|
+
function extractBundleUrl(pluginId, manifest) {
|
|
2089
|
+
const render = manifest.render;
|
|
2090
|
+
if (!render || typeof render !== "object") return { url: null, source: "none" };
|
|
2091
|
+
const injected = manifest.bundleUrl || render.bundleUrl || render.reactNative?.bundleUrl || null;
|
|
2092
|
+
const hasNativeComponent = !!(render.reactNative?.component || render.component);
|
|
2093
|
+
if (hasNativeComponent) {
|
|
2094
|
+
return {
|
|
2095
|
+
url: `/api/ui-plugins/${encodeURIComponent(pluginId)}/bundle.js`,
|
|
2096
|
+
source: injected ? "ignored-explicit" : "derived-default",
|
|
2097
|
+
...injected && { ignored: injected }
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
2100
|
+
return { url: null, source: "none" };
|
|
2141
2101
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
fontSize: 17,
|
|
2168
|
-
fontFamily: fontFam3,
|
|
2169
|
-
fontWeight: "500",
|
|
2170
|
-
color: import_core9.ada.ink,
|
|
2171
|
-
letterSpacing: -0.2
|
|
2172
|
-
},
|
|
2173
|
-
heroWrap: {
|
|
2174
|
-
paddingTop: 24,
|
|
2175
|
-
paddingBottom: 12,
|
|
2176
|
-
alignItems: "center",
|
|
2177
|
-
justifyContent: "center"
|
|
2178
|
-
},
|
|
2179
|
-
body: {
|
|
2180
|
-
flex: 1
|
|
2181
|
-
},
|
|
2182
|
-
bottomBar: {
|
|
2183
|
-
paddingBottom: import_react_native6.Platform.OS === "ios" ? 48 : 32,
|
|
2184
|
-
paddingTop: 12,
|
|
2185
|
-
alignItems: "center",
|
|
2186
|
-
gap: 8
|
|
2187
|
-
},
|
|
2188
|
-
closeBtn: {
|
|
2189
|
-
width: 64,
|
|
2190
|
-
height: 64,
|
|
2191
|
-
borderRadius: 32,
|
|
2192
|
-
backgroundColor: import_core9.ada.ink,
|
|
2193
|
-
justifyContent: "center",
|
|
2194
|
-
alignItems: "center",
|
|
2195
|
-
shadowColor: import_core9.ada.ink,
|
|
2196
|
-
shadowOffset: { width: 0, height: 8 },
|
|
2197
|
-
shadowOpacity: 0.18,
|
|
2198
|
-
shadowRadius: 14,
|
|
2199
|
-
elevation: 8
|
|
2200
|
-
},
|
|
2201
|
-
closeLabel: {
|
|
2202
|
-
fontSize: 13,
|
|
2203
|
-
fontFamily: fontFam3,
|
|
2204
|
-
fontWeight: "500",
|
|
2205
|
-
color: import_core9.ada.inkMuted,
|
|
2206
|
-
letterSpacing: 0.3
|
|
2102
|
+
function extractBundleHash(manifest) {
|
|
2103
|
+
if (manifest.bundleHash) return manifest.bundleHash;
|
|
2104
|
+
const render = manifest.render;
|
|
2105
|
+
if (!render || typeof render !== "object") return void 0;
|
|
2106
|
+
if (render.bundleHash) return render.bundleHash;
|
|
2107
|
+
if (render.reactNative?.bundleHash) return render.reactNative.bundleHash;
|
|
2108
|
+
return void 0;
|
|
2109
|
+
}
|
|
2110
|
+
function extractComponentId(manifest) {
|
|
2111
|
+
const render = manifest.render;
|
|
2112
|
+
if (!render || typeof render !== "object") return null;
|
|
2113
|
+
return render.component || render.reactNative?.component || null;
|
|
2114
|
+
}
|
|
2115
|
+
function usePlugin(pluginId, manifest) {
|
|
2116
|
+
const [plugin, setPlugin] = (0, import_react11.useState)(null);
|
|
2117
|
+
const [loading, setLoading] = (0, import_react11.useState)(true);
|
|
2118
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
2119
|
+
const [bundleMissing, setBundleMissing] = (0, import_react11.useState)(false);
|
|
2120
|
+
const version = manifest.version || "1.0.0";
|
|
2121
|
+
const { url: bundleUrl, ignored: ignoredUrl } = extractBundleUrl(pluginId, manifest);
|
|
2122
|
+
const bundleHash = extractBundleHash(manifest);
|
|
2123
|
+
const componentId = extractComponentId(manifest);
|
|
2124
|
+
const lookupId = componentId || pluginId;
|
|
2125
|
+
if (ignoredUrl) {
|
|
2126
|
+
console.warn(`[usePlugin] ${pluginId}: IGNORED connector-injected bundleUrl="${ignoredUrl}". The host derives bundle URLs from pluginId via the canonical route.`);
|
|
2207
2127
|
}
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
const cleanup = { ...s.activeProps };
|
|
2250
|
-
delete cleanup[id];
|
|
2251
|
-
const patch = { activeProps: cleanup };
|
|
2252
|
-
if (s.activeDrawer === id) patch.activeDrawer = null;
|
|
2253
|
-
if (s.activeFullscreen === id) patch.activeFullscreen = null;
|
|
2254
|
-
set(patch);
|
|
2255
|
-
},
|
|
2256
|
-
list: (filter) => {
|
|
2257
|
-
const all = Object.values(get().manifests);
|
|
2258
|
-
return all.filter((m) => {
|
|
2259
|
-
if (filter?.type && m.type !== filter.type) return false;
|
|
2260
|
-
if (filter?.visibility && !filter.visibility.includes(m.visibility)) return false;
|
|
2261
|
-
if (filter?.placement) {
|
|
2262
|
-
if (filter.placement === "unset") {
|
|
2263
|
-
if (m.placement) return false;
|
|
2264
|
-
} else if (m.placement !== filter.placement) {
|
|
2265
|
-
return false;
|
|
2128
|
+
(0, import_react11.useEffect)(() => {
|
|
2129
|
+
let cancelled = false;
|
|
2130
|
+
(async () => {
|
|
2131
|
+
try {
|
|
2132
|
+
if (nativePluginRegistry.has(lookupId)) {
|
|
2133
|
+
const registered = await nativePluginRegistry.get(lookupId);
|
|
2134
|
+
if (cancelled) return;
|
|
2135
|
+
if (!registered) {
|
|
2136
|
+
throw new Error(`Local plugin not found: ${lookupId}`);
|
|
2137
|
+
}
|
|
2138
|
+
if (registered.type === "service") {
|
|
2139
|
+
throw new Error(`Plugin ${lookupId} is a service plugin and cannot be rendered`);
|
|
2140
|
+
}
|
|
2141
|
+
setPlugin(registered);
|
|
2142
|
+
setLoading(false);
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
if (bundleUrl) {
|
|
2146
|
+
try {
|
|
2147
|
+
const component = await bundleManager.load(pluginId, bundleUrl, version, bundleHash);
|
|
2148
|
+
if (cancelled) return;
|
|
2149
|
+
setPlugin(component);
|
|
2150
|
+
setLoading(false);
|
|
2151
|
+
return;
|
|
2152
|
+
} catch (bundleErr) {
|
|
2153
|
+
const msg = bundleErr instanceof Error ? bundleErr.message : String(bundleErr);
|
|
2154
|
+
console.warn(`[usePlugin] ${pluginId}: Bundle load failed, falling back to WebView:`, msg);
|
|
2155
|
+
if (!cancelled) {
|
|
2156
|
+
setBundleMissing(true);
|
|
2157
|
+
setLoading(false);
|
|
2158
|
+
}
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
const iframeUrl = manifest?.render?.iframeUrl || manifest?.render?.mode === "adaptive" && manifest?.render?.iframe?.iframeUrl;
|
|
2163
|
+
if (iframeUrl) {
|
|
2164
|
+
if (!cancelled) {
|
|
2165
|
+
setBundleMissing(true);
|
|
2166
|
+
setLoading(false);
|
|
2167
|
+
}
|
|
2168
|
+
return;
|
|
2266
2169
|
}
|
|
2170
|
+
throw new Error(
|
|
2171
|
+
`Plugin "${manifest.name || pluginId}" has no bundle URL and is not in the local registry. Check that the solution definition includes a valid render.reactNative.bundleUrl.`
|
|
2172
|
+
);
|
|
2173
|
+
} catch (err) {
|
|
2174
|
+
if (cancelled) return;
|
|
2175
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2176
|
+
console.error(`[usePlugin] Failed to load ${pluginId}:`, msg);
|
|
2177
|
+
setError(msg);
|
|
2178
|
+
setLoading(false);
|
|
2267
2179
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
return
|
|
2274
|
-
}
|
|
2275
|
-
function isInlineSurface(m) {
|
|
2276
|
-
return m.type === "card" || m.type === "header" || m.type === "ambient" || m.type === "nudge";
|
|
2180
|
+
})();
|
|
2181
|
+
return () => {
|
|
2182
|
+
cancelled = true;
|
|
2183
|
+
};
|
|
2184
|
+
}, [pluginId, lookupId, bundleUrl, bundleHash, version]);
|
|
2185
|
+
return { plugin, loading, error, bundleMissing };
|
|
2277
2186
|
}
|
|
2278
2187
|
|
|
2279
|
-
// src/
|
|
2188
|
+
// src/hooks/useRemotePlugins.ts
|
|
2280
2189
|
var import_react12 = require("react");
|
|
2281
|
-
var
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
const
|
|
2285
|
-
const
|
|
2286
|
-
const
|
|
2287
|
-
const
|
|
2288
|
-
|
|
2289
|
-
|
|
2190
|
+
var import_core8 = require("@ateam-ai-mobile/core");
|
|
2191
|
+
function useRemotePlugins(solutionId) {
|
|
2192
|
+
const [plugins, setPlugins] = (0, import_react12.useState)([]);
|
|
2193
|
+
const [loading, setLoading] = (0, import_react12.useState)(true);
|
|
2194
|
+
const [refreshing, setRefreshing] = (0, import_react12.useState)(false);
|
|
2195
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
2196
|
+
const fetchRemotePlugins = (0, import_react12.useCallback)(async () => {
|
|
2197
|
+
try {
|
|
2198
|
+
setError(null);
|
|
2199
|
+
const targetSolutionId = solutionId || "current";
|
|
2200
|
+
let data;
|
|
2201
|
+
try {
|
|
2202
|
+
data = await (0, import_core8.apiFetch)(`/api/solutions/${targetSolutionId}/ui-plugins`);
|
|
2203
|
+
} catch (err) {
|
|
2204
|
+
if (err?.message?.includes("404")) {
|
|
2205
|
+
console.warn(`[useRemotePlugins] Solution ${targetSolutionId} not found or has no plugins`);
|
|
2206
|
+
setPlugins([]);
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
throw err;
|
|
2210
|
+
}
|
|
2211
|
+
const uiPlugins = (data.plugins || []).map((plugin) => ({
|
|
2212
|
+
id: plugin.id,
|
|
2213
|
+
name: plugin.name,
|
|
2214
|
+
version: plugin.version || "1.0.0",
|
|
2215
|
+
source: "remote",
|
|
2216
|
+
manifest: {
|
|
2217
|
+
id: plugin.id,
|
|
2218
|
+
name: plugin.name,
|
|
2219
|
+
version: plugin.version || "1.0.0",
|
|
2220
|
+
type: "ui",
|
|
2221
|
+
description: plugin.description || "",
|
|
2222
|
+
capabilities: plugin.capabilities || {},
|
|
2223
|
+
channels: plugin.channels || ["default"],
|
|
2224
|
+
render: plugin.render && typeof plugin.render === "object" ? plugin.render : { mode: "react-native", component: plugin.name || plugin.id },
|
|
2225
|
+
entry_point: plugin.entry_point || plugin.name,
|
|
2226
|
+
sandbox: plugin.sandbox !== false,
|
|
2227
|
+
requires_auth: plugin.requires_auth !== false
|
|
2228
|
+
}
|
|
2229
|
+
}));
|
|
2230
|
+
setPlugins(uiPlugins);
|
|
2231
|
+
} catch (err) {
|
|
2232
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2233
|
+
console.error("[useRemotePlugins] Failed to fetch plugins:", message);
|
|
2234
|
+
setError(message);
|
|
2235
|
+
setPlugins([]);
|
|
2236
|
+
} finally {
|
|
2237
|
+
setLoading(false);
|
|
2238
|
+
setRefreshing(false);
|
|
2239
|
+
}
|
|
2240
|
+
}, [solutionId]);
|
|
2241
|
+
const refresh = (0, import_react12.useCallback)(async () => {
|
|
2242
|
+
setRefreshing(true);
|
|
2243
|
+
await fetchRemotePlugins();
|
|
2244
|
+
}, [fetchRemotePlugins]);
|
|
2290
2245
|
(0, import_react12.useEffect)(() => {
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2246
|
+
setLoading(true);
|
|
2247
|
+
fetchRemotePlugins();
|
|
2248
|
+
}, [fetchRemotePlugins]);
|
|
2249
|
+
return {
|
|
2250
|
+
plugins,
|
|
2251
|
+
loading,
|
|
2252
|
+
error,
|
|
2253
|
+
refreshing,
|
|
2254
|
+
refresh
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
// src/api/plugins.ts
|
|
2259
|
+
var import_core9 = require("@ateam-ai-mobile/core");
|
|
2260
|
+
var import_core10 = require("@ateam-ai-mobile/core");
|
|
2261
|
+
function supportsNative(manifest) {
|
|
2262
|
+
const mode = manifest.render?.mode;
|
|
2263
|
+
return mode === "react-native" || mode === "adaptive";
|
|
2264
|
+
}
|
|
2265
|
+
function getNativeComponentId(manifest) {
|
|
2266
|
+
if (manifest.render?.mode === "react-native") return manifest.render.component;
|
|
2267
|
+
if (manifest.render?.mode === "adaptive") return manifest.render.reactNative?.component;
|
|
2268
|
+
return null;
|
|
2269
|
+
}
|
|
2270
|
+
function getNativeBundleUrl(manifest) {
|
|
2271
|
+
const direct = manifest.bundleUrl;
|
|
2272
|
+
if (direct) return direct;
|
|
2273
|
+
const render = manifest.render;
|
|
2274
|
+
if (render.mode === "react-native") return render.bundleUrl || null;
|
|
2275
|
+
if (render.mode === "adaptive") return render.reactNative?.bundleUrl || null;
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
function getNativeBundleHash(manifest) {
|
|
2279
|
+
const direct = manifest.bundleHash;
|
|
2280
|
+
if (direct) return direct;
|
|
2281
|
+
const render = manifest.render;
|
|
2282
|
+
if (render.mode === "react-native") return render.bundleHash || null;
|
|
2283
|
+
if (render.mode === "adaptive") return render.reactNative?.bundleHash || null;
|
|
2284
|
+
return null;
|
|
2285
|
+
}
|
|
2286
|
+
function supportsWebView(manifest) {
|
|
2287
|
+
return manifest.render?.mode === "iframe" || manifest.render?.mode === "adaptive";
|
|
2288
|
+
}
|
|
2289
|
+
async function listPlugins() {
|
|
2290
|
+
const res = await (0, import_core9.apiFetch)("/mcp", {
|
|
2291
|
+
method: "POST",
|
|
2292
|
+
body: JSON.stringify({
|
|
2293
|
+
jsonrpc: "2.0",
|
|
2294
|
+
id: Date.now(),
|
|
2295
|
+
method: "tools/call",
|
|
2296
|
+
params: {
|
|
2297
|
+
name: "cp.listContextPlugins",
|
|
2298
|
+
arguments: {}
|
|
2296
2299
|
}
|
|
2297
|
-
})
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2300
|
+
})
|
|
2301
|
+
});
|
|
2302
|
+
const structured = res.result?.structuredContent?.plugins;
|
|
2303
|
+
if (structured) return structured;
|
|
2304
|
+
const text = res.result?.content?.[0]?.text;
|
|
2305
|
+
if (!text) return [];
|
|
2306
|
+
try {
|
|
2307
|
+
const parsed = JSON.parse(text);
|
|
2308
|
+
return parsed.plugins || parsed || [];
|
|
2309
|
+
} catch {
|
|
2310
|
+
return [];
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
async function getPlugin(pluginId) {
|
|
2314
|
+
const res = await (0, import_core9.apiFetch)("/mcp", {
|
|
2315
|
+
method: "POST",
|
|
2316
|
+
body: JSON.stringify({
|
|
2317
|
+
jsonrpc: "2.0",
|
|
2318
|
+
id: Date.now(),
|
|
2319
|
+
method: "tools/call",
|
|
2320
|
+
params: {
|
|
2321
|
+
name: "cp.getContextPlugin",
|
|
2322
|
+
arguments: { id: pluginId }
|
|
2323
|
+
// Backend expects { id }, NOT { pluginId }
|
|
2324
|
+
}
|
|
2325
|
+
})
|
|
2326
|
+
});
|
|
2327
|
+
if (res.result?.structuredContent) return res.result.structuredContent;
|
|
2328
|
+
const text = res.result?.content?.[0]?.text;
|
|
2329
|
+
if (!text) return null;
|
|
2330
|
+
try {
|
|
2331
|
+
const parsed = JSON.parse(text);
|
|
2332
|
+
if (parsed.error) {
|
|
2333
|
+
console.warn("[getPlugin] Backend error:", parsed.error);
|
|
2334
|
+
return null;
|
|
2335
|
+
}
|
|
2336
|
+
return parsed;
|
|
2337
|
+
} catch {
|
|
2338
|
+
return null;
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
function resolvePluginUrl(manifest, tenant) {
|
|
2342
|
+
const render = manifest.render;
|
|
2343
|
+
let url;
|
|
2344
|
+
if (render?.mode === "iframe") {
|
|
2345
|
+
url = render.iframeUrl;
|
|
2346
|
+
} else if (render?.mode === "adaptive") {
|
|
2347
|
+
url = render.iframeUrl || render.iframe?.iframeUrl;
|
|
2348
|
+
}
|
|
2349
|
+
if (!url) return "";
|
|
2350
|
+
if (url.startsWith("http")) {
|
|
2351
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
2352
|
+
return tenant ? `${url}${sep}tenant=${encodeURIComponent(tenant)}` : url;
|
|
2353
|
+
}
|
|
2354
|
+
if (tenant && url.startsWith("/mcp-ui/")) {
|
|
2355
|
+
const tenantUrl = url.replace("/mcp-ui/", `/mcp-ui/${encodeURIComponent(tenant)}/`);
|
|
2356
|
+
return `${(0, import_core10.getCoreApiUrl)()}${tenantUrl}`;
|
|
2357
|
+
}
|
|
2358
|
+
return `${(0, import_core10.getCoreApiUrl)()}${url}`;
|
|
2322
2359
|
}
|
|
2323
2360
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2324
2361
|
0 && (module.exports = {
|
|
@@ -2356,6 +2393,7 @@ function SurfaceDispatcher() {
|
|
|
2356
2393
|
View,
|
|
2357
2394
|
bundleManager,
|
|
2358
2395
|
createNativeBridge,
|
|
2396
|
+
gatePluginNative,
|
|
2359
2397
|
getHaptics,
|
|
2360
2398
|
getNativeBundleHash,
|
|
2361
2399
|
getNativeBundleUrl,
|