@shin1ohno/sage 0.8.4 → 0.8.7
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/dist/cli/mcp-handler.d.ts.map +1 -1
- package/dist/cli/mcp-handler.js +202 -1575
- package/dist/cli/mcp-handler.js.map +1 -1
- package/dist/config/update-validation.d.ts +52 -0
- package/dist/config/update-validation.d.ts.map +1 -0
- package/dist/config/update-validation.js +133 -0
- package/dist/config/update-validation.js.map +1 -0
- package/dist/index.js +163 -1815
- package/dist/index.js.map +1 -1
- package/dist/integrations/calendar-event-creator.d.ts +2 -3
- package/dist/integrations/calendar-event-creator.d.ts.map +1 -1
- package/dist/integrations/calendar-event-creator.js +3 -4
- package/dist/integrations/calendar-event-creator.js.map +1 -1
- package/dist/integrations/calendar-event-deleter.d.ts +2 -3
- package/dist/integrations/calendar-event-deleter.d.ts.map +1 -1
- package/dist/integrations/calendar-event-deleter.js +3 -4
- package/dist/integrations/calendar-event-deleter.js.map +1 -1
- package/dist/integrations/calendar-event-response.d.ts +4 -17
- package/dist/integrations/calendar-event-response.d.ts.map +1 -1
- package/dist/integrations/calendar-event-response.js +3 -4
- package/dist/integrations/calendar-event-response.js.map +1 -1
- package/dist/integrations/notion-mcp.d.ts +28 -3
- package/dist/integrations/notion-mcp.d.ts.map +1 -1
- package/dist/integrations/notion-mcp.js +21 -5
- package/dist/integrations/notion-mcp.js.map +1 -1
- package/dist/integrations/reminder-manager.d.ts.map +1 -1
- package/dist/integrations/reminder-manager.js +2 -0
- package/dist/integrations/reminder-manager.js.map +1 -1
- package/dist/services/container.d.ts +56 -0
- package/dist/services/container.d.ts.map +1 -0
- package/dist/services/container.js +76 -0
- package/dist/services/container.js.map +1 -0
- package/dist/tools/calendar/handlers.d.ts +186 -0
- package/dist/tools/calendar/handlers.d.ts.map +1 -0
- package/dist/tools/calendar/handlers.js +525 -0
- package/dist/tools/calendar/handlers.js.map +1 -0
- package/dist/tools/calendar/index.d.ts +11 -0
- package/dist/tools/calendar/index.d.ts.map +1 -0
- package/dist/tools/calendar/index.js +10 -0
- package/dist/tools/calendar/index.js.map +1 -0
- package/dist/tools/index.d.ts +23 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +24 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/integrations/handlers.d.ts +57 -0
- package/dist/tools/integrations/handlers.d.ts.map +1 -0
- package/dist/tools/integrations/handlers.js +159 -0
- package/dist/tools/integrations/handlers.js.map +1 -0
- package/dist/tools/integrations/index.d.ts +11 -0
- package/dist/tools/integrations/index.d.ts.map +1 -0
- package/dist/tools/integrations/index.js +10 -0
- package/dist/tools/integrations/index.js.map +1 -0
- package/dist/tools/registry.d.ts +8 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +10 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/reminders/handlers.d.ts +61 -0
- package/dist/tools/reminders/handlers.d.ts.map +1 -0
- package/dist/tools/reminders/handlers.js +148 -0
- package/dist/tools/reminders/handlers.js.map +1 -0
- package/dist/tools/reminders/index.d.ts +11 -0
- package/dist/tools/reminders/index.d.ts.map +1 -0
- package/dist/tools/reminders/index.js +10 -0
- package/dist/tools/reminders/index.js.map +1 -0
- package/dist/tools/setup/handlers.d.ts +81 -0
- package/dist/tools/setup/handlers.d.ts.map +1 -0
- package/dist/tools/setup/handlers.js +172 -0
- package/dist/tools/setup/handlers.js.map +1 -0
- package/dist/tools/setup/index.d.ts +11 -0
- package/dist/tools/setup/index.d.ts.map +1 -0
- package/dist/tools/setup/index.js +10 -0
- package/dist/tools/setup/index.js.map +1 -0
- package/dist/tools/tasks/handlers.d.ts +95 -0
- package/dist/tools/tasks/handlers.d.ts.map +1 -0
- package/dist/tools/tasks/handlers.js +197 -0
- package/dist/tools/tasks/handlers.js.map +1 -0
- package/dist/tools/tasks/index.d.ts +11 -0
- package/dist/tools/tasks/index.d.ts.map +1 -0
- package/dist/tools/tasks/index.js +10 -0
- package/dist/tools/tasks/index.js.map +1 -0
- package/dist/tools/types.d.ts +54 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +9 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types/calendar.d.ts +41 -0
- package/dist/types/calendar.d.ts.map +1 -0
- package/dist/types/calendar.js +18 -0
- package/dist/types/calendar.js.map +1 -0
- package/dist/utils/estimation.d.ts +34 -0
- package/dist/utils/estimation.d.ts.map +1 -1
- package/dist/utils/estimation.js +38 -1
- package/dist/utils/estimation.js.map +1 -1
- package/dist/utils/mcp-response.d.ts +89 -0
- package/dist/utils/mcp-response.d.ts.map +1 -0
- package/dist/utils/mcp-response.js +103 -0
- package/dist/utils/mcp-response.js.map +1 -0
- package/dist/utils/task-splitter.d.ts +65 -4
- package/dist/utils/task-splitter.d.ts.map +1 -1
- package/dist/utils/task-splitter.js +69 -5
- package/dist/utils/task-splitter.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/cli/http-server.d.ts +0 -74
- package/dist/cli/http-server.d.ts.map +0 -1
- package/dist/cli/http-server.js +0 -407
- package/dist/cli/http-server.js.map +0 -1
- package/dist/remote/remote-mcp-server.d.ts +0 -244
- package/dist/remote/remote-mcp-server.d.ts.map +0 -1
- package/dist/remote/remote-mcp-server.js +0 -507
- package/dist/remote/remote-mcp-server.js.map +0 -1
package/dist/cli/mcp-handler.js
CHANGED
|
@@ -6,17 +6,22 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { VERSION, SERVER_NAME } from '../version.js';
|
|
8
8
|
import { ConfigLoader } from '../config/loader.js';
|
|
9
|
-
import { SetupWizard } from '../setup/wizard.js';
|
|
10
|
-
import { TaskAnalyzer } from '../tools/analyze-tasks.js';
|
|
11
9
|
import { ReminderManager } from '../integrations/reminder-manager.js';
|
|
12
10
|
import { CalendarService } from '../integrations/calendar-service.js';
|
|
13
11
|
import { NotionMCPService } from '../integrations/notion-mcp.js';
|
|
14
12
|
import { TodoListManager } from '../integrations/todo-list-manager.js';
|
|
15
13
|
import { TaskSynchronizer } from '../integrations/task-synchronizer.js';
|
|
16
14
|
import { CalendarEventResponseService } from '../integrations/calendar-event-response.js';
|
|
17
|
-
import { CalendarEventCreatorService } from '../integrations/calendar-event-creator.js';
|
|
18
|
-
import { CalendarEventDeleterService } from '../integrations/calendar-event-deleter.js';
|
|
19
15
|
import { WorkingCadenceService } from '../services/working-cadence.js';
|
|
16
|
+
import { CalendarSourceManager } from '../integrations/calendar-source-manager.js';
|
|
17
|
+
import { GoogleCalendarService } from '../integrations/google-calendar-service.js';
|
|
18
|
+
import { GoogleOAuthHandler } from '../oauth/google-oauth-handler.js';
|
|
19
|
+
// Extracted tool handlers
|
|
20
|
+
import { handleCheckSetupStatus, handleStartSetupWizard, handleAnswerWizardQuestion, handleSaveConfig, } from '../tools/setup/index.js';
|
|
21
|
+
import { handleAnalyzeTasks, handleUpdateTaskStatus, handleSyncTasks, handleDetectDuplicates, } from '../tools/tasks/index.js';
|
|
22
|
+
import { handleSetReminder, handleListTodos, } from '../tools/reminders/index.js';
|
|
23
|
+
import { handleSyncToNotion, handleUpdateConfig, } from '../tools/integrations/index.js';
|
|
24
|
+
import { handleListCalendarSources, handleListCalendarEvents, handleFindAvailableSlots, handleCreateCalendarEvent, handleRespondToCalendarEvent, handleRespondToCalendarEventsBatch, handleDeleteCalendarEvent, handleDeleteCalendarEventsBatch, } from '../tools/calendar/handlers.js';
|
|
20
25
|
// Protocol version
|
|
21
26
|
const PROTOCOL_VERSION = '2024-11-05';
|
|
22
27
|
/**
|
|
@@ -31,9 +36,9 @@ class MCPHandlerImpl {
|
|
|
31
36
|
todoListManager = null;
|
|
32
37
|
taskSynchronizer = null;
|
|
33
38
|
calendarEventResponseService = null;
|
|
34
|
-
calendarEventCreatorService = null;
|
|
35
|
-
calendarEventDeleterService = null;
|
|
36
39
|
workingCadenceService = null;
|
|
40
|
+
calendarSourceManager = null;
|
|
41
|
+
googleCalendarService = null;
|
|
37
42
|
initialized = false;
|
|
38
43
|
tools = new Map();
|
|
39
44
|
constructor() {
|
|
@@ -68,14 +73,92 @@ class MCPHandlerImpl {
|
|
|
68
73
|
notionDatabaseId: userConfig.integrations.notion.databaseId,
|
|
69
74
|
});
|
|
70
75
|
this.calendarService = new CalendarService();
|
|
76
|
+
// Initialize Google Calendar service with OAuth handler
|
|
77
|
+
const oauthConfig = {
|
|
78
|
+
clientId: process.env.GOOGLE_CLIENT_ID || '',
|
|
79
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
|
|
80
|
+
redirectUri: process.env.GOOGLE_REDIRECT_URI || 'http://localhost:3000/oauth/callback',
|
|
81
|
+
};
|
|
82
|
+
const oauthHandler = new GoogleOAuthHandler(oauthConfig);
|
|
83
|
+
this.googleCalendarService = new GoogleCalendarService(oauthHandler);
|
|
84
|
+
this.calendarSourceManager = new CalendarSourceManager({
|
|
85
|
+
calendarService: this.calendarService,
|
|
86
|
+
googleCalendarService: this.googleCalendarService,
|
|
87
|
+
config: userConfig,
|
|
88
|
+
});
|
|
71
89
|
this.notionService = new NotionMCPService();
|
|
72
90
|
this.todoListManager = new TodoListManager();
|
|
73
91
|
this.taskSynchronizer = new TaskSynchronizer();
|
|
74
92
|
this.calendarEventResponseService = new CalendarEventResponseService();
|
|
75
|
-
this.calendarEventCreatorService = new CalendarEventCreatorService();
|
|
76
|
-
this.calendarEventDeleterService = new CalendarEventDeleterService();
|
|
77
93
|
this.workingCadenceService = new WorkingCadenceService();
|
|
78
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Create SetupContext for setup tool handlers
|
|
97
|
+
*/
|
|
98
|
+
createSetupContext() {
|
|
99
|
+
return {
|
|
100
|
+
getConfig: () => this.config,
|
|
101
|
+
setConfig: (config) => {
|
|
102
|
+
this.config = config;
|
|
103
|
+
},
|
|
104
|
+
getWizardSession: () => this.wizardSession,
|
|
105
|
+
setWizardSession: (session) => {
|
|
106
|
+
this.wizardSession = session;
|
|
107
|
+
},
|
|
108
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Create TaskToolsContext for task tool handlers
|
|
113
|
+
*/
|
|
114
|
+
createTaskToolsContext() {
|
|
115
|
+
return {
|
|
116
|
+
getConfig: () => this.config,
|
|
117
|
+
getTodoListManager: () => this.todoListManager,
|
|
118
|
+
getTaskSynchronizer: () => this.taskSynchronizer,
|
|
119
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Create ReminderTodoContext for reminder/todo tool handlers
|
|
124
|
+
*/
|
|
125
|
+
createReminderTodoContext() {
|
|
126
|
+
return {
|
|
127
|
+
getConfig: () => this.config,
|
|
128
|
+
getReminderManager: () => this.reminderManager,
|
|
129
|
+
getTodoListManager: () => this.todoListManager,
|
|
130
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Create IntegrationToolsContext for integration tool handlers
|
|
135
|
+
*/
|
|
136
|
+
createIntegrationToolsContext() {
|
|
137
|
+
return {
|
|
138
|
+
getConfig: () => this.config,
|
|
139
|
+
setConfig: (config) => {
|
|
140
|
+
this.config = config;
|
|
141
|
+
},
|
|
142
|
+
getNotionService: () => this.notionService,
|
|
143
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create CalendarToolsContext for calendar tool handlers
|
|
148
|
+
*/
|
|
149
|
+
createCalendarToolsContext() {
|
|
150
|
+
return {
|
|
151
|
+
getConfig: () => this.config,
|
|
152
|
+
getCalendarSourceManager: () => this.calendarSourceManager,
|
|
153
|
+
getCalendarEventResponseService: () => this.calendarEventResponseService,
|
|
154
|
+
getGoogleCalendarService: () => this.googleCalendarService,
|
|
155
|
+
getWorkingCadenceService: () => this.workingCadenceService,
|
|
156
|
+
setWorkingCadenceService: (service) => {
|
|
157
|
+
this.workingCadenceService = service;
|
|
158
|
+
},
|
|
159
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
79
162
|
/**
|
|
80
163
|
* Handle an MCP request
|
|
81
164
|
*/
|
|
@@ -209,7 +292,7 @@ class MCPHandlerImpl {
|
|
|
209
292
|
* Register all tools
|
|
210
293
|
*/
|
|
211
294
|
registerTools() {
|
|
212
|
-
// check_setup_status
|
|
295
|
+
// check_setup_status - uses extracted handler
|
|
213
296
|
this.registerTool({
|
|
214
297
|
name: 'check_setup_status',
|
|
215
298
|
description: 'Check if sage has been configured. Returns setup status and guidance.',
|
|
@@ -217,61 +300,8 @@ class MCPHandlerImpl {
|
|
|
217
300
|
type: 'object',
|
|
218
301
|
properties: {},
|
|
219
302
|
},
|
|
220
|
-
}, async () =>
|
|
221
|
-
|
|
222
|
-
const isValid = this.config !== null;
|
|
223
|
-
if (!exists) {
|
|
224
|
-
return {
|
|
225
|
-
content: [
|
|
226
|
-
{
|
|
227
|
-
type: 'text',
|
|
228
|
-
text: JSON.stringify({
|
|
229
|
-
setupComplete: false,
|
|
230
|
-
configExists: false,
|
|
231
|
-
message: 'sageの初期設定が必要です。start_setup_wizardを実行してセットアップを開始してください。',
|
|
232
|
-
nextAction: 'start_setup_wizard',
|
|
233
|
-
}, null, 2),
|
|
234
|
-
},
|
|
235
|
-
],
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
if (!isValid) {
|
|
239
|
-
return {
|
|
240
|
-
content: [
|
|
241
|
-
{
|
|
242
|
-
type: 'text',
|
|
243
|
-
text: JSON.stringify({
|
|
244
|
-
setupComplete: false,
|
|
245
|
-
configExists: true,
|
|
246
|
-
message: '設定ファイルが見つかりましたが、読み込みに失敗しました。設定を再作成してください。',
|
|
247
|
-
nextAction: 'start_setup_wizard',
|
|
248
|
-
}, null, 2),
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
content: [
|
|
255
|
-
{
|
|
256
|
-
type: 'text',
|
|
257
|
-
text: JSON.stringify({
|
|
258
|
-
setupComplete: true,
|
|
259
|
-
configExists: true,
|
|
260
|
-
userName: this.config?.user.name,
|
|
261
|
-
message: 'sageは設定済みです。タスク分析やリマインド設定を開始できます。',
|
|
262
|
-
availableTools: [
|
|
263
|
-
'analyze_tasks',
|
|
264
|
-
'set_reminder',
|
|
265
|
-
'find_available_slots',
|
|
266
|
-
'sync_to_notion',
|
|
267
|
-
'update_config',
|
|
268
|
-
],
|
|
269
|
-
}, null, 2),
|
|
270
|
-
},
|
|
271
|
-
],
|
|
272
|
-
};
|
|
273
|
-
});
|
|
274
|
-
// start_setup_wizard
|
|
303
|
+
}, async () => handleCheckSetupStatus(this.createSetupContext()));
|
|
304
|
+
// start_setup_wizard - uses extracted handler
|
|
275
305
|
this.registerTool({
|
|
276
306
|
name: 'start_setup_wizard',
|
|
277
307
|
description: 'Start the interactive setup wizard for sage. Returns the first question.',
|
|
@@ -285,34 +315,10 @@ class MCPHandlerImpl {
|
|
|
285
315
|
},
|
|
286
316
|
},
|
|
287
317
|
},
|
|
288
|
-
}, async (args) => {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
content: [
|
|
294
|
-
{
|
|
295
|
-
type: 'text',
|
|
296
|
-
text: JSON.stringify({
|
|
297
|
-
sessionId: this.wizardSession.sessionId,
|
|
298
|
-
currentStep: this.wizardSession.currentStep,
|
|
299
|
-
totalSteps: this.wizardSession.totalSteps,
|
|
300
|
-
progress: Math.round((this.wizardSession.currentStep / this.wizardSession.totalSteps) * 100),
|
|
301
|
-
question: {
|
|
302
|
-
id: question.id,
|
|
303
|
-
text: question.text,
|
|
304
|
-
type: question.type,
|
|
305
|
-
options: question.options,
|
|
306
|
-
defaultValue: question.defaultValue,
|
|
307
|
-
helpText: question.helpText,
|
|
308
|
-
},
|
|
309
|
-
message: 'セットアップを開始します。以下の質問に回答してください。',
|
|
310
|
-
}, null, 2),
|
|
311
|
-
},
|
|
312
|
-
],
|
|
313
|
-
};
|
|
314
|
-
});
|
|
315
|
-
// answer_wizard_question
|
|
318
|
+
}, async (args) => handleStartSetupWizard(this.createSetupContext(), {
|
|
319
|
+
mode: args.mode,
|
|
320
|
+
}));
|
|
321
|
+
// answer_wizard_question - uses extracted handler
|
|
316
322
|
this.registerTool({
|
|
317
323
|
name: 'answer_wizard_question',
|
|
318
324
|
description: 'Answer a question in the setup wizard and get the next question.',
|
|
@@ -330,77 +336,11 @@ class MCPHandlerImpl {
|
|
|
330
336
|
},
|
|
331
337
|
required: ['questionId', 'answer'],
|
|
332
338
|
},
|
|
333
|
-
}, async (args) => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
content: [
|
|
339
|
-
{
|
|
340
|
-
type: 'text',
|
|
341
|
-
text: JSON.stringify({
|
|
342
|
-
error: true,
|
|
343
|
-
message: 'セットアップセッションが見つかりません。start_setup_wizardを実行してください。',
|
|
344
|
-
}, null, 2),
|
|
345
|
-
},
|
|
346
|
-
],
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
const result = SetupWizard.answerQuestion(this.wizardSession, questionId, answer);
|
|
350
|
-
if (!result.success) {
|
|
351
|
-
return {
|
|
352
|
-
content: [
|
|
353
|
-
{
|
|
354
|
-
type: 'text',
|
|
355
|
-
text: JSON.stringify({
|
|
356
|
-
error: true,
|
|
357
|
-
message: result.error,
|
|
358
|
-
currentQuestion: result.currentQuestion,
|
|
359
|
-
}, null, 2),
|
|
360
|
-
},
|
|
361
|
-
],
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
if (result.isComplete) {
|
|
365
|
-
return {
|
|
366
|
-
content: [
|
|
367
|
-
{
|
|
368
|
-
type: 'text',
|
|
369
|
-
text: JSON.stringify({
|
|
370
|
-
isComplete: true,
|
|
371
|
-
sessionId: this.wizardSession.sessionId,
|
|
372
|
-
answers: this.wizardSession.answers,
|
|
373
|
-
message: 'すべての質問に回答しました。save_configを実行して設定を保存してください。',
|
|
374
|
-
nextAction: 'save_config',
|
|
375
|
-
}, null, 2),
|
|
376
|
-
},
|
|
377
|
-
],
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
const nextQuestion = SetupWizard.getCurrentQuestion(this.wizardSession);
|
|
381
|
-
return {
|
|
382
|
-
content: [
|
|
383
|
-
{
|
|
384
|
-
type: 'text',
|
|
385
|
-
text: JSON.stringify({
|
|
386
|
-
success: true,
|
|
387
|
-
currentStep: this.wizardSession.currentStep,
|
|
388
|
-
totalSteps: this.wizardSession.totalSteps,
|
|
389
|
-
progress: Math.round((this.wizardSession.currentStep / this.wizardSession.totalSteps) * 100),
|
|
390
|
-
question: {
|
|
391
|
-
id: nextQuestion.id,
|
|
392
|
-
text: nextQuestion.text,
|
|
393
|
-
type: nextQuestion.type,
|
|
394
|
-
options: nextQuestion.options,
|
|
395
|
-
defaultValue: nextQuestion.defaultValue,
|
|
396
|
-
helpText: nextQuestion.helpText,
|
|
397
|
-
},
|
|
398
|
-
}, null, 2),
|
|
399
|
-
},
|
|
400
|
-
],
|
|
401
|
-
};
|
|
402
|
-
});
|
|
403
|
-
// save_config
|
|
339
|
+
}, async (args) => handleAnswerWizardQuestion(this.createSetupContext(), {
|
|
340
|
+
questionId: args.questionId,
|
|
341
|
+
answer: args.answer,
|
|
342
|
+
}));
|
|
343
|
+
// save_config - uses extracted handler
|
|
404
344
|
this.registerTool({
|
|
405
345
|
name: 'save_config',
|
|
406
346
|
description: 'Save the configuration after completing the setup wizard.',
|
|
@@ -414,74 +354,10 @@ class MCPHandlerImpl {
|
|
|
414
354
|
},
|
|
415
355
|
required: ['confirm'],
|
|
416
356
|
},
|
|
417
|
-
}, async (args) => {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
content: [
|
|
422
|
-
{
|
|
423
|
-
type: 'text',
|
|
424
|
-
text: JSON.stringify({
|
|
425
|
-
saved: false,
|
|
426
|
-
message: '設定の保存がキャンセルされました。',
|
|
427
|
-
}, null, 2),
|
|
428
|
-
},
|
|
429
|
-
],
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
if (!this.wizardSession) {
|
|
433
|
-
return {
|
|
434
|
-
content: [
|
|
435
|
-
{
|
|
436
|
-
type: 'text',
|
|
437
|
-
text: JSON.stringify({
|
|
438
|
-
error: true,
|
|
439
|
-
message: 'セットアップセッションが見つかりません。start_setup_wizardを実行してください。',
|
|
440
|
-
}, null, 2),
|
|
441
|
-
},
|
|
442
|
-
],
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
try {
|
|
446
|
-
const newConfig = SetupWizard.buildConfig(this.wizardSession);
|
|
447
|
-
await ConfigLoader.save(newConfig);
|
|
448
|
-
this.config = newConfig;
|
|
449
|
-
this.wizardSession = null;
|
|
450
|
-
return {
|
|
451
|
-
content: [
|
|
452
|
-
{
|
|
453
|
-
type: 'text',
|
|
454
|
-
text: JSON.stringify({
|
|
455
|
-
saved: true,
|
|
456
|
-
configPath: ConfigLoader.getConfigPath(),
|
|
457
|
-
userName: newConfig.user.name,
|
|
458
|
-
message: `設定を保存しました。${newConfig.user.name}さん、sageをご利用いただきありがとうございます!`,
|
|
459
|
-
availableTools: [
|
|
460
|
-
'analyze_tasks',
|
|
461
|
-
'set_reminder',
|
|
462
|
-
'find_available_slots',
|
|
463
|
-
'sync_to_notion',
|
|
464
|
-
],
|
|
465
|
-
}, null, 2),
|
|
466
|
-
},
|
|
467
|
-
],
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
catch (error) {
|
|
471
|
-
return {
|
|
472
|
-
content: [
|
|
473
|
-
{
|
|
474
|
-
type: 'text',
|
|
475
|
-
text: JSON.stringify({
|
|
476
|
-
error: true,
|
|
477
|
-
message: `設定の保存に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
478
|
-
}, null, 2),
|
|
479
|
-
},
|
|
480
|
-
],
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
// analyze_tasks
|
|
357
|
+
}, async (args) => handleSaveConfig(this.createSetupContext(), {
|
|
358
|
+
confirm: args.confirm,
|
|
359
|
+
}));
|
|
360
|
+
// analyze_tasks - uses extracted handler
|
|
485
361
|
this.registerTool({
|
|
486
362
|
name: 'analyze_tasks',
|
|
487
363
|
description: 'Analyze tasks to determine priority, estimate time, and identify stakeholders.',
|
|
@@ -507,61 +383,10 @@ class MCPHandlerImpl {
|
|
|
507
383
|
},
|
|
508
384
|
required: ['tasks'],
|
|
509
385
|
},
|
|
510
|
-
}, async (args) => {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
{
|
|
515
|
-
type: 'text',
|
|
516
|
-
text: JSON.stringify({
|
|
517
|
-
error: true,
|
|
518
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
519
|
-
}, null, 2),
|
|
520
|
-
},
|
|
521
|
-
],
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
try {
|
|
525
|
-
const tasks = args.tasks;
|
|
526
|
-
const result = await TaskAnalyzer.analyzeTasks(tasks, this.config);
|
|
527
|
-
return {
|
|
528
|
-
content: [
|
|
529
|
-
{
|
|
530
|
-
type: 'text',
|
|
531
|
-
text: JSON.stringify({
|
|
532
|
-
success: true,
|
|
533
|
-
summary: result.summary,
|
|
534
|
-
tasks: result.analyzedTasks.map((t) => ({
|
|
535
|
-
title: t.original.title,
|
|
536
|
-
description: t.original.description,
|
|
537
|
-
deadline: t.original.deadline,
|
|
538
|
-
priority: t.priority,
|
|
539
|
-
estimatedMinutes: t.estimatedMinutes,
|
|
540
|
-
stakeholders: t.stakeholders,
|
|
541
|
-
tags: t.tags,
|
|
542
|
-
reasoning: t.reasoning,
|
|
543
|
-
suggestedReminders: t.suggestedReminders,
|
|
544
|
-
})),
|
|
545
|
-
}, null, 2),
|
|
546
|
-
},
|
|
547
|
-
],
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
catch (error) {
|
|
551
|
-
return {
|
|
552
|
-
content: [
|
|
553
|
-
{
|
|
554
|
-
type: 'text',
|
|
555
|
-
text: JSON.stringify({
|
|
556
|
-
error: true,
|
|
557
|
-
message: `タスク分析に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
558
|
-
}, null, 2),
|
|
559
|
-
},
|
|
560
|
-
],
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
// set_reminder
|
|
386
|
+
}, async (args) => handleAnalyzeTasks(this.createTaskToolsContext(), {
|
|
387
|
+
tasks: args.tasks,
|
|
388
|
+
}));
|
|
389
|
+
// set_reminder - uses extracted handler
|
|
565
390
|
this.registerTool({
|
|
566
391
|
name: 'set_reminder',
|
|
567
392
|
description: 'Set a reminder for a task in Apple Reminders or Notion.',
|
|
@@ -600,100 +425,15 @@ class MCPHandlerImpl {
|
|
|
600
425
|
},
|
|
601
426
|
required: ['taskTitle'],
|
|
602
427
|
},
|
|
603
|
-
}, async (args) => {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}, null, 2),
|
|
613
|
-
},
|
|
614
|
-
],
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
if (!this.reminderManager) {
|
|
618
|
-
this.initializeServices(this.config);
|
|
619
|
-
}
|
|
620
|
-
try {
|
|
621
|
-
const result = await this.reminderManager.setReminder({
|
|
622
|
-
taskTitle: args.taskTitle,
|
|
623
|
-
targetDate: args.dueDate,
|
|
624
|
-
reminderType: args.reminderType,
|
|
625
|
-
list: args.list ?? this.config.integrations.appleReminders.defaultList,
|
|
626
|
-
priority: args.priority,
|
|
627
|
-
notes: args.notes,
|
|
628
|
-
});
|
|
629
|
-
if (result.success) {
|
|
630
|
-
if (result.delegateToNotion && result.notionRequest) {
|
|
631
|
-
return {
|
|
632
|
-
content: [
|
|
633
|
-
{
|
|
634
|
-
type: 'text',
|
|
635
|
-
text: JSON.stringify({
|
|
636
|
-
success: true,
|
|
637
|
-
destination: 'notion_mcp',
|
|
638
|
-
method: 'delegate',
|
|
639
|
-
delegateToNotion: true,
|
|
640
|
-
notionRequest: result.notionRequest,
|
|
641
|
-
message: `Notionへの追加はClaude Codeが直接notion-create-pagesツールを使用してください。`,
|
|
642
|
-
}, null, 2),
|
|
643
|
-
},
|
|
644
|
-
],
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
return {
|
|
648
|
-
content: [
|
|
649
|
-
{
|
|
650
|
-
type: 'text',
|
|
651
|
-
text: JSON.stringify({
|
|
652
|
-
success: true,
|
|
653
|
-
destination: result.destination,
|
|
654
|
-
method: result.method,
|
|
655
|
-
reminderId: result.reminderId,
|
|
656
|
-
reminderUrl: result.reminderUrl ?? result.pageUrl,
|
|
657
|
-
message: result.destination === 'apple_reminders'
|
|
658
|
-
? `Apple Remindersにリマインダーを作成しました: ${args.taskTitle}`
|
|
659
|
-
: `Notionにタスクを作成しました: ${args.taskTitle}`,
|
|
660
|
-
}, null, 2),
|
|
661
|
-
},
|
|
662
|
-
],
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
return {
|
|
666
|
-
content: [
|
|
667
|
-
{
|
|
668
|
-
type: 'text',
|
|
669
|
-
text: JSON.stringify({
|
|
670
|
-
success: false,
|
|
671
|
-
destination: result.destination,
|
|
672
|
-
error: result.error,
|
|
673
|
-
fallbackText: result.fallbackText,
|
|
674
|
-
message: result.fallbackText
|
|
675
|
-
? '自動作成に失敗しました。以下のテキストを手動でコピーしてください。'
|
|
676
|
-
: `リマインダー作成に失敗しました: ${result.error}`,
|
|
677
|
-
}, null, 2),
|
|
678
|
-
},
|
|
679
|
-
],
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
catch (error) {
|
|
683
|
-
return {
|
|
684
|
-
content: [
|
|
685
|
-
{
|
|
686
|
-
type: 'text',
|
|
687
|
-
text: JSON.stringify({
|
|
688
|
-
error: true,
|
|
689
|
-
message: `リマインダー設定に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
690
|
-
}, null, 2),
|
|
691
|
-
},
|
|
692
|
-
],
|
|
693
|
-
};
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
// find_available_slots
|
|
428
|
+
}, async (args) => handleSetReminder(this.createReminderTodoContext(), {
|
|
429
|
+
taskTitle: args.taskTitle,
|
|
430
|
+
dueDate: args.dueDate,
|
|
431
|
+
reminderType: args.reminderType,
|
|
432
|
+
list: args.list,
|
|
433
|
+
priority: args.priority,
|
|
434
|
+
notes: args.notes,
|
|
435
|
+
}));
|
|
436
|
+
// find_available_slots - uses extracted handler
|
|
697
437
|
this.registerTool({
|
|
698
438
|
name: 'find_available_slots',
|
|
699
439
|
description: 'Find available time slots in the calendar for scheduling tasks.',
|
|
@@ -719,110 +459,13 @@ class MCPHandlerImpl {
|
|
|
719
459
|
},
|
|
720
460
|
required: ['durationMinutes'],
|
|
721
461
|
},
|
|
722
|
-
}, async (args) => {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
error: true,
|
|
730
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
731
|
-
}, null, 2),
|
|
732
|
-
},
|
|
733
|
-
],
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
if (!this.calendarService) {
|
|
737
|
-
this.initializeServices(this.config);
|
|
738
|
-
}
|
|
739
|
-
try {
|
|
740
|
-
const durationMinutes = args.durationMinutes;
|
|
741
|
-
const startDate = args.startDate;
|
|
742
|
-
const endDate = args.endDate;
|
|
743
|
-
const preferDeepWork = args.preferDeepWork;
|
|
744
|
-
const platformInfo = await this.calendarService.detectPlatform();
|
|
745
|
-
const isAvailable = await this.calendarService.isAvailable();
|
|
746
|
-
if (!isAvailable) {
|
|
747
|
-
const searchStart = startDate ?? new Date().toISOString().split('T')[0];
|
|
748
|
-
const searchEnd = endDate ??
|
|
749
|
-
new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
750
|
-
const manualPrompt = this.calendarService.generateManualInputPrompt(searchStart, searchEnd);
|
|
751
|
-
return {
|
|
752
|
-
content: [
|
|
753
|
-
{
|
|
754
|
-
type: 'text',
|
|
755
|
-
text: JSON.stringify({
|
|
756
|
-
success: false,
|
|
757
|
-
platform: platformInfo.platform,
|
|
758
|
-
method: platformInfo.recommendedMethod,
|
|
759
|
-
message: 'カレンダー統合がこのプラットフォームで利用できません。手動で予定を入力してください。',
|
|
760
|
-
manualPrompt,
|
|
761
|
-
}, null, 2),
|
|
762
|
-
},
|
|
763
|
-
],
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
const searchStart = startDate ?? new Date().toISOString().split('T')[0];
|
|
767
|
-
const searchEnd = endDate ??
|
|
768
|
-
new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
769
|
-
const events = await this.calendarService.fetchEvents(searchStart, searchEnd);
|
|
770
|
-
const workingHours = {
|
|
771
|
-
start: this.config.calendar.workingHours.start,
|
|
772
|
-
end: this.config.calendar.workingHours.end,
|
|
773
|
-
};
|
|
774
|
-
const slots = this.calendarService.findAvailableSlotsFromEvents(events, durationMinutes, workingHours, searchStart);
|
|
775
|
-
const suitabilityConfig = {
|
|
776
|
-
deepWorkDays: this.config.calendar.deepWorkDays,
|
|
777
|
-
meetingHeavyDays: this.config.calendar.meetingHeavyDays,
|
|
778
|
-
};
|
|
779
|
-
const scoredSlots = slots.map((slot) => this.calendarService.calculateSuitability(slot, suitabilityConfig));
|
|
780
|
-
const filteredSlots = preferDeepWork
|
|
781
|
-
? scoredSlots.filter((s) => s.dayType === 'deep-work')
|
|
782
|
-
: scoredSlots;
|
|
783
|
-
const suitabilityOrder = { excellent: 0, good: 1, acceptable: 2 };
|
|
784
|
-
filteredSlots.sort((a, b) => suitabilityOrder[a.suitability] - suitabilityOrder[b.suitability]);
|
|
785
|
-
return {
|
|
786
|
-
content: [
|
|
787
|
-
{
|
|
788
|
-
type: 'text',
|
|
789
|
-
text: JSON.stringify({
|
|
790
|
-
success: true,
|
|
791
|
-
platform: platformInfo.platform,
|
|
792
|
-
method: platformInfo.recommendedMethod,
|
|
793
|
-
searchRange: { start: searchStart, end: searchEnd },
|
|
794
|
-
eventsFound: events.length,
|
|
795
|
-
slots: filteredSlots.slice(0, 10).map((slot) => ({
|
|
796
|
-
start: slot.start,
|
|
797
|
-
end: slot.end,
|
|
798
|
-
durationMinutes: slot.durationMinutes,
|
|
799
|
-
suitability: slot.suitability,
|
|
800
|
-
dayType: slot.dayType,
|
|
801
|
-
reason: slot.reason,
|
|
802
|
-
})),
|
|
803
|
-
message: filteredSlots.length > 0
|
|
804
|
-
? `${filteredSlots.length}件の空き時間が見つかりました。`
|
|
805
|
-
: '指定した条件に合う空き時間が見つかりませんでした。',
|
|
806
|
-
}, null, 2),
|
|
807
|
-
},
|
|
808
|
-
],
|
|
809
|
-
};
|
|
810
|
-
}
|
|
811
|
-
catch (error) {
|
|
812
|
-
return {
|
|
813
|
-
content: [
|
|
814
|
-
{
|
|
815
|
-
type: 'text',
|
|
816
|
-
text: JSON.stringify({
|
|
817
|
-
error: true,
|
|
818
|
-
message: `カレンダー検索に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
819
|
-
}, null, 2),
|
|
820
|
-
},
|
|
821
|
-
],
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
});
|
|
825
|
-
// list_calendar_events
|
|
462
|
+
}, async (args) => handleFindAvailableSlots(this.createCalendarToolsContext(), {
|
|
463
|
+
durationMinutes: args.durationMinutes,
|
|
464
|
+
startDate: args.startDate,
|
|
465
|
+
endDate: args.endDate,
|
|
466
|
+
preferDeepWork: args.preferDeepWork,
|
|
467
|
+
}));
|
|
468
|
+
// list_calendar_events - uses extracted handler
|
|
826
469
|
this.registerTool({
|
|
827
470
|
name: 'list_calendar_events',
|
|
828
471
|
description: 'List calendar events for a specified period. Returns events with details including calendar name and location.',
|
|
@@ -837,98 +480,19 @@ class MCPHandlerImpl {
|
|
|
837
480
|
type: 'string',
|
|
838
481
|
description: 'End date in ISO 8601 format (e.g., 2025-01-20)',
|
|
839
482
|
},
|
|
840
|
-
|
|
483
|
+
calendarId: {
|
|
841
484
|
type: 'string',
|
|
842
|
-
description: 'Optional: filter events by calendar
|
|
485
|
+
description: 'Optional: filter events by calendar ID',
|
|
843
486
|
},
|
|
844
487
|
},
|
|
845
488
|
required: ['startDate', 'endDate'],
|
|
846
489
|
},
|
|
847
|
-
}, async (args) => {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
text: JSON.stringify({
|
|
854
|
-
error: true,
|
|
855
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
856
|
-
}, null, 2),
|
|
857
|
-
},
|
|
858
|
-
],
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
if (!this.calendarService) {
|
|
862
|
-
this.initializeServices(this.config);
|
|
863
|
-
}
|
|
864
|
-
try {
|
|
865
|
-
const startDate = args.startDate;
|
|
866
|
-
const endDate = args.endDate;
|
|
867
|
-
const calendarName = args.calendarName;
|
|
868
|
-
const platformInfo = await this.calendarService.detectPlatform();
|
|
869
|
-
const isAvailable = await this.calendarService.isAvailable();
|
|
870
|
-
if (!isAvailable) {
|
|
871
|
-
return {
|
|
872
|
-
content: [
|
|
873
|
-
{
|
|
874
|
-
type: 'text',
|
|
875
|
-
text: JSON.stringify({
|
|
876
|
-
success: false,
|
|
877
|
-
platform: platformInfo.platform,
|
|
878
|
-
method: platformInfo.recommendedMethod,
|
|
879
|
-
message: 'カレンダー統合がこのプラットフォームで利用できません。macOSで実行してください。',
|
|
880
|
-
}, null, 2),
|
|
881
|
-
},
|
|
882
|
-
],
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
const result = await this.calendarService.listEvents({
|
|
886
|
-
startDate,
|
|
887
|
-
endDate,
|
|
888
|
-
calendarName,
|
|
889
|
-
});
|
|
890
|
-
return {
|
|
891
|
-
content: [
|
|
892
|
-
{
|
|
893
|
-
type: 'text',
|
|
894
|
-
text: JSON.stringify({
|
|
895
|
-
success: true,
|
|
896
|
-
platform: platformInfo.platform,
|
|
897
|
-
method: platformInfo.recommendedMethod,
|
|
898
|
-
events: result.events.map((event) => ({
|
|
899
|
-
id: event.id,
|
|
900
|
-
title: event.title,
|
|
901
|
-
start: event.start,
|
|
902
|
-
end: event.end,
|
|
903
|
-
isAllDay: event.isAllDay,
|
|
904
|
-
calendar: event.calendar,
|
|
905
|
-
location: event.location,
|
|
906
|
-
})),
|
|
907
|
-
period: result.period,
|
|
908
|
-
totalEvents: result.totalEvents,
|
|
909
|
-
message: result.totalEvents > 0
|
|
910
|
-
? `${result.totalEvents}件のイベントが見つかりました。`
|
|
911
|
-
: '指定した期間にイベントが見つかりませんでした。',
|
|
912
|
-
}, null, 2),
|
|
913
|
-
},
|
|
914
|
-
],
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
|
-
catch (error) {
|
|
918
|
-
return {
|
|
919
|
-
content: [
|
|
920
|
-
{
|
|
921
|
-
type: 'text',
|
|
922
|
-
text: JSON.stringify({
|
|
923
|
-
error: true,
|
|
924
|
-
message: `カレンダーイベントの取得に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
925
|
-
}, null, 2),
|
|
926
|
-
},
|
|
927
|
-
],
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
});
|
|
931
|
-
// sync_to_notion
|
|
490
|
+
}, async (args) => handleListCalendarEvents(this.createCalendarToolsContext(), {
|
|
491
|
+
startDate: args.startDate,
|
|
492
|
+
endDate: args.endDate,
|
|
493
|
+
calendarId: args.calendarId,
|
|
494
|
+
}));
|
|
495
|
+
// sync_to_notion - uses extracted handler
|
|
932
496
|
this.registerTool({
|
|
933
497
|
name: 'sync_to_notion',
|
|
934
498
|
description: 'Sync a task to Notion database for long-term tracking.',
|
|
@@ -955,141 +519,15 @@ class MCPHandlerImpl {
|
|
|
955
519
|
},
|
|
956
520
|
required: ['taskTitle'],
|
|
957
521
|
},
|
|
958
|
-
}, async (args) => {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
}, null, 2),
|
|
968
|
-
},
|
|
969
|
-
],
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
if (!this.config.integrations.notion.enabled) {
|
|
973
|
-
return {
|
|
974
|
-
content: [
|
|
975
|
-
{
|
|
976
|
-
type: 'text',
|
|
977
|
-
text: JSON.stringify({
|
|
978
|
-
error: true,
|
|
979
|
-
message: 'Notion統合が有効になっていません。update_configでNotion設定を更新してください。',
|
|
980
|
-
}, null, 2),
|
|
981
|
-
},
|
|
982
|
-
],
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
if (!this.notionService) {
|
|
986
|
-
this.initializeServices(this.config);
|
|
987
|
-
}
|
|
988
|
-
try {
|
|
989
|
-
const taskTitle = args.taskTitle;
|
|
990
|
-
const description = args.description;
|
|
991
|
-
const priority = args.priority;
|
|
992
|
-
const dueDate = args.dueDate;
|
|
993
|
-
const stakeholders = args.stakeholders;
|
|
994
|
-
const estimatedMinutes = args.estimatedMinutes;
|
|
995
|
-
const isAvailable = await this.notionService.isAvailable();
|
|
996
|
-
const properties = this.notionService.buildNotionProperties({
|
|
997
|
-
title: taskTitle,
|
|
998
|
-
priority,
|
|
999
|
-
deadline: dueDate,
|
|
1000
|
-
stakeholders,
|
|
1001
|
-
estimatedMinutes,
|
|
1002
|
-
description,
|
|
1003
|
-
});
|
|
1004
|
-
if (!isAvailable) {
|
|
1005
|
-
const fallbackText = this.notionService.generateFallbackTemplate({
|
|
1006
|
-
title: taskTitle,
|
|
1007
|
-
priority,
|
|
1008
|
-
deadline: dueDate,
|
|
1009
|
-
stakeholders,
|
|
1010
|
-
estimatedMinutes,
|
|
1011
|
-
description,
|
|
1012
|
-
});
|
|
1013
|
-
return {
|
|
1014
|
-
content: [
|
|
1015
|
-
{
|
|
1016
|
-
type: 'text',
|
|
1017
|
-
text: JSON.stringify({
|
|
1018
|
-
success: false,
|
|
1019
|
-
method: 'fallback',
|
|
1020
|
-
message: 'Notion MCP統合が利用できません。以下のテンプレートを手動でNotionにコピーしてください。',
|
|
1021
|
-
fallbackText,
|
|
1022
|
-
task: {
|
|
1023
|
-
taskTitle,
|
|
1024
|
-
priority: priority ?? 'P3',
|
|
1025
|
-
dueDate,
|
|
1026
|
-
stakeholders: stakeholders ?? [],
|
|
1027
|
-
estimatedMinutes,
|
|
1028
|
-
},
|
|
1029
|
-
}, null, 2),
|
|
1030
|
-
},
|
|
1031
|
-
],
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
const result = await this.notionService.createPage({
|
|
1035
|
-
databaseId: this.config.integrations.notion.databaseId,
|
|
1036
|
-
title: taskTitle,
|
|
1037
|
-
properties,
|
|
1038
|
-
});
|
|
1039
|
-
if (result.success) {
|
|
1040
|
-
return {
|
|
1041
|
-
content: [
|
|
1042
|
-
{
|
|
1043
|
-
type: 'text',
|
|
1044
|
-
text: JSON.stringify({
|
|
1045
|
-
success: true,
|
|
1046
|
-
method: 'mcp',
|
|
1047
|
-
pageId: result.pageId,
|
|
1048
|
-
pageUrl: result.pageUrl,
|
|
1049
|
-
message: `Notionにタスクを同期しました: ${taskTitle}`,
|
|
1050
|
-
}, null, 2),
|
|
1051
|
-
},
|
|
1052
|
-
],
|
|
1053
|
-
};
|
|
1054
|
-
}
|
|
1055
|
-
const fallbackText = this.notionService.generateFallbackTemplate({
|
|
1056
|
-
title: taskTitle,
|
|
1057
|
-
priority,
|
|
1058
|
-
deadline: dueDate,
|
|
1059
|
-
stakeholders,
|
|
1060
|
-
estimatedMinutes,
|
|
1061
|
-
description,
|
|
1062
|
-
});
|
|
1063
|
-
return {
|
|
1064
|
-
content: [
|
|
1065
|
-
{
|
|
1066
|
-
type: 'text',
|
|
1067
|
-
text: JSON.stringify({
|
|
1068
|
-
success: false,
|
|
1069
|
-
method: 'fallback',
|
|
1070
|
-
error: result.error,
|
|
1071
|
-
message: 'Notion MCP呼び出しに失敗しました。以下のテンプレートを手動でコピーしてください。',
|
|
1072
|
-
fallbackText,
|
|
1073
|
-
}, null, 2),
|
|
1074
|
-
},
|
|
1075
|
-
],
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
catch (error) {
|
|
1079
|
-
return {
|
|
1080
|
-
content: [
|
|
1081
|
-
{
|
|
1082
|
-
type: 'text',
|
|
1083
|
-
text: JSON.stringify({
|
|
1084
|
-
error: true,
|
|
1085
|
-
message: `Notion同期に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1086
|
-
}, null, 2),
|
|
1087
|
-
},
|
|
1088
|
-
],
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
// update_config
|
|
522
|
+
}, async (args) => handleSyncToNotion(this.createIntegrationToolsContext(), {
|
|
523
|
+
taskTitle: args.taskTitle,
|
|
524
|
+
description: args.description,
|
|
525
|
+
priority: args.priority,
|
|
526
|
+
dueDate: args.dueDate,
|
|
527
|
+
stakeholders: args.stakeholders,
|
|
528
|
+
estimatedMinutes: args.estimatedMinutes,
|
|
529
|
+
}));
|
|
530
|
+
// update_config - uses extracted handler
|
|
1093
531
|
this.registerTool({
|
|
1094
532
|
name: 'update_config',
|
|
1095
533
|
description: 'Update sage configuration settings.',
|
|
@@ -1115,73 +553,11 @@ class MCPHandlerImpl {
|
|
|
1115
553
|
},
|
|
1116
554
|
required: ['section', 'updates'],
|
|
1117
555
|
},
|
|
1118
|
-
}, async (args) => {
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
type: 'text',
|
|
1124
|
-
text: JSON.stringify({
|
|
1125
|
-
error: true,
|
|
1126
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1127
|
-
}, null, 2),
|
|
1128
|
-
},
|
|
1129
|
-
],
|
|
1130
|
-
};
|
|
1131
|
-
}
|
|
1132
|
-
try {
|
|
1133
|
-
const section = args.section;
|
|
1134
|
-
const updates = args.updates;
|
|
1135
|
-
const validationResult = this.validateConfigUpdate(section, updates);
|
|
1136
|
-
if (!validationResult.valid) {
|
|
1137
|
-
return {
|
|
1138
|
-
content: [
|
|
1139
|
-
{
|
|
1140
|
-
type: 'text',
|
|
1141
|
-
text: JSON.stringify({
|
|
1142
|
-
error: true,
|
|
1143
|
-
message: `設定の検証に失敗しました: ${validationResult.error}`,
|
|
1144
|
-
invalidFields: validationResult.invalidFields,
|
|
1145
|
-
}, null, 2),
|
|
1146
|
-
},
|
|
1147
|
-
],
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
const updatedConfig = this.applyConfigUpdates(this.config, section, updates);
|
|
1151
|
-
await ConfigLoader.save(updatedConfig);
|
|
1152
|
-
this.config = updatedConfig;
|
|
1153
|
-
if (section === 'integrations') {
|
|
1154
|
-
this.initializeServices(this.config);
|
|
1155
|
-
}
|
|
1156
|
-
return {
|
|
1157
|
-
content: [
|
|
1158
|
-
{
|
|
1159
|
-
type: 'text',
|
|
1160
|
-
text: JSON.stringify({
|
|
1161
|
-
success: true,
|
|
1162
|
-
section,
|
|
1163
|
-
updatedFields: Object.keys(updates),
|
|
1164
|
-
message: `設定を更新しました: ${section}`,
|
|
1165
|
-
}, null, 2),
|
|
1166
|
-
},
|
|
1167
|
-
],
|
|
1168
|
-
};
|
|
1169
|
-
}
|
|
1170
|
-
catch (error) {
|
|
1171
|
-
return {
|
|
1172
|
-
content: [
|
|
1173
|
-
{
|
|
1174
|
-
type: 'text',
|
|
1175
|
-
text: JSON.stringify({
|
|
1176
|
-
error: true,
|
|
1177
|
-
message: `設定の更新に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1178
|
-
}, null, 2),
|
|
1179
|
-
},
|
|
1180
|
-
],
|
|
1181
|
-
};
|
|
1182
|
-
}
|
|
1183
|
-
});
|
|
1184
|
-
// list_todos
|
|
556
|
+
}, async (args) => handleUpdateConfig(this.createIntegrationToolsContext(), {
|
|
557
|
+
section: args.section,
|
|
558
|
+
updates: args.updates,
|
|
559
|
+
}));
|
|
560
|
+
// list_todos - uses extracted handler
|
|
1185
561
|
this.registerTool({
|
|
1186
562
|
name: 'list_todos',
|
|
1187
563
|
description: 'List TODO items from Apple Reminders and Notion with optional filtering.',
|
|
@@ -1214,90 +590,14 @@ class MCPHandlerImpl {
|
|
|
1214
590
|
},
|
|
1215
591
|
},
|
|
1216
592
|
},
|
|
1217
|
-
}, async (args) => {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1226
|
-
}, null, 2),
|
|
1227
|
-
},
|
|
1228
|
-
],
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
if (!this.todoListManager) {
|
|
1232
|
-
this.initializeServices(this.config);
|
|
1233
|
-
}
|
|
1234
|
-
try {
|
|
1235
|
-
const priority = args.priority;
|
|
1236
|
-
const status = args.status;
|
|
1237
|
-
const source = args.source;
|
|
1238
|
-
const todayOnly = args.todayOnly;
|
|
1239
|
-
const tags = args.tags;
|
|
1240
|
-
let todos;
|
|
1241
|
-
if (todayOnly) {
|
|
1242
|
-
todos = await this.todoListManager.getTodaysTasks();
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1245
|
-
todos = await this.todoListManager.listTodos({
|
|
1246
|
-
priority,
|
|
1247
|
-
status,
|
|
1248
|
-
source,
|
|
1249
|
-
tags,
|
|
1250
|
-
});
|
|
1251
|
-
}
|
|
1252
|
-
const formattedTodos = todos.map((todo) => ({
|
|
1253
|
-
id: todo.id,
|
|
1254
|
-
title: todo.title,
|
|
1255
|
-
priority: todo.priority,
|
|
1256
|
-
status: todo.status,
|
|
1257
|
-
dueDate: todo.dueDate,
|
|
1258
|
-
source: todo.source,
|
|
1259
|
-
tags: todo.tags,
|
|
1260
|
-
estimatedMinutes: todo.estimatedMinutes,
|
|
1261
|
-
stakeholders: todo.stakeholders,
|
|
1262
|
-
}));
|
|
1263
|
-
return {
|
|
1264
|
-
content: [
|
|
1265
|
-
{
|
|
1266
|
-
type: 'text',
|
|
1267
|
-
text: JSON.stringify({
|
|
1268
|
-
success: true,
|
|
1269
|
-
totalCount: todos.length,
|
|
1270
|
-
todos: formattedTodos,
|
|
1271
|
-
message: todos.length > 0
|
|
1272
|
-
? `${todos.length}件のタスクが見つかりました。`
|
|
1273
|
-
: 'タスクが見つかりませんでした。',
|
|
1274
|
-
filters: {
|
|
1275
|
-
priority,
|
|
1276
|
-
status,
|
|
1277
|
-
source,
|
|
1278
|
-
todayOnly,
|
|
1279
|
-
tags,
|
|
1280
|
-
},
|
|
1281
|
-
}, null, 2),
|
|
1282
|
-
},
|
|
1283
|
-
],
|
|
1284
|
-
};
|
|
1285
|
-
}
|
|
1286
|
-
catch (error) {
|
|
1287
|
-
return {
|
|
1288
|
-
content: [
|
|
1289
|
-
{
|
|
1290
|
-
type: 'text',
|
|
1291
|
-
text: JSON.stringify({
|
|
1292
|
-
error: true,
|
|
1293
|
-
message: `TODOリストの取得に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1294
|
-
}, null, 2),
|
|
1295
|
-
},
|
|
1296
|
-
],
|
|
1297
|
-
};
|
|
1298
|
-
}
|
|
1299
|
-
});
|
|
1300
|
-
// update_task_status
|
|
593
|
+
}, async (args) => handleListTodos(this.createReminderTodoContext(), {
|
|
594
|
+
priority: args.priority,
|
|
595
|
+
status: args.status,
|
|
596
|
+
source: args.source,
|
|
597
|
+
todayOnly: args.todayOnly,
|
|
598
|
+
tags: args.tags,
|
|
599
|
+
}));
|
|
600
|
+
// update_task_status - uses extracted handler
|
|
1301
601
|
this.registerTool({
|
|
1302
602
|
name: 'update_task_status',
|
|
1303
603
|
description: 'Update the status of a task in Apple Reminders or Notion.',
|
|
@@ -1322,80 +622,13 @@ class MCPHandlerImpl {
|
|
|
1322
622
|
},
|
|
1323
623
|
required: ['taskId', 'status', 'source'],
|
|
1324
624
|
},
|
|
1325
|
-
}, async (args) => {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
error: true,
|
|
1333
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1334
|
-
}, null, 2),
|
|
1335
|
-
},
|
|
1336
|
-
],
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
if (!this.todoListManager) {
|
|
1340
|
-
this.initializeServices(this.config);
|
|
1341
|
-
}
|
|
1342
|
-
try {
|
|
1343
|
-
const taskId = args.taskId;
|
|
1344
|
-
const status = args.status;
|
|
1345
|
-
const source = args.source;
|
|
1346
|
-
const syncAcrossSources = args.syncAcrossSources;
|
|
1347
|
-
const result = await this.todoListManager.updateTaskStatus(taskId, status, source);
|
|
1348
|
-
if (!result.success) {
|
|
1349
|
-
return {
|
|
1350
|
-
content: [
|
|
1351
|
-
{
|
|
1352
|
-
type: 'text',
|
|
1353
|
-
text: JSON.stringify({
|
|
1354
|
-
success: false,
|
|
1355
|
-
taskId,
|
|
1356
|
-
error: result.error,
|
|
1357
|
-
message: `タスクステータスの更新に失敗しました: ${result.error}`,
|
|
1358
|
-
}, null, 2),
|
|
1359
|
-
},
|
|
1360
|
-
],
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
let syncResult;
|
|
1364
|
-
if (syncAcrossSources) {
|
|
1365
|
-
syncResult = await this.todoListManager.syncTaskAcrossSources(taskId);
|
|
1366
|
-
}
|
|
1367
|
-
return {
|
|
1368
|
-
content: [
|
|
1369
|
-
{
|
|
1370
|
-
type: 'text',
|
|
1371
|
-
text: JSON.stringify({
|
|
1372
|
-
success: true,
|
|
1373
|
-
taskId,
|
|
1374
|
-
newStatus: status,
|
|
1375
|
-
updatedFields: result.updatedFields,
|
|
1376
|
-
syncedSources: result.syncedSources,
|
|
1377
|
-
syncResult: syncAcrossSources ? syncResult : undefined,
|
|
1378
|
-
message: `タスクのステータスを「${status}」に更新しました。`,
|
|
1379
|
-
}, null, 2),
|
|
1380
|
-
},
|
|
1381
|
-
],
|
|
1382
|
-
};
|
|
1383
|
-
}
|
|
1384
|
-
catch (error) {
|
|
1385
|
-
return {
|
|
1386
|
-
content: [
|
|
1387
|
-
{
|
|
1388
|
-
type: 'text',
|
|
1389
|
-
text: JSON.stringify({
|
|
1390
|
-
error: true,
|
|
1391
|
-
message: `タスクステータスの更新に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1392
|
-
}, null, 2),
|
|
1393
|
-
},
|
|
1394
|
-
],
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
});
|
|
1398
|
-
// sync_tasks
|
|
625
|
+
}, async (args) => handleUpdateTaskStatus(this.createTaskToolsContext(), {
|
|
626
|
+
taskId: args.taskId,
|
|
627
|
+
status: args.status,
|
|
628
|
+
source: args.source,
|
|
629
|
+
syncAcrossSources: args.syncAcrossSources,
|
|
630
|
+
}));
|
|
631
|
+
// sync_tasks - uses extracted handler
|
|
1399
632
|
this.registerTool({
|
|
1400
633
|
name: 'sync_tasks',
|
|
1401
634
|
description: 'Synchronize tasks between Apple Reminders and Notion, detecting and resolving conflicts.',
|
|
@@ -1403,59 +636,8 @@ class MCPHandlerImpl {
|
|
|
1403
636
|
type: 'object',
|
|
1404
637
|
properties: {},
|
|
1405
638
|
},
|
|
1406
|
-
}, async () =>
|
|
1407
|
-
|
|
1408
|
-
return {
|
|
1409
|
-
content: [
|
|
1410
|
-
{
|
|
1411
|
-
type: 'text',
|
|
1412
|
-
text: JSON.stringify({
|
|
1413
|
-
error: true,
|
|
1414
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1415
|
-
}, null, 2),
|
|
1416
|
-
},
|
|
1417
|
-
],
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
if (!this.taskSynchronizer) {
|
|
1421
|
-
this.initializeServices(this.config);
|
|
1422
|
-
}
|
|
1423
|
-
try {
|
|
1424
|
-
const result = await this.taskSynchronizer.syncAllTasks();
|
|
1425
|
-
return {
|
|
1426
|
-
content: [
|
|
1427
|
-
{
|
|
1428
|
-
type: 'text',
|
|
1429
|
-
text: JSON.stringify({
|
|
1430
|
-
success: true,
|
|
1431
|
-
totalTasks: result.totalTasks,
|
|
1432
|
-
syncedTasks: result.syncedTasks,
|
|
1433
|
-
conflicts: result.conflicts,
|
|
1434
|
-
errors: result.errors,
|
|
1435
|
-
durationMs: result.duration,
|
|
1436
|
-
message: result.conflicts.length > 0
|
|
1437
|
-
? `${result.syncedTasks}件のタスクを同期しました。${result.conflicts.length}件の競合が検出されました。`
|
|
1438
|
-
: `${result.syncedTasks}件のタスクを同期しました。`,
|
|
1439
|
-
}, null, 2),
|
|
1440
|
-
},
|
|
1441
|
-
],
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
catch (error) {
|
|
1445
|
-
return {
|
|
1446
|
-
content: [
|
|
1447
|
-
{
|
|
1448
|
-
type: 'text',
|
|
1449
|
-
text: JSON.stringify({
|
|
1450
|
-
error: true,
|
|
1451
|
-
message: `タスク同期に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1452
|
-
}, null, 2),
|
|
1453
|
-
},
|
|
1454
|
-
],
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
|
-
});
|
|
1458
|
-
// detect_duplicates
|
|
639
|
+
}, async () => handleSyncTasks(this.createTaskToolsContext()));
|
|
640
|
+
// detect_duplicates - uses extracted handler
|
|
1459
641
|
this.registerTool({
|
|
1460
642
|
name: 'detect_duplicates',
|
|
1461
643
|
description: 'Detect duplicate tasks between Apple Reminders and Notion.',
|
|
@@ -1468,82 +650,9 @@ class MCPHandlerImpl {
|
|
|
1468
650
|
},
|
|
1469
651
|
},
|
|
1470
652
|
},
|
|
1471
|
-
}, async (args) => {
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
content: [
|
|
1475
|
-
{
|
|
1476
|
-
type: 'text',
|
|
1477
|
-
text: JSON.stringify({
|
|
1478
|
-
error: true,
|
|
1479
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1480
|
-
}, null, 2),
|
|
1481
|
-
},
|
|
1482
|
-
],
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
|
-
if (!this.taskSynchronizer) {
|
|
1486
|
-
this.initializeServices(this.config);
|
|
1487
|
-
}
|
|
1488
|
-
try {
|
|
1489
|
-
const autoMerge = args.autoMerge;
|
|
1490
|
-
const duplicates = await this.taskSynchronizer.detectDuplicates();
|
|
1491
|
-
const formattedDuplicates = duplicates.map((d) => ({
|
|
1492
|
-
tasks: d.tasks.map((t) => ({
|
|
1493
|
-
id: t.id,
|
|
1494
|
-
title: t.title,
|
|
1495
|
-
source: t.source,
|
|
1496
|
-
status: t.status,
|
|
1497
|
-
priority: t.priority,
|
|
1498
|
-
})),
|
|
1499
|
-
similarity: Math.round(d.similarity * 100),
|
|
1500
|
-
confidence: d.confidence,
|
|
1501
|
-
suggestedMerge: {
|
|
1502
|
-
title: d.suggestedMerge.title,
|
|
1503
|
-
priority: d.suggestedMerge.priority,
|
|
1504
|
-
status: d.suggestedMerge.status,
|
|
1505
|
-
tags: d.suggestedMerge.tags,
|
|
1506
|
-
},
|
|
1507
|
-
}));
|
|
1508
|
-
let mergeResults;
|
|
1509
|
-
if (autoMerge) {
|
|
1510
|
-
const highConfidenceDuplicates = duplicates.filter((d) => d.confidence === 'high');
|
|
1511
|
-
if (highConfidenceDuplicates.length > 0) {
|
|
1512
|
-
mergeResults =
|
|
1513
|
-
await this.taskSynchronizer.mergeDuplicates(highConfidenceDuplicates);
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
return {
|
|
1517
|
-
content: [
|
|
1518
|
-
{
|
|
1519
|
-
type: 'text',
|
|
1520
|
-
text: JSON.stringify({
|
|
1521
|
-
success: true,
|
|
1522
|
-
duplicatesFound: duplicates.length,
|
|
1523
|
-
duplicates: formattedDuplicates,
|
|
1524
|
-
mergeResults: autoMerge ? mergeResults : undefined,
|
|
1525
|
-
message: duplicates.length > 0
|
|
1526
|
-
? `${duplicates.length}件の重複タスクが検出されました。`
|
|
1527
|
-
: '重複タスクは見つかりませんでした。',
|
|
1528
|
-
}, null, 2),
|
|
1529
|
-
},
|
|
1530
|
-
],
|
|
1531
|
-
};
|
|
1532
|
-
}
|
|
1533
|
-
catch (error) {
|
|
1534
|
-
return {
|
|
1535
|
-
content: [
|
|
1536
|
-
{
|
|
1537
|
-
type: 'text',
|
|
1538
|
-
text: JSON.stringify({
|
|
1539
|
-
error: true,
|
|
1540
|
-
message: `重複検出に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1541
|
-
}, null, 2),
|
|
1542
|
-
},
|
|
1543
|
-
],
|
|
1544
|
-
};
|
|
1545
|
-
}
|
|
1546
|
-
});
|
|
653
|
+
}, async (args) => handleDetectDuplicates(this.createTaskToolsContext(), {
|
|
654
|
+
autoMerge: args.autoMerge,
|
|
655
|
+
}));
|
|
1547
656
|
// get_working_cadence
|
|
1548
657
|
this.registerTool({
|
|
1549
658
|
name: 'get_working_cadence',
|
|
@@ -1643,97 +752,11 @@ class MCPHandlerImpl {
|
|
|
1643
752
|
},
|
|
1644
753
|
required: ['eventId', 'response'],
|
|
1645
754
|
},
|
|
1646
|
-
}, async (args) => {
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
type: 'text',
|
|
1652
|
-
text: JSON.stringify({
|
|
1653
|
-
error: true,
|
|
1654
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1655
|
-
}, null, 2),
|
|
1656
|
-
},
|
|
1657
|
-
],
|
|
1658
|
-
};
|
|
1659
|
-
}
|
|
1660
|
-
if (!this.calendarEventResponseService) {
|
|
1661
|
-
this.initializeServices(this.config);
|
|
1662
|
-
}
|
|
1663
|
-
try {
|
|
1664
|
-
const eventId = args.eventId;
|
|
1665
|
-
const response = args.response;
|
|
1666
|
-
const comment = args.comment;
|
|
1667
|
-
const isAvailable = await this.calendarEventResponseService.isEventKitAvailable();
|
|
1668
|
-
if (!isAvailable) {
|
|
1669
|
-
return {
|
|
1670
|
-
content: [
|
|
1671
|
-
{
|
|
1672
|
-
type: 'text',
|
|
1673
|
-
text: JSON.stringify({
|
|
1674
|
-
success: false,
|
|
1675
|
-
message: 'カレンダーイベント返信機能はmacOSでのみ利用可能です。',
|
|
1676
|
-
}, null, 2),
|
|
1677
|
-
},
|
|
1678
|
-
],
|
|
1679
|
-
};
|
|
1680
|
-
}
|
|
1681
|
-
const result = await this.calendarEventResponseService.respondToEvent({
|
|
1682
|
-
eventId,
|
|
1683
|
-
response,
|
|
1684
|
-
comment,
|
|
1685
|
-
});
|
|
1686
|
-
if (result.success) {
|
|
1687
|
-
return {
|
|
1688
|
-
content: [
|
|
1689
|
-
{
|
|
1690
|
-
type: 'text',
|
|
1691
|
-
text: JSON.stringify({
|
|
1692
|
-
success: true,
|
|
1693
|
-
eventId: result.eventId,
|
|
1694
|
-
eventTitle: result.eventTitle,
|
|
1695
|
-
newStatus: result.newStatus,
|
|
1696
|
-
method: result.method,
|
|
1697
|
-
instanceOnly: result.instanceOnly,
|
|
1698
|
-
message: result.message,
|
|
1699
|
-
}, null, 2),
|
|
1700
|
-
},
|
|
1701
|
-
],
|
|
1702
|
-
};
|
|
1703
|
-
}
|
|
1704
|
-
return {
|
|
1705
|
-
content: [
|
|
1706
|
-
{
|
|
1707
|
-
type: 'text',
|
|
1708
|
-
text: JSON.stringify({
|
|
1709
|
-
success: false,
|
|
1710
|
-
eventId: result.eventId,
|
|
1711
|
-
eventTitle: result.eventTitle,
|
|
1712
|
-
skipped: result.skipped,
|
|
1713
|
-
reason: result.reason,
|
|
1714
|
-
error: result.error,
|
|
1715
|
-
message: result.skipped
|
|
1716
|
-
? `イベントをスキップしました: ${result.reason}`
|
|
1717
|
-
: `イベント返信に失敗しました: ${result.error}`,
|
|
1718
|
-
}, null, 2),
|
|
1719
|
-
},
|
|
1720
|
-
],
|
|
1721
|
-
};
|
|
1722
|
-
}
|
|
1723
|
-
catch (error) {
|
|
1724
|
-
return {
|
|
1725
|
-
content: [
|
|
1726
|
-
{
|
|
1727
|
-
type: 'text',
|
|
1728
|
-
text: JSON.stringify({
|
|
1729
|
-
error: true,
|
|
1730
|
-
message: `カレンダーイベント返信に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1731
|
-
}, null, 2),
|
|
1732
|
-
},
|
|
1733
|
-
],
|
|
1734
|
-
};
|
|
1735
|
-
}
|
|
1736
|
-
});
|
|
755
|
+
}, async (args) => handleRespondToCalendarEvent(this.createCalendarToolsContext(), {
|
|
756
|
+
eventId: args.eventId,
|
|
757
|
+
response: args.response,
|
|
758
|
+
comment: args.comment,
|
|
759
|
+
}));
|
|
1737
760
|
// respond_to_calendar_events_batch
|
|
1738
761
|
this.registerTool({
|
|
1739
762
|
name: 'respond_to_calendar_events_batch',
|
|
@@ -1758,78 +781,11 @@ class MCPHandlerImpl {
|
|
|
1758
781
|
},
|
|
1759
782
|
required: ['eventIds', 'response'],
|
|
1760
783
|
},
|
|
1761
|
-
}, async (args) => {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
type: 'text',
|
|
1767
|
-
text: JSON.stringify({
|
|
1768
|
-
error: true,
|
|
1769
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1770
|
-
}, null, 2),
|
|
1771
|
-
},
|
|
1772
|
-
],
|
|
1773
|
-
};
|
|
1774
|
-
}
|
|
1775
|
-
if (!this.calendarEventResponseService) {
|
|
1776
|
-
this.initializeServices(this.config);
|
|
1777
|
-
}
|
|
1778
|
-
try {
|
|
1779
|
-
const eventIds = args.eventIds;
|
|
1780
|
-
const response = args.response;
|
|
1781
|
-
const comment = args.comment;
|
|
1782
|
-
const isAvailable = await this.calendarEventResponseService.isEventKitAvailable();
|
|
1783
|
-
if (!isAvailable) {
|
|
1784
|
-
return {
|
|
1785
|
-
content: [
|
|
1786
|
-
{
|
|
1787
|
-
type: 'text',
|
|
1788
|
-
text: JSON.stringify({
|
|
1789
|
-
success: false,
|
|
1790
|
-
message: 'カレンダーイベント返信機能はmacOSでのみ利用可能です。',
|
|
1791
|
-
}, null, 2),
|
|
1792
|
-
},
|
|
1793
|
-
],
|
|
1794
|
-
};
|
|
1795
|
-
}
|
|
1796
|
-
const result = await this.calendarEventResponseService.respondToEventsBatch({
|
|
1797
|
-
eventIds,
|
|
1798
|
-
response,
|
|
1799
|
-
comment,
|
|
1800
|
-
});
|
|
1801
|
-
return {
|
|
1802
|
-
content: [
|
|
1803
|
-
{
|
|
1804
|
-
type: 'text',
|
|
1805
|
-
text: JSON.stringify({
|
|
1806
|
-
success: result.success,
|
|
1807
|
-
summary: result.summary,
|
|
1808
|
-
details: {
|
|
1809
|
-
succeeded: result.details.succeeded,
|
|
1810
|
-
skipped: result.details.skipped,
|
|
1811
|
-
failed: result.details.failed,
|
|
1812
|
-
},
|
|
1813
|
-
message: result.message,
|
|
1814
|
-
}, null, 2),
|
|
1815
|
-
},
|
|
1816
|
-
],
|
|
1817
|
-
};
|
|
1818
|
-
}
|
|
1819
|
-
catch (error) {
|
|
1820
|
-
return {
|
|
1821
|
-
content: [
|
|
1822
|
-
{
|
|
1823
|
-
type: 'text',
|
|
1824
|
-
text: JSON.stringify({
|
|
1825
|
-
error: true,
|
|
1826
|
-
message: `カレンダーイベント一括返信に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1827
|
-
}, null, 2),
|
|
1828
|
-
},
|
|
1829
|
-
],
|
|
1830
|
-
};
|
|
1831
|
-
}
|
|
1832
|
-
});
|
|
784
|
+
}, async (args) => handleRespondToCalendarEventsBatch(this.createCalendarToolsContext(), {
|
|
785
|
+
eventIds: args.eventIds,
|
|
786
|
+
response: args.response,
|
|
787
|
+
comment: args.comment,
|
|
788
|
+
}));
|
|
1833
789
|
// create_calendar_event
|
|
1834
790
|
this.registerTool({
|
|
1835
791
|
name: 'create_calendar_event',
|
|
@@ -1860,100 +816,14 @@ class MCPHandlerImpl {
|
|
|
1860
816
|
},
|
|
1861
817
|
required: ['title', 'startDate', 'endDate'],
|
|
1862
818
|
},
|
|
1863
|
-
}, async (args) => {
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1872
|
-
}, null, 2),
|
|
1873
|
-
},
|
|
1874
|
-
],
|
|
1875
|
-
};
|
|
1876
|
-
}
|
|
1877
|
-
if (!this.calendarEventCreatorService) {
|
|
1878
|
-
this.initializeServices(this.config);
|
|
1879
|
-
}
|
|
1880
|
-
try {
|
|
1881
|
-
const title = args.title;
|
|
1882
|
-
const startDate = args.startDate;
|
|
1883
|
-
const endDate = args.endDate;
|
|
1884
|
-
const location = args.location;
|
|
1885
|
-
const notes = args.notes;
|
|
1886
|
-
const calendarName = args.calendarName;
|
|
1887
|
-
const alarms = args.alarms;
|
|
1888
|
-
const isAvailable = await this.calendarEventCreatorService.isEventKitAvailable();
|
|
1889
|
-
if (!isAvailable) {
|
|
1890
|
-
return {
|
|
1891
|
-
content: [
|
|
1892
|
-
{
|
|
1893
|
-
type: 'text',
|
|
1894
|
-
text: JSON.stringify({
|
|
1895
|
-
success: false,
|
|
1896
|
-
message: 'カレンダーイベント作成機能はmacOSでのみ利用可能です。',
|
|
1897
|
-
}, null, 2),
|
|
1898
|
-
},
|
|
1899
|
-
],
|
|
1900
|
-
};
|
|
1901
|
-
}
|
|
1902
|
-
const result = await this.calendarEventCreatorService.createEvent({
|
|
1903
|
-
title,
|
|
1904
|
-
startDate,
|
|
1905
|
-
endDate,
|
|
1906
|
-
location,
|
|
1907
|
-
notes,
|
|
1908
|
-
calendarName,
|
|
1909
|
-
alarms,
|
|
1910
|
-
});
|
|
1911
|
-
if (result.success) {
|
|
1912
|
-
return {
|
|
1913
|
-
content: [
|
|
1914
|
-
{
|
|
1915
|
-
type: 'text',
|
|
1916
|
-
text: JSON.stringify({
|
|
1917
|
-
success: true,
|
|
1918
|
-
eventId: result.eventId,
|
|
1919
|
-
title: result.title,
|
|
1920
|
-
startDate: result.startDate,
|
|
1921
|
-
endDate: result.endDate,
|
|
1922
|
-
calendarName: result.calendarName,
|
|
1923
|
-
isAllDay: result.isAllDay,
|
|
1924
|
-
message: result.message,
|
|
1925
|
-
}, null, 2),
|
|
1926
|
-
},
|
|
1927
|
-
],
|
|
1928
|
-
};
|
|
1929
|
-
}
|
|
1930
|
-
return {
|
|
1931
|
-
content: [
|
|
1932
|
-
{
|
|
1933
|
-
type: 'text',
|
|
1934
|
-
text: JSON.stringify({
|
|
1935
|
-
success: false,
|
|
1936
|
-
error: result.error,
|
|
1937
|
-
message: result.message,
|
|
1938
|
-
}, null, 2),
|
|
1939
|
-
},
|
|
1940
|
-
],
|
|
1941
|
-
};
|
|
1942
|
-
}
|
|
1943
|
-
catch (error) {
|
|
1944
|
-
return {
|
|
1945
|
-
content: [
|
|
1946
|
-
{
|
|
1947
|
-
type: 'text',
|
|
1948
|
-
text: JSON.stringify({
|
|
1949
|
-
error: true,
|
|
1950
|
-
message: `カレンダーイベント作成に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1951
|
-
}, null, 2),
|
|
1952
|
-
},
|
|
1953
|
-
],
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
});
|
|
819
|
+
}, async (args) => handleCreateCalendarEvent(this.createCalendarToolsContext(), {
|
|
820
|
+
title: args.title,
|
|
821
|
+
startDate: args.startDate,
|
|
822
|
+
endDate: args.endDate,
|
|
823
|
+
location: args.location,
|
|
824
|
+
notes: args.notes,
|
|
825
|
+
calendarName: args.calendarName,
|
|
826
|
+
}));
|
|
1957
827
|
// delete_calendar_event
|
|
1958
828
|
this.registerTool({
|
|
1959
829
|
name: 'delete_calendar_event',
|
|
@@ -1972,88 +842,9 @@ class MCPHandlerImpl {
|
|
|
1972
842
|
},
|
|
1973
843
|
required: ['eventId'],
|
|
1974
844
|
},
|
|
1975
|
-
}, async (args) => {
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
content: [
|
|
1979
|
-
{
|
|
1980
|
-
type: 'text',
|
|
1981
|
-
text: JSON.stringify({
|
|
1982
|
-
error: true,
|
|
1983
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
1984
|
-
}, null, 2),
|
|
1985
|
-
},
|
|
1986
|
-
],
|
|
1987
|
-
};
|
|
1988
|
-
}
|
|
1989
|
-
if (!this.calendarEventDeleterService) {
|
|
1990
|
-
this.initializeServices(this.config);
|
|
1991
|
-
}
|
|
1992
|
-
try {
|
|
1993
|
-
const eventId = args.eventId;
|
|
1994
|
-
const calendarName = args.calendarName;
|
|
1995
|
-
const isAvailable = await this.calendarEventDeleterService.isEventKitAvailable();
|
|
1996
|
-
if (!isAvailable) {
|
|
1997
|
-
return {
|
|
1998
|
-
content: [
|
|
1999
|
-
{
|
|
2000
|
-
type: 'text',
|
|
2001
|
-
text: JSON.stringify({
|
|
2002
|
-
success: false,
|
|
2003
|
-
message: 'カレンダーイベント削除機能はmacOSでのみ利用可能です。',
|
|
2004
|
-
}, null, 2),
|
|
2005
|
-
},
|
|
2006
|
-
],
|
|
2007
|
-
};
|
|
2008
|
-
}
|
|
2009
|
-
const result = await this.calendarEventDeleterService.deleteEvent({
|
|
2010
|
-
eventId,
|
|
2011
|
-
calendarName,
|
|
2012
|
-
});
|
|
2013
|
-
if (result.success) {
|
|
2014
|
-
return {
|
|
2015
|
-
content: [
|
|
2016
|
-
{
|
|
2017
|
-
type: 'text',
|
|
2018
|
-
text: JSON.stringify({
|
|
2019
|
-
success: true,
|
|
2020
|
-
eventId: result.eventId,
|
|
2021
|
-
title: result.title,
|
|
2022
|
-
calendarName: result.calendarName,
|
|
2023
|
-
message: result.message,
|
|
2024
|
-
}, null, 2),
|
|
2025
|
-
},
|
|
2026
|
-
],
|
|
2027
|
-
};
|
|
2028
|
-
}
|
|
2029
|
-
return {
|
|
2030
|
-
content: [
|
|
2031
|
-
{
|
|
2032
|
-
type: 'text',
|
|
2033
|
-
text: JSON.stringify({
|
|
2034
|
-
success: false,
|
|
2035
|
-
eventId: result.eventId,
|
|
2036
|
-
error: result.error,
|
|
2037
|
-
message: result.message,
|
|
2038
|
-
}, null, 2),
|
|
2039
|
-
},
|
|
2040
|
-
],
|
|
2041
|
-
};
|
|
2042
|
-
}
|
|
2043
|
-
catch (error) {
|
|
2044
|
-
return {
|
|
2045
|
-
content: [
|
|
2046
|
-
{
|
|
2047
|
-
type: 'text',
|
|
2048
|
-
text: JSON.stringify({
|
|
2049
|
-
error: true,
|
|
2050
|
-
message: `カレンダーイベント削除に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
2051
|
-
}, null, 2),
|
|
2052
|
-
},
|
|
2053
|
-
],
|
|
2054
|
-
};
|
|
2055
|
-
}
|
|
2056
|
-
});
|
|
845
|
+
}, async (args) => handleDeleteCalendarEvent(this.createCalendarToolsContext(), {
|
|
846
|
+
eventId: args.eventId,
|
|
847
|
+
}));
|
|
2057
848
|
// delete_calendar_events_batch
|
|
2058
849
|
this.registerTool({
|
|
2059
850
|
name: 'delete_calendar_events_batch',
|
|
@@ -2073,80 +864,18 @@ class MCPHandlerImpl {
|
|
|
2073
864
|
},
|
|
2074
865
|
required: ['eventIds'],
|
|
2075
866
|
},
|
|
2076
|
-
}, async (args) => {
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
};
|
|
2089
|
-
}
|
|
2090
|
-
if (!this.calendarEventDeleterService) {
|
|
2091
|
-
this.initializeServices(this.config);
|
|
2092
|
-
}
|
|
2093
|
-
try {
|
|
2094
|
-
const eventIds = args.eventIds;
|
|
2095
|
-
const calendarName = args.calendarName;
|
|
2096
|
-
const isAvailable = await this.calendarEventDeleterService.isEventKitAvailable();
|
|
2097
|
-
if (!isAvailable) {
|
|
2098
|
-
return {
|
|
2099
|
-
content: [
|
|
2100
|
-
{
|
|
2101
|
-
type: 'text',
|
|
2102
|
-
text: JSON.stringify({
|
|
2103
|
-
success: false,
|
|
2104
|
-
message: 'カレンダーイベント削除機能はmacOSでのみ利用可能です。',
|
|
2105
|
-
}, null, 2),
|
|
2106
|
-
},
|
|
2107
|
-
],
|
|
2108
|
-
};
|
|
2109
|
-
}
|
|
2110
|
-
const result = await this.calendarEventDeleterService.deleteEventsBatch({
|
|
2111
|
-
eventIds,
|
|
2112
|
-
calendarName,
|
|
2113
|
-
});
|
|
2114
|
-
return {
|
|
2115
|
-
content: [
|
|
2116
|
-
{
|
|
2117
|
-
type: 'text',
|
|
2118
|
-
text: JSON.stringify({
|
|
2119
|
-
success: result.success,
|
|
2120
|
-
totalCount: result.totalCount,
|
|
2121
|
-
successCount: result.successCount,
|
|
2122
|
-
failedCount: result.failedCount,
|
|
2123
|
-
results: result.results.map((r) => ({
|
|
2124
|
-
eventId: r.eventId,
|
|
2125
|
-
success: r.success,
|
|
2126
|
-
title: r.title,
|
|
2127
|
-
calendarName: r.calendarName,
|
|
2128
|
-
error: r.error,
|
|
2129
|
-
})),
|
|
2130
|
-
message: result.message,
|
|
2131
|
-
}, null, 2),
|
|
2132
|
-
},
|
|
2133
|
-
],
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
catch (error) {
|
|
2137
|
-
return {
|
|
2138
|
-
content: [
|
|
2139
|
-
{
|
|
2140
|
-
type: 'text',
|
|
2141
|
-
text: JSON.stringify({
|
|
2142
|
-
error: true,
|
|
2143
|
-
message: `カレンダーイベント一括削除に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
2144
|
-
}, null, 2),
|
|
2145
|
-
},
|
|
2146
|
-
],
|
|
2147
|
-
};
|
|
2148
|
-
}
|
|
2149
|
-
});
|
|
867
|
+
}, async (args) => handleDeleteCalendarEventsBatch(this.createCalendarToolsContext(), {
|
|
868
|
+
eventIds: args.eventIds,
|
|
869
|
+
}));
|
|
870
|
+
// list_calendar_sources - uses extracted handler
|
|
871
|
+
this.registerTool({
|
|
872
|
+
name: 'list_calendar_sources',
|
|
873
|
+
description: 'List available and enabled calendar sources.',
|
|
874
|
+
inputSchema: {
|
|
875
|
+
type: 'object',
|
|
876
|
+
properties: {},
|
|
877
|
+
},
|
|
878
|
+
}, async () => handleListCalendarSources(this.createCalendarToolsContext()));
|
|
2150
879
|
}
|
|
2151
880
|
/**
|
|
2152
881
|
* Register a tool
|
|
@@ -2154,108 +883,6 @@ class MCPHandlerImpl {
|
|
|
2154
883
|
registerTool(definition, handler) {
|
|
2155
884
|
this.tools.set(definition.name, { definition, handler });
|
|
2156
885
|
}
|
|
2157
|
-
/**
|
|
2158
|
-
* Validate config updates
|
|
2159
|
-
*/
|
|
2160
|
-
validateConfigUpdate(section, updates) {
|
|
2161
|
-
const invalidFields = [];
|
|
2162
|
-
switch (section) {
|
|
2163
|
-
case 'user':
|
|
2164
|
-
if (updates.name !== undefined && typeof updates.name !== 'string') {
|
|
2165
|
-
invalidFields.push('name');
|
|
2166
|
-
}
|
|
2167
|
-
if (updates.timezone !== undefined && typeof updates.timezone !== 'string') {
|
|
2168
|
-
invalidFields.push('timezone');
|
|
2169
|
-
}
|
|
2170
|
-
break;
|
|
2171
|
-
case 'calendar':
|
|
2172
|
-
if (updates.workingHours !== undefined) {
|
|
2173
|
-
const wh = updates.workingHours;
|
|
2174
|
-
if (!wh.start || !wh.end) {
|
|
2175
|
-
invalidFields.push('workingHours');
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
if (updates.deepWorkDays !== undefined && !Array.isArray(updates.deepWorkDays)) {
|
|
2179
|
-
invalidFields.push('deepWorkDays');
|
|
2180
|
-
}
|
|
2181
|
-
if (updates.meetingHeavyDays !== undefined &&
|
|
2182
|
-
!Array.isArray(updates.meetingHeavyDays)) {
|
|
2183
|
-
invalidFields.push('meetingHeavyDays');
|
|
2184
|
-
}
|
|
2185
|
-
break;
|
|
2186
|
-
case 'integrations':
|
|
2187
|
-
if (updates.notion !== undefined) {
|
|
2188
|
-
const notion = updates.notion;
|
|
2189
|
-
if (notion.enabled === true && !notion.databaseId) {
|
|
2190
|
-
invalidFields.push('notion.databaseId');
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2193
|
-
break;
|
|
2194
|
-
case 'team':
|
|
2195
|
-
if (updates.members !== undefined && !Array.isArray(updates.members)) {
|
|
2196
|
-
invalidFields.push('members');
|
|
2197
|
-
}
|
|
2198
|
-
if (updates.managers !== undefined && !Array.isArray(updates.managers)) {
|
|
2199
|
-
invalidFields.push('managers');
|
|
2200
|
-
}
|
|
2201
|
-
break;
|
|
2202
|
-
}
|
|
2203
|
-
if (invalidFields.length > 0) {
|
|
2204
|
-
return {
|
|
2205
|
-
valid: false,
|
|
2206
|
-
error: `無効なフィールド: ${invalidFields.join(', ')}`,
|
|
2207
|
-
invalidFields,
|
|
2208
|
-
};
|
|
2209
|
-
}
|
|
2210
|
-
return { valid: true };
|
|
2211
|
-
}
|
|
2212
|
-
/**
|
|
2213
|
-
* Apply config updates
|
|
2214
|
-
*/
|
|
2215
|
-
applyConfigUpdates(currentConfig, section, updates) {
|
|
2216
|
-
const newConfig = { ...currentConfig };
|
|
2217
|
-
switch (section) {
|
|
2218
|
-
case 'user':
|
|
2219
|
-
newConfig.user = { ...newConfig.user, ...updates };
|
|
2220
|
-
break;
|
|
2221
|
-
case 'calendar':
|
|
2222
|
-
newConfig.calendar = {
|
|
2223
|
-
...newConfig.calendar,
|
|
2224
|
-
...updates,
|
|
2225
|
-
};
|
|
2226
|
-
break;
|
|
2227
|
-
case 'priorityRules':
|
|
2228
|
-
newConfig.priorityRules = {
|
|
2229
|
-
...newConfig.priorityRules,
|
|
2230
|
-
...updates,
|
|
2231
|
-
};
|
|
2232
|
-
break;
|
|
2233
|
-
case 'integrations':
|
|
2234
|
-
if (updates.appleReminders) {
|
|
2235
|
-
newConfig.integrations.appleReminders = {
|
|
2236
|
-
...newConfig.integrations.appleReminders,
|
|
2237
|
-
...updates.appleReminders,
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
|
-
if (updates.notion) {
|
|
2241
|
-
newConfig.integrations.notion = {
|
|
2242
|
-
...newConfig.integrations.notion,
|
|
2243
|
-
...updates.notion,
|
|
2244
|
-
};
|
|
2245
|
-
}
|
|
2246
|
-
break;
|
|
2247
|
-
case 'team':
|
|
2248
|
-
newConfig.team = { ...newConfig.team, ...updates };
|
|
2249
|
-
break;
|
|
2250
|
-
case 'preferences':
|
|
2251
|
-
newConfig.preferences = {
|
|
2252
|
-
...newConfig.preferences,
|
|
2253
|
-
...updates,
|
|
2254
|
-
};
|
|
2255
|
-
break;
|
|
2256
|
-
}
|
|
2257
|
-
return newConfig;
|
|
2258
|
-
}
|
|
2259
886
|
}
|
|
2260
887
|
/**
|
|
2261
888
|
* Create an MCP handler
|