docuking-mcp 2.0.1 → 2.0.3

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.
Files changed (2) hide show
  1. package/index.js +57 -12
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -37,6 +37,10 @@ import crypto from 'crypto';
37
37
  // 환경변수에서 API 엔드포인트 설정 (키는 로컬 config에서 읽음)
38
38
  const API_ENDPOINT = process.env.DOCUKING_API_ENDPOINT || 'https://docuking.ai/api';
39
39
 
40
+ // 파일 크기 제한 (50MB) - Base64 인코딩 시 66MB, 서버 제한 200MB 이내
41
+ const MAX_FILE_SIZE_MB = 50;
42
+ const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
43
+
40
44
  /**
41
45
  * 로컬 프로젝트의 .docuking/config.json에서 설정 읽기
42
46
  *
@@ -1110,9 +1114,11 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1110
1114
  }
1111
1115
 
1112
1116
  // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
1113
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]+)_/);
1117
+ // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
1118
+ const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1114
1119
  const isCoworker = !!coworkerMatch;
1115
- const coworkerName = coworkerMatch ? coworkerMatch[1] : null;
1120
+ // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
1121
+ const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
1116
1122
 
1117
1123
  // .docuking/config.json에 설정 저장
1118
1124
  saveLocalConfig(localPath, {
@@ -1264,9 +1270,11 @@ Git처럼 무엇을 변경했는지 명확히 작성해주세요.
1264
1270
  const projectName = projectInfo.projectName;
1265
1271
 
1266
1272
  // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
1267
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]+)_/);
1273
+ // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
1274
+ const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1268
1275
  const isCoworker = !!coworkerMatch;
1269
- const coworkerName = coworkerMatch ? coworkerMatch[1] : null;
1276
+ // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
1277
+ const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
1270
1278
  const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerName}` : null;
1271
1279
 
1272
1280
  // 작업 폴더 결정: 모두 yy_All_Docu/ 사용, 협업자는 yy_All_Docu/yy_Coworker_{이름}/ 에서 작업
@@ -1325,8 +1333,9 @@ docuking_init을 먼저 실행하세요.`,
1325
1333
  filesToPush.push({ path: filePath, serverPath: serverFilePath, fullPath, fileType });
1326
1334
  }
1327
1335
  } else {
1328
- // 전체 파일 - 제외된 파일 목록도 수집
1329
- collectFiles(workingPath, '', filesToPush, excludedFiles);
1336
+ // 전체 파일 - 제외된 파일 및 대용량 파일 목록도 수집
1337
+ const largeFiles = [];
1338
+ collectFiles(workingPath, '', filesToPush, excludedFiles, largeFiles);
1330
1339
 
1331
1340
  // 서버 경로 추가
1332
1341
  for (const file of filesToPush) {
@@ -1336,6 +1345,15 @@ docuking_init을 먼저 실행하세요.`,
1336
1345
  if (isCoworker) {
1337
1346
  console.log(`[DocuKing] 코워커 Push: ${filesToPush.length}개 파일 (${coworkerFolderName}/)`);
1338
1347
  }
1348
+
1349
+ // 대용량 파일 경고
1350
+ if (largeFiles.length > 0) {
1351
+ console.error(`\n[DocuKing] ⚠️ 대용량 파일 ${largeFiles.length}개 제외됨 (${MAX_FILE_SIZE_MB}MB 초과):`);
1352
+ for (const f of largeFiles) {
1353
+ console.error(` - ${f.path} (${f.sizeMB}MB)`);
1354
+ }
1355
+ console.error(`💡 대용량 파일은 Google Drive, NAS 등 별도 방법으로 공유하세요.\n`);
1356
+ }
1339
1357
  }
1340
1358
 
1341
1359
  if (filesToPush.length === 0) {
@@ -1349,6 +1367,9 @@ docuking_init을 먼저 실행하세요.`,
1349
1367
  };
1350
1368
  }
1351
1369
 
1370
+ // 총 용량 계산
1371
+ const totalSizeMB = filesToPush.reduce((sum, f) => sum + (f.sizeMB || 0), 0);
1372
+
1352
1373
  // 파일 업로드 (진행률 표시)
1353
1374
  const results = [];
1354
1375
  const total = filesToPush.length;
@@ -1356,7 +1377,7 @@ docuking_init을 먼저 실행하세요.`,
1356
1377
  let skipped = 0;
1357
1378
 
1358
1379
  // 시작 안내 메시지 출력 (AI가 사용자에게 전달할 수 있도록)
1359
- console.error(`[DocuKing] Push 시작: ${total}개 파일`);
1380
+ console.error(`[DocuKing] Push 시작: ${total}개 파일 (총 ${totalSizeMB.toFixed(1)}MB)`);
1360
1381
  console.error(`[DocuKing] 💡 실시간 진행상황은 DocuKing 웹(https://docuking.ai)에서 확인하세요`);
1361
1382
 
1362
1383
  // Sync 시작 알림 (웹에서 프로그레스바 표시용)
@@ -1404,8 +1425,14 @@ docuking_init을 먼저 실행하세요.`,
1404
1425
  for (const file of filesToPush) {
1405
1426
  current++;
1406
1427
  const progress = `${current}/${total}`;
1428
+ const sizeInfo = file.sizeMB >= 1 ? ` (${file.sizeMB.toFixed(1)}MB)` : '';
1407
1429
  processedLocalPaths.add(file.serverPath);
1408
1430
 
1431
+ // 1MB 이상 파일은 업로드 시작 시 로그 출력 (사용자가 진행 상황 파악 가능)
1432
+ if (file.sizeMB >= 1) {
1433
+ console.error(`[DocuKing] ${progress} 업로드 중: ${file.path}${sizeInfo}`);
1434
+ }
1435
+
1409
1436
  try {
1410
1437
  // 파일 해시 계산 (변경 감지)
1411
1438
  let fileHash;
@@ -1978,8 +2005,9 @@ function hasAllDocuFolder(projectPath) {
1978
2005
 
1979
2006
  // 유틸: 디렉토리 재귀 탐색
1980
2007
  // excludedFiles: 제외된 파일 목록을 수집할 배열 (선택)
2008
+ // largeFiles: 대용량 파일 목록을 수집할 배열 (선택)
1981
2009
  // zz_* 폴더는 로컬 전용이므로 동기화에서 제외
1982
- function collectFiles(basePath, relativePath, results, excludedFiles = null) {
2010
+ function collectFiles(basePath, relativePath, results, excludedFiles = null, largeFiles = null) {
1983
2011
  const fullPath = path.join(basePath, relativePath);
1984
2012
  const entries = fs.readdirSync(fullPath, { withFileTypes: true });
1985
2013
 
@@ -1992,7 +2020,7 @@ function collectFiles(basePath, relativePath, results, excludedFiles = null) {
1992
2020
  console.error(`[DocuKing] 제외됨: ${entryRelPath}/ (zz_* 폴더 - 로컬 전용)`);
1993
2021
  continue;
1994
2022
  }
1995
- collectFiles(basePath, entryRelPath, results, excludedFiles);
2023
+ collectFiles(basePath, entryRelPath, results, excludedFiles, largeFiles);
1996
2024
  } else if (entry.isFile()) {
1997
2025
  const fileType = getFileType(entry.name);
1998
2026
 
@@ -2005,10 +2033,25 @@ function collectFiles(basePath, relativePath, results, excludedFiles = null) {
2005
2033
  continue;
2006
2034
  }
2007
2035
 
2036
+ // 파일 크기 확인
2037
+ const fileFullPath = path.join(fullPath, entry.name);
2038
+ const stats = fs.statSync(fileFullPath);
2039
+ const fileSizeMB = stats.size / (1024 * 1024);
2040
+
2041
+ // 대용량 파일은 별도 추적
2042
+ if (stats.size > MAX_FILE_SIZE_BYTES) {
2043
+ console.error(`[DocuKing] ⚠️ 대용량 파일 제외: ${entryRelPath} (${fileSizeMB.toFixed(1)}MB > ${MAX_FILE_SIZE_MB}MB)`);
2044
+ if (largeFiles) {
2045
+ largeFiles.push({ path: entryRelPath, sizeMB: fileSizeMB.toFixed(1) });
2046
+ }
2047
+ continue;
2048
+ }
2049
+
2008
2050
  results.push({
2009
2051
  path: entryRelPath,
2010
- fullPath: path.join(fullPath, entry.name),
2052
+ fullPath: fileFullPath,
2011
2053
  fileType, // 'text' 또는 'binary'
2054
+ sizeMB: fileSizeMB, // 진행률 표시용
2012
2055
  });
2013
2056
  }
2014
2057
  }
@@ -2066,9 +2109,11 @@ async function handleStatus(args) {
2066
2109
  const projectName = projectInfo.projectName;
2067
2110
 
2068
2111
  // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
2069
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]+)_/);
2112
+ // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
2113
+ const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
2070
2114
  const isCoworker = !!coworkerMatch;
2071
- const coworkerName = coworkerMatch ? coworkerMatch[1] : null;
2115
+ // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
2116
+ const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
2072
2117
  const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerName}` : null;
2073
2118
 
2074
2119
  // 권한 정보 구성
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docuking-mcp",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "DocuKing MCP Server - AI 시대의 문서 협업 플랫폼",
5
5
  "type": "module",
6
6
  "main": "index.js",