@lobehub/lobehub 2.0.0-next.294 → 2.0.0-next.296

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 (249) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/apps/desktop/src/main/__mocks__/node-mac-permissions.ts +0 -1
  3. package/apps/desktop/src/main/__mocks__/setup.ts +0 -1
  4. package/apps/desktop/src/main/controllers/__tests__/SystemCtr.test.ts +1 -4
  5. package/apps/desktop/tsconfig.json +4 -10
  6. package/changelog/v1.json +18 -0
  7. package/e2e/scripts/setup.ts +45 -32
  8. package/locales/en-US/plugin.json +4 -0
  9. package/locales/zh-CN/plugin.json +4 -0
  10. package/package.json +1 -1
  11. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +5 -5
  12. package/packages/agent-runtime/src/utils/stepContextComputer.test.ts +5 -5
  13. package/packages/builtin-tool-gtd/src/client/Inspector/index.ts +0 -4
  14. package/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +1 -1
  15. package/packages/builtin-tool-gtd/src/client/Render/TodoList/index.tsx +39 -10
  16. package/packages/builtin-tool-gtd/src/client/Render/index.ts +0 -2
  17. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/TodoItemRow.tsx +26 -12
  18. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/actions.ts +5 -5
  19. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/store.test.ts +14 -8
  20. package/packages/builtin-tool-gtd/src/executor/index.test.ts +48 -227
  21. package/packages/builtin-tool-gtd/src/executor/index.ts +15 -158
  22. package/packages/builtin-tool-gtd/src/manifest.ts +12 -42
  23. package/packages/builtin-tool-gtd/src/systemRole.ts +14 -8
  24. package/packages/builtin-tool-gtd/src/types.ts +47 -41
  25. package/packages/builtin-tool-memory/package.json +8 -0
  26. package/packages/builtin-tool-memory/src/client/Inspector/AddContextMemory/index.tsx +60 -0
  27. package/packages/builtin-tool-memory/src/client/Inspector/AddExperienceMemory/index.tsx +60 -0
  28. package/packages/builtin-tool-memory/src/client/Inspector/AddIdentityMemory/index.tsx +60 -0
  29. package/packages/builtin-tool-memory/src/client/Inspector/AddPreferenceMemory/index.tsx +60 -0
  30. package/packages/builtin-tool-memory/src/client/Inspector/RemoveIdentityMemory/index.tsx +60 -0
  31. package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +67 -0
  32. package/packages/builtin-tool-memory/src/client/Inspector/UpdateIdentityMemory/index.tsx +60 -0
  33. package/packages/builtin-tool-memory/src/client/Inspector/index.ts +35 -0
  34. package/packages/builtin-tool-memory/src/client/Intervention/AddExperienceMemory/index.tsx +17 -0
  35. package/packages/builtin-tool-memory/src/client/Intervention/index.ts +13 -0
  36. package/packages/builtin-tool-memory/src/client/Render/AddExperienceMemory/index.tsx +17 -0
  37. package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +217 -0
  38. package/packages/builtin-tool-memory/src/client/Render/index.ts +15 -0
  39. package/packages/builtin-tool-memory/src/client/Streaming/AddExperienceMemory/index.tsx +17 -0
  40. package/packages/builtin-tool-memory/src/client/Streaming/index.ts +18 -0
  41. package/packages/builtin-tool-memory/src/client/components/ExperienceMemoryCard.tsx +231 -0
  42. package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
  43. package/packages/builtin-tool-memory/src/client/index.ts +27 -0
  44. package/packages/builtin-tool-memory/src/executor/index.ts +9 -1
  45. package/packages/builtin-tool-memory/src/types.ts +61 -0
  46. package/packages/context-engine/src/providers/GTDTodoInjector.ts +15 -7
  47. package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +4 -0
  48. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +1 -0
  49. package/packages/database/src/models/__tests__/knowledgeBase.test.ts +1 -1
  50. package/packages/database/src/repositories/knowledge/index.ts +1 -4
  51. package/packages/prompts/src/prompts/gtd/index.test.ts +32 -16
  52. package/packages/prompts/src/prompts/gtd/index.ts +9 -5
  53. package/packages/types/src/discover/assistants.ts +2 -2
  54. package/packages/types/src/stepContext.ts +4 -1
  55. package/scripts/migrate-spa-navigation.ts +129 -0
  56. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-topics/route.ts +112 -109
  57. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-user-topics/route.ts +125 -113
  58. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-users/route.ts +74 -65
  59. package/src/app/[variants]/(auth)/auth-error/page.tsx +1 -1
  60. package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +1 -1
  61. package/src/app/[variants]/(auth)/next-auth/error/AuthErrorPage.tsx +1 -1
  62. package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +1 -1
  63. package/src/app/[variants]/(auth)/oauth/callback/error/page.tsx +1 -1
  64. package/src/app/[variants]/(auth)/oauth/callback/success/page.tsx +1 -1
  65. package/src/app/[variants]/(auth)/oauth/consent/[uid]/page.tsx +1 -1
  66. package/src/app/[variants]/(auth)/reset-password/layout.tsx +1 -1
  67. package/src/app/[variants]/(auth)/reset-password/page.tsx +2 -2
  68. package/src/app/[variants]/(auth)/signin/layout.tsx +1 -1
  69. package/src/app/[variants]/(auth)/signin/useSignIn.ts +1 -1
  70. package/src/app/[variants]/(auth)/signup/[[...signup]]/BetterAuthSignUpForm.tsx +2 -2
  71. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -1
  72. package/src/app/[variants]/(auth)/signup/[[...signup]]/useSignUp.tsx +1 -1
  73. package/src/app/[variants]/(auth)/verify-email/layout.tsx +1 -1
  74. package/src/app/[variants]/(auth)/verify-email/page.tsx +2 -2
  75. package/src/app/[variants]/(main)/_layout/index.tsx +1 -1
  76. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/CronTopicGroup.tsx +1 -1
  77. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/AddTopicButon.tsx +1 -1
  78. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/Nav.tsx +1 -1
  79. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
  80. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
  81. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useTopicNavigation.ts +1 -1
  82. package/src/app/[variants]/(main)/agent/features/TelemetryNotification.tsx +2 -3
  83. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Nav.tsx +9 -9
  84. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -3
  85. package/src/app/[variants]/(main)/community/(detail)/features/MakedownRender.tsx +1 -2
  86. package/src/app/[variants]/(main)/community/(detail)/features/ShareButton.tsx +2 -3
  87. package/src/app/[variants]/(main)/community/(detail)/features/Toc/Heading.tsx +2 -3
  88. package/src/app/[variants]/(main)/community/(detail)/mcp/features/Details/Versions/index.tsx +2 -2
  89. package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Nav.tsx +12 -11
  90. package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Parameter/ParameterItem.tsx +2 -3
  91. package/src/app/[variants]/(main)/community/(detail)/provider/features/Details/Nav.tsx +11 -10
  92. package/src/app/[variants]/(main)/community/(detail)/provider/features/Header.tsx +10 -9
  93. package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +1 -1
  94. package/src/app/[variants]/(main)/community/(list)/assistant/features/Category/useCategory.tsx +1 -1
  95. package/src/app/[variants]/(main)/community/(list)/features/SortButton/index.tsx +2 -3
  96. package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +1 -1
  97. package/src/app/[variants]/(main)/community/features/CreateButton/Inner.tsx +1 -1
  98. package/src/app/[variants]/(main)/community/features/CreateButton/index.tsx +1 -1
  99. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -2
  100. package/src/app/[variants]/(main)/community/features/Title.tsx +5 -5
  101. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Nav.tsx +1 -1
  102. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
  103. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
  104. package/src/app/[variants]/(main)/group/features/Conversation/Header/ShareButton/index.tsx +1 -1
  105. package/src/app/[variants]/(main)/group/features/TelemetryNotification.tsx +2 -3
  106. package/src/app/[variants]/(main)/home/_layout/Body/Agent/AllAgentsDrawer/index.tsx +1 -1
  107. package/src/app/[variants]/(main)/hooks/useActiveTabKey.ts +6 -11
  108. package/src/app/[variants]/(main)/image/NotSupportClient.tsx +4 -3
  109. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ImageUpload.tsx +1 -1
  110. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/ImageManageModal.tsx +1 -1
  111. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/index.tsx +1 -1
  112. package/src/app/[variants]/(main)/memory/(home)/features/RoleTagCloud/index.tsx +1 -1
  113. package/src/app/[variants]/(main)/memory/_layout/Sidebar/Header/Nav.tsx +1 -1
  114. package/src/app/[variants]/(main)/memory/features/SourceLink.tsx +1 -1
  115. package/src/app/[variants]/(main)/page/_layout/Body/AllPagesDrawer/index.tsx +1 -1
  116. package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +4 -2
  117. package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +30 -35
  118. package/src/app/[variants]/(main)/resource/library/_layout/Header/index.tsx +9 -11
  119. package/src/app/[variants]/(main)/settings/about/features/ItemCard.tsx +2 -3
  120. package/src/app/[variants]/(main)/settings/about/features/ItemLink.tsx +2 -3
  121. package/src/app/[variants]/(main)/settings/about/features/Version.tsx +6 -7
  122. package/src/app/[variants]/(main)/settings/features/SettingsContent.tsx +1 -1
  123. package/src/app/[variants]/(main)/settings/features/UpgradeAlert.tsx +4 -4
  124. package/src/app/[variants]/(main)/settings/provider/(list)/Footer.tsx +2 -2
  125. package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +1 -1
  126. package/src/app/[variants]/(main)/settings/provider/detail/ollama/CheckError.tsx +1 -1
  127. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +12 -6
  128. package/src/app/[variants]/(main)/settings/security/index.tsx +1 -1
  129. package/src/app/[variants]/(main)/settings/stats/features/overview/ShareButton/ShareModal.tsx +1 -1
  130. package/src/app/[variants]/(main)/settings/stats/features/rankings/AssistantsRank.tsx +1 -1
  131. package/src/app/[variants]/(main)/settings/stats/features/rankings/TopicsRank.tsx +1 -1
  132. package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
  133. package/src/app/[variants]/(mobile)/chat/settings/features/AgentInfoDescription/index.tsx +1 -1
  134. package/src/app/[variants]/(mobile)/chat/settings/features/SettingButton.tsx +1 -1
  135. package/src/app/[variants]/(mobile)/router/index.tsx +1 -1
  136. package/src/app/[variants]/page.tsx +1 -1
  137. package/src/app/[variants]/router/index.tsx +1 -1
  138. package/src/components/404/index.tsx +4 -4
  139. package/src/components/Analytics/index.tsx +1 -1
  140. package/src/components/BrandWatermark/index.tsx +4 -4
  141. package/src/components/Branding/ProductLogo/Custom.tsx +1 -1
  142. package/src/components/Error/index.tsx +3 -4
  143. package/src/components/GoBack/index.tsx +2 -2
  144. package/src/components/LabsModal/LabCard.tsx +1 -1
  145. package/src/components/Link.tsx +25 -5
  146. package/src/components/OllamaSetupGuide/index.tsx +5 -4
  147. package/src/components/WebFavicon/index.tsx +1 -1
  148. package/src/components/client/ClientResponsiveContent/index.tsx +1 -1
  149. package/src/components/client/ClientResponsiveLayout.tsx +1 -1
  150. package/src/components/mdx/Image.tsx +1 -1
  151. package/src/components/mdx/Link.tsx +26 -9
  152. package/src/features/AlertBanner/CloudBanner.tsx +2 -3
  153. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +8 -7
  154. package/src/features/ChatInput/ActionBar/Params/Controls.tsx +1 -3
  155. package/src/features/ChatInput/ActionBar/Token/index.tsx +1 -1
  156. package/src/features/ChatInput/Mobile/index.tsx +1 -1
  157. package/src/features/Conversation/ChatItem/components/MessageContent/index.tsx +1 -1
  158. package/src/features/Conversation/Error/OllamaBizError/index.tsx +1 -1
  159. package/src/features/Conversation/Error/OllamaSetupGuide/Desktop.tsx +1 -2
  160. package/src/features/Conversation/Error/index.tsx +1 -1
  161. package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/Settings.tsx +1 -1
  162. package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/index.tsx +11 -17
  163. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/LoadingPlaceholder/index.tsx +13 -3
  164. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/CustomRender.tsx +43 -0
  165. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/FallbacktArgumentRender.tsx +59 -0
  166. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/index.tsx +46 -0
  167. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/index.tsx +13 -19
  168. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +18 -18
  169. package/src/features/Conversation/Messages/AssistantGroup/index.tsx +1 -1
  170. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +11 -10
  171. package/src/features/Conversation/Messages/components/SearchGrounding.tsx +1 -1
  172. package/src/features/Conversation/TodoProgress/index.tsx +56 -23
  173. package/src/features/DataImporter/Error.tsx +3 -3
  174. package/src/features/DevPanel/CacheViewer/cacheProvider.tsx +2 -1
  175. package/src/features/DevPanel/MetadataViewer/Og.tsx +1 -1
  176. package/src/features/DevPanel/features/FloatPanel.tsx +1 -1
  177. package/src/features/DevPanel/features/Table/TooltipContent.tsx +3 -4
  178. package/src/features/DevPanel/index.tsx +1 -1
  179. package/src/features/EditorCanvas/InlineToolbar.tsx +1 -6
  180. package/src/features/FileViewer/NotSupport/index.tsx +2 -3
  181. package/src/features/Follow/index.tsx +8 -9
  182. package/src/features/LibraryModal/AddFilesToKnowledgeBase/SelectForm.tsx +2 -2
  183. package/src/features/MCP/Scores.tsx +1 -1
  184. package/src/features/MCPPluginDetail/Nav.tsx +8 -8
  185. package/src/features/MCPPluginDetail/Overview/TagList.tsx +1 -1
  186. package/src/features/MobileTabBar/index.tsx +2 -1
  187. package/src/features/OllamaSetupGuide/Desktop.tsx +1 -2
  188. package/src/features/PWAInstall/Install.tsx +1 -1
  189. package/src/features/PWAInstall/index.tsx +1 -1
  190. package/src/features/PluginStore/McpList/index.tsx +1 -1
  191. package/src/features/PluginStore/PluginList/Detail/Header.tsx +6 -6
  192. package/src/features/PluginsUI/Render/DefaultType/index.tsx +1 -1
  193. package/src/features/PluginsUI/Render/MCPType/index.tsx +1 -1
  194. package/src/features/Portal/Artifacts/Body/Renderer/index.tsx +1 -1
  195. package/src/features/ResourceManager/components/ChunkDrawer/index.tsx +1 -1
  196. package/src/features/ResourceManager/components/Explorer/Header/index.tsx +57 -4
  197. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +6 -4
  198. package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +26 -26
  199. package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +16 -5
  200. package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +147 -149
  201. package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +5 -4
  202. package/src/features/ResourceManager/index.tsx +1 -1
  203. package/src/features/Setting/Footer.tsx +4 -5
  204. package/src/features/User/UserPanel/PanelContent.tsx +1 -1
  205. package/src/hooks/useActiveTabKey.ts +6 -4
  206. package/src/hooks/useIsSingleMode.test.ts +10 -24
  207. package/src/hooks/useIsSingleMode.ts +4 -2
  208. package/src/hooks/useIsSubSlug.ts +2 -1
  209. package/src/hooks/useQuery.ts +5 -5
  210. package/src/layout/GlobalProvider/AppTheme.tsx +2 -2
  211. package/src/layout/GlobalProvider/StyleRegistry.tsx +1 -1
  212. package/src/layout/GlobalProvider/useUserStateRedirect.ts +13 -25
  213. package/src/libs/next/Image.tsx +13 -0
  214. package/src/libs/next/Link.tsx +13 -0
  215. package/src/libs/next/dynamic.tsx +13 -0
  216. package/src/libs/next/index.ts +22 -0
  217. package/src/libs/next/navigation.ts +22 -0
  218. package/src/libs/router/Link.tsx +30 -0
  219. package/src/libs/router/index.ts +18 -0
  220. package/src/libs/router/navigation.ts +72 -0
  221. package/src/locales/default/plugin.ts +1 -0
  222. package/src/server/modules/AgentRuntime/AgentStateManager.ts +5 -1
  223. package/src/store/chat/slices/message/selectors/dbMessage.test.ts +11 -11
  224. package/src/store/chat/slices/portal/selectors.test.ts +5 -15
  225. package/src/store/file/slices/resource/action.ts +4 -2
  226. package/src/store/page/index.ts +1 -1
  227. package/src/store/page/slices/crud/index.ts +1 -1
  228. package/src/tools/inspectors.ts +2 -0
  229. package/src/tools/interventions.ts +2 -0
  230. package/src/tools/renders.ts +3 -1
  231. package/src/tools/streamings.ts +2 -0
  232. package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +0 -52
  233. package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +0 -52
  234. package/src/app/[variants]/(main)/hooks/usePathname.ts +0 -10
  235. package/src/app/[variants]/(main)/hooks/useQuery.ts +0 -12
  236. package/src/app/[variants]/(main)/hooks/useRouter.ts +0 -22
  237. package/src/app/[variants]/(main)/hooks/useSearchParams.ts +0 -11
  238. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/CustomRender.tsx +0 -113
  239. package/src/features/Conversation/Messages/Tool/Tool/Render.tsx +0 -47
  240. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/AbortResponse.tsx +0 -0
  241. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Arguments/index.tsx +0 -0
  242. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/ErrorResponse.tsx +0 -0
  243. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ApprovalActions.tsx +0 -0
  244. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/Fallback.tsx +0 -0
  245. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/KeyValueEditor.tsx +0 -0
  246. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ModeSelector.tsx +0 -0
  247. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/index.tsx +0 -0
  248. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/PluginSettings.tsx +0 -0
  249. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/RejectedResponse.tsx +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.296](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.295...v2.0.0-next.296)
6
+
7
+ <sup>Released on **2026-01-16**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Improve todo list.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Improve todo list, closes [#11533](https://github.com/lobehub/lobe-chat/issues/11533) ([a4b71e9](https://github.com/lobehub/lobe-chat/commit/a4b71e9))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.295](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.294...v2.0.0-next.295)
31
+
32
+ <sup>Released on **2026-01-15**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Migrate Next.js navigation APIs to React Router for SPA.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Code refactoring
44
+
45
+ - **misc**: Migrate Next.js navigation APIs to React Router for SPA, closes [#11394](https://github.com/lobehub/lobe-chat/issues/11394) ([2253d46](https://github.com/lobehub/lobe-chat/commit/2253d46))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ## [Version 2.0.0-next.294](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.293...v2.0.0-next.294)
6
56
 
7
57
  <sup>Released on **2026-01-15**</sup>
@@ -2,7 +2,6 @@
2
2
  * Mock for node-mac-permissions native module
3
3
  * Used in tests since the native module only works on macOS
4
4
  */
5
-
6
5
  import { vi } from 'vitest';
7
6
 
8
7
  export const askForAccessibilityAccess = vi.fn(() => undefined);
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Vitest setup file for mocking native modules
3
3
  */
4
-
5
4
  import { vi } from 'vitest';
6
5
 
7
6
  // Mock node-mac-permissions before any imports
@@ -4,10 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
4
  import type { App } from '@/core/App';
5
5
  import type { IpcContext } from '@/utils/ipc';
6
6
  import { IpcHandler } from '@/utils/ipc/base';
7
- import {
8
- __resetMacPermissionsModuleCache,
9
- __setMacPermissionsModule,
10
- } from '@/utils/permissions';
7
+ import { __resetMacPermissionsModuleCache, __setMacPermissionsModule } from '@/utils/permissions';
11
8
 
12
9
  import SystemController from '../SystemCtr';
13
10
 
@@ -15,15 +15,9 @@
15
15
  "moduleResolution": "bundler",
16
16
  "resolveJsonModule": true,
17
17
  "paths": {
18
- "@/*": [
19
- "./src/main/*"
20
- ],
21
- "~common/*": [
22
- "./src/common/*"
23
- ],
24
- "*": [
25
- "./*"
26
- ]
18
+ "@/*": ["./src/main/*"],
19
+ "~common/*": ["./src/common/*"],
20
+ "*": ["./*"]
27
21
  }
28
22
  },
29
23
  "include": [
@@ -33,4 +27,4 @@
33
27
  "electron-builder.js",
34
28
  "native-deps.config.js"
35
29
  ]
36
- }
30
+ }
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Improve todo list."
6
+ ]
7
+ },
8
+ "date": "2026-01-16",
9
+ "version": "2.0.0-next.296"
10
+ },
11
+ {
12
+ "children": {
13
+ "improvements": [
14
+ "Migrate Next.js navigation APIs to React Router for SPA."
15
+ ]
16
+ },
17
+ "date": "2026-01-15",
18
+ "version": "2.0.0-next.295"
19
+ },
2
20
  {
3
21
  "children": {},
4
22
  "date": "2026-01-15",
@@ -16,9 +16,7 @@
16
16
  * --port <port> Server port (default: 3006)
17
17
  * --help Show help message
18
18
  */
19
-
20
- import { type ChildProcess, spawn, spawnSync } from 'node:child_process';
21
- import { existsSync, unlinkSync, writeFileSync } from 'node:fs';
19
+ import { spawn, spawnSync } from 'node:child_process';
22
20
  import { resolve } from 'node:path';
23
21
 
24
22
  // ============================================================================
@@ -33,21 +31,27 @@ const CONFIG = {
33
31
  defaultPort: 3006,
34
32
  dockerImage: 'paradedb/paradedb:latest',
35
33
  projectRoot: resolve(__dirname, '../..'),
36
- serverTimeout: 120_000, // 2 minutes
37
-
38
- // Secrets (for e2e testing only)
39
- secrets: {
40
- betterAuthSecret: 'e2e-test-secret-key-for-better-auth-32chars!',
41
- keyVaultsSecret: 'LA7n9k3JdEcbSgml2sxfw+4TV1AzaaFU5+R176aQz4s=',
42
- },
34
+
43
35
 
44
- // S3 Mock (required even if not testing file uploads)
45
- s3Mock: {
36
+ // S3 Mock (required even if not testing file uploads)
37
+ s3Mock: {
46
38
  accessKeyId: 'e2e-mock-access-key',
47
39
  bucket: 'e2e-mock-bucket',
48
40
  endpoint: 'https://e2e-mock-s3.localhost',
49
41
  secretAccessKey: 'e2e-mock-secret-key',
42
+ },
43
+
44
+
45
+
46
+ // 2 minutes
47
+ // Secrets (for e2e testing only)
48
+ secrets: {
49
+ betterAuthSecret: 'e2e-test-secret-key-for-better-auth-32chars!',
50
+ keyVaultsSecret: 'LA7n9k3JdEcbSgml2sxfw+4TV1AzaaFU5+R176aQz4s=',
50
51
  },
52
+
53
+
54
+ serverTimeout: 120_000,
51
55
  };
52
56
 
53
57
  // ============================================================================
@@ -55,11 +59,11 @@ const CONFIG = {
55
59
  // ============================================================================
56
60
 
57
61
  const colors = {
58
- cyan: (s: string) => `\x1b[36m${s}\x1b[0m`,
59
- dim: (s: string) => `\x1b[2m${s}\x1b[0m`,
60
- green: (s: string) => `\x1b[32m${s}\x1b[0m`,
61
- red: (s: string) => `\x1b[31m${s}\x1b[0m`,
62
- yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
62
+ cyan: (s: string) => `\u001B[36m${s}\u001B[0m`,
63
+ dim: (s: string) => `\u001B[2m${s}\u001B[0m`,
64
+ green: (s: string) => `\u001B[32m${s}\u001B[0m`,
65
+ red: (s: string) => `\u001B[31m${s}\u001B[0m`,
66
+ yellow: (s: string) => `\u001B[33m${s}\u001B[0m`,
63
67
  };
64
68
 
65
69
  function log(emoji: string, message: string) {
@@ -73,12 +77,12 @@ function logStep(step: number, total: number, message: string) {
73
77
  function exec(
74
78
  command: string,
75
79
  args: string[] = [],
76
- options: { cwd?: string; silent?: boolean } = {}
80
+ options: { cwd?: string; silent?: boolean } = {},
77
81
  ) {
78
82
  const { cwd = CONFIG.projectRoot, silent = false } = options;
79
83
  const result = spawnSync(command, args, {
80
84
  cwd,
81
- encoding: 'utf-8',
85
+ encoding: 'utf8',
82
86
  shell: true,
83
87
  stdio: silent ? 'pipe' : 'inherit',
84
88
  });
@@ -88,7 +92,7 @@ function exec(
88
92
  function execAsync(
89
93
  command: string,
90
94
  args: string[] = [],
91
- env: Record<string, string> = {}
95
+ env: Record<string, string> = {},
92
96
  ): Promise<void> {
93
97
  return new Promise((resolve, reject) => {
94
98
  const child = spawn(command, args, {
@@ -111,14 +115,16 @@ function execAsync(
111
115
  }
112
116
 
113
117
  async function sleep(ms: number): Promise<void> {
114
- return new Promise((resolve) => setTimeout(resolve, ms));
118
+ return new Promise((resolve) => {
119
+ setTimeout(resolve, ms);
120
+ });
115
121
  }
116
122
 
117
123
  async function waitForCondition(
118
124
  check: () => Promise<boolean>,
119
125
  timeout: number,
120
126
  interval: number = 1000,
121
- onWait?: () => void
127
+ onWait?: () => void,
122
128
  ): Promise<boolean> {
123
129
  const startTime = Date.now();
124
130
  while (Date.now() - startTime < timeout) {
@@ -204,7 +210,7 @@ async function startPostgres(): Promise<void> {
204
210
  },
205
211
  30_000,
206
212
  2000,
207
- () => process.stdout.write('.')
213
+ () => process.stdout.write('.'),
208
214
  );
209
215
 
210
216
  console.log();
@@ -327,7 +333,7 @@ async function startServer(port: number): Promise<void> {
327
333
  () => isServerRunning(port),
328
334
  CONFIG.serverTimeout,
329
335
  2000,
330
- () => process.stdout.write('.')
336
+ () => process.stdout.write('.'),
331
337
  );
332
338
 
333
339
  console.log();
@@ -412,27 +418,34 @@ function parseArgs(): Options {
412
418
  for (let i = 0; i < args.length; i++) {
413
419
  switch (args[i]) {
414
420
  case '--help':
415
- case '-h':
421
+ case '-h': {
416
422
  options.help = true;
417
423
  break;
418
- case '--clean':
424
+ }
425
+ case '--clean': {
419
426
  options.clean = true;
420
427
  break;
421
- case '--skip-db':
428
+ }
429
+ case '--skip-db': {
422
430
  options.skipDb = true;
423
431
  break;
424
- case '--skip-migrate':
432
+ }
433
+ case '--skip-migrate': {
425
434
  options.skipMigrate = true;
426
435
  break;
427
- case '--build':
436
+ }
437
+ case '--build': {
428
438
  options.build = true;
429
439
  break;
430
- case '--start':
440
+ }
441
+ case '--start': {
431
442
  options.start = true;
432
443
  break;
433
- case '--port':
444
+ }
445
+ case '--port': {
434
446
  options.port = parseInt(args[++i], 10) || CONFIG.defaultPort;
435
447
  break;
448
+ }
436
449
  }
437
450
  }
438
451
 
@@ -526,4 +539,4 @@ ${colors.green('✅ E2E environment setup completed!')}
526
539
  }
527
540
  }
528
541
 
529
- main();
542
+ await main();
@@ -173,6 +173,10 @@
173
173
  "builtins.lobe-user-memory.apiName.removeIdentityMemory": "Delete identity memory",
174
174
  "builtins.lobe-user-memory.apiName.searchUserMemory": "Search memory",
175
175
  "builtins.lobe-user-memory.apiName.updateIdentityMemory": "Update identity memory",
176
+ "builtins.lobe-user-memory.inspector.noResults": "No results",
177
+ "builtins.lobe-user-memory.render.contexts": "Contexts",
178
+ "builtins.lobe-user-memory.render.experiences": "Experiences",
179
+ "builtins.lobe-user-memory.render.preferences": "Preferences",
176
180
  "builtins.lobe-user-memory.title": "Memory",
177
181
  "builtins.lobe-web-browsing.apiName.crawlMultiPages": "Read multiple pages",
178
182
  "builtins.lobe-web-browsing.apiName.crawlSinglePage": "Read page content",
@@ -173,6 +173,10 @@
173
173
  "builtins.lobe-user-memory.apiName.removeIdentityMemory": "删除身份记忆",
174
174
  "builtins.lobe-user-memory.apiName.searchUserMemory": "搜索记忆",
175
175
  "builtins.lobe-user-memory.apiName.updateIdentityMemory": "更新身份记忆",
176
+ "builtins.lobe-user-memory.inspector.noResults": "无结果",
177
+ "builtins.lobe-user-memory.render.contexts": "情境记忆",
178
+ "builtins.lobe-user-memory.render.experiences": "经验记忆",
179
+ "builtins.lobe-user-memory.render.preferences": "偏好记忆",
176
180
  "builtins.lobe-user-memory.title": "记忆",
177
181
  "builtins.lobe-web-browsing.apiName.crawlMultiPages": "读取多个页面内容",
178
182
  "builtins.lobe-web-browsing.apiName.crawlSinglePage": "读取页面内容",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.294",
3
+ "version": "2.0.0-next.296",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -1607,8 +1607,8 @@ describe('AgentRuntime', () => {
1607
1607
  const stepContext = {
1608
1608
  todos: {
1609
1609
  items: [
1610
- { text: 'Buy milk', completed: false },
1611
- { text: 'Call mom', completed: true },
1610
+ { text: 'Buy milk', status: 'todo' as const },
1611
+ { text: 'Call mom', status: 'completed' as const },
1612
1612
  ],
1613
1613
  updatedAt: '2024-06-01T00:00:00.000Z',
1614
1614
  },
@@ -1634,7 +1634,7 @@ describe('AgentRuntime', () => {
1634
1634
  stepContext: expect.objectContaining({
1635
1635
  todos: expect.objectContaining({
1636
1636
  items: expect.arrayContaining([
1637
- expect.objectContaining({ text: 'Buy milk', completed: false }),
1637
+ expect.objectContaining({ text: 'Buy milk', status: 'todo' }),
1638
1638
  ]),
1639
1639
  }),
1640
1640
  }),
@@ -1666,7 +1666,7 @@ describe('AgentRuntime', () => {
1666
1666
 
1667
1667
  const stepContext = {
1668
1668
  todos: {
1669
- items: [{ text: 'Task 1', completed: false }],
1669
+ items: [{ text: 'Task 1', status: 'todo' as const }],
1670
1670
  updatedAt: '2024-06-01T00:00:00.000Z',
1671
1671
  },
1672
1672
  };
@@ -1746,7 +1746,7 @@ describe('AgentRuntime', () => {
1746
1746
 
1747
1747
  const stepContext = {
1748
1748
  todos: {
1749
- items: [{ text: 'Batch task', completed: false }],
1749
+ items: [{ text: 'Batch task', status: 'todo' as const }],
1750
1750
  updatedAt: '2024-06-01T00:00:00.000Z',
1751
1751
  },
1752
1752
  };
@@ -7,8 +7,8 @@ describe('computeStepContext', () => {
7
7
  it('should include todos when provided', () => {
8
8
  const todos = {
9
9
  items: [
10
- { text: 'Buy milk', completed: false },
11
- { text: 'Call mom', completed: true },
10
+ { text: 'Buy milk', status: 'todo' as const },
11
+ { text: 'Call mom', status: 'completed' as const },
12
12
  ],
13
13
  updatedAt: '2024-06-01T00:00:00.000Z',
14
14
  };
@@ -18,9 +18,9 @@ describe('computeStepContext', () => {
18
18
  expect(result.todos).toBeDefined();
19
19
  expect(result.todos?.items).toHaveLength(2);
20
20
  expect(result.todos?.items[0].text).toBe('Buy milk');
21
- expect(result.todos?.items[0].completed).toBe(false);
21
+ expect(result.todos?.items[0].status).toBe('todo');
22
22
  expect(result.todos?.items[1].text).toBe('Call mom');
23
- expect(result.todos?.items[1].completed).toBe(true);
23
+ expect(result.todos?.items[1].status).toBe('completed');
24
24
  });
25
25
 
26
26
  it('should not include todos key when undefined', () => {
@@ -42,7 +42,7 @@ describe('computeStepContext', () => {
42
42
  // This should compile and work - object param allows future extensions
43
43
  const result = computeStepContext({
44
44
  todos: {
45
- items: [{ text: 'Task', completed: false }],
45
+ items: [{ text: 'Task', status: 'todo' as const }],
46
46
  updatedAt: '2024-01-01T00:00:00.000Z',
47
47
  },
48
48
  });
@@ -2,12 +2,10 @@ import { type BuiltinInspector } from '@lobechat/types';
2
2
 
3
3
  import { GTDApiName } from '../../types';
4
4
  import { ClearTodosInspector } from './ClearTodos';
5
- import { CompleteTodosInspector } from './CompleteTodos';
6
5
  import { CreatePlanInspector } from './CreatePlan';
7
6
  import { CreateTodosInspector } from './CreateTodos';
8
7
  import { ExecTaskInspector } from './ExecTask';
9
8
  import { ExecTasksInspector } from './ExecTasks';
10
- import { RemoveTodosInspector } from './RemoveTodos';
11
9
  import { UpdatePlanInspector } from './UpdatePlan';
12
10
  import { UpdateTodosInspector } from './UpdateTodos';
13
11
 
@@ -19,12 +17,10 @@ import { UpdateTodosInspector } from './UpdateTodos';
19
17
  */
20
18
  export const GTDInspectors: Record<string, BuiltinInspector> = {
21
19
  [GTDApiName.clearTodos]: ClearTodosInspector as BuiltinInspector,
22
- [GTDApiName.completeTodos]: CompleteTodosInspector as BuiltinInspector,
23
20
  [GTDApiName.createPlan]: CreatePlanInspector as BuiltinInspector,
24
21
  [GTDApiName.createTodos]: CreateTodosInspector as BuiltinInspector,
25
22
  [GTDApiName.execTask]: ExecTaskInspector as BuiltinInspector,
26
23
  [GTDApiName.execTasks]: ExecTasksInspector as BuiltinInspector,
27
- [GTDApiName.removeTodos]: RemoveTodosInspector as BuiltinInspector,
28
24
  [GTDApiName.updatePlan]: UpdatePlanInspector as BuiltinInspector,
29
25
  [GTDApiName.updateTodos]: UpdateTodosInspector as BuiltinInspector,
30
26
  };
@@ -17,7 +17,7 @@ const AddTodoIntervention = memo<BuiltinInterventionProps<CreateTodosParams>>(
17
17
  // - Initial AI input: { adds: string[] } (from AI)
18
18
  // - After user edit: { items: TodoItem[] } (saved format)
19
19
  const defaultItems: TodoItem[] =
20
- args?.items || args?.adds?.map((text) => ({ completed: false, text })) || [];
20
+ args?.items || args?.adds?.map((text) => ({ status: 'todo', text })) || [];
21
21
 
22
22
  const handleSave = useCallback(
23
23
  async (items: TodoItem[]) => {
@@ -1,11 +1,12 @@
1
1
  'use client';
2
2
 
3
3
  import { type BuiltinRenderProps } from '@lobechat/types';
4
- import { Block, Checkbox } from '@lobehub/ui';
5
- import { createStaticStyles, cssVar } from 'antd-style';
4
+ import { Block, Checkbox, Icon } from '@lobehub/ui';
5
+ import { createStaticStyles, cssVar, cx } from 'antd-style';
6
+ import { CircleArrowRight } from 'lucide-react';
6
7
  import { memo } from 'react';
7
8
 
8
- import type { TodoItem, TodoList as TodoListType } from '../../../types';
9
+ import type { TodoItem, TodoList as TodoListType, TodoStatus } from '../../../types';
9
10
 
10
11
  export interface TodoListRenderState {
11
12
  todos?: TodoListType;
@@ -23,30 +24,58 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
23
24
  border-block-end: none;
24
25
  }
25
26
  `,
26
- textChecked: css`
27
+ processingRow: css`
28
+ display: flex;
29
+ gap: 7px;
30
+ align-items: center;
31
+ `,
32
+ textCompleted: css`
27
33
  color: ${cssVar.colorTextQuaternary};
28
34
  text-decoration: line-through;
29
35
  `,
36
+ textProcessing: css`
37
+ color: ${cssVar.colorText};
38
+ `,
39
+ textTodo: css`
40
+ color: ${cssVar.colorTextSecondary};
41
+ `,
30
42
  }));
31
43
 
32
44
  interface ReadOnlyTodoItemProps {
33
- completed: boolean;
45
+ status: TodoStatus;
34
46
  text: string;
35
47
  }
36
48
 
37
49
  /**
38
50
  * Read-only todo item row, matching the style of TodoItemRow in SortableTodoList
39
51
  */
40
- const ReadOnlyTodoItem = memo<ReadOnlyTodoItemProps>(({ text, completed }) => {
52
+ const ReadOnlyTodoItem = memo<ReadOnlyTodoItemProps>(({ text, status }) => {
53
+ const isCompleted = status === 'completed';
54
+ const isProcessing = status === 'processing';
55
+
56
+ // Processing state uses CircleArrowRight icon
57
+ if (isProcessing) {
58
+ return (
59
+ <div className={cx(styles.itemRow, styles.processingRow)}>
60
+ <Icon icon={CircleArrowRight} size={17} style={{ color: cssVar.colorTextSecondary }} />
61
+ <span className={styles.textProcessing}>{text}</span>
62
+ </div>
63
+ );
64
+ }
65
+
66
+ // Todo and completed states use Checkbox
41
67
  return (
42
68
  <Checkbox
43
69
  backgroundColor={cssVar.colorSuccess}
44
- checked={completed}
45
- classNames={{ text: completed ? styles.textChecked : undefined, wrapper: styles.itemRow }}
70
+ checked={isCompleted}
71
+ classNames={{
72
+ text: cx(styles.textTodo, isCompleted && styles.textCompleted),
73
+ wrapper: styles.itemRow,
74
+ }}
46
75
  shape={'circle'}
47
76
  style={{ borderWidth: 1.5, cursor: 'default' }}
48
77
  textProps={{
49
- type: completed ? 'secondary' : undefined,
78
+ type: isCompleted ? 'secondary' : undefined,
50
79
  }}
51
80
  >
52
81
  {text}
@@ -73,7 +102,7 @@ const TodoListUI = memo<TodoListUIProps>(({ items }) => {
73
102
  // Outer container with background - matches AddTodoIntervention
74
103
  <Block variant={'outlined'} width="100%">
75
104
  {items.map((item, index) => (
76
- <ReadOnlyTodoItem completed={item.completed} key={index} text={item.text} />
105
+ <ReadOnlyTodoItem key={index} status={item.status} text={item.text} />
77
106
  ))}
78
107
  </Block>
79
108
  );
@@ -14,9 +14,7 @@ import TodoListRender from './TodoList';
14
14
  export const GTDRenders = {
15
15
  // All todo operations render the same TodoList UI
16
16
  [GTDApiName.clearTodos]: TodoListRender,
17
- [GTDApiName.completeTodos]: TodoListRender,
18
17
  [GTDApiName.createTodos]: TodoListRender,
19
- [GTDApiName.removeTodos]: TodoListRender,
20
18
  [GTDApiName.updateTodos]: TodoListRender,
21
19
 
22
20
  // Plan operations render the PlanCard UI
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
 
3
- import { ActionIcon, Checkbox, Flexbox, SortableList } from '@lobehub/ui';
3
+ import { ActionIcon, Checkbox, Flexbox, Icon, SortableList } from '@lobehub/ui';
4
4
  import { Input, InputRef } from 'antd';
5
5
  import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Trash2 } from 'lucide-react';
6
+ import { CircleArrowRight, Trash2 } from 'lucide-react';
7
7
  import { ChangeEvent, KeyboardEvent, memo, useCallback, useEffect, useRef } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
@@ -34,10 +34,13 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
34
34
  }
35
35
  }
36
36
  `,
37
- textChecked: css`
37
+ textCompleted: css`
38
38
  color: ${cssVar.colorTextQuaternary};
39
39
  text-decoration: line-through;
40
40
  `,
41
+ textProcessing: css`
42
+ color: ${cssVar.colorWarningText};
43
+ `,
41
44
  }));
42
45
 
43
46
  interface TodoItemRowProps {
@@ -53,7 +56,9 @@ const TodoItemRow = memo<TodoItemRowProps>(({ id, placeholder }) => {
53
56
  // Find item by stable id
54
57
  const item = useTodoListStore((s) => s.items.find((item) => item.id === id));
55
58
  const text = item?.text ?? '';
56
- const completed = item?.completed ?? false;
59
+ const status = item?.status ?? 'todo';
60
+ const isCompleted = status === 'completed';
61
+ const isProcessing = status === 'processing';
57
62
 
58
63
  const focusedId = useTodoListStore((s) => s.focusedId);
59
64
  const cursorPosition = useTodoListStore((s) => s.cursorPosition);
@@ -123,15 +128,24 @@ const TodoItemRow = memo<TodoItemRowProps>(({ id, placeholder }) => {
123
128
  return (
124
129
  <Flexbox align="center" className={styles.itemRow} gap={4} horizontal width="100%">
125
130
  <SortableList.DragHandle className={cx(styles.dragHandle, 'drag-handle')} size="small" />
126
- <Checkbox
127
- backgroundColor={cssVar.colorSuccess}
128
- checked={completed}
129
- onChange={handleToggle}
130
- shape={'circle'}
131
- style={{ borderWidth: 1.5 }}
132
- />
131
+ {isProcessing ? (
132
+ <Icon
133
+ icon={CircleArrowRight}
134
+ onClick={handleToggle}
135
+ size={16}
136
+ style={{ color: cssVar.colorInfo, cursor: 'pointer', flexShrink: 0 }}
137
+ />
138
+ ) : (
139
+ <Checkbox
140
+ backgroundColor={cssVar.colorSuccess}
141
+ checked={isCompleted}
142
+ onChange={handleToggle}
143
+ shape={'circle'}
144
+ style={{ borderWidth: 1.5 }}
145
+ />
146
+ )}
133
147
  <Input
134
- className={cx(completed && styles.textChecked)}
148
+ className={cx(isCompleted && styles.textCompleted, isProcessing && styles.textProcessing)}
135
149
  onChange={handleChange}
136
150
  onFocus={handleFocus}
137
151
  onKeyDown={handleKeyDown}
@@ -1,6 +1,6 @@
1
1
  import { debounce } from 'es-toolkit/compat';
2
2
 
3
- import type { TodoItem } from '../../../../types';
3
+ import { getNextTodoStatus, type TodoItem } from '../../../../types';
4
4
  import { AUTO_SAVE_DELAY, AUTO_SAVE_MAX_WAIT, initialState } from './initialState';
5
5
  import type { StoreInternals, TodoListItem, TodoListStore } from './types';
6
6
  import { ADD_ITEM_ID } from './types';
@@ -37,7 +37,7 @@ export const createActions = (
37
37
 
38
38
  try {
39
39
  // Convert TodoListItem[] to TodoItem[] (remove id)
40
- const todoItems: TodoItem[] = items.map(({ completed, text }) => ({ completed, text }));
40
+ const todoItems: TodoItem[] = items.map(({ status, text }) => ({ status, text }));
41
41
  console.log('[performSave] calling onSave with', todoItems.length, 'items');
42
42
  await internals.onSave(todoItems);
43
43
  console.log('[performSave] onSave completed');
@@ -69,7 +69,7 @@ export const createActions = (
69
69
  if (!newItemText.trim()) return;
70
70
 
71
71
  set({
72
- items: [...items, { completed: false, id: generateId(), text: newItemText.trim() }],
72
+ items: [...items, { id: generateId(), status: 'todo', text: newItemText.trim() }],
73
73
  newItemText: '',
74
74
  });
75
75
  markDirtyAndSave();
@@ -97,7 +97,7 @@ export const createActions = (
97
97
  set({ saveStatus: 'saving' });
98
98
 
99
99
  try {
100
- const todoItems: TodoItem[] = items.map(({ completed, text }) => ({ completed, text }));
100
+ const todoItems: TodoItem[] = items.map(({ status, text }) => ({ status, text }));
101
101
  console.log('[saveNow] force saving', todoItems.length, 'items');
102
102
  await internals.onSave(todoItems);
103
103
  console.log('[saveNow] save completed');
@@ -160,7 +160,7 @@ export const createActions = (
160
160
  const { items } = get();
161
161
  set({
162
162
  items: items.map((item) =>
163
- item.id === id ? { ...item, completed: !item.completed } : item,
163
+ item.id === id ? { ...item, status: getNextTodoStatus(item.status) } : item,
164
164
  ),
165
165
  });
166
166
  markDirtyAndSave();