@ikyyofc/gemini-cli 3.0.5 → 3.0.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/skills.js +49 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikyyofc/gemini-cli",
3
- "version": "3.0.5",
3
+ "version": "3.0.6",
4
4
  "description": "AI Agent CLI — native function calling · GEMINI.md context · extensions",
5
5
  "type": "module",
6
6
  "bin": { "gemini": "./index.js" },
package/src/skills.js CHANGED
@@ -110,40 +110,45 @@ function consolidate(cwd, beforeSnapshot) {
110
110
  }
111
111
 
112
112
  // ─────────────────────────────────────────────────────────────────
113
- // Install
114
- // 1. Snapshot existing SKILL.md paths
115
- // 2. npx skills add (wherever it installs)
116
- // 3. Find new SKILL.md files and copy ALL → ~/.agents/
113
+ // Install — npx skills puts files directly into ~/.agents/skills/
114
+ // No post-copy needed; just run npx and report what's new
117
115
  // ─────────────────────────────────────────────────────────────────
118
116
  export async function installSkill(rawSource, opts = {}) {
119
117
  const { skill: explicitSkill = null, all = false } = opts;
120
118
  const { source, skill: parsedSkill } = parseSource(rawSource);
121
119
  const skillName = explicitSkill ?? parsedSkill;
122
120
 
123
- const cwd = process.cwd();
124
- const before = new Set(
125
- KNOWN_AGENT_DIRS.flatMap(rel => scanForSkillMds(path.join(cwd, rel), 3))
126
- );
121
+ // Snapshot before
122
+ const before = new Set(loadSkills().map(s => s.slug));
127
123
 
128
124
  const parts = ["add", source, "-y"];
129
125
  if (skillName) parts.push(`--skill "${skillName}"`);
130
126
  if (all) parts.push("--skill '*'");
131
127
 
132
128
  const { stdout, stderr } = await npxSkills(parts.join(" "));
133
- const installed = consolidate(cwd, before);
134
129
 
135
- return { output: stdout || stderr, installed };
130
+ // Report what was newly installed
131
+ const after = loadSkills().map(s => s.slug);
132
+ const newSlugs = after.filter(s => !before.has(s));
133
+
134
+ return { output: stdout || stderr, installed: newSlugs };
136
135
  }
137
136
 
138
137
  // ─────────────────────────────────────────────────────────────────
139
- // Remove — delete from ~/.agents/ then best-effort npx remove
138
+ // Remove — checks both ~/.agents/<slug>/ and ~/.agents/skills/<slug>/
140
139
  // ─────────────────────────────────────────────────────────────────
141
140
  export async function removeSkillNpx(slug) {
142
- const skillDir = path.join(AGENTS_DIR, slug);
143
- if (!fs.existsSync(skillDir)) throw new Error(`"${slug}" not found in ~/.agents/`);
144
- fs.rmSync(skillDir, { recursive: true, force: true });
141
+ const candidates = [
142
+ path.join(AGENTS_DIR, slug),
143
+ path.join(AGENTS_DIR, "skills", slug),
144
+ ];
145
+ const found = candidates.filter(d => fs.existsSync(d));
146
+ if (!found.length) throw new Error(`"${slug}" not found in ~/.agents/`);
147
+
148
+ found.forEach(d => fs.rmSync(d, { recursive: true, force: true }));
145
149
  try { await npxSkills(`remove ${slug} -y`); } catch {}
146
- return { output: `Removed ~/.agents/${slug}` };
150
+
151
+ return { output: `Removed: ${found.join(", ")}` };
147
152
  }
148
153
 
149
154
  // ─────────────────────────────────────────────────────────────────
@@ -167,26 +172,38 @@ export async function initSkill(name = "") {
167
172
  }
168
173
 
169
174
  // ─────────────────────────────────────────────────────────────────
170
- // Load all skills from ~/.agents/ for agent context injection
175
+ // Load all skills scans both:
176
+ // ~/.agents/<slug>/SKILL.md (manual / flat)
177
+ // ~/.agents/skills/<slug>/SKILL.md (npx skills default)
171
178
  // ─────────────────────────────────────────────────────────────────
172
179
  export function loadSkills() {
173
180
  const skills = [];
174
- if (!fs.existsSync(AGENTS_DIR)) return skills;
175
-
176
- for (const entry of fs.readdirSync(AGENTS_DIR, { withFileTypes: true })) {
177
- if (!entry.isDirectory()) continue;
178
- const skillMd = path.join(AGENTS_DIR, entry.name, "SKILL.md");
179
- if (!fs.existsSync(skillMd)) continue;
180
-
181
- const content = fs.readFileSync(skillMd, "utf8");
182
- const nameMatch = content.match(/^#\s+(.+)$/m);
183
- skills.push({
184
- name: nameMatch?.[1]?.trim() ?? entry.name,
185
- slug: entry.name,
186
- content,
187
- path: path.join(AGENTS_DIR, entry.name),
188
- });
189
- }
181
+ const seen = new Set();
182
+
183
+ const scanBase = (baseDir) => {
184
+ if (!fs.existsSync(baseDir)) return;
185
+ for (const entry of fs.readdirSync(baseDir, { withFileTypes: true })) {
186
+ if (!entry.isDirectory()) continue;
187
+ if (seen.has(entry.name)) continue;
188
+ const skillMd = path.join(baseDir, entry.name, "SKILL.md");
189
+ if (!fs.existsSync(skillMd)) continue;
190
+ seen.add(entry.name);
191
+ const content = fs.readFileSync(skillMd, "utf8");
192
+ const nameMatch = content.match(/^#\s+(.+)$/m);
193
+ skills.push({
194
+ name: nameMatch?.[1]?.trim() ?? entry.name,
195
+ slug: entry.name,
196
+ content,
197
+ path: path.join(baseDir, entry.name),
198
+ });
199
+ }
200
+ };
201
+
202
+ // Flat: ~/.agents/<slug>/SKILL.md
203
+ scanBase(AGENTS_DIR);
204
+ // Nested: ~/.agents/skills/<slug>/SKILL.md (npx skills default)
205
+ scanBase(path.join(AGENTS_DIR, "skills"));
206
+
190
207
  return skills;
191
208
  }
192
209