@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,1479 @@
1
+ #!/usr/bin/env node
2
+ import { saveBenchmarkOptIn } from './chunk-HFQHU5LC.js';
3
+ import { isDaemonConnected, connectToDaemon, getDaemonClient, getDaemonStatus } from './chunk-EEBSK2IH.js';
4
+ import './chunk-GSUGROXB.js';
5
+ import { BRAND_COLORS } from './chunk-DMXC2JTC.js';
6
+ import './chunk-KJWKY4L4.js';
7
+ import './chunk-VTSNRV3V.js';
8
+ import { __name } from './chunk-EWOJGXRX.js';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+ import { statSync, existsSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { useApp, useInput, Box, Text, useStdout } from 'ink';
13
+ import { useState, useEffect, useRef, useCallback } from 'react';
14
+ import { execSync } from 'child_process';
15
+
16
+ process.env.VREKO_CLI='true';process.env.NODE_NO_WARNINGS='1';
17
+ function snapshotPreWriteMtime(targetFile) {
18
+ try {
19
+ return statSync(targetFile).mtimeMs;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ __name(snapshotPreWriteMtime, "snapshotPreWriteMtime");
25
+ async function pollForWorkspaceJsonUpdate(targetFile, preMtime, options = {}) {
26
+ const { intervalMs = 500, timeoutMs = 45e3, cancelled = /* @__PURE__ */ __name(() => false, "cancelled") } = options;
27
+ const deadline = Date.now() + timeoutMs;
28
+ while (Date.now() < deadline) {
29
+ if (cancelled()) return false;
30
+ try {
31
+ const mtime = statSync(targetFile).mtimeMs;
32
+ if (preMtime === null || mtime > preMtime) {
33
+ return true;
34
+ }
35
+ } catch {
36
+ }
37
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
38
+ }
39
+ return false;
40
+ }
41
+ __name(pollForWorkspaceJsonUpdate, "pollForWorkspaceJsonUpdate");
42
+ function writeVrekoInitConfig(repoPath, profile) {
43
+ const vrekoDir = join(repoPath, ".vreko");
44
+ const configPath = join(vrekoDir, "config.json");
45
+ if (existsSync(configPath)) {
46
+ return;
47
+ }
48
+ try {
49
+ mkdirSync(vrekoDir, {
50
+ recursive: true
51
+ });
52
+ const config = {
53
+ protectionLevel: profile.recommendedConfig.protectionLevel,
54
+ snapshotFrequency: profile.recommendedConfig.snapshotFrequency,
55
+ projections: {
56
+ docs: {
57
+ approvedFiles: []
58
+ }
59
+ }
60
+ };
61
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
62
+ `, "utf8");
63
+ } catch {
64
+ }
65
+ }
66
+ __name(writeVrekoInitConfig, "writeVrekoInitConfig");
67
+
68
+ // src/ui/init/Activation.tsx
69
+ function capitalize(s) {
70
+ return s.charAt(0).toUpperCase() + s.slice(1);
71
+ }
72
+ __name(capitalize, "capitalize");
73
+ function totalWatchCount(targets) {
74
+ return targets.reduce((s, t) => s + Math.max(t.fileCount, 1), 0);
75
+ }
76
+ __name(totalWatchCount, "totalWatchCount");
77
+ function delay(ms) {
78
+ return new Promise((resolve) => setTimeout(resolve, ms));
79
+ }
80
+ __name(delay, "delay");
81
+ function Activation({ profile, repoPath = process.cwd(), force }) {
82
+ const { exit } = useApp();
83
+ const [stage, setStage] = useState("service");
84
+ const [checks, setChecks] = useState([
85
+ {
86
+ label: "Connecting to service",
87
+ status: "pending"
88
+ },
89
+ {
90
+ label: "Verifying workspace",
91
+ status: "pending"
92
+ },
93
+ {
94
+ label: "Checking file watcher",
95
+ status: "pending"
96
+ },
97
+ {
98
+ label: "Loading intelligence",
99
+ status: "pending"
100
+ },
101
+ {
102
+ label: "Writing workspace.json",
103
+ status: "pending"
104
+ }
105
+ ]);
106
+ const updateCheck = /* @__PURE__ */ __name((index, status, detail) => {
107
+ setChecks((prev) => prev.map((c, i) => i === index ? {
108
+ ...c,
109
+ status,
110
+ detail
111
+ } : c));
112
+ }, "updateCheck");
113
+ useEffect(() => {
114
+ if (stage !== "service") {
115
+ return;
116
+ }
117
+ let cancelled = false;
118
+ async function run() {
119
+ updateCheck(0, "running");
120
+ let step1Connected = false;
121
+ try {
122
+ if (!isDaemonConnected()) {
123
+ await connectToDaemon();
124
+ }
125
+ if (cancelled) {
126
+ return;
127
+ }
128
+ step1Connected = true;
129
+ updateCheck(0, "done");
130
+ } catch {
131
+ if (cancelled) {
132
+ return;
133
+ }
134
+ try {
135
+ const { execFileSync } = await import('child_process');
136
+ execFileSync("vreko", [
137
+ "service",
138
+ "start",
139
+ "--service"
140
+ ], {
141
+ stdio: "pipe",
142
+ timeout: 1e4
143
+ });
144
+ await delay(1500);
145
+ await connectToDaemon();
146
+ if (cancelled) {
147
+ return;
148
+ }
149
+ step1Connected = true;
150
+ updateCheck(0, "done");
151
+ } catch {
152
+ }
153
+ if (!step1Connected) {
154
+ if (cancelled) {
155
+ return;
156
+ }
157
+ updateCheck(0, "error", "Failed to connect - start service with: vr service start");
158
+ }
159
+ }
160
+ writeVrekoInitConfig(repoPath, profile);
161
+ if (step1Connected) {
162
+ updateCheck(4, "running");
163
+ try {
164
+ const client = getDaemonClient();
165
+ if (client) {
166
+ const targetFile = join(repoPath, ".agents", "workspace.json");
167
+ const preMtime = snapshotPreWriteMtime(targetFile);
168
+ await client.call("workspace/trigger-workspace-json-write", {
169
+ workspace: repoPath
170
+ });
171
+ await client.call("workspace/write-from-scan-profile", {
172
+ workspace: repoPath,
173
+ ...force && {
174
+ force: true
175
+ }
176
+ });
177
+ const written = await pollForWorkspaceJsonUpdate(targetFile, preMtime, {
178
+ cancelled: /* @__PURE__ */ __name(() => cancelled, "cancelled")
179
+ });
180
+ if (written) {
181
+ updateCheck(4, "done", "Baseline written to .agents/workspace.json");
182
+ } else {
183
+ updateCheck(4, "error", "Write in progress - will complete in background");
184
+ }
185
+ } else {
186
+ updateCheck(4, "error", "No daemon client - will write on first session");
187
+ }
188
+ } catch (e) {
189
+ const msg = e instanceof Error ? e.message : String(e);
190
+ console.warn(`[vreko init] workspace.json write failed (non-fatal): ${msg}`);
191
+ updateCheck(4, "error", "Write deferred - will complete on first session");
192
+ }
193
+ }
194
+ updateCheck(1, "running");
195
+ try {
196
+ const status = await getDaemonStatus();
197
+ if (cancelled) {
198
+ return;
199
+ }
200
+ if (status.connected) {
201
+ const uptimeMin = status.uptime ? Math.floor(status.uptime / 6e4) : 0;
202
+ updateCheck(1, "done", `Workspace registered${uptimeMin > 0 ? ` (service up ${uptimeMin}m)` : ""}`);
203
+ } else {
204
+ updateCheck(1, "error", "Service not responding");
205
+ }
206
+ } catch {
207
+ if (cancelled) {
208
+ return;
209
+ }
210
+ updateCheck(1, "done", "Workspace registered");
211
+ }
212
+ await delay(200);
213
+ if (cancelled) {
214
+ return;
215
+ }
216
+ updateCheck(2, "running");
217
+ await delay(100);
218
+ if (cancelled) {
219
+ return;
220
+ }
221
+ const hasVreko = existsSync(`${repoPath}/.vreko`);
222
+ updateCheck(2, "done", hasVreko ? "File watcher active" : "File watcher starting");
223
+ await delay(200);
224
+ if (cancelled) {
225
+ return;
226
+ }
227
+ updateCheck(3, "running");
228
+ await delay(150);
229
+ if (cancelled) {
230
+ return;
231
+ }
232
+ updateCheck(3, "done", "Intelligence ready");
233
+ await delay(400);
234
+ if (cancelled) {
235
+ return;
236
+ }
237
+ setStage("done");
238
+ }
239
+ __name(run, "run");
240
+ run();
241
+ return () => {
242
+ cancelled = true;
243
+ };
244
+ }, [
245
+ stage,
246
+ repoPath
247
+ ]);
248
+ useInput((_input, key) => {
249
+ if (stage !== "done") {
250
+ return;
251
+ }
252
+ const answer = _input.toLowerCase();
253
+ let optedIn;
254
+ if (answer === "y") {
255
+ optedIn = true;
256
+ } else if (answer === "n") {
257
+ optedIn = false;
258
+ } else if (key.return) {
259
+ optedIn = false;
260
+ } else {
261
+ return;
262
+ }
263
+ saveBenchmarkOptIn(optedIn).then(() => {
264
+ exit();
265
+ });
266
+ }, {
267
+ isActive: stage === "done"
268
+ });
269
+ const watchCount = totalWatchCount(profile.recommendedConfig.watchTargets);
270
+ const patternCount = profile.insights.length + profile.lockedInsights.length;
271
+ const fragileFile = profile.topFragileFile || "your most-changed file";
272
+ if (stage === "done") {
273
+ return /* @__PURE__ */ jsxs(Box, {
274
+ flexDirection: "column",
275
+ borderStyle: "round",
276
+ padding: 1,
277
+ children: [
278
+ /* @__PURE__ */ jsx(Text, {
279
+ bold: true,
280
+ color: "green",
281
+ children: "Vreko is watching your codebase."
282
+ }),
283
+ /* @__PURE__ */ jsxs(Box, {
284
+ marginTop: 1,
285
+ flexDirection: "column",
286
+ children: [
287
+ /* @__PURE__ */ jsxs(Text, {
288
+ children: [
289
+ /* @__PURE__ */ jsx(Text, {
290
+ color: BRAND_COLORS.primary,
291
+ children: "\u2713"
292
+ }),
293
+ ` Protection: ${capitalize(profile.recommendedConfig.protectionLevel)} \xB7 Watching ${watchCount} target${watchCount !== 1 ? "s" : ""}`
294
+ ]
295
+ }),
296
+ /* @__PURE__ */ jsxs(Text, {
297
+ children: [
298
+ /* @__PURE__ */ jsx(Text, {
299
+ color: BRAND_COLORS.primary,
300
+ children: "\u2713"
301
+ }),
302
+ ` Snapshot frequency: ${capitalize(profile.recommendedConfig.snapshotFrequency)} (risk-adaptive)`
303
+ ]
304
+ }),
305
+ /* @__PURE__ */ jsxs(Text, {
306
+ children: [
307
+ /* @__PURE__ */ jsx(Text, {
308
+ color: BRAND_COLORS.primary,
309
+ children: "\u2713"
310
+ }),
311
+ " Config written to .vreko/config.json"
312
+ ]
313
+ })
314
+ ]
315
+ }),
316
+ /* @__PURE__ */ jsxs(Box, {
317
+ marginTop: 1,
318
+ borderStyle: "single",
319
+ padding: 1,
320
+ flexDirection: "column",
321
+ children: [
322
+ /* @__PURE__ */ jsx(Text, {
323
+ children: "Try it now:"
324
+ }),
325
+ /* @__PURE__ */ jsx(Text, {}),
326
+ /* @__PURE__ */ jsxs(Text, {
327
+ color: "cyan",
328
+ children: [
329
+ '$ echo "test" >> ',
330
+ fragileFile
331
+ ]
332
+ }),
333
+ /* @__PURE__ */ jsx(Text, {}),
334
+ /* @__PURE__ */ jsx(Text, {
335
+ children: "Vreko will catch the change to your most fragile"
336
+ }),
337
+ /* @__PURE__ */ jsx(Text, {
338
+ children: "file in real time."
339
+ })
340
+ ]
341
+ }),
342
+ /* @__PURE__ */ jsxs(Box, {
343
+ marginTop: 1,
344
+ flexDirection: "column",
345
+ children: [
346
+ /* @__PURE__ */ jsxs(Text, {
347
+ children: [
348
+ "Recovery Risk: ",
349
+ capitalize(profile.overallRisk),
350
+ " \xB7 ",
351
+ "Protection: ",
352
+ capitalize(profile.recommendedConfig.protectionLevel)
353
+ ]
354
+ }),
355
+ /* @__PURE__ */ jsxs(Text, {
356
+ children: [
357
+ watchCount,
358
+ " target",
359
+ watchCount !== 1 ? "s" : "",
360
+ " watched",
361
+ " \xB7 ",
362
+ patternCount,
363
+ " patterns seeded",
364
+ " \xB7 ",
365
+ profile.lockedInsights.length,
366
+ " insight unlocking"
367
+ ]
368
+ })
369
+ ]
370
+ }),
371
+ /* @__PURE__ */ jsx(Box, {
372
+ marginTop: 1,
373
+ children: /* @__PURE__ */ jsxs(Text, {
374
+ bold: true,
375
+ children: [
376
+ "Vreko is active. Run ",
377
+ /* @__PURE__ */ jsx(Text, {
378
+ color: "cyan",
379
+ children: "vr status"
380
+ }),
381
+ " anytime."
382
+ ]
383
+ })
384
+ }),
385
+ /* @__PURE__ */ jsx(Box, {
386
+ marginTop: 1,
387
+ children: /* @__PURE__ */ jsx(Text, {
388
+ dimColor: true,
389
+ children: "Run `vr status` anytime. Your code stays local."
390
+ })
391
+ }),
392
+ /* @__PURE__ */ jsx(Box, {
393
+ marginTop: 1,
394
+ children: /* @__PURE__ */ jsx(Text, {
395
+ children: "Share anonymous benchmarks to improve comparisons? [y/N]"
396
+ })
397
+ })
398
+ ]
399
+ });
400
+ }
401
+ return /* @__PURE__ */ jsxs(Box, {
402
+ flexDirection: "column",
403
+ borderStyle: "round",
404
+ padding: 1,
405
+ children: [
406
+ /* @__PURE__ */ jsx(Text, {
407
+ children: "Starting Vreko service..."
408
+ }),
409
+ /* @__PURE__ */ jsx(Box, {
410
+ marginTop: 1,
411
+ flexDirection: "column",
412
+ minHeight: 4,
413
+ children: checks.filter((check) => check.status !== "pending").map((check, i) => {
414
+ const icon = check.status === "done" ? "\u2713" : check.status === "error" ? "\u26A0" : "\u2026";
415
+ const color = check.status === "done" ? BRAND_COLORS.primary : check.status === "error" ? "yellow" : "cyan";
416
+ return /* @__PURE__ */ jsxs(Text, {
417
+ color,
418
+ children: [
419
+ icon,
420
+ " ",
421
+ check.label,
422
+ check.detail ? ` - ${check.detail}` : ""
423
+ ]
424
+ }, i);
425
+ })
426
+ })
427
+ ]
428
+ });
429
+ }
430
+ __name(Activation, "Activation");
431
+ function Consent({ onAccept }) {
432
+ const { exit } = useApp();
433
+ const [declined, setDeclined] = useState(false);
434
+ useInput((input, key) => {
435
+ if (key.return || input === "y" || input === "Y") {
436
+ onAccept();
437
+ } else if (input === "n" || input === "N" || key.escape) {
438
+ setDeclined(true);
439
+ setTimeout(() => exit(), 300);
440
+ }
441
+ });
442
+ if (declined) {
443
+ return /* @__PURE__ */ jsx(Box, {
444
+ flexDirection: "column",
445
+ padding: 1,
446
+ children: /* @__PURE__ */ jsx(Text, {
447
+ color: "yellow",
448
+ children: "Setup cancelled. No data was collected."
449
+ })
450
+ });
451
+ }
452
+ return /* @__PURE__ */ jsxs(Box, {
453
+ flexDirection: "column",
454
+ borderStyle: "round",
455
+ padding: 1,
456
+ width: 78,
457
+ children: [
458
+ /* @__PURE__ */ jsx(Text, {
459
+ bold: true,
460
+ color: BRAND_COLORS.primary,
461
+ children: "Data Collection Notice"
462
+ }),
463
+ /* @__PURE__ */ jsxs(Box, {
464
+ marginTop: 1,
465
+ flexDirection: "column",
466
+ gap: 0,
467
+ children: [
468
+ /* @__PURE__ */ jsx(Text, {
469
+ children: "Vreko collects the following to power its intelligence features:"
470
+ }),
471
+ /* @__PURE__ */ jsxs(Box, {
472
+ marginTop: 1,
473
+ flexDirection: "column",
474
+ children: [
475
+ /* @__PURE__ */ jsxs(Text, {
476
+ children: [
477
+ " \u2713 ",
478
+ "Session metadata (start/end times, file counts, risk scores)"
479
+ ]
480
+ }),
481
+ /* @__PURE__ */ jsxs(Text, {
482
+ children: [
483
+ " \u2713 ",
484
+ "Git commit hashes and change attribution"
485
+ ]
486
+ }),
487
+ /* @__PURE__ */ jsxs(Text, {
488
+ children: [
489
+ " \u2713 ",
490
+ "Rollback events and AI tool attribution"
491
+ ]
492
+ })
493
+ ]
494
+ }),
495
+ /* @__PURE__ */ jsxs(Box, {
496
+ marginTop: 1,
497
+ flexDirection: "column",
498
+ children: [
499
+ /* @__PURE__ */ jsx(Text, {
500
+ color: "green",
501
+ children: " \u2717 File contents never leave your device"
502
+ }),
503
+ /* @__PURE__ */ jsx(Text, {
504
+ color: "green",
505
+ children: " \u2717 Source code is never read or transmitted"
506
+ })
507
+ ]
508
+ })
509
+ ]
510
+ }),
511
+ /* @__PURE__ */ jsxs(Box, {
512
+ marginTop: 1,
513
+ flexDirection: "column",
514
+ children: [
515
+ /* @__PURE__ */ jsx(Text, {
516
+ dimColor: true,
517
+ children: "Data stays local by default. Cloud sync (opt-in) transmits metadata only."
518
+ }),
519
+ /* @__PURE__ */ jsx(Text, {
520
+ dimColor: true,
521
+ children: "Run `vreko purge` at any time to delete all local data."
522
+ }),
523
+ /* @__PURE__ */ jsx(Text, {
524
+ dimColor: true,
525
+ children: "Privacy policy: https://vreko.dev/privacy"
526
+ })
527
+ ]
528
+ }),
529
+ /* @__PURE__ */ jsx(Box, {
530
+ marginTop: 1,
531
+ children: /* @__PURE__ */ jsxs(Text, {
532
+ children: [
533
+ "Press ",
534
+ /* @__PURE__ */ jsx(Text, {
535
+ bold: true,
536
+ color: "green",
537
+ children: "Y / Enter"
538
+ }),
539
+ " to accept \xB7 ",
540
+ /* @__PURE__ */ jsx(Text, {
541
+ bold: true,
542
+ color: "red",
543
+ children: "N / ESC"
544
+ }),
545
+ " to decline"
546
+ ]
547
+ })
548
+ })
549
+ ]
550
+ });
551
+ }
552
+ __name(Consent, "Consent");
553
+ function detectRepoInfo(repoPath) {
554
+ const checks = [];
555
+ if (existsSync(join(repoPath, ".git"))) {
556
+ checks.push("\u2713 Git repository found");
557
+ } else {
558
+ checks.push("\u26A0 No git repository found - some features unavailable");
559
+ }
560
+ if (existsSync(join(repoPath, "pnpm-workspace.yaml"))) {
561
+ const pkgCount = readdirSync(repoPath, {
562
+ withFileTypes: true
563
+ }).filter((d) => d.isDirectory() && (d.name === "packages" || d.name === "apps")).reduce((acc) => {
564
+ try {
565
+ return acc + readdirSync(join(repoPath, "packages"), {
566
+ withFileTypes: true
567
+ }).filter((d) => d.isDirectory()).length + readdirSync(join(repoPath, "apps"), {
568
+ withFileTypes: true
569
+ }).filter((d) => d.isDirectory()).length;
570
+ } catch {
571
+ return acc;
572
+ }
573
+ }, 0);
574
+ checks.push(`\u2713 pnpm workspace monorepo${pkgCount > 0 ? ` (${pkgCount} packages)` : ""}`);
575
+ } else if (existsSync(join(repoPath, "yarn.lock"))) {
576
+ checks.push("\u2713 Yarn workspace detected");
577
+ } else if (existsSync(join(repoPath, "package.json"))) {
578
+ checks.push("\u2713 Node.js project detected");
579
+ }
580
+ if (existsSync(join(repoPath, "turbo.json"))) {
581
+ checks.push("\u2713 Turborepo build system");
582
+ } else if (existsSync(join(repoPath, "nx.json"))) {
583
+ checks.push("\u2713 Nx workspace");
584
+ }
585
+ if (existsSync(join(repoPath, "next.config.js")) || existsSync(join(repoPath, "next.config.ts"))) {
586
+ checks.push("\u2713 Next.js application");
587
+ }
588
+ const aiTools = [];
589
+ const aiDirCandidates = [
590
+ {
591
+ path: join(repoPath, ".cursor"),
592
+ name: "Cursor"
593
+ },
594
+ {
595
+ path: join(repoPath, ".github", "copilot"),
596
+ name: "GitHub Copilot"
597
+ },
598
+ {
599
+ path: join(repoPath, ".claude"),
600
+ name: "Claude Code"
601
+ },
602
+ {
603
+ path: join(repoPath, ".windsurf"),
604
+ name: "Windsurf"
605
+ }
606
+ ];
607
+ for (const { path, name } of aiDirCandidates) {
608
+ try {
609
+ if (existsSync(path) && statSync(path).isDirectory()) {
610
+ aiTools.push(name);
611
+ }
612
+ } catch {
613
+ }
614
+ }
615
+ if (aiTools.length > 0) {
616
+ checks.push(`\u2713 AI tools detected: ${aiTools.join(", ")}`);
617
+ }
618
+ try {
619
+ const count = execSync("git rev-list --count HEAD", {
620
+ cwd: repoPath,
621
+ encoding: "utf-8",
622
+ timeout: 3e3,
623
+ stdio: [
624
+ "pipe",
625
+ "pipe",
626
+ "ignore"
627
+ ]
628
+ }).trim();
629
+ if (count) {
630
+ checks.push(`\u2713 ${count} commits in history`);
631
+ }
632
+ } catch {
633
+ }
634
+ return checks.slice(0, 5);
635
+ }
636
+ __name(detectRepoInfo, "detectRepoInfo");
637
+ function Detection({ repoPath = process.cwd(), onReady }) {
638
+ const [checks, setChecks] = useState([]);
639
+ useInput((_input, key) => {
640
+ if (key.return) {
641
+ onReady();
642
+ }
643
+ });
644
+ useEffect(() => {
645
+ const detected = detectRepoInfo(repoPath);
646
+ detected.forEach((check, index) => {
647
+ setTimeout(() => {
648
+ setChecks((prev) => [
649
+ ...prev,
650
+ check
651
+ ]);
652
+ }, (index + 1) * 200);
653
+ });
654
+ }, [
655
+ repoPath
656
+ ]);
657
+ return /* @__PURE__ */ jsxs(Box, {
658
+ flexDirection: "column",
659
+ borderStyle: "round",
660
+ padding: 1,
661
+ children: [
662
+ /* @__PURE__ */ jsxs(Box, {
663
+ marginTop: 1,
664
+ flexDirection: "column",
665
+ children: [
666
+ /* @__PURE__ */ jsx(Text, {
667
+ children: "Detecting repository..."
668
+ }),
669
+ /* @__PURE__ */ jsx(Box, {
670
+ marginTop: 1,
671
+ flexDirection: "column",
672
+ minHeight: 4,
673
+ children: checks.map((msg, i) => /* @__PURE__ */ jsx(Text, {
674
+ color: msg.startsWith("\u26A0") ? "yellow" : void 0,
675
+ children: msg.startsWith("\u26A0") ? msg : /* @__PURE__ */ jsxs(Fragment, {
676
+ children: [
677
+ /* @__PURE__ */ jsx(Text, {
678
+ color: BRAND_COLORS.primary,
679
+ children: "\u2713"
680
+ }),
681
+ msg.slice(1)
682
+ ]
683
+ })
684
+ }, i))
685
+ })
686
+ ]
687
+ }),
688
+ /* @__PURE__ */ jsx(Box, {
689
+ marginTop: 1,
690
+ children: /* @__PURE__ */ jsx(Text, {
691
+ dimColor: true,
692
+ children: "Analyzing behavioral patterns - no code will be read."
693
+ })
694
+ }),
695
+ /* @__PURE__ */ jsx(Box, {
696
+ marginTop: 1,
697
+ children: /* @__PURE__ */ jsx(Text, {
698
+ color: BRAND_COLORS.primary,
699
+ children: "Press [ENTER] to scan your repository \u2192"
700
+ })
701
+ })
702
+ ]
703
+ });
704
+ }
705
+ __name(Detection, "Detection");
706
+ var NULL_PROFILE = {
707
+ overallRisk: "low",
708
+ confidence: 0,
709
+ primary: {
710
+ recoveryRisk: 0,
711
+ changeVolatility: 0,
712
+ workflowFragility: 0
713
+ },
714
+ secondary: {
715
+ complexity: 0,
716
+ collaboration: 0,
717
+ aiExposure: 0,
718
+ structuralRisk: 0
719
+ },
720
+ topDrivers: [],
721
+ insights: [],
722
+ lockedInsights: [],
723
+ recommendedConfig: {
724
+ protectionLevel: "standard",
725
+ snapshotFrequency: "balanced",
726
+ watchTargets: [],
727
+ enabledFeatures: []
728
+ },
729
+ topFragileFile: null,
730
+ topFragileFiles: [],
731
+ coChange: [],
732
+ fragility: []
733
+ };
734
+ function useAnalysis(repoPath, onComplete, minDisplayMs = 0) {
735
+ const [done, setDone] = useState(false);
736
+ const [errored, setErrored] = useState(false);
737
+ const [profile, setProfile] = useState(null);
738
+ const hasStarted = useRef(false);
739
+ const startTimeRef = useRef(Date.now());
740
+ useEffect(() => {
741
+ if (hasStarted.current) {
742
+ return;
743
+ }
744
+ hasStarted.current = true;
745
+ const runScan = /* @__PURE__ */ __name(async () => {
746
+ if (isDaemonConnected()) {
747
+ const client = getDaemonClient();
748
+ return client.call("workspace/run-init-scan", {
749
+ workspace: repoPath
750
+ });
751
+ }
752
+ const { runInitScan } = await import('./init-scan-RZNYDTUV.js');
753
+ return runInitScan({
754
+ repoPath
755
+ });
756
+ }, "runScan");
757
+ runScan().then((result) => {
758
+ const resolved = result ?? NULL_PROFILE;
759
+ setDone(true);
760
+ setProfile(resolved);
761
+ const elapsed = Date.now() - startTimeRef.current;
762
+ const delay2 = Math.max(500, minDisplayMs - elapsed);
763
+ setTimeout(() => onComplete(resolved), delay2);
764
+ }).catch(() => setErrored(true));
765
+ }, [
766
+ repoPath
767
+ ]);
768
+ return {
769
+ done,
770
+ errored,
771
+ profile
772
+ };
773
+ }
774
+ __name(useAnalysis, "useAnalysis");
775
+ function useKeyboard(options) {
776
+ const { onEnter, onEscape, onArrowRight, onArrowLeft, onArrowUp, onArrowDown, enabled = true } = options;
777
+ useInput((_input, key) => {
778
+ if (key.return) {
779
+ onEnter?.();
780
+ } else if (key.escape) {
781
+ onEscape?.();
782
+ } else if (key.rightArrow) {
783
+ onArrowRight?.();
784
+ } else if (key.leftArrow) {
785
+ onArrowLeft?.();
786
+ } else if (key.upArrow) {
787
+ onArrowUp?.();
788
+ } else if (key.downArrow) {
789
+ onArrowDown?.();
790
+ }
791
+ }, {
792
+ isActive: enabled
793
+ });
794
+ }
795
+ __name(useKeyboard, "useKeyboard");
796
+ function announce(_message, priority = "polite") {
797
+ }
798
+ __name(announce, "announce");
799
+ function capitalize2(s) {
800
+ return s.charAt(0).toUpperCase() + s.slice(1);
801
+ }
802
+ __name(capitalize2, "capitalize");
803
+ function totalWatchCount2(targets) {
804
+ return targets.reduce((s, t) => s + Math.max(t.fileCount, 1), 0);
805
+ }
806
+ __name(totalWatchCount2, "totalWatchCount");
807
+ function prioritizeInsights(insights) {
808
+ return [
809
+ ...insights
810
+ ].sort((a, b) => {
811
+ if (a.type === "co-change" && b.type !== "co-change") {
812
+ return -1;
813
+ }
814
+ if (b.type === "co-change" && a.type !== "co-change") {
815
+ return 1;
816
+ }
817
+ if (a.type === "blast-radius" && b.type !== "blast-radius") {
818
+ return -1;
819
+ }
820
+ if (b.type === "blast-radius" && a.type !== "blast-radius") {
821
+ return 1;
822
+ }
823
+ if (a.type === "recovery" && b.type !== "recovery") {
824
+ return -1;
825
+ }
826
+ if (b.type === "recovery" && a.type !== "recovery") {
827
+ return 1;
828
+ }
829
+ const severityOrder = {
830
+ critical: 0,
831
+ warning: 1,
832
+ notable: 2,
833
+ info: 3
834
+ };
835
+ return severityOrder[a.severity] - severityOrder[b.severity];
836
+ });
837
+ }
838
+ __name(prioritizeInsights, "prioritizeInsights");
839
+ var PAGE_SIZE = 3;
840
+ function Insights({ profile, onContinue, onCustomize }) {
841
+ const [currentPage, setCurrentPage] = useState(0);
842
+ const { insights, lockedInsights, recommendedConfig } = profile;
843
+ const sorted = prioritizeInsights(insights);
844
+ const maxPage = Math.max(0, sorted.length - PAGE_SIZE);
845
+ useInput((input, key) => {
846
+ if (key.upArrow && currentPage > 0) {
847
+ setCurrentPage((p) => p - 1);
848
+ } else if (key.downArrow && currentPage < maxPage) {
849
+ setCurrentPage((p) => p + 1);
850
+ } else if (key.return) {
851
+ onContinue();
852
+ } else if ((input === "c" || input === "C") && onCustomize) {
853
+ onCustomize();
854
+ }
855
+ });
856
+ const locked = lockedInsights[0];
857
+ const watchCount = totalWatchCount2(recommendedConfig.watchTargets);
858
+ const visibleInsights = sorted.slice(currentPage, currentPage + PAGE_SIZE);
859
+ const shownEnd = currentPage + visibleInsights.length;
860
+ return /* @__PURE__ */ jsxs(Box, {
861
+ flexDirection: "column",
862
+ borderStyle: "round",
863
+ padding: 1,
864
+ children: [
865
+ /* @__PURE__ */ jsxs(Box, {
866
+ children: [
867
+ /* @__PURE__ */ jsx(Box, {
868
+ width: "50%",
869
+ children: /* @__PURE__ */ jsx(Text, {
870
+ bold: true,
871
+ children: "What We Found"
872
+ })
873
+ }),
874
+ /* @__PURE__ */ jsx(Box, {
875
+ width: "50%",
876
+ children: /* @__PURE__ */ jsx(Text, {
877
+ bold: true,
878
+ children: "What We'll Do"
879
+ })
880
+ })
881
+ ]
882
+ }),
883
+ /* @__PURE__ */ jsxs(Box, {
884
+ marginTop: 1,
885
+ flexDirection: "column",
886
+ children: [
887
+ visibleInsights.map((insight) => /* @__PURE__ */ jsxs(Box, {
888
+ marginBottom: 1,
889
+ children: [
890
+ /* @__PURE__ */ jsxs(Box, {
891
+ width: "50%",
892
+ paddingRight: 2,
893
+ flexDirection: "column",
894
+ children: [
895
+ /* @__PURE__ */ jsxs(Text, {
896
+ color: insight.severity === "critical" ? "red" : insight.severity === "warning" || insight.severity === "notable" ? "yellow" : void 0,
897
+ children: [
898
+ insight.severity === "info" ? "\u2139" : "\u26A0",
899
+ " ",
900
+ insight.observation
901
+ ]
902
+ }),
903
+ /* @__PURE__ */ jsxs(Text, {
904
+ dimColor: true,
905
+ children: [
906
+ " ",
907
+ insight.whyItMatters
908
+ ]
909
+ }),
910
+ insight.comparison && /* @__PURE__ */ jsxs(Text, {
911
+ dimColor: true,
912
+ color: "cyan",
913
+ children: [
914
+ " ",
915
+ insight.comparison
916
+ ]
917
+ })
918
+ ]
919
+ }),
920
+ /* @__PURE__ */ jsx(Box, {
921
+ width: "50%",
922
+ children: /* @__PURE__ */ jsx(Text, {
923
+ children: insight.whatWeWillDo
924
+ })
925
+ })
926
+ ]
927
+ }, insight.id)),
928
+ locked && currentPage === maxPage && /* @__PURE__ */ jsxs(Box, {
929
+ marginBottom: 1,
930
+ children: [
931
+ /* @__PURE__ */ jsxs(Box, {
932
+ width: "50%",
933
+ paddingRight: 2,
934
+ flexDirection: "column",
935
+ children: [
936
+ /* @__PURE__ */ jsxs(Text, {
937
+ dimColor: true,
938
+ children: [
939
+ "\u2504 ",
940
+ locked.teaser
941
+ ]
942
+ }),
943
+ /* @__PURE__ */ jsxs(Text, {
944
+ dimColor: true,
945
+ children: [
946
+ " ",
947
+ locked.requirement
948
+ ]
949
+ })
950
+ ]
951
+ }),
952
+ /* @__PURE__ */ jsx(Box, {
953
+ width: "50%",
954
+ children: /* @__PURE__ */ jsxs(Text, {
955
+ dimColor: true,
956
+ children: [
957
+ "Available after ",
958
+ locked.unlockCondition.days,
959
+ " days of active development."
960
+ ]
961
+ })
962
+ })
963
+ ]
964
+ })
965
+ ]
966
+ }),
967
+ /* @__PURE__ */ jsxs(Box, {
968
+ marginTop: 1,
969
+ borderStyle: "single",
970
+ padding: 1,
971
+ flexDirection: "column",
972
+ children: [
973
+ /* @__PURE__ */ jsxs(Text, {
974
+ children: [
975
+ "Protection: ",
976
+ capitalize2(recommendedConfig.protectionLevel),
977
+ " \xB7 ",
978
+ "Watching: ",
979
+ watchCount,
980
+ " target",
981
+ watchCount !== 1 ? "s" : ""
982
+ ]
983
+ }),
984
+ /* @__PURE__ */ jsxs(Text, {
985
+ children: [
986
+ "Snapshot Frequency: ",
987
+ capitalize2(recommendedConfig.snapshotFrequency),
988
+ " (risk-adaptive)"
989
+ ]
990
+ })
991
+ ]
992
+ }),
993
+ /* @__PURE__ */ jsx(Box, {
994
+ marginTop: 1,
995
+ children: /* @__PURE__ */ jsxs(Text, {
996
+ color: BRAND_COLORS.primary,
997
+ children: [
998
+ "[ENTER] Accept \xB7 ",
999
+ onCustomize ? "[c] Customize \xB7 " : "",
1000
+ sorted.length > PAGE_SIZE ? `[\u2191\u2193] More insights (${shownEnd}/${sorted.length})` : ""
1001
+ ]
1002
+ })
1003
+ })
1004
+ ]
1005
+ });
1006
+ }
1007
+ __name(Insights, "Insights");
1008
+ var LOGO_FULL = `\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557
1009
+ \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557
1010
+ \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551
1011
+ \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551
1012
+ \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
1013
+ \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D `;
1014
+ function Logo() {
1015
+ const { stdout } = useStdout();
1016
+ const columns = stdout.columns ?? 80;
1017
+ if (columns >= 80) {
1018
+ return /* @__PURE__ */ jsx(Box, {
1019
+ flexDirection: "column",
1020
+ children: /* @__PURE__ */ jsx(Text, {
1021
+ color: BRAND_COLORS.primary,
1022
+ children: LOGO_FULL
1023
+ })
1024
+ });
1025
+ }
1026
+ return /* @__PURE__ */ jsx(Box, {
1027
+ children: /* @__PURE__ */ jsx(Text, {
1028
+ bold: true,
1029
+ color: BRAND_COLORS.primary,
1030
+ children: "\u2501\u2501 VREKO \u2501\u2501"
1031
+ })
1032
+ });
1033
+ }
1034
+ __name(Logo, "Logo");
1035
+ function useTerminalLayout() {
1036
+ const { stdout } = useStdout();
1037
+ const columns = stdout.columns ?? 80;
1038
+ const rows = stdout.rows ?? 24;
1039
+ return {
1040
+ isWide: columns >= 120,
1041
+ canShowFullLogo: columns >= 80,
1042
+ columns,
1043
+ rows
1044
+ };
1045
+ }
1046
+ __name(useTerminalLayout, "useTerminalLayout");
1047
+
1048
+ // src/ui/init/Profile.tsx
1049
+ function riskLabel(score) {
1050
+ if (score > 75) {
1051
+ return "high";
1052
+ }
1053
+ if (score > 50) {
1054
+ return "elevated";
1055
+ }
1056
+ if (score > 25) {
1057
+ return "moderate";
1058
+ }
1059
+ return "low";
1060
+ }
1061
+ __name(riskLabel, "riskLabel");
1062
+ function renderBar(score, width = 10) {
1063
+ const filled = Math.round(score / 100 * width);
1064
+ const empty = width - filled;
1065
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
1066
+ }
1067
+ __name(renderBar, "renderBar");
1068
+ function ProfileMetrics({ profile }) {
1069
+ const topDriver = profile.topDrivers[0];
1070
+ return /* @__PURE__ */ jsxs(Box, {
1071
+ flexDirection: "column",
1072
+ children: [
1073
+ /* @__PURE__ */ jsx(Text, {
1074
+ bold: true,
1075
+ children: "Your Codebase Intelligence Profile"
1076
+ }),
1077
+ /* @__PURE__ */ jsxs(Box, {
1078
+ marginTop: 1,
1079
+ padding: 1,
1080
+ borderStyle: "single",
1081
+ flexDirection: "column",
1082
+ children: [
1083
+ /* @__PURE__ */ jsxs(Text, {
1084
+ children: [
1085
+ "CODEBASE HEALTH ",
1086
+ /* @__PURE__ */ jsx(Text, {
1087
+ color: BRAND_COLORS.primary,
1088
+ children: renderBar(profile.primary.recoveryRisk)
1089
+ }),
1090
+ ` ${Math.round(profile.primary.recoveryRisk)}% ${riskLabel(profile.primary.recoveryRisk)}`
1091
+ ]
1092
+ }),
1093
+ /* @__PURE__ */ jsxs(Text, {
1094
+ children: [
1095
+ "CHANGE VOLATILITY ",
1096
+ /* @__PURE__ */ jsx(Text, {
1097
+ color: BRAND_COLORS.primary,
1098
+ children: renderBar(profile.primary.changeVolatility)
1099
+ }),
1100
+ ` ${Math.round(profile.primary.changeVolatility)}% ${riskLabel(profile.primary.changeVolatility)}`
1101
+ ]
1102
+ }),
1103
+ /* @__PURE__ */ jsxs(Text, {
1104
+ children: [
1105
+ "WORKFLOW FRAGILITY ",
1106
+ /* @__PURE__ */ jsx(Text, {
1107
+ color: BRAND_COLORS.primary,
1108
+ children: renderBar(profile.primary.workflowFragility)
1109
+ }),
1110
+ ` ${Math.round(profile.primary.workflowFragility)}% ${riskLabel(profile.primary.workflowFragility)}`
1111
+ ]
1112
+ }),
1113
+ /* @__PURE__ */ jsx(Text, {
1114
+ color: "gray",
1115
+ children: "\u2500".repeat(55)
1116
+ }),
1117
+ /* @__PURE__ */ jsxs(Box, {
1118
+ flexDirection: "column",
1119
+ children: [
1120
+ /* @__PURE__ */ jsxs(Text, {
1121
+ dimColor: true,
1122
+ children: [
1123
+ "complexity ",
1124
+ Math.round(profile.secondary.complexity)
1125
+ ]
1126
+ }),
1127
+ profile.secondary.collaboration > 0 ? /* @__PURE__ */ jsxs(Text, {
1128
+ dimColor: true,
1129
+ children: [
1130
+ "collaboration ",
1131
+ Math.round(profile.secondary.collaboration)
1132
+ ]
1133
+ }) : /* @__PURE__ */ jsx(Text, {
1134
+ dimColor: true,
1135
+ children: "collaboration Solo developer detected"
1136
+ }),
1137
+ profile.secondary.aiExposure > 0 ? /* @__PURE__ */ jsxs(Text, {
1138
+ dimColor: true,
1139
+ children: [
1140
+ "AI exposure ",
1141
+ Math.round(profile.secondary.aiExposure)
1142
+ ]
1143
+ }) : /* @__PURE__ */ jsx(Text, {
1144
+ dimColor: true,
1145
+ children: "AI exposure Tracking begins after first session"
1146
+ }),
1147
+ profile.secondary.structuralRisk > 0 && /* @__PURE__ */ jsxs(Text, {
1148
+ dimColor: true,
1149
+ children: [
1150
+ "structural ",
1151
+ Math.round(profile.secondary.structuralRisk)
1152
+ ]
1153
+ })
1154
+ ]
1155
+ })
1156
+ ]
1157
+ }),
1158
+ /* @__PURE__ */ jsxs(Box, {
1159
+ marginTop: 1,
1160
+ flexDirection: "column",
1161
+ children: [
1162
+ topDriver && /* @__PURE__ */ jsxs(Text, {
1163
+ children: [
1164
+ "Top driver: ",
1165
+ topDriver.label
1166
+ ]
1167
+ }),
1168
+ /* @__PURE__ */ jsxs(Text, {
1169
+ children: [
1170
+ "Confidence: ",
1171
+ profile.confidence >= 0.7 ? "high" : profile.confidence >= 0.4 ? "moderate" : "low"
1172
+ ]
1173
+ })
1174
+ ]
1175
+ })
1176
+ ]
1177
+ });
1178
+ }
1179
+ __name(ProfileMetrics, "ProfileMetrics");
1180
+ function Profile({ profile, onContinue }) {
1181
+ useInput((_input, key) => {
1182
+ if (key.return) {
1183
+ onContinue();
1184
+ }
1185
+ });
1186
+ const { isWide } = useTerminalLayout();
1187
+ return /* @__PURE__ */ jsxs(Box, {
1188
+ flexDirection: "column",
1189
+ borderStyle: "round",
1190
+ padding: 1,
1191
+ children: [
1192
+ isWide ? /* @__PURE__ */ jsxs(Box, {
1193
+ children: [
1194
+ /* @__PURE__ */ jsx(Box, {
1195
+ width: 45,
1196
+ flexShrink: 0,
1197
+ children: /* @__PURE__ */ jsx(Logo, {})
1198
+ }),
1199
+ /* @__PURE__ */ jsx(Box, {
1200
+ flexGrow: 1,
1201
+ children: /* @__PURE__ */ jsx(ProfileMetrics, {
1202
+ profile
1203
+ })
1204
+ })
1205
+ ]
1206
+ }) : /* @__PURE__ */ jsx(ProfileMetrics, {
1207
+ profile
1208
+ }),
1209
+ /* @__PURE__ */ jsx(Box, {
1210
+ marginTop: 1,
1211
+ children: /* @__PURE__ */ jsxs(Text, {
1212
+ color: BRAND_COLORS.primary,
1213
+ children: [
1214
+ "Press [ENTER] to see what we found ",
1215
+ "\u2192"
1216
+ ]
1217
+ })
1218
+ })
1219
+ ]
1220
+ });
1221
+ }
1222
+ __name(Profile, "Profile");
1223
+
1224
+ // src/ui/init/InitApp.tsx
1225
+ var MIN_SCAN_DISPLAY_MS = 4e3;
1226
+ function ScanningFrame({ repoPath, onComplete }) {
1227
+ const { done, errored } = useAnalysis(repoPath, onComplete, MIN_SCAN_DISPLAY_MS);
1228
+ const statusLabel = done ? "[\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588] done" : errored ? "[ error ]" : "[\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591] ...";
1229
+ return /* @__PURE__ */ jsxs(Box, {
1230
+ flexDirection: "column",
1231
+ borderStyle: "round",
1232
+ padding: 1,
1233
+ children: [
1234
+ /* @__PURE__ */ jsx(Text, {
1235
+ children: "Scanning your development history..."
1236
+ }),
1237
+ /* @__PURE__ */ jsxs(Box, {
1238
+ marginTop: 1,
1239
+ flexDirection: "column",
1240
+ children: [
1241
+ /* @__PURE__ */ jsxs(Text, {
1242
+ children: [
1243
+ "Reflog Analysis ",
1244
+ statusLabel
1245
+ ]
1246
+ }),
1247
+ /* @__PURE__ */ jsxs(Text, {
1248
+ children: [
1249
+ "Commit Patterns ",
1250
+ statusLabel
1251
+ ]
1252
+ }),
1253
+ /* @__PURE__ */ jsxs(Text, {
1254
+ children: [
1255
+ "Repo Structure ",
1256
+ statusLabel
1257
+ ]
1258
+ }),
1259
+ /* @__PURE__ */ jsxs(Text, {
1260
+ children: [
1261
+ "Dependency Analysis ",
1262
+ statusLabel
1263
+ ]
1264
+ })
1265
+ ]
1266
+ }),
1267
+ /* @__PURE__ */ jsxs(Box, {
1268
+ marginTop: 1,
1269
+ flexDirection: "column",
1270
+ children: [
1271
+ /* @__PURE__ */ jsxs(Text, {
1272
+ color: "green",
1273
+ children: [
1274
+ "\u{1F512}",
1275
+ " Metadata only - file contents are never read"
1276
+ ]
1277
+ }),
1278
+ /* @__PURE__ */ jsxs(Text, {
1279
+ dimColor: true,
1280
+ children: [
1281
+ "\u2601",
1282
+ " Baseline comparison: disabled (offline mode)"
1283
+ ]
1284
+ })
1285
+ ]
1286
+ })
1287
+ ]
1288
+ });
1289
+ }
1290
+ __name(ScanningFrame, "ScanningFrame");
1291
+ var FRAME_ENABLED_MAP = {
1292
+ VIRGIN: {
1293
+ detection: true,
1294
+ scanning: true,
1295
+ profile: true,
1296
+ insights: true,
1297
+ consent: true,
1298
+ activation: true
1299
+ },
1300
+ NEW_WORKSPACE: {
1301
+ detection: false,
1302
+ scanning: true,
1303
+ profile: true,
1304
+ insights: true,
1305
+ consent: true,
1306
+ activation: true
1307
+ },
1308
+ COLD_RETURN: {
1309
+ detection: false,
1310
+ scanning: true,
1311
+ profile: true,
1312
+ insights: true,
1313
+ consent: false,
1314
+ activation: true
1315
+ },
1316
+ WARM_RETURN: {
1317
+ detection: false,
1318
+ scanning: false,
1319
+ profile: true,
1320
+ insights: false,
1321
+ consent: false,
1322
+ activation: true
1323
+ },
1324
+ HOT_RECONNECT: {
1325
+ detection: false,
1326
+ scanning: false,
1327
+ profile: false,
1328
+ insights: false,
1329
+ consent: false,
1330
+ activation: true
1331
+ }
1332
+ };
1333
+ function isFrameEnabled(frame, profile = "COLD_RETURN") {
1334
+ return FRAME_ENABLED_MAP[profile]?.[frame] ?? true;
1335
+ }
1336
+ __name(isFrameEnabled, "isFrameEnabled");
1337
+ function InitApp({ pathArg, options, initProfile }) {
1338
+ const [stage, setStage] = useState("detection");
1339
+ const [profile, setProfile] = useState(null);
1340
+ const repoPath = typeof pathArg === "string" && pathArg || process.cwd();
1341
+ const handleNextStage = useCallback(() => {
1342
+ const allStages = [
1343
+ "detection",
1344
+ "scanning",
1345
+ "profile",
1346
+ "insights",
1347
+ "consent",
1348
+ "activation"
1349
+ ];
1350
+ const profile2 = initProfile ?? "COLD_RETURN";
1351
+ const enabledStages = allStages.filter((s) => isFrameEnabled(s, profile2));
1352
+ const currentIndex = enabledStages.indexOf(stage);
1353
+ if (currentIndex < enabledStages.length - 1) {
1354
+ const nextStage = enabledStages[currentIndex + 1];
1355
+ setStage(nextStage);
1356
+ }
1357
+ }, [
1358
+ stage,
1359
+ initProfile
1360
+ ]);
1361
+ const handlePrevStage = useCallback(() => {
1362
+ const allStages = [
1363
+ "detection",
1364
+ "scanning",
1365
+ "profile",
1366
+ "insights",
1367
+ "consent",
1368
+ "activation"
1369
+ ];
1370
+ const profile2 = initProfile ?? "COLD_RETURN";
1371
+ const enabledStages = allStages.filter((s) => isFrameEnabled(s, profile2));
1372
+ const currentIndex = enabledStages.indexOf(stage);
1373
+ if (currentIndex > 0) {
1374
+ const prevStage = enabledStages[currentIndex - 1];
1375
+ setStage(prevStage);
1376
+ }
1377
+ }, [
1378
+ stage,
1379
+ initProfile
1380
+ ]);
1381
+ useKeyboard({
1382
+ onEnter: handleNextStage,
1383
+ onEscape: /* @__PURE__ */ __name(() => {
1384
+ process.exit(0);
1385
+ }, "onEscape"),
1386
+ onArrowRight: handleNextStage,
1387
+ onArrowLeft: handlePrevStage,
1388
+ enabled: stage === "profile" || stage === "insights" || stage === "activation"
1389
+ });
1390
+ useEffect(() => {
1391
+ }, [
1392
+ stage
1393
+ ]);
1394
+ const isGitRepo = existsSync(join(repoPath, ".git"));
1395
+ if (!isGitRepo) {
1396
+ return /* @__PURE__ */ jsxs(Box, {
1397
+ flexDirection: "column",
1398
+ padding: 1,
1399
+ children: [
1400
+ /* @__PURE__ */ jsx(Text, {
1401
+ children: "Vreko requires a Git repository."
1402
+ }),
1403
+ /* @__PURE__ */ jsxs(Box, {
1404
+ marginTop: 1,
1405
+ flexDirection: "column",
1406
+ children: [
1407
+ /* @__PURE__ */ jsxs(Text, {
1408
+ children: [
1409
+ "Initialize one with: ",
1410
+ /* @__PURE__ */ jsx(Text, {
1411
+ color: "cyan",
1412
+ children: "git init"
1413
+ })
1414
+ ]
1415
+ }),
1416
+ /* @__PURE__ */ jsxs(Text, {
1417
+ children: [
1418
+ "Then run: ",
1419
+ /* @__PURE__ */ jsx(Text, {
1420
+ color: "cyan",
1421
+ children: "vr init"
1422
+ })
1423
+ ]
1424
+ })
1425
+ ]
1426
+ })
1427
+ ]
1428
+ });
1429
+ }
1430
+ const handleScanComplete = useCallback((p) => {
1431
+ setProfile(p);
1432
+ setStage("profile");
1433
+ }, []);
1434
+ return /* @__PURE__ */ jsxs(Box, {
1435
+ flexDirection: "column",
1436
+ padding: 1,
1437
+ width: 80,
1438
+ children: [
1439
+ (stage === "detection" || stage === "scanning") && /* @__PURE__ */ jsx(Logo, {}),
1440
+ stage === "detection" && isFrameEnabled("detection", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(Detection, {
1441
+ repoPath,
1442
+ onReady: /* @__PURE__ */ __name(() => setStage("scanning"), "onReady")
1443
+ }),
1444
+ stage === "scanning" && isFrameEnabled("scanning", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(ScanningFrame, {
1445
+ repoPath,
1446
+ onComplete: handleScanComplete
1447
+ }),
1448
+ stage === "profile" && profile && isFrameEnabled("profile", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(Profile, {
1449
+ profile,
1450
+ onContinue: /* @__PURE__ */ __name(() => setStage("insights"), "onContinue")
1451
+ }),
1452
+ stage === "insights" && profile && isFrameEnabled("insights", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(Insights, {
1453
+ profile,
1454
+ onContinue: /* @__PURE__ */ __name(() => setStage("consent"), "onContinue")
1455
+ }),
1456
+ stage === "consent" && isFrameEnabled("consent", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(Consent, {
1457
+ onAccept: /* @__PURE__ */ __name(() => setStage("activation"), "onAccept")
1458
+ }),
1459
+ stage === "activation" && profile && isFrameEnabled("activation", initProfile ?? "COLD_RETURN") && /* @__PURE__ */ jsx(Activation, {
1460
+ profile,
1461
+ repoPath,
1462
+ force: options.force
1463
+ }),
1464
+ (stage === "profile" || stage === "insights" || stage === "activation") && /* @__PURE__ */ jsx(Box, {
1465
+ marginTop: 1,
1466
+ flexDirection: "column",
1467
+ children: /* @__PURE__ */ jsx(Text, {
1468
+ dimColor: true,
1469
+ children: "Press Enter or \u2192 to continue | \u2190 to go back | ESC to cancel"
1470
+ })
1471
+ })
1472
+ ]
1473
+ });
1474
+ }
1475
+ __name(InitApp, "InitApp");
1476
+
1477
+ export { InitApp, MIN_SCAN_DISPLAY_MS, isFrameEnabled };
1478
+ //# sourceMappingURL=InitApp-7K5DTYSW.js.map
1479
+ //# sourceMappingURL=InitApp-7K5DTYSW.js.map