ethagent 3.3.3 → 4.0.0

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 (322) hide show
  1. package/.claude-plugin/marketplace.json +11 -0
  2. package/.claude-plugin/plugin.json +35 -0
  3. package/LICENSE +1 -1
  4. package/README.md +64 -104
  5. package/commands/ethagent.md +40 -0
  6. package/package.json +16 -16
  7. package/src/app/keybindings/KeybindingProvider.tsx +1 -6
  8. package/src/app/keybindings/types.ts +1 -6
  9. package/src/cli/ResetConfirmView.tsx +54 -53
  10. package/src/cli/demo.ts +86 -0
  11. package/src/cli/hookIo.ts +45 -0
  12. package/src/cli/main.tsx +94 -123
  13. package/src/cli/memoryGuard.ts +49 -0
  14. package/src/cli/reset.ts +28 -70
  15. package/src/cli/sessionStart.ts +33 -0
  16. package/src/cli/status.ts +46 -0
  17. package/src/cli/sync.ts +167 -0
  18. package/src/cli/syncAdapters/claude-code.ts +86 -0
  19. package/src/cli/syncAdapters/codex.ts +66 -0
  20. package/src/cli/syncAdapters/index.ts +45 -0
  21. package/src/cli/syncAdapters/managedBlock.ts +175 -0
  22. package/src/cli/syncAdapters/shared.ts +63 -0
  23. package/src/identity/continuity/envelopeParse.ts +20 -1
  24. package/src/identity/continuity/publicSkills.ts +3 -1
  25. package/src/identity/continuity/skills/publicSkillsSync.ts +2 -1
  26. package/src/identity/continuity/skills/scaffold.ts +5 -2
  27. package/src/identity/continuity/snapshots.ts +12 -5
  28. package/src/identity/continuity/storage/defaults.ts +20 -19
  29. package/src/identity/continuity/storage/status.ts +1 -1
  30. package/src/identity/ens/ensLookup/constants.ts +1 -1
  31. package/src/identity/manager/IdentityManager.tsx +33 -0
  32. package/src/identity/{hub → manager}/OperationalRoutes.tsx +37 -18
  33. package/src/identity/{hub → manager}/Routes.tsx +48 -34
  34. package/src/identity/{hub → manager}/continuity/ContinuityDashboardScreen.tsx +9 -19
  35. package/src/identity/{hub → manager}/continuity/RebackupStorageScreen.tsx +3 -3
  36. package/src/identity/manager/continuity/RecoveryConfirmScreen.tsx +102 -0
  37. package/src/identity/{hub → manager}/continuity/SavePromptScreen.tsx +2 -3
  38. package/src/identity/{hub → manager}/continuity/completion.ts +1 -1
  39. package/src/identity/{hub → manager}/continuity/effects.ts +1 -1
  40. package/src/identity/{hub → manager}/continuity/skills/DeleteSkillConfirmScreen.tsx +2 -2
  41. package/src/identity/{hub → manager}/continuity/skills/NewSkillScreen.tsx +0 -5
  42. package/src/identity/{hub → manager}/continuity/skills/NewSkillVisibilityScreen.tsx +4 -4
  43. package/src/identity/{hub → manager}/continuity/skills/SkillActionsScreen.tsx +6 -22
  44. package/src/identity/{hub → manager}/continuity/skills/SkillsTreeScreen.tsx +5 -17
  45. package/src/identity/{hub → manager}/continuity/snapshot.ts +1 -1
  46. package/src/identity/{hub → manager}/continuity/vault.ts +1 -1
  47. package/src/identity/{hub → manager}/create/CreateFlow.tsx +59 -32
  48. package/src/identity/{hub → manager}/create/effects.ts +19 -10
  49. package/src/identity/manager/create/importScan.ts +122 -0
  50. package/src/identity/{hub → manager}/custody/CustodyEditFlow.tsx +17 -61
  51. package/src/identity/{hub → manager}/custody/actions.ts +1 -15
  52. package/src/identity/{hub → manager}/custody/routes.tsx +20 -40
  53. package/src/identity/{hub → manager}/custody/transactions.ts +1 -0
  54. package/src/identity/{hub → manager}/custody/types.ts +1 -2
  55. package/src/identity/{hub → manager}/custody/useCustodyEffects.ts +1 -1
  56. package/src/identity/{hub → manager}/ens/EnsEditAdvancedScreens.tsx +2 -2
  57. package/src/identity/{hub → manager}/ens/EnsEditMaintenanceScreens.tsx +12 -23
  58. package/src/identity/{hub → manager}/ens/EnsEditReviewScreens.tsx +18 -42
  59. package/src/identity/{hub → manager}/ens/EnsEditRunners.tsx +1 -1
  60. package/src/identity/{hub → manager}/ens/EnsEditShared.tsx +0 -2
  61. package/src/identity/{hub → manager}/ens/EnsEditSimpleScreens.tsx +10 -19
  62. package/src/identity/{hub → manager}/ens/EnsFlow.tsx +133 -41
  63. package/src/identity/{hub → manager}/ens/EnsOperatorWalletsScreen.tsx +14 -19
  64. package/src/identity/{hub → manager}/ens/editCopy.ts +1 -14
  65. package/src/identity/{hub → manager}/profile/EditProfileFlow.tsx +99 -66
  66. package/src/identity/{hub → manager}/profile/effects.ts +1 -3
  67. package/src/identity/{hub → manager}/profile/operatorSave.ts +1 -1
  68. package/src/identity/{hub → manager}/profile/state.ts +1 -1
  69. package/src/identity/{hub/identityHubReducer.ts → manager/reducer.ts} +25 -26
  70. package/src/identity/{hub → manager}/restore/RestoreFlow.tsx +16 -24
  71. package/src/identity/{hub → manager}/restore/apply.ts +1 -1
  72. package/src/identity/{hub → manager}/restore/auth.ts +1 -1
  73. package/src/identity/{hub → manager}/restore/discover.ts +1 -1
  74. package/src/identity/{hub → manager}/restore/fetch.ts +1 -1
  75. package/src/identity/{hub → manager}/restore/restoreAdmin.ts +1 -1
  76. package/src/identity/{hub → manager}/restore/useRestoreEffects.ts +2 -9
  77. package/src/identity/{hub → manager}/settings/StorageCredentialScreen.tsx +10 -25
  78. package/src/identity/{hub → manager}/shared/components/DetailsScreen.tsx +5 -7
  79. package/src/identity/{hub → manager}/shared/components/ErrorScreen.tsx +6 -10
  80. package/src/identity/{hub → manager}/shared/components/FlowTimeline.tsx +4 -3
  81. package/src/identity/{hub → manager}/shared/components/IdentitySummary.tsx +19 -59
  82. package/src/identity/manager/shared/components/LazyMenu.tsx +147 -0
  83. package/src/identity/manager/shared/components/MenuScreen.tsx +220 -0
  84. package/src/identity/manager/shared/components/OperationCompleteScreen.tsx +28 -0
  85. package/src/identity/{hub → manager}/shared/components/UnlinkedIdentityScreen.tsx +9 -10
  86. package/src/identity/{hub → manager}/shared/components/WalletApprovalScreen.tsx +1 -2
  87. package/src/identity/manager/shared/components/Wordmark.tsx +54 -0
  88. package/src/identity/{hub → manager}/shared/components/menuFlagsFromReconciliation.ts +39 -15
  89. package/src/identity/{hub → manager}/shared/effects/profilePrep.ts +1 -1
  90. package/src/identity/manager/shared/effects/types.ts +30 -0
  91. package/src/identity/{hub → manager}/shared/model/copy.ts +0 -4
  92. package/src/identity/{hub → manager}/shared/model/errors.ts +32 -3
  93. package/src/identity/{hub → manager}/shared/model/network.ts +2 -2
  94. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/hook.ts +5 -0
  95. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/run.ts +1 -1
  96. package/src/identity/{hub/shared/reconciliation/useAgentReconciliation.ts → manager/shared/reconciliation/index.ts} +6 -0
  97. package/src/identity/{hub → manager}/shared/utils.ts +6 -10
  98. package/src/identity/{hub → manager}/transfer/TokenTransferFlow.tsx +3 -3
  99. package/src/identity/{hub → manager}/transfer/TokenTransferScreens.tsx +4 -10
  100. package/src/identity/{hub → manager}/transfer/effects.ts +1 -1
  101. package/src/identity/{hub → manager}/types.ts +5 -6
  102. package/src/identity/{hub/useIdentityHubContinuity.ts → manager/useContinuity.ts} +59 -27
  103. package/src/identity/{hub/useIdentityHubController.ts → manager/useController.ts} +38 -35
  104. package/src/identity/{hub/useIdentityHubSideEffects.ts → manager/useSideEffects.ts} +40 -4
  105. package/src/identity/registry/erc8004/discovery.ts +3 -17
  106. package/src/identity/registry/erc8004/utils.ts +1 -1
  107. package/src/identity/storage/ipfs.ts +21 -1
  108. package/src/identity/wallet/browserWallet/html.ts +10 -2
  109. package/src/identity/wallet/browserWallet/http.ts +18 -0
  110. package/src/identity/wallet/browserWallet/requestServer.ts +5 -1
  111. package/src/identity/wallet/browserWallet/requests.ts +10 -28
  112. package/src/identity/wallet/browserWallet/session.ts +26 -33
  113. package/src/identity/wallet/browserWallet/validation.ts +14 -0
  114. package/src/identity/wallet/browserWallet/walletPageSource.ts +22 -40
  115. package/src/identity/wallet/page/boot.ts +43 -0
  116. package/src/identity/wallet/page/config.ts +59 -0
  117. package/src/identity/wallet/page/constants.ts +12 -0
  118. package/src/identity/wallet/page/copy.ts +47 -68
  119. package/src/identity/wallet/page/css.ts +638 -0
  120. package/src/identity/wallet/page/{errorView.ts → errors.ts} +5 -14
  121. package/src/identity/wallet/page/{controller.ts → flow.ts} +4 -71
  122. package/src/identity/wallet/page/markup.ts +44 -34
  123. package/src/identity/wallet/page/{walletProvider.ts → provider.ts} +0 -3
  124. package/src/identity/wallet/page/resize.ts +95 -0
  125. package/src/identity/wallet/page/state.ts +135 -8
  126. package/src/identity/wallet/page/timeline.ts +161 -0
  127. package/src/identity/wallet/page/view.ts +22 -302
  128. package/src/storage/config.ts +30 -80
  129. package/src/storage/reset.ts +31 -0
  130. package/src/storage/secrets.ts +1 -16
  131. package/src/ui/Select.tsx +27 -5
  132. package/src/ui/Spinner.tsx +16 -15
  133. package/src/ui/Surface.tsx +21 -17
  134. package/src/ui/TextArea.tsx +173 -0
  135. package/src/ui/TextInput.tsx +31 -133
  136. package/src/ui/theme.ts +22 -13
  137. package/src/utils/clipboard.ts +0 -140
  138. package/src/app/FirstRun.tsx +0 -577
  139. package/src/app/FirstRunTimeline.tsx +0 -51
  140. package/src/app/firstRunConfig.ts +0 -26
  141. package/src/app/hooks/useCancelRequest.ts +0 -22
  142. package/src/app/hooks/useDoublePress.ts +0 -46
  143. package/src/app/hooks/useExitOnCtrlC.ts +0 -36
  144. package/src/auth/openaiOAuth/credentials.ts +0 -47
  145. package/src/auth/openaiOAuth/crypto.ts +0 -23
  146. package/src/auth/openaiOAuth/index.ts +0 -238
  147. package/src/auth/openaiOAuth/landingPage.ts +0 -116
  148. package/src/auth/openaiOAuth/listener.ts +0 -151
  149. package/src/auth/openaiOAuth/refresh.ts +0 -70
  150. package/src/auth/openaiOAuth/shared.ts +0 -115
  151. package/src/chat/ChatBottomPane.tsx +0 -296
  152. package/src/chat/ChatScreen.tsx +0 -1685
  153. package/src/chat/ConversationStack.tsx +0 -56
  154. package/src/chat/MessageList.tsx +0 -638
  155. package/src/chat/SessionStatus.tsx +0 -53
  156. package/src/chat/chatEnvironment.ts +0 -16
  157. package/src/chat/chatScreenUtils.ts +0 -194
  158. package/src/chat/chatSessionState.ts +0 -146
  159. package/src/chat/chatTurnContext.ts +0 -50
  160. package/src/chat/chatTurnOrchestrator.ts +0 -603
  161. package/src/chat/chatTurnRows.ts +0 -64
  162. package/src/chat/commands.ts +0 -494
  163. package/src/chat/continuityEditReview.ts +0 -42
  164. package/src/chat/display/DiffView.tsx +0 -193
  165. package/src/chat/display/SyntaxText.tsx +0 -192
  166. package/src/chat/display/toolCallDisplay.ts +0 -103
  167. package/src/chat/display/toolResultDisplay.ts +0 -19
  168. package/src/chat/input/ChatInput.tsx +0 -625
  169. package/src/chat/input/chatInputHelpers.ts +0 -62
  170. package/src/chat/input/chatInputState.ts +0 -247
  171. package/src/chat/input/chatPaste.ts +0 -49
  172. package/src/chat/input/imageRefs.ts +0 -30
  173. package/src/chat/input/inputRendering.tsx +0 -93
  174. package/src/chat/input/textCursor.ts +0 -212
  175. package/src/chat/messageMarkdown.ts +0 -220
  176. package/src/chat/messageRows.ts +0 -43
  177. package/src/chat/planImplementation.ts +0 -62
  178. package/src/chat/slashCommandHandlers.ts +0 -122
  179. package/src/chat/slashCommandViews.ts +0 -120
  180. package/src/chat/transcript/TranscriptView.tsx +0 -184
  181. package/src/chat/transcript/transcriptViewport.ts +0 -295
  182. package/src/chat/views/ContextLimitView.tsx +0 -95
  183. package/src/chat/views/ContinuityEditReviewView.tsx +0 -50
  184. package/src/chat/views/CopyPicker.tsx +0 -50
  185. package/src/chat/views/PermissionPrompt.tsx +0 -156
  186. package/src/chat/views/PermissionsView.tsx +0 -165
  187. package/src/chat/views/PlanApprovalView.tsx +0 -91
  188. package/src/chat/views/ResumeView.tsx +0 -273
  189. package/src/chat/views/RewindView.tsx +0 -412
  190. package/src/cli/preview.tsx +0 -14
  191. package/src/cli/updateNotice.ts +0 -54
  192. package/src/identity/continuity/privateEdit/apply.ts +0 -170
  193. package/src/identity/continuity/privateEdit/diff.ts +0 -6
  194. package/src/identity/continuity/privateEdit/files.ts +0 -23
  195. package/src/identity/continuity/privateEdit/types.ts +0 -28
  196. package/src/identity/continuity/privateEdit.ts +0 -46
  197. package/src/identity/hub/IdentityHub.tsx +0 -14
  198. package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +0 -104
  199. package/src/identity/hub/ens/effects.ts +0 -218
  200. package/src/identity/hub/shared/components/MenuScreen.tsx +0 -241
  201. package/src/identity/hub/shared/effects/types.ts +0 -53
  202. package/src/identity/hub/shared/reconciliation/index.ts +0 -14
  203. package/src/identity/wallet/page/grainient.ts +0 -278
  204. package/src/identity/wallet/page/html.ts +0 -28
  205. package/src/identity/wallet/page/styles/base.ts +0 -259
  206. package/src/identity/wallet/page/styles/components.ts +0 -262
  207. package/src/identity/wallet/page/styles/index.ts +0 -5
  208. package/src/identity/wallet/page/styles/responsive.ts +0 -247
  209. package/src/identity/wallet/page.tsx +0 -38
  210. package/src/mcp/approvals.ts +0 -113
  211. package/src/mcp/config.ts +0 -235
  212. package/src/mcp/manager.ts +0 -482
  213. package/src/mcp/managerHelpers.ts +0 -70
  214. package/src/mcp/names.ts +0 -19
  215. package/src/mcp/output.ts +0 -96
  216. package/src/models/ModelPicker.tsx +0 -1009
  217. package/src/models/catalog.ts +0 -327
  218. package/src/models/huggingface.ts +0 -712
  219. package/src/models/huggingfaceStorage.ts +0 -136
  220. package/src/models/llamacpp.ts +0 -848
  221. package/src/models/llamacppCommands.ts +0 -44
  222. package/src/models/llamacppConfig.ts +0 -34
  223. package/src/models/llamacppDiscovery.ts +0 -176
  224. package/src/models/llamacppOutput.ts +0 -65
  225. package/src/models/llamacppPreflight.ts +0 -158
  226. package/src/models/modelDisplay.ts +0 -180
  227. package/src/models/modelPickerCatalogFlow.ts +0 -56
  228. package/src/models/modelPickerCredentials.ts +0 -166
  229. package/src/models/modelPickerData.ts +0 -41
  230. package/src/models/modelPickerDisplay.tsx +0 -132
  231. package/src/models/modelPickerHfFlow.ts +0 -192
  232. package/src/models/modelPickerLocalRunnerFlow.ts +0 -115
  233. package/src/models/modelPickerOptions.ts +0 -457
  234. package/src/models/modelPickerTypes.ts +0 -69
  235. package/src/models/modelPickerUninstallFlow.ts +0 -48
  236. package/src/models/modelPickerViewHelpers.ts +0 -174
  237. package/src/models/modelRecommendation.ts +0 -139
  238. package/src/models/providerDisplay.ts +0 -16
  239. package/src/models/runtimeDetection.ts +0 -81
  240. package/src/models/uncensoredCatalog.ts +0 -86
  241. package/src/providers/anthropic.ts +0 -290
  242. package/src/providers/contracts.ts +0 -71
  243. package/src/providers/errors.ts +0 -80
  244. package/src/providers/gemini.ts +0 -391
  245. package/src/providers/openai-chat.ts +0 -474
  246. package/src/providers/openai-responses-format.ts +0 -177
  247. package/src/providers/openai-responses.ts +0 -306
  248. package/src/providers/openaiChatWire.ts +0 -124
  249. package/src/providers/registry.ts +0 -120
  250. package/src/providers/retry.ts +0 -58
  251. package/src/providers/sse.ts +0 -93
  252. package/src/runtime/compaction.ts +0 -395
  253. package/src/runtime/cwd.ts +0 -43
  254. package/src/runtime/providerTurn.ts +0 -38
  255. package/src/runtime/sessionMode.ts +0 -55
  256. package/src/runtime/systemPrompt.ts +0 -213
  257. package/src/runtime/textToolParser.ts +0 -161
  258. package/src/runtime/toolClaimGuards.ts +0 -143
  259. package/src/runtime/toolExecution.ts +0 -304
  260. package/src/runtime/toolIntent.ts +0 -143
  261. package/src/runtime/turn.ts +0 -369
  262. package/src/runtime/turnNudges.ts +0 -223
  263. package/src/runtime/turnTypes.ts +0 -86
  264. package/src/storage/factoryReset.ts +0 -127
  265. package/src/storage/history.ts +0 -58
  266. package/src/storage/permissions.ts +0 -76
  267. package/src/storage/rewind.ts +0 -266
  268. package/src/storage/sessionExport.ts +0 -49
  269. package/src/storage/sessions.ts +0 -495
  270. package/src/tools/bashSafety.ts +0 -186
  271. package/src/tools/bashTool.ts +0 -140
  272. package/src/tools/changeDirectoryTool.ts +0 -213
  273. package/src/tools/contracts.ts +0 -192
  274. package/src/tools/deleteFileTool.ts +0 -116
  275. package/src/tools/editTool.ts +0 -165
  276. package/src/tools/editUtils.ts +0 -170
  277. package/src/tools/fileDiff.ts +0 -261
  278. package/src/tools/listDirectoryTool.ts +0 -55
  279. package/src/tools/listSkillFilesTool.ts +0 -77
  280. package/src/tools/listSkillsTool.ts +0 -68
  281. package/src/tools/mcpResourceTools.ts +0 -95
  282. package/src/tools/permissionRules.ts +0 -85
  283. package/src/tools/privateContinuityEditTool.ts +0 -187
  284. package/src/tools/privateContinuityReadTool.ts +0 -106
  285. package/src/tools/readSkillTool.ts +0 -107
  286. package/src/tools/readTool.ts +0 -85
  287. package/src/tools/registry.ts +0 -103
  288. package/src/tools/writeFileTool.ts +0 -167
  289. package/src/ui/BrandSplash.tsx +0 -133
  290. package/src/ui/terminalTitle.ts +0 -30
  291. package/src/utils/images.ts +0 -140
  292. package/src/utils/markdownSegments.ts +0 -51
  293. package/src/utils/messages.ts +0 -37
  294. package/src/utils/withRetry.ts +0 -324
  295. /package/src/identity/{hub → manager}/continuity/state.ts +0 -0
  296. /package/src/identity/{hub → manager}/custody/helpers.ts +0 -0
  297. /package/src/identity/{hub → manager}/custody/preflight.ts +0 -0
  298. /package/src/identity/{hub → manager}/custody/state.ts +0 -0
  299. /package/src/identity/{hub → manager}/custody/useCustodyFlow.tsx +0 -0
  300. /package/src/identity/{hub → manager}/ens/EnsEditFlow.tsx +0 -0
  301. /package/src/identity/{hub → manager}/ens/advancedEnsValidation.ts +0 -0
  302. /package/src/identity/{hub → manager}/ens/state.ts +0 -0
  303. /package/src/identity/{hub → manager}/ens/transactions.ts +0 -0
  304. /package/src/identity/{hub → manager}/ens/types.ts +0 -0
  305. /package/src/identity/{hub → manager}/profile/identity.ts +0 -0
  306. /package/src/identity/{hub → manager}/restore/envelopes.ts +0 -0
  307. /package/src/identity/{hub → manager}/restore/helpers.ts +0 -0
  308. /package/src/identity/{hub → manager}/restore/recovery.ts +0 -0
  309. /package/src/identity/{hub → manager}/restore/resolve.ts +0 -0
  310. /package/src/identity/{hub → manager}/shared/components/BusyScreen.tsx +0 -0
  311. /package/src/identity/{hub → manager}/shared/components/NetworkScreen.tsx +0 -0
  312. /package/src/identity/{hub → manager}/shared/components/PinataJwtInput.tsx +0 -0
  313. /package/src/identity/{hub → manager}/shared/effects/receipts.ts +0 -0
  314. /package/src/identity/{hub → manager}/shared/effects/sync.ts +0 -0
  315. /package/src/identity/{hub → manager}/shared/model/format.ts +0 -0
  316. /package/src/identity/{hub → manager}/shared/operatorWallets.ts +0 -0
  317. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/ownership.ts +0 -0
  318. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/types.ts +0 -0
  319. /package/src/identity/{hub → manager}/shared/reconciliation/walletSetup.ts +0 -0
  320. /package/src/identity/{hub → manager}/shared/txGuard.ts +0 -0
  321. /package/src/identity/{hub → manager}/transfer/progress.ts +0 -0
  322. /package/src/identity/{hub → manager}/transfer/state.ts +0 -0
@@ -1,31 +1,3 @@
1
- import { config } from './state.js'
2
- import type { WalletConfig, WalletTx } from './types.js'
3
- import { CANCEL_CLOSE_DELAY_MS, CLOSE_DELAY_MS, TX_CLOSE_DELAY_MS } from './constants.js'
4
- import { shortAddr } from './copy.js'
5
- import {
6
- applyFlowChrome,
7
- approve,
8
- cancel,
9
- clearLastWalletError,
10
- currentState,
11
- errorSlot,
12
- getLastWalletError,
13
- initializeViewElements,
14
- setState,
15
- showPreparedMessage,
16
- statusHint,
17
- statusText,
18
- } from './view.js'
19
- import { serializeWalletError } from './errorView.js'
20
- import {
21
- buildTxParams,
22
- clearCurrentWalletMethod,
23
- currentWalletMethod,
24
- setActiveEthereum,
25
- waitForEthereumProvider,
26
- walletRequest,
27
- } from './walletProvider.js'
28
-
29
1
  let closeCountdown: ReturnType<typeof setInterval> | null = null
30
2
  let handlersAttached = false
31
3
 
@@ -162,13 +134,13 @@ export async function cancelFlow(): Promise<void> {
162
134
  } else {
163
135
  await post("/cancel", {}).catch(() => { });
164
136
  }
165
- setState("done");
166
- statusText.textContent = lastWalletError ? "Aborted · returning" : "Cancelled · returning";
137
+ setState("cancelled");
138
+ statusText.textContent = lastWalletError ? "Aborted" : "Cancelled";
167
139
  closeSoon(CANCEL_CLOSE_DELAY_MS);
168
140
  }
169
141
 
170
142
  function escapeAllowed(): boolean {
171
- return currentState !== "submitting" && currentState !== "done";
143
+ return currentState !== "submitting" && currentState !== "done" && currentState !== "cancelled";
172
144
  }
173
145
 
174
146
  export function startSessionMode(): void {
@@ -199,7 +171,7 @@ export function startSessionMode(): void {
199
171
  events.close();
200
172
  __sessionMode = false;
201
173
  setState("done");
202
- statusText.textContent = "All set · Returning";
174
+ statusText.textContent = "All set";
203
175
  closeSoon();
204
176
  });
205
177
  events.onerror = () => {
@@ -210,42 +182,3 @@ export function startSessionMode(): void {
210
182
  showReconnecting(true);
211
183
  };
212
184
  }
213
-
214
- function attachWalletHandlers(): void {
215
- if (handlersAttached) return
216
- handlersAttached = true
217
- approve.onclick = runWalletFlow
218
- cancel.onclick = cancelFlow
219
- window.addEventListener('keydown', (e) => {
220
- if (e.key === 'Escape') {
221
- if (!escapeAllowed()) { e.preventDefault(); return }
222
- e.preventDefault()
223
- cancelFlow()
224
- } else if (e.key === 'Enter') {
225
- if (!approve.hidden && !approve.disabled) { e.preventDefault(); runWalletFlow(); return }
226
- }
227
- })
228
- }
229
-
230
- export function bootWallet(): void {
231
- initializeViewElements()
232
- attachWalletHandlers()
233
- applyFlowChrome()
234
- if (!window.__WALLET_PREVIEW__) {
235
- if (document.readyState === 'loading') {
236
- document.addEventListener('DOMContentLoaded', bootWallet, { once: true })
237
- } else {
238
- if (config && config.kind === 'session-wait') {
239
- startSessionMode()
240
- } else {
241
- runWalletFlow()
242
- }
243
- }
244
- } else {
245
- window.__walletPreview = {
246
- setState,
247
- setConfig: (c: Partial<WalletConfig>) => { Object.assign(config, c); applyFlowChrome() },
248
- }
249
- runWalletFlow()
250
- }
251
- }
@@ -1,47 +1,57 @@
1
- import { WALLET_CSS } from './styles/index.js'
2
-
3
1
  export const CARD_HTML = `
4
- <canvas id="grainient" class="grainient-canvas" aria-hidden="true"></canvas>
5
2
  <main data-flow="sign" id="card">
6
- <div class="chrome">
7
- <span class="chrome-spacer"></span>
8
- <span class="chrome-title" id="chrome-title">ethagent</span>
9
- <span class="chrome-actions"></span>
10
- </div>
11
- <div class="body">
12
- <div class="splash-wrap"><pre class="splash" id="splash"></pre></div>
13
- <div class="head"><span class="label" id="prompt-text">signature request</span></div>
14
- <h2 class="flow-title" id="flow-title">Sign Message</h2>
15
- <ol class="timeline" id="timeline" hidden aria-label="Wallet flow steps"></ol>
16
- <div class="details" id="details-block">
17
- <p class="flow-detail" id="flow-detail">
18
- <span class="key" id="detail-key">message</span>
19
- <span id="detail-val"></span>
20
- </p>
3
+ <div class="card-inner" id="card-inner">
4
+ <div class="chrome">
5
+ <span class="chrome-brand"></span>
6
+ <span class="chrome-title" id="chrome-title"></span>
7
+ <span class="chrome-actions"></span>
21
8
  </div>
22
- <div class="status" id="status-block">
23
- <p class="status-line">
24
- <span class="marker" id="status-marker"></span>
25
- <span id="status-text">Connecting to your wallet…</span>
26
- </p>
27
- <p class="status-hint" id="status-hint">Open your wallet extension if it doesn't pop up automatically.</p>
28
- <p class="status-hint" id="reconnect-hint" hidden>Reconnecting to terminal…</p>
9
+ <div class="body">
10
+ <div class="card-header">
11
+ <h2 class="flow-title" id="flow-title">Sign Message</h2>
12
+ <p class="flow-subtitle" id="flow-subtitle"></p>
13
+ </div>
14
+ <div class="timeline" id="timeline" hidden>
15
+ <div class="timeline-head">
16
+ <span class="timeline-now" id="timeline-now"></span>
17
+ <span class="timeline-count" id="timeline-count"></span>
18
+ </div>
19
+ <div class="timeline-track" id="timeline-track"></div>
20
+ </div>
21
+ <div class="details" id="details-block">
22
+ <p class="flow-detail" id="flow-detail">
23
+ <span class="key" id="detail-key">message</span>
24
+ <span id="detail-val"></span>
25
+ </p>
26
+ </div>
27
+ <div class="status" id="status-block">
28
+ <p class="status-line">
29
+ <span class="marker" id="status-marker"></span>
30
+ <span id="status-text">Connecting to your wallet…</span>
31
+ </p>
32
+ <p class="status-hint" id="status-hint">Open your wallet extension if it doesn't pop up automatically.</p>
33
+ <p class="status-hint" id="reconnect-hint" hidden>Reconnecting to terminal…</p>
34
+ </div>
35
+ <div id="error-block-slot"></div>
29
36
  </div>
30
- <div id="error-block-slot"></div>
31
- </div>
32
- <div class="footer">
33
- <span class="net-pill" id="network-row"><span class="dot"></span><span id="net-val">Sepolia</span></span>
34
- <div class="actions">
35
- <button id="cancel" class="shortcut"><span class="key">esc</span><span>cancel</span></button>
36
- <button id="approve" class="shortcut primary" hidden>
37
- <span class="key">enter</span><span>retry</span>
38
- </button>
37
+ <div class="footer">
38
+ <div class="actions">
39
+ <button id="cancel" class="shortcut"><span class="key">esc</span><span>cancel</span></button>
40
+ <button id="approve" class="shortcut primary" hidden>
41
+ <span class="key">enter</span><span>retry</span>
42
+ </button>
43
+ </div>
39
44
  </div>
40
45
  </div>
41
46
  </main>
42
47
  `;
43
48
 
44
49
  export function injectStylesAndMarkup(): void {
50
+ const font = document.createElement("link");
51
+ font.rel = "stylesheet";
52
+ font.href = "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap";
53
+ document.head.appendChild(font);
54
+
45
55
  const style = document.createElement("style");
46
56
  style.id = "wallet-styles";
47
57
  style.textContent = WALLET_CSS;
@@ -1,6 +1,3 @@
1
- import type { WalletTx } from './types.js'
2
- import { WALLET_PROVIDER_POLL_MS, WALLET_PROVIDER_WAIT_MS } from './constants.js'
3
-
4
1
  let announcedEthereum: any = null;
5
2
  let activeEthereum: any = null;
6
3
 
@@ -0,0 +1,95 @@
1
+ // Smoothly animates the card's height whenever its content changes, so the
2
+ // surface glides between states instead of snapping. The animation is the
3
+ // native Web Animations API, with no external library, so it stays lightweight
4
+ // and runs the same on every machine. It falls back to an instant resize when
5
+ // the API is unavailable or the user prefers reduced motion.
6
+
7
+ let cardEl: HTMLElement | null = null;
8
+ let cardInnerEl: HTMLElement | null = null;
9
+ let resizeAnim: Animation | null = null;
10
+ let trackedHeight = 0;
11
+ let measuredOnce = false;
12
+ let cardResizeReady = false;
13
+
14
+ // Snappy ease-out (mirrors --ease-out in css.ts): quick to start, gentle to settle.
15
+ const RESIZE_DURATION_MS = 200;
16
+ const RESIZE_EASING = "cubic-bezier(0.16, 1, 0.3, 1)";
17
+
18
+ function prefersReducedMotion(): boolean {
19
+ try {
20
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
21
+ } catch (_) {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ function cardHeightCap(): number {
27
+ const compact = window.matchMedia("(max-width: 560px), (max-height: 680px)").matches;
28
+ const margin = compact ? 20 : 32;
29
+ return Math.max(160, window.innerHeight - margin);
30
+ }
31
+
32
+ function naturalHeight(): number {
33
+ if (!cardInnerEl) return 0;
34
+ return Math.min(cardInnerEl.offsetHeight, cardHeightCap());
35
+ }
36
+
37
+ function applyHeight(px: number): void {
38
+ if (cardEl) cardEl.style.height = Math.round(px) + "px";
39
+ }
40
+
41
+ function settleToContent(): void {
42
+ if (!cardEl || !cardInnerEl) return;
43
+ const target = naturalHeight();
44
+ if (!measuredOnce) {
45
+ measuredOnce = true;
46
+ trackedHeight = target;
47
+ applyHeight(target);
48
+ return;
49
+ }
50
+ if (Math.abs(target - trackedHeight) < 1) return;
51
+ const from = cardEl.getBoundingClientRect().height || trackedHeight;
52
+ trackedHeight = target;
53
+ animateHeight(from, target);
54
+ }
55
+
56
+ function animateHeight(from: number, to: number): void {
57
+ const el = cardEl;
58
+ if (!el) return;
59
+ if (resizeAnim) {
60
+ try { resizeAnim.cancel(); } catch (_) { /* noop */ }
61
+ resizeAnim = null;
62
+ }
63
+ // The rounded inline height is the source of truth: set it first so the card
64
+ // rests at the final size once the animation ends (default fill is none).
65
+ applyHeight(to);
66
+ if (typeof el.animate !== "function" || prefersReducedMotion() || Math.abs(to - from) < 1) return;
67
+ const anim = el.animate(
68
+ [{ height: Math.round(from) + "px" }, { height: Math.round(to) + "px" }],
69
+ { duration: RESIZE_DURATION_MS, easing: RESIZE_EASING }
70
+ );
71
+ resizeAnim = anim;
72
+ const clear = (): void => { if (resizeAnim === anim) resizeAnim = null; };
73
+ anim.onfinish = clear;
74
+ anim.oncancel = clear;
75
+ }
76
+
77
+ export function setupCardResize(): void {
78
+ if (cardResizeReady) return;
79
+ cardEl = document.getElementById("card");
80
+ cardInnerEl = document.getElementById("card-inner");
81
+ if (!cardEl || !cardInnerEl || typeof ResizeObserver === "undefined") return;
82
+ cardResizeReady = true;
83
+ settleToContent();
84
+ let scheduled = false;
85
+ const observer = new ResizeObserver(() => {
86
+ if (scheduled) return;
87
+ scheduled = true;
88
+ requestAnimationFrame(() => {
89
+ scheduled = false;
90
+ settleToContent();
91
+ });
92
+ });
93
+ observer.observe(cardInnerEl);
94
+ window.addEventListener("resize", () => settleToContent());
95
+ }
@@ -1,9 +1,136 @@
1
- import type { WalletConfig } from './types.js'
2
-
3
- export const config: WalletConfig =
4
- (window.__WALLET_CONFIG__ as WalletConfig) || {
5
- sessionToken: 'preview',
6
- kind: 'sign',
7
- chainIdHex: '0xaa36a7',
8
- message: 'identity proof for 0x9F2a???BC4e',
1
+ function spinnerText(value: string): string {
2
+ const text = preserveProtocolCaps(value);
3
+ return text.replace(/^(\s*)([a-z])/, (_match, prefix, letter) => `${prefix}${letter.toUpperCase()}`);
4
+ }
5
+ function spinnerHintText(value: string): string { return preserveProtocolCaps(value); }
6
+ function preserveProtocolCaps(value: string): string {
7
+ return String(value || "")
8
+ .replace(/\bapi\b/gi, "API")
9
+ .replace(/\bens\b/gi, "ENS")
10
+ .replace(/\berc-8004\b/gi, "ERC-8004")
11
+ .replace(/\bgguf\b/gi, "GGUF")
12
+ .replace(/\bhugging face\b/gi, "Hugging Face")
13
+ .replace(/\bipfs\b/gi, "IPFS")
14
+ .replace(/\bjson\b/gi, "JSON")
15
+ .replace(/\bjwt\b/gi, "JWT")
16
+ .replace(/\bmemory\.md\b/gi, "MEMORY.md")
17
+ .replace(/\bopenai\b/gi, "OpenAI")
18
+ .replace(/\banthropic\b/gi, "Anthropic")
19
+ .replace(/\bgemini\b/gi, "Gemini")
20
+ .replace(/\bos\b/gi, "OS")
21
+ .replace(/\brpc\b/gi, "RPC")
22
+ .replace(/\bsoul\.md\b/gi, "SOUL.md")
23
+ .replace(/\buri\b/gi, "URI")
24
+ .replace(/\burl\b/gi, "URL");
25
+ }
26
+
27
+ function setStatus(marker: string, text: string, hint: string, spin: boolean): void {
28
+ const lineEl = statusText.parentElement as HTMLElement;
29
+ const hintEl = statusHint;
30
+ const displayText = spin ? spinnerText(text) : text;
31
+ const displayHint = spin ? spinnerHintText(hint) : hint;
32
+ const apply = () => {
33
+ if (spin) startSpinner();
34
+ else setMarker(marker);
35
+ statusText.textContent = displayText;
36
+ hintEl.textContent = displayHint;
37
+ requestAnimationFrame(() => {
38
+ lineEl.classList.remove("is-changing");
39
+ hintEl.classList.remove("is-changing");
40
+ });
41
+ };
42
+ if (statusText.textContent === displayText && hintEl.textContent === displayHint) {
43
+ if (spin) startSpinner();
44
+ else setMarker(marker);
45
+ return;
46
+ }
47
+ lineEl.classList.add("is-changing");
48
+ hintEl.classList.add("is-changing");
49
+ setTimeout(apply, 260);
50
+ }
51
+
52
+ export let currentState: string | null = null;
53
+
54
+ export function setState(state: string, payload?: any): void {
55
+ payload = payload || {};
56
+ currentState = state;
57
+ errorSlot.innerHTML = "";
58
+ statusBlock.style.display = "flex";
59
+ statusBlock.dataset.tone = state === "done" ? "success" : state === "cancelled" ? "cancelled" : "pending";
60
+ const terminal = state === "done" || state === "cancelled";
61
+ const cardEl = document.getElementById("card");
62
+ if (cardEl) cardEl.dataset.phase = terminal ? "terminal" : "active";
63
+ setTabTitle(tabTitleForState(state));
64
+ applyTransferTimeline();
65
+ switch (state) {
66
+ case "connecting":
67
+ setStatus("·", "Connecting To Wallet...", "Open your wallet if needed.", true);
68
+ break;
69
+ case "approve":
70
+ if (config.kind === "account") {
71
+ const copy = accountCopy();
72
+ setStatus("·", copy.text, copy.hint, true);
73
+ } else if (config.kind === "sign") {
74
+ const sigCopy = signCopy();
75
+ setStatus("·", sigCopy.text, sigCopy.hint, true);
76
+ } else {
77
+ const txCopy = transactionCopy();
78
+ setStatus("·", txCopy.text, txCopy.hint, true);
79
+ }
80
+ break;
81
+ case "approve-sign":
82
+ {
83
+ const sigCopy = signCopy();
84
+ setStatus("·", sigCopy.text, sigCopy.hint, true);
85
+ }
86
+ break;
87
+ case "preparing-transaction":
88
+ setStatus("·", purposeCopy().prepare!.text, purposeCopy().prepare!.hint, true);
89
+ break;
90
+ case "approve-transaction":
91
+ {
92
+ const txCopy = transactionCopy();
93
+ setStatus("·", txCopy.text, txCopy.hint, true);
94
+ }
95
+ break;
96
+ case "submitting":
97
+ if (config.kind === "account") setStatus("·", "Connecting Wallet...", "Returning to terminal.", true);
98
+ else if (config.kind === "sign") setStatus("·", "Verifying Signature...", hasNextLifecyclePrompt() ? nextLifecycleHint() : "Returning to terminal.", true);
99
+ else setStatus("·", "Submitted · Waiting For Confirmation...", "Your wallet accepted the transaction.", true);
100
+ break;
101
+ case "done":
102
+ stopSpinner();
103
+ statusMarker.innerHTML =
104
+ '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"' +
105
+ ' stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
106
+ '<polyline points="20 6 9 17 4 12"></polyline></svg>';
107
+ statusText.textContent =
108
+ config.kind === "account" ? "Connected"
109
+ : config.kind === "sign" ? "Signed"
110
+ : "Submitted";
111
+ statusHint.textContent = payload.txHash
112
+ ? (isTransactionFlow() ? "Transaction submitted. Returning." : "This tab will close shortly.")
113
+ : hasNextLifecyclePrompt() ? nextLifecycleHint() : "This tab will close shortly.";
114
+ markActiveTimelineStepDone();
115
+ break;
116
+ case "cancelled":
117
+ stopSpinner();
118
+ statusMarker.innerHTML = "";
119
+ break;
120
+ case "error":
121
+ stopSpinner();
122
+ statusBlock.style.display = "none";
123
+ renderError(payload);
124
+ break;
9
125
  }
126
+ }
127
+
128
+ let lastWalletError: WalletErrorPayload | null = null;
129
+
130
+ function renderError(payload: WalletErrorPayload): void {
131
+ errorSlot.innerHTML = walletErrorHtml(payload);
132
+ lastWalletError = payload;
133
+ }
134
+
135
+ export function getLastWalletError(): WalletErrorPayload | null { return lastWalletError }
136
+ export function clearLastWalletError(): void { lastWalletError = null }
@@ -0,0 +1,161 @@
1
+ type LifecycleId =
2
+ | "ens-clear"
3
+ | "ens-link"
4
+ | "ens-update"
5
+ | "ens-register"
6
+ | "custody-switch"
7
+ | "public-profile-vault";
8
+
9
+ const LIFECYCLE_DEFINITIONS: Record<LifecycleId, { steps: string[] }> = {
10
+ "ens-clear": { steps: ["Clear Records on Mainnet", "Save Cleared Snapshot"] },
11
+ "ens-link": { steps: ["Create Subdomain", "Set Records", "Save Snapshot"] },
12
+ "ens-update": { steps: ["Update Records on Mainnet", "Save Updated Snapshot"] },
13
+ "ens-register": { steps: ["Commit ENS Name", "Register ENS Name"] },
14
+ "custody-switch": { steps: ["Deploy Vault", "Deposit Token", "Reconcile Operators"] },
15
+ "public-profile-vault": { steps: ["Sign Profile", "Save Through Vault"] },
16
+ };
17
+
18
+ const FLOW_LIFECYCLE: Record<string, LifecycleId> = {
19
+ "ens-clear": "ens-clear",
20
+ "ens-link": "ens-link",
21
+ "ens-update": "ens-update",
22
+ "ens-register": "ens-register",
23
+ "custody-switch": "custody-switch",
24
+ "public-profile-vault": "public-profile-vault",
25
+ };
26
+
27
+ const PURPOSE_TIMELINE: Record<string, readonly [string, string]> = {
28
+ "create-agent": ["Sign Recovery Access", "Mint Token"],
29
+ "update-snapshot-owner": ["Sign Snapshot", "Save Onchain"],
30
+ "update-snapshot-operator": ["Sign Snapshot", "Save Onchain"],
31
+ "update-snapshot-connected": ["Sign Snapshot", "Save Onchain"],
32
+ "update-profile-owner": ["Sign Profile", "Save Onchain"],
33
+ "update-profile-operator": ["Sign Profile", "Save Onchain"],
34
+ "update-profile-connected": ["Sign Profile", "Save Onchain"],
35
+ "update-operators": ["Sign Operator List", "Publish List"],
36
+ "create-simple-ens-subdomain": ["Sign Request", "Create Subdomain"],
37
+ "set-simple-ens-records": ["Sign Records", "Write Records"],
38
+ "create-agent-ens-subdomain": ["Sign Request", "Create Subdomain"],
39
+ "set-agent-ens-records": ["Sign Records", "Write Records"],
40
+ "rotate-agent-uri-vault-owner": ["Sign", "Save"],
41
+ "rotate-agent-uri-vault-operator": ["Sign", "Save"],
42
+ "update-ens": ["Sign Snapshot", "Save Onchain"],
43
+ "clear-ens": ["Sign Snapshot", "Save Onchain"],
44
+ };
45
+
46
+ function activeLifecycle(): LifecycleId | undefined {
47
+ if (config.flowId && FLOW_LIFECYCLE[config.flowId]) return FLOW_LIFECYCLE[config.flowId];
48
+ return undefined;
49
+ }
50
+
51
+ let currentTimelineKey: string | null = null;
52
+
53
+ function lifecycleStepIndex(lifecycle: LifecycleId, state: string | null): number {
54
+ const flowStep = typeof config.flowStep === "number" ? config.flowStep : 1;
55
+ const def = LIFECYCLE_DEFINITIONS[lifecycle];
56
+ const steps = def.steps.length;
57
+ if (state === "done") return Math.min(flowStep, steps);
58
+ return Math.max(0, Math.min(flowStep - 1, steps - 1));
59
+ }
60
+
61
+ function hasNextLifecyclePrompt(): boolean {
62
+ const lifecycle = activeLifecycle();
63
+ if (!lifecycle) return false;
64
+ const flowStep = typeof config.flowStep === "number" ? config.flowStep : 1;
65
+ return flowStep < LIFECYCLE_DEFINITIONS[lifecycle].steps.length;
66
+ }
67
+
68
+ function nextLifecycleHint(): string {
69
+ return "Keep this page open. The next wallet step will appear here.";
70
+ }
71
+
72
+ function purposeStepIndex(state: string | null): number {
73
+ if (state === "approve-transaction" || state === "submitting") return 1;
74
+ if (state === "done") return 2;
75
+ return 0;
76
+ }
77
+
78
+ export function applyTransferTimeline(): void {
79
+ const timeline = document.getElementById("timeline") as HTMLElement | null;
80
+ if (!timeline) return;
81
+
82
+ if (currentState === "error" || currentState === "cancelled") {
83
+ hideTimeline(timeline);
84
+ return;
85
+ }
86
+
87
+ const lifecycle = activeLifecycle();
88
+ let steps: string[] | null = null;
89
+ let activeIndex = 0;
90
+ let key = "";
91
+
92
+ if (lifecycle) {
93
+ steps = LIFECYCLE_DEFINITIONS[lifecycle].steps;
94
+ activeIndex = lifecycleStepIndex(lifecycle, currentState);
95
+ key = "flow:" + lifecycle;
96
+ } else if (config.kind === "sign-transaction") {
97
+ const tuple = PURPOSE_TIMELINE[config.purpose || ""] || (["Sign", "Submit"] as const);
98
+ steps = [tuple[0], tuple[1]];
99
+ activeIndex = purposeStepIndex(currentState);
100
+ key = "purpose:" + (config.purpose || "");
101
+ }
102
+
103
+ if (!steps) {
104
+ hideTimeline(timeline);
105
+ return;
106
+ }
107
+
108
+ currentTimelineKey = key;
109
+ timeline.hidden = false;
110
+
111
+ const total = steps.length;
112
+ const currentIndex = Math.min(activeIndex, total - 1);
113
+ const stepNumber = Math.min(activeIndex + 1, total);
114
+
115
+ const now = document.getElementById("timeline-now");
116
+ if (now) now.textContent = steps[currentIndex] ?? "";
117
+ const count = document.getElementById("timeline-count");
118
+ if (count) count.textContent = pad(stepNumber) + " / " + pad(total);
119
+ renderTimelineSegments(total, activeIndex);
120
+ }
121
+
122
+ function hideTimeline(timeline: HTMLElement): void {
123
+ if (!timeline.hidden) timeline.hidden = true;
124
+ currentTimelineKey = null;
125
+ const track = document.getElementById("timeline-track");
126
+ if (track) track.innerHTML = "";
127
+ }
128
+
129
+ function renderTimelineSegments(total: number, activeIndex: number): void {
130
+ const track = document.getElementById("timeline-track");
131
+ if (!track) return;
132
+ if (track.childElementCount !== total) {
133
+ track.innerHTML = "";
134
+ for (let i = 0; i < total; i++) {
135
+ const seg = document.createElement("span");
136
+ seg.className = "timeline-seg";
137
+ track.appendChild(seg);
138
+ }
139
+ }
140
+ const isDone = currentState === "done";
141
+ const children = track.children;
142
+ for (let i = 0; i < children.length; i++) {
143
+ const seg = children[i] as HTMLElement;
144
+ const done = i < activeIndex;
145
+ const active = i === activeIndex && !isDone;
146
+ seg.className = "timeline-seg" + (done ? " is-done" : active ? " is-active" : "");
147
+ }
148
+ }
149
+
150
+ function pad(value: number): string {
151
+ return String(value).padStart(2, "0");
152
+ }
153
+
154
+ function markActiveTimelineStepDone(): void {
155
+ const track = document.getElementById("timeline-track");
156
+ if (!track) return;
157
+ const segs = track.querySelectorAll(".timeline-seg.is-active");
158
+ for (let i = 0; i < segs.length; i++) {
159
+ (segs[i] as HTMLElement).className = "timeline-seg is-done";
160
+ }
161
+ }