forked from NoeFabris/opencode-antigravity-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauth-menu.ts
More file actions
143 lines (119 loc) · 5.2 KB
/
Copy pathauth-menu.ts
File metadata and controls
143 lines (119 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { ANSI } from './ansi';
import { select, type MenuItem } from './select';
import { confirm } from './confirm';
export type AccountStatus = 'active' | 'rate-limited' | 'expired' | 'verification-required' | 'unknown';
export interface AccountInfo {
email?: string;
index: number;
addedAt?: number;
lastUsed?: number;
status?: AccountStatus;
isCurrentAccount?: boolean;
enabled?: boolean;
}
export type AuthMenuAction =
| { type: 'add' }
| { type: 'select-account'; account: AccountInfo }
| { type: 'delete-all' }
| { type: 'check' }
| { type: 'verify' }
| { type: 'verify-all' }
| { type: 'configure-models' }
| { type: 'cancel' };
export type AccountAction = 'back' | 'delete' | 'refresh' | 'toggle' | 'verify' | 'cancel';
function formatRelativeTime(timestamp: number | undefined): string {
if (!timestamp) return 'never';
const days = Math.floor((Date.now() - timestamp) / 86400000);
if (days === 0) return 'today';
if (days === 1) return 'yesterday';
if (days < 7) return `${days}d ago`;
if (days < 30) return `${Math.floor(days / 7)}w ago`;
return new Date(timestamp).toLocaleDateString();
}
function formatDate(timestamp: number | undefined): string {
if (!timestamp) return 'unknown';
return new Date(timestamp).toLocaleDateString();
}
function getStatusBadge(status: AccountStatus | undefined): string {
switch (status) {
case 'active': return `${ANSI.green}[active]${ANSI.reset}`;
case 'rate-limited': return `${ANSI.yellow}[rate-limited]${ANSI.reset}`;
case 'expired': return `${ANSI.red}[expired]${ANSI.reset}`;
case 'verification-required': return `${ANSI.red}[needs verification]${ANSI.reset}`;
default: return '';
}
}
export async function showAuthMenu(accounts: AccountInfo[]): Promise<AuthMenuAction> {
const items: MenuItem<AuthMenuAction>[] = [
{ label: 'Actions', value: { type: 'cancel' }, kind: 'heading' },
{ label: 'Add account', value: { type: 'add' }, color: 'cyan' },
{ label: 'Check quotas', value: { type: 'check' }, color: 'cyan' },
{ label: 'Verify one account', value: { type: 'verify' }, color: 'cyan' },
{ label: 'Verify all accounts', value: { type: 'verify-all' }, color: 'cyan' },
{ label: 'Configure models in opencode.json', value: { type: 'configure-models' }, color: 'cyan' },
{ label: '', value: { type: 'cancel' }, separator: true },
{ label: 'Accounts', value: { type: 'cancel' }, kind: 'heading' },
...accounts.map(account => {
const statusBadge = getStatusBadge(account.status);
const currentBadge = account.isCurrentAccount ? ` ${ANSI.cyan}[current]${ANSI.reset}` : '';
const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : '';
const baseLabel = account.email || `Account ${account.index + 1}`;
const numbered = `${account.index + 1}. ${baseLabel}`;
const fullLabel = `${numbered}${currentBadge}${statusBadge ? ' ' + statusBadge : ''}${disabledBadge}`;
return {
label: fullLabel,
hint: account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : '',
value: { type: 'select-account' as const, account },
};
}),
{ label: '', value: { type: 'cancel' }, separator: true },
{ label: 'Danger zone', value: { type: 'cancel' }, kind: 'heading' },
{ label: 'Delete all accounts', value: { type: 'delete-all' }, color: 'red' as const },
];
while (true) {
const result = await select(items, {
message: 'Google accounts (Antigravity)',
subtitle: 'Select an action or account',
clearScreen: true,
});
if (!result) return { type: 'cancel' };
if (result.type === 'delete-all') {
const confirmed = await confirm('Delete ALL accounts? This cannot be undone.');
if (!confirmed) continue;
}
return result;
}
}
export async function showAccountDetails(account: AccountInfo): Promise<AccountAction> {
const label = account.email || `Account ${account.index + 1}`;
const badge = getStatusBadge(account.status);
const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : '';
const header = `${label}${badge ? ' ' + badge : ''}${disabledBadge}`;
const subtitleParts = [
`Added: ${formatDate(account.addedAt)}`,
`Last used: ${formatRelativeTime(account.lastUsed)}`,
];
while (true) {
const result = await select([
{ label: 'Back', value: 'back' as const },
{ label: 'Verify account access', value: 'verify' as const, color: 'cyan' },
{ label: account.enabled === false ? 'Enable account' : 'Disable account', value: 'toggle' as const, color: account.enabled === false ? 'green' : 'yellow' },
{ label: 'Refresh token', value: 'refresh' as const, color: 'cyan' },
{ label: 'Delete this account', value: 'delete' as const, color: 'red' },
], {
message: header,
subtitle: subtitleParts.join(' | '),
clearScreen: true,
});
if (result === 'delete') {
const confirmed = await confirm(`Delete ${label}?`);
if (!confirmed) continue;
}
if (result === 'refresh') {
const confirmed = await confirm(`Re-authenticate ${label}?`);
if (!confirmed) continue;
}
return result ?? 'cancel';
}
}
export { isTTY } from './ansi';