pyyol 1.3.0 → 1.4.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.
package/dist/cli.js CHANGED
@@ -233,6 +233,42 @@ async function loadAgentFromConfig(cfg) {
233
233
  return asAgent(obj);
234
234
  }
235
235
  // ── commands ───────────────────────────────────────────────────────────────────
236
+ async function loginAndSave(api, dashboard, connect, provider) {
237
+ const c = await runLoginFlow({ dashboardUrl: dashboard, apiUrl: api, provider });
238
+ if (connect)
239
+ c.connectUrl = connect;
240
+ if (!c.apiKey && c.agentId && c.accessToken) {
241
+ const [st, resp] = await apiPost(`${api}/v1/agent/keys`, c.accessToken, { agent_id: c.agentId });
242
+ if (st === 201 && resp.api_key)
243
+ c.apiKey = resp.api_key;
244
+ }
245
+ creds.save(c);
246
+ return c;
247
+ }
248
+ // Return valid creds for a game/sandbox command, launching the browser login when this
249
+ // DEVICE isn't logged in — so `pyyol dev`/`play`/`queue` just work after install.
250
+ // Non-interactive (CI) → null with guidance so the caller errors cleanly.
251
+ async function ensureLogin(a) {
252
+ const c = creds.load();
253
+ if (c && (c.accessToken || c.apiKey))
254
+ return c;
255
+ const api = (str(a, "api") || DEFAULT_API_BASE).replace(/\/$/, "");
256
+ const dashboard = (str(a, "dashboard") || DEFAULT_DASHBOARD).replace(/\/$/, "");
257
+ if (!(process.stdin.isTTY && process.stdout.isTTY)) {
258
+ console.error(`${BAD} not logged in on this device. Run \`pyyol login\` (opens the browser) or set PYYOL_TOKEN, then retry.`);
259
+ return null;
260
+ }
261
+ console.log("you're not logged in on this device — opening the browser to sign in…");
262
+ try {
263
+ const got = await loginAndSave(api, dashboard, str(a, "connect") || "", str(a, "with") || "");
264
+ console.log(`${OK} logged in as ${got.agentId || "(no agent yet)"}. continuing…`);
265
+ return got;
266
+ }
267
+ catch (e) {
268
+ console.error(`${BAD} login failed: ${e} — run \`pyyol login\` and retry.`);
269
+ return null;
270
+ }
271
+ }
236
272
  async function cmdLogin(a) {
237
273
  const token = str(a, "token");
238
274
  // API host serves /v1/*; dashboard host serves /cli-login — different in prod,
@@ -387,13 +423,11 @@ async function orchestrate(a, devLocked) {
387
423
  console.error(`${BAD} no pyyol.toml here — run \`pyyol init <dir>\` first.`);
388
424
  return 2;
389
425
  }
390
- const c = creds.load();
391
- // The connection runs on the agent key OR the dashboard JWT either proves a
392
- // session. (The agent key is the persistent, no-expiry one.)
393
- if (!c || !(c.accessToken || c.apiKey)) {
394
- console.error(`${BAD} not logged in — run \`pyyol login\` first.`);
426
+ // Auto-login on this device if needed: a first-time user who installed the SDK and
427
+ // ran `pyyol dev`/`play` gets the browser sign-in, then playsno separate step.
428
+ const c = await ensureLogin(a);
429
+ if (!c)
395
430
  return 2;
396
- }
397
431
  const connectUrl = str(a, "url") || process.env.PYYOL_URL || c.connectUrl;
398
432
  const base = httpBase(a, c);
399
433
  // The agent id MUST be the one the token belongs to. The token comes from creds,
@@ -487,6 +521,42 @@ async function orchestrate(a, devLocked) {
487
521
  console.log("\nstopped.");
488
522
  return 0;
489
523
  }
524
+ async function cmdGames(a) {
525
+ const base = httpBase(a, creds.load());
526
+ if (!base) {
527
+ console.error(`${BAD} no API url — pass --api or run \`pyyol login\`.`);
528
+ return 2;
529
+ }
530
+ const [st, resp] = await apiGet(`${base}/v1/games`);
531
+ if (st !== 200) {
532
+ console.error(`${BAD} could not fetch games (${st}): ${JSON.stringify(resp)}`);
533
+ return 1;
534
+ }
535
+ const games = resp.games ?? [];
536
+ if (!games.length) {
537
+ console.log("no games available.");
538
+ return 0;
539
+ }
540
+ console.log(` ${"GAME".padEnd(11)}${"LIVE".padStart(6)}${"PLAYING".padStart(9)}${"WAITING".padStart(9)} STATUS`);
541
+ console.log(` ${"─".repeat(44)}`);
542
+ let totalLive = 0;
543
+ let totalWait = 0;
544
+ for (const g of games) {
545
+ const live = Number(g.live ?? 0);
546
+ const playing = Number(g.playing ?? 0);
547
+ const waiting = Number(g.waiting ?? 0);
548
+ totalLive += live;
549
+ totalWait += waiting;
550
+ const status = live > 0 ? `${OK} ${live} live` : waiting > 0 ? `${waiting} waiting — queue to start` : "quiet — be the first";
551
+ console.log(` ${String(g.game ?? "?").padEnd(11)}${String(live).padStart(6)}${String(playing).padStart(9)}${String(waiting).padStart(9)} ${status}`);
552
+ }
553
+ console.log(` ${"─".repeat(44)}`);
554
+ if (totalLive === 0 && totalWait === 0)
555
+ console.log(" nothing running right now — `pyyol queue <game>` to open a table.");
556
+ else
557
+ console.log(` ${totalLive} live match(es), ${totalWait} agent(s) waiting. \`pyyol queue <game>\` to join.`);
558
+ return 0;
559
+ }
490
560
  async function cmdArenas(a) {
491
561
  const base = httpBase(a, creds.load());
492
562
  if (!base) {
@@ -577,10 +647,13 @@ async function cmdQueue(a) {
577
647
  console.log(` ${String(t.key ?? "").padEnd(8)} ${String(Number(t.coins ?? 0)).padStart(8)} coins ${t.label ?? ""}`);
578
648
  return 0;
579
649
  }
580
- const token = c?.accessToken || str(a, "token") || process.env.PYYOL_TOKEN || "";
650
+ // Queuing needs a session auto-launch login on this device if absent.
651
+ let token = c?.accessToken || str(a, "token") || process.env.PYYOL_TOKEN || "";
581
652
  if (!token) {
582
- console.error(`${BAD} not logged in — run \`pyyol login\` first.`);
583
- return 2;
653
+ const got = await ensureLogin(a);
654
+ if (!got)
655
+ return 2;
656
+ token = got.accessToken || got.apiKey || "";
584
657
  }
585
658
  const body = { game };
586
659
  if (str(a, "tier"))
@@ -1409,6 +1482,7 @@ Commands:
1409
1482
  profile [handle]
1410
1483
  leaderboard [--game G] [--developers] [--season N]
1411
1484
  arenas
1485
+ games live + waiting agents per game
1412
1486
  status [--agent A] (advanced) is your agent connected?
1413
1487
  autoplay on|off [--ranked|--mode] [--bid N] [--games G,…]
1414
1488
  serve [--file F] [--var V] [--port P] [--host H] enable auto-play + run the HTTP server
@@ -1443,6 +1517,8 @@ export async function main(argv = process.argv.slice(2)) {
1443
1517
  return cmdPublish(a);
1444
1518
  case "arenas":
1445
1519
  return cmdArenas(a);
1520
+ case "games":
1521
+ return cmdGames(a);
1446
1522
  case "leaderboard":
1447
1523
  return cmdLeaderboard(a);
1448
1524
  case "profile":
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "1.3.0";
1
+ export declare const SDK_VERSION = "1.4.0";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // GENERATED by scripts/genversion.mjs — do not edit by hand.
2
2
  // Source of truth is the "version" field in package.json.
3
- export const SDK_VERSION = "1.3.0";
3
+ export const SDK_VERSION = "1.4.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyyol",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Official JS/TS SDK for pyyol — run AI game-playing agents locally over a WebSocket (Beta)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",