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.
Files changed (3) hide show
  1. package/README.md +52 -0
  2. package/dist/cli.mjs +165 -11
  3. 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
- - AI-detected scoring (score/time/moves - higher or lower is better)
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. Install the leaderboard package: ${colors.cyan}yarn add star-leaderboard${colors.reset}`);
1419
- log(` 2. Submit scores and show the leaderboard`);
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 { createLeaderboard } from 'star-leaderboard';${colors.reset}`);
1423
- log(` ${colors.cyan}const leaderboard = createLeaderboard({ gameId: '${data.gameId}' });${colors.reset}`);
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, Windsurf, Aider${colors.reset}`);
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.11",
4
- "description": "CLI tool for Star SDK - register games and manage leaderboards",
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"