ethagent 2.1.1 → 2.3.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 (177) hide show
  1. package/package.json +2 -1
  2. package/src/app/FirstRun.tsx +1 -7
  3. package/src/app/FirstRunTimeline.tsx +1 -1
  4. package/src/auth/openaiOAuth/credentials.ts +47 -0
  5. package/src/auth/openaiOAuth/crypto.ts +23 -0
  6. package/src/auth/openaiOAuth/index.ts +238 -0
  7. package/src/auth/openaiOAuth/landingPage.ts +125 -0
  8. package/src/auth/openaiOAuth/listener.ts +151 -0
  9. package/src/auth/openaiOAuth/refresh.ts +70 -0
  10. package/src/auth/openaiOAuth/shared.ts +115 -0
  11. package/src/chat/ChatBottomPane.tsx +20 -11
  12. package/src/chat/ChatScreen.tsx +160 -35
  13. package/src/chat/ConversationStack.tsx +1 -1
  14. package/src/chat/MessageList.tsx +185 -72
  15. package/src/chat/SessionStatus.tsx +3 -1
  16. package/src/chat/chatScreenUtils.ts +11 -15
  17. package/src/chat/chatSessionState.ts +3 -2
  18. package/src/chat/chatTurnOrchestrator.ts +1 -7
  19. package/src/chat/commands.ts +28 -27
  20. package/src/chat/display/DiffView.tsx +193 -0
  21. package/src/chat/display/SyntaxText.tsx +192 -0
  22. package/src/chat/display/toolCallDisplay.ts +103 -0
  23. package/src/chat/display/toolResultDisplay.ts +19 -0
  24. package/src/chat/{ChatInput.tsx → input/ChatInput.tsx} +36 -23
  25. package/src/chat/{TranscriptView.tsx → transcript/TranscriptView.tsx} +24 -50
  26. package/src/chat/{transcriptViewport.ts → transcript/transcriptViewport.ts} +12 -30
  27. package/src/chat/{ContextLimitView.tsx → views/ContextLimitView.tsx} +3 -3
  28. package/src/chat/{ContinuityEditReviewView.tsx → views/ContinuityEditReviewView.tsx} +11 -3
  29. package/src/chat/{CopyPicker.tsx → views/CopyPicker.tsx} +4 -5
  30. package/src/chat/{PermissionPrompt.tsx → views/PermissionPrompt.tsx} +16 -17
  31. package/src/chat/{PermissionsView.tsx → views/PermissionsView.tsx} +6 -6
  32. package/src/chat/{PlanApprovalView.tsx → views/PlanApprovalView.tsx} +4 -4
  33. package/src/chat/{ResumeView.tsx → views/ResumeView.tsx} +35 -35
  34. package/src/chat/views/RewindView.tsx +410 -0
  35. package/src/identity/continuity/privateEdit/diff.ts +2 -78
  36. package/src/identity/ens/agentRecords.ts +5 -19
  37. package/src/identity/ens/ensAutomation/setup.ts +0 -1
  38. package/src/identity/ens/ensAutomation/types.ts +0 -1
  39. package/src/identity/hub/OperationalRoutes.tsx +23 -32
  40. package/src/identity/hub/Routes.tsx +13 -13
  41. package/src/identity/hub/{flows/continuity → continuity}/ContinuityDashboardScreen.tsx +9 -9
  42. package/src/identity/hub/{flows/continuity → continuity}/RebackupStorageScreen.tsx +2 -2
  43. package/src/identity/hub/{flows/continuity → continuity}/RecoveryConfirmScreen.tsx +5 -5
  44. package/src/identity/hub/{flows/continuity → continuity}/SavePromptScreen.tsx +5 -5
  45. package/src/identity/hub/{effects/rebackup/runRebackup.ts → continuity/effects.ts} +19 -19
  46. package/src/identity/hub/{effects/rebackup → continuity}/index.ts +1 -1
  47. package/src/identity/hub/{effects/shared → continuity}/snapshot.ts +8 -8
  48. package/src/identity/hub/{effects/rebackup → continuity}/vault.ts +15 -15
  49. package/src/identity/hub/{flows/create → create}/CreateFlow.tsx +13 -13
  50. package/src/identity/hub/{effects/create.ts → create/effects.ts} +4 -4
  51. package/src/identity/hub/{flows/custody → custody}/CustodyEditFlow.tsx +10 -48
  52. package/src/identity/hub/{flows/custody/custodyFlowActions.ts → custody/actions.ts} +11 -9
  53. package/src/identity/hub/{flows/custody/custodyFlowHelpers.ts → custody/helpers.ts} +4 -4
  54. package/src/identity/hub/{effects/vault → custody}/preflight.ts +5 -5
  55. package/src/identity/hub/{flows/custody/custodyFlowRoutes.tsx → custody/routes.tsx} +8 -8
  56. package/src/identity/hub/{flows/custody/custodyEffects.ts → custody/transactions.ts} +9 -9
  57. package/src/identity/hub/{flows/custody/custodyFlowTypes.ts → custody/types.ts} +6 -6
  58. package/src/identity/hub/{flows/custody/custodyFlowEffects.ts → custody/useCustodyEffects.ts} +7 -7
  59. package/src/identity/hub/{flows/custody → custody}/useCustodyFlow.tsx +5 -5
  60. package/src/identity/hub/ens/EnsEditAdvancedScreens.tsx +241 -0
  61. package/src/identity/hub/{flows/ens → ens}/EnsEditFlow.tsx +27 -82
  62. package/src/identity/hub/{flows/ens → ens}/EnsEditMaintenanceScreens.tsx +25 -65
  63. package/src/identity/hub/{flows/ens → ens}/EnsEditReviewScreens.tsx +12 -30
  64. package/src/identity/hub/ens/EnsEditRunners.tsx +62 -0
  65. package/src/identity/hub/{flows/ens → ens}/EnsEditShared.tsx +15 -14
  66. package/src/identity/hub/{flows/ens → ens}/EnsEditSimpleScreens.tsx +68 -217
  67. package/src/identity/hub/{flows/ens/IdentityHubEnsFlow.tsx → ens/EnsFlow.tsx} +18 -11
  68. package/src/identity/hub/{flows/ens/OperatorWalletsScreen.tsx → ens/EnsOperatorWalletsScreen.tsx} +17 -48
  69. package/src/identity/hub/{advancedEnsValidation.ts → ens/advancedEnsValidation.ts} +2 -2
  70. package/src/identity/hub/{flows/ens/ensEditCopy.ts → ens/editCopy.ts} +4 -4
  71. package/src/identity/hub/{effects/ens/flows.ts → ens/effects.ts} +7 -7
  72. package/src/identity/hub/{effects/ens → ens}/index.ts +1 -1
  73. package/src/identity/hub/{model/ens.ts → ens/state.ts} +1 -1
  74. package/src/identity/hub/{effects/ens → ens}/transactions.ts +232 -232
  75. package/src/identity/hub/{flows/ens/ensEditTypes.ts → ens/types.ts} +12 -26
  76. package/src/identity/hub/identityHubReducer.ts +3 -3
  77. package/src/identity/hub/{flows/profile → profile}/EditProfileFlow.tsx +17 -10
  78. package/src/identity/hub/{effects/publicProfile/runPublicProfileSave.ts → profile/effects.ts} +55 -177
  79. package/src/identity/hub/{model → profile}/identity.ts +3 -3
  80. package/src/identity/hub/{effects/profile/profileState.ts → profile/state.ts} +181 -173
  81. package/src/identity/hub/{flows/restore → restore}/RestoreFlow.tsx +21 -21
  82. package/src/identity/hub/{effects/restore → restore}/apply.ts +10 -10
  83. package/src/identity/hub/{effects/restore → restore}/auth.ts +7 -7
  84. package/src/identity/hub/{effects/restore → restore}/discover.ts +6 -6
  85. package/src/identity/hub/{effects/restore → restore}/envelopes.ts +2 -2
  86. package/src/identity/hub/{effects/restore → restore}/fetch.ts +3 -3
  87. package/src/identity/hub/{effects/restore/shared.ts → restore/helpers.ts} +6 -6
  88. package/src/identity/hub/{effects/restore → restore}/recovery.ts +10 -10
  89. package/src/identity/hub/{effects/restore → restore}/resolve.ts +4 -4
  90. package/src/identity/hub/restore/restoreAdmin.ts +34 -0
  91. package/src/identity/hub/{flows/restore/useRestoreFlowEffects.ts → restore/useRestoreEffects.ts} +5 -5
  92. package/src/identity/hub/{flows/settings → settings}/StorageCredentialScreen.tsx +5 -5
  93. package/src/identity/hub/{components → shared/components}/BusyScreen.tsx +4 -4
  94. package/src/identity/hub/{components → shared/components}/DetailsScreen.tsx +4 -4
  95. package/src/identity/hub/{components → shared/components}/ErrorScreen.tsx +4 -4
  96. package/src/identity/hub/{components → shared/components}/FlowTimeline.tsx +1 -1
  97. package/src/identity/hub/{components → shared/components}/IdentitySummary.tsx +16 -11
  98. package/src/identity/hub/{components → shared/components}/MenuScreen.tsx +8 -9
  99. package/src/identity/hub/{components → shared/components}/NetworkScreen.tsx +4 -4
  100. package/src/identity/hub/{components → shared/components}/PinataJwtInput.tsx +4 -4
  101. package/src/identity/hub/{components → shared/components}/UnlinkedIdentityScreen.tsx +5 -5
  102. package/src/identity/hub/{components → shared/components}/WalletApprovalScreen.tsx +6 -6
  103. package/src/identity/hub/{components → shared/components}/menuFlagsFromReconciliation.ts +2 -4
  104. package/src/identity/hub/{effects/shared → shared/effects}/profilePrep.ts +1 -1
  105. package/src/identity/hub/{effects → shared/effects}/receipts.ts +2 -2
  106. package/src/identity/hub/{effects/shared → shared/effects}/sync.ts +6 -47
  107. package/src/identity/hub/{effects → shared/effects}/types.ts +3 -3
  108. package/src/identity/hub/{model → shared/model}/copy.ts +2 -2
  109. package/src/identity/hub/{model → shared/model}/errors.ts +5 -5
  110. package/src/identity/hub/{model → shared/model}/network.ts +3 -3
  111. package/src/identity/hub/{operatorWallets.ts → shared/operatorWallets.ts} +1 -1
  112. package/src/identity/hub/{reconciliation → shared/reconciliation}/agentReconciliation/hook.ts +1 -2
  113. package/src/identity/hub/{reconciliation → shared/reconciliation}/agentReconciliation/ownership.ts +2 -2
  114. package/src/identity/hub/{reconciliation → shared/reconciliation}/agentReconciliation/run.ts +7 -40
  115. package/src/identity/hub/{reconciliation → shared/reconciliation}/agentReconciliation/types.ts +0 -4
  116. package/src/identity/hub/{reconciliation → shared/reconciliation}/index.ts +0 -7
  117. package/src/identity/hub/shared/reconciliation/walletSetup.ts +27 -0
  118. package/src/identity/hub/{utils.ts → shared/utils.ts} +5 -5
  119. package/src/identity/hub/{flows/token-transfer/IdentityHubTokenTransferFlow.tsx → transfer/TokenTransferFlow.tsx} +8 -8
  120. package/src/identity/hub/{flows/token-transfer → transfer}/TokenTransferScreens.tsx +14 -14
  121. package/src/identity/hub/{effects/token-transfer/runTokenTransfer.ts → transfer/effects.ts} +16 -16
  122. package/src/identity/hub/{effects/token-transfer → transfer}/progress.ts +1 -1
  123. package/src/identity/hub/useIdentityHubController.ts +11 -11
  124. package/src/identity/hub/useIdentityHubSideEffects.ts +11 -11
  125. package/src/identity/wallet/browserWallet/types.ts +0 -5
  126. package/src/identity/wallet/page/copy.ts +1 -31
  127. package/src/identity/wallet/walletPurposeCompat.ts +0 -2
  128. package/src/models/ModelPicker.tsx +248 -8
  129. package/src/models/catalog.ts +29 -1
  130. package/src/models/modelPickerOptions.ts +12 -10
  131. package/src/models/providerDisplay.ts +16 -0
  132. package/src/providers/errors.ts +6 -4
  133. package/src/providers/openai-chat.ts +2 -1
  134. package/src/providers/openai-responses-format.ts +156 -0
  135. package/src/providers/openai-responses.ts +276 -0
  136. package/src/providers/registry.ts +85 -8
  137. package/src/runtime/sessionMode.ts +1 -1
  138. package/src/runtime/systemPrompt.ts +4 -2
  139. package/src/runtime/toolExecution.ts +9 -6
  140. package/src/runtime/turn.ts +29 -1
  141. package/src/storage/rewind.ts +20 -0
  142. package/src/storage/secrets.ts +4 -1
  143. package/src/storage/sessions.ts +2 -1
  144. package/src/tools/bashSafety.ts +7 -3
  145. package/src/tools/bashTool.ts +1 -1
  146. package/src/tools/contracts.ts +3 -0
  147. package/src/tools/deleteFileTool.ts +8 -3
  148. package/src/tools/editTool.ts +10 -5
  149. package/src/tools/fileDiff.ts +261 -0
  150. package/src/tools/privateContinuityEditTool.ts +11 -1
  151. package/src/tools/writeFileTool.ts +8 -3
  152. package/src/ui/Spinner.tsx +25 -3
  153. package/src/ui/TextInput.tsx +2 -2
  154. package/src/ui/theme.ts +17 -0
  155. package/src/utils/clipboard.ts +10 -7
  156. package/src/utils/openExternal.ts +20 -10
  157. package/src/chat/RewindView.tsx +0 -386
  158. package/src/chat/toolResultDisplay.ts +0 -8
  159. package/src/identity/ens/ensRegistration.ts +0 -199
  160. package/src/identity/hub/effects/index.ts +0 -74
  161. package/src/identity/hub/effects/publicProfile/index.ts +0 -5
  162. package/src/identity/hub/effects/restore/restoreEffects.ts +0 -22
  163. package/src/identity/hub/effects/restoreAdmin.ts +0 -93
  164. package/src/identity/hub/effects/token-transfer/index.ts +0 -6
  165. package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +0 -336
  166. package/src/identity/hub/flows/ens/EnsEditRunners.tsx +0 -198
  167. package/src/identity/hub/reconciliation/walletSetup.ts +0 -220
  168. /package/src/chat/{chatInputState.ts → input/chatInputState.ts} +0 -0
  169. /package/src/chat/{chatPaste.ts → input/chatPaste.ts} +0 -0
  170. /package/src/chat/{textCursor.ts → input/textCursor.ts} +0 -0
  171. /package/src/identity/hub/{model/continuity.ts → continuity/state.ts} +0 -0
  172. /package/src/identity/hub/{model/custody.ts → custody/state.ts} +0 -0
  173. /package/src/identity/hub/{effects/restore → restore}/index.ts +0 -0
  174. /package/src/identity/hub/{model → shared/model}/format.ts +0 -0
  175. /package/src/identity/hub/{reconciliation → shared/reconciliation}/useAgentReconciliation.ts +0 -0
  176. /package/src/identity/hub/{txGuard.ts → shared/txGuard.ts} +0 -0
  177. /package/src/identity/hub/{model/transfer.ts → transfer/state.ts} +0 -0
@@ -1,10 +1,10 @@
1
1
  import type React from 'react'
2
2
  import type { Address } from 'viem'
3
- import type { EthagentConfig, EthagentIdentity } from '../../../../storage/config.js'
4
- import type { Erc8004RegistryConfig } from '../../../registry/erc8004.js'
5
- import type { EffectCallbacks } from '../../effects/types.js'
6
- import type { ProfileUpdates, Step } from '../../identityHubReducer.js'
7
- import type { WalletApprovalScreen } from '../../components/WalletApprovalScreen.js'
3
+ import type { EthagentConfig, EthagentIdentity } from '../../../storage/config.js'
4
+ import type { Erc8004RegistryConfig } from '../../registry/erc8004.js'
5
+ import type { EffectCallbacks } from '../shared/effects/types.js'
6
+ import type { ProfileUpdates, Step } from '../identityHubReducer.js'
7
+ import type { WalletApprovalScreen } from '../shared/components/WalletApprovalScreen.js'
8
8
 
9
9
  export type GuardOwnership = (
10
10
  identity: EthagentIdentity,
@@ -35,7 +35,7 @@ export interface CustodyFlowDeps {
35
35
  export interface CustodyFlow {
36
36
  beginVaultDeposit: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
37
37
  beginVaultUnwrap: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
38
- beginWithdrawToken: (currentStep: Step, returnTo: Step) => void
38
+ beginWithdrawToken: (currentStep: Step, returnTo: Step, returnContext?: 'ens' | 'simple-exit') => void
39
39
  beginReturnToVault: (currentStep: Step, returnTo: Step, vaultAddress: Address) => void
40
40
  renderCustodyStep: () => React.ReactElement | null
41
41
  renderRebackupSubtitle: (
@@ -1,16 +1,16 @@
1
1
  import { useEffect } from 'react'
2
- import { createErc8004PublicClient } from '../../../registry/erc8004.js'
3
- import { confirmAgentInVault } from '../../../registry/vault.js'
4
- import { invalidateOwnershipCache } from '../../reconciliation/index.js'
5
- import type { ProfileUpdates } from '../../identityHubReducer.js'
6
- import type { CustodyFlowDeps } from './custodyFlowTypes.js'
7
- import { humanOwnerAddress } from './custodyFlowHelpers.js'
2
+ import { createErc8004PublicClient } from '../../registry/erc8004.js'
3
+ import { confirmAgentInVault } from '../../registry/vault.js'
4
+ import { invalidateOwnershipCache } from '../shared/reconciliation/index.js'
5
+ import type { ProfileUpdates } from '../identityHubReducer.js'
6
+ import type { CustodyFlowDeps } from './types.js'
7
+ import { humanOwnerAddress } from './helpers.js'
8
8
  import {
9
9
  runVaultDeployTransaction,
10
10
  runVaultDepositTransaction,
11
11
  runVaultUnwrapTransaction,
12
12
  runVaultWithdrawTransaction,
13
- } from './custodyEffects.js'
13
+ } from './transactions.js'
14
14
 
15
15
  export function useCustodyTransactionEffects({
16
16
  step,
@@ -1,10 +1,10 @@
1
- import type { CustodyFlow, CustodyFlowDeps } from './custodyFlowTypes.js'
2
- import { createCustodyFlowActions } from './custodyFlowActions.js'
3
- import { useCustodyTransactionEffects } from './custodyFlowEffects.js'
1
+ import type { CustodyFlow, CustodyFlowDeps } from './types.js'
2
+ import { createCustodyFlowActions } from './actions.js'
3
+ import { useCustodyTransactionEffects } from './useCustodyEffects.js'
4
4
  import {
5
5
  renderCustodyStep,
6
6
  renderRebackupSubtitle,
7
- } from './custodyFlowRoutes.js'
7
+ } from './routes.js'
8
8
 
9
9
  export function useCustodyFlow(deps: CustodyFlowDeps): CustodyFlow {
10
10
  useCustodyTransactionEffects(deps)
@@ -22,4 +22,4 @@ export type {
22
22
  CustodyFlowDeps,
23
23
  GuardOwnership,
24
24
  TriggerRebackup,
25
- } from './custodyFlowTypes.js'
25
+ } from './types.js'
@@ -0,0 +1,241 @@
1
+ import React from 'react'
2
+ import { Box, Text } from 'ink'
3
+ import { type Address } from 'viem'
4
+ import { Surface } from '../../../ui/Surface.js'
5
+ import { Select } from '../../../ui/Select.js'
6
+ import { TextInput } from '../../../ui/TextInput.js'
7
+ import { Spinner } from '../../../ui/Spinner.js'
8
+ import { theme } from '../../../ui/theme.js'
9
+ import {
10
+ normalizeEthDomain,
11
+ sanitizeSubdomainPrefix,
12
+ } from '../../ens/ensLookup.js'
13
+ import { isRootEthName } from '../../ens/ensAutomation.js'
14
+ import type { Erc8004RegistryConfig } from '../../registry/erc8004.js'
15
+ import {
16
+ type CustodyMode,
17
+ } from '../custody/state.js'
18
+ import { shortAddress } from '../shared/model/format.js'
19
+ import {
20
+ footerHint,
21
+ } from './EnsEditShared.js'
22
+ import { IdentitySummary } from '../shared/components/IdentitySummary.js'
23
+ import {
24
+ EnsSetupBlockedScreen,
25
+ EnsSetupReviewScreen,
26
+ } from './EnsEditReviewScreens.js'
27
+ import { EscCancel } from './EnsEditRunners.js'
28
+ import type {
29
+ EnsEditProps,
30
+ EnsPhase,
31
+ } from './types.js'
32
+ import type { AgentReconciliation } from '../shared/reconciliation/index.js'
33
+
34
+ type AdvancedScreenProps = {
35
+ phase: EnsPhase
36
+ identity: EnsEditProps['identity']
37
+ ownerAddress: Address
38
+ agentId: EnsEditProps['identity']['agentId']
39
+ reconciliation: AgentReconciliation
40
+ savedSubdomainLabel: string
41
+ agentNameSuggestion: string
42
+ currentEnsName: string
43
+ savedCustodyMode: CustodyMode | undefined
44
+ registry: Erc8004RegistryConfig
45
+ setPhase: (phase: EnsPhase) => void
46
+ runDiscovery: (mode?: 'simple' | 'advanced') => void
47
+ runAdvancedSubdomainCheck: (rootName: string, label: string) => void
48
+ onEnsSetup: EnsEditProps['onEnsSetup']
49
+ onEnsLink: EnsEditProps['onEnsLink']
50
+ onWithdrawToken: () => void
51
+ }
52
+
53
+ export function renderAdvancedEnsPhase({
54
+ phase,
55
+ identity,
56
+ ownerAddress,
57
+ agentId,
58
+ reconciliation,
59
+ savedSubdomainLabel,
60
+ agentNameSuggestion,
61
+ currentEnsName,
62
+ savedCustodyMode,
63
+ registry,
64
+ setPhase,
65
+ runDiscovery,
66
+ runAdvancedSubdomainCheck,
67
+ onEnsSetup,
68
+ onEnsLink,
69
+ onWithdrawToken,
70
+ }: AdvancedScreenProps): React.ReactNode | null {
71
+ if (phase.kind === 'advanced-transfer-check') {
72
+ type TransferCheckAction = 'continue' | 'withdraw' | 'back'
73
+ const custody = reconciliation.custody
74
+ const tokenInVault = custody === 'advanced' || custody === 'mid-flow-uri-pending'
75
+ const tokenInOwnerWallet = custody === 'simple' || custody === 'withdrawn'
76
+ const probePending = custody === 'unknown' && reconciliation.rpc !== 'failing'
77
+ const probeFailed = reconciliation.rpc === 'failing'
78
+
79
+ const options: Array<{ value: TransferCheckAction; role?: 'section' | 'utility'; label: string; hint?: string }> = []
80
+ options.push({ value: 'continue', role: 'section', label: 'Setup' })
81
+ if (tokenInOwnerWallet) {
82
+ options.push({
83
+ value: 'continue',
84
+ label: 'Continue ENS Setup',
85
+ hint: 'Owner wallet holds this token onchain.',
86
+ })
87
+ } else if (tokenInVault) {
88
+ options.push({
89
+ value: 'withdraw',
90
+ label: 'Withdraw Token',
91
+ hint: 'Pull token out to sign ENS records. Redeposit to the Vault any time after.',
92
+ })
93
+ } else if (probePending) {
94
+ options.push({
95
+ value: 'continue',
96
+ label: 'Checking onchain state…',
97
+ hint: 'Try again in a moment.',
98
+ })
99
+ } else if (probeFailed) {
100
+ options.push({
101
+ value: 'continue',
102
+ label: 'Onchain check unavailable',
103
+ hint: 'RPC unreachable. Resolve connectivity, then retry.',
104
+ })
105
+ } else {
106
+ options.push({
107
+ value: 'continue',
108
+ label: 'Token Owner Unknown',
109
+ hint: 'Try again in a moment.',
110
+ })
111
+ }
112
+ options.push({ value: 'back', role: 'section', label: 'Navigation' })
113
+ options.push({ value: 'back', label: 'Back', hint: 'Return to setup type', role: 'utility' })
114
+
115
+ return (
116
+ <Surface
117
+ title="Token Custody Check"
118
+ subtitle="ENS setup continues only after the owner wallet holds this token onchain."
119
+ footer={footerHint('enter select · esc back')}
120
+ >
121
+ <Box marginTop={1}>
122
+ <Select<TransferCheckAction>
123
+ options={options}
124
+ hintLayout="inline"
125
+ onSubmit={choice => {
126
+ if (choice === 'withdraw') {
127
+ onWithdrawToken()
128
+ return
129
+ }
130
+ if (choice === 'continue' && tokenInOwnerWallet) {
131
+ runDiscovery('advanced')
132
+ return
133
+ }
134
+ if (choice === 'back') {
135
+ return setPhase({ kind: 'mode-select' })
136
+ }
137
+ }}
138
+ onCancel={() => setPhase({ kind: 'mode-select' })}
139
+ />
140
+ </Box>
141
+ </Surface>
142
+ )
143
+ }
144
+
145
+ if (phase.kind === 'advanced-root-check') {
146
+ return (
147
+ <Surface
148
+ title="Checking ENS and Token Ownership"
149
+ subtitle={`Verifying the connected wallet manages ${phase.rootName} and owns the ERC-8004 token.`}
150
+ footer={footerHint('esc back')}
151
+ >
152
+ <Box marginTop={1}>
153
+ <Text color={theme.textSubtle}>Reading from Ethereum mainnet...</Text>
154
+ </Box>
155
+ </Surface>
156
+ )
157
+ }
158
+
159
+ if (phase.kind === 'advanced-subdomain') {
160
+ const rootName = phase.rootName
161
+ return (
162
+ <Surface
163
+ title="Agent Subdomain"
164
+ subtitle={`Pick a subdomain label under ${rootName}.`}
165
+ footer={footerHint('enter next · esc back')}
166
+ >
167
+ {phase.error ? (
168
+ <Box flexDirection="column">
169
+ <Text color={theme.accentError}>{phase.error}</Text>
170
+ </Box>
171
+ ) : null}
172
+ <Box marginTop={1}>
173
+ <TextInput
174
+ key={`advanced-subdomain-${rootName}`}
175
+ initialValue={phase.label || savedSubdomainLabel || ''}
176
+ placeholder={agentNameSuggestion || 'agent-name'}
177
+ validate={value => {
178
+ const trimmed = value.trim()
179
+ const label = sanitizeSubdomainPrefix(trimmed)
180
+ if (!label) return 'Enter a subdomain label'
181
+ if (trimmed.includes('.')) return 'Enter only the subdomain label'
182
+ if (label !== trimmed.toLowerCase()) return 'Use lowercase letters, numbers, and hyphens only'
183
+ return null
184
+ }}
185
+ onSubmit={value => runAdvancedSubdomainCheck(rootName, sanitizeSubdomainPrefix(value))}
186
+ onCancel={() => setPhase({ kind: 'pick-parent', mode: 'advanced' })}
187
+ />
188
+ </Box>
189
+ </Surface>
190
+ )
191
+ }
192
+
193
+ if (phase.kind === 'advanced-subdomain-check') {
194
+ return (
195
+ <Surface
196
+ title="Check Agent Subdomain"
197
+ subtitle={`Verifying ${phase.label}.${phase.rootName} on Ethereum Mainnet.`}
198
+ footer={footerHint('esc back')}
199
+ >
200
+ <Box marginTop={1}>
201
+ <Spinner label="checking agent subdomain..." />
202
+ </Box>
203
+ <EscCancel onCancel={() => setPhase({ kind: 'advanced-subdomain', rootName: phase.rootName, label: phase.label })} />
204
+ </Surface>
205
+ )
206
+ }
207
+
208
+ if (phase.kind === 'advanced-review') {
209
+ return (
210
+ <EnsSetupReviewScreen
211
+ setup={phase.setup}
212
+ currentEnsName={currentEnsName}
213
+ currentMode={savedCustodyMode}
214
+ registry={registry}
215
+ onBegin={() => {
216
+ if (phase.setup.txCount > 0) {
217
+ onEnsSetup(phase.setup)
218
+ return
219
+ }
220
+ onEnsLink(phase.setup.fullName, {
221
+ mode: 'advanced',
222
+ ownerAddress: phase.setup.ownerAddress,
223
+ })
224
+ }}
225
+ onBack={() => setPhase({ kind: 'advanced-subdomain', rootName: phase.setup.rootName, label: phase.setup.label })}
226
+ />
227
+ )
228
+ }
229
+
230
+ if (phase.kind === 'advanced-manual') {
231
+ return (
232
+ <EnsSetupBlockedScreen
233
+ fallback={phase.fallback}
234
+ onCheckAgain={() => runAdvancedSubdomainCheck(phase.fallback.rootName, phase.fallback.label)}
235
+ onBack={() => setPhase({ kind: 'advanced-subdomain', rootName: phase.fallback.rootName, label: phase.fallback.label })}
236
+ />
237
+ )
238
+ }
239
+
240
+ return null
241
+ }
@@ -1,35 +1,34 @@
1
1
  import React from 'react'
2
2
  import { getAddress, type Address } from 'viem'
3
- import type { BrowserWalletReady } from '../../../wallet/browserWallet.js'
4
- import { requestBrowserWalletAccount } from '../../../wallet/browserWallet.js'
3
+ import type { BrowserWalletReady } from '../../wallet/browserWallet.js'
5
4
  import {
6
5
  AGENT_RECORD_READ_KEY_LIST,
7
6
  buildAgentEnsRecords,
8
7
  diffRecords,
9
8
  recordsFromTextMap,
10
- } from '../../../ens/agentRecords.js'
9
+ } from '../../ens/agentRecords.js'
11
10
  import {
12
11
  discoverOwnedEnsNameDetails,
13
12
  readEthagentTextRecords,
14
13
  sanitizeSubdomainPrefix,
15
14
  splitSubdomainName,
16
15
  validateAgentEnsLink,
17
- } from '../../../ens/ensLookup.js'
16
+ } from '../../ens/ensLookup.js'
18
17
  import {
19
18
  preflightDeleteSubdomain,
20
19
  preflightEnsRoot,
21
20
  preflightEnsSetup,
22
- } from '../../../ens/ensAutomation.js'
21
+ } from '../../ens/ensAutomation.js'
23
22
  import {
24
23
  readCustodyMode,
25
24
  readIdentityStateString,
26
- } from '../../model/custody.js'
25
+ } from '../custody/state.js'
27
26
  import {
28
27
  discoveryErrorMessage,
29
28
  emptyAgentEnsRecords,
30
29
  networkLabelForChainId,
31
30
  type EnsLinkOptions,
32
- } from './ensEditCopy.js'
31
+ } from './editCopy.js'
33
32
  import { rootErrorMessage } from './EnsEditShared.js'
34
33
  import { renderAdvancedEnsPhase } from './EnsEditAdvancedScreens.js'
35
34
  import { renderEnsMaintenancePhase } from './EnsEditMaintenanceScreens.js'
@@ -38,18 +37,20 @@ import type {
38
37
  DiscoveryState,
39
38
  EnsEditProps,
40
39
  EnsPhase,
41
- } from './ensEditTypes.js'
40
+ } from './types.js'
42
41
 
43
42
  export type { EnsLinkOptions }
44
43
 
45
44
  export const EnsEditFlow: React.FC<EnsEditProps> = ({
46
45
  identity,
47
46
  registry,
47
+ reconciliation,
48
48
  onEnsLink,
49
49
  onEnsUnlink,
50
50
  onEnsRecordsUpdate,
51
51
  onEnsSetup,
52
52
  onManageOperatorWalletAccess,
53
+ onWithdrawToken,
53
54
  initialView,
54
55
  onBack,
55
56
  }) => {
@@ -59,7 +60,6 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
59
60
  const savedRootName = currentEnsParts?.parent ?? ''
60
61
  const savedSubdomainLabel = currentEnsParts?.label ?? ''
61
62
  const agentNameSuggestion = sanitizeSubdomainPrefix(readIdentityStateString(identity.state, 'name'))
62
- const agentCardCid = identity.publicSkills?.agentCardCid
63
63
  const savedCustodyMode = readCustodyMode(identity.state)
64
64
  const savedOwnerAddress = readIdentityStateString(identity.state, 'ownerAddress')
65
65
  const savedOperator = readIdentityStateString(identity.state, 'activeOperatorAddress')
@@ -76,13 +76,13 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
76
76
  const [operatorWalletSession, setOperatorWalletSession] = React.useState<BrowserWalletReady | null>(null)
77
77
  const discoveryControllerRef = React.useRef<AbortController | null>(null)
78
78
 
79
- const runDiscovery = React.useCallback(() => {
79
+ const runDiscovery = React.useCallback((targetMode: 'simple' | 'advanced' = 'simple') => {
80
80
  discoveryControllerRef.current?.abort()
81
81
  const controller = new AbortController()
82
82
  discoveryControllerRef.current = controller
83
83
  setDiscovery({ status: 'loading' })
84
84
  setDiscoveryStartedAt(Date.now())
85
- setPhase({ kind: 'discovering' })
85
+ setPhase({ kind: 'discovering', mode: targetMode })
86
86
  discoverOwnedEnsNameDetails(ownerAddress, {
87
87
  signal: controller.signal,
88
88
  budgetMs: 30_000,
@@ -93,7 +93,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
93
93
  if (discoveryControllerRef.current === controller) discoveryControllerRef.current = null
94
94
  if (result.status === 'error') {
95
95
  setDiscovery({ status: 'error', message: discoveryErrorMessage(result.errors), names: [] })
96
- setPhase({ kind: 'pick-parent' })
96
+ setPhase({ kind: 'pick-parent', mode: targetMode })
97
97
  return
98
98
  }
99
99
  setDiscovery({
@@ -101,13 +101,13 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
101
101
  names: result.names,
102
102
  ...(result.status === 'partial' ? { warning: 'Some ENS lookup sources failed; showing root names found so far.' } : {}),
103
103
  })
104
- setPhase({ kind: 'pick-parent' })
104
+ setPhase({ kind: 'pick-parent', mode: targetMode })
105
105
  })
106
106
  .catch((err: unknown) => {
107
107
  if (controller.signal.aborted) return
108
108
  if (discoveryControllerRef.current === controller) discoveryControllerRef.current = null
109
109
  setDiscovery({ status: 'error', message: err instanceof Error ? err.message : String(err), names: [] })
110
- setPhase({ kind: 'pick-parent' })
110
+ setPhase({ kind: 'pick-parent', mode: targetMode })
111
111
  })
112
112
  }, [ownerAddress])
113
113
 
@@ -145,7 +145,6 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
145
145
  chainId: registry.chainId,
146
146
  identityRegistryAddress: registry.identityRegistryAddress,
147
147
  agentId: identity.agentId,
148
- agentCardCid,
149
148
  })
150
149
  const recordsDiff = diffRecords(current, next)
151
150
  if (mode === 'simple' && !validation.ok && validation.reason === 'no-owner') {
@@ -157,36 +156,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
157
156
  setValidationError(err instanceof Error ? err.message : String(err))
158
157
  setPhase({ kind: 'pick-parent' })
159
158
  }
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])
159
+ }, [ownerAddress, registry, identity.agentId])
190
160
 
191
161
  const runAdvancedRootCheck = React.useCallback((rootName: string): void => {
192
162
  setPhase({ kind: 'advanced-root-check', rootName })
@@ -197,12 +167,12 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
197
167
  agentId: identity.agentId,
198
168
  }).then(result => {
199
169
  if (result.ok) {
200
- setPhase({ kind: 'advanced-subdomain', rootName, label: savedSubdomainLabel || agentNameSuggestion })
170
+ setPhase({ kind: 'advanced-subdomain', rootName, label: savedSubdomainLabel })
201
171
  return
202
172
  }
203
- setPhase({ kind: 'advanced-root', rootName, error: rootErrorMessage(result.reason, result.detail, rootName) })
173
+ setPhase({ kind: 'pick-parent', mode: 'advanced', error: rootErrorMessage(result.reason, result.detail, rootName) })
204
174
  }).catch((err: unknown) => {
205
- setPhase({ kind: 'advanced-root', rootName, error: err instanceof Error ? err.message : String(err) })
175
+ setPhase({ kind: 'pick-parent', mode: 'advanced', error: err instanceof Error ? err.message : String(err) })
206
176
  })
207
177
  }, [agentNameSuggestion, identity.agentId, ownerAddress, registry, savedSubdomainLabel])
208
178
 
@@ -215,15 +185,9 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
215
185
  allowSameOwnerOperator: true,
216
186
  registry,
217
187
  agentId: identity.agentId,
218
- agentCardCid,
219
188
  }).then(result => {
220
189
  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
- })
190
+ setPhase({ kind: 'advanced-review', setup: result.setup })
227
191
  return
228
192
  }
229
193
  setPhase({ kind: 'advanced-manual', fallback: result.fallback })
@@ -235,7 +199,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
235
199
  error: err instanceof Error ? err.message : String(err),
236
200
  })
237
201
  })
238
- }, [agentCardCid, identity.agentId, ownerAddress, registry])
202
+ }, [identity.agentId, ownerAddress, registry])
239
203
 
240
204
  const runSimpleCreatePreflight = React.useCallback((fullName: string): void => {
241
205
  const parts = splitSubdomainName(fullName)
@@ -253,7 +217,6 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
253
217
  allowSameOwnerOperator: true,
254
218
  registry,
255
219
  agentId: identity.agentId,
256
- agentCardCid,
257
220
  }).then(result => {
258
221
  if (result.ok) {
259
222
  setPhase({ kind: 'simple-create-review', setup: result.setup })
@@ -268,23 +231,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
268
231
  error: err instanceof Error ? err.message : String(err),
269
232
  })
270
233
  })
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])
234
+ }, [identity.agentId, ownerAddress, registry])
288
235
 
289
236
  const runDeleteSubdomainPreflight = React.useCallback((fullName: string): void => {
290
237
  setValidationError(null)
@@ -323,6 +270,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
323
270
 
324
271
  const maintenanceScreen = renderEnsMaintenancePhase({
325
272
  phase,
273
+ identity,
326
274
  currentEnsName,
327
275
  currentEnsCanDelete: Boolean(currentEnsParts),
328
276
  savedCustodyMode,
@@ -340,30 +288,26 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
340
288
  onBack,
341
289
  onEnsUnlink,
342
290
  onEnsRecordsUpdate,
343
- onManageOperatorWalletAccess,
344
291
  })
345
292
  if (maintenanceScreen) return maintenanceScreen
346
293
 
347
294
  const advancedScreen = renderAdvancedEnsPhase({
348
295
  phase,
296
+ identity,
349
297
  ownerAddress,
350
298
  agentId: identity.agentId,
351
- savedOwnerAddress,
352
- savedOperator,
353
- savedRootName,
299
+ reconciliation,
354
300
  savedSubdomainLabel,
355
301
  agentNameSuggestion,
356
302
  currentEnsName,
357
303
  savedCustodyMode,
358
304
  registry,
359
- operatorWalletSession,
360
305
  setPhase,
361
- connectOperatorWallet,
362
- runAdvancedRootCheck,
306
+ runDiscovery,
363
307
  runAdvancedSubdomainCheck,
364
- runAdvancedPreflight,
365
308
  onEnsSetup,
366
309
  onEnsLink,
310
+ onWithdrawToken,
367
311
  })
368
312
  if (advancedScreen) return advancedScreen
369
313
 
@@ -384,6 +328,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
384
328
  cancelDiscoveryToModeSelect,
385
329
  runDiscovery,
386
330
  runValidation,
331
+ runAdvancedRootCheck,
387
332
  backToSimpleSubdomain,
388
333
  runSimpleCreatePreflight,
389
334
  onEnsSetup,