@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,550 @@
|
|
|
1
|
+
// adapters/mcp-ts/src/tools/vibe_pm/scaffold.ts
|
|
2
|
+
// vibe_pm.scaffold - Vibe Standard Directory Structure (Vibe-SDS) generator
|
|
3
|
+
// Creates standardized project structure for AI-friendly development
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
const ZONE_COMMENTS = {
|
|
7
|
+
BLACK: "[BLACK ZONE] AI 접근 금지 - 시스템 전용",
|
|
8
|
+
RED: "[RED ZONE] AI 수정 금지 - 설정 파일",
|
|
9
|
+
GREEN: "[GREEN ZONE] AI 작업 구역",
|
|
10
|
+
YELLOW: "[YELLOW ZONE] AI 수정 가능 - 주의 필요",
|
|
11
|
+
};
|
|
12
|
+
// ============================================================
|
|
13
|
+
// AI Context & Rules Templates
|
|
14
|
+
// ============================================================
|
|
15
|
+
const CURSORRULES_CONTENT = `# Vibe PM Enforced Rules (DO NOT DELETE)
|
|
16
|
+
# This file ensures AI agents follow Vibe PM protocol in this project.
|
|
17
|
+
|
|
18
|
+
## IDENTITY
|
|
19
|
+
You are a Vibe PM Worker. You are NOT an autonomous coding agent.
|
|
20
|
+
You operate under the strict supervision of Vibe PM.
|
|
21
|
+
|
|
22
|
+
## PRIME DIRECTIVES
|
|
23
|
+
1. **NO TICKET, NO WORK**: You cannot modify code without an active "Work Order".
|
|
24
|
+
- If user asks for code changes, run \`vibe_pm.create_work_order\` first.
|
|
25
|
+
- Exception: Minor typo fixes or formatting (still report via \`vibe_pm.status\`).
|
|
26
|
+
|
|
27
|
+
2. **CONTEXT AWARENESS**: At the start of every session, run \`vibe_pm.status\` or \`vibe_pm.briefing\` to understand the current phase.
|
|
28
|
+
|
|
29
|
+
3. **SAFETY ZONES (Vibe-SDS)**:
|
|
30
|
+
- ✅ WRITE: \`src/\`, \`tests/\`
|
|
31
|
+
- ⚠️ READ-ONLY: \`docs/\`, \`AI_ENTRYPOINT.md\`
|
|
32
|
+
- ⛔ FORBIDDEN: \`config/\`, \`.vibe/\`, \`.env\`
|
|
33
|
+
|
|
34
|
+
## TOOL USAGE
|
|
35
|
+
- Use \`vibe_pm.get_decision\` when ambiguity exists (A/B/C choices).
|
|
36
|
+
- Use \`vibe_pm.inspect_code\` after EVERY implementation step.
|
|
37
|
+
- Use \`vibe_pm.repair_plan\` when inspection fails.
|
|
38
|
+
|
|
39
|
+
## COMMUNICATION
|
|
40
|
+
- Explain decisions in simple Korean (한국어) for non-technical founders.
|
|
41
|
+
- Always confirm before making significant changes.
|
|
42
|
+
- Reference \`AI_ENTRYPOINT.md\` for project-specific context.
|
|
43
|
+
|
|
44
|
+
## CLEAN DESK POLICY (DOCUMENTATION)
|
|
45
|
+
1. **START**: Read requirements from \`docs/planning/\`.
|
|
46
|
+
2. **UPDATE**: As you implement, verify against the checklist in the plan file.
|
|
47
|
+
3. **FINISH**: When running \`vibe_pm.finalize_work\`, ALWAYS provide \`completed_plan_path\`.
|
|
48
|
+
- The system will automatically move it to \`docs/archive/\`.
|
|
49
|
+
- Do NOT delete the file yourself. Let the tool handle it.
|
|
50
|
+
|
|
51
|
+
## FINALIZATION PROTOCOL (CRITICAL)
|
|
52
|
+
1. **Definition of Done**:
|
|
53
|
+
- Coding is NOT the last step.
|
|
54
|
+
- \`inspect_code\` passing ("GO") is NOT the last step.
|
|
55
|
+
- You MUST run \`vibe_pm.finalize_work\` to finish a task.
|
|
56
|
+
|
|
57
|
+
2. **No Fragmentation**:
|
|
58
|
+
- NEVER create scattered markdown files like \`feature_login.md\`.
|
|
59
|
+
- All updates go to \`docs/specs/CURRENT_SPEC.md\` via \`finalize_work\`.
|
|
60
|
+
|
|
61
|
+
3. **Logging Standard**:
|
|
62
|
+
- Write \`task_summary\` for a non-technical founder.
|
|
63
|
+
- ✅ "사용자가 이메일로 로그인할 수 있게 되었습니다."
|
|
64
|
+
- ❌ "Implemented bcrypt hash in auth.py."
|
|
65
|
+
|
|
66
|
+
4. **Git Standard**:
|
|
67
|
+
- Use Conventional Commits (e.g., \`feat: user login\`).
|
|
68
|
+
- NEVER commit directly using shell commands.
|
|
69
|
+
- ALWAYS use \`vibe_pm.finalize_work\`.
|
|
70
|
+
|
|
71
|
+
## SELF-HEALING PROTOCOL
|
|
72
|
+
1. **BE PROACTIVE**: Do NOT ask for permission for trivial fixes.
|
|
73
|
+
- Missing package? → Just install it.
|
|
74
|
+
- Syntax error? → Just fix it.
|
|
75
|
+
- Format issue? → Just format it.
|
|
76
|
+
|
|
77
|
+
2. **REPORT AFTERWARDS**: Instead of "Shall I fix it?", say:
|
|
78
|
+
"I detected a missing package and fixed it automatically. The code is now verified."
|
|
79
|
+
|
|
80
|
+
3. **ONLY ASK WHEN RISKY**: Ask ONLY when:
|
|
81
|
+
- Changing database schema (data loss risk)
|
|
82
|
+
- Modifying business logic
|
|
83
|
+
- Touching security configurations
|
|
84
|
+
- Deleting existing data
|
|
85
|
+
|
|
86
|
+
4. **EXAMPLE RESPONSES**:
|
|
87
|
+
- ✅ "검증 과정에서 'pandas' 패키지가 누락된 것을 발견하여 자동으로 설치했습니다."
|
|
88
|
+
- ❌ "'pandas' 패키지가 없습니다. 설치할까요?"
|
|
89
|
+
`;
|
|
90
|
+
const CURRENT_SPEC_CONTENT = `# Project Specification
|
|
91
|
+
|
|
92
|
+
> This is the **Living Spec** - the single source of truth for this project.
|
|
93
|
+
> Last updated: ${new Date().toISOString().split('T')[0]}
|
|
94
|
+
|
|
95
|
+
## 1. Overview
|
|
96
|
+
|
|
97
|
+
<!-- vibe_pm.briefing 후 자동 채워짐 -->
|
|
98
|
+
**Project**: Not initialized
|
|
99
|
+
**Goal**: Run \`vibe_pm.briefing\` to set up.
|
|
100
|
+
|
|
101
|
+
## 2. Architecture
|
|
102
|
+
|
|
103
|
+
<!-- 시스템 구조 설명 -->
|
|
104
|
+
TBD
|
|
105
|
+
|
|
106
|
+
## 3. Database Schema
|
|
107
|
+
|
|
108
|
+
<!-- 데이터베이스 스키마 -->
|
|
109
|
+
TBD
|
|
110
|
+
|
|
111
|
+
## 4. API Endpoints
|
|
112
|
+
|
|
113
|
+
<!-- API 엔드포인트 목록 -->
|
|
114
|
+
TBD
|
|
115
|
+
|
|
116
|
+
## 5. Security
|
|
117
|
+
|
|
118
|
+
<!-- 보안 관련 설정 -->
|
|
119
|
+
TBD
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
*This file is managed by \`vibe_pm.finalize_work\`. Do not edit manually.*
|
|
124
|
+
`;
|
|
125
|
+
const VIBE_CI_WORKFLOW_CONTENT = `name: Vibe PM CI
|
|
126
|
+
|
|
127
|
+
on:
|
|
128
|
+
push:
|
|
129
|
+
pull_request:
|
|
130
|
+
|
|
131
|
+
jobs:
|
|
132
|
+
baseline-check:
|
|
133
|
+
runs-on: ubuntu-latest
|
|
134
|
+
steps:
|
|
135
|
+
- uses: actions/checkout@v4
|
|
136
|
+
|
|
137
|
+
- name: Set up Node
|
|
138
|
+
uses: actions/setup-node@v4
|
|
139
|
+
with:
|
|
140
|
+
node-version: "20"
|
|
141
|
+
|
|
142
|
+
- name: Set up Python
|
|
143
|
+
uses: actions/setup-python@v5
|
|
144
|
+
with:
|
|
145
|
+
python-version: "3.11"
|
|
146
|
+
|
|
147
|
+
- name: Install & Test (Node)
|
|
148
|
+
if: \${{ hashFiles('package.json') != '' }}
|
|
149
|
+
run: |
|
|
150
|
+
if [ -f package-lock.json ]; then npm ci; else npm install; fi
|
|
151
|
+
node -e "const p=require('./package.json');process.exit(p.scripts&&p.scripts.test?0:1)" \\
|
|
152
|
+
&& npm test \\
|
|
153
|
+
|| echo "::notice::No npm test script found. CI ran baseline checks only."
|
|
154
|
+
|
|
155
|
+
- name: Install & Test (Python)
|
|
156
|
+
if: \${{ hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != '' }}
|
|
157
|
+
run: |
|
|
158
|
+
python -m pip install --upgrade pip
|
|
159
|
+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
|
160
|
+
if [ -f pyproject.toml ]; then pip install -e .; fi
|
|
161
|
+
if [ -d tests ]; then
|
|
162
|
+
pip install pytest
|
|
163
|
+
pytest -q
|
|
164
|
+
else
|
|
165
|
+
echo "::notice::No tests/ directory found. CI ran baseline checks only."
|
|
166
|
+
fi
|
|
167
|
+
`;
|
|
168
|
+
const AI_ENTRYPOINT_CONTENT = `# AI Entrypoint: Vibe PM Project
|
|
169
|
+
|
|
170
|
+
> This project is managed by **Vibe PM**. Any AI agent accessing this codebase MUST adhere to the following protocols.
|
|
171
|
+
|
|
172
|
+
## 1. Project Overview
|
|
173
|
+
|
|
174
|
+
<!-- This section will be auto-updated by vibe_pm.briefing -->
|
|
175
|
+
**Status**: Not briefed yet. Run \`vibe_pm.briefing\` to initialize.
|
|
176
|
+
|
|
177
|
+
## 2. Directory Structure (Vibe-SDS)
|
|
178
|
+
|
|
179
|
+
| Path | Permission | Purpose |
|
|
180
|
+
|:-----|:-----------|:--------|
|
|
181
|
+
| \`src/\` | **R/W** | Main implementation code. Your workspace. |
|
|
182
|
+
| \`tests/\` | **R/W** | Test files. Always add tests for new features. |
|
|
183
|
+
| \`docs/\` | **READ** | Documentation. Read for context, don't modify without approval. |
|
|
184
|
+
| \`config/\` | **FORBIDDEN** | Configuration files. Protected by Vibe PM. |
|
|
185
|
+
| \`.vibe/\` | **FORBIDDEN** | Internal system state. Never touch. |
|
|
186
|
+
|
|
187
|
+
## 3. Workflow Protocol
|
|
188
|
+
|
|
189
|
+
\`\`\`
|
|
190
|
+
1. Briefing → vibe_pm.briefing → Understand the goal
|
|
191
|
+
2. Decision → vibe_pm.get_decision → Clarify trade-offs (A/B/C)
|
|
192
|
+
3. Work Order → vibe_pm.create_work_order → Receive specific tasks
|
|
193
|
+
4. Implementation → Write code in src/ → Follow the work order
|
|
194
|
+
5. Inspection → vibe_pm.inspect_code → Validate your work
|
|
195
|
+
\`\`\`
|
|
196
|
+
|
|
197
|
+
## 4. Quick Start
|
|
198
|
+
|
|
199
|
+
\`\`\`bash
|
|
200
|
+
# Check current project status
|
|
201
|
+
vibe_pm.status
|
|
202
|
+
|
|
203
|
+
# Start a new project
|
|
204
|
+
vibe_pm.briefing { "project_brief": "Your idea here" }
|
|
205
|
+
|
|
206
|
+
# Get pending decisions
|
|
207
|
+
vibe_pm.get_decision
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
## 5. Rules Summary
|
|
211
|
+
|
|
212
|
+
1. **No Ticket, No Work**: Always get a Work Order before coding.
|
|
213
|
+
2. **Zone Safety**: Only modify files in \`src/\` and \`tests/\`.
|
|
214
|
+
3. **Inspect After Implementation**: Run \`vibe_pm.inspect_code\` after every change.
|
|
215
|
+
4. **Finalize After Approval**: Run \`vibe_pm.finalize_work\` after "GO" to update docs and commit.
|
|
216
|
+
5. **Ask When Uncertain**: Use \`vibe_pm.get_decision\` for ambiguous choices.
|
|
217
|
+
|
|
218
|
+
## 6. Documentation Architecture (Living Spec)
|
|
219
|
+
|
|
220
|
+
We follow the "Living Spec" approach - no fragmentation allowed.
|
|
221
|
+
|
|
222
|
+
| Path | Purpose |
|
|
223
|
+
|------|---------|
|
|
224
|
+
| \`docs/specs/CURRENT_SPEC.md\` | The absolute truth of the system |
|
|
225
|
+
| \`docs/specs/CHANGELOG.md\` | High-level version history |
|
|
226
|
+
| \`docs/dev_logs/\` | Daily work logs (auto-generated) |
|
|
227
|
+
|
|
228
|
+
### Rules
|
|
229
|
+
- Do NOT create scattered markdown files like \`feature_login.md\`.
|
|
230
|
+
- Do NOT edit spec files manually. Use \`vibe_pm.finalize_work\`.
|
|
231
|
+
- If you touch the code, you must leave a trace in both DEV_LOG and Git.
|
|
232
|
+
- Every task must end with \`finalize_work\`, not just \`inspect_code\`.
|
|
233
|
+
|
|
234
|
+
## 7. Self-Healing System
|
|
235
|
+
|
|
236
|
+
Vibe PM automatically fixes trivial issues without asking:
|
|
237
|
+
|
|
238
|
+
| Issue | Auto-Fix | Example |
|
|
239
|
+
|-------|----------|---------|
|
|
240
|
+
| Missing package | ✅ | Adds to requirements.txt |
|
|
241
|
+
| Syntax error | ✅ | Fixes indentation |
|
|
242
|
+
| Format issue | ✅ | Runs formatter |
|
|
243
|
+
| Logic change | ❌ | Asks user |
|
|
244
|
+
| Data deletion | ❌ | Asks user |
|
|
245
|
+
|
|
246
|
+
### How It Works
|
|
247
|
+
1. \`inspect_code\` runs with \`auto_fix=true\` (default)
|
|
248
|
+
2. Safe issues are fixed immediately
|
|
249
|
+
3. You see: "Auto-fixed 2 issues. All tests passed."
|
|
250
|
+
4. Only risky changes require your approval.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
*This file is auto-generated by \`vibe_pm.scaffold\`. Do not delete.*
|
|
255
|
+
`;
|
|
256
|
+
const TEMPLATES = {
|
|
257
|
+
minimal: [
|
|
258
|
+
{ path: "src/.gitkeep", content: "", description: "소스 코드 디렉토리" },
|
|
259
|
+
{ path: "README.md", content: `# Project\n\nCreated with Vibe PM.\n` },
|
|
260
|
+
// AI Context & Rules (always included)
|
|
261
|
+
{ path: ".cursorrules", content: CURSORRULES_CONTENT, description: "Cursor AI 행동 규칙" },
|
|
262
|
+
{ path: "AI_ENTRYPOINT.md", content: AI_ENTRYPOINT_CONTENT, description: "AI 에이전트 진입점" },
|
|
263
|
+
],
|
|
264
|
+
standard: [
|
|
265
|
+
// BLACK ZONE - System only
|
|
266
|
+
{ path: ".vibe/.gitkeep", content: "", description: ZONE_COMMENTS.BLACK },
|
|
267
|
+
{ path: ".vibe/state/.gitkeep", content: "" },
|
|
268
|
+
{ path: ".vibe/decisions/.gitkeep", content: "" },
|
|
269
|
+
// RED ZONE - Protected config
|
|
270
|
+
{
|
|
271
|
+
path: "config/settings.yaml",
|
|
272
|
+
content: `# ${ZONE_COMMENTS.RED}\n# Project Settings\nenv: development\n`,
|
|
273
|
+
description: ZONE_COMMENTS.RED,
|
|
274
|
+
},
|
|
275
|
+
// GREEN ZONE - AI workspace
|
|
276
|
+
{ path: "src/.gitkeep", content: "", description: ZONE_COMMENTS.GREEN },
|
|
277
|
+
{ path: "src/components/.gitkeep", content: "" },
|
|
278
|
+
{ path: "src/lib/.gitkeep", content: "" },
|
|
279
|
+
{ path: "tests/.gitkeep", content: "", description: ZONE_COMMENTS.GREEN },
|
|
280
|
+
// YELLOW ZONE - Documentation (Living Spec)
|
|
281
|
+
{ path: "docs/specs/CURRENT_SPEC.md", content: CURRENT_SPEC_CONTENT, description: "살아있는 스펙 (SSOT)" },
|
|
282
|
+
{ path: "docs/specs/CHANGELOG.md", content: "# Changelog\n\nAll notable changes to this project.\n\n---\n", description: "버전 히스토리" },
|
|
283
|
+
{ path: "docs/dev_logs/.gitkeep", content: "", description: "일일 개발 일지" },
|
|
284
|
+
{ path: "docs/planning/.gitkeep", content: "", description: "작업대 (기획 및 체크리스트)" },
|
|
285
|
+
{ path: "docs/archive/.gitkeep", content: "", description: "창고 (완료된 작업)" },
|
|
286
|
+
// GitHub Actions (CI)
|
|
287
|
+
{
|
|
288
|
+
path: ".github/workflows/vibe-ci.yml",
|
|
289
|
+
content: VIBE_CI_WORKFLOW_CONTENT,
|
|
290
|
+
description: "GitHub Actions CI (baseline-check)",
|
|
291
|
+
},
|
|
292
|
+
// Root files
|
|
293
|
+
{
|
|
294
|
+
path: "README.md",
|
|
295
|
+
content: `# Project
|
|
296
|
+
|
|
297
|
+
Created with [Vibe PM](https://vibecode.town) - AI Project Manager for non-technical founders.
|
|
298
|
+
|
|
299
|
+
## Directory Structure
|
|
300
|
+
|
|
301
|
+
\`\`\`
|
|
302
|
+
.vibe/ # System state (do not edit)
|
|
303
|
+
config/ # Configuration (protected)
|
|
304
|
+
src/ # Source code (AI workspace)
|
|
305
|
+
components/ # UI components
|
|
306
|
+
lib/ # Utilities
|
|
307
|
+
tests/ # Test files
|
|
308
|
+
docs/ # Documentation
|
|
309
|
+
\`\`\`
|
|
310
|
+
|
|
311
|
+
## Getting Started
|
|
312
|
+
|
|
313
|
+
1. Describe your project idea
|
|
314
|
+
2. Make decisions with vibe_pm.get_decision
|
|
315
|
+
3. Let AI implement in src/
|
|
316
|
+
4. Verify with vibe_pm.inspect_code
|
|
317
|
+
`,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
path: ".gitignore",
|
|
321
|
+
content: `# Vibe PM state (local only)
|
|
322
|
+
.vibe/state/
|
|
323
|
+
|
|
324
|
+
# Environment
|
|
325
|
+
.env
|
|
326
|
+
.env.local
|
|
327
|
+
.env.*.local
|
|
328
|
+
|
|
329
|
+
# Dependencies
|
|
330
|
+
node_modules/
|
|
331
|
+
__pycache__/
|
|
332
|
+
*.pyc
|
|
333
|
+
venv/
|
|
334
|
+
.venv/
|
|
335
|
+
|
|
336
|
+
# Build outputs
|
|
337
|
+
dist/
|
|
338
|
+
build/
|
|
339
|
+
*.egg-info/
|
|
340
|
+
|
|
341
|
+
# IDE
|
|
342
|
+
.idea/
|
|
343
|
+
.vscode/
|
|
344
|
+
*.swp
|
|
345
|
+
*.swo
|
|
346
|
+
|
|
347
|
+
# OS
|
|
348
|
+
.DS_Store
|
|
349
|
+
Thumbs.db
|
|
350
|
+
`,
|
|
351
|
+
},
|
|
352
|
+
// AI Context & Rules (always included)
|
|
353
|
+
{ path: ".cursorrules", content: CURSORRULES_CONTENT, description: "Cursor AI 행동 규칙" },
|
|
354
|
+
{ path: "AI_ENTRYPOINT.md", content: AI_ENTRYPOINT_CONTENT, description: "AI 에이전트 진입점" },
|
|
355
|
+
],
|
|
356
|
+
python_cli: [
|
|
357
|
+
// Inherit from standard
|
|
358
|
+
...[], // Will be merged below
|
|
359
|
+
// Python-specific
|
|
360
|
+
{
|
|
361
|
+
path: "src/main.py",
|
|
362
|
+
content: `#!/usr/bin/env python3
|
|
363
|
+
"""Main entry point for the application."""
|
|
364
|
+
|
|
365
|
+
def main():
|
|
366
|
+
print("Hello from Vibe PM!")
|
|
367
|
+
|
|
368
|
+
if __name__ == "__main__":
|
|
369
|
+
main()
|
|
370
|
+
`,
|
|
371
|
+
},
|
|
372
|
+
{ path: "requirements.txt", content: "# Add your dependencies here\n" },
|
|
373
|
+
{
|
|
374
|
+
path: "pyproject.toml",
|
|
375
|
+
content: `[build-system]
|
|
376
|
+
requires = ["hatchling"]
|
|
377
|
+
build-backend = "hatchling.build"
|
|
378
|
+
|
|
379
|
+
[project]
|
|
380
|
+
name = "my-project"
|
|
381
|
+
version = "0.1.0"
|
|
382
|
+
description = "Created with Vibe PM"
|
|
383
|
+
requires-python = ">=3.10"
|
|
384
|
+
|
|
385
|
+
[project.scripts]
|
|
386
|
+
my-project = "src.main:main"
|
|
387
|
+
`,
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
node_api: [
|
|
391
|
+
// Inherit from standard
|
|
392
|
+
...[], // Will be merged below
|
|
393
|
+
// Node-specific
|
|
394
|
+
{
|
|
395
|
+
path: "src/index.ts",
|
|
396
|
+
content: `// Main entry point
|
|
397
|
+
console.log("Hello from Vibe PM!");
|
|
398
|
+
`,
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
path: "package.json",
|
|
402
|
+
content: JSON.stringify({
|
|
403
|
+
name: "my-project",
|
|
404
|
+
version: "0.1.0",
|
|
405
|
+
description: "Created with Vibe PM",
|
|
406
|
+
type: "module",
|
|
407
|
+
main: "dist/index.js",
|
|
408
|
+
scripts: {
|
|
409
|
+
dev: "tsx watch src/index.ts",
|
|
410
|
+
build: "tsc",
|
|
411
|
+
start: "node dist/index.js",
|
|
412
|
+
test: "vitest",
|
|
413
|
+
},
|
|
414
|
+
devDependencies: {
|
|
415
|
+
typescript: "^5.0.0",
|
|
416
|
+
tsx: "^4.0.0",
|
|
417
|
+
vitest: "^1.0.0",
|
|
418
|
+
},
|
|
419
|
+
}, null, 2) + "\n",
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
path: "tsconfig.json",
|
|
423
|
+
content: JSON.stringify({
|
|
424
|
+
compilerOptions: {
|
|
425
|
+
target: "ES2022",
|
|
426
|
+
module: "NodeNext",
|
|
427
|
+
moduleResolution: "NodeNext",
|
|
428
|
+
outDir: "./dist",
|
|
429
|
+
strict: true,
|
|
430
|
+
esModuleInterop: true,
|
|
431
|
+
skipLibCheck: true,
|
|
432
|
+
},
|
|
433
|
+
include: ["src/**/*"],
|
|
434
|
+
exclude: ["node_modules", "dist"],
|
|
435
|
+
}, null, 2) + "\n",
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
// Merge python_cli and node_api with standard template
|
|
440
|
+
TEMPLATES.python_cli = [...TEMPLATES.standard, ...TEMPLATES.python_cli.filter(t => t.path !== "")];
|
|
441
|
+
TEMPLATES.node_api = [...TEMPLATES.standard, ...TEMPLATES.node_api.filter(t => t.path !== "")];
|
|
442
|
+
// ============================================================
|
|
443
|
+
// Helper Functions
|
|
444
|
+
// ============================================================
|
|
445
|
+
/**
|
|
446
|
+
* Generate ASCII tree representation of created structure
|
|
447
|
+
*/
|
|
448
|
+
function generateTree(items) {
|
|
449
|
+
const dirs = new Set();
|
|
450
|
+
const files = [];
|
|
451
|
+
for (const item of items) {
|
|
452
|
+
const parts = item.path.split("/");
|
|
453
|
+
if (parts.length > 1) {
|
|
454
|
+
// Add all parent directories
|
|
455
|
+
let current = "";
|
|
456
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
457
|
+
current = current ? `${current}/${parts[i]}` : parts[i];
|
|
458
|
+
dirs.add(current);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
files.push(item.path);
|
|
462
|
+
}
|
|
463
|
+
const allPaths = [...Array.from(dirs).sort(), ...files.sort()];
|
|
464
|
+
const lines = [];
|
|
465
|
+
for (let i = 0; i < allPaths.length; i++) {
|
|
466
|
+
const p = allPaths[i];
|
|
467
|
+
const depth = p.split("/").length - 1;
|
|
468
|
+
const isLast = i === allPaths.length - 1 || allPaths[i + 1]?.split("/").length - 1 < depth;
|
|
469
|
+
const prefix = " ".repeat(depth) + (isLast ? "└── " : "├── ");
|
|
470
|
+
const name = p.split("/").pop() || p;
|
|
471
|
+
const isDir = dirs.has(p);
|
|
472
|
+
lines.push(`${prefix}${name}${isDir ? "/" : ""}`);
|
|
473
|
+
}
|
|
474
|
+
return lines.join("\n");
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Check if directory is empty (or doesn't exist)
|
|
478
|
+
*/
|
|
479
|
+
async function isDirectoryEmpty(dir) {
|
|
480
|
+
try {
|
|
481
|
+
const entries = await fs.readdir(dir);
|
|
482
|
+
// Ignore hidden files like .git
|
|
483
|
+
const nonHidden = entries.filter(e => !e.startsWith("."));
|
|
484
|
+
return nonHidden.length === 0;
|
|
485
|
+
}
|
|
486
|
+
catch {
|
|
487
|
+
// Directory doesn't exist - treat as empty
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
// ============================================================
|
|
492
|
+
// Main Implementation
|
|
493
|
+
// ============================================================
|
|
494
|
+
export async function scaffold(input, basePath = process.cwd()) {
|
|
495
|
+
const projectRoot = basePath;
|
|
496
|
+
const template = TEMPLATES[input.template] || TEMPLATES.standard;
|
|
497
|
+
// Safety check: don't overwrite non-empty directory without force
|
|
498
|
+
if (!input.force) {
|
|
499
|
+
const isEmpty = await isDirectoryEmpty(projectRoot);
|
|
500
|
+
if (!isEmpty) {
|
|
501
|
+
// Check if .vibe already exists (already scaffolded)
|
|
502
|
+
try {
|
|
503
|
+
await fs.access(path.join(projectRoot, ".vibe"));
|
|
504
|
+
// Already scaffolded - continue to fill in missing pieces
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
// Not scaffolded, not empty, not forced - refuse
|
|
508
|
+
return {
|
|
509
|
+
success: false,
|
|
510
|
+
created_paths: [],
|
|
511
|
+
skipped_paths: [],
|
|
512
|
+
structure_tree: "",
|
|
513
|
+
next_action: {
|
|
514
|
+
tool: "vibe_pm.scaffold",
|
|
515
|
+
reason: "디렉토리가 비어있지 않습니다. force: true 옵션을 사용하거나 빈 디렉토리에서 실행하세요.",
|
|
516
|
+
},
|
|
517
|
+
error: "directory_not_empty",
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const created = [];
|
|
523
|
+
const skipped = [];
|
|
524
|
+
for (const item of template) {
|
|
525
|
+
const fullPath = path.join(projectRoot, item.path);
|
|
526
|
+
try {
|
|
527
|
+
// Check if already exists
|
|
528
|
+
await fs.access(fullPath);
|
|
529
|
+
skipped.push(item.path);
|
|
530
|
+
}
|
|
531
|
+
catch {
|
|
532
|
+
// Create parent directories
|
|
533
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
534
|
+
// Create file
|
|
535
|
+
await fs.writeFile(fullPath, item.content);
|
|
536
|
+
created.push(item.path);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const structureTree = generateTree(template);
|
|
540
|
+
return {
|
|
541
|
+
success: true,
|
|
542
|
+
created_paths: created,
|
|
543
|
+
skipped_paths: skipped,
|
|
544
|
+
structure_tree: structureTree,
|
|
545
|
+
next_action: {
|
|
546
|
+
tool: "vibe_pm.briefing",
|
|
547
|
+
reason: "프로젝트 구조가 준비되었습니다. 이제 프로젝트 아이디어를 브리핑하세요.",
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// adapters/mcp-ts/src/tools/vibe_pm/search_oss.ts
|
|
2
|
+
// vibe_pm.search_oss - Search OSS repos (gh) and write evidence under runs/<run_id>/export/
|
|
3
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { runEngine } from "../../engine.js";
|
|
5
|
+
import { safeJsonParse } from "../../cli.js";
|
|
6
|
+
import { validateToolInput } from "../../security/input-validator.js";
|
|
7
|
+
import { resolveProjectId, resolveRunId } from "./context.js";
|
|
8
|
+
function toCsv(values) {
|
|
9
|
+
return values
|
|
10
|
+
.map((v) => (typeof v === "string" ? v.trim() : ""))
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.join(",");
|
|
13
|
+
}
|
|
14
|
+
function toInt(v) {
|
|
15
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
16
|
+
return Math.trunc(v);
|
|
17
|
+
if (typeof v === "string") {
|
|
18
|
+
const n = Number(v);
|
|
19
|
+
if (Number.isFinite(n))
|
|
20
|
+
return Math.trunc(n);
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
export async function searchOss(input) {
|
|
25
|
+
const basePath = process.cwd();
|
|
26
|
+
validateToolInput({ project_id: input.project_id, run_id: input.run_id });
|
|
27
|
+
const resolvedRun = resolveRunId(input.run_id ?? input.project_id, basePath);
|
|
28
|
+
const run_id = resolvedRun.run_id;
|
|
29
|
+
const project_id = resolveProjectId(run_id, basePath);
|
|
30
|
+
const keywords = Array.isArray(input.keywords) ? input.keywords.map((k) => String(k).trim()).filter(Boolean) : [];
|
|
31
|
+
if (keywords.length === 0) {
|
|
32
|
+
throw new McpError(ErrorCode.InvalidParams, "[VALIDATION] keywords is required");
|
|
33
|
+
}
|
|
34
|
+
const cmd = [
|
|
35
|
+
"search-oss",
|
|
36
|
+
run_id,
|
|
37
|
+
"--intent",
|
|
38
|
+
String(input.intent ?? "").trim(),
|
|
39
|
+
"--keywords",
|
|
40
|
+
toCsv(keywords)
|
|
41
|
+
];
|
|
42
|
+
const constraints = input?.constraints ?? {};
|
|
43
|
+
const licenseAllowlist = Array.isArray(constraints?.license_allowlist)
|
|
44
|
+
? constraints.license_allowlist.map((x) => String(x).trim()).filter(Boolean)
|
|
45
|
+
: [];
|
|
46
|
+
if (licenseAllowlist.length > 0) {
|
|
47
|
+
cmd.push("--license-allowlist", toCsv(licenseAllowlist));
|
|
48
|
+
}
|
|
49
|
+
const minStars = toInt(constraints?.min_stars);
|
|
50
|
+
if (minStars !== undefined)
|
|
51
|
+
cmd.push("--min-stars", String(minStars));
|
|
52
|
+
const updatedWithinDays = toInt(constraints?.updated_within_days);
|
|
53
|
+
if (updatedWithinDays !== undefined)
|
|
54
|
+
cmd.push("--updated-within-days", String(updatedWithinDays));
|
|
55
|
+
const language = typeof constraints?.language === "string" ? constraints.language.trim() : "";
|
|
56
|
+
if (language)
|
|
57
|
+
cmd.push("--language", language);
|
|
58
|
+
const limit = toInt(constraints?.limit);
|
|
59
|
+
if (limit !== undefined)
|
|
60
|
+
cmd.push("--limit", String(limit));
|
|
61
|
+
const sort = typeof constraints?.sort === "string" ? constraints.sort.trim() : "";
|
|
62
|
+
if (sort)
|
|
63
|
+
cmd.push("--sort", sort);
|
|
64
|
+
const writeEvidence = input?.write_evidence !== false;
|
|
65
|
+
if (!writeEvidence)
|
|
66
|
+
cmd.push("--no-write-evidence");
|
|
67
|
+
const res = await runEngine("vibecoding-helper", cmd, { timeoutMs: 180_000 });
|
|
68
|
+
if (res.code !== 0) {
|
|
69
|
+
throw new Error(`search-oss failed: ${res.stderr || res.stdout || `exit_code=${res.code}`}`);
|
|
70
|
+
}
|
|
71
|
+
const parsed = safeJsonParse(res.stdout);
|
|
72
|
+
if (!parsed.ok) {
|
|
73
|
+
throw new Error(`search-oss invalid_json: ${parsed.error}`);
|
|
74
|
+
}
|
|
75
|
+
const doc = parsed.value;
|
|
76
|
+
const query = typeof doc?.query === "string" && doc.query.trim()
|
|
77
|
+
? String(doc.query).trim()
|
|
78
|
+
: keywords.map((k) => k.trim()).filter(Boolean).join(" ");
|
|
79
|
+
const warnings = [];
|
|
80
|
+
if (Array.isArray(doc?.warnings)) {
|
|
81
|
+
for (const w of doc.warnings) {
|
|
82
|
+
if (typeof w === "string" && w.trim())
|
|
83
|
+
warnings.push(w.trim());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const candidates = [];
|
|
87
|
+
const rawCandidates = Array.isArray(doc?.candidates) ? doc.candidates : [];
|
|
88
|
+
for (const c of rawCandidates) {
|
|
89
|
+
const obj = c;
|
|
90
|
+
const repo = typeof obj?.repo === "string" ? obj.repo.trim() : "";
|
|
91
|
+
if (!repo)
|
|
92
|
+
continue;
|
|
93
|
+
const urlRaw = typeof obj?.url === "string" ? obj.url.trim() : "";
|
|
94
|
+
const url = urlRaw || `https://github.com/${repo}`;
|
|
95
|
+
candidates.push({
|
|
96
|
+
repo,
|
|
97
|
+
url,
|
|
98
|
+
description: typeof obj?.description === "string" ? obj.description : "",
|
|
99
|
+
license: typeof obj?.license === "string" ? obj.license : "",
|
|
100
|
+
stars: typeof obj?.stars === "number" ? obj.stars : 0,
|
|
101
|
+
updated_at: typeof obj?.updated_at === "string" ? obj.updated_at : "",
|
|
102
|
+
ref_candidates: Array.isArray(obj?.ref_candidates)
|
|
103
|
+
? obj.ref_candidates.map((x) => String(x)).filter(Boolean)
|
|
104
|
+
: []
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const evidencePath = typeof doc?.evidence_path === "string" && doc.evidence_path.trim() ? String(doc.evidence_path).trim() : undefined;
|
|
108
|
+
const out = {
|
|
109
|
+
success: true,
|
|
110
|
+
project_id,
|
|
111
|
+
run_id,
|
|
112
|
+
intent: String(input.intent ?? "").trim(),
|
|
113
|
+
query,
|
|
114
|
+
candidates,
|
|
115
|
+
warnings,
|
|
116
|
+
next_action: {
|
|
117
|
+
tool: "vibe_pm.export_output",
|
|
118
|
+
reason: "Pick a template repo + pinned ref, then export using target=web_template_repo."
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
if (evidencePath)
|
|
122
|
+
out.evidence_path = evidencePath;
|
|
123
|
+
return out;
|
|
124
|
+
}
|