@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.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/en-US/plugin.json +4 -0
- package/locales/zh-CN/plugin.json +4 -0
- package/package.json +2 -2
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +5 -5
- package/packages/agent-runtime/src/utils/stepContextComputer.test.ts +5 -5
- package/packages/builtin-tool-gtd/src/client/Inspector/index.ts +0 -4
- package/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +1 -1
- package/packages/builtin-tool-gtd/src/client/Render/TodoList/index.tsx +39 -10
- package/packages/builtin-tool-gtd/src/client/Render/index.ts +0 -2
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/TodoItemRow.tsx +26 -12
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/actions.ts +5 -5
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/store.test.ts +14 -8
- package/packages/builtin-tool-gtd/src/executor/index.test.ts +48 -227
- package/packages/builtin-tool-gtd/src/executor/index.ts +15 -158
- package/packages/builtin-tool-gtd/src/manifest.ts +12 -42
- package/packages/builtin-tool-gtd/src/systemRole.ts +14 -8
- package/packages/builtin-tool-gtd/src/types.ts +47 -41
- package/packages/builtin-tool-memory/package.json +8 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddContextMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddExperienceMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddPreferenceMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/RemoveIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +67 -0
- package/packages/builtin-tool-memory/src/client/Inspector/UpdateIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/index.ts +35 -0
- package/packages/builtin-tool-memory/src/client/Intervention/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Intervention/index.ts +13 -0
- package/packages/builtin-tool-memory/src/client/Render/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +217 -0
- package/packages/builtin-tool-memory/src/client/Render/index.ts +15 -0
- package/packages/builtin-tool-memory/src/client/Streaming/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Streaming/index.ts +18 -0
- package/packages/builtin-tool-memory/src/client/components/ExperienceMemoryCard.tsx +231 -0
- package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
- package/packages/builtin-tool-memory/src/client/index.ts +27 -0
- package/packages/builtin-tool-memory/src/executor/index.ts +9 -1
- package/packages/builtin-tool-memory/src/types.ts +61 -0
- package/packages/context-engine/src/providers/GTDTodoInjector.ts +15 -7
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +4 -0
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +1 -0
- package/packages/prompts/src/prompts/gtd/index.test.ts +32 -16
- package/packages/prompts/src/prompts/gtd/index.ts +9 -5
- package/packages/types/package.json +1 -1
- package/packages/types/src/discover/assistants.ts +4 -0
- package/packages/types/src/discover/groupAgents.ts +196 -0
- package/packages/types/src/discover/index.ts +5 -1
- package/packages/types/src/stepContext.ts +4 -1
- package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/DetailProvider.tsx +19 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Members/index.tsx +137 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +88 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Overview/index.tsx +213 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +85 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/TagList.tsx +20 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/index.tsx +71 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Versions/index.tsx +119 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +51 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +253 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +222 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +34 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/Summary/index.tsx +42 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/index.tsx +41 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/StatusPage/index.tsx +104 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/index.tsx +103 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/loading.tsx +1 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +7 -1
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +2 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +186 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +59 -0
- package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
- package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +26 -8
- package/src/app/[variants]/(main)/community/(list)/assistant/index.tsx +1 -0
- package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
- package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +2 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +2 -1
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupForkConfirmModal.tsx +60 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupPublishResultModal.tsx +62 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +122 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +46 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/types.ts +12 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +211 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/utils.ts +22 -0
- package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +4 -2
- package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +30 -35
- package/src/app/[variants]/(main)/resource/library/_layout/Header/index.tsx +9 -11
- package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/index.tsx +11 -17
- package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/LoadingPlaceholder/index.tsx +13 -3
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/CustomRender.tsx +43 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/FallbacktArgumentRender.tsx +59 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/index.tsx +46 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/index.tsx +13 -19
- package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +17 -17
- package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -9
- package/src/features/Conversation/TodoProgress/index.tsx +56 -23
- package/src/features/PluginsUI/Render/MCPType/index.tsx +1 -1
- package/src/features/ResourceManager/components/Explorer/Header/index.tsx +57 -4
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +6 -4
- package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +16 -5
- package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +5 -4
- package/src/hooks/useActiveTabKey.ts +1 -2
- package/src/locales/default/plugin.ts +1 -0
- package/src/locales/default/setting.ts +12 -0
- package/src/server/routers/lambda/market/agentGroup.ts +296 -0
- package/src/server/routers/lambda/market/index.ts +134 -4
- package/src/server/services/discover/index.ts +123 -7
- package/src/services/discover.ts +55 -0
- package/src/store/chat/slices/message/selectors/dbMessage.test.ts +11 -11
- package/src/store/discover/slices/groupAgent/action.ts +80 -0
- package/src/store/discover/store.ts +3 -0
- package/src/store/file/slices/resource/action.ts +4 -2
- package/src/tools/inspectors.ts +2 -0
- package/src/tools/interventions.ts +2 -0
- package/src/tools/renders.ts +3 -1
- package/src/tools/streamings.ts +2 -0
- package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +0 -52
- package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +0 -52
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/CustomRender.tsx +0 -113
- package/src/features/Conversation/Messages/Tool/Tool/Render.tsx +0 -47
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/AbortResponse.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Arguments/index.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/ErrorResponse.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ApprovalActions.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/Fallback.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/KeyValueEditor.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ModeSelector.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/index.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/PluginSettings.tsx +0 -0
- /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].
|
|
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',
|
|
36
|
-
{ text: 'Call mom',
|
|
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].
|
|
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].
|
|
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',
|
|
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',
|
|
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].
|
|
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',
|
|
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',
|
|
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',
|
|
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].
|
|
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',
|
|
168
|
-
{ text: 'Task 2',
|
|
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
|
-
{
|
|
202
|
-
{
|
|
203
|
-
{
|
|
204
|
-
{
|
|
205
|
-
{
|
|
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
|
-
{
|
|
215
|
-
{
|
|
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].
|
|
226
|
+
expect(result.state?.todos.items[2].status).toBe('completed');
|
|
227
227
|
// Other items should remain uncompleted
|
|
228
|
-
expect(result.state?.todos.items[0].
|
|
229
|
-
expect(result.state?.todos.items[1].
|
|
230
|
-
expect(result.state?.todos.items[3].
|
|
231
|
-
expect(result.state?.todos.items[4].
|
|
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',
|
|
375
|
-
{ text: 'Task 2',
|
|
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',
|
|
393
|
-
{ text: 'Task 2',
|
|
394
|
-
{ text: 'Task 3',
|
|
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',
|
|
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',
|
|
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',
|
|
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].
|
|
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',
|
|
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',
|
|
557
|
-
{ text: 'Task 2',
|
|
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
|
|
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
|
-
|
|
586
|
-
expect(gtdExecutor.hasApi('
|
|
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).
|
|
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) => ({
|
|
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({
|
|
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
|
-
|
|
160
|
-
|
|
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],
|
|
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) =>
|
|
248
|
+
updatedTodos = existingTodos.filter((todo) => todo.status !== 'completed');
|
|
392
249
|
clearedCount = existingTodos.length - updatedTodos.length;
|
|
393
250
|
|
|
394
251
|
if (clearedCount === 0) {
|