@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.
- package/LICENSE +21 -0
- package/README.md +269 -0
- package/build/auth/gate.js +225 -0
- package/build/auth/index.js +55 -0
- package/build/auth/public_key.js +27 -0
- package/build/auth/token_cache.js +122 -0
- package/build/auth/token_verifier.js +103 -0
- package/build/bootstrap/doctor.js +115 -0
- package/build/bootstrap/installer.js +673 -0
- package/build/bootstrap/lock.js +37 -0
- package/build/bootstrap/platform.js +26 -0
- package/build/bootstrap/registry.js +37 -0
- package/build/cache/index.js +147 -0
- package/build/cli.js +101 -0
- package/build/contracts.js +22 -0
- package/build/control_plane/gate.js +161 -0
- package/build/control_plane/index.js +6 -0
- package/build/dx/activity.js +139 -0
- package/build/engine.js +106 -0
- package/build/errors.js +171 -0
- package/build/generated/activate_input.js +2 -0
- package/build/generated/activate_output.js +57 -0
- package/build/generated/advisory_review_input.js +2 -0
- package/build/generated/advisory_review_output.js +35 -0
- package/build/generated/auth_token_file.js +2 -0
- package/build/generated/briefing_input.js +2 -0
- package/build/generated/briefing_output.js +2 -0
- package/build/generated/clinic_bridge_file.js +13 -0
- package/build/generated/contracts_bundle_info.js +5 -0
- package/build/generated/create_work_order_input.js +2 -0
- package/build/generated/create_work_order_output.js +2 -0
- package/build/generated/current_work_order_file.js +2 -0
- package/build/generated/doctor_input.js +2 -0
- package/build/generated/doctor_output.js +24 -0
- package/build/generated/execution_result.js +2 -0
- package/build/generated/execution_task.js +2 -0
- package/build/generated/export_output_input.js +2 -0
- package/build/generated/export_output_output.js +2 -0
- package/build/generated/finalize_work_input.js +2 -0
- package/build/generated/finalize_work_output.js +2 -0
- package/build/generated/gate_input.js +2 -0
- package/build/generated/gate_output.js +2 -0
- package/build/generated/gate_result_v1.js +2 -0
- package/build/generated/get_decision_input.js +2 -0
- package/build/generated/get_decision_output.js +13 -0
- package/build/generated/handoff_to_clinic.js +2 -0
- package/build/generated/index.js +75 -0
- package/build/generated/inspect_code_input.js +2 -0
- package/build/generated/inspect_code_output.js +13 -0
- package/build/generated/memory_retrieve_output.js +2 -0
- package/build/generated/memory_state_file.js +2 -0
- package/build/generated/memory_status_input.js +2 -0
- package/build/generated/memory_status_output.js +13 -0
- package/build/generated/memory_sync_input.js +2 -0
- package/build/generated/memory_sync_output.js +13 -0
- package/build/generated/plugin_result.js +2 -0
- package/build/generated/react_perf_check_patterns_input.js +2 -0
- package/build/generated/react_perf_check_patterns_output.js +2 -0
- package/build/generated/react_perf_generate_report_input.js +2 -0
- package/build/generated/react_perf_generate_report_output.js +2 -0
- package/build/generated/repair_plan_input.js +2 -0
- package/build/generated/repair_plan_output.js +2 -0
- package/build/generated/run_app_input.js +2 -0
- package/build/generated/run_app_output.js +2 -0
- package/build/generated/run_state_file.js +13 -0
- package/build/generated/scaffold_input.js +2 -0
- package/build/generated/scaffold_output.js +2 -0
- package/build/generated/search_oss_input.js +2 -0
- package/build/generated/search_oss_output.js +2 -0
- package/build/generated/selection_validation_result.js +2 -0
- package/build/generated/signal_agent_input.js +2 -0
- package/build/generated/spec_high_ask_queue_items_file.js +2 -0
- package/build/generated/spec_high_clinic_bridge_output.js +2 -0
- package/build/generated/spec_high_decision_draft_output.js +2 -0
- package/build/generated/spec_high_validate_output.js +2 -0
- package/build/generated/status_input.js +2 -0
- package/build/generated/status_output.js +2 -0
- package/build/generated/submit_decision_input.js +2 -0
- package/build/generated/submit_decision_output.js +2 -0
- package/build/generated/tool_error_output.js +2 -0
- package/build/generated/undo_last_task_input.js +2 -0
- package/build/generated/undo_last_task_output.js +2 -0
- package/build/generated/update_input.js +2 -0
- package/build/generated/update_output.js +2 -0
- package/build/generated/vibe_pm_inspection_result.js +2 -0
- package/build/generated/vibe_pm_report_markdown.js +2 -0
- package/build/generated/vibe_pm_verdict.js +2 -0
- package/build/generated/vibe_repo_config.js +2 -0
- package/build/generated/vibecoding_helper_answer_output.js +2 -0
- package/build/generated/vibecoding_helper_one_loop_selection_output.js +2 -0
- package/build/generated/vibecoding_helper_show_ask_queue_output.js +2 -0
- package/build/generated/work_order_v1.js +2 -0
- package/build/generated/zoekt_evidence_input.js +2 -0
- package/build/generated/zoekt_evidence_output.js +2 -0
- package/build/index.js +111 -0
- package/build/legacy_alias.js +65 -0
- package/build/local-mode/bash.js +61 -0
- package/build/local-mode/config.js +171 -0
- package/build/local-mode/git.js +33 -0
- package/build/local-mode/init.js +110 -0
- package/build/local-mode/paths.js +24 -0
- package/build/local-mode/templates.js +856 -0
- package/build/local-mode/work-order.js +41 -0
- package/build/resources/index.js +246 -0
- package/build/security/input-validator.js +119 -0
- package/build/security/path-policy.js +289 -0
- package/build/security/sandbox.js +228 -0
- package/build/tools/react_perf/check_patterns.js +172 -0
- package/build/tools/react_perf/generate_report.js +337 -0
- package/build/tools/react_perf/index.js +119 -0
- package/build/tools/react_perf/rules/advanced.js +325 -0
- package/build/tools/react_perf/rules/async.js +104 -0
- package/build/tools/react_perf/rules/bundle.js +101 -0
- package/build/tools/react_perf/rules/client.js +186 -0
- package/build/tools/react_perf/rules/index.js +74 -0
- package/build/tools/react_perf/rules/js.js +148 -0
- package/build/tools/react_perf/rules/rendering.js +166 -0
- package/build/tools/react_perf/rules/rerender.js +161 -0
- package/build/tools/react_perf/rules/server.js +141 -0
- package/build/tools/react_perf/types.js +127 -0
- package/build/tools/vibe_pm/activate.js +102 -0
- package/build/tools/vibe_pm/advisory_review.js +77 -0
- package/build/tools/vibe_pm/briefing.js +178 -0
- package/build/tools/vibe_pm/context.js +439 -0
- package/build/tools/vibe_pm/create_work_order.js +271 -0
- package/build/tools/vibe_pm/doc_status_gate.js +370 -0
- package/build/tools/vibe_pm/doctor.js +262 -0
- package/build/tools/vibe_pm/entity_gate/preflight.js +78 -0
- package/build/tools/vibe_pm/export_output.js +135 -0
- package/build/tools/vibe_pm/finalize_work.js +393 -0
- package/build/tools/vibe_pm/gate.js +33 -0
- package/build/tools/vibe_pm/get_decision.js +281 -0
- package/build/tools/vibe_pm/index.js +593 -0
- package/build/tools/vibe_pm/inspect_code.js +828 -0
- package/build/tools/vibe_pm/intent/generator.js +294 -0
- package/build/tools/vibe_pm/intent/index.js +5 -0
- package/build/tools/vibe_pm/intent/prompt_density.js +227 -0
- package/build/tools/vibe_pm/intent/types.js +70 -0
- package/build/tools/vibe_pm/intent/verifier.js +237 -0
- package/build/tools/vibe_pm/kce/doc_usage.js +51 -0
- package/build/tools/vibe_pm/kce/on_finalize.js +11 -0
- package/build/tools/vibe_pm/kce/preflight.js +232 -0
- package/build/tools/vibe_pm/local_memory.js +26 -0
- package/build/tools/vibe_pm/memory_status.js +82 -0
- package/build/tools/vibe_pm/memory_sync.js +134 -0
- package/build/tools/vibe_pm/modules/decision_snapshot.js +29 -0
- package/build/tools/vibe_pm/modules/ensure.js +100 -0
- package/build/tools/vibe_pm/modules/fingerprint.js +30 -0
- package/build/tools/vibe_pm/modules/fix_dependencies.js +394 -0
- package/build/tools/vibe_pm/modules/planning_v1.js +110 -0
- package/build/tools/vibe_pm/modules/repo_context.js +56 -0
- package/build/tools/vibe_pm/modules/research_v1.js +114 -0
- package/build/tools/vibe_pm/modules/skills_v1.js +100 -0
- package/build/tools/vibe_pm/pm_language.js +222 -0
- package/build/tools/vibe_pm/repair_plan.js +199 -0
- package/build/tools/vibe_pm/run_app.js +597 -0
- package/build/tools/vibe_pm/run_app_podman.js +64 -0
- package/build/tools/vibe_pm/scaffold.js +550 -0
- package/build/tools/vibe_pm/search_oss.js +124 -0
- package/build/tools/vibe_pm/status.js +153 -0
- package/build/tools/vibe_pm/submit_decision.js +87 -0
- package/build/tools/vibe_pm/system_design/issue_mapping.js +47 -0
- package/build/tools/vibe_pm/system_design/rulebook.js +112 -0
- package/build/tools/vibe_pm/system_design/semgrep.js +132 -0
- package/build/tools/vibe_pm/types.js +229 -0
- package/build/tools/vibe_pm/undo_last_task.js +163 -0
- package/build/tools/vibe_pm/update.js +146 -0
- package/build/tools/vibe_pm/zoekt_evidence.js +96 -0
- package/build/tools.js +269 -0
- package/build/version-check.js +239 -0
- package/build/vibe-cli.js +631 -0
- package/package.json +76 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
// adapters/mcp-ts/src/tools/vibe_pm/index.ts
|
|
2
|
+
// vibe_pm.* MCP tools registration and export
|
|
3
|
+
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { briefingInputSchema, briefingOutputSchema, getDecisionInputSchema, getDecisionOutputSchema, submitDecisionInputSchema, submitDecisionOutputSchema, createWorkOrderInputSchema, createWorkOrderOutputSchema, inspectCodeInputSchema, inspectCodeOutputSchema, statusInputSchema, statusOutputSchema, memoryStatusInputSchema, memoryStatusOutputSchema, memorySyncInputSchema, memorySyncOutputSchema, advisoryReviewInputSchema, advisoryReviewOutputSchema, activateInputSchema, activateOutputSchema, repairPlanInputSchema, repairPlanOutputSchema, scaffoldInputSchema, scaffoldOutputSchema, finalizeWorkInputSchema, finalizeWorkOutputSchema, undoLastTaskInputSchema, undoLastTaskOutputSchema, runAppInputSchema, runAppOutputSchema, exportOutputInputSchema, exportOutputOutputSchema, searchOssInputSchema, searchOssOutputSchema, zoektEvidenceInputSchema, zoektEvidenceOutputSchema, doctorOutputSchema, updateOutputSchema } from "./types.js";
|
|
5
|
+
import { briefing } from "./briefing.js";
|
|
6
|
+
import { getDecision } from "./get_decision.js";
|
|
7
|
+
import { submitDecision } from "./submit_decision.js";
|
|
8
|
+
import { createWorkOrder } from "./create_work_order.js";
|
|
9
|
+
import { inspectCode } from "./inspect_code.js";
|
|
10
|
+
import { status } from "./status.js";
|
|
11
|
+
import { memoryStatus } from "./memory_status.js";
|
|
12
|
+
import { memorySync } from "./memory_sync.js";
|
|
13
|
+
import { advisoryReview } from "./advisory_review.js";
|
|
14
|
+
import { activate } from "./activate.js";
|
|
15
|
+
import { repairPlan } from "./repair_plan.js";
|
|
16
|
+
import { doctor, DoctorInputSchema } from "./doctor.js";
|
|
17
|
+
import { update, UpdateInputSchema } from "./update.js";
|
|
18
|
+
import { scaffold } from "./scaffold.js";
|
|
19
|
+
import { finalizeWork } from "./finalize_work.js";
|
|
20
|
+
import { undoLastTask } from "./undo_last_task.js";
|
|
21
|
+
import { runApp } from "./run_app.js";
|
|
22
|
+
import { exportOutput } from "./export_output.js";
|
|
23
|
+
import { searchOss } from "./search_oss.js";
|
|
24
|
+
import { zoektEvidence } from "./zoekt_evidence.js";
|
|
25
|
+
import { gate, gateInputSchema, gateOutputSchema } from "./gate.js";
|
|
26
|
+
import { getAuthGate } from "../../auth/index.js";
|
|
27
|
+
import { ToolErrorOutputSchema } from "../../generated/tool_error_output.js";
|
|
28
|
+
import { decorateToolOutputText, notifyDesktopBestEffort } from "../../dx/activity.js";
|
|
29
|
+
// ============================================================
|
|
30
|
+
// Helper Functions
|
|
31
|
+
// ============================================================
|
|
32
|
+
/**
|
|
33
|
+
* Create a successful tool result with both text and structured content
|
|
34
|
+
*/
|
|
35
|
+
function toolResult(toolName, data, durationMs) {
|
|
36
|
+
const jsonText = JSON.stringify(data, null, 2);
|
|
37
|
+
void notifyDesktopBestEffort({ toolName, data, outcome: "success", durationMs });
|
|
38
|
+
return {
|
|
39
|
+
content: decorateToolOutputText(toolName, jsonText, data, "success", durationMs),
|
|
40
|
+
structuredContent: data
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Legacy helper for backward compatibility
|
|
45
|
+
*/
|
|
46
|
+
function toolText(obj) {
|
|
47
|
+
return { content: [{ type: "text", text: JSON.stringify(obj, null, 2) }] };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create an error tool result (non-throwing for graceful degradation)
|
|
51
|
+
*/
|
|
52
|
+
function err(toolName, reason, extra) {
|
|
53
|
+
const out = ToolErrorOutputSchema.parse({
|
|
54
|
+
status: "ERROR",
|
|
55
|
+
reason,
|
|
56
|
+
message: extra?.message ?? "요청을 처리하는 중 문제가 생겼습니다.",
|
|
57
|
+
recovery: extra?.recovery,
|
|
58
|
+
is_retryable: extra?.is_retryable,
|
|
59
|
+
details: extra?.details,
|
|
60
|
+
debug: extra?.debug
|
|
61
|
+
});
|
|
62
|
+
const jsonText = JSON.stringify(out, null, 2);
|
|
63
|
+
void notifyDesktopBestEffort({ toolName, data: out, outcome: "error" });
|
|
64
|
+
return {
|
|
65
|
+
content: decorateToolOutputText(toolName, jsonText, out, "error"),
|
|
66
|
+
structuredContent: out,
|
|
67
|
+
isError: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convert McpError to tool result for consistent error handling
|
|
72
|
+
*/
|
|
73
|
+
function errorResult(toolName, error) {
|
|
74
|
+
const details = { mcp_code: error.code };
|
|
75
|
+
if (error.data !== undefined) {
|
|
76
|
+
details.mcp_data = error.data;
|
|
77
|
+
}
|
|
78
|
+
return err(toolName, "mcp_error", {
|
|
79
|
+
message: error.message,
|
|
80
|
+
recovery: "입력 값을 확인한 뒤 다시 시도해 주세요.",
|
|
81
|
+
is_retryable: false,
|
|
82
|
+
details
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// ============================================================
|
|
86
|
+
// Tool Handlers (with error handling and structured content)
|
|
87
|
+
// ============================================================
|
|
88
|
+
async function vibePmBriefing(input) {
|
|
89
|
+
const startedAt = Date.now();
|
|
90
|
+
try {
|
|
91
|
+
const result = await briefing(input);
|
|
92
|
+
// Validate output against schema
|
|
93
|
+
const validated = briefingOutputSchema.parse(result);
|
|
94
|
+
return toolResult("vibe_pm.briefing", validated, Date.now() - startedAt);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
if (e instanceof McpError) {
|
|
98
|
+
return errorResult("vibe_pm.briefing", e);
|
|
99
|
+
}
|
|
100
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
101
|
+
return err("vibe_pm.briefing", "briefing_failed", {
|
|
102
|
+
message: msg,
|
|
103
|
+
recovery: "프로젝트 아이디어를 더 구체적으로 설명해보세요."
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function vibePmGetDecision(input) {
|
|
108
|
+
const startedAt = Date.now();
|
|
109
|
+
try {
|
|
110
|
+
const result = await getDecision(input);
|
|
111
|
+
const validated = getDecisionOutputSchema.parse(result);
|
|
112
|
+
return toolResult("vibe_pm.get_decision", validated, Date.now() - startedAt);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
if (e instanceof McpError) {
|
|
116
|
+
return errorResult("vibe_pm.get_decision", e);
|
|
117
|
+
}
|
|
118
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
119
|
+
return err("vibe_pm.get_decision", "get_decision_failed", {
|
|
120
|
+
message: msg,
|
|
121
|
+
recovery: "vibe_pm.briefing 으로 프로젝트를 먼저 시작하세요."
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function vibePmSubmitDecision(input) {
|
|
126
|
+
const startedAt = Date.now();
|
|
127
|
+
try {
|
|
128
|
+
const result = await submitDecision(input);
|
|
129
|
+
const validated = submitDecisionOutputSchema.parse(result);
|
|
130
|
+
return toolResult("vibe_pm.submit_decision", validated, Date.now() - startedAt);
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
if (e instanceof McpError) {
|
|
134
|
+
return errorResult("vibe_pm.submit_decision", e);
|
|
135
|
+
}
|
|
136
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
137
|
+
return err("vibe_pm.submit_decision", "submit_decision_failed", {
|
|
138
|
+
message: msg,
|
|
139
|
+
recovery: "vibe_pm.get_decision 으로 유효한 결재 항목을 확인하세요."
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function vibePmCreateWorkOrder(input) {
|
|
144
|
+
const startedAt = Date.now();
|
|
145
|
+
try {
|
|
146
|
+
const result = await createWorkOrder(input);
|
|
147
|
+
const validated = createWorkOrderOutputSchema.parse(result);
|
|
148
|
+
return toolResult("vibe_pm.create_work_order", validated, Date.now() - startedAt);
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
if (e instanceof McpError) {
|
|
152
|
+
return errorResult("vibe_pm.create_work_order", e);
|
|
153
|
+
}
|
|
154
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
155
|
+
return err("vibe_pm.create_work_order", "create_work_order_failed", {
|
|
156
|
+
message: msg,
|
|
157
|
+
recovery: "모든 결재가 완료되었는지 vibe_pm.status 로 확인하세요."
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function vibePmInspectCode(input) {
|
|
162
|
+
const startedAt = Date.now();
|
|
163
|
+
try {
|
|
164
|
+
const result = await inspectCode(input);
|
|
165
|
+
const validated = inspectCodeOutputSchema.parse(result);
|
|
166
|
+
return toolResult("vibe_pm.inspect_code", validated, Date.now() - startedAt);
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
if (e instanceof McpError) {
|
|
170
|
+
return errorResult("vibe_pm.inspect_code", e);
|
|
171
|
+
}
|
|
172
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
173
|
+
return err("vibe_pm.inspect_code", "inspect_code_failed", {
|
|
174
|
+
message: msg,
|
|
175
|
+
recovery: "vibe_pm.create_work_order 로 작업 지시서를 먼저 생성하세요."
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function vibePmStatus(input) {
|
|
180
|
+
const startedAt = Date.now();
|
|
181
|
+
try {
|
|
182
|
+
const result = await status(input);
|
|
183
|
+
const validated = statusOutputSchema.parse(result);
|
|
184
|
+
return toolResult("vibe_pm.status", validated, Date.now() - startedAt);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
if (e instanceof McpError) {
|
|
188
|
+
return errorResult("vibe_pm.status", e);
|
|
189
|
+
}
|
|
190
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
191
|
+
return err("vibe_pm.status", "status_failed", {
|
|
192
|
+
message: msg,
|
|
193
|
+
recovery: "vibe_pm.briefing 으로 프로젝트를 먼저 시작하세요."
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function vibePmMemoryStatus(input) {
|
|
198
|
+
const startedAt = Date.now();
|
|
199
|
+
try {
|
|
200
|
+
// Pro gating: memory_status is a PRO control tool (manual sync/status visibility)
|
|
201
|
+
const gate = getAuthGate();
|
|
202
|
+
const allowed = await gate.check("local_memory_pro_tools");
|
|
203
|
+
if (!allowed.allowed) {
|
|
204
|
+
return err("vibe_pm.memory_status", "feature_locked", {
|
|
205
|
+
message: "이 기능은 Pro 전용입니다. (Local Memory 상태 조회)",
|
|
206
|
+
recovery: "vibe_pm.activate로 라이선스를 등록한 뒤 다시 시도하세요.",
|
|
207
|
+
details: { feature: "local_memory_pro_tools", gate_reason: allowed.reason ?? "unknown" }
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const result = await memoryStatus(input);
|
|
211
|
+
const validated = memoryStatusOutputSchema.parse(result);
|
|
212
|
+
return toolResult("vibe_pm.memory_status", validated, Date.now() - startedAt);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
if (e instanceof McpError) {
|
|
216
|
+
return errorResult("vibe_pm.memory_status", e);
|
|
217
|
+
}
|
|
218
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
219
|
+
return err("vibe_pm.memory_status", "memory_status_failed", {
|
|
220
|
+
message: msg,
|
|
221
|
+
recovery: "Local Memory 상태 확인에 실패했습니다. vibe_pm.doctor 를 실행해보세요."
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async function vibePmMemorySync(input) {
|
|
226
|
+
const startedAt = Date.now();
|
|
227
|
+
try {
|
|
228
|
+
// Pro gating: memory_sync performs indexing/refresh and is PRO-only.
|
|
229
|
+
const gate = getAuthGate();
|
|
230
|
+
const allowed = await gate.check("local_memory_pro_tools");
|
|
231
|
+
if (!allowed.allowed) {
|
|
232
|
+
return err("vibe_pm.memory_sync", "feature_locked", {
|
|
233
|
+
message: "이 기능은 Pro 전용입니다. (Local Memory 동기화)",
|
|
234
|
+
recovery: "vibe_pm.activate로 라이선스를 등록한 뒤 다시 시도하세요.",
|
|
235
|
+
details: { feature: "local_memory_pro_tools", gate_reason: allowed.reason ?? "unknown" }
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const result = await memorySync(input);
|
|
239
|
+
const validated = memorySyncOutputSchema.parse(result);
|
|
240
|
+
return toolResult("vibe_pm.memory_sync", validated, Date.now() - startedAt);
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
if (e instanceof McpError) {
|
|
244
|
+
return errorResult("vibe_pm.memory_sync", e);
|
|
245
|
+
}
|
|
246
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
247
|
+
return err("vibe_pm.memory_sync", "memory_sync_failed", {
|
|
248
|
+
message: msg,
|
|
249
|
+
recovery: "Local Memory 갱신에 실패했습니다. vibe_pm.doctor 를 실행해보세요."
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function vibePmAdvisoryReview(input) {
|
|
254
|
+
const startedAt = Date.now();
|
|
255
|
+
try {
|
|
256
|
+
// P18: Pro gating (triage is always allowed; quick/thorough require deep_advisory entitlement)
|
|
257
|
+
const mode = (input.mode ?? "triage");
|
|
258
|
+
if (mode !== "triage") {
|
|
259
|
+
const gate = getAuthGate();
|
|
260
|
+
const allowed = await gate.check("deep_advisory");
|
|
261
|
+
if (!allowed.allowed) {
|
|
262
|
+
return err("vibe_pm.advisory_review", "feature_locked", {
|
|
263
|
+
message: "이 기능은 Pro 전용입니다. (심층 리뷰)",
|
|
264
|
+
recovery: "vibe_pm.activate로 라이선스 키를 등록한 뒤 다시 시도하세요.",
|
|
265
|
+
details: { feature: "deep_advisory", gate_reason: allowed.reason ?? "unknown" }
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const result = await advisoryReview(input);
|
|
270
|
+
const validated = advisoryReviewOutputSchema.parse(result);
|
|
271
|
+
return toolResult("vibe_pm.advisory_review", validated, Date.now() - startedAt);
|
|
272
|
+
}
|
|
273
|
+
catch (e) {
|
|
274
|
+
if (e instanceof McpError) {
|
|
275
|
+
return errorResult("vibe_pm.advisory_review", e);
|
|
276
|
+
}
|
|
277
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
278
|
+
return err("vibe_pm.advisory_review", "advisory_review_failed", {
|
|
279
|
+
message: msg,
|
|
280
|
+
recovery: "필요하면 먼저 vibe_pm.memory_sync 로 문서 인덱스를 갱신한 뒤 다시 시도하세요."
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async function vibePmActivate(input) {
|
|
285
|
+
const startedAt = Date.now();
|
|
286
|
+
try {
|
|
287
|
+
const result = await activate(input);
|
|
288
|
+
const validated = activateOutputSchema.parse(result);
|
|
289
|
+
return toolResult("vibe_pm.activate", validated, Date.now() - startedAt);
|
|
290
|
+
}
|
|
291
|
+
catch (e) {
|
|
292
|
+
if (e instanceof McpError) {
|
|
293
|
+
return errorResult("vibe_pm.activate", e);
|
|
294
|
+
}
|
|
295
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
296
|
+
return err("vibe_pm.activate", "activate_failed", {
|
|
297
|
+
message: msg,
|
|
298
|
+
recovery: "네트워크/키 상태를 확인한 뒤 다시 시도하세요. (오프라인 모드에서는 활성화가 불가합니다.)"
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function vibePmRepairPlan(input) {
|
|
303
|
+
const startedAt = Date.now();
|
|
304
|
+
try {
|
|
305
|
+
const result = await repairPlan(input);
|
|
306
|
+
const validated = repairPlanOutputSchema.parse(result);
|
|
307
|
+
return toolResult("vibe_pm.repair_plan", validated, Date.now() - startedAt);
|
|
308
|
+
}
|
|
309
|
+
catch (e) {
|
|
310
|
+
if (e instanceof McpError) {
|
|
311
|
+
return errorResult("vibe_pm.repair_plan", e);
|
|
312
|
+
}
|
|
313
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
314
|
+
return err("vibe_pm.repair_plan", "repair_plan_failed", {
|
|
315
|
+
message: msg,
|
|
316
|
+
recovery: "vibe_pm.inspect_code 를 먼저 실행하세요."
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function vibePmDoctor(input) {
|
|
321
|
+
const startedAt = Date.now();
|
|
322
|
+
try {
|
|
323
|
+
const result = await doctor(input);
|
|
324
|
+
const validated = doctorOutputSchema.parse(result);
|
|
325
|
+
return toolResult("vibe_pm.doctor", validated, Date.now() - startedAt);
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
if (e instanceof McpError) {
|
|
329
|
+
return errorResult("vibe_pm.doctor", e);
|
|
330
|
+
}
|
|
331
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
332
|
+
return err("vibe_pm.doctor", "doctor_failed", { message: msg });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function vibePmUpdate(input) {
|
|
336
|
+
const startedAt = Date.now();
|
|
337
|
+
try {
|
|
338
|
+
const result = await update(input);
|
|
339
|
+
const validated = updateOutputSchema.parse(result);
|
|
340
|
+
return toolResult("vibe_pm.update", validated, Date.now() - startedAt);
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
if (e instanceof McpError) {
|
|
344
|
+
return errorResult("vibe_pm.update", e);
|
|
345
|
+
}
|
|
346
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
347
|
+
return err("vibe_pm.update", "update_failed", { message: msg });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async function vibePmScaffold(input) {
|
|
351
|
+
const startedAt = Date.now();
|
|
352
|
+
try {
|
|
353
|
+
const result = await scaffold(input);
|
|
354
|
+
const validated = scaffoldOutputSchema.parse(result);
|
|
355
|
+
return toolResult("vibe_pm.scaffold", validated, Date.now() - startedAt);
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
if (e instanceof McpError) {
|
|
359
|
+
return errorResult("vibe_pm.scaffold", e);
|
|
360
|
+
}
|
|
361
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
362
|
+
return err("vibe_pm.scaffold", "scaffold_failed", {
|
|
363
|
+
message: msg,
|
|
364
|
+
recovery: "빈 디렉토리에서 실행하거나 force: true 옵션을 사용하세요."
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async function vibePmFinalizeWork(input) {
|
|
369
|
+
const startedAt = Date.now();
|
|
370
|
+
try {
|
|
371
|
+
const result = await finalizeWork(input);
|
|
372
|
+
const validated = finalizeWorkOutputSchema.parse(result);
|
|
373
|
+
return toolResult("vibe_pm.finalize_work", validated, Date.now() - startedAt);
|
|
374
|
+
}
|
|
375
|
+
catch (e) {
|
|
376
|
+
if (e instanceof McpError) {
|
|
377
|
+
return errorResult("vibe_pm.finalize_work", e);
|
|
378
|
+
}
|
|
379
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
380
|
+
return err("vibe_pm.finalize_work", "finalize_work_failed", {
|
|
381
|
+
message: msg,
|
|
382
|
+
recovery: "Git 저장소인지 확인하고 다시 시도하세요."
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async function vibePmUndoLastTask(input) {
|
|
387
|
+
const startedAt = Date.now();
|
|
388
|
+
try {
|
|
389
|
+
const result = await undoLastTask(input);
|
|
390
|
+
const validated = undoLastTaskOutputSchema.parse(result);
|
|
391
|
+
return toolResult("vibe_pm.undo_last_task", validated, Date.now() - startedAt);
|
|
392
|
+
}
|
|
393
|
+
catch (e) {
|
|
394
|
+
if (e instanceof McpError) {
|
|
395
|
+
return errorResult("vibe_pm.undo_last_task", e);
|
|
396
|
+
}
|
|
397
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
398
|
+
return err("vibe_pm.undo_last_task", "undo_last_task_failed", {
|
|
399
|
+
message: msg,
|
|
400
|
+
recovery: "Git 저장소인지 확인하고 커밋 이력이 있는지 확인하세요."
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async function vibePmRunApp(input) {
|
|
405
|
+
const startedAt = Date.now();
|
|
406
|
+
try {
|
|
407
|
+
const result = await runApp(input);
|
|
408
|
+
const validated = runAppOutputSchema.parse(result);
|
|
409
|
+
return toolResult("vibe_pm.run_app", validated, Date.now() - startedAt);
|
|
410
|
+
}
|
|
411
|
+
catch (e) {
|
|
412
|
+
if (e instanceof McpError) {
|
|
413
|
+
return errorResult("vibe_pm.run_app", e);
|
|
414
|
+
}
|
|
415
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
416
|
+
return err("vibe_pm.run_app", "run_app_failed", {
|
|
417
|
+
message: msg,
|
|
418
|
+
recovery: "package.json 또는 requirements.txt가 있는지 확인하세요."
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async function vibePmExportOutput(input) {
|
|
423
|
+
const startedAt = Date.now();
|
|
424
|
+
try {
|
|
425
|
+
const result = await exportOutput(input);
|
|
426
|
+
const validated = exportOutputOutputSchema.parse(result);
|
|
427
|
+
return toolResult("vibe_pm.export_output", validated, Date.now() - startedAt);
|
|
428
|
+
}
|
|
429
|
+
catch (e) {
|
|
430
|
+
if (e instanceof McpError) {
|
|
431
|
+
return errorResult("vibe_pm.export_output", e);
|
|
432
|
+
}
|
|
433
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
434
|
+
return err("vibe_pm.export_output", "export_output_failed", {
|
|
435
|
+
message: msg,
|
|
436
|
+
recovery: "내보내기 대상과 출력 폴더를 확인한 뒤 다시 시도해 주세요."
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async function vibePmSearchOss(input) {
|
|
441
|
+
const startedAt = Date.now();
|
|
442
|
+
try {
|
|
443
|
+
const result = await searchOss(input);
|
|
444
|
+
const validated = searchOssOutputSchema.parse(result);
|
|
445
|
+
return toolResult("vibe_pm.search_oss", validated, Date.now() - startedAt);
|
|
446
|
+
}
|
|
447
|
+
catch (e) {
|
|
448
|
+
if (e instanceof McpError) {
|
|
449
|
+
return errorResult("vibe_pm.search_oss", e);
|
|
450
|
+
}
|
|
451
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
452
|
+
return err("vibe_pm.search_oss", "search_oss_failed", {
|
|
453
|
+
message: msg,
|
|
454
|
+
recovery: "gh 인증/설치 상태를 확인한 뒤 다시 시도해주세요."
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async function vibePmZoektEvidence(input) {
|
|
459
|
+
const startedAt = Date.now();
|
|
460
|
+
try {
|
|
461
|
+
const result = await zoektEvidence(input);
|
|
462
|
+
const validated = zoektEvidenceOutputSchema.parse(result);
|
|
463
|
+
return toolResult("vibe_pm.zoekt_evidence", validated, Date.now() - startedAt);
|
|
464
|
+
}
|
|
465
|
+
catch (e) {
|
|
466
|
+
if (e instanceof McpError) {
|
|
467
|
+
return errorResult("vibe_pm.zoekt_evidence", e);
|
|
468
|
+
}
|
|
469
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
470
|
+
return err("vibe_pm.zoekt_evidence", "zoekt_evidence_failed", {
|
|
471
|
+
message: msg,
|
|
472
|
+
recovery: "roots 경로/권한을 확인한 뒤 다시 시도해주세요."
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async function vibePmGate(input) {
|
|
477
|
+
const startedAt = Date.now();
|
|
478
|
+
try {
|
|
479
|
+
const result = await gate(input);
|
|
480
|
+
const validated = gateOutputSchema.parse(result);
|
|
481
|
+
return toolResult("vibe_pm.gate", validated, Date.now() - startedAt);
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
if (e instanceof McpError) {
|
|
485
|
+
return errorResult("vibe_pm.gate", e);
|
|
486
|
+
}
|
|
487
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
488
|
+
return err("vibe_pm.gate", "gate_failed", {
|
|
489
|
+
message: msg,
|
|
490
|
+
recovery: "work_order 형식을 확인하고 다시 시도해주세요."
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// ============================================================
|
|
495
|
+
// Export
|
|
496
|
+
// ============================================================
|
|
497
|
+
export function defineVibePmTools() {
|
|
498
|
+
return {
|
|
499
|
+
// Input schemas (for validation)
|
|
500
|
+
briefingInputSchema,
|
|
501
|
+
getDecisionInputSchema,
|
|
502
|
+
submitDecisionInputSchema,
|
|
503
|
+
createWorkOrderInputSchema,
|
|
504
|
+
inspectCodeInputSchema,
|
|
505
|
+
statusInputSchema,
|
|
506
|
+
memoryStatusInputSchema,
|
|
507
|
+
memorySyncInputSchema,
|
|
508
|
+
advisoryReviewInputSchema,
|
|
509
|
+
activateInputSchema,
|
|
510
|
+
repairPlanInputSchema,
|
|
511
|
+
doctorInputSchema: DoctorInputSchema,
|
|
512
|
+
updateInputSchema: UpdateInputSchema,
|
|
513
|
+
scaffoldInputSchema,
|
|
514
|
+
finalizeWorkInputSchema,
|
|
515
|
+
undoLastTaskInputSchema,
|
|
516
|
+
runAppInputSchema,
|
|
517
|
+
exportOutputInputSchema,
|
|
518
|
+
searchOssInputSchema,
|
|
519
|
+
zoektEvidenceInputSchema,
|
|
520
|
+
gateInputSchema,
|
|
521
|
+
// Tool handlers
|
|
522
|
+
vibePmBriefing,
|
|
523
|
+
vibePmGetDecision,
|
|
524
|
+
vibePmSubmitDecision,
|
|
525
|
+
vibePmCreateWorkOrder,
|
|
526
|
+
vibePmInspectCode,
|
|
527
|
+
vibePmStatus,
|
|
528
|
+
vibePmMemoryStatus,
|
|
529
|
+
vibePmMemorySync,
|
|
530
|
+
vibePmAdvisoryReview,
|
|
531
|
+
vibePmActivate,
|
|
532
|
+
vibePmRepairPlan,
|
|
533
|
+
vibePmDoctor,
|
|
534
|
+
vibePmUpdate,
|
|
535
|
+
vibePmScaffold,
|
|
536
|
+
vibePmFinalizeWork,
|
|
537
|
+
vibePmUndoLastTask,
|
|
538
|
+
vibePmRunApp,
|
|
539
|
+
vibePmExportOutput,
|
|
540
|
+
vibePmSearchOss,
|
|
541
|
+
vibePmZoektEvidence,
|
|
542
|
+
vibePmGate
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
// ============================================================
|
|
546
|
+
// Tool Descriptions (for MCP registration)
|
|
547
|
+
// ============================================================
|
|
548
|
+
export const VIBE_PM_TOOL_DESCRIPTIONS = {
|
|
549
|
+
"vibe_pm.briefing": `프로젝트를 시작하거나 재개합니다. 사용자의 아이디어를 받아 구조화합니다.
|
|
550
|
+
사용 시점: 사용자가 "시작해줘" 또는 새 아이디어를 설명할 때`,
|
|
551
|
+
"vibe_pm.get_decision": `현재 결재가 필요한 안건을 조회합니다.
|
|
552
|
+
사용 시점: 구현 전 승인이 필요할 때`,
|
|
553
|
+
"vibe_pm.submit_decision": `결재를 제출합니다.
|
|
554
|
+
사용 시점: 사용자가 선택지(A/B/C/U)를 고른 후`,
|
|
555
|
+
"vibe_pm.create_work_order": `결정된 사항을 바탕으로 작업 지시서를 발행합니다.
|
|
556
|
+
사용 시점: 모든 결재가 완료된 후, 구현 전`,
|
|
557
|
+
"vibe_pm.inspect_code": `구현된 코드를 검수합니다. auto_fix 옵션으로 의존성 문제 자동 수정.
|
|
558
|
+
사용 시점: 구현 완료 후 검증이 필요할 때`,
|
|
559
|
+
"vibe_pm.status": `현재 프로젝트 상태를 조회합니다.
|
|
560
|
+
사용 시점: 사용자가 "상태", "어디까지 했어" 물어볼 때`,
|
|
561
|
+
"vibe_pm.memory_status": `Local Memory(문서 자동 기억) 준비 상태를 조회합니다.
|
|
562
|
+
사용 시점: 문서 참조가 잘 안 되거나 인덱스 상태를 확인하고 싶을 때`,
|
|
563
|
+
"vibe_pm.memory_sync": `Local Memory(문서 자동 기억) 인덱스를 갱신합니다. (변경분만 처리)
|
|
564
|
+
사용 시점: 문서를 많이 바꿨거나 즉시 갱신이 필요할 때`,
|
|
565
|
+
"vibe_pm.advisory_review": `코드/설계/운영 관점의 고차원 조언 리뷰를 제공합니다. (기본: triage로 실행 여부/포커스만 결정)
|
|
566
|
+
사용 시점: 사용자가 심층 리뷰를 원하거나, 마감 직전 최종 점검이 필요할 때`,
|
|
567
|
+
"vibe_pm.activate": `라이선스 키를 등록해 Pro 기능을 활성화합니다. (1회 온라인 활성화 → 로컬 토큰 캐시 → 오프라인 검증)
|
|
568
|
+
사용 시점: Pro 기능을 쓰고 싶을 때 또는 라이선스 만료/재활성화가 필요할 때`,
|
|
569
|
+
"vibe_pm.repair_plan": `검수 실패 시 AI에게 보낼 수정 요청 프롬프트를 생성합니다.
|
|
570
|
+
사용 시점: inspect_code가 FIX 또는 BLOCK을 반환했을 때`,
|
|
571
|
+
"vibe_pm.doctor": `설치 상태를 점검하고 문제가 있으면 자동으로 수정합니다.
|
|
572
|
+
사용 시점: 도구가 동작하지 않거나 오류가 발생할 때`,
|
|
573
|
+
"vibe_pm.update": `엔진 바이너리를 최신 버전으로 업데이트합니다.
|
|
574
|
+
사용 시점: 새 버전이 출시되었거나 업데이트가 필요할 때`,
|
|
575
|
+
"vibe_pm.scaffold": `표준 프로젝트 구조(Vibe-SDS)를 생성합니다.
|
|
576
|
+
사용 시점: 새 프로젝트 시작 시, 빈 디렉토리에서 "프로젝트 시작해줘" 할 때
|
|
577
|
+
템플릿: minimal, standard, python_cli, node_api`,
|
|
578
|
+
"vibe_pm.finalize_work": `작업 완료 후 문서 갱신, 개발 로그 작성, Git 커밋/푸시를 한 번에 처리합니다.
|
|
579
|
+
사용 시점: 작업이 완료되고 "커밋해줘", "마무리해줘" 할 때`,
|
|
580
|
+
"vibe_pm.undo_last_task": `방금 완료한 작업을 취소하고 이전 상태로 되돌립니다. Git revert 사용.
|
|
581
|
+
사용 시점: "방금 한 거 취소해줘", "롤백해줘" 할 때`,
|
|
582
|
+
"vibe_pm.run_app": `프로젝트를 자동으로 감지하여 실행합니다. Node.js/Python 지원.
|
|
583
|
+
사용 시점: "실행해줘", "서버 켜줘" 할 때`,
|
|
584
|
+
"vibe_pm.search_oss": `OSS 템플릿/레포 후보를 검색(gh)하고 근거를 저장합니다.
|
|
585
|
+
사용 시점: export_output용 템플릿을 고르기 전에 후보를 좁히고 싶을 때`,
|
|
586
|
+
"vibe_pm.zoekt_evidence": `로컬 루트들에서 패턴 증거를 수집합니다(zoekt/rg/python_scan).
|
|
587
|
+
사용 시점: 특정 코드 패턴이 실제로 얼마나 쓰이는지 근거가 필요할 때`,
|
|
588
|
+
"vibe_pm.export_output": `구현된 기능을 원하는 형태로 내보냅니다. (문서/API/CLI 등)
|
|
589
|
+
사용 시점: 기능 구현 및 검수 후, 결과물을 다른 형태로 배포/공유하고 싶을 때`,
|
|
590
|
+
"vibe_pm.gate": `작업 지시서가 시스템 설계 규칙을 준수하는지 검증합니다. (Schema/Path/Runtime/Semgrep Gate)
|
|
591
|
+
사용 시점: 실행 전 work order가 규칙을 준수하는지 직접 확인하고 싶을 때
|
|
592
|
+
BLOCK이 없으면 실행 가능, BLOCK이 있으면 수정이 필요합니다.`
|
|
593
|
+
};
|