@iletai/nzb 1.2.1 → 1.2.3
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/copilot/mcp-config.js +64 -11
- package/dist/telegram/bot.js +18 -0
- package/package.json +1 -1
|
@@ -1,31 +1,84 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
let cachedConfig;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
* Detect if running inside WSL.
|
|
7
|
+
*/
|
|
8
|
+
const isWSL = (() => {
|
|
9
|
+
try {
|
|
10
|
+
return readFileSync("/proc/version", "utf-8").toLowerCase().includes("microsoft");
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
})();
|
|
16
|
+
/**
|
|
17
|
+
* Transform a VS Code MCP server entry for native WSL execution.
|
|
18
|
+
* Strips `wsl.exe bash -c "..."` wrappers since NZB runs inside WSL directly.
|
|
19
|
+
* Also resolves `${input:...}` placeholders from environment or strips them.
|
|
20
|
+
*/
|
|
21
|
+
function transformForWSL(entry) {
|
|
22
|
+
if (!isWSL || entry.type !== "stdio")
|
|
23
|
+
return entry;
|
|
24
|
+
const cmd = entry.command;
|
|
25
|
+
const args = entry.args || [];
|
|
26
|
+
// Detect wsl.exe wrapper: wsl.exe [bash -c "actual command"]
|
|
27
|
+
if (cmd === "wsl.exe" || cmd === "wsl") {
|
|
28
|
+
// Find the actual command inside `bash -c "..."` pattern
|
|
29
|
+
const bashIdx = args.indexOf("bash");
|
|
30
|
+
const cIdx = bashIdx >= 0 ? args.indexOf("-c", bashIdx) : -1;
|
|
31
|
+
if (cIdx >= 0 && args.length > cIdx + 1) {
|
|
32
|
+
const innerCmd = args[cIdx + 1];
|
|
33
|
+
// Strip nvm source prefix if present (NZB already has node in PATH)
|
|
34
|
+
const cleaned = innerCmd
|
|
35
|
+
.replace(/^source\s+~\/\.nvm\/nvm\.sh\s*&&\s*/, "")
|
|
36
|
+
.replace(/^source\s+~\/\.nvm\/nvm\.sh\s*;\s*/, "")
|
|
37
|
+
.trim();
|
|
38
|
+
return {
|
|
39
|
+
...entry,
|
|
40
|
+
command: "bash",
|
|
41
|
+
args: ["-c", cleaned],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// npx commands referencing Windows paths — convert to Linux
|
|
46
|
+
if (cmd === "npx") {
|
|
47
|
+
const fixedArgs = args.map((a) => a.replace(/^([a-zA-Z]):\\/, (_, drive) => `/mnt/${drive.toLowerCase()}/`).replace(/\\/g, "/"));
|
|
48
|
+
return { ...entry, args: fixedArgs };
|
|
49
|
+
}
|
|
50
|
+
return entry;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load MCP server configs from ~/.nzb/mcp.json (NZB-specific, priority)
|
|
54
|
+
* then fall back to ~/.copilot/mcp-config.json (shared with VS Code).
|
|
55
|
+
* Skips disabled entries. Transforms wsl.exe wrappers for native WSL execution.
|
|
10
56
|
*/
|
|
11
57
|
export function loadMcpConfig() {
|
|
12
58
|
if (cachedConfig)
|
|
13
59
|
return cachedConfig;
|
|
14
|
-
const
|
|
60
|
+
const nzbPath = join(homedir(), ".nzb", "mcp.json");
|
|
61
|
+
const copilotPath = join(homedir(), ".copilot", "mcp-config.json");
|
|
62
|
+
const configPath = existsSync(nzbPath) ? nzbPath : copilotPath;
|
|
15
63
|
try {
|
|
16
64
|
const raw = readFileSync(configPath, "utf-8");
|
|
17
65
|
const parsed = JSON.parse(raw);
|
|
18
66
|
if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
|
|
19
|
-
// Filter out malformed entries — each server must have at least a type
|
|
20
67
|
const servers = {};
|
|
21
68
|
for (const [name, entry] of Object.entries(parsed.mcpServers)) {
|
|
22
|
-
if (entry
|
|
23
|
-
|
|
69
|
+
if (!entry || typeof entry !== "object" || !("type" in entry)) {
|
|
70
|
+
console.log(`[nzb] Skipping malformed MCP server '${name}'`);
|
|
71
|
+
continue;
|
|
24
72
|
}
|
|
25
|
-
|
|
26
|
-
|
|
73
|
+
const e = entry;
|
|
74
|
+
if (e.disabled) {
|
|
75
|
+
console.log(`[nzb] Skipping disabled MCP server '${name}'`);
|
|
76
|
+
continue;
|
|
27
77
|
}
|
|
78
|
+
const transformed = transformForWSL(e);
|
|
79
|
+
servers[name] = transformed;
|
|
28
80
|
}
|
|
81
|
+
console.log(`[nzb] Loaded ${Object.keys(servers).length} MCP servers from ${configPath}`);
|
|
29
82
|
cachedConfig = servers;
|
|
30
83
|
return servers;
|
|
31
84
|
}
|
package/dist/telegram/bot.js
CHANGED
|
@@ -247,6 +247,11 @@ export function createBot() {
|
|
|
247
247
|
const replyParams = { message_id: userMessageId };
|
|
248
248
|
const msgPreview = ctx.message.text.length > 80 ? ctx.message.text.slice(0, 80) + "…" : ctx.message.text;
|
|
249
249
|
void logInfo(`📩 Message: ${msgPreview}`);
|
|
250
|
+
// React with 👀 to acknowledge message received
|
|
251
|
+
try {
|
|
252
|
+
await ctx.react("👀");
|
|
253
|
+
}
|
|
254
|
+
catch { /* reactions may not be available */ }
|
|
250
255
|
// Typing indicator — keeps sending "typing" action every 4s until the final
|
|
251
256
|
// response is delivered. We use bot.api directly for reliability, and await the
|
|
252
257
|
// first call so the user sees typing immediately before any async work begins.
|
|
@@ -425,11 +430,19 @@ export function createBot() {
|
|
|
425
430
|
if (placeholderMsgId && chunks.length === 1) {
|
|
426
431
|
try {
|
|
427
432
|
await bot.api.editMessageText(chatId, placeholderMsgId, chunks[0], { parse_mode: "MarkdownV2" });
|
|
433
|
+
try {
|
|
434
|
+
await bot.api.setMessageReaction(chatId, userMessageId, [{ type: "emoji", emoji: "👍" }]);
|
|
435
|
+
}
|
|
436
|
+
catch { }
|
|
428
437
|
return;
|
|
429
438
|
}
|
|
430
439
|
catch {
|
|
431
440
|
try {
|
|
432
441
|
await bot.api.editMessageText(chatId, placeholderMsgId, fallbackChunks[0]);
|
|
442
|
+
try {
|
|
443
|
+
await bot.api.setMessageReaction(chatId, userMessageId, [{ type: "emoji", emoji: "👍" }]);
|
|
444
|
+
}
|
|
445
|
+
catch { }
|
|
433
446
|
return;
|
|
434
447
|
}
|
|
435
448
|
catch {
|
|
@@ -482,6 +495,11 @@ export function createBot() {
|
|
|
482
495
|
/* ignore — placeholder stays but user has the real message */
|
|
483
496
|
}
|
|
484
497
|
}
|
|
498
|
+
// React ✅ on the user's original message to signal completion
|
|
499
|
+
try {
|
|
500
|
+
await bot.api.setMessageReaction(chatId, userMessageId, [{ type: "emoji", emoji: "👍" }]);
|
|
501
|
+
}
|
|
502
|
+
catch { /* reactions may not be available */ }
|
|
485
503
|
});
|
|
486
504
|
}
|
|
487
505
|
else {
|