shiply-cli 0.3.0 → 0.4.1
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/dist/confetti.js +1 -1
- package/dist/index.js +13 -1
- package/dist/skill.js +29 -0
- package/package.json +2 -2
- package/skill/SKILL.md +75 -0
package/dist/confetti.js
CHANGED
|
@@ -2,7 +2,7 @@ const GLYPHS = ['✦', '✧', '★', '☆', '●', '◆', '▲', '■', '♥', '
|
|
|
2
2
|
const COLORS = [196, 202, 208, 220, 226, 118, 46, 51, 45, 39, 99, 201, 207, 213];
|
|
3
3
|
const ESC = '\x1b';
|
|
4
4
|
/** Full-width ANSI confetti burst — sites going live deserve a party. */
|
|
5
|
-
export function confetti(message = '
|
|
5
|
+
export function confetti(message = '⛵ SITE IS LIVE ⛵') {
|
|
6
6
|
const cols = Math.min(process.stdout.columns ?? 80, 100);
|
|
7
7
|
const rows = Math.min(Math.max((process.stdout.rows ?? 24) - 6, 8), 18);
|
|
8
8
|
let out = '\n';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { parseArgs } from 'node:util';
|
|
|
4
4
|
import { confetti } from './confetti.js';
|
|
5
5
|
import { loadApiKey, saveApiKey } from './config.js';
|
|
6
6
|
import { api, DEFAULT_BASE, publish, resolveBase } from './publish.js';
|
|
7
|
+
import { installSkill } from './skill.js';
|
|
7
8
|
import { readState, writeState } from './state.js';
|
|
8
9
|
import { checkReadiness, targetToHostname } from './status.js';
|
|
9
10
|
const HELP = `shiply — instant static hosting for agents (https://shiply.now)
|
|
@@ -13,6 +14,8 @@ Usage:
|
|
|
13
14
|
Re-running UPDATES the same site (state in .shiply.json)
|
|
14
15
|
shiply update <dir> Same as publish when .shiply.json exists
|
|
15
16
|
shiply status <slug-or-domain> [--wait] SSL + readiness check (agent-friendly output)
|
|
17
|
+
shiply skill [--project] Install the shiply skill for your AI agent
|
|
18
|
+
(global ~/.claude/skills, or ./.claude/skills with --project)
|
|
16
19
|
shiply login [--email <address>] Email a 6-digit code, mint + save an API key
|
|
17
20
|
shiply help
|
|
18
21
|
|
|
@@ -69,6 +72,7 @@ async function main() {
|
|
|
69
72
|
email: { type: 'string' },
|
|
70
73
|
wait: { type: 'boolean' },
|
|
71
74
|
'new-site': { type: 'boolean' },
|
|
75
|
+
project: { type: 'boolean' },
|
|
72
76
|
timeout: { type: 'string' },
|
|
73
77
|
'no-confetti': { type: 'boolean' },
|
|
74
78
|
help: { type: 'boolean', short: 'h' },
|
|
@@ -121,7 +125,7 @@ async function main() {
|
|
|
121
125
|
if (live.status < 400) {
|
|
122
126
|
console.log(`SITE_READY url=${res.siteUrl} status=${live.status}`);
|
|
123
127
|
if (!values['no-confetti'])
|
|
124
|
-
console.log(confetti(
|
|
128
|
+
console.log(confetti(`⛵ ${host} IS LIVE ⛵`));
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
catch {
|
|
@@ -165,6 +169,14 @@ async function main() {
|
|
|
165
169
|
await new Promise((r) => setTimeout(r, 5000));
|
|
166
170
|
}
|
|
167
171
|
}
|
|
172
|
+
case 'skill': {
|
|
173
|
+
const written = await installSkill(Boolean(values.project));
|
|
174
|
+
for (const w of written)
|
|
175
|
+
console.log(`✔ skill installed — ${w}`);
|
|
176
|
+
console.log(' Your agent now knows how to publish, update (same URL!), check SSL, and more.');
|
|
177
|
+
console.log(' Restart the agent session to pick it up. Re-run after CLI upgrades.');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
168
180
|
case 'login': {
|
|
169
181
|
const base = resolveBase(values.base);
|
|
170
182
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
package/dist/skill.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/** The SKILL.md ships inside the npm package (skill/SKILL.md next to dist/). */
|
|
6
|
+
export async function bundledSkill() {
|
|
7
|
+
const here = dirname(fileURLToPath(import.meta.url)); // <pkg>/dist
|
|
8
|
+
return readFile(join(here, '..', 'skill', 'SKILL.md'), 'utf8');
|
|
9
|
+
}
|
|
10
|
+
/** Where agents look for skills. Claude Code is the reference layout
|
|
11
|
+
* (~/.claude/skills/<name>/SKILL.md); several other agents read the same
|
|
12
|
+
* format from their own folders. */
|
|
13
|
+
export function installTargets(project) {
|
|
14
|
+
if (project) {
|
|
15
|
+
return [{ agent: 'this project (Claude Code & compatible)', dir: join(process.cwd(), '.claude', 'skills', 'shiply') }];
|
|
16
|
+
}
|
|
17
|
+
return [{ agent: 'Claude Code (all projects)', dir: join(homedir(), '.claude', 'skills', 'shiply') }];
|
|
18
|
+
}
|
|
19
|
+
export async function installSkill(project) {
|
|
20
|
+
const content = await bundledSkill();
|
|
21
|
+
const written = [];
|
|
22
|
+
for (const t of installTargets(project)) {
|
|
23
|
+
await mkdir(t.dir, { recursive: true });
|
|
24
|
+
const file = join(t.dir, 'SKILL.md');
|
|
25
|
+
await writeFile(file, content);
|
|
26
|
+
written.push(`${t.agent}: ${file}`);
|
|
27
|
+
}
|
|
28
|
+
return written;
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shiply-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Publish static sites to shiply.now from the command line — instant web hosting for agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": { "shiply": "dist/index.js" },
|
|
8
|
-
"files": ["dist", "README.md"],
|
|
8
|
+
"files": ["dist", "skill", "README.md"],
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc -p tsconfig.build.json",
|
|
11
11
|
"prepublishOnly": "pnpm build",
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shiply
|
|
3
|
+
description: Publish static sites to the web instantly with shiply.now and manage them (updates, SSL checks, custom domains, variables). Use when the user asks to publish, host, deploy, share, or update a website/page/demo/report, or wants a live URL for generated files. Triggers - "publish this", "host this", "put this online", "give me a link", "update the site", shiply.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# shiply — instant web hosting for agents
|
|
7
|
+
|
|
8
|
+
shiply.now puts files on the web in seconds. No account needed to start:
|
|
9
|
+
anonymous sites are live immediately, last 24 hours, and can be claimed into
|
|
10
|
+
an account to keep them. The cardinal rule:
|
|
11
|
+
|
|
12
|
+
**NEVER create a new site to update an existing one. Always re-publish to the
|
|
13
|
+
same site** — otherwise you litter subdomains and lose the user's URL.
|
|
14
|
+
|
|
15
|
+
## Pick your interface (best first)
|
|
16
|
+
|
|
17
|
+
### 1. MCP (native tools)
|
|
18
|
+
If the `shiply` MCP server is connected (https://shiply.now/mcp), use
|
|
19
|
+
`publish_site`. Every result includes a `toUpdate` field telling you the exact
|
|
20
|
+
call for updates — follow it. Other tools: `site_status`, `list_sites`,
|
|
21
|
+
`set_handle`, `set_variable`, `add_domain`, `check_domain`, `get_analytics`,
|
|
22
|
+
`delete_site`, `rollback` via dashboard.
|
|
23
|
+
|
|
24
|
+
### 2. CLI
|
|
25
|
+
```bash
|
|
26
|
+
npm i -g shiply-cli # or: curl -fsSL https://shiply.now/install.sh | bash
|
|
27
|
+
shiply publish ./dir # live URL + confetti
|
|
28
|
+
shiply publish ./dir # run AGAIN after edits → updates the SAME site
|
|
29
|
+
shiply status <slug> --wait # SSL + readiness; prints SSL_READY / SITE_READY
|
|
30
|
+
shiply login # email code → API key → sites become permanent
|
|
31
|
+
```
|
|
32
|
+
The CLI stores each directory's site in `.shiply.json` (slug + update token),
|
|
33
|
+
so repeat publishes reuse the URL automatically. `--new-site` opts out.
|
|
34
|
+
Gitignore `.shiply.json` in public repos. Parse `SITE_READY` / `SSL_READY`
|
|
35
|
+
lines for automation; exit code 0 = ready.
|
|
36
|
+
|
|
37
|
+
### 3. Raw HTTP (no installs)
|
|
38
|
+
```
|
|
39
|
+
1. POST https://shiply.now/api/v1/publish
|
|
40
|
+
{"files":[{"path":"index.html","size":<bytes>,"contentType":"text/html","hash":"<sha256, optional>"}]}
|
|
41
|
+
(+ "Authorization: Bearer shp_…" for permanent owned sites)
|
|
42
|
+
2. PUT each file's bytes to response upload.uploads[].url
|
|
43
|
+
3. POST upload.finalizeUrl with {"versionId":"..."}
|
|
44
|
+
```
|
|
45
|
+
**Updates:** anonymous → include `"claimToken":"..."` (returned ONCE by the
|
|
46
|
+
first publish — save it); owned → include `"slug":"..."`. Hashes make updates
|
|
47
|
+
cheap: unchanged files are skipped server-side.
|
|
48
|
+
|
|
49
|
+
## The lifecycle to explain to users
|
|
50
|
+
- Anonymous site: live instantly, expires in 24 h. Give the user the
|
|
51
|
+
`claimUrl` — claiming keeps it forever on a free account.
|
|
52
|
+
- API key (`shiply login` or POST /api/auth/agent/request-code →
|
|
53
|
+
verify-code): publishes are permanent and manageable.
|
|
54
|
+
- Paid plans add vanity handles (<name>.shiply.now), more custom domains,
|
|
55
|
+
storage, analytics: https://shiply.now/dashboard/plan
|
|
56
|
+
|
|
57
|
+
## Power features (Bearer key)
|
|
58
|
+
- **Custom domains**: POST /api/v1/domains {"hostname","slug"} → tell the
|
|
59
|
+
user to CNAME the hostname to `cname.shiply.now` → cert auto-issues; poll
|
|
60
|
+
GET /api/v1/domains/{id}/check until `ready:true`.
|
|
61
|
+
- **SSL/readiness checker**: `shiply status <slug-or-domain> --wait` or the
|
|
62
|
+
check endpoint — confirms certificate + serving before telling the user
|
|
63
|
+
it's done.
|
|
64
|
+
- **Variables**: encrypted per-user KV for API keys the user's sites need
|
|
65
|
+
(GET/PUT /api/v1/variables, DELETE /api/v1/variables/{NAME}); Supabase can
|
|
66
|
+
be connected from the dashboard and lands here as SUPABASE_URL +
|
|
67
|
+
SUPABASE_ANON_KEY.
|
|
68
|
+
- **Rollback**: POST /api/v1/publish/{slug}/rollback {"versionId"} flips any
|
|
69
|
+
finalized version live instantly.
|
|
70
|
+
- **SPA**: pass `"spaMode":true` so deep links serve index.html.
|
|
71
|
+
|
|
72
|
+
## Limits & references
|
|
73
|
+
≤1000 files/site (≤50 inline via MCP), ≤100 MiB/file, 1 GiB total.
|
|
74
|
+
Machine guide: https://shiply.now/llms.txt · OpenAPI:
|
|
75
|
+
https://shiply.now/openapi.json · Docs: https://shiply.now/docs
|