teleton 0.8.0 → 0.8.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/README.md +28 -11
- package/dist/{chunk-H36RFKRI.js → chunk-2IZU3REP.js} +572 -174
- package/dist/chunk-3UFPFWYP.js +12 -0
- package/dist/{chunk-NUGDTPE4.js → chunk-4L66JHQE.js} +2 -1
- package/dist/{chunk-TVRZJIZX.js → chunk-55SKE6YH.js} +4 -4
- package/dist/{setup-server-QXED3D2L.js → chunk-57URFK6M.js} +161 -210
- package/dist/chunk-5SEMA47R.js +75 -0
- package/dist/{chunk-JHYZYFZJ.js → chunk-7YKSXOQQ.js} +17 -2
- package/dist/{chunk-IJBWWQE4.js → chunk-C4NKJT2Z.js} +12 -0
- package/dist/{chunk-RQBAMUCV.js → chunk-GGXJLMOH.js} +1451 -743
- package/dist/{chunk-WIKM24GZ.js → chunk-H7MFXJZK.js} +7 -2
- package/dist/{chunk-U56QTM46.js → chunk-HEDJCLA6.js} +85 -44
- package/dist/{chunk-QVBSUYVX.js → chunk-J73TA3UM.js} +17 -9
- package/dist/{chunk-P36I6OIV.js → chunk-LC4TV3KL.js} +13 -2
- package/dist/{chunk-RCMD3U65.js → chunk-NQ6FZKCE.js} +13 -0
- package/dist/{chunk-SD4NLLYG.js → chunk-VYKW7FMV.js} +224 -93
- package/dist/chunk-W25Z7CM6.js +487 -0
- package/dist/{chunk-OJCLKU5Z.js → chunk-WFTC3JJW.js} +16 -0
- package/dist/{server-H3QA252W.js → chunk-XBSCYMKM.js} +369 -374
- package/dist/{chunk-PHSAHTK4.js → chunk-YOSUPUAJ.js} +75 -7
- package/dist/cli/index.js +67 -22
- package/dist/{client-LNZTDQSA.js → client-YOOHI776.js} +4 -4
- package/dist/{get-my-gifts-OMGKOEPM.js → get-my-gifts-Y7EN7RK4.js} +3 -3
- package/dist/index.js +15 -14
- package/dist/{memory-AS7WKGTW.js → memory-Q6EWGK2S.js} +7 -5
- package/dist/memory-hook-WUXJNVT5.js +18 -0
- package/dist/{migrate-POHWYEIW.js → migrate-WFU6COBN.js} +5 -5
- package/dist/server-GYZXKIKU.js +787 -0
- package/dist/server-YODFBZKG.js +392 -0
- package/dist/setup-server-IZBUOJRU.js +215 -0
- package/dist/{store-GAFULOOX.js → store-7M4XV6M5.js} +6 -6
- package/dist/{task-dependency-resolver-3FIKQ7Z6.js → task-dependency-resolver-L6UUMTHK.js} +3 -3
- package/dist/{task-executor-RUTFG6VG.js → task-executor-XBNJLUCS.js} +3 -3
- package/dist/{tasks-BEZ4QRI2.js → tasks-WQIKXDX5.js} +1 -1
- package/dist/{tool-adapter-IH5VGBOO.js → tool-adapter-IVX2XQJE.js} +1 -1
- package/dist/{tool-index-H3SHOJC3.js → tool-index-NYH57UWP.js} +9 -6
- package/dist/{transcript-IMNE6KU3.js → transcript-IM7G25OS.js} +2 -2
- package/dist/web/assets/index-BfYCdwLI.js +80 -0
- package/dist/web/assets/{index-BrVqauzj.css → index-DmlyQVhR.css} +1 -1
- package/dist/web/assets/{index.es-DkU1GvWU.js → index.es-DitvF-9H.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +14 -5
- package/dist/chunk-XBE4JB7C.js +0 -8
- package/dist/web/assets/index-DYeEkvJ6.js +0 -72
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/utils/errors.ts
|
|
2
|
+
function getErrorMessage(error) {
|
|
3
|
+
return error instanceof Error ? error.message : String(error);
|
|
4
|
+
}
|
|
5
|
+
function isHttpError(err) {
|
|
6
|
+
return typeof err === "object" && err !== null && ("status" in err || "response" in err);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
getErrorMessage,
|
|
11
|
+
isHttpError
|
|
12
|
+
};
|
|
@@ -239,6 +239,7 @@ var TaskStore = class {
|
|
|
239
239
|
* Get all parent task results for a dependent task.
|
|
240
240
|
* Uses a single JOIN query instead of N+1 queries.
|
|
241
241
|
*/
|
|
242
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- result is JSON-parsed dynamic data
|
|
242
243
|
getParentResults(taskId) {
|
|
243
244
|
const rows = this.db.prepare(
|
|
244
245
|
`
|
|
@@ -254,7 +255,7 @@ var TaskStore = class {
|
|
|
254
255
|
let parsedResult;
|
|
255
256
|
try {
|
|
256
257
|
parsedResult = JSON.parse(row.result);
|
|
257
|
-
} catch
|
|
258
|
+
} catch {
|
|
258
259
|
parsedResult = row.result;
|
|
259
260
|
}
|
|
260
261
|
return {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getDatabase
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VYKW7FMV.js";
|
|
4
4
|
import {
|
|
5
5
|
createLogger
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
7
7
|
|
|
8
8
|
// src/session/store.ts
|
|
9
9
|
import { randomUUID } from "crypto";
|
|
@@ -255,8 +255,8 @@ function shouldResetSession(session, policy) {
|
|
|
255
255
|
}
|
|
256
256
|
return false;
|
|
257
257
|
}
|
|
258
|
-
function resetSessionWithPolicy(chatId,
|
|
259
|
-
|
|
258
|
+
function resetSessionWithPolicy(chatId, _policy) {
|
|
259
|
+
resetSession(chatId);
|
|
260
260
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
261
261
|
return updateSession(chatId, {
|
|
262
262
|
lastResetDate: today
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getModelsForProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WFTC3JJW.js";
|
|
4
4
|
import {
|
|
5
5
|
ConfigSchema,
|
|
6
6
|
DealsConfigSchema,
|
|
@@ -11,40 +11,26 @@ import {
|
|
|
11
11
|
isNewWorkspace,
|
|
12
12
|
saveWallet,
|
|
13
13
|
walletExists
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7YKSXOQQ.js";
|
|
15
15
|
import {
|
|
16
16
|
getClaudeCodeApiKey,
|
|
17
17
|
getProviderMetadata,
|
|
18
18
|
getSupportedProviders,
|
|
19
19
|
isClaudeCodeTokenValid,
|
|
20
20
|
validateApiKeyFormat
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-VFA7QMCZ.js";
|
|
21
|
+
} from "./chunk-YOSUPUAJ.js";
|
|
23
22
|
import {
|
|
24
23
|
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
25
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-C4NKJT2Z.js";
|
|
26
25
|
import {
|
|
27
26
|
fetchWithTimeout
|
|
28
27
|
} from "./chunk-XQUHC3JZ.js";
|
|
29
|
-
import "./chunk-R4YSJ4EY.js";
|
|
30
28
|
import {
|
|
31
29
|
TELETON_ROOT
|
|
32
30
|
} from "./chunk-EYWNOHMJ.js";
|
|
33
31
|
import {
|
|
34
32
|
createLogger
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import "./chunk-3RG5ZIWI.js";
|
|
37
|
-
|
|
38
|
-
// src/webui/setup-server.ts
|
|
39
|
-
import { Hono as Hono2 } from "hono";
|
|
40
|
-
import { serve } from "@hono/node-server";
|
|
41
|
-
import { cors } from "hono/cors";
|
|
42
|
-
import { bodyLimit } from "hono/body-limit";
|
|
43
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
44
|
-
import { join as join3, dirname as dirname2, resolve, relative } from "path";
|
|
45
|
-
import { fileURLToPath } from "url";
|
|
46
|
-
import { exec } from "child_process";
|
|
47
|
-
import { platform } from "os";
|
|
33
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
48
34
|
|
|
49
35
|
// src/webui/routes/setup.ts
|
|
50
36
|
import { Hono } from "hono";
|
|
@@ -110,6 +96,7 @@ var TelegramAuthManager = class {
|
|
|
110
96
|
const id = randomBytes(16).toString("hex");
|
|
111
97
|
const expiresAt = Date.now() + SESSION_TTL_MS;
|
|
112
98
|
this.session = {
|
|
99
|
+
type: "phone",
|
|
113
100
|
id,
|
|
114
101
|
client,
|
|
115
102
|
phone,
|
|
@@ -122,7 +109,7 @@ var TelegramAuthManager = class {
|
|
|
122
109
|
createdAt: Date.now(),
|
|
123
110
|
apiId,
|
|
124
111
|
apiHash,
|
|
125
|
-
timer: setTimeout(() => this.cleanup(), SESSION_TTL_MS)
|
|
112
|
+
timer: setTimeout(() => void this.cleanup(), SESSION_TTL_MS)
|
|
126
113
|
};
|
|
127
114
|
log.info("Telegram verification code sent");
|
|
128
115
|
return { authSessionId: id, codeDelivery, fragmentUrl, codeLength, expiresAt };
|
|
@@ -132,7 +119,7 @@ var TelegramAuthManager = class {
|
|
|
132
119
|
*/
|
|
133
120
|
async verifyCode(authSessionId, code) {
|
|
134
121
|
const session = this.getSession(authSessionId);
|
|
135
|
-
if (!session) return { status: "expired" };
|
|
122
|
+
if (!session || session.type !== "phone") return { status: "expired" };
|
|
136
123
|
if (session.codeAttempts >= MAX_CODE_ATTEMPTS) {
|
|
137
124
|
return { status: "too_many_attempts" };
|
|
138
125
|
}
|
|
@@ -206,7 +193,7 @@ var TelegramAuthManager = class {
|
|
|
206
193
|
*/
|
|
207
194
|
async resendCode(authSessionId) {
|
|
208
195
|
const session = this.getSession(authSessionId);
|
|
209
|
-
if (!session || session.state !== "code_sent") return null;
|
|
196
|
+
if (!session || session.type !== "phone" || session.state !== "code_sent") return null;
|
|
210
197
|
const result = await session.client.invoke(
|
|
211
198
|
new Api.auth.ResendCode({
|
|
212
199
|
phoneNumber: session.phone,
|
|
@@ -235,6 +222,111 @@ var TelegramAuthManager = class {
|
|
|
235
222
|
}
|
|
236
223
|
return { codeDelivery: "sms" };
|
|
237
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Start QR code authentication session
|
|
227
|
+
*/
|
|
228
|
+
async startQrSession(apiId, apiHash) {
|
|
229
|
+
await this.cleanup();
|
|
230
|
+
const gramLogger = new Logger(LogLevel.NONE);
|
|
231
|
+
const client = new TelegramClient(new StringSession(""), apiId, apiHash, {
|
|
232
|
+
connectionRetries: 3,
|
|
233
|
+
floodSleepThreshold: 0,
|
|
234
|
+
baseLogger: gramLogger
|
|
235
|
+
});
|
|
236
|
+
await client.connect();
|
|
237
|
+
const result = await client.invoke(
|
|
238
|
+
new Api.auth.ExportLoginToken({
|
|
239
|
+
apiId,
|
|
240
|
+
apiHash,
|
|
241
|
+
exceptIds: []
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
if (!(result instanceof Api.auth.LoginToken)) {
|
|
245
|
+
await client.disconnect();
|
|
246
|
+
throw new Error("Unexpected QR auth response");
|
|
247
|
+
}
|
|
248
|
+
const id = randomBytes(16).toString("hex");
|
|
249
|
+
const expiresAt = Date.now() + SESSION_TTL_MS;
|
|
250
|
+
this.session = {
|
|
251
|
+
type: "qr",
|
|
252
|
+
id,
|
|
253
|
+
client,
|
|
254
|
+
state: "qr_waiting",
|
|
255
|
+
passwordAttempts: 0,
|
|
256
|
+
createdAt: Date.now(),
|
|
257
|
+
apiId,
|
|
258
|
+
apiHash,
|
|
259
|
+
timer: setTimeout(() => void this.cleanup(), SESSION_TTL_MS)
|
|
260
|
+
};
|
|
261
|
+
log.info("QR code authentication session started");
|
|
262
|
+
return {
|
|
263
|
+
authSessionId: id,
|
|
264
|
+
token: result.token.toString("base64url"),
|
|
265
|
+
expires: result.expires,
|
|
266
|
+
expiresAt
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Refresh QR token / check if scanned
|
|
271
|
+
*/
|
|
272
|
+
async refreshQrToken(authSessionId) {
|
|
273
|
+
const session = this.getSession(authSessionId);
|
|
274
|
+
if (!session || session.type !== "qr") return { status: "expired" };
|
|
275
|
+
if (session.state === "2fa_required") {
|
|
276
|
+
return { status: "2fa_required", passwordHint: session.passwordHint };
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
const result = await session.client.invoke(
|
|
280
|
+
new Api.auth.ExportLoginToken({
|
|
281
|
+
apiId: session.apiId,
|
|
282
|
+
apiHash: session.apiHash,
|
|
283
|
+
exceptIds: []
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
if (result instanceof Api.auth.LoginTokenSuccess) {
|
|
287
|
+
session.state = "authenticated";
|
|
288
|
+
const user = this.extractUser(result.authorization);
|
|
289
|
+
await this.saveSession(session);
|
|
290
|
+
log.info("QR code authentication successful");
|
|
291
|
+
return { status: "authenticated", user };
|
|
292
|
+
}
|
|
293
|
+
if (result instanceof Api.auth.LoginTokenMigrateTo) {
|
|
294
|
+
await session.client._switchDC(
|
|
295
|
+
result.dcId
|
|
296
|
+
);
|
|
297
|
+
const imported = await session.client.invoke(
|
|
298
|
+
new Api.auth.ImportLoginToken({ token: result.token })
|
|
299
|
+
);
|
|
300
|
+
if (imported instanceof Api.auth.LoginTokenSuccess) {
|
|
301
|
+
session.state = "authenticated";
|
|
302
|
+
const user = this.extractUser(imported.authorization);
|
|
303
|
+
await this.saveSession(session);
|
|
304
|
+
log.info("QR code authentication successful (after DC migration)");
|
|
305
|
+
return { status: "authenticated", user };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (result instanceof Api.auth.LoginToken) {
|
|
309
|
+
return {
|
|
310
|
+
status: "waiting",
|
|
311
|
+
token: result.token.toString("base64url"),
|
|
312
|
+
expires: result.expires
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return { status: "waiting" };
|
|
316
|
+
} catch (err) {
|
|
317
|
+
const error = err;
|
|
318
|
+
if (error.errorMessage === "SESSION_PASSWORD_NEEDED") {
|
|
319
|
+
session.state = "2fa_required";
|
|
320
|
+
try {
|
|
321
|
+
const passwordResult = await session.client.invoke(new Api.account.GetPassword());
|
|
322
|
+
session.passwordHint = passwordResult.hint ?? void 0;
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
return { status: "2fa_required", passwordHint: session.passwordHint };
|
|
326
|
+
}
|
|
327
|
+
throw err;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
238
330
|
/**
|
|
239
331
|
* Cancel and clean up session
|
|
240
332
|
*/
|
|
@@ -261,7 +353,7 @@ var TelegramAuthManager = class {
|
|
|
261
353
|
getSession(id) {
|
|
262
354
|
if (!this.session || this.session.id !== id) return null;
|
|
263
355
|
if (Date.now() - this.session.createdAt > SESSION_TTL_MS) {
|
|
264
|
-
this.cleanup();
|
|
356
|
+
void this.cleanup();
|
|
265
357
|
return null;
|
|
266
358
|
}
|
|
267
359
|
return this.session;
|
|
@@ -361,7 +453,7 @@ function createSetupRoutes() {
|
|
|
361
453
|
app.get("/detect-claude-code-key", (c) => {
|
|
362
454
|
try {
|
|
363
455
|
const key = getClaudeCodeApiKey();
|
|
364
|
-
const masked =
|
|
456
|
+
const masked = maskKey(key);
|
|
365
457
|
return c.json({
|
|
366
458
|
success: true,
|
|
367
459
|
data: {
|
|
@@ -596,6 +688,50 @@ function createSetupRoutes() {
|
|
|
596
688
|
);
|
|
597
689
|
}
|
|
598
690
|
});
|
|
691
|
+
app.post("/telegram/qr-start", async (c) => {
|
|
692
|
+
try {
|
|
693
|
+
const body = await c.req.json();
|
|
694
|
+
if (!body.apiId || !body.apiHash) {
|
|
695
|
+
return c.json({ success: false, error: "Missing apiId or apiHash" }, 400);
|
|
696
|
+
}
|
|
697
|
+
const result = await authManager.startQrSession(body.apiId, body.apiHash);
|
|
698
|
+
return c.json({ success: true, data: result });
|
|
699
|
+
} catch (err) {
|
|
700
|
+
const error = err;
|
|
701
|
+
if (error.seconds) {
|
|
702
|
+
return c.json(
|
|
703
|
+
{ success: false, error: `Rate limited. Please wait ${error.seconds} seconds.` },
|
|
704
|
+
429
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
return c.json(
|
|
708
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
709
|
+
500
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
app.post("/telegram/qr-refresh", async (c) => {
|
|
714
|
+
try {
|
|
715
|
+
const body = await c.req.json();
|
|
716
|
+
if (!body.authSessionId) {
|
|
717
|
+
return c.json({ success: false, error: "Missing authSessionId" }, 400);
|
|
718
|
+
}
|
|
719
|
+
const result = await authManager.refreshQrToken(body.authSessionId);
|
|
720
|
+
return c.json({ success: true, data: result });
|
|
721
|
+
} catch (err) {
|
|
722
|
+
const error = err;
|
|
723
|
+
if (error.seconds) {
|
|
724
|
+
return c.json(
|
|
725
|
+
{ success: false, error: `Rate limited. Please wait ${error.seconds} seconds.` },
|
|
726
|
+
429
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
return c.json(
|
|
730
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
731
|
+
500
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
});
|
|
599
735
|
app.delete("/telegram/session", async (c) => {
|
|
600
736
|
try {
|
|
601
737
|
const body = await c.req.json().catch(() => ({ authSessionId: "" }));
|
|
@@ -721,191 +857,6 @@ function createSetupRoutes() {
|
|
|
721
857
|
return app;
|
|
722
858
|
}
|
|
723
859
|
|
|
724
|
-
// src/webui/setup-server.ts
|
|
725
|
-
import { randomBytes as randomBytes2 } from "crypto";
|
|
726
|
-
import { readFileSync as readYaml, writeFileSync as writeFileSync3 } from "fs";
|
|
727
|
-
import YAML2 from "yaml";
|
|
728
|
-
var log3 = createLogger("Setup");
|
|
729
|
-
function findWebDist() {
|
|
730
|
-
const candidates = [resolve("dist/web"), resolve("web")];
|
|
731
|
-
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
732
|
-
candidates.push(resolve(__dirname, "web"), resolve(__dirname, "../dist/web"));
|
|
733
|
-
for (const candidate of candidates) {
|
|
734
|
-
if (existsSync3(join3(candidate, "index.html"))) {
|
|
735
|
-
return candidate;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
return null;
|
|
739
|
-
}
|
|
740
|
-
function autoOpenBrowser(url) {
|
|
741
|
-
const os = platform();
|
|
742
|
-
let cmd;
|
|
743
|
-
if (os === "darwin") {
|
|
744
|
-
cmd = `open "${url}"`;
|
|
745
|
-
} else if (os === "win32") {
|
|
746
|
-
cmd = `start "${url}"`;
|
|
747
|
-
} else {
|
|
748
|
-
cmd = `xdg-open "${url}"`;
|
|
749
|
-
}
|
|
750
|
-
exec(cmd, (err) => {
|
|
751
|
-
if (err) {
|
|
752
|
-
log3.info(`Open this URL in your browser: ${url}`);
|
|
753
|
-
}
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
var SetupServer = class {
|
|
757
|
-
constructor(port = 7777) {
|
|
758
|
-
this.port = port;
|
|
759
|
-
this.app = new Hono2();
|
|
760
|
-
this.launchPromise = new Promise((resolve2) => {
|
|
761
|
-
this.launchResolve = resolve2;
|
|
762
|
-
});
|
|
763
|
-
this.setupMiddleware();
|
|
764
|
-
this.setupRoutes();
|
|
765
|
-
this.setupStaticServing();
|
|
766
|
-
}
|
|
767
|
-
app;
|
|
768
|
-
server = null;
|
|
769
|
-
launchResolve = null;
|
|
770
|
-
launchPromise;
|
|
771
|
-
/** Returns a promise that resolves with the auth token when the user clicks "Start Agent" */
|
|
772
|
-
waitForLaunch() {
|
|
773
|
-
return this.launchPromise;
|
|
774
|
-
}
|
|
775
|
-
setupMiddleware() {
|
|
776
|
-
this.app.use(
|
|
777
|
-
"*",
|
|
778
|
-
cors({
|
|
779
|
-
origin: [
|
|
780
|
-
"http://localhost:5173",
|
|
781
|
-
`http://localhost:${this.port}`,
|
|
782
|
-
"http://127.0.0.1:5173",
|
|
783
|
-
`http://127.0.0.1:${this.port}`
|
|
784
|
-
],
|
|
785
|
-
credentials: true,
|
|
786
|
-
allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
|
|
787
|
-
allowHeaders: ["Content-Type"],
|
|
788
|
-
maxAge: 3600
|
|
789
|
-
})
|
|
790
|
-
);
|
|
791
|
-
this.app.use(
|
|
792
|
-
"*",
|
|
793
|
-
bodyLimit({
|
|
794
|
-
maxSize: 2 * 1024 * 1024,
|
|
795
|
-
onError: (c) => c.json({ success: false, error: "Request body too large (max 2MB)" }, 413)
|
|
796
|
-
})
|
|
797
|
-
);
|
|
798
|
-
this.app.use("*", async (c, next) => {
|
|
799
|
-
await next();
|
|
800
|
-
c.res.headers.set("X-Content-Type-Options", "nosniff");
|
|
801
|
-
c.res.headers.set("X-Frame-Options", "DENY");
|
|
802
|
-
c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
setupRoutes() {
|
|
806
|
-
this.app.get("/health", (c) => c.json({ status: "ok" }));
|
|
807
|
-
this.app.route("/api/setup", createSetupRoutes());
|
|
808
|
-
this.app.get(
|
|
809
|
-
"/auth/check",
|
|
810
|
-
(c) => c.json({ success: true, data: { authenticated: false, setup: true } })
|
|
811
|
-
);
|
|
812
|
-
this.app.post("/api/setup/launch", async (c) => {
|
|
813
|
-
try {
|
|
814
|
-
const token = randomBytes2(32).toString("hex");
|
|
815
|
-
const configPath = join3(TELETON_ROOT, "config.yaml");
|
|
816
|
-
const raw = readYaml(configPath, "utf-8");
|
|
817
|
-
const config = YAML2.parse(raw);
|
|
818
|
-
config.webui = { ...config.webui || {}, enabled: true, auth_token: token };
|
|
819
|
-
writeFileSync3(configPath, YAML2.stringify(config), { encoding: "utf-8", mode: 384 });
|
|
820
|
-
log3.info("Launch requested \u2014 auth token generated");
|
|
821
|
-
const resolve2 = this.launchResolve;
|
|
822
|
-
this.launchResolve = null;
|
|
823
|
-
if (resolve2) {
|
|
824
|
-
setTimeout(() => resolve2(token), 500);
|
|
825
|
-
}
|
|
826
|
-
return c.json({ success: true, data: { token } });
|
|
827
|
-
} catch (err) {
|
|
828
|
-
return c.json(
|
|
829
|
-
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
830
|
-
500
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
this.app.onError((err, c) => {
|
|
835
|
-
log3.error({ err }, "Setup server error");
|
|
836
|
-
return c.json({ success: false, error: err.message || "Internal server error" }, 500);
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
setupStaticServing() {
|
|
840
|
-
const webDist = findWebDist();
|
|
841
|
-
if (!webDist) return;
|
|
842
|
-
const indexHtml = readFileSync2(join3(webDist, "index.html"), "utf-8");
|
|
843
|
-
const mimeTypes = {
|
|
844
|
-
js: "application/javascript",
|
|
845
|
-
css: "text/css",
|
|
846
|
-
svg: "image/svg+xml",
|
|
847
|
-
png: "image/png",
|
|
848
|
-
jpg: "image/jpeg",
|
|
849
|
-
jpeg: "image/jpeg",
|
|
850
|
-
ico: "image/x-icon",
|
|
851
|
-
json: "application/json",
|
|
852
|
-
woff2: "font/woff2",
|
|
853
|
-
woff: "font/woff"
|
|
854
|
-
};
|
|
855
|
-
this.app.get("*", (c) => {
|
|
856
|
-
const filePath = resolve(join3(webDist, c.req.path));
|
|
857
|
-
const rel = relative(webDist, filePath);
|
|
858
|
-
if (rel.startsWith("..") || resolve(filePath) !== filePath) {
|
|
859
|
-
return c.html(indexHtml);
|
|
860
|
-
}
|
|
861
|
-
try {
|
|
862
|
-
const content = readFileSync2(filePath);
|
|
863
|
-
const ext = filePath.split(".").pop() || "";
|
|
864
|
-
if (mimeTypes[ext]) {
|
|
865
|
-
const immutable = c.req.path.startsWith("/assets/");
|
|
866
|
-
return c.body(content, 200, {
|
|
867
|
-
"Content-Type": mimeTypes[ext],
|
|
868
|
-
"Cache-Control": immutable ? "public, max-age=31536000, immutable" : "public, max-age=3600"
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
} catch {
|
|
872
|
-
}
|
|
873
|
-
return c.html(indexHtml);
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
async start() {
|
|
877
|
-
return new Promise((resolve2, reject) => {
|
|
878
|
-
try {
|
|
879
|
-
this.server = serve(
|
|
880
|
-
{
|
|
881
|
-
fetch: this.app.fetch,
|
|
882
|
-
hostname: "127.0.0.1",
|
|
883
|
-
port: this.port
|
|
884
|
-
},
|
|
885
|
-
() => {
|
|
886
|
-
const url = `http://localhost:${this.port}/setup`;
|
|
887
|
-
log3.info(`Setup wizard: ${url}`);
|
|
888
|
-
autoOpenBrowser(url);
|
|
889
|
-
resolve2();
|
|
890
|
-
}
|
|
891
|
-
);
|
|
892
|
-
} catch (error) {
|
|
893
|
-
reject(error);
|
|
894
|
-
}
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
async stop() {
|
|
898
|
-
if (this.server) {
|
|
899
|
-
return new Promise((resolve2) => {
|
|
900
|
-
this.server.closeAllConnections();
|
|
901
|
-
this.server.close(() => {
|
|
902
|
-
log3.info("Setup server stopped");
|
|
903
|
-
resolve2();
|
|
904
|
-
});
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
860
|
export {
|
|
910
|
-
|
|
861
|
+
createSetupRoutes
|
|
911
862
|
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger
|
|
3
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
4
|
+
|
|
5
|
+
// src/api/tls.ts
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { createHash, X509Certificate } from "crypto";
|
|
9
|
+
import { generate } from "selfsigned";
|
|
10
|
+
var log = createLogger("TLS");
|
|
11
|
+
function computeFingerprint(certPem) {
|
|
12
|
+
const x509 = new X509Certificate(certPem);
|
|
13
|
+
const der = x509.raw;
|
|
14
|
+
return createHash("sha256").update(der).digest("hex");
|
|
15
|
+
}
|
|
16
|
+
function isCertValid(certPem) {
|
|
17
|
+
try {
|
|
18
|
+
const x509 = new X509Certificate(certPem);
|
|
19
|
+
const now = /* @__PURE__ */ new Date();
|
|
20
|
+
return now >= new Date(x509.validFrom) && now <= new Date(x509.validTo);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function ensureTlsCert(dataDir) {
|
|
26
|
+
const certPath = join(dataDir, "api-cert.pem");
|
|
27
|
+
const keyPath = join(dataDir, "api-key.pem");
|
|
28
|
+
if (existsSync(certPath) && existsSync(keyPath)) {
|
|
29
|
+
const cert = readFileSync(certPath, "utf-8");
|
|
30
|
+
const key = readFileSync(keyPath, "utf-8");
|
|
31
|
+
if (isCertValid(cert)) {
|
|
32
|
+
const fingerprint2 = computeFingerprint(cert);
|
|
33
|
+
log.info("Loaded existing TLS certificate");
|
|
34
|
+
return { cert, key, fingerprint: fingerprint2 };
|
|
35
|
+
}
|
|
36
|
+
log.warn("Existing TLS certificate is expired, regenerating");
|
|
37
|
+
}
|
|
38
|
+
log.info("Generating self-signed TLS certificate");
|
|
39
|
+
const notBeforeDate = /* @__PURE__ */ new Date();
|
|
40
|
+
const notAfterDate = /* @__PURE__ */ new Date();
|
|
41
|
+
notAfterDate.setFullYear(notAfterDate.getFullYear() + 2);
|
|
42
|
+
const pems = await generate([{ name: "commonName", value: "teleton-api" }], {
|
|
43
|
+
keySize: 2048,
|
|
44
|
+
algorithm: "sha256",
|
|
45
|
+
notBeforeDate,
|
|
46
|
+
notAfterDate,
|
|
47
|
+
extensions: [
|
|
48
|
+
{ name: "basicConstraints", cA: false, critical: true },
|
|
49
|
+
{
|
|
50
|
+
name: "keyUsage",
|
|
51
|
+
digitalSignature: true,
|
|
52
|
+
keyEncipherment: true,
|
|
53
|
+
critical: true
|
|
54
|
+
},
|
|
55
|
+
{ name: "extKeyUsage", serverAuth: true },
|
|
56
|
+
{
|
|
57
|
+
name: "subjectAltName",
|
|
58
|
+
altNames: [
|
|
59
|
+
{ type: 2, value: "localhost" },
|
|
60
|
+
{ type: 7, ip: "127.0.0.1" },
|
|
61
|
+
{ type: 7, ip: "::1" }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
writeFileSync(certPath, pems.cert, { mode: 384 });
|
|
67
|
+
writeFileSync(keyPath, pems.private, { mode: 384 });
|
|
68
|
+
const fingerprint = computeFingerprint(pems.cert);
|
|
69
|
+
log.info(`TLS certificate generated (fingerprint: ${fingerprint.slice(0, 16)}...)`);
|
|
70
|
+
return { cert: pems.cert, key: pems.private, fingerprint };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
ensureTlsCert
|
|
75
|
+
};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-VFA7QMCZ.js";
|
|
5
5
|
import {
|
|
6
6
|
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-C4NKJT2Z.js";
|
|
8
8
|
import {
|
|
9
9
|
fetchWithTimeout
|
|
10
10
|
} from "./chunk-XQUHC3JZ.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-EYWNOHMJ.js";
|
|
16
16
|
import {
|
|
17
17
|
createLogger
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
19
19
|
|
|
20
20
|
// src/ton/endpoint.ts
|
|
21
21
|
var ENDPOINT_CACHE_TTL_MS = 6e4;
|
|
@@ -341,10 +341,23 @@ var _LoggingObject = z.object({
|
|
|
341
341
|
pretty: z.boolean().default(true).describe("Enable pino-pretty formatting (human-readable, colored output)")
|
|
342
342
|
});
|
|
343
343
|
var LoggingConfigSchema = _LoggingObject.default(_LoggingObject.parse({}));
|
|
344
|
+
var _TonProxyObject = z.object({
|
|
345
|
+
enabled: z.boolean().default(false).describe("Enable TON Proxy (Tonutils-Proxy) for .ton site access"),
|
|
346
|
+
port: z.number().min(1).max(65535).default(8080).describe("HTTP proxy port (default: 8080)"),
|
|
347
|
+
binary_path: z.string().optional().describe("Custom path to tonutils-proxy-cli binary (auto-downloaded if omitted)")
|
|
348
|
+
});
|
|
349
|
+
var TonProxyConfigSchema = _TonProxyObject.default(_TonProxyObject.parse({}));
|
|
344
350
|
var _DevObject = z.object({
|
|
345
351
|
hot_reload: z.boolean().default(false).describe("Enable plugin hot-reload (watches ~/.teleton/plugins/ for changes)")
|
|
346
352
|
});
|
|
347
353
|
var DevConfigSchema = _DevObject.default(_DevObject.parse({}));
|
|
354
|
+
var _ApiObject = z.object({
|
|
355
|
+
enabled: z.boolean().default(false).describe("Enable HTTPS Management API server"),
|
|
356
|
+
port: z.number().min(1).max(65535).default(7778).describe("HTTPS server port"),
|
|
357
|
+
key_hash: z.string().default("").describe("SHA-256 hash of the API key (auto-generated if empty)"),
|
|
358
|
+
allowed_ips: z.array(z.string()).default([]).describe("IP whitelist (empty = allow all authenticated requests)")
|
|
359
|
+
});
|
|
360
|
+
var ApiConfigSchema = _ApiObject.default(_ApiObject.parse({}));
|
|
348
361
|
var McpServerSchema = z.object({
|
|
349
362
|
command: z.string().optional().describe("Stdio command (e.g. 'npx @modelcontextprotocol/server-filesystem /tmp')"),
|
|
350
363
|
args: z.array(z.string()).optional().describe("Explicit args array (overrides command splitting)"),
|
|
@@ -404,6 +417,8 @@ var ConfigSchema = z.object({
|
|
|
404
417
|
dev: DevConfigSchema,
|
|
405
418
|
tool_rag: ToolRagConfigSchema,
|
|
406
419
|
capabilities: CapabilitiesConfigSchema,
|
|
420
|
+
api: ApiConfigSchema.optional(),
|
|
421
|
+
ton_proxy: TonProxyConfigSchema,
|
|
407
422
|
mcp: McpConfigSchema,
|
|
408
423
|
plugins: z.record(z.string(), z.unknown()).default({}).describe("Per-plugin config (key = plugin name with underscores)"),
|
|
409
424
|
cocoon: z.object({
|
|
@@ -23,6 +23,9 @@ var CONTEXT_MAX_RECENT_MESSAGES = 10;
|
|
|
23
23
|
var CONTEXT_MAX_RELEVANT_CHUNKS = 5;
|
|
24
24
|
var FEED_MESSAGE_MAX_CHARS = 2e3;
|
|
25
25
|
var HYBRID_SEARCH_MIN_SCORE = 0.15;
|
|
26
|
+
var RECENCY_DECAY_FACTOR = 0.05;
|
|
27
|
+
var RECENCY_WEIGHT = 0.15;
|
|
28
|
+
var EMBEDDING_QUERY_MAX_CHARS = 1e3;
|
|
26
29
|
var CONTEXT_OVERFLOW_SUMMARY_MESSAGES = 15;
|
|
27
30
|
var RATE_LIMIT_MAX_RETRIES = 3;
|
|
28
31
|
var SERVER_ERROR_MAX_RETRIES = 3;
|
|
@@ -51,9 +54,12 @@ var ADAPTIVE_CHUNK_RATIO_TRIGGER = 0.1;
|
|
|
51
54
|
var SESSION_SLUG_RECENT_MESSAGES = 10;
|
|
52
55
|
var SESSION_SLUG_MAX_TOKENS = 50;
|
|
53
56
|
var MASKING_KEEP_RECENT_COUNT = 10;
|
|
57
|
+
var RESULT_TRUNCATION_THRESHOLD = 4e3;
|
|
58
|
+
var RESULT_TRUNCATION_KEEP_CHARS = 500;
|
|
54
59
|
var EMBEDDING_CACHE_EVICTION_RATIO = 0.1;
|
|
55
60
|
var WEB_FETCH_MAX_TEXT_LENGTH = 2e4;
|
|
56
61
|
var WEB_SEARCH_MAX_RESULTS = 10;
|
|
62
|
+
var TOOL_CONCURRENCY_LIMIT = 2;
|
|
57
63
|
var TOOL_RAG_MIN_SCORE = 0.1;
|
|
58
64
|
var TOOL_RAG_VECTOR_WEIGHT = 0.6;
|
|
59
65
|
var TOOL_RAG_KEYWORD_WEIGHT = 0.4;
|
|
@@ -83,6 +89,9 @@ export {
|
|
|
83
89
|
CONTEXT_MAX_RELEVANT_CHUNKS,
|
|
84
90
|
FEED_MESSAGE_MAX_CHARS,
|
|
85
91
|
HYBRID_SEARCH_MIN_SCORE,
|
|
92
|
+
RECENCY_DECAY_FACTOR,
|
|
93
|
+
RECENCY_WEIGHT,
|
|
94
|
+
EMBEDDING_QUERY_MAX_CHARS,
|
|
86
95
|
CONTEXT_OVERFLOW_SUMMARY_MESSAGES,
|
|
87
96
|
RATE_LIMIT_MAX_RETRIES,
|
|
88
97
|
SERVER_ERROR_MAX_RETRIES,
|
|
@@ -111,9 +120,12 @@ export {
|
|
|
111
120
|
SESSION_SLUG_RECENT_MESSAGES,
|
|
112
121
|
SESSION_SLUG_MAX_TOKENS,
|
|
113
122
|
MASKING_KEEP_RECENT_COUNT,
|
|
123
|
+
RESULT_TRUNCATION_THRESHOLD,
|
|
124
|
+
RESULT_TRUNCATION_KEEP_CHARS,
|
|
114
125
|
EMBEDDING_CACHE_EVICTION_RATIO,
|
|
115
126
|
WEB_FETCH_MAX_TEXT_LENGTH,
|
|
116
127
|
WEB_SEARCH_MAX_RESULTS,
|
|
128
|
+
TOOL_CONCURRENCY_LIMIT,
|
|
117
129
|
TOOL_RAG_MIN_SCORE,
|
|
118
130
|
TOOL_RAG_VECTOR_WEIGHT,
|
|
119
131
|
TOOL_RAG_KEYWORD_WEIGHT
|