ethagent 1.0.0 → 1.0.2
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ethagent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A privacy-first AI agent with a portable Ethereum identity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/ethagent.js",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"ink": "^6.8.0",
|
|
48
48
|
"react": "^19.2.4",
|
|
49
49
|
"tsx": "^4.21.0",
|
|
50
|
+
"update-notifier": "^7.3.1",
|
|
50
51
|
"viem": "^2.48.4",
|
|
51
52
|
"zod": "^3.25.76"
|
|
52
53
|
},
|
package/src/cli/main.tsx
CHANGED
|
@@ -12,8 +12,13 @@ import { AppInputProvider, useAppInput } from '../app/input/AppInputProvider.js'
|
|
|
12
12
|
import { loadConfig, type EthagentConfig } from '../storage/config.js'
|
|
13
13
|
import { runResetCommand } from './reset.js'
|
|
14
14
|
import { runPreviewCommand } from './preview.js'
|
|
15
|
+
import updateNotifier from 'update-notifier'
|
|
15
16
|
|
|
16
17
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
const pkgPath = path.resolve(__dirname, '..', '..', 'package.json')
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
20
|
+
|
|
21
|
+
updateNotifier({ pkg }).notify()
|
|
17
22
|
|
|
18
23
|
function readVersion(): string {
|
|
19
24
|
try {
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
runPublicProfilePreflight,
|
|
28
28
|
runPublicProfileSigning,
|
|
29
29
|
runPublicProfileStorageSubmit,
|
|
30
|
-
runContinuityUnlock,
|
|
31
30
|
runRecoveryRefetch,
|
|
32
31
|
isAgentTokenIdRequiredError,
|
|
33
32
|
type EffectCallbacks,
|
|
@@ -362,18 +361,7 @@ export const IdentityHub: React.FC<IdentityHubProps> = ({ mode, config, initialA
|
|
|
362
361
|
return () => { cancelled = true }
|
|
363
362
|
}, [step])
|
|
364
363
|
|
|
365
|
-
|
|
366
|
-
if (step.kind !== 'continuity-unlocking') return
|
|
367
|
-
let cancelled = false
|
|
368
|
-
runContinuityUnlock(step, callbacks)
|
|
369
|
-
.then(() => {
|
|
370
|
-
if (!cancelled) setContinuityReady(true)
|
|
371
|
-
})
|
|
372
|
-
.catch((err: unknown) => {
|
|
373
|
-
if (!cancelled) handleStepError(err, { kind: 'continuity-private' })
|
|
374
|
-
})
|
|
375
|
-
return () => { cancelled = true }
|
|
376
|
-
}, [step])
|
|
364
|
+
|
|
377
365
|
|
|
378
366
|
useEffect(() => {
|
|
379
367
|
if (step.kind !== 'recovery-refetching') return
|
|
@@ -632,7 +620,6 @@ export const IdentityHub: React.FC<IdentityHubProps> = ({ mode, config, initialA
|
|
|
632
620
|
notice={step.notice}
|
|
633
621
|
canBackup={canRebackup}
|
|
634
622
|
footer={footer}
|
|
635
|
-
onRestore={() => { if (identity) setStep({ kind: 'continuity-unlocking', identity, returnTo: 'private' }) }}
|
|
636
623
|
onOpenSoul={() => { void openContinuityFile('soul') }}
|
|
637
624
|
onOpenMemory={() => { void openContinuityFile('memory') }}
|
|
638
625
|
onBackup={() => triggerRebackup({ kind: 'continuity-private' })}
|
|
@@ -762,17 +749,7 @@ export const IdentityHub: React.FC<IdentityHubProps> = ({ mode, config, initialA
|
|
|
762
749
|
)
|
|
763
750
|
}
|
|
764
751
|
|
|
765
|
-
|
|
766
|
-
return (
|
|
767
|
-
<WalletApprovalScreen
|
|
768
|
-
title="Restore Memory & Persona"
|
|
769
|
-
subtitle="Wallet approval decrypts the encrypted snapshot into local SOUL.md and MEMORY.md working files."
|
|
770
|
-
walletSession={walletSession}
|
|
771
|
-
label="waiting for wallet approval..."
|
|
772
|
-
onCancel={() => setStep({ kind: 'continuity-private' })}
|
|
773
|
-
/>
|
|
774
|
-
)
|
|
775
|
-
}
|
|
752
|
+
|
|
776
753
|
|
|
777
754
|
|
|
778
755
|
if (step.kind === 'rebackup-storage' || step.kind === 'public-profile-storage') {
|
|
@@ -831,52 +831,6 @@ export async function runPublicProfileStorageSubmit(
|
|
|
831
831
|
})
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
-
export async function runContinuityUnlock(
|
|
835
|
-
step: Extract<Step, { kind: 'continuity-unlocking' }>,
|
|
836
|
-
callbacks: Pick<EffectCallbacks, 'onStep' | 'onWalletReady'>,
|
|
837
|
-
): Promise<void> {
|
|
838
|
-
const identity = step.identity
|
|
839
|
-
const ownerAddress = getAddress(identity.ownerAddress ?? identity.address)
|
|
840
|
-
const chainId = identity.chainId ?? identity.backup?.chainId ?? 1
|
|
841
|
-
const snapshotCid = step.cid ?? identity.backup?.cid
|
|
842
|
-
if (snapshotCid) {
|
|
843
|
-
const raw = await catFromIpfs(identity.backup?.ipfsApiUrl ?? DEFAULT_IPFS_API_URL, snapshotCid)
|
|
844
|
-
const envelope = parseRestorableEnvelope(raw)
|
|
845
|
-
if (isContinuitySnapshotEnvelope(envelope)) {
|
|
846
|
-
assertContinuitySnapshotOwner(envelope, ownerAddress)
|
|
847
|
-
const wallet = await requestBrowserWalletSignature({
|
|
848
|
-
chainId,
|
|
849
|
-
expectedAccount: ownerAddress,
|
|
850
|
-
message: envelope.challenge,
|
|
851
|
-
onReady: callbacks.onWalletReady,
|
|
852
|
-
})
|
|
853
|
-
const payload = restoreContinuitySnapshotEnvelope({ envelope, walletSignature: wallet.signature })
|
|
854
|
-
await writeContinuityFiles({ ...identity, state: payload.state }, payload.files)
|
|
855
|
-
await restorePublishedPublicSkills(identity, identity.backup?.ipfsApiUrl ?? DEFAULT_IPFS_API_URL, step.publicSkillsCid)
|
|
856
|
-
callbacks.onStep({ kind: 'continuity-private', notice: 'published snapshot restored locally. review, then publish when ready.' })
|
|
857
|
-
return
|
|
858
|
-
}
|
|
859
|
-
assertAgentStateBackupOwner(envelope, ownerAddress)
|
|
860
|
-
const wallet = await requestBrowserWalletSignature({
|
|
861
|
-
chainId,
|
|
862
|
-
expectedAccount: ownerAddress,
|
|
863
|
-
message: envelope.challenge,
|
|
864
|
-
onReady: callbacks.onWalletReady,
|
|
865
|
-
})
|
|
866
|
-
restoreAgentStateBackupEnvelope({ envelope, walletSignature: wallet.signature })
|
|
867
|
-
} else {
|
|
868
|
-
const wallet = await requestBrowserWalletSignature({
|
|
869
|
-
chainId,
|
|
870
|
-
expectedAccount: ownerAddress,
|
|
871
|
-
message: createContinuitySnapshotChallenge(ownerAddress),
|
|
872
|
-
onReady: callbacks.onWalletReady,
|
|
873
|
-
})
|
|
874
|
-
void wallet.signature
|
|
875
|
-
}
|
|
876
|
-
await ensureContinuityFiles(identity)
|
|
877
|
-
callbacks.onStep({ kind: 'continuity-private', notice: 'local private working files are ready on this machine.' })
|
|
878
|
-
}
|
|
879
|
-
|
|
880
834
|
|
|
881
835
|
export async function runRecoveryRefetch(
|
|
882
836
|
identity: EthagentIdentity,
|
|
@@ -35,7 +35,6 @@ export type Step =
|
|
|
35
35
|
| { kind: 'public-profile-storage'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; error?: string; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step }
|
|
36
36
|
| { kind: 'continuity-private'; notice?: string }
|
|
37
37
|
| { kind: 'continuity-public'; notice?: string }
|
|
38
|
-
| { kind: 'continuity-unlocking'; identity: EthagentIdentity; cid?: string; publicSkillsCid?: string; returnTo?: 'private' }
|
|
39
38
|
| { kind: 'rebackup-confirm' }
|
|
40
39
|
| { kind: 'recovery-refetch-confirm' }
|
|
41
40
|
| { kind: 'recovery-refetching'; identity: EthagentIdentity; registry: Erc8004RegistryConfig }
|
|
@@ -168,8 +167,6 @@ function backStep(from: Step): Step {
|
|
|
168
167
|
case 'continuity-private':
|
|
169
168
|
case 'continuity-public':
|
|
170
169
|
return { kind: 'menu' }
|
|
171
|
-
case 'continuity-unlocking':
|
|
172
|
-
return { kind: 'continuity-private' }
|
|
173
170
|
case 'rebackup-confirm':
|
|
174
171
|
case 'recovery-refetch-confirm':
|
|
175
172
|
case 'recovery-refetching':
|
|
@@ -7,7 +7,7 @@ import type { EthagentConfig, EthagentIdentity } from '../../../storage/config.j
|
|
|
7
7
|
import { IdentitySummary } from './IdentitySummary.js'
|
|
8
8
|
import { shortCid } from '../identityHubModel.js'
|
|
9
9
|
|
|
10
|
-
type PrivateAction = '
|
|
10
|
+
type PrivateAction = 'soul' | 'memory' | 'backup' | 'back'
|
|
11
11
|
type PublicAction = 'edit' | 'skills' | 'publish' | 'back'
|
|
12
12
|
|
|
13
13
|
type CommonProps = {
|
|
@@ -21,7 +21,6 @@ type CommonProps = {
|
|
|
21
21
|
|
|
22
22
|
export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
23
23
|
canBackup: boolean
|
|
24
|
-
onRestore: () => void
|
|
25
24
|
onOpenSoul: () => void
|
|
26
25
|
onOpenMemory: () => void
|
|
27
26
|
onBackup: () => void
|
|
@@ -32,7 +31,6 @@ export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
|
32
31
|
notice,
|
|
33
32
|
footer,
|
|
34
33
|
canBackup,
|
|
35
|
-
onRestore,
|
|
36
34
|
onOpenSoul,
|
|
37
35
|
onOpenMemory,
|
|
38
36
|
onBackup,
|
|
@@ -44,8 +42,6 @@ export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
|
44
42
|
<Box marginTop={1}>
|
|
45
43
|
<Select<PrivateAction>
|
|
46
44
|
options={[
|
|
47
|
-
{ value: 'restore', role: 'section', prefix: '--', label: 'Restore' },
|
|
48
|
-
{ value: 'restore', label: 'restore snapshot', hint: 'decrypt latest IPFS backup with owner wallet' },
|
|
49
45
|
{ value: 'soul', role: 'section', prefix: '--', label: 'Open local files' },
|
|
50
46
|
{ value: 'soul', label: 'open SOUL.md', hint: 'edit persona and operating preferences', disabled: !ready },
|
|
51
47
|
{ value: 'memory', label: 'open MEMORY.md', hint: 'edit private working memory for this agent', disabled: !ready },
|
|
@@ -56,7 +52,6 @@ export const PrivateContinuityScreen: React.FC<CommonProps & {
|
|
|
56
52
|
]}
|
|
57
53
|
hintLayout="inline"
|
|
58
54
|
onSubmit={choice => {
|
|
59
|
-
if (choice === 'restore') return onRestore()
|
|
60
55
|
if (choice === 'soul') return onOpenSoul()
|
|
61
56
|
if (choice === 'memory') return onOpenMemory()
|
|
62
57
|
if (choice === 'backup') return onBackup()
|
|
@@ -106,7 +101,7 @@ const PrivateRows: React.FC<{ identity?: EthagentIdentity; ready: boolean }> = (
|
|
|
106
101
|
<Box flexDirection="column" marginTop={1}>
|
|
107
102
|
<Text>
|
|
108
103
|
<Text color={theme.dim}>{'local files'.padEnd(13)}</Text>
|
|
109
|
-
<Text color={ready ? theme.text : theme.dim}>{ready ? 'SOUL.md and MEMORY.md ready' : '
|
|
104
|
+
<Text color={ready ? theme.text : theme.dim}>{ready ? 'SOUL.md and MEMORY.md ready' : 'missing local working files'}</Text>
|
|
110
105
|
</Text>
|
|
111
106
|
<Text>
|
|
112
107
|
<Text color={theme.dim}>{'snapshot'.padEnd(13)}</Text>
|
|
@@ -135,7 +130,7 @@ const PublicProfileRows: React.FC<{ identity?: EthagentIdentity }> = ({ identity
|
|
|
135
130
|
function privateSubtitle(ready: boolean): string {
|
|
136
131
|
return ready
|
|
137
132
|
? 'SOUL.md and MEMORY.md are private local files on this machine.'
|
|
138
|
-
: '
|
|
133
|
+
: 'Use "refetch latest snapshot" from the hub menu to recover files.'
|
|
139
134
|
}
|
|
140
135
|
|
|
141
136
|
function readStateString(state: Record<string, unknown> | undefined, key: string): string {
|