ethagent 3.3.4 → 4.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.
Files changed (322) hide show
  1. package/.claude-plugin/marketplace.json +11 -0
  2. package/.claude-plugin/plugin.json +35 -0
  3. package/LICENSE +1 -1
  4. package/README.md +64 -104
  5. package/commands/ethagent.md +40 -0
  6. package/package.json +16 -16
  7. package/src/app/keybindings/KeybindingProvider.tsx +1 -6
  8. package/src/app/keybindings/types.ts +1 -6
  9. package/src/cli/ResetConfirmView.tsx +54 -53
  10. package/src/cli/demo.ts +86 -0
  11. package/src/cli/hookIo.ts +45 -0
  12. package/src/cli/main.tsx +94 -123
  13. package/src/cli/memoryGuard.ts +49 -0
  14. package/src/cli/reset.ts +28 -70
  15. package/src/cli/sessionStart.ts +33 -0
  16. package/src/cli/status.ts +46 -0
  17. package/src/cli/sync.ts +167 -0
  18. package/src/cli/syncAdapters/claude-code.ts +86 -0
  19. package/src/cli/syncAdapters/codex.ts +66 -0
  20. package/src/cli/syncAdapters/index.ts +45 -0
  21. package/src/cli/syncAdapters/managedBlock.ts +175 -0
  22. package/src/cli/syncAdapters/shared.ts +63 -0
  23. package/src/identity/continuity/envelopeParse.ts +20 -1
  24. package/src/identity/continuity/publicSkills.ts +3 -1
  25. package/src/identity/continuity/skills/publicSkillsSync.ts +2 -1
  26. package/src/identity/continuity/skills/scaffold.ts +5 -2
  27. package/src/identity/continuity/snapshots.ts +12 -5
  28. package/src/identity/continuity/storage/defaults.ts +20 -19
  29. package/src/identity/continuity/storage/status.ts +1 -1
  30. package/src/identity/ens/ensLookup/constants.ts +1 -1
  31. package/src/identity/manager/IdentityManager.tsx +33 -0
  32. package/src/identity/{hub → manager}/OperationalRoutes.tsx +37 -18
  33. package/src/identity/{hub → manager}/Routes.tsx +48 -34
  34. package/src/identity/{hub → manager}/continuity/ContinuityDashboardScreen.tsx +9 -19
  35. package/src/identity/{hub → manager}/continuity/RebackupStorageScreen.tsx +3 -3
  36. package/src/identity/manager/continuity/RecoveryConfirmScreen.tsx +102 -0
  37. package/src/identity/{hub → manager}/continuity/SavePromptScreen.tsx +2 -3
  38. package/src/identity/{hub → manager}/continuity/completion.ts +1 -1
  39. package/src/identity/{hub → manager}/continuity/effects.ts +1 -1
  40. package/src/identity/{hub → manager}/continuity/skills/DeleteSkillConfirmScreen.tsx +2 -2
  41. package/src/identity/{hub → manager}/continuity/skills/NewSkillScreen.tsx +0 -5
  42. package/src/identity/{hub → manager}/continuity/skills/NewSkillVisibilityScreen.tsx +4 -4
  43. package/src/identity/{hub → manager}/continuity/skills/SkillActionsScreen.tsx +6 -22
  44. package/src/identity/{hub → manager}/continuity/skills/SkillsTreeScreen.tsx +5 -17
  45. package/src/identity/{hub → manager}/continuity/snapshot.ts +1 -1
  46. package/src/identity/{hub → manager}/continuity/vault.ts +1 -1
  47. package/src/identity/{hub → manager}/create/CreateFlow.tsx +59 -32
  48. package/src/identity/{hub → manager}/create/effects.ts +19 -10
  49. package/src/identity/manager/create/importScan.ts +122 -0
  50. package/src/identity/{hub → manager}/custody/CustodyEditFlow.tsx +17 -61
  51. package/src/identity/{hub → manager}/custody/actions.ts +1 -15
  52. package/src/identity/{hub → manager}/custody/routes.tsx +20 -40
  53. package/src/identity/{hub → manager}/custody/transactions.ts +1 -0
  54. package/src/identity/{hub → manager}/custody/types.ts +1 -2
  55. package/src/identity/{hub → manager}/custody/useCustodyEffects.ts +1 -1
  56. package/src/identity/{hub → manager}/ens/EnsEditAdvancedScreens.tsx +2 -2
  57. package/src/identity/{hub → manager}/ens/EnsEditMaintenanceScreens.tsx +12 -23
  58. package/src/identity/{hub → manager}/ens/EnsEditReviewScreens.tsx +18 -42
  59. package/src/identity/{hub → manager}/ens/EnsEditRunners.tsx +1 -1
  60. package/src/identity/{hub → manager}/ens/EnsEditShared.tsx +0 -2
  61. package/src/identity/{hub → manager}/ens/EnsEditSimpleScreens.tsx +10 -19
  62. package/src/identity/{hub → manager}/ens/EnsFlow.tsx +133 -41
  63. package/src/identity/{hub → manager}/ens/EnsOperatorWalletsScreen.tsx +14 -19
  64. package/src/identity/{hub → manager}/ens/editCopy.ts +1 -14
  65. package/src/identity/{hub → manager}/profile/EditProfileFlow.tsx +99 -66
  66. package/src/identity/{hub → manager}/profile/effects.ts +1 -3
  67. package/src/identity/{hub → manager}/profile/operatorSave.ts +1 -1
  68. package/src/identity/{hub → manager}/profile/state.ts +1 -1
  69. package/src/identity/{hub/identityHubReducer.ts → manager/reducer.ts} +25 -26
  70. package/src/identity/{hub → manager}/restore/RestoreFlow.tsx +16 -24
  71. package/src/identity/{hub → manager}/restore/apply.ts +1 -1
  72. package/src/identity/{hub → manager}/restore/auth.ts +1 -1
  73. package/src/identity/{hub → manager}/restore/discover.ts +1 -1
  74. package/src/identity/{hub → manager}/restore/fetch.ts +1 -1
  75. package/src/identity/{hub → manager}/restore/restoreAdmin.ts +1 -1
  76. package/src/identity/{hub → manager}/restore/useRestoreEffects.ts +2 -9
  77. package/src/identity/{hub → manager}/settings/StorageCredentialScreen.tsx +10 -25
  78. package/src/identity/{hub → manager}/shared/components/DetailsScreen.tsx +5 -7
  79. package/src/identity/{hub → manager}/shared/components/ErrorScreen.tsx +6 -10
  80. package/src/identity/{hub → manager}/shared/components/FlowTimeline.tsx +4 -3
  81. package/src/identity/{hub → manager}/shared/components/IdentitySummary.tsx +19 -59
  82. package/src/identity/manager/shared/components/LazyMenu.tsx +147 -0
  83. package/src/identity/manager/shared/components/MenuScreen.tsx +220 -0
  84. package/src/identity/manager/shared/components/OperationCompleteScreen.tsx +28 -0
  85. package/src/identity/{hub → manager}/shared/components/UnlinkedIdentityScreen.tsx +9 -10
  86. package/src/identity/{hub → manager}/shared/components/WalletApprovalScreen.tsx +1 -2
  87. package/src/identity/manager/shared/components/Wordmark.tsx +54 -0
  88. package/src/identity/{hub → manager}/shared/components/menuFlagsFromReconciliation.ts +39 -15
  89. package/src/identity/{hub → manager}/shared/effects/profilePrep.ts +1 -1
  90. package/src/identity/manager/shared/effects/types.ts +30 -0
  91. package/src/identity/{hub → manager}/shared/model/copy.ts +0 -4
  92. package/src/identity/{hub → manager}/shared/model/errors.ts +32 -3
  93. package/src/identity/{hub → manager}/shared/model/network.ts +2 -2
  94. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/hook.ts +5 -0
  95. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/run.ts +1 -1
  96. package/src/identity/{hub/shared/reconciliation/useAgentReconciliation.ts → manager/shared/reconciliation/index.ts} +6 -0
  97. package/src/identity/{hub → manager}/shared/utils.ts +6 -10
  98. package/src/identity/{hub → manager}/transfer/TokenTransferFlow.tsx +3 -3
  99. package/src/identity/{hub → manager}/transfer/TokenTransferScreens.tsx +4 -10
  100. package/src/identity/{hub → manager}/transfer/effects.ts +1 -1
  101. package/src/identity/{hub → manager}/types.ts +5 -6
  102. package/src/identity/{hub/useIdentityHubContinuity.ts → manager/useContinuity.ts} +59 -27
  103. package/src/identity/{hub/useIdentityHubController.ts → manager/useController.ts} +38 -35
  104. package/src/identity/{hub/useIdentityHubSideEffects.ts → manager/useSideEffects.ts} +40 -4
  105. package/src/identity/registry/erc8004/discovery.ts +3 -17
  106. package/src/identity/registry/erc8004/utils.ts +1 -1
  107. package/src/identity/storage/ipfs.ts +21 -1
  108. package/src/identity/wallet/browserWallet/html.ts +10 -2
  109. package/src/identity/wallet/browserWallet/http.ts +18 -0
  110. package/src/identity/wallet/browserWallet/requestServer.ts +5 -1
  111. package/src/identity/wallet/browserWallet/requests.ts +10 -28
  112. package/src/identity/wallet/browserWallet/session.ts +26 -33
  113. package/src/identity/wallet/browserWallet/validation.ts +14 -0
  114. package/src/identity/wallet/browserWallet/walletPageSource.ts +22 -40
  115. package/src/identity/wallet/page/boot.ts +43 -0
  116. package/src/identity/wallet/page/config.ts +59 -0
  117. package/src/identity/wallet/page/constants.ts +12 -0
  118. package/src/identity/wallet/page/copy.ts +47 -68
  119. package/src/identity/wallet/page/css.ts +638 -0
  120. package/src/identity/wallet/page/{errorView.ts → errors.ts} +5 -14
  121. package/src/identity/wallet/page/{controller.ts → flow.ts} +4 -71
  122. package/src/identity/wallet/page/markup.ts +44 -34
  123. package/src/identity/wallet/page/{walletProvider.ts → provider.ts} +0 -3
  124. package/src/identity/wallet/page/resize.ts +95 -0
  125. package/src/identity/wallet/page/state.ts +135 -8
  126. package/src/identity/wallet/page/timeline.ts +161 -0
  127. package/src/identity/wallet/page/view.ts +22 -302
  128. package/src/storage/config.ts +30 -80
  129. package/src/storage/reset.ts +31 -0
  130. package/src/storage/secrets.ts +1 -16
  131. package/src/ui/Select.tsx +27 -5
  132. package/src/ui/Spinner.tsx +16 -15
  133. package/src/ui/Surface.tsx +21 -17
  134. package/src/ui/TextArea.tsx +173 -0
  135. package/src/ui/TextInput.tsx +31 -133
  136. package/src/ui/theme.ts +22 -13
  137. package/src/utils/clipboard.ts +0 -140
  138. package/src/app/FirstRun.tsx +0 -577
  139. package/src/app/FirstRunTimeline.tsx +0 -51
  140. package/src/app/firstRunConfig.ts +0 -26
  141. package/src/app/hooks/useCancelRequest.ts +0 -22
  142. package/src/app/hooks/useDoublePress.ts +0 -46
  143. package/src/app/hooks/useExitOnCtrlC.ts +0 -36
  144. package/src/auth/openaiOAuth/credentials.ts +0 -47
  145. package/src/auth/openaiOAuth/crypto.ts +0 -23
  146. package/src/auth/openaiOAuth/index.ts +0 -238
  147. package/src/auth/openaiOAuth/landingPage.ts +0 -116
  148. package/src/auth/openaiOAuth/listener.ts +0 -151
  149. package/src/auth/openaiOAuth/refresh.ts +0 -70
  150. package/src/auth/openaiOAuth/shared.ts +0 -115
  151. package/src/chat/ChatBottomPane.tsx +0 -296
  152. package/src/chat/ChatScreen.tsx +0 -1685
  153. package/src/chat/ConversationStack.tsx +0 -56
  154. package/src/chat/MessageList.tsx +0 -638
  155. package/src/chat/SessionStatus.tsx +0 -53
  156. package/src/chat/chatEnvironment.ts +0 -16
  157. package/src/chat/chatScreenUtils.ts +0 -194
  158. package/src/chat/chatSessionState.ts +0 -146
  159. package/src/chat/chatTurnContext.ts +0 -50
  160. package/src/chat/chatTurnOrchestrator.ts +0 -603
  161. package/src/chat/chatTurnRows.ts +0 -64
  162. package/src/chat/commands.ts +0 -494
  163. package/src/chat/continuityEditReview.ts +0 -42
  164. package/src/chat/display/DiffView.tsx +0 -193
  165. package/src/chat/display/SyntaxText.tsx +0 -192
  166. package/src/chat/display/toolCallDisplay.ts +0 -103
  167. package/src/chat/display/toolResultDisplay.ts +0 -19
  168. package/src/chat/input/ChatInput.tsx +0 -625
  169. package/src/chat/input/chatInputHelpers.ts +0 -62
  170. package/src/chat/input/chatInputState.ts +0 -247
  171. package/src/chat/input/chatPaste.ts +0 -49
  172. package/src/chat/input/imageRefs.ts +0 -30
  173. package/src/chat/input/inputRendering.tsx +0 -93
  174. package/src/chat/input/textCursor.ts +0 -212
  175. package/src/chat/messageMarkdown.ts +0 -220
  176. package/src/chat/messageRows.ts +0 -43
  177. package/src/chat/planImplementation.ts +0 -62
  178. package/src/chat/slashCommandHandlers.ts +0 -122
  179. package/src/chat/slashCommandViews.ts +0 -120
  180. package/src/chat/transcript/TranscriptView.tsx +0 -184
  181. package/src/chat/transcript/transcriptViewport.ts +0 -295
  182. package/src/chat/views/ContextLimitView.tsx +0 -95
  183. package/src/chat/views/ContinuityEditReviewView.tsx +0 -50
  184. package/src/chat/views/CopyPicker.tsx +0 -50
  185. package/src/chat/views/PermissionPrompt.tsx +0 -156
  186. package/src/chat/views/PermissionsView.tsx +0 -165
  187. package/src/chat/views/PlanApprovalView.tsx +0 -91
  188. package/src/chat/views/ResumeView.tsx +0 -273
  189. package/src/chat/views/RewindView.tsx +0 -412
  190. package/src/cli/preview.tsx +0 -14
  191. package/src/cli/updateNotice.ts +0 -54
  192. package/src/identity/continuity/privateEdit/apply.ts +0 -170
  193. package/src/identity/continuity/privateEdit/diff.ts +0 -6
  194. package/src/identity/continuity/privateEdit/files.ts +0 -23
  195. package/src/identity/continuity/privateEdit/types.ts +0 -28
  196. package/src/identity/continuity/privateEdit.ts +0 -46
  197. package/src/identity/hub/IdentityHub.tsx +0 -14
  198. package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +0 -104
  199. package/src/identity/hub/ens/effects.ts +0 -218
  200. package/src/identity/hub/shared/components/MenuScreen.tsx +0 -241
  201. package/src/identity/hub/shared/effects/types.ts +0 -53
  202. package/src/identity/hub/shared/reconciliation/index.ts +0 -14
  203. package/src/identity/wallet/page/grainient.ts +0 -278
  204. package/src/identity/wallet/page/html.ts +0 -28
  205. package/src/identity/wallet/page/styles/base.ts +0 -260
  206. package/src/identity/wallet/page/styles/components.ts +0 -262
  207. package/src/identity/wallet/page/styles/index.ts +0 -5
  208. package/src/identity/wallet/page/styles/responsive.ts +0 -247
  209. package/src/identity/wallet/page.tsx +0 -38
  210. package/src/mcp/approvals.ts +0 -113
  211. package/src/mcp/config.ts +0 -235
  212. package/src/mcp/manager.ts +0 -482
  213. package/src/mcp/managerHelpers.ts +0 -70
  214. package/src/mcp/names.ts +0 -19
  215. package/src/mcp/output.ts +0 -96
  216. package/src/models/ModelPicker.tsx +0 -1009
  217. package/src/models/catalog.ts +0 -327
  218. package/src/models/huggingface.ts +0 -712
  219. package/src/models/huggingfaceStorage.ts +0 -136
  220. package/src/models/llamacpp.ts +0 -848
  221. package/src/models/llamacppCommands.ts +0 -44
  222. package/src/models/llamacppConfig.ts +0 -34
  223. package/src/models/llamacppDiscovery.ts +0 -176
  224. package/src/models/llamacppOutput.ts +0 -65
  225. package/src/models/llamacppPreflight.ts +0 -158
  226. package/src/models/modelDisplay.ts +0 -180
  227. package/src/models/modelPickerCatalogFlow.ts +0 -56
  228. package/src/models/modelPickerCredentials.ts +0 -166
  229. package/src/models/modelPickerData.ts +0 -41
  230. package/src/models/modelPickerDisplay.tsx +0 -132
  231. package/src/models/modelPickerHfFlow.ts +0 -192
  232. package/src/models/modelPickerLocalRunnerFlow.ts +0 -115
  233. package/src/models/modelPickerOptions.ts +0 -457
  234. package/src/models/modelPickerTypes.ts +0 -69
  235. package/src/models/modelPickerUninstallFlow.ts +0 -48
  236. package/src/models/modelPickerViewHelpers.ts +0 -174
  237. package/src/models/modelRecommendation.ts +0 -139
  238. package/src/models/providerDisplay.ts +0 -16
  239. package/src/models/runtimeDetection.ts +0 -81
  240. package/src/models/uncensoredCatalog.ts +0 -86
  241. package/src/providers/anthropic.ts +0 -290
  242. package/src/providers/contracts.ts +0 -71
  243. package/src/providers/errors.ts +0 -80
  244. package/src/providers/gemini.ts +0 -391
  245. package/src/providers/openai-chat.ts +0 -474
  246. package/src/providers/openai-responses-format.ts +0 -177
  247. package/src/providers/openai-responses.ts +0 -306
  248. package/src/providers/openaiChatWire.ts +0 -124
  249. package/src/providers/registry.ts +0 -120
  250. package/src/providers/retry.ts +0 -58
  251. package/src/providers/sse.ts +0 -93
  252. package/src/runtime/compaction.ts +0 -395
  253. package/src/runtime/cwd.ts +0 -43
  254. package/src/runtime/providerTurn.ts +0 -38
  255. package/src/runtime/sessionMode.ts +0 -55
  256. package/src/runtime/systemPrompt.ts +0 -213
  257. package/src/runtime/textToolParser.ts +0 -161
  258. package/src/runtime/toolClaimGuards.ts +0 -143
  259. package/src/runtime/toolExecution.ts +0 -304
  260. package/src/runtime/toolIntent.ts +0 -143
  261. package/src/runtime/turn.ts +0 -369
  262. package/src/runtime/turnNudges.ts +0 -223
  263. package/src/runtime/turnTypes.ts +0 -86
  264. package/src/storage/factoryReset.ts +0 -127
  265. package/src/storage/history.ts +0 -58
  266. package/src/storage/permissions.ts +0 -76
  267. package/src/storage/rewind.ts +0 -266
  268. package/src/storage/sessionExport.ts +0 -49
  269. package/src/storage/sessions.ts +0 -495
  270. package/src/tools/bashSafety.ts +0 -186
  271. package/src/tools/bashTool.ts +0 -140
  272. package/src/tools/changeDirectoryTool.ts +0 -213
  273. package/src/tools/contracts.ts +0 -192
  274. package/src/tools/deleteFileTool.ts +0 -116
  275. package/src/tools/editTool.ts +0 -165
  276. package/src/tools/editUtils.ts +0 -170
  277. package/src/tools/fileDiff.ts +0 -261
  278. package/src/tools/listDirectoryTool.ts +0 -55
  279. package/src/tools/listSkillFilesTool.ts +0 -77
  280. package/src/tools/listSkillsTool.ts +0 -68
  281. package/src/tools/mcpResourceTools.ts +0 -95
  282. package/src/tools/permissionRules.ts +0 -85
  283. package/src/tools/privateContinuityEditTool.ts +0 -187
  284. package/src/tools/privateContinuityReadTool.ts +0 -106
  285. package/src/tools/readSkillTool.ts +0 -107
  286. package/src/tools/readTool.ts +0 -85
  287. package/src/tools/registry.ts +0 -103
  288. package/src/tools/writeFileTool.ts +0 -167
  289. package/src/ui/BrandSplash.tsx +0 -133
  290. package/src/ui/terminalTitle.ts +0 -30
  291. package/src/utils/images.ts +0 -140
  292. package/src/utils/markdownSegments.ts +0 -51
  293. package/src/utils/messages.ts +0 -37
  294. package/src/utils/withRetry.ts +0 -324
  295. /package/src/identity/{hub → manager}/continuity/state.ts +0 -0
  296. /package/src/identity/{hub → manager}/custody/helpers.ts +0 -0
  297. /package/src/identity/{hub → manager}/custody/preflight.ts +0 -0
  298. /package/src/identity/{hub → manager}/custody/state.ts +0 -0
  299. /package/src/identity/{hub → manager}/custody/useCustodyFlow.tsx +0 -0
  300. /package/src/identity/{hub → manager}/ens/EnsEditFlow.tsx +0 -0
  301. /package/src/identity/{hub → manager}/ens/advancedEnsValidation.ts +0 -0
  302. /package/src/identity/{hub → manager}/ens/state.ts +0 -0
  303. /package/src/identity/{hub → manager}/ens/transactions.ts +0 -0
  304. /package/src/identity/{hub → manager}/ens/types.ts +0 -0
  305. /package/src/identity/{hub → manager}/profile/identity.ts +0 -0
  306. /package/src/identity/{hub → manager}/restore/envelopes.ts +0 -0
  307. /package/src/identity/{hub → manager}/restore/helpers.ts +0 -0
  308. /package/src/identity/{hub → manager}/restore/recovery.ts +0 -0
  309. /package/src/identity/{hub → manager}/restore/resolve.ts +0 -0
  310. /package/src/identity/{hub → manager}/shared/components/BusyScreen.tsx +0 -0
  311. /package/src/identity/{hub → manager}/shared/components/NetworkScreen.tsx +0 -0
  312. /package/src/identity/{hub → manager}/shared/components/PinataJwtInput.tsx +0 -0
  313. /package/src/identity/{hub → manager}/shared/effects/receipts.ts +0 -0
  314. /package/src/identity/{hub → manager}/shared/effects/sync.ts +0 -0
  315. /package/src/identity/{hub → manager}/shared/model/format.ts +0 -0
  316. /package/src/identity/{hub → manager}/shared/operatorWallets.ts +0 -0
  317. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/ownership.ts +0 -0
  318. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/types.ts +0 -0
  319. /package/src/identity/{hub → manager}/shared/reconciliation/walletSetup.ts +0 -0
  320. /package/src/identity/{hub → manager}/shared/txGuard.ts +0 -0
  321. /package/src/identity/{hub → manager}/transfer/progress.ts +0 -0
  322. /package/src/identity/{hub → manager}/transfer/state.ts +0 -0
@@ -1,53 +0,0 @@
1
- import React from 'react'
2
- import { Box, Text } from 'ink'
3
- import type { ContextUsage } from '../runtime/compaction.js'
4
- import { theme } from '../ui/theme.js'
5
- import { formatModelDisplayName } from '../models/modelDisplay.js'
6
- import { providerDisplayName } from '../models/providerDisplay.js'
7
- import type { ProviderId } from '../storage/config.js'
8
-
9
- type StatusBarProps = {
10
- provider: string
11
- model: string
12
- turns: number
13
- approxTokens: number
14
- startedAt: number
15
- contextUsage: ContextUsage
16
- }
17
-
18
- const SessionStatusInner: React.FC<StatusBarProps> = ({
19
- provider,
20
- model,
21
- turns,
22
- approxTokens,
23
- startedAt,
24
- contextUsage,
25
- }) => {
26
- const displayModel = formatModelDisplayName(provider, model, { maxLength: 24 })
27
- return (
28
- <Box flexDirection="row">
29
- <Text color={theme.dim}>
30
- {providerDisplayName(provider as ProviderId)} · {displayModel} · {turns} {turns === 1 ? 'turn' : 'turns'} · ~{formatTokens(approxTokens)} tokens · Context {contextUsage.percent}% (~{formatTokens(contextUsage.usedTokens)} / {formatTokens(contextUsage.windowTokens)}) · {formatElapsed(Date.now() - startedAt)}
31
- </Text>
32
- </Box>
33
- )
34
- }
35
-
36
- export const SessionStatus = React.memo(SessionStatusInner)
37
-
38
- export function formatTokens(count: number): string {
39
- if (count < 1000) return String(count)
40
- if (count < 10_000) return `${(count / 1000).toFixed(1)}k`
41
- return `${Math.round(count / 1000)}k`
42
- }
43
-
44
- export function formatElapsed(ms: number): string {
45
- const seconds = Math.max(0, Math.floor(ms / 1000))
46
- if (seconds < 60) return `${seconds}s`
47
- const minutes = Math.floor(seconds / 60)
48
- const rem = seconds % 60
49
- if (minutes < 60) return `${minutes}m${rem.toString().padStart(2, '0')}s`
50
- const hours = Math.floor(minutes / 60)
51
- const minRem = minutes % 60
52
- return `${hours}h${minRem.toString().padStart(2, '0')}m`
53
- }
@@ -1,16 +0,0 @@
1
- import os from 'node:os'
2
- import path from 'node:path'
3
- import type { EthagentConfig } from '../storage/config.js'
4
- import { ensureLlamaCppRunnerReady } from '../models/llamacppPreflight.js'
5
-
6
- export function compressHome(cwd: string): string {
7
- const home = os.homedir()
8
- if (cwd === home) return '~'
9
- if (cwd.startsWith(home + path.sep)) return '~' + cwd.slice(home.length).replace(/\\/g, '/')
10
- return cwd.replace(/\\/g, '/')
11
- }
12
-
13
- export async function ensureLocalProviderReady(config: EthagentConfig): Promise<{ ok: true } | { ok: false; message: string }> {
14
- if (config.provider === 'llamacpp') return ensureLlamaCppRunnerReady(config)
15
- return { ok: true }
16
- }
@@ -1,194 +0,0 @@
1
- import { systemMessage } from '../utils/messages.js'
2
- import { buildSystemPrompt } from '../runtime/systemPrompt.js'
3
- import type { Message } from '../providers/contracts.js'
4
- import { isLocalProvider } from '../providers/registry.js'
5
- import type { SessionMode } from '../runtime/sessionMode.js'
6
- import type { EthagentConfig } from '../storage/config.js'
7
- import {
8
- latestUserMessageCorrectsToolState,
9
- sessionMessagesToProviderMessages,
10
- TOOL_CORRECTION_CONTEXT_MESSAGE,
11
- type SessionMessage,
12
- } from '../storage/sessions.js'
13
- import type { MessageRow } from './MessageList.js'
14
- import { hidesSuccessfulToolResultContent, toolResultDiffContent, toolResultTextContent } from './display/toolResultDisplay.js'
15
-
16
- export type TurnCheckpoint = {
17
- sessionId: string
18
- turnId: string
19
- messageRole: 'user'
20
- promptSnippet: string
21
- checkpointLabel: string
22
- }
23
-
24
- export function buildBaseMessages(
25
- sessionMessages: SessionMessage[],
26
- config: EthagentConfig,
27
- hasTools: boolean,
28
- cwd: string,
29
- mode: SessionMode = 'chat',
30
- options: { preserveTurnId?: string; compactToolHistory?: boolean } = {},
31
- ): Message[] {
32
- const compactToolHistory = options.compactToolHistory ?? isLocalProvider(config.provider)
33
- const correctionContext = latestUserMessageCorrectsToolState(sessionMessages)
34
- ? [systemMessage(TOOL_CORRECTION_CONTEXT_MESSAGE)]
35
- : []
36
- return [
37
- systemMessage(buildSystemPrompt({
38
- cwd,
39
- model: config.model,
40
- provider: config.provider,
41
- hasTools,
42
- hasIdentity: Boolean(config.identity),
43
- mode,
44
- })),
45
- ...correctionContext,
46
- ...sessionMessagesToProviderMessages(sessionMessages, {
47
- compactToolHistory,
48
- preserveTurnId: options.preserveTurnId,
49
- }),
50
- ]
51
- }
52
-
53
- export function sessionMessagesToRows(messages: SessionMessage[], nextRowId: () => string): MessageRow[] {
54
- const restored: MessageRow[] = []
55
- const toolCallByUseId = new Map<string, Extract<MessageRow, { role: 'tool_call' }>>()
56
- for (const msg of messages) {
57
- if (msg.role === 'user') restored.push({ role: 'user', id: nextRowId(), content: msg.content })
58
- else if (msg.role === 'assistant') restored.push({ role: 'assistant', id: nextRowId(), content: msg.content })
59
- else if (msg.role === 'tool_use') {
60
- const row: Extract<MessageRow, { role: 'tool_call' }> = {
61
- role: 'tool_call',
62
- id: nextRowId(),
63
- name: msg.name,
64
- summary: msg.name,
65
- input: msg.input,
66
- }
67
- restored.push(row)
68
- toolCallByUseId.set(msg.toolUseId, row)
69
- } else if (msg.role === 'tool_result') {
70
- const isError = Boolean(msg.isError)
71
- const summary = isError ? `${msg.name} failed` : `${msg.name} completed`
72
- const content = toolResultContentForRow(msg.name, msg.content, msg.isError)
73
- const diff = toolResultDiffForRow(msg.content, msg.isError)
74
- const existing = toolCallByUseId.get(msg.toolUseId)
75
- if (existing) {
76
- existing.result = diff ? { content, summary, isError, diff } : { content, summary, isError }
77
- existing.name = msg.name
78
- } else {
79
- restored.push({
80
- role: 'tool_call',
81
- id: nextRowId(),
82
- name: msg.name,
83
- summary: msg.name,
84
- result: diff ? { content, summary, isError, diff } : { content, summary, isError },
85
- })
86
- }
87
- }
88
- }
89
- return restored
90
- }
91
-
92
- export function truncateForRow(text: string, max = 1200): string {
93
- if (text.length <= max) return text
94
- return `${text.slice(0, max - 3)}...`
95
- }
96
-
97
- export function toolResultContentForRow(name: string, content: string, isError?: boolean): string {
98
- const textContent = toolResultTextContent(content)
99
- return hidesSuccessfulToolResultContent(name, isError) ? '' : truncateForRow(textContent)
100
- }
101
-
102
- export function toolResultDiffForRow(content: string, isError?: boolean): string | undefined {
103
- return toolResultDiffContent(content, isError)
104
- }
105
-
106
- export function splitStreamingContent(text: string): { committed: string; liveTail: string } {
107
- if (!text) return { committed: '', liveTail: '' }
108
- const boundary = findStableBoundary(text)
109
- if (boundary <= 0 || boundary >= text.length) {
110
- return { committed: boundary >= text.length ? text : '', liveTail: boundary >= text.length ? '' : text }
111
- }
112
- return { committed: text.slice(0, boundary), liveTail: text.slice(boundary) }
113
- }
114
-
115
- export function findStableBoundary(text: string): number {
116
- let lastStructural = 0
117
- let lastSentence = 0
118
- let inFence = false
119
- let offset = 0
120
- const lines = text.match(/[^\n]*\n?|$/g)?.filter(Boolean) ?? []
121
-
122
- for (const lineWithEnding of lines) {
123
- const line = lineWithEnding.endsWith('\n') ? lineWithEnding.slice(0, -1) : lineWithEnding
124
- const trimmed = line.trim()
125
- const nextOffset = offset + lineWithEnding.length
126
-
127
- if (/^```/.test(trimmed)) {
128
- inFence = !inFence
129
- if (!inFence) lastStructural = nextOffset
130
- offset = nextOffset
131
- continue
132
- }
133
-
134
- if (!inFence) {
135
- if (!trimmed) {
136
- lastStructural = nextOffset
137
- } else if (/^(#{1,3}\s|>\s?|[-*+]\s|\d+\.\s)/.test(trimmed)) {
138
- lastStructural = nextOffset
139
- }
140
-
141
- let match: RegExpExecArray | null
142
- const sentencePattern = /[.!?]["')\]]?(?=\s|$)/g
143
- while ((match = sentencePattern.exec(line)) !== null) {
144
- lastSentence = offset + match.index + match[0].length
145
- }
146
- }
147
-
148
- offset = nextOffset
149
- }
150
-
151
- if (inFence) return lastStructural
152
- if (lastStructural > 0) return lastStructural
153
- if (text.length > 220 && lastSentence > 0) return lastSentence
154
- if (text.length > 320) {
155
- const fallbackSpace = text.lastIndexOf(' ', Math.max(160, text.length - 80))
156
- if (fallbackSpace > 80) return fallbackSpace + 1
157
- }
158
- return 0
159
- }
160
-
161
- export function formatBytes(bytes: number): string {
162
- if (bytes <= 0) return '0B'
163
- const gb = bytes / (1024 * 1024 * 1024)
164
- if (gb >= 1) return `${gb.toFixed(2)}GB`
165
- const mb = bytes / (1024 * 1024)
166
- if (mb >= 1) return `${mb.toFixed(0)}MB`
167
- const kb = bytes / 1024
168
- return `${kb.toFixed(0)}KB`
169
- }
170
-
171
- export function createTurnCheckpoint(sessionId: string, userText: string): TurnCheckpoint {
172
- const promptSnippet = summarizePrompt(userText)
173
- return {
174
- sessionId,
175
- turnId: `turn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
176
- messageRole: 'user',
177
- promptSnippet,
178
- checkpointLabel: promptSnippet || 'Untitled checkpoint',
179
- }
180
- }
181
-
182
- export function summarizePrompt(text: string): string {
183
- const normalized = text.replace(/\s+/g, ' ').trim()
184
- if (!normalized) return ''
185
- return normalized.length <= 96 ? normalized : `${normalized.slice(0, 93)}...`
186
- }
187
-
188
- export function buildDeleteCommand(targetPath: string): string {
189
- const escaped = targetPath.replace(/"/g, '""')
190
- if (process.platform === 'win32') {
191
- return `del /f /q "${escaped}"`
192
- }
193
- return `rm -f -- "${targetPath.replace(/"/g, '\\"')}"`
194
- }
@@ -1,146 +0,0 @@
1
- import { localProviderBaseUrlFor, type EthagentConfig } from '../storage/config.js'
2
- import type { SessionMetadata, SessionMessage } from '../storage/sessions.js'
3
- import type { SessionMode } from '../runtime/sessionMode.js'
4
- import type { MessageRow } from './MessageList.js'
5
- import type { ModelPickerSelection } from '../models/ModelPicker.js'
6
- import { sessionMessagesToRows } from './chatScreenUtils.js'
7
- import { formatModelDisplayName } from '../models/modelDisplay.js'
8
- import { providerDisplayName } from '../models/modelPickerOptions.js'
9
-
10
- export type ModelSelectionResolution =
11
- | { kind: 'noop' }
12
- | {
13
- kind: 'switch'
14
- config: EthagentConfig
15
- notice: string
16
- tone: 'info' | 'dim'
17
- }
18
-
19
- export type ResumedSessionState = {
20
- cwd: string
21
- mode: SessionMode
22
- rows: MessageRow[]
23
- promptHistory: string[]
24
- statusStartedAt: number
25
- }
26
-
27
- const MAX_PROMPT_HISTORY = 500
28
-
29
- export function resolveModelSelection(
30
- selection: ModelPickerSelection,
31
- currentConfig: EthagentConfig,
32
- ): ModelSelectionResolution {
33
- if (selection.kind === 'llamacpp') {
34
- const baseUrl = localProviderBaseUrlFor(
35
- 'llamacpp',
36
- currentConfig.provider === 'llamacpp' ? currentConfig.baseUrl : undefined,
37
- )
38
- if (
39
- selection.model === currentConfig.model
40
- && currentConfig.provider === 'llamacpp'
41
- && currentConfig.baseUrl === baseUrl
42
- && currentConfig.localMmprojPath === selection.mmprojPath
43
- ) {
44
- return { kind: 'noop' }
45
- }
46
- return {
47
- kind: 'switch',
48
- config: {
49
- ...currentConfig,
50
- provider: 'llamacpp',
51
- model: selection.model,
52
- baseUrl,
53
- localMmprojPath: selection.mmprojPath,
54
- },
55
- notice: `llama.cpp ready. Now using ${formatModelDisplayName('llamacpp', selection.model, { maxLength: 64 })}${selection.mmprojPath ? ' · vision' : ''}.`,
56
- tone: 'info',
57
- }
58
- }
59
-
60
- const nextProvider = selection.provider
61
- const nextBaseUrl =
62
- nextProvider === 'openai' && currentConfig.provider === 'openai'
63
- ? currentConfig.baseUrl
64
- : undefined
65
- const nextConfig: EthagentConfig = {
66
- ...currentConfig,
67
- provider: nextProvider,
68
- model: selection.model,
69
- baseUrl: nextBaseUrl,
70
- localMmprojPath: undefined,
71
- }
72
-
73
- return {
74
- kind: 'switch',
75
- config: nextConfig,
76
- notice: `${selection.keyJustSet ? `${providerDisplayName(selection.provider)} key saved.` : `${providerDisplayName(selection.provider)} ready.`} Now using ${providerDisplayName(nextConfig.provider)} · ${formatModelDisplayName(nextConfig.provider, nextConfig.model, { maxLength: 64 })}.`,
77
- tone: 'dim',
78
- }
79
- }
80
-
81
- export function buildResumedSessionState(args: {
82
- messages: SessionMessage[]
83
- metadata: SessionMetadata | null
84
- fallbackCwd: string
85
- nextRowId: () => string
86
- }): ResumedSessionState {
87
- const cwd = args.metadata?.lastCwd ?? args.metadata?.workspaceRoot ?? args.fallbackCwd
88
- return {
89
- cwd,
90
- mode: args.metadata?.mode ?? 'chat',
91
- rows: [
92
- ...sessionMessagesToRows(args.messages, args.nextRowId),
93
- {
94
- role: 'note',
95
- id: args.nextRowId(),
96
- kind: 'dim',
97
- content: formatResumeNote(args.metadata),
98
- },
99
- ],
100
- promptHistory: promptHistoryFromSessionMessages(args.messages),
101
- statusStartedAt: Date.now(),
102
- }
103
- }
104
-
105
- function formatResumeNote(metadata: SessionMetadata | null): string {
106
- const id = metadata?.id?.slice(0, 8) ?? ''
107
- const source = metadata?.compactedFromSessionId ? ` summarized from ${metadata.compactedFromSessionId.slice(0, 8)}` : ''
108
- return `Resumed from session ${id}.${source}`.trim()
109
- }
110
-
111
- export function restoreConversationState(
112
- messages: SessionMessage[],
113
- turnId: string,
114
- nextRowId: () => string,
115
- ): {
116
- messages: SessionMessage[]
117
- rows: MessageRow[]
118
- promptHistory: string[]
119
- truncated: boolean
120
- } {
121
- const firstIndex = messages.findIndex(message => message.turnId === turnId)
122
- const nextMessages =
123
- firstIndex >= 0
124
- ? messages.slice(0, firstIndex)
125
- : messages.filter(message => message.turnId !== turnId)
126
-
127
- return {
128
- messages: nextMessages,
129
- rows: sessionMessagesToRows(nextMessages, nextRowId),
130
- promptHistory: promptHistoryFromSessionMessages(nextMessages),
131
- truncated: firstIndex >= 0,
132
- }
133
- }
134
-
135
- export function promptHistoryFromSessionMessages(messages: SessionMessage[]): string[] {
136
- const prompts: string[] = []
137
- for (const message of messages) {
138
- if (message.role !== 'user') continue
139
- if (message.synthetic) continue
140
- const prompt = message.content.trim()
141
- if (!prompt) continue
142
- if (prompts[prompts.length - 1] === prompt) continue
143
- prompts.push(prompt)
144
- }
145
- return prompts.slice(-MAX_PROMPT_HISTORY)
146
- }
@@ -1,50 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import type { Message } from '../providers/contracts.js'
4
-
5
- export async function buildFileMentionContextMessages(
6
- userText: string,
7
- cwd: string,
8
- ): Promise<Message[]> {
9
- const mentions = extractFileMentions(userText)
10
- if (mentions.length === 0) return []
11
-
12
- const lines: string[] = []
13
- for (const mention of mentions) {
14
- const resolved = path.resolve(cwd, mention)
15
- const rel = path.relative(cwd, resolved)
16
- if (rel.startsWith('..') || path.isAbsolute(rel)) {
17
- lines.push(
18
- `@${mention} -> outside current workspace; do not use unless the user changes directory or names an allowed path.`,
19
- )
20
- continue
21
- }
22
- try {
23
- const stats = await fs.stat(resolved)
24
- lines.push(`@${mention} -> ${mention} (${stats.isDirectory() ? 'directory' : 'file'})`)
25
- } catch {
26
- lines.push(`@${mention} -> unresolved`)
27
- }
28
- }
29
-
30
- return [
31
- {
32
- role: 'user',
33
- content: [
34
- 'Resolved file mentions for this request:',
35
- ...lines,
36
- 'Treat these mentions as authoritative filenames from the user request. Read referenced context files when needed, and edit only the file requested by the user or the target file you have inspected.',
37
- ].join('\n'),
38
- },
39
- ]
40
- }
41
-
42
- function extractFileMentions(text: string): string[] {
43
- const mentions = new Set<string>()
44
- for (const match of text.matchAll(/@([^\s]+)/g)) {
45
- const raw = match[1]?.replace(/[),.;:!?]+$/g, '')
46
- if (!raw || raw.length === 0) continue
47
- mentions.add(raw.replace(/\\/g, '/'))
48
- }
49
- return [...mentions]
50
- }