docuking-mcp 1.2.4 → 1.2.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/index.js +99 -64
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -954,8 +954,18 @@ MCP 설정에 다음을 추가하세요:
|
|
|
954
954
|
💡 참여자는 ${folderName}/ 폴더에만 Push할 수 있습니다.
|
|
955
955
|
오너의 문서는 Pull로 읽을 수 있지만 수정은 제안서 형태로 작성하세요.
|
|
956
956
|
|
|
957
|
-
|
|
958
|
-
|
|
957
|
+
⛔ [AI 즉시 수행] 아래 작업을 지금 바로 실행하세요:
|
|
958
|
+
|
|
959
|
+
1. MCP 설정 파일을 Read 도구로 읽으세요:
|
|
960
|
+
- Claude Code: ~/.claude.json
|
|
961
|
+
- Cursor: ~/.cursor/mcp.json
|
|
962
|
+
|
|
963
|
+
2. Edit 도구로 해당 파일의 mcpServers.docuking.env에 DOCUKING_REPOS를 추가하세요:
|
|
964
|
+
"DOCUKING_REPOS": "${repoConfig}"
|
|
965
|
+
|
|
966
|
+
3. 사용자에게 "설정 완료. 재시작 후 Push/Pull 가능합니다" 안내
|
|
967
|
+
|
|
968
|
+
❗ 이 작업을 수행하지 않으면 Push/Pull이 작동하지 않습니다.`,
|
|
959
969
|
},
|
|
960
970
|
],
|
|
961
971
|
};
|
|
@@ -977,8 +987,18 @@ MCP 설정에 다음을 추가하세요:
|
|
|
977
987
|
- "DocuKing에 올려줘" → 로컬 문서를 서버에 Push
|
|
978
988
|
- "DocuKing에서 가져와" → 서버 문서를 로컬로 Pull
|
|
979
989
|
|
|
980
|
-
|
|
981
|
-
|
|
990
|
+
⛔ [AI 즉시 수행] 아래 작업을 지금 바로 실행하세요:
|
|
991
|
+
|
|
992
|
+
1. MCP 설정 파일을 Read 도구로 읽으세요:
|
|
993
|
+
- Claude Code: ~/.claude.json
|
|
994
|
+
- Cursor: ~/.cursor/mcp.json
|
|
995
|
+
|
|
996
|
+
2. Edit 도구로 해당 파일의 mcpServers.docuking.env에 DOCUKING_REPOS를 추가하세요:
|
|
997
|
+
"DOCUKING_REPOS": "${repoConfig}"
|
|
998
|
+
|
|
999
|
+
3. 사용자에게 "설정 완료. 재시작 후 Push/Pull 가능합니다" 안내
|
|
1000
|
+
|
|
1001
|
+
❗ 이 작업을 수행하지 않으면 Push/Pull이 작동하지 않습니다.`,
|
|
982
1002
|
},
|
|
983
1003
|
],
|
|
984
1004
|
};
|
|
@@ -1137,30 +1157,6 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1137
1157
|
};
|
|
1138
1158
|
}
|
|
1139
1159
|
|
|
1140
|
-
// 파일 업로드 (진행률 표시)
|
|
1141
|
-
const results = [];
|
|
1142
|
-
const total = filesToPush.length;
|
|
1143
|
-
let current = 0;
|
|
1144
|
-
let skipped = 0;
|
|
1145
|
-
|
|
1146
|
-
// 시작 안내 메시지 출력 (AI가 사용자에게 전달할 수 있도록)
|
|
1147
|
-
console.error(`[DocuKing] Push 시작: ${total}개 파일`);
|
|
1148
|
-
console.error(`[DocuKing] 💡 실시간 진행상황은 DocuKing 웹(https://docuking.ai)에서 확인하세요`);
|
|
1149
|
-
|
|
1150
|
-
// Sync 시작 알림 (웹에서 프로그레스바 표시용)
|
|
1151
|
-
try {
|
|
1152
|
-
await fetch(`${API_ENDPOINT}/projects/${projectId}/sync/start`, {
|
|
1153
|
-
method: 'POST',
|
|
1154
|
-
headers: {
|
|
1155
|
-
'Content-Type': 'application/json',
|
|
1156
|
-
'Authorization': `Bearer ${API_KEY}`,
|
|
1157
|
-
},
|
|
1158
|
-
body: JSON.stringify({ totalFiles: total }),
|
|
1159
|
-
});
|
|
1160
|
-
} catch (e) {
|
|
1161
|
-
console.error('[DocuKing] Sync 시작 알림 실패:', e.message);
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
1160
|
// 서버에서 파일 해시 조회 (변경 감지용)
|
|
1165
1161
|
let serverFileHashes = {};
|
|
1166
1162
|
try {
|
|
@@ -1181,36 +1177,82 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1181
1177
|
console.error('[DocuKing] 파일 해시 조회 실패:', e.message);
|
|
1182
1178
|
}
|
|
1183
1179
|
|
|
1180
|
+
// ★ 변경된 파일만 필터링 (업로드 전에 미리 계산)
|
|
1181
|
+
const changedFiles = [];
|
|
1182
|
+
const unchangedFiles = [];
|
|
1183
|
+
|
|
1184
1184
|
for (const file of filesToPush) {
|
|
1185
|
+
let fileHash;
|
|
1186
|
+
let content;
|
|
1187
|
+
let encoding = 'utf-8';
|
|
1188
|
+
|
|
1189
|
+
if (file.fileType === 'binary') {
|
|
1190
|
+
const buffer = fs.readFileSync(file.fullPath);
|
|
1191
|
+
fileHash = crypto.createHash('sha256').update(buffer).digest('hex');
|
|
1192
|
+
content = buffer.toString('base64');
|
|
1193
|
+
encoding = 'base64';
|
|
1194
|
+
} else {
|
|
1195
|
+
content = fs.readFileSync(file.fullPath, 'utf-8');
|
|
1196
|
+
fileHash = crypto.createHash('sha256').update(content, 'utf-8').digest('hex');
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (serverFileHashes[file.path] === fileHash) {
|
|
1200
|
+
unchangedFiles.push(file.path);
|
|
1201
|
+
} else {
|
|
1202
|
+
changedFiles.push({ ...file, content, encoding, fileHash });
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const totalLocal = filesToPush.length;
|
|
1207
|
+
const totalChanged = changedFiles.length;
|
|
1208
|
+
const totalUnchanged = unchangedFiles.length;
|
|
1209
|
+
|
|
1210
|
+
// ★ 변경된 파일이 없으면 즉시 반환
|
|
1211
|
+
if (totalChanged === 0) {
|
|
1212
|
+
return {
|
|
1213
|
+
content: [
|
|
1214
|
+
{
|
|
1215
|
+
type: 'text',
|
|
1216
|
+
text: `변경된 파일이 없습니다.
|
|
1217
|
+
|
|
1218
|
+
📊 로컬 파일: ${totalLocal}개
|
|
1219
|
+
✓ 서버와 동일: ${totalUnchanged}개
|
|
1220
|
+
⊘ 변경 필요: 0개
|
|
1221
|
+
|
|
1222
|
+
이미 모든 파일이 서버와 동기화되어 있습니다.`,
|
|
1223
|
+
},
|
|
1224
|
+
],
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// ★ 변경된 파일만 업로드 (AI에게 명확히 알림)
|
|
1229
|
+
console.error(`[DocuKing] 변경 감지 완료: 전체 ${totalLocal}개 중 ${totalChanged}개만 업로드`);
|
|
1230
|
+
console.error(`[DocuKing] 💡 실시간 진행상황은 DocuKing 웹(https://docuking.ai)에서 확인하세요`);
|
|
1231
|
+
|
|
1232
|
+
// Sync 시작 알림 (변경된 파일 수만 전달)
|
|
1233
|
+
try {
|
|
1234
|
+
await fetch(`${API_ENDPOINT}/projects/${projectId}/sync/start`, {
|
|
1235
|
+
method: 'POST',
|
|
1236
|
+
headers: {
|
|
1237
|
+
'Content-Type': 'application/json',
|
|
1238
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
1239
|
+
},
|
|
1240
|
+
body: JSON.stringify({ totalFiles: totalChanged }),
|
|
1241
|
+
});
|
|
1242
|
+
} catch (e) {
|
|
1243
|
+
console.error('[DocuKing] Sync 시작 알림 실패:', e.message);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// 파일 업로드 (변경된 파일만)
|
|
1247
|
+
const results = [];
|
|
1248
|
+
let current = 0;
|
|
1249
|
+
|
|
1250
|
+
for (const file of changedFiles) {
|
|
1185
1251
|
current++;
|
|
1186
|
-
const progress = `${current}/${
|
|
1252
|
+
const progress = `${current}/${totalChanged}`;
|
|
1187
1253
|
|
|
1188
1254
|
try {
|
|
1189
|
-
|
|
1190
|
-
let fileHash;
|
|
1191
|
-
let content;
|
|
1192
|
-
let encoding = 'utf-8';
|
|
1193
|
-
|
|
1194
|
-
if (file.fileType === 'binary') {
|
|
1195
|
-
// 바이너리 파일은 Base64로 인코딩
|
|
1196
|
-
const buffer = fs.readFileSync(file.fullPath);
|
|
1197
|
-
fileHash = crypto.createHash('sha256').update(buffer).digest('hex');
|
|
1198
|
-
content = buffer.toString('base64');
|
|
1199
|
-
encoding = 'base64';
|
|
1200
|
-
} else {
|
|
1201
|
-
// 텍스트 파일은 UTF-8
|
|
1202
|
-
content = fs.readFileSync(file.fullPath, 'utf-8');
|
|
1203
|
-
fileHash = crypto.createHash('sha256').update(content, 'utf-8').digest('hex');
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
// 변경 감지: 서버에 같은 해시가 있으면 스킵
|
|
1207
|
-
if (serverFileHashes[file.path] === fileHash) {
|
|
1208
|
-
const resultText = `${progress} ⊘ ${file.path} (변경 없음)`;
|
|
1209
|
-
results.push(resultText);
|
|
1210
|
-
console.log(resultText);
|
|
1211
|
-
skipped++;
|
|
1212
|
-
continue;
|
|
1213
|
-
}
|
|
1255
|
+
const { content, encoding, fileHash } = file;
|
|
1214
1256
|
|
|
1215
1257
|
// 재시도 로직 (최대 3회)
|
|
1216
1258
|
let lastError = null;
|
|
@@ -1325,17 +1367,16 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1325
1367
|
|
|
1326
1368
|
const successCount = results.filter(r => r.includes('✓')).length;
|
|
1327
1369
|
const failCount = results.filter(r => r.includes('✗')).length;
|
|
1328
|
-
const skippedCount = skipped; // 이미 계산된 스킵 개수 사용
|
|
1329
1370
|
const excludedCount = excludedFiles.length;
|
|
1330
1371
|
|
|
1331
|
-
// 요약 정보
|
|
1332
|
-
let summary = `\n📦 커밋 메시지: "${message}"\n\n📊 처리 결과:\n -
|
|
1372
|
+
// 요약 정보 (★ 변경된 파일만 업로드했음을 명확히 표시)
|
|
1373
|
+
let summary = `\n📦 커밋 메시지: "${message}"\n\n📊 처리 결과:\n - 로컬 파일: ${totalLocal}개\n - 변경 없음 (스킵): ${totalUnchanged}개\n - 변경 감지: ${totalChanged}개\n - 업로드 성공: ${successCount}개\n - 업로드 실패: ${failCount}개`;
|
|
1333
1374
|
if (excludedCount > 0) {
|
|
1334
1375
|
summary += `\n - 제외 (압축/설치파일): ${excludedCount}개`;
|
|
1335
1376
|
}
|
|
1336
1377
|
|
|
1337
1378
|
// 상세 결과를 표시 (Git처럼)
|
|
1338
|
-
let resultText = `✓ Push
|
|
1379
|
+
let resultText = `✓ Push 완료! (변경된 ${totalChanged}개 파일만 업로드)${summary}`;
|
|
1339
1380
|
|
|
1340
1381
|
// 업로드된 파일이 있으면 상세 목록 표시
|
|
1341
1382
|
if (successCount > 0) {
|
|
@@ -1343,12 +1384,6 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1343
1384
|
resultText += `\n\n📤 업로드된 파일 (${successCount}개):\n${uploadedFiles.map(r => ` ${r.replace(/^\d+\/\d+ /, '')}`).join('\n')}`;
|
|
1344
1385
|
}
|
|
1345
1386
|
|
|
1346
|
-
// 스킵된 파일이 있으면 표시
|
|
1347
|
-
if (skippedCount > 0) {
|
|
1348
|
-
const skippedFiles = results.filter(r => r.includes('⊘'));
|
|
1349
|
-
resultText += `\n\n⏭️ 스킵된 파일 (${skippedCount}개, 변경 없음):\n${skippedFiles.map(r => ` ${r.replace(/^\d+\/\d+ /, '')}`).join('\n')}`;
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
1387
|
// 실패한 파일이 있으면 표시
|
|
1353
1388
|
if (failCount > 0) {
|
|
1354
1389
|
const failedFiles = results.filter(r => r.includes('✗'));
|