@quangnv13/nonstop 1.0.5 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/README.vi.md +3 -0
- package/dist/bot.js +103 -76
- package/dist/i18n.js +153 -3
- package/dist/runtime-manager.js +19 -4
- package/dist/runtime.js +2 -1
- package/dist/session-controls.js +12 -7
- package/dist/session-output.js +2 -1
- package/dist/store.js +4 -30
- package/dist/ui.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,9 @@ nonstop
|
|
|
97
97
|
|
|
98
98
|
## 🕹️ Usage Guide
|
|
99
99
|
|
|
100
|
+
> [!IMPORTANT]
|
|
101
|
+
> **No workspaces are auto-generated on first launch.** To start working on any folder, you must first configure/create a workspace mapping to that folder (either via the local TUI Control Center or the Telegram Bot's `📁 Workspaces` menu).
|
|
102
|
+
|
|
100
103
|
### 1. Local TUI Control Center
|
|
101
104
|
Simply run `nonstop` in your terminal to open the management dashboard. From here, you can:
|
|
102
105
|
* **Start / Stop** the background bot runtime.
|
|
@@ -129,7 +132,7 @@ Once the bot runtime is active, you can interact with it via the following Teleg
|
|
|
129
132
|
* Selecting a workspace sets it as the working directory for your next PTY session.
|
|
130
133
|
|
|
131
134
|
#### **⚙️ Dynamic Configuration**
|
|
132
|
-
* Press **⚙️
|
|
135
|
+
* Press **⚙️ Settings** or send `/config`.
|
|
133
136
|
* Tap any settings button (e.g. *Token*, *Admin*, *Interval*, etc.) and send a new value via message to apply immediately.
|
|
134
137
|
* If you modify the `Telegram Bot Token`, the bot will automatically reload and restart itself securely.
|
|
135
138
|
|
package/README.vi.md
CHANGED
|
@@ -97,6 +97,9 @@ nonstop
|
|
|
97
97
|
|
|
98
98
|
## 🕹️ Hướng Dẫn Sử Dụng
|
|
99
99
|
|
|
100
|
+
> [!IMPORTANT]
|
|
101
|
+
> **Không có workspace nào được tự động tạo sẵn trong lần chạy đầu tiên.** Để bắt đầu làm việc trên thư mục mong muốn, bạn phải tạo/cấu hình ít nhất một workspace liên kết với thư mục đó (thông qua Trung tâm điều khiển TUI cục bộ hoặc menu `📁 Workspaces` của Bot Telegram).
|
|
102
|
+
|
|
100
103
|
### 1. Trung Tâm Điều Khiển TUI Cục Bộ
|
|
101
104
|
Chỉ cần chạy lệnh `nonstop` trên terminal của bạn để mở giao diện bảng điều khiển. Từ đây bạn có thể:
|
|
102
105
|
* **Khởi động / Dừng (Start / Stop)** bot chạy ẩn.
|
package/dist/bot.js
CHANGED
|
@@ -40,6 +40,7 @@ const path = __importStar(require("path"));
|
|
|
40
40
|
const logger_js_1 = require("./logger.js");
|
|
41
41
|
const session_controls_js_1 = require("./session-controls.js");
|
|
42
42
|
const store_js_1 = require("./store.js");
|
|
43
|
+
const i18n_js_1 = require("./i18n.js");
|
|
43
44
|
const grammyRequire = require;
|
|
44
45
|
const { Bot, InlineKeyboard } = grammyRequire('grammy');
|
|
45
46
|
const SUPPORTED_PRESETS = ['powershell', 'bash', 'codex', 'antigravity'];
|
|
@@ -71,6 +72,7 @@ function createBotRuntime(deps) {
|
|
|
71
72
|
}
|
|
72
73
|
const bot = new Bot(token);
|
|
73
74
|
const chatStates = new Map();
|
|
75
|
+
const getT = () => (0, i18n_js_1.createTranslator)(deps.getConfig().language);
|
|
74
76
|
function getChatState(chatId) {
|
|
75
77
|
const existing = chatStates.get(chatId);
|
|
76
78
|
if (existing)
|
|
@@ -111,63 +113,69 @@ function createBotRuntime(deps) {
|
|
|
111
113
|
}
|
|
112
114
|
function buildMainMenuText() {
|
|
113
115
|
const activeSession = deps.getActiveSession();
|
|
116
|
+
const t = getT();
|
|
114
117
|
return [
|
|
115
118
|
'🖥 nonstop client',
|
|
116
119
|
'',
|
|
117
120
|
`📁 Workspaces: ${deps.getWorkspaces().length}`,
|
|
118
121
|
activeSession
|
|
119
|
-
?
|
|
120
|
-
: '
|
|
122
|
+
? t('bot.menu.activeSessionRunning', { preset: activeSession.preset, cwd: activeSession.cwd })
|
|
123
|
+
: t('bot.menu.activeSessionNone')
|
|
121
124
|
].join('\n');
|
|
122
125
|
}
|
|
123
126
|
function buildMainMenuKeyboard() {
|
|
127
|
+
const t = getT();
|
|
124
128
|
return createKeyboard()
|
|
125
|
-
.text('
|
|
126
|
-
.text('
|
|
129
|
+
.text(t('bot.menu.workspaces'), 'workspaces_list')
|
|
130
|
+
.text(t('bot.menu.session'), 'sessions_list')
|
|
127
131
|
.row()
|
|
128
|
-
.text('
|
|
129
|
-
.text('
|
|
132
|
+
.text(t('bot.menu.config'), 'config_menu')
|
|
133
|
+
.text(t('bot.menu.help'), 'help_view');
|
|
130
134
|
}
|
|
131
135
|
async function showMainMenu(ctx) {
|
|
132
136
|
await renderText(ctx, buildMainMenuText(), buildMainMenuKeyboard());
|
|
133
137
|
}
|
|
134
138
|
async function showHelp(ctx) {
|
|
139
|
+
const t = getT();
|
|
135
140
|
await renderText(ctx, [
|
|
136
|
-
'
|
|
141
|
+
t('bot.help.title'),
|
|
137
142
|
'',
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
+
t('bot.help.start'),
|
|
144
|
+
t('bot.help.status'),
|
|
145
|
+
t('bot.help.help'),
|
|
146
|
+
t('bot.help.config'),
|
|
147
|
+
t('bot.help.send'),
|
|
143
148
|
'',
|
|
144
|
-
'
|
|
145
|
-
].join('\n'), createKeyboard().text('
|
|
149
|
+
t('bot.help.inputModeNotice')
|
|
150
|
+
].join('\n'), createKeyboard().text(t('bot.general.back'), 'main_menu'));
|
|
146
151
|
}
|
|
147
152
|
async function showStatus(ctx) {
|
|
148
153
|
const activeSession = deps.getActiveSession();
|
|
149
154
|
const currentAllowedUsername = normalizeUsername(process.env.ADMIN_USERNAME || process.env.TELEGRAM_USERNAME || '');
|
|
155
|
+
const t = getT();
|
|
150
156
|
await renderText(ctx, [
|
|
151
|
-
'
|
|
157
|
+
t('bot.status.title'),
|
|
152
158
|
'',
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
activeSession ?
|
|
157
|
-
activeSession ?
|
|
158
|
-
].filter(Boolean).join('\n'), createKeyboard().text('
|
|
159
|
+
`${t('bot.status.user')}: ${currentAllowedUsername || t('bot.status.unlimited')}`,
|
|
160
|
+
`${t('bot.status.workspaces')}: ${deps.getWorkspaces().length}`,
|
|
161
|
+
`${t('bot.status.session')}: ${activeSession ? t('bot.status.running') : t('bot.status.none')}`,
|
|
162
|
+
activeSession ? `${t('bot.status.preset')}: ${activeSession.preset}` : '',
|
|
163
|
+
activeSession ? `${t('bot.status.directory')}: ${activeSession.cwd}` : ''
|
|
164
|
+
].filter(Boolean).join('\n'), createKeyboard().text(t('bot.general.back'), 'main_menu'));
|
|
159
165
|
}
|
|
160
166
|
async function showConfigMenu(ctx) {
|
|
161
167
|
const config = deps.getConfig();
|
|
168
|
+
const t = getT();
|
|
169
|
+
const notConfigured = t('bot.config.notConfigured');
|
|
162
170
|
const lines = [
|
|
163
|
-
'
|
|
171
|
+
t('bot.config.title'),
|
|
164
172
|
'',
|
|
165
|
-
`• Token: ${config.telegramBotToken ? '••••' + config.telegramBotToken.slice(-4) :
|
|
166
|
-
`• Admin Username: ${config.adminUsername ||
|
|
167
|
-
`• Client Name: ${config.clientName ||
|
|
168
|
-
`• Telegram Username: ${config.telegramUsername ||
|
|
169
|
-
`•
|
|
170
|
-
`•
|
|
173
|
+
`• Token: ${config.telegramBotToken ? '••••' + config.telegramBotToken.slice(-4) : notConfigured}`,
|
|
174
|
+
`• Admin Username: ${config.adminUsername || notConfigured}`,
|
|
175
|
+
`• Client Name: ${config.clientName || notConfigured}`,
|
|
176
|
+
`• Telegram Username: ${config.telegramUsername || notConfigured}`,
|
|
177
|
+
`• ${t('bot.config.languageLabel')}: ${config.language} (vi/en)`,
|
|
178
|
+
`• ${t('bot.config.startupLabel')}: ${config.startupMode} (disabled/background/open-ui)`,
|
|
171
179
|
`• Output Interval: ${config.outputInterval} ms`,
|
|
172
180
|
`• Max Output Lines: ${config.maxOutputLines}`,
|
|
173
181
|
`• Max Render Lines: ${config.maxRenderLines}`,
|
|
@@ -183,8 +191,8 @@ function createBotRuntime(deps) {
|
|
|
183
191
|
.text('Client Name', 'config_edit:clientName')
|
|
184
192
|
.text('Telegram User', 'config_edit:telegramUsername')
|
|
185
193
|
.row()
|
|
186
|
-
.text(
|
|
187
|
-
.text(
|
|
194
|
+
.text(`${t('bot.config.languageLabel')} (${config.language === 'vi' ? '🇻🇳 vi' : '🇬🇧 en'})`, 'config_edit:language')
|
|
195
|
+
.text(`${t('bot.config.startupLabel')} (${config.startupMode})`, 'config_edit:startupMode')
|
|
188
196
|
.row()
|
|
189
197
|
.text('Interval', 'config_edit:outputInterval')
|
|
190
198
|
.text('Max Output Lines', 'config_edit:maxOutputLines')
|
|
@@ -197,15 +205,16 @@ function createBotRuntime(deps) {
|
|
|
197
205
|
.row()
|
|
198
206
|
.text('Antigravity Args', 'config_edit:antigravityArgs')
|
|
199
207
|
.row()
|
|
200
|
-
.text('
|
|
208
|
+
.text(t('bot.general.back'), 'main_menu');
|
|
201
209
|
await renderText(ctx, lines.join('\n'), keyboard);
|
|
202
210
|
}
|
|
203
211
|
async function showWorkspacesMenu(ctx) {
|
|
204
212
|
const workspaces = deps.getWorkspaces();
|
|
205
|
-
const
|
|
213
|
+
const t = getT();
|
|
214
|
+
const lines = [t('bot.workspaces.title'), ''];
|
|
206
215
|
const keyboard = createKeyboard();
|
|
207
216
|
if (workspaces.length === 0) {
|
|
208
|
-
lines.push('
|
|
217
|
+
lines.push(t('bot.workspaces.empty'));
|
|
209
218
|
}
|
|
210
219
|
else {
|
|
211
220
|
for (const ws of workspaces) {
|
|
@@ -214,15 +223,16 @@ function createBotRuntime(deps) {
|
|
|
214
223
|
keyboard.text(`📁 ${ws.name}`, `view_workspace:${ws.id}`).row();
|
|
215
224
|
}
|
|
216
225
|
}
|
|
217
|
-
keyboard.text('
|
|
226
|
+
keyboard.text(t('bot.workspaces.add'), 'workspace_action:add').row().text(t('bot.general.back'), 'main_menu');
|
|
218
227
|
await renderText(ctx, lines.join('\n'), keyboard);
|
|
219
228
|
}
|
|
220
229
|
function buildWorkspaceDetailsKeyboard(workspace) {
|
|
230
|
+
const t = getT();
|
|
221
231
|
return createKeyboard()
|
|
222
|
-
.text('
|
|
223
|
-
.text('
|
|
232
|
+
.text(t('bot.workspaces.editName'), `workspace_action:edit_name:${workspace.id}`)
|
|
233
|
+
.text(t('bot.workspaces.editPath'), `workspace_action:edit_path:${workspace.id}`)
|
|
224
234
|
.row()
|
|
225
|
-
.text('
|
|
235
|
+
.text(t('bot.workspaces.delete'), `workspace_action:delete:${workspace.id}`)
|
|
226
236
|
.row()
|
|
227
237
|
.text('Powershell', `start_session:${workspace.id}:powershell`)
|
|
228
238
|
.text('Bash', `start_session:${workspace.id}:bash`)
|
|
@@ -230,53 +240,59 @@ function createBotRuntime(deps) {
|
|
|
230
240
|
.text('Codex', `start_session:${workspace.id}:codex`)
|
|
231
241
|
.text('Antigravity', `start_session:${workspace.id}:antigravity`)
|
|
232
242
|
.row()
|
|
233
|
-
.text('
|
|
243
|
+
.text(t('bot.general.back'), 'workspaces_list');
|
|
234
244
|
}
|
|
235
245
|
async function showWorkspaceDetails(ctx, workspaceId) {
|
|
236
246
|
const workspace = getWorkspaceById(workspaceId);
|
|
247
|
+
const t = getT();
|
|
237
248
|
if (!workspace) {
|
|
238
|
-
await renderText(ctx, '
|
|
249
|
+
await renderText(ctx, t('bot.workspaces.notFound'), createKeyboard().text(t('bot.general.back'), 'workspaces_list'));
|
|
239
250
|
return;
|
|
240
251
|
}
|
|
241
|
-
await renderText(ctx, ['
|
|
252
|
+
await renderText(ctx, [t('bot.workspaces.detailsTitle'), '', `${t('bot.workspaces.detailsName')}: ${workspace.name}`, `${t('bot.workspaces.detailsPath')}: ${workspace.path}`].join('\n'), buildWorkspaceDetailsKeyboard(workspace));
|
|
242
253
|
}
|
|
243
254
|
async function showSessionsMenu(ctx) {
|
|
244
255
|
const activeSession = deps.getActiveSession();
|
|
245
256
|
const keyboard = createKeyboard();
|
|
246
|
-
const
|
|
257
|
+
const t = getT();
|
|
258
|
+
const lines = [t('bot.sessions.title'), ''];
|
|
247
259
|
if (!activeSession || activeSession.status !== 'running') {
|
|
248
|
-
lines.push('
|
|
260
|
+
lines.push(t('bot.sessions.empty'));
|
|
249
261
|
}
|
|
250
262
|
else {
|
|
251
263
|
lines.push(`ID: ${activeSession.sessionId}`);
|
|
252
264
|
lines.push(`Preset: ${activeSession.preset}`);
|
|
253
|
-
lines.push(
|
|
254
|
-
keyboard.text('
|
|
265
|
+
lines.push(`${t('bot.sessionDetails.directory')}: ${activeSession.cwd}`);
|
|
266
|
+
keyboard.text(t('bot.sessions.control'), `view_session:${activeSession.sessionId}`).row();
|
|
255
267
|
}
|
|
256
|
-
keyboard.text('
|
|
268
|
+
keyboard.text(t('bot.general.back'), 'main_menu');
|
|
257
269
|
await renderText(ctx, lines.join('\n'), keyboard);
|
|
258
270
|
}
|
|
259
271
|
async function showSessionDetails(ctx, sessionId) {
|
|
260
272
|
const session = deps.getActiveSession();
|
|
273
|
+
const t = getT();
|
|
261
274
|
if (!session || session.status !== 'running' || (sessionId && session.sessionId !== sessionId)) {
|
|
262
|
-
await renderText(ctx, '
|
|
275
|
+
await renderText(ctx, t('bot.sessionDetails.notRunning'), createKeyboard().text(t('bot.general.back'), 'main_menu'));
|
|
263
276
|
return;
|
|
264
277
|
}
|
|
265
278
|
const keyboard = (0, session_controls_js_1.buildSessionActionMarkup)({
|
|
266
279
|
sessionId: session.sessionId,
|
|
267
280
|
inputMode: session.inputMode,
|
|
268
281
|
autoEnter: session.autoEnter,
|
|
269
|
-
includeBackButton: true
|
|
282
|
+
includeBackButton: true,
|
|
283
|
+
language: deps.getConfig().language
|
|
270
284
|
});
|
|
285
|
+
const onText = t('bot.sessionDetails.on');
|
|
286
|
+
const offText = t('bot.sessionDetails.off');
|
|
271
287
|
await renderText(ctx, [
|
|
272
|
-
'
|
|
288
|
+
t('bot.sessionDetails.title'),
|
|
273
289
|
'',
|
|
274
290
|
`ID: ${session.sessionId}`,
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
291
|
+
`${t('bot.sessionDetails.preset')}: ${session.preset}`,
|
|
292
|
+
`${t('bot.sessionDetails.status')}: ${session.status}`,
|
|
293
|
+
`${t('bot.sessionDetails.directory')}: ${session.cwd}`,
|
|
294
|
+
`${t('bot.sessionDetails.inputMode')}: ${session.inputMode ? onText : offText}`,
|
|
295
|
+
`${t('bot.sessionDetails.autoEnter')}: ${session.autoEnter ? onText : offText}`
|
|
280
296
|
].join('\n'), keyboard);
|
|
281
297
|
}
|
|
282
298
|
async function beginWorkspaceDraft(ctx, workspaceDraft, prompt) {
|
|
@@ -296,9 +312,10 @@ function createBotRuntime(deps) {
|
|
|
296
312
|
if (!draft)
|
|
297
313
|
return false;
|
|
298
314
|
const workspaces = [...deps.getWorkspaces()];
|
|
315
|
+
const t = getT();
|
|
299
316
|
if (draft.mode === 'add_name') {
|
|
300
317
|
state.workspaceDraft = { mode: 'add_path', name: text };
|
|
301
|
-
await ctx.reply('
|
|
318
|
+
await ctx.reply(t('bot.workspaces.addPathPrompt'));
|
|
302
319
|
return true;
|
|
303
320
|
}
|
|
304
321
|
if (draft.mode === 'add_path') {
|
|
@@ -310,21 +327,21 @@ function createBotRuntime(deps) {
|
|
|
310
327
|
workspaces.push(workspace);
|
|
311
328
|
deps.saveWorkspaces(workspaces);
|
|
312
329
|
state.workspaceDraft = null;
|
|
313
|
-
await ctx.reply(
|
|
330
|
+
await ctx.reply(t('bot.workspaces.added', { name: workspace.name }));
|
|
314
331
|
await showWorkspaceDetails(ctx, workspace.id);
|
|
315
332
|
return true;
|
|
316
333
|
}
|
|
317
334
|
const targetIndex = workspaces.findIndex((w) => w.id === draft.workspaceId);
|
|
318
335
|
if (targetIndex === -1) {
|
|
319
336
|
state.workspaceDraft = null;
|
|
320
|
-
await ctx.reply('
|
|
337
|
+
await ctx.reply(t('bot.workspaces.notExists'));
|
|
321
338
|
return true;
|
|
322
339
|
}
|
|
323
340
|
if (draft.mode === 'edit_name') {
|
|
324
341
|
workspaces[targetIndex] = { ...workspaces[targetIndex], name: text };
|
|
325
342
|
deps.saveWorkspaces(workspaces);
|
|
326
343
|
state.workspaceDraft = null;
|
|
327
|
-
await ctx.reply('
|
|
344
|
+
await ctx.reply(t('bot.workspaces.updatedName'));
|
|
328
345
|
await showWorkspaceDetails(ctx, workspaces[targetIndex].id);
|
|
329
346
|
return true;
|
|
330
347
|
}
|
|
@@ -332,7 +349,7 @@ function createBotRuntime(deps) {
|
|
|
332
349
|
workspaces[targetIndex] = { ...workspaces[targetIndex], path: text };
|
|
333
350
|
deps.saveWorkspaces(workspaces);
|
|
334
351
|
state.workspaceDraft = null;
|
|
335
|
-
await ctx.reply('
|
|
352
|
+
await ctx.reply(t('bot.workspaces.updatedPath'));
|
|
336
353
|
await showWorkspaceDetails(ctx, workspaces[targetIndex].id);
|
|
337
354
|
return true;
|
|
338
355
|
}
|
|
@@ -350,10 +367,11 @@ function createBotRuntime(deps) {
|
|
|
350
367
|
const field = draft.field;
|
|
351
368
|
const config = deps.getConfig();
|
|
352
369
|
const isNumeric = ['outputInterval', 'maxOutputLines', 'maxRenderLines'].includes(field);
|
|
370
|
+
const t = getT();
|
|
353
371
|
if (isNumeric) {
|
|
354
372
|
const parsed = parseInt(text, 10);
|
|
355
373
|
if (isNaN(parsed) || !Number.isFinite(parsed)) {
|
|
356
|
-
await ctx.reply(
|
|
374
|
+
await ctx.reply(t('bot.config.invalidValue', { field }));
|
|
357
375
|
return true;
|
|
358
376
|
}
|
|
359
377
|
const nextConfig = { ...config, [field]: parsed };
|
|
@@ -368,7 +386,7 @@ function createBotRuntime(deps) {
|
|
|
368
386
|
await deps.saveConfig(nextConfig);
|
|
369
387
|
}
|
|
370
388
|
state.configFieldDraft = null;
|
|
371
|
-
await ctx.reply(
|
|
389
|
+
await ctx.reply(t('bot.config.updated', { field }));
|
|
372
390
|
await showConfigMenu(ctx);
|
|
373
391
|
return true;
|
|
374
392
|
}
|
|
@@ -378,7 +396,8 @@ function createBotRuntime(deps) {
|
|
|
378
396
|
const username = normalizeUsername(ctx.from?.username);
|
|
379
397
|
const currentAllowedUsername = normalizeUsername(process.env.ADMIN_USERNAME || process.env.TELEGRAM_USERNAME || '');
|
|
380
398
|
if (currentAllowedUsername && username !== currentAllowedUsername) {
|
|
381
|
-
|
|
399
|
+
const t = getT();
|
|
400
|
+
await ctx.reply(t('bot.general.authError'));
|
|
382
401
|
return;
|
|
383
402
|
}
|
|
384
403
|
await next();
|
|
@@ -398,22 +417,24 @@ function createBotRuntime(deps) {
|
|
|
398
417
|
// /send <lệnh> — gửi raw text tới session đang chạy
|
|
399
418
|
bot.command('send', async (ctx) => {
|
|
400
419
|
const rawText = ctx.message?.text ?? '';
|
|
420
|
+
const t = getT();
|
|
401
421
|
// Bỏ phần "/send " ở đầu
|
|
402
422
|
const payload = rawText.replace(/^\/send\s*/i, '').trim();
|
|
403
423
|
if (!payload) {
|
|
404
|
-
await ctx.reply('
|
|
424
|
+
await ctx.reply(t('bot.general.sendUsage'));
|
|
405
425
|
return;
|
|
406
426
|
}
|
|
407
427
|
const session = deps.getActiveSession();
|
|
408
428
|
if (!session || session.status !== 'running') {
|
|
409
|
-
await ctx.reply('
|
|
429
|
+
await ctx.reply(t('bot.general.noActiveSession'));
|
|
410
430
|
return;
|
|
411
431
|
}
|
|
412
432
|
deps.sendInput(session.autoEnter ? `${payload}\r` : payload);
|
|
413
|
-
await ctx.reply('
|
|
433
|
+
await ctx.reply(t('bot.general.sentCommand'));
|
|
414
434
|
});
|
|
415
435
|
bot.on('message:text', async (ctx) => {
|
|
416
436
|
const text = ctx.message.text;
|
|
437
|
+
const t = getT();
|
|
417
438
|
// Bỏ qua các lệnh bắt đầu bằng /
|
|
418
439
|
if (text.startsWith('/'))
|
|
419
440
|
return;
|
|
@@ -425,10 +446,10 @@ function createBotRuntime(deps) {
|
|
|
425
446
|
if (session?.status === 'running' && session.inputMode) {
|
|
426
447
|
const payload = session.autoEnter ? `${text}\r` : text;
|
|
427
448
|
deps.sendInput(payload);
|
|
428
|
-
await ctx.reply('
|
|
449
|
+
await ctx.reply(t('bot.general.sentCommand'));
|
|
429
450
|
return;
|
|
430
451
|
}
|
|
431
|
-
await ctx.reply('
|
|
452
|
+
await ctx.reply(t('bot.general.defaultMessage'));
|
|
432
453
|
});
|
|
433
454
|
bot.callbackQuery('main_menu', async (ctx) => {
|
|
434
455
|
await safeAnswerCallback(ctx);
|
|
@@ -468,7 +489,8 @@ function createBotRuntime(deps) {
|
|
|
468
489
|
if (!chatId)
|
|
469
490
|
return;
|
|
470
491
|
getChatState(chatId).configFieldDraft = { field };
|
|
471
|
-
|
|
492
|
+
const t = getT();
|
|
493
|
+
await ctx.reply(t('bot.config.enterValue', { field }));
|
|
472
494
|
});
|
|
473
495
|
bot.callbackQuery('help_view', async (ctx) => {
|
|
474
496
|
await safeAnswerCallback(ctx);
|
|
@@ -484,15 +506,18 @@ function createBotRuntime(deps) {
|
|
|
484
506
|
});
|
|
485
507
|
bot.callbackQuery('workspace_action:add', async (ctx) => {
|
|
486
508
|
await safeAnswerCallback(ctx);
|
|
487
|
-
|
|
509
|
+
const t = getT();
|
|
510
|
+
await beginWorkspaceDraft(ctx, { mode: 'add_name' }, t('bot.workspaces.addNamePrompt'));
|
|
488
511
|
});
|
|
489
512
|
bot.callbackQuery(/^workspace_action:edit_name:(.+)$/, async (ctx) => {
|
|
490
513
|
await safeAnswerCallback(ctx);
|
|
491
|
-
|
|
514
|
+
const t = getT();
|
|
515
|
+
await beginWorkspaceDraft(ctx, { mode: 'edit_name', workspaceId: ctx.match[1] }, t('bot.workspaces.addNamePrompt'));
|
|
492
516
|
});
|
|
493
517
|
bot.callbackQuery(/^workspace_action:edit_path:(.+)$/, async (ctx) => {
|
|
494
518
|
await safeAnswerCallback(ctx);
|
|
495
|
-
|
|
519
|
+
const t = getT();
|
|
520
|
+
await beginWorkspaceDraft(ctx, { mode: 'edit_path', workspaceId: ctx.match[1] }, t('bot.workspaces.addPathPrompt'));
|
|
496
521
|
});
|
|
497
522
|
bot.callbackQuery(/^workspace_action:delete:(.+)$/, async (ctx) => {
|
|
498
523
|
await safeAnswerCallback(ctx);
|
|
@@ -504,17 +529,18 @@ function createBotRuntime(deps) {
|
|
|
504
529
|
await safeAnswerCallback(ctx);
|
|
505
530
|
const workspaceId = ctx.match[1];
|
|
506
531
|
const preset = ctx.match[2];
|
|
532
|
+
const t = getT();
|
|
507
533
|
if (!SUPPORTED_PRESETS.includes(preset)) {
|
|
508
|
-
await ctx.reply(
|
|
534
|
+
await ctx.reply(t('bot.sessionControls.presetNotSupported', { preset }));
|
|
509
535
|
return;
|
|
510
536
|
}
|
|
511
537
|
if (deps.getActiveSession()?.status === 'running') {
|
|
512
|
-
await ctx.reply('
|
|
538
|
+
await ctx.reply(t('bot.sessionControls.runningSessionExists'));
|
|
513
539
|
return;
|
|
514
540
|
}
|
|
515
541
|
const workspace = getWorkspaceById(workspaceId);
|
|
516
542
|
if (!workspace) {
|
|
517
|
-
await ctx.reply('
|
|
543
|
+
await ctx.reply(t('bot.workspaces.notFound'));
|
|
518
544
|
return;
|
|
519
545
|
}
|
|
520
546
|
try {
|
|
@@ -527,7 +553,7 @@ function createBotRuntime(deps) {
|
|
|
527
553
|
preset,
|
|
528
554
|
error: error instanceof Error ? error.message : String(error)
|
|
529
555
|
});
|
|
530
|
-
await ctx.reply(
|
|
556
|
+
await ctx.reply(t('bot.sessionControls.startError', { error: error instanceof Error ? error.message : String(error) }));
|
|
531
557
|
}
|
|
532
558
|
});
|
|
533
559
|
bot.callbackQuery('sessions_list', async (ctx) => {
|
|
@@ -543,8 +569,9 @@ function createBotRuntime(deps) {
|
|
|
543
569
|
const session = deps.getActiveSession();
|
|
544
570
|
const sessionId = ctx.match[1];
|
|
545
571
|
const action = ctx.match[2];
|
|
572
|
+
const t = getT();
|
|
546
573
|
if (!session || session.sessionId !== sessionId || session.status !== 'running') {
|
|
547
|
-
await ctx.reply('
|
|
574
|
+
await ctx.reply(t('bot.sessionControls.notRunning'));
|
|
548
575
|
return;
|
|
549
576
|
}
|
|
550
577
|
switch (action) {
|
|
@@ -567,7 +594,7 @@ function createBotRuntime(deps) {
|
|
|
567
594
|
case 'refresh':
|
|
568
595
|
break;
|
|
569
596
|
default:
|
|
570
|
-
await ctx.reply(
|
|
597
|
+
await ctx.reply(t('bot.sessionControls.unsupportedAction', { action }));
|
|
571
598
|
return;
|
|
572
599
|
}
|
|
573
600
|
await showSessionDetails(ctx, sessionId);
|
package/dist/i18n.js
CHANGED
|
@@ -25,7 +25,78 @@ const MESSAGES = {
|
|
|
25
25
|
'settings.saved': 'Settings saved.',
|
|
26
26
|
'startup.disabled': 'Disabled',
|
|
27
27
|
'startup.background': 'Background',
|
|
28
|
-
'startup.openUi': 'Open UI'
|
|
28
|
+
'startup.openUi': 'Open UI',
|
|
29
|
+
// Bot English
|
|
30
|
+
'bot.menu.workspaces': '📁 Workspaces',
|
|
31
|
+
'bot.menu.session': '⚡ Session',
|
|
32
|
+
'bot.menu.config': '⚙️ Settings',
|
|
33
|
+
'bot.menu.help': 'ℹ️ Help',
|
|
34
|
+
'bot.menu.activeSessionNone': '⚡ Session: none',
|
|
35
|
+
'bot.menu.activeSessionRunning': '⚡ Session: {preset} | {cwd}',
|
|
36
|
+
'bot.help.title': '📖 Available Commands',
|
|
37
|
+
'bot.help.start': '/start — Open main menu',
|
|
38
|
+
'bot.help.status': '/status — Runtime status',
|
|
39
|
+
'bot.help.help': '/help — Help text',
|
|
40
|
+
'bot.help.config': '/config — System configuration',
|
|
41
|
+
'bot.help.send': '/send <command> — Send raw input directly to the active session',
|
|
42
|
+
'bot.help.inputModeNotice': 'When Input Mode is ON, any normal text message you send (without a leading /) will be fed directly into your shell.',
|
|
43
|
+
'bot.help.back': '⬅️ Back',
|
|
44
|
+
'bot.status.title': '📊 Runtime Status',
|
|
45
|
+
'bot.status.user': 'User',
|
|
46
|
+
'bot.status.unlimited': 'unlimited',
|
|
47
|
+
'bot.status.workspaces': 'Workspaces',
|
|
48
|
+
'bot.status.session': 'Session',
|
|
49
|
+
'bot.status.running': 'running',
|
|
50
|
+
'bot.status.none': 'none',
|
|
51
|
+
'bot.status.preset': 'Preset',
|
|
52
|
+
'bot.status.directory': 'Directory',
|
|
53
|
+
'bot.config.title': '⚙️ nonstop configuration',
|
|
54
|
+
'bot.config.notConfigured': 'Not configured',
|
|
55
|
+
'bot.config.languageLabel': 'Language',
|
|
56
|
+
'bot.config.startupLabel': 'Startup Mode',
|
|
57
|
+
'bot.config.updated': '✓ Config updated for "{field}".',
|
|
58
|
+
'bot.config.enterValue': 'Enter new value for field "{field}":',
|
|
59
|
+
'bot.config.invalidValue': '❌ Invalid value. Please enter a valid integer for field "{field}".',
|
|
60
|
+
'bot.workspaces.title': '📁 Workspace List',
|
|
61
|
+
'bot.workspaces.empty': 'No workspaces configured.',
|
|
62
|
+
'bot.workspaces.add': '➕ Add workspace',
|
|
63
|
+
'bot.workspaces.editName': '✏️ Edit name',
|
|
64
|
+
'bot.workspaces.editPath': '🛠️ Edit path',
|
|
65
|
+
'bot.workspaces.delete': '🗑️ Delete',
|
|
66
|
+
'bot.workspaces.notFound': 'Workspace not found.',
|
|
67
|
+
'bot.workspaces.detailsTitle': '📁 Workspace Details',
|
|
68
|
+
'bot.workspaces.detailsName': 'Name',
|
|
69
|
+
'bot.workspaces.detailsPath': 'Path',
|
|
70
|
+
'bot.workspaces.addNamePrompt': 'Enter new workspace name:',
|
|
71
|
+
'bot.workspaces.addPathPrompt': 'Enter workspace path:',
|
|
72
|
+
'bot.workspaces.added': '✓ Added workspace "{name}".',
|
|
73
|
+
'bot.workspaces.notExists': 'Workspace no longer exists.',
|
|
74
|
+
'bot.workspaces.updatedName': '✓ Updated workspace name.',
|
|
75
|
+
'bot.workspaces.updatedPath': '✓ Updated workspace path.',
|
|
76
|
+
'bot.sessions.title': '⚡ Session',
|
|
77
|
+
'bot.sessions.empty': 'No running session.',
|
|
78
|
+
'bot.sessions.control': '🎮 Control',
|
|
79
|
+
'bot.sessionDetails.title': '🎮 Session Control',
|
|
80
|
+
'bot.sessionDetails.notRunning': 'Session is not running.',
|
|
81
|
+
'bot.sessionDetails.id': 'ID',
|
|
82
|
+
'bot.sessionDetails.preset': 'Preset',
|
|
83
|
+
'bot.sessionDetails.status': 'Status',
|
|
84
|
+
'bot.sessionDetails.directory': 'Directory',
|
|
85
|
+
'bot.sessionDetails.inputMode': 'Input mode',
|
|
86
|
+
'bot.sessionDetails.autoEnter': 'Auto enter',
|
|
87
|
+
'bot.sessionDetails.on': 'ON',
|
|
88
|
+
'bot.sessionDetails.off': 'OFF',
|
|
89
|
+
'bot.sessionControls.presetNotSupported': 'Preset not supported: {preset}',
|
|
90
|
+
'bot.sessionControls.runningSessionExists': 'There is already a running session. Stop the current session first.',
|
|
91
|
+
'bot.sessionControls.startError': 'Error starting session: {error}',
|
|
92
|
+
'bot.sessionControls.notRunning': 'Session is not running.',
|
|
93
|
+
'bot.sessionControls.unsupportedAction': 'Unsupported action: {action}',
|
|
94
|
+
'bot.general.back': '⬅️ Back',
|
|
95
|
+
'bot.general.authError': 'This bot is only for the configured Telegram account.',
|
|
96
|
+
'bot.general.sendUsage': 'Usage: /send <command to send>',
|
|
97
|
+
'bot.general.noActiveSession': 'No active session running.',
|
|
98
|
+
'bot.general.sentCommand': '✓ Command sent',
|
|
99
|
+
'bot.general.defaultMessage': 'Use /start to open the menu.'
|
|
29
100
|
},
|
|
30
101
|
vi: {
|
|
31
102
|
'wizard.title': 'Thiết lập nonstop',
|
|
@@ -50,9 +121,88 @@ const MESSAGES = {
|
|
|
50
121
|
'settings.saved': 'Đã lưu cấu hình.',
|
|
51
122
|
'startup.disabled': 'Tắt',
|
|
52
123
|
'startup.background': 'Chạy nền',
|
|
53
|
-
'startup.openUi': 'Mở giao diện'
|
|
124
|
+
'startup.openUi': 'Mở giao diện',
|
|
125
|
+
// Bot Vietnamese
|
|
126
|
+
'bot.menu.workspaces': '📁 Workspaces',
|
|
127
|
+
'bot.menu.session': '⚡ Session',
|
|
128
|
+
'bot.menu.config': '⚙️ Cấu hình',
|
|
129
|
+
'bot.menu.help': 'ℹ️ Trợ giúp',
|
|
130
|
+
'bot.menu.activeSessionNone': '⚡ Session: không có',
|
|
131
|
+
'bot.menu.activeSessionRunning': '⚡ Session: {preset} | {cwd}',
|
|
132
|
+
'bot.help.title': '📖 Lệnh có sẵn',
|
|
133
|
+
'bot.help.start': '/start — Mở menu chính',
|
|
134
|
+
'bot.help.status': '/status — Trạng thái runtime',
|
|
135
|
+
'bot.help.help': '/help — Trợ giúp',
|
|
136
|
+
'bot.help.config': '/config — Cấu hình hệ thống',
|
|
137
|
+
'bot.help.send': '/send <lệnh> — Gửi lệnh thô tới session',
|
|
138
|
+
'bot.help.inputModeNotice': 'Khi input mode BẬT, tin nhắn thường sẽ được gửi thẳng vào session.',
|
|
139
|
+
'bot.help.back': '⬅️ Quay lại',
|
|
140
|
+
'bot.status.title': '📊 Trạng thái Runtime',
|
|
141
|
+
'bot.status.user': 'Người dùng',
|
|
142
|
+
'bot.status.unlimited': 'không giới hạn',
|
|
143
|
+
'bot.status.workspaces': 'Workspaces',
|
|
144
|
+
'bot.status.session': 'Session',
|
|
145
|
+
'bot.status.running': 'đang chạy',
|
|
146
|
+
'bot.status.none': 'không có',
|
|
147
|
+
'bot.status.preset': 'Preset',
|
|
148
|
+
'bot.status.directory': 'Thư mục',
|
|
149
|
+
'bot.config.title': '⚙️ Cấu hình nonstop',
|
|
150
|
+
'bot.config.notConfigured': 'Chưa cấu hình',
|
|
151
|
+
'bot.config.languageLabel': 'Ngôn ngữ',
|
|
152
|
+
'bot.config.startupLabel': 'Chế độ khởi động',
|
|
153
|
+
'bot.config.updated': '✓ Đã cập nhật cấu hình cho "{field}".',
|
|
154
|
+
'bot.config.enterValue': 'Nhập giá trị mới cho field "{field}":',
|
|
155
|
+
'bot.config.invalidValue': '❌ Giá trị nhập vào không hợp lệ. Vui lòng nhập một số nguyên hợp lệ cho field "{field}".',
|
|
156
|
+
'bot.workspaces.title': '📁 Danh sách Workspace',
|
|
157
|
+
'bot.workspaces.empty': 'Chưa có workspace nào.',
|
|
158
|
+
'bot.workspaces.add': '➕ Thêm workspace',
|
|
159
|
+
'bot.workspaces.editName': '✏️ Sửa tên',
|
|
160
|
+
'bot.workspaces.editPath': '🛠️ Sửa đường dẫn',
|
|
161
|
+
'bot.workspaces.delete': '🗑️ Xóa',
|
|
162
|
+
'bot.workspaces.notFound': 'Workspace không tìm thấy.',
|
|
163
|
+
'bot.workspaces.detailsTitle': '📁 Chi tiết Workspace',
|
|
164
|
+
'bot.workspaces.detailsName': 'Tên',
|
|
165
|
+
'bot.workspaces.detailsPath': 'Đường dẫn',
|
|
166
|
+
'bot.workspaces.addNamePrompt': 'Nhập tên workspace mới:',
|
|
167
|
+
'bot.workspaces.addPathPrompt': 'Nhập đường dẫn workspace:',
|
|
168
|
+
'bot.workspaces.added': '✓ Đã thêm workspace "{name}".',
|
|
169
|
+
'bot.workspaces.notExists': 'Workspace không còn tồn tại.',
|
|
170
|
+
'bot.workspaces.updatedName': '✓ Đã cập nhật tên workspace.',
|
|
171
|
+
'bot.workspaces.updatedPath': '✓ Đã cập nhật đường dẫn workspace.',
|
|
172
|
+
'bot.sessions.title': '⚡ Session',
|
|
173
|
+
'bot.sessions.empty': 'Không có session đang chạy.',
|
|
174
|
+
'bot.sessions.control': '🎮 Điều khiển',
|
|
175
|
+
'bot.sessionDetails.title': '🎮 Điều khiển Session',
|
|
176
|
+
'bot.sessionDetails.notRunning': 'Session không đang chạy.',
|
|
177
|
+
'bot.sessionDetails.id': 'ID',
|
|
178
|
+
'bot.sessionDetails.preset': 'Preset',
|
|
179
|
+
'bot.sessionDetails.status': 'Trạng thái',
|
|
180
|
+
'bot.sessionDetails.directory': 'Thư mục',
|
|
181
|
+
'bot.sessionDetails.inputMode': 'Input mode',
|
|
182
|
+
'bot.sessionDetails.autoEnter': 'Auto enter',
|
|
183
|
+
'bot.sessionDetails.on': 'BẬT',
|
|
184
|
+
'bot.sessionDetails.off': 'TẮT',
|
|
185
|
+
'bot.sessionControls.presetNotSupported': 'Preset không hỗ trợ: {preset}',
|
|
186
|
+
'bot.sessionControls.runningSessionExists': 'Đã có session đang chạy. Dừng session hiện tại trước.',
|
|
187
|
+
'bot.sessionControls.startError': 'Lỗi khi khởi chạy session: {error}',
|
|
188
|
+
'bot.sessionControls.notRunning': 'Session không đang chạy.',
|
|
189
|
+
'bot.sessionControls.unsupportedAction': 'Hành động không hỗ trợ: {action}',
|
|
190
|
+
'bot.general.back': '⬅️ Quay lại',
|
|
191
|
+
'bot.general.authError': 'Bot này chỉ dành cho tài khoản Telegram đã cấu hình.',
|
|
192
|
+
'bot.general.sendUsage': 'Cách dùng: /send <lệnh cần gửi>',
|
|
193
|
+
'bot.general.noActiveSession': 'Không có session đang chạy.',
|
|
194
|
+
'bot.general.sentCommand': '✓ Đã gửi lệnh',
|
|
195
|
+
'bot.general.defaultMessage': 'Dùng /start để mở menu.'
|
|
54
196
|
}
|
|
55
197
|
};
|
|
56
198
|
function createTranslator(language) {
|
|
57
|
-
return (key) =>
|
|
199
|
+
return (key, params) => {
|
|
200
|
+
let msg = MESSAGES[language][key] || MESSAGES.en[key];
|
|
201
|
+
if (params) {
|
|
202
|
+
for (const [k, v] of Object.entries(params)) {
|
|
203
|
+
msg = msg.replace(new RegExp(`{${k}}`, 'g'), String(v));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return msg;
|
|
207
|
+
};
|
|
58
208
|
}
|
package/dist/runtime-manager.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getRuntimeStatus = getRuntimeStatus;
|
|
37
|
+
exports.getEntryScriptPath = getEntryScriptPath;
|
|
37
38
|
exports.startBackgroundRuntime = startBackgroundRuntime;
|
|
38
39
|
exports.stopBackgroundRuntime = stopBackgroundRuntime;
|
|
39
40
|
const child_process_1 = require("child_process");
|
|
@@ -50,11 +51,25 @@ function getRuntimeStatus() {
|
|
|
50
51
|
}
|
|
51
52
|
return { running: true, snapshot };
|
|
52
53
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
function getEntryScriptPath() {
|
|
55
|
+
// Try relative to __dirname (compiled location inside dist/)
|
|
56
|
+
const prodPath = path.join(__dirname, 'index.js');
|
|
57
|
+
if (fs.existsSync(prodPath)) {
|
|
58
|
+
return prodPath;
|
|
59
|
+
}
|
|
60
|
+
// Try relative to process.cwd() (local dev environment)
|
|
61
|
+
const localDevPath = path.join(process.cwd(), 'dist', 'index.js');
|
|
62
|
+
if (fs.existsSync(localDevPath)) {
|
|
63
|
+
return localDevPath;
|
|
64
|
+
}
|
|
65
|
+
// Fallback to process.argv[1]
|
|
66
|
+
if (process.argv[1] && process.argv[1].endsWith('.js') && fs.existsSync(process.argv[1])) {
|
|
67
|
+
return process.argv[1];
|
|
57
68
|
}
|
|
69
|
+
throw new Error('dist/index.js not found. Please ensure the project is built.');
|
|
70
|
+
}
|
|
71
|
+
function startBackgroundRuntime() {
|
|
72
|
+
const entryScriptPath = getEntryScriptPath();
|
|
58
73
|
const child = (0, child_process_1.spawn)(process.execPath, [entryScriptPath, '--background'], {
|
|
59
74
|
cwd: process.cwd(),
|
|
60
75
|
detached: true,
|
package/dist/runtime.js
CHANGED
|
@@ -373,7 +373,8 @@ class NonstopRuntime {
|
|
|
373
373
|
sessionId: session.sessionId,
|
|
374
374
|
snapshot: finalText,
|
|
375
375
|
inputMode: session.inputMode,
|
|
376
|
-
autoEnter: session.autoEnter
|
|
376
|
+
autoEnter: session.autoEnter,
|
|
377
|
+
language: this.config.language
|
|
377
378
|
});
|
|
378
379
|
if (!this.onSessionOutputPush) {
|
|
379
380
|
session.lastSentFinalText = finalText;
|
package/dist/session-controls.js
CHANGED
|
@@ -4,18 +4,23 @@ exports.buildSessionActionMarkup = buildSessionActionMarkup;
|
|
|
4
4
|
function buildSessionActionMarkup(options) {
|
|
5
5
|
const inputMode = options.inputMode ?? true;
|
|
6
6
|
const autoEnter = options.autoEnter ?? true;
|
|
7
|
+
const isVi = options.language === 'vi';
|
|
7
8
|
const rows = [
|
|
8
9
|
[
|
|
9
10
|
{
|
|
10
|
-
text: inputMode
|
|
11
|
+
text: inputMode
|
|
12
|
+
? (isVi ? '⌨️ Tắt Input' : '⌨️ Input OFF')
|
|
13
|
+
: (isVi ? '⌨️ Bật Input' : '⌨️ Input ON'),
|
|
11
14
|
callback_data: `session_cmd:${options.sessionId}:toggle_input`
|
|
12
15
|
},
|
|
13
16
|
{
|
|
14
|
-
text: autoEnter
|
|
17
|
+
text: autoEnter
|
|
18
|
+
? (isVi ? '⏎ Tắt AutoEnter' : '⏎ AutoEnter OFF')
|
|
19
|
+
: (isVi ? '⏎ Bật AutoEnter' : '⏎ Bật AutoEnter ON'),
|
|
15
20
|
callback_data: `session_cmd:${options.sessionId}:toggle_enter`
|
|
16
21
|
},
|
|
17
22
|
{
|
|
18
|
-
text: '🔄 Refresh',
|
|
23
|
+
text: isVi ? '🔄 Tải lại' : '🔄 Refresh',
|
|
19
24
|
callback_data: `session_cmd:${options.sessionId}:refresh`
|
|
20
25
|
}
|
|
21
26
|
],
|
|
@@ -25,11 +30,11 @@ function buildSessionActionMarkup(options) {
|
|
|
25
30
|
callback_data: `session_cmd:${options.sessionId}:send_escape`
|
|
26
31
|
},
|
|
27
32
|
{
|
|
28
|
-
text: '⬆️ Up',
|
|
33
|
+
text: isVi ? '⬆️ Lên' : '⬆️ Up',
|
|
29
34
|
callback_data: `session_cmd:${options.sessionId}:send_up`
|
|
30
35
|
},
|
|
31
36
|
{
|
|
32
|
-
text: '⬇️ Down',
|
|
37
|
+
text: isVi ? '⬇️ Xuống' : '⬇️ Down',
|
|
33
38
|
callback_data: `session_cmd:${options.sessionId}:send_down`
|
|
34
39
|
}
|
|
35
40
|
],
|
|
@@ -39,7 +44,7 @@ function buildSessionActionMarkup(options) {
|
|
|
39
44
|
callback_data: `session_cmd:${options.sessionId}:send_enter`
|
|
40
45
|
},
|
|
41
46
|
{
|
|
42
|
-
text: '🛑 Stop',
|
|
47
|
+
text: isVi ? '🛑 Dừng' : '🛑 Stop',
|
|
43
48
|
callback_data: `session_cmd:${options.sessionId}:stop`
|
|
44
49
|
}
|
|
45
50
|
]
|
|
@@ -47,7 +52,7 @@ function buildSessionActionMarkup(options) {
|
|
|
47
52
|
if (options.includeBackButton) {
|
|
48
53
|
rows.push([
|
|
49
54
|
{
|
|
50
|
-
text: '⬅️ Back',
|
|
55
|
+
text: isVi ? '⬅️ Quay lại' : '⬅️ Back',
|
|
51
56
|
callback_data: 'sessions_list'
|
|
52
57
|
}
|
|
53
58
|
]);
|
package/dist/session-output.js
CHANGED
|
@@ -9,7 +9,8 @@ function buildSessionOutputMessages(options) {
|
|
|
9
9
|
sessionId: options.sessionId,
|
|
10
10
|
inputMode: options.inputMode,
|
|
11
11
|
autoEnter: options.autoEnter,
|
|
12
|
-
includeBackButton: false
|
|
12
|
+
includeBackButton: false,
|
|
13
|
+
language: options.language
|
|
13
14
|
});
|
|
14
15
|
return chunkTelegramCodeBlocks(options.snapshot, TELEGRAM_MESSAGE_LIMIT).map((chunk) => ({
|
|
15
16
|
text: `\`\`\`\n${chunk}\n\`\`\``,
|
package/dist/store.js
CHANGED
|
@@ -52,26 +52,22 @@ exports.workspacesFilePath = path.join(exports.DATA_DIR, 'workspaces.json');
|
|
|
52
52
|
function loadWorkspaces() {
|
|
53
53
|
ensureDataDir();
|
|
54
54
|
if (!fs.existsSync(exports.workspacesFilePath)) {
|
|
55
|
-
return
|
|
55
|
+
return [];
|
|
56
56
|
}
|
|
57
57
|
try {
|
|
58
58
|
const raw = fs.readFileSync(exports.workspacesFilePath, 'utf8');
|
|
59
59
|
const parsed = JSON.parse(raw);
|
|
60
60
|
if (!Array.isArray(parsed)) {
|
|
61
|
-
return
|
|
61
|
+
return [];
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
return parsed.filter(isWorkspaceRecord).map((workspace) => ({
|
|
64
64
|
id: workspace.id,
|
|
65
65
|
name: workspace.name,
|
|
66
66
|
path: workspace.path
|
|
67
67
|
}));
|
|
68
|
-
if (workspaces.length === 0) {
|
|
69
|
-
return regenerateDefaultWorkspaces();
|
|
70
|
-
}
|
|
71
|
-
return workspaces;
|
|
72
68
|
}
|
|
73
69
|
catch {
|
|
74
|
-
return
|
|
70
|
+
return [];
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
function saveWorkspaces(workspaces) {
|
|
@@ -90,25 +86,3 @@ function isWorkspaceRecord(value) {
|
|
|
90
86
|
typeof record.name === 'string' &&
|
|
91
87
|
typeof record.path === 'string');
|
|
92
88
|
}
|
|
93
|
-
function regenerateDefaultWorkspaces() {
|
|
94
|
-
const rootDir = path.resolve(exports.DATA_DIR, '..');
|
|
95
|
-
const defaultWorkspaces = [
|
|
96
|
-
{
|
|
97
|
-
id: 'ws_root',
|
|
98
|
-
name: 'Project Root',
|
|
99
|
-
path: rootDir.replace(/\\/g, '/')
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
id: 'ws_src',
|
|
103
|
-
name: 'Source',
|
|
104
|
-
path: path.join(rootDir, 'src').replace(/\\/g, '/')
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
id: 'ws_docs',
|
|
108
|
-
name: 'Docs',
|
|
109
|
-
path: path.join(rootDir, 'docs').replace(/\\/g, '/')
|
|
110
|
-
}
|
|
111
|
-
];
|
|
112
|
-
saveWorkspaces(defaultWorkspaces);
|
|
113
|
-
return defaultWorkspaces;
|
|
114
|
-
}
|
package/dist/ui.js
CHANGED
|
@@ -423,7 +423,7 @@ async function configureStartup(config) {
|
|
|
423
423
|
{ label: isVi ? 'Chạy nền (background)' : 'Background', value: 'background' },
|
|
424
424
|
{ label: isVi ? 'Mở giao diện (open-ui)' : 'Open UI', value: 'open-ui' }
|
|
425
425
|
], ['disabled', 'background', 'open-ui'].indexOf(config.startupMode));
|
|
426
|
-
const entryScriptPath =
|
|
426
|
+
const entryScriptPath = (0, runtime_manager_js_1.getEntryScriptPath)();
|
|
427
427
|
const result = (0, startup_js_1.applyStartupMode)(nextMode, entryScriptPath, process.cwd());
|
|
428
428
|
const nextConfig = { ...config, startupMode: nextMode };
|
|
429
429
|
(0, config_js_1.saveConfigToDisk)(nextConfig);
|