ethagent 2.4.0 → 3.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/README.md +7 -4
- package/package.json +2 -1
- package/src/app/FirstRun.tsx +155 -15
- package/src/app/FirstRunTimeline.tsx +4 -0
- package/src/app/input/AppInputProvider.tsx +19 -0
- package/src/app/input/appInputParser.ts +19 -4
- package/src/chat/ChatBottomPane.tsx +3 -1
- package/src/chat/ChatScreen.tsx +7 -1
- package/src/chat/ConversationStack.tsx +25 -19
- package/src/chat/MessageList.tsx +194 -53
- package/src/chat/chatSessionState.ts +1 -1
- package/src/chat/chatTurnOrchestrator.ts +59 -0
- package/src/chat/input/ChatInput.tsx +3 -0
- package/src/chat/input/textCursor.ts +13 -3
- package/src/chat/transcript/TranscriptView.tsx +7 -5
- package/src/chat/transcript/transcriptViewport.ts +88 -17
- package/src/chat/views/PermissionPrompt.tsx +26 -26
- package/src/chat/views/PermissionsView.tsx +18 -12
- package/src/chat/views/RewindView.tsx +3 -1
- package/src/cli/ResetConfirmView.tsx +24 -9
- package/src/identity/continuity/editor.ts +27 -2
- package/src/identity/continuity/envelope.ts +125 -0
- package/src/identity/continuity/publicSkills.ts +37 -1
- package/src/identity/continuity/skills/frontmatter.ts +183 -0
- package/src/identity/continuity/skills/loadSkills.ts +609 -0
- package/src/identity/continuity/skills/publicSkillsSync.ts +32 -0
- package/src/identity/continuity/skills/scaffold.ts +52 -0
- package/src/identity/continuity/skills/types.ts +30 -0
- package/src/identity/continuity/storage/defaults.ts +28 -47
- package/src/identity/continuity/storage/files.ts +1 -0
- package/src/identity/continuity/storage/paths.ts +1 -0
- package/src/identity/continuity/storage/scaffold.ts +25 -23
- package/src/identity/continuity/storage/status.ts +34 -5
- package/src/identity/continuity/storage/types.ts +3 -2
- package/src/identity/continuity/storage.ts +3 -0
- package/src/identity/hub/OperationalRoutes.tsx +105 -3
- package/src/identity/hub/Routes.tsx +5 -3
- package/src/identity/hub/continuity/ContinuityDashboardScreen.tsx +5 -51
- package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +1 -1
- package/src/identity/hub/continuity/SavePromptScreen.tsx +1 -0
- package/src/identity/hub/continuity/effects.ts +36 -5
- package/src/identity/hub/continuity/skills/DeleteSkillConfirmScreen.tsx +112 -0
- package/src/identity/hub/continuity/skills/DeleteSkillScreen.tsx +123 -0
- package/src/identity/hub/continuity/skills/NewSkillScreen.tsx +57 -0
- package/src/identity/hub/continuity/skills/NewSkillVisibilityScreen.tsx +52 -0
- package/src/identity/hub/continuity/skills/SkillVisibilityScreen.tsx +171 -0
- package/src/identity/hub/continuity/skills/SkillsTreeScreen.tsx +213 -0
- package/src/identity/hub/continuity/snapshot.ts +3 -0
- package/src/identity/hub/continuity/state.ts +3 -2
- package/src/identity/hub/continuity/vault.ts +42 -10
- package/src/identity/hub/custody/CustodyEditFlow.tsx +3 -3
- package/src/identity/hub/identityHubReducer.ts +21 -0
- package/src/identity/hub/profile/effects.ts +16 -3
- package/src/identity/hub/restore/RestoreFlow.tsx +43 -6
- package/src/identity/hub/restore/apply.ts +12 -1
- package/src/identity/hub/restore/recovery.ts +11 -1
- package/src/identity/hub/restore/resolve.ts +1 -1
- package/src/identity/hub/restore/useRestoreEffects.ts +4 -6
- package/src/identity/hub/shared/components/DetailsScreen.tsx +4 -1
- package/src/identity/hub/shared/components/IdentitySummary.tsx +97 -53
- package/src/identity/hub/shared/components/MenuScreen.tsx +18 -15
- package/src/identity/hub/shared/components/UnlinkedIdentityScreen.tsx +1 -1
- package/src/identity/hub/shared/components/menuFlagsFromReconciliation.ts +8 -12
- package/src/identity/hub/shared/effects/sync.ts +16 -3
- package/src/identity/hub/shared/model/copy.ts +2 -4
- package/src/identity/hub/transfer/effects.ts +15 -2
- package/src/identity/hub/useIdentityHubContinuity.ts +145 -23
- package/src/identity/hub/useIdentityHubController.ts +5 -1
- package/src/identity/hub/useIdentityHubSideEffects.ts +2 -4
- package/src/mcp/manager.ts +1 -1
- package/src/models/ModelPicker.tsx +89 -84
- package/src/models/llamacpp.ts +160 -11
- package/src/models/llamacppPreflight.ts +1 -16
- package/src/models/modelPickerOptions.ts +43 -37
- package/src/providers/contracts.ts +1 -0
- package/src/providers/openai-chat.ts +50 -9
- package/src/providers/openai-responses.ts +19 -4
- package/src/runtime/toolExecution.ts +4 -3
- package/src/runtime/turn.ts +61 -30
- package/src/tools/changeDirectoryTool.ts +1 -1
- package/src/tools/contracts.ts +10 -0
- package/src/tools/deleteFileTool.ts +1 -1
- package/src/tools/editTool.ts +1 -1
- package/src/tools/listDirectoryTool.ts +1 -1
- package/src/tools/listSkillFilesTool.ts +77 -0
- package/src/tools/listSkillsTool.ts +68 -0
- package/src/tools/mcpResourceTools.ts +2 -2
- package/src/tools/privateContinuityReadTool.ts +1 -1
- package/src/tools/readSkillTool.ts +107 -0
- package/src/tools/readTool.ts +1 -1
- package/src/tools/registry.ts +6 -0
- package/src/tools/writeFileTool.ts +22 -2
- package/src/ui/Spinner.tsx +1 -1
- package/src/identity/continuity/localBackup.ts +0 -249
- package/src/identity/continuity/zipWriter.ts +0 -95
- package/src/identity/hub/continuity/index.ts +0 -7
- package/src/identity/hub/ens/index.ts +0 -11
- package/src/identity/hub/restore/index.ts +0 -22
|
@@ -6,7 +6,13 @@ import {
|
|
|
6
6
|
restoreContinuitySnapshotEnvelope,
|
|
7
7
|
transferSnapshotMetadataFromEnvelope,
|
|
8
8
|
} from '../../continuity/envelope.js'
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ensureIdentityMarkdownScaffold,
|
|
11
|
+
localContinuitySnapshotContentHashes,
|
|
12
|
+
restoreSkillsTree,
|
|
13
|
+
writeContinuityFiles,
|
|
14
|
+
} from '../../continuity/storage.js'
|
|
15
|
+
import { syncPublicSkillsManifest } from '../../continuity/skills/publicSkillsSync.js'
|
|
10
16
|
import { recordPublishedContinuitySnapshot, updatePublishedContinuitySnapshotContentHashes } from '../../continuity/snapshots.js'
|
|
11
17
|
import { catFromIpfs, DEFAULT_IPFS_API_URL } from '../../storage/ipfs.js'
|
|
12
18
|
import {
|
|
@@ -123,9 +129,13 @@ export async function runRecoveryRefetch(
|
|
|
123
129
|
} : {}),
|
|
124
130
|
}
|
|
125
131
|
await writeContinuityFiles(nextIdentity, payload.files)
|
|
132
|
+
if (payload.skills) {
|
|
133
|
+
await restoreSkillsTree(nextIdentity, payload.skills)
|
|
134
|
+
}
|
|
126
135
|
callbacks.onRestoreProgress?.({ phase: 'finishing', label: 'finalizing refreshed identity...' })
|
|
127
136
|
const publicSkillsRestored = await restorePublishedPublicSkills(nextIdentity, apiUrl, candidate.publicDiscovery?.skillsCid)
|
|
128
137
|
await ensureIdentityMarkdownScaffold(nextIdentity)
|
|
138
|
+
await syncPublicSkillsManifest(nextIdentity).catch(() => null)
|
|
129
139
|
await recordPublishedContinuitySnapshot({ identity: nextIdentity, label: 'Refetched Latest Snapshot From Chain' }).catch(() => null)
|
|
130
140
|
if (publicSkillsRestored) {
|
|
131
141
|
const contentHashes = await localContinuitySnapshotContentHashes(nextIdentity)
|
|
@@ -29,7 +29,7 @@ export async function resolveAgentEnsToCandidate(
|
|
|
29
29
|
return { ok: false, message: `Could not reach Ethereum mainnet to resolve ${trimmed}: ${err instanceof Error ? err.message : String(err)}` }
|
|
30
30
|
}
|
|
31
31
|
const tokenValue = records[AGENT_RECORD_KEYS.token]
|
|
32
|
-
if (!tokenValue) return { ok: false, message: `${trimmed} has no org.ethagent.token record
|
|
32
|
+
if (!tokenValue) return { ok: false, message: `${trimmed} has no org.ethagent.token record.` }
|
|
33
33
|
const tokenRef = parseAgentTokenReference(tokenValue)
|
|
34
34
|
if (!tokenRef) return { ok: false, message: `${trimmed}'s org.ethagent.token record is not a valid eip155 reference.` }
|
|
35
35
|
if (tokenRef.chainId !== registry.chainId) {
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { useEffect } from 'react'
|
|
2
2
|
import type { EthagentConfig } from '../../../storage/config.js'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
runRestoreFetch,
|
|
8
|
-
} from './index.js'
|
|
3
|
+
import { runRestoreAuthorize } from './apply.js'
|
|
4
|
+
import { runRestoreConnectWallet } from './auth.js'
|
|
5
|
+
import { runRestoreDiscover } from './discover.js'
|
|
6
|
+
import { runRestoreFetch } from './fetch.js'
|
|
9
7
|
import type { EffectCallbacks } from '../shared/effects/types.js'
|
|
10
8
|
import type { Step } from '../identityHubReducer.js'
|
|
11
9
|
|
|
@@ -6,12 +6,14 @@ import { Select, type SelectOption } from '../../../../ui/Select.js'
|
|
|
6
6
|
import type { EthagentConfig, EthagentIdentity } from '../../../../storage/config.js'
|
|
7
7
|
import { copyableIdentityFields, identityValuesCopyHint } from '../model/copy.js'
|
|
8
8
|
import { IdentitySummary } from './IdentitySummary.js'
|
|
9
|
+
import type { ContinuityWorkingTreeStatus } from '../../../continuity/storage.js'
|
|
9
10
|
|
|
10
11
|
type CopyAction = `copy:${string}` | 'back'
|
|
11
12
|
|
|
12
13
|
type DetailsScreenProps = {
|
|
13
14
|
identity?: EthagentIdentity
|
|
14
15
|
config?: EthagentConfig
|
|
16
|
+
workingStatus?: ContinuityWorkingTreeStatus | null
|
|
15
17
|
copyNotice?: string | null
|
|
16
18
|
unlinked?: boolean
|
|
17
19
|
onchainOwner?: string
|
|
@@ -23,6 +25,7 @@ type DetailsScreenProps = {
|
|
|
23
25
|
export const DetailsScreen: React.FC<DetailsScreenProps> = ({
|
|
24
26
|
identity,
|
|
25
27
|
config,
|
|
28
|
+
workingStatus,
|
|
26
29
|
copyNotice,
|
|
27
30
|
unlinked,
|
|
28
31
|
onchainOwner,
|
|
@@ -45,7 +48,7 @@ export const DetailsScreen: React.FC<DetailsScreenProps> = ({
|
|
|
45
48
|
|
|
46
49
|
return (
|
|
47
50
|
<Surface title="Token Values" subtitle={unlinked ? 'Token no longer linked to this wallet, values retained for reference.' : `${identityValuesCopyHint(identity)}.`} footer={footer}>
|
|
48
|
-
<IdentitySummary identity={identity} config={config} onchainOwner={onchainOwner} />
|
|
51
|
+
<IdentitySummary identity={identity} config={config} workingStatus={workingStatus} onchainOwner={onchainOwner} />
|
|
49
52
|
{copyNotice ? <Text color={theme.accentPeriwinkle} bold>{copyNotice}</Text> : null}
|
|
50
53
|
<Box marginTop={1}>
|
|
51
54
|
<Select<CopyAction>
|
|
@@ -67,59 +67,67 @@ export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, conf
|
|
|
67
67
|
<Text color={identity.agentId ? theme.text : theme.dim} bold={Boolean(identity.agentId)}>{tokenLine}</Text>
|
|
68
68
|
</>
|
|
69
69
|
)}
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<Text color={theme.dim}>{'Owner'.padEnd(12)}</Text>
|
|
87
|
-
<Text color={theme.text}>{shortAddress(ownerAddress)}</Text>
|
|
88
|
-
</Text>
|
|
89
|
-
) : null}
|
|
70
|
+
<SummaryRow
|
|
71
|
+
left={{
|
|
72
|
+
label: 'ENS',
|
|
73
|
+
value: ensStatus.kind === 'linked'
|
|
74
|
+
? <Text color={theme.accentPeriwinkle}>{ensStatus.name}</Text>
|
|
75
|
+
: ensStatus.kind === 'issue'
|
|
76
|
+
? <Text color={theme.accentError}>{ensStatus.name} ({ensValidationReasonText(ensStatus.reason)})</Text>
|
|
77
|
+
: <Text color={theme.dim}>Not Linked</Text>,
|
|
78
|
+
}}
|
|
79
|
+
right={tokenLinked
|
|
80
|
+
? {
|
|
81
|
+
label: 'Custody',
|
|
82
|
+
value: <Text color={custodyMode ? theme.text : theme.dim}>{displayCustodyMode(custodyMode)}</Text>,
|
|
83
|
+
}
|
|
84
|
+
: undefined}
|
|
85
|
+
/>
|
|
90
86
|
{(() => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
const vaultAddress = custodyMode === 'advanced'
|
|
88
|
+
? readIdentityStateString(identity.state, 'operatorVaultAddress')
|
|
89
|
+
: undefined
|
|
90
|
+
const pairedOperatorsValue = custodyMode === 'advanced' && tokenLinked
|
|
91
|
+
? approvedOperatorCount > 1
|
|
92
|
+
? <Text color={theme.text}>{`${approvedOperatorCount} authorized`}</Text>
|
|
93
|
+
: activeOperator
|
|
94
|
+
? <Text color={theme.text}>{shortAddress(activeOperator)}</Text>
|
|
95
|
+
: <Text color={theme.dim}>None Authorized</Text>
|
|
96
|
+
: null
|
|
97
|
+
const lastSavedCell = {
|
|
98
|
+
label: 'Last Saved',
|
|
99
|
+
value: <Text color={lastBackup === 'never' ? theme.dim : theme.text}>{displayValue(lastBackup)}</Text>,
|
|
100
|
+
}
|
|
101
|
+
const pendingCell = {
|
|
102
|
+
label: 'Pending',
|
|
103
|
+
value: <Text color={theme.dim}>local ahead of chain, owner rotates pointer</Text>,
|
|
104
|
+
}
|
|
94
105
|
return (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
<>
|
|
107
|
+
{ownerAddress ? (
|
|
108
|
+
<SummaryRow
|
|
109
|
+
left={{
|
|
110
|
+
label: 'Owner',
|
|
111
|
+
value: <Text color={theme.text}>{shortAddress(ownerAddress)}</Text>,
|
|
112
|
+
}}
|
|
113
|
+
{...(pairedOperatorsValue
|
|
114
|
+
? { right: { label: 'Operators', value: pairedOperatorsValue } }
|
|
115
|
+
: {})}
|
|
116
|
+
/>
|
|
117
|
+
) : null}
|
|
118
|
+
{vaultAddress ? (
|
|
119
|
+
<SummaryRow
|
|
120
|
+
left={{ label: 'Vault', value: <Text color={theme.text}>{shortAddress(vaultAddress)}</Text> }}
|
|
121
|
+
right={hasPendingPublish(identity) ? pendingCell : lastSavedCell}
|
|
122
|
+
/>
|
|
123
|
+
) : (
|
|
124
|
+
hasPendingPublish(identity)
|
|
125
|
+
? <SummaryRow left={lastSavedCell} right={pendingCell} />
|
|
126
|
+
: <SummaryRow left={lastSavedCell} />
|
|
127
|
+
)}
|
|
128
|
+
</>
|
|
99
129
|
)
|
|
100
130
|
})()}
|
|
101
|
-
{tokenLinked && custodyMode === 'advanced' ? (
|
|
102
|
-
<Text>
|
|
103
|
-
<Text color={theme.dim}>{'Operators'.padEnd(12)}</Text>
|
|
104
|
-
{approvedOperatorCount > 1 ? (
|
|
105
|
-
<Text color={theme.text}>{`${approvedOperatorCount} authorized${activeOperator ? ` (active ${shortAddress(activeOperator)})` : ''}`}</Text>
|
|
106
|
-
) : activeOperator ? (
|
|
107
|
-
<Text color={theme.text}>{shortAddress(activeOperator)}</Text>
|
|
108
|
-
) : (
|
|
109
|
-
<Text color={theme.dim}>None Authorized</Text>
|
|
110
|
-
)}
|
|
111
|
-
</Text>
|
|
112
|
-
) : null}
|
|
113
|
-
<Text>
|
|
114
|
-
<Text color={theme.dim}>{'Last Saved'.padEnd(12)}</Text>
|
|
115
|
-
<Text color={lastBackup === 'never' ? theme.dim : theme.text}>{displayValue(lastBackup)}</Text>
|
|
116
|
-
</Text>
|
|
117
|
-
{hasPendingPublish(identity) ? (
|
|
118
|
-
<Text>
|
|
119
|
-
<Text color={theme.dim}>{'Pending'.padEnd(12)}</Text>
|
|
120
|
-
<Text color={theme.dim}>local snapshot ahead of chain, owner wallet rotates the pointer</Text>
|
|
121
|
-
</Text>
|
|
122
|
-
) : null}
|
|
123
131
|
{transferSnapshot ? (
|
|
124
132
|
<Box marginTop={1}>
|
|
125
133
|
<TransferSnapshotStatus status={transferSnapshot} />
|
|
@@ -134,6 +142,39 @@ export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, conf
|
|
|
134
142
|
)
|
|
135
143
|
}
|
|
136
144
|
|
|
145
|
+
type SummaryCell = { label: string; value: React.ReactNode }
|
|
146
|
+
|
|
147
|
+
const LEFT_LABEL_WIDTH = 12
|
|
148
|
+
const LEFT_VALUE_WIDTH = 30
|
|
149
|
+
const RIGHT_CELL_WIDTH = 36
|
|
150
|
+
|
|
151
|
+
const SummaryRow: React.FC<{ left: SummaryCell; right?: SummaryCell }> = ({ left, right }) => {
|
|
152
|
+
if (!right) {
|
|
153
|
+
return (
|
|
154
|
+
<Text>
|
|
155
|
+
<Text color={theme.dim}>{left.label.padEnd(LEFT_LABEL_WIDTH)}</Text>
|
|
156
|
+
{left.value}
|
|
157
|
+
</Text>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
return (
|
|
161
|
+
<Box flexDirection="row">
|
|
162
|
+
<Box width={LEFT_LABEL_WIDTH + LEFT_VALUE_WIDTH}>
|
|
163
|
+
<Text>
|
|
164
|
+
<Text color={theme.dim}>{left.label.padEnd(LEFT_LABEL_WIDTH)}</Text>
|
|
165
|
+
{left.value}
|
|
166
|
+
</Text>
|
|
167
|
+
</Box>
|
|
168
|
+
<Box width={RIGHT_CELL_WIDTH}>
|
|
169
|
+
<Text>
|
|
170
|
+
<Text color={theme.dim}>{right.label.padEnd(LEFT_LABEL_WIDTH)}</Text>
|
|
171
|
+
{right.value}
|
|
172
|
+
</Text>
|
|
173
|
+
</Box>
|
|
174
|
+
</Box>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
137
178
|
const TransferSnapshotStatus: React.FC<{ status: NonNullable<TransferSnapshotView> }> = ({ status }) => {
|
|
138
179
|
const receiverLabel = status.receiverHandle && status.receiverHandle !== status.receiver
|
|
139
180
|
? `${shortAddress(status.receiver)} (${status.receiverHandle})`
|
|
@@ -163,10 +204,13 @@ const TransferSnapshotStatus: React.FC<{ status: NonNullable<TransferSnapshotVie
|
|
|
163
204
|
const LocalChangeStatusLine: React.FC<{ status: LocalChangeStatusView }> = ({ status }) => {
|
|
164
205
|
if (status.hasLocalChanges) {
|
|
165
206
|
return (
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
207
|
+
<Box flexDirection="column">
|
|
208
|
+
<Text color={theme.accentError} bold>
|
|
209
|
+
Local changes detected
|
|
210
|
+
{status.files.length > 0 ? `: ${status.files.join(', ')}` : ''}
|
|
211
|
+
</Text>
|
|
212
|
+
<Text color={theme.dim}>Save Snapshot Now to publish.</Text>
|
|
213
|
+
</Box>
|
|
170
214
|
)
|
|
171
215
|
}
|
|
172
216
|
|
|
@@ -28,6 +28,7 @@ type MenuScreenProps = {
|
|
|
28
28
|
onEnsName: () => void
|
|
29
29
|
onWalletSetup: () => void
|
|
30
30
|
onContinuity: () => void
|
|
31
|
+
onSkillsTree: () => void
|
|
31
32
|
onIdentityValues: () => void
|
|
32
33
|
onPrepareTransfer: () => void
|
|
33
34
|
onStorage: () => void
|
|
@@ -40,6 +41,7 @@ type Action =
|
|
|
40
41
|
| 'ens-name'
|
|
41
42
|
| 'wallet-setup'
|
|
42
43
|
| 'continuity'
|
|
44
|
+
| 'skills-tree'
|
|
43
45
|
| 'backup'
|
|
44
46
|
| 'refetch'
|
|
45
47
|
| 'identity-values'
|
|
@@ -66,6 +68,7 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
66
68
|
onEnsName,
|
|
67
69
|
onWalletSetup,
|
|
68
70
|
onContinuity,
|
|
71
|
+
onSkillsTree,
|
|
69
72
|
onIdentityValues,
|
|
70
73
|
onPrepareTransfer,
|
|
71
74
|
onStorage,
|
|
@@ -91,47 +94,46 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
91
94
|
: null)
|
|
92
95
|
|
|
93
96
|
const walletSetupBaseHint = custodyMode === 'advanced'
|
|
94
|
-
? '
|
|
95
|
-
: 'Simple
|
|
97
|
+
? 'Owner wallet, vault, operators'
|
|
98
|
+
: 'Simple mode, switch for vault delegation'
|
|
96
99
|
|
|
97
100
|
const walletSetupLabel = flags?.custodyAsterisk ? 'Custody Mode *' : 'Custody Mode'
|
|
98
101
|
const walletSetupHint = flags?.custodyModeReason ?? flags?.custodyHint ?? walletSetupBaseHint
|
|
99
102
|
|
|
100
|
-
const saveSnapshotLabel = flags?.saveSnapshotAsterisk ? 'Save Snapshot
|
|
101
|
-
const saveSnapshotHint = flags?.saveSnapshotHint ?? '
|
|
103
|
+
const saveSnapshotLabel = flags?.saveSnapshotAsterisk ? 'Save Snapshot *' : 'Save Snapshot'
|
|
104
|
+
const saveSnapshotHint = flags?.saveSnapshotHint ?? 'Publish encrypted snapshot'
|
|
102
105
|
|
|
103
|
-
const ensNameHint = flags?.ensNameReason ?? 'Public name or subdomain
|
|
106
|
+
const ensNameHint = flags?.ensNameReason ?? 'Public name or subdomain'
|
|
104
107
|
|
|
105
|
-
const prepareTransferHint = flags?.prepareTransferReason ?? '
|
|
108
|
+
const prepareTransferHint = flags?.prepareTransferReason ?? 'Hand off this agent'
|
|
106
109
|
|
|
107
110
|
const tokenValuesHint = flags?.tokenValuesUnlinkedNote ?? identityValuesCopyHint(identity)
|
|
108
111
|
|
|
109
112
|
const options: Array<SelectOption<Action>> = identity
|
|
110
113
|
? [
|
|
111
114
|
{ value: 'public-profile', role: 'section', label: 'Public Identity' },
|
|
112
|
-
{ value: 'public-profile', label: 'Public Profile', hint: '
|
|
115
|
+
{ value: 'public-profile', label: 'Public Profile', hint: 'Identity card and profile fields' },
|
|
113
116
|
{ value: 'ens-name', label: 'ENS Name', hint: ensNameHint, disabled: flags?.ensNameDisabled ?? false },
|
|
114
117
|
{ value: 'continuity', role: 'section', label: 'Continuity' },
|
|
115
|
-
{ value: 'continuity', label: 'Soul
|
|
118
|
+
{ value: 'continuity', label: 'Soul & Memory', hint: 'Edit SOUL.md and MEMORY.md' },
|
|
119
|
+
{ value: 'skills-tree', label: 'Skills', hint: 'Browse and edit SKILL.md files' },
|
|
116
120
|
{ value: 'backup', label: saveSnapshotLabel, hint: saveSnapshotHint, disabled: !canRebackup || (flags?.saveSnapshotDisabled ?? false) },
|
|
117
|
-
{ value: 'refetch', label: 'Refetch
|
|
121
|
+
{ value: 'refetch', label: 'Refetch Snapshot', hint: 'Restore latest snapshot', disabled: !canRefetch || (flags?.refetchLatestDisabled ?? false) },
|
|
118
122
|
{ value: 'wallet-setup', role: 'section', label: 'Custody' },
|
|
119
123
|
{ value: 'wallet-setup', label: walletSetupLabel, hint: walletSetupHint, disabled: !identity.agentId || (flags?.custodyModeDisabled ?? false) },
|
|
120
124
|
{ value: 'prepare-transfer', label: 'Prepare Transfer', hint: prepareTransferHint, disabled: flags?.prepareTransferDisabled ?? false },
|
|
121
125
|
{ value: 'identity-values', role: 'section', label: 'Token' },
|
|
122
126
|
{ value: 'identity-values', label: 'Token Values', hint: tokenValuesHint },
|
|
123
|
-
{ value: 'load', label: 'Load Agent', hint: 'Refresh
|
|
124
|
-
{ value: 'create', label: 'New Agent', hint: 'Mint another
|
|
125
|
-
{ value: 'storage',
|
|
126
|
-
{ value: 'storage', label: 'IPFS Storage', hint: 'Publishing credentials for encrypted snapshots' },
|
|
127
|
+
{ value: 'load', label: 'Load Agent', hint: 'Refresh or load another agent' },
|
|
128
|
+
{ value: 'create', label: 'New Agent', hint: 'Mint another agent' },
|
|
129
|
+
{ value: 'storage', label: 'IPFS Storage', hint: 'Publishing credentials' },
|
|
127
130
|
{ value: 'cancel', role: 'section', label: 'Exit' },
|
|
128
|
-
{ value: 'cancel', label: 'Close Identity Hub', hint: 'Return to chat
|
|
131
|
+
{ value: 'cancel', label: 'Close Identity Hub', hint: 'Return to chat', role: 'utility' },
|
|
129
132
|
]
|
|
130
133
|
: [
|
|
131
134
|
{ value: 'create', role: 'section', label: 'Setup' },
|
|
132
135
|
{ value: 'create', label: 'Create New Agent', hint: 'Mint a wallet-owned token for this machine' },
|
|
133
136
|
{ value: 'load', label: 'Load Existing Agent', hint: 'Find a token owned by this wallet or linked to it' },
|
|
134
|
-
{ value: mode === 'first-run' ? 'skip' : 'cancel', role: 'section', label: 'Exit' },
|
|
135
137
|
...(mode === 'first-run'
|
|
136
138
|
? [
|
|
137
139
|
{ value: 'skip' as Action, label: 'Skip For Now', hint: 'Continue now, use /identity later', role: 'utility' as const },
|
|
@@ -170,6 +172,7 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
170
172
|
if (choice === 'ens-name') return onEnsName()
|
|
171
173
|
if (choice === 'wallet-setup') return onWalletSetup()
|
|
172
174
|
if (choice === 'continuity') return onContinuity()
|
|
175
|
+
if (choice === 'skills-tree') return onSkillsTree()
|
|
173
176
|
if (choice === 'backup') return onBackupNow()
|
|
174
177
|
if (choice === 'refetch') return onRefetchLatest()
|
|
175
178
|
if (choice === 'identity-values') return onIdentityValues()
|
|
@@ -43,7 +43,7 @@ export const UnlinkedIdentityScreen: React.FC<UnlinkedIdentityScreenProps> = ({
|
|
|
43
43
|
<Surface
|
|
44
44
|
title="No Linked Agent"
|
|
45
45
|
subtitle="The agent token recorded locally is not currently owned by your wallet."
|
|
46
|
-
footer={<Text color={theme.dim}>enter selects
|
|
46
|
+
footer={<Text color={theme.dim}>enter selects · esc back</Text>}
|
|
47
47
|
>
|
|
48
48
|
<Box flexDirection="column">
|
|
49
49
|
{transferSnapshot ? (
|
|
@@ -25,9 +25,9 @@ export function menuFlagsFromReconciliation(r: AgentReconciliation, perspective:
|
|
|
25
25
|
|
|
26
26
|
let prepareTransferReason: string | undefined
|
|
27
27
|
if (isOperator) {
|
|
28
|
-
prepareTransferReason = '
|
|
28
|
+
prepareTransferReason = 'Owner-only action'
|
|
29
29
|
} else if (!unlinked && (r.custody === 'advanced' || r.custody === 'mid-flow-uri-pending')) {
|
|
30
|
-
prepareTransferReason = '
|
|
30
|
+
prepareTransferReason = 'Withdraw from vault first'
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const custodyAsterisk = r.custody === 'mid-flow-uri-pending' || r.vault === 'missing'
|
|
@@ -35,17 +35,13 @@ export function menuFlagsFromReconciliation(r: AgentReconciliation, perspective:
|
|
|
35
35
|
if (isOperator) {
|
|
36
36
|
custodyHint = undefined
|
|
37
37
|
} else if (r.custody === 'mid-flow-uri-pending') {
|
|
38
|
-
custodyHint = '
|
|
38
|
+
custodyHint = 'Setup pending, open to finish'
|
|
39
39
|
} else if (r.vault === 'missing') {
|
|
40
|
-
custodyHint = 'Vault
|
|
40
|
+
custodyHint = 'Vault missing, open to redeploy'
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const custodyModeReason = isOperator
|
|
44
|
-
|
|
45
|
-
: undefined
|
|
46
|
-
const ensNameReason = isOperator
|
|
47
|
-
? 'Operators cannot change the ENS subdomain or its records.'
|
|
48
|
-
: undefined
|
|
43
|
+
const custodyModeReason = isOperator ? 'Owner-only action' : undefined
|
|
44
|
+
const ensNameReason = isOperator ? 'Owner-only action' : undefined
|
|
49
45
|
|
|
50
46
|
return {
|
|
51
47
|
prepareTransferDisabled: unlinked || inVault || isOperator,
|
|
@@ -56,11 +52,11 @@ export function menuFlagsFromReconciliation(r: AgentReconciliation, perspective:
|
|
|
56
52
|
...(ensNameReason ? { ensNameReason } : {}),
|
|
57
53
|
saveSnapshotDisabled: unlinked,
|
|
58
54
|
refetchLatestDisabled: unlinked,
|
|
59
|
-
...(unlinked ? { tokenValuesUnlinkedNote: '
|
|
55
|
+
...(unlinked ? { tokenValuesUnlinkedNote: 'Unlinked, retained for reference' } : {}),
|
|
60
56
|
|
|
61
57
|
custodyAsterisk: custodyAsterisk && !isOperator,
|
|
62
58
|
...(custodyHint ? { custodyHint } : {}),
|
|
63
59
|
saveSnapshotAsterisk: r.agentUri === 'local-newer',
|
|
64
|
-
...(r.agentUri === 'local-newer' ? { saveSnapshotHint: 'Local
|
|
60
|
+
...(r.agentUri === 'local-newer' ? { saveSnapshotHint: 'Local newer than chain' } : {}),
|
|
65
61
|
}
|
|
66
62
|
}
|
|
@@ -16,7 +16,11 @@ import {
|
|
|
16
16
|
} from '../reconciliation/index.js'
|
|
17
17
|
import { normalizeApprovedOperatorWallets } from '../operatorWallets.js'
|
|
18
18
|
import { readOwnerAddressField } from '../../../identityCompat.js'
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
continuitySnapshotContentHashesFromSources,
|
|
21
|
+
localContinuitySnapshotContentHashes,
|
|
22
|
+
} from '../../../continuity/storage.js'
|
|
23
|
+
import type { ContinuityFiles, ContinuitySkillsTree } from '../../../continuity/envelope.js'
|
|
20
24
|
import { updatePublishedContinuitySnapshotContentHashes } from '../../../continuity/snapshots.js'
|
|
21
25
|
import type { EffectCallbacks } from './types.js'
|
|
22
26
|
import { awaitConfirmedReceipt } from './receipts.js'
|
|
@@ -141,9 +145,18 @@ export async function syncVaultMetadataOperatorsAfterOwnerSave(args: {
|
|
|
141
145
|
}
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
export async function markCurrentContinuityFilesPublished(
|
|
148
|
+
export async function markCurrentContinuityFilesPublished(
|
|
149
|
+
identity: EthagentIdentity,
|
|
150
|
+
publishedSources?: {
|
|
151
|
+
privateFiles: ContinuityFiles
|
|
152
|
+
publicSkills: string
|
|
153
|
+
skills: ContinuitySkillsTree
|
|
154
|
+
},
|
|
155
|
+
): Promise<void> {
|
|
145
156
|
const cid = identity.backup?.cid
|
|
146
157
|
if (!cid) return
|
|
147
|
-
const contentHashes =
|
|
158
|
+
const contentHashes = publishedSources
|
|
159
|
+
? continuitySnapshotContentHashesFromSources(publishedSources)
|
|
160
|
+
: await localContinuitySnapshotContentHashes(identity)
|
|
148
161
|
await updatePublishedContinuitySnapshotContentHashes(identity, cid, contentHashes).catch(() => null)
|
|
149
162
|
}
|
|
@@ -28,8 +28,6 @@ export function copyableIdentityFields(identity?: EthagentIdentity, config?: Eth
|
|
|
28
28
|
return fields
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export function identityValuesCopyHint(
|
|
32
|
-
return
|
|
33
|
-
? 'Copy token, ENS, and token URI pointers'
|
|
34
|
-
: 'Copy token and token URI pointers'
|
|
31
|
+
export function identityValuesCopyHint(_identity?: EthagentIdentity): string {
|
|
32
|
+
return 'Copy token and pointers'
|
|
35
33
|
}
|
|
@@ -9,15 +9,21 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
continuityAgentSnapshot,
|
|
11
11
|
continuityVaultStatus,
|
|
12
|
+
prepareSyncedSkillsTree,
|
|
12
13
|
readContinuityFiles,
|
|
13
14
|
readPublicSkillsFile,
|
|
14
15
|
writePublicSkillsFile,
|
|
15
16
|
} from '../../continuity/storage.js'
|
|
16
17
|
import {
|
|
18
|
+
appendPublicSkillEntries,
|
|
17
19
|
createAgentCard,
|
|
18
20
|
defaultPublicSkillsProfile,
|
|
19
21
|
serializeAgentCard,
|
|
20
22
|
} from '../../continuity/publicSkills.js'
|
|
23
|
+
import {
|
|
24
|
+
derivePublicSkillEntries,
|
|
25
|
+
syncPublicSkillsManifest,
|
|
26
|
+
} from '../../continuity/skills/publicSkillsSync.js'
|
|
21
27
|
import { recordPublishedContinuitySnapshot } from '../../continuity/snapshots.js'
|
|
22
28
|
import { addToIpfs, DEFAULT_IPFS_API_URL, isPinataUploadUrl } from '../../storage/ipfs.js'
|
|
23
29
|
import {
|
|
@@ -161,16 +167,22 @@ export async function runTokenTransferSigning(
|
|
|
161
167
|
}
|
|
162
168
|
const nextIdentityForFiles: EthagentIdentity = { ...step.identity, state }
|
|
163
169
|
const continuityFiles = await readContinuityFiles(nextIdentityForFiles)
|
|
164
|
-
const publicSkillsJson = await
|
|
170
|
+
const publicSkillsJson = await syncPublicSkillsManifest(nextIdentityForFiles)
|
|
165
171
|
const publicSkillsPin = await addToIpfs(DEFAULT_IPFS_API_URL, publicSkillsJson, fetch, { pinataJwt: step.pinataJwt })
|
|
166
172
|
assertVerifiedPin(publicSkillsPin)
|
|
173
|
+
const publicSkillEntries = await derivePublicSkillEntries(nextIdentityForFiles)
|
|
174
|
+
const augmentedPublicProfile = appendPublicSkillEntries(
|
|
175
|
+
defaultPublicSkillsProfile(nextIdentityForFiles),
|
|
176
|
+
publicSkillEntries,
|
|
177
|
+
)
|
|
167
178
|
const agentCardPin = await addToIpfs(
|
|
168
179
|
DEFAULT_IPFS_API_URL,
|
|
169
|
-
serializeAgentCard(createAgentCard(
|
|
180
|
+
serializeAgentCard(createAgentCard(augmentedPublicProfile)),
|
|
170
181
|
fetch,
|
|
171
182
|
{ pinataJwt: step.pinataJwt },
|
|
172
183
|
)
|
|
173
184
|
assertVerifiedPin(agentCardPin)
|
|
185
|
+
const skillsTree = await prepareSyncedSkillsTree(nextIdentityForFiles)
|
|
174
186
|
const envelope = createTransferContinuitySnapshotEnvelope({
|
|
175
187
|
ownerAddress,
|
|
176
188
|
ownerWalletSignature: senderSignature.signature,
|
|
@@ -181,6 +193,7 @@ export async function runTokenTransferSigning(
|
|
|
181
193
|
payload: {
|
|
182
194
|
agent: continuityAgentSnapshot(nextIdentityForFiles),
|
|
183
195
|
files: continuityFiles,
|
|
196
|
+
...(Object.keys(skillsTree).length > 0 ? { skills: skillsTree } : {}),
|
|
184
197
|
transcript: [],
|
|
185
198
|
state,
|
|
186
199
|
},
|