@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,393 @@
|
|
|
1
|
+
// adapters/mcp-ts/src/tools/vibe_pm/finalize_work.ts
|
|
2
|
+
// vibe_pm.finalize_work - Document updates + DEV_LOG + Git commit/push
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { simpleGit } from "simple-git";
|
|
6
|
+
import { memorySync } from "./memory_sync.js";
|
|
7
|
+
import { getAuthGate } from "../../auth/index.js";
|
|
8
|
+
import { advisoryReview } from "./advisory_review.js";
|
|
9
|
+
import { runDocStatusTriage } from "./doc_status_gate.js";
|
|
10
|
+
import { kickoffKceSyncBestEffort } from "./kce/on_finalize.js";
|
|
11
|
+
import { updateVersionFile } from "../../version-check.js";
|
|
12
|
+
import { CONTRACTS_VERSION, CONTRACTS_BUNDLE_SHA256 } from "../../generated/contracts_bundle_info.js";
|
|
13
|
+
/**
|
|
14
|
+
* vibe_pm.finalize_work - Complete work with documentation and Git
|
|
15
|
+
*
|
|
16
|
+
* Steps:
|
|
17
|
+
* 1. Calculate date (YYYY-MM-DD)
|
|
18
|
+
* 2. Create/append DEV_LOG file (docs/dev_logs/{date}.md)
|
|
19
|
+
* 3. Update CURRENT_SPEC.md sections (if spec_changes provided)
|
|
20
|
+
* 4. git add .
|
|
21
|
+
* 5. git commit with conventional commit format
|
|
22
|
+
* 6. git push (if remote origin exists)
|
|
23
|
+
* 7. Return result
|
|
24
|
+
*/
|
|
25
|
+
export async function finalizeWork(input, basePath = process.cwd()) {
|
|
26
|
+
const updatedFiles = [];
|
|
27
|
+
let warning;
|
|
28
|
+
// Step 1: Calculate date
|
|
29
|
+
const today = new Date();
|
|
30
|
+
const dateStr = today.toISOString().split("T")[0]; // YYYY-MM-DD
|
|
31
|
+
const timestamp = today.toISOString();
|
|
32
|
+
// Step 1.5: Archive Logic (Clean Desk Policy)
|
|
33
|
+
let sessionSummary = input.task_summary;
|
|
34
|
+
if (input.completed_plan_path) {
|
|
35
|
+
try {
|
|
36
|
+
const planPath = path.resolve(basePath, input.completed_plan_path);
|
|
37
|
+
const planningDir = path.resolve(basePath, "docs", "planning");
|
|
38
|
+
// Validate: must be inside docs/planning and exist
|
|
39
|
+
if (fs.existsSync(planPath) && planPath.startsWith(planningDir)) {
|
|
40
|
+
const archiveDir = path.join(basePath, "docs", "archive");
|
|
41
|
+
if (!fs.existsSync(archiveDir))
|
|
42
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
43
|
+
const fileName = path.basename(planPath);
|
|
44
|
+
const datePrefix = dateStr.replace(/-/g, ""); // 20240520
|
|
45
|
+
const archiveName = `${datePrefix}_${fileName}`;
|
|
46
|
+
const archivePath = path.join(archiveDir, archiveName);
|
|
47
|
+
fs.renameSync(planPath, archivePath);
|
|
48
|
+
const relativeArchive = path.relative(basePath, archivePath);
|
|
49
|
+
updatedFiles.push(relativeArchive);
|
|
50
|
+
sessionSummary += `\n\n> **Archived Plan**: \`${relativeArchive}\``;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
warning = warning ? `${warning}; Invalid plan path` : "Invalid plan path (not in planning dir or missing)";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
warning = warning ? `${warning}; Archive error: ${e}` : `Archive error: ${e}`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Step 2: Create/append DEV_LOG
|
|
61
|
+
const devLogDir = path.join(basePath, "docs", "dev_logs");
|
|
62
|
+
const devLogPath = path.join(devLogDir, `${dateStr}.md`);
|
|
63
|
+
try {
|
|
64
|
+
// Ensure directory exists
|
|
65
|
+
if (!fs.existsSync(devLogDir)) {
|
|
66
|
+
fs.mkdirSync(devLogDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
const logEntry = formatDevLogEntry(sessionSummary, timestamp, input.git_commit);
|
|
69
|
+
if (fs.existsSync(devLogPath)) {
|
|
70
|
+
// Append to existing file
|
|
71
|
+
fs.appendFileSync(devLogPath, `\n${logEntry}`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Create new file with header
|
|
75
|
+
const header = `# DEV LOG - ${dateStr}\n\n`;
|
|
76
|
+
fs.writeFileSync(devLogPath, header + logEntry);
|
|
77
|
+
}
|
|
78
|
+
updatedFiles.push(devLogPath);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
warning = `DEV_LOG 생성 실패: ${err instanceof Error ? err.message : String(err)}`;
|
|
82
|
+
}
|
|
83
|
+
// Step 3: Update CURRENT_SPEC.md (if spec_changes provided)
|
|
84
|
+
if (input.spec_changes && input.spec_changes.length > 0) {
|
|
85
|
+
const specPath = path.join(basePath, "docs", "CURRENT_SPEC.md");
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(specPath)) {
|
|
88
|
+
let specContent = fs.readFileSync(specPath, "utf-8");
|
|
89
|
+
for (const change of input.spec_changes) {
|
|
90
|
+
specContent = applySpecChange(specContent, change.section, change.content, change.action ?? "REPLACE");
|
|
91
|
+
}
|
|
92
|
+
fs.writeFileSync(specPath, specContent);
|
|
93
|
+
updatedFiles.push(specPath);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Create new CURRENT_SPEC.md
|
|
97
|
+
let newContent = "# CURRENT_SPEC\n\n";
|
|
98
|
+
for (const change of input.spec_changes) {
|
|
99
|
+
newContent += `## ${change.section}\n\n${change.content}\n\n`;
|
|
100
|
+
}
|
|
101
|
+
fs.writeFileSync(specPath, newContent);
|
|
102
|
+
updatedFiles.push(specPath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
const errMsg = `CURRENT_SPEC.md 갱신 실패: ${err instanceof Error ? err.message : String(err)}`;
|
|
107
|
+
warning = warning ? `${warning}; ${errMsg}` : errMsg;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Step 3.5: Doc Status Triage (must run before git add/commit; idempotent best-effort)
|
|
111
|
+
try {
|
|
112
|
+
const touched = updatedFiles
|
|
113
|
+
.map((p) => {
|
|
114
|
+
const abs = path.isAbsolute(p) ? p : path.resolve(basePath, p);
|
|
115
|
+
return path.relative(basePath, abs).replace(/\\\\/g, "/");
|
|
116
|
+
})
|
|
117
|
+
.filter(Boolean);
|
|
118
|
+
const triage = runDocStatusTriage({ basePath, touched_paths: touched, now: today });
|
|
119
|
+
for (const p of [...triage.tagged, ...triage.archived, ...triage.tombstoned]) {
|
|
120
|
+
if (!updatedFiles.includes(p))
|
|
121
|
+
updatedFiles.push(p);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
warning = appendWarning(warning, `DOC_STATUS_TRIAGE_FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
126
|
+
}
|
|
127
|
+
// Best-effort: keep Local Memory up-to-date after doc updates (do not block finalize_work)
|
|
128
|
+
if (shouldKickoffAutoMemorySync(basePath)) {
|
|
129
|
+
void kickoffAutoMemorySyncProOnly();
|
|
130
|
+
}
|
|
131
|
+
// Step 4-6: Git (add/commit/pull-rebase/push)
|
|
132
|
+
const commitMessage = formatCommitMessage(input.git_commit);
|
|
133
|
+
let commitHash = "no-commit";
|
|
134
|
+
let pushedToRemote = false;
|
|
135
|
+
let remoteUrl;
|
|
136
|
+
try {
|
|
137
|
+
const git = simpleGit({ baseDir: basePath });
|
|
138
|
+
const isRepo = await git.checkIsRepo();
|
|
139
|
+
if (isRepo) {
|
|
140
|
+
// Stage + commit (only when there are changes)
|
|
141
|
+
const status = await git.status();
|
|
142
|
+
const hasChanges = status.files.length > 0;
|
|
143
|
+
let commitCreated = false;
|
|
144
|
+
// Best-effort: pre-finalize triage (never blocks finalize_work)
|
|
145
|
+
if (hasChanges && shouldKickoffAutoAdvisoryTriage(basePath)) {
|
|
146
|
+
try {
|
|
147
|
+
void advisoryReview({
|
|
148
|
+
mode: "triage",
|
|
149
|
+
trigger: "pre_finalize",
|
|
150
|
+
budget: "low",
|
|
151
|
+
changed_paths: status.files.map((f) => f.path)
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// ignore
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (hasChanges) {
|
|
159
|
+
await git.add(".");
|
|
160
|
+
try {
|
|
161
|
+
await git.commit(commitMessage);
|
|
162
|
+
commitHash = (await git.revparse(["HEAD"])).trim() || "unknown";
|
|
163
|
+
commitCreated = true;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
warning = appendWarning(warning, `Git commit 실패: ${err instanceof Error ? err.message : String(err)}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
commitHash = "no-changes";
|
|
171
|
+
warning = appendWarning(warning, "커밋할 변경사항 없음");
|
|
172
|
+
}
|
|
173
|
+
// Remote origin (optional)
|
|
174
|
+
try {
|
|
175
|
+
remoteUrl = (await git.raw(["remote", "get-url", "origin"])).trim();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
remoteUrl = undefined;
|
|
179
|
+
}
|
|
180
|
+
const canPull = commitCreated || commitHash === "no-changes";
|
|
181
|
+
if (remoteUrl && canPull) {
|
|
182
|
+
// Default: current branch (fallback: main)
|
|
183
|
+
let branchName = "main";
|
|
184
|
+
try {
|
|
185
|
+
const branch = await git.branch();
|
|
186
|
+
if (branch.current)
|
|
187
|
+
branchName = branch.current;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// ignore
|
|
191
|
+
}
|
|
192
|
+
if (branchName !== "main") {
|
|
193
|
+
warning = appendWarning(warning, `NOT_ON_MAIN: current=${branchName}`);
|
|
194
|
+
}
|
|
195
|
+
// Smart sync: pull --rebase before push
|
|
196
|
+
try {
|
|
197
|
+
await git.pull("origin", branchName, { "--rebase": "true" });
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
// Rebase conflict stop (no auto-resolve)
|
|
201
|
+
try {
|
|
202
|
+
await git.rebase(["--abort"]);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// ignore
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
success: false,
|
|
209
|
+
updated_files: updatedFiles,
|
|
210
|
+
commit_hash: commitHash,
|
|
211
|
+
pushed_to_remote: false,
|
|
212
|
+
remote_url: remoteUrl,
|
|
213
|
+
warning: appendWarning(warning, "MERGE_CONFLICT: manual_resolution_required"),
|
|
214
|
+
next_action: {
|
|
215
|
+
tool: "vibe_pm.status",
|
|
216
|
+
reason: "작업 완료 상태를 확인하세요",
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// Push only when we produced a new commit
|
|
221
|
+
if (commitCreated && commitHash !== "no-commit" && commitHash !== "no-changes") {
|
|
222
|
+
try {
|
|
223
|
+
await git.push("origin", branchName);
|
|
224
|
+
pushedToRemote = true;
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
warning = appendWarning(warning, `Git push 실패: ${err instanceof Error ? err.message : String(err)}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
// Git not available / not a repo / unexpected error: keep docs work, but surface warning
|
|
235
|
+
warning = appendWarning(warning, `Git 처리 실패: ${err instanceof Error ? err.message : String(err)}`);
|
|
236
|
+
}
|
|
237
|
+
// Best-effort: KCE sync (do not block finalize_work)
|
|
238
|
+
if (shouldKickoffAutoMemorySync(basePath)) {
|
|
239
|
+
void kickoffKceSyncBestEffort();
|
|
240
|
+
}
|
|
241
|
+
// Best-effort: Update .vibe/version.json (finalize_work + release 정책)
|
|
242
|
+
try {
|
|
243
|
+
const pkgJsonPath = path.join(basePath, "package.json");
|
|
244
|
+
let appVersion = "0.0.0";
|
|
245
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
246
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
247
|
+
appVersion = pkgJson.version ?? "0.0.0";
|
|
248
|
+
}
|
|
249
|
+
updateVersionFile({
|
|
250
|
+
repoRoot: basePath,
|
|
251
|
+
version: appVersion,
|
|
252
|
+
channel: "stable",
|
|
253
|
+
contractsSemver: CONTRACTS_VERSION,
|
|
254
|
+
contractsSha256: `sha256:${CONTRACTS_BUNDLE_SHA256}`,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Best-effort: do not block finalize_work
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
success: commitHash !== "no-commit" || updatedFiles.length > 0,
|
|
262
|
+
updated_files: updatedFiles,
|
|
263
|
+
commit_hash: commitHash,
|
|
264
|
+
pushed_to_remote: pushedToRemote,
|
|
265
|
+
remote_url: remoteUrl,
|
|
266
|
+
warning,
|
|
267
|
+
next_action: {
|
|
268
|
+
tool: "vibe_pm.status",
|
|
269
|
+
reason: "작업 완료 상태를 확인하세요"
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Format DEV_LOG entry
|
|
275
|
+
*/
|
|
276
|
+
function formatDevLogEntry(summary, timestamp, commit) {
|
|
277
|
+
const time = timestamp.split("T")[1]?.slice(0, 5) ?? "";
|
|
278
|
+
const typeLabel = getCommitTypeLabel(commit.type);
|
|
279
|
+
const scope = commit.scope ? `(${commit.scope})` : "";
|
|
280
|
+
return `## ${time} - ${typeLabel}${scope}: ${commit.subject}
|
|
281
|
+
|
|
282
|
+
${summary}
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
function shouldKickoffAutoMemorySync(basePath) {
|
|
288
|
+
// Skip for tests / library calls where basePath is injected
|
|
289
|
+
if (path.resolve(basePath) !== path.resolve(process.cwd()))
|
|
290
|
+
return false;
|
|
291
|
+
const raw = (process.env.VIBECODE_AUTOMEMORY ?? "").trim().toLowerCase();
|
|
292
|
+
if (raw && (raw === "0" || raw === "false" || raw === "no" || raw === "off"))
|
|
293
|
+
return false;
|
|
294
|
+
const nodeEnv = (process.env.NODE_ENV ?? "").trim().toLowerCase();
|
|
295
|
+
if (nodeEnv === "test")
|
|
296
|
+
return false;
|
|
297
|
+
const vitest = (process.env.VITEST ?? "").trim().toLowerCase();
|
|
298
|
+
if (vitest && vitest !== "0" && vitest !== "false" && vitest !== "no" && vitest !== "off")
|
|
299
|
+
return false;
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
async function kickoffAutoMemorySyncProOnly() {
|
|
303
|
+
try {
|
|
304
|
+
const gate = getAuthGate();
|
|
305
|
+
const allowed = await gate.check("local_memory_pro_tools");
|
|
306
|
+
if (!allowed.allowed)
|
|
307
|
+
return;
|
|
308
|
+
await memorySync({ docs_root: "docs", mode: "pre_finalize", force_full: false });
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
// ignore (best-effort)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function shouldKickoffAutoAdvisoryTriage(basePath) {
|
|
315
|
+
// Skip for tests / library calls where basePath is injected
|
|
316
|
+
if (path.resolve(basePath) !== path.resolve(process.cwd()))
|
|
317
|
+
return false;
|
|
318
|
+
const raw = (process.env.VIBECODE_AUTOADVISORY ?? "").trim().toLowerCase();
|
|
319
|
+
if (raw && (raw === "0" || raw === "false" || raw === "no" || raw === "off"))
|
|
320
|
+
return false;
|
|
321
|
+
const nodeEnv = (process.env.NODE_ENV ?? "").trim().toLowerCase();
|
|
322
|
+
if (nodeEnv === "test")
|
|
323
|
+
return false;
|
|
324
|
+
const vitest = (process.env.VITEST ?? "").trim().toLowerCase();
|
|
325
|
+
if (vitest && vitest !== "0" && vitest !== "false" && vitest !== "no" && vitest !== "off")
|
|
326
|
+
return false;
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Get human-readable commit type label
|
|
331
|
+
*/
|
|
332
|
+
function getCommitTypeLabel(type) {
|
|
333
|
+
const labels = {
|
|
334
|
+
feat: "새 기능",
|
|
335
|
+
fix: "버그 수정",
|
|
336
|
+
docs: "문서",
|
|
337
|
+
style: "스타일",
|
|
338
|
+
refactor: "리팩토링",
|
|
339
|
+
test: "테스트",
|
|
340
|
+
chore: "기타"
|
|
341
|
+
};
|
|
342
|
+
return labels[type] ?? type;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Format commit message in conventional commit style
|
|
346
|
+
*/
|
|
347
|
+
function formatCommitMessage(commit) {
|
|
348
|
+
const scope = commit.scope ? `(${commit.scope})` : "";
|
|
349
|
+
let message = `${commit.type}${scope}: ${commit.subject}`;
|
|
350
|
+
if (commit.body) {
|
|
351
|
+
message += `\n\n${commit.body}`;
|
|
352
|
+
}
|
|
353
|
+
if (commit.footer) {
|
|
354
|
+
message += `\n\n${commit.footer}`;
|
|
355
|
+
}
|
|
356
|
+
return message;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Apply spec change to content
|
|
360
|
+
*/
|
|
361
|
+
function applySpecChange(content, section, newContent, action) {
|
|
362
|
+
// Find section pattern: ## Section Name or # Section Name
|
|
363
|
+
const sectionPattern = new RegExp(`(^#{1,3}\\s*${escapeRegExp(section)}\\s*$)([\\s\\S]*?)(?=^#{1,3}\\s|$)`, "m");
|
|
364
|
+
const match = content.match(sectionPattern);
|
|
365
|
+
if (match) {
|
|
366
|
+
if (action === "REPLACE") {
|
|
367
|
+
return content.replace(sectionPattern, `$1\n\n${newContent}\n\n`);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// APPEND
|
|
371
|
+
const existingContent = match[2].trim();
|
|
372
|
+
return content.replace(sectionPattern, `$1\n\n${existingContent}\n\n${newContent}\n\n`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
// Section not found, append at end
|
|
377
|
+
return content + `\n\n## ${section}\n\n${newContent}\n`;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Escape string for shell argument
|
|
382
|
+
*/
|
|
383
|
+
function appendWarning(existing, next) {
|
|
384
|
+
if (!existing)
|
|
385
|
+
return next;
|
|
386
|
+
return `${existing}; ${next}`;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Escape string for regex
|
|
390
|
+
*/
|
|
391
|
+
function escapeRegExp(str) {
|
|
392
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
393
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// adapters/mcp-ts/src/tools/vibe_pm/gate.ts
|
|
2
|
+
// vibe_pm.gate - System Design Gate check (direct)
|
|
3
|
+
import { GateInputSchema } from "../../generated/gate_input.js";
|
|
4
|
+
import { GateOutputSchema } from "../../generated/gate_output.js";
|
|
5
|
+
import { WorkOrderV1Schema } from "../../generated/work_order_v1.js";
|
|
6
|
+
import { checkGate } from "../../control_plane/gate.js";
|
|
7
|
+
// SSOT-generated (JSON Schema → Zod)
|
|
8
|
+
export const gateInputSchema = GateInputSchema;
|
|
9
|
+
export const gateOutputSchema = GateOutputSchema;
|
|
10
|
+
/**
|
|
11
|
+
* vibe_pm.gate
|
|
12
|
+
*
|
|
13
|
+
* Validates a WorkOrderV1 against System Design Gate.
|
|
14
|
+
* Returns GateOutput (GateResultV1-compatible shape).
|
|
15
|
+
*/
|
|
16
|
+
export async function gate(input) {
|
|
17
|
+
const basePath = process.cwd();
|
|
18
|
+
// Fail-closed on tool input drift
|
|
19
|
+
const parsed = gateInputSchema.parse(input);
|
|
20
|
+
const workOrder = WorkOrderV1Schema.parse(parsed.work_order);
|
|
21
|
+
const opts = parsed.options;
|
|
22
|
+
const out = await checkGate(workOrder, {
|
|
23
|
+
repoRoot: basePath,
|
|
24
|
+
failFast: opts?.fail_fast,
|
|
25
|
+
semgrep: opts?.semgrep,
|
|
26
|
+
runtime: opts?.runtime
|
|
27
|
+
});
|
|
28
|
+
if (!out.result) {
|
|
29
|
+
throw new Error(out.error ?? "Gate returned no result");
|
|
30
|
+
}
|
|
31
|
+
// Fail-closed on output drift
|
|
32
|
+
return gateOutputSchema.parse(out.result);
|
|
33
|
+
}
|