ethagent 3.3.3 → 4.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.
- package/.claude-plugin/marketplace.json +11 -0
- package/.claude-plugin/plugin.json +35 -0
- package/LICENSE +1 -1
- package/README.md +64 -104
- package/commands/ethagent.md +40 -0
- package/package.json +16 -16
- package/src/app/keybindings/KeybindingProvider.tsx +1 -6
- package/src/app/keybindings/types.ts +1 -6
- package/src/cli/ResetConfirmView.tsx +54 -53
- package/src/cli/demo.ts +86 -0
- package/src/cli/hookIo.ts +45 -0
- package/src/cli/main.tsx +94 -123
- package/src/cli/memoryGuard.ts +49 -0
- package/src/cli/reset.ts +28 -70
- package/src/cli/sessionStart.ts +33 -0
- package/src/cli/status.ts +46 -0
- package/src/cli/sync.ts +167 -0
- package/src/cli/syncAdapters/claude-code.ts +86 -0
- package/src/cli/syncAdapters/codex.ts +66 -0
- package/src/cli/syncAdapters/index.ts +45 -0
- package/src/cli/syncAdapters/managedBlock.ts +175 -0
- package/src/cli/syncAdapters/shared.ts +63 -0
- package/src/identity/continuity/envelopeParse.ts +20 -1
- package/src/identity/continuity/publicSkills.ts +3 -1
- package/src/identity/continuity/skills/publicSkillsSync.ts +2 -1
- package/src/identity/continuity/skills/scaffold.ts +5 -2
- package/src/identity/continuity/snapshots.ts +12 -5
- package/src/identity/continuity/storage/defaults.ts +20 -19
- package/src/identity/continuity/storage/status.ts +1 -1
- package/src/identity/ens/ensLookup/constants.ts +1 -1
- package/src/identity/manager/IdentityManager.tsx +33 -0
- package/src/identity/{hub → manager}/OperationalRoutes.tsx +37 -18
- package/src/identity/{hub → manager}/Routes.tsx +48 -34
- package/src/identity/{hub → manager}/continuity/ContinuityDashboardScreen.tsx +9 -19
- package/src/identity/{hub → manager}/continuity/RebackupStorageScreen.tsx +3 -3
- package/src/identity/manager/continuity/RecoveryConfirmScreen.tsx +102 -0
- package/src/identity/{hub → manager}/continuity/SavePromptScreen.tsx +2 -3
- package/src/identity/{hub → manager}/continuity/completion.ts +1 -1
- package/src/identity/{hub → manager}/continuity/effects.ts +1 -1
- package/src/identity/{hub → manager}/continuity/skills/DeleteSkillConfirmScreen.tsx +2 -2
- package/src/identity/{hub → manager}/continuity/skills/NewSkillScreen.tsx +0 -5
- package/src/identity/{hub → manager}/continuity/skills/NewSkillVisibilityScreen.tsx +4 -4
- package/src/identity/{hub → manager}/continuity/skills/SkillActionsScreen.tsx +6 -22
- package/src/identity/{hub → manager}/continuity/skills/SkillsTreeScreen.tsx +5 -17
- package/src/identity/{hub → manager}/continuity/snapshot.ts +1 -1
- package/src/identity/{hub → manager}/continuity/vault.ts +1 -1
- package/src/identity/{hub → manager}/create/CreateFlow.tsx +59 -32
- package/src/identity/{hub → manager}/create/effects.ts +19 -10
- package/src/identity/manager/create/importScan.ts +122 -0
- package/src/identity/{hub → manager}/custody/CustodyEditFlow.tsx +17 -61
- package/src/identity/{hub → manager}/custody/actions.ts +1 -15
- package/src/identity/{hub → manager}/custody/routes.tsx +20 -40
- package/src/identity/{hub → manager}/custody/transactions.ts +1 -0
- package/src/identity/{hub → manager}/custody/types.ts +1 -2
- package/src/identity/{hub → manager}/custody/useCustodyEffects.ts +1 -1
- package/src/identity/{hub → manager}/ens/EnsEditAdvancedScreens.tsx +2 -2
- package/src/identity/{hub → manager}/ens/EnsEditMaintenanceScreens.tsx +12 -23
- package/src/identity/{hub → manager}/ens/EnsEditReviewScreens.tsx +18 -42
- package/src/identity/{hub → manager}/ens/EnsEditRunners.tsx +1 -1
- package/src/identity/{hub → manager}/ens/EnsEditShared.tsx +0 -2
- package/src/identity/{hub → manager}/ens/EnsEditSimpleScreens.tsx +10 -19
- package/src/identity/{hub → manager}/ens/EnsFlow.tsx +133 -41
- package/src/identity/{hub → manager}/ens/EnsOperatorWalletsScreen.tsx +14 -19
- package/src/identity/{hub → manager}/ens/editCopy.ts +1 -14
- package/src/identity/{hub → manager}/profile/EditProfileFlow.tsx +99 -66
- package/src/identity/{hub → manager}/profile/effects.ts +1 -3
- package/src/identity/{hub → manager}/profile/operatorSave.ts +1 -1
- package/src/identity/{hub → manager}/profile/state.ts +1 -1
- package/src/identity/{hub/identityHubReducer.ts → manager/reducer.ts} +25 -26
- package/src/identity/{hub → manager}/restore/RestoreFlow.tsx +16 -24
- package/src/identity/{hub → manager}/restore/apply.ts +1 -1
- package/src/identity/{hub → manager}/restore/auth.ts +1 -1
- package/src/identity/{hub → manager}/restore/discover.ts +1 -1
- package/src/identity/{hub → manager}/restore/fetch.ts +1 -1
- package/src/identity/{hub → manager}/restore/restoreAdmin.ts +1 -1
- package/src/identity/{hub → manager}/restore/useRestoreEffects.ts +2 -9
- package/src/identity/{hub → manager}/settings/StorageCredentialScreen.tsx +10 -25
- package/src/identity/{hub → manager}/shared/components/DetailsScreen.tsx +5 -7
- package/src/identity/{hub → manager}/shared/components/ErrorScreen.tsx +6 -10
- package/src/identity/{hub → manager}/shared/components/FlowTimeline.tsx +4 -3
- package/src/identity/{hub → manager}/shared/components/IdentitySummary.tsx +19 -59
- package/src/identity/manager/shared/components/LazyMenu.tsx +147 -0
- package/src/identity/manager/shared/components/MenuScreen.tsx +220 -0
- package/src/identity/manager/shared/components/OperationCompleteScreen.tsx +28 -0
- package/src/identity/{hub → manager}/shared/components/UnlinkedIdentityScreen.tsx +9 -10
- package/src/identity/{hub → manager}/shared/components/WalletApprovalScreen.tsx +1 -2
- package/src/identity/manager/shared/components/Wordmark.tsx +54 -0
- package/src/identity/{hub → manager}/shared/components/menuFlagsFromReconciliation.ts +39 -15
- package/src/identity/{hub → manager}/shared/effects/profilePrep.ts +1 -1
- package/src/identity/manager/shared/effects/types.ts +30 -0
- package/src/identity/{hub → manager}/shared/model/copy.ts +0 -4
- package/src/identity/{hub → manager}/shared/model/errors.ts +32 -3
- package/src/identity/{hub → manager}/shared/model/network.ts +2 -2
- package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/hook.ts +5 -0
- package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/run.ts +1 -1
- package/src/identity/{hub/shared/reconciliation/useAgentReconciliation.ts → manager/shared/reconciliation/index.ts} +6 -0
- package/src/identity/{hub → manager}/shared/utils.ts +6 -10
- package/src/identity/{hub → manager}/transfer/TokenTransferFlow.tsx +3 -3
- package/src/identity/{hub → manager}/transfer/TokenTransferScreens.tsx +4 -10
- package/src/identity/{hub → manager}/transfer/effects.ts +1 -1
- package/src/identity/{hub → manager}/types.ts +5 -6
- package/src/identity/{hub/useIdentityHubContinuity.ts → manager/useContinuity.ts} +59 -27
- package/src/identity/{hub/useIdentityHubController.ts → manager/useController.ts} +38 -35
- package/src/identity/{hub/useIdentityHubSideEffects.ts → manager/useSideEffects.ts} +40 -4
- package/src/identity/registry/erc8004/discovery.ts +3 -17
- package/src/identity/registry/erc8004/utils.ts +1 -1
- package/src/identity/storage/ipfs.ts +21 -1
- package/src/identity/wallet/browserWallet/html.ts +10 -2
- package/src/identity/wallet/browserWallet/http.ts +18 -0
- package/src/identity/wallet/browserWallet/requestServer.ts +5 -1
- package/src/identity/wallet/browserWallet/requests.ts +10 -28
- package/src/identity/wallet/browserWallet/session.ts +26 -33
- package/src/identity/wallet/browserWallet/validation.ts +14 -0
- package/src/identity/wallet/browserWallet/walletPageSource.ts +22 -40
- package/src/identity/wallet/page/boot.ts +43 -0
- package/src/identity/wallet/page/config.ts +59 -0
- package/src/identity/wallet/page/constants.ts +12 -0
- package/src/identity/wallet/page/copy.ts +47 -68
- package/src/identity/wallet/page/css.ts +638 -0
- package/src/identity/wallet/page/{errorView.ts → errors.ts} +5 -14
- package/src/identity/wallet/page/{controller.ts → flow.ts} +4 -71
- package/src/identity/wallet/page/markup.ts +44 -34
- package/src/identity/wallet/page/{walletProvider.ts → provider.ts} +0 -3
- package/src/identity/wallet/page/resize.ts +95 -0
- package/src/identity/wallet/page/state.ts +135 -8
- package/src/identity/wallet/page/timeline.ts +161 -0
- package/src/identity/wallet/page/view.ts +22 -302
- package/src/storage/config.ts +30 -80
- package/src/storage/reset.ts +31 -0
- package/src/storage/secrets.ts +1 -16
- package/src/ui/Select.tsx +27 -5
- package/src/ui/Spinner.tsx +16 -15
- package/src/ui/Surface.tsx +21 -17
- package/src/ui/TextArea.tsx +173 -0
- package/src/ui/TextInput.tsx +31 -133
- package/src/ui/theme.ts +22 -13
- package/src/utils/clipboard.ts +0 -140
- package/src/app/FirstRun.tsx +0 -577
- package/src/app/FirstRunTimeline.tsx +0 -51
- package/src/app/firstRunConfig.ts +0 -26
- package/src/app/hooks/useCancelRequest.ts +0 -22
- package/src/app/hooks/useDoublePress.ts +0 -46
- package/src/app/hooks/useExitOnCtrlC.ts +0 -36
- package/src/auth/openaiOAuth/credentials.ts +0 -47
- package/src/auth/openaiOAuth/crypto.ts +0 -23
- package/src/auth/openaiOAuth/index.ts +0 -238
- package/src/auth/openaiOAuth/landingPage.ts +0 -116
- package/src/auth/openaiOAuth/listener.ts +0 -151
- package/src/auth/openaiOAuth/refresh.ts +0 -70
- package/src/auth/openaiOAuth/shared.ts +0 -115
- package/src/chat/ChatBottomPane.tsx +0 -296
- package/src/chat/ChatScreen.tsx +0 -1685
- package/src/chat/ConversationStack.tsx +0 -56
- package/src/chat/MessageList.tsx +0 -638
- package/src/chat/SessionStatus.tsx +0 -53
- package/src/chat/chatEnvironment.ts +0 -16
- package/src/chat/chatScreenUtils.ts +0 -194
- package/src/chat/chatSessionState.ts +0 -146
- package/src/chat/chatTurnContext.ts +0 -50
- package/src/chat/chatTurnOrchestrator.ts +0 -603
- package/src/chat/chatTurnRows.ts +0 -64
- package/src/chat/commands.ts +0 -494
- package/src/chat/continuityEditReview.ts +0 -42
- package/src/chat/display/DiffView.tsx +0 -193
- package/src/chat/display/SyntaxText.tsx +0 -192
- package/src/chat/display/toolCallDisplay.ts +0 -103
- package/src/chat/display/toolResultDisplay.ts +0 -19
- package/src/chat/input/ChatInput.tsx +0 -625
- package/src/chat/input/chatInputHelpers.ts +0 -62
- package/src/chat/input/chatInputState.ts +0 -247
- package/src/chat/input/chatPaste.ts +0 -49
- package/src/chat/input/imageRefs.ts +0 -30
- package/src/chat/input/inputRendering.tsx +0 -93
- package/src/chat/input/textCursor.ts +0 -212
- package/src/chat/messageMarkdown.ts +0 -220
- package/src/chat/messageRows.ts +0 -43
- package/src/chat/planImplementation.ts +0 -62
- package/src/chat/slashCommandHandlers.ts +0 -122
- package/src/chat/slashCommandViews.ts +0 -120
- package/src/chat/transcript/TranscriptView.tsx +0 -184
- package/src/chat/transcript/transcriptViewport.ts +0 -295
- package/src/chat/views/ContextLimitView.tsx +0 -95
- package/src/chat/views/ContinuityEditReviewView.tsx +0 -50
- package/src/chat/views/CopyPicker.tsx +0 -50
- package/src/chat/views/PermissionPrompt.tsx +0 -156
- package/src/chat/views/PermissionsView.tsx +0 -165
- package/src/chat/views/PlanApprovalView.tsx +0 -91
- package/src/chat/views/ResumeView.tsx +0 -273
- package/src/chat/views/RewindView.tsx +0 -412
- package/src/cli/preview.tsx +0 -14
- package/src/cli/updateNotice.ts +0 -54
- package/src/identity/continuity/privateEdit/apply.ts +0 -170
- package/src/identity/continuity/privateEdit/diff.ts +0 -6
- package/src/identity/continuity/privateEdit/files.ts +0 -23
- package/src/identity/continuity/privateEdit/types.ts +0 -28
- package/src/identity/continuity/privateEdit.ts +0 -46
- package/src/identity/hub/IdentityHub.tsx +0 -14
- package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +0 -104
- package/src/identity/hub/ens/effects.ts +0 -218
- package/src/identity/hub/shared/components/MenuScreen.tsx +0 -241
- package/src/identity/hub/shared/effects/types.ts +0 -53
- package/src/identity/hub/shared/reconciliation/index.ts +0 -14
- package/src/identity/wallet/page/grainient.ts +0 -278
- package/src/identity/wallet/page/html.ts +0 -28
- package/src/identity/wallet/page/styles/base.ts +0 -259
- package/src/identity/wallet/page/styles/components.ts +0 -262
- package/src/identity/wallet/page/styles/index.ts +0 -5
- package/src/identity/wallet/page/styles/responsive.ts +0 -247
- package/src/identity/wallet/page.tsx +0 -38
- package/src/mcp/approvals.ts +0 -113
- package/src/mcp/config.ts +0 -235
- package/src/mcp/manager.ts +0 -482
- package/src/mcp/managerHelpers.ts +0 -70
- package/src/mcp/names.ts +0 -19
- package/src/mcp/output.ts +0 -96
- package/src/models/ModelPicker.tsx +0 -1009
- package/src/models/catalog.ts +0 -327
- package/src/models/huggingface.ts +0 -712
- package/src/models/huggingfaceStorage.ts +0 -136
- package/src/models/llamacpp.ts +0 -848
- package/src/models/llamacppCommands.ts +0 -44
- package/src/models/llamacppConfig.ts +0 -34
- package/src/models/llamacppDiscovery.ts +0 -176
- package/src/models/llamacppOutput.ts +0 -65
- package/src/models/llamacppPreflight.ts +0 -158
- package/src/models/modelDisplay.ts +0 -180
- package/src/models/modelPickerCatalogFlow.ts +0 -56
- package/src/models/modelPickerCredentials.ts +0 -166
- package/src/models/modelPickerData.ts +0 -41
- package/src/models/modelPickerDisplay.tsx +0 -132
- package/src/models/modelPickerHfFlow.ts +0 -192
- package/src/models/modelPickerLocalRunnerFlow.ts +0 -115
- package/src/models/modelPickerOptions.ts +0 -457
- package/src/models/modelPickerTypes.ts +0 -69
- package/src/models/modelPickerUninstallFlow.ts +0 -48
- package/src/models/modelPickerViewHelpers.ts +0 -174
- package/src/models/modelRecommendation.ts +0 -139
- package/src/models/providerDisplay.ts +0 -16
- package/src/models/runtimeDetection.ts +0 -81
- package/src/models/uncensoredCatalog.ts +0 -86
- package/src/providers/anthropic.ts +0 -290
- package/src/providers/contracts.ts +0 -71
- package/src/providers/errors.ts +0 -80
- package/src/providers/gemini.ts +0 -391
- package/src/providers/openai-chat.ts +0 -474
- package/src/providers/openai-responses-format.ts +0 -177
- package/src/providers/openai-responses.ts +0 -306
- package/src/providers/openaiChatWire.ts +0 -124
- package/src/providers/registry.ts +0 -120
- package/src/providers/retry.ts +0 -58
- package/src/providers/sse.ts +0 -93
- package/src/runtime/compaction.ts +0 -395
- package/src/runtime/cwd.ts +0 -43
- package/src/runtime/providerTurn.ts +0 -38
- package/src/runtime/sessionMode.ts +0 -55
- package/src/runtime/systemPrompt.ts +0 -213
- package/src/runtime/textToolParser.ts +0 -161
- package/src/runtime/toolClaimGuards.ts +0 -143
- package/src/runtime/toolExecution.ts +0 -304
- package/src/runtime/toolIntent.ts +0 -143
- package/src/runtime/turn.ts +0 -369
- package/src/runtime/turnNudges.ts +0 -223
- package/src/runtime/turnTypes.ts +0 -86
- package/src/storage/factoryReset.ts +0 -127
- package/src/storage/history.ts +0 -58
- package/src/storage/permissions.ts +0 -76
- package/src/storage/rewind.ts +0 -266
- package/src/storage/sessionExport.ts +0 -49
- package/src/storage/sessions.ts +0 -495
- package/src/tools/bashSafety.ts +0 -186
- package/src/tools/bashTool.ts +0 -140
- package/src/tools/changeDirectoryTool.ts +0 -213
- package/src/tools/contracts.ts +0 -192
- package/src/tools/deleteFileTool.ts +0 -116
- package/src/tools/editTool.ts +0 -165
- package/src/tools/editUtils.ts +0 -170
- package/src/tools/fileDiff.ts +0 -261
- package/src/tools/listDirectoryTool.ts +0 -55
- package/src/tools/listSkillFilesTool.ts +0 -77
- package/src/tools/listSkillsTool.ts +0 -68
- package/src/tools/mcpResourceTools.ts +0 -95
- package/src/tools/permissionRules.ts +0 -85
- package/src/tools/privateContinuityEditTool.ts +0 -187
- package/src/tools/privateContinuityReadTool.ts +0 -106
- package/src/tools/readSkillTool.ts +0 -107
- package/src/tools/readTool.ts +0 -85
- package/src/tools/registry.ts +0 -103
- package/src/tools/writeFileTool.ts +0 -167
- package/src/ui/BrandSplash.tsx +0 -133
- package/src/ui/terminalTitle.ts +0 -30
- package/src/utils/images.ts +0 -140
- package/src/utils/markdownSegments.ts +0 -51
- package/src/utils/messages.ts +0 -37
- package/src/utils/withRetry.ts +0 -324
- /package/src/identity/{hub → manager}/continuity/state.ts +0 -0
- /package/src/identity/{hub → manager}/custody/helpers.ts +0 -0
- /package/src/identity/{hub → manager}/custody/preflight.ts +0 -0
- /package/src/identity/{hub → manager}/custody/state.ts +0 -0
- /package/src/identity/{hub → manager}/custody/useCustodyFlow.tsx +0 -0
- /package/src/identity/{hub → manager}/ens/EnsEditFlow.tsx +0 -0
- /package/src/identity/{hub → manager}/ens/advancedEnsValidation.ts +0 -0
- /package/src/identity/{hub → manager}/ens/state.ts +0 -0
- /package/src/identity/{hub → manager}/ens/transactions.ts +0 -0
- /package/src/identity/{hub → manager}/ens/types.ts +0 -0
- /package/src/identity/{hub → manager}/profile/identity.ts +0 -0
- /package/src/identity/{hub → manager}/restore/envelopes.ts +0 -0
- /package/src/identity/{hub → manager}/restore/helpers.ts +0 -0
- /package/src/identity/{hub → manager}/restore/recovery.ts +0 -0
- /package/src/identity/{hub → manager}/restore/resolve.ts +0 -0
- /package/src/identity/{hub → manager}/shared/components/BusyScreen.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/components/NetworkScreen.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/components/PinataJwtInput.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/effects/receipts.ts +0 -0
- /package/src/identity/{hub → manager}/shared/effects/sync.ts +0 -0
- /package/src/identity/{hub → manager}/shared/model/format.ts +0 -0
- /package/src/identity/{hub → manager}/shared/operatorWallets.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/ownership.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/types.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/walletSetup.ts +0 -0
- /package/src/identity/{hub → manager}/shared/txGuard.ts +0 -0
- /package/src/identity/{hub → manager}/transfer/progress.ts +0 -0
- /package/src/identity/{hub → manager}/transfer/state.ts +0 -0
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { EthagentConfig, EthagentIdentity } from '../../../storage/config.js'
|
|
2
|
-
import { supportedErc8004ChainForId } from '../../registry/erc8004.js'
|
|
3
2
|
import { snapshotSaveRequiresOwnerSigner } from '../continuity/snapshot.js'
|
|
4
|
-
import type {
|
|
5
|
-
import type { ProfileUpdates, Step } from '../
|
|
6
|
-
|
|
7
|
-
const MIN_BUSY_ERROR_MS = 2000
|
|
3
|
+
import type { IdentityManagerInitialAction } from '../types.js'
|
|
4
|
+
import type { ProfileUpdates, Step } from '../reducer.js'
|
|
8
5
|
|
|
9
6
|
export function isWalletCancelled(err: unknown): boolean {
|
|
10
7
|
if (!err) return false
|
|
@@ -18,9 +15,7 @@ export function isStorageError(err: unknown): boolean {
|
|
|
18
15
|
return /pinata|ipfs|pin|storage/i.test(message)
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
return supportedErc8004ChainForId(chainId)?.name ?? `chain ${chainId}`
|
|
23
|
-
}
|
|
18
|
+
const MIN_BUSY_ERROR_MS = 2000
|
|
24
19
|
|
|
25
20
|
export function waitForMinimumBusyTime(startedAt: number): Promise<void> {
|
|
26
21
|
const remaining = MIN_BUSY_ERROR_MS - (Date.now() - startedAt)
|
|
@@ -51,11 +46,12 @@ export function rebackupWalletApprovalView(
|
|
|
51
46
|
}
|
|
52
47
|
}
|
|
53
48
|
|
|
54
|
-
export function isCreateStep(step: Step): step is Extract<Step, { kind: 'replace-confirm' | 'create-name' | 'create-description' | 'create-custody' | 'create-preflight' | 'create-registry' | 'create-signing' | 'create-storage' }> {
|
|
49
|
+
export function isCreateStep(step: Step): step is Extract<Step, { kind: 'replace-confirm' | 'create-name' | 'create-description' | 'create-custody' | 'create-import' | 'create-preflight' | 'create-registry' | 'create-signing' | 'create-storage' }> {
|
|
55
50
|
return step.kind === 'replace-confirm'
|
|
56
51
|
|| step.kind === 'create-name'
|
|
57
52
|
|| step.kind === 'create-description'
|
|
58
53
|
|| step.kind === 'create-custody'
|
|
54
|
+
|| step.kind === 'create-import'
|
|
59
55
|
|| step.kind === 'create-preflight'
|
|
60
56
|
|| step.kind === 'create-registry'
|
|
61
57
|
|| step.kind === 'create-signing'
|
|
@@ -67,7 +63,7 @@ export function isRestoreStep(step: Step): step is Exclude<Extract<Step, { kind:
|
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
export function initialStepForAction(
|
|
70
|
-
action:
|
|
66
|
+
action: IdentityManagerInitialAction | undefined,
|
|
71
67
|
config: EthagentConfig | undefined,
|
|
72
68
|
): Step {
|
|
73
69
|
if (action === 'create') return config?.identity ? { kind: 'replace-confirm', next: 'create' } : { kind: 'create-name' }
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
EffectCallbacks,
|
|
10
10
|
TokenTransferProgress,
|
|
11
11
|
} from '../shared/effects/types.js'
|
|
12
|
-
import type { Step } from '../
|
|
12
|
+
import type { Step } from '../reducer.js'
|
|
13
13
|
import { BusyScreen } from '../shared/components/BusyScreen.js'
|
|
14
14
|
import { RebackupStorageScreen } from '../continuity/RebackupStorageScreen.js'
|
|
15
15
|
import {
|
|
@@ -87,7 +87,7 @@ export const TokenTransferFlow: React.FC<TokenTransferFlowProps> = ({
|
|
|
87
87
|
return (
|
|
88
88
|
<BusyScreen
|
|
89
89
|
title="Resolve Receiver Wallet"
|
|
90
|
-
subtitle={`Resolving ${step.targetHandle}
|
|
90
|
+
subtitle={`Resolving ${step.targetHandle}.`}
|
|
91
91
|
label="checking ens or address..."
|
|
92
92
|
onCancel={() => {
|
|
93
93
|
resolveAbortRef.current?.abort()
|
|
@@ -158,5 +158,5 @@ function networkLabelForChainId(chainId: number): string {
|
|
|
158
158
|
|
|
159
159
|
function tokenTransferBackHint(returnTo: Step | undefined): string {
|
|
160
160
|
if (returnTo?.kind === 'edit-profile-ens') return 'Return to ENS setup'
|
|
161
|
-
return 'Return to
|
|
161
|
+
return 'Return to menu'
|
|
162
162
|
}
|
|
@@ -16,7 +16,6 @@ import { FlowTimeline } from '../shared/components/FlowTimeline.js'
|
|
|
16
16
|
import { OPEN_BROWSER_HINT } from '../shared/components/WalletApprovalScreen.js'
|
|
17
17
|
|
|
18
18
|
const TRANSFER_STEPS = ['Choose Receiver', 'Sender Signs', 'Receiver Signs', 'Sender Updates URI', 'Transfer Token']
|
|
19
|
-
const APPROVAL_GUARDRAIL = 'No approve(), setApprovalForAll(), transferFrom(), or token approval is requested.'
|
|
20
19
|
|
|
21
20
|
type TokenTransferTargetScreenProps = {
|
|
22
21
|
identity: EthagentIdentity
|
|
@@ -49,12 +48,10 @@ export const TokenTransferTargetScreen: React.FC<TokenTransferTargetScreenProps>
|
|
|
49
48
|
<StatusRow label="Network" value={tokenNetworkLabel} />
|
|
50
49
|
<StatusRow label="Sender" value={senderValue} />
|
|
51
50
|
<Box marginTop={1} flexDirection="column">
|
|
52
|
-
<Text color={theme.textSubtle}>Use this before any ERC-8004 token transfer.</Text>
|
|
53
|
-
<Text color={theme.textSubtle}>Both signed wallets can read this snapshot; after transfer, restore with the receiver wallet.</Text>
|
|
54
|
-
<Text color={theme.textSubtle}>{APPROVAL_GUARDRAIL}</Text>
|
|
55
51
|
{custodyMode === 'advanced' ? (
|
|
56
|
-
<Text color={theme.textSubtle}>Advanced custody:
|
|
52
|
+
<Text color={theme.textSubtle}>Advanced custody: sign as the owner wallet.</Text>
|
|
57
53
|
) : null}
|
|
54
|
+
<Text color={theme.textSubtle}>No token approval is requested.</Text>
|
|
58
55
|
</Box>
|
|
59
56
|
<Box marginTop={1} flexDirection="column">
|
|
60
57
|
<TextInput
|
|
@@ -180,7 +177,6 @@ export const TokenTransferReadyScreen: React.FC<TokenTransferReadyScreenProps> =
|
|
|
180
177
|
footer={footer}
|
|
181
178
|
>
|
|
182
179
|
<Box flexDirection="column">
|
|
183
|
-
<Text color={theme.text}>Snapshot published. Transfer the ERC-8004 token externally on {tokenNetworkLabel} from sender to receiver.</Text>
|
|
184
180
|
<Box marginTop={1} flexDirection="column">
|
|
185
181
|
<StatusRow label="Token" value={identity.agentId ? `#${identity.agentId}` : 'not created'} tone={identity.agentId ? 'ok' : 'warn'} />
|
|
186
182
|
<StatusRow label="Network" value={tokenNetworkLabel} tone="ok" />
|
|
@@ -190,10 +186,8 @@ export const TokenTransferReadyScreen: React.FC<TokenTransferReadyScreenProps> =
|
|
|
190
186
|
<StatusRow label="Token URI tx" value={shortHash(txHash)} tone="ok" />
|
|
191
187
|
</Box>
|
|
192
188
|
<Box marginTop={1} flexDirection="column">
|
|
193
|
-
<Text color={theme.textSubtle}>
|
|
194
|
-
<Text color={theme.textSubtle}>
|
|
195
|
-
<Text color={theme.textSubtle}>After transfer, use Switch Agent with the receiver wallet.</Text>
|
|
196
|
-
<Text color={theme.textSubtle}>{APPROVAL_GUARDRAIL}</Text>
|
|
189
|
+
<Text color={theme.textSubtle}>Transfer the token externally, then restore with the receiver wallet.</Text>
|
|
190
|
+
<Text color={theme.textSubtle}>No token approval is requested.</Text>
|
|
197
191
|
</Box>
|
|
198
192
|
<Box marginTop={1}>
|
|
199
193
|
<Select<'back'>
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import { resolveValidatedPinataJwt, savePinataJwt } from '../../storage/pinataJwt.js'
|
|
28
28
|
import { openBrowserWalletSession } from '../../wallet/browserWallet.js'
|
|
29
29
|
import { resolveEnsAddress } from '../../ens/ensLookup.js'
|
|
30
|
-
import type { Step } from '../
|
|
30
|
+
import type { Step } from '../reducer.js'
|
|
31
31
|
import type { EffectCallbacks } from '../shared/effects/types.js'
|
|
32
32
|
import { awaitConfirmedReceipt } from '../shared/effects/receipts.js'
|
|
33
33
|
import {
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { EthagentConfig, EthagentIdentity } from '../../storage/config.js'
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type IdentityManagerResult =
|
|
4
4
|
| { kind: 'token'; identity: EthagentIdentity }
|
|
5
5
|
| { kind: 'updated'; config: EthagentConfig; message: string }
|
|
6
|
-
| { kind: 'skip' }
|
|
7
6
|
| { kind: 'cancel' }
|
|
8
7
|
|
|
9
|
-
export type
|
|
8
|
+
export type IdentityManagerInitialAction = 'create' | 'load' | 'settings' | 'save-snapshot' | 'save-prompt'
|
|
10
9
|
|
|
11
|
-
export type
|
|
10
|
+
export type IdentityManagerProps = {
|
|
12
11
|
mode: 'first-run' | 'manage'
|
|
13
12
|
config?: EthagentConfig
|
|
14
|
-
initialAction?:
|
|
15
|
-
onComplete: (result:
|
|
13
|
+
initialAction?: IdentityManagerInitialAction
|
|
14
|
+
onComplete: (result: IdentityManagerResult) => void
|
|
16
15
|
onConfigChange?: (config: EthagentConfig) => void
|
|
17
16
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
+
import { watch, type FSWatcher } from 'node:fs'
|
|
2
3
|
import type { EthagentIdentity } from '../../storage/config.js'
|
|
3
4
|
import { catFromIpfs, DEFAULT_IPFS_API_URL } from '../storage/ipfs.js'
|
|
4
5
|
import {
|
|
@@ -19,21 +20,37 @@ import {
|
|
|
19
20
|
import type { SkillVisibility } from '../continuity/skills/types.js'
|
|
20
21
|
import { syncAgentCardManifest } from '../continuity/skills/publicSkillsSync.js'
|
|
21
22
|
import { continuityVaultRef } from '../continuity/storage.js'
|
|
22
|
-
import type { Step } from './
|
|
23
|
+
import type { Step } from './reducer.js'
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
const WORKING_STATUS_STEPS = new Set<string>([
|
|
26
|
+
'menu',
|
|
27
|
+
'continuity-private',
|
|
28
|
+
'continuity-public',
|
|
29
|
+
'continuity-skills-tree',
|
|
30
|
+
'save-prompt',
|
|
31
|
+
'rebackup-confirm',
|
|
32
|
+
'recovery-refetch-confirm',
|
|
33
|
+
'continuity-overwrite-confirm',
|
|
34
|
+
'restore-recovery-input',
|
|
35
|
+
'restore-ens-input',
|
|
36
|
+
'restore-token-id-input',
|
|
37
|
+
'restore-select-token',
|
|
38
|
+
])
|
|
39
|
+
const WATCHED_VAULT_FILES = new Set<string>(['SOUL.md', 'MEMORY.md', 'agent-card.json'])
|
|
40
|
+
|
|
41
|
+
type UseIdentityManagerContinuityArgs = {
|
|
25
42
|
identity: EthagentIdentity | undefined
|
|
26
43
|
step: Step
|
|
27
44
|
setStep: (step: Step) => void
|
|
28
45
|
handleStepError: (err: unknown, backStep: Step, softCancel?: Step) => void
|
|
29
46
|
}
|
|
30
47
|
|
|
31
|
-
export function
|
|
48
|
+
export function useIdentityManagerContinuity({
|
|
32
49
|
identity,
|
|
33
50
|
step,
|
|
34
51
|
setStep,
|
|
35
52
|
handleStepError,
|
|
36
|
-
}:
|
|
53
|
+
}: UseIdentityManagerContinuityArgs): {
|
|
37
54
|
continuityReady: boolean
|
|
38
55
|
setContinuityReady: (ready: boolean) => void
|
|
39
56
|
workingStatus: ContinuityWorkingTreeStatus | null
|
|
@@ -60,36 +77,51 @@ export function useIdentityHubContinuity({
|
|
|
60
77
|
return () => { cancelled = true }
|
|
61
78
|
}, [identity, step.kind])
|
|
62
79
|
|
|
80
|
+
const computeStatus = useCallback(async (): Promise<ContinuityWorkingTreeStatus | null> => {
|
|
81
|
+
if (!identity) return null
|
|
82
|
+
try {
|
|
83
|
+
const [latest] = await listPublishedContinuitySnapshots(identity, 1)
|
|
84
|
+
return await continuityWorkingTreeStatus(identity, latest)
|
|
85
|
+
} catch {
|
|
86
|
+
return null
|
|
87
|
+
}
|
|
88
|
+
}, [identity])
|
|
89
|
+
|
|
90
|
+
const editorReturn = 'editorOpened' in step ? step.editorOpened : undefined
|
|
91
|
+
|
|
63
92
|
useEffect(() => {
|
|
64
93
|
let cancelled = false
|
|
65
94
|
if (!identity) return
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
&& step.kind !== 'continuity-skills-tree'
|
|
71
|
-
&& step.kind !== 'save-prompt'
|
|
72
|
-
&& step.kind !== 'rebackup-confirm'
|
|
73
|
-
) return
|
|
95
|
+
if (!WORKING_STATUS_STEPS.has(step.kind)) return
|
|
96
|
+
void computeStatus().then(status => { if (!cancelled) setWorkingStatus(status) })
|
|
97
|
+
return () => { cancelled = true }
|
|
98
|
+
}, [identity, step.kind, editorReturn, computeStatus])
|
|
74
99
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (!identity) return
|
|
102
|
+
if (!WORKING_STATUS_STEPS.has(step.kind)) return
|
|
103
|
+
let cancelled = false
|
|
104
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
105
|
+
let watcher: FSWatcher | undefined
|
|
106
|
+
const schedule = (): void => {
|
|
107
|
+
if (timer) clearTimeout(timer)
|
|
108
|
+
timer = setTimeout(() => {
|
|
109
|
+
void computeStatus().then(status => { if (!cancelled) setWorkingStatus(status) })
|
|
110
|
+
}, 200)
|
|
85
111
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
112
|
+
try {
|
|
113
|
+
watcher = watch(continuityVaultRef(identity).dir, (_event, filename) => {
|
|
114
|
+
if (filename && !WATCHED_VAULT_FILES.has(String(filename))) return
|
|
115
|
+
schedule()
|
|
116
|
+
})
|
|
117
|
+
watcher.on('error', () => { try { watcher?.close() } catch {} })
|
|
118
|
+
} catch {}
|
|
89
119
|
return () => {
|
|
90
120
|
cancelled = true
|
|
121
|
+
if (timer) clearTimeout(timer)
|
|
122
|
+
try { watcher?.close() } catch {}
|
|
91
123
|
}
|
|
92
|
-
}, [identity, step.kind])
|
|
124
|
+
}, [identity, step.kind, computeStatus])
|
|
93
125
|
|
|
94
126
|
const requireReadyVault = async (): Promise<EthagentIdentity> => {
|
|
95
127
|
if (!identity) throw new Error('No active identity')
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useEffect, useReducer, useState } from 'react'
|
|
2
2
|
import type { EthagentConfig, EthagentIdentity } from '../../storage/config.js'
|
|
3
|
-
import { defaultModelFor } from '../../storage/config.js'
|
|
4
3
|
import { setTokenIdentity } from '../../storage/identity.js'
|
|
5
4
|
import type { BrowserWalletReady } from '../wallet/browserWallet.js'
|
|
6
5
|
import { registryConfigFromConfig } from '../registry/registryConfig.js'
|
|
@@ -26,11 +25,11 @@ import type {
|
|
|
26
25
|
} from './shared/effects/types.js'
|
|
27
26
|
import { resolveVaultAddress } from './custody/transactions.js'
|
|
28
27
|
import { useCustodyFlow } from './custody/useCustodyFlow.js'
|
|
29
|
-
import {
|
|
28
|
+
import { identityManagerErrorView } from './shared/model/errors.js'
|
|
30
29
|
import { readCustodyMode } from './custody/state.js'
|
|
31
30
|
import { selectEnsStatus } from './ens/state.js'
|
|
32
|
-
import {
|
|
33
|
-
import type {
|
|
31
|
+
import { identityManagerReducer, type ProfileUpdates, type Step } from './reducer.js'
|
|
32
|
+
import type { IdentityManagerProps } from './types.js'
|
|
34
33
|
import {
|
|
35
34
|
capitalizeFeedbackMessage,
|
|
36
35
|
initialStepForAction,
|
|
@@ -40,20 +39,20 @@ import {
|
|
|
40
39
|
preflightTokenOwnership,
|
|
41
40
|
useAgentReconciliation,
|
|
42
41
|
} from './shared/reconciliation/index.js'
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
42
|
+
import { useIdentityManagerContinuity } from './useContinuity.js'
|
|
43
|
+
import { useIdentityManagerSideEffects } from './useSideEffects.js'
|
|
45
44
|
|
|
46
|
-
export function
|
|
45
|
+
export function useIdentityManagerController({
|
|
47
46
|
mode,
|
|
48
47
|
config,
|
|
49
48
|
initialAction,
|
|
50
49
|
onComplete,
|
|
51
50
|
onConfigChange,
|
|
52
|
-
}:
|
|
51
|
+
}: IdentityManagerProps) {
|
|
53
52
|
const [firstRunIdentity, setFirstRunIdentity] = useState<EthagentIdentity | null>(null)
|
|
54
53
|
const identity = config?.identity ?? firstRunIdentity ?? undefined
|
|
55
54
|
const { reconciliation, refresh: refreshReconciliation } = useAgentReconciliation(config ?? null)
|
|
56
|
-
const [step, dispatch] = useReducer(
|
|
55
|
+
const [step, dispatch] = useReducer(identityManagerReducer, initialStepForAction(initialAction, config))
|
|
57
56
|
const [walletSession, setWalletSession] = useState<BrowserWalletReady | null>(null)
|
|
58
57
|
const [restoreProgress, setRestoreProgress] = useState<RestoreProgress | null>(null)
|
|
59
58
|
const [tokenTransferProgress, setTokenTransferProgress] = useState<TokenTransferProgress | null>(null)
|
|
@@ -63,7 +62,7 @@ export function useIdentityHubController({
|
|
|
63
62
|
|
|
64
63
|
const setStep = (s: Step) => dispatch({ type: 'setStep', step: s })
|
|
65
64
|
const back = () => dispatch({ type: 'back', from: step })
|
|
66
|
-
const
|
|
65
|
+
const closeManager = () => onComplete({ kind: 'cancel' })
|
|
67
66
|
|
|
68
67
|
useEffect(() => { setWalletSession(null) }, [step.kind])
|
|
69
68
|
useEffect(() => {
|
|
@@ -114,21 +113,24 @@ export function useIdentityHubController({
|
|
|
114
113
|
const registry = registryFromIdentity(nextIdentity)
|
|
115
114
|
const custodyMode = readCustodyMode(nextIdentity.state)
|
|
116
115
|
|
|
116
|
+
const seedConfig: EthagentConfig = {
|
|
117
|
+
version: 2,
|
|
118
|
+
firstSeenAt: new Date().toISOString(),
|
|
119
|
+
identity: { ...nextIdentity, source: 'erc8004' },
|
|
120
|
+
...(registry
|
|
121
|
+
? {
|
|
122
|
+
erc8004: {
|
|
123
|
+
chainId: registry.chainId,
|
|
124
|
+
rpcUrl: registry.rpcUrl,
|
|
125
|
+
identityRegistryAddress: registry.identityRegistryAddress,
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
: {}),
|
|
129
|
+
}
|
|
130
|
+
const persisted = await setTokenIdentity(seedConfig, nextIdentity)
|
|
131
|
+
onConfigChange?.(persisted)
|
|
132
|
+
|
|
117
133
|
if (source === 'create' && custodyMode === 'advanced' && registry) {
|
|
118
|
-
const seedConfig: EthagentConfig = {
|
|
119
|
-
version: 1,
|
|
120
|
-
provider: 'llamacpp',
|
|
121
|
-
model: defaultModelFor('llamacpp'),
|
|
122
|
-
firstRunAt: new Date().toISOString(),
|
|
123
|
-
identity: { ...nextIdentity, source: 'erc8004' },
|
|
124
|
-
erc8004: {
|
|
125
|
-
chainId: registry.chainId,
|
|
126
|
-
rpcUrl: registry.rpcUrl,
|
|
127
|
-
identityRegistryAddress: registry.identityRegistryAddress,
|
|
128
|
-
},
|
|
129
|
-
}
|
|
130
|
-
const persisted = await setTokenIdentity(seedConfig, nextIdentity)
|
|
131
|
-
onConfigChange?.(persisted)
|
|
132
134
|
const ownerAddress = (nextIdentity.ownerAddress ?? nextIdentity.address) as `0x${string}`
|
|
133
135
|
const profileUpdates: ProfileUpdates = {
|
|
134
136
|
custodyMode: 'advanced',
|
|
@@ -148,10 +150,10 @@ export function useIdentityHubController({
|
|
|
148
150
|
|
|
149
151
|
const ensStatus = selectEnsStatus(nextIdentity)
|
|
150
152
|
if (registry && ensStatus.kind === 'none') {
|
|
151
|
-
setStep({ kind: 'first-run-ens-prompt', identity: nextIdentity, registry })
|
|
153
|
+
setStep({ kind: 'first-run-ens-prompt', identity: nextIdentity, registry, origin: source === 'restore' ? 'restore' : 'create' })
|
|
152
154
|
return
|
|
153
155
|
}
|
|
154
|
-
|
|
156
|
+
setStep({ kind: 'menu' })
|
|
155
157
|
return
|
|
156
158
|
}
|
|
157
159
|
const nextConfig = await setTokenIdentity(config, nextIdentity)
|
|
@@ -184,7 +186,8 @@ export function useIdentityHubController({
|
|
|
184
186
|
return
|
|
185
187
|
}
|
|
186
188
|
}
|
|
187
|
-
|
|
189
|
+
onConfigChange?.(nextConfig)
|
|
190
|
+
setStep({ kind: 'operation-complete', message: capitalizeFeedbackMessage(message) })
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
const callbacks: EffectCallbacks = {
|
|
@@ -200,7 +203,7 @@ export function useIdentityHubController({
|
|
|
200
203
|
setStep(softCancel)
|
|
201
204
|
return
|
|
202
205
|
}
|
|
203
|
-
setStep({ kind: 'error', error:
|
|
206
|
+
setStep({ kind: 'error', error: identityManagerErrorView(err), back: backStep })
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
const guardOwnership = async (
|
|
@@ -290,14 +293,14 @@ export function useIdentityHubController({
|
|
|
290
293
|
...(onConfigChange ? { onConfigChange } : {}),
|
|
291
294
|
})
|
|
292
295
|
|
|
293
|
-
const continuity =
|
|
296
|
+
const continuity = useIdentityManagerContinuity({
|
|
294
297
|
identity,
|
|
295
298
|
step,
|
|
296
299
|
setStep,
|
|
297
300
|
handleStepError,
|
|
298
301
|
})
|
|
299
302
|
|
|
300
|
-
|
|
303
|
+
useIdentityManagerSideEffects({
|
|
301
304
|
step,
|
|
302
305
|
config,
|
|
303
306
|
callbacks,
|
|
@@ -310,10 +313,10 @@ export function useIdentityHubController({
|
|
|
310
313
|
|
|
311
314
|
const finishFirstRunIdentity = (): void => {
|
|
312
315
|
if (!firstRunIdentity) {
|
|
313
|
-
onComplete({ kind: '
|
|
316
|
+
onComplete({ kind: 'cancel' })
|
|
314
317
|
return
|
|
315
318
|
}
|
|
316
|
-
|
|
319
|
+
setStep({ kind: 'menu' })
|
|
317
320
|
}
|
|
318
321
|
|
|
319
322
|
const openEnsEdit = (backStep: Step): void => {
|
|
@@ -337,7 +340,7 @@ export function useIdentityHubController({
|
|
|
337
340
|
handleStepError(new Error('no agent registry configured for this identity'), backStep)
|
|
338
341
|
return
|
|
339
342
|
}
|
|
340
|
-
setStep({ kind: 'edit-profile-
|
|
343
|
+
setStep({ kind: 'edit-profile-menu', identity, registry, returnTo: backStep })
|
|
341
344
|
}
|
|
342
345
|
|
|
343
346
|
const openTokenTransferFlow = async (): Promise<void> => {
|
|
@@ -385,7 +388,7 @@ export function useIdentityHubController({
|
|
|
385
388
|
workingStatus: continuity.workingStatus,
|
|
386
389
|
setStep,
|
|
387
390
|
back,
|
|
388
|
-
|
|
391
|
+
closeManager,
|
|
389
392
|
setWalletSession,
|
|
390
393
|
setJwtSaved,
|
|
391
394
|
setCopyNotice,
|
|
@@ -406,4 +409,4 @@ export function useIdentityHubController({
|
|
|
406
409
|
}
|
|
407
410
|
}
|
|
408
411
|
|
|
409
|
-
export type
|
|
412
|
+
export type IdentityManagerController = ReturnType<typeof useIdentityManagerController>
|
|
@@ -2,11 +2,12 @@ import { useEffect } from 'react'
|
|
|
2
2
|
import type { EthagentConfig } from '../../storage/config.js'
|
|
3
3
|
import { setTokenIdentity } from '../../storage/identity.js'
|
|
4
4
|
import { isRegistrationPreflightError, pinataErrorText } from './shared/model/errors.js'
|
|
5
|
-
import type { ProfileUpdates, Step } from './
|
|
5
|
+
import type { ProfileUpdates, Step } from './reducer.js'
|
|
6
6
|
import {
|
|
7
7
|
runCreatePreflight,
|
|
8
8
|
runCreateSigning,
|
|
9
9
|
} from './create/effects.js'
|
|
10
|
+
import { scanImportCandidates } from './create/importScan.js'
|
|
10
11
|
import {
|
|
11
12
|
runRebackupSigning,
|
|
12
13
|
} from './continuity/effects.js'
|
|
@@ -36,7 +37,7 @@ type TriggerRebackup = (
|
|
|
36
37
|
options?: { vaultAddress?: `0x${string}`; useVault?: boolean },
|
|
37
38
|
) => void
|
|
38
39
|
|
|
39
|
-
type
|
|
40
|
+
type UseIdentityManagerSideEffectsArgs = {
|
|
40
41
|
step: Step
|
|
41
42
|
config: EthagentConfig | undefined
|
|
42
43
|
callbacks: EffectCallbacks
|
|
@@ -47,7 +48,7 @@ type UseIdentityHubSideEffectsArgs = {
|
|
|
47
48
|
onConfigChange?: (config: EthagentConfig) => void
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
export function
|
|
51
|
+
export function useIdentityManagerSideEffects({
|
|
51
52
|
step,
|
|
52
53
|
config,
|
|
53
54
|
callbacks,
|
|
@@ -56,12 +57,45 @@ export function useIdentityHubSideEffects({
|
|
|
56
57
|
triggerRebackup,
|
|
57
58
|
setContinuityReady,
|
|
58
59
|
onConfigChange,
|
|
59
|
-
}:
|
|
60
|
+
}: UseIdentityManagerSideEffectsArgs): void {
|
|
60
61
|
useEffect(() => {
|
|
61
62
|
if (step.kind !== 'rebackup-start') return
|
|
62
63
|
triggerRebackup(step.back)
|
|
63
64
|
}, [step])
|
|
64
65
|
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (step.kind !== 'create-import') return
|
|
68
|
+
if (step.candidates !== undefined) return
|
|
69
|
+
let cancelled = false
|
|
70
|
+
const toPreflight: Step = {
|
|
71
|
+
kind: 'create-preflight',
|
|
72
|
+
name: step.name,
|
|
73
|
+
description: step.description,
|
|
74
|
+
...(step.network ? { network: step.network } : {}),
|
|
75
|
+
custodyMode: step.custodyMode,
|
|
76
|
+
}
|
|
77
|
+
scanImportCandidates()
|
|
78
|
+
.then(candidates => {
|
|
79
|
+
if (cancelled) return
|
|
80
|
+
if (candidates.length === 0) {
|
|
81
|
+
setStep(toPreflight)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
setStep({
|
|
85
|
+
kind: 'create-import',
|
|
86
|
+
name: step.name,
|
|
87
|
+
description: step.description,
|
|
88
|
+
...(step.network ? { network: step.network } : {}),
|
|
89
|
+
custodyMode: step.custodyMode,
|
|
90
|
+
candidates,
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
.catch(() => {
|
|
94
|
+
if (!cancelled) setStep(toPreflight)
|
|
95
|
+
})
|
|
96
|
+
return () => { cancelled = true }
|
|
97
|
+
}, [step])
|
|
98
|
+
|
|
65
99
|
useEffect(() => {
|
|
66
100
|
if (step.kind !== 'create-preflight') return
|
|
67
101
|
let cancelled = false
|
|
@@ -94,6 +128,7 @@ export function useIdentityHubSideEffects({
|
|
|
94
128
|
custodyMode: step.custodyMode,
|
|
95
129
|
error: pinataErrorText(err),
|
|
96
130
|
pinataJwt: step.pinataJwt,
|
|
131
|
+
...(step.importNotes ? { importNotes: step.importNotes } : {}),
|
|
97
132
|
})
|
|
98
133
|
return
|
|
99
134
|
}
|
|
@@ -120,6 +155,7 @@ export function useIdentityHubSideEffects({
|
|
|
120
155
|
profileUpdates: step.profileUpdates,
|
|
121
156
|
returnTo: step.returnTo,
|
|
122
157
|
walletPurpose: step.walletPurpose,
|
|
158
|
+
...(step.vaultAddress ? { vaultAddress: step.vaultAddress } : {}),
|
|
123
159
|
})
|
|
124
160
|
return
|
|
125
161
|
}
|
|
@@ -5,7 +5,10 @@ import { isAgentInVault } from '../vault.js'
|
|
|
5
5
|
import { ERC8004_ABI, TRANSFER_EVENT } from './abi.js'
|
|
6
6
|
import {
|
|
7
7
|
SUPPORTED_ERC8004_CHAINS,
|
|
8
|
+
chainSortIndex,
|
|
8
9
|
erc8004ConfigForSupportedChain,
|
|
10
|
+
logBlockRangeForChain,
|
|
11
|
+
minLogBlockRangeForChain,
|
|
9
12
|
supportedErc8004ChainForId,
|
|
10
13
|
} from './chains.js'
|
|
11
14
|
import { createErc8004PublicClient } from './client.js'
|
|
@@ -492,20 +495,3 @@ function blockRangesBackwards(
|
|
|
492
495
|
}
|
|
493
496
|
return ranges
|
|
494
497
|
}
|
|
495
|
-
|
|
496
|
-
function logBlockRangeForChain(chainId: number): bigint {
|
|
497
|
-
const chain = supportedErc8004ChainForId(chainId)
|
|
498
|
-
if (!chain) return 10_000n
|
|
499
|
-
return chain.logBlockRange
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function minLogBlockRangeForChain(chainId: number): bigint {
|
|
503
|
-
const chain = supportedErc8004ChainForId(chainId)
|
|
504
|
-
if (!chain) return 2_000n
|
|
505
|
-
return chain.kind === 'l2' ? chain.logBlockRange : chain.logBlockRange / 2n || 1n
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function chainSortIndex(chainId: number): number {
|
|
509
|
-
const index = SUPPORTED_ERC8004_CHAINS.findIndex(chain => chain.chainId === chainId)
|
|
510
|
-
return index === -1 ? Number.MAX_SAFE_INTEGER : index
|
|
511
|
-
}
|
|
@@ -12,7 +12,7 @@ export function uniqueStrings(values: string[]): string[] {
|
|
|
12
12
|
export function cleanRpcError(err: unknown): string {
|
|
13
13
|
const message = err instanceof Error ? err.message : String(err)
|
|
14
14
|
return message
|
|
15
|
-
.replace(
|
|
15
|
+
.replace(/\s+/g, ' ')
|
|
16
16
|
.slice(0, 220)
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -15,6 +15,26 @@ type IpfsOptions = {
|
|
|
15
15
|
pinataJwt?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export class PinataUploadError extends Error {
|
|
19
|
+
readonly status: number
|
|
20
|
+
readonly statusText: string
|
|
21
|
+
constructor(status: number, statusText: string) {
|
|
22
|
+
super(pinataUploadErrorMessage(status, statusText))
|
|
23
|
+
this.name = 'PinataUploadError'
|
|
24
|
+
this.status = status
|
|
25
|
+
this.statusText = statusText
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function pinataUploadErrorMessage(status: number, statusText: string): string {
|
|
30
|
+
const code = statusText ? `${status} ${statusText}` : String(status)
|
|
31
|
+
if (status === 401) return `Pinata rejected the upload (${code}): the storage credential is invalid or expired.`
|
|
32
|
+
if (status === 403) return `Pinata refused the upload (${code}): your account is likely at its file or storage limit.`
|
|
33
|
+
if (status === 429) return `Pinata is rate-limiting uploads (${code}): too many requests in a short window.`
|
|
34
|
+
if (status === 413) return `Pinata rejected the upload (${code}): the snapshot is larger than your plan allows.`
|
|
35
|
+
return `IPFS upload failed: ${code}.`
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
export function extractPinataJwt(input: string): string {
|
|
19
39
|
const trimmed = input.trim()
|
|
20
40
|
const matches = trimmed.match(/\b[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g) ?? []
|
|
@@ -142,7 +162,7 @@ async function addFileToPinata(
|
|
|
142
162
|
},
|
|
143
163
|
body,
|
|
144
164
|
})
|
|
145
|
-
if (!response.ok) throw new
|
|
165
|
+
if (!response.ok) throw new PinataUploadError(response.status, response.statusText)
|
|
146
166
|
const data = await response.json() as { data?: { cid?: string }; IpfsHash?: string; Hash?: string; Cid?: string }
|
|
147
167
|
const cid = data.data?.cid ?? data.IpfsHash ?? data.Hash ?? data.Cid
|
|
148
168
|
if (!cid) throw new Error('IPFS upload response did not include a CID')
|
|
@@ -4,14 +4,22 @@ import { loadWalletPageSource } from './walletPageSource.js'
|
|
|
4
4
|
|
|
5
5
|
const WALLET_HTML = loadWalletHtml()
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
function injectWalletConfig(shell: string, title: string, sessionToken: string, payload: Record<string, unknown>): string {
|
|
8
8
|
const config = JSON.stringify({ sessionToken, ...normalizeWalletPayloadPurpose(payload) }).replaceAll('<', '\\u003c')
|
|
9
9
|
const injection = `<script>window.__WALLET_CONFIG__ = ${config};</script>`
|
|
10
|
-
return
|
|
10
|
+
return shell
|
|
11
11
|
.replace(/<title>.*?<\/title>/, `<title>${escapeHtml(title)}</title>`)
|
|
12
12
|
.replace('<head>', `<head>\n ${injection}`)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export function walletPage(title: string, sessionToken: string, payload: Record<string, unknown>): string {
|
|
16
|
+
return injectWalletConfig(WALLET_HTML, title, sessionToken, payload)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function walletPageFresh(title: string, sessionToken: string, payload: Record<string, unknown>): string {
|
|
20
|
+
return injectWalletConfig(loadWalletHtml(), title, sessionToken, payload)
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
export function __testWalletPage(title: string, sessionToken: string, payload: Record<string, unknown>): string {
|
|
16
24
|
return walletPage(title, sessionToken, payload)
|
|
17
25
|
}
|