opencode-account-manager 0.6.4 → 0.6.6

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 (86) hide show
  1. package/README.md +235 -216
  2. package/README_VI.md +235 -216
  3. package/dist/cli.js +83 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/core/config-store.d.ts +12 -0
  6. package/dist/core/config-store.d.ts.map +1 -1
  7. package/dist/core/config-store.js +98 -0
  8. package/dist/core/config-store.js.map +1 -1
  9. package/dist/core/health-log.d.ts +9 -0
  10. package/dist/core/health-log.d.ts.map +1 -0
  11. package/dist/core/health-log.js +154 -0
  12. package/dist/core/health-log.js.map +1 -0
  13. package/dist/core/health-oauth.d.ts +5 -0
  14. package/dist/core/health-oauth.d.ts.map +1 -0
  15. package/dist/core/health-oauth.js +147 -0
  16. package/dist/core/health-oauth.js.map +1 -0
  17. package/dist/core/health-orchestrator.d.ts +32 -0
  18. package/dist/core/health-orchestrator.d.ts.map +1 -0
  19. package/dist/core/health-orchestrator.js +148 -0
  20. package/dist/core/health-orchestrator.js.map +1 -0
  21. package/dist/core/health-utils.d.ts +15 -0
  22. package/dist/core/health-utils.d.ts.map +1 -0
  23. package/dist/core/health-utils.js +60 -0
  24. package/dist/core/health-utils.js.map +1 -0
  25. package/dist/core/paths.d.ts +1 -0
  26. package/dist/core/paths.d.ts.map +1 -1
  27. package/dist/core/paths.js +4 -0
  28. package/dist/core/paths.js.map +1 -1
  29. package/dist/core/types.d.ts +26 -0
  30. package/dist/core/types.d.ts.map +1 -1
  31. package/dist/tui/Dashboard.d.ts.map +1 -1
  32. package/dist/tui/Dashboard.js +69 -2
  33. package/dist/tui/Dashboard.js.map +1 -1
  34. package/dist/tui/components/AccountList.d.ts +5 -3
  35. package/dist/tui/components/AccountList.d.ts.map +1 -1
  36. package/dist/tui/components/AccountList.js +9 -3
  37. package/dist/tui/components/AccountList.js.map +1 -1
  38. package/dist/tui/components/DashboardView.d.ts +3 -2
  39. package/dist/tui/components/DashboardView.d.ts.map +1 -1
  40. package/dist/tui/components/DashboardView.js +102 -17
  41. package/dist/tui/components/DashboardView.js.map +1 -1
  42. package/dist/tui/components/HealthBadge.d.ts +9 -0
  43. package/dist/tui/components/HealthBadge.d.ts.map +1 -0
  44. package/dist/tui/components/HealthBadge.js +56 -0
  45. package/dist/tui/components/HealthBadge.js.map +1 -0
  46. package/dist/tui/components/StatusBadge.d.ts +2 -1
  47. package/dist/tui/components/StatusBadge.d.ts.map +1 -1
  48. package/dist/tui/components/StatusBadge.js +30 -2
  49. package/dist/tui/components/StatusBadge.js.map +1 -1
  50. package/dist/tui/components/index.d.ts +1 -0
  51. package/dist/tui/components/index.d.ts.map +1 -1
  52. package/dist/tui/components/index.js +3 -1
  53. package/dist/tui/components/index.js.map +1 -1
  54. package/docs/BLUEPRINT.md +476 -476
  55. package/docs/ROADMAP.md +125 -107
  56. package/package.json +38 -38
  57. package/src/cli.ts +139 -38
  58. package/src/core/config-store.ts +278 -171
  59. package/src/core/crypto.ts +162 -162
  60. package/src/core/health-log.ts +173 -0
  61. package/src/core/health-oauth.ts +190 -0
  62. package/src/core/health-orchestrator.ts +224 -0
  63. package/src/core/importers/amExport.ts +177 -177
  64. package/src/core/opencode-config.ts +217 -217
  65. package/src/core/paths.ts +10 -6
  66. package/src/core/types.ts +193 -147
  67. package/src/tui/Dashboard.tsx +557 -478
  68. package/src/tui/components/AccountList.tsx +122 -104
  69. package/src/tui/components/ActionPalette.tsx +117 -117
  70. package/src/tui/components/Box.tsx +7 -7
  71. package/src/tui/components/DashboardView.tsx +324 -220
  72. package/src/tui/components/ExportModal.tsx +255 -255
  73. package/src/tui/components/FileBrowser.tsx +393 -393
  74. package/src/tui/components/Header.tsx +26 -26
  75. package/src/tui/components/HealthBadge.tsx +64 -0
  76. package/src/tui/components/ImportModal.tsx +334 -334
  77. package/src/tui/components/McpServerList.tsx +67 -67
  78. package/src/tui/components/Menu.tsx +61 -61
  79. package/src/tui/components/PasswordInput.tsx +159 -159
  80. package/src/tui/components/ProviderList.tsx +59 -59
  81. package/src/tui/components/SectionBox.tsx +35 -35
  82. package/src/tui/components/StatsRow.tsx +33 -33
  83. package/src/tui/components/StatusBadge.tsx +36 -3
  84. package/src/tui/components/index.ts +15 -14
  85. package/test-minimal.js +26 -26
  86. package/test-with-accounts.js +58 -58
package/src/core/types.ts CHANGED
@@ -1,158 +1,204 @@
1
- export type RateLimitResetTimes = Record<string, number>;
2
-
3
- export interface AccountFingerprint {
4
- deviceId?: string;
5
- sessionToken?: string;
6
- userAgent?: string;
7
- apiClient?: string;
8
- clientMetadata?: Record<string, unknown>;
9
- quotaUser?: string;
10
- createdAt?: number;
11
- }
12
-
13
- export interface FingerprintHistoryEntry {
14
- fingerprint: AccountFingerprint;
15
- timestamp: number;
16
- reason?: string;
17
- }
18
-
19
- export interface Account {
20
- email: string;
21
- refreshToken?: string;
22
- projectId?: string;
23
- managedProjectId?: string;
24
- addedAt?: number;
25
- lastUsed?: number;
26
- rateLimitResetTimes?: RateLimitResetTimes;
27
- fingerprint?: AccountFingerprint;
28
- fingerprintHistory?: FingerprintHistoryEntry[];
29
- enabled?: boolean;
30
- }
31
-
32
- export interface PluginAccountsFile {
33
- version: number;
34
- accounts: Account[];
35
- activeIndex?: number;
36
- activeIndexByFamily?: Record<string, number>;
37
- }
38
-
39
- export interface PortableExportFile {
40
- version: number;
41
- exportedAt: number;
42
- exportedFrom: "opencode-account-manager" | "antigravity-sync";
43
- accounts: Account[];
44
- }
45
-
46
- // ============================================================================
47
- // Encrypted Export Types (v0.4.0)
48
- // ============================================================================
49
-
50
- export interface EncryptedExportFile {
51
- // Header (not encrypted)
52
- version: 1;
53
- format: "encrypted";
54
- algorithm: "aes-256-gcm";
55
-
56
- // Encryption parameters (hex encoded)
57
- salt: string;
58
- iv: string;
59
- authTag: string;
60
-
61
- // Encrypted payload (hex encoded JSON)
62
- data: string;
63
-
64
- // Metadata (not encrypted, for display)
65
- exportedAt: number;
66
- accountCount: number;
67
- exportedFrom: "opencode-account-manager";
68
- }
69
-
70
- /**
71
- * Type guard to check if data is an encrypted export file
72
- */
73
- export function isEncryptedExportFile(data: unknown): data is EncryptedExportFile {
74
- if (typeof data !== "object" || data === null) return false;
75
- const obj = data as Record<string, unknown>;
76
- return (
77
- obj.format === "encrypted" &&
78
- obj.algorithm === "aes-256-gcm" &&
79
- typeof obj.salt === "string" &&
80
- typeof obj.iv === "string" &&
81
- typeof obj.authTag === "string" &&
82
- typeof obj.data === "string"
83
- );
84
- }
85
-
86
- /**
87
- * Type guard to check if data is a portable export file
88
- */
89
- export function isPortableExportFile(data: unknown): data is PortableExportFile {
90
- if (typeof data !== "object" || data === null) return false;
91
- const obj = data as Record<string, unknown>;
92
- return (
93
- typeof obj.version === "number" &&
94
- typeof obj.exportedAt === "number" &&
95
- Array.isArray(obj.accounts)
96
- );
97
- }
1
+ export type RateLimitResetTimes = Record<string, number>;
2
+
3
+ export interface AccountFingerprint {
4
+ deviceId?: string;
5
+ sessionToken?: string;
6
+ userAgent?: string;
7
+ apiClient?: string;
8
+ clientMetadata?: Record<string, unknown>;
9
+ quotaUser?: string;
10
+ createdAt?: number;
11
+ }
12
+
13
+ export interface FingerprintHistoryEntry {
14
+ fingerprint: AccountFingerprint;
15
+ timestamp: number;
16
+ reason?: string;
17
+ }
18
+
19
+ export interface Account {
20
+ email: string;
21
+ refreshToken?: string;
22
+ projectId?: string;
23
+ managedProjectId?: string;
24
+ addedAt?: number;
25
+ lastUsed?: number;
26
+ rateLimitResetTimes?: RateLimitResetTimes;
27
+ fingerprint?: AccountFingerprint;
28
+ fingerprintHistory?: FingerprintHistoryEntry[];
29
+ enabled?: boolean;
30
+ }
31
+
32
+ export interface PluginAccountsFile {
33
+ version: number;
34
+ accounts: Account[];
35
+ activeIndex?: number;
36
+ activeIndexByFamily?: Record<string, number>;
37
+ }
38
+
39
+ export interface PortableExportFile {
40
+ version: number;
41
+ exportedAt: number;
42
+ exportedFrom: "opencode-account-manager" | "antigravity-sync";
43
+ accounts: Account[];
44
+ }
45
+
46
+ // ============================================================================
47
+ // Encrypted Export Types (v0.4.0)
48
+ // ============================================================================
49
+
50
+ export interface EncryptedExportFile {
51
+ // Header (not encrypted)
52
+ version: 1;
53
+ format: "encrypted";
54
+ algorithm: "aes-256-gcm";
55
+
56
+ // Encryption parameters (hex encoded)
57
+ salt: string;
58
+ iv: string;
59
+ authTag: string;
60
+
61
+ // Encrypted payload (hex encoded JSON)
62
+ data: string;
63
+
64
+ // Metadata (not encrypted, for display)
65
+ exportedAt: number;
66
+ accountCount: number;
67
+ exportedFrom: "opencode-account-manager";
68
+ }
69
+
70
+ /**
71
+ * Type guard to check if data is an encrypted export file
72
+ */
73
+ export function isEncryptedExportFile(data: unknown): data is EncryptedExportFile {
74
+ if (typeof data !== "object" || data === null) return false;
75
+ const obj = data as Record<string, unknown>;
76
+ return (
77
+ obj.format === "encrypted" &&
78
+ obj.algorithm === "aes-256-gcm" &&
79
+ typeof obj.salt === "string" &&
80
+ typeof obj.iv === "string" &&
81
+ typeof obj.authTag === "string" &&
82
+ typeof obj.data === "string"
83
+ );
84
+ }
85
+
86
+ /**
87
+ * Type guard to check if data is a portable export file
88
+ */
89
+ export function isPortableExportFile(data: unknown): data is PortableExportFile {
90
+ if (typeof data !== "object" || data === null) return false;
91
+ const obj = data as Record<string, unknown>;
92
+ return (
93
+ typeof obj.version === "number" &&
94
+ typeof obj.exportedAt === "number" &&
95
+ Array.isArray(obj.accounts)
96
+ );
97
+ }
98
+
99
+ // ============================================================================
100
+ // Export Format Types
101
+ // ============================================================================
102
+
103
+ export type ExportFormat = "encrypted" | "plain";
104
+
105
+ export interface ExportOptions {
106
+ format: ExportFormat;
107
+ folder: string;
108
+ password?: string; // Required for encrypted
109
+ accounts: Account[];
110
+ }
111
+
112
+ export interface ImportResult {
113
+ success: boolean;
114
+ accounts: Account[];
115
+ newCount: number;
116
+ overwrittenCount: number;
117
+ error?: string;
118
+ }
119
+
120
+ // ============================================================================
121
+ // Antigravity Manager Export Types
122
+ // ============================================================================
123
+
124
+ /**
125
+ * Single entry in AM export file (from app export button)
126
+ * Format: [{ "email": "...", "refresh_token": "..." }, ...]
127
+ */
128
+ export interface AMExportEntry {
129
+ email: string;
130
+ refresh_token: string;
131
+ }
132
+
133
+ /**
134
+ * Type guard to check if data is an AM export file
135
+ */
136
+ export function isAMExportFile(data: unknown): data is AMExportEntry[] {
137
+ if (!Array.isArray(data)) return false;
138
+ if (data.length === 0) return true;
139
+
140
+ const sample = data.slice(0, 3);
141
+ return sample.every(item =>
142
+ typeof item === "object" &&
143
+ item !== null &&
144
+ typeof (item as Record<string, unknown>).email === "string" &&
145
+ typeof (item as Record<string, unknown>).refresh_token === "string"
146
+ );
147
+ }
148
+
149
+ // ============================================================================
150
+ // Import Source Detection
151
+ // ============================================================================
152
+
153
+ export type ImportFileType =
154
+ | "encrypted" // .ocam encrypted file
155
+ | "portable" // opencode-account-manager plain export
156
+ | "am-export" // Antigravity Manager app export
157
+ | "plugin-native" // antigravity-accounts.json format
158
+ | "unknown";
98
159
 
99
160
  // ============================================================================
100
- // Export Format Types
161
+ // Account Health Types
101
162
  // ============================================================================
102
163
 
103
- export type ExportFormat = "encrypted" | "plain";
104
-
105
- export interface ExportOptions {
106
- format: ExportFormat;
107
- folder: string;
108
- password?: string; // Required for encrypted
109
- accounts: Account[];
164
+ export type AccountHealthStatus =
165
+ | "ok"
166
+ | "verification_required"
167
+ | "revoked"
168
+ | "disabled"
169
+ | "deleted"
170
+ | "password_changed"
171
+ | "network_error"
172
+ | "unknown_error"
173
+ | "not_checked"
174
+ | "not_configured";
175
+
176
+ export type AccountHealthSource = "oauth" | "log" | "cache" | "manual";
177
+
178
+ export interface AccountHealthResult {
179
+ status: AccountHealthStatus;
180
+ checkedAt: number;
181
+ source: AccountHealthSource;
182
+ message?: string;
183
+ errorCode?: string;
184
+ errorDescription?: string;
185
+ httpStatus?: number;
110
186
  }
111
187
 
112
- export interface ImportResult {
113
- success: boolean;
114
- accounts: Account[];
115
- newCount: number;
116
- overwrittenCount: number;
117
- error?: string;
188
+ export interface HealthSettings {
189
+ ttlMs?: number;
190
+ cooldownMs?: number;
191
+ maxConcurrency?: number;
118
192
  }
119
193
 
120
- // ============================================================================
121
- // Antigravity Manager Export Types
122
- // ============================================================================
123
-
124
- /**
125
- * Single entry in AM export file (from app export button)
126
- * Format: [{ "email": "...", "refresh_token": "..." }, ...]
127
- */
128
- export interface AMExportEntry {
129
- email: string;
130
- refresh_token: string;
194
+ export interface HealthOAuthConfig {
195
+ clientId?: string;
196
+ clientSecret?: string;
197
+ tokenEndpoint?: string;
131
198
  }
132
199
 
133
- /**
134
- * Type guard to check if data is an AM export file
135
- */
136
- export function isAMExportFile(data: unknown): data is AMExportEntry[] {
137
- if (!Array.isArray(data)) return false;
138
- if (data.length === 0) return true;
139
-
140
- const sample = data.slice(0, 3);
141
- return sample.every(item =>
142
- typeof item === "object" &&
143
- item !== null &&
144
- typeof (item as Record<string, unknown>).email === "string" &&
145
- typeof (item as Record<string, unknown>).refresh_token === "string"
146
- );
200
+ export interface HealthConfig {
201
+ settings?: HealthSettings;
202
+ oauth?: HealthOAuthConfig;
203
+ cache?: Record<string, AccountHealthResult>;
147
204
  }
148
-
149
- // ============================================================================
150
- // Import Source Detection
151
- // ============================================================================
152
-
153
- export type ImportFileType =
154
- | "encrypted" // .ocam encrypted file
155
- | "portable" // opencode-account-manager plain export
156
- | "am-export" // Antigravity Manager app export
157
- | "plugin-native" // antigravity-accounts.json format
158
- | "unknown";