@42ailab/42plugin 0.3.7 → 0.3.9
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/42plugin-repair +187 -2
- package/package.json +6 -6
package/bin/42plugin-repair
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
const { platform, arch, env, argv } = process;
|
|
9
9
|
const { execSync } = require("child_process");
|
|
10
|
-
const { existsSync, rmSync, writeFileSync } = require("fs");
|
|
10
|
+
const { existsSync, readFileSync, rmSync, readdirSync, lstatSync, unlinkSync, writeFileSync } = require("fs");
|
|
11
11
|
const { join, isAbsolute } = require("path");
|
|
12
12
|
|
|
13
13
|
// 解析命令行参数
|
|
14
14
|
const uninstallOnly = argv.includes("--uninstall-only") || argv.includes("--remove");
|
|
15
|
+
const purgeData = argv.includes("--purge");
|
|
15
16
|
const packages = ["@42ailab/42plugin", `@42ailab/42plugin-${platform}-${arch}`];
|
|
16
17
|
|
|
17
18
|
// 颜色输出
|
|
@@ -68,6 +69,165 @@ function detectPackageManager() {
|
|
|
68
69
|
return "npm";
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
function cleanupClaudeCodeConfig() {
|
|
73
|
+
const homeDir = env.HOME || env.USERPROFILE || "";
|
|
74
|
+
if (!homeDir) return;
|
|
75
|
+
|
|
76
|
+
const claudeDir = join(homeDir, ".claude");
|
|
77
|
+
if (!existsSync(claudeDir)) {
|
|
78
|
+
log(" ℹ️ 未找到 ~/.claude 目录,跳过", "yellow");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 1. 清理 settings.json 中的 42plugin hook 条目
|
|
83
|
+
const settingsPath = join(claudeDir, "settings.json");
|
|
84
|
+
if (existsSync(settingsPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const raw = readFileSync(settingsPath, "utf-8");
|
|
87
|
+
const settings = JSON.parse(raw);
|
|
88
|
+
|
|
89
|
+
if (settings.hooks) {
|
|
90
|
+
let modified = false;
|
|
91
|
+
|
|
92
|
+
for (const eventType of Object.keys(settings.hooks)) {
|
|
93
|
+
if (!Array.isArray(settings.hooks[eventType])) continue;
|
|
94
|
+
|
|
95
|
+
const original = settings.hooks[eventType];
|
|
96
|
+
const filtered = original.filter((entry) => {
|
|
97
|
+
// 移除带 42plugin- 前缀 _marker 的条目
|
|
98
|
+
if (entry._marker && entry._marker.startsWith("42plugin-")) {
|
|
99
|
+
modified = true;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
// 移除无 _marker 但命令包含 42plugin __hook 的遗留条目
|
|
103
|
+
if (!entry._marker && entry.hooks) {
|
|
104
|
+
const isOurHook = entry.hooks.some((h) => {
|
|
105
|
+
const cmd = h.command || "";
|
|
106
|
+
return /42plugin\s+__hook/.test(cmd);
|
|
107
|
+
});
|
|
108
|
+
if (isOurHook) {
|
|
109
|
+
modified = true;
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 移除无 _marker 但命令指向 42plugin hook 脚本的遗留条目
|
|
114
|
+
if (!entry._marker && entry.hooks) {
|
|
115
|
+
const isOurScript = entry.hooks.some((h) => {
|
|
116
|
+
const cmd = h.command || "";
|
|
117
|
+
return /\.claude[\\/]hooks[\\/](skill-explorer-|42plugin)/.test(cmd);
|
|
118
|
+
});
|
|
119
|
+
if (isOurScript) {
|
|
120
|
+
modified = true;
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
settings.hooks[eventType] = filtered;
|
|
128
|
+
|
|
129
|
+
// 清理空数组
|
|
130
|
+
if (filtered.length === 0) {
|
|
131
|
+
delete settings.hooks[eventType];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 清理空 hooks 对象
|
|
136
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
137
|
+
delete settings.hooks;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (modified) {
|
|
141
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
142
|
+
log(" ✅ settings.json hook 条目已清理", "green");
|
|
143
|
+
} else {
|
|
144
|
+
log(" ℹ️ settings.json 中无 42plugin hook 条目", "yellow");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
log(` ⚠️ settings.json 清理失败: ${error.message}`, "yellow");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 2. 清理 ~/.claude/skills/ 中的 42plugin 相关目录/符号链接
|
|
153
|
+
const skillsDir = join(claudeDir, "skills");
|
|
154
|
+
if (existsSync(skillsDir)) {
|
|
155
|
+
try {
|
|
156
|
+
const entries = readdirSync(skillsDir);
|
|
157
|
+
let cleaned = 0;
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
if (entry.startsWith("42plugin")) {
|
|
160
|
+
const fullPath = join(skillsDir, entry);
|
|
161
|
+
try {
|
|
162
|
+
const stat = lstatSync(fullPath);
|
|
163
|
+
if (stat.isSymbolicLink()) {
|
|
164
|
+
unlinkSync(fullPath);
|
|
165
|
+
cleaned++;
|
|
166
|
+
} else if (stat.isDirectory()) {
|
|
167
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
168
|
+
cleaned++;
|
|
169
|
+
} else if (stat.isFile()) {
|
|
170
|
+
unlinkSync(fullPath);
|
|
171
|
+
cleaned++;
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
174
|
+
log(` ⚠️ 清理 ${fullPath} 失败: ${e.message}`, "yellow");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (cleaned > 0) {
|
|
179
|
+
log(` ✅ 已清理 ${cleaned} 个 skills 目录/链接`, "green");
|
|
180
|
+
}
|
|
181
|
+
} catch {}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 3. 清理 ~/.claude/agents/ 中的 42plugin 相关文件
|
|
185
|
+
const agentsDir = join(claudeDir, "agents");
|
|
186
|
+
if (existsSync(agentsDir)) {
|
|
187
|
+
try {
|
|
188
|
+
const entries = readdirSync(agentsDir);
|
|
189
|
+
let cleaned = 0;
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (entry.startsWith("42plugin-") && entry.endsWith(".md")) {
|
|
192
|
+
const fullPath = join(agentsDir, entry);
|
|
193
|
+
try {
|
|
194
|
+
unlinkSync(fullPath);
|
|
195
|
+
cleaned++;
|
|
196
|
+
} catch (e) {
|
|
197
|
+
log(` ⚠️ 清理 ${fullPath} 失败: ${e.message}`, "yellow");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (cleaned > 0) {
|
|
202
|
+
log(` ✅ 已清理 ${cleaned} 个 agent 文件`, "green");
|
|
203
|
+
}
|
|
204
|
+
} catch {}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 4. 清理 ~/.claude/hooks/ 中的 42plugin 相关脚本
|
|
208
|
+
const hooksDir = join(claudeDir, "hooks");
|
|
209
|
+
if (existsSync(hooksDir)) {
|
|
210
|
+
try {
|
|
211
|
+
const entries = readdirSync(hooksDir);
|
|
212
|
+
let cleaned = 0;
|
|
213
|
+
for (const entry of entries) {
|
|
214
|
+
if (entry.startsWith("skill-explorer-") && entry.endsWith(".sh")) {
|
|
215
|
+
const fullPath = join(hooksDir, entry);
|
|
216
|
+
try {
|
|
217
|
+
unlinkSync(fullPath);
|
|
218
|
+
cleaned++;
|
|
219
|
+
} catch (e) {
|
|
220
|
+
log(` ⚠️ 清理 ${fullPath} 失败: ${e.message}`, "yellow");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (cleaned > 0) {
|
|
225
|
+
log(` ✅ 已清理 ${cleaned} 个 hook 脚本`, "green");
|
|
226
|
+
}
|
|
227
|
+
} catch {}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
71
231
|
async function repair() {
|
|
72
232
|
if (uninstallOnly) {
|
|
73
233
|
log("\n🗑️ 42plugin 卸载工具", "cyan");
|
|
@@ -210,8 +370,33 @@ async function repair() {
|
|
|
210
370
|
}
|
|
211
371
|
}
|
|
212
372
|
|
|
213
|
-
//
|
|
373
|
+
// 仅卸载模式:清理 Claude Code 配置并跳过重新安装
|
|
214
374
|
if (uninstallOnly) {
|
|
375
|
+
log("\n步骤 4: 清理 Claude Code 配置...", "yellow");
|
|
376
|
+
cleanupClaudeCodeConfig();
|
|
377
|
+
|
|
378
|
+
// --purge: 删除用户数据目录 ~/.42plugin/
|
|
379
|
+
const homeDir = env.HOME || env.USERPROFILE || "";
|
|
380
|
+
if (homeDir) {
|
|
381
|
+
const pluginDataDir = join(homeDir, ".42plugin");
|
|
382
|
+
if (purgeData) {
|
|
383
|
+
if (existsSync(pluginDataDir)) {
|
|
384
|
+
log("\n步骤 5: 清理用户数据 (~/.42plugin/)...", "yellow");
|
|
385
|
+
try {
|
|
386
|
+
rmSync(pluginDataDir, { recursive: true, force: true });
|
|
387
|
+
log(" ✅ 用户数据已删除", "green");
|
|
388
|
+
} catch (error) {
|
|
389
|
+
log(` ⚠️ 用户数据清理失败: ${error.message}`, "yellow");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
} else if (existsSync(pluginDataDir)) {
|
|
393
|
+
log("\n📁 数据保留提示:", "cyan");
|
|
394
|
+
log(` 用户数据目录 ${pluginDataDir} 已保留(含配置和历史记录)。`, "blue");
|
|
395
|
+
log(" 如需彻底删除,请运行:", "blue");
|
|
396
|
+
log(" 42plugin-repair --remove --purge", "blue");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
215
400
|
log("\n✅ 42plugin 已彻底卸载。", "green");
|
|
216
401
|
log(" 如需重新安装,请运行:", "blue");
|
|
217
402
|
log(" npm install -g @42ailab/42plugin", "blue");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@42ailab/42plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "42plugin CLI - AI 插件管理工具",
|
|
5
5
|
"bin": {
|
|
6
6
|
"42plugin": "bin/42plugin",
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@42ailab/42plugin-darwin-arm64": "0.3.
|
|
40
|
-
"@42ailab/42plugin-darwin-x64": "0.3.
|
|
41
|
-
"@42ailab/42plugin-linux-arm64": "0.3.
|
|
42
|
-
"@42ailab/42plugin-linux-x64": "0.3.
|
|
43
|
-
"@42ailab/42plugin-win32-x64": "0.3.
|
|
39
|
+
"@42ailab/42plugin-darwin-arm64": "0.3.9",
|
|
40
|
+
"@42ailab/42plugin-darwin-x64": "0.3.9",
|
|
41
|
+
"@42ailab/42plugin-linux-arm64": "0.3.9",
|
|
42
|
+
"@42ailab/42plugin-linux-x64": "0.3.9",
|
|
43
|
+
"@42ailab/42plugin-win32-x64": "0.3.9"
|
|
44
44
|
}
|
|
45
45
|
}
|