jefrichat-mcp 0.12.0 → 0.13.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 +39 -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,8 @@ function notifyIncoming(m) {
|
|
|
25417
25417
|
}
|
|
25418
25418
|
} else if (process.platform === "win32") {
|
|
25419
25419
|
const esc2 = (x) => x.replace(/'/g, "''");
|
|
25420
|
-
const
|
|
25420
|
+
const silent = sound ? "" : `$a=$tpl.CreateElement('audio');$a.SetAttribute('silent','true');$tpl.DocumentElement.AppendChild($a)|Out-Null;`;
|
|
25421
|
+
const ps = `$t='${esc2(title)}';$b='${esc2(body)}';try{$null=[Windows.UI.Notifications.ToastNotificationManager,Windows.UI.Notifications,ContentType=WindowsRuntime];$tpl=[Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02);$x=$tpl.GetElementsByTagName('text');$x.Item(0).AppendChild($tpl.CreateTextNode($t))|Out-Null;$x.Item(1).AppendChild($tpl.CreateTextNode($b))|Out-Null;` + silent + `$toast=[Windows.UI.Notifications.ToastNotification]::new($tpl);[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe').Show($toast);}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
25422
|
cp.spawn("powershell", ["-NoProfile", "-WindowStyle", "Hidden", "-Command", ps], { stdio: "ignore", detached: true }).unref();
|
|
25422
25423
|
} else {
|
|
25423
25424
|
cp.spawn("notify-send", ["-a", "Jefri Chat", title, body], { stdio: "ignore", detached: true }).unref();
|
|
@@ -25613,6 +25614,18 @@ var MIME = {
|
|
|
25613
25614
|
".zip": "application/zip"
|
|
25614
25615
|
};
|
|
25615
25616
|
var mimeOf = (name) => MIME[np3.extname(name).toLowerCase()] ?? "application/octet-stream";
|
|
25617
|
+
function fmtTime(iso) {
|
|
25618
|
+
if (!iso) return "";
|
|
25619
|
+
const d = new Date(iso);
|
|
25620
|
+
if (isNaN(d.getTime())) return "";
|
|
25621
|
+
return d.toLocaleString(void 0, {
|
|
25622
|
+
month: "short",
|
|
25623
|
+
day: "numeric",
|
|
25624
|
+
hour: "2-digit",
|
|
25625
|
+
minute: "2-digit",
|
|
25626
|
+
hour12: false
|
|
25627
|
+
});
|
|
25628
|
+
}
|
|
25616
25629
|
function screenshotDir() {
|
|
25617
25630
|
try {
|
|
25618
25631
|
const out = cp3.execFileSync("defaults", ["read", "com.apple.screencapture", "location"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
@@ -25731,22 +25744,30 @@ ${e?.message ?? e}`);
|
|
|
25731
25744
|
"jefri_agents",
|
|
25732
25745
|
{
|
|
25733
25746
|
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
|
|
25747
|
+
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
25748
|
inputSchema: {}
|
|
25736
25749
|
},
|
|
25737
25750
|
async () => withClient(async (c) => {
|
|
25738
25751
|
const all = await c.identities();
|
|
25739
|
-
const
|
|
25740
|
-
|
|
25741
|
-
);
|
|
25742
|
-
|
|
25752
|
+
const others = all.filter((i) => i.username !== c.identity?.username);
|
|
25753
|
+
const isOn = (i) => i.status !== "offline" && !!i.status;
|
|
25754
|
+
others.sort((a, b) => isOn(a) === isOn(b) ? a.username.localeCompare(b.username) : isOn(a) ? -1 : 1);
|
|
25755
|
+
const lines = others.map((i) => {
|
|
25756
|
+
const dot = isOn(i) ? "\u{1F7E2}" : "\u26AA";
|
|
25757
|
+
const live = isOn(i) ? i.status : "offline";
|
|
25758
|
+
return `${dot} @${i.username} \u2014 ${i.displayName} [${i.type}] (${live})${i.owner ? ` \xB7 by @${i.owner}` : ""}${i.tags.length ? " \xB7 " + i.tags.join(", ") : ""}`;
|
|
25759
|
+
});
|
|
25760
|
+
const onCount = others.filter(isOn).length;
|
|
25761
|
+
const header = others.length ? `${onCount} online / ${others.length} total:
|
|
25762
|
+
` : "";
|
|
25763
|
+
return ok(lines.length ? header + lines.join("\n") : "No other identities on the network yet.");
|
|
25743
25764
|
})
|
|
25744
25765
|
);
|
|
25745
25766
|
server2.registerTool(
|
|
25746
25767
|
"jefri_send",
|
|
25747
25768
|
{
|
|
25748
25769
|
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.",
|
|
25770
|
+
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
25771
|
inputSchema: {
|
|
25751
25772
|
to: external_exports.string().describe("recipient username, e.g. claude_backend"),
|
|
25752
25773
|
text: external_exports.string().describe("the message body")
|
|
@@ -26400,17 +26421,19 @@ ${cmd}`);
|
|
|
26400
26421
|
return name ? ` (in group "${name}" \xB7 reply with jefri_send_group groupId="${m.groupId}")` : ` (in group id ${m.groupId})`;
|
|
26401
26422
|
};
|
|
26402
26423
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26424
|
+
const ts = fmtTime(m.createdAt);
|
|
26425
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26403
26426
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26404
26427
|
try {
|
|
26405
26428
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
26406
26429
|
const body2 = plain.kind === "file" ? `\u{1F512}\u{1F4CE} private file: ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`;
|
|
26407
|
-
return
|
|
26430
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body2}`;
|
|
26408
26431
|
} catch {
|
|
26409
|
-
return
|
|
26432
|
+
return `${at}@${m.senderUsername}${where(m)}: \u{1F512} Private message unavailable on this device`;
|
|
26410
26433
|
}
|
|
26411
26434
|
}
|
|
26412
26435
|
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
|
|
26436
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body}`;
|
|
26414
26437
|
}));
|
|
26415
26438
|
return ok(`\u{1F4E8} ${lines.length} message(s):
|
|
26416
26439
|
` + lines.join("\n"));
|
|
@@ -26531,19 +26554,21 @@ ${cmd}`
|
|
|
26531
26554
|
const msgs = (res?.messages ?? []).slice(-(limit ?? 20));
|
|
26532
26555
|
if (!msgs.length) return ok(`No messages yet in ${label}.`);
|
|
26533
26556
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26557
|
+
const ts = fmtTime(m.createdAt);
|
|
26558
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26534
26559
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26535
26560
|
try {
|
|
26536
26561
|
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 ?? ""}`}`;
|
|
26562
|
+
return `${at}${m.senderUsername}: ${plain.kind === "file" ? `\u{1F512}\u{1F4CE} ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`}`;
|
|
26538
26563
|
} catch {
|
|
26539
|
-
return `${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26564
|
+
return `${at}${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26540
26565
|
}
|
|
26541
26566
|
}
|
|
26542
26567
|
if (m.kind === "file") {
|
|
26543
26568
|
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}`;
|
|
26569
|
+
return `${at}${m.senderUsername}: \u{1F4CE} ${m.fileName} \u2014 to save it call ${dl}`;
|
|
26545
26570
|
}
|
|
26546
|
-
return `${m.senderUsername}: ${m.content}`;
|
|
26571
|
+
return `${at}${m.senderUsername}: ${m.content}`;
|
|
26547
26572
|
}));
|
|
26548
26573
|
return ok(lines.join("\n"));
|
|
26549
26574
|
})
|
package/package.json
CHANGED