agentic-awesome-skills 14.2.0 → 14.3.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 +33 -11
- package/package.json +5 -2
- package/tools/bin/install.js +221 -21
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<!-- registry-sync: version=14.
|
|
1
|
+
<!-- registry-sync: version=14.3.0; skills=1948; stars=43042; updated_at=2026-07-13T07:58:11+00:00 -->
|
|
2
2
|
[](https://github.com/sickn33/agentic-awesome-skills)
|
|
3
3
|
|
|
4
|
-
# 🌌 Agentic Awesome Skills: 1,
|
|
4
|
+
# 🌌 Agentic Awesome Skills: 1,948+ Agentic Skills for Claude Code, Gemini CLI, Cursor, Autohand Code, Copilot & More
|
|
5
5
|
|
|
6
|
-
> **Installable GitHub library of 1,
|
|
6
|
+
> **Installable GitHub library of 1,948+ agentic skills for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants.**
|
|
7
7
|
|
|
8
8
|
Agentic Awesome Skills is an installable GitHub library and npm installer for reusable `SKILL.md` playbooks. It is designed for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, Kiro, OpenCode, GitHub Copilot, and other AI coding assistants that benefit from structured operating instructions. Instead of collecting one-off prompt snippets, this repository gives you a searchable, installable catalog of skills, bundles, workflows, plugin-safe distributions, and practical docs that help agents perform recurring tasks with better context, stronger constraints, and clearer outputs.
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ You can use this repo to install a broad multi-tool skill library, start from fo
|
|
|
13
13
|
|
|
14
14
|
The canonical project page is the GitHub repository at <https://github.com/sickn33/agentic-awesome-skills>; the hosted catalog is a companion discovery surface for search, plugins, and skill detail pages.
|
|
15
15
|
|
|
16
|
-
**Start here:** [Install in 1 minute](#installation) · [Recommended plugins](#recommended-specialized-plugins) · [Compare plugin packs](https://sickn33.github.io/agentic-awesome-skills/plugins) · [Choose your tool](#choose-your-tool) · [📚 Browse 1,
|
|
16
|
+
**Start here:** [Install in 1 minute](#installation) · [Recommended plugins](#recommended-specialized-plugins) · [Compare plugin packs](https://sickn33.github.io/agentic-awesome-skills/plugins) · [Choose your tool](#choose-your-tool) · [📚 Browse 1,948+ Skills](#browse-1948-skills) · [Bundles & workflows](#bundles--workflows) · [Support the project](#support-the-project)
|
|
17
17
|
|
|
18
18
|
[](https://github.com/sickn33/agentic-awesome-skills/stargazers)
|
|
19
19
|
[](https://x.com/AASkills_)
|
|
@@ -30,13 +30,13 @@ The canonical project page is the GitHub repository at <https://github.com/sickn
|
|
|
30
30
|
[](https://github.com/opencode-ai/opencode)
|
|
31
31
|
[](https://github.com/sickn33/agentic-awesome-skills)
|
|
32
32
|
|
|
33
|
-
**Current release: V14.
|
|
33
|
+
**Current release: V14.3.0.** Trusted by 43k+ GitHub stargazers, this repository combines official and community skill collections with bundles, workflows, installation paths, and docs that help you go from first install to daily use quickly.
|
|
34
34
|
|
|
35
35
|
## Why This Repo
|
|
36
36
|
|
|
37
37
|
- **Installable, not just inspirational**: use `npx agentic-awesome-skills` to put skills where your tool expects them.
|
|
38
38
|
- **Built for major agent workflows**: Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, Kiro, OpenCode, Copilot, and more.
|
|
39
|
-
- **Broad coverage with real utility**: 1,
|
|
39
|
+
- **Broad coverage with real utility**: 1,948+ skills across development, testing, security, infrastructure, product, and marketing.
|
|
40
40
|
- **Focused by default**: specialized plugins help you start with the web, security, data, docs, DevOps, QA, OSS, or agent/MCP workflows you actually need.
|
|
41
41
|
- **Useful whether you want breadth or curation**: install the full catalog, choose a specialized plugin, start with bundles, or compare alternatives before installing.
|
|
42
42
|
|
|
@@ -48,7 +48,7 @@ The canonical project page is the GitHub repository at <https://github.com/sickn
|
|
|
48
48
|
- [Choose Your Tool](#choose-your-tool)
|
|
49
49
|
- [Quick FAQ](#quick-faq)
|
|
50
50
|
- [Bundles & Workflows](#bundles--workflows)
|
|
51
|
-
- [Browse 1,
|
|
51
|
+
- [Browse 1,948+ Skills](#browse-1948-skills)
|
|
52
52
|
- [Troubleshooting](#troubleshooting)
|
|
53
53
|
- [Stable Skills Manifest v1](#stable-skills-manifest-v1)
|
|
54
54
|
- [Support the Project](#support-the-project)
|
|
@@ -79,6 +79,18 @@ npx agentic-awesome-skills --agy
|
|
|
79
79
|
|
|
80
80
|
The npm installer uses a shallow, release-pinned clone by default so first-run installs stay lighter than a full repository history checkout while matching the published npm package version. Use `--tag main` only when you intentionally want the current repository tip.
|
|
81
81
|
|
|
82
|
+
### Focused single-skill install with GitHub CLI (preview)
|
|
83
|
+
|
|
84
|
+
GitHub CLI can preview and install one exact skill for Copilot and other supported hosts. Use an exact `SKILL.md` path in this large, mirrored repository so the selected source is unambiguous and discovery stays fast:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
gh skill preview sickn33/agentic-awesome-skills skills/brainstorming/SKILL.md
|
|
88
|
+
gh skill install sickn33/agentic-awesome-skills skills/brainstorming/SKILL.md \
|
|
89
|
+
--agent github-copilot --scope user --pin v14.2.0
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`gh skill` support is currently a GitHub CLI preview and may change. Install a focused skill or plugin surface for the job; do not use `--all` unless you intentionally want every discovered canonical and mirrored skill.
|
|
93
|
+
|
|
82
94
|
### Verify the install
|
|
83
95
|
|
|
84
96
|
```bash
|
|
@@ -142,7 +154,7 @@ Use the same repository, but install or invoke it in the way your host expects.
|
|
|
142
154
|
| Antigravity CLI (`agy`) | `npx agentic-awesome-skills --agy` | `/brainstorming help me plan a feature` |
|
|
143
155
|
| Kiro CLI | `npx agentic-awesome-skills --kiro` | `Use brainstorming to plan a feature` |
|
|
144
156
|
| Kiro IDE | `npx agentic-awesome-skills --path ~/.kiro/skills` | `Use @brainstorming to plan a feature` |
|
|
145
|
-
| GitHub Copilot |
|
|
157
|
+
| GitHub Copilot | `gh skill install sickn33/agentic-awesome-skills skills/brainstorming/SKILL.md --agent github-copilot --scope user --pin v14.2.0` (preview) | `Ask Copilot to use brainstorming to plan a feature` |
|
|
146
158
|
| OpenCode | `npx agentic-awesome-skills --path .agents/skills --category development,backend --risk safe,none` | `opencode run @brainstorming help me plan a feature` |
|
|
147
159
|
| AdaL CLI | `npx agentic-awesome-skills --path .adal/skills` | `Use brainstorming to plan a feature` |
|
|
148
160
|
| Custom path | `npx agentic-awesome-skills --path ./my-skills` | Depends on your tool |
|
|
@@ -159,7 +171,7 @@ Use the table above for install targets. Use specialized plugins when you are ch
|
|
|
159
171
|
|
|
160
172
|
### What is Agentic Awesome Skills?
|
|
161
173
|
|
|
162
|
-
**Agentic Awesome Skills** (Release 14.
|
|
174
|
+
**Agentic Awesome Skills** (Release 14.3.0) is a large, installable skill library for AI coding assistants. It packages 1,948+ reusable `SKILL.md` playbooks, specialized plugins, bundles, workflows, generated catalogs, and a CLI installer so Claude Code, Codex CLI, Autohand Code, Cursor, Gemini CLI, Antigravity, and similar tools can reuse proven operating instructions instead of one-off prompts.
|
|
163
175
|
|
|
164
176
|
### How do I install it?
|
|
165
177
|
|
|
@@ -224,7 +236,15 @@ If Antigravity starts hitting context limits with too many active skills, the ac
|
|
|
224
236
|
|
|
225
237
|
If you use OpenCode or another `.agents/skills` host, prefer a reduced install up front instead of copying the full library into a context-sensitive runtime. The installer now supports `--risk`, `--category`, and `--tags` so you can keep the installed set narrow.
|
|
226
238
|
|
|
227
|
-
|
|
239
|
+
For a reproducible exact set, pin the package and catalog release and preview the full per-target plan before writing:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npx agentic-awesome-skills@14.3.0 --codex --release 14.3.0 --skills frontend-design,game-development/2d-games --dry-run
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Remove `--dry-run` only after reviewing the install, update, and removal plan. Unknown or ambiguous skill identifiers fail closed, and metadata filters combine with `--skills` using AND.
|
|
246
|
+
|
|
247
|
+
## Browse 1,948+ Skills
|
|
228
248
|
|
|
229
249
|
Use the root repo as a landing page, then jump into the deeper surface that matches your intent.
|
|
230
250
|
|
|
@@ -398,6 +418,7 @@ Key source families include:
|
|
|
398
418
|
- **[adelaidasofia/ai-brain-starter](https://github.com/adelaidasofia/ai-brain-starter)**: Source for the `ingest-youtube` skill - YouTube transcript ingestion into markdown vaults with yt-dlp metadata, VTT cleanup, and capture-seed stubs (MIT).
|
|
399
419
|
- **[JDDavenport/context-kit](https://github.com/JDDavenport/context-kit)**: Source reference for the `context-kit` skill - local-first Personal Context Artifact setup, installer review, and private context hygiene for Claude Code and adjacent agent workflows.
|
|
400
420
|
- **[JularDepick/user-thoughts.SKILL](https://github.com/JularDepick/user-thoughts.SKILL)**: Source for the `user-thoughts` skill - persistent project idea repository workflows for capturing decisions, tech stack notes, UI/UX rationale, and MDBASE-backed project memory (MIT).
|
|
421
|
+
- **[TheaDust/lore](https://github.com/TheaDust/lore)**: Source for the `lore` skill - Markdown-only, zero-dependency long-term project memory for AI coding agents, with monorepo scopes, two-section platform mirrors, and stdlib Python helpers (MIT).
|
|
401
422
|
- **[ZeroPointRepo/youtube-skills](https://github.com/ZeroPointRepo/youtube-skills)**: Source for the `youtube-full` skill - TranscriptAPI-backed YouTube transcripts, search, channel browsing, playlists, and cloud-safe video research workflows (MIT).
|
|
402
423
|
- **[ejentum/ejentum-mcp](https://github.com/ejentum/ejentum-mcp)**: Source for the `ejentum-reasoning-harness` skill - MCP cognitive harness modes for reasoning, code review, anti-deception checks, and memory-drift analysis (MIT).
|
|
403
424
|
- **[luoyuctl/agenttrace](https://github.com/luoyuctl/agenttrace)**: Source for the `agenttrace-session-audit` skill - local AI coding-agent session audits for cost spikes, tool failures, latency gaps, anomalies, health gates, and session diffs (MIT).
|
|
@@ -423,6 +444,7 @@ Key source families include:
|
|
|
423
444
|
- **[Elkidogz/technical-change-skill](https://github.com/Elkidogz/technical-change-skill)**: Source for the Technical Change Tracker skill - structured JSON change records, session handoff, and accessible HTML dashboards for coding continuity.
|
|
424
445
|
- **[vipin-si/article-illustrations](https://github.com/vipin-si/article-illustrations)**: Source for the `article-illustrations` skill - Grav-style hand-drawn article illustrations with whiteboard sketches, sparse annotations, and visual metaphor QA guidance (MIT).
|
|
425
446
|
- **[274326424/video-content-extractor](https://github.com/274326424/video-content-extractor)**: Source for the `video-content-extractor` skill - FFmpeg and Tesseract OCR workflows for extracting timestamped screen text and structured Markdown reports from MP4 videos (MIT).
|
|
447
|
+
- **[metrox-eth/quit-sponsor](https://github.com/metrox-eth/quit-sponsor)**: Source for the `quit-sponsor` skill - evidence-based quit-smoking sponsorship for agents with persistent memory: 44-source cited protocols, sponsor decision tree, three-clause contract, wave protocol, slip attribution coaching, and a timestamped logbook (MIT).
|
|
426
448
|
- **[rmyndharis/antigravity-skills](https://github.com/rmyndharis/antigravity-skills)**: For the massive contribution of 300+ Enterprise skills and the catalog generation logic.
|
|
427
449
|
- **[amartelr/antigravity-workspace-manager](https://github.com/amartelr/antigravity-workspace-manager)**: Workspace Manager CLI companion to dynamically auto-provision subsets of skills across local development environments.
|
|
428
450
|
- **[obra/superpowers](https://github.com/obra/superpowers)**: The original "Superpowers" by Jesse Vincent.
|
|
@@ -482,7 +504,7 @@ Key source families include:
|
|
|
482
504
|
- **[christopherlhammer11-ai/tool-use-guardian](https://github.com/christopherlhammer11-ai/tool-use-guardian)**: Source for the Tool Use Guardian skill — tool-call reliability wrapper with retries, recovery, and failure classification.
|
|
483
505
|
- **[christopherlhammer11-ai/recallmax](https://github.com/christopherlhammer11-ai/recallmax)**: Source for the RecallMax skill — long-context memory, summarization, and conversation compression for agents.
|
|
484
506
|
- **[tsilverberg/webapp-uat](https://github.com/tsilverberg/webapp-uat)**: Full browser UAT skill — Playwright testing with console/network error capture, WCAG 2.2 AA accessibility checks, i18n validation, responsive testing, and P0-P3 bug triage. Read-only by default, works with React, Vue, Angular, Ionic, Next.js.
|
|
485
|
-
- **[Wolfe-Jam/faf-skills](https://github.com/Wolfe-Jam/faf-skills)**: AI-context and project DNA skills — .faf format management, AI-readiness scoring, bi-sync, MCP server building, and championship-grade testing (
|
|
507
|
+
- **[Wolfe-Jam/faf-skills](https://github.com/Wolfe-Jam/faf-skills)**: AI-context and project DNA skills — .faf format management, AI-readiness scoring, bi-sync, MCP server building, and championship-grade testing (7 skills, MIT).
|
|
486
508
|
- **[fullstackcrew-alpha/privacy-mask](https://github.com/fullstackcrew-alpha/privacy-mask)**: Local image privacy masking for AI coding agents. Detects and redacts PII, API keys, and secrets in screenshots via OCR + 47 regex rules. Claude Code hook integration for automatic masking. Supports Tesseract and RapidOCR. 100% offline (MIT).
|
|
487
509
|
- **[AvdLee/SwiftUI-Agent-Skill](https://github.com/AvdLee/SwiftUI-Agent-Skill)**: SwiftUI best-practices skill for agent workflows (MIT).
|
|
488
510
|
- **[CloudAI-X/threejs-skills](https://github.com/CloudAI-X/threejs-skills)**: Three.js-focused skill collection for agent-assisted 3D web work.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-awesome-skills",
|
|
3
|
-
"version": "14.
|
|
4
|
-
"description": "1,
|
|
3
|
+
"version": "14.3.0",
|
|
4
|
+
"description": "1,948+ agentic skills for Claude Code, Gemini CLI, Cursor, Antigravity & more. Installer CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"validate": "node tools/scripts/run-python.js tools/scripts/validate_skills.py",
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
"build": "npm run chain && npm run catalog",
|
|
35
35
|
"check:stale-claims": "node tools/scripts/run-python.js tools/scripts/check_stale_claims.py",
|
|
36
36
|
"check:live-seo": "node tools/scripts/check-live-seo-geo.js",
|
|
37
|
+
"pages:redirect-bridge": "node tools/scripts/generate-pages-redirect-bridge.js",
|
|
38
|
+
"traffic:normalize": "node tools/scripts/normalize_traffic_snapshots.js",
|
|
39
|
+
"traffic:migration-readiness": "node tools/scripts/audit_search_migration_readiness.js",
|
|
37
40
|
"check:warning-budget": "node tools/scripts/run-python.js tools/scripts/check_validation_warning_budget.py",
|
|
38
41
|
"check:readme-credits": "node tools/scripts/run-python.js tools/scripts/check_readme_credits.py",
|
|
39
42
|
"audit:consistency": "node tools/scripts/run-python.js tools/scripts/audit_consistency.py",
|
package/tools/bin/install.js
CHANGED
|
@@ -41,7 +41,9 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
41
41
|
let riskArg = null;
|
|
42
42
|
let categoryArg = null;
|
|
43
43
|
let tagsArg = null;
|
|
44
|
+
let skillsArg = null;
|
|
44
45
|
let versionInfo = false;
|
|
46
|
+
let dryRun = false;
|
|
45
47
|
let cursor = false,
|
|
46
48
|
claude = false,
|
|
47
49
|
gemini = false,
|
|
@@ -56,7 +58,7 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
56
58
|
versionInfo = true;
|
|
57
59
|
continue;
|
|
58
60
|
}
|
|
59
|
-
if (["--path", "--release", "--tag", "--risk", "--category", "--tags"].includes(a[i])) {
|
|
61
|
+
if (["--path", "--release", "--tag", "--risk", "--category", "--tags", "--skills"].includes(a[i])) {
|
|
60
62
|
const value = a[i + 1];
|
|
61
63
|
if (!value || value.startsWith("--")) {
|
|
62
64
|
throw new Error(`Option ${a[i]} requires a value.`);
|
|
@@ -67,9 +69,14 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
67
69
|
if (a[i] === "--risk") riskArg = value;
|
|
68
70
|
if (a[i] === "--category") categoryArg = value;
|
|
69
71
|
if (a[i] === "--tags") tagsArg = value;
|
|
72
|
+
if (a[i] === "--skills") skillsArg = value;
|
|
70
73
|
i += 1;
|
|
71
74
|
continue;
|
|
72
75
|
}
|
|
76
|
+
if (a[i] === "--dry-run") {
|
|
77
|
+
dryRun = true;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
73
80
|
if (a[i] === "--cursor") {
|
|
74
81
|
cursor = true;
|
|
75
82
|
continue;
|
|
@@ -109,7 +116,9 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
109
116
|
riskArg,
|
|
110
117
|
categoryArg,
|
|
111
118
|
tagsArg,
|
|
119
|
+
skillsArg,
|
|
112
120
|
versionInfo,
|
|
121
|
+
dryRun,
|
|
113
122
|
cursor,
|
|
114
123
|
claude,
|
|
115
124
|
gemini,
|
|
@@ -179,6 +188,8 @@ Options:
|
|
|
179
188
|
--risk <csv> Install only skills matching these risk labels
|
|
180
189
|
--category <csv> Install only skills matching these categories
|
|
181
190
|
--tags <csv> Install only skills matching these tags
|
|
191
|
+
--skills <csv> Set exact managed skill names, ids, or nested skill paths
|
|
192
|
+
--dry-run Preview installs/updates/removals for every target without writing
|
|
182
193
|
--version Print the installer version
|
|
183
194
|
--release <ver> Clone tag v<ver> (e.g. 4.6.0 -> v4.6.0)
|
|
184
195
|
--tag <tag> Clone this tag or branch (e.g. v4.6.0, main)
|
|
@@ -191,6 +202,7 @@ Examples:
|
|
|
191
202
|
npx agentic-awesome-skills --agy
|
|
192
203
|
npx agentic-awesome-skills --path .agents/skills --category development,backend --risk safe,none
|
|
193
204
|
npx agentic-awesome-skills --path .agents/skills --tags debugging,typescript-legacy-
|
|
205
|
+
npx agentic-awesome-skills --codex --skills frontend-design,game-development/2d-games --dry-run
|
|
194
206
|
npx agentic-awesome-skills --release 4.6.0
|
|
195
207
|
npx agentic-awesome-skills --path ./my-skills
|
|
196
208
|
npx agentic-awesome-skills --claude --codex Install to multiple targets
|
|
@@ -230,6 +242,19 @@ function parseSelectorArg(raw) {
|
|
|
230
242
|
};
|
|
231
243
|
}
|
|
232
244
|
|
|
245
|
+
function parseExactSkillArg(raw) {
|
|
246
|
+
if (typeof raw !== "string" || !raw.trim()) {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const values = raw.split(",").map((value) => value.trim());
|
|
251
|
+
if (values.some((value) => !value)) {
|
|
252
|
+
throw new Error("--skills must be a comma-separated list of non-empty exact skill names, ids, or paths.");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return uniqueValues(values);
|
|
256
|
+
}
|
|
257
|
+
|
|
233
258
|
function hasActiveSelector(selector) {
|
|
234
259
|
return selector.include.length > 0 || selector.exclude.length > 0;
|
|
235
260
|
}
|
|
@@ -422,21 +447,51 @@ function replaceManagedEntry(
|
|
|
422
447
|
}
|
|
423
448
|
|
|
424
449
|
/** Copy contents of repo's skills/ into target so each skill is target/skill-name/ (for Claude Code etc.). */
|
|
425
|
-
function
|
|
450
|
+
function resolveExactSkillSelections(repoSkills, skillEntries, requestedSkills = []) {
|
|
451
|
+
if (requestedSkills.length === 0) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const skills = skillEntries.map((skillId) => readSkill(repoSkills, skillId));
|
|
456
|
+
const resolvedEntries = new Set();
|
|
457
|
+
|
|
458
|
+
for (const requestedSkill of requestedSkills) {
|
|
459
|
+
const matches = skills.filter((skill) => (
|
|
460
|
+
skill.name === requestedSkill ||
|
|
461
|
+
skill.id === requestedSkill ||
|
|
462
|
+
path.basename(skill.id) === requestedSkill
|
|
463
|
+
));
|
|
464
|
+
|
|
465
|
+
if (matches.length === 0) {
|
|
466
|
+
throw new Error(`Unknown skill requested by --skills: ${requestedSkill}`);
|
|
467
|
+
}
|
|
468
|
+
if (matches.length > 1) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`Ambiguous skill requested by --skills: ${requestedSkill}. Use one exact nested skill path: ${matches.map((skill) => skill.id).join(", ")}`,
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
resolvedEntries.add(matches[0].id);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return resolvedEntries;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function getInstallEntries(tempDir, selectors = buildInstallSelectors({}), requestedSkills = []) {
|
|
426
481
|
const repoSkills = path.join(tempDir, "skills");
|
|
427
482
|
if (!fs.existsSync(repoSkills)) {
|
|
428
|
-
|
|
429
|
-
process.exit(1);
|
|
483
|
+
throw new Error("Cloned repo has no skills/ directory.");
|
|
430
484
|
}
|
|
431
485
|
|
|
432
486
|
const skillEntries = listSkillIdsRecursive(repoSkills);
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
487
|
+
const selectedEntries = resolveExactSkillSelections(repoSkills, skillEntries, requestedSkills);
|
|
488
|
+
const filteredEntries = skillEntries.filter((skillId) => (
|
|
489
|
+
(!selectedEntries || selectedEntries.has(skillId)) &&
|
|
490
|
+
(!hasInstallSelectors(selectors) || matchesInstallSelectors(readSkill(repoSkills, skillId), selectors))
|
|
491
|
+
));
|
|
492
|
+
|
|
493
|
+
if ((selectedEntries || hasInstallSelectors(selectors)) && filteredEntries.length === 0) {
|
|
494
|
+
throw new Error("No skills matched the requested --skills/--risk/--category/--tags selection.");
|
|
440
495
|
}
|
|
441
496
|
|
|
442
497
|
const entries = [...filteredEntries];
|
|
@@ -550,6 +605,22 @@ function readInstallManifest(targetPath) {
|
|
|
550
605
|
}
|
|
551
606
|
}
|
|
552
607
|
|
|
608
|
+
function normalizeManifestEntries(entries) {
|
|
609
|
+
const normalized = [];
|
|
610
|
+
const invalid = [];
|
|
611
|
+
for (const entry of entries) {
|
|
612
|
+
try {
|
|
613
|
+
normalized.push(normalizeInstallEntry(entry));
|
|
614
|
+
} catch (error) {
|
|
615
|
+
invalid.push(entry);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return {
|
|
619
|
+
entries: uniqueValues(normalized).sort(),
|
|
620
|
+
invalid: uniqueValues(invalid).sort(),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
553
624
|
function writeInstallManifest(targetPath, installEntries) {
|
|
554
625
|
const manifestPath = resolveInstallManifestPath(targetPath);
|
|
555
626
|
const normalizedEntries = [...new Set(installEntries.map(normalizeInstallEntry).filter(Boolean))].sort();
|
|
@@ -572,14 +643,17 @@ function writeInstallManifest(targetPath, installEntries) {
|
|
|
572
643
|
|
|
573
644
|
function pruneRemovedEntries(targetPath, previousEntries, installEntries) {
|
|
574
645
|
const next = new Set(installEntries.map(normalizeInstallEntry));
|
|
575
|
-
|
|
576
|
-
|
|
646
|
+
const normalizedPrevious = normalizeManifestEntries(previousEntries);
|
|
647
|
+
for (const entry of normalizedPrevious.invalid) {
|
|
648
|
+
console.warn(` Skipping unsafe managed entry path from manifest: ${entry}`);
|
|
649
|
+
}
|
|
650
|
+
for (const normalizedEntry of normalizedPrevious.entries) {
|
|
577
651
|
if (next.has(normalizedEntry)) {
|
|
578
652
|
continue;
|
|
579
653
|
}
|
|
580
|
-
const candidate = resolveManagedPath(targetPath,
|
|
654
|
+
const candidate = resolveManagedPath(targetPath, normalizedEntry);
|
|
581
655
|
if (!candidate) {
|
|
582
|
-
console.warn(` Skipping unsafe managed entry path from manifest: ${
|
|
656
|
+
console.warn(` Skipping unsafe managed entry path from manifest: ${normalizedEntry}`);
|
|
583
657
|
continue;
|
|
584
658
|
}
|
|
585
659
|
assertSafeDestinationPath(candidate, targetPath);
|
|
@@ -658,7 +732,16 @@ function resolveInstallRef(opts) {
|
|
|
658
732
|
return DEFAULT_RELEASE_REF;
|
|
659
733
|
}
|
|
660
734
|
|
|
661
|
-
function installForTarget(
|
|
735
|
+
function installForTarget(
|
|
736
|
+
tempDir,
|
|
737
|
+
target,
|
|
738
|
+
selectors = buildInstallSelectors({}),
|
|
739
|
+
installEntries = null,
|
|
740
|
+
requestedSkills = [],
|
|
741
|
+
) {
|
|
742
|
+
// Resolve all selection errors before creating or changing the target.
|
|
743
|
+
const resolvedInstallEntries = installEntries || getInstallEntries(tempDir, selectors, requestedSkills);
|
|
744
|
+
|
|
662
745
|
if (fs.existsSync(target.path)) {
|
|
663
746
|
ensureTargetIsDirectory(target.path);
|
|
664
747
|
const targetStats = fs.lstatSync(target.path);
|
|
@@ -698,10 +781,9 @@ function installForTarget(tempDir, target, selectors = buildInstallSelectors({})
|
|
|
698
781
|
fs.mkdirSync(target.path, { recursive: true });
|
|
699
782
|
}
|
|
700
783
|
|
|
701
|
-
const
|
|
702
|
-
const managedEntries = getManagedEntries(installEntries, target);
|
|
784
|
+
const managedEntries = getManagedEntries(resolvedInstallEntries, target);
|
|
703
785
|
const previousEntries = readInstallManifest(target.path);
|
|
704
|
-
installSkillsIntoTarget(tempDir, target.path,
|
|
786
|
+
installSkillsIntoTarget(tempDir, target.path, resolvedInstallEntries);
|
|
705
787
|
pruneRemovedEntries(target.path, previousEntries, managedEntries);
|
|
706
788
|
writeInstallManifest(target.path, managedEntries);
|
|
707
789
|
console.log(` ✓ Installed to ${target.path}`);
|
|
@@ -737,7 +819,7 @@ function getPostInstallMessages(targets, selectors = buildInstallSelectors({}))
|
|
|
737
819
|
|
|
738
820
|
if (targets.some((target) => isOpenCodeStylePath(target.path))) {
|
|
739
821
|
const baseMessage =
|
|
740
|
-
"For Antigravity 2.0, OpenCode, or other .agents/skills installs, prefer a reduced install with --risk, --category, or --tags to avoid context overload.";
|
|
822
|
+
"For Antigravity 2.0, OpenCode, or other .agents/skills installs, prefer a reduced install with --skills, --risk, --category, or --tags to avoid context overload.";
|
|
741
823
|
messages.push(baseMessage);
|
|
742
824
|
if (!hasInstallSelectors(selectors)) {
|
|
743
825
|
messages.push(
|
|
@@ -749,6 +831,82 @@ function getPostInstallMessages(targets, selectors = buildInstallSelectors({}))
|
|
|
749
831
|
return messages;
|
|
750
832
|
}
|
|
751
833
|
|
|
834
|
+
function buildDryRunTargetPlan(target, installEntries) {
|
|
835
|
+
const desiredEntries = uniqueValues(getManagedEntries(installEntries, target)).sort();
|
|
836
|
+
const targetExists = fs.existsSync(target.path);
|
|
837
|
+
|
|
838
|
+
if (targetExists) {
|
|
839
|
+
const stats = fs.lstatSync(target.path);
|
|
840
|
+
if (stats.isSymbolicLink()) {
|
|
841
|
+
throw new Error(`Refusing to preview through symlinked target: ${target.path}`);
|
|
842
|
+
}
|
|
843
|
+
if (!stats.isDirectory()) {
|
|
844
|
+
throw new Error(`Install path exists but is not a directory: ${target.path}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const previous = normalizeManifestEntries(readInstallManifest(target.path));
|
|
849
|
+
const desiredSet = new Set(desiredEntries);
|
|
850
|
+
const remove = previous.entries.filter((entry) => !desiredSet.has(entry));
|
|
851
|
+
|
|
852
|
+
// Match the apply-time destination checks without creating any path. This
|
|
853
|
+
// makes the preview fail before a later install could encounter a symlinked
|
|
854
|
+
// managed destination or an unsafe stale manifest entry.
|
|
855
|
+
for (const entry of [...desiredEntries, ...remove]) {
|
|
856
|
+
const candidate = resolveManagedPath(target.path, entry);
|
|
857
|
+
if (!candidate) {
|
|
858
|
+
throw new Error(`Refusing unsafe managed entry in dry-run plan: ${entry}`);
|
|
859
|
+
}
|
|
860
|
+
assertSafeDestinationPath(candidate, target.path);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
return {
|
|
864
|
+
name: target.name,
|
|
865
|
+
path: target.path,
|
|
866
|
+
targetExists,
|
|
867
|
+
replacesRepositoryClone: targetExists && fs.existsSync(path.join(target.path, ".git")),
|
|
868
|
+
installOrUpdate: desiredEntries,
|
|
869
|
+
remove,
|
|
870
|
+
ignoredUnsafeManifestEntries: previous.invalid,
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function buildDryRunPlan(ref, targets, installEntries) {
|
|
875
|
+
return {
|
|
876
|
+
ref: ref || "default release",
|
|
877
|
+
targets: targets.map((target) => buildDryRunTargetPlan(target, installEntries)),
|
|
878
|
+
skills: installEntries.filter((entry) => entry !== "docs").sort(),
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
function printDryRunPlan(plan) {
|
|
883
|
+
console.log("\nDry run: no target files or directories will be created, changed, or removed.");
|
|
884
|
+
console.log(`Ref: ${plan.ref}`);
|
|
885
|
+
console.log(`Exact skill set (${plan.skills.length}):`);
|
|
886
|
+
for (const skill of plan.skills) {
|
|
887
|
+
console.log(` ${skill}`);
|
|
888
|
+
}
|
|
889
|
+
console.log("Target mutation plans:");
|
|
890
|
+
for (const target of plan.targets) {
|
|
891
|
+
console.log(` ${target.name}: ${target.path}`);
|
|
892
|
+
console.log(` target: ${target.targetExists ? "existing directory" : "will be created"}`);
|
|
893
|
+
if (target.replacesRepositoryClone) {
|
|
894
|
+
console.log(" migration: existing repository clone will be backed up and replaced");
|
|
895
|
+
}
|
|
896
|
+
console.log(` install/update managed entries (${target.installOrUpdate.length}):`);
|
|
897
|
+
for (const entry of target.installOrUpdate) {
|
|
898
|
+
console.log(` ${entry}`);
|
|
899
|
+
}
|
|
900
|
+
console.log(` remove stale managed entries (${target.remove.length}):`);
|
|
901
|
+
for (const entry of target.remove) {
|
|
902
|
+
console.log(` ${entry}`);
|
|
903
|
+
}
|
|
904
|
+
for (const entry of target.ignoredUnsafeManifestEntries) {
|
|
905
|
+
console.log(` ignored unsafe manifest entry: ${entry}`);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
752
910
|
function main() {
|
|
753
911
|
let opts;
|
|
754
912
|
try {
|
|
@@ -759,6 +917,14 @@ function main() {
|
|
|
759
917
|
return;
|
|
760
918
|
}
|
|
761
919
|
const selectors = buildInstallSelectors(opts);
|
|
920
|
+
let requestedSkills;
|
|
921
|
+
try {
|
|
922
|
+
requestedSkills = parseExactSkillArg(opts.skillsArg);
|
|
923
|
+
} catch (error) {
|
|
924
|
+
console.error(`Error: ${error.message}`);
|
|
925
|
+
process.exitCode = 1;
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
762
928
|
const ref = resolveInstallRef(opts);
|
|
763
929
|
|
|
764
930
|
if (opts.help) {
|
|
@@ -788,10 +954,38 @@ function main() {
|
|
|
788
954
|
}
|
|
789
955
|
run("git", buildCloneArgs(REPO, tempDir, ref));
|
|
790
956
|
|
|
957
|
+
// Resolve the exact set once before touching any target. This keeps an
|
|
958
|
+
// unknown/ambiguous --skills value or an empty filter intersection atomic
|
|
959
|
+
// across multi-target installs.
|
|
960
|
+
let installEntries;
|
|
961
|
+
try {
|
|
962
|
+
installEntries = getInstallEntries(tempDir, selectors, requestedSkills);
|
|
963
|
+
} catch (error) {
|
|
964
|
+
console.error(`Error: ${error.message}`);
|
|
965
|
+
process.exitCode = 1;
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Preflight every target before mutating the first one. The same plan is
|
|
970
|
+
// printed for --dry-run and acts as the multi-target safety gate for apply.
|
|
971
|
+
let dryRunPlan;
|
|
972
|
+
try {
|
|
973
|
+
dryRunPlan = buildDryRunPlan(ref, targets, installEntries);
|
|
974
|
+
} catch (error) {
|
|
975
|
+
console.error(`Error: ${error.message}`);
|
|
976
|
+
process.exitCode = 1;
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (opts.dryRun) {
|
|
981
|
+
printDryRunPlan(dryRunPlan);
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
|
|
791
985
|
console.log(`\nInstalling for ${targets.length} target(s):`);
|
|
792
986
|
for (const target of targets) {
|
|
793
987
|
console.log(`\n${target.name}:`);
|
|
794
|
-
installForTarget(tempDir, target, selectors);
|
|
988
|
+
installForTarget(tempDir, target, selectors, installEntries);
|
|
795
989
|
}
|
|
796
990
|
|
|
797
991
|
for (const message of getPostInstallMessages(targets, selectors)) {
|
|
@@ -821,6 +1015,8 @@ module.exports = {
|
|
|
821
1015
|
replaceManagedEntry,
|
|
822
1016
|
getPostInstallMessages,
|
|
823
1017
|
buildCloneArgs,
|
|
1018
|
+
buildDryRunPlan,
|
|
1019
|
+
buildDryRunTargetPlan,
|
|
824
1020
|
buildInstallSelectors,
|
|
825
1021
|
getInstallEntries,
|
|
826
1022
|
getManagedEntries,
|
|
@@ -831,10 +1027,14 @@ module.exports = {
|
|
|
831
1027
|
main,
|
|
832
1028
|
matchesInstallSelectors,
|
|
833
1029
|
normalizeInstallEntry,
|
|
1030
|
+
normalizeManifestEntries,
|
|
1031
|
+
parseExactSkillArg,
|
|
834
1032
|
parseSelectorArg,
|
|
1033
|
+
printDryRunPlan,
|
|
835
1034
|
parseArgs,
|
|
836
1035
|
pruneRemovedEntries,
|
|
837
1036
|
readInstallManifest,
|
|
1037
|
+
resolveExactSkillSelections,
|
|
838
1038
|
resolveInstallRef,
|
|
839
1039
|
writeInstallManifest,
|
|
840
1040
|
};
|