ethagent 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +127 -29
  3. package/package.json +16 -9
  4. package/src/app/FirstRun.tsx +192 -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 +43 -18
  11. package/src/chat/ContextLimitView.tsx +4 -4
  12. package/src/chat/ContinuityEditReviewView.tsx +11 -17
  13. package/src/chat/ConversationStack.tsx +3 -0
  14. package/src/chat/CopyPicker.tsx +0 -1
  15. package/src/chat/MessageList.tsx +62 -45
  16. package/src/chat/PermissionPrompt.tsx +13 -9
  17. package/src/chat/PlanApprovalView.tsx +3 -3
  18. package/src/chat/ResumeView.tsx +1 -4
  19. package/src/chat/RewindView.tsx +2 -2
  20. package/src/chat/TranscriptView.tsx +6 -0
  21. package/src/chat/chatInputState.ts +1 -1
  22. package/src/chat/chatScreenUtils.ts +22 -11
  23. package/src/chat/chatSessionState.ts +2 -2
  24. package/src/chat/chatTurnOrchestrator.ts +16 -81
  25. package/src/chat/commands.ts +1 -1
  26. package/src/chat/textCursor.ts +1 -1
  27. package/src/chat/transcriptViewport.ts +2 -7
  28. package/src/cli/ResetConfirmView.tsx +1 -1
  29. package/src/cli/main.tsx +9 -3
  30. package/src/cli/preview.tsx +0 -5
  31. package/src/cli/updateNotice.ts +5 -3
  32. package/src/identity/continuity/editor.ts +7 -107
  33. package/src/identity/continuity/envelope.ts +1048 -40
  34. package/src/identity/continuity/history.ts +4 -4
  35. package/src/identity/continuity/localBackup.ts +249 -0
  36. package/src/identity/continuity/privateEdit/apply.ts +170 -0
  37. package/src/identity/continuity/privateEdit/diff.ts +82 -0
  38. package/src/identity/continuity/privateEdit/files.ts +23 -0
  39. package/src/identity/continuity/privateEdit/types.ts +28 -0
  40. package/src/identity/continuity/privateEdit.ts +10 -298
  41. package/src/identity/continuity/publicSkills.ts +8 -9
  42. package/src/identity/continuity/snapshots.ts +17 -6
  43. package/src/identity/continuity/storage/defaults.ts +111 -0
  44. package/src/identity/continuity/storage/files.ts +72 -0
  45. package/src/identity/continuity/storage/markdown.ts +81 -0
  46. package/src/identity/continuity/storage/paths.ts +24 -0
  47. package/src/identity/continuity/storage/scaffold.ts +124 -0
  48. package/src/identity/continuity/storage/status.ts +86 -0
  49. package/src/identity/continuity/storage/types.ts +27 -0
  50. package/src/identity/continuity/storage.ts +32 -507
  51. package/src/identity/continuity/zipWriter.ts +95 -0
  52. package/src/identity/crypto/backupEnvelope.ts +14 -247
  53. package/src/identity/crypto/eth.ts +7 -7
  54. package/src/identity/ens/agentRecords.ts +96 -0
  55. package/src/identity/ens/ensAutomation/contracts.ts +38 -0
  56. package/src/identity/ens/ensAutomation/delete.ts +80 -0
  57. package/src/identity/ens/ensAutomation/names.ts +14 -0
  58. package/src/identity/ens/ensAutomation/operators.ts +29 -0
  59. package/src/identity/ens/ensAutomation/read.ts +114 -0
  60. package/src/identity/ens/ensAutomation/root.ts +63 -0
  61. package/src/identity/ens/ensAutomation/setup.ts +284 -0
  62. package/src/identity/ens/ensAutomation/transactions.ts +107 -0
  63. package/src/identity/ens/ensAutomation/types.ts +126 -0
  64. package/src/identity/ens/ensAutomation.ts +29 -0
  65. package/src/identity/ens/ensLookup/client.ts +43 -0
  66. package/src/identity/ens/ensLookup/constants.ts +26 -0
  67. package/src/identity/ens/ensLookup/discovery.ts +70 -0
  68. package/src/identity/ens/ensLookup/names.ts +34 -0
  69. package/src/identity/ens/ensLookup/records.ts +45 -0
  70. package/src/identity/ens/ensLookup/resolve.ts +75 -0
  71. package/src/identity/ens/ensLookup/tokenReference.ts +17 -0
  72. package/src/identity/ens/ensLookup/types.ts +38 -0
  73. package/src/identity/ens/ensLookup/validation.ts +72 -0
  74. package/src/identity/ens/ensLookup.ts +19 -0
  75. package/src/identity/ens/ensRegistration.ts +199 -0
  76. package/src/identity/ens/resolverDelegation.ts +48 -0
  77. package/src/identity/hub/IdentityHub.tsx +13 -815
  78. package/src/identity/hub/OperationalRoutes.tsx +370 -0
  79. package/src/identity/hub/Routes.tsx +361 -0
  80. package/src/identity/hub/advancedEnsValidation.ts +45 -0
  81. package/src/identity/hub/{screens → components}/DetailsScreen.tsx +14 -8
  82. package/src/identity/hub/{screens → components}/ErrorScreen.tsx +15 -5
  83. package/src/identity/hub/components/FlowTimeline.tsx +27 -0
  84. package/src/identity/hub/components/IdentitySummary.tsx +190 -0
  85. package/src/identity/hub/components/MenuScreen.tsx +237 -0
  86. package/src/identity/hub/{screens → components}/NetworkScreen.tsx +3 -3
  87. package/src/identity/hub/{screens/RebackupStorageScreen.tsx → components/PinataJwtInput.tsx} +21 -18
  88. package/src/identity/hub/components/UnlinkedIdentityScreen.tsx +76 -0
  89. package/src/identity/hub/{screens → components}/WalletApprovalScreen.tsx +9 -8
  90. package/src/identity/hub/components/menuFlagsFromReconciliation.ts +68 -0
  91. package/src/identity/hub/effects/create.ts +310 -0
  92. package/src/identity/hub/effects/ens/flows.ts +218 -0
  93. package/src/identity/hub/effects/ens/index.ts +11 -0
  94. package/src/identity/hub/effects/ens/transactions.ts +239 -0
  95. package/src/identity/hub/effects/index.ts +74 -0
  96. package/src/identity/hub/effects/profile/profileState.ts +173 -0
  97. package/src/identity/hub/effects/publicProfile/index.ts +5 -0
  98. package/src/identity/hub/effects/publicProfile/runPublicProfileSave.ts +646 -0
  99. package/src/identity/hub/effects/rebackup/index.ts +7 -0
  100. package/src/identity/hub/effects/rebackup/operatorVault.ts +378 -0
  101. package/src/identity/hub/effects/rebackup/runRebackup.ts +451 -0
  102. package/src/identity/hub/effects/receipts.ts +46 -0
  103. package/src/identity/hub/effects/restore/apply.ts +112 -0
  104. package/src/identity/hub/effects/restore/auth.ts +159 -0
  105. package/src/identity/hub/effects/restore/discover.ts +86 -0
  106. package/src/identity/hub/effects/restore/envelopes.ts +21 -0
  107. package/src/identity/hub/effects/restore/fetch.ts +25 -0
  108. package/src/identity/hub/effects/restore/index.ts +22 -0
  109. package/src/identity/hub/effects/restore/recovery.ts +135 -0
  110. package/src/identity/hub/effects/restore/resolve.ts +102 -0
  111. package/src/identity/hub/effects/restore/restoreEffects.ts +22 -0
  112. package/src/identity/hub/effects/restore/shared.ts +91 -0
  113. package/src/identity/hub/effects/restoreAdmin.ts +93 -0
  114. package/src/identity/hub/effects/shared/profilePrep.ts +139 -0
  115. package/src/identity/hub/effects/shared/snapshot.ts +336 -0
  116. package/src/identity/hub/effects/shared/sync.ts +190 -0
  117. package/src/identity/hub/effects/token-transfer/index.ts +6 -0
  118. package/src/identity/hub/effects/token-transfer/progress.ts +59 -0
  119. package/src/identity/hub/effects/token-transfer/runTokenTransfer.ts +299 -0
  120. package/src/identity/hub/effects/types.ts +53 -0
  121. package/src/identity/hub/effects/vault/preflight.ts +50 -0
  122. package/src/identity/hub/flows/continuity/ContinuityDashboardScreen.tsx +170 -0
  123. package/src/identity/hub/flows/continuity/RebackupStorageScreen.tsx +28 -0
  124. package/src/identity/hub/flows/continuity/RecoveryConfirmScreen.tsx +104 -0
  125. package/src/identity/hub/flows/continuity/SavePromptScreen.tsx +49 -0
  126. package/src/identity/hub/{screens → flows/create}/CreateFlow.tsx +61 -62
  127. package/src/identity/hub/flows/custody/CustodyEditFlow.tsx +347 -0
  128. package/src/identity/hub/flows/custody/custodyEffects.ts +321 -0
  129. package/src/identity/hub/flows/custody/custodyFlowActions.ts +236 -0
  130. package/src/identity/hub/flows/custody/custodyFlowEffects.ts +163 -0
  131. package/src/identity/hub/flows/custody/custodyFlowHelpers.ts +25 -0
  132. package/src/identity/hub/flows/custody/custodyFlowRoutes.tsx +239 -0
  133. package/src/identity/hub/flows/custody/custodyFlowTypes.ts +45 -0
  134. package/src/identity/hub/flows/custody/useCustodyFlow.tsx +25 -0
  135. package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +336 -0
  136. package/src/identity/hub/flows/ens/EnsEditFlow.tsx +397 -0
  137. package/src/identity/hub/flows/ens/EnsEditMaintenanceScreens.tsx +332 -0
  138. package/src/identity/hub/flows/ens/EnsEditReviewScreens.tsx +471 -0
  139. package/src/identity/hub/flows/ens/EnsEditRunners.tsx +198 -0
  140. package/src/identity/hub/flows/ens/EnsEditShared.tsx +162 -0
  141. package/src/identity/hub/flows/ens/EnsEditSimpleScreens.tsx +518 -0
  142. package/src/identity/hub/flows/ens/IdentityHubEnsFlow.tsx +299 -0
  143. package/src/identity/hub/flows/ens/OperatorWalletsScreen.tsx +398 -0
  144. package/src/identity/hub/flows/ens/ensEditCopy.ts +117 -0
  145. package/src/identity/hub/flows/ens/ensEditTypes.ts +91 -0
  146. package/src/identity/hub/flows/profile/EditProfileFlow.tsx +271 -0
  147. package/src/identity/hub/flows/restore/RestoreFlow.tsx +324 -0
  148. package/src/identity/hub/flows/restore/useRestoreFlowEffects.ts +77 -0
  149. package/src/identity/hub/{screens → flows/settings}/StorageCredentialScreen.tsx +25 -43
  150. package/src/identity/hub/flows/token-transfer/IdentityHubTokenTransferFlow.tsx +162 -0
  151. package/src/identity/hub/flows/token-transfer/TokenTransferScreens.tsx +256 -0
  152. package/src/identity/hub/identityHubReducer.ts +166 -101
  153. package/src/identity/hub/model/continuity.ts +94 -0
  154. package/src/identity/hub/model/copy.ts +35 -0
  155. package/src/identity/hub/model/custody.ts +54 -0
  156. package/src/identity/hub/model/ens.ts +49 -0
  157. package/src/identity/hub/model/errors.ts +140 -0
  158. package/src/identity/hub/model/format.ts +15 -0
  159. package/src/identity/hub/model/identity.ts +94 -0
  160. package/src/identity/hub/model/network.ts +32 -0
  161. package/src/identity/hub/model/transfer.ts +57 -0
  162. package/src/identity/hub/operatorWallets.ts +131 -0
  163. package/src/identity/hub/reconciliation/agentReconciliation/hook.ts +46 -0
  164. package/src/identity/hub/reconciliation/agentReconciliation/ownership.ts +129 -0
  165. package/src/identity/hub/reconciliation/agentReconciliation/run.ts +302 -0
  166. package/src/identity/hub/reconciliation/agentReconciliation/types.ts +17 -0
  167. package/src/identity/hub/reconciliation/index.ts +21 -0
  168. package/src/identity/hub/reconciliation/useAgentReconciliation.ts +10 -0
  169. package/src/identity/hub/reconciliation/walletSetup.ts +220 -0
  170. package/src/identity/hub/txGuard.ts +51 -0
  171. package/src/identity/hub/types.ts +17 -0
  172. package/src/identity/hub/useIdentityHubContinuity.ts +136 -0
  173. package/src/identity/hub/useIdentityHubController.ts +396 -0
  174. package/src/identity/hub/useIdentityHubSideEffects.ts +309 -0
  175. package/src/identity/hub/utils.ts +79 -0
  176. package/src/identity/identityCompat.ts +34 -0
  177. package/src/identity/profile/agentIcon.ts +61 -0
  178. package/src/identity/profile/imagePicker.ts +12 -12
  179. package/src/identity/registry/erc8004/abi.ts +14 -0
  180. package/src/identity/registry/erc8004/chains.ts +150 -0
  181. package/src/identity/registry/erc8004/client.ts +11 -0
  182. package/src/identity/registry/erc8004/discovery.ts +511 -0
  183. package/src/identity/registry/erc8004/metadata.ts +335 -0
  184. package/src/identity/registry/erc8004/ownership.ts +121 -0
  185. package/src/identity/registry/erc8004/preflight.ts +123 -0
  186. package/src/identity/registry/erc8004/transactions.ts +77 -0
  187. package/src/identity/registry/erc8004/types.ts +88 -0
  188. package/src/identity/registry/erc8004/uri.ts +59 -0
  189. package/src/identity/registry/erc8004/utils.ts +58 -0
  190. package/src/identity/registry/erc8004.ts +53 -1106
  191. package/src/identity/registry/fieldParsers.ts +28 -0
  192. package/src/identity/registry/operatorVault/bytecode.ts +98 -0
  193. package/src/identity/registry/operatorVault/constants.ts +38 -0
  194. package/src/identity/registry/operatorVault/read.ts +246 -0
  195. package/src/identity/registry/operatorVault/transactions.ts +81 -0
  196. package/src/identity/registry/operatorVault.ts +44 -0
  197. package/src/identity/storage/ipfs.ts +26 -24
  198. package/src/identity/wallet/browserWallet/gas.ts +41 -0
  199. package/src/identity/wallet/browserWallet/html.ts +106 -0
  200. package/src/identity/wallet/browserWallet/http.ts +28 -0
  201. package/src/identity/wallet/browserWallet/requestServer.ts +106 -0
  202. package/src/identity/wallet/browserWallet/requests.ts +191 -0
  203. package/src/identity/wallet/browserWallet/session.ts +325 -0
  204. package/src/identity/wallet/browserWallet/types.ts +192 -0
  205. package/src/identity/wallet/browserWallet/validation.ts +74 -0
  206. package/src/identity/wallet/browserWallet.ts +30 -393
  207. package/src/identity/wallet/page/constants.ts +5 -0
  208. package/src/identity/wallet/page/controller.ts +251 -0
  209. package/src/identity/wallet/page/copy.ts +340 -0
  210. package/src/identity/wallet/page/grainient.ts +278 -0
  211. package/src/identity/wallet/page/html.ts +28 -0
  212. package/src/identity/wallet/page/markup.ts +50 -0
  213. package/src/identity/wallet/page/state.ts +9 -0
  214. package/src/identity/wallet/page/styles/base.ts +259 -0
  215. package/src/identity/wallet/page/styles/components.ts +262 -0
  216. package/src/identity/wallet/page/styles/index.ts +5 -0
  217. package/src/identity/wallet/page/styles/responsive.ts +247 -0
  218. package/src/identity/wallet/page/types.ts +47 -0
  219. package/src/identity/wallet/page/view.ts +535 -0
  220. package/src/identity/wallet/page/walletProvider.ts +70 -0
  221. package/src/identity/wallet/page.tsx +38 -0
  222. package/src/identity/wallet/walletPurposeCompat.ts +27 -0
  223. package/src/mcp/manager.ts +0 -1
  224. package/src/models/ModelPicker.tsx +36 -30
  225. package/src/models/catalog.ts +5 -2
  226. package/src/models/huggingface.ts +9 -9
  227. package/src/models/llamacpp.ts +13 -13
  228. package/src/models/modelDisplay.ts +75 -0
  229. package/src/models/modelPickerOptions.ts +16 -3
  230. package/src/models/modelRecommendation.ts +0 -1
  231. package/src/providers/errors.ts +16 -0
  232. package/src/providers/gemini.ts +252 -39
  233. package/src/providers/registry.ts +2 -2
  234. package/src/providers/retry.ts +1 -1
  235. package/src/runtime/sessionMode.ts +1 -1
  236. package/src/runtime/systemPrompt.ts +2 -0
  237. package/src/runtime/toolExecution.ts +18 -22
  238. package/src/runtime/toolIntent.ts +0 -20
  239. package/src/runtime/turn.ts +0 -92
  240. package/src/storage/atomicWrite.ts +4 -1
  241. package/src/storage/config.ts +181 -5
  242. package/src/storage/identity.ts +9 -3
  243. package/src/storage/secrets.ts +2 -2
  244. package/src/tools/bashSafety.ts +8 -0
  245. package/src/tools/changeDirectoryTool.ts +1 -1
  246. package/src/tools/deleteFileTool.ts +4 -4
  247. package/src/tools/editTool.ts +4 -4
  248. package/src/tools/editUtils.ts +5 -5
  249. package/src/tools/privateContinuityEditTool.ts +4 -5
  250. package/src/tools/privateContinuityReadTool.ts +1 -2
  251. package/src/tools/registry.ts +30 -0
  252. package/src/tools/writeFileTool.ts +5 -5
  253. package/src/ui/BrandSplash.tsx +20 -85
  254. package/src/ui/ProgressBar.tsx +3 -5
  255. package/src/ui/Select.tsx +21 -9
  256. package/src/ui/Spinner.tsx +38 -3
  257. package/src/ui/Surface.tsx +3 -3
  258. package/src/ui/TextInput.tsx +191 -29
  259. package/src/ui/theme.ts +7 -34
  260. package/src/utils/openExternal.ts +21 -0
  261. package/src/utils/withRetry.ts +47 -3
  262. package/src/identity/hub/identityHubEffects.ts +0 -937
  263. package/src/identity/hub/identityHubModel.ts +0 -291
  264. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +0 -144
  265. package/src/identity/hub/screens/EditProfileFlow.tsx +0 -145
  266. package/src/identity/hub/screens/IdentitySummary.tsx +0 -90
  267. package/src/identity/hub/screens/MenuScreen.tsx +0 -117
  268. package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +0 -87
  269. package/src/identity/hub/screens/RestoreFlow.tsx +0 -206
  270. package/src/identity/wallet/wallet-page/wallet.html +0 -1202
  271. /package/src/identity/hub/{screens → components}/BusyScreen.tsx +0 -0
@@ -0,0 +1,646 @@
1
+ import { getAddress, type Address, type Hex } from 'viem'
2
+ import type { EthagentIdentity } from '../../../../storage/config.js'
3
+ import {
4
+ createWalletRestoreAccessChallenge,
5
+ serializeContinuitySnapshotEnvelope,
6
+ type WalletChallengePurpose,
7
+ } from '../../../continuity/envelope.js'
8
+ import {
9
+ prepareSyncedPublicSkillsJson,
10
+ readContinuityFiles,
11
+ writePublicSkillsFile,
12
+ } from '../../../continuity/storage.js'
13
+ import {
14
+ createAgentCard,
15
+ defaultPublicSkillsProfile,
16
+ serializeAgentCard,
17
+ } from '../../../continuity/publicSkills.js'
18
+ import { recordPublishedContinuitySnapshot } from '../../../continuity/snapshots.js'
19
+ import { addToIpfs, DEFAULT_IPFS_API_URL, isPinataUploadUrl } from '../../../storage/ipfs.js'
20
+ import {
21
+ createErc8004PublicClient,
22
+ encodeSetAgentUri,
23
+ preflightSetAgentUri,
24
+ withEthagentPointers,
25
+ type Erc8004RegistryConfig,
26
+ } from '../../../registry/erc8004.js'
27
+ import {
28
+ OPERATOR_VAULT_ABI,
29
+ encodeRotateAgentURI,
30
+ } from '../../../registry/operatorVault.js'
31
+ import { resolveValidatedPinataJwt, savePinataJwt } from '../../../storage/pinataJwt.js'
32
+ import {
33
+ openBrowserWalletSession,
34
+ requestBrowserWalletSignatureAndTransaction,
35
+ type BrowserWalletSession,
36
+ type BrowserWalletSignature,
37
+ type WalletPurpose,
38
+ } from '../../../wallet/browserWallet.js'
39
+ import type { ProfileUpdates, Step } from '../../identityHubReducer.js'
40
+ import { reconcileWalletSetup } from '../../reconciliation/index.js'
41
+ import { acquireTxGuard, releaseTxGuard } from '../../txGuard.js'
42
+ import type { EffectCallbacks } from '../types.js'
43
+ import { awaitConfirmedReceipt } from '../receipts.js'
44
+ import {
45
+ createMainnetEnsPublicClient,
46
+ runUpdateEnsRecords,
47
+ } from '../ens/transactions.js'
48
+ import {
49
+ assertVerifiedPin,
50
+ deriveAgentName,
51
+ prepareProfileStateForSave,
52
+ readEnsOkFromState,
53
+ } from '../shared/profilePrep.js'
54
+ import {
55
+ appendResolverSyncWarning,
56
+ markCurrentContinuityFilesPublished,
57
+ resolverSyncWarningMessage,
58
+ syncResolverApprovalsAfterOwnerSave,
59
+ } from '../shared/sync.js'
60
+ import {
61
+ assertSnapshotSaveSignerAuthorized,
62
+ createContinuityEnvelopeForSave,
63
+ expectedAccountForSnapshotSave,
64
+ operatorsPointerFromState,
65
+ ownerAddressForSnapshotSave,
66
+ snapshotSaveWalletRole,
67
+ walletRestoreAccessContext,
68
+ } from '../shared/snapshot.js'
69
+ import { rebackupCompletionMessage } from '../rebackup/runRebackup.js'
70
+
71
+ type BackupMetadata = NonNullable<EthagentIdentity['backup']>
72
+ type PublicSkillsMetadata = NonNullable<EthagentIdentity['publicSkills']>
73
+
74
+ type PublicProfilePreparedTransaction = {
75
+ ownerAddress: Address
76
+ agentUri: string
77
+ metadataCid: string
78
+ publicSkills: PublicSkillsMetadata
79
+ identity: EthagentIdentity
80
+ publicSkillsJson: string
81
+ }
82
+
83
+ export async function runPublicProfilePreflight(
84
+ identity: EthagentIdentity,
85
+ registry: Erc8004RegistryConfig,
86
+ callbacks: EffectCallbacks,
87
+ profileUpdates?: ProfileUpdates,
88
+ returnTo: Step = { kind: 'continuity-public' },
89
+ vaultAddress?: Address,
90
+ ): Promise<void> {
91
+ const apiUrl = DEFAULT_IPFS_API_URL
92
+ let jwt: string | undefined
93
+ try {
94
+ jwt = isPinataUploadUrl(apiUrl) ? await resolveValidatedPinataJwt() : undefined
95
+ } catch (err: unknown) {
96
+ callbacks.onStep({ kind: 'public-profile-storage', identity, registry, error: (err as Error).message, profileUpdates, returnTo, ...(vaultAddress ? { vaultAddress } : {}) })
97
+ return
98
+ }
99
+ if (isPinataUploadUrl(apiUrl) && !jwt) {
100
+ callbacks.onStep({ kind: 'public-profile-storage', identity, registry, profileUpdates, returnTo, ...(vaultAddress ? { vaultAddress } : {}) })
101
+ return
102
+ }
103
+ callbacks.onStep({ kind: 'public-profile-signing', identity, registry, pinataJwt: jwt, profileUpdates, returnTo, ...(vaultAddress ? { vaultAddress } : {}) })
104
+ }
105
+
106
+ export async function runPublicProfileSigning(
107
+ step: Extract<Step, { kind: 'public-profile-signing' }>,
108
+ callbacks: EffectCallbacks,
109
+ ): Promise<void> {
110
+ acquireTxGuard('public-profile')
111
+ try {
112
+ return await runPublicProfileSigningInner(step, callbacks)
113
+ } finally {
114
+ releaseTxGuard('public-profile')
115
+ }
116
+ }
117
+
118
+ async function runPublicProfileSigningInner(
119
+ step: Extract<Step, { kind: 'public-profile-signing' }>,
120
+ callbacks: EffectCallbacks,
121
+ ): Promise<void> {
122
+ if (snapshotSaveWalletRole(step.identity, step.profileUpdates) === 'operator') {
123
+ await runOperatorWalletPublicProfileSave(step, callbacks)
124
+ return
125
+ }
126
+ const snapshotOwner = ownerAddressForSnapshotSave(step.identity, step.profileUpdates)
127
+ const walletAccess = walletRestoreAccessContext(step.identity, step.registry, step.profileUpdates, snapshotOwner)
128
+ const expectedSigner = expectedAccountForSnapshotSave(step.identity, step.profileUpdates, walletAccess)
129
+ const profileRole = snapshotSaveWalletRole(step.identity, step.profileUpdates)
130
+ const profilePurpose: WalletPurpose = profileRole === 'operator'
131
+ ? 'update-profile-operator'
132
+ : profileRole === 'owner'
133
+ ? 'update-profile-owner'
134
+ : 'update-profile-connected'
135
+ const result = await requestBrowserWalletSignatureAndTransaction<PublicProfilePreparedTransaction>({
136
+ chainId: step.registry.chainId,
137
+ messageForAccount: account => `Authorize public profile update for agent #${step.identity.agentId ?? 'unknown'} (${account})`,
138
+ onReady: callbacks.onWalletReady,
139
+ purpose: profilePurpose,
140
+ ...(expectedSigner ? { expectedAccount: expectedSigner } : {}),
141
+ prepareTransaction: async wallet => {
142
+ if (!step.identity.agentId) throw new Error('Cannot update public profile: identity is missing an agent token ID')
143
+ assertSnapshotSaveSignerAuthorized(step.identity, step.profileUpdates, wallet.account, snapshotOwner, walletAccess)
144
+ const {
145
+ state,
146
+ nextName,
147
+ nextDescription,
148
+ nextEnsName,
149
+ uploadedImageUri,
150
+ } = await prepareProfileStateForSave({
151
+ identity: step.identity,
152
+ registry: step.registry,
153
+ profileUpdates: step.profileUpdates,
154
+ pinataJwt: step.pinataJwt,
155
+ ownerAddress: snapshotOwner,
156
+ walletAccount: getAddress(wallet.account),
157
+ includeLastBackedUpAt: false,
158
+ })
159
+ const nextIdentityForFiles: EthagentIdentity = { ...step.identity, state }
160
+ const publicSkillsJson = await prepareSyncedPublicSkillsJson(nextIdentityForFiles)
161
+ const publicSkillsPin = await addToIpfs(DEFAULT_IPFS_API_URL, publicSkillsJson, fetch, { pinataJwt: step.pinataJwt })
162
+ assertVerifiedPin(publicSkillsPin)
163
+ const agentCardPin = await addToIpfs(
164
+ DEFAULT_IPFS_API_URL,
165
+ serializeAgentCard(createAgentCard(defaultPublicSkillsProfile(nextIdentityForFiles))),
166
+ fetch,
167
+ { pinataJwt: step.pinataJwt },
168
+ )
169
+ assertVerifiedPin(agentCardPin)
170
+ const updatedAt = new Date().toISOString()
171
+ const publicSkills: PublicSkillsMetadata = {
172
+ cid: publicSkillsPin.cid,
173
+ agentCardCid: agentCardPin.cid,
174
+ updatedAt,
175
+ status: 'pinned',
176
+ }
177
+ const existingBackup = step.identity.backup ? {
178
+ cid: step.identity.backup.cid,
179
+ ...(step.identity.backup.envelopeVersion ? { envelopeVersion: step.identity.backup.envelopeVersion } : {}),
180
+ ...(step.identity.backup.createdAt ? { createdAt: step.identity.backup.createdAt } : {}),
181
+ } : undefined
182
+ const registration = withEthagentPointers({
183
+ type: 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1',
184
+ name: nextName ?? deriveAgentName(step.identity),
185
+ ...(nextDescription ? { description: nextDescription } : {}),
186
+ ...(uploadedImageUri ? { image: uploadedImageUri } : {}),
187
+ }, {
188
+ backup: existingBackup,
189
+ publicDiscovery: {
190
+ skillsCid: publicSkills.cid,
191
+ agentCardCid: publicSkills.agentCardCid,
192
+ updatedAt,
193
+ },
194
+ registration: {
195
+ chainId: step.registry.chainId,
196
+ identityRegistryAddress: step.registry.identityRegistryAddress,
197
+ agentId: step.identity.agentId,
198
+ },
199
+ ensName: nextEnsName,
200
+ operators: operatorsPointerFromState(state, nextEnsName),
201
+ ownerAddress: snapshotOwner,
202
+ })
203
+ const metadataPin = await addToIpfs(DEFAULT_IPFS_API_URL, JSON.stringify(registration, null, 2), fetch, { pinataJwt: step.pinataJwt })
204
+ assertVerifiedPin(metadataPin)
205
+ const metadataCid = metadataPin.cid
206
+ const agentUri = `ipfs://${metadataCid}`
207
+ const agentId = BigInt(step.identity.agentId)
208
+ await preflightSetAgentUri({
209
+ ...step.registry,
210
+ account: wallet.account,
211
+ agentId,
212
+ newUri: agentUri,
213
+ })
214
+ return {
215
+ to: step.registry.identityRegistryAddress,
216
+ data: encodeSetAgentUri({ agentId, newUri: agentUri }),
217
+ prepared: {
218
+ ownerAddress: snapshotOwner,
219
+ agentUri,
220
+ metadataCid,
221
+ publicSkills,
222
+ identity: { ...step.identity, state },
223
+ publicSkillsJson,
224
+ },
225
+ }
226
+ },
227
+ })
228
+ const client = createErc8004PublicClient(step.registry)
229
+ await awaitConfirmedReceipt(client, result.txHash, 'Owner-wallet profile save', { kind: 'public-profile', chainId: step.registry.chainId })
230
+ const nextIdentity: EthagentIdentity = {
231
+ ...result.prepared.identity,
232
+ source: 'erc8004',
233
+ address: getAddress(result.prepared.ownerAddress),
234
+ ownerAddress: getAddress(result.prepared.ownerAddress),
235
+ chainId: step.registry.chainId,
236
+ rpcUrl: step.registry.rpcUrl,
237
+ identityRegistryAddress: step.registry.identityRegistryAddress,
238
+ agentUri: result.prepared.agentUri,
239
+ metadataCid: result.prepared.metadataCid,
240
+ publicSkills: result.prepared.publicSkills,
241
+ }
242
+ await writePublicSkillsFile(nextIdentity, result.prepared.publicSkillsJson)
243
+ await markCurrentContinuityFilesPublished(nextIdentity)
244
+ const resolverSyncWarning = await syncResolverApprovalsAfterOwnerSave({
245
+ beforeIdentity: step.identity,
246
+ afterIdentity: nextIdentity,
247
+ registry: step.registry,
248
+ callbacks,
249
+ }).then(() => null).catch(err => resolverSyncWarningMessage(err))
250
+ const completionMessage = appendResolverSyncWarning(
251
+ rebackupCompletionMessage(
252
+ step.profileUpdates,
253
+ step.identity,
254
+ readEnsOkFromState(nextIdentity.state),
255
+ ),
256
+ resolverSyncWarning,
257
+ )
258
+ await callbacks.onIdentityComplete(nextIdentity, completionMessage, 'update')
259
+ }
260
+
261
+ async function runOperatorWalletPublicProfileSave(
262
+ step: Extract<Step, { kind: 'public-profile-signing' }>,
263
+ callbacks: EffectCallbacks,
264
+ ): Promise<void> {
265
+ if (!step.identity.agentId) throw new Error('Cannot update public profile: identity is missing an agent token ID')
266
+ const baseState = (step.identity.state ?? {}) as Record<string, unknown>
267
+ const ensName = typeof baseState.ensName === 'string' ? baseState.ensName.trim() : ''
268
+ if (!ensName) {
269
+ throw new Error('Operator wallet profile updates require an ENS subdomain, connect the owner wallet to set one up first')
270
+ }
271
+ const snapshotOwner = ownerAddressForSnapshotSave(step.identity, step.profileUpdates)
272
+ const walletAccess = walletRestoreAccessContext(step.identity, step.registry, step.profileUpdates, snapshotOwner)
273
+ if (!walletAccess) throw new Error('Operator-wallet profile updates require wallet restore access context')
274
+ const challengePurpose: WalletChallengePurpose = 'restore-operator'
275
+ if (step.vaultAddress) {
276
+ await runOperatorWalletVaultPublicProfileSave({
277
+ step,
278
+ callbacks,
279
+ snapshotOwner,
280
+ walletAccess,
281
+ challengePurpose,
282
+ vaultAddress: step.vaultAddress,
283
+ })
284
+ return
285
+ }
286
+
287
+ const reconcileBaseState = (step.identity.state ?? {}) as Record<string, unknown>
288
+ const activeOperator = typeof reconcileBaseState.activeOperatorAddress === 'string'
289
+ ? reconcileBaseState.activeOperatorAddress.trim()
290
+ : ''
291
+ if (activeOperator) {
292
+ const fixPlan = await reconcileWalletSetup({ identity: step.identity, registry: step.registry })
293
+ const stale = fixPlan.items.find(
294
+ (item): item is Extract<typeof item, { kind: 'missing-approval' }> =>
295
+ item.kind === 'missing-approval'
296
+ && item.address.toLowerCase() === activeOperator.toLowerCase(),
297
+ )
298
+ if (stale) {
299
+ throw new Error(
300
+ `Operator wallet ${stale.address} is no longer approved as a resolver delegate for this agent's ENS subdomain. Connect the owner wallet and run "Fix Records" to restore the approval before retrying.`,
301
+ )
302
+ }
303
+ }
304
+
305
+ const session = await openBrowserWalletSession({ onReady: callbacks.onWalletReady })
306
+ try {
307
+ const wallet = await session.requestSignature({
308
+ chainId: step.registry.chainId,
309
+ messageForAccount: account => createWalletRestoreAccessChallenge({
310
+ token: walletAccess.token,
311
+ ownerAddress: snapshotOwner,
312
+ walletAddress: account,
313
+ accessEpoch: walletAccess.accessEpoch,
314
+ purpose: challengePurpose,
315
+ }),
316
+ purpose: 'update-profile-operator',
317
+ })
318
+ assertSnapshotSaveSignerAuthorized(step.identity, step.profileUpdates, wallet.account, snapshotOwner, walletAccess)
319
+ const prepared = await prepareOperatorProfileArtifacts({
320
+ step,
321
+ wallet,
322
+ snapshotOwner,
323
+ walletAccess,
324
+ challengePurpose,
325
+ includeMetadata: false,
326
+ })
327
+ await publishOperatorProfileEnsRecord({
328
+ ensName,
329
+ signer: wallet.account,
330
+ registry: step.registry,
331
+ agentCardUri: prepared.agentCardUri,
332
+ callbacks,
333
+ session,
334
+ })
335
+
336
+ await writePublicSkillsFile(prepared.nextIdentity, prepared.publicSkillsJson)
337
+ await markCurrentContinuityFilesPublished(prepared.nextIdentity).catch(() => null)
338
+ await recordPublishedContinuitySnapshot({
339
+ identity: prepared.nextIdentity,
340
+ label: 'operator-wallet ENS profile update',
341
+ }).catch(() => null)
342
+
343
+ await callbacks.onIdentityComplete(
344
+ prepared.nextIdentity,
345
+ 'Profile pointer published to ENS records (org.ethagent.profile). ERC-8004 metadata stays put until owner wallet next signs.',
346
+ 'update',
347
+ )
348
+ } finally {
349
+ await session.close().catch(() => null)
350
+ callbacks.onWalletReady(null)
351
+ }
352
+ }
353
+
354
+ type WalletAccessContext = NonNullable<ReturnType<typeof walletRestoreAccessContext>>
355
+
356
+ async function runOperatorWalletVaultPublicProfileSave(args: {
357
+ step: Extract<Step, { kind: 'public-profile-signing' }>
358
+ callbacks: EffectCallbacks
359
+ snapshotOwner: Address
360
+ walletAccess: WalletAccessContext
361
+ challengePurpose: WalletChallengePurpose
362
+ vaultAddress: Address
363
+ }): Promise<void> {
364
+ const { step, callbacks, snapshotOwner, walletAccess, challengePurpose, vaultAddress } = args
365
+ const session = await openBrowserWalletSession({ onReady: callbacks.onWalletReady })
366
+ try {
367
+ const wallet = await session.requestSignature({
368
+ chainId: step.registry.chainId,
369
+ messageForAccount: account => createWalletRestoreAccessChallenge({
370
+ token: walletAccess.token,
371
+ ownerAddress: snapshotOwner,
372
+ walletAddress: account,
373
+ accessEpoch: walletAccess.accessEpoch,
374
+ purpose: challengePurpose,
375
+ }),
376
+ purpose: 'update-profile-operator',
377
+ flowId: 'public-profile-vault',
378
+ flowStep: 1,
379
+ })
380
+ assertSnapshotSaveSignerAuthorized(step.identity, step.profileUpdates, wallet.account, snapshotOwner, walletAccess)
381
+ await assertVaultSignerCanRotateAgentUri({
382
+ registry: step.registry,
383
+ vaultAddress,
384
+ agentId: BigInt(step.identity.agentId!),
385
+ signer: wallet.account,
386
+ })
387
+
388
+ const prepared = await prepareOperatorProfileArtifacts({
389
+ step,
390
+ wallet,
391
+ snapshotOwner,
392
+ walletAccess,
393
+ challengePurpose,
394
+ includeMetadata: true,
395
+ })
396
+ if (!prepared.agentUri || !prepared.metadataCid) {
397
+ throw new Error('Vault profile update did not prepare ERC-8004 metadata')
398
+ }
399
+
400
+ const vaultCall = encodeRotateAgentURI({
401
+ registry: getAddress(step.registry.identityRegistryAddress),
402
+ agentId: BigInt(step.identity.agentId!),
403
+ newURI: prepared.agentUri,
404
+ vaultAddress,
405
+ })
406
+ const vaultTx = await session.sendTransaction({
407
+ chainId: step.registry.chainId,
408
+ expectedAccount: wallet.account,
409
+ to: vaultCall.to,
410
+ data: vaultCall.data,
411
+ purpose: 'rotate-agent-uri-vault-operator',
412
+ flowId: 'public-profile-vault',
413
+ flowStep: 2,
414
+ })
415
+ const client = createErc8004PublicClient(step.registry)
416
+ await awaitConfirmedReceipt(
417
+ client,
418
+ vaultTx.txHash,
419
+ 'Operator public profile URI rotation through vault',
420
+ { kind: 'public-profile', chainId: step.registry.chainId },
421
+ )
422
+
423
+ const nextIdentity: EthagentIdentity = {
424
+ ...prepared.nextIdentity,
425
+ backup: prepared.nextIdentity.backup
426
+ ? { ...prepared.nextIdentity.backup, txHash: vaultTx.txHash }
427
+ : prepared.nextIdentity.backup,
428
+ }
429
+ await writePublicSkillsFile(nextIdentity, prepared.publicSkillsJson)
430
+ await markCurrentContinuityFilesPublished(nextIdentity).catch(() => null)
431
+ await recordPublishedContinuitySnapshot({
432
+ identity: nextIdentity,
433
+ label: 'operator-wallet vaulted profile update',
434
+ }).catch(() => null)
435
+
436
+ await callbacks.onIdentityComplete(
437
+ nextIdentity,
438
+ 'Profile updated. ERC-8004 metadata published through the operator delegation vault.',
439
+ 'update',
440
+ )
441
+ } finally {
442
+ await session.close().catch(() => null)
443
+ callbacks.onWalletReady(null)
444
+ }
445
+ }
446
+
447
+ type OperatorProfileArtifacts = {
448
+ nextIdentity: EthagentIdentity
449
+ publicSkillsJson: string
450
+ agentCardUri: string
451
+ agentUri?: string
452
+ metadataCid?: string
453
+ }
454
+
455
+ async function prepareOperatorProfileArtifacts(args: {
456
+ step: Extract<Step, { kind: 'public-profile-signing' }>
457
+ wallet: BrowserWalletSignature
458
+ snapshotOwner: Address
459
+ walletAccess: WalletAccessContext
460
+ challengePurpose: WalletChallengePurpose
461
+ includeMetadata: boolean
462
+ }): Promise<OperatorProfileArtifacts> {
463
+ const { step, wallet, snapshotOwner, walletAccess, challengePurpose } = args
464
+ const {
465
+ state,
466
+ nextName,
467
+ nextDescription,
468
+ nextEnsName,
469
+ uploadedImageUri,
470
+ } = await prepareProfileStateForSave({
471
+ identity: step.identity,
472
+ registry: step.registry,
473
+ profileUpdates: step.profileUpdates,
474
+ pinataJwt: step.pinataJwt,
475
+ ownerAddress: snapshotOwner,
476
+ walletAccount: getAddress(wallet.account),
477
+ includeLastBackedUpAt: true,
478
+ })
479
+ const nextIdentityForFiles: EthagentIdentity = { ...step.identity, state }
480
+
481
+ const publicSkillsJson = await prepareSyncedPublicSkillsJson(nextIdentityForFiles)
482
+ const publicSkillsPin = await addToIpfs(DEFAULT_IPFS_API_URL, publicSkillsJson, fetch, { pinataJwt: step.pinataJwt })
483
+ assertVerifiedPin(publicSkillsPin)
484
+ const agentCardPin = await addToIpfs(
485
+ DEFAULT_IPFS_API_URL,
486
+ serializeAgentCard(createAgentCard(defaultPublicSkillsProfile(nextIdentityForFiles))),
487
+ fetch,
488
+ { pinataJwt: step.pinataJwt },
489
+ )
490
+ assertVerifiedPin(agentCardPin)
491
+
492
+ const continuityFiles = await readContinuityFiles(nextIdentityForFiles)
493
+ const envelope = createContinuityEnvelopeForSave({
494
+ identity: nextIdentityForFiles,
495
+ registry: step.registry,
496
+ ownerAddress: snapshotOwner,
497
+ signerAddress: wallet.account,
498
+ walletSignature: wallet.signature,
499
+ state,
500
+ files: continuityFiles,
501
+ walletAccess,
502
+ challengePurpose,
503
+ })
504
+ const statePin = await addToIpfs(DEFAULT_IPFS_API_URL, serializeContinuitySnapshotEnvelope(envelope), fetch, { pinataJwt: step.pinataJwt })
505
+ assertVerifiedPin(statePin)
506
+
507
+ const publicSkills: PublicSkillsMetadata = {
508
+ cid: publicSkillsPin.cid,
509
+ agentCardCid: agentCardPin.cid,
510
+ updatedAt: envelope.createdAt,
511
+ status: 'pinned',
512
+ }
513
+ const backup: BackupMetadata = {
514
+ cid: statePin.cid,
515
+ createdAt: envelope.createdAt,
516
+ envelopeVersion: envelope.envelopeVersion,
517
+ ipfsApiUrl: DEFAULT_IPFS_API_URL,
518
+ status: 'pinned',
519
+ ownerAddress: snapshotOwner,
520
+ chainId: step.registry.chainId,
521
+ rpcUrl: step.registry.rpcUrl,
522
+ identityRegistryAddress: step.registry.identityRegistryAddress,
523
+ agentId: step.identity.agentId!,
524
+ }
525
+
526
+ let metadataCid: string | undefined
527
+ let agentUri: string | undefined
528
+ if (args.includeMetadata) {
529
+ const registration = withEthagentPointers({
530
+ type: 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1',
531
+ name: nextName ?? deriveAgentName(step.identity),
532
+ ...(nextDescription ? { description: nextDescription } : {}),
533
+ ...(uploadedImageUri ? { image: uploadedImageUri } : {}),
534
+ }, {
535
+ backup: { cid: statePin.cid, envelopeVersion: envelope.envelopeVersion, createdAt: envelope.createdAt },
536
+ publicDiscovery: { skillsCid: publicSkills.cid, agentCardCid: publicSkills.agentCardCid, updatedAt: publicSkills.updatedAt },
537
+ registration: { chainId: step.registry.chainId, identityRegistryAddress: step.registry.identityRegistryAddress, agentId: step.identity.agentId },
538
+ ensName: nextEnsName,
539
+ operators: operatorsPointerFromState(state, nextEnsName),
540
+ ownerAddress: snapshotOwner,
541
+ })
542
+ const metadataPin = await addToIpfs(DEFAULT_IPFS_API_URL, JSON.stringify(registration, null, 2), fetch, { pinataJwt: step.pinataJwt })
543
+ assertVerifiedPin(metadataPin)
544
+ metadataCid = metadataPin.cid
545
+ agentUri = `ipfs://${metadataCid}`
546
+ }
547
+
548
+ const nextBackup = agentUri && metadataCid
549
+ ? { ...backup, metadataCid, agentUri }
550
+ : backup
551
+ const nextIdentity: EthagentIdentity = {
552
+ ...step.identity,
553
+ state,
554
+ backup: nextBackup,
555
+ publicSkills,
556
+ ...(agentUri ? { agentUri } : {}),
557
+ ...(metadataCid ? { metadataCid } : {}),
558
+ }
559
+
560
+ return {
561
+ nextIdentity,
562
+ publicSkillsJson,
563
+ agentCardUri: `ipfs://${agentCardPin.cid}`,
564
+ ...(agentUri ? { agentUri } : {}),
565
+ ...(metadataCid ? { metadataCid } : {}),
566
+ }
567
+ }
568
+
569
+ async function publishOperatorProfileEnsRecord(args: {
570
+ ensName: string
571
+ signer: Address
572
+ registry: Erc8004RegistryConfig
573
+ agentCardUri: string
574
+ callbacks: EffectCallbacks
575
+ session: BrowserWalletSession
576
+ flowId?: string
577
+ flowStep?: number
578
+ }): Promise<void> {
579
+ const ensClient = createMainnetEnsPublicClient()
580
+ const tx = await runUpdateEnsRecords({
581
+ fullName: args.ensName,
582
+ ownerAddress: args.signer,
583
+ records: { profile: args.agentCardUri },
584
+ callbacks: args.callbacks,
585
+ purpose: 'update-profile-operator',
586
+ tokenChainId: args.registry.chainId,
587
+ session: args.session,
588
+ publicClient: ensClient,
589
+ ...(args.flowId ? { flowId: args.flowId } : {}),
590
+ ...(typeof args.flowStep === 'number' ? { flowStep: args.flowStep } : {}),
591
+ })
592
+ await awaitConfirmedReceipt(
593
+ ensClient,
594
+ tx.txHash as Hex,
595
+ 'Public profile ENS record update',
596
+ { kind: 'public-profile', chainId: 1 },
597
+ )
598
+ }
599
+
600
+ async function assertVaultSignerCanRotateAgentUri(args: {
601
+ registry: Erc8004RegistryConfig
602
+ vaultAddress: Address
603
+ agentId: bigint
604
+ signer: Address
605
+ }): Promise<void> {
606
+ const client = createErc8004PublicClient(args.registry)
607
+ const registryAddress = getAddress(args.registry.identityRegistryAddress)
608
+ const vaultAddress = getAddress(args.vaultAddress)
609
+ const signer = getAddress(args.signer)
610
+ let vaultOwner: Address
611
+ try {
612
+ vaultOwner = getAddress(await client.readContract({
613
+ address: vaultAddress,
614
+ abi: OPERATOR_VAULT_ABI,
615
+ functionName: 'agentOwner',
616
+ args: [registryAddress, args.agentId],
617
+ }) as Address)
618
+ } catch (err: unknown) {
619
+ throw new Error(`Could not verify operator delegation vault custody for agent #${args.agentId.toString()}: ${err instanceof Error ? err.message : String(err)}`)
620
+ }
621
+ if (vaultOwner === '0x0000000000000000000000000000000000000000') {
622
+ throw new Error(`Operator delegation vault ${vaultAddress} does not currently hold agent token #${args.agentId.toString()}. Connect the owner wallet and run "Fix Records" or return the token to the vault before retrying.`)
623
+ }
624
+ if (vaultOwner.toLowerCase() === signer.toLowerCase()) return
625
+
626
+ const isOperator = await client.readContract({
627
+ address: vaultAddress,
628
+ abi: OPERATOR_VAULT_ABI,
629
+ functionName: 'metadataOperators',
630
+ args: [registryAddress, args.agentId, signer],
631
+ }) as boolean
632
+ if (isOperator) return
633
+
634
+ throw new Error(
635
+ `Operator wallet ${signer} is not yet authorized on the operator delegation vault to rotate this agent's URI. Connect the owner wallet and run "Fix Records" or re-add this operator to grant the permission.`,
636
+ )
637
+ }
638
+
639
+ export async function runPublicProfileStorageSubmit(
640
+ input: string,
641
+ step: Extract<Step, { kind: 'public-profile-storage' }>,
642
+ callbacks: EffectCallbacks,
643
+ ): Promise<void> {
644
+ const { jwt: pinataJwt } = await savePinataJwt(input)
645
+ callbacks.onStep({ kind: 'public-profile-signing', identity: step.identity, registry: step.registry, pinataJwt, profileUpdates: step.profileUpdates, returnTo: step.returnTo, ...(step.vaultAddress ? { vaultAddress: step.vaultAddress } : {}) })
646
+ }
@@ -0,0 +1,7 @@
1
+ export {
2
+ rebackupCompletionMessage,
3
+ runRebackupPreflight,
4
+ runRebackupSigning,
5
+ runRebackupSigningInSession,
6
+ runRebackupStorageSubmit,
7
+ } from './runRebackup.js'