@quangnv13/nonstop 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/ui.js +74 -97
  2. package/package.json +1 -1
package/dist/ui.js CHANGED
@@ -67,12 +67,22 @@ function infoRow(label, value, valueColor = (s) => s) {
67
67
  function separator() {
68
68
  return chalk_1.default.gray(' ' + '─'.repeat(44));
69
69
  }
70
- async function pause(rl) {
71
- await rl.question(`\n${chalk_1.default.gray('Nhấn Enter để tiếp tục...')}`);
70
+ async function askQuestion(query) {
71
+ const rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
72
+ try {
73
+ return await rl.question(query);
74
+ }
75
+ finally {
76
+ rl.close();
77
+ process.stdin.resume();
78
+ }
79
+ }
80
+ async function pause() {
81
+ await askQuestion(`\n${chalk_1.default.gray('Nhấn Enter để tiếp tục...')}`);
72
82
  }
73
- async function askWithDefault(rl, label, currentValue) {
83
+ async function askWithDefault(label, currentValue) {
74
84
  const prompt = `${chalk_1.default.bold(label)}${currentValue ? chalk_1.default.gray(` [${currentValue}]`) : ''}: `;
75
- const answer = await rl.question(prompt);
85
+ const answer = await askQuestion(prompt);
76
86
  return answer.trim() || currentValue;
77
87
  }
78
88
  async function runSelectionMenu(headerRenderer, options, initialIndex = 0) {
@@ -172,15 +182,9 @@ async function launchControlCenter() {
172
182
  let config = (0, config_js_1.loadConfigFromDisk)();
173
183
  const isTTY = process.stdin.isTTY;
174
184
  const wasRaw = process.stdin.isRaw;
175
- let rl;
176
185
  try {
177
186
  if ((0, config_js_1.getMissingConfigFields)(config).length > 0) {
178
- const result = await runSetupWizard(config);
179
- config = result.config;
180
- rl = result.rl;
181
- }
182
- else {
183
- rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
187
+ config = await runSetupWizard(config);
184
188
  }
185
189
  let lastSelection = 0;
186
190
  while (true) {
@@ -200,47 +204,39 @@ async function launchControlCenter() {
200
204
  { label: t('menu.logs'), value: 'logs' },
201
205
  { label: t('menu.exit'), value: 'exit' }
202
206
  ];
203
- rl.pause();
204
207
  const choice = await runSelectionMenu(() => renderDashboardHeader(config, (0, runtime_manager_js_1.getRuntimeStatus)().snapshot), options, lastSelection);
205
- rl.resume();
206
208
  lastSelection = options.findIndex(opt => opt.value === choice);
207
209
  if (lastSelection < 0)
208
210
  lastSelection = 0;
209
211
  if (choice === 'exit')
210
212
  break;
211
213
  if (choice === 'toggle') {
212
- await handleToggleRuntime(config, rl);
214
+ await handleToggleRuntime(config);
213
215
  continue;
214
216
  }
215
217
  if (choice === 'settings') {
216
- config = await editConfig(config, rl);
218
+ config = await editConfig(config);
217
219
  continue;
218
220
  }
219
221
  if (choice === 'workspaces') {
220
- await manageWorkspaces(rl, config.language);
222
+ await manageWorkspaces(config.language);
221
223
  continue;
222
224
  }
223
225
  if (choice === 'startup') {
224
- config = await configureStartup(config, rl);
226
+ config = await configureStartup(config);
225
227
  continue;
226
228
  }
227
229
  if (choice === 'language') {
228
- config = await switchLanguage(config, rl);
230
+ config = await switchLanguage(config);
229
231
  continue;
230
232
  }
231
233
  if (choice === 'logs') {
232
- await showRecentLogs(rl);
234
+ await showRecentLogs();
233
235
  continue;
234
236
  }
235
237
  }
236
238
  }
237
239
  finally {
238
- if (rl) {
239
- try {
240
- rl.close();
241
- }
242
- catch { /* ignore */ }
243
- }
244
240
  process.stdout.write('\u001b[?25h');
245
241
  if (isTTY) {
246
242
  try {
@@ -261,49 +257,37 @@ async function runSetupWizard(currentConfig) {
261
257
  { label: 'English (en)', value: 'en' }
262
258
  ], currentConfig.language === 'en' ? 1 : 0);
263
259
  const t = (0, i18n_js_1.createTranslator)(language);
264
- const rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
265
- try {
266
- clearScreen();
267
- console.log(titleBox(t('wizard.title')));
268
- console.log('');
269
- const telegramBotToken = await askWithDefault(rl, t('wizard.token'), currentConfig.telegramBotToken);
270
- const adminUsername = await askWithDefault(rl, t('wizard.admin'), currentConfig.adminUsername);
271
- const clientName = await askWithDefault(rl, t('wizard.clientName'), currentConfig.clientName);
272
- rl.pause();
273
- const startupMode = await runSelectionMenu(() => {
274
- console.log(titleBox(t('wizard.title')));
275
- console.log(chalk_1.default.gray(` ${t('wizard.startupMode')}:`));
276
- }, [
277
- { label: `Tắt (disabled)`, value: 'disabled' },
278
- { label: `Chạy nền (background)`, value: 'background' },
279
- { label: `Mở giao diện (open-ui)`, value: 'open-ui' }
280
- ], 0);
281
- rl.resume();
282
- const nextConfig = {
283
- ...currentConfig,
284
- language,
285
- telegramBotToken,
286
- adminUsername,
287
- telegramUsername: adminUsername,
288
- clientName,
289
- startupMode
290
- };
291
- (0, config_js_1.saveConfigToDisk)(nextConfig);
292
- clearScreen();
260
+ clearScreen();
261
+ console.log(titleBox(t('wizard.title')));
262
+ console.log('');
263
+ const telegramBotToken = await askWithDefault(t('wizard.token'), currentConfig.telegramBotToken);
264
+ const adminUsername = await askWithDefault(t('wizard.admin'), currentConfig.adminUsername);
265
+ const clientName = await askWithDefault(t('wizard.clientName'), currentConfig.clientName);
266
+ const startupMode = await runSelectionMenu(() => {
293
267
  console.log(titleBox(t('wizard.title')));
294
- console.log(`\n${chalk_1.default.green(t('wizard.complete'))}`);
295
- await pause(rl);
296
- return { config: nextConfig, rl };
297
- }
298
- catch (error) {
299
- try {
300
- rl.close();
301
- }
302
- catch { /* ignore */ }
303
- throw error;
304
- }
268
+ console.log(chalk_1.default.gray(` ${t('wizard.startupMode')}:`));
269
+ }, [
270
+ { label: `Tắt (disabled)`, value: 'disabled' },
271
+ { label: `Chạy nền (background)`, value: 'background' },
272
+ { label: `Mở giao diện (open-ui)`, value: 'open-ui' }
273
+ ], 0);
274
+ const nextConfig = {
275
+ ...currentConfig,
276
+ language,
277
+ telegramBotToken,
278
+ adminUsername,
279
+ telegramUsername: adminUsername,
280
+ clientName,
281
+ startupMode
282
+ };
283
+ (0, config_js_1.saveConfigToDisk)(nextConfig);
284
+ clearScreen();
285
+ console.log(titleBox(t('wizard.title')));
286
+ console.log(`\n${chalk_1.default.green(t('wizard.complete'))}`);
287
+ await pause();
288
+ return nextConfig;
305
289
  }
306
- async function handleToggleRuntime(config, rl) {
290
+ async function handleToggleRuntime(config) {
307
291
  const status = (0, runtime_manager_js_1.getRuntimeStatus)();
308
292
  const targetState = !status.running;
309
293
  clearScreen();
@@ -326,31 +310,30 @@ async function handleToggleRuntime(config, rl) {
326
310
  }
327
311
  catch (error) {
328
312
  console.log(`\n${chalk_1.default.red(error instanceof Error ? error.message : String(error))}`);
329
- await pause(rl);
313
+ await pause();
330
314
  return;
331
315
  }
332
- // Không pause — quay lại menu ngay để trạng thái cập nhật tức thì
333
316
  }
334
- async function editConfig(config, rl) {
317
+ async function editConfig(config) {
335
318
  clearScreen();
336
319
  console.log(titleBox('Sửa cấu hình'));
337
320
  console.log('');
338
321
  const nextConfig = {
339
322
  ...config,
340
- telegramBotToken: await askWithDefault(rl, 'TELEGRAM_BOT_TOKEN', config.telegramBotToken),
341
- adminUsername: await askWithDefault(rl, 'ADMIN_USERNAME', config.adminUsername),
342
- clientName: await askWithDefault(rl, 'CLIENT_NAME', config.clientName),
343
- telegramUsername: await askWithDefault(rl, 'TELEGRAM_USERNAME', config.telegramUsername),
344
- codexCmd: await askWithDefault(rl, 'CODEX_CMD', config.codexCmd),
345
- antigravityCmd: await askWithDefault(rl, 'ANTIGRAVITY_CMD', config.antigravityCmd)
323
+ telegramBotToken: await askWithDefault('TELEGRAM_BOT_TOKEN', config.telegramBotToken),
324
+ adminUsername: await askWithDefault('ADMIN_USERNAME', config.adminUsername),
325
+ clientName: await askWithDefault('CLIENT_NAME', config.clientName),
326
+ telegramUsername: await askWithDefault('TELEGRAM_USERNAME', config.telegramUsername),
327
+ codexCmd: await askWithDefault('CODEX_CMD', config.codexCmd),
328
+ antigravityCmd: await askWithDefault('ANTIGRAVITY_CMD', config.antigravityCmd)
346
329
  };
347
330
  (0, config_js_1.saveConfigToDisk)(nextConfig);
348
331
  console.log(`\n${chalk_1.default.green('✓ Đã lưu cấu hình.')}`);
349
332
  console.log(chalk_1.default.gray('Khởi động lại runtime nền nếu đang chạy để áp dụng thay đổi.'));
350
- await pause(rl);
333
+ await pause();
351
334
  return nextConfig;
352
335
  }
353
- async function manageWorkspaces(rl, language) {
336
+ async function manageWorkspaces(language) {
354
337
  const isVi = language === 'vi';
355
338
  while (true) {
356
339
  const workspaces = (0, store_js_1.loadWorkspaces)();
@@ -362,23 +345,21 @@ async function manageWorkspaces(rl, language) {
362
345
  })),
363
346
  { label: isVi ? '← Quay lại menu chính' : '← Back', value: { type: 'back' } }
364
347
  ];
365
- rl.pause();
366
348
  const selection = await runSelectionMenu(() => {
367
349
  console.log(titleBox(isVi ? 'Quản lý Workspace' : 'Manage Workspaces'));
368
350
  console.log(chalk_1.default.gray(` ${isVi ? 'Chọn workspace hoặc thêm mới:' : 'Select workspace or add new:'}`));
369
351
  }, options);
370
- rl.resume();
371
352
  if (selection.type === 'back')
372
353
  return;
373
354
  if (selection.type === 'add') {
374
355
  clearScreen();
375
356
  console.log(titleBox(isVi ? 'Thêm workspace mới' : 'Add workspace'));
376
357
  console.log('');
377
- const name = (await rl.question(chalk_1.default.bold(isVi ? 'Tên workspace: ' : 'Workspace name: '))).trim();
378
- const rawPath = (await rl.question(chalk_1.default.bold(isVi ? 'Đường dẫn: ' : 'Path: '))).trim();
358
+ const name = (await askQuestion(chalk_1.default.bold(isVi ? 'Tên workspace: ' : 'Workspace name: '))).trim();
359
+ const rawPath = (await askQuestion(chalk_1.default.bold(isVi ? 'Đường dẫn: ' : 'Path: '))).trim();
379
360
  if (!rawPath) {
380
361
  console.log(chalk_1.default.red(isVi ? ' Đường dẫn không được để trống.' : ' Path cannot be empty.'));
381
- await pause(rl);
362
+ await pause();
382
363
  continue;
383
364
  }
384
365
  const resolvedPath = path.resolve(rawPath);
@@ -388,7 +369,7 @@ async function manageWorkspaces(rl, language) {
388
369
  workspaces.push({ id: (0, store_js_1.createWorkspaceId)(), name: name || 'Workspace', path: resolvedPath });
389
370
  (0, store_js_1.saveWorkspaces)(workspaces);
390
371
  console.log(chalk_1.default.green(`\n ✓ ${isVi ? 'Đã thêm workspace.' : 'Workspace added.'}`));
391
- await pause(rl);
372
+ await pause();
392
373
  continue;
393
374
  }
394
375
  if (selection.type === 'workspace' && typeof selection.index === 'number') {
@@ -410,15 +391,15 @@ async function manageWorkspaces(rl, language) {
410
391
  (0, store_js_1.saveWorkspaces)(workspaces);
411
392
  clearScreen();
412
393
  console.log(chalk_1.default.green(`\n ✓ ${isVi ? 'Đã xóa workspace.' : 'Workspace deleted.'}`));
413
- await pause(rl);
394
+ await pause();
414
395
  continue;
415
396
  }
416
397
  if (action === 'edit') {
417
398
  clearScreen();
418
399
  console.log(titleBox(isVi ? 'Sửa workspace' : 'Edit workspace'));
419
400
  console.log('');
420
- const newName = await askWithDefault(rl, isVi ? 'Tên mới' : 'New name', ws.name);
421
- const newPath = await askWithDefault(rl, isVi ? 'Đường dẫn mới' : 'New path', ws.path);
401
+ const newName = await askWithDefault(isVi ? 'Tên mới' : 'New name', ws.name);
402
+ const newPath = await askWithDefault(isVi ? 'Đường dẫn mới' : 'New path', ws.path);
422
403
  const resolvedPath = path.resolve(newPath.trim());
423
404
  if (!fs.existsSync(resolvedPath)) {
424
405
  console.log(chalk_1.default.yellow(` ⚠ ${isVi ? 'Đường dẫn không tồn tại.' : 'Path does not exist.'}`));
@@ -426,15 +407,14 @@ async function manageWorkspaces(rl, language) {
426
407
  workspaces[idx] = { ...ws, name: newName.trim() || ws.name, path: resolvedPath };
427
408
  (0, store_js_1.saveWorkspaces)(workspaces);
428
409
  console.log(chalk_1.default.green(`\n ✓ ${isVi ? 'Đã cập nhật workspace.' : 'Workspace updated.'}`));
429
- await pause(rl);
410
+ await pause();
430
411
  continue;
431
412
  }
432
413
  }
433
414
  }
434
415
  }
435
- async function configureStartup(config, rl) {
416
+ async function configureStartup(config) {
436
417
  const isVi = config.language === 'vi';
437
- rl.pause();
438
418
  const nextMode = await runSelectionMenu(() => {
439
419
  console.log(titleBox(isVi ? 'Cấu hình khởi động' : 'Configure startup'));
440
420
  console.log(chalk_1.default.gray(` ${isVi ? 'Chế độ hiện tại:' : 'Current mode:'} ${config.startupMode}`));
@@ -443,7 +423,6 @@ async function configureStartup(config, rl) {
443
423
  { label: isVi ? 'Chạy nền (background)' : 'Background', value: 'background' },
444
424
  { label: isVi ? 'Mở giao diện (open-ui)' : 'Open UI', value: 'open-ui' }
445
425
  ], ['disabled', 'background', 'open-ui'].indexOf(config.startupMode));
446
- rl.resume();
447
426
  const entryScriptPath = path.join(process.cwd(), 'dist', 'index.js');
448
427
  const result = (0, startup_js_1.applyStartupMode)(nextMode, entryScriptPath, process.cwd());
449
428
  const nextConfig = { ...config, startupMode: nextMode };
@@ -451,11 +430,10 @@ async function configureStartup(config, rl) {
451
430
  clearScreen();
452
431
  console.log(titleBox(isVi ? 'Cấu hình khởi động' : 'Configure startup'));
453
432
  console.log(`\n${chalk_1.default.green(result)}`);
454
- await pause(rl);
433
+ await pause();
455
434
  return nextConfig;
456
435
  }
457
- async function switchLanguage(config, rl) {
458
- rl.pause();
436
+ async function switchLanguage(config) {
459
437
  const language = await runSelectionMenu(() => {
460
438
  console.log(titleBox('Đổi ngôn ngữ / Switch language'));
461
439
  console.log(chalk_1.default.gray(` Hiện tại: ${config.language}`));
@@ -463,21 +441,20 @@ async function switchLanguage(config, rl) {
463
441
  { label: 'Tiếng Việt (vi)', value: 'vi' },
464
442
  { label: 'English (en)', value: 'en' }
465
443
  ], config.language === 'en' ? 1 : 0);
466
- rl.resume();
467
444
  const nextConfig = { ...config, language };
468
445
  (0, config_js_1.saveConfigToDisk)(nextConfig);
469
446
  return nextConfig;
470
447
  }
471
- async function showRecentLogs(rl) {
448
+ async function showRecentLogs() {
472
449
  clearScreen();
473
450
  console.log(titleBox('Nhật ký gần đây'));
474
451
  const logPath = path.join(process.cwd(), 'data', 'nonstop.log');
475
452
  if (!fs.existsSync(logPath)) {
476
453
  console.log(chalk_1.default.gray('\n Chưa có nhật ký.'));
477
- await pause(rl);
454
+ await pause();
478
455
  return;
479
456
  }
480
457
  const lines = fs.readFileSync(logPath, 'utf8').split(/\r?\n/).filter(Boolean).slice(-25);
481
458
  console.log('\n' + lines.map(l => chalk_1.default.gray(' ') + l).join('\n'));
482
- await pause(rl);
459
+ await pause();
483
460
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quangnv13/nonstop",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "preferGlobal": true,
5
5
  "publishConfig": {
6
6
  "access": "public"