@vibecodetown/mcp-server 2.2.0 → 2.2.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 (70) hide show
  1. package/README.md +10 -10
  2. package/build/auth/index.js +0 -2
  3. package/build/auth/public_key.js +6 -4
  4. package/build/bootstrap/doctor.js +113 -5
  5. package/build/bootstrap/installer.js +85 -15
  6. package/build/bootstrap/registry.js +11 -6
  7. package/build/bootstrap/skills-installer.js +365 -0
  8. package/build/dx/activity.js +26 -3
  9. package/build/engine.js +151 -0
  10. package/build/errors.js +107 -0
  11. package/build/generated/bridge_build_seed_input.js +2 -0
  12. package/build/generated/bridge_build_seed_output.js +2 -0
  13. package/build/generated/bridge_confirm_reference_input.js +2 -0
  14. package/build/generated/bridge_confirm_reference_output.js +2 -0
  15. package/build/generated/bridge_confirmed_reference_file.js +2 -0
  16. package/build/generated/bridge_generate_references_input.js +2 -0
  17. package/build/generated/bridge_generate_references_output.js +2 -0
  18. package/build/generated/bridge_references_file.js +2 -0
  19. package/build/generated/bridge_work_order_seed_file.js +2 -0
  20. package/build/generated/contracts_bundle_info.js +3 -3
  21. package/build/generated/index.js +14 -0
  22. package/build/generated/ingress_input.js +2 -0
  23. package/build/generated/ingress_output.js +2 -0
  24. package/build/generated/ingress_resolution_file.js +2 -0
  25. package/build/generated/ingress_summary_file.js +2 -0
  26. package/build/generated/message_template_id_mapping_file.js +2 -0
  27. package/build/generated/run_app_input.js +1 -1
  28. package/build/index.js +4 -3
  29. package/build/local-mode/paths.js +1 -0
  30. package/build/local-mode/setup.js +21 -1
  31. package/build/path-utils.js +68 -0
  32. package/build/runtime/cli_invoker.js +1 -1
  33. package/build/tools/vibe_pm/advisory_review.js +5 -3
  34. package/build/tools/vibe_pm/bridge_build_seed.js +164 -0
  35. package/build/tools/vibe_pm/bridge_confirm_reference.js +91 -0
  36. package/build/tools/vibe_pm/bridge_generate_references.js +258 -0
  37. package/build/tools/vibe_pm/briefing.js +27 -3
  38. package/build/tools/vibe_pm/context.js +79 -0
  39. package/build/tools/vibe_pm/create_work_order.js +200 -3
  40. package/build/tools/vibe_pm/doctor.js +95 -0
  41. package/build/tools/vibe_pm/entity_gate/preflight.js +8 -3
  42. package/build/tools/vibe_pm/export_output.js +14 -13
  43. package/build/tools/vibe_pm/finalize_work.js +78 -40
  44. package/build/tools/vibe_pm/get_decision.js +2 -2
  45. package/build/tools/vibe_pm/index.js +128 -42
  46. package/build/tools/vibe_pm/ingress.js +645 -0
  47. package/build/tools/vibe_pm/ingress_gate.js +116 -0
  48. package/build/tools/vibe_pm/inspect_code.js +90 -20
  49. package/build/tools/vibe_pm/kce/doc_usage.js +4 -9
  50. package/build/tools/vibe_pm/kce/on_finalize.js +2 -2
  51. package/build/tools/vibe_pm/kce/preflight.js +11 -7
  52. package/build/tools/vibe_pm/memory_status.js +11 -8
  53. package/build/tools/vibe_pm/memory_sync.js +11 -8
  54. package/build/tools/vibe_pm/pm_language.js +17 -16
  55. package/build/tools/vibe_pm/python_error.js +115 -0
  56. package/build/tools/vibe_pm/run_app.js +169 -43
  57. package/build/tools/vibe_pm/run_app_podman.js +64 -2
  58. package/build/tools/vibe_pm/search_oss.js +5 -3
  59. package/build/tools/vibe_pm/spec_rag.js +185 -0
  60. package/build/tools/vibe_pm/status.js +50 -3
  61. package/build/tools/vibe_pm/submit_decision.js +2 -2
  62. package/build/tools/vibe_pm/types.js +28 -0
  63. package/build/tools/vibe_pm/undo_last_task.js +9 -2
  64. package/build/tools/vibe_pm/waiter_mapping.js +155 -0
  65. package/build/tools/vibe_pm/zoekt_evidence.js +5 -3
  66. package/build/tools.js +13 -5
  67. package/build/vibe-cli.js +245 -7
  68. package/package.json +5 -4
  69. package/skills/VRIP_INSTALL_MANIFEST_DOCTOR.skill.md +288 -0
  70. package/skills/index.json +14 -0
package/build/vibe-cli.js CHANGED
@@ -6,6 +6,7 @@ import * as path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { healthCheck, validateCacheIntegrity, checkForUpdates } from "./bootstrap/doctor.js";
8
8
  import { ensureEngines } from "./bootstrap/installer.js";
9
+ import { listAvailableSkills, listActivatedSkills, getSkillById, activateSkills, deactivateSkill, getSkillsHealth, getSkillContent } from "./bootstrap/skills-installer.js";
9
10
  import { CONTRACTS_BUNDLE_SHA256, CONTRACTS_VERSION } from "./generated/contracts_bundle_info.js";
10
11
  import { spawnBashScriptInRepoSync } from "./local-mode/bash.js";
11
12
  import { getGitHooksPath, getGitRoot } from "./local-mode/git.js";
@@ -77,9 +78,21 @@ async function cmdDoctor() {
77
78
  // Check cache integrity
78
79
  const cacheResult = await validateCacheIntegrity();
79
80
  console.log(` Cache: ${cacheResult.valid ? c("green", "✓") : c("yellow", "⚠")} ${cacheResult.valid ? "valid" : "needs repair"}`);
80
- // Check Agent Skills files
81
+ // Check Skills Bundle
81
82
  console.log("");
82
- console.log(" Agent Skills:");
83
+ console.log(" Skills Bundle:");
84
+ const skillsStatus = health.skills.status;
85
+ const skillsIcon = skillsStatus === "OK"
86
+ ? c("green", "✓")
87
+ : skillsStatus === "WARN"
88
+ ? c("yellow", "⚠")
89
+ : c("red", "✗");
90
+ console.log(` Status: ${skillsIcon} ${skillsStatus}`);
91
+ console.log(` Version: ${health.skills.version ?? c("dim", "unknown")}`);
92
+ console.log(` Installed: ${health.skills.summary.ok}/${health.skills.summary.total}`);
93
+ // Check Agent Skills files (project-level guidance)
94
+ console.log("");
95
+ console.log(" Agent Guidance Files:");
83
96
  const skillFiles = [
84
97
  { name: "AGENTS.md", path: "AGENTS.md" },
85
98
  { name: ".cursorrules", path: ".cursorrules" },
@@ -93,7 +106,7 @@ async function cmdDoctor() {
93
106
  // Summary
94
107
  console.log("");
95
108
  console.log(c("cyan", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
96
- const allOk = health.status === "OK" && cacheResult.valid;
109
+ const allOk = health.status === "OK" && cacheResult.valid && skillsStatus === "OK";
97
110
  if (allOk) {
98
111
  console.log("");
99
112
  console.log(` ${c("green", "✓ 모든 것이 정상입니다!")}`);
@@ -192,16 +205,18 @@ async function cmdSetup() {
192
205
  return;
193
206
  }
194
207
  // Step 1: Local mode
195
- console.log(" Step 1/3: 로컬 모드 초기화...");
208
+ console.log(" Step 1/4: 로컬 모드 초기화...");
196
209
  // Step 2: Engines
197
210
  if (!localOnly) {
198
- console.log(" Step 2/3: 엔진 설치...");
211
+ console.log(" Step 2/4: 엔진 설치...");
199
212
  }
200
213
  else {
201
- console.log(" Step 2/3: 엔진 설치 (스킵 - local-only)");
214
+ console.log(" Step 2/4: 엔진 설치 (스킵 - local-only)");
202
215
  }
203
216
  // Step 3: Version lock
204
- console.log(" Step 3/3: 버전 잠금...");
217
+ console.log(" Step 3/4: 버전 잠금...");
218
+ // Step 4: Skills
219
+ console.log(" Step 4/4: 스킬 활성화...");
205
220
  const result = await runSetup(repoRoot, VERSION, {
206
221
  force: forceFlag,
207
222
  localOnly,
@@ -221,6 +236,9 @@ async function cmdSetup() {
221
236
  const ok = result.engines.filter(e => e.status === "ok").length;
222
237
  console.log(` ${c("green", "\u2713")} 엔진: ${ok}/${result.engines.length} 준비됨`);
223
238
  }
239
+ if (result.skills.activated.length > 0) {
240
+ console.log(` ${c("green", "\u2713")} 스킬: ${result.skills.activated.length}개 활성화됨`);
241
+ }
224
242
  if (result.versionLock) {
225
243
  console.log(` ${c("green", "\u2713")} 버전 잠금 생성됨`);
226
244
  }
@@ -616,6 +634,200 @@ async function cmdUpdate() {
616
634
  console.log("");
617
635
  }
618
636
  // ============================================================
637
+ // Skills Management Commands
638
+ // ============================================================
639
+ /**
640
+ * vibe skills - Skill bundle management
641
+ *
642
+ * Subcommands:
643
+ * list - List all available skills
644
+ * activate - Activate skill(s) for this project
645
+ * deactivate - Deactivate a skill from this project
646
+ * info - Show skill details
647
+ * status - Show skills health status
648
+ */
649
+ async function cmdSkills() {
650
+ const args = process.argv.slice(3); // after "vibe skills"
651
+ const subcommand = args[0] ?? "list";
652
+ const jsonMode = args.includes("--json");
653
+ const projectRoot = process.cwd();
654
+ switch (subcommand) {
655
+ case "list": {
656
+ const available = listAvailableSkills();
657
+ const activated = listActivatedSkills(projectRoot);
658
+ if (jsonMode) {
659
+ console.log(JSON.stringify({ available, activated }, null, 2));
660
+ return;
661
+ }
662
+ console.log("");
663
+ console.log(c("cyan", "Vibe PM Skills"));
664
+ console.log("");
665
+ console.log(" Available Skills:");
666
+ if (available.length === 0) {
667
+ console.log(` ${c("dim", "(none)")}`);
668
+ }
669
+ else {
670
+ for (const skill of available) {
671
+ const isActive = activated.includes(skill.id);
672
+ const status = isActive ? c("green", "✓") : c("dim", "○");
673
+ console.log(` ${status} ${skill.id.padEnd(35)} v${skill.version}`);
674
+ console.log(` ${c("dim", skill.description)}`);
675
+ }
676
+ }
677
+ console.log("");
678
+ if (activated.length > 0) {
679
+ console.log(` Activated: ${c("green", String(activated.length))} / ${available.length}`);
680
+ }
681
+ else {
682
+ console.log(` ${c("dim", "No skills activated. Run:")} ${c("cyan", "vibe skills activate <id>")}`);
683
+ }
684
+ console.log("");
685
+ break;
686
+ }
687
+ case "activate": {
688
+ const skillIds = args.slice(1).filter(a => !a.startsWith("-"));
689
+ if (skillIds.length === 0) {
690
+ // Activate all skills if no ID specified
691
+ console.log("");
692
+ console.log(c("cyan", "Activating all available skills..."));
693
+ console.log("");
694
+ }
695
+ const result = await activateSkills(projectRoot, skillIds.length > 0 ? skillIds : undefined);
696
+ if (jsonMode) {
697
+ console.log(JSON.stringify(result, null, 2));
698
+ return;
699
+ }
700
+ if (result.activated.length > 0) {
701
+ console.log(` ${c("green", "✓")} Activated skills:`);
702
+ for (const id of result.activated) {
703
+ console.log(` - ${id}`);
704
+ }
705
+ }
706
+ if (result.errors.length > 0) {
707
+ console.log("");
708
+ console.log(` ${c("red", "✗")} Errors:`);
709
+ for (const err of result.errors) {
710
+ console.log(` - ${err}`);
711
+ }
712
+ }
713
+ console.log("");
714
+ break;
715
+ }
716
+ case "deactivate": {
717
+ const skillId = args[1];
718
+ if (!skillId || skillId.startsWith("-")) {
719
+ console.log(` ${c("red", "✗")} Usage: vibe skills deactivate <skill_id>`);
720
+ return;
721
+ }
722
+ const result = await deactivateSkill(projectRoot, skillId);
723
+ if (jsonMode) {
724
+ console.log(JSON.stringify(result, null, 2));
725
+ return;
726
+ }
727
+ if (result.success) {
728
+ console.log(` ${c("green", "✓")} Deactivated: ${skillId}`);
729
+ }
730
+ else {
731
+ console.log(` ${c("red", "✗")} ${result.error}`);
732
+ }
733
+ console.log("");
734
+ break;
735
+ }
736
+ case "info": {
737
+ const skillId = args[1];
738
+ if (!skillId || skillId.startsWith("-")) {
739
+ console.log(` ${c("red", "✗")} Usage: vibe skills info <skill_id>`);
740
+ return;
741
+ }
742
+ const skill = getSkillById(skillId);
743
+ if (!skill) {
744
+ console.log(` ${c("red", "✗")} Skill not found: ${skillId}`);
745
+ return;
746
+ }
747
+ if (jsonMode) {
748
+ console.log(JSON.stringify(skill, null, 2));
749
+ return;
750
+ }
751
+ console.log("");
752
+ console.log(c("cyan", `Skill: ${skill.id}`));
753
+ console.log("");
754
+ console.log(` Version: ${skill.version}`);
755
+ console.log(` Description: ${skill.description}`);
756
+ console.log(` Tags: ${skill.tags.join(", ")}`);
757
+ console.log(` File: ${skill.file}`);
758
+ console.log(` SHA256: ${skill.sha256.slice(0, 16)}...`);
759
+ console.log("");
760
+ // Show content preview
761
+ const content = getSkillContent(skillId);
762
+ if (content) {
763
+ const lines = content.split("\n").slice(0, 10);
764
+ console.log(c("dim", " Preview:"));
765
+ for (const line of lines) {
766
+ console.log(` ${c("dim", line.slice(0, 60))}`);
767
+ }
768
+ if (content.split("\n").length > 10) {
769
+ console.log(` ${c("dim", "...")}`);
770
+ }
771
+ }
772
+ console.log("");
773
+ break;
774
+ }
775
+ case "status": {
776
+ const health = getSkillsHealth();
777
+ if (jsonMode) {
778
+ console.log(JSON.stringify(health, null, 2));
779
+ return;
780
+ }
781
+ console.log("");
782
+ console.log(c("cyan", "Skills Bundle Status"));
783
+ console.log("");
784
+ console.log(` Installed: ${health.installed ? c("green", "✓") : c("red", "✗")}`);
785
+ console.log(` Bundle Path: ${health.bundlePath ?? c("dim", "(not found)")}`);
786
+ console.log(` Version: ${health.version ?? c("dim", "(unknown)")}`);
787
+ console.log("");
788
+ console.log(" Skills:");
789
+ for (const skill of health.skills) {
790
+ const icon = skill.status === "ok"
791
+ ? c("green", "✓")
792
+ : skill.status === "missing"
793
+ ? c("red", "✗")
794
+ : c("yellow", "⚠");
795
+ console.log(` ${icon} ${skill.id} (${skill.status})`);
796
+ if (skill.error) {
797
+ console.log(` ${c("dim", skill.error)}`);
798
+ }
799
+ }
800
+ console.log("");
801
+ console.log(` Summary: ${c("green", String(health.summary.ok))} ok, ` +
802
+ `${c("red", String(health.summary.missing))} missing, ` +
803
+ `${c("yellow", String(health.summary.corrupted))} corrupted`);
804
+ console.log("");
805
+ break;
806
+ }
807
+ case "help":
808
+ default: {
809
+ console.log("");
810
+ console.log(c("cyan", "vibe skills") + " - Skill bundle management");
811
+ console.log("");
812
+ console.log("Subcommands:");
813
+ console.log(` ${c("green", "list")} List all available skills`);
814
+ console.log(` ${c("green", "activate")} Activate skill(s) for this project`);
815
+ console.log(` ${c("green", "deactivate")} Deactivate a skill from this project`);
816
+ console.log(` ${c("green", "info")} Show skill details`);
817
+ console.log(` ${c("green", "status")} Show skills health status`);
818
+ console.log("");
819
+ console.log("Examples:");
820
+ console.log(` ${c("dim", "$")} vibe skills list`);
821
+ console.log(` ${c("dim", "$")} vibe skills activate VRIP_INSTALL_MANIFEST_DOCTOR`);
822
+ console.log(` ${c("dim", "$")} vibe skills activate # activate all`);
823
+ console.log(` ${c("dim", "$")} vibe skills info VRIP_INSTALL_MANIFEST_DOCTOR`);
824
+ console.log(` ${c("dim", "$")} vibe skills status --json`);
825
+ console.log("");
826
+ break;
827
+ }
828
+ }
829
+ }
830
+ // ============================================================
619
831
  // New Commands: exec, inspect, run (VRIP v1.1 compliant)
620
832
  // ============================================================
621
833
  /**
@@ -1058,6 +1270,27 @@ Usage: vibe run [options]
1058
1270
 
1059
1271
  프로젝트 설정에 따라 앱을 실행합니다.
1060
1272
  (현재 개발 중 - vibe_pm.run_app MCP 도구 사용)
1273
+ `,
1274
+ skills: `vibe skills - 스킬 번들 관리
1275
+
1276
+ Usage: vibe skills <command> [options]
1277
+
1278
+ Commands:
1279
+ list 사용 가능한 스킬 목록
1280
+ activate 프로젝트에 스킬 활성화
1281
+ deactivate 스킬 비활성화
1282
+ info 스킬 상세 정보
1283
+ status 스킬 번들 상태 확인
1284
+
1285
+ Options:
1286
+ --json JSON 형식 출력
1287
+
1288
+ Examples:
1289
+ $ vibe skills list
1290
+ $ vibe skills activate VRIP_INSTALL_MANIFEST_DOCTOR
1291
+ $ vibe skills activate # 모든 스킬 활성화
1292
+ $ vibe skills info VRIP_INSTALL_MANIFEST_DOCTOR
1293
+ $ vibe skills status --json
1061
1294
  `,
1062
1295
  };
1063
1296
  // P0-1: Helper functions for --help priority handling
@@ -1093,6 +1326,7 @@ function cmdHelp(subcommand) {
1093
1326
  console.log(` ${c("green", "version")} 버전 정보 출력`);
1094
1327
  console.log(` ${c("green", "reset")} 프로젝트 초기화 (runs/ 정리)`);
1095
1328
  console.log(` ${c("green", "update")} 엔진 바이너리 업데이트`);
1329
+ console.log(` ${c("green", "skills")} 스킬 번들 관리`);
1096
1330
  console.log(` ${c("green", "help")} 이 도움말 표시`);
1097
1331
  console.log("");
1098
1332
  console.log("Options:");
@@ -1108,6 +1342,7 @@ function cmdHelp(subcommand) {
1108
1342
  console.log(` ${c("dim", "$")} vibe inspect --json # VRIP 모드 검수`);
1109
1343
  console.log(` ${c("dim", "$")} vibe exec status # 데몬 상태 확인`);
1110
1344
  console.log(` ${c("dim", "$")} vibe doctor # 설치 진단`);
1345
+ console.log(` ${c("dim", "$")} vibe skills list # 스킬 목록`);
1111
1346
  console.log(` ${c("dim", "$")} vibe reset --force # 프로젝트 초기화`);
1112
1347
  console.log("");
1113
1348
  console.log("More info:");
@@ -1184,6 +1419,9 @@ async function main() {
1184
1419
  case "run":
1185
1420
  await cmdRun();
1186
1421
  break;
1422
+ case "skills":
1423
+ await cmdSkills();
1424
+ break;
1187
1425
  case "help":
1188
1426
  case "-h":
1189
1427
  case "--help":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecodetown/mcp-server",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
5
  "description": "Vibe PM - AI Project Manager MCP Server for non-technical founders",
6
6
  "keywords": [
@@ -27,13 +27,13 @@
27
27
  "node": ">=18"
28
28
  },
29
29
  "bin": {
30
- "mcp-server": "build/index.js",
31
- "vibecode-mcp": "build/index.js",
32
- "vibe": "build/vibe-cli.js"
30
+ "vibecode-mcp": "./build/index.js",
31
+ "vibe": "./build/vibe-cli.js"
33
32
  },
34
33
  "main": "./build/index.js",
35
34
  "files": [
36
35
  "build/",
36
+ "skills/",
37
37
  "README.md",
38
38
  "LICENSE"
39
39
  ],
@@ -57,6 +57,7 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@modelcontextprotocol/sdk": "^1.0.0",
60
+ "@msgpack/msgpack": "^3.1.3",
60
61
  "minimatch": "^9.0.3",
61
62
  "node-notifier": "^10.0.1",
62
63
  "simple-git": "^3.30.0",
@@ -0,0 +1,288 @@
1
+ # Skill: VRIP + install_manifest + doctor 운영 스킬 v1
2
+
3
+ > **Version**: 1.0.0
4
+ > **Target**: Claude Code / Codex CLI / Cursor
5
+ > **Created**: 2026-01-24
6
+
7
+ ## 0) 이 스킬의 목표
8
+
9
+ * MCP↔CLI↔Daemon이 **설치 상태/실행 상태**를 헷갈리지 않게 강제한다.
10
+ * `.vibe/install_manifest.json`을 **설치 SSOT**로 유지한다.
11
+ * `vibe doctor`로 **Gate 판정(PASS/WARN/FAIL)** 을 일관되게 만든다.
12
+ * MCP는 "읽기 전용" 규칙을 어기지 않는다.
13
+
14
+ ---
15
+
16
+ ## 1) 입력 (Input)
17
+
18
+ 사용자가 아래 중 하나를 요청하면 이 스킬을 실행한다.
19
+
20
+ * "설치 상태 확인해줘"
21
+ * "왜 MCP는 되는데 로컬이 안 돼?"
22
+ * "엔진 버전 꼬였나?"
23
+ * "doctor 결과 이상함"
24
+ * "manifest 스키마/권한/갱신 규칙 적용"
25
+ * "MCP가 로컬을 안 쓰는 느낌인데?"
26
+
27
+ ---
28
+
29
+ ## 2) 출력 (Output)
30
+
31
+ 항상 아래 3가지를 반환한다.
32
+
33
+ 1. **현재 상태 요약**: 설치/엔진/데몬/무결성
34
+ 2. **Gate 결과**: PASS/WARN/FAIL + 코드 목록
35
+ 3. **즉시 실행 커맨드**: `vibe doctor`, `vibe update`, `vibe exec status` 등 최소 세트
36
+
37
+ ---
38
+
39
+ ## 3) 핵심 규칙 (Law 요약)
40
+
41
+ | 규칙 | 설명 |
42
+ |------|------|
43
+ | MCP는 manifest를 **절대 쓰지 않는다** | 읽기 전용 |
44
+ | 설치/엔진 상태 갱신 | **vibe update만** |
45
+ | 진단 요약 갱신 | **vibe doctor만** |
46
+ | 데몬 생존 갱신 | **vibe exec --daemon만** |
47
+ | 결과의 SSOT | **run_dir** |
48
+ | 설치의 SSOT | **install_manifest** |
49
+
50
+ ---
51
+
52
+ ## 4) 실행 절차 (Step-by-step)
53
+
54
+ ### Step 1) manifest 존재/파싱
55
+
56
+ * 파일: `.vibe/install_manifest.json`
57
+ * 없으면:
58
+ * **FAIL: MANIFEST_MISSING**
59
+ * 다음 액션: `vibe update` (설치/생성 담당)
60
+
61
+ ### Step 2) doctor로 Gate 판정 생성
62
+
63
+ * 실행: `vibe doctor --json`
64
+ * 결과를 `integrity.doctor_summary`로 기록(doctor가 쓰는 유일한 영역)
65
+
66
+ ### Step 3) engines/components 점검(doctor 결과 기반)
67
+
68
+ * `status != ok`인 엔진 있으면:
69
+ * **FAIL** (sha_mismatch, missing, wrong_platform, permission_denied)
70
+ * 다음 액션: `vibe update --engine <name>` 또는 `vibe update`
71
+
72
+ ### Step 4) bins 점검
73
+
74
+ * `bins.vibe.ok == false` → FAIL
75
+ * `bins.mcp_server.ok == false` → FAIL
76
+ * 다음 액션: 패키지 재설치 or update 루틴
77
+
78
+ ### Step 5) 데몬 상태(선택)
79
+
80
+ * `vibe exec status --json`
81
+ * lock stale이면:
82
+ * WARN 또는 FAIL(운영 정책에 따라)
83
+ * 다음 액션: `vibe exec stop` 후 재기동
84
+
85
+ ---
86
+
87
+ ## 5) Gate 체크리스트 (표준 코드)
88
+
89
+ doctor는 반드시 아래 코드 체계를 써라(이름 통일이 중요).
90
+
91
+ ### FAIL (즉시 중단/수리 필요)
92
+
93
+ | 코드 | 설명 |
94
+ |------|------|
95
+ | `MANIFEST_MISSING` | manifest 파일 없음 |
96
+ | `MANIFEST_SCHEMA_INVALID` | manifest 스키마 검증 실패 |
97
+ | `BIN_VIBE_MISSING` | vibe CLI 바이너리 없음 |
98
+ | `BIN_MCP_SERVER_MISSING` | MCP 서버 바이너리 없음 |
99
+ | `ENGINE_MISSING:<name>` | 특정 엔진 없음 |
100
+ | `ENGINE_SHA_MISMATCH:<name>` | 엔진 SHA256 불일치 |
101
+ | `ENGINE_WRONG_PLATFORM:<name>` | 플랫폼 불일치 |
102
+ | `ENGINE_PERMISSION_DENIED:<name>` | 엔진 실행 권한 없음 |
103
+ | `RUN_ROOT_UNWRITABLE` | runs 디렉토리 쓰기 불가 |
104
+ | `DAEMON_MISCONFIGURED` | 데몬 설정 오류 |
105
+
106
+ ### WARN (기능은 되지만 위험)
107
+
108
+ | 코드 | 설명 |
109
+ |------|------|
110
+ | `PKG_VERSION_MISMATCH` | 패키지 버전 불일치 |
111
+ | `DAEMON_STALE_LOCK` | 데몬 lock 파일 stale |
112
+ | `RUN_ROOT_CONFLICT_SUSPECTED` | run_dir 충돌 의심 |
113
+
114
+ ### INFO
115
+
116
+ | 코드 | 설명 |
117
+ |------|------|
118
+ | `DAEMON_NOT_USED` | 데몬 미사용 |
119
+ | `CACHE_OK` | 캐시 정상 |
120
+ | `ENGINE_OK:<name>` | 특정 엔진 정상 |
121
+
122
+ ---
123
+
124
+ ## 6) 표준 커맨드 세트 (복붙용)
125
+
126
+ ### 설치/동기화(SSOT 생성/갱신)
127
+
128
+ ```bash
129
+ vibe update
130
+ ```
131
+
132
+ ### 진단(Gate 판정)
133
+
134
+ ```bash
135
+ vibe doctor --json
136
+ ```
137
+
138
+ ### 데몬 상태
139
+
140
+ ```bash
141
+ vibe exec status --json
142
+ ```
143
+
144
+ ### 데몬 기동(운영)
145
+
146
+ ```bash
147
+ vibe exec --daemon --config .vibe/exec/config.json
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 7) MCP 구현자 규칙 (Wrapper 안전 패턴)
153
+
154
+ MCP 도구는 다음만 한다.
155
+
156
+ 1. `vibe <command>` 호출 (필수)
157
+ 2. run_dir / manifest 읽기
158
+ 3. 해석/요약/다음 액션 제시
159
+
160
+ **금지**
161
+
162
+ * `.vibe/install_manifest.json` 쓰기
163
+ * `.vibe/runs/**` 쓰기
164
+ * 엔진 바이너리 직접 호출
165
+
166
+ ---
167
+
168
+ ## 8) 실패 유형별 즉시 처방 (Playbook)
169
+
170
+ ### 케이스 A) "MCP는 되는데 로컬이 안 돼"
171
+
172
+ **증상**: MCP 도구는 동작하지만 CLI가 안 됨
173
+
174
+ **진단**:
175
+ ```bash
176
+ vibe doctor --json | jq '.engines'
177
+ ```
178
+
179
+ **처방**:
180
+ 1. doctor 결과에서 `BIN_VIBE_MISSING` / `ENGINE_MISSING` 찾기
181
+ 2. `vibe update` 실행
182
+ 3. 여전히 안 되면 권한/플랫폼 mismatch 분기
183
+
184
+ ### 케이스 B) "JSON 파싱/출력 때문에 터짐"
185
+
186
+ **증상**: stdout JSON 파싱 실패
187
+
188
+ **규칙**:
189
+ * stdout JSON을 결과로 쓰지 말고(run_dir SSOT)
190
+ * CLI stdout은 `run_id` 같은 control 데이터만
191
+ * MCP는 run_dir 파일을 읽어라
192
+
193
+ **처방**:
194
+ ```bash
195
+ # 잘못된 방식
196
+ result=$(vibe inspect_code --json) # stdout 파싱 X
197
+
198
+ # 올바른 방식
199
+ vibe inspect_code
200
+ cat runs/<run_id>/result.json # run_dir에서 읽기
201
+ ```
202
+
203
+ ### 케이스 C) "daemon.lock 때문에 꼬임"
204
+
205
+ **증상**: `DAEMON_STALE_LOCK` 발생
206
+
207
+ **처방**:
208
+ ```bash
209
+ vibe exec stop
210
+ rm -f .vibe/exec/daemon.lock # lock 정리
211
+ vibe exec --daemon --config .vibe/exec/config.json
212
+ ```
213
+
214
+ ---
215
+
216
+ ## 9) 스킬 완료 조건 (Done Criteria)
217
+
218
+ 아래를 만족해야 완료로 간주한다.
219
+
220
+ - [ ] `.vibe/install_manifest.json` 존재 + 스키마 통과
221
+ - [ ] `vibe doctor --json` 결과가 ok=true 또는 WARN만
222
+ - [ ] engines/components가 모두 `status=ok` (또는 정책상 허용된 일부만 WARN)
223
+ - [ ] MCP는 "읽기 전용" 규칙을 위반하지 않음
224
+
225
+ ---
226
+
227
+ ## 10) 스킬이 요구하는 파일(SSOT)
228
+
229
+ | 파일 | 필수 | 설명 |
230
+ |------|------|------|
231
+ | `.vibe/install_manifest.json` | ✅ | 설치 상태 SSOT |
232
+ | `schemas/install_manifest.schema.v1.json` | ✅ | manifest 스키마 |
233
+ | `docs/ssot/INSTALL_MANIFEST_AUTHORITY_RULES.v1.md` | 선택 | 권한 규칙 |
234
+ | `docs/ssot/VRIP.md` | 선택 | VRIP 프로토콜 |
235
+
236
+ ---
237
+
238
+ ## 11) 에이전트용 프롬프트 템플릿
239
+
240
+ 사용자가 상황을 설명하면 아래 템플릿으로 진단하라.
241
+
242
+ ### 입력 템플릿
243
+
244
+ ```
245
+ ## 현재 상황
246
+ [사용자가 설명한 문제]
247
+
248
+ ## doctor 결과
249
+ [vibe doctor --json 출력 붙여넣기]
250
+
251
+ ## manifest 상태
252
+ [cat .vibe/install_manifest.json 출력 또는 "없음"]
253
+ ```
254
+
255
+ ### 출력 템플릿
256
+
257
+ ```
258
+ ## Gate 판정
259
+ - **Status**: PASS / WARN / FAIL
260
+ - **코드**: [해당 코드 목록]
261
+
262
+ ## 원인 분석
263
+ [문제의 근본 원인]
264
+
265
+ ## 즉시 실행 커맨드
266
+ ```bash
267
+ [복사 가능한 커맨드]
268
+ ```
269
+
270
+ ## 수정 체크리스트
271
+ - [ ] [필요한 조치 1]
272
+ - [ ] [필요한 조치 2]
273
+ ```
274
+
275
+ ---
276
+
277
+ ## 12) 관련 문서
278
+
279
+ | 문서 | 역할 |
280
+ |------|------|
281
+ | `docs/ssot/VRIP.md` | Vibe Run Invocation Protocol |
282
+ | `docs/ssot/INSTALL_MANIFEST_AUTHORITY_RULES.v1.md` | manifest 권한 규칙 |
283
+ | `docs/DEV_SPEC/system_design_mapping/VIBE_PM_CONTROL_PLANE_SPEC.md` | Control Plane 스펙 |
284
+ | `adapters/mcp-ts/src/tools/vibe_pm/doctor.ts` | doctor MCP 도구 |
285
+
286
+ ---
287
+
288
+ **스킬 끝**
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "skills": [
4
+ {
5
+ "id": "VRIP_INSTALL_MANIFEST_DOCTOR",
6
+ "file": "VRIP_INSTALL_MANIFEST_DOCTOR.skill.md",
7
+ "version": "1.0.0",
8
+ "description": "MCP↔CLI↔Daemon 설치/실행 상태 진단 및 Gate 판정",
9
+ "tags": ["doctor", "manifest", "vrip", "diagnostic"],
10
+ "sha256": "ce45856decad28008792d124bc2d19a6d0db8dc327d2fc982e816954d92b2ea0"
11
+ }
12
+ ],
13
+ "created_at": "2026-01-24T12:00:00.000Z"
14
+ }