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,127 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import { PROVIDERS, getConfigDir } from './config.js'
4
- import { rmSecret } from './secrets.js'
5
-
6
- const PRESERVED_LOCAL_MODEL_ENTRIES = new Set([
7
- 'local-models.json',
8
- 'local-runner.json',
9
- 'models',
10
- 'runners',
11
- ])
12
-
13
- const SECRET_ACCOUNTS = [
14
- 'ethereum:default',
15
- 'pinata:jwt',
16
- ...PROVIDERS,
17
- ] as const
18
-
19
- export type FactoryResetPlan = {
20
- configDir: string
21
- deletePaths: string[]
22
- preservedPaths: string[]
23
- preservedDescriptions: string[]
24
- remoteDescriptions: string[]
25
- }
26
-
27
- export type FactoryResetResult = {
28
- deletedPaths: string[]
29
- preservedPaths: string[]
30
- clearedSecretAccounts: string[]
31
- }
32
-
33
- export async function createFactoryResetPlan(): Promise<FactoryResetPlan> {
34
- const configDir = path.resolve(getConfigDir())
35
- const entries = await readConfigEntries(configDir)
36
- const deletePaths: string[] = []
37
- const preservedPaths: string[] = []
38
-
39
- for (const entry of entries) {
40
- const target = path.join(configDir, entry)
41
- assertInsideConfigDir(configDir, target)
42
- if (PRESERVED_LOCAL_MODEL_ENTRIES.has(entry)) preservedPaths.push(target)
43
- else deletePaths.push(target)
44
- }
45
-
46
- return {
47
- configDir,
48
- deletePaths,
49
- preservedPaths,
50
- preservedDescriptions: [
51
- 'Local GGUF models and metadata',
52
- 'llama.cpp runner assets',
53
- 'External package-installed runtimes',
54
- ],
55
- remoteDescriptions: [
56
- 'ERC-8004 tokens and onchain records',
57
- 'IPFS snapshots and public metadata',
58
- ],
59
- }
60
- }
61
-
62
- export async function runFactoryReset(options: { clearSecrets?: boolean } = {}): Promise<FactoryResetResult> {
63
- const plan = await createFactoryResetPlan()
64
- const clearedSecretAccounts: string[] = []
65
- if (options.clearSecrets ?? true) {
66
- for (const account of SECRET_ACCOUNTS) {
67
- try {
68
- await rmSecret(account)
69
- clearedSecretAccounts.push(account)
70
- } catch {
71
- continue
72
- }
73
- }
74
- }
75
-
76
- const deletedPaths: string[] = []
77
- for (const target of plan.deletePaths) {
78
- assertInsideConfigDir(plan.configDir, target)
79
- await fs.rm(target, { recursive: true, force: true })
80
- deletedPaths.push(target)
81
- }
82
-
83
- return {
84
- deletedPaths,
85
- preservedPaths: plan.preservedPaths,
86
- clearedSecretAccounts,
87
- }
88
- }
89
-
90
- export function formatFactoryResetPlan(plan: FactoryResetPlan): string {
91
- return [
92
- 'Ethagent Reset',
93
- '',
94
- 'Deletes:',
95
- ...formatDeleteSummary(plan.deletePaths.length),
96
- '',
97
- 'Keeps:',
98
- ...plan.preservedDescriptions.map(item => ` - ${item}`),
99
- '',
100
- 'Not Touched:',
101
- ...plan.remoteDescriptions.map(item => ` - ${item}`),
102
- ].join('\n')
103
- }
104
-
105
- async function readConfigEntries(configDir: string): Promise<string[]> {
106
- try {
107
- return await fs.readdir(configDir)
108
- } catch (err: unknown) {
109
- if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []
110
- throw err
111
- }
112
- }
113
-
114
- function formatDeleteSummary(count: number): string[] {
115
- if (count === 0) return [' - No local ethagent data found']
116
- return [
117
- ' - Identity files, sessions, history, credentials',
118
- ` - ${count} local path${count === 1 ? '' : 's'} under ~/.ethagent`,
119
- ]
120
- }
121
-
122
- function assertInsideConfigDir(configDir: string, target: string): void {
123
- const relative = path.relative(path.resolve(configDir), path.resolve(target))
124
- if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
125
- throw new Error(`refusing to reset path outside ethagent config: ${target}`)
126
- }
127
- }
@@ -1,58 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import { getConfigDir } from './config.js'
4
-
5
- const MAX_ENTRIES = 500
6
-
7
- export function getHistoryPath(): string {
8
- return path.join(getConfigDir(), 'history.jsonl')
9
- }
10
-
11
- type Entry = { text: string; ts: number }
12
-
13
- export async function appendHistory(text: string): Promise<void> {
14
- const clean = text.trim()
15
- if (!clean) return
16
- try {
17
- await fs.mkdir(getConfigDir(), { recursive: true })
18
- } catch {
19
- return
20
- }
21
- const line = JSON.stringify({ text: clean, ts: Date.now() } satisfies Entry) + '\n'
22
- try {
23
- await fs.appendFile(getHistoryPath(), line, { mode: 0o600 })
24
- } catch {
25
- return
26
- }
27
- }
28
-
29
- export async function readHistory(): Promise<string[]> {
30
- let raw: string
31
- try {
32
- raw = await fs.readFile(getHistoryPath(), 'utf8')
33
- } catch (err: unknown) {
34
- if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []
35
- throw err
36
- }
37
- const entries: Entry[] = []
38
- for (const line of raw.split('\n')) {
39
- const trimmed = line.trim()
40
- if (!trimmed) continue
41
- try {
42
- entries.push(JSON.parse(trimmed) as Entry)
43
- } catch {
44
- continue
45
- }
46
- }
47
- const seen = new Set<string>()
48
- const out: string[] = []
49
- for (let i = entries.length - 1; i >= 0; i--) {
50
- const entry = entries[i]
51
- if (!entry) continue
52
- if (seen.has(entry.text)) continue
53
- seen.add(entry.text)
54
- out.unshift(entry.text)
55
- if (out.length >= MAX_ENTRIES) break
56
- }
57
- return out
58
- }
@@ -1,76 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import { z } from 'zod'
4
- import { ensureConfigDir, getConfigDir } from './config.js'
5
- import { SessionPermissionRuleSchema, type SessionPermissionRule } from '../tools/contracts.js'
6
- import { atomicWriteText } from './atomicWrite.js'
7
-
8
- const StoredPermissionRuleSchema = z.object({
9
- workspaceRoot: z.string().min(1),
10
- rule: SessionPermissionRuleSchema,
11
- })
12
-
13
- type StoredPermissionRule = z.infer<typeof StoredPermissionRuleSchema>
14
-
15
- function getPermissionsPath(): string {
16
- return path.join(getConfigDir(), 'permissions.json')
17
- }
18
-
19
- export async function loadPermissionRules(workspaceRoot: string): Promise<SessionPermissionRule[]> {
20
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
21
- const allRules = await loadAllPermissionRules()
22
- return allRules
23
- .filter(entry => path.resolve(entry.workspaceRoot) === normalizedWorkspaceRoot)
24
- .map(entry => entry.rule)
25
- }
26
-
27
- export async function deletePermissionRule(workspaceRoot: string, rule: SessionPermissionRule): Promise<void> {
28
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
29
- const allRules = await loadAllPermissionRules()
30
- const next = allRules.filter(entry =>
31
- !(path.resolve(entry.workspaceRoot) === normalizedWorkspaceRoot && JSON.stringify(entry.rule) === JSON.stringify(rule)),
32
- )
33
- await writeAllPermissionRules(next)
34
- }
35
-
36
- export async function clearPermissionRules(workspaceRoot: string): Promise<void> {
37
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
38
- const allRules = await loadAllPermissionRules()
39
- const next = allRules.filter(entry => path.resolve(entry.workspaceRoot) !== normalizedWorkspaceRoot)
40
- await writeAllPermissionRules(next)
41
- }
42
-
43
- export async function savePermissionRule(workspaceRoot: string, rule: SessionPermissionRule): Promise<void> {
44
- const allRules = await loadAllPermissionRules()
45
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
46
- const nextEntry: StoredPermissionRule = { workspaceRoot: normalizedWorkspaceRoot, rule }
47
- const deduped = [...allRules.filter(entry => !sameStoredRule(entry, nextEntry)), nextEntry]
48
- await writeAllPermissionRules(deduped)
49
- }
50
-
51
- async function loadAllPermissionRules(): Promise<StoredPermissionRule[]> {
52
- let raw: string
53
- try {
54
- raw = await fs.readFile(getPermissionsPath(), 'utf8')
55
- } catch (error: unknown) {
56
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') return []
57
- throw error
58
- }
59
-
60
- try {
61
- const parsed = JSON.parse(raw)
62
- return z.array(StoredPermissionRuleSchema).parse(parsed)
63
- } catch {
64
- return []
65
- }
66
- }
67
-
68
- async function writeAllPermissionRules(rules: StoredPermissionRule[]): Promise<void> {
69
- await ensureConfigDir()
70
- const file = getPermissionsPath()
71
- await atomicWriteText(file, JSON.stringify(rules, null, 2) + '\n')
72
- }
73
-
74
- function sameStoredRule(left: StoredPermissionRule, right: StoredPermissionRule): boolean {
75
- return left.workspaceRoot === right.workspaceRoot && JSON.stringify(left.rule) === JSON.stringify(right.rule)
76
- }
@@ -1,266 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import { z } from 'zod'
4
- import { ensureConfigDir, getConfigDir } from './config.js'
5
- import { atomicWriteText } from './atomicWrite.js'
6
-
7
- const RewindSnapshotSchema = z.object({
8
- id: z.string().optional(),
9
- workspaceRoot: z.string().min(1),
10
- filePath: z.string().min(1),
11
- relativePath: z.string().optional(),
12
- existedBefore: z.boolean(),
13
- previousContent: z.string(),
14
- changeSummary: z.string().optional(),
15
- createdAt: z.string(),
16
- sessionId: z.string().optional(),
17
- turnId: z.string().optional(),
18
- messageRole: z.literal('user').optional(),
19
- promptSnippet: z.string().optional(),
20
- checkpointLabel: z.string().optional(),
21
- })
22
-
23
- type RewindSnapshot = z.infer<typeof RewindSnapshotSchema>
24
- export type RewindEntry = {
25
- id: string
26
- workspaceRoot: string
27
- filePath: string
28
- relativePath: string
29
- existedBefore: boolean
30
- previousContent: string
31
- changeSummary: string
32
- createdAt: string
33
- sessionId?: string
34
- turnId?: string
35
- messageRole?: 'user'
36
- promptSnippet: string
37
- checkpointLabel: string
38
- }
39
-
40
- export type ListRewindEntriesOptions = {
41
- limit?: number
42
- offset?: number
43
- }
44
-
45
- function getRewindPath(): string {
46
- return path.join(getConfigDir(), 'rewind.jsonl')
47
- }
48
-
49
- export async function recordRewindSnapshot(snapshot: RewindSnapshot): Promise<void> {
50
- await ensureConfigDir()
51
- const normalized = normalizeSnapshot(snapshot)
52
- if (isIdentityMarkdownSnapshot(normalized)) return
53
- await fs.appendFile(getRewindPath(), `${JSON.stringify(normalized)}\n`, { encoding: 'utf8', mode: 0o600 })
54
- }
55
-
56
- export async function rewindWorkspaceEdits(
57
- workspaceRoot: string,
58
- steps = 1,
59
- ): Promise<{ reverted: number; files: string[] }> {
60
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
61
- const snapshots = await loadSnapshots()
62
- const candidates = snapshots
63
- .map((snapshot, index) => ({ snapshot, index }))
64
- .filter(entry =>
65
- path.resolve(entry.snapshot.workspaceRoot) === normalizedWorkspaceRoot &&
66
- !isIdentityMarkdownSnapshot(entry.snapshot),
67
- )
68
-
69
- if (candidates.length === 0) return { reverted: 0, files: [] }
70
-
71
- const selected = candidates.slice(Math.max(0, candidates.length - steps))
72
- const revertedFiles: string[] = []
73
-
74
- for (let index = selected.length - 1; index >= 0; index -= 1) {
75
- const snapshot = selected[index]!.snapshot
76
- if (snapshot.existedBefore) {
77
- await fs.mkdir(path.dirname(snapshot.filePath), { recursive: true })
78
- await fs.writeFile(snapshot.filePath, snapshot.previousContent, 'utf8')
79
- } else {
80
- try {
81
- await fs.unlink(snapshot.filePath)
82
- } catch (error: unknown) {
83
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
84
- }
85
- }
86
- revertedFiles.push(snapshot.filePath)
87
- }
88
-
89
- const selectedIndexes = new Set(selected.map(entry => entry.index))
90
- const remaining = snapshots.filter((_snapshot, index) => !selectedIndexes.has(index))
91
- await writeSnapshots(remaining)
92
-
93
- return { reverted: selected.length, files: revertedFiles }
94
- }
95
-
96
- async function loadSnapshots(): Promise<RewindSnapshot[]> {
97
- let raw: string
98
- try {
99
- raw = await fs.readFile(getRewindPath(), 'utf8')
100
- } catch (error: unknown) {
101
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') return []
102
- throw error
103
- }
104
-
105
- const out: RewindSnapshot[] = []
106
- for (const line of raw.split('\n')) {
107
- const trimmed = line.trim()
108
- if (!trimmed) continue
109
- try {
110
- out.push(normalizeSnapshot(RewindSnapshotSchema.parse(JSON.parse(trimmed))))
111
- } catch {
112
- continue
113
- }
114
- }
115
- return out
116
- }
117
-
118
- export async function listRewindEntries(
119
- workspaceRoot: string,
120
- options: ListRewindEntriesOptions = {},
121
- ): Promise<RewindEntry[]> {
122
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
123
- const limit = options.limit ?? 30
124
- const offset = options.offset ?? 0
125
- const snapshots = await loadSnapshots()
126
- return snapshots
127
- .filter(snapshot => !isIdentityMarkdownSnapshot(snapshot))
128
- .filter(snapshot => isSnapshotWithinScope(snapshot, normalizedWorkspaceRoot))
129
- .map(snapshot => toEntry(snapshot))
130
- .reverse()
131
- .slice(offset, offset + limit)
132
- }
133
-
134
- export async function groupRewindEntriesByTurn(
135
- workspaceRoot: string,
136
- sessionId: string,
137
- ): Promise<Map<string, RewindEntry[]>> {
138
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
139
- const snapshots = await loadSnapshots()
140
- const grouped = new Map<string, RewindEntry[]>()
141
- for (const snapshot of snapshots) {
142
- if (isIdentityMarkdownSnapshot(snapshot)) continue
143
- if (!isSnapshotWithinScope(snapshot, normalizedWorkspaceRoot)) continue
144
- if (snapshot.sessionId !== sessionId) continue
145
- if (!snapshot.turnId) continue
146
- const entry = toEntry(snapshot)
147
- const bucket = grouped.get(snapshot.turnId)
148
- if (bucket) bucket.push(entry)
149
- else grouped.set(snapshot.turnId, [entry])
150
- }
151
- return grouped
152
- }
153
-
154
- export async function rewindWorkspaceEditsByEntryIds(
155
- workspaceRoot: string,
156
- entryIds: string[],
157
- ): Promise<{ reverted: number; files: string[] }> {
158
- const normalizedWorkspaceRoot = path.resolve(workspaceRoot)
159
- const selectedIds = new Set(entryIds)
160
- const snapshots = await loadSnapshots()
161
- const selected = snapshots
162
- .map((snapshot, index) => ({ snapshot, index }))
163
- .filter(entry =>
164
- path.resolve(entry.snapshot.workspaceRoot) === normalizedWorkspaceRoot &&
165
- !isIdentityMarkdownSnapshot(entry.snapshot) &&
166
- selectedIds.has(entry.snapshot.id!),
167
- )
168
-
169
- if (selected.length === 0) return { reverted: 0, files: [] }
170
-
171
- const revertedFiles: string[] = []
172
- for (let index = selected.length - 1; index >= 0; index -= 1) {
173
- const snapshot = selected[index]!.snapshot
174
- if (snapshot.existedBefore) {
175
- await fs.mkdir(path.dirname(snapshot.filePath), { recursive: true })
176
- await fs.writeFile(snapshot.filePath, snapshot.previousContent, 'utf8')
177
- } else {
178
- try {
179
- await fs.unlink(snapshot.filePath)
180
- } catch (error: unknown) {
181
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
182
- }
183
- }
184
- revertedFiles.push(snapshot.filePath)
185
- }
186
-
187
- const selectedIndexes = new Set(selected.map(entry => entry.index))
188
- const remaining = snapshots.filter((_snapshot, index) => !selectedIndexes.has(index))
189
- await writeSnapshots(remaining)
190
-
191
- return { reverted: selected.length, files: revertedFiles }
192
- }
193
-
194
- async function writeSnapshots(snapshots: RewindSnapshot[]): Promise<void> {
195
- await ensureConfigDir()
196
- const file = getRewindPath()
197
- const body = snapshots.map(snapshot => JSON.stringify(snapshot)).join('\n')
198
- await atomicWriteText(file, body ? `${body}\n` : '')
199
- }
200
-
201
- function normalizeSnapshot(snapshot: RewindSnapshot): RewindSnapshot {
202
- const workspaceRoot = path.resolve(snapshot.workspaceRoot)
203
- const filePath = path.resolve(snapshot.filePath)
204
- return {
205
- ...snapshot,
206
- id: snapshot.id ?? stableSnapshotId(workspaceRoot, filePath, snapshot.createdAt),
207
- workspaceRoot,
208
- filePath,
209
- relativePath: snapshot.relativePath ?? (path.relative(workspaceRoot, filePath) || path.basename(filePath)),
210
- changeSummary: snapshot.changeSummary ?? (snapshot.existedBefore ? 'restore previous file contents' : 'remove created file'),
211
- promptSnippet: normalizeSnippet(snapshot.promptSnippet),
212
- checkpointLabel: normalizeSnippet(snapshot.checkpointLabel) || normalizeSnippet(snapshot.promptSnippet),
213
- }
214
- }
215
-
216
- function toEntry(snapshot: RewindSnapshot): RewindEntry {
217
- return {
218
- id: snapshot.id!,
219
- workspaceRoot: snapshot.workspaceRoot,
220
- filePath: snapshot.filePath,
221
- relativePath: snapshot.relativePath!,
222
- existedBefore: snapshot.existedBefore,
223
- previousContent: snapshot.previousContent,
224
- changeSummary: snapshot.changeSummary!,
225
- createdAt: snapshot.createdAt,
226
- sessionId: snapshot.sessionId,
227
- turnId: snapshot.turnId,
228
- messageRole: snapshot.messageRole,
229
- promptSnippet: snapshot.promptSnippet ?? '',
230
- checkpointLabel: snapshot.checkpointLabel ?? snapshot.promptSnippet ?? 'Untitled checkpoint',
231
- }
232
- }
233
-
234
- function stableSnapshotId(workspaceRoot: string, filePath: string, createdAt: string): string {
235
- const rel = path.relative(workspaceRoot, filePath) || path.basename(filePath)
236
- return `${createdAt}:${rel}`.replaceAll('\\', '/')
237
- }
238
-
239
- function isSnapshotWithinScope(snapshot: RewindSnapshot, scopeRoot: string): boolean {
240
- if (path.resolve(snapshot.workspaceRoot) === scopeRoot) return true
241
- const relative = path.relative(scopeRoot, path.resolve(snapshot.filePath))
242
- return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative)
243
- }
244
-
245
- function isIdentityMarkdownSnapshot(snapshot: RewindSnapshot): boolean {
246
- const relativePath = (snapshot.relativePath ?? '').replaceAll('\\', '/').toLowerCase()
247
- const basename = path.basename(snapshot.filePath).toLowerCase()
248
- if (relativePath.startsWith('identity-vault/') && IDENTITY_MARKDOWN_FILES.has(basename)) return true
249
-
250
- const continuityRoot = path.resolve(getConfigDir(), 'continuity')
251
- const relativeToContinuity = path.relative(continuityRoot, path.resolve(snapshot.filePath))
252
- return (
253
- relativeToContinuity !== '' &&
254
- !relativeToContinuity.startsWith('..') &&
255
- !path.isAbsolute(relativeToContinuity) &&
256
- IDENTITY_MARKDOWN_FILES.has(basename)
257
- )
258
- }
259
-
260
- const IDENTITY_MARKDOWN_FILES = new Set(['soul.md', 'memory.md', 'agent-card.json'])
261
-
262
- function normalizeSnippet(input?: string): string {
263
- const normalized = (input ?? '').replace(/\s+/g, ' ').trim()
264
- if (!normalized) return ''
265
- return normalized.length <= 120 ? normalized : `${normalized.slice(0, 117)}...`
266
- }
@@ -1,49 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
- import { getConfigDir } from './config.js'
4
- import type { SessionMessage } from './sessions.js'
5
-
6
- export function getExportsDir(): string {
7
- return path.join(getConfigDir(), 'exports')
8
- }
9
-
10
- export async function exportSessionMarkdown(
11
- id: string,
12
- messages: SessionMessage[],
13
- meta: { model: string; provider: string },
14
- ): Promise<string> {
15
- await fs.mkdir(getExportsDir(), { recursive: true })
16
- const file = path.join(getExportsDir(), `${id}.md`)
17
-
18
- const userTurns = messages.filter(m => m.role === 'user').length
19
- const lines: string[] = []
20
- lines.push('---')
21
- lines.push(`session: ${id}`)
22
- lines.push(`provider: ${meta.provider}`)
23
- lines.push(`model: ${meta.model}`)
24
- lines.push(`turns: ${userTurns}`)
25
- lines.push(`exportedAt: ${new Date().toISOString()}`)
26
- lines.push('---')
27
- lines.push('')
28
- for (const m of messages) {
29
- if (m.role === 'system') continue
30
- const header =
31
- m.role === 'user'
32
- ? '## user'
33
- : m.role === 'assistant'
34
- ? '## assistant'
35
- : m.role === 'tool_use'
36
- ? `## tool use · ${m.name}`
37
- : `## tool result · ${m.name}`
38
- lines.push(`${header} <sub>${m.createdAt}</sub>`)
39
- lines.push('')
40
- if (m.role === 'tool_use') {
41
- lines.push(JSON.stringify(m.input, null, 2))
42
- } else {
43
- lines.push(m.content)
44
- }
45
- lines.push('')
46
- }
47
- await fs.writeFile(file, lines.join('\n'), { mode: 0o600 })
48
- return file
49
- }