@vreko/cli 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +45 -0
  3. package/dist/CeremonyView-LQS7FTMK.js +134 -0
  4. package/dist/CeremonyView-LQS7FTMK.js.map +1 -0
  5. package/dist/InitApp-7K5DTYSW.js +1479 -0
  6. package/dist/InitApp-7K5DTYSW.js.map +1 -0
  7. package/dist/SkippedTestDetector-PJSKSOZR.js +7 -0
  8. package/dist/SkippedTestDetector-PJSKSOZR.js.map +1 -0
  9. package/dist/TuiApp-FX23XQBK.js +8 -0
  10. package/dist/TuiApp-FX23XQBK.js.map +1 -0
  11. package/dist/analysis-ABEO6RTN.js +8 -0
  12. package/dist/analysis-ABEO6RTN.js.map +1 -0
  13. package/dist/auth-XNBEBNPY.js +7669 -0
  14. package/dist/auth-XNBEBNPY.js.map +1 -0
  15. package/dist/ceremony-M7CXVBVA.js +45 -0
  16. package/dist/ceremony-M7CXVBVA.js.map +1 -0
  17. package/dist/chunk-A3QSZJPD.js +3147 -0
  18. package/dist/chunk-A3QSZJPD.js.map +1 -0
  19. package/dist/chunk-ASGZ5B6C.js +3969 -0
  20. package/dist/chunk-ASGZ5B6C.js.map +1 -0
  21. package/dist/chunk-DMXC2JTC.js +58 -0
  22. package/dist/chunk-DMXC2JTC.js.map +1 -0
  23. package/dist/chunk-EEBSK2IH.js +161 -0
  24. package/dist/chunk-EEBSK2IH.js.map +1 -0
  25. package/dist/chunk-EWOJGXRX.js +22 -0
  26. package/dist/chunk-EWOJGXRX.js.map +1 -0
  27. package/dist/chunk-F7GEJLP7.js +2389 -0
  28. package/dist/chunk-F7GEJLP7.js.map +1 -0
  29. package/dist/chunk-GOYL3F4T.js +605 -0
  30. package/dist/chunk-GOYL3F4T.js.map +1 -0
  31. package/dist/chunk-GRMRYWYS.js +17 -0
  32. package/dist/chunk-GRMRYWYS.js.map +1 -0
  33. package/dist/chunk-GSUGROXB.js +1951 -0
  34. package/dist/chunk-GSUGROXB.js.map +1 -0
  35. package/dist/chunk-H7773ONB.js +50 -0
  36. package/dist/chunk-H7773ONB.js.map +1 -0
  37. package/dist/chunk-HFQHU5LC.js +445 -0
  38. package/dist/chunk-HFQHU5LC.js.map +1 -0
  39. package/dist/chunk-IVHUBLJD.js +318 -0
  40. package/dist/chunk-IVHUBLJD.js.map +1 -0
  41. package/dist/chunk-KJWKY4L4.js +14 -0
  42. package/dist/chunk-KJWKY4L4.js.map +1 -0
  43. package/dist/chunk-MJVY2XUN.js +1793 -0
  44. package/dist/chunk-MJVY2XUN.js.map +1 -0
  45. package/dist/chunk-QWZVCJII.js +1797 -0
  46. package/dist/chunk-QWZVCJII.js.map +1 -0
  47. package/dist/chunk-VTSNRV3V.js +3237 -0
  48. package/dist/chunk-VTSNRV3V.js.map +1 -0
  49. package/dist/chunk-W5B4GTXR.js +1466 -0
  50. package/dist/chunk-W5B4GTXR.js.map +1 -0
  51. package/dist/chunk-WZEZLVOW.js +4995 -0
  52. package/dist/chunk-WZEZLVOW.js.map +1 -0
  53. package/dist/chunk-YPTTIXKC.js +199 -0
  54. package/dist/chunk-YPTTIXKC.js.map +1 -0
  55. package/dist/chunk-Z55UGM6X.js +6360 -0
  56. package/dist/chunk-Z55UGM6X.js.map +1 -0
  57. package/dist/chunk-ZIIRQODJ.js +110 -0
  58. package/dist/chunk-ZIIRQODJ.js.map +1 -0
  59. package/dist/chunk-ZSUQ4FMB.js +77 -0
  60. package/dist/chunk-ZSUQ4FMB.js.map +1 -0
  61. package/dist/client-JMTSZS3V.js +10 -0
  62. package/dist/client-JMTSZS3V.js.map +1 -0
  63. package/dist/deprecated-snap.js +19 -0
  64. package/dist/deprecated-snap.js.map +1 -0
  65. package/dist/dist-2KWBZFLA.js +14 -0
  66. package/dist/dist-2KWBZFLA.js.map +1 -0
  67. package/dist/dist-5ZYKNNU3.js +7 -0
  68. package/dist/dist-5ZYKNNU3.js.map +1 -0
  69. package/dist/dist-CP3RFHPI.js +11 -0
  70. package/dist/dist-CP3RFHPI.js.map +1 -0
  71. package/dist/gecko-53ITAGG6.js +56 -0
  72. package/dist/gecko-53ITAGG6.js.map +1 -0
  73. package/dist/guards-QAFC64NO.js +7 -0
  74. package/dist/guards-QAFC64NO.js.map +1 -0
  75. package/dist/index.js +57785 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/init-command-246JIVXM.js +7 -0
  78. package/dist/init-command-246JIVXM.js.map +1 -0
  79. package/dist/init-core-KAI7LCXZ.js +12 -0
  80. package/dist/init-core-KAI7LCXZ.js.map +1 -0
  81. package/dist/init-scan-RZNYDTUV.js +1919 -0
  82. package/dist/init-scan-RZNYDTUV.js.map +1 -0
  83. package/dist/local-service-adapter-6KNN6WQL.js +8 -0
  84. package/dist/local-service-adapter-6KNN6WQL.js.map +1 -0
  85. package/dist/secure-credentials-JXWAQLS2.js +306 -0
  86. package/dist/secure-credentials-JXWAQLS2.js.map +1 -0
  87. package/dist/tui-TPJPUS2R.js +111 -0
  88. package/dist/tui-TPJPUS2R.js.map +1 -0
  89. package/dist/vreko-dir-O3RLG7PI.js +8 -0
  90. package/dist/vreko-dir-O3RLG7PI.js.map +1 -0
  91. package/package.json +132 -0
  92. package/scripts/check-banned-words.ts +152 -0
  93. package/scripts/hooks/posttooluse-file-notify.sh +108 -0
  94. package/scripts/hooks/pretooluse-fragile-guard.sh +82 -0
  95. package/scripts/post-install-notice.js +24 -0
  96. package/scripts/postinstall.mjs +84 -0
  97. package/scripts/preuninstall.mjs +34 -0
  98. package/scripts/verify-jsx-transform.mjs +55 -0
@@ -0,0 +1,1797 @@
1
+ #!/usr/bin/env node
2
+ import { cliState } from './chunk-GRMRYWYS.js';
3
+ import { getDaemonClient, connectToDaemon } from './chunk-EEBSK2IH.js';
4
+ import { getServicePidPath } from './chunk-GSUGROXB.js';
5
+ import { resolveVrekoBinaryPath, detectAIClients, getVrekoMCPConfig, writeClientConfig } from './chunk-MJVY2XUN.js';
6
+ import { __name, __require } from './chunk-EWOJGXRX.js';
7
+ import { execFileSync } from 'child_process';
8
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, lstatSync, copyFileSync, chmodSync, rmSync, statSync, appendFileSync } from 'fs';
9
+ import { readdir } from 'fs/promises';
10
+ import { homedir } from 'os';
11
+ import { join, dirname, normalize, resolve, basename, extname } from 'path';
12
+ import * as clack from '@clack/prompts';
13
+ import chalk from 'chalk';
14
+ import { Command } from 'commander';
15
+ import ora from 'ora';
16
+ import { createHash } from 'crypto';
17
+ import { fileURLToPath } from 'url';
18
+
19
+ process.env.VREKO_CLI='true';process.env.NODE_NO_WARNINGS='1';
20
+ function generateClaudeIntegration(config, baseline) {
21
+ const { workspacePath, overwrite = false } = config;
22
+ const result = {
23
+ filesWritten: [],
24
+ filesSkipped: [],
25
+ intelligenceAvailable: false,
26
+ fragileFilesIncluded: 0,
27
+ coChangePatternsIncluded: 0,
28
+ globalSettingsUpdated: false
29
+ };
30
+ const fragileFiles = (baseline?.fragileFiles ?? []).filter((f) => f.compositeScore >= 30).sort((a, b) => b.compositeScore - a.compositeScore).slice(0, 15).map((f) => ({
31
+ path: f.path,
32
+ score: f.compositeScore / 100,
33
+ level: f.compositeScore >= 80 ? "critical" : f.compositeScore >= 60 ? "fragile" : "moderate"
34
+ }));
35
+ const coChangePairs = (baseline?.coChangeClusters ?? []).filter((c) => c.files.length >= 2 && c.coOccurrenceRate >= 0.5).sort((a, b) => b.coOccurrenceRate - a.coOccurrenceRate).slice(0, 10).map((c) => ({
36
+ fileA: c.files[0],
37
+ fileB: c.files[1],
38
+ frequency: c.coOccurrenceRate
39
+ }));
40
+ result.intelligenceAvailable = fragileFiles.length > 0 || coChangePairs.length > 0;
41
+ result.fragileFilesIncluded = fragileFiles.length;
42
+ result.coChangePatternsIncluded = coChangePairs.length;
43
+ const files = [
44
+ {
45
+ relativePath: ".mcp.json",
46
+ content: buildMcpJson(config)
47
+ },
48
+ {
49
+ relativePath: ".claude/agents/vreko-preflight.md",
50
+ content: buildPreflightAgent(fragileFiles, coChangePairs)
51
+ },
52
+ {
53
+ relativePath: ".claude/agents/vreko-session.md",
54
+ content: VREKO_SESSION_AGENT
55
+ },
56
+ {
57
+ relativePath: ".claude/commands/snap-check.md",
58
+ content: SNAP_CHECK_COMMAND
59
+ }
60
+ ];
61
+ for (const file of files) {
62
+ const fullPath = join(workspacePath, file.relativePath);
63
+ const dir = join(fullPath, "..");
64
+ if (existsSync(fullPath) && !overwrite) {
65
+ const existing = readFileSync(fullPath, "utf-8");
66
+ const existingHash = createHash("sha256").update(existing).digest("hex");
67
+ const newHash = createHash("sha256").update(file.content).digest("hex");
68
+ const suffix = existingHash !== newHash ? " (modified, use --force to update)" : "";
69
+ result.filesSkipped.push(`${file.relativePath}${suffix}`);
70
+ continue;
71
+ }
72
+ mkdirSync(dir, {
73
+ recursive: true
74
+ });
75
+ writeFileSync(fullPath, file.content, "utf-8");
76
+ result.filesWritten.push(file.relativePath);
77
+ }
78
+ result.globalSettingsUpdated = writeVrekoToClaudeCodeGlobalSettings();
79
+ return result;
80
+ }
81
+ __name(generateClaudeIntegration, "generateClaudeIntegration");
82
+ function buildMcpJson(config) {
83
+ const { command, args: cmdArgs } = resolveMcpCommand(config.workspacePath);
84
+ const servers = {
85
+ vreko: {
86
+ type: "stdio",
87
+ command,
88
+ args: cmdArgs,
89
+ instructions: "Vreko provides codebase intelligence. Use vreko_pulse to check risk before modifying files. Use vreko_learn to record patterns. Use vreko_end to close sessions."
90
+ }
91
+ };
92
+ if (config.includeChannel === true) {
93
+ const channelArgs = [
94
+ ...cmdArgs
95
+ ];
96
+ channelArgs.push("--channel");
97
+ servers["vreko-channel"] = {
98
+ type: "stdio",
99
+ command,
100
+ args: channelArgs,
101
+ instructions: "Vreko intelligence channel. Pushes real-time warnings about fragile files and risk spikes. Requires: claude --channels vreko-channel"
102
+ };
103
+ }
104
+ return `${JSON.stringify({
105
+ mcpServers: servers
106
+ }, null, 2)}
107
+ `;
108
+ }
109
+ __name(buildMcpJson, "buildMcpJson");
110
+ function resolveMcpCommand(workspacePath) {
111
+ return {
112
+ command: resolveVrekoBinaryPath(),
113
+ args: [
114
+ "mcp",
115
+ "--stdio",
116
+ "--workspace",
117
+ workspacePath
118
+ ]
119
+ };
120
+ }
121
+ __name(resolveMcpCommand, "resolveMcpCommand");
122
+ function writeVrekoToClaudeCodeGlobalSettings() {
123
+ const settingsPath = join(homedir(), ".claude", "settings.json");
124
+ if (!existsSync(settingsPath)) {
125
+ return false;
126
+ }
127
+ let settings = {};
128
+ try {
129
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
130
+ } catch {
131
+ return false;
132
+ }
133
+ const mcpServers = settings.mcpServers ?? {};
134
+ const command = resolveVrekoBinaryPath();
135
+ const existing = mcpServers.vreko;
136
+ if (existing?.command === command) {
137
+ return false;
138
+ }
139
+ mcpServers.vreko = {
140
+ command,
141
+ args: [
142
+ "mcp",
143
+ "--stdio"
144
+ ]
145
+ };
146
+ settings.mcpServers = mcpServers;
147
+ try {
148
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
149
+ `, "utf-8");
150
+ return true;
151
+ } catch {
152
+ return false;
153
+ }
154
+ }
155
+ __name(writeVrekoToClaudeCodeGlobalSettings, "writeVrekoToClaudeCodeGlobalSettings");
156
+ function buildPreflightAgent(fragileFiles, coChangePairs) {
157
+ let fragileSection;
158
+ if (fragileFiles.length > 0) {
159
+ const lines = fragileFiles.map((f) => `- \`${f.path}\` - fragility: ${f.level} (score: ${f.score.toFixed(2)})`).join("\n");
160
+ fragileSection = `## Known Fragile Files in This Codebase
161
+
162
+ The following files have high rollback rates or frequent issues:
163
+
164
+ ${lines}
165
+
166
+ If the task involves any of these files, always recommend creating
167
+ a snapshot before modification.`;
168
+ } else {
169
+ fragileSection = `## Codebase Intelligence
170
+
171
+ Vreko is still learning about this codebase. Use vreko_pulse
172
+ to get real-time risk assessment for any files being modified.
173
+ Intelligence will improve as more sessions are tracked.`;
174
+ }
175
+ let coChangeSection = "";
176
+ if (coChangePairs.length > 0) {
177
+ const lines = coChangePairs.map((p) => `- \`${p.fileA}\` \u2194 \`${p.fileB}\` (${(p.frequency * 100).toFixed(0)}% co-change rate)`).join("\n");
178
+ coChangeSection = `
179
+
180
+ ## Co-Change Patterns
181
+
182
+ These files historically change together. If modifying one,
183
+ check whether the others also need updates:
184
+
185
+ ${lines}`;
186
+ }
187
+ return `---
188
+ name: vreko-preflight
189
+ description: >
190
+ Run before implementing changes that touch multiple files
191
+ or modify config/infrastructure. Queries Vreko for risk
192
+ context and known fragile patterns in this codebase.
193
+ tools:
194
+ - Read
195
+ - Grep
196
+ - Glob
197
+ - mcp__vreko__vreko_pulse
198
+ ---
199
+
200
+ You are a preflight check agent for this codebase. Vreko has
201
+ accumulated intelligence about which files are risky and which
202
+ files always change together.
203
+
204
+ Before the parent agent modifies files, you:
205
+
206
+ 1. Call vreko_pulse with the workspace path and list of files about to change
207
+ 2. Check the risk assessment in the response
208
+ 3. Flag any files with HIGH or CRITICAL fragility
209
+ 4. Surface co-change patterns (files that must change together)
210
+ 5. Return a structured summary to the parent agent:
211
+ - Files safe to modify in parallel
212
+ - Files requiring sequential, careful changes
213
+ - Known pitfalls from codebase history
214
+ - Whether a snapshot is recommended before proceeding
215
+
216
+ Do NOT modify any files. Read-only analysis only.
217
+
218
+ ${fragileSection}${coChangeSection}
219
+ `;
220
+ }
221
+ __name(buildPreflightAgent, "buildPreflightAgent");
222
+ var VREKO_SESSION_AGENT = `---
223
+ name: vreko-session
224
+ description: >
225
+ Manage Vreko session lifecycle. Use at the start and
226
+ end of significant implementation work to capture context
227
+ and trigger intelligence collection.
228
+ tools:
229
+ - mcp__vreko__vreko
230
+ - mcp__vreko__vreko_learn
231
+ - mcp__vreko__vreko_end
232
+ ---
233
+
234
+ You manage Vreko sessions for this codebase.
235
+
236
+ When starting work:
237
+ - Call vreko to begin a session with a descriptive task name
238
+ - Note the session context for the parent agent
239
+
240
+ When completing work:
241
+ - Call vreko_learn with any patterns discovered during implementation:
242
+ - Files that needed to change together (co-change pattern)
243
+ - Config that was fragile or surprising (fragile pattern)
244
+ - Dependencies that weren't obvious (dependency pattern)
245
+ - Conventions the codebase follows (convention pattern)
246
+ - Call vreko_end to close the session
247
+
248
+ Capture learnings in this format:
249
+ - Pattern type: co-change | fragile | dependency | convention
250
+ - Affected files: list of file paths
251
+ - Description: what the implementing agent discovered
252
+
253
+ The more patterns captured, the better Vreko's intelligence
254
+ becomes for future sessions.
255
+ `;
256
+ var SNAP_CHECK_COMMAND = `---
257
+ description: Check Vreko risk context for files you're about to change
258
+ argument-hint: <file paths or description of planned changes>
259
+ ---
260
+
261
+ Query Vreko intelligence for the specified files or task.
262
+
263
+ 1. Call the vreko_pulse MCP tool with the provided context
264
+ 2. Display risk scores, fragile file warnings, and relevant history
265
+ 3. If any file has fragility level "fragile" or "critical", warn explicitly
266
+ 4. List co-change groups - files that should be modified together
267
+ 5. Recommend whether to create a manual snapshot before proceeding
268
+ 6. If fragile files are involved, suggest the vreko-preflight agent
269
+ for more detailed analysis
270
+ `;
271
+ function validateWorkspacePath(workspacePath) {
272
+ try {
273
+ const normalizedPath = normalize(workspacePath);
274
+ const absolutePath = resolve(normalizedPath);
275
+ if (!absolutePath.startsWith(process.cwd()) && !absolutePath.startsWith("/")) {
276
+ return {
277
+ valid: false,
278
+ root: "",
279
+ error: "Invalid workspace path"
280
+ };
281
+ }
282
+ const hasGit = existsSync(resolve(absolutePath, ".git"));
283
+ const hasPackageJson = existsSync(resolve(absolutePath, "package.json"));
284
+ const hasVreko = existsSync(resolve(absolutePath, ".vreko"));
285
+ if (!hasGit && !hasPackageJson && !hasVreko) {
286
+ return {
287
+ valid: false,
288
+ root: absolutePath,
289
+ error: "Workspace must contain at least one marker: .git, package.json, or .vreko"
290
+ };
291
+ }
292
+ try {
293
+ const stat = lstatSync(absolutePath);
294
+ if (stat.isSymbolicLink()) {
295
+ return {
296
+ valid: false,
297
+ root: absolutePath,
298
+ error: "Workspace path cannot be a symbolic link"
299
+ };
300
+ }
301
+ } catch {
302
+ return {
303
+ valid: false,
304
+ root: absolutePath,
305
+ error: "Cannot access workspace path"
306
+ };
307
+ }
308
+ return {
309
+ valid: true,
310
+ root: absolutePath
311
+ };
312
+ } catch (error) {
313
+ return {
314
+ valid: false,
315
+ root: "",
316
+ error: error instanceof Error ? error.message : "Unknown error validating workspace"
317
+ };
318
+ }
319
+ }
320
+ __name(validateWorkspacePath, "validateWorkspacePath");
321
+ function resolveWorkspaceRoot(explicitPath) {
322
+ if (explicitPath) {
323
+ const validation = validateWorkspacePath(explicitPath);
324
+ if (validation.valid) {
325
+ return validation;
326
+ }
327
+ }
328
+ let currentPath = resolve(process.cwd());
329
+ const maxIterations = 50;
330
+ for (let i = 0; i < maxIterations; i++) {
331
+ const hasMarker = existsSync(resolve(currentPath, ".git")) || existsSync(resolve(currentPath, "package.json")) || existsSync(resolve(currentPath, ".vreko"));
332
+ if (hasMarker) {
333
+ return validateWorkspacePath(currentPath);
334
+ }
335
+ const parent = resolve(currentPath, "..");
336
+ if (parent === currentPath) {
337
+ break;
338
+ }
339
+ currentPath = parent;
340
+ }
341
+ return validateWorkspacePath(process.cwd());
342
+ }
343
+ __name(resolveWorkspaceRoot, "resolveWorkspaceRoot");
344
+ function findWorkspaceRoot(cwd) {
345
+ let dir = cwd;
346
+ while (dir !== "/") {
347
+ if (existsSync(join(dir, ".vreko"))) {
348
+ return dir;
349
+ }
350
+ const parent = join(dir, "..");
351
+ if (parent === dir) {
352
+ break;
353
+ }
354
+ dir = parent;
355
+ }
356
+ return null;
357
+ }
358
+ __name(findWorkspaceRoot, "findWorkspaceRoot");
359
+ function findGitRoot(cwd) {
360
+ try {
361
+ const { execSync } = __require("child_process");
362
+ return execSync("git rev-parse --show-toplevel", {
363
+ cwd,
364
+ encoding: "utf-8",
365
+ stdio: [
366
+ "pipe",
367
+ "pipe",
368
+ "pipe"
369
+ ]
370
+ }).trim();
371
+ } catch {
372
+ return null;
373
+ }
374
+ }
375
+ __name(findGitRoot, "findGitRoot");
376
+ var HOOK_SCRIPT_SRC = join(dirname(fileURLToPath(import.meta.url)), "../scripts/hooks/pretooluse-fragile-guard.sh");
377
+ var VREKO_HOOK_COMMAND = ".claude/hooks/vreko-fragile-guard.sh";
378
+ var VREKO_HOOK_MARKER = "vreko-fragile-guard.sh";
379
+ var HOOK_ENTRY = {
380
+ matcher: "Edit|Write|MultiEdit",
381
+ hooks: [
382
+ {
383
+ type: "command",
384
+ command: VREKO_HOOK_COMMAND
385
+ }
386
+ ]
387
+ };
388
+ var POST_HOOK_SCRIPT_SRC = join(dirname(fileURLToPath(import.meta.url)), "../scripts/hooks/posttooluse-file-notify.sh");
389
+ var POST_HOOK_COMMAND = ".claude/hooks/vreko-file-notify.sh";
390
+ var POST_HOOK_MARKER = "vreko-file-notify.sh";
391
+ var POST_HOOK_ENTRY = {
392
+ matcher: "Edit|Write|MultiEdit",
393
+ hooks: [
394
+ {
395
+ type: "command",
396
+ command: POST_HOOK_COMMAND
397
+ }
398
+ ]
399
+ };
400
+ function readSettings(settingsPath) {
401
+ if (!existsSync(settingsPath)) {
402
+ return {};
403
+ }
404
+ try {
405
+ return JSON.parse(readFileSync(settingsPath, "utf-8"));
406
+ } catch (err) {
407
+ console.error(`[vreko hooks] Failed to parse ${settingsPath}:`, err);
408
+ return {};
409
+ }
410
+ }
411
+ __name(readSettings, "readSettings");
412
+ function writeSettings(settingsPath, settings) {
413
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
414
+ `, "utf-8");
415
+ }
416
+ __name(writeSettings, "writeSettings");
417
+ function readVrekoConfig(workspace) {
418
+ const configPath = join(workspace, ".vreko", "config.json");
419
+ if (!existsSync(configPath)) {
420
+ return {};
421
+ }
422
+ try {
423
+ return JSON.parse(readFileSync(configPath, "utf-8"));
424
+ } catch (err) {
425
+ console.error("[vreko hooks] Failed to parse .vreko/config.json:", err);
426
+ return {};
427
+ }
428
+ }
429
+ __name(readVrekoConfig, "readVrekoConfig");
430
+ function writeVrekoConfig(workspace, config) {
431
+ const configDir = join(workspace, ".vreko");
432
+ if (!existsSync(configDir)) {
433
+ mkdirSync(configDir, {
434
+ recursive: true
435
+ });
436
+ }
437
+ writeFileSync(join(configDir, "config.json"), `${JSON.stringify(config, null, 2)}
438
+ `, "utf-8");
439
+ }
440
+ __name(writeVrekoConfig, "writeVrekoConfig");
441
+ function isVrekoHookPresent(preToolUseArray) {
442
+ return preToolUseArray.some((entry) => {
443
+ if (typeof entry !== "object" || entry === null) {
444
+ return false;
445
+ }
446
+ const e = entry;
447
+ const hooks = e.hooks;
448
+ if (!Array.isArray(hooks)) {
449
+ return false;
450
+ }
451
+ return hooks.some((h) => {
452
+ if (typeof h !== "object" || h === null) {
453
+ return false;
454
+ }
455
+ const hook = h;
456
+ return typeof hook.command === "string" && hook.command.includes(VREKO_HOOK_MARKER);
457
+ });
458
+ });
459
+ }
460
+ __name(isVrekoHookPresent, "isVrekoHookPresent");
461
+ function isVrekoPostHookPresent(postToolUseArray) {
462
+ return postToolUseArray.some((entry) => {
463
+ if (typeof entry !== "object" || entry === null) {
464
+ return false;
465
+ }
466
+ const e = entry;
467
+ const hooks = e.hooks;
468
+ if (!Array.isArray(hooks)) {
469
+ return false;
470
+ }
471
+ return hooks.some((h) => {
472
+ if (typeof h !== "object" || h === null) {
473
+ return false;
474
+ }
475
+ const hook = h;
476
+ return typeof hook.command === "string" && hook.command.includes(POST_HOOK_MARKER);
477
+ });
478
+ });
479
+ }
480
+ __name(isVrekoPostHookPresent, "isVrekoPostHookPresent");
481
+ function copyHookScripts(cwd) {
482
+ const hooksDir = join(cwd, ".claude", "hooks");
483
+ const hookDest = join(cwd, VREKO_HOOK_COMMAND);
484
+ const postHookDest = join(cwd, POST_HOOK_COMMAND);
485
+ if (!existsSync(HOOK_SCRIPT_SRC)) {
486
+ throw new Error(`Hook script not found at ${HOOK_SCRIPT_SRC}`);
487
+ }
488
+ if (!existsSync(hooksDir)) {
489
+ mkdirSync(hooksDir, {
490
+ recursive: true
491
+ });
492
+ }
493
+ copyFileSync(HOOK_SCRIPT_SRC, hookDest);
494
+ chmodSync(hookDest, 493);
495
+ if (existsSync(POST_HOOK_SCRIPT_SRC)) {
496
+ copyFileSync(POST_HOOK_SCRIPT_SRC, postHookDest);
497
+ chmodSync(postHookDest, 493);
498
+ } else {
499
+ console.error(`[vreko hooks] PostToolUse hook script not found at ${POST_HOOK_SCRIPT_SRC}`);
500
+ }
501
+ return {
502
+ hookDest,
503
+ postHookDest
504
+ };
505
+ }
506
+ __name(copyHookScripts, "copyHookScripts");
507
+ function mergeHookEntries(settingsPath) {
508
+ const settings = readSettings(settingsPath);
509
+ const hooks = settings.hooks ?? {};
510
+ const preToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
511
+ const postToolUse = Array.isArray(hooks.PostToolUse) ? hooks.PostToolUse : [];
512
+ if (!isVrekoHookPresent(preToolUse)) preToolUse.push(HOOK_ENTRY);
513
+ if (!isVrekoPostHookPresent(postToolUse)) postToolUse.push(POST_HOOK_ENTRY);
514
+ hooks.PreToolUse = preToolUse;
515
+ hooks.PostToolUse = postToolUse;
516
+ settings.hooks = hooks;
517
+ writeSettings(settingsPath, settings);
518
+ }
519
+ __name(mergeHookEntries, "mergeHookEntries");
520
+ function writeVrekoConfigHooks(cwd) {
521
+ const config = readVrekoConfig(cwd);
522
+ const cfgHooks = config.hooks ?? {};
523
+ cfgHooks["claude-code"] = {
524
+ installed: true,
525
+ mode: "advisory",
526
+ fragileThreshold: 2,
527
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
528
+ postToolUseInstalled: true
529
+ };
530
+ config.hooks = cfgHooks;
531
+ writeVrekoConfig(cwd, config);
532
+ }
533
+ __name(writeVrekoConfigHooks, "writeVrekoConfigHooks");
534
+ async function installHook(tool, workspace) {
535
+ if (tool !== "claude-code") {
536
+ throw new Error(`Hook install for '${tool}' is not yet supported. Only 'claude-code' is supported.`);
537
+ }
538
+ const cwd = workspace ?? process.cwd();
539
+ const settingsPath = join(cwd, ".claude", "settings.json");
540
+ const { hookDest, postHookDest } = copyHookScripts(cwd);
541
+ mergeHookEntries(settingsPath);
542
+ writeVrekoConfigHooks(cwd);
543
+ console.log("Vreko hooks installed for Claude Code");
544
+ console.log(` PreToolUse hook: ${hookDest}`);
545
+ console.log(` Settings: ${settingsPath}`);
546
+ }
547
+ __name(installHook, "installHook");
548
+ async function uninstallHook(tool, workspace) {
549
+ if (tool !== "claude-code") {
550
+ console.error(`[vreko hooks] Hook uninstall for '${tool}' is not yet supported.`);
551
+ process.exit(1);
552
+ }
553
+ const cwd = workspace ?? process.cwd();
554
+ const settingsPath = join(cwd, ".claude", "settings.json");
555
+ const hookDest = join(cwd, VREKO_HOOK_COMMAND);
556
+ if (existsSync(settingsPath)) {
557
+ try {
558
+ const settings = readSettings(settingsPath);
559
+ const hooks = settings.hooks ?? {};
560
+ if (Array.isArray(hooks.PreToolUse)) {
561
+ hooks.PreToolUse = hooks.PreToolUse.filter((entry) => {
562
+ if (typeof entry !== "object" || entry === null) {
563
+ return true;
564
+ }
565
+ const e = entry;
566
+ const entryHooks = e.hooks;
567
+ if (!Array.isArray(entryHooks)) {
568
+ return true;
569
+ }
570
+ return !entryHooks.some((h) => {
571
+ if (typeof h !== "object" || h === null) {
572
+ return false;
573
+ }
574
+ const hook = h;
575
+ return typeof hook.command === "string" && hook.command.includes(VREKO_HOOK_MARKER);
576
+ });
577
+ });
578
+ }
579
+ if (Array.isArray(hooks.PostToolUse)) {
580
+ hooks.PostToolUse = hooks.PostToolUse.filter((entry) => {
581
+ if (typeof entry !== "object" || entry === null) {
582
+ return true;
583
+ }
584
+ const e = entry;
585
+ const entryHooks = e.hooks;
586
+ if (!Array.isArray(entryHooks)) {
587
+ return true;
588
+ }
589
+ return !entryHooks.some((h) => {
590
+ if (typeof h !== "object" || h === null) {
591
+ return false;
592
+ }
593
+ const hook = h;
594
+ return typeof hook.command === "string" && hook.command.includes(POST_HOOK_MARKER);
595
+ });
596
+ });
597
+ }
598
+ settings.hooks = hooks;
599
+ writeSettings(settingsPath, settings);
600
+ } catch (err) {
601
+ console.error("[vreko hooks] Failed to update settings.json:", err);
602
+ }
603
+ }
604
+ if (existsSync(hookDest)) {
605
+ try {
606
+ rmSync(hookDest);
607
+ } catch (err) {
608
+ console.error("[vreko hooks] Failed to remove PreToolUse hook script:", err);
609
+ }
610
+ }
611
+ const postHookDest = join(cwd, POST_HOOK_COMMAND);
612
+ if (existsSync(postHookDest)) {
613
+ try {
614
+ rmSync(postHookDest);
615
+ } catch (err) {
616
+ console.error("[vreko hooks] Failed to remove PostToolUse hook script:", err);
617
+ }
618
+ }
619
+ const config = readVrekoConfig(cwd);
620
+ const cfgHooks = config.hooks ?? {};
621
+ const claudeCodeCfg = cfgHooks["claude-code"] ?? {};
622
+ claudeCodeCfg.installed = false;
623
+ cfgHooks["claude-code"] = claudeCodeCfg;
624
+ config.hooks = cfgHooks;
625
+ writeVrekoConfig(cwd, config);
626
+ console.log("Vreko hook removed");
627
+ }
628
+ __name(uninstallHook, "uninstallHook");
629
+ async function hookStatus(workspace) {
630
+ const cwd = workspace ?? process.cwd();
631
+ const settingsPath = join(cwd, ".claude", "settings.json");
632
+ const hookDest = join(cwd, VREKO_HOOK_COMMAND);
633
+ const config = readVrekoConfig(cwd);
634
+ const cfgHooks = config.hooks ?? {};
635
+ const claudeCodeCfg = cfgHooks["claude-code"] ?? {};
636
+ const configInstalled = claudeCodeCfg.installed === true;
637
+ const scriptExists = existsSync(hookDest);
638
+ const settings = readSettings(settingsPath);
639
+ const hooks = settings.hooks ?? {};
640
+ const preToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
641
+ const postToolUse = Array.isArray(hooks.PostToolUse) ? hooks.PostToolUse : [];
642
+ const settingsHasEntry = isVrekoHookPresent(preToolUse);
643
+ const settingsHasPostEntry = isVrekoPostHookPresent(postToolUse);
644
+ const postHookDest = join(cwd, POST_HOOK_COMMAND);
645
+ const postScriptExists = existsSync(postHookDest);
646
+ console.log("Vreko hooks status:");
647
+ console.log(` Config installed flag: ${configInstalled ? "\u2705 true" : "\u274C false"}`);
648
+ console.log(` PreToolUse: script ${scriptExists ? "\u2705" : "\u274C"}, settings ${settingsHasEntry ? "\u2705" : "\u274C"}`);
649
+ console.log(` PostToolUse: script ${postScriptExists ? "\u2705" : "\u274C"}, settings ${settingsHasPostEntry ? "\u2705" : "\u274C"}`);
650
+ const fullyInstalled = configInstalled && scriptExists && settingsHasEntry && postScriptExists && settingsHasPostEntry;
651
+ const notInstalled = !configInstalled && !scriptExists && !settingsHasEntry && !postScriptExists && !settingsHasPostEntry;
652
+ if (fullyInstalled) {
653
+ console.log("\n\u2705 All hooks fully installed and active");
654
+ if (claudeCodeCfg.mode) {
655
+ console.log(` Mode: ${claudeCodeCfg.mode}`);
656
+ }
657
+ } else if (notInstalled) {
658
+ console.log("\n Not installed. Run: vreko hooks install --tool claude-code");
659
+ } else {
660
+ console.log("\n\u26A0\uFE0F Partial install detected. Run uninstall then reinstall to fix.");
661
+ }
662
+ }
663
+ __name(hookStatus, "hookStatus");
664
+ function createHooksCommand() {
665
+ const hooks = new Command("hooks").description("Manage Vreko integration hooks for AI coding tools").addHelpText("after", "\nExamples:\n vreko hooks install --tool claude-code\n vreko hooks status\n");
666
+ hooks.command("install").description("Install the Vreko PreToolUse hook for the specified AI tool").requiredOption("--tool <tool>", "AI tool to install hook for (e.g. claude-code)").option("--workspace <path>", "Workspace directory (default: cwd)").action(async (opts) => {
667
+ try {
668
+ await installHook(opts.tool, opts.workspace);
669
+ } catch (err) {
670
+ console.error("[vreko hooks] Install failed:", err);
671
+ process.exit(1);
672
+ }
673
+ });
674
+ hooks.command("uninstall").description("Remove the Vreko PreToolUse hook for the specified AI tool").requiredOption("--tool <tool>", "AI tool to uninstall hook for (e.g. claude-code)").option("--workspace <path>", "Workspace directory (default: cwd)").action(async (opts) => {
675
+ try {
676
+ await uninstallHook(opts.tool, opts.workspace);
677
+ } catch (err) {
678
+ console.error("[vreko hooks] Uninstall failed:", err);
679
+ process.exit(1);
680
+ }
681
+ });
682
+ hooks.command("status").description("Show current hook installation status").option("--workspace <path>", "Workspace directory (default: cwd)").action(async (opts) => {
683
+ try {
684
+ await hookStatus(opts.workspace);
685
+ } catch (err) {
686
+ console.error("[vreko hooks] Status check failed:", err);
687
+ process.exit(1);
688
+ }
689
+ });
690
+ return hooks;
691
+ }
692
+ __name(createHooksCommand, "createHooksCommand");
693
+
694
+ // src/commands/init/init-core.ts
695
+ var GROUND_TRUTH_SKILL_CONTENT = `---
696
+ name: ground-truth
697
+ description: Disciplined methodology for AI-assisted coding that keeps Claude anchored to what the codebase actually says instead of what Claude assumes. Use this skill for any non-trivial coding task - refactors, multi-file changes, bug fixes, feature implementation, spec work, or anything touching more than a single function. Also use when the user mentions "refactor," "implement," "add a feature," "fix this bug," "migrate," "clean up," "audit," or anything that implies structured work on a real codebase. Especially use when working inside a git repository or when the user references files, modules, or prior work. Do not skip for tasks that seem simple on the surface; small changes in real codebases frequently have non-obvious ripple effects, and Ground Truth is built to catch those before they ship. The skill also responds to the user phrases "run ground truth," "ground truth audit," "brief me," "verify this," "close the session," and "pulse check."
698
+ ---
699
+
700
+ # Ground Truth
701
+
702
+ A methodology for disciplined coding work in real codebases, powered by Vreko behavioral intelligence.
703
+
704
+ ## The core principle
705
+
706
+ Ground truth is what the codebase actually says - the imports that actually exist, the functions that are actually called, the types that are actually exported, the tests that actually pass. Everything else is assumption. LLMs produce code that looks right more easily than they produce code that is right in the specific context of the codebase in front of them. The gap between those two things is where regressions live.
707
+
708
+ Ground Truth closes that gap with four disciplines and five workflows. The disciplines are the mindset; the workflows are the verbs the user invokes.
709
+
710
+ ## Pre-flight (run once per session, first)
711
+
712
+ Before any workflow, check the capability surface:
713
+
714
+ \`\`\`bash
715
+ # Is Vreko installed and running?
716
+ vreko --version 2>/dev/null && vreko service status 2>/dev/null
717
+ \`\`\`
718
+
719
+ If the command fails with "command not found", explain to the user in one sentence what Vreko does and offer to install it:
720
+
721
+ > Vreko is a local service that tracks changes to this codebase, attributes them to AI tools, and surfaces codebase-specific intelligence as you work. Want me to install it? (\`npm install -g @vreko/cli && vreko init\`)
722
+
723
+ Do not install without approval. If the user approves, run the install, then \`vreko init\`, then continue with the requested workflow. If the user declines, Ground Truth degrades gracefully - the methodology still applies, the Vreko-specific MCP calls are skipped.
724
+
725
+ If the workspace has \`.vreko/docs/\` present, read \`INTELLIGENCE.md\` before any workflow. That file contains the capability declaration, current session context, and intelligence summary. Treat it as authoritative for this codebase.
726
+
727
+ ## Workflow 1: \`ground-truth brief\`
728
+
729
+ **Trigger phrases:** "brief me," "what do I need to know," "give me context," "start a session"
730
+
731
+ **What it does:** Opens a Vreko session, reads the ambient docs, synthesizes a short briefing for the user.
732
+
733
+ **Steps:**
734
+ 1. Call MCP tool \`vreko\` with a task description derived from the user's request.
735
+ 2. Read \`.vreko/docs/INTELLIGENCE.md\` and \`.vreko/docs/current-session.md\` if they exist.
736
+ 3. Synthesize a \u2264200-word briefing covering: what this codebase is, what's fragile, what the agent has learned about it, what the user should be aware of before working.
737
+ 4. Present the briefing inline; do not create a file.
738
+
739
+ **Output format:**
740
+ \`\`\`
741
+ Session: <session-id>
742
+ Codebase: <brief description>
743
+ Fragile files in scope: <list or "none identified">
744
+ Recent patterns: <brief summary>
745
+ Watch for: <1-2 specific risks>
746
+ \`\`\`
747
+
748
+ **Anti-pattern:** Do not paraphrase the entire docs folder. Extract the two or three items relevant to what the user is about to do.
749
+
750
+ ## Workflow 2: \`ground-truth audit\`
751
+
752
+ **Trigger phrases:** "run ground truth audit," "audit this," "verify the current state," "check the real state"
753
+
754
+ **What it does:** Runs a grep-based audit of the current codebase state to establish ground truth before proceeding. Pairs with \`vreko_pulse\` to fold in live intelligence.
755
+
756
+ **Steps:**
757
+ 1. Identify the claim or scope to audit (ask if unclear).
758
+ 2. Generate 4-8 \`rg\` / \`grep\` commands that would verify the claim.
759
+ 3. Execute each command; capture output verbatim.
760
+ 4. Call \`vreko_pulse\` to pull live warnings and fragile-file data.
761
+ 5. Synthesize a report: what the audit found, what the pulse flagged, where they agree, where they disagree.
762
+ 6. If the user had assumptions going in, call out explicitly which were confirmed and which were contradicted.
763
+
764
+ **Output format:**
765
+ \`\`\`
766
+ Claim: <what was being verified>
767
+
768
+ Audit results:
769
+ [A1] <command> \u2192 <summary of output>
770
+ [A2] <command> \u2192 <summary of output>
771
+ ...
772
+
773
+ Pulse:
774
+ Active warnings: <list>
775
+ Fragile files in scope: <list>
776
+ Missing co-change partners: <list>
777
+
778
+ Synthesis:
779
+ Confirmed: <list>
780
+ Contradicted: <list>
781
+ Unknown: <list>
782
+ \`\`\`
783
+
784
+ **Anti-pattern:** Do not let the audit exceed 8 commands. If more depth is needed, split into two audits with distinct scopes.
785
+
786
+ ## Workflow 3: \`ground-truth verify\`
787
+
788
+ **Trigger phrases:** "verify this," "run verification," "check the work," "gate this"
789
+
790
+ **What it does:** Runs the verification protocol for work that was just completed - tests, grep gates, lint. Records outcome as a learning.
791
+
792
+ **Steps:**
793
+ 1. Identify the verification targets (which tests, which grep gates, which build commands).
794
+ 2. Run each in sequence. Capture exit codes and summary output.
795
+ 3. If all pass, call \`vreko_learn\` with a terse outcome record: \`{ insight: "<what was verified>: passed", severity: "info" }\`.
796
+ 4. If any fail, call \`vreko_learn\` with the failure: \`{ insight: "<what failed and why>", severity: "warn" }\`, then present the failure to the user; do not mark the work complete.
797
+ 5. Report pass/fail summary to the user.
798
+
799
+ **Output format:**
800
+ \`\`\`
801
+ Verification gates:
802
+ [V1] <command> \u2192 PASS / FAIL
803
+ [V2] <command> \u2192 PASS / FAIL
804
+ ...
805
+
806
+ Overall: PASS / FAIL
807
+ Learning recorded: <learning-id>
808
+ \`\`\`
809
+
810
+ **Anti-pattern:** Do not call work "done" without running verification. Do not skip verification because tests are slow; offer to run a subset if full suite is impractical.
811
+
812
+ ## Workflow 4: \`ground-truth check\`
813
+
814
+ **Trigger phrases:** "pulse check," "quick check," "how are we doing," "anything I'm missing"
815
+
816
+ **What it does:** Lightweight mid-session check. Pulls \`vreko_pulse\` and annotates for the user what to be aware of for the next several turns.
817
+
818
+ **Steps:**
819
+ 1. Call \`vreko_pulse\`.
820
+ 2. Read the \`LLM_HINT\` section of the response (see spec 03).
821
+ 3. Summarize in 2-3 sentences what the user should be aware of right now.
822
+ 4. If pulse returns warnings the user hasn't acknowledged, surface them.
823
+
824
+ **Output format:** Brief prose, no tables. Example: "Pulse check: you're in \`auth/session.ts\`, which was rolled back 4\xD7 in the last 90 days. Co-change partner \`auth/middleware.ts\` hasn't been touched yet - if you're refactoring session logic, middleware probably needs coordination. No other warnings."
825
+
826
+ **Anti-pattern:** Do not repeat the same warning on consecutive checks. Track what was surfaced and only re-surface if state has changed.
827
+
828
+ ## Workflow 5: \`ground-truth close\`
829
+
830
+ **Trigger phrases:** "close the session," "we're done here," "wrap up," "ceremony"
831
+
832
+ **What it does:** Closes the Vreko session, reads the closing ceremony, presents the summary.
833
+
834
+ **Steps:**
835
+ 1. Call \`vreko_end\` with a one-sentence outcome summary of what was accomplished.
836
+ 2. Parse the ceremony response: learnings captured, pitfalls avoided, estimated token savings, session coherence score, carry-forward items.
837
+ 3. Present the summary to the user in a compact format.
838
+ 4. If there are carry-forward items, explicitly flag them for the next session.
839
+
840
+ **Output format:**
841
+ \`\`\`
842
+ Session closed: <session-id>
843
+ Outcome: <one sentence>
844
+
845
+ Ceremony summary:
846
+ Learnings captured: <n>
847
+ Pitfalls avoided: <n>
848
+ Token savings (est): ~<n>
849
+ Coherence score: <n>%
850
+
851
+ Carry forward to next session:
852
+ \u2022 <item>
853
+ \u2022 <item>
854
+ \`\`\`
855
+
856
+ **Anti-pattern:** Do not skip the closing ceremony just because the session was short. Short sessions often have the most valuable learnings.
857
+
858
+ ## How workflows compose
859
+
860
+ A typical disciplined coding session looks like:
861
+
862
+ 1. User states intent \u2192 Claude runs \`ground-truth brief\`.
863
+ 2. Before significant changes \u2192 Claude runs \`ground-truth audit\` on the scope.
864
+ 3. Mid-session, at file-change boundaries \u2192 Claude runs \`ground-truth check\`.
865
+ 4. After implementation \u2192 Claude runs \`ground-truth verify\`.
866
+ 5. At session end \u2192 Claude runs \`ground-truth close\`.
867
+
868
+ The user doesn't need to type these verbatim. The skill recognizes intent from natural phrasing.
869
+
870
+ ## What this skill does NOT do
871
+
872
+ - Does not replace the user's judgment. If verification passes but something still feels wrong, stop and investigate.
873
+ - Does not auto-install Vreko. Always asks.
874
+ - Does not expose MCP tools directly to the user. The user asks for ground truth; the skill orchestrates the tools.
875
+ - Does not write to \`.vreko/docs/\` directly. That's the service's job.
876
+
877
+ ## Integration with other Vreko skills
878
+
879
+ - \`vreko-ground-truth-audit\` (published) - generates grep-based audit commands; Ground Truth's \`audit\` workflow uses its patterns.
880
+ - \`vreko-brand-voice\` (published) - use when Ground Truth output will surface in external communication.
881
+ - \`vreko-spec-writer\` (published) - use when Ground Truth discovers work that warrants a spec.
882
+
883
+ ## Installation
884
+
885
+ \`\`\`bash
886
+ # Users install the skill file into their Claude Code skills directory:
887
+ mkdir -p ~/.claude/skills/ground-truth
888
+ curl -o ~/.claude/skills/ground-truth/SKILL.md \\
889
+ https://skills.vreko.dev/ground-truth/SKILL.md
890
+ \`\`\`
891
+
892
+ Or, bundled: Ground Truth ships as the headline skill inside \`@vreko/skills\` npm package, which \`vreko init\` installs into the appropriate directory per detected AI tool.
893
+
894
+ ---
895
+
896
+ **Version:** 1.0.0
897
+ **Author:** Vreko / Marcelle Labs
898
+ **License:** MIT (methodology); skill file free to distribute
899
+ **Canonical URL:** https://vreko.dev/ground-truth
900
+ `;
901
+ var cliVersion = "3.0.1" ;
902
+ function createInitCommand() {
903
+ return new Command("init").description("Bootstrap Vreko for a repository").argument("[path]", "Workspace path (default: current directory)").option("-y, --yes", "Skip confirmation prompts").option("--non-interactive", "Run without prompts (extension/automation)").option("--json", "Output structured JSON result").option("--dry-run", "Show what would be configured").option("--force", "Re-initialize even if already set up").option("--skip-mcp", "Skip MCP configuration").option("--skip-service", "Skip service registration").option("--api-key <key>", "API key for Pro features").option("--dev", "Use local dev mode for MCP").option("--npm", "Use npm/npx mode for MCP").option("-q, --quiet", "Suppress informational output").option("-v, --verbose", "Show detailed detection reasoning").action(async (path, options) => {
904
+ const result = await runInit(path, options);
905
+ if (options.json) {
906
+ console.log(JSON.stringify(result, null, 2));
907
+ }
908
+ if (!result.success) {
909
+ process.exit(1);
910
+ }
911
+ });
912
+ }
913
+ __name(createInitCommand, "createInitCommand");
914
+ async function runInit(pathArg, options) {
915
+ const jsonMode = !!options.json;
916
+ const skipPrompts = !!options.yes || !!options.nonInteractive || cliState.yes;
917
+ const quiet = !!options.quiet;
918
+ const verbose = !!options.verbose;
919
+ const result = {
920
+ success: true,
921
+ version: cliVersion,
922
+ workspace: {
923
+ path: "",
924
+ alreadyInitialized: false,
925
+ reinitialized: false
926
+ },
927
+ detection: {
928
+ stack: [],
929
+ monorepoType: "none",
930
+ packageManager: "npm",
931
+ gitRepo: false,
932
+ gitRoot: null,
933
+ fileCount: 0
934
+ },
935
+ configuration: {
936
+ configCreated: false,
937
+ gitignoreUpdated: false,
938
+ ctxStubCreated: false
939
+ },
940
+ service: {
941
+ started: false,
942
+ connected: false,
943
+ workspaceRegistered: false,
944
+ version: null,
945
+ skipped: !!options.skipService
946
+ },
947
+ mcp: {
948
+ clients: {},
949
+ configured: [],
950
+ skipped: !!options.skipMcp
951
+ },
952
+ errors: []
953
+ };
954
+ try {
955
+ const spinner = jsonMode ? null : ora("Detecting workspace...").start();
956
+ const workspacePath = resolve(pathArg || process.cwd());
957
+ result.workspace.path = workspacePath;
958
+ if (!existsSync(workspacePath)) {
959
+ fail(spinner, result, `Path does not exist: ${workspacePath}`);
960
+ return result;
961
+ }
962
+ if (!statSync(workspacePath).isDirectory()) {
963
+ fail(spinner, result, `Path is not a directory: ${workspacePath}`);
964
+ return result;
965
+ }
966
+ const vrekoDir = join(workspacePath, ".vreko");
967
+ const configPath = join(vrekoDir, "config.json");
968
+ const alreadyInitialized = existsSync(configPath);
969
+ result.workspace.alreadyInitialized = alreadyInitialized;
970
+ if (alreadyInitialized && options.force) {
971
+ result.workspace.reinitialized = true;
972
+ }
973
+ const detected = detectStack(workspacePath, verbose && !jsonMode);
974
+ result.detection = {
975
+ ...detected,
976
+ fileCount: 0
977
+ };
978
+ if (spinner) {
979
+ spinner.succeed("Workspace detected");
980
+ }
981
+ if (!jsonMode && !quiet) {
982
+ if (detected.stack.length > 0) {
983
+ }
984
+ if (detected.monorepoType !== "none") {
985
+ }
986
+ }
987
+ if (!jsonMode && !options.dryRun) {
988
+ if (options.nonInteractive) {
989
+ process.stderr.write([
990
+ "",
991
+ "Vreko data notice:",
992
+ " \u2022 Session metadata (timing, file counts, risk scores) is collected locally.",
993
+ " \u2022 No file contents or source code ever leave your device.",
994
+ " \u2022 Cloud sync is opt-in and syncs metadata only.",
995
+ " \u2022 Run `vreko purge` at any time to delete all local data.",
996
+ " \u2022 Privacy policy: https://vreko.dev/privacy",
997
+ ""
998
+ ].join("\n"));
999
+ } else if (!skipPrompts) {
1000
+ const consentResult = await clack.confirm({
1001
+ message: "Vreko collects session metadata (timing, file counts, risk scores) locally. No file contents leave your device. Agree to continue?",
1002
+ initialValue: true
1003
+ });
1004
+ if (clack.isCancel(consentResult)) {
1005
+ clack.cancel("Cancelled.");
1006
+ return result;
1007
+ }
1008
+ if (!consentResult) {
1009
+ clack.cancel("Setup cancelled. No data was collected.");
1010
+ return result;
1011
+ }
1012
+ }
1013
+ }
1014
+ if (!skipPrompts && !options.dryRun) {
1015
+ const proceedResult = await clack.confirm({
1016
+ message: `Initialize Vreko for ${basename(workspacePath)}?`,
1017
+ initialValue: true
1018
+ });
1019
+ if (clack.isCancel(proceedResult)) {
1020
+ clack.cancel("Cancelled.");
1021
+ return result;
1022
+ }
1023
+ if (!proceedResult) {
1024
+ return result;
1025
+ }
1026
+ }
1027
+ const configSpinner = jsonMode ? null : ora("Configuring workspace...").start();
1028
+ if (!options.dryRun) {
1029
+ mkdirSync(vrekoDir, {
1030
+ recursive: true
1031
+ });
1032
+ if (!alreadyInitialized || options.force) {
1033
+ const config = buildWorkspaceConfig(workspacePath, detected);
1034
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
1035
+ `);
1036
+ result.configuration.configCreated = true;
1037
+ }
1038
+ if (configSpinner) {
1039
+ configSpinner.succeed("Created .vreko/config.json");
1040
+ }
1041
+ if (detected.gitRepo) {
1042
+ const gitignoreUpdated = ensureGitignore(workspacePath);
1043
+ result.configuration.gitignoreUpdated = gitignoreUpdated;
1044
+ if (!jsonMode && gitignoreUpdated) {
1045
+ ora().succeed("Updated .gitignore");
1046
+ }
1047
+ }
1048
+ const ctxPath = join(vrekoDir, ".ctx");
1049
+ if (!existsSync(ctxPath)) {
1050
+ writeFileSync(ctxPath, "# Vreko compiled context - auto-generated\n");
1051
+ result.configuration.ctxStubCreated = true;
1052
+ if (!jsonMode) {
1053
+ ora().succeed("Created .vreko/.ctx");
1054
+ }
1055
+ }
1056
+ } else {
1057
+ if (configSpinner) {
1058
+ configSpinner.info("Would create .vreko/config.json");
1059
+ }
1060
+ if (detected.gitRepo && !jsonMode) {
1061
+ ora().info("Would update .gitignore");
1062
+ }
1063
+ if (!jsonMode) {
1064
+ ora().info("Would create .vreko/.ctx");
1065
+ }
1066
+ }
1067
+ if (!jsonMode) {
1068
+ }
1069
+ if (!options.skipService) {
1070
+ const daemonSpinner = jsonMode ? null : ora("Connecting to service...").start();
1071
+ if (!options.dryRun) {
1072
+ const daemonResult = await registerWithDaemon(workspacePath, daemonSpinner, jsonMode);
1073
+ result.service = {
1074
+ ...result.service,
1075
+ ...daemonResult
1076
+ };
1077
+ if (!daemonResult.connected) {
1078
+ const daemonErrorMsg = "\u26A0 Service could not be reached - Vreko is initialized but workspace sync is disabled. Run `vr service start` to enable syncing." + (daemonResult.errorMessage ? ` ${daemonResult.errorMessage}` : "");
1079
+ if (!jsonMode) {
1080
+ console.warn(daemonErrorMsg);
1081
+ }
1082
+ result.errors.push("Service connection failed - init completed without service registration");
1083
+ } else {
1084
+ try {
1085
+ const client = getDaemonClient();
1086
+ if (client) {
1087
+ const seedResult = await client.call("workspace/seed-knowledge", {
1088
+ workspace: workspacePath
1089
+ });
1090
+ if (!jsonMode && seedResult.seeded > 0) {
1091
+ ora().succeed(`Seeded ${seedResult.seeded} intelligence patterns into workspace`);
1092
+ }
1093
+ try {
1094
+ await client.call("workspace/trigger-workspace-json-write", {
1095
+ workspace: workspacePath
1096
+ });
1097
+ } catch (error) {
1098
+ console.warn("init-core: workspace/trigger-workspace-json-write failed (non-fatal)", {
1099
+ error
1100
+ });
1101
+ }
1102
+ try {
1103
+ await client.call("workspace/write-from-scan-profile", {
1104
+ workspace: workspacePath,
1105
+ ...options.force && {
1106
+ force: true
1107
+ }
1108
+ });
1109
+ } catch (error) {
1110
+ console.warn("init-core: workspace/write-from-scan-profile failed (non-fatal)", {
1111
+ error
1112
+ });
1113
+ }
1114
+ }
1115
+ } catch (error) {
1116
+ console.warn("init-core: knowledge seeding failed (non-fatal)", {
1117
+ error
1118
+ });
1119
+ }
1120
+ }
1121
+ } else {
1122
+ if (daemonSpinner) {
1123
+ daemonSpinner.info("Would register workspace with service");
1124
+ }
1125
+ }
1126
+ if (!jsonMode) {
1127
+ }
1128
+ }
1129
+ if (!options.skipMcp) {
1130
+ const mcpSpinner = jsonMode ? null : ora("Configuring AI tools...").start();
1131
+ if (!options.dryRun) {
1132
+ const mcpResult = await configureMCP(workspacePath, options.apiKey, options.dev, options.npm, skipPrompts, jsonMode, mcpSpinner);
1133
+ result.mcp = {
1134
+ ...result.mcp,
1135
+ ...mcpResult
1136
+ };
1137
+ } else {
1138
+ if (mcpSpinner) {
1139
+ mcpSpinner.info("Would configure detected AI tools");
1140
+ }
1141
+ }
1142
+ if (!jsonMode) {
1143
+ }
1144
+ }
1145
+ if (!options.dryRun) {
1146
+ const claudeSpinner = jsonMode ? null : ora("Generating Claude Code integration...").start();
1147
+ try {
1148
+ let baselineData;
1149
+ if (result.service.connected) {
1150
+ try {
1151
+ const client = getDaemonClient();
1152
+ const record = await client.call("baseline/get", {
1153
+ workspace: workspacePath
1154
+ });
1155
+ if (record?.fragileFiles !== void 0 || record?.coChangeClusters !== void 0) {
1156
+ baselineData = {
1157
+ fragileFiles: record.fragileFiles,
1158
+ coChangeClusters: record.coChangeClusters
1159
+ };
1160
+ }
1161
+ } catch {
1162
+ }
1163
+ }
1164
+ const claudeResult = generateClaudeIntegration({
1165
+ workspacePath,
1166
+ overwrite: false,
1167
+ includeChannel: false
1168
+ }, baselineData);
1169
+ if (claudeResult.filesWritten.length > 0) {
1170
+ if (claudeSpinner) {
1171
+ claudeSpinner.succeed(`Generated Claude Code integration (${claudeResult.filesWritten.length} files)`);
1172
+ }
1173
+ if (!jsonMode && !quiet) {
1174
+ for (const _f of claudeResult.filesWritten) {
1175
+ }
1176
+ }
1177
+ } else {
1178
+ if (claudeSpinner) {
1179
+ claudeSpinner.info("Claude Code integration already present");
1180
+ }
1181
+ }
1182
+ } catch {
1183
+ if (claudeSpinner) {
1184
+ claudeSpinner.warn("Claude Code integration skipped (non-fatal)");
1185
+ }
1186
+ }
1187
+ if (!jsonMode) {
1188
+ }
1189
+ }
1190
+ if (!options.dryRun && !skipPrompts) {
1191
+ const claudeDir = join(homedir(), ".claude");
1192
+ const hasClaudeCode = existsSync(claudeDir);
1193
+ if (hasClaudeCode) {
1194
+ try {
1195
+ const skillDir = join(homedir(), ".claude", "skills", "ground-truth");
1196
+ const skillPath = join(skillDir, "SKILL.md");
1197
+ if (existsSync(skillPath)) {
1198
+ if (!jsonMode) {
1199
+ ora().info("Ground Truth skill already installed");
1200
+ }
1201
+ } else {
1202
+ const installSkill = await clack.confirm({
1203
+ message: "Install the Ground Truth skill for Claude Code? (Recommended - helps Claude work effectively in this codebase)",
1204
+ initialValue: true
1205
+ });
1206
+ if (!clack.isCancel(installSkill) && installSkill === true) {
1207
+ mkdirSync(skillDir, {
1208
+ recursive: true
1209
+ });
1210
+ writeFileSync(skillPath, GROUND_TRUTH_SKILL_CONTENT, "utf8");
1211
+ if (!jsonMode) {
1212
+ ora().succeed(`Ground Truth skill installed at ${skillPath}`);
1213
+ }
1214
+ }
1215
+ }
1216
+ } catch (skillError) {
1217
+ const skillMessage = skillError instanceof Error ? skillError.message : String(skillError);
1218
+ if (!jsonMode) {
1219
+ ora().warn(`Ground Truth skill install failed (non-fatal): ${skillMessage}`);
1220
+ }
1221
+ }
1222
+ }
1223
+ }
1224
+ if (!options.dryRun) {
1225
+ try {
1226
+ await installHook("claude-code", workspacePath);
1227
+ } catch (err) {
1228
+ if (!jsonMode && !quiet) {
1229
+ console.warn(`[vr init] Hook installation skipped: ${err instanceof Error ? err.message : String(err)}`);
1230
+ }
1231
+ }
1232
+ }
1233
+ if (!options.dryRun) {
1234
+ const fileCount = await countSourceFiles(workspacePath);
1235
+ result.detection.fileCount = fileCount;
1236
+ if (!jsonMode && !quiet) {
1237
+ const configuredTools = result.mcp.configured;
1238
+ const toolList = configuredTools.length > 0 ? configuredTools.join(", ") : null;
1239
+ const supervisorOk = result.service.supervisorInstalled !== false;
1240
+ console.log();
1241
+ console.log(chalk.green(" \u2713 Workspace registered"));
1242
+ if (supervisorOk) {
1243
+ console.log(chalk.green(" \u2713 Daemon running (supervised)"));
1244
+ } else {
1245
+ console.log(chalk.yellow(" \u26A0 Supervisor not installed (you may need to run vreko service install)"));
1246
+ console.log(chalk.green(" \u2713 Daemon running (this session only - will not restart on crash)"));
1247
+ }
1248
+ if (toolList) {
1249
+ console.log(chalk.green(` \u2713 MCP config written to ${toolList}`));
1250
+ }
1251
+ console.log();
1252
+ console.log(chalk.cyan(" \u2192 Restart Claude Desktop once to load vreko."));
1253
+ console.log(chalk.cyan(" You won't need to do this again."));
1254
+ console.log();
1255
+ if (supervisorOk) {
1256
+ console.log(chalk.white(" vreko is now ready. Try asking your AI agent about this codebase."));
1257
+ } else {
1258
+ console.log(chalk.yellow(" vreko is running but unsupervised. Run `vr doctor` if you hit issues."));
1259
+ }
1260
+ console.log();
1261
+ }
1262
+ }
1263
+ const authStatus = checkAuthToken();
1264
+ if (!authStatus.hasToken && !jsonMode) {
1265
+ console.warn("\n\u26A0\uFE0F Sync is configured but no API key was found.");
1266
+ console.warn(" Workspace metadata will not sync to the intelligence platform.");
1267
+ console.warn(" Run `vreko login` or set VREKO_API_KEY.\n");
1268
+ }
1269
+ return result;
1270
+ } catch (error) {
1271
+ const message = error instanceof Error ? error.message : String(error);
1272
+ result.success = false;
1273
+ result.error = message;
1274
+ return result;
1275
+ }
1276
+ }
1277
+ __name(runInit, "runInit");
1278
+ function detectStack(workspacePath, verbose) {
1279
+ const stack = [];
1280
+ const result = {
1281
+ stack,
1282
+ monorepoType: "none",
1283
+ packageManager: "npm",
1284
+ gitRepo: false,
1285
+ gitRoot: null
1286
+ };
1287
+ const gitRoot = findGitRoot(workspacePath);
1288
+ if (gitRoot) {
1289
+ result.gitRepo = true;
1290
+ result.gitRoot = gitRoot;
1291
+ }
1292
+ const lockfiles = [
1293
+ [
1294
+ "pnpm-lock.yaml",
1295
+ "pnpm"
1296
+ ],
1297
+ [
1298
+ "bun.lockb",
1299
+ "bun"
1300
+ ],
1301
+ [
1302
+ "yarn.lock",
1303
+ "yarn"
1304
+ ],
1305
+ [
1306
+ "package-lock.json",
1307
+ "npm"
1308
+ ]
1309
+ ];
1310
+ for (const [file, pm] of lockfiles) {
1311
+ if (existsSync(join(workspacePath, file))) {
1312
+ result.packageManager = pm;
1313
+ break;
1314
+ }
1315
+ }
1316
+ const signals = [
1317
+ // [file/pattern, stack label, verbose detail]
1318
+ [
1319
+ "next.config.js",
1320
+ "Next.js"
1321
+ ],
1322
+ [
1323
+ "next.config.ts",
1324
+ "Next.js"
1325
+ ],
1326
+ [
1327
+ "next.config.mjs",
1328
+ "Next.js"
1329
+ ],
1330
+ [
1331
+ "nuxt.config.ts",
1332
+ "Nuxt"
1333
+ ],
1334
+ [
1335
+ "svelte.config.js",
1336
+ "SvelteKit"
1337
+ ],
1338
+ [
1339
+ "astro.config.mjs",
1340
+ "Astro"
1341
+ ],
1342
+ [
1343
+ "remix.config.js",
1344
+ "Remix"
1345
+ ],
1346
+ [
1347
+ "tsconfig.json",
1348
+ "TypeScript"
1349
+ ],
1350
+ [
1351
+ "Cargo.toml",
1352
+ "Rust"
1353
+ ],
1354
+ [
1355
+ "go.mod",
1356
+ "Go"
1357
+ ],
1358
+ [
1359
+ "pyproject.toml",
1360
+ "Python"
1361
+ ],
1362
+ [
1363
+ "requirements.txt",
1364
+ "Python"
1365
+ ],
1366
+ [
1367
+ "Gemfile",
1368
+ "Ruby"
1369
+ ],
1370
+ [
1371
+ "composer.json",
1372
+ "PHP"
1373
+ ],
1374
+ [
1375
+ "Package.swift",
1376
+ "Swift"
1377
+ ],
1378
+ [
1379
+ ".env",
1380
+ "env-config"
1381
+ ]
1382
+ ];
1383
+ const seen = /* @__PURE__ */ new Set();
1384
+ for (const [file, label] of signals) {
1385
+ if (!seen.has(label) && existsSync(join(workspacePath, file))) {
1386
+ stack.push(label);
1387
+ seen.add(label);
1388
+ }
1389
+ }
1390
+ const pkgPath = join(workspacePath, "package.json");
1391
+ if (existsSync(pkgPath)) {
1392
+ try {
1393
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1394
+ const allDeps = {
1395
+ ...pkg.dependencies || {},
1396
+ ...pkg.devDependencies || {}
1397
+ };
1398
+ const depSignals = [
1399
+ [
1400
+ "drizzle-orm",
1401
+ "Drizzle"
1402
+ ],
1403
+ [
1404
+ "prisma",
1405
+ "Prisma"
1406
+ ],
1407
+ [
1408
+ "pg",
1409
+ "PostgreSQL"
1410
+ ],
1411
+ [
1412
+ "mysql2",
1413
+ "MySQL"
1414
+ ],
1415
+ [
1416
+ "better-sqlite3",
1417
+ "SQLite"
1418
+ ],
1419
+ [
1420
+ "mongoose",
1421
+ "MongoDB"
1422
+ ],
1423
+ [
1424
+ "redis",
1425
+ "Redis"
1426
+ ],
1427
+ [
1428
+ "tailwindcss",
1429
+ "Tailwind"
1430
+ ],
1431
+ [
1432
+ "@trpc/server",
1433
+ "tRPC"
1434
+ ],
1435
+ [
1436
+ "express",
1437
+ "Express"
1438
+ ],
1439
+ [
1440
+ "fastify",
1441
+ "Fastify"
1442
+ ],
1443
+ [
1444
+ "hono",
1445
+ "Hono"
1446
+ ]
1447
+ ];
1448
+ for (const [dep, label] of depSignals) {
1449
+ if (!seen.has(label) && allDeps[dep]) {
1450
+ stack.push(label);
1451
+ seen.add(label);
1452
+ }
1453
+ }
1454
+ } catch {
1455
+ }
1456
+ }
1457
+ if (existsSync(join(workspacePath, "turbo.json"))) {
1458
+ result.monorepoType = "turborepo";
1459
+ } else if (existsSync(join(workspacePath, "nx.json"))) {
1460
+ result.monorepoType = "nx";
1461
+ } else if (existsSync(join(workspacePath, "lerna.json"))) {
1462
+ result.monorepoType = "lerna";
1463
+ } else if (existsSync(join(workspacePath, "pnpm-workspace.yaml"))) {
1464
+ result.monorepoType = "pnpm";
1465
+ }
1466
+ return result;
1467
+ }
1468
+ __name(detectStack, "detectStack");
1469
+ function buildWorkspaceConfig(workspacePath, detected) {
1470
+ return {
1471
+ version: 1,
1472
+ workspace: {
1473
+ path: workspacePath,
1474
+ name: basename(workspacePath),
1475
+ stack: detected.stack,
1476
+ monorepoType: detected.monorepoType,
1477
+ packageManager: detected.packageManager
1478
+ },
1479
+ protection: {
1480
+ mode: "auto",
1481
+ level: "standard"
1482
+ },
1483
+ intelligence: {
1484
+ enabled: true
1485
+ },
1486
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1487
+ cliVersion
1488
+ };
1489
+ }
1490
+ __name(buildWorkspaceConfig, "buildWorkspaceConfig");
1491
+ function ensureGitignore(workspacePath) {
1492
+ const gitignorePath = join(workspacePath, ".gitignore");
1493
+ const entry = ".vreko/";
1494
+ if (existsSync(gitignorePath)) {
1495
+ const content = readFileSync(gitignorePath, "utf-8");
1496
+ const lines = content.split("\n").map((l) => l.trim());
1497
+ if (lines.includes(entry) || lines.includes(".vreko")) {
1498
+ return false;
1499
+ }
1500
+ const suffix = content.endsWith("\n") ? "" : "\n";
1501
+ appendFileSync(gitignorePath, `${suffix}
1502
+ # Vreko local data
1503
+ ${entry}
1504
+ `);
1505
+ return true;
1506
+ }
1507
+ writeFileSync(gitignorePath, `# Vreko local data
1508
+ ${entry}
1509
+ `);
1510
+ return true;
1511
+ }
1512
+ __name(ensureGitignore, "ensureGitignore");
1513
+ async function startAndConnectDaemon(result, spinner) {
1514
+ try {
1515
+ const client = await connectToDaemon();
1516
+ const health = await client.health.check();
1517
+ result.version = health?.version ?? null;
1518
+ if (health?.supervisorMode === "extension") {
1519
+ try {
1520
+ execFileSync("vreko", [
1521
+ "service",
1522
+ "install"
1523
+ ], {
1524
+ stdio: "pipe",
1525
+ timeout: 15e3
1526
+ });
1527
+ result.supervisorInstalled = true;
1528
+ } catch {
1529
+ result.supervisorInstalled = false;
1530
+ }
1531
+ }
1532
+ return {
1533
+ connected: true
1534
+ };
1535
+ } catch {
1536
+ if (spinner) spinner.text = "Starting service...";
1537
+ try {
1538
+ execFileSync("vreko", [
1539
+ "service",
1540
+ "start",
1541
+ "-d"
1542
+ ], {
1543
+ stdio: "pipe",
1544
+ timeout: 1e4
1545
+ });
1546
+ result.started = true;
1547
+ const maxWait = 5e3;
1548
+ const interval = 200;
1549
+ let waited = 0;
1550
+ while (waited < maxWait) {
1551
+ try {
1552
+ const client = await connectToDaemon();
1553
+ const health = await client.health.check();
1554
+ result.version = health?.version ?? null;
1555
+ return {
1556
+ connected: true
1557
+ };
1558
+ } catch {
1559
+ await sleep(interval);
1560
+ waited += interval;
1561
+ }
1562
+ }
1563
+ return {
1564
+ connected: false
1565
+ };
1566
+ } catch (_startError) {
1567
+ result.errorMessage = _startError instanceof Error ? _startError.message : String(_startError);
1568
+ if (spinner) spinner.warn("Could not start service (init will continue without it)");
1569
+ return {
1570
+ connected: false
1571
+ };
1572
+ }
1573
+ }
1574
+ }
1575
+ __name(startAndConnectDaemon, "startAndConnectDaemon");
1576
+ async function registerWorkspaceWithDaemon(workspacePath, spinner, jsonMode, result) {
1577
+ try {
1578
+ const client = getDaemonClient();
1579
+ if (client) {
1580
+ await client.call("workspace/init", {
1581
+ workspace: workspacePath
1582
+ });
1583
+ result.workspaceRegistered = true;
1584
+ if (!jsonMode && spinner) ora().succeed("Workspace registered");
1585
+ }
1586
+ } catch (_regError) {
1587
+ result.workspaceRegistered = false;
1588
+ if (!jsonMode) ora().warn("Workspace registration failed (service may need restart)");
1589
+ }
1590
+ }
1591
+ __name(registerWorkspaceWithDaemon, "registerWorkspaceWithDaemon");
1592
+ async function registerWithDaemon(_workspacePath, spinner, jsonMode) {
1593
+ const result = {
1594
+ started: false,
1595
+ connected: false,
1596
+ workspaceRegistered: false,
1597
+ version: null
1598
+ };
1599
+ try {
1600
+ const { connected } = await startAndConnectDaemon(result, spinner);
1601
+ if (!connected) {
1602
+ if (!result.errorMessage) {
1603
+ result.errorMessage = "Service did not respond after start";
1604
+ if (spinner) spinner.warn("Service did not respond (init will continue without it)");
1605
+ }
1606
+ return result;
1607
+ }
1608
+ result.connected = true;
1609
+ if (spinner) {
1610
+ spinner.succeed(`Service running (v${result.version ?? "unknown"}, pid ${await getDaemonPid()})`);
1611
+ }
1612
+ await registerWorkspaceWithDaemon(_workspacePath, spinner, jsonMode, result);
1613
+ return result;
1614
+ } catch (_error) {
1615
+ result.errorMessage = _error instanceof Error ? _error.message : String(_error);
1616
+ if (spinner) spinner.warn("Service connection failed");
1617
+ return result;
1618
+ }
1619
+ }
1620
+ __name(registerWithDaemon, "registerWithDaemon");
1621
+ async function getDaemonPid() {
1622
+ const pidPath = getServicePidPath();
1623
+ try {
1624
+ return readFileSync(pidPath, "utf-8").trim();
1625
+ } catch {
1626
+ return "?";
1627
+ }
1628
+ }
1629
+ __name(getDaemonPid, "getDaemonPid");
1630
+ async function configureMCP(workspacePath, apiKey, devMode, npmMode, _skipPrompts, jsonMode, spinner) {
1631
+ const result = {
1632
+ clients: {},
1633
+ configured: []
1634
+ };
1635
+ try {
1636
+ const detection = detectAIClients({
1637
+ cwd: workspacePath
1638
+ });
1639
+ if (detection.detected.length === 0) {
1640
+ if (spinner) {
1641
+ spinner.info("No AI tools detected (MCP configuration skipped)");
1642
+ }
1643
+ return result;
1644
+ }
1645
+ if (spinner) {
1646
+ spinner.stop();
1647
+ }
1648
+ for (const client of detection.needsSetup) {
1649
+ const clientSpinner = jsonMode ? null : ora(` ${client.displayName}...`).start();
1650
+ if (client.hasVreko) {
1651
+ result.clients[client.name] = "already_configured";
1652
+ if (clientSpinner) {
1653
+ clientSpinner.succeed(`${client.displayName} already configured`);
1654
+ }
1655
+ continue;
1656
+ }
1657
+ try {
1658
+ const mcpConfig = getVrekoMCPConfig({
1659
+ apiKey,
1660
+ useNpx: !!npmMode,
1661
+ useLocalDev: !!devMode,
1662
+ workspaceRoot: workspacePath,
1663
+ client: client.format
1664
+ });
1665
+ const writeResult = writeClientConfig(client, mcpConfig);
1666
+ if (writeResult.success) {
1667
+ result.clients[client.name] = "configured";
1668
+ result.configured.push(client.name);
1669
+ if (clientSpinner) {
1670
+ clientSpinner.succeed(`${client.displayName} configured`);
1671
+ }
1672
+ } else {
1673
+ result.clients[client.name] = "failed";
1674
+ if (clientSpinner) {
1675
+ clientSpinner.fail(`${client.displayName} failed: ${writeResult.error}`);
1676
+ }
1677
+ }
1678
+ } catch (_error) {
1679
+ result.clients[client.name] = "failed";
1680
+ if (clientSpinner) {
1681
+ clientSpinner.fail(`${client.displayName} failed`);
1682
+ }
1683
+ }
1684
+ }
1685
+ for (const client of detection.clients) {
1686
+ if (!client.exists && !jsonMode) {
1687
+ result.clients[client.name] = "not_installed";
1688
+ }
1689
+ }
1690
+ return result;
1691
+ } catch (_error) {
1692
+ if (spinner) {
1693
+ spinner.warn("MCP configuration failed (non-fatal)");
1694
+ }
1695
+ return result;
1696
+ }
1697
+ }
1698
+ __name(configureMCP, "configureMCP");
1699
+ async function countSourceFiles(workspacePath) {
1700
+ const extensions = /* @__PURE__ */ new Set([
1701
+ ".ts",
1702
+ ".tsx",
1703
+ ".js",
1704
+ ".jsx",
1705
+ ".py",
1706
+ ".rs",
1707
+ ".go",
1708
+ ".rb",
1709
+ ".php",
1710
+ ".swift",
1711
+ ".java",
1712
+ ".kt",
1713
+ ".vue",
1714
+ ".svelte"
1715
+ ]);
1716
+ const skip = /* @__PURE__ */ new Set([
1717
+ "node_modules",
1718
+ ".git",
1719
+ "dist",
1720
+ "build",
1721
+ ".vreko",
1722
+ "target",
1723
+ "__pycache__"
1724
+ ]);
1725
+ let count = 0;
1726
+ async function walk(dir) {
1727
+ try {
1728
+ const entries = await readdir(dir, {
1729
+ withFileTypes: true
1730
+ });
1731
+ for (const e of entries) {
1732
+ if (skip.has(e.name)) {
1733
+ continue;
1734
+ }
1735
+ if (e.isDirectory()) {
1736
+ await walk(join(dir, e.name));
1737
+ } else if (extensions.has(extname(e.name))) {
1738
+ count++;
1739
+ }
1740
+ }
1741
+ } catch {
1742
+ }
1743
+ }
1744
+ __name(walk, "walk");
1745
+ await walk(workspacePath);
1746
+ return count;
1747
+ }
1748
+ __name(countSourceFiles, "countSourceFiles");
1749
+ function sleep(ms) {
1750
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
1751
+ }
1752
+ __name(sleep, "sleep");
1753
+ function checkAuthToken() {
1754
+ if (process.env.VREKO_SERVICE_TOKEN) {
1755
+ return {
1756
+ hasToken: true,
1757
+ source: "env-service"
1758
+ };
1759
+ }
1760
+ if (process.env.VREKO_API_KEY) {
1761
+ return {
1762
+ hasToken: true,
1763
+ source: "env-api"
1764
+ };
1765
+ }
1766
+ try {
1767
+ const authPath = join(homedir(), ".vreko", "auth.json");
1768
+ if (existsSync(authPath)) {
1769
+ const authContent = readFileSync(authPath, "utf-8");
1770
+ const auth = JSON.parse(authContent);
1771
+ if (auth.token) {
1772
+ return {
1773
+ hasToken: true,
1774
+ source: "auth-file"
1775
+ };
1776
+ }
1777
+ }
1778
+ } catch {
1779
+ }
1780
+ return {
1781
+ hasToken: false,
1782
+ source: "none"
1783
+ };
1784
+ }
1785
+ __name(checkAuthToken, "checkAuthToken");
1786
+ function fail(spinner, result, message) {
1787
+ result.success = false;
1788
+ result.error = message;
1789
+ if (spinner) {
1790
+ spinner.fail(message);
1791
+ }
1792
+ }
1793
+ __name(fail, "fail");
1794
+
1795
+ export { createHooksCommand, createInitCommand, findWorkspaceRoot, generateClaudeIntegration, resolveWorkspaceRoot };
1796
+ //# sourceMappingURL=chunk-QWZVCJII.js.map
1797
+ //# sourceMappingURL=chunk-QWZVCJII.js.map