@vibecodetown/mcp-server 2.1.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 (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +269 -0
  3. package/build/auth/gate.js +225 -0
  4. package/build/auth/index.js +55 -0
  5. package/build/auth/public_key.js +27 -0
  6. package/build/auth/token_cache.js +122 -0
  7. package/build/auth/token_verifier.js +103 -0
  8. package/build/bootstrap/doctor.js +115 -0
  9. package/build/bootstrap/installer.js +673 -0
  10. package/build/bootstrap/lock.js +37 -0
  11. package/build/bootstrap/platform.js +26 -0
  12. package/build/bootstrap/registry.js +37 -0
  13. package/build/cache/index.js +147 -0
  14. package/build/cli.js +101 -0
  15. package/build/contracts.js +22 -0
  16. package/build/control_plane/gate.js +161 -0
  17. package/build/control_plane/index.js +6 -0
  18. package/build/dx/activity.js +139 -0
  19. package/build/engine.js +106 -0
  20. package/build/errors.js +171 -0
  21. package/build/generated/activate_input.js +2 -0
  22. package/build/generated/activate_output.js +57 -0
  23. package/build/generated/advisory_review_input.js +2 -0
  24. package/build/generated/advisory_review_output.js +35 -0
  25. package/build/generated/auth_token_file.js +2 -0
  26. package/build/generated/briefing_input.js +2 -0
  27. package/build/generated/briefing_output.js +2 -0
  28. package/build/generated/clinic_bridge_file.js +13 -0
  29. package/build/generated/contracts_bundle_info.js +5 -0
  30. package/build/generated/create_work_order_input.js +2 -0
  31. package/build/generated/create_work_order_output.js +2 -0
  32. package/build/generated/current_work_order_file.js +2 -0
  33. package/build/generated/doctor_input.js +2 -0
  34. package/build/generated/doctor_output.js +24 -0
  35. package/build/generated/execution_result.js +2 -0
  36. package/build/generated/execution_task.js +2 -0
  37. package/build/generated/export_output_input.js +2 -0
  38. package/build/generated/export_output_output.js +2 -0
  39. package/build/generated/finalize_work_input.js +2 -0
  40. package/build/generated/finalize_work_output.js +2 -0
  41. package/build/generated/gate_input.js +2 -0
  42. package/build/generated/gate_output.js +2 -0
  43. package/build/generated/gate_result_v1.js +2 -0
  44. package/build/generated/get_decision_input.js +2 -0
  45. package/build/generated/get_decision_output.js +13 -0
  46. package/build/generated/handoff_to_clinic.js +2 -0
  47. package/build/generated/index.js +75 -0
  48. package/build/generated/inspect_code_input.js +2 -0
  49. package/build/generated/inspect_code_output.js +13 -0
  50. package/build/generated/memory_retrieve_output.js +2 -0
  51. package/build/generated/memory_state_file.js +2 -0
  52. package/build/generated/memory_status_input.js +2 -0
  53. package/build/generated/memory_status_output.js +13 -0
  54. package/build/generated/memory_sync_input.js +2 -0
  55. package/build/generated/memory_sync_output.js +13 -0
  56. package/build/generated/plugin_result.js +2 -0
  57. package/build/generated/react_perf_check_patterns_input.js +2 -0
  58. package/build/generated/react_perf_check_patterns_output.js +2 -0
  59. package/build/generated/react_perf_generate_report_input.js +2 -0
  60. package/build/generated/react_perf_generate_report_output.js +2 -0
  61. package/build/generated/repair_plan_input.js +2 -0
  62. package/build/generated/repair_plan_output.js +2 -0
  63. package/build/generated/run_app_input.js +2 -0
  64. package/build/generated/run_app_output.js +2 -0
  65. package/build/generated/run_state_file.js +13 -0
  66. package/build/generated/scaffold_input.js +2 -0
  67. package/build/generated/scaffold_output.js +2 -0
  68. package/build/generated/search_oss_input.js +2 -0
  69. package/build/generated/search_oss_output.js +2 -0
  70. package/build/generated/selection_validation_result.js +2 -0
  71. package/build/generated/signal_agent_input.js +2 -0
  72. package/build/generated/spec_high_ask_queue_items_file.js +2 -0
  73. package/build/generated/spec_high_clinic_bridge_output.js +2 -0
  74. package/build/generated/spec_high_decision_draft_output.js +2 -0
  75. package/build/generated/spec_high_validate_output.js +2 -0
  76. package/build/generated/status_input.js +2 -0
  77. package/build/generated/status_output.js +2 -0
  78. package/build/generated/submit_decision_input.js +2 -0
  79. package/build/generated/submit_decision_output.js +2 -0
  80. package/build/generated/tool_error_output.js +2 -0
  81. package/build/generated/undo_last_task_input.js +2 -0
  82. package/build/generated/undo_last_task_output.js +2 -0
  83. package/build/generated/update_input.js +2 -0
  84. package/build/generated/update_output.js +2 -0
  85. package/build/generated/vibe_pm_inspection_result.js +2 -0
  86. package/build/generated/vibe_pm_report_markdown.js +2 -0
  87. package/build/generated/vibe_pm_verdict.js +2 -0
  88. package/build/generated/vibe_repo_config.js +2 -0
  89. package/build/generated/vibecoding_helper_answer_output.js +2 -0
  90. package/build/generated/vibecoding_helper_one_loop_selection_output.js +2 -0
  91. package/build/generated/vibecoding_helper_show_ask_queue_output.js +2 -0
  92. package/build/generated/work_order_v1.js +2 -0
  93. package/build/generated/zoekt_evidence_input.js +2 -0
  94. package/build/generated/zoekt_evidence_output.js +2 -0
  95. package/build/index.js +111 -0
  96. package/build/legacy_alias.js +65 -0
  97. package/build/local-mode/bash.js +61 -0
  98. package/build/local-mode/config.js +171 -0
  99. package/build/local-mode/git.js +33 -0
  100. package/build/local-mode/init.js +110 -0
  101. package/build/local-mode/paths.js +24 -0
  102. package/build/local-mode/templates.js +856 -0
  103. package/build/local-mode/work-order.js +41 -0
  104. package/build/resources/index.js +246 -0
  105. package/build/security/input-validator.js +119 -0
  106. package/build/security/path-policy.js +289 -0
  107. package/build/security/sandbox.js +228 -0
  108. package/build/tools/react_perf/check_patterns.js +172 -0
  109. package/build/tools/react_perf/generate_report.js +337 -0
  110. package/build/tools/react_perf/index.js +119 -0
  111. package/build/tools/react_perf/rules/advanced.js +325 -0
  112. package/build/tools/react_perf/rules/async.js +104 -0
  113. package/build/tools/react_perf/rules/bundle.js +101 -0
  114. package/build/tools/react_perf/rules/client.js +186 -0
  115. package/build/tools/react_perf/rules/index.js +74 -0
  116. package/build/tools/react_perf/rules/js.js +148 -0
  117. package/build/tools/react_perf/rules/rendering.js +166 -0
  118. package/build/tools/react_perf/rules/rerender.js +161 -0
  119. package/build/tools/react_perf/rules/server.js +141 -0
  120. package/build/tools/react_perf/types.js +127 -0
  121. package/build/tools/vibe_pm/activate.js +102 -0
  122. package/build/tools/vibe_pm/advisory_review.js +77 -0
  123. package/build/tools/vibe_pm/briefing.js +178 -0
  124. package/build/tools/vibe_pm/context.js +439 -0
  125. package/build/tools/vibe_pm/create_work_order.js +271 -0
  126. package/build/tools/vibe_pm/doc_status_gate.js +370 -0
  127. package/build/tools/vibe_pm/doctor.js +262 -0
  128. package/build/tools/vibe_pm/entity_gate/preflight.js +78 -0
  129. package/build/tools/vibe_pm/export_output.js +135 -0
  130. package/build/tools/vibe_pm/finalize_work.js +393 -0
  131. package/build/tools/vibe_pm/gate.js +33 -0
  132. package/build/tools/vibe_pm/get_decision.js +281 -0
  133. package/build/tools/vibe_pm/index.js +593 -0
  134. package/build/tools/vibe_pm/inspect_code.js +828 -0
  135. package/build/tools/vibe_pm/intent/generator.js +294 -0
  136. package/build/tools/vibe_pm/intent/index.js +5 -0
  137. package/build/tools/vibe_pm/intent/prompt_density.js +227 -0
  138. package/build/tools/vibe_pm/intent/types.js +70 -0
  139. package/build/tools/vibe_pm/intent/verifier.js +237 -0
  140. package/build/tools/vibe_pm/kce/doc_usage.js +51 -0
  141. package/build/tools/vibe_pm/kce/on_finalize.js +11 -0
  142. package/build/tools/vibe_pm/kce/preflight.js +232 -0
  143. package/build/tools/vibe_pm/local_memory.js +26 -0
  144. package/build/tools/vibe_pm/memory_status.js +82 -0
  145. package/build/tools/vibe_pm/memory_sync.js +134 -0
  146. package/build/tools/vibe_pm/modules/decision_snapshot.js +29 -0
  147. package/build/tools/vibe_pm/modules/ensure.js +100 -0
  148. package/build/tools/vibe_pm/modules/fingerprint.js +30 -0
  149. package/build/tools/vibe_pm/modules/fix_dependencies.js +394 -0
  150. package/build/tools/vibe_pm/modules/planning_v1.js +110 -0
  151. package/build/tools/vibe_pm/modules/repo_context.js +56 -0
  152. package/build/tools/vibe_pm/modules/research_v1.js +114 -0
  153. package/build/tools/vibe_pm/modules/skills_v1.js +100 -0
  154. package/build/tools/vibe_pm/pm_language.js +222 -0
  155. package/build/tools/vibe_pm/repair_plan.js +199 -0
  156. package/build/tools/vibe_pm/run_app.js +597 -0
  157. package/build/tools/vibe_pm/run_app_podman.js +64 -0
  158. package/build/tools/vibe_pm/scaffold.js +550 -0
  159. package/build/tools/vibe_pm/search_oss.js +124 -0
  160. package/build/tools/vibe_pm/status.js +153 -0
  161. package/build/tools/vibe_pm/submit_decision.js +87 -0
  162. package/build/tools/vibe_pm/system_design/issue_mapping.js +47 -0
  163. package/build/tools/vibe_pm/system_design/rulebook.js +112 -0
  164. package/build/tools/vibe_pm/system_design/semgrep.js +132 -0
  165. package/build/tools/vibe_pm/types.js +229 -0
  166. package/build/tools/vibe_pm/undo_last_task.js +163 -0
  167. package/build/tools/vibe_pm/update.js +146 -0
  168. package/build/tools/vibe_pm/zoekt_evidence.js +96 -0
  169. package/build/tools.js +269 -0
  170. package/build/version-check.js +239 -0
  171. package/build/vibe-cli.js +631 -0
  172. package/package.json +76 -0
@@ -0,0 +1,229 @@
1
+ // adapters/mcp-ts/src/tools/vibe_pm/types.ts
2
+ // Type definitions for vibe_pm.* MCP tools
3
+ // Reference: docs/DEV_SPEC/MCP_TOOL_SCHEMA_SPEC.md
4
+ import { z } from "zod";
5
+ // ============================================================
6
+ // vibe_pm.briefing
7
+ // ============================================================
8
+ // Input schema is generated from JSON Schema SSOT.
9
+ export const briefingInputSchema = BriefingInputSchema;
10
+ // Output schema is generated from JSON Schema SSOT.
11
+ export const briefingOutputSchema = BriefingOutputSchema;
12
+ // ============================================================
13
+ // vibe_pm.get_decision
14
+ // ============================================================
15
+ // Input schema is generated from JSON Schema SSOT.
16
+ export const getDecisionInputSchema = GetDecisionInputSchema;
17
+ const choiceSchema = z.object({
18
+ key: z.enum(["A", "B", "C", "U"]).describe("선택 키"),
19
+ label: z.string().describe("선택지 레이블"),
20
+ description: z.string().optional().describe("선택지 설명")
21
+ });
22
+ const decisionRequestSchema = z.object({
23
+ decision_id: z.string().describe("결재 ID (내부용)"),
24
+ title: z.string().describe("비즈니스 언어 제목"),
25
+ context: z.string().describe("컨텍스트 설명 (기술 용어 없음)"),
26
+ choices: z.array(choiceSchema).describe("선택 가능한 옵션들")
27
+ });
28
+ // Output schema is generated from JSON Schema SSOT.
29
+ export const getDecisionOutputSchema = GetDecisionOutputSchema;
30
+ // ============================================================
31
+ // vibe_pm.memory_status
32
+ // ============================================================
33
+ // Input schema is generated from JSON Schema SSOT.
34
+ export const memoryStatusInputSchema = MemoryStatusInputSchema;
35
+ // Output schema is generated from JSON Schema SSOT.
36
+ export const memoryStatusOutputSchema = MemoryStatusOutputSchema;
37
+ // ============================================================
38
+ // vibe_pm.memory_sync
39
+ // ============================================================
40
+ // Input schema is generated from JSON Schema SSOT.
41
+ export const memorySyncInputSchema = MemorySyncInputSchema;
42
+ // Output schema is generated from JSON Schema SSOT.
43
+ export const memorySyncOutputSchema = MemorySyncOutputSchema;
44
+ // ============================================================
45
+ // vibe_pm.advisory_review
46
+ // ============================================================
47
+ // Input schema is generated from JSON Schema SSOT.
48
+ export const advisoryReviewInputSchema = AdvisoryReviewInputSchema;
49
+ // Output schema is generated from JSON Schema SSOT.
50
+ export const advisoryReviewOutputSchema = AdvisoryReviewOutputSchema;
51
+ // ============================================================
52
+ // vibe_pm.activate
53
+ // ============================================================
54
+ // Input schema is generated from JSON Schema SSOT.
55
+ export const activateInputSchema = ActivateInputSchema;
56
+ // Output schema is generated from JSON Schema SSOT.
57
+ export const activateOutputSchema = ActivateOutputSchema;
58
+ // ============================================================
59
+ // vibe_pm.submit_decision
60
+ // ============================================================
61
+ // Input schema is generated from JSON Schema SSOT.
62
+ export const submitDecisionInputSchema = SubmitDecisionInputSchema;
63
+ // Output schema is generated from JSON Schema SSOT.
64
+ export const submitDecisionOutputSchema = SubmitDecisionOutputSchema;
65
+ // ============================================================
66
+ // vibe_pm.create_work_order
67
+ // ============================================================
68
+ // Input schema is generated from JSON Schema SSOT.
69
+ export const createWorkOrderInputSchema = CreateWorkOrderInputSchema;
70
+ const workOrderSchema = z.object({
71
+ headline: z.string().describe("현재 작업 목표 (단일 항목)"),
72
+ scope: z.object({
73
+ include: z.array(z.string()).describe("포함 범위"),
74
+ exclude: z.array(z.string()).describe("제외 범위")
75
+ }).describe("작업 범위 정의"),
76
+ do_not_touch: z.array(z.string()).describe("건드리지 말아야 할 항목"),
77
+ verify_criteria: z.array(z.string()).describe("검증 기준"),
78
+ paste_to_agent: z.string().describe("AI 에이전트에 붙여넣을 텍스트")
79
+ });
80
+ // Output schema is generated from JSON Schema SSOT.
81
+ export const createWorkOrderOutputSchema = CreateWorkOrderOutputSchema;
82
+ // ============================================================
83
+ // vibe_pm.inspect_code
84
+ // ============================================================
85
+ // Input schema is generated from JSON Schema SSOT.
86
+ export const inspectCodeInputSchema = InspectCodeInputSchema;
87
+ // Output schema is generated from JSON Schema SSOT.
88
+ export const inspectCodeOutputSchema = InspectCodeOutputSchema;
89
+ /**
90
+ * P11: Validate inspect_code output against schema contract
91
+ * @throws ZodError if validation fails
92
+ */
93
+ export function validateInspectCodeOutput(output) {
94
+ return inspectCodeOutputSchema.parse(output);
95
+ }
96
+ /**
97
+ * P14: Select message template ID based on review result and issues
98
+ * Reference: docs/specs/PM_USER_MESSAGES_SSOT_v1.0.md
99
+ *
100
+ * Selection rules:
101
+ * - GO → GO-01 (기본) or GO-02 (다음 작업 연결 시)
102
+ * - FIX + VERIFY_FAIL → FIX-02
103
+ * - FIX (other) → FIX-01
104
+ * - BLOCK + RULE_VIOLATION|RISK_SPIKE → BLOCK-01
105
+ * - BLOCK + SCOPE_MISMATCH → BLOCK-02
106
+ */
107
+ export function selectMessageTemplate(reviewResult, issues, hasNextWorkOrder = false) {
108
+ const issueTypes = new Set(issues.map(i => i.type));
109
+ switch (reviewResult) {
110
+ case "GO":
111
+ return hasNextWorkOrder ? "GO-02" : "GO-01";
112
+ case "FIX":
113
+ return issueTypes.has("VERIFY_FAIL") ? "FIX-02" : "FIX-01";
114
+ case "BLOCK":
115
+ if (issueTypes.has("RULE_VIOLATION") || issueTypes.has("RISK_SPIKE")) {
116
+ return "BLOCK-01";
117
+ }
118
+ return "BLOCK-02"; // SCOPE_MISMATCH or default
119
+ default:
120
+ return "GO-01";
121
+ }
122
+ }
123
+ // ============================================================
124
+ // vibe_pm.status
125
+ // ============================================================
126
+ // Input schema is generated from JSON Schema SSOT.
127
+ export const statusInputSchema = StatusInputSchema;
128
+ // Output schema is generated from JSON Schema SSOT.
129
+ export const statusOutputSchema = StatusOutputSchema;
130
+ // ============================================================
131
+ // vibe_pm.repair_plan
132
+ // ============================================================
133
+ // Input schema is generated from JSON Schema SSOT.
134
+ export const repairPlanInputSchema = RepairPlanInputSchema;
135
+ // Output schema is generated from JSON Schema SSOT.
136
+ export const repairPlanOutputSchema = RepairPlanOutputSchema;
137
+ // ============================================================
138
+ // vibe_pm.scaffold (Vibe-SDS - Standard Directory Structure)
139
+ // ============================================================
140
+ // Input schema is generated from JSON Schema SSOT.
141
+ export const scaffoldInputSchema = ScaffoldInputSchema;
142
+ // Output schema is generated from JSON Schema SSOT.
143
+ export const scaffoldOutputSchema = ScaffoldOutputSchema;
144
+ // ============================================================
145
+ // vibe_pm.finalize_work
146
+ // ============================================================
147
+ // Imported from generated SSOT
148
+ import { BriefingInputSchema } from "../../generated/briefing_input.js";
149
+ import { CreateWorkOrderOutputSchema } from "../../generated/create_work_order_output.js";
150
+ import { BriefingOutputSchema } from "../../generated/briefing_output.js";
151
+ import { DoctorOutputSchema } from "../../generated/doctor_output.js";
152
+ import { FinalizeWorkInputSchema } from "../../generated/finalize_work_input.js";
153
+ import { FinalizeWorkOutputSchema } from "../../generated/finalize_work_output.js";
154
+ import { GetDecisionInputSchema } from "../../generated/get_decision_input.js";
155
+ import { GetDecisionOutputSchema } from "../../generated/get_decision_output.js";
156
+ import { CreateWorkOrderInputSchema } from "../../generated/create_work_order_input.js";
157
+ import { InspectCodeInputSchema } from "../../generated/inspect_code_input.js";
158
+ import { InspectCodeOutputSchema } from "../../generated/inspect_code_output.js";
159
+ import { RepairPlanInputSchema } from "../../generated/repair_plan_input.js";
160
+ import { RepairPlanOutputSchema } from "../../generated/repair_plan_output.js";
161
+ import { RunAppInputSchema } from "../../generated/run_app_input.js";
162
+ import { RunAppOutputSchema } from "../../generated/run_app_output.js";
163
+ import { ScaffoldInputSchema } from "../../generated/scaffold_input.js";
164
+ import { ScaffoldOutputSchema } from "../../generated/scaffold_output.js";
165
+ import { StatusInputSchema } from "../../generated/status_input.js";
166
+ import { StatusOutputSchema } from "../../generated/status_output.js";
167
+ import { SubmitDecisionInputSchema } from "../../generated/submit_decision_input.js";
168
+ import { SubmitDecisionOutputSchema } from "../../generated/submit_decision_output.js";
169
+ import { UndoLastTaskInputSchema } from "../../generated/undo_last_task_input.js";
170
+ import { UndoLastTaskOutputSchema } from "../../generated/undo_last_task_output.js";
171
+ import { UpdateOutputSchema } from "../../generated/update_output.js";
172
+ import { MemoryStatusInputSchema } from "../../generated/memory_status_input.js";
173
+ import { MemoryStatusOutputSchema } from "../../generated/memory_status_output.js";
174
+ import { MemorySyncInputSchema } from "../../generated/memory_sync_input.js";
175
+ import { MemorySyncOutputSchema } from "../../generated/memory_sync_output.js";
176
+ import { AdvisoryReviewInputSchema } from "../../generated/advisory_review_input.js";
177
+ import { AdvisoryReviewOutputSchema } from "../../generated/advisory_review_output.js";
178
+ import { ActivateInputSchema } from "../../generated/activate_input.js";
179
+ import { ActivateOutputSchema } from "../../generated/activate_output.js";
180
+ import { ExportOutputInputSchema } from "../../generated/export_output_input.js";
181
+ import { ExportOutputOutputSchema } from "../../generated/export_output_output.js";
182
+ import { SearchOssInputSchema } from "../../generated/search_oss_input.js";
183
+ import { SearchOssOutputSchema } from "../../generated/search_oss_output.js";
184
+ import { ZoektEvidenceInputSchema } from "../../generated/zoekt_evidence_input.js";
185
+ import { ZoektEvidenceOutputSchema } from "../../generated/zoekt_evidence_output.js";
186
+ export const finalizeWorkInputSchema = FinalizeWorkInputSchema;
187
+ // Output schema is generated from JSON Schema SSOT.
188
+ export const finalizeWorkOutputSchema = FinalizeWorkOutputSchema;
189
+ // ============================================================
190
+ // vibe_pm.undo_last_task
191
+ // ============================================================
192
+ // Input schema is generated from JSON Schema SSOT.
193
+ export const undoLastTaskInputSchema = UndoLastTaskInputSchema;
194
+ // Output schema is generated from JSON Schema SSOT.
195
+ export const undoLastTaskOutputSchema = UndoLastTaskOutputSchema;
196
+ // ============================================================
197
+ // vibe_pm.run_app
198
+ // ============================================================
199
+ // Input schema is generated from JSON Schema SSOT.
200
+ export const runAppInputSchema = RunAppInputSchema;
201
+ // Output schema is generated from JSON Schema SSOT.
202
+ export const runAppOutputSchema = RunAppOutputSchema;
203
+ // ============================================================
204
+ // vibe_pm.export_output
205
+ // ============================================================
206
+ // Input schema is generated from JSON Schema SSOT.
207
+ export const exportOutputInputSchema = ExportOutputInputSchema;
208
+ // Output schema is generated from JSON Schema SSOT.
209
+ export const exportOutputOutputSchema = ExportOutputOutputSchema;
210
+ // ============================================================
211
+ // vibe_pm.search_oss
212
+ // ============================================================
213
+ // Input schema is generated from JSON Schema SSOT.
214
+ export const searchOssInputSchema = SearchOssInputSchema;
215
+ // Output schema is generated from JSON Schema SSOT.
216
+ export const searchOssOutputSchema = SearchOssOutputSchema;
217
+ // ============================================================
218
+ // vibe_pm.zoekt_evidence
219
+ // ============================================================
220
+ // Input schema is generated from JSON Schema SSOT.
221
+ export const zoektEvidenceInputSchema = ZoektEvidenceInputSchema;
222
+ // Output schema is generated from JSON Schema SSOT.
223
+ export const zoektEvidenceOutputSchema = ZoektEvidenceOutputSchema;
224
+ // ============================================================
225
+ // vibe_pm.doctor / vibe_pm.update (Output SSOT only)
226
+ // ============================================================
227
+ export const doctorOutputSchema = DoctorOutputSchema;
228
+ export const updateOutputSchema = UpdateOutputSchema;
229
+ // All output schemas are exported in-place above
@@ -0,0 +1,163 @@
1
+ // adapters/mcp-ts/src/tools/vibe_pm/undo_last_task.ts
2
+ // vibe_pm.undo_last_task - Time machine rollback via git revert
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+ import { exec } from "node:child_process";
6
+ import { promisify } from "node:util";
7
+ const execAsync = promisify(exec);
8
+ /**
9
+ * vibe_pm.undo_last_task - Rollback recent commits via git revert
10
+ *
11
+ * Steps:
12
+ * 1. git log --oneline -n {steps} to get recent commits
13
+ * 2. For each commit, git revert --no-edit
14
+ * 3. Add [ROLLBACK] entry to DEV_LOG
15
+ * 4. Return result
16
+ */
17
+ export async function undoLastTask(input) {
18
+ const basePath = process.cwd();
19
+ const steps = input.steps ?? 1;
20
+ const reason = input.reason ?? "사용자 요청으로 롤백";
21
+ // Step 1: Get recent commits
22
+ let commits;
23
+ try {
24
+ commits = await getRecentCommits(basePath, steps);
25
+ }
26
+ catch (err) {
27
+ return {
28
+ success: false,
29
+ reverted_tasks: [],
30
+ current_commit: "unknown",
31
+ message: `Git 로그를 가져올 수 없습니다: ${err instanceof Error ? err.message : String(err)}`
32
+ };
33
+ }
34
+ if (commits.length === 0) {
35
+ return {
36
+ success: false,
37
+ reverted_tasks: [],
38
+ current_commit: await getCurrentCommit(basePath),
39
+ message: "되돌릴 커밋이 없습니다"
40
+ };
41
+ }
42
+ // Step 2: Revert each commit
43
+ const revertedTasks = [];
44
+ const revertErrors = [];
45
+ for (const commit of commits) {
46
+ try {
47
+ await execAsync(`git revert --no-edit ${commit.hash}`, { cwd: basePath });
48
+ revertedTasks.push({
49
+ commit_hash: commit.shortHash,
50
+ task_summary: commit.subject,
51
+ timestamp: commit.timestamp
52
+ });
53
+ }
54
+ catch (err) {
55
+ const errMsg = err instanceof Error ? err.message : String(err);
56
+ revertErrors.push(`${commit.shortHash}: ${errMsg}`);
57
+ // If revert fails due to conflicts, abort and stop
58
+ if (errMsg.includes("conflict") || errMsg.includes("CONFLICT")) {
59
+ try {
60
+ await execAsync("git revert --abort", { cwd: basePath });
61
+ }
62
+ catch {
63
+ // Ignore abort errors
64
+ }
65
+ break;
66
+ }
67
+ }
68
+ }
69
+ // Step 3: Add DEV_LOG entry
70
+ if (revertedTasks.length > 0) {
71
+ try {
72
+ await addRollbackLog(basePath, revertedTasks, reason);
73
+ }
74
+ catch {
75
+ // Logging is optional
76
+ }
77
+ }
78
+ // Step 4: Get current commit
79
+ const currentCommit = await getCurrentCommit(basePath);
80
+ // Determine result message
81
+ let message;
82
+ if (revertedTasks.length === steps) {
83
+ message = `${revertedTasks.length}개 작업을 성공적으로 롤백했습니다`;
84
+ }
85
+ else if (revertedTasks.length > 0) {
86
+ message = `${revertedTasks.length}/${steps}개 작업을 롤백했습니다. 일부 실패: ${revertErrors.join("; ")}`;
87
+ }
88
+ else {
89
+ message = `롤백 실패: ${revertErrors.join("; ")}`;
90
+ }
91
+ return {
92
+ success: revertedTasks.length > 0,
93
+ reverted_tasks: revertedTasks,
94
+ current_commit: currentCommit,
95
+ message
96
+ };
97
+ }
98
+ /**
99
+ * Get recent commits from git log
100
+ */
101
+ async function getRecentCommits(basePath, count) {
102
+ const { stdout } = await execAsync(`git log --oneline -n ${count} --format="%H|%h|%s|%ci"`, { cwd: basePath });
103
+ const commits = [];
104
+ const lines = stdout.trim().split("\n").filter(Boolean);
105
+ for (const line of lines) {
106
+ const [hash, shortHash, subject, timestamp] = line.split("|");
107
+ if (hash && shortHash && subject) {
108
+ commits.push({
109
+ hash,
110
+ shortHash,
111
+ subject,
112
+ timestamp: timestamp ?? new Date().toISOString()
113
+ });
114
+ }
115
+ }
116
+ return commits;
117
+ }
118
+ /**
119
+ * Get current HEAD commit hash
120
+ */
121
+ async function getCurrentCommit(basePath) {
122
+ try {
123
+ const { stdout } = await execAsync("git rev-parse --short HEAD", { cwd: basePath });
124
+ return stdout.trim();
125
+ }
126
+ catch {
127
+ return "unknown";
128
+ }
129
+ }
130
+ /**
131
+ * Add rollback entry to DEV_LOG
132
+ */
133
+ async function addRollbackLog(basePath, revertedTasks, reason) {
134
+ const today = new Date();
135
+ const dateStr = today.toISOString().split("T")[0];
136
+ const time = today.toISOString().split("T")[1]?.slice(0, 5) ?? "";
137
+ const devLogDir = path.join(basePath, "docs", "dev_logs");
138
+ const devLogPath = path.join(devLogDir, `${dateStr}.md`);
139
+ // Ensure directory exists
140
+ if (!fs.existsSync(devLogDir)) {
141
+ fs.mkdirSync(devLogDir, { recursive: true });
142
+ }
143
+ // Create rollback entry
144
+ const taskList = revertedTasks
145
+ .map((t) => `- \`${t.commit_hash}\`: ${t.task_summary}`)
146
+ .join("\n");
147
+ const entry = `## ${time} - [ROLLBACK] 작업 취소
148
+
149
+ **이유:** ${reason}
150
+
151
+ **취소된 작업:**
152
+ ${taskList}
153
+
154
+ ---
155
+ `;
156
+ if (fs.existsSync(devLogPath)) {
157
+ fs.appendFileSync(devLogPath, `\n${entry}`);
158
+ }
159
+ else {
160
+ const header = `# DEV LOG - ${dateStr}\n\n`;
161
+ fs.writeFileSync(devLogPath, header + entry);
162
+ }
163
+ }
@@ -0,0 +1,146 @@
1
+ // adapters/mcp-ts/src/tools/vibe_pm/update.ts
2
+ // vibe_pm.update - Manual engine update
3
+ import { UpdateInputSchema } from "../../generated/update_input.js";
4
+ import { ensureEngines, checkUpdates, clearCache, getEngineHealth } from "../../bootstrap/installer.js";
5
+ import { ENGINE_SPECS } from "../../bootstrap/registry.js";
6
+ // ============================================================
7
+ // Input/Output Types
8
+ // ============================================================
9
+ export { UpdateInputSchema };
10
+ // ============================================================
11
+ // Update Implementation
12
+ // ============================================================
13
+ /**
14
+ * vibe_pm.update - Manual engine update
15
+ *
16
+ * PM-friendly description:
17
+ * 엔진 바이너리를 최신 버전으로 업데이트합니다.
18
+ */
19
+ export async function update(input) {
20
+ const force = input.force ?? false;
21
+ const targetEngines = input.engines ?? Object.keys(ENGINE_SPECS);
22
+ const results = [];
23
+ try {
24
+ // Step 1: Check what needs updating
25
+ const updateStatus = await checkUpdates();
26
+ // Step 2: Filter engines to update
27
+ const enginesToUpdate = [];
28
+ for (const name of targetEngines) {
29
+ if (!(name in ENGINE_SPECS)) {
30
+ results.push({
31
+ name,
32
+ action: "failed",
33
+ from_version: null,
34
+ to_version: "unknown",
35
+ message: `알 수 없는 엔진: ${name}`
36
+ });
37
+ continue;
38
+ }
39
+ const engineName = name;
40
+ const status = updateStatus[engineName];
41
+ if (force || status.needsUpdate) {
42
+ enginesToUpdate.push(engineName);
43
+ }
44
+ else {
45
+ results.push({
46
+ name: engineName,
47
+ action: "skipped",
48
+ from_version: status.current,
49
+ to_version: status.required,
50
+ message: "이미 최신 버전입니다"
51
+ });
52
+ }
53
+ }
54
+ // Step 3: Clear cache if force mode
55
+ if (force) {
56
+ for (const name of enginesToUpdate) {
57
+ await clearCache(name);
58
+ }
59
+ }
60
+ // Step 4: Update engines
61
+ if (enginesToUpdate.length > 0) {
62
+ // Run ensureEngines which will update anything that needs updating
63
+ await ensureEngines();
64
+ // Check results
65
+ const newHealth = await getEngineHealth();
66
+ for (const name of enginesToUpdate) {
67
+ const health = newHealth.find((h) => h.name === name);
68
+ const oldStatus = updateStatus[name];
69
+ if (health?.status === "ok") {
70
+ results.push({
71
+ name,
72
+ action: "updated",
73
+ from_version: oldStatus.current,
74
+ to_version: health.version,
75
+ message: force ? "강제 재설치 완료" : "업데이트 완료"
76
+ });
77
+ }
78
+ else {
79
+ results.push({
80
+ name,
81
+ action: "failed",
82
+ from_version: oldStatus.current,
83
+ to_version: oldStatus.required,
84
+ message: `업데이트 실패: ${health?.status ?? "unknown"}`
85
+ });
86
+ }
87
+ }
88
+ }
89
+ // Step 5: Generate summary
90
+ const updated = results.filter((r) => r.action === "updated").length;
91
+ const skipped = results.filter((r) => r.action === "skipped").length;
92
+ const failed = results.filter((r) => r.action === "failed").length;
93
+ let status;
94
+ let summary;
95
+ let nextAction;
96
+ if (failed > 0 && updated === 0) {
97
+ status = "ERROR";
98
+ summary = `업데이트 실패: ${failed}개 엔진`;
99
+ nextAction = {
100
+ type: "RETRY",
101
+ message: "force: true 옵션으로 다시 시도하거나, 네트워크 연결을 확인하세요."
102
+ };
103
+ }
104
+ else if (failed > 0) {
105
+ status = "PARTIAL";
106
+ summary = `부분 성공: ${updated}개 업데이트, ${failed}개 실패`;
107
+ nextAction = {
108
+ type: "RETRY",
109
+ message: "실패한 엔진은 force: true 옵션으로 다시 시도하세요."
110
+ };
111
+ }
112
+ else if (updated > 0) {
113
+ status = "OK";
114
+ summary = `${updated}개 엔진 업데이트 완료`;
115
+ nextAction = {
116
+ type: "NONE",
117
+ message: "모든 엔진이 최신 버전입니다."
118
+ };
119
+ }
120
+ else {
121
+ status = "OK";
122
+ summary = "모든 엔진이 이미 최신 버전입니다";
123
+ nextAction = {
124
+ type: "NONE",
125
+ message: "업데이트할 항목이 없습니다."
126
+ };
127
+ }
128
+ return {
129
+ status,
130
+ summary,
131
+ results,
132
+ next_action: nextAction
133
+ };
134
+ }
135
+ catch (e) {
136
+ return {
137
+ status: "ERROR",
138
+ summary: e instanceof Error ? e.message : "알 수 없는 오류",
139
+ results,
140
+ next_action: {
141
+ type: "CONTACT_SUPPORT",
142
+ message: "업데이트 중 오류가 발생했습니다. 네트워크 연결을 확인하고 다시 시도하세요."
143
+ }
144
+ };
145
+ }
146
+ }
@@ -0,0 +1,96 @@
1
+ // adapters/mcp-ts/src/tools/vibe_pm/zoekt_evidence.ts
2
+ // vibe_pm.zoekt_evidence - Collect pattern evidence across local roots (zoekt/rg/python_scan)
3
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
4
+ import { runEngine } from "../../engine.js";
5
+ import { safeJsonParse } from "../../cli.js";
6
+ import { validateToolInput } from "../../security/input-validator.js";
7
+ import { resolveProjectId, resolveRunId } from "./context.js";
8
+ function toCsv(values) {
9
+ return values
10
+ .map((v) => (typeof v === "string" ? v.trim() : ""))
11
+ .filter(Boolean)
12
+ .join(",");
13
+ }
14
+ function toInt(v) {
15
+ if (typeof v === "number" && Number.isFinite(v))
16
+ return Math.trunc(v);
17
+ if (typeof v === "string") {
18
+ const n = Number(v);
19
+ if (Number.isFinite(n))
20
+ return Math.trunc(n);
21
+ }
22
+ return undefined;
23
+ }
24
+ export async function zoektEvidence(input) {
25
+ const basePath = process.cwd();
26
+ validateToolInput({ project_id: input.project_id, run_id: input.run_id });
27
+ const resolvedRun = resolveRunId(input.run_id ?? input.project_id, basePath);
28
+ const run_id = resolvedRun.run_id;
29
+ const project_id = resolveProjectId(run_id, basePath);
30
+ const roots = Array.isArray(input.roots) ? input.roots.map((r) => String(r).trim()).filter(Boolean) : [];
31
+ const queries = Array.isArray(input.queries) ? input.queries.map((q) => String(q).trim()).filter(Boolean) : [];
32
+ if (roots.length === 0)
33
+ throw new McpError(ErrorCode.InvalidParams, "[VALIDATION] roots is required");
34
+ if (queries.length === 0)
35
+ throw new McpError(ErrorCode.InvalidParams, "[VALIDATION] queries is required");
36
+ const cmd = ["zoekt-evidence", run_id, "--roots", toCsv(roots), "--queries", toCsv(queries)];
37
+ const samplePaths = toInt(input?.sample_paths);
38
+ if (samplePaths !== undefined)
39
+ cmd.push("--sample-paths", String(samplePaths));
40
+ const maxFileBytes = toInt(input?.max_file_bytes);
41
+ if (maxFileBytes !== undefined)
42
+ cmd.push("--max-file-bytes", String(maxFileBytes));
43
+ const writeEvidence = input?.write_evidence !== false;
44
+ if (!writeEvidence)
45
+ cmd.push("--no-write-evidence");
46
+ const res = await runEngine("vibecoding-helper", cmd, { timeoutMs: 300_000 });
47
+ if (res.code !== 0) {
48
+ throw new Error(`zoekt-evidence failed: ${res.stderr || res.stdout || `exit_code=${res.code}`}`);
49
+ }
50
+ const parsed = safeJsonParse(res.stdout);
51
+ if (!parsed.ok) {
52
+ throw new Error(`zoekt-evidence invalid_json: ${parsed.error}`);
53
+ }
54
+ const doc = parsed.value;
55
+ const engineRaw = typeof doc?.engine === "string" ? doc.engine : "";
56
+ const engine = engineRaw === "zoekt" || engineRaw === "rg" || engineRaw === "python_scan" ? engineRaw : "python_scan";
57
+ const warnings = [];
58
+ if (Array.isArray(doc?.warnings)) {
59
+ for (const w of doc.warnings) {
60
+ if (typeof w === "string" && w.trim())
61
+ warnings.push(w.trim());
62
+ }
63
+ }
64
+ const queriesOut = [];
65
+ const rawQueries = Array.isArray(doc?.queries) ? doc.queries : [];
66
+ for (const q of rawQueries) {
67
+ const obj = q;
68
+ const qq = typeof obj?.q === "string" ? obj.q.trim() : "";
69
+ if (!qq)
70
+ continue;
71
+ queriesOut.push({
72
+ q: qq,
73
+ repos_scanned: typeof obj?.repos_scanned === "number" ? obj.repos_scanned : 0,
74
+ match_count: typeof obj?.match_count === "number" ? obj.match_count : 0,
75
+ sample_paths: Array.isArray(obj?.sample_paths)
76
+ ? obj.sample_paths.map((x) => String(x)).filter(Boolean)
77
+ : []
78
+ });
79
+ }
80
+ const evidencePath = typeof doc?.evidence_path === "string" && doc.evidence_path.trim() ? String(doc.evidence_path).trim() : undefined;
81
+ const out = {
82
+ success: true,
83
+ project_id,
84
+ run_id,
85
+ engine,
86
+ queries: queriesOut,
87
+ warnings,
88
+ next_action: {
89
+ tool: "vibe_pm.export_output",
90
+ reason: "Use this evidence to validate patterns/OSS choices, then export."
91
+ }
92
+ };
93
+ if (evidencePath)
94
+ out.evidence_path = evidencePath;
95
+ return out;
96
+ }