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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/bin/axconfig +17 -0
  4. package/dist/agents/claude-code.d.ts +14 -0
  5. package/dist/agents/claude-code.js +98 -0
  6. package/dist/agents/codex.d.ts +15 -0
  7. package/dist/agents/codex.js +164 -0
  8. package/dist/agents/gemini.d.ts +14 -0
  9. package/dist/agents/gemini.js +156 -0
  10. package/dist/agents/opencode.d.ts +14 -0
  11. package/dist/agents/opencode.js +152 -0
  12. package/dist/auth/agents/claude-code.d.ts +9 -0
  13. package/dist/auth/agents/claude-code.js +106 -0
  14. package/dist/auth/agents/codex.d.ts +9 -0
  15. package/dist/auth/agents/codex.js +75 -0
  16. package/dist/auth/agents/gemini.d.ts +9 -0
  17. package/dist/auth/agents/gemini.js +97 -0
  18. package/dist/auth/agents/opencode.d.ts +9 -0
  19. package/dist/auth/agents/opencode.js +62 -0
  20. package/dist/auth/check-auth.d.ts +13 -0
  21. package/dist/auth/check-auth.js +24 -0
  22. package/dist/auth/extract-credentials.d.ts +11 -0
  23. package/dist/auth/extract-credentials.js +20 -0
  24. package/dist/auth/get-access-token.d.ts +35 -0
  25. package/dist/auth/get-access-token.js +116 -0
  26. package/dist/auth/types.d.ts +19 -0
  27. package/dist/auth/types.js +4 -0
  28. package/dist/build-agent-config.d.ts +41 -0
  29. package/dist/build-agent-config.js +79 -0
  30. package/dist/builder.d.ts +19 -0
  31. package/dist/builder.js +27 -0
  32. package/dist/cli.d.ts +10 -0
  33. package/dist/cli.js +79 -0
  34. package/dist/commands/auth.d.ts +19 -0
  35. package/dist/commands/auth.js +87 -0
  36. package/dist/commands/create.d.ts +14 -0
  37. package/dist/commands/create.js +101 -0
  38. package/dist/crypto.d.ts +39 -0
  39. package/dist/crypto.js +78 -0
  40. package/dist/index.d.ts +51 -0
  41. package/dist/index.js +53 -0
  42. package/dist/parse-permissions.d.ts +50 -0
  43. package/dist/parse-permissions.js +125 -0
  44. package/dist/types.d.ts +85 -0
  45. package/dist/types.js +8 -0
  46. 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 };