@shin1ohno/sage 0.7.9 → 0.8.6
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/README.md +26 -8
- package/dist/cli/mcp-handler.d.ts.map +1 -1
- package/dist/cli/mcp-handler.js +141 -987
- package/dist/cli/mcp-handler.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +30 -1
- package/dist/config/loader.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/config/validation.d.ts +130 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +53 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/index.js +443 -1632
- 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/calendar-service.d.ts +6 -3
- package/dist/integrations/calendar-service.d.ts.map +1 -1
- package/dist/integrations/calendar-service.js +26 -4
- package/dist/integrations/calendar-service.js.map +1 -1
- package/dist/integrations/calendar-source-manager.d.ts +302 -0
- package/dist/integrations/calendar-source-manager.d.ts.map +1 -0
- package/dist/integrations/calendar-source-manager.js +862 -0
- package/dist/integrations/calendar-source-manager.js.map +1 -0
- package/dist/integrations/google-calendar-service.d.ts +176 -0
- package/dist/integrations/google-calendar-service.d.ts.map +1 -0
- package/dist/integrations/google-calendar-service.js +745 -0
- package/dist/integrations/google-calendar-service.js.map +1 -0
- 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/oauth/google-oauth-handler.d.ts +149 -0
- package/dist/oauth/google-oauth-handler.d.ts.map +1 -0
- package/dist/oauth/google-oauth-handler.js +365 -0
- package/dist/oauth/google-oauth-handler.js.map +1 -0
- 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/types/config.d.ts +15 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +21 -0
- package/dist/types/config.js.map +1 -1
- package/dist/types/google-calendar-types.d.ts +139 -0
- package/dist/types/google-calendar-types.d.ts.map +1 -0
- package/dist/types/google-calendar-types.js +46 -0
- package/dist/types/google-calendar-types.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- 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.d.ts +2 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +22 -4
- package/dist/version.js.map +1 -1
- package/package.json +4 -3
- 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,8 +6,6 @@
|
|
|
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';
|
|
@@ -17,6 +15,11 @@ import { CalendarEventResponseService } from '../integrations/calendar-event-res
|
|
|
17
15
|
import { CalendarEventCreatorService } from '../integrations/calendar-event-creator.js';
|
|
18
16
|
import { CalendarEventDeleterService } from '../integrations/calendar-event-deleter.js';
|
|
19
17
|
import { WorkingCadenceService } from '../services/working-cadence.js';
|
|
18
|
+
// Extracted tool handlers
|
|
19
|
+
import { handleCheckSetupStatus, handleStartSetupWizard, handleAnswerWizardQuestion, handleSaveConfig, } from '../tools/setup/index.js';
|
|
20
|
+
import { handleAnalyzeTasks, handleUpdateTaskStatus, handleSyncTasks, handleDetectDuplicates, } from '../tools/tasks/index.js';
|
|
21
|
+
import { handleSetReminder, handleListTodos, } from '../tools/reminders/index.js';
|
|
22
|
+
import { handleSyncToNotion, handleUpdateConfig, } from '../tools/integrations/index.js';
|
|
20
23
|
// Protocol version
|
|
21
24
|
const PROTOCOL_VERSION = '2024-11-05';
|
|
22
25
|
/**
|
|
@@ -76,6 +79,57 @@ class MCPHandlerImpl {
|
|
|
76
79
|
this.calendarEventDeleterService = new CalendarEventDeleterService();
|
|
77
80
|
this.workingCadenceService = new WorkingCadenceService();
|
|
78
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Create SetupContext for setup tool handlers
|
|
84
|
+
*/
|
|
85
|
+
createSetupContext() {
|
|
86
|
+
return {
|
|
87
|
+
getConfig: () => this.config,
|
|
88
|
+
setConfig: (config) => {
|
|
89
|
+
this.config = config;
|
|
90
|
+
},
|
|
91
|
+
getWizardSession: () => this.wizardSession,
|
|
92
|
+
setWizardSession: (session) => {
|
|
93
|
+
this.wizardSession = session;
|
|
94
|
+
},
|
|
95
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create TaskToolsContext for task tool handlers
|
|
100
|
+
*/
|
|
101
|
+
createTaskToolsContext() {
|
|
102
|
+
return {
|
|
103
|
+
getConfig: () => this.config,
|
|
104
|
+
getTodoListManager: () => this.todoListManager,
|
|
105
|
+
getTaskSynchronizer: () => this.taskSynchronizer,
|
|
106
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create ReminderTodoContext for reminder/todo tool handlers
|
|
111
|
+
*/
|
|
112
|
+
createReminderTodoContext() {
|
|
113
|
+
return {
|
|
114
|
+
getConfig: () => this.config,
|
|
115
|
+
getReminderManager: () => this.reminderManager,
|
|
116
|
+
getTodoListManager: () => this.todoListManager,
|
|
117
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create IntegrationToolsContext for integration tool handlers
|
|
122
|
+
*/
|
|
123
|
+
createIntegrationToolsContext() {
|
|
124
|
+
return {
|
|
125
|
+
getConfig: () => this.config,
|
|
126
|
+
setConfig: (config) => {
|
|
127
|
+
this.config = config;
|
|
128
|
+
},
|
|
129
|
+
getNotionService: () => this.notionService,
|
|
130
|
+
initializeServices: (config) => this.initializeServices(config),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
79
133
|
/**
|
|
80
134
|
* Handle an MCP request
|
|
81
135
|
*/
|
|
@@ -209,7 +263,7 @@ class MCPHandlerImpl {
|
|
|
209
263
|
* Register all tools
|
|
210
264
|
*/
|
|
211
265
|
registerTools() {
|
|
212
|
-
// check_setup_status
|
|
266
|
+
// check_setup_status - uses extracted handler
|
|
213
267
|
this.registerTool({
|
|
214
268
|
name: 'check_setup_status',
|
|
215
269
|
description: 'Check if sage has been configured. Returns setup status and guidance.',
|
|
@@ -217,61 +271,8 @@ class MCPHandlerImpl {
|
|
|
217
271
|
type: 'object',
|
|
218
272
|
properties: {},
|
|
219
273
|
},
|
|
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
|
|
274
|
+
}, async () => handleCheckSetupStatus(this.createSetupContext()));
|
|
275
|
+
// start_setup_wizard - uses extracted handler
|
|
275
276
|
this.registerTool({
|
|
276
277
|
name: 'start_setup_wizard',
|
|
277
278
|
description: 'Start the interactive setup wizard for sage. Returns the first question.',
|
|
@@ -285,34 +286,10 @@ class MCPHandlerImpl {
|
|
|
285
286
|
},
|
|
286
287
|
},
|
|
287
288
|
},
|
|
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
|
|
289
|
+
}, async (args) => handleStartSetupWizard(this.createSetupContext(), {
|
|
290
|
+
mode: args.mode,
|
|
291
|
+
}));
|
|
292
|
+
// answer_wizard_question - uses extracted handler
|
|
316
293
|
this.registerTool({
|
|
317
294
|
name: 'answer_wizard_question',
|
|
318
295
|
description: 'Answer a question in the setup wizard and get the next question.',
|
|
@@ -330,77 +307,11 @@ class MCPHandlerImpl {
|
|
|
330
307
|
},
|
|
331
308
|
required: ['questionId', 'answer'],
|
|
332
309
|
},
|
|
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
|
|
310
|
+
}, async (args) => handleAnswerWizardQuestion(this.createSetupContext(), {
|
|
311
|
+
questionId: args.questionId,
|
|
312
|
+
answer: args.answer,
|
|
313
|
+
}));
|
|
314
|
+
// save_config - uses extracted handler
|
|
404
315
|
this.registerTool({
|
|
405
316
|
name: 'save_config',
|
|
406
317
|
description: 'Save the configuration after completing the setup wizard.',
|
|
@@ -414,74 +325,10 @@ class MCPHandlerImpl {
|
|
|
414
325
|
},
|
|
415
326
|
required: ['confirm'],
|
|
416
327
|
},
|
|
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
|
|
328
|
+
}, async (args) => handleSaveConfig(this.createSetupContext(), {
|
|
329
|
+
confirm: args.confirm,
|
|
330
|
+
}));
|
|
331
|
+
// analyze_tasks - uses extracted handler
|
|
485
332
|
this.registerTool({
|
|
486
333
|
name: 'analyze_tasks',
|
|
487
334
|
description: 'Analyze tasks to determine priority, estimate time, and identify stakeholders.',
|
|
@@ -507,61 +354,10 @@ class MCPHandlerImpl {
|
|
|
507
354
|
},
|
|
508
355
|
required: ['tasks'],
|
|
509
356
|
},
|
|
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
|
|
357
|
+
}, async (args) => handleAnalyzeTasks(this.createTaskToolsContext(), {
|
|
358
|
+
tasks: args.tasks,
|
|
359
|
+
}));
|
|
360
|
+
// set_reminder - uses extracted handler
|
|
565
361
|
this.registerTool({
|
|
566
362
|
name: 'set_reminder',
|
|
567
363
|
description: 'Set a reminder for a task in Apple Reminders or Notion.',
|
|
@@ -600,99 +396,14 @@ class MCPHandlerImpl {
|
|
|
600
396
|
},
|
|
601
397
|
required: ['taskTitle'],
|
|
602
398
|
},
|
|
603
|
-
}, async (args) => {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
message: 'sageが設定されていません。check_setup_statusを実行してください。',
|
|
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
|
-
});
|
|
399
|
+
}, async (args) => handleSetReminder(this.createReminderTodoContext(), {
|
|
400
|
+
taskTitle: args.taskTitle,
|
|
401
|
+
dueDate: args.dueDate,
|
|
402
|
+
reminderType: args.reminderType,
|
|
403
|
+
list: args.list,
|
|
404
|
+
priority: args.priority,
|
|
405
|
+
notes: args.notes,
|
|
406
|
+
}));
|
|
696
407
|
// find_available_slots
|
|
697
408
|
this.registerTool({
|
|
698
409
|
name: 'find_available_slots',
|
|
@@ -928,7 +639,7 @@ class MCPHandlerImpl {
|
|
|
928
639
|
};
|
|
929
640
|
}
|
|
930
641
|
});
|
|
931
|
-
// sync_to_notion
|
|
642
|
+
// sync_to_notion - uses extracted handler
|
|
932
643
|
this.registerTool({
|
|
933
644
|
name: 'sync_to_notion',
|
|
934
645
|
description: 'Sync a task to Notion database for long-term tracking.',
|
|
@@ -955,233 +666,45 @@ class MCPHandlerImpl {
|
|
|
955
666
|
},
|
|
956
667
|
required: ['taskTitle'],
|
|
957
668
|
},
|
|
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
|
|
669
|
+
}, async (args) => handleSyncToNotion(this.createIntegrationToolsContext(), {
|
|
670
|
+
taskTitle: args.taskTitle,
|
|
671
|
+
description: args.description,
|
|
672
|
+
priority: args.priority,
|
|
673
|
+
dueDate: args.dueDate,
|
|
674
|
+
stakeholders: args.stakeholders,
|
|
675
|
+
estimatedMinutes: args.estimatedMinutes,
|
|
676
|
+
}));
|
|
677
|
+
// update_config - uses extracted handler
|
|
1093
678
|
this.registerTool({
|
|
1094
679
|
name: 'update_config',
|
|
1095
|
-
description: 'Update sage configuration settings.',
|
|
1096
|
-
inputSchema: {
|
|
1097
|
-
type: 'object',
|
|
1098
|
-
properties: {
|
|
1099
|
-
section: {
|
|
1100
|
-
type: 'string',
|
|
1101
|
-
enum: [
|
|
1102
|
-
'user',
|
|
1103
|
-
'calendar',
|
|
1104
|
-
'priorityRules',
|
|
1105
|
-
'integrations',
|
|
1106
|
-
'team',
|
|
1107
|
-
'preferences',
|
|
1108
|
-
],
|
|
1109
|
-
description: 'Configuration section to update',
|
|
1110
|
-
},
|
|
1111
|
-
updates: {
|
|
1112
|
-
type: 'object',
|
|
1113
|
-
description: 'Key-value pairs to update',
|
|
1114
|
-
},
|
|
1115
|
-
},
|
|
1116
|
-
required: ['section', 'updates'],
|
|
1117
|
-
},
|
|
1118
|
-
}, async (args) => {
|
|
1119
|
-
if (!this.config) {
|
|
1120
|
-
return {
|
|
1121
|
-
content: [
|
|
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
|
-
},
|
|
680
|
+
description: 'Update sage configuration settings.',
|
|
681
|
+
inputSchema: {
|
|
682
|
+
type: 'object',
|
|
683
|
+
properties: {
|
|
684
|
+
section: {
|
|
685
|
+
type: 'string',
|
|
686
|
+
enum: [
|
|
687
|
+
'user',
|
|
688
|
+
'calendar',
|
|
689
|
+
'priorityRules',
|
|
690
|
+
'integrations',
|
|
691
|
+
'team',
|
|
692
|
+
'preferences',
|
|
1147
693
|
],
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
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
|
|
694
|
+
description: 'Configuration section to update',
|
|
695
|
+
},
|
|
696
|
+
updates: {
|
|
697
|
+
type: 'object',
|
|
698
|
+
description: 'Key-value pairs to update',
|
|
699
|
+
},
|
|
700
|
+
},
|
|
701
|
+
required: ['section', 'updates'],
|
|
702
|
+
},
|
|
703
|
+
}, async (args) => handleUpdateConfig(this.createIntegrationToolsContext(), {
|
|
704
|
+
section: args.section,
|
|
705
|
+
updates: args.updates,
|
|
706
|
+
}));
|
|
707
|
+
// list_todos - uses extracted handler
|
|
1185
708
|
this.registerTool({
|
|
1186
709
|
name: 'list_todos',
|
|
1187
710
|
description: 'List TODO items from Apple Reminders and Notion with optional filtering.',
|
|
@@ -1214,90 +737,14 @@ class MCPHandlerImpl {
|
|
|
1214
737
|
},
|
|
1215
738
|
},
|
|
1216
739
|
},
|
|
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
|
|
740
|
+
}, async (args) => handleListTodos(this.createReminderTodoContext(), {
|
|
741
|
+
priority: args.priority,
|
|
742
|
+
status: args.status,
|
|
743
|
+
source: args.source,
|
|
744
|
+
todayOnly: args.todayOnly,
|
|
745
|
+
tags: args.tags,
|
|
746
|
+
}));
|
|
747
|
+
// update_task_status - uses extracted handler
|
|
1301
748
|
this.registerTool({
|
|
1302
749
|
name: 'update_task_status',
|
|
1303
750
|
description: 'Update the status of a task in Apple Reminders or Notion.',
|
|
@@ -1322,80 +769,13 @@ class MCPHandlerImpl {
|
|
|
1322
769
|
},
|
|
1323
770
|
required: ['taskId', 'status', 'source'],
|
|
1324
771
|
},
|
|
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
|
|
772
|
+
}, async (args) => handleUpdateTaskStatus(this.createTaskToolsContext(), {
|
|
773
|
+
taskId: args.taskId,
|
|
774
|
+
status: args.status,
|
|
775
|
+
source: args.source,
|
|
776
|
+
syncAcrossSources: args.syncAcrossSources,
|
|
777
|
+
}));
|
|
778
|
+
// sync_tasks - uses extracted handler
|
|
1399
779
|
this.registerTool({
|
|
1400
780
|
name: 'sync_tasks',
|
|
1401
781
|
description: 'Synchronize tasks between Apple Reminders and Notion, detecting and resolving conflicts.',
|
|
@@ -1403,59 +783,8 @@ class MCPHandlerImpl {
|
|
|
1403
783
|
type: 'object',
|
|
1404
784
|
properties: {},
|
|
1405
785
|
},
|
|
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
|
|
786
|
+
}, async () => handleSyncTasks(this.createTaskToolsContext()));
|
|
787
|
+
// detect_duplicates - uses extracted handler
|
|
1459
788
|
this.registerTool({
|
|
1460
789
|
name: 'detect_duplicates',
|
|
1461
790
|
description: 'Detect duplicate tasks between Apple Reminders and Notion.',
|
|
@@ -1468,82 +797,9 @@ class MCPHandlerImpl {
|
|
|
1468
797
|
},
|
|
1469
798
|
},
|
|
1470
799
|
},
|
|
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
|
-
});
|
|
800
|
+
}, async (args) => handleDetectDuplicates(this.createTaskToolsContext(), {
|
|
801
|
+
autoMerge: args.autoMerge,
|
|
802
|
+
}));
|
|
1547
803
|
// get_working_cadence
|
|
1548
804
|
this.registerTool({
|
|
1549
805
|
name: 'get_working_cadence',
|
|
@@ -2154,108 +1410,6 @@ class MCPHandlerImpl {
|
|
|
2154
1410
|
registerTool(definition, handler) {
|
|
2155
1411
|
this.tools.set(definition.name, { definition, handler });
|
|
2156
1412
|
}
|
|
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
1413
|
}
|
|
2260
1414
|
/**
|
|
2261
1415
|
* Create an MCP handler
|