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

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
@@ -2,57 +2,46 @@
2
2
 
3
3
  <img width="1107" height="525" alt="screenshot" src="https://github.com/user-attachments/assets/511a6118-e470-4955-b5a0-c8d9672d060b" />
4
4
 
5
- OpenCode TUI plugin for saving and switching between multiple OpenAI OAuth accounts with a single `/switch` command.
6
-
5
+ OpenCode TUI plugin for switching between saved OpenAI OAuth accounts with a single `/switch` command.
7
6
 
8
7
  ## Features
9
8
 
10
- - one `/switch` command for login, switch, and remove
11
- - reuses the native OpenCode OpenAI OAuth flow
12
- - stores saved accounts in a plugin-owned JSON file
13
- - switches only `auth.json.openai` when you pick an account
14
- - keeps saved-account removal separate from active auth
15
- - supports multiple credentials for the same email by keying entries from the refresh token hash
16
-
17
- ## Behavior
18
-
19
- The `/switch` dialog can show:
9
+ - one `/switch` command for login, switching, and removal
10
+ - uses the native OpenCode OpenAI OAuth flow
11
+ - supports multiple saved accounts
12
+ - marks the current account in the picker
13
+ - keeps saved-account removal separate from the active session
20
14
 
21
- - `login`
22
- - saved accounts
23
- - `logout`
15
+ ## Installation
24
16
 
25
- Saved accounts are displayed with:
17
+ Install the plugin with the OpenCode plugin command:
26
18
 
27
- - title: email, or account id, or generated fallback key
28
- - footer: `Current` for the active credential
29
-
30
- `login` behavior:
19
+ ```bash
20
+ opencode plugin @harars/opencode-switch-openai-auth-plugin
21
+ ```
31
22
 
32
- - calls the native OpenCode provider auth flow for `openai`
33
- - rereads the active OpenAI auth after OAuth completes
34
- - saves that credential into `auth-switch/accounts.json`
23
+ ## Usage
35
24
 
36
- `switch` behavior:
25
+ Run the command below in OpenCode:
37
26
 
38
- - writes the selected saved credential into `auth.json.openai`
39
- - refreshes host auth state when runtime support is available
27
+ ```text
28
+ /switch
29
+ ```
40
30
 
41
- `logout` behavior:
31
+ From there you can:
42
32
 
43
- - removes a saved credential from the plugin store
44
- - does not delete the currently active OpenAI auth from `auth.json`
33
+ - sign in with another OpenAI account
34
+ - switch to a saved account
35
+ - remove a saved account
45
36
 
46
37
  ## Storage
47
38
 
48
- Plugin account store locations:
39
+ Saved accounts are stored in a plugin-managed JSON file:
49
40
 
50
41
  - Linux: `~/.local/share/opencode/auth-switch/accounts.json`
51
42
  - macOS: `~/Library/Application Support/opencode/auth-switch/accounts.json`
52
43
  - Windows: `%LOCALAPPDATA%/opencode/auth-switch/accounts.json`
53
44
 
54
- `OPENCODE_TEST_HOME` is supported for tests.
55
-
56
45
  ## Local Development
57
46
 
58
47
  Install dependencies:
@@ -68,28 +57,13 @@ bun test
68
57
  bunx tsc -p tsconfig.json --noEmit
69
58
  ```
70
59
 
71
- ## Loading The Plugin
72
-
73
- After publishing to npm, add the package name directly to your OpenCode `tui.json`.
60
+ Build the package output:
74
61
 
75
- Example:
76
-
77
- ```json
78
- {
79
- "plugin": [
80
- "@harars/opencode-switch-openai-auth-plugin"
81
- ],
82
- "plugin_enabled": {
83
- "harars.switch-auth": true
84
- }
85
- }
62
+ ```bash
63
+ bun run build
86
64
  ```
87
65
 
88
- This package should publish built `dist` files so OpenCode can load the plugin from the installed package.
89
-
90
- For local development, you can still point `tui.json` at a local file path.
91
-
92
- Example local file setup:
66
+ For local development, point your workspace `tui.json` at the local source entry:
93
67
 
94
68
  ```json
95
69
  {
@@ -105,5 +79,4 @@ Example local file setup:
105
79
  ## Package
106
80
 
107
81
  - package name: `@harars/opencode-switch-openai-auth-plugin`
108
- - plugin id: `harars.switch-auth`
109
82
  - license: MIT
package/dist/index.js CHANGED
@@ -437,6 +437,37 @@ function same(prev, next) {
437
437
  return false;
438
438
  return prev.refresh === next.refresh;
439
439
  }
440
+ function unwrap(input) {
441
+ if (!input || typeof input !== "object") {
442
+ return {
443
+ ok: true,
444
+ data: input
445
+ };
446
+ }
447
+ if ("error" in input && input.error !== undefined) {
448
+ return {
449
+ ok: false
450
+ };
451
+ }
452
+ if ("data" in input) {
453
+ return input.data === undefined ? {
454
+ ok: false
455
+ } : {
456
+ ok: true,
457
+ data: input.data
458
+ };
459
+ }
460
+ return {
461
+ ok: true,
462
+ data: input
463
+ };
464
+ }
465
+ async function authMethods(api) {
466
+ const res = unwrap(await api.client.provider.auth());
467
+ if (!res.ok)
468
+ return [];
469
+ return res.data.openai ?? [];
470
+ }
440
471
  function bind(api, authz) {
441
472
  useKeyboard((evt) => {
442
473
  if (evt.name !== "c" || evt.ctrl || evt.meta)
@@ -668,17 +699,15 @@ async function auto(api, index, method, authz) {
668
699
  }
669
700
  async function hasLogin(api) {
670
701
  try {
671
- const res = await api.client.provider.auth();
672
- const methods = res.data?.openai ?? [];
673
- return methods.some((item) => item.type === "oauth");
702
+ return (await authMethods(api)).some((item) => item.type === "oauth");
674
703
  } catch {
675
704
  return false;
676
705
  }
677
706
  }
678
707
  async function loginOpenAI(api) {
679
708
  try {
680
- const auth = await api.client.provider.auth();
681
- const methods = (auth.data?.openai ?? []).map((method2, index2) => ({
709
+ const available = await authMethods(api);
710
+ const methods = available.map((method2, index2) => ({
682
711
  method: method2,
683
712
  index: index2
684
713
  })).filter((item) => item.method.type === "oauth");
@@ -697,12 +726,12 @@ async function loginOpenAI(api) {
697
726
  const inputs = await prompts(api, method.label, method);
698
727
  if (method.prompts?.length && !inputs)
699
728
  return false;
700
- const authz = await api.client.provider.oauth.authorize({
729
+ const authz = unwrap(await api.client.provider.oauth.authorize({
701
730
  providerID: "openai",
702
731
  method: picked.index,
703
732
  inputs
704
- });
705
- if (authz.error || !authz.data) {
733
+ }));
734
+ if (!authz.ok) {
706
735
  api.ui.toast({
707
736
  variant: "error",
708
737
  message: "Login failed"
package/dist/tui.js CHANGED
@@ -437,6 +437,37 @@ function same(prev, next) {
437
437
  return false;
438
438
  return prev.refresh === next.refresh;
439
439
  }
440
+ function unwrap(input) {
441
+ if (!input || typeof input !== "object") {
442
+ return {
443
+ ok: true,
444
+ data: input
445
+ };
446
+ }
447
+ if ("error" in input && input.error !== undefined) {
448
+ return {
449
+ ok: false
450
+ };
451
+ }
452
+ if ("data" in input) {
453
+ return input.data === undefined ? {
454
+ ok: false
455
+ } : {
456
+ ok: true,
457
+ data: input.data
458
+ };
459
+ }
460
+ return {
461
+ ok: true,
462
+ data: input
463
+ };
464
+ }
465
+ async function authMethods(api) {
466
+ const res = unwrap(await api.client.provider.auth());
467
+ if (!res.ok)
468
+ return [];
469
+ return res.data.openai ?? [];
470
+ }
440
471
  function bind(api, authz) {
441
472
  useKeyboard((evt) => {
442
473
  if (evt.name !== "c" || evt.ctrl || evt.meta)
@@ -668,17 +699,15 @@ async function auto(api, index, method, authz) {
668
699
  }
669
700
  async function hasLogin(api) {
670
701
  try {
671
- const res = await api.client.provider.auth();
672
- const methods = res.data?.openai ?? [];
673
- return methods.some((item) => item.type === "oauth");
702
+ return (await authMethods(api)).some((item) => item.type === "oauth");
674
703
  } catch {
675
704
  return false;
676
705
  }
677
706
  }
678
707
  async function loginOpenAI(api) {
679
708
  try {
680
- const auth = await api.client.provider.auth();
681
- const methods = (auth.data?.openai ?? []).map((method2, index2) => ({
709
+ const available = await authMethods(api);
710
+ const methods = available.map((method2, index2) => ({
682
711
  method: method2,
683
712
  index: index2
684
713
  })).filter((item) => item.method.type === "oauth");
@@ -697,12 +726,12 @@ async function loginOpenAI(api) {
697
726
  const inputs = await prompts(api, method.label, method);
698
727
  if (method.prompts?.length && !inputs)
699
728
  return false;
700
- const authz = await api.client.provider.oauth.authorize({
729
+ const authz = unwrap(await api.client.provider.oauth.authorize({
701
730
  providerID: "openai",
702
731
  method: picked.index,
703
732
  inputs
704
- });
705
- if (authz.error || !authz.data) {
733
+ }));
734
+ if (!authz.ok) {
706
735
  api.ui.toast({
707
736
  variant: "error",
708
737
  message: "Login failed"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harars/opencode-switch-openai-auth-plugin",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "OpenCode TUI plugin for switching saved OpenAI OAuth accounts",
5
5
  "repository": {
6
6
  "type": "git",