clawdex-mobile 1.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 (526) hide show
  1. package/.github/workflows/ci.yml +77 -0
  2. package/.github/workflows/npm-release.yml +67 -0
  3. package/AGENTS.md +120 -0
  4. package/LICENSE +21 -0
  5. package/README.md +648 -0
  6. package/STATUS.md +115 -0
  7. package/apps/mobile/.env.example +7 -0
  8. package/apps/mobile/App.tsx +589 -0
  9. package/apps/mobile/app.json +33 -0
  10. package/apps/mobile/assets/brand/adaptive-icon.png +0 -0
  11. package/apps/mobile/assets/brand/app-icon.png +0 -0
  12. package/apps/mobile/assets/brand/favicon.png +0 -0
  13. package/apps/mobile/assets/brand/mark.png +0 -0
  14. package/apps/mobile/assets/brand/splash-icon.png +0 -0
  15. package/apps/mobile/babel.config.js +7 -0
  16. package/apps/mobile/eslint.config.cjs +28 -0
  17. package/apps/mobile/index.js +5 -0
  18. package/apps/mobile/metro.config.js +3 -0
  19. package/apps/mobile/package.json +55 -0
  20. package/apps/mobile/src/api/__tests__/chatMapping.test.ts +132 -0
  21. package/apps/mobile/src/api/__tests__/client.test.ts +872 -0
  22. package/apps/mobile/src/api/__tests__/ws.test.ts +575 -0
  23. package/apps/mobile/src/api/chatMapping.ts +591 -0
  24. package/apps/mobile/src/api/client.ts +1087 -0
  25. package/apps/mobile/src/api/types.ts +267 -0
  26. package/apps/mobile/src/api/ws.ts +801 -0
  27. package/apps/mobile/src/components/ActivityBar.tsx +76 -0
  28. package/apps/mobile/src/components/ApprovalBanner.tsx +207 -0
  29. package/apps/mobile/src/components/BrandMark.tsx +43 -0
  30. package/apps/mobile/src/components/ChatHeader.tsx +106 -0
  31. package/apps/mobile/src/components/ChatInput.tsx +236 -0
  32. package/apps/mobile/src/components/ChatMessage.tsx +400 -0
  33. package/apps/mobile/src/components/StatusLine.tsx +52 -0
  34. package/apps/mobile/src/components/ToolBlock.tsx +65 -0
  35. package/apps/mobile/src/components/TypingIndicator.tsx +64 -0
  36. package/apps/mobile/src/config.ts +75 -0
  37. package/apps/mobile/src/navigation/DrawerContent.tsx +969 -0
  38. package/apps/mobile/src/screens/GitScreen.tsx +573 -0
  39. package/apps/mobile/src/screens/MainScreen.tsx +6905 -0
  40. package/apps/mobile/src/screens/PrivacyScreen.tsx +196 -0
  41. package/apps/mobile/src/screens/SettingsScreen.tsx +776 -0
  42. package/apps/mobile/src/screens/TerminalScreen.tsx +251 -0
  43. package/apps/mobile/src/screens/TermsScreen.tsx +192 -0
  44. package/apps/mobile/src/theme.ts +112 -0
  45. package/apps/mobile/src/types/assets.d.ts +4 -0
  46. package/apps/mobile/tsconfig.json +33 -0
  47. package/bin/clawdex.js +72 -0
  48. package/docs/app-review-notes.md +111 -0
  49. package/docs/open-source-license-requirements.md +32 -0
  50. package/docs/plans/2026-02-20-codex-desktop-style-redesign.md +190 -0
  51. package/docs/plans/2026-02-20-codex-mobile-implementation.md +1630 -0
  52. package/docs/plans/2026-02-21-codex-ui-redesign-design.md +101 -0
  53. package/docs/plans/2026-02-21-codex-ui-redesign.md +1229 -0
  54. package/docs/realtime-streaming-limitations.md +77 -0
  55. package/package.json +47 -0
  56. package/scripts/setup-secure-dev.sh +169 -0
  57. package/scripts/setup-wizard.sh +1302 -0
  58. package/scripts/start-bridge-secure.sh +38 -0
  59. package/scripts/start-expo.sh +176 -0
  60. package/scripts/stop-services.sh +61 -0
  61. package/scripts/teardown.sh +136 -0
  62. package/services/mac-bridge/.env.example +10 -0
  63. package/services/mac-bridge/codex-types/AbsolutePathBuf.ts +14 -0
  64. package/services/mac-bridge/codex-types/AddConversationListenerParams.ts +6 -0
  65. package/services/mac-bridge/codex-types/AddConversationSubscriptionResponse.ts +5 -0
  66. package/services/mac-bridge/codex-types/AgentMessageContent.ts +5 -0
  67. package/services/mac-bridge/codex-types/AgentMessageContentDeltaEvent.ts +5 -0
  68. package/services/mac-bridge/codex-types/AgentMessageDeltaEvent.ts +5 -0
  69. package/services/mac-bridge/codex-types/AgentMessageEvent.ts +5 -0
  70. package/services/mac-bridge/codex-types/AgentMessageItem.ts +21 -0
  71. package/services/mac-bridge/codex-types/AgentReasoningDeltaEvent.ts +5 -0
  72. package/services/mac-bridge/codex-types/AgentReasoningEvent.ts +5 -0
  73. package/services/mac-bridge/codex-types/AgentReasoningRawContentDeltaEvent.ts +5 -0
  74. package/services/mac-bridge/codex-types/AgentReasoningRawContentEvent.ts +5 -0
  75. package/services/mac-bridge/codex-types/AgentReasoningSectionBreakEvent.ts +5 -0
  76. package/services/mac-bridge/codex-types/AgentStatus.ts +8 -0
  77. package/services/mac-bridge/codex-types/ApplyPatchApprovalParams.ts +21 -0
  78. package/services/mac-bridge/codex-types/ApplyPatchApprovalRequestEvent.ts +23 -0
  79. package/services/mac-bridge/codex-types/ApplyPatchApprovalResponse.ts +6 -0
  80. package/services/mac-bridge/codex-types/ArchiveConversationParams.ts +6 -0
  81. package/services/mac-bridge/codex-types/ArchiveConversationResponse.ts +5 -0
  82. package/services/mac-bridge/codex-types/AskForApproval.ts +9 -0
  83. package/services/mac-bridge/codex-types/AuthMode.ts +8 -0
  84. package/services/mac-bridge/codex-types/AuthStatusChangeNotification.ts +9 -0
  85. package/services/mac-bridge/codex-types/BackgroundEventEvent.ts +5 -0
  86. package/services/mac-bridge/codex-types/ByteRange.ts +13 -0
  87. package/services/mac-bridge/codex-types/CallToolResult.ts +9 -0
  88. package/services/mac-bridge/codex-types/CancelLoginChatGptParams.ts +5 -0
  89. package/services/mac-bridge/codex-types/CancelLoginChatGptResponse.ts +5 -0
  90. package/services/mac-bridge/codex-types/ClientInfo.ts +5 -0
  91. package/services/mac-bridge/codex-types/ClientNotification.ts +5 -0
  92. package/services/mac-bridge/codex-types/ClientRequest.ts +60 -0
  93. package/services/mac-bridge/codex-types/CodexErrorInfo.ts +8 -0
  94. package/services/mac-bridge/codex-types/CollabAgentInteractionBeginEvent.ts +23 -0
  95. package/services/mac-bridge/codex-types/CollabAgentInteractionEndEvent.ts +28 -0
  96. package/services/mac-bridge/codex-types/CollabAgentSpawnBeginEvent.ts +19 -0
  97. package/services/mac-bridge/codex-types/CollabAgentSpawnEndEvent.ts +28 -0
  98. package/services/mac-bridge/codex-types/CollabCloseBeginEvent.ts +18 -0
  99. package/services/mac-bridge/codex-types/CollabCloseEndEvent.ts +24 -0
  100. package/services/mac-bridge/codex-types/CollabResumeBeginEvent.ts +18 -0
  101. package/services/mac-bridge/codex-types/CollabResumeEndEvent.ts +24 -0
  102. package/services/mac-bridge/codex-types/CollabWaitingBeginEvent.ts +18 -0
  103. package/services/mac-bridge/codex-types/CollabWaitingEndEvent.ts +19 -0
  104. package/services/mac-bridge/codex-types/CollaborationMode.ts +10 -0
  105. package/services/mac-bridge/codex-types/CollaborationModeMask.ts +11 -0
  106. package/services/mac-bridge/codex-types/ContentItem.ts +5 -0
  107. package/services/mac-bridge/codex-types/ContextCompactedEvent.ts +5 -0
  108. package/services/mac-bridge/codex-types/ContextCompactionItem.ts +5 -0
  109. package/services/mac-bridge/codex-types/ConversationGitInfo.ts +5 -0
  110. package/services/mac-bridge/codex-types/ConversationSummary.ts +8 -0
  111. package/services/mac-bridge/codex-types/CreditsSnapshot.ts +5 -0
  112. package/services/mac-bridge/codex-types/CustomPrompt.ts +5 -0
  113. package/services/mac-bridge/codex-types/DeprecationNoticeEvent.ts +13 -0
  114. package/services/mac-bridge/codex-types/DynamicToolCallRequest.ts +6 -0
  115. package/services/mac-bridge/codex-types/ElicitationRequestEvent.ts +5 -0
  116. package/services/mac-bridge/codex-types/ErrorEvent.ts +6 -0
  117. package/services/mac-bridge/codex-types/EventMsg.ts +78 -0
  118. package/services/mac-bridge/codex-types/ExecApprovalRequestEvent.ts +44 -0
  119. package/services/mac-bridge/codex-types/ExecCommandApprovalParams.ts +16 -0
  120. package/services/mac-bridge/codex-types/ExecCommandApprovalResponse.ts +6 -0
  121. package/services/mac-bridge/codex-types/ExecCommandBeginEvent.ts +35 -0
  122. package/services/mac-bridge/codex-types/ExecCommandEndEvent.ts +64 -0
  123. package/services/mac-bridge/codex-types/ExecCommandOutputDeltaEvent.ts +18 -0
  124. package/services/mac-bridge/codex-types/ExecCommandSource.ts +5 -0
  125. package/services/mac-bridge/codex-types/ExecCommandStatus.ts +5 -0
  126. package/services/mac-bridge/codex-types/ExecOneOffCommandParams.ts +6 -0
  127. package/services/mac-bridge/codex-types/ExecOneOffCommandResponse.ts +5 -0
  128. package/services/mac-bridge/codex-types/ExecOutputStream.ts +5 -0
  129. package/services/mac-bridge/codex-types/ExecPolicyAmendment.ts +12 -0
  130. package/services/mac-bridge/codex-types/ExitedReviewModeEvent.ts +6 -0
  131. package/services/mac-bridge/codex-types/FileChange.ts +5 -0
  132. package/services/mac-bridge/codex-types/ForcedLoginMethod.ts +5 -0
  133. package/services/mac-bridge/codex-types/ForkConversationParams.ts +7 -0
  134. package/services/mac-bridge/codex-types/ForkConversationResponse.ts +7 -0
  135. package/services/mac-bridge/codex-types/FunctionCallOutputBody.ts +6 -0
  136. package/services/mac-bridge/codex-types/FunctionCallOutputContentItem.ts +9 -0
  137. package/services/mac-bridge/codex-types/FunctionCallOutputPayload.ts +12 -0
  138. package/services/mac-bridge/codex-types/FuzzyFileSearchParams.ts +5 -0
  139. package/services/mac-bridge/codex-types/FuzzyFileSearchResponse.ts +6 -0
  140. package/services/mac-bridge/codex-types/FuzzyFileSearchResult.ts +8 -0
  141. package/services/mac-bridge/codex-types/FuzzyFileSearchSessionCompletedNotification.ts +5 -0
  142. package/services/mac-bridge/codex-types/FuzzyFileSearchSessionUpdatedNotification.ts +6 -0
  143. package/services/mac-bridge/codex-types/GetAuthStatusParams.ts +5 -0
  144. package/services/mac-bridge/codex-types/GetAuthStatusResponse.ts +6 -0
  145. package/services/mac-bridge/codex-types/GetConversationSummaryParams.ts +6 -0
  146. package/services/mac-bridge/codex-types/GetConversationSummaryResponse.ts +6 -0
  147. package/services/mac-bridge/codex-types/GetHistoryEntryResponseEvent.ts +10 -0
  148. package/services/mac-bridge/codex-types/GetUserAgentResponse.ts +5 -0
  149. package/services/mac-bridge/codex-types/GetUserSavedConfigResponse.ts +6 -0
  150. package/services/mac-bridge/codex-types/GhostCommit.ts +8 -0
  151. package/services/mac-bridge/codex-types/GitDiffToRemoteParams.ts +5 -0
  152. package/services/mac-bridge/codex-types/GitDiffToRemoteResponse.ts +6 -0
  153. package/services/mac-bridge/codex-types/GitSha.ts +5 -0
  154. package/services/mac-bridge/codex-types/HistoryEntry.ts +5 -0
  155. package/services/mac-bridge/codex-types/InitializeCapabilities.ts +17 -0
  156. package/services/mac-bridge/codex-types/InitializeParams.ts +7 -0
  157. package/services/mac-bridge/codex-types/InitializeResponse.ts +5 -0
  158. package/services/mac-bridge/codex-types/InputItem.ts +10 -0
  159. package/services/mac-bridge/codex-types/InputModality.ts +8 -0
  160. package/services/mac-bridge/codex-types/InterruptConversationParams.ts +6 -0
  161. package/services/mac-bridge/codex-types/InterruptConversationResponse.ts +6 -0
  162. package/services/mac-bridge/codex-types/ItemCompletedEvent.ts +7 -0
  163. package/services/mac-bridge/codex-types/ItemStartedEvent.ts +7 -0
  164. package/services/mac-bridge/codex-types/ListConversationsParams.ts +5 -0
  165. package/services/mac-bridge/codex-types/ListConversationsResponse.ts +6 -0
  166. package/services/mac-bridge/codex-types/ListCustomPromptsResponseEvent.ts +9 -0
  167. package/services/mac-bridge/codex-types/ListRemoteSkillsResponseEvent.ts +9 -0
  168. package/services/mac-bridge/codex-types/ListSkillsResponseEvent.ts +9 -0
  169. package/services/mac-bridge/codex-types/LocalShellAction.ts +6 -0
  170. package/services/mac-bridge/codex-types/LocalShellExecAction.ts +5 -0
  171. package/services/mac-bridge/codex-types/LocalShellStatus.ts +5 -0
  172. package/services/mac-bridge/codex-types/LoginApiKeyParams.ts +5 -0
  173. package/services/mac-bridge/codex-types/LoginApiKeyResponse.ts +5 -0
  174. package/services/mac-bridge/codex-types/LoginChatGptCompleteNotification.ts +8 -0
  175. package/services/mac-bridge/codex-types/LoginChatGptResponse.ts +5 -0
  176. package/services/mac-bridge/codex-types/LogoutChatGptResponse.ts +5 -0
  177. package/services/mac-bridge/codex-types/McpAuthStatus.ts +5 -0
  178. package/services/mac-bridge/codex-types/McpInvocation.ts +18 -0
  179. package/services/mac-bridge/codex-types/McpListToolsResponseEvent.ts +25 -0
  180. package/services/mac-bridge/codex-types/McpStartupCompleteEvent.ts +6 -0
  181. package/services/mac-bridge/codex-types/McpStartupFailure.ts +5 -0
  182. package/services/mac-bridge/codex-types/McpStartupStatus.ts +5 -0
  183. package/services/mac-bridge/codex-types/McpStartupUpdateEvent.ts +14 -0
  184. package/services/mac-bridge/codex-types/McpToolCallBeginEvent.ts +10 -0
  185. package/services/mac-bridge/codex-types/McpToolCallEndEvent.ts +15 -0
  186. package/services/mac-bridge/codex-types/MessagePhase.ts +11 -0
  187. package/services/mac-bridge/codex-types/ModeKind.ts +8 -0
  188. package/services/mac-bridge/codex-types/ModelRerouteEvent.ts +6 -0
  189. package/services/mac-bridge/codex-types/ModelRerouteReason.ts +5 -0
  190. package/services/mac-bridge/codex-types/NetworkAccess.ts +8 -0
  191. package/services/mac-bridge/codex-types/NetworkApprovalContext.ts +6 -0
  192. package/services/mac-bridge/codex-types/NetworkApprovalProtocol.ts +5 -0
  193. package/services/mac-bridge/codex-types/NewConversationParams.ts +8 -0
  194. package/services/mac-bridge/codex-types/NewConversationResponse.ts +7 -0
  195. package/services/mac-bridge/codex-types/ParsedCommand.ts +12 -0
  196. package/services/mac-bridge/codex-types/PatchApplyBeginEvent.ts +23 -0
  197. package/services/mac-bridge/codex-types/PatchApplyEndEvent.ts +36 -0
  198. package/services/mac-bridge/codex-types/PatchApplyStatus.ts +5 -0
  199. package/services/mac-bridge/codex-types/Personality.ts +5 -0
  200. package/services/mac-bridge/codex-types/PlanDeltaEvent.ts +5 -0
  201. package/services/mac-bridge/codex-types/PlanItem.ts +5 -0
  202. package/services/mac-bridge/codex-types/PlanItemArg.ts +6 -0
  203. package/services/mac-bridge/codex-types/PlanType.ts +5 -0
  204. package/services/mac-bridge/codex-types/Profile.ts +9 -0
  205. package/services/mac-bridge/codex-types/RateLimitSnapshot.ts +8 -0
  206. package/services/mac-bridge/codex-types/RateLimitWindow.ts +17 -0
  207. package/services/mac-bridge/codex-types/RawResponseItemEvent.ts +6 -0
  208. package/services/mac-bridge/codex-types/ReadOnlyAccess.ts +19 -0
  209. package/services/mac-bridge/codex-types/ReasoningContentDeltaEvent.ts +5 -0
  210. package/services/mac-bridge/codex-types/ReasoningEffort.ts +8 -0
  211. package/services/mac-bridge/codex-types/ReasoningItem.ts +5 -0
  212. package/services/mac-bridge/codex-types/ReasoningItemContent.ts +5 -0
  213. package/services/mac-bridge/codex-types/ReasoningItemReasoningSummary.ts +5 -0
  214. package/services/mac-bridge/codex-types/ReasoningRawContentDeltaEvent.ts +5 -0
  215. package/services/mac-bridge/codex-types/ReasoningSummary.ts +10 -0
  216. package/services/mac-bridge/codex-types/RemoteSkillDownloadedEvent.ts +8 -0
  217. package/services/mac-bridge/codex-types/RemoteSkillSummary.ts +5 -0
  218. package/services/mac-bridge/codex-types/RemoveConversationListenerParams.ts +5 -0
  219. package/services/mac-bridge/codex-types/RemoveConversationSubscriptionResponse.ts +5 -0
  220. package/services/mac-bridge/codex-types/RequestId.ts +5 -0
  221. package/services/mac-bridge/codex-types/RequestUserInputEvent.ts +15 -0
  222. package/services/mac-bridge/codex-types/RequestUserInputQuestion.ts +6 -0
  223. package/services/mac-bridge/codex-types/RequestUserInputQuestionOption.ts +5 -0
  224. package/services/mac-bridge/codex-types/Resource.ts +9 -0
  225. package/services/mac-bridge/codex-types/ResourceTemplate.ts +9 -0
  226. package/services/mac-bridge/codex-types/ResponseItem.ts +18 -0
  227. package/services/mac-bridge/codex-types/ResumeConversationParams.ts +8 -0
  228. package/services/mac-bridge/codex-types/ResumeConversationResponse.ts +7 -0
  229. package/services/mac-bridge/codex-types/ReviewCodeLocation.ts +9 -0
  230. package/services/mac-bridge/codex-types/ReviewDecision.ts +9 -0
  231. package/services/mac-bridge/codex-types/ReviewFinding.ts +9 -0
  232. package/services/mac-bridge/codex-types/ReviewLineRange.ts +8 -0
  233. package/services/mac-bridge/codex-types/ReviewOutputEvent.ts +9 -0
  234. package/services/mac-bridge/codex-types/ReviewRequest.ts +9 -0
  235. package/services/mac-bridge/codex-types/ReviewTarget.ts +9 -0
  236. package/services/mac-bridge/codex-types/SandboxMode.ts +5 -0
  237. package/services/mac-bridge/codex-types/SandboxPolicy.ts +44 -0
  238. package/services/mac-bridge/codex-types/SandboxSettings.ts +6 -0
  239. package/services/mac-bridge/codex-types/SendUserMessageParams.ts +7 -0
  240. package/services/mac-bridge/codex-types/SendUserMessageResponse.ts +5 -0
  241. package/services/mac-bridge/codex-types/SendUserTurnParams.ts +16 -0
  242. package/services/mac-bridge/codex-types/SendUserTurnResponse.ts +5 -0
  243. package/services/mac-bridge/codex-types/ServerNotification.ts +45 -0
  244. package/services/mac-bridge/codex-types/ServerRequest.ts +16 -0
  245. package/services/mac-bridge/codex-types/SessionConfiguredEvent.ts +57 -0
  246. package/services/mac-bridge/codex-types/SessionConfiguredNotification.ts +8 -0
  247. package/services/mac-bridge/codex-types/SessionNetworkProxyRuntime.ts +5 -0
  248. package/services/mac-bridge/codex-types/SessionSource.ts +6 -0
  249. package/services/mac-bridge/codex-types/SetDefaultModelParams.ts +6 -0
  250. package/services/mac-bridge/codex-types/SetDefaultModelResponse.ts +5 -0
  251. package/services/mac-bridge/codex-types/Settings.ts +9 -0
  252. package/services/mac-bridge/codex-types/SkillDependencies.ts +6 -0
  253. package/services/mac-bridge/codex-types/SkillErrorInfo.ts +5 -0
  254. package/services/mac-bridge/codex-types/SkillInterface.ts +5 -0
  255. package/services/mac-bridge/codex-types/SkillMetadata.ts +12 -0
  256. package/services/mac-bridge/codex-types/SkillScope.ts +5 -0
  257. package/services/mac-bridge/codex-types/SkillToolDependency.ts +5 -0
  258. package/services/mac-bridge/codex-types/SkillsListEntry.ts +7 -0
  259. package/services/mac-bridge/codex-types/StepStatus.ts +5 -0
  260. package/services/mac-bridge/codex-types/StreamErrorEvent.ts +12 -0
  261. package/services/mac-bridge/codex-types/SubAgentSource.ts +6 -0
  262. package/services/mac-bridge/codex-types/TerminalInteractionEvent.ts +17 -0
  263. package/services/mac-bridge/codex-types/TextElement.ts +14 -0
  264. package/services/mac-bridge/codex-types/ThreadId.ts +5 -0
  265. package/services/mac-bridge/codex-types/ThreadNameUpdatedEvent.ts +6 -0
  266. package/services/mac-bridge/codex-types/ThreadRolledBackEvent.ts +9 -0
  267. package/services/mac-bridge/codex-types/TokenCountEvent.ts +7 -0
  268. package/services/mac-bridge/codex-types/TokenUsage.ts +5 -0
  269. package/services/mac-bridge/codex-types/TokenUsageInfo.ts +6 -0
  270. package/services/mac-bridge/codex-types/Tool.ts +9 -0
  271. package/services/mac-bridge/codex-types/Tools.ts +5 -0
  272. package/services/mac-bridge/codex-types/TurnAbortReason.ts +5 -0
  273. package/services/mac-bridge/codex-types/TurnAbortedEvent.ts +6 -0
  274. package/services/mac-bridge/codex-types/TurnCompleteEvent.ts +5 -0
  275. package/services/mac-bridge/codex-types/TurnDiffEvent.ts +5 -0
  276. package/services/mac-bridge/codex-types/TurnItem.ts +11 -0
  277. package/services/mac-bridge/codex-types/TurnStartedEvent.ts +6 -0
  278. package/services/mac-bridge/codex-types/UndoCompletedEvent.ts +5 -0
  279. package/services/mac-bridge/codex-types/UndoStartedEvent.ts +5 -0
  280. package/services/mac-bridge/codex-types/UpdatePlanArgs.ts +10 -0
  281. package/services/mac-bridge/codex-types/UserInfoResponse.ts +5 -0
  282. package/services/mac-bridge/codex-types/UserInput.ts +16 -0
  283. package/services/mac-bridge/codex-types/UserMessageEvent.ts +22 -0
  284. package/services/mac-bridge/codex-types/UserMessageItem.ts +6 -0
  285. package/services/mac-bridge/codex-types/UserSavedConfig.ts +14 -0
  286. package/services/mac-bridge/codex-types/Verbosity.ts +9 -0
  287. package/services/mac-bridge/codex-types/ViewImageToolCallEvent.ts +13 -0
  288. package/services/mac-bridge/codex-types/WarningEvent.ts +5 -0
  289. package/services/mac-bridge/codex-types/WebSearchAction.ts +5 -0
  290. package/services/mac-bridge/codex-types/WebSearchBeginEvent.ts +5 -0
  291. package/services/mac-bridge/codex-types/WebSearchEndEvent.ts +6 -0
  292. package/services/mac-bridge/codex-types/WebSearchItem.ts +6 -0
  293. package/services/mac-bridge/codex-types/WebSearchMode.ts +5 -0
  294. package/services/mac-bridge/codex-types/index.ts +234 -0
  295. package/services/mac-bridge/codex-types/serde_json/JsonValue.ts +5 -0
  296. package/services/mac-bridge/codex-types/v2/Account.ts +6 -0
  297. package/services/mac-bridge/codex-types/v2/AccountLoginCompletedNotification.ts +5 -0
  298. package/services/mac-bridge/codex-types/v2/AccountRateLimitsUpdatedNotification.ts +6 -0
  299. package/services/mac-bridge/codex-types/v2/AccountUpdatedNotification.ts +6 -0
  300. package/services/mac-bridge/codex-types/v2/AgentMessageDeltaNotification.ts +5 -0
  301. package/services/mac-bridge/codex-types/v2/AnalyticsConfig.ts +6 -0
  302. package/services/mac-bridge/codex-types/v2/AppBranding.ts +8 -0
  303. package/services/mac-bridge/codex-types/v2/AppDisabledReason.ts +5 -0
  304. package/services/mac-bridge/codex-types/v2/AppInfo.ts +19 -0
  305. package/services/mac-bridge/codex-types/v2/AppListUpdatedNotification.ts +9 -0
  306. package/services/mac-bridge/codex-types/v2/AppMetadata.ts +7 -0
  307. package/services/mac-bridge/codex-types/v2/AppReview.ts +5 -0
  308. package/services/mac-bridge/codex-types/v2/AppScreenshot.ts +5 -0
  309. package/services/mac-bridge/codex-types/v2/AppsConfig.ts +6 -0
  310. package/services/mac-bridge/codex-types/v2/AppsListParams.ts +24 -0
  311. package/services/mac-bridge/codex-types/v2/AppsListResponse.ts +14 -0
  312. package/services/mac-bridge/codex-types/v2/AskForApproval.ts +5 -0
  313. package/services/mac-bridge/codex-types/v2/ByteRange.ts +5 -0
  314. package/services/mac-bridge/codex-types/v2/CancelLoginAccountParams.ts +5 -0
  315. package/services/mac-bridge/codex-types/v2/CancelLoginAccountResponse.ts +6 -0
  316. package/services/mac-bridge/codex-types/v2/CancelLoginAccountStatus.ts +5 -0
  317. package/services/mac-bridge/codex-types/v2/ChatgptAuthTokensRefreshParams.ts +16 -0
  318. package/services/mac-bridge/codex-types/v2/ChatgptAuthTokensRefreshReason.ts +5 -0
  319. package/services/mac-bridge/codex-types/v2/ChatgptAuthTokensRefreshResponse.ts +5 -0
  320. package/services/mac-bridge/codex-types/v2/CodexErrorInfo.ts +11 -0
  321. package/services/mac-bridge/codex-types/v2/CollabAgentState.ts +6 -0
  322. package/services/mac-bridge/codex-types/v2/CollabAgentStatus.ts +5 -0
  323. package/services/mac-bridge/codex-types/v2/CollabAgentTool.ts +5 -0
  324. package/services/mac-bridge/codex-types/v2/CollabAgentToolCallStatus.ts +5 -0
  325. package/services/mac-bridge/codex-types/v2/CommandAction.ts +5 -0
  326. package/services/mac-bridge/codex-types/v2/CommandExecParams.ts +6 -0
  327. package/services/mac-bridge/codex-types/v2/CommandExecResponse.ts +5 -0
  328. package/services/mac-bridge/codex-types/v2/CommandExecutionApprovalDecision.ts +6 -0
  329. package/services/mac-bridge/codex-types/v2/CommandExecutionOutputDeltaNotification.ts +5 -0
  330. package/services/mac-bridge/codex-types/v2/CommandExecutionRequestApprovalParams.ts +37 -0
  331. package/services/mac-bridge/codex-types/v2/CommandExecutionRequestApprovalResponse.ts +6 -0
  332. package/services/mac-bridge/codex-types/v2/CommandExecutionStatus.ts +5 -0
  333. package/services/mac-bridge/codex-types/v2/Config.ts +17 -0
  334. package/services/mac-bridge/codex-types/v2/ConfigBatchWriteParams.ts +10 -0
  335. package/services/mac-bridge/codex-types/v2/ConfigEdit.ts +7 -0
  336. package/services/mac-bridge/codex-types/v2/ConfigLayer.ts +7 -0
  337. package/services/mac-bridge/codex-types/v2/ConfigLayerMetadata.ts +6 -0
  338. package/services/mac-bridge/codex-types/v2/ConfigLayerSource.ts +16 -0
  339. package/services/mac-bridge/codex-types/v2/ConfigReadParams.ts +11 -0
  340. package/services/mac-bridge/codex-types/v2/ConfigReadResponse.ts +8 -0
  341. package/services/mac-bridge/codex-types/v2/ConfigRequirements.ts +9 -0
  342. package/services/mac-bridge/codex-types/v2/ConfigRequirementsReadResponse.ts +10 -0
  343. package/services/mac-bridge/codex-types/v2/ConfigValueWriteParams.ts +11 -0
  344. package/services/mac-bridge/codex-types/v2/ConfigWarningNotification.ts +22 -0
  345. package/services/mac-bridge/codex-types/v2/ConfigWriteResponse.ts +12 -0
  346. package/services/mac-bridge/codex-types/v2/ContextCompactedNotification.ts +8 -0
  347. package/services/mac-bridge/codex-types/v2/CreditsSnapshot.ts +5 -0
  348. package/services/mac-bridge/codex-types/v2/DeprecationNoticeNotification.ts +13 -0
  349. package/services/mac-bridge/codex-types/v2/DynamicToolCallOutputContentItem.ts +5 -0
  350. package/services/mac-bridge/codex-types/v2/DynamicToolCallParams.ts +6 -0
  351. package/services/mac-bridge/codex-types/v2/DynamicToolCallResponse.ts +6 -0
  352. package/services/mac-bridge/codex-types/v2/DynamicToolSpec.ts +6 -0
  353. package/services/mac-bridge/codex-types/v2/ErrorNotification.ts +6 -0
  354. package/services/mac-bridge/codex-types/v2/ExecPolicyAmendment.ts +5 -0
  355. package/services/mac-bridge/codex-types/v2/ExperimentalFeature.ts +37 -0
  356. package/services/mac-bridge/codex-types/v2/ExperimentalFeatureListParams.ts +13 -0
  357. package/services/mac-bridge/codex-types/v2/ExperimentalFeatureListResponse.ts +11 -0
  358. package/services/mac-bridge/codex-types/v2/ExperimentalFeatureStage.ts +5 -0
  359. package/services/mac-bridge/codex-types/v2/FeedbackUploadParams.ts +5 -0
  360. package/services/mac-bridge/codex-types/v2/FeedbackUploadResponse.ts +5 -0
  361. package/services/mac-bridge/codex-types/v2/FileChangeApprovalDecision.ts +5 -0
  362. package/services/mac-bridge/codex-types/v2/FileChangeOutputDeltaNotification.ts +5 -0
  363. package/services/mac-bridge/codex-types/v2/FileChangeRequestApprovalParams.ts +14 -0
  364. package/services/mac-bridge/codex-types/v2/FileChangeRequestApprovalResponse.ts +6 -0
  365. package/services/mac-bridge/codex-types/v2/FileUpdateChange.ts +6 -0
  366. package/services/mac-bridge/codex-types/v2/GetAccountParams.ts +13 -0
  367. package/services/mac-bridge/codex-types/v2/GetAccountRateLimitsResponse.ts +14 -0
  368. package/services/mac-bridge/codex-types/v2/GetAccountResponse.ts +6 -0
  369. package/services/mac-bridge/codex-types/v2/GitInfo.ts +5 -0
  370. package/services/mac-bridge/codex-types/v2/HazelnutScope.ts +5 -0
  371. package/services/mac-bridge/codex-types/v2/ItemCompletedNotification.ts +6 -0
  372. package/services/mac-bridge/codex-types/v2/ItemStartedNotification.ts +6 -0
  373. package/services/mac-bridge/codex-types/v2/ListMcpServerStatusParams.ts +13 -0
  374. package/services/mac-bridge/codex-types/v2/ListMcpServerStatusResponse.ts +11 -0
  375. package/services/mac-bridge/codex-types/v2/LoginAccountParams.ts +21 -0
  376. package/services/mac-bridge/codex-types/v2/LoginAccountResponse.ts +9 -0
  377. package/services/mac-bridge/codex-types/v2/LogoutAccountResponse.ts +5 -0
  378. package/services/mac-bridge/codex-types/v2/McpAuthStatus.ts +5 -0
  379. package/services/mac-bridge/codex-types/v2/McpServerOauthLoginCompletedNotification.ts +5 -0
  380. package/services/mac-bridge/codex-types/v2/McpServerOauthLoginParams.ts +5 -0
  381. package/services/mac-bridge/codex-types/v2/McpServerOauthLoginResponse.ts +5 -0
  382. package/services/mac-bridge/codex-types/v2/McpServerRefreshResponse.ts +5 -0
  383. package/services/mac-bridge/codex-types/v2/McpServerStatus.ts +9 -0
  384. package/services/mac-bridge/codex-types/v2/McpToolCallError.ts +5 -0
  385. package/services/mac-bridge/codex-types/v2/McpToolCallProgressNotification.ts +5 -0
  386. package/services/mac-bridge/codex-types/v2/McpToolCallResult.ts +6 -0
  387. package/services/mac-bridge/codex-types/v2/McpToolCallStatus.ts +5 -0
  388. package/services/mac-bridge/codex-types/v2/MergeStrategy.ts +5 -0
  389. package/services/mac-bridge/codex-types/v2/Model.ts +8 -0
  390. package/services/mac-bridge/codex-types/v2/ModelListParams.ts +17 -0
  391. package/services/mac-bridge/codex-types/v2/ModelListResponse.ts +11 -0
  392. package/services/mac-bridge/codex-types/v2/ModelRerouteReason.ts +5 -0
  393. package/services/mac-bridge/codex-types/v2/ModelReroutedNotification.ts +6 -0
  394. package/services/mac-bridge/codex-types/v2/NetworkAccess.ts +5 -0
  395. package/services/mac-bridge/codex-types/v2/NetworkRequirements.ts +5 -0
  396. package/services/mac-bridge/codex-types/v2/OverriddenMetadata.ts +7 -0
  397. package/services/mac-bridge/codex-types/v2/PatchApplyStatus.ts +5 -0
  398. package/services/mac-bridge/codex-types/v2/PatchChangeKind.ts +5 -0
  399. package/services/mac-bridge/codex-types/v2/PlanDeltaNotification.ts +9 -0
  400. package/services/mac-bridge/codex-types/v2/ProductSurface.ts +5 -0
  401. package/services/mac-bridge/codex-types/v2/ProfileV2.ts +11 -0
  402. package/services/mac-bridge/codex-types/v2/RateLimitSnapshot.ts +8 -0
  403. package/services/mac-bridge/codex-types/v2/RateLimitWindow.ts +5 -0
  404. package/services/mac-bridge/codex-types/v2/RawResponseItemCompletedNotification.ts +6 -0
  405. package/services/mac-bridge/codex-types/v2/ReadOnlyAccess.ts +6 -0
  406. package/services/mac-bridge/codex-types/v2/ReasoningEffortOption.ts +6 -0
  407. package/services/mac-bridge/codex-types/v2/ReasoningSummaryPartAddedNotification.ts +5 -0
  408. package/services/mac-bridge/codex-types/v2/ReasoningSummaryTextDeltaNotification.ts +5 -0
  409. package/services/mac-bridge/codex-types/v2/ReasoningTextDeltaNotification.ts +5 -0
  410. package/services/mac-bridge/codex-types/v2/RemoteSkillSummary.ts +5 -0
  411. package/services/mac-bridge/codex-types/v2/ResidencyRequirement.ts +5 -0
  412. package/services/mac-bridge/codex-types/v2/ReviewDelivery.ts +5 -0
  413. package/services/mac-bridge/codex-types/v2/ReviewStartParams.ts +12 -0
  414. package/services/mac-bridge/codex-types/v2/ReviewStartResponse.ts +13 -0
  415. package/services/mac-bridge/codex-types/v2/ReviewTarget.ts +9 -0
  416. package/services/mac-bridge/codex-types/v2/SandboxMode.ts +5 -0
  417. package/services/mac-bridge/codex-types/v2/SandboxPolicy.ts +8 -0
  418. package/services/mac-bridge/codex-types/v2/SandboxWorkspaceWrite.ts +5 -0
  419. package/services/mac-bridge/codex-types/v2/SessionSource.ts +6 -0
  420. package/services/mac-bridge/codex-types/v2/SkillDependencies.ts +6 -0
  421. package/services/mac-bridge/codex-types/v2/SkillErrorInfo.ts +5 -0
  422. package/services/mac-bridge/codex-types/v2/SkillInterface.ts +5 -0
  423. package/services/mac-bridge/codex-types/v2/SkillMetadata.ts +12 -0
  424. package/services/mac-bridge/codex-types/v2/SkillScope.ts +5 -0
  425. package/services/mac-bridge/codex-types/v2/SkillToolDependency.ts +5 -0
  426. package/services/mac-bridge/codex-types/v2/SkillsConfigWriteParams.ts +5 -0
  427. package/services/mac-bridge/codex-types/v2/SkillsConfigWriteResponse.ts +5 -0
  428. package/services/mac-bridge/codex-types/v2/SkillsListEntry.ts +7 -0
  429. package/services/mac-bridge/codex-types/v2/SkillsListExtraRootsForCwd.ts +5 -0
  430. package/services/mac-bridge/codex-types/v2/SkillsListParams.ts +18 -0
  431. package/services/mac-bridge/codex-types/v2/SkillsListResponse.ts +6 -0
  432. package/services/mac-bridge/codex-types/v2/SkillsRemoteReadParams.ts +7 -0
  433. package/services/mac-bridge/codex-types/v2/SkillsRemoteReadResponse.ts +6 -0
  434. package/services/mac-bridge/codex-types/v2/SkillsRemoteWriteParams.ts +5 -0
  435. package/services/mac-bridge/codex-types/v2/SkillsRemoteWriteResponse.ts +5 -0
  436. package/services/mac-bridge/codex-types/v2/TerminalInteractionNotification.ts +5 -0
  437. package/services/mac-bridge/codex-types/v2/TextElement.ts +14 -0
  438. package/services/mac-bridge/codex-types/v2/TextPosition.ts +13 -0
  439. package/services/mac-bridge/codex-types/v2/TextRange.ts +6 -0
  440. package/services/mac-bridge/codex-types/v2/Thread.ts +51 -0
  441. package/services/mac-bridge/codex-types/v2/ThreadArchiveParams.ts +5 -0
  442. package/services/mac-bridge/codex-types/v2/ThreadArchiveResponse.ts +5 -0
  443. package/services/mac-bridge/codex-types/v2/ThreadArchivedNotification.ts +5 -0
  444. package/services/mac-bridge/codex-types/v2/ThreadCompactStartParams.ts +5 -0
  445. package/services/mac-bridge/codex-types/v2/ThreadCompactStartResponse.ts +5 -0
  446. package/services/mac-bridge/codex-types/v2/ThreadForkParams.ts +28 -0
  447. package/services/mac-bridge/codex-types/v2/ThreadForkResponse.ts +9 -0
  448. package/services/mac-bridge/codex-types/v2/ThreadItem.ts +81 -0
  449. package/services/mac-bridge/codex-types/v2/ThreadListParams.ts +39 -0
  450. package/services/mac-bridge/codex-types/v2/ThreadListResponse.ts +11 -0
  451. package/services/mac-bridge/codex-types/v2/ThreadLoadedListParams.ts +13 -0
  452. package/services/mac-bridge/codex-types/v2/ThreadLoadedListResponse.ts +14 -0
  453. package/services/mac-bridge/codex-types/v2/ThreadNameUpdatedNotification.ts +5 -0
  454. package/services/mac-bridge/codex-types/v2/ThreadReadParams.ts +9 -0
  455. package/services/mac-bridge/codex-types/v2/ThreadReadResponse.ts +6 -0
  456. package/services/mac-bridge/codex-types/v2/ThreadResumeParams.ts +37 -0
  457. package/services/mac-bridge/codex-types/v2/ThreadResumeResponse.ts +9 -0
  458. package/services/mac-bridge/codex-types/v2/ThreadRollbackParams.ts +12 -0
  459. package/services/mac-bridge/codex-types/v2/ThreadRollbackResponse.ts +14 -0
  460. package/services/mac-bridge/codex-types/v2/ThreadSetNameParams.ts +5 -0
  461. package/services/mac-bridge/codex-types/v2/ThreadSetNameResponse.ts +5 -0
  462. package/services/mac-bridge/codex-types/v2/ThreadSortKey.ts +5 -0
  463. package/services/mac-bridge/codex-types/v2/ThreadSourceKind.ts +5 -0
  464. package/services/mac-bridge/codex-types/v2/ThreadStartParams.ts +17 -0
  465. package/services/mac-bridge/codex-types/v2/ThreadStartResponse.ts +9 -0
  466. package/services/mac-bridge/codex-types/v2/ThreadStartedNotification.ts +6 -0
  467. package/services/mac-bridge/codex-types/v2/ThreadTokenUsage.ts +6 -0
  468. package/services/mac-bridge/codex-types/v2/ThreadTokenUsageUpdatedNotification.ts +6 -0
  469. package/services/mac-bridge/codex-types/v2/ThreadUnarchiveParams.ts +5 -0
  470. package/services/mac-bridge/codex-types/v2/ThreadUnarchiveResponse.ts +6 -0
  471. package/services/mac-bridge/codex-types/v2/ThreadUnarchivedNotification.ts +5 -0
  472. package/services/mac-bridge/codex-types/v2/TokenUsageBreakdown.ts +5 -0
  473. package/services/mac-bridge/codex-types/v2/ToolRequestUserInputAnswer.ts +8 -0
  474. package/services/mac-bridge/codex-types/v2/ToolRequestUserInputOption.ts +8 -0
  475. package/services/mac-bridge/codex-types/v2/ToolRequestUserInputParams.ts +9 -0
  476. package/services/mac-bridge/codex-types/v2/ToolRequestUserInputQuestion.ts +9 -0
  477. package/services/mac-bridge/codex-types/v2/ToolRequestUserInputResponse.ts +9 -0
  478. package/services/mac-bridge/codex-types/v2/ToolsV2.ts +5 -0
  479. package/services/mac-bridge/codex-types/v2/Turn.ts +18 -0
  480. package/services/mac-bridge/codex-types/v2/TurnCompletedNotification.ts +6 -0
  481. package/services/mac-bridge/codex-types/v2/TurnDiffUpdatedNotification.ts +9 -0
  482. package/services/mac-bridge/codex-types/v2/TurnError.ts +6 -0
  483. package/services/mac-bridge/codex-types/v2/TurnInterruptParams.ts +5 -0
  484. package/services/mac-bridge/codex-types/v2/TurnInterruptResponse.ts +5 -0
  485. package/services/mac-bridge/codex-types/v2/TurnPlanStep.ts +6 -0
  486. package/services/mac-bridge/codex-types/v2/TurnPlanStepStatus.ts +5 -0
  487. package/services/mac-bridge/codex-types/v2/TurnPlanUpdatedNotification.ts +6 -0
  488. package/services/mac-bridge/codex-types/v2/TurnStartParams.ts +44 -0
  489. package/services/mac-bridge/codex-types/v2/TurnStartResponse.ts +6 -0
  490. package/services/mac-bridge/codex-types/v2/TurnStartedNotification.ts +6 -0
  491. package/services/mac-bridge/codex-types/v2/TurnStatus.ts +5 -0
  492. package/services/mac-bridge/codex-types/v2/TurnSteerParams.ts +11 -0
  493. package/services/mac-bridge/codex-types/v2/TurnSteerResponse.ts +5 -0
  494. package/services/mac-bridge/codex-types/v2/UserInput.ts +10 -0
  495. package/services/mac-bridge/codex-types/v2/WebSearchAction.ts +5 -0
  496. package/services/mac-bridge/codex-types/v2/WindowsWorldWritableWarningNotification.ts +5 -0
  497. package/services/mac-bridge/codex-types/v2/WriteStatus.ts +5 -0
  498. package/services/mac-bridge/codex-types/v2/index.ts +204 -0
  499. package/services/mac-bridge/eslint.config.cjs +22 -0
  500. package/services/mac-bridge/package.json +30 -0
  501. package/services/mac-bridge/schema.ts +0 -0
  502. package/services/mac-bridge/src/index.ts +18 -0
  503. package/services/mac-bridge/src/server.ts +426 -0
  504. package/services/mac-bridge/src/services/__tests__/gitService.test.ts +157 -0
  505. package/services/mac-bridge/src/services/__tests__/realtimeHub.test.ts +116 -0
  506. package/services/mac-bridge/src/services/__tests__/terminalService.test.ts +51 -0
  507. package/services/mac-bridge/src/services/codexAppServerClient.ts +507 -0
  508. package/services/mac-bridge/src/services/codexCliAdapter.ts +622 -0
  509. package/services/mac-bridge/src/services/gitService.ts +61 -0
  510. package/services/mac-bridge/src/services/realtimeHub.ts +25 -0
  511. package/services/mac-bridge/src/services/terminalService.ts +226 -0
  512. package/services/mac-bridge/src/types.ts +151 -0
  513. package/services/mac-bridge/src/utils/__tests__/threadMapping.test.ts +397 -0
  514. package/services/mac-bridge/src/utils/threadMapping.ts +176 -0
  515. package/services/mac-bridge/tsconfig.json +16 -0
  516. package/services/mac-bridge/vitest.config.ts +9 -0
  517. package/services/rust-bridge/.env.example +11 -0
  518. package/services/rust-bridge/Cargo.lock +1127 -0
  519. package/services/rust-bridge/Cargo.toml +14 -0
  520. package/services/rust-bridge/package.json +13 -0
  521. package/services/rust-bridge/security_best_practices_report.md +24 -0
  522. package/services/rust-bridge/src/main.rs +2713 -0
  523. package/services/rust-bridge/src/services/git.rs +271 -0
  524. package/services/rust-bridge/src/services/mod.rs +5 -0
  525. package/services/rust-bridge/src/services/terminal.rs +267 -0
  526. package/tsconfig.json +4 -0
@@ -0,0 +1,872 @@
1
+ import { HostBridgeApiClient } from '../client';
2
+ import type { HostBridgeWsClient } from '../ws';
3
+
4
+ function createWsMock() {
5
+ type WsLike = Pick<HostBridgeWsClient, 'request' | 'waitForTurnCompletion'>;
6
+ return {
7
+ request: jest.fn(),
8
+ waitForTurnCompletion: jest.fn().mockResolvedValue(undefined),
9
+ } as jest.Mocked<WsLike>;
10
+ }
11
+
12
+ describe('HostBridgeApiClient', () => {
13
+ it('health() calls bridge/health/read', async () => {
14
+ const ws = createWsMock();
15
+ ws.request.mockResolvedValue({ status: 'ok', at: '2026-01-01T00:00:00Z', uptimeSec: 10 });
16
+
17
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
18
+ const result = await client.health();
19
+
20
+ expect(ws.request).toHaveBeenCalledWith('bridge/health/read');
21
+ expect(result.status).toBe('ok');
22
+ });
23
+
24
+ it('listChats() maps app-server list response', async () => {
25
+ const ws = createWsMock();
26
+ ws.request.mockResolvedValue({
27
+ data: [
28
+ {
29
+ id: 'thr_1',
30
+ preview: 'hello world',
31
+ createdAt: 1700000000,
32
+ updatedAt: 1700000001,
33
+ status: { type: 'active' },
34
+ turns: [
35
+ {
36
+ status: 'completed',
37
+ items: [],
38
+ },
39
+ ],
40
+ },
41
+ ],
42
+ });
43
+
44
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
45
+ const chats = await client.listChats();
46
+
47
+ expect(ws.request).toHaveBeenCalledWith(
48
+ 'thread/list',
49
+ expect.objectContaining({
50
+ sourceKinds: ['cli', 'vscode', 'exec', 'appServer', 'unknown'],
51
+ })
52
+ );
53
+ expect(chats).toHaveLength(1);
54
+ expect(chats[0].id).toBe('thr_1');
55
+ expect(chats[0].status).toBe('complete');
56
+ });
57
+
58
+ it('listChats() treats idle thread status as complete even with stale inProgress turn', async () => {
59
+ const ws = createWsMock();
60
+ ws.request.mockResolvedValue({
61
+ data: [
62
+ {
63
+ id: 'thr_idle_with_stale_turn',
64
+ preview: 'done',
65
+ createdAt: 1700000000,
66
+ updatedAt: 1700000001,
67
+ status: { type: 'idle' },
68
+ turns: [
69
+ {
70
+ status: 'inProgress',
71
+ items: [],
72
+ },
73
+ ],
74
+ },
75
+ ],
76
+ });
77
+
78
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
79
+ const chats = await client.listChats();
80
+
81
+ expect(chats).toHaveLength(1);
82
+ expect(chats[0].status).toBe('complete');
83
+ });
84
+
85
+ it('listChats() excludes sub-agent source kinds defensively', async () => {
86
+ const ws = createWsMock();
87
+ ws.request.mockResolvedValue({
88
+ data: [
89
+ {
90
+ id: 'thr_root',
91
+ preview: 'root chat',
92
+ createdAt: 1700000000,
93
+ updatedAt: 1700000001,
94
+ status: { type: 'idle' },
95
+ source: 'appServer',
96
+ turns: [],
97
+ },
98
+ {
99
+ id: 'thr_sub',
100
+ preview: 'spawned worker',
101
+ createdAt: 1700000000,
102
+ updatedAt: 1700000002,
103
+ status: { type: 'idle' },
104
+ source: {
105
+ subAgent: {
106
+ thread_spawn: {
107
+ parent_thread_id: 'thr_root',
108
+ depth: 1,
109
+ },
110
+ },
111
+ },
112
+ turns: [],
113
+ },
114
+ {
115
+ id: 'thr_sub_legacy',
116
+ preview: 'legacy sub-agent',
117
+ createdAt: 1700000000,
118
+ updatedAt: 1700000003,
119
+ status: { type: 'idle' },
120
+ source: { kind: 'subAgent' },
121
+ turns: [],
122
+ },
123
+ ],
124
+ });
125
+
126
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
127
+ const chats = await client.listChats();
128
+
129
+ expect(chats.map((chat) => chat.id)).toEqual(['thr_root']);
130
+ });
131
+
132
+ it('sendChatMessage() starts a turn without waiting for completion', async () => {
133
+ const ws = createWsMock();
134
+ ws.request
135
+ .mockResolvedValueOnce({}) // thread/resume
136
+ .mockResolvedValueOnce({ turn: { id: 'turn_1' } }) // turn/start
137
+ .mockResolvedValueOnce({
138
+ thread: {
139
+ id: 'thr_1',
140
+ preview: 'final',
141
+ createdAt: 1700000000,
142
+ updatedAt: 1700000002,
143
+ status: { type: 'idle' },
144
+ turns: [
145
+ {
146
+ id: 'turn_1',
147
+ items: [
148
+ {
149
+ type: 'userMessage',
150
+ id: 'u1',
151
+ content: [{ type: 'text', text: 'Hello' }],
152
+ },
153
+ {
154
+ type: 'agentMessage',
155
+ id: 'a1',
156
+ text: 'Hi there',
157
+ },
158
+ ],
159
+ },
160
+ ],
161
+ },
162
+ });
163
+
164
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
165
+ const chat = await client.sendChatMessage('thr_1', { content: 'Hello' });
166
+
167
+ expect(ws.request).toHaveBeenNthCalledWith(2, 'turn/start', expect.any(Object));
168
+ expect(ws.waitForTurnCompletion).not.toHaveBeenCalled();
169
+ expect(chat.id).toBe('thr_1');
170
+ expect(chat.messages.length).toBeGreaterThan(0);
171
+ });
172
+
173
+ it('sendChatMessage() retries thread/read until sent user message is materialized', async () => {
174
+ jest.useFakeTimers();
175
+ try {
176
+ const ws = createWsMock();
177
+ ws.request
178
+ .mockResolvedValueOnce({}) // thread/resume
179
+ .mockResolvedValueOnce({ turn: { id: 'turn_retry' } }) // turn/start
180
+ .mockResolvedValueOnce({
181
+ thread: {
182
+ id: 'thr_retry',
183
+ preview: 'stale',
184
+ createdAt: 1700000000,
185
+ updatedAt: 1700000001,
186
+ status: { type: 'idle' },
187
+ turns: [],
188
+ },
189
+ }) // stale thread/read (missing latest user item)
190
+ .mockResolvedValueOnce({
191
+ thread: {
192
+ id: 'thr_retry',
193
+ preview: 'Hello',
194
+ createdAt: 1700000000,
195
+ updatedAt: 1700000002,
196
+ status: { type: 'idle' },
197
+ turns: [
198
+ {
199
+ id: 'turn_retry',
200
+ items: [
201
+ {
202
+ type: 'userMessage',
203
+ id: 'u_retry',
204
+ content: [{ type: 'text', text: 'Hello' }],
205
+ },
206
+ ],
207
+ },
208
+ ],
209
+ },
210
+ }); // retried thread/read
211
+
212
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
213
+ const chatPromise = client.sendChatMessage('thr_retry', { content: 'Hello' });
214
+
215
+ await Promise.resolve();
216
+ await jest.advanceTimersByTimeAsync(200);
217
+ const chat = await chatPromise;
218
+
219
+ expect(chat.messages.some((message) => message.role === 'user' && message.content === 'Hello')).toBe(true);
220
+ expect(ws.request).toHaveBeenCalledWith(
221
+ 'turn/start',
222
+ expect.objectContaining({
223
+ threadId: 'thr_retry',
224
+ })
225
+ );
226
+ } finally {
227
+ jest.useRealTimers();
228
+ }
229
+ });
230
+
231
+ it('sendChatMessage() keeps a repeated user prompt when the new turn is missing from thread/read', async () => {
232
+ jest.useFakeTimers();
233
+ try {
234
+ const ws = createWsMock();
235
+ const staleReadResponse = {
236
+ thread: {
237
+ id: 'thr_repeat',
238
+ preview: 'repeat',
239
+ createdAt: 1700000000,
240
+ updatedAt: 1700000002,
241
+ status: { type: 'idle' },
242
+ turns: [
243
+ {
244
+ id: 'turn_old',
245
+ items: [
246
+ {
247
+ type: 'userMessage',
248
+ id: 'u_old_repeat',
249
+ content: [{ type: 'text', text: 'repeat' }],
250
+ },
251
+ {
252
+ type: 'agentMessage',
253
+ id: 'a_old_repeat',
254
+ text: 'old answer',
255
+ },
256
+ ],
257
+ },
258
+ ],
259
+ },
260
+ };
261
+
262
+ ws.request
263
+ .mockResolvedValueOnce({}) // thread/resume
264
+ .mockResolvedValueOnce({ turn: { id: 'turn_new_repeat' } }) // turn/start
265
+ .mockResolvedValue(staleReadResponse); // thread/read retries always stale
266
+
267
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
268
+ const chatPromise = client.sendChatMessage('thr_repeat', { content: 'repeat' });
269
+
270
+ await Promise.resolve();
271
+ await jest.advanceTimersByTimeAsync(2_000);
272
+ const chat = await chatPromise;
273
+
274
+ const repeatedUserMessages = chat.messages.filter(
275
+ (message) => message.role === 'user' && message.content === 'repeat'
276
+ );
277
+ expect(repeatedUserMessages.length).toBeGreaterThanOrEqual(2);
278
+ } finally {
279
+ jest.useRealTimers();
280
+ }
281
+ });
282
+
283
+ it('createChat() forwards selected model to thread/start', async () => {
284
+ const ws = createWsMock();
285
+ ws.request
286
+ .mockResolvedValueOnce({
287
+ thread: {
288
+ id: 'thr_model',
289
+ preview: '',
290
+ createdAt: 1700000000,
291
+ updatedAt: 1700000000,
292
+ status: { type: 'idle' },
293
+ turns: [],
294
+ },
295
+ })
296
+ .mockResolvedValueOnce({
297
+ thread: {
298
+ id: 'thr_model',
299
+ preview: '',
300
+ createdAt: 1700000000,
301
+ updatedAt: 1700000000,
302
+ status: { type: 'idle' },
303
+ turns: [],
304
+ },
305
+ });
306
+
307
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
308
+ await client.createChat({ model: 'gpt-5.3-codex' });
309
+
310
+ expect(ws.request).toHaveBeenCalledWith(
311
+ 'thread/start',
312
+ expect.objectContaining({
313
+ model: 'gpt-5.3-codex',
314
+ })
315
+ );
316
+ });
317
+
318
+ it('createChat() forwards selected approval policy to thread/start', async () => {
319
+ const ws = createWsMock();
320
+ ws.request.mockResolvedValueOnce({
321
+ thread: {
322
+ id: 'thr_policy',
323
+ preview: '',
324
+ createdAt: 1700000000,
325
+ updatedAt: 1700000000,
326
+ status: { type: 'idle' },
327
+ turns: [],
328
+ },
329
+ });
330
+
331
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
332
+ await client.createChat({ approvalPolicy: 'never' });
333
+
334
+ expect(ws.request).toHaveBeenCalledWith(
335
+ 'thread/start',
336
+ expect.objectContaining({
337
+ approvalPolicy: 'never',
338
+ })
339
+ );
340
+ });
341
+
342
+ it('renameChat() retries with threadName when name payload is rejected', async () => {
343
+ const ws = createWsMock();
344
+ ws.request
345
+ .mockRejectedValueOnce(new Error('missing field `threadName`'))
346
+ .mockResolvedValueOnce({}) // thread/name/set retry with threadName
347
+ .mockResolvedValueOnce({}) // explicit threadName attempt
348
+ .mockResolvedValueOnce({
349
+ thread: {
350
+ id: 'thr_rename',
351
+ preview: '',
352
+ createdAt: 1700000000,
353
+ updatedAt: 1700000002,
354
+ status: { type: 'idle' },
355
+ name: 'Renamed Chat',
356
+ turns: [],
357
+ },
358
+ });
359
+
360
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
361
+ const renamed = await client.renameChat('thr_rename', 'Renamed Chat');
362
+
363
+ expect(ws.request).toHaveBeenNthCalledWith(1, 'thread/name/set', {
364
+ threadId: 'thr_rename',
365
+ name: 'Renamed Chat',
366
+ });
367
+ expect(ws.request).toHaveBeenNthCalledWith(2, 'thread/name/set', {
368
+ threadId: 'thr_rename',
369
+ threadName: 'Renamed Chat',
370
+ });
371
+ expect(ws.request).toHaveBeenNthCalledWith(3, 'thread/name/set', {
372
+ threadId: 'thr_rename',
373
+ threadName: 'Renamed Chat',
374
+ });
375
+ expect(renamed.title).toBe('Renamed Chat');
376
+ });
377
+
378
+ it('sendChatMessage() forwards selected model/effort to turn/start', async () => {
379
+ const ws = createWsMock();
380
+ ws.request
381
+ .mockResolvedValueOnce({}) // thread/resume
382
+ .mockResolvedValueOnce({ turn: { id: 'turn_model' } }) // turn/start
383
+ .mockResolvedValueOnce({
384
+ thread: {
385
+ id: 'thr_model',
386
+ preview: 'done',
387
+ createdAt: 1700000000,
388
+ updatedAt: 1700000002,
389
+ status: { type: 'idle' },
390
+ turns: [
391
+ {
392
+ id: 'turn_model',
393
+ items: [
394
+ {
395
+ type: 'userMessage',
396
+ id: 'u1',
397
+ content: [{ type: 'text', text: 'hello' }],
398
+ },
399
+ {
400
+ type: 'agentMessage',
401
+ id: 'a1',
402
+ text: 'ok',
403
+ },
404
+ ],
405
+ },
406
+ ],
407
+ },
408
+ });
409
+
410
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
411
+ await client.sendChatMessage('thr_model', {
412
+ content: 'hello',
413
+ model: 'gpt-5.3-codex',
414
+ effort: 'high',
415
+ });
416
+
417
+ expect(ws.request).toHaveBeenNthCalledWith(1, 'thread/resume', expect.any(Object));
418
+ expect(ws.request).toHaveBeenNthCalledWith(
419
+ 2,
420
+ 'turn/start',
421
+ expect.objectContaining({
422
+ model: 'gpt-5.3-codex',
423
+ effort: 'high',
424
+ })
425
+ );
426
+ });
427
+
428
+ it('sendChatMessage() forwards selected approval policy to resume and turn/start', async () => {
429
+ const ws = createWsMock();
430
+ ws.request
431
+ .mockResolvedValueOnce({}) // thread/resume
432
+ .mockResolvedValueOnce({ turn: { id: 'turn_policy' } }) // turn/start
433
+ .mockResolvedValueOnce({
434
+ thread: {
435
+ id: 'thr_policy_turn',
436
+ preview: 'done',
437
+ createdAt: 1700000000,
438
+ updatedAt: 1700000002,
439
+ status: { type: 'idle' },
440
+ turns: [
441
+ {
442
+ id: 'turn_policy',
443
+ items: [
444
+ {
445
+ type: 'userMessage',
446
+ id: 'u_policy',
447
+ content: [{ type: 'text', text: 'hello' }],
448
+ },
449
+ ],
450
+ },
451
+ ],
452
+ },
453
+ });
454
+
455
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
456
+ await client.sendChatMessage('thr_policy_turn', {
457
+ content: 'hello',
458
+ approvalPolicy: 'never',
459
+ });
460
+
461
+ expect(ws.request).toHaveBeenNthCalledWith(
462
+ 1,
463
+ 'thread/resume',
464
+ expect.objectContaining({
465
+ approvalPolicy: 'never',
466
+ })
467
+ );
468
+ expect(ws.request).toHaveBeenNthCalledWith(
469
+ 2,
470
+ 'turn/start',
471
+ expect.objectContaining({
472
+ approvalPolicy: 'never',
473
+ })
474
+ );
475
+ });
476
+
477
+ it('resumeThread() retries with legacy payload when modern resume params are rejected', async () => {
478
+ const ws = createWsMock();
479
+ ws.request
480
+ .mockRejectedValueOnce(new Error('unknown field `experimentalRawEvents`'))
481
+ .mockResolvedValueOnce({});
482
+
483
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
484
+ await expect(client.resumeThread('thr_resume')).resolves.toBeUndefined();
485
+
486
+ expect(ws.request).toHaveBeenNthCalledWith(
487
+ 1,
488
+ 'thread/resume',
489
+ expect.objectContaining({
490
+ threadId: 'thr_resume',
491
+ experimentalRawEvents: true,
492
+ approvalPolicy: 'untrusted',
493
+ })
494
+ );
495
+ expect(ws.request).toHaveBeenNthCalledWith(
496
+ 2,
497
+ 'thread/resume',
498
+ expect.objectContaining({
499
+ threadId: 'thr_resume',
500
+ approvalPolicy: 'on-request',
501
+ developerInstructions: null,
502
+ })
503
+ );
504
+
505
+ const legacyPayload = ws.request.mock.calls[1]?.[1] as Record<string, unknown>;
506
+ expect(legacyPayload).not.toHaveProperty('experimentalRawEvents');
507
+ });
508
+
509
+ it('resumeThread() keeps never approval policy in legacy retry when explicitly requested', async () => {
510
+ const ws = createWsMock();
511
+ ws.request
512
+ .mockRejectedValueOnce(new Error('unknown field `experimentalRawEvents`'))
513
+ .mockResolvedValueOnce({});
514
+
515
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
516
+ await expect(
517
+ client.resumeThread('thr_resume_never', { approvalPolicy: 'never' })
518
+ ).resolves.toBeUndefined();
519
+
520
+ expect(ws.request).toHaveBeenNthCalledWith(
521
+ 1,
522
+ 'thread/resume',
523
+ expect.objectContaining({
524
+ threadId: 'thr_resume_never',
525
+ approvalPolicy: 'never',
526
+ })
527
+ );
528
+ expect(ws.request).toHaveBeenNthCalledWith(
529
+ 2,
530
+ 'thread/resume',
531
+ expect.objectContaining({
532
+ threadId: 'thr_resume_never',
533
+ approvalPolicy: 'never',
534
+ })
535
+ );
536
+ });
537
+
538
+ it('sendChatMessage() forwards mention and local-image attachments to turn/start input', async () => {
539
+ const ws = createWsMock();
540
+ ws.request
541
+ .mockResolvedValueOnce({}) // thread/resume
542
+ .mockResolvedValueOnce({ turn: { id: 'turn_mentions' } }) // turn/start
543
+ .mockResolvedValueOnce({
544
+ thread: {
545
+ id: 'thr_mentions',
546
+ preview: 'done',
547
+ createdAt: 1700000000,
548
+ updatedAt: 1700000002,
549
+ status: { type: 'idle' },
550
+ turns: [
551
+ {
552
+ id: 'turn_mentions',
553
+ items: [
554
+ {
555
+ type: 'userMessage',
556
+ id: 'u_mentions',
557
+ content: [{ type: 'text', text: 'review these files' }],
558
+ },
559
+ ],
560
+ },
561
+ ],
562
+ },
563
+ });
564
+
565
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
566
+ await client.sendChatMessage('thr_mentions', {
567
+ content: 'review these files',
568
+ mentions: [
569
+ { path: 'apps/mobile/src/screens/MainScreen.tsx' },
570
+ { path: 'apps/mobile/src/api/client.ts', name: 'client.ts' },
571
+ ],
572
+ localImages: [{ path: '.clawdex-mobile-attachments/example.png' }],
573
+ });
574
+
575
+ expect(ws.request).toHaveBeenNthCalledWith(
576
+ 2,
577
+ 'turn/start',
578
+ expect.objectContaining({
579
+ input: expect.arrayContaining([
580
+ expect.objectContaining({
581
+ type: 'text',
582
+ text: 'review these files',
583
+ }),
584
+ expect.objectContaining({
585
+ type: 'mention',
586
+ path: 'apps/mobile/src/screens/MainScreen.tsx',
587
+ name: 'MainScreen.tsx',
588
+ }),
589
+ expect.objectContaining({
590
+ type: 'mention',
591
+ path: 'apps/mobile/src/api/client.ts',
592
+ name: 'client.ts',
593
+ }),
594
+ expect.objectContaining({
595
+ type: 'localImage',
596
+ path: '.clawdex-mobile-attachments/example.png',
597
+ }),
598
+ ]),
599
+ })
600
+ );
601
+ });
602
+
603
+ it('uploadAttachment() calls bridge/attachments/upload', async () => {
604
+ const ws = createWsMock();
605
+ ws.request.mockResolvedValue({
606
+ path: '.clawdex-mobile-attachments/file.txt',
607
+ fileName: 'file.txt',
608
+ mimeType: 'text/plain',
609
+ sizeBytes: 10,
610
+ kind: 'file',
611
+ });
612
+
613
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
614
+ const uploaded = await client.uploadAttachment({
615
+ dataBase64: 'aGVsbG8=',
616
+ fileName: 'file.txt',
617
+ mimeType: 'text/plain',
618
+ kind: 'file',
619
+ });
620
+
621
+ expect(ws.request).toHaveBeenCalledWith('bridge/attachments/upload', {
622
+ dataBase64: 'aGVsbG8=',
623
+ fileName: 'file.txt',
624
+ mimeType: 'text/plain',
625
+ kind: 'file',
626
+ });
627
+ expect(uploaded.path).toBe('.clawdex-mobile-attachments/file.txt');
628
+ });
629
+
630
+ it('interruptTurn() calls turn/interrupt with thread and turn id', async () => {
631
+ const ws = createWsMock();
632
+ ws.request.mockResolvedValue({});
633
+
634
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
635
+ await client.interruptTurn('thr_stop', 'turn_stop');
636
+
637
+ expect(ws.request).toHaveBeenCalledWith('turn/interrupt', {
638
+ threadId: 'thr_stop',
639
+ turnId: 'turn_stop',
640
+ });
641
+ });
642
+
643
+ it('interruptLatestTurn() resolves and interrupts the latest active turn', async () => {
644
+ const ws = createWsMock();
645
+ ws.request
646
+ .mockResolvedValueOnce({
647
+ thread: {
648
+ id: 'thr_active',
649
+ preview: 'working',
650
+ createdAt: 1700000000,
651
+ updatedAt: 1700000001,
652
+ status: { type: 'active' },
653
+ turns: [
654
+ {
655
+ id: 'turn_done',
656
+ status: 'completed',
657
+ items: [],
658
+ },
659
+ {
660
+ id: 'turn_live',
661
+ status: 'inProgress',
662
+ items: [],
663
+ },
664
+ ],
665
+ },
666
+ })
667
+ .mockResolvedValueOnce({});
668
+
669
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
670
+ const turnId = await client.interruptLatestTurn('thr_active');
671
+
672
+ expect(turnId).toBe('turn_live');
673
+ expect(ws.request).toHaveBeenNthCalledWith(1, 'thread/read', {
674
+ threadId: 'thr_active',
675
+ includeTurns: true,
676
+ });
677
+ expect(ws.request).toHaveBeenNthCalledWith(2, 'turn/interrupt', {
678
+ threadId: 'thr_active',
679
+ turnId: 'turn_live',
680
+ });
681
+ });
682
+
683
+ it('interruptLatestTurn() returns null when there is no active turn', async () => {
684
+ const ws = createWsMock();
685
+ ws.request.mockResolvedValueOnce({
686
+ thread: {
687
+ id: 'thr_idle',
688
+ preview: 'done',
689
+ createdAt: 1700000000,
690
+ updatedAt: 1700000001,
691
+ status: { type: 'idle' },
692
+ turns: [
693
+ {
694
+ id: 'turn_done',
695
+ status: 'completed',
696
+ items: [],
697
+ },
698
+ ],
699
+ },
700
+ });
701
+
702
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
703
+ const turnId = await client.interruptLatestTurn('thr_idle');
704
+
705
+ expect(turnId).toBeNull();
706
+ expect(ws.request).toHaveBeenCalledTimes(1);
707
+ expect(ws.request).toHaveBeenNthCalledWith(1, 'thread/read', {
708
+ threadId: 'thr_idle',
709
+ includeTurns: true,
710
+ });
711
+ });
712
+
713
+ it('sendChatMessage() sends structured collaborationMode for plan mode', async () => {
714
+ const ws = createWsMock();
715
+ ws.request
716
+ .mockResolvedValueOnce({}) // thread/resume
717
+ .mockResolvedValueOnce({ turn: { id: 'turn_plan' } }) // turn/start
718
+ .mockResolvedValueOnce({
719
+ thread: {
720
+ id: 'thr_plan',
721
+ preview: 'done',
722
+ createdAt: 1700000000,
723
+ updatedAt: 1700000002,
724
+ status: { type: 'idle' },
725
+ turns: [
726
+ {
727
+ id: 'turn_plan',
728
+ items: [
729
+ {
730
+ type: 'userMessage',
731
+ id: 'u_plan',
732
+ content: [{ type: 'text', text: 'hello' }],
733
+ },
734
+ ],
735
+ },
736
+ ],
737
+ },
738
+ });
739
+
740
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
741
+ await client.sendChatMessage('thr_plan', {
742
+ content: 'hello',
743
+ model: 'gpt-5.3-codex',
744
+ effort: 'high',
745
+ collaborationMode: 'plan',
746
+ });
747
+
748
+ expect(ws.request).toHaveBeenNthCalledWith(
749
+ 2,
750
+ 'turn/start',
751
+ expect.objectContaining({
752
+ model: 'gpt-5.3-codex',
753
+ effort: 'high',
754
+ collaborationMode: {
755
+ mode: 'plan',
756
+ settings: {
757
+ model: 'gpt-5.3-codex',
758
+ reasoning_effort: 'high',
759
+ developer_instructions: null,
760
+ },
761
+ },
762
+ })
763
+ );
764
+ });
765
+
766
+ it('sendChatMessage() resolves default model before plan mode turn when model is unset', async () => {
767
+ const ws = createWsMock();
768
+ ws.request
769
+ .mockResolvedValueOnce({
770
+ data: [
771
+ {
772
+ id: 'gpt-5.3-codex',
773
+ displayName: 'GPT-5.3 Codex',
774
+ isDefault: true,
775
+ },
776
+ ],
777
+ }) // model/list fallback
778
+ .mockResolvedValueOnce({}) // thread/resume
779
+ .mockResolvedValueOnce({ turn: { id: 'turn_plan_fallback' } }) // turn/start
780
+ .mockResolvedValueOnce({
781
+ thread: {
782
+ id: 'thr_plan_fallback',
783
+ preview: 'done',
784
+ createdAt: 1700000000,
785
+ updatedAt: 1700000002,
786
+ status: { type: 'idle' },
787
+ turns: [
788
+ {
789
+ id: 'turn_plan_fallback',
790
+ items: [
791
+ {
792
+ type: 'userMessage',
793
+ id: 'u_plan_fallback',
794
+ content: [{ type: 'text', text: 'hello' }],
795
+ },
796
+ ],
797
+ },
798
+ ],
799
+ },
800
+ });
801
+
802
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
803
+ await client.sendChatMessage('thr_plan_fallback', {
804
+ content: 'hello',
805
+ collaborationMode: 'plan',
806
+ });
807
+
808
+ expect(ws.request).toHaveBeenNthCalledWith(
809
+ 1,
810
+ 'model/list',
811
+ expect.objectContaining({
812
+ includeHidden: false,
813
+ })
814
+ );
815
+ expect(ws.request).toHaveBeenNthCalledWith(
816
+ 3,
817
+ 'turn/start',
818
+ expect.objectContaining({
819
+ model: 'gpt-5.3-codex',
820
+ collaborationMode: {
821
+ mode: 'plan',
822
+ settings: {
823
+ model: 'gpt-5.3-codex',
824
+ reasoning_effort: null,
825
+ developer_instructions: null,
826
+ },
827
+ },
828
+ })
829
+ );
830
+ });
831
+
832
+ it('listModels() maps model/list response', async () => {
833
+ const ws = createWsMock();
834
+ ws.request.mockResolvedValue({
835
+ data: [
836
+ {
837
+ id: 'gpt-5.3-codex',
838
+ displayName: 'GPT-5.3 Codex',
839
+ description: 'Default coding model',
840
+ hidden: false,
841
+ supportsPersonality: true,
842
+ isDefault: true,
843
+ defaultReasoningEffort: 'medium',
844
+ supportedReasoningEfforts: [
845
+ { reasoningEffort: 'low', description: 'Lower latency' },
846
+ { reasoningEffort: 'medium', description: 'Balanced' },
847
+ { reasoningEffort: 'high', description: 'Higher depth' },
848
+ ],
849
+ },
850
+ ],
851
+ });
852
+
853
+ const client = new HostBridgeApiClient({ ws: ws as unknown as HostBridgeWsClient });
854
+ const models = await client.listModels();
855
+
856
+ expect(ws.request).toHaveBeenCalledWith(
857
+ 'model/list',
858
+ expect.objectContaining({
859
+ includeHidden: false,
860
+ })
861
+ );
862
+ expect(models).toHaveLength(1);
863
+ expect(models[0].id).toBe('gpt-5.3-codex');
864
+ expect(models[0].isDefault).toBe(true);
865
+ expect(models[0].defaultReasoningEffort).toBe('medium');
866
+ expect(models[0].reasoningEffort?.map((option) => option.effort)).toEqual([
867
+ 'low',
868
+ 'medium',
869
+ 'high',
870
+ ]);
871
+ });
872
+ });