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 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), and [Codex](https://developers.openai.com/codex).
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.2",
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,4 +1,4 @@
1
- export type AgentType = 'opencode' | 'claude-code' | 'codex';
1
+ export type AgentType = 'opencode' | 'claude-code' | 'codex' | 'cursor';
2
2
 
3
3
  export interface Skill {
4
4
  name: string;
@@ -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"