@mandujs/cli 0.13.0 → 0.13.2

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/package.json +1 -1
  2. package/src/commands/init.ts +143 -108
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
5
5
  "type": "module",
6
6
  "main": "./src/main.ts",
@@ -252,23 +252,11 @@ export async function init(options: InitOptions = {}): Promise<boolean> {
252
252
  console.log(` src/client/shared/lib/utils.ts → 유틸리티 (cn 함수)`);
253
253
  }
254
254
 
255
- // MCP 설정 안내
256
- console.log(`\n🤖 AI 에이전트 통합:`);
257
- if (mcpResult.status === "created") {
258
- console.log(` .mcp.json 생성됨 (Claude Code 자동 연결)`);
259
- } else if (mcpResult.status === "updated") {
260
- console.log(` .mcp.json에 mandu 서버 추가/업데이트됨`);
261
- } else if (mcpResult.status === "unchanged") {
262
- console.log(` .mcp.json 이미 최신`);
263
- } else if (mcpResult.status === "backed-up") {
264
- console.log(` .mcp.json 파싱 실패 → 백업 후 새로 생성됨`);
265
- if (mcpResult.backupPath) {
266
- console.log(` 백업: ${mcpResult.backupPath}`);
267
- }
268
- } else if (mcpResult.status === "error") {
269
- console.log(` .mcp.json 설정 실패: ${mcpResult.error}`);
270
- }
271
- console.log(` AGENTS.md → 에이전트 가이드 (Bun 사용 명시)`);
255
+ // MCP 설정 안내
256
+ console.log(`\n🤖 AI 에이전트 통합:`);
257
+ logMcpConfigStatus(".mcp.json", mcpResult.mcpJson, "Claude Code 자동 연결");
258
+ logMcpConfigStatus(".claude.json", mcpResult.claudeJson, "Claude MCP 로컬 범위");
259
+ console.log(` AGENTS.md 에이전트 가이드 (Bun 사용 명시)`);
272
260
 
273
261
  // Lockfile 안내
274
262
  console.log(`\n🔒 설정 무결성:`);
@@ -382,97 +370,144 @@ async function updatePackageJson(
382
370
  await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
383
371
  }
384
372
 
385
- type McpConfigStatus = "created" | "updated" | "unchanged" | "backed-up" | "error";
386
-
387
- interface McpConfigResult {
388
- status: McpConfigStatus;
389
- backupPath?: string;
390
- error?: string;
391
- }
392
-
393
- /**
394
- * .mcp.json 설정 (AI 에이전트 통합)
395
- * - 파일 없으면 새로 생성
396
- * - 파일 있으면 mandu 서버만 추가/업데이트 (다른 설정 유지)
397
- */
398
- async function setupMcpConfig(targetDir: string): Promise<McpConfigResult> {
399
- const mcpPath = path.join(targetDir, ".mcp.json");
400
-
401
- const manduServer = {
402
- command: "bunx",
403
- args: ["@mandujs/mcp"],
404
- };
405
-
406
- const writeConfig = async (data: Record<string, unknown>) => {
407
- await fs.writeFile(mcpPath, JSON.stringify(data, null, 2) + "\n");
408
- };
409
-
410
- const fileExists = async (filePath: string) => {
411
- try {
412
- await fs.access(filePath);
413
- return true;
414
- } catch {
415
- return false;
416
- }
417
- };
418
-
419
- const getBackupPath = async (basePath: string) => {
420
- const base = `${basePath}.bak`;
421
- if (!(await fileExists(base))) {
422
- return base;
423
- }
424
- for (let i = 1; i <= 50; i++) {
425
- const candidate = `${basePath}.bak.${i}`;
426
- if (!(await fileExists(candidate))) {
427
- return candidate;
428
- }
429
- }
430
- return `${basePath}.bak.${Date.now()}`;
431
- };
432
-
433
- try {
434
- const existingContent = await fs.readFile(mcpPath, "utf-8");
435
- let existing: Record<string, unknown>;
436
-
437
- try {
438
- existing = JSON.parse(existingContent) as Record<string, unknown>;
439
- } catch {
440
- const backupPath = await getBackupPath(mcpPath);
441
- await fs.writeFile(backupPath, existingContent);
442
- await writeConfig({ mcpServers: { mandu: manduServer } });
443
- return { status: "backed-up", backupPath };
444
- }
445
-
446
- if (!existing || typeof existing !== "object") {
447
- existing = {};
448
- }
449
-
450
- if (!existing.mcpServers || typeof existing.mcpServers !== "object") {
451
- existing.mcpServers = {};
452
- }
453
-
454
- const current = (existing.mcpServers as Record<string, unknown>).mandu;
455
- const isSame =
456
- current && JSON.stringify(current) === JSON.stringify(manduServer);
457
-
458
- if (isSame) {
459
- return { status: "unchanged" };
460
- }
461
-
462
- (existing.mcpServers as Record<string, unknown>).mandu = manduServer;
463
- await writeConfig(existing);
464
- return { status: "updated" };
465
- } catch (error) {
466
- if (error && typeof error === "object" && "code" in error && (error as { code?: string }).code === "ENOENT") {
467
- await writeConfig({ mcpServers: { mandu: manduServer } });
468
- return { status: "created" };
469
- }
470
- return {
471
- status: "error",
472
- error: error instanceof Error ? error.message : String(error),
473
- };
474
- }
475
- }
373
+ type McpConfigStatus = "created" | "updated" | "unchanged" | "backed-up" | "error";
374
+
375
+ interface McpConfigFileResult {
376
+ status: McpConfigStatus;
377
+ backupPath?: string;
378
+ error?: string;
379
+ }
380
+
381
+ interface McpConfigResult {
382
+ mcpJson: McpConfigFileResult;
383
+ claudeJson: McpConfigFileResult;
384
+ }
385
+
386
+ function logMcpConfigStatus(
387
+ label: string,
388
+ result: McpConfigFileResult,
389
+ createdNote?: string
390
+ ): void {
391
+ if (result.status === "created") {
392
+ console.log(` ${label} 생성됨${createdNote ? ` (${createdNote})` : ""}`);
393
+ return;
394
+ }
395
+
396
+ if (result.status === "updated") {
397
+ console.log(` ${label}에 mandu 서버 추가/업데이트됨`);
398
+ return;
399
+ }
400
+
401
+ if (result.status === "unchanged") {
402
+ console.log(` ${label} 이미 최신`);
403
+ return;
404
+ }
405
+
406
+ if (result.status === "backed-up") {
407
+ console.log(` ${label} 파싱 실패 백업 새로 생성됨`);
408
+ if (result.backupPath) {
409
+ console.log(` 백업: ${result.backupPath}`);
410
+ }
411
+ return;
412
+ }
413
+
414
+ if (result.status === "error") {
415
+ console.log(` ${label} 설정 실패: ${result.error}`);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * .mcp.json / .claude.json 설정 (AI 에이전트 통합)
421
+ * - 파일 없으면 새로 생성
422
+ * - 파일 있으면 mandu 서버만 추가/업데이트 (다른 설정 유지)
423
+ */
424
+ async function setupMcpConfig(targetDir: string): Promise<McpConfigResult> {
425
+ const mcpPath = path.join(targetDir, ".mcp.json");
426
+ const claudePath = path.join(targetDir, ".claude.json");
427
+
428
+ const manduServer = {
429
+ command: "bunx",
430
+ args: ["@mandujs/mcp"],
431
+ cwd: ".",
432
+ };
433
+
434
+ const updateMcpFile = async (filePath: string): Promise<McpConfigFileResult> => {
435
+ const writeConfig = async (data: Record<string, unknown>) => {
436
+ await fs.writeFile(filePath, JSON.stringify(data, null, 2) + "\n");
437
+ };
438
+
439
+ const fileExists = async (candidatePath: string) => {
440
+ try {
441
+ await fs.access(candidatePath);
442
+ return true;
443
+ } catch {
444
+ return false;
445
+ }
446
+ };
447
+
448
+ const getBackupPath = async (basePath: string) => {
449
+ const base = `${basePath}.bak`;
450
+ if (!(await fileExists(base))) {
451
+ return base;
452
+ }
453
+ for (let i = 1; i <= 50; i++) {
454
+ const candidate = `${basePath}.bak.${i}`;
455
+ if (!(await fileExists(candidate))) {
456
+ return candidate;
457
+ }
458
+ }
459
+ return `${basePath}.bak.${Date.now()}`;
460
+ };
461
+
462
+ try {
463
+ const existingContent = await fs.readFile(filePath, "utf-8");
464
+ let existing: Record<string, unknown>;
465
+
466
+ try {
467
+ existing = JSON.parse(existingContent) as Record<string, unknown>;
468
+ } catch {
469
+ const backupPath = await getBackupPath(filePath);
470
+ await fs.writeFile(backupPath, existingContent);
471
+ await writeConfig({ mcpServers: { mandu: manduServer } });
472
+ return { status: "backed-up", backupPath };
473
+ }
474
+
475
+ if (!existing || typeof existing !== "object") {
476
+ existing = {};
477
+ }
478
+
479
+ if (!existing.mcpServers || typeof existing.mcpServers !== "object") {
480
+ existing.mcpServers = {};
481
+ }
482
+
483
+ const current = (existing.mcpServers as Record<string, unknown>).mandu;
484
+ const isSame =
485
+ current && JSON.stringify(current) === JSON.stringify(manduServer);
486
+
487
+ if (isSame) {
488
+ return { status: "unchanged" };
489
+ }
490
+
491
+ (existing.mcpServers as Record<string, unknown>).mandu = manduServer;
492
+ await writeConfig(existing);
493
+ return { status: "updated" };
494
+ } catch (error) {
495
+ if (error && typeof error === "object" && "code" in error && (error as { code?: string }).code === "ENOENT") {
496
+ await writeConfig({ mcpServers: { mandu: manduServer } });
497
+ return { status: "created" };
498
+ }
499
+ return {
500
+ status: "error",
501
+ error: error instanceof Error ? error.message : String(error),
502
+ };
503
+ }
504
+ };
505
+
506
+ const mcpJson = await updateMcpFile(mcpPath);
507
+ const claudeJson = await updateMcpFile(claudePath);
508
+
509
+ return { mcpJson, claudeJson };
510
+ }
476
511
 
477
512
  interface LockfileResult {
478
513
  success: boolean;