star-sdk-cli 0.1.11 → 0.1.13
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 +52 -0
- package/dist/cli.mjs +165 -11
- package/package.json +19 -3
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# star-sdk-cli
|
|
2
|
+
|
|
3
|
+
CLI for [Star SDK](https://www.npmjs.com/package/star-sdk) — register games, deploy to hosting, and install AI coding docs.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
All commands run via `npx star-sdk` (no global install needed).
|
|
8
|
+
|
|
9
|
+
### Commands
|
|
10
|
+
|
|
11
|
+
| Command | Description |
|
|
12
|
+
|---------|-------------|
|
|
13
|
+
| `npx star-sdk init "Game Name"` | Register a game, get a gameId and deploy key |
|
|
14
|
+
| `npx star-sdk deploy [path]` | Deploy your game to Star hosting |
|
|
15
|
+
| `npx star-sdk install [agent]` | Install SDK docs for AI coding tools |
|
|
16
|
+
| `npx star-sdk docs [topic]` | Print API docs (audio, canvas, leaderboard) |
|
|
17
|
+
| `npx star-sdk whoami` | Show current game config |
|
|
18
|
+
|
|
19
|
+
### Workflow
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 1. Register your game
|
|
23
|
+
npx star-sdk init "My Game"
|
|
24
|
+
# Creates .starrc with gameId and deploy key
|
|
25
|
+
|
|
26
|
+
# 2. Build your game (use the gameId from .starrc)
|
|
27
|
+
# ... write your game code ...
|
|
28
|
+
|
|
29
|
+
# 3. Deploy
|
|
30
|
+
npx star-sdk deploy
|
|
31
|
+
# => Live at https://buildwithstar.com/games/<id>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### AI Agent Support
|
|
35
|
+
|
|
36
|
+
Install SDK documentation directly into your AI coding tool:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx star-sdk install # Claude Code (default)
|
|
40
|
+
npx star-sdk install cursor # Cursor
|
|
41
|
+
npx star-sdk install codex # OpenAI Codex
|
|
42
|
+
npx star-sdk install windsurf # Windsurf
|
|
43
|
+
npx star-sdk install aider # Aider
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Documentation
|
|
47
|
+
|
|
48
|
+
Full docs at [buildwithstar.com/docs/sdk](https://buildwithstar.com/docs/sdk)
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
package/dist/cli.mjs
CHANGED
|
@@ -89,6 +89,20 @@ function gameOver(finalScore) {
|
|
|
89
89
|
}
|
|
90
90
|
\`\`\`
|
|
91
91
|
|
|
92
|
+
### Lower-is-Better Games (Time, Moves, Golf)
|
|
93
|
+
|
|
94
|
+
For games where lower scores win, set \`sort: 'asc'\` in \`Star.init()\`:
|
|
95
|
+
|
|
96
|
+
\`\`\`javascript
|
|
97
|
+
Star.init({ gameId: '<gameId from .starrc>', leaderboard: { sort: 'asc' } });
|
|
98
|
+
|
|
99
|
+
// Submit the raw value \u2014 do NOT invert the score
|
|
100
|
+
Star.leaderboard.submit(reactionTimeMs);
|
|
101
|
+
Star.leaderboard.show();
|
|
102
|
+
\`\`\`
|
|
103
|
+
|
|
104
|
+
**Do NOT** invert scores to fake ascending order (e.g., \`10000 - score\`). Use \`sort: 'asc'\` instead.
|
|
105
|
+
|
|
92
106
|
### Audio (It Just Works)
|
|
93
107
|
|
|
94
108
|
Star.audio handles mobile audio unlocking automatically. Just call \`play()\` - no special handling needed.
|
|
@@ -207,6 +221,26 @@ Star.game(ctx => {
|
|
|
207
221
|
\`\`\`
|
|
208
222
|
|
|
209
223
|
For detailed API documentation, see the linked files above.
|
|
224
|
+
|
|
225
|
+
## Examples
|
|
226
|
+
|
|
227
|
+
Complete working games are in the \`examples/\` directory (also published with the npm package):
|
|
228
|
+
|
|
229
|
+
- **click-frenzy** \u2014 5-second click speed game with leaderboard
|
|
230
|
+
- **dodge** \u2014 Avoid falling obstacles, keyboard and touch controls
|
|
231
|
+
- **reaction-time** \u2014 Test your reflexes over 5 rounds, DOM-based (no canvas)
|
|
232
|
+
|
|
233
|
+
Each example is a single HTML file, no build step \u2014 imports from esm.sh.
|
|
234
|
+
|
|
235
|
+
## Deploy
|
|
236
|
+
|
|
237
|
+
When the game is ready, deploy it with one command:
|
|
238
|
+
|
|
239
|
+
\`\`\`bash
|
|
240
|
+
npx star-sdk deploy
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
This uploads the game to Star hosting and returns a live URL. Requires \`npx star-sdk init\` to have been run first (which creates the deploy key in \`.starrc\`).
|
|
210
244
|
`;
|
|
211
245
|
var AUDIO_DOCS = `**Installation**
|
|
212
246
|
|
|
@@ -1074,7 +1108,7 @@ game(({ ctx, width, height, loop, ui, on, canvas }) => {
|
|
|
1074
1108
|
- Score submission (works for guests and logged-in users)
|
|
1075
1109
|
- Leaderboard UI (modal with rankings)
|
|
1076
1110
|
- Weekly/all-time timeframes
|
|
1077
|
-
-
|
|
1111
|
+
- Configurable sort order (\`'asc'\` for lower-is-better, \`'desc'\` for higher-is-better)
|
|
1078
1112
|
|
|
1079
1113
|
---
|
|
1080
1114
|
|
|
@@ -1265,6 +1299,27 @@ const data = await leaderboard.getScores({
|
|
|
1265
1299
|
|
|
1266
1300
|
---
|
|
1267
1301
|
|
|
1302
|
+
**Sort Order:**
|
|
1303
|
+
|
|
1304
|
+
By default, leaderboards rank higher scores first (\`'desc'\`). For games where lower is better (reaction time, speedruns, golf), set \`sort: 'asc'\`:
|
|
1305
|
+
|
|
1306
|
+
\`\`\`javascript
|
|
1307
|
+
const leaderboard = createLeaderboard({ gameId: '<gameId from .starrc>', sort: 'asc' });
|
|
1308
|
+
\`\`\`
|
|
1309
|
+
|
|
1310
|
+
**IMPORTANT: Do NOT invert scores to fake ascending order.** Use \`sort: 'asc'\` instead.
|
|
1311
|
+
|
|
1312
|
+
\`\`\`javascript
|
|
1313
|
+
// BAD \u2014 do not do this
|
|
1314
|
+
leaderboard.submit(10000 - reactionTimeMs);
|
|
1315
|
+
|
|
1316
|
+
// GOOD \u2014 submit the real value with sort: 'asc'
|
|
1317
|
+
const leaderboard = createLeaderboard({ gameId, sort: 'asc' });
|
|
1318
|
+
leaderboard.submit(reactionTimeMs);
|
|
1319
|
+
\`\`\`
|
|
1320
|
+
|
|
1321
|
+
---
|
|
1322
|
+
|
|
1268
1323
|
**Tips:**
|
|
1269
1324
|
|
|
1270
1325
|
1. **Call \`submit()\` before \`show()\`** - Ensures your score appears immediately in the leaderboard.
|
|
@@ -1309,6 +1364,7 @@ ${colors.bright}Star SDK CLI${colors.reset} v${VERSION}
|
|
|
1309
1364
|
|
|
1310
1365
|
${colors.dim}Commands:${colors.reset}
|
|
1311
1366
|
${colors.cyan}init <name>${colors.reset} Register a new game
|
|
1367
|
+
${colors.cyan}deploy [path]${colors.reset} Deploy game to Star hosting
|
|
1312
1368
|
${colors.cyan}install [agent]${colors.reset} Install Star SDK docs for AI coding agents
|
|
1313
1369
|
${colors.cyan}docs [topic]${colors.reset} Print API documentation (default: all docs)
|
|
1314
1370
|
${colors.cyan}whoami${colors.reset} Show current configuration
|
|
@@ -1331,6 +1387,10 @@ ${colors.dim}Examples:${colors.reset}
|
|
|
1331
1387
|
${colors.dim}# Register a new game${colors.reset}
|
|
1332
1388
|
npx star-sdk init "My Awesome Game"
|
|
1333
1389
|
|
|
1390
|
+
${colors.dim}# Deploy to Star hosting${colors.reset}
|
|
1391
|
+
npx star-sdk deploy ${colors.dim}# Deploy current directory${colors.reset}
|
|
1392
|
+
npx star-sdk deploy ./dist ${colors.dim}# Deploy specific directory${colors.reset}
|
|
1393
|
+
|
|
1334
1394
|
${colors.dim}# Install for different AI agents${colors.reset}
|
|
1335
1395
|
npx star-sdk install ${colors.dim}# Claude Code (default)${colors.reset}
|
|
1336
1396
|
npx star-sdk install codex ${colors.dim}# OpenAI Codex${colors.reset}
|
|
@@ -1343,7 +1403,7 @@ ${colors.dim}Examples:${colors.reset}
|
|
|
1343
1403
|
npx star-sdk docs audio ${colors.dim}# Just audio API${colors.reset}
|
|
1344
1404
|
npx star-sdk docs skill ${colors.dim}# Just main skill file${colors.reset}
|
|
1345
1405
|
|
|
1346
|
-
${colors.dim}Learn more:${colors.reset} https://buildwithstar.com/docs
|
|
1406
|
+
${colors.dim}Learn more:${colors.reset} https://buildwithstar.com/docs/sdk
|
|
1347
1407
|
`);
|
|
1348
1408
|
}
|
|
1349
1409
|
function showVersion() {
|
|
@@ -1403,7 +1463,8 @@ async function initCommand(name, email) {
|
|
|
1403
1463
|
gameId: data.gameId,
|
|
1404
1464
|
name: data.name,
|
|
1405
1465
|
email: email?.trim(),
|
|
1406
|
-
dashboardUrl: data.dashboardUrl
|
|
1466
|
+
dashboardUrl: data.dashboardUrl,
|
|
1467
|
+
deployKey: data.deployKey
|
|
1407
1468
|
};
|
|
1408
1469
|
saveConfig(config);
|
|
1409
1470
|
log("");
|
|
@@ -1415,20 +1476,20 @@ async function initCommand(name, email) {
|
|
|
1415
1476
|
log(`${colors.dim}Config saved to${colors.reset} ${colors.bright}.starrc${colors.reset}`);
|
|
1416
1477
|
log("");
|
|
1417
1478
|
log(`${colors.dim}Next steps:${colors.reset}`);
|
|
1418
|
-
log(` 1.
|
|
1419
|
-
log(` 2.
|
|
1479
|
+
log(` 1. Add the SDK: ${colors.cyan}npm install star-sdk${colors.reset}`);
|
|
1480
|
+
log(` 2. Build your game, then deploy: ${colors.cyan}npx star-sdk deploy${colors.reset}`);
|
|
1420
1481
|
log("");
|
|
1421
1482
|
log(`${colors.dim}Example:${colors.reset}`);
|
|
1422
|
-
log(` ${colors.cyan}import
|
|
1423
|
-
log(` ${colors.cyan}
|
|
1424
|
-
log(` ${colors.cyan}leaderboard.submit(1500);${colors.reset}`);
|
|
1425
|
-
log(` ${colors.cyan}leaderboard.show();${colors.reset}`);
|
|
1483
|
+
log(` ${colors.cyan}import Star from 'star-sdk';${colors.reset}`);
|
|
1484
|
+
log(` ${colors.cyan}Star.init({ gameId: '${data.gameId}' });${colors.reset}`);
|
|
1485
|
+
log(` ${colors.cyan}Star.leaderboard.submit(1500);${colors.reset}`);
|
|
1486
|
+
log(` ${colors.cyan}Star.leaderboard.show();${colors.reset}`);
|
|
1426
1487
|
log("");
|
|
1427
1488
|
log(`${colors.dim}Using an AI coding agent?${colors.reset}`);
|
|
1428
|
-
log(` ${colors.cyan}npx star-sdk install${colors.reset} ${colors.dim}Claude Code, Codex, Cursor,
|
|
1489
|
+
log(` ${colors.cyan}npx star-sdk install${colors.reset} ${colors.dim}Claude Code, Codex, Cursor, Aider${colors.reset}`);
|
|
1429
1490
|
log("");
|
|
1430
1491
|
log(`${colors.dim}Documentation:${colors.reset}`);
|
|
1431
|
-
log(` ${colors.cyan}https://buildwithstar.com/docs${colors.reset}`);
|
|
1492
|
+
log(` ${colors.cyan}https://buildwithstar.com/docs/sdk/sdk${colors.reset}`);
|
|
1432
1493
|
log("");
|
|
1433
1494
|
} catch (err) {
|
|
1434
1495
|
if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
|
|
@@ -1458,8 +1519,98 @@ function whoamiCommand() {
|
|
|
1458
1519
|
if (config.dashboardUrl) {
|
|
1459
1520
|
log(` ${colors.dim}Dashboard:${colors.reset} ${colors.cyan}${config.dashboardUrl}${colors.reset}`);
|
|
1460
1521
|
}
|
|
1522
|
+
if (config.deployUrl) {
|
|
1523
|
+
log(` ${colors.dim}Live URL:${colors.reset} ${colors.cyan}${config.deployUrl}${colors.reset}`);
|
|
1524
|
+
}
|
|
1525
|
+
if (config.deployKey) {
|
|
1526
|
+
log(` ${colors.dim}Deploy key:${colors.reset} ${colors.dim}${config.deployKey.slice(0, 8)}...${colors.reset}`);
|
|
1527
|
+
}
|
|
1461
1528
|
log("");
|
|
1462
1529
|
}
|
|
1530
|
+
async function deployCommand(dirPath) {
|
|
1531
|
+
const config = loadConfig();
|
|
1532
|
+
if (!config) {
|
|
1533
|
+
error('No .starrc found. Run "npx star-sdk init <name>" first.');
|
|
1534
|
+
process.exit(1);
|
|
1535
|
+
}
|
|
1536
|
+
if (!config.deployKey) {
|
|
1537
|
+
error('No deploy key found. Re-run "npx star-sdk init <name>" to get one.');
|
|
1538
|
+
process.exit(1);
|
|
1539
|
+
}
|
|
1540
|
+
const deployDir = dirPath ? path.resolve(dirPath) : process.cwd();
|
|
1541
|
+
if (!fs.existsSync(deployDir)) {
|
|
1542
|
+
error(`Directory not found: ${deployDir}`);
|
|
1543
|
+
process.exit(1);
|
|
1544
|
+
}
|
|
1545
|
+
if (!fs.statSync(deployDir).isDirectory()) {
|
|
1546
|
+
error(`Not a directory: ${deployDir}`);
|
|
1547
|
+
process.exit(1);
|
|
1548
|
+
}
|
|
1549
|
+
const indexPath = path.join(deployDir, "index.html");
|
|
1550
|
+
if (!fs.existsSync(indexPath)) {
|
|
1551
|
+
error(`No index.html found in ${deployDir}`);
|
|
1552
|
+
log("");
|
|
1553
|
+
log("Your game needs an index.html file to deploy.");
|
|
1554
|
+
process.exit(1);
|
|
1555
|
+
}
|
|
1556
|
+
log(`Deploying ${colors.bright}${config.name}${colors.reset} from ${colors.dim}${deployDir}${colors.reset}`);
|
|
1557
|
+
try {
|
|
1558
|
+
const archiver = (await import("archiver")).default;
|
|
1559
|
+
const zipBuffer = await new Promise((resolve2, reject) => {
|
|
1560
|
+
const chunks = [];
|
|
1561
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
1562
|
+
archive.on("data", (chunk) => chunks.push(chunk));
|
|
1563
|
+
archive.on("end", () => resolve2(Buffer.concat(chunks)));
|
|
1564
|
+
archive.on("error", reject);
|
|
1565
|
+
archive.glob("**/*", {
|
|
1566
|
+
cwd: deployDir,
|
|
1567
|
+
ignore: ["node_modules/**", ".starrc", ".git/**", ".DS_Store"],
|
|
1568
|
+
dot: false
|
|
1569
|
+
});
|
|
1570
|
+
archive.finalize();
|
|
1571
|
+
});
|
|
1572
|
+
log(` ${colors.dim}Uploading ${(zipBuffer.length / 1024).toFixed(1)} KB...${colors.reset}`);
|
|
1573
|
+
const response = await fetch(`${API_BASE}/api/sdk/games/${config.gameId}/deploy`, {
|
|
1574
|
+
method: "POST",
|
|
1575
|
+
headers: {
|
|
1576
|
+
"Content-Type": "application/zip",
|
|
1577
|
+
"x-deploy-key": config.deployKey
|
|
1578
|
+
},
|
|
1579
|
+
body: zipBuffer
|
|
1580
|
+
});
|
|
1581
|
+
if (!response.ok) {
|
|
1582
|
+
const data2 = await response.json().catch(() => ({}));
|
|
1583
|
+
if (response.status === 403) {
|
|
1584
|
+
error(data2.error || 'Invalid deploy key. Re-run "npx star-sdk init" to get a new one.');
|
|
1585
|
+
} else if (response.status === 404) {
|
|
1586
|
+
error("Game not found. It may have been deleted.");
|
|
1587
|
+
} else if (response.status === 413) {
|
|
1588
|
+
error(data2.error || "Upload too large (50MB limit).");
|
|
1589
|
+
} else if (response.status === 429) {
|
|
1590
|
+
error(data2.error || "Rate limit exceeded. Try again later.");
|
|
1591
|
+
} else {
|
|
1592
|
+
error(data2.error || `Deploy failed (HTTP ${response.status})`);
|
|
1593
|
+
}
|
|
1594
|
+
process.exit(1);
|
|
1595
|
+
}
|
|
1596
|
+
const data = await response.json();
|
|
1597
|
+
config.deployUrl = data.url;
|
|
1598
|
+
saveConfig(config);
|
|
1599
|
+
log("");
|
|
1600
|
+
success("Deployed successfully!");
|
|
1601
|
+
log("");
|
|
1602
|
+
log(` ${colors.dim}URL:${colors.reset} ${colors.cyan}${data.url}${colors.reset}`);
|
|
1603
|
+
log(` ${colors.dim}Files:${colors.reset} ${data.files} files, ${data.assets} assets`);
|
|
1604
|
+
log("");
|
|
1605
|
+
} catch (err) {
|
|
1606
|
+
if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
|
|
1607
|
+
error("Could not connect to Star API. Check your internet connection.");
|
|
1608
|
+
} else {
|
|
1609
|
+
error(err.message || "Deploy failed");
|
|
1610
|
+
}
|
|
1611
|
+
process.exit(1);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1463
1614
|
function transformForStdout(content) {
|
|
1464
1615
|
return content.replace(/\[(\w+)\.md\]\(\.\/\1\.md\)/g, "$1 (`npx star-sdk docs $1`)").replace(/see (\w+)\.md/g, "run `npx star-sdk docs $1`").replace(
|
|
1465
1616
|
/For detailed API documentation, see the linked files above\./,
|
|
@@ -1670,6 +1821,9 @@ async function main() {
|
|
|
1670
1821
|
case "init":
|
|
1671
1822
|
await initCommand(positional[0], email);
|
|
1672
1823
|
break;
|
|
1824
|
+
case "deploy":
|
|
1825
|
+
await deployCommand(positional[0]);
|
|
1826
|
+
break;
|
|
1673
1827
|
case "install": {
|
|
1674
1828
|
const agent = positional[0] || "claude";
|
|
1675
1829
|
const scope = flags.project ? "project" : "global";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "star-sdk-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "CLI
|
|
3
|
+
"version": "0.1.13",
|
|
4
|
+
"description": "CLI for Star SDK — register games, install AI docs, and deploy to Star hosting",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"star-sdk": "./dist/cli.mjs"
|
|
@@ -18,14 +18,30 @@
|
|
|
18
18
|
"build": "tsup",
|
|
19
19
|
"dev": "tsx src/cli.ts"
|
|
20
20
|
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"homepage": "https://buildwithstar.com/docs/sdk",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/buildwithstar/star-sdk",
|
|
26
|
+
"directory": "packages/star-sdk-cli"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/buildwithstar/star-sdk/issues"
|
|
30
|
+
},
|
|
21
31
|
"keywords": [
|
|
22
32
|
"star",
|
|
23
33
|
"sdk",
|
|
24
34
|
"cli",
|
|
25
35
|
"games",
|
|
26
|
-
"leaderboard"
|
|
36
|
+
"leaderboard",
|
|
37
|
+
"deploy",
|
|
38
|
+
"hosting"
|
|
27
39
|
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"archiver": "^7.0.0"
|
|
42
|
+
},
|
|
28
43
|
"devDependencies": {
|
|
44
|
+
"@types/archiver": "^6.0.0",
|
|
29
45
|
"tsup": "^8.0.0",
|
|
30
46
|
"tsx": "^4.7.0",
|
|
31
47
|
"typescript": "^5.4.5"
|