ethagent 0.2.1 → 1.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/LICENSE +21 -0
- package/README.md +114 -32
- package/bin/ethagent.js +11 -2
- package/package.json +25 -7
- package/src/app/FirstRun.tsx +412 -0
- package/src/app/hooks/useCancelRequest.ts +22 -0
- package/src/app/hooks/useDoublePress.ts +46 -0
- package/src/app/hooks/useExitOnCtrlC.ts +36 -0
- package/src/app/input/AppInputProvider.tsx +116 -0
- package/src/app/input/appInputParser.ts +279 -0
- package/src/app/keybindings/KeybindingProvider.tsx +134 -0
- package/src/app/keybindings/resolver.ts +42 -0
- package/src/app/keybindings/types.ts +26 -0
- package/src/chat/ChatBottomPane.tsx +280 -0
- package/src/chat/ChatInput.tsx +722 -0
- package/src/chat/ChatScreen.tsx +1575 -0
- package/src/chat/ContextLimitView.tsx +95 -0
- package/src/chat/ContinuityEditReviewView.tsx +48 -0
- package/src/chat/ConversationStack.tsx +47 -0
- package/src/chat/CopyPicker.tsx +52 -0
- package/src/chat/MessageList.tsx +609 -0
- package/src/chat/PermissionPrompt.tsx +153 -0
- package/src/chat/PermissionsView.tsx +159 -0
- package/src/chat/PlanApprovalView.tsx +91 -0
- package/src/chat/ResumeView.tsx +267 -0
- package/src/chat/RewindView.tsx +386 -0
- package/src/chat/SessionStatus.tsx +51 -0
- package/src/chat/TranscriptView.tsx +202 -0
- package/src/chat/chatInputState.ts +247 -0
- package/src/chat/chatPaste.ts +49 -0
- package/src/chat/chatScreenUtils.ts +187 -0
- package/src/chat/chatSessionState.ts +142 -0
- package/src/chat/chatTurnOrchestrator.ts +701 -0
- package/src/chat/commands.ts +673 -0
- package/src/chat/textCursor.ts +202 -0
- package/src/chat/toolResultDisplay.ts +8 -0
- package/src/chat/transcriptViewport.ts +247 -0
- package/src/cli/ResetConfirmView.tsx +61 -0
- package/src/cli/main.tsx +177 -0
- package/src/cli/preview.tsx +19 -0
- package/src/cli/reset.ts +106 -0
- package/src/identity/continuity/editor.ts +149 -0
- package/src/identity/continuity/envelope.ts +345 -0
- package/src/identity/continuity/history.ts +153 -0
- package/src/identity/continuity/privateEdit.ts +334 -0
- package/src/identity/continuity/publicSkills.ts +173 -0
- package/src/identity/continuity/snapshots.ts +183 -0
- package/src/identity/continuity/storage.ts +507 -0
- package/src/identity/crypto/backupEnvelope.ts +486 -0
- package/src/identity/crypto/eth.ts +137 -0
- package/src/identity/hub/IdentityHub.tsx +868 -0
- package/src/identity/hub/identityHubEffects.ts +1146 -0
- package/src/identity/hub/identityHubModel.ts +291 -0
- package/src/identity/hub/identityHubReducer.ts +212 -0
- package/src/identity/hub/screens/BusyScreen.tsx +26 -0
- package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +144 -0
- package/src/identity/hub/screens/CreateFlow.tsx +206 -0
- package/src/identity/hub/screens/DetailsScreen.tsx +64 -0
- package/src/identity/hub/screens/EditProfileFlow.tsx +145 -0
- package/src/identity/hub/screens/ErrorScreen.tsx +35 -0
- package/src/identity/hub/screens/IdentitySummary.tsx +70 -0
- package/src/identity/hub/screens/MenuScreen.tsx +117 -0
- package/src/identity/hub/screens/NetworkScreen.tsx +41 -0
- package/src/identity/hub/screens/RebackupStorageScreen.tsx +50 -0
- package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +85 -0
- package/src/identity/hub/screens/RestoreFlow.tsx +206 -0
- package/src/identity/hub/screens/StorageCredentialScreen.tsx +128 -0
- package/src/identity/hub/screens/WalletApprovalScreen.tsx +43 -0
- package/src/identity/profile/imagePicker.ts +180 -0
- package/src/identity/registry/erc8004.ts +1106 -0
- package/src/identity/registry/registryConfig.ts +69 -0
- package/src/identity/storage/ipfs.ts +212 -0
- package/src/identity/storage/pinataJwt.ts +53 -0
- package/src/identity/wallet/browserWallet.ts +393 -0
- package/src/identity/wallet/wallet-page/wallet.html +1082 -0
- package/src/mcp/approvals.ts +113 -0
- package/src/mcp/config.ts +235 -0
- package/src/mcp/manager.ts +541 -0
- package/src/mcp/names.ts +19 -0
- package/src/mcp/output.ts +96 -0
- package/src/models/ModelPicker.tsx +1446 -0
- package/src/models/catalog.ts +296 -0
- package/src/models/huggingface.ts +651 -0
- package/src/models/llamacpp.ts +810 -0
- package/src/models/llamacppPreflight.ts +150 -0
- package/src/models/modelDisplay.ts +105 -0
- package/src/models/modelPickerOptions.ts +421 -0
- package/src/models/modelRecommendation.ts +140 -0
- package/src/models/runtimeDetection.ts +81 -0
- package/src/models/uncensoredCatalog.ts +86 -0
- package/src/providers/anthropic.ts +259 -0
- package/src/providers/contracts.ts +62 -0
- package/src/providers/errors.ts +62 -0
- package/src/providers/gemini.ts +152 -0
- package/src/providers/openai-chat.ts +472 -0
- package/src/providers/registry.ts +42 -0
- package/src/providers/retry.ts +58 -0
- package/src/providers/sse.ts +93 -0
- package/src/runtime/compaction.ts +389 -0
- package/src/runtime/cwd.ts +43 -0
- package/src/runtime/sessionMode.ts +55 -0
- package/src/runtime/systemPrompt.ts +209 -0
- package/src/runtime/toolClaimGuards.ts +143 -0
- package/src/runtime/toolExecution.ts +304 -0
- package/src/runtime/toolIntent.ts +163 -0
- package/src/runtime/turn.ts +858 -0
- package/src/storage/atomicWrite.ts +68 -0
- package/src/storage/config.ts +189 -0
- package/src/storage/factoryReset.ts +130 -0
- package/src/storage/history.ts +58 -0
- package/src/storage/identity.ts +99 -0
- package/src/storage/permissions.ts +76 -0
- package/src/storage/rewind.ts +246 -0
- package/src/storage/secrets.ts +181 -0
- package/src/storage/sessionExport.ts +49 -0
- package/src/storage/sessions.ts +482 -0
- package/src/tools/bashSafety.ts +174 -0
- package/src/tools/bashTool.ts +140 -0
- package/src/tools/changeDirectoryTool.ts +213 -0
- package/src/tools/contracts.ts +179 -0
- package/src/tools/deleteFileTool.ts +111 -0
- package/src/tools/editTool.ts +160 -0
- package/src/tools/editUtils.ts +170 -0
- package/src/tools/listDirectoryTool.ts +55 -0
- package/src/tools/mcpResourceTools.ts +95 -0
- package/src/tools/permissionRules.ts +85 -0
- package/src/tools/privateContinuityEditTool.ts +178 -0
- package/src/tools/privateContinuityReadTool.ts +107 -0
- package/src/tools/readTool.ts +85 -0
- package/src/tools/registry.ts +67 -0
- package/src/tools/writeFileTool.ts +142 -0
- package/src/ui/BrandSplash.tsx +193 -0
- package/src/ui/ProgressBar.tsx +34 -0
- package/src/ui/Select.tsx +143 -0
- package/src/ui/Spinner.tsx +269 -0
- package/src/ui/Surface.tsx +47 -0
- package/src/ui/TextInput.tsx +97 -0
- package/src/ui/theme.ts +59 -0
- package/src/utils/clipboard.ts +216 -0
- package/src/utils/markdownSegments.ts +51 -0
- package/src/utils/messages.ts +35 -0
- package/src/utils/withRetry.ts +280 -0
- package/src/cli.tsx +0 -147
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
export type ImageFilePickerResult =
|
|
6
|
+
| { ok: true; file: string; method: string }
|
|
7
|
+
| { ok: false; cancelled: boolean; error: string }
|
|
8
|
+
|
|
9
|
+
type PickerCommand = {
|
|
10
|
+
cmd: string
|
|
11
|
+
args: string[]
|
|
12
|
+
method: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function openImageFilePicker(
|
|
16
|
+
options: {
|
|
17
|
+
platform?: NodeJS.Platform
|
|
18
|
+
env?: NodeJS.ProcessEnv
|
|
19
|
+
timeoutMs?: number
|
|
20
|
+
spawnImpl?: typeof spawn
|
|
21
|
+
} = {},
|
|
22
|
+
): Promise<ImageFilePickerResult> {
|
|
23
|
+
const platform = options.platform ?? process.platform
|
|
24
|
+
const env = options.env ?? process.env
|
|
25
|
+
const command = resolveImagePickerCommand(platform, env)
|
|
26
|
+
if (!command) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
cancelled: false,
|
|
30
|
+
error: platform === 'linux'
|
|
31
|
+
? 'install zenity or kdialog, or enter the image path manually'
|
|
32
|
+
: 'no native image picker is available; enter the image path manually',
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const result = await runPickerCommand(command, options.spawnImpl ?? spawn, options.timeoutMs ?? 120_000)
|
|
36
|
+
if (!result.ok) return result
|
|
37
|
+
const file = result.file.trim()
|
|
38
|
+
if (!file) return { ok: false, cancelled: true, error: 'image selection cancelled' }
|
|
39
|
+
return { ok: true, file, method: command.method }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolveImagePickerCommand(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): PickerCommand | null {
|
|
43
|
+
if (platform === 'win32') {
|
|
44
|
+
const powershell = findExecutable('powershell.exe', env, platform) ?? findExecutable('pwsh.exe', env, platform)
|
|
45
|
+
if (!powershell) return null
|
|
46
|
+
return {
|
|
47
|
+
cmd: powershell,
|
|
48
|
+
args: [
|
|
49
|
+
'-NoProfile',
|
|
50
|
+
'-STA',
|
|
51
|
+
'-ExecutionPolicy',
|
|
52
|
+
'Bypass',
|
|
53
|
+
'-Command',
|
|
54
|
+
[
|
|
55
|
+
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8',
|
|
56
|
+
'Add-Type -AssemblyName System.Windows.Forms',
|
|
57
|
+
'$dialog = New-Object System.Windows.Forms.OpenFileDialog',
|
|
58
|
+
'$dialog.Title = "Choose agent image"',
|
|
59
|
+
'$dialog.Filter = "Images (*.png;*.jpg;*.jpeg;*.gif;*.webp;*.svg)|*.png;*.jpg;*.jpeg;*.gif;*.webp;*.svg|All files (*.*)|*.*"',
|
|
60
|
+
'$dialog.CheckFileExists = $true',
|
|
61
|
+
'if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $dialog.FileName }',
|
|
62
|
+
].join('; '),
|
|
63
|
+
],
|
|
64
|
+
method: 'windows file picker',
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (platform === 'darwin') {
|
|
68
|
+
return {
|
|
69
|
+
cmd: 'osascript',
|
|
70
|
+
args: [
|
|
71
|
+
'-e',
|
|
72
|
+
'set selectedFile to choose file with prompt "Choose agent image"',
|
|
73
|
+
'-e',
|
|
74
|
+
'POSIX path of selectedFile',
|
|
75
|
+
],
|
|
76
|
+
method: 'macOS file picker',
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const zenity = findExecutable('zenity', env, platform)
|
|
80
|
+
if (zenity) {
|
|
81
|
+
return {
|
|
82
|
+
cmd: zenity,
|
|
83
|
+
args: [
|
|
84
|
+
'--file-selection',
|
|
85
|
+
'--title=Choose agent image',
|
|
86
|
+
'--file-filter=Images | *.png *.jpg *.jpeg *.gif *.webp *.svg',
|
|
87
|
+
],
|
|
88
|
+
method: 'zenity',
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const kdialog = findExecutable('kdialog', env, platform)
|
|
92
|
+
if (kdialog) {
|
|
93
|
+
return {
|
|
94
|
+
cmd: kdialog,
|
|
95
|
+
args: ['--getopenfilename', '.', 'Images (*.png *.jpg *.jpeg *.gif *.webp *.svg)'],
|
|
96
|
+
method: 'kdialog',
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function runPickerCommand(
|
|
103
|
+
command: PickerCommand,
|
|
104
|
+
spawnImpl: typeof spawn,
|
|
105
|
+
timeoutMs: number,
|
|
106
|
+
): Promise<ImageFilePickerResult> {
|
|
107
|
+
return new Promise(resolve => {
|
|
108
|
+
let stdout = ''
|
|
109
|
+
let stderr = ''
|
|
110
|
+
let settled = false
|
|
111
|
+
let child: ReturnType<typeof spawn>
|
|
112
|
+
try {
|
|
113
|
+
child = spawnImpl(command.cmd, command.args, {
|
|
114
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
115
|
+
windowsHide: true,
|
|
116
|
+
})
|
|
117
|
+
} catch (err: unknown) {
|
|
118
|
+
resolve({ ok: false, cancelled: false, error: (err as Error).message })
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
if (settled) return
|
|
123
|
+
settled = true
|
|
124
|
+
child.kill()
|
|
125
|
+
resolve({ ok: false, cancelled: false, error: 'image picker timed out' })
|
|
126
|
+
}, timeoutMs)
|
|
127
|
+
child.stdout?.setEncoding('utf8')
|
|
128
|
+
child.stderr?.setEncoding('utf8')
|
|
129
|
+
child.stdout?.on('data', chunk => { stdout += String(chunk) })
|
|
130
|
+
child.stderr?.on('data', chunk => { stderr += String(chunk) })
|
|
131
|
+
child.on('error', err => {
|
|
132
|
+
if (settled) return
|
|
133
|
+
settled = true
|
|
134
|
+
clearTimeout(timer)
|
|
135
|
+
resolve({ ok: false, cancelled: false, error: err.message })
|
|
136
|
+
})
|
|
137
|
+
child.on('close', code => {
|
|
138
|
+
if (settled) return
|
|
139
|
+
settled = true
|
|
140
|
+
clearTimeout(timer)
|
|
141
|
+
const file = stdout.trim()
|
|
142
|
+
if (code === 0 && file) {
|
|
143
|
+
resolve({ ok: true, file, method: command.method })
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
const detail = stderr.trim()
|
|
147
|
+
const cancelled = code === 0 || /cancel/i.test(detail)
|
|
148
|
+
resolve({ ok: false, cancelled, error: cancelled ? 'image selection cancelled' : detail || `${command.method} exited ${code}` })
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function findExecutable(command: string, env: NodeJS.ProcessEnv, platform: NodeJS.Platform): string | null {
|
|
154
|
+
const hasPathSeparator = command.includes('/') || command.includes('\\')
|
|
155
|
+
if (hasPathSeparator || path.isAbsolute(command)) return canAccessExecutable(command) ? command : null
|
|
156
|
+
const pathParts = (env.PATH ?? '').split(path.delimiter).filter(Boolean)
|
|
157
|
+
const extensions = platform === 'win32'
|
|
158
|
+
? (env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean)
|
|
159
|
+
: ['']
|
|
160
|
+
for (const dir of pathParts) {
|
|
161
|
+
for (const ext of extensions) {
|
|
162
|
+
const candidate = path.join(dir, platform === 'win32' && path.extname(command) === '' ? `${command}${ext}` : command)
|
|
163
|
+
if (canAccessExecutable(candidate)) return candidate
|
|
164
|
+
if (platform === 'win32') {
|
|
165
|
+
const lower = path.join(dir, platform === 'win32' && path.extname(command) === '' ? `${command}${ext.toLowerCase()}` : command)
|
|
166
|
+
if (canAccessExecutable(lower)) return lower
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return null
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function canAccessExecutable(file: string): boolean {
|
|
174
|
+
try {
|
|
175
|
+
fs.accessSync(file, fs.constants.X_OK)
|
|
176
|
+
return true
|
|
177
|
+
} catch {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
}
|