Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
wisp.place
1import {
2 Card,
3 CardContent,
4 CardDescription,
5 CardHeader,
6 CardTitle
7} from '@public/components/ui/card'
8import { Badge } from '@public/components/ui/badge'
9import { ExternalLink } from 'lucide-react'
10import { CodeBlock } from '@public/components/ui/code-block'
11
12export function CLITab() {
13 return (
14 <div className="space-y-4 min-h-[400px]">
15 <Card>
16 <CardHeader>
17 <div className="flex items-center gap-2 mb-2">
18 <CardTitle>Wisp CLI Tool</CardTitle>
19 <Badge variant="secondary" className="text-xs">v0.2.0</Badge>
20 <Badge variant="outline" className="text-xs">Alpha</Badge>
21 </div>
22 <CardDescription>
23 Deploy static sites directly from your terminal
24 </CardDescription>
25 </CardHeader>
26 <CardContent className="space-y-6">
27 <div className="prose prose-sm max-w-none dark:prose-invert">
28 <p className="text-sm text-muted-foreground">
29 The Wisp CLI is a command-line tool for deploying static websites directly to your AT Protocol account.
30 Authenticate with app password or OAuth and deploy from CI/CD pipelines.
31 </p>
32 </div>
33
34 <div className="space-y-3">
35 <h3 className="text-sm font-semibold">Features</h3>
36 <ul className="text-sm text-muted-foreground space-y-2 list-disc list-inside">
37 <li><strong>Deploy:</strong> Push static sites directly from your terminal</li>
38 <li><strong>Pull:</strong> Download sites from the PDS for development or backup</li>
39 <li><strong>Serve:</strong> Run a local server with real-time firehose updates</li>
40 </ul>
41 </div>
42
43 <div className="space-y-3">
44 <h3 className="text-sm font-semibold">Download v0.2.0</h3>
45 <div className="grid gap-2">
46 <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
47 <a
48 href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin"
49 target="_blank"
50 rel="noopener noreferrer"
51 className="flex items-center justify-between mb-2"
52 >
53 <span className="font-mono text-sm">macOS (Apple Silicon)</span>
54 <ExternalLink className="w-4 h-4 text-muted-foreground" />
55 </a>
56 <div className="text-xs text-muted-foreground">
57 <span className="font-mono">SHA-1: a8c27ea41c5e2672bfecb3476ece1c801741d759</span>
58 </div>
59 </div>
60 <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
61 <a
62 href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-linux"
63 target="_blank"
64 rel="noopener noreferrer"
65 className="flex items-center justify-between mb-2"
66 >
67 <span className="font-mono text-sm">Linux (ARM64)</span>
68 <ExternalLink className="w-4 h-4 text-muted-foreground" />
69 </a>
70 <div className="text-xs text-muted-foreground">
71 <span className="font-mono">SHA-1: fd7ee689c7600fc953179ea755b0357c8481a622</span>
72 </div>
73 </div>
74 <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
75 <a
76 href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux"
77 target="_blank"
78 rel="noopener noreferrer"
79 className="flex items-center justify-between mb-2"
80 >
81 <span className="font-mono text-sm">Linux (x86_64)</span>
82 <ExternalLink className="w-4 h-4 text-muted-foreground" />
83 </a>
84 <div className="text-xs text-muted-foreground">
85 <span className="font-mono">SHA-1: 8bca6992559e19e1d29ab3d2fcc6d09b28e5a485</span>
86 </div>
87 </div>
88 <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
89 <a
90 href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-windows.exe"
91 target="_blank"
92 rel="noopener noreferrer"
93 className="flex items-center justify-between mb-2"
94 >
95 <span className="font-mono text-sm">Windows (x86_64)</span>
96 <ExternalLink className="w-4 h-4 text-muted-foreground" />
97 </a>
98 <div className="text-xs text-muted-foreground">
99 <span className="font-mono">SHA-1: 90ea3987a06597fa6c42e1df9009e9758e92dd54</span>
100 </div>
101 </div>
102 </div>
103 </div>
104
105 <div className="space-y-3">
106 <h3 className="text-sm font-semibold">Deploy a Site</h3>
107 <CodeBlock
108 code={`# Download and make executable
109curl -O https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin
110chmod +x wisp-cli-aarch64-darwin
111
112# Deploy your site
113./wisp-cli-aarch64-darwin deploy your-handle.bsky.social \\
114 --path ./dist \\
115 --site my-site \\
116 --password your-app-password
117
118# Your site will be available at:
119# https://sites.wisp.place/your-handle/my-site`}
120 language="bash"
121 />
122 </div>
123
124 <div className="space-y-3">
125 <h3 className="text-sm font-semibold">Pull a Site from PDS</h3>
126 <p className="text-xs text-muted-foreground">
127 Download a site from the PDS to your local machine (uses OAuth authentication):
128 </p>
129 <CodeBlock
130 code={`# Pull a site to a specific directory
131wisp-cli pull your-handle.bsky.social \\
132 --site my-site \\
133 --output ./my-site
134
135# Pull to current directory
136wisp-cli pull your-handle.bsky.social \\
137 --site my-site
138
139# Opens browser for OAuth authentication on first run`}
140 language="bash"
141 />
142 </div>
143
144 <div className="space-y-3">
145 <h3 className="text-sm font-semibold">Serve a Site Locally with Real-Time Updates</h3>
146 <p className="text-xs text-muted-foreground">
147 Run a local server that monitors the firehose for real-time updates (uses OAuth authentication):
148 </p>
149 <CodeBlock
150 code={`# Serve on http://localhost:8080 (default)
151wisp-cli serve your-handle.bsky.social \\
152 --site my-site
153
154# Serve on a custom port
155wisp-cli serve your-handle.bsky.social \\
156 --site my-site \\
157 --port 3000
158
159# Downloads site, serves it, and watches firehose for live updates!`}
160 language="bash"
161 />
162 </div>
163
164 <div className="space-y-3">
165 <h3 className="text-sm font-semibold">CI/CD with Tangled Spindle</h3>
166 <p className="text-xs text-muted-foreground">
167 Deploy automatically on every push using{' '}
168 <a
169 href="https://blog.tangled.org/ci"
170 target="_blank"
171 rel="noopener noreferrer"
172 className="text-accent hover:underline"
173 >
174 Tangled Spindle
175 </a>
176 </p>
177
178 <div className="space-y-4">
179 <div>
180 <h4 className="text-xs font-semibold mb-2 flex items-center gap-2">
181 <span>Example 1: Simple Asset Publishing</span>
182 <Badge variant="secondary" className="text-xs">Copy Files</Badge>
183 </h4>
184 <CodeBlock
185 code={`when:
186 - event: ['push']
187 branch: ['main']
188 - event: ['manual']
189
190engine: 'nixery'
191
192clone:
193 skip: false
194 depth: 1
195
196dependencies:
197 nixpkgs:
198 - coreutils
199 - curl
200
201environment:
202 SITE_PATH: '.' # Copy entire repo
203 SITE_NAME: 'myWebbedSite'
204 WISP_HANDLE: 'your-handle.bsky.social'
205
206steps:
207 - name: deploy assets to wisp
208 command: |
209 # Download Wisp CLI
210 curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli
211 chmod +x wisp-cli
212
213 # Deploy to Wisp
214 ./wisp-cli deploy \\
215 "$WISP_HANDLE" \\
216 --path "$SITE_PATH" \\
217 --site "$SITE_NAME" \\
218 --password "$WISP_APP_PASSWORD"
219
220 # Output
221 #Deployed site 'myWebbedSite': at://did:plc:ttdrpj45ibqunmfhdsb4zdwq/place.wisp.fs/myWebbedSite
222 #Available at: https://sites.wisp.place/did:plc:ttdrpj45ibqunmfhdsb4zdwq/myWebbedSite
223 `}
224 language="yaml"
225 />
226 </div>
227
228 <div>
229 <h4 className="text-xs font-semibold mb-2 flex items-center gap-2">
230 <span>Example 2: React/Vite Build & Deploy</span>
231 <Badge variant="secondary" className="text-xs">Full Build</Badge>
232 </h4>
233 <CodeBlock
234 code={`when:
235 - event: ['push']
236 branch: ['main']
237 - event: ['manual']
238
239engine: 'nixery'
240
241clone:
242 skip: false
243 depth: 1
244 submodules: false
245
246dependencies:
247 nixpkgs:
248 - nodejs
249 - coreutils
250 - curl
251 github:NixOS/nixpkgs/nixpkgs-unstable:
252 - bun
253
254environment:
255 SITE_PATH: 'dist'
256 SITE_NAME: 'my-react-site'
257 WISP_HANDLE: 'your-handle.bsky.social'
258
259steps:
260 - name: build site
261 command: |
262 # necessary to ensure bun is in PATH
263 export PATH="$HOME/.nix-profile/bin:$PATH"
264
265 bun install --frozen-lockfile
266
267 # build with vite, run directly to get around env issues
268 bun node_modules/.bin/vite build
269
270 - name: deploy to wisp
271 command: |
272 # Download Wisp CLI
273 curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli
274 chmod +x wisp-cli
275
276 # Deploy to Wisp
277 ./wisp-cli deploy \\
278 "$WISP_HANDLE" \\
279 --path "$SITE_PATH" \\
280 --site "$SITE_NAME" \\
281 --password "$WISP_APP_PASSWORD"`}
282 language="yaml"
283 />
284 </div>
285 </div>
286
287 <div className="p-3 bg-muted/30 rounded-lg border-l-4 border-accent">
288 <p className="text-xs text-muted-foreground">
289 <strong className="text-foreground">Note:</strong> Set <code className="px-1.5 py-0.5 bg-background rounded text-xs">WISP_APP_PASSWORD</code> as a secret in your Tangled Spindle repository settings.
290 Generate an app password from your AT Protocol account settings.
291 </p>
292 </div>
293 </div>
294
295 <div className="space-y-3">
296 <h3 className="text-sm font-semibold">Learn More</h3>
297 <div className="grid gap-2">
298 <a
299 href="https://tangled.org/@nekomimi.pet/wisp.place-monorepo/tree/main/cli"
300 target="_blank"
301 rel="noopener noreferrer"
302 className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"
303 >
304 <span className="text-sm">Source Code</span>
305 <ExternalLink className="w-4 h-4 text-muted-foreground" />
306 </a>
307 <a
308 href="https://blog.tangled.org/ci"
309 target="_blank"
310 rel="noopener noreferrer"
311 className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"
312 >
313 <span className="text-sm">Tangled Spindle CI/CD</span>
314 <ExternalLink className="w-4 h-4 text-muted-foreground" />
315 </a>
316 </div>
317 </div>
318 </CardContent>
319 </Card>
320 </div>
321 )
322}