axconfig 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 +249 -0
- package/bin/axconfig +17 -0
- package/dist/agents/claude-code.d.ts +14 -0
- package/dist/agents/claude-code.js +98 -0
- package/dist/agents/codex.d.ts +15 -0
- package/dist/agents/codex.js +164 -0
- package/dist/agents/gemini.d.ts +14 -0
- package/dist/agents/gemini.js +156 -0
- package/dist/agents/opencode.d.ts +14 -0
- package/dist/agents/opencode.js +152 -0
- package/dist/auth/agents/claude-code.d.ts +9 -0
- package/dist/auth/agents/claude-code.js +106 -0
- package/dist/auth/agents/codex.d.ts +9 -0
- package/dist/auth/agents/codex.js +75 -0
- package/dist/auth/agents/gemini.d.ts +9 -0
- package/dist/auth/agents/gemini.js +97 -0
- package/dist/auth/agents/opencode.d.ts +9 -0
- package/dist/auth/agents/opencode.js +62 -0
- package/dist/auth/check-auth.d.ts +13 -0
- package/dist/auth/check-auth.js +24 -0
- package/dist/auth/extract-credentials.d.ts +11 -0
- package/dist/auth/extract-credentials.js +20 -0
- package/dist/auth/get-access-token.d.ts +35 -0
- package/dist/auth/get-access-token.js +116 -0
- package/dist/auth/types.d.ts +19 -0
- package/dist/auth/types.js +4 -0
- package/dist/build-agent-config.d.ts +41 -0
- package/dist/build-agent-config.js +79 -0
- package/dist/builder.d.ts +19 -0
- package/dist/builder.js +27 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +79 -0
- package/dist/commands/auth.d.ts +19 -0
- package/dist/commands/auth.js +87 -0
- package/dist/commands/create.d.ts +14 -0
- package/dist/commands/create.js +101 -0
- package/dist/crypto.d.ts +39 -0
- package/dist/crypto.js +78 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +53 -0
- package/dist/parse-permissions.d.ts +50 -0
- package/dist/parse-permissions.js +125 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +8 -0
- package/package.json +93 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
const AGENT_ID = "opencode";
|
|
8
|
+
function getAuthFilePath() {
|
|
9
|
+
const xdgData = process.env.XDG_DATA_HOME ?? path.join(homedir(), ".local/share");
|
|
10
|
+
return path.join(xdgData, "opencode", "auth.json");
|
|
11
|
+
}
|
|
12
|
+
/** Check OpenCode auth status */
|
|
13
|
+
function checkAuth() {
|
|
14
|
+
const authFile = getAuthFilePath();
|
|
15
|
+
if (!existsSync(authFile)) {
|
|
16
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const auth = JSON.parse(readFileSync(authFile, "utf8"));
|
|
20
|
+
const providers = Object.keys(auth);
|
|
21
|
+
const firstProvider = providers[0];
|
|
22
|
+
if (firstProvider !== undefined) {
|
|
23
|
+
const firstAuth = auth[firstProvider];
|
|
24
|
+
const method = firstAuth?.type === "oauth"
|
|
25
|
+
? "OAuth"
|
|
26
|
+
: firstAuth?.type === "api"
|
|
27
|
+
? "API key"
|
|
28
|
+
: "Well-known";
|
|
29
|
+
return {
|
|
30
|
+
agentId: AGENT_ID,
|
|
31
|
+
authenticated: true,
|
|
32
|
+
method: providers.length > 1
|
|
33
|
+
? `${method} (${providers.length} providers)`
|
|
34
|
+
: method,
|
|
35
|
+
details: { providers },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Invalid JSON
|
|
41
|
+
}
|
|
42
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
43
|
+
}
|
|
44
|
+
/** Extract OpenCode credentials */
|
|
45
|
+
function extractCredentials() {
|
|
46
|
+
const authFile = getAuthFilePath();
|
|
47
|
+
if (!existsSync(authFile)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const auth = JSON.parse(readFileSync(authFile, "utf8"));
|
|
52
|
+
const providers = Object.keys(auth);
|
|
53
|
+
if (providers.length > 0) {
|
|
54
|
+
return { agent: AGENT_ID, type: "oauth", data: auth };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Invalid JSON
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth detection for AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Checks credential presence for each agent without making API calls.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentId } from "../types.js";
|
|
7
|
+
import type { AuthStatus } from "./types.js";
|
|
8
|
+
/** Check auth status for a specific agent */
|
|
9
|
+
declare function checkAuth(agentId: AgentId): AuthStatus;
|
|
10
|
+
/** Check auth status for all agents */
|
|
11
|
+
declare function checkAllAuth(): AuthStatus[];
|
|
12
|
+
export { checkAuth, checkAllAuth };
|
|
13
|
+
export type { AuthStatus } from "./types.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth detection for AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Checks credential presence for each agent without making API calls.
|
|
5
|
+
*/
|
|
6
|
+
import { checkAuth as checkClaudeCode } from "./agents/claude-code.js";
|
|
7
|
+
import { checkAuth as checkCodex } from "./agents/codex.js";
|
|
8
|
+
import { checkAuth as checkGemini } from "./agents/gemini.js";
|
|
9
|
+
import { checkAuth as checkOpenCode } from "./agents/opencode.js";
|
|
10
|
+
const AUTH_CHECKERS = {
|
|
11
|
+
"claude-code": checkClaudeCode,
|
|
12
|
+
codex: checkCodex,
|
|
13
|
+
gemini: checkGemini,
|
|
14
|
+
opencode: checkOpenCode,
|
|
15
|
+
};
|
|
16
|
+
/** Check auth status for a specific agent */
|
|
17
|
+
function checkAuth(agentId) {
|
|
18
|
+
return AUTH_CHECKERS[agentId]();
|
|
19
|
+
}
|
|
20
|
+
/** Check auth status for all agents */
|
|
21
|
+
function checkAllAuth() {
|
|
22
|
+
return Object.values(AUTH_CHECKERS).map((checker) => checker());
|
|
23
|
+
}
|
|
24
|
+
export { checkAuth, checkAllAuth };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential extraction for AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Extracts full credential data from each agent's storage for export.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentId } from "../types.js";
|
|
7
|
+
import type { Credentials } from "./types.js";
|
|
8
|
+
/** Extract credentials for a specific agent */
|
|
9
|
+
declare function extractCredentials(agentId: AgentId): Credentials | undefined;
|
|
10
|
+
export { extractCredentials };
|
|
11
|
+
export type { Credentials } from "./types.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential extraction for AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Extracts full credential data from each agent's storage for export.
|
|
5
|
+
*/
|
|
6
|
+
import { extractCredentials as extractClaudeCode } from "./agents/claude-code.js";
|
|
7
|
+
import { extractCredentials as extractCodex } from "./agents/codex.js";
|
|
8
|
+
import { extractCredentials as extractGemini } from "./agents/gemini.js";
|
|
9
|
+
import { extractCredentials as extractOpenCode } from "./agents/opencode.js";
|
|
10
|
+
const EXTRACTORS = {
|
|
11
|
+
"claude-code": extractClaudeCode,
|
|
12
|
+
codex: extractCodex,
|
|
13
|
+
gemini: extractGemini,
|
|
14
|
+
opencode: extractOpenCode,
|
|
15
|
+
};
|
|
16
|
+
/** Extract credentials for a specific agent */
|
|
17
|
+
function extractCredentials(agentId) {
|
|
18
|
+
return EXTRACTORS[agentId]();
|
|
19
|
+
}
|
|
20
|
+
export { extractCredentials };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access token extraction from agent credentials.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to extract access tokens from credentials
|
|
5
|
+
* and convert credentials to environment variables.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentId } from "../types.js";
|
|
8
|
+
import type { Credentials } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Extract access token from credentials.
|
|
11
|
+
*
|
|
12
|
+
* Returns the primary access token (OAuth token or API key) from
|
|
13
|
+
* the credential data based on agent type.
|
|
14
|
+
*/
|
|
15
|
+
declare function getAccessToken(creds: Credentials): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Get access token for an agent.
|
|
18
|
+
*
|
|
19
|
+
* Convenience function that extracts credentials and returns the access token.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const token = getAgentAccessToken("claude-code");
|
|
23
|
+
* if (token) {
|
|
24
|
+
* // Use token for API calls
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
declare function getAgentAccessToken(agentId: AgentId): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Convert credentials to environment variables.
|
|
30
|
+
*
|
|
31
|
+
* Returns a record of environment variable names to values that can be
|
|
32
|
+
* used to authenticate the agent via environment.
|
|
33
|
+
*/
|
|
34
|
+
declare function credentialsToEnvironment(creds: Credentials): Record<string, string>;
|
|
35
|
+
export { credentialsToEnvironment, getAccessToken, getAgentAccessToken };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access token extraction from agent credentials.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to extract access tokens from credentials
|
|
5
|
+
* and convert credentials to environment variables.
|
|
6
|
+
*/
|
|
7
|
+
import { extractCredentials } from "./extract-credentials.js";
|
|
8
|
+
/**
|
|
9
|
+
* Extract access token from credentials.
|
|
10
|
+
*
|
|
11
|
+
* Returns the primary access token (OAuth token or API key) from
|
|
12
|
+
* the credential data based on agent type.
|
|
13
|
+
*/
|
|
14
|
+
function getAccessToken(creds) {
|
|
15
|
+
const data = creds.data;
|
|
16
|
+
switch (creds.agent) {
|
|
17
|
+
case "claude-code": {
|
|
18
|
+
if (creds.type === "oauth" && typeof data.accessToken === "string") {
|
|
19
|
+
return data.accessToken;
|
|
20
|
+
}
|
|
21
|
+
if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
22
|
+
return data.apiKey;
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "codex": {
|
|
27
|
+
if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
28
|
+
return data.apiKey;
|
|
29
|
+
}
|
|
30
|
+
if (creds.type === "oauth" && typeof data.access_token === "string") {
|
|
31
|
+
return data.access_token;
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case "gemini": {
|
|
36
|
+
if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
37
|
+
return data.apiKey;
|
|
38
|
+
}
|
|
39
|
+
if (creds.type === "oauth" && typeof data.access_token === "string") {
|
|
40
|
+
return data.access_token;
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "opencode": {
|
|
45
|
+
// OpenCode stores provider tokens; return first available
|
|
46
|
+
for (const provider of Object.values(data)) {
|
|
47
|
+
if (provider &&
|
|
48
|
+
typeof provider === "object" &&
|
|
49
|
+
"access_token" in provider &&
|
|
50
|
+
typeof provider.access_token === "string") {
|
|
51
|
+
return provider.access_token;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get access token for an agent.
|
|
61
|
+
*
|
|
62
|
+
* Convenience function that extracts credentials and returns the access token.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const token = getAgentAccessToken("claude-code");
|
|
66
|
+
* if (token) {
|
|
67
|
+
* // Use token for API calls
|
|
68
|
+
* }
|
|
69
|
+
*/
|
|
70
|
+
function getAgentAccessToken(agentId) {
|
|
71
|
+
const creds = extractCredentials(agentId);
|
|
72
|
+
if (!creds)
|
|
73
|
+
return undefined;
|
|
74
|
+
return getAccessToken(creds);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Convert credentials to environment variables.
|
|
78
|
+
*
|
|
79
|
+
* Returns a record of environment variable names to values that can be
|
|
80
|
+
* used to authenticate the agent via environment.
|
|
81
|
+
*/
|
|
82
|
+
function credentialsToEnvironment(creds) {
|
|
83
|
+
const environment = {};
|
|
84
|
+
const data = creds.data;
|
|
85
|
+
switch (creds.agent) {
|
|
86
|
+
case "claude-code": {
|
|
87
|
+
if (creds.type === "oauth" && typeof data.accessToken === "string") {
|
|
88
|
+
environment.CLAUDE_CODE_OAUTH_TOKEN = data.accessToken;
|
|
89
|
+
}
|
|
90
|
+
else if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
91
|
+
environment.ANTHROPIC_API_KEY = data.apiKey;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "codex": {
|
|
96
|
+
if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
97
|
+
environment.OPENAI_API_KEY = data.apiKey;
|
|
98
|
+
}
|
|
99
|
+
// OAuth tokens for Codex require auth.json file, not env vars
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case "gemini": {
|
|
103
|
+
if (creds.type === "api-key" && typeof data.apiKey === "string") {
|
|
104
|
+
environment.GEMINI_API_KEY = data.apiKey;
|
|
105
|
+
}
|
|
106
|
+
// OAuth tokens for Gemini require oauth_creds.json file
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "opencode": {
|
|
110
|
+
// OpenCode requires auth.json file, no env var support
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return environment;
|
|
115
|
+
}
|
|
116
|
+
export { credentialsToEnvironment, getAccessToken, getAgentAccessToken };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for auth module.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentId } from "../types.js";
|
|
5
|
+
/** Auth status for an agent */
|
|
6
|
+
interface AuthStatus {
|
|
7
|
+
agentId: AgentId;
|
|
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: AgentId;
|
|
16
|
+
type: "oauth" | "api-key";
|
|
17
|
+
data: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export type { AuthStatus, Credentials };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build agent-specific configuration from CLI options.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentId, PermissionIssue } from "./types.js";
|
|
5
|
+
/** Result of building agent config from CLI options */
|
|
6
|
+
type AgentConfigResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
env: Record<string, string>;
|
|
9
|
+
warnings: PermissionIssue[];
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
exitCode: number;
|
|
13
|
+
errors: PermissionIssue[];
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
exitCode: number;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
/** Options for building agent config */
|
|
20
|
+
interface BuildAgentConfigOptions {
|
|
21
|
+
agentId: AgentId;
|
|
22
|
+
allow: string | undefined;
|
|
23
|
+
deny: string | undefined;
|
|
24
|
+
output: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build agent-specific config from CLI permission options.
|
|
28
|
+
*
|
|
29
|
+
* Parses --allow and --deny options, validates them against agent capabilities,
|
|
30
|
+
* and returns the environment variables needed to pass config to the agent.
|
|
31
|
+
*/
|
|
32
|
+
declare function buildAgentConfig(options: BuildAgentConfigOptions): AgentConfigResult;
|
|
33
|
+
/**
|
|
34
|
+
* Format permission errors for display.
|
|
35
|
+
*/
|
|
36
|
+
declare function formatPermissionErrors(errors: PermissionIssue[]): string;
|
|
37
|
+
/**
|
|
38
|
+
* Format permission warnings for display.
|
|
39
|
+
*/
|
|
40
|
+
declare function formatPermissionWarnings(warnings: PermissionIssue[]): string;
|
|
41
|
+
export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build agent-specific configuration from CLI options.
|
|
3
|
+
*/
|
|
4
|
+
import { getConfigBuilder } from "./builder.js";
|
|
5
|
+
import { formatRule, parsePermissions } from "./parse-permissions.js";
|
|
6
|
+
/**
|
|
7
|
+
* Build agent-specific config from CLI permission options.
|
|
8
|
+
*
|
|
9
|
+
* Parses --allow and --deny options, validates them against agent capabilities,
|
|
10
|
+
* and returns the environment variables needed to pass config to the agent.
|
|
11
|
+
*/
|
|
12
|
+
function buildAgentConfig(options) {
|
|
13
|
+
const { agentId, allow, deny, output } = options;
|
|
14
|
+
// Parse permissions
|
|
15
|
+
let axrunConfig = {};
|
|
16
|
+
if (allow !== undefined || deny !== undefined) {
|
|
17
|
+
try {
|
|
18
|
+
const permissions = parsePermissions(allow ? [allow] : [], deny ? [deny] : []);
|
|
19
|
+
axrunConfig = { permissions };
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
exitCode: 2,
|
|
26
|
+
message: `Invalid permission syntax: ${message}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Build agent-specific config
|
|
31
|
+
const configBuilder = getConfigBuilder(agentId);
|
|
32
|
+
if (!configBuilder) {
|
|
33
|
+
// No config builder for this agent - return empty config
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
env: {},
|
|
37
|
+
warnings: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const buildResult = configBuilder.build(axrunConfig, output);
|
|
41
|
+
if (!buildResult.ok) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
exitCode: 1,
|
|
45
|
+
errors: buildResult.errors,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
env: buildResult.env,
|
|
51
|
+
warnings: buildResult.warnings,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Format permission errors for display.
|
|
56
|
+
*/
|
|
57
|
+
function formatPermissionErrors(errors) {
|
|
58
|
+
const lines = [
|
|
59
|
+
"Error: Cannot run agent with specified permissions:",
|
|
60
|
+
"",
|
|
61
|
+
];
|
|
62
|
+
for (const error of errors) {
|
|
63
|
+
const suggestionLines = error.suggestions.map((s) => ` • ${s}`);
|
|
64
|
+
lines.push(` ✗ ${formatRule(error.rule)}`, ` ${error.reason}`, " Suggestions:", ...suggestionLines, "");
|
|
65
|
+
}
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format permission warnings for display.
|
|
70
|
+
*/
|
|
71
|
+
function formatPermissionWarnings(warnings) {
|
|
72
|
+
const lines = [];
|
|
73
|
+
for (const warning of warnings) {
|
|
74
|
+
const suggestionLines = warning.suggestions.map((s) => ` • ${s}`);
|
|
75
|
+
lines.push(`⚠ Warning: Rule "${formatRule(warning.rule)}" was REMOVED`, ` ${warning.reason}`, " Suggestions:", ...suggestionLines, "");
|
|
76
|
+
}
|
|
77
|
+
return lines.join("\n");
|
|
78
|
+
}
|
|
79
|
+
export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigBuilder registry.
|
|
3
|
+
*
|
|
4
|
+
* Each agent registers its ConfigBuilder to translate AxrunConfig
|
|
5
|
+
* into agent-specific configuration files.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentId, ConfigBuilder } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Register a config builder for an agent.
|
|
10
|
+
* Called by each agent's config-builder module on import.
|
|
11
|
+
*/
|
|
12
|
+
declare function registerConfigBuilder(builder: ConfigBuilder): void;
|
|
13
|
+
/**
|
|
14
|
+
* Get the config builder for an agent.
|
|
15
|
+
*
|
|
16
|
+
* @returns The config builder, or undefined if not registered
|
|
17
|
+
*/
|
|
18
|
+
declare function getConfigBuilder(agentId: AgentId): ConfigBuilder | undefined;
|
|
19
|
+
export { getConfigBuilder, registerConfigBuilder };
|
package/dist/builder.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigBuilder registry.
|
|
3
|
+
*
|
|
4
|
+
* Each agent registers its ConfigBuilder to translate AxrunConfig
|
|
5
|
+
* into agent-specific configuration files.
|
|
6
|
+
*/
|
|
7
|
+
/** Registry of config builders by agent ID */
|
|
8
|
+
const configBuilders = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Register a config builder for an agent.
|
|
11
|
+
* Called by each agent's config-builder module on import.
|
|
12
|
+
*/
|
|
13
|
+
function registerConfigBuilder(builder) {
|
|
14
|
+
if (configBuilders.has(builder.agentId)) {
|
|
15
|
+
throw new Error(`ConfigBuilder for "${builder.agentId}" is already registered`);
|
|
16
|
+
}
|
|
17
|
+
configBuilders.set(builder.agentId, builder);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the config builder for an agent.
|
|
21
|
+
*
|
|
22
|
+
* @returns The config builder, or undefined if not registered
|
|
23
|
+
*/
|
|
24
|
+
function getConfigBuilder(agentId) {
|
|
25
|
+
return configBuilders.get(agentId);
|
|
26
|
+
}
|
|
27
|
+
export { getConfigBuilder, registerConfigBuilder };
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* axconfig - AI agent configuration CLI.
|
|
4
|
+
*
|
|
5
|
+
* Manages configurations 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, handleAuthList, handleAuthToken, } from "./commands/auth.js";
|
|
10
|
+
import { handleCreate } from "./commands/create.js";
|
|
11
|
+
import { AGENT_IDS } from "./types.js";
|
|
12
|
+
// Import to trigger self-registration
|
|
13
|
+
import "./agents/claude-code.js";
|
|
14
|
+
import "./agents/codex.js";
|
|
15
|
+
import "./agents/gemini.js";
|
|
16
|
+
import "./agents/opencode.js";
|
|
17
|
+
// Handle SIGINT gracefully
|
|
18
|
+
process.on("SIGINT", () => {
|
|
19
|
+
console.error("\nInterrupted");
|
|
20
|
+
process.exit(130); // 128 + SIGINT(2)
|
|
21
|
+
});
|
|
22
|
+
const program = new Command()
|
|
23
|
+
.name(packageJson.name)
|
|
24
|
+
.description(packageJson.description)
|
|
25
|
+
.version(packageJson.version, "-V, --version")
|
|
26
|
+
.showHelpAfterError("(add --help for additional information)")
|
|
27
|
+
.showSuggestionAfterError()
|
|
28
|
+
.helpCommand(false)
|
|
29
|
+
.addHelpText("after", String.raw `
|
|
30
|
+
Examples:
|
|
31
|
+
# Create config and source it in current shell
|
|
32
|
+
eval $(axconfig create --agent claude-code --output /tmp/cfg --allow read)
|
|
33
|
+
|
|
34
|
+
# List authenticated agents
|
|
35
|
+
axconfig auth list
|
|
36
|
+
|
|
37
|
+
# Filter to show only authenticated agents
|
|
38
|
+
axconfig auth list | tail -n +2 | awk -F'\t' '$2 == "authenticated"'
|
|
39
|
+
|
|
40
|
+
# Get access token for an agent
|
|
41
|
+
axconfig auth token --agent claude-code
|
|
42
|
+
|
|
43
|
+
# Export credentials for CI/CD
|
|
44
|
+
axconfig auth export --agent claude-code --output creds.json --no-password`);
|
|
45
|
+
program
|
|
46
|
+
.command("create")
|
|
47
|
+
.description("Create agent-specific configuration")
|
|
48
|
+
.requiredOption("-a, --agent <agent>", `Agent to configure (${AGENT_IDS.join(", ")})`)
|
|
49
|
+
.requiredOption("--output <dir>", "Directory to write config files")
|
|
50
|
+
.option("--allow <rules>", "Comma-separated permissions to allow (e.g., 'read,glob,bash:git *')")
|
|
51
|
+
.option("--deny <rules>", "Comma-separated permissions to deny (e.g., 'bash:rm *,read:.env')")
|
|
52
|
+
.option("--format <format>", "Output format: env (shell export), json", "env")
|
|
53
|
+
.option("--with-credentials <file>", "Path to encrypted credentials file (from 'auth export')")
|
|
54
|
+
.action(handleCreate);
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// Auth Commands
|
|
57
|
+
// =============================================================================
|
|
58
|
+
const auth = program
|
|
59
|
+
.command("auth")
|
|
60
|
+
.description("Manage agent credentials")
|
|
61
|
+
.helpCommand(false);
|
|
62
|
+
auth
|
|
63
|
+
.command("list")
|
|
64
|
+
.description("List agents and their auth status")
|
|
65
|
+
.option("--json", "Output as JSON")
|
|
66
|
+
.action(handleAuthList);
|
|
67
|
+
auth
|
|
68
|
+
.command("token")
|
|
69
|
+
.description("Get access token for an agent")
|
|
70
|
+
.requiredOption("-a, --agent <agent>", `Agent to get token from (${AGENT_IDS.join(", ")})`)
|
|
71
|
+
.action(handleAuthToken);
|
|
72
|
+
auth
|
|
73
|
+
.command("export")
|
|
74
|
+
.description("Export credentials to encrypted file")
|
|
75
|
+
.requiredOption("-a, --agent <agent>", `Agent to export credentials from (${AGENT_IDS.join(", ")})`)
|
|
76
|
+
.requiredOption("--output <file>", "Output file path")
|
|
77
|
+
.option("--no-password", "Use default password (no prompt)")
|
|
78
|
+
.action(handleAuthExport);
|
|
79
|
+
await program.parseAsync(process.argv);
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
export { handleAuthExport, handleAuthList, handleAuthToken };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth commands - manage agent credentials.
|
|
3
|
+
*/
|
|
4
|
+
import { renameSync, writeFileSync } from "node:fs";
|
|
5
|
+
import promptPassword from "@inquirer/password";
|
|
6
|
+
import { checkAllAuth } from "../auth/check-auth.js";
|
|
7
|
+
import { extractCredentials } from "../auth/extract-credentials.js";
|
|
8
|
+
import { getAccessToken } from "../auth/get-access-token.js";
|
|
9
|
+
import { DEFAULT_PASSWORD, encrypt, toBase64 } from "../crypto.js";
|
|
10
|
+
import { AGENT_IDS } from "../types.js";
|
|
11
|
+
/** Handle auth list command */
|
|
12
|
+
function handleAuthList(options) {
|
|
13
|
+
const statuses = checkAllAuth();
|
|
14
|
+
if (options.json) {
|
|
15
|
+
console.log(JSON.stringify(statuses, undefined, 2));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
printAuthTable(statuses);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Handle auth token command */
|
|
22
|
+
function handleAuthToken(options) {
|
|
23
|
+
const { agent } = options;
|
|
24
|
+
// Validate agent
|
|
25
|
+
if (!AGENT_IDS.includes(agent)) {
|
|
26
|
+
console.error(`Error: Unknown agent '${agent}'`);
|
|
27
|
+
console.error(`Supported agents: ${AGENT_IDS.join(", ")}`);
|
|
28
|
+
process.exitCode = 2;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const creds = extractCredentials(agent);
|
|
32
|
+
if (!creds) {
|
|
33
|
+
console.error(`Error: No credentials found for ${agent}`);
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Extract the token based on credential type
|
|
38
|
+
const token = getAccessToken(creds);
|
|
39
|
+
if (!token) {
|
|
40
|
+
console.error(`Error: No access token available for ${agent}`);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Output just the token (no newline for piping)
|
|
45
|
+
process.stdout.write(token);
|
|
46
|
+
}
|
|
47
|
+
/** Handle auth export command */
|
|
48
|
+
async function handleAuthExport(options) {
|
|
49
|
+
const { agent } = options;
|
|
50
|
+
// Validate agent
|
|
51
|
+
if (!AGENT_IDS.includes(agent)) {
|
|
52
|
+
console.error(`Error: Unknown agent '${agent}'`);
|
|
53
|
+
console.error(`Supported agents: ${AGENT_IDS.join(", ")}`);
|
|
54
|
+
process.exitCode = 2;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const creds = extractCredentials(agent);
|
|
58
|
+
if (!creds) {
|
|
59
|
+
console.error(`Error: No credentials found for ${agent}`);
|
|
60
|
+
process.exitCode = 1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Get password
|
|
64
|
+
const userPassword = options.password
|
|
65
|
+
? await promptPassword({ message: "Encryption password" })
|
|
66
|
+
: DEFAULT_PASSWORD;
|
|
67
|
+
// Encrypt and write atomically (write to temp, then rename)
|
|
68
|
+
const encrypted = encrypt(JSON.stringify(creds), userPassword);
|
|
69
|
+
const file = { version: 1, agent, ...toBase64(encrypted) };
|
|
70
|
+
const temporaryFile = `${options.output}.tmp.${Date.now()}`;
|
|
71
|
+
writeFileSync(temporaryFile, JSON.stringify(file, undefined, 2), {
|
|
72
|
+
mode: 0o600,
|
|
73
|
+
});
|
|
74
|
+
renameSync(temporaryFile, options.output);
|
|
75
|
+
console.error(`Credentials exported to ${options.output}`);
|
|
76
|
+
}
|
|
77
|
+
/** Print auth status as TSV table */
|
|
78
|
+
function printAuthTable(statuses) {
|
|
79
|
+
// Header row (UPPERCASE for visibility)
|
|
80
|
+
console.log("AGENT\tSTATUS\tMETHOD");
|
|
81
|
+
// Data rows
|
|
82
|
+
for (const s of statuses) {
|
|
83
|
+
const status = s.authenticated ? "authenticated" : "not_configured";
|
|
84
|
+
console.log(`${s.agentId}\t${status}\t${s.method ?? ""}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export { handleAuthExport, handleAuthList, handleAuthToken };
|