axauth 3.1.5 → 3.2.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/dist/auth/get-access-token-with-refresh.d.ts +12 -0
- package/dist/auth/get-access-token-with-refresh.js +47 -0
- package/dist/auth/registry.js +6 -45
- package/dist/cli.js +7 -1
- package/dist/commands/auth.js +3 -1
- package/dist/commands/vault-failure-messages.d.ts +4 -0
- package/dist/commands/vault-failure-messages.js +12 -0
- package/dist/commands/{vault.d.ts → vault-fetch.d.ts} +2 -15
- package/dist/commands/{vault.js → vault-fetch.js} +13 -77
- package/dist/commands/vault-push.d.ts +19 -0
- package/dist/commands/vault-push.js +70 -0
- package/dist/vault/vault-client.d.ts +6 -0
- package/dist/vault/vault-client.js +14 -0
- package/package.json +13 -13
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentCli } from "axshared";
|
|
2
|
+
import type { AuthAdapter, FindStoredCredentialsOptions, InstallOptions, OperationResult, TokenOptions } from "./adapter.js";
|
|
3
|
+
import type { Credentials } from "./types.js";
|
|
4
|
+
interface AccessTokenDependencies {
|
|
5
|
+
adapter: AuthAdapter;
|
|
6
|
+
installCredentials: (agentId: AgentCli, creds: Credentials, options?: InstallOptions) => OperationResult;
|
|
7
|
+
}
|
|
8
|
+
declare function findCredentialsWithEnvironmentPriority(adapter: AuthAdapter, options?: FindStoredCredentialsOptions): Credentials | undefined;
|
|
9
|
+
type AccessTokenGetter = (agentId: AgentCli, creds: Credentials, options?: TokenOptions) => Promise<string | undefined>;
|
|
10
|
+
declare function getAgentAccessTokenFromStoredCredentials(agentId: AgentCli, adapter: AuthAdapter, options: TokenOptions | undefined, getAccessToken: AccessTokenGetter): Promise<string | undefined>;
|
|
11
|
+
declare function getAccessTokenWithRefresh(agentId: AgentCli, creds: Credentials, options: TokenOptions | undefined, dependencies: AccessTokenDependencies): Promise<string | undefined>;
|
|
12
|
+
export { findCredentialsWithEnvironmentPriority, getAccessTokenWithRefresh, getAgentAccessTokenFromStoredCredentials, };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isCredentialExpired, isTokenExpired } from "./is-token-expired.js";
|
|
2
|
+
import { refreshAndPersist } from "./refresh-credentials.js";
|
|
3
|
+
function findCredentialsWithEnvironmentPriority(adapter, options) {
|
|
4
|
+
const environmentCredentials = adapter.getEnvironmentCredentials?.();
|
|
5
|
+
if (environmentCredentials)
|
|
6
|
+
return environmentCredentials;
|
|
7
|
+
const stored = adapter.findStoredCredentials(options);
|
|
8
|
+
return stored?.credentials;
|
|
9
|
+
}
|
|
10
|
+
function shouldRefreshToken(token, creds, options) {
|
|
11
|
+
if (creds.type === "api-key")
|
|
12
|
+
return false;
|
|
13
|
+
if (options?.skipRefresh)
|
|
14
|
+
return false;
|
|
15
|
+
let expired = isTokenExpired(token);
|
|
16
|
+
if (expired === undefined) {
|
|
17
|
+
expired = isCredentialExpired(creds.data);
|
|
18
|
+
}
|
|
19
|
+
return expired === true;
|
|
20
|
+
}
|
|
21
|
+
async function getAgentAccessTokenFromStoredCredentials(agentId, adapter, options, getAccessToken) {
|
|
22
|
+
const stored = adapter.findStoredCredentials({
|
|
23
|
+
provider: options?.provider,
|
|
24
|
+
});
|
|
25
|
+
if (!stored)
|
|
26
|
+
return undefined;
|
|
27
|
+
return getAccessToken(agentId, stored.credentials, {
|
|
28
|
+
...options,
|
|
29
|
+
storage: options?.storage ?? stored.source,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function getAccessTokenWithRefresh(agentId, creds, options, dependencies) {
|
|
33
|
+
const token = dependencies.adapter.getAccessToken(creds, options);
|
|
34
|
+
if (!token)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (!shouldRefreshToken(token, creds, options)) {
|
|
37
|
+
return token;
|
|
38
|
+
}
|
|
39
|
+
const result = await refreshAndPersist(agentId, creds, (resolvedAgentId, refreshedCreds, installOptions) => dependencies.installCredentials(resolvedAgentId, refreshedCreds, installOptions), {
|
|
40
|
+
timeout: options?.refreshTimeout,
|
|
41
|
+
provider: options?.provider,
|
|
42
|
+
storage: options?.storage,
|
|
43
|
+
});
|
|
44
|
+
const finalCreds = result.ok ? result.credentials : result.staleCredentials;
|
|
45
|
+
return dependencies.adapter.getAccessToken(finalCreds, options);
|
|
46
|
+
}
|
|
47
|
+
export { findCredentialsWithEnvironmentPriority, getAccessTokenWithRefresh, getAgentAccessTokenFromStoredCredentials, };
|
package/dist/auth/registry.js
CHANGED
|
@@ -9,9 +9,8 @@ import { codexAdapter } from "./agents/codex.js";
|
|
|
9
9
|
import { copilotAdapter } from "./agents/copilot.js";
|
|
10
10
|
import { geminiAdapter } from "./agents/gemini.js";
|
|
11
11
|
import { opencodeAdapter } from "./agents/opencode.js";
|
|
12
|
+
import { findCredentialsWithEnvironmentPriority, getAccessTokenWithRefresh, getAgentAccessTokenFromStoredCredentials, } from "./get-access-token-with-refresh.js";
|
|
12
13
|
import { installCredentialsFromEnvironmentCore } from "./install-from-environment.js";
|
|
13
|
-
import { isCredentialExpired, isTokenExpired } from "./is-token-expired.js";
|
|
14
|
-
import { refreshAndPersist } from "./refresh-credentials.js";
|
|
15
14
|
/** Registry of all adapters by agent ID */
|
|
16
15
|
const ADAPTERS = {
|
|
17
16
|
claude: claudeCodeAdapter,
|
|
@@ -92,14 +91,7 @@ function checkAllAuth() {
|
|
|
92
91
|
* const creds = findCredentials("opencode", { provider: "anthropic" });
|
|
93
92
|
*/
|
|
94
93
|
function findCredentials(agentId, options) {
|
|
95
|
-
|
|
96
|
-
// Check environment credentials first (allows easy overrides in CI/CD)
|
|
97
|
-
const environmentCredentials = adapter.getEnvironmentCredentials?.();
|
|
98
|
-
if (environmentCredentials)
|
|
99
|
-
return environmentCredentials;
|
|
100
|
-
// Fall back to stored credentials (keychain/file)
|
|
101
|
-
const stored = adapter.findStoredCredentials(options);
|
|
102
|
-
return stored?.credentials;
|
|
94
|
+
return findCredentialsWithEnvironmentPriority(ADAPTERS[agentId], options);
|
|
103
95
|
}
|
|
104
96
|
/**
|
|
105
97
|
* Extract raw credentials from custom directories.
|
|
@@ -158,32 +150,10 @@ function removeCredentials(agentId, options) {
|
|
|
158
150
|
* const token = await getAccessToken(creds, { skipRefresh: true });
|
|
159
151
|
*/
|
|
160
152
|
async function getAccessToken(agentId, creds, options) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return undefined;
|
|
165
|
-
// API keys don't expire
|
|
166
|
-
if (creds.type === "api-key")
|
|
167
|
-
return token;
|
|
168
|
-
// Skip refresh if requested
|
|
169
|
-
if (options?.skipRefresh)
|
|
170
|
-
return token;
|
|
171
|
-
// Check if token is expired (try JWT first, then credential fields)
|
|
172
|
-
let expired = isTokenExpired(token);
|
|
173
|
-
if (expired === undefined) {
|
|
174
|
-
// Token isn't a JWT - check credential's explicit expiry fields
|
|
175
|
-
expired = isCredentialExpired(creds.data);
|
|
176
|
-
}
|
|
177
|
-
if (expired !== true)
|
|
178
|
-
return token; // Valid or no expiry info
|
|
179
|
-
// Refresh and persist
|
|
180
|
-
const result = await refreshAndPersist(agentId, creds, (aid, c, installOptions) => installCredentials(aid, c, installOptions), {
|
|
181
|
-
timeout: options?.refreshTimeout,
|
|
182
|
-
provider: options?.provider,
|
|
183
|
-
storage: options?.storage,
|
|
153
|
+
return getAccessTokenWithRefresh(agentId, creds, options, {
|
|
154
|
+
adapter: ADAPTERS[agentId],
|
|
155
|
+
installCredentials,
|
|
184
156
|
});
|
|
185
|
-
const finalCreds = result.ok ? result.credentials : result.staleCredentials;
|
|
186
|
-
return ADAPTERS[agentId].getAccessToken(finalCreds, options);
|
|
187
157
|
}
|
|
188
158
|
/**
|
|
189
159
|
* Get access token for an agent by ID.
|
|
@@ -196,16 +166,7 @@ async function getAccessToken(agentId, creds, options) {
|
|
|
196
166
|
* const token = await getAgentAccessToken("claude");
|
|
197
167
|
*/
|
|
198
168
|
async function getAgentAccessToken(agentId, options) {
|
|
199
|
-
|
|
200
|
-
provider: options?.provider,
|
|
201
|
-
});
|
|
202
|
-
if (!stored)
|
|
203
|
-
return undefined;
|
|
204
|
-
// Pass the source to getAccessToken so refresh preserves storage location
|
|
205
|
-
return getAccessToken(agentId, stored.credentials, {
|
|
206
|
-
...options,
|
|
207
|
-
storage: options?.storage ?? stored.source,
|
|
208
|
-
});
|
|
169
|
+
return getAgentAccessTokenFromStoredCredentials(agentId, ADAPTERS[agentId], options, getAccessToken);
|
|
209
170
|
}
|
|
210
171
|
/**
|
|
211
172
|
* Convert credentials to environment variables.
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,8 @@ import packageJson from "../package.json" with { type: "json" };
|
|
|
9
9
|
import { handleAuthExport, handleAuthInstall, handleAuthList, handleAuthRemove, handleAuthToken, } from "./commands/auth.js";
|
|
10
10
|
import { handleDecrypt } from "./commands/decrypt.js";
|
|
11
11
|
import { handleEncrypt } from "./commands/encrypt.js";
|
|
12
|
-
import { handleVaultFetch
|
|
12
|
+
import { handleVaultFetch } from "./commands/vault-fetch.js";
|
|
13
|
+
import { handleVaultPush } from "./commands/vault-push.js";
|
|
13
14
|
import { AGENT_CLIS } from "axshared";
|
|
14
15
|
// Handle SIGINT gracefully
|
|
15
16
|
process.on("SIGINT", () => {
|
|
@@ -198,6 +199,8 @@ vault
|
|
|
198
199
|
.requiredOption("-a, --agent <agent>", `Agent to push credentials from (${AGENT_CLIS.join(", ")})`)
|
|
199
200
|
.requiredOption("-n, --name <name>", "Credential name in vault (e.g., ci, prod)")
|
|
200
201
|
.option("-p, --provider <provider>", "Provider to push (opencode only; pushes single provider instead of all)")
|
|
202
|
+
.option("--display-name <name>", "Human-readable display name for this credential (e.g., 'Claude (Work)')")
|
|
203
|
+
.option("--notes <text>", "Additional notes about this credential")
|
|
201
204
|
.addHelpText("after", String.raw `
|
|
202
205
|
Environment variables (option 1 - single JSON):
|
|
203
206
|
AXVAULT JSON config: {"url":"...","apiKey":"..."}
|
|
@@ -210,6 +213,9 @@ Examples:
|
|
|
210
213
|
# Push local Claude credentials to vault as "ci"
|
|
211
214
|
axauth vault push --agent claude --name ci
|
|
212
215
|
|
|
216
|
+
# Push with a display name for multi-instance identification
|
|
217
|
+
axauth vault push --agent claude --name work-claude --display-name "Claude (Work)"
|
|
218
|
+
|
|
213
219
|
# Push a single OpenCode provider to vault
|
|
214
220
|
axauth vault push --agent opencode --provider anthropic --name ci-anthropic
|
|
215
221
|
|
package/dist/commands/auth.js
CHANGED
|
@@ -37,7 +37,9 @@ async function handleAuthToken(options) {
|
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
// Extract the token based on credential type
|
|
40
|
-
const token = await getAccessToken(agentId, creds, {
|
|
40
|
+
const token = await getAccessToken(agentId, creds, {
|
|
41
|
+
provider: options.provider,
|
|
42
|
+
});
|
|
41
43
|
if (!token) {
|
|
42
44
|
const providerHint = options.provider
|
|
43
45
|
? ` for provider '${options.provider}'`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Human-readable error messages for vault failures */
|
|
2
|
+
const FAILURE_MESSAGES = {
|
|
3
|
+
"not-configured": "Vault not configured. Set AXVAULT (JSON) or AXVAULT_URL + AXVAULT_API_KEY.",
|
|
4
|
+
unreachable: "Vault server is unreachable. Check vault URL and network.",
|
|
5
|
+
unauthorized: "Invalid API key. Check apiKey in vault config.",
|
|
6
|
+
forbidden: "Access denied. API key doesn't have required access to this credential.",
|
|
7
|
+
"not-found": "Credential not found in vault.",
|
|
8
|
+
"legacy-credential": "Credential uses legacy encryption. Re-upload it to vault.",
|
|
9
|
+
"client-error": "Invalid request. Check credential name and try again.",
|
|
10
|
+
"server-error": "Vault server error. Check server logs.",
|
|
11
|
+
};
|
|
12
|
+
export { FAILURE_MESSAGES };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vault
|
|
2
|
+
* Vault fetch command - download credentials from axvault server.
|
|
3
3
|
*/
|
|
4
4
|
interface VaultFetchOptions {
|
|
5
5
|
agent: string;
|
|
@@ -19,17 +19,4 @@ interface VaultFetchOptions {
|
|
|
19
19
|
* - Outputs shell export commands with --env flag (for eval/source)
|
|
20
20
|
*/
|
|
21
21
|
declare function handleVaultFetch(options: VaultFetchOptions): Promise<void>;
|
|
22
|
-
|
|
23
|
-
agent: string;
|
|
24
|
-
name: string;
|
|
25
|
-
provider?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Handle vault push command.
|
|
29
|
-
*
|
|
30
|
-
* Reads local credentials for an agent and pushes them to the vault server
|
|
31
|
-
* in raw (unencrypted) format. This allows the vault to handle encryption
|
|
32
|
-
* and automatic token refresh.
|
|
33
|
-
*/
|
|
34
|
-
declare function handleVaultPush(options: VaultPushOptions): Promise<void>;
|
|
35
|
-
export { handleVaultFetch, handleVaultPush };
|
|
22
|
+
export { handleVaultFetch };
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vault
|
|
2
|
+
* Vault fetch command - download credentials from axvault server.
|
|
3
3
|
*/
|
|
4
|
-
import { credentialsToEnvironment,
|
|
5
|
-
import {
|
|
6
|
-
import { fetchVaultCredentials, pushVaultCredentials, } from "../vault/vault-client.js";
|
|
4
|
+
import { credentialsToEnvironment, installCredentials, } from "../auth/registry.js";
|
|
5
|
+
import { fetchVaultCredentials } from "../vault/vault-client.js";
|
|
7
6
|
import { getVaultConfig } from "../vault/vault-config.js";
|
|
7
|
+
import { FAILURE_MESSAGES } from "./vault-failure-messages.js";
|
|
8
8
|
import { validateAgent } from "./validate-agent.js";
|
|
9
|
-
/** Human-readable error messages for vault failures */
|
|
10
|
-
const FAILURE_MESSAGES = {
|
|
11
|
-
"not-configured": "Vault not configured. Set AXVAULT (JSON) or AXVAULT_URL + AXVAULT_API_KEY.",
|
|
12
|
-
unreachable: "Vault server is unreachable. Check vault URL and network.",
|
|
13
|
-
unauthorized: "Invalid API key. Check apiKey in vault config.",
|
|
14
|
-
forbidden: "Access denied. API key doesn't have read access to this credential.",
|
|
15
|
-
"not-found": "Credential not found in vault.",
|
|
16
|
-
"legacy-credential": "Credential uses legacy encryption. Re-upload it to vault.",
|
|
17
|
-
"client-error": "Invalid request. Check credential name and try again.",
|
|
18
|
-
"server-error": "Vault server error. Check server logs.",
|
|
19
|
-
};
|
|
20
9
|
/**
|
|
21
10
|
* Escape a value for safe use in shell export statement.
|
|
22
11
|
* Uses single quotes and escapes any single quotes in the value.
|
|
@@ -66,7 +55,7 @@ async function handleVaultFetch(options) {
|
|
|
66
55
|
process.exitCode = 1;
|
|
67
56
|
return;
|
|
68
57
|
}
|
|
69
|
-
const { credentials, refreshed } = result;
|
|
58
|
+
const { credentials, refreshed, displayName, notes } = result;
|
|
70
59
|
// Log refresh status to stderr (not stdout, to allow piping)
|
|
71
60
|
if (refreshed) {
|
|
72
61
|
console.error("Note: Credentials were auto-refreshed by vault");
|
|
@@ -112,71 +101,18 @@ async function handleVaultFetch(options) {
|
|
|
112
101
|
}
|
|
113
102
|
else {
|
|
114
103
|
// Output credentials as JSON (default)
|
|
104
|
+
const output = {
|
|
105
|
+
...credentials,
|
|
106
|
+
...(displayName !== undefined && { displayName }),
|
|
107
|
+
...(notes !== undefined && { notes }),
|
|
108
|
+
};
|
|
115
109
|
if (options.json) {
|
|
116
|
-
console.log(JSON.stringify(
|
|
110
|
+
console.log(JSON.stringify(output, undefined, 2));
|
|
117
111
|
}
|
|
118
112
|
else {
|
|
119
113
|
// Compact JSON for piping
|
|
120
|
-
console.log(JSON.stringify(
|
|
114
|
+
console.log(JSON.stringify(output));
|
|
121
115
|
}
|
|
122
116
|
}
|
|
123
117
|
}
|
|
124
|
-
|
|
125
|
-
* Handle vault push command.
|
|
126
|
-
*
|
|
127
|
-
* Reads local credentials for an agent and pushes them to the vault server
|
|
128
|
-
* in raw (unencrypted) format. This allows the vault to handle encryption
|
|
129
|
-
* and automatic token refresh.
|
|
130
|
-
*/
|
|
131
|
-
async function handleVaultPush(options) {
|
|
132
|
-
// Validate agent
|
|
133
|
-
const agentId = validateAgent(options.agent);
|
|
134
|
-
if (!agentId)
|
|
135
|
-
return;
|
|
136
|
-
// Validate provider flag usage
|
|
137
|
-
if (options.provider && agentId !== "opencode") {
|
|
138
|
-
console.error("Error: --provider flag is only supported for opencode agent");
|
|
139
|
-
process.exitCode = 2;
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
if (agentId === "opencode" && !options.provider) {
|
|
143
|
-
console.error("Error: --provider is required for opencode");
|
|
144
|
-
console.error("Hint: Use 'axauth list --json' to see available providers");
|
|
145
|
-
process.exitCode = 1;
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
// Check vault is configured
|
|
149
|
-
const vaultConfig = getVaultConfig();
|
|
150
|
-
if (!vaultConfig) {
|
|
151
|
-
console.error(`Error: ${FAILURE_MESSAGES["not-configured"]}`);
|
|
152
|
-
process.exitCode = 1;
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
// Extract local credentials
|
|
156
|
-
const credentials = agentId === "opencode" && options.provider
|
|
157
|
-
? getStoredCredentialsForProvider(options.provider)
|
|
158
|
-
: findCredentials(agentId);
|
|
159
|
-
if (!credentials) {
|
|
160
|
-
const hint = agentId === "opencode"
|
|
161
|
-
? `No credentials found for provider '${options.provider}'`
|
|
162
|
-
: `No credentials found for ${agentId}\nHint: Authenticate with the agent first, or use 'axauth list' to check status`;
|
|
163
|
-
console.error(`Error: ${hint}`);
|
|
164
|
-
process.exitCode = 1;
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
// Push to vault
|
|
168
|
-
const result = await pushVaultCredentials({
|
|
169
|
-
agentId,
|
|
170
|
-
name: options.name,
|
|
171
|
-
credentials,
|
|
172
|
-
provider: options.provider,
|
|
173
|
-
});
|
|
174
|
-
if (!result.ok) {
|
|
175
|
-
console.error(`Error: ${FAILURE_MESSAGES[result.reason]}`);
|
|
176
|
-
process.exitCode = 1;
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
const label = options.provider ? `${agentId}/${options.provider}` : agentId;
|
|
180
|
-
console.error(`Credentials pushed to vault: ${label} → ${options.name}`);
|
|
181
|
-
}
|
|
182
|
-
export { handleVaultFetch, handleVaultPush };
|
|
118
|
+
export { handleVaultFetch };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault push command - upload local credentials to axvault server.
|
|
3
|
+
*/
|
|
4
|
+
interface VaultPushOptions {
|
|
5
|
+
agent: string;
|
|
6
|
+
name: string;
|
|
7
|
+
provider?: string;
|
|
8
|
+
displayName?: string;
|
|
9
|
+
notes?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Handle vault push command.
|
|
13
|
+
*
|
|
14
|
+
* Reads local credentials for an agent and pushes them to the vault server
|
|
15
|
+
* in raw (unencrypted) format. This allows the vault to handle encryption
|
|
16
|
+
* and automatic token refresh.
|
|
17
|
+
*/
|
|
18
|
+
declare function handleVaultPush(options: VaultPushOptions): Promise<void>;
|
|
19
|
+
export { handleVaultPush };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault push command - upload local credentials to axvault server.
|
|
3
|
+
*/
|
|
4
|
+
import { findCredentials } from "../auth/registry.js";
|
|
5
|
+
import { getStoredCredentialsForProvider } from "../auth/agents/opencode.js";
|
|
6
|
+
import { pushVaultCredentials } from "../vault/vault-client.js";
|
|
7
|
+
import { getVaultConfig } from "../vault/vault-config.js";
|
|
8
|
+
import { FAILURE_MESSAGES } from "./vault-failure-messages.js";
|
|
9
|
+
import { validateAgent } from "./validate-agent.js";
|
|
10
|
+
/**
|
|
11
|
+
* Handle vault push command.
|
|
12
|
+
*
|
|
13
|
+
* Reads local credentials for an agent and pushes them to the vault server
|
|
14
|
+
* in raw (unencrypted) format. This allows the vault to handle encryption
|
|
15
|
+
* and automatic token refresh.
|
|
16
|
+
*/
|
|
17
|
+
async function handleVaultPush(options) {
|
|
18
|
+
// Validate agent
|
|
19
|
+
const agentId = validateAgent(options.agent);
|
|
20
|
+
if (!agentId)
|
|
21
|
+
return;
|
|
22
|
+
// Validate provider flag usage
|
|
23
|
+
if (options.provider && agentId !== "opencode") {
|
|
24
|
+
console.error("Error: --provider flag is only supported for opencode agent");
|
|
25
|
+
process.exitCode = 2;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (agentId === "opencode" && !options.provider) {
|
|
29
|
+
console.error("Error: --provider is required for opencode");
|
|
30
|
+
console.error("Hint: Use 'axauth list --json' to see available providers");
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Check vault is configured
|
|
35
|
+
const vaultConfig = getVaultConfig();
|
|
36
|
+
if (!vaultConfig) {
|
|
37
|
+
console.error(`Error: ${FAILURE_MESSAGES["not-configured"]}`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Extract local credentials
|
|
42
|
+
const credentials = agentId === "opencode" && options.provider
|
|
43
|
+
? getStoredCredentialsForProvider(options.provider)
|
|
44
|
+
: findCredentials(agentId);
|
|
45
|
+
if (!credentials) {
|
|
46
|
+
const hint = agentId === "opencode"
|
|
47
|
+
? `No credentials found for provider '${options.provider}'`
|
|
48
|
+
: `No credentials found for ${agentId}\nHint: Authenticate with the agent first, or use 'axauth list' to check status`;
|
|
49
|
+
console.error(`Error: ${hint}`);
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Push to vault
|
|
54
|
+
const result = await pushVaultCredentials({
|
|
55
|
+
agentId,
|
|
56
|
+
name: options.name,
|
|
57
|
+
credentials,
|
|
58
|
+
provider: options.provider,
|
|
59
|
+
displayName: options.displayName,
|
|
60
|
+
notes: options.notes,
|
|
61
|
+
});
|
|
62
|
+
if (!result.ok) {
|
|
63
|
+
console.error(`Error: ${FAILURE_MESSAGES[result.reason]}`);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const label = options.provider ? `${agentId}/${options.provider}` : agentId;
|
|
68
|
+
console.error(`Credentials pushed to vault: ${label} → ${options.name}`);
|
|
69
|
+
}
|
|
70
|
+
export { handleVaultPush };
|
|
@@ -14,6 +14,8 @@ type VaultResult = {
|
|
|
14
14
|
ok: true;
|
|
15
15
|
credentials: Credentials;
|
|
16
16
|
refreshed: boolean;
|
|
17
|
+
displayName: string | undefined;
|
|
18
|
+
notes: string | undefined;
|
|
17
19
|
} | {
|
|
18
20
|
ok: false;
|
|
19
21
|
reason: VaultFailureReason;
|
|
@@ -61,6 +63,10 @@ interface VaultPushOptions {
|
|
|
61
63
|
credentials: Credentials;
|
|
62
64
|
/** Provider for multi-provider agents (e.g., "anthropic" for OpenCode) */
|
|
63
65
|
provider?: string;
|
|
66
|
+
/** Human-readable display name for this credential */
|
|
67
|
+
displayName?: string;
|
|
68
|
+
/** Additional notes about this credential */
|
|
69
|
+
notes?: string;
|
|
64
70
|
}
|
|
65
71
|
/**
|
|
66
72
|
* Push credentials to the axvault server.
|
|
@@ -11,6 +11,14 @@ import { getVaultConfig } from "./vault-config.js";
|
|
|
11
11
|
const VaultCredentialResponse = z.object({
|
|
12
12
|
name: z.string(),
|
|
13
13
|
credential: z.record(z.string(), z.unknown()),
|
|
14
|
+
displayName: z
|
|
15
|
+
.string()
|
|
16
|
+
.nullish()
|
|
17
|
+
.transform((value) => value ?? undefined),
|
|
18
|
+
notes: z
|
|
19
|
+
.string()
|
|
20
|
+
.nullish()
|
|
21
|
+
.transform((value) => value ?? undefined),
|
|
14
22
|
updatedAt: z.string(),
|
|
15
23
|
});
|
|
16
24
|
/**
|
|
@@ -84,6 +92,8 @@ async function fetchVaultCredentials(options) {
|
|
|
84
92
|
ok: true,
|
|
85
93
|
credentials: body.credential,
|
|
86
94
|
refreshed: wasRefreshed,
|
|
95
|
+
displayName: body.displayName,
|
|
96
|
+
notes: body.notes,
|
|
87
97
|
};
|
|
88
98
|
}
|
|
89
99
|
catch {
|
|
@@ -133,6 +143,10 @@ async function pushVaultCredentials(options) {
|
|
|
133
143
|
type: options.credentials.type,
|
|
134
144
|
data: options.credentials.data,
|
|
135
145
|
...(options.provider !== undefined && { provider: options.provider }),
|
|
146
|
+
...(options.displayName !== undefined && {
|
|
147
|
+
displayName: options.displayName,
|
|
148
|
+
}),
|
|
149
|
+
...(options.notes !== undefined && { notes: options.notes }),
|
|
136
150
|
}),
|
|
137
151
|
});
|
|
138
152
|
// Handle error responses
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "axauth",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.2.0",
|
|
6
6
|
"description": "Authentication management library and CLI for AI coding agents",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -62,31 +62,31 @@
|
|
|
62
62
|
"automation",
|
|
63
63
|
"coding-assistant"
|
|
64
64
|
],
|
|
65
|
-
"packageManager": "pnpm@10.
|
|
65
|
+
"packageManager": "pnpm@10.30.1",
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=22.14.0"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@commander-js/extra-typings": "^14.0.0",
|
|
71
|
-
"@inquirer/password": "^5.0.
|
|
71
|
+
"@inquirer/password": "^5.0.7",
|
|
72
72
|
"axconfig": "^3.6.3",
|
|
73
|
-
"axexec": "^2.0.
|
|
73
|
+
"axexec": "^2.0.1",
|
|
74
74
|
"axshared": "^5.0.0",
|
|
75
|
-
"commander": "^14.0.
|
|
76
|
-
"zod": "^4.3.
|
|
75
|
+
"commander": "^14.0.3",
|
|
76
|
+
"zod": "^4.3.6"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
80
|
-
"@types/node": "^25.0
|
|
81
|
-
"@vitest/coverage-v8": "^4.0.
|
|
82
|
-
"eslint": "^
|
|
83
|
-
"eslint-config-axkit": "^1.1
|
|
80
|
+
"@types/node": "^25.3.0",
|
|
81
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
82
|
+
"eslint": "^10.0.1",
|
|
83
|
+
"eslint-config-axkit": "^1.2.1",
|
|
84
84
|
"fta-check": "^1.5.1",
|
|
85
85
|
"fta-cli": "^3.0.0",
|
|
86
|
-
"knip": "^5.
|
|
86
|
+
"knip": "^5.85.0",
|
|
87
87
|
"prettier": "3.8.1",
|
|
88
|
-
"semantic-release": "^25.0.
|
|
88
|
+
"semantic-release": "^25.0.3",
|
|
89
89
|
"typescript": "^5.9.3",
|
|
90
|
-
"vitest": "^4.0.
|
|
90
|
+
"vitest": "^4.0.18"
|
|
91
91
|
}
|
|
92
92
|
}
|