@grinev/opencode-telegram-bot 0.14.1 → 0.16.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/.env.example +25 -0
- package/README.md +50 -26
- package/dist/agent/manager.js +34 -6
- package/dist/agent/types.js +7 -1
- package/dist/app/start-bot-app.js +6 -1
- package/dist/bot/assistant-run-state.js +60 -0
- package/dist/bot/commands/abort.js +2 -0
- package/dist/bot/commands/commands.js +12 -2
- package/dist/bot/commands/definitions.js +2 -0
- package/dist/bot/commands/new.js +3 -2
- package/dist/bot/commands/open.js +314 -0
- package/dist/bot/commands/projects.js +5 -37
- package/dist/bot/commands/sessions.js +3 -0
- package/dist/bot/commands/start.js +2 -0
- package/dist/bot/commands/status.js +5 -2
- package/dist/bot/commands/tts.js +13 -0
- package/dist/bot/handlers/agent.js +3 -4
- package/dist/bot/handlers/inline-menu.js +9 -1
- package/dist/bot/handlers/model.js +3 -2
- package/dist/bot/handlers/prompt.js +33 -5
- package/dist/bot/handlers/variant.js +3 -2
- package/dist/bot/index.js +179 -94
- package/dist/bot/message-patterns.js +2 -2
- package/dist/bot/streaming/response-streamer.js +26 -17
- package/dist/bot/streaming/tool-call-streamer.js +31 -24
- package/dist/bot/utils/assistant-rendering.js +117 -0
- package/dist/bot/utils/assistant-run-footer.js +9 -0
- package/dist/bot/utils/browser-roots.js +140 -0
- package/dist/bot/utils/file-tree.js +92 -0
- package/dist/bot/utils/finalize-assistant-response.js +18 -24
- package/dist/bot/utils/keyboard.js +6 -6
- package/dist/bot/utils/send-tts-response.js +37 -0
- package/dist/bot/utils/send-with-markdown-fallback.js +3 -3
- package/dist/bot/utils/switch-project.js +48 -0
- package/dist/bot/utils/telegram-text.js +95 -1
- package/dist/cli.js +4 -0
- package/dist/config.js +10 -0
- package/dist/i18n/de.js +32 -9
- package/dist/i18n/en.js +32 -9
- package/dist/i18n/es.js +32 -9
- package/dist/i18n/fr.js +32 -9
- package/dist/i18n/ru.js +32 -9
- package/dist/i18n/zh.js +32 -9
- package/dist/index.js +2 -0
- package/dist/pinned/manager.js +66 -4
- package/dist/project/manager.js +2 -1
- package/dist/settings/manager.js +7 -0
- package/dist/summary/aggregator.js +17 -1
- package/dist/summary/formatter.js +12 -89
- package/dist/telegram/render/block-fallback.js +28 -0
- package/dist/telegram/render/block-parser.js +295 -0
- package/dist/telegram/render/block-renderer.js +457 -0
- package/dist/telegram/render/chunker.js +281 -0
- package/dist/telegram/render/inline-renderer.js +128 -0
- package/dist/telegram/render/markdown-normalizer.js +94 -0
- package/dist/telegram/render/pipeline.js +9 -0
- package/dist/telegram/render/types.js +1 -0
- package/dist/telegram/render/validator.js +160 -0
- package/dist/tts/client.js +59 -0
- package/dist/utils/logger.js +200 -73
- package/package.json +6 -2
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { setCurrentProject } from "../../settings/manager.js";
|
|
2
|
+
import { clearSession } from "../../session/manager.js";
|
|
3
|
+
import { summaryAggregator } from "../../summary/aggregator.js";
|
|
4
|
+
import { pinnedMessageManager } from "../../pinned/manager.js";
|
|
5
|
+
import { keyboardManager } from "../../keyboard/manager.js";
|
|
6
|
+
import { getStoredAgent, resolveProjectAgent } from "../../agent/manager.js";
|
|
7
|
+
import { getStoredModel } from "../../model/manager.js";
|
|
8
|
+
import { formatVariantForButton } from "../../variant/manager.js";
|
|
9
|
+
import { clearAllInteractionState } from "../../interaction/cleanup.js";
|
|
10
|
+
import { createMainKeyboard } from "./keyboard.js";
|
|
11
|
+
import { logger } from "../../utils/logger.js";
|
|
12
|
+
/**
|
|
13
|
+
* Shared logic for switching the active project.
|
|
14
|
+
*
|
|
15
|
+
* Called by both `/projects` (selecting an existing project) and `/open`
|
|
16
|
+
* (browsing and adding a new directory). Performs the full state transition:
|
|
17
|
+
* persists the project, clears the session, resets the pinned message and
|
|
18
|
+
* keyboard, and returns a fresh reply keyboard for the caller to attach to
|
|
19
|
+
* its confirmation message.
|
|
20
|
+
*
|
|
21
|
+
* @param ctx grammY callback context (used for `ctx.chat` / `ctx.api`)
|
|
22
|
+
* @param project the project to switch to
|
|
23
|
+
* @param reason short tag for `clearAllInteractionState` (e.g. "project_switched")
|
|
24
|
+
*/
|
|
25
|
+
export async function switchToProject(ctx, project, reason) {
|
|
26
|
+
setCurrentProject(project);
|
|
27
|
+
clearSession();
|
|
28
|
+
summaryAggregator.clear();
|
|
29
|
+
clearAllInteractionState(reason);
|
|
30
|
+
try {
|
|
31
|
+
await pinnedMessageManager.clear();
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
logger.error("[Bot] Error clearing pinned message:", err);
|
|
35
|
+
}
|
|
36
|
+
if (ctx.chat) {
|
|
37
|
+
keyboardManager.initialize(ctx.api, ctx.chat.id);
|
|
38
|
+
}
|
|
39
|
+
await pinnedMessageManager.refreshContextLimit();
|
|
40
|
+
const contextLimit = pinnedMessageManager.getContextLimit();
|
|
41
|
+
keyboardManager.updateContext(0, contextLimit);
|
|
42
|
+
const currentAgent = await resolveProjectAgent(getStoredAgent());
|
|
43
|
+
const currentModel = getStoredModel();
|
|
44
|
+
const contextInfo = { tokensUsed: 0, tokensLimit: contextLimit };
|
|
45
|
+
const variantName = formatVariantForButton(currentModel.variant || "default");
|
|
46
|
+
keyboardManager.updateAgent(currentAgent);
|
|
47
|
+
return createMainKeyboard(currentAgent, currentModel, contextInfo, variantName);
|
|
48
|
+
}
|
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logger } from "../../utils/logger.js";
|
|
2
|
+
import { editMessageWithMarkdownFallback, isTelegramMarkdownParseError, sendMessageWithMarkdownFallback, } from "./send-with-markdown-fallback.js";
|
|
2
3
|
function resolveParseMode(format) {
|
|
3
4
|
if (format === "markdown_v2") {
|
|
4
5
|
return "MarkdownV2";
|
|
5
6
|
}
|
|
6
7
|
return undefined;
|
|
7
8
|
}
|
|
9
|
+
function stripRichFormattingOptions(options) {
|
|
10
|
+
if (!options) {
|
|
11
|
+
return options;
|
|
12
|
+
}
|
|
13
|
+
const rawOptions = {
|
|
14
|
+
...options,
|
|
15
|
+
};
|
|
16
|
+
delete rawOptions.parse_mode;
|
|
17
|
+
delete rawOptions.entities;
|
|
18
|
+
return rawOptions;
|
|
19
|
+
}
|
|
20
|
+
export function getTelegramRenderedPartSignature(part) {
|
|
21
|
+
return `${part.text}\n${JSON.stringify(part.entities ?? null)}`;
|
|
22
|
+
}
|
|
8
23
|
export async function sendBotText({ api, chatId, text, rawFallbackText, options, format = "raw", }) {
|
|
9
24
|
await sendMessageWithMarkdownFallback({
|
|
10
25
|
api,
|
|
@@ -15,6 +30,85 @@ export async function sendBotText({ api, chatId, text, rawFallbackText, options,
|
|
|
15
30
|
parseMode: resolveParseMode(format),
|
|
16
31
|
});
|
|
17
32
|
}
|
|
33
|
+
export async function sendRenderedBotPart({ api, chatId, part, options, }) {
|
|
34
|
+
const rawOptions = stripRichFormattingOptions(options);
|
|
35
|
+
logger.debug("[Bot] Sending rendered Telegram part", {
|
|
36
|
+
source: part.source,
|
|
37
|
+
textLength: part.text.length,
|
|
38
|
+
fallbackTextLength: part.fallbackText.length,
|
|
39
|
+
entityCount: part.entities?.length ?? 0,
|
|
40
|
+
});
|
|
41
|
+
if (!part.entities?.length) {
|
|
42
|
+
const sentMessage = await api.sendMessage(chatId, part.text, rawOptions);
|
|
43
|
+
return {
|
|
44
|
+
messageId: sentMessage.message_id,
|
|
45
|
+
deliveredSignature: getTelegramRenderedPartSignature({ text: part.text }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const sentMessage = await api.sendMessage(chatId, part.text, {
|
|
50
|
+
...(rawOptions || {}),
|
|
51
|
+
entities: part.entities,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
messageId: sentMessage.message_id,
|
|
55
|
+
deliveredSignature: getTelegramRenderedPartSignature(part),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (!isTelegramMarkdownParseError(error)) {
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
logger.warn("[Bot] Entity payload rejected, retrying assistant message part in raw mode", error);
|
|
63
|
+
const sentMessage = await api.sendMessage(chatId, part.fallbackText, rawOptions);
|
|
64
|
+
logger.debug("[Bot] Assistant message part sent in raw fallback mode", {
|
|
65
|
+
fallbackTextLength: part.fallbackText.length,
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
messageId: sentMessage.message_id,
|
|
69
|
+
deliveredSignature: getTelegramRenderedPartSignature({ text: part.fallbackText }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function editRenderedBotPart({ api, chatId, messageId, part, options, }) {
|
|
74
|
+
const rawOptions = stripRichFormattingOptions(options);
|
|
75
|
+
logger.debug("[Bot] Editing rendered Telegram part", {
|
|
76
|
+
messageId,
|
|
77
|
+
source: part.source,
|
|
78
|
+
textLength: part.text.length,
|
|
79
|
+
fallbackTextLength: part.fallbackText.length,
|
|
80
|
+
entityCount: part.entities?.length ?? 0,
|
|
81
|
+
});
|
|
82
|
+
if (!part.entities?.length) {
|
|
83
|
+
await api.editMessageText(chatId, messageId, part.text, rawOptions);
|
|
84
|
+
return {
|
|
85
|
+
deliveredSignature: getTelegramRenderedPartSignature({ text: part.text }),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await api.editMessageText(chatId, messageId, part.text, {
|
|
90
|
+
...(rawOptions || {}),
|
|
91
|
+
entities: part.entities,
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
deliveredSignature: getTelegramRenderedPartSignature(part),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (!isTelegramMarkdownParseError(error)) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
logger.warn("[Bot] Entity payload rejected, retrying assistant edit part in raw mode", error);
|
|
102
|
+
await api.editMessageText(chatId, messageId, part.fallbackText, rawOptions);
|
|
103
|
+
logger.debug("[Bot] Assistant edit part applied in raw fallback mode", {
|
|
104
|
+
messageId,
|
|
105
|
+
fallbackTextLength: part.fallbackText.length,
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
deliveredSignature: getTelegramRenderedPartSignature({ text: part.fallbackText }),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
18
112
|
export async function editBotText({ api, chatId, messageId, text, rawFallbackText, options, format = "raw", }) {
|
|
19
113
|
await editMessageWithMarkdownFallback({
|
|
20
114
|
api,
|
package/dist/cli.js
CHANGED
|
@@ -32,6 +32,8 @@ async function runStartCommand(mode) {
|
|
|
32
32
|
throw new Error(modeResult.error);
|
|
33
33
|
}
|
|
34
34
|
setRuntimeMode(modeResult.mode);
|
|
35
|
+
const { initializeLogger } = await import("./utils/logger.js");
|
|
36
|
+
await initializeLogger();
|
|
35
37
|
const { ensureRuntimeConfigForStart } = await import("./runtime/bootstrap.js");
|
|
36
38
|
await ensureRuntimeConfigForStart();
|
|
37
39
|
const { startBotApp } = await import("./app/start-bot-app.js");
|
|
@@ -40,6 +42,8 @@ async function runStartCommand(mode) {
|
|
|
40
42
|
}
|
|
41
43
|
async function runConfigCommand() {
|
|
42
44
|
setRuntimeMode("installed");
|
|
45
|
+
const { initializeLogger } = await import("./utils/logger.js");
|
|
46
|
+
await initializeLogger();
|
|
43
47
|
const { runConfigWizardCommand } = await import("./runtime/bootstrap.js");
|
|
44
48
|
await runConfigWizardCommand();
|
|
45
49
|
return EXIT_SUCCESS;
|
package/dist/config.js
CHANGED
|
@@ -74,6 +74,7 @@ export const config = {
|
|
|
74
74
|
commandsListLimit: getOptionalPositiveIntEnvVar("COMMANDS_LIST_LIMIT", 10),
|
|
75
75
|
taskLimit: getOptionalPositiveIntEnvVar("TASK_LIMIT", 10),
|
|
76
76
|
responseStreamThrottleMs: getOptionalPositiveIntEnvVar("RESPONSE_STREAM_THROTTLE_MS", 500),
|
|
77
|
+
bashToolDisplayMaxLength: getOptionalPositiveIntEnvVar("BASH_TOOL_DISPLAY_MAX_LENGTH", 128),
|
|
77
78
|
locale: getOptionalLocaleEnvVar("BOT_LOCALE", "en"),
|
|
78
79
|
hideThinkingMessages: getOptionalBooleanEnvVar("HIDE_THINKING_MESSAGES", false),
|
|
79
80
|
hideToolCallMessages: getOptionalBooleanEnvVar("HIDE_TOOL_CALL_MESSAGES", false),
|
|
@@ -82,10 +83,19 @@ export const config = {
|
|
|
82
83
|
files: {
|
|
83
84
|
maxFileSizeKb: parseInt(getEnvVar("CODE_FILE_MAX_SIZE_KB", false) || "100", 10),
|
|
84
85
|
},
|
|
86
|
+
open: {
|
|
87
|
+
browserRoots: getEnvVar("OPEN_BROWSER_ROOTS", false),
|
|
88
|
+
},
|
|
85
89
|
stt: {
|
|
86
90
|
apiUrl: getEnvVar("STT_API_URL", false),
|
|
87
91
|
apiKey: getEnvVar("STT_API_KEY", false),
|
|
88
92
|
model: getEnvVar("STT_MODEL", false) || "whisper-large-v3-turbo",
|
|
89
93
|
language: getEnvVar("STT_LANGUAGE", false),
|
|
90
94
|
},
|
|
95
|
+
tts: {
|
|
96
|
+
apiUrl: getEnvVar("TTS_API_URL", false),
|
|
97
|
+
apiKey: getEnvVar("TTS_API_KEY", false),
|
|
98
|
+
model: getEnvVar("TTS_MODEL", false) || "gpt-4o-mini-tts",
|
|
99
|
+
voice: getEnvVar("TTS_VOICE", false) || "alloy",
|
|
100
|
+
},
|
|
91
101
|
};
|
package/dist/i18n/de.js
CHANGED
|
@@ -3,6 +3,7 @@ export const de = {
|
|
|
3
3
|
"cmd.description.new": "Neue Sitzung erstellen",
|
|
4
4
|
"cmd.description.stop": "Aktuelle Aktion stoppen",
|
|
5
5
|
"cmd.description.sessions": "Sitzungen auflisten",
|
|
6
|
+
"cmd.description.tts": "Audioantworten umschalten",
|
|
6
7
|
"cmd.description.projects": "Projekte auflisten",
|
|
7
8
|
"cmd.description.task": "Geplante Aufgabe erstellen",
|
|
8
9
|
"cmd.description.tasklist": "Geplante Aufgaben anzeigen",
|
|
@@ -32,8 +33,8 @@ export const de = {
|
|
|
32
33
|
"inline.cancelled_callback": "Abgebrochen",
|
|
33
34
|
"common.unknown": "unbekannt",
|
|
34
35
|
"common.unknown_error": "unbekannter Fehler",
|
|
35
|
-
"start.welcome": "👋 Willkommen beim OpenCode Telegram Bot!\n\nNutze Befehle:\n/projects — Projekt auswählen\n/sessions — Sitzungsliste\n/new — neue Sitzung\n/task — geplante Aufgabe\n/tasklist — geplante Aufgaben\n/status — Status\n/help — Hilfe\n\nNutze die unteren Buttons, um
|
|
36
|
-
"help.keyboard_hint": "💡 Nutze die unteren Buttons für
|
|
36
|
+
"start.welcome": "👋 Willkommen beim OpenCode Telegram Bot!\n\nNutze Befehle:\n/projects — Projekt auswählen\n/sessions — Sitzungsliste\n/new — neue Sitzung\n/task — geplante Aufgabe\n/tasklist — geplante Aufgaben\n/status — Status\n/help — Hilfe\n\nNutze die unteren Buttons, um Agent, Modell und Variante zu wählen.",
|
|
37
|
+
"help.keyboard_hint": "💡 Nutze die unteren Buttons für Agent, Modell, Variante und Kontextaktionen.",
|
|
37
38
|
"help.text": "📖 **Hilfe**\n\n/status - Serverstatus prüfen\n/sessions - Sitzungsliste\n/new - Neue Sitzung erstellen\n/help - Hilfe",
|
|
38
39
|
"bot.thinking": "💭 Denke...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Projekt ist nicht ausgewählt.\n\nWähle zuerst ein Projekt mit /projects.",
|
|
@@ -65,8 +66,11 @@ export const de = {
|
|
|
65
66
|
"status.line.managed_no": "Vom Bot gestartet: Nein",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Betriebszeit: {seconds} s",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent: {mode}",
|
|
69
70
|
"status.line.model": "Modell: {model}",
|
|
71
|
+
"status.line.tts": "TTS-Antworten: {tts}",
|
|
72
|
+
"status.tts.on": "Ein",
|
|
73
|
+
"status.tts.off": "Aus",
|
|
70
74
|
"status.agent_not_set": "nicht gesetzt",
|
|
71
75
|
"status.project_selected": "Projekt: {project}",
|
|
72
76
|
"status.project_not_selected": "Projekt: nicht ausgewählt",
|
|
@@ -75,6 +79,10 @@ export const de = {
|
|
|
75
79
|
"status.session_not_selected": "Aktuelle Sitzung: nicht ausgewählt",
|
|
76
80
|
"status.session_hint": "Nutze /sessions zur Auswahl oder /new zum Erstellen",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode-Server ist nicht verfügbar\n\nNutze /opencode_start, um den Server zu starten.",
|
|
82
|
+
"tts.enabled": "🔊 Audioantworten global aktiviert.",
|
|
83
|
+
"tts.not_configured": "⚠️ Audioantworten sind nicht verfugbar. Setze zuerst `TTS_API_URL` und `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Audioantworten global deaktiviert.",
|
|
85
|
+
"tts.failed": "⚠️ Audioreply konnte nicht erzeugt werden.",
|
|
78
86
|
"projects.empty": "📭 Keine Projekte gefunden.\n\nÖffne ein Verzeichnis in OpenCode und erstelle mindestens eine Sitzung, dann erscheint es hier.",
|
|
79
87
|
"projects.select": "Projekt auswählen:",
|
|
80
88
|
"projects.select_with_current": "Projekt auswählen:\n\nAktuell: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const de = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 OpenCode-Server konnte nicht gestoppt werden\n\nFehler: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode-Server erfolgreich gestoppt",
|
|
129
137
|
"opencode_stop.error": "🔴 Beim Stoppen des Servers ist ein Fehler aufgetreten.\n\nSiehe Anwendungslogs für Details.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "
|
|
133
|
-
"agent.menu.current": "Aktueller
|
|
134
|
-
"agent.menu.select": "
|
|
138
|
+
"agent.changed_callback": "Agent geändert: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent geändert zu: {name}",
|
|
140
|
+
"agent.change_error_callback": "Agent konnte nicht geändert werden",
|
|
141
|
+
"agent.menu.current": "Aktueller Agent: {name}\n\nAgent auswählen:",
|
|
142
|
+
"agent.menu.select": "Agent auswählen:",
|
|
135
143
|
"agent.menu.empty": "⚠️ Keine verfügbaren Agenten",
|
|
136
144
|
"agent.menu.error": "🔴 Agentenliste konnte nicht geladen werden",
|
|
137
145
|
"model.changed_callback": "Modell geändert: {name}",
|
|
@@ -205,7 +213,7 @@ export const de = {
|
|
|
205
213
|
"question.summary.title": "✅ Umfrage abgeschlossen!\n\n",
|
|
206
214
|
"question.summary.question": "Frage {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Antwort:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji} {name}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
|
@@ -337,4 +345,19 @@ export const de = {
|
|
|
337
345
|
"stt.not_configured": "🎤 Spracherkennung ist nicht konfiguriert.\n\nSetze STT_API_URL und STT_API_KEY in .env, um sie zu aktivieren.",
|
|
338
346
|
"stt.error": "🔴 Audio konnte nicht erkannt werden: {error}",
|
|
339
347
|
"stt.empty_result": "🎤 Keine Sprache in der Audionachricht erkannt.",
|
|
348
|
+
"cmd.description.open": "Projekt durch Ordner-Auswahl hinzufügen",
|
|
349
|
+
"open.back": "⬆️ Hoch",
|
|
350
|
+
"open.roots": "📋 Zurück zur Auswahl",
|
|
351
|
+
"open.prev_page": "⬅️ Zurück",
|
|
352
|
+
"open.next_page": "Weiter ➡️",
|
|
353
|
+
"open.select_current": "✅ Diesen Ordner wählen",
|
|
354
|
+
"open.select_root": "📂 Stammverzeichnis zum Durchsuchen wählen:",
|
|
355
|
+
"open.access_denied": "⛔ Zugriff verweigert: Pfad liegt außerhalb erlaubter Verzeichnisse",
|
|
356
|
+
"open.scan_error": "🔴 Verzeichnis kann nicht durchsucht werden: {error}",
|
|
357
|
+
"open.open_error": "🔴 Verzeichnisbrowser konnte nicht geöffnet werden.",
|
|
358
|
+
"open.selected": "✅ Projekt hinzugefügt: {project}\n\n📋 Verwende /sessions oder /new zum Arbeiten.",
|
|
359
|
+
"open.select_error": "🔴 Projekt konnte nicht hinzugefügt werden.",
|
|
360
|
+
"open.no_subfolders": "📭 Keine Unterordner",
|
|
361
|
+
"open.subfolder_count": "{count} Unterordner",
|
|
362
|
+
"open.subfolders_count": "{count} Unterordner",
|
|
340
363
|
};
|
package/dist/i18n/en.js
CHANGED
|
@@ -3,6 +3,7 @@ export const en = {
|
|
|
3
3
|
"cmd.description.new": "Create a new session",
|
|
4
4
|
"cmd.description.stop": "Stop current action",
|
|
5
5
|
"cmd.description.sessions": "List sessions",
|
|
6
|
+
"cmd.description.tts": "Toggle audio replies",
|
|
6
7
|
"cmd.description.projects": "List projects",
|
|
7
8
|
"cmd.description.task": "Create a scheduled task",
|
|
8
9
|
"cmd.description.tasklist": "List scheduled tasks",
|
|
@@ -32,8 +33,8 @@ export const en = {
|
|
|
32
33
|
"inline.cancelled_callback": "Cancelled",
|
|
33
34
|
"common.unknown": "unknown",
|
|
34
35
|
"common.unknown_error": "unknown error",
|
|
35
|
-
"start.welcome": "👋 Welcome to OpenCode Telegram Bot!\n\nUse commands:\n/projects — select project\n/sessions — session list\n/new — new session\n/task — scheduled task\n/tasklist — scheduled tasks\n/status — status\n/help — help\n\nUse the bottom buttons to select agent
|
|
36
|
-
"help.keyboard_hint": "💡 Use the bottom keyboard buttons for agent
|
|
36
|
+
"start.welcome": "👋 Welcome to OpenCode Telegram Bot!\n\nUse commands:\n/projects — select project\n/sessions — session list\n/new — new session\n/task — scheduled task\n/tasklist — scheduled tasks\n/status — status\n/help — help\n\nUse the bottom buttons to select the agent, model, and variant.",
|
|
37
|
+
"help.keyboard_hint": "💡 Use the bottom keyboard buttons for the agent, model, variant, and context actions.",
|
|
37
38
|
"help.text": "📖 **Help**\n\n/status - Check server status\n/sessions - Session list\n/new - Create new session\n/help - Help",
|
|
38
39
|
"bot.thinking": "💭 Thinking...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Project is not selected.\n\nFirst select a project with /projects.",
|
|
@@ -65,8 +66,11 @@ export const en = {
|
|
|
65
66
|
"status.line.managed_no": "Started by bot: No",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Uptime: {seconds} sec",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent: {mode}",
|
|
69
70
|
"status.line.model": "Model: {model}",
|
|
71
|
+
"status.line.tts": "TTS replies: {tts}",
|
|
72
|
+
"status.tts.on": "On",
|
|
73
|
+
"status.tts.off": "Off",
|
|
70
74
|
"status.agent_not_set": "not set",
|
|
71
75
|
"status.project_selected": "Project: {project}",
|
|
72
76
|
"status.project_not_selected": "Project: not selected",
|
|
@@ -75,6 +79,10 @@ export const en = {
|
|
|
75
79
|
"status.session_not_selected": "Current session: not selected",
|
|
76
80
|
"status.session_hint": "Use /sessions to select one or /new to create one",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode Server is unavailable\n\nUse /opencode_start to start the server.",
|
|
82
|
+
"tts.enabled": "🔊 Audio replies enabled globally.",
|
|
83
|
+
"tts.not_configured": "⚠️ Audio replies are unavailable. Set `TTS_API_URL` and `TTS_API_KEY` first.",
|
|
84
|
+
"tts.disabled": "🔇 Audio replies disabled globally.",
|
|
85
|
+
"tts.failed": "⚠️ Failed to generate audio reply.",
|
|
78
86
|
"projects.empty": "📭 No projects found.\n\nOpen a directory in OpenCode and create at least one session, then it will appear here.",
|
|
79
87
|
"projects.select": "Select a project:",
|
|
80
88
|
"projects.select_with_current": "Select a project:\n\nCurrent: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const en = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 Failed to stop OpenCode Server\n\nError: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode Server stopped successfully",
|
|
129
137
|
"opencode_stop.error": "🔴 An error occurred while stopping server.\n\nCheck application logs for details.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "Failed to change
|
|
133
|
-
"agent.menu.current": "Current
|
|
134
|
-
"agent.menu.select": "Select
|
|
138
|
+
"agent.changed_callback": "Agent changed: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent changed to: {name}",
|
|
140
|
+
"agent.change_error_callback": "Failed to change agent",
|
|
141
|
+
"agent.menu.current": "Current agent: {name}\n\nSelect agent:",
|
|
142
|
+
"agent.menu.select": "Select agent:",
|
|
135
143
|
"agent.menu.empty": "⚠️ No available agents",
|
|
136
144
|
"agent.menu.error": "🔴 Failed to get agents list",
|
|
137
145
|
"model.changed_callback": "Model changed: {name}",
|
|
@@ -205,7 +213,7 @@ export const en = {
|
|
|
205
213
|
"question.summary.title": "✅ Poll completed!\n\n",
|
|
206
214
|
"question.summary.question": "Question {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Answer:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji} {name}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
|
@@ -337,4 +345,19 @@ export const en = {
|
|
|
337
345
|
"stt.not_configured": "🎤 Voice recognition is not configured.\n\nSet STT_API_URL and STT_API_KEY in .env to enable it.",
|
|
338
346
|
"stt.error": "🔴 Failed to recognize audio: {error}",
|
|
339
347
|
"stt.empty_result": "🎤 No speech detected in the audio message.",
|
|
348
|
+
"cmd.description.open": "Add a project by browsing directories",
|
|
349
|
+
"open.back": "⬆️ Up",
|
|
350
|
+
"open.roots": "📋 Back to roots",
|
|
351
|
+
"open.prev_page": "⬅️ Previous",
|
|
352
|
+
"open.next_page": "Next ➡️",
|
|
353
|
+
"open.select_current": "✅ Select this folder",
|
|
354
|
+
"open.select_root": "📂 Select a root directory to browse:",
|
|
355
|
+
"open.access_denied": "⛔ Access denied: path is outside allowed roots",
|
|
356
|
+
"open.scan_error": "🔴 Cannot browse directory: {error}",
|
|
357
|
+
"open.open_error": "🔴 Failed to open directory browser.",
|
|
358
|
+
"open.selected": "✅ Project added: {project}\n\n📋 Use /sessions or /new to start working.",
|
|
359
|
+
"open.select_error": "🔴 Failed to add project.",
|
|
360
|
+
"open.no_subfolders": "📭 No subfolders",
|
|
361
|
+
"open.subfolder_count": "{count} subfolder",
|
|
362
|
+
"open.subfolders_count": "{count} subfolders",
|
|
340
363
|
};
|
package/dist/i18n/es.js
CHANGED
|
@@ -3,6 +3,7 @@ export const es = {
|
|
|
3
3
|
"cmd.description.new": "Crear una sesión nueva",
|
|
4
4
|
"cmd.description.stop": "Detener la acción actual",
|
|
5
5
|
"cmd.description.sessions": "Listar sesiones",
|
|
6
|
+
"cmd.description.tts": "Alternar respuestas de audio",
|
|
6
7
|
"cmd.description.projects": "Listar proyectos",
|
|
7
8
|
"cmd.description.task": "Crear tarea programada",
|
|
8
9
|
"cmd.description.tasklist": "Ver tareas programadas",
|
|
@@ -32,8 +33,8 @@ export const es = {
|
|
|
32
33
|
"inline.cancelled_callback": "Cancelado",
|
|
33
34
|
"common.unknown": "desconocido",
|
|
34
35
|
"common.unknown_error": "error desconocido",
|
|
35
|
-
"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
|
|
36
|
-
"help.keyboard_hint": "💡 Usa los botones inferiores para
|
|
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 agente, modelo y variante.",
|
|
37
|
+
"help.keyboard_hint": "💡 Usa los botones inferiores para agente, modelo, variante y acciones de contexto.",
|
|
37
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",
|
|
38
39
|
"bot.thinking": "💭 Pensando...",
|
|
39
40
|
"bot.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
|
|
@@ -65,8 +66,11 @@ export const es = {
|
|
|
65
66
|
"status.line.managed_no": "Iniciado por el bot: No",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Tiempo activo: {seconds} s",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agente: {mode}",
|
|
69
70
|
"status.line.model": "Modelo: {model}",
|
|
71
|
+
"status.line.tts": "Respuestas TTS: {tts}",
|
|
72
|
+
"status.tts.on": "Activadas",
|
|
73
|
+
"status.tts.off": "Desactivadas",
|
|
70
74
|
"status.agent_not_set": "no configurado",
|
|
71
75
|
"status.project_selected": "Proyecto: {project}",
|
|
72
76
|
"status.project_not_selected": "Proyecto: no seleccionado",
|
|
@@ -75,6 +79,10 @@ export const es = {
|
|
|
75
79
|
"status.session_not_selected": "Sesión actual: no seleccionada",
|
|
76
80
|
"status.session_hint": "Usa /sessions para elegir una o /new para crear una",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode Server no está disponible\n\nUsa /opencode_start para iniciar el servidor.",
|
|
82
|
+
"tts.enabled": "🔊 Respuestas de audio activadas globalmente.",
|
|
83
|
+
"tts.not_configured": "⚠️ Las respuestas de audio no estan disponibles. Configura primero `TTS_API_URL` y `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Respuestas de audio desactivadas globalmente.",
|
|
85
|
+
"tts.failed": "⚠️ No se pudo generar la respuesta de audio.",
|
|
78
86
|
"projects.empty": "📭 No se encontraron proyectos.\n\nAbre un directorio en OpenCode y crea al menos una sesión; entonces aparecerá aquí.",
|
|
79
87
|
"projects.select": "Selecciona un proyecto:",
|
|
80
88
|
"projects.select_with_current": "Selecciona un proyecto:\n\nActual: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const es = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 No se pudo detener OpenCode Server\n\nError: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode Server detenido correctamente",
|
|
129
137
|
"opencode_stop.error": "🔴 Ocurrió un error al detener el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "No se pudo cambiar el
|
|
133
|
-
"agent.menu.current": "
|
|
134
|
-
"agent.menu.select": "Selecciona el
|
|
138
|
+
"agent.changed_callback": "Agente cambiado: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agente cambiado a: {name}",
|
|
140
|
+
"agent.change_error_callback": "No se pudo cambiar el agente",
|
|
141
|
+
"agent.menu.current": "Agente actual: {name}\n\nSelecciona el agente:",
|
|
142
|
+
"agent.menu.select": "Selecciona el agente:",
|
|
135
143
|
"agent.menu.empty": "⚠️ No hay agentes disponibles",
|
|
136
144
|
"agent.menu.error": "🔴 No se pudo obtener la lista de agentes",
|
|
137
145
|
"model.changed_callback": "Modelo cambiado: {name}",
|
|
@@ -205,7 +213,7 @@ export const es = {
|
|
|
205
213
|
"question.summary.title": "✅ ¡Encuesta completada!\n\n",
|
|
206
214
|
"question.summary.question": "Pregunta {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Respuesta:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
|
@@ -337,4 +345,19 @@ export const es = {
|
|
|
337
345
|
"stt.not_configured": "🎤 El reconocimiento de voz no está configurado.\n\nConfigura STT_API_URL y STT_API_KEY en .env para habilitarlo.",
|
|
338
346
|
"stt.error": "🔴 No se pudo reconocer el audio: {error}",
|
|
339
347
|
"stt.empty_result": "🎤 No se detectó voz en el mensaje de audio.",
|
|
348
|
+
"cmd.description.open": "Añadir proyecto navegando directorios",
|
|
349
|
+
"open.back": "⬆️ Subir",
|
|
350
|
+
"open.roots": "📋 Volver a raíces",
|
|
351
|
+
"open.prev_page": "⬅️ Anterior",
|
|
352
|
+
"open.next_page": "Siguiente ➡️",
|
|
353
|
+
"open.select_current": "✅ Seleccionar esta carpeta",
|
|
354
|
+
"open.select_root": "📂 Selecciona un directorio raíz para explorar:",
|
|
355
|
+
"open.access_denied": "⛔ Acceso denegado: la ruta está fuera de los directorios permitidos",
|
|
356
|
+
"open.scan_error": "🔴 No se puede explorar el directorio: {error}",
|
|
357
|
+
"open.open_error": "🔴 No se pudo abrir el explorador de directorios.",
|
|
358
|
+
"open.selected": "✅ Proyecto añadido: {project}\n\n📋 Usa /sessions o /new para empezar a trabajar.",
|
|
359
|
+
"open.select_error": "🔴 No se pudo añadir el proyecto.",
|
|
360
|
+
"open.no_subfolders": "📭 Sin subcarpetas",
|
|
361
|
+
"open.subfolder_count": "{count} subcarpeta",
|
|
362
|
+
"open.subfolders_count": "{count} subcarpetas",
|
|
340
363
|
};
|
package/dist/i18n/fr.js
CHANGED
|
@@ -3,6 +3,7 @@ export const fr = {
|
|
|
3
3
|
"cmd.description.new": "Créer une nouvelle session",
|
|
4
4
|
"cmd.description.stop": "Arrêter l'action en cours",
|
|
5
5
|
"cmd.description.sessions": "Lister les sessions",
|
|
6
|
+
"cmd.description.tts": "Basculer les réponses audio",
|
|
6
7
|
"cmd.description.projects": "Lister les projets",
|
|
7
8
|
"cmd.description.task": "Créer une tâche planifiée",
|
|
8
9
|
"cmd.description.tasklist": "Afficher les tâches planifiées",
|
|
@@ -32,8 +33,8 @@ export const fr = {
|
|
|
32
33
|
"inline.cancelled_callback": "Annulé",
|
|
33
34
|
"common.unknown": "inconnu",
|
|
34
35
|
"common.unknown_error": "erreur inconnue",
|
|
35
|
-
"start.welcome": "👋 Bienvenue dans OpenCode Telegram Bot !\n\nUtilisez les commandes :\n/projects — sélectionner un projet\n/sessions — liste des sessions\n/new — nouvelle session\n/task — tâche planifiée\n/tasklist — tâches planifiées\n/status — statut\n/help — aide\n\nUtilisez les boutons du bas pour choisir
|
|
36
|
-
"help.keyboard_hint": "💡 Utilisez les boutons du bas pour
|
|
36
|
+
"start.welcome": "👋 Bienvenue dans OpenCode Telegram Bot !\n\nUtilisez les commandes :\n/projects — sélectionner un projet\n/sessions — liste des sessions\n/new — nouvelle session\n/task — tâche planifiée\n/tasklist — tâches planifiées\n/status — statut\n/help — aide\n\nUtilisez les boutons du bas pour choisir l'agent, le modèle et la variante.",
|
|
37
|
+
"help.keyboard_hint": "💡 Utilisez les boutons du bas pour l'agent, le modèle, la variante et les actions de contexte.",
|
|
37
38
|
"help.text": "📖 **Aide**\n\n/status - Vérifier l'état du serveur\n/sessions - Liste des sessions\n/new - Créer une nouvelle session\n/help - Aide",
|
|
38
39
|
"bot.thinking": "💭 Réflexion en cours...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Aucun projet n'est sélectionné.\n\nSélectionnez d'abord un projet avec /projects.",
|
|
@@ -65,8 +66,11 @@ export const fr = {
|
|
|
65
66
|
"status.line.managed_no": "Démarré par le bot : Non",
|
|
66
67
|
"status.line.pid": "PID : {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Temps de fonctionnement : {seconds} sec",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent : {mode}",
|
|
69
70
|
"status.line.model": "Modèle : {model}",
|
|
71
|
+
"status.line.tts": "Réponses TTS : {tts}",
|
|
72
|
+
"status.tts.on": "Activées",
|
|
73
|
+
"status.tts.off": "Désactivées",
|
|
70
74
|
"status.agent_not_set": "non défini",
|
|
71
75
|
"status.project_selected": "Projet : {project}",
|
|
72
76
|
"status.project_not_selected": "Projet : non sélectionné",
|
|
@@ -75,6 +79,10 @@ export const fr = {
|
|
|
75
79
|
"status.session_not_selected": "Session actuelle : non sélectionnée",
|
|
76
80
|
"status.session_hint": "Utilisez /sessions pour en sélectionner une ou /new pour en créer une",
|
|
77
81
|
"status.server_unavailable": "🔴 Le serveur OpenCode est indisponible\n\nUtilisez /opencode_start pour démarrer le serveur.",
|
|
82
|
+
"tts.enabled": "🔊 Réponses audio activées globalement.",
|
|
83
|
+
"tts.not_configured": "⚠️ Les réponses audio ne sont pas disponibles. Définissez d'abord `TTS_API_URL` et `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Réponses audio désactivées globalement.",
|
|
85
|
+
"tts.failed": "⚠️ Impossible de générer la réponse audio.",
|
|
78
86
|
"projects.empty": "📭 Aucun projet trouvé.\n\nOuvrez un répertoire dans OpenCode et créez au moins une session, il apparaîtra ensuite ici.",
|
|
79
87
|
"projects.select": "Sélectionnez un projet :",
|
|
80
88
|
"projects.select_with_current": "Sélectionnez un projet :\n\nActuel : 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const fr = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 Impossible d'arrêter le serveur OpenCode\n\nErreur : {error}",
|
|
128
136
|
"opencode_stop.success": "✅ Serveur OpenCode arrêté avec succès",
|
|
129
137
|
"opencode_stop.error": "🔴 Une erreur s'est produite lors de l'arrêt du serveur.\n\nConsultez les logs de l'application pour plus de détails.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "Impossible de modifier
|
|
133
|
-
"agent.menu.current": "
|
|
134
|
-
"agent.menu.select": "Sélectionnez un
|
|
138
|
+
"agent.changed_callback": "Agent modifié : {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent défini sur : {name}",
|
|
140
|
+
"agent.change_error_callback": "Impossible de modifier l'agent",
|
|
141
|
+
"agent.menu.current": "Agent actuel : {name}\n\nSélectionnez un agent :",
|
|
142
|
+
"agent.menu.select": "Sélectionnez un agent :",
|
|
135
143
|
"agent.menu.empty": "⚠️ Aucun mode disponible",
|
|
136
144
|
"agent.menu.error": "🔴 Impossible de récupérer la liste des modes",
|
|
137
145
|
"model.changed_callback": "Modèle modifié : {name}",
|
|
@@ -205,7 +213,7 @@ export const fr = {
|
|
|
205
213
|
"question.summary.title": "✅ Sondage terminé !\n\n",
|
|
206
214
|
"question.summary.question": "Question {index} :\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Réponse :\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
|
@@ -337,4 +345,19 @@ export const fr = {
|
|
|
337
345
|
"stt.not_configured": "🎤 La reconnaissance vocale n'est pas configurée.\n\nDéfinissez STT_API_URL et STT_API_KEY dans .env pour l'activer.",
|
|
338
346
|
"stt.error": "🔴 Impossible de reconnaître l'audio : {error}",
|
|
339
347
|
"stt.empty_result": "🎤 Aucune parole détectée dans le message audio.",
|
|
348
|
+
"cmd.description.open": "Ajouter un projet en parcourant les dossiers",
|
|
349
|
+
"open.back": "⬆️ Remonter",
|
|
350
|
+
"open.roots": "📋 Retour aux racines",
|
|
351
|
+
"open.prev_page": "⬅️ Précédent",
|
|
352
|
+
"open.next_page": "Suivant ➡️",
|
|
353
|
+
"open.select_current": "✅ Sélectionner ce dossier",
|
|
354
|
+
"open.select_root": "📂 Sélectionnez un répertoire racine à parcourir :",
|
|
355
|
+
"open.access_denied": "⛔ Accès refusé : le chemin est en dehors des répertoires autorisés",
|
|
356
|
+
"open.scan_error": "🔴 Impossible de parcourir le répertoire : {error}",
|
|
357
|
+
"open.open_error": "🔴 Impossible d'ouvrir l'explorateur de répertoires.",
|
|
358
|
+
"open.selected": "✅ Projet ajouté : {project}\n\n📋 Utilisez /sessions ou /new pour commencer.",
|
|
359
|
+
"open.select_error": "🔴 Impossible d'ajouter le projet.",
|
|
360
|
+
"open.no_subfolders": "📭 Aucun sous-dossier",
|
|
361
|
+
"open.subfolder_count": "{count} sous-dossier",
|
|
362
|
+
"open.subfolders_count": "{count} sous-dossiers",
|
|
340
363
|
};
|