shepherd-onboard 0.1.16 → 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 +85 -23
- package/package.json +1 -1
package/bin/shepherd-onboard.js
CHANGED
|
@@ -1356,15 +1356,15 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1356
1356
|
<title>Select Messages Chats</title>
|
|
1357
1357
|
<style>
|
|
1358
1358
|
:root {
|
|
1359
|
-
--bg: #
|
|
1359
|
+
--bg: #ffffff;
|
|
1360
1360
|
--fg: #141614;
|
|
1361
|
-
--muted: #
|
|
1362
|
-
--faint: #
|
|
1363
|
-
--line: #
|
|
1361
|
+
--muted: #615d59;
|
|
1362
|
+
--faint: #a39e98;
|
|
1363
|
+
--line: #e6e6e6;
|
|
1364
1364
|
--green: #1f5c2e;
|
|
1365
1365
|
--green-hover: #246836;
|
|
1366
1366
|
--radius: 8px;
|
|
1367
|
-
--grid: 20px minmax(0, 1fr)
|
|
1367
|
+
--grid: 20px minmax(0, 1fr) 76px 108px;
|
|
1368
1368
|
}
|
|
1369
1369
|
* { box-sizing: border-box; }
|
|
1370
1370
|
body {
|
|
@@ -1377,9 +1377,9 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1377
1377
|
-webkit-font-smoothing: antialiased;
|
|
1378
1378
|
}
|
|
1379
1379
|
main {
|
|
1380
|
-
width: min(
|
|
1380
|
+
width: min(640px, calc(100vw - 32px));
|
|
1381
1381
|
margin: 0 auto;
|
|
1382
|
-
padding:
|
|
1382
|
+
padding: 56px 0 28px;
|
|
1383
1383
|
}
|
|
1384
1384
|
.header {
|
|
1385
1385
|
display: grid;
|
|
@@ -1390,7 +1390,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1390
1390
|
.brand {
|
|
1391
1391
|
display: grid;
|
|
1392
1392
|
justify-items: center;
|
|
1393
|
-
gap:
|
|
1393
|
+
gap: 16px;
|
|
1394
1394
|
min-width: 0;
|
|
1395
1395
|
}
|
|
1396
1396
|
.logo {
|
|
@@ -1412,14 +1412,14 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1412
1412
|
}
|
|
1413
1413
|
h1 {
|
|
1414
1414
|
margin: 0;
|
|
1415
|
-
font-size:
|
|
1415
|
+
font-size: 30px;
|
|
1416
1416
|
line-height: 1.1;
|
|
1417
1417
|
font-weight: 700;
|
|
1418
1418
|
letter-spacing: 0;
|
|
1419
1419
|
}
|
|
1420
1420
|
.subtitle {
|
|
1421
1421
|
margin: 8px 0 0;
|
|
1422
|
-
font-size:
|
|
1422
|
+
font-size: 14px;
|
|
1423
1423
|
line-height: 1.4;
|
|
1424
1424
|
color: var(--muted);
|
|
1425
1425
|
}
|
|
@@ -1431,11 +1431,11 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1431
1431
|
}
|
|
1432
1432
|
.search {
|
|
1433
1433
|
width: 100%;
|
|
1434
|
-
border: 1px solid
|
|
1434
|
+
border: 1px solid var(--line);
|
|
1435
1435
|
border-radius: 8px;
|
|
1436
1436
|
background: #ffffff;
|
|
1437
1437
|
color: var(--fg);
|
|
1438
|
-
padding:
|
|
1438
|
+
padding: 12px 13px;
|
|
1439
1439
|
font: inherit;
|
|
1440
1440
|
font-size: 15px;
|
|
1441
1441
|
outline: none;
|
|
@@ -1463,6 +1463,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1463
1463
|
font-size: 11px;
|
|
1464
1464
|
font-weight: 600;
|
|
1465
1465
|
text-transform: uppercase;
|
|
1466
|
+
letter-spacing: 0.02em;
|
|
1466
1467
|
}
|
|
1467
1468
|
.list-head .right { text-align: left; }
|
|
1468
1469
|
.chat-list { display: block; }
|
|
@@ -1476,7 +1477,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1476
1477
|
cursor: pointer;
|
|
1477
1478
|
transition: background 120ms ease;
|
|
1478
1479
|
}
|
|
1479
|
-
.chat-row:hover { background: #
|
|
1480
|
+
.chat-row:hover { background: #f6f5f4; }
|
|
1480
1481
|
input[type="checkbox"] {
|
|
1481
1482
|
position: absolute;
|
|
1482
1483
|
opacity: 0;
|
|
@@ -1514,7 +1515,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1514
1515
|
text-overflow: ellipsis;
|
|
1515
1516
|
white-space: nowrap;
|
|
1516
1517
|
font-size: 15px;
|
|
1517
|
-
font-weight:
|
|
1518
|
+
font-weight: 500;
|
|
1518
1519
|
}
|
|
1519
1520
|
.chat-people {
|
|
1520
1521
|
color: var(--muted);
|
|
@@ -1528,9 +1529,9 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1528
1529
|
justify-self: start;
|
|
1529
1530
|
color: var(--muted);
|
|
1530
1531
|
font-size: 12.5px;
|
|
1531
|
-
font-weight:
|
|
1532
|
+
font-weight: 400;
|
|
1532
1533
|
}
|
|
1533
|
-
.chat-kind--group { color: var(--
|
|
1534
|
+
.chat-kind--group { color: var(--fg); }
|
|
1534
1535
|
.chat-meta {
|
|
1535
1536
|
color: var(--muted);
|
|
1536
1537
|
font-size: 12.5px;
|
|
@@ -1563,7 +1564,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1563
1564
|
button {
|
|
1564
1565
|
appearance: none;
|
|
1565
1566
|
border: 0;
|
|
1566
|
-
border-radius:
|
|
1567
|
+
border-radius: 8px;
|
|
1567
1568
|
background: var(--green);
|
|
1568
1569
|
color: #FFFFFF;
|
|
1569
1570
|
padding: 9px 13px;
|
|
@@ -1600,7 +1601,6 @@ function renderMessagesSelectorPage(chats, token, error = "") {
|
|
|
1600
1601
|
</div>
|
|
1601
1602
|
${error ? `<p class="error">${html(error)}</p>` : ""}
|
|
1602
1603
|
<div class="list-head">
|
|
1603
|
-
<span></span>
|
|
1604
1604
|
<span></span>
|
|
1605
1605
|
<span>Name</span>
|
|
1606
1606
|
<span>Type</span>
|
|
@@ -1685,7 +1685,9 @@ function renderChatPeople(chat) {
|
|
|
1685
1685
|
|
|
1686
1686
|
function chatPeopleLine(chat) {
|
|
1687
1687
|
if (chat.kind !== "group") return "";
|
|
1688
|
-
const names = chat.participants
|
|
1688
|
+
const names = chat.participants
|
|
1689
|
+
?.map((participant) => participant.name)
|
|
1690
|
+
.filter((name) => name && !looksLikeHandleList(name)) ?? [];
|
|
1689
1691
|
const line = names.slice(0, 6).join(", ");
|
|
1690
1692
|
if (!line || normalizeDisplayText(line) === normalizeDisplayText(chat.label)) return "";
|
|
1691
1693
|
return line;
|
|
@@ -2022,8 +2024,8 @@ function createMessageSerializer(kit, contactLookup = emptyContactLookup()) {
|
|
|
2022
2024
|
};
|
|
2023
2025
|
}
|
|
2024
2026
|
|
|
2025
|
-
function buildContactLookup() {
|
|
2026
|
-
const contacts = loadContacts();
|
|
2027
|
+
function buildContactLookup(opts = {}) {
|
|
2028
|
+
const contacts = opts.loadAll === false ? [] : loadContacts();
|
|
2027
2029
|
const myCard = loadMyCard();
|
|
2028
2030
|
const handleToName = new Map();
|
|
2029
2031
|
const selfHandles = new Set();
|
|
@@ -2070,6 +2072,9 @@ function emptyContactLookup() {
|
|
|
2070
2072
|
|
|
2071
2073
|
function loadContacts() {
|
|
2072
2074
|
if (platform() !== "darwin") return [];
|
|
2075
|
+
const sqliteContacts = loadContactsFromAddressBookDb();
|
|
2076
|
+
if (sqliteContacts.length > 0) return sqliteContacts;
|
|
2077
|
+
|
|
2073
2078
|
const script = `
|
|
2074
2079
|
set output to ""
|
|
2075
2080
|
tell application "Contacts"
|
|
@@ -2093,14 +2098,71 @@ return output`;
|
|
|
2093
2098
|
try {
|
|
2094
2099
|
const raw = execFileSync("osascript", ["-e", script], {
|
|
2095
2100
|
encoding: "utf8",
|
|
2096
|
-
timeout:
|
|
2101
|
+
timeout: 120_000,
|
|
2097
2102
|
});
|
|
2098
2103
|
return parseContacts(raw);
|
|
2099
|
-
} catch {
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
if (args.debug === true) console.error("Could not load Contacts:", safeError(err));
|
|
2100
2106
|
return [];
|
|
2101
2107
|
}
|
|
2102
2108
|
}
|
|
2103
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
|
+
|
|
2104
2166
|
function loadMyCard() {
|
|
2105
2167
|
if (platform() !== "darwin") return null;
|
|
2106
2168
|
const script = `
|