jefrichat-mcp 0.9.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 +56 -16
- package/dist/index.js +362 -126
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -49471,16 +49471,21 @@ function setPrefs(patch) {
|
|
|
49471
49471
|
import fs3 from "node:fs";
|
|
49472
49472
|
import np2 from "node:path";
|
|
49473
49473
|
import os3 from "node:os";
|
|
49474
|
+
var DEFAULT_TEMPLATE = '{persona}You are @{me}, an autonomous agent on Jefri Chat. A message came in{where}. It may address several agents by @name (e.g. "@alice: do X @bob: do Y") \u2014 do ONLY the part addressed to you (@{me}); ignore parts meant for other agents. If nothing is addressed to you, reply with nothing to do. You can do ANYTHING (research, writing, analysis, code, running tools) \u2014 not just code. If a CLAUDE.md or relevant files are in this folder, read them first to get oriented. If the request is unclear, reply with ONE short clarifying question and stop (only your owner will answer). Otherwise do your part and reply concisely with the result.\n\n{context}Latest message from @{sender}: {message}';
|
|
49474
49475
|
var DEFAULTS2 = {
|
|
49475
49476
|
enabled: false,
|
|
49476
49477
|
brain: "claude",
|
|
49477
49478
|
workdir: process.cwd(),
|
|
49478
49479
|
replyMode: "mentions",
|
|
49479
49480
|
persona: "",
|
|
49480
|
-
replyToBots: false
|
|
49481
|
+
replyToBots: false,
|
|
49482
|
+
ownerOnly: false,
|
|
49483
|
+
contextMessages: 12,
|
|
49484
|
+
promptTemplate: DEFAULT_TEMPLATE
|
|
49481
49485
|
};
|
|
49482
49486
|
var DIR = np2.join(os3.homedir(), ".jefri");
|
|
49483
49487
|
var FILE = np2.join(DIR, "autonomous.json");
|
|
49488
|
+
var LOG_FILE = np2.join(DIR, "autonomous.log");
|
|
49484
49489
|
function loadCfg() {
|
|
49485
49490
|
try {
|
|
49486
49491
|
return { ...DEFAULTS2, ...JSON.parse(fs3.readFileSync(FILE, "utf8")) };
|
|
@@ -49521,6 +49526,18 @@ var MIME = {
|
|
|
49521
49526
|
".zip": "application/zip"
|
|
49522
49527
|
};
|
|
49523
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
|
+
}
|
|
49524
49541
|
function screenshotDir() {
|
|
49525
49542
|
try {
|
|
49526
49543
|
const out = cp2.execFileSync("defaults", ["read", "com.apple.screencapture", "location"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
@@ -49639,22 +49656,30 @@ ${e?.message ?? e}`);
|
|
|
49639
49656
|
"jefri_agents",
|
|
49640
49657
|
{
|
|
49641
49658
|
title: "List your connections",
|
|
49642
|
-
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.",
|
|
49643
49660
|
inputSchema: {}
|
|
49644
49661
|
},
|
|
49645
49662
|
async () => withClient(async (c) => {
|
|
49646
49663
|
const all = await c.identities();
|
|
49647
|
-
const
|
|
49648
|
-
|
|
49649
|
-
);
|
|
49650
|
-
|
|
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.");
|
|
49651
49676
|
})
|
|
49652
49677
|
);
|
|
49653
49678
|
server.registerTool(
|
|
49654
49679
|
"jefri_send",
|
|
49655
49680
|
{
|
|
49656
49681
|
title: "Send a message",
|
|
49657
|
-
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.",
|
|
49658
49683
|
inputSchema: {
|
|
49659
49684
|
to: external_exports.string().describe("recipient username, e.g. claude_backend"),
|
|
49660
49685
|
text: external_exports.string().describe("the message body")
|
|
@@ -50308,17 +50333,19 @@ ${cmd}`);
|
|
|
50308
50333
|
return name ? ` (in group "${name}" \xB7 reply with jefri_send_group groupId="${m.groupId}")` : ` (in group id ${m.groupId})`;
|
|
50309
50334
|
};
|
|
50310
50335
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
50336
|
+
const ts = fmtTime(m.createdAt);
|
|
50337
|
+
const at = ts ? `[${ts}] ` : "";
|
|
50311
50338
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
50312
50339
|
try {
|
|
50313
50340
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
50314
50341
|
const body2 = plain.kind === "file" ? `\u{1F512}\u{1F4CE} private file: ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`;
|
|
50315
|
-
return
|
|
50342
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body2}`;
|
|
50316
50343
|
} catch {
|
|
50317
|
-
return
|
|
50344
|
+
return `${at}@${m.senderUsername}${where(m)}: \u{1F512} Private message unavailable on this device`;
|
|
50318
50345
|
}
|
|
50319
50346
|
}
|
|
50320
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;
|
|
50321
|
-
return
|
|
50348
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body}`;
|
|
50322
50349
|
}));
|
|
50323
50350
|
return ok(`\u{1F4E8} ${lines.length} message(s):
|
|
50324
50351
|
` + lines.join("\n"));
|
|
@@ -50439,19 +50466,21 @@ ${cmd}`
|
|
|
50439
50466
|
const msgs = (res?.messages ?? []).slice(-(limit ?? 20));
|
|
50440
50467
|
if (!msgs.length) return ok(`No messages yet in ${label}.`);
|
|
50441
50468
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
50469
|
+
const ts = fmtTime(m.createdAt);
|
|
50470
|
+
const at = ts ? `[${ts}] ` : "";
|
|
50442
50471
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
50443
50472
|
try {
|
|
50444
50473
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
50445
|
-
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 ?? ""}`}`;
|
|
50446
50475
|
} catch {
|
|
50447
|
-
return `${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
50476
|
+
return `${at}${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
50448
50477
|
}
|
|
50449
50478
|
}
|
|
50450
50479
|
if (m.kind === "file") {
|
|
50451
50480
|
const dl = groupId ? `jefri_download_file(groupId: "${groupId}", fileName: "${m.fileName}")` : `jefri_download_file(from: "${m.senderUsername}", fileName: "${m.fileName}")`;
|
|
50452
|
-
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}`;
|
|
50453
50482
|
}
|
|
50454
|
-
return `${m.senderUsername}: ${m.content}`;
|
|
50483
|
+
return `${at}${m.senderUsername}: ${m.content}`;
|
|
50455
50484
|
}));
|
|
50456
50485
|
return ok(lines.join("\n"));
|
|
50457
50486
|
})
|
|
@@ -50607,7 +50636,10 @@ ${cmd}`
|
|
|
50607
50636
|
brain: external_exports.string().optional().describe("'claude', 'codex', or a full custom command (e.g. for OpenClaw)"),
|
|
50608
50637
|
workdir: external_exports.string().optional().describe("folder the brain works in (scope it!)"),
|
|
50609
50638
|
replyMode: external_exports.enum(["mentions", "dms", "all"]).optional().describe("groups: mentions=only when @-mentioned, all=every message, dms=DMs only"),
|
|
50610
|
-
persona: external_exports.string().optional().describe("role/instructions for the agent"),
|
|
50639
|
+
persona: external_exports.string().optional().describe("role/instructions for the agent (injected as {persona})"),
|
|
50640
|
+
promptTemplate: external_exports.string().optional().describe("advanced: fully customize how the message is framed to the brain. Placeholders: {persona} {me} {sender} {where} {context} {message}. Pass 'default' to reset."),
|
|
50641
|
+
ownerOnly: external_exports.boolean().optional().describe("only act on messages from your OWNER \u2014 ignore other people (great for a private agent team). Default off."),
|
|
50642
|
+
contextMessages: external_exports.number().optional().describe("how many recent messages of the conversation to give the brain for memory (0 = stateless, default 12)"),
|
|
50611
50643
|
replyToBots: external_exports.boolean().optional().describe("also auto-reply to other agents (default off \u2014 prevents bot loops)")
|
|
50612
50644
|
}
|
|
50613
50645
|
},
|
|
@@ -50615,9 +50647,13 @@ ${cmd}`
|
|
|
50615
50647
|
const patch = {};
|
|
50616
50648
|
if (typeof args.enabled === "boolean") patch.enabled = args.enabled;
|
|
50617
50649
|
if (typeof args.replyToBots === "boolean") patch.replyToBots = args.replyToBots;
|
|
50650
|
+
if (typeof args.ownerOnly === "boolean") patch.ownerOnly = args.ownerOnly;
|
|
50651
|
+
if (typeof args.contextMessages === "number") patch.contextMessages = Math.max(0, Math.min(40, Math.floor(args.contextMessages)));
|
|
50618
50652
|
if (typeof args.brain === "string" && args.brain.trim()) patch.brain = args.brain.trim();
|
|
50619
50653
|
if (typeof args.workdir === "string" && args.workdir.trim()) patch.workdir = args.workdir.trim();
|
|
50620
50654
|
if (typeof args.persona === "string") patch.persona = args.persona;
|
|
50655
|
+
if (typeof args.promptTemplate === "string" && args.promptTemplate.trim())
|
|
50656
|
+
patch.promptTemplate = args.promptTemplate.trim().toLowerCase() === "default" ? DEFAULT_TEMPLATE : args.promptTemplate;
|
|
50621
50657
|
if (args.replyMode) patch.replyMode = args.replyMode;
|
|
50622
50658
|
const c = setAuto(patch);
|
|
50623
50659
|
const modeLabel = c.replyMode === "all" ? "every message" : c.replyMode === "dms" ? "DMs only" : "DMs + group @mentions";
|
|
@@ -50626,8 +50662,12 @@ ${cmd}`
|
|
|
50626
50662
|
` Brain: ${c.brain}`,
|
|
50627
50663
|
` Work folder: ${c.workdir}`,
|
|
50628
50664
|
` Replies to: ${modeLabel}`,
|
|
50665
|
+
` Owner-only: ${c.ownerOnly ? "yes (only you direct me)" : "no (anyone who @mentions me)"}`,
|
|
50629
50666
|
` Persona: ${c.persona ? c.persona.slice(0, 80) : "(none)"}`,
|
|
50630
|
-
`
|
|
50667
|
+
` Conversation memory: ${c.contextMessages > 0 ? `last ${c.contextMessages} messages` : "off"}`,
|
|
50668
|
+
` Prompt: ${c.promptTemplate === DEFAULT_TEMPLATE ? "default (@name routing + ask-if-unclear)" : "custom"}`,
|
|
50669
|
+
` Reply to other bots: ${c.replyToBots ? "yes" : "no"}`,
|
|
50670
|
+
` Activity log: ~/.jefri/autonomous.log (watch it: tail -f ~/.jefri/autonomous.log)`
|
|
50631
50671
|
];
|
|
50632
50672
|
if (c.enabled)
|
|
50633
50673
|
lines.push(`
|
package/dist/index.js
CHANGED
|
@@ -6883,12 +6883,12 @@ var require_dist = __commonJS({
|
|
|
6883
6883
|
throw new Error(`Unknown format "${name}"`);
|
|
6884
6884
|
return f;
|
|
6885
6885
|
};
|
|
6886
|
-
function addFormats(ajv, list,
|
|
6886
|
+
function addFormats(ajv, list, fs7, exportName) {
|
|
6887
6887
|
var _a;
|
|
6888
6888
|
var _b;
|
|
6889
6889
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6890
6890
|
for (const f of list)
|
|
6891
|
-
ajv.addFormat(f,
|
|
6891
|
+
ajv.addFormat(f, fs7[f]);
|
|
6892
6892
|
}
|
|
6893
6893
|
module.exports = exports = formatsPlugin;
|
|
6894
6894
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -6940,14 +6940,14 @@ var require_buffer_util = __commonJS({
|
|
|
6940
6940
|
}
|
|
6941
6941
|
return target;
|
|
6942
6942
|
}
|
|
6943
|
-
function _mask(source,
|
|
6943
|
+
function _mask(source, mask2, output, offset, length) {
|
|
6944
6944
|
for (let i = 0; i < length; i++) {
|
|
6945
|
-
output[offset + i] = source[i] ^
|
|
6945
|
+
output[offset + i] = source[i] ^ mask2[i & 3];
|
|
6946
6946
|
}
|
|
6947
6947
|
}
|
|
6948
|
-
function _unmask(buffer,
|
|
6948
|
+
function _unmask(buffer, mask2) {
|
|
6949
6949
|
for (let i = 0; i < buffer.length; i++) {
|
|
6950
|
-
buffer[i] ^=
|
|
6950
|
+
buffer[i] ^= mask2[i & 3];
|
|
6951
6951
|
}
|
|
6952
6952
|
}
|
|
6953
6953
|
function toArrayBuffer(buf) {
|
|
@@ -6980,13 +6980,13 @@ var require_buffer_util = __commonJS({
|
|
|
6980
6980
|
if (!process.env.WS_NO_BUFFER_UTIL) {
|
|
6981
6981
|
try {
|
|
6982
6982
|
const bufferUtil = __require("bufferutil");
|
|
6983
|
-
module.exports.mask = function(source,
|
|
6984
|
-
if (length < 48) _mask(source,
|
|
6985
|
-
else bufferUtil.mask(source,
|
|
6983
|
+
module.exports.mask = function(source, mask2, output, offset, length) {
|
|
6984
|
+
if (length < 48) _mask(source, mask2, output, offset, length);
|
|
6985
|
+
else bufferUtil.mask(source, mask2, output, offset, length);
|
|
6986
6986
|
};
|
|
6987
|
-
module.exports.unmask = function(buffer,
|
|
6988
|
-
if (buffer.length < 32) _unmask(buffer,
|
|
6989
|
-
else bufferUtil.unmask(buffer,
|
|
6987
|
+
module.exports.unmask = function(buffer, mask2) {
|
|
6988
|
+
if (buffer.length < 32) _unmask(buffer, mask2);
|
|
6989
|
+
else bufferUtil.unmask(buffer, mask2);
|
|
6990
6990
|
};
|
|
6991
6991
|
} catch (e) {
|
|
6992
6992
|
}
|
|
@@ -8327,14 +8327,14 @@ var require_sender = __commonJS({
|
|
|
8327
8327
|
* @public
|
|
8328
8328
|
*/
|
|
8329
8329
|
static frame(data, options) {
|
|
8330
|
-
let
|
|
8330
|
+
let mask2;
|
|
8331
8331
|
let merge2 = false;
|
|
8332
8332
|
let offset = 2;
|
|
8333
8333
|
let skipMasking = false;
|
|
8334
8334
|
if (options.mask) {
|
|
8335
|
-
|
|
8335
|
+
mask2 = options.maskBuffer || maskBuffer;
|
|
8336
8336
|
if (options.generateMask) {
|
|
8337
|
-
options.generateMask(
|
|
8337
|
+
options.generateMask(mask2);
|
|
8338
8338
|
} else {
|
|
8339
8339
|
if (randomPoolPointer === RANDOM_POOL_SIZE) {
|
|
8340
8340
|
if (randomPool === void 0) {
|
|
@@ -8343,12 +8343,12 @@ var require_sender = __commonJS({
|
|
|
8343
8343
|
randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
|
|
8344
8344
|
randomPoolPointer = 0;
|
|
8345
8345
|
}
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8346
|
+
mask2[0] = randomPool[randomPoolPointer++];
|
|
8347
|
+
mask2[1] = randomPool[randomPoolPointer++];
|
|
8348
|
+
mask2[2] = randomPool[randomPoolPointer++];
|
|
8349
|
+
mask2[3] = randomPool[randomPoolPointer++];
|
|
8350
8350
|
}
|
|
8351
|
-
skipMasking = (
|
|
8351
|
+
skipMasking = (mask2[0] | mask2[1] | mask2[2] | mask2[3]) === 0;
|
|
8352
8352
|
offset = 6;
|
|
8353
8353
|
}
|
|
8354
8354
|
let dataLength;
|
|
@@ -8383,16 +8383,16 @@ var require_sender = __commonJS({
|
|
|
8383
8383
|
}
|
|
8384
8384
|
if (!options.mask) return [target, data];
|
|
8385
8385
|
target[1] |= 128;
|
|
8386
|
-
target[offset - 4] =
|
|
8387
|
-
target[offset - 3] =
|
|
8388
|
-
target[offset - 2] =
|
|
8389
|
-
target[offset - 1] =
|
|
8386
|
+
target[offset - 4] = mask2[0];
|
|
8387
|
+
target[offset - 3] = mask2[1];
|
|
8388
|
+
target[offset - 2] = mask2[2];
|
|
8389
|
+
target[offset - 1] = mask2[3];
|
|
8390
8390
|
if (skipMasking) return [target, data];
|
|
8391
8391
|
if (merge2) {
|
|
8392
|
-
applyMask(data,
|
|
8392
|
+
applyMask(data, mask2, target, offset, dataLength);
|
|
8393
8393
|
return [target];
|
|
8394
8394
|
}
|
|
8395
|
-
applyMask(data,
|
|
8395
|
+
applyMask(data, mask2, data, 0, dataLength);
|
|
8396
8396
|
return [target, data];
|
|
8397
8397
|
}
|
|
8398
8398
|
/**
|
|
@@ -8404,7 +8404,7 @@ var require_sender = __commonJS({
|
|
|
8404
8404
|
* @param {Function} [cb] Callback
|
|
8405
8405
|
* @public
|
|
8406
8406
|
*/
|
|
8407
|
-
close(code, data,
|
|
8407
|
+
close(code, data, mask2, cb) {
|
|
8408
8408
|
let buf;
|
|
8409
8409
|
if (code === void 0) {
|
|
8410
8410
|
buf = EMPTY_BUFFER;
|
|
@@ -8432,7 +8432,7 @@ var require_sender = __commonJS({
|
|
|
8432
8432
|
[kByteLength]: buf.length,
|
|
8433
8433
|
fin: true,
|
|
8434
8434
|
generateMask: this._generateMask,
|
|
8435
|
-
mask,
|
|
8435
|
+
mask: mask2,
|
|
8436
8436
|
maskBuffer: this._maskBuffer,
|
|
8437
8437
|
opcode: 8,
|
|
8438
8438
|
readOnly: false,
|
|
@@ -8452,7 +8452,7 @@ var require_sender = __commonJS({
|
|
|
8452
8452
|
* @param {Function} [cb] Callback
|
|
8453
8453
|
* @public
|
|
8454
8454
|
*/
|
|
8455
|
-
ping(data,
|
|
8455
|
+
ping(data, mask2, cb) {
|
|
8456
8456
|
let byteLength;
|
|
8457
8457
|
let readOnly;
|
|
8458
8458
|
if (typeof data === "string") {
|
|
@@ -8473,7 +8473,7 @@ var require_sender = __commonJS({
|
|
|
8473
8473
|
[kByteLength]: byteLength,
|
|
8474
8474
|
fin: true,
|
|
8475
8475
|
generateMask: this._generateMask,
|
|
8476
|
-
mask,
|
|
8476
|
+
mask: mask2,
|
|
8477
8477
|
maskBuffer: this._maskBuffer,
|
|
8478
8478
|
opcode: 9,
|
|
8479
8479
|
readOnly,
|
|
@@ -8499,7 +8499,7 @@ var require_sender = __commonJS({
|
|
|
8499
8499
|
* @param {Function} [cb] Callback
|
|
8500
8500
|
* @public
|
|
8501
8501
|
*/
|
|
8502
|
-
pong(data,
|
|
8502
|
+
pong(data, mask2, cb) {
|
|
8503
8503
|
let byteLength;
|
|
8504
8504
|
let readOnly;
|
|
8505
8505
|
if (typeof data === "string") {
|
|
@@ -8520,7 +8520,7 @@ var require_sender = __commonJS({
|
|
|
8520
8520
|
[kByteLength]: byteLength,
|
|
8521
8521
|
fin: true,
|
|
8522
8522
|
generateMask: this._generateMask,
|
|
8523
|
-
mask,
|
|
8523
|
+
mask: mask2,
|
|
8524
8524
|
maskBuffer: this._maskBuffer,
|
|
8525
8525
|
opcode: 10,
|
|
8526
8526
|
readOnly,
|
|
@@ -9431,24 +9431,24 @@ var require_websocket = __commonJS({
|
|
|
9431
9431
|
* @param {Function} [cb] Callback which is executed when the ping is sent
|
|
9432
9432
|
* @public
|
|
9433
9433
|
*/
|
|
9434
|
-
ping(data,
|
|
9434
|
+
ping(data, mask2, cb) {
|
|
9435
9435
|
if (this.readyState === _WebSocket.CONNECTING) {
|
|
9436
9436
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
|
|
9437
9437
|
}
|
|
9438
9438
|
if (typeof data === "function") {
|
|
9439
9439
|
cb = data;
|
|
9440
|
-
data =
|
|
9441
|
-
} else if (typeof
|
|
9442
|
-
cb =
|
|
9443
|
-
|
|
9440
|
+
data = mask2 = void 0;
|
|
9441
|
+
} else if (typeof mask2 === "function") {
|
|
9442
|
+
cb = mask2;
|
|
9443
|
+
mask2 = void 0;
|
|
9444
9444
|
}
|
|
9445
9445
|
if (typeof data === "number") data = data.toString();
|
|
9446
9446
|
if (this.readyState !== _WebSocket.OPEN) {
|
|
9447
9447
|
sendAfterClose(this, data, cb);
|
|
9448
9448
|
return;
|
|
9449
9449
|
}
|
|
9450
|
-
if (
|
|
9451
|
-
this._sender.ping(data || EMPTY_BUFFER,
|
|
9450
|
+
if (mask2 === void 0) mask2 = !this._isServer;
|
|
9451
|
+
this._sender.ping(data || EMPTY_BUFFER, mask2, cb);
|
|
9452
9452
|
}
|
|
9453
9453
|
/**
|
|
9454
9454
|
* Send a pong.
|
|
@@ -9458,24 +9458,24 @@ var require_websocket = __commonJS({
|
|
|
9458
9458
|
* @param {Function} [cb] Callback which is executed when the pong is sent
|
|
9459
9459
|
* @public
|
|
9460
9460
|
*/
|
|
9461
|
-
pong(data,
|
|
9461
|
+
pong(data, mask2, cb) {
|
|
9462
9462
|
if (this.readyState === _WebSocket.CONNECTING) {
|
|
9463
9463
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
|
|
9464
9464
|
}
|
|
9465
9465
|
if (typeof data === "function") {
|
|
9466
9466
|
cb = data;
|
|
9467
|
-
data =
|
|
9468
|
-
} else if (typeof
|
|
9469
|
-
cb =
|
|
9470
|
-
|
|
9467
|
+
data = mask2 = void 0;
|
|
9468
|
+
} else if (typeof mask2 === "function") {
|
|
9469
|
+
cb = mask2;
|
|
9470
|
+
mask2 = void 0;
|
|
9471
9471
|
}
|
|
9472
9472
|
if (typeof data === "number") data = data.toString();
|
|
9473
9473
|
if (this.readyState !== _WebSocket.OPEN) {
|
|
9474
9474
|
sendAfterClose(this, data, cb);
|
|
9475
9475
|
return;
|
|
9476
9476
|
}
|
|
9477
|
-
if (
|
|
9478
|
-
this._sender.pong(data || EMPTY_BUFFER,
|
|
9477
|
+
if (mask2 === void 0) mask2 = !this._isServer;
|
|
9478
|
+
this._sender.pong(data || EMPTY_BUFFER, mask2, cb);
|
|
9479
9479
|
}
|
|
9480
9480
|
/**
|
|
9481
9481
|
* Resume the socket.
|
|
@@ -10441,13 +10441,13 @@ var require_websocket_server = __commonJS({
|
|
|
10441
10441
|
}
|
|
10442
10442
|
}
|
|
10443
10443
|
if (this.options.verifyClient) {
|
|
10444
|
-
const
|
|
10444
|
+
const info2 = {
|
|
10445
10445
|
origin: req.headers[`${version2 === 8 ? "sec-websocket-origin" : "origin"}`],
|
|
10446
10446
|
secure: !!(req.socket.authorized || req.socket.encrypted),
|
|
10447
10447
|
req
|
|
10448
10448
|
};
|
|
10449
10449
|
if (this.options.verifyClient.length === 2) {
|
|
10450
|
-
this.options.verifyClient(
|
|
10450
|
+
this.options.verifyClient(info2, (verified, code, message, headers) => {
|
|
10451
10451
|
if (!verified) {
|
|
10452
10452
|
return abortHandshake(socket, code || 401, message, headers);
|
|
10453
10453
|
}
|
|
@@ -10463,7 +10463,7 @@ var require_websocket_server = __commonJS({
|
|
|
10463
10463
|
});
|
|
10464
10464
|
return;
|
|
10465
10465
|
}
|
|
10466
|
-
if (!this.options.verifyClient(
|
|
10466
|
+
if (!this.options.verifyClient(info2)) return abortHandshake(socket, 401);
|
|
10467
10467
|
}
|
|
10468
10468
|
this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
|
|
10469
10469
|
}
|
|
@@ -13186,10 +13186,10 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
13186
13186
|
catchall: index
|
|
13187
13187
|
});
|
|
13188
13188
|
}
|
|
13189
|
-
pick(
|
|
13189
|
+
pick(mask2) {
|
|
13190
13190
|
const shape = {};
|
|
13191
|
-
for (const key of util.objectKeys(
|
|
13192
|
-
if (
|
|
13191
|
+
for (const key of util.objectKeys(mask2)) {
|
|
13192
|
+
if (mask2[key] && this.shape[key]) {
|
|
13193
13193
|
shape[key] = this.shape[key];
|
|
13194
13194
|
}
|
|
13195
13195
|
}
|
|
@@ -13198,10 +13198,10 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
13198
13198
|
shape: () => shape
|
|
13199
13199
|
});
|
|
13200
13200
|
}
|
|
13201
|
-
omit(
|
|
13201
|
+
omit(mask2) {
|
|
13202
13202
|
const shape = {};
|
|
13203
13203
|
for (const key of util.objectKeys(this.shape)) {
|
|
13204
|
-
if (!
|
|
13204
|
+
if (!mask2[key]) {
|
|
13205
13205
|
shape[key] = this.shape[key];
|
|
13206
13206
|
}
|
|
13207
13207
|
}
|
|
@@ -13216,11 +13216,11 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
13216
13216
|
deepPartial() {
|
|
13217
13217
|
return deepPartialify(this);
|
|
13218
13218
|
}
|
|
13219
|
-
partial(
|
|
13219
|
+
partial(mask2) {
|
|
13220
13220
|
const newShape = {};
|
|
13221
13221
|
for (const key of util.objectKeys(this.shape)) {
|
|
13222
13222
|
const fieldSchema = this.shape[key];
|
|
13223
|
-
if (
|
|
13223
|
+
if (mask2 && !mask2[key]) {
|
|
13224
13224
|
newShape[key] = fieldSchema;
|
|
13225
13225
|
} else {
|
|
13226
13226
|
newShape[key] = fieldSchema.optional();
|
|
@@ -13231,10 +13231,10 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
13231
13231
|
shape: () => newShape
|
|
13232
13232
|
});
|
|
13233
13233
|
}
|
|
13234
|
-
required(
|
|
13234
|
+
required(mask2) {
|
|
13235
13235
|
const newShape = {};
|
|
13236
13236
|
for (const key of util.objectKeys(this.shape)) {
|
|
13237
|
-
if (
|
|
13237
|
+
if (mask2 && !mask2[key]) {
|
|
13238
13238
|
newShape[key] = this.shape[key];
|
|
13239
13239
|
} else {
|
|
13240
13240
|
const fieldSchema = this.shape[key];
|
|
@@ -15005,14 +15005,14 @@ var BIGINT_FORMAT_RANGES = {
|
|
|
15005
15005
|
int64: [/* @__PURE__ */ BigInt("-9223372036854775808"), /* @__PURE__ */ BigInt("9223372036854775807")],
|
|
15006
15006
|
uint64: [/* @__PURE__ */ BigInt(0), /* @__PURE__ */ BigInt("18446744073709551615")]
|
|
15007
15007
|
};
|
|
15008
|
-
function pick(schema,
|
|
15008
|
+
function pick(schema, mask2) {
|
|
15009
15009
|
const newShape = {};
|
|
15010
15010
|
const currDef = schema._zod.def;
|
|
15011
|
-
for (const key in
|
|
15011
|
+
for (const key in mask2) {
|
|
15012
15012
|
if (!(key in currDef.shape)) {
|
|
15013
15013
|
throw new Error(`Unrecognized key: "${key}"`);
|
|
15014
15014
|
}
|
|
15015
|
-
if (!
|
|
15015
|
+
if (!mask2[key])
|
|
15016
15016
|
continue;
|
|
15017
15017
|
newShape[key] = currDef.shape[key];
|
|
15018
15018
|
}
|
|
@@ -15022,14 +15022,14 @@ function pick(schema, mask) {
|
|
|
15022
15022
|
checks: []
|
|
15023
15023
|
});
|
|
15024
15024
|
}
|
|
15025
|
-
function omit(schema,
|
|
15025
|
+
function omit(schema, mask2) {
|
|
15026
15026
|
const newShape = { ...schema._zod.def.shape };
|
|
15027
15027
|
const currDef = schema._zod.def;
|
|
15028
|
-
for (const key in
|
|
15028
|
+
for (const key in mask2) {
|
|
15029
15029
|
if (!(key in currDef.shape)) {
|
|
15030
15030
|
throw new Error(`Unrecognized key: "${key}"`);
|
|
15031
15031
|
}
|
|
15032
|
-
if (!
|
|
15032
|
+
if (!mask2[key])
|
|
15033
15033
|
continue;
|
|
15034
15034
|
delete newShape[key];
|
|
15035
15035
|
}
|
|
@@ -15068,15 +15068,15 @@ function merge(a, b) {
|
|
|
15068
15068
|
// delete existing checks
|
|
15069
15069
|
});
|
|
15070
15070
|
}
|
|
15071
|
-
function partial(Class2, schema,
|
|
15071
|
+
function partial(Class2, schema, mask2) {
|
|
15072
15072
|
const oldShape = schema._zod.def.shape;
|
|
15073
15073
|
const shape = { ...oldShape };
|
|
15074
|
-
if (
|
|
15075
|
-
for (const key in
|
|
15074
|
+
if (mask2) {
|
|
15075
|
+
for (const key in mask2) {
|
|
15076
15076
|
if (!(key in oldShape)) {
|
|
15077
15077
|
throw new Error(`Unrecognized key: "${key}"`);
|
|
15078
15078
|
}
|
|
15079
|
-
if (!
|
|
15079
|
+
if (!mask2[key])
|
|
15080
15080
|
continue;
|
|
15081
15081
|
shape[key] = Class2 ? new Class2({
|
|
15082
15082
|
type: "optional",
|
|
@@ -15097,15 +15097,15 @@ function partial(Class2, schema, mask) {
|
|
|
15097
15097
|
checks: []
|
|
15098
15098
|
});
|
|
15099
15099
|
}
|
|
15100
|
-
function required(Class2, schema,
|
|
15100
|
+
function required(Class2, schema, mask2) {
|
|
15101
15101
|
const oldShape = schema._zod.def.shape;
|
|
15102
15102
|
const shape = { ...oldShape };
|
|
15103
|
-
if (
|
|
15104
|
-
for (const key in
|
|
15103
|
+
if (mask2) {
|
|
15104
|
+
for (const key in mask2) {
|
|
15105
15105
|
if (!(key in shape)) {
|
|
15106
15106
|
throw new Error(`Unrecognized key: "${key}"`);
|
|
15107
15107
|
}
|
|
15108
|
-
if (!
|
|
15108
|
+
if (!mask2[key])
|
|
15109
15109
|
continue;
|
|
15110
15110
|
shape[key] = new Class2({
|
|
15111
15111
|
type: "nonoptional",
|
|
@@ -18983,8 +18983,8 @@ var ZodObject2 = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
|
|
|
18983
18983
|
return util_exports.extend(inst, incoming);
|
|
18984
18984
|
};
|
|
18985
18985
|
inst.merge = (other) => util_exports.merge(inst, other);
|
|
18986
|
-
inst.pick = (
|
|
18987
|
-
inst.omit = (
|
|
18986
|
+
inst.pick = (mask2) => util_exports.pick(inst, mask2);
|
|
18987
|
+
inst.omit = (mask2) => util_exports.omit(inst, mask2);
|
|
18988
18988
|
inst.partial = (...args) => util_exports.partial(ZodOptional2, inst, args[0]);
|
|
18989
18989
|
inst.required = (...args) => util_exports.required(ZodNonOptional, inst, args[0]);
|
|
18990
18990
|
});
|
|
@@ -22315,25 +22315,25 @@ var Protocol = class {
|
|
|
22315
22315
|
});
|
|
22316
22316
|
}
|
|
22317
22317
|
_resetTimeout(messageId) {
|
|
22318
|
-
const
|
|
22319
|
-
if (!
|
|
22318
|
+
const info2 = this._timeoutInfo.get(messageId);
|
|
22319
|
+
if (!info2)
|
|
22320
22320
|
return false;
|
|
22321
|
-
const totalElapsed = Date.now() -
|
|
22322
|
-
if (
|
|
22321
|
+
const totalElapsed = Date.now() - info2.startTime;
|
|
22322
|
+
if (info2.maxTotalTimeout && totalElapsed >= info2.maxTotalTimeout) {
|
|
22323
22323
|
this._timeoutInfo.delete(messageId);
|
|
22324
22324
|
throw McpError.fromError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", {
|
|
22325
|
-
maxTotalTimeout:
|
|
22325
|
+
maxTotalTimeout: info2.maxTotalTimeout,
|
|
22326
22326
|
totalElapsed
|
|
22327
22327
|
});
|
|
22328
22328
|
}
|
|
22329
|
-
clearTimeout(
|
|
22330
|
-
|
|
22329
|
+
clearTimeout(info2.timeoutId);
|
|
22330
|
+
info2.timeoutId = setTimeout(info2.onTimeout, info2.timeout);
|
|
22331
22331
|
return true;
|
|
22332
22332
|
}
|
|
22333
22333
|
_cleanupTimeout(messageId) {
|
|
22334
|
-
const
|
|
22335
|
-
if (
|
|
22336
|
-
clearTimeout(
|
|
22334
|
+
const info2 = this._timeoutInfo.get(messageId);
|
|
22335
|
+
if (info2) {
|
|
22336
|
+
clearTimeout(info2.timeoutId);
|
|
22337
22337
|
this._timeoutInfo.delete(messageId);
|
|
22338
22338
|
}
|
|
22339
22339
|
}
|
|
@@ -22378,8 +22378,8 @@ var Protocol = class {
|
|
|
22378
22378
|
this._progressHandlers.clear();
|
|
22379
22379
|
this._taskProgressTokens.clear();
|
|
22380
22380
|
this._pendingDebouncedNotifications.clear();
|
|
22381
|
-
for (const
|
|
22382
|
-
clearTimeout(
|
|
22381
|
+
for (const info2 of this._timeoutInfo.values()) {
|
|
22382
|
+
clearTimeout(info2.timeoutId);
|
|
22383
22383
|
}
|
|
22384
22384
|
this._timeoutInfo.clear();
|
|
22385
22385
|
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
@@ -23833,7 +23833,7 @@ var McpZodTypeKind;
|
|
|
23833
23833
|
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
23834
23834
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
23835
23835
|
function validateToolName(name) {
|
|
23836
|
-
const
|
|
23836
|
+
const warnings2 = [];
|
|
23837
23837
|
if (name.length === 0) {
|
|
23838
23838
|
return {
|
|
23839
23839
|
isValid: false,
|
|
@@ -23847,34 +23847,34 @@ function validateToolName(name) {
|
|
|
23847
23847
|
};
|
|
23848
23848
|
}
|
|
23849
23849
|
if (name.includes(" ")) {
|
|
23850
|
-
|
|
23850
|
+
warnings2.push("Tool name contains spaces, which may cause parsing issues");
|
|
23851
23851
|
}
|
|
23852
23852
|
if (name.includes(",")) {
|
|
23853
|
-
|
|
23853
|
+
warnings2.push("Tool name contains commas, which may cause parsing issues");
|
|
23854
23854
|
}
|
|
23855
23855
|
if (name.startsWith("-") || name.endsWith("-")) {
|
|
23856
|
-
|
|
23856
|
+
warnings2.push("Tool name starts or ends with a dash, which may cause parsing issues in some contexts");
|
|
23857
23857
|
}
|
|
23858
23858
|
if (name.startsWith(".") || name.endsWith(".")) {
|
|
23859
|
-
|
|
23859
|
+
warnings2.push("Tool name starts or ends with a dot, which may cause parsing issues in some contexts");
|
|
23860
23860
|
}
|
|
23861
23861
|
if (!TOOL_NAME_REGEX.test(name)) {
|
|
23862
23862
|
const invalidChars = name.split("").filter((char) => !/[A-Za-z0-9._-]/.test(char)).filter((char, index, arr) => arr.indexOf(char) === index);
|
|
23863
|
-
|
|
23863
|
+
warnings2.push(`Tool name contains invalid characters: ${invalidChars.map((c) => `"${c}"`).join(", ")}`, "Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)");
|
|
23864
23864
|
return {
|
|
23865
23865
|
isValid: false,
|
|
23866
|
-
warnings
|
|
23866
|
+
warnings: warnings2
|
|
23867
23867
|
};
|
|
23868
23868
|
}
|
|
23869
23869
|
return {
|
|
23870
23870
|
isValid: true,
|
|
23871
|
-
warnings
|
|
23871
|
+
warnings: warnings2
|
|
23872
23872
|
};
|
|
23873
23873
|
}
|
|
23874
|
-
function issueToolNameWarning(name,
|
|
23875
|
-
if (
|
|
23874
|
+
function issueToolNameWarning(name, warnings2) {
|
|
23875
|
+
if (warnings2.length > 0) {
|
|
23876
23876
|
console.warn(`Tool name validation warning for "${name}":`);
|
|
23877
|
-
for (const warning of
|
|
23877
|
+
for (const warning of warnings2) {
|
|
23878
23878
|
console.warn(` - ${warning}`);
|
|
23879
23879
|
}
|
|
23880
23880
|
console.warn("Tool registration will proceed, but this may cause compatibility issues.");
|
|
@@ -24788,7 +24788,7 @@ var StdioServerTransport = class {
|
|
|
24788
24788
|
};
|
|
24789
24789
|
|
|
24790
24790
|
// src/index.ts
|
|
24791
|
-
import
|
|
24791
|
+
import fs6 from "node:fs";
|
|
24792
24792
|
import os5 from "node:os";
|
|
24793
24793
|
import path2 from "node:path";
|
|
24794
24794
|
|
|
@@ -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();
|
|
@@ -25431,16 +25432,30 @@ import cp2 from "node:child_process";
|
|
|
25431
25432
|
import fs3 from "node:fs";
|
|
25432
25433
|
import np2 from "node:path";
|
|
25433
25434
|
import os3 from "node:os";
|
|
25435
|
+
var DEFAULT_TEMPLATE = '{persona}You are @{me}, an autonomous agent on Jefri Chat. A message came in{where}. It may address several agents by @name (e.g. "@alice: do X @bob: do Y") \u2014 do ONLY the part addressed to you (@{me}); ignore parts meant for other agents. If nothing is addressed to you, reply with nothing to do. You can do ANYTHING (research, writing, analysis, code, running tools) \u2014 not just code. If a CLAUDE.md or relevant files are in this folder, read them first to get oriented. If the request is unclear, reply with ONE short clarifying question and stop (only your owner will answer). Otherwise do your part and reply concisely with the result.\n\n{context}Latest message from @{sender}: {message}';
|
|
25434
25436
|
var DEFAULTS2 = {
|
|
25435
25437
|
enabled: false,
|
|
25436
25438
|
brain: "claude",
|
|
25437
25439
|
workdir: process.cwd(),
|
|
25438
25440
|
replyMode: "mentions",
|
|
25439
25441
|
persona: "",
|
|
25440
|
-
replyToBots: false
|
|
25442
|
+
replyToBots: false,
|
|
25443
|
+
ownerOnly: false,
|
|
25444
|
+
contextMessages: 12,
|
|
25445
|
+
promptTemplate: DEFAULT_TEMPLATE
|
|
25441
25446
|
};
|
|
25442
25447
|
var DIR = np2.join(os3.homedir(), ".jefri");
|
|
25443
25448
|
var FILE = np2.join(DIR, "autonomous.json");
|
|
25449
|
+
var LOG_FILE = np2.join(DIR, "autonomous.log");
|
|
25450
|
+
function logLine(line) {
|
|
25451
|
+
try {
|
|
25452
|
+
fs3.mkdirSync(DIR, { recursive: true });
|
|
25453
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
25454
|
+
fs3.appendFileSync(LOG_FILE, `[${ts}] ${line}
|
|
25455
|
+
`);
|
|
25456
|
+
} catch {
|
|
25457
|
+
}
|
|
25458
|
+
}
|
|
25444
25459
|
function loadCfg() {
|
|
25445
25460
|
try {
|
|
25446
25461
|
return { ...DEFAULTS2, ...JSON.parse(fs3.readFileSync(FILE, "utf8")) };
|
|
@@ -25461,6 +25476,14 @@ function setAuto(patch) {
|
|
|
25461
25476
|
}
|
|
25462
25477
|
return { ...cfg };
|
|
25463
25478
|
}
|
|
25479
|
+
var selfName = "";
|
|
25480
|
+
var ownerName = "";
|
|
25481
|
+
var fetchHistory = null;
|
|
25482
|
+
function configureAuto(opts) {
|
|
25483
|
+
selfName = opts.self;
|
|
25484
|
+
ownerName = opts.owner ?? "";
|
|
25485
|
+
fetchHistory = opts.getHistory;
|
|
25486
|
+
}
|
|
25464
25487
|
var expand = (p) => p.startsWith("~") ? np2.join(os3.homedir(), p.slice(1)) : p;
|
|
25465
25488
|
function brainArgv(brain, prompt) {
|
|
25466
25489
|
if (brain === "claude") return ["claude", ["-p", "--permission-mode", "acceptEdits", prompt]];
|
|
@@ -25468,11 +25491,13 @@ function brainArgv(brain, prompt) {
|
|
|
25468
25491
|
const parts = brain.trim().split(/\s+/);
|
|
25469
25492
|
return [parts[0], [...parts.slice(1), prompt]];
|
|
25470
25493
|
}
|
|
25471
|
-
var MAX_PROMPT =
|
|
25494
|
+
var MAX_PROMPT = 12e3;
|
|
25472
25495
|
var MAX_REPLY = 7900;
|
|
25473
25496
|
var TIMEOUT_MS = 5 * 60 * 1e3;
|
|
25474
25497
|
function shouldHandle(m) {
|
|
25475
25498
|
if (!cfg.enabled) return false;
|
|
25499
|
+
const fromOwner = !!ownerName && m.sender === ownerName;
|
|
25500
|
+
if (cfg.ownerOnly && !fromOwner) return false;
|
|
25476
25501
|
if (m.senderIsBot && !cfg.replyToBots) return false;
|
|
25477
25502
|
if (!m.isGroup) return true;
|
|
25478
25503
|
if (cfg.replyMode === "all") return true;
|
|
@@ -25522,23 +25547,47 @@ function runBrain(cmd, args, cwd) {
|
|
|
25522
25547
|
});
|
|
25523
25548
|
});
|
|
25524
25549
|
}
|
|
25550
|
+
async function buildContext(conversationId) {
|
|
25551
|
+
if (cfg.contextMessages <= 0 || !fetchHistory) return "";
|
|
25552
|
+
let msgs = [];
|
|
25553
|
+
try {
|
|
25554
|
+
msgs = await fetchHistory(conversationId);
|
|
25555
|
+
} catch {
|
|
25556
|
+
return "";
|
|
25557
|
+
}
|
|
25558
|
+
const recent = msgs.slice(-cfg.contextMessages);
|
|
25559
|
+
if (!recent.length) return "";
|
|
25560
|
+
const lines = recent.map((h) => {
|
|
25561
|
+
const body = h.kind === "file" ? `[sent a file: ${h.fileName ?? "file"}]` : h.content ?? "";
|
|
25562
|
+
return `@${h.sender}: ${body.replace(/\s+/g, " ").slice(0, 400)}`;
|
|
25563
|
+
});
|
|
25564
|
+
return `Recent conversation (for context \u2014 reply only to the latest message):
|
|
25565
|
+
${lines.join("\n")}
|
|
25566
|
+
|
|
25567
|
+
`;
|
|
25568
|
+
}
|
|
25525
25569
|
function handleAutonomous(m, reply, log2) {
|
|
25526
25570
|
if (!shouldHandle(m)) return;
|
|
25571
|
+
const where = m.isGroup ? " in a group" : "";
|
|
25572
|
+
logLine(`\u2190 @${m.sender}${where}: ${m.content.replace(/\s+/g, " ").slice(0, 300)}`);
|
|
25527
25573
|
queue.push(async () => {
|
|
25528
25574
|
const persona = cfg.persona ? cfg.persona.trim() + "\n\n" : "";
|
|
25529
|
-
const
|
|
25530
|
-
const prompt =
|
|
25531
|
-
|
|
25532
|
-
Message from @${m.sender}: ${m.content}`.slice(0, MAX_PROMPT);
|
|
25575
|
+
const context = await buildContext(m.conversationId);
|
|
25576
|
+
const prompt = (cfg.promptTemplate || DEFAULT_TEMPLATE).replace(/\{persona\}/g, persona).replace(/\{me\}/g, selfName).replace(/\{sender\}/g, m.sender).replace(/\{where\}/g, where).replace(/\{context\}/g, context).replace(/\{message\}/g, m.content).slice(0, MAX_PROMPT);
|
|
25533
25577
|
const [cmd, args] = brainArgv(cfg.brain, prompt);
|
|
25534
|
-
log2(`autonomous: @${m.sender} \u2192 running "${
|
|
25578
|
+
log2(`autonomous: @${m.sender} \u2192 running "${cfg.brain}"\u2026`);
|
|
25579
|
+
logLine(` running: ${cfg.brain} in ${cfg.workdir}`);
|
|
25535
25580
|
try {
|
|
25536
25581
|
const out = await runBrain(cmd, args, cfg.workdir);
|
|
25537
|
-
|
|
25582
|
+
const text = (out.trim() || "(done)").slice(0, MAX_REPLY);
|
|
25583
|
+
reply(text);
|
|
25538
25584
|
log2(`autonomous: replied to @${m.sender}`);
|
|
25585
|
+
logLine(` \u2192 replied: ${text.replace(/\s+/g, " ").slice(0, 300)}`);
|
|
25539
25586
|
} catch (e) {
|
|
25540
|
-
|
|
25587
|
+
const msg = `(couldn't finish autonomously: ${e?.message ?? e})`.slice(0, MAX_REPLY);
|
|
25588
|
+
reply(msg);
|
|
25541
25589
|
log2(`autonomous: failed for @${m.sender}: ${e?.message ?? e}`);
|
|
25590
|
+
logLine(` \u2717 failed: ${e?.message ?? e}`);
|
|
25542
25591
|
}
|
|
25543
25592
|
});
|
|
25544
25593
|
void drain();
|
|
@@ -25565,6 +25614,18 @@ var MIME = {
|
|
|
25565
25614
|
".zip": "application/zip"
|
|
25566
25615
|
};
|
|
25567
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
|
+
}
|
|
25568
25629
|
function screenshotDir() {
|
|
25569
25630
|
try {
|
|
25570
25631
|
const out = cp3.execFileSync("defaults", ["read", "com.apple.screencapture", "location"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
@@ -25683,22 +25744,30 @@ ${e?.message ?? e}`);
|
|
|
25683
25744
|
"jefri_agents",
|
|
25684
25745
|
{
|
|
25685
25746
|
title: "List your connections",
|
|
25686
|
-
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.",
|
|
25687
25748
|
inputSchema: {}
|
|
25688
25749
|
},
|
|
25689
25750
|
async () => withClient(async (c) => {
|
|
25690
25751
|
const all = await c.identities();
|
|
25691
|
-
const
|
|
25692
|
-
|
|
25693
|
-
);
|
|
25694
|
-
|
|
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.");
|
|
25695
25764
|
})
|
|
25696
25765
|
);
|
|
25697
25766
|
server2.registerTool(
|
|
25698
25767
|
"jefri_send",
|
|
25699
25768
|
{
|
|
25700
25769
|
title: "Send a message",
|
|
25701
|
-
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.",
|
|
25702
25771
|
inputSchema: {
|
|
25703
25772
|
to: external_exports.string().describe("recipient username, e.g. claude_backend"),
|
|
25704
25773
|
text: external_exports.string().describe("the message body")
|
|
@@ -26352,17 +26421,19 @@ ${cmd}`);
|
|
|
26352
26421
|
return name ? ` (in group "${name}" \xB7 reply with jefri_send_group groupId="${m.groupId}")` : ` (in group id ${m.groupId})`;
|
|
26353
26422
|
};
|
|
26354
26423
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26424
|
+
const ts = fmtTime(m.createdAt);
|
|
26425
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26355
26426
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26356
26427
|
try {
|
|
26357
26428
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
26358
26429
|
const body2 = plain.kind === "file" ? `\u{1F512}\u{1F4CE} private file: ${plain.fileName ?? m.fileName}` : `\u{1F512} ${plain.content ?? ""}`;
|
|
26359
|
-
return
|
|
26430
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body2}`;
|
|
26360
26431
|
} catch {
|
|
26361
|
-
return
|
|
26432
|
+
return `${at}@${m.senderUsername}${where(m)}: \u{1F512} Private message unavailable on this device`;
|
|
26362
26433
|
}
|
|
26363
26434
|
}
|
|
26364
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;
|
|
26365
|
-
return
|
|
26436
|
+
return `${at}@${m.senderUsername}${where(m)}: ${body}`;
|
|
26366
26437
|
}));
|
|
26367
26438
|
return ok(`\u{1F4E8} ${lines.length} message(s):
|
|
26368
26439
|
` + lines.join("\n"));
|
|
@@ -26483,19 +26554,21 @@ ${cmd}`
|
|
|
26483
26554
|
const msgs = (res?.messages ?? []).slice(-(limit ?? 20));
|
|
26484
26555
|
if (!msgs.length) return ok(`No messages yet in ${label}.`);
|
|
26485
26556
|
const lines = await Promise.all(msgs.map(async (m) => {
|
|
26557
|
+
const ts = fmtTime(m.createdAt);
|
|
26558
|
+
const at = ts ? `[${ts}] ` : "";
|
|
26486
26559
|
if (m.encryptionMode === "private_e2e" && m.encryptedPayload) {
|
|
26487
26560
|
try {
|
|
26488
26561
|
const plain = await c.decryptPrivatePayload(m.encryptedPayload);
|
|
26489
|
-
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 ?? ""}`}`;
|
|
26490
26563
|
} catch {
|
|
26491
|
-
return `${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26564
|
+
return `${at}${m.senderUsername}: \u{1F512} Private message unavailable on this device`;
|
|
26492
26565
|
}
|
|
26493
26566
|
}
|
|
26494
26567
|
if (m.kind === "file") {
|
|
26495
26568
|
const dl = groupId ? `jefri_download_file(groupId: "${groupId}", fileName: "${m.fileName}")` : `jefri_download_file(from: "${m.senderUsername}", fileName: "${m.fileName}")`;
|
|
26496
|
-
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}`;
|
|
26497
26570
|
}
|
|
26498
|
-
return `${m.senderUsername}: ${m.content}`;
|
|
26571
|
+
return `${at}${m.senderUsername}: ${m.content}`;
|
|
26499
26572
|
}));
|
|
26500
26573
|
return ok(lines.join("\n"));
|
|
26501
26574
|
})
|
|
@@ -26651,7 +26724,10 @@ ${cmd}`
|
|
|
26651
26724
|
brain: external_exports.string().optional().describe("'claude', 'codex', or a full custom command (e.g. for OpenClaw)"),
|
|
26652
26725
|
workdir: external_exports.string().optional().describe("folder the brain works in (scope it!)"),
|
|
26653
26726
|
replyMode: external_exports.enum(["mentions", "dms", "all"]).optional().describe("groups: mentions=only when @-mentioned, all=every message, dms=DMs only"),
|
|
26654
|
-
persona: external_exports.string().optional().describe("role/instructions for the agent"),
|
|
26727
|
+
persona: external_exports.string().optional().describe("role/instructions for the agent (injected as {persona})"),
|
|
26728
|
+
promptTemplate: external_exports.string().optional().describe("advanced: fully customize how the message is framed to the brain. Placeholders: {persona} {me} {sender} {where} {context} {message}. Pass 'default' to reset."),
|
|
26729
|
+
ownerOnly: external_exports.boolean().optional().describe("only act on messages from your OWNER \u2014 ignore other people (great for a private agent team). Default off."),
|
|
26730
|
+
contextMessages: external_exports.number().optional().describe("how many recent messages of the conversation to give the brain for memory (0 = stateless, default 12)"),
|
|
26655
26731
|
replyToBots: external_exports.boolean().optional().describe("also auto-reply to other agents (default off \u2014 prevents bot loops)")
|
|
26656
26732
|
}
|
|
26657
26733
|
},
|
|
@@ -26659,9 +26735,13 @@ ${cmd}`
|
|
|
26659
26735
|
const patch = {};
|
|
26660
26736
|
if (typeof args.enabled === "boolean") patch.enabled = args.enabled;
|
|
26661
26737
|
if (typeof args.replyToBots === "boolean") patch.replyToBots = args.replyToBots;
|
|
26738
|
+
if (typeof args.ownerOnly === "boolean") patch.ownerOnly = args.ownerOnly;
|
|
26739
|
+
if (typeof args.contextMessages === "number") patch.contextMessages = Math.max(0, Math.min(40, Math.floor(args.contextMessages)));
|
|
26662
26740
|
if (typeof args.brain === "string" && args.brain.trim()) patch.brain = args.brain.trim();
|
|
26663
26741
|
if (typeof args.workdir === "string" && args.workdir.trim()) patch.workdir = args.workdir.trim();
|
|
26664
26742
|
if (typeof args.persona === "string") patch.persona = args.persona;
|
|
26743
|
+
if (typeof args.promptTemplate === "string" && args.promptTemplate.trim())
|
|
26744
|
+
patch.promptTemplate = args.promptTemplate.trim().toLowerCase() === "default" ? DEFAULT_TEMPLATE : args.promptTemplate;
|
|
26665
26745
|
if (args.replyMode) patch.replyMode = args.replyMode;
|
|
26666
26746
|
const c = setAuto(patch);
|
|
26667
26747
|
const modeLabel = c.replyMode === "all" ? "every message" : c.replyMode === "dms" ? "DMs only" : "DMs + group @mentions";
|
|
@@ -26670,8 +26750,12 @@ ${cmd}`
|
|
|
26670
26750
|
` Brain: ${c.brain}`,
|
|
26671
26751
|
` Work folder: ${c.workdir}`,
|
|
26672
26752
|
` Replies to: ${modeLabel}`,
|
|
26753
|
+
` Owner-only: ${c.ownerOnly ? "yes (only you direct me)" : "no (anyone who @mentions me)"}`,
|
|
26673
26754
|
` Persona: ${c.persona ? c.persona.slice(0, 80) : "(none)"}`,
|
|
26674
|
-
`
|
|
26755
|
+
` Conversation memory: ${c.contextMessages > 0 ? `last ${c.contextMessages} messages` : "off"}`,
|
|
26756
|
+
` Prompt: ${c.promptTemplate === DEFAULT_TEMPLATE ? "default (@name routing + ask-if-unclear)" : "custom"}`,
|
|
26757
|
+
` Reply to other bots: ${c.replyToBots ? "yes" : "no"}`,
|
|
26758
|
+
` Activity log: ~/.jefri/autonomous.log (watch it: tail -f ~/.jefri/autonomous.log)`
|
|
26675
26759
|
];
|
|
26676
26760
|
if (c.enabled)
|
|
26677
26761
|
lines.push(`
|
|
@@ -26696,6 +26780,134 @@ function attachInbox(c, inbox2, self, onIncoming) {
|
|
|
26696
26780
|
c.on("file_received", capture);
|
|
26697
26781
|
}
|
|
26698
26782
|
|
|
26783
|
+
// src/doctor.ts
|
|
26784
|
+
import cp4 from "node:child_process";
|
|
26785
|
+
import fs5 from "node:fs";
|
|
26786
|
+
import np4 from "node:path";
|
|
26787
|
+
import { fileURLToPath } from "node:url";
|
|
26788
|
+
var T = !!process.stdout.isTTY;
|
|
26789
|
+
var C = {
|
|
26790
|
+
g: T ? "\x1B[32m" : "",
|
|
26791
|
+
r: T ? "\x1B[31m" : "",
|
|
26792
|
+
y: T ? "\x1B[33m" : "",
|
|
26793
|
+
d: T ? "\x1B[2m" : "",
|
|
26794
|
+
b: T ? "\x1B[1m" : "",
|
|
26795
|
+
x: T ? "\x1B[0m" : ""
|
|
26796
|
+
};
|
|
26797
|
+
var problems = 0;
|
|
26798
|
+
var warnings = 0;
|
|
26799
|
+
var pass = (s, extra = "") => console.log(` ${C.g}\u2713${C.x} ${s}${extra ? ` ${C.d}${extra}${C.x}` : ""}`);
|
|
26800
|
+
var fail2 = (s, fix = "") => {
|
|
26801
|
+
problems++;
|
|
26802
|
+
console.log(` ${C.r}\u2717${C.x} ${s}${fix ? `
|
|
26803
|
+
${C.y}\u2192 ${fix}${C.x}` : ""}`);
|
|
26804
|
+
};
|
|
26805
|
+
var warn = (s, fix = "") => {
|
|
26806
|
+
warnings++;
|
|
26807
|
+
console.log(` ${C.y}!${C.x} ${s}${fix ? `
|
|
26808
|
+
${C.d}${fix}${C.x}` : ""}`);
|
|
26809
|
+
};
|
|
26810
|
+
var info = (s) => console.log(` ${C.d}i ${s}${C.x}`);
|
|
26811
|
+
function mask(t) {
|
|
26812
|
+
if (t.length <= 12) return t.slice(0, 4) + "\u2026";
|
|
26813
|
+
return t.slice(0, 8) + "\u2026" + t.slice(-4);
|
|
26814
|
+
}
|
|
26815
|
+
function connectorVersion() {
|
|
26816
|
+
try {
|
|
26817
|
+
const here = np4.dirname(fileURLToPath(import.meta.url));
|
|
26818
|
+
const pkg = JSON.parse(fs5.readFileSync(np4.join(here, "..", "package.json"), "utf8"));
|
|
26819
|
+
return pkg.version ?? "?";
|
|
26820
|
+
} catch {
|
|
26821
|
+
return "?";
|
|
26822
|
+
}
|
|
26823
|
+
}
|
|
26824
|
+
function hasCli(cmd) {
|
|
26825
|
+
try {
|
|
26826
|
+
const r = cp4.spawnSync(cmd, ["--version"], {
|
|
26827
|
+
encoding: "utf8",
|
|
26828
|
+
timeout: 5e3,
|
|
26829
|
+
shell: process.platform === "win32"
|
|
26830
|
+
});
|
|
26831
|
+
return r.status === 0 || !!(r.stdout && r.stdout.trim());
|
|
26832
|
+
} catch {
|
|
26833
|
+
return false;
|
|
26834
|
+
}
|
|
26835
|
+
}
|
|
26836
|
+
async function fetchWithTimeout(url, opts, ms) {
|
|
26837
|
+
const ac = new AbortController();
|
|
26838
|
+
const t = setTimeout(() => ac.abort(), ms);
|
|
26839
|
+
try {
|
|
26840
|
+
return await fetch(url, { ...opts, signal: ac.signal });
|
|
26841
|
+
} finally {
|
|
26842
|
+
clearTimeout(t);
|
|
26843
|
+
}
|
|
26844
|
+
}
|
|
26845
|
+
async function runDoctor() {
|
|
26846
|
+
const SERVER2 = process.env.ACP_SERVER ?? "http://localhost:4000";
|
|
26847
|
+
const TOKEN2 = process.env.ACP_TOKEN ?? "";
|
|
26848
|
+
console.log(`
|
|
26849
|
+
${C.b}\u{1FA7A} Jefri Chat connector \u2014 setup check${C.x}
|
|
26850
|
+
`);
|
|
26851
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
26852
|
+
if (major >= 18) pass(`Node ${process.version}`);
|
|
26853
|
+
else fail2(`Node ${process.version} is too old`, "Install Node 18+ from https://nodejs.org");
|
|
26854
|
+
pass(`Connector jefrichat-mcp v${connectorVersion()}`, "npm i -g jefrichat-mcp@latest to update");
|
|
26855
|
+
pass(`Hub URL ${SERVER2}`);
|
|
26856
|
+
if (!TOKEN2)
|
|
26857
|
+
fail2("No ACP_TOKEN set", "Get your token from jefrichat.com \u2192 Connect, then re-add the connector");
|
|
26858
|
+
else if (!TOKEN2.startsWith("acp_"))
|
|
26859
|
+
warn(`Token doesn't look right (${mask(TOKEN2)})`, "Tokens start with acp_ \u2014 check you copied the whole thing");
|
|
26860
|
+
else pass(`Token present (${mask(TOKEN2)})`);
|
|
26861
|
+
if (TOKEN2) {
|
|
26862
|
+
try {
|
|
26863
|
+
const r = await fetchWithTimeout(`${SERVER2}/api/me`, { headers: { Authorization: `Bearer ${TOKEN2}` } }, 8e3);
|
|
26864
|
+
if (r.status === 200) {
|
|
26865
|
+
const j = await r.json().catch(() => ({}));
|
|
26866
|
+
const id = j.identity ?? {};
|
|
26867
|
+
const owner = id.owner ? `, owned by @${id.owner}` : "";
|
|
26868
|
+
pass("Hub reachable & authenticated", `you are @${id.username ?? "?"} (${id.type ?? "?"}${owner})`);
|
|
26869
|
+
} else if (r.status === 401) {
|
|
26870
|
+
fail2("Token rejected by the hub (401)", "The agent may have been deleted or the token is wrong \u2014 get a fresh one from Connect");
|
|
26871
|
+
} else {
|
|
26872
|
+
fail2(`Hub returned HTTP ${r.status}`, "The hub is up but something's off \u2014 try again in a moment");
|
|
26873
|
+
}
|
|
26874
|
+
} catch (e) {
|
|
26875
|
+
const err = e;
|
|
26876
|
+
const reason = err?.name === "AbortError" ? "timed out" : err?.message ?? String(e);
|
|
26877
|
+
fail2(`Can't reach the hub (${reason})`, "Check internet / VPN / firewall \u2014 corporate networks sometimes block it");
|
|
26878
|
+
}
|
|
26879
|
+
} else {
|
|
26880
|
+
info("Skipping hub auth check (no token)");
|
|
26881
|
+
}
|
|
26882
|
+
const auto = getAuto();
|
|
26883
|
+
const brainCmd = auto.brain === "claude" ? "claude" : auto.brain === "codex" ? "codex" : auto.brain.trim().split(/\s+/)[0];
|
|
26884
|
+
if (hasCli(brainCmd)) pass(`Autonomous brain "${brainCmd}" found on PATH`);
|
|
26885
|
+
else info(`Autonomous brain "${brainCmd}" not on PATH (only needed if you enable autonomous mode)`);
|
|
26886
|
+
const prefs2 = getPrefs();
|
|
26887
|
+
if (!prefs2.enabled) info("Desktop notifications are OFF (use the jefri_notifications tool to turn on)");
|
|
26888
|
+
else if (macNeedsTerminalNotifier)
|
|
26889
|
+
warn("macOS notifications need terminal-notifier to show reliably", "run: brew install terminal-notifier");
|
|
26890
|
+
else if (process.platform === "win32")
|
|
26891
|
+
pass("Desktop notifications on (Windows toast)", "if they don't appear, turn off Focus Assist in Settings");
|
|
26892
|
+
else pass("Desktop notifications on");
|
|
26893
|
+
if (auto.enabled)
|
|
26894
|
+
info(`Autonomous mode is ON \u2014 brain "${auto.brain}" in ${auto.workdir} (jefri_autonomous to change)`);
|
|
26895
|
+
console.log("");
|
|
26896
|
+
if (problems === 0 && warnings === 0) {
|
|
26897
|
+
console.log(`${C.g}${C.b}All good \u2014 you're ready to chat.${C.x}
|
|
26898
|
+
`);
|
|
26899
|
+
} else if (problems === 0) {
|
|
26900
|
+
console.log(`${C.y}Ready, with ${warnings} thing${warnings === 1 ? "" : "s"} to look at above.${C.x}
|
|
26901
|
+
`);
|
|
26902
|
+
} else {
|
|
26903
|
+
console.log(
|
|
26904
|
+
`${C.r}${C.b}${problems} problem${problems === 1 ? "" : "s"} to fix${C.x}${warnings ? ` (+${warnings} warning${warnings === 1 ? "" : "s"})` : ""} before this will work. See the \u2192 hints above.
|
|
26905
|
+
`
|
|
26906
|
+
);
|
|
26907
|
+
}
|
|
26908
|
+
process.exitCode = problems ? 1 : 0;
|
|
26909
|
+
}
|
|
26910
|
+
|
|
26699
26911
|
// src/index.ts
|
|
26700
26912
|
var SERVER = process.env.ACP_SERVER ?? "http://localhost:4000";
|
|
26701
26913
|
var TOKEN = process.env.ACP_TOKEN;
|
|
@@ -26708,7 +26920,7 @@ var TOKEN_CACHE = path2.join(os5.homedir(), ".acp", "tokens.json");
|
|
|
26708
26920
|
var cacheKey = `${SERVER}::${USERNAME}`;
|
|
26709
26921
|
function readTokenCache() {
|
|
26710
26922
|
try {
|
|
26711
|
-
return JSON.parse(
|
|
26923
|
+
return JSON.parse(fs6.readFileSync(TOKEN_CACHE, "utf8"));
|
|
26712
26924
|
} catch {
|
|
26713
26925
|
return {};
|
|
26714
26926
|
}
|
|
@@ -26716,8 +26928,8 @@ function readTokenCache() {
|
|
|
26716
26928
|
function cacheToken(tok) {
|
|
26717
26929
|
const c = readTokenCache();
|
|
26718
26930
|
c[cacheKey] = tok;
|
|
26719
|
-
|
|
26720
|
-
|
|
26931
|
+
fs6.mkdirSync(path2.dirname(TOKEN_CACHE), { recursive: true });
|
|
26932
|
+
fs6.writeFileSync(TOKEN_CACHE, JSON.stringify(c, null, 2));
|
|
26721
26933
|
}
|
|
26722
26934
|
var clientPromise = null;
|
|
26723
26935
|
var inbox = [];
|
|
@@ -26765,6 +26977,25 @@ function ensureClient() {
|
|
|
26765
26977
|
});
|
|
26766
26978
|
void refreshAgents();
|
|
26767
26979
|
setInterval(refreshAgents, 6e4).unref?.();
|
|
26980
|
+
const getHistory = (conversationId) => new Promise((resolve) => {
|
|
26981
|
+
const handler = (e) => {
|
|
26982
|
+
if (e?.conversationId !== conversationId) return;
|
|
26983
|
+
c.off("history", handler);
|
|
26984
|
+
resolve((e.messages ?? []).map((mm) => ({ sender: mm.senderUsername, content: mm.content, kind: mm.kind, fileName: mm.fileName })));
|
|
26985
|
+
};
|
|
26986
|
+
c.on("history", handler);
|
|
26987
|
+
try {
|
|
26988
|
+
c.history(conversationId);
|
|
26989
|
+
} catch {
|
|
26990
|
+
c.off("history", handler);
|
|
26991
|
+
resolve([]);
|
|
26992
|
+
}
|
|
26993
|
+
setTimeout(() => {
|
|
26994
|
+
c.off("history", handler);
|
|
26995
|
+
resolve([]);
|
|
26996
|
+
}, 3e3);
|
|
26997
|
+
});
|
|
26998
|
+
configureAuto({ self, owner: c.identity?.owner, getHistory });
|
|
26768
26999
|
if (macNeedsTerminalNotifier)
|
|
26769
27000
|
log("tip: for reliable desktop notifications on macOS, run: brew install terminal-notifier");
|
|
26770
27001
|
if (getAuto().enabled)
|
|
@@ -26788,6 +27019,7 @@ function ensureClient() {
|
|
|
26788
27019
|
sender: m.senderUsername,
|
|
26789
27020
|
isGroup,
|
|
26790
27021
|
groupId: m.groupId,
|
|
27022
|
+
conversationId: m.conversationId,
|
|
26791
27023
|
isMention,
|
|
26792
27024
|
senderIsBot: agentUsers.has(m.senderUsername)
|
|
26793
27025
|
},
|
|
@@ -26811,6 +27043,10 @@ function ensureClient() {
|
|
|
26811
27043
|
var server = new McpServer({ name: "jefrichat", version: "0.1.0" });
|
|
26812
27044
|
registerAcpTools(server, { ensureClient, inbox, serverUrl: SERVER, local: true });
|
|
26813
27045
|
async function main() {
|
|
27046
|
+
if (process.argv[2] === "doctor") {
|
|
27047
|
+
await runDoctor();
|
|
27048
|
+
return;
|
|
27049
|
+
}
|
|
26814
27050
|
ensureClient().catch((e) => log("initial connect failed (will retry on first tool):", e?.message ?? e));
|
|
26815
27051
|
const transport = new StdioServerTransport();
|
|
26816
27052
|
await server.connect(transport);
|
package/package.json
CHANGED