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
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
type WalletContinuitySnapshotSlot,
|
|
37
37
|
} from './envelopeTypes.js'
|
|
38
38
|
|
|
39
|
+
const MAX_WALLET_RESTORE_SLOTS = 256
|
|
40
|
+
|
|
39
41
|
export function restoreContinuitySnapshotEnvelope(args: {
|
|
40
42
|
envelope: ContinuitySnapshotEnvelope
|
|
41
43
|
walletSignature: string
|
|
@@ -232,7 +234,7 @@ function restoreTransferContinuitySnapshotEnvelope(args: {
|
|
|
232
234
|
}): ContinuitySnapshotPayload {
|
|
233
235
|
const currentAddress = args.currentOwnerAddress
|
|
234
236
|
? toChecksumAddress(args.currentOwnerAddress)
|
|
235
|
-
:
|
|
237
|
+
: recoverTransferSlotAddress(args.envelope, args.walletSignature)
|
|
236
238
|
const slot = transferSlotForCurrentOwner(args.envelope, currentAddress)
|
|
237
239
|
assertSignatureForAddress(slot.challenge, args.walletSignature, slot.address)
|
|
238
240
|
|
|
@@ -348,6 +350,20 @@ function walletSlotForRestore(
|
|
|
348
350
|
throw new ContinuitySnapshotRestoreSlotMissingError('unknown')
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
function recoverTransferSlotAddress(
|
|
354
|
+
envelope: TransferContinuitySnapshotEnvelope,
|
|
355
|
+
walletSignature: string,
|
|
356
|
+
): string {
|
|
357
|
+
for (const slot of [envelope.slots.owner, envelope.slots.target]) {
|
|
358
|
+
try {
|
|
359
|
+
const recovered = recoverAddressFromSignature(slot.challenge, walletSignature)
|
|
360
|
+
if (recovered.toLowerCase() === slot.address.toLowerCase()) return toChecksumAddress(slot.address)
|
|
361
|
+
} catch {
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
throw new ContinuityTransferSnapshotTargetMismatchError(envelope.ownerAddress, envelope.targetAddress, 'unknown')
|
|
365
|
+
}
|
|
366
|
+
|
|
351
367
|
function transferSlotForCurrentOwner(
|
|
352
368
|
envelope: TransferContinuitySnapshotEnvelope,
|
|
353
369
|
currentOwner: string,
|
|
@@ -368,6 +384,9 @@ export function normalizeContinuitySnapshotEnvelope(input: unknown): ContinuityS
|
|
|
368
384
|
}
|
|
369
385
|
const ownerAddress = toChecksumAddress(input.ownerAddress)
|
|
370
386
|
const token = normalizeContinuitySnapshotToken(input.token)
|
|
387
|
+
if (input.slots.length > MAX_WALLET_RESTORE_SLOTS) {
|
|
388
|
+
throw new Error('Continuity wallet snapshot has too many restore slots')
|
|
389
|
+
}
|
|
371
390
|
const slots = input.slots.map(normalizeWalletSlot)
|
|
372
391
|
if (slots.length === 0) throw new Error('Continuity wallet snapshot needs at least one slot')
|
|
373
392
|
return {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { EthagentIdentity } from '../../storage/config.js'
|
|
2
2
|
import type { SkillIndexEntry } from './skills/types.js'
|
|
3
|
-
import { identityOwnerAddress } from '../
|
|
3
|
+
import { identityOwnerAddress } from '../manager/custody/state.js'
|
|
4
4
|
import { toChecksumAddress } from '../crypto/eth.js'
|
|
5
|
+
import { isDraftScaffold } from './skills/scaffold.js'
|
|
5
6
|
|
|
6
7
|
type PublicSkill = {
|
|
7
8
|
id: string
|
|
@@ -82,6 +83,7 @@ export function appendPublicSkillEntries(
|
|
|
82
83
|
const usedIds = new Set(baselineIds)
|
|
83
84
|
for (const entry of entries) {
|
|
84
85
|
if (entry.visibility !== 'public') continue
|
|
86
|
+
if (isDraftScaffold(entry)) continue
|
|
85
87
|
const id = uniqueSkillId(entry.name, usedIds)
|
|
86
88
|
usedIds.add(id)
|
|
87
89
|
appended.push({
|
|
@@ -8,11 +8,12 @@ import {
|
|
|
8
8
|
} from '../publicSkills.js'
|
|
9
9
|
import { ensureContinuityVault, ensureTrailingNewline, readOrDefault } from '../storage/files.js'
|
|
10
10
|
import { listSkills } from './loadSkills.js'
|
|
11
|
+
import { isDraftScaffold } from './scaffold.js'
|
|
11
12
|
import type { SkillIndexEntry } from './types.js'
|
|
12
13
|
|
|
13
14
|
export async function derivePublicSkillEntries(identity: EthagentIdentity): Promise<SkillIndexEntry[]> {
|
|
14
15
|
const entries = await listSkills(identity)
|
|
15
|
-
return entries.filter(entry => entry.visibility === 'public')
|
|
16
|
+
return entries.filter(entry => entry.visibility === 'public' && !isDraftScaffold(entry))
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export async function renderAgentCardJsonForIdentity(identity: EthagentIdentity): Promise<string> {
|
|
@@ -9,13 +9,13 @@ export function defaultSkillScaffold({ name, visibility = 'public' }: SkillScaff
|
|
|
9
9
|
return [
|
|
10
10
|
'---',
|
|
11
11
|
`name: ${name}`,
|
|
12
|
-
'description:',
|
|
12
|
+
'description: <one-line public description before publishing>',
|
|
13
13
|
`visibility: ${visibility}`,
|
|
14
14
|
'---',
|
|
15
15
|
'',
|
|
16
16
|
'# Overview',
|
|
17
17
|
'',
|
|
18
|
-
'
|
|
18
|
+
'Replace this draft with one or two sentences describing what this skill does and the problem it solves.',
|
|
19
19
|
'',
|
|
20
20
|
'# When to use',
|
|
21
21
|
'',
|
|
@@ -48,5 +48,8 @@ export function isDraftScaffold(entry: { description: string; name: string }): b
|
|
|
48
48
|
if (desc.length === 0) return true
|
|
49
49
|
if (/^<.*>$/.test(desc)) return true
|
|
50
50
|
if (desc === entry.name) return true
|
|
51
|
+
if (/^overview$/i.test(desc)) return true
|
|
52
|
+
if (/^describe in one or two sentences/i.test(desc)) return true
|
|
53
|
+
if (/^replace this draft/i.test(desc)) return true
|
|
51
54
|
return false
|
|
52
55
|
}
|
|
@@ -82,7 +82,7 @@ export async function updatePublishedContinuitySnapshotContentHashes(
|
|
|
82
82
|
): Promise<void> {
|
|
83
83
|
await ensureContinuityVault(identity)
|
|
84
84
|
const current = currentPublishedSnapshot(identity)
|
|
85
|
-
const snapshots = await
|
|
85
|
+
const { snapshots, unparsable } = await readPublishedContinuitySnapshotLines(identity)
|
|
86
86
|
const index = snapshots.findIndex(item => item.cid === cid)
|
|
87
87
|
if (index === -1) {
|
|
88
88
|
const base = current.find(item => item.cid === cid)
|
|
@@ -93,7 +93,7 @@ export async function updatePublishedContinuitySnapshotContentHashes(
|
|
|
93
93
|
}
|
|
94
94
|
await atomicWriteText(
|
|
95
95
|
publishedContinuitySnapshotsPath(identity),
|
|
96
|
-
snapshots.map(snapshot => JSON.stringify(snapshot)).join('\n') + '\n',
|
|
96
|
+
[...snapshots.map(snapshot => JSON.stringify(snapshot)), ...unparsable].join('\n') + '\n',
|
|
97
97
|
{ mode: 0o600 },
|
|
98
98
|
)
|
|
99
99
|
}
|
|
@@ -143,25 +143,32 @@ function refreshPublishedSnapshotSidecars(
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
async function readPublishedContinuitySnapshotFile(identity: EthagentIdentity): Promise<PublishedContinuitySnapshot[]> {
|
|
146
|
+
return (await readPublishedContinuitySnapshotLines(identity)).snapshots
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function readPublishedContinuitySnapshotLines(
|
|
150
|
+
identity: EthagentIdentity,
|
|
151
|
+
): Promise<{ snapshots: PublishedContinuitySnapshot[]; unparsable: string[] }> {
|
|
146
152
|
let raw: string
|
|
147
153
|
try {
|
|
148
154
|
raw = await fs.readFile(publishedContinuitySnapshotsPath(identity), 'utf8')
|
|
149
155
|
} catch (error: unknown) {
|
|
150
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return []
|
|
156
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { snapshots: [], unparsable: [] }
|
|
151
157
|
throw error
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
const snapshots: PublishedContinuitySnapshot[] = []
|
|
161
|
+
const unparsable: string[] = []
|
|
155
162
|
for (const line of raw.split('\n')) {
|
|
156
163
|
const trimmed = line.trim()
|
|
157
164
|
if (!trimmed) continue
|
|
158
165
|
try {
|
|
159
166
|
snapshots.push(JSON.parse(trimmed) as PublishedContinuitySnapshot)
|
|
160
167
|
} catch {
|
|
161
|
-
|
|
168
|
+
unparsable.push(trimmed)
|
|
162
169
|
}
|
|
163
170
|
}
|
|
164
|
-
return snapshots
|
|
171
|
+
return { snapshots, unparsable }
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
function currentPublishedSnapshot(identity: EthagentIdentity): PublishedContinuitySnapshot[] {
|
|
@@ -32,27 +32,27 @@ export function defaultContinuityFiles(identity: EthagentIdentity, _now = new Da
|
|
|
32
32
|
'',
|
|
33
33
|
'## Persona',
|
|
34
34
|
'',
|
|
35
|
-
'
|
|
35
|
+
'Stable identity, voice, and collaboration defaults this agent carries across sessions and models. Replace these prompts with durable instructions.',
|
|
36
36
|
'',
|
|
37
|
-
'-
|
|
38
|
-
'-
|
|
39
|
-
'-
|
|
37
|
+
'- Role: what this agent is and the kind of work it should be trusted with.',
|
|
38
|
+
'- Voice: how it should sound when helping you.',
|
|
39
|
+
'- Collaboration style: how it should plan, ask questions, and present tradeoffs.',
|
|
40
40
|
'',
|
|
41
41
|
'## Principles',
|
|
42
42
|
'',
|
|
43
|
-
'Owner-approved
|
|
43
|
+
'Owner-approved defaults for repeated decisions. Keep these durable, specific, and easy to apply.',
|
|
44
44
|
'',
|
|
45
|
-
'-
|
|
46
|
-
'-
|
|
47
|
-
'-
|
|
45
|
+
'- Decision rule: how the agent should choose when there are tradeoffs.',
|
|
46
|
+
'- Engineering standard: what quality bar it should preserve.',
|
|
47
|
+
'- Escalation rule: when it should stop and ask.',
|
|
48
48
|
'',
|
|
49
49
|
'## Boundaries',
|
|
50
50
|
'',
|
|
51
|
-
'
|
|
51
|
+
'Private limits and hard constraints. These override task-level convenience.',
|
|
52
52
|
'',
|
|
53
|
-
'- <boundary: e.g., never bypass authentication or authorization checks>',
|
|
54
|
-
'- <boundary: e.g., never commit secrets to source control>',
|
|
55
53
|
'- Never store seed phrases, private keys, raw wallet signatures, or API keys.',
|
|
54
|
+
'- Ask for explicit approval before destructive operations.',
|
|
55
|
+
'- Public capabilities belong in skill folders; keep private persona and limits here.',
|
|
56
56
|
'',
|
|
57
57
|
].join('\n'),
|
|
58
58
|
'MEMORY.md': [
|
|
@@ -62,11 +62,11 @@ export function defaultContinuityFiles(identity: EthagentIdentity, _now = new Da
|
|
|
62
62
|
'',
|
|
63
63
|
'## Durable User Preferences',
|
|
64
64
|
'',
|
|
65
|
-
'Long-lived owner preferences that survive sessions and model switches.
|
|
65
|
+
'Long-lived owner preferences that survive sessions and model switches. Replace these prompts with stable facts.',
|
|
66
66
|
'',
|
|
67
|
-
'-
|
|
68
|
-
'-
|
|
69
|
-
'-
|
|
67
|
+
'- Name and aliases:',
|
|
68
|
+
'- Communication preferences:',
|
|
69
|
+
'- Tooling and workflow:',
|
|
70
70
|
'',
|
|
71
71
|
'## Project Context',
|
|
72
72
|
'',
|
|
@@ -74,14 +74,15 @@ export function defaultContinuityFiles(identity: EthagentIdentity, _now = new Da
|
|
|
74
74
|
'',
|
|
75
75
|
'### <project-name>',
|
|
76
76
|
'',
|
|
77
|
-
'- Repository:
|
|
78
|
-
'- Stack:
|
|
79
|
-
'- Conventions:
|
|
80
|
-
'- Active workstream: <YYYY-MM-DD
|
|
77
|
+
'- Repository:',
|
|
78
|
+
'- Stack:',
|
|
79
|
+
'- Conventions:',
|
|
80
|
+
'- Active workstream: <YYYY-MM-DD summary>',
|
|
81
81
|
'',
|
|
82
82
|
'## Boundaries',
|
|
83
83
|
'',
|
|
84
84
|
'Never store seed phrases, private keys, raw wallet signatures, or API keys.',
|
|
85
|
+
'Public capabilities belong in skill folders; keep private user and project facts here.',
|
|
85
86
|
'',
|
|
86
87
|
].join('\n'),
|
|
87
88
|
}
|
|
@@ -109,7 +109,7 @@ function hashContinuitySnapshotContent(value: string): string {
|
|
|
109
109
|
return createHash('sha256').update(normalizeSnapshotContent(value), 'utf8').digest('hex')
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
function normalizeSnapshotContent(value: string): string {
|
|
112
|
+
export function normalizeSnapshotContent(value: string): string {
|
|
113
113
|
const normalized = value.replace(/\r\n?/g, '\n')
|
|
114
114
|
return normalized.endsWith('\n') ? normalized : `${normalized}\n`
|
|
115
115
|
}
|
|
@@ -11,7 +11,7 @@ export const ENS_RPC_URLS = [
|
|
|
11
11
|
'https://rpc.ankr.com/eth',
|
|
12
12
|
] as const
|
|
13
13
|
|
|
14
|
-
export const ETH_NAME_PATTERN = /^([a-z0-9-]
|
|
14
|
+
export const ETH_NAME_PATTERN = /^([a-z0-9-]+\.)+eth$/i
|
|
15
15
|
|
|
16
16
|
export const ENS_REGISTRY_ABI = parseAbi([
|
|
17
17
|
'function owner(bytes32 node) view returns (address)',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import { Box, useStdout } from 'ink'
|
|
3
|
+
import { IdentityManagerRoutes } from './Routes.js'
|
|
4
|
+
import type { IdentityManagerProps } from './types.js'
|
|
5
|
+
import { useIdentityManagerController } from './useController.js'
|
|
6
|
+
import { Wordmark } from './shared/components/Wordmark.js'
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
IdentityManagerInitialAction,
|
|
10
|
+
IdentityManagerResult,
|
|
11
|
+
} from './types.js'
|
|
12
|
+
|
|
13
|
+
export const IdentityManager: React.FC<IdentityManagerProps> = props => {
|
|
14
|
+
const controller = useIdentityManagerController(props)
|
|
15
|
+
const { stdout } = useStdout()
|
|
16
|
+
const [rows, setRows] = useState<number>(stdout?.rows ?? 24)
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!stdout) return
|
|
20
|
+
const onResize = () => setRows(stdout.rows ?? 24)
|
|
21
|
+
stdout.on('resize', onResize)
|
|
22
|
+
return () => { stdout.off('resize', onResize) }
|
|
23
|
+
}, [stdout])
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Box flexDirection="column" alignItems="center" justifyContent="center" width="100%" minHeight={rows}>
|
|
27
|
+
<Wordmark />
|
|
28
|
+
<Box flexDirection="column" marginTop={1} width="100%">
|
|
29
|
+
<IdentityManagerRoutes controller={controller} />
|
|
30
|
+
</Box>
|
|
31
|
+
</Box>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { hasPendingPublish } from './continuity/state.js'
|
|
3
|
-
import type { ProfileUpdates } from './
|
|
3
|
+
import type { ProfileUpdates } from './reducer.js'
|
|
4
4
|
import { clearPinataJwt, savePinataJwt } from '../storage/pinataJwt.js'
|
|
5
5
|
import {
|
|
6
6
|
runRebackupStorageSubmit,
|
|
@@ -26,6 +26,7 @@ import { DeleteSkillConfirmScreen } from './continuity/skills/DeleteSkillConfirm
|
|
|
26
26
|
import { RecoveryConfirmScreen } from './continuity/RecoveryConfirmScreen.js'
|
|
27
27
|
import { SavePromptScreen } from './continuity/SavePromptScreen.js'
|
|
28
28
|
import { ErrorScreen } from './shared/components/ErrorScreen.js'
|
|
29
|
+
import { OperationCompleteScreen } from './shared/components/OperationCompleteScreen.js'
|
|
29
30
|
import { UnlinkedIdentityScreen } from './shared/components/UnlinkedIdentityScreen.js'
|
|
30
31
|
import { invalidateOwnershipCache } from './shared/reconciliation/index.js'
|
|
31
32
|
import {
|
|
@@ -34,19 +35,18 @@ import {
|
|
|
34
35
|
} from './ens/EnsFlow.js'
|
|
35
36
|
import { CustodyEditFlow, isCustodyEditStep } from './custody/CustodyEditFlow.js'
|
|
36
37
|
import { rebackupWalletApprovalView } from './shared/utils.js'
|
|
37
|
-
import type {
|
|
38
|
+
import type { IdentityManagerController } from './useController.js'
|
|
38
39
|
|
|
39
|
-
type
|
|
40
|
-
controller:
|
|
40
|
+
type IdentityManagerOperationalRoutesProps = {
|
|
41
|
+
controller: IdentityManagerController
|
|
41
42
|
footer: React.ReactNode
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
export const
|
|
45
|
+
export const IdentityManagerOperationalRoutes: React.FC<IdentityManagerOperationalRoutesProps> = ({
|
|
45
46
|
controller,
|
|
46
47
|
footer,
|
|
47
48
|
}) => {
|
|
48
49
|
const {
|
|
49
|
-
mode,
|
|
50
50
|
config,
|
|
51
51
|
onComplete,
|
|
52
52
|
identity,
|
|
@@ -61,7 +61,7 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
61
61
|
workingStatus,
|
|
62
62
|
setStep,
|
|
63
63
|
back,
|
|
64
|
-
|
|
64
|
+
closeManager,
|
|
65
65
|
setWalletSession,
|
|
66
66
|
setJwtSaved,
|
|
67
67
|
setCopyNotice,
|
|
@@ -133,14 +133,35 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
133
133
|
return (
|
|
134
134
|
<WalletApprovalScreen
|
|
135
135
|
title="Refetch Latest Snapshot"
|
|
136
|
-
subtitle="
|
|
136
|
+
subtitle="Decrypts and restores SOUL.md, MEMORY.md, and skills."
|
|
137
137
|
walletSession={walletSession}
|
|
138
|
-
label={restoreProgress?.label ?? '
|
|
138
|
+
label={restoreProgress?.label ?? (walletSession ? 'waiting for your signature...' : 'fetching snapshot...')}
|
|
139
139
|
onCancel={() => setStep(step.back)}
|
|
140
140
|
/>
|
|
141
141
|
)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
if (step.kind === 'continuity-overwrite-confirm') {
|
|
145
|
+
return (
|
|
146
|
+
<RecoveryConfirmScreen
|
|
147
|
+
mode="restore"
|
|
148
|
+
workingStatus={workingStatus}
|
|
149
|
+
footer={footer}
|
|
150
|
+
onConfirm={() => setStep(step.next)}
|
|
151
|
+
onBack={() => setStep(step.back)}
|
|
152
|
+
/>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (step.kind === 'operation-complete') {
|
|
157
|
+
return (
|
|
158
|
+
<OperationCompleteScreen
|
|
159
|
+
message={step.message}
|
|
160
|
+
onReturn={() => setStep({ kind: 'menu' })}
|
|
161
|
+
/>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
144
165
|
if (step.kind === 'continuity-private') {
|
|
145
166
|
return (
|
|
146
167
|
<PrivateContinuityScreen
|
|
@@ -281,6 +302,7 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
281
302
|
onWalletReady={setWalletSession}
|
|
282
303
|
onTriggerRebackup={triggerRebackup}
|
|
283
304
|
onTriggerPublicProfileSave={triggerPublicProfileSave}
|
|
305
|
+
onWithdrawFromVault={s => custodyFlow.beginWithdrawToken(s, s, 'ens')}
|
|
284
306
|
/>
|
|
285
307
|
)
|
|
286
308
|
}
|
|
@@ -299,8 +321,6 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
299
321
|
onSetStep={setStep}
|
|
300
322
|
onSwitchToAdvanced={(returnTo, updates) => custodyFlow.beginVaultDeposit(step, returnTo, updates)}
|
|
301
323
|
onSwitchToSimple={(returnTo, updates) => custodyFlow.beginVaultUnwrap(step, returnTo, updates)}
|
|
302
|
-
onWithdrawToken={returnTo => custodyFlow.beginWithdrawToken(step, returnTo)}
|
|
303
|
-
onReturnToVault={(returnTo, vaultAddress) => custodyFlow.beginReturnToVault(step, returnTo, vaultAddress)}
|
|
304
324
|
onResumeAdvanced={returnTo => {
|
|
305
325
|
const vaultAddress = resolveVaultAddress(step.identity, config?.erc8004?.operatorVaults)
|
|
306
326
|
const updates: ProfileUpdates = {
|
|
@@ -340,8 +360,8 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
340
360
|
if (step.kind === 'rebackup-start') {
|
|
341
361
|
return (
|
|
342
362
|
<BusyScreen
|
|
343
|
-
title="Identity
|
|
344
|
-
label="preparing
|
|
363
|
+
title="Identity"
|
|
364
|
+
label="preparing snapshot..."
|
|
345
365
|
onCancel={back}
|
|
346
366
|
/>
|
|
347
367
|
)
|
|
@@ -385,7 +405,7 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
385
405
|
return (
|
|
386
406
|
<WalletApprovalScreen
|
|
387
407
|
title="Connect Wallet"
|
|
388
|
-
subtitle="Find agents this wallet owns
|
|
408
|
+
subtitle="Find agents this wallet owns or is linked to."
|
|
389
409
|
walletSession={walletSession}
|
|
390
410
|
label="waiting for wallet connection..."
|
|
391
411
|
onCancel={() => setStep({ kind: 'menu' })}
|
|
@@ -396,7 +416,7 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
396
416
|
if (step.kind === 'busy') {
|
|
397
417
|
return (
|
|
398
418
|
<BusyScreen
|
|
399
|
-
title="Identity
|
|
419
|
+
title="Identity"
|
|
400
420
|
label={step.label}
|
|
401
421
|
onCancel={back}
|
|
402
422
|
/>
|
|
@@ -409,10 +429,9 @@ export const IdentityHubOperationalRoutes: React.FC<IdentityHubOperationalRoutes
|
|
|
409
429
|
error={step.error}
|
|
410
430
|
back={step.back}
|
|
411
431
|
footer={footer}
|
|
412
|
-
closeLabel=
|
|
413
|
-
closeHint={mode === 'first-run' ? 'Continue First-Run Setup without an agent identity' : 'Return to chat without retrying'}
|
|
432
|
+
closeLabel="Close"
|
|
414
433
|
onBack={backStep => setStep(backStep)}
|
|
415
|
-
onClose={
|
|
434
|
+
onClose={closeManager}
|
|
416
435
|
/>
|
|
417
436
|
)
|
|
418
437
|
}
|
|
@@ -4,10 +4,10 @@ import { getAddress, isAddress } from 'viem'
|
|
|
4
4
|
import { Surface } from '../../ui/Surface.js'
|
|
5
5
|
import { Select } from '../../ui/Select.js'
|
|
6
6
|
import { theme } from '../../ui/theme.js'
|
|
7
|
-
import type { SelectableNetwork } from '../../storage/config.js'
|
|
7
|
+
import type { EthagentIdentity, SelectableNetwork } from '../../storage/config.js'
|
|
8
8
|
import { copyToClipboard } from '../../utils/clipboard.js'
|
|
9
9
|
import { DEFAULT_IPFS_API_URL } from '../storage/ipfs.js'
|
|
10
|
-
import { chainIdForNetwork, erc8004ConfigForSupportedChain } from '../registry/erc8004.js'
|
|
10
|
+
import { chainIdForNetwork, erc8004ConfigForSupportedChain, type Erc8004AgentCandidate } from '../registry/erc8004.js'
|
|
11
11
|
import { shortAddress } from './shared/model/format.js'
|
|
12
12
|
import { canRestoreCandidate } from './restore/discover.js'
|
|
13
13
|
import {
|
|
@@ -31,16 +31,16 @@ import {
|
|
|
31
31
|
isTokenTransferStep,
|
|
32
32
|
} from './transfer/TokenTransferFlow.js'
|
|
33
33
|
import {
|
|
34
|
-
chainLabel,
|
|
35
34
|
isCreateStep,
|
|
36
35
|
isRestoreStep,
|
|
37
36
|
} from './shared/utils.js'
|
|
38
|
-
import {
|
|
39
|
-
import
|
|
37
|
+
import { localChangeStatusView } from './continuity/state.js'
|
|
38
|
+
import { IdentityManagerOperationalRoutes } from './OperationalRoutes.js'
|
|
39
|
+
import type { IdentityManagerController } from './useController.js'
|
|
40
|
+
import type { Step } from './reducer.js'
|
|
40
41
|
|
|
41
|
-
export const
|
|
42
|
+
export const IdentityManagerRoutes: React.FC<{ controller: IdentityManagerController }> = ({ controller }) => {
|
|
42
43
|
const {
|
|
43
|
-
mode,
|
|
44
44
|
config,
|
|
45
45
|
onComplete,
|
|
46
46
|
onConfigChange,
|
|
@@ -56,7 +56,7 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
56
56
|
workingStatus,
|
|
57
57
|
setStep,
|
|
58
58
|
back,
|
|
59
|
-
|
|
59
|
+
closeManager,
|
|
60
60
|
setCopyNotice,
|
|
61
61
|
handleStepError,
|
|
62
62
|
resolveRegistryForIdentity,
|
|
@@ -66,30 +66,40 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
66
66
|
} = controller
|
|
67
67
|
|
|
68
68
|
const footer = <Text color={theme.dim}>enter select · esc back</Text>
|
|
69
|
+
const setRestoreFetchingStep = (next: Extract<Step, { kind: 'restore-fetching' }>, backStep: Step): void => {
|
|
70
|
+
if (
|
|
71
|
+
isSameLoadedAgent(identity, next.candidate)
|
|
72
|
+
&& localChangeStatusView(workingStatus).hasLocalChanges
|
|
73
|
+
) {
|
|
74
|
+
setStep({ kind: 'continuity-overwrite-confirm', action: 'restore', next, back: backStep })
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
setStep(next)
|
|
78
|
+
}
|
|
69
79
|
|
|
70
80
|
if (step.kind === 'first-run-ens-prompt') {
|
|
71
81
|
const tokenLabel = step.identity.agentId ? `#${step.identity.agentId}` : ''
|
|
72
82
|
return (
|
|
73
83
|
<Surface
|
|
74
|
-
title=
|
|
75
|
-
subtitle={
|
|
84
|
+
title={step.origin === 'restore' ? 'Agent Restored' : 'Token Minted'}
|
|
85
|
+
subtitle={`${tokenLabel} is live. Optional: link an ENS name.`}
|
|
76
86
|
footer={footer}
|
|
77
87
|
>
|
|
78
88
|
<Box flexDirection="column">
|
|
79
|
-
<Text color={theme.textSubtle}>An ENS
|
|
80
|
-
<Text color={theme.textSubtle}>The token
|
|
89
|
+
<Text color={theme.textSubtle}>An ENS name like agent.you.eth gives your agent a public handle.</Text>
|
|
90
|
+
<Text color={theme.textSubtle}>Optional. The token id and network already make it restorable.</Text>
|
|
81
91
|
</Box>
|
|
82
92
|
<Box marginTop={1}>
|
|
83
|
-
<Select<'ens' | '
|
|
93
|
+
<Select<'ens' | 'later'>
|
|
84
94
|
options={[
|
|
85
95
|
{ value: 'ens', role: 'section', label: 'Set Up Now' },
|
|
86
|
-
{ value: 'ens', label: 'Set Up ENS Name', hint: 'Root → Name →
|
|
87
|
-
{ value: '
|
|
88
|
-
{ value: '
|
|
96
|
+
{ value: 'ens', label: 'Set Up ENS Name', hint: 'Root → Name → Apply' },
|
|
97
|
+
{ value: 'later', role: 'section', label: 'Later' },
|
|
98
|
+
{ value: 'later', label: 'Add ENS Later', hint: 'Name it anytime from the menu', role: 'utility' },
|
|
89
99
|
]}
|
|
90
|
-
hintLayout="
|
|
100
|
+
hintLayout="below"
|
|
91
101
|
onSubmit={choice => {
|
|
92
|
-
if (choice === '
|
|
102
|
+
if (choice === 'later') {
|
|
93
103
|
finishFirstRunIdentity()
|
|
94
104
|
return
|
|
95
105
|
}
|
|
@@ -97,7 +107,7 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
97
107
|
kind: 'edit-profile-ens',
|
|
98
108
|
identity: step.identity,
|
|
99
109
|
registry: step.registry,
|
|
100
|
-
returnTo: { kind: 'first-run-ens-prompt', identity: step.identity, registry: step.registry },
|
|
110
|
+
returnTo: { kind: 'first-run-ens-prompt', identity: step.identity, registry: step.registry, origin: step.origin },
|
|
101
111
|
})
|
|
102
112
|
}}
|
|
103
113
|
onCancel={finishFirstRunIdentity}
|
|
@@ -110,13 +120,11 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
110
120
|
if (step.kind === 'menu') {
|
|
111
121
|
return (
|
|
112
122
|
<MenuScreen
|
|
113
|
-
mode={mode}
|
|
114
123
|
config={config}
|
|
115
124
|
identity={identity}
|
|
116
|
-
workingStatus={workingStatus}
|
|
117
125
|
canRebackup={canRebackup}
|
|
118
126
|
reconciliation={reconciliation}
|
|
119
|
-
|
|
127
|
+
workingStatus={workingStatus}
|
|
120
128
|
onCreate={() => {
|
|
121
129
|
if (identity) setStep({ kind: 'replace-confirm', next: 'create' })
|
|
122
130
|
else setStep({ kind: 'create-name' })
|
|
@@ -146,8 +154,7 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
146
154
|
onIdentityValues={() => setStep({ kind: 'details' })}
|
|
147
155
|
onPrepareTransfer={openTokenTransferFlow}
|
|
148
156
|
onStorage={() => setStep({ kind: 'storage-credential' })}
|
|
149
|
-
|
|
150
|
-
onCancel={closeHub}
|
|
157
|
+
onCancel={closeManager}
|
|
151
158
|
/>
|
|
152
159
|
)
|
|
153
160
|
}
|
|
@@ -162,7 +169,7 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
162
169
|
onDescriptionSubmit={(name, description) => setStep({ kind: 'create-network', name, description })}
|
|
163
170
|
onCustodySubmit={(custodyMode) => {
|
|
164
171
|
if (step.kind !== 'create-custody') return
|
|
165
|
-
setStep({ kind: 'create-
|
|
172
|
+
setStep({ kind: 'create-import', name: step.name, description: step.description, ...(step.network ? { network: step.network } : {}), custodyMode })
|
|
166
173
|
}}
|
|
167
174
|
onRegistrySubmit={async value => {
|
|
168
175
|
if (step.kind !== 'create-registry') return
|
|
@@ -253,14 +260,14 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
253
260
|
if (step.kind !== 'restore-select-token') return
|
|
254
261
|
const candidate = step.candidates.find(item => item.agentId.toString() === value)
|
|
255
262
|
if (!candidate?.backup?.cid) return
|
|
256
|
-
|
|
263
|
+
setRestoreFetchingStep({
|
|
257
264
|
kind: 'restore-fetching',
|
|
258
265
|
cid: candidate.backup.cid,
|
|
259
266
|
apiUrl: DEFAULT_IPFS_API_URL,
|
|
260
267
|
candidate,
|
|
261
268
|
requesterAddress: step.requesterAddress,
|
|
262
269
|
purpose: step.purpose,
|
|
263
|
-
})
|
|
270
|
+
}, step)
|
|
264
271
|
}}
|
|
265
272
|
onEnsSubmit={async value => {
|
|
266
273
|
if (step.kind !== 'restore-ens-input') return
|
|
@@ -275,17 +282,17 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
275
282
|
return
|
|
276
283
|
}
|
|
277
284
|
if (!isAddress(step.ownerHandle, { strict: false }) || !canRestoreCandidate(resolution.candidate, getAddress(step.ownerHandle))) {
|
|
278
|
-
setStep({ ...step, busy: false, error: `${shortAddress(step.ownerHandle)} is not
|
|
285
|
+
setStep({ ...step, busy: false, error: `${shortAddress(step.ownerHandle)} is not an operator wallet for this agent. Sign in with an approved operator wallet, or with the owner wallet that holds the token.` })
|
|
279
286
|
return
|
|
280
287
|
}
|
|
281
|
-
|
|
288
|
+
setRestoreFetchingStep({
|
|
282
289
|
kind: 'restore-fetching',
|
|
283
290
|
cid: resolution.candidate.backup.cid,
|
|
284
291
|
apiUrl: DEFAULT_IPFS_API_URL,
|
|
285
292
|
candidate: resolution.candidate,
|
|
286
293
|
requesterAddress: step.ownerHandle,
|
|
287
294
|
purpose: step.purpose,
|
|
288
|
-
})
|
|
295
|
+
}, { ...step, busy: false, error: undefined })
|
|
289
296
|
}}
|
|
290
297
|
onTokenIdSubmit={async value => {
|
|
291
298
|
if (step.kind !== 'restore-token-id-input') return
|
|
@@ -300,17 +307,17 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
300
307
|
return
|
|
301
308
|
}
|
|
302
309
|
if (!isAddress(step.ownerHandle, { strict: false }) || !canRestoreCandidate(resolution.candidate, getAddress(step.ownerHandle))) {
|
|
303
|
-
setStep({ ...step, busy: false, error: `${shortAddress(step.ownerHandle)} is not
|
|
310
|
+
setStep({ ...step, busy: false, error: `${shortAddress(step.ownerHandle)} is not an operator wallet for this agent. Sign in with an approved operator wallet, or with the owner wallet that holds the token.` })
|
|
304
311
|
return
|
|
305
312
|
}
|
|
306
|
-
|
|
313
|
+
setRestoreFetchingStep({
|
|
307
314
|
kind: 'restore-fetching',
|
|
308
315
|
cid: resolution.candidate.backup.cid,
|
|
309
316
|
apiUrl: DEFAULT_IPFS_API_URL,
|
|
310
317
|
candidate: resolution.candidate,
|
|
311
318
|
requesterAddress: step.ownerHandle,
|
|
312
319
|
purpose: step.purpose,
|
|
313
|
-
})
|
|
320
|
+
}, { ...step, busy: false, error: undefined })
|
|
314
321
|
}}
|
|
315
322
|
onPickRecoveryMethod={choice => {
|
|
316
323
|
if (step.kind !== 'restore-recovery-input' && step.kind !== 'restore-select-token') return
|
|
@@ -359,5 +366,12 @@ export const IdentityHubRoutes: React.FC<{ controller: IdentityHubController }>
|
|
|
359
366
|
)
|
|
360
367
|
}
|
|
361
368
|
|
|
362
|
-
return <
|
|
369
|
+
return <IdentityManagerOperationalRoutes controller={controller} footer={footer} />
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function isSameLoadedAgent(identity: EthagentIdentity | undefined, candidate: Erc8004AgentCandidate): boolean {
|
|
373
|
+
if (!identity?.agentId || !identity.chainId || !identity.identityRegistryAddress) return false
|
|
374
|
+
if (identity.chainId !== candidate.chainId) return false
|
|
375
|
+
if (identity.agentId !== candidate.agentId.toString()) return false
|
|
376
|
+
return identity.identityRegistryAddress.toLowerCase() === candidate.identityRegistryAddress.toLowerCase()
|
|
363
377
|
}
|