yuangs 1.3.38 → 1.3.39

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/cli.js CHANGED
@@ -432,14 +432,51 @@ switch (command) {
432
432
  if (history.length === 0) {
433
433
  console.log(chalk.gray('暂无命令历史\n'));
434
434
  } else {
435
- console.log(chalk.bold.cyan('\n📋 命令历史\n'));
435
+ console.log(chalk.bold.cyan('\n📋 命令历史 (输入序号可重新执行)\n'));
436
436
  console.log(chalk.gray('─────────────────────────────────────────────────'));
437
437
  history.forEach((item, index) => {
438
438
  console.log(chalk.white(`${index + 1}. ${item.command}`));
439
439
  console.log(chalk.gray(` 问题: ${item.question}`));
440
440
  console.log(chalk.gray(` 时间: ${item.time}\n`));
441
441
  });
442
- console.log(chalk.gray('─────────────────────────────────────────────────\n'));
442
+ console.log(chalk.gray('─────────────────────────────────────────────────'));
443
+
444
+ const readline = require('readline');
445
+ const rlHistory = readline.createInterface({
446
+ input: process.stdin,
447
+ output: process.stdout
448
+ });
449
+
450
+ rlHistory.question(chalk.green('👇 输入序号 (1-' + history.length + ') 或 q 退出: '), (answer) => {
451
+ const index = parseInt(answer) - 1;
452
+ if (!isNaN(index) && index >= 0 && index < history.length) {
453
+ const targetCommand = history[index].command;
454
+
455
+ // 核心逻辑:把命令“写”进输入流,假装是用户刚打进去的
456
+ console.log(chalk.cyan(`\n✨ 已加载命令,按回车执行:`));
457
+ rlHistory.write(targetCommand);
458
+
459
+ rlHistory.on('line', (input) => {
460
+ const finalCommand = input.trim();
461
+ rlHistory.close();
462
+ if (finalCommand) {
463
+ const { spawn } = require('child_process');
464
+ console.log(chalk.gray('正在执行...'));
465
+ const child = spawn(finalCommand, [], { shell: true, stdio: 'inherit' });
466
+ child.on('close', (code) => {
467
+ process.exit(code);
468
+ });
469
+ } else {
470
+ process.exit(0);
471
+ }
472
+ });
473
+ } else {
474
+ rlHistory.close();
475
+ if (answer.toLowerCase() !== 'q') {
476
+ // 如果输错了或者是q,就退出,不报错
477
+ }
478
+ }
479
+ });
443
480
  }
444
481
  break;
445
482
  case 'save':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuangs",
3
- "version": "1.3.38",
3
+ "version": "1.3.39",
4
4
  "description": "苑广山的个人应用集合 CLI(彩色版)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,66 @@
1
+ const { spawn } = require('child_process');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+
6
+ // Ensure there is some history to test with
7
+ const historyFile = path.join(os.homedir(), '.yuangs_cmd_history.json');
8
+ const dummyHistory = [
9
+ { question: "Test Question", command: "echo 'History Test Success'", time: "Now" }
10
+ ];
11
+
12
+ // Backup existing history if any
13
+ let backupHistory = null;
14
+ if (fs.existsSync(historyFile)) {
15
+ backupHistory = fs.readFileSync(historyFile);
16
+ }
17
+ fs.writeFileSync(historyFile, JSON.stringify(dummyHistory));
18
+
19
+ const cliPath = path.join(__dirname, 'cli.js');
20
+ const child = spawn('node', [cliPath, 'history'], { stdio: 'pipe' });
21
+
22
+ let output = '';
23
+ let step = 0;
24
+
25
+ child.stdout.on('data', (data) => {
26
+ const str = data.toString();
27
+ output += str;
28
+ console.log(`[CLI Output] ${str}`);
29
+
30
+ // Step 1: Wait for prompt and send index '1'
31
+ if (step === 0 && str.includes('输入序号')) {
32
+ console.log('[Test] Sending "1"...');
33
+ child.stdin.write('1\n');
34
+ step++;
35
+ }
36
+
37
+ // Step 2: Wait for pre-fill confirmation (readline write)
38
+ // Note: Since we are in a non-TTY pipe, readline.write might behave differently or just output the text.
39
+ // In our code: rlHistory.write(targetCommand) -> outputs to stdout.
40
+ if (step === 1 && str.includes('echo \'History Test Success\'')) {
41
+ console.log('[Test] Command pre-filled. Sending Enter to execute...');
42
+ child.stdin.write('\n');
43
+ step++;
44
+ }
45
+ });
46
+
47
+ child.stderr.on('data', (data) => {
48
+ console.error(`[CLI Error] ${data}`);
49
+ });
50
+
51
+ child.on('close', (code) => {
52
+ console.log(`[Test] Process exited with code ${code}`);
53
+
54
+ // Restore history
55
+ if (backupHistory) {
56
+ fs.writeFileSync(historyFile, backupHistory);
57
+ } else {
58
+ fs.unlinkSync(historyFile);
59
+ }
60
+
61
+ if (output.includes('History Test Success')) {
62
+ console.log('✅ Interactive History Test PASSED');
63
+ } else {
64
+ console.log('❌ Interactive History Test FAILED');
65
+ }
66
+ });
@@ -0,0 +1,67 @@
1
+ const { spawn } = require('child_process');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+
6
+ // Ensure there is some history to test with
7
+ const historyFile = path.join(os.homedir(), '.yuangs_cmd_history.json');
8
+ const dummyHistory = [
9
+ { question: "First command", command: "echo 'I am command 1'", time: "Now" },
10
+ { question: "Second command", command: "echo 'I am command 2'", time: "Now" },
11
+ { question: "Third command", command: "echo 'I am command 3'", time: "Now" }
12
+ ];
13
+
14
+ // Backup existing history if any
15
+ let backupHistory = null;
16
+ if (fs.existsSync(historyFile)) {
17
+ backupHistory = fs.readFileSync(historyFile);
18
+ }
19
+ fs.writeFileSync(historyFile, JSON.stringify(dummyHistory));
20
+
21
+ const cliPath = path.join(__dirname, 'cli.js');
22
+ // Run: yuangs history
23
+ const child = spawn('node', [cliPath, 'history'], { stdio: 'pipe' });
24
+
25
+ let output = '';
26
+ let step = 0;
27
+
28
+ child.stdout.on('data', (data) => {
29
+ const str = data.toString();
30
+ output += str;
31
+ console.log(`[CLI Output] ${str}`);
32
+
33
+ // Step 1: Wait for prompt and send index '2' (Select standard middleware item)
34
+ if (step === 0 && str.includes('输入序号')) {
35
+ console.log('[Test] Sending "2"... (Selecting second item)');
36
+ child.stdin.write('2\n');
37
+ step++;
38
+ }
39
+
40
+ // Step 2: Wait for pre-fill confirmation
41
+ if (step === 1 && str.includes('echo \'I am command 2\'')) {
42
+ console.log('[Test] Command 2 pre-filled. Sending Enter to execute...');
43
+ child.stdin.write('\n');
44
+ step++;
45
+ }
46
+ });
47
+
48
+ child.stderr.on('data', (data) => {
49
+ console.error(`[CLI Error] ${data}`);
50
+ });
51
+
52
+ child.on('close', (code) => {
53
+ console.log(`[Test] Process exited with code ${code}`);
54
+
55
+ // Restore history
56
+ if (backupHistory) {
57
+ fs.writeFileSync(historyFile, backupHistory);
58
+ } else {
59
+ fs.unlinkSync(historyFile);
60
+ }
61
+
62
+ if (output.includes('I am command 2')) {
63
+ console.log('✅ Interactive Multi-Item History Test PASSED');
64
+ } else {
65
+ console.log('❌ Interactive Multi-Item History Test FAILED');
66
+ }
67
+ });