docuking-mcp 2.1.1 → 2.1.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.
- package/index.js +126 -22
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -93,6 +93,30 @@ function saveLocalConfig(localPath, config) {
|
|
|
93
93
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* 협업자 여부 및 zz_ai 폴더 기본 경로 반환
|
|
98
|
+
* - 오너: localPath (루트에 zz_ai_* 폴더)
|
|
99
|
+
* - 협업자: localPath/yy_Coworker_{폴더명} (협업자 폴더 안에 zz_ai_* 폴더)
|
|
100
|
+
*/
|
|
101
|
+
function getAiBasePath(localPath) {
|
|
102
|
+
const config = getLocalConfig(localPath);
|
|
103
|
+
if (!config || !config.apiKey) {
|
|
104
|
+
return { isCoworker: false, basePath: localPath, coworkerFolder: null };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const apiKey = config.apiKey;
|
|
108
|
+
// 협업자 키 형식: sk_xxx_cw_폴더명_
|
|
109
|
+
const coworkerMatch = apiKey.match(/_cw_([^_]+)_$/);
|
|
110
|
+
|
|
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 };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { isCoworker: false, basePath: localPath, coworkerFolder: null };
|
|
118
|
+
}
|
|
119
|
+
|
|
96
120
|
/**
|
|
97
121
|
* CLAUDE.md에 DocuKing MCP 작업 기록 규칙 추가
|
|
98
122
|
* - 파일이 없으면 새로 생성
|
|
@@ -1174,18 +1198,12 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
|
|
|
1174
1198
|
fs.mkdirSync(mainFolderPath, { recursive: true });
|
|
1175
1199
|
}
|
|
1176
1200
|
|
|
1177
|
-
// zz_ai_* 폴더도 함께 생성 (로컬 전용)
|
|
1178
|
-
const aiFolders = ['zz_ai_1_Talk', 'zz_ai_2_Todo', 'zz_ai_3_Plan'];
|
|
1179
|
-
for (const folder of aiFolders) {
|
|
1180
|
-
const folderPath = path.join(localPath, folder);
|
|
1181
|
-
if (!fs.existsSync(folderPath)) {
|
|
1182
|
-
fs.mkdirSync(folderPath, { recursive: true });
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
1201
|
let coworkerFolderName = null;
|
|
1187
1202
|
let coworkerFolderPath = null;
|
|
1188
1203
|
|
|
1204
|
+
// zz_ai_* 폴더 목록
|
|
1205
|
+
const aiFolders = ['zz_ai_1_Talk', 'zz_ai_2_Todo', 'zz_ai_3_Plan'];
|
|
1206
|
+
|
|
1189
1207
|
if (isCoworker) {
|
|
1190
1208
|
// 협업자: yy_Coworker_{폴더명}/ 폴더를 yy_All_Docu/ 밖에 별도 생성
|
|
1191
1209
|
coworkerFolderName = `yy_Coworker_${coworkerFolder}`;
|
|
@@ -1193,6 +1211,35 @@ docuking_init 호출 시 apiKey 파라미터를 포함해주세요.`,
|
|
|
1193
1211
|
if (!fs.existsSync(coworkerFolderPath)) {
|
|
1194
1212
|
fs.mkdirSync(coworkerFolderPath, { recursive: true });
|
|
1195
1213
|
}
|
|
1214
|
+
// 협업자 폴더 안에 _Private/ 생성
|
|
1215
|
+
const coworkerPrivatePath = path.join(coworkerFolderPath, '_Private');
|
|
1216
|
+
if (!fs.existsSync(coworkerPrivatePath)) {
|
|
1217
|
+
fs.mkdirSync(coworkerPrivatePath, { recursive: true });
|
|
1218
|
+
}
|
|
1219
|
+
// 협업자 폴더 안에 zz_ai_* 폴더 생성
|
|
1220
|
+
for (const folder of aiFolders) {
|
|
1221
|
+
const folderPath = path.join(coworkerFolderPath, folder);
|
|
1222
|
+
if (!fs.existsSync(folderPath)) {
|
|
1223
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
} else {
|
|
1227
|
+
// 오너: yy_All_Docu/ 안에 _Infra_Config/와 _Private/ 생성
|
|
1228
|
+
const infraConfigPath = path.join(mainFolderPath, '_Infra_Config');
|
|
1229
|
+
if (!fs.existsSync(infraConfigPath)) {
|
|
1230
|
+
fs.mkdirSync(infraConfigPath, { recursive: true });
|
|
1231
|
+
}
|
|
1232
|
+
const ownerPrivatePath = path.join(mainFolderPath, '_Private');
|
|
1233
|
+
if (!fs.existsSync(ownerPrivatePath)) {
|
|
1234
|
+
fs.mkdirSync(ownerPrivatePath, { recursive: true });
|
|
1235
|
+
}
|
|
1236
|
+
// 오너: 루트에 zz_ai_* 폴더 생성
|
|
1237
|
+
for (const folder of aiFolders) {
|
|
1238
|
+
const folderPath = path.join(localPath, folder);
|
|
1239
|
+
if (!fs.existsSync(folderPath)) {
|
|
1240
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1196
1243
|
}
|
|
1197
1244
|
|
|
1198
1245
|
// 연결 완료 안내 (오너/코워커에 따라 다른 메시지)
|
|
@@ -1388,6 +1435,54 @@ docuking_init을 먼저 실행하세요.`,
|
|
|
1388
1435
|
console.error(`[DocuKing] frontend/.env.local 백업 실패: ${err.message}`);
|
|
1389
1436
|
}
|
|
1390
1437
|
}
|
|
1438
|
+
|
|
1439
|
+
// package.json 파일 백업 (루트)
|
|
1440
|
+
const packageJsonPath = path.join(localPath, 'package.json');
|
|
1441
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
1442
|
+
if (!fs.existsSync(infraConfigPath)) {
|
|
1443
|
+
fs.mkdirSync(infraConfigPath, { recursive: true });
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
const packageJsonBackupPath = path.join(infraConfigPath, 'package.json');
|
|
1447
|
+
try {
|
|
1448
|
+
fs.copyFileSync(packageJsonPath, packageJsonBackupPath);
|
|
1449
|
+
console.error(`[DocuKing] package.json → _Infra_Config/package.json 자동 백업 완료`);
|
|
1450
|
+
} catch (err) {
|
|
1451
|
+
console.error(`[DocuKing] package.json 백업 실패: ${err.message}`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// backend/package.json 파일도 백업
|
|
1456
|
+
const backendPackageJsonPath = path.join(localPath, 'backend', 'package.json');
|
|
1457
|
+
if (fs.existsSync(backendPackageJsonPath)) {
|
|
1458
|
+
if (!fs.existsSync(infraConfigPath)) {
|
|
1459
|
+
fs.mkdirSync(infraConfigPath, { recursive: true });
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
const backendPackageJsonBackupPath = path.join(infraConfigPath, 'backend.package.json');
|
|
1463
|
+
try {
|
|
1464
|
+
fs.copyFileSync(backendPackageJsonPath, backendPackageJsonBackupPath);
|
|
1465
|
+
console.error(`[DocuKing] backend/package.json → _Infra_Config/backend.package.json 자동 백업 완료`);
|
|
1466
|
+
} catch (err) {
|
|
1467
|
+
console.error(`[DocuKing] backend/package.json 백업 실패: ${err.message}`);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// frontend/package.json 파일도 백업
|
|
1472
|
+
const frontendPackageJsonPath = path.join(localPath, 'frontend', 'package.json');
|
|
1473
|
+
if (fs.existsSync(frontendPackageJsonPath)) {
|
|
1474
|
+
if (!fs.existsSync(infraConfigPath)) {
|
|
1475
|
+
fs.mkdirSync(infraConfigPath, { recursive: true });
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
const frontendPackageJsonBackupPath = path.join(infraConfigPath, 'frontend.package.json');
|
|
1479
|
+
try {
|
|
1480
|
+
fs.copyFileSync(frontendPackageJsonPath, frontendPackageJsonBackupPath);
|
|
1481
|
+
console.error(`[DocuKing] frontend/package.json → _Infra_Config/frontend.package.json 자동 백업 완료`);
|
|
1482
|
+
} catch (err) {
|
|
1483
|
+
console.error(`[DocuKing] frontend/package.json 백업 실패: ${err.message}`);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1391
1486
|
}
|
|
1392
1487
|
|
|
1393
1488
|
// 파일 목록 수집
|
|
@@ -2027,7 +2122,8 @@ const FILE_TYPES = {
|
|
|
2027
2122
|
'.hwpx', '.hwp',
|
|
2028
2123
|
],
|
|
2029
2124
|
|
|
2030
|
-
// 제외 파일 (업로드 거부) -
|
|
2125
|
+
// 제외 파일 (업로드 거부) - 실행파일/시스템 이미지만
|
|
2126
|
+
// 영상/오디오는 150MB 이하면 허용 (유튜브 쇼츠 등)
|
|
2031
2127
|
EXCLUDED: [
|
|
2032
2128
|
// 압축/아카이브 (설치파일 포함 가능성 높음)
|
|
2033
2129
|
'.zip', '.tar', '.gz', '.tgz', '.7z', '.rar', '.tar.Z',
|
|
@@ -2037,10 +2133,6 @@ const FILE_TYPES = {
|
|
|
2037
2133
|
'.exe', '.msi', '.dll', '.so', '.dylib', '.com', '.app', '.pkg', '.deb', '.rpm',
|
|
2038
2134
|
// macOS 스크립트
|
|
2039
2135
|
'.scpt',
|
|
2040
|
-
// 동영상
|
|
2041
|
-
'.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v',
|
|
2042
|
-
// 오디오
|
|
2043
|
-
'.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a',
|
|
2044
2136
|
// 디스크 이미지
|
|
2045
2137
|
'.iso', '.dmg', '.img', '.vhd', '.vmdk',
|
|
2046
2138
|
],
|
|
@@ -2384,8 +2476,11 @@ function generatePlanId() {
|
|
|
2384
2476
|
async function handleTodo(args) {
|
|
2385
2477
|
const { localPath, action, todo, todoId } = args;
|
|
2386
2478
|
|
|
2387
|
-
//
|
|
2388
|
-
|
|
2479
|
+
// 협업자 여부에 따라 zz_ai 경로 결정
|
|
2480
|
+
// - 오너: localPath/zz_ai_2_Todo/
|
|
2481
|
+
// - 협업자: localPath/yy_Coworker_{폴더명}/zz_ai_2_Todo/
|
|
2482
|
+
const { basePath } = getAiBasePath(localPath);
|
|
2483
|
+
const todoBasePath = path.join(basePath, 'zz_ai_2_Todo');
|
|
2389
2484
|
const todoFilePath = path.join(todoBasePath, 'z_King_Todo.md');
|
|
2390
2485
|
|
|
2391
2486
|
// 폴더 생성
|
|
@@ -2575,8 +2670,11 @@ ${listText}
|
|
|
2575
2670
|
async function handleTalk(args) {
|
|
2576
2671
|
const { localPath, title, content, tags = [] } = args;
|
|
2577
2672
|
|
|
2578
|
-
//
|
|
2579
|
-
|
|
2673
|
+
// 협업자 여부에 따라 zz_ai 경로 결정
|
|
2674
|
+
// - 오너: localPath/zz_ai_1_Talk/
|
|
2675
|
+
// - 협업자: localPath/yy_Coworker_{폴더명}/zz_ai_1_Talk/
|
|
2676
|
+
const { basePath } = getAiBasePath(localPath);
|
|
2677
|
+
const talkBasePath = path.join(basePath, 'zz_ai_1_Talk');
|
|
2580
2678
|
|
|
2581
2679
|
// 날짜 기반 파일명 생성 (T_ 접두사)
|
|
2582
2680
|
const { fileName, timestamp } = generateDateFileName(title, 'T');
|
|
@@ -2628,8 +2726,11 @@ ${content}
|
|
|
2628
2726
|
async function handlePlan(args) {
|
|
2629
2727
|
const { localPath, planId, title, goal, steps = [], notes } = args;
|
|
2630
2728
|
|
|
2631
|
-
//
|
|
2632
|
-
|
|
2729
|
+
// 협업자 여부에 따라 zz_ai 경로 결정
|
|
2730
|
+
// - 오너: localPath/zz_ai_3_Plan/
|
|
2731
|
+
// - 협업자: localPath/yy_Coworker_{폴더명}/zz_ai_3_Plan/
|
|
2732
|
+
const { basePath } = getAiBasePath(localPath);
|
|
2733
|
+
const planBasePath = path.join(basePath, 'zz_ai_3_Plan');
|
|
2633
2734
|
|
|
2634
2735
|
// 기존 계획 업데이트 또는 새 계획 생성
|
|
2635
2736
|
let targetPlanId = planId;
|
|
@@ -2778,8 +2879,11 @@ function findPlanFiles(basePath, planId) {
|
|
|
2778
2879
|
async function handleDone(args) {
|
|
2779
2880
|
const { localPath, planId, summary, artifacts = [] } = args;
|
|
2780
2881
|
|
|
2781
|
-
//
|
|
2782
|
-
|
|
2882
|
+
// 협업자 여부에 따라 zz_ai 경로 결정
|
|
2883
|
+
// - 오너: localPath/zz_ai_3_Plan/
|
|
2884
|
+
// - 협업자: localPath/yy_Coworker_{폴더명}/zz_ai_3_Plan/
|
|
2885
|
+
const { basePath } = getAiBasePath(localPath);
|
|
2886
|
+
const planBasePath = path.join(basePath, 'zz_ai_3_Plan');
|
|
2783
2887
|
|
|
2784
2888
|
// 계획 파일 찾기
|
|
2785
2889
|
const planFiles = findPlanFiles(planBasePath, planId);
|