@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
@@ -22,7 +22,7 @@ describe('GTDExecutor', () => {
22
22
  expect(result.content).toContain('Call mom');
23
23
  expect(result.state?.todos.items).toHaveLength(2);
24
24
  expect(result.state?.todos.items[0].text).toBe('Buy milk');
25
- expect(result.state?.todos.items[0].completed).toBe(false);
25
+ expect(result.state?.todos.items[0].status).toBe('todo');
26
26
  expect(result.state?.todos.items[1].text).toBe('Call mom');
27
27
  });
28
28
 
@@ -32,8 +32,8 @@ describe('GTDExecutor', () => {
32
32
  const result = await gtdExecutor.createTodos(
33
33
  {
34
34
  items: [
35
- { text: 'Buy milk', completed: false },
36
- { text: 'Call mom', completed: true },
35
+ { text: 'Buy milk', status: 'todo' },
36
+ { text: 'Call mom', status: 'completed' },
37
37
  ],
38
38
  },
39
39
  ctx,
@@ -43,15 +43,15 @@ describe('GTDExecutor', () => {
43
43
  expect(result.content).toContain('Added 2 items');
44
44
  expect(result.state?.todos.items).toHaveLength(2);
45
45
  expect(result.state?.todos.items[0].text).toBe('Buy milk');
46
- expect(result.state?.todos.items[0].completed).toBe(false);
46
+ expect(result.state?.todos.items[0].status).toBe('todo');
47
47
  expect(result.state?.todos.items[1].text).toBe('Call mom');
48
- expect(result.state?.todos.items[1].completed).toBe(true);
48
+ expect(result.state?.todos.items[1].status).toBe('completed');
49
49
  });
50
50
 
51
51
  it('should append items to existing todo list', async () => {
52
52
  const ctx = createMockContext({
53
53
  todos: {
54
- items: [{ text: 'Existing task', completed: false }],
54
+ items: [{ text: 'Existing task', status: 'todo' }],
55
55
  updatedAt: '2024-01-01T00:00:00.000Z',
56
56
  },
57
57
  });
@@ -89,7 +89,7 @@ describe('GTDExecutor', () => {
89
89
  const result = await gtdExecutor.createTodos(
90
90
  {
91
91
  adds: ['AI task'],
92
- items: [{ text: 'User edited task', completed: true }],
92
+ items: [{ text: 'User edited task', status: 'completed' }],
93
93
  },
94
94
  ctx,
95
95
  );
@@ -97,7 +97,7 @@ describe('GTDExecutor', () => {
97
97
  expect(result.success).toBe(true);
98
98
  expect(result.state?.todos.items).toHaveLength(1);
99
99
  expect(result.state?.todos.items[0].text).toBe('User edited task');
100
- expect(result.state?.todos.items[0].completed).toBe(true);
100
+ expect(result.state?.todos.items[0].status).toBe('completed');
101
101
  });
102
102
  });
103
103
 
@@ -105,7 +105,7 @@ describe('GTDExecutor', () => {
105
105
  it('should add new items via operations', async () => {
106
106
  const ctx = createMockContext({
107
107
  todos: {
108
- items: [{ text: 'Existing task', completed: false }],
108
+ items: [{ text: 'Existing task', status: 'todo' }],
109
109
  updatedAt: '2024-01-01T00:00:00.000Z',
110
110
  },
111
111
  });
@@ -125,7 +125,7 @@ describe('GTDExecutor', () => {
125
125
  it('should update item text via operations', async () => {
126
126
  const ctx = createMockContext({
127
127
  todos: {
128
- items: [{ text: 'Old task', completed: false }],
128
+ items: [{ text: 'Old task', status: 'todo' }],
129
129
  updatedAt: '2024-01-01T00:00:00.000Z',
130
130
  },
131
131
  });
@@ -144,7 +144,7 @@ describe('GTDExecutor', () => {
144
144
  it('should complete items via operations', async () => {
145
145
  const ctx = createMockContext({
146
146
  todos: {
147
- items: [{ text: 'Task', completed: false }],
147
+ items: [{ text: 'Task', status: 'todo' }],
148
148
  updatedAt: '2024-01-01T00:00:00.000Z',
149
149
  },
150
150
  });
@@ -157,15 +157,15 @@ describe('GTDExecutor', () => {
157
157
  );
158
158
 
159
159
  expect(result.success).toBe(true);
160
- expect(result.state?.todos.items[0].completed).toBe(true);
160
+ expect(result.state?.todos.items[0].status).toBe('completed');
161
161
  });
162
162
 
163
163
  it('should remove items via operations', async () => {
164
164
  const ctx = createMockContext({
165
165
  todos: {
166
166
  items: [
167
- { text: 'Task 1', completed: false },
168
- { text: 'Task 2', completed: false },
167
+ { text: 'Task 1', status: 'todo' },
168
+ { text: 'Task 2', status: 'todo' },
169
169
  ],
170
170
  updatedAt: '2024-01-01T00:00:00.000Z',
171
171
  },
@@ -198,11 +198,11 @@ describe('GTDExecutor', () => {
198
198
  createdItems: ['Task A', 'Task B', 'Task C', 'Task D', 'Task E'],
199
199
  todos: {
200
200
  items: [
201
- { completed: false, text: 'Task A' },
202
- { completed: false, text: 'Task B' },
203
- { completed: false, text: 'Task C' },
204
- { completed: false, text: 'Task D' },
205
- { completed: false, text: 'Task E' },
201
+ { status: 'todo', text: 'Task A' },
202
+ { status: 'todo', text: 'Task B' },
203
+ { status: 'todo', text: 'Task C' },
204
+ { status: 'todo', text: 'Task D' },
205
+ { status: 'todo', text: 'Task E' },
206
206
  ],
207
207
  updatedAt: '2025-01-01T00:00:00.000Z',
208
208
  },
@@ -211,8 +211,8 @@ describe('GTDExecutor', () => {
211
211
  const result = await gtdExecutor.updateTodos(
212
212
  {
213
213
  operations: [
214
- { completed: true, index: 5, newText: '', text: '', type: 'complete' }, // out of range
215
- { completed: true, index: 2, newText: '', text: '', type: 'complete' }, // valid
214
+ { index: 5, type: 'complete' }, // out of range
215
+ { index: 2, type: 'complete' }, // valid
216
216
  ],
217
217
  },
218
218
  ctx,
@@ -223,146 +223,12 @@ describe('GTDExecutor', () => {
223
223
  expect(result.state?.todos.items).toHaveLength(5);
224
224
  // Index 5 is out of range (0-4), so should be skipped
225
225
  // Index 2 should be completed
226
- expect(result.state?.todos.items[2].completed).toBe(true);
226
+ expect(result.state?.todos.items[2].status).toBe('completed');
227
227
  // Other items should remain uncompleted
228
- expect(result.state?.todos.items[0].completed).toBe(false);
229
- expect(result.state?.todos.items[1].completed).toBe(false);
230
- expect(result.state?.todos.items[3].completed).toBe(false);
231
- expect(result.state?.todos.items[4].completed).toBe(false);
232
- });
233
- });
234
-
235
- describe('completeTodos', () => {
236
- it('should mark items as done by indices', async () => {
237
- const ctx = createMockContext({
238
- todos: {
239
- items: [
240
- { text: 'Task 1', completed: false },
241
- { text: 'Task 2', completed: false },
242
- { text: 'Task 3', completed: false },
243
- ],
244
- updatedAt: '2024-01-01T00:00:00.000Z',
245
- },
246
- });
247
-
248
- const result = await gtdExecutor.completeTodos({ indices: [0, 2] }, ctx);
249
-
250
- expect(result.success).toBe(true);
251
- expect(result.content).toContain('Completed 2 items');
252
- expect(result.state?.todos.items[0].completed).toBe(true);
253
- expect(result.state?.todos.items[1].completed).toBe(false);
254
- expect(result.state?.todos.items[2].completed).toBe(true);
255
- });
256
-
257
- it('should return error when no indices provided', async () => {
258
- const ctx = createMockContext();
259
-
260
- const result = await gtdExecutor.completeTodos({ indices: [] }, ctx);
261
-
262
- expect(result.success).toBe(false);
263
- expect(result.content).toContain('No indices provided');
264
- });
265
-
266
- it('should handle empty todo list', async () => {
267
- const ctx = createMockContext({
268
- todos: { items: [], updatedAt: '2024-01-01T00:00:00.000Z' },
269
- });
270
-
271
- const result = await gtdExecutor.completeTodos({ indices: [0] }, ctx);
272
-
273
- expect(result.success).toBe(true);
274
- expect(result.content).toContain('No todos to complete');
275
- });
276
-
277
- it('should return error when all indices are invalid', async () => {
278
- const ctx = createMockContext({
279
- todos: {
280
- items: [{ text: 'Task 1', completed: false }],
281
- updatedAt: '2024-01-01T00:00:00.000Z',
282
- },
283
- });
284
-
285
- const result = await gtdExecutor.completeTodos({ indices: [5, 10] }, ctx);
286
-
287
- expect(result.success).toBe(false);
288
- expect(result.content).toContain('Invalid indices');
289
- });
290
-
291
- it('should complete valid indices and warn about invalid ones', async () => {
292
- const ctx = createMockContext({
293
- todos: {
294
- items: [
295
- { text: 'Task 1', completed: false },
296
- { text: 'Task 2', completed: false },
297
- ],
298
- updatedAt: '2024-01-01T00:00:00.000Z',
299
- },
300
- });
301
-
302
- const result = await gtdExecutor.completeTodos({ indices: [0, 99] }, ctx);
303
-
304
- expect(result.success).toBe(true);
305
- expect(result.content).toContain('Completed 1 item');
306
- expect(result.content).toContain('Ignored invalid indices');
307
- expect(result.state?.todos.items[0].completed).toBe(true);
308
- expect(result.state?.todos.items[1].completed).toBe(false);
309
- });
310
-
311
- it('should handle single item completion with correct grammar', async () => {
312
- const ctx = createMockContext({
313
- todos: {
314
- items: [{ text: 'Task 1', completed: false }],
315
- updatedAt: '2024-01-01T00:00:00.000Z',
316
- },
317
- });
318
-
319
- const result = await gtdExecutor.completeTodos({ indices: [0] }, ctx);
320
-
321
- expect(result.success).toBe(true);
322
- expect(result.content).toContain('Completed 1 item');
323
- expect(result.content).not.toContain('items');
324
- });
325
- });
326
-
327
- describe('removeTodos', () => {
328
- it('should remove items by indices', async () => {
329
- const ctx = createMockContext({
330
- todos: {
331
- items: [
332
- { text: 'Task 1', completed: false },
333
- { text: 'Task 2', completed: false },
334
- { text: 'Task 3', completed: false },
335
- ],
336
- updatedAt: '2024-01-01T00:00:00.000Z',
337
- },
338
- });
339
-
340
- const result = await gtdExecutor.removeTodos({ indices: [0, 2] }, ctx);
341
-
342
- expect(result.success).toBe(true);
343
- expect(result.content).toContain('Removed 2 items');
344
- expect(result.state?.todos.items).toHaveLength(1);
345
- expect(result.state?.todos.items[0].text).toBe('Task 2');
346
- });
347
-
348
- it('should return error when no indices provided', async () => {
349
- const ctx = createMockContext();
350
-
351
- const result = await gtdExecutor.removeTodos({ indices: [] }, ctx);
352
-
353
- expect(result.success).toBe(false);
354
- expect(result.content).toContain('No indices provided');
355
- });
356
-
357
- it('should handle empty todo list', async () => {
358
- const ctx = createMockContext({
359
- todos: { items: [], updatedAt: '2024-01-01T00:00:00.000Z' },
360
- });
361
-
362
- const result = await gtdExecutor.removeTodos({ indices: [0] }, ctx);
363
-
364
- expect(result.success).toBe(true);
365
- expect(result.content).toContain('No todos to remove');
228
+ expect(result.state?.todos.items[0].status).toBe('todo');
229
+ expect(result.state?.todos.items[1].status).toBe('todo');
230
+ expect(result.state?.todos.items[3].status).toBe('todo');
231
+ expect(result.state?.todos.items[4].status).toBe('todo');
366
232
  });
367
233
  });
368
234
 
@@ -371,8 +237,8 @@ describe('GTDExecutor', () => {
371
237
  const ctx = createMockContext({
372
238
  todos: {
373
239
  items: [
374
- { text: 'Task 1', completed: false },
375
- { text: 'Task 2', completed: true },
240
+ { text: 'Task 1', status: 'todo' },
241
+ { text: 'Task 2', status: 'completed' },
376
242
  ],
377
243
  updatedAt: '2024-01-01T00:00:00.000Z',
378
244
  },
@@ -389,9 +255,9 @@ describe('GTDExecutor', () => {
389
255
  const ctx = createMockContext({
390
256
  todos: {
391
257
  items: [
392
- { text: 'Task 1', completed: false },
393
- { text: 'Task 2', completed: true },
394
- { text: 'Task 3', completed: true },
258
+ { text: 'Task 1', status: 'todo' },
259
+ { text: 'Task 2', status: 'completed' },
260
+ { text: 'Task 3', status: 'completed' },
395
261
  ],
396
262
  updatedAt: '2024-01-01T00:00:00.000Z',
397
263
  },
@@ -421,7 +287,7 @@ describe('GTDExecutor', () => {
421
287
  it('should handle no completed items to clear', async () => {
422
288
  const ctx = createMockContext({
423
289
  todos: {
424
- items: [{ text: 'Task 1', completed: false }],
290
+ items: [{ text: 'Task 1', status: 'todo' }],
425
291
  updatedAt: '2024-01-01T00:00:00.000Z',
426
292
  },
427
293
  });
@@ -442,13 +308,13 @@ describe('GTDExecutor', () => {
442
308
  operationId: 'test-operation-id',
443
309
  pluginState: {
444
310
  todos: {
445
- items: [{ text: 'Old task from pluginState', completed: false }],
311
+ items: [{ text: 'Old task from pluginState', status: 'todo' }],
446
312
  updatedAt: '2024-01-01T00:00:00.000Z',
447
313
  },
448
314
  },
449
315
  stepContext: {
450
316
  todos: {
451
- items: [{ text: 'New task from stepContext', completed: true }],
317
+ items: [{ text: 'New task from stepContext', status: 'completed' }],
452
318
  updatedAt: '2024-06-01T00:00:00.000Z',
453
319
  },
454
320
  },
@@ -461,7 +327,7 @@ describe('GTDExecutor', () => {
461
327
  expect(result.state?.todos.items).toHaveLength(2);
462
328
  // First item should be from stepContext, not pluginState
463
329
  expect(result.state?.todos.items[0].text).toBe('New task from stepContext');
464
- expect(result.state?.todos.items[0].completed).toBe(true);
330
+ expect(result.state?.todos.items[0].status).toBe('completed');
465
331
  expect(result.state?.todos.items[1].text).toBe('Another task');
466
332
  });
467
333
 
@@ -471,7 +337,7 @@ describe('GTDExecutor', () => {
471
337
  operationId: 'test-operation-id',
472
338
  pluginState: {
473
339
  todos: {
474
- items: [{ text: 'Task from pluginState', completed: false }],
340
+ items: [{ text: 'Task from pluginState', status: 'todo' }],
475
341
  updatedAt: '2024-01-01T00:00:00.000Z',
476
342
  },
477
343
  },
@@ -502,50 +368,6 @@ describe('GTDExecutor', () => {
502
368
  expect(result.state?.todos.items[0].text).toBe('First task');
503
369
  });
504
370
 
505
- it('should work with stepContext.todos for completeTodos', async () => {
506
- const ctx: BuiltinToolContext = {
507
- messageId: 'test-message-id',
508
- operationId: 'test-operation-id',
509
- stepContext: {
510
- todos: {
511
- items: [
512
- { text: 'Task 1', completed: false },
513
- { text: 'Task 2', completed: false },
514
- ],
515
- updatedAt: '2024-06-01T00:00:00.000Z',
516
- },
517
- },
518
- };
519
-
520
- const result = await gtdExecutor.completeTodos({ indices: [0] }, ctx);
521
-
522
- expect(result.success).toBe(true);
523
- expect(result.state?.todos.items[0].completed).toBe(true);
524
- expect(result.state?.todos.items[1].completed).toBe(false);
525
- });
526
-
527
- it('should work with stepContext.todos for removeTodos', async () => {
528
- const ctx: BuiltinToolContext = {
529
- messageId: 'test-message-id',
530
- operationId: 'test-operation-id',
531
- stepContext: {
532
- todos: {
533
- items: [
534
- { text: 'Task 1', completed: false },
535
- { text: 'Task 2', completed: false },
536
- ],
537
- updatedAt: '2024-06-01T00:00:00.000Z',
538
- },
539
- },
540
- };
541
-
542
- const result = await gtdExecutor.removeTodos({ indices: [0] }, ctx);
543
-
544
- expect(result.success).toBe(true);
545
- expect(result.state?.todos.items).toHaveLength(1);
546
- expect(result.state?.todos.items[0].text).toBe('Task 2');
547
- });
548
-
549
371
  it('should work with stepContext.todos for clearTodos', async () => {
550
372
  const ctx: BuiltinToolContext = {
551
373
  messageId: 'test-message-id',
@@ -553,8 +375,8 @@ describe('GTDExecutor', () => {
553
375
  stepContext: {
554
376
  todos: {
555
377
  items: [
556
- { text: 'Task 1', completed: true },
557
- { text: 'Task 2', completed: false },
378
+ { text: 'Task 1', status: 'completed' },
379
+ { text: 'Task 2', status: 'todo' },
558
380
  ],
559
381
  updatedAt: '2024-06-01T00:00:00.000Z',
560
382
  },
@@ -574,27 +396,26 @@ describe('GTDExecutor', () => {
574
396
  expect(gtdExecutor.identifier).toBe('lobe-gtd');
575
397
  });
576
398
 
577
- it('should support all MVP APIs', () => {
399
+ it('should support all APIs', () => {
578
400
  expect(gtdExecutor.hasApi('createTodos')).toBe(true);
579
401
  expect(gtdExecutor.hasApi('updateTodos')).toBe(true);
580
- expect(gtdExecutor.hasApi('completeTodos')).toBe(true);
581
- expect(gtdExecutor.hasApi('removeTodos')).toBe(true);
582
402
  expect(gtdExecutor.hasApi('clearTodos')).toBe(true);
583
- });
584
-
585
- it('should not support non-MVP APIs', () => {
586
- expect(gtdExecutor.hasApi('createPlan')).toBe(false);
587
- expect(gtdExecutor.hasApi('updatePlan')).toBe(false);
403
+ expect(gtdExecutor.hasApi('createPlan')).toBe(true);
404
+ expect(gtdExecutor.hasApi('updatePlan')).toBe(true);
405
+ expect(gtdExecutor.hasApi('execTask')).toBe(true);
406
+ expect(gtdExecutor.hasApi('execTasks')).toBe(true);
588
407
  });
589
408
 
590
409
  it('should return correct API names', () => {
591
410
  const apiNames = gtdExecutor.getApiNames();
592
411
  expect(apiNames).toContain('createTodos');
593
412
  expect(apiNames).toContain('updateTodos');
594
- expect(apiNames).toContain('completeTodos');
595
- expect(apiNames).toContain('removeTodos');
596
413
  expect(apiNames).toContain('clearTodos');
597
- expect(apiNames).toHaveLength(5);
414
+ expect(apiNames).toContain('createPlan');
415
+ expect(apiNames).toContain('updatePlan');
416
+ expect(apiNames).toContain('execTask');
417
+ expect(apiNames).toContain('execTasks');
418
+ expect(apiNames).toHaveLength(7);
598
419
  });
599
420
  });
600
421
  });
@@ -7,14 +7,12 @@ import { useNotebookStore } from '@/store/notebook';
7
7
  import { GTDIdentifier } from '../manifest';
8
8
  import {
9
9
  type ClearTodosParams,
10
- type CompleteTodosParams,
11
10
  type CreatePlanParams,
12
11
  type CreateTodosParams,
13
12
  type ExecTaskParams,
14
13
  type ExecTasksParams,
15
14
  GTDApiName,
16
15
  type Plan,
17
- type RemoveTodosParams,
18
16
  type TodoItem,
19
17
  type TodoState,
20
18
  type UpdatePlanParams,
@@ -49,12 +47,10 @@ const syncTodosToPlan = async (topicId: string, todos: TodoState): Promise<void>
49
47
  // API enum for MVP (Todo + Plan)
50
48
  const GTDApiNameEnum = {
51
49
  clearTodos: GTDApiName.clearTodos,
52
- completeTodos: GTDApiName.completeTodos,
53
50
  createPlan: GTDApiName.createPlan,
54
51
  createTodos: GTDApiName.createTodos,
55
52
  execTask: GTDApiName.execTask,
56
53
  execTasks: GTDApiName.execTasks,
57
- removeTodos: GTDApiName.removeTodos,
58
54
  updatePlan: GTDApiName.updatePlan,
59
55
  updateTodos: GTDApiName.updateTodos,
60
56
  } as const;
@@ -82,7 +78,7 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
82
78
  const itemsToAdd: TodoItem[] = params.items
83
79
  ? params.items
84
80
  : params.adds
85
- ? params.adds.map((text) => ({ completed: false, text }))
81
+ ? params.adds.map((text) => ({ status: 'todo' as const, text }))
86
82
  : [];
87
83
 
88
84
  if (itemsToAdd.length === 0) {
@@ -144,7 +140,7 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
144
140
  switch (op.type) {
145
141
  case 'add': {
146
142
  if (op.text) {
147
- updatedTodos.push({ completed: false, text: op.text });
143
+ updatedTodos.push({ status: 'todo', text: op.text });
148
144
  results.push(`Added: "${op.text}"`);
149
145
  }
150
146
  break;
@@ -156,8 +152,9 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
156
152
  if (op.newText !== undefined) {
157
153
  updatedItem.text = op.newText;
158
154
  }
159
- if (op.completed !== undefined) {
160
- updatedItem.completed = op.completed;
155
+ // Handle status field
156
+ if (op.status !== undefined) {
157
+ updatedItem.status = op.status;
161
158
  }
162
159
  updatedTodos[op.index] = updatedItem;
163
160
  results.push(`Updated item ${op.index + 1}`);
@@ -174,11 +171,19 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
174
171
  case 'complete': {
175
172
  if (op.index !== undefined && op.index >= 0 && op.index < updatedTodos.length) {
176
173
  // Create a new object to avoid mutating frozen/immutable objects from store
177
- updatedTodos[op.index] = { ...updatedTodos[op.index], completed: true };
174
+ updatedTodos[op.index] = { ...updatedTodos[op.index], status: 'completed' };
178
175
  results.push(`Completed: "${updatedTodos[op.index].text}"`);
179
176
  }
180
177
  break;
181
178
  }
179
+ case 'processing': {
180
+ if (op.index !== undefined && op.index >= 0 && op.index < updatedTodos.length) {
181
+ // Create a new object to avoid mutating frozen/immutable objects from store
182
+ updatedTodos[op.index] = { ...updatedTodos[op.index], status: 'processing' };
183
+ results.push(`In progress: "${updatedTodos[op.index].text}"`);
184
+ }
185
+ break;
186
+ }
182
187
  }
183
188
  }
184
189
 
@@ -206,154 +211,6 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
206
211
  };
207
212
  };
208
213
 
209
- /**
210
- * Mark todo items as done by their indices
211
- */
212
- completeTodos = async (
213
- params: CompleteTodosParams,
214
- ctx: BuiltinToolContext,
215
- ): Promise<BuiltinToolResult> => {
216
- const { indices } = params;
217
-
218
- if (!indices || indices.length === 0) {
219
- return {
220
- content: 'No indices provided to complete.',
221
- success: false,
222
- };
223
- }
224
-
225
- const existingTodos = getTodosFromContext(ctx);
226
-
227
- if (existingTodos.length === 0) {
228
- const now = new Date().toISOString();
229
- return {
230
- content: 'No todos to complete. The list is empty.\n\n' + formatTodoStateSummary([], now),
231
- state: {
232
- completedIndices: [],
233
- todos: { items: [], updatedAt: now },
234
- },
235
- success: true,
236
- };
237
- }
238
-
239
- // Validate indices
240
- const validIndices = indices.filter((i: number) => i >= 0 && i < existingTodos.length);
241
- const invalidIndices = indices.filter((i: number) => i < 0 || i >= existingTodos.length);
242
-
243
- if (validIndices.length === 0) {
244
- return {
245
- content: `Invalid indices: ${indices.join(', ')}. Valid range is 0-${existingTodos.length - 1}.`,
246
- success: false,
247
- };
248
- }
249
-
250
- // Mark items as completed
251
- const updatedTodos = existingTodos.map((todo, index) => {
252
- if (validIndices.includes(index)) {
253
- return { ...todo, completed: true };
254
- }
255
- return todo;
256
- });
257
-
258
- const completedItems = validIndices.map((i: number) => existingTodos[i].text);
259
- const now = new Date().toISOString();
260
-
261
- // Format response: action summary + todo state
262
- let actionSummary = `✔️ Completed ${validIndices.length} item${validIndices.length > 1 ? 's' : ''}:\n`;
263
- actionSummary += completedItems.map((text: string) => `- ${text}`).join('\n');
264
-
265
- if (invalidIndices.length > 0) {
266
- actionSummary += `\n\nNote: Ignored invalid indices: ${invalidIndices.join(', ')}`;
267
- }
268
-
269
- const todoState = { items: updatedTodos, updatedAt: now };
270
-
271
- // Sync todos to Plan document if topic exists
272
- if (ctx.topicId) {
273
- await syncTodosToPlan(ctx.topicId, todoState);
274
- }
275
-
276
- return {
277
- content: actionSummary + '\n\n' + formatTodoStateSummary(updatedTodos, now),
278
- state: {
279
- completedIndices: validIndices,
280
- todos: todoState,
281
- },
282
- success: true,
283
- };
284
- };
285
-
286
- /**
287
- * Remove todo items by indices
288
- */
289
- removeTodos = async (
290
- params: RemoveTodosParams,
291
- ctx: BuiltinToolContext,
292
- ): Promise<BuiltinToolResult> => {
293
- const { indices } = params;
294
-
295
- if (!indices || indices.length === 0) {
296
- return {
297
- content: 'No indices provided to remove.',
298
- success: false,
299
- };
300
- }
301
-
302
- const existingTodos = getTodosFromContext(ctx);
303
-
304
- if (existingTodos.length === 0) {
305
- const now = new Date().toISOString();
306
- return {
307
- content: 'No todos to remove. The list is empty.\n\n' + formatTodoStateSummary([], now),
308
- state: {
309
- removedIndices: [],
310
- todos: { items: [], updatedAt: now },
311
- },
312
- success: true,
313
- };
314
- }
315
-
316
- // Validate indices
317
- const validIndices = indices.filter((i: number) => i >= 0 && i < existingTodos.length);
318
- const invalidIndices = indices.filter((i: number) => i < 0 || i >= existingTodos.length);
319
-
320
- if (validIndices.length === 0) {
321
- return {
322
- content: `Invalid indices: ${indices.join(', ')}. Valid range is 0-${existingTodos.length - 1}.`,
323
- success: false,
324
- };
325
- }
326
-
327
- // Remove items
328
- const removedItems = validIndices.map((i: number) => existingTodos[i].text);
329
- const updatedTodos = existingTodos.filter((_, index) => !validIndices.includes(index));
330
- const now = new Date().toISOString();
331
-
332
- // Format response: action summary + todo state
333
- let actionSummary = `🗑️ Removed ${validIndices.length} item${validIndices.length > 1 ? 's' : ''}:\n`;
334
- actionSummary += removedItems.map((text: string) => `- ${text}`).join('\n');
335
-
336
- if (invalidIndices.length > 0) {
337
- actionSummary += `\n\nNote: Ignored invalid indices: ${invalidIndices.join(', ')}`;
338
- }
339
-
340
- const todoState = { items: updatedTodos, updatedAt: now };
341
-
342
- // Sync todos to Plan document if topic exists
343
- if (ctx.topicId) {
344
- await syncTodosToPlan(ctx.topicId, todoState);
345
- }
346
-
347
- return {
348
- content: actionSummary + '\n\n' + formatTodoStateSummary(updatedTodos, now),
349
- state: {
350
- removedIndices: validIndices,
351
- todos: todoState,
352
- },
353
- success: true,
354
- };
355
- };
356
-
357
214
  /**
358
215
  * Clear todo items
359
216
  */
@@ -388,7 +245,7 @@ class GTDExecutor extends BaseExecutor<typeof GTDApiNameEnum> {
388
245
  actionSummary = `🧹 Cleared all ${clearedCount} item${clearedCount > 1 ? 's' : ''} from todo list.`;
389
246
  } else {
390
247
  // mode === 'completed'
391
- updatedTodos = existingTodos.filter((todo) => !todo.completed);
248
+ updatedTodos = existingTodos.filter((todo) => todo.status !== 'completed');
392
249
  clearedCount = existingTodos.length - updatedTodos.length;
393
250
 
394
251
  if (clearedCount === 0) {