ethagent 1.1.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +124 -32
  3. package/package.json +8 -3
  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
@@ -0,0 +1,397 @@
1
+ import React from 'react'
2
+ import { getAddress, type Address } from 'viem'
3
+ import type { BrowserWalletReady } from '../../../wallet/browserWallet.js'
4
+ import { requestBrowserWalletAccount } from '../../../wallet/browserWallet.js'
5
+ import {
6
+ AGENT_RECORD_READ_KEY_LIST,
7
+ buildAgentEnsRecords,
8
+ diffRecords,
9
+ recordsFromTextMap,
10
+ } from '../../../ens/agentRecords.js'
11
+ import {
12
+ discoverOwnedEnsNameDetails,
13
+ readEthagentTextRecords,
14
+ sanitizeSubdomainPrefix,
15
+ splitSubdomainName,
16
+ validateAgentEnsLink,
17
+ } from '../../../ens/ensLookup.js'
18
+ import {
19
+ preflightDeleteSubdomain,
20
+ preflightEnsRoot,
21
+ preflightEnsSetup,
22
+ } from '../../../ens/ensAutomation.js'
23
+ import {
24
+ readCustodyMode,
25
+ readIdentityStateString,
26
+ } from '../../model/custody.js'
27
+ import {
28
+ discoveryErrorMessage,
29
+ emptyAgentEnsRecords,
30
+ networkLabelForChainId,
31
+ type EnsLinkOptions,
32
+ } from './ensEditCopy.js'
33
+ import { rootErrorMessage } from './EnsEditShared.js'
34
+ import { renderAdvancedEnsPhase } from './EnsEditAdvancedScreens.js'
35
+ import { renderEnsMaintenancePhase } from './EnsEditMaintenanceScreens.js'
36
+ import { renderSimpleEnsPhase } from './EnsEditSimpleScreens.js'
37
+ import type {
38
+ DiscoveryState,
39
+ EnsEditProps,
40
+ EnsPhase,
41
+ } from './ensEditTypes.js'
42
+
43
+ export type { EnsLinkOptions }
44
+
45
+ export const EnsEditFlow: React.FC<EnsEditProps> = ({
46
+ identity,
47
+ registry,
48
+ onEnsLink,
49
+ onEnsUnlink,
50
+ onEnsRecordsUpdate,
51
+ onEnsSetup,
52
+ onManageOperatorWalletAccess,
53
+ initialView,
54
+ onBack,
55
+ }) => {
56
+ const ownerAddress = getAddress((identity.ownerAddress ?? identity.address) as Address)
57
+ const currentEnsName = readIdentityStateString(identity.state, 'ensName')
58
+ const currentEnsParts = currentEnsName ? splitSubdomainName(currentEnsName) : null
59
+ const savedRootName = currentEnsParts?.parent ?? ''
60
+ const savedSubdomainLabel = currentEnsParts?.label ?? ''
61
+ const agentNameSuggestion = sanitizeSubdomainPrefix(readIdentityStateString(identity.state, 'name'))
62
+ const agentCardCid = identity.publicSkills?.agentCardCid
63
+ const savedCustodyMode = readCustodyMode(identity.state)
64
+ const savedOwnerAddress = readIdentityStateString(identity.state, 'ownerAddress')
65
+ const savedOperator = readIdentityStateString(identity.state, 'activeOperatorAddress')
66
+ const registryNetworkLabel = networkLabelForChainId(registry.chainId)
67
+ const hasAdvancedSetup = savedCustodyMode === 'advanced' && Boolean(savedOwnerAddress) && Boolean(currentEnsName)
68
+
69
+ const [discovery, setDiscovery] = React.useState<DiscoveryState>({ status: 'idle' })
70
+ const [phase, setPhase] = React.useState<EnsPhase>(() => {
71
+ if (initialView === 'advanced' && !hasAdvancedSetup) return { kind: 'advanced-transfer-check' }
72
+ return { kind: 'mode-select' }
73
+ })
74
+ const [validationError, setValidationError] = React.useState<string | null>(null)
75
+ const [discoveryStartedAt, setDiscoveryStartedAt] = React.useState<number>(() => Date.now())
76
+ const [operatorWalletSession, setOperatorWalletSession] = React.useState<BrowserWalletReady | null>(null)
77
+ const discoveryControllerRef = React.useRef<AbortController | null>(null)
78
+
79
+ const runDiscovery = React.useCallback(() => {
80
+ discoveryControllerRef.current?.abort()
81
+ const controller = new AbortController()
82
+ discoveryControllerRef.current = controller
83
+ setDiscovery({ status: 'loading' })
84
+ setDiscoveryStartedAt(Date.now())
85
+ setPhase({ kind: 'discovering' })
86
+ discoverOwnedEnsNameDetails(ownerAddress, {
87
+ signal: controller.signal,
88
+ budgetMs: 30_000,
89
+ rpcTimeoutMs: 8_000,
90
+ })
91
+ .then(result => {
92
+ if (controller.signal.aborted) return
93
+ if (discoveryControllerRef.current === controller) discoveryControllerRef.current = null
94
+ if (result.status === 'error') {
95
+ setDiscovery({ status: 'error', message: discoveryErrorMessage(result.errors), names: [] })
96
+ setPhase({ kind: 'pick-parent' })
97
+ return
98
+ }
99
+ setDiscovery({
100
+ status: 'ok',
101
+ names: result.names,
102
+ ...(result.status === 'partial' ? { warning: 'Some ENS lookup sources failed; showing root names found so far.' } : {}),
103
+ })
104
+ setPhase({ kind: 'pick-parent' })
105
+ })
106
+ .catch((err: unknown) => {
107
+ if (controller.signal.aborted) return
108
+ if (discoveryControllerRef.current === controller) discoveryControllerRef.current = null
109
+ setDiscovery({ status: 'error', message: err instanceof Error ? err.message : String(err), names: [] })
110
+ setPhase({ kind: 'pick-parent' })
111
+ })
112
+ }, [ownerAddress])
113
+
114
+ React.useEffect(() => () => {
115
+ discoveryControllerRef.current?.abort()
116
+ }, [])
117
+
118
+ const cancelDiscoveryToModeSelect = React.useCallback(() => {
119
+ discoveryControllerRef.current?.abort()
120
+ discoveryControllerRef.current = null
121
+ setDiscovery({ status: 'idle' })
122
+ setPhase({ kind: 'mode-select' })
123
+ }, [])
124
+
125
+ const backToSimpleSubdomain = React.useCallback((fullName: string): void => {
126
+ const parts = splitSubdomainName(fullName)
127
+ setPhase(parts ? { kind: 'pick-subdomain', parent: parts.parent, label: parts.label } : { kind: 'pick-parent' })
128
+ }, [])
129
+
130
+ const runValidation = React.useCallback(async (
131
+ fullName: string,
132
+ mode: 'simple' | 'advanced',
133
+ phaseOwnerAddress?: Address,
134
+ operatorWallet?: Address,
135
+ ): Promise<void> => {
136
+ setValidationError(null)
137
+ setPhase({ kind: 'validating', fullName, mode, ownerAddress: phaseOwnerAddress, operatorWallet })
138
+ try {
139
+ const validation = await validateAgentEnsLink(fullName, ownerAddress)
140
+ const currentText = validation.ok
141
+ ? await readEthagentTextRecords(fullName, AGENT_RECORD_READ_KEY_LIST)
142
+ : {}
143
+ const current = recordsFromTextMap(currentText)
144
+ const next = buildAgentEnsRecords({
145
+ chainId: registry.chainId,
146
+ identityRegistryAddress: registry.identityRegistryAddress,
147
+ agentId: identity.agentId,
148
+ agentCardCid,
149
+ })
150
+ const recordsDiff = diffRecords(current, next)
151
+ if (mode === 'simple' && !validation.ok && validation.reason === 'no-owner') {
152
+ setPhase({ kind: 'simple-name-missing', fullName, validation })
153
+ return
154
+ }
155
+ setPhase({ kind: 'review', fullName, validation, recordsDiff, currentRecords: current, nextRecords: next, mode, ownerAddress: phaseOwnerAddress, operatorWallet })
156
+ } catch (err: unknown) {
157
+ setValidationError(err instanceof Error ? err.message : String(err))
158
+ setPhase({ kind: 'pick-parent' })
159
+ }
160
+ }, [ownerAddress, registry, identity.agentId, agentCardCid])
161
+
162
+ const runAdvancedPreflight = React.useCallback((
163
+ rootName: string,
164
+ label: string,
165
+ operatorWallet: Address,
166
+ ): void => {
167
+ setPhase({ kind: 'advanced-preflight', rootName, label, operatorWallet })
168
+ preflightEnsSetup({
169
+ rootName,
170
+ label,
171
+ operatorAddress: operatorWallet,
172
+ registry,
173
+ agentId: identity.agentId,
174
+ agentCardCid,
175
+ }).then(result => {
176
+ if (result.ok) {
177
+ setPhase({ kind: 'advanced-review', setup: result.setup })
178
+ return
179
+ }
180
+ setPhase({ kind: 'advanced-manual', fallback: result.fallback })
181
+ }).catch((err: unknown) => {
182
+ setPhase({
183
+ kind: 'advanced-operator-wallet',
184
+ rootName,
185
+ label,
186
+ error: err instanceof Error ? err.message : String(err),
187
+ })
188
+ })
189
+ }, [agentCardCid, identity.agentId, registry])
190
+
191
+ const runAdvancedRootCheck = React.useCallback((rootName: string): void => {
192
+ setPhase({ kind: 'advanced-root-check', rootName })
193
+ preflightEnsRoot({
194
+ rootName,
195
+ expectedOwnerAddress: ownerAddress,
196
+ registry,
197
+ agentId: identity.agentId,
198
+ }).then(result => {
199
+ if (result.ok) {
200
+ setPhase({ kind: 'advanced-subdomain', rootName, label: savedSubdomainLabel || agentNameSuggestion })
201
+ return
202
+ }
203
+ setPhase({ kind: 'advanced-root', rootName, error: rootErrorMessage(result.reason, result.detail, rootName) })
204
+ }).catch((err: unknown) => {
205
+ setPhase({ kind: 'advanced-root', rootName, error: err instanceof Error ? err.message : String(err) })
206
+ })
207
+ }, [agentNameSuggestion, identity.agentId, ownerAddress, registry, savedSubdomainLabel])
208
+
209
+ const runAdvancedSubdomainCheck = React.useCallback((rootName: string, label: string): void => {
210
+ setPhase({ kind: 'advanced-subdomain-check', rootName, label })
211
+ preflightEnsSetup({
212
+ rootName,
213
+ label,
214
+ operatorAddress: ownerAddress,
215
+ allowSameOwnerOperator: true,
216
+ registry,
217
+ agentId: identity.agentId,
218
+ agentCardCid,
219
+ }).then(result => {
220
+ if (result.ok) {
221
+ setPhase({
222
+ kind: 'advanced-operator-wallet',
223
+ rootName: result.setup.rootName,
224
+ label: result.setup.label,
225
+ registryAction: result.setup.registryAction,
226
+ })
227
+ return
228
+ }
229
+ setPhase({ kind: 'advanced-manual', fallback: result.fallback })
230
+ }).catch((err: unknown) => {
231
+ setPhase({
232
+ kind: 'advanced-subdomain',
233
+ rootName,
234
+ label,
235
+ error: err instanceof Error ? err.message : String(err),
236
+ })
237
+ })
238
+ }, [agentCardCid, identity.agentId, ownerAddress, registry])
239
+
240
+ const runSimpleCreatePreflight = React.useCallback((fullName: string): void => {
241
+ const parts = splitSubdomainName(fullName)
242
+ if (!parts) {
243
+ setPhase({ kind: 'pick-parent' })
244
+ return
245
+ }
246
+ setPhase({ kind: 'simple-create-preflight', rootName: parts.parent, label: parts.label, fullName })
247
+ preflightEnsSetup({
248
+ rootName: parts.parent,
249
+ label: parts.label,
250
+ operatorAddress: ownerAddress,
251
+ mode: 'simple',
252
+ expectedOwnerAddress: ownerAddress,
253
+ allowSameOwnerOperator: true,
254
+ registry,
255
+ agentId: identity.agentId,
256
+ agentCardCid,
257
+ }).then(result => {
258
+ if (result.ok) {
259
+ setPhase({ kind: 'simple-create-review', setup: result.setup })
260
+ return
261
+ }
262
+ setPhase({ kind: 'simple-create-blocked', fallback: result.fallback })
263
+ }).catch((err: unknown) => {
264
+ setPhase({
265
+ kind: 'pick-subdomain',
266
+ parent: parts.parent,
267
+ label: parts.label,
268
+ error: err instanceof Error ? err.message : String(err),
269
+ })
270
+ })
271
+ }, [agentCardCid, identity.agentId, ownerAddress, registry])
272
+
273
+ const connectOperatorWallet = React.useCallback((rootName: string, label: string): void => {
274
+ setOperatorWalletSession(null)
275
+ setPhase({ kind: 'advanced-operator-wallet-connecting', rootName, label })
276
+ requestBrowserWalletAccount({
277
+ purpose: 'connect-operator-wallet',
278
+ onReady: ready => setOperatorWalletSession(ready),
279
+ }).then(wallet => {
280
+ const operatorWallet = getAddress(wallet.account)
281
+ setOperatorWalletSession(null)
282
+ runAdvancedPreflight(rootName, label, operatorWallet)
283
+ }).catch((err: unknown) => {
284
+ setOperatorWalletSession(null)
285
+ setPhase({ kind: 'advanced-operator-wallet', rootName, label, error: err instanceof Error ? err.message : String(err) })
286
+ })
287
+ }, [runAdvancedPreflight])
288
+
289
+ const runDeleteSubdomainPreflight = React.useCallback((fullName: string): void => {
290
+ setValidationError(null)
291
+ setPhase({ kind: 'delete-subdomain-preflight', fullName })
292
+ preflightDeleteSubdomain({ fullName, expectedOwnerAddress: ownerAddress })
293
+ .then(result => {
294
+ if (result.ok) {
295
+ setPhase({ kind: 'delete-subdomain-confirm', plan: result.plan })
296
+ return
297
+ }
298
+ setPhase({ kind: 'delete-subdomain-blocked', fullName, reason: result.detail })
299
+ })
300
+ .catch((err: unknown) => {
301
+ setPhase({ kind: 'delete-subdomain-blocked', fullName, reason: err instanceof Error ? err.message : String(err) })
302
+ })
303
+ }, [ownerAddress])
304
+
305
+ const runUnlinkEnsLoading = React.useCallback((fullName: string): void => {
306
+ setValidationError(null)
307
+ setPhase({ kind: 'unlink-loading', fullName })
308
+ readEthagentTextRecords(fullName, AGENT_RECORD_READ_KEY_LIST)
309
+ .then(currentText => {
310
+ const currentRecords = recordsFromTextMap(currentText)
311
+ setPhase({
312
+ kind: 'unlink-review',
313
+ fullName,
314
+ currentRecords,
315
+ recordsDiff: diffRecords(currentRecords, emptyAgentEnsRecords()),
316
+ })
317
+ })
318
+ .catch((err: unknown) => {
319
+ setValidationError(err instanceof Error ? err.message : String(err))
320
+ setPhase({ kind: 'mode-select' })
321
+ })
322
+ }, [])
323
+
324
+ const maintenanceScreen = renderEnsMaintenancePhase({
325
+ phase,
326
+ currentEnsName,
327
+ currentEnsCanDelete: Boolean(currentEnsParts),
328
+ savedCustodyMode,
329
+ savedOwnerAddress,
330
+ savedOperator,
331
+ registryNetworkLabel,
332
+ validationError,
333
+ ownerAddress,
334
+ operatorWalletSession,
335
+ setOperatorWalletSession,
336
+ setPhase,
337
+ runDiscovery,
338
+ runUnlinkEnsLoading,
339
+ runDeleteSubdomainPreflight,
340
+ onBack,
341
+ onEnsUnlink,
342
+ onEnsRecordsUpdate,
343
+ onManageOperatorWalletAccess,
344
+ })
345
+ if (maintenanceScreen) return maintenanceScreen
346
+
347
+ const advancedScreen = renderAdvancedEnsPhase({
348
+ phase,
349
+ ownerAddress,
350
+ agentId: identity.agentId,
351
+ savedOwnerAddress,
352
+ savedOperator,
353
+ savedRootName,
354
+ savedSubdomainLabel,
355
+ agentNameSuggestion,
356
+ currentEnsName,
357
+ savedCustodyMode,
358
+ registry,
359
+ operatorWalletSession,
360
+ setPhase,
361
+ connectOperatorWallet,
362
+ runAdvancedRootCheck,
363
+ runAdvancedSubdomainCheck,
364
+ runAdvancedPreflight,
365
+ onEnsSetup,
366
+ onEnsLink,
367
+ })
368
+ if (advancedScreen) return advancedScreen
369
+
370
+ const simpleScreen = renderSimpleEnsPhase({
371
+ phase,
372
+ discovery,
373
+ ownerAddress,
374
+ discoveryStartedAt,
375
+ validationError,
376
+ currentEnsName,
377
+ savedCustodyMode,
378
+ registryNetworkLabel,
379
+ registry,
380
+ agentNameSuggestion,
381
+ operatorWalletSession,
382
+ setOperatorWalletSession,
383
+ setPhase,
384
+ cancelDiscoveryToModeSelect,
385
+ runDiscovery,
386
+ runValidation,
387
+ backToSimpleSubdomain,
388
+ runSimpleCreatePreflight,
389
+ onEnsSetup,
390
+ onEnsLink,
391
+ onEnsRecordsUpdate,
392
+ identity,
393
+ })
394
+ if (simpleScreen) return simpleScreen
395
+
396
+ return null
397
+ }