docuking-mcp 2.1.2 → 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 +124 -17
- 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
|
// 파일 목록 수집
|
|
@@ -2381,8 +2476,11 @@ function generatePlanId() {
|
|
|
2381
2476
|
async function handleTodo(args) {
|
|
2382
2477
|
const { localPath, action, todo, todoId } = args;
|
|
2383
2478
|
|
|
2384
|
-
//
|
|
2385
|
-
|
|
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');
|
|
2386
2484
|
const todoFilePath = path.join(todoBasePath, 'z_King_Todo.md');
|
|
2387
2485
|
|
|
2388
2486
|
// 폴더 생성
|
|
@@ -2572,8 +2670,11 @@ ${listText}
|
|
|
2572
2670
|
async function handleTalk(args) {
|
|
2573
2671
|
const { localPath, title, content, tags = [] } = args;
|
|
2574
2672
|
|
|
2575
|
-
//
|
|
2576
|
-
|
|
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');
|
|
2577
2678
|
|
|
2578
2679
|
// 날짜 기반 파일명 생성 (T_ 접두사)
|
|
2579
2680
|
const { fileName, timestamp } = generateDateFileName(title, 'T');
|
|
@@ -2625,8 +2726,11 @@ ${content}
|
|
|
2625
2726
|
async function handlePlan(args) {
|
|
2626
2727
|
const { localPath, planId, title, goal, steps = [], notes } = args;
|
|
2627
2728
|
|
|
2628
|
-
//
|
|
2629
|
-
|
|
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');
|
|
2630
2734
|
|
|
2631
2735
|
// 기존 계획 업데이트 또는 새 계획 생성
|
|
2632
2736
|
let targetPlanId = planId;
|
|
@@ -2775,8 +2879,11 @@ function findPlanFiles(basePath, planId) {
|
|
|
2775
2879
|
async function handleDone(args) {
|
|
2776
2880
|
const { localPath, planId, summary, artifacts = [] } = args;
|
|
2777
2881
|
|
|
2778
|
-
//
|
|
2779
|
-
|
|
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');
|
|
2780
2887
|
|
|
2781
2888
|
// 계획 파일 찾기
|
|
2782
2889
|
const planFiles = findPlanFiles(planBasePath, planId);
|