shepherd-onboard 0.1.15 → 0.1.17
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/bin/shepherd-onboard.js +107 -52
- package/package.json +1 -1
package/bin/shepherd-onboard.js
CHANGED
|
@@ -1356,16 +1356,15 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1356
1356
|
<title>Select Messages Chats</title>
|
|
1357
1357
|
<style>
|
|
1358
1358
|
:root {
|
|
1359
|
-
--bg: #
|
|
1360
|
-
--panel: #ffffff;
|
|
1359
|
+
--bg: #ffffff;
|
|
1361
1360
|
--fg: #141614;
|
|
1362
|
-
--muted: #
|
|
1363
|
-
--faint: #
|
|
1364
|
-
--line: #
|
|
1361
|
+
--muted: #615d59;
|
|
1362
|
+
--faint: #a39e98;
|
|
1363
|
+
--line: #e6e6e6;
|
|
1365
1364
|
--green: #1f5c2e;
|
|
1366
1365
|
--green-hover: #246836;
|
|
1367
1366
|
--radius: 8px;
|
|
1368
|
-
--grid: 20px minmax(0, 1fr)
|
|
1367
|
+
--grid: 20px minmax(0, 1fr) 76px 108px;
|
|
1369
1368
|
}
|
|
1370
1369
|
* { box-sizing: border-box; }
|
|
1371
1370
|
body {
|
|
@@ -1378,32 +1377,30 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1378
1377
|
-webkit-font-smoothing: antialiased;
|
|
1379
1378
|
}
|
|
1380
1379
|
main {
|
|
1381
|
-
width: min(
|
|
1380
|
+
width: min(640px, calc(100vw - 32px));
|
|
1382
1381
|
margin: 0 auto;
|
|
1383
|
-
padding:
|
|
1382
|
+
padding: 56px 0 28px;
|
|
1384
1383
|
}
|
|
1385
1384
|
.header {
|
|
1386
|
-
display:
|
|
1387
|
-
justify-
|
|
1388
|
-
align
|
|
1389
|
-
|
|
1390
|
-
padding: 0 0 18px;
|
|
1385
|
+
display: grid;
|
|
1386
|
+
justify-items: center;
|
|
1387
|
+
text-align: center;
|
|
1388
|
+
padding: 0 0 28px;
|
|
1391
1389
|
}
|
|
1392
1390
|
.brand {
|
|
1393
|
-
display:
|
|
1394
|
-
|
|
1395
|
-
gap:
|
|
1391
|
+
display: grid;
|
|
1392
|
+
justify-items: center;
|
|
1393
|
+
gap: 16px;
|
|
1396
1394
|
min-width: 0;
|
|
1397
1395
|
}
|
|
1398
1396
|
.logo {
|
|
1399
|
-
width:
|
|
1400
|
-
height:
|
|
1397
|
+
width: 30px;
|
|
1398
|
+
height: 30px;
|
|
1401
1399
|
object-fit: contain;
|
|
1402
|
-
flex: none;
|
|
1403
1400
|
}
|
|
1404
1401
|
.logo-fallback {
|
|
1405
|
-
width:
|
|
1406
|
-
height:
|
|
1402
|
+
width: 30px;
|
|
1403
|
+
height: 30px;
|
|
1407
1404
|
border-radius: 6px;
|
|
1408
1405
|
display: grid;
|
|
1409
1406
|
place-items: center;
|
|
@@ -1415,36 +1412,32 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1415
1412
|
}
|
|
1416
1413
|
h1 {
|
|
1417
1414
|
margin: 0;
|
|
1418
|
-
font-size:
|
|
1415
|
+
font-size: 30px;
|
|
1419
1416
|
line-height: 1.1;
|
|
1420
1417
|
font-weight: 700;
|
|
1421
1418
|
letter-spacing: 0;
|
|
1422
1419
|
}
|
|
1423
1420
|
.subtitle {
|
|
1424
|
-
margin:
|
|
1425
|
-
font-size:
|
|
1421
|
+
margin: 8px 0 0;
|
|
1422
|
+
font-size: 14px;
|
|
1426
1423
|
line-height: 1.4;
|
|
1427
1424
|
color: var(--muted);
|
|
1428
1425
|
}
|
|
1429
1426
|
.panel {
|
|
1430
|
-
background:
|
|
1431
|
-
border: 1px solid var(--line);
|
|
1432
|
-
border-radius: var(--radius);
|
|
1433
|
-
overflow: hidden;
|
|
1427
|
+
background: transparent;
|
|
1434
1428
|
}
|
|
1435
1429
|
.panel-head {
|
|
1436
|
-
padding:
|
|
1437
|
-
border-bottom: 1px solid var(--line);
|
|
1430
|
+
padding: 0 0 18px;
|
|
1438
1431
|
}
|
|
1439
1432
|
.search {
|
|
1440
1433
|
width: 100%;
|
|
1441
|
-
border: 1px solid
|
|
1442
|
-
border-radius:
|
|
1434
|
+
border: 1px solid var(--line);
|
|
1435
|
+
border-radius: 8px;
|
|
1443
1436
|
background: #ffffff;
|
|
1444
1437
|
color: var(--fg);
|
|
1445
|
-
padding:
|
|
1438
|
+
padding: 12px 13px;
|
|
1446
1439
|
font: inherit;
|
|
1447
|
-
font-size:
|
|
1440
|
+
font-size: 15px;
|
|
1448
1441
|
outline: none;
|
|
1449
1442
|
}
|
|
1450
1443
|
.search:focus {
|
|
@@ -1454,7 +1447,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1454
1447
|
}
|
|
1455
1448
|
.search::placeholder { color: var(--faint); }
|
|
1456
1449
|
.error {
|
|
1457
|
-
margin:
|
|
1450
|
+
margin: 0 0 12px;
|
|
1458
1451
|
color: #9B1C1C;
|
|
1459
1452
|
font-size: 13px;
|
|
1460
1453
|
}
|
|
@@ -1463,12 +1456,14 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1463
1456
|
grid-template-columns: var(--grid);
|
|
1464
1457
|
gap: 12px;
|
|
1465
1458
|
align-items: center;
|
|
1466
|
-
padding: 9px
|
|
1459
|
+
padding: 9px 0;
|
|
1460
|
+
border-top: 1px solid var(--line);
|
|
1467
1461
|
border-bottom: 1px solid var(--line);
|
|
1468
1462
|
color: var(--faint);
|
|
1469
1463
|
font-size: 11px;
|
|
1470
1464
|
font-weight: 600;
|
|
1471
1465
|
text-transform: uppercase;
|
|
1466
|
+
letter-spacing: 0.02em;
|
|
1472
1467
|
}
|
|
1473
1468
|
.list-head .right { text-align: left; }
|
|
1474
1469
|
.chat-list { display: block; }
|
|
@@ -1477,13 +1472,12 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1477
1472
|
grid-template-columns: var(--grid);
|
|
1478
1473
|
gap: 12px;
|
|
1479
1474
|
align-items: center;
|
|
1480
|
-
padding: 11px
|
|
1475
|
+
padding: 11px 0;
|
|
1481
1476
|
border-bottom: 1px solid var(--line);
|
|
1482
1477
|
cursor: pointer;
|
|
1483
1478
|
transition: background 120ms ease;
|
|
1484
1479
|
}
|
|
1485
|
-
.chat-row:
|
|
1486
|
-
.chat-row:hover { background: #f6f7f5; }
|
|
1480
|
+
.chat-row:hover { background: #f6f5f4; }
|
|
1487
1481
|
input[type="checkbox"] {
|
|
1488
1482
|
position: absolute;
|
|
1489
1483
|
opacity: 0;
|
|
@@ -1521,7 +1515,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1521
1515
|
text-overflow: ellipsis;
|
|
1522
1516
|
white-space: nowrap;
|
|
1523
1517
|
font-size: 15px;
|
|
1524
|
-
font-weight:
|
|
1518
|
+
font-weight: 500;
|
|
1525
1519
|
}
|
|
1526
1520
|
.chat-people {
|
|
1527
1521
|
color: var(--muted);
|
|
@@ -1535,9 +1529,9 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1535
1529
|
justify-self: start;
|
|
1536
1530
|
color: var(--muted);
|
|
1537
1531
|
font-size: 12.5px;
|
|
1538
|
-
font-weight:
|
|
1532
|
+
font-weight: 400;
|
|
1539
1533
|
}
|
|
1540
|
-
.chat-kind--group { color: var(--
|
|
1534
|
+
.chat-kind--group { color: var(--fg); }
|
|
1541
1535
|
.chat-meta {
|
|
1542
1536
|
color: var(--muted);
|
|
1543
1537
|
font-size: 12.5px;
|
|
@@ -1558,8 +1552,8 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1558
1552
|
gap: 12px;
|
|
1559
1553
|
position: sticky;
|
|
1560
1554
|
bottom: 0;
|
|
1561
|
-
margin-top:
|
|
1562
|
-
padding:
|
|
1555
|
+
margin-top: 16px;
|
|
1556
|
+
padding: 12px 0 0;
|
|
1563
1557
|
background: var(--bg);
|
|
1564
1558
|
}
|
|
1565
1559
|
.selection-count {
|
|
@@ -1570,7 +1564,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1570
1564
|
button {
|
|
1571
1565
|
appearance: none;
|
|
1572
1566
|
border: 0;
|
|
1573
|
-
border-radius:
|
|
1567
|
+
border-radius: 8px;
|
|
1574
1568
|
background: var(--green);
|
|
1575
1569
|
color: #FFFFFF;
|
|
1576
1570
|
padding: 9px 13px;
|
|
@@ -1595,7 +1589,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1595
1589
|
${logo ? `<img class="logo" src="${htmlAttr(logo)}" alt="">` : `<span class="logo-fallback" aria-hidden="true">S</span>`}
|
|
1596
1590
|
<div>
|
|
1597
1591
|
<h1>Select chats</h1>
|
|
1598
|
-
<p class="subtitle">Choose
|
|
1592
|
+
<p class="subtitle">Choose which local Messages chats Shepherd should sync.</p>
|
|
1599
1593
|
</div>
|
|
1600
1594
|
</div>
|
|
1601
1595
|
</header>
|
|
@@ -1607,7 +1601,6 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1607
1601
|
</div>
|
|
1608
1602
|
${error ? `<p class="error">${html(error)}</p>` : ""}
|
|
1609
1603
|
<div class="list-head">
|
|
1610
|
-
<span></span>
|
|
1611
1604
|
<span></span>
|
|
1612
1605
|
<span>Name</span>
|
|
1613
1606
|
<span>Type</span>
|
|
@@ -1692,7 +1685,9 @@ function renderChatPeople(chat) {
|
|
|
1692
1685
|
|
|
1693
1686
|
function chatPeopleLine(chat) {
|
|
1694
1687
|
if (chat.kind !== "group") return "";
|
|
1695
|
-
const names = chat.participants
|
|
1688
|
+
const names = chat.participants
|
|
1689
|
+
?.map((participant) => participant.name)
|
|
1690
|
+
.filter((name) => name && !looksLikeHandleList(name)) ?? [];
|
|
1696
1691
|
const line = names.slice(0, 6).join(", ");
|
|
1697
1692
|
if (!line || normalizeDisplayText(line) === normalizeDisplayText(chat.label)) return "";
|
|
1698
1693
|
return line;
|
|
@@ -2029,8 +2024,8 @@ function createMessageSerializer(kit, contactLookup = emptyContactLookup()) {
|
|
|
2029
2024
|
};
|
|
2030
2025
|
}
|
|
2031
2026
|
|
|
2032
|
-
function buildContactLookup() {
|
|
2033
|
-
const contacts = loadContacts();
|
|
2027
|
+
function buildContactLookup(opts = {}) {
|
|
2028
|
+
const contacts = opts.loadAll === false ? [] : loadContacts();
|
|
2034
2029
|
const myCard = loadMyCard();
|
|
2035
2030
|
const handleToName = new Map();
|
|
2036
2031
|
const selfHandles = new Set();
|
|
@@ -2077,6 +2072,9 @@ function emptyContactLookup() {
|
|
|
2077
2072
|
|
|
2078
2073
|
function loadContacts() {
|
|
2079
2074
|
if (platform() !== "darwin") return [];
|
|
2075
|
+
const sqliteContacts = loadContactsFromAddressBookDb();
|
|
2076
|
+
if (sqliteContacts.length > 0) return sqliteContacts;
|
|
2077
|
+
|
|
2080
2078
|
const script = `
|
|
2081
2079
|
set output to ""
|
|
2082
2080
|
tell application "Contacts"
|
|
@@ -2100,14 +2098,71 @@ return output`;
|
|
|
2100
2098
|
try {
|
|
2101
2099
|
const raw = execFileSync("osascript", ["-e", script], {
|
|
2102
2100
|
encoding: "utf8",
|
|
2103
|
-
timeout:
|
|
2101
|
+
timeout: 120_000,
|
|
2104
2102
|
});
|
|
2105
2103
|
return parseContacts(raw);
|
|
2106
|
-
} catch {
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
if (args.debug === true) console.error("Could not load Contacts:", safeError(err));
|
|
2107
2106
|
return [];
|
|
2108
2107
|
}
|
|
2109
2108
|
}
|
|
2110
2109
|
|
|
2110
|
+
function loadContactsFromAddressBookDb() {
|
|
2111
|
+
const contacts = new Map();
|
|
2112
|
+
for (const dbPath of addressBookDatabasePaths()) {
|
|
2113
|
+
const query = `
|
|
2114
|
+
select r.Z_PK,
|
|
2115
|
+
coalesce(nullif(r.ZNAME, ''), nullif(trim(coalesce(r.ZFIRSTNAME, '') || ' ' || coalesce(r.ZLASTNAME, '')), ''), nullif(r.ZORGANIZATION, ''), '') as display_name,
|
|
2116
|
+
coalesce(p.ZFULLNUMBER, '') as phone,
|
|
2117
|
+
'' as email
|
|
2118
|
+
from ZABCDRECORD r
|
|
2119
|
+
join ZABCDPHONENUMBER p on p.ZOWNER = r.Z_PK
|
|
2120
|
+
where p.ZFULLNUMBER is not null and p.ZFULLNUMBER != ''
|
|
2121
|
+
union all
|
|
2122
|
+
select r.Z_PK,
|
|
2123
|
+
coalesce(nullif(r.ZNAME, ''), nullif(trim(coalesce(r.ZFIRSTNAME, '') || ' ' || coalesce(r.ZLASTNAME, '')), ''), nullif(r.ZORGANIZATION, ''), '') as display_name,
|
|
2124
|
+
'' as phone,
|
|
2125
|
+
coalesce(e.ZADDRESS, '') as email
|
|
2126
|
+
from ZABCDRECORD r
|
|
2127
|
+
join ZABCDEMAILADDRESS e on e.ZOWNER = r.Z_PK
|
|
2128
|
+
where e.ZADDRESS is not null and e.ZADDRESS != '';`;
|
|
2129
|
+
|
|
2130
|
+
try {
|
|
2131
|
+
const raw = execFileSync("sqlite3", ["-separator", "\t", dbPath, query], {
|
|
2132
|
+
encoding: "utf8",
|
|
2133
|
+
timeout: 10_000,
|
|
2134
|
+
});
|
|
2135
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
2136
|
+
const [id, rawName, phone, email] = line.split("\t");
|
|
2137
|
+
const name = rawName?.trim();
|
|
2138
|
+
if (!id || !name) continue;
|
|
2139
|
+
const key = `${dbPath}:${id}`;
|
|
2140
|
+
const current = contacts.get(key) ?? { name, phones: [], emails: [] };
|
|
2141
|
+
if (phone) current.phones.push(phone.trim());
|
|
2142
|
+
if (email) current.emails.push(email.trim());
|
|
2143
|
+
contacts.set(key, current);
|
|
2144
|
+
}
|
|
2145
|
+
} catch (err) {
|
|
2146
|
+
if (args.debug === true) console.error(`Could not read Contacts DB ${dbPath}:`, safeError(err));
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
return [...contacts.values()].filter((contact) => contact.name);
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
function addressBookDatabasePaths() {
|
|
2154
|
+
const addressBookDir = join(homedir(), "Library", "Application Support", "AddressBook");
|
|
2155
|
+
try {
|
|
2156
|
+
const raw = execFileSync("find", [addressBookDir, "-maxdepth", "4", "-name", "AddressBook-v22.abcddb"], {
|
|
2157
|
+
encoding: "utf8",
|
|
2158
|
+
timeout: 5_000,
|
|
2159
|
+
});
|
|
2160
|
+
return [...new Set(raw.split("\n").map((path) => path.trim()).filter(Boolean))];
|
|
2161
|
+
} catch {
|
|
2162
|
+
return [join(addressBookDir, "AddressBook-v22.abcddb")];
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2111
2166
|
function loadMyCard() {
|
|
2112
2167
|
if (platform() !== "darwin") return null;
|
|
2113
2168
|
const script = `
|