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,304 +0,0 @@
1
- import { getTool } from '../tools/registry.js'
2
- import {
3
- buildPermissionRule,
4
- matchPermissionRule,
5
- shouldPersistPermissionDecision,
6
- } from '../tools/permissionRules.js'
7
- import { ZodError } from 'zod'
8
- import type {
9
- PermissionDecision,
10
- PermissionMode,
11
- PermissionRequest,
12
- SessionPermissionRule,
13
- Tool,
14
- ToolExecutionContext,
15
- ToolResult,
16
- } from '../tools/contracts.js'
17
- import { setCwd as setRuntimeCwd } from './cwd.js'
18
- import type { EthagentConfig } from '../storage/config.js'
19
- import type { SessionMessage } from '../storage/sessions.js'
20
- import { toolResultContentForRow, toolResultDiffForRow } from '../chat/chatScreenUtils.js'
21
- import type { MessageRow } from '../chat/MessageList.js'
22
- import { modePolicy, toPermissionMode, type SessionMode } from './sessionMode.js'
23
-
24
- export type ToolExecutorOptions = {
25
- name: string
26
- input: Record<string, unknown>
27
- permissionMode: PermissionMode
28
- cwd: string
29
- config?: EthagentConfig
30
- abortSignal?: AbortSignal
31
- checkpoint?: ToolExecutionContext['checkpoint']
32
- dynamicTools?: Tool[]
33
- mcp?: ToolExecutionContext['mcp']
34
- getPermissionRules: () => SessionPermissionRule[]
35
- requestPermission: (request: PermissionRequest) => Promise<PermissionDecision>
36
- onDirectoryChange: (next: string) => void
37
- }
38
-
39
- export type ToolExecutionOutcome = {
40
- result: ToolResult
41
- sessionRule?: SessionPermissionRule
42
- persistRule?: boolean
43
- }
44
-
45
- export async function executeToolWithPermissions(
46
- options: ToolExecutorOptions,
47
- ): Promise<ToolExecutionOutcome> {
48
- const tool = getTool(options.name, { dynamicTools: options.dynamicTools })
49
- if (!tool) {
50
- return {
51
- result: {
52
- ok: false,
53
- summary: `Unknown tool ${options.name}`,
54
- content: `Tool '${options.name}' is not registered`,
55
- },
56
- }
57
- }
58
-
59
- let parsedInput: ReturnType<typeof tool.parse>
60
- try {
61
- parsedInput = tool.parse(options.input)
62
- } catch (err: unknown) {
63
- return {
64
- result: {
65
- ok: false,
66
- summary: `${options.name} rejected input`,
67
- content: formatToolParseError(err, options.name),
68
- },
69
- }
70
- }
71
-
72
- const context: ToolExecutionContext = {
73
- workspaceRoot: options.cwd,
74
- config: options.config,
75
- abortSignal: options.abortSignal,
76
- mcp: options.mcp,
77
- checkpoint: options.checkpoint,
78
- changeDirectory: next => {
79
- const updated = setRuntimeCwd(next, options.cwd)
80
- options.onDirectoryChange(updated)
81
- },
82
- }
83
-
84
- let request: PermissionRequest
85
- try {
86
- request = await tool.buildPermissionRequest(parsedInput, context)
87
- } catch (err: unknown) {
88
- return {
89
- result: {
90
- ok: false,
91
- summary: `${options.name} failed before execution`,
92
- content: (err as Error).message,
93
- },
94
- }
95
- }
96
-
97
- if (
98
- options.permissionMode === 'plan' &&
99
- request.kind !== 'read' &&
100
- request.kind !== 'private-continuity-read' &&
101
- request.kind !== 'private-skill-read' &&
102
- !(request.kind === 'mcp' && request.readOnly)
103
- ) {
104
- return {
105
- result: {
106
- ok: false,
107
- summary: `${options.name} blocked in plan mode`,
108
- content: 'plan mode allows inspection only. switch modes before changing files, directories, or running shell commands.',
109
- },
110
- }
111
- }
112
-
113
- const matchedRule = matchPermissionRule(options.getPermissionRules(), request)
114
- const decision: PermissionDecision =
115
- modePolicy(options.permissionMode).autoAllowToolKind(tool.kind)
116
- ? 'allow-once'
117
- : matchedRule
118
- ? 'allow-once'
119
- : await options.requestPermission(request)
120
-
121
- if (decision === 'deny') {
122
- return {
123
- result: {
124
- ok: false,
125
- summary: `${options.name} denied`,
126
- content: 'tool use denied by the user',
127
- },
128
- }
129
- }
130
-
131
- const rule = buildPermissionRule(decision, request)
132
- const persistRule = rule !== undefined && shouldPersistPermissionDecision(decision)
133
-
134
- try {
135
- const result = await tool.execute(parsedInput, context)
136
- return { result, sessionRule: rule, persistRule }
137
- } catch (err: unknown) {
138
- return {
139
- result: {
140
- ok: false,
141
- summary: `${options.name} failed`,
142
- content: (err as Error).message || 'tool execution failed',
143
- },
144
- sessionRule: rule,
145
- persistRule,
146
- }
147
- }
148
- }
149
-
150
- function formatToolParseError(err: unknown, toolName?: string): string {
151
- const withToolHint = (message: string): string => {
152
- if (toolName !== 'propose_private_continuity_edit') return message
153
- return [
154
- message,
155
- 'private continuity edit input requires `file` plus one complete edit mode.',
156
- 'The tool resolves the identity vault path; do not search workspace folders for SOUL.md or MEMORY.md.',
157
- 'For new memory/preferences, use {"file":"MEMORY.md","appendToSection":"Durable User Preferences","appendText":"- User preference or memory note."}',
158
- 'For persona or standing behavior, use {"file":"SOUL.md","appendToSection":"Persona","appendText":"- Persona or standing behavior note."}',
159
- 'Do not call propose_private_continuity_edit with empty input or file-only input.',
160
- ].filter(Boolean).join('\n')
161
- }
162
-
163
- if (err instanceof ZodError) {
164
- const missing: string[] = []
165
- const invalid: string[] = []
166
-
167
- for (const issue of err.issues) {
168
- const field = issue.path.join('.') || 'input'
169
- if (issue.code === 'invalid_type' && issue.received === 'undefined') {
170
- missing.push(field)
171
- } else {
172
- invalid.push(`${field}: ${issue.message}`)
173
- }
174
- }
175
-
176
- const parts: string[] = []
177
- if (missing.length > 0) parts.push(`missing required fields: ${missing.join(', ')}`)
178
- if (invalid.length > 0) parts.push(`invalid fields: ${invalid.join('; ')}`)
179
- return withToolHint(parts.join('\n') || 'tool input did not match the required schema')
180
- }
181
-
182
- return withToolHint((err as Error).message || 'tool input did not match the required schema')
183
- }
184
-
185
- export type PendingToolUse = {
186
- id: string
187
- name: string
188
- input: Record<string, unknown>
189
- }
190
-
191
- export type CompletedToolUse = {
192
- id: string
193
- name: string
194
- input: Record<string, unknown>
195
- result: ToolResult
196
- cwd: string
197
- }
198
-
199
- type ExecuteToolResult = {
200
- result: ToolResult
201
- sessionRule?: SessionPermissionRule
202
- persistRule?: boolean
203
- }
204
-
205
- export type ToolUseRunnerResult = {
206
- cancelled: boolean
207
- completedTools: CompletedToolUse[]
208
- }
209
-
210
- export async function runPendingToolUses(args: {
211
- pendingToolUses: PendingToolUse[]
212
- nextRowId: () => string
213
- nowIso: () => string
214
- mode: SessionMode
215
- getCwd: () => string
216
- getConfig: () => EthagentConfig
217
- turnId?: string
218
- controller: AbortController
219
- updateRows: (updater: (prev: MessageRow[]) => MessageRow[]) => void
220
- pushNote: (text: string, kind?: 'info' | 'error' | 'dim') => void
221
- persistTurnMessage: (message: SessionMessage) => Promise<void>
222
- executeTool: (
223
- name: string,
224
- input: Record<string, unknown>,
225
- mode: ReturnType<typeof toPermissionMode>,
226
- ) => Promise<ExecuteToolResult>
227
- applySessionRule: (rule?: SessionPermissionRule, persistRule?: boolean) => Promise<void>
228
- }): Promise<ToolUseRunnerResult> {
229
- const completedTools: CompletedToolUse[] = []
230
-
231
- for (const toolUse of args.pendingToolUses) {
232
- const rowId = args.nextRowId()
233
- args.updateRows(prev => [
234
- ...prev,
235
- {
236
- role: 'tool_call',
237
- id: rowId,
238
- name: toolUse.name,
239
- summary: toolUse.name,
240
- input: toolUse.input,
241
- },
242
- ])
243
- await args.persistTurnMessage({
244
- version: 2,
245
- role: 'tool_use',
246
- toolUseId: toolUse.id,
247
- name: toolUse.name,
248
- input: toolUse.input,
249
- createdAt: args.nowIso(),
250
- turnId: args.turnId,
251
- })
252
-
253
- const cwd = args.getCwd()
254
- const { result, sessionRule, persistRule } = await args.executeTool(
255
- toolUse.name,
256
- toolUse.input,
257
- toPermissionMode(args.mode),
258
- )
259
- completedTools.push({ ...toolUse, result, cwd })
260
-
261
- if (args.controller.signal.aborted) {
262
- return { cancelled: true, completedTools }
263
- }
264
-
265
- await args.applySessionRule(sessionRule, persistRule)
266
- await recordToolResult(args, toolUse, result, rowId)
267
- }
268
-
269
- return { cancelled: false, completedTools }
270
- }
271
-
272
- async function recordToolResult(
273
- args: Pick<
274
- Parameters<typeof runPendingToolUses>[0],
275
- 'nextRowId' | 'nowIso' | 'turnId' | 'updateRows' | 'persistTurnMessage'
276
- >,
277
- toolUse: PendingToolUse,
278
- result: ToolResult,
279
- rowId: string,
280
- ): Promise<void> {
281
- const isError = !result.ok
282
- const resultContent = toolResultContentForRow(toolUse.name, result.content, isError)
283
- const diff = toolResultDiffForRow(result.content, isError)
284
- args.updateRows(prev => prev.map(row =>
285
- row.role === 'tool_call' && row.id === rowId
286
- ? {
287
- ...row,
288
- result: diff
289
- ? { content: resultContent, summary: result.summary, isError, diff }
290
- : { content: resultContent, summary: result.summary, isError },
291
- }
292
- : row,
293
- ))
294
- await args.persistTurnMessage({
295
- version: 2,
296
- role: 'tool_result',
297
- toolUseId: toolUse.id,
298
- name: toolUse.name,
299
- content: result.content,
300
- isError,
301
- createdAt: args.nowIso(),
302
- turnId: args.turnId,
303
- })
304
- }
@@ -1,143 +0,0 @@
1
- import type { PendingToolUse } from './turn.js'
2
- import { unsupportedToolStateClaims, type ToolEvidence } from './toolClaimGuards.js'
3
- export { parseLocalModelTextToolUses as extractLocalTextToolUses } from './textToolParser.js'
4
-
5
- export type ToolIntent = {
6
- name: string
7
- input: Record<string, unknown>
8
- reason: string
9
- }
10
-
11
- export function detectDirectToolIntent(userText: string): ToolIntent | null {
12
- const uses = directToolUsesForUserText(userText)
13
- if (uses.length === 0) return null
14
- const first = uses[0]!
15
- const reason = intentReason(first.name, first.input)
16
- return { name: first.name, input: first.input, reason }
17
- }
18
-
19
- export function validateAssistantTextAgainstTurnEvidence(
20
- text: string,
21
- evidence: ToolEvidence[],
22
- ): 'ok' | 'needs-tool' {
23
- const unsupported = unsupportedToolStateClaims(text, evidence)
24
- return unsupported.length > 0 ? 'needs-tool' : 'ok'
25
- }
26
-
27
- function intentReason(name: string, input: Record<string, unknown>): string {
28
- switch (name) {
29
- case 'change_directory':
30
- return `user requested directory change to ${input.path ?? '.'}`
31
- case 'list_directory':
32
- return input.path ? `user requested listing of ${input.path}` : 'user requested directory listing'
33
- case 'read_file':
34
- return `user requested read of ${input.path ?? '<unknown>'}`
35
- default:
36
- return `user requested ${name}`
37
- }
38
- }
39
-
40
- export function directToolUsesForUserText(userText: string, iterationIndex = 0): PendingToolUse[] {
41
- const text = userText.trim()
42
- if (!text || text.startsWith('/')) return []
43
-
44
- const cdPath = parseChangeDirectoryIntent(text)
45
- if (cdPath) {
46
- return [{
47
- id: `direct-tool-${iterationIndex}-0`,
48
- name: 'change_directory',
49
- input: { path: cdPath },
50
- }]
51
- }
52
-
53
- const listPath = parseListDirectoryIntent(text)
54
- if (listPath !== null) {
55
- return [{
56
- id: `direct-tool-${iterationIndex}-0`,
57
- name: 'list_directory',
58
- input: listPath ? { path: listPath } : {},
59
- }]
60
- }
61
-
62
- const readPath = parseReadFileIntent(text)
63
- if (readPath) {
64
- return [{
65
- id: `direct-tool-${iterationIndex}-0`,
66
- name: 'read_file',
67
- input: { path: readPath },
68
- }]
69
- }
70
-
71
- return []
72
- }
73
-
74
- function parseChangeDirectoryIntent(text: string): string | null {
75
- const normalized = trimCommandText(text)
76
- const patterns = [
77
- /^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?(?:cd|chdir)\s+(?:to\s+|into\s+|in\s+)?(.+)$/i,
78
- /^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?go\s+(?:to|into|in)\s+(.+)$/i,
79
- /^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?change\s+(?:the\s+)?(?:current\s+)?(?:directory|folder)\s+(?:to|into)\s+(.+)$/i,
80
- ]
81
- return firstPathMatch(normalized, patterns)
82
- }
83
-
84
- function parseListDirectoryIntent(text: string): string | null {
85
- const normalized = trimCommandText(text)
86
- const patterns = [
87
- /^(?:please\s+)?(?:ls|dir)$/i,
88
- /^(?:please\s+)?(?:ls|dir)\s+(.+)$/i,
89
- /^(?:please\s+)?(?:list|show)\s+(?:the\s+)?(?:files|directories|folders|entries)(?:\s+(?:in|inside|of)\s+(.+))?$/i,
90
- ]
91
- const match = firstPathMatch(normalized, patterns)
92
- if (match) return match
93
- return patterns.some(pattern => pattern.test(normalized)) ? '' : null
94
- }
95
-
96
- function parseReadFileIntent(text: string): string | null {
97
- const normalized = trimCommandText(text)
98
- const path = firstPathMatch(normalized, [
99
- /^(?:please\s+)?(?:read|open|cat)\s+(.+)$/i,
100
- /^(?:please\s+)?show\s+(?:me\s+)?(?:the\s+)?(?:contents\s+of\s+)?(.+)$/i,
101
- ])
102
- if (!path) return null
103
- return looksLikeConcreteReadTarget(path) ? path : null
104
- }
105
-
106
- function firstPathMatch(text: string, patterns: RegExp[]): string | null {
107
- for (const pattern of patterns) {
108
- const match = text.match(pattern)
109
- if (!match) continue
110
- const raw = match[1]
111
- if (raw === undefined) return ''
112
- const cleaned = cleanPath(raw)
113
- if (cleaned) return cleaned
114
- }
115
- return null
116
- }
117
-
118
- function trimCommandText(text: string): string {
119
- return text
120
- .trim()
121
- .replace(/[.!?]+$/g, '')
122
- .replace(/\s+/g, ' ')
123
- .trim()
124
- }
125
-
126
- function cleanPath(value: string): string {
127
- return value
128
- .trim()
129
- .replace(/^["'`]+|["'`]+$/g, '')
130
- .replace(/\s+(?:please|now)$/i, '')
131
- .trim()
132
- }
133
-
134
- function looksLikeConcreteReadTarget(path: string): boolean {
135
- return path === '.'
136
- || path.startsWith('~')
137
- || path.startsWith('./')
138
- || path.startsWith('../')
139
- || /^[A-Za-z]:[\\/]/.test(path)
140
- || path.includes('/')
141
- || path.includes('\\')
142
- || /\.[A-Za-z0-9]{1,12}$/.test(path)
143
- }