add-skill 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,249 @@
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"
@@ -0,0 +1,109 @@
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
+ ```
@@ -0,0 +1,249 @@
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"