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
|
@@ -2,15 +2,23 @@ import { useEffect, useState } from 'react'
|
|
|
2
2
|
import type { EthagentIdentity } from '../../storage/config.js'
|
|
3
3
|
import { catFromIpfs, DEFAULT_IPFS_API_URL } from '../storage/ipfs.js'
|
|
4
4
|
import {
|
|
5
|
-
continuityVaultRef,
|
|
6
5
|
continuityVaultStatus,
|
|
7
6
|
continuityWorkingTreeStatus,
|
|
8
7
|
ensurePublicSkillsFile,
|
|
9
8
|
type ContinuityWorkingTreeStatus,
|
|
10
9
|
} from '../continuity/storage.js'
|
|
11
|
-
import { openFileInEditor } from '../continuity/editor.js'
|
|
12
|
-
import { exportLocalBackup } from '../continuity/localBackup.js'
|
|
10
|
+
import { openFileInEditor, openInFileManager } from '../continuity/editor.js'
|
|
13
11
|
import { listPublishedContinuitySnapshots } from '../continuity/snapshots.js'
|
|
12
|
+
import {
|
|
13
|
+
createSkillFile,
|
|
14
|
+
deleteSkillEntry,
|
|
15
|
+
invalidateSkillsCache,
|
|
16
|
+
readSkillByRelativePath,
|
|
17
|
+
setSkillVisibility as setSkillVisibilityStorage,
|
|
18
|
+
} from '../continuity/skills/loadSkills.js'
|
|
19
|
+
import type { SkillVisibility } from '../continuity/skills/types.js'
|
|
20
|
+
import { syncPublicSkillsManifest } from '../continuity/skills/publicSkillsSync.js'
|
|
21
|
+
import { continuityVaultRef } from '../continuity/storage.js'
|
|
14
22
|
import type { Step } from './identityHubReducer.js'
|
|
15
23
|
|
|
16
24
|
type UseIdentityHubContinuityArgs = {
|
|
@@ -30,7 +38,11 @@ export function useIdentityHubContinuity({
|
|
|
30
38
|
setContinuityReady: (ready: boolean) => void
|
|
31
39
|
workingStatus: ContinuityWorkingTreeStatus | null
|
|
32
40
|
openContinuityFile: (kind: 'soul' | 'memory' | 'skills') => Promise<void>
|
|
33
|
-
|
|
41
|
+
openSkillFile: (relativePath: string) => Promise<void>
|
|
42
|
+
openSkillsFolder: () => Promise<void>
|
|
43
|
+
createSkill: (name: string, visibility: SkillVisibility) => Promise<void>
|
|
44
|
+
deleteSkill: (relativePath: string) => Promise<void>
|
|
45
|
+
setSkillVisibility: (relativePath: string, visibility: SkillVisibility) => Promise<void>
|
|
34
46
|
} {
|
|
35
47
|
const [continuityReady, setContinuityReady] = useState<boolean>(false)
|
|
36
48
|
const [workingStatus, setWorkingStatus] = useState<ContinuityWorkingTreeStatus | null>(null)
|
|
@@ -55,6 +67,7 @@ export function useIdentityHubContinuity({
|
|
|
55
67
|
step.kind !== 'menu'
|
|
56
68
|
&& step.kind !== 'continuity-private'
|
|
57
69
|
&& step.kind !== 'continuity-public'
|
|
70
|
+
&& step.kind !== 'continuity-skills-tree'
|
|
58
71
|
&& step.kind !== 'save-prompt'
|
|
59
72
|
&& step.kind !== 'rebackup-confirm'
|
|
60
73
|
) return
|
|
@@ -78,8 +91,39 @@ export function useIdentityHubContinuity({
|
|
|
78
91
|
}
|
|
79
92
|
}, [identity, step.kind])
|
|
80
93
|
|
|
94
|
+
const requireReadyVault = async (): Promise<EthagentIdentity> => {
|
|
95
|
+
if (!identity) throw new Error('No active identity')
|
|
96
|
+
const status = await continuityVaultStatus(identity)
|
|
97
|
+
if (!status.ready) {
|
|
98
|
+
throw new Error('Restore local continuity files before editing the skills tree')
|
|
99
|
+
}
|
|
100
|
+
return identity
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const mutateSkillsTree = async (args: {
|
|
104
|
+
backStep: Step
|
|
105
|
+
run: (id: EthagentIdentity) => Promise<string>
|
|
106
|
+
successStep?: (notice: string) => Step
|
|
107
|
+
}): Promise<void> => {
|
|
108
|
+
try {
|
|
109
|
+
const id = await requireReadyVault()
|
|
110
|
+
const notice = await args.run(id)
|
|
111
|
+
invalidateSkillsCache(id)
|
|
112
|
+
await syncPublicSkillsManifest(id)
|
|
113
|
+
const next = args.successStep
|
|
114
|
+
? args.successStep(notice)
|
|
115
|
+
: { kind: 'continuity-skills-tree' as const, notice }
|
|
116
|
+
setStep(next)
|
|
117
|
+
} catch (err: unknown) {
|
|
118
|
+
handleStepError(err, args.backStep)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
81
122
|
const openContinuityFile = async (kind: 'soul' | 'memory' | 'skills'): Promise<void> => {
|
|
82
123
|
if (!identity) return
|
|
124
|
+
const returnKind: 'continuity-private' | 'continuity-skills-tree' = kind === 'skills'
|
|
125
|
+
? 'continuity-skills-tree'
|
|
126
|
+
: 'continuity-private'
|
|
83
127
|
try {
|
|
84
128
|
if (kind === 'skills') {
|
|
85
129
|
await ensurePublicSkillsFile(identity, {
|
|
@@ -89,43 +133,121 @@ export function useIdentityHubContinuity({
|
|
|
89
133
|
const ref = continuityVaultRef(identity)
|
|
90
134
|
const file = kind === 'soul' ? ref.soulPath : kind === 'memory' ? ref.memoryPath : ref.publicSkillsPath
|
|
91
135
|
const result = await openFileInEditor(file)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
: `open failed: ${result.error}
|
|
96
|
-
|
|
136
|
+
if (result.ok) {
|
|
137
|
+
setStep({ kind: returnKind, editorOpened: true })
|
|
138
|
+
} else {
|
|
139
|
+
setStep({ kind: returnKind, notice: `open failed: ${result.error}`, editorOpened: false })
|
|
140
|
+
}
|
|
97
141
|
} catch (err: unknown) {
|
|
98
|
-
handleStepError(err, { kind:
|
|
142
|
+
handleStepError(err, { kind: returnKind })
|
|
99
143
|
}
|
|
100
144
|
}
|
|
101
145
|
|
|
102
|
-
const
|
|
146
|
+
const openSkillFile = async (relativePath: string): Promise<void> => {
|
|
103
147
|
if (!identity) return
|
|
104
148
|
try {
|
|
105
|
-
await
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
: result.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
149
|
+
const skill = await readSkillByRelativePath(identity, relativePath)
|
|
150
|
+
const result = await openFileInEditor(skill.absolutePath)
|
|
151
|
+
invalidateSkillsCache(identity)
|
|
152
|
+
try {
|
|
153
|
+
await syncPublicSkillsManifest(identity)
|
|
154
|
+
} catch (syncErr: unknown) {
|
|
155
|
+
const failPrefix = result.ok ? '' : `open failed: ${result.error}; `
|
|
156
|
+
setStep({ kind: 'continuity-skills-tree', notice: `${failPrefix}public manifest sync failed: ${(syncErr as Error).message}`, editorOpened: result.ok })
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
if (result.ok) {
|
|
160
|
+
setStep({ kind: 'continuity-skills-tree', editorOpened: true })
|
|
161
|
+
} else {
|
|
162
|
+
setStep({ kind: 'continuity-skills-tree', notice: `open failed: ${result.error}`, editorOpened: false })
|
|
163
|
+
}
|
|
115
164
|
} catch (err: unknown) {
|
|
116
|
-
handleStepError(err, { kind: 'continuity-
|
|
165
|
+
handleStepError(err, { kind: 'continuity-skills-tree' })
|
|
117
166
|
}
|
|
118
167
|
}
|
|
119
168
|
|
|
169
|
+
const openSkillsFolder = async (): Promise<void> => {
|
|
170
|
+
if (!identity) return
|
|
171
|
+
try {
|
|
172
|
+
const ref = continuityVaultRef(identity)
|
|
173
|
+
const result = await openInFileManager(ref.skillsDir)
|
|
174
|
+
if (result.ok) {
|
|
175
|
+
setStep({ kind: 'continuity-skills-tree', editorOpened: true })
|
|
176
|
+
} else {
|
|
177
|
+
setStep({ kind: 'continuity-skills-tree', notice: `open failed: ${result.error}`, editorOpened: false })
|
|
178
|
+
}
|
|
179
|
+
} catch (err: unknown) {
|
|
180
|
+
handleStepError(err, { kind: 'continuity-skills-tree' })
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const createSkill = async (name: string, visibility: SkillVisibility): Promise<void> => {
|
|
185
|
+
const normalizedName = sanitizeSkillSegment(name)
|
|
186
|
+
if (!normalizedName) {
|
|
187
|
+
handleStepError(
|
|
188
|
+
new Error('Folder name must contain only letters, numbers, dashes, underscores, or dots'),
|
|
189
|
+
{ kind: 'continuity-skill-new' },
|
|
190
|
+
)
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const id = await requireReadyVault()
|
|
195
|
+
const created = await createSkillFile(id, { name: normalizedName, visibility })
|
|
196
|
+
invalidateSkillsCache(id)
|
|
197
|
+
await syncPublicSkillsManifest(id)
|
|
198
|
+
const result = await openFileInEditor(created.absolutePath)
|
|
199
|
+
if (result.ok) {
|
|
200
|
+
setStep({ kind: 'continuity-skills-tree', editorOpened: true })
|
|
201
|
+
} else {
|
|
202
|
+
setStep({ kind: 'continuity-skills-tree', notice: `created ${created.relativePath}; open failed: ${result.error}`, editorOpened: false })
|
|
203
|
+
}
|
|
204
|
+
} catch (err: unknown) {
|
|
205
|
+
handleStepError(err, { kind: 'continuity-skill-new' })
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const deleteSkill = async (relativePath: string): Promise<void> => {
|
|
210
|
+
await mutateSkillsTree({
|
|
211
|
+
backStep: { kind: 'continuity-skill-delete' },
|
|
212
|
+
run: async id => {
|
|
213
|
+
await deleteSkillEntry(id, relativePath)
|
|
214
|
+
return `deleted ${relativePath}`
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const setSkillVisibility = async (
|
|
220
|
+
relativePath: string,
|
|
221
|
+
visibility: SkillVisibility,
|
|
222
|
+
): Promise<void> => {
|
|
223
|
+
await mutateSkillsTree({
|
|
224
|
+
backStep: { kind: 'continuity-skill-visibility' },
|
|
225
|
+
successStep: notice => ({ kind: 'continuity-skill-visibility', notice }),
|
|
226
|
+
run: async id => {
|
|
227
|
+
await setSkillVisibilityStorage(id, relativePath, visibility)
|
|
228
|
+
const display = relativePath.split('/')[0] ?? relativePath
|
|
229
|
+
return `${display} now ${visibility}`
|
|
230
|
+
},
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
120
234
|
return {
|
|
121
235
|
continuityReady,
|
|
122
236
|
setContinuityReady,
|
|
123
237
|
workingStatus,
|
|
124
238
|
openContinuityFile,
|
|
125
|
-
|
|
239
|
+
openSkillFile,
|
|
240
|
+
openSkillsFolder,
|
|
241
|
+
createSkill,
|
|
242
|
+
deleteSkill,
|
|
243
|
+
setSkillVisibility,
|
|
126
244
|
}
|
|
127
245
|
}
|
|
128
246
|
|
|
247
|
+
export function sanitizeSkillSegment(value: string): string {
|
|
248
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60)
|
|
249
|
+
}
|
|
250
|
+
|
|
129
251
|
async function readPublishedPublicSkills(identity: EthagentIdentity): Promise<string> {
|
|
130
252
|
const cid = identity.publicSkills?.cid
|
|
131
253
|
if (!cid) throw new Error('No saved public skills CID')
|
|
@@ -389,7 +389,11 @@ export function useIdentityHubController({
|
|
|
389
389
|
openTokenTransferFlow,
|
|
390
390
|
openPublicProfileEdit,
|
|
391
391
|
openContinuityFile: continuity.openContinuityFile,
|
|
392
|
-
|
|
392
|
+
openSkillFile: continuity.openSkillFile,
|
|
393
|
+
openSkillsFolder: continuity.openSkillsFolder,
|
|
394
|
+
createSkill: continuity.createSkill,
|
|
395
|
+
deleteSkill: continuity.deleteSkill,
|
|
396
|
+
setSkillVisibility: continuity.setSkillVisibility,
|
|
393
397
|
}
|
|
394
398
|
}
|
|
395
399
|
|
|
@@ -20,10 +20,8 @@ import {
|
|
|
20
20
|
runEnsSetupRecordsTransaction,
|
|
21
21
|
runEnsSetupRegistryTransaction,
|
|
22
22
|
runUpdateEnsRecords,
|
|
23
|
-
} from './ens/
|
|
24
|
-
import {
|
|
25
|
-
runRecoveryRefetch,
|
|
26
|
-
} from './restore/index.js'
|
|
23
|
+
} from './ens/transactions.js'
|
|
24
|
+
import { runRecoveryRefetch } from './restore/recovery.js'
|
|
27
25
|
import type { EffectCallbacks } from './shared/effects/types.js'
|
|
28
26
|
import { useRestoreEffects } from './restore/useRestoreEffects.js'
|
|
29
27
|
import {
|
package/src/mcp/manager.ts
CHANGED
|
@@ -441,7 +441,7 @@ export class McpManager implements McpRuntime {
|
|
|
441
441
|
async buildPermissionRequest() {
|
|
442
442
|
return {
|
|
443
443
|
kind: 'mcp',
|
|
444
|
-
title: '
|
|
444
|
+
title: 'Allow MCP tool?',
|
|
445
445
|
subtitle: `${connection.name} / ${tool.name}`,
|
|
446
446
|
serverName: connection.name,
|
|
447
447
|
normalizedServerName: connection.normalizedName,
|