@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,106 @@
1
+ // adapters/mcp-ts/src/engine.ts
2
+ // Engine execution using cached binaries (no PATH dependency)
3
+ import { ensureEngines } from "./bootstrap/installer.js";
4
+ import { runCmd } from "./cli.js";
5
+ import { TieredCache, createCacheKey } from "./cache/index.js";
6
+ let cached = null;
7
+ /**
8
+ * Engine result cache for read-only operations
9
+ * TTL: 30 seconds, max 50 entries
10
+ */
11
+ const engineResultCache = new TieredCache({
12
+ ttlMs: 30_000,
13
+ maxEntries: 50,
14
+ name: "engine-results",
15
+ });
16
+ /**
17
+ * Get engine context (lazy initialization)
18
+ * Ensures all engines are installed on first call
19
+ */
20
+ export async function getEngineCtx() {
21
+ if (cached)
22
+ return cached;
23
+ const bins = await ensureEngines();
24
+ cached = { bins };
25
+ return cached;
26
+ }
27
+ /**
28
+ * Run an engine command using cached binary path
29
+ * No PATH dependency - uses absolute path to cached binary
30
+ */
31
+ export async function runEngine(cmd, args, opts) {
32
+ const ctx = await getEngineCtx();
33
+ const binPath = ctx.bins[cmd];
34
+ return await runCmd(binPath, args, { timeoutMs: opts?.timeoutMs ?? 120_000 });
35
+ }
36
+ /**
37
+ * Commands that are safe to cache (read-only operations)
38
+ */
39
+ const CACHEABLE_COMMANDS = new Set([
40
+ "validate",
41
+ "show-ask-queue",
42
+ "status",
43
+ "get-decision",
44
+ "list-runs",
45
+ ]);
46
+ function extractSubcommand(args) {
47
+ for (let i = 0; i < args.length; i++) {
48
+ const a = args[i] ?? "";
49
+ if (a === "--root") {
50
+ i += 1; // skip root path
51
+ continue;
52
+ }
53
+ if (a.startsWith("-"))
54
+ continue;
55
+ return a;
56
+ }
57
+ return "";
58
+ }
59
+ /**
60
+ * Run an engine command with optional caching support
61
+ *
62
+ * @param cmd - Engine command to run
63
+ * @param args - Command arguments
64
+ * @param opts - Options including cache control
65
+ * @returns Engine result (may be from cache)
66
+ */
67
+ export async function runEngineWithCache(cmd, args, opts) {
68
+ // Determine if this command is cacheable
69
+ const subCommand = extractSubcommand(args);
70
+ const isCacheable = CACHEABLE_COMMANDS.has(subCommand) && !opts?.skipCache;
71
+ if (isCacheable) {
72
+ const cacheKey = createCacheKey(cmd, ...args);
73
+ const cachedResult = engineResultCache.get(cacheKey);
74
+ if (cachedResult) {
75
+ return cachedResult;
76
+ }
77
+ // Execute and cache the result
78
+ const result = await runEngine(cmd, args, opts);
79
+ // Only cache successful results
80
+ if (result.code === 0) {
81
+ engineResultCache.set(cacheKey, result);
82
+ }
83
+ return result;
84
+ }
85
+ // Non-cacheable command - run directly
86
+ return await runEngine(cmd, args, opts);
87
+ }
88
+ /**
89
+ * Invalidate engine cache entries
90
+ *
91
+ * @param pattern - Optional regex pattern to match cache keys
92
+ */
93
+ export function invalidateEngineCache(pattern) {
94
+ if (pattern) {
95
+ engineResultCache.invalidatePattern(pattern);
96
+ }
97
+ else {
98
+ engineResultCache.clear();
99
+ }
100
+ }
101
+ /**
102
+ * Get engine cache statistics
103
+ */
104
+ export function getEngineCacheStats() {
105
+ return engineResultCache.stats();
106
+ }
@@ -0,0 +1,171 @@
1
+ // adapters/mcp-ts/src/errors.ts
2
+ // Vibe PM error codes and McpError factory
3
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
4
+ // ============================================================
5
+ // Vibe-specific error codes (negative to avoid conflict with JSON-RPC)
6
+ // Reference: MCP protocol error codes range
7
+ // ============================================================
8
+ export const VibeErrorCode = {
9
+ // Engine errors (-32010 ~ -32019)
10
+ EngineNotFound: -32_010,
11
+ EngineTimeout: -32_011,
12
+ EngineCrash: -32_012,
13
+ // Project errors (-32020 ~ -32029)
14
+ ProjectNotFound: -32_020,
15
+ RunNotFound: -32_021,
16
+ BridgeNotFound: -32_022,
17
+ // Decision errors (-32030 ~ -32039)
18
+ DecisionNotFound: -32_030,
19
+ DecisionAlreadySubmitted: -32_031,
20
+ DecisionPending: -32_032,
21
+ // Validation errors (-32040 ~ -32049)
22
+ SchemaValidationFailed: -32_040,
23
+ OutputValidationFailed: -32_041,
24
+ // State errors (-32050 ~ -32059)
25
+ InvalidStateTransition: -32_050,
26
+ ConcurrentModification: -32_051,
27
+ // Security errors (-32060 ~ -32069)
28
+ SecurityValidationFailed: -32_060,
29
+ PathTraversal: -32_061,
30
+ InputTooLarge: -32_062,
31
+ DoNotTouchViolation: -32_063,
32
+ };
33
+ // ============================================================
34
+ // McpError factory functions
35
+ // ============================================================
36
+ /**
37
+ * Create a standardized VibeError wrapped in McpError
38
+ */
39
+ export function createVibeError(code, message, data) {
40
+ const category = getErrorCategory(code);
41
+ const errorData = {
42
+ vibeCode: code,
43
+ category,
44
+ ...data,
45
+ };
46
+ // Map to standard MCP error codes for protocol compatibility
47
+ const mcpCode = mapToMcpErrorCode(code);
48
+ return new McpError(mcpCode, `[${category}] ${message}`, errorData);
49
+ }
50
+ /**
51
+ * Determine error category from code
52
+ */
53
+ function getErrorCategory(code) {
54
+ if (code >= -32_019 && code <= -32_010)
55
+ return "ENGINE";
56
+ if (code >= -32_029 && code <= -32_020)
57
+ return "PROJECT";
58
+ if (code >= -32_039 && code <= -32_030)
59
+ return "DECISION";
60
+ if (code >= -32_049 && code <= -32_040)
61
+ return "VALIDATION";
62
+ if (code >= -32_059 && code <= -32_050)
63
+ return "STATE";
64
+ if (code >= -32_069 && code <= -32_060)
65
+ return "SECURITY";
66
+ return "UNKNOWN";
67
+ }
68
+ /**
69
+ * Map Vibe error codes to standard MCP error codes
70
+ */
71
+ function mapToMcpErrorCode(code) {
72
+ switch (code) {
73
+ case VibeErrorCode.EngineNotFound:
74
+ case VibeErrorCode.ProjectNotFound:
75
+ case VibeErrorCode.RunNotFound:
76
+ case VibeErrorCode.BridgeNotFound:
77
+ case VibeErrorCode.DecisionNotFound:
78
+ return ErrorCode.InvalidParams;
79
+ case VibeErrorCode.EngineTimeout:
80
+ return ErrorCode.InternalError;
81
+ case VibeErrorCode.EngineCrash:
82
+ return ErrorCode.InternalError;
83
+ case VibeErrorCode.DecisionAlreadySubmitted:
84
+ case VibeErrorCode.DecisionPending:
85
+ case VibeErrorCode.InvalidStateTransition:
86
+ case VibeErrorCode.ConcurrentModification:
87
+ return ErrorCode.InvalidRequest;
88
+ case VibeErrorCode.SchemaValidationFailed:
89
+ case VibeErrorCode.OutputValidationFailed:
90
+ return ErrorCode.InvalidParams;
91
+ case VibeErrorCode.SecurityValidationFailed:
92
+ case VibeErrorCode.PathTraversal:
93
+ case VibeErrorCode.InputTooLarge:
94
+ case VibeErrorCode.DoNotTouchViolation:
95
+ return ErrorCode.InvalidParams;
96
+ default:
97
+ return ErrorCode.InternalError;
98
+ }
99
+ }
100
+ // ============================================================
101
+ // Convenience error creators
102
+ // ============================================================
103
+ export function engineNotFoundError(engineName) {
104
+ return createVibeError(VibeErrorCode.EngineNotFound, `Engine "${engineName}" not found. Run vibe_pm.doctor to install.`, {
105
+ context: { engineName },
106
+ recovery: "vibe_pm.doctor 도구를 실행하여 엔진을 설치하세요.",
107
+ });
108
+ }
109
+ export function projectNotFoundError(projectId) {
110
+ return createVibeError(VibeErrorCode.ProjectNotFound, projectId
111
+ ? `Project "${projectId}" not found.`
112
+ : "No active project found in current directory.", {
113
+ context: { projectId },
114
+ recovery: "vibe_pm.briefing 도구로 프로젝트를 시작하세요.",
115
+ });
116
+ }
117
+ export function runNotFoundError(runId) {
118
+ return createVibeError(VibeErrorCode.RunNotFound, `Run "${runId}" not found.`, {
119
+ context: { runId },
120
+ recovery: "vibe_pm.status 도구로 현재 실행 상태를 확인하세요.",
121
+ });
122
+ }
123
+ export function decisionNotFoundError(decisionId) {
124
+ return createVibeError(VibeErrorCode.DecisionNotFound, `Decision "${decisionId}" not found.`, {
125
+ context: { decisionId },
126
+ recovery: "vibe_pm.get_decision 도구로 현재 결재 항목을 조회하세요.",
127
+ });
128
+ }
129
+ export function decisionPendingError(decisionIds) {
130
+ return createVibeError(VibeErrorCode.DecisionPending, `Cannot proceed: ${decisionIds.length} decision(s) pending.`, {
131
+ context: { decisionIds },
132
+ recovery: "vibe_pm.get_decision 으로 대기중인 결재를 확인하세요.",
133
+ });
134
+ }
135
+ export function bridgeNotFoundError(runId) {
136
+ return createVibeError(VibeErrorCode.BridgeNotFound, `Bridge file not found for run "${runId}".`, {
137
+ context: { runId },
138
+ recovery: "vibe_pm.create_work_order 도구로 작업 지시서를 생성하세요.",
139
+ });
140
+ }
141
+ export function validationError(message, zodErrors) {
142
+ return createVibeError(VibeErrorCode.SchemaValidationFailed, message, {
143
+ context: { zodErrors },
144
+ });
145
+ }
146
+ export function stateTransitionError(from, to, reason) {
147
+ return createVibeError(VibeErrorCode.InvalidStateTransition, `Cannot transition from "${from}" to "${to}": ${reason}`, {
148
+ context: { from, to, reason },
149
+ });
150
+ }
151
+ // ============================================================
152
+ // Security error creators
153
+ // ============================================================
154
+ export function pathTraversalError(path) {
155
+ return createVibeError(VibeErrorCode.PathTraversal, `Path traversal detected: "${path}"`, {
156
+ context: { path },
157
+ recovery: "Use paths relative to the project directory without '..' sequences",
158
+ });
159
+ }
160
+ export function inputTooLargeError(field, limit, actual) {
161
+ return createVibeError(VibeErrorCode.InputTooLarge, `Input too large: ${field} exceeds limit (${actual} > ${limit})`, {
162
+ context: { field, limit, actual },
163
+ recovery: "Reduce the size of the input",
164
+ });
165
+ }
166
+ export function doNotTouchError(path, pattern) {
167
+ return createVibeError(VibeErrorCode.DoNotTouchViolation, `Path "${path}" matches do_not_touch pattern "${pattern}"`, {
168
+ context: { path, pattern },
169
+ recovery: "This path is protected and cannot be modified. Choose a different target.",
170
+ });
171
+ }
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const ActivateInputSchema = z.object({ "license_key": z.string().min(10).describe("Gumroad 라이선스 키(UUID 등). 로그/리포트에 남기지 마세요."), "force": z.boolean().describe("기존 토큰 캐시를 무시하고 새로 활성화합니다.").default(false), "app_version": z.string().min(1).describe("Auth 교환 요청에 포함할 app_version(선택). 기본은 MCP 패키지 버전입니다.").optional() }).strict().describe("SSOT schema for vibe_pm.activate MCP tool input");
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ export const ActivateOutputSchema = z.object({ "status": z.enum(["OK", "OFFLINE", "ERROR"]), "summary": z.string().min(1), "token_file": z.string().min(1).describe("로컬 토큰 캐시 파일 경로(토큰 내용은 출력하지 않음)"), "offline_mode": z.boolean(), "entitlements": z.any().superRefine((x, ctx) => {
3
+ const schemas = [z.object({ "deep_advisory": z.boolean(), "auto_fix_plus": z.boolean(), "local_memory_pro_tools": z.boolean(), "premium_embedding": z.boolean(), "github_gate": z.boolean(), "private_repo": z.boolean(), "deep_advisory_pr_comment": z.boolean() }).strict(), z.null()];
4
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
5
+ if (schemas.length - errors.length !== 1) {
6
+ ctx.addIssue({
7
+ path: ctx.path,
8
+ code: "invalid_union",
9
+ unionErrors: errors,
10
+ message: "Invalid input: Should pass single schema",
11
+ });
12
+ }
13
+ }), "policy": z.any().superRefine((x, ctx) => {
14
+ const schemas = [z.object({ "max_runs_per_day": z.number().int().gte(0), "rate_limit_deep_advisory_per_minute": z.number().int().gte(0) }).strict(), z.null()];
15
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
16
+ if (schemas.length - errors.length !== 1) {
17
+ ctx.addIssue({
18
+ path: ctx.path,
19
+ code: "invalid_union",
20
+ unionErrors: errors,
21
+ message: "Invalid input: Should pass single schema",
22
+ });
23
+ }
24
+ }), "subject_id": z.any().superRefine((x, ctx) => {
25
+ const schemas = [z.string().min(1), z.null()];
26
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
27
+ if (schemas.length - errors.length !== 1) {
28
+ ctx.addIssue({
29
+ path: ctx.path,
30
+ code: "invalid_union",
31
+ unionErrors: errors,
32
+ message: "Invalid input: Should pass single schema",
33
+ });
34
+ }
35
+ }), "expires_at": z.any().superRefine((x, ctx) => {
36
+ const schemas = [z.number().int().gte(0).describe("JWT exp(Unix seconds)"), z.null()];
37
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
38
+ if (schemas.length - errors.length !== 1) {
39
+ ctx.addIssue({
40
+ path: ctx.path,
41
+ code: "invalid_union",
42
+ unionErrors: errors,
43
+ message: "Invalid input: Should pass single schema",
44
+ });
45
+ }
46
+ }), "issues": z.array(z.string()), "next_action": z.any().superRefine((x, ctx) => {
47
+ const schemas = [z.object({ "tool": z.enum(["vibe_pm.status", "vibe_pm.advisory_review", "vibe_pm.inspect_code", "vibe_pm.activate", "vibe_pm.doctor"]), "reason": z.string().min(1) }).strict(), z.null()];
48
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
49
+ if (schemas.length - errors.length !== 1) {
50
+ ctx.addIssue({
51
+ path: ctx.path,
52
+ code: "invalid_union",
53
+ unionErrors: errors,
54
+ message: "Invalid input: Should pass single schema",
55
+ });
56
+ }
57
+ }) }).strict().describe("SSOT schema for vibe_pm.activate MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const AdvisoryReviewInputSchema = z.object({ "project_id": z.string().min(1).optional(), "run_id": z.string().min(1).optional(), "mode": z.enum(["triage", "quick", "thorough"]).describe("triage=cheap routing only; quick=light review; thorough=deep review").default("triage"), "trigger": z.enum(["on_demand", "pre_finalize", "pr_event"]).describe("Execution trigger context").default("on_demand"), "budget": z.enum(["low", "medium", "high"]).describe("Latency/token budget hint for routing and depth").default("low"), "changed_paths": z.array(z.string().min(1)).describe("Changed files/paths (preferred over target_paths for routing).").optional(), "target_paths": z.array(z.string().min(1)).describe("Optional. Target paths to analyze if changed_paths not available.").optional(), "diff_context": z.string().min(1).describe("Optional. PR diff summary or patch excerpt. Best-effort.").optional(), "base_sha": z.string().min(7).describe("Optional. Base commit SHA (for caching).").optional(), "head_sha": z.string().min(7).describe("Optional. Head commit SHA (for caching).").optional(), "focus": z.array(z.enum(["BUSINESS_FIT", "ARCHITECTURE", "ALGO_REFACTOR"])).describe("Optional manual focus override. If omitted, router selects focus.").optional(), "product_intent_refs": z.array(z.string().min(1)).describe("Optional. Paths to SSOT/product docs defining business intent.").optional() }).strict().describe("SSOT schema for vibe_pm.advisory_review MCP tool input");
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export const AdvisoryReviewOutputSchema = z.any().superRefine((x, ctx) => {
3
+ const schemas = [z.object({ "kind": z.literal("triage"), "project_id": z.string().min(1), "triage": z.object({ "needs_deep_review": z.boolean(), "reason_summary": z.string().min(1).describe("One-line explanation why deep review is needed or skipped."), "risk_flags": z.array(z.enum(["BUSINESS_POLICY_RISK", "ARCH_BOUNDARY_RISK", "ALGO_COMPLEXITY_RISK", "SECURITY_RISK", "DATA_LOSS_RISK", "NONE"])).min(1) }).strict(), "routing": z.object({ "selected_focus": z.array(z.enum(["BUSINESS_FIT", "ARCHITECTURE", "ALGO_REFACTOR"])).min(0).max(3), "recommended_mode": z.enum(["skip", "quick", "thorough"]).describe("skip means no deep review recommended."), "total_score": z.number().gte(0), "top_contributors": z.array(z.object({ "path": z.string().min(1), "weight": z.number(), "matched_rule": z.string().min(1) }).strict()).min(0).max(10).describe("Explain which paths caused the score to rise.") }).strict(), "cache": z.object({ "cache_key": z.string().min(1), "hit": z.boolean() }).strict(), "next_action": z.any().superRefine((x, ctx) => {
4
+ const schemas = [z.object({ "action_type": z.literal("RUN_ADVISORY_REVIEW"), "tool": z.literal("vibe_pm.advisory_review"), "reason": z.string().min(1), "recommended_input_override": z.object({ "mode": z.enum(["quick", "thorough"]).optional(), "budget": z.enum(["low", "medium", "high"]).optional(), "focus": z.array(z.enum(["BUSINESS_FIT", "ARCHITECTURE", "ALGO_REFACTOR"])).min(1).max(3).optional() }).strict().describe("Optional router suggestions for the next call.").optional() }).strict(), z.object({ "action_type": z.literal("SKIP"), "message": z.string().min(1) }).strict()];
5
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
6
+ if (schemas.length - errors.length !== 1) {
7
+ ctx.addIssue({
8
+ path: ctx.path,
9
+ code: "invalid_union",
10
+ unionErrors: errors,
11
+ message: "Invalid input: Should pass single schema",
12
+ });
13
+ }
14
+ }), "message_template_id": z.enum(["TRIAGE-SKIP-01", "TRIAGE-RUN-01", "TRIAGE-RUN-02"]) }).strict(), z.object({ "kind": z.literal("review"), "project_id": z.string().min(1), "overall_signal": z.enum(["ADVICE", "WARN", "SOFT_BLOCK"]), "summary": z.object({ "one_line": z.string().min(1), "risk_notes": z.array(z.string().min(1)) }).strict(), "findings": z.array(z.object({ "category": z.enum(["BUSINESS_FIT", "ARCHITECTURE", "ALGO_REFACTOR", "DX", "PERFORMANCE_RISK"]), "impact": z.enum(["HIGH", "MEDIUM", "LOW"]), "title": z.string().min(1), "why_it_matters": z.string().min(1), "evidence": z.object({ "file_path": z.string().min(1).optional(), "line_range": z.array(z.number().int().gte(1)).min(2).max(2).optional(), "related_decision_ids": z.array(z.string().min(1)).optional() }).strict().optional(), "recommendation": z.string().min(1), "options": z.array(z.object({ "label": z.string().min(1), "tradeoffs": z.array(z.string().min(1)).min(1), "when_to_choose": z.string().min(1) }).strict()).min(1).max(3) }).strict()), "report_markdown": z.string().min(1).describe("Optional: pre-rendered markdown report for display").optional(), "next_action": z.any().superRefine((x, ctx) => {
15
+ const schemas = [z.object({ "action_type": z.literal("COPY_PASTE_TO_AGENT"), "label": z.string().min(1), "prompt_block": z.string().min(1) }).strict(), z.object({ "action_type": z.literal("ASK_DECISION"), "tool": z.literal("vibe_pm.get_decision"), "reason": z.string().min(1) }).strict(), z.object({ "action_type": z.literal("CONTINUE"), "tool": z.literal("vibe_pm.create_work_order"), "reason": z.string().min(1) }).strict()];
16
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
17
+ if (schemas.length - errors.length !== 1) {
18
+ ctx.addIssue({
19
+ path: ctx.path,
20
+ code: "invalid_union",
21
+ unionErrors: errors,
22
+ message: "Invalid input: Should pass single schema",
23
+ });
24
+ }
25
+ }), "message_template_id": z.enum(["ADV-01", "ADV-02", "WARN-01", "WARN-02", "SOFTBLOCK-01"]) }).strict()];
26
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
27
+ if (schemas.length - errors.length !== 1) {
28
+ ctx.addIssue({
29
+ path: ctx.path,
30
+ code: "invalid_union",
31
+ unionErrors: errors,
32
+ message: "Invalid input: Should pass single schema",
33
+ });
34
+ }
35
+ }).describe("SSOT schema for vibe_pm.advisory_review MCP tool output (triage or review)");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const AuthTokenFileSchema = z.object({ "token": z.string().min(1), "expiresAt": z.number().int().gte(0).describe("JWT exp(Unix seconds)"), "entitlements": z.object({ "deep_advisory": z.boolean(), "auto_fix_plus": z.boolean(), "local_memory_pro_tools": z.boolean(), "premium_embedding": z.boolean(), "github_gate": z.boolean(), "private_repo": z.boolean(), "deep_advisory_pr_comment": z.boolean() }).strict(), "policy": z.object({ "max_runs_per_day": z.number().int().gte(0), "rate_limit_deep_advisory_per_minute": z.number().int().gte(0) }).strict(), "subjectId": z.string().min(1), "cachedAt": z.number().int().gte(0) }).strict().describe("SSOT schema for local cached auth token file (~/.vibe-pm/auth-token.json)");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const BriefingInputSchema = z.object({ "project_brief": z.string().min(1).describe("사용자의 프로젝트 아이디어 (자유 형식)"), "mode": z.enum(["mvp_fast", "balanced", "quality_first"]).describe("개발 모드: mvp_fast(속도 우선), balanced(균형), quality_first(품질 우선)").default("balanced"), "project_id": z.string().min(1).describe("프로젝트 ID (생략 시 폴더명에서 자동 생성)").optional() }).strict().describe("SSOT schema for vibe_pm.briefing MCP tool input");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const BriefingOutputSchema = z.object({ "project_id": z.string().min(1), "run_id": z.string().min(1), "pm_summary": z.object({ "goal": z.string().min(1), "target_user": z.string().min(1), "first_milestone": z.string().min(1), "top_risk": z.string().min(1) }).strict(), "next_action": z.object({ "tool": z.literal("vibe_pm.get_decision"), "reason": z.string().min(1) }).strict() }).strict().describe("SSOT schema for vibe_pm.briefing MCP tool output");
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ export const ClinicBridgeFileSchema = z.any().superRefine((x, ctx) => {
3
+ const schemas = [z.object({ "bridge_version": z.literal(1), "producer": z.string().min(1), "consumer": z.string().min(1), "run": z.object({ "run_id": z.string().min(1), "run_dir": z.string().min(1), "created_at": z.string().min(1).optional() }).strict(), "artifacts": z.record(z.any()).optional(), "intent": z.record(z.any()).optional(), "scope": z.record(z.any()).optional(), "decision_guard": z.object({ "read_only_paths": z.array(z.string()), "allow_paths": z.array(z.string()), "deny_paths": z.array(z.string()), "change_policy": z.object({ "allow": z.array(z.string()).optional(), "deny": z.array(z.string()).optional() }).strict().optional(), "escalation_triggers": z.array(z.object({ "name": z.string().min(1), "when": z.object({ "any_file_matches": z.array(z.string()).optional(), "diff_contains_patterns": z.array(z.string()).optional() }).strict().optional(), "action": z.string().min(1), "message": z.string().min(1) }).strict()).optional() }).strict(), "verification": z.object({ "required": z.array(z.object({ "id": z.string().min(1), "cmd": z.string().min(1) }).strict()), "optional": z.array(z.object({ "id": z.string().min(1), "cmd": z.string().min(1) }).strict()) }).strict(), "feedback_to_spec_high": z.record(z.any()).optional(), "diagnostics": z.record(z.any()).optional() }).strict(), z.object({ "project": z.string().min(1), "mode": z.enum(["mvp_fast", "balanced", "quality_first"]), "headline": z.string().min(1), "scope": z.object({ "include": z.array(z.string()), "exclude": z.array(z.string()) }).strict(), "do_not_touch": z.array(z.string()), "verify_criteria": z.array(z.string()) }).strict()];
4
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
5
+ if (schemas.length - errors.length !== 1) {
6
+ ctx.addIssue({
7
+ path: ctx.path,
8
+ code: "invalid_union",
9
+ unionErrors: errors,
10
+ message: "Invalid input: Should pass single schema",
11
+ });
12
+ }
13
+ }).describe("SSOT schema for clinic_bridge.(yaml|json) parsed object (Spec-High and legacy variants)");
@@ -0,0 +1,5 @@
1
+ // Auto-generated from schemas/contracts.version.json + schemas/contracts.lock.json
2
+ // DO NOT EDIT MANUALLY - run scripts/generate-contracts.sh
3
+ export const CONTRACTS_VERSION = "1.8.1";
4
+ export const CONTRACTS_BUNDLE_SHA256 = "c3fa79c3342e45c7f4e17af6ecb852350d84a684c2078c756ae24d6b05643b89";
5
+ export const CONTRACTS_SCHEMA_COUNT = 87;
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const CreateWorkOrderInputSchema = z.object({ "project_id": z.string().min(1).describe("프로젝트 ID (생략 시 현재 폴더 사용)").optional(), "additional_instructions": z.string().min(1).describe("추가 지시사항 (선택사항)").optional() }).strict().describe("SSOT schema for vibe_pm.create_work_order MCP tool input");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const CreateWorkOrderOutputSchema = z.object({ "project_id": z.string().min(1), "run_id": z.string().min(1), "work_order": z.object({ "headline": z.string().min(1), "scope": z.object({ "include": z.array(z.string()), "exclude": z.array(z.string()) }).strict(), "do_not_touch": z.array(z.string()), "verify_criteria": z.array(z.string()), "paste_to_agent": z.string().min(1) }).strict(), "paths": z.object({ "bridge_path": z.string().min(1), "intent_dir": z.string().min(1).optional() }).strict(), "modules": z.object({ "research": z.object({ "version": z.literal("v1"), "fingerprint": z.string().min(1), "path": z.string().min(1) }).strict(), "skills": z.object({ "version": z.literal("v1"), "fingerprint": z.string().min(1), "path": z.string().min(1) }).strict(), "planning": z.object({ "version": z.literal("v1"), "fingerprint": z.string().min(1), "path": z.string().min(1) }).strict() }).strict(), "next_action": z.object({ "tool": z.literal("vibe_pm.inspect_code"), "reason": z.string().min(1), "when": z.literal("after_implementation") }).strict() }).strict().describe("SSOT schema for vibe_pm.create_work_order MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const CurrentWorkOrderFileSchema = z.object({ "run_id": z.string().min(1), "created_at": z.string().datetime({ offset: true }), "topic": z.string().min(1).optional(), "scope": z.object({ "include": z.array(z.string().min(1)).default([]), "exclude": z.array(z.string().min(1)).default([]) }).strict().optional(), "do_not_touch": z.array(z.string().min(1)).default([]), "verify_criteria": z.array(z.string().min(1)).default([]) }).strict().describe("SSOT schema for repo-local Work Order file used by Local Mode guard (.vibe/state/current_work_order.json).");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const DoctorInputSchema = z.object({ "auto_fix": z.boolean().describe("자동으로 문제를 수정할지 여부 (기본: true)").default(true) }).strict().describe("SSOT schema for vibe_pm.doctor MCP tool input");
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ export const DoctorOutputSchema = z.object({ "status": z.enum(["OK", "FIXED", "NEEDS_ATTENTION", "ERROR"]), "summary": z.string().min(1), "contracts": z.object({ "version": z.string().min(1), "bundle_sha256": z.string().min(1), "schema_count": z.number().int().gte(0) }).strict().optional(), "engines": z.array(z.object({ "name": z.string().min(1), "status": z.enum(["정상", "업데이트 필요", "설치 필요", "손상됨"]), "version": z.string().min(1), "current_version": z.union([z.string(), z.null()]) }).strict()), "actions_taken": z.array(z.string()).optional(), "local_memory": z.any().superRefine((x, ctx) => {
3
+ const schemas = [z.object({ "project_id": z.string().min(1), "status": z.enum(["READY", "NEEDS_SYNC", "OFFLINE_NO_INDEX", "ERROR"]), "summary": z.string().min(1), "docs_root": z.string().min(1), "persist_dir": z.string().min(1), "collection": z.string().min(1), "stats": z.object({ "document_count": z.number().int().gte(0), "chunk_count": z.number().int().gte(0), "last_sync_at": z.union([z.string(), z.null()]).optional() }).strict(), "embedding": z.object({ "backend": z.string().min(1), "model": z.union([z.string(), z.null()]).optional(), "ready": z.boolean() }).strict().optional(), "offline_mode": z.boolean(), "issues": z.array(z.string()), "next_action": z.any().superRefine((x, ctx) => {
4
+ const schemas = [z.object({ "tool": z.enum(["vibe_pm.memory_sync", "vibe_pm.doctor"]), "reason": z.string().min(1) }).strict(), z.null()];
5
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
6
+ if (schemas.length - errors.length !== 1) {
7
+ ctx.addIssue({
8
+ path: ctx.path,
9
+ code: "invalid_union",
10
+ unionErrors: errors,
11
+ message: "Invalid input: Should pass single schema",
12
+ });
13
+ }
14
+ }) }).strict(), z.null()];
15
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
16
+ if (schemas.length - errors.length !== 1) {
17
+ ctx.addIssue({
18
+ path: ctx.path,
19
+ code: "invalid_union",
20
+ unionErrors: errors,
21
+ message: "Invalid input: Should pass single schema",
22
+ });
23
+ }
24
+ }).optional(), "next_action": z.object({ "type": z.enum(["NONE", "MANUAL_FIX", "CONTACT_SUPPORT"]), "message": z.string().min(1) }).strict() }).strict().describe("SSOT schema for vibe_pm.doctor MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const ExecutionResultSchema = z.object({ "task_id": z.string().min(1), "run_id": z.string().min(1), "queue_state": z.enum(["QUEUED", "RUNNING", "DONE", "FAILED", "DLQ"]), "status": z.enum(["SUCCESS", "RETRYABLE_FAIL", "FATAL_FAIL", "SKIPPED_DUPLICATE"]), "summary": z.string().min(1), "attempt": z.object({ "n": z.number().int().gte(1).lte(1000), "max": z.number().int().gte(1).lte(1000) }).strict(), "artifacts_written": z.array(z.object({ "type": z.string().min(1), "path": z.string().min(1) }).strict()).min(0).max(100), "violations": z.array(z.object({ "rule_id": z.string().min(1), "message": z.string().min(1) }).strict()).min(0).max(50), "metrics": z.object({ "started_at": z.string().min(1), "ended_at": z.string().min(1), "duration_ms": z.number().int().gte(0).lte(604800000) }).strict(), "next": z.object({ "action": z.enum(["HANDOFF_TO_CLINIC", "RETRY_LATER", "STOP"]), "reason": z.string().min(1) }).strict() }).strict().describe("SSOT schema for Execution Engine result output (v2.x).");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const ExecutionTaskSchema = z.object({ "task_id": z.string().min(1), "trigger": z.object({ "type": z.enum(["webhook", "cron", "inbox"]), "source_id": z.string().min(1) }).strict(), "plugin": z.object({ "name": z.string().min(1), "version": z.string().min(1).optional() }).strict(), "idempotency_key": z.string().min(1), "priority": z.enum(["low", "normal", "high"]), "instruction": z.string().min(1), "inputs": z.array(z.object({ "type": z.enum(["file", "text", "json"]), "path": z.string().min(1), "mime": z.string().min(1).optional() }).strict()).min(0).max(50), "destination": z.object({ "type": z.enum(["filesystem", "notion", "supabase", "none"]), "ref": z.string().min(1).optional() }).strict(), "safety": z.object({ "allow_paths": z.array(z.string().min(1)).min(1).max(50), "read_only_paths": z.array(z.string().min(1)).min(0).max(50), "deny_paths": z.array(z.string().min(1)).min(0).max(50) }).strict(), "run": z.object({ "base_dir": z.string().min(1), "run_id": z.string().min(1).optional() }).strict() }).strict().describe("SSOT schema for Execution Engine task input (v2.x).");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const ExportOutputInputSchema = z.object({ "project_id": z.string().min(1).optional(), "run_id": z.string().min(1).describe("대상 작업의 식별자(선택). 생략 시 최근 작업 기준").optional(), "target": z.enum(["docs_bundle", "api_openapi", "cli_scaffold", "web_template_repo"]).describe("내보내기 결과물 타입"), "output_dir": z.string().min(1).describe("결과물이 생성될 폴더(repo 기준 상대 경로)").optional(), "dry_run": z.boolean().describe("계획만 생성하고 파일은 만들지 않음").default(false), "cli_language": z.enum(["python", "node"]).describe("cli_scaffold용 언어(선택)").default("python"), "template_pin": z.object({ "repo": z.string().min(1).describe("Template repository (git URL or local path)"), "ref": z.string().min(1).describe("Pinned template ref (commit/tag)") }).strict().describe("web_template_repo용 템플릿 pin 정보").optional() }).strict().describe("SSOT schema for vibe_pm.export_output MCP tool input");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const ExportOutputOutputSchema = z.object({ "success": z.boolean(), "project_id": z.string().min(1), "run_id": z.string().min(1), "target": z.string().min(1), "output_dir": z.string().min(1), "dry_run": z.boolean(), "paths": z.object({ "feature_output_spec_path": z.string().min(1), "export_plan_path": z.string().min(1), "export_artifacts_path": z.string().min(1).optional() }).strict(), "created_paths": z.array(z.string().min(1)), "warnings": z.array(z.string()), "next_action": z.object({ "tool": z.literal("vibe_pm.status"), "reason": z.string().min(1) }).strict() }).strict().describe("SSOT schema for vibe_pm.export_output MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const FinalizeWorkInputSchema = z.object({ "task_summary": z.string().min(1).describe("비개발자가 읽을 수 있는 작업 요약 (DEV_LOG용)"), "spec_changes": z.array(z.object({ "section": z.string().describe("갱신할 스펙 섹션명"), "content": z.string().describe("갱신될 마크다운 내용"), "action": z.enum(["REPLACE", "APPEND"]).default("REPLACE") }).strict()).describe("스펙 변경 (없으면 생략)").optional(), "completed_plan_path": z.string().describe("Path to the completed plan file in 'docs/planning/' to be archived").optional(), "git_commit": z.object({ "type": z.enum(["feat", "fix", "docs", "style", "refactor", "test", "chore"]), "scope": z.string().optional(), "subject": z.string().describe("커밋 메시지 제목 (50자 이내)"), "body": z.string().optional(), "footer": z.string().optional() }).strict() }).strict().describe("Input schema for vibe_pm.finalize_work tool");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const FinalizeWorkOutputSchema = z.object({ "success": z.boolean(), "updated_files": z.array(z.string()), "commit_hash": z.string(), "pushed_to_remote": z.boolean(), "remote_url": z.string().optional(), "warning": z.string().optional(), "next_action": z.object({ "tool": z.literal("vibe_pm.status"), "reason": z.string().min(1) }).strict() }).strict().describe("SSOT schema for vibe_pm.finalize_work MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const GateInputSchema = z.object({ "work_order": z.object({ "intent": z.string().min(10).describe("작업 의도 설명 (최소 10자)"), "scope": z.object({ "include": z.array(z.string()).min(1).describe("포함할 경로 패턴 (glob)"), "exclude": z.array(z.string()).describe("제외할 경로 패턴 (glob)").default([]) }).strict().describe("작업 범위 정의"), "tool_style": z.enum(["CRUD", "QUERY", "EXEC"]).describe("도구 스타일: CRUD(상태변경), QUERY(조회), EXEC(실행)"), "limits": z.object({ "max_depth": z.number().int().gte(1).lte(100).optional(), "max_files": z.number().int().gte(1).lte(10000).optional(), "max_cost": z.number().gte(0).lte(100).optional(), "max_tokens": z.number().int().gte(1).lte(1000000).optional(), "max_seconds": z.number().int().gte(1).lte(3600).optional() }).strict().describe("리소스 제한(옵션). WorkOrderV1의 조건부 요구사항은 Gate에서 별도 검증한다.").optional(), "idempotency_key": z.string().regex(new RegExp("^[a-zA-Z0-9_-]{8,64}$")).describe("멱등성 키 (EXEC 스타일 권장)").optional(), "metadata": z.object({ "requester": z.string().optional(), "project_id": z.string().optional(), "correlation_id": z.string().optional() }).catchall(z.any()).describe("추가 메타데이터").optional() }).strict(), "options": z.object({ "fail_fast": z.boolean().default(true), "semgrep": z.boolean().default(false), "runtime": z.boolean().default(true) }).strict().describe("Per-run gate overrides (optional).").optional() }).strict().describe("SSOT schema for vibe_pm.gate input. Wraps a WorkOrderV1 plus optional per-run gate overrides.");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const GateOutputSchema = z.object({ "verdict": z.enum(["ALLOW", "BLOCK"]).describe("최종 판정: ALLOW(실행 허용), BLOCK(실행 금지)"), "violations": z.array(z.object({ "rule_id": z.string().regex(new RegExp("^SDG-[0-9]{3}$")).describe("규칙 ID (예: SDG-001)"), "level": z.enum(["BLOCK", "WARN", "INFO"]).describe("심각도: BLOCK(차단), WARN(경고), INFO(정보)"), "message": z.string().min(10).describe("위반 내용 설명"), "remediation": z.string().describe("해결 방법 안내").optional(), "location": z.object({ "file": z.string().optional(), "line": z.number().int().gte(1).optional(), "column": z.number().int().gte(1).optional() }).describe("위반 위치 (선택)").optional() }).strict()).describe("위반 항목 목록"), "metadata": z.object({ "gate_version": z.string().regex(new RegExp("^[0-9]+\\.[0-9]+\\.[0-9]+$")).describe("Gate 버전 (semver)"), "checked_at": z.string().datetime({ offset: true }).describe("검사 시각 (ISO 8601)"), "duration_ms": z.number().int().gte(0).describe("검사 소요 시간 (밀리초)").optional(), "gates_run": z.array(z.enum(["schema", "path", "semgrep", "runtime"])).describe("실행된 Gate 목록").optional(), "work_order_hash": z.string().describe("입력 WorkOrder의 SHA256 해시").optional() }).strict().describe("검사 메타데이터"), "summary": z.object({ "total_violations": z.number().int().gte(0).optional(), "block_count": z.number().int().gte(0).optional(), "warn_count": z.number().int().gte(0).optional(), "info_count": z.number().int().gte(0).optional() }).strict().describe("요약 통계").optional() }).strict().describe("SSOT schema for vibe_pm.gate output. Same shape as GateResultV1.");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const GateResultV1Schema = z.object({ "verdict": z.enum(["ALLOW", "BLOCK"]).describe("최종 판정: ALLOW(실행 허용), BLOCK(실행 금지)"), "violations": z.array(z.object({ "rule_id": z.string().regex(new RegExp("^SDG-[0-9]{3}$")).describe("규칙 ID (예: SDG-001)"), "level": z.enum(["BLOCK", "WARN", "INFO"]).describe("심각도: BLOCK(차단), WARN(경고), INFO(정보)"), "message": z.string().min(10).describe("위반 내용 설명"), "remediation": z.string().describe("해결 방법 안내").optional(), "location": z.object({ "file": z.string().optional(), "line": z.number().int().gte(1).optional(), "column": z.number().int().gte(1).optional() }).describe("위반 위치 (선택)").optional() }).strict()).describe("위반 항목 목록"), "metadata": z.object({ "gate_version": z.string().regex(new RegExp("^[0-9]+\\.[0-9]+\\.[0-9]+$")).describe("Gate 버전 (semver)"), "checked_at": z.string().datetime({ offset: true }).describe("검사 시각 (ISO 8601)"), "duration_ms": z.number().int().gte(0).describe("검사 소요 시간 (밀리초)").optional(), "gates_run": z.array(z.enum(["schema", "path", "semgrep", "runtime"])).describe("실행된 Gate 목록").optional(), "work_order_hash": z.string().describe("입력 WorkOrder의 SHA256 해시").optional() }).strict().describe("검사 메타데이터"), "summary": z.object({ "total_violations": z.number().int().gte(0).optional(), "block_count": z.number().int().gte(0).optional(), "warn_count": z.number().int().gte(0).optional(), "info_count": z.number().int().gte(0).optional() }).strict().describe("요약 통계").optional() }).strict().describe("Gate 검사 결과 (실행 허가서). ALLOW면 실행, BLOCK이면 실행 금지.");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const GetDecisionInputSchema = z.object({ "project_id": z.string().min(1).describe("프로젝트 ID (생략 시 현재 폴더 사용)").optional(), "max_items": z.number().int().gte(1).describe("반환할 결재 항목 최대 수").default(2) }).strict().describe("SSOT schema for vibe_pm.get_decision MCP tool input");
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ export const GetDecisionOutputSchema = z.object({ "project_id": z.string().min(1), "decision_requests": z.array(z.object({ "decision_id": z.string().min(1), "title": z.string().min(1), "context": z.string(), "choices": z.array(z.object({ "key": z.enum(["A", "B", "C", "U"]), "label": z.string().min(1), "description": z.string().optional() }).strict()) }).strict()), "next_action": z.any().superRefine((x, ctx) => {
3
+ const schemas = [z.object({ "tool": z.literal("vibe_pm.submit_decision"), "reason": z.string().min(1) }).strict(), z.null()];
4
+ const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []);
5
+ if (schemas.length - errors.length !== 1) {
6
+ ctx.addIssue({
7
+ path: ctx.path,
8
+ code: "invalid_union",
9
+ unionErrors: errors,
10
+ message: "Invalid input: Should pass single schema",
11
+ });
12
+ }
13
+ }) }).strict().describe("SSOT schema for vibe_pm.get_decision MCP tool output");
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const HandoffToClinicSchema = z.object({ "run_id": z.string().min(1), "execution_result_path": z.string().min(1), "requested_checks": z.array(z.literal("selection-validate")).min(1).max(10) }).strict().describe("SSOT schema for Execution Engine file-based handoff to Code Clinic (v2.x).");