docuking-mcp 1.5.0 → 1.6.0
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/index.js +180 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -451,6 +451,33 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
451
451
|
required: ['localPath', 'planId', 'summary'],
|
|
452
452
|
},
|
|
453
453
|
},
|
|
454
|
+
{
|
|
455
|
+
name: 'docuking_todo',
|
|
456
|
+
description: '할일을 z_DocuKing/z_Todo/z_Todo.md 파일에 추가하거나 완료 표시합니다. 단일 파일에 계속 누적되어 전체 작업 히스토리가 됩니다. 논의 후 할일이 생기면 바로 등록하세요.',
|
|
457
|
+
inputSchema: {
|
|
458
|
+
type: 'object',
|
|
459
|
+
properties: {
|
|
460
|
+
localPath: {
|
|
461
|
+
type: 'string',
|
|
462
|
+
description: '로컬 프로젝트 경로',
|
|
463
|
+
},
|
|
464
|
+
action: {
|
|
465
|
+
type: 'string',
|
|
466
|
+
enum: ['add', 'done', 'list'],
|
|
467
|
+
description: 'add: 할일 추가, done: 완료 표시, list: 목록 조회',
|
|
468
|
+
},
|
|
469
|
+
todo: {
|
|
470
|
+
type: 'string',
|
|
471
|
+
description: '할일 내용 (add 시 필수)',
|
|
472
|
+
},
|
|
473
|
+
todoId: {
|
|
474
|
+
type: 'number',
|
|
475
|
+
description: '할일 번호 (done 시 필수)',
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
required: ['localPath', 'action'],
|
|
479
|
+
},
|
|
480
|
+
},
|
|
454
481
|
],
|
|
455
482
|
};
|
|
456
483
|
});
|
|
@@ -958,6 +985,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
958
985
|
return await handlePlan(args);
|
|
959
986
|
case 'docuking_done':
|
|
960
987
|
return await handleDone(args);
|
|
988
|
+
case 'docuking_todo':
|
|
989
|
+
return await handleTodo(args);
|
|
961
990
|
default:
|
|
962
991
|
throw new Error(`Unknown tool: ${name}`);
|
|
963
992
|
}
|
|
@@ -2035,6 +2064,157 @@ function generatePlanId() {
|
|
|
2035
2064
|
return id;
|
|
2036
2065
|
}
|
|
2037
2066
|
|
|
2067
|
+
// docuking_todo 구현 - 할일 추가/완료/조회 (단일 파일 누적)
|
|
2068
|
+
async function handleTodo(args) {
|
|
2069
|
+
const { localPath, action, todo, todoId } = args;
|
|
2070
|
+
|
|
2071
|
+
// z_Todo 폴더 경로
|
|
2072
|
+
const todoBasePath = path.join(localPath, 'z_DocuKing', 'z_Todo');
|
|
2073
|
+
const todoFilePath = path.join(todoBasePath, 'z_Todo.md');
|
|
2074
|
+
|
|
2075
|
+
// 폴더 생성
|
|
2076
|
+
if (!fs.existsSync(todoBasePath)) {
|
|
2077
|
+
fs.mkdirSync(todoBasePath, { recursive: true });
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
// 파일이 없으면 헤더와 함께 생성
|
|
2081
|
+
if (!fs.existsSync(todoFilePath)) {
|
|
2082
|
+
const header = `# TODO 목록
|
|
2083
|
+
|
|
2084
|
+
> 이 파일은 모든 할일을 누적 기록합니다.
|
|
2085
|
+
> - [ ] 미완료 / - [x] 완료 (완료 시 날짜 추가)
|
|
2086
|
+
|
|
2087
|
+
---
|
|
2088
|
+
|
|
2089
|
+
`;
|
|
2090
|
+
fs.writeFileSync(todoFilePath, header, 'utf-8');
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// 파일 읽기
|
|
2094
|
+
let content = fs.readFileSync(todoFilePath, 'utf-8');
|
|
2095
|
+
|
|
2096
|
+
// 현재 TODO 번호 찾기 (가장 큰 번호)
|
|
2097
|
+
const todoPattern = /^(\d+)\. /gm;
|
|
2098
|
+
let maxId = 0;
|
|
2099
|
+
let match;
|
|
2100
|
+
while ((match = todoPattern.exec(content)) !== null) {
|
|
2101
|
+
const id = parseInt(match[1], 10);
|
|
2102
|
+
if (id > maxId) maxId = id;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
const now = new Date();
|
|
2106
|
+
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
|
2107
|
+
const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
|
2108
|
+
|
|
2109
|
+
if (action === 'add') {
|
|
2110
|
+
if (!todo) {
|
|
2111
|
+
return {
|
|
2112
|
+
content: [{ type: 'text', text: '오류: todo 파라미터가 필요합니다.' }],
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
const newId = maxId + 1;
|
|
2117
|
+
const newTodo = `${newId}. - [ ] ${todo} (${dateStr})\n`;
|
|
2118
|
+
|
|
2119
|
+
// 파일 끝에 추가
|
|
2120
|
+
fs.appendFileSync(todoFilePath, newTodo, 'utf-8');
|
|
2121
|
+
|
|
2122
|
+
return {
|
|
2123
|
+
content: [{
|
|
2124
|
+
type: 'text',
|
|
2125
|
+
text: `✓ TODO 추가 완료!
|
|
2126
|
+
|
|
2127
|
+
📝 #${newId}: ${todo}
|
|
2128
|
+
📅 등록: ${dateStr} ${timeStr}
|
|
2129
|
+
|
|
2130
|
+
💡 완료 시: docuking_todo(action: "done", todoId: ${newId})`,
|
|
2131
|
+
}],
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
if (action === 'done') {
|
|
2136
|
+
if (!todoId) {
|
|
2137
|
+
return {
|
|
2138
|
+
content: [{ type: 'text', text: '오류: todoId 파라미터가 필요합니다.' }],
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
// 해당 번호의 TODO 찾아서 완료 표시
|
|
2143
|
+
const todoLinePattern = new RegExp(`^(${todoId}\\. - \\[)( )(\\].*)$`, 'm');
|
|
2144
|
+
const matched = content.match(todoLinePattern);
|
|
2145
|
+
|
|
2146
|
+
if (!matched) {
|
|
2147
|
+
return {
|
|
2148
|
+
content: [{ type: 'text', text: `오류: TODO #${todoId}를 찾을 수 없습니다.` }],
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// [ ] -> [x] 변경 + 완료 날짜 추가
|
|
2153
|
+
const updatedContent = content.replace(
|
|
2154
|
+
todoLinePattern,
|
|
2155
|
+
`$1x$3 ✓${dateStr}`
|
|
2156
|
+
);
|
|
2157
|
+
|
|
2158
|
+
fs.writeFileSync(todoFilePath, updatedContent, 'utf-8');
|
|
2159
|
+
|
|
2160
|
+
// 완료된 TODO 내용 추출
|
|
2161
|
+
const todoContent = matched[0].replace(/^\d+\. - \[ \] /, '').replace(/ \(\d{4}-\d{2}-\d{2}\)$/, '');
|
|
2162
|
+
|
|
2163
|
+
return {
|
|
2164
|
+
content: [{
|
|
2165
|
+
type: 'text',
|
|
2166
|
+
text: `✓ TODO #${todoId} 완료!
|
|
2167
|
+
|
|
2168
|
+
✅ ${todoContent}
|
|
2169
|
+
📅 완료: ${dateStr} ${timeStr}`,
|
|
2170
|
+
}],
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
if (action === 'list') {
|
|
2175
|
+
// 미완료 TODO만 추출
|
|
2176
|
+
const pendingPattern = /^(\d+)\. - \[ \] (.+)$/gm;
|
|
2177
|
+
const pendingTodos = [];
|
|
2178
|
+
let listMatch;
|
|
2179
|
+
while ((listMatch = pendingPattern.exec(content)) !== null) {
|
|
2180
|
+
pendingTodos.push({ id: listMatch[1], content: listMatch[2] });
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
// 완료된 TODO 수 세기
|
|
2184
|
+
const completedCount = (content.match(/- \[x\]/g) || []).length;
|
|
2185
|
+
|
|
2186
|
+
if (pendingTodos.length === 0) {
|
|
2187
|
+
return {
|
|
2188
|
+
content: [{
|
|
2189
|
+
type: 'text',
|
|
2190
|
+
text: `📋 미완료 TODO: 없음
|
|
2191
|
+
|
|
2192
|
+
✅ 완료된 TODO: ${completedCount}개
|
|
2193
|
+
📁 전체 기록: z_DocuKing/z_Todo/z_Todo.md`,
|
|
2194
|
+
}],
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
const listText = pendingTodos.map(t => ` #${t.id}: ${t.content}`).join('\n');
|
|
2199
|
+
|
|
2200
|
+
return {
|
|
2201
|
+
content: [{
|
|
2202
|
+
type: 'text',
|
|
2203
|
+
text: `📋 미완료 TODO: ${pendingTodos.length}개
|
|
2204
|
+
|
|
2205
|
+
${listText}
|
|
2206
|
+
|
|
2207
|
+
✅ 완료된 TODO: ${completedCount}개
|
|
2208
|
+
📁 전체 기록: z_DocuKing/z_Todo/z_Todo.md`,
|
|
2209
|
+
}],
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
return {
|
|
2214
|
+
content: [{ type: 'text', text: '오류: action은 add, done, list 중 하나여야 합니다.' }],
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2038
2218
|
// docuking_talk 구현 - 대화록 자동 저장
|
|
2039
2219
|
async function handleTalk(args) {
|
|
2040
2220
|
const { localPath, title, content, tags = [] } = args;
|