opencode-account-manager 0.4.1

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 (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +183 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/accounts.d.ts +19 -0
  8. package/dist/core/accounts.d.ts.map +1 -0
  9. package/dist/core/accounts.js +181 -0
  10. package/dist/core/accounts.js.map +1 -0
  11. package/dist/core/config-store.d.ts +48 -0
  12. package/dist/core/config-store.d.ts.map +1 -0
  13. package/dist/core/config-store.js +206 -0
  14. package/dist/core/config-store.js.map +1 -0
  15. package/dist/core/crypto.d.ts +40 -0
  16. package/dist/core/crypto.d.ts.map +1 -0
  17. package/dist/core/crypto.js +172 -0
  18. package/dist/core/crypto.js.map +1 -0
  19. package/dist/core/importers/amJson.d.ts +17 -0
  20. package/dist/core/importers/amJson.d.ts.map +1 -0
  21. package/dist/core/importers/amJson.js +131 -0
  22. package/dist/core/importers/amJson.js.map +1 -0
  23. package/dist/core/opencode-config.d.ts +92 -0
  24. package/dist/core/opencode-config.d.ts.map +1 -0
  25. package/dist/core/opencode-config.js +148 -0
  26. package/dist/core/opencode-config.js.map +1 -0
  27. package/dist/core/paths.d.ts +5 -0
  28. package/dist/core/paths.d.ts.map +1 -0
  29. package/dist/core/paths.js +38 -0
  30. package/dist/core/paths.js.map +1 -0
  31. package/dist/core/types.d.ts +74 -0
  32. package/dist/core/types.d.ts.map +1 -0
  33. package/dist/core/types.js +30 -0
  34. package/dist/core/types.js.map +1 -0
  35. package/dist/core/utils.d.ts +5 -0
  36. package/dist/core/utils.d.ts.map +1 -0
  37. package/dist/core/utils.js +35 -0
  38. package/dist/core/utils.js.map +1 -0
  39. package/dist/tui/Dashboard.d.ts +7 -0
  40. package/dist/tui/Dashboard.d.ts.map +1 -0
  41. package/dist/tui/Dashboard.js +331 -0
  42. package/dist/tui/Dashboard.js.map +1 -0
  43. package/dist/tui/components/AccountList.d.ts +18 -0
  44. package/dist/tui/components/AccountList.d.ts.map +1 -0
  45. package/dist/tui/components/AccountList.js +92 -0
  46. package/dist/tui/components/AccountList.js.map +1 -0
  47. package/dist/tui/components/Box.d.ts +11 -0
  48. package/dist/tui/components/Box.d.ts.map +1 -0
  49. package/dist/tui/components/Box.js +15 -0
  50. package/dist/tui/components/Box.js.map +1 -0
  51. package/dist/tui/components/ExportModal.d.ts +10 -0
  52. package/dist/tui/components/ExportModal.d.ts.map +1 -0
  53. package/dist/tui/components/ExportModal.js +192 -0
  54. package/dist/tui/components/ExportModal.js.map +1 -0
  55. package/dist/tui/components/FileBrowser.d.ts +12 -0
  56. package/dist/tui/components/FileBrowser.d.ts.map +1 -0
  57. package/dist/tui/components/FileBrowser.js +349 -0
  58. package/dist/tui/components/FileBrowser.js.map +1 -0
  59. package/dist/tui/components/Header.d.ts +8 -0
  60. package/dist/tui/components/Header.d.ts.map +1 -0
  61. package/dist/tui/components/Header.js +20 -0
  62. package/dist/tui/components/Header.js.map +1 -0
  63. package/dist/tui/components/ImportModal.d.ts +10 -0
  64. package/dist/tui/components/ImportModal.d.ts.map +1 -0
  65. package/dist/tui/components/ImportModal.js +215 -0
  66. package/dist/tui/components/ImportModal.js.map +1 -0
  67. package/dist/tui/components/McpServerList.d.ts +8 -0
  68. package/dist/tui/components/McpServerList.d.ts.map +1 -0
  69. package/dist/tui/components/McpServerList.js +35 -0
  70. package/dist/tui/components/McpServerList.js.map +1 -0
  71. package/dist/tui/components/Menu.d.ts +10 -0
  72. package/dist/tui/components/Menu.d.ts.map +1 -0
  73. package/dist/tui/components/Menu.js +83 -0
  74. package/dist/tui/components/Menu.js.map +1 -0
  75. package/dist/tui/components/PasswordInput.d.ts +12 -0
  76. package/dist/tui/components/PasswordInput.d.ts.map +1 -0
  77. package/dist/tui/components/PasswordInput.js +130 -0
  78. package/dist/tui/components/PasswordInput.js.map +1 -0
  79. package/dist/tui/components/ProviderList.d.ts +8 -0
  80. package/dist/tui/components/ProviderList.d.ts.map +1 -0
  81. package/dist/tui/components/ProviderList.js +37 -0
  82. package/dist/tui/components/ProviderList.js.map +1 -0
  83. package/dist/tui/components/SectionBox.d.ts +10 -0
  84. package/dist/tui/components/SectionBox.d.ts.map +1 -0
  85. package/dist/tui/components/SectionBox.js +16 -0
  86. package/dist/tui/components/SectionBox.js.map +1 -0
  87. package/dist/tui/components/StatsRow.d.ts +13 -0
  88. package/dist/tui/components/StatsRow.d.ts.map +1 -0
  89. package/dist/tui/components/StatsRow.js +18 -0
  90. package/dist/tui/components/StatsRow.js.map +1 -0
  91. package/dist/tui/components/StatusBadge.d.ts +8 -0
  92. package/dist/tui/components/StatusBadge.d.ts.map +1 -0
  93. package/dist/tui/components/StatusBadge.js +30 -0
  94. package/dist/tui/components/StatusBadge.js.map +1 -0
  95. package/dist/tui/components/index.d.ts +14 -0
  96. package/dist/tui/components/index.d.ts.map +1 -0
  97. package/dist/tui/components/index.js +32 -0
  98. package/dist/tui/components/index.js.map +1 -0
  99. package/dist/tui/index.d.ts +5 -0
  100. package/dist/tui/index.d.ts.map +1 -0
  101. package/dist/tui/index.js +13 -0
  102. package/dist/tui/index.js.map +1 -0
  103. package/docs/BLUEPRINT.md +476 -0
  104. package/docs/ROADMAP.md +74 -0
  105. package/package.json +38 -0
  106. package/src/cli.ts +207 -0
  107. package/src/core/accounts.ts +215 -0
  108. package/src/core/config-store.ts +212 -0
  109. package/src/core/crypto.ts +162 -0
  110. package/src/core/importers/amJson.ts +185 -0
  111. package/src/core/opencode-config.ts +217 -0
  112. package/src/core/paths.ts +32 -0
  113. package/src/core/types.ts +118 -0
  114. package/src/core/utils.ts +28 -0
  115. package/src/tui/Dashboard.tsx +431 -0
  116. package/src/tui/components/AccountList.tsx +155 -0
  117. package/src/tui/components/Box.tsx +37 -0
  118. package/src/tui/components/ExportModal.tsx +255 -0
  119. package/src/tui/components/FileBrowser.tsx +393 -0
  120. package/src/tui/components/Header.tsx +26 -0
  121. package/src/tui/components/ImportModal.tsx +288 -0
  122. package/src/tui/components/McpServerList.tsx +67 -0
  123. package/src/tui/components/Menu.tsx +103 -0
  124. package/src/tui/components/PasswordInput.tsx +159 -0
  125. package/src/tui/components/ProviderList.tsx +61 -0
  126. package/src/tui/components/SectionBox.tsx +35 -0
  127. package/src/tui/components/StatsRow.tsx +33 -0
  128. package/src/tui/components/StatusBadge.tsx +33 -0
  129. package/src/tui/components/index.ts +13 -0
  130. package/src/tui/index.tsx +11 -0
  131. package/tsconfig.json +20 -0
@@ -0,0 +1,476 @@
1
+ # OpenCode Account Manager - Blueprint v0.4.0
2
+
3
+ ## Overview
4
+
5
+ Technical specification for the **Encrypted Export/Import** feature.
6
+
7
+ ---
8
+
9
+ ## 1. Architecture
10
+
11
+ ```
12
+ ┌─────────────────────────────────────────────────────────────────────────┐
13
+ │ TUI Layer │
14
+ ├─────────────────────────────────────────────────────────────────────────┤
15
+ │ Dashboard.tsx │
16
+ │ ├── ExportModal.tsx (format selection → folder → password → save) │
17
+ │ ├── ImportModal.tsx (file selection → password → preview → import) │
18
+ │ └── Components: │
19
+ │ ├── FileBrowser.tsx (folder/file selection UI) │
20
+ │ ├── PasswordInput.tsx (masked password input) │
21
+ │ └── FormatSelector.tsx (encrypted vs plain) │
22
+ ├─────────────────────────────────────────────────────────────────────────┤
23
+ │ Core Layer │
24
+ ├─────────────────────────────────────────────────────────────────────────┤
25
+ │ crypto.ts - AES-256-GCM encryption/decryption │
26
+ │ config-store.ts - Persist user preferences (last folder, etc.) │
27
+ │ accounts.ts - Extended with encrypt/decrypt functions │
28
+ │ types.ts - New types for encrypted files │
29
+ └─────────────────────────────────────────────────────────────────────────┘
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 2. File Specifications
35
+
36
+ ### 2.1 Encrypted Export File (.ocam)
37
+
38
+ **Extension:** `.ocam` (OpenCode Account Manager)
39
+
40
+ **Structure:**
41
+ ```typescript
42
+ interface EncryptedExportFile {
43
+ // Header (not encrypted)
44
+ version: 1;
45
+ format: "encrypted";
46
+ algorithm: "aes-256-gcm";
47
+
48
+ // Encryption parameters
49
+ salt: string; // 32 bytes, hex encoded (for key derivation)
50
+ iv: string; // 12 bytes, hex encoded (initialization vector)
51
+ authTag: string; // 16 bytes, hex encoded (authentication tag)
52
+
53
+ // Encrypted payload
54
+ data: string; // Encrypted JSON, hex encoded
55
+
56
+ // Metadata (not encrypted)
57
+ exportedAt: number; // Unix timestamp ms
58
+ accountCount: number; // Number of accounts (for display)
59
+ exportedFrom: string; // App identifier
60
+ }
61
+ ```
62
+
63
+ **Example:**
64
+ ```json
65
+ {
66
+ "version": 1,
67
+ "format": "encrypted",
68
+ "algorithm": "aes-256-gcm",
69
+ "salt": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
70
+ "iv": "1234567890abcdef12345678",
71
+ "authTag": "fedcba0987654321fedcba0987654321",
72
+ "data": "encrypted_hex_data_here...",
73
+ "exportedAt": 1707123456789,
74
+ "accountCount": 5,
75
+ "exportedFrom": "opencode-account-manager"
76
+ }
77
+ ```
78
+
79
+ ### 2.2 Plain Export File (.json)
80
+
81
+ Keep existing format for backward compatibility:
82
+ ```typescript
83
+ interface PortableExportFile {
84
+ version: number;
85
+ exportedAt: number;
86
+ exportedFrom: "opencode-account-manager";
87
+ accounts: Account[];
88
+ }
89
+ ```
90
+
91
+ ### 2.3 App Config File
92
+
93
+ **Location:** `%APPDATA%/opencode/ocam-config.json` (Windows)
94
+ `~/.config/opencode/ocam-config.json` (Linux/Mac)
95
+
96
+ ```typescript
97
+ interface AppConfig {
98
+ lastExportFolder?: string;
99
+ lastImportFolder?: string;
100
+ defaultExportFormat?: "encrypted" | "plain";
101
+ recentFolders?: string[]; // Max 5 recent folders
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 3. Encryption Specification
108
+
109
+ ### 3.1 Algorithm: AES-256-GCM
110
+
111
+ - **Key Derivation:** scrypt (N=16384, r=8, p=1)
112
+ - **Key Length:** 256 bits (32 bytes)
113
+ - **Salt Length:** 256 bits (32 bytes, random)
114
+ - **IV Length:** 96 bits (12 bytes, random)
115
+ - **Auth Tag:** 128 bits (16 bytes)
116
+
117
+ ### 3.2 Encryption Flow
118
+
119
+ ```
120
+ Password (user input)
121
+
122
+
123
+ ┌───────────────────────────────────────┐
124
+ │ scrypt(password, salt, N=16384) │
125
+ │ Output: 32-byte key │
126
+ └───────────────────────────────────────┘
127
+
128
+
129
+ ┌───────────────────────────────────────┐
130
+ │ AES-256-GCM.encrypt( │
131
+ │ key: derived_key, │
132
+ │ iv: random_12_bytes, │
133
+ │ plaintext: JSON.stringify(data), │
134
+ │ aad: none │
135
+ │ ) │
136
+ │ Output: ciphertext + authTag │
137
+ └───────────────────────────────────────┘
138
+
139
+
140
+ { salt, iv, authTag, data: ciphertext }
141
+ ```
142
+
143
+ ### 3.3 Decryption Flow
144
+
145
+ ```
146
+ { salt, iv, authTag, data } + Password
147
+
148
+
149
+ ┌───────────────────────────────────────┐
150
+ │ scrypt(password, salt, N=16384) │
151
+ │ Output: 32-byte key │
152
+ └───────────────────────────────────────┘
153
+
154
+
155
+ ┌───────────────────────────────────────┐
156
+ │ AES-256-GCM.decrypt( │
157
+ │ key: derived_key, │
158
+ │ iv: iv, │
159
+ │ ciphertext: data, │
160
+ │ authTag: authTag │
161
+ │ ) │
162
+ │ Output: plaintext (or throw error) │
163
+ └───────────────────────────────────────┘
164
+
165
+
166
+ JSON.parse(plaintext) → Account[]
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 4. UI Components
172
+
173
+ ### 4.1 ExportModal
174
+
175
+ **States:**
176
+ 1. `format-select` - Choose encrypted or plain
177
+ 2. `folder-select` - Choose destination folder
178
+ 3. `password-input` - Enter password (only for encrypted)
179
+ 4. `exporting` - Show progress
180
+ 5. `success` - Show result
181
+ 6. `error` - Show error message
182
+
183
+ **Props:**
184
+ ```typescript
185
+ interface ExportModalProps {
186
+ accounts: Account[];
187
+ onComplete: (filePath: string) => void;
188
+ onCancel: () => void;
189
+ }
190
+ ```
191
+
192
+ ### 4.2 ImportModal
193
+
194
+ **States:**
195
+ 1. `file-select` - Choose file to import
196
+ 2. `password-input` - Enter password (only for .ocam)
197
+ 3. `preview` - Show accounts to import with conflict info
198
+ 4. `importing` - Show progress
199
+ 5. `success` - Show result
200
+ 6. `error` - Show error message
201
+
202
+ **Props:**
203
+ ```typescript
204
+ interface ImportModalProps {
205
+ existingAccounts: Account[];
206
+ onComplete: (imported: number, overwritten: number) => void;
207
+ onCancel: () => void;
208
+ }
209
+ ```
210
+
211
+ ### 4.3 FileBrowser
212
+
213
+ **Features:**
214
+ - Quick locations (Current Dir, Desktop, Documents, Recent)
215
+ - Folder navigation with arrow keys
216
+ - Text input for pasting path
217
+ - Filter by extension (for import)
218
+ - Show file metadata (size, date, encrypted/plain)
219
+
220
+ **Props:**
221
+ ```typescript
222
+ interface FileBrowserProps {
223
+ mode: "folder" | "file";
224
+ initialPath?: string;
225
+ extensions?: string[]; // e.g., [".ocam", ".json"]
226
+ onSelect: (path: string) => void;
227
+ onCancel: () => void;
228
+ }
229
+ ```
230
+
231
+ ### 4.4 PasswordInput
232
+
233
+ **Features:**
234
+ - Masked input (show dots)
235
+ - Optional confirmation field (for export)
236
+ - Password mismatch warning
237
+ - Enter to submit, Escape to cancel
238
+
239
+ **Props:**
240
+ ```typescript
241
+ interface PasswordInputProps {
242
+ mode: "single" | "confirm";
243
+ title?: string;
244
+ warning?: string;
245
+ onSubmit: (password: string) => void;
246
+ onCancel: () => void;
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 5. User Flows
253
+
254
+ ### 5.1 Export Flow
255
+
256
+ ```
257
+ [E] pressed
258
+
259
+
260
+ ┌─────────────────────────────────┐
261
+ │ Select export format: │
262
+ │ [1] Encrypted (.ocam) │
263
+ │ [2] Plain JSON │
264
+ └─────────────────────────────────┘
265
+
266
+ ├─── [1] ──────────────────────────────────────┐
267
+ │ │
268
+ ▼ ▼
269
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
270
+ │ Select folder │ │ Select folder │
271
+ │ (FileBrowser mode="folder") │ │ (FileBrowser mode="folder") │
272
+ └─────────────────────────────────┘ └─────────────────────────────────┘
273
+ │ │
274
+ ▼ ▼
275
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
276
+ │ Enter password │ │ Save file │
277
+ │ (PasswordInput mode="confirm") │ │ filename: accounts-{date}.json │
278
+ └─────────────────────────────────┘ └─────────────────────────────────┘
279
+ │ │
280
+ ▼ ▼
281
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
282
+ │ Encrypt & Save │ │ Success message │
283
+ │ filename: accounts-{date}.ocam │ └─────────────────────────────────┘
284
+ └─────────────────────────────────┘
285
+
286
+
287
+ ┌─────────────────────────────────┐
288
+ │ Success message │
289
+ └─────────────────────────────────┘
290
+ ```
291
+
292
+ ### 5.2 Import Flow
293
+
294
+ ```
295
+ [I] pressed
296
+
297
+
298
+ ┌─────────────────────────────────┐
299
+ │ Select file │
300
+ │ (FileBrowser mode="file") │
301
+ │ extensions: [".ocam", ".json"] │
302
+ └─────────────────────────────────┘
303
+
304
+ ├─── .ocam ────────────────────────────────────┐
305
+ │ │
306
+ ▼ ▼
307
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
308
+ │ Enter password │ │ .json file │
309
+ │ (PasswordInput mode="single") │ │ Parse directly │
310
+ └─────────────────────────────────┘ └─────────────────────────────────┘
311
+ │ │
312
+ ├─── Wrong password ───┐ │
313
+ │ ▼ │
314
+ │ ┌─────────────────────────────────┐ │
315
+ │ │ Error: Invalid password │ │
316
+ │ │ [Try again] [Cancel] │ │
317
+ │ └─────────────────────────────────┘ │
318
+ │ │
319
+ ▼ ▼
320
+ ┌─────────────────────────────────────────────────────────────┐
321
+ │ Preview accounts │
322
+ │ Show: email, exists? (will overwrite) │
323
+ │ [Enter] Import [Esc] Cancel │
324
+ └─────────────────────────────────────────────────────────────┘
325
+
326
+
327
+ ┌─────────────────────────────────┐
328
+ │ Import accounts (overwrite) │
329
+ └─────────────────────────────────┘
330
+
331
+
332
+ ┌─────────────────────────────────┐
333
+ │ Success: X imported, Y new │
334
+ └─────────────────────────────────┘
335
+ ```
336
+
337
+ ---
338
+
339
+ ## 6. Implementation Checklist
340
+
341
+ ### Core Layer
342
+ - [ ] `src/core/crypto.ts`
343
+ - [ ] `generateSalt(): string`
344
+ - [ ] `generateIV(): string`
345
+ - [ ] `deriveKey(password: string, salt: string): Buffer`
346
+ - [ ] `encrypt(data: object, password: string): EncryptedData`
347
+ - [ ] `decrypt(encrypted: EncryptedData, password: string): object`
348
+
349
+ - [ ] `src/core/config-store.ts`
350
+ - [ ] `getConfigPath(): string`
351
+ - [ ] `readConfig(): AppConfig`
352
+ - [ ] `writeConfig(config: AppConfig): void`
353
+ - [ ] `updateLastExportFolder(folder: string): void`
354
+ - [ ] `updateLastImportFolder(folder: string): void`
355
+ - [ ] `getRecentFolders(): string[]`
356
+
357
+ - [ ] `src/core/types.ts`
358
+ - [ ] `EncryptedExportFile` interface
359
+ - [ ] `AppConfig` interface
360
+ - [ ] Update `PortableExportFile.exportedFrom`
361
+
362
+ - [ ] `src/core/accounts.ts`
363
+ - [ ] `encryptAndExport(accounts: Account[], password: string): EncryptedExportFile`
364
+ - [ ] `decryptAndImport(file: EncryptedExportFile, password: string): Account[]`
365
+ - [ ] `isEncryptedFile(data: unknown): boolean`
366
+
367
+ ### TUI Layer
368
+ - [ ] `src/tui/components/PasswordInput.tsx`
369
+ - [ ] Masked input display
370
+ - [ ] Confirm mode (two fields)
371
+ - [ ] Mismatch warning
372
+ - [ ] Enter/Escape handling
373
+
374
+ - [ ] `src/tui/components/FileBrowser.tsx`
375
+ - [ ] Quick locations list
376
+ - [ ] Folder navigation
377
+ - [ ] Text input for path
378
+ - [ ] File filtering by extension
379
+ - [ ] File metadata display
380
+
381
+ - [ ] `src/tui/components/ExportModal.tsx`
382
+ - [ ] Format selection step
383
+ - [ ] Folder selection step
384
+ - [ ] Password input step
385
+ - [ ] Export execution
386
+ - [ ] Success/Error display
387
+
388
+ - [ ] `src/tui/components/ImportModal.tsx`
389
+ - [ ] File selection step
390
+ - [ ] Password input step (if encrypted)
391
+ - [ ] Preview with conflict detection
392
+ - [ ] Import execution
393
+ - [ ] Success/Error display
394
+
395
+ - [ ] `src/tui/Dashboard.tsx`
396
+ - [ ] Modal state management
397
+ - [ ] Export handler
398
+ - [ ] Import handler
399
+
400
+ - [ ] `src/tui/components/Menu.tsx`
401
+ - [ ] Update export action
402
+ - [ ] Update import action
403
+
404
+ - [ ] `src/tui/components/index.ts`
405
+ - [ ] Export new components
406
+
407
+ ---
408
+
409
+ ## 7. Testing
410
+
411
+ ### Manual Test Cases
412
+
413
+ 1. **Export Encrypted**
414
+ - Export 5 accounts with password "test123"
415
+ - Verify .ocam file created
416
+ - Verify file content is encrypted (not readable)
417
+
418
+ 2. **Import Encrypted**
419
+ - Import the exported .ocam file
420
+ - Enter correct password → success
421
+ - Enter wrong password → error with retry option
422
+
423
+ 3. **Export Plain**
424
+ - Export 5 accounts as plain JSON
425
+ - Verify .json file created
426
+ - Verify accounts are readable in file
427
+
428
+ 4. **Import Plain**
429
+ - Import a plain .json file
430
+ - No password required
431
+ - Accounts imported successfully
432
+
433
+ 5. **Overwrite Existing**
434
+ - Export 3 accounts
435
+ - Modify 1 account locally
436
+ - Import the file
437
+ - Verify the account is overwritten
438
+
439
+ 6. **Remember Folder**
440
+ - Export to custom folder
441
+ - Close and reopen app
442
+ - Export again → should show last folder as recent
443
+
444
+ ---
445
+
446
+ ## 8. Security Considerations
447
+
448
+ 1. **Password not stored** - Never save password to disk
449
+ 2. **Memory cleanup** - Clear password from memory after use
450
+ 3. **Auth tag verification** - Detect tampered files
451
+ 4. **No password hints** - Don't store any password metadata
452
+ 5. **Salt per file** - Each export uses unique salt
453
+ 6. **Warning on plain export** - Show security warning
454
+
455
+ ---
456
+
457
+ ## 9. Error Handling
458
+
459
+ | Error | User Message |
460
+ |-------|--------------|
461
+ | Wrong password | "Invalid password. Please try again." |
462
+ | Corrupted file | "File is corrupted or invalid format." |
463
+ | File not found | "File not found: {path}" |
464
+ | Permission denied | "Cannot write to folder: {path}" |
465
+ | Disk full | "Not enough disk space." |
466
+ | Invalid JSON | "Invalid file format." |
467
+
468
+ ---
469
+
470
+ ## 10. Dependencies
471
+
472
+ No new npm packages required. Using Node.js built-in:
473
+ - `crypto` - AES-256-GCM, scrypt
474
+ - `fs` - File operations
475
+ - `path` - Path manipulation
476
+ - `os` - Home directory, platform detection
@@ -0,0 +1,74 @@
1
+ # OpenCode Account Manager - Roadmap
2
+
3
+ ## Version History
4
+
5
+ ### v0.1.0 - Initial Release
6
+ - [x] Basic TUI dashboard
7
+ - [x] View accounts from antigravity-auth plugin
8
+ - [x] Show rate limit status per account
9
+ - [x] Import from Antigravity Manager folder
10
+
11
+ ### v0.2.0 - Account Management
12
+ - [x] Select mode with keyboard navigation
13
+ - [x] Enable/Disable selected accounts
14
+ - [x] Delete selected accounts
15
+ - [x] Export selected accounts to JSON
16
+ - [x] Per-model rate limit display (claude, gemini, etc.)
17
+
18
+ ### v0.3.0 - OpenCode Dashboard
19
+ - [x] Rename to opencode-account-manager
20
+ - [x] Read opencode.json config
21
+ - [x] Display all AI providers with model counts
22
+ - [x] Display MCP servers with enabled/disabled status
23
+ - [x] Tab navigation between sections (Providers, Accounts, MCP)
24
+ - [x] Collapsible sections
25
+
26
+ ### v0.4.0 - Encrypted Export/Import (Current)
27
+ - [ ] **Encrypted Export** - AES-256-GCM with password protection
28
+ - [ ] **Plain JSON Export** - Keep original format as option
29
+ - [ ] **File Browser UI** - Browse folders, quick locations, paste path
30
+ - [ ] **Import from File** - Select .ocam or .json files
31
+ - [ ] **Password Input** - Masked input with confirmation
32
+ - [ ] **Remember Preferences** - Last export/import folder saved
33
+ - [ ] **Overwrite Mode** - Replace existing accounts on import
34
+
35
+ ---
36
+
37
+ ## Future Ideas (Backlog)
38
+
39
+ ### v0.5.0 - Enhanced Security
40
+ - [ ] Password strength indicator
41
+ - [ ] Auto-lock after inactivity
42
+ - [ ] Encrypted storage for config
43
+
44
+ ### v0.6.0 - Cloud Sync
45
+ - [ ] Sync accounts to cloud storage (Google Drive, Dropbox)
46
+ - [ ] Multi-device sync
47
+ - [ ] Conflict resolution
48
+
49
+ ### v0.7.0 - Account Health
50
+ - [ ] Check if refresh tokens are still valid
51
+ - [ ] Auto-refresh expired tokens
52
+ - [ ] Health check on startup
53
+
54
+ ### v0.8.0 - MCP Management
55
+ - [ ] Enable/Disable MCP servers from TUI
56
+ - [ ] Add new MCP servers
57
+ - [ ] View MCP server logs
58
+
59
+ ### v0.9.0 - Provider Management
60
+ - [ ] Add/Edit custom providers
61
+ - [ ] Test provider connection
62
+ - [ ] Model usage statistics
63
+
64
+ ### v1.0.0 - Stable Release
65
+ - [ ] Full documentation
66
+ - [ ] npm publish
67
+ - [ ] Windows/Mac/Linux installers
68
+ - [ ] Integration tests
69
+
70
+ ---
71
+
72
+ ## Contributing
73
+
74
+ See [BLUEPRINT.md](./BLUEPRINT.md) for technical architecture and implementation details.
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "opencode-account-manager",
3
+ "version": "0.4.1",
4
+ "description": "TUI Dashboard for OpenCode - View providers, MCP servers, and plugin accounts",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "ocam": "./dist/cli.js",
8
+ "opencode-account-manager": "./dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "npx tsc",
12
+ "dev": "npx tsc -w",
13
+ "start": "node dist/cli.js",
14
+ "dashboard": "node dist/cli.js dashboard"
15
+ },
16
+ "keywords": [
17
+ "opencode",
18
+ "antigravity",
19
+ "account-manager",
20
+ "dashboard",
21
+ "tui",
22
+ "mcp",
23
+ "providers"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "@types/node": "^20.10.0",
29
+ "@types/react": "^17.0.0",
30
+ "typescript": "^5.3.0"
31
+ },
32
+ "dependencies": {
33
+ "chalk": "^4.1.2",
34
+ "commander": "^11.1.0",
35
+ "ink": "^3.2.0",
36
+ "react": "^17.0.2"
37
+ }
38
+ }