ethagent 1.1.2 → 2.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 (268) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +126 -30
  3. package/package.json +7 -2
  4. package/src/app/FirstRun.tsx +190 -146
  5. package/src/app/FirstRunTimeline.tsx +47 -0
  6. package/src/app/input/AppInputProvider.tsx +1 -1
  7. package/src/app/keybindings/KeybindingProvider.tsx +1 -1
  8. package/src/chat/ChatBottomPane.tsx +0 -1
  9. package/src/chat/ChatInput.tsx +6 -6
  10. package/src/chat/ChatScreen.tsx +35 -15
  11. package/src/chat/ContextLimitView.tsx +4 -4
  12. package/src/chat/ContinuityEditReviewView.tsx +10 -22
  13. package/src/chat/CopyPicker.tsx +0 -1
  14. package/src/chat/MessageList.tsx +62 -45
  15. package/src/chat/PermissionPrompt.tsx +13 -9
  16. package/src/chat/PlanApprovalView.tsx +3 -3
  17. package/src/chat/ResumeView.tsx +1 -4
  18. package/src/chat/RewindView.tsx +2 -2
  19. package/src/chat/chatInputState.ts +1 -1
  20. package/src/chat/chatScreenUtils.ts +22 -11
  21. package/src/chat/chatSessionState.ts +2 -2
  22. package/src/chat/chatTurnOrchestrator.ts +16 -81
  23. package/src/chat/commands.ts +1 -1
  24. package/src/chat/textCursor.ts +1 -1
  25. package/src/chat/transcriptViewport.ts +2 -7
  26. package/src/cli/ResetConfirmView.tsx +1 -1
  27. package/src/cli/main.tsx +9 -3
  28. package/src/cli/preview.tsx +0 -5
  29. package/src/cli/updateNotice.ts +4 -2
  30. package/src/identity/continuity/editor.ts +7 -107
  31. package/src/identity/continuity/envelope.ts +1048 -40
  32. package/src/identity/continuity/history.ts +4 -4
  33. package/src/identity/continuity/localBackup.ts +249 -0
  34. package/src/identity/continuity/privateEdit/apply.ts +170 -0
  35. package/src/identity/continuity/privateEdit/diff.ts +82 -0
  36. package/src/identity/continuity/privateEdit/files.ts +23 -0
  37. package/src/identity/continuity/privateEdit/types.ts +28 -0
  38. package/src/identity/continuity/privateEdit.ts +10 -298
  39. package/src/identity/continuity/publicSkills.ts +8 -9
  40. package/src/identity/continuity/snapshots.ts +17 -6
  41. package/src/identity/continuity/storage/defaults.ts +111 -0
  42. package/src/identity/continuity/storage/files.ts +72 -0
  43. package/src/identity/continuity/storage/markdown.ts +81 -0
  44. package/src/identity/continuity/storage/paths.ts +24 -0
  45. package/src/identity/continuity/storage/scaffold.ts +124 -0
  46. package/src/identity/continuity/storage/status.ts +86 -0
  47. package/src/identity/continuity/storage/types.ts +27 -0
  48. package/src/identity/continuity/storage.ts +32 -507
  49. package/src/identity/continuity/zipWriter.ts +95 -0
  50. package/src/identity/crypto/backupEnvelope.ts +14 -247
  51. package/src/identity/crypto/eth.ts +7 -7
  52. package/src/identity/ens/agentRecords.ts +96 -0
  53. package/src/identity/ens/ensAutomation/contracts.ts +38 -0
  54. package/src/identity/ens/ensAutomation/delete.ts +80 -0
  55. package/src/identity/ens/ensAutomation/names.ts +14 -0
  56. package/src/identity/ens/ensAutomation/operators.ts +29 -0
  57. package/src/identity/ens/ensAutomation/read.ts +114 -0
  58. package/src/identity/ens/ensAutomation/root.ts +63 -0
  59. package/src/identity/ens/ensAutomation/setup.ts +284 -0
  60. package/src/identity/ens/ensAutomation/transactions.ts +107 -0
  61. package/src/identity/ens/ensAutomation/types.ts +126 -0
  62. package/src/identity/ens/ensAutomation.ts +29 -0
  63. package/src/identity/ens/ensLookup/client.ts +43 -0
  64. package/src/identity/ens/ensLookup/constants.ts +26 -0
  65. package/src/identity/ens/ensLookup/discovery.ts +70 -0
  66. package/src/identity/ens/ensLookup/names.ts +34 -0
  67. package/src/identity/ens/ensLookup/records.ts +45 -0
  68. package/src/identity/ens/ensLookup/resolve.ts +75 -0
  69. package/src/identity/ens/ensLookup/tokenReference.ts +17 -0
  70. package/src/identity/ens/ensLookup/types.ts +38 -0
  71. package/src/identity/ens/ensLookup/validation.ts +72 -0
  72. package/src/identity/ens/ensLookup.ts +19 -0
  73. package/src/identity/ens/ensRegistration.ts +199 -0
  74. package/src/identity/ens/resolverDelegation.ts +48 -0
  75. package/src/identity/hub/IdentityHub.tsx +13 -817
  76. package/src/identity/hub/OperationalRoutes.tsx +370 -0
  77. package/src/identity/hub/Routes.tsx +361 -0
  78. package/src/identity/hub/advancedEnsValidation.ts +45 -0
  79. package/src/identity/hub/{screens → components}/DetailsScreen.tsx +14 -8
  80. package/src/identity/hub/{screens → components}/ErrorScreen.tsx +15 -5
  81. package/src/identity/hub/components/FlowTimeline.tsx +27 -0
  82. package/src/identity/hub/components/IdentitySummary.tsx +190 -0
  83. package/src/identity/hub/components/MenuScreen.tsx +237 -0
  84. package/src/identity/hub/{screens → components}/NetworkScreen.tsx +3 -3
  85. package/src/identity/hub/{screens/RebackupStorageScreen.tsx → components/PinataJwtInput.tsx} +21 -18
  86. package/src/identity/hub/components/UnlinkedIdentityScreen.tsx +76 -0
  87. package/src/identity/hub/{screens → components}/WalletApprovalScreen.tsx +9 -8
  88. package/src/identity/hub/components/menuFlagsFromReconciliation.ts +68 -0
  89. package/src/identity/hub/effects/create.ts +310 -0
  90. package/src/identity/hub/effects/ens/flows.ts +218 -0
  91. package/src/identity/hub/effects/ens/index.ts +11 -0
  92. package/src/identity/hub/effects/ens/transactions.ts +239 -0
  93. package/src/identity/hub/effects/index.ts +74 -0
  94. package/src/identity/hub/effects/profile/profileState.ts +173 -0
  95. package/src/identity/hub/effects/publicProfile/index.ts +5 -0
  96. package/src/identity/hub/effects/publicProfile/runPublicProfileSave.ts +646 -0
  97. package/src/identity/hub/effects/rebackup/index.ts +7 -0
  98. package/src/identity/hub/effects/rebackup/operatorVault.ts +378 -0
  99. package/src/identity/hub/effects/rebackup/runRebackup.ts +451 -0
  100. package/src/identity/hub/effects/receipts.ts +46 -0
  101. package/src/identity/hub/effects/restore/apply.ts +112 -0
  102. package/src/identity/hub/effects/restore/auth.ts +159 -0
  103. package/src/identity/hub/effects/restore/discover.ts +86 -0
  104. package/src/identity/hub/effects/restore/envelopes.ts +21 -0
  105. package/src/identity/hub/effects/restore/fetch.ts +25 -0
  106. package/src/identity/hub/effects/restore/index.ts +22 -0
  107. package/src/identity/hub/effects/restore/recovery.ts +135 -0
  108. package/src/identity/hub/effects/restore/resolve.ts +102 -0
  109. package/src/identity/hub/effects/restore/restoreEffects.ts +22 -0
  110. package/src/identity/hub/effects/restore/shared.ts +91 -0
  111. package/src/identity/hub/effects/restoreAdmin.ts +93 -0
  112. package/src/identity/hub/effects/shared/profilePrep.ts +139 -0
  113. package/src/identity/hub/effects/shared/snapshot.ts +336 -0
  114. package/src/identity/hub/effects/shared/sync.ts +190 -0
  115. package/src/identity/hub/effects/token-transfer/index.ts +6 -0
  116. package/src/identity/hub/effects/token-transfer/progress.ts +59 -0
  117. package/src/identity/hub/effects/token-transfer/runTokenTransfer.ts +299 -0
  118. package/src/identity/hub/effects/types.ts +53 -0
  119. package/src/identity/hub/effects/vault/preflight.ts +50 -0
  120. package/src/identity/hub/flows/continuity/ContinuityDashboardScreen.tsx +170 -0
  121. package/src/identity/hub/flows/continuity/RebackupStorageScreen.tsx +28 -0
  122. package/src/identity/hub/{screens → flows/continuity}/RecoveryConfirmScreen.tsx +28 -19
  123. package/src/identity/hub/flows/continuity/SavePromptScreen.tsx +49 -0
  124. package/src/identity/hub/{screens → flows/create}/CreateFlow.tsx +61 -62
  125. package/src/identity/hub/flows/custody/CustodyEditFlow.tsx +347 -0
  126. package/src/identity/hub/flows/custody/custodyEffects.ts +321 -0
  127. package/src/identity/hub/flows/custody/custodyFlowActions.ts +236 -0
  128. package/src/identity/hub/flows/custody/custodyFlowEffects.ts +163 -0
  129. package/src/identity/hub/flows/custody/custodyFlowHelpers.ts +25 -0
  130. package/src/identity/hub/flows/custody/custodyFlowRoutes.tsx +239 -0
  131. package/src/identity/hub/flows/custody/custodyFlowTypes.ts +45 -0
  132. package/src/identity/hub/flows/custody/useCustodyFlow.tsx +25 -0
  133. package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +336 -0
  134. package/src/identity/hub/flows/ens/EnsEditFlow.tsx +397 -0
  135. package/src/identity/hub/flows/ens/EnsEditMaintenanceScreens.tsx +332 -0
  136. package/src/identity/hub/flows/ens/EnsEditReviewScreens.tsx +471 -0
  137. package/src/identity/hub/flows/ens/EnsEditRunners.tsx +198 -0
  138. package/src/identity/hub/flows/ens/EnsEditShared.tsx +162 -0
  139. package/src/identity/hub/flows/ens/EnsEditSimpleScreens.tsx +518 -0
  140. package/src/identity/hub/flows/ens/IdentityHubEnsFlow.tsx +299 -0
  141. package/src/identity/hub/flows/ens/OperatorWalletsScreen.tsx +398 -0
  142. package/src/identity/hub/flows/ens/ensEditCopy.ts +117 -0
  143. package/src/identity/hub/flows/ens/ensEditTypes.ts +91 -0
  144. package/src/identity/hub/flows/profile/EditProfileFlow.tsx +271 -0
  145. package/src/identity/hub/flows/restore/RestoreFlow.tsx +324 -0
  146. package/src/identity/hub/flows/restore/useRestoreFlowEffects.ts +77 -0
  147. package/src/identity/hub/{screens → flows/settings}/StorageCredentialScreen.tsx +23 -44
  148. package/src/identity/hub/flows/token-transfer/IdentityHubTokenTransferFlow.tsx +162 -0
  149. package/src/identity/hub/flows/token-transfer/TokenTransferScreens.tsx +256 -0
  150. package/src/identity/hub/identityHubReducer.ts +164 -99
  151. package/src/identity/hub/model/continuity.ts +94 -0
  152. package/src/identity/hub/model/copy.ts +35 -0
  153. package/src/identity/hub/model/custody.ts +54 -0
  154. package/src/identity/hub/model/ens.ts +49 -0
  155. package/src/identity/hub/model/errors.ts +140 -0
  156. package/src/identity/hub/model/format.ts +15 -0
  157. package/src/identity/hub/model/identity.ts +94 -0
  158. package/src/identity/hub/model/network.ts +32 -0
  159. package/src/identity/hub/model/transfer.ts +57 -0
  160. package/src/identity/hub/operatorWallets.ts +131 -0
  161. package/src/identity/hub/reconciliation/agentReconciliation/hook.ts +46 -0
  162. package/src/identity/hub/reconciliation/agentReconciliation/ownership.ts +129 -0
  163. package/src/identity/hub/reconciliation/agentReconciliation/run.ts +302 -0
  164. package/src/identity/hub/reconciliation/agentReconciliation/types.ts +17 -0
  165. package/src/identity/hub/reconciliation/index.ts +21 -0
  166. package/src/identity/hub/reconciliation/useAgentReconciliation.ts +10 -0
  167. package/src/identity/hub/reconciliation/walletSetup.ts +220 -0
  168. package/src/identity/hub/txGuard.ts +51 -0
  169. package/src/identity/hub/types.ts +17 -0
  170. package/src/identity/hub/useIdentityHubContinuity.ts +136 -0
  171. package/src/identity/hub/useIdentityHubController.ts +396 -0
  172. package/src/identity/hub/useIdentityHubSideEffects.ts +309 -0
  173. package/src/identity/hub/utils.ts +79 -0
  174. package/src/identity/identityCompat.ts +34 -0
  175. package/src/identity/profile/agentIcon.ts +61 -0
  176. package/src/identity/profile/imagePicker.ts +12 -12
  177. package/src/identity/registry/erc8004/abi.ts +14 -0
  178. package/src/identity/registry/erc8004/chains.ts +150 -0
  179. package/src/identity/registry/erc8004/client.ts +11 -0
  180. package/src/identity/registry/erc8004/discovery.ts +511 -0
  181. package/src/identity/registry/erc8004/metadata.ts +335 -0
  182. package/src/identity/registry/erc8004/ownership.ts +121 -0
  183. package/src/identity/registry/erc8004/preflight.ts +123 -0
  184. package/src/identity/registry/erc8004/transactions.ts +77 -0
  185. package/src/identity/registry/erc8004/types.ts +88 -0
  186. package/src/identity/registry/erc8004/uri.ts +59 -0
  187. package/src/identity/registry/erc8004/utils.ts +58 -0
  188. package/src/identity/registry/erc8004.ts +53 -1106
  189. package/src/identity/registry/fieldParsers.ts +28 -0
  190. package/src/identity/registry/operatorVault/bytecode.ts +98 -0
  191. package/src/identity/registry/operatorVault/constants.ts +38 -0
  192. package/src/identity/registry/operatorVault/read.ts +246 -0
  193. package/src/identity/registry/operatorVault/transactions.ts +81 -0
  194. package/src/identity/registry/operatorVault.ts +44 -0
  195. package/src/identity/storage/ipfs.ts +26 -24
  196. package/src/identity/wallet/browserWallet/gas.ts +41 -0
  197. package/src/identity/wallet/browserWallet/html.ts +106 -0
  198. package/src/identity/wallet/browserWallet/http.ts +28 -0
  199. package/src/identity/wallet/browserWallet/requestServer.ts +106 -0
  200. package/src/identity/wallet/browserWallet/requests.ts +191 -0
  201. package/src/identity/wallet/browserWallet/session.ts +325 -0
  202. package/src/identity/wallet/browserWallet/types.ts +192 -0
  203. package/src/identity/wallet/browserWallet/validation.ts +74 -0
  204. package/src/identity/wallet/browserWallet.ts +30 -393
  205. package/src/identity/wallet/page/constants.ts +5 -0
  206. package/src/identity/wallet/page/controller.ts +251 -0
  207. package/src/identity/wallet/page/copy.ts +340 -0
  208. package/src/identity/wallet/page/grainient.ts +278 -0
  209. package/src/identity/wallet/page/html.ts +28 -0
  210. package/src/identity/wallet/page/markup.ts +50 -0
  211. package/src/identity/wallet/page/state.ts +9 -0
  212. package/src/identity/wallet/page/styles/base.ts +259 -0
  213. package/src/identity/wallet/page/styles/components.ts +262 -0
  214. package/src/identity/wallet/page/styles/index.ts +5 -0
  215. package/src/identity/wallet/page/styles/responsive.ts +247 -0
  216. package/src/identity/wallet/page/types.ts +47 -0
  217. package/src/identity/wallet/page/view.ts +535 -0
  218. package/src/identity/wallet/page/walletProvider.ts +70 -0
  219. package/src/identity/wallet/page.tsx +38 -0
  220. package/src/identity/wallet/walletPurposeCompat.ts +27 -0
  221. package/src/mcp/manager.ts +0 -1
  222. package/src/models/ModelPicker.tsx +36 -30
  223. package/src/models/catalog.ts +5 -2
  224. package/src/models/huggingface.ts +9 -9
  225. package/src/models/llamacpp.ts +13 -13
  226. package/src/models/modelDisplay.ts +75 -0
  227. package/src/models/modelPickerOptions.ts +16 -3
  228. package/src/models/modelRecommendation.ts +0 -1
  229. package/src/providers/errors.ts +16 -0
  230. package/src/providers/gemini.ts +252 -39
  231. package/src/providers/registry.ts +2 -2
  232. package/src/providers/retry.ts +1 -1
  233. package/src/runtime/sessionMode.ts +1 -1
  234. package/src/runtime/systemPrompt.ts +2 -0
  235. package/src/runtime/toolExecution.ts +18 -22
  236. package/src/runtime/toolIntent.ts +0 -20
  237. package/src/runtime/turn.ts +0 -92
  238. package/src/storage/atomicWrite.ts +4 -1
  239. package/src/storage/config.ts +181 -5
  240. package/src/storage/identity.ts +9 -3
  241. package/src/storage/secrets.ts +2 -2
  242. package/src/tools/bashSafety.ts +8 -0
  243. package/src/tools/changeDirectoryTool.ts +1 -1
  244. package/src/tools/deleteFileTool.ts +4 -4
  245. package/src/tools/editTool.ts +4 -4
  246. package/src/tools/editUtils.ts +5 -5
  247. package/src/tools/privateContinuityEditTool.ts +4 -5
  248. package/src/tools/privateContinuityReadTool.ts +1 -2
  249. package/src/tools/registry.ts +30 -0
  250. package/src/tools/writeFileTool.ts +5 -5
  251. package/src/ui/BrandSplash.tsx +20 -85
  252. package/src/ui/ProgressBar.tsx +3 -5
  253. package/src/ui/Select.tsx +20 -8
  254. package/src/ui/Spinner.tsx +38 -3
  255. package/src/ui/Surface.tsx +2 -2
  256. package/src/ui/TextInput.tsx +63 -20
  257. package/src/ui/theme.ts +7 -34
  258. package/src/utils/openExternal.ts +21 -0
  259. package/src/utils/withRetry.ts +47 -3
  260. package/src/identity/hub/identityHubEffects.ts +0 -937
  261. package/src/identity/hub/identityHubModel.ts +0 -371
  262. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +0 -156
  263. package/src/identity/hub/screens/EditProfileFlow.tsx +0 -146
  264. package/src/identity/hub/screens/IdentitySummary.tsx +0 -106
  265. package/src/identity/hub/screens/MenuScreen.tsx +0 -117
  266. package/src/identity/hub/screens/RestoreFlow.tsx +0 -206
  267. package/src/identity/wallet/wallet-page/wallet.html +0 -1202
  268. /package/src/identity/hub/{screens → components}/BusyScreen.tsx +0 -0
@@ -1,1202 +0,0 @@
1
- <!doctype html>
2
- <html>
3
-
4
- <head>
5
- <meta charset="utf-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <title>wallet request</title>
8
- <style>
9
- *,
10
- *::before,
11
- *::after {
12
- box-sizing: border-box;
13
- }
14
-
15
- :root {
16
- interpolate-size: allow-keywords;
17
- --font-ui: Inter, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
18
- --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;
19
- --font-display: Inter, "SF Pro Display", "Segoe UI", system-ui, sans-serif;
20
- --c-gray-900: #1f2330;
21
- --c-gray-800: #2f364a;
22
- --c-gray-700: #49526a;
23
- --c-gray-500: #6f7890;
24
- --c-gray-400: #949bb0;
25
- --c-blue-400: #5f8fff;
26
- --c-blue-500: #3f76ff;
27
- --c-blue-700: #2954c6;
28
- --c-danger: #e5484d;
29
- --c-success: #1aa86b;
30
- --pastel-red: #f6b7ba;
31
- --pastel-peach: #f8cdbb;
32
- --pastel-yellow: #f5e6b3;
33
- --pastel-mint: #bfe8cd;
34
- --pastel-sky: #bfdcf4;
35
- --pastel-blue: #a9c7f7;
36
- --mint-accent: #7070f0;
37
- --mint-accent-strong: #5858d8;
38
- --mint-accent-soft: rgba(112, 112, 240, 0.16);
39
- --mint-glow: rgba(112, 112, 240, 0.28);
40
- --c-text-accent: #9eaae0;
41
- --ease-standard: cubic-bezier(0.2, 0.0, 0, 1);
42
- --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
43
- --fg-1: #1f2330;
44
- }
45
-
46
- html,
47
- body {
48
- height: 100%;
49
- margin: 0;
50
- overflow: hidden;
51
- }
52
-
53
- body {
54
- position: relative;
55
- font-family: var(--font-ui);
56
- color: var(--fg-1);
57
- background: #fbfaf6;
58
- display: grid;
59
- place-items: center;
60
- padding: clamp(18px, 3vw, 28px);
61
- }
62
-
63
- body::before {
64
- content: "";
65
- position: fixed;
66
- inset: 0;
67
- z-index: 0;
68
- background:
69
- radial-gradient(55% 45% at 12% 18%, rgba(245, 216, 216, 0.85), transparent 65%),
70
- radial-gradient(60% 50% at 88% 22%, rgba(245, 231, 207, 0.85), transparent 65%),
71
- radial-gradient(55% 55% at 50% 50%, rgba(245, 240, 212, 0.75), transparent 70%),
72
- radial-gradient(60% 55% at 18% 88%, rgba(212, 238, 221, 0.85), transparent 65%),
73
- radial-gradient(60% 55% at 85% 85%, rgba(212, 230, 245, 0.85), transparent 65%),
74
- linear-gradient(180deg, #fef3ee 0%, #fef7e8 40%, #f1f9ee 75%, #ecf3fb 100%);
75
- filter: saturate(1.05);
76
- }
77
-
78
- body::after {
79
- content: "";
80
- position: fixed;
81
- inset: 0;
82
- z-index: 0;
83
- pointer-events: none;
84
- background-image: radial-gradient(rgba(0, 0, 0, 0.035) 1px, transparent 1px);
85
- background-size: 3px 3px;
86
- mix-blend-mode: multiply;
87
- opacity: 0.6;
88
- }
89
-
90
- main {
91
- position: relative;
92
- z-index: 1;
93
- width: min(700px, 100%);
94
- max-height: calc(100dvh - 36px);
95
- display: flex;
96
- flex-direction: column;
97
- background: rgba(255, 255, 255, 0.95);
98
- backdrop-filter: blur(40px) saturate(1.4);
99
- -webkit-backdrop-filter: blur(40px) saturate(1.4);
100
- border: 1px solid rgba(255, 255, 255, 0.7);
101
- border-radius: 26px;
102
- box-shadow:
103
- 0 1px 0 rgba(255, 255, 255, 0.9) inset,
104
- 0 -1px 0 rgba(255, 255, 255, 0.4) inset,
105
- 0 30px 60px -20px rgba(31, 35, 48, 0.25),
106
- 0 12px 24px -8px rgba(31, 35, 48, 0.12);
107
- overflow: hidden;
108
- height: fit-content;
109
- }
110
-
111
- .chrome {
112
- display: flex;
113
- align-items: center;
114
- justify-content: center;
115
- padding: 14px 20px;
116
- border-bottom: 1px solid rgba(255, 255, 255, 0.5);
117
- background: transparent;
118
- flex: none;
119
- }
120
-
121
- .chrome-title {
122
- flex: 1;
123
- text-align: center;
124
- font-size: 11.5px;
125
- color: rgba(31, 35, 48, 0.55);
126
- font-weight: 500;
127
- letter-spacing: 0.01em;
128
- margin: 0;
129
- }
130
-
131
- .body {
132
- flex: 1;
133
- min-height: 0;
134
- padding: clamp(20px, 3vw, 28px) clamp(22px, 4vw, 32px) clamp(22px, 3vw, 30px);
135
- display: flex;
136
- flex-direction: column;
137
- gap: 15px;
138
- overflow: hidden;
139
- }
140
-
141
- .splash-wrap {
142
- flex: none;
143
- display: flex;
144
- justify-content: center;
145
- margin: 6px 0 2px;
146
- padding: 4px 0;
147
- }
148
-
149
- .splash {
150
- font-family: var(--font-mono);
151
- font-size: clamp(9.5px, 1.35vw, 11px);
152
- font-weight: 700;
153
- line-height: 1.05;
154
- letter-spacing: 0;
155
- white-space: pre;
156
- margin: 0;
157
- text-align: left;
158
- transform: scaleX(0.8);
159
- transform-origin: 50% 50%;
160
- color: rgba(255, 255, 255, 0.18);
161
- }
162
-
163
- .spinner {
164
- display: inline-block;
165
- width: 14px;
166
- height: 14px;
167
- border-radius: 999px;
168
- border: 1.6px solid color-mix(in srgb, var(--accent) 30%, transparent);
169
- border-top-color: var(--accent);
170
- animation: spin 0.9s linear infinite;
171
- }
172
-
173
- @keyframes spin {
174
- to {
175
- transform: rotate(360deg);
176
- }
177
- }
178
-
179
- [data-flow] {
180
- --accent: var(--mint-accent);
181
- --accent-soft: var(--mint-accent-soft);
182
- --glow: var(--mint-glow);
183
- }
184
-
185
- main,
186
- .head .label,
187
- .status,
188
- .status-line,
189
- .status-hint,
190
- .flow-detail,
191
- #error-block-slot,
192
- .net-pill {
193
- transition: height 480ms var(--ease-standard), background-color 320ms var(--ease-standard), border-color 320ms var(--ease-standard), color 320ms var(--ease-standard), box-shadow 320ms var(--ease-standard);
194
- }
195
-
196
- .status-line,
197
- .status-hint {
198
- transition: opacity 280ms var(--ease-standard), transform 280ms var(--ease-standard), color 320ms var(--ease-standard);
199
- }
200
-
201
- .status-line.is-changing,
202
- .status-hint.is-changing {
203
- opacity: 0;
204
- transform: translateY(-3px);
205
- }
206
-
207
- .head {
208
- display: flex;
209
- align-items: center;
210
- justify-content: space-between;
211
- gap: 12px;
212
- }
213
-
214
- .head .label {
215
- font-family: var(--font-ui);
216
- color: var(--c-gray-800);
217
- font-size: 11.5px;
218
- font-weight: 500;
219
- letter-spacing: 0;
220
- text-transform: capitalize;
221
- display: inline-flex;
222
- align-items: center;
223
- gap: 6px;
224
- padding: 5px 13px 5px 10px;
225
- background: rgba(255, 255, 255, 0.6);
226
- border-radius: 999px;
227
- border: 1px solid rgba(255, 255, 255, 0.85);
228
- box-shadow: 0 1px 2px rgba(31, 35, 48, 0.05), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
229
- }
230
-
231
- .head .label::before {
232
- content: "";
233
- width: 6px;
234
- height: 6px;
235
- border-radius: 999px;
236
- background: var(--accent);
237
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent);
238
- }
239
-
240
- .flow-title {
241
- font-family: var(--font-display);
242
- font-size: clamp(18px, 2.6vw, 20px);
243
- font-weight: 600;
244
- line-height: 1.22;
245
- letter-spacing: 0;
246
- margin: 0;
247
- color: var(--c-gray-900);
248
- text-wrap: balance;
249
- }
250
-
251
- .details {
252
- display: flex;
253
- flex-direction: column;
254
- gap: 9px;
255
- padding: 14px 16px;
256
- background: rgba(255, 255, 255, 0.45);
257
- backdrop-filter: blur(16px);
258
- border: 1px solid rgba(255, 255, 255, 0.85);
259
- border-radius: 14px;
260
- box-shadow: 0 4px 16px -4px rgba(31, 35, 48, 0.08), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
261
- max-height: 210px;
262
- opacity: 1;
263
- margin-top: 0;
264
- overflow: hidden;
265
- transition: max-height 480ms var(--ease-standard), padding 480ms var(--ease-standard), margin 480ms var(--ease-standard), opacity 480ms var(--ease-standard), border-color 480ms var(--ease-standard), box-shadow 480ms var(--ease-standard);
266
- }
267
-
268
- .details[hidden] {
269
- display: flex;
270
- max-height: 0;
271
- opacity: 0;
272
- padding-top: 0;
273
- padding-bottom: 0;
274
- margin-top: -14px;
275
- border-color: transparent;
276
- box-shadow: none;
277
- pointer-events: none;
278
- }
279
-
280
- .flow-detail {
281
- display: grid;
282
- grid-template-columns: 96px 1fr;
283
- align-items: center;
284
- gap: 12px;
285
- font-size: 13.5px;
286
- color: var(--c-gray-700);
287
- margin: 0;
288
- line-height: 1.35;
289
- }
290
-
291
- .flow-detail[hidden] {
292
- display: none;
293
- }
294
-
295
- .flow-detail .key {
296
- font-family: var(--font-mono);
297
- font-size: 10px;
298
- font-weight: 500;
299
- color: var(--c-gray-500);
300
- text-transform: lowercase;
301
- letter-spacing: 0.05em;
302
- padding: 3px 8px;
303
- background: rgba(15, 17, 23, 0.04);
304
- border: 1px solid rgba(15, 17, 23, 0.06);
305
- border-radius: 6px;
306
- justify-self: start;
307
- min-width: 0;
308
- }
309
-
310
- .flow-detail span:last-child {
311
- overflow: hidden;
312
- text-overflow: ellipsis;
313
- white-space: nowrap;
314
- }
315
-
316
- .status {
317
- display: flex;
318
- flex-direction: column;
319
- gap: 7px;
320
- padding: 15px 17px;
321
- background: rgba(255, 255, 255, 0.45);
322
- backdrop-filter: blur(16px);
323
- border: 1px solid rgba(255, 255, 255, 0.85);
324
- border-radius: 14px;
325
- box-shadow: 0 4px 16px -4px rgba(31, 35, 48, 0.08), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
326
- }
327
-
328
- .status-line {
329
- display: flex;
330
- align-items: center;
331
- gap: 12px;
332
- font-size: 13.5px;
333
- font-weight: 500;
334
- color: var(--c-gray-900);
335
- margin: 0;
336
- }
337
-
338
- .status-line .marker {
339
- font-family: var(--font-mono);
340
- font-size: 13px;
341
- width: 29px;
342
- height: 29px;
343
- display: inline-flex;
344
- align-items: center;
345
- justify-content: center;
346
- border-radius: 999px;
347
- background: rgba(255, 255, 255, 0.55);
348
- backdrop-filter: blur(12px);
349
- -webkit-backdrop-filter: blur(12px);
350
- border: 1px solid rgba(255, 255, 255, 0.75);
351
- box-shadow: 0 2px 8px -2px rgba(31, 35, 48, 0.1), 0 1px 0 rgba(255, 255, 255, 0.8) inset;
352
- color: var(--c-text-accent);
353
- flex: none;
354
- font-variant-numeric: tabular-nums;
355
- font-weight: 600;
356
- }
357
-
358
- .status-hint {
359
- font-size: 12.5px;
360
- color: var(--c-gray-500);
361
- margin: 0 0 0 41px;
362
- line-height: 1.4;
363
- }
364
-
365
- #error-block-slot:empty {
366
- display: block;
367
- max-height: 0;
368
- opacity: 0;
369
- padding-top: 0;
370
- padding-bottom: 0;
371
- margin-top: -14px;
372
- border-color: transparent;
373
- box-shadow: none;
374
- pointer-events: none;
375
- }
376
-
377
- #error-block-slot {
378
- padding: 12px 14px;
379
- background: rgba(255, 255, 255, 0.45);
380
- backdrop-filter: blur(16px);
381
- border: 1px solid rgba(255, 255, 255, 0.85);
382
- border-radius: 14px;
383
- box-shadow: 0 8px 24px -6px rgba(31, 35, 48, 0.08), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
384
- max-height: 400px;
385
- opacity: 1;
386
- margin-top: 0;
387
- overflow: hidden;
388
- transition: max-height 480ms var(--ease-standard), padding 480ms var(--ease-standard), margin 480ms var(--ease-standard), opacity 480ms var(--ease-standard), border-color 320ms var(--ease-standard), box-shadow 320ms var(--ease-standard);
389
- }
390
-
391
- .error-title {
392
- color: var(--c-gray-900);
393
- font-size: 12px;
394
- font-weight: 600;
395
- letter-spacing: 0;
396
- text-transform: capitalize;
397
- margin: 0 0 4px;
398
- }
399
-
400
- .error-msg {
401
- color: var(--c-gray-900);
402
- font-size: 13px;
403
- font-weight: 600;
404
- margin: 0 0 6px;
405
- line-height: 1.45;
406
- }
407
-
408
- .error-hint {
409
- color: var(--c-gray-500);
410
- font-size: 11.5px;
411
- margin: 0;
412
- line-height: 1.5;
413
- }
414
-
415
- .error-hint a {
416
- color: var(--c-text-accent);
417
- text-decoration: none;
418
- font-weight: 600;
419
- border-bottom: 1px dashed color-mix(in srgb, var(--c-text-accent) 50%, transparent);
420
- padding-bottom: 1px;
421
- transition: all 0.2s ease;
422
- }
423
-
424
- .error-hint a:hover {
425
- color: var(--c-text-accent);
426
- border-bottom-style: solid;
427
- }
428
-
429
- .error-hint code {
430
- font-family: var(--font-mono);
431
- font-size: 11px;
432
- padding: 2px 6px;
433
- background: rgba(15, 17, 23, 0.06);
434
- border-radius: 4px;
435
- color: var(--c-gray-700);
436
- }
437
-
438
- .footer {
439
- flex: none;
440
- padding: 15px 22px 17px;
441
- border-top: 1px solid rgba(255, 255, 255, 0.5);
442
- background: transparent;
443
- display: flex;
444
- align-items: center;
445
- justify-content: space-between;
446
- gap: 12px;
447
- }
448
-
449
- .net-pill {
450
- display: inline-flex;
451
- align-items: center;
452
- gap: 6px;
453
- font-family: var(--font-ui);
454
- font-size: 11.5px;
455
- font-weight: 500;
456
- color: var(--c-gray-800);
457
- padding: 5px 13px 5px 10px;
458
- background: rgba(255, 255, 255, 0.6);
459
- border: 1px solid rgba(255, 255, 255, 0.85);
460
- border-radius: 999px;
461
- box-shadow: 0 1px 2px rgba(31, 35, 48, 0.05), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
462
- }
463
-
464
- .net-pill .dot {
465
- width: 6px;
466
- height: 6px;
467
- border-radius: 999px;
468
- background: var(--accent);
469
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent);
470
- }
471
-
472
- .net-pill[hidden] {
473
- display: none;
474
- }
475
-
476
- .actions {
477
- display: inline-flex;
478
- align-items: center;
479
- gap: 10px;
480
- }
481
-
482
- .shortcut {
483
- font: inherit;
484
- font-family: var(--font-ui);
485
-
486
- font-size: 12.5px;
487
- font-weight: 500;
488
- background: rgba(255, 255, 255, 0.7);
489
- border: 1px solid rgba(255, 255, 255, 0.85);
490
- padding: 5px 10px;
491
- cursor: pointer;
492
- color: var(--c-gray-700);
493
- display: inline-flex;
494
- align-items: center;
495
- gap: 6px;
496
- border-radius: 7px;
497
- transition: all 0.15s var(--ease-standard);
498
- box-shadow: 0 1px 2px rgba(31, 35, 48, 0.03), 0 1px 0 rgba(255, 255, 255, 0.5) inset;
499
- }
500
-
501
- .shortcut:focus {
502
- outline: none;
503
- }
504
-
505
- .shortcut:focus-visible {
506
- outline: 2px solid var(--c-blue-400);
507
- outline-offset: 2px;
508
- }
509
-
510
- .shortcut:hover:not(:disabled) {
511
- background: rgba(255, 255, 255, 0.95);
512
- color: var(--c-gray-900);
513
- transform: translateY(-0.5px);
514
- }
515
-
516
- .shortcut:active:not(:disabled) {
517
- transform: translateY(0);
518
- }
519
-
520
- .shortcut:disabled {
521
- opacity: 0.4;
522
- cursor: not-allowed;
523
- }
524
-
525
- .shortcut[hidden] {
526
- display: none;
527
- }
528
-
529
- .shortcut.primary {
530
- background: var(--c-gray-900);
531
- border-color: var(--c-gray-900);
532
- color: #fff;
533
- box-shadow: 0 2px 8px -2px rgba(15, 17, 23, 0.2), 0 1px 0 rgba(255, 255, 255, 0.1) inset;
534
- }
535
-
536
- .shortcut.primary:hover:not(:disabled) {
537
- background: #1a1d27;
538
- color: #fff;
539
- }
540
-
541
- .shortcut.primary .key {
542
- background: rgba(255, 255, 255, 0.14);
543
- border-color: rgba(255, 255, 255, 0.18);
544
- color: rgba(255, 255, 255, 0.9);
545
- }
546
-
547
- .key {
548
- display: inline-flex;
549
- align-items: center;
550
- justify-content: center;
551
- gap: 4px;
552
- padding: 2px 6px;
553
- font-family: var(--font-mono);
554
- font-size: 10.5px;
555
- font-weight: 500;
556
- color: var(--c-gray-500);
557
- background: rgba(15, 17, 23, 0.04);
558
- border: 1px solid rgba(15, 17, 23, 0.07);
559
- border-radius: 5px;
560
- letter-spacing: 0.02em;
561
- }
562
-
563
- .shortcut .pix {
564
- color: currentColor;
565
- opacity: 0.85;
566
- display: inline-flex;
567
- }
568
-
569
- .head .net {
570
- display: none;
571
- }
572
-
573
- @media (max-width: 560px), (max-height: 680px) {
574
- body {
575
- padding: 10px;
576
- }
577
-
578
- main {
579
- max-height: calc(100dvh - 20px);
580
- border-radius: 18px;
581
- }
582
-
583
- .chrome {
584
- padding: 9px 12px;
585
- }
586
-
587
- .body {
588
- padding: 12px 13px 14px;
589
- gap: 9px;
590
- }
591
-
592
- .splash-wrap {
593
- margin: 2px 0 0;
594
- padding: 2px 0;
595
- }
596
-
597
- .splash {
598
- font-size: 8px;
599
- }
600
-
601
- .flow-title {
602
- font-size: 16px;
603
- }
604
-
605
- .details,
606
- .status {
607
- padding: 10px 11px;
608
- border-radius: 12px;
609
- }
610
-
611
- .flow-detail {
612
- grid-template-columns: 74px 1fr;
613
- gap: 8px;
614
- font-size: 12px;
615
- }
616
-
617
- .status-line {
618
- gap: 8px;
619
- font-size: 12px;
620
- }
621
-
622
- .status-line .marker {
623
- width: 24px;
624
- height: 24px;
625
- }
626
-
627
- .status-hint {
628
- margin-left: 32px;
629
- font-size: 11.5px;
630
- }
631
-
632
- .footer {
633
- padding: 10px 12px 12px;
634
- gap: 8px;
635
- }
636
-
637
- .actions {
638
- gap: 7px;
639
- }
640
-
641
- .shortcut {
642
- font-size: 11.5px;
643
- padding: 4px 8px;
644
- }
645
-
646
- .net-pill {
647
- font-size: 10px;
648
- padding: 4px 8px;
649
- }
650
- }
651
-
652
- /* dark mode: terminal-style window. */
653
- main {
654
- background: #0b0f14;
655
- color: #f1f1f1;
656
- border-color: rgba(255, 255, 255, 0.08);
657
- box-shadow:
658
- 0 1px 0 rgba(255, 255, 255, 0.05) inset,
659
- 0 -1px 0 rgba(0, 0, 0, 0.4) inset,
660
- 0 30px 60px -20px rgba(0, 0, 0, 0.55),
661
- 0 12px 24px -8px rgba(0, 0, 0, 0.35);
662
- --c-gray-900: #f1f1f1;
663
- --c-gray-800: #d8d8d8;
664
- --c-gray-700: #b0b0b0;
665
- --c-gray-500: #8a8a8a;
666
- --c-gray-400: #6f6f6f;
667
- }
668
-
669
- .splash {
670
- color: rgba(255, 255, 255, 0.7);
671
- }
672
-
673
- .chrome {
674
- border-bottom-color: rgba(255, 255, 255, 0.06);
675
- background: transparent;
676
- }
677
-
678
- .chrome-title {
679
- color: rgba(241, 241, 241, 0.55);
680
- }
681
-
682
- .head .label {
683
- background: rgba(255, 255, 255, 0.06);
684
- border-color: rgba(255, 255, 255, 0.1);
685
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.05) inset;
686
- }
687
-
688
- .details,
689
- #error-block-slot {
690
- background: rgba(255, 255, 255, 0.04);
691
- border-color: rgba(255, 255, 255, 0.08);
692
- box-shadow: 0 4px 16px -4px rgba(0, 0, 0, 0.35), 0 1px 0 rgba(255, 255, 255, 0.04) inset;
693
- }
694
-
695
- .status {
696
- background: rgba(255, 255, 255, 0.04);
697
- border-color: rgba(255, 255, 255, 0.08);
698
- box-shadow: 0 4px 16px -4px rgba(0, 0, 0, 0.35), 0 1px 0 rgba(255, 255, 255, 0.04) inset;
699
- }
700
-
701
- .status-line .marker {
702
- background: rgba(255, 255, 255, 0.07);
703
- border-color: rgba(255, 255, 255, 0.12);
704
- box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.07) inset;
705
- }
706
-
707
- .flow-detail .key {
708
- background: rgba(255, 255, 255, 0.05);
709
- border-color: rgba(255, 255, 255, 0.08);
710
- }
711
-
712
- .error-hint code {
713
- background: rgba(255, 255, 255, 0.06);
714
- }
715
-
716
- .footer {
717
- border-top-color: rgba(255, 255, 255, 0.06);
718
- background: transparent;
719
- }
720
-
721
- .net-pill {
722
- background: rgba(255, 255, 255, 0.06);
723
- border-color: rgba(255, 255, 255, 0.1);
724
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.05) inset;
725
- }
726
-
727
- /* esc key: secondary black */
728
- #cancel.shortcut {
729
- background: #1f2330;
730
- border-color: rgba(255, 255, 255, 0.08);
731
- color: #b0b0b0;
732
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.04) inset;
733
- }
734
-
735
- #cancel.shortcut:hover:not(:disabled) {
736
- background: #2a2e3c;
737
- color: #f1f1f1;
738
- }
739
-
740
- /* primary action: pin literal so the var override does not bleed through */
741
- .shortcut.primary {
742
- background: #1f2330;
743
- border-color: #1f2330;
744
- color: #fff;
745
- box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.1) inset;
746
- }
747
-
748
- .shortcut.primary:hover:not(:disabled) {
749
- background: #2a2e3c;
750
- color: #fff;
751
- }
752
-
753
- .shortcut.primary .key {
754
- background: rgba(255, 255, 255, 0.12);
755
- border-color: rgba(255, 255, 255, 0.2);
756
- color: rgba(255, 255, 255, 0.9);
757
- }
758
-
759
- .key {
760
- background: rgba(255, 255, 255, 0.06);
761
- border-color: rgba(255, 255, 255, 0.1);
762
- }
763
- </style>
764
- </head>
765
-
766
- <body>
767
- <main data-flow="sign" id="card">
768
- <div class="chrome">
769
- <span class="chrome-title" id="chrome-title">ethagent</span>
770
- </div>
771
- <div class="body">
772
- <div class="splash-wrap">
773
- <pre class="splash" id="splash"></pre>
774
- </div>
775
- <div class="head"><span class="label" id="prompt-text">signature request</span></div>
776
- <h2 class="flow-title" id="flow-title">Sign a message to prove ownership</h2>
777
- <div class="details" id="details-block">
778
- <p class="flow-detail" id="flow-detail"><span class="key" id="detail-key">message</span><span
779
- id="detail-val">—</span></p>
780
- </div>
781
- <div class="status" id="status-block">
782
- <p class="status-line"><span class="marker" id="status-marker"></span><span id="status-text">connecting to your
783
- wallet…</span></p>
784
- <p class="status-hint" id="status-hint">open your wallet extension if it doesn't pop up automatically.</p>
785
- </div>
786
- <div id="error-block-slot"></div>
787
- </div>
788
- <div class="footer">
789
- <span class="net-pill" id="network-row"><span class="dot"></span><span id="net-val">Sepolia</span></span>
790
- <div class="actions">
791
- <button id="cancel" class="shortcut"><span class="key">esc</span><span>cancel</span></button>
792
- <button id="approve" class="shortcut primary" hidden><span class="key"><svg width="10" height="10"
793
- viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"
794
- stroke-linejoin="round">
795
- <polyline points="9 10 4 15 9 20"></polyline>
796
- <path d="M20 4v7a4 4 0 0 1-4 4H4"></path>
797
- </svg></span><span>retry</span></button>
798
- </div>
799
- </div>
800
- </main>
801
- <script>
802
- const glyphs = {
803
- eyes: `
804
- -+:
805
- :=- -%@@@%.
806
- *@@@@@#- *@@-
807
- +@@. +@
808
- @@= -#=-+++=+:
809
- #% .:===-: -@* +@@@@%
810
- *@-+@@@@@: %@@+ @@@=#@
811
- *@= @@@@@@@- .@.@@@@@@@ :
812
- @@+=@@@@@@@@@@@@: .% *@@@@@*-=
813
- #:-@ -@@@@@@@@@-+% @ -@@@- #
814
- : #+ @@@@@@@- -% =# =
815
- -@: *@ .+%%
816
- :%#: --
817
- .-:
818
- `,
819
- ellipsis: "…",
820
- emDash: "—"
821
- };
822
- function escapeHtml(value) {
823
- return String(value == null ? "" : value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
824
- }
825
- function renderEyes() { return escapeHtml(glyphs.eyes); }
826
- document.getElementById("splash").innerHTML = renderEyes();
827
-
828
- const config = window.__WALLET_CONFIG__ || { sessionToken: "preview", kind: "sign", chainIdHex: "0xaa36a7", message: "identity proof for 0x9F2a…BC4e" };
829
- const CLOSE_DELAY_MS = 10000;
830
- const TX_CLOSE_DELAY_MS = 10000;
831
- const CANCEL_CLOSE_DELAY_MS = 10000;
832
- const WALLET_PROVIDER_WAIT_MS = 3000;
833
- const WALLET_PROVIDER_POLL_MS = 100;
834
- const CHAINS = { "0x1": { name: "Ethereum Mainnet" }, "0xaa36a7": { name: "Sepolia" }, "0x2105": { name: "Base" }, "0x14a34": { name: "Base Sepolia" }, "0xa": { name: "OP Mainnet" }, "0xa4b1": { name: "Arbitrum One" } };
835
- const FLOW_COPY = {
836
- account: { accent: "sign", tabTitle: "connect wallet", label: "wallet request", title: "Connect wallet to find your agent", detail: null },
837
- sign: { accent: "sign", tabTitle: "sign message", label: "signature request", title: "Sign a message to prove ownership", detail: "message" },
838
- "sign-transaction": { accent: "transaction", tabTitle: "approve identity update", label: "identity approval", title: "Sign, then save identity files", detail: "message" },
839
- transaction: { accent: "transaction", tabTitle: "submit transaction", label: "transaction request", title: "Submit transaction to mint your ERC-8004 agent", detail: "registry" }
840
- };
841
- const STATE_TITLES = { connecting: "Connecting wallet", approveSign: "Approve signature", preparingTransaction: "Preparing transaction", approveTransaction: "Approve transaction", error: "Wallet error", default: "Wallet request" };
842
- function chainLabel(hex) { const k = String(hex || "").toLowerCase(); return (CHAINS[k] && CHAINS[k].name) || ("chain " + k); }
843
- function shortAddr(addr) { if (!addr || typeof addr !== "string") return glyphs.emDash; if (addr.length <= 14) return addr; return addr.slice(0, 6) + glyphs.ellipsis + addr.slice(-4); }
844
- function isTransactionFlow() { return config.kind === "transaction" || config.kind === "sign-transaction"; }
845
-
846
- const card = document.getElementById("card");
847
- const promptText = document.getElementById("prompt-text");
848
- const flowTitle = document.getElementById("flow-title");
849
- const networkRow = document.getElementById("network-row");
850
- const flowDetail = document.getElementById("flow-detail");
851
- const detailsBlock = document.getElementById("details-block");
852
- const detailKey = document.getElementById("detail-key");
853
- const detailVal = document.getElementById("detail-val");
854
- const netVal = document.getElementById("net-val");
855
- const statusBlock = document.getElementById("status-block");
856
- const statusMarker = document.getElementById("status-marker");
857
- const statusText = document.getElementById("status-text");
858
- const statusHint = document.getElementById("status-hint");
859
- const errorSlot = document.getElementById("error-block-slot");
860
- const approve = document.getElementById("approve");
861
- const cancel = document.getElementById("cancel");
862
- let announcedEthereum = null;
863
- let activeEthereum = null;
864
- let closeCountdown = null;
865
-
866
- function rememberAnnouncedProvider(event) { const provider = event && event.detail && event.detail.provider; if (provider && !announcedEthereum) announcedEthereum = provider; }
867
- window.addEventListener("eip6963:announceProvider", rememberAnnouncedProvider);
868
- try { window.dispatchEvent(new Event("eip6963:requestProvider")); } catch (_) { }
869
- function ethereumProvider() { return activeEthereum || window.ethereum || announcedEthereum; }
870
- function noWalletError() { return new Error("No browser wallet detected. Install MetaMask, Rabby, or use Brave."); }
871
-
872
- function waitForEthereumProvider(timeoutMs) {
873
- const existing = ethereumProvider();
874
- if (existing) return Promise.resolve(existing);
875
- return new Promise((resolve, reject) => {
876
- let settled = false;
877
- const cleanup = () => {
878
- clearTimeout(timer);
879
- clearInterval(interval);
880
- window.removeEventListener("ethereum#initialized", check);
881
- window.removeEventListener("eip6963:announceProvider", onAnnounce);
882
- };
883
- const finish = (fn) => {
884
- if (settled) return;
885
- settled = true;
886
- cleanup();
887
- fn();
888
- };
889
- const check = () => { const provider = ethereumProvider(); if (provider) finish(() => resolve(provider)); };
890
- const onAnnounce = (event) => { rememberAnnouncedProvider(event); check(); };
891
- const timer = setTimeout(() => finish(() => reject(noWalletError())), timeoutMs || WALLET_PROVIDER_WAIT_MS);
892
- const interval = setInterval(check, WALLET_PROVIDER_POLL_MS);
893
- window.addEventListener("ethereum#initialized", check);
894
- window.addEventListener("eip6963:announceProvider", onAnnounce);
895
- try { window.dispatchEvent(new Event("eip6963:requestProvider")); } catch (_) { }
896
- check();
897
- });
898
- }
899
- async function walletRequest(method, params) {
900
- const provider = ethereumProvider();
901
- if (!provider) throw noWalletError();
902
- return await provider.request(params === undefined ? { method } : { method, params });
903
- }
904
-
905
- let spinning = false;
906
- function startSpinner() {
907
- spinning = true;
908
- statusMarker.innerHTML = '<span class="spinner" aria-hidden="true"></span>';
909
- statusMarker.style.background = "transparent";
910
- }
911
- function stopSpinner() {
912
- if (!spinning) return;
913
- spinning = false;
914
- statusMarker.innerHTML = "";
915
- statusMarker.style.background = "";
916
- }
917
- function setMarker(text) { stopSpinner(); statusMarker.textContent = text; }
918
- function flowCopy() { return FLOW_COPY[config.kind] || FLOW_COPY.sign; }
919
-
920
- function tabTitleForState(state) {
921
- if (state === "connecting") return STATE_TITLES.connecting;
922
- if (state === "approve-sign") return STATE_TITLES.approveSign;
923
- if (state === "preparing-transaction") return STATE_TITLES.preparingTransaction;
924
- if (state === "approve-transaction") return STATE_TITLES.approveTransaction;
925
- if (state === "error") return STATE_TITLES.error;
926
- if (state === "approve") {
927
- if (config.kind === "account") return "Approve connection";
928
- if (config.kind === "sign") return STATE_TITLES.approveSign;
929
- return STATE_TITLES.approveTransaction;
930
- }
931
- if (state === "submitting") {
932
- if (config.kind === "account") return STATE_TITLES.connecting;
933
- if (config.kind === "sign") return "Verifying signature";
934
- return "Confirming transaction";
935
- }
936
- if (state === "done") {
937
- if (config.kind === "account") return "Wallet connected";
938
- if (config.kind === "sign") return "Message signed";
939
- return "Transaction submitted";
940
- }
941
- return flowCopy().tabTitle || STATE_TITLES.default;
942
- }
943
- function setTabTitle(title) {
944
- const t = title || flowCopy().tabTitle || STATE_TITLES.default;
945
- document.title = t;
946
- const chromeTitle = document.getElementById("chrome-title");
947
- if (chromeTitle) chromeTitle.textContent = "ethagent · " + t;
948
- }
949
- function messagePreview(message) { const preview = String(message || "").split("\n")[0]; return preview.length > 64 ? preview.slice(0, 64) + glyphs.ellipsis : preview; }
950
- function detailPreview(copy) {
951
- if (copy.detail === "message") return messagePreview(config.message);
952
- if (copy.detail === "registry" && config.tx) return shortAddr(config.tx.to);
953
- return "";
954
- }
955
- function showPreparedMessage(message) {
956
- const copy = flowCopy();
957
- if (copy.detail !== "message") return;
958
- const preview = messagePreview(message);
959
- detailKey.textContent = copy.detail;
960
- detailVal.textContent = preview;
961
- flowDetail.hidden = preview.length === 0;
962
- detailsBlock.hidden = flowDetail.hidden;
963
- }
964
- function applyFlowChrome() {
965
- const copy = flowCopy();
966
- card.dataset.flow = copy.accent;
967
- promptText.textContent = copy.label;
968
- flowTitle.textContent = copy.title;
969
- setTabTitle(copy.tabTitle);
970
- if (!copy.detail) {
971
- networkRow.hidden = true;
972
- flowDetail.hidden = true;
973
- detailsBlock.hidden = true;
974
- } else {
975
- networkRow.hidden = false;
976
- flowDetail.hidden = false;
977
- detailsBlock.hidden = false;
978
- netVal.textContent = chainLabel(config.chainIdHex);
979
- detailKey.textContent = copy.detail;
980
- detailVal.textContent = detailPreview(copy);
981
- flowDetail.hidden = detailVal.textContent.length === 0;
982
- if (flowDetail.hidden) detailsBlock.hidden = true;
983
- }
984
- }
985
-
986
- function setStatus(marker, text, hint, spin) {
987
- const lineEl = statusText.parentElement;
988
- const hintEl = statusHint;
989
- const apply = () => {
990
- if (spin) startSpinner();
991
- else setMarker(marker);
992
- statusText.textContent = text;
993
- hintEl.textContent = hint;
994
- requestAnimationFrame(() => {
995
- lineEl.classList.remove("is-changing");
996
- hintEl.classList.remove("is-changing");
997
- });
998
- };
999
- if (statusText.textContent === text && hintEl.textContent === hint) {
1000
- if (spin) startSpinner();
1001
- else setMarker(marker);
1002
- return;
1003
- }
1004
- lineEl.classList.add("is-changing");
1005
- hintEl.classList.add("is-changing");
1006
- setTimeout(apply, 220);
1007
- }
1008
-
1009
- function setState(state, payload) {
1010
- payload = payload || {};
1011
- errorSlot.innerHTML = "";
1012
- statusBlock.style.display = "flex";
1013
- setTabTitle(tabTitleForState(state));
1014
- switch (state) {
1015
- case "connecting":
1016
- setStatus("·", "Connecting to your wallet…", "Open your wallet extension if it doesn't pop up automatically.", true);
1017
- break;
1018
- case "approve":
1019
- if (config.kind === "account") setStatus("·", "Approve wallet connection", "The selected address will be used to search for owned agents.", true);
1020
- else if (config.kind === "sign") setStatus("·", "Approve the signature in your wallet", "A prompt should be open. Waiting for your signature.", true);
1021
- else setStatus("·", "Review and submit the transaction in your wallet", "Check the network and contract address before approving.", true);
1022
- break;
1023
- case "approve-sign":
1024
- setStatus("·", "Approve the signature in your wallet", "This encrypts or decrypts SOUL.md and MEMORY.md.", true);
1025
- break;
1026
- case "preparing-transaction":
1027
- setStatus("·", "Encrypting SOUL.md and MEMORY.md, then preparing the update...", "Keep this page open. The transaction prompt will appear here.", true);
1028
- break;
1029
- case "approve-transaction":
1030
- setStatus("·", "Review and submit the transaction in your wallet", "Check the network and contract address before approving.", true);
1031
- break;
1032
- case "submitting":
1033
- if (config.kind === "account") setStatus("·", "Connecting wallet…", "Sending the selected address back.", true);
1034
- else if (config.kind === "sign") setStatus("·", "Verifying signature…", "Recovering the signing address.", true);
1035
- else setStatus("·", "Submitted · waiting for confirmation…", "Your wallet has accepted the transaction.", true);
1036
- break;
1037
- case "done":
1038
- stopSpinner();
1039
- statusMarker.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
1040
- statusText.textContent = config.kind === "account" ? "Connected · returning" : config.kind === "sign" ? "Signed · returning" : "Submitted · returning";
1041
- statusHint.textContent = payload.txHash ? (isTransactionFlow() ? "Transaction submitted. Returning." : "This tab will close shortly.") : "This tab will close shortly.";
1042
- break;
1043
- case "error":
1044
- stopSpinner();
1045
- statusBlock.style.display = "none";
1046
- renderError(payload);
1047
- break;
1048
- }
1049
- }
1050
-
1051
- function renderError(payload) {
1052
- const msg = payload.message || "Something went wrong.";
1053
- const isNoWallet = /no wallet|window\.ethereum|metamask|rabby|brave|extension/i.test(msg);
1054
- const isUserReject = /user rejected|user denied|cancelled|canceled/i.test(msg);
1055
- const isWrongChain = /chain|network/i.test(msg) && !isNoWallet;
1056
- let title = "Wallet error";
1057
- let body = msg;
1058
- let hint = "Press enter to retry, or esc to abort.";
1059
- if (isNoWallet) {
1060
- title = "No wallet";
1061
- body = "Install a browser wallet.";
1062
- hint = 'Get <a href="https://phantom.com/download" target="_blank" rel="noopener">Phantom</a>, then press <code>enter</code>.';
1063
- } else if (isUserReject) {
1064
- title = "Rejected";
1065
- body = "Request declined in wallet.";
1066
- hint = "Press <code>enter</code> to retry, or <code>esc</code> to abort.";
1067
- } else if (isWrongChain) {
1068
- title = "Wrong network";
1069
- hint = "Expected <code>" + escapeHtml(chainLabel(config.chainIdHex)) + "</code>. Switch networks, then retry.";
1070
- }
1071
- errorSlot.innerHTML = '<p class="error-title">' + escapeHtml(title) + "</p>" + '<p class="error-msg">' + escapeHtml(body) + "</p>" + '<p class="error-hint">' + hint + "</p>";
1072
- }
1073
-
1074
- async function post(path, body) {
1075
- const r = await fetch(path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...(body || {}), sessionToken: config.sessionToken }) });
1076
- const d = await r.json();
1077
- if (!r.ok || !d.ok) throw new Error(d.error || "wallet request failed");
1078
- return d;
1079
- }
1080
- function showCloseCountdown(delayMs) {
1081
- if (closeCountdown) clearInterval(closeCountdown);
1082
- const deadline = Date.now() + delayMs;
1083
- const update = () => {
1084
- const seconds = Math.max(1, Math.ceil((deadline - Date.now()) / 1000));
1085
- statusHint.textContent = "Return to your terminal. Closing in " + seconds + "s.";
1086
- };
1087
- update();
1088
- closeCountdown = setInterval(update, 250);
1089
- }
1090
- function closeSoon(delayMs) {
1091
- const ms = delayMs == null ? CLOSE_DELAY_MS : delayMs;
1092
- showCloseCountdown(ms);
1093
- setTimeout(() => {
1094
- if (closeCountdown) clearInterval(closeCountdown);
1095
- try { if (window.opener && !window.opener.closed) window.opener.focus(); } catch (_) { }
1096
- window.close();
1097
- window.open("", "_self");
1098
- window.close();
1099
- }, ms);
1100
- }
1101
-
1102
- async function ensureWallet() {
1103
- setState("connecting");
1104
- const provider = await waitForEthereumProvider();
1105
- activeEthereum = provider;
1106
- const accounts = await provider.request({ method: "eth_requestAccounts" });
1107
- const account = accounts && accounts[0];
1108
- if (!account) throw new Error("No wallet account was selected.");
1109
- if (!config.chainIdHex) return account;
1110
- try { await provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: config.chainIdHex }] }); }
1111
- catch (err) {
1112
- const cur = await provider.request({ method: "eth_chainId" });
1113
- if (String(cur).toLowerCase() !== String(config.chainIdHex).toLowerCase()) throw err;
1114
- }
1115
- return account;
1116
- }
1117
-
1118
- async function runWalletFlow() {
1119
- approve.disabled = true;
1120
- approve.hidden = true;
1121
- cancel.disabled = false;
1122
- errorSlot.innerHTML = "";
1123
- try {
1124
- const account = await ensureWallet();
1125
- if (config.kind === "account") {
1126
- setState("submitting");
1127
- await post("/complete", { account });
1128
- setState("done");
1129
- closeSoon();
1130
- return;
1131
- }
1132
- if (config.kind === "sign") {
1133
- const prepared = config.message ? { message: config.message } : await post("/prepare", { account });
1134
- showPreparedMessage(prepared.message);
1135
- setState("approve");
1136
- const signature = await walletRequest("personal_sign", [prepared.message, account]);
1137
- setState("submitting");
1138
- await post("/complete", { account, message: prepared.message, signature });
1139
- setState("done");
1140
- closeSoon();
1141
- return;
1142
- }
1143
- if (config.kind === "sign-transaction") {
1144
- const prepared = config.message ? { message: config.message } : await post("/prepare", { account });
1145
- showPreparedMessage(prepared.message);
1146
- setState("approve-sign", { account });
1147
- const signature = await walletRequest("personal_sign", [prepared.message, account]);
1148
- setState("preparing-transaction", { account });
1149
- const txPayload = await post("/prepare-transaction", { account, message: prepared.message, signature });
1150
- setState("approve-transaction", { account, tx: txPayload.tx });
1151
- const tx = txPayload.tx || {};
1152
- const txHash = await walletRequest("eth_sendTransaction", [{ from: account, to: tx.to, data: tx.data, value: tx.value }]);
1153
- setState("submitting", { account, tx, txHash });
1154
- await post("/complete", { account, txHash });
1155
- setState("done", { account, tx, txHash });
1156
- closeSoon(TX_CLOSE_DELAY_MS);
1157
- return;
1158
- }
1159
- if (config.kind === "transaction") {
1160
- setState("approve", { account, tx: config.tx });
1161
- const txHash = await walletRequest("eth_sendTransaction", [{ from: account, to: config.tx.to, data: config.tx.data, value: config.tx.value }]);
1162
- setState("submitting", { account, tx: config.tx, txHash });
1163
- await post("/complete", { account, txHash });
1164
- setState("done", { account, tx: config.tx, txHash });
1165
- closeSoon(TX_CLOSE_DELAY_MS);
1166
- return;
1167
- }
1168
- throw new Error("Unknown wallet request type.");
1169
- } catch (err) {
1170
- approve.disabled = false;
1171
- approve.hidden = false;
1172
- cancel.disabled = false;
1173
- setState("error", { message: (err && err.message) || String(err) });
1174
- }
1175
- }
1176
-
1177
- async function cancelFlow() {
1178
- approve.disabled = true;
1179
- cancel.disabled = true;
1180
- await post("/cancel", {}).catch(() => { });
1181
- setState("done");
1182
- statusText.textContent = "Cancelled · returning";
1183
- closeSoon(CANCEL_CLOSE_DELAY_MS);
1184
- }
1185
- approve.onclick = runWalletFlow;
1186
- cancel.onclick = cancelFlow;
1187
- window.addEventListener("keydown", (e) => {
1188
- if (e.key === "Escape") { e.preventDefault(); cancelFlow(); }
1189
- else if (e.key === "Enter" && !approve.hidden && !approve.disabled) { e.preventDefault(); runWalletFlow(); }
1190
- });
1191
-
1192
- applyFlowChrome();
1193
- if (!window.__WALLET_PREVIEW__) {
1194
- window.addEventListener("load", () => setTimeout(runWalletFlow, 150));
1195
- } else {
1196
- window.__walletPreview = { setState, setConfig: (c) => { Object.assign(config, c); applyFlowChrome(); } };
1197
- setState("connecting");
1198
- }
1199
- </script>
1200
- </body>
1201
-
1202
- </html>