@lyra-ai/toolkit 0.2.4 → 0.2.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/package.json +5 -5
  2. package/src/zentao.mjs +20 -19
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@lyra-ai/toolkit",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "面向 AI agent 的零依赖开发工具集",
5
5
  "type": "module",
6
6
  "bin": {
7
- "toolkit": "./bin/toolkit.mjs",
8
- "zentao": "./bin/zentao.mjs",
9
- "log-query": "./bin/log-query.mjs",
10
- "skillhub": "./bin/skillhub.mjs"
7
+ "toolkit": "bin/toolkit.mjs",
8
+ "zentao": "bin/zentao.mjs",
9
+ "log-query": "bin/log-query.mjs",
10
+ "skillhub": "bin/skillhub.mjs"
11
11
  },
12
12
  "engines": {
13
13
  "node": ">=18"
package/src/zentao.mjs CHANGED
@@ -595,24 +595,29 @@ async function maskedPrompt(question) {
595
595
  return new Promise((resolve) => {
596
596
  process.stdout.write(question);
597
597
  let buf = '';
598
+ // Windows 终端回车是 \r\n:上一个 rl.question 按 \r 返回后,残留 \n 会被下一个 raw read 读到。
599
+ // 用 started 标志忽略"开头还没输入真字符时"收到的 \r/\n,避免空密码直接提交(向导秒退)。
600
+ let started = false;
601
+ const finish = () => {
602
+ process.stdout.write('\n');
603
+ process.stdin.removeListener('data', onData);
604
+ process.stdin.setRawMode(false);
605
+ resolve(buf);
606
+ };
598
607
  const onData = (c) => {
599
608
  const ch = c.toString();
600
- if (ch === '\r' || ch === '\n') {
601
- process.stdout.write('\n');
602
- process.stdin.removeListener('data', onData);
603
- process.stdin.setRawMode(false);
604
- resolve(buf);
605
- } else if (ch === '') {
606
- process.stdout.write('\n');
607
- process.exit(0);
608
- } else if (ch === '\x7f' || ch === '\b') {
609
- if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write('\b \b'); }
610
- } else {
611
- buf += ch;
612
- process.stdout.write('*');
609
+ if (ch === '\x03') { process.stdout.write('\n'); process.exit(0); } // Ctrl+C
610
+ if (ch === '\r' || ch === '\n') { if (started) finish(); return; } // 开头换行 = 残留,忽略
611
+ if (ch === '\x7f' || ch === '\b') {
612
+ if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write('\b \b'); started = true; }
613
+ return;
613
614
  }
615
+ buf += ch;
616
+ started = true;
617
+ process.stdout.write('*');
614
618
  };
615
619
  process.stdin.setRawMode(true);
620
+ process.stdin.resume();
616
621
  process.stdin.on('data', onData);
617
622
  });
618
623
  }
@@ -661,14 +666,10 @@ async function cmdInit(parsed, config, deps) {
661
666
 
662
667
  const u = await ask('禅道地址 (ZENTAO_URL)', config.zentaoUrl || '');
663
668
  const un = await ask('用户名 (ZENTAO_USERNAME)', config.username || '');
664
- const pw = await (async () => {
665
- rl.pause();
666
- const p = await maskedPrompt('密码 (ZENTAO_PASSWORD): ');
667
- rl.resume();
668
- return p;
669
- })();
670
669
 
670
+ // 先关掉 readline,彻底交出 stdin 控制权,再用裸 raw-mode 收密码(避免与 readline 冲突)
671
671
  rl.close();
672
+ const pw = await maskedPrompt('密码 (ZENTAO_PASSWORD): ');
672
673
 
673
674
  setConfigKey('ZENTAO_URL', u, deps.fs);
674
675
  setConfigKey('ZENTAO_USERNAME', un, deps.fs);