axauth 1.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/LICENSE +21 -0
- package/README.md +147 -0
- package/bin/axauth +17 -0
- package/dist/auth/adapter.d.ts +121 -0
- package/dist/auth/adapter.js +7 -0
- package/dist/auth/agents/claude-code-storage.d.ts +18 -0
- package/dist/auth/agents/claude-code-storage.js +66 -0
- package/dist/auth/agents/claude-code.d.ts +9 -0
- package/dist/auth/agents/claude-code.js +162 -0
- package/dist/auth/agents/codex-auth-check.d.ts +9 -0
- package/dist/auth/agents/codex-auth-check.js +101 -0
- package/dist/auth/agents/codex-config.d.ts +12 -0
- package/dist/auth/agents/codex-config.js +40 -0
- package/dist/auth/agents/codex-storage.d.ts +43 -0
- package/dist/auth/agents/codex-storage.js +82 -0
- package/dist/auth/agents/codex.d.ts +9 -0
- package/dist/auth/agents/codex.js +126 -0
- package/dist/auth/agents/copilot-auth-check.d.ts +17 -0
- package/dist/auth/agents/copilot-auth-check.js +46 -0
- package/dist/auth/agents/copilot-storage.d.ts +32 -0
- package/dist/auth/agents/copilot-storage.js +139 -0
- package/dist/auth/agents/copilot.d.ts +10 -0
- package/dist/auth/agents/copilot.js +144 -0
- package/dist/auth/agents/gemini-auth-check.d.ts +16 -0
- package/dist/auth/agents/gemini-auth-check.js +73 -0
- package/dist/auth/agents/gemini-storage.d.ts +24 -0
- package/dist/auth/agents/gemini-storage.js +69 -0
- package/dist/auth/agents/gemini.d.ts +9 -0
- package/dist/auth/agents/gemini.js +157 -0
- package/dist/auth/agents/opencode.d.ts +9 -0
- package/dist/auth/agents/opencode.js +128 -0
- package/dist/auth/file-storage.d.ts +14 -0
- package/dist/auth/file-storage.js +63 -0
- package/dist/auth/keychain.d.ts +12 -0
- package/dist/auth/keychain.js +56 -0
- package/dist/auth/registry.d.ts +109 -0
- package/dist/auth/registry.js +145 -0
- package/dist/auth/resolve-config-directory.d.ts +14 -0
- package/dist/auth/resolve-config-directory.js +16 -0
- package/dist/auth/types.d.ts +19 -0
- package/dist/auth/types.js +4 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +74 -0
- package/dist/commands/auth.d.ts +34 -0
- package/dist/commands/auth.js +155 -0
- package/dist/crypto.d.ts +39 -0
- package/dist/crypto.js +78 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +39 -0
- package/package.json +96 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based credential storage utilities.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
/** Load JSON data from a file and cast to expected type */
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
8
|
+
function loadJsonFile(filePath) {
|
|
9
|
+
if (!existsSync(filePath)) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const data = JSON.parse(readFileSync(filePath, "utf8"));
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Save JSON data to a file atomically */
|
|
21
|
+
function saveJsonFile(filePath, data, options) {
|
|
22
|
+
try {
|
|
23
|
+
const directory = path.dirname(filePath);
|
|
24
|
+
if (!existsSync(directory)) {
|
|
25
|
+
mkdirSync(directory, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
const temporaryFile = `${filePath}.tmp.${Date.now()}`;
|
|
28
|
+
writeFileSync(temporaryFile, JSON.stringify(data, undefined, 2), {
|
|
29
|
+
mode: options?.mode ?? 0o600,
|
|
30
|
+
});
|
|
31
|
+
renameSync(temporaryFile, filePath);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Delete a file if it exists */
|
|
39
|
+
function deleteFile(filePath) {
|
|
40
|
+
if (!existsSync(filePath)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
unlinkSync(filePath);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Ensure a directory exists */
|
|
52
|
+
function ensureDirectory(directoryPath) {
|
|
53
|
+
try {
|
|
54
|
+
if (!existsSync(directoryPath)) {
|
|
55
|
+
mkdirSync(directoryPath, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export { deleteFile, ensureDirectory, loadJsonFile, saveJsonFile };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS Keychain utilities for credential storage.
|
|
3
|
+
*/
|
|
4
|
+
/** Check if running on macOS */
|
|
5
|
+
declare function isMacOS(): boolean;
|
|
6
|
+
/** Load data from macOS Keychain */
|
|
7
|
+
declare function loadFromKeychain(service: string, account: string): string | undefined;
|
|
8
|
+
/** Save data to macOS Keychain */
|
|
9
|
+
declare function saveToKeychain(service: string, account: string, data: string): boolean;
|
|
10
|
+
/** Delete entry from macOS Keychain */
|
|
11
|
+
declare function deleteFromKeychain(service: string, account: string): boolean;
|
|
12
|
+
export { deleteFromKeychain, isMacOS, loadFromKeychain, saveToKeychain };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS Keychain utilities for credential storage.
|
|
3
|
+
*/
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
/** Check if running on macOS */
|
|
6
|
+
function isMacOS() {
|
|
7
|
+
return process.platform === "darwin";
|
|
8
|
+
}
|
|
9
|
+
/** Load data from macOS Keychain */
|
|
10
|
+
function loadFromKeychain(service, account) {
|
|
11
|
+
if (!isMacOS()) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const result = execFileSync("security", ["find-generic-password", "-a", account, "-s", service, "-w"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
16
|
+
return result.trim();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Save data to macOS Keychain */
|
|
23
|
+
function saveToKeychain(service, account, data) {
|
|
24
|
+
if (!isMacOS()) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
// First try to delete existing entry (ignore errors)
|
|
29
|
+
try {
|
|
30
|
+
execFileSync("security", ["delete-generic-password", "-a", account, "-s", service], { stdio: ["pipe", "pipe", "pipe"] });
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Ignore - might not exist
|
|
34
|
+
}
|
|
35
|
+
// Add new entry
|
|
36
|
+
execFileSync("security", ["add-generic-password", "-a", account, "-s", service, "-w", data], { stdio: ["pipe", "pipe", "pipe"] });
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Delete entry from macOS Keychain */
|
|
44
|
+
function deleteFromKeychain(service, account) {
|
|
45
|
+
if (!isMacOS()) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
execFileSync("security", ["delete-generic-password", "-a", account, "-s", service], { stdio: ["pipe", "pipe", "pipe"] });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export { deleteFromKeychain, isMacOS, loadFromKeychain, saveToKeychain };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter registry - unified entry point for auth operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides a single API for all agent authentication operations,
|
|
5
|
+
* delegating to the appropriate adapter based on agent ID.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentCli } from "axshared";
|
|
8
|
+
import type { AdapterCapabilities, AuthAdapter, InstallOptions, OperationResult, RemoveOptions } from "./adapter.js";
|
|
9
|
+
import type { AuthStatus, Credentials } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Get the adapter for an agent.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const adapter = getAdapter("claude");
|
|
15
|
+
* const status = adapter.checkAuth();
|
|
16
|
+
*/
|
|
17
|
+
declare function getAdapter(agentId: AgentCli): AuthAdapter;
|
|
18
|
+
/**
|
|
19
|
+
* Get all adapters.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const adapters = getAllAdapters();
|
|
23
|
+
* const statuses = adapters.map(a => a.checkAuth());
|
|
24
|
+
*/
|
|
25
|
+
declare function getAllAdapters(): AuthAdapter[];
|
|
26
|
+
/**
|
|
27
|
+
* Get adapter capabilities for an agent.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const caps = getCapabilities("gemini");
|
|
31
|
+
* if (caps.keychain) { ... }
|
|
32
|
+
*/
|
|
33
|
+
declare function getCapabilities(agentId: AgentCli): AdapterCapabilities;
|
|
34
|
+
/**
|
|
35
|
+
* Check auth status for an agent.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* const status = checkAuth("claude");
|
|
39
|
+
* if (status.authenticated) { ... }
|
|
40
|
+
*/
|
|
41
|
+
declare function checkAuth(agentId: AgentCli): AuthStatus;
|
|
42
|
+
/**
|
|
43
|
+
* Check auth status for all agents.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const statuses = checkAllAuth();
|
|
47
|
+
* const authenticated = statuses.filter(s => s.authenticated);
|
|
48
|
+
*/
|
|
49
|
+
declare function checkAllAuth(): AuthStatus[];
|
|
50
|
+
/**
|
|
51
|
+
* Extract raw credentials for an agent.
|
|
52
|
+
*
|
|
53
|
+
* Note: The `data` field format is agent-specific and not standardized.
|
|
54
|
+
* Use {@link getAccessToken} to extract the token in a uniform way.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const creds = extractRawCredentials("codex");
|
|
58
|
+
* if (creds) { await exportCredentials(creds); }
|
|
59
|
+
*/
|
|
60
|
+
declare function extractRawCredentials(agentId: AgentCli): Credentials | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Install credentials for an agent.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const result = installCredentials(creds, { storage: "keychain" });
|
|
66
|
+
* if (!result.ok) { console.error(result.message); }
|
|
67
|
+
*/
|
|
68
|
+
declare function installCredentials(creds: Credentials, options?: InstallOptions): OperationResult;
|
|
69
|
+
/**
|
|
70
|
+
* Remove credentials for an agent.
|
|
71
|
+
*
|
|
72
|
+
* When `options.path` is provided, only the file at that path is removed.
|
|
73
|
+
* Keychain credentials are not affected (keychain is only for default location).
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Remove from default location (keychain + default file)
|
|
77
|
+
* const result = removeCredentials("gemini");
|
|
78
|
+
*
|
|
79
|
+
* // Remove from custom path only (no keychain)
|
|
80
|
+
* const result = removeCredentials("gemini", { path: "/path/to/creds.json" });
|
|
81
|
+
*/
|
|
82
|
+
declare function removeCredentials(agentId: AgentCli, options?: RemoveOptions): OperationResult;
|
|
83
|
+
/**
|
|
84
|
+
* Get access token from credentials.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* const token = getAccessToken(creds);
|
|
88
|
+
* if (token) { headers.Authorization = `Bearer ${token}`; }
|
|
89
|
+
*/
|
|
90
|
+
declare function getAccessToken(creds: Credentials): string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Get access token for an agent (convenience function).
|
|
93
|
+
*
|
|
94
|
+
* Extracts credentials and returns the access token in one call.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* const token = getAgentAccessToken("claude");
|
|
98
|
+
* if (token) { ... }
|
|
99
|
+
*/
|
|
100
|
+
declare function getAgentAccessToken(agentId: AgentCli): string | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Convert credentials to environment variables.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const env = credentialsToEnvironment(creds);
|
|
106
|
+
* Object.assign(process.env, env);
|
|
107
|
+
*/
|
|
108
|
+
declare function credentialsToEnvironment(creds: Credentials): Record<string, string>;
|
|
109
|
+
export { checkAllAuth, checkAuth, credentialsToEnvironment, extractRawCredentials, getAccessToken, getAdapter, getAgentAccessToken, getAllAdapters, getCapabilities, installCredentials, removeCredentials, };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter registry - unified entry point for auth operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides a single API for all agent authentication operations,
|
|
5
|
+
* delegating to the appropriate adapter based on agent ID.
|
|
6
|
+
*/
|
|
7
|
+
import { claudeCodeAdapter } from "./agents/claude-code.js";
|
|
8
|
+
import { codexAdapter } from "./agents/codex.js";
|
|
9
|
+
import { copilotAdapter } from "./agents/copilot.js";
|
|
10
|
+
import { geminiAdapter } from "./agents/gemini.js";
|
|
11
|
+
import { opencodeAdapter } from "./agents/opencode.js";
|
|
12
|
+
/** Registry of all adapters by agent ID */
|
|
13
|
+
const ADAPTERS = {
|
|
14
|
+
claude: claudeCodeAdapter,
|
|
15
|
+
codex: codexAdapter,
|
|
16
|
+
copilot: copilotAdapter,
|
|
17
|
+
gemini: geminiAdapter,
|
|
18
|
+
opencode: opencodeAdapter,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Get the adapter for an agent.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const adapter = getAdapter("claude");
|
|
25
|
+
* const status = adapter.checkAuth();
|
|
26
|
+
*/
|
|
27
|
+
function getAdapter(agentId) {
|
|
28
|
+
return ADAPTERS[agentId];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get all adapters.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const adapters = getAllAdapters();
|
|
35
|
+
* const statuses = adapters.map(a => a.checkAuth());
|
|
36
|
+
*/
|
|
37
|
+
function getAllAdapters() {
|
|
38
|
+
return Object.values(ADAPTERS);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get adapter capabilities for an agent.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const caps = getCapabilities("gemini");
|
|
45
|
+
* if (caps.keychain) { ... }
|
|
46
|
+
*/
|
|
47
|
+
function getCapabilities(agentId) {
|
|
48
|
+
return ADAPTERS[agentId].capabilities;
|
|
49
|
+
}
|
|
50
|
+
// Unified operations that delegate to the appropriate adapter
|
|
51
|
+
/**
|
|
52
|
+
* Check auth status for an agent.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const status = checkAuth("claude");
|
|
56
|
+
* if (status.authenticated) { ... }
|
|
57
|
+
*/
|
|
58
|
+
function checkAuth(agentId) {
|
|
59
|
+
return ADAPTERS[agentId].checkAuth();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check auth status for all agents.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const statuses = checkAllAuth();
|
|
66
|
+
* const authenticated = statuses.filter(s => s.authenticated);
|
|
67
|
+
*/
|
|
68
|
+
function checkAllAuth() {
|
|
69
|
+
return getAllAdapters().map((adapter) => adapter.checkAuth());
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract raw credentials for an agent.
|
|
73
|
+
*
|
|
74
|
+
* Note: The `data` field format is agent-specific and not standardized.
|
|
75
|
+
* Use {@link getAccessToken} to extract the token in a uniform way.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const creds = extractRawCredentials("codex");
|
|
79
|
+
* if (creds) { await exportCredentials(creds); }
|
|
80
|
+
*/
|
|
81
|
+
function extractRawCredentials(agentId) {
|
|
82
|
+
return ADAPTERS[agentId].extractRawCredentials();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Install credentials for an agent.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* const result = installCredentials(creds, { storage: "keychain" });
|
|
89
|
+
* if (!result.ok) { console.error(result.message); }
|
|
90
|
+
*/
|
|
91
|
+
function installCredentials(creds, options) {
|
|
92
|
+
return ADAPTERS[creds.agent].installCredentials(creds, options);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Remove credentials for an agent.
|
|
96
|
+
*
|
|
97
|
+
* When `options.path` is provided, only the file at that path is removed.
|
|
98
|
+
* Keychain credentials are not affected (keychain is only for default location).
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Remove from default location (keychain + default file)
|
|
102
|
+
* const result = removeCredentials("gemini");
|
|
103
|
+
*
|
|
104
|
+
* // Remove from custom path only (no keychain)
|
|
105
|
+
* const result = removeCredentials("gemini", { path: "/path/to/creds.json" });
|
|
106
|
+
*/
|
|
107
|
+
function removeCredentials(agentId, options) {
|
|
108
|
+
return ADAPTERS[agentId].removeCredentials(options);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get access token from credentials.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const token = getAccessToken(creds);
|
|
115
|
+
* if (token) { headers.Authorization = `Bearer ${token}`; }
|
|
116
|
+
*/
|
|
117
|
+
function getAccessToken(creds) {
|
|
118
|
+
return ADAPTERS[creds.agent].getAccessToken(creds);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get access token for an agent (convenience function).
|
|
122
|
+
*
|
|
123
|
+
* Extracts credentials and returns the access token in one call.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const token = getAgentAccessToken("claude");
|
|
127
|
+
* if (token) { ... }
|
|
128
|
+
*/
|
|
129
|
+
function getAgentAccessToken(agentId) {
|
|
130
|
+
const creds = extractRawCredentials(agentId);
|
|
131
|
+
if (!creds)
|
|
132
|
+
return undefined;
|
|
133
|
+
return getAccessToken(creds);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Convert credentials to environment variables.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* const env = credentialsToEnvironment(creds);
|
|
140
|
+
* Object.assign(process.env, env);
|
|
141
|
+
*/
|
|
142
|
+
function credentialsToEnvironment(creds) {
|
|
143
|
+
return ADAPTERS[creds.agent].credentialsToEnvironment(creds);
|
|
144
|
+
}
|
|
145
|
+
export { checkAllAuth, checkAuth, credentialsToEnvironment, extractRawCredentials, getAccessToken, getAdapter, getAgentAccessToken, getAllAdapters, getCapabilities, installCredentials, removeCredentials, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to resolve config directories from axconfig readers.
|
|
3
|
+
*
|
|
4
|
+
* Checks the reader's env var override before falling back to the default.
|
|
5
|
+
*/
|
|
6
|
+
import type { ConfigReader } from "axconfig";
|
|
7
|
+
/**
|
|
8
|
+
* Get the resolved config directory for a reader.
|
|
9
|
+
*
|
|
10
|
+
* Checks the env var specified by the reader first, then falls back
|
|
11
|
+
* to the reader's default config directory.
|
|
12
|
+
*/
|
|
13
|
+
declare function getResolvedConfigDirectory(reader: ConfigReader): string;
|
|
14
|
+
export { getResolvedConfigDirectory };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to resolve config directories from axconfig readers.
|
|
3
|
+
*
|
|
4
|
+
* Checks the reader's env var override before falling back to the default.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get the resolved config directory for a reader.
|
|
8
|
+
*
|
|
9
|
+
* Checks the env var specified by the reader first, then falls back
|
|
10
|
+
* to the reader's default config directory.
|
|
11
|
+
*/
|
|
12
|
+
function getResolvedConfigDirectory(reader) {
|
|
13
|
+
const environmentValue = process.env[reader.envVar];
|
|
14
|
+
return environmentValue ?? reader.defaultConfigDir();
|
|
15
|
+
}
|
|
16
|
+
export { getResolvedConfigDirectory };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for auth module.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentCli } from "axshared";
|
|
5
|
+
/** Auth status for an agent */
|
|
6
|
+
interface AuthStatus {
|
|
7
|
+
agentId: AgentCli;
|
|
8
|
+
authenticated: boolean;
|
|
9
|
+
method?: string;
|
|
10
|
+
/** Additional details (e.g., provider list for opencode) */
|
|
11
|
+
details?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/** Extracted credential data */
|
|
14
|
+
interface Credentials {
|
|
15
|
+
agent: AgentCli;
|
|
16
|
+
type: "oauth" | "api-key";
|
|
17
|
+
data: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export type { AuthStatus, Credentials };
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* axauth - AI agent authentication CLI.
|
|
4
|
+
*
|
|
5
|
+
* Manages credentials for AI coding agents.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from "@commander-js/extra-typings";
|
|
8
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
9
|
+
import { handleAuthExport, handleAuthInstall, handleAuthList, handleAuthRemove, handleAuthToken, } from "./commands/auth.js";
|
|
10
|
+
import { AGENT_CLIS } from "axshared";
|
|
11
|
+
// Handle SIGINT gracefully
|
|
12
|
+
process.on("SIGINT", () => {
|
|
13
|
+
console.error("\nInterrupted");
|
|
14
|
+
process.exit(130); // 128 + SIGINT(2)
|
|
15
|
+
});
|
|
16
|
+
const program = new Command()
|
|
17
|
+
.name(packageJson.name)
|
|
18
|
+
.description(packageJson.description)
|
|
19
|
+
.version(packageJson.version, "-V, --version")
|
|
20
|
+
.showHelpAfterError("(add --help for additional information)")
|
|
21
|
+
.showSuggestionAfterError()
|
|
22
|
+
.helpCommand(false)
|
|
23
|
+
.addHelpText("after", String.raw `
|
|
24
|
+
Examples:
|
|
25
|
+
# List authenticated agents
|
|
26
|
+
axauth list
|
|
27
|
+
|
|
28
|
+
# Filter to show only authenticated agents
|
|
29
|
+
axauth list | tail -n +2 | awk -F'\t' '$2 == "authenticated"'
|
|
30
|
+
|
|
31
|
+
# Get access token for an agent
|
|
32
|
+
axauth token --agent claude
|
|
33
|
+
|
|
34
|
+
# Export credentials for CI/CD
|
|
35
|
+
axauth export --agent claude --output creds.json --no-password
|
|
36
|
+
|
|
37
|
+
# Remove credentials (agent will prompt for login)
|
|
38
|
+
axauth remove-credentials --agent claude
|
|
39
|
+
|
|
40
|
+
# Install credentials from exported file
|
|
41
|
+
axauth install-credentials --agent claude --input creds.json`);
|
|
42
|
+
program
|
|
43
|
+
.command("list")
|
|
44
|
+
.description("List agents and their auth status")
|
|
45
|
+
.option("--json", "Output as JSON")
|
|
46
|
+
.action(handleAuthList);
|
|
47
|
+
program
|
|
48
|
+
.command("token")
|
|
49
|
+
.description("Get access token for an agent")
|
|
50
|
+
.requiredOption("-a, --agent <agent>", `Agent to get token from (${AGENT_CLIS.join(", ")})`)
|
|
51
|
+
.action(handleAuthToken);
|
|
52
|
+
program
|
|
53
|
+
.command("export")
|
|
54
|
+
.description("Export credentials to encrypted file")
|
|
55
|
+
.requiredOption("-a, --agent <agent>", `Agent to export credentials from (${AGENT_CLIS.join(", ")})`)
|
|
56
|
+
.requiredOption("--output <file>", "Output file path")
|
|
57
|
+
.option("--no-password", "Use default password (no prompt)")
|
|
58
|
+
.action(handleAuthExport);
|
|
59
|
+
program
|
|
60
|
+
.command("remove-credentials")
|
|
61
|
+
.description("Remove credentials from storage")
|
|
62
|
+
.requiredOption("-a, --agent <agent>", `Agent to remove credentials from (${AGENT_CLIS.join(", ")})`)
|
|
63
|
+
.option("--path <file>", "Custom file path (removes only this file, not keychain)")
|
|
64
|
+
.action(handleAuthRemove);
|
|
65
|
+
program
|
|
66
|
+
.command("install-credentials")
|
|
67
|
+
.description("Install credentials from encrypted file")
|
|
68
|
+
.requiredOption("-a, --agent <agent>", `Agent to install credentials for (${AGENT_CLIS.join(", ")})`)
|
|
69
|
+
.requiredOption("--input <file>", "Encrypted credentials file path")
|
|
70
|
+
.option("--no-password", "Use default password (no prompt)")
|
|
71
|
+
.option("--path <file>", "Custom file path (forces file storage, ignores --storage)")
|
|
72
|
+
.option("--storage <type>", "Storage type: keychain (macOS only) or file (for default location)")
|
|
73
|
+
.action(handleAuthInstall);
|
|
74
|
+
await program.parseAsync(process.argv);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth commands - manage agent credentials.
|
|
3
|
+
*/
|
|
4
|
+
/** Handle auth list command */
|
|
5
|
+
declare function handleAuthList(options: {
|
|
6
|
+
json?: true;
|
|
7
|
+
}): void;
|
|
8
|
+
/** Handle auth token command */
|
|
9
|
+
declare function handleAuthToken(options: {
|
|
10
|
+
agent: string;
|
|
11
|
+
}): void;
|
|
12
|
+
interface AuthExportOptions {
|
|
13
|
+
agent: string;
|
|
14
|
+
output: string;
|
|
15
|
+
password: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Handle auth export command */
|
|
18
|
+
declare function handleAuthExport(options: AuthExportOptions): Promise<void>;
|
|
19
|
+
interface AuthRemoveOptions {
|
|
20
|
+
agent: string;
|
|
21
|
+
path?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Handle auth remove-credentials command */
|
|
24
|
+
declare function handleAuthRemove(options: AuthRemoveOptions): void;
|
|
25
|
+
interface AuthInstallOptions {
|
|
26
|
+
agent: string;
|
|
27
|
+
input: string;
|
|
28
|
+
password: boolean;
|
|
29
|
+
path?: string;
|
|
30
|
+
storage?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Handle auth install-credentials command */
|
|
33
|
+
declare function handleAuthInstall(options: AuthInstallOptions): Promise<void>;
|
|
34
|
+
export { handleAuthExport, handleAuthInstall, handleAuthList, handleAuthRemove, handleAuthToken, };
|