opensteer 0.6.2 → 0.6.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.
@@ -11,8 +11,9 @@ import {
11
11
  resolveCloudSelection,
12
12
  resolveConfigWithEnv,
13
13
  resolveNamespace,
14
- resolveNamespaceDir
15
- } from "./chunk-WDRMHPWL.js";
14
+ resolveNamespaceDir,
15
+ selectCloudCredential
16
+ } from "./chunk-KE35RQOJ.js";
16
17
  import {
17
18
  flattenExtractionDataToFieldPlan
18
19
  } from "./chunk-3H5RRIMZ.js";
@@ -10081,30 +10082,20 @@ var Opensteer = class _Opensteer {
10081
10082
  this.pool = new BrowserPool(resolved.browser || {});
10082
10083
  if (cloudSelection.cloud) {
10083
10084
  const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
10084
- const apiKey = cloudConfig?.apiKey?.trim();
10085
- const accessToken = cloudConfig?.accessToken?.trim();
10086
- if (apiKey && accessToken) {
10087
- throw new Error(
10088
- "Cloud mode cannot use both cloud.apiKey and cloud.accessToken. Set only one credential."
10089
- );
10090
- }
10091
- let credential = "";
10092
- let authScheme = cloudConfig?.authScheme ?? "api-key";
10093
- if (accessToken) {
10094
- credential = accessToken;
10095
- authScheme = "bearer";
10096
- } else if (apiKey) {
10097
- credential = apiKey;
10098
- }
10085
+ const credential = selectCloudCredential({
10086
+ apiKey: cloudConfig?.apiKey,
10087
+ accessToken: cloudConfig?.accessToken,
10088
+ authScheme: cloudConfig?.authScheme
10089
+ });
10099
10090
  if (!credential) {
10100
10091
  throw new Error(
10101
10092
  "Cloud mode requires credentials via cloud.apiKey/cloud.accessToken or OPENSTEER_API_KEY/OPENSTEER_ACCESS_TOKEN."
10102
10093
  );
10103
10094
  }
10104
10095
  this.cloud = createCloudRuntimeState(
10105
- credential,
10096
+ credential.token,
10106
10097
  cloudConfig?.baseUrl,
10107
- authScheme
10098
+ credential.authScheme
10108
10099
  );
10109
10100
  } else {
10110
10101
  this.cloud = null;
@@ -2,7 +2,7 @@ import {
2
2
  cloudAuthHeaders,
3
3
  normalizeCloudBaseUrl,
4
4
  parseCloudHttpError
5
- } from "./chunk-WDRMHPWL.js";
5
+ } from "./chunk-KE35RQOJ.js";
6
6
 
7
7
  // src/cloud/browser-profile-client.ts
8
8
  var BrowserProfileClient = class {
@@ -261,6 +261,67 @@ import fs from "fs";
261
261
  import path2 from "path";
262
262
  import { fileURLToPath } from "url";
263
263
  import { parse as parseDotenv } from "dotenv";
264
+
265
+ // src/cloud/credential-selection.ts
266
+ function selectCloudCredential(options) {
267
+ const apiKey = normalizeNonEmptyString(options.apiKey);
268
+ const accessToken = normalizeNonEmptyString(options.accessToken);
269
+ if (apiKey) {
270
+ if (options.authScheme === "bearer") {
271
+ return {
272
+ apiKey,
273
+ authScheme: "bearer",
274
+ kind: "access-token",
275
+ token: apiKey,
276
+ compatibilityBearerApiKey: true
277
+ };
278
+ }
279
+ return {
280
+ apiKey,
281
+ authScheme: "api-key",
282
+ kind: "api-key",
283
+ token: apiKey
284
+ };
285
+ }
286
+ if (accessToken) {
287
+ return {
288
+ accessToken,
289
+ authScheme: "bearer",
290
+ kind: "access-token",
291
+ token: accessToken
292
+ };
293
+ }
294
+ return null;
295
+ }
296
+ function selectCloudCredentialByPrecedence(layers, authScheme) {
297
+ for (const layer of layers) {
298
+ const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
299
+ const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
300
+ if (!hasApiKey && !hasAccessToken) {
301
+ continue;
302
+ }
303
+ return {
304
+ source: layer.source,
305
+ apiKey: layer.apiKey,
306
+ accessToken: layer.accessToken,
307
+ hasApiKey,
308
+ hasAccessToken,
309
+ credential: selectCloudCredential({
310
+ apiKey: layer.apiKey,
311
+ accessToken: layer.accessToken,
312
+ authScheme: layer.authScheme ?? authScheme
313
+ })
314
+ };
315
+ }
316
+ return null;
317
+ }
318
+ function normalizeNonEmptyString(value) {
319
+ if (typeof value !== "string") return void 0;
320
+ const normalized = value.trim();
321
+ return normalized.length ? normalized : void 0;
322
+ }
323
+
324
+ // src/config.ts
264
325
  var DEFAULT_CONFIG = {
265
326
  browser: {
266
327
  headless: false,
@@ -552,11 +613,6 @@ function normalizeCloudOptions(value) {
552
613
  }
553
614
  return value;
554
615
  }
555
- function normalizeNonEmptyString(value) {
556
- if (typeof value !== "string") return void 0;
557
- const normalized = value.trim();
558
- return normalized.length ? normalized : void 0;
559
- }
560
616
  function parseCloudEnabled(value, source) {
561
617
  if (value == null) return void 0;
562
618
  if (typeof value === "boolean") return value;
@@ -565,6 +621,18 @@ function parseCloudEnabled(value, source) {
565
621
  `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
566
622
  );
567
623
  }
624
+ function resolveCloudCredentialFields(selectedLayer) {
625
+ const credential = selectedLayer?.credential;
626
+ if (!credential) return {};
627
+ if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
628
+ return {
629
+ apiKey: credential.token
630
+ };
631
+ }
632
+ return {
633
+ accessToken: credential.token
634
+ };
635
+ }
568
636
  function resolveCloudSelection(config, env = process.env) {
569
637
  const configCloud = parseCloudEnabled(config.cloud, "cloud");
570
638
  if (configCloud !== void 0) {
@@ -601,6 +669,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
601
669
  });
602
670
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
603
671
  assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
672
+ const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
673
+ const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
674
+ const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
604
675
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
605
676
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
606
677
  const env = resolveEnv(envRootDir, {
@@ -639,13 +710,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
639
710
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
640
711
  const envBaseUrl = resolveOpensteerBaseUrl(env);
641
712
  const envAuthScheme = resolveOpensteerAuthScheme(env);
642
- if (envApiKey && envAccessTokenRaw) {
643
- throw new Error(
644
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
645
- );
646
- }
647
- const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
648
- const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
649
713
  const envCloudProfileId = resolveOpensteerCloudProfileId(env);
650
714
  const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
651
715
  const envCloudAnnounce = parseCloudAnnounce(
@@ -674,11 +738,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
674
738
  const inputHasCloudBaseUrl = Boolean(
675
739
  inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
676
740
  );
677
- if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
678
- throw new Error(
679
- "cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
680
- );
681
- }
682
741
  const cloudSelection = resolveCloudSelection({
683
742
  cloud: resolved.cloud
684
743
  }, env);
@@ -689,11 +748,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
689
748
  accessToken: resolvedCloudAccessTokenRaw,
690
749
  ...resolvedCloudRest
691
750
  } = resolvedCloud;
692
- if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
693
- throw new Error(
694
- "Cloud config cannot include both apiKey and accessToken at the same time."
695
- );
696
- }
697
751
  const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
698
752
  resolvedCloud.browserProfile,
699
753
  "resolved.cloud.browserProfile"
@@ -705,25 +759,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
705
759
  const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
706
760
  let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
707
761
  const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
708
- const credentialOverriddenByInput = inputHasCloudApiKey || inputHasCloudAccessToken;
709
- let apiKey = normalizeNonEmptyString(resolvedCloudApiKeyRaw);
710
- let accessToken = normalizeNonEmptyString(resolvedCloudAccessTokenRaw);
711
- if (!credentialOverriddenByInput) {
712
- if (envAccessToken) {
713
- accessToken = envAccessToken;
714
- apiKey = void 0;
715
- } else if (envApiCredential) {
716
- apiKey = envApiCredential;
717
- accessToken = void 0;
718
- }
719
- }
762
+ const selectedCredentialLayer = selectCloudCredentialByPrecedence(
763
+ [
764
+ {
765
+ source: "input",
766
+ apiKey: inputCloudOptions?.apiKey,
767
+ accessToken: inputCloudOptions?.accessToken,
768
+ hasApiKey: inputHasCloudApiKey,
769
+ hasAccessToken: inputHasCloudAccessToken
770
+ },
771
+ {
772
+ source: "env",
773
+ apiKey: envApiKey,
774
+ accessToken: envAccessTokenRaw,
775
+ hasApiKey: envApiKey !== void 0,
776
+ hasAccessToken: envAccessTokenRaw !== void 0
777
+ },
778
+ {
779
+ source: "file",
780
+ apiKey: fileCloudOptions?.apiKey,
781
+ accessToken: fileCloudOptions?.accessToken,
782
+ hasApiKey: fileHasCloudApiKey,
783
+ hasAccessToken: fileHasCloudAccessToken
784
+ }
785
+ ],
786
+ authScheme
787
+ );
788
+ const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
720
789
  if (accessToken) {
721
790
  authScheme = "bearer";
722
791
  }
723
792
  resolved.cloud = {
724
793
  ...resolvedCloudRest,
725
- ...inputHasCloudApiKey ? { apiKey: resolvedCloudApiKeyRaw } : apiKey ? { apiKey } : {},
726
- ...inputHasCloudAccessToken ? { accessToken: resolvedCloudAccessTokenRaw } : accessToken ? { accessToken } : {},
794
+ ...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
795
+ ...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
727
796
  authScheme,
728
797
  announce,
729
798
  ...browserProfile ? { browserProfile } : {}
@@ -1300,6 +1369,7 @@ export {
1300
1369
  createKeychainStore,
1301
1370
  extractErrorMessage,
1302
1371
  normalizeError,
1372
+ selectCloudCredential,
1303
1373
  normalizeNamespace,
1304
1374
  resolveNamespaceDir,
1305
1375
  resolveCloudSelection,
@@ -4,67 +4,30 @@ import {
4
4
  normalizeCloudBaseUrl,
5
5
  resolveCloudSelection,
6
6
  resolveConfigWithEnv,
7
+ selectCloudCredential,
7
8
  stripTrailingSlashes
8
- } from "./chunk-WDRMHPWL.js";
9
+ } from "./chunk-KE35RQOJ.js";
9
10
 
10
11
  // src/cli/auth.ts
11
12
  import open from "open";
12
13
 
13
14
  // src/auth/credential-resolver.ts
14
15
  function resolveCloudCredential(options) {
15
- const flagApiKey = normalizeToken(options.apiKeyFlag);
16
- const flagAccessToken = normalizeToken(options.accessTokenFlag);
17
- if (flagApiKey && flagAccessToken) {
18
- throw new Error("--api-key and --access-token are mutually exclusive.");
19
- }
20
- if (flagAccessToken) {
21
- return {
22
- kind: "access-token",
23
- source: "flag",
24
- token: flagAccessToken,
25
- authScheme: "bearer"
26
- };
27
- }
28
- if (flagApiKey) {
29
- return {
30
- kind: "api-key",
31
- source: "flag",
32
- token: flagApiKey,
33
- authScheme: "api-key"
34
- };
16
+ const flagCredential = selectCloudCredential({
17
+ apiKey: options.apiKeyFlag,
18
+ accessToken: options.accessTokenFlag
19
+ });
20
+ if (flagCredential) {
21
+ return toResolvedCloudCredential("flag", flagCredential);
35
22
  }
36
23
  const envAuthScheme = parseEnvAuthScheme(options.env.OPENSTEER_AUTH_SCHEME);
37
- const envApiKey = normalizeToken(options.env.OPENSTEER_API_KEY);
38
- const envAccessToken = normalizeToken(options.env.OPENSTEER_ACCESS_TOKEN);
39
- if (envApiKey && envAccessToken) {
40
- throw new Error(
41
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
42
- );
43
- }
44
- if (envAccessToken) {
45
- return {
46
- kind: "access-token",
47
- source: "env",
48
- token: envAccessToken,
49
- authScheme: "bearer"
50
- };
51
- }
52
- if (envApiKey) {
53
- if (envAuthScheme === "bearer") {
54
- return {
55
- kind: "access-token",
56
- source: "env",
57
- token: envApiKey,
58
- authScheme: "bearer",
59
- compatibilityBearerApiKey: true
60
- };
61
- }
62
- return {
63
- kind: "api-key",
64
- source: "env",
65
- token: envApiKey,
66
- authScheme: envAuthScheme ?? "api-key"
67
- };
24
+ const envCredential = selectCloudCredential({
25
+ apiKey: options.env.OPENSTEER_API_KEY,
26
+ accessToken: options.env.OPENSTEER_ACCESS_TOKEN,
27
+ authScheme: envAuthScheme
28
+ });
29
+ if (envCredential) {
30
+ return toResolvedCloudCredential("env", envCredential);
68
31
  }
69
32
  return null;
70
33
  }
@@ -94,6 +57,23 @@ function normalizeToken(value) {
94
57
  const normalized = value.trim();
95
58
  return normalized.length ? normalized : void 0;
96
59
  }
60
+ function toResolvedCloudCredential(source, credential) {
61
+ if (credential.compatibilityBearerApiKey) {
62
+ return {
63
+ kind: credential.kind,
64
+ source,
65
+ token: credential.token,
66
+ authScheme: credential.authScheme,
67
+ compatibilityBearerApiKey: true
68
+ };
69
+ }
70
+ return {
71
+ kind: credential.kind,
72
+ source,
73
+ token: credential.token,
74
+ authScheme: credential.authScheme
75
+ };
76
+ }
97
77
 
98
78
  // src/auth/machine-credential-store.ts
99
79
  import { createHash } from "crypto";
@@ -1025,8 +1005,6 @@ async function runLogin(args, deps) {
1025
1005
  return 0;
1026
1006
  }
1027
1007
  writeHumanLine(deps, "Opensteer CLI login successful.");
1028
- writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
1029
- writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
1030
1008
  return 0;
1031
1009
  }
1032
1010
  async function runStatus(args, deps) {
package/dist/cli/auth.cjs CHANGED
@@ -94,6 +94,65 @@ function toNonEmptyString(value) {
94
94
  return normalized.length ? normalized : void 0;
95
95
  }
96
96
 
97
+ // src/cloud/credential-selection.ts
98
+ function selectCloudCredential(options) {
99
+ const apiKey = normalizeNonEmptyString(options.apiKey);
100
+ const accessToken = normalizeNonEmptyString(options.accessToken);
101
+ if (apiKey) {
102
+ if (options.authScheme === "bearer") {
103
+ return {
104
+ apiKey,
105
+ authScheme: "bearer",
106
+ kind: "access-token",
107
+ token: apiKey,
108
+ compatibilityBearerApiKey: true
109
+ };
110
+ }
111
+ return {
112
+ apiKey,
113
+ authScheme: "api-key",
114
+ kind: "api-key",
115
+ token: apiKey
116
+ };
117
+ }
118
+ if (accessToken) {
119
+ return {
120
+ accessToken,
121
+ authScheme: "bearer",
122
+ kind: "access-token",
123
+ token: accessToken
124
+ };
125
+ }
126
+ return null;
127
+ }
128
+ function selectCloudCredentialByPrecedence(layers, authScheme) {
129
+ for (const layer of layers) {
130
+ const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
131
+ const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
132
+ if (!hasApiKey && !hasAccessToken) {
133
+ continue;
134
+ }
135
+ return {
136
+ source: layer.source,
137
+ apiKey: layer.apiKey,
138
+ accessToken: layer.accessToken,
139
+ hasApiKey,
140
+ hasAccessToken,
141
+ credential: selectCloudCredential({
142
+ apiKey: layer.apiKey,
143
+ accessToken: layer.accessToken,
144
+ authScheme: layer.authScheme ?? authScheme
145
+ })
146
+ };
147
+ }
148
+ return null;
149
+ }
150
+ function normalizeNonEmptyString(value) {
151
+ if (typeof value !== "string") return void 0;
152
+ const normalized = value.trim();
153
+ return normalized.length ? normalized : void 0;
154
+ }
155
+
97
156
  // src/config.ts
98
157
  var DEFAULT_CONFIG = {
99
158
  browser: {
@@ -386,11 +445,6 @@ function normalizeCloudOptions(value) {
386
445
  }
387
446
  return value;
388
447
  }
389
- function normalizeNonEmptyString(value) {
390
- if (typeof value !== "string") return void 0;
391
- const normalized = value.trim();
392
- return normalized.length ? normalized : void 0;
393
- }
394
448
  function parseCloudEnabled(value, source) {
395
449
  if (value == null) return void 0;
396
450
  if (typeof value === "boolean") return value;
@@ -399,6 +453,18 @@ function parseCloudEnabled(value, source) {
399
453
  `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
400
454
  );
401
455
  }
456
+ function resolveCloudCredentialFields(selectedLayer) {
457
+ const credential = selectedLayer?.credential;
458
+ if (!credential) return {};
459
+ if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
460
+ return {
461
+ apiKey: credential.token
462
+ };
463
+ }
464
+ return {
465
+ accessToken: credential.token
466
+ };
467
+ }
402
468
  function resolveCloudSelection(config, env = process.env) {
403
469
  const configCloud = parseCloudEnabled(config.cloud, "cloud");
404
470
  if (configCloud !== void 0) {
@@ -435,6 +501,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
435
501
  });
436
502
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
437
503
  assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
504
+ const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
505
+ const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
506
+ const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
438
507
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
439
508
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
440
509
  const env = resolveEnv(envRootDir, {
@@ -473,13 +542,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
473
542
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
474
543
  const envBaseUrl = resolveOpensteerBaseUrl(env);
475
544
  const envAuthScheme = resolveOpensteerAuthScheme(env);
476
- if (envApiKey && envAccessTokenRaw) {
477
- throw new Error(
478
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
479
- );
480
- }
481
- const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
482
- const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
483
545
  const envCloudProfileId = resolveOpensteerCloudProfileId(env);
484
546
  const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
485
547
  const envCloudAnnounce = parseCloudAnnounce(
@@ -508,11 +570,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
508
570
  const inputHasCloudBaseUrl = Boolean(
509
571
  inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
510
572
  );
511
- if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
512
- throw new Error(
513
- "cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
514
- );
515
- }
516
573
  const cloudSelection = resolveCloudSelection({
517
574
  cloud: resolved.cloud
518
575
  }, env);
@@ -523,11 +580,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
523
580
  accessToken: resolvedCloudAccessTokenRaw,
524
581
  ...resolvedCloudRest
525
582
  } = resolvedCloud;
526
- if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
527
- throw new Error(
528
- "Cloud config cannot include both apiKey and accessToken at the same time."
529
- );
530
- }
531
583
  const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
532
584
  resolvedCloud.browserProfile,
533
585
  "resolved.cloud.browserProfile"
@@ -539,25 +591,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
539
591
  const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
540
592
  let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
541
593
  const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
542
- const credentialOverriddenByInput = inputHasCloudApiKey || inputHasCloudAccessToken;
543
- let apiKey = normalizeNonEmptyString(resolvedCloudApiKeyRaw);
544
- let accessToken = normalizeNonEmptyString(resolvedCloudAccessTokenRaw);
545
- if (!credentialOverriddenByInput) {
546
- if (envAccessToken) {
547
- accessToken = envAccessToken;
548
- apiKey = void 0;
549
- } else if (envApiCredential) {
550
- apiKey = envApiCredential;
551
- accessToken = void 0;
552
- }
553
- }
594
+ const selectedCredentialLayer = selectCloudCredentialByPrecedence(
595
+ [
596
+ {
597
+ source: "input",
598
+ apiKey: inputCloudOptions?.apiKey,
599
+ accessToken: inputCloudOptions?.accessToken,
600
+ hasApiKey: inputHasCloudApiKey,
601
+ hasAccessToken: inputHasCloudAccessToken
602
+ },
603
+ {
604
+ source: "env",
605
+ apiKey: envApiKey,
606
+ accessToken: envAccessTokenRaw,
607
+ hasApiKey: envApiKey !== void 0,
608
+ hasAccessToken: envAccessTokenRaw !== void 0
609
+ },
610
+ {
611
+ source: "file",
612
+ apiKey: fileCloudOptions?.apiKey,
613
+ accessToken: fileCloudOptions?.accessToken,
614
+ hasApiKey: fileHasCloudApiKey,
615
+ hasAccessToken: fileHasCloudAccessToken
616
+ }
617
+ ],
618
+ authScheme
619
+ );
620
+ const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
554
621
  if (accessToken) {
555
622
  authScheme = "bearer";
556
623
  }
557
624
  resolved.cloud = {
558
625
  ...resolvedCloudRest,
559
- ...inputHasCloudApiKey ? { apiKey: resolvedCloudApiKeyRaw } : apiKey ? { apiKey } : {},
560
- ...inputHasCloudAccessToken ? { accessToken: resolvedCloudAccessTokenRaw } : accessToken ? { accessToken } : {},
626
+ ...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
627
+ ...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
561
628
  authScheme,
562
629
  announce,
563
630
  ...browserProfile ? { browserProfile } : {}
@@ -577,59 +644,21 @@ function resolveConfigWithEnv(input = {}, options = {}) {
577
644
 
578
645
  // src/auth/credential-resolver.ts
579
646
  function resolveCloudCredential(options) {
580
- const flagApiKey = normalizeToken(options.apiKeyFlag);
581
- const flagAccessToken = normalizeToken(options.accessTokenFlag);
582
- if (flagApiKey && flagAccessToken) {
583
- throw new Error("--api-key and --access-token are mutually exclusive.");
584
- }
585
- if (flagAccessToken) {
586
- return {
587
- kind: "access-token",
588
- source: "flag",
589
- token: flagAccessToken,
590
- authScheme: "bearer"
591
- };
592
- }
593
- if (flagApiKey) {
594
- return {
595
- kind: "api-key",
596
- source: "flag",
597
- token: flagApiKey,
598
- authScheme: "api-key"
599
- };
647
+ const flagCredential = selectCloudCredential({
648
+ apiKey: options.apiKeyFlag,
649
+ accessToken: options.accessTokenFlag
650
+ });
651
+ if (flagCredential) {
652
+ return toResolvedCloudCredential("flag", flagCredential);
600
653
  }
601
654
  const envAuthScheme = parseEnvAuthScheme(options.env.OPENSTEER_AUTH_SCHEME);
602
- const envApiKey = normalizeToken(options.env.OPENSTEER_API_KEY);
603
- const envAccessToken = normalizeToken(options.env.OPENSTEER_ACCESS_TOKEN);
604
- if (envApiKey && envAccessToken) {
605
- throw new Error(
606
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
607
- );
608
- }
609
- if (envAccessToken) {
610
- return {
611
- kind: "access-token",
612
- source: "env",
613
- token: envAccessToken,
614
- authScheme: "bearer"
615
- };
616
- }
617
- if (envApiKey) {
618
- if (envAuthScheme === "bearer") {
619
- return {
620
- kind: "access-token",
621
- source: "env",
622
- token: envApiKey,
623
- authScheme: "bearer",
624
- compatibilityBearerApiKey: true
625
- };
626
- }
627
- return {
628
- kind: "api-key",
629
- source: "env",
630
- token: envApiKey,
631
- authScheme: envAuthScheme ?? "api-key"
632
- };
655
+ const envCredential = selectCloudCredential({
656
+ apiKey: options.env.OPENSTEER_API_KEY,
657
+ accessToken: options.env.OPENSTEER_ACCESS_TOKEN,
658
+ authScheme: envAuthScheme
659
+ });
660
+ if (envCredential) {
661
+ return toResolvedCloudCredential("env", envCredential);
633
662
  }
634
663
  return null;
635
664
  }
@@ -659,6 +688,23 @@ function normalizeToken(value) {
659
688
  const normalized = value.trim();
660
689
  return normalized.length ? normalized : void 0;
661
690
  }
691
+ function toResolvedCloudCredential(source, credential) {
692
+ if (credential.compatibilityBearerApiKey) {
693
+ return {
694
+ kind: credential.kind,
695
+ source,
696
+ token: credential.token,
697
+ authScheme: credential.authScheme,
698
+ compatibilityBearerApiKey: true
699
+ };
700
+ }
701
+ return {
702
+ kind: credential.kind,
703
+ source,
704
+ token: credential.token,
705
+ authScheme: credential.authScheme
706
+ };
707
+ }
662
708
 
663
709
  // src/auth/machine-credential-store.ts
664
710
  var import_node_crypto = require("crypto");
@@ -1729,8 +1775,6 @@ async function runLogin(args, deps) {
1729
1775
  return 0;
1730
1776
  }
1731
1777
  writeHumanLine(deps, "Opensteer CLI login successful.");
1732
- writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
1733
- writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
1734
1778
  return 0;
1735
1779
  }
1736
1780
  async function runStatus(args, deps) {