@keystrokehq/cli 0.0.2 → 0.0.3

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.
@@ -25,7 +25,7 @@ function createAuthCommand() {
25
25
  description: "Authenticate Keystroke CLI via device flow",
26
26
  schema: AuthOptionsSchema,
27
27
  optionsConfig: AUTH_OPTIONS_CONFIG,
28
- loadHandler: async () => (await import("./auth.handler-BBPObKwk.mjs")).handleAuth,
28
+ loadHandler: async () => (await import("./auth.handler-CbhiLOG1.mjs")).handleAuth,
29
29
  subcommands: [
30
30
  createTypedCommand({
31
31
  name: "clear",
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { _ as AUTH_URL_PATH, b as CALLBACK_PATH, h as toErrorMessage, i as logger, t as ui, v as CALLBACK_LOOPBACK_HOST, x as CLI_AUTH_COMMAND, y as CALLBACK_LOOPBACK_ORIGIN } from "./keystroke.mjs";
3
+ import { n as DEFAULT_CLI_WEB_URL, t as DEFAULT_CLI_SERVER_URL } from "./default-urls-BS4twrsS.mjs";
4
+ import { C as CliExitError, _ as AUTH_URL_PATH, b as CALLBACK_PATH, h as toErrorMessage, i as logger, t as ui, v as CALLBACK_LOOPBACK_HOST, x as CLI_AUTH_COMMAND, y as CALLBACK_LOOPBACK_ORIGIN } from "./keystroke.mjs";
4
5
  import { f as upsertOrgCredentials, i as getCredentialsFilePath } from "./dist-BF6r1hfv.mjs";
5
6
  import { a as resolveCliWebUrl, i as resolveCliServerUrl } from "./env-YTZGKGIu.mjs";
6
7
  import { t as openBrowser } from "./browser-gddMccBQ.mjs";
7
8
  import { hostname } from "node:os";
8
9
  import { z } from "zod";
10
+ import { confirm, isCancel } from "@clack/prompts";
9
11
  import { randomBytes } from "node:crypto";
10
12
  import { createServer } from "node:http";
11
13
  //#region src/commands/auth/device-auth.ts
@@ -237,6 +239,74 @@ async function createDeviceCallbackListener(expectedState, timeoutMs) {
237
239
  }
238
240
  //#endregion
239
241
  //#region src/commands/auth/auth.handler.ts
242
+ const LOOPBACK_HOSTNAMES = new Set([
243
+ "localhost",
244
+ "127.0.0.1",
245
+ "::1"
246
+ ]);
247
+ function isLoopbackUrl(rawUrl) {
248
+ try {
249
+ const parsed = new URL(rawUrl);
250
+ const host = parsed.hostname.startsWith("[") ? parsed.hostname.slice(1, -1) : parsed.hostname;
251
+ return LOOPBACK_HOSTNAMES.has(host);
252
+ } catch {
253
+ return false;
254
+ }
255
+ }
256
+ function resolveAuthHosts(options, ctx) {
257
+ const savedWeb = ctx.storedCredentials?.webUrl;
258
+ const savedServer = ctx.storedCredentials?.serverUrl;
259
+ const webUrl = resolveCliWebUrl(options.webUrl, savedWeb);
260
+ const serverUrl = resolveCliServerUrl(ctx.baseUrl);
261
+ return {
262
+ webUrl,
263
+ serverUrl,
264
+ webFromFlag: typeof options.webUrl === "string" && options.webUrl.length > 0,
265
+ webMatchesSaved: savedWeb === webUrl,
266
+ serverMatchesSaved: savedServer === serverUrl
267
+ };
268
+ }
269
+ function shouldConfirmLoopback(hosts) {
270
+ if (isLoopbackUrl("https://keystroke.ai") && isLoopbackUrl("https://api.kestroke.ai")) return false;
271
+ const webNeedsConfirm = !hosts.webFromFlag && isLoopbackUrl(hosts.webUrl);
272
+ const serverNeedsConfirm = isLoopbackUrl(hosts.serverUrl);
273
+ return webNeedsConfirm || serverNeedsConfirm;
274
+ }
275
+ function describeHostSource(matchesSaved, fromFlag = false) {
276
+ if (fromFlag) return "flag";
277
+ if (matchesSaved) return "saved credentials";
278
+ return "env or default";
279
+ }
280
+ function printResolvedHosts(hosts) {
281
+ ui.hint(`Web URL: ${hosts.webUrl} (${describeHostSource(hosts.webMatchesSaved, hosts.webFromFlag)})`);
282
+ ui.hint(`API URL: ${hosts.serverUrl} (${describeHostSource(hosts.serverMatchesSaved)})`);
283
+ }
284
+ async function confirmLoopbackHostsOrExit(hosts) {
285
+ ui.br();
286
+ ui.warn("About to authenticate against a local development environment");
287
+ if (hosts.webMatchesSaved || hosts.serverMatchesSaved) ui.hint(`Saved at: ${getCredentialsFilePath()} (from a previous keystroke auth run)`);
288
+ else ui.hint("Resolved from your environment (WEB_URL / SERVER_URL).");
289
+ ui.hint(`CLI default is ${DEFAULT_CLI_WEB_URL} / ${DEFAULT_CLI_SERVER_URL}.`);
290
+ ui.hint("To switch hosts:");
291
+ ui.hint(` - Reset and re-auth: ${CLI_AUTH_COMMAND} clear, then ${CLI_AUTH_COMMAND}`);
292
+ ui.hint(` - Override once: ${CLI_AUTH_COMMAND} --web-url <url> --server-url <url>`);
293
+ ui.br();
294
+ if (process.stdin.isTTY !== true) {
295
+ ui.warn("Non-interactive shell detected — continuing with the local URLs.");
296
+ return;
297
+ }
298
+ const proceed = await confirm({
299
+ message: "Continue signing in against these local URLs?",
300
+ initialValue: false
301
+ });
302
+ if (isCancel(proceed) || proceed !== true) {
303
+ ui.hint("Cancelled. No credentials were changed.");
304
+ throw new CliExitError("Auth cancelled by user.", {
305
+ exitCode: 0,
306
+ reported: true
307
+ });
308
+ }
309
+ }
240
310
  function getVerificationCode(state) {
241
311
  return state.slice(0, 8).toUpperCase();
242
312
  }
@@ -266,17 +336,22 @@ async function warnIfAlreadyAuthenticated(ctx) {
266
336
  } catch {
267
337
  return;
268
338
  }
269
- const identity = ctx.storedCredentials?.user?.email ?? "unknown user";
339
+ const stored = ctx.storedCredentials;
340
+ const identity = stored?.user?.email ?? "unknown user";
341
+ const activeOrg = stored?.orgs.find((o) => o.organizationId === stored?.activeOrgId);
270
342
  ui.br();
271
343
  ui.warn("Already authenticated");
272
- ui.hint(`Signed in as ${identity}`);
344
+ ui.hint(`Signed in as ${identity}${activeOrg ? ` (${activeOrg.organizationName})` : ""}`);
345
+ if (stored?.webUrl || stored?.serverUrl) ui.hint(`Saved hosts: web ${stored.webUrl ?? "(none)"} | api ${stored.serverUrl ?? "(none)"}`);
273
346
  ui.hint("Continuing will add or replace credentials for the selected organization.");
274
347
  ui.br();
275
348
  }
276
349
  async function handleAuth(options, ctx, overrides) {
277
350
  await warnIfAlreadyAuthenticated(ctx);
278
- const webUrl = resolveCliWebUrl(options.webUrl, ctx.storedCredentials?.webUrl);
279
- const serverUrl = resolveCliServerUrl(ctx.baseUrl);
351
+ const hosts = resolveAuthHosts(options, ctx);
352
+ printResolvedHosts(hosts);
353
+ if (shouldConfirmLoopback(hosts)) await confirmLoopbackHostsOrExit(hosts);
354
+ const { webUrl, serverUrl } = hosts;
280
355
  const timeoutMs = options.timeout * 1e3;
281
356
  const state = createDeviceAuthState();
282
357
  logger.info("Starting auth flow", {
@@ -9,7 +9,7 @@ import * as path$1 from "node:path";
9
9
  import { z } from "zod";
10
10
  import { log } from "@clack/prompts";
11
11
  //#region package.json
12
- var version = "0.0.2";
12
+ var version = "0.0.3";
13
13
  //#endregion
14
14
  //#region src/command-registry.ts
15
15
  const ROOT_OPTIONS_WITH_VALUES = new Set([
@@ -33,7 +33,7 @@ const lazyCommandDefinitions = [
33
33
  },
34
34
  {
35
35
  name: "auth",
36
- loadCommand: async () => (await import("./auth-Byry35LJ.mjs")).createAuthCommand()
36
+ loadCommand: async () => (await import("./auth-CY0Gg9sN.mjs")).createAuthCommand()
37
37
  },
38
38
  {
39
39
  name: "connect",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keystrokehq/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "private": false,
5
5
  "description": "Command-line interface for creating, managing, and deploying Keystroke automations.",
6
6
  "type": "module",
@@ -39,17 +39,17 @@
39
39
  "typescript": "^5.9.3",
40
40
  "vitest": "^4.1.5",
41
41
  "@keystroke/env-utils": "0.0.0",
42
- "@keystroke/skills": "0.0.1",
43
- "@keystroke/project-config": "0.0.0",
44
42
  "@keystroke/local-memory": "0.0.0",
43
+ "@keystroke/shared-types": "0.0.0",
45
44
  "@keystroke/typescript-config": "0.0.0",
46
- "@keystroke/utils": "0.0.0",
45
+ "@keystroke/test-utils": "0.0.0",
47
46
  "@keystroke/workflow-builder": "0.0.1",
47
+ "@keystroke/skills": "0.0.1",
48
+ "@keystroke/utils": "0.0.0",
48
49
  "@keystrokehq/core": "0.0.2",
49
- "@keystroke/shared-types": "0.0.0",
50
50
  "@keystroke/workflow-deploy": "0.0.0",
51
51
  "@keystroke/workflow-sdk": "0.0.0",
52
- "@keystroke/test-utils": "0.0.0"
52
+ "@keystroke/project-config": "0.0.0"
53
53
  },
54
54
  "keywords": [
55
55
  "automation",