@viberaven/cli 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -31,9 +31,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  ));
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
- // ../../node_modules/picocolors/picocolors.js
34
+ // ../../../../node_modules/picocolors/picocolors.js
35
35
  var require_picocolors = __commonJS({
36
- "../../node_modules/picocolors/picocolors.js"(exports2, module2) {
36
+ "../../../../node_modules/picocolors/picocolors.js"(exports2, module2) {
37
37
  var p2 = process || {};
38
38
  var argv = p2.argv || [];
39
39
  var env = p2.env || {};
@@ -103,9 +103,9 @@ var require_picocolors = __commonJS({
103
103
  }
104
104
  });
105
105
 
106
- // ../../node_modules/sisteransi/src/index.js
106
+ // ../../../../node_modules/sisteransi/src/index.js
107
107
  var require_src = __commonJS({
108
- "../../node_modules/sisteransi/src/index.js"(exports2, module2) {
108
+ "../../../../node_modules/sisteransi/src/index.js"(exports2, module2) {
109
109
  "use strict";
110
110
  var ESC = "\x1B";
111
111
  var CSI = `${ESC}[`;
@@ -170,8 +170,8 @@ __export(cli_exports, {
170
170
  runScanCommand: () => runScanCommand
171
171
  });
172
172
  module.exports = __toCommonJS(cli_exports);
173
- var import_promises19 = require("node:fs/promises");
174
- var import_node_path25 = require("node:path");
173
+ var import_promises25 = require("node:fs/promises");
174
+ var import_node_path31 = require("node:path");
175
175
 
176
176
  // src/config.ts
177
177
  var import_node_os = require("node:os");
@@ -655,6 +655,7 @@ var PUBLIC_INIT_ALL_COMMAND = `${PUBLIC_COMMAND} init --agents all`;
655
655
  var PUBLIC_AUDIT_COMMAND = `${PUBLIC_COMMAND} audit --vercel-supabase`;
656
656
  var PUBLIC_NEXT_JSON_COMMAND = `${PUBLIC_COMMAND} next --json`;
657
657
  var PUBLIC_CLEAN_PLAN_COMMAND = `${PUBLIC_COMMAND} clean --plan`;
658
+ var PUBLIC_ACTIONS_COMMAND = `${PUBLIC_COMMAND} actions`;
658
659
  function promptGapCommand(gapId) {
659
660
  return `${PUBLIC_COMMAND} prompt --gap ${gapId}`;
660
661
  }
@@ -2215,20 +2216,20 @@ function mapEvidenceSourceToLegacyEvidenceClass(source, status) {
2215
2216
  }
2216
2217
  return "mcp-verifier";
2217
2218
  }
2218
- function isProviderLayerCheck(check2) {
2219
- return check2.evidenceSource === "provider" || check2.evidenceSource === "mcp";
2219
+ function isProviderLayerCheck(check) {
2220
+ return check.evidenceSource === "provider" || check.evidenceSource === "mcp";
2220
2221
  }
2221
- function isRepoLayerCheck(check2) {
2222
- return check2.evidenceSource === "repo";
2222
+ function isRepoLayerCheck(check) {
2223
+ return check.evidenceSource === "repo";
2223
2224
  }
2224
2225
  function computeLayerReadinessPercent(checks, layer) {
2225
2226
  const filtered = checks.filter(
2226
- (check2) => layer === "repo" ? isRepoLayerCheck(check2) : isProviderLayerCheck(check2)
2227
+ (check) => layer === "repo" ? isRepoLayerCheck(check) : isProviderLayerCheck(check)
2227
2228
  );
2228
2229
  if (filtered.length === 0) {
2229
2230
  return 100;
2230
2231
  }
2231
- const verified = filtered.filter((check2) => check2.status === "verified").length;
2232
+ const verified = filtered.filter((check) => check.status === "verified").length;
2232
2233
  return Math.round(verified / filtered.length * 100);
2233
2234
  }
2234
2235
  function aggregateReadinessPercents(providerResults) {
@@ -2260,7 +2261,7 @@ function mergeVerificationIntoMissionGraph(graph, layer) {
2260
2261
  if (!mission) {
2261
2262
  continue;
2262
2263
  }
2263
- if (mission.checks.some((check2) => check2.verificationCheckId === layerCheck.id || check2.id === missionRowId(layerCheck.id))) {
2264
+ if (mission.checks.some((check) => check.verificationCheckId === layerCheck.id || check.id === missionRowId(layerCheck.id))) {
2264
2265
  continue;
2265
2266
  }
2266
2267
  mission.checks.push(verificationCheckToMissionCheck(layerCheck, mission));
@@ -2351,7 +2352,7 @@ function readinessPercentForRepoChecks(checks) {
2351
2352
  if (repoChecks.length === 0) {
2352
2353
  return 100;
2353
2354
  }
2354
- const verified = repoChecks.filter((check2) => isVerifiedMissionCheck(check2)).length;
2355
+ const verified = repoChecks.filter((check) => isVerifiedMissionCheck(check)).length;
2355
2356
  return Math.round(verified / repoChecks.length * 100);
2356
2357
  }
2357
2358
  function readinessPercentForProviderChecks(checks) {
@@ -2359,29 +2360,29 @@ function readinessPercentForProviderChecks(checks) {
2359
2360
  if (providerChecks.length === 0) {
2360
2361
  return 100;
2361
2362
  }
2362
- const verified = providerChecks.filter((check2) => isVerifiedMissionCheck(check2)).length;
2363
+ const verified = providerChecks.filter((check) => isVerifiedMissionCheck(check)).length;
2363
2364
  return Math.round(verified / providerChecks.length * 100);
2364
2365
  }
2365
- function isRepoLayerMissionCheck(check2) {
2366
- if (check2.evidenceSource === "provider" || check2.evidenceSource === "mcp" || check2.evidenceSource === "manual") {
2366
+ function isRepoLayerMissionCheck(check) {
2367
+ if (check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.evidenceSource === "manual") {
2367
2368
  return false;
2368
2369
  }
2369
- if (check2.evidenceSource === "repo") {
2370
+ if (check.evidenceSource === "repo") {
2370
2371
  return true;
2371
2372
  }
2372
- return check2.evidenceClass === "repo-verified" || check2.evidenceClass === "missing-repo-fix";
2373
+ return check.evidenceClass === "repo-verified" || check.evidenceClass === "missing-repo-fix";
2373
2374
  }
2374
- function isProviderLayerMissionCheck(check2) {
2375
- if (check2.evidenceSource === "provider" || check2.evidenceSource === "mcp") {
2375
+ function isProviderLayerMissionCheck(check) {
2376
+ if (check.evidenceSource === "provider" || check.evidenceSource === "mcp") {
2376
2377
  return true;
2377
2378
  }
2378
- return check2.evidenceClass === "mcp-verifier";
2379
+ return check.evidenceClass === "mcp-verifier";
2379
2380
  }
2380
- function isVerifiedMissionCheck(check2) {
2381
- if (check2.verificationStatus) {
2382
- return check2.verificationStatus === "verified";
2381
+ function isVerifiedMissionCheck(check) {
2382
+ if (check.verificationStatus) {
2383
+ return check.verificationStatus === "verified";
2383
2384
  }
2384
- return check2.status === "passed" || check2.status === "user-confirmed";
2385
+ return check.status === "passed" || check.status === "user-confirmed";
2385
2386
  }
2386
2387
  function rebuildAreas(providerMissions) {
2387
2388
  const byArea = /* @__PURE__ */ new Map();
@@ -2410,7 +2411,7 @@ function rebuildAreas(providerMissions) {
2410
2411
  const repoReadinessPercent = percentVerified(repoChecks);
2411
2412
  const providerReadinessPercent = percentVerified(providerChecks);
2412
2413
  const criticalCount = missions.flatMap((m2) => m2.checks).filter(
2413
- (check2) => isProviderLayerMissionCheck(check2) && (check2.verificationStatus === "missing" || check2.status === "missing" || check2.status === "failed")
2414
+ (check) => isProviderLayerMissionCheck(check) && (check.verificationStatus === "missing" || check.status === "missing" || check.status === "failed")
2414
2415
  ).length;
2415
2416
  return {
2416
2417
  key,
@@ -2427,7 +2428,7 @@ function percentVerified(checks) {
2427
2428
  if (checks.length === 0) {
2428
2429
  return 100;
2429
2430
  }
2430
- const verified = checks.filter((check2) => isVerifiedMissionCheck(check2)).length;
2431
+ const verified = checks.filter((check) => isVerifiedMissionCheck(check)).length;
2431
2432
  return Math.round(verified / checks.length * 100);
2432
2433
  }
2433
2434
 
@@ -2492,7 +2493,7 @@ function toProviderMission(summary) {
2492
2493
  promptSubject: summary.promptSubject,
2493
2494
  readinessPercent: summary.readinessPercent,
2494
2495
  repoReadinessPercent: summary.readinessPercent,
2495
- providerReadinessPercent: checks.some((check2) => check2.evidenceClass === "mcp-verifier") ? 0 : 100,
2496
+ providerReadinessPercent: checks.some((check) => check.evidenceClass === "mcp-verifier") ? 0 : 100,
2496
2497
  checks
2497
2498
  };
2498
2499
  }
@@ -2537,7 +2538,7 @@ function overlaySifgLeaks(providerMissions, graph) {
2537
2538
  const providerCheckIds = new Map(
2538
2539
  providerMissions.map((mission) => [
2539
2540
  mission.key,
2540
- new Set(mission.checks.map((check2) => check2.id))
2541
+ new Set(mission.checks.map((check) => check.id))
2541
2542
  ])
2542
2543
  );
2543
2544
  for (const leak of graph.leaks) {
@@ -2556,9 +2557,9 @@ function overlaySifgLeaks(providerMissions, graph) {
2556
2557
  continue;
2557
2558
  }
2558
2559
  const usedCheckIds = providerCheckIds.get(mission.key) ?? /* @__PURE__ */ new Set();
2559
- const check2 = toSifgMissionCheck(mission, pipeline, pipelineId, leaks, usedCheckIds);
2560
- mission.checks.push(check2);
2561
- usedCheckIds.add(check2.id);
2560
+ const check = toSifgMissionCheck(mission, pipeline, pipelineId, leaks, usedCheckIds);
2561
+ mission.checks.push(check);
2562
+ usedCheckIds.add(check.id);
2562
2563
  providerCheckIds.set(mission.key, usedCheckIds);
2563
2564
  }
2564
2565
  for (const mission of providerMissions) {
@@ -2609,11 +2610,11 @@ function stableSifgSuffix(id) {
2609
2610
  }
2610
2611
  function readinessPercentForChecks(checks) {
2611
2612
  const actionableChecks = checks.filter(isActionableCheck);
2612
- const passed = actionableChecks.filter((check2) => check2.status === "passed").length;
2613
+ const passed = actionableChecks.filter((check) => check.status === "passed").length;
2613
2614
  return Math.round(passed / Math.max(actionableChecks.length, 1) * 100);
2614
2615
  }
2615
- function isActionableCheck(check2) {
2616
- return check2.evidenceClass !== "manual-dashboard" && check2.evidenceClass !== "mcp-verifier";
2616
+ function isActionableCheck(check) {
2617
+ return check.evidenceClass !== "manual-dashboard" && check.evidenceClass !== "mcp-verifier";
2617
2618
  }
2618
2619
  function buildAreas(providerMissions) {
2619
2620
  const byArea = /* @__PURE__ */ new Map();
@@ -2624,15 +2625,15 @@ function buildAreas(providerMissions) {
2624
2625
  }
2625
2626
  return [...byArea.entries()].map(([key, missions]) => {
2626
2627
  const actionableChecks = missions.flatMap((mission) => mission.checks).filter(isActionableCheck);
2627
- const passed = actionableChecks.filter((check2) => check2.status === "passed").length;
2628
- const missing = actionableChecks.filter((check2) => check2.status === "missing" || check2.status === "failed").length;
2628
+ const passed = actionableChecks.filter((check) => check.status === "passed").length;
2629
+ const missing = actionableChecks.filter((check) => check.status === "missing" || check.status === "failed").length;
2629
2630
  return {
2630
2631
  key,
2631
2632
  label: AREA_LABELS[key],
2632
2633
  readinessPercent: Math.round(passed / Math.max(actionableChecks.length, 1) * 100),
2633
2634
  repoReadinessPercent: Math.round(passed / Math.max(actionableChecks.length, 1) * 100),
2634
2635
  providerReadinessPercent: missions.some(
2635
- (mission) => mission.checks.some((check2) => check2.evidenceClass === "mcp-verifier")
2636
+ (mission) => mission.checks.some((check) => check.evidenceClass === "mcp-verifier")
2636
2637
  ) ? 0 : 100,
2637
2638
  criticalCount: missing,
2638
2639
  providerMissions: missions
@@ -7586,9 +7587,9 @@ function runVerifier(verifier, ctx) {
7586
7587
  }
7587
7588
  const connectionState = verifier.connectStatus(ctx);
7588
7589
  const rawChecks = verifier.runChecks(ctx);
7589
- const checks = rawChecks.map((check2) => ({
7590
- ...check2,
7591
- status: coerceProviderVerificationStatus(check2.status, connectionState)
7590
+ const checks = rawChecks.map((check) => ({
7591
+ ...check,
7592
+ status: coerceProviderVerificationStatus(check.status, connectionState)
7592
7593
  }));
7593
7594
  const diffs = verifier.buildDiffs(ctx);
7594
7595
  return {
@@ -7991,8 +7992,8 @@ async function runProjectScan(options) {
7991
7992
  }
7992
7993
 
7993
7994
  // src/artifacts.ts
7994
- var import_promises5 = require("node:fs/promises");
7995
- var import_node_path8 = require("node:path");
7995
+ var import_promises7 = require("node:fs/promises");
7996
+ var import_node_path10 = require("node:path");
7996
7997
 
7997
7998
  // src/capabilities/classify.ts
7998
7999
  function gapText(gap) {
@@ -8313,24 +8314,24 @@ var CHECK_TO_PLAYBOOK = {
8313
8314
  "stripe-product": "stripe",
8314
8315
  "stripe-keys": "stripe"
8315
8316
  };
8316
- function mapCheckToPlaybook(check2) {
8317
- if (CHECK_TO_PLAYBOOK[check2.id]) {
8318
- return CHECK_TO_PLAYBOOK[check2.id];
8317
+ function mapCheckToPlaybook(check) {
8318
+ if (CHECK_TO_PLAYBOOK[check.id]) {
8319
+ return CHECK_TO_PLAYBOOK[check.id];
8319
8320
  }
8320
- const providerKey = check2.providerKey.toLowerCase();
8321
- if (providerKey.includes("vercel") || check2.area === "deployment") {
8321
+ const providerKey = check.providerKey.toLowerCase();
8322
+ if (providerKey.includes("vercel") || check.area === "deployment") {
8322
8323
  return "vercel";
8323
8324
  }
8324
- if (providerKey.includes("stripe") || check2.area === "payments") {
8325
+ if (providerKey.includes("stripe") || check.area === "payments") {
8325
8326
  return "stripe";
8326
8327
  }
8327
- if (providerKey.includes("supabase") && check2.area === "auth") {
8328
+ if (providerKey.includes("supabase") && check.area === "auth") {
8328
8329
  return "auth-supabase";
8329
8330
  }
8330
- if (providerKey.includes("supabase") || check2.area === "database") {
8331
+ if (providerKey.includes("supabase") || check.area === "database") {
8331
8332
  return "supabase";
8332
8333
  }
8333
- if (check2.area === "auth") {
8334
+ if (check.area === "auth") {
8334
8335
  return "auth-supabase";
8335
8336
  }
8336
8337
  return "vercel";
@@ -8471,21 +8472,21 @@ function loadPlaybookSync(provider2) {
8471
8472
  }
8472
8473
 
8473
8474
  // src/playbooks/manualChecks.ts
8474
- function isManualProviderCheck(check2) {
8475
- return check2.evidenceClass === "manual-dashboard" || check2.evidenceClass === "mcp-verifier" || check2.evidenceSource === "provider" || check2.evidenceSource === "mcp" || check2.status === "needs-connection" || check2.status === "unknown";
8475
+ function isManualProviderCheck(check) {
8476
+ return check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown";
8476
8477
  }
8477
8478
  function collectManualChecks(artifact) {
8478
8479
  const refs = [];
8479
8480
  for (const area of artifact.missionGraph.areas ?? []) {
8480
8481
  for (const mission of area.providerMissions) {
8481
- for (const check2 of mission.checks) {
8482
- if (!isManualProviderCheck(check2)) {
8482
+ for (const check of mission.checks) {
8483
+ if (!isManualProviderCheck(check)) {
8483
8484
  continue;
8484
8485
  }
8485
8486
  refs.push({
8486
8487
  areaLabel: area.label,
8487
8488
  providerLabel: mission.providerLabel,
8488
- check: check2,
8489
+ check,
8489
8490
  mapCategory: area.key
8490
8491
  });
8491
8492
  }
@@ -8751,8 +8752,8 @@ function generateAgentSummary(artifact) {
8751
8752
  const manualChecks = (artifact.missionGraph.areas ?? []).flatMap(
8752
8753
  (area) => area.providerMissions.flatMap(
8753
8754
  (mission) => mission.checks.filter(
8754
- (check2) => check2.evidenceClass === "manual-dashboard" || check2.evidenceClass === "mcp-verifier" || check2.evidenceSource === "provider" || check2.evidenceSource === "mcp" || check2.status === "needs-connection" || check2.status === "unknown"
8755
- ).map((check2) => ({ area: area.label, provider: mission.providerLabel, check: check2 }))
8755
+ (check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
8756
+ ).map((check) => ({ area: area.label, provider: mission.providerLabel, check }))
8756
8757
  )
8757
8758
  );
8758
8759
  lines.push("");
@@ -9407,28 +9408,379 @@ function sanitizeArtifactForDisk(artifact) {
9407
9408
  return redactUnknown(artifact);
9408
9409
  }
9409
9410
 
9411
+ // src/actions/artifacts.ts
9412
+ var import_promises6 = require("node:fs/promises");
9413
+ var import_node_path9 = require("node:path");
9414
+
9415
+ // src/actions/canonical.ts
9416
+ var REPO_MARKERS = [
9417
+ "/app/",
9418
+ "/src/",
9419
+ "/pages/",
9420
+ "/components/",
9421
+ "/lib/",
9422
+ "/server/",
9423
+ "/api/",
9424
+ "/supabase/",
9425
+ "/prisma/",
9426
+ "/drizzle/",
9427
+ "/db/",
9428
+ "/migrations/",
9429
+ "/vercel/",
9430
+ "/.github/"
9431
+ ];
9432
+ function slashPath(value) {
9433
+ return value.replace(/\\/g, "/").replace(/\/+/g, "/").trim();
9434
+ }
9435
+ function stripQueryAndHash(value) {
9436
+ const queryIndex = value.search(/[?#]/);
9437
+ return queryIndex === -1 ? value : value.slice(0, queryIndex);
9438
+ }
9439
+ function trimSlashes(value) {
9440
+ return value.replace(/^\/+/, "").replace(/\/+$/, "");
9441
+ }
9442
+ function stripWindowsDrive(value) {
9443
+ return value.replace(/^[a-z]:\//i, "");
9444
+ }
9445
+ function stripAbsolutePrefix(value) {
9446
+ const normalized = slashPath(value);
9447
+ const isAbsolute2 = /^[a-z]:\//i.test(normalized) || normalized.startsWith("/");
9448
+ if (!isAbsolute2) {
9449
+ return normalized;
9450
+ }
9451
+ const lower = normalized.toLowerCase();
9452
+ for (const marker of REPO_MARKERS) {
9453
+ const index = lower.lastIndexOf(marker);
9454
+ if (index !== -1) {
9455
+ return normalized.slice(index + 1);
9456
+ }
9457
+ }
9458
+ return stripWindowsDrive(normalized).replace(/^users\/[^/]+\//i, "").replace(/^home\/[^/]+\//i, "");
9459
+ }
9460
+ function normalizeActionPath(path) {
9461
+ return trimSlashes(stripAbsolutePrefix(stripQueryAndHash(path))).toLowerCase();
9462
+ }
9463
+ function displayRepoPath(path) {
9464
+ return trimSlashes(stripAbsolutePrefix(stripQueryAndHash(path)));
9465
+ }
9466
+ function normalizeActionValues(values = []) {
9467
+ return Array.from(new Set(values.map((value) => value.trim().toLowerCase()).filter(Boolean))).sort();
9468
+ }
9469
+ function normalizeSegment(value) {
9470
+ const normalized = value?.trim().toLowerCase();
9471
+ return normalized || void 0;
9472
+ }
9473
+ function buildActionKey(input) {
9474
+ const segments = [
9475
+ normalizeSegment(input.kind),
9476
+ normalizeSegment(input.provider),
9477
+ normalizeSegment(input.category),
9478
+ input.target ? normalizeActionPath(input.target) : void 0
9479
+ ].filter((segment) => Boolean(segment));
9480
+ const values = normalizeActionValues(input.values);
9481
+ if (values.length > 0) {
9482
+ segments.push(values.join(","));
9483
+ }
9484
+ return segments.join(":");
9485
+ }
9486
+ function normalizeFingerprintValue(value) {
9487
+ if (Array.isArray(value)) {
9488
+ const normalized = value.map((entry) => normalizeFingerprintValue(entry)).filter((entry) => entry !== void 0);
9489
+ if (normalized.every((entry) => typeof entry === "string")) {
9490
+ return Array.from(new Set(normalized)).sort();
9491
+ }
9492
+ return normalized;
9493
+ }
9494
+ if (value && typeof value === "object") {
9495
+ return Object.fromEntries(
9496
+ Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalizeFingerprintValue(entry)])
9497
+ );
9498
+ }
9499
+ if (typeof value === "string") {
9500
+ return value.trim();
9501
+ }
9502
+ return value;
9503
+ }
9504
+ function actionFingerprint(value) {
9505
+ return JSON.stringify(normalizeFingerprintValue(value));
9506
+ }
9507
+
9508
+ // src/actions/derive.ts
9509
+ function verifyActionCommand(id) {
9510
+ return `${PUBLIC_COMMAND} verify --action ${id}`;
9511
+ }
9512
+ function providerTitle(task) {
9513
+ const provider2 = task.providerAction?.provider.toLowerCase();
9514
+ if (provider2 === "stripe") {
9515
+ return "Connect Stripe Webhook";
9516
+ }
9517
+ if (provider2 === "supabase") {
9518
+ return "Confirm Supabase Production Proof";
9519
+ }
9520
+ if (provider2 === "vercel") {
9521
+ return "Confirm Vercel Production Setup";
9522
+ }
9523
+ return task.title;
9524
+ }
9525
+ function deriveProviderAction(task) {
9526
+ const provider2 = task.providerAction?.provider.toLowerCase() ?? "provider";
9527
+ const exactStep = task.providerAction?.exactStep ?? task.title;
9528
+ const title = providerTitle(task);
9529
+ const actionKey = buildActionKey({
9530
+ kind: "provider-action",
9531
+ provider: provider2,
9532
+ category: task.gapId,
9533
+ target: exactStep,
9534
+ values: [task.providerAction?.doneSignal ?? ""]
9535
+ });
9536
+ return {
9537
+ id: "pending",
9538
+ actionKey,
9539
+ revision: 1,
9540
+ kind: "provider-action",
9541
+ provider: provider2,
9542
+ title,
9543
+ status: provider2 === "supabase" ? "waiting-on-database-proof" : "waiting-on-provider",
9544
+ severity: task.severity,
9545
+ gapId: task.gapId,
9546
+ readiness: [task.providerAction?.doneSignal ?? "Provider step identified"],
9547
+ target: {
9548
+ type: "provider",
9549
+ label: exactStep,
9550
+ provider: provider2
9551
+ },
9552
+ verifyCommand: verifyActionCommand("pending"),
9553
+ resumeInstruction: `${title} is complete. Continue VibeRaven from pending.`
9554
+ };
9555
+ }
9556
+ function deriveRepoCodeAction(task) {
9557
+ const targetSource = task.file ?? task.gapId;
9558
+ const canonicalFile = normalizeActionPath(targetSource);
9559
+ const displayFile = displayRepoPath(targetSource);
9560
+ const actionKey = buildActionKey({
9561
+ kind: "repo-code",
9562
+ provider: "repo",
9563
+ category: task.gapId,
9564
+ target: canonicalFile,
9565
+ values: [task.mcpTool ?? "", task.exactFix ?? ""]
9566
+ });
9567
+ return {
9568
+ id: "pending",
9569
+ actionKey,
9570
+ revision: 1,
9571
+ kind: "repo-code",
9572
+ title: task.title,
9573
+ status: "active",
9574
+ severity: task.severity,
9575
+ gapId: task.gapId,
9576
+ readiness: [task.exactFix ?? "Repo-code fix is available"],
9577
+ target: task.file ? { type: "file", label: "Repo target", path: displayFile } : { type: "command", label: "Apply repo fix", command: task.mcpTool ?? `${PUBLIC_COMMAND} prompt --gap ${task.gapId}` },
9578
+ fileTargets: task.file ? [{ path: displayFile, reason: task.exactFix }] : void 0,
9579
+ verifyCommand: verifyActionCommand("pending"),
9580
+ resumeInstruction: `${task.title} is complete. Continue VibeRaven from pending.`,
9581
+ mcpTool: task.mcpTool,
9582
+ mcpArgs: task.mcpArgs,
9583
+ fallbackCommand: `${PUBLIC_COMMAND} --heal --apply --gap ${task.gapId} --yes`
9584
+ };
9585
+ }
9586
+ function deriveVerifyAction() {
9587
+ return {
9588
+ id: "pending",
9589
+ actionKey: buildActionKey({
9590
+ kind: "verify",
9591
+ provider: "gate",
9592
+ category: "final",
9593
+ target: `${PUBLIC_COMMAND} --strict`
9594
+ }),
9595
+ revision: 1,
9596
+ kind: "verify",
9597
+ title: "Run Final Verification",
9598
+ status: "blocked",
9599
+ readiness: ["Run after provider and repo-code actions are complete"],
9600
+ target: { type: "command", label: "Final strict gate", command: `${PUBLIC_COMMAND} --strict` },
9601
+ verifyCommand: `${PUBLIC_COMMAND} --strict`,
9602
+ resumeInstruction: "Final verification finished. Continue VibeRaven from pending."
9603
+ };
9604
+ }
9605
+ function deriveCurrentActions(input) {
9606
+ const primaryActions = input.tasks.filter((task) => task.fixType === "provider-action" || task.fixType === "repo-code").map((task) => task.fixType === "provider-action" ? deriveProviderAction(task) : deriveRepoCodeAction(task));
9607
+ return [...primaryActions, deriveVerifyAction()];
9608
+ }
9609
+
9610
+ // src/actions/registry.ts
9611
+ var import_promises5 = require("node:fs/promises");
9612
+ var import_node_path8 = require("node:path");
9613
+ function emptyActionRegistry() {
9614
+ return { version: 1, nextId: 1, actions: {} };
9615
+ }
9616
+ function actionRegistryPath(cwd) {
9617
+ return (0, import_node_path8.join)(getProjectArtifactsDir(cwd), "action-registry.json");
9618
+ }
9619
+ async function loadActionRegistry(cwd) {
9620
+ try {
9621
+ const parsed = JSON.parse(await (0, import_promises5.readFile)(actionRegistryPath(cwd), "utf8"));
9622
+ if (parsed.version === 1 && Number.isInteger(parsed.nextId) && parsed.actions) {
9623
+ return parsed;
9624
+ }
9625
+ } catch {
9626
+ }
9627
+ return emptyActionRegistry();
9628
+ }
9629
+ async function saveActionRegistry(cwd, registry) {
9630
+ const dir = getProjectArtifactsDir(cwd);
9631
+ await (0, import_promises5.mkdir)(dir, { recursive: true });
9632
+ await (0, import_promises5.writeFile)(actionRegistryPath(cwd), `${JSON.stringify(registry, null, 2)}
9633
+ `, "utf8");
9634
+ }
9635
+ function nextActionId(registry) {
9636
+ const id = `VR-A${registry.nextId}`;
9637
+ registry.nextId += 1;
9638
+ return id;
9639
+ }
9640
+ function currentFingerprint(action) {
9641
+ return actionFingerprint({
9642
+ kind: action.kind,
9643
+ title: action.title,
9644
+ provider: action.provider,
9645
+ readiness: action.readiness ?? [],
9646
+ target: action.target,
9647
+ copyPayloads: action.copyPayloads ?? [],
9648
+ fileTargets: action.fileTargets ?? [],
9649
+ verifyCommand: action.verifyCommand,
9650
+ resumeInstruction: action.resumeInstruction
9651
+ });
9652
+ }
9653
+ function replaceActionHandle(value, id) {
9654
+ return value?.replace(/pending|VR-A\d+/g, id);
9655
+ }
9656
+ function replaceActionTarget(action, id) {
9657
+ const { target } = action;
9658
+ if (!target) {
9659
+ return void 0;
9660
+ }
9661
+ if (target.type === "url") {
9662
+ return { ...target, href: replaceActionHandle(target.href, id) ?? target.href };
9663
+ }
9664
+ if (target.type === "command" || target.type === "verify") {
9665
+ return { ...target, command: replaceActionHandle(target.command, id) ?? target.command };
9666
+ }
9667
+ return target;
9668
+ }
9669
+ async function assignActionIds(input) {
9670
+ const now = input.now ?? (/* @__PURE__ */ new Date()).toISOString();
9671
+ const registry = await loadActionRegistry(input.cwd);
9672
+ const seen = /* @__PURE__ */ new Set();
9673
+ const actions = input.actions.map((action) => {
9674
+ seen.add(action.actionKey);
9675
+ const fingerprint = currentFingerprint(action);
9676
+ let entry = registry.actions[action.actionKey];
9677
+ if (!entry) {
9678
+ entry = {
9679
+ id: nextActionId(registry),
9680
+ actionKey: action.actionKey,
9681
+ status: "active",
9682
+ createdAt: now,
9683
+ lastSeenAt: now,
9684
+ revision: 1,
9685
+ fingerprint,
9686
+ title: action.title,
9687
+ gapId: action.gapId,
9688
+ kind: action.kind,
9689
+ provider: action.provider
9690
+ };
9691
+ } else {
9692
+ entry.status = "active";
9693
+ entry.lastSeenAt = now;
9694
+ entry.title = action.title;
9695
+ entry.gapId = action.gapId;
9696
+ entry.kind = action.kind;
9697
+ entry.provider = action.provider;
9698
+ if (entry.fingerprint !== fingerprint) {
9699
+ entry.revision += 1;
9700
+ entry.fingerprint = fingerprint;
9701
+ }
9702
+ }
9703
+ registry.actions[action.actionKey] = entry;
9704
+ return {
9705
+ ...action,
9706
+ id: entry.id,
9707
+ revision: entry.revision,
9708
+ verifyCommand: replaceActionHandle(action.verifyCommand, entry.id),
9709
+ resumeInstruction: replaceActionHandle(action.resumeInstruction, entry.id),
9710
+ target: replaceActionTarget(action, entry.id)
9711
+ };
9712
+ });
9713
+ for (const entry of Object.values(registry.actions)) {
9714
+ if (entry.status === "active" && !seen.has(entry.actionKey)) {
9715
+ entry.status = entry.gapId && input.currentGapIds && !input.currentGapIds.has(entry.gapId) ? "resolved" : "stale";
9716
+ }
9717
+ }
9718
+ await saveActionRegistry(input.cwd, registry);
9719
+ return { actions, registry };
9720
+ }
9721
+ async function resolveActionById(cwd, id) {
9722
+ const registry = await loadActionRegistry(cwd);
9723
+ return Object.values(registry.actions).find((entry) => entry.id === id);
9724
+ }
9725
+
9726
+ // src/actions/artifacts.ts
9727
+ function gateStatus2(artifact) {
9728
+ if (!Array.isArray(artifact.gaps)) {
9729
+ return "unknown";
9730
+ }
9731
+ return artifact.gaps.length === 0 ? "clear" : "not_clear";
9732
+ }
9733
+ async function writeActionArtifacts(input) {
9734
+ const derived = deriveCurrentActions({
9735
+ artifact: input.artifact,
9736
+ tasks: input.tasks,
9737
+ paths: input.paths
9738
+ });
9739
+ const currentGapIds = new Set(input.artifact.gaps.map((gap) => gap.id));
9740
+ const assigned = await assignActionIds({
9741
+ cwd: input.cwd,
9742
+ actions: derived,
9743
+ currentGapIds
9744
+ });
9745
+ const manifest = {
9746
+ version: 1,
9747
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
9748
+ workspaceRoot: ".",
9749
+ gateStatus: gateStatus2(input.artifact),
9750
+ actions: assigned.actions
9751
+ };
9752
+ const actionsPath = (0, import_node_path9.join)(getProjectArtifactsDir(input.cwd), "actions.json");
9753
+ await (0, import_promises6.writeFile)(actionsPath, `${JSON.stringify(manifest, null, 2)}
9754
+ `, "utf8");
9755
+ return {
9756
+ actionsPath,
9757
+ actionRegistryPath: actionRegistryPath(input.cwd),
9758
+ manifest
9759
+ };
9760
+ }
9761
+
9410
9762
  // src/artifacts.ts
9411
9763
  async function copyReportAssets(reportAssetsDir) {
9412
9764
  const sourceDir = getBundledReportAssetsDir();
9413
- await (0, import_promises5.mkdir)((0, import_node_path8.join)(reportAssetsDir, "assets"), { recursive: true });
9765
+ await (0, import_promises7.mkdir)((0, import_node_path10.join)(reportAssetsDir, "assets"), { recursive: true });
9414
9766
  for (const rel of REPORT_ASSET_FILES) {
9415
- await (0, import_promises5.copyFile)((0, import_node_path8.join)(sourceDir, rel), (0, import_node_path8.join)(reportAssetsDir, rel));
9767
+ await (0, import_promises7.copyFile)((0, import_node_path10.join)(sourceDir, rel), (0, import_node_path10.join)(reportAssetsDir, rel));
9416
9768
  }
9417
9769
  }
9418
9770
  async function writeScanArtifacts(options) {
9419
9771
  const cwd = options.cwd ?? options.artifact.workspacePath;
9420
9772
  const dir = getProjectArtifactsDir(cwd);
9421
- await (0, import_promises5.mkdir)(dir, { recursive: true });
9422
- const jsonPath = (0, import_node_path8.join)(dir, "last-scan.json");
9423
- const gateResultPath = (0, import_node_path8.join)(dir, "gate-result.json");
9424
- const contextMapPath = (0, import_node_path8.join)(dir, "context-map.json");
9425
- const gapsDir = (0, import_node_path8.join)(dir, "gaps");
9426
- const tasklistPath = (0, import_node_path8.join)(dir, "agent-tasklist.md");
9427
- const summaryPath = (0, import_node_path8.join)(dir, "agent-summary.md");
9428
- const playbookPath = (0, import_node_path8.join)(dir, "launch-playbook.md");
9429
- const reportPath = (0, import_node_path8.join)(dir, "report.html");
9430
- const reportAssetsDir = (0, import_node_path8.join)(dir, "report");
9431
- await (0, import_promises5.mkdir)(gapsDir, { recursive: true });
9773
+ await (0, import_promises7.mkdir)(dir, { recursive: true });
9774
+ const jsonPath = (0, import_node_path10.join)(dir, "last-scan.json");
9775
+ const gateResultPath = (0, import_node_path10.join)(dir, "gate-result.json");
9776
+ const contextMapPath = (0, import_node_path10.join)(dir, "context-map.json");
9777
+ const gapsDir = (0, import_node_path10.join)(dir, "gaps");
9778
+ const tasklistPath = (0, import_node_path10.join)(dir, "agent-tasklist.md");
9779
+ const summaryPath = (0, import_node_path10.join)(dir, "agent-summary.md");
9780
+ const playbookPath = (0, import_node_path10.join)(dir, "launch-playbook.md");
9781
+ const reportPath = (0, import_node_path10.join)(dir, "report.html");
9782
+ const reportAssetsDir = (0, import_node_path10.join)(dir, "report");
9783
+ await (0, import_promises7.mkdir)(gapsDir, { recursive: true });
9432
9784
  const safe = sanitizeArtifactForDisk(options.artifact);
9433
9785
  const json = `${JSON.stringify(safe, null, 2)}
9434
9786
  `;
@@ -9443,17 +9795,23 @@ async function writeScanArtifacts(options) {
9443
9795
  `;
9444
9796
  const gapEvidenceFiles = generateGapEvidenceFiles(safe);
9445
9797
  await copyReportAssets(reportAssetsDir);
9446
- await (0, import_promises5.writeFile)(gateResultPath, gateResult, "utf-8");
9447
- await (0, import_promises5.writeFile)(contextMapPath, contextMap, "utf-8");
9798
+ await (0, import_promises7.writeFile)(gateResultPath, gateResult, "utf-8");
9799
+ await (0, import_promises7.writeFile)(contextMapPath, contextMap, "utf-8");
9448
9800
  for (const gap of gapEvidenceFiles) {
9449
- await (0, import_promises5.writeFile)((0, import_node_path8.join)(dir, "gaps", `${gap.content.id}.json`), `${JSON.stringify(gap.content, null, 2)}
9801
+ await (0, import_promises7.writeFile)((0, import_node_path10.join)(dir, "gaps", `${gap.content.id}.json`), `${JSON.stringify(gap.content, null, 2)}
9450
9802
  `, "utf-8");
9451
9803
  }
9452
- await (0, import_promises5.writeFile)(tasklistPath, tasklist, "utf-8");
9453
- await (0, import_promises5.writeFile)(jsonPath, json, "utf-8");
9454
- await (0, import_promises5.writeFile)(summaryPath, summary, "utf-8");
9455
- await (0, import_promises5.writeFile)(playbookPath, playbook, "utf-8");
9456
- await (0, import_promises5.writeFile)(reportPath, html, "utf-8");
9804
+ await (0, import_promises7.writeFile)(tasklistPath, tasklist, "utf-8");
9805
+ await (0, import_promises7.writeFile)(jsonPath, json, "utf-8");
9806
+ await (0, import_promises7.writeFile)(summaryPath, summary, "utf-8");
9807
+ await (0, import_promises7.writeFile)(playbookPath, playbook, "utf-8");
9808
+ await (0, import_promises7.writeFile)(reportPath, html, "utf-8");
9809
+ const actionArtifacts = await writeActionArtifacts({
9810
+ cwd,
9811
+ artifact: safe,
9812
+ tasks,
9813
+ paths: { reportPath, playbookPath }
9814
+ });
9457
9815
  return {
9458
9816
  dir,
9459
9817
  jsonPath,
@@ -9464,7 +9822,9 @@ async function writeScanArtifacts(options) {
9464
9822
  summaryPath,
9465
9823
  playbookPath,
9466
9824
  reportPath,
9467
- reportAssetsDir
9825
+ reportAssetsDir,
9826
+ actionsPath: actionArtifacts.actionsPath,
9827
+ actionRegistryPath: actionArtifacts.actionRegistryPath
9468
9828
  };
9469
9829
  }
9470
9830
 
@@ -9573,9 +9933,9 @@ function missionMatchesProvider(mission, provider2) {
9573
9933
  return normalizeProviderToken2(mission.provider || mission.providerLabel || mission.key) === current || normalizeProviderToken2(mission.providerLabel || mission.provider || mission.key) === current;
9574
9934
  }
9575
9935
  function missionEvidenceScore(mission) {
9576
- const repoVerified = mission.checks.filter((check2) => check2.evidenceClass === "repo-verified" || check2.status === "passed").length;
9936
+ const repoVerified = mission.checks.filter((check) => check.evidenceClass === "repo-verified" || check.status === "passed").length;
9577
9937
  const missing = mission.checks.filter(
9578
- (check2) => check2.evidenceClass === "missing-repo-fix" || check2.status === "missing" || check2.status === "failed"
9938
+ (check) => check.evidenceClass === "missing-repo-fix" || check.status === "missing" || check.status === "failed"
9579
9939
  ).length;
9580
9940
  return repoVerified * 100 + (mission.readinessPercent ?? 0) - missing;
9581
9941
  }
@@ -9595,7 +9955,7 @@ function openChecksForMission(mission) {
9595
9955
  return 0;
9596
9956
  }
9597
9957
  return mission.checks.filter(
9598
- (check2) => check2.status === "missing" || check2.status === "failed" || check2.status === "needs-connection"
9958
+ (check) => check.status === "missing" || check.status === "failed" || check.status === "needs-connection"
9599
9959
  ).length;
9600
9960
  }
9601
9961
 
@@ -9627,7 +9987,7 @@ function manualActionCheckCount(artifact) {
9627
9987
  return (artifact.missionGraph.areas ?? []).reduce((areaTotal, area) => {
9628
9988
  return areaTotal + area.providerMissions.reduce((missionTotal, mission) => {
9629
9989
  return missionTotal + mission.checks.filter(
9630
- (check2) => check2.evidenceClass === "manual-dashboard" || check2.evidenceClass === "mcp-verifier" || check2.evidenceSource === "provider" || check2.evidenceSource === "mcp" || check2.status === "needs-connection" || check2.status === "unknown"
9990
+ (check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
9631
9991
  ).length;
9632
9992
  }, 0);
9633
9993
  }, 0);
@@ -9679,7 +10039,7 @@ function printScanSummary(artifact, paths) {
9679
10039
  if (next.upgradeUrl) {
9680
10040
  console.log(`Upgrade: ${next.upgradeUrl}`);
9681
10041
  }
9682
- console.log(formatAgentStatus(AGENT_ACTION, "Keep operating: read .viberaven/agent-tasklist.md, apply the next safe repo fix, then continue the VibeRaven loop."));
10042
+ console.log(formatAgentStatus(AGENT_ACTION, "Read .viberaven/agent-tasklist.md, run the next command above, then rescan."));
9683
10043
  console.log("");
9684
10044
  if (artifact.usage) {
9685
10045
  const lanes = artifact.usage.unlockedMapCategoryKeys.length;
@@ -9704,8 +10064,8 @@ function printScanSummary(artifact, paths) {
9704
10064
  }
9705
10065
 
9706
10066
  // src/runnerConnect.ts
9707
- var import_promises6 = require("node:fs/promises");
9708
- var import_node_path9 = require("node:path");
10067
+ var import_promises8 = require("node:fs/promises");
10068
+ var import_node_path11 = require("node:path");
9709
10069
  var import_node_child_process3 = require("node:child_process");
9710
10070
  var import_node_crypto = require("node:crypto");
9711
10071
 
@@ -10048,12 +10408,12 @@ async function executeSafeFixJob(job, workspaceRoot) {
10048
10408
  }
10049
10409
  async function createSafeFixFile(job, input, targetPath) {
10050
10410
  try {
10051
- await (0, import_promises6.access)(targetPath);
10411
+ await (0, import_promises8.access)(targetPath);
10052
10412
  return safeFixNeedsUser(job, "SAFE_FIX_TARGET_EXISTS", `Refusing to overwrite ${input.path}.`);
10053
10413
  } catch {
10054
10414
  }
10055
10415
  try {
10056
- await (0, import_promises6.mkdir)((0, import_node_path9.dirname)(targetPath), { recursive: true });
10416
+ await (0, import_promises8.mkdir)((0, import_node_path11.dirname)(targetPath), { recursive: true });
10057
10417
  await writeNewFileAtomically(targetPath, input.content);
10058
10418
  } catch {
10059
10419
  return safeFixNeedsUser(job, "SAFE_FIX_WRITE_FAILED", `Could not create ${input.path}.`);
@@ -10063,7 +10423,7 @@ async function createSafeFixFile(job, input, targetPath) {
10063
10423
  async function applySafeFixReplacement(job, input, targetPath) {
10064
10424
  let current;
10065
10425
  try {
10066
- current = await (0, import_promises6.readFile)(targetPath, "utf-8");
10426
+ current = await (0, import_promises8.readFile)(targetPath, "utf-8");
10067
10427
  } catch {
10068
10428
  return safeFixNeedsUser(job, "SAFE_FIX_TARGET_MISSING", `Cannot update missing file ${input.path}.`);
10069
10429
  }
@@ -10121,17 +10481,17 @@ function safeFixNeedsUser(job, code, message) {
10121
10481
  };
10122
10482
  }
10123
10483
  async function resolveSafeFixTarget(workspaceRoot, relativePath) {
10124
- const root = await (0, import_promises6.realpath)(workspaceRoot).catch(() => (0, import_node_path9.resolve)(workspaceRoot));
10125
- const target = (0, import_node_path9.resolve)(root, relativePath);
10484
+ const root = await (0, import_promises8.realpath)(workspaceRoot).catch(() => (0, import_node_path11.resolve)(workspaceRoot));
10485
+ const target = (0, import_node_path11.resolve)(root, relativePath);
10126
10486
  if (!isInsideRoot(root, target)) {
10127
10487
  return { ok: false, reason: "Safe fix target escaped the workspace root." };
10128
10488
  }
10129
- const parent = (0, import_node_path9.dirname)(target);
10489
+ const parent = (0, import_node_path11.dirname)(target);
10130
10490
  const parentReal = await realpathNearestExisting(parent, root);
10131
10491
  if (!isInsideRoot(root, parentReal)) {
10132
10492
  return { ok: false, reason: "Safe fix parent path escaped the workspace root." };
10133
10493
  }
10134
- const targetReal = await (0, import_promises6.realpath)(target).catch(() => null);
10494
+ const targetReal = await (0, import_promises8.realpath)(target).catch(() => null);
10135
10495
  if (targetReal && !isInsideRoot(root, targetReal)) {
10136
10496
  return { ok: false, reason: "Safe fix target path escaped the workspace root." };
10137
10497
  }
@@ -10141,10 +10501,10 @@ async function realpathNearestExisting(path, root) {
10141
10501
  let candidate = path;
10142
10502
  while (isInsideRoot(root, candidate)) {
10143
10503
  try {
10144
- await (0, import_promises6.lstat)(candidate);
10145
- return (0, import_promises6.realpath)(candidate);
10504
+ await (0, import_promises8.lstat)(candidate);
10505
+ return (0, import_promises8.realpath)(candidate);
10146
10506
  } catch {
10147
- const next = (0, import_node_path9.dirname)(candidate);
10507
+ const next = (0, import_node_path11.dirname)(candidate);
10148
10508
  if (next === candidate) {
10149
10509
  break;
10150
10510
  }
@@ -10154,29 +10514,29 @@ async function realpathNearestExisting(path, root) {
10154
10514
  return root;
10155
10515
  }
10156
10516
  function isInsideRoot(root, candidate) {
10157
- const rel = (0, import_node_path9.relative)(root, candidate);
10158
- return rel === "" || !rel.startsWith("..") && !(0, import_node_path9.isAbsolute)(rel);
10517
+ const rel = (0, import_node_path11.relative)(root, candidate);
10518
+ return rel === "" || !rel.startsWith("..") && !(0, import_node_path11.isAbsolute)(rel);
10159
10519
  }
10160
10520
  async function writeNewFileAtomically(targetPath, content) {
10161
10521
  const tempPath = tempPathFor(targetPath);
10162
10522
  try {
10163
- await (0, import_promises6.writeFile)(tempPath, content, { encoding: "utf-8", flag: "wx" });
10164
- await (0, import_promises6.link)(tempPath, targetPath);
10523
+ await (0, import_promises8.writeFile)(tempPath, content, { encoding: "utf-8", flag: "wx" });
10524
+ await (0, import_promises8.link)(tempPath, targetPath);
10165
10525
  } finally {
10166
- await (0, import_promises6.rm)(tempPath, { force: true }).catch(() => void 0);
10526
+ await (0, import_promises8.rm)(tempPath, { force: true }).catch(() => void 0);
10167
10527
  }
10168
10528
  }
10169
10529
  async function replaceFileAtomically(targetPath, content) {
10170
10530
  const tempPath = tempPathFor(targetPath);
10171
10531
  try {
10172
- await (0, import_promises6.writeFile)(tempPath, content, { encoding: "utf-8", flag: "wx" });
10173
- await (0, import_promises6.rename)(tempPath, targetPath);
10532
+ await (0, import_promises8.writeFile)(tempPath, content, { encoding: "utf-8", flag: "wx" });
10533
+ await (0, import_promises8.rename)(tempPath, targetPath);
10174
10534
  } finally {
10175
- await (0, import_promises6.rm)(tempPath, { force: true }).catch(() => void 0);
10535
+ await (0, import_promises8.rm)(tempPath, { force: true }).catch(() => void 0);
10176
10536
  }
10177
10537
  }
10178
10538
  function tempPathFor(targetPath) {
10179
- return (0, import_node_path9.join)((0, import_node_path9.dirname)(targetPath), `.${(0, import_node_path9.basename)(targetPath)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
10539
+ return (0, import_node_path11.join)((0, import_node_path11.dirname)(targetPath), `.${(0, import_node_path11.basename)(targetPath)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
10180
10540
  }
10181
10541
  async function executePackageScriptJob(job, scriptName, options) {
10182
10542
  const packageJson = await readPackageJson(options.workspaceRoot);
@@ -10350,7 +10710,7 @@ function proofItemForJob(job, kind, label, summary, evidence, redactionSecrets =
10350
10710
  }
10351
10711
  async function readPackageJson(workspaceRoot) {
10352
10712
  try {
10353
- const raw = await (0, import_promises6.readFile)((0, import_node_path9.join)(workspaceRoot, "package.json"), "utf-8");
10713
+ const raw = await (0, import_promises8.readFile)((0, import_node_path11.join)(workspaceRoot, "package.json"), "utf-8");
10354
10714
  const parsed = JSON.parse(raw);
10355
10715
  if (isRecord6(parsed) && isRecord6(parsed.scripts)) {
10356
10716
  return { scripts: Object.fromEntries(Object.entries(parsed.scripts).filter(([, value]) => typeof value === "string")) };
@@ -10433,7 +10793,7 @@ async function collectLocalRepoMetadata(workspaceRoot, commandRunner = runComman
10433
10793
  const headSha = headResult.ok ? normalizeSha(headResult.stdout) : null;
10434
10794
  const dirty = statusResult.ok ? statusResult.stdout.trim().length > 0 : void 0;
10435
10795
  return {
10436
- rootName: (0, import_node_path9.basename)(workspaceRoot) || "workspace",
10796
+ rootName: (0, import_node_path11.basename)(workspaceRoot) || "workspace",
10437
10797
  remotes: remoteResult.ok ? parseGitRemotes(remoteResult.stdout) : [],
10438
10798
  branch,
10439
10799
  headSha,
@@ -10451,7 +10811,7 @@ async function detectPackageManager(workspaceRoot) {
10451
10811
  ];
10452
10812
  for (const [manager, file] of checks) {
10453
10813
  try {
10454
- await (0, import_promises6.access)((0, import_node_path9.join)(workspaceRoot, file));
10814
+ await (0, import_promises8.access)((0, import_node_path11.join)(workspaceRoot, file));
10455
10815
  return manager;
10456
10816
  } catch {
10457
10817
  }
@@ -10642,9 +11002,9 @@ function isRecord6(value) {
10642
11002
  }
10643
11003
 
10644
11004
  // src/tui/runInteractive.ts
10645
- var import_node_path14 = require("node:path");
11005
+ var import_node_path16 = require("node:path");
10646
11006
 
10647
- // ../../node_modules/@clack/core/dist/index.mjs
11007
+ // ../../../../node_modules/@clack/core/dist/index.mjs
10648
11008
  var import_sisteransi = __toESM(require_src(), 1);
10649
11009
  var import_node_process = require("node:process");
10650
11010
  var g = __toESM(require("node:readline"), 1);
@@ -11002,7 +11362,7 @@ var LD = class extends x {
11002
11362
  }
11003
11363
  };
11004
11364
 
11005
- // ../../node_modules/@clack/prompts/dist/index.mjs
11365
+ // ../../../../node_modules/@clack/prompts/dist/index.mjs
11006
11366
  var import_node_process2 = __toESM(require("node:process"), 1);
11007
11367
  var import_picocolors2 = __toESM(require_picocolors(), 1);
11008
11368
  var import_sisteransi2 = __toESM(require_src(), 1);
@@ -11229,7 +11589,7 @@ function buildAgentFixPrompt(artifact, gap) {
11229
11589
  }
11230
11590
 
11231
11591
  // src/version.ts
11232
- var VERSION = "1.1.6";
11592
+ var VERSION = "1.1.7";
11233
11593
 
11234
11594
  // src/commands/guide.ts
11235
11595
  var import_picocolors3 = __toESM(require_picocolors());
@@ -11298,8 +11658,8 @@ async function runGuideCommand(options) {
11298
11658
  }
11299
11659
 
11300
11660
  // src/commands/audit.ts
11301
- var import_promises7 = require("node:fs/promises");
11302
- var import_node_path10 = require("node:path");
11661
+ var import_promises9 = require("node:fs/promises");
11662
+ var import_node_path12 = require("node:path");
11303
11663
  var ENV_FILES = [
11304
11664
  ".env",
11305
11665
  ".env.local",
@@ -11390,7 +11750,7 @@ function buildVercelSupabaseAudit(input) {
11390
11750
  buildPoolerCheck(input.files),
11391
11751
  buildServiceRoleCheck(input.files)
11392
11752
  ];
11393
- const status = checks.every((check2) => check2.status === "pass") ? "pass" : "needs_work";
11753
+ const status = checks.every((check) => check.status === "pass") ? "pass" : "needs_work";
11394
11754
  return {
11395
11755
  status,
11396
11756
  summary: status === "pass" ? "Repo evidence passes the local Vercel/Supabase audit checks." : "Repo evidence needs work before claiming Vercel/Supabase production readiness.",
@@ -11399,23 +11759,23 @@ function buildVercelSupabaseAudit(input) {
11399
11759
  }
11400
11760
  async function readIfExists(projectRoot, relativePath) {
11401
11761
  try {
11402
- const absolutePath = (0, import_node_path10.join)(projectRoot, relativePath);
11403
- const fileStat = await (0, import_promises7.stat)(absolutePath);
11762
+ const absolutePath = (0, import_node_path12.join)(projectRoot, relativePath);
11763
+ const fileStat = await (0, import_promises9.stat)(absolutePath);
11404
11764
  if (!fileStat.isFile()) {
11405
11765
  return void 0;
11406
11766
  }
11407
11767
  return {
11408
11768
  path: relativePath,
11409
- content: await (0, import_promises7.readFile)(absolutePath, "utf8")
11769
+ content: await (0, import_promises9.readFile)(absolutePath, "utf8")
11410
11770
  };
11411
11771
  } catch {
11412
11772
  return void 0;
11413
11773
  }
11414
11774
  }
11415
11775
  async function collectSqlFiles(projectRoot, root) {
11416
- const base = (0, import_node_path10.join)(projectRoot, root);
11776
+ const base = (0, import_node_path12.join)(projectRoot, root);
11417
11777
  try {
11418
- const rootStat = await (0, import_promises7.stat)(base);
11778
+ const rootStat = await (0, import_promises9.stat)(base);
11419
11779
  if (!rootStat.isDirectory()) {
11420
11780
  return [];
11421
11781
  }
@@ -11426,25 +11786,25 @@ async function collectSqlFiles(projectRoot, root) {
11426
11786
  async function visit(dir) {
11427
11787
  let entries;
11428
11788
  try {
11429
- entries = await (0, import_promises7.readdir)(dir, { withFileTypes: true });
11789
+ entries = await (0, import_promises9.readdir)(dir, { withFileTypes: true });
11430
11790
  } catch {
11431
11791
  return;
11432
11792
  }
11433
11793
  for (const entry of entries) {
11434
11794
  if (entry.isDirectory()) {
11435
11795
  if (!SKIP_DIRS.has(entry.name)) {
11436
- await visit((0, import_node_path10.join)(dir, entry.name));
11796
+ await visit((0, import_node_path12.join)(dir, entry.name));
11437
11797
  }
11438
11798
  continue;
11439
11799
  }
11440
11800
  if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".sql")) {
11441
11801
  continue;
11442
11802
  }
11443
- const absolutePath = (0, import_node_path10.join)(dir, entry.name);
11803
+ const absolutePath = (0, import_node_path12.join)(dir, entry.name);
11444
11804
  try {
11445
11805
  files.push({
11446
- path: (0, import_node_path10.relative)(projectRoot, absolutePath).replace(/\\/g, "/"),
11447
- content: await (0, import_promises7.readFile)(absolutePath, "utf8")
11806
+ path: (0, import_node_path12.relative)(projectRoot, absolutePath).replace(/\\/g, "/"),
11807
+ content: await (0, import_promises9.readFile)(absolutePath, "utf8")
11448
11808
  });
11449
11809
  } catch {
11450
11810
  }
@@ -11477,13 +11837,13 @@ function renderVercelSupabaseAudit(result) {
11477
11837
  "Boundary: this audit uses local repo evidence only. Provider dashboard settings still need manual verification or read-only provider MCP confirmation.",
11478
11838
  ""
11479
11839
  ];
11480
- for (const check2 of result.checks) {
11481
- lines.push(`${check2.status === "pass" ? "PASS" : "NEEDS_WORK"} ${check2.id}`);
11482
- lines.push(` ${check2.summary}`);
11483
- for (const evidence of check2.evidence.slice(0, 5)) {
11840
+ for (const check of result.checks) {
11841
+ lines.push(`${check.status === "pass" ? "PASS" : "NEEDS_WORK"} ${check.id}`);
11842
+ lines.push(` ${check.summary}`);
11843
+ for (const evidence of check.evidence.slice(0, 5)) {
11484
11844
  lines.push(` - ${evidence}`);
11485
11845
  }
11486
- if (check2.evidence.length === 0) {
11846
+ if (check.evidence.length === 0) {
11487
11847
  lines.push(" - No local evidence found.");
11488
11848
  }
11489
11849
  lines.push("");
@@ -11492,8 +11852,8 @@ function renderVercelSupabaseAudit(result) {
11492
11852
  }
11493
11853
 
11494
11854
  // src/commands/initRules.ts
11495
- var import_promises10 = require("node:fs/promises");
11496
- var import_node_path13 = require("node:path");
11855
+ var import_promises12 = require("node:fs/promises");
11856
+ var import_node_path15 = require("node:path");
11497
11857
 
11498
11858
  // src/commands/agentRulesBlock.ts
11499
11859
  var VIBERAVEN_BLOCK_START = "<!-- VIBERAVEN:START -->";
@@ -11515,15 +11875,6 @@ Maps repo evidence to OWASP LLM Top 10 launch risks. Supports SAFECode-style dep
11515
11875
  var STACK_FRAMING = `Stack context for this repo: Next.js, Supabase, Vercel, VibeRaven.
11516
11876
  Do NOT deploy to Vercel or ship to production users without running \`${PUBLIC_AGENT_MODE_COMMAND}\`.
11517
11877
  Do NOT rely on manual production checklists when VibeRaven gate artifacts exist in \`.viberaven/\`.`;
11518
- var PRODUCTION_PROTOCOL = `## VibeRaven Production Protocol
11519
-
11520
- Before making deploy, auth, database, payment, API, or scaling changes:
11521
-
11522
- 1. Read \`.viberaven/prp.json\`.
11523
- 2. Follow \`.viberaven/mission-map.md\`.
11524
- 3. Do not deploy if \`decision.status\` is \`blocked\`.
11525
- 4. Fix \`nextActions\` in order.
11526
- 5. Re-run \`${PUBLIC_AGENT_MODE_COMMAND}\`.`;
11527
11878
  var AGENT_NEGATIVE_CONSTRAINTS = `## Event-Triggered Production Verification
11528
11879
 
11529
11880
  Trigger: modifications to \`package.json\`, \`vercel.json\`, \`supabase/migrations/**/*\`, \`.env.example\`, auth/billing/webhook paths, or deploy workflow files.
@@ -11549,8 +11900,6 @@ var AGENT_RULES_BODY = `${AGENT_RULES_PREAMBLE}
11549
11900
 
11550
11901
  ${STACK_FRAMING}
11551
11902
 
11552
- ${PRODUCTION_PROTOCOL}
11553
-
11554
11903
  ${AGENT_NEGATIVE_CONSTRAINTS}
11555
11904
 
11556
11905
  ## VibeRaven Production-Readiness Gate
@@ -11600,11 +11949,10 @@ var AGENT_CONTEXT_BODY = `${AGENT_RULES_PREAMBLE}
11600
11949
 
11601
11950
  After \`--agent-mode\`, read these artifacts in order:
11602
11951
 
11603
- 1. \`.viberaven/prp.json\`
11604
- 2. \`.viberaven/mission-map.md\`
11605
- 3. \`.viberaven/agent-tasklist.md\`
11606
- 4. \`.viberaven/gate-result.json\`
11607
- 5. \`.viberaven/context-map.json\``;
11952
+ 1. \`.viberaven/mission-map.md\`
11953
+ 2. \`.viberaven/agent-tasklist.md\`
11954
+ 3. \`.viberaven/gate-result.json\`
11955
+ 4. \`.viberaven/context-map.json\``;
11608
11956
  var MISSION_MAP_BODY = `${AGENT_RULES_PREAMBLE}
11609
11957
 
11610
11958
  ## Mission Map loop
@@ -11742,8 +12090,8 @@ function escapeRegExp3(value) {
11742
12090
  }
11743
12091
 
11744
12092
  // src/commands/cursorRulesPack.ts
11745
- var import_promises8 = require("node:fs/promises");
11746
- var import_node_path11 = require("node:path");
12093
+ var import_promises10 = require("node:fs/promises");
12094
+ var import_node_path13 = require("node:path");
11747
12095
  var CURSOR_RULES_DIR = ".cursor/rules";
11748
12096
  var LEGACY_CURSOR_RULE_FILE = `${CURSOR_RULES_DIR}/viberaven.mdc`;
11749
12097
  var DOMAIN_PATH_POINTER = "Before editing these files, read `.viberaven/agent-context.md` and `.viberaven/mission-map.md`.";
@@ -11827,25 +12175,25 @@ async function initCursorRulesPack(options) {
11827
12175
  const pack = buildCursorRulesPack();
11828
12176
  for (const rule of pack) {
11829
12177
  const file = `${CURSOR_RULES_DIR}/${rule.filename}`;
11830
- const path = (0, import_node_path11.join)(options.cwd, file);
12178
+ const path = (0, import_node_path13.join)(options.cwd, file);
11831
12179
  const existing = await readExistingFile(path);
11832
12180
  const changed = !existing.exists || existing.content !== rule.content;
11833
12181
  const action = !existing.exists ? "created" : changed ? "updated" : "unchanged";
11834
12182
  if (!options.dryRun && changed) {
11835
- await (0, import_promises8.mkdir)((0, import_node_path11.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
11836
- await (0, import_promises8.writeFile)(path, rule.content, "utf-8");
12183
+ await (0, import_promises10.mkdir)((0, import_node_path13.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
12184
+ await (0, import_promises10.writeFile)(path, rule.content, "utf-8");
11837
12185
  }
11838
12186
  results.push({ target: "cursor", file, path, action });
11839
12187
  }
11840
- const legacyPath = (0, import_node_path11.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
12188
+ const legacyPath = (0, import_node_path13.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
11841
12189
  if (!options.dryRun && await fileExists(legacyPath)) {
11842
- await (0, import_promises8.rm)(legacyPath, { force: true });
12190
+ await (0, import_promises10.rm)(legacyPath, { force: true });
11843
12191
  }
11844
12192
  return results;
11845
12193
  }
11846
12194
  async function readExistingFile(path) {
11847
12195
  try {
11848
- return { exists: true, content: await (0, import_promises8.readFile)(path, "utf-8") };
12196
+ return { exists: true, content: await (0, import_promises10.readFile)(path, "utf-8") };
11849
12197
  } catch (error) {
11850
12198
  if (isFileNotFoundError(error)) {
11851
12199
  return { exists: false, content: "" };
@@ -11855,7 +12203,7 @@ async function readExistingFile(path) {
11855
12203
  }
11856
12204
  async function fileExists(path) {
11857
12205
  try {
11858
- await (0, import_promises8.access)(path);
12206
+ await (0, import_promises10.access)(path);
11859
12207
  return true;
11860
12208
  } catch {
11861
12209
  return false;
@@ -11949,19 +12297,19 @@ function getAgentRulesTargets(value) {
11949
12297
 
11950
12298
  // src/commands/seedPackageJsonScripts.ts
11951
12299
  var import_node_fs7 = require("node:fs");
11952
- var import_promises9 = require("node:fs/promises");
11953
- var import_node_path12 = require("node:path");
12300
+ var import_promises11 = require("node:fs/promises");
12301
+ var import_node_path14 = require("node:path");
11954
12302
  var VIBERAVEN_PACKAGE_JSON_SCRIPTS = {
11955
12303
  "viberaven:gate": PUBLIC_AGENT_MODE_COMMAND,
11956
12304
  "viberaven:verify": PUBLIC_VERIFY_COMMAND,
11957
12305
  "viberaven:strict": PUBLIC_STRICT_COMMAND
11958
12306
  };
11959
12307
  async function seedPackageJsonScripts(options) {
11960
- const packageJsonPath = (0, import_node_path12.join)(options.cwd, "package.json");
12308
+ const packageJsonPath = (0, import_node_path14.join)(options.cwd, "package.json");
11961
12309
  if (!(0, import_node_fs7.existsSync)(packageJsonPath)) {
11962
12310
  return null;
11963
12311
  }
11964
- const raw = await (0, import_promises9.readFile)(packageJsonPath, "utf-8");
12312
+ const raw = await (0, import_promises11.readFile)(packageJsonPath, "utf-8");
11965
12313
  let pkg;
11966
12314
  try {
11967
12315
  pkg = JSON.parse(raw);
@@ -11991,7 +12339,7 @@ async function seedPackageJsonScripts(options) {
11991
12339
  pkg.scripts = scripts;
11992
12340
  const output = `${JSON.stringify(pkg, null, 2)}
11993
12341
  `;
11994
- await (0, import_promises9.writeFile)(packageJsonPath, output, "utf-8");
12342
+ await (0, import_promises11.writeFile)(packageJsonPath, output, "utf-8");
11995
12343
  }
11996
12344
  return { action: "updated", added, skipped, changed: true };
11997
12345
  }
@@ -12006,13 +12354,13 @@ async function initAgentRules(options) {
12006
12354
  continue;
12007
12355
  }
12008
12356
  const file = AGENT_RULE_TARGETS[target].file;
12009
- const path = (0, import_node_path13.join)(options.cwd, file);
12357
+ const path = (0, import_node_path15.join)(options.cwd, file);
12010
12358
  const existing = await readExistingFile2(path);
12011
12359
  const injected = injectAgentRulesBlock(existing.content, renderAgentRulesForTarget(target));
12012
12360
  const action = !existing.exists ? "created" : injected.changed ? "updated" : "unchanged";
12013
12361
  if (!options.dryRun && injected.changed) {
12014
- await (0, import_promises10.mkdir)((0, import_node_path13.dirname)(path), { recursive: true });
12015
- await (0, import_promises10.writeFile)(path, injected.content, "utf-8");
12362
+ await (0, import_promises12.mkdir)((0, import_node_path15.dirname)(path), { recursive: true });
12363
+ await (0, import_promises12.writeFile)(path, injected.content, "utf-8");
12016
12364
  }
12017
12365
  results.push({ target, file, path, action });
12018
12366
  }
@@ -12080,7 +12428,7 @@ function formatAgentRulesInitSummary(output) {
12080
12428
  }
12081
12429
  async function readExistingFile2(path) {
12082
12430
  try {
12083
- return { exists: true, content: await (0, import_promises10.readFile)(path, "utf-8") };
12431
+ return { exists: true, content: await (0, import_promises12.readFile)(path, "utf-8") };
12084
12432
  } catch (error) {
12085
12433
  if (isFileNotFoundError2(error)) {
12086
12434
  return { exists: false, content: "" };
@@ -12388,7 +12736,7 @@ async function runInteractiveSession(startDir = process.cwd()) {
12388
12736
  Ie(`${import_picocolors4.default.bold("VibeRaven")} ${import_picocolors4.default.dim(VERSION)}`);
12389
12737
  const cwd = await resolveWorkspaceRoot(startDir);
12390
12738
  const artifactsAt = await findArtifactsWorkspace(startDir);
12391
- if (artifactsAt && (0, import_node_path14.resolve)(artifactsAt) !== (0, import_node_path14.resolve)(startDir)) {
12739
+ if (artifactsAt && (0, import_node_path16.resolve)(artifactsAt) !== (0, import_node_path16.resolve)(startDir)) {
12392
12740
  M2.message(import_picocolors4.default.dim(`Using scan from: ${artifactsAt}`));
12393
12741
  } else {
12394
12742
  M2.message(import_picocolors4.default.dim(`Project folder: ${cwd}`));
@@ -12455,29 +12803,29 @@ async function runInteractiveSession(startDir = process.cwd()) {
12455
12803
  }
12456
12804
 
12457
12805
  // src/commands/condense.ts
12458
- var import_promises11 = require("node:fs/promises");
12459
- var import_node_path15 = require("node:path");
12806
+ var import_promises13 = require("node:fs/promises");
12807
+ var import_node_path17 = require("node:path");
12460
12808
  async function runCondenseCommand(options) {
12461
12809
  const dir = getProjectArtifactsDir(options.cwd);
12462
- const artifact = JSON.parse(await (0, import_promises11.readFile)((0, import_node_path15.join)(dir, "last-scan.json"), "utf8"));
12463
- const contextMapPath = (0, import_node_path15.join)(dir, "context-map.json");
12464
- await (0, import_promises11.writeFile)(contextMapPath, `${JSON.stringify(generateContextMap(artifact), null, 2)}
12810
+ const artifact = JSON.parse(await (0, import_promises13.readFile)((0, import_node_path17.join)(dir, "last-scan.json"), "utf8"));
12811
+ const contextMapPath = (0, import_node_path17.join)(dir, "context-map.json");
12812
+ await (0, import_promises13.writeFile)(contextMapPath, `${JSON.stringify(generateContextMap(artifact), null, 2)}
12465
12813
  `, "utf8");
12466
12814
  return { contextMapPath };
12467
12815
  }
12468
12816
 
12469
12817
  // src/heal/apply.ts
12470
- var import_promises13 = require("node:fs/promises");
12818
+ var import_promises15 = require("node:fs/promises");
12471
12819
  var import_node_fs10 = require("node:fs");
12472
- var import_node_path19 = require("node:path");
12820
+ var import_node_path21 = require("node:path");
12473
12821
 
12474
12822
  // src/heal/pathSafety.ts
12475
- var import_node_path16 = require("node:path");
12823
+ var import_node_path18 = require("node:path");
12476
12824
  var BLOCKED_SEGMENTS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", ".viberaven"]);
12477
12825
  function assertSafeHealTarget(cwd, target) {
12478
- const root = (0, import_node_path16.resolve)(cwd);
12479
- const absolute = (0, import_node_path16.resolve)(root, target);
12480
- const rel = (0, import_node_path16.relative)(root, absolute);
12826
+ const root = (0, import_node_path18.resolve)(cwd);
12827
+ const absolute = (0, import_node_path18.resolve)(root, target);
12828
+ const rel = (0, import_node_path18.relative)(root, absolute);
12481
12829
  if (rel.startsWith("..") || rel === "" || /^[A-Za-z]:/.test(rel)) {
12482
12830
  throw new Error("Heal target must stay inside the workspace");
12483
12831
  }
@@ -12501,8 +12849,8 @@ function applyEmptyCatchRecipe(source) {
12501
12849
 
12502
12850
  // src/heal/recipes/index.ts
12503
12851
  var import_node_fs9 = require("node:fs");
12504
- var import_promises12 = require("node:fs/promises");
12505
- var import_node_path18 = require("node:path");
12852
+ var import_promises14 = require("node:fs/promises");
12853
+ var import_node_path20 = require("node:path");
12506
12854
 
12507
12855
  // src/heal/recipes/envAuthSecret.ts
12508
12856
  function applyAuthSecretRecipe(source) {
@@ -12884,7 +13232,7 @@ function applyRateLimitRecipe(source, hasUpstash) {
12884
13232
 
12885
13233
  // src/heal/recipes/eslintRestrictedImports.ts
12886
13234
  var import_node_fs8 = require("node:fs");
12887
- var import_node_path17 = require("node:path");
13235
+ var import_node_path19 = require("node:path");
12888
13236
  var VIBERAVEN_ESLINT_MARKER = "VibeRaven heal: eslint_restricted_imports";
12889
13237
  var RESTRICTED_IMPORTS_MESSAGE = `Restricted import. Run ${PUBLIC_AGENT_MODE_COMMAND} before substituting packages.`;
12890
13238
  var RESTRICTED_PATHS = [
@@ -12914,7 +13262,7 @@ var ESLINT_CONFIG_CANDIDATES = [
12914
13262
  ];
12915
13263
  function detectEslintConfigFile(cwd) {
12916
13264
  for (const candidate of ESLINT_CONFIG_CANDIDATES) {
12917
- if ((0, import_node_fs8.existsSync)((0, import_node_path17.join)(cwd, candidate))) {
13265
+ if ((0, import_node_fs8.existsSync)((0, import_node_path19.join)(cwd, candidate))) {
12918
13266
  return candidate;
12919
13267
  }
12920
13268
  }
@@ -13090,13 +13438,13 @@ function defaultTargetFile(gapId) {
13090
13438
  }
13091
13439
  async function readSourceOrEmpty(absolutePath) {
13092
13440
  if (!(0, import_node_fs9.existsSync)(absolutePath)) return "";
13093
- return (0, import_promises12.readFile)(absolutePath, "utf8");
13441
+ return (0, import_promises14.readFile)(absolutePath, "utf8");
13094
13442
  }
13095
13443
  async function detectUpstash(cwd) {
13096
13444
  try {
13097
- const pkgPath = (0, import_node_path18.join)(cwd, "package.json");
13445
+ const pkgPath = (0, import_node_path20.join)(cwd, "package.json");
13098
13446
  if (!(0, import_node_fs9.existsSync)(pkgPath)) return false;
13099
- const raw = await (0, import_promises12.readFile)(pkgPath, "utf8");
13447
+ const raw = await (0, import_promises14.readFile)(pkgPath, "utf8");
13100
13448
  const pkg = JSON.parse(raw);
13101
13449
  const deps = {
13102
13450
  ...pkg["dependencies"] ?? {},
@@ -13111,7 +13459,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13111
13459
  const targetFile = explicitTarget ?? defaultTargetFile(gapId);
13112
13460
  if (targetFile === void 0) return null;
13113
13461
  if (gapId === "auth_secret_missing" || gapId === "node_env_not_set" || gapId === "database_url_missing") {
13114
- const absolutePath = (0, import_node_path18.join)(cwd, targetFile);
13462
+ const absolutePath = (0, import_node_path20.join)(cwd, targetFile);
13115
13463
  const source = await readSourceOrEmpty(absolutePath);
13116
13464
  let result;
13117
13465
  if (gapId === "auth_secret_missing") result = applyAuthSecretRecipe(source);
@@ -13125,25 +13473,25 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13125
13473
  };
13126
13474
  }
13127
13475
  if (gapId === "missing_error_boundary") {
13128
- const absolutePath = (0, import_node_path18.join)(cwd, "app/error.tsx");
13476
+ const absolutePath = (0, import_node_path20.join)(cwd, "app/error.tsx");
13129
13477
  const source = await readSourceOrEmpty(absolutePath);
13130
13478
  const result = applyErrorBoundaryRecipe(source);
13131
13479
  return { ...result, canAutoApply: true, recipeName: gapId };
13132
13480
  }
13133
13481
  if (gapId === "missing_health_route") {
13134
- const absolutePath = (0, import_node_path18.join)(cwd, "app/api/health/route.ts");
13482
+ const absolutePath = (0, import_node_path20.join)(cwd, "app/api/health/route.ts");
13135
13483
  const source = await readSourceOrEmpty(absolutePath);
13136
13484
  const result = applyHealthRouteRecipe(source);
13137
13485
  return { ...result, canAutoApply: true, recipeName: gapId };
13138
13486
  }
13139
13487
  if (gapId === "missing_loading_state") {
13140
- const absolutePath = (0, import_node_path18.join)(cwd, "app/loading.tsx");
13488
+ const absolutePath = (0, import_node_path20.join)(cwd, "app/loading.tsx");
13141
13489
  const source = await readSourceOrEmpty(absolutePath);
13142
13490
  const result = applyLoadingStateRecipe(source);
13143
13491
  return { ...result, canAutoApply: true, recipeName: gapId };
13144
13492
  }
13145
13493
  if (gapId === "missing_404_page") {
13146
- const absolutePath = (0, import_node_path18.join)(cwd, "app/not-found.tsx");
13494
+ const absolutePath = (0, import_node_path20.join)(cwd, "app/not-found.tsx");
13147
13495
  const source = await readSourceOrEmpty(absolutePath);
13148
13496
  const result = applyNotFoundRecipe(source);
13149
13497
  return { ...result, canAutoApply: true, recipeName: gapId };
@@ -13161,10 +13509,10 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13161
13509
  }
13162
13510
  if (gapId === "missing_csp_header") {
13163
13511
  let configFile = "next.config.js";
13164
- let absolutePath = (0, import_node_path18.join)(cwd, configFile);
13512
+ let absolutePath = (0, import_node_path20.join)(cwd, configFile);
13165
13513
  if (!(0, import_node_fs9.existsSync)(absolutePath)) {
13166
13514
  configFile = "next.config.mjs";
13167
- absolutePath = (0, import_node_path18.join)(cwd, configFile);
13515
+ absolutePath = (0, import_node_path20.join)(cwd, configFile);
13168
13516
  }
13169
13517
  const source = await readSourceOrEmpty(absolutePath);
13170
13518
  const result = applyCspHeaderRecipe(source);
@@ -13176,7 +13524,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13176
13524
  }
13177
13525
  if (gapId === "missing_rate_limit") {
13178
13526
  const hasUpstash = await detectUpstash(cwd);
13179
- const middlewarePath = (0, import_node_path18.join)(cwd, "middleware.ts");
13527
+ const middlewarePath = (0, import_node_path20.join)(cwd, "middleware.ts");
13180
13528
  const source = await readSourceOrEmpty(middlewarePath);
13181
13529
  const result = applyRateLimitRecipe(source, hasUpstash);
13182
13530
  return {
@@ -13198,7 +13546,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13198
13546
  recipeName: gapId
13199
13547
  };
13200
13548
  }
13201
- const absolutePath = (0, import_node_path18.join)(cwd, configFile);
13549
+ const absolutePath = (0, import_node_path20.join)(cwd, configFile);
13202
13550
  const source = await readSourceOrEmpty(absolutePath);
13203
13551
  const result = applyEslintRestrictedImportsRecipe(source, configFile);
13204
13552
  return {
@@ -13273,14 +13621,14 @@ async function applyHeal(options) {
13273
13621
  rollback: { available: false, instructions: "Recipe matched but no change was needed (already applied or file already exists)." }
13274
13622
  };
13275
13623
  }
13276
- const absoluteTarget = (0, import_node_path19.join)(options.cwd, dispatched.targetFile);
13624
+ const absoluteTarget = (0, import_node_path21.join)(options.cwd, dispatched.targetFile);
13277
13625
  assertSafeHealTarget(options.cwd, dispatched.targetFile);
13278
- await (0, import_promises13.mkdir)((0, import_node_path19.dirname)(absoluteTarget), { recursive: true });
13279
- const healDir2 = (0, import_node_path19.join)(options.cwd, ".viberaven", "heal", id);
13280
- await (0, import_promises13.mkdir)((0, import_node_path19.join)(healDir2, "before"), { recursive: true });
13281
- const beforeContent = (0, import_node_fs10.existsSync)(absoluteTarget) ? await (0, import_promises13.readFile)(absoluteTarget, "utf8") : "";
13282
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
13283
- await (0, import_promises13.writeFile)(absoluteTarget, dispatched.output, "utf8");
13626
+ await (0, import_promises15.mkdir)((0, import_node_path21.dirname)(absoluteTarget), { recursive: true });
13627
+ const healDir2 = (0, import_node_path21.join)(options.cwd, ".viberaven", "heal", id);
13628
+ await (0, import_promises15.mkdir)((0, import_node_path21.join)(healDir2, "before"), { recursive: true });
13629
+ const beforeContent = (0, import_node_fs10.existsSync)(absoluteTarget) ? await (0, import_promises15.readFile)(absoluteTarget, "utf8") : "";
13630
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
13631
+ await (0, import_promises15.writeFile)(absoluteTarget, dispatched.output, "utf8");
13284
13632
  const patch2 = [
13285
13633
  `--- ${dispatched.targetFile}`,
13286
13634
  `+++ ${dispatched.targetFile}`,
@@ -13290,7 +13638,7 @@ async function applyHeal(options) {
13290
13638
  dispatched.output,
13291
13639
  ""
13292
13640
  ].join("\n");
13293
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "patch.diff"), patch2, "utf8");
13641
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir2, "patch.diff"), patch2, "utf8");
13294
13642
  const result2 = {
13295
13643
  $schema: "https://viberaven.dev/schemas/heal-result.schema.json",
13296
13644
  schemaVersion: "v1",
@@ -13301,7 +13649,7 @@ async function applyHeal(options) {
13301
13649
  gapId: options.gapId,
13302
13650
  recipe: dispatched.recipeName,
13303
13651
  target: dispatched.targetFile,
13304
- changedFiles: [(0, import_node_path19.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
13652
+ changedFiles: [(0, import_node_path21.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
13305
13653
  artifacts: {
13306
13654
  patch: `.viberaven/heal/${id}/patch.diff`,
13307
13655
  result: `.viberaven/heal/${id}/result.json`
@@ -13311,7 +13659,7 @@ async function applyHeal(options) {
13311
13659
  instructions: "Restore .viberaven/heal/<healId>/before/target.txt to the target file or apply the reverse patch."
13312
13660
  }
13313
13661
  };
13314
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "result.json"), `${JSON.stringify(result2, null, 2)}
13662
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir2, "result.json"), `${JSON.stringify(result2, null, 2)}
13315
13663
  `, "utf8");
13316
13664
  return result2;
13317
13665
  }
@@ -13331,7 +13679,7 @@ async function applyHeal(options) {
13331
13679
  };
13332
13680
  }
13333
13681
  const absolute = assertSafeHealTarget(options.cwd, options.target);
13334
- const before = await (0, import_promises13.readFile)(absolute, "utf8");
13682
+ const before = await (0, import_promises15.readFile)(absolute, "utf8");
13335
13683
  const recipe = applyEmptyCatchRecipe(before);
13336
13684
  if (!recipe.changed) {
13337
13685
  return {
@@ -13348,10 +13696,10 @@ async function applyHeal(options) {
13348
13696
  rollback: { available: false, instructions: "No supported heal recipe matched this file." }
13349
13697
  };
13350
13698
  }
13351
- const healDir = (0, import_node_path19.join)(options.cwd, ".viberaven", "heal", id);
13352
- await (0, import_promises13.mkdir)((0, import_node_path19.join)(healDir, "before"), { recursive: true });
13353
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "before", "target.txt"), before, "utf8");
13354
- await (0, import_promises13.writeFile)(absolute, recipe.output, "utf8");
13699
+ const healDir = (0, import_node_path21.join)(options.cwd, ".viberaven", "heal", id);
13700
+ await (0, import_promises15.mkdir)((0, import_node_path21.join)(healDir, "before"), { recursive: true });
13701
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir, "before", "target.txt"), before, "utf8");
13702
+ await (0, import_promises15.writeFile)(absolute, recipe.output, "utf8");
13355
13703
  const patch = [
13356
13704
  `--- ${options.target}`,
13357
13705
  `+++ ${options.target}`,
@@ -13361,7 +13709,7 @@ async function applyHeal(options) {
13361
13709
  recipe.output,
13362
13710
  ""
13363
13711
  ].join("\n");
13364
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "patch.diff"), patch, "utf8");
13712
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir, "patch.diff"), patch, "utf8");
13365
13713
  const result = {
13366
13714
  $schema: "https://viberaven.dev/schemas/heal-result.schema.json",
13367
13715
  schemaVersion: "v1",
@@ -13372,7 +13720,7 @@ async function applyHeal(options) {
13372
13720
  gapId: options.gapId,
13373
13721
  recipe: "empty-catch-safe-response",
13374
13722
  target: options.target,
13375
- changedFiles: [(0, import_node_path19.relative)(options.cwd, absolute).replace(/\\/g, "/")],
13723
+ changedFiles: [(0, import_node_path21.relative)(options.cwd, absolute).replace(/\\/g, "/")],
13376
13724
  artifacts: {
13377
13725
  patch: `.viberaven/heal/${id}/patch.diff`,
13378
13726
  result: `.viberaven/heal/${id}/result.json`
@@ -13382,20 +13730,20 @@ async function applyHeal(options) {
13382
13730
  instructions: "Restore .viberaven/heal/<healId>/before/target.txt to the target file or apply the reverse patch."
13383
13731
  }
13384
13732
  };
13385
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "result.json"), `${JSON.stringify(result, null, 2)}
13733
+ await (0, import_promises15.writeFile)((0, import_node_path21.join)(healDir, "result.json"), `${JSON.stringify(result, null, 2)}
13386
13734
  `, "utf8");
13387
13735
  return result;
13388
13736
  }
13389
13737
 
13390
13738
  // src/heal/plan.ts
13391
- var import_promises14 = require("node:fs/promises");
13392
- var import_node_path20 = require("node:path");
13739
+ var import_promises16 = require("node:fs/promises");
13740
+ var import_node_path22 = require("node:path");
13393
13741
  function healId2() {
13394
13742
  return `heal_${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 14)}`;
13395
13743
  }
13396
13744
  async function writeHealPlan(options) {
13397
- const dir = (0, import_node_path20.join)(options.cwd, ".viberaven");
13398
- await (0, import_promises14.mkdir)(dir, { recursive: true });
13745
+ const dir = (0, import_node_path22.join)(options.cwd, ".viberaven");
13746
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
13399
13747
  const id = healId2();
13400
13748
  const target = options.target ?? `gap:${options.gapId}`;
13401
13749
  const markdown = [
@@ -13422,21 +13770,21 @@ async function writeHealPlan(options) {
13422
13770
  artifacts: { plan: ".viberaven/heal-plan.md" },
13423
13771
  rollback: { available: false, instructions: "No source files were changed." }
13424
13772
  };
13425
- await (0, import_promises14.writeFile)((0, import_node_path20.join)(dir, "heal-plan.md"), markdown, "utf8");
13426
- await (0, import_promises14.writeFile)((0, import_node_path20.join)(dir, "heal-plan.json"), `${JSON.stringify(result, null, 2)}
13773
+ await (0, import_promises16.writeFile)((0, import_node_path22.join)(dir, "heal-plan.md"), markdown, "utf8");
13774
+ await (0, import_promises16.writeFile)((0, import_node_path22.join)(dir, "heal-plan.json"), `${JSON.stringify(result, null, 2)}
13427
13775
  `, "utf8");
13428
13776
  return result;
13429
13777
  }
13430
13778
 
13431
13779
  // src/heal/prompt.ts
13432
- var import_promises15 = require("node:fs/promises");
13433
- var import_node_path21 = require("node:path");
13780
+ var import_promises17 = require("node:fs/promises");
13781
+ var import_node_path23 = require("node:path");
13434
13782
  function healId3() {
13435
13783
  return `heal_${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 14)}`;
13436
13784
  }
13437
13785
  async function writeHealPrompt(options) {
13438
- const dir = (0, import_node_path21.join)(options.cwd, ".viberaven");
13439
- await (0, import_promises15.mkdir)(dir, { recursive: true });
13786
+ const dir = (0, import_node_path23.join)(options.cwd, ".viberaven");
13787
+ await (0, import_promises17.mkdir)(dir, { recursive: true });
13440
13788
  const id = healId3();
13441
13789
  const target = options.target ?? `gap:${options.gapId}`;
13442
13790
  const prompt = [
@@ -13463,12 +13811,12 @@ async function writeHealPrompt(options) {
13463
13811
  artifacts: { prompt: ".viberaven/heal-prompt.md" },
13464
13812
  rollback: { available: false, instructions: "No source files were changed." }
13465
13813
  };
13466
- await (0, import_promises15.writeFile)((0, import_node_path21.join)(dir, "heal-prompt.md"), prompt, "utf8");
13814
+ await (0, import_promises17.writeFile)((0, import_node_path23.join)(dir, "heal-prompt.md"), prompt, "utf8");
13467
13815
  return result;
13468
13816
  }
13469
13817
 
13470
13818
  // src/loopState.ts
13471
- var import_promises16 = require("fs/promises");
13819
+ var import_promises18 = require("fs/promises");
13472
13820
  var import_path = require("path");
13473
13821
  var DEFAULT_LOOP_STATE = {
13474
13822
  batchApplied: 0,
@@ -13481,7 +13829,7 @@ function loopStatePath(workspaceRoot) {
13481
13829
  }
13482
13830
  async function loadLoopState(workspaceRoot) {
13483
13831
  try {
13484
- const raw = await (0, import_promises16.readFile)(loopStatePath(workspaceRoot), "utf8");
13832
+ const raw = await (0, import_promises18.readFile)(loopStatePath(workspaceRoot), "utf8");
13485
13833
  const parsed = JSON.parse(raw);
13486
13834
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && typeof parsed.batchApplied === "number" && typeof parsed.lastGapCount === "number" && typeof parsed.stalledScans === "number") {
13487
13835
  const p2 = parsed;
@@ -13501,8 +13849,8 @@ async function loadLoopState(workspaceRoot) {
13501
13849
  async function saveLoopState(workspaceRoot, state) {
13502
13850
  try {
13503
13851
  const dir = (0, import_path.join)(workspaceRoot, ".viberaven");
13504
- await (0, import_promises16.mkdir)(dir, { recursive: true });
13505
- await (0, import_promises16.writeFile)(loopStatePath(workspaceRoot), JSON.stringify(state, null, 2) + "\n", "utf8");
13852
+ await (0, import_promises18.mkdir)(dir, { recursive: true });
13853
+ await (0, import_promises18.writeFile)(loopStatePath(workspaceRoot), JSON.stringify(state, null, 2) + "\n", "utf8");
13506
13854
  } catch (err) {
13507
13855
  console.warn("[VibeRaven] Could not save loop-state.json:", err instanceof Error ? err.message : String(err));
13508
13856
  }
@@ -13548,9 +13896,9 @@ async function runHealCommand(options) {
13548
13896
  }
13549
13897
 
13550
13898
  // src/stackRecommend.ts
13551
- var import_promises17 = require("node:fs/promises");
13899
+ var import_promises19 = require("node:fs/promises");
13552
13900
  var import_node_fs11 = require("node:fs");
13553
- var import_node_path22 = require("node:path");
13901
+ var import_node_path24 = require("node:path");
13554
13902
  var DEFAULT_STACK = {
13555
13903
  frontend: "react",
13556
13904
  ui: "tailwind + shadcn/ui",
@@ -13561,11 +13909,11 @@ var DEFAULT_STACK = {
13561
13909
  reason: "Agent-default stack for lowest launch friction when repo signals are ambiguous"
13562
13910
  };
13563
13911
  async function recommendStack(cwd = process.cwd()) {
13564
- const pkgPath = (0, import_node_path22.join)(cwd, "package.json");
13912
+ const pkgPath = (0, import_node_path24.join)(cwd, "package.json");
13565
13913
  if (!(0, import_node_fs11.existsSync)(pkgPath)) {
13566
13914
  return DEFAULT_STACK;
13567
13915
  }
13568
- const pkg = JSON.parse(await (0, import_promises17.readFile)(pkgPath, "utf-8"));
13916
+ const pkg = JSON.parse(await (0, import_promises19.readFile)(pkgPath, "utf-8"));
13569
13917
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
13570
13918
  const names = Object.keys(deps).join(" ").toLowerCase();
13571
13919
  const rec = {
@@ -13617,8 +13965,8 @@ async function runInitCommand(options) {
13617
13965
  }
13618
13966
 
13619
13967
  // src/commands/doctorAgents.ts
13620
- var import_promises18 = require("node:fs/promises");
13621
- var import_node_path23 = require("node:path");
13968
+ var import_promises20 = require("node:fs/promises");
13969
+ var import_node_path25 = require("node:path");
13622
13970
  var REQUIRED_EXISTENCE_CHECKS = [
13623
13971
  { id: "agents-md", file: "AGENTS.md" },
13624
13972
  { id: "claude-md", file: "CLAUDE.md" },
@@ -13638,7 +13986,7 @@ var STALE_PATTERNS = [
13638
13986
  async function checkAgentInjection(cwd) {
13639
13987
  const checks = [];
13640
13988
  for (const item3 of REQUIRED_EXISTENCE_CHECKS) {
13641
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13989
+ const exists = await fileExists2((0, import_node_path25.join)(cwd, item3.file));
13642
13990
  checks.push({
13643
13991
  id: item3.id,
13644
13992
  status: exists ? "pass" : "fail",
@@ -13646,17 +13994,17 @@ async function checkAgentInjection(cwd) {
13646
13994
  });
13647
13995
  }
13648
13996
  for (const item3 of OPTIONAL_CURSOR_PACK_CHECKS) {
13649
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13997
+ const exists = await fileExists2((0, import_node_path25.join)(cwd, item3.file));
13650
13998
  checks.push({
13651
13999
  id: item3.id,
13652
14000
  status: exists ? "pass" : "fail",
13653
14001
  message: exists ? `${item3.file} exists` : `Missing ${item3.file} \u2014 run npx -y viberaven init --agents all`
13654
14002
  });
13655
14003
  }
13656
- const legacyCursorPath = (0, import_node_path23.join)(cwd, ".cursor/rules/viberaven.mdc");
14004
+ const legacyCursorPath = (0, import_node_path25.join)(cwd, ".cursor/rules/viberaven.mdc");
13657
14005
  if (await fileExists2(legacyCursorPath)) {
13658
- const legacyContent = await (0, import_promises18.readFile)(legacyCursorPath, "utf-8");
13659
- const hasCoreSplit = await fileExists2((0, import_node_path23.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
14006
+ const legacyContent = await (0, import_promises20.readFile)(legacyCursorPath, "utf-8");
14007
+ const hasCoreSplit = await fileExists2((0, import_node_path25.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
13660
14008
  if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
13661
14009
  checks.push({
13662
14010
  id: "cursor-legacy-mdc",
@@ -13667,7 +14015,7 @@ async function checkAgentInjection(cwd) {
13667
14015
  }
13668
14016
  for (const target of CORE_AGENT_INJECTION_TARGETS) {
13669
14017
  const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
13670
- const path = (0, import_node_path23.join)(cwd, file);
14018
+ const path = (0, import_node_path25.join)(cwd, file);
13671
14019
  const exists = await fileExists2(path);
13672
14020
  if (!exists) {
13673
14021
  checks.push({
@@ -13677,7 +14025,7 @@ async function checkAgentInjection(cwd) {
13677
14025
  });
13678
14026
  continue;
13679
14027
  }
13680
- const content = await (0, import_promises18.readFile)(path, "utf-8");
14028
+ const content = await (0, import_promises20.readFile)(path, "utf-8");
13681
14029
  const hasCommand = content.includes(PUBLIC_AGENT_MODE_COMMAND);
13682
14030
  checks.push({
13683
14031
  id: `canonical-${target}`,
@@ -13695,15 +14043,15 @@ async function checkAgentInjection(cwd) {
13695
14043
  }
13696
14044
  }
13697
14045
  return {
13698
- ok: checks.every((check2) => check2.status === "pass"),
14046
+ ok: checks.every((check) => check.status === "pass"),
13699
14047
  checks
13700
14048
  };
13701
14049
  }
13702
14050
  function formatDoctorAgentsReport(report) {
13703
14051
  const lines = ["VibeRaven agent injection doctor", ""];
13704
- for (const check2 of report.checks) {
13705
- const icon = check2.status === "pass" ? "\u2713" : "\u2717";
13706
- lines.push(`${icon} ${check2.message}`);
14052
+ for (const check of report.checks) {
14053
+ const icon = check.status === "pass" ? "\u2713" : "\u2717";
14054
+ lines.push(`${icon} ${check.message}`);
13707
14055
  }
13708
14056
  lines.push("");
13709
14057
  lines.push(report.ok ? "All agent injection checks passed." : "Agent injection checks failed.");
@@ -13711,7 +14059,7 @@ function formatDoctorAgentsReport(report) {
13711
14059
  }
13712
14060
  async function fileExists2(path) {
13713
14061
  try {
13714
- await (0, import_promises18.access)(path);
14062
+ await (0, import_promises20.access)(path);
13715
14063
  return true;
13716
14064
  } catch {
13717
14065
  return false;
@@ -13924,8 +14272,673 @@ async function runAuditCommand(input) {
13924
14272
  return result.status === "pass" ? 0 : 1;
13925
14273
  }
13926
14274
 
13927
- // src/commands/preview.ts
13928
- var import_picocolors5 = __toESM(require_picocolors());
14275
+ // src/commands/actions.ts
14276
+ var import_promises21 = require("node:fs/promises");
14277
+ var import_node_path26 = require("node:path");
14278
+
14279
+ // src/actions/render.ts
14280
+ function redact(text) {
14281
+ return text.replace(
14282
+ /\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|DATABASE_URL|POSTGRES_URL|SERVICE_ROLE)[A-Z0-9_]*)=([^,\s]+)/gi,
14283
+ "$1=<redacted>"
14284
+ ).replace(/\bpostgres(?:ql)?:\/\/[^@\s]+@/gi, "postgresql://<redacted>@").replace(/[A-Za-z]:\\[^\s`"]+/g, "<repo-relative-path>").replace(/\b\/Users\/[^\s`"]+/g, "<repo-relative-path>").replace(/\b\/home\/[^\s`"]+/g, "<repo-relative-path>").replace(/\beyJ[A-Za-z0-9._-]*\b/g, "<redacted>");
14285
+ }
14286
+ function stringifyPayload(value) {
14287
+ if (Array.isArray(value)) {
14288
+ return value.map((entry) => String(entry)).join("\n");
14289
+ }
14290
+ if (value && typeof value === "object") {
14291
+ return JSON.stringify(value, null, 2);
14292
+ }
14293
+ return String(value ?? "");
14294
+ }
14295
+ function fenceFor(format) {
14296
+ if (format === "bash" || format === "sql" || format === "json") {
14297
+ return format;
14298
+ }
14299
+ return "txt";
14300
+ }
14301
+ function renderTarget(target) {
14302
+ if (!target) {
14303
+ return [];
14304
+ }
14305
+ if (target.type === "url") {
14306
+ return [`Open: ${redact(target.href || target.label)}`];
14307
+ }
14308
+ if (target.type === "file") {
14309
+ return [`File: ${redact(target.path)}`];
14310
+ }
14311
+ if (target.type === "command") {
14312
+ return ["Run:", "```bash", redact(target.command), "```"];
14313
+ }
14314
+ if (target.type === "provider") {
14315
+ return [`Provider: ${redact(target.label)}`];
14316
+ }
14317
+ return ["Verify:", "```bash", redact(target.command), "```"];
14318
+ }
14319
+ function renderReadiness(action) {
14320
+ const readiness = action.readiness?.slice(0, 2).map(redact).filter(Boolean);
14321
+ if (!readiness || readiness.length === 0) {
14322
+ return void 0;
14323
+ }
14324
+ return `Ready: ${readiness.join(", ")}`;
14325
+ }
14326
+ function renderCopyPayload(action) {
14327
+ const payload = action.copyPayloads?.[0];
14328
+ if (!payload) {
14329
+ return [];
14330
+ }
14331
+ const raw = stringifyPayload(payload.value);
14332
+ if (raw.length > 500) {
14333
+ return [];
14334
+ }
14335
+ return [`Copy: ${redact(payload.label)}`, `\`\`\`${fenceFor(payload.format)}`, redact(raw), "```"];
14336
+ }
14337
+ function renderVerifyCommand(action) {
14338
+ if (!action.verifyCommand) {
14339
+ return [];
14340
+ }
14341
+ if (action.target?.type === "verify" && action.target.command === action.verifyCommand) {
14342
+ return [];
14343
+ }
14344
+ return ["Verify:", "```bash", redact(action.verifyCommand), "```"];
14345
+ }
14346
+ function renderAction(action) {
14347
+ return [
14348
+ `[${action.id}] ${redact(action.title)}`,
14349
+ `Status: ${action.status}`,
14350
+ renderReadiness(action),
14351
+ ...renderTarget(action.target),
14352
+ ...renderCopyPayload(action),
14353
+ ...renderVerifyCommand(action),
14354
+ action.resumeInstruction ? `Resume: "${redact(action.resumeInstruction)}"` : void 0
14355
+ ].filter((line) => Boolean(line));
14356
+ }
14357
+ function renderActionSurface(manifest, options = {}) {
14358
+ const visibleActions = typeof options.limit === "number" ? manifest.actions.slice(0, options.limit) : manifest.actions;
14359
+ const lines = [
14360
+ "VibeRaven Production Actions",
14361
+ `Gate: ${manifest.gateStatus}`,
14362
+ `Showing: ${visibleActions.length} of ${manifest.actions.length} current actions`,
14363
+ "Full state: .viberaven/actions.json",
14364
+ ""
14365
+ ];
14366
+ for (const action of visibleActions) {
14367
+ lines.push(...renderAction(action), "");
14368
+ }
14369
+ return `${lines.join("\n").trimEnd()}
14370
+ `;
14371
+ }
14372
+
14373
+ // src/commands/actions.ts
14374
+ async function runActionsCommand(input) {
14375
+ const actionsPath = (0, import_node_path26.join)(getProjectArtifactsDir(input.cwd), "actions.json");
14376
+ let raw;
14377
+ try {
14378
+ raw = await (0, import_promises21.readFile)(actionsPath, "utf8");
14379
+ } catch {
14380
+ process.stderr.write("No VibeRaven actions found. Run `npx -y viberaven --agent-mode` first.\n");
14381
+ return 1;
14382
+ }
14383
+ if (input.json) {
14384
+ process.stdout.write(raw.endsWith("\n") ? raw : `${raw}
14385
+ `);
14386
+ return 0;
14387
+ }
14388
+ const manifest = JSON.parse(raw);
14389
+ process.stdout.write(renderActionSurface(manifest));
14390
+ return 0;
14391
+ }
14392
+
14393
+ // src/commands/verifyAction.ts
14394
+ var import_promises22 = require("node:fs/promises");
14395
+ var import_node_path27 = require("node:path");
14396
+ async function currentActionExists(cwd, actionId) {
14397
+ try {
14398
+ const raw = await (0, import_promises22.readFile)((0, import_node_path27.join)(getProjectArtifactsDir(cwd), "actions.json"), "utf8");
14399
+ const manifest = JSON.parse(raw);
14400
+ return manifest.actions.some((action) => action.id === actionId);
14401
+ } catch {
14402
+ return false;
14403
+ }
14404
+ }
14405
+ async function runVerifyActionCommand(input) {
14406
+ const entry = await resolveActionById(input.cwd, input.actionId);
14407
+ if (!entry) {
14408
+ process.stdout.write(
14409
+ `Action ${input.actionId} is not in the registry. Run \`npx -y viberaven actions\` for current actions.
14410
+ `
14411
+ );
14412
+ return 1;
14413
+ }
14414
+ if (entry.status === "resolved") {
14415
+ process.stdout.write(
14416
+ `Action ${entry.id} (${entry.title ?? "untitled action"}) is already resolved. Run \`npx -y viberaven actions\` for current actions.
14417
+ `
14418
+ );
14419
+ return 0;
14420
+ }
14421
+ if (entry.status === "replaced") {
14422
+ process.stdout.write(
14423
+ `Action ${entry.id} (${entry.title ?? "untitled action"}) was replaced${entry.replacedBy ? ` by ${entry.replacedBy}` : ""}. Run \`npx -y viberaven actions\` for current actions.
14424
+ `
14425
+ );
14426
+ return 1;
14427
+ }
14428
+ if (entry.status === "stale" || !await currentActionExists(input.cwd, input.actionId)) {
14429
+ process.stdout.write(
14430
+ `Action ${entry.id} (${entry.title ?? "untitled action"}) is not in the current action surface. Run \`npx -y viberaven actions\` or rescan with \`npx -y viberaven --agent-mode\`.
14431
+ `
14432
+ );
14433
+ return 1;
14434
+ }
14435
+ process.stdout.write(
14436
+ `Verifying ${entry.id} (${entry.title ?? "untitled action"}).
14437
+ Run \`npx -y viberaven --verify\` to refresh the production gate for this action.
14438
+ `
14439
+ );
14440
+ return 0;
14441
+ }
14442
+
14443
+ // src/console/server.ts
14444
+ var import_node_http = require("node:http");
14445
+ var import_node_fs12 = require("node:fs");
14446
+ var import_promises24 = require("node:fs/promises");
14447
+ var import_node_path29 = require("node:path");
14448
+
14449
+ // src/console/commands.ts
14450
+ var import_node_child_process4 = require("node:child_process");
14451
+ var ACTION_ID_RE = /^VR-A[1-9][0-9]*$/;
14452
+ function isPlainRequestObject(request) {
14453
+ return typeof request === "object" && request !== null && !Array.isArray(request);
14454
+ }
14455
+ function hasOnlyKeys(request, keys) {
14456
+ const actualKeys = Object.keys(request);
14457
+ return actualKeys.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(request, key));
14458
+ }
14459
+ function resolveConsoleCommandArgs(request) {
14460
+ if (!isPlainRequestObject(request) || typeof request.type !== "string") {
14461
+ throw new Error("Unsupported console command.");
14462
+ }
14463
+ if (request.type === "actions-json" && hasOnlyKeys(request, ["type"])) return ["actions", "--json"];
14464
+ if (request.type === "verify-gate" && hasOnlyKeys(request, ["type"])) return ["--verify"];
14465
+ if (request.type === "agent-mode" && hasOnlyKeys(request, ["type"])) return ["--agent-mode"];
14466
+ if (request.type === "verify-action" && hasOnlyKeys(request, ["type", "actionId"])) {
14467
+ if (typeof request.actionId !== "string" || !ACTION_ID_RE.test(request.actionId)) {
14468
+ throw new Error("Invalid VibeRaven action ID.");
14469
+ }
14470
+ return ["verify", "--action", request.actionId];
14471
+ }
14472
+ throw new Error("Unsupported console command.");
14473
+ }
14474
+ async function runAllowedConsoleCommand(input) {
14475
+ const args = resolveConsoleCommandArgs(input.request);
14476
+ return new Promise((resolve5, reject) => {
14477
+ let settled = false;
14478
+ const settle = (callback) => {
14479
+ if (settled) return;
14480
+ settled = true;
14481
+ callback();
14482
+ };
14483
+ const child = (0, import_node_child_process4.spawn)(process.execPath, [input.cliPath, ...args], {
14484
+ cwd: input.cwd,
14485
+ shell: false,
14486
+ windowsHide: true
14487
+ });
14488
+ let stdout = "";
14489
+ let stderr = "";
14490
+ child.stdout?.on("data", (chunk) => {
14491
+ stdout += String(chunk);
14492
+ });
14493
+ child.stderr?.on("data", (chunk) => {
14494
+ stderr += String(chunk);
14495
+ });
14496
+ child.on("error", (error) => {
14497
+ settle(() => reject(error));
14498
+ });
14499
+ child.on("close", (exitCode) => {
14500
+ settle(() => resolve5({ exitCode, stdout, stderr }));
14501
+ });
14502
+ });
14503
+ }
14504
+
14505
+ // src/console/manifest.ts
14506
+ var import_promises23 = require("node:fs/promises");
14507
+ var import_node_path28 = require("node:path");
14508
+ var ACTIONS_ARTIFACT_PATH = ".viberaven/actions.json";
14509
+ var REPO_PATH_PLACEHOLDER = "<repo-relative-path>";
14510
+ var REDACTED_PLACEHOLDER = "<redacted>";
14511
+ function isSensitiveKey(key) {
14512
+ return /secret|token|key|password|database_url|postgres_url|service_role/i.test(key);
14513
+ }
14514
+ function isAbsoluteLocalPath(value) {
14515
+ return /^[A-Za-z]:[\\/]/.test(value) || /^\/(?:Users|home|tmp|workspace|workspaces|var)\//.test(value);
14516
+ }
14517
+ function redactConsoleSecrets(text) {
14518
+ return redactString(text).replace(/\[REDACTED(?:_(?:SECRET|PRIVATE_KEY))?\]/g, REDACTED_PLACEHOLDER);
14519
+ }
14520
+ function redactConsoleValue(text) {
14521
+ return redactConsoleSecrets(text).replace(
14522
+ /\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|DATABASE_URL|POSTGRES_URL|SERVICE_ROLE)[A-Z0-9_]*)=([^,\s]+)/gi,
14523
+ `$1=${REDACTED_PLACEHOLDER}`
14524
+ ).replace(/\bpostgres(?:ql)?:\/\/[^@\s]+@/gi, `postgresql://${REDACTED_PLACEHOLDER}@`).replace(/(["'`])([A-Za-z]:[\\/][\s\S]*?)\1/g, `$1${REPO_PATH_PLACEHOLDER}$1`).replace(/(["'`])(\/(?:Users|home|tmp|workspace|workspaces|var)\/[\s\S]*?)\1/g, `$1${REPO_PATH_PLACEHOLDER}$1`).replace(/[A-Za-z]:[\\/][^"'`,;\n|]+[\\/][^"'`,;\n|]*/g, REPO_PATH_PLACEHOLDER).replace(/(^|[\s"'=])\/(?:Users|home|tmp|workspace|workspaces|var)\/[^"'`,;\n|]+\/[^"'`,;\n|]*/g, `$1${REPO_PATH_PLACEHOLDER}`).replace(/[A-Za-z]:[\\/][^\s`"]+/g, REPO_PATH_PLACEHOLDER).replace(/(^|[\s"'=])\/(?:Users|home|tmp|workspace|workspaces|var)\/[^\s`"]+/g, `$1${REPO_PATH_PLACEHOLDER}`).replace(/\beyJ[A-Za-z0-9._-]*\b/g, REDACTED_PLACEHOLDER);
14525
+ }
14526
+ function redactPayloadValue(value) {
14527
+ if (typeof value === "string") {
14528
+ return redactConsoleValue(value);
14529
+ }
14530
+ if (Array.isArray(value)) {
14531
+ return value.map((entry) => redactConsoleValue(entry));
14532
+ }
14533
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactUnknown2(entry, key)]));
14534
+ }
14535
+ function redactUnknown2(value, key) {
14536
+ if (key && isSensitiveKey(key)) {
14537
+ return REDACTED_PLACEHOLDER;
14538
+ }
14539
+ if (typeof value === "string") {
14540
+ return redactConsoleValue(value);
14541
+ }
14542
+ if (Array.isArray(value)) {
14543
+ return value.map((entry) => redactUnknown2(entry));
14544
+ }
14545
+ if (value && typeof value === "object") {
14546
+ return Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [entryKey, redactUnknown2(entry, entryKey)]));
14547
+ }
14548
+ return value;
14549
+ }
14550
+ function primaryControlFor(action) {
14551
+ if (!action.target) {
14552
+ return action.verifyCommand ? "verify" : "none";
14553
+ }
14554
+ if (action.target.type === "provider") return "provider";
14555
+ if (action.target.type === "file") return "file";
14556
+ if (action.target.type === "command") return "run";
14557
+ if (action.target.type === "verify") return "verify";
14558
+ if (action.target.type === "url") return "open";
14559
+ return "none";
14560
+ }
14561
+ function targetValue(target) {
14562
+ if (!target) return void 0;
14563
+ if (target.type === "url") return target.href;
14564
+ if (target.type === "file") return target.path;
14565
+ if (target.type === "command" || target.type === "verify") return target.command;
14566
+ return target.provider;
14567
+ }
14568
+ function targetView(target) {
14569
+ if (!target) {
14570
+ return { type: "none", label: "" };
14571
+ }
14572
+ const value = targetValue(target);
14573
+ const redactedValue = target.type === "file" && value && isAbsoluteLocalPath(value) ? REPO_PATH_PLACEHOLDER : value ? redactConsoleValue(value) : void 0;
14574
+ return {
14575
+ type: target.type,
14576
+ label: redactConsoleValue(target.label),
14577
+ ...redactedValue ? { value: redactedValue } : {}
14578
+ };
14579
+ }
14580
+ function copyPayloadView(payload) {
14581
+ return {
14582
+ label: redactConsoleValue(payload.label),
14583
+ format: payload.format,
14584
+ value: redactPayloadValue(payload.value)
14585
+ };
14586
+ }
14587
+ function toConsoleActionViewModel(action) {
14588
+ const verifyCommand = action.verifyCommand ?? `npx -y viberaven verify --action ${action.id}`;
14589
+ return {
14590
+ id: action.id,
14591
+ title: redactConsoleValue(action.title),
14592
+ kind: action.kind,
14593
+ status: action.status,
14594
+ provider: action.provider ? redactConsoleValue(action.provider) : void 0,
14595
+ readiness: (action.readiness ?? []).map(redactConsoleValue),
14596
+ primaryControl: primaryControlFor(action),
14597
+ target: targetView(action.target),
14598
+ copyPayloads: (action.copyPayloads ?? []).map(copyPayloadView),
14599
+ verify: {
14600
+ actionId: action.id,
14601
+ command: redactConsoleValue(verifyCommand),
14602
+ fallbackCommand: action.fallbackCommand ? redactConsoleValue(action.fallbackCommand) : void 0
14603
+ },
14604
+ resumeInstruction: redactConsoleValue(action.resumeInstruction ?? ""),
14605
+ lifecycle: {
14606
+ replacedBy: action.replacedBy,
14607
+ supersedes: action.supersedes ?? []
14608
+ }
14609
+ };
14610
+ }
14611
+ function isV1ActionsManifest(value) {
14612
+ if (!value || typeof value !== "object") return false;
14613
+ const candidate = value;
14614
+ return candidate.version === 1 && Array.isArray(candidate.actions);
14615
+ }
14616
+ async function loadConsoleActionState(cwd) {
14617
+ const actionsPath = (0, import_node_path28.join)(getProjectArtifactsDir(cwd), "actions.json");
14618
+ try {
14619
+ const manifest = JSON.parse(await (0, import_promises23.readFile)(actionsPath, "utf8"));
14620
+ if (!isV1ActionsManifest(manifest)) {
14621
+ return {
14622
+ ok: false,
14623
+ reason: "invalid",
14624
+ message: "Invalid VibeRaven actions manifest. Run npx -y viberaven --agent-mode.",
14625
+ artifactPath: ACTIONS_ARTIFACT_PATH
14626
+ };
14627
+ }
14628
+ return {
14629
+ ok: true,
14630
+ generatedAt: String(manifest.generatedAt ?? ""),
14631
+ gateStatus: String(manifest.gateStatus ?? ""),
14632
+ artifactPath: ACTIONS_ARTIFACT_PATH,
14633
+ actions: manifest.actions.map(toConsoleActionViewModel)
14634
+ };
14635
+ } catch (error) {
14636
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
14637
+ return {
14638
+ ok: false,
14639
+ reason: "missing",
14640
+ message: "No VibeRaven actions found. Run npx -y viberaven --agent-mode.",
14641
+ artifactPath: ACTIONS_ARTIFACT_PATH
14642
+ };
14643
+ }
14644
+ return {
14645
+ ok: false,
14646
+ reason: "invalid",
14647
+ message: "Unable to read VibeRaven actions manifest. Run npx -y viberaven --agent-mode.",
14648
+ artifactPath: ACTIONS_ARTIFACT_PATH
14649
+ };
14650
+ }
14651
+ }
14652
+
14653
+ // src/console/security.ts
14654
+ var import_node_crypto2 = require("node:crypto");
14655
+ function createConsoleSessionToken() {
14656
+ return (0, import_node_crypto2.randomBytes)(32).toString("hex");
14657
+ }
14658
+ function isAllowedConsoleOrigin(origin, port) {
14659
+ if (!origin) return true;
14660
+ return origin === `http://127.0.0.1:${port}` || origin === `http://localhost:${port}`;
14661
+ }
14662
+ function requireConsoleToken(authorizationHeader, expectedToken) {
14663
+ const prefix = "Bearer ";
14664
+ if (!authorizationHeader?.startsWith(prefix)) return false;
14665
+ const received = Buffer.from(authorizationHeader.slice(prefix.length));
14666
+ const expected = Buffer.from(expectedToken);
14667
+ return received.length === expected.length && (0, import_node_crypto2.timingSafeEqual)(received, expected);
14668
+ }
14669
+
14670
+ // src/console/server.ts
14671
+ var PUBLIC_COMMAND_ERROR_MESSAGES = /* @__PURE__ */ new Set(["Unsupported console command.", "Invalid VibeRaven action ID."]);
14672
+ var STATIC_ASSETS = /* @__PURE__ */ new Map([
14673
+ ["/", { filename: "index.html", contentType: "text/html; charset=utf-8" }],
14674
+ ["/styles.css", { filename: "styles.css", contentType: "text/css; charset=utf-8" }],
14675
+ ["/app.js", { filename: "app.js", contentType: "application/javascript; charset=utf-8" }]
14676
+ ]);
14677
+ var ACTION_EVENT_FILES = /* @__PURE__ */ new Set(["actions.json", "action-registry.json", "gate-result.json"]);
14678
+ function sendJson(response, status, body) {
14679
+ response.writeHead(status, { "Content-Type": "application/json" });
14680
+ response.end(JSON.stringify(body));
14681
+ }
14682
+ function sendText(response, status, contentType, body) {
14683
+ response.writeHead(status, { "Content-Type": contentType });
14684
+ response.end(body);
14685
+ }
14686
+ function injectConsoleToken(html, token) {
14687
+ const tokenScript = `<script>window.__VIBERAVEN_TOKEN__ = ${JSON.stringify(token)};</script>`;
14688
+ return html.includes("</head>") ? html.replace("</head>", ` ${tokenScript}
14689
+ </head>`) : `${html}
14690
+ ${tokenScript}`;
14691
+ }
14692
+ async function readJsonBody(request) {
14693
+ const chunks = [];
14694
+ for await (const chunk of request) {
14695
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
14696
+ }
14697
+ const body = Buffer.concat(chunks).toString("utf8").trim();
14698
+ if (!body) return {};
14699
+ try {
14700
+ return JSON.parse(body);
14701
+ } catch {
14702
+ throw new Error("Invalid JSON body.");
14703
+ }
14704
+ }
14705
+ function getHeader(request, name) {
14706
+ const value = request.headers[name.toLowerCase()];
14707
+ return Array.isArray(value) ? value[0] : value;
14708
+ }
14709
+ function getServerPort(server) {
14710
+ const address = server.address();
14711
+ if (!address || typeof address === "string") {
14712
+ throw new Error("Console server is not listening on a TCP port.");
14713
+ }
14714
+ return address.port;
14715
+ }
14716
+ function publicCommandErrorMessage(error) {
14717
+ if (error instanceof Error && PUBLIC_COMMAND_ERROR_MESSAGES.has(error.message)) {
14718
+ return error.message;
14719
+ }
14720
+ return "Console command failed.";
14721
+ }
14722
+ function sanitizeCommandOutput(output) {
14723
+ return redactConsoleValue(output).split(/\r?\n/).filter((line) => !/^\s*(?:stack\b|at\s+)/i.test(line)).join("\n");
14724
+ }
14725
+ function sanitizeCommandResult(result) {
14726
+ return {
14727
+ exitCode: result.exitCode,
14728
+ stdout: sanitizeCommandOutput(result.stdout),
14729
+ stderr: sanitizeCommandOutput(result.stderr)
14730
+ };
14731
+ }
14732
+ function resolveConsoleAsset(filename) {
14733
+ const candidates = [
14734
+ (0, import_node_path29.join)(__dirname, "console", filename),
14735
+ (0, import_node_path29.join)(__dirname, "..", "..", "assets", "console", filename)
14736
+ ];
14737
+ return candidates.find((candidate) => (0, import_node_fs12.existsSync)(candidate));
14738
+ }
14739
+ function removeEventClient(eventClients, client) {
14740
+ eventClients.delete(client);
14741
+ }
14742
+ function destroyEventClient(eventClients, client) {
14743
+ removeEventClient(eventClients, client);
14744
+ if (client.response.writableEnded || client.response.destroyed) return;
14745
+ if (typeof client.response.destroy === "function") {
14746
+ client.response.destroy();
14747
+ return;
14748
+ }
14749
+ client.response.socket?.destroy();
14750
+ }
14751
+ function sendActionChangedEvent(eventClients, client) {
14752
+ const { response } = client;
14753
+ if (response.writableEnded || response.destroyed) {
14754
+ removeEventClient(eventClients, client);
14755
+ return;
14756
+ }
14757
+ const didFlush = response.write('event: actions\ndata: {"type":"actions-changed"}\n\n');
14758
+ if (!didFlush) {
14759
+ destroyEventClient(eventClients, client);
14760
+ }
14761
+ }
14762
+ async function createConsoleServer(input) {
14763
+ const token = createConsoleSessionToken();
14764
+ const cliPath = input.cliPath ?? process.argv[1] ?? "";
14765
+ const runCommand2 = input.runCommand ?? runAllowedConsoleCommand;
14766
+ const watchDirectory = input.watchDirectory ?? import_node_fs12.watch;
14767
+ const eventClients = /* @__PURE__ */ new Set();
14768
+ const viberavenDir = (0, import_node_path29.join)(input.cwd, ".viberaven");
14769
+ let watcher;
14770
+ function closeWatcher() {
14771
+ watcher?.close();
14772
+ watcher = void 0;
14773
+ }
14774
+ if ((0, import_node_fs12.existsSync)(viberavenDir)) {
14775
+ try {
14776
+ watcher = watchDirectory(viberavenDir, (_eventType, filename) => {
14777
+ const changedFile = typeof filename === "string" ? filename : void 0;
14778
+ if (!changedFile || !ACTION_EVENT_FILES.has(changedFile)) return;
14779
+ for (const client of Array.from(eventClients)) {
14780
+ sendActionChangedEvent(eventClients, client);
14781
+ }
14782
+ });
14783
+ watcher.on("error", closeWatcher);
14784
+ } catch {
14785
+ closeWatcher();
14786
+ }
14787
+ }
14788
+ const server = (0, import_node_http.createServer)(async (request, response) => {
14789
+ const actualPort2 = getServerPort(server);
14790
+ const origin = getHeader(request, "origin");
14791
+ const authorization = getHeader(request, "authorization");
14792
+ const hasValidToken = requireConsoleToken(authorization, token);
14793
+ const hasAllowedOrigin = isAllowedConsoleOrigin(origin, actualPort2);
14794
+ const url = new URL(request.url ?? "/", `http://127.0.0.1:${actualPort2}`);
14795
+ const staticAsset = STATIC_ASSETS.get(url.pathname);
14796
+ if (request.method === "GET" && staticAsset) {
14797
+ const assetPath = resolveConsoleAsset(staticAsset.filename);
14798
+ if (!assetPath) {
14799
+ sendJson(response, 404, { ok: false, error: "Console asset not found." });
14800
+ return;
14801
+ }
14802
+ const assetBody = await (0, import_promises24.readFile)(assetPath, "utf8");
14803
+ sendText(
14804
+ response,
14805
+ 200,
14806
+ staticAsset.contentType,
14807
+ staticAsset.filename === "index.html" ? injectConsoleToken(assetBody, token) : assetBody
14808
+ );
14809
+ return;
14810
+ }
14811
+ if (request.method === "GET" && url.pathname === "/api/actions") {
14812
+ if (!hasValidToken && !hasAllowedOrigin) {
14813
+ sendJson(response, 403, { ok: false, error: "Disallowed origin." });
14814
+ return;
14815
+ }
14816
+ sendJson(response, 200, await loadConsoleActionState(input.cwd));
14817
+ return;
14818
+ }
14819
+ if (request.method === "GET" && url.pathname === "/api/events") {
14820
+ if (!hasValidToken && !hasAllowedOrigin) {
14821
+ sendJson(response, 403, { ok: false, error: "Disallowed origin." });
14822
+ return;
14823
+ }
14824
+ response.writeHead(200, {
14825
+ "Content-Type": "text/event-stream",
14826
+ "Cache-Control": "no-cache",
14827
+ Connection: "keep-alive"
14828
+ });
14829
+ response.write(": connected\n\n");
14830
+ input.onEventResponse?.(response);
14831
+ const client = { response };
14832
+ const removeClient = () => removeEventClient(eventClients, client);
14833
+ eventClients.add(client);
14834
+ request.on("close", removeClient);
14835
+ request.on("error", removeClient);
14836
+ response.on("close", removeClient);
14837
+ response.on("error", removeClient);
14838
+ return;
14839
+ }
14840
+ if (request.method === "POST" && url.pathname === "/api/command") {
14841
+ if (!hasAllowedOrigin) {
14842
+ sendJson(response, 403, { ok: false, error: "Disallowed origin." });
14843
+ return;
14844
+ }
14845
+ if (!hasValidToken) {
14846
+ sendJson(response, 401, { ok: false, error: "Unauthorized." });
14847
+ return;
14848
+ }
14849
+ let commandRequest;
14850
+ try {
14851
+ commandRequest = await readJsonBody(request);
14852
+ } catch {
14853
+ sendJson(response, 400, { ok: false, error: "Invalid JSON body." });
14854
+ return;
14855
+ }
14856
+ try {
14857
+ const result = await runCommand2({ cliPath, cwd: input.cwd, request: commandRequest });
14858
+ sendJson(response, 200, { ok: true, result: sanitizeCommandResult(result) });
14859
+ } catch (error) {
14860
+ sendJson(response, 400, { ok: false, error: publicCommandErrorMessage(error) });
14861
+ }
14862
+ return;
14863
+ }
14864
+ sendJson(response, 404, { ok: false, error: "Not found." });
14865
+ });
14866
+ await new Promise((resolve5, reject) => {
14867
+ const handleListenError = (error) => {
14868
+ closeWatcher();
14869
+ reject(error);
14870
+ };
14871
+ server.once("error", handleListenError);
14872
+ server.listen(input.port ?? 0, "127.0.0.1", () => {
14873
+ server.off("error", handleListenError);
14874
+ resolve5();
14875
+ });
14876
+ });
14877
+ const actualPort = getServerPort(server);
14878
+ return {
14879
+ url: `http://127.0.0.1:${actualPort}`,
14880
+ token,
14881
+ close: () => new Promise((resolve5, reject) => {
14882
+ closeWatcher();
14883
+ for (const client of eventClients) {
14884
+ client.response.end();
14885
+ }
14886
+ eventClients.clear();
14887
+ server.close((error) => {
14888
+ if (error) {
14889
+ reject(error);
14890
+ return;
14891
+ }
14892
+ resolve5();
14893
+ });
14894
+ })
14895
+ };
14896
+ }
14897
+
14898
+ // src/commands/console.ts
14899
+ async function runConsoleCliCommand(input) {
14900
+ const closeServer = async (serverToClose) => {
14901
+ try {
14902
+ await serverToClose.close();
14903
+ return 0;
14904
+ } catch (error) {
14905
+ process.stderr.write(
14906
+ `Could not stop console server: ${error instanceof Error ? error.message : String(error)}
14907
+ `
14908
+ );
14909
+ return 1;
14910
+ }
14911
+ };
14912
+ const start = input.start ?? createConsoleServer;
14913
+ const server = await start({
14914
+ cwd: input.cwd,
14915
+ port: input.port,
14916
+ open: false
14917
+ });
14918
+ process.stdout.write(`VibeRaven Console: ${server.url}
14919
+ `);
14920
+ process.stdout.write("Local only. Press Ctrl+C to stop.\n");
14921
+ if (input.open) {
14922
+ try {
14923
+ await openUrlInBrowser(server.url);
14924
+ } catch (error) {
14925
+ process.stderr.write(
14926
+ `Could not open browser: ${error instanceof Error ? error.message : String(error)}. Open manually: ${server.url}
14927
+ `
14928
+ );
14929
+ }
14930
+ }
14931
+ if (input.once) {
14932
+ return closeServer(server);
14933
+ }
14934
+ return new Promise((resolve5) => {
14935
+ const onSigint = () => {
14936
+ process.off("SIGINT", onSigint);
14937
+ void closeServer(server).then(resolve5);
14938
+ };
14939
+ process.once("SIGINT", onSigint);
14940
+ });
14941
+ }
13929
14942
 
13930
14943
  // src/output/nextActionBlock.ts
13931
14944
  function buildNextActionBlock(tasks, loopState, plan) {
@@ -13941,11 +14954,7 @@ function buildNextActionBlock(tasks, loopState, plan) {
13941
14954
  return {
13942
14955
  ...base,
13943
14956
  type: "stalled",
13944
- title: "Loop stalled - no gap reduction after 2+ consecutive scans",
13945
- agentInstruction: "Stop the scan loop. Explain the blocker plainly, then either guide the provider/user action or report that no safe repo-code recipe is available.",
13946
- executionPlan: [
13947
- { kind: "stop", note: "Do not keep spending scans while the loop is stalled." }
13948
- ],
14957
+ title: "Loop stalled \u2014 no gap reduction after 2+ consecutive scans",
13949
14958
  requiresUserAction: true,
13950
14959
  stallReason
13951
14960
  };
@@ -13954,67 +14963,42 @@ function buildNextActionBlock(tasks, loopState, plan) {
13954
14963
  return {
13955
14964
  ...base,
13956
14965
  type: "verify",
13957
- title: "Batch complete - run verify to rescan before next batch",
13958
- agentInstruction: "Run verify now, read the refreshed VibeRaven artifacts, then continue with the next safe repo fix or provider step. Do not stop at a summary.",
13959
- executionPlan: [
13960
- { kind: "verify", command: "viberaven_verify" },
13961
- { kind: "continue-loop", note: "After verify, continue until the gate is clear or a provider/user blocker remains." }
13962
- ],
14966
+ title: "Batch complete \u2014 run verify to rescan before next batch",
13963
14967
  mcpTool: "viberaven_verify",
13964
14968
  mcpArgs: {},
13965
14969
  requiresUserAction: false
13966
14970
  };
13967
14971
  }
13968
- const repoCodeTask = tasks.find((task) => task.fixType === "repo-code" && !task.requiresUserAction);
14972
+ const repoCodeTask = tasks.find((t) => t.fixType === "repo-code" && !t.requiresUserAction);
13969
14973
  if (repoCodeTask) {
13970
- const fallbackCommand = repoCodeTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${repoCodeTask.gapId} --yes` : void 0;
13971
14974
  return {
13972
14975
  ...base,
13973
14976
  type: "repo-code",
13974
14977
  gapId: repoCodeTask.gapId,
13975
14978
  title: repoCodeTask.title,
13976
- agentInstruction: "Apply this repo-code fix now using the MCP tool or fallback command, then continue the local VibeRaven loop. Do not stop at a summary.",
13977
- executionPlan: [
13978
- {
13979
- kind: "apply-repo-fix",
13980
- command: repoCodeTask.mcpTool ?? fallbackCommand,
13981
- note: "Patch only this gap and preserve unrelated user changes."
13982
- },
13983
- { kind: "continue-loop", note: "Apply remaining safe repo fixes until the batch is full, then verify once." }
13984
- ],
13985
14979
  mcpTool: repoCodeTask.mcpTool,
13986
14980
  mcpArgs: repoCodeTask.mcpArgs,
13987
- fallbackCommand,
14981
+ fallbackCommand: repoCodeTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${repoCodeTask.gapId} --yes` : void 0,
13988
14982
  requiresUserAction: false
13989
14983
  };
13990
14984
  }
13991
- const providerTask = tasks.find((task) => task.fixType === "provider-action");
14985
+ const providerTask = tasks.find((t) => t.fixType === "provider-action");
13992
14986
  if (providerTask) {
13993
14987
  return {
13994
14988
  ...base,
13995
14989
  type: "provider-action",
13996
14990
  gapId: providerTask.gapId,
13997
14991
  title: providerTask.title,
13998
- agentInstruction: "Open or present the provider step now. If browser/tool access is available, open the dashboard link for the user; otherwise show the exact step and copy values. Do not keep telling the user to verify until the provider step is done.",
13999
- executionPlan: [
14000
- { kind: "open-provider-step", note: "Use VIBERAVEN_PROVIDER_ACTION for the exact dashboard step and URL." },
14001
- { kind: "wait-for-user", note: "Wait for confirmation or read-only MCP evidence before verifying." }
14002
- ],
14003
14992
  requiresUserAction: true
14004
14993
  };
14005
14994
  }
14006
- const upgradeTask = tasks.find((task) => task.fixType === "upgrade-required");
14995
+ const upgradeTask = tasks.find((t) => t.fixType === "upgrade-required");
14007
14996
  if (upgradeTask) {
14008
14997
  return {
14009
14998
  ...base,
14010
14999
  type: "upgrade-required",
14011
15000
  gapId: upgradeTask.gapId,
14012
15001
  title: upgradeTask.title,
14013
- agentInstruction: "Explain that this production lane needs an upgrade or connected provider evidence. Continue with any remaining unlocked repo-code fixes if present; otherwise stop cleanly.",
14014
- executionPlan: [
14015
- { kind: "upgrade", command: "https://viberaven.dev/pricing" },
14016
- { kind: "stop", note: "Do not pretend locked lanes or provider state were fixed locally." }
14017
- ],
14018
15002
  requiresUserAction: true,
14019
15003
  upgradeUrl: "https://viberaven.dev/pricing"
14020
15004
  };
@@ -14022,20 +15006,15 @@ function buildNextActionBlock(tasks, loopState, plan) {
14022
15006
  return {
14023
15007
  ...base,
14024
15008
  type: "done",
14025
- title: "All gaps resolved - production gate is clear",
14026
- agentInstruction: "The repo-code gate is clear. Run strict before deploy and still verify provider dashboard state through MCP or the provider dashboard.",
14027
- executionPlan: [
14028
- { kind: "verify", command: "npx -y viberaven --strict" },
14029
- { kind: "stop", note: "Do not deploy until provider dashboard state is verified where applicable." }
14030
- ],
15009
+ title: "All gaps resolved \u2014 production gate is clear",
14031
15010
  requiresUserAction: false
14032
15011
  };
14033
15012
  }
14034
15013
  function resolveStallReason(tasks) {
14035
15014
  if (tasks.length === 0) return "no-recipes";
14036
- const allUpgradeOrEmpty = tasks.every((task) => task.fixType === "upgrade-required");
15015
+ const allUpgradeOrEmpty = tasks.every((t) => t.fixType === "upgrade-required");
14037
15016
  if (allUpgradeOrEmpty) return "no-recipes";
14038
- const allProviderAction = tasks.every((task) => task.fixType === "provider-action");
15017
+ const allProviderAction = tasks.every((t) => t.fixType === "provider-action");
14039
15018
  if (allProviderAction) return "provider-action-required";
14040
15019
  return "unknown";
14041
15020
  }
@@ -14064,7 +15043,7 @@ function buildProviderActionBlock(task) {
14064
15043
  }
14065
15044
  function printProviderActionBlock(tasks) {
14066
15045
  const task = tasks.find(
14067
- (entry) => entry.fixType === "provider-action" && entry.requiresUserAction === true
15046
+ (t) => t.fixType === "provider-action" && t.requiresUserAction === true
14068
15047
  );
14069
15048
  if (!task) return;
14070
15049
  const block = buildProviderActionBlock(task);
@@ -14079,138 +15058,10 @@ function printNextActionBlock(block) {
14079
15058
  console.log(NEXT_ACTION_END);
14080
15059
  }
14081
15060
 
14082
- // src/commands/preview.ts
14083
- function previewArtifact(cwd) {
14084
- return {
14085
- version: 1,
14086
- scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
14087
- workspacePath: cwd,
14088
- score: 42,
14089
- scoreLabel: "Blocked",
14090
- summary: "Vercel, Supabase, and Stripe are detected, but launch-critical provider setup is not proven yet.",
14091
- archetype: "ai-built-saas",
14092
- plan: "free",
14093
- productionCorePercent: 40,
14094
- usage: {
14095
- plan: "free",
14096
- remainingPrompts: 0,
14097
- used: 0,
14098
- limit: 0,
14099
- period: "lifetime",
14100
- unlockedMapCategoryKeys: ["appFlow", "frontend", "backend", "auth", "database", "payments"]
14101
- },
14102
- gaps: [
14103
- {
14104
- id: "auth_secret_missing",
14105
- category: "SECURITY & AUTH",
14106
- severity: "critical",
14107
- title: "Create production auth secret",
14108
- detail: "The app needs a production session secret before real users sign in.",
14109
- copyPrompt: "Generate and document NEXTAUTH_SECRET or the equivalent auth secret for this stack.",
14110
- toolSuggestions: [],
14111
- mcpSuggestion: null,
14112
- primaryMapCategory: "auth",
14113
- affectedMapCategories: []
14114
- },
14115
- {
14116
- id: "rls_disabled",
14117
- category: "DATABASE & DATA",
14118
- severity: "critical",
14119
- title: "Verify Supabase RLS before launch",
14120
- detail: "Database access must be protected by Row Level Security or equivalent server-side controls.",
14121
- copyPrompt: "Open Supabase and verify RLS policies for user-owned tables.",
14122
- toolSuggestions: [],
14123
- mcpSuggestion: null,
14124
- primaryMapCategory: "database",
14125
- affectedMapCategories: []
14126
- },
14127
- {
14128
- id: "stripe_webhook_secret_missing",
14129
- category: "PAYMENTS",
14130
- severity: "critical",
14131
- title: "Connect Stripe webhook secret",
14132
- detail: "Stripe webhook signature verification needs STRIPE_WEBHOOK_SECRET before live payments.",
14133
- copyPrompt: "Create a Stripe webhook endpoint and add STRIPE_WEBHOOK_SECRET to the deployment environment.",
14134
- toolSuggestions: [],
14135
- mcpSuggestion: null,
14136
- primaryMapCategory: "payments",
14137
- affectedMapCategories: []
14138
- }
14139
- ],
14140
- missionGraph: {
14141
- areas: [],
14142
- byArea: {},
14143
- byProvider: {},
14144
- repositoryEvidence: { env: [], security: [] }
14145
- },
14146
- stackWiring: { items: [], byKey: {} },
14147
- providerRegistry: {
14148
- version: 1,
14149
- source: "bundled",
14150
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
14151
- status: "fresh",
14152
- staleAfterDays: 14,
14153
- providers: []
14154
- }
14155
- };
14156
- }
14157
- function check(done, text) {
14158
- const mark = done ? import_picocolors5.default.green("[x]") : import_picocolors5.default.yellow("[ ]");
14159
- return ` ${mark} ${text}`;
14160
- }
14161
- async function runPreviewCommand(options) {
14162
- const artifact = previewArtifact(options.cwd);
14163
- const tasks = buildTaskList(artifact);
14164
- const next = buildNextActionBlock(tasks, {
14165
- batchApplied: 1,
14166
- appliedGapIdsSinceScan: ["auth_secret_missing"],
14167
- lastGapCount: artifact.gaps.length,
14168
- stalledScans: 0
14169
- }, "free");
14170
- if (options.json) {
14171
- console.log(JSON.stringify({ artifact, tasks, next }, null, 2));
14172
- return 0;
14173
- }
14174
- console.log(import_picocolors5.default.dim(`VibeRaven ${VERSION} preview - local rehearsal, no login or API spend.`));
14175
- console.log(import_picocolors5.default.bold("VibeRaven"));
14176
- console.log("Taking this app from demo to production.");
14177
- console.log("");
14178
- console.log(`${import_picocolors5.default.bold("Status:")} ${import_picocolors5.default.red("BLOCKED")} | vercel + supabase + stripe | 3 launch gaps`);
14179
- console.log("");
14180
- console.log(import_picocolors5.default.bold("Progress"));
14181
- console.log(check(true, "Understand the stack and launch gaps"));
14182
- console.log(check(true, "Patch the first repo-owned secret gap"));
14183
- console.log(check(false, "Open Supabase and verify RLS policies"));
14184
- console.log(check(false, "Connect Stripe webhook signing secret"));
14185
- console.log(check(false, "Verify again before launch"));
14186
- console.log("");
14187
- console.log(import_picocolors5.default.bold("I can do now"));
14188
- console.log(" 1. Add missing env names and agent rules.");
14189
- console.log(" 2. Prepare focused repo fixes the coding agent can apply.");
14190
- console.log(" 3. Keep the launch loop moving until provider proof is needed.");
14191
- console.log("");
14192
- console.log(import_picocolors5.default.bold("I need you for"));
14193
- console.log(" 1. Supabase: open the project and confirm RLS policies.");
14194
- console.log(" 2. Stripe: create or open the webhook endpoint.");
14195
- console.log(" 3. Deployment: paste provider secrets into Vercel or your host.");
14196
- console.log("");
14197
- console.log(import_picocolors5.default.bold("Open"));
14198
- console.log(` supabase: ${import_picocolors5.default.cyan("https://supabase.com/dashboard")}`);
14199
- console.log(` stripe: ${import_picocolors5.default.cyan("https://dashboard.stripe.com/")}`);
14200
- console.log("");
14201
- console.log(`${import_picocolors5.default.bold("Copy env names:")} NEXTAUTH_SECRET, STRIPE_WEBHOOK_SECRET`);
14202
- console.log(`${import_picocolors5.default.bold("Next:")} I will guide the blocked provider setup, then verify when you confirm it is done.`);
14203
- if (options.agentMode) {
14204
- console.log("");
14205
- console.log(import_picocolors5.default.dim("Agent note: render the checklist above as the live timeline; update [ ] to [x] as work completes."));
14206
- }
14207
- return 0;
14208
- }
14209
-
14210
15061
  // src/providerMcpBridge.ts
14211
- var import_node_fs12 = require("node:fs");
15062
+ var import_node_fs13 = require("node:fs");
14212
15063
  var import_node_os2 = require("node:os");
14213
- var import_node_path24 = require("node:path");
15064
+ var import_node_path30 = require("node:path");
14214
15065
  var UPGRADE_URL4 = "https://viberaven.dev/pricing";
14215
15066
  var FALLBACK_COMMAND = "npx -y viberaven audit --vercel-supabase --json";
14216
15067
  var SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["supabase", "vercel"]);
@@ -14218,9 +15069,9 @@ var configPathsOverride;
14218
15069
  function defaultMcpConfigPaths() {
14219
15070
  const home = (0, import_node_os2.homedir)();
14220
15071
  return [
14221
- (0, import_node_path24.join)(home, ".config", "claude", "claude_desktop_config.json"),
14222
- (0, import_node_path24.join)(home, ".cursor", "mcp.json"),
14223
- (0, import_node_path24.join)(home, ".gemini", "antigravity", "mcp_config.json")
15072
+ (0, import_node_path30.join)(home, ".config", "claude", "claude_desktop_config.json"),
15073
+ (0, import_node_path30.join)(home, ".cursor", "mcp.json"),
15074
+ (0, import_node_path30.join)(home, ".gemini", "antigravity", "mcp_config.json")
14224
15075
  ];
14225
15076
  }
14226
15077
  function resolveConfigPaths() {
@@ -14249,11 +15100,11 @@ function findServerEntry(servers, provider2) {
14249
15100
  function findProviderMcpConfig(provider2, configPaths) {
14250
15101
  const paths = configPaths ?? resolveConfigPaths();
14251
15102
  for (const path of paths) {
14252
- if (!(0, import_node_fs12.existsSync)(path)) {
15103
+ if (!(0, import_node_fs13.existsSync)(path)) {
14253
15104
  continue;
14254
15105
  }
14255
15106
  try {
14256
- const raw = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
15107
+ const raw = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
14257
15108
  const servers = parseMcpServers(raw);
14258
15109
  if (!servers) {
14259
15110
  continue;
@@ -14323,8 +15174,8 @@ Usage:
14323
15174
 
14324
15175
  viberaven status
14325
15176
 
14326
- viberaven preview [--agent-mode] [--json]
14327
- Local production rehearsal for videos and onboarding; no login or API spend
15177
+ viberaven actions [--json] [path]
15178
+ Print current chat-native production action surface
14328
15179
 
14329
15180
  viberaven connect --session <id> --token <token> [--once] [--api-url <url>]
14330
15181
  Handshake, save runner session, then watch for jobs (Ctrl+C to stop)
@@ -14458,7 +15309,7 @@ function isBooleanFlag(command, key) {
14458
15309
  return true;
14459
15310
  }
14460
15311
  if (key === "strict") return true;
14461
- if (key === "open" && (command === "" || command === "scan" || command === "report")) return true;
15312
+ if (key === "open" && (command === "" || command === "scan" || command === "report" || command === "console")) return true;
14462
15313
  if (key === "verify" && command === "") return true;
14463
15314
  if (key === "vercel-supabase" && command === "audit") return true;
14464
15315
  if (key === "json" && command === "validate-npm-package") return true;
@@ -14480,7 +15331,7 @@ async function guardEarlyVerifyScan(input) {
14480
15331
  if (!verifyLike) {
14481
15332
  return void 0;
14482
15333
  }
14483
- const workspacePath = input.positional[0] ? (0, import_node_path25.join)(process.cwd(), input.positional[0]) : await resolveWorkspaceRoot(process.cwd());
15334
+ const workspacePath = input.positional[0] ? (0, import_node_path31.join)(process.cwd(), input.positional[0]) : await resolveWorkspaceRoot(process.cwd());
14484
15335
  const loopState = await loadLoopState(workspacePath);
14485
15336
  if (loopState.batchApplied <= 0) {
14486
15337
  return void 0;
@@ -14529,8 +15380,8 @@ async function cmdLogout() {
14529
15380
  }
14530
15381
  async function cmdProviderVerify(flags, positional) {
14531
15382
  const provider2 = typeof flags.provider === "string" ? flags.provider : positional[0];
14532
- const check2 = typeof flags.check === "string" ? flags.check : positional[1];
14533
- if (!provider2 || !check2) {
15383
+ const check = typeof flags.check === "string" ? flags.check : positional[1];
15384
+ if (!provider2 || !check) {
14534
15385
  console.error("Usage: viberaven provider-verify --provider <supabase|vercel> --check <id> [--plan free|pro]");
14535
15386
  return 1;
14536
15387
  }
@@ -14543,7 +15394,7 @@ async function cmdProviderVerify(flags, positional) {
14543
15394
  }
14544
15395
  const result = await verifyProviderGap({
14545
15396
  provider: provider2,
14546
- check: check2,
15397
+ check,
14547
15398
  cwd: process.cwd(),
14548
15399
  plan
14549
15400
  });
@@ -14556,7 +15407,7 @@ async function cmdStatus(flags, positional) {
14556
15407
  console.log("Not signed in. Run: viberaven login");
14557
15408
  return 1;
14558
15409
  }
14559
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15410
+ const startDir = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd();
14560
15411
  let artifact;
14561
15412
  try {
14562
15413
  artifact = await loadLastArtifact(startDir);
@@ -14710,7 +15561,7 @@ async function cmdWatch(flags) {
14710
15561
  }
14711
15562
  }
14712
15563
  async function runScanCommand(flags, positional, options) {
14713
- const workspacePath = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
15564
+ const workspacePath = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
14714
15565
  const apiBaseUrl = resolveApiBaseUrl(typeof flags["api-url"] === "string" ? flags["api-url"] : void 0);
14715
15566
  let accessToken;
14716
15567
  try {
@@ -14776,6 +15627,12 @@ async function runScanCommand(flags, positional, options) {
14776
15627
  const block = buildNextActionBlock(tasks, updatedState, plan);
14777
15628
  printNextActionBlock(block);
14778
15629
  printProviderActionBlock(tasks);
15630
+ try {
15631
+ const manifest = JSON.parse(await (0, import_promises25.readFile)(paths.actionsPath, "utf8"));
15632
+ console.log(renderActionSurface(manifest, { limit: 5 }).trimEnd());
15633
+ } catch (error) {
15634
+ console.warn(error instanceof Error ? error.message : String(error));
15635
+ }
14779
15636
  await saveLoopState(workspacePath, updatedState);
14780
15637
  }
14781
15638
  if (flags.open) {
@@ -14788,7 +15645,7 @@ async function runScanCommand(flags, positional, options) {
14788
15645
  return { exitCode: 0, artifacts: paths };
14789
15646
  }
14790
15647
  async function cmdReport(flags, positional) {
14791
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15648
+ const startDir = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd();
14792
15649
  try {
14793
15650
  const paths = await refreshReportFromDisk(startDir);
14794
15651
  console.log(`Report refreshed: ${paths.reportPath}`);
@@ -14810,7 +15667,7 @@ async function cmdReport(flags, positional) {
14810
15667
  }
14811
15668
  }
14812
15669
  async function cmdPrompt(flags, positional) {
14813
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15670
+ const startDir = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd();
14814
15671
  let artifact;
14815
15672
  try {
14816
15673
  artifact = await loadLastArtifact(startDir);
@@ -14908,7 +15765,7 @@ async function main() {
14908
15765
  const wantsJsonl = hasFlag(flags, "jsonl");
14909
15766
  const wantsStrict = hasFlag(flags, "strict");
14910
15767
  if (flags.condense) {
14911
- const cwd = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15768
+ const cwd = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd();
14912
15769
  const result = await runCondenseCommand({ cwd });
14913
15770
  console.log(`VibeRaven context map refreshed: ${result.contextMapPath}`);
14914
15771
  return 0;
@@ -14926,6 +15783,18 @@ async function main() {
14926
15783
  console.log(JSON.stringify(result, null, 2));
14927
15784
  return result.status.startsWith("refused") || result.status === "failed" ? 1 : 0;
14928
15785
  }
15786
+ if (!command && flags.verify === true && typeof flags.action === "string") {
15787
+ return runVerifyActionCommand({
15788
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd(),
15789
+ actionId: flags.action
15790
+ });
15791
+ }
15792
+ if (command === "verify" && typeof flags.action === "string") {
15793
+ return runVerifyActionCommand({
15794
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd(),
15795
+ actionId: flags.action
15796
+ });
15797
+ }
14929
15798
  if (!command && (isAgentMode || flags.verify === true || wantsJson || wantsJsonl || wantsStrict)) {
14930
15799
  const guardedExitCode = await guardEarlyVerifyScan({ flags, positional, wantsStrict });
14931
15800
  if (guardedExitCode !== void 0) {
@@ -14937,7 +15806,7 @@ async function main() {
14937
15806
  console.error("VibeRaven could not produce machine output because scan artifacts were not written.");
14938
15807
  return 3;
14939
15808
  }
14940
- const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0, import_promises19.readFile)(scanResult.artifacts.gateResultPath, "utf8")) : void 0;
15809
+ const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0, import_promises25.readFile)(scanResult.artifacts.gateResultPath, "utf8")) : void 0;
14941
15810
  const strictExitCode = wantsStrict && gateResult ? exitCodeForStrictGate(gateResult, { failOnWarnings: flags.strict === "warning" }) : scanResult.exitCode;
14942
15811
  if (wantsJson && gateResult) {
14943
15812
  process.stdout.write(renderGateResultJson(gateResult));
@@ -14969,16 +15838,27 @@ async function main() {
14969
15838
  return 0;
14970
15839
  case "status":
14971
15840
  return cmdStatus(flags, positional);
14972
- case "preview":
14973
- return runPreviewCommand({
14974
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd(),
14975
- agentMode: flags["agent-mode"] === true,
15841
+ case "actions":
15842
+ return runActionsCommand({
15843
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd(),
14976
15844
  json: Boolean(flags.json)
14977
15845
  });
15846
+ case "console":
15847
+ if (process.env.VIBERAVEN_EXPERIMENTAL_CONSOLE !== "1") {
15848
+ console.error("The local VibeRaven Console is experimental and hidden from the public npm release.");
15849
+ console.error("Use chat-native actions instead: viberaven actions");
15850
+ console.error("To preview the experimental console, set VIBERAVEN_EXPERIMENTAL_CONSOLE=1.");
15851
+ return 1;
15852
+ }
15853
+ return runConsoleCliCommand({
15854
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd(),
15855
+ port: typeof flags.port === "string" ? Number.parseInt(flags.port, 10) : void 0,
15856
+ open: flags.open === true
15857
+ });
14978
15858
  case "next":
14979
15859
  return runNextCommand({
14980
15860
  json: Boolean(flags.json),
14981
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd()
15861
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd()
14982
15862
  });
14983
15863
  case "guide": {
14984
15864
  const provider2 = positional[0];
@@ -15016,7 +15896,7 @@ async function main() {
15016
15896
  case "provider-verify":
15017
15897
  return cmdProviderVerify(flags, positional);
15018
15898
  case "init": {
15019
- const cwd = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15899
+ const cwd = positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd();
15020
15900
  const agents = typeof flags.agents === "string" ? flags.agents : void 0;
15021
15901
  return runInitCommand({
15022
15902
  cwd,
@@ -15030,7 +15910,7 @@ async function main() {
15030
15910
  return 1;
15031
15911
  }
15032
15912
  return runDoctorAgentsCommand({
15033
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd()
15913
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd()
15034
15914
  });
15035
15915
  case "validate-npm-package":
15036
15916
  return runValidateNpmPackageCommand({
@@ -15043,7 +15923,7 @@ async function main() {
15043
15923
  return 1;
15044
15924
  }
15045
15925
  return runAuditCommand({
15046
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd(),
15926
+ cwd: positional[0] ? (0, import_node_path31.join)(process.cwd(), positional[0]) : process.cwd(),
15047
15927
  json: Boolean(flags.json)
15048
15928
  });
15049
15929
  default: