axauth 2.1.0 → 3.0.0
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 +10 -4
- package/dist/auth/adapter.d.ts +60 -20
- package/dist/auth/agents/claude-install.d.ts +11 -0
- package/dist/auth/agents/claude-install.js +80 -0
- package/dist/auth/agents/claude-storage.d.ts +13 -5
- package/dist/auth/agents/claude-storage.js +11 -16
- package/dist/auth/agents/claude.js +14 -89
- package/dist/auth/agents/codex-auth-check.d.ts +6 -5
- package/dist/auth/agents/codex-auth-check.js +34 -20
- package/dist/auth/agents/codex-install.js +1 -2
- package/dist/auth/agents/codex-storage.d.ts +0 -1
- package/dist/auth/agents/codex-storage.js +4 -5
- package/dist/auth/agents/codex.js +4 -4
- package/dist/auth/agents/copilot-install.js +2 -3
- package/dist/auth/agents/copilot.js +11 -6
- package/dist/auth/agents/gemini-install.d.ts +1 -1
- package/dist/auth/agents/gemini-install.js +3 -3
- package/dist/auth/agents/gemini.js +19 -17
- package/dist/auth/agents/opencode-credentials.d.ts +25 -37
- package/dist/auth/agents/opencode-credentials.js +48 -122
- package/dist/auth/agents/opencode-remove-provider.d.ts +25 -0
- package/dist/auth/agents/opencode-remove-provider.js +86 -0
- package/dist/auth/agents/opencode-storage.js +18 -22
- package/dist/auth/agents/opencode.d.ts +1 -1
- package/dist/auth/agents/opencode.js +59 -41
- package/dist/auth/build-refreshed-credentials.d.ts +6 -4
- package/dist/auth/build-refreshed-credentials.js +34 -19
- package/dist/auth/extract-creds-from-directory.d.ts +7 -3
- package/dist/auth/extract-creds-from-directory.js +4 -1
- package/dist/auth/refresh-credentials.d.ts +38 -12
- package/dist/auth/refresh-credentials.js +49 -18
- package/dist/auth/registry.d.ts +18 -15
- package/dist/auth/registry.js +35 -18
- package/dist/auth/resolve-refresh-credentials.d.ts +11 -8
- package/dist/auth/resolve-refresh-credentials.js +12 -48
- package/dist/auth/types.d.ts +3 -35
- package/dist/auth/types.js +2 -47
- package/dist/auth/wait-for-refreshed-credentials.d.ts +5 -1
- package/dist/auth/wait-for-refreshed-credentials.js +7 -4
- package/dist/commands/auth-export.js +24 -46
- package/dist/commands/auth.js +13 -3
- package/dist/commands/copy-to-clipboard.d.ts +6 -0
- package/dist/commands/copy-to-clipboard.js +48 -0
- package/dist/commands/vault.js +16 -15
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/vault/vault-client.js +21 -2
- package/package.json +7 -7
|
@@ -65,17 +65,16 @@ function buildAuthContent(type, data) {
|
|
|
65
65
|
if (type === "api-key") {
|
|
66
66
|
return { OPENAI_API_KEY: data.apiKey };
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const auth = rest;
|
|
68
|
+
// source is now at top-level, so data is clean
|
|
69
|
+
if ("tokens" in data) {
|
|
70
|
+
const auth = data;
|
|
72
71
|
if (!auth.last_refresh) {
|
|
73
72
|
auth.last_refresh = new Date().toISOString();
|
|
74
73
|
}
|
|
75
74
|
return auth;
|
|
76
75
|
}
|
|
77
76
|
return {
|
|
78
|
-
tokens:
|
|
77
|
+
tokens: data,
|
|
79
78
|
last_refresh: new Date().toISOString(),
|
|
80
79
|
};
|
|
81
80
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
|
-
import { checkAuth,
|
|
8
|
+
import { checkAuth, findStoredCredentials, getEnvironmentCredentials, } from "./codex-auth-check.js";
|
|
9
9
|
import { CREDS_FILE_NAME, installCodexCredentials, removeCodexCredentials, } from "./codex-install.js";
|
|
10
10
|
const AGENT_ID = "codex";
|
|
11
11
|
/** Codex authentication adapter */
|
|
@@ -18,9 +18,9 @@ const codexAdapter = {
|
|
|
18
18
|
installApiKey: true,
|
|
19
19
|
},
|
|
20
20
|
checkAuth,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
getEnvironmentCredentials,
|
|
22
|
+
findStoredCredentials,
|
|
23
|
+
loadCredentialsFromDirectory(options) {
|
|
24
24
|
// Codex doesn't separate config/data - use either directory
|
|
25
25
|
const directory = options.dataDir ?? options.configDir;
|
|
26
26
|
if (!directory)
|
|
@@ -40,9 +40,8 @@ function installCopilotCredentials(creds, resolved, options) {
|
|
|
40
40
|
message: `Failed to install credentials to ${targetPath}`,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
// Default location: use storage option or
|
|
44
|
-
const
|
|
45
|
-
const targetStorage = options?.storage ?? (sourceMarker === "keychain" ? "keychain" : "file");
|
|
43
|
+
// Default location: use storage option or default to file
|
|
44
|
+
const targetStorage = options?.storage ?? "file";
|
|
46
45
|
if (targetStorage === "keychain") {
|
|
47
46
|
if (!isMacOS()) {
|
|
48
47
|
return {
|
|
@@ -37,7 +37,7 @@ const copilotAdapter = {
|
|
|
37
37
|
method: methodMap[result.source],
|
|
38
38
|
};
|
|
39
39
|
},
|
|
40
|
-
|
|
40
|
+
getEnvironmentCredentials() {
|
|
41
41
|
const token = getEnvironmentToken();
|
|
42
42
|
if (!token)
|
|
43
43
|
return undefined;
|
|
@@ -47,17 +47,22 @@ const copilotAdapter = {
|
|
|
47
47
|
data: { accessToken: token },
|
|
48
48
|
};
|
|
49
49
|
},
|
|
50
|
-
|
|
50
|
+
findStoredCredentials() {
|
|
51
51
|
const result = findFirstAvailableToken();
|
|
52
52
|
if (!result)
|
|
53
53
|
return undefined;
|
|
54
|
+
// Map TokenSource to CredentialSource (environment/gh-cli -> file)
|
|
55
|
+
const source = result.source === "keychain" ? "keychain" : "file";
|
|
54
56
|
return {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
credentials: {
|
|
58
|
+
agent: AGENT_ID,
|
|
59
|
+
type: "oauth-token",
|
|
60
|
+
data: { accessToken: result.token },
|
|
61
|
+
},
|
|
62
|
+
source,
|
|
58
63
|
};
|
|
59
64
|
},
|
|
60
|
-
|
|
65
|
+
loadCredentialsFromDirectory(options) {
|
|
61
66
|
// Copilot doesn't separate config/data - use either directory
|
|
62
67
|
const directory = options.dataDir ?? options.configDir;
|
|
63
68
|
if (!directory)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { InstallOptions, OperationResult, RemoveOptions } from "../adapter.js";
|
|
7
7
|
/** Install OAuth credentials to storage */
|
|
8
|
-
declare function installOAuthCredentials(oauthData: Record<string, unknown>,
|
|
8
|
+
declare function installOAuthCredentials(oauthData: Record<string, unknown>, options?: InstallOptions): OperationResult;
|
|
9
9
|
/** Remove credentials from storage */
|
|
10
10
|
declare function removeGeminiCredentials(options?: RemoveOptions): OperationResult;
|
|
11
11
|
export { installOAuthCredentials, removeGeminiCredentials };
|
|
@@ -11,7 +11,7 @@ import { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds, getDe
|
|
|
11
11
|
const AGENT_ID = "gemini";
|
|
12
12
|
const CREDS_FILE_NAME = "oauth_creds.json";
|
|
13
13
|
/** Install OAuth credentials to storage */
|
|
14
|
-
function installOAuthCredentials(oauthData,
|
|
14
|
+
function installOAuthCredentials(oauthData, options) {
|
|
15
15
|
// Resolve custom directory with validation
|
|
16
16
|
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
17
17
|
if (!resolved.ok)
|
|
@@ -20,8 +20,8 @@ function installOAuthCredentials(oauthData, source, options) {
|
|
|
20
20
|
if (resolved.customDir) {
|
|
21
21
|
return installToCustomDirectory(oauthData, resolved.customDir);
|
|
22
22
|
}
|
|
23
|
-
// Default location: use storage option
|
|
24
|
-
const targetStorage = options?.storage ??
|
|
23
|
+
// Default location: use storage option, default to file
|
|
24
|
+
const targetStorage = options?.storage ?? "file";
|
|
25
25
|
if (targetStorage === "keychain") {
|
|
26
26
|
return installToKeychain(oauthData);
|
|
27
27
|
}
|
|
@@ -29,9 +29,9 @@ const geminiAdapter = {
|
|
|
29
29
|
method: result.method,
|
|
30
30
|
};
|
|
31
31
|
},
|
|
32
|
-
|
|
32
|
+
getEnvironmentCredentials() {
|
|
33
33
|
const result = checkEnvironmentAuth();
|
|
34
|
-
if (!result
|
|
34
|
+
if (!result?.data)
|
|
35
35
|
return undefined;
|
|
36
36
|
return {
|
|
37
37
|
agent: AGENT_ID,
|
|
@@ -39,29 +39,32 @@ const geminiAdapter = {
|
|
|
39
39
|
data: result.data,
|
|
40
40
|
};
|
|
41
41
|
},
|
|
42
|
-
|
|
42
|
+
findStoredCredentials() {
|
|
43
43
|
const result = findCredentials();
|
|
44
|
-
if (!result
|
|
44
|
+
if (!result?.data)
|
|
45
45
|
return undefined;
|
|
46
|
-
// Env-sourced credentials (api-key, vertex-ai) are read-only,
|
|
46
|
+
// Env-sourced credentials (api-key, vertex-ai) are read-only, treat as file
|
|
47
47
|
if (result.source === "api-key" || result.source === "vertex-ai") {
|
|
48
48
|
return {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
credentials: {
|
|
50
|
+
agent: AGENT_ID,
|
|
51
|
+
type: "api-key",
|
|
52
|
+
data: result.data,
|
|
53
|
+
},
|
|
54
|
+
source: "file",
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
|
-
// OAuth credentials from keychain or file
|
|
57
|
+
// OAuth credentials from keychain or file - return source separately
|
|
55
58
|
return {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
_source: result.source === "keychain" ? "keychain" : "file",
|
|
59
|
+
credentials: {
|
|
60
|
+
agent: AGENT_ID,
|
|
61
|
+
type: "oauth-credentials",
|
|
62
|
+
data: result.data,
|
|
61
63
|
},
|
|
64
|
+
source: result.source === "keychain" ? "keychain" : "file",
|
|
62
65
|
};
|
|
63
66
|
},
|
|
64
|
-
|
|
67
|
+
loadCredentialsFromDirectory(options) {
|
|
65
68
|
// Gemini doesn't separate config/data - use either directory
|
|
66
69
|
const directory = options.dataDir ?? options.configDir;
|
|
67
70
|
if (!directory)
|
|
@@ -75,8 +78,7 @@ const geminiAdapter = {
|
|
|
75
78
|
message: "API key credentials cannot be installed (use GEMINI_API_KEY env var)",
|
|
76
79
|
};
|
|
77
80
|
}
|
|
78
|
-
|
|
79
|
-
return installOAuthCredentials(oauthData, _source, options);
|
|
81
|
+
return installOAuthCredentials(creds.data, options);
|
|
80
82
|
},
|
|
81
83
|
removeCredentials(options) {
|
|
82
84
|
return removeGeminiCredentials(options);
|
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenCode per-provider credential handling.
|
|
3
3
|
*
|
|
4
|
-
* Handles
|
|
5
|
-
* from OpenCode's
|
|
4
|
+
* Handles extracting and removing individual provider credentials
|
|
5
|
+
* from OpenCode's auth.json file.
|
|
6
6
|
*/
|
|
7
|
+
import type { CredentialType } from "axshared";
|
|
7
8
|
import type { Credentials } from "../types.js";
|
|
9
|
+
import { OpenCodeAuth } from "./opencode-schema.js";
|
|
8
10
|
declare const AGENT_ID: "opencode";
|
|
9
11
|
declare const CREDS_FILE_NAME = "auth.json";
|
|
10
12
|
/** Gets the default auth file path for OpenCode. */
|
|
11
13
|
declare function getDefaultAuthFilePath(): string;
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* Maps OpenCode auth entry type to axauth credential type.
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* - `oauth` -> `oauth-credentials` (refreshable)
|
|
18
|
+
* - `api` -> `api-key` (static)
|
|
19
|
+
* - `wellknown` -> `api-key` (static, treated as API key for simplicity)
|
|
20
|
+
*/
|
|
21
|
+
declare function mapToCredentialType(entry: OpenCodeAuth): CredentialType;
|
|
22
|
+
interface StoredCredentialsOptions {
|
|
23
|
+
/** Custom data directory (overrides default) */
|
|
24
|
+
dataDir?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get all stored credentials as per-provider entries.
|
|
17
28
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* // Output: [
|
|
21
|
-
* // { agent: "opencode", provider: "anthropic", type: "oauth-credentials", data: {...} },
|
|
22
|
-
* // { agent: "opencode", provider: "cerebras", type: "api-key", data: {...} }
|
|
23
|
-
* // ]
|
|
29
|
+
* Reads auth.json from disk and returns an array of per-provider credentials.
|
|
30
|
+
* Used by CLI commands that need to export or list all providers.
|
|
24
31
|
*/
|
|
25
|
-
declare function
|
|
32
|
+
declare function getAllStoredCredentials(options?: StoredCredentialsOptions): Credentials[];
|
|
26
33
|
/**
|
|
27
|
-
*
|
|
34
|
+
* Get stored credentials for a specific provider.
|
|
28
35
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* @returns Per-provider credential or undefined if provider not found
|
|
36
|
+
* Reads auth.json from disk and returns credentials for the specified provider.
|
|
37
|
+
* Used by CLI commands that need a specific provider's credentials.
|
|
32
38
|
*/
|
|
33
|
-
declare function
|
|
39
|
+
declare function getStoredCredentialsForProvider(provider: string, options?: StoredCredentialsOptions): Credentials | undefined;
|
|
34
40
|
type ReadAuthResult = {
|
|
35
41
|
ok: true;
|
|
36
42
|
data: Record<string, unknown> | undefined;
|
|
@@ -46,23 +52,5 @@ type ReadAuthResult = {
|
|
|
46
52
|
* Returns { ok: false, error: "..." } if file exists but cannot be read/parsed.
|
|
47
53
|
*/
|
|
48
54
|
declare function readAuthFile(authFile: string): ReadAuthResult;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
configDir?: string;
|
|
52
|
-
dataDir?: string;
|
|
53
|
-
}
|
|
54
|
-
interface RemoveProviderResult {
|
|
55
|
-
ok: boolean;
|
|
56
|
-
message: string;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Remove a single provider from OpenCode's auth.json.
|
|
60
|
-
*
|
|
61
|
-
* Unlike removeCredentials which deletes the entire auth.json,
|
|
62
|
-
* this function removes only the specified provider while preserving others.
|
|
63
|
-
*
|
|
64
|
-
* @param options - Options including the provider to remove
|
|
65
|
-
* @returns Operation result with success/failure message
|
|
66
|
-
*/
|
|
67
|
-
declare function removeProviderCredentials(options: RemoveProviderOptions): RemoveProviderResult;
|
|
68
|
-
export { AGENT_ID, CREDS_FILE_NAME, extractProviderCredentials, getDefaultAuthFilePath, readAuthFile, removeProviderCredentials, splitToPerProviderCredentials, };
|
|
55
|
+
export { AGENT_ID, CREDS_FILE_NAME, getAllStoredCredentials, getDefaultAuthFilePath, getStoredCredentialsForProvider, mapToCredentialType, readAuthFile, };
|
|
56
|
+
export { removeProviderCredentials } from "./opencode-remove-provider.js";
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenCode per-provider credential handling.
|
|
3
3
|
*
|
|
4
|
-
* Handles
|
|
5
|
-
* from OpenCode's
|
|
4
|
+
* Handles extracting and removing individual provider credentials
|
|
5
|
+
* from OpenCode's auth.json file.
|
|
6
6
|
*/
|
|
7
|
-
import { readFileSync
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { resolveAgentDataDirectory } from "axshared";
|
|
10
|
-
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
11
10
|
import { OpenCodeAuth } from "./opencode-schema.js";
|
|
12
11
|
const AGENT_ID = "opencode";
|
|
13
12
|
const CREDS_FILE_NAME = "auth.json";
|
|
@@ -33,61 +32,62 @@ function mapToCredentialType(entry) {
|
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
}
|
|
35
|
+
/** Build auth file path from options */
|
|
36
|
+
function resolveAuthPath(options) {
|
|
37
|
+
return options?.dataDir
|
|
38
|
+
? path.join(options.dataDir, CREDS_FILE_NAME)
|
|
39
|
+
: getDefaultAuthFilePath();
|
|
40
|
+
}
|
|
41
|
+
/** Build credentials object from provider entry */
|
|
42
|
+
function buildCredentials(provider, entry) {
|
|
43
|
+
const parsed = OpenCodeAuth.safeParse(entry);
|
|
44
|
+
if (!parsed.success)
|
|
45
|
+
return undefined;
|
|
46
|
+
return {
|
|
47
|
+
agent: AGENT_ID,
|
|
48
|
+
provider,
|
|
49
|
+
type: mapToCredentialType(parsed.data),
|
|
50
|
+
data: entry,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
36
53
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Takes a bundled credential (all providers in `data`) and returns an array
|
|
40
|
-
* of individual credentials, one per provider, with correct credential types.
|
|
54
|
+
* Get all stored credentials as per-provider entries.
|
|
41
55
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* // Output: [
|
|
45
|
-
* // { agent: "opencode", provider: "anthropic", type: "oauth-credentials", data: {...} },
|
|
46
|
-
* // { agent: "opencode", provider: "cerebras", type: "api-key", data: {...} }
|
|
47
|
-
* // ]
|
|
56
|
+
* Reads auth.json from disk and returns an array of per-provider credentials.
|
|
57
|
+
* Used by CLI commands that need to export or list all providers.
|
|
48
58
|
*/
|
|
49
|
-
function
|
|
59
|
+
function getAllStoredCredentials(options) {
|
|
60
|
+
const authResult = readAuthFile(resolveAuthPath(options));
|
|
61
|
+
if (!authResult.ok || !authResult.data)
|
|
62
|
+
return [];
|
|
50
63
|
const result = [];
|
|
51
|
-
for (const [provider, entry] of Object.entries(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (normalizedProvider.length === 0)
|
|
55
|
-
continue;
|
|
56
|
-
const parsed = OpenCodeAuth.safeParse(entry);
|
|
57
|
-
if (!parsed.success)
|
|
64
|
+
for (const [provider, entry] of Object.entries(authResult.data)) {
|
|
65
|
+
const normalized = provider.trim();
|
|
66
|
+
if (normalized.length === 0)
|
|
58
67
|
continue;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
type: mapToCredentialType(parsed.data),
|
|
63
|
-
data: entry,
|
|
64
|
-
});
|
|
68
|
+
const creds = buildCredentials(normalized, entry);
|
|
69
|
+
if (creds)
|
|
70
|
+
result.push(creds);
|
|
65
71
|
}
|
|
66
72
|
return result;
|
|
67
73
|
}
|
|
68
74
|
/**
|
|
69
|
-
*
|
|
75
|
+
* Get stored credentials for a specific provider.
|
|
70
76
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* @returns Per-provider credential or undefined if provider not found
|
|
77
|
+
* Reads auth.json from disk and returns credentials for the specified provider.
|
|
78
|
+
* Used by CLI commands that need a specific provider's credentials.
|
|
74
79
|
*/
|
|
75
|
-
function
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
80
|
+
function getStoredCredentialsForProvider(provider, options) {
|
|
81
|
+
const normalized = provider.trim();
|
|
82
|
+
if (normalized.length === 0)
|
|
78
83
|
return undefined;
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
84
|
+
const authResult = readAuthFile(resolveAuthPath(options));
|
|
85
|
+
if (!authResult.ok || !authResult.data)
|
|
81
86
|
return undefined;
|
|
82
|
-
const
|
|
83
|
-
if (!
|
|
87
|
+
const entry = authResult.data[normalized];
|
|
88
|
+
if (!entry)
|
|
84
89
|
return undefined;
|
|
85
|
-
return
|
|
86
|
-
agent: AGENT_ID,
|
|
87
|
-
provider: normalizedProvider,
|
|
88
|
-
type: mapToCredentialType(parsed.data),
|
|
89
|
-
data: entry,
|
|
90
|
-
};
|
|
90
|
+
return buildCredentials(normalized, entry);
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Read and parse the auth file.
|
|
@@ -123,80 +123,6 @@ function readAuthFile(authFile) {
|
|
|
123
123
|
return { ok: false, error: `Failed to parse auth file: ${message}` };
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* Unlike removeCredentials which deletes the entire auth.json,
|
|
130
|
-
* this function removes only the specified provider while preserving others.
|
|
131
|
-
*
|
|
132
|
-
* @param options - Options including the provider to remove
|
|
133
|
-
* @returns Operation result with success/failure message
|
|
134
|
-
*/
|
|
135
|
-
function removeProviderCredentials(options) {
|
|
136
|
-
// Normalize and validate provider name
|
|
137
|
-
const provider = options.provider.trim();
|
|
138
|
-
if (provider.length === 0) {
|
|
139
|
-
return { ok: false, message: "Provider name cannot be empty" };
|
|
140
|
-
}
|
|
141
|
-
const resolved = resolveCustomDirectory(AGENT_ID, options.configDir, options.dataDir);
|
|
142
|
-
if (!resolved.ok)
|
|
143
|
-
return resolved.error;
|
|
144
|
-
const targetPath = resolved.customDir
|
|
145
|
-
? path.join(resolved.customDir, CREDS_FILE_NAME)
|
|
146
|
-
: getDefaultAuthFilePath();
|
|
147
|
-
const authResult = readAuthFile(targetPath);
|
|
148
|
-
if (!authResult.ok) {
|
|
149
|
-
return { ok: false, message: authResult.error };
|
|
150
|
-
}
|
|
151
|
-
if (!authResult.data) {
|
|
152
|
-
return { ok: true, message: "No credentials file found" };
|
|
153
|
-
}
|
|
154
|
-
if (!Object.hasOwn(authResult.data, provider)) {
|
|
155
|
-
return {
|
|
156
|
-
ok: true,
|
|
157
|
-
message: `No credentials found for provider '${provider}'`,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
// Remove the provider by filtering entries
|
|
161
|
-
const remaining = Object.fromEntries(Object.entries(authResult.data).filter(([key]) => key !== provider));
|
|
162
|
-
try {
|
|
163
|
-
if (Object.keys(remaining).length === 0) {
|
|
164
|
-
// No providers left, delete the file
|
|
165
|
-
unlinkSync(targetPath);
|
|
166
|
-
return {
|
|
167
|
-
ok: true,
|
|
168
|
-
message: `Removed provider '${provider}' (file deleted, no remaining providers)`,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
// Write back without the removed provider
|
|
172
|
-
const temporaryFile = `${targetPath}.tmp.${Date.now()}`;
|
|
173
|
-
try {
|
|
174
|
-
writeFileSync(temporaryFile, JSON.stringify(remaining, undefined, 2), {
|
|
175
|
-
mode: 0o600,
|
|
176
|
-
});
|
|
177
|
-
renameSync(temporaryFile, targetPath);
|
|
178
|
-
}
|
|
179
|
-
catch (error) {
|
|
180
|
-
// Clean up temp file on failure
|
|
181
|
-
try {
|
|
182
|
-
unlinkSync(temporaryFile);
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
// Ignore cleanup errors
|
|
186
|
-
}
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
ok: true,
|
|
191
|
-
message: `Removed provider '${provider}' from ${targetPath}`,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
catch (error) {
|
|
195
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
196
|
-
return {
|
|
197
|
-
ok: false,
|
|
198
|
-
message: `Failed to remove provider credentials: ${message}`,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
export { AGENT_ID, CREDS_FILE_NAME, extractProviderCredentials, getDefaultAuthFilePath, readAuthFile, removeProviderCredentials, splitToPerProviderCredentials, };
|
|
126
|
+
export { AGENT_ID, CREDS_FILE_NAME, getAllStoredCredentials, getDefaultAuthFilePath, getStoredCredentialsForProvider, mapToCredentialType, readAuthFile, };
|
|
127
|
+
// Re-export from extracted module
|
|
128
|
+
export { removeProviderCredentials } from "./opencode-remove-provider.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode provider removal.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from opencode-credentials.ts for complexity reduction.
|
|
5
|
+
*/
|
|
6
|
+
interface RemoveProviderOptions {
|
|
7
|
+
provider: string;
|
|
8
|
+
configDir?: string;
|
|
9
|
+
dataDir?: string;
|
|
10
|
+
}
|
|
11
|
+
interface RemoveProviderResult {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Remove a single provider from OpenCode's auth.json.
|
|
17
|
+
*
|
|
18
|
+
* Unlike removeCredentials which deletes the entire auth.json,
|
|
19
|
+
* this function removes only the specified provider while preserving others.
|
|
20
|
+
*
|
|
21
|
+
* @param options - Options including the provider to remove
|
|
22
|
+
* @returns Operation result with success/failure message
|
|
23
|
+
*/
|
|
24
|
+
declare function removeProviderCredentials(options: RemoveProviderOptions): RemoveProviderResult;
|
|
25
|
+
export { removeProviderCredentials };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode provider removal.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from opencode-credentials.ts for complexity reduction.
|
|
5
|
+
*/
|
|
6
|
+
import { renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
9
|
+
import { AGENT_ID, CREDS_FILE_NAME, getDefaultAuthFilePath, readAuthFile, } from "./opencode-credentials.js";
|
|
10
|
+
/**
|
|
11
|
+
* Remove a single provider from OpenCode's auth.json.
|
|
12
|
+
*
|
|
13
|
+
* Unlike removeCredentials which deletes the entire auth.json,
|
|
14
|
+
* this function removes only the specified provider while preserving others.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Options including the provider to remove
|
|
17
|
+
* @returns Operation result with success/failure message
|
|
18
|
+
*/
|
|
19
|
+
function removeProviderCredentials(options) {
|
|
20
|
+
// Normalize and validate provider name
|
|
21
|
+
const provider = options.provider.trim();
|
|
22
|
+
if (provider.length === 0) {
|
|
23
|
+
return { ok: false, message: "Provider name cannot be empty" };
|
|
24
|
+
}
|
|
25
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options.configDir, options.dataDir);
|
|
26
|
+
if (!resolved.ok)
|
|
27
|
+
return resolved.error;
|
|
28
|
+
const targetPath = resolved.customDir
|
|
29
|
+
? path.join(resolved.customDir, CREDS_FILE_NAME)
|
|
30
|
+
: getDefaultAuthFilePath();
|
|
31
|
+
const authResult = readAuthFile(targetPath);
|
|
32
|
+
if (!authResult.ok) {
|
|
33
|
+
return { ok: false, message: authResult.error };
|
|
34
|
+
}
|
|
35
|
+
if (!authResult.data) {
|
|
36
|
+
return { ok: true, message: "No credentials file found" };
|
|
37
|
+
}
|
|
38
|
+
if (!Object.hasOwn(authResult.data, provider)) {
|
|
39
|
+
return {
|
|
40
|
+
ok: true,
|
|
41
|
+
message: `No credentials found for provider '${provider}'`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Remove the provider by filtering entries
|
|
45
|
+
const remaining = Object.fromEntries(Object.entries(authResult.data).filter(([key]) => key !== provider));
|
|
46
|
+
try {
|
|
47
|
+
if (Object.keys(remaining).length === 0) {
|
|
48
|
+
// No providers left, delete the file
|
|
49
|
+
unlinkSync(targetPath);
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
message: `Removed provider '${provider}' (file deleted, no remaining providers)`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Write back without the removed provider
|
|
56
|
+
const temporaryFile = `${targetPath}.tmp.${Date.now()}`;
|
|
57
|
+
try {
|
|
58
|
+
writeFileSync(temporaryFile, JSON.stringify(remaining, undefined, 2), {
|
|
59
|
+
mode: 0o600,
|
|
60
|
+
});
|
|
61
|
+
renameSync(temporaryFile, targetPath);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// Clean up temp file on failure
|
|
65
|
+
try {
|
|
66
|
+
unlinkSync(temporaryFile);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Ignore cleanup errors
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
message: `Removed provider '${provider}' from ${targetPath}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
message: `Failed to remove provider credentials: ${message}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export { removeProviderCredentials };
|
|
@@ -21,29 +21,25 @@ function installCredentials(creds, options) {
|
|
|
21
21
|
if (!existsSync(targetDirectory)) {
|
|
22
22
|
mkdirSync(targetDirectory, { recursive: true, mode: 0o700 });
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
// Per-provider credential: merge into existing auth.json at provider's slot
|
|
36
|
-
const authResult = readAuthFile(targetPath);
|
|
37
|
-
if (!authResult.ok) {
|
|
38
|
-
return { ok: false, message: authResult.error };
|
|
39
|
-
}
|
|
40
|
-
const existingAuth = authResult.data ?? {};
|
|
41
|
-
authData = { ...existingAuth, [provider]: cleanData };
|
|
24
|
+
// OpenCode requires per-provider credentials
|
|
25
|
+
if (creds.agent !== "opencode" || !creds.provider) {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
message: "Bundled credential format is no longer supported for OpenCode; please provide per-provider credentials.",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Validate provider key is non-empty (defensive check for programmatic use)
|
|
32
|
+
const provider = creds.provider.trim();
|
|
33
|
+
if (provider.length === 0) {
|
|
34
|
+
return { ok: false, message: "Provider name cannot be empty" };
|
|
42
35
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
// Per-provider credential: merge into existing auth.json at provider's slot
|
|
37
|
+
const authResult = readAuthFile(targetPath);
|
|
38
|
+
if (!authResult.ok) {
|
|
39
|
+
return { ok: false, message: authResult.error };
|
|
46
40
|
}
|
|
41
|
+
const existingAuth = authResult.data ?? {};
|
|
42
|
+
const authData = { ...existingAuth, [provider]: creds.data };
|
|
47
43
|
// OpenCode stores auth data directly as the file content
|
|
48
44
|
const temporaryFile = `${targetPath}.tmp.${Date.now()}`;
|
|
49
45
|
try {
|
|
@@ -62,7 +58,7 @@ function installCredentials(creds, options) {
|
|
|
62
58
|
}
|
|
63
59
|
throw error;
|
|
64
60
|
}
|
|
65
|
-
const providerInfo =
|
|
61
|
+
const providerInfo = ` (${provider})`;
|
|
66
62
|
return {
|
|
67
63
|
ok: true,
|
|
68
64
|
message: `Installed credentials${providerInfo} to ${targetPath}`,
|