teleton 0.7.4 → 0.8.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.
Files changed (50) hide show
  1. package/README.md +43 -30
  2. package/dist/chunk-3RG5ZIWI.js +10 -0
  3. package/dist/{chunk-U7FQYCBQ.js → chunk-7TECSLJ4.js} +2 -2
  4. package/dist/{chunk-LAQOUFOJ.js → chunk-H36RFKRI.js} +7583 -11185
  5. package/dist/{chunk-RO62LO6Z.js → chunk-IJBWWQE4.js} +4 -0
  6. package/dist/{chunk-BGC2IUM5.js → chunk-JHYZYFZJ.js} +69 -20
  7. package/dist/{chunk-QOQWUUA4.js → chunk-OJCLKU5Z.js} +68 -2
  8. package/dist/{chunk-OCLG5GKI.js → chunk-P36I6OIV.js} +2 -2
  9. package/dist/chunk-PHSAHTK4.js +314 -0
  10. package/dist/{chunk-5PLZ3KSO.js → chunk-QVBSUYVX.js} +14 -42
  11. package/dist/{chunk-4DU3C27M.js → chunk-R4YSJ4EY.js} +5 -1
  12. package/dist/chunk-RQBAMUCV.js +10281 -0
  13. package/dist/{chunk-XDYDA2KV.js → chunk-SD4NLLYG.js} +293 -64
  14. package/dist/chunk-TVRZJIZX.js +292 -0
  15. package/dist/{chunk-EK7M5K26.js → chunk-U56QTM46.js} +3 -3
  16. package/dist/{chunk-XBKSS6DM.js → chunk-VFA7QMCZ.js} +5 -3
  17. package/dist/{chunk-VAUJSSD3.js → chunk-XQUHC3JZ.js} +1 -1
  18. package/dist/cli/index.js +96 -33
  19. package/dist/{client-RTNALK7W.js → client-LNZTDQSA.js} +6 -7
  20. package/dist/{get-my-gifts-TPVUGUWT.js → get-my-gifts-OMGKOEPM.js} +1 -1
  21. package/dist/index.js +15 -17
  22. package/dist/{memory-JQZ6MTRU.js → memory-AS7WKGTW.js} +7 -8
  23. package/dist/{migrate-GS5ACQDA.js → migrate-POHWYEIW.js} +7 -8
  24. package/dist/{multipart-parser-S3YC6NRJ.js → multipart-parser-UFQLJOV2.js} +2 -2
  25. package/dist/{paths-TMNTEDDD.js → paths-XA2RJH4S.js} +1 -1
  26. package/dist/{server-TCJOBV3D.js → server-H3QA252W.js} +39 -12
  27. package/dist/{setup-server-YHYJLAMA.js → setup-server-QXED3D2L.js} +24 -12
  28. package/dist/store-GAFULOOX.js +34 -0
  29. package/dist/{task-dependency-resolver-WKZWJLLM.js → task-dependency-resolver-3FIKQ7Z6.js} +3 -3
  30. package/dist/{task-executor-PD3H4MLO.js → task-executor-RUTFG6VG.js} +2 -2
  31. package/dist/{tasks-QSCWSMPS.js → tasks-BEZ4QRI2.js} +1 -1
  32. package/dist/{tool-adapter-Y3TCEQOC.js → tool-adapter-IH5VGBOO.js} +1 -1
  33. package/dist/{tool-index-6HBRVXVG.js → tool-index-H3SHOJC3.js} +6 -6
  34. package/dist/{transcript-UDJZP6NK.js → transcript-IMNE6KU3.js} +2 -2
  35. package/dist/web/assets/index-BrVqauzj.css +1 -0
  36. package/dist/web/assets/index-DYeEkvJ6.js +72 -0
  37. package/dist/web/assets/{index.es-CqZHj0tz.js → index.es-DkU1GvWU.js} +1 -1
  38. package/dist/web/index.html +2 -2
  39. package/package.json +2 -2
  40. package/dist/BigInteger-DQ33LTTE.js +0 -5
  41. package/dist/chunk-JQDLW7IE.js +0 -107
  42. package/dist/chunk-QGM4M3NI.js +0 -37
  43. package/dist/chunk-RMLQS3X6.js +0 -161
  44. package/dist/chunk-TSKJCWQQ.js +0 -1263
  45. package/dist/chunk-UCN6TI25.js +0 -143
  46. package/dist/chunk-YFG2QHLA.js +0 -3585
  47. package/dist/web/assets/index-B6M9knfJ.css +0 -1
  48. package/dist/web/assets/index-DAGeQfVZ.js +0 -72
  49. package/scripts/patch-gramjs.sh +0 -46
  50. package/scripts/postinstall.mjs +0 -16
@@ -21,9 +21,11 @@ var DEBOUNCE_MAX_MULTIPLIER = 3;
21
21
  var DEBOUNCE_MAX_BUFFER_SIZE = 20;
22
22
  var CONTEXT_MAX_RECENT_MESSAGES = 10;
23
23
  var CONTEXT_MAX_RELEVANT_CHUNKS = 5;
24
+ var FEED_MESSAGE_MAX_CHARS = 2e3;
24
25
  var HYBRID_SEARCH_MIN_SCORE = 0.15;
25
26
  var CONTEXT_OVERFLOW_SUMMARY_MESSAGES = 15;
26
27
  var RATE_LIMIT_MAX_RETRIES = 3;
28
+ var SERVER_ERROR_MAX_RETRIES = 3;
27
29
  var KNOWLEDGE_CHUNK_SIZE = 500;
28
30
  var PAYMENT_TOLERANCE_RATIO = 0.99;
29
31
  var TELEGRAM_CONNECTION_RETRIES = 5;
@@ -79,9 +81,11 @@ export {
79
81
  DEBOUNCE_MAX_BUFFER_SIZE,
80
82
  CONTEXT_MAX_RECENT_MESSAGES,
81
83
  CONTEXT_MAX_RELEVANT_CHUNKS,
84
+ FEED_MESSAGE_MAX_CHARS,
82
85
  HYBRID_SEARCH_MIN_SCORE,
83
86
  CONTEXT_OVERFLOW_SUMMARY_MESSAGES,
84
87
  RATE_LIMIT_MAX_RETRIES,
88
+ SERVER_ERROR_MAX_RETRIES,
85
89
  KNOWLEDGE_CHUNK_SIZE,
86
90
  PAYMENT_TOLERANCE_RATIO,
87
91
  TELEGRAM_CONNECTION_RETRIES,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  COINGECKO_API_URL,
3
3
  tonapiFetch
4
- } from "./chunk-XBKSS6DM.js";
4
+ } from "./chunk-VFA7QMCZ.js";
5
5
  import {
6
6
  TELEGRAM_MAX_MESSAGE_LENGTH
7
- } from "./chunk-RO62LO6Z.js";
7
+ } from "./chunk-IJBWWQE4.js";
8
8
  import {
9
9
  fetchWithTimeout
10
- } from "./chunk-VAUJSSD3.js";
10
+ } from "./chunk-XQUHC3JZ.js";
11
11
  import {
12
12
  TELETON_ROOT,
13
13
  WORKSPACE_PATHS,
@@ -17,20 +17,21 @@ import {
17
17
  createLogger
18
18
  } from "./chunk-RCMD3U65.js";
19
19
 
20
- // src/ton/wallet-service.ts
21
- import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
22
- import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
23
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
24
- import { join, dirname } from "path";
25
-
26
20
  // src/ton/endpoint.ts
27
21
  var ENDPOINT_CACHE_TTL_MS = 6e4;
28
22
  var ORBS_HOST = "ton.access.orbs.network";
29
23
  var ORBS_TOPOLOGY_URL = `https://${ORBS_HOST}/mngr/nodes?npm_version=2.3.3`;
30
- var TONCENTER_FALLBACK = `https://toncenter.com/api/v2/jsonRPC`;
24
+ var TONCENTER_URL = `https://toncenter.com/api/v2/jsonRPC`;
31
25
  var _cache = null;
26
+ var _toncenterApiKey;
27
+ function setToncenterApiKey(key) {
28
+ _toncenterApiKey = key;
29
+ }
30
+ function getToncenterApiKey() {
31
+ return _toncenterApiKey;
32
+ }
32
33
  async function discoverOrbsEndpoint() {
33
- const res = await fetch(ORBS_TOPOLOGY_URL);
34
+ const res = await fetch(ORBS_TOPOLOGY_URL, { signal: AbortSignal.timeout(5e3) });
34
35
  const nodes = await res.json();
35
36
  const healthy = nodes.filter(
36
37
  (n) => n.Healthy === "1" && n.Weight > 0 && n.Mngr?.health?.["v2-mainnet"]
@@ -53,10 +54,28 @@ async function getCachedHttpEndpoint() {
53
54
  return _cache.url;
54
55
  }
55
56
  let url;
56
- try {
57
- url = await discoverOrbsEndpoint();
58
- } catch {
59
- url = TONCENTER_FALLBACK;
57
+ if (_toncenterApiKey) {
58
+ try {
59
+ const testUrl = `https://toncenter.com/api/v2/getAddressInformation?address=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c`;
60
+ const res = await fetch(testUrl, {
61
+ headers: { "X-API-Key": _toncenterApiKey },
62
+ signal: AbortSignal.timeout(5e3)
63
+ });
64
+ if (!res.ok) throw new Error(`TonCenter ${res.status}`);
65
+ url = TONCENTER_URL;
66
+ } catch {
67
+ try {
68
+ url = await discoverOrbsEndpoint();
69
+ } catch {
70
+ url = TONCENTER_URL;
71
+ }
72
+ }
73
+ } else {
74
+ try {
75
+ url = await discoverOrbsEndpoint();
76
+ } catch {
77
+ url = TONCENTER_URL;
78
+ }
60
79
  }
61
80
  _cache = { url, ts: Date.now() };
62
81
  return url;
@@ -66,6 +85,10 @@ function invalidateEndpointCache() {
66
85
  }
67
86
 
68
87
  // src/ton/wallet-service.ts
88
+ import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
89
+ import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
90
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
91
+ import { join, dirname } from "path";
69
92
  var log = createLogger("TON");
70
93
  var WALLET_FILE = join(TELETON_ROOT, "wallet.json");
71
94
  var _walletCache;
@@ -147,7 +170,8 @@ async function getCachedTonClient() {
147
170
  if (_tonClientCache && _tonClientCache.endpoint === endpoint) {
148
171
  return _tonClientCache.client;
149
172
  }
150
- const client = new TonClient({ endpoint });
173
+ const apiKey = getToncenterApiKey();
174
+ const client = new TonClient({ endpoint, ...apiKey && { apiKey } });
151
175
  _tonClientCache = { client, endpoint };
152
176
  return client;
153
177
  }
@@ -217,8 +241,8 @@ async function getTonPrice() {
217
241
 
218
242
  // src/config/schema.ts
219
243
  import { z } from "zod";
220
- var DMPolicy = z.enum(["allowlist", "open", "disabled"]);
221
- var GroupPolicy = z.enum(["open", "allowlist", "disabled"]);
244
+ var DMPolicy = z.enum(["allowlist", "open", "admin-only", "disabled"]);
245
+ var GroupPolicy = z.enum(["open", "allowlist", "admin-only", "disabled"]);
222
246
  var SessionResetPolicySchema = z.object({
223
247
  daily_reset_enabled: z.boolean().default(true).describe("Enable daily session reset"),
224
248
  daily_reset_hour: z.number().min(0).max(23).default(4).describe("Hour of day (0-23) to reset sessions"),
@@ -236,6 +260,10 @@ var AgentConfigSchema = z.object({
236
260
  "openrouter",
237
261
  "moonshot",
238
262
  "mistral",
263
+ "cerebras",
264
+ "zai",
265
+ "minimax",
266
+ "huggingface",
239
267
  "cocoon",
240
268
  "local"
241
269
  ]).default("anthropic"),
@@ -332,7 +360,7 @@ var _McpObject = z.object({
332
360
  });
333
361
  var McpConfigSchema = _McpObject.default(_McpObject.parse({}));
334
362
  var _ToolRagObject = z.object({
335
- enabled: z.boolean().default(false).describe("Enable semantic tool retrieval (Tool RAG)"),
363
+ enabled: z.boolean().default(true).describe("Enable semantic tool retrieval (Tool RAG)"),
336
364
  top_k: z.number().default(25).describe("Max tools to retrieve per LLM call"),
337
365
  always_include: z.array(z.string()).default([
338
366
  "telegram_send_message",
@@ -346,6 +374,24 @@ var _ToolRagObject = z.object({
346
374
  skip_unlimited_providers: z.boolean().default(false).describe("Skip Tool RAG for providers with no tool limit (e.g. Anthropic)")
347
375
  });
348
376
  var ToolRagConfigSchema = _ToolRagObject.default(_ToolRagObject.parse({}));
377
+ var _ExecLimitsObject = z.object({
378
+ timeout: z.number().min(1).max(3600).default(120).describe("Max seconds per command execution"),
379
+ max_output: z.number().min(1e3).max(5e5).default(5e4).describe("Max chars of stdout/stderr captured per command")
380
+ });
381
+ var _ExecAuditObject = z.object({
382
+ log_commands: z.boolean().default(true).describe("Log every command to SQLite audit table")
383
+ });
384
+ var _ExecObject = z.object({
385
+ mode: z.enum(["off", "yolo"]).default("off").describe("Exec mode: off (disabled) or yolo (full system access)"),
386
+ scope: z.enum(["admin-only", "allowlist", "all"]).default("admin-only").describe("Who can trigger exec tools"),
387
+ allowlist: z.array(z.number()).default([]).describe("Telegram user IDs allowed to use exec (when scope = allowlist)"),
388
+ limits: _ExecLimitsObject.default(_ExecLimitsObject.parse({})),
389
+ audit: _ExecAuditObject.default(_ExecAuditObject.parse({}))
390
+ });
391
+ var _CapabilitiesObject = z.object({
392
+ exec: _ExecObject.default(_ExecObject.parse({}))
393
+ });
394
+ var CapabilitiesConfigSchema = _CapabilitiesObject.default(_CapabilitiesObject.parse({}));
349
395
  var ConfigSchema = z.object({
350
396
  meta: MetaConfigSchema.default(MetaConfigSchema.parse({})),
351
397
  agent: AgentConfigSchema,
@@ -357,12 +403,14 @@ var ConfigSchema = z.object({
357
403
  logging: LoggingConfigSchema,
358
404
  dev: DevConfigSchema,
359
405
  tool_rag: ToolRagConfigSchema,
406
+ capabilities: CapabilitiesConfigSchema,
360
407
  mcp: McpConfigSchema,
361
408
  plugins: z.record(z.string(), z.unknown()).default({}).describe("Per-plugin config (key = plugin name with underscores)"),
362
409
  cocoon: z.object({
363
410
  port: z.number().min(1).max(65535).default(1e4).describe("HTTP port of the cocoon-cli proxy")
364
411
  }).optional().describe("Cocoon Network \u2014 expects external cocoon-cli running on this port"),
365
412
  tonapi_key: z.string().optional().describe("TonAPI key for higher rate limits (from @tonapi_bot)"),
413
+ toncenter_api_key: z.string().optional().describe("TonCenter API key for dedicated RPC endpoint (free at https://toncenter.com)"),
366
414
  tavily_api_key: z.string().optional().describe("Tavily API key for web search & extract (free at https://tavily.com)")
367
415
  });
368
416
 
@@ -464,7 +512,8 @@ export {
464
512
  ensureWorkspace,
465
513
  isNewWorkspace,
466
514
  loadTemplate,
467
- getCachedHttpEndpoint,
515
+ setToncenterApiKey,
516
+ invalidateEndpointCache,
468
517
  generateWallet,
469
518
  saveWallet,
470
519
  loadWallet,
@@ -118,11 +118,11 @@ var MODEL_OPTIONS = {
118
118
  { value: "x-ai/grok-4", name: "Grok 4", description: "256K ctx, $3/M" }
119
119
  ],
120
120
  moonshot: [
121
- { value: "kimi-k2.5", name: "Kimi K2.5", description: "Free, 256K ctx, multimodal" },
121
+ { value: "k2p5", name: "Kimi K2.5", description: "Free, 262K ctx, multimodal" },
122
122
  {
123
123
  value: "kimi-k2-thinking",
124
124
  name: "Kimi K2 Thinking",
125
- description: "Free, 256K ctx, reasoning"
125
+ description: "Free, 262K ctx, reasoning"
126
126
  }
127
127
  ],
128
128
  mistral: [
@@ -146,6 +146,72 @@ var MODEL_OPTIONS = {
146
146
  name: "Magistral Small",
147
147
  description: "Reasoning, 128K ctx, $0.50/M"
148
148
  }
149
+ ],
150
+ cerebras: [
151
+ {
152
+ value: "qwen-3-235b-a22b-instruct-2507",
153
+ name: "Qwen 3 235B",
154
+ description: "131K ctx, $0.60/$1.20"
155
+ },
156
+ { value: "gpt-oss-120b", name: "GPT OSS 120B", description: "Reasoning, 131K ctx, $0.25/M" },
157
+ { value: "zai-glm-4.7", name: "ZAI GLM-4.7", description: "131K ctx, $2.25/M" },
158
+ { value: "llama3.1-8b", name: "Llama 3.1 8B", description: "Fast & cheap, 32K ctx, $0.10/M" }
159
+ ],
160
+ zai: [
161
+ { value: "glm-4.7", name: "GLM-4.7", description: "204K ctx, $0.60/$2.20" },
162
+ { value: "glm-5", name: "GLM-5", description: "Best quality, 204K ctx, $1.00/$3.20" },
163
+ { value: "glm-4.6", name: "GLM-4.6", description: "204K ctx, $0.60/$2.20" },
164
+ { value: "glm-4.7-flash", name: "GLM-4.7 Flash", description: "FREE, 200K ctx" },
165
+ { value: "glm-4.5-flash", name: "GLM-4.5 Flash", description: "FREE, 131K ctx" },
166
+ { value: "glm-4.5v", name: "GLM-4.5V", description: "Vision, 64K ctx, $0.60/$1.80" }
167
+ ],
168
+ minimax: [
169
+ { value: "MiniMax-M2.5", name: "MiniMax M2.5", description: "204K ctx, $0.30/$1.20" },
170
+ {
171
+ value: "MiniMax-M2.5-highspeed",
172
+ name: "MiniMax M2.5 Fast",
173
+ description: "204K ctx, $0.60/$2.40"
174
+ },
175
+ { value: "MiniMax-M2.1", name: "MiniMax M2.1", description: "204K ctx, $0.30/$1.20" },
176
+ { value: "MiniMax-M2", name: "MiniMax M2", description: "196K ctx, $0.30/$1.20" }
177
+ ],
178
+ huggingface: [
179
+ {
180
+ value: "deepseek-ai/DeepSeek-V3.2",
181
+ name: "DeepSeek V3.2",
182
+ description: "163K ctx, $0.28/$0.40"
183
+ },
184
+ {
185
+ value: "deepseek-ai/DeepSeek-R1-0528",
186
+ name: "DeepSeek R1",
187
+ description: "Reasoning, 163K ctx, $3/$5"
188
+ },
189
+ {
190
+ value: "Qwen/Qwen3-235B-A22B-Thinking-2507",
191
+ name: "Qwen3 235B",
192
+ description: "Reasoning, 262K ctx, $0.30/$3"
193
+ },
194
+ {
195
+ value: "Qwen/Qwen3-Coder-480B-A35B-Instruct",
196
+ name: "Qwen3 Coder 480B",
197
+ description: "Coding, 262K ctx, $2/$2"
198
+ },
199
+ {
200
+ value: "Qwen/Qwen3-Next-80B-A3B-Instruct",
201
+ name: "Qwen3 Next 80B",
202
+ description: "262K ctx, $0.25/$1"
203
+ },
204
+ {
205
+ value: "moonshotai/Kimi-K2.5",
206
+ name: "Kimi K2.5",
207
+ description: "262K ctx, $0.60/$3"
208
+ },
209
+ {
210
+ value: "zai-org/GLM-4.7-Flash",
211
+ name: "GLM-4.7 Flash",
212
+ description: "FREE, 200K ctx"
213
+ },
214
+ { value: "zai-org/GLM-5", name: "GLM-5", description: "202K ctx, $1/$3.20" }
149
215
  ]
150
216
  };
151
217
  function getModelsForProvider(provider) {
@@ -24,7 +24,7 @@ function getTranscriptPath(sessionId) {
24
24
  }
25
25
  function ensureSessionsDir() {
26
26
  if (!existsSync(SESSIONS_DIR)) {
27
- mkdirSync(SESSIONS_DIR, { recursive: true });
27
+ mkdirSync(SESSIONS_DIR, { recursive: true, mode: 448 });
28
28
  }
29
29
  }
30
30
  function appendToTranscript(sessionId, message) {
@@ -32,7 +32,7 @@ function appendToTranscript(sessionId, message) {
32
32
  const transcriptPath = getTranscriptPath(sessionId);
33
33
  const line = JSON.stringify(message) + "\n";
34
34
  try {
35
- appendFileSync(transcriptPath, line, "utf-8");
35
+ appendFileSync(transcriptPath, line, { encoding: "utf-8", mode: 384 });
36
36
  } catch (error) {
37
37
  log.error({ err: error }, `Failed to append to transcript ${sessionId}`);
38
38
  }
@@ -0,0 +1,314 @@
1
+ import {
2
+ createLogger
3
+ } from "./chunk-RCMD3U65.js";
4
+
5
+ // src/config/providers.ts
6
+ var PROVIDER_REGISTRY = {
7
+ anthropic: {
8
+ id: "anthropic",
9
+ displayName: "Anthropic (Claude)",
10
+ envVar: "ANTHROPIC_API_KEY",
11
+ keyPrefix: "sk-ant-",
12
+ keyHint: "sk-ant-api03-...",
13
+ consoleUrl: "https://console.anthropic.com/",
14
+ defaultModel: "claude-opus-4-6",
15
+ utilityModel: "claude-haiku-4-5-20251001",
16
+ toolLimit: null,
17
+ piAiProvider: "anthropic"
18
+ },
19
+ "claude-code": {
20
+ id: "claude-code",
21
+ displayName: "Claude Code (Auto)",
22
+ envVar: "ANTHROPIC_API_KEY",
23
+ keyPrefix: "sk-ant-",
24
+ keyHint: "Auto-detected from Claude Code",
25
+ consoleUrl: "https://console.anthropic.com/",
26
+ defaultModel: "claude-opus-4-6",
27
+ utilityModel: "claude-haiku-4-5-20251001",
28
+ toolLimit: null,
29
+ piAiProvider: "anthropic"
30
+ },
31
+ openai: {
32
+ id: "openai",
33
+ displayName: "OpenAI (GPT-4o)",
34
+ envVar: "OPENAI_API_KEY",
35
+ keyPrefix: "sk-",
36
+ keyHint: "sk-proj-...",
37
+ consoleUrl: "https://platform.openai.com/api-keys",
38
+ defaultModel: "gpt-4o",
39
+ utilityModel: "gpt-4o-mini",
40
+ toolLimit: 128,
41
+ piAiProvider: "openai"
42
+ },
43
+ google: {
44
+ id: "google",
45
+ displayName: "Google (Gemini)",
46
+ envVar: "GOOGLE_API_KEY",
47
+ keyPrefix: null,
48
+ keyHint: "AIza...",
49
+ consoleUrl: "https://aistudio.google.com/apikey",
50
+ defaultModel: "gemini-2.5-flash",
51
+ utilityModel: "gemini-2.0-flash-lite",
52
+ toolLimit: 128,
53
+ piAiProvider: "google"
54
+ },
55
+ xai: {
56
+ id: "xai",
57
+ displayName: "xAI (Grok)",
58
+ envVar: "XAI_API_KEY",
59
+ keyPrefix: "xai-",
60
+ keyHint: "xai-...",
61
+ consoleUrl: "https://console.x.ai/",
62
+ defaultModel: "grok-3",
63
+ utilityModel: "grok-3-mini-fast",
64
+ toolLimit: 128,
65
+ piAiProvider: "xai"
66
+ },
67
+ groq: {
68
+ id: "groq",
69
+ displayName: "Groq",
70
+ envVar: "GROQ_API_KEY",
71
+ keyPrefix: "gsk_",
72
+ keyHint: "gsk_...",
73
+ consoleUrl: "https://console.groq.com/keys",
74
+ defaultModel: "llama-3.3-70b-versatile",
75
+ utilityModel: "llama-3.1-8b-instant",
76
+ toolLimit: 128,
77
+ piAiProvider: "groq"
78
+ },
79
+ openrouter: {
80
+ id: "openrouter",
81
+ displayName: "OpenRouter",
82
+ envVar: "OPENROUTER_API_KEY",
83
+ keyPrefix: "sk-or-",
84
+ keyHint: "sk-or-v1-...",
85
+ consoleUrl: "https://openrouter.ai/keys",
86
+ defaultModel: "anthropic/claude-opus-4.5",
87
+ utilityModel: "google/gemini-2.5-flash-lite",
88
+ toolLimit: 128,
89
+ piAiProvider: "openrouter"
90
+ },
91
+ moonshot: {
92
+ id: "moonshot",
93
+ displayName: "Moonshot (Kimi K2.5)",
94
+ envVar: "MOONSHOT_API_KEY",
95
+ keyPrefix: "sk-",
96
+ keyHint: "sk-...",
97
+ consoleUrl: "https://platform.moonshot.ai/",
98
+ defaultModel: "k2p5",
99
+ utilityModel: "k2p5",
100
+ toolLimit: 128,
101
+ piAiProvider: "kimi-coding"
102
+ },
103
+ mistral: {
104
+ id: "mistral",
105
+ displayName: "Mistral AI",
106
+ envVar: "MISTRAL_API_KEY",
107
+ keyPrefix: null,
108
+ keyHint: "...",
109
+ consoleUrl: "https://console.mistral.ai/api-keys",
110
+ defaultModel: "devstral-small-2507",
111
+ utilityModel: "ministral-8b-latest",
112
+ toolLimit: 128,
113
+ piAiProvider: "mistral"
114
+ },
115
+ cerebras: {
116
+ id: "cerebras",
117
+ displayName: "Cerebras",
118
+ envVar: "CEREBRAS_API_KEY",
119
+ keyPrefix: "csk-",
120
+ keyHint: "csk-...",
121
+ consoleUrl: "https://cloud.cerebras.ai/",
122
+ defaultModel: "qwen-3-235b-a22b-instruct-2507",
123
+ utilityModel: "llama3.1-8b",
124
+ toolLimit: 128,
125
+ piAiProvider: "cerebras"
126
+ },
127
+ zai: {
128
+ id: "zai",
129
+ displayName: "ZAI (Zhipu)",
130
+ envVar: "ZAI_API_KEY",
131
+ keyPrefix: null,
132
+ keyHint: "...",
133
+ consoleUrl: "https://z.ai/manage-apikey/apikey-list",
134
+ defaultModel: "glm-4.7",
135
+ utilityModel: "glm-4.7-flash",
136
+ toolLimit: 128,
137
+ piAiProvider: "zai"
138
+ },
139
+ minimax: {
140
+ id: "minimax",
141
+ displayName: "MiniMax",
142
+ envVar: "MINIMAX_API_KEY",
143
+ keyPrefix: null,
144
+ keyHint: "Save your key \u2014 shown only once!",
145
+ consoleUrl: "https://platform.minimax.io/",
146
+ defaultModel: "MiniMax-M2.5",
147
+ utilityModel: "MiniMax-M2",
148
+ toolLimit: 128,
149
+ piAiProvider: "minimax"
150
+ },
151
+ huggingface: {
152
+ id: "huggingface",
153
+ displayName: "HuggingFace",
154
+ envVar: "HF_TOKEN",
155
+ keyPrefix: "hf_",
156
+ keyHint: "hf_...",
157
+ consoleUrl: "https://huggingface.co/settings/tokens",
158
+ defaultModel: "deepseek-ai/DeepSeek-V3.2",
159
+ utilityModel: "Qwen/Qwen3-Next-80B-A3B-Instruct",
160
+ toolLimit: 128,
161
+ piAiProvider: "huggingface"
162
+ },
163
+ cocoon: {
164
+ id: "cocoon",
165
+ displayName: "Cocoon Network (Decentralized)",
166
+ envVar: "",
167
+ keyPrefix: null,
168
+ keyHint: "No API key needed \u2014 pays in TON",
169
+ consoleUrl: "https://cocoon.network",
170
+ defaultModel: "Qwen/Qwen3-32B",
171
+ utilityModel: "Qwen/Qwen3-32B",
172
+ toolLimit: 128,
173
+ piAiProvider: "cocoon"
174
+ },
175
+ local: {
176
+ id: "local",
177
+ displayName: "Local (Ollama, vLLM, LM Studio...)",
178
+ envVar: "",
179
+ keyPrefix: null,
180
+ keyHint: "No API key needed",
181
+ consoleUrl: "",
182
+ defaultModel: "auto",
183
+ utilityModel: "auto",
184
+ toolLimit: 128,
185
+ piAiProvider: "local"
186
+ }
187
+ };
188
+ function getProviderMetadata(provider) {
189
+ const meta = PROVIDER_REGISTRY[provider];
190
+ if (!meta) {
191
+ throw new Error(`Unknown provider: ${provider}`);
192
+ }
193
+ return meta;
194
+ }
195
+ function getSupportedProviders() {
196
+ return Object.values(PROVIDER_REGISTRY);
197
+ }
198
+ function validateApiKeyFormat(provider, key) {
199
+ const meta = PROVIDER_REGISTRY[provider];
200
+ if (!meta) return `Unknown provider: ${provider}`;
201
+ if (provider === "cocoon" || provider === "local" || provider === "claude-code") return void 0;
202
+ if (!key || key.trim().length === 0) return "API key is required";
203
+ if (meta.keyPrefix && !key.startsWith(meta.keyPrefix)) {
204
+ return `Invalid format (should start with ${meta.keyPrefix})`;
205
+ }
206
+ return void 0;
207
+ }
208
+
209
+ // src/providers/claude-code-credentials.ts
210
+ import { readFileSync, existsSync } from "fs";
211
+ import { execSync } from "child_process";
212
+ import { homedir } from "os";
213
+ import { join } from "path";
214
+ var log = createLogger("ClaudeCodeCreds");
215
+ var cachedToken = null;
216
+ var cachedExpiresAt = 0;
217
+ function getClaudeConfigDir() {
218
+ return process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
219
+ }
220
+ function getCredentialsFilePath() {
221
+ return join(getClaudeConfigDir(), ".credentials.json");
222
+ }
223
+ function readCredentialsFile() {
224
+ const filePath = getCredentialsFilePath();
225
+ if (!existsSync(filePath)) return null;
226
+ try {
227
+ const raw = readFileSync(filePath, "utf-8");
228
+ return JSON.parse(raw);
229
+ } catch (e) {
230
+ log.warn({ err: e, path: filePath }, "Failed to parse Claude Code credentials file");
231
+ return null;
232
+ }
233
+ }
234
+ function readKeychainCredentials() {
235
+ const serviceNames = ["Claude Code-credentials", "Claude Code"];
236
+ for (const service of serviceNames) {
237
+ try {
238
+ const raw = execSync(`security find-generic-password -s "${service}" -w`, {
239
+ encoding: "utf-8",
240
+ stdio: ["pipe", "pipe", "pipe"]
241
+ }).trim();
242
+ return JSON.parse(raw);
243
+ } catch {
244
+ }
245
+ }
246
+ return null;
247
+ }
248
+ function readCredentials() {
249
+ if (process.platform === "darwin") {
250
+ const keychainCreds = readKeychainCredentials();
251
+ if (keychainCreds) return keychainCreds;
252
+ log.debug("Keychain read failed, falling back to credentials file");
253
+ }
254
+ return readCredentialsFile();
255
+ }
256
+ function extractToken(creds) {
257
+ const oauth = creds.claudeAiOauth;
258
+ if (!oauth?.accessToken) {
259
+ log.warn("Claude Code credentials found but missing accessToken");
260
+ return null;
261
+ }
262
+ return {
263
+ token: oauth.accessToken,
264
+ expiresAt: oauth.expiresAt ?? 0
265
+ };
266
+ }
267
+ function getClaudeCodeApiKey(fallbackKey) {
268
+ if (cachedToken && Date.now() < cachedExpiresAt) {
269
+ return cachedToken;
270
+ }
271
+ const creds = readCredentials();
272
+ if (creds) {
273
+ const extracted = extractToken(creds);
274
+ if (extracted) {
275
+ cachedToken = extracted.token;
276
+ cachedExpiresAt = extracted.expiresAt;
277
+ log.debug("Claude Code credentials loaded successfully");
278
+ return cachedToken;
279
+ }
280
+ }
281
+ if (fallbackKey && fallbackKey.length > 0) {
282
+ log.warn("Claude Code credentials not found, using fallback api_key from config");
283
+ return fallbackKey;
284
+ }
285
+ throw new Error("No Claude Code credentials found. Run 'claude login' or set api_key in config.");
286
+ }
287
+ function refreshClaudeCodeApiKey() {
288
+ cachedToken = null;
289
+ cachedExpiresAt = 0;
290
+ const creds = readCredentials();
291
+ if (creds) {
292
+ const extracted = extractToken(creds);
293
+ if (extracted) {
294
+ cachedToken = extracted.token;
295
+ cachedExpiresAt = extracted.expiresAt;
296
+ log.info("Claude Code credentials refreshed from disk");
297
+ return cachedToken;
298
+ }
299
+ }
300
+ log.warn("Failed to refresh Claude Code credentials from disk");
301
+ return null;
302
+ }
303
+ function isClaudeCodeTokenValid() {
304
+ return cachedToken !== null && Date.now() < cachedExpiresAt;
305
+ }
306
+
307
+ export {
308
+ getProviderMetadata,
309
+ getSupportedProviders,
310
+ validateApiKeyFormat,
311
+ getClaudeCodeApiKey,
312
+ refreshClaudeCodeApiKey,
313
+ isClaudeCodeTokenValid
314
+ };