ethagent 0.2.1 → 1.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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -32
  3. package/bin/ethagent.js +11 -2
  4. package/package.json +25 -7
  5. package/src/app/FirstRun.tsx +412 -0
  6. package/src/app/hooks/useCancelRequest.ts +22 -0
  7. package/src/app/hooks/useDoublePress.ts +46 -0
  8. package/src/app/hooks/useExitOnCtrlC.ts +36 -0
  9. package/src/app/input/AppInputProvider.tsx +116 -0
  10. package/src/app/input/appInputParser.ts +279 -0
  11. package/src/app/keybindings/KeybindingProvider.tsx +134 -0
  12. package/src/app/keybindings/resolver.ts +42 -0
  13. package/src/app/keybindings/types.ts +26 -0
  14. package/src/chat/ChatBottomPane.tsx +280 -0
  15. package/src/chat/ChatInput.tsx +722 -0
  16. package/src/chat/ChatScreen.tsx +1575 -0
  17. package/src/chat/ContextLimitView.tsx +95 -0
  18. package/src/chat/ContinuityEditReviewView.tsx +48 -0
  19. package/src/chat/ConversationStack.tsx +47 -0
  20. package/src/chat/CopyPicker.tsx +52 -0
  21. package/src/chat/MessageList.tsx +609 -0
  22. package/src/chat/PermissionPrompt.tsx +153 -0
  23. package/src/chat/PermissionsView.tsx +159 -0
  24. package/src/chat/PlanApprovalView.tsx +91 -0
  25. package/src/chat/ResumeView.tsx +267 -0
  26. package/src/chat/RewindView.tsx +386 -0
  27. package/src/chat/SessionStatus.tsx +51 -0
  28. package/src/chat/TranscriptView.tsx +202 -0
  29. package/src/chat/chatInputState.ts +247 -0
  30. package/src/chat/chatPaste.ts +49 -0
  31. package/src/chat/chatScreenUtils.ts +187 -0
  32. package/src/chat/chatSessionState.ts +142 -0
  33. package/src/chat/chatTurnOrchestrator.ts +701 -0
  34. package/src/chat/commands.ts +673 -0
  35. package/src/chat/textCursor.ts +202 -0
  36. package/src/chat/toolResultDisplay.ts +8 -0
  37. package/src/chat/transcriptViewport.ts +247 -0
  38. package/src/cli/ResetConfirmView.tsx +61 -0
  39. package/src/cli/main.tsx +177 -0
  40. package/src/cli/preview.tsx +19 -0
  41. package/src/cli/reset.ts +106 -0
  42. package/src/identity/continuity/editor.ts +149 -0
  43. package/src/identity/continuity/envelope.ts +345 -0
  44. package/src/identity/continuity/history.ts +153 -0
  45. package/src/identity/continuity/privateEdit.ts +334 -0
  46. package/src/identity/continuity/publicSkills.ts +173 -0
  47. package/src/identity/continuity/snapshots.ts +183 -0
  48. package/src/identity/continuity/storage.ts +507 -0
  49. package/src/identity/crypto/backupEnvelope.ts +486 -0
  50. package/src/identity/crypto/eth.ts +137 -0
  51. package/src/identity/hub/IdentityHub.tsx +845 -0
  52. package/src/identity/hub/identityHubEffects.ts +1100 -0
  53. package/src/identity/hub/identityHubModel.ts +291 -0
  54. package/src/identity/hub/identityHubReducer.ts +209 -0
  55. package/src/identity/hub/screens/BusyScreen.tsx +26 -0
  56. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +139 -0
  57. package/src/identity/hub/screens/CreateFlow.tsx +206 -0
  58. package/src/identity/hub/screens/DetailsScreen.tsx +64 -0
  59. package/src/identity/hub/screens/EditProfileFlow.tsx +145 -0
  60. package/src/identity/hub/screens/ErrorScreen.tsx +35 -0
  61. package/src/identity/hub/screens/IdentitySummary.tsx +70 -0
  62. package/src/identity/hub/screens/MenuScreen.tsx +117 -0
  63. package/src/identity/hub/screens/NetworkScreen.tsx +41 -0
  64. package/src/identity/hub/screens/RebackupStorageScreen.tsx +50 -0
  65. package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +85 -0
  66. package/src/identity/hub/screens/RestoreFlow.tsx +206 -0
  67. package/src/identity/hub/screens/StorageCredentialScreen.tsx +128 -0
  68. package/src/identity/hub/screens/WalletApprovalScreen.tsx +43 -0
  69. package/src/identity/profile/imagePicker.ts +180 -0
  70. package/src/identity/registry/erc8004.ts +1106 -0
  71. package/src/identity/registry/registryConfig.ts +69 -0
  72. package/src/identity/storage/ipfs.ts +212 -0
  73. package/src/identity/storage/pinataJwt.ts +53 -0
  74. package/src/identity/wallet/browserWallet.ts +393 -0
  75. package/src/identity/wallet/wallet-page/wallet.html +1082 -0
  76. package/src/mcp/approvals.ts +113 -0
  77. package/src/mcp/config.ts +235 -0
  78. package/src/mcp/manager.ts +541 -0
  79. package/src/mcp/names.ts +19 -0
  80. package/src/mcp/output.ts +96 -0
  81. package/src/models/ModelPicker.tsx +1446 -0
  82. package/src/models/catalog.ts +296 -0
  83. package/src/models/huggingface.ts +651 -0
  84. package/src/models/llamacpp.ts +810 -0
  85. package/src/models/llamacppPreflight.ts +150 -0
  86. package/src/models/modelDisplay.ts +105 -0
  87. package/src/models/modelPickerOptions.ts +421 -0
  88. package/src/models/modelRecommendation.ts +140 -0
  89. package/src/models/runtimeDetection.ts +81 -0
  90. package/src/models/uncensoredCatalog.ts +86 -0
  91. package/src/providers/anthropic.ts +259 -0
  92. package/src/providers/contracts.ts +62 -0
  93. package/src/providers/errors.ts +62 -0
  94. package/src/providers/gemini.ts +152 -0
  95. package/src/providers/openai-chat.ts +472 -0
  96. package/src/providers/registry.ts +42 -0
  97. package/src/providers/retry.ts +58 -0
  98. package/src/providers/sse.ts +93 -0
  99. package/src/runtime/compaction.ts +389 -0
  100. package/src/runtime/cwd.ts +43 -0
  101. package/src/runtime/sessionMode.ts +55 -0
  102. package/src/runtime/systemPrompt.ts +209 -0
  103. package/src/runtime/toolClaimGuards.ts +143 -0
  104. package/src/runtime/toolExecution.ts +304 -0
  105. package/src/runtime/toolIntent.ts +163 -0
  106. package/src/runtime/turn.ts +858 -0
  107. package/src/storage/atomicWrite.ts +68 -0
  108. package/src/storage/config.ts +189 -0
  109. package/src/storage/factoryReset.ts +130 -0
  110. package/src/storage/history.ts +58 -0
  111. package/src/storage/identity.ts +99 -0
  112. package/src/storage/permissions.ts +76 -0
  113. package/src/storage/rewind.ts +246 -0
  114. package/src/storage/secrets.ts +181 -0
  115. package/src/storage/sessionExport.ts +49 -0
  116. package/src/storage/sessions.ts +482 -0
  117. package/src/tools/bashSafety.ts +174 -0
  118. package/src/tools/bashTool.ts +140 -0
  119. package/src/tools/changeDirectoryTool.ts +213 -0
  120. package/src/tools/contracts.ts +179 -0
  121. package/src/tools/deleteFileTool.ts +111 -0
  122. package/src/tools/editTool.ts +160 -0
  123. package/src/tools/editUtils.ts +170 -0
  124. package/src/tools/listDirectoryTool.ts +55 -0
  125. package/src/tools/mcpResourceTools.ts +95 -0
  126. package/src/tools/permissionRules.ts +85 -0
  127. package/src/tools/privateContinuityEditTool.ts +178 -0
  128. package/src/tools/privateContinuityReadTool.ts +107 -0
  129. package/src/tools/readTool.ts +85 -0
  130. package/src/tools/registry.ts +67 -0
  131. package/src/tools/writeFileTool.ts +142 -0
  132. package/src/ui/BrandSplash.tsx +193 -0
  133. package/src/ui/ProgressBar.tsx +34 -0
  134. package/src/ui/Select.tsx +143 -0
  135. package/src/ui/Spinner.tsx +269 -0
  136. package/src/ui/Surface.tsx +47 -0
  137. package/src/ui/TextInput.tsx +97 -0
  138. package/src/ui/theme.ts +59 -0
  139. package/src/utils/clipboard.ts +216 -0
  140. package/src/utils/markdownSegments.ts +51 -0
  141. package/src/utils/messages.ts +35 -0
  142. package/src/utils/withRetry.ts +280 -0
  143. 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
+ }