jefrichat-mcp 0.12.0 → 0.15.0
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/http.js +37 -13
- package/dist/index.js +41 -14
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -49526,6 +49526,18 @@ var MIME = {
|
|
|
49526
49526
|
".zip": "application/zip"
|
|
49527
49527
|
};
|
|
49528
49528
|
var mimeOf = (name) => MIME[np3.extname(name).toLowerCase()] ?? "application/octet-stream";
|
|
49529
|
+
function fmtTime(iso) {
|
|
49530
|
+
if (!iso) return "";
|
|
49531
|
+
const d = new Date(iso);
|
|
49532
|
+
if (isNaN(d.getTime())) return "";
|
|
49533
|
+
return d.toLocaleString(void 0, {
|
|
49534
|
+
month: "short",
|
|
49535
|
+
day: "numeric",
|
|
49536
|
+
hour: "2-digit",
|
|
49537
|
+
minute: "2-digit",
|
|
49538
|
+
hour12: false
|
|
49539
|
+
});
|
|
49540
|
+
}
|
|
49529
49541
|
function screenshotDir() {
|
|
49530
49542
|
try {
|
|
49531
49543
|
const out = cp2.execFileSync("defaults", ["read", "com.apple.screencapture", "location"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
@@ -49644,22 +49656,30 @@ ${e?.message ?? e}`);
|
|
|
49644
49656
|
"jefri_agents",
|
|
49645
49657
|
{
|
|
49646
49658
|
title: "List your connections",
|
|
49647
|
-
description: "List the people and agents you're connected to (plus your own agents) \u2014 these are who you can message. To reach someone new, use jefri_search to find them, then jefri_connect
|
|
49659
|
+
description: "List the people and agents you're connected to (plus your own agents) \u2014 these are who you can message, with a live \u{1F7E2} online / \u26AA offline indicator for each. NOTE: you can message someone even when they're \u26AA offline \u2014 the message is stored and delivered the moment they reconnect, so never refuse to send just because a recipient is offline. To reach someone new, use jefri_search to find them, then jefri_connect.",
|
|
49648
49660
|
inputSchema: {}
|
|
49649
49661
|
},
|
|
49650
49662
|
async () => withClient(async (c) => {
|
|
49651
49663
|
const all = await c.identities();
|
|
49652
|
-
const
|
|
49653
|
-
|
|
49654
|
-
);
|
|
49655
|
-
|
|
49664
|
+
const others = all.filter((i) => i.username !== c.identity?.username);
|
|
49665
|
+
const isOn = (i) => i.status !== "offline" && !!i.status;
|
|
49666
|
+
others.sort((a, b) => isOn(a) === isOn(b) ? a.username.localeCompare(b.username) : isOn(a) ? -1 : 1);
|
|
49667
|
+
const lines = others.map((i) => {
|
|
49668
|
+
const dot = isOn(i) ? "\u{1F7E2}" : "\u26AA";
|
|
49669
|
+
const live = isOn(i) ? i.status : "offline";
|
|
49670
|
+
return `${dot} @${i.username} \u2014 ${i.displayName} [${i.type}] (${live})${i.owner ? ` \xB7 by @${i.owner}` : ""}${i.tags.length ? " \xB7 " + i.tags.join(", ") : ""}`;
|
|
49671
|
+
});
|
|
49672
|
+
const onCount = others.filter(isOn).length;
|
|
49673
|
+
const header = others.length ? `${onCount} online / ${others.length} total:
|
|
49674
|
+
` : "";
|
|
49675
|
+
return ok(lines.length ? header + lines.join("\n") : "No other identities on the network yet.");
|
|
49656
49676
|
})
|
|
49657
49677
|
);
|
|
49658
49678
|
server.registerTool(
|
|
49659
49679
|
"jefri_send",
|
|
49660
49680
|
{
|
|
49661
49681
|
title: "Send a message",
|
|
49662
|
-
description: "Send a direct message to another Jefri Chat user or agent by username. Use jefri_agents first if you don't know the username.",
|
|
49682
|
+
description: "Send a direct message to another Jefri Chat user or agent by username. Works whether or not they're online \u2014 an offline recipient gets the message the moment they reconnect, so send it regardless of their status. Use jefri_agents first if you don't know the username.",
|
|
49663
49683
|
inputSchema: {
|
|
49664
49684
|
to: external_exports.string().describe("recipient username, e.g. claude_backend"),
|
|
49665
49685
|
text: external_exports.string().describe("the message body")
|
|
@@ -50313,17 +50333,19 @@ ${cmd}`);
|
|
|
50313
50333
|
return name ? ` (in group "${name}" \xB7 reply with jefri_send_group groupId="${m.groupId}")` : ` (in group id ${m.groupId})`;
|
|
50314
50334
|
};
|
|
50315
50335
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
50336
|
+
const ts = fmtTime(m.createdAt);
|
|
50337
|
+
const at = ts ? `[${ts}] ` : "";
|
|
50316
50338
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
50317
50339
|
try {
|
|
50318
50340
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
50319
50341
|
const body2 = plain.kind === "file" ? `\u{1F512}\u{1F4CE} private file: ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`;
|
|
50320
|
-
return
|
|
50342
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body2}`;
|
|
50321
50343
|
} catch {
|
|
50322
|
-
return
|
|
50344
|
+
return `${at}@${m.senderUsername}${where(m)}: \u{1F512} Private message unavailable on this device`;
|
|
50323
50345
|
}
|
|
50324
50346
|
}
|
|
50325
50347
|
const body = m.kind === "file" ? `\u{1F4CE} sent a file: ${m.fileName} \u2014 to save it call jefri_download_file(from: "${m.senderUsername}"${m.fileName ? `, fileName: "${m.fileName}"` : ""})` : m.content;
|
|
50326
|
-
return
|
|
50348
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body}`;
|
|
50327
50349
|
}));
|
|
50328
50350
|
return ok(`\u{1F4E8} ${lines.length} message(s):
|
|
50329
50351
|
` + lines.join("\n"));
|
|
@@ -50444,19 +50466,21 @@ ${cmd}`
|
|
|
50444
50466
|
const msgs = (res?.messages ?? []).slice(-(limit ?? 20));
|
|
50445
50467
|
if (!msgs.length) return ok(`No messages yet in ${label}.`);
|
|
50446
50468
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
50469
|
+
const ts = fmtTime(m.createdAt);
|
|
50470
|
+
const at = ts ? `[${ts}] ` : "";
|
|
50447
50471
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
50448
50472
|
try {
|
|
50449
50473
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
50450
|
-
return `${m.senderUsername}: ${plain.kind === "file" ? `\u{1F512}\u{1F4CE} ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`}`;
|
|
50474
|
+
return `${at}${m.senderUsername}: ${plain.kind === "file" ? `\u{1F512}\u{1F4CE} ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`}`;
|
|
50451
50475
|
} catch {
|
|
50452
|
-
return `${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
50476
|
+
return `${at}${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
50453
50477
|
}
|
|
50454
50478
|
}
|
|
50455
50479
|
if (m.kind === "file") {
|
|
50456
50480
|
const dl = groupId ? `jefri_download_file(groupId: "${groupId}", fileName: "${m.fileName}")` : `jefri_download_file(from: "${m.senderUsername}", fileName: "${m.fileName}")`;
|
|
50457
|
-
return `${m.senderUsername}: \u{1F4CE} ${m.fileName} \u2014 to save it call ${dl}`;
|
|
50481
|
+
return `${at}${m.senderUsername}: \u{1F4CE} ${m.fileName} \u2014 to save it call ${dl}`;
|
|
50458
50482
|
}
|
|
50459
|
-
return `${m.senderUsername}: ${m.content}`;
|
|
50483
|
+
return `${at}${m.senderUsername}: ${m.content}`;
|
|
50460
50484
|
}));
|
|
50461
50485
|
return ok(lines.join("\n"));
|
|
50462
50486
|
})
|
package/dist/index.js
CHANGED
|
@@ -25417,7 +25417,10 @@ function notifyIncoming(m) {
|
|
|
25417
25417
|
}
|
|
25418
25418
|
} else if (process.platform === "win32") {
|
|
25419
25419
|
const esc2 = (x) => x.replace(/'/g, "''");
|
|
25420
|
-
const
|
|
25420
|
+
const xesc = (x) => x.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
25421
|
+
const audio = sound ? `<audio src="ms-winsoundevent:Notification.Default"/>` : `<audio silent="true"/>`;
|
|
25422
|
+
const xml = `<toast><visual><binding template="ToastGeneric"><text>${xesc(title)}</text><text>${xesc(body)}</text></binding></visual>${audio}</toast>`;
|
|
25423
|
+
const ps = `$ErrorActionPreference='Stop';$t='${esc2(title)}';$b='${esc2(body)}';try{[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom, ContentType = WindowsRuntime] | Out-Null;$d=New-Object Windows.Data.Xml.Dom.XmlDocument;$d.LoadXml('${xml}');$toast=New-Object Windows.UI.Notifications.ToastNotification -ArgumentList $d;[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe').Show($toast);Start-Sleep -Milliseconds 400;}catch{Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$n=New-Object System.Windows.Forms.NotifyIcon;$n.Icon=[System.Drawing.SystemIcons]::Information;$n.BalloonTipTitle=$t;$n.BalloonTipText=$b;$n.Visible=$true;$n.ShowBalloonTip(6000);Start-Sleep -Milliseconds 6500;$n.Dispose();}`;
|
|
25421
25424
|
cp.spawn("powershell", ["-NoProfile", "-WindowStyle", "Hidden", "-Command", ps], { stdio: "ignore", detached: true }).unref();
|
|
25422
25425
|
} else {
|
|
25423
25426
|
cp.spawn("notify-send", ["-a", "Jefri Chat", title, body], { stdio: "ignore", detached: true }).unref();
|
|
@@ -25613,6 +25616,18 @@ var MIME = {
|
|
|
25613
25616
|
".zip": "application/zip"
|
|
25614
25617
|
};
|
|
25615
25618
|
var mimeOf = (name) => MIME[np3.extname(name).toLowerCase()] ?? "application/octet-stream";
|
|
25619
|
+
function fmtTime(iso) {
|
|
25620
|
+
if (!iso) return "";
|
|
25621
|
+
const d = new Date(iso);
|
|
25622
|
+
if (isNaN(d.getTime())) return "";
|
|
25623
|
+
return d.toLocaleString(void 0, {
|
|
25624
|
+
month: "short",
|
|
25625
|
+
day: "numeric",
|
|
25626
|
+
hour: "2-digit",
|
|
25627
|
+
minute: "2-digit",
|
|
25628
|
+
hour12: false
|
|
25629
|
+
});
|
|
25630
|
+
}
|
|
25616
25631
|
function screenshotDir() {
|
|
25617
25632
|
try {
|
|
25618
25633
|
const out = cp3.execFileSync("defaults", ["read", "com.apple.screencapture", "location"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
@@ -25731,22 +25746,30 @@ ${e?.message ?? e}`);
|
|
|
25731
25746
|
"jefri_agents",
|
|
25732
25747
|
{
|
|
25733
25748
|
title: "List your connections",
|
|
25734
|
-
description: "List the people and agents you're connected to (plus your own agents) \u2014 these are who you can message. To reach someone new, use jefri_search to find them, then jefri_connect
|
|
25749
|
+
description: "List the people and agents you're connected to (plus your own agents) \u2014 these are who you can message, with a live \u{1F7E2} online / \u26AA offline indicator for each. NOTE: you can message someone even when they're \u26AA offline \u2014 the message is stored and delivered the moment they reconnect, so never refuse to send just because a recipient is offline. To reach someone new, use jefri_search to find them, then jefri_connect.",
|
|
25735
25750
|
inputSchema: {}
|
|
25736
25751
|
},
|
|
25737
25752
|
async () => withClient(async (c) => {
|
|
25738
25753
|
const all = await c.identities();
|
|
25739
|
-
const
|
|
25740
|
-
|
|
25741
|
-
);
|
|
25742
|
-
|
|
25754
|
+
const others = all.filter((i) => i.username !== c.identity?.username);
|
|
25755
|
+
const isOn = (i) => i.status !== "offline" && !!i.status;
|
|
25756
|
+
others.sort((a, b) => isOn(a) === isOn(b) ? a.username.localeCompare(b.username) : isOn(a) ? -1 : 1);
|
|
25757
|
+
const lines = others.map((i) => {
|
|
25758
|
+
const dot = isOn(i) ? "\u{1F7E2}" : "\u26AA";
|
|
25759
|
+
const live = isOn(i) ? i.status : "offline";
|
|
25760
|
+
return `${dot} @${i.username} \u2014 ${i.displayName} [${i.type}] (${live})${i.owner ? ` \xB7 by @${i.owner}` : ""}${i.tags.length ? " \xB7 " + i.tags.join(", ") : ""}`;
|
|
25761
|
+
});
|
|
25762
|
+
const onCount = others.filter(isOn).length;
|
|
25763
|
+
const header = others.length ? `${onCount} online / ${others.length} total:
|
|
25764
|
+
` : "";
|
|
25765
|
+
return ok(lines.length ? header + lines.join("\n") : "No other identities on the network yet.");
|
|
25743
25766
|
})
|
|
25744
25767
|
);
|
|
25745
25768
|
server2.registerTool(
|
|
25746
25769
|
"jefri_send",
|
|
25747
25770
|
{
|
|
25748
25771
|
title: "Send a message",
|
|
25749
|
-
description: "Send a direct message to another Jefri Chat user or agent by username. Use jefri_agents first if you don't know the username.",
|
|
25772
|
+
description: "Send a direct message to another Jefri Chat user or agent by username. Works whether or not they're online \u2014 an offline recipient gets the message the moment they reconnect, so send it regardless of their status. Use jefri_agents first if you don't know the username.",
|
|
25750
25773
|
inputSchema: {
|
|
25751
25774
|
to: external_exports.string().describe("recipient username, e.g. claude_backend"),
|
|
25752
25775
|
text: external_exports.string().describe("the message body")
|
|
@@ -26400,17 +26423,19 @@ ${cmd}`);
|
|
|
26400
26423
|
return name ? ` (in group "${name}" \xB7 reply with jefri_send_group groupId="${m.groupId}")` : ` (in group id ${m.groupId})`;
|
|
26401
26424
|
};
|
|
26402
26425
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26426
|
+
const ts = fmtTime(m.createdAt);
|
|
26427
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26403
26428
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26404
26429
|
try {
|
|
26405
26430
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
26406
26431
|
const body2 = plain.kind === "file" ? `\u{1F512}\u{1F4CE} private file: ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`;
|
|
26407
|
-
return
|
|
26432
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body2}`;
|
|
26408
26433
|
} catch {
|
|
26409
|
-
return
|
|
26434
|
+
return `${at}@${m.senderUsername}${where(m)}: \u{1F512} Private message unavailable on this device`;
|
|
26410
26435
|
}
|
|
26411
26436
|
}
|
|
26412
26437
|
const body = m.kind === "file" ? `\u{1F4CE} sent a file: ${m.fileName} \u2014 to save it call jefri_download_file(from: "${m.senderUsername}"${m.fileName ? `, fileName: "${m.fileName}"` : ""})` : m.content;
|
|
26413
|
-
return
|
|
26438
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body}`;
|
|
26414
26439
|
}));
|
|
26415
26440
|
return ok(`\u{1F4E8} ${lines.length} message(s):
|
|
26416
26441
|
` + lines.join("\n"));
|
|
@@ -26531,19 +26556,21 @@ ${cmd}`
|
|
|
26531
26556
|
const msgs = (res?.messages ?? []).slice(-(limit ?? 20));
|
|
26532
26557
|
if (!msgs.length) return ok(`No messages yet in ${label}.`);
|
|
26533
26558
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26559
|
+
const ts = fmtTime(m.createdAt);
|
|
26560
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26534
26561
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26535
26562
|
try {
|
|
26536
26563
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
26537
|
-
return `${m.senderUsername}: ${plain.kind === "file" ? `\u{1F512}\u{1F4CE} ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`}`;
|
|
26564
|
+
return `${at}${m.senderUsername}: ${plain.kind === "file" ? `\u{1F512}\u{1F4CE} ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`}`;
|
|
26538
26565
|
} catch {
|
|
26539
|
-
return `${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26566
|
+
return `${at}${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26540
26567
|
}
|
|
26541
26568
|
}
|
|
26542
26569
|
if (m.kind === "file") {
|
|
26543
26570
|
const dl = groupId ? `jefri_download_file(groupId: "${groupId}", fileName: "${m.fileName}")` : `jefri_download_file(from: "${m.senderUsername}", fileName: "${m.fileName}")`;
|
|
26544
|
-
return `${m.senderUsername}: \u{1F4CE} ${m.fileName} \u2014 to save it call ${dl}`;
|
|
26571
|
+
return `${at}${m.senderUsername}: \u{1F4CE} ${m.fileName} \u2014 to save it call ${dl}`;
|
|
26545
26572
|
}
|
|
26546
|
-
return `${m.senderUsername}: ${m.content}`;
|
|
26573
|
+
return `${at}${m.senderUsername}: ${m.content}`;
|
|
26547
26574
|
}));
|
|
26548
26575
|
return ok(lines.join("\n"));
|
|
26549
26576
|
})
|
package/package.json
CHANGED