teleton 0.7.2 → 0.7.4

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 (31) hide show
  1. package/README.md +31 -12
  2. package/dist/{chunk-ND2X5FWB.js → chunk-5PLZ3KSO.js} +16 -3
  3. package/dist/{chunk-NERLQY2H.js → chunk-BGC2IUM5.js} +73 -15
  4. package/dist/{chunk-FNV5FF35.js → chunk-EK7M5K26.js} +29 -13
  5. package/dist/chunk-JQDLW7IE.js +107 -0
  6. package/dist/{chunk-VSMUAU5X.js → chunk-LAQOUFOJ.js} +2419 -2132
  7. package/dist/chunk-QOQWUUA4.js +158 -0
  8. package/dist/{chunk-LRCPA7SC.js → chunk-RMLQS3X6.js} +15 -3
  9. package/dist/{chunk-UDD7FYOU.js → chunk-WIKM24GZ.js} +1 -18
  10. package/dist/{chunk-RBU6JXD3.js → chunk-XDYDA2KV.js} +1 -1
  11. package/dist/{chunk-JHKWHGBM.js → chunk-YFG2QHLA.js} +380 -47
  12. package/dist/cli/index.js +216 -272
  13. package/dist/{client-3VWE7NC4.js → client-RTNALK7W.js} +3 -2
  14. package/dist/{get-my-gifts-RI7FAXAL.js → get-my-gifts-TPVUGUWT.js} +1 -1
  15. package/dist/index.js +9 -10
  16. package/dist/{memory-5SS3Q5EA.js → memory-JQZ6MTRU.js} +2 -2
  17. package/dist/{migrate-M7SJMDOL.js → migrate-GS5ACQDA.js} +2 -2
  18. package/dist/{server-NPSODUMA.js → server-TCJOBV3D.js} +292 -11
  19. package/dist/{setup-server-C7ZTPHD5.js → setup-server-YHYJLAMA.js} +77 -112
  20. package/dist/{tool-index-MIVK3D7H.js → tool-index-6HBRVXVG.js} +1 -1
  21. package/dist/web/assets/index-B6M9knfJ.css +1 -0
  22. package/dist/web/assets/index-DAGeQfVZ.js +72 -0
  23. package/dist/web/assets/{index.es-D81xLR29.js → index.es-CqZHj0tz.js} +1 -1
  24. package/dist/web/index.html +2 -2
  25. package/package.json +2 -2
  26. package/dist/chunk-EHEV7FJ7.js +0 -157
  27. package/dist/chunk-QUAPFI2N.js +0 -42
  28. package/dist/endpoint-FLYNEZ2F.js +0 -7
  29. package/dist/format-transactions-FD74HI5N.js +0 -9
  30. package/dist/web/assets/index-BqwoDycr.js +0 -72
  31. package/dist/web/assets/index-CRDIf07k.css +0 -1
package/README.md CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  - **Full Telegram access** - Operates as a real user via MTProto (GramJS), not a limited bot
23
23
  - **Agentic loop** - Up to 5 iterations of tool calling per message, the agent thinks, acts, observes, and repeats
24
- - **Multi-Provider LLM** - Anthropic, OpenAI, Google Gemini, xAI Grok, Groq, OpenRouter, Moonshot, Mistral, Cocoon, Local
24
+ - **Multi-Provider LLM** - Anthropic, Claude Code, OpenAI, Google Gemini, xAI Grok, Groq, OpenRouter, Moonshot, Mistral, Cocoon, Local (11 providers)
25
25
  - **TON Blockchain** - Built-in W5R1 wallet, send/receive TON & jettons, swap on STON.fi and DeDust, NFTs, DNS domains
26
26
  - **Persistent memory** - Hybrid RAG (sqlite-vec + FTS5), auto-compaction with AI summarization, daily logs
27
27
  - **100+ built-in tools** - Messaging, media, blockchain, DEX trading, deals, DNS, journaling, and more
@@ -37,7 +37,7 @@
37
37
 
38
38
  | Category | Tools | Description |
39
39
  | ------------- | ----- | ------------------------------------------------------------------------------------------------------------------ |
40
- | Telegram | 66 | Messaging, media, chats, groups, polls, stickers, gifts, stars, stories, contacts, folders, profile, memory, tasks |
40
+ | Telegram | 73 | Messaging, media, chats, groups, polls, stickers, gifts, stars, stories, contacts, folders, profile, memory, tasks, voice transcription, scheduled messages |
41
41
  | TON & Jettons | 15 | W5R1 wallet, send/receive TON & jettons, balances, prices, holders, history, charts, NFTs, smart DEX router |
42
42
  | STON.fi DEX | 5 | Swap, quote, search, trending tokens, liquidity pools |
43
43
  | DeDust DEX | 5 | Swap, quote, pools, prices, token analytics (holders, top traders, buy/sell tax) |
@@ -51,7 +51,7 @@
51
51
 
52
52
  | Capability | Description |
53
53
  | ----------------------- | --------------------------------------------------------------------------------------------------------------------------- |
54
- | **Multi-Provider LLM** | Switch between Anthropic, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cocoon, or Local with one config change |
54
+ | **Multi-Provider LLM** | Switch between Anthropic, Claude Code, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cocoon, or Local Dashboard validates API key before switching |
55
55
  | **RAG + Hybrid Search** | Local ONNX embeddings (384d) or Voyage AI (512d/1024d) with FTS5 keyword + sqlite-vec cosine similarity, fused via RRF |
56
56
  | **Auto-Compaction** | AI-summarized context management prevents overflow, preserves key information in `memory/*.md` files |
57
57
  | **Observation Masking** | Compresses old tool results to one-line summaries, saving ~90% context window |
@@ -71,7 +71,7 @@
71
71
  ## Prerequisites
72
72
 
73
73
  - **Node.js 20.0.0+** - [Download](https://nodejs.org/)
74
- - **LLM API Key** - One of: [Anthropic](https://console.anthropic.com/) (recommended), [OpenAI](https://platform.openai.com/), [Google](https://aistudio.google.com/), [xAI](https://console.x.ai/), [Groq](https://console.groq.com/), [OpenRouter](https://openrouter.ai/)
74
+ - **LLM API Key** - One of: [Anthropic](https://console.anthropic.com/) (recommended), [OpenAI](https://platform.openai.com/), [Google](https://aistudio.google.com/), [xAI](https://console.x.ai/), [Groq](https://console.groq.com/), [OpenRouter](https://openrouter.ai/), [Moonshot](https://platform.moonshot.ai/), [Mistral](https://console.mistral.ai/) — or keyless: Claude Code (auto-detect), Cocoon (TON), Local (Ollama/vLLM)
75
75
  - **Telegram Account** - Dedicated account recommended for security
76
76
  - **Telegram API Credentials** - From [my.telegram.org/apps](https://my.telegram.org/apps)
77
77
  - **Your Telegram User ID** - Message [@userinfobot](https://t.me/userinfobot)
@@ -109,7 +109,7 @@ teleton setup
109
109
  ```
110
110
 
111
111
  The wizard will configure:
112
- - LLM provider selection (Anthropic, OpenAI, Google, xAI, Groq, OpenRouter)
112
+ - LLM provider selection (11 providers: Anthropic, Claude Code, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cocoon, Local)
113
113
  - Telegram authentication (API credentials, phone, login code)
114
114
  - Access policies (DM/group response rules)
115
115
  - Admin user ID
@@ -152,10 +152,10 @@ The `teleton setup` wizard generates a fully configured `~/.teleton/config.yaml`
152
152
 
153
153
  ```yaml
154
154
  agent:
155
- provider: "anthropic" # anthropic | openai | google | xai | groq | openrouter
155
+ provider: "anthropic" # anthropic | claude-code | openai | google | xai | groq | openrouter | moonshot | mistral | cocoon | local
156
156
  api_key: "sk-ant-api03-..."
157
- model: "claude-opus-4-5-20251101"
158
- utility_model: "claude-3-5-haiku-20241022" # for summarization, compaction, vision
157
+ model: "claude-opus-4-6"
158
+ utility_model: "claude-haiku-4-5-20251001" # for summarization, compaction, vision
159
159
  max_agentic_iterations: 5
160
160
 
161
161
  telegram:
@@ -183,6 +183,24 @@ webui: # Optional: Web dashboard
183
183
  # auth_token: "..." # Auto-generated if omitted
184
184
  ```
185
185
 
186
+ ### Supported Models
187
+
188
+ All models are defined in `src/config/model-catalog.ts` and shared across the CLI setup, WebUI setup wizard, and Dashboard. To add a model, add it there — it will appear everywhere automatically.
189
+
190
+ | Provider | Models |
191
+ |----------|--------|
192
+ | **Anthropic** | Claude Opus 4.6, Claude Opus 4.5, Claude Sonnet 4.6, Claude Haiku 4.5 |
193
+ | **Claude Code** | Same as Anthropic (auto-detected credentials) |
194
+ | **OpenAI** | GPT-5, GPT-5 Pro, GPT-5 Mini, GPT-5.1, GPT-4o, GPT-4.1, GPT-4.1 Mini, o4 Mini, o3, Codex Mini |
195
+ | **Google** | Gemini 3 Pro (preview), Gemini 3 Flash (preview), Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.5 Flash Lite, Gemini 2.0 Flash |
196
+ | **xAI** | Grok 4.1 Fast, Grok 4 Fast, Grok 4, Grok Code, Grok 3 |
197
+ | **Groq** | Llama 4 Maverick, Qwen3 32B, DeepSeek R1 70B, Llama 3.3 70B |
198
+ | **OpenRouter** | Claude Opus/Sonnet, GPT-5, Gemini, DeepSeek R1/V3, Qwen3 Coder/Max/235B, Nemotron, Sonar Pro, MiniMax, Grok 4 |
199
+ | **Moonshot** | Kimi K2.5, Kimi K2 Thinking |
200
+ | **Mistral** | Devstral Small/Medium, Mistral Large, Magistral Small |
201
+ | **Cocoon** | Qwen/Qwen3-32B (decentralized, pays in TON) |
202
+ | **Local** | Auto-detected (Ollama, vLLM, LM Studio) |
203
+
186
204
  ### MCP Servers
187
205
 
188
206
  Connect external tool servers via the [Model Context Protocol](https://modelcontextprotocol.io/). No code needed - tools are auto-discovered and registered at startup.
@@ -283,7 +301,7 @@ Teleton includes an **optional web dashboard** for monitoring and configuration.
283
301
 
284
302
  ### Features
285
303
 
286
- - **Dashboard**: System status, uptime, model info, session count, memory stats
304
+ - **Dashboard**: System status, uptime, model info, session count, memory stats, provider switching with API key validation
287
305
  - **Tools Management**: View all tools grouped by module, toggle enable/disable, change scope per tool
288
306
  - **Plugin Marketplace**: Install, update, and manage plugins from registry with secrets management
289
307
  - **Soul Editor**: Edit SOUL.md, SECURITY.md, STRATEGY.md, MEMORY.md with unsaved changes warning
@@ -386,7 +404,7 @@ All admin commands support `/`, `!`, or `.` prefix:
386
404
 
387
405
  | Layer | Technology |
388
406
  |-------|------------|
389
- | LLM | Multi-provider via [pi-ai](https://github.com/mariozechner/pi-ai) (Anthropic, OpenAI, Google, xAI, Groq, OpenRouter) |
407
+ | LLM | Multi-provider via [pi-ai](https://github.com/mariozechner/pi-ai) (11 providers: Anthropic, Claude Code, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cocoon, Local) |
390
408
  | Telegram Userbot | [GramJS](https://gram.js.org/) (MTProto) |
391
409
  | Inline Bot | [Grammy](https://grammy.dev/) (Bot API, for deals) |
392
410
  | Blockchain | [TON SDK](https://github.com/ton-org/ton) (W5R1 wallet) |
@@ -414,7 +432,7 @@ src/
414
432
  │ ├── module-loader.ts # Built-in module loading (deals → +5 tools)
415
433
  │ ├── plugin-loader.ts # External plugin discovery, validation, hot-reload
416
434
  │ ├── mcp-loader.ts # MCP client (stdio/SSE), tool discovery, lifecycle
417
- │ ├── telegram/ # Telegram operations (66 tools)
435
+ │ ├── telegram/ # Telegram operations (73 tools)
418
436
  │ ├── ton/ # TON blockchain + jettons + DEX router (15 tools)
419
437
  │ ├── stonfi/ # STON.fi DEX (5 tools)
420
438
  │ ├── dedust/ # DeDust DEX (5 tools)
@@ -463,7 +481,8 @@ src/
463
481
  │ └── loader.ts # 10 sections: soul + security + strategy + memory + context + ...
464
482
  ├── config/ # Configuration
465
483
  │ ├── schema.ts # Zod schemas + validation
466
- └── providers.ts # Multi-provider LLM registry (10 providers)
484
+ ├── providers.ts # Multi-provider LLM registry (11 providers)
485
+ │ └── model-catalog.ts # Shared model catalog (60+ models across all providers)
467
486
  ├── webui/ # Optional web dashboard
468
487
  │ ├── server.ts # Hono server, auth middleware, static serving
469
488
  │ └── routes/ # 11 API route groups (status, tools, logs, memory, soul, plugins, mcp, tasks, workspace, config, marketplace)
@@ -1,6 +1,10 @@
1
+ import {
2
+ getClaudeCodeApiKey,
3
+ refreshClaudeCodeApiKey
4
+ } from "./chunk-JQDLW7IE.js";
1
5
  import {
2
6
  getProviderMetadata
3
- } from "./chunk-LRCPA7SC.js";
7
+ } from "./chunk-RMLQS3X6.js";
4
8
  import {
5
9
  appendToTranscript,
6
10
  readTranscript
@@ -92,12 +96,13 @@ function sanitizeToolsForGemini(tools) {
92
96
  // src/agent/client.ts
93
97
  var log = createLogger("LLM");
94
98
  function isOAuthToken(apiKey, provider) {
95
- if (provider && provider !== "anthropic") return false;
99
+ if (provider && provider !== "anthropic" && provider !== "claude-code") return false;
96
100
  return apiKey.startsWith("sk-ant-oat01-");
97
101
  }
98
102
  function getEffectiveApiKey(provider, rawKey) {
99
103
  if (provider === "local") return "local";
100
104
  if (provider === "cocoon") return "";
105
+ if (provider === "claude-code") return getClaudeCodeApiKey(rawKey);
101
106
  return rawKey;
102
107
  }
103
108
  var modelCache = /* @__PURE__ */ new Map();
@@ -307,7 +312,15 @@ async function chatWithContext(config, options) {
307
312
  const { stripCocoonPayload } = await import("./tool-adapter-Y3TCEQOC.js");
308
313
  completeOptions.onPayload = stripCocoonPayload;
309
314
  }
310
- const response = await complete(model, context, completeOptions);
315
+ let response = await complete(model, context, completeOptions);
316
+ if (provider === "claude-code" && response.stopReason === "error" && response.errorMessage && (response.errorMessage.includes("401") || response.errorMessage.toLowerCase().includes("unauthorized"))) {
317
+ log.warn("Claude Code token rejected (401), refreshing credentials and retrying...");
318
+ const refreshedKey = refreshClaudeCodeApiKey();
319
+ if (refreshedKey) {
320
+ completeOptions.apiKey = refreshedKey;
321
+ response = await complete(model, context, completeOptions);
322
+ }
323
+ }
311
324
  if (isCocoon) {
312
325
  const textBlock = response.content.find((b) => b.type === "text");
313
326
  if (textBlock?.type === "text" && textBlock.text.includes("<tool_call>")) {
@@ -1,6 +1,3 @@
1
- import {
2
- getCachedHttpEndpoint
3
- } from "./chunk-QUAPFI2N.js";
4
1
  import {
5
2
  COINGECKO_API_URL,
6
3
  tonapiFetch
@@ -25,10 +22,55 @@ import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto
25
22
  import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
26
23
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
27
24
  import { join, dirname } from "path";
25
+
26
+ // src/ton/endpoint.ts
27
+ var ENDPOINT_CACHE_TTL_MS = 6e4;
28
+ var ORBS_HOST = "ton.access.orbs.network";
29
+ var ORBS_TOPOLOGY_URL = `https://${ORBS_HOST}/mngr/nodes?npm_version=2.3.3`;
30
+ var TONCENTER_FALLBACK = `https://toncenter.com/api/v2/jsonRPC`;
31
+ var _cache = null;
32
+ async function discoverOrbsEndpoint() {
33
+ const res = await fetch(ORBS_TOPOLOGY_URL);
34
+ const nodes = await res.json();
35
+ const healthy = nodes.filter(
36
+ (n) => n.Healthy === "1" && n.Weight > 0 && n.Mngr?.health?.["v2-mainnet"]
37
+ );
38
+ if (healthy.length === 0) throw new Error("no healthy orbs nodes");
39
+ const totalWeight = healthy.reduce((sum, n) => sum + n.Weight, 0);
40
+ let r = Math.floor(Math.random() * totalWeight);
41
+ let chosen = healthy[0];
42
+ for (const node of healthy) {
43
+ r -= node.Weight;
44
+ if (r < 0) {
45
+ chosen = node;
46
+ break;
47
+ }
48
+ }
49
+ return `https://${ORBS_HOST}/${chosen.NodeId}/1/mainnet/toncenter-api-v2/jsonRPC`;
50
+ }
51
+ async function getCachedHttpEndpoint() {
52
+ if (_cache && Date.now() - _cache.ts < ENDPOINT_CACHE_TTL_MS) {
53
+ return _cache.url;
54
+ }
55
+ let url;
56
+ try {
57
+ url = await discoverOrbsEndpoint();
58
+ } catch {
59
+ url = TONCENTER_FALLBACK;
60
+ }
61
+ _cache = { url, ts: Date.now() };
62
+ return url;
63
+ }
64
+ function invalidateEndpointCache() {
65
+ _cache = null;
66
+ }
67
+
68
+ // src/ton/wallet-service.ts
28
69
  var log = createLogger("TON");
29
70
  var WALLET_FILE = join(TELETON_ROOT, "wallet.json");
30
71
  var _walletCache;
31
72
  var _keyPairCache = null;
73
+ var _tonClientCache = null;
32
74
  async function generateWallet() {
33
75
  const mnemonic = await mnemonicNew(24);
34
76
  const keyPair = await mnemonicToPrivateKey(mnemonic);
@@ -100,6 +142,19 @@ function getWalletAddress() {
100
142
  const wallet = loadWallet();
101
143
  return wallet?.address || null;
102
144
  }
145
+ async function getCachedTonClient() {
146
+ const endpoint = await getCachedHttpEndpoint();
147
+ if (_tonClientCache && _tonClientCache.endpoint === endpoint) {
148
+ return _tonClientCache.client;
149
+ }
150
+ const client = new TonClient({ endpoint });
151
+ _tonClientCache = { client, endpoint };
152
+ return client;
153
+ }
154
+ function invalidateTonClientCache() {
155
+ _tonClientCache = null;
156
+ invalidateEndpointCache();
157
+ }
103
158
  async function getKeyPair() {
104
159
  if (_keyPairCache) return _keyPairCache;
105
160
  const wallet = loadWallet();
@@ -109,8 +164,7 @@ async function getKeyPair() {
109
164
  }
110
165
  async function getWalletBalance(address) {
111
166
  try {
112
- const endpoint = await getCachedHttpEndpoint();
113
- const client = new TonClient({ endpoint });
167
+ const client = await getCachedTonClient();
114
168
  const { Address } = await import("@ton/core");
115
169
  const addressObj = Address.parse(address);
116
170
  const balance = await client.getBalance(addressObj);
@@ -163,7 +217,7 @@ async function getTonPrice() {
163
217
 
164
218
  // src/config/schema.ts
165
219
  import { z } from "zod";
166
- var DMPolicy = z.enum(["pairing", "allowlist", "open", "disabled"]);
220
+ var DMPolicy = z.enum(["allowlist", "open", "disabled"]);
167
221
  var GroupPolicy = z.enum(["open", "allowlist", "disabled"]);
168
222
  var SessionResetPolicySchema = z.object({
169
223
  daily_reset_enabled: z.boolean().default(true).describe("Enable daily session reset"),
@@ -174,6 +228,7 @@ var SessionResetPolicySchema = z.object({
174
228
  var AgentConfigSchema = z.object({
175
229
  provider: z.enum([
176
230
  "anthropic",
231
+ "claude-code",
177
232
  "openai",
178
233
  "google",
179
234
  "xai",
@@ -186,7 +241,7 @@ var AgentConfigSchema = z.object({
186
241
  ]).default("anthropic"),
187
242
  api_key: z.string().default(""),
188
243
  base_url: z.string().url().optional().describe("Base URL for local LLM server (e.g. http://localhost:11434/v1)"),
189
- model: z.string().default("claude-opus-4-5-20251101"),
244
+ model: z.string().default("claude-opus-4-6"),
190
245
  utility_model: z.string().optional().describe("Cheap model for summarization (auto-detected if omitted)"),
191
246
  max_tokens: z.number().default(4096),
192
247
  temperature: z.number().default(0.7),
@@ -200,7 +255,7 @@ var TelegramConfigSchema = z.object({
200
255
  phone: z.string(),
201
256
  session_name: z.string().default("teleton_session"),
202
257
  session_path: z.string().default("~/.teleton"),
203
- dm_policy: DMPolicy.default("pairing"),
258
+ dm_policy: DMPolicy.default("allowlist"),
204
259
  allow_from: z.array(z.number()).default([]),
205
260
  group_policy: GroupPolicy.default("open"),
206
261
  group_allow_from: z.array(z.number()).default([]),
@@ -220,7 +275,6 @@ var TelegramConfigSchema = z.object({
220
275
  });
221
276
  var StorageConfigSchema = z.object({
222
277
  sessions_file: z.string().default("~/.teleton/sessions.json"),
223
- pairing_file: z.string().default("~/.teleton/pairing.json"),
224
278
  memory_file: z.string().default("~/.teleton/memory.json"),
225
279
  history_limit: z.number().default(100)
226
280
  });
@@ -233,7 +287,7 @@ var MetaConfigSchema = z.object({
233
287
  var _DealsObject = z.object({
234
288
  enabled: z.boolean().default(true),
235
289
  expiry_seconds: z.number().default(120),
236
- buy_max_floor_percent: z.number().default(100),
290
+ buy_max_floor_percent: z.number().default(95),
237
291
  sell_min_floor_percent: z.number().default(105),
238
292
  poll_interval_ms: z.number().default(5e3),
239
293
  max_verification_retries: z.number().default(12),
@@ -327,13 +381,14 @@ function findPackageRoot() {
327
381
  }
328
382
  var TEMPLATES_DIR = join2(findPackageRoot(), "src", "templates");
329
383
  async function ensureWorkspace(config) {
384
+ const silent = config?.silent ?? false;
330
385
  if (!existsSync2(TELETON_ROOT)) {
331
386
  mkdirSync2(TELETON_ROOT, { recursive: true });
332
- log2.info(`Created Teleton root at ${TELETON_ROOT}`);
387
+ if (!silent) log2.info(`Created Teleton root at ${TELETON_ROOT}`);
333
388
  }
334
389
  if (!existsSync2(WORKSPACE_ROOT)) {
335
390
  mkdirSync2(WORKSPACE_ROOT, { recursive: true });
336
- log2.info(`Created workspace at ${WORKSPACE_ROOT}`);
391
+ if (!silent) log2.info(`Created workspace at ${WORKSPACE_ROOT}`);
337
392
  }
338
393
  const directories = [
339
394
  WORKSPACE_PATHS.MEMORY_DIR,
@@ -369,11 +424,11 @@ async function ensureWorkspace(config) {
369
424
  walletPath: join2(TELETON_ROOT, "wallet.json")
370
425
  };
371
426
  if (config?.ensureTemplates) {
372
- await bootstrapTemplates(workspace);
427
+ await bootstrapTemplates(workspace, silent);
373
428
  }
374
429
  return workspace;
375
430
  }
376
- async function bootstrapTemplates(workspace) {
431
+ async function bootstrapTemplates(workspace, silent = false) {
377
432
  const templates = [
378
433
  { name: "SOUL.md", path: workspace.soulPath },
379
434
  { name: "MEMORY.md", path: workspace.memoryPath },
@@ -387,7 +442,7 @@ async function bootstrapTemplates(workspace) {
387
442
  const templateSource = join2(TEMPLATES_DIR, template.name);
388
443
  if (existsSync2(templateSource)) {
389
444
  copyFileSync(templateSource, template.path);
390
- log2.info(`Created ${template.name}`);
445
+ if (!silent) log2.info(`Created ${template.name}`);
391
446
  }
392
447
  }
393
448
  }
@@ -409,12 +464,15 @@ export {
409
464
  ensureWorkspace,
410
465
  isNewWorkspace,
411
466
  loadTemplate,
467
+ getCachedHttpEndpoint,
412
468
  generateWallet,
413
469
  saveWallet,
414
470
  loadWallet,
415
471
  walletExists,
416
472
  importWallet,
417
473
  getWalletAddress,
474
+ getCachedTonClient,
475
+ invalidateTonClientCache,
418
476
  getKeyPair,
419
477
  getWalletBalance,
420
478
  getTonPrice
@@ -91,14 +91,22 @@ var AnthropicEmbeddingProvider = class {
91
91
  // src/memory/embeddings/local.ts
92
92
  import { pipeline, env } from "@huggingface/transformers";
93
93
  import { join } from "path";
94
+ import { mkdirSync } from "fs";
94
95
  var log = createLogger("Memory");
95
- env.cacheDir = join(TELETON_ROOT, "models");
96
+ var modelCacheDir = join(TELETON_ROOT, "models");
97
+ try {
98
+ mkdirSync(modelCacheDir, { recursive: true });
99
+ } catch {
100
+ }
101
+ env.cacheDir = modelCacheDir;
96
102
  var extractorPromise = null;
97
103
  function getExtractor(model) {
98
104
  if (!extractorPromise) {
99
- log.info(`Loading local embedding model: ${model} (cache: ${env.cacheDir})`);
105
+ log.info(`Loading local embedding model: ${model} (cache: ${modelCacheDir})`);
100
106
  extractorPromise = pipeline("feature-extraction", model, {
101
- dtype: "fp32"
107
+ dtype: "fp32",
108
+ // Explicit cache_dir to avoid any env race condition
109
+ cache_dir: modelCacheDir
102
110
  }).then((ext) => {
103
111
  log.info(`Local embedding model ready`);
104
112
  return ext;
@@ -121,21 +129,29 @@ var LocalEmbeddingProvider = class {
121
129
  }
122
130
  /**
123
131
  * Pre-download and load the model at startup.
124
- * If loading fails, marks this provider as disabled (returns empty embeddings).
132
+ * If loading fails, retries once then marks provider as disabled (FTS5-only).
125
133
  * Call this once during app init — avoids retry spam on every message.
126
134
  * @returns true if model loaded successfully, false if fallback to noop
127
135
  */
128
136
  async warmup() {
129
- try {
130
- await getExtractor(this.model);
131
- return true;
132
- } catch (err) {
133
- log.warn(
134
- `Local embedding model unavailable \u2014 falling back to FTS5-only search (no vector embeddings)`
135
- );
136
- this._disabled = true;
137
- return false;
137
+ for (let attempt = 1; attempt <= 2; attempt++) {
138
+ try {
139
+ await getExtractor(this.model);
140
+ return true;
141
+ } catch (err) {
142
+ if (attempt === 1) {
143
+ log.warn(`Embedding model load failed (attempt 1), retrying...`);
144
+ await new Promise((r) => setTimeout(r, 1e3));
145
+ } else {
146
+ log.warn(
147
+ `Local embedding model unavailable \u2014 falling back to FTS5-only search (no vector embeddings)`
148
+ );
149
+ this._disabled = true;
150
+ return false;
151
+ }
152
+ }
138
153
  }
154
+ return false;
139
155
  }
140
156
  async embedQuery(text) {
141
157
  if (this._disabled) return [];
@@ -0,0 +1,107 @@
1
+ import {
2
+ createLogger
3
+ } from "./chunk-RCMD3U65.js";
4
+
5
+ // src/providers/claude-code-credentials.ts
6
+ import { readFileSync, existsSync } from "fs";
7
+ import { execSync } from "child_process";
8
+ import { homedir } from "os";
9
+ import { join } from "path";
10
+ var log = createLogger("ClaudeCodeCreds");
11
+ var cachedToken = null;
12
+ var cachedExpiresAt = 0;
13
+ function getClaudeConfigDir() {
14
+ return process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
15
+ }
16
+ function getCredentialsFilePath() {
17
+ return join(getClaudeConfigDir(), ".credentials.json");
18
+ }
19
+ function readCredentialsFile() {
20
+ const filePath = getCredentialsFilePath();
21
+ if (!existsSync(filePath)) return null;
22
+ try {
23
+ const raw = readFileSync(filePath, "utf-8");
24
+ return JSON.parse(raw);
25
+ } catch (e) {
26
+ log.warn({ err: e, path: filePath }, "Failed to parse Claude Code credentials file");
27
+ return null;
28
+ }
29
+ }
30
+ function readKeychainCredentials() {
31
+ const serviceNames = ["Claude Code-credentials", "Claude Code"];
32
+ for (const service of serviceNames) {
33
+ try {
34
+ const raw = execSync(`security find-generic-password -s "${service}" -w`, {
35
+ encoding: "utf-8",
36
+ stdio: ["pipe", "pipe", "pipe"]
37
+ }).trim();
38
+ return JSON.parse(raw);
39
+ } catch {
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ function readCredentials() {
45
+ if (process.platform === "darwin") {
46
+ const keychainCreds = readKeychainCredentials();
47
+ if (keychainCreds) return keychainCreds;
48
+ log.debug("Keychain read failed, falling back to credentials file");
49
+ }
50
+ return readCredentialsFile();
51
+ }
52
+ function extractToken(creds) {
53
+ const oauth = creds.claudeAiOauth;
54
+ if (!oauth?.accessToken) {
55
+ log.warn("Claude Code credentials found but missing accessToken");
56
+ return null;
57
+ }
58
+ return {
59
+ token: oauth.accessToken,
60
+ expiresAt: oauth.expiresAt ?? 0
61
+ };
62
+ }
63
+ function getClaudeCodeApiKey(fallbackKey) {
64
+ if (cachedToken && Date.now() < cachedExpiresAt) {
65
+ return cachedToken;
66
+ }
67
+ const creds = readCredentials();
68
+ if (creds) {
69
+ const extracted = extractToken(creds);
70
+ if (extracted) {
71
+ cachedToken = extracted.token;
72
+ cachedExpiresAt = extracted.expiresAt;
73
+ log.debug("Claude Code credentials loaded successfully");
74
+ return cachedToken;
75
+ }
76
+ }
77
+ if (fallbackKey && fallbackKey.length > 0) {
78
+ log.warn("Claude Code credentials not found, using fallback api_key from config");
79
+ return fallbackKey;
80
+ }
81
+ throw new Error("No Claude Code credentials found. Run 'claude login' or set api_key in config.");
82
+ }
83
+ function refreshClaudeCodeApiKey() {
84
+ cachedToken = null;
85
+ cachedExpiresAt = 0;
86
+ const creds = readCredentials();
87
+ if (creds) {
88
+ const extracted = extractToken(creds);
89
+ if (extracted) {
90
+ cachedToken = extracted.token;
91
+ cachedExpiresAt = extracted.expiresAt;
92
+ log.info("Claude Code credentials refreshed from disk");
93
+ return cachedToken;
94
+ }
95
+ }
96
+ log.warn("Failed to refresh Claude Code credentials from disk");
97
+ return null;
98
+ }
99
+ function isClaudeCodeTokenValid() {
100
+ return cachedToken !== null && Date.now() < cachedExpiresAt;
101
+ }
102
+
103
+ export {
104
+ getClaudeCodeApiKey,
105
+ refreshClaudeCodeApiKey,
106
+ isClaudeCodeTokenValid
107
+ };