docuking-mcp 1.1.0 → 1.2.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 +108 -107
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -515,7 +515,7 @@ z_DocuKing/
|
|
|
515
515
|
**특징:**
|
|
516
516
|
- 프로젝트에 초대받아 참여한 사람
|
|
517
517
|
- **읽기**: 전체 문서 Pull 가능 (오너의 문서도 볼 수 있음)
|
|
518
|
-
- **쓰기**: 자신의 폴더(\`
|
|
518
|
+
- **쓰기**: 자신의 폴더(\`zz_Coworker_{이름}/\`)에만 Push 가능
|
|
519
519
|
- API Key: \`sk_cw_\`로 시작
|
|
520
520
|
- 프로젝트 설정 변경 불가능
|
|
521
521
|
|
|
@@ -524,39 +524,37 @@ z_DocuKing/
|
|
|
524
524
|
2. MCP 설정 (한 번만)
|
|
525
525
|
3. 프로젝트 연결 (\`docuking_init\`)
|
|
526
526
|
4. Pull로 오너의 문서 가져오기 (\`docuking_pull\`)
|
|
527
|
-
5. 내 폴더에 문서 작성 (\`
|
|
527
|
+
5. 내 폴더에 문서 작성 (\`zz_Coworker_{이름}/\`)
|
|
528
528
|
6. Push (\`docuking_push\`)
|
|
529
529
|
|
|
530
|
-
**폴더
|
|
530
|
+
**폴더 구조 (z_DocuKing과 zz_Coworker는 같은 레벨):**
|
|
531
531
|
\`\`\`
|
|
532
|
-
|
|
533
|
-
├──
|
|
534
|
-
|
|
535
|
-
├──
|
|
536
|
-
│ └──
|
|
537
|
-
└──
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
532
|
+
프로젝트/
|
|
533
|
+
├── src/ ← 소스 코드 (git 관리)
|
|
534
|
+
├── z_DocuKing/ ← 오너의 문서 공간
|
|
535
|
+
│ ├── 정책/
|
|
536
|
+
│ │ └── README.md ← 오너의 파일 (읽기만 가능)
|
|
537
|
+
│ └── 기획/
|
|
538
|
+
│ └── 요구사항.md ← 오너의 파일 (읽기만 가능)
|
|
539
|
+
└── zz_Coworker_김개발/ ← 참여자 "김개발"의 폴더 (z_DocuKing과 같은 레벨!)
|
|
540
|
+
├── 제안서.md ← 여기에만 Push 가능
|
|
541
|
+
└── 수정안.md ← 여기에만 Push 가능
|
|
541
542
|
\`\`\`
|
|
542
543
|
|
|
543
544
|
**중요 규칙:**
|
|
544
|
-
-
|
|
545
|
-
-
|
|
546
|
-
-
|
|
545
|
+
- 코워커 폴더(\`zz_Coworker_{이름}/\`)는 z_DocuKing과 같은 레벨에 생성됨
|
|
546
|
+
- 참여자는 Pull로 z_DocuKing/ 폴더의 오너 문서를 볼 수 있음
|
|
547
|
+
- 참여자는 자신의 폴더에만 Push 가능
|
|
548
|
+
- \`docuking_status\`로 현재 권한과 작업 폴더 확인 가능
|
|
547
549
|
|
|
548
550
|
**참여자가 오너의 파일을 수정하고 싶을 때:**
|
|
549
|
-
1. 오너의 파일을
|
|
550
|
-
2.
|
|
551
|
-
|
|
552
|
-
4. **해결 방법**: 수정한 내용을 자신의 폴더에 새 파일로 작성
|
|
553
|
-
- 예: \`정책/README.md\`를 수정했다면
|
|
554
|
-
- → \`Co-worker/김개발/정책_README_수정제안.md\`로 작성 후 Push
|
|
551
|
+
1. Pull로 오너의 파일을 로컬에 가져옴 (z_DocuKing/에 저장됨)
|
|
552
|
+
2. 내용을 참고하여 자신의 폴더에 수정 제안 작성
|
|
553
|
+
- 예: \`zz_Coworker_김개발/정책_README_수정제안.md\`로 작성 후 Push
|
|
555
554
|
|
|
556
555
|
**AI가 참여자에게 안내해야 할 내용:**
|
|
557
|
-
-
|
|
558
|
-
-
|
|
559
|
-
- 오너의 파일을 수정하고 싶다면, 자신의 폴더에 제안서 형태로 작성하도록 안내
|
|
556
|
+
- 참여자의 작업 폴더는 \`zz_Coworker_{이름}/\` (z_DocuKing이 아님)
|
|
557
|
+
- 오너의 파일을 직접 수정할 수 없으므로, 제안서 형태로 작성하도록 안내
|
|
560
558
|
|
|
561
559
|
## AI 응답 가이드 (중요!)
|
|
562
560
|
|
|
@@ -942,24 +940,42 @@ Git처럼 무엇을 변경했는지 명확히 작성해주세요.
|
|
|
942
940
|
const projectId = projectInfo.projectId;
|
|
943
941
|
const projectName = projectInfo.projectName;
|
|
944
942
|
|
|
945
|
-
// DocuKing 폴더 찾기
|
|
946
|
-
const folderName = findDocuKingFolder(localPath);
|
|
947
|
-
if (!folderName) {
|
|
948
|
-
return {
|
|
949
|
-
content: [
|
|
950
|
-
{
|
|
951
|
-
type: 'text',
|
|
952
|
-
text: `오류: DocuKing 폴더가 없습니다.
|
|
953
|
-
docuking_init을 먼저 실행하세요.`,
|
|
954
|
-
},
|
|
955
|
-
],
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
const docuKingPath = path.join(localPath, folderName);
|
|
959
|
-
|
|
960
943
|
// Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
|
|
961
944
|
const coworkerMatch = API_KEY.match(/^sk_[a-f0-9]+_cw_([^_]+)_/);
|
|
962
|
-
const
|
|
945
|
+
const isCoworker = !!coworkerMatch;
|
|
946
|
+
const coworkerName = coworkerMatch ? coworkerMatch[1] : null;
|
|
947
|
+
const coworkerFolderName = isCoworker ? `zz_Coworker_${coworkerName}` : null;
|
|
948
|
+
|
|
949
|
+
// 작업 폴더 결정: 코워커는 zz_Coworker_{이름}/, 오너는 z_DocuKing/
|
|
950
|
+
let workingPath;
|
|
951
|
+
let serverPathPrefix = ''; // 서버에 저장될 때 경로 접두사
|
|
952
|
+
|
|
953
|
+
if (isCoworker) {
|
|
954
|
+
// 코워커: zz_Coworker_{이름}/ 폴더 사용 (z_DocuKing과 같은 레벨)
|
|
955
|
+
workingPath = path.join(localPath, coworkerFolderName);
|
|
956
|
+
serverPathPrefix = `${coworkerFolderName}/`;
|
|
957
|
+
|
|
958
|
+
if (!fs.existsSync(workingPath)) {
|
|
959
|
+
// 폴더가 없으면 생성
|
|
960
|
+
fs.mkdirSync(workingPath, { recursive: true });
|
|
961
|
+
console.log(`[DocuKing] 코워커 폴더 생성: ${coworkerFolderName}/`);
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
// 오너: z_DocuKing/ 폴더 사용
|
|
965
|
+
const folderName = findDocuKingFolder(localPath);
|
|
966
|
+
if (!folderName) {
|
|
967
|
+
return {
|
|
968
|
+
content: [
|
|
969
|
+
{
|
|
970
|
+
type: 'text',
|
|
971
|
+
text: `오류: DocuKing 폴더가 없습니다.
|
|
972
|
+
docuking_init을 먼저 실행하세요.`,
|
|
973
|
+
},
|
|
974
|
+
],
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
workingPath = path.join(localPath, folderName);
|
|
978
|
+
}
|
|
963
979
|
|
|
964
980
|
// 파일 목록 수집
|
|
965
981
|
const filesToPush = [];
|
|
@@ -967,7 +983,7 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
967
983
|
|
|
968
984
|
if (filePath) {
|
|
969
985
|
// 특정 파일만
|
|
970
|
-
const fullPath = path.join(
|
|
986
|
+
const fullPath = path.join(workingPath, filePath);
|
|
971
987
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
|
972
988
|
const fileType = getFileType(filePath);
|
|
973
989
|
if (fileType === 'excluded') {
|
|
@@ -981,52 +997,21 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
981
997
|
};
|
|
982
998
|
}
|
|
983
999
|
|
|
984
|
-
//
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const normalizedPrefix = allowedPathPrefix.toLowerCase();
|
|
988
|
-
if (!normalizedPath.startsWith(normalizedPrefix)) {
|
|
989
|
-
return {
|
|
990
|
-
content: [
|
|
991
|
-
{
|
|
992
|
-
type: 'text',
|
|
993
|
-
text: `오류: 협업자는 ${allowedPathPrefix} 폴더에만 Push할 수 있습니다.\n\n요청한 파일: ${filePath}\n허용된 경로: ${allowedPathPrefix}\n\n💡 참고: 오너의 파일을 로컬에서 수정하셨다면, 수정 내용을 ${allowedPathPrefix} 폴더에 새 파일로 작성해주세요.\n예: 정책/README.md를 수정했다면 → ${allowedPathPrefix}정책_README_수정제안.md`,
|
|
994
|
-
},
|
|
995
|
-
],
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
filesToPush.push({ path: filePath, fullPath, fileType });
|
|
1000
|
+
// 서버 경로: 코워커는 zz_Coworker_{이름}/파일경로, 오너는 파일경로
|
|
1001
|
+
const serverFilePath = serverPathPrefix + filePath;
|
|
1002
|
+
filesToPush.push({ path: filePath, serverPath: serverFilePath, fullPath, fileType });
|
|
1001
1003
|
}
|
|
1002
1004
|
} else {
|
|
1003
1005
|
// 전체 파일 - 제외된 파일 목록도 수집
|
|
1004
|
-
collectFiles(
|
|
1005
|
-
|
|
1006
|
-
// 참여자인 경우 허용된 경로의 파일만 필터링
|
|
1007
|
-
if (allowedPathPrefix) {
|
|
1008
|
-
const normalizedPrefix = allowedPathPrefix.toLowerCase();
|
|
1009
|
-
const filteredFiles = filesToPush.filter(file => {
|
|
1010
|
-
const normalizedPath = file.path.toLowerCase();
|
|
1011
|
-
return normalizedPath.startsWith(normalizedPrefix);
|
|
1012
|
-
});
|
|
1013
|
-
|
|
1014
|
-
if (filteredFiles.length === 0) {
|
|
1015
|
-
return {
|
|
1016
|
-
content: [
|
|
1017
|
-
{
|
|
1018
|
-
type: 'text',
|
|
1019
|
-
text: `Push할 파일이 없습니다.\n\n협업자는 ${allowedPathPrefix} 폴더에만 Push할 수 있습니다.\n\n현재 폴더 구조를 확인하고, 해당 폴더에 파일을 배치한 후 다시 시도해주세요.`,
|
|
1020
|
-
},
|
|
1021
|
-
],
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1006
|
+
collectFiles(workingPath, '', filesToPush, excludedFiles);
|
|
1024
1007
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1008
|
+
// 서버 경로 추가
|
|
1009
|
+
for (const file of filesToPush) {
|
|
1010
|
+
file.serverPath = serverPathPrefix + file.path;
|
|
1011
|
+
}
|
|
1028
1012
|
|
|
1029
|
-
|
|
1013
|
+
if (isCoworker) {
|
|
1014
|
+
console.log(`[DocuKing] 코워커 Push: ${filesToPush.length}개 파일 (${coworkerFolderName}/)`);
|
|
1030
1015
|
}
|
|
1031
1016
|
}
|
|
1032
1017
|
|
|
@@ -1135,7 +1120,7 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1135
1120
|
},
|
|
1136
1121
|
body: JSON.stringify({
|
|
1137
1122
|
projectId,
|
|
1138
|
-
path: file.
|
|
1123
|
+
path: file.serverPath, // 서버 경로 (코워커는 zz_Coworker_{이름}/파일경로)
|
|
1139
1124
|
content,
|
|
1140
1125
|
encoding, // 'utf-8' 또는 'base64'
|
|
1141
1126
|
message, // 커밋 메시지
|
|
@@ -1300,11 +1285,10 @@ async function handlePull(args) {
|
|
|
1300
1285
|
const projectId = projectInfo.projectId;
|
|
1301
1286
|
|
|
1302
1287
|
// DocuKing 폴더 찾기 (없으면 기본값으로 생성)
|
|
1303
|
-
let
|
|
1304
|
-
if (!
|
|
1305
|
-
|
|
1288
|
+
let ownerFolderName = findDocuKingFolder(localPath);
|
|
1289
|
+
if (!ownerFolderName) {
|
|
1290
|
+
ownerFolderName = 'z_DocuKing';
|
|
1306
1291
|
}
|
|
1307
|
-
const docuKingPath = path.join(localPath, folderName);
|
|
1308
1292
|
|
|
1309
1293
|
// 파일 목록 조회
|
|
1310
1294
|
let files = [];
|
|
@@ -1370,7 +1354,18 @@ async function handlePull(args) {
|
|
|
1370
1354
|
}
|
|
1371
1355
|
|
|
1372
1356
|
const data = await response.json();
|
|
1373
|
-
|
|
1357
|
+
|
|
1358
|
+
// 서버 경로에 따라 로컬 저장 경로 결정
|
|
1359
|
+
// zz_Coworker_{이름}/으로 시작하면 해당 폴더에, 아니면 z_DocuKing/에 저장
|
|
1360
|
+
let fullPath;
|
|
1361
|
+
const coworkerPrefixMatch = file.path.match(/^(zz_Coworker_[^/]+)\//);
|
|
1362
|
+
if (coworkerPrefixMatch) {
|
|
1363
|
+
// 코워커 폴더 파일: 프로젝트 루트에 zz_Coworker_{이름}/ 폴더로 저장
|
|
1364
|
+
fullPath = path.join(localPath, file.path);
|
|
1365
|
+
} else {
|
|
1366
|
+
// 오너 폴더 파일: z_DocuKing/ 폴더에 저장
|
|
1367
|
+
fullPath = path.join(localPath, ownerFolderName, file.path);
|
|
1368
|
+
}
|
|
1374
1369
|
|
|
1375
1370
|
// 디렉토리 생성
|
|
1376
1371
|
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
@@ -1625,20 +1620,20 @@ async function handleStatus(args) {
|
|
|
1625
1620
|
const coworkerMatch = API_KEY.match(/^sk_[a-f0-9]+_cw_([^_]+)_/);
|
|
1626
1621
|
const isCoworker = !!coworkerMatch;
|
|
1627
1622
|
const coworkerName = coworkerMatch ? coworkerMatch[1] : null;
|
|
1628
|
-
const
|
|
1623
|
+
const coworkerFolderName = isCoworker ? `zz_Coworker_${coworkerName}` : null;
|
|
1629
1624
|
|
|
1630
1625
|
// 권한 정보 구성
|
|
1631
1626
|
let permissionInfo = '';
|
|
1632
1627
|
if (isCoworker) {
|
|
1633
1628
|
permissionInfo = `\n\n## 현재 권한: 참여자 (Co-worker)
|
|
1634
1629
|
- 이름: ${coworkerName}
|
|
1635
|
-
- 읽기 권한: 전체 문서 (
|
|
1636
|
-
- 쓰기 권한: ${
|
|
1637
|
-
- 설명:
|
|
1630
|
+
- 읽기 권한: 전체 문서 (Pull로 z_DocuKing/ 폴더의 문서 가져오기 가능)
|
|
1631
|
+
- 쓰기 권한: ${coworkerFolderName}/ 폴더만 (z_DocuKing과 같은 레벨)
|
|
1632
|
+
- 설명: 코워커 전용 폴더에서 작업하면 자동으로 서버에 Push됩니다.`;
|
|
1638
1633
|
} else {
|
|
1639
1634
|
permissionInfo = `\n\n## 현재 권한: 오너 (Owner)
|
|
1640
1635
|
- 읽기 권한: 전체 문서
|
|
1641
|
-
- 쓰기 권한: 전체
|
|
1636
|
+
- 쓰기 권한: z_DocuKing/ 폴더 전체 (제한 없음)
|
|
1642
1637
|
- 설명: 프로젝트의 모든 폴더에 Push할 수 있습니다.`;
|
|
1643
1638
|
}
|
|
1644
1639
|
|
|
@@ -1662,29 +1657,35 @@ async function handleStatus(args) {
|
|
|
1662
1657
|
}
|
|
1663
1658
|
|
|
1664
1659
|
// 로컬 파일 목록 조회
|
|
1665
|
-
const folderName = findDocuKingFolder(localPath);
|
|
1666
|
-
const docuKingPath = folderName ? path.join(localPath, folderName) : null;
|
|
1667
1660
|
let localFiles = [];
|
|
1668
|
-
|
|
1669
|
-
collectFiles(docuKingPath, '', localFiles);
|
|
1670
|
-
}
|
|
1661
|
+
let pushableFiles = [];
|
|
1671
1662
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1663
|
+
if (isCoworker) {
|
|
1664
|
+
// 코워커: zz_Coworker_{이름}/ 폴더에서 파일 수집
|
|
1665
|
+
const coworkerPath = path.join(localPath, coworkerFolderName);
|
|
1666
|
+
if (fs.existsSync(coworkerPath)) {
|
|
1667
|
+
collectFiles(coworkerPath, '', localFiles);
|
|
1668
|
+
}
|
|
1669
|
+
pushableFiles = localFiles; // 코워커는 자기 폴더의 모든 파일 Push 가능
|
|
1670
|
+
} else {
|
|
1671
|
+
// 오너: z_DocuKing/ 폴더에서 파일 수집
|
|
1672
|
+
const folderName = findDocuKingFolder(localPath);
|
|
1673
|
+
const docuKingPath = folderName ? path.join(localPath, folderName) : null;
|
|
1674
|
+
if (docuKingPath && fs.existsSync(docuKingPath)) {
|
|
1675
|
+
collectFiles(docuKingPath, '', localFiles);
|
|
1676
|
+
}
|
|
1677
|
+
pushableFiles = localFiles; // 오너는 모든 파일 Push 가능
|
|
1680
1678
|
}
|
|
1681
1679
|
|
|
1682
1680
|
const projectNameInfo = projectName ? ` (${projectName})` : '';
|
|
1681
|
+
const workingFolder = isCoworker ? coworkerFolderName : 'z_DocuKing';
|
|
1683
1682
|
const statusText = `DocuKing 동기화 상태
|
|
1684
1683
|
|
|
1685
1684
|
**프로젝트**: ${projectId}${projectNameInfo}
|
|
1685
|
+
**작업 폴더**: ${workingFolder}/
|
|
1686
1686
|
**로컬 파일**: ${localFiles.length}개
|
|
1687
|
-
**서버 파일**: ${serverFiles.length}
|
|
1687
|
+
**서버 파일**: ${serverFiles.length}개
|
|
1688
|
+
**Push 가능한 파일**: ${pushableFiles.length}개${permissionInfo}
|
|
1688
1689
|
|
|
1689
1690
|
## 사용 가능한 작업
|
|
1690
1691
|
- **Push**: docuking_push({ localPath, message: "..." })
|