ethagent 3.0.0 → 3.0.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/package.json +1 -1
- package/src/identity/continuity/envelope.ts +9 -9
- package/src/identity/continuity/publicSkills.ts +17 -0
- package/src/identity/hub/OperationalRoutes.tsx +11 -39
- package/src/identity/hub/continuity/ContinuityDashboardScreen.tsx +3 -23
- package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +5 -5
- package/src/identity/hub/continuity/SavePromptScreen.tsx +1 -3
- package/src/identity/hub/continuity/skills/SkillActionsScreen.tsx +151 -0
- package/src/identity/hub/continuity/skills/SkillsTreeScreen.tsx +1 -33
- package/src/identity/hub/continuity/state.ts +9 -9
- package/src/identity/hub/create/CreateFlow.tsx +1 -1
- package/src/identity/hub/custody/routes.tsx +1 -1
- package/src/identity/hub/ens/EnsEditAdvancedScreens.tsx +0 -1
- package/src/identity/hub/ens/EnsEditMaintenanceScreens.tsx +0 -1
- package/src/identity/hub/identityHubReducer.ts +3 -9
- package/src/identity/hub/profile/EditProfileFlow.tsx +5 -5
- package/src/identity/hub/restore/recovery.ts +3 -3
- package/src/identity/hub/shared/components/IdentitySummary.tsx +22 -2
- package/src/identity/hub/shared/components/MenuScreen.tsx +4 -4
- package/src/identity/hub/shared/components/UnlinkedIdentityScreen.tsx +3 -3
- package/src/identity/hub/shared/components/menuFlagsFromReconciliation.ts +1 -1
- package/src/identity/hub/useIdentityHubContinuity.ts +3 -3
- package/src/identity/wallet/page/copy.ts +43 -43
- package/src/models/modelPickerOptions.ts +2 -0
- package/src/identity/hub/continuity/skills/DeleteSkillScreen.tsx +0 -123
- package/src/identity/hub/continuity/skills/SkillVisibilityScreen.tsx +0 -171
|
@@ -62,10 +62,8 @@ export type Step =
|
|
|
62
62
|
| { kind: 'continuity-skills-tree'; notice?: string; editorOpened?: boolean }
|
|
63
63
|
| { kind: 'continuity-skill-new'; error?: string }
|
|
64
64
|
| { kind: 'continuity-skill-new-visibility'; name: string; error?: string }
|
|
65
|
-
| { kind: 'continuity-skill-
|
|
65
|
+
| { kind: 'continuity-skill-actions'; relativePath: string; notice?: string }
|
|
66
66
|
| { kind: 'continuity-skill-delete-confirm'; target: { kind: 'skill'; relativePath: string } }
|
|
67
|
-
| { kind: 'continuity-skill-visibility'; notice?: string }
|
|
68
|
-
| { kind: 'continuity-skill-visibility-pick'; relativePath: string }
|
|
69
67
|
| { kind: 'rebackup-confirm'; back: Step }
|
|
70
68
|
| { kind: 'recovery-refetch-confirm'; back: Step }
|
|
71
69
|
| { kind: 'recovery-refetching'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; back: Step }
|
|
@@ -186,14 +184,10 @@ function backStep(from: Step): Step {
|
|
|
186
184
|
return { kind: 'continuity-skills-tree' }
|
|
187
185
|
case 'continuity-skill-new-visibility':
|
|
188
186
|
return { kind: 'continuity-skill-new' }
|
|
189
|
-
case 'continuity-skill-
|
|
187
|
+
case 'continuity-skill-actions':
|
|
190
188
|
return { kind: 'continuity-skills-tree' }
|
|
191
189
|
case 'continuity-skill-delete-confirm':
|
|
192
|
-
return { kind: 'continuity-skill-
|
|
193
|
-
case 'continuity-skill-visibility':
|
|
194
|
-
return { kind: 'continuity-skills-tree' }
|
|
195
|
-
case 'continuity-skill-visibility-pick':
|
|
196
|
-
return { kind: 'continuity-skill-visibility' }
|
|
190
|
+
return { kind: 'continuity-skill-actions', relativePath: from.target.relativePath }
|
|
197
191
|
case 'rebackup-confirm':
|
|
198
192
|
case 'recovery-refetch-confirm':
|
|
199
193
|
case 'recovery-refetching':
|
|
@@ -57,7 +57,7 @@ export const EditProfileFlow: React.FC<EditProfileFlowProps> = ({
|
|
|
57
57
|
const currentName = step.name ?? readIdentityStateString(step.identity.state, 'name')
|
|
58
58
|
return (
|
|
59
59
|
<Surface
|
|
60
|
-
title="Edit
|
|
60
|
+
title="Edit Profile"
|
|
61
61
|
subtitle={<FlowTimeline steps={EDIT_PROFILE_STEPS} current={1} />}
|
|
62
62
|
footer={footerHint(EDIT_NEXT_FOOTER)}
|
|
63
63
|
>
|
|
@@ -112,7 +112,7 @@ export const EditProfileFlow: React.FC<EditProfileFlowProps> = ({
|
|
|
112
112
|
const draftDescription = step.description ?? currentDescription
|
|
113
113
|
return (
|
|
114
114
|
<Surface
|
|
115
|
-
title="Edit
|
|
115
|
+
title="Edit Profile"
|
|
116
116
|
subtitle={<FlowTimeline steps={EDIT_PROFILE_STEPS} current={2} />}
|
|
117
117
|
footer={footerHint(EDIT_DESCRIPTION_FOOTER)}
|
|
118
118
|
>
|
|
@@ -145,7 +145,7 @@ const AgentIconStep: React.FC<{
|
|
|
145
145
|
if (entryMode) {
|
|
146
146
|
return (
|
|
147
147
|
<Surface
|
|
148
|
-
title="Edit
|
|
148
|
+
title="Edit Profile"
|
|
149
149
|
subtitle={<FlowTimeline steps={EDIT_PROFILE_STEPS} current={3} />}
|
|
150
150
|
footer={footerHint(EDIT_NEXT_FOOTER)}
|
|
151
151
|
>
|
|
@@ -165,7 +165,7 @@ const AgentIconStep: React.FC<{
|
|
|
165
165
|
|
|
166
166
|
return (
|
|
167
167
|
<Surface
|
|
168
|
-
title="Edit
|
|
168
|
+
title="Edit Profile"
|
|
169
169
|
subtitle={<FlowTimeline steps={EDIT_PROFILE_STEPS} current={3} />}
|
|
170
170
|
footer={footerHint('enter select · esc back')}
|
|
171
171
|
>
|
|
@@ -208,7 +208,7 @@ const EditProfileReviewStep: React.FC<{
|
|
|
208
208
|
const currentIcon = readIdentityStateString(step.identity.state, 'imageUrl')
|
|
209
209
|
return (
|
|
210
210
|
<Surface
|
|
211
|
-
title="Edit
|
|
211
|
+
title="Edit Profile"
|
|
212
212
|
subtitle={<FlowTimeline steps={EDIT_PROFILE_STEPS} current={4} />}
|
|
213
213
|
footer={footerHint('enter save · esc back')}
|
|
214
214
|
>
|
|
@@ -78,7 +78,7 @@ export async function runRecoveryRefetch(
|
|
|
78
78
|
walletSignature: wallet.signature,
|
|
79
79
|
currentOwnerAddress: getAddress(wallet.account),
|
|
80
80
|
})
|
|
81
|
-
callbacks.onRestoreProgress?.({ phase: 'writing', label: 'restoring SOUL.md, MEMORY.md, and skills
|
|
81
|
+
callbacks.onRestoreProgress?.({ phase: 'writing', label: 'restoring SOUL.md, MEMORY.md, and skills...' })
|
|
82
82
|
const transferSnapshot = transferSnapshotMetadataFromEnvelope(envelope)
|
|
83
83
|
const refreshedBackup: BackupMetadata = {
|
|
84
84
|
cid: candidate.backup.cid,
|
|
@@ -136,10 +136,10 @@ export async function runRecoveryRefetch(
|
|
|
136
136
|
const publicSkillsRestored = await restorePublishedPublicSkills(nextIdentity, apiUrl, candidate.publicDiscovery?.skillsCid)
|
|
137
137
|
await ensureIdentityMarkdownScaffold(nextIdentity)
|
|
138
138
|
await syncPublicSkillsManifest(nextIdentity).catch(() => null)
|
|
139
|
-
await recordPublishedContinuitySnapshot({ identity: nextIdentity, label: 'Refetched Latest Snapshot From
|
|
139
|
+
await recordPublishedContinuitySnapshot({ identity: nextIdentity, label: 'Refetched Latest Snapshot From Onchain' }).catch(() => null)
|
|
140
140
|
if (publicSkillsRestored) {
|
|
141
141
|
const contentHashes = await localContinuitySnapshotContentHashes(nextIdentity)
|
|
142
142
|
await updatePublishedContinuitySnapshotContentHashes(nextIdentity, candidate.backup.cid, contentHashes).catch(() => null)
|
|
143
143
|
}
|
|
144
|
-
await callbacks.onIdentityComplete(nextIdentity, 'Latest Published Snapshot Restored From
|
|
144
|
+
await callbacks.onIdentityComplete(nextIdentity, 'Latest Published Snapshot Restored From Onchain', 'update')
|
|
145
145
|
}
|
|
@@ -28,9 +28,10 @@ interface IdentitySummaryProps {
|
|
|
28
28
|
hideHeader?: boolean
|
|
29
29
|
tokenLinked?: boolean
|
|
30
30
|
onchainOwner?: string
|
|
31
|
+
compact?: boolean
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, config, workingStatus, hideLocalChanges = false, hideHeader = false, tokenLinked = true, onchainOwner }) => {
|
|
34
|
+
export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, config, workingStatus, hideLocalChanges = false, hideHeader = false, tokenLinked = true, onchainOwner, compact = false }) => {
|
|
34
35
|
if (!identity) {
|
|
35
36
|
return (
|
|
36
37
|
<Text color={theme.dim}>No agent yet. Create or load one.</Text>
|
|
@@ -59,6 +60,25 @@ export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, conf
|
|
|
59
60
|
? `${tokenValue} · ${displayValue(networkValue)}`
|
|
60
61
|
: displayValue(tokenValue)
|
|
61
62
|
|
|
63
|
+
if (compact) {
|
|
64
|
+
const name = stateName || 'Active Agent'
|
|
65
|
+
const tokenSegment = identity.agentId ? `#${identity.agentId}` : null
|
|
66
|
+
const networkSegment = identity.agentId ? displayValue(networkValue) : null
|
|
67
|
+
const ensSegment = ensStatus.kind === 'linked'
|
|
68
|
+
? ensStatus.name
|
|
69
|
+
: ensStatus.kind === 'issue'
|
|
70
|
+
? ensStatus.name
|
|
71
|
+
: null
|
|
72
|
+
return (
|
|
73
|
+
<Text>
|
|
74
|
+
<Text color={theme.accentPeriwinkle} bold>{name}</Text>
|
|
75
|
+
{tokenSegment ? <><Text color={theme.dim}> · </Text><Text color={theme.text}>{tokenSegment}</Text></> : null}
|
|
76
|
+
{networkSegment ? <><Text color={theme.dim}> · </Text><Text color={theme.text}>{networkSegment}</Text></> : null}
|
|
77
|
+
{ensSegment ? <><Text color={theme.dim}> · </Text><Text color={ensStatus.kind === 'issue' ? theme.accentError : theme.accentPeriwinkle}>{ensSegment}</Text></> : null}
|
|
78
|
+
</Text>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
62
82
|
return (
|
|
63
83
|
<Box flexDirection="column">
|
|
64
84
|
{hideHeader ? null : (
|
|
@@ -100,7 +120,7 @@ export const IdentitySummary: React.FC<IdentitySummaryProps> = ({ identity, conf
|
|
|
100
120
|
}
|
|
101
121
|
const pendingCell = {
|
|
102
122
|
label: 'Pending',
|
|
103
|
-
value: <Text color={theme.dim}>local ahead of
|
|
123
|
+
value: <Text color={theme.dim}>local ahead of onchain, owner rotates pointer</Text>,
|
|
104
124
|
}
|
|
105
125
|
return (
|
|
106
126
|
<>
|
|
@@ -112,7 +112,7 @@ export const MenuScreen: React.FC<MenuScreenProps> = ({
|
|
|
112
112
|
const options: Array<SelectOption<Action>> = identity
|
|
113
113
|
? [
|
|
114
114
|
{ value: 'public-profile', role: 'section', label: 'Public Identity' },
|
|
115
|
-
{ value: 'public-profile', label: 'Public Profile', hint: '
|
|
115
|
+
{ value: 'public-profile', label: 'Public Profile', hint: 'Agent card and profile fields' },
|
|
116
116
|
{ value: 'ens-name', label: 'ENS Name', hint: ensNameHint, disabled: flags?.ensNameDisabled ?? false },
|
|
117
117
|
{ value: 'continuity', role: 'section', label: 'Continuity' },
|
|
118
118
|
{ value: 'continuity', label: 'Soul & Memory', hint: 'Edit SOUL.md and MEMORY.md' },
|
|
@@ -197,7 +197,7 @@ function renderReconciliationBanner(r: AgentReconciliation, identity: EthagentId
|
|
|
197
197
|
return (
|
|
198
198
|
<>
|
|
199
199
|
<Text color={theme.accentError} bold>Agent Unlinked</Text>
|
|
200
|
-
<Text color={theme.textSubtle}>{tokenLabel} was transferred. Local SOUL.md, MEMORY.md, skills
|
|
200
|
+
<Text color={theme.textSubtle}>{tokenLabel} was transferred. Local SOUL.md, MEMORY.md, and skills remain. Back them up before this directory is reused.</Text>
|
|
201
201
|
<Text color={theme.textSubtle}>Use Load Agent or New Agent to re-enable disabled actions.</Text>
|
|
202
202
|
</>
|
|
203
203
|
)
|
|
@@ -205,7 +205,7 @@ function renderReconciliationBanner(r: AgentReconciliation, identity: EthagentId
|
|
|
205
205
|
return (
|
|
206
206
|
<>
|
|
207
207
|
<Text color={theme.accentError} bold>Agent Unlinked</Text>
|
|
208
|
-
<Text color={theme.textSubtle}>{tokenLabel} left without Prepare Transfer. Back up local SOUL.md, MEMORY.md, skills
|
|
208
|
+
<Text color={theme.textSubtle}>{tokenLabel} left without Prepare Transfer. Back up local SOUL.md, MEMORY.md, and skills before loading another agent.</Text>
|
|
209
209
|
<Text color={theme.textSubtle}>For continuity handoff: ask the new holder to return the token, then run Prepare Transfer before re-sending.</Text>
|
|
210
210
|
<Text color={theme.textSubtle}>Use Load Agent or New Agent to re-enable disabled actions.</Text>
|
|
211
211
|
</>
|
|
@@ -224,7 +224,7 @@ function renderReconciliationBanner(r: AgentReconciliation, identity: EthagentId
|
|
|
224
224
|
}
|
|
225
225
|
const lines: string[] = []
|
|
226
226
|
if (r.custody === 'mid-flow-uri-pending') lines.push('Advanced setup pending. Open Custody Mode to finish.')
|
|
227
|
-
if (r.agentUri === 'local-newer') lines.push('Local state newer than
|
|
227
|
+
if (r.agentUri === 'local-newer') lines.push('Local state newer than onchain. Save Snapshot Now to publish.')
|
|
228
228
|
if (r.agentUri === 'chain-newer') lines.push('Onchain agentURI is newer than local. Refetch Latest.')
|
|
229
229
|
if (r.vault === 'missing') lines.push('Recorded vault address has no contract at it. Open Custody Mode to redeploy.')
|
|
230
230
|
if (r.workingTree === 'dirty') lines.push('Local edits pending. Save Snapshot Now to publish.')
|
|
@@ -33,7 +33,7 @@ export const UnlinkedIdentityScreen: React.FC<UnlinkedIdentityScreenProps> = ({
|
|
|
33
33
|
]
|
|
34
34
|
if (onRetry) {
|
|
35
35
|
options.push({ value: 'retry', role: 'section', label: 'Recheck' })
|
|
36
|
-
options.push({ value: 'retry', label: 'Retry Ownership Check', hint: 'Re-query
|
|
36
|
+
options.push({ value: 'retry', label: 'Retry Ownership Check', hint: 'Re-query onchain to confirm the current owner', role: 'utility' })
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
const tokenLabel = agentId ? `Token #${agentId}` : 'Token'
|
|
@@ -48,13 +48,13 @@ export const UnlinkedIdentityScreen: React.FC<UnlinkedIdentityScreenProps> = ({
|
|
|
48
48
|
<Box flexDirection="column">
|
|
49
49
|
{transferSnapshot ? (
|
|
50
50
|
<Text color={theme.textSubtle}>
|
|
51
|
-
{tokenLabel} was transferred. Local SOUL.md, MEMORY.md, skills
|
|
51
|
+
{tokenLabel} was transferred. Local SOUL.md, MEMORY.md, and skills remain. Back them up before this directory is reused.
|
|
52
52
|
</Text>
|
|
53
53
|
) : (
|
|
54
54
|
<>
|
|
55
55
|
<Text color={theme.accentPeriwinkle}>{tokenLabel} left this wallet without Prepare Transfer, so the new holder has no continuity handoff.</Text>
|
|
56
56
|
<Text color={theme.textSubtle}>
|
|
57
|
-
Local SOUL.md, MEMORY.md, skills
|
|
57
|
+
Local SOUL.md, MEMORY.md, and skills remain. Back them up before this directory is reused.
|
|
58
58
|
</Text>
|
|
59
59
|
</>
|
|
60
60
|
)}
|
|
@@ -57,6 +57,6 @@ export function menuFlagsFromReconciliation(r: AgentReconciliation, perspective:
|
|
|
57
57
|
custodyAsterisk: custodyAsterisk && !isOperator,
|
|
58
58
|
...(custodyHint ? { custodyHint } : {}),
|
|
59
59
|
saveSnapshotAsterisk: r.agentUri === 'local-newer',
|
|
60
|
-
...(r.agentUri === 'local-newer' ? { saveSnapshotHint: 'Local newer than
|
|
60
|
+
...(r.agentUri === 'local-newer' ? { saveSnapshotHint: 'Local newer than onchain' } : {}),
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -208,7 +208,7 @@ export function useIdentityHubContinuity({
|
|
|
208
208
|
|
|
209
209
|
const deleteSkill = async (relativePath: string): Promise<void> => {
|
|
210
210
|
await mutateSkillsTree({
|
|
211
|
-
backStep: { kind: 'continuity-
|
|
211
|
+
backStep: { kind: 'continuity-skills-tree' },
|
|
212
212
|
run: async id => {
|
|
213
213
|
await deleteSkillEntry(id, relativePath)
|
|
214
214
|
return `deleted ${relativePath}`
|
|
@@ -221,8 +221,8 @@ export function useIdentityHubContinuity({
|
|
|
221
221
|
visibility: SkillVisibility,
|
|
222
222
|
): Promise<void> => {
|
|
223
223
|
await mutateSkillsTree({
|
|
224
|
-
backStep: { kind: 'continuity-skill-
|
|
225
|
-
successStep: notice => ({ kind: 'continuity-skill-
|
|
224
|
+
backStep: { kind: 'continuity-skill-actions', relativePath },
|
|
225
|
+
successStep: notice => ({ kind: 'continuity-skill-actions', relativePath, notice }),
|
|
226
226
|
run: async id => {
|
|
227
227
|
await setSkillVisibilityStorage(id, relativePath, visibility)
|
|
228
228
|
const display = relativePath.split('/')[0] ?? relativePath
|
|
@@ -17,19 +17,19 @@ export interface FlowCopy {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const FLOW_COPY: Record<string, FlowCopy> = {
|
|
20
|
-
account: { accent: "sign", tabTitle: "Connect Wallet", label: "
|
|
20
|
+
account: { accent: "sign", tabTitle: "Connect Wallet", label: "Connection Request", title: "Connect Wallet", detail: null },
|
|
21
21
|
sign: { accent: "sign", tabTitle: "Sign Message", label: "Signature Request", title: "Sign Message", detail: "message" },
|
|
22
|
-
"sign-transaction": { accent: "transaction", tabTitle: "Sign
|
|
23
|
-
transaction: { accent: "transaction", tabTitle: "Submit Transaction", label: "Transaction
|
|
22
|
+
"sign-transaction": { accent: "transaction", tabTitle: "Sign Snapshot", label: "Snapshot Signature", title: "Sign Snapshot", detail: "message" },
|
|
23
|
+
transaction: { accent: "transaction", tabTitle: "Submit Transaction", label: "Onchain Transaction", title: "Submit Transaction", detail: "registry" },
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export const TRANSACTION_TITLES: Record<string, string> = {
|
|
27
27
|
"register-agent": "Mint Agent Token",
|
|
28
28
|
"create-agent": "Create Agent",
|
|
29
|
-
"update-ens-records": "
|
|
30
|
-
"clear-ens-records": "
|
|
31
|
-
"create-simple-ens-subdomain": "
|
|
32
|
-
"set-simple-ens-records": "
|
|
29
|
+
"update-ens-records": "Submit With ENS Controller Wallet",
|
|
30
|
+
"clear-ens-records": "Submit With ENS Controller Wallet",
|
|
31
|
+
"create-simple-ens-subdomain": "Submit With Connected Wallet",
|
|
32
|
+
"set-simple-ens-records": "Submit With Connected Wallet",
|
|
33
33
|
"create-agent-ens-subdomain": "Owner Wallet Required",
|
|
34
34
|
"set-agent-ens-records": "Owner Wallet Required",
|
|
35
35
|
"publish-transfer-snapshot": "Switch Back to Sender Wallet",
|
|
@@ -48,7 +48,7 @@ export const STATE_TITLES = {
|
|
|
48
48
|
preparingTransaction: "Preparing Transaction",
|
|
49
49
|
approveTransaction: "Review Transaction",
|
|
50
50
|
error: "Wallet Error",
|
|
51
|
-
default: "Wallet
|
|
51
|
+
default: "Wallet Action",
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
export interface SubCopy { text: string; hint: string; }
|
|
@@ -64,14 +64,14 @@ export interface PurposeCopyEntry {
|
|
|
64
64
|
export const PURPOSE_COPY: Record<string, PurposeCopyEntry> = {
|
|
65
65
|
"connect-operator-wallet": {
|
|
66
66
|
flowTitle: "Connect Wallet",
|
|
67
|
-
account: { text: "Connect Wallet", hint: "Reads
|
|
67
|
+
account: { text: "Connect Wallet", hint: "Reads the operator wallet address for the agent ENS records. No signature or transaction." },
|
|
68
68
|
prepare: { text: "Reading Operator Wallet...", hint: "Return to the terminal." },
|
|
69
69
|
},
|
|
70
70
|
"create-agent": {
|
|
71
71
|
flowTitle: "Create Agent",
|
|
72
72
|
sign: { text: "Sign With Owner Wallet", hint: "Creates encrypted recovery access. No token approval." },
|
|
73
73
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
74
|
-
transaction: { text: "
|
|
74
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Submits one onchain transaction that mints a new ERC-8004 agent token to this wallet." },
|
|
75
75
|
},
|
|
76
76
|
"restore-owner-wallet": {
|
|
77
77
|
flowTitle: "Owner Wallet Required",
|
|
@@ -87,91 +87,91 @@ export const PURPOSE_COPY: Record<string, PurposeCopyEntry> = {
|
|
|
87
87
|
flowTitle: "Owner Wallet Required",
|
|
88
88
|
sign: { text: "Sign With Owner Wallet", hint: "Encrypts local files before publishing. Owner wallet is required because this update changes ownership-protected fields." },
|
|
89
89
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
90
|
-
transaction: { text: "
|
|
90
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Publishes the updated snapshot to the ERC-8004 token URI." },
|
|
91
91
|
},
|
|
92
92
|
"update-snapshot-operator": {
|
|
93
93
|
flowTitle: "Operator Wallet Save",
|
|
94
94
|
sign: { text: "Sign With Operator Wallet", hint: "Signs the encrypted snapshot for restore access." },
|
|
95
95
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
96
|
-
transaction: { text: "
|
|
96
|
+
transaction: { text: "Submit With Operator Wallet", hint: "Publishes the latest agent snapshot through the Vault." },
|
|
97
97
|
},
|
|
98
98
|
"update-snapshot-connected": {
|
|
99
99
|
flowTitle: "Save Snapshot",
|
|
100
100
|
sign: { text: "Sign With Connected Wallet", hint: "Encrypts local files before publishing. Single-wallet setup; no token approval." },
|
|
101
101
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
102
|
-
transaction: { text: "
|
|
102
|
+
transaction: { text: "Submit With Connected Wallet", hint: "Publishes the updated snapshot to the ERC-8004 token URI." },
|
|
103
103
|
},
|
|
104
104
|
"update-ens": {
|
|
105
105
|
flowTitle: "Update ENS in Agent Snapshot",
|
|
106
106
|
sign: { text: "Sign With Owner Wallet", hint: "Saves a new agent snapshot with this ENS name. No onchain ENS records change in this signature." },
|
|
107
107
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
108
|
-
transaction: { text: "
|
|
108
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Publishes the updated ERC-8004 token URI pointing to the new snapshot." },
|
|
109
109
|
},
|
|
110
110
|
"clear-ens": {
|
|
111
|
-
flowTitle: "
|
|
111
|
+
flowTitle: "Unlink ENS from Agent",
|
|
112
112
|
sign: { text: "Sign With Owner Wallet", hint: "Saves a new agent snapshot with no ENS name. No onchain ENS records change in this signature." },
|
|
113
113
|
prepare: { text: "Saving Snapshot...", hint: "Keep this page open." },
|
|
114
|
-
transaction: { text: "
|
|
114
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Publishes the updated ERC-8004 token URI pointing to the new snapshot." },
|
|
115
115
|
},
|
|
116
116
|
"update-profile-owner": {
|
|
117
117
|
flowTitle: "Owner Wallet Required",
|
|
118
118
|
sign: { text: "Sign With Owner Wallet", hint: "Saves public profile changes. Owner wallet is required because this update changes ownership-protected fields." },
|
|
119
119
|
prepare: { text: "Preparing Profile Update...", hint: "Keep this page open." },
|
|
120
|
-
transaction: { text: "
|
|
120
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Publishes the updated public profile to the ERC-8004 token URI." },
|
|
121
121
|
},
|
|
122
122
|
"update-profile-operator": {
|
|
123
123
|
flowTitle: "Operator Wallet Profile Update",
|
|
124
124
|
sign: { text: "Sign With Operator Wallet", hint: "Signs the encrypted snapshot for restore access." },
|
|
125
125
|
prepare: { text: "Preparing Profile Update...", hint: "Keep this page open." },
|
|
126
|
-
transaction: { text: "
|
|
126
|
+
transaction: { text: "Submit With Operator Wallet", hint: "Publishes the updated agent profile through the Vault. No ENS write." },
|
|
127
127
|
},
|
|
128
128
|
"update-profile-connected": {
|
|
129
129
|
flowTitle: "Update Public Profile",
|
|
130
130
|
sign: { text: "Sign With Connected Wallet", hint: "Saves public profile changes. Single-wallet setup; no token approval." },
|
|
131
131
|
prepare: { text: "Preparing Profile Update...", hint: "Keep this page open." },
|
|
132
|
-
transaction: { text: "
|
|
132
|
+
transaction: { text: "Submit With Connected Wallet", hint: "Publishes the updated public profile to the ERC-8004 token URI." },
|
|
133
133
|
},
|
|
134
134
|
"update-ens-records": {
|
|
135
135
|
flowTitle: "Update ENS Records",
|
|
136
|
-
sign: { text: "Sign With ENS
|
|
136
|
+
sign: { text: "Sign With ENS Controller Wallet", hint: "Authorizes ENS record changes. No token approval." },
|
|
137
137
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
138
|
-
transaction: { text: "
|
|
138
|
+
transaction: { text: "Submit With ENS Controller Wallet", hint: "Submit one Ethereum Mainnet ENS record transaction." },
|
|
139
139
|
},
|
|
140
140
|
"clear-ens-records": {
|
|
141
|
-
flowTitle: "
|
|
142
|
-
sign: { text: "Sign With ENS
|
|
141
|
+
flowTitle: "Clear ENS Records",
|
|
142
|
+
sign: { text: "Sign With ENS Controller Wallet", hint: "Authorizes clearing ethagent ENS text records. No token approval." },
|
|
143
143
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
144
|
-
transaction: { text: "
|
|
144
|
+
transaction: { text: "Submit With ENS Controller Wallet", hint: "Submit one Ethereum Mainnet transaction to clear ethagent ENS text records." },
|
|
145
145
|
},
|
|
146
146
|
"create-simple-ens-subdomain": {
|
|
147
147
|
flowTitle: "Review ENS Subdomain Creation",
|
|
148
148
|
sign: { text: "Sign With Connected Wallet", hint: "Connected wallet owns the ENS root and is creating the agent subdomain." },
|
|
149
149
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
150
|
-
transaction: { text: "
|
|
150
|
+
transaction: { text: "Submit With Connected Wallet", hint: "Creates the agent ENS subdomain on Ethereum Mainnet. Must come from the parent name's owner." },
|
|
151
151
|
},
|
|
152
152
|
"set-simple-ens-records": {
|
|
153
153
|
flowTitle: "Apply ENS Records",
|
|
154
154
|
sign: { text: "Sign With Connected Wallet", hint: "Connected wallet writes the agent ENS records." },
|
|
155
155
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
156
|
-
transaction: { text: "
|
|
156
|
+
transaction: { text: "Submit With Connected Wallet", hint: "Writes the agent ENS text records onchain. Must come from the name's controller." },
|
|
157
157
|
},
|
|
158
158
|
"create-agent-ens-subdomain": {
|
|
159
159
|
flowTitle: "Review Agent ENS Subdomain",
|
|
160
160
|
sign: { text: "Sign With Owner Wallet", hint: "Owner wallet controls the ENS root that the agent subdomain hangs off." },
|
|
161
161
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
162
|
-
transaction: { text: "
|
|
162
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Creates the agent ENS subdomain on Ethereum Mainnet. Must come from the parent name's owner wallet." },
|
|
163
163
|
},
|
|
164
164
|
"set-agent-ens-records": {
|
|
165
165
|
flowTitle: "Apply Agent ENS Records",
|
|
166
166
|
sign: { text: "Sign With Owner Wallet", hint: "Owner wallet writes the agent ENS records pointing at the operator wallet." },
|
|
167
167
|
prepare: { text: "Preparing ENS Transaction...", hint: "Keep this page open." },
|
|
168
|
-
transaction: { text: "
|
|
168
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Writes the agent ENS text and address records onchain. Must come from the name's controller." },
|
|
169
169
|
},
|
|
170
170
|
"update-operators": {
|
|
171
171
|
flowTitle: "Owner Wallet Required",
|
|
172
172
|
sign: { text: "Sign With Owner Wallet", hint: "Authorizes the new operator wallet access list. No token approval." },
|
|
173
173
|
prepare: { text: "Preparing Operator Wallets...", hint: "Keep this page open." },
|
|
174
|
-
transaction: { text: "
|
|
174
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Publishes the updated operator wallet access list onchain." },
|
|
175
175
|
},
|
|
176
176
|
"operator-proof": {
|
|
177
177
|
flowTitle: "Operator Wallet Required",
|
|
@@ -181,7 +181,7 @@ export const PURPOSE_COPY: Record<string, PurposeCopyEntry> = {
|
|
|
181
181
|
"sync-operator-vault": {
|
|
182
182
|
flowTitle: "Owner Wallet Required",
|
|
183
183
|
prepare: { text: "Preparing Vault Operator Update...", hint: "Keep this page open." },
|
|
184
|
-
transaction: { text: "
|
|
184
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Updates the Vault metadata-operator list so authorized operator wallets can rotate the agent URI." },
|
|
185
185
|
},
|
|
186
186
|
"refetch-snapshot": {
|
|
187
187
|
flowTitle: "Refetch Latest Snapshot",
|
|
@@ -189,7 +189,7 @@ export const PURPOSE_COPY: Record<string, PurposeCopyEntry> = {
|
|
|
189
189
|
prepare: { text: "Verifying Wallet...", hint: "Return to the terminal." },
|
|
190
190
|
},
|
|
191
191
|
"prepare-transfer-sender": {
|
|
192
|
-
flowTitle: "
|
|
192
|
+
flowTitle: "Submit With Sender Wallet",
|
|
193
193
|
sign: { text: "Sign With Sender Wallet", hint: "Creates sender restore access. No token approval." },
|
|
194
194
|
prepare: { text: "Verifying Sender Wallet...", hint: "Return to the terminal." },
|
|
195
195
|
},
|
|
@@ -201,47 +201,47 @@ export const PURPOSE_COPY: Record<string, PurposeCopyEntry> = {
|
|
|
201
201
|
"publish-transfer-snapshot": {
|
|
202
202
|
flowTitle: "Switch Back to Sender Wallet",
|
|
203
203
|
prepare: { text: "Preparing Token Update...", hint: "Keep this page open." },
|
|
204
|
-
transaction: { text: "
|
|
204
|
+
transaction: { text: "Submit With Sender Wallet", hint: "Submits one transaction to publish the transfer snapshot to the ERC-8004 token URI." },
|
|
205
205
|
},
|
|
206
206
|
"deploy-agent-vault": {
|
|
207
207
|
flowTitle: "Deploy Vault",
|
|
208
208
|
prepare: { text: "Preparing Vault Deploy...", hint: "Keep this page open." },
|
|
209
|
-
transaction: { text: "
|
|
209
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Deploys the Vault contract onchain. One-time setup per agent." },
|
|
210
210
|
errorContext: "While submitting the Vault deploy",
|
|
211
211
|
},
|
|
212
212
|
"deposit-agent-vault": {
|
|
213
213
|
flowTitle: "Deposit Token Into Vault",
|
|
214
214
|
prepare: { text: "Preparing Vault Deposit...", hint: "Keep this page open." },
|
|
215
|
-
transaction: { text: "
|
|
215
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Sends the agent token to the Vault so the vault can save updates on your behalf." },
|
|
216
216
|
errorContext: "While submitting the Vault deposit",
|
|
217
217
|
},
|
|
218
218
|
"unwrap-agent-vault": {
|
|
219
219
|
flowTitle: "Unwrap Token From Vault",
|
|
220
220
|
prepare: { text: "Preparing Vault Unwrap...", hint: "Keep this page open." },
|
|
221
|
-
transaction: { text: "
|
|
221
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Returns the agent token from the Vault to your owner wallet." },
|
|
222
222
|
},
|
|
223
223
|
"rotate-agent-uri-vault-owner": {
|
|
224
224
|
flowTitle: "Save Update Through Vault",
|
|
225
|
-
sign: { text: "Sign With Owner Wallet", hint: "
|
|
225
|
+
sign: { text: "Sign With Owner Wallet", hint: "Signs the new snapshot before saving onchain. No token approval." },
|
|
226
226
|
prepare: { text: "Preparing Update...", hint: "Keep this page open." },
|
|
227
|
-
transaction: { text: "
|
|
227
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Saves your update onchain through the Vault. Your token is locked in its dedicated Vault, so updates go through it." },
|
|
228
228
|
},
|
|
229
229
|
"rotate-agent-uri-vault-operator": {
|
|
230
230
|
flowTitle: "Save Update Through Vault",
|
|
231
|
-
sign: { text: "Sign With Operator Wallet", hint: "
|
|
231
|
+
sign: { text: "Sign With Operator Wallet", hint: "Signs the new snapshot before saving onchain. No token approval." },
|
|
232
232
|
prepare: { text: "Preparing Update...", hint: "Keep this page open." },
|
|
233
|
-
transaction: { text: "
|
|
233
|
+
transaction: { text: "Submit With Operator Wallet", hint: "Publishes the latest agent snapshot through the Vault. Your token is locked in its dedicated Vault, so the operator wallet calls the vault to publish." },
|
|
234
234
|
},
|
|
235
235
|
"withdraw-vault": {
|
|
236
236
|
flowTitle: "Withdraw Token From Vault",
|
|
237
237
|
prepare: { text: "Preparing Token Withdrawal...", hint: "Keep this page open." },
|
|
238
|
-
transaction: { text: "
|
|
238
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Temporarily returns the agent token from the vault to your owner wallet. Vault stays configured so you can redeposit later." },
|
|
239
239
|
errorContext: "While submitting the Vault withdraw",
|
|
240
240
|
},
|
|
241
241
|
"delete-ens-subdomain": {
|
|
242
242
|
flowTitle: "Delete ENS Subdomain",
|
|
243
243
|
prepare: { text: "Preparing Subdomain Deletion...", hint: "Keep this page open." },
|
|
244
|
-
transaction: { text: "
|
|
244
|
+
transaction: { text: "Submit With Owner Wallet", hint: "Clears the subdomain entry in the parent ENS name. After this, the label is freed for reuse." },
|
|
245
245
|
errorContext: "While deleting the ENS subdomain",
|
|
246
246
|
},
|
|
247
247
|
};
|
|
@@ -285,13 +285,13 @@ export function ensTokenChainHint(): string {
|
|
|
285
285
|
}
|
|
286
286
|
export function transactionCopy(): SubCopy {
|
|
287
287
|
const txCopy = requirePurposeSubCopy("transaction");
|
|
288
|
-
const expected = config.expectedAccount ? "
|
|
288
|
+
const expected = config.expectedAccount ? " Required wallet:" + shortAddr(config.expectedAccount) + "." : "";
|
|
289
289
|
const text = config.expectedAccount ? txCopy.text + " (" + shortAddr(config.expectedAccount) + ")" : txCopy.text;
|
|
290
290
|
return { text, hint: txCopy.hint + expected + ensTokenChainHint() };
|
|
291
291
|
}
|
|
292
292
|
export function signCopy(): SubCopy {
|
|
293
293
|
const sigCopy = requirePurposeSubCopy("sign");
|
|
294
|
-
const expected = config.expectedAccount ? "
|
|
294
|
+
const expected = config.expectedAccount ? " Required wallet:" + shortAddr(config.expectedAccount) + "." : "";
|
|
295
295
|
const text = config.expectedAccount ? sigCopy.text + " (" + shortAddr(config.expectedAccount) + ")" : sigCopy.text;
|
|
296
296
|
return { text, hint: sigCopy.hint + expected + ensTokenChainHint() };
|
|
297
297
|
}
|
|
@@ -68,6 +68,7 @@ export function buildModelPickerOptions(
|
|
|
68
68
|
|
|
69
69
|
options.push(sectionOption('hdr:local', 'Local Models'))
|
|
70
70
|
appendHfModelOptions(options, data, context, 'Added From Links', 46)
|
|
71
|
+
options.push(groupOption('hdr:local:manage', 'Manage'))
|
|
71
72
|
options.push(utilityOption('hf:download', 'Add Local Model File', LOCAL_MODEL_LINK_HINT))
|
|
72
73
|
options.push(utilityOption('local:catalog', 'View Full Catalog', 'Curated local GGUF files'))
|
|
73
74
|
if (data.hfModels.length > 0) {
|
|
@@ -109,6 +110,7 @@ export function buildModelPickerOptions(
|
|
|
109
110
|
contextFitLabel(provider, model, `${displayName}${active ? ' *' : ''}`, context.contextFit),
|
|
110
111
|
))
|
|
111
112
|
}
|
|
113
|
+
options.push(groupOption(`hdr:cloud:${provider}:manage`, 'Manage'))
|
|
112
114
|
options.push(utilityOption(`catalog:${provider}`, 'Full Catalog'))
|
|
113
115
|
const manageLabel = provider === 'openai' && data.cloudCredentialKinds?.openai === 'oauth'
|
|
114
116
|
? 'Manage ChatGPT Sign-in'
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
2
|
-
import { Box, Text } from 'ink'
|
|
3
|
-
import { Surface } from '../../../../ui/Surface.js'
|
|
4
|
-
import { Select, type SelectOption } from '../../../../ui/Select.js'
|
|
5
|
-
import { theme } from '../../../../ui/theme.js'
|
|
6
|
-
import type { EthagentIdentity } from '../../../../storage/config.js'
|
|
7
|
-
import { listSkills } from '../../../continuity/skills/loadSkills.js'
|
|
8
|
-
import type { SkillIndexEntry } from '../../../continuity/skills/types.js'
|
|
9
|
-
|
|
10
|
-
type DeleteTarget =
|
|
11
|
-
| { kind: 'skill'; relativePath: string }
|
|
12
|
-
| { kind: 'cancel' }
|
|
13
|
-
|
|
14
|
-
interface DeleteSkillScreenProps {
|
|
15
|
-
identity?: EthagentIdentity
|
|
16
|
-
notice?: string
|
|
17
|
-
footer: React.ReactNode
|
|
18
|
-
onPick: (target: { kind: 'skill'; relativePath: string }) => void
|
|
19
|
-
onCancel: () => void
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const DeleteSkillScreen: React.FC<DeleteSkillScreenProps> = ({
|
|
23
|
-
identity,
|
|
24
|
-
notice,
|
|
25
|
-
footer,
|
|
26
|
-
onPick,
|
|
27
|
-
onCancel,
|
|
28
|
-
}) => {
|
|
29
|
-
const [entries, setEntries] = useState<SkillIndexEntry[] | null>(null)
|
|
30
|
-
const [error, setError] = useState<string | null>(null)
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
let cancelled = false
|
|
34
|
-
if (!identity) {
|
|
35
|
-
setEntries([])
|
|
36
|
-
return () => { cancelled = true }
|
|
37
|
-
}
|
|
38
|
-
listSkills(identity)
|
|
39
|
-
.then(list => { if (!cancelled) { setEntries(list); setError(null) } })
|
|
40
|
-
.catch(err => {
|
|
41
|
-
if (cancelled) return
|
|
42
|
-
setEntries([])
|
|
43
|
-
setError(String((err as Error).message ?? err))
|
|
44
|
-
})
|
|
45
|
-
return () => { cancelled = true }
|
|
46
|
-
}, [identity])
|
|
47
|
-
|
|
48
|
-
const subtitle = notice ?? 'Pick a skill to delete. The whole folder will be removed.'
|
|
49
|
-
const isLoading = entries === null
|
|
50
|
-
const skills = entries ?? []
|
|
51
|
-
const hasAnything = skills.length > 0
|
|
52
|
-
|
|
53
|
-
const options = buildOptions(skills, isLoading)
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<Surface title="Delete Skill" subtitle={subtitle} footer={footer} tone="error">
|
|
57
|
-
{error && (
|
|
58
|
-
<Box marginTop={1}>
|
|
59
|
-
<Text color={theme.accentError}>{error}</Text>
|
|
60
|
-
</Box>
|
|
61
|
-
)}
|
|
62
|
-
{!isLoading && !hasAnything && (
|
|
63
|
-
<Box marginTop={1}>
|
|
64
|
-
<Text color={theme.dim}>Nothing to delete. The skills tree is empty.</Text>
|
|
65
|
-
</Box>
|
|
66
|
-
)}
|
|
67
|
-
<Box marginTop={1}>
|
|
68
|
-
<Select<DeleteTarget>
|
|
69
|
-
options={options}
|
|
70
|
-
hintLayout="inline"
|
|
71
|
-
onSubmit={choice => {
|
|
72
|
-
if (choice.kind === 'cancel') return onCancel()
|
|
73
|
-
return onPick(choice)
|
|
74
|
-
}}
|
|
75
|
-
onCancel={onCancel}
|
|
76
|
-
/>
|
|
77
|
-
</Box>
|
|
78
|
-
</Surface>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function buildOptions(
|
|
83
|
-
entries: SkillIndexEntry[],
|
|
84
|
-
isLoading: boolean,
|
|
85
|
-
): Array<SelectOption<DeleteTarget>> {
|
|
86
|
-
const rows: Array<SelectOption<DeleteTarget>> = []
|
|
87
|
-
const noopValue: DeleteTarget = { kind: 'cancel' }
|
|
88
|
-
|
|
89
|
-
if (isLoading) {
|
|
90
|
-
rows.push({
|
|
91
|
-
value: noopValue,
|
|
92
|
-
role: 'notice',
|
|
93
|
-
label: 'Loading...',
|
|
94
|
-
labelColor: theme.dim,
|
|
95
|
-
indent: 0,
|
|
96
|
-
})
|
|
97
|
-
} else if (entries.length > 0) {
|
|
98
|
-
rows.push({ value: noopValue, role: 'section', label: 'Targets' })
|
|
99
|
-
rows.push({ value: noopValue, role: 'notice', label: 'skills/', labelColor: theme.dim, indent: 3 })
|
|
100
|
-
const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name))
|
|
101
|
-
for (let i = 0; i < sorted.length; i++) {
|
|
102
|
-
const skill = sorted[i]
|
|
103
|
-
if (!skill) continue
|
|
104
|
-
const isLast = i === sorted.length - 1
|
|
105
|
-
const branch = isLast ? '└── ' : '├── '
|
|
106
|
-
rows.push({
|
|
107
|
-
value: { kind: 'skill', relativePath: skill.relativePath },
|
|
108
|
-
label: `${branch}${skill.name}/`,
|
|
109
|
-
indent: 3,
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
rows.push({ value: noopValue, role: 'section', label: 'Navigation' })
|
|
115
|
-
rows.push({
|
|
116
|
-
value: { kind: 'cancel' },
|
|
117
|
-
label: 'Back',
|
|
118
|
-
hint: 'Return to Skills',
|
|
119
|
-
role: 'utility',
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
return rows
|
|
123
|
-
}
|