@vibecodetown/mcp-server 2.1.4 → 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 (80) hide show
  1. package/README.md +10 -10
  2. package/build/auth/credential_store.js +146 -0
  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/control_plane/gate.js +52 -70
  9. package/build/dx/activity.js +26 -3
  10. package/build/engine.js +151 -0
  11. package/build/errors.js +107 -0
  12. package/build/generated/bridge_build_seed_input.js +2 -0
  13. package/build/generated/bridge_build_seed_output.js +2 -0
  14. package/build/generated/bridge_confirm_reference_input.js +2 -0
  15. package/build/generated/bridge_confirm_reference_output.js +2 -0
  16. package/build/generated/bridge_confirmed_reference_file.js +2 -0
  17. package/build/generated/bridge_generate_references_input.js +2 -0
  18. package/build/generated/bridge_generate_references_output.js +2 -0
  19. package/build/generated/bridge_references_file.js +2 -0
  20. package/build/generated/bridge_work_order_seed_file.js +2 -0
  21. package/build/generated/contracts_bundle_info.js +3 -3
  22. package/build/generated/index.js +14 -0
  23. package/build/generated/ingress_input.js +2 -0
  24. package/build/generated/ingress_output.js +2 -0
  25. package/build/generated/ingress_resolution_file.js +2 -0
  26. package/build/generated/ingress_summary_file.js +2 -0
  27. package/build/generated/message_template_id_mapping_file.js +2 -0
  28. package/build/generated/run_app_input.js +1 -1
  29. package/build/index.js +4 -1
  30. package/build/local-mode/git.js +36 -22
  31. package/build/local-mode/paths.js +1 -0
  32. package/build/local-mode/project-state.js +176 -0
  33. package/build/local-mode/setup.js +21 -1
  34. package/build/local-mode/templates.js +3 -3
  35. package/build/path-utils.js +68 -0
  36. package/build/runtime/cli_invoker.js +416 -0
  37. package/build/tools/vibe_pm/advisory_review.js +5 -3
  38. package/build/tools/vibe_pm/bridge_build_seed.js +164 -0
  39. package/build/tools/vibe_pm/bridge_confirm_reference.js +91 -0
  40. package/build/tools/vibe_pm/bridge_generate_references.js +258 -0
  41. package/build/tools/vibe_pm/briefing.js +26 -1
  42. package/build/tools/vibe_pm/context.js +79 -0
  43. package/build/tools/vibe_pm/create_work_order.js +200 -3
  44. package/build/tools/vibe_pm/doctor.js +95 -0
  45. package/build/tools/vibe_pm/entity_gate/preflight.js +8 -3
  46. package/build/tools/vibe_pm/export_output.js +14 -13
  47. package/build/tools/vibe_pm/finalize_work.js +74 -0
  48. package/build/tools/vibe_pm/force_override.js +104 -0
  49. package/build/tools/vibe_pm/get_decision.js +2 -2
  50. package/build/tools/vibe_pm/index.js +160 -3
  51. package/build/tools/vibe_pm/ingress.js +645 -0
  52. package/build/tools/vibe_pm/ingress_gate.js +116 -0
  53. package/build/tools/vibe_pm/inspect_code.js +90 -20
  54. package/build/tools/vibe_pm/kce/doc_usage.js +4 -9
  55. package/build/tools/vibe_pm/kce/on_finalize.js +2 -2
  56. package/build/tools/vibe_pm/kce/preflight.js +11 -7
  57. package/build/tools/vibe_pm/list_rules.js +135 -0
  58. package/build/tools/vibe_pm/memory_status.js +11 -8
  59. package/build/tools/vibe_pm/memory_sync.js +11 -8
  60. package/build/tools/vibe_pm/pm_language.js +17 -16
  61. package/build/tools/vibe_pm/pre_commit_analysis.js +292 -0
  62. package/build/tools/vibe_pm/publish_mcp.js +271 -0
  63. package/build/tools/vibe_pm/python_error.js +115 -0
  64. package/build/tools/vibe_pm/run_app.js +215 -86
  65. package/build/tools/vibe_pm/run_app_podman.js +64 -2
  66. package/build/tools/vibe_pm/save_rule.js +120 -0
  67. package/build/tools/vibe_pm/search_oss.js +5 -3
  68. package/build/tools/vibe_pm/spec_rag.js +185 -0
  69. package/build/tools/vibe_pm/status.js +50 -3
  70. package/build/tools/vibe_pm/submit_decision.js +2 -2
  71. package/build/tools/vibe_pm/types.js +28 -0
  72. package/build/tools/vibe_pm/undo_last_task.js +23 -20
  73. package/build/tools/vibe_pm/waiter_mapping.js +155 -0
  74. package/build/tools/vibe_pm/zoekt_evidence.js +5 -3
  75. package/build/tools.js +13 -5
  76. package/build/version-check.js +5 -5
  77. package/build/vibe-cli.js +742 -39
  78. package/package.json +5 -4
  79. package/skills/VRIP_INSTALL_MANIFEST_DOCTOR.skill.md +288 -0
  80. package/skills/index.json +14 -0
@@ -0,0 +1,155 @@
1
+ // adapters/mcp-ts/src/tools/vibe_pm/waiter_mapping.ts
2
+ // Waiter(Front) rendering: message_template_id mapping + term dictionary (data-driven)
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { MessageTemplateIdMappingFileSchema } from "../../generated/message_template_id_mapping_file.js";
7
+ let cache = null;
8
+ function packageRoot() {
9
+ const here = path.dirname(fileURLToPath(import.meta.url));
10
+ // src/tools/vibe_pm → package root
11
+ return path.resolve(here, "..", "..", "..");
12
+ }
13
+ function repoRoot(pkgRoot) {
14
+ // adapters/mcp-ts → repo root
15
+ return path.resolve(pkgRoot, "..", "..");
16
+ }
17
+ function existsFile(p) {
18
+ try {
19
+ return fs.existsSync(p) && fs.statSync(p).isFile();
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ function readJsonFile(p) {
26
+ const raw = fs.readFileSync(p, "utf-8");
27
+ return JSON.parse(raw);
28
+ }
29
+ function safeLocaleList(mapping) {
30
+ const locales = mapping?.supported_locales;
31
+ return Array.isArray(locales) ? locales.map((x) => String(x).trim()).filter(Boolean) : [];
32
+ }
33
+ function safeDefaultLocale(mapping) {
34
+ const d = mapping?.default_locale;
35
+ return typeof d === "string" && d.trim() ? d.trim() : "ko";
36
+ }
37
+ function safeFallbackLocale(mapping) {
38
+ const f = mapping?.human_language_policy?.fallback_locale;
39
+ const s = typeof f === "string" && f.trim() ? f.trim() : "";
40
+ return s || safeDefaultLocale(mapping);
41
+ }
42
+ export function resetWaiterMappingCacheForTest() {
43
+ cache = null;
44
+ }
45
+ export function getWaiterMapping() {
46
+ const pkgRoot = packageRoot();
47
+ const candidates = [
48
+ path.join(pkgRoot, "assets", "message_template_id_mapping.v1.json"),
49
+ path.join(repoRoot(pkgRoot), "schemas", "message_template_id_mapping.v1.json")
50
+ ];
51
+ for (const p of candidates) {
52
+ if (!existsFile(p))
53
+ continue;
54
+ const mtimeMs = fs.statSync(p).mtimeMs;
55
+ if (cache && cache.mappingPath === p && cache.mtimeMs === mtimeMs) {
56
+ return cache.mapping;
57
+ }
58
+ const raw = readJsonFile(p);
59
+ const parsed = MessageTemplateIdMappingFileSchema.parse(raw);
60
+ cache = { mappingPath: p, mtimeMs, mapping: parsed };
61
+ return parsed;
62
+ }
63
+ // Fail-closed is too harsh for user-facing rendering; fall back to a minimal internal default.
64
+ const fallback = MessageTemplateIdMappingFileSchema.parse({
65
+ version: "message_template_id_mapping.v1",
66
+ default_locale: "ko",
67
+ supported_locales: ["ko", "en"],
68
+ templates: {
69
+ "GO-01": { category: "GO", verdict: { ko: "진행 가능", en: "OK to proceed" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
70
+ "GO-02": { category: "GO", verdict: { ko: "진행 가능", en: "OK to proceed" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
71
+ "FIX-01": { category: "FIX", verdict: { ko: "보완 필요", en: "Needs changes" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
72
+ "FIX-02": { category: "FIX", verdict: { ko: "보완 필요", en: "Needs changes" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
73
+ "BLOCK-01": { category: "BLOCK", verdict: { ko: "반려", en: "Blocked" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
74
+ "BLOCK-02": { category: "BLOCK", verdict: { ko: "반려", en: "Blocked" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
75
+ "TRIAGE-SKIP-01": { category: "TRIAGE", verdict: { ko: "사전 점검 생략", en: "Pre-check skipped" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
76
+ "TRIAGE-RUN-01": { category: "TRIAGE", verdict: { ko: "사전 점검 실행", en: "Pre-check running" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
77
+ "TRIAGE-RUN-02": { category: "TRIAGE", verdict: { ko: "사전 점검 실행", en: "Pre-check running" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
78
+ "ADV-01": { category: "ADVICE", verdict: { ko: "참고", en: "Advice" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
79
+ "ADV-02": { category: "ADVICE", verdict: { ko: "참고", en: "Advice" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
80
+ "WARN-01": { category: "WARN", verdict: { ko: "주의", en: "Warning" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
81
+ "WARN-02": { category: "WARN", verdict: { ko: "주의", en: "Warning" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } },
82
+ "SOFTBLOCK-01": { category: "SOFTBLOCK", verdict: { ko: "잠깐 멈춤", en: "Pause" }, next_action_prefix: { ko: "다음 단계:", en: "Next:" } }
83
+ },
84
+ term_dictionary: { entries: [{ id: "ENGINE_RUN_ID", aliases: ["run_id"], replacement: { ko: "프로젝트", en: "project" }, category: "engine_term" }] }
85
+ });
86
+ cache = { mappingPath: "<fallback>", mtimeMs: 0, mapping: fallback };
87
+ return fallback;
88
+ }
89
+ export function resolveLocaleFromText(text, mapping = getWaiterMapping()) {
90
+ const env = (process.env.VIBECODE_LOCALE ?? "").trim();
91
+ const supported = safeLocaleList(mapping);
92
+ if (env && supported.includes(env))
93
+ return env;
94
+ const hasKo = /[가-힣]/.test(text);
95
+ if (hasKo && supported.includes("ko"))
96
+ return "ko";
97
+ if (!hasKo && supported.includes("en"))
98
+ return "en";
99
+ return safeFallbackLocale(mapping);
100
+ }
101
+ export function resolveLocaleFromData(data, mapping = getWaiterMapping()) {
102
+ const env = (process.env.VIBECODE_LOCALE ?? "").trim();
103
+ const supported = safeLocaleList(mapping);
104
+ if (env && supported.includes(env))
105
+ return env;
106
+ if (data && typeof data === "object") {
107
+ const obj = data;
108
+ const oneLine = obj.review_summary?.one_line_verdict;
109
+ const msg = typeof oneLine === "string" ? oneLine : typeof obj.message === "string" ? obj.message : "";
110
+ if (msg)
111
+ return resolveLocaleFromText(msg, mapping);
112
+ }
113
+ return safeFallbackLocale(mapping);
114
+ }
115
+ export function renderVerdictFromTemplateId(templateId, locale, mapping = getWaiterMapping()) {
116
+ const templates = mapping?.templates ?? {};
117
+ const t = templates[templateId];
118
+ if (!t || typeof t !== "object")
119
+ return null;
120
+ const verdict = t?.verdict;
121
+ if (!verdict || typeof verdict !== "object")
122
+ return null;
123
+ const v = verdict[locale];
124
+ if (typeof v === "string" && v.trim())
125
+ return v.trim();
126
+ const fallback = safeFallbackLocale(mapping);
127
+ const vf = verdict[fallback];
128
+ if (typeof vf === "string" && vf.trim())
129
+ return vf.trim();
130
+ return null;
131
+ }
132
+ function escapeRegex(s) {
133
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
134
+ }
135
+ export function applyTermDictionary(text, locale, mapping = getWaiterMapping()) {
136
+ let out = text;
137
+ const entries = mapping?.term_dictionary?.entries;
138
+ if (!Array.isArray(entries) || entries.length === 0)
139
+ return out;
140
+ for (const e of entries) {
141
+ const obj = e;
142
+ const aliases = Array.isArray(obj?.aliases) ? obj.aliases.map((a) => String(a)).filter(Boolean) : [];
143
+ const rep = obj?.replacement;
144
+ const replacement = typeof rep === "object" && rep !== null ? String(rep[locale] ?? "").trim() : "";
145
+ if (!replacement || aliases.length === 0)
146
+ continue;
147
+ for (const a of aliases) {
148
+ const alias = String(a).trim();
149
+ if (!alias)
150
+ continue;
151
+ out = out.replace(new RegExp(escapeRegex(alias), "gi"), replacement);
152
+ }
153
+ }
154
+ return out;
155
+ }
@@ -1,10 +1,11 @@
1
1
  // adapters/mcp-ts/src/tools/vibe_pm/zoekt_evidence.ts
2
2
  // vibe_pm.zoekt_evidence - Collect pattern evidence across local roots (zoekt/rg/python_scan)
3
3
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
4
- import { runEngine } from "../../engine.js";
4
+ import { runPythonCli } from "../../engine.js";
5
5
  import { safeJsonParse } from "../../cli.js";
6
6
  import { validateToolInput } from "../../security/input-validator.js";
7
7
  import { resolveProjectId, resolveRunId } from "./context.js";
8
+ import { classifyPythonError } from "./python_error.js";
8
9
  function toCsv(values) {
9
10
  return values
10
11
  .map((v) => (typeof v === "string" ? v.trim() : ""))
@@ -43,9 +44,10 @@ export async function zoektEvidence(input) {
43
44
  const writeEvidence = input?.write_evidence !== false;
44
45
  if (!writeEvidence)
45
46
  cmd.push("--no-write-evidence");
46
- const res = await runEngine("vibecoding-helper", cmd, { timeoutMs: 300_000 });
47
+ const res = await runPythonCli(cmd, { timeoutMs: 300_000 });
47
48
  if (res.code !== 0) {
48
- throw new Error(`zoekt-evidence failed: ${res.stderr || res.stdout || `exit_code=${res.code}`}`);
49
+ const classified = classifyPythonError(res.stderr ?? "", res.code, "패턴 증거 수집");
50
+ throw new Error(`${classified.issueCode}: ${classified.summary}`);
49
51
  }
50
52
  const parsed = safeJsonParse(res.stdout);
51
53
  if (!parsed.ok) {
package/build/tools.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { z } from "zod";
4
4
  import { safeJsonParse } from "./cli.js";
5
5
  import { parseSelectionValidationResult } from "./contracts.js";
6
- import { runEngine } from "./engine.js";
6
+ import { runEngine, runPythonCli } from "./engine.js";
7
7
  import { doctor as doctorImpl } from "./bootstrap/doctor.js";
8
8
  import { ToolErrorOutputSchema } from "./generated/tool_error_output.js";
9
9
  function toolText(obj) {
@@ -45,7 +45,9 @@ export function defineTools() {
45
45
  });
46
46
  async function vibecodeOneLoop(input) {
47
47
  try {
48
- const { code, stdout, stderr } = await runEngine("vibecoding-helper", ["one-loop", input.run_id, "--output", input.output], { timeoutMs: input.timeout_ms ?? 120_000 });
48
+ // [DEPRECATED] Use vibe_pm.inspect_code instead
49
+ // Changed from runEngine("vibecoding-helper") to runPythonCli for correct routing
50
+ const { code, stdout, stderr } = await runPythonCli(["one-loop", input.run_id, "--output", input.output], { timeoutMs: input.timeout_ms ?? 120_000 });
49
51
  const parsed = safeJsonParse(stdout);
50
52
  if (!parsed.ok) {
51
53
  return err("invalid_json", {
@@ -148,7 +150,9 @@ export function defineTools() {
148
150
  });
149
151
  async function vibecodeShowAskQueue(input) {
150
152
  try {
151
- const { code, stdout, stderr } = await runEngine("vibecoding-helper", ["show-ask-queue", input.run_id], { timeoutMs: input.timeout_ms ?? 60_000 });
153
+ // [DEPRECATED] Use vibe_pm.get_decision instead
154
+ // Changed from runEngine("vibecoding-helper") to runPythonCli for correct routing
155
+ const { code, stdout, stderr } = await runPythonCli(["show-ask-queue", input.run_id], { timeoutMs: input.timeout_ms ?? 60_000 });
152
156
  return toolText({
153
157
  status: code === 0 ? "OK" : "FAIL",
154
158
  exit_code: code,
@@ -168,7 +172,9 @@ export function defineTools() {
168
172
  });
169
173
  async function vibecodeShowDecisions(input) {
170
174
  try {
171
- const { code, stdout, stderr } = await runEngine("vibecoding-helper", ["show-decisions", input.run_id], { timeoutMs: input.timeout_ms ?? 60_000 });
175
+ // [DEPRECATED] Use vibe_pm.status instead
176
+ // Changed from runEngine("vibecoding-helper") to runPythonCli for correct routing
177
+ const { code, stdout, stderr } = await runPythonCli(["show-decisions", input.run_id], { timeoutMs: input.timeout_ms ?? 60_000 });
172
178
  return toolText({
173
179
  status: code === 0 ? "OK" : "FAIL",
174
180
  exit_code: code,
@@ -189,7 +195,9 @@ export function defineTools() {
189
195
  });
190
196
  async function vibecodeAnswer(input) {
191
197
  try {
192
- const { code, stdout, stderr } = await runEngine("vibecoding-helper", ["answer", input.run_id, "--text", input.text], { timeoutMs: input.timeout_ms ?? 120_000 });
198
+ // [DEPRECATED] Use vibe_pm.submit_decision instead
199
+ // Changed from runEngine("vibecoding-helper") to runPythonCli for correct routing
200
+ const { code, stdout, stderr } = await runPythonCli(["answer", input.run_id, "--text", input.text], { timeoutMs: input.timeout_ms ?? 120_000 });
193
201
  return toolText({
194
202
  status: code === 0 ? "OK" : "FAIL",
195
203
  exit_code: code,
@@ -3,14 +3,14 @@
3
3
  // 정책: 절대 실행을 막지 않는다 (모든 실패는 GO)
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { spawnSync } from "node:child_process";
7
6
  import readline from "node:readline";
7
+ import { invokeGitSync } from "./runtime/cli_invoker.js";
8
8
  function execGit(args, cwd) {
9
- const r = spawnSync("git", args, { cwd, encoding: "utf-8", timeout: 10000 });
9
+ const result = invokeGitSync(args, cwd, { timeoutMs: 10000 });
10
10
  return {
11
- status: r.status,
12
- stdout: r.stdout ?? "",
13
- stderr: r.stderr ?? "",
11
+ status: result.exitCode,
12
+ stdout: result.stdout,
13
+ stderr: result.stderr,
14
14
  };
15
15
  }
16
16
  function repoRootOrNull(cwd) {