@promptedgames/cli 0.1.1 → 0.1.2

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 (2) hide show
  1. package/dist/index.js +58 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import { Command, Option } from "commander";
5
5
  import Conf from "conf";
6
6
  import crypto from "crypto";
7
+ import { execSync } from "child_process";
7
8
  import fs from "fs";
8
9
  import { createRequire } from "module";
9
10
  import path from "path";
@@ -863,6 +864,8 @@ var require2 = createRequire(import.meta.url);
863
864
  var pkg = require2("../package.json");
864
865
  var config = new Conf({ projectName: "prompted" });
865
866
  var DEFAULT_SERVER = "https://prompted.games";
867
+ var CLI_USER_AGENT = `prompted-cli/${pkg.version}`;
868
+ var CLI_UPDATE_COMMAND = `npm i -g ${pkg.name}`;
866
869
  function getServer() {
867
870
  return program.opts().host ?? process.env.PROMPTED_SERVER ?? DEFAULT_SERVER;
868
871
  }
@@ -913,6 +916,51 @@ function fail(message, exitCode = 1) {
913
916
  console.error(JSON.stringify({ error: message }));
914
917
  process.exit(exitCode);
915
918
  }
919
+ function withUserAgent(headers) {
920
+ return { ...headers, "User-Agent": CLI_USER_AGENT };
921
+ }
922
+ function shouldPromptForUpdate() {
923
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
924
+ }
925
+ function promptYesNo(question) {
926
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
927
+ return new Promise((resolve) => {
928
+ rl.question(question, (answer) => {
929
+ rl.close();
930
+ resolve(answer.trim().toLowerCase().startsWith("y"));
931
+ });
932
+ });
933
+ }
934
+ function runCliUpdate() {
935
+ try {
936
+ execSync(CLI_UPDATE_COMMAND, { stdio: "inherit" });
937
+ return true;
938
+ } catch {
939
+ return false;
940
+ }
941
+ }
942
+ async function enforceMinimumCliVersion(status, body) {
943
+ if (status !== 426 || typeof body !== "object" || body === null) return;
944
+ const err = body;
945
+ if (err.error !== "cli_version_too_old") return;
946
+ const message = typeof err.message === "string" && err.message.length > 0 ? err.message : "Your Prompted CLI version is too old. Please update.";
947
+ const minimumVersion = typeof err.minimumVersion === "string" && err.minimumVersion.length > 0 ? err.minimumVersion : "unknown";
948
+ const currentVersion = typeof err.currentVersion === "string" && err.currentVersion.length > 0 ? err.currentVersion : pkg.version;
949
+ const details = `Current version: ${currentVersion}. Minimum required: ${minimumVersion}.`;
950
+ if (shouldPromptForUpdate()) {
951
+ console.error(message);
952
+ console.error(details);
953
+ const shouldUpdate = await promptYesNo(`Run \`${CLI_UPDATE_COMMAND}\` now? (y/n) `);
954
+ if (shouldUpdate) {
955
+ console.error(`Running: ${CLI_UPDATE_COMMAND}`);
956
+ if (runCliUpdate()) {
957
+ fail("CLI updated successfully. Please rerun your previous command.");
958
+ }
959
+ fail(`Automatic update failed. Run \`${CLI_UPDATE_COMMAND}\` manually.`);
960
+ }
961
+ }
962
+ fail(`${message} ${details} Update with: ${CLI_UPDATE_COMMAND}`);
963
+ }
916
964
  function sleep(ms) {
917
965
  return new Promise((resolve) => setTimeout(resolve, ms));
918
966
  }
@@ -929,6 +977,7 @@ async function request(path2, options) {
929
977
  const headers = {
930
978
  ...options?.headers ?? {}
931
979
  };
980
+ headers["User-Agent"] = CLI_USER_AGENT;
932
981
  if (token) {
933
982
  headers["Authorization"] = `Bearer ${token}`;
934
983
  } else if (userId) {
@@ -942,6 +991,7 @@ async function request(path2, options) {
942
991
  if (!res.ok) fail(`Request failed: ${res.status}`);
943
992
  fail("Invalid JSON response");
944
993
  }
994
+ await enforceMinimumCliVersion(res.status, body);
945
995
  if (res.status === 401) {
946
996
  fail("Authentication failed. Run `prompted login` to sign in again.");
947
997
  }
@@ -958,6 +1008,7 @@ async function requestMayFail(path2, options) {
958
1008
  const headers = {
959
1009
  ...options?.headers ?? {}
960
1010
  };
1011
+ headers["User-Agent"] = CLI_USER_AGENT;
961
1012
  if (token) {
962
1013
  headers["Authorization"] = `Bearer ${token}`;
963
1014
  } else if (userId) {
@@ -970,6 +1021,7 @@ async function requestMayFail(path2, options) {
970
1021
  } catch {
971
1022
  body = null;
972
1023
  }
1024
+ await enforceMinimumCliVersion(res.status, body);
973
1025
  if (!res.ok) {
974
1026
  const msg = body?.error ?? `Request failed: ${res.status}`;
975
1027
  return { ok: false, status: res.status, data: body, error: msg };
@@ -1073,10 +1125,12 @@ program.command("login").description("Store auth credentials or start device log
1073
1125
  const clientId = "prompted-cli";
1074
1126
  const startRes = await fetch(`${getServer()}/api/auth/device/code`, {
1075
1127
  method: "POST",
1076
- headers: { "Content-Type": "application/json" },
1128
+ headers: withUserAgent({ "Content-Type": "application/json" }),
1077
1129
  body: JSON.stringify({ client_id: clientId })
1078
1130
  });
1079
1131
  if (!startRes.ok) {
1132
+ const err = await startRes.json().catch(() => null);
1133
+ await enforceMinimumCliVersion(startRes.status, err);
1080
1134
  fail("Failed to start device login");
1081
1135
  }
1082
1136
  const start = await startRes.json();
@@ -1098,7 +1152,7 @@ program.command("login").description("Store auth credentials or start device log
1098
1152
  try {
1099
1153
  response = await fetch(`${getServer()}/api/auth/device/token`, {
1100
1154
  method: "POST",
1101
- headers: { "Content-Type": "application/json" },
1155
+ headers: withUserAgent({ "Content-Type": "application/json" }),
1102
1156
  body: JSON.stringify({
1103
1157
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1104
1158
  device_code: start.device_code,
@@ -1106,6 +1160,7 @@ program.command("login").description("Store auth credentials or start device log
1106
1160
  })
1107
1161
  });
1108
1162
  body = await response.json().catch(() => ({}));
1163
+ await enforceMinimumCliVersion(response.status, body);
1109
1164
  networkRetries = 0;
1110
1165
  } catch {
1111
1166
  networkRetries += 1;
@@ -1118,7 +1173,7 @@ program.command("login").description("Store auth credentials or start device log
1118
1173
  config.set("token", body.access_token);
1119
1174
  try {
1120
1175
  const meRes = await fetch(`${getServer()}/api/me`, {
1121
- headers: { "Authorization": `Bearer ${body.access_token}` }
1176
+ headers: withUserAgent({ "Authorization": `Bearer ${body.access_token}` })
1122
1177
  });
1123
1178
  if (meRes.ok) {
1124
1179
  const me = await meRes.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptedgames/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "packageManager": "pnpm@10.33.0",
5
5
  "description": "CLI for playing games on the Prompted platform. Build AI agents that play poker, Secret Hitler, Coup, Skull, and Liar's Dice.",
6
6
  "type": "module",