@quangnv13/nonstop 1.0.13 → 1.0.16

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 CHANGED
@@ -1,6 +1,8 @@
1
- # 🚀 nonstop
1
+ <h1 align="center">🚀 nonstop</h1>
2
2
 
3
- 🌐 [Tiếng Việt](./README.vi.md) | **English**
3
+ <p align="center">
4
+ 🌐 <b>English</b> | 🌐 <a href="./README.vi.md">Tiếng Việt</a>
5
+ </p>
4
6
 
5
7
  <p align="center">
6
8
  <img src="./images/nonstop.png" alt="nonstop Banner" width="800px" style="border-radius: 8px;" />
@@ -34,14 +36,17 @@
34
36
  ## 🌟 Key Features
35
37
 
36
38
  * **💻 Immersive TUI Control Center** — Manage runtime processes, inspect logs, register workspaces, and edit configuration directly from a command-line interface.
37
- * **🤖 Telegram PTY Terminal** — Execute and control real-time, interactive shell sessions (PowerShell, Bash, Codex, or Antigravity) remotely from Telegram.
39
+ * **🤖 Telegram PTY Terminal** — Execute and control real-time, interactive shell sessions (PowerShell, Bash, Codex, Antigravity, or Claude) remotely from Telegram.
38
40
  * **⚙️ Inline Configuration Engine** — Modify environment settings dynamically through the new `/config` inline Telegram menu or directly in the CLI.
39
41
  * **📂 Smart Workspaces** — Navigate and switch between different working directories on your machine with a few taps.
40
42
  * **🔄 Optimized Output Stream** — Advanced batch-delivery mechanics with configurable output intervals (`OUTPUT_INTERVAL`) and interaction-triggered flush delays (`ACTION_INTERVAL`), ensuring fluid terminal logs inside Telegram without hitting API limits.
41
43
  * **🚀 Native OS Autostart** — Easy configuration to run as a background service on OS startup (supports Windows and Linux).
44
+ * **🔄 Seamless Remote/Local Switching** — Continue background PTY sessions directly from your computer terminal. The Telegram output sync automatically pauses during active local interaction to prevent rate limits, then flushes a final summary snapshot of the session to Telegram immediately when you detach (via `Ctrl+B` then `D`).
45
+ * **⚠️ Dangerous Command Protection** — Intercepts and prompts for confirmation (via Telegram inline buttons) before executing commands matching a customizable comma-separated list of dangerous patterns, preventing accidental system damage.
42
46
  * **🌐 Bilingual Support** — Fully localized in English (`en`) and Vietnamese (`vi`).
43
47
  * **🛡️ Hardened Security** — Hardened token validation and authorization checks, restricting control access strictly to the configured admin account.
44
48
 
49
+
45
50
  ---
46
51
 
47
52
  ## ⚙️ Architecture & Data Flow
@@ -104,6 +109,7 @@ nonstop
104
109
  Simply run `nonstop` in your terminal to open the management dashboard. From here, you can:
105
110
  * **Start / Stop** the background bot runtime.
106
111
  * **Configure Workspaces**: Manage directories where terminal sessions can be started.
112
+ * **Attach to Active Sessions**: View and take over background shell sessions (e.g., started from Telegram) directly in your computer's terminal.
107
113
  * **Autostart Settings**: Set up the application to run automatically on system boot.
108
114
  * **View Logs**: Monitor bot logs and output in real time.
109
115
 
@@ -119,7 +125,7 @@ Once the bot runtime is active, you can interact with it via the following Teleg
119
125
 
120
126
  #### **⚡ Managing PTY Shell Sessions**
121
127
  1. Select **⚡ Session** from the main menu.
122
- 2. Select an environment preset (e.g., **PowerShell**, **Bash**, **Codex**, or **Antigravity**) to start a session.
128
+ 2. Select an environment preset (e.g., **PowerShell**, **Bash**, **Codex**, **Antigravity**, or **Claude**) to start a session.
123
129
  3. Once running, **enable Input Mode**.
124
130
  4. Any normal text message you send to the bot (without a leading `/`) will be fed directly into your shell.
125
131
  5. Use the inline control buttons to send key inputs:
@@ -139,6 +145,25 @@ Once the bot runtime is active, you can interact with it via the following Teleg
139
145
  * Tap any settings button (e.g. *Token*, *Admin*, *Interval*, etc.) and send a new value via message to apply immediately.
140
146
  * If you modify the `Telegram Bot Token`, the bot will automatically reload and restart itself securely.
141
147
 
148
+ ### 3. Remote/Local Switching
149
+ `nonstop` allows you to seamlessly switch control between your Telegram app and your local computer terminal:
150
+
151
+ 1. **Start the Session on Telegram**: Run a session from Telegram bot as usual (e.g., select **⚡ Session** -> **PowerShell**).
152
+ 2. **Take Over Locally**:
153
+ - Open your computer's terminal and run:
154
+ ```bash
155
+ nonstop
156
+ ```
157
+ - In the TUI, select **List of spawned CLIs**.
158
+ - Select the active session you want to connect to.
159
+ - You are now connected directly. Any typing or commands run locally will execute in the same background PTY process.
160
+ - *Note: While you are attached locally, synchronization of new outputs to Telegram is automatically paused to prevent hitting Telegram API rate limits.*
161
+ 3. **Detach and Return to Telegram**:
162
+ - To disconnect from the local terminal without stopping the process, press **`Ctrl+B` then `D`** (similar to detaching in tmux).
163
+ - `nonstop` will detach, and the session will continue running in the background.
164
+ - Upon detachment, a final summary snapshot of the session's terminal screen is automatically sent to Telegram so you can see the latest status.
165
+ - You can now resume interacting with the session via the Telegram Bot.
166
+
142
167
  ---
143
168
 
144
169
  ## 🎛️ Configuration
@@ -154,6 +179,15 @@ APP_LANGUAGE=en
154
179
  STARTUP_MODE=disabled
155
180
  OUTPUT_INTERVAL=20000
156
181
  ACTION_INTERVAL=5000
182
+ DANGEROUS_COMMAND_CONFIRM=rm -rf /,rm -rf,rm -fr,sudo,del /s,rd /s,rmdir /s,format,shutdown,reboot,poweroff,init 0,dd if=,mkfs,fdisk
183
+
184
+ # CLI OVERRIDES (Optional)
185
+ CODEX_CMD=codex
186
+ CODEX_ARGS=[]
187
+ ANTIGRAVITY_CMD=agy
188
+ ANTIGRAVITY_ARGS=[]
189
+ CLAUDE_CMD=claude
190
+ CLAUDE_ARGS=[]
157
191
  ```
158
192
 
159
193
  ---
package/README.vi.md CHANGED
@@ -1,6 +1,8 @@
1
- # 🚀 nonstop
1
+ <h1 align="center">🚀 nonstop</h1>
2
2
 
3
- 🌐 **Tiếng Việt** | [English](./README.md)
3
+ <p align="center">
4
+ <a href="./README.md">English</a> | 🌐 <b>Tiếng Việt</b>
5
+ </p>
4
6
 
5
7
  <p align="center">
6
8
  <img src="./images/nonstop.png" alt="nonstop Banner" width="800px" style="border-radius: 8px;" />
@@ -34,14 +36,17 @@
34
36
  ## 🌟 Tính Năng Nổi Bật
35
37
 
36
38
  * **💻 Trung Tâm Điều Khiển TUI Trực Quan** — Quản lý các tiến trình runtime, kiểm tra nhật ký (logs), đăng ký thư mục làm việc và sửa đổi cấu hình trực tiếp từ giao diện terminal.
37
- * **🤖 Terminal PTY Qua Telegram** — Thực thi và điều khiển các phiên shell tương tác thời gian thực (PowerShell, Bash, Codex hoặc Antigravity) từ xa thông qua Telegram.
39
+ * **🤖 Terminal PTY Qua Telegram** — Thực thi và điều khiển các phiên shell tương tác thời gian thực (PowerShell, Bash, Codex, Antigravity hoặc Claude) từ xa thông qua Telegram.
38
40
  * **⚙️ Trình Cấu Hình Động Trực Tiếp** — Thay đổi các tham số môi trường động thông qua menu `/config` bằng các phím inline Telegram hoặc trực tiếp trên CLI.
39
41
  * **📂 Quản Lý Workspace Linh Hoạt** — Điều hướng và chuyển đổi nhanh chóng giữa các thư mục làm việc khác nhau trên máy chủ cục bộ.
40
42
  * **🔄 Luồng Đầu Ra Được Tối Ưu Hóa** — Cơ chế gom cụm đầu ra thông minh với khoảng giãn cách cấu hình được (`OUTPUT_INTERVAL`) và độ trễ flush kích hoạt bởi tương tác (`ACTION_INTERVAL`), giúp nhật ký terminal hiển thị mượt mà trên Telegram mà không vượt quá giới hạn API.
41
43
  * **🚀 Khởi Động Cùng Hệ Điều Hành** — Dễ dàng cấu hình để chạy như một dịch vụ nền khi hệ thống khởi động (hỗ trợ Windows và Linux).
44
+ * **🔄 Chuyển Đổi Trực Tiếp/Từ Xa Liền Mạch** — Tiếp tục tương tác trực tiếp với phiên PTY chạy nền ngay từ terminal máy tính. Luồng đồng bộ tin nhắn lên Telegram tự động tạm ngưng khi bạn đang thao tác cục bộ để tránh bị giới hạn API, và tự động gửi 1 tin nhắn tóm tắt trạng thái cuối cùng lên Telegram ngay khi bạn ngắt kết nối (bằng phím tắt `Ctrl+B` rồi `D`).
45
+ * **⚠️ Bảo Vệ Lệnh Nguy Hiểm** — Tự động chặn và yêu cầu xác thực (thông qua nút bấm inline Telegram) trước khi thực thi các lệnh khớp với danh sách cấu hình, giúp hạn chế rủi ro phá hoại hệ thống ngoài ý muốn.
42
46
  * **🌐 Hỗ Trợ Đa Ngôn Ngữ** — Bản dịch hoàn chỉnh cho tiếng Anh (`en`) và tiếng Việt (`vi`).
43
47
  * **🛡️ Bảo Mật Nghiêm Ngặt** — Xác thực token và kiểm tra quyền hạn chặt chẽ, chỉ cho phép tài khoản Admin đã cấu hình điều khiển hệ thống.
44
48
 
49
+
45
50
  ---
46
51
 
47
52
  ## ⚙️ Kiến Trúc & Luồng Dữ Liệu
@@ -104,6 +109,7 @@ nonstop
104
109
  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ể:
105
110
  * **Khởi động / Dừng (Start / Stop)** bot chạy ẩn.
106
111
  * **Cấu hình Workspace**: Quản lý các thư mục mà phiên terminal được phép khởi chạy từ đó.
112
+ * **Kết nối vào phiên hoạt động**: Xem và điều khiển trực tiếp các phiên shell chạy ẩn (ví dụ: được khởi chạy từ Telegram) ngay trên terminal máy tính của bạn.
107
113
  * **Tự động khởi động (Autostart)**: Thiết lập ứng dụng tự chạy khi hệ thống khởi động.
108
114
  * **Xem logs**: Theo dõi nhật ký hoạt động của bot thời gian thực.
109
115
 
@@ -119,7 +125,7 @@ Khi bot đang hoạt động, bạn có thể tương tác với nó thông qua
119
125
 
120
126
  #### **⚡ Quản Lý Các Phiên Shell PTY**
121
127
  1. Chọn **⚡ Session** từ menu chính.
122
- 2. Chọn một môi trường shell (ví dụ: **PowerShell**, **Bash**, **Codex**, hoặc **Antigravity**) để bắt đầu.
128
+ 2. Chọn một môi trường shell (ví dụ: **PowerShell**, **Bash**, **Codex**, **Antigravity**, hoặc **Claude**) để bắt đầu.
123
129
  3. Khi phiên hoạt động, hãy **bật Chế Độ Nhập (Input Mode)**.
124
130
  4. Bất kỳ tin nhắn văn bản thông thường nào bạn gửi tới bot (không bắt đầu bằng dấu `/`) sẽ được ghi thẳng vào phiên shell của bạn.
125
131
  5. Sử dụng các nút bấm trên bàn phím inline để gửi nhanh phím chức năng:
@@ -139,6 +145,25 @@ Khi bot đang hoạt động, bạn có thể tương tác với nó thông qua
139
145
  * Nhấn vào bất kỳ trường cấu hình nào (ví dụ: *Token*, *Admin*, *Interval*, v.v.) và gửi giá trị mới thông qua tin nhắn để áp dụng ngay lập tức.
140
146
  * Khi thay đổi `Telegram Bot Token`, bot sẽ tự động tải lại cấu hình và khởi động lại một cách an toàn.
141
147
 
148
+ ### 3. Chuyển Đổi Qua Lại Giữa Telegram và Terminal Cục Bộ
149
+ `nonstop` cho phép bạn chuyển đổi quyền điều khiển liền mạch giữa ứng dụng Telegram và terminal trên máy tính của bạn:
150
+
151
+ 1. **Khởi chạy phiên trên Telegram**: Bắt đầu một phiên terminal từ bot Telegram như bình thường (ví dụ: chọn **⚡ Session** -> **PowerShell**).
152
+ 2. **Tiếp quản trực tiếp trên máy tính**:
153
+ - Mở terminal trên máy tính của bạn và chạy:
154
+ ```bash
155
+ nonstop
156
+ ```
157
+ - Trong giao diện TUI, chọn **Danh sách CLI đã spawn**.
158
+ - Chọn phiên đang chạy mà bạn muốn kết nối.
159
+ - Giờ đây bạn đã kết nối trực tiếp. Mọi thao tác gõ phím và lệnh chạy cục bộ sẽ thực thi trên cùng một tiến trình PTY nền đó.
160
+ - *Lưu ý: Trong khi bạn đang kết nối trực tiếp trên máy tính, luồng đồng bộ tin nhắn lên Telegram sẽ tự động tạm ngưng để tránh bị giới hạn API.*
161
+ 3. **Ngắt kết nối để quay lại Telegram**:
162
+ - Để ngắt kết nối cục bộ mà không dừng tiến trình terminal, nhấn tổ hợp phím **`Ctrl+B` rồi nhấn `D`** (tương tự như detach trong tmux).
163
+ - Ứng dụng sẽ ngắt kết nối trực tiếp, tiến trình shell vẫn tiếp tục chạy ẩn.
164
+ - Ngay sau khi ngắt kết nối, một tin nhắn tóm tắt trạng thái màn hình terminal cuối cùng sẽ được tự động gửi lên Telegram.
165
+ - Bạn có thể tiếp tục tương tác với phiên terminal này qua bot Telegram.
166
+
142
167
  ---
143
168
 
144
169
  ## 🎛️ Cấu Hình Ban Đầu
@@ -154,6 +179,15 @@ APP_LANGUAGE=en
154
179
  STARTUP_MODE=disabled
155
180
  OUTPUT_INTERVAL=20000
156
181
  ACTION_INTERVAL=5000
182
+ DANGEROUS_COMMAND_CONFIRM=rm -rf /,rm -rf,rm -fr,sudo,del /s,rd /s,rmdir /s,format,shutdown,reboot,poweroff,init 0,dd if=,mkfs,fdisk
183
+
184
+ # CLI OVERRIDES (Optional)
185
+ CODEX_CMD=codex
186
+ CODEX_ARGS=[]
187
+ ANTIGRAVITY_CMD=agy
188
+ ANTIGRAVITY_ARGS=[]
189
+ CLAUDE_CMD=claude
190
+ CLAUDE_ARGS=[]
157
191
  ```
158
192
 
159
193
  ---
package/dist/bot.js CHANGED
@@ -43,7 +43,7 @@ const store_js_1 = require("./store.js");
43
43
  const i18n_js_1 = require("./i18n.js");
44
44
  const grammyRequire = require;
45
45
  const { Bot, InlineKeyboard } = grammyRequire('grammy');
46
- const SUPPORTED_PRESETS = ['powershell', 'bash', 'codex', 'antigravity'];
46
+ const SUPPORTED_PRESETS = ['powershell', 'bash', 'codex', 'antigravity', 'claude'];
47
47
  const LAST_CHAT_ID_PATH = path.join(process.cwd(), 'data', 'last-chat-id.txt');
48
48
  function saveLastChatId(chatId) {
49
49
  try {
@@ -68,7 +68,7 @@ function loadLastChatId() {
68
68
  function createBotRuntime(deps) {
69
69
  const token = process.env.TELEGRAM_BOT_TOKEN;
70
70
  if (!token) {
71
- throw new Error('TELEGRAM_BOT_TOKEN bắt buộc.');
71
+ throw new Error('TELEGRAM_BOT_TOKEN is required.');
72
72
  }
73
73
  const bot = new Bot(token);
74
74
  const chatStates = new Map();
@@ -182,7 +182,10 @@ function createBotRuntime(deps) {
182
182
  `• Codex Cmd: ${config.codexCmd}`,
183
183
  `• Codex Args: ${config.codexArgs}`,
184
184
  `• Antigravity Cmd: ${config.antigravityCmd}`,
185
- `• Antigravity Args: ${config.antigravityArgs}`
185
+ `• Antigravity Args: ${config.antigravityArgs}`,
186
+ `• Claude Cmd: ${config.claudeCmd}`,
187
+ `• Claude Args: ${config.claudeArgs}`,
188
+ `• Dangerous Cmds: ${config.dangerousCommandConfirm || notConfigured}`
186
189
  ];
187
190
  const keyboard = createKeyboard()
188
191
  .text('Token', 'config_edit:telegramBotToken')
@@ -205,6 +208,11 @@ function createBotRuntime(deps) {
205
208
  .row()
206
209
  .text('Antigravity Args', 'config_edit:antigravityArgs')
207
210
  .row()
211
+ .text('Claude Cmd', 'config_edit:claudeCmd')
212
+ .text('Claude Args', 'config_edit:claudeArgs')
213
+ .row()
214
+ .text('Dangerous Cmds', 'config_edit:dangerousCommandConfirm')
215
+ .row()
208
216
  .text(t('bot.general.back'), 'main_menu');
209
217
  await renderText(ctx, lines.join('\n'), keyboard);
210
218
  }
@@ -239,6 +247,7 @@ function createBotRuntime(deps) {
239
247
  .row()
240
248
  .text('Codex', `start_session:${workspace.id}:codex`)
241
249
  .text('Antigravity', `start_session:${workspace.id}:antigravity`)
250
+ .text('Claude', `start_session:${workspace.id}:claude`)
242
251
  .row()
243
252
  .text(t('bot.general.back'), 'workspaces_list');
244
253
  }
@@ -429,7 +438,25 @@ function createBotRuntime(deps) {
429
438
  await ctx.reply(t('bot.general.noActiveSession'));
430
439
  return;
431
440
  }
432
- deps.sendInput(session.autoEnter ? `${payload}\r` : payload);
441
+ const finalInput = session.autoEnter ? `${payload}\r` : payload;
442
+ const config = deps.getConfig();
443
+ const dangerousCmdsList = (config.dangerousCommandConfirm || '')
444
+ .split(',')
445
+ .map(c => c.trim().toLowerCase())
446
+ .filter(Boolean);
447
+ const isDangerous = dangerousCmdsList.some(dangerous => payload.toLowerCase().includes(dangerous));
448
+ if (isDangerous) {
449
+ const chatId = ctx.chat?.id;
450
+ if (chatId) {
451
+ getChatState(chatId).pendingDangerousCommand = finalInput;
452
+ const keyboard = createKeyboard()
453
+ .text(t('bot.general.confirmYes'), 'confirm_dangerous_yes')
454
+ .text(t('bot.general.confirmNo'), 'confirm_dangerous_no');
455
+ await ctx.reply(t('bot.general.dangerousConfirm', { command: payload }), { reply_markup: keyboard });
456
+ return;
457
+ }
458
+ }
459
+ deps.sendInput(finalInput);
433
460
  await ctx.reply(t('bot.general.sentCommand'));
434
461
  });
435
462
  bot.on('message:text', async (ctx) => {
@@ -445,12 +472,70 @@ function createBotRuntime(deps) {
445
472
  const session = deps.getActiveSession();
446
473
  if (session?.status === 'running' && session.inputMode) {
447
474
  const payload = session.autoEnter ? `${text}\r` : text;
475
+ const config = deps.getConfig();
476
+ const dangerousCmdsList = (config.dangerousCommandConfirm || '')
477
+ .split(',')
478
+ .map(c => c.trim().toLowerCase())
479
+ .filter(Boolean);
480
+ const isDangerous = dangerousCmdsList.some(dangerous => text.toLowerCase().includes(dangerous));
481
+ if (isDangerous) {
482
+ const chatId = ctx.chat?.id;
483
+ if (chatId) {
484
+ getChatState(chatId).pendingDangerousCommand = payload;
485
+ const keyboard = createKeyboard()
486
+ .text(t('bot.general.confirmYes'), 'confirm_dangerous_yes')
487
+ .text(t('bot.general.confirmNo'), 'confirm_dangerous_no');
488
+ await ctx.reply(t('bot.general.dangerousConfirm', { command: text }), { reply_markup: keyboard });
489
+ return;
490
+ }
491
+ }
448
492
  deps.sendInput(payload);
449
493
  await ctx.reply(t('bot.general.sentCommand'));
450
494
  return;
451
495
  }
452
496
  await ctx.reply(t('bot.general.defaultMessage'));
453
497
  });
498
+ bot.callbackQuery('confirm_dangerous_yes', async (ctx) => {
499
+ await safeAnswerCallback(ctx);
500
+ const chatId = ctx.chat?.id;
501
+ const t = getT();
502
+ if (!chatId)
503
+ return;
504
+ const state = getChatState(chatId);
505
+ const command = state.pendingDangerousCommand;
506
+ state.pendingDangerousCommand = undefined;
507
+ if (!command) {
508
+ await ctx.reply(t('bot.general.defaultMessage'));
509
+ return;
510
+ }
511
+ const session = deps.getActiveSession();
512
+ if (!session || session.status !== 'running') {
513
+ await ctx.reply(t('bot.general.noActiveSession'));
514
+ return;
515
+ }
516
+ deps.sendInput(command);
517
+ try {
518
+ await ctx.editMessageText(t('bot.general.sentCommand'));
519
+ }
520
+ catch {
521
+ await ctx.reply(t('bot.general.sentCommand'));
522
+ }
523
+ });
524
+ bot.callbackQuery('confirm_dangerous_no', async (ctx) => {
525
+ await safeAnswerCallback(ctx);
526
+ const chatId = ctx.chat?.id;
527
+ const t = getT();
528
+ if (!chatId)
529
+ return;
530
+ const state = getChatState(chatId);
531
+ state.pendingDangerousCommand = undefined;
532
+ try {
533
+ await ctx.editMessageText(t('bot.general.confirmCancelled'));
534
+ }
535
+ catch {
536
+ await ctx.reply(t('bot.general.confirmCancelled'));
537
+ }
538
+ });
454
539
  bot.callbackQuery('main_menu', async (ctx) => {
455
540
  await safeAnswerCallback(ctx);
456
541
  await showMainMenu(ctx);
@@ -548,7 +633,7 @@ function createBotRuntime(deps) {
548
633
  await showSessionDetails(ctx);
549
634
  }
550
635
  catch (error) {
551
- logger_js_1.logger.error('Lỗi khi khởi chạy session', {
636
+ logger_js_1.logger.error('Error starting session', {
552
637
  workspaceId,
553
638
  preset,
554
639
  error: error instanceof Error ? error.message : String(error)
@@ -601,7 +686,7 @@ function createBotRuntime(deps) {
601
686
  await showSessionDetails(ctx, sessionId);
602
687
  });
603
688
  bot.catch((error) => {
604
- logger_js_1.logger.error('Lỗi bot handler', {
689
+ logger_js_1.logger.error('Bot handler error', {
605
690
  error: error.error instanceof Error ? error.error.message : String(error.error)
606
691
  });
607
692
  });
@@ -617,7 +702,15 @@ function createBotRuntime(deps) {
617
702
  bot.stop();
618
703
  },
619
704
  async pushSessionOutput(chatId, text, options) {
620
- await bot.api.sendMessage(chatId, text, options);
705
+ try {
706
+ await bot.api.sendMessage(chatId, text, options);
707
+ }
708
+ catch (error) {
709
+ logger_js_1.logger.error('Failed to send Telegram message', {
710
+ chatId,
711
+ error: error instanceof Error ? error.message : String(error)
712
+ });
713
+ }
621
714
  },
622
715
  // Confirmation prompt đã bị xóa — không dùng nữa
623
716
  async showConfirmationPrompt(_session, _text) {
package/dist/config.js CHANGED
@@ -57,7 +57,10 @@ const DEFAULTS = {
57
57
  codexCmd: 'codex',
58
58
  codexArgs: '[]',
59
59
  antigravityCmd: 'agy',
60
- antigravityArgs: '[]'
60
+ antigravityArgs: '[]',
61
+ claudeCmd: 'claude',
62
+ claudeArgs: '[]',
63
+ dangerousCommandConfirm: 'rm -rf /,rm -rf,rm -fr,sudo,del /s,rd /s,rmdir /s,format,shutdown,reboot,poweroff,init 0,dd if=,mkfs,fdisk'
61
64
  };
62
65
  exports.ENV_FILE_PATH = path.join(process.cwd(), '.env');
63
66
  exports.ENV_EXAMPLE_FILE_PATH = path.join(process.cwd(), '.env.example');
@@ -76,7 +79,10 @@ function parseConfigFromEnv(env) {
76
79
  codexArgs: env.CODEX_ARGS?.trim() || DEFAULTS.codexArgs,
77
80
  antigravityCmd: env.ANTIGRAVITY_CMD?.trim() || DEFAULTS.antigravityCmd,
78
81
  antigravityArgs: env.ANTIGRAVITY_ARGS?.trim() || DEFAULTS.antigravityArgs,
79
- actionInterval: parseInteger(env.ACTION_INTERVAL, DEFAULTS.actionInterval)
82
+ claudeCmd: env.CLAUDE_CMD?.trim() || DEFAULTS.claudeCmd,
83
+ claudeArgs: env.CLAUDE_ARGS?.trim() || DEFAULTS.claudeArgs,
84
+ actionInterval: parseInteger(env.ACTION_INTERVAL, DEFAULTS.actionInterval),
85
+ dangerousCommandConfirm: env.DANGEROUS_COMMAND_CONFIRM !== undefined ? env.DANGEROUS_COMMAND_CONFIRM.trim() : DEFAULTS.dangerousCommandConfirm
80
86
  };
81
87
  }
82
88
  function getMissingConfigFields(config) {
@@ -101,12 +107,15 @@ function serializeConfigToEnv(config) {
101
107
  `ACTION_INTERVAL=${config.actionInterval}`,
102
108
  `MAX_OUTPUT_LINES=${config.maxOutputLines}`,
103
109
  `MAX_RENDER_LINES=${config.maxRenderLines}`,
110
+ `DANGEROUS_COMMAND_CONFIRM=${config.dangerousCommandConfirm}`,
104
111
  '',
105
112
  '# CLI OVERRIDES (Optional)',
106
113
  `CODEX_CMD=${config.codexCmd}`,
107
114
  `CODEX_ARGS=${config.codexArgs}`,
108
115
  `ANTIGRAVITY_CMD=${config.antigravityCmd}`,
109
116
  `ANTIGRAVITY_ARGS=${config.antigravityArgs}`,
117
+ `CLAUDE_CMD=${config.claudeCmd}`,
118
+ `CLAUDE_ARGS=${config.claudeArgs}`,
110
119
  ''
111
120
  ].join('\n');
112
121
  }
@@ -155,6 +164,9 @@ function applyConfigToProcessEnv(config) {
155
164
  process.env.CODEX_ARGS = config.codexArgs;
156
165
  process.env.ANTIGRAVITY_CMD = config.antigravityCmd;
157
166
  process.env.ANTIGRAVITY_ARGS = config.antigravityArgs;
167
+ process.env.CLAUDE_CMD = config.claudeCmd;
168
+ process.env.CLAUDE_ARGS = config.claudeArgs;
169
+ process.env.DANGEROUS_COMMAND_CONFIRM = config.dangerousCommandConfirm;
158
170
  }
159
171
  function normalizeUsername(value) {
160
172
  const trimmed = value.trim();
package/dist/i18n.js CHANGED
@@ -31,8 +31,8 @@ const MESSAGES = {
31
31
  'bot.menu.session': '⚡ Session',
32
32
  'bot.menu.config': '⚙️ Settings',
33
33
  'bot.menu.help': 'ℹ️ Help',
34
- 'bot.menu.activeSessionNone': '⚡ Session: none',
35
- 'bot.menu.activeSessionRunning': '⚡ Session: {preset} | {cwd}',
34
+ 'bot.menu.activeSessionNone': '⚡ Active Session: None',
35
+ 'bot.menu.activeSessionRunning': '⚡ Active Session: {preset} | {cwd}',
36
36
  'bot.help.title': '📖 Available Commands',
37
37
  'bot.help.start': '/start — Open main menu',
38
38
  'bot.help.status': '/status — Runtime status',
@@ -45,23 +45,23 @@ const MESSAGES = {
45
45
  'bot.status.user': 'User',
46
46
  'bot.status.unlimited': 'unlimited',
47
47
  'bot.status.workspaces': 'Workspaces',
48
- 'bot.status.session': 'Session',
48
+ 'bot.status.session': 'Active Session',
49
49
  'bot.status.running': 'running',
50
50
  'bot.status.none': 'none',
51
51
  'bot.status.preset': 'Preset',
52
52
  'bot.status.directory': 'Directory',
53
- 'bot.config.title': '⚙️ nonstop configuration',
53
+ 'bot.config.title': '⚙️ nonstop Configuration',
54
54
  'bot.config.notConfigured': 'Not configured',
55
55
  'bot.config.languageLabel': 'Language',
56
56
  'bot.config.startupLabel': 'Startup Mode',
57
- 'bot.config.updated': '✓ Config updated for "{field}".',
57
+ 'bot.config.updated': '✓ Configuration updated for "{field}".',
58
58
  'bot.config.enterValue': 'Enter new value for field "{field}":',
59
59
  'bot.config.invalidValue': '❌ Invalid value. Please enter a valid integer for field "{field}".',
60
60
  'bot.workspaces.title': '📁 Workspace List',
61
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',
62
+ 'bot.workspaces.add': '➕ Add Workspace',
63
+ 'bot.workspaces.editName': '✏️ Edit Name',
64
+ 'bot.workspaces.editPath': '🛠️ Edit Path',
65
65
  'bot.workspaces.delete': '🗑️ Delete',
66
66
  'bot.workspaces.notFound': 'Workspace not found.',
67
67
  'bot.workspaces.detailsTitle': '📁 Workspace Details',
@@ -73,8 +73,8 @@ const MESSAGES = {
73
73
  'bot.workspaces.notExists': 'Workspace no longer exists.',
74
74
  'bot.workspaces.updatedName': '✓ Updated workspace name.',
75
75
  'bot.workspaces.updatedPath': '✓ Updated workspace path.',
76
- 'bot.sessions.title': '⚡ Session',
77
- 'bot.sessions.empty': 'No running session.',
76
+ 'bot.sessions.title': '⚡ Active Session',
77
+ 'bot.sessions.empty': 'No active session.',
78
78
  'bot.sessions.control': '🎮 Control',
79
79
  'bot.sessionDetails.title': '🎮 Session Control',
80
80
  'bot.sessionDetails.notRunning': 'Session is not running.',
@@ -82,8 +82,8 @@ const MESSAGES = {
82
82
  'bot.sessionDetails.preset': 'Preset',
83
83
  'bot.sessionDetails.status': 'Status',
84
84
  'bot.sessionDetails.directory': 'Directory',
85
- 'bot.sessionDetails.inputMode': 'Input mode',
86
- 'bot.sessionDetails.autoEnter': 'Auto enter',
85
+ 'bot.sessionDetails.inputMode': 'Input Mode',
86
+ 'bot.sessionDetails.autoEnter': 'Auto Enter',
87
87
  'bot.sessionDetails.on': 'ON',
88
88
  'bot.sessionDetails.off': 'OFF',
89
89
  'bot.sessionControls.presetNotSupported': 'Preset not supported: {preset}',
@@ -96,7 +96,11 @@ const MESSAGES = {
96
96
  'bot.general.sendUsage': 'Usage: /send <command to send>',
97
97
  'bot.general.noActiveSession': 'No active session running.',
98
98
  'bot.general.sentCommand': '✓ Command sent',
99
- 'bot.general.defaultMessage': 'Use /start to open the menu.'
99
+ 'bot.general.dangerousConfirm': '⚠️ This command may be dangerous and cannot be undone: "{command}". Are you sure you want to execute it?',
100
+ 'bot.general.confirmYes': 'Yes, execute',
101
+ 'bot.general.confirmNo': 'Cancel',
102
+ 'bot.general.confirmCancelled': 'Command execution cancelled.',
103
+ 'bot.general.defaultMessage': 'Use /start to open the main menu.'
100
104
  },
101
105
  vi: {
102
106
  'wizard.title': 'Thiết lập nonstop',
@@ -113,7 +117,7 @@ const MESSAGES = {
113
117
  'dashboard.choice': 'Chọn một tùy chọn',
114
118
  'menu.toggleRuntime': 'Bật/Tắt runtime nền',
115
119
  'menu.settings': 'Sửa cấu hình',
116
- 'menu.workspaces': 'Quản lý workspace',
120
+ 'menu.workspaces': 'Quản lý không gian làm việc',
117
121
  'menu.startup': 'Cấu hình khởi động',
118
122
  'menu.language': 'Đổi ngôn ngữ',
119
123
  'menu.logs': 'Xem nhật ký gần đây',
@@ -123,25 +127,25 @@ const MESSAGES = {
123
127
  'startup.background': 'Chạy nền',
124
128
  'startup.openUi': 'Mở giao diện',
125
129
  // Bot Vietnamese
126
- 'bot.menu.workspaces': '📁 Workspaces',
127
- 'bot.menu.session': '⚡ Session',
130
+ 'bot.menu.workspaces': '📁 Không gian làm việc',
131
+ 'bot.menu.session': '⚡ Phiên làm việc',
128
132
  'bot.menu.config': '⚙️ Cấu hình',
129
133
  'bot.menu.help': 'ℹ️ Trợ giúp',
130
- 'bot.menu.activeSessionNone': '⚡ Session: không có',
131
- 'bot.menu.activeSessionRunning': '⚡ Session: {preset} | {cwd}',
134
+ 'bot.menu.activeSessionNone': '⚡ Phiên làm việc: không có',
135
+ 'bot.menu.activeSessionRunning': '⚡ Phiên làm việc: {preset} | {cwd}',
132
136
  'bot.help.title': '📖 Lệnh có sẵn',
133
137
  'bot.help.start': '/start — Mở menu chính',
134
138
  'bot.help.status': '/status — Trạng thái runtime',
135
139
  'bot.help.help': '/help — Trợ giúp',
136
140
  '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.',
141
+ 'bot.help.send': '/send <lệnh> — Gửi lệnh thô tới phiên làm việc',
142
+ 'bot.help.inputModeNotice': 'Khi chế độ nhập BẬT, tin nhắn thường sẽ được gửi thẳng vào phiên làm việc.',
139
143
  'bot.help.back': '⬅️ Quay lại',
140
144
  'bot.status.title': '📊 Trạng thái Runtime',
141
145
  'bot.status.user': 'Người dùng',
142
146
  'bot.status.unlimited': 'không giới hạn',
143
- 'bot.status.workspaces': 'Workspaces',
144
- 'bot.status.session': 'Session',
147
+ 'bot.status.workspaces': 'Không gian làm việc',
148
+ 'bot.status.session': 'Phiên làm việc',
145
149
  'bot.status.running': 'đang chạy',
146
150
  'bot.status.none': 'không có',
147
151
  'bot.status.preset': 'Preset',
@@ -151,47 +155,51 @@ const MESSAGES = {
151
155
  'bot.config.languageLabel': 'Ngôn ngữ',
152
156
  'bot.config.startupLabel': 'Chế độ khởi động',
153
157
  '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',
158
+ 'bot.config.enterValue': 'Nhập giá trị mới cho trường "{field}":',
159
+ '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 trường "{field}".',
160
+ 'bot.workspaces.title': '📁 Danh sách không gian làm việc',
161
+ 'bot.workspaces.empty': 'Chưa có không gian làm việc nào.',
162
+ 'bot.workspaces.add': '➕ Thêm không gian làm việc',
159
163
  'bot.workspaces.editName': '✏️ Sửa tên',
160
164
  'bot.workspaces.editPath': '🛠️ Sửa đường dẫn',
161
165
  'bot.workspaces.delete': '🗑️ Xóa',
162
- 'bot.workspaces.notFound': 'Workspace không tìm thấy.',
163
- 'bot.workspaces.detailsTitle': '📁 Chi tiết Workspace',
166
+ 'bot.workspaces.notFound': 'Không tìm thấy không gian làm việc.',
167
+ 'bot.workspaces.detailsTitle': '📁 Chi tiết không gian làm việc',
164
168
  'bot.workspaces.detailsName': 'Tên',
165
169
  '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.',
170
+ 'bot.workspaces.addNamePrompt': 'Nhập tên không gian làm việc mới:',
171
+ 'bot.workspaces.addPathPrompt': 'Nhập đường dẫn không gian làm việc:',
172
+ 'bot.workspaces.added': '✓ Đã thêm không gian làm việc "{name}".',
173
+ 'bot.workspaces.notExists': 'Không gian làm việc không còn tồn tại.',
174
+ 'bot.workspaces.updatedName': '✓ Đã cập nhật tên không gian làm việc.',
175
+ 'bot.workspaces.updatedPath': '✓ Đã cập nhật đường dẫn không gian làm việc.',
176
+ 'bot.sessions.title': '⚡ Phiên làm việc',
177
+ 'bot.sessions.empty': 'Không có phiên làm việc đang chạy.',
174
178
  '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.',
179
+ 'bot.sessionDetails.title': '🎮 Điều khiển phiên',
180
+ 'bot.sessionDetails.notRunning': 'Phiên làm việc không đang chạy.',
177
181
  'bot.sessionDetails.id': 'ID',
178
182
  'bot.sessionDetails.preset': 'Preset',
179
183
  'bot.sessionDetails.status': 'Trạng thái',
180
184
  'bot.sessionDetails.directory': 'Thư mục',
181
- 'bot.sessionDetails.inputMode': 'Input mode',
182
- 'bot.sessionDetails.autoEnter': 'Auto enter',
185
+ 'bot.sessionDetails.inputMode': 'Chế độ nhập',
186
+ 'bot.sessionDetails.autoEnter': 'Tự động Enter',
183
187
  'bot.sessionDetails.on': 'BẬT',
184
188
  'bot.sessionDetails.off': 'TẮT',
185
189
  '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.',
190
+ 'bot.sessionControls.runningSessionExists': 'Đã có phiên làm việc đang chạy. Dừng phiên hiện tại trước.',
191
+ 'bot.sessionControls.startError': 'Lỗi khi khởi chạy phiên làm việc: {error}',
192
+ 'bot.sessionControls.notRunning': 'Phiên làm việc không đang chạy.',
189
193
  'bot.sessionControls.unsupportedAction': 'Hành động không hỗ trợ: {action}',
190
194
  'bot.general.back': '⬅️ Quay lại',
191
195
  'bot.general.authError': 'Bot này chỉ dành cho tài khoản Telegram đã cấu hình.',
192
196
  '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.',
197
+ 'bot.general.noActiveSession': 'Không có phiên làm việc đang chạy.',
194
198
  'bot.general.sentCommand': '✓ Đã gửi lệnh',
199
+ 'bot.general.dangerousConfirm': '⚠️ Lệnh này có thể nguy hiểm và không thể hoàn tác: "{command}". Bạn có chắc chắn muốn thực hiện không?',
200
+ 'bot.general.confirmYes': 'Đồng ý, chạy lệnh',
201
+ 'bot.general.confirmNo': 'Hủy',
202
+ 'bot.general.confirmCancelled': 'Đã hủy thực hiện lệnh.',
195
203
  'bot.general.defaultMessage': 'Dùng /start để mở menu.'
196
204
  }
197
205
  };