tibiaway-ai 1.0.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 +284 -0
- package/agents/tibiaway.md +64 -0
- package/bin/tibiaway.js +11 -0
- package/commands/analyze.md +23 -0
- package/commands/boss.md +20 -0
- package/commands/diary.md +21 -0
- package/commands/hunt.md +22 -0
- package/commands/profit.md +22 -0
- package/commands/quest.md +23 -0
- package/commands/set.md +30 -0
- package/package.json +50 -0
- package/src/commands/analyze.js +141 -0
- package/src/commands/boss.js +85 -0
- package/src/commands/diary.js +143 -0
- package/src/commands/hunt.js +86 -0
- package/src/commands/profit.js +84 -0
- package/src/commands/quest.js +80 -0
- package/src/commands/set.js +94 -0
- package/src/commands/sync.js +14 -0
- package/src/installer.js +78 -0
- package/src/standalone.js +129 -0
- package/src/tibia-api.js +55 -0
- package/src/utils/api.js +109 -0
- package/src/utils/banner.js +72 -0
- package/src/utils/character.js +77 -0
- package/src/utils/config.js +84 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter, addDiaryEntry } from '../utils/config.js';
|
|
5
|
+
import { askClaude, askClaudeWithImage } from '../utils/api.js';
|
|
6
|
+
import { error, success, highlight, separator, info } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp'];
|
|
9
|
+
const TEXT_EXTENSIONS = ['txt', 'md', 'log'];
|
|
10
|
+
|
|
11
|
+
export async function handleAnalyze(filePath) {
|
|
12
|
+
const character = getCharacter();
|
|
13
|
+
if (!character) {
|
|
14
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(chalk.hex('#FF6B1A').bold('🔍 ANALYZER\n'));
|
|
19
|
+
|
|
20
|
+
if (!filePath) {
|
|
21
|
+
error('Debes especificar un archivo. Ejemplo: tibiaway analyze ./screenshot.png');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!existsSync(filePath)) {
|
|
26
|
+
error(`Archivo no encontrado: ${filePath}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const ext = filePath.split('.').pop().toLowerCase();
|
|
31
|
+
|
|
32
|
+
if (IMAGE_EXTENSIONS.includes(ext)) {
|
|
33
|
+
await analyzeImage(filePath, character);
|
|
34
|
+
} else if (TEXT_EXTENSIONS.includes(ext)) {
|
|
35
|
+
await analyzeText(filePath, character);
|
|
36
|
+
} else {
|
|
37
|
+
error(`Formato no soportado: .${ext}. Usa: ${[...IMAGE_EXTENSIONS, ...TEXT_EXTENSIONS].join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function analyzeImage(filePath, character) {
|
|
42
|
+
info(`Analizando imagen: ${filePath}`);
|
|
43
|
+
console.log('');
|
|
44
|
+
|
|
45
|
+
const prompt = `Analiza esta captura de pantalla del juego Tibia.
|
|
46
|
+
|
|
47
|
+
Identifica qué tipo de screenshot es:
|
|
48
|
+
- Si muestra loot (ítems del suelo o contenedor): lista todos los ítems visibles y estima el valor total en gold
|
|
49
|
+
- Si muestra experiencia ganada / progress bar: extrae la exp ganada y estima exp/hora
|
|
50
|
+
- Si muestra el client con criaturas o hunting: analiza la situación y da tips
|
|
51
|
+
- Si muestra estadísticas, skills, o equipamiento: analiza y da recomendaciones
|
|
52
|
+
- Si muestra chat o mensajes: analiza el contexto y da sugerencias
|
|
53
|
+
- Si es otra cosa: describe qué ves y da insights relevantes
|
|
54
|
+
|
|
55
|
+
Para mi perfil de personaje, indica si lo que se ve es bueno, mejorable, o si hay algo importante que deba saber.
|
|
56
|
+
|
|
57
|
+
Al final, genera una nota resumida (1-2 líneas) para registrar en mi diario.
|
|
58
|
+
Termina la respuesta con la línea exacta:
|
|
59
|
+
NOTA_DIARIO: [la nota breve aquí]`;
|
|
60
|
+
|
|
61
|
+
const spinner = ora({ text: 'Analizando screenshot con visión IA...', color: 'yellow' }).start();
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const response = await askClaudeWithImage(prompt, filePath);
|
|
65
|
+
spinner.stop();
|
|
66
|
+
separator();
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
69
|
+
console.log('');
|
|
70
|
+
separator();
|
|
71
|
+
|
|
72
|
+
const noteMatch = response.match(/NOTA_DIARIO:\s*(.+)/);
|
|
73
|
+
if (noteMatch) {
|
|
74
|
+
addDiaryEntry({
|
|
75
|
+
location: 'Análisis de screenshot',
|
|
76
|
+
note: noteMatch[1].trim(),
|
|
77
|
+
level: character.level,
|
|
78
|
+
});
|
|
79
|
+
success('Análisis guardado en el diario.');
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
spinner.stop();
|
|
83
|
+
error(`Error al analizar la imagen: ${err.message}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function analyzeText(filePath, character) {
|
|
88
|
+
info(`Analizando archivo de texto: ${filePath}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
|
|
91
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
92
|
+
|
|
93
|
+
if (content.trim().length === 0) {
|
|
94
|
+
error('El archivo está vacío.');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const prompt = `Analiza las siguientes notas de hunt / sesión de Tibia:
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
${content.slice(0, 4000)}
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
Extrae y analiza:
|
|
105
|
+
1. Qué tipo de información contienen estas notas
|
|
106
|
+
2. Métricas clave (si hay): exp, gold, loot, tiempo, supplies
|
|
107
|
+
3. Insights principales sobre la sesión
|
|
108
|
+
4. ¿Qué se puede mejorar?
|
|
109
|
+
5. Recomendaciones basadas en lo que se ve
|
|
110
|
+
|
|
111
|
+
Para mi perfil, indica si la sesión fue buena y qué cambios aplicarías.
|
|
112
|
+
|
|
113
|
+
Al final genera una nota resumida (1-2 líneas) para el diario.
|
|
114
|
+
Termina con la línea exacta:
|
|
115
|
+
NOTA_DIARIO: [la nota breve aquí]`;
|
|
116
|
+
|
|
117
|
+
const spinner = ora({ text: 'Analizando notas...', color: 'yellow' }).start();
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const response = await askClaude(prompt);
|
|
121
|
+
spinner.stop();
|
|
122
|
+
separator();
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
125
|
+
console.log('');
|
|
126
|
+
separator();
|
|
127
|
+
|
|
128
|
+
const noteMatch = response.match(/NOTA_DIARIO:\s*(.+)/);
|
|
129
|
+
if (noteMatch) {
|
|
130
|
+
addDiaryEntry({
|
|
131
|
+
location: 'Análisis de notas',
|
|
132
|
+
note: noteMatch[1].trim(),
|
|
133
|
+
level: character.level,
|
|
134
|
+
});
|
|
135
|
+
success('Análisis guardado en el diario.');
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
spinner.stop();
|
|
139
|
+
error(`Error al analizar el archivo: ${err.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter } from '../utils/config.js';
|
|
5
|
+
import { askClaude } from '../utils/api.js';
|
|
6
|
+
import { error, highlight, separator } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
export async function handleBoss(bossName) {
|
|
9
|
+
const character = getCharacter();
|
|
10
|
+
if (!character) {
|
|
11
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(chalk.hex('#FF6B1A').bold('💀 BOSS ADVISOR\n'));
|
|
16
|
+
|
|
17
|
+
let targetBoss = bossName;
|
|
18
|
+
|
|
19
|
+
if (!targetBoss) {
|
|
20
|
+
const answer = await inquirer.prompt([
|
|
21
|
+
{
|
|
22
|
+
type: 'input',
|
|
23
|
+
name: 'boss',
|
|
24
|
+
message: highlight('¿Qué boss quieres enfrentar?'),
|
|
25
|
+
validate: (i) => i.trim().length > 0 || 'Ingresa el nombre del boss.',
|
|
26
|
+
},
|
|
27
|
+
]);
|
|
28
|
+
targetBoss = answer.boss.trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const prompt = `Explícame todo sobre el boss: ${targetBoss}
|
|
32
|
+
|
|
33
|
+
Dame información completa y detallada:
|
|
34
|
+
|
|
35
|
+
1. DESCRIPCIÓN GENERAL
|
|
36
|
+
- Qué es, dónde está, historia/lore relevante
|
|
37
|
+
- Cuándo aparece / cómo se invoca / periodicidad
|
|
38
|
+
|
|
39
|
+
2. ESTADÍSTICAS CLAVE
|
|
40
|
+
- HP aproximado
|
|
41
|
+
- Debilidades elementales y resistencias
|
|
42
|
+
- Inmunidades importantes
|
|
43
|
+
|
|
44
|
+
3. MECÁNICAS PRINCIPALES
|
|
45
|
+
- Ataques que usa y daño aproximado
|
|
46
|
+
- Mecánicas especiales (summons, fases, habilidades únicas)
|
|
47
|
+
- Comportamientos que hay que conocer sí o sí
|
|
48
|
+
|
|
49
|
+
4. FASES (si aplica)
|
|
50
|
+
- Descripción de cada fase y cambios de comportamiento
|
|
51
|
+
|
|
52
|
+
5. PREPARACIÓN RECOMENDADA PARA MI PERSONAJE
|
|
53
|
+
- Set óptimo e imbuements
|
|
54
|
+
- Supplies necesarios (con cantidades estimadas)
|
|
55
|
+
- Level mínimo recomendado para mi vocación
|
|
56
|
+
|
|
57
|
+
6. ESTRATEGIA POR VOCACIÓN
|
|
58
|
+
- Cómo lo enfrento siendo ${character.vocation}
|
|
59
|
+
- Posicionamiento, skills a usar, rotación
|
|
60
|
+
|
|
61
|
+
7. LOOT DESTACADO
|
|
62
|
+
- Items más valiosos o interesantes del drop
|
|
63
|
+
|
|
64
|
+
8. ERRORES COMUNES Y TIPS
|
|
65
|
+
- Qué NO hacer
|
|
66
|
+
- Trucos que no son obvios
|
|
67
|
+
|
|
68
|
+
Sé específico. Si el boss tiene mecánicas que matan instant, mencionarlo claramente.`;
|
|
69
|
+
|
|
70
|
+
console.log(chalk.hex('#888888')(`Analizando: ${targetBoss}\n`));
|
|
71
|
+
const spinner = ora({ text: 'Consultando el libro de los bosses...', color: 'yellow' }).start();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const response = await askClaude(prompt);
|
|
75
|
+
spinner.stop();
|
|
76
|
+
separator();
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
79
|
+
console.log('');
|
|
80
|
+
separator();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
spinner.stop();
|
|
83
|
+
error(`Error al consultar la IA: ${err.message}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter, addDiaryEntry, getDiary } from '../utils/config.js';
|
|
5
|
+
import { askClaude } from '../utils/api.js';
|
|
6
|
+
import { error, success, highlight, separator, info, gold, dim } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
export async function handleDiary(subcommand) {
|
|
9
|
+
const character = getCharacter();
|
|
10
|
+
if (!character) {
|
|
11
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(chalk.hex('#FF6B1A').bold('📖 DIARIO DE PROGRESO\n'));
|
|
16
|
+
|
|
17
|
+
const cmd = subcommand || await promptSubcommand();
|
|
18
|
+
|
|
19
|
+
if (cmd === 'add') {
|
|
20
|
+
await addEntry(character);
|
|
21
|
+
} else if (cmd === 'show') {
|
|
22
|
+
await showEntries();
|
|
23
|
+
} else if (cmd === 'summary') {
|
|
24
|
+
await generateSummary(character);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function promptSubcommand() {
|
|
29
|
+
const { sub } = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'list',
|
|
32
|
+
name: 'sub',
|
|
33
|
+
message: highlight('¿Qué quieres hacer?'),
|
|
34
|
+
choices: [
|
|
35
|
+
{ name: 'Agregar nueva entrada', value: 'add' },
|
|
36
|
+
{ name: 'Ver historial', value: 'show' },
|
|
37
|
+
{ name: 'Resumen de progreso con IA', value: 'summary' },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
return sub;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function addEntry(character) {
|
|
45
|
+
const answers = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: 'input',
|
|
48
|
+
name: 'location',
|
|
49
|
+
message: highlight('¿Dónde cazaste / qué hiciste hoy?'),
|
|
50
|
+
validate: (i) => i.trim().length > 0 || 'Ingresa una ubicación o actividad.',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'input',
|
|
54
|
+
name: 'note',
|
|
55
|
+
message: highlight('Nota del día (logros, observaciones, etc.):'),
|
|
56
|
+
validate: (i) => i.trim().length > 0 || 'Escribe algo en la nota.',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'input',
|
|
60
|
+
name: 'level',
|
|
61
|
+
message: highlight(`¿En qué level estás? (actual: ${character.level})`),
|
|
62
|
+
default: String(character.level),
|
|
63
|
+
validate: (i) => !isNaN(parseInt(i)) || 'Ingresa un número.',
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
addDiaryEntry({
|
|
68
|
+
location: answers.location.trim(),
|
|
69
|
+
note: answers.note.trim(),
|
|
70
|
+
level: parseInt(answers.level),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
success('Entrada añadida al diario.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function showEntries() {
|
|
77
|
+
const entries = getDiary();
|
|
78
|
+
|
|
79
|
+
if (entries.length === 0) {
|
|
80
|
+
info('El diario está vacío. Agrega una entrada con: tibiaway diary add');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
separator();
|
|
85
|
+
console.log(chalk.hex('#FFD700').bold(' HISTORIAL DEL DIARIO\n'));
|
|
86
|
+
|
|
87
|
+
for (const entry of entries.slice(-20).reverse()) {
|
|
88
|
+
const date = new Date(entry.date).toLocaleDateString('es-ES', {
|
|
89
|
+
day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit',
|
|
90
|
+
});
|
|
91
|
+
console.log(` ${gold(date)} ${dim('·')} ${chalk.hex('#FF6B1A')(`Lv ${entry.level}`)} ${dim('·')} ${chalk.white(entry.location)}`);
|
|
92
|
+
console.log(` ${dim('→')} ${chalk.hex('#f0f0f0')(entry.note)}`);
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
separator();
|
|
97
|
+
info(`Total de entradas: ${entries.length}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function generateSummary(character) {
|
|
101
|
+
const entries = getDiary();
|
|
102
|
+
|
|
103
|
+
if (entries.length === 0) {
|
|
104
|
+
info('El diario está vacío. Agrega entradas primero con: tibiaway diary add');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const entriesText = entries.slice(-30).map((e) => {
|
|
109
|
+
const date = new Date(e.date).toLocaleDateString('es-ES');
|
|
110
|
+
return `[${date}] Level ${e.level} - ${e.location}: ${e.note}`;
|
|
111
|
+
}).join('\n');
|
|
112
|
+
|
|
113
|
+
const prompt = `Analiza el siguiente diario de progreso de mi personaje en Tibia y dame un resumen inteligente:
|
|
114
|
+
|
|
115
|
+
ENTRADAS DEL DIARIO (últimas 30):
|
|
116
|
+
${entriesText}
|
|
117
|
+
|
|
118
|
+
Por favor analiza:
|
|
119
|
+
1. PROGRESO GENERAL: Cuántos levels subí, en qué periodo
|
|
120
|
+
2. LUGARES FRECUENTADOS: Dónde paso más tiempo y si es óptimo para mi nivel
|
|
121
|
+
3. TENDENCIAS: Qué patrones ves en mi forma de jugar
|
|
122
|
+
4. LOGROS DESTACADOS: Qué cosas importantes sucedieron
|
|
123
|
+
5. RECOMENDACIONES: Qué debería cambiar o mejorar basado en mi historial
|
|
124
|
+
6. PRÓXIMOS OBJETIVOS SUGERIDOS: Qué debería hacer ahora
|
|
125
|
+
|
|
126
|
+
Sé analítico pero también alentador. Si hay áreas de mejora, mencionarlas con tacto.`;
|
|
127
|
+
|
|
128
|
+
console.log('');
|
|
129
|
+
const spinner = ora({ text: 'Analizando tu progreso...', color: 'yellow' }).start();
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const response = await askClaude(prompt);
|
|
133
|
+
spinner.stop();
|
|
134
|
+
separator();
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
137
|
+
console.log('');
|
|
138
|
+
separator();
|
|
139
|
+
} catch (err) {
|
|
140
|
+
spinner.stop();
|
|
141
|
+
error(`Error al generar el resumen: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter } from '../utils/config.js';
|
|
5
|
+
import { askClaude } from '../utils/api.js';
|
|
6
|
+
import { error, highlight, separator } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
export async function handleHunt() {
|
|
9
|
+
const character = getCharacter();
|
|
10
|
+
if (!character) {
|
|
11
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(chalk.hex('#FF6B1A').bold('⚔ HUNT ADVISOR\n'));
|
|
16
|
+
|
|
17
|
+
const answers = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'objetivo',
|
|
21
|
+
message: highlight('¿Cuál es tu objetivo principal?'),
|
|
22
|
+
choices: [
|
|
23
|
+
{ name: 'Máxima experiencia (exp/h)', value: 'exp' },
|
|
24
|
+
{ name: 'Loot valioso', value: 'loot' },
|
|
25
|
+
{ name: 'Mayor profit (balance positivo)', value: 'profit' },
|
|
26
|
+
{ name: 'Tarea de bestiary/task', value: 'task' },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'list',
|
|
31
|
+
name: 'party',
|
|
32
|
+
message: highlight('¿Vas solo o en party?'),
|
|
33
|
+
choices: [
|
|
34
|
+
{ name: 'Solo', value: 'solo' },
|
|
35
|
+
{ name: 'Party (2-3 jugadores)', value: 'small_party' },
|
|
36
|
+
{ name: 'Full party (4+ jugadores)', value: 'full_party' },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'confirm',
|
|
41
|
+
name: 'premium',
|
|
42
|
+
message: highlight('¿Tienes cuenta Premium?'),
|
|
43
|
+
default: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'input',
|
|
47
|
+
name: 'restricciones',
|
|
48
|
+
message: highlight('¿Alguna restricción o preferencia? (zonas, criaturas, etc.) — Enter para saltar:'),
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
const prompt = `Dame las mejores recomendaciones de hunting spots para mi personaje.
|
|
53
|
+
|
|
54
|
+
Objetivo: ${answers.objetivo}
|
|
55
|
+
Modalidad: ${answers.party}
|
|
56
|
+
Cuenta Premium: ${answers.premium ? 'Sí' : 'No'}
|
|
57
|
+
${answers.restricciones ? `Preferencias/restricciones: ${answers.restricciones}` : ''}
|
|
58
|
+
|
|
59
|
+
Por favor dame entre 3 y 5 hunting spots recomendados, ordenados por prioridad para mi objetivo.
|
|
60
|
+
|
|
61
|
+
Para cada spot incluye:
|
|
62
|
+
1. Nombre del lugar y criaturas principales
|
|
63
|
+
2. Exp/hora estimada para mi level y vocación
|
|
64
|
+
3. Profit estimado (positivo o negativo)
|
|
65
|
+
4. Requisitos de acceso (quests, level, etc.)
|
|
66
|
+
5. Tips específicos para mi vocación
|
|
67
|
+
6. ¿Necesita party o funciona bien solo?
|
|
68
|
+
|
|
69
|
+
Sé específico con los números. Si no tienes datos exactos, da rangos razonables.`;
|
|
70
|
+
|
|
71
|
+
console.log('');
|
|
72
|
+
const spinner = ora({ text: 'Consultando al oráculo tibian...', color: 'yellow' }).start();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const response = await askClaude(prompt);
|
|
76
|
+
spinner.stop();
|
|
77
|
+
separator();
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
80
|
+
console.log('');
|
|
81
|
+
separator();
|
|
82
|
+
} catch (err) {
|
|
83
|
+
spinner.stop();
|
|
84
|
+
error(`Error al consultar la IA: ${err.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter } from '../utils/config.js';
|
|
5
|
+
import { askClaude } from '../utils/api.js';
|
|
6
|
+
import { error, highlight, separator } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
export async function handleProfit() {
|
|
9
|
+
const character = getCharacter();
|
|
10
|
+
if (!character) {
|
|
11
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(chalk.hex('#FF6B1A').bold('💰 PROFIT CALCULATOR\n'));
|
|
16
|
+
|
|
17
|
+
const answers = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'input',
|
|
20
|
+
name: 'lugar',
|
|
21
|
+
message: highlight('¿Dónde cazaste?'),
|
|
22
|
+
validate: (i) => i.trim().length > 0 || 'Ingresa el lugar.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
type: 'input',
|
|
26
|
+
name: 'tiempo',
|
|
27
|
+
message: highlight('¿Cuánto tiempo cazaste? (en minutos)'),
|
|
28
|
+
validate: (i) => (!isNaN(parseInt(i)) && parseInt(i) > 0) || 'Ingresa minutos válidos.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'input',
|
|
32
|
+
name: 'supplies',
|
|
33
|
+
message: highlight('¿Cuánto gastaste en supplies? (en gold)'),
|
|
34
|
+
validate: (i) => (!isNaN(parseInt(i)) && parseInt(i) >= 0) || 'Ingresa un número válido.',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'input',
|
|
38
|
+
name: 'loot',
|
|
39
|
+
message: highlight('¿Qué loosteaste? (lista los ítems y cantidades, o el valor total en gold):'),
|
|
40
|
+
validate: (i) => i.trim().length > 0 || 'Ingresa el loot.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'input',
|
|
44
|
+
name: 'exp_ganada',
|
|
45
|
+
message: highlight('¿Cuánta experiencia ganaste? (0 si no sabes):'),
|
|
46
|
+
default: '0',
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
const prompt = `Analiza esta sesión de hunting y dame un reporte completo de profit/waste/exp.
|
|
51
|
+
|
|
52
|
+
Lugar de caza: ${answers.lugar}
|
|
53
|
+
Tiempo: ${answers.tiempo} minutos
|
|
54
|
+
Supplies gastados: ${answers.supplies} gold
|
|
55
|
+
Loot obtenido: ${answers.loot}
|
|
56
|
+
Experiencia ganada: ${answers.exp_ganada} xp
|
|
57
|
+
|
|
58
|
+
Calcula y muestra:
|
|
59
|
+
1. Waste total (supplies - valor loot en tiendas)
|
|
60
|
+
2. Valor estimado del loot (usa precios de mercado de Tibia actuales)
|
|
61
|
+
3. Balance final (profit o loss, con símbolo + o -)
|
|
62
|
+
4. Experiencia ganada y exp/hora estimada
|
|
63
|
+
5. Evaluación del spot: ¿Vale la pena para mi perfil?
|
|
64
|
+
6. Comparación con alternatives para mi level
|
|
65
|
+
7. Sugerencias para mejorar el resultado
|
|
66
|
+
|
|
67
|
+
Usa formato claro con números. Separa bien cada sección.`;
|
|
68
|
+
|
|
69
|
+
console.log('');
|
|
70
|
+
const spinner = ora({ text: 'Calculando profit...', color: 'yellow' }).start();
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const response = await askClaude(prompt);
|
|
74
|
+
spinner.stop();
|
|
75
|
+
separator();
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
78
|
+
console.log('');
|
|
79
|
+
separator();
|
|
80
|
+
} catch (err) {
|
|
81
|
+
spinner.stop();
|
|
82
|
+
error(`Error al consultar la IA: ${err.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCharacter } from '../utils/config.js';
|
|
5
|
+
import { askClaude } from '../utils/api.js';
|
|
6
|
+
import { error, highlight, separator } from '../utils/banner.js';
|
|
7
|
+
|
|
8
|
+
export async function handleQuest() {
|
|
9
|
+
const character = getCharacter();
|
|
10
|
+
if (!character) {
|
|
11
|
+
error('No hay personaje configurado. Ejecuta: tibiaway setup');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(chalk.hex('#FF6B1A').bold('📜 QUEST ADVISOR\n'));
|
|
16
|
+
|
|
17
|
+
const answers = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'objetivo',
|
|
21
|
+
message: highlight('¿Qué buscas con la quest?'),
|
|
22
|
+
choices: [
|
|
23
|
+
{ name: 'Acceso a zona de caza importante', value: 'acceso' },
|
|
24
|
+
{ name: 'Outfit o addon', value: 'outfit' },
|
|
25
|
+
{ name: 'Achievement / title', value: 'achievement' },
|
|
26
|
+
{ name: 'Reward de equipment', value: 'equipment' },
|
|
27
|
+
{ name: 'Story quest / lore', value: 'story' },
|
|
28
|
+
{ name: 'Desbloquear boss o área', value: 'boss_access' },
|
|
29
|
+
{ name: 'No sé, recomiéndame algo', value: 'sugerencia' },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'confirm',
|
|
34
|
+
name: 'party',
|
|
35
|
+
message: highlight('¿Tienes party disponible?'),
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: 'input',
|
|
40
|
+
name: 'contexto',
|
|
41
|
+
message: highlight('¿Algo específico que quieras o que ya hayas completado? (Enter para saltar):'),
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const prompt = `Dame recomendaciones de quests para mi personaje.
|
|
46
|
+
|
|
47
|
+
Objetivo: ${answers.objetivo}
|
|
48
|
+
Party disponible: ${answers.party ? 'Sí' : 'No (solo)'}
|
|
49
|
+
${answers.contexto ? `Contexto adicional: ${answers.contexto}` : ''}
|
|
50
|
+
|
|
51
|
+
Dame entre 3 y 5 quests recomendadas para mi level y vocación.
|
|
52
|
+
|
|
53
|
+
Para cada quest incluye:
|
|
54
|
+
1. Nombre de la quest
|
|
55
|
+
2. Por qué es relevante para mi perfil y objetivo
|
|
56
|
+
3. Level mínimo recomendado
|
|
57
|
+
4. Prerequisitos (otras quests, items, etc.)
|
|
58
|
+
5. Dificultad estimada (fácil/media/difícil)
|
|
59
|
+
6. Reward principal
|
|
60
|
+
7. ¿Necesita party o se puede hacer solo?
|
|
61
|
+
8. Tip o advertencia importante
|
|
62
|
+
|
|
63
|
+
Prioriza quests con mejor relación esfuerzo/recompensa para mi situación actual.`;
|
|
64
|
+
|
|
65
|
+
console.log('');
|
|
66
|
+
const spinner = ora({ text: 'Consultando el grimorio de quests...', color: 'yellow' }).start();
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const response = await askClaude(prompt);
|
|
70
|
+
spinner.stop();
|
|
71
|
+
separator();
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log(chalk.hex('#f0f0f0')(response));
|
|
74
|
+
console.log('');
|
|
75
|
+
separator();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
spinner.stop();
|
|
78
|
+
error(`Error al consultar la IA: ${err.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|