@human-avatar/skills-for-humanity 1.0.2 → 1.1.0

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/bin/install.js +62 -85
  2. package/package.json +1 -1
package/bin/install.js CHANGED
@@ -28,14 +28,12 @@ const SCOPES = {
28
28
  user: {
29
29
  label: 'User',
30
30
  description: 'available in all projects',
31
- pluginsDir: path.join(os.homedir(), '.claude', 'plugins', 'skills-for-humanity'),
32
- settingsPath: path.join(os.homedir(), '.claude', 'settings.json'),
31
+ skillsDir: path.join(os.homedir(), '.claude', 'skills'),
33
32
  },
34
33
  project: {
35
34
  label: 'Project',
36
35
  description: `this project only ${dim}(${process.cwd()})${reset}`,
37
- pluginsDir: path.join(process.cwd(), '.claude', 'plugins', 'skills-for-humanity'),
38
- settingsPath: path.join(process.cwd(), '.claude', 'settings.json'),
36
+ skillsDir: path.join(process.cwd(), '.claude', 'skills'),
39
37
  },
40
38
  };
41
39
 
@@ -49,17 +47,16 @@ const args = process.argv.slice(2);
49
47
 
50
48
  if (args.includes('--help') || args.includes('-h')) {
51
49
  log(`
52
- ${bold}skills-for-humanity${reset} — 93 structured thinking tools for Claude Code
50
+ ${bold}skills-for-humanity${reset} — 131 structured thinking tools for Claude Code
53
51
 
54
52
  ${bold}Usage:${reset}
55
53
  npx @human-avatar/skills-for-humanity [options]
56
54
 
57
55
  ${bold}Options:${reset}
58
56
  ${cyan}--scope user|project${reset} Install scope (prompted if omitted)
59
- ${dim}user: ~/.claude/ — all projects${reset}
60
- ${dim}project: ./.claude/ — this project only${reset}
61
- ${cyan}--dir <path>${reset} Install to a custom directory (skips scope prompt)
62
- ${cyan}--uninstall${reset} Remove skills and clean up settings.json
57
+ ${dim}user: ~/.claude/skills/ — all projects${reset}
58
+ ${dim}project: ./.claude/skills/ — this project only${reset}
59
+ ${cyan}--uninstall${reset} Remove installed skills
63
60
  ${cyan}--help${reset} Show this help message
64
61
 
65
62
  ${bold}After install:${reset}
@@ -86,20 +83,10 @@ function removeDir(dir) {
86
83
  if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });
87
84
  }
88
85
 
89
- function readSettings(settingsPath) {
90
- if (!fs.existsSync(settingsPath)) return {};
91
- try { return JSON.parse(fs.readFileSync(settingsPath, 'utf8')); }
92
- catch { return {}; }
93
- }
94
-
95
- function writeSettings(settingsPath, settings) {
96
- fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
97
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
98
- }
99
-
100
- function countDirs(dir) {
101
- try { return fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).length; }
102
- catch { return '?'; }
86
+ function ourSkillNames() {
87
+ return fs.readdirSync(SKILLS_SRC, { withFileTypes: true })
88
+ .filter((e) => e.isDirectory())
89
+ .map((e) => e.name);
103
90
  }
104
91
 
105
92
  function prompt(question) {
@@ -112,8 +99,8 @@ function prompt(question) {
112
99
  async function askScope() {
113
100
  log(`${bold}Where should the skills be installed?${reset}`);
114
101
  log();
115
- log(` ${cyan}1) User${reset} — available in all projects ${dim}(~/.claude/)${reset}`);
116
- log(` ${cyan}2) Project${reset} — this project only ${dim}(./.claude/)${reset}`);
102
+ log(` ${cyan}1) User${reset} — available in all projects ${dim}(~/.claude/skills/)${reset}`);
103
+ log(` ${cyan}2) Project${reset} — this project only ${dim}(./.claude/skills/)${reset}`);
117
104
  log();
118
105
 
119
106
  while (true) {
@@ -129,16 +116,6 @@ async function askScope() {
129
116
  // ---------------------------------------------------------------------------
130
117
 
131
118
  async function resolveTarget() {
132
- // --dir takes precedence, skips scope prompt entirely
133
- const dirFlag = args.indexOf('--dir');
134
- if (dirFlag !== -1 && args[dirFlag + 1]) {
135
- const custom = path.resolve(args[dirFlag + 1]);
136
- // For custom dirs, write settings next to the dir's .claude parent if it exists,
137
- // otherwise fall back to user settings.
138
- const customSettings = path.join(path.dirname(custom), 'settings.json');
139
- return { pluginsDir: custom, settingsPath: customSettings };
140
- }
141
-
142
119
  // --scope flag skips the interactive prompt
143
120
  const scopeFlag = args.indexOf('--scope');
144
121
  if (scopeFlag !== -1 && args[scopeFlag + 1]) {
@@ -159,6 +136,26 @@ async function resolveTarget() {
159
136
  return SCOPES[key];
160
137
  }
161
138
 
139
+ // ---------------------------------------------------------------------------
140
+ // Migrate: remove legacy pluginDirectories entry if present
141
+ // ---------------------------------------------------------------------------
142
+
143
+ function cleanLegacySettings(settingsPath, legacyDir) {
144
+ if (!fs.existsSync(settingsPath)) return;
145
+ try {
146
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
147
+ if (!Array.isArray(settings.pluginDirectories)) return;
148
+ const before = settings.pluginDirectories.length;
149
+ settings.pluginDirectories = settings.pluginDirectories.filter(
150
+ (d) => !path.resolve(d).includes('skills-for-humanity')
151
+ );
152
+ if (settings.pluginDirectories.length < before) {
153
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
154
+ log(`${dim}→ Removed legacy pluginDirectories entry from ${settingsPath}${reset}`);
155
+ }
156
+ } catch { /* ignore */ }
157
+ }
158
+
162
159
  // ---------------------------------------------------------------------------
163
160
  // Uninstall
164
161
  // ---------------------------------------------------------------------------
@@ -169,28 +166,24 @@ async function uninstall() {
169
166
  log();
170
167
 
171
168
  const target = await resolveTarget();
172
-
173
- removeDir(target.pluginsDir);
174
- log(`${green}✓${reset} Removed ${dim}${target.pluginsDir}${reset}`);
175
-
176
- try {
177
- const settings = readSettings(target.settingsPath);
178
- if (Array.isArray(settings.pluginDirectories)) {
179
- const before = settings.pluginDirectories.length;
180
- settings.pluginDirectories = settings.pluginDirectories.filter(
181
- (d) => path.resolve(d) !== path.resolve(target.pluginsDir)
182
- );
183
- if (settings.pluginDirectories.length < before) {
184
- writeSettings(target.settingsPath, settings);
185
- log(`${green}✓${reset} Removed from ${dim}${target.settingsPath}${reset}`);
186
- } else {
187
- log(`${dim}→ Not found in settings — nothing to remove${reset}`);
188
- }
169
+ const { skillsDir } = target;
170
+
171
+ const names = ourSkillNames();
172
+ let removed = 0;
173
+ for (const name of names) {
174
+ const dest = path.join(skillsDir, name);
175
+ if (fs.existsSync(dest)) {
176
+ removeDir(dest);
177
+ removed++;
189
178
  }
190
- } catch (e) {
191
- warn(`Could not update settings.json: ${e.message}`);
192
179
  }
193
180
 
181
+ log(`${green}✓${reset} Removed ${removed} skills from ${dim}${skillsDir}${reset}`);
182
+
183
+ // Clean up legacy pluginDirectories entry if present
184
+ const settingsPath = path.join(path.dirname(skillsDir), 'settings.json');
185
+ cleanLegacySettings(settingsPath, skillsDir);
186
+
194
187
  log();
195
188
  log(`${dim}Uninstall complete.${reset}`);
196
189
  log();
@@ -203,51 +196,35 @@ async function uninstall() {
203
196
  async function install() {
204
197
  log();
205
198
  log(`${bold}${cyan}skills-for-humanity${reset}`);
206
- log(`${dim}93 structured thinking tools for Claude Code${reset}`);
199
+ log(`${dim}131 structured thinking tools for Claude Code${reset}`);
207
200
  log();
208
201
 
209
202
  const target = await resolveTarget();
210
- const { pluginsDir, settingsPath } = target;
203
+ const { skillsDir } = target;
211
204
 
212
- // 1. Copy skills
213
- const isUpdate = fs.existsSync(pluginsDir);
214
- log(`${isUpdate ? 'Updating' : 'Installing'} skills to ${yellow}${pluginsDir}${reset}…`);
205
+ // Copy each skill into the skills directory
206
+ const names = ourSkillNames();
207
+ const isUpdate = names.some((n) => fs.existsSync(path.join(skillsDir, n)));
208
+ log(`${isUpdate ? 'Updating' : 'Installing'} ${names.length} skills to ${yellow}${skillsDir}${reset}…`);
215
209
 
216
210
  try {
217
- copyDir(SKILLS_SRC, pluginsDir);
218
- log(`${green}✓${reset} Skills ${isUpdate ? 'updated' : 'installed'} (${countDirs(pluginsDir)} skills)`);
211
+ for (const name of names) {
212
+ copyDir(path.join(SKILLS_SRC, name), path.join(skillsDir, name));
213
+ }
214
+ log(`${green}✓${reset} ${names.length} skills ${isUpdate ? 'updated' : 'installed'}`);
219
215
  } catch (e) {
220
216
  err(`Could not copy skills: ${e.message}`);
221
217
  process.exit(1);
222
218
  }
223
219
 
224
- // 2. Register in settings.json
225
- try {
226
- const settings = readSettings(settingsPath);
227
- if (!Array.isArray(settings.pluginDirectories)) settings.pluginDirectories = [];
228
-
229
- const already = settings.pluginDirectories.some(
230
- (d) => path.resolve(d) === path.resolve(pluginsDir)
231
- );
232
-
233
- if (!already) {
234
- settings.pluginDirectories.push(pluginsDir);
235
- writeSettings(settingsPath, settings);
236
- log(`${green}✓${reset} Registered in ${dim}${settingsPath}${reset}`);
237
- } else {
238
- log(`${dim}→ Already registered in ${settingsPath}${reset}`);
239
- }
240
- } catch (e) {
241
- warn(`Could not update settings.json: ${e.message}`);
242
- log();
243
- log(`Add this to ${yellow}${settingsPath}${reset} manually:`);
244
- log(` ${dim}{ "pluginDirectories": ["${pluginsDir}"] }${reset}`);
245
- }
220
+ // Clean up legacy pluginDirectories entry if present
221
+ const settingsPath = path.join(path.dirname(skillsDir), 'settings.json');
222
+ cleanLegacySettings(settingsPath, skillsDir);
246
223
 
247
- // 3. Done
224
+ // Done
248
225
  log();
249
226
  log(`${bold}Done.${reset} Restart Claude Code, then:`);
250
- log(` ${cyan}/human${reset} ${dim}— route to the right skill from all 93${reset}`);
227
+ log(` ${cyan}/human${reset} ${dim}— route to the right skill from all 131${reset}`);
251
228
  log(` ${cyan}/ethics${reset} ${dim}— ethical analysis${reset}`);
252
229
  log(` ${cyan}/logic${reset} ${dim}— validate and pressure-test reasoning${reset}`);
253
230
  log(` ${cyan}/creativity${reset} ${dim}— de Bono suite + brainstorm${reset}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@human-avatar/skills-for-humanity",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "93 structured thinking tools for Claude Code — logic, ethics, creativity, decision-making, systems thinking, and more.",
5
5
  "keywords": [
6
6
  "claude-code",