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.
Files changed (44) hide show
  1. package/README.md +28 -11
  2. package/dist/{chunk-H36RFKRI.js → chunk-2IZU3REP.js} +572 -174
  3. package/dist/chunk-3UFPFWYP.js +12 -0
  4. package/dist/{chunk-NUGDTPE4.js → chunk-4L66JHQE.js} +2 -1
  5. package/dist/{chunk-TVRZJIZX.js → chunk-55SKE6YH.js} +4 -4
  6. package/dist/{setup-server-QXED3D2L.js → chunk-57URFK6M.js} +161 -210
  7. package/dist/chunk-5SEMA47R.js +75 -0
  8. package/dist/{chunk-JHYZYFZJ.js → chunk-7YKSXOQQ.js} +17 -2
  9. package/dist/{chunk-IJBWWQE4.js → chunk-C4NKJT2Z.js} +12 -0
  10. package/dist/{chunk-RQBAMUCV.js → chunk-GGXJLMOH.js} +1451 -743
  11. package/dist/{chunk-WIKM24GZ.js → chunk-H7MFXJZK.js} +7 -2
  12. package/dist/{chunk-U56QTM46.js → chunk-HEDJCLA6.js} +85 -44
  13. package/dist/{chunk-QVBSUYVX.js → chunk-J73TA3UM.js} +17 -9
  14. package/dist/{chunk-P36I6OIV.js → chunk-LC4TV3KL.js} +13 -2
  15. package/dist/{chunk-RCMD3U65.js → chunk-NQ6FZKCE.js} +13 -0
  16. package/dist/{chunk-SD4NLLYG.js → chunk-VYKW7FMV.js} +224 -93
  17. package/dist/chunk-W25Z7CM6.js +487 -0
  18. package/dist/{chunk-OJCLKU5Z.js → chunk-WFTC3JJW.js} +16 -0
  19. package/dist/{server-H3QA252W.js → chunk-XBSCYMKM.js} +369 -374
  20. package/dist/{chunk-PHSAHTK4.js → chunk-YOSUPUAJ.js} +75 -7
  21. package/dist/cli/index.js +67 -22
  22. package/dist/{client-LNZTDQSA.js → client-YOOHI776.js} +4 -4
  23. package/dist/{get-my-gifts-OMGKOEPM.js → get-my-gifts-Y7EN7RK4.js} +3 -3
  24. package/dist/index.js +15 -14
  25. package/dist/{memory-AS7WKGTW.js → memory-Q6EWGK2S.js} +7 -5
  26. package/dist/memory-hook-WUXJNVT5.js +18 -0
  27. package/dist/{migrate-POHWYEIW.js → migrate-WFU6COBN.js} +5 -5
  28. package/dist/server-GYZXKIKU.js +787 -0
  29. package/dist/server-YODFBZKG.js +392 -0
  30. package/dist/setup-server-IZBUOJRU.js +215 -0
  31. package/dist/{store-GAFULOOX.js → store-7M4XV6M5.js} +6 -6
  32. package/dist/{task-dependency-resolver-3FIKQ7Z6.js → task-dependency-resolver-L6UUMTHK.js} +3 -3
  33. package/dist/{task-executor-RUTFG6VG.js → task-executor-XBNJLUCS.js} +3 -3
  34. package/dist/{tasks-BEZ4QRI2.js → tasks-WQIKXDX5.js} +1 -1
  35. package/dist/{tool-adapter-IH5VGBOO.js → tool-adapter-IVX2XQJE.js} +1 -1
  36. package/dist/{tool-index-H3SHOJC3.js → tool-index-NYH57UWP.js} +9 -6
  37. package/dist/{transcript-IMNE6KU3.js → transcript-IM7G25OS.js} +2 -2
  38. package/dist/web/assets/index-BfYCdwLI.js +80 -0
  39. package/dist/web/assets/{index-BrVqauzj.css → index-DmlyQVhR.css} +1 -1
  40. package/dist/web/assets/{index.es-DkU1GvWU.js → index.es-DitvF-9H.js} +1 -1
  41. package/dist/web/index.html +2 -2
  42. package/package.json +14 -5
  43. package/dist/chunk-XBE4JB7C.js +0 -8
  44. 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 (e) {
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-SD4NLLYG.js";
3
+ } from "./chunk-VYKW7FMV.js";
4
4
  import {
5
5
  createLogger
6
- } from "./chunk-RCMD3U65.js";
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, policy) {
259
- const newSession = resetSession(chatId);
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-OJCLKU5Z.js";
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-JHYZYFZJ.js";
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-PHSAHTK4.js";
22
- import "./chunk-VFA7QMCZ.js";
21
+ } from "./chunk-YOSUPUAJ.js";
23
22
  import {
24
23
  TELEGRAM_MAX_MESSAGE_LENGTH
25
- } from "./chunk-IJBWWQE4.js";
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-RCMD3U65.js";
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 = key.slice(0, 12) + "****" + key.slice(-4);
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
- SetupServer
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-IJBWWQE4.js";
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-RCMD3U65.js";
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