@kurokeita/add-skill 1.11.0 → 1.13.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.
- package/README.md +1 -0
- package/dist/bin/cli.js +139 -39
- package/dist/skills/git-convention/SKILL.md +112 -0
- package/dist/skills/git-convention/examples/commit-messages.txt +34 -0
- package/dist/skills/git-convention/examples/pr-description-template.md +40 -0
- package/dist/skills/git-convention/references/branching-workflows.md +63 -0
- package/dist/skills/git-convention/references/conventional-commits.md +85 -0
- package/dist/skills/git-convention/references/pr-best-practices.md +66 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,6 +87,7 @@ pnpm dev import https://github.com/owner/repo/tree/main/skills/skill-name
|
|
|
87
87
|
| Platform | Agents Path | Skills Path | Workflows Path |
|
|
88
88
|
| :--- | :--- | :--- | :--- |
|
|
89
89
|
| Antigravity | *Not Supported* | `~/.gemini/antigravity/global_skills` | `~/.gemini/antigravity/global_workflows` |
|
|
90
|
+
| Claude Code | `~/.claude/agents` | `~/.claude/skills` | `~/.claude/skills` |
|
|
90
91
|
| Codex | `~/.codex/skills` | `~/.codex/skills` | `~/.codex/skills` |
|
|
91
92
|
| Gemini CLI | `~/.gemini/agents` | `~/.gemini/skills` | `~/.gemini/commands` |
|
|
92
93
|
| GitHub Copilot | `~/.copilot/agents` | `~/.copilot/skills` | `~/.copilot/prompts` |
|
package/dist/bin/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import pc5 from "picocolors";
|
|
|
7
7
|
|
|
8
8
|
// src/commands/add.ts
|
|
9
9
|
import os3 from "node:os";
|
|
10
|
-
import
|
|
10
|
+
import path6 from "node:path";
|
|
11
11
|
import {
|
|
12
12
|
cancel,
|
|
13
13
|
confirm,
|
|
@@ -119,6 +119,7 @@ function resolveProjectRoot(moduleDir) {
|
|
|
119
119
|
var PROJECT_ROOT = resolveProjectRoot(__dirname);
|
|
120
120
|
var PLATFORM_LABELS = {
|
|
121
121
|
antigravity: "Antigravity",
|
|
122
|
+
"claude-code": "Claude Code",
|
|
122
123
|
codex: "Codex",
|
|
123
124
|
gemini: "Gemini CLI",
|
|
124
125
|
copilot: "GitHub Copilot",
|
|
@@ -126,18 +127,21 @@ var PLATFORM_LABELS = {
|
|
|
126
127
|
};
|
|
127
128
|
var PLATFORM_PATHS_SKILLS = {
|
|
128
129
|
antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_skills"),
|
|
130
|
+
"claude-code": path2.join(os2.homedir(), ".claude/skills"),
|
|
129
131
|
codex: path2.join(os2.homedir(), ".codex/skills"),
|
|
130
132
|
copilot: path2.join(os2.homedir(), ".copilot/skills"),
|
|
131
133
|
gemini: path2.join(os2.homedir(), ".gemini/skills"),
|
|
132
134
|
windsurf: path2.join(os2.homedir(), ".codeium/windsurf/skills")
|
|
133
135
|
};
|
|
134
136
|
var PLATFORM_PATHS_AGENTS = {
|
|
137
|
+
"claude-code": path2.join(os2.homedir(), ".claude/agents"),
|
|
135
138
|
codex: path2.join(os2.homedir(), ".codex/skills"),
|
|
136
139
|
copilot: path2.join(os2.homedir(), ".copilot/agents"),
|
|
137
140
|
gemini: path2.join(os2.homedir(), ".gemini/agents")
|
|
138
141
|
};
|
|
139
142
|
var PLATFORM_PATHS_WORKFLOWS = {
|
|
140
143
|
antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_workflows"),
|
|
144
|
+
"claude-code": path2.join(os2.homedir(), ".claude/skills"),
|
|
141
145
|
codex: path2.join(os2.homedir(), ".codex/skills"),
|
|
142
146
|
copilot: path2.join(os2.homedir(), ".copilot/prompts"),
|
|
143
147
|
gemini: path2.join(os2.homedir(), ".gemini/commands"),
|
|
@@ -170,11 +174,106 @@ var AntigravityHandler = class {
|
|
|
170
174
|
}
|
|
171
175
|
};
|
|
172
176
|
|
|
173
|
-
// src/utils/platforms/
|
|
177
|
+
// src/utils/platforms/claude-code.ts
|
|
174
178
|
import path3 from "node:path";
|
|
175
|
-
import fs3 from "fs-extra";
|
|
176
179
|
import yaml from "js-yaml";
|
|
177
180
|
var frontmatterRegex = /^---\n([\s\S]*?)\n---/;
|
|
181
|
+
var CLAUDE_CODE_TOOLS = [
|
|
182
|
+
"Read",
|
|
183
|
+
"Edit",
|
|
184
|
+
"Write",
|
|
185
|
+
"Bash",
|
|
186
|
+
"Glob",
|
|
187
|
+
"Grep",
|
|
188
|
+
"WebFetch",
|
|
189
|
+
"WebSearch"
|
|
190
|
+
];
|
|
191
|
+
var ClaudeCodeHandler = class {
|
|
192
|
+
platform = "claude-code";
|
|
193
|
+
getTargetFileName(itemName, type) {
|
|
194
|
+
if (type === "agent") {
|
|
195
|
+
const name = itemName.replace(/\.md$/, "");
|
|
196
|
+
return path3.join(name, `${name}.md`);
|
|
197
|
+
}
|
|
198
|
+
if (type === "workflow") {
|
|
199
|
+
const name = itemName.replace(/\.md$/, "");
|
|
200
|
+
return path3.join(name, "SKILL.md");
|
|
201
|
+
}
|
|
202
|
+
return itemName;
|
|
203
|
+
}
|
|
204
|
+
transform(content, type, itemName) {
|
|
205
|
+
if (type === "skill") return content;
|
|
206
|
+
if (type === "agent") {
|
|
207
|
+
return this.transformAgent(content, itemName);
|
|
208
|
+
}
|
|
209
|
+
if (type === "workflow") {
|
|
210
|
+
return this.transformWorkflow(content, itemName);
|
|
211
|
+
}
|
|
212
|
+
return content;
|
|
213
|
+
}
|
|
214
|
+
transformAgent(content, itemName) {
|
|
215
|
+
const match = content.match(frontmatterRegex);
|
|
216
|
+
let frontmatter = {
|
|
217
|
+
name: itemName.replace(/\.md$/, ""),
|
|
218
|
+
description: "",
|
|
219
|
+
tools: CLAUDE_CODE_TOOLS
|
|
220
|
+
};
|
|
221
|
+
let body = content;
|
|
222
|
+
if (match) {
|
|
223
|
+
try {
|
|
224
|
+
const parsed = yaml.load(match[1]);
|
|
225
|
+
frontmatter = { ...frontmatter, ...parsed };
|
|
226
|
+
frontmatter.tools = CLAUDE_CODE_TOOLS;
|
|
227
|
+
delete frontmatter.target;
|
|
228
|
+
body = content.replace(frontmatterRegex, "").trim();
|
|
229
|
+
} catch (_) {
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const yamlStr = yaml.dump(frontmatter);
|
|
233
|
+
return `---
|
|
234
|
+
${yamlStr}---
|
|
235
|
+
|
|
236
|
+
${body}`;
|
|
237
|
+
}
|
|
238
|
+
transformWorkflow(content, itemName) {
|
|
239
|
+
const name = itemName.replace(/\.md$/, "");
|
|
240
|
+
const match = content.match(frontmatterRegex);
|
|
241
|
+
let description = "";
|
|
242
|
+
let body = content.trim();
|
|
243
|
+
if (match) {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = yaml.load(match[1]);
|
|
246
|
+
if (typeof parsed.description === "string" && parsed.description.trim()) {
|
|
247
|
+
description = parsed.description.trim();
|
|
248
|
+
}
|
|
249
|
+
if (typeof parsed.name === "string" && parsed.name.trim()) {
|
|
250
|
+
}
|
|
251
|
+
} catch (_) {
|
|
252
|
+
}
|
|
253
|
+
body = content.replace(frontmatterRegex, "").trim();
|
|
254
|
+
}
|
|
255
|
+
if (!description) {
|
|
256
|
+
const titleMatch = body.match(/^#\s+(.+)$/m);
|
|
257
|
+
const title = titleMatch?.[1]?.trim() || name;
|
|
258
|
+
description = `Workflow: ${title}`;
|
|
259
|
+
}
|
|
260
|
+
const frontmatter = yaml.dump({
|
|
261
|
+
name,
|
|
262
|
+
description,
|
|
263
|
+
"user-invocable": true
|
|
264
|
+
});
|
|
265
|
+
return `---
|
|
266
|
+
${frontmatter}---
|
|
267
|
+
|
|
268
|
+
${body}`;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// src/utils/platforms/codex.ts
|
|
273
|
+
import path4 from "node:path";
|
|
274
|
+
import fs3 from "fs-extra";
|
|
275
|
+
import yaml2 from "js-yaml";
|
|
276
|
+
var frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
|
|
178
277
|
var CODEX_TYPE_FIELD = "x-ai-agents-type";
|
|
179
278
|
function extractTitle(body) {
|
|
180
279
|
const match = body.match(/^#\s+(.+)$/m);
|
|
@@ -193,7 +292,7 @@ function buildDescription(type, itemName, title) {
|
|
|
193
292
|
function toYamlFrontmatter(name, description, extraFields = {}) {
|
|
194
293
|
const normalizedName = name.replace(/\n+/g, " ").trim();
|
|
195
294
|
const normalizedDescription = description.replace(/\n+/g, " ").trim();
|
|
196
|
-
return
|
|
295
|
+
return yaml2.dump(
|
|
197
296
|
{
|
|
198
297
|
name: normalizedName,
|
|
199
298
|
description: normalizedDescription,
|
|
@@ -203,10 +302,10 @@ function toYamlFrontmatter(name, description, extraFields = {}) {
|
|
|
203
302
|
).trimEnd();
|
|
204
303
|
}
|
|
205
304
|
function parseCodexType(content) {
|
|
206
|
-
const match = content.match(
|
|
305
|
+
const match = content.match(frontmatterRegex2);
|
|
207
306
|
if (!match) return "skill";
|
|
208
307
|
try {
|
|
209
|
-
const parsed =
|
|
308
|
+
const parsed = yaml2.load(match[1]);
|
|
210
309
|
if (parsed && typeof parsed === "object") {
|
|
211
310
|
const type = parsed[CODEX_TYPE_FIELD];
|
|
212
311
|
if (type === "agent" || type === "workflow" || type === "skill") {
|
|
@@ -221,9 +320,9 @@ function parseCodexType(content) {
|
|
|
221
320
|
async function codexEntryMatchesType(basePath, entry, requestedType) {
|
|
222
321
|
let targetPath = null;
|
|
223
322
|
if (entry.isDirectory()) {
|
|
224
|
-
targetPath =
|
|
323
|
+
targetPath = path4.join(basePath, entry.name, "SKILL.md");
|
|
225
324
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
226
|
-
targetPath =
|
|
325
|
+
targetPath = path4.join(basePath, entry.name);
|
|
227
326
|
}
|
|
228
327
|
if (!targetPath) return false;
|
|
229
328
|
try {
|
|
@@ -237,7 +336,7 @@ var CodexHandler = class {
|
|
|
237
336
|
platform = "codex";
|
|
238
337
|
getTargetFileName(itemName, type) {
|
|
239
338
|
if (type === "agent" || type === "workflow") {
|
|
240
|
-
return
|
|
339
|
+
return path4.join(path4.parse(itemName).name, "SKILL.md");
|
|
241
340
|
}
|
|
242
341
|
return itemName;
|
|
243
342
|
}
|
|
@@ -247,11 +346,11 @@ var CodexHandler = class {
|
|
|
247
346
|
let name = itemName;
|
|
248
347
|
let description = "";
|
|
249
348
|
let body = content.trim();
|
|
250
|
-
const match = content.match(
|
|
349
|
+
const match = content.match(frontmatterRegex2);
|
|
251
350
|
if (match) {
|
|
252
|
-
body = content.replace(
|
|
351
|
+
body = content.replace(frontmatterRegex2, "").trim();
|
|
253
352
|
try {
|
|
254
|
-
const parsed =
|
|
353
|
+
const parsed = yaml2.load(match[1]);
|
|
255
354
|
if (parsed && typeof parsed === "object") {
|
|
256
355
|
const frontmatter = parsed;
|
|
257
356
|
if (typeof frontmatter.name === "string" && frontmatter.name.trim()) {
|
|
@@ -281,7 +380,7 @@ ${body}`;
|
|
|
281
380
|
};
|
|
282
381
|
|
|
283
382
|
// src/utils/platforms/copilot.ts
|
|
284
|
-
import
|
|
383
|
+
import yaml3 from "js-yaml";
|
|
285
384
|
var CopilotHandler = class {
|
|
286
385
|
platform = "copilot";
|
|
287
386
|
getTargetFileName(itemName, type) {
|
|
@@ -292,8 +391,8 @@ var CopilotHandler = class {
|
|
|
292
391
|
}
|
|
293
392
|
transform(content, type, itemName) {
|
|
294
393
|
if (type !== "agent") return content;
|
|
295
|
-
const
|
|
296
|
-
const match = content.match(
|
|
394
|
+
const frontmatterRegex3 = /^---\n([\s\S]*?)\n---/;
|
|
395
|
+
const match = content.match(frontmatterRegex3);
|
|
297
396
|
let frontmatter = {
|
|
298
397
|
name: itemName,
|
|
299
398
|
description: "",
|
|
@@ -303,7 +402,7 @@ var CopilotHandler = class {
|
|
|
303
402
|
let body = content;
|
|
304
403
|
if (match) {
|
|
305
404
|
try {
|
|
306
|
-
const parsed =
|
|
405
|
+
const parsed = yaml3.load(match[1]);
|
|
307
406
|
frontmatter = { ...frontmatter, ...parsed };
|
|
308
407
|
frontmatter.target = "github-copilot";
|
|
309
408
|
frontmatter.tools = [
|
|
@@ -313,11 +412,11 @@ var CopilotHandler = class {
|
|
|
313
412
|
"grep_search",
|
|
314
413
|
"githubRepo"
|
|
315
414
|
];
|
|
316
|
-
body = content.replace(
|
|
415
|
+
body = content.replace(frontmatterRegex3, "").trim();
|
|
317
416
|
} catch (_) {
|
|
318
417
|
}
|
|
319
418
|
}
|
|
320
|
-
const yamlStr =
|
|
419
|
+
const yamlStr = yaml3.dump(frontmatter);
|
|
321
420
|
return `---
|
|
322
421
|
${yamlStr}---
|
|
323
422
|
|
|
@@ -339,7 +438,7 @@ var DefaultHandler = class {
|
|
|
339
438
|
};
|
|
340
439
|
|
|
341
440
|
// src/utils/platforms/gemini.ts
|
|
342
|
-
import
|
|
441
|
+
import yaml4 from "js-yaml";
|
|
343
442
|
|
|
344
443
|
// src/utils/toml.ts
|
|
345
444
|
function convertToGeminiCommandTOML(markdownContent) {
|
|
@@ -382,8 +481,8 @@ var GeminiHandler = class {
|
|
|
382
481
|
return convertToGeminiCommandTOML(content);
|
|
383
482
|
}
|
|
384
483
|
if (type === "agent") {
|
|
385
|
-
const
|
|
386
|
-
const match = content.match(
|
|
484
|
+
const frontmatterRegex3 = /^---\n([\s\S]*?)\n---/;
|
|
485
|
+
const match = content.match(frontmatterRegex3);
|
|
387
486
|
let frontmatter = {
|
|
388
487
|
name: itemName,
|
|
389
488
|
description: "",
|
|
@@ -405,7 +504,7 @@ var GeminiHandler = class {
|
|
|
405
504
|
let body = content;
|
|
406
505
|
if (match) {
|
|
407
506
|
try {
|
|
408
|
-
const parsed =
|
|
507
|
+
const parsed = yaml4.load(match[1]);
|
|
409
508
|
frontmatter = { ...frontmatter, ...parsed };
|
|
410
509
|
frontmatter.tools = [
|
|
411
510
|
"list_directory",
|
|
@@ -422,11 +521,11 @@ var GeminiHandler = class {
|
|
|
422
521
|
"activate_skill"
|
|
423
522
|
];
|
|
424
523
|
delete frontmatter.skills;
|
|
425
|
-
body = content.replace(
|
|
524
|
+
body = content.replace(frontmatterRegex3, "").trim();
|
|
426
525
|
} catch (_) {
|
|
427
526
|
}
|
|
428
527
|
}
|
|
429
|
-
const yamlStr =
|
|
528
|
+
const yamlStr = yaml4.dump(frontmatter);
|
|
430
529
|
return `---
|
|
431
530
|
${yamlStr}---
|
|
432
531
|
|
|
@@ -437,12 +536,12 @@ ${body}`;
|
|
|
437
536
|
};
|
|
438
537
|
|
|
439
538
|
// src/utils/platforms/windsurf.ts
|
|
440
|
-
import
|
|
539
|
+
import path5 from "node:path";
|
|
441
540
|
var WindsurfHandler = class {
|
|
442
541
|
platform = "windsurf";
|
|
443
542
|
getTargetFileName(itemName, type) {
|
|
444
543
|
if (type === "agent") {
|
|
445
|
-
return
|
|
544
|
+
return path5.join(path5.parse(itemName).name, "AGENTS.md");
|
|
446
545
|
}
|
|
447
546
|
return itemName;
|
|
448
547
|
}
|
|
@@ -457,6 +556,7 @@ function registerHandler(handler) {
|
|
|
457
556
|
handlers.set(handler.platform, handler);
|
|
458
557
|
}
|
|
459
558
|
registerHandler(new AntigravityHandler());
|
|
559
|
+
registerHandler(new ClaudeCodeHandler());
|
|
460
560
|
registerHandler(new CodexHandler());
|
|
461
561
|
registerHandler(new CopilotHandler());
|
|
462
562
|
registerHandler(new GeminiHandler());
|
|
@@ -475,7 +575,7 @@ function getPlatformOptions(type) {
|
|
|
475
575
|
}));
|
|
476
576
|
}
|
|
477
577
|
async function installItem(itemName, overwrite, sourcePath, targetBaseDir) {
|
|
478
|
-
const targetPath =
|
|
578
|
+
const targetPath = path6.join(targetBaseDir, itemName);
|
|
479
579
|
if (!await fs4.pathExists(sourcePath)) {
|
|
480
580
|
throw new Error(`Item '${itemName}' not found at ${sourcePath}`);
|
|
481
581
|
}
|
|
@@ -584,7 +684,7 @@ async function add(type, url, options) {
|
|
|
584
684
|
const handler = getHandler(platform);
|
|
585
685
|
for (const item of selectedItems) {
|
|
586
686
|
const targetItemName = handler.getTargetFileName(item, normalizedType);
|
|
587
|
-
const targetPath =
|
|
687
|
+
const targetPath = path6.join(targetBase, targetItemName);
|
|
588
688
|
if (await fs4.pathExists(targetPath)) {
|
|
589
689
|
existingItems.push({ item, platform });
|
|
590
690
|
}
|
|
@@ -627,14 +727,14 @@ async function add(type, url, options) {
|
|
|
627
727
|
try {
|
|
628
728
|
let currentSourcePath;
|
|
629
729
|
if (url && tempDir) {
|
|
630
|
-
const potentialFile =
|
|
730
|
+
const potentialFile = path6.join(tempDir, item);
|
|
631
731
|
if (await fs4.pathExists(potentialFile) && (await fs4.stat(potentialFile)).isFile()) {
|
|
632
732
|
currentSourcePath = potentialFile;
|
|
633
733
|
} else {
|
|
634
734
|
currentSourcePath = tempDir;
|
|
635
735
|
}
|
|
636
736
|
} else {
|
|
637
|
-
const src =
|
|
737
|
+
const src = path6.join(TYPE_DIRS[normalizedType], item);
|
|
638
738
|
if ((await fs4.stat(src)).isFile()) {
|
|
639
739
|
currentSourcePath = src;
|
|
640
740
|
} else {
|
|
@@ -647,7 +747,7 @@ async function add(type, url, options) {
|
|
|
647
747
|
normalizedType
|
|
648
748
|
);
|
|
649
749
|
if ((normalizedType === "agent" || normalizedType === "workflow") && currentSourcePath.endsWith(".md")) {
|
|
650
|
-
const targetPath =
|
|
750
|
+
const targetPath = path6.join(targetBase, targetItemName);
|
|
651
751
|
if (!overwrite && await fs4.pathExists(targetPath)) {
|
|
652
752
|
skippedCount++;
|
|
653
753
|
} else {
|
|
@@ -655,9 +755,9 @@ async function add(type, url, options) {
|
|
|
655
755
|
content = handler.transform(
|
|
656
756
|
content,
|
|
657
757
|
normalizedType,
|
|
658
|
-
|
|
758
|
+
path6.parse(item).name
|
|
659
759
|
);
|
|
660
|
-
await fs4.ensureDir(
|
|
760
|
+
await fs4.ensureDir(path6.dirname(targetPath));
|
|
661
761
|
await fs4.writeFile(targetPath, content);
|
|
662
762
|
installedCount++;
|
|
663
763
|
}
|
|
@@ -715,7 +815,7 @@ async function add(type, url, options) {
|
|
|
715
815
|
}
|
|
716
816
|
|
|
717
817
|
// src/commands/import.ts
|
|
718
|
-
import
|
|
818
|
+
import path7 from "node:path";
|
|
719
819
|
import {
|
|
720
820
|
cancel as cancel2,
|
|
721
821
|
confirm as confirm2,
|
|
@@ -784,12 +884,12 @@ async function importItem(type, url, options) {
|
|
|
784
884
|
throw e;
|
|
785
885
|
}
|
|
786
886
|
const shouldFlatten = (normalizedType === "agent" || normalizedType === "workflow") && !isFile;
|
|
787
|
-
const targetPath = shouldFlatten ? targetBaseDir :
|
|
887
|
+
const targetPath = shouldFlatten ? targetBaseDir : path7.join(targetBaseDir, itemName);
|
|
788
888
|
if (shouldFlatten) {
|
|
789
889
|
const srcFiles = await fs5.readdir(tempDir);
|
|
790
890
|
const conflicts = [];
|
|
791
891
|
for (const file of srcFiles) {
|
|
792
|
-
if (await fs5.pathExists(
|
|
892
|
+
if (await fs5.pathExists(path7.join(targetBaseDir, file))) {
|
|
793
893
|
conflicts.push(file);
|
|
794
894
|
}
|
|
795
895
|
}
|
|
@@ -820,7 +920,7 @@ async function importItem(type, url, options) {
|
|
|
820
920
|
s.start(`Importing ${itemName} to ${targetBaseDir}...`);
|
|
821
921
|
await fs5.ensureDir(targetBaseDir);
|
|
822
922
|
if (isFile) {
|
|
823
|
-
await fs5.copy(
|
|
923
|
+
await fs5.copy(path7.join(tempDir, itemName), targetPath, {
|
|
824
924
|
overwrite: true
|
|
825
925
|
});
|
|
826
926
|
} else {
|
|
@@ -965,7 +1065,7 @@ async function list(type, options) {
|
|
|
965
1065
|
}
|
|
966
1066
|
|
|
967
1067
|
// src/commands/remove.ts
|
|
968
|
-
import
|
|
1068
|
+
import path8 from "node:path";
|
|
969
1069
|
import {
|
|
970
1070
|
confirm as confirm3,
|
|
971
1071
|
intro as intro4,
|
|
@@ -1079,7 +1179,7 @@ async function remove(type, options) {
|
|
|
1079
1179
|
const targetBase = targetPaths[platform];
|
|
1080
1180
|
if (!targetBase) continue;
|
|
1081
1181
|
for (const item of selectedItems) {
|
|
1082
|
-
const targetPath =
|
|
1182
|
+
const targetPath = path8.join(targetBase, item);
|
|
1083
1183
|
if (await fs7.pathExists(targetPath)) {
|
|
1084
1184
|
sDel.message(`Removing ${pc4.bold(item)} from ${pc4.cyan(platform)}...`);
|
|
1085
1185
|
try {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-convention
|
|
3
|
+
description: This skill should be used when the user asks to "create a branch", "commit changes", "create a pull request", "manage branches", or "follow conventional commits". Provides guidelines for version control workflows and commit message formatting.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Git Convention
|
|
8
|
+
|
|
9
|
+
Guide for managing version control workflows, including branching strategies, commit message formatting following Conventional Commits, and pull request management.
|
|
10
|
+
|
|
11
|
+
## When to Use This Skill
|
|
12
|
+
|
|
13
|
+
- Creating new feature, bugfix, or maintenance branches
|
|
14
|
+
- Formatting commit messages to follow project standards
|
|
15
|
+
- Preparing and creating pull requests
|
|
16
|
+
- Managing branch lifecycle and cleanup
|
|
17
|
+
- Ensuring consistency across the repository's history
|
|
18
|
+
|
|
19
|
+
## Branching Strategy
|
|
20
|
+
|
|
21
|
+
Follow a consistent naming convention for branches to ensure clarity and organization.
|
|
22
|
+
|
|
23
|
+
### Branch Naming Convention
|
|
24
|
+
|
|
25
|
+
Use a prefix followed by a descriptive name in kebab-case:
|
|
26
|
+
|
|
27
|
+
- `feature/` - New features or significant functional additions (e.g., `feature/user-authentication`)
|
|
28
|
+
- `fix/` - Bug fixes and patches (e.g., `fix/login-error`)
|
|
29
|
+
- `refactor/` - Code restructuring without changing behavior (e.g., `refactor/api-client`)
|
|
30
|
+
- `docs/` - Documentation updates (e.g., `docs/update-readme`)
|
|
31
|
+
- `chore/` - Maintenance tasks, dependency updates, or internal tooling (e.g., `chore/update-deps`)
|
|
32
|
+
- `test/` - Adding or modifying tests (e.g., `test/unit-tests-auth`)
|
|
33
|
+
|
|
34
|
+
### Workflow
|
|
35
|
+
|
|
36
|
+
1. Start from the main integration branch (e.g., `main` or `develop`).
|
|
37
|
+
2. Ensure the local branch is up-to-date: `git pull origin main`.
|
|
38
|
+
3. Create the new branch: `git checkout -b <prefix>/<description>`.
|
|
39
|
+
|
|
40
|
+
## Conventional Commits
|
|
41
|
+
|
|
42
|
+
Format commit messages according to the [Conventional Commits](https://www.conventionalcommits.org/) specification to enable automated changelog generation and easier history browsing.
|
|
43
|
+
|
|
44
|
+
### Structure
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
<type>(<scope>): <description>
|
|
48
|
+
|
|
49
|
+
[optional body]
|
|
50
|
+
|
|
51
|
+
[optional footer(s)]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Types
|
|
55
|
+
|
|
56
|
+
- `feat`: A new feature
|
|
57
|
+
- `fix`: A bug fix
|
|
58
|
+
- `docs`: Documentation only changes
|
|
59
|
+
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
|
|
60
|
+
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
|
61
|
+
- `perf`: A code change that improves performance
|
|
62
|
+
- `test`: Adding missing tests or correcting existing tests
|
|
63
|
+
- `build`: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
|
64
|
+
- `ci`: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
|
|
65
|
+
- `chore`: Other changes that don't modify src or test files
|
|
66
|
+
- `revert`: Reverts a previous commit
|
|
67
|
+
|
|
68
|
+
### Guidelines
|
|
69
|
+
|
|
70
|
+
- **Description**: Use the imperative, present tense (e.g., "add", not "added" or "adds").
|
|
71
|
+
- **Case**: The description should be in lower-case or sentence-case.
|
|
72
|
+
- **Scope**: Use a scope to provide additional contextual information (e.g., `feat(auth): add login validation`).
|
|
73
|
+
- **Body**: Use the body to explain the "what" and "why" of the change, not the "how".
|
|
74
|
+
- **Footer**: Use the footer to reference issues (e.g., `Closes #123`) or breaking changes.
|
|
75
|
+
|
|
76
|
+
## Pull Request Management
|
|
77
|
+
|
|
78
|
+
Create clear and informative pull requests to facilitate effective code review and collaboration.
|
|
79
|
+
|
|
80
|
+
### PR Creation Process
|
|
81
|
+
|
|
82
|
+
1. **Push your branch**: `git push origin <branch-name>`.
|
|
83
|
+
2. **Open the PR**: Use the GitHub CLI or web interface.
|
|
84
|
+
3. **Title**: Use the Conventional Commits format for the title (e.g., `feat(ui): add dashboard widgets`).
|
|
85
|
+
4. **Description**: Use a template (if available) to describe:
|
|
86
|
+
- What changes were made.
|
|
87
|
+
- Why they were made.
|
|
88
|
+
- How they were tested.
|
|
89
|
+
- Any breaking changes or new dependencies.
|
|
90
|
+
|
|
91
|
+
### Best Practices
|
|
92
|
+
|
|
93
|
+
- **Keep it focused**: One PR per logical change. Avoid "mega-PRs".
|
|
94
|
+
- **Self-review**: Review your own changes before asking others.
|
|
95
|
+
- **Link issues**: Use keywords like `Fixes #123` or `Closes #123` in the description.
|
|
96
|
+
- **Update regularly**: Rebase or merge from the main branch if the PR becomes stale.
|
|
97
|
+
|
|
98
|
+
## Additional Resources
|
|
99
|
+
|
|
100
|
+
### Reference Files
|
|
101
|
+
|
|
102
|
+
For detailed patterns and advanced git workflows, consult:
|
|
103
|
+
|
|
104
|
+
- **`references/conventional-commits.md`** - Detailed Conventional Commits specification.
|
|
105
|
+
- **`references/branching-workflows.md`** - Advanced branching and merging strategies.
|
|
106
|
+
|
|
107
|
+
### Example Files
|
|
108
|
+
|
|
109
|
+
Working examples in `examples/`:
|
|
110
|
+
|
|
111
|
+
- **`commit-messages.txt`** - Examples of well-formatted commit messages.
|
|
112
|
+
- **`pr-description-template.md`** - A standard PR description template.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Example Commit Messages
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
- `feat(ui): add progress bar component`
|
|
5
|
+
- `feat(auth): implement oauth2 login with google`
|
|
6
|
+
- `feat!: change default api version to v2`
|
|
7
|
+
|
|
8
|
+
## Bug Fixes
|
|
9
|
+
- `fix(parser): handle empty input string gracefully`
|
|
10
|
+
- `fix: resolve race condition in database connection pool`
|
|
11
|
+
- `fix(styles): fix padding issues on mobile devices`
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
- `docs: update readme with installation instructions`
|
|
15
|
+
- `docs(api): document the new /user/profile endpoint`
|
|
16
|
+
- `docs: add contributing guide`
|
|
17
|
+
|
|
18
|
+
## Refactoring
|
|
19
|
+
- `refactor(core): simplify the request handling logic`
|
|
20
|
+
- `refactor: move utility functions to a separate module`
|
|
21
|
+
- `refactor(tests): reduce duplication in integration tests`
|
|
22
|
+
|
|
23
|
+
## Performance
|
|
24
|
+
- `perf(image): optimize image loading speed using lazy-loading`
|
|
25
|
+
- `perf: add caching layer for frequently accessed data`
|
|
26
|
+
|
|
27
|
+
## Tests
|
|
28
|
+
- `test(auth): add unit tests for jwt validation`
|
|
29
|
+
- `test: increase coverage for the math module`
|
|
30
|
+
|
|
31
|
+
## Chore
|
|
32
|
+
- `chore: update dependencies`
|
|
33
|
+
- `chore(deps): bump vite from 4.0 to 5.0`
|
|
34
|
+
- `chore: remove unused log statements`
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
|
|
3
|
+
|
|
4
|
+
## Related Issue
|
|
5
|
+
<!-- Link to the issue this PR addresses (e.g., Fixes #123, Closes #456) -->
|
|
6
|
+
Fixes #
|
|
7
|
+
|
|
8
|
+
## Type of Change
|
|
9
|
+
<!-- Please delete options that are not relevant -->
|
|
10
|
+
- [ ] Bug fix (non-breaking change which fixes an issue)
|
|
11
|
+
- [ ] New feature (non-breaking change which adds functionality)
|
|
12
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
|
13
|
+
- [ ] Documentation update
|
|
14
|
+
- [ ] Refactor (code change that neither fixes a bug nor adds a feature)
|
|
15
|
+
|
|
16
|
+
## How did you test this change?
|
|
17
|
+
<!--
|
|
18
|
+
Please describe the tests that you ran to verify your changes.
|
|
19
|
+
Provide instructions so we can reproduce.
|
|
20
|
+
Please also list any relevant details for your test configuration.
|
|
21
|
+
-->
|
|
22
|
+
- [ ] Test Case A: ...
|
|
23
|
+
- [ ] Test Case B: ...
|
|
24
|
+
|
|
25
|
+
### Screenshots (if applicable)
|
|
26
|
+
<!-- Add images to show visual changes -->
|
|
27
|
+
|
|
28
|
+
## Checklist
|
|
29
|
+
|
|
30
|
+
- [ ] I have read the [CONTRIBUTING](CONTRIBUTING.md) document.
|
|
31
|
+
- [ ] My code follows the code style of this project.
|
|
32
|
+
- [ ] I have performed a self-review of my own code.
|
|
33
|
+
- [ ] I have commented my code, particularly in hard-to-understand areas.
|
|
34
|
+
- [ ] I have made corresponding changes to the documentation.
|
|
35
|
+
- [ ] My changes generate no new warnings.
|
|
36
|
+
- [ ] I have added tests that prove my fix is effective or that my feature works.
|
|
37
|
+
- [ ] New and existing unit tests pass locally with my changes.
|
|
38
|
+
|
|
39
|
+
## Special notes for your reviewer
|
|
40
|
+
<!-- Any specific areas you want the reviewer to focus on? -->
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Advanced Branching and Merging Strategies
|
|
2
|
+
|
|
3
|
+
Choosing the right branching strategy is crucial for team collaboration and continuous delivery.
|
|
4
|
+
|
|
5
|
+
## Gitflow Workflow
|
|
6
|
+
|
|
7
|
+
Gitflow is a legacy Git workflow that was first published and made popular by Vincent Driessen. It's often used for projects that have a scheduled release cycle.
|
|
8
|
+
|
|
9
|
+
- `main` branch stores the official release history.
|
|
10
|
+
- `develop` branch serves as an integration branch for features.
|
|
11
|
+
- `feature/*` branches are used for developing new features.
|
|
12
|
+
- `release/*` branches support preparation of a new production release.
|
|
13
|
+
- `hotfix/*` branches are used to quickly patch production releases.
|
|
14
|
+
|
|
15
|
+
## GitHub Flow
|
|
16
|
+
|
|
17
|
+
GitHub Flow is a lightweight, branch-based workflow that supports teams and projects where deployments happen regularly.
|
|
18
|
+
|
|
19
|
+
- Anything in the `main` branch is deployable.
|
|
20
|
+
- To work on something new, create a descriptive branch off of `main`.
|
|
21
|
+
- Commit to that branch locally and regularly push your work to the same named branch on the server.
|
|
22
|
+
- When you need feedback or help, or you think the branch is ready for merging, open a pull request.
|
|
23
|
+
- After someone else has reviewed and signed off on the feature, you can merge it into `main`.
|
|
24
|
+
- Once it is merged and pushed to `main`, you can and should deploy immediately.
|
|
25
|
+
|
|
26
|
+
## Trunk-Based Development
|
|
27
|
+
|
|
28
|
+
A version control management strategy where developers merge small, frequent updates to a core “trunk” or main branch.
|
|
29
|
+
|
|
30
|
+
- High frequency of commits.
|
|
31
|
+
- Small PRs.
|
|
32
|
+
- Continuous Integration.
|
|
33
|
+
- Feature flags are often used to hide work-in-progress.
|
|
34
|
+
|
|
35
|
+
## Merging vs Rebasing
|
|
36
|
+
|
|
37
|
+
### Merging
|
|
38
|
+
|
|
39
|
+
`git merge` is a "non-destructive" operation. The existing branches are not changed in any way. This avoids all of the potential pitfalls of rebasing.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git checkout feature/abc
|
|
43
|
+
git merge main
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Rebasing
|
|
47
|
+
|
|
48
|
+
`git rebase` moves the entire feature branch to begin on the tip of the `main` branch, effectively incorporating all of the new commits in `main`. It re-writes the project history by creating brand new commits for each commit in the original branch.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git checkout feature/abc
|
|
52
|
+
git rebase main
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Golden Rule of Rebasing**: Never use it on public branches.
|
|
56
|
+
|
|
57
|
+
## Conflict Resolution
|
|
58
|
+
|
|
59
|
+
1. Identify the conflict: `git status` will show unmerged paths.
|
|
60
|
+
2. Open the files and look for `<<<<<<<`, `=======`, `>>>>>>>`.
|
|
61
|
+
3. Decide which changes to keep.
|
|
62
|
+
4. Stage the resolved files: `git add <file>`.
|
|
63
|
+
5. Complete the merge or rebase: `git commit` or `git rebase --continue`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Conventional Commits Specification
|
|
2
|
+
|
|
3
|
+
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of.
|
|
4
|
+
|
|
5
|
+
## The Specification
|
|
6
|
+
|
|
7
|
+
The commit message should be structured as follows:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<type>[optional scope]: <description>
|
|
11
|
+
|
|
12
|
+
[optional body]
|
|
13
|
+
|
|
14
|
+
[optional footer(s)]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Type
|
|
18
|
+
|
|
19
|
+
The type is a short string that describes the category of the change. Common types include:
|
|
20
|
+
|
|
21
|
+
- `feat`: (feature)
|
|
22
|
+
- `fix`: (bug fix)
|
|
23
|
+
- `docs`: (documentation)
|
|
24
|
+
- `style`: (formatting, missing semi-colons, etc; no code change)
|
|
25
|
+
- `refactor`: (refactoring production code)
|
|
26
|
+
- `test`: (adding missing tests, refactoring tests; no production code change)
|
|
27
|
+
- `chore`: (updating grunt tasks etc; no production code change)
|
|
28
|
+
|
|
29
|
+
### Scope
|
|
30
|
+
|
|
31
|
+
A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., `fix(parser):`
|
|
32
|
+
|
|
33
|
+
### Description
|
|
34
|
+
|
|
35
|
+
The description contains a succinct description of the change:
|
|
36
|
+
|
|
37
|
+
- use the imperative, present tense: "change" not "changed" nor "changes"
|
|
38
|
+
- don't capitalize the first letter
|
|
39
|
+
- no dot (.) at the end
|
|
40
|
+
|
|
41
|
+
### Body
|
|
42
|
+
|
|
43
|
+
A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.
|
|
44
|
+
|
|
45
|
+
### Footer
|
|
46
|
+
|
|
47
|
+
One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a `:<space>` or `<space>#` separator, followed by a string value (this is inspired by the git trailer convention).
|
|
48
|
+
|
|
49
|
+
### Breaking Changes
|
|
50
|
+
|
|
51
|
+
A breaking change MUST be indicated by an `!` after the type/scope, or as a footer entry starting with `BREAKING CHANGE:`.
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
### Commit message with description and breaking change footer
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
feat: allow provided config object to extend other configs
|
|
59
|
+
|
|
60
|
+
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Commit message with ! to draw attention to breaking change
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
feat!: send an email to the customer when a product is shipped
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Commit message with scope and ! to draw attention to breaking change
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
chore(api)!: drop support for Node 6
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Commit message with multi-paragraph body and multiple footers
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
fix: prevent racing of requests
|
|
79
|
+
|
|
80
|
+
Introduce a request id and a reference to latest request. All
|
|
81
|
+
rest responses are checked against the current id before update.
|
|
82
|
+
|
|
83
|
+
Reviewers: adrian, jdoe
|
|
84
|
+
Fixes #123
|
|
85
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Pull Request Description Best Practices
|
|
2
|
+
|
|
3
|
+
A well-crafted pull request (PR) description is essential for effective code review, maintaining project history, and ensuring that changes meet quality standards.
|
|
4
|
+
|
|
5
|
+
## Core Components
|
|
6
|
+
|
|
7
|
+
The most effective PR templates across major open-source repositories (like React, VS Code, and Kubernetes) share these core components:
|
|
8
|
+
|
|
9
|
+
### 1. Summary & Motivation
|
|
10
|
+
|
|
11
|
+
Explain **what** you changed and **why** you changed it.
|
|
12
|
+
|
|
13
|
+
- What problem does this PR solve?
|
|
14
|
+
- What is the context for this change?
|
|
15
|
+
- Are there any architectural decisions or trade-offs made?
|
|
16
|
+
|
|
17
|
+
### 2. Related Issues
|
|
18
|
+
|
|
19
|
+
Always link to the issue(s) being addressed. Use keywords that GitHub recognizes to automatically close issues when the PR is merged:
|
|
20
|
+
|
|
21
|
+
- `Fixes #123`
|
|
22
|
+
|
|
23
|
+
- `Closes #123`
|
|
24
|
+
|
|
25
|
+
- `Resolves #123`
|
|
26
|
+
|
|
27
|
+
### 3. Type of Change
|
|
28
|
+
|
|
29
|
+
Categorize the PR to help maintainers quickly understand its impact:
|
|
30
|
+
|
|
31
|
+
- **Bug Fix**: Non-breaking change that fixes an issue.
|
|
32
|
+
|
|
33
|
+
- **New Feature**: Non-breaking change that adds functionality.
|
|
34
|
+
|
|
35
|
+
- **Breaking Change**: Fix or feature that would cause existing functionality to change.
|
|
36
|
+
- **Documentation**: Changes to documentation only.
|
|
37
|
+
- **Refactor**: Code change that neither fixes a bug nor adds a feature.
|
|
38
|
+
|
|
39
|
+
### 4. Test Plan (Verification)
|
|
40
|
+
|
|
41
|
+
Describe how you verified your changes. This is the most critical section for reviewers.
|
|
42
|
+
|
|
43
|
+
- **Automated Tests**: Mention new or existing tests that cover the changes.
|
|
44
|
+
- **Manual Testing**: List the steps taken to manually verify the behavior.
|
|
45
|
+
- **Screenshots/Gifs**: Provide visual evidence for UI/UX changes.
|
|
46
|
+
|
|
47
|
+
### 5. Checklist
|
|
48
|
+
|
|
49
|
+
A set of mandatory steps the contributor must confirm:
|
|
50
|
+
|
|
51
|
+
- [ ] My code follows the project's style guidelines.
|
|
52
|
+
- [ ] I have performed a self-review of my code.
|
|
53
|
+
- [ ] I have added tests that cover my changes.
|
|
54
|
+
- [ ] All new and existing tests passed.
|
|
55
|
+
- [ ] I have updated the documentation accordingly.
|
|
56
|
+
|
|
57
|
+
### 6. Special Notes for Reviewers
|
|
58
|
+
|
|
59
|
+
Use this section to highlight specific areas where you need feedback or to explain complex logic that might be hard to follow.
|
|
60
|
+
|
|
61
|
+
## Best Practices
|
|
62
|
+
|
|
63
|
+
- **Keep it focused**: One logical change per PR. Small PRs are easier to review and less likely to introduce bugs.
|
|
64
|
+
- **Write for the future**: Your PR description will be part of the repository's history. Write it so that someone reading it a year from now can understand the context.
|
|
65
|
+
- **Be concise but thorough**: Avoid "fluff," but don't leave out critical information.
|
|
66
|
+
- **Update the description**: If the PR evolves during the review process, update the description to reflect the final state of the changes.
|