@iletai/nzb 1.1.0 → 1.1.2
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/api/server.js +1 -1
- package/dist/config.js +6 -0
- package/dist/copilot/orchestrator.js +3 -3
- package/dist/daemon.js +22 -2
- package/dist/telegram/bot.js +29 -7
- package/dist/update.js +14 -8
- package/package.json +1 -1
package/dist/api/server.js
CHANGED
|
@@ -28,7 +28,7 @@ const app = express();
|
|
|
28
28
|
app.use(express.json());
|
|
29
29
|
// Bearer token authentication middleware (skip /status health check)
|
|
30
30
|
app.use((req, res, next) => {
|
|
31
|
-
if (!apiToken || req.path === "/status"
|
|
31
|
+
if (!apiToken || req.path === "/status")
|
|
32
32
|
return next();
|
|
33
33
|
const auth = req.headers.authorization;
|
|
34
34
|
if (!auth || auth !== `Bearer ${apiToken}`) {
|
package/dist/config.js
CHANGED
|
@@ -11,8 +11,14 @@ const configSchema = z.object({
|
|
|
11
11
|
API_PORT: z.string().optional(),
|
|
12
12
|
COPILOT_MODEL: z.string().optional(),
|
|
13
13
|
WORKER_TIMEOUT: z.string().optional(),
|
|
14
|
+
NODE_EXTRA_CA_CERTS: z.string().optional(),
|
|
14
15
|
});
|
|
15
16
|
const raw = configSchema.parse(process.env);
|
|
17
|
+
// Apply NODE_EXTRA_CA_CERTS from .env if not already set via environment.
|
|
18
|
+
// This allows corporate users to configure their CA bundle path in ~/.nzb/.env.
|
|
19
|
+
if (raw.NODE_EXTRA_CA_CERTS && !process.env.NODE_EXTRA_CA_CERTS) {
|
|
20
|
+
process.env.NODE_EXTRA_CA_CERTS = raw.NODE_EXTRA_CA_CERTS;
|
|
21
|
+
}
|
|
16
22
|
const parsedUserId = raw.AUTHORIZED_USER_ID ? parseInt(raw.AUTHORIZED_USER_ID, 10) : undefined;
|
|
17
23
|
const parsedPort = parseInt(raw.API_PORT || "7777", 10);
|
|
18
24
|
if (parsedUserId !== undefined && (Number.isNaN(parsedUserId) || parsedUserId <= 0)) {
|
|
@@ -7,8 +7,8 @@ import { loadMcpConfig } from "./mcp-config.js";
|
|
|
7
7
|
import { getSkillDirectories } from "./skills.js";
|
|
8
8
|
import { getOrchestratorSystemMessage } from "./system-message.js";
|
|
9
9
|
import { createTools } from "./tools.js";
|
|
10
|
-
const MAX_RETRIES =
|
|
11
|
-
const RECONNECT_DELAYS_MS = [1_000,
|
|
10
|
+
const MAX_RETRIES = 2;
|
|
11
|
+
const RECONNECT_DELAYS_MS = [1_000, 5_000];
|
|
12
12
|
const HEALTH_CHECK_INTERVAL_MS = 30_000;
|
|
13
13
|
const ORCHESTRATOR_SESSION_KEY = "orchestrator_session_id";
|
|
14
14
|
let logMessage = () => { };
|
|
@@ -242,7 +242,7 @@ async function executeOnSession(prompt, callback, onToolEvent) {
|
|
|
242
242
|
callback(accumulated, false);
|
|
243
243
|
});
|
|
244
244
|
try {
|
|
245
|
-
const result = await session.sendAndWait({ prompt },
|
|
245
|
+
const result = await session.sendAndWait({ prompt }, 120_000);
|
|
246
246
|
const finalContent = result?.data?.content || accumulated || "(No response)";
|
|
247
247
|
return finalContent;
|
|
248
248
|
}
|
package/dist/daemon.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
+
import { existsSync } from "fs";
|
|
2
3
|
import { broadcastToSSE, startApiServer } from "./api/server.js";
|
|
3
4
|
import { config } from "./config.js";
|
|
4
5
|
import { getClient, stopClient } from "./copilot/client.js";
|
|
@@ -6,6 +7,21 @@ import { getWorkers, initOrchestrator, setMessageLogger, setProactiveNotify } fr
|
|
|
6
7
|
import { closeDb, getDb } from "./store/db.js";
|
|
7
8
|
import { createBot, sendProactiveMessage, startBot, stopBot } from "./telegram/bot.js";
|
|
8
9
|
import { checkForUpdate } from "./update.js";
|
|
10
|
+
// Auto-detect system CA bundle for corporate environments with TLS inspection.
|
|
11
|
+
// NODE_EXTRA_CA_CERTS must be set before any TLS connection is made.
|
|
12
|
+
// Users can override via NODE_EXTRA_CA_CERTS env var or NODE_EXTRA_CA_CERTS in ~/.nzb/.env.
|
|
13
|
+
if (!process.env.NODE_EXTRA_CA_CERTS) {
|
|
14
|
+
const knownCaBundles = [
|
|
15
|
+
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu
|
|
16
|
+
"/etc/pki/tls/certs/ca-bundle.crt", // RHEL/CentOS/Fedora
|
|
17
|
+
"/etc/ssl/cert.pem", // macOS / Alpine
|
|
18
|
+
];
|
|
19
|
+
const found = knownCaBundles.find((p) => existsSync(p));
|
|
20
|
+
if (found) {
|
|
21
|
+
process.env.NODE_EXTRA_CA_CERTS = found;
|
|
22
|
+
console.log(`[nzb] Auto-detected system CA bundle: ${found}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
9
25
|
function truncate(text, max = 200) {
|
|
10
26
|
const oneLine = text.replace(/\n/g, " ").trim();
|
|
11
27
|
return oneLine.length > max ? oneLine.slice(0, max) + "…" : oneLine;
|
|
@@ -60,11 +76,15 @@ async function main() {
|
|
|
60
76
|
console.log("[nzb] Telegram user ID missing — skipping bot. Run 'nzb setup' and enter your Telegram user ID (get it from @userinfobot).");
|
|
61
77
|
}
|
|
62
78
|
console.log("[nzb] NZB is fully operational.");
|
|
63
|
-
// Non-blocking update check
|
|
79
|
+
// Non-blocking update check — notify via console + all active channels
|
|
64
80
|
checkForUpdate()
|
|
65
81
|
.then(({ updateAvailable, current, latest }) => {
|
|
66
82
|
if (updateAvailable) {
|
|
67
|
-
|
|
83
|
+
const msg = `⬆ Update available: v${current} → v${latest} — run \`nzb update\` to install`;
|
|
84
|
+
console.log(`[nzb] ${msg}`);
|
|
85
|
+
if (config.telegramEnabled)
|
|
86
|
+
sendProactiveMessage(msg).catch(() => { });
|
|
87
|
+
broadcastToSSE(msg);
|
|
68
88
|
}
|
|
69
89
|
})
|
|
70
90
|
.catch(() => { }); // silent — network may be unavailable
|
package/dist/telegram/bot.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Bot } from "grammy";
|
|
2
|
+
import { Agent as HttpsAgent } from "https";
|
|
2
3
|
import { config, persistModel } from "../config.js";
|
|
3
4
|
import { cancelCurrentMessage, getQueueSize, getWorkers, sendToOrchestrator } from "../copilot/orchestrator.js";
|
|
4
5
|
import { listSkills } from "../copilot/skills.js";
|
|
@@ -7,6 +8,10 @@ import { searchMemories } from "../store/db.js";
|
|
|
7
8
|
import { chunkMessage, toTelegramMarkdown } from "./formatter.js";
|
|
8
9
|
let bot;
|
|
9
10
|
const startedAt = Date.now();
|
|
11
|
+
// Direct-connection HTTPS agent for Telegram API requests.
|
|
12
|
+
// This bypasses corporate proxy (HTTP_PROXY/HTTPS_PROXY env vars) without
|
|
13
|
+
// modifying process.env, so other services (Copilot SDK, MCP, npm) are unaffected.
|
|
14
|
+
const telegramAgent = new HttpsAgent({ keepAlive: true });
|
|
10
15
|
export function createBot() {
|
|
11
16
|
if (!config.telegramBotToken) {
|
|
12
17
|
throw new Error("Telegram bot token is missing. Run 'nzb setup' and enter the bot token from @BotFather.");
|
|
@@ -14,11 +19,20 @@ export function createBot() {
|
|
|
14
19
|
if (config.authorizedUserId === undefined) {
|
|
15
20
|
throw new Error("Telegram user ID is missing. Run 'nzb setup' and enter your Telegram user ID (get it from @userinfobot).");
|
|
16
21
|
}
|
|
17
|
-
bot = new Bot(config.telegramBotToken
|
|
22
|
+
bot = new Bot(config.telegramBotToken, {
|
|
23
|
+
client: {
|
|
24
|
+
baseFetchConfig: {
|
|
25
|
+
agent: telegramAgent,
|
|
26
|
+
compress: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
console.log("[nzb] Telegram bot using direct HTTPS agent (proxy bypass)");
|
|
18
31
|
// Auth middleware — only allow the authorized user
|
|
19
32
|
bot.use(async (ctx, next) => {
|
|
20
33
|
if (config.authorizedUserId !== undefined && ctx.from?.id !== config.authorizedUserId) {
|
|
21
|
-
|
|
34
|
+
console.log(`[nzb] Telegram auth rejected: user ${ctx.from?.id} (authorized: ${config.authorizedUserId})`);
|
|
35
|
+
return;
|
|
22
36
|
}
|
|
23
37
|
await next();
|
|
24
38
|
});
|
|
@@ -171,7 +185,8 @@ export function createBot() {
|
|
|
171
185
|
const enqueueEdit = (text) => {
|
|
172
186
|
if (finalized || text === lastEditedText)
|
|
173
187
|
return;
|
|
174
|
-
editChain = editChain
|
|
188
|
+
editChain = editChain
|
|
189
|
+
.then(async () => {
|
|
175
190
|
if (finalized || text === lastEditedText)
|
|
176
191
|
return;
|
|
177
192
|
if (!placeholderMsgId) {
|
|
@@ -199,7 +214,8 @@ export function createBot() {
|
|
|
199
214
|
}
|
|
200
215
|
}
|
|
201
216
|
lastEditedText = text;
|
|
202
|
-
})
|
|
217
|
+
})
|
|
218
|
+
.catch(() => { });
|
|
203
219
|
};
|
|
204
220
|
const onToolEvent = (event) => {
|
|
205
221
|
if (event.type === "tool_start") {
|
|
@@ -231,7 +247,9 @@ export function createBot() {
|
|
|
231
247
|
await bot.api.editMessageText(chatId, placeholderMsgId, fallbackChunks[0]);
|
|
232
248
|
return;
|
|
233
249
|
}
|
|
234
|
-
catch {
|
|
250
|
+
catch {
|
|
251
|
+
/* fall through to send new messages */
|
|
252
|
+
}
|
|
235
253
|
}
|
|
236
254
|
}
|
|
237
255
|
// Multi-chunk or no placeholder: delete placeholder and send chunks
|
|
@@ -239,7 +257,9 @@ export function createBot() {
|
|
|
239
257
|
try {
|
|
240
258
|
await bot.api.deleteMessage(chatId, placeholderMsgId);
|
|
241
259
|
}
|
|
242
|
-
catch {
|
|
260
|
+
catch {
|
|
261
|
+
/* ignore */
|
|
262
|
+
}
|
|
243
263
|
}
|
|
244
264
|
const sendChunk = async (chunk, fallback, isFirst) => {
|
|
245
265
|
const opts = isFirst
|
|
@@ -260,7 +280,9 @@ export function createBot() {
|
|
|
260
280
|
await ctx.reply(fallbackChunks[i], i === 0 ? { reply_parameters: replyParams } : {});
|
|
261
281
|
}
|
|
262
282
|
}
|
|
263
|
-
catch {
|
|
283
|
+
catch {
|
|
284
|
+
/* nothing more we can do */
|
|
285
|
+
}
|
|
264
286
|
}
|
|
265
287
|
});
|
|
266
288
|
}
|
package/dist/update.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
+
import { exec as execCb, execSync } from "child_process";
|
|
1
2
|
import { readFileSync } from "fs";
|
|
2
|
-
import {
|
|
3
|
+
import { dirname, join } from "path";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
|
-
import { exec as execCb, execSync } from "child_process";
|
|
5
5
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
|
|
6
|
+
const PKG_NAME = "@iletai/nzb";
|
|
7
|
+
function getPackageJson() {
|
|
7
8
|
try {
|
|
8
9
|
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
9
|
-
return pkg.version || "0.0.0";
|
|
10
|
+
return { name: pkg.name || PKG_NAME, version: pkg.version || "0.0.0" };
|
|
10
11
|
}
|
|
11
12
|
catch {
|
|
12
|
-
return "0.0.0";
|
|
13
|
+
return { name: PKG_NAME, version: "0.0.0" };
|
|
13
14
|
}
|
|
14
15
|
}
|
|
16
|
+
function getLocalVersion() {
|
|
17
|
+
return getPackageJson().version;
|
|
18
|
+
}
|
|
15
19
|
/** Run a command asynchronously and return stdout. */
|
|
16
20
|
function execAsync(cmd, timeoutMs) {
|
|
17
21
|
return new Promise((resolve, reject) => {
|
|
@@ -25,7 +29,8 @@ function execAsync(cmd, timeoutMs) {
|
|
|
25
29
|
/** Fetch the latest published version from npm. Returns null on failure. */
|
|
26
30
|
export async function getLatestVersion() {
|
|
27
31
|
try {
|
|
28
|
-
const
|
|
32
|
+
const { name } = getPackageJson();
|
|
33
|
+
const result = await execAsync(`npm view ${name} version`, 10_000);
|
|
29
34
|
return result || null;
|
|
30
35
|
}
|
|
31
36
|
catch {
|
|
@@ -54,10 +59,11 @@ export async function checkForUpdate() {
|
|
|
54
59
|
checkSucceeded: latest !== null,
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
|
-
/** Run `npm install -g
|
|
62
|
+
/** Run `npm install -g <pkg>@latest` and return success/failure. */
|
|
58
63
|
export async function performUpdate() {
|
|
59
64
|
try {
|
|
60
|
-
const
|
|
65
|
+
const { name } = getPackageJson();
|
|
66
|
+
const output = execSync(`npm install -g ${name}@latest`, {
|
|
61
67
|
encoding: "utf-8",
|
|
62
68
|
timeout: 60_000,
|
|
63
69
|
stdio: ["ignore", "pipe", "pipe"],
|