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,108 @@
1
+ /**
2
+ * Type definitions for opencode-copilot-multi plugin
3
+ */
4
+ import type { Plugin } from '@opencode-ai/plugin';
5
+ export type { Plugin };
6
+ /**
7
+ * OAuth authentication data structure
8
+ */
9
+ export interface OAuthData {
10
+ type: 'oauth';
11
+ refresh: string;
12
+ access: string;
13
+ expires: number;
14
+ }
15
+ /**
16
+ * Account in the multi-account pool
17
+ */
18
+ export interface Account {
19
+ /** Unique identifier (based on refresh token hash) */
20
+ id: string;
21
+ /** GitHub username */
22
+ username: string;
23
+ /** Display name for UI */
24
+ displayName: string;
25
+ /** OAuth credentials */
26
+ auth: OAuthData;
27
+ /** Available models for this account */
28
+ models: string[];
29
+ /** When the account was added */
30
+ addedAt: number;
31
+ /** Last successful API call */
32
+ lastUsed?: number;
33
+ }
34
+ /**
35
+ * Account pool storage schema
36
+ */
37
+ export interface AccountPool {
38
+ version: number;
39
+ accounts: Account[];
40
+ lastUpdated: number;
41
+ }
42
+ /**
43
+ * Model configuration for opencode.json
44
+ */
45
+ export interface ModelConfig {
46
+ name: string;
47
+ limit: {
48
+ context: number;
49
+ output: number;
50
+ };
51
+ modalities: {
52
+ input: string[];
53
+ output: string[];
54
+ };
55
+ }
56
+ /**
57
+ * Provider configuration for opencode.json
58
+ */
59
+ export interface ProviderConfig {
60
+ options?: {
61
+ baseURL?: string;
62
+ apiKey?: string;
63
+ };
64
+ models: Record<string, ModelConfig>;
65
+ }
66
+ /**
67
+ * OpenCode config structure (partial)
68
+ */
69
+ export interface OpencodeConfig {
70
+ plugin?: string[];
71
+ provider?: Record<string, ProviderConfig>;
72
+ command?: Record<string, {
73
+ template: string;
74
+ description?: string;
75
+ agent?: string;
76
+ model?: string;
77
+ }>;
78
+ [key: string]: unknown;
79
+ }
80
+ /**
81
+ * GitHub Copilot API headers
82
+ */
83
+ export declare const COPILOT_HEADERS: {
84
+ readonly 'Editor-Version': "vscode/1.95.0";
85
+ readonly 'Editor-Plugin-Version': "copilot/1.250.0";
86
+ readonly 'Copilot-Integration-Id': "vscode-chat";
87
+ readonly 'Openai-Intent': "conversation-panel";
88
+ readonly 'Content-Type': "application/json";
89
+ readonly Accept: "application/json";
90
+ };
91
+ /**
92
+ * Plugin constants
93
+ */
94
+ export declare const PLUGIN_CONSTANTS: {
95
+ /** Package name (for npm and plugin registration) */
96
+ readonly PACKAGE_NAME: "opencode-copilot-multi-fix";
97
+ /** Provider name registered with OpenCode */
98
+ readonly PROVIDER_NAME: "copilot-multi";
99
+ /** Base URL for GitHub Copilot API */
100
+ readonly BASE_URL: "https://api.githubcopilot.com";
101
+ /** Pool file name */
102
+ readonly POOL_FILE: "copilot-multi-accounts.json";
103
+ /** Current pool schema version */
104
+ readonly POOL_VERSION: 1;
105
+ /** Token refresh buffer (5 minutes before expiry) */
106
+ readonly TOKEN_REFRESH_BUFFER_MS: number;
107
+ };
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B,qDAAqD;;IAErD,6CAA6C;;IAE7C,sCAAsC;;IAEtC,qBAAqB;;IAErB,kCAAkC;;IAElC,qDAAqD;;CAE7C,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Type definitions for opencode-copilot-multi plugin
3
+ */
4
+ /**
5
+ * GitHub Copilot API headers
6
+ */
7
+ export const COPILOT_HEADERS = {
8
+ 'Editor-Version': 'vscode/1.95.0',
9
+ 'Editor-Plugin-Version': 'copilot/1.250.0',
10
+ 'Copilot-Integration-Id': 'vscode-chat',
11
+ 'Openai-Intent': 'conversation-panel',
12
+ 'Content-Type': 'application/json',
13
+ 'Accept': 'application/json',
14
+ };
15
+ /**
16
+ * Plugin constants
17
+ */
18
+ export const PLUGIN_CONSTANTS = {
19
+ /** Package name (for npm and plugin registration) */
20
+ PACKAGE_NAME: 'opencode-copilot-multi-fix',
21
+ /** Provider name registered with OpenCode */
22
+ PROVIDER_NAME: 'copilot-multi',
23
+ /** Base URL for GitHub Copilot API */
24
+ BASE_URL: 'https://api.githubcopilot.com',
25
+ /** Pool file name */
26
+ POOL_FILE: 'copilot-multi-accounts.json',
27
+ /** Current pool schema version */
28
+ POOL_VERSION: 1,
29
+ /** Token refresh buffer (5 minutes before expiry) */
30
+ TOKEN_REFRESH_BUFFER_MS: 5 * 60 * 1000,
31
+ };
32
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsFH;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,gBAAgB,EAAE,eAAe;IACjC,uBAAuB,EAAE,iBAAiB;IAC1C,wBAAwB,EAAE,aAAa;IACvC,eAAe,EAAE,oBAAoB;IACrC,cAAc,EAAE,kBAAkB;IAClC,QAAQ,EAAE,kBAAkB;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,qDAAqD;IACrD,YAAY,EAAE,4BAA4B;IAC1C,6CAA6C;IAC7C,aAAa,EAAE,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,EAAE,+BAA+B;IACzC,qBAAqB;IACrB,SAAS,EAAE,6BAA6B;IACxC,kCAAkC;IAClC,YAAY,EAAE,CAAC;IACf,qDAAqD;IACrD,uBAAuB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;CAC9B,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Custom error classes for the plugin
3
+ */
4
+ export declare class PluginError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ export declare class AccountNotFoundError extends PluginError {
8
+ readonly username: string;
9
+ constructor(username: string);
10
+ }
11
+ export declare class TokenRefreshError extends PluginError {
12
+ readonly username: string;
13
+ readonly cause?: Error | undefined;
14
+ constructor(username: string, cause?: Error | undefined);
15
+ }
16
+ export declare class InvalidModelIdError extends PluginError {
17
+ readonly modelId: string;
18
+ constructor(modelId: string);
19
+ }
20
+ export declare class GitHubAPIError extends PluginError {
21
+ readonly statusCode?: number | undefined;
22
+ constructor(message: string, statusCode?: number | undefined);
23
+ }
24
+ export declare class PoolCorruptedError extends PluginError {
25
+ readonly path: string;
26
+ constructor(path: string);
27
+ }
28
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,oBAAqB,SAAQ,WAAW;aACvB,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;CAI7C;AAED,qBAAa,iBAAkB,SAAQ,WAAW;aAE9B,QAAQ,EAAE,MAAM;aAChB,KAAK,CAAC,EAAE,KAAK;gBADb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED,qBAAa,mBAAoB,SAAQ,WAAW;aACtB,OAAO,EAAE,MAAM;gBAAf,OAAO,EAAE,MAAM;CAI5C;AAED,qBAAa,cAAe,SAAQ,WAAW;aAG3B,UAAU,CAAC,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,UAAU,CAAC,EAAE,MAAM,YAAA;CAKtC;AAED,qBAAa,kBAAmB,SAAQ,WAAW;aACrB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIzC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Custom error classes for the plugin
3
+ */
4
+ export class PluginError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = 'PluginError';
8
+ }
9
+ }
10
+ export class AccountNotFoundError extends PluginError {
11
+ username;
12
+ constructor(username) {
13
+ super(`Account not found: ${username}`);
14
+ this.username = username;
15
+ this.name = 'AccountNotFoundError';
16
+ }
17
+ }
18
+ export class TokenRefreshError extends PluginError {
19
+ username;
20
+ cause;
21
+ constructor(username, cause) {
22
+ super(`Failed to refresh token for account: ${username}`);
23
+ this.username = username;
24
+ this.cause = cause;
25
+ this.name = 'TokenRefreshError';
26
+ }
27
+ }
28
+ export class InvalidModelIdError extends PluginError {
29
+ modelId;
30
+ constructor(modelId) {
31
+ super(`Invalid model ID format: ${modelId}. Expected format: username:model`);
32
+ this.modelId = modelId;
33
+ this.name = 'InvalidModelIdError';
34
+ }
35
+ }
36
+ export class GitHubAPIError extends PluginError {
37
+ statusCode;
38
+ constructor(message, statusCode) {
39
+ super(message);
40
+ this.statusCode = statusCode;
41
+ this.name = 'GitHubAPIError';
42
+ }
43
+ }
44
+ export class PoolCorruptedError extends PluginError {
45
+ path;
46
+ constructor(path) {
47
+ super(`Account pool file is corrupted: ${path}`);
48
+ this.path = path;
49
+ this.name = 'PoolCorruptedError';
50
+ }
51
+ }
52
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IACvB;IAA5B,YAA4B,QAAgB;QAC1C,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QADd,aAAQ,GAAR,QAAQ,CAAQ;QAE1C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAE9B;IACA;IAFlB,YACkB,QAAgB,EAChB,KAAa;QAE7B,KAAK,CAAC,wCAAwC,QAAQ,EAAE,CAAC,CAAC;QAH1C,aAAQ,GAAR,QAAQ,CAAQ;QAChB,UAAK,GAAL,KAAK,CAAQ;QAG7B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,WAAW;IACtB;IAA5B,YAA4B,OAAe;QACzC,KAAK,CAAC,4BAA4B,OAAO,mCAAmC,CAAC,CAAC;QADpD,YAAO,GAAP,OAAO,CAAQ;QAEzC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,WAAW;IAG3B;IAFlB,YACE,OAAe,EACC,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IACrB;IAA5B,YAA4B,IAAY;QACtC,KAAK,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;QADvB,SAAI,GAAJ,IAAI,CAAQ;QAEtC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * JSONC (JSON with Comments) utilities
3
+ *
4
+ * Simple parser that strips comments and trailing commas
5
+ * to enable JSON.parse() on JSONC files
6
+ */
7
+ /**
8
+ * Parse JSONC content to JavaScript object
9
+ * Removes:
10
+ * - Single-line comments (// ...)
11
+ * - Multi-line comments (slash-star ... star-slash)
12
+ * - Trailing commas
13
+ */
14
+ export declare function parseJSONC(content: string): any;
15
+ /**
16
+ * Stringify object to JSON with formatting
17
+ * Note: This does NOT preserve original comments
18
+ */
19
+ export declare function stringifyJSON(obj: any, indent?: number): string;
20
+ //# sourceMappingURL=jsonc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonc.d.ts","sourceRoot":"","sources":["../../src/utils/jsonc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAmF/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAElE"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * JSONC (JSON with Comments) utilities
3
+ *
4
+ * Simple parser that strips comments and trailing commas
5
+ * to enable JSON.parse() on JSONC files
6
+ */
7
+ /**
8
+ * Parse JSONC content to JavaScript object
9
+ * Removes:
10
+ * - Single-line comments (// ...)
11
+ * - Multi-line comments (slash-star ... star-slash)
12
+ * - Trailing commas
13
+ */
14
+ export function parseJSONC(content) {
15
+ // Strategy: Remove comments carefully, preserving strings
16
+ let cleaned = '';
17
+ let inString = false;
18
+ let inSingleLineComment = false;
19
+ let inMultiLineComment = false;
20
+ let escapeNext = false;
21
+ for (let i = 0; i < content.length; i++) {
22
+ const char = content[i];
23
+ const nextChar = content[i + 1];
24
+ // Handle escape sequences in strings
25
+ if (escapeNext) {
26
+ if (inString) {
27
+ cleaned += char;
28
+ }
29
+ escapeNext = false;
30
+ continue;
31
+ }
32
+ if (char === '\\' && inString) {
33
+ cleaned += char;
34
+ escapeNext = true;
35
+ continue;
36
+ }
37
+ // Toggle string mode
38
+ if (char === '"' && !inSingleLineComment && !inMultiLineComment) {
39
+ inString = !inString;
40
+ cleaned += char;
41
+ continue;
42
+ }
43
+ // Inside string - preserve everything
44
+ if (inString) {
45
+ cleaned += char;
46
+ continue;
47
+ }
48
+ // Start single-line comment
49
+ if (char === '/' && nextChar === '/' && !inMultiLineComment) {
50
+ inSingleLineComment = true;
51
+ i++; // Skip next char
52
+ continue;
53
+ }
54
+ // End single-line comment
55
+ if (inSingleLineComment && (char === '\n' || char === '\r')) {
56
+ inSingleLineComment = false;
57
+ cleaned += char; // Preserve newline
58
+ continue;
59
+ }
60
+ // Start multi-line comment
61
+ if (char === '/' && nextChar === '*' && !inSingleLineComment) {
62
+ inMultiLineComment = true;
63
+ i++; // Skip next char
64
+ continue;
65
+ }
66
+ // End multi-line comment
67
+ if (inMultiLineComment && char === '*' && nextChar === '/') {
68
+ inMultiLineComment = false;
69
+ i++; // Skip next char
70
+ continue;
71
+ }
72
+ // Skip comment content
73
+ if (inSingleLineComment || inMultiLineComment) {
74
+ continue;
75
+ }
76
+ // Preserve non-comment content
77
+ cleaned += char;
78
+ }
79
+ // Remove trailing commas (before } or ])
80
+ const trailingCommaPattern = /,(\s*[}\]])/g;
81
+ cleaned = cleaned.replace(trailingCommaPattern, '$1');
82
+ return JSON.parse(cleaned);
83
+ }
84
+ /**
85
+ * Stringify object to JSON with formatting
86
+ * Note: This does NOT preserve original comments
87
+ */
88
+ export function stringifyJSON(obj, indent = 2) {
89
+ return JSON.stringify(obj, null, indent);
90
+ }
91
+ //# sourceMappingURL=jsonc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonc.js","sourceRoot":"","sources":["../../src/utils/jsonc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Logger utility for the plugin
3
+ * Writes to file to avoid interfering with OpenCode TUI
4
+ */
5
+ export declare const logger: {
6
+ debug(message: string, data?: unknown): void;
7
+ info(message: string, data?: unknown): void;
8
+ warn(message: string, data?: unknown): void;
9
+ error(message: string, data?: unknown): void;
10
+ };
11
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA2CH,eAAO,MAAM,MAAM;mBACF,MAAM,SAAS,OAAO,GAAG,IAAI;kBAI9B,MAAM,SAAS,OAAO,GAAG,IAAI;kBAI7B,MAAM,SAAS,OAAO,GAAG,IAAI;mBAI5B,MAAM,SAAS,OAAO,GAAG,IAAI;CAG7C,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Logger utility for the plugin
3
+ * Writes to file to avoid interfering with OpenCode TUI
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import os from 'os';
8
+ const LOG_FILE = 'copilot-multi.log';
9
+ function getLogPath() {
10
+ const homeDir = os.homedir();
11
+ const logDir = process.env.XDG_DATA_HOME
12
+ ? path.join(process.env.XDG_DATA_HOME, 'opencode', 'log')
13
+ : path.join(homeDir, '.local', 'share', 'opencode', 'log');
14
+ return path.join(logDir, LOG_FILE);
15
+ }
16
+ function ensureLogDir() {
17
+ const logPath = getLogPath();
18
+ const logDir = path.dirname(logPath);
19
+ if (!fs.existsSync(logDir)) {
20
+ fs.mkdirSync(logDir, { recursive: true });
21
+ }
22
+ }
23
+ function formatMessage(level, message, data) {
24
+ const timestamp = new Date().toISOString();
25
+ const dataStr = data !== undefined ? ` ${JSON.stringify(data)}` : '';
26
+ return `[${timestamp}] [${level}] ${message}${dataStr}\n`;
27
+ }
28
+ function writeLog(level, message, data) {
29
+ try {
30
+ ensureLogDir();
31
+ const logPath = getLogPath();
32
+ const formatted = formatMessage(level, message, data);
33
+ fs.appendFileSync(logPath, formatted);
34
+ }
35
+ catch {
36
+ // Silently fail - logging should never break the plugin
37
+ }
38
+ }
39
+ export const logger = {
40
+ debug(message, data) {
41
+ writeLog('DEBUG', message, data);
42
+ },
43
+ info(message, data) {
44
+ writeLog('INFO', message, data);
45
+ },
46
+ warn(message, data) {
47
+ writeLog('WARN', message, data);
48
+ },
49
+ error(message, data) {
50
+ writeLog('ERROR', message, data);
51
+ },
52
+ };
53
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AAErC,SAAS,UAAU;IACjB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa;QACtC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC;QACzD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IAE7D,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,OAAe,EAAE,IAAc;IACnE,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,OAAO,IAAI,SAAS,MAAM,KAAK,KAAK,OAAO,GAAG,OAAO,IAAI,CAAC;AAC5D,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,OAAe,EAAE,IAAc;IAC9D,IAAI,CAAC;QACH,YAAY,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACtD,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "opencode-copilot-multi-fix",
3
+ "version": "1.1.0",
4
+ "description": "OpenCode plugin for multiple GitHub Copilot accounts with Windows path fix",
5
+ "keywords": [
6
+ "opencode",
7
+ "plugin",
8
+ "github",
9
+ "copilot",
10
+ "multi-account"
11
+ ],
12
+ "homepage": "https://github.com/LucasSabena/multi-copilot-account#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/LucasSabena/multi-copilot-account/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/LucasSabena/multi-copilot-account.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Valerio Fantozzi (forked by Lucas Sabena)",
22
+ "type": "module",
23
+ "main": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "bin": {
26
+ "opencode-copilot-multi-fix": "bin/cli.js"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/LucasSabena/multi-copilot-account.git"
31
+ },
32
+ "license": "MIT",
33
+ "author": "Valerio Fantozzi (forked by Lucas Sabena)",
34
+ "type": "module",
35
+ "main": "dist/index.js",
36
+ "types": "dist/index.d.ts",
37
+ "bin": {
38
+ "opencode-copilot-multi-fix": "bin/cli.js"
39
+ },
40
+ "directories": {
41
+ "example": "example"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "bin/cli.js",
46
+ "scripts/postinstall.js",
47
+ "README.md"
48
+ ],
49
+ "scripts": {
50
+ "build": "tsc && tsc --project tsconfig.cli.json",
51
+ "watch": "tsc --watch",
52
+ "clean": "rm -rf dist bin/*.js",
53
+ "prepublishOnly": "npm run build",
54
+ "postinstall": "node scripts/postinstall.js"
55
+ },
56
+ "dependencies": {
57
+ "undici-types": "^6.21.0",
58
+ "zod": "^4.1.8"
59
+ },
60
+ "devDependencies": {
61
+ "@opencode-ai/plugin": "^1.1.35",
62
+ "@types/node": "^20.0.0",
63
+ "typescript": "^5.0.0"
64
+ },
65
+ "peerDependencies": {
66
+ "@opencode-ai/plugin": "*"
67
+ },
68
+ "engines": {
69
+ "node": ">=18.0.0"
70
+ }
71
+ }
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Post-install script
5
+ * Automatically registers the plugin in OpenCode configuration
6
+ *
7
+ * Runs after: npm install -g opencode-copilot-multi-fix
8
+ */
9
+
10
+ import { ensurePluginInstalled } from '../dist/config/writer.js';
11
+ import { registerProviderInAuthJson } from '../dist/storage/auth.js';
12
+ import { logger } from '../dist/utils/logger.js';
13
+
14
+ const colors = {
15
+ reset: '\x1b[0m',
16
+ bold: '\x1b[1m',
17
+ dim: '\x1b[2m',
18
+ green: '\x1b[32m',
19
+ yellow: '\x1b[33m',
20
+ cyan: '\x1b[36m',
21
+ };
22
+
23
+ const c = colors;
24
+
25
+ async function postinstall() {
26
+ try {
27
+ // Check if we're in development mode (npm install in project directory)
28
+ // Skip auto-install in dev mode to avoid interference
29
+ if (process.env.npm_config_global !== 'true' && process.cwd().includes('opencode-copilot-multi')) {
30
+ // We're in the project directory doing dev install
31
+ console.log(`${c.dim}Skipping auto-install in development mode${c.reset}`);
32
+ return;
33
+ }
34
+
35
+ console.log('');
36
+ console.log(`${c.cyan}◆${c.reset} ${c.bold}Setting up OpenCode Copilot Multi-Account Plugin...${c.reset}`);
37
+ console.log('');
38
+
39
+ // Step 1: Register plugin in opencode.json(c)
40
+ const wasInstalled = await ensurePluginInstalled();
41
+
42
+ if (wasInstalled) {
43
+ console.log(` ${c.green}✓${c.reset} Registered in ${c.bold}opencode.json(c)${c.reset}`);
44
+ } else {
45
+ console.log(` ${c.yellow}→${c.reset} Already registered in ${c.bold}opencode.json(c)${c.reset}`);
46
+ }
47
+
48
+ // Step 2: Register provider in auth.json
49
+ const authRegistered = await registerProviderInAuthJson();
50
+
51
+ if (authRegistered) {
52
+ console.log(` ${c.green}✓${c.reset} Registered in ${c.bold}auth.json${c.reset}`);
53
+ } else {
54
+ console.log(` ${c.yellow}⚠${c.reset} Could not register in ${c.bold}auth.json${c.reset}`);
55
+ }
56
+
57
+ console.log('');
58
+ console.log(`${c.green}✓${c.reset} ${c.bold}Setup complete!${c.reset}`);
59
+ console.log('');
60
+ console.log(`${c.dim}Next steps:${c.reset}`);
61
+ console.log(` ${c.dim}1.${c.reset} Run: ${c.cyan}opencode-copilot-multi-fix add${c.reset}`);
62
+ console.log(` ${c.dim}2.${c.reset} Restart OpenCode`);
63
+ console.log('');
64
+
65
+ } catch (error) {
66
+ // Don't fail the installation if setup fails
67
+ // User can still run 'opencode-copilot-multi-fix install' manually
68
+ logger.error('Post-install setup failed (non-fatal)', {
69
+ error: error instanceof Error ? error.message : String(error)
70
+ });
71
+
72
+ console.log('');
73
+ console.log(`${c.yellow}⚠${c.reset} ${c.bold}Automatic setup encountered an issue${c.reset}`);
74
+ console.log('');
75
+ console.log(`${c.dim}Please run manually:${c.reset} ${c.cyan}opencode-copilot-multi-fix install${c.reset}`);
76
+ console.log('');
77
+ }
78
+ }
79
+
80
+ // Run postinstall
81
+ postinstall().catch((error) => {
82
+ // Silent fail - don't block npm install
83
+ logger.error('Post-install script failed', {
84
+ error: error instanceof Error ? error.message : String(error)
85
+ });
86
+ });