@adonis0123/skill-development 1.0.5 → 1.0.7

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/README.md CHANGED
@@ -76,7 +76,8 @@ skill-name/
76
76
  - [@adonis0123/commit](https://www.npmjs.com/package/@adonis0123/commit) - 提交信息生成
77
77
  - [@adonis0123/staged-changes-review](https://www.npmjs.com/package/@adonis0123/staged-changes-review) - 代码审查
78
78
  - [@adonis0123/create-skill](https://www.npmjs.com/package/@adonis0123/create-skill) - 创建新技能包
79
-
79
+ - [@adonis0123/code-doc-generator](https://www.npmjs.com/package/@adonis0123/code-doc-generator) - 代码文档生成
80
+ - [@adonis0123/css-tailwind-styling](https://www.npmjs.com/package/@adonis0123/css-tailwind-styling) - CSS 和 Tailwind 样式规范
80
81
  ## License
81
82
 
82
83
  MIT
package/install-skill.js CHANGED
@@ -23,9 +23,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // shared/src/install-skill.ts
26
- var import_fs2 = __toESM(require("fs"));
27
- var import_path2 = __toESM(require("path"));
28
- var import_os2 = __toESM(require("os"));
26
+ var import_fs3 = __toESM(require("fs"));
27
+ var import_path3 = __toESM(require("path"));
28
+ var import_os3 = __toESM(require("os"));
29
29
  var import_child_process = require("child_process");
30
30
 
31
31
  // shared/src/utils.ts
@@ -116,6 +116,69 @@ function readSkillConfig(dir) {
116
116
  return JSON.parse(import_fs.default.readFileSync(configPath, "utf-8"));
117
117
  }
118
118
 
119
+ // shared/src/claude-settings.ts
120
+ var import_fs2 = __toESM(require("fs"));
121
+ var import_path2 = __toESM(require("path"));
122
+ var import_os2 = __toESM(require("os"));
123
+ function getClaudeSettingsPath() {
124
+ return import_path2.default.join(import_os2.default.homedir(), ".claude", "settings.json");
125
+ }
126
+ function readClaudeSettings() {
127
+ const settingsPath = getClaudeSettingsPath();
128
+ if (!import_fs2.default.existsSync(settingsPath)) {
129
+ return {};
130
+ }
131
+ try {
132
+ const content = import_fs2.default.readFileSync(settingsPath, "utf-8");
133
+ return JSON.parse(content);
134
+ } catch (error) {
135
+ console.warn(" \u26A0 Warning: Could not parse settings.json, treating as empty");
136
+ return {};
137
+ }
138
+ }
139
+ function writeClaudeSettings(settings) {
140
+ const settingsPath = getClaudeSettingsPath();
141
+ const settingsDir = import_path2.default.dirname(settingsPath);
142
+ if (!import_fs2.default.existsSync(settingsDir)) {
143
+ import_fs2.default.mkdirSync(settingsDir, { recursive: true });
144
+ }
145
+ import_fs2.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
146
+ }
147
+ function hookMatcherExists(existingHooks, newMatcher) {
148
+ return existingHooks.some((hook) => hook.matcher === newMatcher.matcher);
149
+ }
150
+ function addClaudeHooks(hooksConfig, skillName) {
151
+ const settings = readClaudeSettings();
152
+ let modified = false;
153
+ if (!settings.hooks || typeof settings.hooks !== "object") {
154
+ settings.hooks = {};
155
+ }
156
+ const hooks = settings.hooks;
157
+ for (const [hookType, hookMatchers] of Object.entries(hooksConfig)) {
158
+ if (!hookMatchers || !Array.isArray(hookMatchers)) {
159
+ continue;
160
+ }
161
+ if (!hooks[hookType] || !Array.isArray(hooks[hookType])) {
162
+ hooks[hookType] = [];
163
+ }
164
+ const existingHooks = hooks[hookType];
165
+ for (const matcher of hookMatchers) {
166
+ if (!hookMatcherExists(existingHooks, matcher)) {
167
+ existingHooks.push(matcher);
168
+ modified = true;
169
+ console.log(` \u2713 Added ${hookType} hook for ${skillName}`);
170
+ } else {
171
+ console.log(` \u2139 ${hookType} hook already exists, skipping`);
172
+ }
173
+ }
174
+ hooks[hookType] = existingHooks;
175
+ }
176
+ if (modified) {
177
+ writeClaudeSettings(settings);
178
+ }
179
+ return modified;
180
+ }
181
+
119
182
  // shared/src/install-skill.ts
120
183
  function fetchFromRemote(tempDir, remoteSource) {
121
184
  try {
@@ -124,7 +187,7 @@ function fetchFromRemote(tempDir, remoteSource) {
124
187
  stdio: "pipe",
125
188
  timeout: 6e4
126
189
  });
127
- if (import_fs2.default.existsSync(import_path2.default.join(tempDir, "SKILL.md"))) {
190
+ if (import_fs3.default.existsSync(import_path3.default.join(tempDir, "SKILL.md"))) {
128
191
  console.log(" \u2713 Fetched latest version from remote");
129
192
  return true;
130
193
  }
@@ -146,14 +209,14 @@ function getSourceDir(config, packageDir) {
146
209
  isRemote: false
147
210
  };
148
211
  }
149
- const tempDir = import_path2.default.join(import_os2.default.tmpdir(), `skill-fetch-${Date.now()}`);
212
+ const tempDir = import_path3.default.join(import_os3.default.tmpdir(), `skill-fetch-${Date.now()}`);
150
213
  const remoteSuccess = fetchFromRemote(tempDir, config.remoteSource);
151
214
  if (remoteSuccess) {
152
215
  return {
153
216
  sourceDir: tempDir,
154
217
  cleanup: () => {
155
218
  try {
156
- import_fs2.default.rmSync(tempDir, { recursive: true, force: true });
219
+ import_fs3.default.rmSync(tempDir, { recursive: true, force: true });
157
220
  } catch {
158
221
  }
159
222
  },
@@ -161,7 +224,7 @@ function getSourceDir(config, packageDir) {
161
224
  };
162
225
  }
163
226
  try {
164
- import_fs2.default.rmSync(tempDir, { recursive: true, force: true });
227
+ import_fs3.default.rmSync(tempDir, { recursive: true, force: true });
165
228
  } catch {
166
229
  }
167
230
  return {
@@ -172,11 +235,11 @@ function getSourceDir(config, packageDir) {
172
235
  };
173
236
  }
174
237
  function updateManifest(skillsDir, config, targetName, isRemote) {
175
- const manifestPath = import_path2.default.join(skillsDir, ".skills-manifest.json");
238
+ const manifestPath = import_path3.default.join(skillsDir, ".skills-manifest.json");
176
239
  let manifest = { skills: {} };
177
- if (import_fs2.default.existsSync(manifestPath)) {
240
+ if (import_fs3.default.existsSync(manifestPath)) {
178
241
  try {
179
- manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
242
+ manifest = JSON.parse(import_fs3.default.readFileSync(manifestPath, "utf-8"));
180
243
  } catch {
181
244
  console.warn(" Warning: Could not parse existing manifest, creating new one");
182
245
  manifest = { skills: {} };
@@ -187,55 +250,68 @@ function updateManifest(skillsDir, config, targetName, isRemote) {
187
250
  version: config.version,
188
251
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
189
252
  package: config.package || config.name,
190
- path: import_path2.default.join(skillsDir, skillName),
253
+ path: import_path3.default.join(skillsDir, skillName),
191
254
  target: targetName,
192
255
  ...config.remoteSource && { source: config.remoteSource }
193
256
  };
194
- import_fs2.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
257
+ import_fs3.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
195
258
  }
196
259
  function installToTarget(target, config, sourceDir, isRemote) {
197
- var _a;
260
+ var _a, _b;
198
261
  console.log(`
199
262
  \u{1F4E6} Installing to ${target.name}...`);
200
263
  const isGlobal = isGlobalInstall();
201
264
  const location = detectInstallLocation(target.paths, isGlobal);
202
265
  const skillName = extractSkillName(config.name);
203
- const targetDir = import_path2.default.join(location.base, skillName);
204
- const altTargetDir = import_path2.default.join(location.base, config.name);
266
+ const targetDir = import_path3.default.join(location.base, skillName);
267
+ const altTargetDir = import_path3.default.join(location.base, config.name);
205
268
  console.log(` Type: ${location.type}${isGlobal ? " (global)" : " (project)"}`);
206
269
  console.log(` Directory: ${targetDir}`);
207
- if (import_fs2.default.existsSync(altTargetDir) && altTargetDir !== targetDir) {
270
+ if (import_fs3.default.existsSync(altTargetDir) && altTargetDir !== targetDir) {
208
271
  console.log(" \u{1F9F9} Cleaning up alternative path format...");
209
272
  removeDir(altTargetDir);
210
273
  console.log(` \u2713 Removed directory: ${config.name}`);
211
274
  }
212
275
  ensureDir(targetDir);
213
- const skillMdSource = import_path2.default.join(sourceDir, "SKILL.md");
214
- if (!import_fs2.default.existsSync(skillMdSource)) {
276
+ const skillMdSource = import_path3.default.join(sourceDir, "SKILL.md");
277
+ if (!import_fs3.default.existsSync(skillMdSource)) {
215
278
  throw new Error("SKILL.md is required but not found");
216
279
  }
217
- import_fs2.default.copyFileSync(skillMdSource, import_path2.default.join(targetDir, "SKILL.md"));
280
+ import_fs3.default.copyFileSync(skillMdSource, import_path3.default.join(targetDir, "SKILL.md"));
218
281
  console.log(" \u2713 Copied SKILL.md");
219
282
  const filesToCopy = config.files || {};
220
283
  for (const [source, dest] of Object.entries(filesToCopy)) {
221
- const sourcePath = import_path2.default.join(sourceDir, source);
222
- if (!import_fs2.default.existsSync(sourcePath)) {
284
+ const sourcePath = import_path3.default.join(sourceDir, source);
285
+ if (!import_fs3.default.existsSync(sourcePath)) {
223
286
  console.warn(` \u26A0 Warning: ${source} not found, skipping`);
224
287
  continue;
225
288
  }
226
- const destPath = import_path2.default.join(targetDir, dest);
227
- if (import_fs2.default.statSync(sourcePath).isDirectory()) {
289
+ const destPath = import_path3.default.join(targetDir, dest);
290
+ if (import_fs3.default.statSync(sourcePath).isDirectory()) {
228
291
  copyDir(sourcePath, destPath);
229
292
  console.log(` \u2713 Copied directory: ${source}`);
230
293
  } else {
231
- const destDir = import_path2.default.dirname(destPath);
294
+ const destDir = import_path3.default.dirname(destPath);
232
295
  ensureDir(destDir);
233
- import_fs2.default.copyFileSync(sourcePath, destPath);
296
+ import_fs3.default.copyFileSync(sourcePath, destPath);
234
297
  console.log(` \u2713 Copied file: ${source}`);
235
298
  }
236
299
  }
237
300
  updateManifest(location.base, config, target.name, isRemote);
238
- if ((_a = config.hooks) == null ? void 0 : _a.postinstall) {
301
+ if (target.name === "claude-code" && ((_a = config.claudeSettings) == null ? void 0 : _a.hooks)) {
302
+ console.log(" \u{1F527} \u914D\u7F6E Claude Code \u94A9\u5B50...");
303
+ try {
304
+ const skillName2 = extractSkillName(config.name);
305
+ const modified = addClaudeHooks(config.claudeSettings.hooks, skillName2);
306
+ if (modified) {
307
+ console.log(" \u2705 \u94A9\u5B50\u5DF2\u914D\u7F6E\u5230 ~/.claude/settings.json");
308
+ }
309
+ } catch (error) {
310
+ const message = error instanceof Error ? error.message : String(error);
311
+ console.warn(` \u26A0 \u8B66\u544A: \u65E0\u6CD5\u914D\u7F6E\u94A9\u5B50: ${message}`);
312
+ }
313
+ }
314
+ if ((_b = config.hooks) == null ? void 0 : _b.postinstall) {
239
315
  console.log(" \u{1F527} Running postinstall hook...");
240
316
  try {
241
317
  (0, import_child_process.execSync)(config.hooks.postinstall, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis0123/skill-development",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Claude Code Skill - 技能开发指南,提供创建有效技能的完整流程和最佳实践。安装时自动从 Anthropic 官方仓库拉取最新版本。",
5
5
  "scripts": {
6
6
  "postinstall": "node install-skill.js",
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // shared/src/uninstall-skill.ts
26
- var import_fs2 = __toESM(require("fs"));
27
- var import_path2 = __toESM(require("path"));
26
+ var import_fs3 = __toESM(require("fs"));
27
+ var import_path3 = __toESM(require("path"));
28
28
 
29
29
  // shared/src/utils.ts
30
30
  var import_fs = __toESM(require("fs"));
@@ -96,17 +96,77 @@ function readSkillConfig(dir) {
96
96
  return JSON.parse(import_fs.default.readFileSync(configPath, "utf-8"));
97
97
  }
98
98
 
99
+ // shared/src/claude-settings.ts
100
+ var import_fs2 = __toESM(require("fs"));
101
+ var import_path2 = __toESM(require("path"));
102
+ var import_os2 = __toESM(require("os"));
103
+ function getClaudeSettingsPath() {
104
+ return import_path2.default.join(import_os2.default.homedir(), ".claude", "settings.json");
105
+ }
106
+ function readClaudeSettings() {
107
+ const settingsPath = getClaudeSettingsPath();
108
+ if (!import_fs2.default.existsSync(settingsPath)) {
109
+ return {};
110
+ }
111
+ try {
112
+ const content = import_fs2.default.readFileSync(settingsPath, "utf-8");
113
+ return JSON.parse(content);
114
+ } catch (error) {
115
+ console.warn(" \u26A0 Warning: Could not parse settings.json, treating as empty");
116
+ return {};
117
+ }
118
+ }
119
+ function writeClaudeSettings(settings) {
120
+ const settingsPath = getClaudeSettingsPath();
121
+ const settingsDir = import_path2.default.dirname(settingsPath);
122
+ if (!import_fs2.default.existsSync(settingsDir)) {
123
+ import_fs2.default.mkdirSync(settingsDir, { recursive: true });
124
+ }
125
+ import_fs2.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
126
+ }
127
+ function removeClaudeHooks(hooksConfig, skillName) {
128
+ const settings = readClaudeSettings();
129
+ let modified = false;
130
+ if (!settings.hooks || typeof settings.hooks !== "object") {
131
+ return false;
132
+ }
133
+ const hooks = settings.hooks;
134
+ for (const [hookType, hookMatchers] of Object.entries(hooksConfig)) {
135
+ if (!hookMatchers || !Array.isArray(hookMatchers)) {
136
+ continue;
137
+ }
138
+ if (!hooks[hookType] || !Array.isArray(hooks[hookType])) {
139
+ continue;
140
+ }
141
+ const existingHooks = hooks[hookType];
142
+ const initialLength = existingHooks.length;
143
+ const matchersToRemove = hookMatchers.map((m) => m.matcher);
144
+ const filteredHooks = existingHooks.filter(
145
+ (hook) => !matchersToRemove.includes(hook.matcher)
146
+ );
147
+ if (filteredHooks.length < initialLength) {
148
+ hooks[hookType] = filteredHooks;
149
+ modified = true;
150
+ console.log(` \u2713 Removed ${hookType} hook for ${skillName}`);
151
+ }
152
+ }
153
+ if (modified) {
154
+ writeClaudeSettings(settings);
155
+ }
156
+ return modified;
157
+ }
158
+
99
159
  // shared/src/uninstall-skill.ts
100
160
  function updateManifest(skillsDir, config) {
101
- const manifestPath = import_path2.default.join(skillsDir, ".skills-manifest.json");
102
- if (!import_fs2.default.existsSync(manifestPath)) {
161
+ const manifestPath = import_path3.default.join(skillsDir, ".skills-manifest.json");
162
+ if (!import_fs3.default.existsSync(manifestPath)) {
103
163
  return;
104
164
  }
105
165
  try {
106
- const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
166
+ const manifest = JSON.parse(import_fs3.default.readFileSync(manifestPath, "utf-8"));
107
167
  if (manifest.skills && manifest.skills[config.name]) {
108
168
  delete manifest.skills[config.name];
109
- import_fs2.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
169
+ import_fs3.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
110
170
  console.log(" \u2713 Updated manifest");
111
171
  }
112
172
  } catch (error) {
@@ -115,25 +175,38 @@ function updateManifest(skillsDir, config) {
115
175
  }
116
176
  }
117
177
  function uninstallFromTarget(target, config) {
178
+ var _a;
118
179
  console.log(`
119
180
  \u{1F5D1}\uFE0F Uninstalling from ${target.name}...`);
120
181
  const isGlobal = isGlobalInstall();
121
182
  const location = detectInstallLocation(target.paths, isGlobal);
122
183
  const skillName = extractSkillName(config.name);
123
- const skillNameTargetDir = import_path2.default.join(location.base, skillName);
124
- const fullPackageNameTargetDir = import_path2.default.join(location.base, config.name);
184
+ const skillNameTargetDir = import_path3.default.join(location.base, skillName);
185
+ const fullPackageNameTargetDir = import_path3.default.join(location.base, config.name);
125
186
  let removed = false;
126
- if (import_fs2.default.existsSync(skillNameTargetDir)) {
187
+ if (import_fs3.default.existsSync(skillNameTargetDir)) {
127
188
  removeDir(skillNameTargetDir);
128
189
  console.log(` \u2713 Removed skill directory: ${skillName}`);
129
190
  removed = true;
130
191
  }
131
- if (import_fs2.default.existsSync(fullPackageNameTargetDir) && fullPackageNameTargetDir !== skillNameTargetDir) {
192
+ if (import_fs3.default.existsSync(fullPackageNameTargetDir) && fullPackageNameTargetDir !== skillNameTargetDir) {
132
193
  removeDir(fullPackageNameTargetDir);
133
194
  console.log(` \u2713 Removed skill directory: ${config.name}`);
134
195
  removed = true;
135
196
  }
136
197
  updateManifest(location.base, config);
198
+ if (target.name === "claude-code" && removed && ((_a = config.claudeSettings) == null ? void 0 : _a.hooks)) {
199
+ try {
200
+ console.log(" \u{1F527} \u79FB\u9664 Claude Code \u94A9\u5B50...");
201
+ const skillName2 = extractSkillName(config.name);
202
+ const modified = removeClaudeHooks(config.claudeSettings.hooks, skillName2);
203
+ if (modified) {
204
+ console.log(" \u2705 \u94A9\u5B50\u5DF2\u4ECE ~/.claude/settings.json \u79FB\u9664");
205
+ }
206
+ } catch (error) {
207
+ console.warn(" \u26A0 \u8B66\u544A: \u65E0\u6CD5\u79FB\u9664\u94A9\u5B50\uFF08\u53EF\u5B89\u5168\u5FFD\u7565\uFF09");
208
+ }
209
+ }
137
210
  if (removed) {
138
211
  console.log(` \u2705 Uninstalled from ${target.name}`);
139
212
  return true;