@grinev/opencode-telegram-bot 0.16.1 → 0.17.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 +5 -0
- package/README.md +57 -42
- package/dist/app/start-bot-app.js +0 -2
- package/dist/bot/commands/definitions.js +2 -0
- package/dist/bot/commands/opencode-start.js +27 -24
- package/dist/bot/commands/opencode-stop.js +51 -23
- package/dist/bot/commands/projects.js +30 -6
- package/dist/bot/commands/skills.js +376 -0
- package/dist/bot/commands/status.js +21 -14
- package/dist/bot/commands/worktree.js +196 -0
- package/dist/bot/handlers/inline-menu.js +1 -0
- package/dist/bot/handlers/voice.js +8 -1
- package/dist/bot/index.js +14 -2
- package/dist/config.js +2 -0
- package/dist/git/worktree.js +158 -0
- package/dist/i18n/de.js +39 -1
- package/dist/i18n/en.js +39 -1
- package/dist/i18n/es.js +39 -1
- package/dist/i18n/fr.js +39 -1
- package/dist/i18n/ru.js +39 -1
- package/dist/i18n/zh.js +39 -1
- package/dist/opencode/process.js +182 -0
- package/dist/pinned/manager.js +28 -61
- package/dist/project/manager.js +47 -32
- package/dist/runtime/bootstrap.js +119 -7
- package/dist/scheduled-task/executor.js +137 -7
- package/dist/settings/manager.js +9 -12
- package/package.json +1 -1
- package/dist/process/manager.js +0 -273
- package/dist/process/types.js +0 -1
package/dist/bot/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { AGENT_MODE_BUTTON_TEXT_PATTERN, MODEL_BUTTON_TEXT_PATTERN, VARIANT_BUTT
|
|
|
16
16
|
import { sessionsCommand, handleSessionSelect } from "./commands/sessions.js";
|
|
17
17
|
import { newCommand } from "./commands/new.js";
|
|
18
18
|
import { projectsCommand, handleProjectSelect } from "./commands/projects.js";
|
|
19
|
+
import { worktreeCommand, handleWorktreeCallback } from "./commands/worktree.js";
|
|
19
20
|
import { openCommand, handleOpenCallback, clearOpenPathIndex } from "./commands/open.js";
|
|
20
21
|
import { abortCommand } from "./commands/abort.js";
|
|
21
22
|
import { opencodeStartCommand } from "./commands/opencode-start.js";
|
|
@@ -24,6 +25,7 @@ import { renameCommand, handleRenameCancel, handleRenameTextAnswer } from "./com
|
|
|
24
25
|
import { handleTaskCallback, handleTaskTextInput, taskCommand } from "./commands/task.js";
|
|
25
26
|
import { handleTaskListCallback, taskListCommand } from "./commands/tasklist.js";
|
|
26
27
|
import { commandsCommand, handleCommandsCallback, handleCommandTextArguments, } from "./commands/commands.js";
|
|
28
|
+
import { skillsCommand, handleSkillsCallback, handleSkillTextArguments, } from "./commands/skills.js";
|
|
27
29
|
import { ttsCommand } from "./commands/tts.js";
|
|
28
30
|
import { handleQuestionCallback, showCurrentQuestion, handleQuestionTextAnswer, } from "./handlers/question.js";
|
|
29
31
|
import { handlePermissionCallback, showPermissionRequest } from "./handlers/permission.js";
|
|
@@ -801,6 +803,7 @@ export function createBot() {
|
|
|
801
803
|
bot.command("opencode_start", opencodeStartCommand);
|
|
802
804
|
bot.command("opencode_stop", opencodeStopCommand);
|
|
803
805
|
bot.command("projects", projectsCommand);
|
|
806
|
+
bot.command("worktree", worktreeCommand);
|
|
804
807
|
bot.command("open", openCommand);
|
|
805
808
|
bot.command("sessions", sessionsCommand);
|
|
806
809
|
bot.command("new", newCommand);
|
|
@@ -809,6 +812,7 @@ export function createBot() {
|
|
|
809
812
|
bot.command("tasklist", taskListCommand);
|
|
810
813
|
bot.command("rename", renameCommand);
|
|
811
814
|
bot.command("commands", commandsCommand);
|
|
815
|
+
bot.command("skills", skillsCommand);
|
|
812
816
|
bot.on("message:text", unknownCommandMiddleware);
|
|
813
817
|
bot.on("callback_query:data", async (ctx) => {
|
|
814
818
|
logger.debug(`[Bot] Received callback_query:data: ${ctx.callbackQuery?.data}`);
|
|
@@ -825,6 +829,7 @@ export function createBot() {
|
|
|
825
829
|
}
|
|
826
830
|
const handledSession = await handleSessionSelect(ctx);
|
|
827
831
|
const handledProject = await handleProjectSelect(ctx);
|
|
832
|
+
const handledWorktree = await handleWorktreeCallback(ctx);
|
|
828
833
|
const handledOpen = await handleOpenCallback(ctx);
|
|
829
834
|
const handledQuestion = await handleQuestionCallback(ctx);
|
|
830
835
|
const handledPermission = await handlePermissionCallback(ctx);
|
|
@@ -836,10 +841,12 @@ export function createBot() {
|
|
|
836
841
|
const handledTaskList = await handleTaskListCallback(ctx);
|
|
837
842
|
const handledRenameCancel = await handleRenameCancel(ctx);
|
|
838
843
|
const handledCommands = await handleCommandsCallback(ctx, { bot, ensureEventSubscription });
|
|
839
|
-
|
|
844
|
+
const handledSkills = await handleSkillsCallback(ctx, { bot, ensureEventSubscription });
|
|
845
|
+
logger.debug(`[Bot] Callback handled: inlineCancel=${handledInlineCancel}, session=${handledSession}, project=${handledProject}, worktree=${handledWorktree}, open=${handledOpen}, question=${handledQuestion}, permission=${handledPermission}, agent=${handledAgent}, model=${handledModel}, variant=${handledVariant}, compactConfirm=${handledCompactConfirm}, task=${handledTask}, taskList=${handledTaskList}, rename=${handledRenameCancel}, commands=${handledCommands}, skills=${handledSkills}`);
|
|
840
846
|
if (!handledInlineCancel &&
|
|
841
847
|
!handledSession &&
|
|
842
848
|
!handledProject &&
|
|
849
|
+
!handledWorktree &&
|
|
843
850
|
!handledOpen &&
|
|
844
851
|
!handledQuestion &&
|
|
845
852
|
!handledPermission &&
|
|
@@ -850,7 +857,8 @@ export function createBot() {
|
|
|
850
857
|
!handledTask &&
|
|
851
858
|
!handledTaskList &&
|
|
852
859
|
!handledRenameCancel &&
|
|
853
|
-
!handledCommands
|
|
860
|
+
!handledCommands &&
|
|
861
|
+
!handledSkills) {
|
|
854
862
|
logger.debug("Unknown callback query:", ctx.callbackQuery?.data);
|
|
855
863
|
await ctx.answerCallbackQuery({ text: t("callback.unknown_command") });
|
|
856
864
|
}
|
|
@@ -1049,6 +1057,10 @@ export function createBot() {
|
|
|
1049
1057
|
if (handledCommandArgs) {
|
|
1050
1058
|
return;
|
|
1051
1059
|
}
|
|
1060
|
+
const handledSkillArgs = await handleSkillTextArguments(ctx, promptDeps);
|
|
1061
|
+
if (handledSkillArgs) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1052
1064
|
await processUserPrompt(ctx, text, promptDeps);
|
|
1053
1065
|
logger.debug("[Bot] message:text handler completed (prompt sent in background)");
|
|
1054
1066
|
});
|
package/dist/config.js
CHANGED
|
@@ -73,6 +73,7 @@ export const config = {
|
|
|
73
73
|
projectsListLimit: getOptionalPositiveIntEnvVar("PROJECTS_LIST_LIMIT", 10),
|
|
74
74
|
commandsListLimit: getOptionalPositiveIntEnvVar("COMMANDS_LIST_LIMIT", 10),
|
|
75
75
|
taskLimit: getOptionalPositiveIntEnvVar("TASK_LIMIT", 10),
|
|
76
|
+
scheduledTaskExecutionTimeoutMinutes: getOptionalPositiveIntEnvVar("SCHEDULED_TASK_EXECUTION_TIMEOUT_MINUTES", 120),
|
|
76
77
|
responseStreamThrottleMs: getOptionalPositiveIntEnvVar("RESPONSE_STREAM_THROTTLE_MS", 500),
|
|
77
78
|
bashToolDisplayMaxLength: getOptionalPositiveIntEnvVar("BASH_TOOL_DISPLAY_MAX_LENGTH", 128),
|
|
78
79
|
locale: getOptionalLocaleEnvVar("BOT_LOCALE", "en"),
|
|
@@ -92,6 +93,7 @@ export const config = {
|
|
|
92
93
|
apiKey: getEnvVar("STT_API_KEY", false),
|
|
93
94
|
model: getEnvVar("STT_MODEL", false) || "whisper-large-v3-turbo",
|
|
94
95
|
language: getEnvVar("STT_LANGUAGE", false),
|
|
96
|
+
notePrompt: getEnvVar("STT_NOTE_PROMPT", false),
|
|
95
97
|
},
|
|
96
98
|
tts: {
|
|
97
99
|
apiUrl: getEnvVar("TTS_API_URL", false),
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const GIT_HEADS_PREFIX = "refs/heads/";
|
|
5
|
+
const GIT_WORKTREES_MARKER = `${path.sep}.git${path.sep}worktrees${path.sep}`;
|
|
6
|
+
const GIT_WORKTREE_LIST_MAX_BUFFER = 1024 * 1024;
|
|
7
|
+
function normalizePathKey(value) {
|
|
8
|
+
const normalized = path.resolve(value).replace(/[\\/]+$/, "");
|
|
9
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
10
|
+
}
|
|
11
|
+
function normalizeBranchName(value) {
|
|
12
|
+
return value.startsWith(GIT_HEADS_PREFIX) ? value.slice(GIT_HEADS_PREFIX.length) : value;
|
|
13
|
+
}
|
|
14
|
+
function parseGitWorktreeList(stdout) {
|
|
15
|
+
const entries = [];
|
|
16
|
+
let currentPath = null;
|
|
17
|
+
let currentBranch = null;
|
|
18
|
+
const pushCurrent = () => {
|
|
19
|
+
if (!currentPath) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
entries.push({
|
|
23
|
+
path: currentPath,
|
|
24
|
+
branch: currentBranch,
|
|
25
|
+
});
|
|
26
|
+
currentPath = null;
|
|
27
|
+
currentBranch = null;
|
|
28
|
+
};
|
|
29
|
+
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
30
|
+
const line = rawLine.trim();
|
|
31
|
+
if (!line) {
|
|
32
|
+
pushCurrent();
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (line.startsWith("worktree ")) {
|
|
36
|
+
pushCurrent();
|
|
37
|
+
currentPath = line.slice("worktree ".length);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (line.startsWith("branch ")) {
|
|
41
|
+
currentBranch = normalizeBranchName(line.slice("branch ".length));
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (line === "detached") {
|
|
45
|
+
currentBranch = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
pushCurrent();
|
|
49
|
+
return entries;
|
|
50
|
+
}
|
|
51
|
+
async function runGitWorktreeList(worktree) {
|
|
52
|
+
const stdout = await new Promise((resolve, reject) => {
|
|
53
|
+
execFile("git", ["worktree", "list", "--porcelain"], {
|
|
54
|
+
cwd: worktree,
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
maxBuffer: GIT_WORKTREE_LIST_MAX_BUFFER,
|
|
57
|
+
}, (error, output) => {
|
|
58
|
+
if (error) {
|
|
59
|
+
reject(error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
resolve(output);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
return parseGitWorktreeList(stdout);
|
|
66
|
+
}
|
|
67
|
+
async function readHeadBranch(gitDir) {
|
|
68
|
+
try {
|
|
69
|
+
const headPath = path.join(gitDir, "HEAD");
|
|
70
|
+
const headContent = (await readFile(headPath, "utf-8")).trim();
|
|
71
|
+
const match = headContent.match(/^ref:\s+(.+)$/);
|
|
72
|
+
return match ? normalizeBranchName(match[1]) : null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function deriveMainProjectPath(activeWorktreePath, gitDir) {
|
|
79
|
+
const normalizedGitDir = path.resolve(gitDir);
|
|
80
|
+
if (path.basename(normalizedGitDir).toLowerCase() === ".git") {
|
|
81
|
+
return path.resolve(activeWorktreePath);
|
|
82
|
+
}
|
|
83
|
+
if (normalizedGitDir.includes(GIT_WORKTREES_MARKER)) {
|
|
84
|
+
return path.resolve(normalizedGitDir, "..", "..", "..");
|
|
85
|
+
}
|
|
86
|
+
return path.resolve(activeWorktreePath);
|
|
87
|
+
}
|
|
88
|
+
export async function resolveGitDir(worktree) {
|
|
89
|
+
const gitPath = path.join(worktree, ".git");
|
|
90
|
+
try {
|
|
91
|
+
const gitStat = await stat(gitPath);
|
|
92
|
+
if (gitStat.isDirectory()) {
|
|
93
|
+
return gitPath;
|
|
94
|
+
}
|
|
95
|
+
if (!gitStat.isFile()) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const gitPointer = (await readFile(gitPath, "utf-8")).trim();
|
|
99
|
+
const match = gitPointer.match(/^gitdir:\s*(.+)$/i);
|
|
100
|
+
if (!match) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return path.resolve(worktree, match[1].trim());
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export async function getGitWorktreeContext(worktree) {
|
|
110
|
+
const activeWorktreePath = path.resolve(worktree);
|
|
111
|
+
const gitDir = await resolveGitDir(activeWorktreePath);
|
|
112
|
+
if (!gitDir) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const mainProjectPath = deriveMainProjectPath(activeWorktreePath, gitDir);
|
|
116
|
+
const activeWorktreeKey = normalizePathKey(activeWorktreePath);
|
|
117
|
+
const mainProjectKey = normalizePathKey(mainProjectPath);
|
|
118
|
+
const parsedEntries = await runGitWorktreeList(activeWorktreePath);
|
|
119
|
+
const worktrees = parsedEntries.map((entry) => {
|
|
120
|
+
const entryPath = path.resolve(entry.path);
|
|
121
|
+
const entryKey = normalizePathKey(entryPath);
|
|
122
|
+
return {
|
|
123
|
+
path: entryPath,
|
|
124
|
+
branch: entry.branch,
|
|
125
|
+
isCurrent: entryKey === activeWorktreeKey,
|
|
126
|
+
isMain: entryKey === mainProjectKey,
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
let currentEntry = worktrees.find((entry) => entry.isCurrent) ?? null;
|
|
130
|
+
if (!currentEntry) {
|
|
131
|
+
currentEntry = {
|
|
132
|
+
path: activeWorktreePath,
|
|
133
|
+
branch: await readHeadBranch(gitDir),
|
|
134
|
+
isCurrent: true,
|
|
135
|
+
isMain: activeWorktreeKey === mainProjectKey,
|
|
136
|
+
};
|
|
137
|
+
worktrees.push(currentEntry);
|
|
138
|
+
}
|
|
139
|
+
else if (!currentEntry.branch) {
|
|
140
|
+
currentEntry.branch = await readHeadBranch(gitDir);
|
|
141
|
+
}
|
|
142
|
+
worktrees.sort((left, right) => {
|
|
143
|
+
if (left.isMain !== right.isMain) {
|
|
144
|
+
return left.isMain ? -1 : 1;
|
|
145
|
+
}
|
|
146
|
+
if (left.path === right.path) {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
return left.path.localeCompare(right.path);
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
mainProjectPath,
|
|
153
|
+
activeWorktreePath,
|
|
154
|
+
branch: currentEntry.branch,
|
|
155
|
+
isLinkedWorktree: activeWorktreeKey !== mainProjectKey,
|
|
156
|
+
worktrees,
|
|
157
|
+
};
|
|
158
|
+
}
|
package/dist/i18n/de.js
CHANGED
|
@@ -5,9 +5,11 @@ export const de = {
|
|
|
5
5
|
"cmd.description.sessions": "Sitzungen auflisten",
|
|
6
6
|
"cmd.description.tts": "Audioantworten umschalten",
|
|
7
7
|
"cmd.description.projects": "Projekte auflisten",
|
|
8
|
+
"cmd.description.worktree": "Git-Worktrees wechseln",
|
|
8
9
|
"cmd.description.task": "Geplante Aufgabe erstellen",
|
|
9
10
|
"cmd.description.tasklist": "Geplante Aufgaben anzeigen",
|
|
10
11
|
"cmd.description.commands": "Benutzerdefinierte Befehle",
|
|
12
|
+
"cmd.description.skills": "Skill-Katalog",
|
|
11
13
|
"cmd.description.opencode_start": "OpenCode-Server starten",
|
|
12
14
|
"cmd.description.opencode_stop": "OpenCode-Server stoppen",
|
|
13
15
|
"cmd.description.help": "Hilfe",
|
|
@@ -33,7 +35,7 @@ export const de = {
|
|
|
33
35
|
"inline.cancelled_callback": "Abgebrochen",
|
|
34
36
|
"common.unknown": "unbekannt",
|
|
35
37
|
"common.unknown_error": "unbekannter Fehler",
|
|
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.",
|
|
38
|
+
"start.welcome": "👋 Willkommen beim OpenCode Telegram Bot!\n\nNutze Befehle:\n/projects — Projekt auswählen\n/sessions — Sitzungsliste\n/new — neue Sitzung\n/commands — benutzerdefinierte Befehle\n/skills — Skill-Katalog\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
39
|
"help.keyboard_hint": "💡 Nutze die unteren Buttons für Agent, Modell, Variante und Kontextaktionen.",
|
|
38
40
|
"help.text": "📖 **Hilfe**\n\n/status - Serverstatus prüfen\n/sessions - Sitzungsliste\n/new - Neue Sitzung erstellen\n/help - Hilfe",
|
|
39
41
|
"bot.thinking": "💭 Denke...",
|
|
@@ -73,6 +75,7 @@ export const de = {
|
|
|
73
75
|
"status.tts.off": "Aus",
|
|
74
76
|
"status.agent_not_set": "nicht gesetzt",
|
|
75
77
|
"status.project_selected": "Projekt: {project}",
|
|
78
|
+
"status.worktree_selected": "Worktree: {worktree}",
|
|
76
79
|
"status.project_not_selected": "Projekt: nicht ausgewählt",
|
|
77
80
|
"status.project_hint": "Nutze /projects, um ein Projekt auszuwahlen",
|
|
78
81
|
"status.session_selected": "Aktuelle Sitzung: {title}",
|
|
@@ -124,15 +127,20 @@ export const de = {
|
|
|
124
127
|
"stop.error": "🔴 Aktion konnte nicht gestoppt werden.\n\nEvent-Stream ist gestoppt, versuche /abort erneut.",
|
|
125
128
|
"opencode_start.already_running_managed": "⚠️ OpenCode-Server läuft bereits\n\nPID: {pid}\nBetriebszeit: {seconds} Sekunden",
|
|
126
129
|
"opencode_start.already_running_external": "✅ OpenCode-Server läuft bereits als externer Prozess\n\nVersion: {version}\n\nDieser Server wurde nicht vom Bot gestartet, daher kann /opencode-stop ihn nicht stoppen.",
|
|
130
|
+
"opencode_start.already_running": "✅ OpenCode-Server läuft bereits\n\nVersion: {version}",
|
|
131
|
+
"opencode_start.remote_configured": "⚠️ /opencode_start funktioniert nur mit einem lokalen OpenCode-Server.",
|
|
127
132
|
"opencode_start.starting": "🔄 Starte OpenCode-Server...",
|
|
128
133
|
"opencode_start.start_error": "🔴 OpenCode-Server konnte nicht gestartet werden\n\nFehler: {error}\n\nPrüfe, ob OpenCode CLI installiert und im PATH verfügbar ist:\nopencode --version\nnpm install -g @opencode-ai/cli",
|
|
129
134
|
"opencode_start.started_not_ready": "⚠️ OpenCode-Server gestartet, aber reagiert nicht\n\nPID: {pid}\n\nDer Server startet möglicherweise noch. Versuche /status in ein paar Sekunden.",
|
|
130
135
|
"opencode_start.success": "✅ OpenCode-Server erfolgreich gestartet\n\nPID: {pid}\nVersion: {version}",
|
|
131
136
|
"opencode_start.error": "🔴 Beim Starten des Servers ist ein Fehler aufgetreten.\n\nSiehe Anwendungslogs für Details.",
|
|
132
137
|
"opencode_stop.external_running": "⚠️ OpenCode-Server läuft als externer Prozess\n\nDieser Server wurde nicht über /opencode-start gestartet.\nStoppe ihn manuell oder nutze /status, um den Zustand zu prüfen.",
|
|
138
|
+
"opencode_stop.remote_configured": "⚠️ /opencode_stop funktioniert nur mit einem lokalen OpenCode-Server.",
|
|
133
139
|
"opencode_stop.not_running": "⚠️ OpenCode-Server läuft nicht",
|
|
140
|
+
"opencode_stop.pid_not_found": "⚠️ OpenCode-Server antwortet auf Port {port}, aber es wurde kein lokaler Prozess zum Stoppen gefunden.",
|
|
134
141
|
"opencode_stop.stopping": "🛑 Stoppe OpenCode-Server...\n\nPID: {pid}",
|
|
135
142
|
"opencode_stop.stop_error": "🔴 OpenCode-Server konnte nicht gestoppt werden\n\nFehler: {error}",
|
|
143
|
+
"opencode_stop.still_running": "Der Server antwortet nach der Stop-Anfrage weiterhin.",
|
|
136
144
|
"opencode_stop.success": "✅ OpenCode-Server erfolgreich gestoppt",
|
|
137
145
|
"opencode_stop.error": "🔴 Beim Stoppen des Servers ist ein Fehler aufgetreten.\n\nSiehe Anwendungslogs für Details.",
|
|
138
146
|
"agent.changed_callback": "Agent geändert: {name}",
|
|
@@ -222,6 +230,7 @@ export const de = {
|
|
|
222
230
|
"pinned.default_session_title": "neue Sitzung",
|
|
223
231
|
"pinned.unknown": "Unbekannt",
|
|
224
232
|
"pinned.line.project": "Projekt: {project}",
|
|
233
|
+
"pinned.line.worktree": "Worktree: {worktree}",
|
|
225
234
|
"pinned.line.model": "Modell: {model}",
|
|
226
235
|
"pinned.line.context": "Kontext: {used} / {limit} ({percent}%)",
|
|
227
236
|
"pinned.line.cost": "Kosten: {cost} ausgegeben",
|
|
@@ -323,6 +332,23 @@ export const de = {
|
|
|
323
332
|
"commands.button.next_page": "Weiter ➡️",
|
|
324
333
|
"commands.page_empty_callback": "Keine Befehle auf dieser Seite",
|
|
325
334
|
"commands.page_load_error_callback": "Diese Seite konnte nicht geladen werden. Bitte versuche es erneut.",
|
|
335
|
+
"skills.select": "Wähle einen OpenCode-Skill:",
|
|
336
|
+
"skills.empty": "📭 Für dieses Projekt sind keine OpenCode-Skills verfügbar.",
|
|
337
|
+
"skills.fetch_error": "🔴 OpenCode-Skills konnten nicht geladen werden.",
|
|
338
|
+
"skills.no_description": "Keine Beschreibung",
|
|
339
|
+
"skills.button.execute": "✅ Ausführen",
|
|
340
|
+
"skills.button.cancel": "❌ Abbrechen",
|
|
341
|
+
"skills.confirm": "Bestätige die Ausführung des Skills {skill}. Für die Ausführung mit Argumenten sende die Argumente als Nachricht.",
|
|
342
|
+
"skills.inactive_callback": "Dieses Skill-Menü ist inaktiv",
|
|
343
|
+
"skills.cancelled_callback": "Abgebrochen",
|
|
344
|
+
"skills.execute_callback": "Skill wird verwendet...",
|
|
345
|
+
"skills.executing_prefix": "⚡ Skill wird verwendet:",
|
|
346
|
+
"skills.arguments_empty": "⚠️ Argumente dürfen nicht leer sein. Sende Text oder tippe auf Ausführen.",
|
|
347
|
+
"skills.select_page": "Wähle einen OpenCode-Skill (Seite {page}):",
|
|
348
|
+
"skills.button.prev_page": "⬅️ Zurück",
|
|
349
|
+
"skills.button.next_page": "Weiter ➡️",
|
|
350
|
+
"skills.page_empty_callback": "Keine Skills auf dieser Seite",
|
|
351
|
+
"skills.page_load_error_callback": "Diese Seite konnte nicht geladen werden. Bitte versuche es erneut.",
|
|
326
352
|
"cmd.description.rename": "Aktuelle Sitzung umbenennen",
|
|
327
353
|
"legacy.models.fetch_error": "🔴 Modellliste konnte nicht geladen werden. Prüfe den Serverstatus mit /status.",
|
|
328
354
|
"legacy.models.empty": "📋 Keine verfügbaren Modelle. Konfiguriere Provider in OpenCode.",
|
|
@@ -336,6 +362,18 @@ export const de = {
|
|
|
336
362
|
"stt.error": "🔴 Audio konnte nicht erkannt werden: {error}",
|
|
337
363
|
"stt.empty_result": "🎤 Keine Sprache in der Audionachricht erkannt.",
|
|
338
364
|
"cmd.description.open": "Projekt durch Ordner-Auswahl hinzufügen",
|
|
365
|
+
"worktree.branch_detached": "detached HEAD",
|
|
366
|
+
"worktree.select_with_current": "Worktree auswählen:",
|
|
367
|
+
"worktree.project_not_selected": "🏗 Es ist kein Projekt ausgewählt.\n\nWähle zuerst ein Projekt mit /projects.",
|
|
368
|
+
"worktree.not_git_repo": "🌿 Git-Worktrees sind für das aktuelle Projekt nicht verfügbar. Wähle zuerst ein Git-Repository.",
|
|
369
|
+
"worktree.not_git_repo_callback": "Aktuelles Projekt ist kein Git-Repository",
|
|
370
|
+
"worktree.empty": "📭 Für das aktuelle Repository wurden keine Git-Worktrees gefunden.",
|
|
371
|
+
"worktree.fetch_error": "🔴 Git-Worktrees konnten nicht geladen werden.",
|
|
372
|
+
"worktree.page_empty_callback": "Keine Worktrees auf dieser Seite",
|
|
373
|
+
"worktree.selection_missing_callback": "Der ausgewählte Worktree ist nicht mehr verfügbar",
|
|
374
|
+
"worktree.already_selected_callback": "Dieser Worktree ist bereits ausgewählt",
|
|
375
|
+
"worktree.selected": "✅ Worktree ausgewählt: {worktree}\n\n📋 Die Sitzung wurde zurückgesetzt. Nutze /sessions oder /new, um fortzufahren.",
|
|
376
|
+
"worktree.select_error": "🔴 Worktree konnte nicht ausgewählt werden.",
|
|
339
377
|
"open.back": "⬆️ Hoch",
|
|
340
378
|
"open.roots": "📋 Zurück zur Auswahl",
|
|
341
379
|
"open.prev_page": "⬅️ Zurück",
|
package/dist/i18n/en.js
CHANGED
|
@@ -5,9 +5,11 @@ export const en = {
|
|
|
5
5
|
"cmd.description.sessions": "List sessions",
|
|
6
6
|
"cmd.description.tts": "Toggle audio replies",
|
|
7
7
|
"cmd.description.projects": "List projects",
|
|
8
|
+
"cmd.description.worktree": "Switch git worktrees",
|
|
8
9
|
"cmd.description.task": "Create a scheduled task",
|
|
9
10
|
"cmd.description.tasklist": "List scheduled tasks",
|
|
10
11
|
"cmd.description.commands": "Custom commands",
|
|
12
|
+
"cmd.description.skills": "Skills catalog",
|
|
11
13
|
"cmd.description.opencode_start": "Start OpenCode server",
|
|
12
14
|
"cmd.description.opencode_stop": "Stop OpenCode server",
|
|
13
15
|
"cmd.description.help": "Help",
|
|
@@ -33,7 +35,7 @@ export const en = {
|
|
|
33
35
|
"inline.cancelled_callback": "Cancelled",
|
|
34
36
|
"common.unknown": "unknown",
|
|
35
37
|
"common.unknown_error": "unknown error",
|
|
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.",
|
|
38
|
+
"start.welcome": "👋 Welcome to OpenCode Telegram Bot!\n\nUse commands:\n/projects — select project\n/sessions — session list\n/new — new session\n/commands — custom commands\n/skills — skills catalog\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
39
|
"help.keyboard_hint": "💡 Use the bottom keyboard buttons for the agent, model, variant, and context actions.",
|
|
38
40
|
"help.text": "📖 **Help**\n\n/status - Check server status\n/sessions - Session list\n/new - Create new session\n/help - Help",
|
|
39
41
|
"bot.thinking": "💭 Thinking...",
|
|
@@ -73,6 +75,7 @@ export const en = {
|
|
|
73
75
|
"status.tts.off": "Off",
|
|
74
76
|
"status.agent_not_set": "not set",
|
|
75
77
|
"status.project_selected": "Project: {project}",
|
|
78
|
+
"status.worktree_selected": "Worktree: {worktree}",
|
|
76
79
|
"status.project_not_selected": "Project: not selected",
|
|
77
80
|
"status.project_hint": "Use /projects to select a project",
|
|
78
81
|
"status.session_selected": "Current session: {title}",
|
|
@@ -124,15 +127,20 @@ export const en = {
|
|
|
124
127
|
"stop.error": "🔴 Failed to stop action.\n\nEvent stream is stopped, try /abort again.",
|
|
125
128
|
"opencode_start.already_running_managed": "⚠️ OpenCode Server is already running\n\nPID: {pid}\nUptime: {seconds} seconds",
|
|
126
129
|
"opencode_start.already_running_external": "✅ OpenCode Server is already running as an external process\n\nVersion: {version}\n\nThis server was not started by bot, so /opencode-stop cannot stop it.",
|
|
130
|
+
"opencode_start.already_running": "✅ OpenCode Server is already running\n\nVersion: {version}",
|
|
131
|
+
"opencode_start.remote_configured": "⚠️ /opencode_start works only with a local OpenCode Server.",
|
|
127
132
|
"opencode_start.starting": "🔄 Starting OpenCode Server...",
|
|
128
133
|
"opencode_start.start_error": "🔴 Failed to start OpenCode Server\n\nError: {error}\n\nCheck that OpenCode CLI is installed and available in PATH:\nopencode --version\nnpm install -g @opencode-ai/cli",
|
|
129
134
|
"opencode_start.started_not_ready": "⚠️ OpenCode Server started, but is not responding\n\nPID: {pid}\n\nServer may still be starting. Try /status in a few seconds.",
|
|
130
135
|
"opencode_start.success": "✅ OpenCode Server started successfully\n\nPID: {pid}\nVersion: {version}",
|
|
131
136
|
"opencode_start.error": "🔴 An error occurred while starting server.\n\nCheck application logs for details.",
|
|
132
137
|
"opencode_stop.external_running": "⚠️ OpenCode Server is running as an external process\n\nThis server was not started via /opencode-start.\nStop it manually or use /status to check state.",
|
|
138
|
+
"opencode_stop.remote_configured": "⚠️ /opencode_stop works only with a local OpenCode Server.",
|
|
133
139
|
"opencode_stop.not_running": "⚠️ OpenCode Server is not running",
|
|
140
|
+
"opencode_stop.pid_not_found": "⚠️ OpenCode Server responds on port {port}, but no local process was found to stop.",
|
|
134
141
|
"opencode_stop.stopping": "🛑 Stopping OpenCode Server...\n\nPID: {pid}",
|
|
135
142
|
"opencode_stop.stop_error": "🔴 Failed to stop OpenCode Server\n\nError: {error}",
|
|
143
|
+
"opencode_stop.still_running": "Server is still responding after the stop request.",
|
|
136
144
|
"opencode_stop.success": "✅ OpenCode Server stopped successfully",
|
|
137
145
|
"opencode_stop.error": "🔴 An error occurred while stopping server.\n\nCheck application logs for details.",
|
|
138
146
|
"agent.changed_callback": "Agent changed: {name}",
|
|
@@ -222,6 +230,7 @@ export const en = {
|
|
|
222
230
|
"pinned.default_session_title": "new session",
|
|
223
231
|
"pinned.unknown": "Unknown",
|
|
224
232
|
"pinned.line.project": "Project: {project}",
|
|
233
|
+
"pinned.line.worktree": "Worktree: {worktree}",
|
|
225
234
|
"pinned.line.model": "Model: {model}",
|
|
226
235
|
"pinned.line.context": "Context: {used} / {limit} ({percent}%)",
|
|
227
236
|
"pinned.line.cost": "Cost: {cost} spent",
|
|
@@ -323,6 +332,23 @@ export const en = {
|
|
|
323
332
|
"commands.button.next_page": "Next ➡️",
|
|
324
333
|
"commands.page_empty_callback": "No commands on this page",
|
|
325
334
|
"commands.page_load_error_callback": "Cannot load this page. Please try again.",
|
|
335
|
+
"skills.select": "Choose an OpenCode skill:",
|
|
336
|
+
"skills.empty": "📭 No OpenCode skills are available for this project.",
|
|
337
|
+
"skills.fetch_error": "🔴 Failed to load OpenCode skills.",
|
|
338
|
+
"skills.no_description": "No description",
|
|
339
|
+
"skills.button.execute": "✅ Execute",
|
|
340
|
+
"skills.button.cancel": "❌ Cancel",
|
|
341
|
+
"skills.confirm": "Confirm execution of skill {skill}. To run it with arguments, send the arguments as a message.",
|
|
342
|
+
"skills.inactive_callback": "This skill menu is inactive",
|
|
343
|
+
"skills.cancelled_callback": "Cancelled",
|
|
344
|
+
"skills.execute_callback": "Using skill...",
|
|
345
|
+
"skills.executing_prefix": "⚡ Using skill:",
|
|
346
|
+
"skills.arguments_empty": "⚠️ Arguments cannot be empty. Send text or tap Execute.",
|
|
347
|
+
"skills.select_page": "Choose an OpenCode skill (page {page}):",
|
|
348
|
+
"skills.button.prev_page": "⬅️ Prev",
|
|
349
|
+
"skills.button.next_page": "Next ➡️",
|
|
350
|
+
"skills.page_empty_callback": "No skills on this page",
|
|
351
|
+
"skills.page_load_error_callback": "Cannot load this page. Please try again.",
|
|
326
352
|
"cmd.description.rename": "Rename current session",
|
|
327
353
|
"legacy.models.fetch_error": "🔴 Failed to get models list. Check server status with /status.",
|
|
328
354
|
"legacy.models.empty": "📋 No available models. Configure providers in OpenCode.",
|
|
@@ -336,6 +362,18 @@ export const en = {
|
|
|
336
362
|
"stt.error": "🔴 Failed to recognize audio: {error}",
|
|
337
363
|
"stt.empty_result": "🎤 No speech detected in the audio message.",
|
|
338
364
|
"cmd.description.open": "Add a project by browsing directories",
|
|
365
|
+
"worktree.branch_detached": "detached HEAD",
|
|
366
|
+
"worktree.select_with_current": "Select a worktree:",
|
|
367
|
+
"worktree.project_not_selected": "🏗 Project is not selected.\n\nFirst select a project with /projects.",
|
|
368
|
+
"worktree.not_git_repo": "🌿 Git worktrees are unavailable for the current project. Select a git repository first.",
|
|
369
|
+
"worktree.not_git_repo_callback": "Current project is not a git repository",
|
|
370
|
+
"worktree.empty": "📭 No git worktrees found for the current repository.",
|
|
371
|
+
"worktree.fetch_error": "🔴 Failed to load git worktrees.",
|
|
372
|
+
"worktree.page_empty_callback": "No worktrees on this page",
|
|
373
|
+
"worktree.selection_missing_callback": "Selected worktree is no longer available",
|
|
374
|
+
"worktree.already_selected_callback": "This worktree is already selected",
|
|
375
|
+
"worktree.selected": "✅ Worktree selected: {worktree}\n\n📋 Session was reset. Use /sessions or /new to continue.",
|
|
376
|
+
"worktree.select_error": "🔴 Failed to select worktree.",
|
|
339
377
|
"open.back": "⬆️ Up",
|
|
340
378
|
"open.roots": "📋 Back to roots",
|
|
341
379
|
"open.prev_page": "⬅️ Previous",
|
package/dist/i18n/es.js
CHANGED
|
@@ -5,9 +5,11 @@ export const es = {
|
|
|
5
5
|
"cmd.description.sessions": "Listar sesiones",
|
|
6
6
|
"cmd.description.tts": "Alternar respuestas de audio",
|
|
7
7
|
"cmd.description.projects": "Listar proyectos",
|
|
8
|
+
"cmd.description.worktree": "Cambiar worktrees de git",
|
|
8
9
|
"cmd.description.task": "Crear tarea programada",
|
|
9
10
|
"cmd.description.tasklist": "Ver tareas programadas",
|
|
10
11
|
"cmd.description.commands": "Comandos personalizados",
|
|
12
|
+
"cmd.description.skills": "Catálogo de skills",
|
|
11
13
|
"cmd.description.opencode_start": "Iniciar servidor OpenCode",
|
|
12
14
|
"cmd.description.opencode_stop": "Detener servidor OpenCode",
|
|
13
15
|
"cmd.description.help": "Ayuda",
|
|
@@ -33,7 +35,7 @@ export const es = {
|
|
|
33
35
|
"inline.cancelled_callback": "Cancelado",
|
|
34
36
|
"common.unknown": "desconocido",
|
|
35
37
|
"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 agente, modelo y variante.",
|
|
38
|
+
"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/commands — comandos personalizados\n/skills — catálogo de skills\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
39
|
"help.keyboard_hint": "💡 Usa los botones inferiores para agente, modelo, variante y acciones de contexto.",
|
|
38
40
|
"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
41
|
"bot.thinking": "💭 Pensando...",
|
|
@@ -73,6 +75,7 @@ export const es = {
|
|
|
73
75
|
"status.tts.off": "Desactivadas",
|
|
74
76
|
"status.agent_not_set": "no configurado",
|
|
75
77
|
"status.project_selected": "Proyecto: {project}",
|
|
78
|
+
"status.worktree_selected": "Worktree: {worktree}",
|
|
76
79
|
"status.project_not_selected": "Proyecto: no seleccionado",
|
|
77
80
|
"status.project_hint": "Usa /projects para seleccionar un proyecto",
|
|
78
81
|
"status.session_selected": "Sesión actual: {title}",
|
|
@@ -124,15 +127,20 @@ export const es = {
|
|
|
124
127
|
"stop.error": "🔴 No se pudo detener la acción.\n\nEl flujo de eventos está detenido; prueba /abort otra vez.",
|
|
125
128
|
"opencode_start.already_running_managed": "⚠️ OpenCode Server ya está en ejecución\n\nPID: {pid}\nTiempo activo: {seconds} segundos",
|
|
126
129
|
"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.",
|
|
130
|
+
"opencode_start.already_running": "✅ OpenCode Server ya está en ejecución\n\nVersión: {version}",
|
|
131
|
+
"opencode_start.remote_configured": "⚠️ /opencode_start solo funciona con un OpenCode Server local.",
|
|
127
132
|
"opencode_start.starting": "🔄 Iniciando OpenCode Server...",
|
|
128
133
|
"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",
|
|
129
134
|
"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.",
|
|
130
135
|
"opencode_start.success": "✅ OpenCode Server iniciado correctamente\n\nPID: {pid}\nVersión: {version}",
|
|
131
136
|
"opencode_start.error": "🔴 Ocurrió un error al iniciar el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
|
|
132
137
|
"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.",
|
|
138
|
+
"opencode_stop.remote_configured": "⚠️ /opencode_stop solo funciona con un OpenCode Server local.",
|
|
133
139
|
"opencode_stop.not_running": "⚠️ OpenCode Server no está en ejecución",
|
|
140
|
+
"opencode_stop.pid_not_found": "⚠️ OpenCode Server responde en el puerto {port}, pero no se encontró ningún proceso local para detenerlo.",
|
|
134
141
|
"opencode_stop.stopping": "🛑 Deteniendo OpenCode Server...\n\nPID: {pid}",
|
|
135
142
|
"opencode_stop.stop_error": "🔴 No se pudo detener OpenCode Server\n\nError: {error}",
|
|
143
|
+
"opencode_stop.still_running": "El servidor sigue respondiendo después de la solicitud de detención.",
|
|
136
144
|
"opencode_stop.success": "✅ OpenCode Server detenido correctamente",
|
|
137
145
|
"opencode_stop.error": "🔴 Ocurrió un error al detener el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
|
|
138
146
|
"agent.changed_callback": "Agente cambiado: {name}",
|
|
@@ -222,6 +230,7 @@ export const es = {
|
|
|
222
230
|
"pinned.default_session_title": "sesión nueva",
|
|
223
231
|
"pinned.unknown": "Desconocido",
|
|
224
232
|
"pinned.line.project": "Proyecto: {project}",
|
|
233
|
+
"pinned.line.worktree": "Worktree: {worktree}",
|
|
225
234
|
"pinned.line.model": "Modelo: {model}",
|
|
226
235
|
"pinned.line.context": "Contexto: {used} / {limit} ({percent}%)",
|
|
227
236
|
"pinned.line.cost": "Costo: {cost} gastado",
|
|
@@ -323,6 +332,23 @@ export const es = {
|
|
|
323
332
|
"commands.button.next_page": "Siguiente ➡️",
|
|
324
333
|
"commands.page_empty_callback": "No hay comandos en esta página",
|
|
325
334
|
"commands.page_load_error_callback": "No se pudo cargar esta página. Por favor, inténtalo de nuevo.",
|
|
335
|
+
"skills.select": "Elige un skill de OpenCode:",
|
|
336
|
+
"skills.empty": "📭 No hay skills de OpenCode disponibles para este proyecto.",
|
|
337
|
+
"skills.fetch_error": "🔴 No se pudieron cargar los skills de OpenCode.",
|
|
338
|
+
"skills.no_description": "Sin descripción",
|
|
339
|
+
"skills.button.execute": "✅ Ejecutar",
|
|
340
|
+
"skills.button.cancel": "❌ Cancelar",
|
|
341
|
+
"skills.confirm": "Confirma la ejecución del skill {skill}. Para ejecutarlo con argumentos, envía los argumentos como mensaje.",
|
|
342
|
+
"skills.inactive_callback": "Este menú de skills está inactivo",
|
|
343
|
+
"skills.cancelled_callback": "Cancelado",
|
|
344
|
+
"skills.execute_callback": "Usando skill...",
|
|
345
|
+
"skills.executing_prefix": "⚡ Usando skill:",
|
|
346
|
+
"skills.arguments_empty": "⚠️ Los argumentos no pueden estar vacíos. Envía texto o toca Ejecutar.",
|
|
347
|
+
"skills.select_page": "Elige un skill de OpenCode (página {page}):",
|
|
348
|
+
"skills.button.prev_page": "⬅️ Anterior",
|
|
349
|
+
"skills.button.next_page": "Siguiente ➡️",
|
|
350
|
+
"skills.page_empty_callback": "No hay skills en esta página",
|
|
351
|
+
"skills.page_load_error_callback": "No se pudo cargar esta página. Por favor, inténtalo de nuevo.",
|
|
326
352
|
"cmd.description.rename": "Renombrar la sesión actual",
|
|
327
353
|
"legacy.models.fetch_error": "🔴 No se pudo obtener la lista de modelos. Revisa el estado del servidor con /status.",
|
|
328
354
|
"legacy.models.empty": "📋 No hay modelos disponibles. Configura los proveedores en OpenCode.",
|
|
@@ -336,6 +362,18 @@ export const es = {
|
|
|
336
362
|
"stt.error": "🔴 No se pudo reconocer el audio: {error}",
|
|
337
363
|
"stt.empty_result": "🎤 No se detectó voz en el mensaje de audio.",
|
|
338
364
|
"cmd.description.open": "Añadir proyecto navegando directorios",
|
|
365
|
+
"worktree.branch_detached": "detached HEAD",
|
|
366
|
+
"worktree.select_with_current": "Selecciona un worktree:",
|
|
367
|
+
"worktree.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
|
|
368
|
+
"worktree.not_git_repo": "🌿 Los git worktrees no están disponibles para el proyecto actual. Selecciona primero un repositorio git.",
|
|
369
|
+
"worktree.not_git_repo_callback": "El proyecto actual no es un repositorio git",
|
|
370
|
+
"worktree.empty": "📭 No se encontraron git worktrees para el repositorio actual.",
|
|
371
|
+
"worktree.fetch_error": "🔴 No se pudieron cargar los git worktrees.",
|
|
372
|
+
"worktree.page_empty_callback": "No hay worktrees en esta página",
|
|
373
|
+
"worktree.selection_missing_callback": "El worktree seleccionado ya no está disponible",
|
|
374
|
+
"worktree.already_selected_callback": "Este worktree ya está seleccionado",
|
|
375
|
+
"worktree.selected": "✅ Worktree seleccionado: {worktree}\n\n📋 La sesión se reinició. Usa /sessions o /new para continuar.",
|
|
376
|
+
"worktree.select_error": "🔴 No se pudo seleccionar el worktree.",
|
|
339
377
|
"open.back": "⬆️ Subir",
|
|
340
378
|
"open.roots": "📋 Volver a raíces",
|
|
341
379
|
"open.prev_page": "⬅️ Anterior",
|