@elizaos/plugin-contacts 2.0.3-beta.2 → 2.0.3-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/components/ContactsAppView.d.ts +16 -0
  2. package/dist/components/ContactsAppView.d.ts.map +1 -0
  3. package/dist/components/ContactsAppView.helpers.d.ts +11 -0
  4. package/dist/components/ContactsAppView.helpers.d.ts.map +1 -0
  5. package/dist/components/ContactsAppView.helpers.js +36 -0
  6. package/dist/components/ContactsAppView.helpers.js.map +1 -0
  7. package/dist/components/ContactsAppView.interact.d.ts +2 -0
  8. package/dist/components/ContactsAppView.interact.d.ts.map +1 -0
  9. package/dist/components/ContactsAppView.interact.js +59 -0
  10. package/dist/components/ContactsAppView.interact.js.map +1 -0
  11. package/dist/components/ContactsAppView.js +747 -0
  12. package/dist/components/ContactsAppView.js.map +1 -0
  13. package/dist/components/ContactsSpatialView.d.ts +48 -0
  14. package/dist/components/ContactsSpatialView.d.ts.map +1 -0
  15. package/dist/components/ContactsSpatialView.js +254 -0
  16. package/dist/components/ContactsSpatialView.js.map +1 -0
  17. package/dist/components/ContactsView.d.ts +18 -0
  18. package/dist/components/ContactsView.d.ts.map +1 -0
  19. package/dist/components/ContactsView.js +163 -0
  20. package/dist/components/ContactsView.js.map +1 -0
  21. package/dist/components/contacts-app.d.ts +13 -0
  22. package/dist/components/contacts-app.d.ts.map +1 -0
  23. package/dist/components/contacts-app.js +20 -0
  24. package/dist/components/contacts-app.js.map +1 -0
  25. package/dist/components/contacts-view-bundle.d.ts +3 -0
  26. package/dist/components/contacts-view-bundle.d.ts.map +1 -0
  27. package/dist/components/contacts-view-bundle.js +7 -0
  28. package/dist/components/contacts-view-bundle.js.map +1 -0
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +20 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/plugin.d.ts +13 -0
  34. package/dist/plugin.d.ts.map +1 -0
  35. package/dist/plugin.js +32 -0
  36. package/dist/plugin.js.map +1 -0
  37. package/dist/providers/contacts.d.ts +11 -0
  38. package/dist/providers/contacts.d.ts.map +1 -0
  39. package/dist/providers/contacts.js +68 -0
  40. package/dist/providers/contacts.js.map +1 -0
  41. package/dist/register-terminal-view.d.ts +15 -0
  42. package/dist/register-terminal-view.d.ts.map +1 -0
  43. package/dist/register-terminal-view.js +21 -0
  44. package/dist/register-terminal-view.js.map +1 -0
  45. package/dist/register.d.ts +10 -0
  46. package/dist/register.d.ts.map +1 -0
  47. package/dist/register.js +10 -0
  48. package/dist/register.js.map +1 -0
  49. package/dist/ui.d.ts +4 -0
  50. package/dist/ui.d.ts.map +1 -0
  51. package/dist/ui.js +15 -0
  52. package/dist/ui.js.map +1 -0
  53. package/dist/views/bundle.js +467 -0
  54. package/dist/views/bundle.js.map +1 -0
  55. package/dist/views/dist-Cd2YtKy4.js +270 -0
  56. package/dist/views/dist-Cd2YtKy4.js.map +1 -0
  57. package/dist/views/web-DMSWpoWr.js +39 -0
  58. package/dist/views/web-DMSWpoWr.js.map +1 -0
  59. package/package.json +7 -6
@@ -0,0 +1,467 @@
1
+ import { n as e } from "./dist-Cd2YtKy4.js";
2
+ import { navigateToMessagesWithNumber as t, navigateToPhoneWithNumber as n } from "@elizaos/ui/app-navigate-view";
3
+ import { isNative as r } from "@elizaos/ui/platform";
4
+ import { Button as i, Card as a, Divider as o, Field as s, HStack as c, List as l, SpatialSurface as u, Text as d, VStack as f } from "@elizaos/ui/spatial";
5
+ import { useCallback as p, useEffect as m, useMemo as h, useRef as g, useState as _ } from "react";
6
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
7
+ var x = e("ElizaContacts", { web: () => import("./web-DMSWpoWr.js").then((e) => new e.ContactsWeb()) });
8
+ //#endregion
9
+ //#region src/components/ContactsAppView.helpers.ts
10
+ function S(e, t) {
11
+ if (t.length === 0) return !0;
12
+ let n = t.toLowerCase();
13
+ return !!(e.displayName.toLowerCase().includes(n) || e.phoneNumbers.some((e) => e.toLowerCase().includes(n)) || e.emailAddresses.some((e) => e.toLowerCase().includes(n)));
14
+ }
15
+ function C(e, t = 200) {
16
+ return typeof e != "number" || !Number.isFinite(e) ? t : Math.min(500, Math.max(1, Math.trunc(e)));
17
+ }
18
+ async function w(e) {
19
+ let t = e?.query?.trim() ?? "", n = typeof e?.limit == "number" ? C(e.limit) : void 0, r = await x.listContacts({
20
+ ...t ? { query: t } : {},
21
+ ...typeof n == "number" ? { limit: n } : {}
22
+ }), i = t ? r.contacts.filter((e) => S(e, t)) : r.contacts;
23
+ return {
24
+ contacts: i,
25
+ query: t,
26
+ count: i.length
27
+ };
28
+ }
29
+ //#endregion
30
+ //#region src/components/ContactsAppView.interact.ts
31
+ async function T(e, t) {
32
+ if (e === "terminal-list-contacts") {
33
+ let e = await w({
34
+ query: typeof t?.query == "string" ? t.query : void 0,
35
+ limit: typeof t?.limit == "number" ? t.limit : void 0
36
+ });
37
+ return {
38
+ viewType: "tui",
39
+ query: e.query,
40
+ count: e.count,
41
+ contacts: e.contacts.map((e) => ({
42
+ id: e.id,
43
+ lookupKey: e.lookupKey,
44
+ displayName: e.displayName,
45
+ phoneNumbers: e.phoneNumbers,
46
+ emailAddresses: e.emailAddresses,
47
+ starred: e.starred
48
+ }))
49
+ };
50
+ }
51
+ if (e === "terminal-create-contact") {
52
+ let e = typeof t?.displayName == "string" ? t.displayName.trim() : "";
53
+ if (!e) throw Error("displayName is required");
54
+ let n = { displayName: e }, r = typeof t?.phoneNumber == "string" ? t.phoneNumber.trim() : "", i = typeof t?.emailAddress == "string" ? t.emailAddress.trim() : "";
55
+ return r && (n.phoneNumber = r), i && (n.emailAddress = i), {
56
+ created: !0,
57
+ id: (await x.createContact(n)).id,
58
+ viewType: "tui"
59
+ };
60
+ }
61
+ if (e === "terminal-import-vcard") {
62
+ let e = typeof t?.vcardText == "string" ? t.vcardText.trim() : "";
63
+ if (!e) throw Error("vcardText is required");
64
+ let n = await x.importVCard({ vcardText: e });
65
+ return {
66
+ imported: n.imported.length,
67
+ contacts: n.imported.map((e) => ({
68
+ id: e.id,
69
+ lookupKey: e.lookupKey,
70
+ displayName: e.displayName,
71
+ phoneNumbers: e.phoneNumbers,
72
+ emailAddresses: e.emailAddresses,
73
+ starred: e.starred,
74
+ sourceName: e.sourceName
75
+ })),
76
+ viewType: "tui"
77
+ };
78
+ }
79
+ throw Error(`Unsupported capability "${e}"`);
80
+ }
81
+ //#endregion
82
+ //#region src/components/ContactsSpatialView.tsx
83
+ var E = {
84
+ displayName: "",
85
+ phoneNumber: "",
86
+ emailAddress: ""
87
+ };
88
+ function D(e) {
89
+ let t = e.trim().split(/\s+/).filter(Boolean);
90
+ return t.length === 0 ? "?" : t.length === 1 ? (t[0]?.charAt(0) ?? "?").toUpperCase() : `${t[0]?.charAt(0) ?? ""}${t[t.length - 1]?.charAt(0) ?? ""}`.toUpperCase() || "?";
91
+ }
92
+ function O(e) {
93
+ let t = /* @__PURE__ */ new Set(), n = [];
94
+ for (let r of e) t.has(r) || (t.add(r), n.push(r));
95
+ return n;
96
+ }
97
+ function k(e) {
98
+ return e.phoneNumbers[0] ?? e.emailAddresses[0] ?? "no contact method";
99
+ }
100
+ function A({ snapshot: e, onAction: t }) {
101
+ let n = (e) => () => t?.(e), r = e.mode, o = e.selectedId == null ? null : e.contacts.find((t) => t.id === e.selectedId) ?? null;
102
+ return /* @__PURE__ */ b(a, {
103
+ gap: 1,
104
+ padding: 1,
105
+ children: [
106
+ /* @__PURE__ */ b(c, {
107
+ gap: 1,
108
+ align: "center",
109
+ children: [/* @__PURE__ */ y(d, {
110
+ style: "caption",
111
+ tone: "muted",
112
+ grow: 1,
113
+ children: e.loading ? "loading" : `${e.contacts.length} contacts`
114
+ }), r === "list" ? /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y(i, {
115
+ variant: "outline",
116
+ tone: "default",
117
+ agent: "refresh",
118
+ onPress: n("refresh"),
119
+ children: "Refresh"
120
+ }), /* @__PURE__ */ y(i, {
121
+ agent: "new",
122
+ onPress: n("new"),
123
+ children: "New"
124
+ })] }) : /* @__PURE__ */ y(i, {
125
+ variant: "outline",
126
+ tone: "default",
127
+ agent: "back",
128
+ onPress: n("back"),
129
+ children: "Back"
130
+ })]
131
+ }),
132
+ e.error ? /* @__PURE__ */ y(d, {
133
+ tone: "danger",
134
+ style: "caption",
135
+ children: e.error
136
+ }) : null,
137
+ r === "list" ? /* @__PURE__ */ y(j, {
138
+ snapshot: e,
139
+ dispatch: n,
140
+ onAction: t
141
+ }) : r === "detail" && o ? /* @__PURE__ */ y(M, {
142
+ contact: o,
143
+ dispatch: n
144
+ }) : /* @__PURE__ */ y(N, {
145
+ snapshot: e,
146
+ dispatch: n,
147
+ onAction: t
148
+ })
149
+ ]
150
+ });
151
+ }
152
+ function j({ snapshot: e, dispatch: t, onAction: n }) {
153
+ return /* @__PURE__ */ b(v, { children: [
154
+ /* @__PURE__ */ y(s, {
155
+ kind: "text",
156
+ label: "Search",
157
+ value: e.query,
158
+ placeholder: "name, phone, or email",
159
+ agent: "search",
160
+ onChange: (e) => n?.(`search:${e}`)
161
+ }),
162
+ /* @__PURE__ */ y(o, { label: "address book" }),
163
+ e.contacts.length === 0 ? /* @__PURE__ */ y(d, {
164
+ tone: "muted",
165
+ align: "center",
166
+ style: "caption",
167
+ children: e.loading ? "Loading" : "None"
168
+ }) : /* @__PURE__ */ y(l, {
169
+ gap: 0,
170
+ children: e.contacts.slice(0, 12).map((e) => {
171
+ let n = e.displayName || "Unnamed";
172
+ return /* @__PURE__ */ b(c, {
173
+ gap: 1,
174
+ align: "center",
175
+ agent: `select-${e.id}`,
176
+ children: [
177
+ /* @__PURE__ */ b(d, {
178
+ tone: "muted",
179
+ wrap: !1,
180
+ children: [
181
+ "[",
182
+ D(n),
183
+ "]"
184
+ ]
185
+ }),
186
+ /* @__PURE__ */ b(f, {
187
+ gap: 0,
188
+ grow: 1,
189
+ children: [/* @__PURE__ */ y(d, {
190
+ bold: !0,
191
+ wrap: !1,
192
+ children: n
193
+ }), /* @__PURE__ */ y(d, {
194
+ style: "caption",
195
+ tone: "muted",
196
+ wrap: !1,
197
+ children: k(e)
198
+ })]
199
+ }),
200
+ e.starred ? /* @__PURE__ */ y(d, {
201
+ tone: "warning",
202
+ wrap: !1,
203
+ children: "*"
204
+ }) : null,
205
+ /* @__PURE__ */ y(i, {
206
+ variant: "outline",
207
+ tone: "default",
208
+ agent: `select:${e.id}`,
209
+ onPress: t(`select:${e.id}`),
210
+ children: "Open"
211
+ })
212
+ ]
213
+ }, e.id);
214
+ })
215
+ })
216
+ ] });
217
+ }
218
+ function M({ contact: e, dispatch: t }) {
219
+ let n = O(e.phoneNumbers), r = O(e.emailAddresses);
220
+ return /* @__PURE__ */ b(v, { children: [
221
+ /* @__PURE__ */ b(c, {
222
+ gap: 1,
223
+ align: "center",
224
+ children: [
225
+ /* @__PURE__ */ b(d, {
226
+ tone: "muted",
227
+ children: [
228
+ "[",
229
+ D(e.displayName),
230
+ "]"
231
+ ]
232
+ }),
233
+ /* @__PURE__ */ y(d, {
234
+ style: "subheading",
235
+ bold: !0,
236
+ grow: 1,
237
+ children: e.displayName || "Unnamed"
238
+ }),
239
+ e.starred ? /* @__PURE__ */ y(d, {
240
+ tone: "warning",
241
+ children: "starred"
242
+ }) : null
243
+ ]
244
+ }),
245
+ /* @__PURE__ */ y(o, { label: "phone" }),
246
+ n.length === 0 ? /* @__PURE__ */ y(d, {
247
+ tone: "muted",
248
+ style: "caption",
249
+ children: "None"
250
+ }) : /* @__PURE__ */ y(l, {
251
+ gap: 0,
252
+ children: n.map((e) => /* @__PURE__ */ b(c, {
253
+ gap: 1,
254
+ align: "center",
255
+ children: [
256
+ /* @__PURE__ */ y(d, {
257
+ grow: 1,
258
+ wrap: !1,
259
+ children: e
260
+ }),
261
+ /* @__PURE__ */ y(i, {
262
+ agent: `call:${e}`,
263
+ onPress: t(`call:${e}`),
264
+ children: "Call"
265
+ }),
266
+ /* @__PURE__ */ y(i, {
267
+ variant: "outline",
268
+ tone: "default",
269
+ agent: `text:${e}`,
270
+ onPress: t(`text:${e}`),
271
+ children: "Text"
272
+ })
273
+ ]
274
+ }, e))
275
+ }),
276
+ /* @__PURE__ */ y(o, { label: "email" }),
277
+ r.length === 0 ? /* @__PURE__ */ y(d, {
278
+ tone: "muted",
279
+ style: "caption",
280
+ children: "None"
281
+ }) : /* @__PURE__ */ y(l, {
282
+ gap: 0,
283
+ children: r.map((e) => /* @__PURE__ */ y(d, {
284
+ wrap: !1,
285
+ children: e
286
+ }, e))
287
+ }),
288
+ /* @__PURE__ */ y(d, {
289
+ tone: "muted",
290
+ style: "caption",
291
+ children: "Editing existing contacts is unavailable on this device."
292
+ })
293
+ ] });
294
+ }
295
+ function N({ snapshot: e, dispatch: t, onAction: n }) {
296
+ let r = e.form ?? E, a = r.displayName.trim().length > 0 && !e.submitting;
297
+ return /* @__PURE__ */ b(v, { children: [
298
+ /* @__PURE__ */ y(s, {
299
+ kind: "text",
300
+ label: "Name",
301
+ value: r.displayName,
302
+ placeholder: "Full name",
303
+ agent: "name",
304
+ onChange: (e) => n?.(`name:${e}`)
305
+ }),
306
+ /* @__PURE__ */ y(s, {
307
+ kind: "text",
308
+ label: "Phone",
309
+ value: r.phoneNumber,
310
+ placeholder: "+1 555 123 4567",
311
+ agent: "phone",
312
+ onChange: (e) => n?.(`phone:${e}`)
313
+ }),
314
+ /* @__PURE__ */ y(s, {
315
+ kind: "text",
316
+ label: "Email",
317
+ value: r.emailAddress,
318
+ placeholder: "name@example.com",
319
+ agent: "email",
320
+ onChange: (e) => n?.(`email:${e}`)
321
+ }),
322
+ /* @__PURE__ */ b(c, {
323
+ gap: 1,
324
+ children: [/* @__PURE__ */ y(i, {
325
+ grow: 1,
326
+ disabled: !a,
327
+ agent: "save",
328
+ onPress: t("save"),
329
+ children: e.submitting ? "Saving" : "Save"
330
+ }), /* @__PURE__ */ y(i, {
331
+ variant: "ghost",
332
+ tone: "danger",
333
+ agent: "cancel",
334
+ onPress: t("cancel"),
335
+ children: "Cancel"
336
+ })]
337
+ })
338
+ ] });
339
+ }
340
+ //#endregion
341
+ //#region src/components/ContactsView.tsx
342
+ var P = {
343
+ displayName: "",
344
+ phoneNumber: "",
345
+ emailAddress: ""
346
+ };
347
+ function F() {
348
+ let [e, i] = _([]), [a, o] = _(""), [s, c] = _("list"), [l, d] = _(null), [f, v] = _(P), [b, C] = _(!1), [w, T] = _(!1), [E, D] = _(null), O = p(async () => {
349
+ if (!r) {
350
+ i([]), D(null), C(!1);
351
+ return;
352
+ }
353
+ C(!0), D(null);
354
+ try {
355
+ let e = await x.requestPermissions().catch(() => null);
356
+ if (e && e.contacts !== "granted") {
357
+ i([]), D("Contacts access is needed to show your address book. Grant it in your device settings, then retry.");
358
+ return;
359
+ }
360
+ i((await x.listContacts({})).contacts);
361
+ } catch (e) {
362
+ D(e instanceof Error ? e.message : String(e)), i([]);
363
+ } finally {
364
+ C(!1);
365
+ }
366
+ }, []), k = g(!1);
367
+ m(() => {
368
+ k.current || (k.current = !0, O());
369
+ let e = setInterval(() => {
370
+ O();
371
+ }, 2e4);
372
+ return () => clearInterval(e);
373
+ }, [O]);
374
+ let j = h(() => {
375
+ let t = a.trim();
376
+ return t ? e.filter((e) => S(e, t)) : e;
377
+ }, [e, a]), M = p(async () => {
378
+ let e = f.displayName.trim();
379
+ if (!e || w) return;
380
+ let t = { displayName: e }, n = f.phoneNumber.trim(), r = f.emailAddress.trim();
381
+ n && (t.phoneNumber = n), r && (t.emailAddress = r), T(!0), D(null);
382
+ try {
383
+ await x.createContact(t), v(P), c("list"), await O();
384
+ } catch (e) {
385
+ D(e instanceof Error ? e.message : String(e));
386
+ } finally {
387
+ T(!1);
388
+ }
389
+ }, [
390
+ f,
391
+ O,
392
+ w
393
+ ]), N = p((e) => {
394
+ if (e.startsWith("select:")) {
395
+ d(e.slice(7)), c("detail");
396
+ return;
397
+ }
398
+ if (e.startsWith("call:")) {
399
+ n(e.slice(5));
400
+ return;
401
+ }
402
+ if (e.startsWith("text:")) {
403
+ t(e.slice(5));
404
+ return;
405
+ }
406
+ if (e.startsWith("search:")) {
407
+ o(e.slice(7));
408
+ return;
409
+ }
410
+ if (e.startsWith("name:")) {
411
+ let t = e.slice(5);
412
+ v((e) => ({
413
+ ...e,
414
+ displayName: t
415
+ }));
416
+ return;
417
+ }
418
+ if (e.startsWith("phone:")) {
419
+ let t = e.slice(6);
420
+ v((e) => ({
421
+ ...e,
422
+ phoneNumber: t
423
+ }));
424
+ return;
425
+ }
426
+ if (e.startsWith("email:")) {
427
+ let t = e.slice(6);
428
+ v((e) => ({
429
+ ...e,
430
+ emailAddress: t
431
+ }));
432
+ return;
433
+ }
434
+ switch (e) {
435
+ case "refresh":
436
+ O();
437
+ return;
438
+ case "new":
439
+ v(P), c("new");
440
+ return;
441
+ case "back":
442
+ case "cancel":
443
+ c("list"), d(null);
444
+ return;
445
+ case "save":
446
+ M();
447
+ return;
448
+ }
449
+ }, [M, O]);
450
+ return /* @__PURE__ */ y(u, { children: /* @__PURE__ */ y(A, {
451
+ snapshot: {
452
+ contacts: j,
453
+ query: a,
454
+ mode: s,
455
+ selectedId: l,
456
+ form: f,
457
+ loading: b,
458
+ submitting: w,
459
+ error: E
460
+ },
461
+ onAction: N
462
+ }) });
463
+ }
464
+ //#endregion
465
+ export { F as ContactsView, T as interact };
466
+
467
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","names":[],"sources":["../../../plugin-native-contacts/src/index.ts","../../src/components/ContactsAppView.helpers.ts","../../src/components/ContactsAppView.interact.ts","../../src/components/ContactsSpatialView.tsx","../../src/components/ContactsView.tsx"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\n\nimport type { ContactsPlugin } from \"./definitions\";\n\nexport * from \"./definitions\";\n\nconst loadWeb = () => import(\"./web\").then((m) => new m.ContactsWeb());\n\nexport const Contacts = registerPlugin<ContactsPlugin>(\"ElizaContacts\", {\n web: loadWeb,\n});\n","// Shared (non-component) data helpers for the contacts overlay. Kept out of\n// ContactsAppView.tsx so that file exports only React components and stays\n// Fast-Refresh-compatible. Used by both the view components and the view-bundle\n// `interact` handler.\n\nimport { type ContactSummary, Contacts } from \"@elizaos/capacitor-contacts\";\n\nexport function matchesQuery(contact: ContactSummary, q: string): boolean {\n if (q.length === 0) return true;\n const needle = q.toLowerCase();\n if (contact.displayName.toLowerCase().includes(needle)) return true;\n if (\n contact.phoneNumbers.some((p: string) => p.toLowerCase().includes(needle))\n ) {\n return true;\n }\n if (\n contact.emailAddresses.some((e: string) => e.toLowerCase().includes(needle))\n ) {\n return true;\n }\n return false;\n}\n\nfunction normalizeContactsLimit(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 loadContactsState(options?: {\n query?: string;\n limit?: number;\n}) {\n const query = options?.query?.trim() ?? \"\";\n const limit =\n typeof options?.limit === \"number\"\n ? normalizeContactsLimit(options.limit)\n : undefined;\n const result = await Contacts.listContacts({\n ...(query ? { query } : {}),\n ...(typeof limit === \"number\" ? { limit } : {}),\n });\n const contacts = query\n ? result.contacts.filter((contact) => matchesQuery(contact, query))\n : result.contacts;\n return {\n contacts,\n query,\n count: contacts.length,\n };\n}\n","// View-bundle `interact` capability handler, split out of ContactsAppView.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 ./contacts-view-bundle.ts.\n\nimport {\n Contacts,\n type CreateContactOptions,\n} from \"@elizaos/capacitor-contacts\";\nimport { loadContactsState } from \"./ContactsAppView.helpers\";\n\nexport async function interact(\n capability: string,\n params?: Record<string, unknown>,\n): Promise<unknown> {\n if (capability === \"terminal-list-contacts\") {\n const state = await loadContactsState({\n query: typeof params?.query === \"string\" ? params.query : undefined,\n limit: typeof params?.limit === \"number\" ? params.limit : undefined,\n });\n return {\n viewType: \"tui\",\n query: state.query,\n count: state.count,\n contacts: state.contacts.map((contact) => ({\n id: contact.id,\n lookupKey: contact.lookupKey,\n displayName: contact.displayName,\n phoneNumbers: contact.phoneNumbers,\n emailAddresses: contact.emailAddresses,\n starred: contact.starred,\n })),\n };\n }\n\n if (capability === \"terminal-create-contact\") {\n const displayName =\n typeof params?.displayName === \"string\" ? params.displayName.trim() : \"\";\n if (!displayName) throw new Error(\"displayName is required\");\n const payload: CreateContactOptions = { displayName };\n const phoneNumber =\n typeof params?.phoneNumber === \"string\" ? params.phoneNumber.trim() : \"\";\n const emailAddress =\n typeof params?.emailAddress === \"string\"\n ? params.emailAddress.trim()\n : \"\";\n if (phoneNumber) payload.phoneNumber = phoneNumber;\n if (emailAddress) payload.emailAddress = emailAddress;\n const result = await Contacts.createContact(payload);\n return { created: true, id: result.id, viewType: \"tui\" };\n }\n\n if (capability === \"terminal-import-vcard\") {\n const vcardText =\n typeof params?.vcardText === \"string\" ? params.vcardText.trim() : \"\";\n if (!vcardText) throw new Error(\"vcardText is required\");\n const result = await Contacts.importVCard({ vcardText });\n return {\n imported: result.imported.length,\n contacts: result.imported.map((contact) => ({\n id: contact.id,\n lookupKey: contact.lookupKey,\n displayName: contact.displayName,\n phoneNumbers: contact.phoneNumbers,\n emailAddresses: contact.emailAddresses,\n starred: contact.starred,\n sourceName: contact.sourceName,\n })),\n viewType: \"tui\",\n };\n }\n\n throw new Error(`Unsupported capability \"${capability}\"`);\n}\n","/**\n * ContactsSpatialView - the contacts address book 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 contact record, so it is safe to render in the Node agent process\n * where the terminal lives (no Capacitor runtime import).\n */\n\nimport type { ContactSummary } from \"@elizaos/capacitor-contacts\";\nimport {\n Button,\n Card,\n Divider,\n Field,\n HStack,\n List,\n Text,\n VStack,\n} from \"@elizaos/ui/spatial\";\n\n/** Which screen the contacts surface is currently showing. */\nexport type ContactsMode = \"list\" | \"detail\" | \"new\";\n\n/** Pending values for the new-contact form. */\nexport interface ContactsFormDraft {\n displayName: string;\n phoneNumber: string;\n emailAddress: string;\n}\n\nexport interface ContactsSnapshot {\n /** Address book records (already filtered to the active query when present). */\n contacts: ContactSummary[];\n /** Active search filter; empty string when unfiltered. */\n query: string;\n /** Current screen. */\n mode: ContactsMode;\n /** Id of the contact shown in detail mode, if any. */\n selectedId?: string | null;\n /** Draft for the new-contact form (detail/new mode). */\n form?: ContactsFormDraft;\n loading?: boolean;\n submitting?: boolean;\n error?: string | null;\n}\n\nconst EMPTY_FORM: ContactsFormDraft = {\n displayName: \"\",\n phoneNumber: \"\",\n emailAddress: \"\",\n};\n\nfunction getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return \"?\";\n if (parts.length === 1) return (parts[0]?.charAt(0) ?? \"?\").toUpperCase();\n const first = parts[0]?.charAt(0) ?? \"\";\n const last = parts[parts.length - 1]?.charAt(0) ?? \"\";\n return `${first}${last}`.toUpperCase() || \"?\";\n}\n\nfunction dedupePreservingOrder(values: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const value of values) {\n if (seen.has(value)) continue;\n seen.add(value);\n out.push(value);\n }\n return out;\n}\n\nfunction primaryLine(contact: ContactSummary): string {\n return (\n contact.phoneNumbers[0] ?? contact.emailAddresses[0] ?? \"no contact method\"\n );\n}\n\nexport interface ContactsSpatialViewProps {\n snapshot: ContactsSnapshot;\n /**\n * Dispatch by agent id: `refresh`, `new`, `back`, `cancel`, `save`,\n * `select:<id>`, `call:<value>`, `text:<value>`, and the field-edit signals\n * `search:<value>`, `name:<value>`, `phone:<value>`, `email:<value>`.\n */\n onAction?: (action: string) => void;\n}\n\nexport function ContactsSpatialView({\n snapshot,\n onAction,\n}: ContactsSpatialViewProps) {\n const dispatch = (action: string) => () => onAction?.(action);\n const mode = snapshot.mode;\n const selected =\n snapshot.selectedId != null\n ? (snapshot.contacts.find((c) => c.id === snapshot.selectedId) ?? null)\n : null;\n\n return (\n <Card gap={1} padding={1}>\n <HStack gap={1} align=\"center\">\n <Text style=\"caption\" tone=\"muted\" grow={1}>\n {snapshot.loading\n ? \"loading\"\n : `${snapshot.contacts.length} contacts`}\n </Text>\n {mode === \"list\" ? (\n <>\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent=\"refresh\"\n onPress={dispatch(\"refresh\")}\n >\n Refresh\n </Button>\n <Button agent=\"new\" onPress={dispatch(\"new\")}>\n New\n </Button>\n </>\n ) : (\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent=\"back\"\n onPress={dispatch(\"back\")}\n >\n Back\n </Button>\n )}\n </HStack>\n\n {snapshot.error ? (\n <Text tone=\"danger\" style=\"caption\">\n {snapshot.error}\n </Text>\n ) : null}\n\n {mode === \"list\" ? (\n <ContactsListBody\n snapshot={snapshot}\n dispatch={dispatch}\n onAction={onAction}\n />\n ) : mode === \"detail\" && selected ? (\n <ContactsDetailBody contact={selected} dispatch={dispatch} />\n ) : (\n <ContactsFormBody\n snapshot={snapshot}\n dispatch={dispatch}\n onAction={onAction}\n />\n )}\n </Card>\n );\n}\n\nfunction ContactsListBody({\n snapshot,\n dispatch,\n onAction,\n}: {\n snapshot: ContactsSnapshot;\n dispatch: (action: string) => () => void;\n onAction?: (action: string) => void;\n}) {\n return (\n <>\n <Field\n kind=\"text\"\n label=\"Search\"\n value={snapshot.query}\n placeholder=\"name, phone, or email\"\n agent=\"search\"\n onChange={(value) => onAction?.(`search:${value}`)}\n />\n <Divider label=\"address book\" />\n {snapshot.contacts.length === 0 ? (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n {snapshot.loading ? \"Loading\" : \"None\"}\n </Text>\n ) : (\n <List gap={0}>\n {snapshot.contacts.slice(0, 12).map((contact) => {\n const name = contact.displayName || \"Unnamed\";\n return (\n <HStack\n key={contact.id}\n gap={1}\n align=\"center\"\n agent={`select-${contact.id}`}\n >\n <Text tone=\"muted\" wrap={false}>\n [{getInitials(name)}]\n </Text>\n <VStack gap={0} grow={1}>\n <Text bold wrap={false}>\n {name}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {primaryLine(contact)}\n </Text>\n </VStack>\n {contact.starred ? (\n <Text tone=\"warning\" wrap={false}>\n *\n </Text>\n ) : null}\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent={`select:${contact.id}`}\n onPress={dispatch(`select:${contact.id}`)}\n >\n Open\n </Button>\n </HStack>\n );\n })}\n </List>\n )}\n </>\n );\n}\n\nfunction ContactsDetailBody({\n contact,\n dispatch,\n}: {\n contact: ContactSummary;\n dispatch: (action: string) => () => void;\n}) {\n const phones = dedupePreservingOrder(contact.phoneNumbers);\n const emails = dedupePreservingOrder(contact.emailAddresses);\n return (\n <>\n <HStack gap={1} align=\"center\">\n <Text tone=\"muted\">[{getInitials(contact.displayName)}]</Text>\n <Text style=\"subheading\" bold grow={1}>\n {contact.displayName || \"Unnamed\"}\n </Text>\n {contact.starred ? <Text tone=\"warning\">starred</Text> : null}\n </HStack>\n\n <Divider label=\"phone\" />\n {phones.length === 0 ? (\n <Text tone=\"muted\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {phones.map((value) => (\n <HStack key={value} gap={1} align=\"center\">\n <Text grow={1} wrap={false}>\n {value}\n </Text>\n <Button\n agent={`call:${value}`}\n onPress={dispatch(`call:${value}`)}\n >\n Call\n </Button>\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent={`text:${value}`}\n onPress={dispatch(`text:${value}`)}\n >\n Text\n </Button>\n </HStack>\n ))}\n </List>\n )}\n\n <Divider label=\"email\" />\n {emails.length === 0 ? (\n <Text tone=\"muted\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {emails.map((value) => (\n <Text key={value} wrap={false}>\n {value}\n </Text>\n ))}\n </List>\n )}\n\n <Text tone=\"muted\" style=\"caption\">\n Editing existing contacts is unavailable on this device.\n </Text>\n </>\n );\n}\n\nfunction ContactsFormBody({\n snapshot,\n dispatch,\n onAction,\n}: {\n snapshot: ContactsSnapshot;\n dispatch: (action: string) => () => void;\n onAction?: (action: string) => void;\n}) {\n const form = snapshot.form ?? EMPTY_FORM;\n const canSubmit = form.displayName.trim().length > 0 && !snapshot.submitting;\n return (\n <>\n <Field\n kind=\"text\"\n label=\"Name\"\n value={form.displayName}\n placeholder=\"Full name\"\n agent=\"name\"\n onChange={(value) => onAction?.(`name:${value}`)}\n />\n <Field\n kind=\"text\"\n label=\"Phone\"\n value={form.phoneNumber}\n placeholder=\"+1 555 123 4567\"\n agent=\"phone\"\n onChange={(value) => onAction?.(`phone:${value}`)}\n />\n <Field\n kind=\"text\"\n label=\"Email\"\n value={form.emailAddress}\n placeholder=\"name@example.com\"\n agent=\"email\"\n onChange={(value) => onAction?.(`email:${value}`)}\n />\n <HStack gap={1}>\n <Button\n grow={1}\n disabled={!canSubmit}\n agent=\"save\"\n onPress={dispatch(\"save\")}\n >\n {snapshot.submitting ? \"Saving\" : \"Save\"}\n </Button>\n <Button\n variant=\"ghost\"\n tone=\"danger\"\n agent=\"cancel\"\n onPress={dispatch(\"cancel\")}\n >\n Cancel\n </Button>\n </HStack>\n </>\n );\n}\n","/**\n * ContactsView — the single GUI/XR data wrapper for the Contacts surface.\n *\n * It owns the live Android address-book data (contact fetch, permission gate,\n * background poll, list/detail/new mode, the new-contact form, and the\n * Call/Text handoffs to the Phone/Messages views) and renders the one\n * presentational {@link ContactsSpatialView} inside a {@link SpatialSurface}.\n * Omitting the `modality` prop lets `SpatialSurface` auto-detect GUI vs XR via\n * `window.__elizaXRContext`, so the SAME component serves both surfaces. The\n * TUI surface renders the same `ContactsSpatialView` through the terminal\n * registry (see `register-terminal-view.tsx`).\n *\n * The full-screen overlay-app variant (with vCard import + permission-recovery\n * callout) remains `ContactsAppView`, loaded by the overlay-app registry on\n * ElizaOS; this wrapper is the cross-modality view-bundle export.\n */\n\nimport {\n type ContactSummary,\n Contacts,\n type CreateContactOptions,\n} from \"@elizaos/capacitor-contacts\";\nimport {\n navigateToMessagesWithNumber,\n navigateToPhoneWithNumber,\n} from \"@elizaos/ui/app-navigate-view\";\nimport { isNative } from \"@elizaos/ui/platform\";\nimport { SpatialSurface } from \"@elizaos/ui/spatial\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { matchesQuery } from \"./ContactsAppView.helpers.ts\";\nimport {\n type ContactsFormDraft,\n type ContactsMode,\n type ContactsSnapshot,\n ContactsSpatialView,\n} from \"./ContactsSpatialView.tsx\";\n\nconst EMPTY_FORM: ContactsFormDraft = {\n displayName: \"\",\n phoneNumber: \"\",\n emailAddress: \"\",\n};\n\nexport function ContactsView() {\n const [contacts, setContacts] = useState<ContactSummary[]>([]);\n const [query, setQuery] = useState(\"\");\n const [mode, setMode] = useState<ContactsMode>(\"list\");\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [form, setForm] = useState<ContactsFormDraft>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(async () => {\n if (!isNative) {\n setContacts([]);\n setError(null);\n setLoading(false);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const status = await Contacts.requestPermissions().catch(() => null);\n if (status && status.contacts !== \"granted\") {\n setContacts([]);\n setError(\n \"Contacts access is needed to show your address book. Grant it in your device settings, then retry.\",\n );\n return;\n }\n const result = await Contacts.listContacts({});\n setContacts(result.contacts);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setContacts([]);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Load the address book on mount, then keep it fresh with a quiet 20s poll.\n // Torn down 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(() => {\n void refresh();\n }, 20_000);\n return () => clearInterval(interval);\n }, [refresh]);\n\n // The native bridge has no server-side filter we depend on here; apply the\n // active query client-side so search reacts instantly without a refetch.\n const visibleContacts = useMemo(() => {\n const needle = query.trim();\n if (!needle) return contacts;\n return contacts.filter((contact) => matchesQuery(contact, needle));\n }, [contacts, query]);\n\n const createContact = useCallback(async () => {\n const displayName = form.displayName.trim();\n if (!displayName || submitting) return;\n const payload: CreateContactOptions = { displayName };\n const phone = form.phoneNumber.trim();\n const email = form.emailAddress.trim();\n if (phone) payload.phoneNumber = phone;\n if (email) payload.emailAddress = email;\n\n setSubmitting(true);\n setError(null);\n try {\n await Contacts.createContact(payload);\n setForm(EMPTY_FORM);\n setMode(\"list\");\n await refresh();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setSubmitting(false);\n }\n }, [form, refresh, submitting]);\n\n const onAction = useCallback(\n (action: string) => {\n if (action.startsWith(\"select:\")) {\n setSelectedId(action.slice(\"select:\".length));\n setMode(\"detail\");\n return;\n }\n if (action.startsWith(\"call:\")) {\n navigateToPhoneWithNumber(action.slice(\"call:\".length));\n return;\n }\n if (action.startsWith(\"text:\")) {\n navigateToMessagesWithNumber(action.slice(\"text:\".length));\n return;\n }\n if (action.startsWith(\"search:\")) {\n setQuery(action.slice(\"search:\".length));\n return;\n }\n if (action.startsWith(\"name:\")) {\n const value = action.slice(\"name:\".length);\n setForm((prev) => ({ ...prev, displayName: value }));\n return;\n }\n if (action.startsWith(\"phone:\")) {\n const value = action.slice(\"phone:\".length);\n setForm((prev) => ({ ...prev, phoneNumber: value }));\n return;\n }\n if (action.startsWith(\"email:\")) {\n const value = action.slice(\"email:\".length);\n setForm((prev) => ({ ...prev, emailAddress: value }));\n return;\n }\n switch (action) {\n case \"refresh\":\n void refresh();\n return;\n case \"new\":\n setForm(EMPTY_FORM);\n setMode(\"new\");\n return;\n case \"back\":\n case \"cancel\":\n setMode(\"list\");\n setSelectedId(null);\n return;\n case \"save\":\n void createContact();\n return;\n }\n },\n [createContact, refresh],\n );\n\n const snapshot: ContactsSnapshot = {\n contacts: visibleContacts,\n query,\n mode,\n selectedId,\n form,\n loading,\n submitting,\n error,\n };\n\n return (\n <SpatialSurface>\n <ContactsSpatialView snapshot={snapshot} onAction={onAction} />\n </SpatialSurface>\n );\n}\n"],"mappings":"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"}