jefrichat-mcp 0.9.0 → 0.12.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 +19 -3
- package/dist/index.js +323 -112
- 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")) };
|
|
@@ -50607,7 +50612,10 @@ ${cmd}`
|
|
|
50607
50612
|
brain: external_exports.string().optional().describe("'claude', 'codex', or a full custom command (e.g. for OpenClaw)"),
|
|
50608
50613
|
workdir: external_exports.string().optional().describe("folder the brain works in (scope it!)"),
|
|
50609
50614
|
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"),
|
|
50615
|
+
persona: external_exports.string().optional().describe("role/instructions for the agent (injected as {persona})"),
|
|
50616
|
+
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."),
|
|
50617
|
+
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."),
|
|
50618
|
+
contextMessages: external_exports.number().optional().describe("how many recent messages of the conversation to give the brain for memory (0 = stateless, default 12)"),
|
|
50611
50619
|
replyToBots: external_exports.boolean().optional().describe("also auto-reply to other agents (default off \u2014 prevents bot loops)")
|
|
50612
50620
|
}
|
|
50613
50621
|
},
|
|
@@ -50615,9 +50623,13 @@ ${cmd}`
|
|
|
50615
50623
|
const patch = {};
|
|
50616
50624
|
if (typeof args.enabled === "boolean") patch.enabled = args.enabled;
|
|
50617
50625
|
if (typeof args.replyToBots === "boolean") patch.replyToBots = args.replyToBots;
|
|
50626
|
+
if (typeof args.ownerOnly === "boolean") patch.ownerOnly = args.ownerOnly;
|
|
50627
|
+
if (typeof args.contextMessages === "number") patch.contextMessages = Math.max(0, Math.min(40, Math.floor(args.contextMessages)));
|
|
50618
50628
|
if (typeof args.brain === "string" && args.brain.trim()) patch.brain = args.brain.trim();
|
|
50619
50629
|
if (typeof args.workdir === "string" && args.workdir.trim()) patch.workdir = args.workdir.trim();
|
|
50620
50630
|
if (typeof args.persona === "string") patch.persona = args.persona;
|
|
50631
|
+
if (typeof args.promptTemplate === "string" && args.promptTemplate.trim())
|
|
50632
|
+
patch.promptTemplate = args.promptTemplate.trim().toLowerCase() === "default" ? DEFAULT_TEMPLATE : args.promptTemplate;
|
|
50621
50633
|
if (args.replyMode) patch.replyMode = args.replyMode;
|
|
50622
50634
|
const c = setAuto(patch);
|
|
50623
50635
|
const modeLabel = c.replyMode === "all" ? "every message" : c.replyMode === "dms" ? "DMs only" : "DMs + group @mentions";
|
|
@@ -50626,8 +50638,12 @@ ${cmd}`
|
|
|
50626
50638
|
` Brain: ${c.brain}`,
|
|
50627
50639
|
` Work folder: ${c.workdir}`,
|
|
50628
50640
|
` Replies to: ${modeLabel}`,
|
|
50641
|
+
` Owner-only: ${c.ownerOnly ? "yes (only you direct me)" : "no (anyone who @mentions me)"}`,
|
|
50629
50642
|
` Persona: ${c.persona ? c.persona.slice(0, 80) : "(none)"}`,
|
|
50630
|
-
`
|
|
50643
|
+
` Conversation memory: ${c.contextMessages > 0 ? `last ${c.contextMessages} messages` : "off"}`,
|
|
50644
|
+
` Prompt: ${c.promptTemplate === DEFAULT_TEMPLATE ? "default (@name routing + ask-if-unclear)" : "custom"}`,
|
|
50645
|
+
` Reply to other bots: ${c.replyToBots ? "yes" : "no"}`,
|
|
50646
|
+
` Activity log: ~/.jefri/autonomous.log (watch it: tail -f ~/.jefri/autonomous.log)`
|
|
50631
50647
|
];
|
|
50632
50648
|
if (c.enabled)
|
|
50633
50649
|
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
|
|
|
@@ -25431,16 +25431,30 @@ import cp2 from "node:child_process";
|
|
|
25431
25431
|
import fs3 from "node:fs";
|
|
25432
25432
|
import np2 from "node:path";
|
|
25433
25433
|
import os3 from "node:os";
|
|
25434
|
+
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
25435
|
var DEFAULTS2 = {
|
|
25435
25436
|
enabled: false,
|
|
25436
25437
|
brain: "claude",
|
|
25437
25438
|
workdir: process.cwd(),
|
|
25438
25439
|
replyMode: "mentions",
|
|
25439
25440
|
persona: "",
|
|
25440
|
-
replyToBots: false
|
|
25441
|
+
replyToBots: false,
|
|
25442
|
+
ownerOnly: false,
|
|
25443
|
+
contextMessages: 12,
|
|
25444
|
+
promptTemplate: DEFAULT_TEMPLATE
|
|
25441
25445
|
};
|
|
25442
25446
|
var DIR = np2.join(os3.homedir(), ".jefri");
|
|
25443
25447
|
var FILE = np2.join(DIR, "autonomous.json");
|
|
25448
|
+
var LOG_FILE = np2.join(DIR, "autonomous.log");
|
|
25449
|
+
function logLine(line) {
|
|
25450
|
+
try {
|
|
25451
|
+
fs3.mkdirSync(DIR, { recursive: true });
|
|
25452
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
25453
|
+
fs3.appendFileSync(LOG_FILE, `[${ts}] ${line}
|
|
25454
|
+
`);
|
|
25455
|
+
} catch {
|
|
25456
|
+
}
|
|
25457
|
+
}
|
|
25444
25458
|
function loadCfg() {
|
|
25445
25459
|
try {
|
|
25446
25460
|
return { ...DEFAULTS2, ...JSON.parse(fs3.readFileSync(FILE, "utf8")) };
|
|
@@ -25461,6 +25475,14 @@ function setAuto(patch) {
|
|
|
25461
25475
|
}
|
|
25462
25476
|
return { ...cfg };
|
|
25463
25477
|
}
|
|
25478
|
+
var selfName = "";
|
|
25479
|
+
var ownerName = "";
|
|
25480
|
+
var fetchHistory = null;
|
|
25481
|
+
function configureAuto(opts) {
|
|
25482
|
+
selfName = opts.self;
|
|
25483
|
+
ownerName = opts.owner ?? "";
|
|
25484
|
+
fetchHistory = opts.getHistory;
|
|
25485
|
+
}
|
|
25464
25486
|
var expand = (p) => p.startsWith("~") ? np2.join(os3.homedir(), p.slice(1)) : p;
|
|
25465
25487
|
function brainArgv(brain, prompt) {
|
|
25466
25488
|
if (brain === "claude") return ["claude", ["-p", "--permission-mode", "acceptEdits", prompt]];
|
|
@@ -25468,11 +25490,13 @@ function brainArgv(brain, prompt) {
|
|
|
25468
25490
|
const parts = brain.trim().split(/\s+/);
|
|
25469
25491
|
return [parts[0], [...parts.slice(1), prompt]];
|
|
25470
25492
|
}
|
|
25471
|
-
var MAX_PROMPT =
|
|
25493
|
+
var MAX_PROMPT = 12e3;
|
|
25472
25494
|
var MAX_REPLY = 7900;
|
|
25473
25495
|
var TIMEOUT_MS = 5 * 60 * 1e3;
|
|
25474
25496
|
function shouldHandle(m) {
|
|
25475
25497
|
if (!cfg.enabled) return false;
|
|
25498
|
+
const fromOwner = !!ownerName && m.sender === ownerName;
|
|
25499
|
+
if (cfg.ownerOnly && !fromOwner) return false;
|
|
25476
25500
|
if (m.senderIsBot && !cfg.replyToBots) return false;
|
|
25477
25501
|
if (!m.isGroup) return true;
|
|
25478
25502
|
if (cfg.replyMode === "all") return true;
|
|
@@ -25522,23 +25546,47 @@ function runBrain(cmd, args, cwd) {
|
|
|
25522
25546
|
});
|
|
25523
25547
|
});
|
|
25524
25548
|
}
|
|
25549
|
+
async function buildContext(conversationId) {
|
|
25550
|
+
if (cfg.contextMessages <= 0 || !fetchHistory) return "";
|
|
25551
|
+
let msgs = [];
|
|
25552
|
+
try {
|
|
25553
|
+
msgs = await fetchHistory(conversationId);
|
|
25554
|
+
} catch {
|
|
25555
|
+
return "";
|
|
25556
|
+
}
|
|
25557
|
+
const recent = msgs.slice(-cfg.contextMessages);
|
|
25558
|
+
if (!recent.length) return "";
|
|
25559
|
+
const lines = recent.map((h) => {
|
|
25560
|
+
const body = h.kind === "file" ? `[sent a file: ${h.fileName ?? "file"}]` : h.content ?? "";
|
|
25561
|
+
return `@${h.sender}: ${body.replace(/\s+/g, " ").slice(0, 400)}`;
|
|
25562
|
+
});
|
|
25563
|
+
return `Recent conversation (for context \u2014 reply only to the latest message):
|
|
25564
|
+
${lines.join("\n")}
|
|
25565
|
+
|
|
25566
|
+
`;
|
|
25567
|
+
}
|
|
25525
25568
|
function handleAutonomous(m, reply, log2) {
|
|
25526
25569
|
if (!shouldHandle(m)) return;
|
|
25570
|
+
const where = m.isGroup ? " in a group" : "";
|
|
25571
|
+
logLine(`\u2190 @${m.sender}${where}: ${m.content.replace(/\s+/g, " ").slice(0, 300)}`);
|
|
25527
25572
|
queue.push(async () => {
|
|
25528
25573
|
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);
|
|
25574
|
+
const context = await buildContext(m.conversationId);
|
|
25575
|
+
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
25576
|
const [cmd, args] = brainArgv(cfg.brain, prompt);
|
|
25534
|
-
log2(`autonomous: @${m.sender} \u2192 running "${
|
|
25577
|
+
log2(`autonomous: @${m.sender} \u2192 running "${cfg.brain}"\u2026`);
|
|
25578
|
+
logLine(` running: ${cfg.brain} in ${cfg.workdir}`);
|
|
25535
25579
|
try {
|
|
25536
25580
|
const out = await runBrain(cmd, args, cfg.workdir);
|
|
25537
|
-
|
|
25581
|
+
const text = (out.trim() || "(done)").slice(0, MAX_REPLY);
|
|
25582
|
+
reply(text);
|
|
25538
25583
|
log2(`autonomous: replied to @${m.sender}`);
|
|
25584
|
+
logLine(` \u2192 replied: ${text.replace(/\s+/g, " ").slice(0, 300)}`);
|
|
25539
25585
|
} catch (e) {
|
|
25540
|
-
|
|
25586
|
+
const msg = `(couldn't finish autonomously: ${e?.message ?? e})`.slice(0, MAX_REPLY);
|
|
25587
|
+
reply(msg);
|
|
25541
25588
|
log2(`autonomous: failed for @${m.sender}: ${e?.message ?? e}`);
|
|
25589
|
+
logLine(` \u2717 failed: ${e?.message ?? e}`);
|
|
25542
25590
|
}
|
|
25543
25591
|
});
|
|
25544
25592
|
void drain();
|
|
@@ -26651,7 +26699,10 @@ ${cmd}`
|
|
|
26651
26699
|
brain: external_exports.string().optional().describe("'claude', 'codex', or a full custom command (e.g. for OpenClaw)"),
|
|
26652
26700
|
workdir: external_exports.string().optional().describe("folder the brain works in (scope it!)"),
|
|
26653
26701
|
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"),
|
|
26702
|
+
persona: external_exports.string().optional().describe("role/instructions for the agent (injected as {persona})"),
|
|
26703
|
+
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."),
|
|
26704
|
+
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."),
|
|
26705
|
+
contextMessages: external_exports.number().optional().describe("how many recent messages of the conversation to give the brain for memory (0 = stateless, default 12)"),
|
|
26655
26706
|
replyToBots: external_exports.boolean().optional().describe("also auto-reply to other agents (default off \u2014 prevents bot loops)")
|
|
26656
26707
|
}
|
|
26657
26708
|
},
|
|
@@ -26659,9 +26710,13 @@ ${cmd}`
|
|
|
26659
26710
|
const patch = {};
|
|
26660
26711
|
if (typeof args.enabled === "boolean") patch.enabled = args.enabled;
|
|
26661
26712
|
if (typeof args.replyToBots === "boolean") patch.replyToBots = args.replyToBots;
|
|
26713
|
+
if (typeof args.ownerOnly === "boolean") patch.ownerOnly = args.ownerOnly;
|
|
26714
|
+
if (typeof args.contextMessages === "number") patch.contextMessages = Math.max(0, Math.min(40, Math.floor(args.contextMessages)));
|
|
26662
26715
|
if (typeof args.brain === "string" && args.brain.trim()) patch.brain = args.brain.trim();
|
|
26663
26716
|
if (typeof args.workdir === "string" && args.workdir.trim()) patch.workdir = args.workdir.trim();
|
|
26664
26717
|
if (typeof args.persona === "string") patch.persona = args.persona;
|
|
26718
|
+
if (typeof args.promptTemplate === "string" && args.promptTemplate.trim())
|
|
26719
|
+
patch.promptTemplate = args.promptTemplate.trim().toLowerCase() === "default" ? DEFAULT_TEMPLATE : args.promptTemplate;
|
|
26665
26720
|
if (args.replyMode) patch.replyMode = args.replyMode;
|
|
26666
26721
|
const c = setAuto(patch);
|
|
26667
26722
|
const modeLabel = c.replyMode === "all" ? "every message" : c.replyMode === "dms" ? "DMs only" : "DMs + group @mentions";
|
|
@@ -26670,8 +26725,12 @@ ${cmd}`
|
|
|
26670
26725
|
` Brain: ${c.brain}`,
|
|
26671
26726
|
` Work folder: ${c.workdir}`,
|
|
26672
26727
|
` Replies to: ${modeLabel}`,
|
|
26728
|
+
` Owner-only: ${c.ownerOnly ? "yes (only you direct me)" : "no (anyone who @mentions me)"}`,
|
|
26673
26729
|
` Persona: ${c.persona ? c.persona.slice(0, 80) : "(none)"}`,
|
|
26674
|
-
`
|
|
26730
|
+
` Conversation memory: ${c.contextMessages > 0 ? `last ${c.contextMessages} messages` : "off"}`,
|
|
26731
|
+
` Prompt: ${c.promptTemplate === DEFAULT_TEMPLATE ? "default (@name routing + ask-if-unclear)" : "custom"}`,
|
|
26732
|
+
` Reply to other bots: ${c.replyToBots ? "yes" : "no"}`,
|
|
26733
|
+
` Activity log: ~/.jefri/autonomous.log (watch it: tail -f ~/.jefri/autonomous.log)`
|
|
26675
26734
|
];
|
|
26676
26735
|
if (c.enabled)
|
|
26677
26736
|
lines.push(`
|
|
@@ -26696,6 +26755,134 @@ function attachInbox(c, inbox2, self, onIncoming) {
|
|
|
26696
26755
|
c.on("file_received", capture);
|
|
26697
26756
|
}
|
|
26698
26757
|
|
|
26758
|
+
// src/doctor.ts
|
|
26759
|
+
import cp4 from "node:child_process";
|
|
26760
|
+
import fs5 from "node:fs";
|
|
26761
|
+
import np4 from "node:path";
|
|
26762
|
+
import { fileURLToPath } from "node:url";
|
|
26763
|
+
var T = !!process.stdout.isTTY;
|
|
26764
|
+
var C = {
|
|
26765
|
+
g: T ? "\x1B[32m" : "",
|
|
26766
|
+
r: T ? "\x1B[31m" : "",
|
|
26767
|
+
y: T ? "\x1B[33m" : "",
|
|
26768
|
+
d: T ? "\x1B[2m" : "",
|
|
26769
|
+
b: T ? "\x1B[1m" : "",
|
|
26770
|
+
x: T ? "\x1B[0m" : ""
|
|
26771
|
+
};
|
|
26772
|
+
var problems = 0;
|
|
26773
|
+
var warnings = 0;
|
|
26774
|
+
var pass = (s, extra = "") => console.log(` ${C.g}\u2713${C.x} ${s}${extra ? ` ${C.d}${extra}${C.x}` : ""}`);
|
|
26775
|
+
var fail2 = (s, fix = "") => {
|
|
26776
|
+
problems++;
|
|
26777
|
+
console.log(` ${C.r}\u2717${C.x} ${s}${fix ? `
|
|
26778
|
+
${C.y}\u2192 ${fix}${C.x}` : ""}`);
|
|
26779
|
+
};
|
|
26780
|
+
var warn = (s, fix = "") => {
|
|
26781
|
+
warnings++;
|
|
26782
|
+
console.log(` ${C.y}!${C.x} ${s}${fix ? `
|
|
26783
|
+
${C.d}${fix}${C.x}` : ""}`);
|
|
26784
|
+
};
|
|
26785
|
+
var info = (s) => console.log(` ${C.d}i ${s}${C.x}`);
|
|
26786
|
+
function mask(t) {
|
|
26787
|
+
if (t.length <= 12) return t.slice(0, 4) + "\u2026";
|
|
26788
|
+
return t.slice(0, 8) + "\u2026" + t.slice(-4);
|
|
26789
|
+
}
|
|
26790
|
+
function connectorVersion() {
|
|
26791
|
+
try {
|
|
26792
|
+
const here = np4.dirname(fileURLToPath(import.meta.url));
|
|
26793
|
+
const pkg = JSON.parse(fs5.readFileSync(np4.join(here, "..", "package.json"), "utf8"));
|
|
26794
|
+
return pkg.version ?? "?";
|
|
26795
|
+
} catch {
|
|
26796
|
+
return "?";
|
|
26797
|
+
}
|
|
26798
|
+
}
|
|
26799
|
+
function hasCli(cmd) {
|
|
26800
|
+
try {
|
|
26801
|
+
const r = cp4.spawnSync(cmd, ["--version"], {
|
|
26802
|
+
encoding: "utf8",
|
|
26803
|
+
timeout: 5e3,
|
|
26804
|
+
shell: process.platform === "win32"
|
|
26805
|
+
});
|
|
26806
|
+
return r.status === 0 || !!(r.stdout && r.stdout.trim());
|
|
26807
|
+
} catch {
|
|
26808
|
+
return false;
|
|
26809
|
+
}
|
|
26810
|
+
}
|
|
26811
|
+
async function fetchWithTimeout(url, opts, ms) {
|
|
26812
|
+
const ac = new AbortController();
|
|
26813
|
+
const t = setTimeout(() => ac.abort(), ms);
|
|
26814
|
+
try {
|
|
26815
|
+
return await fetch(url, { ...opts, signal: ac.signal });
|
|
26816
|
+
} finally {
|
|
26817
|
+
clearTimeout(t);
|
|
26818
|
+
}
|
|
26819
|
+
}
|
|
26820
|
+
async function runDoctor() {
|
|
26821
|
+
const SERVER2 = process.env.ACP_SERVER ?? "http://localhost:4000";
|
|
26822
|
+
const TOKEN2 = process.env.ACP_TOKEN ?? "";
|
|
26823
|
+
console.log(`
|
|
26824
|
+
${C.b}\u{1FA7A} Jefri Chat connector \u2014 setup check${C.x}
|
|
26825
|
+
`);
|
|
26826
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
26827
|
+
if (major >= 18) pass(`Node ${process.version}`);
|
|
26828
|
+
else fail2(`Node ${process.version} is too old`, "Install Node 18+ from https://nodejs.org");
|
|
26829
|
+
pass(`Connector jefrichat-mcp v${connectorVersion()}`, "npm i -g jefrichat-mcp@latest to update");
|
|
26830
|
+
pass(`Hub URL ${SERVER2}`);
|
|
26831
|
+
if (!TOKEN2)
|
|
26832
|
+
fail2("No ACP_TOKEN set", "Get your token from jefrichat.com \u2192 Connect, then re-add the connector");
|
|
26833
|
+
else if (!TOKEN2.startsWith("acp_"))
|
|
26834
|
+
warn(`Token doesn't look right (${mask(TOKEN2)})`, "Tokens start with acp_ \u2014 check you copied the whole thing");
|
|
26835
|
+
else pass(`Token present (${mask(TOKEN2)})`);
|
|
26836
|
+
if (TOKEN2) {
|
|
26837
|
+
try {
|
|
26838
|
+
const r = await fetchWithTimeout(`${SERVER2}/api/me`, { headers: { Authorization: `Bearer ${TOKEN2}` } }, 8e3);
|
|
26839
|
+
if (r.status === 200) {
|
|
26840
|
+
const j = await r.json().catch(() => ({}));
|
|
26841
|
+
const id = j.identity ?? {};
|
|
26842
|
+
const owner = id.owner ? `, owned by @${id.owner}` : "";
|
|
26843
|
+
pass("Hub reachable & authenticated", `you are @${id.username ?? "?"} (${id.type ?? "?"}${owner})`);
|
|
26844
|
+
} else if (r.status === 401) {
|
|
26845
|
+
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");
|
|
26846
|
+
} else {
|
|
26847
|
+
fail2(`Hub returned HTTP ${r.status}`, "The hub is up but something's off \u2014 try again in a moment");
|
|
26848
|
+
}
|
|
26849
|
+
} catch (e) {
|
|
26850
|
+
const err = e;
|
|
26851
|
+
const reason = err?.name === "AbortError" ? "timed out" : err?.message ?? String(e);
|
|
26852
|
+
fail2(`Can't reach the hub (${reason})`, "Check internet / VPN / firewall \u2014 corporate networks sometimes block it");
|
|
26853
|
+
}
|
|
26854
|
+
} else {
|
|
26855
|
+
info("Skipping hub auth check (no token)");
|
|
26856
|
+
}
|
|
26857
|
+
const auto = getAuto();
|
|
26858
|
+
const brainCmd = auto.brain === "claude" ? "claude" : auto.brain === "codex" ? "codex" : auto.brain.trim().split(/\s+/)[0];
|
|
26859
|
+
if (hasCli(brainCmd)) pass(`Autonomous brain "${brainCmd}" found on PATH`);
|
|
26860
|
+
else info(`Autonomous brain "${brainCmd}" not on PATH (only needed if you enable autonomous mode)`);
|
|
26861
|
+
const prefs2 = getPrefs();
|
|
26862
|
+
if (!prefs2.enabled) info("Desktop notifications are OFF (use the jefri_notifications tool to turn on)");
|
|
26863
|
+
else if (macNeedsTerminalNotifier)
|
|
26864
|
+
warn("macOS notifications need terminal-notifier to show reliably", "run: brew install terminal-notifier");
|
|
26865
|
+
else if (process.platform === "win32")
|
|
26866
|
+
pass("Desktop notifications on (Windows toast)", "if they don't appear, turn off Focus Assist in Settings");
|
|
26867
|
+
else pass("Desktop notifications on");
|
|
26868
|
+
if (auto.enabled)
|
|
26869
|
+
info(`Autonomous mode is ON \u2014 brain "${auto.brain}" in ${auto.workdir} (jefri_autonomous to change)`);
|
|
26870
|
+
console.log("");
|
|
26871
|
+
if (problems === 0 && warnings === 0) {
|
|
26872
|
+
console.log(`${C.g}${C.b}All good \u2014 you're ready to chat.${C.x}
|
|
26873
|
+
`);
|
|
26874
|
+
} else if (problems === 0) {
|
|
26875
|
+
console.log(`${C.y}Ready, with ${warnings} thing${warnings === 1 ? "" : "s"} to look at above.${C.x}
|
|
26876
|
+
`);
|
|
26877
|
+
} else {
|
|
26878
|
+
console.log(
|
|
26879
|
+
`${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.
|
|
26880
|
+
`
|
|
26881
|
+
);
|
|
26882
|
+
}
|
|
26883
|
+
process.exitCode = problems ? 1 : 0;
|
|
26884
|
+
}
|
|
26885
|
+
|
|
26699
26886
|
// src/index.ts
|
|
26700
26887
|
var SERVER = process.env.ACP_SERVER ?? "http://localhost:4000";
|
|
26701
26888
|
var TOKEN = process.env.ACP_TOKEN;
|
|
@@ -26708,7 +26895,7 @@ var TOKEN_CACHE = path2.join(os5.homedir(), ".acp", "tokens.json");
|
|
|
26708
26895
|
var cacheKey = `${SERVER}::${USERNAME}`;
|
|
26709
26896
|
function readTokenCache() {
|
|
26710
26897
|
try {
|
|
26711
|
-
return JSON.parse(
|
|
26898
|
+
return JSON.parse(fs6.readFileSync(TOKEN_CACHE, "utf8"));
|
|
26712
26899
|
} catch {
|
|
26713
26900
|
return {};
|
|
26714
26901
|
}
|
|
@@ -26716,8 +26903,8 @@ function readTokenCache() {
|
|
|
26716
26903
|
function cacheToken(tok) {
|
|
26717
26904
|
const c = readTokenCache();
|
|
26718
26905
|
c[cacheKey] = tok;
|
|
26719
|
-
|
|
26720
|
-
|
|
26906
|
+
fs6.mkdirSync(path2.dirname(TOKEN_CACHE), { recursive: true });
|
|
26907
|
+
fs6.writeFileSync(TOKEN_CACHE, JSON.stringify(c, null, 2));
|
|
26721
26908
|
}
|
|
26722
26909
|
var clientPromise = null;
|
|
26723
26910
|
var inbox = [];
|
|
@@ -26765,6 +26952,25 @@ function ensureClient() {
|
|
|
26765
26952
|
});
|
|
26766
26953
|
void refreshAgents();
|
|
26767
26954
|
setInterval(refreshAgents, 6e4).unref?.();
|
|
26955
|
+
const getHistory = (conversationId) => new Promise((resolve) => {
|
|
26956
|
+
const handler = (e) => {
|
|
26957
|
+
if (e?.conversationId !== conversationId) return;
|
|
26958
|
+
c.off("history", handler);
|
|
26959
|
+
resolve((e.messages ?? []).map((mm) => ({ sender: mm.senderUsername, content: mm.content, kind: mm.kind, fileName: mm.fileName })));
|
|
26960
|
+
};
|
|
26961
|
+
c.on("history", handler);
|
|
26962
|
+
try {
|
|
26963
|
+
c.history(conversationId);
|
|
26964
|
+
} catch {
|
|
26965
|
+
c.off("history", handler);
|
|
26966
|
+
resolve([]);
|
|
26967
|
+
}
|
|
26968
|
+
setTimeout(() => {
|
|
26969
|
+
c.off("history", handler);
|
|
26970
|
+
resolve([]);
|
|
26971
|
+
}, 3e3);
|
|
26972
|
+
});
|
|
26973
|
+
configureAuto({ self, owner: c.identity?.owner, getHistory });
|
|
26768
26974
|
if (macNeedsTerminalNotifier)
|
|
26769
26975
|
log("tip: for reliable desktop notifications on macOS, run: brew install terminal-notifier");
|
|
26770
26976
|
if (getAuto().enabled)
|
|
@@ -26788,6 +26994,7 @@ function ensureClient() {
|
|
|
26788
26994
|
sender: m.senderUsername,
|
|
26789
26995
|
isGroup,
|
|
26790
26996
|
groupId: m.groupId,
|
|
26997
|
+
conversationId: m.conversationId,
|
|
26791
26998
|
isMention,
|
|
26792
26999
|
senderIsBot: agentUsers.has(m.senderUsername)
|
|
26793
27000
|
},
|
|
@@ -26811,6 +27018,10 @@ function ensureClient() {
|
|
|
26811
27018
|
var server = new McpServer({ name: "jefrichat", version: "0.1.0" });
|
|
26812
27019
|
registerAcpTools(server, { ensureClient, inbox, serverUrl: SERVER, local: true });
|
|
26813
27020
|
async function main() {
|
|
27021
|
+
if (process.argv[2] === "doctor") {
|
|
27022
|
+
await runDoctor();
|
|
27023
|
+
return;
|
|
27024
|
+
}
|
|
26814
27025
|
ensureClient().catch((e) => log("initial connect failed (will retry on first tool):", e?.message ?? e));
|
|
26815
27026
|
const transport = new StdioServerTransport();
|
|
26816
27027
|
await server.connect(transport);
|
package/package.json
CHANGED