docuking-mcp 2.1.3 → 2.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.
Files changed (2) hide show
  1. package/index.js +101 -69
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -40,6 +40,29 @@ import crypto from 'crypto';
40
40
  // 환경변수에서 API 엔드포인트 설정 (키는 로컬 config에서 읽음)
41
41
  const API_ENDPOINT = process.env.DOCUKING_API_ENDPOINT || 'https://docuking.ai/api';
42
42
 
43
+ /**
44
+ * API 키에서 협업자 폴더명 추출
45
+ * API 키 형식: sk_프로젝트8자_cw_폴더명_랜덤48자(hex)
46
+ * hex는 0-9, a-f만 포함하므로 언더스코어 없음
47
+ * 따라서 _cw_ 이후 마지막 _ 전까지가 폴더명
48
+ */
49
+ function parseCoworkerFromApiKey(apiKey) {
50
+ if (!apiKey) return { isCoworker: false, coworkerFolder: null };
51
+
52
+ const cwIndex = apiKey.indexOf('_cw_');
53
+ if (cwIndex === -1) return { isCoworker: false, coworkerFolder: null };
54
+
55
+ const afterCw = apiKey.substring(cwIndex + 4);
56
+ const lastUnderscore = afterCw.lastIndexOf('_');
57
+ if (lastUnderscore === -1) return { isCoworker: false, coworkerFolder: null };
58
+
59
+ const folderName = afterCw.substring(0, lastUnderscore);
60
+ return {
61
+ isCoworker: !!folderName,
62
+ coworkerFolder: folderName || null,
63
+ };
64
+ }
65
+
43
66
  // 파일 크기 제한 (150MB) - Base64 인코딩 시 약 200MB, 서버 제한 200MB와 일치
44
67
  const MAX_FILE_SIZE_MB = 150;
45
68
  const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
@@ -105,13 +128,11 @@ function getAiBasePath(localPath) {
105
128
  }
106
129
 
107
130
  const apiKey = config.apiKey;
108
- // 협업자 형식: sk_xxx_cw_폴더명_
109
- const coworkerMatch = apiKey.match(/_cw_([^_]+)_$/);
131
+ const { isCoworker, coworkerFolder } = parseCoworkerFromApiKey(apiKey);
110
132
 
111
- if (coworkerMatch) {
112
- const folderName = coworkerMatch[1];
113
- const coworkerFolderPath = path.join(localPath, `yy_Coworker_${folderName}`);
114
- return { isCoworker: true, basePath: coworkerFolderPath, coworkerFolder: folderName };
133
+ if (isCoworker && coworkerFolder) {
134
+ const coworkerFolderPath = path.join(localPath, `yy_Coworker_${coworkerFolder}`);
135
+ return { isCoworker: true, basePath: coworkerFolderPath, coworkerFolder };
115
136
  }
116
137
 
117
138
  return { isCoworker: false, basePath: localPath, coworkerFolder: null };
@@ -121,68 +142,91 @@ function getAiBasePath(localPath) {
121
142
  * CLAUDE.md에 DocuKing MCP 작업 기록 규칙 추가
122
143
  * - 파일이 없으면 새로 생성
123
144
  * - 파일이 있으면 DocuKing 섹션이 없을 때만 추가
145
+ * - Talk → Todo → Plan → Done 흐름 포함
124
146
  */
125
147
  function updateClaudeMd(localPath) {
126
148
  const claudeMdPath = path.join(localPath, 'CLAUDE.md');
127
- const marker = '## DocuKing AI 작업 기록 (필수)';
149
+ const marker = '## DocuKing 연결됨';
150
+ const oldMarker = '## DocuKing AI 작업 기록 (필수)';
128
151
 
129
152
  const docukingSection = `
130
153
  ---
131
154
 
132
155
  ${marker}
133
156
 
134
- **모든 작업은 MCP 도구로 기록한다. 예외 없음.**
135
-
136
- ### 작업 시작 시 → \`docuking_plan\`
137
- \`\`\`
138
- docuking_plan({
139
- localPath: "${localPath.replace(/\\/g, '\\\\')}",
140
- title: "작업 제목",
141
- goal: "작업 목표",
142
- steps: [
143
- { name: "단계1", status: "pending" },
144
- { name: "단계2", status: "pending" }
145
- ]
146
- })
147
- \`\`\`
148
-
149
- ### 단계 완료 시 → \`docuking_plan\` (업데이트)
150
- \`\`\`
151
- docuking_plan({
152
- localPath: "${localPath.replace(/\\/g, '\\\\')}",
153
- planId: "기존 planId",
154
- title: "작업 제목",
155
- steps: [
156
- { name: "단계1", status: "done", result: "결과 요약" },
157
- { name: "단계2", status: "in_progress" }
158
- ]
159
- })
160
- \`\`\`
161
-
162
- ### 작업 완료 → \`docuking_done\`
163
- \`\`\`
164
- docuking_done({
165
- localPath: "${localPath.replace(/\\/g, '\\\\')}",
166
- planId: "planId",
167
- summary: "작업 완료 요약",
168
- artifacts: ["변경된/파일/경로.ts"]
169
- })
170
- \`\`\`
171
-
172
- ### 절대 규칙
173
- - **작업 시작 반드시 \`docuking_plan\` 호출**
174
- - **작업 완료 반드시 \`docuking_done\` 호출**
175
- - 결과는 \`zz_ai_3_Plan/\`에 자동 저장됨 (로컬 전용)
157
+ ### MCP 도구
158
+ | 도구 | 용도 |
159
+ |------|------|
160
+ | docuking_push | 문서 업로드 ("올려줘") |
161
+ | docuking_pull | 문서 다운로드 ("가져와") |
162
+ | docuking_list | 서버 파일 목록 조회 |
163
+ | docuking_status | 동기화 상태 확인 |
164
+ | docuking_log | 커밋 히스토리 조회 |
165
+ | docuking_diff | 버전 간 차이 비교 |
166
+ | docuking_rollback | 특정 커밋으로 되돌림 |
167
+ | docuking_plan | 작업 시작 시 계획 기록 |
168
+ | docuking_done | 작업 완료 시 결과 기록 |
169
+ | docuking_todo | 킹투두 (프로젝트 할일) |
170
+ | docuking_talk | 대화록 저장 |
171
+
172
+ ### 작업 흐름 (필수)
173
+
174
+ **1단계: Talk 기록 (작업 원인/배경)**
175
+ - 사용자 요청의 배경, 논의 내용을 먼저 기록
176
+ - Plan을 세우기 전에 반드시 Talk로 " 이 작업을 하는지" 남김
177
+
178
+ **2단계: Todo 등록 (할일 등록)**
179
+ - 의미 있는 작업이면 킹투두에 등록
180
+ - 나중에 추적/공유할 가치가 있는 작업
181
+
182
+ **3단계: Plan 생성 → 작업 → Done 완료**
183
+ - 기존대로 plan → 작업 → done
184
+
185
+ ### Talk 자동 기록 (docuking_talk)
186
+
187
+ **다음 상황에서 AI가 자동으로 기록:**
188
+ - 설계 방향 결정 (A vs B 선택, "왜 이렇게?")
189
+ - 버그 원인 분석 및 해결책 논의
190
+ - 아키텍처/구조 변경 논의
191
+ - 사용자가 중요한 결정을 내릴 때
192
+ - Plan을 세우게 된 원인/배경 논의
193
+
194
+ ### Todo 자동 등록 (docuking_todo)
195
+
196
+ **다음 상황에서 AI가 자동으로 등록:**
197
+ - 사용자가 "나중에 해야 것" 언급 시
198
+ - 작업 발견한 추가 개선사항
199
+ - "TODO", "FIXME" 성격의 발견 사항
200
+ - 의미 있는 작업 시작 시 (추적용)
201
+
202
+ ### 규칙
203
+ 1. yy_All_Docu/ 폴더만 동기화 대상
204
+ 2. Push는 사용자 요청 시에만
205
+ 3. **Talk → Todo → Plan → Done** 순서 준수
206
+ 4. Plan 전에 반드시 Talk로 배경 기록
176
207
  `;
177
208
 
178
209
  try {
179
210
  if (fs.existsSync(claudeMdPath)) {
180
211
  // 파일이 있으면 DocuKing 섹션 존재 여부 확인
181
- const content = fs.readFileSync(claudeMdPath, 'utf-8');
212
+ let content = fs.readFileSync(claudeMdPath, 'utf-8');
213
+
214
+ // 새 마커가 이미 있으면 스킵
182
215
  if (content.includes(marker)) {
183
- // 이미 DocuKing 섹션이 있으면 스킵
184
216
  return;
185
217
  }
218
+
219
+ // 구버전 마커가 있으면 교체
220
+ if (content.includes(oldMarker)) {
221
+ // 구버전 섹션 찾아서 교체 (--- 부터 끝까지 또는 다음 --- 전까지)
222
+ const oldSectionStart = content.lastIndexOf('---\n\n' + oldMarker);
223
+ if (oldSectionStart !== -1) {
224
+ content = content.substring(0, oldSectionStart) + docukingSection;
225
+ fs.writeFileSync(claudeMdPath, content, 'utf-8');
226
+ return;
227
+ }
228
+ }
229
+
186
230
  // 섹션이 없으면 끝에 추가
187
231
  fs.appendFileSync(claudeMdPath, docukingSection, 'utf-8');
188
232
  } else {
@@ -1172,12 +1216,8 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
1172
1216
  };
1173
1217
  }
1174
1218
 
1175
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
1176
- // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
1177
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1178
- const isCoworker = !!coworkerMatch;
1179
- // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
1180
- const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
1219
+ // Co-worker 권한은 API Key 형식에서 판단
1220
+ const { isCoworker, coworkerFolder } = parseCoworkerFromApiKey(apiKey);
1181
1221
 
1182
1222
  // .docuking/config.json에 설정 저장
1183
1223
  saveLocalConfig(localPath, {
@@ -1344,12 +1384,8 @@ Git처럼 무엇을 변경했는지 명확히 작성해주세요.
1344
1384
  const projectId = projectInfo.projectId;
1345
1385
  const projectName = projectInfo.projectName;
1346
1386
 
1347
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
1348
- // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
1349
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
1350
- const isCoworker = !!coworkerMatch;
1351
- // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
1352
- const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
1387
+ // Co-worker 권한은 API Key 형식에서 판단
1388
+ const { isCoworker, coworkerFolder } = parseCoworkerFromApiKey(apiKey);
1353
1389
  const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerFolder}` : null;
1354
1390
 
1355
1391
  // 작업 폴더 결정: 오너는 yy_All_Docu/, 협업자는 yy_Coworker_{폴더명}/ (별도 폴더)
@@ -2271,12 +2307,8 @@ async function handleStatus(args) {
2271
2307
  const projectId = projectInfo.projectId;
2272
2308
  const projectName = projectInfo.projectName;
2273
2309
 
2274
- // Co-worker 권한은 API Key 형식에서 판단 (sk_xxx_cw_폴더명_)
2275
- // 폴더명이 비어있는 경우도 처리 (sk_xxx_cw__)
2276
- const coworkerMatch = apiKey.match(/^sk_[a-f0-9]+_cw_([^_]*)_/);
2277
- const isCoworker = !!coworkerMatch;
2278
- // 코워커 폴더명이 비어있으면 'default'로 기본값 설정
2279
- const coworkerFolder = coworkerMatch ? (coworkerMatch[1] || 'default') : null;
2310
+ // Co-worker 권한은 API Key 형식에서 판단
2311
+ const { isCoworker, coworkerFolder } = parseCoworkerFromApiKey(apiKey);
2280
2312
  const coworkerFolderName = isCoworker ? `yy_Coworker_${coworkerFolder}` : null;
2281
2313
 
2282
2314
  // 권한 정보 구성
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docuking-mcp",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "DocuKing MCP Server - AI 시대의 문서 협업 플랫폼",
5
5
  "type": "module",
6
6
  "main": "index.js",