@elizaos/plugin-messages 2.0.3-beta.5 → 2.0.3-beta.7
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/components/MessagesAppView.d.ts +3 -0
- package/dist/components/MessagesAppView.d.ts.map +1 -0
- package/dist/components/MessagesAppView.helpers.d.ts +20 -0
- package/dist/components/MessagesAppView.helpers.d.ts.map +1 -0
- package/dist/components/MessagesAppView.helpers.js +56 -0
- package/dist/components/MessagesAppView.helpers.js.map +1 -0
- package/dist/components/MessagesAppView.interact.d.ts +2 -0
- package/dist/components/MessagesAppView.interact.d.ts.map +1 -0
- package/dist/components/MessagesAppView.interact.js +49 -0
- package/dist/components/MessagesAppView.interact.js.map +1 -0
- package/dist/components/MessagesAppView.js +642 -0
- package/dist/components/MessagesAppView.js.map +1 -0
- package/dist/components/MessagesSpatialView.d.ts +47 -0
- package/dist/components/MessagesSpatialView.d.ts.map +1 -0
- package/dist/components/MessagesSpatialView.js +152 -0
- package/dist/components/MessagesSpatialView.js.map +1 -0
- package/dist/components/MessagesView.d.ts +13 -0
- package/dist/components/MessagesView.d.ts.map +1 -0
- package/dist/components/MessagesView.js +144 -0
- package/dist/components/MessagesView.js.map +1 -0
- package/dist/components/messages-app.d.ts +5 -0
- package/dist/components/messages-app.d.ts.map +1 -0
- package/dist/components/messages-app.js +20 -0
- package/dist/components/messages-app.js.map +1 -0
- package/dist/components/messages-view-bundle.d.ts +3 -0
- package/dist/components/messages-view-bundle.d.ts.map +1 -0
- package/dist/components/messages-view-bundle.js +7 -0
- package/dist/components/messages-view-bundle.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +29 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +28 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +10 -0
- package/dist/register.js.map +1 -0
- package/dist/ui.d.ts +4 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +15 -0
- package/dist/ui.js.map +1 -0
- package/dist/views/bundle.js +338 -0
- package/dist/views/bundle.js.map +1 -0
- package/dist/views/dist-Cd2YtKy4.js +270 -0
- package/dist/views/dist-Cd2YtKy4.js.map +1 -0
- package/dist/views/web-BNoqOavR.js +90 -0
- package/dist/views/web-BNoqOavR.js.map +1 -0
- package/dist/views/web-DeLuzxfk.js +32 -0
- package/dist/views/web-DeLuzxfk.js.map +1 -0
- package/package.json +8 -8
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const appMessagesPlugin = {
|
|
2
|
+
name: "@elizaos/plugin-messages",
|
|
3
|
+
description: "Android Messages overlay: read SMS conversations and compose text messages through the native SMS bridge.",
|
|
4
|
+
views: [
|
|
5
|
+
// ONE declaration → GUI + XR + TUI, all drawn from the single MessagesView
|
|
6
|
+
// spatial source. `modalities` is a plain literal here (plugin.ts is not in
|
|
7
|
+
// the view bundle), so no brand-new `@elizaos/core` runtime export reaches
|
|
8
|
+
// the bundle build.
|
|
9
|
+
{
|
|
10
|
+
id: "messages",
|
|
11
|
+
label: "Messages",
|
|
12
|
+
description: "SMS conversations via the Android Messages bridge",
|
|
13
|
+
icon: "MessageSquare",
|
|
14
|
+
path: "/messages",
|
|
15
|
+
modalities: ["gui", "xr", "tui"],
|
|
16
|
+
bundlePath: "dist/views/bundle.js",
|
|
17
|
+
componentExport: "MessagesView",
|
|
18
|
+
tags: ["messaging", "sms", "android"],
|
|
19
|
+
visibleInManager: true,
|
|
20
|
+
desktopTabEnabled: true
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
var plugin_default = appMessagesPlugin;
|
|
25
|
+
export {
|
|
26
|
+
appMessagesPlugin,
|
|
27
|
+
plugin_default as default
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Plugin } from \"@elizaos/core\";\n\nexport const appMessagesPlugin: Plugin = {\n name: \"@elizaos/plugin-messages\",\n description:\n \"Android Messages overlay: read SMS conversations and compose text messages through the native SMS bridge.\",\n views: [\n // ONE declaration → GUI + XR + TUI, all drawn from the single MessagesView\n // spatial source. `modalities` is a plain literal here (plugin.ts is not in\n // the view bundle), so no brand-new `@elizaos/core` runtime export reaches\n // the bundle build.\n {\n id: \"messages\",\n label: \"Messages\",\n description: \"SMS conversations via the Android Messages bridge\",\n icon: \"MessageSquare\",\n path: \"/messages\",\n modalities: [\"gui\", \"xr\", \"tui\"],\n bundlePath: \"dist/views/bundle.js\",\n componentExport: \"MessagesView\",\n tags: [\"messaging\", \"sms\", \"android\"],\n visibleInManager: true,\n desktopTabEnabled: true,\n },\n ],\n};\n\nexport default appMessagesPlugin;\n"],"mappings":"AAEO,MAAM,oBAA4B;AAAA,EACvC,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,MACN,MAAM;AAAA,MACN,YAAY,CAAC,OAAO,MAAM,KAAK;AAAA,MAC/B,YAAY;AAAA,MACZ,iBAAiB;AAAA,MACjB,MAAM,CAAC,aAAa,OAAO,SAAS;AAAA,MACpC,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,IACrB;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the messages view for terminal rendering.
|
|
3
|
+
*
|
|
4
|
+
* The agent terminal mounts plugin views by id from the `@elizaos/tui` terminal
|
|
5
|
+
* registry. This makes the messages `viewType: "tui"` declaration render for
|
|
6
|
+
* real in the terminal (the unified {@link MessagesSpatialView}) rather than
|
|
7
|
+
* only navigating a GUI shell. A module-level snapshot lets a host push live SMS
|
|
8
|
+
* data; on a non-Android agent it defaults to an empty inbox with no SMS role.
|
|
9
|
+
*/
|
|
10
|
+
import { type MessagesSnapshot } from "./components/MessagesSpatialView.tsx";
|
|
11
|
+
/** Update the snapshot the registered terminal view renders from. */
|
|
12
|
+
export declare function setMessagesTerminalSnapshot(next: MessagesSnapshot): void;
|
|
13
|
+
/** Register the messages terminal view; returns an unregister function. */
|
|
14
|
+
export declare function registerMessagesTerminalView(): () => void;
|
|
15
|
+
//# sourceMappingURL=register-terminal-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-terminal-view.d.ts","sourceRoot":"","sources":["../src/register-terminal-view.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,sCAAsC,CAAC;AAY9C,qEAAqE;AACrE,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAExE;AAED,2EAA2E;AAC3E,wBAAgB,4BAA4B,IAAI,MAAM,IAAI,CAIzD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { registerSpatialTerminalView } from "@elizaos/ui/spatial/tui";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import {
|
|
4
|
+
MessagesSpatialView
|
|
5
|
+
} from "./components/MessagesSpatialView.js";
|
|
6
|
+
const EMPTY = {
|
|
7
|
+
threads: [],
|
|
8
|
+
selectedThreadId: null,
|
|
9
|
+
composeAddress: "",
|
|
10
|
+
composeBody: "",
|
|
11
|
+
ownsSmsRole: false,
|
|
12
|
+
smsRoleHolder: null
|
|
13
|
+
};
|
|
14
|
+
let current = EMPTY;
|
|
15
|
+
function setMessagesTerminalSnapshot(next) {
|
|
16
|
+
current = next;
|
|
17
|
+
}
|
|
18
|
+
function registerMessagesTerminalView() {
|
|
19
|
+
return registerSpatialTerminalView(
|
|
20
|
+
"messages",
|
|
21
|
+
() => createElement(MessagesSpatialView, { snapshot: current })
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
registerMessagesTerminalView,
|
|
26
|
+
setMessagesTerminalSnapshot
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=register-terminal-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/register-terminal-view.tsx"],"sourcesContent":["/**\n * Register the messages view for terminal rendering.\n *\n * The agent terminal mounts plugin views by id from the `@elizaos/tui` terminal\n * registry. This makes the messages `viewType: \"tui\"` declaration render for\n * real in the terminal (the unified {@link MessagesSpatialView}) rather than\n * only navigating a GUI shell. A module-level snapshot lets a host push live SMS\n * data; on a non-Android agent it defaults to an empty inbox with no SMS role.\n */\n\nimport { registerSpatialTerminalView } from \"@elizaos/ui/spatial/tui\";\nimport { createElement } from \"react\";\nimport {\n type MessagesSnapshot,\n MessagesSpatialView,\n} from \"./components/MessagesSpatialView.js\";\n\nconst EMPTY: MessagesSnapshot = {\n threads: [],\n selectedThreadId: null,\n composeAddress: \"\",\n composeBody: \"\",\n ownsSmsRole: false,\n smsRoleHolder: null,\n};\nlet current: MessagesSnapshot = EMPTY;\n\n/** Update the snapshot the registered terminal view renders from. */\nexport function setMessagesTerminalSnapshot(next: MessagesSnapshot): void {\n current = next;\n}\n\n/** Register the messages terminal view; returns an unregister function. */\nexport function registerMessagesTerminalView(): () => void {\n return registerSpatialTerminalView(\"messages\", () =>\n createElement(MessagesSpatialView, { snapshot: current }),\n );\n}\n"],"mappings":"AAUA,SAAS,mCAAmC;AAC5C,SAAS,qBAAqB;AAC9B;AAAA,EAEE;AAAA,OACK;AAEP,MAAM,QAA0B;AAAA,EAC9B,SAAS,CAAC;AAAA,EACV,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,aAAa;AAAA,EACb,eAAe;AACjB;AACA,IAAI,UAA4B;AAGzB,SAAS,4BAA4B,MAA8B;AACxE,YAAU;AACZ;AAGO,SAAS,+BAA2C;AACzD,SAAO;AAAA,IAA4B;AAAA,IAAY,MAC7C,cAAc,qBAAqB,EAAE,UAAU,QAAQ,CAAC;AAAA,EAC1D;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":""}
|
package/dist/register.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isElizaOS } from "@elizaos/ui";
|
|
2
|
+
import { registerMessagesApp } from "./components/messages-app.js";
|
|
3
|
+
if (isElizaOS()) {
|
|
4
|
+
registerMessagesApp();
|
|
5
|
+
}
|
|
6
|
+
if (typeof window === "undefined") {
|
|
7
|
+
void import("./register-terminal-view.js").then((m) => m.registerMessagesTerminalView()).catch(() => {
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/register.ts"],"sourcesContent":["import { isElizaOS } from \"@elizaos/ui\";\nimport { registerMessagesApp } from \"./components/messages-app.js\";\n\nif (isElizaOS()) {\n registerMessagesApp();\n}\n\n// In a terminal host (the Node agent, no DOM), register the messages view so it\n// renders inline in the terminal. Lazy + DOM-guarded so the terminal engine\n// stays out of browser/mobile bundles.\nif (typeof window === \"undefined\") {\n void import(\"./register-terminal-view.js\")\n .then((m) => m.registerMessagesTerminalView())\n .catch(() => {\n // Terminal rendering is best-effort; never block plugin load.\n });\n}\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,2BAA2B;AAEpC,IAAI,UAAU,GAAG;AACf,sBAAoB;AACtB;AAKA,IAAI,OAAO,WAAW,aAAa;AACjC,OAAK,OAAO,6BAA6B,EACtC,KAAK,CAAC,MAAM,EAAE,6BAA6B,CAAC,EAC5C,MAAM,MAAM;AAAA,EAEb,CAAC;AACL;","names":[]}
|
package/dist/ui.d.ts
ADDED
package/dist/ui.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,mBAAmB,GACpB,MAAM,8BAA8B,CAAC"}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MessagesAppView } from "./components/MessagesAppView.js";
|
|
2
|
+
import { MessagesView } from "./components/MessagesView.js";
|
|
3
|
+
import {
|
|
4
|
+
MESSAGES_APP_NAME,
|
|
5
|
+
messagesApp,
|
|
6
|
+
registerMessagesApp
|
|
7
|
+
} from "./components/messages-app.js";
|
|
8
|
+
export {
|
|
9
|
+
MESSAGES_APP_NAME,
|
|
10
|
+
MessagesAppView,
|
|
11
|
+
MessagesView,
|
|
12
|
+
messagesApp,
|
|
13
|
+
registerMessagesApp
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui.ts"],"sourcesContent":["export { MessagesAppView } from \"./components/MessagesAppView.js\";\nexport { MessagesView } from \"./components/MessagesView.js\";\nexport {\n MESSAGES_APP_NAME,\n messagesApp,\n registerMessagesApp,\n} from \"./components/messages-app.js\";\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { n as e } from "./dist-Cd2YtKy4.js";
|
|
2
|
+
import { consumePendingMessageRecipient as t } from "@elizaos/ui/app-navigate-view";
|
|
3
|
+
import { Button as n, Card as r, Divider as i, Field as a, HStack as o, List as s, SpatialSurface as c, Text as l, VStack as u } from "@elizaos/ui/spatial";
|
|
4
|
+
import { useCallback as d, useEffect as f, useMemo as p, useRef as m, useState as h } from "react";
|
|
5
|
+
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
6
|
+
var v = e("ElizaMessages", { web: () => import("./web-DeLuzxfk.js").then((e) => new e.MessagesWeb()) }), y = e("ElizaSystem", { web: () => import("./web-BNoqOavR.js").then((e) => new e.SystemWeb()) }), b = 1;
|
|
7
|
+
function x(e) {
|
|
8
|
+
let t = /* @__PURE__ */ new Map();
|
|
9
|
+
for (let n of e) {
|
|
10
|
+
let e = n.threadId || n.address || n.id, r = t.get(e) ?? [];
|
|
11
|
+
r.push(n), t.set(e, r);
|
|
12
|
+
}
|
|
13
|
+
return Array.from(t.entries()).map(([e, t]) => {
|
|
14
|
+
let n = [...t].sort((e, t) => e.date - t.date), r = n[n.length - 1] ?? t[0];
|
|
15
|
+
return {
|
|
16
|
+
id: e,
|
|
17
|
+
address: r?.address,
|
|
18
|
+
messages: n,
|
|
19
|
+
lastMessage: r,
|
|
20
|
+
unreadCount: n.filter((e) => !e.read && e.type === b).length
|
|
21
|
+
};
|
|
22
|
+
}).filter((e) => !!e.lastMessage).sort((e, t) => t.lastMessage.date - e.lastMessage.date);
|
|
23
|
+
}
|
|
24
|
+
function S(e) {
|
|
25
|
+
return e?.roles.find((e) => e.role === "sms") ?? null;
|
|
26
|
+
}
|
|
27
|
+
function C(e, t = 200) {
|
|
28
|
+
return typeof e != "number" || !Number.isFinite(e) ? t : Math.min(500, Math.max(1, Math.trunc(e)));
|
|
29
|
+
}
|
|
30
|
+
async function w(e = 200) {
|
|
31
|
+
let [t, n] = await Promise.all([v.listMessages({ limit: C(e) }), y.getStatus().catch(() => null)]), r = x(t.messages), i = S(n);
|
|
32
|
+
return {
|
|
33
|
+
messages: t.messages,
|
|
34
|
+
threads: r,
|
|
35
|
+
systemStatus: n,
|
|
36
|
+
ownsSmsRole: i?.held === !0,
|
|
37
|
+
smsRoleHolder: i?.holders[0] ?? null
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/components/MessagesAppView.interact.ts
|
|
42
|
+
async function T(e, t) {
|
|
43
|
+
if (e === "terminal-list-threads") {
|
|
44
|
+
let e = await w(C(t?.limit));
|
|
45
|
+
return {
|
|
46
|
+
viewType: "tui",
|
|
47
|
+
threads: e.threads.map((e) => ({
|
|
48
|
+
id: e.id,
|
|
49
|
+
address: e.address,
|
|
50
|
+
messageCount: e.messages.length,
|
|
51
|
+
unreadCount: e.unreadCount,
|
|
52
|
+
lastMessage: e.lastMessage.body,
|
|
53
|
+
lastMessageAt: e.lastMessage.date
|
|
54
|
+
})),
|
|
55
|
+
ownsSmsRole: e.ownsSmsRole,
|
|
56
|
+
smsRoleHolder: e.smsRoleHolder
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (e === "terminal-send-sms") {
|
|
60
|
+
let e = typeof t?.address == "string" ? t.address.trim() : "", n = typeof t?.body == "string" ? t.body.trim() : "";
|
|
61
|
+
if (!e) throw Error("address is required");
|
|
62
|
+
if (!n) throw Error("body is required");
|
|
63
|
+
return await v.sendSms({
|
|
64
|
+
address: e,
|
|
65
|
+
body: n
|
|
66
|
+
}), {
|
|
67
|
+
sent: !0,
|
|
68
|
+
address: e,
|
|
69
|
+
bodyLength: n.length,
|
|
70
|
+
viewType: "tui"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (e === "terminal-request-sms-role") {
|
|
74
|
+
await y.requestRole({ role: "sms" });
|
|
75
|
+
let e = await w(200);
|
|
76
|
+
return {
|
|
77
|
+
requested: !0,
|
|
78
|
+
ownsSmsRole: e.ownsSmsRole,
|
|
79
|
+
smsRoleHolder: e.smsRoleHolder,
|
|
80
|
+
viewType: "tui"
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
throw Error(`Unsupported capability "${e}"`);
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/components/MessagesSpatialView.tsx
|
|
87
|
+
var E = 2;
|
|
88
|
+
function D(e) {
|
|
89
|
+
return e === E ? "out" : "in";
|
|
90
|
+
}
|
|
91
|
+
function O(e) {
|
|
92
|
+
return D(e) === "out" ? ">" : "<";
|
|
93
|
+
}
|
|
94
|
+
function k(e) {
|
|
95
|
+
return D(e) === "out" ? "primary" : "default";
|
|
96
|
+
}
|
|
97
|
+
function A(e) {
|
|
98
|
+
return e.ownsSmsRole ? "sms-default" : e.smsRoleHolder ? `bridge:${e.smsRoleHolder}` : "bridge-only";
|
|
99
|
+
}
|
|
100
|
+
function j(e) {
|
|
101
|
+
return e.ownsSmsRole ? "success" : "warning";
|
|
102
|
+
}
|
|
103
|
+
function M({ snapshot: e, onAction: t }) {
|
|
104
|
+
let c = (e) => () => t?.(e), d = e.threads.find((t) => t.id === e.selectedThreadId) ?? null, f = e.composeAddress.trim().length > 0 && e.composeBody.trim().length > 0;
|
|
105
|
+
return /* @__PURE__ */ _(r, {
|
|
106
|
+
gap: 1,
|
|
107
|
+
padding: 1,
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ _(o, {
|
|
110
|
+
gap: 1,
|
|
111
|
+
align: "center",
|
|
112
|
+
children: [/* @__PURE__ */ g(l, {
|
|
113
|
+
style: "caption",
|
|
114
|
+
tone: j(e),
|
|
115
|
+
grow: 1,
|
|
116
|
+
children: A(e)
|
|
117
|
+
}), /* @__PURE__ */ g(l, {
|
|
118
|
+
style: "caption",
|
|
119
|
+
tone: "muted",
|
|
120
|
+
children: e.loading ? "loading" : `${e.threads.length} threads`
|
|
121
|
+
})]
|
|
122
|
+
}),
|
|
123
|
+
e.error ? /* @__PURE__ */ g(l, {
|
|
124
|
+
tone: "danger",
|
|
125
|
+
style: "caption",
|
|
126
|
+
children: e.error
|
|
127
|
+
}) : null,
|
|
128
|
+
e.ownsSmsRole ? null : /* @__PURE__ */ g(n, {
|
|
129
|
+
variant: "outline",
|
|
130
|
+
tone: "warning",
|
|
131
|
+
agent: "request-sms-role",
|
|
132
|
+
onPress: c("request-sms-role"),
|
|
133
|
+
children: "Set default SMS"
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ g(i, { label: "threads" }),
|
|
136
|
+
e.threads.length === 0 ? /* @__PURE__ */ g(l, {
|
|
137
|
+
tone: "muted",
|
|
138
|
+
align: "center",
|
|
139
|
+
style: "caption",
|
|
140
|
+
children: "None"
|
|
141
|
+
}) : /* @__PURE__ */ g(s, {
|
|
142
|
+
gap: 0,
|
|
143
|
+
children: e.threads.slice(0, 8).map((t) => {
|
|
144
|
+
let r = t.id === e.selectedThreadId;
|
|
145
|
+
return /* @__PURE__ */ _(o, {
|
|
146
|
+
gap: 1,
|
|
147
|
+
align: "center",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ g(l, {
|
|
150
|
+
tone: k(t.lastMessage.type),
|
|
151
|
+
children: O(t.lastMessage.type)
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ _(u, {
|
|
154
|
+
gap: 0,
|
|
155
|
+
grow: 1,
|
|
156
|
+
children: [/* @__PURE__ */ g(l, {
|
|
157
|
+
bold: !0,
|
|
158
|
+
wrap: !1,
|
|
159
|
+
children: t.address || "Unknown"
|
|
160
|
+
}), /* @__PURE__ */ g(l, {
|
|
161
|
+
style: "caption",
|
|
162
|
+
tone: "muted",
|
|
163
|
+
wrap: !1,
|
|
164
|
+
children: t.lastMessage.body
|
|
165
|
+
})]
|
|
166
|
+
}),
|
|
167
|
+
t.unreadCount > 0 ? /* @__PURE__ */ g(l, {
|
|
168
|
+
style: "caption",
|
|
169
|
+
tone: "primary",
|
|
170
|
+
children: String(t.unreadCount)
|
|
171
|
+
}) : null,
|
|
172
|
+
/* @__PURE__ */ g(n, {
|
|
173
|
+
variant: r ? "solid" : "ghost",
|
|
174
|
+
tone: "primary",
|
|
175
|
+
agent: `open-thread-${t.id}`,
|
|
176
|
+
onPress: c(`open-thread:${t.id}`),
|
|
177
|
+
children: "Open"
|
|
178
|
+
})
|
|
179
|
+
]
|
|
180
|
+
}, t.id);
|
|
181
|
+
})
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ g(i, { label: d ? d.address : "compose" }),
|
|
184
|
+
d ? /* @__PURE__ */ g(s, {
|
|
185
|
+
gap: 0,
|
|
186
|
+
children: d.messages.slice(-6).map((e) => /* @__PURE__ */ _(o, {
|
|
187
|
+
gap: 1,
|
|
188
|
+
align: "start",
|
|
189
|
+
children: [/* @__PURE__ */ g(l, {
|
|
190
|
+
tone: k(e.type),
|
|
191
|
+
style: "caption",
|
|
192
|
+
children: D(e.type)
|
|
193
|
+
}), /* @__PURE__ */ g(l, {
|
|
194
|
+
grow: 1,
|
|
195
|
+
children: e.body
|
|
196
|
+
})]
|
|
197
|
+
}, e.id))
|
|
198
|
+
}) : null,
|
|
199
|
+
/* @__PURE__ */ g(a, {
|
|
200
|
+
label: "To",
|
|
201
|
+
value: e.composeAddress,
|
|
202
|
+
placeholder: "phone number",
|
|
203
|
+
agent: "compose-address",
|
|
204
|
+
onChange: (e) => t?.(`compose-address:${e}`)
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ g(a, {
|
|
207
|
+
label: "Body",
|
|
208
|
+
kind: "textarea",
|
|
209
|
+
value: e.composeBody,
|
|
210
|
+
placeholder: "message",
|
|
211
|
+
agent: "compose-body",
|
|
212
|
+
onChange: (e) => t?.(`compose-body:${e}`)
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ _(o, {
|
|
215
|
+
gap: 1,
|
|
216
|
+
wrap: !0,
|
|
217
|
+
children: [/* @__PURE__ */ g(n, {
|
|
218
|
+
grow: 1,
|
|
219
|
+
disabled: !f,
|
|
220
|
+
agent: "send",
|
|
221
|
+
onPress: c("send"),
|
|
222
|
+
children: "Send"
|
|
223
|
+
}), /* @__PURE__ */ g(n, {
|
|
224
|
+
variant: "outline",
|
|
225
|
+
tone: "default",
|
|
226
|
+
agent: "refresh",
|
|
227
|
+
onPress: c("refresh"),
|
|
228
|
+
children: "Refresh"
|
|
229
|
+
})]
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/components/MessagesView.tsx
|
|
236
|
+
function N() {
|
|
237
|
+
let [e, n] = h([]), [r, i] = h(null), [a, o] = h(null), [s, l] = h(""), [u, _] = h(""), [b, C] = h(!1), [w, T] = h(!1), [E, D] = h(null), O = d(async () => {
|
|
238
|
+
C(!0), D(null);
|
|
239
|
+
try {
|
|
240
|
+
i(await y.getStatus().catch(() => null));
|
|
241
|
+
let e = await v.requestPermissions().catch(() => null);
|
|
242
|
+
if (e && e.sms !== "granted") {
|
|
243
|
+
n([]), D("SMS access is needed to read and send messages. Grant it in your device settings, then retry.");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
n((await v.listMessages({ limit: 200 })).messages);
|
|
247
|
+
} catch (e) {
|
|
248
|
+
D(e instanceof Error ? e.message : String(e)), n([]);
|
|
249
|
+
} finally {
|
|
250
|
+
C(!1);
|
|
251
|
+
}
|
|
252
|
+
}, []), k = m(!1);
|
|
253
|
+
f(() => {
|
|
254
|
+
k.current || (k.current = !0, O());
|
|
255
|
+
let e = setInterval(() => void O(), 2e4);
|
|
256
|
+
return () => clearInterval(e);
|
|
257
|
+
}, [O]), f(() => {
|
|
258
|
+
let e = t();
|
|
259
|
+
e && (o(null), l(e), _(""), D(null));
|
|
260
|
+
}, []);
|
|
261
|
+
let A = p(() => x(e), [e]), j = S(r), N = j?.held === !0, P = j?.holders[0] ?? null, F = d((e) => {
|
|
262
|
+
let t = A.find((t) => t.id === e);
|
|
263
|
+
t && (o(t.id), l(t.address), D(null));
|
|
264
|
+
}, [A]), I = d(async () => {
|
|
265
|
+
D(null);
|
|
266
|
+
try {
|
|
267
|
+
await y.requestRole({ role: "sms" }), i(await y.getStatus());
|
|
268
|
+
} catch (e) {
|
|
269
|
+
D(e instanceof Error ? e.message : String(e));
|
|
270
|
+
}
|
|
271
|
+
}, []), L = d(async () => {
|
|
272
|
+
let e = s.trim(), t = u.trim();
|
|
273
|
+
if (!(!e || !t || w)) {
|
|
274
|
+
T(!0), D(null);
|
|
275
|
+
try {
|
|
276
|
+
await v.sendSms({
|
|
277
|
+
address: e,
|
|
278
|
+
body: t
|
|
279
|
+
}), _(""), await O();
|
|
280
|
+
} catch (e) {
|
|
281
|
+
D(e instanceof Error ? e.message : String(e));
|
|
282
|
+
} finally {
|
|
283
|
+
T(!1);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}, [
|
|
287
|
+
s,
|
|
288
|
+
u,
|
|
289
|
+
O,
|
|
290
|
+
w
|
|
291
|
+
]), R = d((e) => {
|
|
292
|
+
if (e.startsWith("open-thread:")) {
|
|
293
|
+
F(e.slice(12));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (e.startsWith("compose-address:")) {
|
|
297
|
+
l(e.slice(16));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (e.startsWith("compose-body:")) {
|
|
301
|
+
_(e.slice(13));
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
switch (e) {
|
|
305
|
+
case "send":
|
|
306
|
+
L();
|
|
307
|
+
return;
|
|
308
|
+
case "request-sms-role":
|
|
309
|
+
I();
|
|
310
|
+
return;
|
|
311
|
+
case "refresh":
|
|
312
|
+
O();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
}, [
|
|
316
|
+
F,
|
|
317
|
+
O,
|
|
318
|
+
I,
|
|
319
|
+
L
|
|
320
|
+
]);
|
|
321
|
+
return /* @__PURE__ */ g(c, { children: /* @__PURE__ */ g(M, {
|
|
322
|
+
snapshot: {
|
|
323
|
+
threads: A,
|
|
324
|
+
selectedThreadId: a,
|
|
325
|
+
composeAddress: s,
|
|
326
|
+
composeBody: u,
|
|
327
|
+
ownsSmsRole: N,
|
|
328
|
+
smsRoleHolder: P,
|
|
329
|
+
loading: b,
|
|
330
|
+
error: E
|
|
331
|
+
},
|
|
332
|
+
onAction: R
|
|
333
|
+
}) });
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
export { N as MessagesView, T as interact };
|
|
337
|
+
|
|
338
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","names":["loadWeb"],"sources":["../../../plugin-native-messages/dist/esm/index.js","../../../plugin-native-system/dist/esm/index.js","../../src/components/MessagesAppView.helpers.ts","../../src/components/MessagesAppView.interact.ts","../../src/components/MessagesSpatialView.tsx","../../src/components/MessagesView.tsx"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.MessagesWeb());\nexport const Messages = registerPlugin(\"ElizaMessages\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.SystemWeb());\nexport const System = registerPlugin(\"ElizaSystem\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","// Pure SMS data helpers shared between MessagesAppView.tsx (the React views) and\n// MessagesAppView.interact.ts (the terminal capability handler). Split out so the\n// .tsx file exports only React components and stays Fast-Refresh-compatible\n// (Vite full-reloads a component file that also exports plain functions/types).\n\nimport type { SmsMessageSummary } from \"@elizaos/capacitor-messages\";\nimport { Messages } from \"@elizaos/capacitor-messages\";\nimport {\n type AndroidRoleStatus,\n System,\n type SystemStatus,\n} from \"@elizaos/capacitor-system\";\n\nexport type ThreadSummary = {\n id: string;\n address: string;\n messages: SmsMessageSummary[];\n lastMessage: SmsMessageSummary;\n unreadCount: number;\n};\n\nconst INBOUND_SMS_TYPE = 1;\n\nexport function buildThreads(messages: SmsMessageSummary[]): ThreadSummary[] {\n const byThread = new Map<string, SmsMessageSummary[]>();\n for (const message of messages) {\n const key = message.threadId || message.address || message.id;\n const list = byThread.get(key) ?? [];\n list.push(message);\n byThread.set(key, list);\n }\n return Array.from(byThread.entries())\n .map(([id, threadMessages]) => {\n const sorted = [...threadMessages].sort((a, b) => a.date - b.date);\n const lastMessage = sorted[sorted.length - 1] ?? threadMessages[0];\n return {\n id,\n address: lastMessage?.address,\n messages: sorted,\n lastMessage,\n unreadCount: sorted.filter(\n (m) => !m.read && m.type === INBOUND_SMS_TYPE,\n ).length,\n };\n })\n .filter((thread): thread is ThreadSummary => Boolean(thread.lastMessage))\n .sort((a, b) => b.lastMessage.date - a.lastMessage.date);\n}\n\nexport function smsRole(status: SystemStatus | null) {\n return (\n status?.roles.find((role: AndroidRoleStatus) => role.role === \"sms\") ?? null\n );\n}\n\nexport function normalizeMessagesLimit(value: unknown, fallback = 200): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return Math.min(500, Math.max(1, Math.trunc(value)));\n}\n\nexport async function loadMessagesState(limit = 200) {\n const [messageResult, statusResult] = await Promise.all([\n Messages.listMessages({ limit: normalizeMessagesLimit(limit) }),\n System.getStatus().catch(() => null),\n ]);\n const threads = buildThreads(messageResult.messages);\n const currentSmsRole = smsRole(statusResult);\n return {\n messages: messageResult.messages,\n threads,\n systemStatus: statusResult,\n ownsSmsRole: currentSmsRole?.held === true,\n smsRoleHolder: currentSmsRole?.holders[0] ?? null,\n };\n}\n","// View-bundle `interact` capability handler, split out of MessagesAppView.tsx so\n// that file exports only React components and stays Fast-Refresh-compatible\n// (Vite would full-reload a component file that also exports a plain function).\n// The view bundle re-exports `interact` via ./messages-view-bundle.ts.\n\nimport { Messages } from \"@elizaos/capacitor-messages\";\nimport { System } from \"@elizaos/capacitor-system\";\nimport {\n loadMessagesState,\n normalizeMessagesLimit,\n} from \"./MessagesAppView.helpers.ts\";\n\nexport async function interact(\n capability: string,\n params?: Record<string, unknown>,\n): Promise<unknown> {\n if (capability === \"terminal-list-threads\") {\n const state = await loadMessagesState(\n normalizeMessagesLimit(params?.limit),\n );\n return {\n viewType: \"tui\",\n threads: state.threads.map((thread) => ({\n id: thread.id,\n address: thread.address,\n messageCount: thread.messages.length,\n unreadCount: thread.unreadCount,\n lastMessage: thread.lastMessage.body,\n lastMessageAt: thread.lastMessage.date,\n })),\n ownsSmsRole: state.ownsSmsRole,\n smsRoleHolder: state.smsRoleHolder,\n };\n }\n\n if (capability === \"terminal-send-sms\") {\n const address =\n typeof params?.address === \"string\" ? params.address.trim() : \"\";\n const body = typeof params?.body === \"string\" ? params.body.trim() : \"\";\n if (!address) throw new Error(\"address is required\");\n if (!body) throw new Error(\"body is required\");\n await Messages.sendSms({ address, body });\n return { sent: true, address, bodyLength: body.length, viewType: \"tui\" };\n }\n\n if (capability === \"terminal-request-sms-role\") {\n await System.requestRole({ role: \"sms\" });\n const state = await loadMessagesState(200);\n return {\n requested: true,\n ownsSmsRole: state.ownsSmsRole,\n smsRoleHolder: state.smsRoleHolder,\n viewType: \"tui\",\n };\n }\n\n throw new Error(`Unsupported capability \"${capability}\"`);\n}\n","/**\n * MessagesSpatialView - the SMS messaging surface authored once with the\n * spatial vocabulary, so it renders correctly wherever it is displayed:\n *\n * - GUI / XR - mounted in `<SpatialSurface>` (DOM; XR scales up).\n * - TUI - rendered to real terminal lines by the agent terminal, via\n * `registerSpatialTerminalView` (see `register-terminal-view.tsx`).\n *\n * It is purely presentational (a snapshot + an action callback in, primitives\n * out) and imports only the cross-modality primitives plus a type-only view of\n * the native SMS summary, so it is safe to render in the Node agent process\n * where the terminal lives (no Capacitor runtime import).\n */\n\nimport type { SmsMessageSummary } from \"@elizaos/capacitor-messages\";\nimport {\n Button,\n Card,\n Divider,\n Field,\n HStack,\n List,\n type SpatialTone,\n Text,\n VStack,\n} from \"@elizaos/ui/spatial\";\n\nconst INBOUND_SMS_TYPE = 1;\nconst SENT_SMS_TYPE = 2;\n\n/** A grouped SMS conversation, sorted with its newest message last. */\nexport interface MessagesThreadSummary {\n id: string;\n address: string;\n messages: SmsMessageSummary[];\n lastMessage: SmsMessageSummary;\n unreadCount: number;\n}\n\nexport interface MessagesSnapshot {\n threads: MessagesThreadSummary[];\n selectedThreadId: string | null;\n composeAddress: string;\n composeBody: string;\n /** This device holds the Android default-SMS role (full inbox). */\n ownsSmsRole: boolean;\n /** When not held, the package name of whichever app holds the role. */\n smsRoleHolder: string | null;\n loading?: boolean;\n error?: string | null;\n}\n\n/** in/out marker for a single message, by Android SMS type discriminant. */\nfunction messageDirection(type: number): \"in\" | \"out\" {\n return type === SENT_SMS_TYPE ? \"out\" : \"in\";\n}\n\nfunction directionMark(type: number): string {\n return messageDirection(type) === \"out\" ? \">\" : \"<\";\n}\n\nfunction directionTone(type: number): SpatialTone {\n return messageDirection(type) === \"out\" ? \"primary\" : \"default\";\n}\n\nfunction roleLabel(snapshot: MessagesSnapshot): string {\n if (snapshot.ownsSmsRole) return \"sms-default\";\n if (snapshot.smsRoleHolder) return `bridge:${snapshot.smsRoleHolder}`;\n return \"bridge-only\";\n}\n\nfunction roleTone(snapshot: MessagesSnapshot): SpatialTone {\n return snapshot.ownsSmsRole ? \"success\" : \"warning\";\n}\n\nexport interface MessagesSpatialViewProps {\n snapshot: MessagesSnapshot;\n /**\n * Dispatched action ids: `open-thread:<id>` (open a conversation), `send`,\n * `request-sms-role`, `refresh`, `compose-address:<value>`,\n * `compose-body:<value>`.\n */\n onAction?: (action: string) => void;\n}\n\nexport function MessagesSpatialView({\n snapshot,\n onAction,\n}: MessagesSpatialViewProps) {\n const dispatch = (action: string) => () => onAction?.(action);\n const selectedThread =\n snapshot.threads.find((t) => t.id === snapshot.selectedThreadId) ?? null;\n const canSend =\n snapshot.composeAddress.trim().length > 0 &&\n snapshot.composeBody.trim().length > 0;\n\n return (\n <Card gap={1} padding={1}>\n <HStack gap={1} align=\"center\">\n <Text style=\"caption\" tone={roleTone(snapshot)} grow={1}>\n {roleLabel(snapshot)}\n </Text>\n <Text style=\"caption\" tone=\"muted\">\n {snapshot.loading ? \"loading\" : `${snapshot.threads.length} threads`}\n </Text>\n </HStack>\n\n {snapshot.error ? (\n <Text tone=\"danger\" style=\"caption\">\n {snapshot.error}\n </Text>\n ) : null}\n\n {!snapshot.ownsSmsRole ? (\n <Button\n variant=\"outline\"\n tone=\"warning\"\n agent=\"request-sms-role\"\n onPress={dispatch(\"request-sms-role\")}\n >\n Set default SMS\n </Button>\n ) : null}\n\n <Divider label=\"threads\" />\n {snapshot.threads.length === 0 ? (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {snapshot.threads.slice(0, 8).map((thread) => {\n const selected = thread.id === snapshot.selectedThreadId;\n return (\n <HStack key={thread.id} gap={1} align=\"center\">\n <Text tone={directionTone(thread.lastMessage.type)}>\n {directionMark(thread.lastMessage.type)}\n </Text>\n <VStack gap={0} grow={1}>\n <Text bold wrap={false}>\n {thread.address || \"Unknown\"}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {thread.lastMessage.body}\n </Text>\n </VStack>\n {thread.unreadCount > 0 ? (\n <Text style=\"caption\" tone=\"primary\">\n {String(thread.unreadCount)}\n </Text>\n ) : null}\n <Button\n variant={selected ? \"solid\" : \"ghost\"}\n tone=\"primary\"\n agent={`open-thread-${thread.id}`}\n onPress={dispatch(`open-thread:${thread.id}`)}\n >\n Open\n </Button>\n </HStack>\n );\n })}\n </List>\n )}\n\n <Divider label={selectedThread ? selectedThread.address : \"compose\"} />\n {selectedThread ? (\n <List gap={0}>\n {selectedThread.messages.slice(-6).map((message) => (\n <HStack key={message.id} gap={1} align=\"start\">\n <Text tone={directionTone(message.type)} style=\"caption\">\n {messageDirection(message.type)}\n </Text>\n <Text grow={1}>{message.body}</Text>\n </HStack>\n ))}\n </List>\n ) : null}\n\n <Field\n label=\"To\"\n value={snapshot.composeAddress}\n placeholder=\"phone number\"\n agent=\"compose-address\"\n onChange={(value) => onAction?.(`compose-address:${value}`)}\n />\n <Field\n label=\"Body\"\n kind=\"textarea\"\n value={snapshot.composeBody}\n placeholder=\"message\"\n agent=\"compose-body\"\n onChange={(value) => onAction?.(`compose-body:${value}`)}\n />\n <HStack gap={1} wrap>\n <Button\n grow={1}\n disabled={!canSend}\n agent=\"send\"\n onPress={dispatch(\"send\")}\n >\n Send\n </Button>\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent=\"refresh\"\n onPress={dispatch(\"refresh\")}\n >\n Refresh\n </Button>\n </HStack>\n </Card>\n );\n}\n\n/** Group a flat SMS list into threads, newest-last per thread, newest first. */\nexport function buildMessagesThreads(\n messages: SmsMessageSummary[],\n): MessagesThreadSummary[] {\n const byThread = new Map<string, SmsMessageSummary[]>();\n for (const message of messages) {\n const key = message.threadId || message.address || message.id;\n const list = byThread.get(key) ?? [];\n list.push(message);\n byThread.set(key, list);\n }\n return Array.from(byThread.entries())\n .map(([id, threadMessages]) => {\n const sorted = [...threadMessages].sort((a, b) => a.date - b.date);\n const lastMessage = sorted[sorted.length - 1];\n return {\n id,\n address: lastMessage.address,\n messages: sorted,\n lastMessage,\n unreadCount: sorted.filter(\n (m) => !m.read && m.type === INBOUND_SMS_TYPE,\n ).length,\n };\n })\n .sort((a, b) => b.lastMessage.date - a.lastMessage.date);\n}\n","/**\n * MessagesView — the single GUI/XR data wrapper for the Messages surface.\n *\n * It owns the live Android SMS data (inbox fetch, default-SMS role status,\n * compose state, pending-recipient handoff, send / request-role actions) and\n * renders the one presentational {@link MessagesSpatialView} inside a\n * {@link SpatialSurface}. Omitting the `modality` prop lets `SpatialSurface`\n * auto-detect GUI vs XR via `window.__elizaXRContext`, so the SAME component\n * serves both surfaces. The TUI surface renders the same `MessagesSpatialView`\n * through the terminal registry (see `register-terminal-view.tsx`).\n */\n\nimport type { SmsMessageSummary } from \"@elizaos/capacitor-messages\";\nimport { Messages } from \"@elizaos/capacitor-messages\";\nimport { System, type SystemStatus } from \"@elizaos/capacitor-system\";\nimport { consumePendingMessageRecipient } from \"@elizaos/ui/app-navigate-view\";\nimport { SpatialSurface } from \"@elizaos/ui/spatial\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { buildThreads, smsRole } from \"./MessagesAppView.helpers.ts\";\nimport {\n type MessagesSnapshot,\n MessagesSpatialView,\n} from \"./MessagesSpatialView.tsx\";\n\nexport function MessagesView() {\n const [messages, setMessages] = useState<SmsMessageSummary[]>([]);\n const [systemStatus, setSystemStatus] = useState<SystemStatus | null>(null);\n const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null);\n const [composeAddress, setComposeAddress] = useState(\"\");\n const [composeBody, setComposeBody] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [sending, setSending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const statusResult = await System.getStatus().catch(() => null);\n setSystemStatus(statusResult);\n const perm = await Messages.requestPermissions().catch(() => null);\n if (perm && perm.sms !== \"granted\") {\n setMessages([]);\n setError(\n \"SMS access is needed to read and send messages. Grant it in your device settings, then retry.\",\n );\n return;\n }\n const messageResult = await Messages.listMessages({ limit: 200 });\n setMessages(messageResult.messages);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setMessages([]);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Load on mount, then quietly poll so newly received SMS surface without a\n // manual control. The bridge has no push channel, so a 20s interval keeps the\n // thread list fresh; it is cleared on unmount.\n const autoLoadedRef = useRef(false);\n useEffect(() => {\n if (!autoLoadedRef.current) {\n autoLoadedRef.current = true;\n void refresh();\n }\n const interval = setInterval(() => void refresh(), 20_000);\n return () => clearInterval(interval);\n }, [refresh]);\n\n // Seed the composer from a cross-view handoff (e.g. a Contacts \"Message\"\n // control that navigated here with a number). Single-shot: the recipient is\n // consumed so a later plain navigation does not re-seed a stale \"To\" field.\n useEffect(() => {\n const pending = consumePendingMessageRecipient();\n if (pending) {\n setSelectedThreadId(null);\n setComposeAddress(pending);\n setComposeBody(\"\");\n setError(null);\n }\n }, []);\n\n const threads = useMemo(() => buildThreads(messages), [messages]);\n const currentSmsRole = smsRole(systemStatus);\n const ownsSmsRole = currentSmsRole?.held === true;\n const smsRoleHolder = currentSmsRole?.holders[0] ?? null;\n\n const openThread = useCallback(\n (threadId: string) => {\n const thread = threads.find((t) => t.id === threadId);\n if (!thread) return;\n setSelectedThreadId(thread.id);\n setComposeAddress(thread.address);\n setError(null);\n },\n [threads],\n );\n\n const requestSmsRole = useCallback(async () => {\n setError(null);\n try {\n await System.requestRole({ role: \"sms\" });\n const next = await System.getStatus();\n setSystemStatus(next);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n }, []);\n\n const send = useCallback(async () => {\n const address = composeAddress.trim();\n const body = composeBody.trim();\n if (!address || !body || sending) return;\n setSending(true);\n setError(null);\n try {\n await Messages.sendSms({ address, body });\n setComposeBody(\"\");\n await refresh();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setSending(false);\n }\n }, [composeAddress, composeBody, refresh, sending]);\n\n const onAction = useCallback(\n (action: string) => {\n if (action.startsWith(\"open-thread:\")) {\n openThread(action.slice(\"open-thread:\".length));\n return;\n }\n if (action.startsWith(\"compose-address:\")) {\n setComposeAddress(action.slice(\"compose-address:\".length));\n return;\n }\n if (action.startsWith(\"compose-body:\")) {\n setComposeBody(action.slice(\"compose-body:\".length));\n return;\n }\n switch (action) {\n case \"send\":\n void send();\n return;\n case \"request-sms-role\":\n void requestSmsRole();\n return;\n case \"refresh\":\n void refresh();\n return;\n }\n },\n [openThread, refresh, requestSmsRole, send],\n );\n\n const snapshot: MessagesSnapshot = {\n threads,\n selectedThreadId,\n composeAddress,\n composeBody,\n ownsSmsRole,\n smsRoleHolder,\n loading,\n error,\n };\n\n return (\n <SpatialSurface>\n <MessagesSpatialView snapshot={snapshot} onAction={onAction} />\n </SpatialSurface>\n );\n}\n"],"mappings":"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"}
|