add-skill 1.0.2 → 1.0.4
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 +12 -8
- package/dist/index.js +14 -4
- package/package.json +3 -2
- package/src/agents.ts +9 -0
- package/src/index.ts +4 -4
- package/src/skills.ts +1 -0
- package/src/types.ts +1 -1
- package/.claude/skills/vercel-deploy/SKILL.md +0 -109
- package/.claude/skills/vercel-deploy/scripts/deploy.sh +0 -249
- package/.codex/skills/vercel-deploy/SKILL.md +0 -109
- package/.codex/skills/vercel-deploy/scripts/deploy.sh +0 -249
- package/.opencode/skill/vercel-deploy/SKILL.md +0 -109
- package/.opencode/skill/vercel-deploy/scripts/deploy.sh +0 -249
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Install agent skills onto your coding agents from any git repository.
|
|
4
4
|
|
|
5
|
-
Supports [OpenCode](https://opencode.ai), [Claude Code](https://claude.ai/code),
|
|
5
|
+
Supports [OpenCode](https://opencode.ai), [Claude Code](https://claude.ai/code), [Codex](https://developers.openai.com/codex), and [Cursor](https://cursor.com).
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
@@ -47,7 +47,7 @@ npx add-skill git@github.com:vercel-labs/agent-skills.git
|
|
|
47
47
|
| Option | Description |
|
|
48
48
|
|--------|-------------|
|
|
49
49
|
| `-g, --global` | Install to user directory instead of project |
|
|
50
|
-
| `-a, --agent <agents...>` | Target specific agents: `opencode`, `claude-code`, `codex` |
|
|
50
|
+
| `-a, --agent <agents...>` | Target specific agents: `opencode`, `claude-code`, `codex`, `cursor` |
|
|
51
51
|
| `-s, --skill <skills...>` | Install specific skills by name |
|
|
52
52
|
| `-l, --list` | List available skills without installing |
|
|
53
53
|
| `-y, --yes` | Skip all confirmation prompts |
|
|
@@ -86,6 +86,7 @@ Installed in your current working directory. Commit these to share with your tea
|
|
|
86
86
|
| OpenCode | `.opencode/skill/<name>/` |
|
|
87
87
|
| Claude Code | `.claude/skills/<name>/` |
|
|
88
88
|
| Codex | `.codex/skills/<name>/` |
|
|
89
|
+
| Cursor | `.cursor/skills/<name>/` |
|
|
89
90
|
|
|
90
91
|
### Global (`--global`)
|
|
91
92
|
|
|
@@ -96,6 +97,7 @@ Installed in your home directory. Available across all projects.
|
|
|
96
97
|
| OpenCode | `~/.config/opencode/skill/<name>/` |
|
|
97
98
|
| Claude Code | `~/.claude/skills/<name>/` |
|
|
98
99
|
| Codex | `~/.codex/skills/<name>/` |
|
|
100
|
+
| Cursor | `~/.cursor/skills/<name>/` |
|
|
99
101
|
|
|
100
102
|
## Agent Detection
|
|
101
103
|
|
|
@@ -142,6 +144,7 @@ The CLI searches for skills in these locations within a repository:
|
|
|
142
144
|
- `.codex/skills/`
|
|
143
145
|
- `.claude/skills/`
|
|
144
146
|
- `.opencode/skill/`
|
|
147
|
+
- `.cursor/skills/`
|
|
145
148
|
|
|
146
149
|
If no skills are found in standard locations, a recursive search is performed.
|
|
147
150
|
|
|
@@ -149,12 +152,12 @@ If no skills are found in standard locations, a recursive search is performed.
|
|
|
149
152
|
|
|
150
153
|
Skills are generally compatible across agents since they follow a shared [Agent Skills specification](https://agentskills.io). However, some features may be agent-specific:
|
|
151
154
|
|
|
152
|
-
| Feature | OpenCode | Claude Code | Codex |
|
|
153
|
-
|
|
154
|
-
| Basic skills | Yes | Yes | Yes |
|
|
155
|
-
| `allowed-tools` | Yes | Yes | Yes |
|
|
156
|
-
| `context: fork` | No | Yes | No |
|
|
157
|
-
| Hooks | No | Yes | No |
|
|
155
|
+
| Feature | OpenCode | Claude Code | Codex | Cursor |
|
|
156
|
+
|---------|----------|-------------|-------|--------|
|
|
157
|
+
| Basic skills | Yes | Yes | Yes | Yes |
|
|
158
|
+
| `allowed-tools` | Yes | Yes | Yes | Yes |
|
|
159
|
+
| `context: fork` | No | Yes | No | No |
|
|
160
|
+
| Hooks | No | Yes | No | No |
|
|
158
161
|
|
|
159
162
|
## Troubleshooting
|
|
160
163
|
|
|
@@ -179,6 +182,7 @@ Ensure you have write access to the target directory.
|
|
|
179
182
|
- [OpenCode Skills Documentation](https://opencode.ai/docs/skills/)
|
|
180
183
|
- [Claude Code Skills Documentation](https://code.claude.com/docs/en/skills)
|
|
181
184
|
- [Codex Skills Documentation](https://developers.openai.com/codex/skills/)
|
|
185
|
+
- [Cursor Skills Documentation](https://cursor.com/docs/context/skills)
|
|
182
186
|
|
|
183
187
|
## License
|
|
184
188
|
|
package/dist/index.js
CHANGED
|
@@ -143,7 +143,8 @@ async function discoverSkills(basePath, subpath) {
|
|
|
143
143
|
join2(searchPath, "skills/.system"),
|
|
144
144
|
join2(searchPath, ".codex/skills"),
|
|
145
145
|
join2(searchPath, ".claude/skills"),
|
|
146
|
-
join2(searchPath, ".opencode/skill")
|
|
146
|
+
join2(searchPath, ".opencode/skill"),
|
|
147
|
+
join2(searchPath, ".cursor/skills")
|
|
147
148
|
];
|
|
148
149
|
for (const dir of prioritySearchDirs) {
|
|
149
150
|
try {
|
|
@@ -215,6 +216,15 @@ var agents = {
|
|
|
215
216
|
detectInstalled: async () => {
|
|
216
217
|
return existsSync(join3(home, ".codex"));
|
|
217
218
|
}
|
|
219
|
+
},
|
|
220
|
+
cursor: {
|
|
221
|
+
name: "cursor",
|
|
222
|
+
displayName: "Cursor",
|
|
223
|
+
skillsDir: ".cursor/skills",
|
|
224
|
+
globalSkillsDir: join3(home, ".cursor/skills"),
|
|
225
|
+
detectInstalled: async () => {
|
|
226
|
+
return existsSync(join3(home, ".cursor"));
|
|
227
|
+
}
|
|
218
228
|
}
|
|
219
229
|
};
|
|
220
230
|
async function detectInstalledAgents() {
|
|
@@ -277,7 +287,7 @@ function getInstallPath(skillName, agentType, options = {}) {
|
|
|
277
287
|
|
|
278
288
|
// src/index.ts
|
|
279
289
|
var version = "1.0.0";
|
|
280
|
-
program.name("add-skill").description("Install skills onto coding agents (OpenCode, Claude Code, Codex)").version(version).argument("<source>", "Git repo URL, GitHub shorthand (owner/repo), or direct path to skill").option("-g, --global", "Install skill globally (user-level) instead of project-level").option("-a, --agent <agents...>", "Specify agents to install to (opencode, claude-code, codex)").option("-s, --skill <skills...>", "Specify skill names to install (skip selection prompt)").option("-l, --list", "List available skills in the repository without installing").option("-y, --yes", "Skip confirmation prompts").action(async (source, options) => {
|
|
290
|
+
program.name("add-skill").description("Install skills onto coding agents (OpenCode, Claude Code, Codex, Cursor)").version(version).argument("<source>", "Git repo URL, GitHub shorthand (owner/repo), or direct path to skill").option("-g, --global", "Install skill globally (user-level) instead of project-level").option("-a, --agent <agents...>", "Specify agents to install to (opencode, claude-code, codex, cursor)").option("-s, --skill <skills...>", "Specify skill names to install (skip selection prompt)").option("-l, --list", "List available skills in the repository without installing").option("-y, --yes", "Skip confirmation prompts").action(async (source, options) => {
|
|
281
291
|
await main(source, options);
|
|
282
292
|
});
|
|
283
293
|
program.parse();
|
|
@@ -359,7 +369,7 @@ async function main(source, options) {
|
|
|
359
369
|
}
|
|
360
370
|
let targetAgents;
|
|
361
371
|
if (options.agent && options.agent.length > 0) {
|
|
362
|
-
const validAgents = ["opencode", "claude-code", "codex"];
|
|
372
|
+
const validAgents = ["opencode", "claude-code", "codex", "cursor"];
|
|
363
373
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
364
374
|
if (invalidAgents.length > 0) {
|
|
365
375
|
p.log.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
@@ -374,7 +384,7 @@ async function main(source, options) {
|
|
|
374
384
|
spinner2.stop(`Detected ${installedAgents.length} agent${installedAgents.length !== 1 ? "s" : ""}`);
|
|
375
385
|
if (installedAgents.length === 0) {
|
|
376
386
|
if (options.yes) {
|
|
377
|
-
targetAgents = ["opencode", "claude-code", "codex"];
|
|
387
|
+
targetAgents = ["opencode", "claude-code", "codex", "cursor"];
|
|
378
388
|
p.log.info("Installing to all agents (none detected)");
|
|
379
389
|
} else {
|
|
380
390
|
p.log.warn("No coding agents detected. You can still install skills.");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "add-skill",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Install agent skills onto coding agents (OpenCode, Claude Code, Codex)",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Install agent skills onto coding agents (OpenCode, Claude Code, Codex, Cursor)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"add-skill": "./dist/index.js"
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"opencode",
|
|
18
18
|
"claude-code",
|
|
19
19
|
"codex",
|
|
20
|
+
"cursor",
|
|
20
21
|
"ai-agents"
|
|
21
22
|
],
|
|
22
23
|
"author": "",
|
package/src/agents.ts
CHANGED
|
@@ -33,6 +33,15 @@ export const agents: Record<AgentType, AgentConfig> = {
|
|
|
33
33
|
return existsSync(join(home, '.codex'));
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
|
+
cursor: {
|
|
37
|
+
name: 'cursor',
|
|
38
|
+
displayName: 'Cursor',
|
|
39
|
+
skillsDir: '.cursor/skills',
|
|
40
|
+
globalSkillsDir: join(home, '.cursor/skills'),
|
|
41
|
+
detectInstalled: async () => {
|
|
42
|
+
return existsSync(join(home, '.cursor'));
|
|
43
|
+
},
|
|
44
|
+
},
|
|
36
45
|
};
|
|
37
46
|
|
|
38
47
|
export async function detectInstalledAgents(): Promise<AgentType[]> {
|
package/src/index.ts
CHANGED
|
@@ -21,11 +21,11 @@ interface Options {
|
|
|
21
21
|
|
|
22
22
|
program
|
|
23
23
|
.name('add-skill')
|
|
24
|
-
.description('Install skills onto coding agents (OpenCode, Claude Code, Codex)')
|
|
24
|
+
.description('Install skills onto coding agents (OpenCode, Claude Code, Codex, Cursor)')
|
|
25
25
|
.version(version)
|
|
26
26
|
.argument('<source>', 'Git repo URL, GitHub shorthand (owner/repo), or direct path to skill')
|
|
27
27
|
.option('-g, --global', 'Install skill globally (user-level) instead of project-level')
|
|
28
|
-
.option('-a, --agent <agents...>', 'Specify agents to install to (opencode, claude-code, codex)')
|
|
28
|
+
.option('-a, --agent <agents...>', 'Specify agents to install to (opencode, claude-code, codex, cursor)')
|
|
29
29
|
.option('-s, --skill <skills...>', 'Specify skill names to install (skip selection prompt)')
|
|
30
30
|
.option('-l, --list', 'List available skills in the repository without installing')
|
|
31
31
|
.option('-y, --yes', 'Skip confirmation prompts')
|
|
@@ -131,7 +131,7 @@ async function main(source: string, options: Options) {
|
|
|
131
131
|
let targetAgents: AgentType[];
|
|
132
132
|
|
|
133
133
|
if (options.agent && options.agent.length > 0) {
|
|
134
|
-
const validAgents = ['opencode', 'claude-code', 'codex'];
|
|
134
|
+
const validAgents = ['opencode', 'claude-code', 'codex', 'cursor'];
|
|
135
135
|
const invalidAgents = options.agent.filter(a => !validAgents.includes(a));
|
|
136
136
|
|
|
137
137
|
if (invalidAgents.length > 0) {
|
|
@@ -149,7 +149,7 @@ async function main(source: string, options: Options) {
|
|
|
149
149
|
|
|
150
150
|
if (installedAgents.length === 0) {
|
|
151
151
|
if (options.yes) {
|
|
152
|
-
targetAgents = ['opencode', 'claude-code', 'codex'];
|
|
152
|
+
targetAgents = ['opencode', 'claude-code', 'codex', 'cursor'];
|
|
153
153
|
p.log.info('Installing to all agents (none detected)');
|
|
154
154
|
} else {
|
|
155
155
|
p.log.warn('No coding agents detected. You can still install skills.');
|
package/src/skills.ts
CHANGED
|
@@ -84,6 +84,7 @@ export async function discoverSkills(basePath: string, subpath?: string): Promis
|
|
|
84
84
|
join(searchPath, '.codex/skills'),
|
|
85
85
|
join(searchPath, '.claude/skills'),
|
|
86
86
|
join(searchPath, '.opencode/skill'),
|
|
87
|
+
join(searchPath, '.cursor/skills'),
|
|
87
88
|
];
|
|
88
89
|
|
|
89
90
|
for (const dir of prioritySearchDirs) {
|
package/src/types.ts
CHANGED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: vercel-deploy
|
|
3
|
-
description: Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as "Deploy my app", "Deploy this to production", "Create a preview deployment", "Deploy and give me the link", or "Push this live". No authentication required - returns preview URL and claimable deployment link.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Vercel Deploy
|
|
7
|
-
|
|
8
|
-
Deploy any project to Vercel instantly. No authentication required.
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
1. Packages your project into a tarball (excludes `node_modules` and `.git`)
|
|
13
|
-
2. Auto-detects framework from `package.json`
|
|
14
|
-
3. Uploads to deployment service
|
|
15
|
-
4. Returns **Preview URL** (live site) and **Claim URL** (transfer to your Vercel account)
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh [path]
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Arguments:**
|
|
24
|
-
- `path` - Directory to deploy, or a `.tgz` file (defaults to current directory)
|
|
25
|
-
|
|
26
|
-
**Examples:**
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# Deploy current directory
|
|
30
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh
|
|
31
|
-
|
|
32
|
-
# Deploy specific project
|
|
33
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project
|
|
34
|
-
|
|
35
|
-
# Deploy existing tarball
|
|
36
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project.tgz
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Output
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Preparing deployment...
|
|
43
|
-
Detected framework: nextjs
|
|
44
|
-
Creating deployment package...
|
|
45
|
-
Deploying...
|
|
46
|
-
✓ Deployment successful!
|
|
47
|
-
|
|
48
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
49
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
The script also outputs JSON to stdout for programmatic use:
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"previewUrl": "https://skill-deploy-abc123.vercel.app",
|
|
57
|
-
"claimUrl": "https://vercel.com/claim-deployment?code=...",
|
|
58
|
-
"deploymentId": "dpl_...",
|
|
59
|
-
"projectId": "prj_..."
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Framework Detection
|
|
64
|
-
|
|
65
|
-
The script auto-detects frameworks from `package.json`. Supported frameworks include:
|
|
66
|
-
|
|
67
|
-
- **React**: Next.js, Gatsby, Create React App, Remix, React Router
|
|
68
|
-
- **Vue**: Nuxt, Vitepress, Vuepress, Gridsome
|
|
69
|
-
- **Svelte**: SvelteKit, Svelte, Sapper
|
|
70
|
-
- **Other Frontend**: Astro, Solid Start, Angular, Ember, Preact, Docusaurus
|
|
71
|
-
- **Backend**: Express, Hono, Fastify, NestJS, Elysia, h3, Nitro
|
|
72
|
-
- **Build Tools**: Vite, Parcel
|
|
73
|
-
- **And more**: Blitz, Hydrogen, RedwoodJS, Storybook, Sanity, etc.
|
|
74
|
-
|
|
75
|
-
For static HTML projects (no `package.json`), framework is set to `null`.
|
|
76
|
-
|
|
77
|
-
## Static HTML Projects
|
|
78
|
-
|
|
79
|
-
For projects without a `package.json`:
|
|
80
|
-
- If there's a single `.html` file not named `index.html`, it gets renamed automatically
|
|
81
|
-
- This ensures the page is served at the root URL (`/`)
|
|
82
|
-
|
|
83
|
-
## Present Results to User
|
|
84
|
-
|
|
85
|
-
Always show both URLs:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
✓ Deployment successful!
|
|
89
|
-
|
|
90
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
91
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
92
|
-
|
|
93
|
-
View your site at the Preview URL.
|
|
94
|
-
To transfer this deployment to your Vercel account, visit the Claim URL.
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Troubleshooting
|
|
98
|
-
|
|
99
|
-
### Network Egress Error
|
|
100
|
-
|
|
101
|
-
If deployment fails due to network restrictions (common on claude.ai), tell the user:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
Deployment failed due to network restrictions. To fix this:
|
|
105
|
-
|
|
106
|
-
1. Go to https://claude.ai/admin-settings/capabilities
|
|
107
|
-
2. Add *.vercel.com to the allowed domains
|
|
108
|
-
3. Try deploying again
|
|
109
|
-
```
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Vercel Deployment Script (via claimable deploy endpoint)
|
|
4
|
-
# Usage: ./deploy.sh [project-path]
|
|
5
|
-
# Returns: JSON with previewUrl, claimUrl, deploymentId, projectId
|
|
6
|
-
|
|
7
|
-
set -e
|
|
8
|
-
|
|
9
|
-
DEPLOY_ENDPOINT="https://claude-skills-deploy.vercel.com/api/deploy"
|
|
10
|
-
|
|
11
|
-
# Detect framework from package.json
|
|
12
|
-
detect_framework() {
|
|
13
|
-
local pkg_json="$1"
|
|
14
|
-
|
|
15
|
-
if [ ! -f "$pkg_json" ]; then
|
|
16
|
-
echo "null"
|
|
17
|
-
return
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
local content=$(cat "$pkg_json")
|
|
21
|
-
|
|
22
|
-
# Helper to check if a package exists in dependencies or devDependencies
|
|
23
|
-
has_dep() {
|
|
24
|
-
echo "$content" | grep -q "\"$1\""
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
# Order matters - check more specific frameworks first
|
|
28
|
-
|
|
29
|
-
# Blitz
|
|
30
|
-
if has_dep "blitz"; then echo "blitzjs"; return; fi
|
|
31
|
-
|
|
32
|
-
# Next.js
|
|
33
|
-
if has_dep "next"; then echo "nextjs"; return; fi
|
|
34
|
-
|
|
35
|
-
# Gatsby
|
|
36
|
-
if has_dep "gatsby"; then echo "gatsby"; return; fi
|
|
37
|
-
|
|
38
|
-
# Remix
|
|
39
|
-
if has_dep "@remix-run/"; then echo "remix"; return; fi
|
|
40
|
-
|
|
41
|
-
# React Router (v7 framework mode)
|
|
42
|
-
if has_dep "@react-router/"; then echo "react-router"; return; fi
|
|
43
|
-
|
|
44
|
-
# TanStack Start
|
|
45
|
-
if has_dep "@tanstack/start"; then echo "tanstack-start"; return; fi
|
|
46
|
-
|
|
47
|
-
# Astro
|
|
48
|
-
if has_dep "astro"; then echo "astro"; return; fi
|
|
49
|
-
|
|
50
|
-
# Hydrogen (Shopify)
|
|
51
|
-
if has_dep "@shopify/hydrogen"; then echo "hydrogen"; return; fi
|
|
52
|
-
|
|
53
|
-
# SvelteKit
|
|
54
|
-
if has_dep "@sveltejs/kit"; then echo "sveltekit-1"; return; fi
|
|
55
|
-
|
|
56
|
-
# Svelte (standalone)
|
|
57
|
-
if has_dep "svelte"; then echo "svelte"; return; fi
|
|
58
|
-
|
|
59
|
-
# Nuxt
|
|
60
|
-
if has_dep "nuxt"; then echo "nuxtjs"; return; fi
|
|
61
|
-
|
|
62
|
-
# Vue with Vitepress
|
|
63
|
-
if has_dep "vitepress"; then echo "vitepress"; return; fi
|
|
64
|
-
|
|
65
|
-
# Vue with Vuepress
|
|
66
|
-
if has_dep "vuepress"; then echo "vuepress"; return; fi
|
|
67
|
-
|
|
68
|
-
# Gridsome
|
|
69
|
-
if has_dep "gridsome"; then echo "gridsome"; return; fi
|
|
70
|
-
|
|
71
|
-
# SolidStart
|
|
72
|
-
if has_dep "@solidjs/start"; then echo "solidstart-1"; return; fi
|
|
73
|
-
|
|
74
|
-
# Docusaurus
|
|
75
|
-
if has_dep "@docusaurus/core"; then echo "docusaurus-2"; return; fi
|
|
76
|
-
|
|
77
|
-
# RedwoodJS
|
|
78
|
-
if has_dep "@redwoodjs/"; then echo "redwoodjs"; return; fi
|
|
79
|
-
|
|
80
|
-
# Hexo
|
|
81
|
-
if has_dep "hexo"; then echo "hexo"; return; fi
|
|
82
|
-
|
|
83
|
-
# Eleventy
|
|
84
|
-
if has_dep "@11ty/eleventy"; then echo "eleventy"; return; fi
|
|
85
|
-
|
|
86
|
-
# Angular / Ionic Angular
|
|
87
|
-
if has_dep "@ionic/angular"; then echo "ionic-angular"; return; fi
|
|
88
|
-
if has_dep "@angular/core"; then echo "angular"; return; fi
|
|
89
|
-
|
|
90
|
-
# Ionic React
|
|
91
|
-
if has_dep "@ionic/react"; then echo "ionic-react"; return; fi
|
|
92
|
-
|
|
93
|
-
# Create React App
|
|
94
|
-
if has_dep "react-scripts"; then echo "create-react-app"; return; fi
|
|
95
|
-
|
|
96
|
-
# Ember
|
|
97
|
-
if has_dep "ember-cli" || has_dep "ember-source"; then echo "ember"; return; fi
|
|
98
|
-
|
|
99
|
-
# Dojo
|
|
100
|
-
if has_dep "@dojo/framework"; then echo "dojo"; return; fi
|
|
101
|
-
|
|
102
|
-
# Polymer
|
|
103
|
-
if has_dep "@polymer/"; then echo "polymer"; return; fi
|
|
104
|
-
|
|
105
|
-
# Preact
|
|
106
|
-
if has_dep "preact"; then echo "preact"; return; fi
|
|
107
|
-
|
|
108
|
-
# Stencil
|
|
109
|
-
if has_dep "@stencil/core"; then echo "stencil"; return; fi
|
|
110
|
-
|
|
111
|
-
# UmiJS
|
|
112
|
-
if has_dep "umi"; then echo "umijs"; return; fi
|
|
113
|
-
|
|
114
|
-
# Sapper (legacy Svelte)
|
|
115
|
-
if has_dep "sapper"; then echo "sapper"; return; fi
|
|
116
|
-
|
|
117
|
-
# Saber
|
|
118
|
-
if has_dep "saber"; then echo "saber"; return; fi
|
|
119
|
-
|
|
120
|
-
# Sanity
|
|
121
|
-
if has_dep "sanity"; then echo "sanity-v3"; return; fi
|
|
122
|
-
if has_dep "@sanity/"; then echo "sanity"; return; fi
|
|
123
|
-
|
|
124
|
-
# Storybook
|
|
125
|
-
if has_dep "@storybook/"; then echo "storybook"; return; fi
|
|
126
|
-
|
|
127
|
-
# NestJS
|
|
128
|
-
if has_dep "@nestjs/core"; then echo "nestjs"; return; fi
|
|
129
|
-
|
|
130
|
-
# Elysia
|
|
131
|
-
if has_dep "elysia"; then echo "elysia"; return; fi
|
|
132
|
-
|
|
133
|
-
# Hono
|
|
134
|
-
if has_dep "hono"; then echo "hono"; return; fi
|
|
135
|
-
|
|
136
|
-
# Fastify
|
|
137
|
-
if has_dep "fastify"; then echo "fastify"; return; fi
|
|
138
|
-
|
|
139
|
-
# h3
|
|
140
|
-
if has_dep "h3"; then echo "h3"; return; fi
|
|
141
|
-
|
|
142
|
-
# Nitro
|
|
143
|
-
if has_dep "nitropack"; then echo "nitro"; return; fi
|
|
144
|
-
|
|
145
|
-
# Express
|
|
146
|
-
if has_dep "express"; then echo "express"; return; fi
|
|
147
|
-
|
|
148
|
-
# Vite (generic - check last among JS frameworks)
|
|
149
|
-
if has_dep "vite"; then echo "vite"; return; fi
|
|
150
|
-
|
|
151
|
-
# Parcel
|
|
152
|
-
if has_dep "parcel"; then echo "parcel"; return; fi
|
|
153
|
-
|
|
154
|
-
# No framework detected
|
|
155
|
-
echo "null"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# Parse arguments
|
|
159
|
-
INPUT_PATH="${1:-.}"
|
|
160
|
-
|
|
161
|
-
# Create temp directory for packaging
|
|
162
|
-
TEMP_DIR=$(mktemp -d)
|
|
163
|
-
TARBALL="$TEMP_DIR/project.tgz"
|
|
164
|
-
CLEANUP_TEMP=true
|
|
165
|
-
|
|
166
|
-
cleanup() {
|
|
167
|
-
if [ "$CLEANUP_TEMP" = true ]; then
|
|
168
|
-
rm -rf "$TEMP_DIR"
|
|
169
|
-
fi
|
|
170
|
-
}
|
|
171
|
-
trap cleanup EXIT
|
|
172
|
-
|
|
173
|
-
echo "Preparing deployment..." >&2
|
|
174
|
-
|
|
175
|
-
# Check if input is a .tgz file or a directory
|
|
176
|
-
FRAMEWORK="null"
|
|
177
|
-
|
|
178
|
-
if [ -f "$INPUT_PATH" ] && [[ "$INPUT_PATH" == *.tgz ]]; then
|
|
179
|
-
# Input is already a tarball, use it directly
|
|
180
|
-
echo "Using provided tarball..." >&2
|
|
181
|
-
TARBALL="$INPUT_PATH"
|
|
182
|
-
CLEANUP_TEMP=false
|
|
183
|
-
# Can't detect framework from tarball, leave as null
|
|
184
|
-
elif [ -d "$INPUT_PATH" ]; then
|
|
185
|
-
# Input is a directory, need to tar it
|
|
186
|
-
PROJECT_PATH=$(cd "$INPUT_PATH" && pwd)
|
|
187
|
-
|
|
188
|
-
# Detect framework from package.json
|
|
189
|
-
FRAMEWORK=$(detect_framework "$PROJECT_PATH/package.json")
|
|
190
|
-
|
|
191
|
-
# Check if this is a static HTML project (no package.json)
|
|
192
|
-
if [ ! -f "$PROJECT_PATH/package.json" ]; then
|
|
193
|
-
# Find HTML files in root
|
|
194
|
-
HTML_FILES=$(find "$PROJECT_PATH" -maxdepth 1 -name "*.html" -type f)
|
|
195
|
-
HTML_COUNT=$(echo "$HTML_FILES" | grep -c . || echo 0)
|
|
196
|
-
|
|
197
|
-
# If there's exactly one HTML file and it's not index.html, rename it
|
|
198
|
-
if [ "$HTML_COUNT" -eq 1 ]; then
|
|
199
|
-
HTML_FILE=$(echo "$HTML_FILES" | head -1)
|
|
200
|
-
BASENAME=$(basename "$HTML_FILE")
|
|
201
|
-
if [ "$BASENAME" != "index.html" ]; then
|
|
202
|
-
echo "Renaming $BASENAME to index.html..." >&2
|
|
203
|
-
mv "$HTML_FILE" "$PROJECT_PATH/index.html"
|
|
204
|
-
fi
|
|
205
|
-
fi
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
# Create tarball of the project (excluding node_modules and .git)
|
|
209
|
-
echo "Creating deployment package..." >&2
|
|
210
|
-
tar -czf "$TARBALL" -C "$PROJECT_PATH" --exclude='node_modules' --exclude='.git' .
|
|
211
|
-
else
|
|
212
|
-
echo "Error: Input must be a directory or a .tgz file" >&2
|
|
213
|
-
exit 1
|
|
214
|
-
fi
|
|
215
|
-
|
|
216
|
-
if [ "$FRAMEWORK" != "null" ]; then
|
|
217
|
-
echo "Detected framework: $FRAMEWORK" >&2
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Deploy
|
|
221
|
-
echo "Deploying..." >&2
|
|
222
|
-
RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")
|
|
223
|
-
|
|
224
|
-
# Check for error in response
|
|
225
|
-
if echo "$RESPONSE" | grep -q '"error"'; then
|
|
226
|
-
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
|
227
|
-
echo "Error: $ERROR_MSG" >&2
|
|
228
|
-
exit 1
|
|
229
|
-
fi
|
|
230
|
-
|
|
231
|
-
# Extract URLs from response
|
|
232
|
-
PREVIEW_URL=$(echo "$RESPONSE" | grep -o '"previewUrl":"[^"]*"' | cut -d'"' -f4)
|
|
233
|
-
CLAIM_URL=$(echo "$RESPONSE" | grep -o '"claimUrl":"[^"]*"' | cut -d'"' -f4)
|
|
234
|
-
|
|
235
|
-
if [ -z "$PREVIEW_URL" ]; then
|
|
236
|
-
echo "Error: Could not extract preview URL from response" >&2
|
|
237
|
-
echo "$RESPONSE" >&2
|
|
238
|
-
exit 1
|
|
239
|
-
fi
|
|
240
|
-
|
|
241
|
-
echo "" >&2
|
|
242
|
-
echo "Deployment successful!" >&2
|
|
243
|
-
echo "" >&2
|
|
244
|
-
echo "Preview URL: $PREVIEW_URL" >&2
|
|
245
|
-
echo "Claim URL: $CLAIM_URL" >&2
|
|
246
|
-
echo "" >&2
|
|
247
|
-
|
|
248
|
-
# Output JSON for programmatic use
|
|
249
|
-
echo "$RESPONSE"
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: vercel-deploy
|
|
3
|
-
description: Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as "Deploy my app", "Deploy this to production", "Create a preview deployment", "Deploy and give me the link", or "Push this live". No authentication required - returns preview URL and claimable deployment link.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Vercel Deploy
|
|
7
|
-
|
|
8
|
-
Deploy any project to Vercel instantly. No authentication required.
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
1. Packages your project into a tarball (excludes `node_modules` and `.git`)
|
|
13
|
-
2. Auto-detects framework from `package.json`
|
|
14
|
-
3. Uploads to deployment service
|
|
15
|
-
4. Returns **Preview URL** (live site) and **Claim URL** (transfer to your Vercel account)
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh [path]
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Arguments:**
|
|
24
|
-
- `path` - Directory to deploy, or a `.tgz` file (defaults to current directory)
|
|
25
|
-
|
|
26
|
-
**Examples:**
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# Deploy current directory
|
|
30
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh
|
|
31
|
-
|
|
32
|
-
# Deploy specific project
|
|
33
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project
|
|
34
|
-
|
|
35
|
-
# Deploy existing tarball
|
|
36
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project.tgz
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Output
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Preparing deployment...
|
|
43
|
-
Detected framework: nextjs
|
|
44
|
-
Creating deployment package...
|
|
45
|
-
Deploying...
|
|
46
|
-
✓ Deployment successful!
|
|
47
|
-
|
|
48
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
49
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
The script also outputs JSON to stdout for programmatic use:
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"previewUrl": "https://skill-deploy-abc123.vercel.app",
|
|
57
|
-
"claimUrl": "https://vercel.com/claim-deployment?code=...",
|
|
58
|
-
"deploymentId": "dpl_...",
|
|
59
|
-
"projectId": "prj_..."
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Framework Detection
|
|
64
|
-
|
|
65
|
-
The script auto-detects frameworks from `package.json`. Supported frameworks include:
|
|
66
|
-
|
|
67
|
-
- **React**: Next.js, Gatsby, Create React App, Remix, React Router
|
|
68
|
-
- **Vue**: Nuxt, Vitepress, Vuepress, Gridsome
|
|
69
|
-
- **Svelte**: SvelteKit, Svelte, Sapper
|
|
70
|
-
- **Other Frontend**: Astro, Solid Start, Angular, Ember, Preact, Docusaurus
|
|
71
|
-
- **Backend**: Express, Hono, Fastify, NestJS, Elysia, h3, Nitro
|
|
72
|
-
- **Build Tools**: Vite, Parcel
|
|
73
|
-
- **And more**: Blitz, Hydrogen, RedwoodJS, Storybook, Sanity, etc.
|
|
74
|
-
|
|
75
|
-
For static HTML projects (no `package.json`), framework is set to `null`.
|
|
76
|
-
|
|
77
|
-
## Static HTML Projects
|
|
78
|
-
|
|
79
|
-
For projects without a `package.json`:
|
|
80
|
-
- If there's a single `.html` file not named `index.html`, it gets renamed automatically
|
|
81
|
-
- This ensures the page is served at the root URL (`/`)
|
|
82
|
-
|
|
83
|
-
## Present Results to User
|
|
84
|
-
|
|
85
|
-
Always show both URLs:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
✓ Deployment successful!
|
|
89
|
-
|
|
90
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
91
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
92
|
-
|
|
93
|
-
View your site at the Preview URL.
|
|
94
|
-
To transfer this deployment to your Vercel account, visit the Claim URL.
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Troubleshooting
|
|
98
|
-
|
|
99
|
-
### Network Egress Error
|
|
100
|
-
|
|
101
|
-
If deployment fails due to network restrictions (common on claude.ai), tell the user:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
Deployment failed due to network restrictions. To fix this:
|
|
105
|
-
|
|
106
|
-
1. Go to https://claude.ai/admin-settings/capabilities
|
|
107
|
-
2. Add *.vercel.com to the allowed domains
|
|
108
|
-
3. Try deploying again
|
|
109
|
-
```
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Vercel Deployment Script (via claimable deploy endpoint)
|
|
4
|
-
# Usage: ./deploy.sh [project-path]
|
|
5
|
-
# Returns: JSON with previewUrl, claimUrl, deploymentId, projectId
|
|
6
|
-
|
|
7
|
-
set -e
|
|
8
|
-
|
|
9
|
-
DEPLOY_ENDPOINT="https://claude-skills-deploy.vercel.com/api/deploy"
|
|
10
|
-
|
|
11
|
-
# Detect framework from package.json
|
|
12
|
-
detect_framework() {
|
|
13
|
-
local pkg_json="$1"
|
|
14
|
-
|
|
15
|
-
if [ ! -f "$pkg_json" ]; then
|
|
16
|
-
echo "null"
|
|
17
|
-
return
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
local content=$(cat "$pkg_json")
|
|
21
|
-
|
|
22
|
-
# Helper to check if a package exists in dependencies or devDependencies
|
|
23
|
-
has_dep() {
|
|
24
|
-
echo "$content" | grep -q "\"$1\""
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
# Order matters - check more specific frameworks first
|
|
28
|
-
|
|
29
|
-
# Blitz
|
|
30
|
-
if has_dep "blitz"; then echo "blitzjs"; return; fi
|
|
31
|
-
|
|
32
|
-
# Next.js
|
|
33
|
-
if has_dep "next"; then echo "nextjs"; return; fi
|
|
34
|
-
|
|
35
|
-
# Gatsby
|
|
36
|
-
if has_dep "gatsby"; then echo "gatsby"; return; fi
|
|
37
|
-
|
|
38
|
-
# Remix
|
|
39
|
-
if has_dep "@remix-run/"; then echo "remix"; return; fi
|
|
40
|
-
|
|
41
|
-
# React Router (v7 framework mode)
|
|
42
|
-
if has_dep "@react-router/"; then echo "react-router"; return; fi
|
|
43
|
-
|
|
44
|
-
# TanStack Start
|
|
45
|
-
if has_dep "@tanstack/start"; then echo "tanstack-start"; return; fi
|
|
46
|
-
|
|
47
|
-
# Astro
|
|
48
|
-
if has_dep "astro"; then echo "astro"; return; fi
|
|
49
|
-
|
|
50
|
-
# Hydrogen (Shopify)
|
|
51
|
-
if has_dep "@shopify/hydrogen"; then echo "hydrogen"; return; fi
|
|
52
|
-
|
|
53
|
-
# SvelteKit
|
|
54
|
-
if has_dep "@sveltejs/kit"; then echo "sveltekit-1"; return; fi
|
|
55
|
-
|
|
56
|
-
# Svelte (standalone)
|
|
57
|
-
if has_dep "svelte"; then echo "svelte"; return; fi
|
|
58
|
-
|
|
59
|
-
# Nuxt
|
|
60
|
-
if has_dep "nuxt"; then echo "nuxtjs"; return; fi
|
|
61
|
-
|
|
62
|
-
# Vue with Vitepress
|
|
63
|
-
if has_dep "vitepress"; then echo "vitepress"; return; fi
|
|
64
|
-
|
|
65
|
-
# Vue with Vuepress
|
|
66
|
-
if has_dep "vuepress"; then echo "vuepress"; return; fi
|
|
67
|
-
|
|
68
|
-
# Gridsome
|
|
69
|
-
if has_dep "gridsome"; then echo "gridsome"; return; fi
|
|
70
|
-
|
|
71
|
-
# SolidStart
|
|
72
|
-
if has_dep "@solidjs/start"; then echo "solidstart-1"; return; fi
|
|
73
|
-
|
|
74
|
-
# Docusaurus
|
|
75
|
-
if has_dep "@docusaurus/core"; then echo "docusaurus-2"; return; fi
|
|
76
|
-
|
|
77
|
-
# RedwoodJS
|
|
78
|
-
if has_dep "@redwoodjs/"; then echo "redwoodjs"; return; fi
|
|
79
|
-
|
|
80
|
-
# Hexo
|
|
81
|
-
if has_dep "hexo"; then echo "hexo"; return; fi
|
|
82
|
-
|
|
83
|
-
# Eleventy
|
|
84
|
-
if has_dep "@11ty/eleventy"; then echo "eleventy"; return; fi
|
|
85
|
-
|
|
86
|
-
# Angular / Ionic Angular
|
|
87
|
-
if has_dep "@ionic/angular"; then echo "ionic-angular"; return; fi
|
|
88
|
-
if has_dep "@angular/core"; then echo "angular"; return; fi
|
|
89
|
-
|
|
90
|
-
# Ionic React
|
|
91
|
-
if has_dep "@ionic/react"; then echo "ionic-react"; return; fi
|
|
92
|
-
|
|
93
|
-
# Create React App
|
|
94
|
-
if has_dep "react-scripts"; then echo "create-react-app"; return; fi
|
|
95
|
-
|
|
96
|
-
# Ember
|
|
97
|
-
if has_dep "ember-cli" || has_dep "ember-source"; then echo "ember"; return; fi
|
|
98
|
-
|
|
99
|
-
# Dojo
|
|
100
|
-
if has_dep "@dojo/framework"; then echo "dojo"; return; fi
|
|
101
|
-
|
|
102
|
-
# Polymer
|
|
103
|
-
if has_dep "@polymer/"; then echo "polymer"; return; fi
|
|
104
|
-
|
|
105
|
-
# Preact
|
|
106
|
-
if has_dep "preact"; then echo "preact"; return; fi
|
|
107
|
-
|
|
108
|
-
# Stencil
|
|
109
|
-
if has_dep "@stencil/core"; then echo "stencil"; return; fi
|
|
110
|
-
|
|
111
|
-
# UmiJS
|
|
112
|
-
if has_dep "umi"; then echo "umijs"; return; fi
|
|
113
|
-
|
|
114
|
-
# Sapper (legacy Svelte)
|
|
115
|
-
if has_dep "sapper"; then echo "sapper"; return; fi
|
|
116
|
-
|
|
117
|
-
# Saber
|
|
118
|
-
if has_dep "saber"; then echo "saber"; return; fi
|
|
119
|
-
|
|
120
|
-
# Sanity
|
|
121
|
-
if has_dep "sanity"; then echo "sanity-v3"; return; fi
|
|
122
|
-
if has_dep "@sanity/"; then echo "sanity"; return; fi
|
|
123
|
-
|
|
124
|
-
# Storybook
|
|
125
|
-
if has_dep "@storybook/"; then echo "storybook"; return; fi
|
|
126
|
-
|
|
127
|
-
# NestJS
|
|
128
|
-
if has_dep "@nestjs/core"; then echo "nestjs"; return; fi
|
|
129
|
-
|
|
130
|
-
# Elysia
|
|
131
|
-
if has_dep "elysia"; then echo "elysia"; return; fi
|
|
132
|
-
|
|
133
|
-
# Hono
|
|
134
|
-
if has_dep "hono"; then echo "hono"; return; fi
|
|
135
|
-
|
|
136
|
-
# Fastify
|
|
137
|
-
if has_dep "fastify"; then echo "fastify"; return; fi
|
|
138
|
-
|
|
139
|
-
# h3
|
|
140
|
-
if has_dep "h3"; then echo "h3"; return; fi
|
|
141
|
-
|
|
142
|
-
# Nitro
|
|
143
|
-
if has_dep "nitropack"; then echo "nitro"; return; fi
|
|
144
|
-
|
|
145
|
-
# Express
|
|
146
|
-
if has_dep "express"; then echo "express"; return; fi
|
|
147
|
-
|
|
148
|
-
# Vite (generic - check last among JS frameworks)
|
|
149
|
-
if has_dep "vite"; then echo "vite"; return; fi
|
|
150
|
-
|
|
151
|
-
# Parcel
|
|
152
|
-
if has_dep "parcel"; then echo "parcel"; return; fi
|
|
153
|
-
|
|
154
|
-
# No framework detected
|
|
155
|
-
echo "null"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# Parse arguments
|
|
159
|
-
INPUT_PATH="${1:-.}"
|
|
160
|
-
|
|
161
|
-
# Create temp directory for packaging
|
|
162
|
-
TEMP_DIR=$(mktemp -d)
|
|
163
|
-
TARBALL="$TEMP_DIR/project.tgz"
|
|
164
|
-
CLEANUP_TEMP=true
|
|
165
|
-
|
|
166
|
-
cleanup() {
|
|
167
|
-
if [ "$CLEANUP_TEMP" = true ]; then
|
|
168
|
-
rm -rf "$TEMP_DIR"
|
|
169
|
-
fi
|
|
170
|
-
}
|
|
171
|
-
trap cleanup EXIT
|
|
172
|
-
|
|
173
|
-
echo "Preparing deployment..." >&2
|
|
174
|
-
|
|
175
|
-
# Check if input is a .tgz file or a directory
|
|
176
|
-
FRAMEWORK="null"
|
|
177
|
-
|
|
178
|
-
if [ -f "$INPUT_PATH" ] && [[ "$INPUT_PATH" == *.tgz ]]; then
|
|
179
|
-
# Input is already a tarball, use it directly
|
|
180
|
-
echo "Using provided tarball..." >&2
|
|
181
|
-
TARBALL="$INPUT_PATH"
|
|
182
|
-
CLEANUP_TEMP=false
|
|
183
|
-
# Can't detect framework from tarball, leave as null
|
|
184
|
-
elif [ -d "$INPUT_PATH" ]; then
|
|
185
|
-
# Input is a directory, need to tar it
|
|
186
|
-
PROJECT_PATH=$(cd "$INPUT_PATH" && pwd)
|
|
187
|
-
|
|
188
|
-
# Detect framework from package.json
|
|
189
|
-
FRAMEWORK=$(detect_framework "$PROJECT_PATH/package.json")
|
|
190
|
-
|
|
191
|
-
# Check if this is a static HTML project (no package.json)
|
|
192
|
-
if [ ! -f "$PROJECT_PATH/package.json" ]; then
|
|
193
|
-
# Find HTML files in root
|
|
194
|
-
HTML_FILES=$(find "$PROJECT_PATH" -maxdepth 1 -name "*.html" -type f)
|
|
195
|
-
HTML_COUNT=$(echo "$HTML_FILES" | grep -c . || echo 0)
|
|
196
|
-
|
|
197
|
-
# If there's exactly one HTML file and it's not index.html, rename it
|
|
198
|
-
if [ "$HTML_COUNT" -eq 1 ]; then
|
|
199
|
-
HTML_FILE=$(echo "$HTML_FILES" | head -1)
|
|
200
|
-
BASENAME=$(basename "$HTML_FILE")
|
|
201
|
-
if [ "$BASENAME" != "index.html" ]; then
|
|
202
|
-
echo "Renaming $BASENAME to index.html..." >&2
|
|
203
|
-
mv "$HTML_FILE" "$PROJECT_PATH/index.html"
|
|
204
|
-
fi
|
|
205
|
-
fi
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
# Create tarball of the project (excluding node_modules and .git)
|
|
209
|
-
echo "Creating deployment package..." >&2
|
|
210
|
-
tar -czf "$TARBALL" -C "$PROJECT_PATH" --exclude='node_modules' --exclude='.git' .
|
|
211
|
-
else
|
|
212
|
-
echo "Error: Input must be a directory or a .tgz file" >&2
|
|
213
|
-
exit 1
|
|
214
|
-
fi
|
|
215
|
-
|
|
216
|
-
if [ "$FRAMEWORK" != "null" ]; then
|
|
217
|
-
echo "Detected framework: $FRAMEWORK" >&2
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Deploy
|
|
221
|
-
echo "Deploying..." >&2
|
|
222
|
-
RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")
|
|
223
|
-
|
|
224
|
-
# Check for error in response
|
|
225
|
-
if echo "$RESPONSE" | grep -q '"error"'; then
|
|
226
|
-
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
|
227
|
-
echo "Error: $ERROR_MSG" >&2
|
|
228
|
-
exit 1
|
|
229
|
-
fi
|
|
230
|
-
|
|
231
|
-
# Extract URLs from response
|
|
232
|
-
PREVIEW_URL=$(echo "$RESPONSE" | grep -o '"previewUrl":"[^"]*"' | cut -d'"' -f4)
|
|
233
|
-
CLAIM_URL=$(echo "$RESPONSE" | grep -o '"claimUrl":"[^"]*"' | cut -d'"' -f4)
|
|
234
|
-
|
|
235
|
-
if [ -z "$PREVIEW_URL" ]; then
|
|
236
|
-
echo "Error: Could not extract preview URL from response" >&2
|
|
237
|
-
echo "$RESPONSE" >&2
|
|
238
|
-
exit 1
|
|
239
|
-
fi
|
|
240
|
-
|
|
241
|
-
echo "" >&2
|
|
242
|
-
echo "Deployment successful!" >&2
|
|
243
|
-
echo "" >&2
|
|
244
|
-
echo "Preview URL: $PREVIEW_URL" >&2
|
|
245
|
-
echo "Claim URL: $CLAIM_URL" >&2
|
|
246
|
-
echo "" >&2
|
|
247
|
-
|
|
248
|
-
# Output JSON for programmatic use
|
|
249
|
-
echo "$RESPONSE"
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: vercel-deploy
|
|
3
|
-
description: Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as "Deploy my app", "Deploy this to production", "Create a preview deployment", "Deploy and give me the link", or "Push this live". No authentication required - returns preview URL and claimable deployment link.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Vercel Deploy
|
|
7
|
-
|
|
8
|
-
Deploy any project to Vercel instantly. No authentication required.
|
|
9
|
-
|
|
10
|
-
## How It Works
|
|
11
|
-
|
|
12
|
-
1. Packages your project into a tarball (excludes `node_modules` and `.git`)
|
|
13
|
-
2. Auto-detects framework from `package.json`
|
|
14
|
-
3. Uploads to deployment service
|
|
15
|
-
4. Returns **Preview URL** (live site) and **Claim URL** (transfer to your Vercel account)
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh [path]
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Arguments:**
|
|
24
|
-
- `path` - Directory to deploy, or a `.tgz` file (defaults to current directory)
|
|
25
|
-
|
|
26
|
-
**Examples:**
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# Deploy current directory
|
|
30
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh
|
|
31
|
-
|
|
32
|
-
# Deploy specific project
|
|
33
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project
|
|
34
|
-
|
|
35
|
-
# Deploy existing tarball
|
|
36
|
-
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project.tgz
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Output
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Preparing deployment...
|
|
43
|
-
Detected framework: nextjs
|
|
44
|
-
Creating deployment package...
|
|
45
|
-
Deploying...
|
|
46
|
-
✓ Deployment successful!
|
|
47
|
-
|
|
48
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
49
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
The script also outputs JSON to stdout for programmatic use:
|
|
53
|
-
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"previewUrl": "https://skill-deploy-abc123.vercel.app",
|
|
57
|
-
"claimUrl": "https://vercel.com/claim-deployment?code=...",
|
|
58
|
-
"deploymentId": "dpl_...",
|
|
59
|
-
"projectId": "prj_..."
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Framework Detection
|
|
64
|
-
|
|
65
|
-
The script auto-detects frameworks from `package.json`. Supported frameworks include:
|
|
66
|
-
|
|
67
|
-
- **React**: Next.js, Gatsby, Create React App, Remix, React Router
|
|
68
|
-
- **Vue**: Nuxt, Vitepress, Vuepress, Gridsome
|
|
69
|
-
- **Svelte**: SvelteKit, Svelte, Sapper
|
|
70
|
-
- **Other Frontend**: Astro, Solid Start, Angular, Ember, Preact, Docusaurus
|
|
71
|
-
- **Backend**: Express, Hono, Fastify, NestJS, Elysia, h3, Nitro
|
|
72
|
-
- **Build Tools**: Vite, Parcel
|
|
73
|
-
- **And more**: Blitz, Hydrogen, RedwoodJS, Storybook, Sanity, etc.
|
|
74
|
-
|
|
75
|
-
For static HTML projects (no `package.json`), framework is set to `null`.
|
|
76
|
-
|
|
77
|
-
## Static HTML Projects
|
|
78
|
-
|
|
79
|
-
For projects without a `package.json`:
|
|
80
|
-
- If there's a single `.html` file not named `index.html`, it gets renamed automatically
|
|
81
|
-
- This ensures the page is served at the root URL (`/`)
|
|
82
|
-
|
|
83
|
-
## Present Results to User
|
|
84
|
-
|
|
85
|
-
Always show both URLs:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
✓ Deployment successful!
|
|
89
|
-
|
|
90
|
-
Preview URL: https://skill-deploy-abc123.vercel.app
|
|
91
|
-
Claim URL: https://vercel.com/claim-deployment?code=...
|
|
92
|
-
|
|
93
|
-
View your site at the Preview URL.
|
|
94
|
-
To transfer this deployment to your Vercel account, visit the Claim URL.
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Troubleshooting
|
|
98
|
-
|
|
99
|
-
### Network Egress Error
|
|
100
|
-
|
|
101
|
-
If deployment fails due to network restrictions (common on claude.ai), tell the user:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
Deployment failed due to network restrictions. To fix this:
|
|
105
|
-
|
|
106
|
-
1. Go to https://claude.ai/admin-settings/capabilities
|
|
107
|
-
2. Add *.vercel.com to the allowed domains
|
|
108
|
-
3. Try deploying again
|
|
109
|
-
```
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Vercel Deployment Script (via claimable deploy endpoint)
|
|
4
|
-
# Usage: ./deploy.sh [project-path]
|
|
5
|
-
# Returns: JSON with previewUrl, claimUrl, deploymentId, projectId
|
|
6
|
-
|
|
7
|
-
set -e
|
|
8
|
-
|
|
9
|
-
DEPLOY_ENDPOINT="https://claude-skills-deploy.vercel.com/api/deploy"
|
|
10
|
-
|
|
11
|
-
# Detect framework from package.json
|
|
12
|
-
detect_framework() {
|
|
13
|
-
local pkg_json="$1"
|
|
14
|
-
|
|
15
|
-
if [ ! -f "$pkg_json" ]; then
|
|
16
|
-
echo "null"
|
|
17
|
-
return
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
local content=$(cat "$pkg_json")
|
|
21
|
-
|
|
22
|
-
# Helper to check if a package exists in dependencies or devDependencies
|
|
23
|
-
has_dep() {
|
|
24
|
-
echo "$content" | grep -q "\"$1\""
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
# Order matters - check more specific frameworks first
|
|
28
|
-
|
|
29
|
-
# Blitz
|
|
30
|
-
if has_dep "blitz"; then echo "blitzjs"; return; fi
|
|
31
|
-
|
|
32
|
-
# Next.js
|
|
33
|
-
if has_dep "next"; then echo "nextjs"; return; fi
|
|
34
|
-
|
|
35
|
-
# Gatsby
|
|
36
|
-
if has_dep "gatsby"; then echo "gatsby"; return; fi
|
|
37
|
-
|
|
38
|
-
# Remix
|
|
39
|
-
if has_dep "@remix-run/"; then echo "remix"; return; fi
|
|
40
|
-
|
|
41
|
-
# React Router (v7 framework mode)
|
|
42
|
-
if has_dep "@react-router/"; then echo "react-router"; return; fi
|
|
43
|
-
|
|
44
|
-
# TanStack Start
|
|
45
|
-
if has_dep "@tanstack/start"; then echo "tanstack-start"; return; fi
|
|
46
|
-
|
|
47
|
-
# Astro
|
|
48
|
-
if has_dep "astro"; then echo "astro"; return; fi
|
|
49
|
-
|
|
50
|
-
# Hydrogen (Shopify)
|
|
51
|
-
if has_dep "@shopify/hydrogen"; then echo "hydrogen"; return; fi
|
|
52
|
-
|
|
53
|
-
# SvelteKit
|
|
54
|
-
if has_dep "@sveltejs/kit"; then echo "sveltekit-1"; return; fi
|
|
55
|
-
|
|
56
|
-
# Svelte (standalone)
|
|
57
|
-
if has_dep "svelte"; then echo "svelte"; return; fi
|
|
58
|
-
|
|
59
|
-
# Nuxt
|
|
60
|
-
if has_dep "nuxt"; then echo "nuxtjs"; return; fi
|
|
61
|
-
|
|
62
|
-
# Vue with Vitepress
|
|
63
|
-
if has_dep "vitepress"; then echo "vitepress"; return; fi
|
|
64
|
-
|
|
65
|
-
# Vue with Vuepress
|
|
66
|
-
if has_dep "vuepress"; then echo "vuepress"; return; fi
|
|
67
|
-
|
|
68
|
-
# Gridsome
|
|
69
|
-
if has_dep "gridsome"; then echo "gridsome"; return; fi
|
|
70
|
-
|
|
71
|
-
# SolidStart
|
|
72
|
-
if has_dep "@solidjs/start"; then echo "solidstart-1"; return; fi
|
|
73
|
-
|
|
74
|
-
# Docusaurus
|
|
75
|
-
if has_dep "@docusaurus/core"; then echo "docusaurus-2"; return; fi
|
|
76
|
-
|
|
77
|
-
# RedwoodJS
|
|
78
|
-
if has_dep "@redwoodjs/"; then echo "redwoodjs"; return; fi
|
|
79
|
-
|
|
80
|
-
# Hexo
|
|
81
|
-
if has_dep "hexo"; then echo "hexo"; return; fi
|
|
82
|
-
|
|
83
|
-
# Eleventy
|
|
84
|
-
if has_dep "@11ty/eleventy"; then echo "eleventy"; return; fi
|
|
85
|
-
|
|
86
|
-
# Angular / Ionic Angular
|
|
87
|
-
if has_dep "@ionic/angular"; then echo "ionic-angular"; return; fi
|
|
88
|
-
if has_dep "@angular/core"; then echo "angular"; return; fi
|
|
89
|
-
|
|
90
|
-
# Ionic React
|
|
91
|
-
if has_dep "@ionic/react"; then echo "ionic-react"; return; fi
|
|
92
|
-
|
|
93
|
-
# Create React App
|
|
94
|
-
if has_dep "react-scripts"; then echo "create-react-app"; return; fi
|
|
95
|
-
|
|
96
|
-
# Ember
|
|
97
|
-
if has_dep "ember-cli" || has_dep "ember-source"; then echo "ember"; return; fi
|
|
98
|
-
|
|
99
|
-
# Dojo
|
|
100
|
-
if has_dep "@dojo/framework"; then echo "dojo"; return; fi
|
|
101
|
-
|
|
102
|
-
# Polymer
|
|
103
|
-
if has_dep "@polymer/"; then echo "polymer"; return; fi
|
|
104
|
-
|
|
105
|
-
# Preact
|
|
106
|
-
if has_dep "preact"; then echo "preact"; return; fi
|
|
107
|
-
|
|
108
|
-
# Stencil
|
|
109
|
-
if has_dep "@stencil/core"; then echo "stencil"; return; fi
|
|
110
|
-
|
|
111
|
-
# UmiJS
|
|
112
|
-
if has_dep "umi"; then echo "umijs"; return; fi
|
|
113
|
-
|
|
114
|
-
# Sapper (legacy Svelte)
|
|
115
|
-
if has_dep "sapper"; then echo "sapper"; return; fi
|
|
116
|
-
|
|
117
|
-
# Saber
|
|
118
|
-
if has_dep "saber"; then echo "saber"; return; fi
|
|
119
|
-
|
|
120
|
-
# Sanity
|
|
121
|
-
if has_dep "sanity"; then echo "sanity-v3"; return; fi
|
|
122
|
-
if has_dep "@sanity/"; then echo "sanity"; return; fi
|
|
123
|
-
|
|
124
|
-
# Storybook
|
|
125
|
-
if has_dep "@storybook/"; then echo "storybook"; return; fi
|
|
126
|
-
|
|
127
|
-
# NestJS
|
|
128
|
-
if has_dep "@nestjs/core"; then echo "nestjs"; return; fi
|
|
129
|
-
|
|
130
|
-
# Elysia
|
|
131
|
-
if has_dep "elysia"; then echo "elysia"; return; fi
|
|
132
|
-
|
|
133
|
-
# Hono
|
|
134
|
-
if has_dep "hono"; then echo "hono"; return; fi
|
|
135
|
-
|
|
136
|
-
# Fastify
|
|
137
|
-
if has_dep "fastify"; then echo "fastify"; return; fi
|
|
138
|
-
|
|
139
|
-
# h3
|
|
140
|
-
if has_dep "h3"; then echo "h3"; return; fi
|
|
141
|
-
|
|
142
|
-
# Nitro
|
|
143
|
-
if has_dep "nitropack"; then echo "nitro"; return; fi
|
|
144
|
-
|
|
145
|
-
# Express
|
|
146
|
-
if has_dep "express"; then echo "express"; return; fi
|
|
147
|
-
|
|
148
|
-
# Vite (generic - check last among JS frameworks)
|
|
149
|
-
if has_dep "vite"; then echo "vite"; return; fi
|
|
150
|
-
|
|
151
|
-
# Parcel
|
|
152
|
-
if has_dep "parcel"; then echo "parcel"; return; fi
|
|
153
|
-
|
|
154
|
-
# No framework detected
|
|
155
|
-
echo "null"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# Parse arguments
|
|
159
|
-
INPUT_PATH="${1:-.}"
|
|
160
|
-
|
|
161
|
-
# Create temp directory for packaging
|
|
162
|
-
TEMP_DIR=$(mktemp -d)
|
|
163
|
-
TARBALL="$TEMP_DIR/project.tgz"
|
|
164
|
-
CLEANUP_TEMP=true
|
|
165
|
-
|
|
166
|
-
cleanup() {
|
|
167
|
-
if [ "$CLEANUP_TEMP" = true ]; then
|
|
168
|
-
rm -rf "$TEMP_DIR"
|
|
169
|
-
fi
|
|
170
|
-
}
|
|
171
|
-
trap cleanup EXIT
|
|
172
|
-
|
|
173
|
-
echo "Preparing deployment..." >&2
|
|
174
|
-
|
|
175
|
-
# Check if input is a .tgz file or a directory
|
|
176
|
-
FRAMEWORK="null"
|
|
177
|
-
|
|
178
|
-
if [ -f "$INPUT_PATH" ] && [[ "$INPUT_PATH" == *.tgz ]]; then
|
|
179
|
-
# Input is already a tarball, use it directly
|
|
180
|
-
echo "Using provided tarball..." >&2
|
|
181
|
-
TARBALL="$INPUT_PATH"
|
|
182
|
-
CLEANUP_TEMP=false
|
|
183
|
-
# Can't detect framework from tarball, leave as null
|
|
184
|
-
elif [ -d "$INPUT_PATH" ]; then
|
|
185
|
-
# Input is a directory, need to tar it
|
|
186
|
-
PROJECT_PATH=$(cd "$INPUT_PATH" && pwd)
|
|
187
|
-
|
|
188
|
-
# Detect framework from package.json
|
|
189
|
-
FRAMEWORK=$(detect_framework "$PROJECT_PATH/package.json")
|
|
190
|
-
|
|
191
|
-
# Check if this is a static HTML project (no package.json)
|
|
192
|
-
if [ ! -f "$PROJECT_PATH/package.json" ]; then
|
|
193
|
-
# Find HTML files in root
|
|
194
|
-
HTML_FILES=$(find "$PROJECT_PATH" -maxdepth 1 -name "*.html" -type f)
|
|
195
|
-
HTML_COUNT=$(echo "$HTML_FILES" | grep -c . || echo 0)
|
|
196
|
-
|
|
197
|
-
# If there's exactly one HTML file and it's not index.html, rename it
|
|
198
|
-
if [ "$HTML_COUNT" -eq 1 ]; then
|
|
199
|
-
HTML_FILE=$(echo "$HTML_FILES" | head -1)
|
|
200
|
-
BASENAME=$(basename "$HTML_FILE")
|
|
201
|
-
if [ "$BASENAME" != "index.html" ]; then
|
|
202
|
-
echo "Renaming $BASENAME to index.html..." >&2
|
|
203
|
-
mv "$HTML_FILE" "$PROJECT_PATH/index.html"
|
|
204
|
-
fi
|
|
205
|
-
fi
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
# Create tarball of the project (excluding node_modules and .git)
|
|
209
|
-
echo "Creating deployment package..." >&2
|
|
210
|
-
tar -czf "$TARBALL" -C "$PROJECT_PATH" --exclude='node_modules' --exclude='.git' .
|
|
211
|
-
else
|
|
212
|
-
echo "Error: Input must be a directory or a .tgz file" >&2
|
|
213
|
-
exit 1
|
|
214
|
-
fi
|
|
215
|
-
|
|
216
|
-
if [ "$FRAMEWORK" != "null" ]; then
|
|
217
|
-
echo "Detected framework: $FRAMEWORK" >&2
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Deploy
|
|
221
|
-
echo "Deploying..." >&2
|
|
222
|
-
RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")
|
|
223
|
-
|
|
224
|
-
# Check for error in response
|
|
225
|
-
if echo "$RESPONSE" | grep -q '"error"'; then
|
|
226
|
-
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"error":"[^"]*"' | cut -d'"' -f4)
|
|
227
|
-
echo "Error: $ERROR_MSG" >&2
|
|
228
|
-
exit 1
|
|
229
|
-
fi
|
|
230
|
-
|
|
231
|
-
# Extract URLs from response
|
|
232
|
-
PREVIEW_URL=$(echo "$RESPONSE" | grep -o '"previewUrl":"[^"]*"' | cut -d'"' -f4)
|
|
233
|
-
CLAIM_URL=$(echo "$RESPONSE" | grep -o '"claimUrl":"[^"]*"' | cut -d'"' -f4)
|
|
234
|
-
|
|
235
|
-
if [ -z "$PREVIEW_URL" ]; then
|
|
236
|
-
echo "Error: Could not extract preview URL from response" >&2
|
|
237
|
-
echo "$RESPONSE" >&2
|
|
238
|
-
exit 1
|
|
239
|
-
fi
|
|
240
|
-
|
|
241
|
-
echo "" >&2
|
|
242
|
-
echo "Deployment successful!" >&2
|
|
243
|
-
echo "" >&2
|
|
244
|
-
echo "Preview URL: $PREVIEW_URL" >&2
|
|
245
|
-
echo "Claim URL: $CLAIM_URL" >&2
|
|
246
|
-
echo "" >&2
|
|
247
|
-
|
|
248
|
-
# Output JSON for programmatic use
|
|
249
|
-
echo "$RESPONSE"
|