ethagent 1.0.9 → 1.1.1
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/README.md +18 -81
- package/package.json +1 -2
- package/src/chat/ChatScreen.tsx +5 -4
- package/src/chat/ContinuityEditReviewView.tsx +3 -3
- package/src/chat/chatTurnOrchestrator.ts +1 -1
- package/src/chat/commands.ts +5 -5
- package/src/cli/ResetConfirmView.tsx +12 -13
- package/src/cli/main.tsx +27 -30
- package/src/cli/reset.ts +7 -8
- package/src/cli/updateNotice.ts +52 -0
- package/src/identity/continuity/envelope.ts +11 -5
- package/src/identity/continuity/storage.ts +1 -1
- package/src/identity/hub/IdentityHub.tsx +6 -7
- package/src/identity/hub/identityHubModel.ts +12 -12
- package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +39 -34
- package/src/identity/hub/screens/CreateFlow.tsx +4 -4
- package/src/identity/hub/screens/DetailsScreen.tsx +2 -2
- package/src/identity/hub/screens/EditProfileFlow.tsx +5 -5
- package/src/identity/hub/screens/ErrorScreen.tsx +2 -2
- package/src/identity/hub/screens/IdentitySummary.tsx +32 -12
- package/src/identity/hub/screens/MenuScreen.tsx +17 -17
- package/src/identity/hub/screens/NetworkScreen.tsx +7 -3
- package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +9 -7
- package/src/identity/hub/screens/RestoreFlow.tsx +2 -2
- package/src/identity/hub/screens/StorageCredentialScreen.tsx +5 -5
- package/src/identity/wallet/wallet-page/wallet.html +1202 -1082
- package/src/models/ModelPicker.tsx +71 -71
- package/src/models/llamacppPreflight.ts +1 -1
- package/src/models/modelPickerOptions.ts +22 -22
- package/src/storage/factoryReset.ts +17 -20
- package/src/tools/privateContinuityEditTool.ts +1 -1
- package/src/ui/BrandSplash.tsx +7 -4
|
@@ -93,7 +93,7 @@ export function tokenLabel(candidate: Erc8004AgentCandidate): string {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
export function tokenCandidateLabel(candidate: Erc8004AgentCandidate): string {
|
|
96
|
-
return candidate.name?.trim() || `
|
|
96
|
+
return candidate.name?.trim() || `Agent Token #${candidate.agentId.toString()}`
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export function tokenCandidateSelectLabel(
|
|
@@ -200,8 +200,8 @@ export function identitySummaryRows(
|
|
|
200
200
|
const tokenValue = identity?.agentId ? `#${identity.agentId}` : 'not created'
|
|
201
201
|
const chain = chainSummaryRow(config, identity)
|
|
202
202
|
const stateValue = backup?.cid ? shortCid(backup.cid) : 'not saved yet'
|
|
203
|
-
const skillsValue = identity?.publicSkills?.cid ? shortCid(identity.publicSkills.cid) : 'not
|
|
204
|
-
const cardValue = identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : 'not
|
|
203
|
+
const skillsValue = identity?.publicSkills?.cid ? shortCid(identity.publicSkills.cid) : 'not saved'
|
|
204
|
+
const cardValue = identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : 'not saved'
|
|
205
205
|
const imageValue = typeof identity?.state?.imageUrl === 'string' && identity.state.imageUrl.trim() ? 'attached' : 'not attached'
|
|
206
206
|
return [
|
|
207
207
|
{ label: 'owner', value: ownerValue, tone: identity ? 'ok' : 'dim' },
|
|
@@ -232,8 +232,8 @@ export function identityDetailSections(
|
|
|
232
232
|
const chain = chainSummaryRow(config, identity)
|
|
233
233
|
const stateCid = backup?.cid ?? 'not saved yet'
|
|
234
234
|
const registrationCid = identity?.metadataCid ?? 'not saved yet'
|
|
235
|
-
const publicSkillsCid = identity?.publicSkills?.cid ?? 'not
|
|
236
|
-
const agentCardCid = identity?.publicSkills?.agentCardCid ?? 'not
|
|
235
|
+
const publicSkillsCid = identity?.publicSkills?.cid ?? 'not saved'
|
|
236
|
+
const agentCardCid = identity?.publicSkills?.agentCardCid ?? 'not saved'
|
|
237
237
|
|
|
238
238
|
return [
|
|
239
239
|
{
|
|
@@ -273,14 +273,14 @@ export type CopyableField = {
|
|
|
273
273
|
export function copyableIdentityFields(identity?: EthagentIdentity): CopyableField[] {
|
|
274
274
|
if (!identity) return []
|
|
275
275
|
const fields: CopyableField[] = []
|
|
276
|
-
if (identity.backup?.cid) fields.push({ label: '
|
|
277
|
-
if (identity.publicSkills?.cid) fields.push({ label: '
|
|
278
|
-
if (identity.publicSkills?.agentCardCid) fields.push({ label: '
|
|
279
|
-
if (identity.metadataCid) fields.push({ label: '
|
|
280
|
-
if (identity.agentUri) fields.push({ label: '
|
|
276
|
+
if (identity.backup?.cid) fields.push({ label: 'State CID', value: identity.backup.cid })
|
|
277
|
+
if (identity.publicSkills?.cid) fields.push({ label: 'Skills CID', value: identity.publicSkills.cid })
|
|
278
|
+
if (identity.publicSkills?.agentCardCid) fields.push({ label: 'Agent Card CID', value: identity.publicSkills.agentCardCid })
|
|
279
|
+
if (identity.metadataCid) fields.push({ label: 'Registration CID', value: identity.metadataCid })
|
|
280
|
+
if (identity.agentUri) fields.push({ label: 'Agent URI', value: identity.agentUri })
|
|
281
281
|
const owner = identity.ownerAddress ?? identity.address
|
|
282
|
-
if (owner) fields.push({ label: '
|
|
283
|
-
if (identity.agentId) fields.push({ label: '
|
|
282
|
+
if (owner) fields.push({ label: 'Owner Address', value: owner })
|
|
283
|
+
if (identity.agentId) fields.push({ label: 'Token ID', value: identity.agentId })
|
|
284
284
|
return fields
|
|
285
285
|
}
|
|
286
286
|
|
|
@@ -4,57 +4,66 @@ import { Surface } from '../../../ui/Surface.js'
|
|
|
4
4
|
import { Select } from '../../../ui/Select.js'
|
|
5
5
|
import { theme } from '../../../ui/theme.js'
|
|
6
6
|
import type { EthagentConfig, EthagentIdentity } from '../../../storage/config.js'
|
|
7
|
+
import type { ContinuityWorkingTreeStatus } from '../../continuity/storage.js'
|
|
7
8
|
import { IdentitySummary } from './IdentitySummary.js'
|
|
8
9
|
import { shortCid } from '../identityHubModel.js'
|
|
9
10
|
|
|
10
|
-
type PrivateAction = 'soul' | 'memory' | '
|
|
11
|
-
type PublicAction = 'edit' | 'skills' | '
|
|
11
|
+
type PrivateAction = 'soul' | 'memory' | 'back'
|
|
12
|
+
type PublicAction = 'edit' | 'skills' | 'back'
|
|
12
13
|
|
|
13
14
|
type CommonProps = {
|
|
14
15
|
identity?: EthagentIdentity
|
|
15
16
|
config?: EthagentConfig
|
|
17
|
+
workingStatus?: ContinuityWorkingTreeStatus | null
|
|
16
18
|
ready: boolean
|
|
17
19
|
notice?: string
|
|
18
20
|
footer: React.ReactNode
|
|
19
21
|
onBack: () => void
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
const SaveFromHubHint: React.FC<{ workingStatus?: ContinuityWorkingTreeStatus | null }> = ({ workingStatus }) => {
|
|
25
|
+
const needsBackup = workingStatus?.publishState === 'local-changes'
|
|
26
|
+
|| workingStatus?.publishState === 'not-published'
|
|
27
|
+
|| workingStatus?.publishState === 'verify-needed'
|
|
28
|
+
if (!needsBackup) return null
|
|
29
|
+
return (
|
|
30
|
+
<Box marginTop={1}>
|
|
31
|
+
<Text color={theme.accentPeach}>Save path: Identity Hub > Save Snapshot Now > Yes, Save Snapshot Now.</Text>
|
|
32
|
+
</Box>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
22
36
|
export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
23
|
-
canBackup: boolean
|
|
24
37
|
onOpenSoul: () => void
|
|
25
38
|
onOpenMemory: () => void
|
|
26
|
-
onBackup: () => void
|
|
27
39
|
}> = ({
|
|
28
40
|
identity,
|
|
29
41
|
config,
|
|
42
|
+
workingStatus,
|
|
30
43
|
ready,
|
|
31
44
|
notice,
|
|
32
45
|
footer,
|
|
33
|
-
canBackup,
|
|
34
46
|
onOpenSoul,
|
|
35
47
|
onOpenMemory,
|
|
36
|
-
onBackup,
|
|
37
48
|
onBack,
|
|
38
49
|
}) => (
|
|
39
50
|
<Surface title="Private Memory Files" subtitle={notice ?? privateSubtitle(ready)} footer={footer}>
|
|
40
|
-
<IdentitySummary identity={identity} config={config} compact />
|
|
51
|
+
<IdentitySummary identity={identity} config={config} workingStatus={workingStatus} compact />
|
|
41
52
|
<PrivateRows identity={identity} ready={ready} />
|
|
53
|
+
<SaveFromHubHint workingStatus={workingStatus} />
|
|
42
54
|
<Box marginTop={1}>
|
|
43
55
|
<Select<PrivateAction>
|
|
44
56
|
options={[
|
|
45
|
-
{ value: 'soul', role: 'section', prefix: '--', label: 'Open
|
|
46
|
-
{ value: 'soul', label: '
|
|
47
|
-
{ value: 'memory', label: '
|
|
48
|
-
{ value: 'backup', role: 'section', prefix: '--', label: 'Recovery' },
|
|
49
|
-
{ value: 'backup', label: 'save snapshot now', hint: 'encrypts and publishes local SOUL.md and MEMORY.md changes, as well as skills.json and public metadata', disabled: !ready || !canBackup },
|
|
57
|
+
{ value: 'soul', role: 'section', prefix: '--', label: 'Open Local Files' },
|
|
58
|
+
{ value: 'soul', label: 'Open SOUL.md', hint: 'Edit persona and operating preferences', disabled: !ready },
|
|
59
|
+
{ value: 'memory', label: 'Open MEMORY.md', hint: 'Edit private working memory for this agent', disabled: !ready },
|
|
50
60
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
51
|
-
{ value: 'back', label: '
|
|
61
|
+
{ value: 'back', label: 'Back To Identity Hub', hint: 'Return without changing private files', role: 'utility' },
|
|
52
62
|
]}
|
|
53
63
|
hintLayout="inline"
|
|
54
64
|
onSubmit={choice => {
|
|
55
65
|
if (choice === 'soul') return onOpenSoul()
|
|
56
66
|
if (choice === 'memory') return onOpenMemory()
|
|
57
|
-
if (choice === 'backup') return onBackup()
|
|
58
67
|
return onBack()
|
|
59
68
|
}}
|
|
60
69
|
onCancel={onBack}
|
|
@@ -64,31 +73,27 @@ export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
|
64
73
|
)
|
|
65
74
|
|
|
66
75
|
export const PublicSkillsScreen: React.FC<CommonProps & {
|
|
67
|
-
canPublish: boolean
|
|
68
76
|
onEditProfile: () => void
|
|
69
77
|
onOpenSkills: () => void
|
|
70
|
-
|
|
71
|
-
}> = ({ identity, config, notice, footer, canPublish, onEditProfile, onOpenSkills, onPublish, onBack }) => (
|
|
78
|
+
}> = ({ identity, config, workingStatus, notice, footer, onEditProfile, onOpenSkills, onBack }) => (
|
|
72
79
|
<Surface title="Public Profile" subtitle={notice ?? 'Manage public metadata, skills.json, and the agent card.'} footer={footer}>
|
|
73
|
-
<IdentitySummary identity={identity} config={config} compact />
|
|
80
|
+
<IdentitySummary identity={identity} config={config} workingStatus={workingStatus} compact />
|
|
74
81
|
<PublicProfileRows identity={identity} />
|
|
82
|
+
<SaveFromHubHint workingStatus={workingStatus} />
|
|
75
83
|
<Box marginTop={1}>
|
|
76
84
|
<Select<PublicAction>
|
|
77
85
|
options={[
|
|
78
86
|
{ value: 'edit', role: 'section', prefix: '--', label: 'Profile' },
|
|
79
|
-
{ value: 'edit', label: '
|
|
87
|
+
{ value: 'edit', label: 'Edit Name, Description, Image', hint: 'Upload a local image to IPFS automatically' },
|
|
80
88
|
{ value: 'skills', role: 'section', prefix: '--', label: 'Capabilities' },
|
|
81
|
-
{ value: 'skills', label: '
|
|
82
|
-
{ value: 'publish', role: 'section', prefix: '--', label: 'Recovery' },
|
|
83
|
-
{ value: 'publish', label: 'save snapshot now', hint: 'publishes local memory, skills, and metadata', disabled: !canPublish },
|
|
89
|
+
{ value: 'skills', label: 'Open skills.json', hint: 'Edit public capabilities and notes' },
|
|
84
90
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
85
|
-
{ value: 'back', label: '
|
|
91
|
+
{ value: 'back', label: 'Back To Identity Hub', hint: 'Return without changing public metadata', role: 'utility' },
|
|
86
92
|
]}
|
|
87
93
|
hintLayout="inline"
|
|
88
94
|
onSubmit={choice => {
|
|
89
95
|
if (choice === 'edit') return onEditProfile()
|
|
90
96
|
if (choice === 'skills') return onOpenSkills()
|
|
91
|
-
if (choice === 'publish') return onPublish()
|
|
92
97
|
return onBack()
|
|
93
98
|
}}
|
|
94
99
|
onCancel={onBack}
|
|
@@ -100,12 +105,12 @@ export const PublicSkillsScreen: React.FC<CommonProps & {
|
|
|
100
105
|
const PrivateRows: React.FC<{ identity?: EthagentIdentity; ready: boolean }> = ({ identity, ready }) => (
|
|
101
106
|
<Box flexDirection="column" marginTop={1}>
|
|
102
107
|
<Text>
|
|
103
|
-
<Text color={theme.dim}>{'
|
|
104
|
-
<Text color={ready ? theme.text : theme.dim}>{ready ? 'SOUL.md and MEMORY.md
|
|
108
|
+
<Text color={theme.dim}>{'Local Files'.padEnd(13)}</Text>
|
|
109
|
+
<Text color={ready ? theme.text : theme.dim}>{ready ? 'SOUL.md and MEMORY.md Ready' : 'Missing Local Working Files'}</Text>
|
|
105
110
|
</Text>
|
|
106
111
|
<Text>
|
|
107
|
-
<Text color={theme.dim}>{'
|
|
108
|
-
<Text color={identity?.backup?.cid ? theme.text : theme.dim}>{identity?.backup?.cid ? shortCid(identity.backup.cid) : '
|
|
112
|
+
<Text color={theme.dim}>{'Snapshot'.padEnd(13)}</Text>
|
|
113
|
+
<Text color={identity?.backup?.cid ? theme.text : theme.dim}>{identity?.backup?.cid ? shortCid(identity.backup.cid) : 'Not Saved Yet'}</Text>
|
|
109
114
|
</Text>
|
|
110
115
|
</Box>
|
|
111
116
|
)
|
|
@@ -114,15 +119,15 @@ const PublicProfileRows: React.FC<{ identity?: EthagentIdentity }> = ({ identity
|
|
|
114
119
|
<Box flexDirection="column" marginTop={1}>
|
|
115
120
|
<Text>
|
|
116
121
|
<Text color={theme.dim}>{'skills.json'.padEnd(13)}</Text>
|
|
117
|
-
<Text color={identity?.publicSkills?.cid ? theme.text : theme.dim}>{identity?.publicSkills?.cid ? shortCid(identity.publicSkills.cid) : '
|
|
122
|
+
<Text color={identity?.publicSkills?.cid ? theme.text : theme.dim}>{identity?.publicSkills?.cid ? shortCid(identity.publicSkills.cid) : 'Not Saved'}</Text>
|
|
118
123
|
</Text>
|
|
119
124
|
<Text>
|
|
120
|
-
<Text color={theme.dim}>{'
|
|
121
|
-
<Text color={identity?.publicSkills?.agentCardCid ? theme.text : theme.dim}>{identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : '
|
|
125
|
+
<Text color={theme.dim}>{'Agent Card'.padEnd(13)}</Text>
|
|
126
|
+
<Text color={identity?.publicSkills?.agentCardCid ? theme.text : theme.dim}>{identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : 'Not Saved'}</Text>
|
|
122
127
|
</Text>
|
|
123
128
|
<Text>
|
|
124
|
-
<Text color={theme.dim}>{'
|
|
125
|
-
<Text color={readStateString(identity?.state, 'imageUrl') ? theme.text : theme.dim}>{readStateString(identity?.state, 'imageUrl') ? '
|
|
129
|
+
<Text color={theme.dim}>{'Image'.padEnd(13)}</Text>
|
|
130
|
+
<Text color={readStateString(identity?.state, 'imageUrl') ? theme.text : theme.dim}>{readStateString(identity?.state, 'imageUrl') ? 'Attached' : 'Not Attached'}</Text>
|
|
126
131
|
</Text>
|
|
127
132
|
</Box>
|
|
128
133
|
)
|
|
@@ -130,7 +135,7 @@ const PublicProfileRows: React.FC<{ identity?: EthagentIdentity }> = ({ identity
|
|
|
130
135
|
function privateSubtitle(ready: boolean): string {
|
|
131
136
|
return ready
|
|
132
137
|
? 'SOUL.md and MEMORY.md are private local files on this machine.'
|
|
133
|
-
: 'Use "
|
|
138
|
+
: 'Use "Refetch Latest Snapshot" from the Identity Hub menu to recover files.'
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
function readStateString(state: Record<string, unknown> | undefined, key: string): string {
|
|
@@ -81,10 +81,10 @@ export const CreateFlow: React.FC<CreateFlowProps> = ({
|
|
|
81
81
|
</Box>
|
|
82
82
|
<Select<'replace' | 'back'>
|
|
83
83
|
options={[
|
|
84
|
-
{ value: 'back', role: 'section', prefix: '--', label: 'Current
|
|
85
|
-
{ value: 'back', label: '
|
|
86
|
-
{ value: 'replace', role: 'section', prefix: '--', label: 'New
|
|
87
|
-
{ value: 'replace', label: '
|
|
84
|
+
{ value: 'back', role: 'section', prefix: '--', label: 'Current Identity' },
|
|
85
|
+
{ value: 'back', label: 'Keep Current Agent', hint: 'Return without minting anything', role: 'utility' },
|
|
86
|
+
{ value: 'replace', role: 'section', prefix: '--', label: 'New Identity' },
|
|
87
|
+
{ value: 'replace', label: 'Mint and Use New Agent', hint: 'Create separate token and make it active' },
|
|
88
88
|
]}
|
|
89
89
|
hintLayout="inline"
|
|
90
90
|
onSubmit={choice => {
|
|
@@ -33,9 +33,9 @@ export const DetailsScreen: React.FC<DetailsScreenProps> = ({
|
|
|
33
33
|
label: field.label,
|
|
34
34
|
hint: shortPreview(field.value),
|
|
35
35
|
})),
|
|
36
|
-
...(copyable.length === 0 ? [{ value: 'back' as const, role: 'notice' as const, label: '
|
|
36
|
+
...(copyable.length === 0 ? [{ value: 'back' as const, role: 'notice' as const, label: 'No Values Available Yet' }] : []),
|
|
37
37
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
38
|
-
{ value: 'back', label: '
|
|
38
|
+
{ value: 'back', label: 'Back To Identity Hub', hint: 'Return without copying', role: 'utility' },
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
return (
|
|
@@ -67,12 +67,12 @@ export const EditProfileFlow: React.FC<EditProfileFlowProps> = ({
|
|
|
67
67
|
<Select<'choose' | 'manual' | 'skip' | 'delete' | 'back'>
|
|
68
68
|
options={[
|
|
69
69
|
{ value: 'choose', role: 'section', prefix: '--', label: 'Image' },
|
|
70
|
-
{ value: 'choose', label: '
|
|
71
|
-
{ value: 'manual', label: '
|
|
72
|
-
...(currentImage ? [{ value: 'delete' as const, label: '
|
|
73
|
-
{ value: 'skip', label: currentImage ? '
|
|
70
|
+
{ value: 'choose', label: 'Choose Image File', hint: 'Open the operating system file picker' },
|
|
71
|
+
{ value: 'manual', label: 'Enter Path Manually', hint: 'Fallback if a file picker is unavailable' },
|
|
72
|
+
...(currentImage ? [{ value: 'delete' as const, label: 'Delete Current Image', hint: 'Remove the attached image from public profile' }] : []),
|
|
73
|
+
{ value: 'skip', label: currentImage ? 'Keep Current Image' : 'No Image', hint: 'Save without changing the image' },
|
|
74
74
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
75
|
-
{ value: 'back', label: '
|
|
75
|
+
{ value: 'back', label: 'Back', hint: 'Return to description', role: 'utility' },
|
|
76
76
|
]}
|
|
77
77
|
hintLayout="inline"
|
|
78
78
|
onSubmit={choice => {
|
|
@@ -20,9 +20,9 @@ export const ErrorScreen: React.FC<ErrorScreenProps> = ({ error, back, footer, o
|
|
|
20
20
|
<Select<'back' | 'close'>
|
|
21
21
|
options={[
|
|
22
22
|
{ value: 'back', role: 'section', prefix: '--', label: 'Recovery' },
|
|
23
|
-
{ value: 'back', label: '
|
|
23
|
+
{ value: 'back', label: 'Go Back', hint: 'Return to the previous identity step' },
|
|
24
24
|
{ value: 'close', role: 'section', prefix: '--', label: 'Exit' },
|
|
25
|
-
{ value: 'close', label: '
|
|
25
|
+
{ value: 'close', label: 'Close Identity Hub', hint: 'Return to chat without retrying', role: 'utility' },
|
|
26
26
|
]}
|
|
27
27
|
hintLayout="inline"
|
|
28
28
|
onSubmit={choice => {
|
|
@@ -14,7 +14,7 @@ export const IdentitySummary: React.FC<{
|
|
|
14
14
|
}> = ({ identity, config, workingStatus, compact = false }) => {
|
|
15
15
|
if (!identity) {
|
|
16
16
|
return (
|
|
17
|
-
<Text color={theme.dim}>
|
|
17
|
+
<Text color={theme.dim}>No agent yet. Create or load one.</Text>
|
|
18
18
|
)
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -39,32 +39,52 @@ export const IdentitySummary: React.FC<{
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const lastSavedRow = needsBackup
|
|
42
|
-
? { label: '
|
|
43
|
-
: { label: '
|
|
42
|
+
? { label: 'Unsaved', value: changedFiles.length > 0 ? changedFiles.join(', ') : 'Markdown files', tone: 'warn' as const, highlight: true }
|
|
43
|
+
: { label: 'Last Saved', value: lastBackup, tone: lastBackup === 'never' ? 'dim' as const : 'ok' as const }
|
|
44
44
|
|
|
45
45
|
const summaryRows = [
|
|
46
|
-
{ label: '
|
|
47
|
-
{ label: '
|
|
48
|
-
{ label: '
|
|
49
|
-
{ label: '
|
|
46
|
+
{ label: 'Token', value: row('token')?.value ?? 'Not Created', tone: row('token')?.tone ?? 'dim', highlight: true },
|
|
47
|
+
{ label: 'Network', value: row('network')?.value ?? 'Unknown', tone: row('network')?.tone ?? 'dim' },
|
|
48
|
+
{ label: 'Owner', value: row('owner')?.value ?? 'Not Connected', tone: row('owner')?.tone ?? 'dim' },
|
|
49
|
+
{ label: 'Snapshot', value: row('state')?.value ?? 'Not Saved Yet', tone: row('state')?.tone ?? 'dim', highlight: true },
|
|
50
50
|
lastSavedRow,
|
|
51
|
-
{ label: '
|
|
52
|
-
{ label: '
|
|
53
|
-
{ label: '
|
|
51
|
+
{ label: 'Skills', value: row('skills')?.value ?? 'Not Saved', tone: row('skills')?.tone ?? 'dim' },
|
|
52
|
+
{ label: 'Agent Card', value: row('card')?.value ?? 'Not Saved', tone: row('card')?.tone ?? 'dim' },
|
|
53
|
+
{ label: 'Image', value: row('image')?.value ?? 'Not Attached', tone: row('image')?.tone ?? 'dim' },
|
|
54
54
|
]
|
|
55
55
|
|
|
56
56
|
return (
|
|
57
57
|
<Box flexDirection="column">
|
|
58
|
-
<Text color={theme.accentPrimary} bold>{stateName || '
|
|
58
|
+
<Text color={theme.accentPrimary} bold>{stateName || 'Active Agent'}</Text>
|
|
59
59
|
{summaryRows.map(row => {
|
|
60
60
|
const valueColor = row.tone === 'warn' ? 'red' : (row.tone === 'ok' ? theme.text : theme.dim)
|
|
61
61
|
return (
|
|
62
62
|
<Text key={row.label}>
|
|
63
63
|
<Text color={theme.dim}>{row.label.padEnd(12)}</Text>
|
|
64
|
-
<Text color={valueColor} bold={row.highlight}>{row.value}</Text>
|
|
64
|
+
<Text color={valueColor} bold={row.highlight}>{displayValue(row.value)}</Text>
|
|
65
65
|
</Text>
|
|
66
66
|
)
|
|
67
67
|
})}
|
|
68
68
|
</Box>
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
function displayValue(value: string): string {
|
|
73
|
+
const mapped = DISPLAY_VALUES[value]
|
|
74
|
+
return mapped ?? value
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const DISPLAY_VALUES: Record<string, string> = {
|
|
78
|
+
'not attached': 'Not Attached',
|
|
79
|
+
'not connected': 'Not Connected',
|
|
80
|
+
'not created': 'Not Created',
|
|
81
|
+
'not saved': 'Not Saved',
|
|
82
|
+
'not saved yet': 'Not Saved Yet',
|
|
83
|
+
'never': 'Never',
|
|
84
|
+
'unknown': 'Unknown',
|
|
85
|
+
'ethereum mainnet': 'Ethereum Mainnet',
|
|
86
|
+
'arbitrum one': 'Arbitrum One',
|
|
87
|
+
'base': 'Base',
|
|
88
|
+
'optimism': 'Optimism',
|
|
89
|
+
'polygon': 'Polygon',
|
|
90
|
+
}
|
|
@@ -55,7 +55,7 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
55
55
|
onSkip,
|
|
56
56
|
onCancel,
|
|
57
57
|
}) => {
|
|
58
|
-
const title = mode === 'first-run' ? 'Set Up Agent Identity' : '
|
|
58
|
+
const title = mode === 'first-run' ? 'Set Up Agent Identity' : 'Identity Hub'
|
|
59
59
|
const subtitle = mode === 'first-run'
|
|
60
60
|
? 'Create a portable agent or load one you already own.'
|
|
61
61
|
: 'Public, private, recovery, storage, and device controls are separate.'
|
|
@@ -64,30 +64,30 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
64
64
|
|
|
65
65
|
const options: Array<SelectOption<Action>> = identity
|
|
66
66
|
? [
|
|
67
|
-
{ value: 'public-profile', role: 'section', prefix: '--', label: 'Public
|
|
68
|
-
{ value: 'public-profile', label: '
|
|
69
|
-
{ value: 'private-memory', role: 'section', prefix: '--', label: 'Private
|
|
70
|
-
{ value: 'private-memory', label: '
|
|
67
|
+
{ value: 'public-profile', role: 'section', prefix: '--', label: 'Public Metadata' },
|
|
68
|
+
{ value: 'public-profile', label: 'Public Profile', hint: 'Name, image, skills.json, Agent Card' },
|
|
69
|
+
{ value: 'private-memory', role: 'section', prefix: '--', label: 'Private Local Files' },
|
|
70
|
+
{ value: 'private-memory', label: 'Memory and Persona', hint: 'SOUL.md and MEMORY.md only on this device' },
|
|
71
71
|
{ value: 'backup', role: 'section', prefix: '--', label: 'Recovery' },
|
|
72
|
-
{ value: 'backup', label: '
|
|
73
|
-
{ value: 'refetch', label: '
|
|
72
|
+
{ value: 'backup', label: 'Save Snapshot Now', hint: 'Saves any local edits to SOUL.md, MEMORY.md, skills.json, and public profile', disabled: !canRebackup },
|
|
73
|
+
{ value: 'refetch', label: 'Refetch Latest Snapshot', hint: 'Restore local files from the latest saved snapshot', disabled: !canRefetch },
|
|
74
74
|
{ value: 'storage-credential', role: 'section', prefix: '--', label: 'Storage' },
|
|
75
|
-
{ value: 'storage-credential', label: 'IPFS
|
|
76
|
-
{ value: 'copy', role: 'section', prefix: '--', label: 'Agent
|
|
77
|
-
{ value: 'copy', label: '
|
|
78
|
-
{ value: 'load', label: '
|
|
79
|
-
{ value: 'create', label: '
|
|
75
|
+
{ value: 'storage-credential', label: 'IPFS Credential', hint: 'Save, replace, or forget Pinata JWT' },
|
|
76
|
+
{ value: 'copy', role: 'section', prefix: '--', label: 'Agent Token' },
|
|
77
|
+
{ value: 'copy', label: 'Copy Values', hint: 'Copy CIDs, token ID, URI, or owner' },
|
|
78
|
+
{ value: 'load', label: 'Switch Agent', hint: 'Load a different token owned by your wallet' },
|
|
79
|
+
{ value: 'create', label: 'New Agent', hint: 'Mint another token and make it active here' },
|
|
80
80
|
{ value: 'cancel', role: 'section', prefix: '--', label: 'Exit' },
|
|
81
|
-
{ value: 'cancel', label: '
|
|
81
|
+
{ value: 'cancel', label: 'Close Identity Hub', hint: 'Return to chat without changing identity', role: 'utility' },
|
|
82
82
|
]
|
|
83
83
|
: [
|
|
84
84
|
{ value: 'create', role: 'section', prefix: '--', label: 'Setup' },
|
|
85
|
-
{ value: 'create', label: '
|
|
86
|
-
{ value: 'load', label: '
|
|
85
|
+
{ value: 'create', label: 'Create New Agent', hint: 'Mint a wallet-owned token for this machine' },
|
|
86
|
+
{ value: 'load', label: 'Load Existing Agent', hint: 'Find an agent token your wallet already owns' },
|
|
87
87
|
{ value: 'skip', role: 'section', prefix: '--', label: 'Exit' },
|
|
88
88
|
...(mode === 'first-run'
|
|
89
|
-
? [{ value: 'skip' as Action, label: '
|
|
90
|
-
: [{ value: 'cancel' as Action, label: '
|
|
89
|
+
? [{ value: 'skip' as Action, label: 'Skip For Now', hint: 'Continue now; use /identity later', role: 'utility' as const }]
|
|
90
|
+
: [{ value: 'cancel' as Action, label: 'Close Identity Hub', hint: 'Return to chat without changing identity', role: 'utility' as const }]),
|
|
91
91
|
]
|
|
92
92
|
|
|
93
93
|
return (
|
|
@@ -14,9 +14,9 @@ type NetworkScreenProps = {
|
|
|
14
14
|
|
|
15
15
|
export const NetworkScreen: React.FC<NetworkScreenProps> = ({ subtitle, footer, onSelect, onCancel }) => {
|
|
16
16
|
const options: Array<SelectOption<SelectableNetwork>> = [
|
|
17
|
-
{ value: 'mainnet', role: 'section', prefix: '--', label: 'Main
|
|
17
|
+
{ value: 'mainnet', role: 'section', prefix: '--', label: 'Main Network' },
|
|
18
18
|
networkOption('mainnet'),
|
|
19
|
-
{ value: 'arbitrum', role: 'section', prefix: '--', label: 'Lower-
|
|
19
|
+
{ value: 'arbitrum', role: 'section', prefix: '--', label: 'Lower-Fee Networks' },
|
|
20
20
|
...SELECTABLE_NETWORKS.filter(network => network !== 'mainnet').map(networkOption),
|
|
21
21
|
]
|
|
22
22
|
|
|
@@ -35,7 +35,11 @@ export const NetworkScreen: React.FC<NetworkScreenProps> = ({ subtitle, footer,
|
|
|
35
35
|
function networkOption(network: SelectableNetwork): SelectOption<SelectableNetwork> {
|
|
36
36
|
return {
|
|
37
37
|
value: network,
|
|
38
|
-
label: networkLabel(network),
|
|
38
|
+
label: titleCase(networkLabel(network)),
|
|
39
39
|
hint: networkSubtitle(network),
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
function titleCase(value: string): string {
|
|
44
|
+
return value.replace(/\b[a-z]/g, letter => letter.toUpperCase())
|
|
45
|
+
}
|
|
@@ -20,16 +20,16 @@ export const RecoveryConfirmScreen: React.FC<RecoveryConfirmScreenProps> = ({ mo
|
|
|
20
20
|
const isPublish = mode === 'publish'
|
|
21
21
|
const title = isPublish ? 'Save Snapshot?' : 'Refetch Latest From Chain?'
|
|
22
22
|
const subtitle = isPublish
|
|
23
|
-
? '
|
|
23
|
+
? 'Saves any local edits to SOUL.md, MEMORY.md, skills.json, and public profile.'
|
|
24
24
|
: 'This overwrites local files with the on-chain version.'
|
|
25
25
|
|
|
26
26
|
const headlineColor = isPublish ? theme.accentPeach : theme.accentMint
|
|
27
27
|
const headline = isPublish
|
|
28
|
-
? 'Saving
|
|
28
|
+
? 'Saving updates the on-chain pointer for this agent.'
|
|
29
29
|
: 'Refetching replaces local SOUL.md, MEMORY.md, and skills.json with what is on chain.'
|
|
30
30
|
const detail = isPublish
|
|
31
|
-
? '
|
|
32
|
-
: 'Unsaved local edits will be lost. Use this when local files are missing or out of sync with the latest
|
|
31
|
+
? 'Any local edits to SOUL.md, MEMORY.md, skills.json, and public profile become the saved state. The previous snapshot pointer is overwritten.'
|
|
32
|
+
: 'Unsaved local edits will be lost. Use this when local files are missing or out of sync with the latest saved snapshot.'
|
|
33
33
|
|
|
34
34
|
const needsBackup = workingStatus?.publishState === 'local-changes' || workingStatus?.publishState === 'not-published' || workingStatus?.publishState === 'verify-needed'
|
|
35
35
|
let changedFiles: string[] = []
|
|
@@ -50,8 +50,10 @@ export const RecoveryConfirmScreen: React.FC<RecoveryConfirmScreenProps> = ({ mo
|
|
|
50
50
|
<Text color={theme.textSubtle}>{detail}</Text>
|
|
51
51
|
{isPublish && changedFiles.length > 0 && (
|
|
52
52
|
<Box marginTop={1}>
|
|
53
|
-
<Text
|
|
54
|
-
|
|
53
|
+
<Text>
|
|
54
|
+
<Text color={theme.textSubtle}>ready to save: </Text>
|
|
55
|
+
<Text color={theme.accentMint} bold>{changedFiles.join(', ')}</Text>
|
|
56
|
+
</Text>
|
|
55
57
|
</Box>
|
|
56
58
|
)}
|
|
57
59
|
</Box>
|
|
@@ -62,7 +64,7 @@ export const RecoveryConfirmScreen: React.FC<RecoveryConfirmScreenProps> = ({ mo
|
|
|
62
64
|
{
|
|
63
65
|
value: 'confirm',
|
|
64
66
|
label: isPublish ? 'Yes, Save Snapshot Now' : 'Yes, Refetch From Chain',
|
|
65
|
-
hint: isPublish ? 'Sign and
|
|
67
|
+
hint: isPublish ? 'Sign and save the encrypted snapshot' : 'Wallet decrypts and overwrites local files',
|
|
66
68
|
},
|
|
67
69
|
{ value: 'back', role: 'section', prefix: '--', label: 'Cancel' },
|
|
68
70
|
{
|
|
@@ -59,7 +59,7 @@ export const RestoreFlow: React.FC<RestoreFlowProps> = ({
|
|
|
59
59
|
<Select<'connect'>
|
|
60
60
|
options={[
|
|
61
61
|
{ value: 'connect', role: 'section', prefix: '--', label: 'Wallet' },
|
|
62
|
-
{ value: 'connect', label: '
|
|
62
|
+
{ value: 'connect', label: 'Connect Wallet', hint: 'Search tokens owned by browser wallet' },
|
|
63
63
|
]}
|
|
64
64
|
hintLayout="inline"
|
|
65
65
|
onSubmit={onConnectWallet}
|
|
@@ -137,7 +137,7 @@ export const RestoreFlow: React.FC<RestoreFlowProps> = ({
|
|
|
137
137
|
>
|
|
138
138
|
<Select<string>
|
|
139
139
|
options={[
|
|
140
|
-
{ value: 'section:owned-agents', role: 'section', prefix: '--', label: 'Owned
|
|
140
|
+
{ value: 'section:owned-agents', role: 'section', prefix: '--', label: 'Owned Agents' },
|
|
141
141
|
...step.candidates.map(candidate => {
|
|
142
142
|
const current = isSwitch && isCurrentAgentCandidate(config?.identity, candidate)
|
|
143
143
|
return {
|
|
@@ -86,9 +86,9 @@ export const StorageCredentialScreen: React.FC<StorageCredentialScreenProps> = (
|
|
|
86
86
|
<Select<StorageCredentialAction>
|
|
87
87
|
options={[
|
|
88
88
|
{ value: 'forget', role: 'section', prefix: '--', label: 'Credential' },
|
|
89
|
-
{ value: 'forget', label: '
|
|
89
|
+
{ value: 'forget', label: 'Forget Credential', hint: 'Remove local IPFS pinning token' },
|
|
90
90
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
91
|
-
{ value: 'back', label: '
|
|
91
|
+
{ value: 'back', label: 'Keep Credential', hint: 'Return without changing storage access', role: 'utility' },
|
|
92
92
|
]}
|
|
93
93
|
hintLayout="inline"
|
|
94
94
|
onSubmit={choice => choice === 'forget' ? onConfirmForget() : onCancel()}
|
|
@@ -109,10 +109,10 @@ export const StorageCredentialScreen: React.FC<StorageCredentialScreenProps> = (
|
|
|
109
109
|
<Select<StorageCredentialAction>
|
|
110
110
|
options={[
|
|
111
111
|
{ value: 'edit', role: 'section', prefix: '--', label: 'Credential' },
|
|
112
|
-
{ value: 'edit', label: hasCredential ? '
|
|
113
|
-
{ value: 'forget', label: '
|
|
112
|
+
{ value: 'edit', label: hasCredential ? 'Replace Credential' : 'Save Credential', hint: 'Store Pinata JWT for IPFS pinning' },
|
|
113
|
+
{ value: 'forget', label: 'Forget Credential', hint: 'Remove the local pinning token; existing pins remain', disabled: !hasCredential },
|
|
114
114
|
{ value: 'back', role: 'section', prefix: '--', label: 'Navigation' },
|
|
115
|
-
{ value: 'back', label: '
|
|
115
|
+
{ value: 'back', label: 'Back To Identity Hub', hint: 'Return without changing storage access', role: 'utility' },
|
|
116
116
|
]}
|
|
117
117
|
hintLayout="inline"
|
|
118
118
|
onSubmit={choice => {
|