@catcuts-skills/hello-world 1.0.3 → 1.0.4
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/package.json +1 -1
- package/scripts/install-skill.js +122 -0
package/package.json
CHANGED
package/scripts/install-skill.js
CHANGED
|
@@ -16,11 +16,30 @@
|
|
|
16
16
|
const { execSync } = require('child_process');
|
|
17
17
|
const path = require('path');
|
|
18
18
|
const fs = require('fs');
|
|
19
|
+
const os = require('os');
|
|
19
20
|
const { printUsageGuide } = require('./usage-guide');
|
|
20
21
|
|
|
21
22
|
// 获取包根目录
|
|
22
23
|
const packageRoot = path.resolve(__dirname, '..');
|
|
23
24
|
|
|
25
|
+
// 获取用户主目录
|
|
26
|
+
const homeDir = os.homedir();
|
|
27
|
+
|
|
28
|
+
// 技能名称
|
|
29
|
+
const skillName = 'hello-world';
|
|
30
|
+
|
|
31
|
+
// 需要清理的路径列表
|
|
32
|
+
const pathsToClean = {
|
|
33
|
+
// skills CLI 的规范副本目录(这是问题的根源)
|
|
34
|
+
canonical: path.join(homeDir, '.agents', 'skills', skillName),
|
|
35
|
+
|
|
36
|
+
// Claude Code 全局技能目录(符号链接)
|
|
37
|
+
claudeGlobal: path.join(homeDir, '.claude', 'skills', skillName),
|
|
38
|
+
|
|
39
|
+
// Claude Code 项目级技能目录(如果存在)
|
|
40
|
+
claudeLocal: path.join(process.cwd(), '.claude', 'skills', skillName),
|
|
41
|
+
};
|
|
42
|
+
|
|
24
43
|
// 解析命令行参数
|
|
25
44
|
const args = process.argv.slice(2);
|
|
26
45
|
const dryRun = args.includes('--dry-run');
|
|
@@ -52,6 +71,106 @@ function log(message, type = 'info') {
|
|
|
52
71
|
console.log(`${prefix} ${message}`);
|
|
53
72
|
}
|
|
54
73
|
|
|
74
|
+
// 检查路径是否为符号链接
|
|
75
|
+
function isSymlink(filePath) {
|
|
76
|
+
try {
|
|
77
|
+
return fs.lstatSync(filePath).isSymbolicLink();
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 安全删除路径(支持符号链接、文件、目录)
|
|
84
|
+
function safeRemovePath(filePath, description) {
|
|
85
|
+
try {
|
|
86
|
+
if (!fs.existsSync(filePath)) {
|
|
87
|
+
return { success: true, removed: false, message: '不存在' };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const stats = fs.lstatSync(filePath);
|
|
91
|
+
const isLink = stats.isSymbolicLink();
|
|
92
|
+
const isDir = stats.isDirectory();
|
|
93
|
+
|
|
94
|
+
if (isLink) {
|
|
95
|
+
fs.unlinkSync(filePath);
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
removed: true,
|
|
99
|
+
message: `已删除符号链接: ${description}`
|
|
100
|
+
};
|
|
101
|
+
} else if (isDir) {
|
|
102
|
+
fs.rmSync(filePath, { recursive: true, force: true });
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
removed: true,
|
|
106
|
+
message: `已删除目录: ${description}`
|
|
107
|
+
};
|
|
108
|
+
} else {
|
|
109
|
+
fs.unlinkSync(filePath);
|
|
110
|
+
return {
|
|
111
|
+
success: true,
|
|
112
|
+
removed: true,
|
|
113
|
+
message: `已删除文件: ${description}`
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
removed: false,
|
|
120
|
+
message: `删除失败: ${error.message}`
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 清理旧的安装文件
|
|
126
|
+
function cleanOldInstallations() {
|
|
127
|
+
log('\n正在清理旧的安装文件...', 'info');
|
|
128
|
+
|
|
129
|
+
const results = [];
|
|
130
|
+
|
|
131
|
+
// 1. 清理规范副本目录(.agents/skills/hello-world)
|
|
132
|
+
const canonicalResult = safeRemovePath(
|
|
133
|
+
pathsToClean.canonical,
|
|
134
|
+
'规范副本'
|
|
135
|
+
);
|
|
136
|
+
results.push({ path: pathsToClean.canonical, ...canonicalResult });
|
|
137
|
+
|
|
138
|
+
// 2. 清理 Claude Code 全局符号链接
|
|
139
|
+
const globalResult = safeRemovePath(
|
|
140
|
+
pathsToClean.claudeGlobal,
|
|
141
|
+
'全局技能链接'
|
|
142
|
+
);
|
|
143
|
+
results.push({ path: pathsToClean.claudeGlobal, ...globalResult });
|
|
144
|
+
|
|
145
|
+
// 3. 清理 Claude Code 项目级安装(如果存在)
|
|
146
|
+
const localResult = safeRemovePath(
|
|
147
|
+
pathsToClean.claudeLocal,
|
|
148
|
+
'项目级技能'
|
|
149
|
+
);
|
|
150
|
+
results.push({ path: pathsToClean.claudeLocal, ...localResult });
|
|
151
|
+
|
|
152
|
+
// 输出清理结果
|
|
153
|
+
let removedCount = 0;
|
|
154
|
+
results.forEach((result) => {
|
|
155
|
+
if (result.removed) {
|
|
156
|
+
log(` ✓ ${result.message}`, 'success');
|
|
157
|
+
removedCount++;
|
|
158
|
+
} else if (result.success) {
|
|
159
|
+
log(` ⊗ ${result.message} (跳过)`, 'info');
|
|
160
|
+
} else {
|
|
161
|
+
log(` ✗ ${result.message}`, 'warning');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (removedCount > 0) {
|
|
166
|
+
log(`\n已清理 ${removedCount} 个旧安装文件`, 'success');
|
|
167
|
+
} else {
|
|
168
|
+
log('未发现需要清理的文件', 'info');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return removedCount > 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
55
174
|
// 错误处理
|
|
56
175
|
function handleError(error) {
|
|
57
176
|
log(`安装失败: ${error.message}`, 'error');
|
|
@@ -64,6 +183,9 @@ try {
|
|
|
64
183
|
log(`开始安装 Hello World Skill...`, 'info');
|
|
65
184
|
log(`安装范围: ${isGlobal ? '全局(GLOBAL)' : '项目级(LOCAL)'}`, 'info');
|
|
66
185
|
|
|
186
|
+
// 清理旧的安装文件(解决增量更新导致的文件残留问题)
|
|
187
|
+
cleanOldInstallations();
|
|
188
|
+
|
|
67
189
|
// 构建 skills 命令
|
|
68
190
|
const commandParts = [
|
|
69
191
|
'npx',
|