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,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini CLI ConfigBuilder.
|
|
3
|
+
*
|
|
4
|
+
* Translates AxrunConfig into Gemini CLI's TOML policy format.
|
|
5
|
+
*
|
|
6
|
+
* Gemini CLI supports:
|
|
7
|
+
* - Tool permissions via [[rule]] with toolName
|
|
8
|
+
* - Bash patterns via commandPrefix
|
|
9
|
+
* - Does NOT support path restrictions
|
|
10
|
+
*/
|
|
11
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { registerConfigBuilder } from "../builder.js";
|
|
14
|
+
/** Gemini CLI tool name mapping */
|
|
15
|
+
const TOOL_MAP = {
|
|
16
|
+
read: "read_file",
|
|
17
|
+
write: "write_file",
|
|
18
|
+
edit: "edit_file",
|
|
19
|
+
bash: "run_shell_command",
|
|
20
|
+
glob: "glob",
|
|
21
|
+
grep: "grep",
|
|
22
|
+
web: "web_fetch",
|
|
23
|
+
};
|
|
24
|
+
/** Gemini CLI capabilities */
|
|
25
|
+
const CAPABILITIES = {
|
|
26
|
+
toolPermissions: true,
|
|
27
|
+
bashPatterns: true,
|
|
28
|
+
pathRestrictions: false, // Gemini doesn't support path patterns
|
|
29
|
+
canDenyRead: true,
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Generate TOML rule for tool permissions.
|
|
33
|
+
*/
|
|
34
|
+
function generateToolRule(toolNames, decision, priority) {
|
|
35
|
+
if (toolNames.length === 0)
|
|
36
|
+
return "";
|
|
37
|
+
const toolNameValue = toolNames.length === 1 ? `"${toolNames[0]}"` : JSON.stringify(toolNames);
|
|
38
|
+
return `[[rule]]
|
|
39
|
+
toolName = ${toolNameValue}
|
|
40
|
+
decision = "${decision}"
|
|
41
|
+
priority = ${priority}`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate TOML rule for bash command patterns.
|
|
45
|
+
*/
|
|
46
|
+
function generateBashRule(patterns, decision, priority) {
|
|
47
|
+
if (patterns.length === 0)
|
|
48
|
+
return "";
|
|
49
|
+
const prefixValue = patterns.length === 1 ? `"${patterns[0]}"` : JSON.stringify(patterns);
|
|
50
|
+
return `[[rule]]
|
|
51
|
+
toolName = "run_shell_command"
|
|
52
|
+
commandPrefix = ${prefixValue}
|
|
53
|
+
decision = "${decision}"
|
|
54
|
+
priority = ${priority}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build Gemini CLI configuration.
|
|
58
|
+
*/
|
|
59
|
+
function build(config, output) {
|
|
60
|
+
mkdirSync(output, { recursive: true });
|
|
61
|
+
const warnings = [];
|
|
62
|
+
const errors = [];
|
|
63
|
+
const permissions = config.permissions;
|
|
64
|
+
// Check for unsupported rules
|
|
65
|
+
if (permissions) {
|
|
66
|
+
// Check allow rules for path restrictions (not supported, will be dropped)
|
|
67
|
+
for (const rule of permissions.allow) {
|
|
68
|
+
if (rule.type === "path") {
|
|
69
|
+
warnings.push({
|
|
70
|
+
rule,
|
|
71
|
+
reason: "Gemini CLI does not support path restrictions",
|
|
72
|
+
suggestions: [
|
|
73
|
+
`Use "${rule.tool}" to allow all ${rule.tool} operations`,
|
|
74
|
+
"Remove the path restriction",
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Check deny rules for path restrictions (not supported, must abort)
|
|
80
|
+
for (const rule of permissions.deny) {
|
|
81
|
+
if (rule.type === "path") {
|
|
82
|
+
errors.push({
|
|
83
|
+
rule,
|
|
84
|
+
reason: "Gemini CLI does not support path restrictions",
|
|
85
|
+
suggestions: [
|
|
86
|
+
`Use "${rule.tool}" to deny all ${rule.tool} operations`,
|
|
87
|
+
"Use a different agent that supports path restrictions (e.g., claude-code)",
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// If there are errors, abort
|
|
94
|
+
if (errors.length > 0) {
|
|
95
|
+
return { ok: false, errors };
|
|
96
|
+
}
|
|
97
|
+
// Create directory structure
|
|
98
|
+
const policiesDirectory = path.join(output, "policies");
|
|
99
|
+
mkdirSync(policiesDirectory, { recursive: true });
|
|
100
|
+
const rules = [];
|
|
101
|
+
if (permissions) {
|
|
102
|
+
// Collect tool permissions (excluding path rules which were warned about)
|
|
103
|
+
const allowTools = permissions.allow
|
|
104
|
+
.filter((r) => r.type === "tool")
|
|
105
|
+
.map((r) => TOOL_MAP[r.name]);
|
|
106
|
+
const denyTools = permissions.deny
|
|
107
|
+
.filter((r) => r.type === "tool")
|
|
108
|
+
.map((r) => TOOL_MAP[r.name]);
|
|
109
|
+
// Collect bash patterns
|
|
110
|
+
const allowBash = permissions.allow
|
|
111
|
+
.filter((r) => r.type === "bash")
|
|
112
|
+
.map((r) => r.pattern);
|
|
113
|
+
const denyBash = permissions.deny
|
|
114
|
+
.filter((r) => r.type === "bash")
|
|
115
|
+
.map((r) => r.pattern);
|
|
116
|
+
// Generate allow rules (high priority)
|
|
117
|
+
if (allowTools.length > 0) {
|
|
118
|
+
rules.push(generateToolRule(allowTools, "allow", 999));
|
|
119
|
+
}
|
|
120
|
+
if (allowBash.length > 0) {
|
|
121
|
+
rules.push(generateBashRule(allowBash, "allow", 998));
|
|
122
|
+
}
|
|
123
|
+
// Generate deny rules (medium priority)
|
|
124
|
+
if (denyTools.length > 0) {
|
|
125
|
+
rules.push(generateToolRule(denyTools, "deny", 500));
|
|
126
|
+
}
|
|
127
|
+
if (denyBash.length > 0) {
|
|
128
|
+
rules.push(generateBashRule(denyBash, "deny", 499));
|
|
129
|
+
}
|
|
130
|
+
// Default deny for shell commands not explicitly allowed
|
|
131
|
+
if (allowBash.length > 0 || denyBash.length > 0) {
|
|
132
|
+
rules.push(generateToolRule(["run_shell_command"], "deny", 1));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Write policy file
|
|
136
|
+
const policyPath = path.join(policiesDirectory, "axconfig.toml");
|
|
137
|
+
const policyContent = rules.filter((r) => r !== "").join("\n\n");
|
|
138
|
+
writeFileSync(policyPath, policyContent || "# No rules\n");
|
|
139
|
+
// Write empty settings.json to prevent loading user settings
|
|
140
|
+
const settingsPath = path.join(output, "settings.json");
|
|
141
|
+
writeFileSync(settingsPath, "{}");
|
|
142
|
+
return {
|
|
143
|
+
ok: true,
|
|
144
|
+
env: { GEMINI_CLI_SYSTEM_SETTINGS_PATH: settingsPath },
|
|
145
|
+
warnings,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** Gemini CLI ConfigBuilder */
|
|
149
|
+
const geminiConfigBuilder = {
|
|
150
|
+
agentId: "gemini",
|
|
151
|
+
capabilities: CAPABILITIES,
|
|
152
|
+
build,
|
|
153
|
+
};
|
|
154
|
+
// Self-register on import
|
|
155
|
+
registerConfigBuilder(geminiConfigBuilder);
|
|
156
|
+
export { geminiConfigBuilder };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode ConfigBuilder.
|
|
3
|
+
*
|
|
4
|
+
* Translates AxrunConfig into OpenCode's opencode.json format.
|
|
5
|
+
*
|
|
6
|
+
* OpenCode supports:
|
|
7
|
+
* - Tool permissions via permission.{edit,bash,webfetch}
|
|
8
|
+
* - Bash patterns via permission.bash object with glob patterns
|
|
9
|
+
* - Does NOT support path restrictions
|
|
10
|
+
*/
|
|
11
|
+
import type { ConfigBuilder } from "../types.js";
|
|
12
|
+
/** OpenCode ConfigBuilder */
|
|
13
|
+
declare const openCodeConfigBuilder: ConfigBuilder;
|
|
14
|
+
export { openCodeConfigBuilder };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode ConfigBuilder.
|
|
3
|
+
*
|
|
4
|
+
* Translates AxrunConfig into OpenCode's opencode.json format.
|
|
5
|
+
*
|
|
6
|
+
* OpenCode supports:
|
|
7
|
+
* - Tool permissions via permission.{edit,bash,webfetch}
|
|
8
|
+
* - Bash patterns via permission.bash object with glob patterns
|
|
9
|
+
* - Does NOT support path restrictions
|
|
10
|
+
*/
|
|
11
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { registerConfigBuilder } from "../builder.js";
|
|
14
|
+
/** OpenCode capabilities */
|
|
15
|
+
const CAPABILITIES = {
|
|
16
|
+
toolPermissions: true,
|
|
17
|
+
bashPatterns: true,
|
|
18
|
+
pathRestrictions: false, // OpenCode doesn't support path patterns
|
|
19
|
+
canDenyRead: true,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Build OpenCode configuration.
|
|
23
|
+
*/
|
|
24
|
+
function build(config, output) {
|
|
25
|
+
mkdirSync(output, { recursive: true });
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const errors = [];
|
|
28
|
+
const permissions = config.permissions;
|
|
29
|
+
// Check for unsupported rules
|
|
30
|
+
if (permissions) {
|
|
31
|
+
// Path restrictions not supported - warn for allow, error for deny
|
|
32
|
+
for (const rule of permissions.allow) {
|
|
33
|
+
if (rule.type === "path") {
|
|
34
|
+
warnings.push({
|
|
35
|
+
rule,
|
|
36
|
+
reason: "OpenCode does not support path restrictions",
|
|
37
|
+
suggestions: [
|
|
38
|
+
`Use "${rule.tool}" to allow all ${rule.tool} operations`,
|
|
39
|
+
"Remove the path restriction",
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const rule of permissions.deny) {
|
|
45
|
+
if (rule.type === "path") {
|
|
46
|
+
errors.push({
|
|
47
|
+
rule,
|
|
48
|
+
reason: "OpenCode does not support path restrictions",
|
|
49
|
+
suggestions: [
|
|
50
|
+
`Use "${rule.tool}" to deny all ${rule.tool} operations`,
|
|
51
|
+
"Use a different agent that supports path restrictions (e.g., claude-code)",
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// If there are errors, abort
|
|
58
|
+
if (errors.length > 0) {
|
|
59
|
+
return { ok: false, errors };
|
|
60
|
+
}
|
|
61
|
+
const configPath = path.join(output, "opencode.json");
|
|
62
|
+
// Build permission config
|
|
63
|
+
const permissionConfig = {};
|
|
64
|
+
if (permissions) {
|
|
65
|
+
// Collect tool permissions
|
|
66
|
+
const allowedTools = new Set(permissions.allow
|
|
67
|
+
.filter((r) => r.type === "tool")
|
|
68
|
+
.map((r) => r.name));
|
|
69
|
+
const deniedTools = new Set(permissions.deny
|
|
70
|
+
.filter((r) => r.type === "tool")
|
|
71
|
+
.map((r) => r.name));
|
|
72
|
+
// Set edit permission (covers read, write, edit)
|
|
73
|
+
if (deniedTools.has("edit") || deniedTools.has("write")) {
|
|
74
|
+
permissionConfig.edit = "deny";
|
|
75
|
+
}
|
|
76
|
+
else if (allowedTools.has("edit") || allowedTools.has("write")) {
|
|
77
|
+
permissionConfig.edit = "allow";
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
permissionConfig.edit = "deny"; // Default deny
|
|
81
|
+
}
|
|
82
|
+
// Set webfetch permission
|
|
83
|
+
if (deniedTools.has("web")) {
|
|
84
|
+
permissionConfig.webfetch = "deny";
|
|
85
|
+
}
|
|
86
|
+
else if (allowedTools.has("web")) {
|
|
87
|
+
permissionConfig.webfetch = "allow";
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
permissionConfig.webfetch = "deny"; // Default deny
|
|
91
|
+
}
|
|
92
|
+
// Build bash permission with patterns
|
|
93
|
+
const allowBash = permissions.allow
|
|
94
|
+
.filter((r) => r.type === "bash")
|
|
95
|
+
.map((r) => r.pattern);
|
|
96
|
+
const denyBash = permissions.deny
|
|
97
|
+
.filter((r) => r.type === "bash")
|
|
98
|
+
.map((r) => r.pattern);
|
|
99
|
+
const bashAllowed = allowedTools.has("bash");
|
|
100
|
+
const bashDenied = deniedTools.has("bash");
|
|
101
|
+
if (bashDenied) {
|
|
102
|
+
// Deny all bash
|
|
103
|
+
permissionConfig.bash = "deny";
|
|
104
|
+
}
|
|
105
|
+
else if (allowBash.length > 0 || denyBash.length > 0) {
|
|
106
|
+
// Use pattern-based config
|
|
107
|
+
const bashConfig = {};
|
|
108
|
+
// Add allow patterns
|
|
109
|
+
for (const pattern of allowBash) {
|
|
110
|
+
bashConfig[pattern] = "allow";
|
|
111
|
+
}
|
|
112
|
+
// Add deny patterns
|
|
113
|
+
for (const pattern of denyBash) {
|
|
114
|
+
bashConfig[pattern] = "deny";
|
|
115
|
+
}
|
|
116
|
+
// Default deny for unmatched patterns
|
|
117
|
+
bashConfig["*"] = "deny";
|
|
118
|
+
permissionConfig.bash = bashConfig;
|
|
119
|
+
}
|
|
120
|
+
else if (bashAllowed) {
|
|
121
|
+
permissionConfig.bash = "allow";
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
permissionConfig.bash = "deny"; // Default deny
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// No permissions = deny all
|
|
129
|
+
permissionConfig.edit = "deny";
|
|
130
|
+
permissionConfig.bash = "deny";
|
|
131
|
+
permissionConfig.webfetch = "deny";
|
|
132
|
+
}
|
|
133
|
+
// Write config file
|
|
134
|
+
const openCodeConfig = {
|
|
135
|
+
permission: permissionConfig,
|
|
136
|
+
};
|
|
137
|
+
writeFileSync(configPath, JSON.stringify(openCodeConfig, undefined, 2));
|
|
138
|
+
return {
|
|
139
|
+
ok: true,
|
|
140
|
+
env: { OPENCODE_CONFIG: configPath },
|
|
141
|
+
warnings,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** OpenCode ConfigBuilder */
|
|
145
|
+
const openCodeConfigBuilder = {
|
|
146
|
+
agentId: "opencode",
|
|
147
|
+
capabilities: CAPABILITIES,
|
|
148
|
+
build,
|
|
149
|
+
};
|
|
150
|
+
// Self-register on import
|
|
151
|
+
registerConfigBuilder(openCodeConfigBuilder);
|
|
152
|
+
export { openCodeConfigBuilder };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthStatus, Credentials } from "../types.js";
|
|
5
|
+
/** Check Claude Code auth status */
|
|
6
|
+
declare function checkAuth(): AuthStatus;
|
|
7
|
+
/** Extract Claude Code credentials */
|
|
8
|
+
declare function extractCredentials(): Credentials | undefined;
|
|
9
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
const AGENT_ID = "claude-code";
|
|
9
|
+
/** Check Claude Code auth status */
|
|
10
|
+
function checkAuth() {
|
|
11
|
+
// 1. Check env var first
|
|
12
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
13
|
+
return { agentId: AGENT_ID, authenticated: true, method: "OAuth (env)" };
|
|
14
|
+
}
|
|
15
|
+
// 2. Check credentials store
|
|
16
|
+
if (process.platform === "darwin") {
|
|
17
|
+
// macOS: Keychain
|
|
18
|
+
try {
|
|
19
|
+
const result = execSync('security find-generic-password -a "$USER" -s "Claude Code-credentials" -w', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
20
|
+
const creds = JSON.parse(result.trim());
|
|
21
|
+
if (creds.claudeAiOauth?.accessToken) {
|
|
22
|
+
const subType = creds.claudeAiOauth.subscriptionType;
|
|
23
|
+
return {
|
|
24
|
+
agentId: AGENT_ID,
|
|
25
|
+
authenticated: true,
|
|
26
|
+
method: `OAuth (${subType ?? "keychain"})`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Not in keychain or access denied
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Linux/Windows: Plaintext file
|
|
36
|
+
const configDirectory = process.env.CLAUDE_CONFIG_DIR ?? path.join(homedir(), ".claude");
|
|
37
|
+
const credsFile = path.join(configDirectory, ".credentials.json");
|
|
38
|
+
if (existsSync(credsFile)) {
|
|
39
|
+
try {
|
|
40
|
+
const creds = JSON.parse(readFileSync(credsFile, "utf8"));
|
|
41
|
+
if (creds.claudeAiOauth?.accessToken) {
|
|
42
|
+
return { agentId: AGENT_ID, authenticated: true, method: "OAuth" };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Invalid JSON
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 3. Check API key
|
|
51
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
52
|
+
return { agentId: AGENT_ID, authenticated: true, method: "API key" };
|
|
53
|
+
}
|
|
54
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
55
|
+
}
|
|
56
|
+
/** Extract Claude Code credentials */
|
|
57
|
+
function extractCredentials() {
|
|
58
|
+
// 1. Check env var first
|
|
59
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
60
|
+
return {
|
|
61
|
+
agent: AGENT_ID,
|
|
62
|
+
type: "oauth",
|
|
63
|
+
data: { accessToken: process.env.CLAUDE_CODE_OAUTH_TOKEN },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// 2. Check credentials store
|
|
67
|
+
if (process.platform === "darwin") {
|
|
68
|
+
// macOS: Keychain
|
|
69
|
+
try {
|
|
70
|
+
const result = execSync('security find-generic-password -a "$USER" -s "Claude Code-credentials" -w', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
71
|
+
const creds = JSON.parse(result.trim());
|
|
72
|
+
if (creds.claudeAiOauth) {
|
|
73
|
+
return { agent: AGENT_ID, type: "oauth", data: creds.claudeAiOauth };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Not in keychain or access denied
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Linux/Windows: Plaintext file
|
|
82
|
+
const configDirectory = process.env.CLAUDE_CONFIG_DIR ?? path.join(homedir(), ".claude");
|
|
83
|
+
const credsFile = path.join(configDirectory, ".credentials.json");
|
|
84
|
+
if (existsSync(credsFile)) {
|
|
85
|
+
try {
|
|
86
|
+
const creds = JSON.parse(readFileSync(credsFile, "utf8"));
|
|
87
|
+
if (creds.claudeAiOauth) {
|
|
88
|
+
return { agent: AGENT_ID, type: "oauth", data: creds.claudeAiOauth };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Invalid JSON
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 3. Check API key
|
|
97
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
98
|
+
return {
|
|
99
|
+
agent: AGENT_ID,
|
|
100
|
+
type: "api-key",
|
|
101
|
+
data: { apiKey: process.env.ANTHROPIC_API_KEY },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthStatus, Credentials } from "../types.js";
|
|
5
|
+
/** Check Codex auth status */
|
|
6
|
+
declare function checkAuth(): AuthStatus;
|
|
7
|
+
/** Extract Codex credentials */
|
|
8
|
+
declare function extractCredentials(): Credentials | undefined;
|
|
9
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex 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 = "codex";
|
|
8
|
+
/** Check Codex auth status */
|
|
9
|
+
function checkAuth() {
|
|
10
|
+
// Check env vars first
|
|
11
|
+
if (process.env.CODEX_API_KEY || process.env.OPENAI_API_KEY) {
|
|
12
|
+
return { agentId: AGENT_ID, authenticated: true, method: "API key (env)" };
|
|
13
|
+
}
|
|
14
|
+
// Check file
|
|
15
|
+
const codexHome = process.env.CODEX_HOME ?? path.join(homedir(), ".codex");
|
|
16
|
+
const authFile = path.join(codexHome, "auth.json");
|
|
17
|
+
if (existsSync(authFile)) {
|
|
18
|
+
try {
|
|
19
|
+
const auth = JSON.parse(readFileSync(authFile, "utf8"));
|
|
20
|
+
if (auth.OPENAI_API_KEY) {
|
|
21
|
+
return { agentId: AGENT_ID, authenticated: true, method: "API key" };
|
|
22
|
+
}
|
|
23
|
+
if (auth.tokens?.access_token) {
|
|
24
|
+
return {
|
|
25
|
+
agentId: AGENT_ID,
|
|
26
|
+
authenticated: true,
|
|
27
|
+
method: "ChatGPT OAuth",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Invalid JSON
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
36
|
+
}
|
|
37
|
+
/** Extract Codex credentials */
|
|
38
|
+
function extractCredentials() {
|
|
39
|
+
// Check env vars first
|
|
40
|
+
const environmentKey = process.env.CODEX_API_KEY ?? process.env.OPENAI_API_KEY;
|
|
41
|
+
if (environmentKey) {
|
|
42
|
+
return {
|
|
43
|
+
agent: AGENT_ID,
|
|
44
|
+
type: "api-key",
|
|
45
|
+
data: { apiKey: environmentKey },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Check file
|
|
49
|
+
const codexHome = process.env.CODEX_HOME ?? path.join(homedir(), ".codex");
|
|
50
|
+
const authFile = path.join(codexHome, "auth.json");
|
|
51
|
+
if (existsSync(authFile)) {
|
|
52
|
+
try {
|
|
53
|
+
const auth = JSON.parse(readFileSync(authFile, "utf8"));
|
|
54
|
+
if (auth.OPENAI_API_KEY) {
|
|
55
|
+
return {
|
|
56
|
+
agent: AGENT_ID,
|
|
57
|
+
type: "api-key",
|
|
58
|
+
data: { apiKey: auth.OPENAI_API_KEY },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (auth.tokens) {
|
|
62
|
+
return {
|
|
63
|
+
agent: AGENT_ID,
|
|
64
|
+
type: "oauth",
|
|
65
|
+
data: auth.tokens,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Invalid JSON
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthStatus, Credentials } from "../types.js";
|
|
5
|
+
/** Check Gemini auth status */
|
|
6
|
+
declare function checkAuth(): AuthStatus;
|
|
7
|
+
/** Extract Gemini credentials */
|
|
8
|
+
declare function extractCredentials(): Credentials | undefined;
|
|
9
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini 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 = "gemini";
|
|
8
|
+
const GEMINI_DIR = path.join(homedir(), ".gemini");
|
|
9
|
+
/** Check Gemini auth status */
|
|
10
|
+
function checkAuth() {
|
|
11
|
+
const settingsFile = path.join(GEMINI_DIR, "settings.json");
|
|
12
|
+
if (!existsSync(settingsFile)) {
|
|
13
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const settings = JSON.parse(readFileSync(settingsFile, "utf8"));
|
|
17
|
+
const authType = settings.security?.auth?.selectedType;
|
|
18
|
+
switch (authType) {
|
|
19
|
+
case "oauth-personal": {
|
|
20
|
+
if (existsSync(path.join(GEMINI_DIR, "oauth_creds.json"))) {
|
|
21
|
+
return {
|
|
22
|
+
agentId: AGENT_ID,
|
|
23
|
+
authenticated: true,
|
|
24
|
+
method: "Google OAuth",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case "gemini-api-key": {
|
|
30
|
+
if (process.env.GEMINI_API_KEY) {
|
|
31
|
+
return { agentId: AGENT_ID, authenticated: true, method: "API key" };
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case "vertex-ai": {
|
|
36
|
+
if ((process.env.GOOGLE_CLOUD_PROJECT &&
|
|
37
|
+
process.env.GOOGLE_CLOUD_LOCATION) ||
|
|
38
|
+
process.env.GOOGLE_API_KEY) {
|
|
39
|
+
return {
|
|
40
|
+
agentId: AGENT_ID,
|
|
41
|
+
authenticated: true,
|
|
42
|
+
method: "Vertex AI",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case "compute-default-credentials": {
|
|
48
|
+
return {
|
|
49
|
+
agentId: AGENT_ID,
|
|
50
|
+
authenticated: true,
|
|
51
|
+
method: "Compute ADC",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Invalid JSON
|
|
58
|
+
}
|
|
59
|
+
return { agentId: AGENT_ID, authenticated: false };
|
|
60
|
+
}
|
|
61
|
+
/** Extract Gemini credentials */
|
|
62
|
+
function extractCredentials() {
|
|
63
|
+
const settingsFile = path.join(GEMINI_DIR, "settings.json");
|
|
64
|
+
if (!existsSync(settingsFile)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const settings = JSON.parse(readFileSync(settingsFile, "utf8"));
|
|
69
|
+
const authType = settings.security?.auth?.selectedType;
|
|
70
|
+
if (authType === "oauth-personal") {
|
|
71
|
+
const oauthFile = path.join(GEMINI_DIR, "oauth_creds.json");
|
|
72
|
+
if (existsSync(oauthFile)) {
|
|
73
|
+
const oauthCreds = JSON.parse(readFileSync(oauthFile, "utf8"));
|
|
74
|
+
return { agent: AGENT_ID, type: "oauth", data: oauthCreds };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (authType === "gemini-api-key" && process.env.GEMINI_API_KEY) {
|
|
78
|
+
return {
|
|
79
|
+
agent: AGENT_ID,
|
|
80
|
+
type: "api-key",
|
|
81
|
+
data: { apiKey: process.env.GEMINI_API_KEY },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else if (authType === "vertex-ai" && process.env.GOOGLE_API_KEY) {
|
|
85
|
+
return {
|
|
86
|
+
agent: AGENT_ID,
|
|
87
|
+
type: "api-key",
|
|
88
|
+
data: { apiKey: process.env.GOOGLE_API_KEY },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Invalid JSON
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
export { checkAuth, extractCredentials };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode auth detection and credential extraction.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthStatus, Credentials } from "../types.js";
|
|
5
|
+
/** Check OpenCode auth status */
|
|
6
|
+
declare function checkAuth(): AuthStatus;
|
|
7
|
+
/** Extract OpenCode credentials */
|
|
8
|
+
declare function extractCredentials(): Credentials | undefined;
|
|
9
|
+
export { checkAuth, extractCredentials };
|