ethagent 3.3.3 → 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 -259
  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,70 +0,0 @@
1
- import {
2
- OPENAI_OAUTH_CLIENT_ID,
3
- OPENAI_OAUTH_TOKEN_URL,
4
- asTrimmedString,
5
- parseChatgptAccountId,
6
- } from './shared.js'
7
- import type { OpenAIOAuthCredentials } from './credentials.js'
8
-
9
- export type RefreshedTokens = {
10
- accessToken: string
11
- refreshToken: string
12
- idToken?: string
13
- accountId?: string
14
- expiresIn: number
15
- }
16
-
17
- const REFRESH_LEEWAY_MS = 60_000
18
-
19
- export function shouldRefresh(creds: OpenAIOAuthCredentials, now: number = Date.now()): boolean {
20
- return now >= creds.expiresAt - REFRESH_LEEWAY_MS
21
- }
22
-
23
- export async function refreshOpenAIAccessToken(refreshToken: string): Promise<RefreshedTokens> {
24
- const body = new URLSearchParams({
25
- client_id: OPENAI_OAUTH_CLIENT_ID,
26
- grant_type: 'refresh_token',
27
- refresh_token: refreshToken,
28
- })
29
-
30
- const response = await fetch(OPENAI_OAUTH_TOKEN_URL, {
31
- method: 'POST',
32
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
33
- body,
34
- signal: AbortSignal.timeout(15_000),
35
- })
36
-
37
- if (!response.ok) {
38
- const errorText = await response.text().catch(() => '')
39
- throw new Error(
40
- errorText.trim()
41
- ? `OpenAI token refresh failed (${response.status}): ${errorText.trim()}`
42
- : `OpenAI token refresh failed with status ${response.status}.`,
43
- )
44
- }
45
-
46
- const payload = (await response.json()) as {
47
- access_token?: string
48
- refresh_token?: string
49
- id_token?: string
50
- expires_in?: number
51
- }
52
- const accessToken = asTrimmedString(payload.access_token)
53
- if (!accessToken) {
54
- throw new Error('OpenAI token refresh succeeded without a new access token.')
55
- }
56
- const nextRefresh = asTrimmedString(payload.refresh_token) ?? refreshToken
57
- const idToken = asTrimmedString(payload.id_token)
58
- const expiresIn = typeof payload.expires_in === 'number' && payload.expires_in > 0
59
- ? payload.expires_in
60
- : 3600
61
- const accountId = parseChatgptAccountId(idToken) ?? parseChatgptAccountId(accessToken)
62
-
63
- return {
64
- accessToken,
65
- refreshToken: nextRefresh,
66
- idToken,
67
- accountId,
68
- expiresIn,
69
- }
70
- }
@@ -1,115 +0,0 @@
1
- export const OPENAI_OAUTH_ISSUER = 'https://auth.openai.com'
2
- export const OPENAI_OAUTH_TOKEN_URL = `${OPENAI_OAUTH_ISSUER}/oauth/token`
3
- export const OPENAI_OAUTH_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann'
4
- export const OPENAI_OAUTH_CALLBACK_PORT = 1455
5
- export const OPENAI_OAUTH_SCOPE =
6
- 'openid profile email offline_access api.connectors.read api.connectors.invoke'
7
- export const OPENAI_OAUTH_ORIGINATOR = 'codex_cli_rs'
8
- export const OPENAI_API_KEY_TOKEN_NAME = 'openai-api-key'
9
- export const OPENAI_ID_TOKEN_SUBJECT_TYPE =
10
- 'urn:ietf:params:oauth:token-type:id_token'
11
- export const OPENAI_TOKEN_EXCHANGE_GRANT =
12
- 'urn:ietf:params:oauth:grant-type:token-exchange'
13
-
14
- export function asTrimmedString(value: unknown): string | undefined {
15
- if (typeof value !== 'string') return undefined
16
- const trimmed = value.trim()
17
- return trimmed ? trimmed : undefined
18
- }
19
-
20
- export function decodeJwtPayload(
21
- token: string,
22
- ): Record<string, unknown> | undefined {
23
- const parts = token.split('.')
24
- if (parts.length < 2) return undefined
25
- const segment = parts[1]
26
- if (!segment) return undefined
27
-
28
- try {
29
- const normalized = segment.replace(/-/g, '+').replace(/_/g, '/')
30
- const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4)
31
- const json = Buffer.from(padded, 'base64').toString('utf8')
32
- const parsed = JSON.parse(json) as unknown
33
- return parsed && typeof parsed === 'object'
34
- ? (parsed as Record<string, unknown>)
35
- : undefined
36
- } catch {
37
- return undefined
38
- }
39
- }
40
-
41
- export function parseChatgptAccountId(
42
- token: string | undefined,
43
- ): string | undefined {
44
- if (!token) return undefined
45
-
46
- const payload = decodeJwtPayload(token)
47
- const nestedAuthRaw = payload?.['https://api.openai.com/auth']
48
- const nestedAuth =
49
- nestedAuthRaw && typeof nestedAuthRaw === 'object'
50
- ? (nestedAuthRaw as Record<string, unknown>)
51
- : undefined
52
-
53
- return (
54
- asTrimmedString(
55
- nestedAuth?.chatgpt_account_id ??
56
- payload?.['https://api.openai.com/auth.chatgpt_account_id'] ??
57
- payload?.chatgpt_account_id,
58
- ) ?? undefined
59
- )
60
- }
61
-
62
- export function escapeHtml(value: string): string {
63
- return value.replace(/[&<>"']/g, char => {
64
- switch (char) {
65
- case '&':
66
- return '&amp;'
67
- case '<':
68
- return '&lt;'
69
- case '>':
70
- return '&gt;'
71
- case '"':
72
- return '&quot;'
73
- case '\'':
74
- return '&#39;'
75
- default:
76
- return char
77
- }
78
- })
79
- }
80
-
81
- export async function exchangeIdTokenForApiKey(idToken: string): Promise<string> {
82
- const body = new URLSearchParams({
83
- grant_type: OPENAI_TOKEN_EXCHANGE_GRANT,
84
- client_id: OPENAI_OAUTH_CLIENT_ID,
85
- requested_token: OPENAI_API_KEY_TOKEN_NAME,
86
- subject_token: idToken,
87
- subject_token_type: OPENAI_ID_TOKEN_SUBJECT_TYPE,
88
- })
89
-
90
- const response = await fetch(OPENAI_OAUTH_TOKEN_URL, {
91
- method: 'POST',
92
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
93
- body,
94
- signal: AbortSignal.timeout(15_000),
95
- })
96
-
97
- if (!response.ok) {
98
- const bodyText = await response.text().catch(() => '')
99
- throw new Error(
100
- bodyText.trim()
101
- ? `OpenAI API key exchange failed (${response.status}): ${bodyText.trim()}`
102
- : `OpenAI API key exchange failed with status ${response.status}.`,
103
- )
104
- }
105
-
106
- const payload = (await response.json()) as { access_token?: string }
107
- const apiKey = asTrimmedString(payload.access_token)
108
- if (!apiKey) {
109
- throw new Error(
110
- 'OpenAI API key exchange completed, but no key was returned.',
111
- )
112
- }
113
-
114
- return apiKey
115
- }
@@ -1,296 +0,0 @@
1
- import React from 'react'
2
- import type { EthagentConfig } from '../storage/config.js'
3
- import type { PermissionDecision, PermissionRequest, SessionPermissionRule } from '../tools/contracts.js'
4
- import { type ModelPickerSelection, ModelPicker } from '../models/ModelPicker.js'
5
- import type { ModelPickerContextFit } from '../models/modelPickerOptions.js'
6
- import { ResumeView } from './views/ResumeView.js'
7
- import { RewindView } from './views/RewindView.js'
8
- import { PermissionsView } from './views/PermissionsView.js'
9
- import { CopyPicker } from './views/CopyPicker.js'
10
- import { PermissionPrompt } from './views/PermissionPrompt.js'
11
- import { PlanApprovalView, type PlanApprovalAction } from './views/PlanApprovalView.js'
12
- import { ChatInput } from './input/ChatInput.js'
13
- import { IdentityHub, type IdentityHubInitialAction, type IdentityHubResult } from '../identity/hub/IdentityHub.js'
14
- import type { CopyResult } from '../utils/clipboard.js'
15
- import { getSlashSuggestions } from './commands.js'
16
- import { modelSupportsImages } from '../utils/images.js'
17
- import { Box, Text } from 'ink'
18
- import { theme } from '../ui/theme.js'
19
- import { Spinner } from '../ui/Spinner.js'
20
- import { ContextLimitView, type ContextLimitAction } from './views/ContextLimitView.js'
21
- import type { ContextUsage } from '../runtime/compaction.js'
22
- import {
23
- ContinuityEditReviewView,
24
- type ContinuityEditReviewAction,
25
- type ContinuityEditReviewState,
26
- } from './views/ContinuityEditReviewView.js'
27
-
28
- export type Overlay = 'none' | 'modelPicker' | 'resume' | 'rewind' | 'copyPicker' | 'permission' | 'permissions' | 'planApproval' | 'identity' | 'contextLimit' | 'continuityEditReview'
29
- export type CopyPickerState = { turnText: string; turnLabel: string } | null
30
- export type IdentityOverlayState = {
31
- initialAction: IdentityHubInitialAction | undefined
32
- existing: { address: string } | null
33
- }
34
- export type ContextLimitState = {
35
- usage: ContextUsage
36
- prompt: string
37
- } | null
38
-
39
- export type BottomPaneActivity = {
40
- label: string
41
- hint?: string
42
- } | null
43
-
44
- type ChatBottomPaneProps = {
45
- overlay: Overlay
46
- config: EthagentConfig
47
- sessionId: string
48
- cwd: string
49
- currentSessionId: string
50
- copyPickerState: CopyPickerState
51
- contextLimitState: ContextLimitState
52
- continuityEditReview: ContinuityEditReviewState | null
53
- modelPickerContextFit: ModelPickerContextFit | null
54
- permissionRequest: PermissionRequest | null
55
- history: string[]
56
- streaming: boolean
57
- streamingStartedAt: number | null
58
- activity: BottomPaneActivity
59
- placeholderHints: string[]
60
- queuedInputs: string[]
61
- slashSuggestions: ReturnType<typeof getSlashSuggestions>
62
- planApprovalContextLabel: string
63
- footerRight: React.ReactNode
64
- handleModelPick: (sel: ModelPickerSelection) => void | Promise<void>
65
- handleModelPickerCancel: () => void
66
- handleResumePick: (id: string) => void | Promise<void>
67
- handleResumeClearAll: () => void | Promise<void>
68
- identityOverlay: IdentityOverlayState | null
69
- handleIdentityResult: (result: IdentityHubResult) => void
70
- handleRestoreConversation: (turnId: string, promptText?: string) => void
71
- pendingInputDraft: string | null
72
- onInputDraftConsumed: () => void
73
- handleSummarizeFromTurn: (turnId: string) => void | Promise<unknown>
74
- handleCopyDone: (result: CopyResult, label: string) => void
75
- handleCopyCancel: () => void
76
- resolvePermission: (decision: PermissionDecision) => void
77
- handlePlanApproval: (action: PlanApprovalAction) => void | Promise<void>
78
- handlePlanApprovalCancel: () => void
79
- handleContextLimitAction: (action: ContextLimitAction) => void | Promise<void>
80
- handleContextLimitCancel: () => void
81
- handleContinuityEditReviewAction: (action: ContinuityEditReviewAction) => void | Promise<void>
82
- handleContinuityEditReviewCancel: () => void
83
- onPermissionRulesChanged: (rules: SessionPermissionRule[]) => void
84
- onConfigChange: (config: EthagentConfig) => void
85
- handleSubmit: (value: string) => void | Promise<void>
86
- setOverlay: React.Dispatch<React.SetStateAction<Overlay>>
87
- pushNote: (text: string, kind?: 'info' | 'error' | 'dim') => void
88
- }
89
-
90
- export function ChatBottomPane({
91
- overlay,
92
- config,
93
- sessionId,
94
- cwd,
95
- currentSessionId,
96
- copyPickerState,
97
- contextLimitState,
98
- continuityEditReview,
99
- modelPickerContextFit,
100
- permissionRequest,
101
- history,
102
- streaming,
103
- streamingStartedAt,
104
- activity,
105
- placeholderHints,
106
- queuedInputs,
107
- slashSuggestions,
108
- planApprovalContextLabel,
109
- footerRight,
110
- handleModelPick,
111
- handleModelPickerCancel,
112
- handleResumePick,
113
- handleResumeClearAll,
114
- identityOverlay,
115
- handleIdentityResult,
116
- handleRestoreConversation,
117
- handleSummarizeFromTurn,
118
- pendingInputDraft,
119
- onInputDraftConsumed,
120
- handleCopyDone,
121
- handleCopyCancel,
122
- resolvePermission,
123
- handlePlanApproval,
124
- handlePlanApprovalCancel,
125
- handleContextLimitAction,
126
- handleContextLimitCancel,
127
- handleContinuityEditReviewAction,
128
- handleContinuityEditReviewCancel,
129
- onPermissionRulesChanged,
130
- onConfigChange,
131
- handleSubmit,
132
- setOverlay,
133
- pushNote,
134
- }: ChatBottomPaneProps): React.ReactNode {
135
- if (overlay === 'modelPicker') {
136
- return (
137
- <ModelPicker
138
- currentConfig={config}
139
- currentProvider={config.provider}
140
- currentModel={config.model}
141
- contextFit={modelPickerContextFit}
142
- onPick={handleModelPick}
143
- onCancel={handleModelPickerCancel}
144
- />
145
- )
146
- }
147
-
148
- if (overlay === 'resume') {
149
- return (
150
- <ResumeView
151
- currentSessionId={sessionId}
152
- onResume={handleResumePick}
153
- onClearAll={handleResumeClearAll}
154
- onCancel={() => setOverlay('none')}
155
- />
156
- )
157
- }
158
-
159
- if (overlay === 'rewind') {
160
- return (
161
- <RewindView
162
- cwd={cwd}
163
- currentSessionId={currentSessionId}
164
- onRestoreConversation={handleRestoreConversation}
165
- onSummarizeFromTurn={handleSummarizeFromTurn}
166
- onDone={(message, variant = 'info') => {
167
- setOverlay('none')
168
- pushNote(message, variant)
169
- }}
170
- onCancel={() => setOverlay('none')}
171
- />
172
- )
173
- }
174
-
175
- if (overlay === 'permissions') {
176
- return (
177
- <PermissionsView
178
- cwd={cwd}
179
- onRulesChanged={onPermissionRulesChanged}
180
- onNotice={(message, variant = 'info') => {
181
- pushNote(message, variant)
182
- }}
183
- onCancel={() => setOverlay('none')}
184
- />
185
- )
186
- }
187
-
188
- if (overlay === 'copyPicker' && copyPickerState) {
189
- return (
190
- <CopyPicker
191
- turnText={copyPickerState.turnText}
192
- turnLabel={copyPickerState.turnLabel}
193
- onDone={handleCopyDone}
194
- onCancel={handleCopyCancel}
195
- />
196
- )
197
- }
198
-
199
- if (overlay === 'permission' && permissionRequest) {
200
- return (
201
- <PermissionPrompt
202
- request={permissionRequest}
203
- onDecision={resolvePermission}
204
- onCancel={() => resolvePermission('deny')}
205
- />
206
- )
207
- }
208
-
209
- if (overlay === 'identity' && identityOverlay) {
210
- return (
211
- <IdentityHub
212
- mode="manage"
213
- config={config}
214
- initialAction={identityOverlay.initialAction}
215
- onComplete={handleIdentityResult}
216
- onConfigChange={onConfigChange}
217
- />
218
- )
219
- }
220
-
221
- if (overlay === 'planApproval') {
222
- return (
223
- <PlanApprovalView
224
- contextLabel={planApprovalContextLabel}
225
- onSelect={handlePlanApproval}
226
- onCancel={handlePlanApprovalCancel}
227
- />
228
- )
229
- }
230
-
231
- if (overlay === 'contextLimit' && contextLimitState) {
232
- return (
233
- <ContextLimitView
234
- usage={contextLimitState.usage}
235
- promptPreview={summarizePrompt(contextLimitState.prompt)}
236
- onSelect={handleContextLimitAction}
237
- onCancel={handleContextLimitCancel}
238
- />
239
- )
240
- }
241
-
242
- if (overlay === 'continuityEditReview' && continuityEditReview) {
243
- return (
244
- <ContinuityEditReviewView
245
- review={continuityEditReview}
246
- onSelect={handleContinuityEditReviewAction}
247
- onCancel={handleContinuityEditReviewCancel}
248
- />
249
- )
250
- }
251
-
252
- return (
253
- <Box flexDirection="column" width="100%">
254
- {activity ? (
255
- <Box marginLeft={2} marginBottom={1}>
256
- <Spinner active label={activity.label} hint={activity.hint} />
257
- </Box>
258
- ) : streaming ? (
259
- <Box marginLeft={2} marginBottom={1}>
260
- <Spinner active hint="esc to cancel" startedAt={streamingStartedAt ?? undefined} />
261
- </Box>
262
- ) : null}
263
- <ChatInput
264
- onSubmit={handleSubmit}
265
- history={history}
266
- placeholderHints={placeholderHints}
267
- queuedMessages={queuedInputs}
268
- slashSuggestions={slashSuggestions}
269
- footerRight={footerRight}
270
- cwd={cwd}
271
- seedText={pendingInputDraft}
272
- onSeedConsumed={onInputDraftConsumed}
273
- onImagePaste={() => {
274
- if (!modelSupportsImages(config.provider, config.model, { mmprojPath: config.localMmprojPath })) {
275
- const hint = config.provider === 'llamacpp'
276
- ? ' · run "Add Vision Encoder" in alt+p to enable image input on this model'
277
- : ' · switch via alt+p'
278
- pushNote(`current model "${config.model}" does not accept image input${hint}`, 'error')
279
- }
280
- }}
281
- />
282
- <Box marginLeft={2} marginTop={0} flexDirection="column">
283
- <Text>
284
- <Text color={theme.dim}>Workspace · </Text>
285
- <Text color={theme.textSubtle}>{cwd}</Text>
286
- </Text>
287
- </Box>
288
- </Box>
289
- )
290
- }
291
-
292
- function summarizePrompt(text: string): string {
293
- const normalized = text.replace(/\s+/g, ' ').trim()
294
- if (normalized.length <= 100) return normalized
295
- return `${normalized.slice(0, 97)}...`
296
- }