ethagent 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/package.json +1 -2
  2. package/src/chat/ChatScreen.tsx +5 -4
  3. package/src/chat/ContinuityEditReviewView.tsx +3 -3
  4. package/src/chat/commands.ts +5 -5
  5. package/src/cli/ResetConfirmView.tsx +12 -13
  6. package/src/cli/main.tsx +27 -30
  7. package/src/cli/reset.ts +7 -8
  8. package/src/cli/updateNotice.ts +52 -0
  9. package/src/identity/continuity/envelope.ts +11 -5
  10. package/src/identity/continuity/storage.ts +1 -1
  11. package/src/identity/hub/IdentityHub.tsx +6 -7
  12. package/src/identity/hub/identityHubModel.ts +12 -12
  13. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +39 -34
  14. package/src/identity/hub/screens/CreateFlow.tsx +4 -4
  15. package/src/identity/hub/screens/DetailsScreen.tsx +2 -2
  16. package/src/identity/hub/screens/EditProfileFlow.tsx +5 -5
  17. package/src/identity/hub/screens/ErrorScreen.tsx +2 -2
  18. package/src/identity/hub/screens/IdentitySummary.tsx +32 -12
  19. package/src/identity/hub/screens/MenuScreen.tsx +17 -17
  20. package/src/identity/hub/screens/NetworkScreen.tsx +7 -3
  21. package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +9 -7
  22. package/src/identity/hub/screens/RestoreFlow.tsx +2 -2
  23. package/src/identity/hub/screens/StorageCredentialScreen.tsx +5 -5
  24. package/src/identity/wallet/wallet-page/wallet.html +1095 -966
  25. package/src/models/ModelPicker.tsx +71 -71
  26. package/src/models/llamacppPreflight.ts +1 -1
  27. package/src/models/modelPickerOptions.ts +22 -22
  28. package/src/storage/factoryReset.ts +17 -20
  29. package/src/tools/privateContinuityEditTool.ts +1 -1
  30. package/src/ui/BrandSplash.tsx +7 -4
@@ -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' | 'backup' | 'back'
11
- type PublicAction = 'edit' | 'skills' | 'publish' | 'back'
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 &gt; Save Snapshot Now &gt; 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 local files' },
46
- { value: 'soul', label: 'open SOUL.md', hint: 'edit persona and operating preferences', disabled: !ready },
47
- { value: 'memory', label: 'open MEMORY.md', hint: 'edit private working memory for this agent', disabled: !ready },
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: 'back to identity hub', hint: 'return without changing private files', role: 'utility' },
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
- onPublish: () => void
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: 'edit name, description, image', hint: 'upload a local image to IPFS automatically' },
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: 'open skills.json', hint: 'edit public capabilities and notes' },
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: 'back to identity hub', hint: 'return without changing public metadata', role: 'utility' },
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}>{'local files'.padEnd(13)}</Text>
104
- <Text color={ready ? theme.text : theme.dim}>{ready ? 'SOUL.md and MEMORY.md ready' : 'missing local working files'}</Text>
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}>{'snapshot'.padEnd(13)}</Text>
108
- <Text color={identity?.backup?.cid ? theme.text : theme.dim}>{identity?.backup?.cid ? shortCid(identity.backup.cid) : 'not saved yet'}</Text>
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) : 'not published'}</Text>
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}>{'agent card'.padEnd(13)}</Text>
121
- <Text color={identity?.publicSkills?.agentCardCid ? theme.text : theme.dim}>{identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : 'not published'}</Text>
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}>{'image'.padEnd(13)}</Text>
125
- <Text color={readStateString(identity?.state, 'imageUrl') ? theme.text : theme.dim}>{readStateString(identity?.state, 'imageUrl') ? 'attached' : 'not attached'}</Text>
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 "refetch latest snapshot" from the hub menu to recover files.'
138
+ : 'Use "Refetch Latest Snapshot" from the 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 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' },
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: 'no values available yet' }] : []),
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: 'back to identity hub', hint: 'return without copying', role: 'utility' },
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: '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: 'publish without changing the image' },
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: 'back', hint: 'return to description', role: 'utility' },
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: 'go back', hint: 'return to the previous identity step' },
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: 'close hub', hint: 'return to the chat without retrying', role: 'utility' },
25
+ { value: 'close', label: 'Close 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}>no agent yet. create or load one.</Text>
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: 'unsaved changes', 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 }
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: '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 },
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: 'skills', value: row('skills')?.value ?? 'not published', tone: row('skills')?.tone ?? 'dim' },
52
- { label: 'agent card', value: row('card')?.value ?? 'not published', tone: row('card')?.tone ?? 'dim' },
53
- { label: 'image', value: row('image')?.value ?? 'not attached', tone: row('image')?.tone ?? 'dim' },
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 || 'active agent'}</Text>
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' : '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 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' },
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: 'save snapshot now', hint: 'publishes SOUL.md, MEMORY.md, skills.json, and metadata', disabled: !canRebackup },
73
- { value: 'refetch', label: 'refetch latest snapshot', hint: 'restore local files from the latest published snapshot', disabled: !canRefetch },
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 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' },
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: 'close hub', hint: 'return to the chat without changing identity', role: 'utility' },
81
+ { value: 'cancel', label: 'Close 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: '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' },
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: 'skip for now', hint: 'continue now; use /identity later', role: 'utility' as const }]
90
- : [{ value: 'cancel' as Action, label: 'close hub', hint: 'return to the chat without changing identity', role: 'utility' as const }]),
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 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 network' },
17
+ { value: 'mainnet', role: 'section', prefix: '--', label: 'Main Network' },
18
18
  networkOption('mainnet'),
19
- { value: 'arbitrum', role: 'section', prefix: '--', label: 'Lower-fee networks' },
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
- ? 'This replaces the current on-chain snapshot pointer.'
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 replaces the on-chain pointer for this agent.'
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
- ? 'The old snapshot pointer is overwritten. Local edits become the saved state.'
32
- : 'Unsaved local edits will be lost. Use this when local files are missing or out of sync with the latest published snapshot.'
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 color={theme.textSubtle}>unsaved changes: </Text>
54
- <Text color="red" bold>{changedFiles.join(', ')}</Text>
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 overwrite the on-chain pointer' : 'Wallet decrypts and overwrites local files',
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: 'connect wallet', hint: 'search tokens owned by browser wallet' },
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 agents' },
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: 'forget credential', hint: 'remove local IPFS pinning token' },
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: 'keep credential', hint: 'return without changing storage access', role: 'utility' },
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 ? '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 },
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: 'back to identity hub', hint: 'return without changing storage access', role: 'utility' },
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 => {