@lyra-ai/toolkit 0.2.4 → 0.2.6
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/bin/toolkit.mjs +4 -4
- package/package.json +5 -5
- package/src/flush.mjs +243 -221
- package/src/hook.mjs +35 -21
- package/src/install.mjs +69 -30
- package/src/shared/backlog.mjs +96 -0
- package/src/shared/config.mjs +17 -0
- package/src/shared/http.mjs +29 -0
- package/src/shared/lock.mjs +79 -0
- package/src/shared/settle.mjs +20 -0
- package/src/shared/zip.mjs +89 -0
- package/src/status.mjs +103 -36
- package/src/uninstall.mjs +26 -13
- package/src/zentao.mjs +20 -19
package/src/uninstall.mjs
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* uninstall.mjs — `toolkit uninstall`
|
|
4
|
-
*
|
|
3
|
+
* uninstall.mjs — `toolkit uninstall [--purge]`
|
|
4
|
+
*
|
|
5
|
+
* 删除 @skills-dir 插件目录(~/.claude/skills/toolkit)+ 旧版裸目录残留
|
|
6
|
+
* + settings.json 里失效的 toolkit@local 条目。可选 --purge 清除 ~/.toolkit/ 数据。
|
|
7
|
+
*
|
|
8
|
+
* 注:@skills-dir plugin 没有「卸载步骤」(按官方文档,删文件夹即停用)。
|
|
5
9
|
*/
|
|
6
10
|
import fs from 'node:fs';
|
|
7
11
|
import path from 'node:path';
|
|
8
12
|
import os from 'node:os';
|
|
9
13
|
|
|
10
14
|
const HOME = os.homedir();
|
|
11
|
-
const PLUGIN_DIR = path.join(HOME, '.claude', '
|
|
15
|
+
const PLUGIN_DIR = path.join(HOME, '.claude', 'skills', 'toolkit');
|
|
16
|
+
const OLD_PLUGIN_DIR = path.join(HOME, '.claude', 'plugins', 'toolkit');
|
|
12
17
|
const SETTINGS_PATH = path.join(HOME, '.claude', 'settings.json');
|
|
13
|
-
const
|
|
18
|
+
const OLD_PLUGIN_KEY = 'toolkit@local';
|
|
19
|
+
|
|
20
|
+
// 数据目录与 shared/config.mjs 的 TOOLKIT_DIR 同逻辑,但在调用时求值,
|
|
21
|
+
// 以便测试用 TOOLKIT_HOME / HOME 隔离(避免模块加载时绑定的陈旧值)。
|
|
22
|
+
function dataDir() {
|
|
23
|
+
return process.env.TOOLKIT_HOME || path.join(os.homedir(), '.toolkit');
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
function rmrf(dir) {
|
|
16
27
|
if (!fs.existsSync(dir)) return;
|
|
@@ -25,24 +36,26 @@ function rmrf(dir) {
|
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
export function uninstall(opts = {}) {
|
|
28
|
-
// 1.
|
|
39
|
+
// 1. 删 @skills-dir 插件目录 + 旧版裸目录残留
|
|
29
40
|
rmrf(PLUGIN_DIR);
|
|
30
|
-
|
|
41
|
+
rmrf(OLD_PLUGIN_DIR);
|
|
42
|
+
console.log(`✅ 插件目录已删除(${PLUGIN_DIR})`);
|
|
31
43
|
|
|
32
|
-
// 2. 移除 settings.json
|
|
44
|
+
// 2. 移除 settings.json 里失效的 toolkit@local(若有)
|
|
33
45
|
try {
|
|
34
46
|
const settings = JSON.parse(fs.readFileSync(SETTINGS_PATH, 'utf-8'));
|
|
35
|
-
if (settings.enabledPlugins?.[
|
|
36
|
-
delete settings.enabledPlugins[
|
|
47
|
+
if (settings.enabledPlugins?.[OLD_PLUGIN_KEY] !== undefined) {
|
|
48
|
+
delete settings.enabledPlugins[OLD_PLUGIN_KEY];
|
|
37
49
|
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
38
|
-
console.log('✅ settings.json
|
|
50
|
+
console.log('✅ settings.json 失效条目已移除');
|
|
39
51
|
}
|
|
40
52
|
} catch {}
|
|
41
53
|
|
|
42
|
-
// 3. 数据(~/.toolkit
|
|
54
|
+
// 3. 数据(~/.toolkit/,走 TOOLKIT_HOME 或 ~/.toolkit,与 install 一致)
|
|
43
55
|
if (opts.purge) {
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
const dir = dataDir();
|
|
57
|
+
rmrf(dir);
|
|
58
|
+
console.log(`✅ ${dir} 数据已清除`);
|
|
46
59
|
} else {
|
|
47
60
|
console.log('ℹ️ ~/.toolkit/ 数据保留(含 UID + 上传记录)。');
|
|
48
61
|
console.log(' 彻底清除: toolkit uninstall --purge');
|
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 === '\
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
process.
|
|
604
|
-
|
|
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);
|