@keystrokehq/cli 0.0.94 → 0.0.96

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 CHANGED
@@ -19,20 +19,23 @@ Right now the CLI exposes `init`, `build`, `dev`, `start`, `health`, `auth`, `--
19
19
 
20
20
  ### `auth`
21
21
 
22
- Authenticate with a running keystroke deployment via Better Auth device flow. Config lives in `~/.keystroke`; bearer tokens live in the OS keychain.
22
+ Authenticate with Keystroke via Better Auth device flow. Config lives in `~/.keystroke`; bearer tokens live in the OS keychain.
23
23
 
24
24
  ```bash
25
25
  keystroke auth login
26
26
  keystroke auth login --web-url http://localhost:3000
27
+ keystroke auth login --web-url https://app.keystroke.ai --platform-url https://api.keystroke.ai
27
28
  keystroke auth status
28
29
  keystroke auth logout
29
30
  ```
30
31
 
31
- | Setting | Default | Purpose |
32
- | ------------- | ----------------------- | ------------------------------------------------------------- |
33
- | `webUrl` | `http://localhost:3000` | Web dashboard; dev proxies `/api/*` and `/health` to platform |
34
- | `platformUrl` | `http://localhost:3002` | Platform API (direct; used by CLI platform commands) |
35
- | `serverUrl` | `http://localhost:3001` | Local keystroke server API |
32
+ | Setting | Default | Purpose |
33
+ | ------------- | -------------------------- | ---------------------------------------------------------------- |
34
+ | `webUrl` | `https://app.keystroke.ai` | Web dashboard; device login and session checks |
35
+ | `platformUrl` | `https://api.keystroke.ai` | Platform API (direct; used by CLI platform commands) |
36
+ | `serverUrl` | `http://localhost:3001` | Local keystroke server API (`keystroke dev` / `keystroke start`) |
37
+
38
+ `auth login` persists both `webUrl` and `platformUrl`. Local dev: `--web-url http://localhost:3000` (platform URL resolves to `http://localhost:3002`). Cloud auth does not change `serverUrl` — local project commands still hit your dev server.
36
39
 
37
40
  Existing commands do not require auth yet. Use `resolveCliAuth()` when adding protected commands.
38
41
 
package/dist/index.mjs CHANGED
@@ -6129,6 +6129,12 @@ const OrganizationSlugSchema = string().trim().toLowerCase().min(2, "Slug must b
6129
6129
  const ClaimableOrganizationSlugSchema = OrganizationSlugSchema.refine((slug) => !RESERVED_ORGANIZATION_SLUGS.has(slug), "This slug is reserved");
6130
6130
  /** Browser→platform request budget (ping + small platform overhead). */
6131
6131
  const PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS = 17e3;
6132
+ /** Normalize a public origin URL (no trailing slash). */
6133
+ function originFromPublicUrl(value, fallback) {
6134
+ const trimmed = value?.trim();
6135
+ if (!trimmed) return fallback.replace(/\/+$/, "");
6136
+ return trimmed.replace(/\/+$/, "");
6137
+ }
6132
6138
  /** TCP port to bind for a local server, derived from a public URL. */
6133
6139
  function listenPortFromUrl(url, fallback) {
6134
6140
  const parsed = new URL(url);
@@ -7201,6 +7207,27 @@ function clearAccessToken(webUrl) {
7201
7207
  new Entry(SERVICE, accountForWebUrl(webUrl)).deletePassword();
7202
7208
  }
7203
7209
  //#endregion
7210
+ //#region src/resolve-platform-url.ts
7211
+ const DEFAULT_WEB_URL = "https://app.keystroke.ai";
7212
+ const DEFAULT_PLATFORM_URL = "https://api.keystroke.ai";
7213
+ const LOCAL_PLATFORM_URL = "http://localhost:3002";
7214
+ function webOriginFromUrl(webUrl) {
7215
+ return originFromPublicUrl(webUrl, webUrl.replace(/\/+$/, ""));
7216
+ }
7217
+ /** Known web origins with a fixed platform API — undefined for custom/staging URLs. */
7218
+ function knownPlatformUrlForWebUrl(webUrl) {
7219
+ const webOrigin = webOriginFromUrl(webUrl);
7220
+ if (webOrigin === "http://localhost:3000" || webOrigin === "http://127.0.0.1:3000") return LOCAL_PLATFORM_URL;
7221
+ if (webOrigin === "https://app.keystroke.ai") return DEFAULT_PLATFORM_URL;
7222
+ }
7223
+ function resolvePlatformUrlForWebUrl(webUrl, options = {}) {
7224
+ const explicit = options.platformUrl?.trim();
7225
+ if (explicit) return explicit.replace(/\/+$/, "");
7226
+ const known = knownPlatformUrlForWebUrl(webUrl);
7227
+ if (known) return known;
7228
+ return (options.fallback?.trim() || "https://api.keystroke.ai").replace(/\/+$/, "");
7229
+ }
7230
+ //#endregion
7204
7231
  //#region src/config.ts
7205
7232
  function getCliConfigDir(cwd = join(homedir(), ".keystroke")) {
7206
7233
  return cwd;
@@ -7213,8 +7240,13 @@ function getEffectiveApiTarget(config) {
7213
7240
  if (explicit === "local" || explicit === "platform") return explicit;
7214
7241
  return "local";
7215
7242
  }
7243
+ function syncPlatformUrlWithWebUrl(config) {
7244
+ const known = knownPlatformUrlForWebUrl(config.get("webUrl"));
7245
+ if (!known) return;
7246
+ if (config.get("platformUrl") !== known) config.set("platformUrl", known);
7247
+ }
7216
7248
  function createCliConfig(cwd = getCliConfigDir()) {
7217
- return new Conf({
7249
+ const config = new Conf({
7218
7250
  projectName: "keystroke",
7219
7251
  cwd,
7220
7252
  schema: {
@@ -7224,11 +7256,11 @@ function createCliConfig(cwd = getCliConfigDir()) {
7224
7256
  },
7225
7257
  webUrl: {
7226
7258
  type: "string",
7227
- default: "http://localhost:3000"
7259
+ default: DEFAULT_WEB_URL
7228
7260
  },
7229
7261
  platformUrl: {
7230
7262
  type: "string",
7231
- default: "http://localhost:3002"
7263
+ default: DEFAULT_PLATFORM_URL
7232
7264
  },
7233
7265
  activeOrganizationId: { type: "string" },
7234
7266
  activeProjectId: { type: "string" },
@@ -7238,6 +7270,8 @@ function createCliConfig(cwd = getCliConfigDir()) {
7238
7270
  }
7239
7271
  }
7240
7272
  });
7273
+ syncPlatformUrlWithWebUrl(config);
7274
+ return config;
7241
7275
  }
7242
7276
  function getServerUrl(config) {
7243
7277
  return config.get("serverUrl");
@@ -7246,7 +7280,7 @@ function getWebUrl(config) {
7246
7280
  return config.get("webUrl");
7247
7281
  }
7248
7282
  function getPlatformUrl(config) {
7249
- return config.get("platformUrl");
7283
+ return resolvePlatformUrlForWebUrl(getWebUrl(config), { fallback: config.get("platformUrl") });
7250
7284
  }
7251
7285
  //#endregion
7252
7286
  //#region src/auth/resolve-cli-auth.ts
@@ -11781,7 +11815,7 @@ function registerCredentialsCommand(program) {
11781
11815
  /** OAuth device-flow client id for `keystroke auth login`. */
11782
11816
  const CLI_CLIENT_ID = "keystroke-cli";
11783
11817
  //#endregion
11784
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/version.mjs
11818
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/version.mjs
11785
11819
  const PACKAGE_VERSION = "1.6.11";
11786
11820
  //#endregion
11787
11821
  //#region ../../node_modules/.pnpm/better-call@1.3.5_zod@4.4.3/node_modules/better-call/dist/error.mjs
@@ -11906,7 +11940,7 @@ var BetterAuthError = class extends Error {
11906
11940
  }
11907
11941
  };
11908
11942
  //#endregion
11909
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
11943
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
11910
11944
  const deviceAuthorizationClient = () => {
11911
11945
  return {
11912
11946
  id: "device-authorization",
@@ -12051,7 +12085,7 @@ let onMount = ($store, initialize) => {
12051
12085
  });
12052
12086
  };
12053
12087
  //#endregion
12054
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/query.mjs
12088
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/query.mjs
12055
12089
  const isServer = () => typeof window === "undefined";
12056
12090
  const useAuthQuery = (initializedAtom, path, $fetch, options) => {
12057
12091
  const value = /* @__PURE__ */ atom({
@@ -12145,7 +12179,7 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
12145
12179
  return value;
12146
12180
  };
12147
12181
  //#endregion
12148
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/broadcast-channel.mjs
12182
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/broadcast-channel.mjs
12149
12183
  const kBroadcastChannel = Symbol.for("better-auth:broadcast-channel");
12150
12184
  const now$1 = () => Math.floor(Date.now() / 1e3);
12151
12185
  var WindowBroadcastChannel = class {
@@ -12188,7 +12222,7 @@ function getGlobalBroadcastChannel(name = "better-auth.message") {
12188
12222
  return globalThis[kBroadcastChannel];
12189
12223
  }
12190
12224
  //#endregion
12191
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/focus-manager.mjs
12225
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/focus-manager.mjs
12192
12226
  const kFocusManager = Symbol.for("better-auth:focus-manager");
12193
12227
  var WindowFocusManager = class {
12194
12228
  listeners = /* @__PURE__ */ new Set();
@@ -12217,7 +12251,7 @@ function getGlobalFocusManager() {
12217
12251
  return globalThis[kFocusManager];
12218
12252
  }
12219
12253
  //#endregion
12220
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/online-manager.mjs
12254
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/online-manager.mjs
12221
12255
  const kOnlineManager = Symbol.for("better-auth:online-manager");
12222
12256
  var WindowOnlineManager = class {
12223
12257
  listeners = /* @__PURE__ */ new Set();
@@ -12249,7 +12283,7 @@ function getGlobalOnlineManager() {
12249
12283
  return globalThis[kOnlineManager];
12250
12284
  }
12251
12285
  //#endregion
12252
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/parser.mjs
12286
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/parser.mjs
12253
12287
  const PROTO_POLLUTION_PATTERNS = {
12254
12288
  proto: /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,
12255
12289
  constructor: /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,
@@ -12319,7 +12353,7 @@ function parseJSON(value, options = { strict: true }) {
12319
12353
  return betterJSONParse(value, options);
12320
12354
  }
12321
12355
  //#endregion
12322
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/session-refresh.mjs
12356
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/session-refresh.mjs
12323
12357
  const now = () => Math.floor(Date.now() / 1e3);
12324
12358
  /**
12325
12359
  * Normalize $fetch response: `throw: true` returns data directly, otherwise `{ data, error }`.
@@ -12517,7 +12551,7 @@ Object.freeze({
12517
12551
  }
12518
12552
  });
12519
12553
  //#endregion
12520
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/utils/url.mjs
12554
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/utils/url.mjs
12521
12555
  function checkHasPath(url) {
12522
12556
  try {
12523
12557
  return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/";
@@ -12589,7 +12623,7 @@ function getOrigin(url) {
12589
12623
  }
12590
12624
  }
12591
12625
  //#endregion
12592
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/fetch-plugins.mjs
12626
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/fetch-plugins.mjs
12593
12627
  const redirectPlugin = {
12594
12628
  id: "redirect",
12595
12629
  name: "Redirect",
@@ -12604,7 +12638,7 @@ const redirectPlugin = {
12604
12638
  } }
12605
12639
  };
12606
12640
  //#endregion
12607
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/session-atom.mjs
12641
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/session-atom.mjs
12608
12642
  function getSessionAtom($fetch, options) {
12609
12643
  const $signal = /* @__PURE__ */ atom(false);
12610
12644
  const session = useAuthQuery($signal, "/get-session", $fetch, { method: "GET" });
@@ -13091,7 +13125,7 @@ var betterFetch = async (url, options) => {
13091
13125
  };
13092
13126
  };
13093
13127
  //#endregion
13094
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/config.mjs
13128
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/config.mjs
13095
13129
  const resolvePublicAuthUrl = (basePath) => {
13096
13130
  if (typeof process === "undefined") return void 0;
13097
13131
  const path = basePath ?? "/api/auth";
@@ -13189,12 +13223,12 @@ const getClientConfig = (options, loadEnv) => {
13189
13223
  };
13190
13224
  };
13191
13225
  //#endregion
13192
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/utils/is-atom.mjs
13226
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/utils/is-atom.mjs
13193
13227
  function isAtom(value) {
13194
13228
  return typeof value === "object" && value !== null && "get" in value && typeof value.get === "function" && "lc" in value && typeof value.lc === "number";
13195
13229
  }
13196
13230
  //#endregion
13197
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/proxy.mjs
13231
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/proxy.mjs
13198
13232
  function getMethod(path, knownPathMethods, args) {
13199
13233
  const method = knownPathMethods[path];
13200
13234
  const { fetchOptions, query: _query, ...body } = args || {};
@@ -13274,7 +13308,7 @@ function capitalizeFirstLetter(str) {
13274
13308
  return str.charAt(0).toUpperCase() + str.slice(1);
13275
13309
  }
13276
13310
  //#endregion
13277
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.20_crossws@0.4.5_srvx@0.11.15__react-dom_b346619fb1e6b75975d0aa0d3d1e104e/node_modules/better-auth/dist/client/vanilla.mjs
13311
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@tanstack+react-start@1.168.22_crossws@0.4.5_srvx@0.11.15__react-dom_58aa013e967694c3ee75e7bc1076e12b/node_modules/better-auth/dist/client/vanilla.mjs
13278
13312
  function createAuthClient(options) {
13279
13313
  const { pluginPathMethods, pluginsActions, pluginsAtoms, $fetch, atomListeners, $store } = getClientConfig(options);
13280
13314
  const resolvedHooks = {};
@@ -13362,10 +13396,15 @@ async function getSessionWithBearer(baseURL, accessToken) {
13362
13396
  //#endregion
13363
13397
  //#region src/commands/auth/login.ts
13364
13398
  function registerAuthLoginCommand(auth) {
13365
- auth.command("login").description("Authenticate via browser device flow").option("--web-url <url>", "Web dashboard origin (default from config)").option("--org <id>", "Active organization id (skips prompt when you belong to several)").action(async (options) => {
13399
+ auth.command("login").description("Authenticate via browser device flow").option("--web-url <url>", "Web dashboard origin (default from config)").option("--platform-url <url>", "Platform API origin (derived from web URL when omitted)").option("--org <id>", "Active organization id (skips prompt when you belong to several)").action(async (options) => {
13366
13400
  const config = createCliConfig();
13367
13401
  const webUrl = options.webUrl ?? getWebUrl(config);
13368
- if (options.webUrl) config.set("webUrl", webUrl);
13402
+ const platformUrl = resolvePlatformUrlForWebUrl(webUrl, {
13403
+ platformUrl: options.platformUrl,
13404
+ fallback: getPlatformUrl(config)
13405
+ });
13406
+ config.set("webUrl", webUrl);
13407
+ config.set("platformUrl", platformUrl);
13369
13408
  try {
13370
13409
  const result = await runDeviceLogin({
13371
13410
  baseURL: webUrl,
@@ -14312,7 +14351,7 @@ function registerConfigCommand(program) {
14312
14351
  process.stdout.write(`${JSON.stringify({
14313
14352
  serverUrl: cliConfig.get("serverUrl"),
14314
14353
  webUrl: cliConfig.get("webUrl"),
14315
- platformUrl: cliConfig.get("platformUrl"),
14354
+ platformUrl: getPlatformUrl(cliConfig),
14316
14355
  activeOrganizationId: cliConfig.get("activeOrganizationId"),
14317
14356
  activeProjectId: cliConfig.get("activeProjectId"),
14318
14357
  apiTarget: getEffectiveApiTarget(cliConfig),