teleton 0.1.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.
- package/README.md +395 -0
- package/bin/teleton.js +2 -0
- package/dist/chunk-7NJ46ZIX.js +74 -0
- package/dist/chunk-UR2LQEKR.js +319 -0
- package/dist/chunk-WDUHRPGA.js +1930 -0
- package/dist/chunk-WXVHT6CI.js +18938 -0
- package/dist/chunk-XBGUNXF2.js +176 -0
- package/dist/cli/index.js +1055 -0
- package/dist/get-my-gifts-YKUHPRGS.js +8 -0
- package/dist/index.js +12 -0
- package/dist/memory-O5NYYWF3.js +60 -0
- package/dist/migrate-25RH22HJ.js +59 -0
- package/dist/paths-STCOKEXS.js +14 -0
- package/dist/scraper-DW5Z2AP5.js +377 -0
- package/dist/task-dependency-resolver-5I62EU67.js +133 -0
- package/dist/task-executor-ZMXWLMI7.js +144 -0
- package/dist/tasks-NUFMZNV5.js +8 -0
- package/package.json +85 -0
- package/src/templates/BOOTSTRAP.md +48 -0
- package/src/templates/IDENTITY.md +33 -0
- package/src/templates/MEMORY.md +34 -0
- package/src/templates/SOUL.md +43 -0
- package/src/templates/USER.md +36 -0
|
@@ -0,0 +1,1055 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CasinoConfigSchema,
|
|
3
|
+
ConfigSchema,
|
|
4
|
+
DealsConfigSchema,
|
|
5
|
+
MarketConfigSchema,
|
|
6
|
+
configExists,
|
|
7
|
+
ensureWorkspace,
|
|
8
|
+
generateWallet,
|
|
9
|
+
getDefaultConfigPath,
|
|
10
|
+
getProviderMetadata,
|
|
11
|
+
getSupportedProviders,
|
|
12
|
+
isNewWorkspace,
|
|
13
|
+
main,
|
|
14
|
+
saveWallet,
|
|
15
|
+
validateApiKeyFormat
|
|
16
|
+
} from "../chunk-WXVHT6CI.js";
|
|
17
|
+
import "../chunk-XBGUNXF2.js";
|
|
18
|
+
import "../chunk-WDUHRPGA.js";
|
|
19
|
+
import "../chunk-UR2LQEKR.js";
|
|
20
|
+
import {
|
|
21
|
+
TELETON_ROOT
|
|
22
|
+
} from "../chunk-7NJ46ZIX.js";
|
|
23
|
+
|
|
24
|
+
// src/cli/index.ts
|
|
25
|
+
import { Command } from "commander";
|
|
26
|
+
|
|
27
|
+
// src/cli/prompts.ts
|
|
28
|
+
import * as clack from "@clack/prompts";
|
|
29
|
+
var ClackPrompter = class {
|
|
30
|
+
/**
|
|
31
|
+
* Display intro banner
|
|
32
|
+
*/
|
|
33
|
+
async intro(title) {
|
|
34
|
+
clack.intro(title);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Display outro message
|
|
38
|
+
*/
|
|
39
|
+
async outro(message) {
|
|
40
|
+
clack.outro(message);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Display note/info
|
|
44
|
+
*/
|
|
45
|
+
async note(message, title) {
|
|
46
|
+
clack.note(message, title);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Text input prompt
|
|
50
|
+
*/
|
|
51
|
+
async text(options) {
|
|
52
|
+
const result = await clack.text({
|
|
53
|
+
message: options.message,
|
|
54
|
+
placeholder: options.placeholder,
|
|
55
|
+
initialValue: options.initialValue,
|
|
56
|
+
validate: options.validate
|
|
57
|
+
});
|
|
58
|
+
if (clack.isCancel(result)) {
|
|
59
|
+
throw new CancelledError();
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Password input (hidden)
|
|
65
|
+
*/
|
|
66
|
+
async password(options) {
|
|
67
|
+
const result = await clack.password({
|
|
68
|
+
message: options.message,
|
|
69
|
+
validate: options.validate
|
|
70
|
+
});
|
|
71
|
+
if (clack.isCancel(result)) {
|
|
72
|
+
throw new CancelledError();
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Select prompt (single choice)
|
|
78
|
+
*/
|
|
79
|
+
async select(options) {
|
|
80
|
+
const result = await clack.select({
|
|
81
|
+
message: options.message,
|
|
82
|
+
options: options.options.map((opt) => {
|
|
83
|
+
const mapped = {
|
|
84
|
+
value: opt.value,
|
|
85
|
+
label: opt.label
|
|
86
|
+
};
|
|
87
|
+
if (opt.hint) {
|
|
88
|
+
mapped.hint = opt.hint;
|
|
89
|
+
}
|
|
90
|
+
return mapped;
|
|
91
|
+
}),
|
|
92
|
+
initialValue: options.initialValue
|
|
93
|
+
});
|
|
94
|
+
if (clack.isCancel(result)) {
|
|
95
|
+
throw new CancelledError();
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Confirm (yes/no)
|
|
101
|
+
*/
|
|
102
|
+
async confirm(options) {
|
|
103
|
+
const result = await clack.confirm({
|
|
104
|
+
message: options.message,
|
|
105
|
+
initialValue: options.initialValue ?? false
|
|
106
|
+
});
|
|
107
|
+
if (clack.isCancel(result)) {
|
|
108
|
+
throw new CancelledError();
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Multi-select prompt
|
|
114
|
+
*/
|
|
115
|
+
async multiselect(options) {
|
|
116
|
+
const result = await clack.multiselect({
|
|
117
|
+
message: options.message,
|
|
118
|
+
options: options.options.map((opt) => {
|
|
119
|
+
const mapped = {
|
|
120
|
+
value: opt.value,
|
|
121
|
+
label: opt.label
|
|
122
|
+
};
|
|
123
|
+
if (opt.hint) {
|
|
124
|
+
mapped.hint = opt.hint;
|
|
125
|
+
}
|
|
126
|
+
return mapped;
|
|
127
|
+
}),
|
|
128
|
+
required: options.required
|
|
129
|
+
});
|
|
130
|
+
if (clack.isCancel(result)) {
|
|
131
|
+
throw new CancelledError();
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Spinner for long operations
|
|
137
|
+
*/
|
|
138
|
+
spinner() {
|
|
139
|
+
const s = clack.spinner();
|
|
140
|
+
return {
|
|
141
|
+
start: (message) => s.start(message),
|
|
142
|
+
stop: (message) => s.stop(message),
|
|
143
|
+
message: (message) => s.message(message)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Log message
|
|
148
|
+
*/
|
|
149
|
+
log(message) {
|
|
150
|
+
clack.log.message(message);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Log warning
|
|
154
|
+
*/
|
|
155
|
+
warn(message) {
|
|
156
|
+
clack.log.warn(message);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Log error
|
|
160
|
+
*/
|
|
161
|
+
error(message) {
|
|
162
|
+
clack.log.error(message);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Log success
|
|
166
|
+
*/
|
|
167
|
+
success(message) {
|
|
168
|
+
clack.log.success(message);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
var CancelledError = class extends Error {
|
|
172
|
+
constructor() {
|
|
173
|
+
super("Operation cancelled by user");
|
|
174
|
+
this.name = "CancelledError";
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
function createPrompter() {
|
|
178
|
+
return new ClackPrompter();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/cli/commands/onboard.ts
|
|
182
|
+
import { writeFileSync } from "fs";
|
|
183
|
+
import { execSync } from "child_process";
|
|
184
|
+
import YAML from "yaml";
|
|
185
|
+
async function onboardCommand(options = {}) {
|
|
186
|
+
const prompter = createPrompter();
|
|
187
|
+
try {
|
|
188
|
+
if (options.nonInteractive) {
|
|
189
|
+
await runNonInteractiveOnboarding(options, prompter);
|
|
190
|
+
} else {
|
|
191
|
+
await runInteractiveOnboarding(options, prompter);
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (err instanceof CancelledError) {
|
|
195
|
+
prompter.outro("Onboarding cancelled");
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function runInteractiveOnboarding(options, prompter) {
|
|
202
|
+
const blue2 = "\x1B[34m";
|
|
203
|
+
const reset2 = "\x1B[0m";
|
|
204
|
+
console.log(`
|
|
205
|
+
${blue2} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
206
|
+
\u2502 \u2502
|
|
207
|
+
\u2502 ______________ ________________ _ __ ___ _____________ ________ \u2502
|
|
208
|
+
\u2502 /_ __/ ____/ / / ____/_ __/ __ \\/ | / / / | / ____/ ____/ | / /_ __/ \u2502
|
|
209
|
+
\u2502 / / / __/ / / / __/ / / / / / / |/ / / /| |/ / __/ __/ / |/ / / / \u2502
|
|
210
|
+
\u2502 / / / /___/ /___/ /___ / / / /_/ / /| / / ___ / /_/ / /___/ /| / / / \u2502
|
|
211
|
+
\u2502 /_/ /_____/_____/_____/ /_/ \\____/_/ |_/ /_/ |_\\____/_____/_/ |_/ /_/ \u2502
|
|
212
|
+
\u2502 \u2502
|
|
213
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SETUP \u2500\u2500\u2518${reset2}
|
|
214
|
+
|
|
215
|
+
Need help? Join @ResistanceForum on Telegram
|
|
216
|
+
`);
|
|
217
|
+
prompter.note(
|
|
218
|
+
"Your Teleton agent will have FULL CONTROL over:\n\n\u2022 TELEGRAM: Read, send, and delete messages on your behalf\n\u2022 TON WALLET: A new wallet will be generated that the agent\n can use to send transactions autonomously\n\nWe strongly recommend using a dedicated Telegram account.\nOnly fund the generated wallet with amounts you're comfortable\nletting the agent manage.",
|
|
219
|
+
"Security Warning"
|
|
220
|
+
);
|
|
221
|
+
const acceptRisk = await prompter.confirm({
|
|
222
|
+
message: "I understand the risks and want to continue",
|
|
223
|
+
initialValue: false
|
|
224
|
+
});
|
|
225
|
+
if (!acceptRisk) {
|
|
226
|
+
prompter.outro("Setup cancelled - you must accept the risks to continue");
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
const spinner2 = prompter.spinner();
|
|
230
|
+
spinner2.start("Creating workspace...");
|
|
231
|
+
const workspace = await ensureWorkspace({
|
|
232
|
+
workspaceDir: options.workspace,
|
|
233
|
+
ensureTemplates: true
|
|
234
|
+
});
|
|
235
|
+
const isNew = isNewWorkspace(workspace);
|
|
236
|
+
spinner2.stop(`\u2713 Workspace: ${workspace.root}`);
|
|
237
|
+
if (!isNew) {
|
|
238
|
+
prompter.warn("Existing configuration detected");
|
|
239
|
+
const shouldOverwrite = await prompter.confirm({
|
|
240
|
+
message: "Overwrite existing configuration?",
|
|
241
|
+
initialValue: false
|
|
242
|
+
});
|
|
243
|
+
if (!shouldOverwrite) {
|
|
244
|
+
prompter.outro("Setup cancelled - existing configuration preserved");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const flow = await prompter.select({
|
|
249
|
+
message: "Installation mode",
|
|
250
|
+
options: [
|
|
251
|
+
{ value: "quick", label: "QuickStart", hint: "Minimal configuration (recommended)" },
|
|
252
|
+
{ value: "advanced", label: "Advanced", hint: "Detailed configuration" }
|
|
253
|
+
],
|
|
254
|
+
initialValue: "quick"
|
|
255
|
+
});
|
|
256
|
+
const providers = getSupportedProviders();
|
|
257
|
+
const selectedProvider = await prompter.select({
|
|
258
|
+
message: "AI Provider",
|
|
259
|
+
options: providers.map((p) => ({
|
|
260
|
+
value: p.id,
|
|
261
|
+
label: p.displayName,
|
|
262
|
+
hint: p.toolLimit !== null ? `${p.defaultModel} (max ${p.toolLimit} tools)` : `${p.defaultModel}`
|
|
263
|
+
})),
|
|
264
|
+
initialValue: "anthropic"
|
|
265
|
+
});
|
|
266
|
+
const providerMeta = getProviderMetadata(selectedProvider);
|
|
267
|
+
if (providerMeta.toolLimit !== null) {
|
|
268
|
+
prompter.note(
|
|
269
|
+
`${providerMeta.displayName} supports max ${providerMeta.toolLimit} tools.
|
|
270
|
+
Tonnet currently has ~121 tools. If more tools are added,
|
|
271
|
+
some may be truncated.`,
|
|
272
|
+
"Tool Limit"
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
prompter.note(
|
|
276
|
+
"You need Telegram credentials from https://my.telegram.org/apps\nCreate an application and note the API ID and API Hash",
|
|
277
|
+
"Telegram"
|
|
278
|
+
);
|
|
279
|
+
const apiIdStr = options.apiId ? options.apiId.toString() : await prompter.text({
|
|
280
|
+
message: "API ID (from my.telegram.org)",
|
|
281
|
+
validate: (value) => {
|
|
282
|
+
if (!value || isNaN(parseInt(value))) return "Invalid API ID (must be a number)";
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
const apiId = parseInt(apiIdStr);
|
|
286
|
+
const apiHash = options.apiHash ? options.apiHash : await prompter.text({
|
|
287
|
+
message: "API Hash (from my.telegram.org)",
|
|
288
|
+
validate: (value) => {
|
|
289
|
+
if (!value || value.length < 10) return "Invalid API Hash";
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const phone = options.phone ? options.phone : await prompter.text({
|
|
293
|
+
message: "Phone number (international format, e.g. +1234567890)",
|
|
294
|
+
placeholder: "+1234567890",
|
|
295
|
+
validate: (value) => {
|
|
296
|
+
if (!value || !value.startsWith("+")) return "Invalid format (must start with +)";
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
prompter.note(
|
|
300
|
+
"To get your Telegram User ID:\n1. Open @userinfobot on Telegram\n2. Send /start\n3. Note the ID displayed",
|
|
301
|
+
"User ID"
|
|
302
|
+
);
|
|
303
|
+
const userIdStr = options.userId ? options.userId.toString() : await prompter.text({
|
|
304
|
+
message: "Your Telegram User ID (for admin rights)",
|
|
305
|
+
validate: (value) => {
|
|
306
|
+
if (!value || isNaN(parseInt(value))) return "Invalid User ID";
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const userId = parseInt(userIdStr);
|
|
310
|
+
prompter.note(
|
|
311
|
+
`${providerMeta.displayName} API key required.
|
|
312
|
+
Get it at: ${providerMeta.consoleUrl}`,
|
|
313
|
+
"API Key"
|
|
314
|
+
);
|
|
315
|
+
const apiKey = options.apiKey ? options.apiKey : await prompter.password({
|
|
316
|
+
message: `${providerMeta.displayName} API Key (${providerMeta.keyHint})`,
|
|
317
|
+
validate: (value) => validateApiKeyFormat(selectedProvider, value)
|
|
318
|
+
});
|
|
319
|
+
let selectedModel = providerMeta.defaultModel;
|
|
320
|
+
if (flow === "advanced") {
|
|
321
|
+
const customModel = await prompter.text({
|
|
322
|
+
message: `Model ID (default: ${providerMeta.defaultModel})`,
|
|
323
|
+
placeholder: providerMeta.defaultModel,
|
|
324
|
+
initialValue: providerMeta.defaultModel
|
|
325
|
+
});
|
|
326
|
+
if (customModel && customModel.trim()) {
|
|
327
|
+
selectedModel = customModel.trim();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
let dmPolicy = "open";
|
|
331
|
+
let groupPolicy = "open";
|
|
332
|
+
let requireMention = true;
|
|
333
|
+
if (flow === "advanced") {
|
|
334
|
+
dmPolicy = await prompter.select({
|
|
335
|
+
message: "DM policy (private messages)",
|
|
336
|
+
options: [
|
|
337
|
+
{ value: "open", label: "Open", hint: "Reply to everyone" },
|
|
338
|
+
{ value: "allowlist", label: "Allowlist", hint: "Only specific users" },
|
|
339
|
+
{ value: "disabled", label: "Disabled", hint: "No DM replies" }
|
|
340
|
+
],
|
|
341
|
+
initialValue: "open"
|
|
342
|
+
});
|
|
343
|
+
groupPolicy = await prompter.select({
|
|
344
|
+
message: "Group policy",
|
|
345
|
+
options: [
|
|
346
|
+
{ value: "open", label: "Open", hint: "Reply in all groups" },
|
|
347
|
+
{ value: "allowlist", label: "Allowlist", hint: "Only specific groups" },
|
|
348
|
+
{ value: "disabled", label: "Disabled", hint: "No group replies" }
|
|
349
|
+
],
|
|
350
|
+
initialValue: "open"
|
|
351
|
+
});
|
|
352
|
+
requireMention = await prompter.confirm({
|
|
353
|
+
message: "Require @mention in groups?",
|
|
354
|
+
initialValue: true
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
const config = {
|
|
358
|
+
meta: {
|
|
359
|
+
version: "1.0.0",
|
|
360
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
361
|
+
onboard_command: "teleton setup"
|
|
362
|
+
},
|
|
363
|
+
agent: {
|
|
364
|
+
provider: selectedProvider,
|
|
365
|
+
api_key: apiKey,
|
|
366
|
+
model: selectedModel,
|
|
367
|
+
max_tokens: 4096,
|
|
368
|
+
temperature: 0.7,
|
|
369
|
+
system_prompt: null,
|
|
370
|
+
max_agentic_iterations: 5,
|
|
371
|
+
session_reset_policy: {
|
|
372
|
+
daily_reset_enabled: true,
|
|
373
|
+
daily_reset_hour: 4,
|
|
374
|
+
idle_expiry_enabled: true,
|
|
375
|
+
idle_expiry_minutes: 1440
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
telegram: {
|
|
379
|
+
api_id: apiId,
|
|
380
|
+
api_hash: apiHash,
|
|
381
|
+
phone,
|
|
382
|
+
session_name: "tonnet_session",
|
|
383
|
+
session_path: workspace.sessionPath,
|
|
384
|
+
dm_policy: dmPolicy,
|
|
385
|
+
allow_from: [],
|
|
386
|
+
group_policy: groupPolicy,
|
|
387
|
+
group_allow_from: [],
|
|
388
|
+
require_mention: requireMention,
|
|
389
|
+
max_message_length: 4096,
|
|
390
|
+
typing_simulation: true,
|
|
391
|
+
rate_limit_messages_per_second: 1,
|
|
392
|
+
rate_limit_groups_per_minute: 20,
|
|
393
|
+
admin_ids: [userId],
|
|
394
|
+
agent_channel: null,
|
|
395
|
+
debounce_ms: 1500,
|
|
396
|
+
bot_token: "YOUR_BOT_TOKEN_FROM_BOTFATHER",
|
|
397
|
+
bot_username: "your_deals_bot"
|
|
398
|
+
},
|
|
399
|
+
storage: {
|
|
400
|
+
sessions_file: `${workspace.root}/sessions.json`,
|
|
401
|
+
pairing_file: `${workspace.root}/pairing.json`,
|
|
402
|
+
memory_file: `${workspace.root}/memory.json`,
|
|
403
|
+
history_limit: 100
|
|
404
|
+
},
|
|
405
|
+
casino: CasinoConfigSchema.parse({}),
|
|
406
|
+
deals: DealsConfigSchema.parse({}),
|
|
407
|
+
market: MarketConfigSchema.parse({})
|
|
408
|
+
};
|
|
409
|
+
spinner2.start("Saving configuration...");
|
|
410
|
+
const configYaml = YAML.stringify(config);
|
|
411
|
+
writeFileSync(workspace.configPath, configYaml, "utf-8");
|
|
412
|
+
spinner2.stop("\u2713 Configuration saved");
|
|
413
|
+
spinner2.start("Generating TON wallet...");
|
|
414
|
+
const wallet = await generateWallet();
|
|
415
|
+
saveWallet(wallet);
|
|
416
|
+
spinner2.stop("\u2713 TON wallet generated");
|
|
417
|
+
spinner2.start("Installing browser for market data...");
|
|
418
|
+
try {
|
|
419
|
+
execSync("npx playwright install chromium", {
|
|
420
|
+
stdio: "pipe",
|
|
421
|
+
timeout: 12e4
|
|
422
|
+
// 2 minutes timeout
|
|
423
|
+
});
|
|
424
|
+
spinner2.stop("\u2713 Browser installed");
|
|
425
|
+
} catch (err) {
|
|
426
|
+
spinner2.stop(
|
|
427
|
+
"\u26A0 Browser install failed (can be done later with: npx playwright install chromium)"
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
prompter.note(
|
|
431
|
+
"BACKUP REQUIRED - WRITE DOWN THESE 24 WORDS:\n\n" + wallet.mnemonic.join(" ") + "\n\nThese words allow you to recover your wallet.\nWithout them, you will lose access to your TON.\nWrite them on paper and keep them safe.",
|
|
432
|
+
"Mnemonic Seed (24 words)"
|
|
433
|
+
);
|
|
434
|
+
prompter.note(
|
|
435
|
+
`Workspace: ${workspace.root}
|
|
436
|
+
Config: ${workspace.configPath}
|
|
437
|
+
Templates: SOUL.md, MEMORY.md, IDENTITY.md, USER.md
|
|
438
|
+
Telegram: ${phone} (API ID: ${apiId})
|
|
439
|
+
Admin: User ID ${userId}
|
|
440
|
+
Provider: ${providerMeta.displayName}
|
|
441
|
+
Model: ${selectedModel}
|
|
442
|
+
TON Wallet: ${wallet.address}`,
|
|
443
|
+
"Setup complete"
|
|
444
|
+
);
|
|
445
|
+
prompter.note(
|
|
446
|
+
"Next steps:\n\n1. Start the agent:\n $ teleton start\n\n2. On first launch, you will be asked for:\n - Telegram verification code\n - 2FA password (if enabled)\n\n3. Send a message to your Telegram account to test",
|
|
447
|
+
"Ready"
|
|
448
|
+
);
|
|
449
|
+
prompter.outro("Good luck!");
|
|
450
|
+
}
|
|
451
|
+
async function runNonInteractiveOnboarding(options, prompter) {
|
|
452
|
+
if (!options.apiId || !options.apiHash || !options.phone || !options.apiKey || !options.userId) {
|
|
453
|
+
prompter.error(
|
|
454
|
+
"Non-interactive mode requires: --api-id, --api-hash, --phone, --api-key, --user-id"
|
|
455
|
+
);
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
const workspace = await ensureWorkspace({
|
|
459
|
+
workspaceDir: options.workspace,
|
|
460
|
+
ensureTemplates: true
|
|
461
|
+
});
|
|
462
|
+
const selectedProvider = options.provider || "anthropic";
|
|
463
|
+
const providerMeta = getProviderMetadata(selectedProvider);
|
|
464
|
+
const config = {
|
|
465
|
+
meta: {
|
|
466
|
+
version: "1.0.0",
|
|
467
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
468
|
+
onboard_command: "teleton setup"
|
|
469
|
+
},
|
|
470
|
+
agent: {
|
|
471
|
+
provider: selectedProvider,
|
|
472
|
+
api_key: options.apiKey,
|
|
473
|
+
model: providerMeta.defaultModel,
|
|
474
|
+
max_tokens: 4096,
|
|
475
|
+
temperature: 0.7,
|
|
476
|
+
system_prompt: null,
|
|
477
|
+
max_agentic_iterations: 5,
|
|
478
|
+
session_reset_policy: {
|
|
479
|
+
daily_reset_enabled: true,
|
|
480
|
+
daily_reset_hour: 4,
|
|
481
|
+
idle_expiry_enabled: true,
|
|
482
|
+
idle_expiry_minutes: 1440
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
telegram: {
|
|
486
|
+
api_id: options.apiId,
|
|
487
|
+
api_hash: options.apiHash,
|
|
488
|
+
phone: options.phone,
|
|
489
|
+
session_name: "tonnet_session",
|
|
490
|
+
session_path: workspace.sessionPath,
|
|
491
|
+
dm_policy: "open",
|
|
492
|
+
allow_from: [],
|
|
493
|
+
group_policy: "open",
|
|
494
|
+
group_allow_from: [],
|
|
495
|
+
require_mention: true,
|
|
496
|
+
max_message_length: 4096,
|
|
497
|
+
typing_simulation: true,
|
|
498
|
+
rate_limit_messages_per_second: 1,
|
|
499
|
+
rate_limit_groups_per_minute: 20,
|
|
500
|
+
admin_ids: [options.userId],
|
|
501
|
+
agent_channel: null,
|
|
502
|
+
debounce_ms: 1500,
|
|
503
|
+
bot_token: "YOUR_BOT_TOKEN_FROM_BOTFATHER",
|
|
504
|
+
bot_username: "your_deals_bot"
|
|
505
|
+
},
|
|
506
|
+
storage: {
|
|
507
|
+
sessions_file: `${workspace.root}/sessions.json`,
|
|
508
|
+
pairing_file: `${workspace.root}/pairing.json`,
|
|
509
|
+
memory_file: `${workspace.root}/memory.json`,
|
|
510
|
+
history_limit: 100
|
|
511
|
+
},
|
|
512
|
+
casino: CasinoConfigSchema.parse({}),
|
|
513
|
+
deals: DealsConfigSchema.parse({}),
|
|
514
|
+
market: MarketConfigSchema.parse({})
|
|
515
|
+
};
|
|
516
|
+
const configYaml = YAML.stringify(config);
|
|
517
|
+
writeFileSync(workspace.configPath, configYaml, "utf-8");
|
|
518
|
+
prompter.success(`\u2713 Configuration created: ${workspace.configPath}`);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/cli/commands/doctor.ts
|
|
522
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
523
|
+
import { join } from "path";
|
|
524
|
+
import { homedir } from "os";
|
|
525
|
+
import { parse } from "yaml";
|
|
526
|
+
var green = "\x1B[32m";
|
|
527
|
+
var yellow = "\x1B[33m";
|
|
528
|
+
var red = "\x1B[31m";
|
|
529
|
+
var reset = "\x1B[0m";
|
|
530
|
+
var blue = "\x1B[34m";
|
|
531
|
+
function formatResult(result) {
|
|
532
|
+
const icon = result.status === "ok" ? `${green}\u2713${reset}` : result.status === "warn" ? `${yellow}\u26A0${reset}` : `${red}\u2717${reset}`;
|
|
533
|
+
return `${icon} ${result.name}: ${result.message}`;
|
|
534
|
+
}
|
|
535
|
+
async function checkConfig(workspaceDir) {
|
|
536
|
+
const configPath = join(workspaceDir, "config.yaml");
|
|
537
|
+
if (!existsSync(configPath)) {
|
|
538
|
+
return {
|
|
539
|
+
name: "Config file",
|
|
540
|
+
status: "error",
|
|
541
|
+
message: `Not found at ${configPath}`
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
const content = readFileSync(configPath, "utf-8");
|
|
546
|
+
const raw = parse(content);
|
|
547
|
+
const result = ConfigSchema.safeParse(raw);
|
|
548
|
+
if (!result.success) {
|
|
549
|
+
return {
|
|
550
|
+
name: "Config file",
|
|
551
|
+
status: "error",
|
|
552
|
+
message: `Invalid: ${result.error.issues[0]?.message || "Unknown error"}`
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
name: "Config file",
|
|
557
|
+
status: "ok",
|
|
558
|
+
message: "Valid"
|
|
559
|
+
};
|
|
560
|
+
} catch (err) {
|
|
561
|
+
return {
|
|
562
|
+
name: "Config file",
|
|
563
|
+
status: "error",
|
|
564
|
+
message: `Parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async function checkTelegramCredentials(workspaceDir) {
|
|
569
|
+
const configPath = join(workspaceDir, "config.yaml");
|
|
570
|
+
if (!existsSync(configPath)) {
|
|
571
|
+
return {
|
|
572
|
+
name: "Telegram credentials",
|
|
573
|
+
status: "error",
|
|
574
|
+
message: "Config not found"
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
try {
|
|
578
|
+
const content = readFileSync(configPath, "utf-8");
|
|
579
|
+
const config = parse(content);
|
|
580
|
+
if (!config.telegram?.api_id || !config.telegram?.api_hash) {
|
|
581
|
+
return {
|
|
582
|
+
name: "Telegram credentials",
|
|
583
|
+
status: "error",
|
|
584
|
+
message: "Missing API ID or API Hash"
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
if (!config.telegram?.phone) {
|
|
588
|
+
return {
|
|
589
|
+
name: "Telegram credentials",
|
|
590
|
+
status: "error",
|
|
591
|
+
message: "Missing phone number"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
name: "Telegram credentials",
|
|
596
|
+
status: "ok",
|
|
597
|
+
message: `Phone: ${config.telegram.phone}`
|
|
598
|
+
};
|
|
599
|
+
} catch {
|
|
600
|
+
return {
|
|
601
|
+
name: "Telegram credentials",
|
|
602
|
+
status: "error",
|
|
603
|
+
message: "Could not read config"
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
async function checkApiKey(workspaceDir) {
|
|
608
|
+
const configPath = join(workspaceDir, "config.yaml");
|
|
609
|
+
if (!existsSync(configPath)) {
|
|
610
|
+
return {
|
|
611
|
+
name: "API key",
|
|
612
|
+
status: "error",
|
|
613
|
+
message: "Config not found"
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
const content = readFileSync(configPath, "utf-8");
|
|
618
|
+
const config = parse(content);
|
|
619
|
+
const provider = config.agent?.provider || "anthropic";
|
|
620
|
+
const apiKey = config.agent?.api_key;
|
|
621
|
+
let meta;
|
|
622
|
+
try {
|
|
623
|
+
meta = getProviderMetadata(provider);
|
|
624
|
+
} catch {
|
|
625
|
+
return {
|
|
626
|
+
name: "API key",
|
|
627
|
+
status: "error",
|
|
628
|
+
message: `Unknown provider: ${provider}`
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
if (!apiKey) {
|
|
632
|
+
return {
|
|
633
|
+
name: `${meta.displayName} API key`,
|
|
634
|
+
status: "error",
|
|
635
|
+
message: "Not configured"
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
const validationError = validateApiKeyFormat(provider, apiKey);
|
|
639
|
+
if (validationError) {
|
|
640
|
+
return {
|
|
641
|
+
name: `${meta.displayName} API key`,
|
|
642
|
+
status: "warn",
|
|
643
|
+
message: validationError
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
const maskLen = Math.min(10, apiKey.length - 4);
|
|
647
|
+
const masked = apiKey.substring(0, maskLen) + "..." + apiKey.substring(apiKey.length - 4);
|
|
648
|
+
return {
|
|
649
|
+
name: `${meta.displayName} API key`,
|
|
650
|
+
status: "ok",
|
|
651
|
+
message: masked
|
|
652
|
+
};
|
|
653
|
+
} catch {
|
|
654
|
+
return {
|
|
655
|
+
name: "API key",
|
|
656
|
+
status: "error",
|
|
657
|
+
message: "Could not read config"
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async function checkWallet(workspaceDir) {
|
|
662
|
+
const walletPath = join(workspaceDir, "wallet.json");
|
|
663
|
+
if (!existsSync(walletPath)) {
|
|
664
|
+
return {
|
|
665
|
+
name: "TON wallet",
|
|
666
|
+
status: "warn",
|
|
667
|
+
message: "Not found (run teleton setup to generate)"
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
const content = readFileSync(walletPath, "utf-8");
|
|
672
|
+
const wallet = JSON.parse(content);
|
|
673
|
+
if (!wallet.address) {
|
|
674
|
+
return {
|
|
675
|
+
name: "TON wallet",
|
|
676
|
+
status: "error",
|
|
677
|
+
message: "Invalid wallet file (no address)"
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
const shortAddr = wallet.address.substring(0, 8) + "..." + wallet.address.substring(wallet.address.length - 6);
|
|
681
|
+
return {
|
|
682
|
+
name: "TON wallet",
|
|
683
|
+
status: "ok",
|
|
684
|
+
message: shortAddr
|
|
685
|
+
};
|
|
686
|
+
} catch {
|
|
687
|
+
return {
|
|
688
|
+
name: "TON wallet",
|
|
689
|
+
status: "error",
|
|
690
|
+
message: "Could not read wallet file"
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
async function checkSoul(workspaceDir) {
|
|
695
|
+
const soulPath = join(workspaceDir, "SOUL.md");
|
|
696
|
+
if (!existsSync(soulPath)) {
|
|
697
|
+
return {
|
|
698
|
+
name: "SOUL.md",
|
|
699
|
+
status: "warn",
|
|
700
|
+
message: "Not found (agent will use defaults)"
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
try {
|
|
704
|
+
const stats = statSync(soulPath);
|
|
705
|
+
const sizeKb = (stats.size / 1024).toFixed(1);
|
|
706
|
+
return {
|
|
707
|
+
name: "SOUL.md",
|
|
708
|
+
status: "ok",
|
|
709
|
+
message: `${sizeKb} KB`
|
|
710
|
+
};
|
|
711
|
+
} catch {
|
|
712
|
+
return {
|
|
713
|
+
name: "SOUL.md",
|
|
714
|
+
status: "error",
|
|
715
|
+
message: "Could not read file"
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async function checkDatabase(workspaceDir) {
|
|
720
|
+
const dbPath = join(workspaceDir, "memory.db");
|
|
721
|
+
if (!existsSync(dbPath)) {
|
|
722
|
+
return {
|
|
723
|
+
name: "Memory database",
|
|
724
|
+
status: "warn",
|
|
725
|
+
message: "Not found (will be created on first start)"
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
const stats = statSync(dbPath);
|
|
730
|
+
const sizeMb = (stats.size / 1024 / 1024).toFixed(2);
|
|
731
|
+
return {
|
|
732
|
+
name: "Memory database",
|
|
733
|
+
status: "ok",
|
|
734
|
+
message: `${sizeMb} MB`
|
|
735
|
+
};
|
|
736
|
+
} catch {
|
|
737
|
+
return {
|
|
738
|
+
name: "Memory database",
|
|
739
|
+
status: "error",
|
|
740
|
+
message: "Could not read database"
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
async function checkTelegramSession(workspaceDir) {
|
|
745
|
+
const sessionPath = join(workspaceDir, "telegram_session.txt");
|
|
746
|
+
if (!existsSync(sessionPath)) {
|
|
747
|
+
return {
|
|
748
|
+
name: "Telegram session",
|
|
749
|
+
status: "warn",
|
|
750
|
+
message: "Not found (will prompt for login on first start)"
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
try {
|
|
754
|
+
const stats = statSync(sessionPath);
|
|
755
|
+
const age = Date.now() - stats.mtimeMs;
|
|
756
|
+
const daysAgo = Math.floor(age / (1e3 * 60 * 60 * 24));
|
|
757
|
+
if (daysAgo > 30) {
|
|
758
|
+
return {
|
|
759
|
+
name: "Telegram session",
|
|
760
|
+
status: "warn",
|
|
761
|
+
message: `Last updated ${daysAgo} days ago (may need re-auth)`
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
name: "Telegram session",
|
|
766
|
+
status: "ok",
|
|
767
|
+
message: daysAgo === 0 ? "Active (today)" : `Active (${daysAgo} days ago)`
|
|
768
|
+
};
|
|
769
|
+
} catch {
|
|
770
|
+
return {
|
|
771
|
+
name: "Telegram session",
|
|
772
|
+
status: "error",
|
|
773
|
+
message: "Could not read session"
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
async function checkMarketData(workspaceDir) {
|
|
778
|
+
const dbPath = join(workspaceDir, "gifts.db");
|
|
779
|
+
if (!existsSync(dbPath)) {
|
|
780
|
+
return {
|
|
781
|
+
name: "Gift market data",
|
|
782
|
+
status: "warn",
|
|
783
|
+
message: "Not found (will fetch on first start)"
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
try {
|
|
787
|
+
const Database = (await import("better-sqlite3")).default;
|
|
788
|
+
const db = new Database(dbPath, { readonly: true });
|
|
789
|
+
const collections = db.prepare("SELECT COUNT(*) as count FROM gift_collections").get();
|
|
790
|
+
const models = db.prepare("SELECT COUNT(*) as count FROM gift_models").get();
|
|
791
|
+
const lastUpdate = db.prepare("SELECT MAX(updated_at) as last FROM gift_collections").get();
|
|
792
|
+
db.close();
|
|
793
|
+
if (!lastUpdate.last) {
|
|
794
|
+
return {
|
|
795
|
+
name: "Gift market data",
|
|
796
|
+
status: "warn",
|
|
797
|
+
message: "Database empty (no data yet)"
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
const lastUpdateTime = (/* @__PURE__ */ new Date(lastUpdate.last + "Z")).getTime();
|
|
801
|
+
const age = Date.now() - lastUpdateTime;
|
|
802
|
+
const hoursAgo = Math.floor(age / (1e3 * 60 * 60));
|
|
803
|
+
const daysAgo = Math.floor(hoursAgo / 24);
|
|
804
|
+
const dataInfo = `${collections.count} collections, ${models.count} models`;
|
|
805
|
+
if (daysAgo > 7) {
|
|
806
|
+
return {
|
|
807
|
+
name: "Gift market data",
|
|
808
|
+
status: "warn",
|
|
809
|
+
message: `Stale (${daysAgo} days old) - ${dataInfo}`
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
if (hoursAgo > 24) {
|
|
813
|
+
return {
|
|
814
|
+
name: "Gift market data",
|
|
815
|
+
status: "ok",
|
|
816
|
+
message: `${daysAgo} day${daysAgo > 1 ? "s" : ""} old - ${dataInfo}`
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
return {
|
|
820
|
+
name: "Gift market data",
|
|
821
|
+
status: "ok",
|
|
822
|
+
message: hoursAgo === 0 ? `Fresh (< 1h) - ${dataInfo}` : `${hoursAgo}h old - ${dataInfo}`
|
|
823
|
+
};
|
|
824
|
+
} catch (err) {
|
|
825
|
+
return {
|
|
826
|
+
name: "Gift market data",
|
|
827
|
+
status: "error",
|
|
828
|
+
message: `Database error: ${err instanceof Error ? err.message : String(err)}`
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async function checkModel(workspaceDir) {
|
|
833
|
+
const configPath = join(workspaceDir, "config.yaml");
|
|
834
|
+
if (!existsSync(configPath)) {
|
|
835
|
+
return {
|
|
836
|
+
name: "AI Model",
|
|
837
|
+
status: "error",
|
|
838
|
+
message: "Config not found"
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
try {
|
|
842
|
+
const content = readFileSync(configPath, "utf-8");
|
|
843
|
+
const config = parse(content);
|
|
844
|
+
const provider = config.agent?.provider || "anthropic";
|
|
845
|
+
let model = config.agent?.model;
|
|
846
|
+
if (!model) {
|
|
847
|
+
try {
|
|
848
|
+
model = getProviderMetadata(provider).defaultModel;
|
|
849
|
+
} catch {
|
|
850
|
+
model = "unknown";
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
name: "AI Model",
|
|
855
|
+
status: "ok",
|
|
856
|
+
message: `${provider}/${model}`
|
|
857
|
+
};
|
|
858
|
+
} catch {
|
|
859
|
+
return {
|
|
860
|
+
name: "AI Model",
|
|
861
|
+
status: "error",
|
|
862
|
+
message: "Could not read config"
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
async function checkAdmins(workspaceDir) {
|
|
867
|
+
const configPath = join(workspaceDir, "config.yaml");
|
|
868
|
+
if (!existsSync(configPath)) {
|
|
869
|
+
return {
|
|
870
|
+
name: "Admin users",
|
|
871
|
+
status: "error",
|
|
872
|
+
message: "Config not found"
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
try {
|
|
876
|
+
const content = readFileSync(configPath, "utf-8");
|
|
877
|
+
const config = parse(content);
|
|
878
|
+
const admins = config.telegram?.admin_ids || [];
|
|
879
|
+
if (admins.length === 0) {
|
|
880
|
+
return {
|
|
881
|
+
name: "Admin users",
|
|
882
|
+
status: "warn",
|
|
883
|
+
message: "None configured (no admin commands available)"
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
return {
|
|
887
|
+
name: "Admin users",
|
|
888
|
+
status: "ok",
|
|
889
|
+
message: `${admins.length} user${admins.length > 1 ? "s" : ""}: ${admins.join(", ")}`
|
|
890
|
+
};
|
|
891
|
+
} catch {
|
|
892
|
+
return {
|
|
893
|
+
name: "Admin users",
|
|
894
|
+
status: "error",
|
|
895
|
+
message: "Could not read config"
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
async function checkNodeVersion() {
|
|
900
|
+
const version = process.version;
|
|
901
|
+
const major = parseInt(version.slice(1).split(".")[0]);
|
|
902
|
+
if (major < 20) {
|
|
903
|
+
return {
|
|
904
|
+
name: "Node.js",
|
|
905
|
+
status: "error",
|
|
906
|
+
message: `${version} (requires >= 20.0.0)`
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
name: "Node.js",
|
|
911
|
+
status: "ok",
|
|
912
|
+
message: version
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
async function checkPlaywrightBrowser() {
|
|
916
|
+
const homeDir = homedir();
|
|
917
|
+
const browserPaths = [
|
|
918
|
+
join(homeDir, ".cache", "ms-playwright", "chromium-*"),
|
|
919
|
+
join(homeDir, ".cache", "ms-playwright"),
|
|
920
|
+
join(homeDir, "Library", "Caches", "ms-playwright"),
|
|
921
|
+
join(homeDir, "AppData", "Local", "ms-playwright")
|
|
922
|
+
];
|
|
923
|
+
for (const basePath of browserPaths) {
|
|
924
|
+
const checkPath = basePath.replace("/chromium-*", "");
|
|
925
|
+
if (existsSync(checkPath)) {
|
|
926
|
+
try {
|
|
927
|
+
const { readdirSync } = await import("fs");
|
|
928
|
+
const contents = readdirSync(checkPath);
|
|
929
|
+
const hasChromium = contents.some((f) => f.startsWith("chromium"));
|
|
930
|
+
if (hasChromium) {
|
|
931
|
+
return {
|
|
932
|
+
name: "Playwright browser",
|
|
933
|
+
status: "ok",
|
|
934
|
+
message: "Chromium installed"
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
} catch {
|
|
938
|
+
return {
|
|
939
|
+
name: "Playwright browser",
|
|
940
|
+
status: "ok",
|
|
941
|
+
message: "Cache found"
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
name: "Playwright browser",
|
|
948
|
+
status: "warn",
|
|
949
|
+
message: "Not found (run: npx playwright install chromium)"
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
async function doctorCommand() {
|
|
953
|
+
const workspaceDir = TELETON_ROOT;
|
|
954
|
+
console.log(`
|
|
955
|
+
${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
956
|
+
\u2502 TELETON DOCTOR - System Health Check \u2502
|
|
957
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${reset}
|
|
958
|
+
`);
|
|
959
|
+
console.log(` Workspace: ${workspaceDir}
|
|
960
|
+
`);
|
|
961
|
+
const results = [];
|
|
962
|
+
console.log(" Running checks...\n");
|
|
963
|
+
results.push(await checkNodeVersion());
|
|
964
|
+
results.push(await checkPlaywrightBrowser());
|
|
965
|
+
results.push(await checkConfig(workspaceDir));
|
|
966
|
+
results.push(await checkTelegramCredentials(workspaceDir));
|
|
967
|
+
results.push(await checkApiKey(workspaceDir));
|
|
968
|
+
results.push(await checkTelegramSession(workspaceDir));
|
|
969
|
+
results.push(await checkWallet(workspaceDir));
|
|
970
|
+
results.push(await checkSoul(workspaceDir));
|
|
971
|
+
results.push(await checkDatabase(workspaceDir));
|
|
972
|
+
results.push(await checkMarketData(workspaceDir));
|
|
973
|
+
results.push(await checkModel(workspaceDir));
|
|
974
|
+
results.push(await checkAdmins(workspaceDir));
|
|
975
|
+
for (const result of results) {
|
|
976
|
+
console.log(` ${formatResult(result)}`);
|
|
977
|
+
}
|
|
978
|
+
const errors = results.filter((r) => r.status === "error").length;
|
|
979
|
+
const warnings = results.filter((r) => r.status === "warn").length;
|
|
980
|
+
const ok = results.filter((r) => r.status === "ok").length;
|
|
981
|
+
console.log("");
|
|
982
|
+
if (errors > 0) {
|
|
983
|
+
console.log(
|
|
984
|
+
`${red} \u2717 ${errors} error${errors > 1 ? "s" : ""} found - run 'teleton setup' to fix${reset}`
|
|
985
|
+
);
|
|
986
|
+
} else if (warnings > 0) {
|
|
987
|
+
console.log(
|
|
988
|
+
`${yellow} \u26A0 ${warnings} warning${warnings > 1 ? "s" : ""} - agent may work with limited features${reset}`
|
|
989
|
+
);
|
|
990
|
+
} else {
|
|
991
|
+
console.log(`${green} \u2713 All ${ok} checks passed - system ready${reset}`);
|
|
992
|
+
}
|
|
993
|
+
console.log("");
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// src/cli/index.ts
|
|
997
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
998
|
+
import { dirname, join as join2 } from "path";
|
|
999
|
+
import { fileURLToPath } from "url";
|
|
1000
|
+
function findPackageJson() {
|
|
1001
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
1002
|
+
for (let i = 0; i < 10; i++) {
|
|
1003
|
+
const candidate = join2(dir, "package.json");
|
|
1004
|
+
if (existsSync2(candidate)) {
|
|
1005
|
+
return JSON.parse(readFileSync2(candidate, "utf-8"));
|
|
1006
|
+
}
|
|
1007
|
+
dir = dirname(dir);
|
|
1008
|
+
}
|
|
1009
|
+
return { version: "0.0.0" };
|
|
1010
|
+
}
|
|
1011
|
+
var packageJson = findPackageJson();
|
|
1012
|
+
var program = new Command();
|
|
1013
|
+
program.name("teleton").description("Teleton Agent - Personal AI Agent for Telegram").version(packageJson.version);
|
|
1014
|
+
program.command("setup").description("Interactive wizard to set up Teleton").option("--workspace <dir>", "Workspace directory (default: ~/.teleton)").option("--non-interactive", "Non-interactive mode (requires all options)").option("--api-id <id>", "Telegram API ID").option("--api-hash <hash>", "Telegram API Hash").option("--phone <number>", "Phone number (international format)").option("--api-key <key>", "Anthropic API key").option("--user-id <id>", "Your Telegram User ID (for admin)").action(async (options) => {
|
|
1015
|
+
try {
|
|
1016
|
+
await onboardCommand({
|
|
1017
|
+
workspace: options.workspace,
|
|
1018
|
+
nonInteractive: options.nonInteractive,
|
|
1019
|
+
apiId: options.apiId ? parseInt(options.apiId) : void 0,
|
|
1020
|
+
apiHash: options.apiHash,
|
|
1021
|
+
phone: options.phone,
|
|
1022
|
+
apiKey: options.apiKey,
|
|
1023
|
+
userId: options.userId ? parseInt(options.userId) : void 0
|
|
1024
|
+
});
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
console.error("Erreur:", error instanceof Error ? error.message : String(error));
|
|
1027
|
+
process.exit(1);
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
program.command("start").description("Start the Teleton agent").option("-c, --config <path>", "Config file path", getDefaultConfigPath()).action(async (options) => {
|
|
1031
|
+
try {
|
|
1032
|
+
if (!configExists(options.config)) {
|
|
1033
|
+
console.error("\u274C Configuration non trouv\xE9e");
|
|
1034
|
+
console.error(` Fichier attendu: ${options.config}`);
|
|
1035
|
+
console.error("\n\u{1F4A1} Lance d'abord: teleton setup");
|
|
1036
|
+
process.exit(1);
|
|
1037
|
+
}
|
|
1038
|
+
await main(options.config);
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
console.error("Erreur:", error instanceof Error ? error.message : String(error));
|
|
1041
|
+
process.exit(1);
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
program.command("doctor").description("Run system health checks").action(async () => {
|
|
1045
|
+
try {
|
|
1046
|
+
await doctorCommand();
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
1049
|
+
process.exit(1);
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
program.action(() => {
|
|
1053
|
+
program.help();
|
|
1054
|
+
});
|
|
1055
|
+
program.parse(process.argv);
|