@harars/opencode-switch-openai-auth-plugin 0.1.4 → 0.1.6

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 (3) hide show
  1. package/dist/index.js +61 -21
  2. package/dist/tui.js +61 -21
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ import { insert as _$insert } from "@opentui/solid";
39
39
  import { setProp as _$setProp } from "@opentui/solid";
40
40
  import { createElement as _$createElement } from "@opentui/solid";
41
41
  import { TextAttributes } from "@opentui/core";
42
+ import { onMount } from "solid-js";
42
43
  import { useKeyboard } from "@opentui/solid";
43
44
 
44
45
  // src/login-helpers.ts
@@ -74,12 +75,34 @@ async function clip(text) {
74
75
  function target(authz) {
75
76
  return authz.instructions.match(/[A-Z0-9]{4}-[A-Z0-9]{4,5}/)?.[0] ?? authz.url;
76
77
  }
78
+ function detail(err) {
79
+ if (err instanceof Error)
80
+ return err.message;
81
+ if (typeof err === "string")
82
+ return err;
83
+ try {
84
+ return JSON.stringify(err);
85
+ } catch {
86
+ return String(err);
87
+ }
88
+ }
89
+ function explain(err) {
90
+ const msg = detail(err);
91
+ const port = msg.match(/port\s+(\d+)\s+in use/i)?.[1];
92
+ if (port) {
93
+ return `Browser login could not start because local port ${port} is already in use. Close the other OpenCode login window or finish the other browser login first.`;
94
+ }
95
+ if (msg.includes("this.client") || msg.includes("\u672A\u5B9A\u4E49\u7684\u4E0D\u662F\u4E00\u4E2Aobject")) {
96
+ return "Browser login callback failed inside OpenCode. Update the plugin to the latest version and retry.";
97
+ }
98
+ return msg;
99
+ }
77
100
  async function runOAuthCallback(callback, input) {
78
101
  try {
79
102
  const res = await callback(input);
80
- return !res.error;
81
- } catch {
82
- return false;
103
+ return res.error ? { ok: false, error: res.error } : { ok: true };
104
+ } catch (err) {
105
+ return { ok: false, error: detail(err) };
83
106
  }
84
107
  }
85
108
 
@@ -428,6 +451,8 @@ function visible(prompt, values) {
428
451
  if (!prompt.when)
429
452
  return true;
430
453
  const cur = values[prompt.when.key];
454
+ if (cur === undefined)
455
+ return false;
431
456
  if (prompt.when.op === "eq")
432
457
  return cur === prompt.when.value;
433
458
  return cur !== prompt.when.value;
@@ -446,12 +471,14 @@ function unwrap(input) {
446
471
  }
447
472
  if ("error" in input && input.error !== undefined) {
448
473
  return {
449
- ok: false
474
+ ok: false,
475
+ error: input.error
450
476
  };
451
477
  }
452
478
  if ("data" in input) {
453
479
  return input.data === undefined ? {
454
- ok: false
480
+ ok: false,
481
+ error: "Missing response data"
455
482
  } : {
456
483
  ok: true,
457
484
  data: input.data
@@ -482,6 +509,9 @@ function bind(api, authz) {
482
509
  }
483
510
  function WaitView(props) {
484
511
  bind(props.api, props.authz);
512
+ onMount(() => {
513
+ props.run();
514
+ });
485
515
  return (() => {
486
516
  var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"), _el$5 = _$createElement("text"), _el$7 = _$createElement("text");
487
517
  _$insertNode(_el$, _el$2);
@@ -532,9 +562,9 @@ function wait(api, title, authz, run) {
532
562
  api.ui.dialog.replace(() => _$createComponent(WaitView, {
533
563
  api,
534
564
  title,
535
- authz
565
+ authz,
566
+ run
536
567
  }));
537
- run();
538
568
  }
539
569
  async function choose(api, methods) {
540
570
  if (methods.length === 1)
@@ -660,19 +690,25 @@ async function code(api, index, method, authz) {
660
690
  },
661
691
  authz,
662
692
  onConfirm: async (value) => {
663
- resolve(await runOAuthCallback(api.client.provider.oauth.callback, {
693
+ resolve(await runOAuthCallback((input) => api.client.provider.oauth.callback(input), {
664
694
  providerID: "openai",
665
695
  method: index,
666
696
  code: value
667
697
  }));
668
698
  },
669
- onCancel: () => resolve(false)
670
- }), () => resolve(false));
699
+ onCancel: () => resolve({
700
+ ok: false,
701
+ error: "Cancelled"
702
+ })
703
+ }), () => resolve({
704
+ ok: false,
705
+ error: "Cancelled"
706
+ }));
671
707
  });
672
- if (!ok) {
708
+ if (!ok.ok) {
673
709
  api.ui.toast({
674
710
  variant: "error",
675
- message: "Login failed"
711
+ message: `Login failed: ${explain(ok.error)}`
676
712
  });
677
713
  return false;
678
714
  }
@@ -682,16 +718,16 @@ async function auto(api, index, method, authz) {
682
718
  const prev = await readCurrentAuth();
683
719
  const ok = await new Promise((resolve) => {
684
720
  wait(api, method.label, authz, async () => {
685
- resolve(await runOAuthCallback(api.client.provider.oauth.callback, {
721
+ resolve(await runOAuthCallback((input) => api.client.provider.oauth.callback(input), {
686
722
  providerID: "openai",
687
723
  method: index
688
724
  }));
689
725
  });
690
726
  });
691
- if (!ok) {
727
+ if (!ok.ok) {
692
728
  api.ui.toast({
693
729
  variant: "error",
694
- message: "Login failed"
730
+ message: `Login failed: ${explain(ok.error)}`
695
731
  });
696
732
  return false;
697
733
  }
@@ -723,9 +759,13 @@ async function loginOpenAI(api) {
723
759
  return false;
724
760
  const picked = methods[index];
725
761
  const method = picked.method;
726
- const inputs = await prompts(api, method.label, method);
727
- if (method.prompts?.length && !inputs)
728
- return false;
762
+ let inputs;
763
+ if (method.prompts?.length) {
764
+ const value = await prompts(api, method.label, method);
765
+ if (!value)
766
+ return false;
767
+ inputs = value;
768
+ }
729
769
  const authz = unwrap(await api.client.provider.oauth.authorize({
730
770
  providerID: "openai",
731
771
  method: picked.index,
@@ -734,7 +774,7 @@ async function loginOpenAI(api) {
734
774
  if (!authz.ok) {
735
775
  api.ui.toast({
736
776
  variant: "error",
737
- message: "Login failed"
777
+ message: `Login failed: ${explain(authz.error)}`
738
778
  });
739
779
  return false;
740
780
  }
@@ -747,10 +787,10 @@ async function loginOpenAI(api) {
747
787
  message: "Unsupported auth method"
748
788
  });
749
789
  return false;
750
- } catch {
790
+ } catch (err) {
751
791
  api.ui.toast({
752
792
  variant: "error",
753
- message: "Login failed"
793
+ message: `Login failed: ${explain(err)}`
754
794
  });
755
795
  return false;
756
796
  }
package/dist/tui.js CHANGED
@@ -39,6 +39,7 @@ import { insert as _$insert } from "@opentui/solid";
39
39
  import { setProp as _$setProp } from "@opentui/solid";
40
40
  import { createElement as _$createElement } from "@opentui/solid";
41
41
  import { TextAttributes } from "@opentui/core";
42
+ import { onMount } from "solid-js";
42
43
  import { useKeyboard } from "@opentui/solid";
43
44
 
44
45
  // src/login-helpers.ts
@@ -74,12 +75,34 @@ async function clip(text) {
74
75
  function target(authz) {
75
76
  return authz.instructions.match(/[A-Z0-9]{4}-[A-Z0-9]{4,5}/)?.[0] ?? authz.url;
76
77
  }
78
+ function detail(err) {
79
+ if (err instanceof Error)
80
+ return err.message;
81
+ if (typeof err === "string")
82
+ return err;
83
+ try {
84
+ return JSON.stringify(err);
85
+ } catch {
86
+ return String(err);
87
+ }
88
+ }
89
+ function explain(err) {
90
+ const msg = detail(err);
91
+ const port = msg.match(/port\s+(\d+)\s+in use/i)?.[1];
92
+ if (port) {
93
+ return `Browser login could not start because local port ${port} is already in use. Close the other OpenCode login window or finish the other browser login first.`;
94
+ }
95
+ if (msg.includes("this.client") || msg.includes("\u672A\u5B9A\u4E49\u7684\u4E0D\u662F\u4E00\u4E2Aobject")) {
96
+ return "Browser login callback failed inside OpenCode. Update the plugin to the latest version and retry.";
97
+ }
98
+ return msg;
99
+ }
77
100
  async function runOAuthCallback(callback, input) {
78
101
  try {
79
102
  const res = await callback(input);
80
- return !res.error;
81
- } catch {
82
- return false;
103
+ return res.error ? { ok: false, error: res.error } : { ok: true };
104
+ } catch (err) {
105
+ return { ok: false, error: detail(err) };
83
106
  }
84
107
  }
85
108
 
@@ -428,6 +451,8 @@ function visible(prompt, values) {
428
451
  if (!prompt.when)
429
452
  return true;
430
453
  const cur = values[prompt.when.key];
454
+ if (cur === undefined)
455
+ return false;
431
456
  if (prompt.when.op === "eq")
432
457
  return cur === prompt.when.value;
433
458
  return cur !== prompt.when.value;
@@ -446,12 +471,14 @@ function unwrap(input) {
446
471
  }
447
472
  if ("error" in input && input.error !== undefined) {
448
473
  return {
449
- ok: false
474
+ ok: false,
475
+ error: input.error
450
476
  };
451
477
  }
452
478
  if ("data" in input) {
453
479
  return input.data === undefined ? {
454
- ok: false
480
+ ok: false,
481
+ error: "Missing response data"
455
482
  } : {
456
483
  ok: true,
457
484
  data: input.data
@@ -482,6 +509,9 @@ function bind(api, authz) {
482
509
  }
483
510
  function WaitView(props) {
484
511
  bind(props.api, props.authz);
512
+ onMount(() => {
513
+ props.run();
514
+ });
485
515
  return (() => {
486
516
  var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"), _el$5 = _$createElement("text"), _el$7 = _$createElement("text");
487
517
  _$insertNode(_el$, _el$2);
@@ -532,9 +562,9 @@ function wait(api, title, authz, run) {
532
562
  api.ui.dialog.replace(() => _$createComponent(WaitView, {
533
563
  api,
534
564
  title,
535
- authz
565
+ authz,
566
+ run
536
567
  }));
537
- run();
538
568
  }
539
569
  async function choose(api, methods) {
540
570
  if (methods.length === 1)
@@ -660,19 +690,25 @@ async function code(api, index, method, authz) {
660
690
  },
661
691
  authz,
662
692
  onConfirm: async (value) => {
663
- resolve(await runOAuthCallback(api.client.provider.oauth.callback, {
693
+ resolve(await runOAuthCallback((input) => api.client.provider.oauth.callback(input), {
664
694
  providerID: "openai",
665
695
  method: index,
666
696
  code: value
667
697
  }));
668
698
  },
669
- onCancel: () => resolve(false)
670
- }), () => resolve(false));
699
+ onCancel: () => resolve({
700
+ ok: false,
701
+ error: "Cancelled"
702
+ })
703
+ }), () => resolve({
704
+ ok: false,
705
+ error: "Cancelled"
706
+ }));
671
707
  });
672
- if (!ok) {
708
+ if (!ok.ok) {
673
709
  api.ui.toast({
674
710
  variant: "error",
675
- message: "Login failed"
711
+ message: `Login failed: ${explain(ok.error)}`
676
712
  });
677
713
  return false;
678
714
  }
@@ -682,16 +718,16 @@ async function auto(api, index, method, authz) {
682
718
  const prev = await readCurrentAuth();
683
719
  const ok = await new Promise((resolve) => {
684
720
  wait(api, method.label, authz, async () => {
685
- resolve(await runOAuthCallback(api.client.provider.oauth.callback, {
721
+ resolve(await runOAuthCallback((input) => api.client.provider.oauth.callback(input), {
686
722
  providerID: "openai",
687
723
  method: index
688
724
  }));
689
725
  });
690
726
  });
691
- if (!ok) {
727
+ if (!ok.ok) {
692
728
  api.ui.toast({
693
729
  variant: "error",
694
- message: "Login failed"
730
+ message: `Login failed: ${explain(ok.error)}`
695
731
  });
696
732
  return false;
697
733
  }
@@ -723,9 +759,13 @@ async function loginOpenAI(api) {
723
759
  return false;
724
760
  const picked = methods[index];
725
761
  const method = picked.method;
726
- const inputs = await prompts(api, method.label, method);
727
- if (method.prompts?.length && !inputs)
728
- return false;
762
+ let inputs;
763
+ if (method.prompts?.length) {
764
+ const value = await prompts(api, method.label, method);
765
+ if (!value)
766
+ return false;
767
+ inputs = value;
768
+ }
729
769
  const authz = unwrap(await api.client.provider.oauth.authorize({
730
770
  providerID: "openai",
731
771
  method: picked.index,
@@ -734,7 +774,7 @@ async function loginOpenAI(api) {
734
774
  if (!authz.ok) {
735
775
  api.ui.toast({
736
776
  variant: "error",
737
- message: "Login failed"
777
+ message: `Login failed: ${explain(authz.error)}`
738
778
  });
739
779
  return false;
740
780
  }
@@ -747,10 +787,10 @@ async function loginOpenAI(api) {
747
787
  message: "Unsupported auth method"
748
788
  });
749
789
  return false;
750
- } catch {
790
+ } catch (err) {
751
791
  api.ui.toast({
752
792
  variant: "error",
753
- message: "Login failed"
793
+ message: `Login failed: ${explain(err)}`
754
794
  });
755
795
  return false;
756
796
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harars/opencode-switch-openai-auth-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "OpenCode TUI plugin for switching saved OpenAI OAuth accounts",
5
5
  "repository": {
6
6
  "type": "git",