ethagent 0.2.1 → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +114 -32
- package/bin/ethagent.js +11 -2
- package/package.json +25 -7
- package/src/app/FirstRun.tsx +412 -0
- package/src/app/hooks/useCancelRequest.ts +22 -0
- package/src/app/hooks/useDoublePress.ts +46 -0
- package/src/app/hooks/useExitOnCtrlC.ts +36 -0
- package/src/app/input/AppInputProvider.tsx +116 -0
- package/src/app/input/appInputParser.ts +279 -0
- package/src/app/keybindings/KeybindingProvider.tsx +134 -0
- package/src/app/keybindings/resolver.ts +42 -0
- package/src/app/keybindings/types.ts +26 -0
- package/src/chat/ChatBottomPane.tsx +280 -0
- package/src/chat/ChatInput.tsx +722 -0
- package/src/chat/ChatScreen.tsx +1575 -0
- package/src/chat/ContextLimitView.tsx +95 -0
- package/src/chat/ContinuityEditReviewView.tsx +48 -0
- package/src/chat/ConversationStack.tsx +47 -0
- package/src/chat/CopyPicker.tsx +52 -0
- package/src/chat/MessageList.tsx +609 -0
- package/src/chat/PermissionPrompt.tsx +153 -0
- package/src/chat/PermissionsView.tsx +159 -0
- package/src/chat/PlanApprovalView.tsx +91 -0
- package/src/chat/ResumeView.tsx +267 -0
- package/src/chat/RewindView.tsx +386 -0
- package/src/chat/SessionStatus.tsx +51 -0
- package/src/chat/TranscriptView.tsx +202 -0
- package/src/chat/chatInputState.ts +247 -0
- package/src/chat/chatPaste.ts +49 -0
- package/src/chat/chatScreenUtils.ts +187 -0
- package/src/chat/chatSessionState.ts +142 -0
- package/src/chat/chatTurnOrchestrator.ts +701 -0
- package/src/chat/commands.ts +673 -0
- package/src/chat/textCursor.ts +202 -0
- package/src/chat/toolResultDisplay.ts +8 -0
- package/src/chat/transcriptViewport.ts +247 -0
- package/src/cli/ResetConfirmView.tsx +61 -0
- package/src/cli/main.tsx +177 -0
- package/src/cli/preview.tsx +19 -0
- package/src/cli/reset.ts +106 -0
- package/src/identity/continuity/editor.ts +149 -0
- package/src/identity/continuity/envelope.ts +345 -0
- package/src/identity/continuity/history.ts +153 -0
- package/src/identity/continuity/privateEdit.ts +334 -0
- package/src/identity/continuity/publicSkills.ts +173 -0
- package/src/identity/continuity/snapshots.ts +183 -0
- package/src/identity/continuity/storage.ts +507 -0
- package/src/identity/crypto/backupEnvelope.ts +486 -0
- package/src/identity/crypto/eth.ts +137 -0
- package/src/identity/hub/IdentityHub.tsx +845 -0
- package/src/identity/hub/identityHubEffects.ts +1100 -0
- package/src/identity/hub/identityHubModel.ts +291 -0
- package/src/identity/hub/identityHubReducer.ts +209 -0
- package/src/identity/hub/screens/BusyScreen.tsx +26 -0
- package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +139 -0
- package/src/identity/hub/screens/CreateFlow.tsx +206 -0
- package/src/identity/hub/screens/DetailsScreen.tsx +64 -0
- package/src/identity/hub/screens/EditProfileFlow.tsx +145 -0
- package/src/identity/hub/screens/ErrorScreen.tsx +35 -0
- package/src/identity/hub/screens/IdentitySummary.tsx +70 -0
- package/src/identity/hub/screens/MenuScreen.tsx +117 -0
- package/src/identity/hub/screens/NetworkScreen.tsx +41 -0
- package/src/identity/hub/screens/RebackupStorageScreen.tsx +50 -0
- package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +85 -0
- package/src/identity/hub/screens/RestoreFlow.tsx +206 -0
- package/src/identity/hub/screens/StorageCredentialScreen.tsx +128 -0
- package/src/identity/hub/screens/WalletApprovalScreen.tsx +43 -0
- package/src/identity/profile/imagePicker.ts +180 -0
- package/src/identity/registry/erc8004.ts +1106 -0
- package/src/identity/registry/registryConfig.ts +69 -0
- package/src/identity/storage/ipfs.ts +212 -0
- package/src/identity/storage/pinataJwt.ts +53 -0
- package/src/identity/wallet/browserWallet.ts +393 -0
- package/src/identity/wallet/wallet-page/wallet.html +1082 -0
- package/src/mcp/approvals.ts +113 -0
- package/src/mcp/config.ts +235 -0
- package/src/mcp/manager.ts +541 -0
- package/src/mcp/names.ts +19 -0
- package/src/mcp/output.ts +96 -0
- package/src/models/ModelPicker.tsx +1446 -0
- package/src/models/catalog.ts +296 -0
- package/src/models/huggingface.ts +651 -0
- package/src/models/llamacpp.ts +810 -0
- package/src/models/llamacppPreflight.ts +150 -0
- package/src/models/modelDisplay.ts +105 -0
- package/src/models/modelPickerOptions.ts +421 -0
- package/src/models/modelRecommendation.ts +140 -0
- package/src/models/runtimeDetection.ts +81 -0
- package/src/models/uncensoredCatalog.ts +86 -0
- package/src/providers/anthropic.ts +259 -0
- package/src/providers/contracts.ts +62 -0
- package/src/providers/errors.ts +62 -0
- package/src/providers/gemini.ts +152 -0
- package/src/providers/openai-chat.ts +472 -0
- package/src/providers/registry.ts +42 -0
- package/src/providers/retry.ts +58 -0
- package/src/providers/sse.ts +93 -0
- package/src/runtime/compaction.ts +389 -0
- package/src/runtime/cwd.ts +43 -0
- package/src/runtime/sessionMode.ts +55 -0
- package/src/runtime/systemPrompt.ts +209 -0
- package/src/runtime/toolClaimGuards.ts +143 -0
- package/src/runtime/toolExecution.ts +304 -0
- package/src/runtime/toolIntent.ts +163 -0
- package/src/runtime/turn.ts +858 -0
- package/src/storage/atomicWrite.ts +68 -0
- package/src/storage/config.ts +189 -0
- package/src/storage/factoryReset.ts +130 -0
- package/src/storage/history.ts +58 -0
- package/src/storage/identity.ts +99 -0
- package/src/storage/permissions.ts +76 -0
- package/src/storage/rewind.ts +246 -0
- package/src/storage/secrets.ts +181 -0
- package/src/storage/sessionExport.ts +49 -0
- package/src/storage/sessions.ts +482 -0
- package/src/tools/bashSafety.ts +174 -0
- package/src/tools/bashTool.ts +140 -0
- package/src/tools/changeDirectoryTool.ts +213 -0
- package/src/tools/contracts.ts +179 -0
- package/src/tools/deleteFileTool.ts +111 -0
- package/src/tools/editTool.ts +160 -0
- package/src/tools/editUtils.ts +170 -0
- package/src/tools/listDirectoryTool.ts +55 -0
- package/src/tools/mcpResourceTools.ts +95 -0
- package/src/tools/permissionRules.ts +85 -0
- package/src/tools/privateContinuityEditTool.ts +178 -0
- package/src/tools/privateContinuityReadTool.ts +107 -0
- package/src/tools/readTool.ts +85 -0
- package/src/tools/registry.ts +67 -0
- package/src/tools/writeFileTool.ts +142 -0
- package/src/ui/BrandSplash.tsx +193 -0
- package/src/ui/ProgressBar.tsx +34 -0
- package/src/ui/Select.tsx +143 -0
- package/src/ui/Spinner.tsx +269 -0
- package/src/ui/Surface.tsx +47 -0
- package/src/ui/TextInput.tsx +97 -0
- package/src/ui/theme.ts +59 -0
- package/src/utils/clipboard.ts +216 -0
- package/src/utils/markdownSegments.ts +51 -0
- package/src/utils/messages.ts +35 -0
- package/src/utils/withRetry.ts +280 -0
- package/src/cli.tsx +0 -147
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
export type RetryClassification = {
|
|
2
|
+
retryable: boolean
|
|
3
|
+
retryAfterMs?: number
|
|
4
|
+
reason: string
|
|
5
|
+
status?: number
|
|
6
|
+
code?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type RetryPolicy = {
|
|
10
|
+
maxRetries: number
|
|
11
|
+
baseDelayMs: number
|
|
12
|
+
maxDelayMs: number
|
|
13
|
+
retryAfterCapMs: number
|
|
14
|
+
jitterRatio: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type RetryEvent = {
|
|
18
|
+
attempt: number
|
|
19
|
+
nextAttempt: number
|
|
20
|
+
maxRetries: number
|
|
21
|
+
delayMs: number
|
|
22
|
+
reason: string
|
|
23
|
+
retryAfterMs?: number
|
|
24
|
+
status?: number
|
|
25
|
+
code?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const RETRYABLE_NET_CODES = new Set([
|
|
29
|
+
'ECONNRESET',
|
|
30
|
+
'EPIPE',
|
|
31
|
+
'ETIMEDOUT',
|
|
32
|
+
'ECONNREFUSED',
|
|
33
|
+
'EHOSTUNREACH',
|
|
34
|
+
'ENETUNREACH',
|
|
35
|
+
'EAI_AGAIN',
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
const RETRYABLE_STATUS = new Set([408, 409, 425, 429, 500, 502, 503, 504, 529])
|
|
39
|
+
const DEFAULT_BASE_DELAY_MS = 500
|
|
40
|
+
const DEFAULT_MAX_DELAY_MS = 32_000
|
|
41
|
+
const DEFAULT_JITTER_RATIO = 0.25
|
|
42
|
+
const DEFAULT_MAX_RETRIES = 4
|
|
43
|
+
|
|
44
|
+
export const DEFAULT_RETRY_POLICY: RetryPolicy = {
|
|
45
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
46
|
+
baseDelayMs: DEFAULT_BASE_DELAY_MS,
|
|
47
|
+
maxDelayMs: DEFAULT_MAX_DELAY_MS,
|
|
48
|
+
retryAfterCapMs: DEFAULT_MAX_DELAY_MS * 4,
|
|
49
|
+
jitterRatio: DEFAULT_JITTER_RATIO,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function classifyRetryableFetchError(err: unknown): RetryClassification {
|
|
53
|
+
if (!err || typeof err !== 'object') return { retryable: false, reason: 'unknown error' }
|
|
54
|
+
const code = (err as { code?: unknown }).code
|
|
55
|
+
if (typeof code === 'string' && RETRYABLE_NET_CODES.has(code)) {
|
|
56
|
+
return { retryable: true, reason: code, code }
|
|
57
|
+
}
|
|
58
|
+
const cause = (err as { cause?: unknown }).cause
|
|
59
|
+
if (cause && typeof cause === 'object') {
|
|
60
|
+
const causeCode = (cause as { code?: unknown }).code
|
|
61
|
+
if (typeof causeCode === 'string' && RETRYABLE_NET_CODES.has(causeCode)) {
|
|
62
|
+
return { retryable: true, reason: causeCode, code: causeCode }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const message = (err as { message?: unknown }).message
|
|
66
|
+
if (typeof message === 'string' && /fetch failed|network|socket hang up|ECONNRESET/i.test(message)) {
|
|
67
|
+
return { retryable: true, reason: 'fetch failed' }
|
|
68
|
+
}
|
|
69
|
+
return { retryable: false, reason: 'non-retryable error' }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function classifyRetryableResponse(response: Response, nowMs: number = Date.now()): RetryClassification {
|
|
73
|
+
if (response.ok) return { retryable: false, reason: 'ok', status: response.status }
|
|
74
|
+
if (!RETRYABLE_STATUS.has(response.status)) {
|
|
75
|
+
return { retryable: false, reason: `HTTP ${response.status}`, status: response.status }
|
|
76
|
+
}
|
|
77
|
+
const retryAfter = response.headers.get('retry-after')
|
|
78
|
+
const retryAfterMs = retryAfter ? parseRetryAfter(retryAfter, nowMs) : undefined
|
|
79
|
+
return { retryable: true, retryAfterMs, reason: `HTTP ${response.status}`, status: response.status }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function classifyRetryableProviderResponse(
|
|
83
|
+
response: Response,
|
|
84
|
+
nowMs: number = Date.now(),
|
|
85
|
+
rateLimitResetProvider?: RateLimitResetProvider,
|
|
86
|
+
): RetryClassification {
|
|
87
|
+
const classification = classifyRetryableResponse(response, nowMs)
|
|
88
|
+
if (
|
|
89
|
+
!classification.retryable ||
|
|
90
|
+
classification.retryAfterMs !== undefined ||
|
|
91
|
+
response.status !== 429 ||
|
|
92
|
+
!rateLimitResetProvider
|
|
93
|
+
) {
|
|
94
|
+
return classification
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...classification,
|
|
98
|
+
retryAfterMs: rateLimitResetDelayMs(response.headers, rateLimitResetProvider, nowMs),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function computeBackoffMs(
|
|
103
|
+
attempt: number,
|
|
104
|
+
retryAfterMs: number | undefined,
|
|
105
|
+
maxDelayMs = DEFAULT_MAX_DELAY_MS,
|
|
106
|
+
baseDelayMs = DEFAULT_BASE_DELAY_MS,
|
|
107
|
+
rng: () => number = Math.random,
|
|
108
|
+
jitterRatio = DEFAULT_JITTER_RATIO,
|
|
109
|
+
retryAfterCapMs = maxDelayMs * 4,
|
|
110
|
+
): number {
|
|
111
|
+
if (retryAfterMs !== undefined && Number.isFinite(retryAfterMs)) {
|
|
112
|
+
return Math.min(Math.max(retryAfterMs, 0), retryAfterCapMs)
|
|
113
|
+
}
|
|
114
|
+
const expo = Math.min(baseDelayMs * Math.pow(2, attempt - 1), maxDelayMs)
|
|
115
|
+
const jitter = rng() * jitterRatio * expo
|
|
116
|
+
return Math.floor(expo + jitter)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function retryPolicyFromOptions(options: FetchWithRetryOptions = {}): RetryPolicy {
|
|
120
|
+
const maxDelayMs = options.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs
|
|
121
|
+
return {
|
|
122
|
+
maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,
|
|
123
|
+
baseDelayMs: options.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,
|
|
124
|
+
maxDelayMs,
|
|
125
|
+
retryAfterCapMs: options.retryAfterCapMs ?? maxDelayMs * 4,
|
|
126
|
+
jitterRatio: options.jitterRatio ?? DEFAULT_RETRY_POLICY.jitterRatio,
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function parseRetryAfter(headerValue: string, nowMs: number = Date.now()): number | undefined {
|
|
131
|
+
const trimmed = headerValue.trim()
|
|
132
|
+
if (!trimmed) return undefined
|
|
133
|
+
const seconds = Number(trimmed)
|
|
134
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000)
|
|
135
|
+
const dateMs = Date.parse(trimmed)
|
|
136
|
+
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - nowMs)
|
|
137
|
+
return undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function parseOpenAIRateLimitResetMs(value: string): number | undefined {
|
|
141
|
+
if (!value) return undefined
|
|
142
|
+
const match = /^(?:(\d+)h)?(?:(\d+)m(?!s))?(?:(\d+)s)?(?:(\d+)ms)?$/.exec(value.trim())
|
|
143
|
+
if (!match || match[0] === '') return undefined
|
|
144
|
+
const hours = Number.parseInt(match[1] ?? '0', 10)
|
|
145
|
+
const minutes = Number.parseInt(match[2] ?? '0', 10)
|
|
146
|
+
const seconds = Number.parseInt(match[3] ?? '0', 10)
|
|
147
|
+
const milliseconds = Number.parseInt(match[4] ?? '0', 10)
|
|
148
|
+
const total = hours * 3_600_000 + minutes * 60_000 + seconds * 1000 + milliseconds
|
|
149
|
+
return total > 0 ? total : undefined
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type RateLimitResetProvider = 'anthropic' | 'openai-compatible'
|
|
153
|
+
|
|
154
|
+
export function rateLimitResetDelayMs(
|
|
155
|
+
headers: Headers,
|
|
156
|
+
provider: RateLimitResetProvider,
|
|
157
|
+
nowMs: number = Date.now(),
|
|
158
|
+
capMs = DEFAULT_RETRY_POLICY.retryAfterCapMs,
|
|
159
|
+
): number | undefined {
|
|
160
|
+
if (provider === 'anthropic') {
|
|
161
|
+
const reset = headers.get('anthropic-ratelimit-unified-reset')
|
|
162
|
+
if (!reset) return undefined
|
|
163
|
+
const unixSeconds = Number(reset)
|
|
164
|
+
if (!Number.isFinite(unixSeconds)) return undefined
|
|
165
|
+
const delay = unixSeconds * 1000 - nowMs
|
|
166
|
+
return delay > 0 ? Math.min(delay, capMs) : undefined
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const requestDelay = parseOpenAIRateLimitResetMs(headers.get('x-ratelimit-reset-requests') ?? '')
|
|
170
|
+
const tokenDelay = parseOpenAIRateLimitResetMs(headers.get('x-ratelimit-reset-tokens') ?? '')
|
|
171
|
+
const delay = Math.max(requestDelay ?? 0, tokenDelay ?? 0)
|
|
172
|
+
return delay > 0 ? Math.min(delay, capMs) : undefined
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export type FetchWithRetryOptions = {
|
|
176
|
+
maxRetries?: number
|
|
177
|
+
baseDelayMs?: number
|
|
178
|
+
maxDelayMs?: number
|
|
179
|
+
retryAfterCapMs?: number
|
|
180
|
+
jitterRatio?: number
|
|
181
|
+
rateLimitResetProvider?: RateLimitResetProvider
|
|
182
|
+
signal?: AbortSignal
|
|
183
|
+
fetchImpl?: typeof fetch
|
|
184
|
+
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>
|
|
185
|
+
rng?: () => number
|
|
186
|
+
now?: () => number
|
|
187
|
+
onRetry?: (event: RetryEvent) => void
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function fetchWithRetry(
|
|
191
|
+
input: string,
|
|
192
|
+
init: RequestInit,
|
|
193
|
+
options: FetchWithRetryOptions = {},
|
|
194
|
+
): Promise<Response> {
|
|
195
|
+
const policy = retryPolicyFromOptions(options)
|
|
196
|
+
const fetchImpl = options.fetchImpl ?? fetch
|
|
197
|
+
const sleepImpl = options.sleep ?? sleep
|
|
198
|
+
const rng = options.rng ?? Math.random
|
|
199
|
+
const now = options.now ?? Date.now
|
|
200
|
+
let lastError: unknown
|
|
201
|
+
for (let attempt = 1; attempt <= policy.maxRetries + 1; attempt += 1) {
|
|
202
|
+
if (options.signal?.aborted) throw new DOMException('aborted', 'AbortError')
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const response = await fetchImpl(input, { ...init, signal: options.signal })
|
|
206
|
+
if (response.ok) return response
|
|
207
|
+
|
|
208
|
+
const classification = classifyRetryableProviderResponse(response, now(), options.rateLimitResetProvider)
|
|
209
|
+
if (!classification.retryable || attempt > policy.maxRetries) return response
|
|
210
|
+
|
|
211
|
+
try { await response.body?.cancel() } catch { /* ignore */ }
|
|
212
|
+
const delayMs = computeBackoffMs(
|
|
213
|
+
attempt,
|
|
214
|
+
classification.retryAfterMs,
|
|
215
|
+
policy.maxDelayMs,
|
|
216
|
+
policy.baseDelayMs,
|
|
217
|
+
rng,
|
|
218
|
+
policy.jitterRatio,
|
|
219
|
+
policy.retryAfterCapMs,
|
|
220
|
+
)
|
|
221
|
+
options.onRetry?.(retryEvent(attempt, policy.maxRetries, delayMs, classification))
|
|
222
|
+
await sleepImpl(delayMs, options.signal)
|
|
223
|
+
continue
|
|
224
|
+
} catch (err) {
|
|
225
|
+
lastError = err
|
|
226
|
+
if (options.signal?.aborted) throw err
|
|
227
|
+
const classification = classifyRetryableFetchError(err)
|
|
228
|
+
if (!classification.retryable || attempt > policy.maxRetries) throw err
|
|
229
|
+
|
|
230
|
+
const delayMs = computeBackoffMs(
|
|
231
|
+
attempt,
|
|
232
|
+
classification.retryAfterMs,
|
|
233
|
+
policy.maxDelayMs,
|
|
234
|
+
policy.baseDelayMs,
|
|
235
|
+
rng,
|
|
236
|
+
policy.jitterRatio,
|
|
237
|
+
policy.retryAfterCapMs,
|
|
238
|
+
)
|
|
239
|
+
options.onRetry?.(retryEvent(attempt, policy.maxRetries, delayMs, classification))
|
|
240
|
+
await sleepImpl(delayMs, options.signal)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
throw lastError ?? new Error('fetchWithRetry exhausted')
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function retryEvent(
|
|
247
|
+
attempt: number,
|
|
248
|
+
maxRetries: number,
|
|
249
|
+
delayMs: number,
|
|
250
|
+
classification: RetryClassification,
|
|
251
|
+
): RetryEvent {
|
|
252
|
+
return {
|
|
253
|
+
attempt,
|
|
254
|
+
nextAttempt: attempt + 1,
|
|
255
|
+
maxRetries,
|
|
256
|
+
delayMs,
|
|
257
|
+
reason: classification.reason,
|
|
258
|
+
...(classification.retryAfterMs !== undefined ? { retryAfterMs: classification.retryAfterMs } : {}),
|
|
259
|
+
...(classification.status !== undefined ? { status: classification.status } : {}),
|
|
260
|
+
...(classification.code !== undefined ? { code: classification.code } : {}),
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
265
|
+
return new Promise((resolve, reject) => {
|
|
266
|
+
if (signal?.aborted) {
|
|
267
|
+
reject(new DOMException('aborted', 'AbortError'))
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
const timer = setTimeout(() => {
|
|
271
|
+
signal?.removeEventListener('abort', onAbort)
|
|
272
|
+
resolve()
|
|
273
|
+
}, ms)
|
|
274
|
+
const onAbort = () => {
|
|
275
|
+
clearTimeout(timer)
|
|
276
|
+
reject(new DOMException('aborted', 'AbortError'))
|
|
277
|
+
}
|
|
278
|
+
signal?.addEventListener('abort', onAbort, { once: true })
|
|
279
|
+
})
|
|
280
|
+
}
|
package/src/cli.tsx
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import {render, Text, Box} from 'ink'
|
|
4
|
-
|
|
5
|
-
const eth = `░░░░░░░╗░░░░░░░░╗░░╗ ░░╗
|
|
6
|
-
░░╔════╝╚══░░╔══╝░░║ ░░║
|
|
7
|
-
░░░░░╗ ░░║ ░░░░░░░║
|
|
8
|
-
░░╔══╝ ░░║ ░░╔══░░║
|
|
9
|
-
░░░░░░░╗ ░░║ ░░║ ░░║
|
|
10
|
-
╚══════╝ ╚═╝ ╚═╝ ╚═╝`
|
|
11
|
-
|
|
12
|
-
const A = [
|
|
13
|
-
` █████╗ `,
|
|
14
|
-
`██╔══██╗`,
|
|
15
|
-
`███████║`,
|
|
16
|
-
`██╔══██║`,
|
|
17
|
-
`██║ ██║`,
|
|
18
|
-
`╚═╝ ╚═╝`,
|
|
19
|
-
].join('\n')
|
|
20
|
-
|
|
21
|
-
const G = [
|
|
22
|
-
` ██████╗ `,
|
|
23
|
-
`██╔════╝ `,
|
|
24
|
-
`██║ ███╗`,
|
|
25
|
-
`██║ ██║`,
|
|
26
|
-
`╚██████╔╝`,
|
|
27
|
-
` ╚═════╝ `,
|
|
28
|
-
].join('\n')
|
|
29
|
-
|
|
30
|
-
const E = [
|
|
31
|
-
`███████╗`,
|
|
32
|
-
`██╔════╝`,
|
|
33
|
-
`█████╗ `,
|
|
34
|
-
`██╔══╝ `,
|
|
35
|
-
`███████╗`,
|
|
36
|
-
`╚══════╝`,
|
|
37
|
-
].join('\n')
|
|
38
|
-
|
|
39
|
-
const N = [
|
|
40
|
-
`███╗ ██╗`,
|
|
41
|
-
`████╗ ██║`,
|
|
42
|
-
`██╔██╗ ██║`,
|
|
43
|
-
`██║╚██╗██║`,
|
|
44
|
-
`██║ ╚████║`,
|
|
45
|
-
`╚═╝ ╚═══╝`,
|
|
46
|
-
].join('\n')
|
|
47
|
-
|
|
48
|
-
const T = [
|
|
49
|
-
`████████╗`,
|
|
50
|
-
`╚══██╔══╝`,
|
|
51
|
-
` ██║ `,
|
|
52
|
-
` ██║ `,
|
|
53
|
-
` ██║ `,
|
|
54
|
-
` ╚═╝ `,
|
|
55
|
-
].join('\n')
|
|
56
|
-
|
|
57
|
-
const eyes = `
|
|
58
|
-
-+:
|
|
59
|
-
:=- -%@@@%.
|
|
60
|
-
*@@@@@#- *@@-
|
|
61
|
-
+@@. +@
|
|
62
|
-
@@= -#=-+++=+:
|
|
63
|
-
#% .:===-: -@* +@@@@%
|
|
64
|
-
*@-+@@@@@: %@@+ @@@=#@
|
|
65
|
-
*@= @@@@@@@- .@.@@@@@@@ :
|
|
66
|
-
@@+=@@@@@@@@@@@@: .% *@@@@@*-=
|
|
67
|
-
#:-@ -@@@@@@@@@-+% @ -@@@- #
|
|
68
|
-
: #+ @@@@@@@- -% =# =
|
|
69
|
-
-@: *@ .+%%
|
|
70
|
-
:%#: --
|
|
71
|
-
.-:
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
const palette = [
|
|
75
|
-
[0xe8, 0xa0, 0xa0],
|
|
76
|
-
[0xe8, 0xbe, 0x8f],
|
|
77
|
-
[0xe8, 0xdf, 0x9a],
|
|
78
|
-
[0x96, 0xd4, 0xa8],
|
|
79
|
-
[0x90, 0xb8, 0xe8],
|
|
80
|
-
]
|
|
81
|
-
|
|
82
|
-
function gradientColor(t) {
|
|
83
|
-
const s = Math.max(0, Math.min(1, t)) * (palette.length - 1)
|
|
84
|
-
const i = Math.min(Math.floor(s), palette.length - 2)
|
|
85
|
-
const f = s - i
|
|
86
|
-
const [r1, g1, b1] = palette[i]
|
|
87
|
-
const [r2, g2, b2] = palette[i + 1]
|
|
88
|
-
const r = Math.round(r1 + (r2 - r1) * f)
|
|
89
|
-
const g = Math.round(g1 + (g2 - g1) * f)
|
|
90
|
-
const b = Math.round(b1 + (b2 - b1) * f)
|
|
91
|
-
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const Eyes = () => {
|
|
95
|
-
const lines = eyes.split('\n')
|
|
96
|
-
const maxLen = Math.max(...lines.map(l => l.trimEnd().length))
|
|
97
|
-
return (
|
|
98
|
-
<Box flexDirection="column">
|
|
99
|
-
{lines.map((line, li) => (
|
|
100
|
-
<Text key={li}>
|
|
101
|
-
{line.split('').map((char, ci) => (
|
|
102
|
-
<Text key={ci} color={gradientColor(ci / Math.max(maxLen - 1, 1))}>{char}</Text>
|
|
103
|
-
))}
|
|
104
|
-
</Text>
|
|
105
|
-
))}
|
|
106
|
-
</Box>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const App = () => {
|
|
111
|
-
const ethLines = eth.split('\n')
|
|
112
|
-
const aLines = A.split('\n')
|
|
113
|
-
const gLines = G.split('\n')
|
|
114
|
-
const eLines = E.split('\n')
|
|
115
|
-
const nLines = N.split('\n')
|
|
116
|
-
const tLines = T.split('\n')
|
|
117
|
-
|
|
118
|
-
const w = 69
|
|
119
|
-
const topLabel = ' privacy-first AI agent with a portable ethereum identity '
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<Box flexDirection="column" alignSelf="flex-start" padding={1}>
|
|
123
|
-
<Eyes />
|
|
124
|
-
<Text>
|
|
125
|
-
<Text color="#555555">╔═</Text>
|
|
126
|
-
<Text color="#777777">{topLabel}</Text>
|
|
127
|
-
<Text color="#555555">{'═'.repeat(w - topLabel.length - 1)}╗</Text>
|
|
128
|
-
</Text>
|
|
129
|
-
{ethLines.map((line, i) => (
|
|
130
|
-
<Box key={i}>
|
|
131
|
-
<Text color="#555555">║</Text>
|
|
132
|
-
<Text color="#555555">{ethLines[i]}</Text>
|
|
133
|
-
<Text color="#555555">{aLines[i]}</Text>
|
|
134
|
-
<Text color="#555555">{gLines[i]}</Text>
|
|
135
|
-
<Text color="#555555">{eLines[i]}</Text>
|
|
136
|
-
<Text color="#555555">{nLines[i]}</Text>
|
|
137
|
-
<Text color="#555555">{tLines[i]}</Text>
|
|
138
|
-
<Text color="#555555">║</Text>
|
|
139
|
-
</Box>
|
|
140
|
-
))}
|
|
141
|
-
<Text color="#555555">{'╚' + '═'.repeat(w) + '╝'}</Text>
|
|
142
|
-
<Text color="#777777">{'\n coming soon...\n'}</Text>
|
|
143
|
-
</Box>
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
render(<App />)
|