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,173 +1,181 @@
1
- import { getAddress, isAddress, type Address } from 'viem'
2
- import type { EthagentIdentity } from '../../../../storage/config.js'
3
- import type { Erc8004RegistryConfig } from '../../../registry/erc8004.js'
4
- import { validateAgentEnsLink, type EnsValidation } from '../../../ens/ensLookup.js'
5
- import { clearOwnerAddressField, clearVaultAddressField, readOwnerAddressField, setVaultAddressField, setOwnerAddressField } from '../../../identityCompat.js'
6
- import { validateAdvancedEnsRelationship } from '../../advancedEnsValidation.js'
7
- import { readCustodyMode } from '../../model/custody.js'
8
- import { ensValidationReasonText } from '../../model/ens.js'
9
- import type { ProfileUpdates } from '../../identityHubReducer.js'
10
- import {
11
- assertActiveOperatorIsApproved,
12
- mergeApprovedOperatorWallets,
13
- normalizeApprovedOperatorWallets,
14
- upsertApprovedOperatorWallet,
15
- } from '../../operatorWallets.js'
16
- function ensValidationToState(validation: EnsValidation): Record<string, unknown> {
17
- const checkedAt = new Date().toISOString()
18
- if (validation.ok) {
19
- return { ok: true, resolvedAddress: validation.resolvedAddress, checkedAt }
20
- }
21
- return {
22
- ok: false,
23
- reason: validation.reason,
24
- ...(validation.detail ? { detail: validation.detail } : {}),
25
- checkedAt,
26
- }
27
- }
28
-
29
- export async function validateEnsForProfileUpdate(
30
- fullName: string,
31
- walletAccount: Address,
32
- profile: ProfileUpdates,
33
- baseState: Record<string, unknown>,
34
- identity: EthagentIdentity,
35
- registry: Erc8004RegistryConfig,
36
- ): Promise<EnsValidation> {
37
- const mode = readCustodyModeForUpdate(profile, baseState)
38
- if (mode === 'advanced') {
39
- const ownerAddress = readOwnerAddressForUpdate(profile, baseState)
40
- if (!ownerAddress) {
41
- return { ok: false, reason: 'lookup-failed', detail: 'no owner address recorded for advanced custody' }
42
- }
43
- const validation = await validateAdvancedEnsRelationship({
44
- fullName,
45
- ownerAddress: getAddress(ownerAddress),
46
- registry,
47
- agentId: identity.agentId,
48
- })
49
- return validation
50
- }
51
- return validateAgentEnsLink(fullName, walletAccount)
52
- }
53
-
54
- export function applyEnsValidationState(
55
- state: Record<string, unknown>,
56
- validation: EnsValidation,
57
- profile: ProfileUpdates,
58
- baseState: Record<string, unknown>,
59
- ): void {
60
- state.ensValidation = ensValidationToState(validation)
61
- if (!validation.ok) {
62
- throw new Error(`${ensValidationReasonText(validation.reason)}${validation.detail ? `: ${validation.detail}` : ''}`)
63
- }
64
- const mode = readCustodyModeForUpdate(profile, baseState)
65
- state.custodyMode = mode
66
- delete state.ensMode
67
- if (mode === 'advanced') {
68
- const ownerAddressValue = readOwnerAddressForUpdate(profile, baseState)
69
- const operatorWallet = readActiveOperatorForUpdate(profile, baseState)
70
- if (!ownerAddressValue || !operatorWallet) {
71
- throw new Error('Advanced custody requires owner wallet and operator wallet addresses')
72
- }
73
- const ownerAddress = getAddress(ownerAddressValue)
74
- const existingOperators = mergeApprovedOperatorWallets(baseState.approvedOperatorWallets, profile.approvedOperatorWallets ?? [], { walletAddress: ownerAddress })
75
- const approvedOperatorWallets = upsertApprovedOperatorWallet(existingOperators, getAddress(operatorWallet), { walletAddress: ownerAddress })
76
- setOwnerAddressField(state, getAddress(ownerAddress))
77
- state.approvedOperatorWallets = approvedOperatorWallets
78
- state.activeOperatorAddress = getAddress(operatorWallet)
79
- return
80
- }
81
- clearOwnerAddressField(state)
82
- delete state.approvedOperatorWallets
83
- delete state.activeOperatorAddress
84
- }
85
-
86
- export function applyOperatorProfileState(
87
- state: Record<string, unknown>,
88
- profile: ProfileUpdates,
89
- baseState: Record<string, unknown>,
90
- ): void {
91
- const operatorFieldsTouched = profile.custodyMode !== undefined
92
- || profile.ownerAddress !== undefined
93
- || profile.approvedOperatorWallets !== undefined
94
- || profile.activeOperatorAddress !== undefined
95
- || profile.operatorVaultAddress !== undefined
96
- || profile.restoreAccessEpoch !== undefined
97
- if (!operatorFieldsTouched) return
98
-
99
- if (profile.custodyMode === 'simple') {
100
- state.custodyMode = 'simple'
101
- delete state.ensMode
102
- clearOwnerAddressField(state)
103
- delete state.approvedOperatorWallets
104
- delete state.activeOperatorAddress
105
- if (profile.restoreAccessEpoch !== undefined) {
106
- state.restoreAccessEpoch = profile.restoreAccessEpoch
107
- }
108
- return
109
- }
110
- if (profile.custodyMode === 'advanced') {
111
- state.custodyMode = 'advanced'
112
- delete state.ensMode
113
- }
114
-
115
- if (profile.operatorVaultAddress !== undefined) {
116
- if (typeof profile.operatorVaultAddress === 'string' && profile.operatorVaultAddress.trim()) {
117
- setVaultAddressField(state, getAddress(profile.operatorVaultAddress))
118
- } else {
119
- clearVaultAddressField(state)
120
- }
121
- }
122
-
123
- if (typeof profile.ownerAddress === 'string' && profile.ownerAddress.trim()) {
124
- setOwnerAddressField(state, getAddress(profile.ownerAddress))
125
- }
126
-
127
- const approvedOperatorWallets = profile.approvedOperatorWallets !== undefined
128
- ? normalizeApprovedOperatorWallets(profile.approvedOperatorWallets)
129
- : normalizeApprovedOperatorWallets(baseState.approvedOperatorWallets)
130
- if (profile.approvedOperatorWallets !== undefined) {
131
- const ownerForCheck = readOwnerAddressField(state) ?? readOwnerAddressField(baseState) ?? ''
132
- if (ownerForCheck && isAddress(ownerForCheck, { strict: false })) {
133
- const ownerLower = ownerForCheck.toLowerCase()
134
- if (approvedOperatorWallets.some(record => record.address.toLowerCase() === ownerLower)) {
135
- throw new Error('Operator wallet must be different from the owner wallet')
136
- }
137
- }
138
- state.approvedOperatorWallets = approvedOperatorWallets
139
- }
140
-
141
- const active = profile.activeOperatorAddress !== undefined
142
- ? assertActiveOperatorIsApproved(approvedOperatorWallets, profile.activeOperatorAddress)
143
- : assertActiveOperatorIsApproved(approvedOperatorWallets, readActiveOperatorForUpdate({}, baseState))
144
- if (active) {
145
- state.activeOperatorAddress = active
146
- } else if (profile.activeOperatorAddress !== undefined) {
147
- delete state.activeOperatorAddress
148
- }
149
- if (profile.restoreAccessEpoch !== undefined) {
150
- state.restoreAccessEpoch = profile.restoreAccessEpoch
151
- }
152
- }
153
-
154
- function readCustodyModeForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): 'simple' | 'advanced' {
155
- if (profile.custodyMode === 'simple' || profile.custodyMode === 'advanced') return profile.custodyMode
156
- return readCustodyMode(baseState) ?? 'simple'
157
- }
158
-
159
- function readOwnerAddressForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): string | undefined {
160
- if (typeof profile.ownerAddress === 'string' && profile.ownerAddress.trim()) return profile.ownerAddress.trim()
161
- return readOwnerAddressField(baseState)
162
- }
163
-
164
- function readActiveOperatorForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): string | undefined {
165
- if (typeof profile.activeOperatorAddress === 'string' && profile.activeOperatorAddress.trim()) return profile.activeOperatorAddress.trim()
166
- const profileApproved = normalizeApprovedOperatorWallets(profile.approvedOperatorWallets)
167
- if (profileApproved[0]) return profileApproved[0].address
168
- const storedActive = baseState.activeOperatorAddress
169
- if (typeof storedActive === 'string' && storedActive.trim()) return storedActive.trim()
170
- const storedApproved = normalizeApprovedOperatorWallets(baseState.approvedOperatorWallets)
171
- if (storedApproved[0]) return storedApproved[0].address
172
- return undefined
173
- }
1
+ import { getAddress, isAddress, type Address } from 'viem'
2
+ import type { EthagentIdentity } from '../../../storage/config.js'
3
+ import type { Erc8004RegistryConfig } from '../../registry/erc8004.js'
4
+ import { validateAgentEnsLink, type EnsValidation } from '../../ens/ensLookup.js'
5
+ import { clearOwnerAddressField, clearVaultAddressField, readOwnerAddressField, setVaultAddressField, setOwnerAddressField } from '../../identityCompat.js'
6
+ import { validateAdvancedEnsRelationship } from '../ens/advancedEnsValidation.js'
7
+ import { readCustodyMode } from '../custody/state.js'
8
+ import { ensValidationReasonText } from '../ens/state.js'
9
+ import type { ProfileUpdates } from '../identityHubReducer.js'
10
+ import {
11
+ assertActiveOperatorIsApproved,
12
+ mergeApprovedOperatorWallets,
13
+ normalizeApprovedOperatorWallets,
14
+ upsertApprovedOperatorWallet,
15
+ } from '../shared/operatorWallets.js'
16
+ function ensValidationToState(validation: EnsValidation): Record<string, unknown> {
17
+ const checkedAt = new Date().toISOString()
18
+ if (validation.ok) {
19
+ return { ok: true, resolvedAddress: validation.resolvedAddress, checkedAt }
20
+ }
21
+ return {
22
+ ok: false,
23
+ reason: validation.reason,
24
+ ...(validation.detail ? { detail: validation.detail } : {}),
25
+ checkedAt,
26
+ }
27
+ }
28
+
29
+ export async function validateEnsForProfileUpdate(
30
+ fullName: string,
31
+ walletAccount: Address,
32
+ profile: ProfileUpdates,
33
+ baseState: Record<string, unknown>,
34
+ identity: EthagentIdentity,
35
+ registry: Erc8004RegistryConfig,
36
+ ): Promise<EnsValidation> {
37
+ const mode = readCustodyModeForUpdate(profile, baseState)
38
+ if (mode === 'advanced') {
39
+ const ownerAddress = readOwnerAddressForUpdate(profile, baseState)
40
+ if (!ownerAddress) {
41
+ return { ok: false, reason: 'lookup-failed', detail: 'no owner address recorded for advanced custody' }
42
+ }
43
+ const validation = await validateAdvancedEnsRelationship({
44
+ fullName,
45
+ ownerAddress: getAddress(ownerAddress),
46
+ registry,
47
+ agentId: identity.agentId,
48
+ })
49
+ return validation
50
+ }
51
+ return validateAgentEnsLink(fullName, walletAccount)
52
+ }
53
+
54
+ export function applyEnsValidationState(
55
+ state: Record<string, unknown>,
56
+ validation: EnsValidation,
57
+ profile: ProfileUpdates,
58
+ baseState: Record<string, unknown>,
59
+ ): void {
60
+ state.ensValidation = ensValidationToState(validation)
61
+ if (!validation.ok) {
62
+ throw new Error(`${ensValidationReasonText(validation.reason)}${validation.detail ? `: ${validation.detail}` : ''}`)
63
+ }
64
+ const mode = readCustodyModeForUpdate(profile, baseState)
65
+ state.custodyMode = mode
66
+ delete state.ensMode
67
+ if (mode === 'advanced') {
68
+ const ownerAddressValue = readOwnerAddressForUpdate(profile, baseState)
69
+ const operatorWallet = readActiveOperatorForUpdate(profile, baseState)
70
+ if (!ownerAddressValue || !operatorWallet) {
71
+ throw new Error('Advanced custody requires owner wallet and operator wallet addresses')
72
+ }
73
+ const ownerAddress = getAddress(ownerAddressValue)
74
+ setOwnerAddressField(state, getAddress(ownerAddress))
75
+ const operatorTouched =
76
+ profile.approvedOperatorWallets !== undefined
77
+ || profile.activeOperatorAddress !== undefined
78
+ if (operatorTouched) {
79
+ const existingOperators = mergeApprovedOperatorWallets(baseState.approvedOperatorWallets, profile.approvedOperatorWallets ?? [], { walletAddress: ownerAddress })
80
+ const approvedOperatorWallets = upsertApprovedOperatorWallet(existingOperators, getAddress(operatorWallet), { walletAddress: ownerAddress })
81
+ state.approvedOperatorWallets = approvedOperatorWallets
82
+ state.activeOperatorAddress = getAddress(operatorWallet)
83
+ } else {
84
+ state.approvedOperatorWallets = normalizeApprovedOperatorWallets(baseState.approvedOperatorWallets)
85
+ state.activeOperatorAddress = getAddress(operatorWallet)
86
+ }
87
+ return
88
+ }
89
+ clearOwnerAddressField(state)
90
+ delete state.approvedOperatorWallets
91
+ delete state.activeOperatorAddress
92
+ }
93
+
94
+ export function applyOperatorProfileState(
95
+ state: Record<string, unknown>,
96
+ profile: ProfileUpdates,
97
+ baseState: Record<string, unknown>,
98
+ ): void {
99
+ const operatorFieldsTouched = profile.custodyMode !== undefined
100
+ || profile.ownerAddress !== undefined
101
+ || profile.approvedOperatorWallets !== undefined
102
+ || profile.activeOperatorAddress !== undefined
103
+ || profile.operatorVaultAddress !== undefined
104
+ || profile.restoreAccessEpoch !== undefined
105
+ if (!operatorFieldsTouched) return
106
+
107
+ if (profile.custodyMode === 'simple') {
108
+ state.custodyMode = 'simple'
109
+ delete state.ensMode
110
+ clearOwnerAddressField(state)
111
+ delete state.approvedOperatorWallets
112
+ delete state.activeOperatorAddress
113
+ if (profile.restoreAccessEpoch !== undefined) {
114
+ state.restoreAccessEpoch = profile.restoreAccessEpoch
115
+ }
116
+ return
117
+ }
118
+ if (profile.custodyMode === 'advanced') {
119
+ state.custodyMode = 'advanced'
120
+ delete state.ensMode
121
+ }
122
+
123
+ if (profile.operatorVaultAddress !== undefined) {
124
+ if (typeof profile.operatorVaultAddress === 'string' && profile.operatorVaultAddress.trim()) {
125
+ setVaultAddressField(state, getAddress(profile.operatorVaultAddress))
126
+ } else {
127
+ clearVaultAddressField(state)
128
+ }
129
+ }
130
+
131
+ if (typeof profile.ownerAddress === 'string' && profile.ownerAddress.trim()) {
132
+ setOwnerAddressField(state, getAddress(profile.ownerAddress))
133
+ }
134
+
135
+ const approvedOperatorWallets = profile.approvedOperatorWallets !== undefined
136
+ ? normalizeApprovedOperatorWallets(profile.approvedOperatorWallets)
137
+ : normalizeApprovedOperatorWallets(baseState.approvedOperatorWallets)
138
+ if (profile.approvedOperatorWallets !== undefined) {
139
+ const ownerForCheck = readOwnerAddressField(state) ?? readOwnerAddressField(baseState) ?? ''
140
+ if (ownerForCheck && isAddress(ownerForCheck, { strict: false })) {
141
+ const ownerLower = ownerForCheck.toLowerCase()
142
+ if (approvedOperatorWallets.some(record => record.address.toLowerCase() === ownerLower)) {
143
+ throw new Error('Operator wallet must be different from the owner wallet')
144
+ }
145
+ }
146
+ state.approvedOperatorWallets = approvedOperatorWallets
147
+ }
148
+
149
+ const active = profile.activeOperatorAddress !== undefined
150
+ ? assertActiveOperatorIsApproved(approvedOperatorWallets, profile.activeOperatorAddress)
151
+ : assertActiveOperatorIsApproved(approvedOperatorWallets, readActiveOperatorForUpdate({}, baseState))
152
+ if (active) {
153
+ state.activeOperatorAddress = active
154
+ } else if (profile.activeOperatorAddress !== undefined) {
155
+ delete state.activeOperatorAddress
156
+ }
157
+ if (profile.restoreAccessEpoch !== undefined) {
158
+ state.restoreAccessEpoch = profile.restoreAccessEpoch
159
+ }
160
+ }
161
+
162
+ function readCustodyModeForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): 'simple' | 'advanced' {
163
+ if (profile.custodyMode === 'simple' || profile.custodyMode === 'advanced') return profile.custodyMode
164
+ return readCustodyMode(baseState) ?? 'simple'
165
+ }
166
+
167
+ function readOwnerAddressForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): string | undefined {
168
+ if (typeof profile.ownerAddress === 'string' && profile.ownerAddress.trim()) return profile.ownerAddress.trim()
169
+ return readOwnerAddressField(baseState)
170
+ }
171
+
172
+ function readActiveOperatorForUpdate(profile: ProfileUpdates, baseState: Record<string, unknown>): string | undefined {
173
+ if (typeof profile.activeOperatorAddress === 'string' && profile.activeOperatorAddress.trim()) return profile.activeOperatorAddress.trim()
174
+ const profileApproved = normalizeApprovedOperatorWallets(profile.approvedOperatorWallets)
175
+ if (profileApproved[0]) return profileApproved[0].address
176
+ const storedActive = baseState.activeOperatorAddress
177
+ if (typeof storedActive === 'string' && storedActive.trim()) return storedActive.trim()
178
+ const storedApproved = normalizeApprovedOperatorWallets(baseState.approvedOperatorWallets)
179
+ if (storedApproved[0]) return storedApproved[0].address
180
+ return undefined
181
+ }
@@ -1,25 +1,25 @@
1
1
  import React from 'react'
2
2
  import { Text } from 'ink'
3
- import { Surface } from '../../../../ui/Surface.js'
4
- import { Select } from '../../../../ui/Select.js'
5
- import { TextInput } from '../../../../ui/TextInput.js'
6
- import { theme } from '../../../../ui/theme.js'
7
- import { normalizeErc8004RegistryConfig } from '../../../registry/erc8004.js'
3
+ import { Surface } from '../../../ui/Surface.js'
4
+ import { Select } from '../../../ui/Select.js'
5
+ import { TextInput } from '../../../ui/TextInput.js'
6
+ import { theme } from '../../../ui/theme.js'
7
+ import { normalizeErc8004RegistryConfig } from '../../registry/erc8004.js'
8
8
  import {
9
9
  isCurrentAgentCandidate,
10
10
  tokenCandidateHint,
11
11
  tokenCandidateSelectLabel,
12
- } from '../../model/identity.js'
13
- import { networkLabel } from '../../model/network.js'
14
- import { shortAddress } from '../../model/format.js'
15
- import { registryConfigFromConfig } from '../../../registry/registryConfig.js'
16
- import type { Step } from '../../identityHubReducer.js'
17
- import { WalletApprovalScreen } from '../../components/WalletApprovalScreen.js'
18
- import { BusyScreen } from '../../components/BusyScreen.js'
19
- import type { BrowserWalletReady } from '../../../wallet/browserWallet.js'
20
- import type { EthagentConfig } from '../../../../storage/config.js'
21
- import { restoreSignatureRequestForStep } from '../../effects/restore/index.js'
22
- import type { RestoreProgress } from '../../effects/types.js'
12
+ } from '../profile/identity.js'
13
+ import { networkLabel } from '../shared/model/network.js'
14
+ import { shortAddress } from '../shared/model/format.js'
15
+ import { registryConfigFromConfig } from '../../registry/registryConfig.js'
16
+ import type { Step } from '../identityHubReducer.js'
17
+ import { WalletApprovalScreen } from '../shared/components/WalletApprovalScreen.js'
18
+ import { BusyScreen } from '../shared/components/BusyScreen.js'
19
+ import type { BrowserWalletReady } from '../../wallet/browserWallet.js'
20
+ import type { EthagentConfig } from '../../../storage/config.js'
21
+ import { restoreSignatureRequestForStep } from './index.js'
22
+ import type { RestoreProgress } from '../shared/effects/types.js'
23
23
 
24
24
  type RestoreStep = Exclude<Extract<Step, { kind: `restore-${string}` }>, { kind: 'restore-wallet' | 'restore-network' }>
25
25
 
@@ -108,8 +108,8 @@ export const RestoreFlow: React.FC<RestoreFlowProps> = ({
108
108
  <Select<'ens' | 'token-id' | 'back'>
109
109
  options={[
110
110
  { value: 'ens', role: 'section', label: 'Recovery Key' },
111
- { value: 'ens', label: 'Enter ENS Name', hint: 'Resolve the agent via its ENS subdomain (e.g. agent.example.eth)' },
112
- { value: 'token-id', label: 'Enter Token ID', hint: 'Look up the agent directly by ERC-8004 token ID (e.g. 45744)' },
111
+ { value: 'ens', label: 'Enter ENS Name', hint: 'Resolve the agent via its ENS subdomain' },
112
+ { value: 'token-id', label: 'Enter Token ID', hint: 'Look up the agent directly by ERC-8004 token ID' },
113
113
  { value: 'back', role: 'section', label: 'Navigation' },
114
114
  { value: 'back', label: 'Back', hint: 'Pick a different network', role: 'utility' },
115
115
  ]}
@@ -146,7 +146,7 @@ export const RestoreFlow: React.FC<RestoreFlowProps> = ({
146
146
  subtitle={`Enter the ERC-8004 token ID on ${networkLabelForRegistry(step.registry)}.`}
147
147
  footer={footerHint(step.busy ? 'Looking up...' : 'enter continue · esc back')}
148
148
  >
149
- <Text color={theme.dim}>The integer token ID assigned at mint (for example, 45744). Store it alongside your wallet seed so the agent stays recoverable even if its ENS record is cleared.</Text>
149
+ <Text color={theme.dim}>The integer token ID assigned at mint.</Text>
150
150
  <TextInput
151
151
  placeholder="45744"
152
152
  onSubmit={value => onTokenIdSubmit(value.trim())}
@@ -202,8 +202,8 @@ export const RestoreFlow: React.FC<RestoreFlowProps> = ({
202
202
  }
203
203
  }),
204
204
  { value: '__ens__', role: 'section', label: 'Recovery Key' },
205
- { value: '__ens__', label: 'Enter ENS Name', hint: 'Resolve the agent via its ENS subdomain (e.g. agent.example.eth)' },
206
- { value: '__token-id__', label: 'Enter Token ID', hint: 'Look up the agent directly by ERC-8004 token ID (e.g. 45744)' },
205
+ { value: '__ens__', label: 'Enter ENS Name', hint: 'Resolve the agent via its ENS subdomain' },
206
+ { value: '__token-id__', label: 'Enter Token ID', hint: 'Look up the agent directly by ERC-8004 token ID' },
207
207
  { value: '__back__', role: 'section', label: 'Navigation' },
208
208
  { value: '__back__', label: 'Back', hint: 'Return to the previous step', role: 'utility' },
209
209
  ]}
@@ -1,19 +1,19 @@
1
1
  import { getAddress } from 'viem'
2
- import type { EthagentIdentity } from '../../../../storage/config.js'
3
- import { restoreAgentStateBackupEnvelope } from '../../../crypto/backupEnvelope.js'
2
+ import type { EthagentIdentity } from '../../../storage/config.js'
3
+ import { restoreAgentStateBackupEnvelope } from '../../crypto/backupEnvelope.js'
4
4
  import {
5
5
  restoreContinuitySnapshotEnvelope,
6
6
  transferSnapshotMetadataFromEnvelope,
7
- } from '../../../continuity/envelope.js'
8
- import { ensureIdentityMarkdownScaffold, writeContinuityFiles } from '../../../continuity/storage.js'
9
- import { recordPublishedContinuitySnapshot } from '../../../continuity/snapshots.js'
10
- import { requestBrowserWalletSignature } from '../../../wallet/browserWallet.js'
11
- import { setVaultAddressField } from '../../../identityCompat.js'
12
- import type { Step } from '../../identityHubReducer.js'
13
- import type { EffectCallbacks } from '../types.js'
7
+ } from '../../continuity/envelope.js'
8
+ import { ensureIdentityMarkdownScaffold, writeContinuityFiles } from '../../continuity/storage.js'
9
+ import { recordPublishedContinuitySnapshot } from '../../continuity/snapshots.js'
10
+ import { requestBrowserWalletSignature } from '../../wallet/browserWallet.js'
11
+ import { setVaultAddressField } from '../../identityCompat.js'
12
+ import type { Step } from '../identityHubReducer.js'
13
+ import type { EffectCallbacks } from '../shared/effects/types.js'
14
14
  import { isContinuitySnapshotEnvelope } from './envelopes.js'
15
15
  import { restoreSignatureRequestForStep } from './auth.js'
16
- import { type BackupMetadata, operatorStateFromCandidate, restorePublishedPublicSkills } from './shared.js'
16
+ import { type BackupMetadata, operatorStateFromCandidate, restorePublishedPublicSkills } from './helpers.js'
17
17
 
18
18
  export async function runRestoreAuthorize(
19
19
  step: Extract<Step, { kind: 'restore-authorizing' }>,
@@ -6,12 +6,12 @@ import {
6
6
  isWalletContinuitySnapshotEnvelope,
7
7
  walletContinuitySnapshotSlotForAddress,
8
8
  type ContinuitySnapshotEnvelope,
9
- } from '../../../continuity/envelope.js'
10
- import { assertAgentStateBackupOwner } from '../../../crypto/backupEnvelope.js'
11
- import type { Erc8004AgentCandidate } from '../../../registry/erc8004.js'
12
- import { requestBrowserWalletAccount, type WalletPurpose } from '../../../wallet/browserWallet.js'
13
- import type { Step } from '../../identityHubReducer.js'
14
- import type { EffectCallbacks } from '../types.js'
9
+ } from '../../continuity/envelope.js'
10
+ import { assertAgentStateBackupOwner } from '../../crypto/backupEnvelope.js'
11
+ import type { Erc8004AgentCandidate } from '../../registry/erc8004.js'
12
+ import { requestBrowserWalletAccount, type WalletPurpose } from '../../wallet/browserWallet.js'
13
+ import type { Step } from '../identityHubReducer.js'
14
+ import type { EffectCallbacks } from '../shared/effects/types.js'
15
15
  import { isContinuitySnapshotEnvelope, parseRestorableEnvelope } from './envelopes.js'
16
16
  import {
17
17
  isAuthorizedOperatorAddress,
@@ -19,7 +19,7 @@ import {
19
19
  ownerCandidateAddresses,
20
20
  requesterAddressFromHandle,
21
21
  restoreTransferSlotForRequester,
22
- } from './shared.js'
22
+ } from './helpers.js'
23
23
 
24
24
  export async function runRestoreConnectWallet(
25
25
  step: Extract<Step, { kind: 'restore-wallet' }>,
@@ -1,15 +1,15 @@
1
- import type { EthagentConfig } from '../../../../storage/config.js'
1
+ import type { EthagentConfig } from '../../../storage/config.js'
2
2
  import {
3
3
  DEFAULT_IPFS_API_URL,
4
- } from '../../../storage/ipfs.js'
4
+ } from '../../storage/ipfs.js'
5
5
  import {
6
6
  discoverOwnedAgentBackups,
7
7
  type Erc8004AgentCandidate,
8
8
  type Erc8004RegistryConfig,
9
- } from '../../../registry/erc8004.js'
10
- import type { RestorePurpose, Step } from '../../identityHubReducer.js'
11
- import type { EffectCallbacks } from '../types.js'
12
- import { isAbortError, isAuthorizedOperatorAddress, requesterAddressFromHandle } from './shared.js'
9
+ } from '../../registry/erc8004.js'
10
+ import type { RestorePurpose, Step } from '../identityHubReducer.js'
11
+ import type { EffectCallbacks } from '../shared/effects/types.js'
12
+ import { isAbortError, isAuthorizedOperatorAddress, requesterAddressFromHandle } from './helpers.js'
13
13
  import type { Address } from 'viem'
14
14
 
15
15
  export async function runRestoreDiscover(
@@ -1,9 +1,9 @@
1
- import { parseAgentStateBackupEnvelope } from '../../../crypto/backupEnvelope.js'
1
+ import { parseAgentStateBackupEnvelope } from '../../crypto/backupEnvelope.js'
2
2
  import {
3
3
  CONTINUITY_SNAPSHOT_ENVELOPE_VERSION,
4
4
  parseContinuitySnapshotEnvelope,
5
5
  type ContinuitySnapshotEnvelope,
6
- } from '../../../continuity/envelope.js'
6
+ } from '../../continuity/envelope.js'
7
7
 
8
8
  export type RestorableEnvelope = ReturnType<typeof parseAgentStateBackupEnvelope> | ContinuitySnapshotEnvelope
9
9
 
@@ -1,6 +1,6 @@
1
- import { catFromIpfs } from '../../../storage/ipfs.js'
2
- import type { Step } from '../../identityHubReducer.js'
3
- import type { EffectCallbacks } from '../types.js'
1
+ import { catFromIpfs } from '../../storage/ipfs.js'
2
+ import type { Step } from '../identityHubReducer.js'
3
+ import type { EffectCallbacks } from '../shared/effects/types.js'
4
4
  import { parseRestorableEnvelope } from './envelopes.js'
5
5
  import { assertCandidateCanReadEnvelope, restoreSignatureRequestForStep } from './auth.js'
6
6
 
@@ -1,13 +1,13 @@
1
1
  import { getAddress, isAddress, type Address } from 'viem'
2
- import type { EthagentIdentity } from '../../../../storage/config.js'
2
+ import type { EthagentIdentity } from '../../../storage/config.js'
3
3
  import {
4
4
  type ContinuitySnapshotEnvelope,
5
5
  type TransferContinuitySnapshotEnvelope,
6
- } from '../../../continuity/envelope.js'
7
- import { catFromIpfs } from '../../../storage/ipfs.js'
8
- import type { Erc8004AgentCandidate } from '../../../registry/erc8004.js'
9
- import { writePublicSkillsFile } from '../../../continuity/storage.js'
10
- import { normalizeApprovedOperatorWallets } from '../../operatorWallets.js'
6
+ } from '../../continuity/envelope.js'
7
+ import { catFromIpfs } from '../../storage/ipfs.js'
8
+ import type { Erc8004AgentCandidate } from '../../registry/erc8004.js'
9
+ import { writePublicSkillsFile } from '../../continuity/storage.js'
10
+ import { normalizeApprovedOperatorWallets } from '../shared/operatorWallets.js'
11
11
 
12
12
  export type BackupMetadata = NonNullable<EthagentIdentity['backup']>
13
13
 
@@ -1,24 +1,24 @@
1
1
  import { getAddress, type Address } from 'viem'
2
- import type { EthagentIdentity } from '../../../../storage/config.js'
2
+ import type { EthagentIdentity } from '../../../storage/config.js'
3
3
  import {
4
4
  assertContinuitySnapshotOwner,
5
5
  isWalletContinuitySnapshotEnvelope,
6
6
  restoreContinuitySnapshotEnvelope,
7
7
  transferSnapshotMetadataFromEnvelope,
8
- } from '../../../continuity/envelope.js'
9
- import { ensureIdentityMarkdownScaffold, localContinuitySnapshotContentHashes, writeContinuityFiles } from '../../../continuity/storage.js'
10
- import { recordPublishedContinuitySnapshot, updatePublishedContinuitySnapshotContentHashes } from '../../../continuity/snapshots.js'
11
- import { catFromIpfs, DEFAULT_IPFS_API_URL } from '../../../storage/ipfs.js'
8
+ } from '../../continuity/envelope.js'
9
+ import { ensureIdentityMarkdownScaffold, localContinuitySnapshotContentHashes, writeContinuityFiles } from '../../continuity/storage.js'
10
+ import { recordPublishedContinuitySnapshot, updatePublishedContinuitySnapshotContentHashes } from '../../continuity/snapshots.js'
11
+ import { catFromIpfs, DEFAULT_IPFS_API_URL } from '../../storage/ipfs.js'
12
12
  import {
13
13
  discoverOwnedAgentBackupByTokenId,
14
14
  type Erc8004RegistryConfig,
15
- } from '../../../registry/erc8004.js'
16
- import { requestBrowserWalletSignature } from '../../../wallet/browserWallet.js'
17
- import { setVaultAddressField } from '../../../identityCompat.js'
18
- import type { EffectCallbacks } from '../types.js'
15
+ } from '../../registry/erc8004.js'
16
+ import { requestBrowserWalletSignature } from '../../wallet/browserWallet.js'
17
+ import { setVaultAddressField } from '../../identityCompat.js'
18
+ import type { EffectCallbacks } from '../shared/effects/types.js'
19
19
  import { isContinuitySnapshotEnvelope, parseRestorableEnvelope } from './envelopes.js'
20
20
  import { restoreMessageForWallet } from './auth.js'
21
- import { type BackupMetadata, operatorStateFromCandidate, restorePublishedPublicSkills } from './shared.js'
21
+ import { type BackupMetadata, operatorStateFromCandidate, restorePublishedPublicSkills } from './helpers.js'
22
22
 
23
23
  export async function runRecoveryRefetch(
24
24
  identity: EthagentIdentity,
@@ -1,13 +1,13 @@
1
1
  import { type Address } from 'viem'
2
- import { DEFAULT_IPFS_API_URL } from '../../../storage/ipfs.js'
2
+ import { DEFAULT_IPFS_API_URL } from '../../storage/ipfs.js'
3
3
  import {
4
4
  createErc8004PublicClient,
5
5
  discoverOwnedAgentBackupByTokenId,
6
6
  type Erc8004AgentCandidate,
7
7
  type Erc8004RegistryConfig,
8
- } from '../../../registry/erc8004.js'
9
- import { parseAgentTokenReference, readEthagentTextRecords } from '../../../ens/ensLookup.js'
10
- import { AGENT_RECORD_KEYS } from '../../../ens/agentRecords.js'
8
+ } from '../../registry/erc8004.js'
9
+ import { parseAgentTokenReference, readEthagentTextRecords } from '../../ens/ensLookup.js'
10
+ import { AGENT_RECORD_KEYS } from '../../ens/agentRecords.js'
11
11
 
12
12
  const ETH_NAME_PATTERN = /^([a-z0-9-]+\.)+eth$/i
13
13