opencode-copilot-multi-fix 1.1.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/bin/cli.js +26 -0
  4. package/dist/commands/multi-copilot.d.ts +18 -0
  5. package/dist/commands/multi-copilot.d.ts.map +1 -0
  6. package/dist/commands/multi-copilot.js +403 -0
  7. package/dist/commands/multi-copilot.js.map +1 -0
  8. package/dist/config/writer.d.ts +22 -0
  9. package/dist/config/writer.d.ts.map +1 -0
  10. package/dist/config/writer.js +143 -0
  11. package/dist/config/writer.js.map +1 -0
  12. package/dist/discovery/accounts.d.ts +24 -0
  13. package/dist/discovery/accounts.d.ts.map +1 -0
  14. package/dist/discovery/accounts.js +128 -0
  15. package/dist/discovery/accounts.js.map +1 -0
  16. package/dist/discovery/models.d.ts +32 -0
  17. package/dist/discovery/models.d.ts.map +1 -0
  18. package/dist/discovery/models.js +124 -0
  19. package/dist/discovery/models.js.map +1 -0
  20. package/dist/discovery/username.d.ts +8 -0
  21. package/dist/discovery/username.d.ts.map +1 -0
  22. package/dist/discovery/username.js +47 -0
  23. package/dist/discovery/username.js.map +1 -0
  24. package/dist/index.d.ts +31 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +82 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/provider.d.ts +16 -0
  29. package/dist/provider.d.ts.map +1 -0
  30. package/dist/provider.js +174 -0
  31. package/dist/provider.js.map +1 -0
  32. package/dist/storage/auth.d.ts +21 -0
  33. package/dist/storage/auth.d.ts.map +1 -0
  34. package/dist/storage/auth.js +130 -0
  35. package/dist/storage/auth.js.map +1 -0
  36. package/dist/storage/pool.d.ts +29 -0
  37. package/dist/storage/pool.d.ts.map +1 -0
  38. package/dist/storage/pool.js +152 -0
  39. package/dist/storage/pool.js.map +1 -0
  40. package/dist/types.d.ts +108 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +32 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/utils/errors.d.ts +28 -0
  45. package/dist/utils/errors.d.ts.map +1 -0
  46. package/dist/utils/errors.js +52 -0
  47. package/dist/utils/errors.js.map +1 -0
  48. package/dist/utils/jsonc.d.ts +20 -0
  49. package/dist/utils/jsonc.d.ts.map +1 -0
  50. package/dist/utils/jsonc.js +91 -0
  51. package/dist/utils/jsonc.js.map +1 -0
  52. package/dist/utils/logger.d.ts +11 -0
  53. package/dist/utils/logger.d.ts.map +1 -0
  54. package/dist/utils/logger.js +53 -0
  55. package/dist/utils/logger.js.map +1 -0
  56. package/package.json +71 -0
  57. package/scripts/postinstall.js +86 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Config writer - writes models to opencode.json
3
+ */
4
+ import type { Account } from '../types.js';
5
+ /**
6
+ * Write models for all accounts to opencode.json
7
+ *
8
+ * Format: provider "copilot-multi" with models like "username:model-id"
9
+ */
10
+ export declare function writeModelsToConfig(accounts: Account[]): Promise<void>;
11
+ /**
12
+ * Remove copilot-multi provider from config
13
+ * (for cleanup/uninstall)
14
+ */
15
+ export declare function removeProviderFromConfig(): Promise<void>;
16
+ /**
17
+ * Ensure plugin is registered in opencode.json(c)
18
+ *
19
+ * @returns true if plugin was newly added, false if already present
20
+ */
21
+ export declare function ensurePluginInstalled(): Promise<boolean>;
22
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/config/writer.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,aAAa,CAAC;AAmE3D;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5E;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ9D;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAwC9D"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Config writer - writes models to opencode.json
3
+ */
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import os from 'os';
7
+ import { logger } from '../utils/logger.js';
8
+ import { buildModelConfig } from '../discovery/models.js';
9
+ import { parseJSONC } from '../utils/jsonc.js';
10
+ import { PLUGIN_CONSTANTS } from '../types.js';
11
+ /**
12
+ * Get path to global opencode.json(c)
13
+ * Checks for both .jsonc and .json variants
14
+ */
15
+ function getGlobalConfigPath() {
16
+ const homeDir = os.homedir();
17
+ const configDir = path.join(homeDir, '.config', 'opencode');
18
+ // Prefer .jsonc if it exists
19
+ const jsoncPath = path.join(configDir, 'opencode.jsonc');
20
+ if (fs.existsSync(jsoncPath)) {
21
+ return jsoncPath;
22
+ }
23
+ // Fall back to .json
24
+ return path.join(configDir, 'opencode.json');
25
+ }
26
+ /**
27
+ * Read current opencode.json(c) config
28
+ */
29
+ async function readConfig() {
30
+ const configPath = getGlobalConfigPath();
31
+ try {
32
+ if (!fs.existsSync(configPath)) {
33
+ logger.debug('Config file not found, will create new one');
34
+ return {};
35
+ }
36
+ const content = fs.readFileSync(configPath, 'utf-8');
37
+ // Use JSONC parser if file is .jsonc
38
+ if (configPath.endsWith('.jsonc')) {
39
+ return parseJSONC(content);
40
+ }
41
+ return JSON.parse(content);
42
+ }
43
+ catch (error) {
44
+ logger.error('Failed to read config', {
45
+ error: error instanceof Error ? error.message : String(error)
46
+ });
47
+ return {};
48
+ }
49
+ }
50
+ /**
51
+ * Write config to opencode.json
52
+ */
53
+ async function writeConfig(config) {
54
+ const configPath = getGlobalConfigPath();
55
+ const configDir = path.dirname(configPath);
56
+ // Ensure directory exists
57
+ if (!fs.existsSync(configDir)) {
58
+ fs.mkdirSync(configDir, { recursive: true });
59
+ }
60
+ // Write with pretty formatting
61
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
62
+ logger.info('Config written', { path: configPath });
63
+ }
64
+ /**
65
+ * Write models for all accounts to opencode.json
66
+ *
67
+ * Format: provider "copilot-multi" with models like "username:model-id"
68
+ */
69
+ export async function writeModelsToConfig(accounts) {
70
+ logger.info(`Writing models for ${accounts.length} accounts to config...`);
71
+ const config = await readConfig();
72
+ // Initialize provider section
73
+ config.provider = config.provider || {};
74
+ // Create/update copilot-multi provider
75
+ config.provider[PLUGIN_CONSTANTS.PROVIDER_NAME] = {
76
+ models: {}
77
+ };
78
+ const providerConfig = config.provider[PLUGIN_CONSTANTS.PROVIDER_NAME];
79
+ // Add models for each account
80
+ for (const account of accounts) {
81
+ for (const modelId of account.models) {
82
+ // Model ID format: "username:model"
83
+ const fullModelId = `${account.username}:${modelId}`;
84
+ providerConfig.models[fullModelId] = buildModelConfig(modelId, account.displayName);
85
+ }
86
+ }
87
+ await writeConfig(config);
88
+ const totalModels = Object.keys(providerConfig.models).length;
89
+ logger.info(`Wrote ${totalModels} models to config`);
90
+ }
91
+ /**
92
+ * Remove copilot-multi provider from config
93
+ * (for cleanup/uninstall)
94
+ */
95
+ export async function removeProviderFromConfig() {
96
+ const config = await readConfig();
97
+ if (config.provider && config.provider[PLUGIN_CONSTANTS.PROVIDER_NAME]) {
98
+ delete config.provider[PLUGIN_CONSTANTS.PROVIDER_NAME];
99
+ await writeConfig(config);
100
+ logger.info('Provider removed from config');
101
+ }
102
+ }
103
+ /**
104
+ * Ensure plugin is registered in opencode.json(c)
105
+ *
106
+ * @returns true if plugin was newly added, false if already present
107
+ */
108
+ export async function ensurePluginInstalled() {
109
+ const configPath = getGlobalConfigPath();
110
+ try {
111
+ // Read config
112
+ let config = {};
113
+ if (fs.existsSync(configPath)) {
114
+ const content = fs.readFileSync(configPath, 'utf-8');
115
+ config = configPath.endsWith('.jsonc') ? parseJSONC(content) : JSON.parse(content);
116
+ }
117
+ else {
118
+ logger.debug('Config file not found, will create new one');
119
+ }
120
+ // Initialize plugin array if needed
121
+ if (!config.plugin) {
122
+ config.plugin = [];
123
+ }
124
+ // Check if already installed
125
+ if (config.plugin.includes(PLUGIN_CONSTANTS.PACKAGE_NAME)) {
126
+ logger.debug('Plugin already in config');
127
+ return false;
128
+ }
129
+ // Add plugin
130
+ config.plugin.push(PLUGIN_CONSTANTS.PACKAGE_NAME);
131
+ // Write back
132
+ await writeConfig(config);
133
+ logger.info('Plugin added to config');
134
+ return true;
135
+ }
136
+ catch (error) {
137
+ logger.error('Failed to ensure plugin installed', {
138
+ error: error instanceof Error ? error.message : String(error)
139
+ });
140
+ throw error;
141
+ }
142
+ }
143
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/config/writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Account discovery and management
3
+ * Non-blocking - called lazily, not at init
4
+ */
5
+ import type { Account } from '../types.js';
6
+ /**
7
+ * Detect and add new account from OpenCode's github-copilot auth
8
+ * This is called lazily (on first request or explicit sync)
9
+ *
10
+ * @returns The new account if added, null if already exists or no auth
11
+ */
12
+ export declare function detectAndAddNewAccount(): Promise<Account | null>;
13
+ /**
14
+ * Sync all accounts - update auth if changed, clean if removed
15
+ * Called periodically or on demand
16
+ *
17
+ * This function:
18
+ * 1. Checks if github-copilot auth still exists
19
+ * 2. If no auth, clears all accounts (user logged out)
20
+ * 3. If auth exists but token changed, adds new account
21
+ * 4. Updates config with current accounts
22
+ */
23
+ export declare function syncAccounts(): Promise<void>;
24
+ //# sourceMappingURL=accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/discovery/accounts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,aAAa,CAAC;AAyBtD;;;;;GAKG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA0CtE;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAiDlD"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Account discovery and management
3
+ * Non-blocking - called lazily, not at init
4
+ */
5
+ import { logger } from '../utils/logger.js';
6
+ import { getGitHubCopilotAuth, generateAccountId } from '../storage/auth.js';
7
+ import { getAccountPool, addAccountToPool, saveAccountPool } from '../storage/pool.js';
8
+ import { fetchGitHubUsername } from './username.js';
9
+ import { DEFAULT_COPILOT_MODELS } from './models.js';
10
+ import { writeModelsToConfig } from '../config/writer.js';
11
+ /**
12
+ * Create a new account object
13
+ */
14
+ function createAccount(username, auth) {
15
+ return {
16
+ id: generateAccountId(auth.refresh),
17
+ username,
18
+ displayName: username, // Can be customized later
19
+ auth,
20
+ models: [...DEFAULT_COPILOT_MODELS],
21
+ addedAt: Date.now(),
22
+ };
23
+ }
24
+ /**
25
+ * Check if account already exists in pool (by refresh token)
26
+ */
27
+ async function accountExistsInPool(auth) {
28
+ const pool = await getAccountPool();
29
+ const id = generateAccountId(auth.refresh);
30
+ return pool.accounts.some(a => a.id === id);
31
+ }
32
+ /**
33
+ * Detect and add new account from OpenCode's github-copilot auth
34
+ * This is called lazily (on first request or explicit sync)
35
+ *
36
+ * @returns The new account if added, null if already exists or no auth
37
+ */
38
+ export async function detectAndAddNewAccount() {
39
+ logger.info('Checking for new GitHub Copilot account...');
40
+ // Get current auth from OpenCode
41
+ const currentAuth = await getGitHubCopilotAuth();
42
+ if (!currentAuth) {
43
+ logger.info('No GitHub Copilot auth found in OpenCode');
44
+ return null;
45
+ }
46
+ // Check if already in pool
47
+ const exists = await accountExistsInPool(currentAuth);
48
+ if (exists) {
49
+ logger.debug('Account already in pool');
50
+ return null;
51
+ }
52
+ // New account! Fetch username
53
+ logger.info('New account detected, fetching username...');
54
+ try {
55
+ const username = await fetchGitHubUsername(currentAuth.access);
56
+ // Create and add account
57
+ const newAccount = createAccount(username, currentAuth);
58
+ await addAccountToPool(newAccount);
59
+ // Update config with new models
60
+ const pool = await getAccountPool();
61
+ await writeModelsToConfig(pool.accounts);
62
+ logger.info(`New account added: ${username}`);
63
+ return newAccount;
64
+ }
65
+ catch (error) {
66
+ logger.error('Failed to add new account', {
67
+ error: error instanceof Error ? error.message : String(error)
68
+ });
69
+ return null;
70
+ }
71
+ }
72
+ /**
73
+ * Sync all accounts - update auth if changed, clean if removed
74
+ * Called periodically or on demand
75
+ *
76
+ * This function:
77
+ * 1. Checks if github-copilot auth still exists
78
+ * 2. If no auth, clears all accounts (user logged out)
79
+ * 3. If auth exists but token changed, adds new account
80
+ * 4. Updates config with current accounts
81
+ */
82
+ export async function syncAccounts() {
83
+ logger.info('Syncing accounts...');
84
+ // Check if github-copilot auth still exists
85
+ const currentAuth = await getGitHubCopilotAuth();
86
+ const pool = await getAccountPool();
87
+ if (!currentAuth) {
88
+ // No github-copilot auth found - user logged out from GitHub Copilot
89
+ if (pool.accounts.length > 0) {
90
+ logger.info('GitHub Copilot auth removed, clearing all accounts from pool');
91
+ pool.accounts = [];
92
+ pool.lastUpdated = Date.now();
93
+ await saveAccountPool(pool);
94
+ await writeModelsToConfig([]);
95
+ logger.info('All accounts cleared due to logout');
96
+ }
97
+ else {
98
+ logger.debug('No auth and no accounts - nothing to sync');
99
+ }
100
+ return;
101
+ }
102
+ // Auth exists - check if it matches any account in pool
103
+ const currentId = generateAccountId(currentAuth.refresh);
104
+ const accountExists = pool.accounts.some(a => a.id === currentId);
105
+ if (!accountExists) {
106
+ // New account detected (token changed)
107
+ logger.info('Token changed or new account, detecting...');
108
+ await detectAndAddNewAccount();
109
+ }
110
+ else {
111
+ // Same account - update auth if needed
112
+ const account = pool.accounts.find(a => a.id === currentId);
113
+ if (account) {
114
+ // Update tokens in case they changed (e.g., refresh)
115
+ if (account.auth.access !== currentAuth.access ||
116
+ account.auth.refresh !== currentAuth.refresh) {
117
+ logger.debug('Updating tokens for existing account');
118
+ account.auth = currentAuth;
119
+ await saveAccountPool(pool);
120
+ }
121
+ }
122
+ }
123
+ // Update config with current accounts
124
+ const updatedPool = await getAccountPool();
125
+ await writeModelsToConfig(updatedPool.accounts);
126
+ logger.info(`Sync complete. ${updatedPool.accounts.length} accounts in pool.`);
127
+ }
128
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/discovery/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Model definitions for GitHub Copilot
3
+ * Based on observed models available via GitHub Copilot
4
+ */
5
+ import type { ModelConfig } from '../types.js';
6
+ /**
7
+ * Default models available through GitHub Copilot
8
+ */
9
+ export declare const DEFAULT_COPILOT_MODELS: string[];
10
+ /**
11
+ * Get display name for a model
12
+ */
13
+ export declare function getModelDisplayName(modelId: string): string;
14
+ /**
15
+ * Get limits for a model
16
+ */
17
+ export declare function getModelLimits(modelId: string): {
18
+ context: number;
19
+ output: number;
20
+ };
21
+ /**
22
+ * Get modalities for a model
23
+ */
24
+ export declare function getModelModalities(modelId: string): {
25
+ input: string[];
26
+ output: string[];
27
+ };
28
+ /**
29
+ * Build full model config for opencode.json
30
+ */
31
+ export declare function buildModelConfig(modelId: string, displayPrefix: string): ModelConfig;
32
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/discovery/models.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,sBAAsB,UAgBlC,CAAC;AA6EF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAEnF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAEzF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,WAAW,CAMpF"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Model definitions for GitHub Copilot
3
+ * Based on observed models available via GitHub Copilot
4
+ */
5
+ /**
6
+ * Default models available through GitHub Copilot
7
+ */
8
+ export const DEFAULT_COPILOT_MODELS = [
9
+ 'claude-sonnet-4',
10
+ 'claude-sonnet-4.5',
11
+ 'claude-haiku-4.5',
12
+ 'claude-opus-4',
13
+ 'claude-opus-4.5',
14
+ 'gpt-4o',
15
+ 'gpt-4o-mini',
16
+ 'gpt-4-turbo',
17
+ 'gpt-5',
18
+ 'o1',
19
+ 'o1-mini',
20
+ 'o3-mini',
21
+ 'gemini-2.5-pro',
22
+ 'gemini-3-flash-preview',
23
+ 'gemini-3-pro-preview',
24
+ ];
25
+ /**
26
+ * Model display names
27
+ */
28
+ const MODEL_DISPLAY_NAMES = {
29
+ 'claude-sonnet-4': 'Claude Sonnet 4',
30
+ 'claude-sonnet-4.5': 'Claude Sonnet 4.5',
31
+ 'claude-haiku-4.5': 'Claude Haiku 4.5',
32
+ 'claude-opus-4': 'Claude Opus 4',
33
+ 'claude-opus-4.5': 'Claude Opus 4.5',
34
+ 'gpt-4o': 'GPT-4o',
35
+ 'gpt-4o-mini': 'GPT-4o Mini',
36
+ 'gpt-4-turbo': 'GPT-4 Turbo',
37
+ 'gpt-5': 'GPT-5',
38
+ 'o1': 'OpenAI o1',
39
+ 'o1-mini': 'OpenAI o1-mini',
40
+ 'o3-mini': 'OpenAI o3-mini',
41
+ 'gemini-2.5-pro': 'Gemini 2.5 Pro',
42
+ 'gemini-3-flash-preview': 'Gemini 3 Flash',
43
+ 'gemini-3-pro-preview': 'Gemini 3 Pro',
44
+ };
45
+ /**
46
+ * Model limits configuration
47
+ */
48
+ const MODEL_LIMITS = {
49
+ // Claude models
50
+ 'claude-sonnet-4': { context: 200000, output: 64000 },
51
+ 'claude-sonnet-4.5': { context: 200000, output: 64000 },
52
+ 'claude-haiku-4.5': { context: 200000, output: 64000 },
53
+ 'claude-opus-4': { context: 200000, output: 64000 },
54
+ 'claude-opus-4.5': { context: 200000, output: 64000 },
55
+ // OpenAI models
56
+ 'gpt-4o': { context: 128000, output: 16000 },
57
+ 'gpt-4o-mini': { context: 128000, output: 16000 },
58
+ 'gpt-4-turbo': { context: 128000, output: 16000 },
59
+ 'gpt-5': { context: 128000, output: 32000 },
60
+ 'o1': { context: 200000, output: 100000 },
61
+ 'o1-mini': { context: 128000, output: 65536 },
62
+ 'o3-mini': { context: 200000, output: 100000 },
63
+ // Gemini models
64
+ 'gemini-2.5-pro': { context: 1048576, output: 65536 },
65
+ 'gemini-3-flash-preview': { context: 1048576, output: 65536 },
66
+ 'gemini-3-pro-preview': { context: 1048576, output: 65536 },
67
+ };
68
+ /**
69
+ * Model modalities
70
+ */
71
+ const MODEL_MODALITIES = {
72
+ // Claude - supports images
73
+ 'claude-sonnet-4': { input: ['text', 'image'], output: ['text'] },
74
+ 'claude-sonnet-4.5': { input: ['text', 'image'], output: ['text'] },
75
+ 'claude-haiku-4.5': { input: ['text', 'image'], output: ['text'] },
76
+ 'claude-opus-4': { input: ['text', 'image'], output: ['text'] },
77
+ 'claude-opus-4.5': { input: ['text', 'image'], output: ['text'] },
78
+ // OpenAI - supports images
79
+ 'gpt-4o': { input: ['text', 'image'], output: ['text'] },
80
+ 'gpt-4o-mini': { input: ['text', 'image'], output: ['text'] },
81
+ 'gpt-4-turbo': { input: ['text', 'image'], output: ['text'] },
82
+ 'gpt-5': { input: ['text', 'image'], output: ['text'] },
83
+ 'o1': { input: ['text', 'image'], output: ['text'] },
84
+ 'o1-mini': { input: ['text'], output: ['text'] },
85
+ 'o3-mini': { input: ['text'], output: ['text'] },
86
+ // Gemini - supports images and PDF
87
+ 'gemini-2.5-pro': { input: ['text', 'image', 'pdf'], output: ['text'] },
88
+ 'gemini-3-flash-preview': { input: ['text', 'image', 'pdf'], output: ['text'] },
89
+ 'gemini-3-pro-preview': { input: ['text', 'image', 'pdf'], output: ['text'] },
90
+ };
91
+ /**
92
+ * Default values for unknown models
93
+ */
94
+ const DEFAULT_LIMITS = { context: 128000, output: 16000 };
95
+ const DEFAULT_MODALITIES = { input: ['text'], output: ['text'] };
96
+ /**
97
+ * Get display name for a model
98
+ */
99
+ export function getModelDisplayName(modelId) {
100
+ return MODEL_DISPLAY_NAMES[modelId] || modelId;
101
+ }
102
+ /**
103
+ * Get limits for a model
104
+ */
105
+ export function getModelLimits(modelId) {
106
+ return MODEL_LIMITS[modelId] || DEFAULT_LIMITS;
107
+ }
108
+ /**
109
+ * Get modalities for a model
110
+ */
111
+ export function getModelModalities(modelId) {
112
+ return MODEL_MODALITIES[modelId] || DEFAULT_MODALITIES;
113
+ }
114
+ /**
115
+ * Build full model config for opencode.json
116
+ */
117
+ export function buildModelConfig(modelId, displayPrefix) {
118
+ return {
119
+ name: `${displayPrefix}: ${getModelDisplayName(modelId)}`,
120
+ limit: getModelLimits(modelId),
121
+ modalities: getModelModalities(modelId),
122
+ };
123
+ }
124
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/discovery/models.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,iBAAiB;IACjB,mBAAmB;IACnB,kBAAkB;IAClB,eAAe;IACf,iBAAiB;IACjB,QAAQ;IACR,aAAa;IACb,aAAa;IACb,OAAO;IACP,IAAI;IACJ,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,wBAAwB;IACxB,sBAAsB;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAA2B;IAClD,iBAAiB,EAAE,iBAAiB;IACpC,mBAAmB,EAAE,mBAAmB;IACxC,kBAAkB,EAAE,kBAAkB;IACtC,eAAe,EAAE,eAAe;IAChC,iBAAiB,EAAE,iBAAiB;IACpC,QAAQ,EAAE,QAAQ;IAClB,aAAa,EAAE,aAAa;IAC5B,aAAa,EAAE,aAAa;IAC5B,OAAO,EAAE,OAAO;IAChB,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,gBAAgB;IAC3B,SAAS,EAAE,gBAAgB;IAC3B,gBAAgB,EAAE,gBAAgB;IAClC,wBAAwB,EAAE,gBAAgB;IAC1C,sBAAsB,EAAE,cAAc;CACvC,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAwD;IACxE,gBAAgB;IAChB,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACrD,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACvD,kBAAkB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACtD,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACnD,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACrD,gBAAgB;IAChB,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC5C,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACjD,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IACjD,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC3C,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACzC,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC7C,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC9C,gBAAgB;IAChB,gBAAgB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;IACrD,wBAAwB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;IAC7D,sBAAsB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;CAC5D,CAAC;AAEF;;GAEG;AACH,MAAM,gBAAgB,GAA0D;IAC9E,2BAA2B;IAC3B,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACjE,mBAAmB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACnE,kBAAkB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAClE,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAC/D,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACjE,2BAA2B;IAC3B,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACxD,aAAa,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAC7D,aAAa,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAC7D,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACvD,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACpD,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAChD,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAChD,mCAAmC;IACnC,gBAAgB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IACvE,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;IAC/E,sBAAsB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;CAC9E,CAAC;AAEF;;GAEG;AACH,MAAM,cAAc,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC1D,MAAM,kBAAkB,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;AAEjE;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,mBAAmB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,YAAY,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,gBAAgB,CAAC,OAAO,CAAC,IAAI,kBAAkB,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,aAAqB;IACrE,OAAO;QACL,IAAI,EAAE,GAAG,aAAa,KAAK,mBAAmB,CAAC,OAAO,CAAC,EAAE;QACzD,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC;QAC9B,UAAU,EAAE,kBAAkB,CAAC,OAAO,CAAC;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Account discovery - fetch GitHub username from API
3
+ */
4
+ /**
5
+ * Fetch GitHub username using the access token
6
+ */
7
+ export declare function fetchGitHubUsername(accessToken: string): Promise<string>;
8
+ //# sourceMappingURL=username.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"username.d.ts","sourceRoot":"","sources":["../../src/discovery/username.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C9E"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Account discovery - fetch GitHub username from API
3
+ */
4
+ import { logger } from '../utils/logger.js';
5
+ import { GitHubAPIError } from '../utils/errors.js';
6
+ const GITHUB_API_TIMEOUT = 5000; // 5 seconds
7
+ const GITHUB_API_URL = 'https://api.github.com/user';
8
+ /**
9
+ * Fetch GitHub username using the access token
10
+ */
11
+ export async function fetchGitHubUsername(accessToken) {
12
+ const controller = new AbortController();
13
+ const timeout = setTimeout(() => controller.abort(), GITHUB_API_TIMEOUT);
14
+ try {
15
+ logger.debug('Fetching GitHub username from API...');
16
+ const response = await fetch(GITHUB_API_URL, {
17
+ headers: {
18
+ 'Authorization': `Bearer ${accessToken}`,
19
+ 'Accept': 'application/json',
20
+ 'User-Agent': 'opencode-copilot-multi',
21
+ },
22
+ signal: controller.signal,
23
+ });
24
+ if (!response.ok) {
25
+ throw new GitHubAPIError(`API returned status ${response.status}`, response.status);
26
+ }
27
+ const data = await response.json();
28
+ if (!data.login) {
29
+ throw new GitHubAPIError('API response missing login field');
30
+ }
31
+ logger.debug(`Fetched username: ${data.login}`);
32
+ return data.login;
33
+ }
34
+ catch (error) {
35
+ if (error instanceof GitHubAPIError) {
36
+ throw error;
37
+ }
38
+ // Timeout or network error
39
+ const message = error instanceof Error ? error.message : 'Unknown error';
40
+ logger.error('Failed to fetch GitHub username', { error: message });
41
+ throw new GitHubAPIError(message);
42
+ }
43
+ finally {
44
+ clearTimeout(timeout);
45
+ }
46
+ }
47
+ //# sourceMappingURL=username.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"username.js","sourceRoot":"","sources":["../../src/discovery/username.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,kBAAkB,GAAG,IAAI,CAAC,CAAC,YAAY;AAC7C,MAAM,cAAc,GAAG,6BAA6B,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAEzE,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAErD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;YAC3C,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,WAAW,EAAE;gBACxC,QAAQ,EAAE,kBAAkB;gBAC5B,YAAY,EAAE,wBAAwB;aACvC;YACD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,cAAc,CACtB,uBAAuB,QAAQ,CAAC,MAAM,EAAE,EACxC,QAAQ,CAAC,MAAM,CAChB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAuC,CAAC;QAExE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,cAAc,CAAC,kCAAkC,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC;IAEpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,MAAM,KAAK,CAAC;QACd,CAAC;QAED,2BAA2B;QAC3B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACzE,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACpE,MAAM,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;IAEpC,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * OpenCode GitHub Copilot Multi-Account Plugin
3
+ *
4
+ * Enables using multiple GitHub Copilot accounts simultaneously.
5
+ * Each account's models appear in the model selector with format:
6
+ * copilot-multi/username:model-name
7
+ *
8
+ * Architecture:
9
+ * - Single auth hook for provider "copilot-multi"
10
+ * - Custom fetch routes requests based on model ID
11
+ * - Account pool stored separately from OpenCode auth
12
+ * - Lazy loading - no blocking init
13
+ *
14
+ * Management:
15
+ * - Use CLI tool: opencode-copilot-multi list|remove|clear
16
+ *
17
+ * @author Valerio Fantozzi
18
+ * @license MIT
19
+ */
20
+ import type { Plugin } from './types.js';
21
+ /**
22
+ * Plugin entry point
23
+ *
24
+ * IMPORTANT: This function must return quickly!
25
+ * - No blocking HTTP calls
26
+ * - No heavy I/O operations
27
+ * - Defer everything to lazy loading
28
+ */
29
+ export declare const plugin: Plugin;
30
+ export default plugin;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,MAsDpB,CAAC;AAGF,eAAe,MAAM,CAAC"}