@viberaven/cli 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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}[`;
@@ -171,7 +171,7 @@ __export(cli_exports, {
171
171
  });
172
172
  module.exports = __toCommonJS(cli_exports);
173
173
  var import_promises19 = require("node:fs/promises");
174
- var import_node_path25 = require("node:path");
174
+ var import_node_path26 = require("node:path");
175
175
 
176
176
  // src/config.ts
177
177
  var import_node_os = require("node:os");
@@ -7992,7 +7992,7 @@ async function runProjectScan(options) {
7992
7992
 
7993
7993
  // src/artifacts.ts
7994
7994
  var import_promises5 = require("node:fs/promises");
7995
- var import_node_path8 = require("node:path");
7995
+ var import_node_path9 = require("node:path");
7996
7996
 
7997
7997
  // src/capabilities/classify.ts
7998
7998
  function gapText(gap) {
@@ -8853,7 +8853,11 @@ function buildProviderAction(gap, provider2) {
8853
8853
  envKeyExample: void 0,
8854
8854
  // Use step title as the done signal
8855
8855
  doneSignal: `${step.title} step completed`,
8856
- verifyCommand: PUBLIC_VERIFY_COMMAND
8856
+ verifyCommand: PUBLIC_VERIFY_COMMAND,
8857
+ actionClass: "manual_provider_step",
8858
+ approvalRequired: true,
8859
+ manualFallback: `Open ${step.openUrl ?? `https://${provider2}.com`} and complete: ${step.instruction}`,
8860
+ copyValues: []
8857
8861
  };
8858
8862
  } catch {
8859
8863
  return void 0;
@@ -9407,27 +9411,179 @@ function sanitizeArtifactForDisk(artifact) {
9407
9411
  return redactUnknown(artifact);
9408
9412
  }
9409
9413
 
9414
+ // src/version.ts
9415
+ var VERSION = "1.1.0";
9416
+
9417
+ // src/prp/buildPrp.ts
9418
+ var import_node_path8 = require("node:path");
9419
+
9420
+ // src/prp/types.ts
9421
+ var PRP_SCHEMA_URL = "https://schemas.viberaven.dev/prp/v0.1/schema.json";
9422
+ var PRP_PROTOCOL = "viberaven-production-protocol";
9423
+ var PRP_PROTOCOL_VERSION = "0.1.0";
9424
+
9425
+ // src/prp/buildPrp.ts
9426
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
9427
+ var REDACTED = "<redacted>";
9428
+ var SENSITIVE_JSON_KEY_PATTERN = /secret|token|api[_-]?key|apikey|password|private[_-]?key|database[_-]?url|connection[_-]?string|service[_-]?role|role[_-]?key/i;
9429
+ function buildProductionProtocolReport(options) {
9430
+ const profile = options.profile ?? "launch";
9431
+ const generatedAt = options.artifact.scannedAt;
9432
+ const expiresAt = new Date(new Date(generatedAt).getTime() + ONE_DAY_MS).toISOString();
9433
+ const evidence = buildEvidence(options.artifact);
9434
+ const nextActions = buildNextActions(options.tasks);
9435
+ const findings = buildFindings(options.artifact, nextActions);
9436
+ return {
9437
+ $schema: PRP_SCHEMA_URL,
9438
+ protocol: PRP_PROTOCOL,
9439
+ protocolVersion: PRP_PROTOCOL_VERSION,
9440
+ producer: {
9441
+ name: "viberaven",
9442
+ version: options.producerVersion
9443
+ },
9444
+ subject: {
9445
+ projectName: sanitizePrpText((0, import_node_path8.basename)(options.artifact.workspacePath) || "workspace"),
9446
+ framework: sanitizePrpText(options.artifact.archetype || "unknown"),
9447
+ packageManager: "unknown",
9448
+ deploymentTarget: sanitizePrpText(options.artifact.selectedProviders?.deployment ?? "unknown"),
9449
+ environment: "production"
9450
+ },
9451
+ profile,
9452
+ decision: {
9453
+ status: resolveDecisionStatus(options.artifact),
9454
+ generatedAt,
9455
+ expiresAt,
9456
+ summary: summarizeDecision(options.artifact)
9457
+ },
9458
+ findings,
9459
+ evidence,
9460
+ nextActions,
9461
+ agentInstructions: {
9462
+ mustRead: [".viberaven/prp.json", ".viberaven/mission-map.md", ".viberaven/context-map.json"],
9463
+ doNotDeployUntil: [
9464
+ "decision.status is not blocked",
9465
+ "critical nextActions are resolved or explicitly accepted"
9466
+ ]
9467
+ }
9468
+ };
9469
+ }
9470
+ function resolveDecisionStatus(artifact) {
9471
+ if (artifact.gaps.some((gap) => gap.severity === "critical")) return "blocked";
9472
+ if (artifact.gaps.some((gap) => gap.severity === "warning")) return "warning";
9473
+ return "clear";
9474
+ }
9475
+ function summarizeDecision(artifact) {
9476
+ const critical = artifact.gaps.filter((gap) => gap.severity === "critical").length;
9477
+ const warning = artifact.gaps.filter((gap) => gap.severity === "warning").length;
9478
+ if (critical > 0) return `${critical} production blocker${critical === 1 ? "" : "s"} found`;
9479
+ if (warning > 0) return `${warning} production warning${warning === 1 ? "" : "s"} found`;
9480
+ return "No production blockers found";
9481
+ }
9482
+ function buildEvidence(artifact) {
9483
+ return artifact.gaps.map((gap) => {
9484
+ const gapId = safePrpId(gap.id);
9485
+ return {
9486
+ id: `evidence.${gapId}.repo`,
9487
+ kind: "repo",
9488
+ status: evidenceStatusForGapSeverity(gap.severity),
9489
+ source: sanitizePrpText(String(gap.file ?? gap.primaryMapCategory ?? "repo")),
9490
+ summary: sanitizePrpText(gap.detail || gap.title || gap.id)
9491
+ };
9492
+ });
9493
+ }
9494
+ function evidenceStatusForGapSeverity(severity) {
9495
+ if (severity === "critical" || severity === "warning") return "missing";
9496
+ return "inconclusive";
9497
+ }
9498
+ function buildFindings(artifact, nextActions) {
9499
+ return artifact.gaps.map((gap) => {
9500
+ const gapId = safePrpId(gap.id);
9501
+ return {
9502
+ id: gapId,
9503
+ severity: gap.severity,
9504
+ category: sanitizePrpText(String(gap.primaryMapCategory ?? "unknown")),
9505
+ summary: sanitizePrpText(gap.title || gap.id),
9506
+ evidenceRefs: [`evidence.${gapId}.repo`],
9507
+ nextActionRefs: nextActions.some((action) => action.gapId === sanitizePrpText(gap.id)) ? [`action.${gapId}`] : []
9508
+ };
9509
+ });
9510
+ }
9511
+ function buildNextActions(tasks) {
9512
+ return tasks.map((task) => ({
9513
+ id: `action.${safePrpId(task.gapId)}`,
9514
+ title: sanitizePrpText(task.title),
9515
+ actionClass: actionClassForTask(task),
9516
+ requiresUserAction: task.requiresUserAction,
9517
+ approvalRequired: task.requiresUserAction,
9518
+ verifyCommand: sanitizePrpText(task.verifyCommand || PUBLIC_VERIFY_COMMAND),
9519
+ gapId: sanitizePrpText(task.gapId),
9520
+ provider: sanitizeOptionalPrpText(task.providerAction?.provider),
9521
+ dashboardUrl: sanitizeOptionalPrpText(task.providerAction?.dashboardUrl),
9522
+ manualFallback: sanitizeOptionalPrpText(task.providerAction?.exactStep ?? task.action),
9523
+ mcpTool: sanitizeOptionalPrpText(task.mcpTool),
9524
+ mcpArgs: sanitizePrpJsonObject(task.mcpArgs)
9525
+ }));
9526
+ }
9527
+ function actionClassForTask(task) {
9528
+ if (task.fixType === "repo-code") return "local_repo_write";
9529
+ if (task.fixType === "provider-action") return "manual_provider_step";
9530
+ if (task.fixType === "manual-verify") return "local_repo_read";
9531
+ return "manual_provider_step";
9532
+ }
9533
+ function safeId(value) {
9534
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "unknown";
9535
+ }
9536
+ function safePrpId(value) {
9537
+ return safeId(sanitizePrpText(value));
9538
+ }
9539
+ function sanitizeOptionalPrpText(value) {
9540
+ return value === void 0 ? void 0 : sanitizePrpText(value);
9541
+ }
9542
+ function sanitizePrpJsonObject(value) {
9543
+ return value === void 0 ? void 0 : sanitizePrpJsonValue(value);
9544
+ }
9545
+ function sanitizePrpJsonValue(value) {
9546
+ if (typeof value === "string") return sanitizePrpText(value);
9547
+ if (Array.isArray(value)) return value.map((item3) => sanitizePrpJsonValue(item3));
9548
+ if (value && typeof value === "object") {
9549
+ return Object.fromEntries(
9550
+ Object.entries(value).map(([key, item3]) => [
9551
+ sanitizePrpText(key),
9552
+ SENSITIVE_JSON_KEY_PATTERN.test(key) ? REDACTED : sanitizePrpJsonValue(item3)
9553
+ ])
9554
+ );
9555
+ }
9556
+ return value;
9557
+ }
9558
+ function sanitizePrpText(value) {
9559
+ return value.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, REDACTED).replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s/@]+:[^\s/@]+@[^\s,;)]+/gi, REDACTED).replace(/\b(?:postgres(?:ql)?|mongodb(?:\+srv)?|redis(?:s)?|mysql|mariadb):\/\/[^\s/@:]+:[^\s/@]+@[^\s,;)]+/gi, REDACTED).replace(/\b(?:redis(?:s)?):\/\/:[^\s/@]+@[^\s,;)]+/gi, REDACTED).replace(
9560
+ /\b([A-Za-z_][A-Za-z0-9_]*(?:SECRET|TOKEN|PASSWORD|PRIVATE[_-]?KEY|API[_-]?KEY|APIKEY|SERVICE[_-]?ROLE|DATABASE[_-]?URL|CONNECTION[_-]?STRING)[A-Za-z0-9_]*)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,
9561
+ `$1=${REDACTED}`
9562
+ ).replace(/\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/gi, `Bearer ${REDACTED}`).replace(/(^|[^A-Za-z0-9])whsec_[A-Za-z0-9_]+/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])sk_(live|test)_[A-Za-z0-9_]+/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])pk_(live|test)_[A-Za-z0-9_]+/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{8,}/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])gh[oprsu]_[A-Za-z0-9_]{16,}/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])github_pat_[A-Za-z0-9_]{16,}/g, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9])(sb|supabase|vercel|stripe)_[A-Za-z0-9_]*\d[A-Za-z0-9_]{15,}/gi, `$1${REDACTED}`).replace(/(^|[^A-Za-z0-9_-])[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}(?=$|[^A-Za-z0-9_-])/g, `$1${REDACTED}`).replace(/\b[A-Za-z0-9+/]{32,}={0,2}\b/g, REDACTED);
9563
+ }
9564
+
9410
9565
  // src/artifacts.ts
9411
9566
  async function copyReportAssets(reportAssetsDir) {
9412
9567
  const sourceDir = getBundledReportAssetsDir();
9413
- await (0, import_promises5.mkdir)((0, import_node_path8.join)(reportAssetsDir, "assets"), { recursive: true });
9568
+ await (0, import_promises5.mkdir)((0, import_node_path9.join)(reportAssetsDir, "assets"), { recursive: true });
9414
9569
  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));
9570
+ await (0, import_promises5.copyFile)((0, import_node_path9.join)(sourceDir, rel), (0, import_node_path9.join)(reportAssetsDir, rel));
9416
9571
  }
9417
9572
  }
9418
9573
  async function writeScanArtifacts(options) {
9419
9574
  const cwd = options.cwd ?? options.artifact.workspacePath;
9420
9575
  const dir = getProjectArtifactsDir(cwd);
9421
9576
  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");
9577
+ const jsonPath = (0, import_node_path9.join)(dir, "last-scan.json");
9578
+ const gateResultPath = (0, import_node_path9.join)(dir, "gate-result.json");
9579
+ const contextMapPath = (0, import_node_path9.join)(dir, "context-map.json");
9580
+ const gapsDir = (0, import_node_path9.join)(dir, "gaps");
9581
+ const prpPath = (0, import_node_path9.join)(dir, "prp.json");
9582
+ const tasklistPath = (0, import_node_path9.join)(dir, "agent-tasklist.md");
9583
+ const summaryPath = (0, import_node_path9.join)(dir, "agent-summary.md");
9584
+ const playbookPath = (0, import_node_path9.join)(dir, "launch-playbook.md");
9585
+ const reportPath = (0, import_node_path9.join)(dir, "report.html");
9586
+ const reportAssetsDir = (0, import_node_path9.join)(dir, "report");
9431
9587
  await (0, import_promises5.mkdir)(gapsDir, { recursive: true });
9432
9588
  const safe = sanitizeArtifactForDisk(options.artifact);
9433
9589
  const json = `${JSON.stringify(safe, null, 2)}
@@ -9437,6 +9593,12 @@ async function writeScanArtifacts(options) {
9437
9593
  const html = generateReportHtml(safe);
9438
9594
  const tasks = buildTaskList(safe);
9439
9595
  const tasklist = buildTaskListMarkdown(tasks);
9596
+ const prp = `${JSON.stringify(buildProductionProtocolReport({
9597
+ artifact: safe,
9598
+ tasks,
9599
+ producerVersion: VERSION
9600
+ }), null, 2)}
9601
+ `;
9440
9602
  const gateResult = `${JSON.stringify(generateGateResult(safe), null, 2)}
9441
9603
  `;
9442
9604
  const contextMap = `${JSON.stringify(generateContextMap(safe), null, 2)}
@@ -9446,9 +9608,10 @@ async function writeScanArtifacts(options) {
9446
9608
  await (0, import_promises5.writeFile)(gateResultPath, gateResult, "utf-8");
9447
9609
  await (0, import_promises5.writeFile)(contextMapPath, contextMap, "utf-8");
9448
9610
  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)}
9611
+ await (0, import_promises5.writeFile)((0, import_node_path9.join)(dir, "gaps", `${gap.content.id}.json`), `${JSON.stringify(gap.content, null, 2)}
9450
9612
  `, "utf-8");
9451
9613
  }
9614
+ await (0, import_promises5.writeFile)(prpPath, prp, "utf-8");
9452
9615
  await (0, import_promises5.writeFile)(tasklistPath, tasklist, "utf-8");
9453
9616
  await (0, import_promises5.writeFile)(jsonPath, json, "utf-8");
9454
9617
  await (0, import_promises5.writeFile)(summaryPath, summary, "utf-8");
@@ -9460,6 +9623,7 @@ async function writeScanArtifacts(options) {
9460
9623
  gateResultPath,
9461
9624
  contextMapPath,
9462
9625
  gapsDir,
9626
+ prpPath,
9463
9627
  tasklistPath,
9464
9628
  summaryPath,
9465
9629
  playbookPath,
@@ -9495,6 +9659,28 @@ function renderJsonlEvents(result) {
9495
9659
  `;
9496
9660
  }
9497
9661
 
9662
+ // src/output/prpSummary.ts
9663
+ function renderProductionProtocolSummary(prp) {
9664
+ const nextAction = prp.nextActions[0];
9665
+ const lines = [
9666
+ "",
9667
+ "VibeRaven Production Protocol",
9668
+ "",
9669
+ `Profile: ${prp.profile}`,
9670
+ `Decision: ${prp.decision.status.toUpperCase()}`,
9671
+ "Canonical artifact: .viberaven/prp.json",
9672
+ ""
9673
+ ];
9674
+ if (nextAction) {
9675
+ lines.push("Next action:", nextAction.title, "");
9676
+ lines.push("Why:", prp.decision.summary);
9677
+ } else {
9678
+ lines.push("Next action:", "No production blockers found.", "");
9679
+ lines.push("Why:", prp.decision.summary);
9680
+ }
9681
+ return lines.join("\n");
9682
+ }
9683
+
9498
9684
  // src/commands/strictGate.ts
9499
9685
  function exitCodeForStrictGate(result, options = {}) {
9500
9686
  if (result.gate.status === "error") return 2;
@@ -9705,7 +9891,7 @@ function printScanSummary(artifact, paths) {
9705
9891
 
9706
9892
  // src/runnerConnect.ts
9707
9893
  var import_promises6 = require("node:fs/promises");
9708
- var import_node_path9 = require("node:path");
9894
+ var import_node_path10 = require("node:path");
9709
9895
  var import_node_child_process3 = require("node:child_process");
9710
9896
  var import_node_crypto = require("node:crypto");
9711
9897
 
@@ -9800,11 +9986,11 @@ function validateSafeFixRelativePath(path) {
9800
9986
  if (segments.some((segment) => segment === ".git" || segment === "node_modules")) {
9801
9987
  return { ok: false, reason: "Safe fix path targets a blocked directory." };
9802
9988
  }
9803
- const basename3 = segments.at(-1)?.toLowerCase() ?? "";
9804
- if (basename3 !== ".env.example" && (basename3 === ".env" || basename3.startsWith(".env."))) {
9989
+ const basename4 = segments.at(-1)?.toLowerCase() ?? "";
9990
+ if (basename4 !== ".env.example" && (basename4 === ".env" || basename4.startsWith(".env."))) {
9805
9991
  return { ok: false, reason: "Safe fix path targets an environment secret file." };
9806
9992
  }
9807
- if (isSecretLikeFilename(basename3)) {
9993
+ if (isSecretLikeFilename(basename4)) {
9808
9994
  return { ok: false, reason: "Safe fix path targets a secret-like file." };
9809
9995
  }
9810
9996
  if (!isAllowedSafeFixPath(normalized)) {
@@ -10053,7 +10239,7 @@ async function createSafeFixFile(job, input, targetPath) {
10053
10239
  } catch {
10054
10240
  }
10055
10241
  try {
10056
- await (0, import_promises6.mkdir)((0, import_node_path9.dirname)(targetPath), { recursive: true });
10242
+ await (0, import_promises6.mkdir)((0, import_node_path10.dirname)(targetPath), { recursive: true });
10057
10243
  await writeNewFileAtomically(targetPath, input.content);
10058
10244
  } catch {
10059
10245
  return safeFixNeedsUser(job, "SAFE_FIX_WRITE_FAILED", `Could not create ${input.path}.`);
@@ -10121,12 +10307,12 @@ function safeFixNeedsUser(job, code, message) {
10121
10307
  };
10122
10308
  }
10123
10309
  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);
10310
+ const root = await (0, import_promises6.realpath)(workspaceRoot).catch(() => (0, import_node_path10.resolve)(workspaceRoot));
10311
+ const target = (0, import_node_path10.resolve)(root, relativePath);
10126
10312
  if (!isInsideRoot(root, target)) {
10127
10313
  return { ok: false, reason: "Safe fix target escaped the workspace root." };
10128
10314
  }
10129
- const parent = (0, import_node_path9.dirname)(target);
10315
+ const parent = (0, import_node_path10.dirname)(target);
10130
10316
  const parentReal = await realpathNearestExisting(parent, root);
10131
10317
  if (!isInsideRoot(root, parentReal)) {
10132
10318
  return { ok: false, reason: "Safe fix parent path escaped the workspace root." };
@@ -10144,7 +10330,7 @@ async function realpathNearestExisting(path, root) {
10144
10330
  await (0, import_promises6.lstat)(candidate);
10145
10331
  return (0, import_promises6.realpath)(candidate);
10146
10332
  } catch {
10147
- const next = (0, import_node_path9.dirname)(candidate);
10333
+ const next = (0, import_node_path10.dirname)(candidate);
10148
10334
  if (next === candidate) {
10149
10335
  break;
10150
10336
  }
@@ -10154,8 +10340,8 @@ async function realpathNearestExisting(path, root) {
10154
10340
  return root;
10155
10341
  }
10156
10342
  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);
10343
+ const rel = (0, import_node_path10.relative)(root, candidate);
10344
+ return rel === "" || !rel.startsWith("..") && !(0, import_node_path10.isAbsolute)(rel);
10159
10345
  }
10160
10346
  async function writeNewFileAtomically(targetPath, content) {
10161
10347
  const tempPath = tempPathFor(targetPath);
@@ -10176,7 +10362,7 @@ async function replaceFileAtomically(targetPath, content) {
10176
10362
  }
10177
10363
  }
10178
10364
  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`);
10365
+ return (0, import_node_path10.join)((0, import_node_path10.dirname)(targetPath), `.${(0, import_node_path10.basename)(targetPath)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
10180
10366
  }
10181
10367
  async function executePackageScriptJob(job, scriptName, options) {
10182
10368
  const packageJson = await readPackageJson(options.workspaceRoot);
@@ -10350,7 +10536,7 @@ function proofItemForJob(job, kind, label, summary, evidence, redactionSecrets =
10350
10536
  }
10351
10537
  async function readPackageJson(workspaceRoot) {
10352
10538
  try {
10353
- const raw = await (0, import_promises6.readFile)((0, import_node_path9.join)(workspaceRoot, "package.json"), "utf-8");
10539
+ const raw = await (0, import_promises6.readFile)((0, import_node_path10.join)(workspaceRoot, "package.json"), "utf-8");
10354
10540
  const parsed = JSON.parse(raw);
10355
10541
  if (isRecord6(parsed) && isRecord6(parsed.scripts)) {
10356
10542
  return { scripts: Object.fromEntries(Object.entries(parsed.scripts).filter(([, value]) => typeof value === "string")) };
@@ -10433,7 +10619,7 @@ async function collectLocalRepoMetadata(workspaceRoot, commandRunner = runComman
10433
10619
  const headSha = headResult.ok ? normalizeSha(headResult.stdout) : null;
10434
10620
  const dirty = statusResult.ok ? statusResult.stdout.trim().length > 0 : void 0;
10435
10621
  return {
10436
- rootName: (0, import_node_path9.basename)(workspaceRoot) || "workspace",
10622
+ rootName: (0, import_node_path10.basename)(workspaceRoot) || "workspace",
10437
10623
  remotes: remoteResult.ok ? parseGitRemotes(remoteResult.stdout) : [],
10438
10624
  branch,
10439
10625
  headSha,
@@ -10451,7 +10637,7 @@ async function detectPackageManager(workspaceRoot) {
10451
10637
  ];
10452
10638
  for (const [manager, file] of checks) {
10453
10639
  try {
10454
- await (0, import_promises6.access)((0, import_node_path9.join)(workspaceRoot, file));
10640
+ await (0, import_promises6.access)((0, import_node_path10.join)(workspaceRoot, file));
10455
10641
  return manager;
10456
10642
  } catch {
10457
10643
  }
@@ -10642,9 +10828,9 @@ function isRecord6(value) {
10642
10828
  }
10643
10829
 
10644
10830
  // src/tui/runInteractive.ts
10645
- var import_node_path14 = require("node:path");
10831
+ var import_node_path15 = require("node:path");
10646
10832
 
10647
- // ../../node_modules/@clack/core/dist/index.mjs
10833
+ // ../../../../node_modules/@clack/core/dist/index.mjs
10648
10834
  var import_sisteransi = __toESM(require_src(), 1);
10649
10835
  var import_node_process = require("node:process");
10650
10836
  var g = __toESM(require("node:readline"), 1);
@@ -11002,7 +11188,7 @@ var LD = class extends x {
11002
11188
  }
11003
11189
  };
11004
11190
 
11005
- // ../../node_modules/@clack/prompts/dist/index.mjs
11191
+ // ../../../../node_modules/@clack/prompts/dist/index.mjs
11006
11192
  var import_node_process2 = __toESM(require("node:process"), 1);
11007
11193
  var import_picocolors2 = __toESM(require_picocolors(), 1);
11008
11194
  var import_sisteransi2 = __toESM(require_src(), 1);
@@ -11228,9 +11414,6 @@ function buildAgentFixPrompt(artifact, gap) {
11228
11414
  ].join("\n");
11229
11415
  }
11230
11416
 
11231
- // src/version.ts
11232
- var VERSION = "1.0.5";
11233
-
11234
11417
  // src/commands/guide.ts
11235
11418
  var import_picocolors3 = __toESM(require_picocolors());
11236
11419
  function formatPasteTarget(step) {
@@ -11299,7 +11482,7 @@ async function runGuideCommand(options) {
11299
11482
 
11300
11483
  // src/commands/audit.ts
11301
11484
  var import_promises7 = require("node:fs/promises");
11302
- var import_node_path10 = require("node:path");
11485
+ var import_node_path11 = require("node:path");
11303
11486
  var ENV_FILES = [
11304
11487
  ".env",
11305
11488
  ".env.local",
@@ -11399,7 +11582,7 @@ function buildVercelSupabaseAudit(input) {
11399
11582
  }
11400
11583
  async function readIfExists(projectRoot, relativePath) {
11401
11584
  try {
11402
- const absolutePath = (0, import_node_path10.join)(projectRoot, relativePath);
11585
+ const absolutePath = (0, import_node_path11.join)(projectRoot, relativePath);
11403
11586
  const fileStat = await (0, import_promises7.stat)(absolutePath);
11404
11587
  if (!fileStat.isFile()) {
11405
11588
  return void 0;
@@ -11413,7 +11596,7 @@ async function readIfExists(projectRoot, relativePath) {
11413
11596
  }
11414
11597
  }
11415
11598
  async function collectSqlFiles(projectRoot, root) {
11416
- const base = (0, import_node_path10.join)(projectRoot, root);
11599
+ const base = (0, import_node_path11.join)(projectRoot, root);
11417
11600
  try {
11418
11601
  const rootStat = await (0, import_promises7.stat)(base);
11419
11602
  if (!rootStat.isDirectory()) {
@@ -11433,17 +11616,17 @@ async function collectSqlFiles(projectRoot, root) {
11433
11616
  for (const entry of entries) {
11434
11617
  if (entry.isDirectory()) {
11435
11618
  if (!SKIP_DIRS.has(entry.name)) {
11436
- await visit((0, import_node_path10.join)(dir, entry.name));
11619
+ await visit((0, import_node_path11.join)(dir, entry.name));
11437
11620
  }
11438
11621
  continue;
11439
11622
  }
11440
11623
  if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".sql")) {
11441
11624
  continue;
11442
11625
  }
11443
- const absolutePath = (0, import_node_path10.join)(dir, entry.name);
11626
+ const absolutePath = (0, import_node_path11.join)(dir, entry.name);
11444
11627
  try {
11445
11628
  files.push({
11446
- path: (0, import_node_path10.relative)(projectRoot, absolutePath).replace(/\\/g, "/"),
11629
+ path: (0, import_node_path11.relative)(projectRoot, absolutePath).replace(/\\/g, "/"),
11447
11630
  content: await (0, import_promises7.readFile)(absolutePath, "utf8")
11448
11631
  });
11449
11632
  } catch {
@@ -11493,7 +11676,7 @@ function renderVercelSupabaseAudit(result) {
11493
11676
 
11494
11677
  // src/commands/initRules.ts
11495
11678
  var import_promises10 = require("node:fs/promises");
11496
- var import_node_path13 = require("node:path");
11679
+ var import_node_path14 = require("node:path");
11497
11680
 
11498
11681
  // src/commands/agentRulesBlock.ts
11499
11682
  var VIBERAVEN_BLOCK_START = "<!-- VIBERAVEN:START -->";
@@ -11515,6 +11698,15 @@ Maps repo evidence to OWASP LLM Top 10 launch risks. Supports SAFECode-style dep
11515
11698
  var STACK_FRAMING = `Stack context for this repo: Next.js, Supabase, Vercel, VibeRaven.
11516
11699
  Do NOT deploy to Vercel or ship to production users without running \`${PUBLIC_AGENT_MODE_COMMAND}\`.
11517
11700
  Do NOT rely on manual production checklists when VibeRaven gate artifacts exist in \`.viberaven/\`.`;
11701
+ var PRODUCTION_PROTOCOL_RULES = `## VibeRaven Production Protocol
11702
+
11703
+ Before making deploy, auth, database, payment, API, or scaling changes:
11704
+
11705
+ 1. Read \`.viberaven/prp.json\`.
11706
+ 2. Follow \`.viberaven/mission-map.md\`.
11707
+ 3. Do not deploy if \`decision.status\` is \`blocked\`.
11708
+ 4. Fix \`nextActions\` in order.
11709
+ 5. Re-run \`${PUBLIC_AGENT_MODE_COMMAND}\`.`;
11518
11710
  var AGENT_NEGATIVE_CONSTRAINTS = `## Event-Triggered Production Verification
11519
11711
 
11520
11712
  Trigger: modifications to \`package.json\`, \`vercel.json\`, \`supabase/migrations/**/*\`, \`.env.example\`, auth/billing/webhook paths, or deploy workflow files.
@@ -11540,6 +11732,8 @@ var AGENT_RULES_BODY = `${AGENT_RULES_PREAMBLE}
11540
11732
 
11541
11733
  ${STACK_FRAMING}
11542
11734
 
11735
+ ${PRODUCTION_PROTOCOL_RULES}
11736
+
11543
11737
  ${AGENT_NEGATIVE_CONSTRAINTS}
11544
11738
 
11545
11739
  ## VibeRaven Production-Readiness Gate
@@ -11589,10 +11783,11 @@ var AGENT_CONTEXT_BODY = `${AGENT_RULES_PREAMBLE}
11589
11783
 
11590
11784
  After \`--agent-mode\`, read these artifacts in order:
11591
11785
 
11592
- 1. \`.viberaven/mission-map.md\`
11593
- 2. \`.viberaven/agent-tasklist.md\`
11594
- 3. \`.viberaven/gate-result.json\`
11595
- 4. \`.viberaven/context-map.json\``;
11786
+ 1. \`.viberaven/prp.json\`
11787
+ 2. \`.viberaven/mission-map.md\`
11788
+ 3. \`.viberaven/agent-tasklist.md\`
11789
+ 4. \`.viberaven/gate-result.json\`
11790
+ 5. \`.viberaven/context-map.json\``;
11596
11791
  var MISSION_MAP_BODY = `${AGENT_RULES_PREAMBLE}
11597
11792
 
11598
11793
  ## Mission Map loop
@@ -11731,7 +11926,7 @@ function escapeRegExp3(value) {
11731
11926
 
11732
11927
  // src/commands/cursorRulesPack.ts
11733
11928
  var import_promises8 = require("node:fs/promises");
11734
- var import_node_path11 = require("node:path");
11929
+ var import_node_path12 = require("node:path");
11735
11930
  var CURSOR_RULES_DIR = ".cursor/rules";
11736
11931
  var LEGACY_CURSOR_RULE_FILE = `${CURSOR_RULES_DIR}/viberaven.mdc`;
11737
11932
  var DOMAIN_PATH_POINTER = "Before editing these files, read `.viberaven/agent-context.md` and `.viberaven/mission-map.md`.";
@@ -11815,17 +12010,17 @@ async function initCursorRulesPack(options) {
11815
12010
  const pack = buildCursorRulesPack();
11816
12011
  for (const rule of pack) {
11817
12012
  const file = `${CURSOR_RULES_DIR}/${rule.filename}`;
11818
- const path = (0, import_node_path11.join)(options.cwd, file);
12013
+ const path = (0, import_node_path12.join)(options.cwd, file);
11819
12014
  const existing = await readExistingFile(path);
11820
12015
  const changed = !existing.exists || existing.content !== rule.content;
11821
12016
  const action = !existing.exists ? "created" : changed ? "updated" : "unchanged";
11822
12017
  if (!options.dryRun && changed) {
11823
- await (0, import_promises8.mkdir)((0, import_node_path11.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
12018
+ await (0, import_promises8.mkdir)((0, import_node_path12.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
11824
12019
  await (0, import_promises8.writeFile)(path, rule.content, "utf-8");
11825
12020
  }
11826
12021
  results.push({ target: "cursor", file, path, action });
11827
12022
  }
11828
- const legacyPath = (0, import_node_path11.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
12023
+ const legacyPath = (0, import_node_path12.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
11829
12024
  if (!options.dryRun && await fileExists(legacyPath)) {
11830
12025
  await (0, import_promises8.rm)(legacyPath, { force: true });
11831
12026
  }
@@ -11938,14 +12133,14 @@ function getAgentRulesTargets(value) {
11938
12133
  // src/commands/seedPackageJsonScripts.ts
11939
12134
  var import_node_fs7 = require("node:fs");
11940
12135
  var import_promises9 = require("node:fs/promises");
11941
- var import_node_path12 = require("node:path");
12136
+ var import_node_path13 = require("node:path");
11942
12137
  var VIBERAVEN_PACKAGE_JSON_SCRIPTS = {
11943
12138
  "viberaven:gate": PUBLIC_AGENT_MODE_COMMAND,
11944
12139
  "viberaven:verify": PUBLIC_VERIFY_COMMAND,
11945
12140
  "viberaven:strict": PUBLIC_STRICT_COMMAND
11946
12141
  };
11947
12142
  async function seedPackageJsonScripts(options) {
11948
- const packageJsonPath = (0, import_node_path12.join)(options.cwd, "package.json");
12143
+ const packageJsonPath = (0, import_node_path13.join)(options.cwd, "package.json");
11949
12144
  if (!(0, import_node_fs7.existsSync)(packageJsonPath)) {
11950
12145
  return null;
11951
12146
  }
@@ -11994,12 +12189,12 @@ async function initAgentRules(options) {
11994
12189
  continue;
11995
12190
  }
11996
12191
  const file = AGENT_RULE_TARGETS[target].file;
11997
- const path = (0, import_node_path13.join)(options.cwd, file);
12192
+ const path = (0, import_node_path14.join)(options.cwd, file);
11998
12193
  const existing = await readExistingFile2(path);
11999
12194
  const injected = injectAgentRulesBlock(existing.content, renderAgentRulesForTarget(target));
12000
12195
  const action = !existing.exists ? "created" : injected.changed ? "updated" : "unchanged";
12001
12196
  if (!options.dryRun && injected.changed) {
12002
- await (0, import_promises10.mkdir)((0, import_node_path13.dirname)(path), { recursive: true });
12197
+ await (0, import_promises10.mkdir)((0, import_node_path14.dirname)(path), { recursive: true });
12003
12198
  await (0, import_promises10.writeFile)(path, injected.content, "utf-8");
12004
12199
  }
12005
12200
  results.push({ target, file, path, action });
@@ -12376,7 +12571,7 @@ async function runInteractiveSession(startDir = process.cwd()) {
12376
12571
  Ie(`${import_picocolors4.default.bold("VibeRaven")} ${import_picocolors4.default.dim(VERSION)}`);
12377
12572
  const cwd = await resolveWorkspaceRoot(startDir);
12378
12573
  const artifactsAt = await findArtifactsWorkspace(startDir);
12379
- if (artifactsAt && (0, import_node_path14.resolve)(artifactsAt) !== (0, import_node_path14.resolve)(startDir)) {
12574
+ if (artifactsAt && (0, import_node_path15.resolve)(artifactsAt) !== (0, import_node_path15.resolve)(startDir)) {
12380
12575
  M2.message(import_picocolors4.default.dim(`Using scan from: ${artifactsAt}`));
12381
12576
  } else {
12382
12577
  M2.message(import_picocolors4.default.dim(`Project folder: ${cwd}`));
@@ -12444,11 +12639,11 @@ async function runInteractiveSession(startDir = process.cwd()) {
12444
12639
 
12445
12640
  // src/commands/condense.ts
12446
12641
  var import_promises11 = require("node:fs/promises");
12447
- var import_node_path15 = require("node:path");
12642
+ var import_node_path16 = require("node:path");
12448
12643
  async function runCondenseCommand(options) {
12449
12644
  const dir = getProjectArtifactsDir(options.cwd);
12450
- const artifact = JSON.parse(await (0, import_promises11.readFile)((0, import_node_path15.join)(dir, "last-scan.json"), "utf8"));
12451
- const contextMapPath = (0, import_node_path15.join)(dir, "context-map.json");
12645
+ const artifact = JSON.parse(await (0, import_promises11.readFile)((0, import_node_path16.join)(dir, "last-scan.json"), "utf8"));
12646
+ const contextMapPath = (0, import_node_path16.join)(dir, "context-map.json");
12452
12647
  await (0, import_promises11.writeFile)(contextMapPath, `${JSON.stringify(generateContextMap(artifact), null, 2)}
12453
12648
  `, "utf8");
12454
12649
  return { contextMapPath };
@@ -12457,15 +12652,15 @@ async function runCondenseCommand(options) {
12457
12652
  // src/heal/apply.ts
12458
12653
  var import_promises13 = require("node:fs/promises");
12459
12654
  var import_node_fs10 = require("node:fs");
12460
- var import_node_path19 = require("node:path");
12655
+ var import_node_path20 = require("node:path");
12461
12656
 
12462
12657
  // src/heal/pathSafety.ts
12463
- var import_node_path16 = require("node:path");
12658
+ var import_node_path17 = require("node:path");
12464
12659
  var BLOCKED_SEGMENTS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", ".viberaven"]);
12465
12660
  function assertSafeHealTarget(cwd, target) {
12466
- const root = (0, import_node_path16.resolve)(cwd);
12467
- const absolute = (0, import_node_path16.resolve)(root, target);
12468
- const rel = (0, import_node_path16.relative)(root, absolute);
12661
+ const root = (0, import_node_path17.resolve)(cwd);
12662
+ const absolute = (0, import_node_path17.resolve)(root, target);
12663
+ const rel = (0, import_node_path17.relative)(root, absolute);
12469
12664
  if (rel.startsWith("..") || rel === "" || /^[A-Za-z]:/.test(rel)) {
12470
12665
  throw new Error("Heal target must stay inside the workspace");
12471
12666
  }
@@ -12490,7 +12685,7 @@ function applyEmptyCatchRecipe(source) {
12490
12685
  // src/heal/recipes/index.ts
12491
12686
  var import_node_fs9 = require("node:fs");
12492
12687
  var import_promises12 = require("node:fs/promises");
12493
- var import_node_path18 = require("node:path");
12688
+ var import_node_path19 = require("node:path");
12494
12689
 
12495
12690
  // src/heal/recipes/envAuthSecret.ts
12496
12691
  function applyAuthSecretRecipe(source) {
@@ -12872,7 +13067,7 @@ function applyRateLimitRecipe(source, hasUpstash) {
12872
13067
 
12873
13068
  // src/heal/recipes/eslintRestrictedImports.ts
12874
13069
  var import_node_fs8 = require("node:fs");
12875
- var import_node_path17 = require("node:path");
13070
+ var import_node_path18 = require("node:path");
12876
13071
  var VIBERAVEN_ESLINT_MARKER = "VibeRaven heal: eslint_restricted_imports";
12877
13072
  var RESTRICTED_IMPORTS_MESSAGE = `Restricted import. Run ${PUBLIC_AGENT_MODE_COMMAND} before substituting packages.`;
12878
13073
  var RESTRICTED_PATHS = [
@@ -12902,7 +13097,7 @@ var ESLINT_CONFIG_CANDIDATES = [
12902
13097
  ];
12903
13098
  function detectEslintConfigFile(cwd) {
12904
13099
  for (const candidate of ESLINT_CONFIG_CANDIDATES) {
12905
- if ((0, import_node_fs8.existsSync)((0, import_node_path17.join)(cwd, candidate))) {
13100
+ if ((0, import_node_fs8.existsSync)((0, import_node_path18.join)(cwd, candidate))) {
12906
13101
  return candidate;
12907
13102
  }
12908
13103
  }
@@ -13082,7 +13277,7 @@ async function readSourceOrEmpty(absolutePath) {
13082
13277
  }
13083
13278
  async function detectUpstash(cwd) {
13084
13279
  try {
13085
- const pkgPath = (0, import_node_path18.join)(cwd, "package.json");
13280
+ const pkgPath = (0, import_node_path19.join)(cwd, "package.json");
13086
13281
  if (!(0, import_node_fs9.existsSync)(pkgPath)) return false;
13087
13282
  const raw = await (0, import_promises12.readFile)(pkgPath, "utf8");
13088
13283
  const pkg = JSON.parse(raw);
@@ -13099,7 +13294,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13099
13294
  const targetFile = explicitTarget ?? defaultTargetFile(gapId);
13100
13295
  if (targetFile === void 0) return null;
13101
13296
  if (gapId === "auth_secret_missing" || gapId === "node_env_not_set" || gapId === "database_url_missing") {
13102
- const absolutePath = (0, import_node_path18.join)(cwd, targetFile);
13297
+ const absolutePath = (0, import_node_path19.join)(cwd, targetFile);
13103
13298
  const source = await readSourceOrEmpty(absolutePath);
13104
13299
  let result;
13105
13300
  if (gapId === "auth_secret_missing") result = applyAuthSecretRecipe(source);
@@ -13113,25 +13308,25 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13113
13308
  };
13114
13309
  }
13115
13310
  if (gapId === "missing_error_boundary") {
13116
- const absolutePath = (0, import_node_path18.join)(cwd, "app/error.tsx");
13311
+ const absolutePath = (0, import_node_path19.join)(cwd, "app/error.tsx");
13117
13312
  const source = await readSourceOrEmpty(absolutePath);
13118
13313
  const result = applyErrorBoundaryRecipe(source);
13119
13314
  return { ...result, canAutoApply: true, recipeName: gapId };
13120
13315
  }
13121
13316
  if (gapId === "missing_health_route") {
13122
- const absolutePath = (0, import_node_path18.join)(cwd, "app/api/health/route.ts");
13317
+ const absolutePath = (0, import_node_path19.join)(cwd, "app/api/health/route.ts");
13123
13318
  const source = await readSourceOrEmpty(absolutePath);
13124
13319
  const result = applyHealthRouteRecipe(source);
13125
13320
  return { ...result, canAutoApply: true, recipeName: gapId };
13126
13321
  }
13127
13322
  if (gapId === "missing_loading_state") {
13128
- const absolutePath = (0, import_node_path18.join)(cwd, "app/loading.tsx");
13323
+ const absolutePath = (0, import_node_path19.join)(cwd, "app/loading.tsx");
13129
13324
  const source = await readSourceOrEmpty(absolutePath);
13130
13325
  const result = applyLoadingStateRecipe(source);
13131
13326
  return { ...result, canAutoApply: true, recipeName: gapId };
13132
13327
  }
13133
13328
  if (gapId === "missing_404_page") {
13134
- const absolutePath = (0, import_node_path18.join)(cwd, "app/not-found.tsx");
13329
+ const absolutePath = (0, import_node_path19.join)(cwd, "app/not-found.tsx");
13135
13330
  const source = await readSourceOrEmpty(absolutePath);
13136
13331
  const result = applyNotFoundRecipe(source);
13137
13332
  return { ...result, canAutoApply: true, recipeName: gapId };
@@ -13149,10 +13344,10 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13149
13344
  }
13150
13345
  if (gapId === "missing_csp_header") {
13151
13346
  let configFile = "next.config.js";
13152
- let absolutePath = (0, import_node_path18.join)(cwd, configFile);
13347
+ let absolutePath = (0, import_node_path19.join)(cwd, configFile);
13153
13348
  if (!(0, import_node_fs9.existsSync)(absolutePath)) {
13154
13349
  configFile = "next.config.mjs";
13155
- absolutePath = (0, import_node_path18.join)(cwd, configFile);
13350
+ absolutePath = (0, import_node_path19.join)(cwd, configFile);
13156
13351
  }
13157
13352
  const source = await readSourceOrEmpty(absolutePath);
13158
13353
  const result = applyCspHeaderRecipe(source);
@@ -13164,7 +13359,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13164
13359
  }
13165
13360
  if (gapId === "missing_rate_limit") {
13166
13361
  const hasUpstash = await detectUpstash(cwd);
13167
- const middlewarePath = (0, import_node_path18.join)(cwd, "middleware.ts");
13362
+ const middlewarePath = (0, import_node_path19.join)(cwd, "middleware.ts");
13168
13363
  const source = await readSourceOrEmpty(middlewarePath);
13169
13364
  const result = applyRateLimitRecipe(source, hasUpstash);
13170
13365
  return {
@@ -13186,7 +13381,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
13186
13381
  recipeName: gapId
13187
13382
  };
13188
13383
  }
13189
- const absolutePath = (0, import_node_path18.join)(cwd, configFile);
13384
+ const absolutePath = (0, import_node_path19.join)(cwd, configFile);
13190
13385
  const source = await readSourceOrEmpty(absolutePath);
13191
13386
  const result = applyEslintRestrictedImportsRecipe(source, configFile);
13192
13387
  return {
@@ -13261,13 +13456,13 @@ async function applyHeal(options) {
13261
13456
  rollback: { available: false, instructions: "Recipe matched but no change was needed (already applied or file already exists)." }
13262
13457
  };
13263
13458
  }
13264
- const absoluteTarget = (0, import_node_path19.join)(options.cwd, dispatched.targetFile);
13459
+ const absoluteTarget = (0, import_node_path20.join)(options.cwd, dispatched.targetFile);
13265
13460
  assertSafeHealTarget(options.cwd, dispatched.targetFile);
13266
- await (0, import_promises13.mkdir)((0, import_node_path19.dirname)(absoluteTarget), { recursive: true });
13267
- const healDir2 = (0, import_node_path19.join)(options.cwd, ".viberaven", "heal", id);
13268
- await (0, import_promises13.mkdir)((0, import_node_path19.join)(healDir2, "before"), { recursive: true });
13461
+ await (0, import_promises13.mkdir)((0, import_node_path20.dirname)(absoluteTarget), { recursive: true });
13462
+ const healDir2 = (0, import_node_path20.join)(options.cwd, ".viberaven", "heal", id);
13463
+ await (0, import_promises13.mkdir)((0, import_node_path20.join)(healDir2, "before"), { recursive: true });
13269
13464
  const beforeContent = (0, import_node_fs10.existsSync)(absoluteTarget) ? await (0, import_promises13.readFile)(absoluteTarget, "utf8") : "";
13270
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
13465
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
13271
13466
  await (0, import_promises13.writeFile)(absoluteTarget, dispatched.output, "utf8");
13272
13467
  const patch2 = [
13273
13468
  `--- ${dispatched.targetFile}`,
@@ -13278,7 +13473,7 @@ async function applyHeal(options) {
13278
13473
  dispatched.output,
13279
13474
  ""
13280
13475
  ].join("\n");
13281
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "patch.diff"), patch2, "utf8");
13476
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir2, "patch.diff"), patch2, "utf8");
13282
13477
  const result2 = {
13283
13478
  $schema: "https://viberaven.dev/schemas/heal-result.schema.json",
13284
13479
  schemaVersion: "v1",
@@ -13289,7 +13484,7 @@ async function applyHeal(options) {
13289
13484
  gapId: options.gapId,
13290
13485
  recipe: dispatched.recipeName,
13291
13486
  target: dispatched.targetFile,
13292
- changedFiles: [(0, import_node_path19.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
13487
+ changedFiles: [(0, import_node_path20.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
13293
13488
  artifacts: {
13294
13489
  patch: `.viberaven/heal/${id}/patch.diff`,
13295
13490
  result: `.viberaven/heal/${id}/result.json`
@@ -13299,7 +13494,7 @@ async function applyHeal(options) {
13299
13494
  instructions: "Restore .viberaven/heal/<healId>/before/target.txt to the target file or apply the reverse patch."
13300
13495
  }
13301
13496
  };
13302
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir2, "result.json"), `${JSON.stringify(result2, null, 2)}
13497
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir2, "result.json"), `${JSON.stringify(result2, null, 2)}
13303
13498
  `, "utf8");
13304
13499
  return result2;
13305
13500
  }
@@ -13336,9 +13531,9 @@ async function applyHeal(options) {
13336
13531
  rollback: { available: false, instructions: "No supported heal recipe matched this file." }
13337
13532
  };
13338
13533
  }
13339
- const healDir = (0, import_node_path19.join)(options.cwd, ".viberaven", "heal", id);
13340
- await (0, import_promises13.mkdir)((0, import_node_path19.join)(healDir, "before"), { recursive: true });
13341
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "before", "target.txt"), before, "utf8");
13534
+ const healDir = (0, import_node_path20.join)(options.cwd, ".viberaven", "heal", id);
13535
+ await (0, import_promises13.mkdir)((0, import_node_path20.join)(healDir, "before"), { recursive: true });
13536
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir, "before", "target.txt"), before, "utf8");
13342
13537
  await (0, import_promises13.writeFile)(absolute, recipe.output, "utf8");
13343
13538
  const patch = [
13344
13539
  `--- ${options.target}`,
@@ -13349,7 +13544,7 @@ async function applyHeal(options) {
13349
13544
  recipe.output,
13350
13545
  ""
13351
13546
  ].join("\n");
13352
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "patch.diff"), patch, "utf8");
13547
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir, "patch.diff"), patch, "utf8");
13353
13548
  const result = {
13354
13549
  $schema: "https://viberaven.dev/schemas/heal-result.schema.json",
13355
13550
  schemaVersion: "v1",
@@ -13360,7 +13555,7 @@ async function applyHeal(options) {
13360
13555
  gapId: options.gapId,
13361
13556
  recipe: "empty-catch-safe-response",
13362
13557
  target: options.target,
13363
- changedFiles: [(0, import_node_path19.relative)(options.cwd, absolute).replace(/\\/g, "/")],
13558
+ changedFiles: [(0, import_node_path20.relative)(options.cwd, absolute).replace(/\\/g, "/")],
13364
13559
  artifacts: {
13365
13560
  patch: `.viberaven/heal/${id}/patch.diff`,
13366
13561
  result: `.viberaven/heal/${id}/result.json`
@@ -13370,19 +13565,19 @@ async function applyHeal(options) {
13370
13565
  instructions: "Restore .viberaven/heal/<healId>/before/target.txt to the target file or apply the reverse patch."
13371
13566
  }
13372
13567
  };
13373
- await (0, import_promises13.writeFile)((0, import_node_path19.join)(healDir, "result.json"), `${JSON.stringify(result, null, 2)}
13568
+ await (0, import_promises13.writeFile)((0, import_node_path20.join)(healDir, "result.json"), `${JSON.stringify(result, null, 2)}
13374
13569
  `, "utf8");
13375
13570
  return result;
13376
13571
  }
13377
13572
 
13378
13573
  // src/heal/plan.ts
13379
13574
  var import_promises14 = require("node:fs/promises");
13380
- var import_node_path20 = require("node:path");
13575
+ var import_node_path21 = require("node:path");
13381
13576
  function healId2() {
13382
13577
  return `heal_${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 14)}`;
13383
13578
  }
13384
13579
  async function writeHealPlan(options) {
13385
- const dir = (0, import_node_path20.join)(options.cwd, ".viberaven");
13580
+ const dir = (0, import_node_path21.join)(options.cwd, ".viberaven");
13386
13581
  await (0, import_promises14.mkdir)(dir, { recursive: true });
13387
13582
  const id = healId2();
13388
13583
  const target = options.target ?? `gap:${options.gapId}`;
@@ -13410,20 +13605,20 @@ async function writeHealPlan(options) {
13410
13605
  artifacts: { plan: ".viberaven/heal-plan.md" },
13411
13606
  rollback: { available: false, instructions: "No source files were changed." }
13412
13607
  };
13413
- await (0, import_promises14.writeFile)((0, import_node_path20.join)(dir, "heal-plan.md"), markdown, "utf8");
13414
- await (0, import_promises14.writeFile)((0, import_node_path20.join)(dir, "heal-plan.json"), `${JSON.stringify(result, null, 2)}
13608
+ await (0, import_promises14.writeFile)((0, import_node_path21.join)(dir, "heal-plan.md"), markdown, "utf8");
13609
+ await (0, import_promises14.writeFile)((0, import_node_path21.join)(dir, "heal-plan.json"), `${JSON.stringify(result, null, 2)}
13415
13610
  `, "utf8");
13416
13611
  return result;
13417
13612
  }
13418
13613
 
13419
13614
  // src/heal/prompt.ts
13420
13615
  var import_promises15 = require("node:fs/promises");
13421
- var import_node_path21 = require("node:path");
13616
+ var import_node_path22 = require("node:path");
13422
13617
  function healId3() {
13423
13618
  return `heal_${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 14)}`;
13424
13619
  }
13425
13620
  async function writeHealPrompt(options) {
13426
- const dir = (0, import_node_path21.join)(options.cwd, ".viberaven");
13621
+ const dir = (0, import_node_path22.join)(options.cwd, ".viberaven");
13427
13622
  await (0, import_promises15.mkdir)(dir, { recursive: true });
13428
13623
  const id = healId3();
13429
13624
  const target = options.target ?? `gap:${options.gapId}`;
@@ -13451,7 +13646,7 @@ async function writeHealPrompt(options) {
13451
13646
  artifacts: { prompt: ".viberaven/heal-prompt.md" },
13452
13647
  rollback: { available: false, instructions: "No source files were changed." }
13453
13648
  };
13454
- await (0, import_promises15.writeFile)((0, import_node_path21.join)(dir, "heal-prompt.md"), prompt, "utf8");
13649
+ await (0, import_promises15.writeFile)((0, import_node_path22.join)(dir, "heal-prompt.md"), prompt, "utf8");
13455
13650
  return result;
13456
13651
  }
13457
13652
 
@@ -13538,7 +13733,7 @@ async function runHealCommand(options) {
13538
13733
  // src/stackRecommend.ts
13539
13734
  var import_promises17 = require("node:fs/promises");
13540
13735
  var import_node_fs11 = require("node:fs");
13541
- var import_node_path22 = require("node:path");
13736
+ var import_node_path23 = require("node:path");
13542
13737
  var DEFAULT_STACK = {
13543
13738
  frontend: "react",
13544
13739
  ui: "tailwind + shadcn/ui",
@@ -13549,7 +13744,7 @@ var DEFAULT_STACK = {
13549
13744
  reason: "Agent-default stack for lowest launch friction when repo signals are ambiguous"
13550
13745
  };
13551
13746
  async function recommendStack(cwd = process.cwd()) {
13552
- const pkgPath = (0, import_node_path22.join)(cwd, "package.json");
13747
+ const pkgPath = (0, import_node_path23.join)(cwd, "package.json");
13553
13748
  if (!(0, import_node_fs11.existsSync)(pkgPath)) {
13554
13749
  return DEFAULT_STACK;
13555
13750
  }
@@ -13606,7 +13801,7 @@ async function runInitCommand(options) {
13606
13801
 
13607
13802
  // src/commands/doctorAgents.ts
13608
13803
  var import_promises18 = require("node:fs/promises");
13609
- var import_node_path23 = require("node:path");
13804
+ var import_node_path24 = require("node:path");
13610
13805
  var REQUIRED_EXISTENCE_CHECKS = [
13611
13806
  { id: "agents-md", file: "AGENTS.md" },
13612
13807
  { id: "claude-md", file: "CLAUDE.md" },
@@ -13626,7 +13821,7 @@ var STALE_PATTERNS = [
13626
13821
  async function checkAgentInjection(cwd) {
13627
13822
  const checks = [];
13628
13823
  for (const item3 of REQUIRED_EXISTENCE_CHECKS) {
13629
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13824
+ const exists = await fileExists2((0, import_node_path24.join)(cwd, item3.file));
13630
13825
  checks.push({
13631
13826
  id: item3.id,
13632
13827
  status: exists ? "pass" : "fail",
@@ -13634,17 +13829,17 @@ async function checkAgentInjection(cwd) {
13634
13829
  });
13635
13830
  }
13636
13831
  for (const item3 of OPTIONAL_CURSOR_PACK_CHECKS) {
13637
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13832
+ const exists = await fileExists2((0, import_node_path24.join)(cwd, item3.file));
13638
13833
  checks.push({
13639
13834
  id: item3.id,
13640
13835
  status: exists ? "pass" : "fail",
13641
13836
  message: exists ? `${item3.file} exists` : `Missing ${item3.file} \u2014 run npx -y viberaven init --agents all`
13642
13837
  });
13643
13838
  }
13644
- const legacyCursorPath = (0, import_node_path23.join)(cwd, ".cursor/rules/viberaven.mdc");
13839
+ const legacyCursorPath = (0, import_node_path24.join)(cwd, ".cursor/rules/viberaven.mdc");
13645
13840
  if (await fileExists2(legacyCursorPath)) {
13646
13841
  const legacyContent = await (0, import_promises18.readFile)(legacyCursorPath, "utf-8");
13647
- const hasCoreSplit = await fileExists2((0, import_node_path23.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
13842
+ const hasCoreSplit = await fileExists2((0, import_node_path24.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
13648
13843
  if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
13649
13844
  checks.push({
13650
13845
  id: "cursor-legacy-mdc",
@@ -13655,7 +13850,7 @@ async function checkAgentInjection(cwd) {
13655
13850
  }
13656
13851
  for (const target of CORE_AGENT_INJECTION_TARGETS) {
13657
13852
  const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
13658
- const path = (0, import_node_path23.join)(cwd, file);
13853
+ const path = (0, import_node_path24.join)(cwd, file);
13659
13854
  const exists = await fileExists2(path);
13660
13855
  if (!exists) {
13661
13856
  checks.push({
@@ -14009,7 +14204,11 @@ function buildProviderActionBlock(task) {
14009
14204
  envKeyExample: pa.envKeyExample ?? null,
14010
14205
  doneSignal: pa.doneSignal,
14011
14206
  verifyCommand: task.verifyCommand,
14012
- mcpAlternative: task.mcpTool ?? pa.mcpAlternative ?? null
14207
+ mcpAlternative: task.mcpTool ?? pa.mcpAlternative ?? null,
14208
+ actionClass: pa.actionClass ?? "manual_provider_step",
14209
+ approvalRequired: pa.approvalRequired ?? true,
14210
+ manualFallback: pa.manualFallback ?? pa.exactStep,
14211
+ copyValues: pa.copyValues ?? []
14013
14212
  }
14014
14213
  };
14015
14214
  }
@@ -14033,7 +14232,7 @@ function printNextActionBlock(block) {
14033
14232
  // src/providerMcpBridge.ts
14034
14233
  var import_node_fs12 = require("node:fs");
14035
14234
  var import_node_os2 = require("node:os");
14036
- var import_node_path24 = require("node:path");
14235
+ var import_node_path25 = require("node:path");
14037
14236
  var UPGRADE_URL4 = "https://viberaven.dev/pricing";
14038
14237
  var FALLBACK_COMMAND = "npx -y viberaven audit --vercel-supabase --json";
14039
14238
  var SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["supabase", "vercel"]);
@@ -14041,9 +14240,9 @@ var configPathsOverride;
14041
14240
  function defaultMcpConfigPaths() {
14042
14241
  const home = (0, import_node_os2.homedir)();
14043
14242
  return [
14044
- (0, import_node_path24.join)(home, ".config", "claude", "claude_desktop_config.json"),
14045
- (0, import_node_path24.join)(home, ".cursor", "mcp.json"),
14046
- (0, import_node_path24.join)(home, ".gemini", "antigravity", "mcp_config.json")
14243
+ (0, import_node_path25.join)(home, ".config", "claude", "claude_desktop_config.json"),
14244
+ (0, import_node_path25.join)(home, ".cursor", "mcp.json"),
14245
+ (0, import_node_path25.join)(home, ".gemini", "antigravity", "mcp_config.json")
14047
14246
  ];
14048
14247
  }
14049
14248
  function resolveConfigPaths() {
@@ -14300,7 +14499,7 @@ async function guardEarlyVerifyScan(input) {
14300
14499
  if (!verifyLike) {
14301
14500
  return void 0;
14302
14501
  }
14303
- const workspacePath = input.positional[0] ? (0, import_node_path25.join)(process.cwd(), input.positional[0]) : await resolveWorkspaceRoot(process.cwd());
14502
+ const workspacePath = input.positional[0] ? (0, import_node_path26.join)(process.cwd(), input.positional[0]) : await resolveWorkspaceRoot(process.cwd());
14304
14503
  const loopState = await loadLoopState(workspacePath);
14305
14504
  if (loopState.batchApplied <= 0) {
14306
14505
  return void 0;
@@ -14376,7 +14575,7 @@ async function cmdStatus(flags, positional) {
14376
14575
  console.log("Not signed in. Run: viberaven login");
14377
14576
  return 1;
14378
14577
  }
14379
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
14578
+ const startDir = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd();
14380
14579
  let artifact;
14381
14580
  try {
14382
14581
  artifact = await loadLastArtifact(startDir);
@@ -14530,7 +14729,7 @@ async function cmdWatch(flags) {
14530
14729
  }
14531
14730
  }
14532
14731
  async function runScanCommand(flags, positional, options) {
14533
- const workspacePath = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
14732
+ const workspacePath = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
14534
14733
  const apiBaseUrl = resolveApiBaseUrl(typeof flags["api-url"] === "string" ? flags["api-url"] : void 0);
14535
14734
  let accessToken;
14536
14735
  try {
@@ -14583,6 +14782,10 @@ async function runScanCommand(flags, positional, options) {
14583
14782
  }
14584
14783
  if (!options?.deferMachineOutput) {
14585
14784
  printScanSummary(artifact, paths);
14785
+ if (flags["agent-mode"]) {
14786
+ const prp = JSON.parse(await (0, import_promises19.readFile)(paths.prpPath, "utf8"));
14787
+ console.log(renderProductionProtocolSummary(prp));
14788
+ }
14586
14789
  }
14587
14790
  if (artifact.usage && !options?.deferMachineOutput) {
14588
14791
  console.log(formatUsageLine(artifact.usage));
@@ -14608,7 +14811,7 @@ async function runScanCommand(flags, positional, options) {
14608
14811
  return { exitCode: 0, artifacts: paths };
14609
14812
  }
14610
14813
  async function cmdReport(flags, positional) {
14611
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
14814
+ const startDir = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd();
14612
14815
  try {
14613
14816
  const paths = await refreshReportFromDisk(startDir);
14614
14817
  console.log(`Report refreshed: ${paths.reportPath}`);
@@ -14630,7 +14833,7 @@ async function cmdReport(flags, positional) {
14630
14833
  }
14631
14834
  }
14632
14835
  async function cmdPrompt(flags, positional) {
14633
- const startDir = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
14836
+ const startDir = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd();
14634
14837
  let artifact;
14635
14838
  try {
14636
14839
  artifact = await loadLastArtifact(startDir);
@@ -14728,7 +14931,7 @@ async function main() {
14728
14931
  const wantsJsonl = hasFlag(flags, "jsonl");
14729
14932
  const wantsStrict = hasFlag(flags, "strict");
14730
14933
  if (flags.condense) {
14731
- const cwd = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
14934
+ const cwd = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd();
14732
14935
  const result = await runCondenseCommand({ cwd });
14733
14936
  console.log(`VibeRaven context map refreshed: ${result.contextMapPath}`);
14734
14937
  return 0;
@@ -14792,7 +14995,7 @@ async function main() {
14792
14995
  case "next":
14793
14996
  return runNextCommand({
14794
14997
  json: Boolean(flags.json),
14795
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd()
14998
+ cwd: positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd()
14796
14999
  });
14797
15000
  case "guide": {
14798
15001
  const provider2 = positional[0];
@@ -14830,7 +15033,7 @@ async function main() {
14830
15033
  case "provider-verify":
14831
15034
  return cmdProviderVerify(flags, positional);
14832
15035
  case "init": {
14833
- const cwd = positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd();
15036
+ const cwd = positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd();
14834
15037
  const agents = typeof flags.agents === "string" ? flags.agents : void 0;
14835
15038
  return runInitCommand({
14836
15039
  cwd,
@@ -14844,7 +15047,7 @@ async function main() {
14844
15047
  return 1;
14845
15048
  }
14846
15049
  return runDoctorAgentsCommand({
14847
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd()
15050
+ cwd: positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd()
14848
15051
  });
14849
15052
  case "validate-npm-package":
14850
15053
  return runValidateNpmPackageCommand({
@@ -14857,7 +15060,7 @@ async function main() {
14857
15060
  return 1;
14858
15061
  }
14859
15062
  return runAuditCommand({
14860
- cwd: positional[0] ? (0, import_node_path25.join)(process.cwd(), positional[0]) : process.cwd(),
15063
+ cwd: positional[0] ? (0, import_node_path26.join)(process.cwd(), positional[0]) : process.cwd(),
14861
15064
  json: Boolean(flags.json)
14862
15065
  });
14863
15066
  default: