@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,61 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ export function findGitBashExe() {
5
+ const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
6
+ const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
7
+ const candidates = [
8
+ path.join(programFiles, "Git", "bin", "bash.exe"),
9
+ path.join(programFiles, "Git", "usr", "bin", "bash.exe"),
10
+ path.join(programFilesX86, "Git", "bin", "bash.exe"),
11
+ path.join(programFilesX86, "Git", "usr", "bin", "bash.exe")
12
+ ];
13
+ for (const candidate of candidates) {
14
+ if (fs.existsSync(candidate))
15
+ return candidate;
16
+ }
17
+ return null;
18
+ }
19
+ export function canRunWsl() {
20
+ if (process.platform !== "win32")
21
+ return false;
22
+ const result = spawnSync("wsl", ["echo", "ok"], { encoding: "utf-8" });
23
+ return result.status === 0;
24
+ }
25
+ function toWslPath(winPath) {
26
+ const result = spawnSync("wsl", ["wslpath", "-a", winPath], { encoding: "utf-8" });
27
+ if (result.status !== 0) {
28
+ throw new Error(`wslpath failed for ${winPath}: ${result.stderr ?? ""}`);
29
+ }
30
+ return (result.stdout ?? "").trim();
31
+ }
32
+ function shSingleQuote(s) {
33
+ return `'${s.replace(/'/g, `'\\''`)}'`;
34
+ }
35
+ export function hasBashRuntime() {
36
+ if (process.platform !== "win32") {
37
+ const bash = spawnSync("bash", ["--version"], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
38
+ return bash.status === 0;
39
+ }
40
+ if (findGitBashExe())
41
+ return true;
42
+ return canRunWsl();
43
+ }
44
+ export function spawnBashScriptInRepoSync(repoRoot, scriptPath, scriptArgs, options) {
45
+ if (process.platform !== "win32") {
46
+ return spawnSync("bash", [scriptPath, ...scriptArgs], { ...options, cwd: repoRoot });
47
+ }
48
+ const gitBash = findGitBashExe();
49
+ if (gitBash) {
50
+ return spawnSync(gitBash, [scriptPath, ...scriptArgs], { ...options, cwd: repoRoot });
51
+ }
52
+ if (!canRunWsl())
53
+ return null;
54
+ const wslRepoRoot = toWslPath(repoRoot);
55
+ const wslScriptPath = toWslPath(scriptPath);
56
+ const cmd = [
57
+ `cd ${shSingleQuote(wslRepoRoot)}`,
58
+ `bash ${shSingleQuote(wslScriptPath)} ${scriptArgs.map(shSingleQuote).join(" ")}`
59
+ ].join(" && ");
60
+ return spawnSync("wsl", ["bash", "-lc", cmd], { ...options });
61
+ }
@@ -0,0 +1,171 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { VibeRepoConfigSchema } from "../generated/vibe_repo_config.js";
4
+ export function isVibeRepo(repoRoot) {
5
+ return fs.existsSync(path.join(repoRoot, ".vibe"));
6
+ }
7
+ export function readRepoConfig(configFile) {
8
+ if (!fs.existsSync(configFile))
9
+ return null;
10
+ const raw = JSON.parse(fs.readFileSync(configFile, "utf-8"));
11
+ // Backward compatibility: ignore legacy fields removed from SSOT.
12
+ if (raw && typeof raw === "object") {
13
+ delete raw.mcp;
14
+ }
15
+ return VibeRepoConfigSchema.parse(raw);
16
+ }
17
+ export function validateRepoConfig(configFile) {
18
+ try {
19
+ const config = readRepoConfig(configFile);
20
+ if (!config)
21
+ return { ok: false, error: `Missing config: ${configFile}` };
22
+ return { ok: true, config };
23
+ }
24
+ catch (e) {
25
+ const message = e instanceof Error ? e.message : String(e);
26
+ return { ok: false, error: message };
27
+ }
28
+ }
29
+ export function defaultRepoConfig(projectName, managedSinceIso) {
30
+ return VibeRepoConfigSchema.parse({
31
+ $schema: "https://vibecode.town/schemas/config.schema.json",
32
+ version: "1.0.3",
33
+ mode: "local-first",
34
+ project: {
35
+ name: projectName,
36
+ managed_since: managedSinceIso,
37
+ },
38
+ policy: {
39
+ no_ticket_no_work: true,
40
+ enforcement: "warn",
41
+ stale_hours: 24,
42
+ auto_update_on_start: "prompt",
43
+ safety_zones: {
44
+ green: ["src/**", "tests/**", "lib/**", "scripts/**"],
45
+ yellow: ["docs/**", "README.md", "*.md"],
46
+ red: ["config/**", ".env", ".env.*", "secrets/**", "credentials.*", "*.pem", "*.key"],
47
+ black: [".vibe/state/**", ".vibe/decisions/**", ".vibe/chroma/**", ".git/**"],
48
+ },
49
+ },
50
+ hooks: {
51
+ pre_commit: { enabled: false, enforcement: "warn" },
52
+ pre_push: { enabled: true, enforcement: "warn", gitleaks_required: false },
53
+ },
54
+ ai_agents: {
55
+ require_entrypoint_read: true,
56
+ require_briefing_before_work: true,
57
+ },
58
+ });
59
+ }
60
+ export function writeRepoConfig(configFile, config) {
61
+ fs.mkdirSync(path.dirname(configFile), { recursive: true });
62
+ fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
63
+ }
64
+ export function setRepoConfigValue(configFile, key, value) {
65
+ const config = readRepoConfig(configFile);
66
+ if (!config)
67
+ return { ok: false, error: `Missing config: ${configFile}` };
68
+ try {
69
+ let updated = config;
70
+ switch (key) {
71
+ case "mode": {
72
+ if (value !== "local-first" && value !== "server-required") {
73
+ return { ok: false, error: `Unsupported mode: ${value}` };
74
+ }
75
+ updated = { ...config, mode: value };
76
+ break;
77
+ }
78
+ case "policy.enforcement": {
79
+ if (value !== "warn" && value !== "block") {
80
+ return { ok: false, error: `Unsupported policy.enforcement: ${value}` };
81
+ }
82
+ updated = {
83
+ ...config,
84
+ policy: {
85
+ ...(config.policy ?? {}),
86
+ enforcement: value,
87
+ },
88
+ };
89
+ break;
90
+ }
91
+ case "policy.auto_update_on_start": {
92
+ if (value !== "off" && value !== "prompt" && value !== "silent") {
93
+ return {
94
+ ok: false,
95
+ error: `Unsupported policy.auto_update_on_start: ${value} (use off|prompt|silent)`
96
+ };
97
+ }
98
+ updated = {
99
+ ...config,
100
+ policy: {
101
+ ...(config.policy ?? {}),
102
+ auto_update_on_start: value,
103
+ },
104
+ };
105
+ break;
106
+ }
107
+ case "hooks.pre_push.enabled": {
108
+ if (value !== "true" && value !== "false") {
109
+ return { ok: false, error: `Unsupported hooks.pre_push.enabled: ${value} (use true|false)` };
110
+ }
111
+ const boolValue = value === "true";
112
+ updated = {
113
+ ...config,
114
+ hooks: {
115
+ ...(config.hooks ?? {}),
116
+ pre_push: {
117
+ ...((config.hooks ?? {}).pre_push ?? {}),
118
+ enabled: boolValue,
119
+ },
120
+ },
121
+ };
122
+ break;
123
+ }
124
+ case "hooks.pre_push.enforcement": {
125
+ if (value !== "warn" && value !== "block") {
126
+ return { ok: false, error: `Unsupported hooks.pre_push.enforcement: ${value}` };
127
+ }
128
+ updated = {
129
+ ...config,
130
+ hooks: {
131
+ ...(config.hooks ?? {}),
132
+ pre_push: {
133
+ ...((config.hooks ?? {}).pre_push ?? {}),
134
+ enforcement: value,
135
+ },
136
+ },
137
+ };
138
+ break;
139
+ }
140
+ case "hooks.pre_push.gitleaks_required": {
141
+ if (value !== "true" && value !== "false") {
142
+ return {
143
+ ok: false,
144
+ error: `Unsupported hooks.pre_push.gitleaks_required: ${value} (use true|false)`
145
+ };
146
+ }
147
+ const boolValue = value === "true";
148
+ updated = {
149
+ ...config,
150
+ hooks: {
151
+ ...(config.hooks ?? {}),
152
+ pre_push: {
153
+ ...((config.hooks ?? {}).pre_push ?? {}),
154
+ gitleaks_required: boolValue,
155
+ },
156
+ },
157
+ };
158
+ break;
159
+ }
160
+ default:
161
+ return { ok: false, error: `Unsupported key: ${key}` };
162
+ }
163
+ const parsed = VibeRepoConfigSchema.parse(updated);
164
+ writeRepoConfig(configFile, parsed);
165
+ return { ok: true, config: parsed };
166
+ }
167
+ catch (e) {
168
+ const message = e instanceof Error ? e.message : String(e);
169
+ return { ok: false, error: message };
170
+ }
171
+ }
@@ -0,0 +1,33 @@
1
+ import { spawnSync } from "node:child_process";
2
+ export function getGitRoot(cwd) {
3
+ const result = spawnSync("git", ["rev-parse", "--show-toplevel"], {
4
+ cwd,
5
+ encoding: "utf-8",
6
+ stdio: ["ignore", "pipe", "pipe"],
7
+ });
8
+ if (result.status !== 0)
9
+ return null;
10
+ const out = (result.stdout ?? "").trim();
11
+ return out.length > 0 ? out : null;
12
+ }
13
+ export function getGitHooksPath(cwd) {
14
+ const result = spawnSync("git", ["config", "--local", "--get", "core.hooksPath"], {
15
+ cwd,
16
+ encoding: "utf-8",
17
+ stdio: ["ignore", "pipe", "pipe"],
18
+ });
19
+ if (result.status !== 0)
20
+ return null;
21
+ const out = (result.stdout ?? "").trim();
22
+ return out.length > 0 ? out : null;
23
+ }
24
+ export function setGitHooksPath(cwd, hooksPath) {
25
+ const result = spawnSync("git", ["config", "--local", "core.hooksPath", hooksPath], {
26
+ cwd,
27
+ encoding: "utf-8",
28
+ stdio: ["ignore", "pipe", "pipe"],
29
+ });
30
+ if (result.status === 0)
31
+ return { ok: true };
32
+ return { ok: false, error: (result.stderr ?? "git config failed").trim() };
33
+ }
@@ -0,0 +1,110 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { defaultRepoConfig, isVibeRepo, writeRepoConfig } from "./config.js";
4
+ import { hasBashRuntime } from "./bash.js";
5
+ import { setGitHooksPath } from "./git.js";
6
+ import { getVibeRepoPaths } from "./paths.js";
7
+ import { GITHUB_ACTIONS_LOCAL_MODE_GUARD_WORKFLOW_TEMPLATE, GITLEAKS_CONFIG_TEMPLATE, PRE_PUSH_HOOK_TEMPLATE, VALIDATE_SH_TEMPLATE } from "./templates.js";
8
+ function ensureGitignoreLine(gitignorePath, line) {
9
+ const normalizedLine = line.endsWith("\n") ? line : `${line}\n`;
10
+ if (!fs.existsSync(gitignorePath)) {
11
+ fs.writeFileSync(gitignorePath, normalizedLine, "utf-8");
12
+ return;
13
+ }
14
+ const current = fs.readFileSync(gitignorePath, "utf-8");
15
+ const lines = new Set(current.split(/\r?\n/));
16
+ const candidate = line.replace(/\r?\n$/, "");
17
+ if (lines.has(candidate))
18
+ return;
19
+ const suffix = current.endsWith("\n") ? "" : "\n";
20
+ fs.writeFileSync(gitignorePath, `${current}${suffix}${line}\n`, "utf-8");
21
+ }
22
+ function chmodExecutable(filePath) {
23
+ try {
24
+ fs.chmodSync(filePath, 0o755);
25
+ }
26
+ catch {
27
+ // Best-effort (Windows)
28
+ }
29
+ }
30
+ export function initLocalModeRepo(repoRoot, opts) {
31
+ const paths = getVibeRepoPaths(repoRoot);
32
+ const created = [];
33
+ const updated = [];
34
+ const notes = [];
35
+ const force = opts?.force ?? false;
36
+ const installHooks = opts?.installHooks ?? true;
37
+ const installCi = opts?.installCi ?? false;
38
+ const ciFailOnWarn = opts?.ciFailOnWarn ?? false;
39
+ fs.mkdirSync(paths.stateDir, { recursive: true });
40
+ fs.mkdirSync(paths.hooksDir, { recursive: true });
41
+ fs.mkdirSync(paths.libDir, { recursive: true });
42
+ fs.mkdirSync(paths.archiveDir, { recursive: true });
43
+ fs.mkdirSync(path.dirname(paths.gitleaksConfigFile), { recursive: true });
44
+ const nowIso = new Date().toISOString();
45
+ const projectName = path.basename(repoRoot);
46
+ if (!fs.existsSync(paths.configFile) || force) {
47
+ const config = defaultRepoConfig(projectName, nowIso);
48
+ writeRepoConfig(paths.configFile, config);
49
+ (force ? updated : created).push(paths.configFile);
50
+ }
51
+ if (!fs.existsSync(paths.validateScript) || force) {
52
+ fs.writeFileSync(paths.validateScript, VALIDATE_SH_TEMPLATE, "utf-8");
53
+ chmodExecutable(paths.validateScript);
54
+ (force ? updated : created).push(paths.validateScript);
55
+ }
56
+ if (!fs.existsSync(paths.gitleaksConfigFile) || force) {
57
+ fs.writeFileSync(paths.gitleaksConfigFile, GITLEAKS_CONFIG_TEMPLATE, "utf-8");
58
+ (force ? updated : created).push(paths.gitleaksConfigFile);
59
+ }
60
+ if (!fs.existsSync(paths.prePushHook) || force) {
61
+ fs.writeFileSync(paths.prePushHook, PRE_PUSH_HOOK_TEMPLATE, "utf-8");
62
+ chmodExecutable(paths.prePushHook);
63
+ (force ? updated : created).push(paths.prePushHook);
64
+ }
65
+ if (installCi) {
66
+ const workflowDir = path.dirname(paths.ciWorkflowFile);
67
+ fs.mkdirSync(workflowDir, { recursive: true });
68
+ if (!fs.existsSync(paths.ciWorkflowFile) || force) {
69
+ const workflow = ciFailOnWarn
70
+ ? GITHUB_ACTIONS_LOCAL_MODE_GUARD_WORKFLOW_TEMPLATE.replace('VIBE_FAIL_ON_WARN: "false"', 'VIBE_FAIL_ON_WARN: "true"')
71
+ : GITHUB_ACTIONS_LOCAL_MODE_GUARD_WORKFLOW_TEMPLATE;
72
+ fs.writeFileSync(paths.ciWorkflowFile, workflow, "utf-8");
73
+ (force ? updated : created).push(paths.ciWorkflowFile);
74
+ }
75
+ }
76
+ ensureGitignoreLine(path.join(repoRoot, ".gitignore"), ".vibe/state/");
77
+ if (installHooks) {
78
+ const set = setGitHooksPath(repoRoot, ".vibe/hooks");
79
+ if (set.ok) {
80
+ notes.push("git core.hooksPath = .vibe/hooks");
81
+ }
82
+ else {
83
+ notes.push(`git core.hooksPath setup skipped: ${set.error}`);
84
+ }
85
+ }
86
+ if (installCi) {
87
+ notes.push(`GitHub Actions workflow: ${path.relative(repoRoot, paths.ciWorkflowFile)}`);
88
+ }
89
+ if (!isVibeRepo(repoRoot)) {
90
+ // should never happen given we created it; but keep safe.
91
+ notes.push(".vibe directory missing after init (unexpected).");
92
+ }
93
+ // Best-effort sanity check: ensure bash exists for hooks/validate.
94
+ if (!hasBashRuntime()) {
95
+ notes.push("bash not found: local guard scripts may not run (install Git Bash or WSL).");
96
+ }
97
+ // P0-3: Bootstrap manifest 생성 (self-block 방지)
98
+ const allManaged = [...created, ...updated].map(p => path.relative(repoRoot, p).replace(/\\/g, "/"));
99
+ const manifest = {
100
+ schema_version: 1,
101
+ created_at: new Date().toISOString(),
102
+ expires_at: new Date(Date.now() + 3600_000).toISOString(), // 1시간
103
+ consumed: false,
104
+ reason: "SYSTEM_BOOTSTRAP",
105
+ managed_paths: allManaged,
106
+ };
107
+ fs.writeFileSync(paths.bootstrapManifest, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
108
+ created.push(paths.bootstrapManifest);
109
+ return { created, updated, notes };
110
+ }
@@ -0,0 +1,24 @@
1
+ import * as path from "node:path";
2
+ export function getVibeRepoPaths(repoRoot) {
3
+ const vibeDir = path.join(repoRoot, ".vibe");
4
+ const stateDir = path.join(vibeDir, "state");
5
+ const hooksDir = path.join(vibeDir, "hooks");
6
+ const libDir = path.join(vibeDir, "lib");
7
+ const ciWorkflowFile = path.join(repoRoot, ".github", "workflows", "vibe-local-mode-guard.yml");
8
+ const gitleaksConfigFile = path.join(repoRoot, "config", "gitleaks", ".gitleaks.toml");
9
+ return {
10
+ repoRoot,
11
+ vibeDir,
12
+ configFile: path.join(vibeDir, "config.json"),
13
+ stateDir,
14
+ currentWorkOrderFile: path.join(stateDir, "current_work_order.json"),
15
+ archiveDir: path.join(vibeDir, "archive"),
16
+ hooksDir,
17
+ libDir,
18
+ validateScript: path.join(libDir, "validate.sh"),
19
+ prePushHook: path.join(hooksDir, "pre-push"),
20
+ ciWorkflowFile,
21
+ gitleaksConfigFile,
22
+ bootstrapManifest: path.join(vibeDir, "bootstrap_manifest.json"),
23
+ };
24
+ }