docuking-mcp 2.0.7 → 2.1.1

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 +155 -98
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,19 +6,22 @@
6
6
  * AI 시대의 문서 협업 플랫폼 - AI가 문서를 Push/Pull 할 수 있게 해주는 MCP 서버
7
7
  *
8
8
  * 폴더 구조:
9
- * - yy_All_Docu/ : 킹폴더와 동기화 (Push/Pull 대상)
10
- * - yy_All_Docu/yy_{이름}/ : 협업자 폴더 (동기화 대상)
11
- * - zz_ai_Talk/ : AI 대화록 (로컬 전용, 킹톡)
12
- * - zz_ai_Todo/ : AI 투두 (로컬 전용, 킹투두)
13
- * - zzz_ai_Plan/ : AI 플랜 (로컬 전용, 킹플랜)
9
+ * - yy_All_Docu/ : 문서 동기화 폴더 (Push/Pull 대상)
10
+ * - yy_All_Docu/_Infra_Config/: 민감 정보 백업 (.env 자동 복사, 팀 공유)
11
+ * - yy_All_Docu/_Private/ : 오너 비공개 폴더 (오너만 접근)
12
+ * - yy_Coworker_{폴더명}/ : 협업자 폴더 (yy_All_Docu와 별도, 동기화 대상)
13
+ * - zz_ai_1_Talk/ : AI 대화록 (킹톡)
14
+ * - zz_ai_2_Todo/ : AI 투두 (킹투두)
15
+ * - zz_ai_3_Plan/ : AI 플랜 (킹플랜)
14
16
  *
15
17
  * 접두사 규칙:
16
- * - yy_* : 동기화 대상 (Push/Pull)
17
- * - zz_* : 로컬 전용 (동기화 )
18
+ * - yy_ : 사람용 폴더 (문서, 협업자)
19
+ * - zz_ : AI용 폴더 (Talk, Todo, Plan)
20
+ * - _ : 비공개 폴더 (본인만 접근)
18
21
  *
19
22
  * 도구:
20
23
  * - docuking_init: 레포 연결, yy_All_Docu/ 폴더 생성
21
- * - docuking_push: 로컬 → 서버
24
+ * - docuking_push: 로컬 → 서버 (.env 자동 백업)
22
25
  * - docuking_pull: 서버 → 로컬
23
26
  */
24
27
 
@@ -37,8 +40,8 @@ import crypto from 'crypto';
37
40
  // 환경변수에서 API 엔드포인트 설정 (키는 로컬 config에서 읽음)
38
41
  const API_ENDPOINT = process.env.DOCUKING_API_ENDPOINT || 'https://docuking.ai/api';
39
42
 
40
- // 파일 크기 제한 (50MB) - Base64 인코딩 시 66MB, 서버 제한 200MB 이내
41
- const MAX_FILE_SIZE_MB = 50;
43
+ // 파일 크기 제한 (150MB) - Base64 인코딩 시 약 200MB, 서버 제한 200MB 일치
44
+ const MAX_FILE_SIZE_MB = 150;
42
45
  const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
43
46
 
44
47
  /**
@@ -145,7 +148,7 @@ docuking_done({
145
148
  ### 절대 규칙
146
149
  - **작업 시작 전 반드시 \`docuking_plan\` 호출**
147
150
  - **작업 완료 후 반드시 \`docuking_done\` 호출**
148
- - 결과는 \`zzz_ai_Plan/\`에 자동 저장됨 (로컬 전용)
151
+ - 결과는 \`zz_ai_3_Plan/\`에 자동 저장됨 (로컬 전용)
149
152
  `;
150
153
 
151
154
  try {
@@ -225,7 +228,7 @@ function setupAutoApproval(localPath) {
225
228
 
226
229
  /**
227
230
  * .gitignore에 DocuKing 폴더 추가
228
- * - yy_All_Docu/, zz_ai_Talk/, zz_ai_Todo/, zzz_ai_Plan/, .docuking/
231
+ * - yy_All_Docu/, zz_ai_1_Talk/, zz_ai_2_Todo/, zz_ai_3_Plan/, .docuking/
229
232
  */
230
233
  function updateGitignore(localPath) {
231
234
  const gitignorePath = path.join(localPath, '.gitignore');
@@ -233,9 +236,9 @@ function updateGitignore(localPath) {
233
236
  const docukingEntries = `
234
237
  ${marker}
235
238
  yy_All_Docu/
236
- zz_ai_Talk/
237
- zz_ai_Todo/
238
- zzz_ai_Plan/
239
+ zz_ai_1_Talk/
240
+ zz_ai_2_Todo/
241
+ zz_ai_3_Plan/
239
242
  .docuking/
240
243
  `;
241
244
 
@@ -459,7 +462,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
459
462
  },
460
463
  {
461
464
  name: 'docuking_talk',
462
- description: '의미 있는 대화 내용을 zz_ai_Talk/ 폴더에 기록합니다 (로컬 전용, 킹톡). AI가 중요한 논의/결정이라고 판단하거나, 사용자가 "이거 기록해줘"라고 요청할 때 사용.',
465
+ description: '의미 있는 대화 내용을 zz_ai_1_Talk/ 폴더에 기록합니다 (로컬 전용, 킹톡). AI가 중요한 논의/결정이라고 판단하거나, 사용자가 "이거 기록해줘"라고 요청할 때 사용.',
463
466
  inputSchema: {
464
467
  type: 'object',
465
468
  properties: {
@@ -486,7 +489,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
486
489
  },
487
490
  {
488
491
  name: 'docuking_plan',
489
- description: '작업 계획 문서를 zzz_ai_Plan/ 폴더에 생성/업데이트합니다 (로컬 전용, 킹플랜). 작업 시작 시 계획을 작성하고, 진행하면서 결과를 upsert합니다.',
492
+ description: '작업 계획 문서를 zz_ai_3_Plan/ 폴더에 생성/업데이트합니다 (로컬 전용, 킹플랜). 작업 시작 시 계획을 작성하고, 진행하면서 결과를 upsert합니다.',
490
493
  inputSchema: {
491
494
  type: 'object',
492
495
  properties: {
@@ -555,7 +558,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
555
558
  },
556
559
  {
557
560
  name: 'docuking_todo',
558
- description: `킹투두(King Todo) - 프로젝트 공식 할일을 zz_ai_Todo/z_King_Todo.md에 관리합니다 (로컬 전용).
561
+ description: `킹투두(King Todo) - 프로젝트 공식 할일을 zz_ai_2_Todo/z_King_Todo.md에 관리합니다 (로컬 전용).
559
562
 
560
563
  **AI 내장 TodoWrite와 다름!** 킹투두는 웹에 동기화되고 팀과 공유됩니다.
561
564
 
@@ -629,7 +632,7 @@ DocuKing은 문서 버전 관리 시스템입니다. Git이 코드를 관리하
629
632
  - **로컬**: 사용자의 yy_All_Docu/ 폴더 (동기화 대상)
630
633
  - **웹탐색기**: DocuKing 서버의 파일 저장소 (킹폴더)
631
634
  - **캔버스**: 선택된 파일을 시각화하는 작업 공간
632
- - **AI 작업 폴더**: zz_ai_Talk/, zz_ai_Todo/, zzz_ai_Plan/ (로컬 전용)
635
+ - **AI 작업 폴더**: zz_ai_1_Talk/, zz_ai_2_Todo/, zz_ai_3_Plan/ (로컬 전용)
633
636
 
634
637
  작동 방식: 로컬 yy_All_Docu/ → Push → 킹폴더 → 캔버스에서 시각화
635
638
 
@@ -664,9 +667,9 @@ DocuKing 문서 폴더는 git에서 제외해야 합니다. 코드는 git으로,
664
667
  \`\`\`gitignore
665
668
  # DocuKing 문서 폴더 (문서는 DocuKing으로 관리)
666
669
  yy_All_Docu/
667
- zz_ai_Talk/
668
- zz_ai_Todo/
669
- zzz_ai_Plan/
670
+ zz_ai_1_Talk/
671
+ zz_ai_2_Todo/
672
+ zz_ai_3_Plan/
670
673
  \`\`\`
671
674
 
672
675
  **왜 gitignore에 등록해야 하나요?**
@@ -702,12 +705,12 @@ zzz_ai_Plan/
702
705
  특정 커밋으로 되돌립니다. (웹 탐색기에서 사용 가능)
703
706
 
704
707
  ### 9. docuking_talk
705
- 의미 있는 대화 내용을 \`zz_ai_Talk/\` 폴더에 기록합니다 (로컬 전용, 킹톡).
708
+ 의미 있는 대화 내용을 \`zz_ai_1_Talk/\` 폴더에 기록합니다 (로컬 전용, 킹톡).
706
709
  - AI가 중요한 논의/결정이라고 판단할 때
707
710
  - 사용자가 "이거 기록해줘"라고 요청할 때
708
711
 
709
712
  ### 10. docuking_plan
710
- 작업 계획을 \`zzz_ai_Plan/\` 폴더에 생성/업데이트합니다 (로컬 전용, 킹플랜).
713
+ 작업 계획을 \`zz_ai_3_Plan/\` 폴더에 생성/업데이트합니다 (로컬 전용, 킹플랜).
711
714
  - 작업 시작 시 계획 생성
712
715
  - 진행하면서 단계별 결과 upsert
713
716
  - planId로 기존 계획 찾아서 업데이트
@@ -792,9 +795,9 @@ yy_All_Docu/
792
795
 
793
796
  **특징:**
794
797
  - 프로젝트에 초대받아 참여한 사람
795
- - **읽기**: 전체 문서 Pull 가능 (오너의 문서도 볼 수 있음)
796
- - **쓰기**: 자신의 폴더(\`yy_All_Docu/yy_Coworker_{이름}/\`)에만 Push 가능
797
- - API Key: \`sk_cw_\`로 시작
798
+ - **읽기**: yy_All_Docu/ 전체 Pull 가능 (오너의 문서도 볼 수 있음)
799
+ - **쓰기**: 자신의 폴더(\`yy_Coworker_{폴더명}/\`)에만 Push 가능
800
+ - API Key: \`sk_xxx_cw_폴더명_\` 형식
798
801
  - 프로젝트 설정 변경 불가능
799
802
 
800
803
  **사용 시나리오:**
@@ -802,28 +805,28 @@ yy_All_Docu/
802
805
  2. MCP 설정 (한 번만)
803
806
  3. 프로젝트 연결 (\`docuking_init\`)
804
807
  4. Pull로 오너의 문서 가져오기 (\`docuking_pull\`)
805
- 5. 내 폴더에 문서 작성 (\`yy_All_Docu/yy_Coworker_{이름}/\`)
808
+ 5. 내 폴더에 문서 작성 (\`yy_Coworker_{폴더명}/\`)
806
809
  6. Push (\`docuking_push\`)
807
810
 
808
811
  **폴더 구조:**
809
812
  \`\`\`
810
- 프로젝트/
813
+ project/
811
814
  ├── src/ ← 소스 코드 (git 관리)
812
- ├── yy_All_Docu/ ← 동기화 대상 (Push/Pull)
813
- │ ├── 정책/
814
- │ │ └── README.md ← 오너의 파일 (읽기만 가능)
815
- ├── 기획/
816
- └── 요구사항.md ← 오너의 파일 (읽기만 가능)
817
- │ └── yy_Coworker_김개발/ ← 참여자 "김개발"의 폴더
818
- ├── 제안서.md ← 여기에만 Push 가능
819
- └── 수정안.md ← 여기에만 Push 가능
820
- ├── zz_ai_Talk/ ← AI 대화록 (로컬 전용)
821
- ├── zz_ai_Todo/ ← AI 투두 (로컬 전용)
822
- └── zzz_ai_Plan/ ← AI 플랜 (로컬 전용)
815
+ ├── yy_All_Docu/ ← 오너 문서 (Pull로 읽기만 가능)
816
+ │ ├── policy/
817
+ │ │ └── README.md ← 오너의 파일
818
+ └── plan/
819
+ └── requirements.md ← 오너의 파일
820
+ ├── yy_Coworker_devkim/ ← 참여자 "devkim"의 폴더 (별도)
821
+ ├── proposal.md ← 여기에만 Push 가능
822
+ └── revision.md ← 여기에만 Push 가능
823
+ ├── zz_ai_1_Talk/ ← AI 대화록 (로컬 전용)
824
+ ├── zz_ai_2_Todo/ ← AI 투두 (로컬 전용)
825
+ └── zz_ai_3_Plan/ ← AI 플랜 (로컬 전용)
823
826
  \`\`\`
824
827
 
825
828
  **중요 규칙:**
826
- - 코워커 폴더(\`yy_Coworker_{이름}/\`)는 yy_All_Docu/ 안에 생성됨
829
+ - 코워커 폴더(\`yy_Coworker_{폴더명}/\`)는 yy_All_Docu/ 밖에 독립 생성
827
830
  - 참여자는 Pull로 yy_All_Docu/ 폴더의 오너 문서를 볼 수 있음
828
831
  - 참여자는 자신의 폴더에만 Push 가능
829
832
  - \`docuking_status\`로 현재 권한과 작업 폴더 확인 가능
@@ -831,10 +834,10 @@ yy_All_Docu/
831
834
  **참여자가 오너의 파일을 수정하고 싶을 때:**
832
835
  1. Pull로 오너의 파일을 로컬에 가져옴 (yy_All_Docu/에 저장됨)
833
836
  2. 내용을 참고하여 자신의 폴더에 수정 제안 작성
834
- - 예: \`yy_All_Docu/yy_Coworker_김개발/정책_README_수정제안.md\`로 작성 후 Push
837
+ - 예: \`yy_Coworker_devkim/policy_README_revision.md\`로 작성 후 Push
835
838
 
836
839
  **AI가 참여자에게 안내해야 할 내용:**
837
- - 참여자의 작업 폴더는 \`yy_All_Docu/yy_Coworker_{이름}/\`
840
+ - 참여자의 작업 폴더는 \`yy_Coworker_{폴더명}/\`
838
841
  - 오너의 파일을 직접 수정할 수 없으므로, 제안서 형태로 작성하도록 안내
839
842
 
840
843
  ## AI 응답 가이드 (중요!)
@@ -918,7 +921,7 @@ AI: (결정이 내려졌으므로 docuking_talk 호출)
918
921
  })
919
922
  \`\`\`
920
923
 
921
- **저장 위치:** \`zz_ai_Talk/YYYY-MM-DD_HHMM__제목.md\` (플랫 구조, 로컬 전용)
924
+ **저장 위치:** \`zz_ai_1_Talk/YYYY-MM-DD_HHMM__제목.md\` (플랫 구조, 로컬 전용)
922
925
 
923
926
  ### 작업 계획 관리 (docuking_plan, docuking_done)
924
927
 
@@ -969,7 +972,7 @@ AI: docuking_done({
969
972
  })
970
973
  \`\`\`
971
974
 
972
- **저장 위치:** \`zzz_ai_Plan/YYYY-MM-DD_HHMM__제목__planId.md\` (플랫 구조, 로컬 전용)
975
+ **저장 위치:** \`zz_ai_3_Plan/YYYY-MM-DD_HHMM__제목__planId.md\` (플랫 구조, 로컬 전용)
973
976
 
974
977
  **핵심 가치:**
975
978
  - AI 세션이 끊겨도 (컴팩션, 세션 종료) 다음 AI가 계획 문서를 보고 이어서 작업 가능
@@ -1045,9 +1048,9 @@ C:\\Projects\\MyApp\\
1045
1048
  ├── src/
1046
1049
  ├── package.json
1047
1050
  ├── yy_All_Docu/ ← 프로젝트 A와 연결 (동기화)
1048
- ├── zz_ai_Talk/ ← AI 대화록 (로컬 전용)
1049
- ├── zz_ai_Todo/ ← AI 투두 (로컬 전용)
1050
- └── zzz_ai_Plan/ ← AI 플랜 (로컬 전용)
1051
+ ├── zz_ai_1_Talk/ ← AI 대화록 (로컬 전용)
1052
+ ├── zz_ai_2_Todo/ ← AI 투두 (로컬 전용)
1053
+ └── zz_ai_3_Plan/ ← AI 플랜 (로컬 전용)
1051
1054
 
1052
1055
  C:\\Projects\\MyWebsite\\
1053
1056
  ├── pages/
@@ -1145,12 +1148,12 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1145
1148
  };
1146
1149
  }
1147
1150
 
1148
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
1149
- // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
1151
+ // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
1152
+ // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
1150
1153
  const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1151
1154
  const isCoworker = !!coworkerMatch;
1152
- // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
1153
- const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
1155
+ // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
1156
+ const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
1154
1157
 
1155
1158
  // .docuking/config.json에 설정 저장
1156
1159
  saveLocalConfig(localPath, {
@@ -1158,11 +1161,11 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1158
1161
  projectName,
1159
1162
  apiKey,
1160
1163
  isCoworker,
1161
- coworkerName,
1164
+ coworkerFolder,
1162
1165
  createdAt: new Date().toISOString(),
1163
1166
  });
1164
1167
 
1165
- // 폴더 생성: 오너는 yy_All_Docu/, 협업자는 yy_All_Docu/yy_{이름}/
1168
+ // 폴더 생성: 오너는 yy_All_Docu/, 협업자는 yy_Coworker_{폴더명}/ (별도)
1166
1169
  const mainFolderName = 'yy_All_Docu';
1167
1170
  const mainFolderPath = path.join(localPath, mainFolderName);
1168
1171
 
@@ -1172,7 +1175,7 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1172
1175
  }
1173
1176
 
1174
1177
  // zz_ai_* 폴더도 함께 생성 (로컬 전용)
1175
- const aiFolders = ['zz_ai_Talk', 'zz_ai_Todo', 'zzz_ai_Plan'];
1178
+ const aiFolders = ['zz_ai_1_Talk', 'zz_ai_2_Todo', 'zz_ai_3_Plan'];
1176
1179
  for (const folder of aiFolders) {
1177
1180
  const folderPath = path.join(localPath, folder);
1178
1181
  if (!fs.existsSync(folderPath)) {
@@ -1184,9 +1187,9 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1184
1187
  let coworkerFolderPath = null;
1185
1188
 
1186
1189
  if (isCoworker) {
1187
- // 협업자: yy_All_Docu/yy_Coworker_{이름}/ 폴더 추가 생성
1188
- coworkerFolderName = `yy_Coworker_${coworkerName}`;
1189
- coworkerFolderPath = path.join(mainFolderPath, coworkerFolderName);
1190
+ // 협업자: yy_Coworker_{폴더명}/ 폴더를 yy_All_Docu/ 밖에 별도 생성
1191
+ coworkerFolderName = `yy_Coworker_${coworkerFolder}`;
1192
+ coworkerFolderPath = path.join(localPath, coworkerFolderName);
1190
1193
  if (!fs.existsSync(coworkerFolderPath)) {
1191
1194
  fs.mkdirSync(coworkerFolderPath, { recursive: true });
1192
1195
  }
@@ -1201,18 +1204,17 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1201
1204
  text: `DocuKing 연결 완료! (참여자)
1202
1205
 
1203
1206
  📁 프로젝트: ${projectName}
1204
- 📂 yy_All_Docu/ 폴더가 생성되었습니다.
1205
- 📂 yy_All_Docu/${coworkerFolderName}/ 작업 폴더가 생성되었습니다.
1206
- 👤 참여자: ${coworkerName}
1207
+ 📂 yy_All_Docu/ 폴더가 생성되었습니다. (오너 문서 Pull 대상)
1208
+ 📂 ${coworkerFolderName}/ 작업 폴더가 생성되었습니다. (내 Push 폴더)
1207
1209
  🔑 설정 저장: .docuking/config.json
1208
1210
 
1209
1211
  참여자 사용법:
1210
- - "DocuKing에서 가져와" → 전체 문서를 yy_All_Docu/에 Pull
1211
- - yy_All_Docu/${coworkerFolderName}/ 폴더에 문서 작성
1212
+ - "DocuKing에서 가져와" → 오너 문서를 yy_All_Docu/에 Pull
1213
+ - ${coworkerFolderName}/ 폴더에 문서 작성
1212
1214
  - "DocuKing에 올려줘" → 내 문서를 서버에 Push
1213
1215
 
1214
- 💡 참여자는 yy_All_Docu/${coworkerFolderName}/ 폴더에만 Push할 수 있습니다.
1215
- 다른 문서는 Pull로 읽을 수 있지만 수정은 자기 폴더에서 작성하세요.`,
1216
+ 💡 참여자는 ${coworkerFolderName}/ 폴더에만 Push할 수 있습니다.
1217
+ 오너 문서는 yy_All_Docu/에서 읽을 수 있지만, 수정은 자기 폴더에서 작성하세요.`,
1216
1218
  },
1217
1219
  ],
1218
1220
  };
@@ -1237,9 +1239,9 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1237
1239
 
1238
1240
  폴더 구조:
1239
1241
  - yy_All_Docu/ : 동기화 대상 (킹폴더)
1240
- - zz_ai_Talk/ : AI 대화록 (로컬 전용, 킹톡)
1241
- - zz_ai_Todo/ : AI 투두 (로컬 전용, 킹투두)
1242
- - zzz_ai_Plan/ : AI 플랜 (로컬 전용, 킹플랜)`,
1242
+ - zz_ai_1_Talk/ : AI 대화록 (로컬 전용, 킹톡)
1243
+ - zz_ai_2_Todo/ : AI 투두 (로컬 전용, 킹투두)
1244
+ - zz_ai_3_Plan/ : AI 플랜 (로컬 전용, 킹플랜)`,
1243
1245
  },
1244
1246
  ],
1245
1247
  };
@@ -1295,22 +1297,22 @@ Git처럼 무엇을 변경했는지 명확히 작성해주세요.
1295
1297
  const projectId = projectInfo.projectId;
1296
1298
  const projectName = projectInfo.projectName;
1297
1299
 
1298
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
1299
- // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
1300
+ // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
1301
+ // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
1300
1302
  const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1301
1303
  const isCoworker = !!coworkerMatch;
1302
- // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
1303
- const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
1304
- const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerName}` : null;
1304
+ // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
1305
+ const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
1306
+ const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerFolder}` : null;
1305
1307
 
1306
- // 작업 폴더 결정: 모두 yy_All_Docu/ 사용, 협업자는 yy_All_Docu/yy_Coworker_{이름}/ 에서 작업
1308
+ // 작업 폴더 결정: 오너는 yy_All_Docu/, 협업자는 yy_Coworker_{폴더명}/ (별도 폴더)
1307
1309
  const mainFolderPath = path.join(localPath, 'yy_All_Docu');
1308
1310
  let workingPath;
1309
1311
  let serverPathPrefix = ''; // 서버에 저장될 때 경로 접두사
1310
1312
 
1311
1313
  if (isCoworker) {
1312
- // 협업자: yy_All_Docu/yy_Coworker_{이름}/ 폴더에서 Push
1313
- workingPath = path.join(mainFolderPath, coworkerFolderName);
1314
+ // 협업자: yy_Coworker_{폴더명}/ 폴더에서 Push (yy_All_Docu/ 밖에 별도)
1315
+ workingPath = path.join(localPath, coworkerFolderName);
1314
1316
  serverPathPrefix = `${coworkerFolderName}/`;
1315
1317
 
1316
1318
  if (!fs.existsSync(workingPath)) {
@@ -1333,6 +1335,61 @@ docuking_init을 먼저 실행하세요.`,
1333
1335
  workingPath = mainFolderPath;
1334
1336
  }
1335
1337
 
1338
+ // .env 파일 자동 백업: _Infra_Config/ 폴더에 복사
1339
+ // 오너만 가능 (협업자는 _Infra_Config/ 에 접근 불가)
1340
+ if (!isCoworker) {
1341
+ const envFilePath = path.join(localPath, '.env');
1342
+ const infraConfigPath = path.join(mainFolderPath, '_Infra_Config');
1343
+
1344
+ if (fs.existsSync(envFilePath)) {
1345
+ // _Infra_Config 폴더 생성
1346
+ if (!fs.existsSync(infraConfigPath)) {
1347
+ fs.mkdirSync(infraConfigPath, { recursive: true });
1348
+ }
1349
+
1350
+ // .env 파일 복사
1351
+ const envBackupPath = path.join(infraConfigPath, '.env');
1352
+ try {
1353
+ fs.copyFileSync(envFilePath, envBackupPath);
1354
+ console.error(`[DocuKing] .env → _Infra_Config/.env 자동 백업 완료`);
1355
+ } catch (err) {
1356
+ console.error(`[DocuKing] .env 백업 실패: ${err.message}`);
1357
+ }
1358
+ }
1359
+
1360
+ // backend/.env 파일도 백업
1361
+ const backendEnvPath = path.join(localPath, 'backend', '.env');
1362
+ if (fs.existsSync(backendEnvPath)) {
1363
+ if (!fs.existsSync(infraConfigPath)) {
1364
+ fs.mkdirSync(infraConfigPath, { recursive: true });
1365
+ }
1366
+
1367
+ const backendEnvBackupPath = path.join(infraConfigPath, 'backend.env');
1368
+ try {
1369
+ fs.copyFileSync(backendEnvPath, backendEnvBackupPath);
1370
+ console.error(`[DocuKing] backend/.env → _Infra_Config/backend.env 자동 백업 완료`);
1371
+ } catch (err) {
1372
+ console.error(`[DocuKing] backend/.env 백업 실패: ${err.message}`);
1373
+ }
1374
+ }
1375
+
1376
+ // frontend/.env.local 파일도 백업
1377
+ const frontendEnvPath = path.join(localPath, 'frontend', '.env.local');
1378
+ if (fs.existsSync(frontendEnvPath)) {
1379
+ if (!fs.existsSync(infraConfigPath)) {
1380
+ fs.mkdirSync(infraConfigPath, { recursive: true });
1381
+ }
1382
+
1383
+ const frontendEnvBackupPath = path.join(infraConfigPath, 'frontend.env.local');
1384
+ try {
1385
+ fs.copyFileSync(frontendEnvPath, frontendEnvBackupPath);
1386
+ console.error(`[DocuKing] frontend/.env.local → _Infra_Config/frontend.env.local 자동 백업 완료`);
1387
+ } catch (err) {
1388
+ console.error(`[DocuKing] frontend/.env.local 백업 실패: ${err.message}`);
1389
+ }
1390
+ }
1391
+ }
1392
+
1336
1393
  // 파일 목록 수집
1337
1394
  const filesToPush = [];
1338
1395
  const excludedFiles = []; // 제외된 파일 목록
@@ -1353,7 +1410,7 @@ docuking_init을 먼저 실행하세요.`,
1353
1410
  };
1354
1411
  }
1355
1412
 
1356
- // 서버 경로: 코워커는 yy_Coworker_{이름}/파일경로, 오너는 파일경로
1413
+ // 서버 경로: 코워커는 yy_Coworker_{폴더명}/파일경로, 오너는 파일경로
1357
1414
  const serverFilePath = serverPathPrefix + filePath;
1358
1415
  filesToPush.push({ path: filePath, serverPath: serverFilePath, fullPath, fileType });
1359
1416
  }
@@ -1534,7 +1591,7 @@ docuking_init을 먼저 실행하세요.`,
1534
1591
  },
1535
1592
  body: JSON.stringify({
1536
1593
  projectId,
1537
- path: file.serverPath, // 서버 경로 (코워커는 yy_Coworker_{이름}/파일경로)
1594
+ path: file.serverPath, // 서버 경로 (코워커는 yy_Coworker_{폴더명}/파일경로)
1538
1595
  content,
1539
1596
  encoding, // 'utf-8' 또는 'base64'
1540
1597
  message, // 커밋 메시지
@@ -2122,21 +2179,21 @@ async function handleStatus(args) {
2122
2179
  const projectId = projectInfo.projectId;
2123
2180
  const projectName = projectInfo.projectName;
2124
2181
 
2125
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_이름_)
2126
- // 이름이 비어있는 경우도 처리 (sk_xxx_cw__)
2182
+ // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
2183
+ // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
2127
2184
  const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
2128
2185
  const isCoworker = !!coworkerMatch;
2129
- // 코워커 이름이 비어있으면 'Coworker'로 기본값 설정
2130
- const coworkerName = coworkerMatch ? (coworkerMatch[1] || 'Coworker') : null;
2131
- const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerName}` : null;
2186
+ // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
2187
+ const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
2188
+ const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerFolder}` : null;
2132
2189
 
2133
2190
  // 권한 정보 구성
2134
2191
  let permissionInfo = '';
2135
2192
  if (isCoworker) {
2136
2193
  permissionInfo = `\n\n## 현재 권한: 참여자 (Co-worker)
2137
- - 이름: ${coworkerName}
2194
+ - 작업 폴더: ${coworkerFolderName}/
2138
2195
  - 읽기 권한: 전체 문서 (Pull로 yy_All_Docu/ 폴더의 문서 가져오기 가능)
2139
- - 쓰기 권한: yy_All_Docu/${coworkerFolderName}/ 폴더만
2196
+ - 쓰기 권한: ${coworkerFolderName}/ 폴더만
2140
2197
  - 설명: 협업자 폴더에서 작업하면 자동으로 서버에 Push됩니다.`;
2141
2198
  } else {
2142
2199
  permissionInfo = `\n\n## 현재 권한: 오너 (Owner)
@@ -2170,8 +2227,8 @@ async function handleStatus(args) {
2170
2227
  const mainFolderPath = path.join(localPath, 'yy_All_Docu');
2171
2228
 
2172
2229
  if (isCoworker) {
2173
- // 협업자: yy_All_Docu/yy_{이름}/ 폴더에서 파일 수집
2174
- const coworkerPath = path.join(mainFolderPath, coworkerFolderName);
2230
+ // 협업자: yy_Coworker_{폴더명}/ 폴더에서 파일 수집 (yy_All_Docu/ 밖에 별도)
2231
+ const coworkerPath = path.join(localPath, coworkerFolderName);
2175
2232
  if (fs.existsSync(coworkerPath)) {
2176
2233
  collectFiles(coworkerPath, '', localFiles);
2177
2234
  }
@@ -2185,7 +2242,7 @@ async function handleStatus(args) {
2185
2242
  }
2186
2243
 
2187
2244
  const projectNameInfo = projectName ? ` (${projectName})` : '';
2188
- const workingFolder = isCoworker ? `yy_All_Docu/${coworkerFolderName}` : 'yy_All_Docu';
2245
+ const workingFolder = isCoworker ? coworkerFolderName : 'yy_All_Docu';
2189
2246
  const statusText = `DocuKing 동기화 상태
2190
2247
 
2191
2248
  **프로젝트**: ${projectId}${projectNameInfo}
@@ -2327,8 +2384,8 @@ function generatePlanId() {
2327
2384
  async function handleTodo(args) {
2328
2385
  const { localPath, action, todo, todoId } = args;
2329
2386
 
2330
- // zz_ai_Todo 폴더 경로 (로컬 전용, 킹투두)
2331
- const todoBasePath = path.join(localPath, 'zz_ai_Todo');
2387
+ // zz_ai_2_Todo 폴더 경로 (로컬 전용, 킹투두)
2388
+ const todoBasePath = path.join(localPath, 'zz_ai_2_Todo');
2332
2389
  const todoFilePath = path.join(todoBasePath, 'z_King_Todo.md');
2333
2390
 
2334
2391
  // 폴더 생성
@@ -2489,7 +2546,7 @@ async function handleTodo(args) {
2489
2546
  text: `📋 킹투두 미결: 없음
2490
2547
 
2491
2548
  ✅ 완료: ${completedCount}개
2492
- 📁 전체 기록: zz_ai_Todo/z_King_Todo.md`,
2549
+ 📁 전체 기록: zz_ai_2_Todo/z_King_Todo.md`,
2493
2550
  }],
2494
2551
  };
2495
2552
  }
@@ -2504,7 +2561,7 @@ async function handleTodo(args) {
2504
2561
  ${listText}
2505
2562
 
2506
2563
  ✅ 완료: ${completedCount}개
2507
- 📁 전체 기록: zz_ai_Todo/z_King_Todo.md`,
2564
+ 📁 전체 기록: zz_ai_2_Todo/z_King_Todo.md`,
2508
2565
  }],
2509
2566
  };
2510
2567
  }
@@ -2518,8 +2575,8 @@ ${listText}
2518
2575
  async function handleTalk(args) {
2519
2576
  const { localPath, title, content, tags = [] } = args;
2520
2577
 
2521
- // zz_ai_Talk 폴더 경로 (로컬 전용, 킹톡)
2522
- const talkBasePath = path.join(localPath, 'zz_ai_Talk');
2578
+ // zz_ai_1_Talk 폴더 경로 (로컬 전용, 킹톡)
2579
+ const talkBasePath = path.join(localPath, 'zz_ai_1_Talk');
2523
2580
 
2524
2581
  // 날짜 기반 파일명 생성 (T_ 접두사)
2525
2582
  const { fileName, timestamp } = generateDateFileName(title, 'T');
@@ -2571,8 +2628,8 @@ ${content}
2571
2628
  async function handlePlan(args) {
2572
2629
  const { localPath, planId, title, goal, steps = [], notes } = args;
2573
2630
 
2574
- // zzz_ai_Plan 폴더 경로 (로컬 전용, 킹플랜)
2575
- const planBasePath = path.join(localPath, 'zzz_ai_Plan');
2631
+ // zz_ai_3_Plan 폴더 경로 (로컬 전용, 킹플랜)
2632
+ const planBasePath = path.join(localPath, 'zz_ai_3_Plan');
2576
2633
 
2577
2634
  // 기존 계획 업데이트 또는 새 계획 생성
2578
2635
  let targetPlanId = planId;
@@ -2721,8 +2778,8 @@ function findPlanFiles(basePath, planId) {
2721
2778
  async function handleDone(args) {
2722
2779
  const { localPath, planId, summary, artifacts = [] } = args;
2723
2780
 
2724
- // zzz_ai_Plan 폴더 경로 (로컬 전용, 킹플랜)
2725
- const planBasePath = path.join(localPath, 'zzz_ai_Plan');
2781
+ // zz_ai_3_Plan 폴더 경로 (로컬 전용, 킹플랜)
2782
+ const planBasePath = path.join(localPath, 'zz_ai_3_Plan');
2726
2783
 
2727
2784
  // 계획 파일 찾기
2728
2785
  const planFiles = findPlanFiles(planBasePath, planId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docuking-mcp",
3
- "version": "2.0.7",
3
+ "version": "2.1.1",
4
4
  "description": "DocuKing MCP Server - AI 시대의 문서 협업 플랫폼",
5
5
  "type": "module",
6
6
  "main": "index.js",