@lobehub/lobehub 2.0.0-next.295 → 2.0.0-next.297

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 (132) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/en-US/plugin.json +4 -0
  4. package/locales/zh-CN/plugin.json +4 -0
  5. package/package.json +2 -2
  6. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +5 -5
  7. package/packages/agent-runtime/src/utils/stepContextComputer.test.ts +5 -5
  8. package/packages/builtin-tool-gtd/src/client/Inspector/index.ts +0 -4
  9. package/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +1 -1
  10. package/packages/builtin-tool-gtd/src/client/Render/TodoList/index.tsx +39 -10
  11. package/packages/builtin-tool-gtd/src/client/Render/index.ts +0 -2
  12. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/TodoItemRow.tsx +26 -12
  13. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/actions.ts +5 -5
  14. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/store.test.ts +14 -8
  15. package/packages/builtin-tool-gtd/src/executor/index.test.ts +48 -227
  16. package/packages/builtin-tool-gtd/src/executor/index.ts +15 -158
  17. package/packages/builtin-tool-gtd/src/manifest.ts +12 -42
  18. package/packages/builtin-tool-gtd/src/systemRole.ts +14 -8
  19. package/packages/builtin-tool-gtd/src/types.ts +47 -41
  20. package/packages/builtin-tool-memory/package.json +8 -0
  21. package/packages/builtin-tool-memory/src/client/Inspector/AddContextMemory/index.tsx +60 -0
  22. package/packages/builtin-tool-memory/src/client/Inspector/AddExperienceMemory/index.tsx +60 -0
  23. package/packages/builtin-tool-memory/src/client/Inspector/AddIdentityMemory/index.tsx +60 -0
  24. package/packages/builtin-tool-memory/src/client/Inspector/AddPreferenceMemory/index.tsx +60 -0
  25. package/packages/builtin-tool-memory/src/client/Inspector/RemoveIdentityMemory/index.tsx +60 -0
  26. package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +67 -0
  27. package/packages/builtin-tool-memory/src/client/Inspector/UpdateIdentityMemory/index.tsx +60 -0
  28. package/packages/builtin-tool-memory/src/client/Inspector/index.ts +35 -0
  29. package/packages/builtin-tool-memory/src/client/Intervention/AddExperienceMemory/index.tsx +17 -0
  30. package/packages/builtin-tool-memory/src/client/Intervention/index.ts +13 -0
  31. package/packages/builtin-tool-memory/src/client/Render/AddExperienceMemory/index.tsx +17 -0
  32. package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +217 -0
  33. package/packages/builtin-tool-memory/src/client/Render/index.ts +15 -0
  34. package/packages/builtin-tool-memory/src/client/Streaming/AddExperienceMemory/index.tsx +17 -0
  35. package/packages/builtin-tool-memory/src/client/Streaming/index.ts +18 -0
  36. package/packages/builtin-tool-memory/src/client/components/ExperienceMemoryCard.tsx +231 -0
  37. package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
  38. package/packages/builtin-tool-memory/src/client/index.ts +27 -0
  39. package/packages/builtin-tool-memory/src/executor/index.ts +9 -1
  40. package/packages/builtin-tool-memory/src/types.ts +61 -0
  41. package/packages/context-engine/src/providers/GTDTodoInjector.ts +15 -7
  42. package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +4 -0
  43. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +1 -0
  44. package/packages/prompts/src/prompts/gtd/index.test.ts +32 -16
  45. package/packages/prompts/src/prompts/gtd/index.ts +9 -5
  46. package/packages/types/package.json +1 -1
  47. package/packages/types/src/discover/assistants.ts +4 -0
  48. package/packages/types/src/discover/groupAgents.ts +196 -0
  49. package/packages/types/src/discover/index.ts +5 -1
  50. package/packages/types/src/stepContext.ts +4 -1
  51. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -2
  52. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/DetailProvider.tsx +19 -0
  53. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Members/index.tsx +137 -0
  54. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +88 -0
  55. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Overview/index.tsx +213 -0
  56. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +85 -0
  57. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/TagList.tsx +20 -0
  58. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/index.tsx +71 -0
  59. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Versions/index.tsx +119 -0
  60. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +51 -0
  61. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +253 -0
  62. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +222 -0
  63. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +34 -0
  64. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/Summary/index.tsx +42 -0
  65. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/index.tsx +41 -0
  66. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/StatusPage/index.tsx +104 -0
  67. package/src/app/[variants]/(main)/community/(detail)/group_agent/index.tsx +103 -0
  68. package/src/app/[variants]/(main)/community/(detail)/group_agent/loading.tsx +1 -0
  69. package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +7 -1
  70. package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +2 -0
  71. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +186 -0
  72. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +59 -0
  73. package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
  74. package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +26 -8
  75. package/src/app/[variants]/(main)/community/(list)/assistant/index.tsx +1 -0
  76. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
  77. package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +2 -0
  78. package/src/app/[variants]/(main)/group/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +2 -1
  79. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupForkConfirmModal.tsx +60 -0
  80. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupPublishResultModal.tsx +62 -0
  81. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +122 -0
  82. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +46 -0
  83. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/types.ts +12 -0
  84. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +211 -0
  85. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/utils.ts +22 -0
  86. package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +4 -2
  87. package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +30 -35
  88. package/src/app/[variants]/(main)/resource/library/_layout/Header/index.tsx +9 -11
  89. package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
  90. package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/index.tsx +11 -17
  91. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/LoadingPlaceholder/index.tsx +13 -3
  92. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/CustomRender.tsx +43 -0
  93. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/FallbacktArgumentRender.tsx +59 -0
  94. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/index.tsx +46 -0
  95. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/index.tsx +13 -19
  96. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +17 -17
  97. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -9
  98. package/src/features/Conversation/TodoProgress/index.tsx +56 -23
  99. package/src/features/PluginsUI/Render/MCPType/index.tsx +1 -1
  100. package/src/features/ResourceManager/components/Explorer/Header/index.tsx +57 -4
  101. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +6 -4
  102. package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +16 -5
  103. package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +5 -4
  104. package/src/hooks/useActiveTabKey.ts +1 -2
  105. package/src/locales/default/plugin.ts +1 -0
  106. package/src/locales/default/setting.ts +12 -0
  107. package/src/server/routers/lambda/market/agentGroup.ts +296 -0
  108. package/src/server/routers/lambda/market/index.ts +134 -4
  109. package/src/server/services/discover/index.ts +123 -7
  110. package/src/services/discover.ts +55 -0
  111. package/src/store/chat/slices/message/selectors/dbMessage.test.ts +11 -11
  112. package/src/store/discover/slices/groupAgent/action.ts +80 -0
  113. package/src/store/discover/store.ts +3 -0
  114. package/src/store/file/slices/resource/action.ts +4 -2
  115. package/src/tools/inspectors.ts +2 -0
  116. package/src/tools/interventions.ts +2 -0
  117. package/src/tools/renders.ts +3 -1
  118. package/src/tools/streamings.ts +2 -0
  119. package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +0 -52
  120. package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +0 -52
  121. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/CustomRender.tsx +0 -113
  122. package/src/features/Conversation/Messages/Tool/Tool/Render.tsx +0 -47
  123. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/AbortResponse.tsx +0 -0
  124. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Arguments/index.tsx +0 -0
  125. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/ErrorResponse.tsx +0 -0
  126. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ApprovalActions.tsx +0 -0
  127. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/Fallback.tsx +0 -0
  128. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/KeyValueEditor.tsx +0 -0
  129. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ModeSelector.tsx +0 -0
  130. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/index.tsx +0 -0
  131. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/PluginSettings.tsx +0 -0
  132. /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.297](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.296...v2.0.0-next.297)
6
+
7
+ <sup>Released on **2026-01-16**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add agent group publish into market & use market group agents in lobehub.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add agent group publish into market & use market group agents in lobehub, closes [#11535](https://github.com/lobehub/lobe-chat/issues/11535) ([02b9e76](https://github.com/lobehub/lobe-chat/commit/02b9e76))
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.296](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.295...v2.0.0-next.296)
31
+
32
+ <sup>Released on **2026-01-16**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Improve todo list.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Improve todo list, closes [#11533](https://github.com/lobehub/lobe-chat/issues/11533) ([a4b71e9](https://github.com/lobehub/lobe-chat/commit/a4b71e9))
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.295](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.294...v2.0.0-next.295)
6
56
 
7
57
  <sup>Released on **2026-01-15**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "features": [
5
+ "Add agent group publish into market & use market group agents in lobehub."
6
+ ]
7
+ },
8
+ "date": "2026-01-16",
9
+ "version": "2.0.0-next.297"
10
+ },
11
+ {
12
+ "children": {
13
+ "improvements": [
14
+ "Improve todo list."
15
+ ]
16
+ },
17
+ "date": "2026-01-16",
18
+ "version": "2.0.0-next.296"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "improvements": [
@@ -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.295",
3
+ "version": "2.0.0-next.297",
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",
@@ -204,7 +204,7 @@
204
204
  "@lobehub/desktop-ipc-typings": "workspace:*",
205
205
  "@lobehub/editor": "^3.11.0",
206
206
  "@lobehub/icons": "^4.0.2",
207
- "@lobehub/market-sdk": "0.28.1",
207
+ "@lobehub/market-sdk": "0.29.0",
208
208
  "@lobehub/tts": "^4.0.2",
209
209
  "@lobehub/ui": "^4.19.0",
210
210
  "@modelcontextprotocol/sdk": "^1.25.1",
@@ -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();
@@ -8,7 +8,7 @@ import { ADD_ITEM_ID } from './types';
8
8
 
9
9
  // Helper to create TodoItem array from text strings
10
10
  const toTodoItems = (...texts: string[]): TodoItem[] =>
11
- texts.map((text) => ({ completed: false, text }));
11
+ texts.map((text) => ({ status: 'todo', text }));
12
12
 
13
13
  describe('TodoListStore', () => {
14
14
  beforeEach(() => {
@@ -39,7 +39,7 @@ describe('TodoListStore', () => {
39
39
 
40
40
  expect(state.items).toHaveLength(2);
41
41
  expect(state.items[0].text).toBe('Task 1');
42
- expect(state.items[0].completed).toBe(false);
42
+ expect(state.items[0].status).toBe('todo');
43
43
  expect(state.items[1].text).toBe('Task 2');
44
44
  });
45
45
 
@@ -63,7 +63,7 @@ describe('TodoListStore', () => {
63
63
  const state = store.getState();
64
64
  expect(state.items).toHaveLength(1);
65
65
  expect(state.items[0].text).toBe('New Task');
66
- expect(state.items[0].completed).toBe(false);
66
+ expect(state.items[0].status).toBe('todo');
67
67
  expect(state.newItemText).toBe('');
68
68
  });
69
69
 
@@ -152,23 +152,29 @@ describe('TodoListStore', () => {
152
152
  });
153
153
 
154
154
  describe('toggleItem', () => {
155
- it('should toggle item completed state', () => {
155
+ it('should cycle through status: todo → processing → completed → todo', () => {
156
156
  const store = createTodoListStore(toTodoItems('Task 1'));
157
157
  const itemId = store.getState().items[0].id;
158
158
 
159
- expect(store.getState().items[0].completed).toBe(false);
159
+ expect(store.getState().items[0].status).toBe('todo');
160
160
 
161
161
  act(() => {
162
162
  store.getState().toggleItem(itemId);
163
163
  });
164
164
 
165
- expect(store.getState().items[0].completed).toBe(true);
165
+ expect(store.getState().items[0].status).toBe('processing');
166
166
 
167
167
  act(() => {
168
168
  store.getState().toggleItem(itemId);
169
169
  });
170
170
 
171
- expect(store.getState().items[0].completed).toBe(false);
171
+ expect(store.getState().items[0].status).toBe('completed');
172
+
173
+ act(() => {
174
+ store.getState().toggleItem(itemId);
175
+ });
176
+
177
+ expect(store.getState().items[0].status).toBe('todo');
172
178
  });
173
179
 
174
180
  it('should mark store as dirty after toggling item', () => {
@@ -362,7 +368,7 @@ describe('TodoListStore', () => {
362
368
 
363
369
  expect(onSave).toHaveBeenCalledTimes(1);
364
370
  // onSave receives TodoItem[] (without id), not TodoListItem[]
365
- expect(onSave).toHaveBeenCalledWith([{ completed: false, text: 'Updated' }]);
371
+ expect(onSave).toHaveBeenCalledWith([{ status: 'todo', text: 'Updated' }]);
366
372
  });
367
373
 
368
374
  it('should set saveStatus to saving during save', async () => {