zardbot-telegram 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.
Files changed (111) hide show
  1. package/.env.example +116 -0
  2. package/LICENSE +21 -0
  3. package/README.md +250 -0
  4. package/dist/agent/manager.js +88 -0
  5. package/dist/agent/types.js +26 -0
  6. package/dist/app/start-bot-app.js +49 -0
  7. package/dist/bot/commands/abort.js +121 -0
  8. package/dist/bot/commands/commands.js +480 -0
  9. package/dist/bot/commands/definitions.js +27 -0
  10. package/dist/bot/commands/help.js +10 -0
  11. package/dist/bot/commands/models.js +38 -0
  12. package/dist/bot/commands/new.js +70 -0
  13. package/dist/bot/commands/opencode-start.js +101 -0
  14. package/dist/bot/commands/opencode-stop.js +44 -0
  15. package/dist/bot/commands/projects.js +223 -0
  16. package/dist/bot/commands/rename.js +139 -0
  17. package/dist/bot/commands/sessions.js +351 -0
  18. package/dist/bot/commands/start.js +43 -0
  19. package/dist/bot/commands/status.js +95 -0
  20. package/dist/bot/commands/task.js +399 -0
  21. package/dist/bot/commands/tasklist.js +220 -0
  22. package/dist/bot/commands/voice.js +145 -0
  23. package/dist/bot/handlers/agent.js +118 -0
  24. package/dist/bot/handlers/context.js +100 -0
  25. package/dist/bot/handlers/document.js +65 -0
  26. package/dist/bot/handlers/inline-menu.js +119 -0
  27. package/dist/bot/handlers/model.js +143 -0
  28. package/dist/bot/handlers/permission.js +235 -0
  29. package/dist/bot/handlers/prompt.js +240 -0
  30. package/dist/bot/handlers/question.js +390 -0
  31. package/dist/bot/handlers/tts.js +89 -0
  32. package/dist/bot/handlers/variant.js +138 -0
  33. package/dist/bot/handlers/voice.js +173 -0
  34. package/dist/bot/index.js +977 -0
  35. package/dist/bot/message-patterns.js +4 -0
  36. package/dist/bot/middleware/auth.js +30 -0
  37. package/dist/bot/middleware/interaction-guard.js +95 -0
  38. package/dist/bot/middleware/unknown-command.js +22 -0
  39. package/dist/bot/streaming/response-streamer.js +286 -0
  40. package/dist/bot/streaming/tool-call-streamer.js +285 -0
  41. package/dist/bot/utils/busy-guard.js +15 -0
  42. package/dist/bot/utils/commands.js +21 -0
  43. package/dist/bot/utils/file-download.js +91 -0
  44. package/dist/bot/utils/finalize-assistant-response.js +52 -0
  45. package/dist/bot/utils/keyboard.js +69 -0
  46. package/dist/bot/utils/send-with-markdown-fallback.js +165 -0
  47. package/dist/bot/utils/telegram-text.js +28 -0
  48. package/dist/bot/utils/thinking-message.js +8 -0
  49. package/dist/cli/args.js +98 -0
  50. package/dist/cli.js +80 -0
  51. package/dist/config.js +97 -0
  52. package/dist/i18n/de.js +357 -0
  53. package/dist/i18n/en.js +357 -0
  54. package/dist/i18n/es.js +357 -0
  55. package/dist/i18n/fr.js +357 -0
  56. package/dist/i18n/index.js +109 -0
  57. package/dist/i18n/ru.js +357 -0
  58. package/dist/i18n/zh.js +357 -0
  59. package/dist/index.js +26 -0
  60. package/dist/interaction/busy.js +8 -0
  61. package/dist/interaction/cleanup.js +32 -0
  62. package/dist/interaction/guard.js +140 -0
  63. package/dist/interaction/manager.js +106 -0
  64. package/dist/interaction/types.js +1 -0
  65. package/dist/keyboard/manager.js +172 -0
  66. package/dist/keyboard/types.js +1 -0
  67. package/dist/model/capabilities.js +62 -0
  68. package/dist/model/context-limit.js +57 -0
  69. package/dist/model/manager.js +259 -0
  70. package/dist/model/types.js +24 -0
  71. package/dist/opencode/client.js +13 -0
  72. package/dist/opencode/events.js +140 -0
  73. package/dist/permission/manager.js +100 -0
  74. package/dist/permission/types.js +1 -0
  75. package/dist/pinned/format.js +29 -0
  76. package/dist/pinned/manager.js +682 -0
  77. package/dist/pinned/types.js +1 -0
  78. package/dist/process/manager.js +273 -0
  79. package/dist/process/types.js +1 -0
  80. package/dist/project/manager.js +88 -0
  81. package/dist/question/manager.js +176 -0
  82. package/dist/question/types.js +1 -0
  83. package/dist/rename/manager.js +53 -0
  84. package/dist/runtime/bootstrap.js +350 -0
  85. package/dist/runtime/mode.js +74 -0
  86. package/dist/runtime/paths.js +37 -0
  87. package/dist/scheduled-task/creation-manager.js +113 -0
  88. package/dist/scheduled-task/display.js +239 -0
  89. package/dist/scheduled-task/executor.js +87 -0
  90. package/dist/scheduled-task/foreground-state.js +32 -0
  91. package/dist/scheduled-task/next-run.js +207 -0
  92. package/dist/scheduled-task/runtime.js +368 -0
  93. package/dist/scheduled-task/schedule-parser.js +169 -0
  94. package/dist/scheduled-task/store.js +65 -0
  95. package/dist/scheduled-task/types.js +19 -0
  96. package/dist/session/cache-manager.js +455 -0
  97. package/dist/session/manager.js +10 -0
  98. package/dist/settings/manager.js +158 -0
  99. package/dist/stt/client.js +97 -0
  100. package/dist/summary/aggregator.js +1136 -0
  101. package/dist/summary/formatter.js +491 -0
  102. package/dist/summary/subagent-formatter.js +63 -0
  103. package/dist/summary/tool-message-batcher.js +90 -0
  104. package/dist/tts/client.js +130 -0
  105. package/dist/utils/error-format.js +29 -0
  106. package/dist/utils/logger.js +127 -0
  107. package/dist/utils/safe-background-task.js +33 -0
  108. package/dist/utils/telegram-rate-limit-retry.js +93 -0
  109. package/dist/variant/manager.js +103 -0
  110. package/dist/variant/types.js +1 -0
  111. package/package.json +79 -0
@@ -0,0 +1,357 @@
1
+ export const es = {
2
+ "cmd.description.status": "Estado del servidor y de la sesión",
3
+ "cmd.description.new": "Crear una sesión nueva",
4
+ "cmd.description.stop": "Detener la acción actual",
5
+ "cmd.description.sessions": "Listar sesiones",
6
+ "cmd.description.projects": "Listar proyectos",
7
+ "cmd.description.task": "Crear tarea programada",
8
+ "cmd.description.tasklist": "Ver tareas programadas",
9
+ "cmd.description.commands": "Comandos personalizados",
10
+ "cmd.description.voice": "Seleccionar voz TTS",
11
+ "cmd.description.opencode_start": "Iniciar servidor OpenCode",
12
+ "cmd.description.opencode_stop": "Detener servidor OpenCode",
13
+ "cmd.description.help": "Ayuda",
14
+ "callback.unknown_command": "Comando desconocido",
15
+ "callback.processing_error": "Error de procesamiento",
16
+ "error.load_agents": "❌ No se pudo cargar la lista de agentes",
17
+ "error.load_models": "❌ No se pudo cargar la lista de modelos",
18
+ "error.load_variants": "❌ No se pudo cargar la lista de variantes",
19
+ "error.context_button": "❌ No se pudo procesar el botón de contexto",
20
+ "error.generic": "🔴 Algo salió mal.",
21
+ "interaction.blocked.expired": "⚠️ Esta interacción ha expirado. Por favor, iníciala de nuevo.",
22
+ "interaction.blocked.expected_callback": "⚠️ Para este paso, usa los botones en línea o toca Cancelar.",
23
+ "interaction.blocked.expected_text": "⚠️ Para este paso, envía un mensaje de texto.",
24
+ "interaction.blocked.expected_command": "⚠️ Para este paso, envía un comando.",
25
+ "interaction.blocked.command_not_allowed": "⚠️ Este comando no está disponible en el paso actual.",
26
+ "interaction.blocked.finish_current": "⚠️ Termina primero la interacción actual (responde o cancela) y después abre otro menú.",
27
+ "inline.blocked.expected_choice": "⚠️ Elige una opción usando los botones en línea o toca Cancelar.",
28
+ "inline.blocked.command_not_allowed": "⚠️ Este comando no está disponible mientras el menú en línea está activo.",
29
+ "question.blocked.expected_answer": "⚠️ Responde la pregunta actual usando botones, Respuesta personalizada o Cancelar.",
30
+ "question.blocked.command_not_allowed": "⚠️ Este comando no está disponible hasta que se complete el flujo de la pregunta actual.",
31
+ "inline.button.cancel": "❌ Cancelar",
32
+ "inline.inactive_callback": "Este menú está inactivo",
33
+ "inline.cancelled_callback": "Cancelado",
34
+ "common.unknown": "desconocido",
35
+ "common.unknown_error": "error desconocido",
36
+ "start.welcome": "👋 ¡Bienvenido a OpenCode Telegram Bot!\n\nUsa los comandos:\n/projects — seleccionar proyecto\n/sessions — lista de sesiones\n/new — sesión nueva\n/task — tarea programada\n/tasklist — tareas programadas\n/status — estado\n/help — ayuda\n\nUsa los botones inferiores para elegir modo, modelo y variante.",
37
+ "help.keyboard_hint": "💡 Usa los botones inferiores para modo del agente, modelo, variante y acciones de contexto.",
38
+ "help.text": "📖 **Ayuda**\n\n/status - Ver estado del servidor\n/sessions - Lista de sesiones\n/new - Crear una sesión nueva\n/help - Ayuda",
39
+ "bot.thinking": "💭 Pensando...",
40
+ "bot.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
41
+ "bot.creating_session": "🔄 Creando una sesión nueva...",
42
+ "bot.create_session_error": "🔴 No se pudo crear la sesión. Prueba /new o revisa el estado del servidor con /status.",
43
+ "bot.session_created": "✅ Sesión creada: {title}",
44
+ "bot.session_busy": "⏳ El agente ya está ejecutando una tarea. Espera a que termine o usa /abort para interrumpir la ejecución actual.",
45
+ "bot.session_reset_project_mismatch": "⚠️ La sesión activa no coincide con el proyecto seleccionado, así que se reinició. Usa /sessions para elegir una o /new para crear una nueva.",
46
+ "bot.prompt_send_error": "No se pudo enviar la solicitud a OpenCode.",
47
+ "bot.session_error": "🔴 OpenCode devolvió un error: {message}",
48
+ "bot.session_retry": "🔁 {message}\n\nEl proveedor devuelve el mismo error en intentos repetidos. Usa /abort para detenerlo.",
49
+ "bot.unknown_command": "⚠️ Comando desconocido: {command}. Usa /help para ver los comandos disponibles.",
50
+ "bot.photo_downloading": "⏳ Descargando foto...",
51
+ "bot.photo_too_large": "⚠️ La foto es demasiado grande (max {maxSizeMb}MB)",
52
+ "bot.photo_model_no_image": "⚠️ El modelo actual no admite entrada de imagen. Enviaré solo texto.",
53
+ "bot.photo_download_error": "🔴 No se pudo descargar la foto",
54
+ "bot.photo_no_caption": "💡 Consejo: agrega un pie de foto para describir que quieres hacer con esta foto.",
55
+ "bot.file_downloading": "⏳ Descargando archivo...",
56
+ "bot.file_too_large": "⚠️ El archivo es demasiado grande (max {maxSizeMb}MB)",
57
+ "bot.file_download_error": "🔴 No se pudo descargar el archivo",
58
+ "bot.model_no_pdf": "⚠️ El modelo actual no admite entrada PDF. Enviaré solo texto.",
59
+ "bot.text_file_too_large": "⚠️ El archivo de texto es demasiado grande (max {maxSizeKb}KB)",
60
+ "status.header_running": "🟢 OpenCode Server está en ejecución",
61
+ "status.health.healthy": "Saludable",
62
+ "status.health.unhealthy": "No saludable",
63
+ "status.line.health": "Estado: {health}",
64
+ "status.line.version": "Versión: {version}",
65
+ "status.line.managed_yes": "Iniciado por el bot: Sí",
66
+ "status.line.managed_no": "Iniciado por el bot: No",
67
+ "status.line.pid": "PID: {pid}",
68
+ "status.line.uptime_sec": "Tiempo activo: {seconds} s",
69
+ "status.line.mode": "Modo: {mode}",
70
+ "status.line.model": "Modelo: {model}",
71
+ "status.agent_not_set": "no configurado",
72
+ "status.project_selected": "Proyecto: {project}",
73
+ "status.project_not_selected": "Proyecto: no seleccionado",
74
+ "status.project_hint": "Usa /projects para seleccionar un proyecto",
75
+ "status.session_selected": "Sesión actual: {title}",
76
+ "status.session_not_selected": "Sesión actual: no seleccionada",
77
+ "status.session_hint": "Usa /sessions para elegir una o /new para crear una",
78
+ "status.server_unavailable": "🔴 OpenCode Server no está disponible\n\nUsa /opencode_start para iniciar el servidor.",
79
+ "projects.empty": "📭 No se encontraron proyectos.\n\nAbre un directorio en OpenCode y crea al menos una sesión; entonces aparecerá aquí.",
80
+ "projects.select": "Selecciona un proyecto:",
81
+ "projects.select_with_current": "Selecciona un proyecto:\n\nActual: 🏗 {project}",
82
+ "projects.page_indicator": "Página {current}/{total}",
83
+ "projects.prev_page": "⬅️ Anterior",
84
+ "projects.next_page": "Siguiente ➡️",
85
+ "projects.fetch_error": "🔴 OpenCode Server no está disponible u ocurrió un error al cargar los proyectos.",
86
+ "projects.page_load_error": "No se puede cargar esta página. Inténtalo de nuevo.",
87
+ "projects.selected": "✅ Proyecto seleccionado: {project}\n\n📋 La sesión se reinició. Usa /sessions o /new para este proyecto.",
88
+ "projects.select_error": "🔴 No se pudo seleccionar el proyecto.",
89
+ "sessions.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
90
+ "sessions.empty": "📭 No se encontraron sesiones.\n\nCrea una sesión nueva con /new.",
91
+ "sessions.select": "Selecciona una sesión:",
92
+ "sessions.select_page": "Selecciona una sesión (página {page}):",
93
+ "sessions.fetch_error": "🔴 OpenCode Server no está disponible u ocurrió un error al cargar las sesiones.",
94
+ "sessions.select_project_first": "🔴 No hay un proyecto seleccionado. Usa /projects.",
95
+ "sessions.page_empty_callback": "No hay sesiones en esta página",
96
+ "sessions.page_load_error_callback": "No se puede cargar esta página. Inténtalo de nuevo.",
97
+ "sessions.button.prev_page": "⬅️ Anterior",
98
+ "sessions.button.next_page": "Siguiente ➡️",
99
+ "sessions.loading_context": "⏳ Cargando contexto y los últimos mensajes...",
100
+ "sessions.selected": "✅ Sesión seleccionada: {title}",
101
+ "sessions.select_error": "🔴 No se pudo seleccionar la sesión.",
102
+ "sessions.preview.empty": "No hay mensajes recientes.",
103
+ "sessions.preview.title": "Mensajes recientes:",
104
+ "sessions.preview.you": "Tú:",
105
+ "sessions.preview.agent": "Agente:",
106
+ "new.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
107
+ "new.created": "✅ Sesión nueva creada: {title}",
108
+ "new.create_error": "🔴 OpenCode Server no está disponible u ocurrió un error al crear la sesión.",
109
+ "stop.no_active_session": "🛑 El agente no se inició\n\nCrea una sesión con /new o selecciona una con /sessions.",
110
+ "stop.in_progress": "🛑 Flujo de eventos detenido; enviando señal de aborto...\n\nEsperando a que el agente se detenga.",
111
+ "stop.warn_unconfirmed": "⚠️ Flujo de eventos detenido, pero el servidor no confirmó el aborto.\n\nRevisa /status y vuelve a intentar /abort en unos segundos.",
112
+ "stop.warn_maybe_finished": "⚠️ Flujo de eventos detenido, pero el agente podría haber terminado ya.",
113
+ "stop.success": "✅ Acción del agente interrumpida. No se enviarán más mensajes de esta ejecución.",
114
+ "stop.warn_still_busy": "⚠️ Señal enviada, pero el agente sigue ocupado.\n\nEl flujo de eventos ya está deshabilitado, así que no se enviarán mensajes intermedios.",
115
+ "stop.warn_timeout": "⚠️ Tiempo de espera agotado al solicitar el aborto.\n\nEl flujo de eventos ya está deshabilitado; vuelve a intentar /abort en unos segundos.",
116
+ "stop.warn_local_only": "⚠️ Flujo de eventos detenido localmente, pero el aborto en el servidor falló.",
117
+ "stop.error": "🔴 No se pudo detener la acción.\n\nEl flujo de eventos está detenido; prueba /abort otra vez.",
118
+ "opencode_start.already_running_managed": "⚠️ OpenCode Server ya está en ejecución\n\nPID: {pid}\nTiempo activo: {seconds} segundos",
119
+ "opencode_start.already_running_external": "✅ OpenCode Server ya está en ejecución como un proceso externo\n\nVersión: {version}\n\nEste servidor no fue iniciado por el bot, por lo que /opencode-stop no puede detenerlo.",
120
+ "opencode_start.starting": "🔄 Iniciando OpenCode Server...",
121
+ "opencode_start.start_error": "🔴 No se pudo iniciar OpenCode Server\n\nError: {error}\n\nRevisa que OpenCode CLI esté instalado y disponible en PATH:\nopencode --version\nnpm install -g @opencode-ai/cli",
122
+ "opencode_start.started_not_ready": "⚠️ OpenCode Server se inició, pero no responde\n\nPID: {pid}\n\nEl servidor puede estar iniciando. Prueba /status en unos segundos.",
123
+ "opencode_start.success": "✅ OpenCode Server iniciado correctamente\n\nPID: {pid}\nVersión: {version}",
124
+ "opencode_start.error": "🔴 Ocurrió un error al iniciar el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
125
+ "opencode_stop.external_running": "⚠️ OpenCode Server está en ejecución como un proceso externo\n\nEste servidor no fue iniciado con /opencode-start.\nDeténlo manualmente o usa /status para revisar el estado.",
126
+ "opencode_stop.not_running": "⚠️ OpenCode Server no está en ejecución",
127
+ "opencode_stop.stopping": "🛑 Deteniendo OpenCode Server...\n\nPID: {pid}",
128
+ "opencode_stop.stop_error": "🔴 No se pudo detener OpenCode Server\n\nError: {error}",
129
+ "opencode_stop.success": "✅ OpenCode Server detenido correctamente",
130
+ "opencode_stop.error": "🔴 Ocurrió un error al detener el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
131
+ "agent.changed_callback": "Modo cambiado: {name}",
132
+ "agent.changed_message": "✅ Modo cambiado a: {name}",
133
+ "agent.change_error_callback": "No se pudo cambiar el modo",
134
+ "agent.menu.current": "Modo actual: {name}\n\nSelecciona el modo:",
135
+ "agent.menu.select": "Selecciona el modo de trabajo:",
136
+ "agent.menu.empty": "⚠️ No hay agentes disponibles",
137
+ "agent.menu.error": "🔴 No se pudo obtener la lista de agentes",
138
+ "model.changed_callback": "Modelo cambiado: {name}",
139
+ "model.changed_message": "✅ Modelo cambiado a: {name}",
140
+ "model.change_error_callback": "No se pudo cambiar el modelo",
141
+ "model.menu.empty": "⚠️ No hay modelos disponibles",
142
+ "model.menu.select": "Selecciona el modelo:",
143
+ "model.menu.current": "Modelo actual: {name}\n\nSelecciona el modelo:",
144
+ "model.menu.favorites_title": "⭐ Favoritos (Agrega modelos a favoritos en OpenCode CLI)",
145
+ "model.menu.favorites_empty": "— Vacío.",
146
+ "model.menu.recent_title": "🕘 Recientes",
147
+ "model.menu.recent_empty": "— Vacío.",
148
+ "model.menu.favorites_hint": "ℹ️ Agrega modelos a favoritos en OpenCode CLI para mantenerlos arriba de la lista.",
149
+ "model.menu.error": "🔴 No se pudo obtener la lista de modelos",
150
+ "variant.model_not_selected_callback": "Error: no hay un modelo seleccionado",
151
+ "variant.changed_callback": "Variante cambiada: {name}",
152
+ "variant.changed_message": "✅ Variante cambiada a: {name}",
153
+ "variant.change_error_callback": "No se pudo cambiar la variante",
154
+ "variant.select_model_first": "⚠️ Selecciona un modelo primero",
155
+ "variant.menu.empty": "⚠️ No hay variantes disponibles",
156
+ "variant.menu.current": "Variante actual: {name}\n\nSelecciona la variante:",
157
+ "variant.menu.error": "🔴 No se pudo obtener la lista de variantes",
158
+ "context.button.confirm": "✅ Sí, compactar contexto",
159
+ "context.no_active_session": "⚠️ No hay una sesión activa. Crea una sesión con /new",
160
+ "context.confirm_text": '📊 Compactación de contexto para la sesión "{title}"\n\nEsto reducirá el uso de contexto eliminando mensajes antiguos del historial. La tarea actual no se interrumpirá.\n\n¿Continuar?',
161
+ "context.callback_session_not_found": "Sesión no encontrada",
162
+ "context.callback_compacting": "Compactando contexto...",
163
+ "context.progress": "⏳ Compactando contexto...",
164
+ "context.error": "❌ La compactación de contexto falló",
165
+ "context.success": "✅ Contexto compactado correctamente",
166
+ "permission.inactive_callback": "La solicitud de permisos está inactiva",
167
+ "permission.processing_error_callback": "Error de procesamiento",
168
+ "permission.no_active_request_callback": "Error: no hay una solicitud activa",
169
+ "permission.reply.once": "Permitido una vez",
170
+ "permission.reply.always": "Siempre permitido",
171
+ "permission.reply.reject": "Rechazado",
172
+ "permission.send_reply_error": "❌ No se pudo enviar la respuesta de permisos",
173
+ "permission.blocked.expected_reply": "⚠️ Primero responde a la solicitud de permisos usando los botones de arriba.",
174
+ "permission.blocked.command_not_allowed": "⚠️ Este comando no está disponible hasta que respondas a la solicitud de permisos.",
175
+ "permission.header": "{emoji} Solicitud de permisos: {name}\n\n",
176
+ "permission.button.allow": "✅ Permitir una vez",
177
+ "permission.button.always": "🔓 Permitir siempre",
178
+ "permission.button.reject": "❌ Rechazar",
179
+ "permission.name.bash": "Bash",
180
+ "permission.name.edit": "Editar",
181
+ "permission.name.write": "Escribir",
182
+ "permission.name.read": "Leer",
183
+ "permission.name.webfetch": "Obtener web",
184
+ "permission.name.websearch": "Buscar en la web",
185
+ "permission.name.glob": "Buscar archivos",
186
+ "permission.name.grep": "Buscar contenido",
187
+ "permission.name.list": "Listar directorio",
188
+ "permission.name.task": "Tarea",
189
+ "permission.name.lsp": "LSP",
190
+ "permission.name.external_directory": "Directorio externo",
191
+ "question.inactive_callback": "La encuesta está inactiva",
192
+ "question.processing_error_callback": "Error de procesamiento",
193
+ "question.select_one_required_callback": "Selecciona al menos una opción",
194
+ "question.enter_custom_callback": "Envía tu respuesta personalizada como mensaje",
195
+ "question.cancelled": "❌ Encuesta cancelada",
196
+ "question.answer_already_received": "Respuesta ya recibida, espera...",
197
+ "question.completed_no_answers": "✅ Encuesta completada (sin respuestas)",
198
+ "question.no_active_project": "❌ No hay un proyecto activo",
199
+ "question.no_active_request": "❌ No hay una solicitud activa",
200
+ "question.send_answers_error": "❌ No se pudieron enviar las respuestas al agente",
201
+ "question.multi_hint": "\n(Puedes seleccionar varias opciones)",
202
+ "question.button.submit": "✅ Listo",
203
+ "question.button.custom": "🔤 Respuesta personalizada",
204
+ "question.button.cancel": "❌ Cancelar",
205
+ "question.use_custom_button_first": '⚠️ Para enviar texto, primero toca "Respuesta personalizada" para la pregunta actual.',
206
+ "question.summary.title": "✅ ¡Encuesta completada!\n\n",
207
+ "question.summary.question": "Pregunta {index}:\n{question}\n\n",
208
+ "question.summary.answer": "Respuesta:\n{answer}\n\n",
209
+ "keyboard.agent_mode": "{emoji} Modo {name}",
210
+ "keyboard.context": "📊 {used} / {limit} ({percent}%)",
211
+ "keyboard.context_empty": "📊 0",
212
+ "keyboard.variant": "💭 {name}",
213
+ "keyboard.variant_default": "💡 Predeterminado",
214
+ "keyboard.updated": "⌨️ Teclado actualizado",
215
+ "pinned.default_session_title": "sesión nueva",
216
+ "pinned.unknown": "Desconocido",
217
+ "pinned.line.project": "Proyecto: {project}",
218
+ "pinned.line.model": "Modelo: {model}",
219
+ "pinned.line.context": "Contexto: {used} / {limit} ({percent}%)",
220
+ "pinned.line.cost": "Costo: {cost} gastado",
221
+ "subagent.header": "Subagente {agent}: {description}",
222
+ "subagent.line.status": "Estado: {status}",
223
+ "subagent.line.task": "Tarea: {task}",
224
+ "subagent.line.agent": "Agente: {agent}",
225
+ "subagent.working": "Trabajando...",
226
+ "subagent.working_with_details": "Trabajando: {details}",
227
+ "subagent.completed": "Completada",
228
+ "subagent.failed": "Error de tarea",
229
+ "subagent.status.pending": "pendiente",
230
+ "subagent.status.running": "en ejecucion",
231
+ "subagent.status.completed": "completado",
232
+ "subagent.status.error": "error",
233
+ "pinned.files.title": "Archivos ({count}):",
234
+ "pinned.files.item": " {path}{diff}",
235
+ "pinned.files.more": " ... y {count} más",
236
+ "tool.todo.overflow": "*({count} tareas más)*",
237
+ "tool.file_header.write": "Escribir archivo/ruta: {path}\n============================================================\n\n",
238
+ "tool.file_header.edit": "Editar archivo/ruta: {path}\n============================================================\n\n",
239
+ "runtime.wizard.ask_token": "Introduce el token del bot de Telegram (obtenlo de @BotFather).\n> ",
240
+ "runtime.wizard.ask_language": "Selecciona el idioma de la interfaz.\nIntroduce el número del idioma de la lista o el código de locale.\nPulsa Enter para mantener el idioma por defecto: {defaultLocale}\n{options}\n> ",
241
+ "runtime.wizard.language_invalid": "Introduce un número de idioma de la lista o un código de locale compatible.\n",
242
+ "runtime.wizard.language_selected": "Idioma seleccionado: {language}\n",
243
+ "runtime.wizard.token_required": "El token es obligatorio. Inténtalo de nuevo.\n",
244
+ "runtime.wizard.token_invalid": "El token parece inválido (se espera el formato <id>:<secret>). Inténtalo de nuevo.\n",
245
+ "runtime.wizard.ask_user_id": "Introduce tu Telegram User ID (puedes obtenerlo de @userinfobot).\n> ",
246
+ "runtime.wizard.user_id_invalid": "Introduce un entero positivo (> 0).\n",
247
+ "runtime.wizard.ask_api_url": "Introduce la URL de la API de OpenCode (opcional).\nPulsa Enter para usar el valor por defecto: {defaultUrl}\n> ",
248
+ "runtime.wizard.ask_server_username": "Introduce el nombre de usuario del servidor OpenCode (opcional).\nPulsa Enter para usar el valor por defecto: {defaultUsername}\n> ",
249
+ "runtime.wizard.ask_server_password": "Introduce la contrasena del servidor OpenCode (opcional).\nPulsa Enter para dejarla vacia.\n> ",
250
+ "runtime.wizard.api_url_invalid": "Introduce una URL válida (http/https) o pulsa Enter para usar el valor por defecto.\n",
251
+ "runtime.wizard.start": "Configuración de OpenCode Telegram Bot.\n",
252
+ "runtime.wizard.saved": "Configuración guardada:\n- {envPath}\n- {settingsPath}\n",
253
+ "runtime.wizard.not_configured_starting": "La aplicación aún no está configurada. Iniciando el asistente...\n",
254
+ "runtime.wizard.tty_required": "El asistente interactivo requiere un terminal TTY. Ejecuta `opencode-telegram config` en una shell interactiva.",
255
+ "rename.no_session": "⚠️ No hay una sesión activa. Crea o selecciona una sesión primero.",
256
+ "rename.prompt": "📝 Introduce un nuevo título para la sesión:\n\nActual: {title}",
257
+ "rename.empty_title": "⚠️ El título no puede estar vacío.",
258
+ "rename.success": "✅ Sesión renombrada a: {title}",
259
+ "rename.error": "🔴 No se pudo renombrar la sesión.",
260
+ "rename.cancelled": "❌ Cambio de nombre cancelado.",
261
+ "rename.inactive_callback": "La solicitud de cambio de nombre está inactiva",
262
+ "rename.inactive": "⚠️ La solicitud de cambio de nombre no está activa. Ejecuta /rename otra vez.",
263
+ "rename.blocked.expected_name": "⚠️ Introduce el nuevo nombre de la sesión como texto o toca Cancelar en el mensaje de cambio de nombre.",
264
+ "rename.blocked.command_not_allowed": "⚠️ Este comando no está disponible mientras el cambio de nombre espera un nuevo nombre.",
265
+ "rename.button.cancel": "❌ Cancelar",
266
+ "task.prompt.schedule": "⏰ Envía el horario de la tarea en lenguaje natural.\n\nEjemplos:\n- cada 5 minutos\n- cada día a las 17:00\n- mañana a las 12:00",
267
+ "task.schedule_empty": "⚠️ El horario no puede estar vacío.",
268
+ "task.parse.in_progress": "⏳ Analizando horario...",
269
+ "task.parse_error": "🔴 No se pudo interpretar el horario.\n\n{message}\n\nEnvía el periodo otra vez de forma más clara.",
270
+ "task.schedule_preview": "✅ Horario interpretado\n\nEntendido como: {summary}\n{cronLine}Zona horaria: {timezone}\nTipo: {kind}\nPróxima ejecución: {nextRunAt}",
271
+ "task.schedule_preview.cron": "Cron: {cron}",
272
+ "task.prompt.body": "📝 Ahora envía lo que el bot debe hacer según este horario.",
273
+ "task.prompt_empty": "⚠️ El texto de la tarea no puede estar vacío.",
274
+ "task.created": "✅ Tarea programada creada\n\nTarea: {description}\nProyecto: {project}\nModelo: {model}\nHorario: {schedule}\n{cronLine}Próxima ejecución: {nextRunAt}",
275
+ "task.created.cron": "Cron: {cron}",
276
+ "task.button.retry_schedule": "🔁 Volver a introducir horario",
277
+ "task.button.cancel": "❌ Cancelar",
278
+ "task.retry_schedule_callback": "Volviendo a introducir el horario...",
279
+ "task.cancel_callback": "Cancelando...",
280
+ "task.cancelled": "❌ Creación de la tarea programada cancelada.",
281
+ "task.inactive_callback": "Este flujo de tarea programada ya no está activo",
282
+ "task.inactive": "⚠️ La creación de la tarea programada no está activa. Ejecuta /task otra vez.",
283
+ "task.blocked.expected_input": "⚠️ Primero termina la configuración actual de la tarea programada: envía texto o usa el botón del mensaje del horario.",
284
+ "task.blocked.command_not_allowed": "⚠️ Este comando no está disponible mientras la creación de la tarea programada está activa.",
285
+ "task.limit_reached": "⚠️ Se alcanzó el límite de tareas ({limit}). Primero elimina una tarea programada existente.",
286
+ "task.schedule_too_frequent": "El horario recurrente es demasiado frecuente. El intervalo mínimo permitido es una vez cada 5 minutos.",
287
+ "task.kind.cron": "recurrente",
288
+ "task.kind.once": "única",
289
+ "task.run.success": "⏰ Tarea programada completada: {description}",
290
+ "task.run.error": "🔴 La tarea programada falló: {description}\n\nError: {error}",
291
+ "tasklist.empty": "📭 Aún no hay tareas programadas.",
292
+ "tasklist.select": "Elige una tarea programada:",
293
+ "tasklist.details": "⏰ Tarea programada\n\nTarea: {prompt}\nProyecto: {project}\nHorario: {schedule}\n{cronLine}Zona horaria: {timezone}\nPróxima ejecución: {nextRunAt}\nÚltima ejecución: {lastRunAt}\nNúmero de ejecuciones: {runCount}",
294
+ "tasklist.details.cron": "Cron: {cron}",
295
+ "tasklist.button.delete": "🗑 Eliminar",
296
+ "tasklist.button.cancel": "❌ Cancelar",
297
+ "tasklist.deleted_callback": "Eliminada",
298
+ "tasklist.cancelled_callback": "Cancelado",
299
+ "tasklist.inactive_callback": "Este menú de tareas programadas está inactivo",
300
+ "tasklist.load_error": "🔴 No se pudieron cargar las tareas programadas.",
301
+ "commands.select": "Elige un comando de OpenCode:",
302
+ "commands.empty": "📭 No hay comandos de OpenCode disponibles para este proyecto.",
303
+ "commands.fetch_error": "🔴 No se pudieron cargar los comandos de OpenCode.",
304
+ "commands.no_description": "Sin descripción",
305
+ "commands.button.execute": "✅ Ejecutar",
306
+ "commands.button.cancel": "❌ Cancelar",
307
+ "commands.confirm": "Confirma la ejecución del comando {command}. Para ejecutarlo con argumentos, envía los argumentos como mensaje.",
308
+ "commands.inactive_callback": "Este menú de comandos está inactivo",
309
+ "commands.cancelled_callback": "Cancelado",
310
+ "commands.execute_callback": "Ejecutando comando...",
311
+ "commands.executing_prefix": "⚡ Ejecutando comando:",
312
+ "commands.arguments_empty": "⚠️ Los argumentos no pueden estar vacíos. Envía texto o toca Ejecutar.",
313
+ "commands.execute_error": "🔴 No se pudo ejecutar el comando de OpenCode.",
314
+ "commands.select_page": "Elige un comando de OpenCode (página {page}):",
315
+ "commands.button.prev_page": "⬅️ Anterior",
316
+ "commands.button.next_page": "Siguiente ➡️",
317
+ "commands.page_empty_callback": "No hay comandos en esta página",
318
+ "commands.page_load_error_callback": "No se pudo cargar esta página. Por favor, inténtalo de nuevo.",
319
+ "cmd.description.rename": "Renombrar la sesión actual",
320
+ "cli.usage": "Uso:\n opencode-telegram [start] [--mode sources|installed]\n opencode-telegram status\n opencode-telegram stop\n opencode-telegram config\n\nNotas:\n - Sin comando, el valor por defecto es `start`\n - `--mode` actualmente solo se admite para `start`",
321
+ "cli.placeholder.status": "El comando `status` es actualmente un marcador de posición. Las comprobaciones reales de estado se agregarán en la capa de servicio (Fase 5).",
322
+ "cli.placeholder.stop": "El comando `stop` es actualmente un marcador de posición. La detención real del proceso en segundo plano se agregará en la capa de servicio (Fase 5).",
323
+ "cli.placeholder.unavailable": "El comando no esta disponible.",
324
+ "cli.error.prefix": "Error de CLI: {message}",
325
+ "cli.args.unknown_command": "Comando desconocido: {value}",
326
+ "cli.args.mode_requires_value": "La opción --mode requiere un valor: sources|installed",
327
+ "cli.args.invalid_mode": "Valor de --mode inválido: {value}. Se espera sources|installed",
328
+ "cli.args.unknown_option": "Opción desconocida: {value}",
329
+ "cli.args.mode_only_start": "La opción --mode solo se admite para el comando start",
330
+ "legacy.models.fetch_error": "🔴 No se pudo obtener la lista de modelos. Revisa el estado del servidor con /status.",
331
+ "legacy.models.empty": "📋 No hay modelos disponibles. Configura los proveedores en OpenCode.",
332
+ "legacy.models.header": "📋 Modelos disponibles:\n\n",
333
+ "legacy.models.no_provider_models": " ⚠️ No hay modelos disponibles\n",
334
+ "legacy.models.env_hint": "💡 Para usar el modelo en .env:\n",
335
+ "legacy.models.error": "🔴 Ocurrió un error al cargar la lista de modelos.",
336
+ "stt.recognizing": "🎤 Reconociendo audio...",
337
+ "stt.recognized": "🎤 Reconocido:\n{text}",
338
+ "stt.not_configured": "🎤 El reconocimiento de voz no está configurado.\n\nConfigura STT_API_URL y STT_API_KEY en .env para habilitarlo.",
339
+ "stt.error": "🔴 No se pudo reconocer el audio: {error}",
340
+ "stt.empty_result": "🎤 No se detectó voz en el mensaje de audio.",
341
+ "tts.not_configured": "🔊 La síntesis de voz no está configurada.\n\nConfigura TTS_API_URL en .env para habilitarlo.\n\nRecomendado: Usa pocket-tts-server para TTS local.\nhttps://github.com/ai-joe-git/pocket-tts-server",
342
+ "tts.voice_changed": "🔊 Voz cambiada: {voice}",
343
+ "tts.voice_error": "🔴 No se pudo cambiar la voz: {error}",
344
+ "tts.fetch_voices_error": "🔴 No se pudieron obtener las voces del servidor TTS.",
345
+ "tts.synthesis_error": "🔴 Error en la síntesis de voz: {error}",
346
+ "tts.speaking": "🔊 Reproduciendo...",
347
+ "tts.menu_title": "Selecciona una voz:",
348
+ "tts.menu_current": "Voz actual: {voice}\n\nSelecciona una voz:",
349
+ "tts.menu_empty": "⚠️ No hay voces disponibles. Verifica la configuración del servidor TTS.",
350
+ "tts.menu_loading": "⏳ Cargando voces...",
351
+ "tts.menu_error": "🔴 No se pudieron cargar las voces.",
352
+ "tts.button.off": "🔇 TTS Apagado",
353
+ "tts.button.off_description": "Desactivar respuestas de voz",
354
+ "tts.button.prev_page": "⬅️ Anterior",
355
+ "tts.button.next_page": "Siguiente ➡️",
356
+ "tts.off_success": "🔇 Respuestas de voz desactivadas.",
357
+ };