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.
- package/README.md +235 -216
- package/README_VI.md +235 -216
- package/dist/cli.js +83 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/config-store.d.ts +12 -0
- package/dist/core/config-store.d.ts.map +1 -1
- package/dist/core/config-store.js +98 -0
- package/dist/core/config-store.js.map +1 -1
- package/dist/core/health-log.d.ts +9 -0
- package/dist/core/health-log.d.ts.map +1 -0
- package/dist/core/health-log.js +154 -0
- package/dist/core/health-log.js.map +1 -0
- package/dist/core/health-oauth.d.ts +5 -0
- package/dist/core/health-oauth.d.ts.map +1 -0
- package/dist/core/health-oauth.js +147 -0
- package/dist/core/health-oauth.js.map +1 -0
- package/dist/core/health-orchestrator.d.ts +32 -0
- package/dist/core/health-orchestrator.d.ts.map +1 -0
- package/dist/core/health-orchestrator.js +148 -0
- package/dist/core/health-orchestrator.js.map +1 -0
- package/dist/core/health-utils.d.ts +15 -0
- package/dist/core/health-utils.d.ts.map +1 -0
- package/dist/core/health-utils.js +60 -0
- package/dist/core/health-utils.js.map +1 -0
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +4 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/tui/Dashboard.d.ts.map +1 -1
- package/dist/tui/Dashboard.js +69 -2
- package/dist/tui/Dashboard.js.map +1 -1
- package/dist/tui/components/AccountList.d.ts +5 -3
- package/dist/tui/components/AccountList.d.ts.map +1 -1
- package/dist/tui/components/AccountList.js +9 -3
- package/dist/tui/components/AccountList.js.map +1 -1
- package/dist/tui/components/DashboardView.d.ts +3 -2
- package/dist/tui/components/DashboardView.d.ts.map +1 -1
- package/dist/tui/components/DashboardView.js +102 -17
- package/dist/tui/components/DashboardView.js.map +1 -1
- package/dist/tui/components/HealthBadge.d.ts +9 -0
- package/dist/tui/components/HealthBadge.d.ts.map +1 -0
- package/dist/tui/components/HealthBadge.js +56 -0
- package/dist/tui/components/HealthBadge.js.map +1 -0
- package/dist/tui/components/StatusBadge.d.ts +2 -1
- package/dist/tui/components/StatusBadge.d.ts.map +1 -1
- package/dist/tui/components/StatusBadge.js +30 -2
- package/dist/tui/components/StatusBadge.js.map +1 -1
- package/dist/tui/components/index.d.ts +1 -0
- package/dist/tui/components/index.d.ts.map +1 -1
- package/dist/tui/components/index.js +3 -1
- package/dist/tui/components/index.js.map +1 -1
- package/docs/BLUEPRINT.md +476 -476
- package/docs/ROADMAP.md +125 -107
- package/package.json +38 -38
- package/src/cli.ts +139 -38
- package/src/core/config-store.ts +278 -171
- package/src/core/crypto.ts +162 -162
- package/src/core/health-log.ts +173 -0
- package/src/core/health-oauth.ts +190 -0
- package/src/core/health-orchestrator.ts +224 -0
- package/src/core/importers/amExport.ts +177 -177
- package/src/core/opencode-config.ts +217 -217
- package/src/core/paths.ts +10 -6
- package/src/core/types.ts +193 -147
- package/src/tui/Dashboard.tsx +557 -478
- package/src/tui/components/AccountList.tsx +122 -104
- package/src/tui/components/ActionPalette.tsx +117 -117
- package/src/tui/components/Box.tsx +7 -7
- package/src/tui/components/DashboardView.tsx +324 -220
- package/src/tui/components/ExportModal.tsx +255 -255
- package/src/tui/components/FileBrowser.tsx +393 -393
- package/src/tui/components/Header.tsx +26 -26
- package/src/tui/components/HealthBadge.tsx +64 -0
- package/src/tui/components/ImportModal.tsx +334 -334
- package/src/tui/components/McpServerList.tsx +67 -67
- package/src/tui/components/Menu.tsx +61 -61
- package/src/tui/components/PasswordInput.tsx +159 -159
- package/src/tui/components/ProviderList.tsx +59 -59
- package/src/tui/components/SectionBox.tsx +35 -35
- package/src/tui/components/StatsRow.tsx +33 -33
- package/src/tui/components/StatusBadge.tsx +36 -3
- package/src/tui/components/index.ts +15 -14
- package/test-minimal.js +26 -26
- 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
|
-
//
|
|
161
|
+
// Account Health Types
|
|
101
162
|
// ============================================================================
|
|
102
163
|
|
|
103
|
-
export type
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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";
|