@viberaven/cli 1.1.2 → 1.1.4

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
@@ -5342,7 +5342,7 @@ ${scan.files.map((file) => file.path).join("\n")}`.replace(/\\/g, "/").toLowerCa
5342
5342
  ];
5343
5343
  const passedCount = items.filter((entry) => entry.status === "passed").length;
5344
5344
  const totalCount = items.length;
5345
- const readinessPercent2 = Math.round(passedCount / Math.max(totalCount, 1) * 100);
5345
+ const readinessPercent = Math.round(passedCount / Math.max(totalCount, 1) * 100);
5346
5346
  return {
5347
5347
  key: "supabase-database",
5348
5348
  provider: "supabase",
@@ -5353,7 +5353,7 @@ ${scan.files.map((file) => file.path).join("\n")}`.replace(/\\/g, "/").toLowerCa
5353
5353
  items,
5354
5354
  passedCount,
5355
5355
  totalCount,
5356
- readinessPercent: readinessPercent2
5356
+ readinessPercent
5357
5357
  };
5358
5358
  }
5359
5359
  function visibleFiles2(scan) {
@@ -8493,7 +8493,7 @@ function needsScanMessage(startDir) {
8493
8493
  return [
8494
8494
  "No CLI scan found for this folder.",
8495
8495
  `Looking from: ${cwd}`,
8496
- 'Choose "Scan project", or run the menu from your repo root (where .viberaven/ lives).',
8496
+ 'Choose "Make this app production ready", or run the menu from your repo root (where .viberaven/ lives).',
8497
8497
  "VS Code extension scans stay inside the editor \u2014 run a CLI scan once to create .viberaven/ on disk."
8498
8498
  ].join("\n");
8499
8499
  }
@@ -11454,7 +11454,7 @@ function buildAgentFixPrompt(artifact, gap2) {
11454
11454
  }
11455
11455
 
11456
11456
  // src/version.ts
11457
- var VERSION = "1.1.2";
11457
+ var VERSION = "1.1.4";
11458
11458
 
11459
11459
  // src/commands/guide.ts
11460
11460
  var import_picocolors3 = __toESM(require_picocolors());
@@ -11770,7 +11770,7 @@ ${AGENT_NEGATIVE_CONSTRAINTS}
11770
11770
  ## VibeRaven Production-Readiness Gate
11771
11771
 
11772
11772
  - Before running build, compile, cleanup, deployment, vercel, or supabase commands, run \`${PUBLIC_AGENT_MODE_COMMAND}\` first from the project root.
11773
- - Treat VibeRaven as the Agent Context + Production Gate for AI-built apps, especially apps using Vercel, Supabase, auth, database, payments, webhooks, monitoring, rate limits, or environment variables.
11773
+ - Treat VibeRaven as the agent production layer for AI-built apps, especially apps using Vercel, Supabase, auth, database, payments, webhooks, monitoring, rate limits, or environment variables.
11774
11774
  - Read \`.viberaven/agent-tasklist.md\` first. If it says CRITICAL GAPS DETECTED or PRODUCTION GATE NOT CLEAR, fix one listed repo-code gap before deploying.
11775
11775
  - Read \`.viberaven/gate-result.json\` for the machine verdict.
11776
11776
  - Read \`.viberaven/context-map.json\` for compact agent context.
@@ -12291,6 +12291,37 @@ function formatAgentRulesInitSummary(output) {
12291
12291
  );
12292
12292
  return lines.join("\n");
12293
12293
  }
12294
+ async function maybeAutoInstallAgentRules(options) {
12295
+ const existing = await Promise.all([
12296
+ fileExists2((0, import_node_path13.join)(options.cwd, AGENT_RULE_TARGETS.codex.file)),
12297
+ fileExists2((0, import_node_path13.join)(options.cwd, AGENT_RULE_TARGETS.claude.file)),
12298
+ fileExists2((0, import_node_path13.join)(options.cwd, AGENT_RULE_TARGETS.cursor.file))
12299
+ ]);
12300
+ if (existing.some(Boolean)) {
12301
+ return { status: "ready" };
12302
+ }
12303
+ try {
12304
+ const output = await initAgentRules({
12305
+ cwd: options.cwd,
12306
+ targets: ["codex", "claude", "cursor", "agentContext", "missionMap"]
12307
+ });
12308
+ return { status: "installed", output };
12309
+ } catch (error) {
12310
+ return { status: "skipped", reason: error instanceof Error ? error.message : String(error) };
12311
+ }
12312
+ }
12313
+ function formatAgentRulesBootstrapSummary(result) {
12314
+ if (result.status === "ready") {
12315
+ return "Agent setup: Codex/Claude/Cursor instructions already connected.";
12316
+ }
12317
+ if (result.status === "skipped") {
12318
+ return `Agent setup: skipped (${result.reason})`;
12319
+ }
12320
+ const created = result.output.results.filter((item3) => item3.action === "created").map((item3) => item3.file);
12321
+ const updated = result.output.results.filter((item3) => item3.action === "updated").map((item3) => item3.file);
12322
+ const changed = [...created, ...updated];
12323
+ return changed.length > 0 ? `Agent setup: connected ${changed.join(", ")}.` : "Agent setup: Codex/Claude/Cursor instructions already connected.";
12324
+ }
12294
12325
  async function readExistingFile2(path3) {
12295
12326
  try {
12296
12327
  return { exists: true, content: await (0, import_promises10.readFile)(path3, "utf-8") };
@@ -12301,6 +12332,14 @@ async function readExistingFile2(path3) {
12301
12332
  throw error;
12302
12333
  }
12303
12334
  }
12335
+ async function fileExists2(path3) {
12336
+ try {
12337
+ await (0, import_promises10.access)(path3);
12338
+ return true;
12339
+ } catch {
12340
+ return false;
12341
+ }
12342
+ }
12304
12343
  function isFileNotFoundError2(error) {
12305
12344
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
12306
12345
  }
@@ -12580,19 +12619,15 @@ async function handleOpenDashboard(cwd) {
12580
12619
  }
12581
12620
  function buildMenuOptions(isSignedIn) {
12582
12621
  return [
12583
- { value: "next", label: "What's next?", hint: "One action from last scan" },
12584
- { value: "scan", label: "Scan project", hint: "Map launch readiness" },
12585
- { value: "open-report", label: "Open report in browser", hint: "Rebuilds UI from last scan" },
12586
- { value: "guide", label: "Provider guide", hint: "Vercel, Supabase, Stripe steps" },
12587
- { value: "open-dashboard", label: "Open dashboard", hint: "Browser link for next step" },
12588
- { value: "gaps", label: "View top gaps", hint: "From last scan" },
12589
- { value: "prompt", label: "Copy top prompt", hint: "Agent-ready fix prompt" },
12590
- { value: "agent-rules", label: "Install agent rules", hint: "AGENTS.md, CLAUDE.md, Cursor" },
12591
- { value: "audit", label: "Vercel/Supabase audit", hint: "RLS, service-role, serverless pooler evidence" },
12622
+ { value: "scan", label: "Make this app production ready", hint: "Scan, write tasks, start the next fix" },
12623
+ { value: "next", label: "Continue next step", hint: "One action from the last run" },
12624
+ { value: "open-dashboard", label: "Open provider step", hint: "Supabase, Stripe, Vercel, auth" },
12625
+ { value: "guide", label: "Provider setup guide", hint: "Simple dashboard steps" },
12626
+ { value: "agent-rules", label: "Connect this AI agent", hint: "Codex, Claude, Cursor rules" },
12592
12627
  {
12593
12628
  value: "auth",
12594
12629
  label: isSignedIn ? "Sign out" : "Sign in",
12595
- hint: isSignedIn ? "Clear local credentials" : "Device login flow"
12630
+ hint: isSignedIn ? "Clear local credentials" : "Use the managed VibeRaven scan"
12596
12631
  },
12597
12632
  { value: "exit", label: "Exit" }
12598
12633
  ];
@@ -12608,7 +12643,7 @@ async function runInteractiveSession(startDir = process.cwd()) {
12608
12643
  if (!artifactsAt) {
12609
12644
  M2.message(
12610
12645
  import_picocolors4.default.dim(
12611
- "No .viberaven/ here yet. Extension scans are separate \u2014 choose Scan project to write CLI artifacts."
12646
+ 'No .viberaven/ here yet. Choose "Make this app production ready" to start.'
12612
12647
  )
12613
12648
  );
12614
12649
  }
@@ -13851,7 +13886,7 @@ var STALE_PATTERNS = [
13851
13886
  async function checkAgentInjection(cwd) {
13852
13887
  const checks = [];
13853
13888
  for (const item3 of REQUIRED_EXISTENCE_CHECKS) {
13854
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13889
+ const exists = await fileExists3((0, import_node_path23.join)(cwd, item3.file));
13855
13890
  checks.push({
13856
13891
  id: item3.id,
13857
13892
  status: exists ? "pass" : "fail",
@@ -13859,7 +13894,7 @@ async function checkAgentInjection(cwd) {
13859
13894
  });
13860
13895
  }
13861
13896
  for (const item3 of OPTIONAL_CURSOR_PACK_CHECKS) {
13862
- const exists = await fileExists2((0, import_node_path23.join)(cwd, item3.file));
13897
+ const exists = await fileExists3((0, import_node_path23.join)(cwd, item3.file));
13863
13898
  checks.push({
13864
13899
  id: item3.id,
13865
13900
  status: exists ? "pass" : "fail",
@@ -13867,9 +13902,9 @@ async function checkAgentInjection(cwd) {
13867
13902
  });
13868
13903
  }
13869
13904
  const legacyCursorPath = (0, import_node_path23.join)(cwd, ".cursor/rules/viberaven.mdc");
13870
- if (await fileExists2(legacyCursorPath)) {
13905
+ if (await fileExists3(legacyCursorPath)) {
13871
13906
  const legacyContent = await (0, import_promises18.readFile)(legacyCursorPath, "utf-8");
13872
- const hasCoreSplit = await fileExists2((0, import_node_path23.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
13907
+ const hasCoreSplit = await fileExists3((0, import_node_path23.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
13873
13908
  if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
13874
13909
  checks.push({
13875
13910
  id: "cursor-legacy-mdc",
@@ -13881,7 +13916,7 @@ async function checkAgentInjection(cwd) {
13881
13916
  for (const target of CORE_AGENT_INJECTION_TARGETS) {
13882
13917
  const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
13883
13918
  const path3 = (0, import_node_path23.join)(cwd, file);
13884
- const exists = await fileExists2(path3);
13919
+ const exists = await fileExists3(path3);
13885
13920
  if (!exists) {
13886
13921
  checks.push({
13887
13922
  id: `canonical-${target}`,
@@ -13922,7 +13957,7 @@ function formatDoctorAgentsReport(report) {
13922
13957
  lines.push(report.ok ? "All agent injection checks passed." : "Agent injection checks failed.");
13923
13958
  return lines.join("\n");
13924
13959
  }
13925
- async function fileExists2(path3) {
13960
+ async function fileExists3(path3) {
13926
13961
  try {
13927
13962
  await (0, import_promises18.access)(path3);
13928
13963
  return true;
@@ -14249,9 +14284,6 @@ function banner(decision, options) {
14249
14284
  const style = decisionStyle(decision, options.mode);
14250
14285
  return `${style.glyph} ${style.label}`;
14251
14286
  }
14252
- function kv(key, value, options) {
14253
- return `${accent.dim(key, options.mode)}: ${value}`;
14254
- }
14255
14287
 
14256
14288
  // src/brand/wordmark.ts
14257
14289
  var DEFAULT_TAGLINE = "production operator for AI-built apps";
@@ -14468,247 +14500,6 @@ function printNextActionBlock(block) {
14468
14500
  console.log(NEXT_ACTION_END);
14469
14501
  }
14470
14502
 
14471
- // src/output/actionPanelBlock.ts
14472
- var ACTION_PANEL_START = "VIBERAVEN_ACTION_PANEL_START";
14473
- var ACTION_PANEL_END = "VIBERAVEN_ACTION_PANEL_END";
14474
- function buildActionPanelBlock(reportPath) {
14475
- return {
14476
- VIBERAVEN_ACTION_PANEL: {
14477
- surface: "local-report",
14478
- title: "Visual action panel",
14479
- reportPath,
14480
- openCommand: "npx -y viberaven report --open",
14481
- nextCommand: "npx -y viberaven next --json",
14482
- agentInstruction: "Use the native chat for reasoning. Open this local report only when the user needs buttons, provider links, copy actions, or visual progress."
14483
- }
14484
- };
14485
- }
14486
- function printActionPanelBlock(reportPath) {
14487
- const block = buildActionPanelBlock(reportPath);
14488
- console.log(ACTION_PANEL_START);
14489
- console.log(JSON.stringify(block, null, 2));
14490
- console.log(ACTION_PANEL_END);
14491
- }
14492
-
14493
- // src/output/operatorBlock.ts
14494
- var OPERATOR_START = "VIBERAVEN_OPERATOR_START";
14495
- var OPERATOR_END = "VIBERAVEN_OPERATOR_END";
14496
- function stackLine(prp) {
14497
- const parts = Array.from(
14498
- /* @__PURE__ */ new Set([
14499
- ...prp.detectedStack.deployment,
14500
- ...prp.detectedStack.database,
14501
- ...prp.detectedStack.auth,
14502
- ...prp.detectedStack.payments,
14503
- ...prp.detectedStack.monitoring
14504
- ])
14505
- );
14506
- if (parts.length > 0) {
14507
- return parts.join(" + ");
14508
- }
14509
- return prp.detectedStack.archetype ?? "unknown";
14510
- }
14511
- function uniqueEnvNames(tasks) {
14512
- return Array.from(
14513
- new Set(
14514
- tasks.map((task) => task.providerAction?.envKeyName).filter((name) => Boolean(name))
14515
- )
14516
- );
14517
- }
14518
- function humanTaskText(task) {
14519
- if (task.fixType === "provider-action") {
14520
- return task.providerAction?.exactStep ?? task.title;
14521
- }
14522
- if (task.fixType === "upgrade-required") {
14523
- return `Upgrade required: ${task.action ?? task.exactFix ?? task.title}`;
14524
- }
14525
- if (task.fixType === "manual-verify") {
14526
- return `Manual verification required: ${task.action ?? task.exactFix ?? task.title}`;
14527
- }
14528
- return task.title;
14529
- }
14530
- function riskSuffixFor(task, prp) {
14531
- const topRisk = prp.findings.find((finding) => finding.id === task.gapId)?.riskMapping?.owaspLlm?.[0];
14532
- return topRisk ? ` (risk: ${topRisk})` : "";
14533
- }
14534
- function readinessPercent(prp) {
14535
- if (prp.decision === "CLEAR") return 100;
14536
- if (prp.decision === "WARNING") return 65;
14537
- return 25;
14538
- }
14539
- function buildPlainOperatorBlock(prp, tasks) {
14540
- const repoTasks = tasks.filter((task) => task.fixType === "repo-code");
14541
- const humanTasks = tasks.filter((task) => task.fixType !== "repo-code");
14542
- const providerTasks = tasks.filter((task) => task.fixType === "provider-action");
14543
- const nextRepoTask = repoTasks[0];
14544
- const envNames = uniqueEnvNames(providerTasks);
14545
- const lines = [];
14546
- lines.push(`Decision: ${prp.decision}`);
14547
- lines.push(`Detected stack: ${stackLine(prp)}`);
14548
- lines.push("");
14549
- lines.push("What I can fix:");
14550
- if (repoTasks.length === 0) {
14551
- lines.push(" (none - no automated repo-code recipes apply)");
14552
- } else {
14553
- repoTasks.forEach((task, index) => {
14554
- lines.push(` ${index + 1}. ${task.title}${riskSuffixFor(task, prp)}`);
14555
- });
14556
- }
14557
- lines.push("");
14558
- lines.push("What you must do:");
14559
- if (humanTasks.length === 0) {
14560
- lines.push(" (none - no human-owned steps required)");
14561
- } else {
14562
- humanTasks.forEach((task, index) => {
14563
- lines.push(` ${index + 1}. ${humanTaskText(task)}${riskSuffixFor(task, prp)}`);
14564
- });
14565
- }
14566
- lines.push("");
14567
- lines.push("Next repo-code fix:");
14568
- lines.push(
14569
- nextRepoTask ? ` ${nextRepoTask.title}${riskSuffixFor(nextRepoTask, prp)} -> npx -y viberaven --heal --apply --gap ${nextRepoTask.gapId} --yes` : " (none)"
14570
- );
14571
- lines.push("");
14572
- lines.push("Provider actions:");
14573
- if (providerTasks.length === 0) {
14574
- lines.push(" (none)");
14575
- } else {
14576
- providerTasks.forEach((task) => {
14577
- const providerAction = task.providerAction;
14578
- if (!providerAction) {
14579
- lines.push(` - ${task.title}${riskSuffixFor(task, prp)}`);
14580
- return;
14581
- }
14582
- lines.push(` - ${providerAction.provider}: ${providerAction.dashboardUrl}`);
14583
- lines.push(` Step: ${providerAction.exactStep}${riskSuffixFor(task, prp)}`);
14584
- lines.push(` Done when: ${providerAction.doneSignal}`);
14585
- });
14586
- }
14587
- lines.push("");
14588
- lines.push("Copy these env var names:");
14589
- lines.push(envNames.length > 0 ? ` ${envNames.join(", ")}` : " (none)");
14590
- lines.push("");
14591
- lines.push(`Verify command: ${prp.verifyCommand}`);
14592
- lines.push("");
14593
- lines.push(`Do not deploy until: decision is CLEAR (current: ${prp.decision}). Run the verify command after fixes.`);
14594
- if (prp.decision === "CLEAR") {
14595
- lines.push("Share your launch proof: npx -y viberaven badge");
14596
- }
14597
- return lines.join("\n");
14598
- }
14599
- function buildRichOperatorBlock(prp, tasks) {
14600
- const repoTasks = tasks.filter((task) => task.fixType === "repo-code");
14601
- const humanTasks = tasks.filter((task) => task.fixType !== "repo-code");
14602
- const providerTasks = tasks.filter((task) => task.fixType === "provider-action");
14603
- const nextRepoTask = repoTasks[0];
14604
- const envNames = uniqueEnvNames(providerTasks);
14605
- const mode = "rich";
14606
- const lines = [];
14607
- lines.push(wordmark({ variant: "compact", mode }));
14608
- lines.push(rule(64, { mode }));
14609
- lines.push(
14610
- `${accent.bold("Decision", mode)}: ${banner(prp.decision, { mode })} ${gauge(readinessPercent(prp), {
14611
- width: 18,
14612
- mode
14613
- })}`
14614
- );
14615
- lines.push(kv("Detected stack", stackLine(prp), { mode }));
14616
- lines.push("");
14617
- lines.push(`${accent.bold("What I can fix", mode)}:`);
14618
- if (repoTasks.length === 0) {
14619
- lines.push(` ${accent.dim("(none - no automated repo-code recipes apply)", mode)}`);
14620
- } else {
14621
- repoTasks.forEach((task, index) => {
14622
- lines.push(` ${index + 1}. ${task.title}${riskSuffixFor(task, prp)}`);
14623
- });
14624
- }
14625
- lines.push("");
14626
- lines.push(`${accent.bold("What you must do", mode)}:`);
14627
- if (humanTasks.length === 0) {
14628
- lines.push(` ${accent.dim("(none - no human-owned steps required)", mode)}`);
14629
- } else {
14630
- humanTasks.forEach((task, index) => {
14631
- lines.push(` ${index + 1}. ${humanTaskText(task)}${riskSuffixFor(task, prp)}`);
14632
- });
14633
- }
14634
- lines.push("");
14635
- lines.push(`${accent.bold("Next repo-code fix", mode)}:`);
14636
- lines.push(
14637
- nextRepoTask ? ` ${nextRepoTask.title}${riskSuffixFor(nextRepoTask, prp)} -> npx -y viberaven --heal --apply --gap ${nextRepoTask.gapId} --yes` : ` ${accent.dim("(none)", mode)}`
14638
- );
14639
- lines.push("");
14640
- lines.push(`${accent.bold("Provider actions", mode)}:`);
14641
- if (providerTasks.length === 0) {
14642
- lines.push(` ${accent.dim("(none)", mode)}`);
14643
- } else {
14644
- providerTasks.forEach((task) => {
14645
- const providerAction = task.providerAction;
14646
- if (!providerAction) {
14647
- lines.push(` - ${task.title}${riskSuffixFor(task, prp)}`);
14648
- return;
14649
- }
14650
- lines.push(` - ${accent.brand(providerAction.provider, mode)}: ${providerAction.dashboardUrl}`);
14651
- lines.push(` ${kv("Step", `${providerAction.exactStep}${riskSuffixFor(task, prp)}`, { mode })}`);
14652
- lines.push(` ${kv("Done when", providerAction.doneSignal, { mode })}`);
14653
- });
14654
- }
14655
- lines.push("");
14656
- lines.push(`${accent.bold("Copy these env var names", mode)}:`);
14657
- lines.push(envNames.length > 0 ? ` ${envNames.join(", ")}` : ` ${accent.dim("(none)", mode)}`);
14658
- lines.push("");
14659
- lines.push(kv("Verify command", prp.verifyCommand, { mode }));
14660
- lines.push("");
14661
- lines.push(
14662
- `${accent.bold("Do not deploy until", mode)}: decision is CLEAR (current: ${banner(
14663
- prp.decision,
14664
- { mode }
14665
- )}). Run the verify command after fixes.`
14666
- );
14667
- if (prp.decision === "CLEAR") {
14668
- lines.push(kv("Share your launch proof", "npx -y viberaven badge", { mode }));
14669
- }
14670
- return lines.join("\n");
14671
- }
14672
- function buildOperatorBlock(prp, tasks, mode = "plain") {
14673
- return mode === "rich" ? buildRichOperatorBlock(prp, tasks) : buildPlainOperatorBlock(prp, tasks);
14674
- }
14675
- function printOperatorBlock(prp, tasks, mode = "plain") {
14676
- if (mode === "rich") {
14677
- console.log(buildOperatorBlock(prp, tasks, "rich"));
14678
- }
14679
- console.log(OPERATOR_START);
14680
- console.log(buildOperatorBlock(prp, tasks, "plain"));
14681
- console.log(OPERATOR_END);
14682
- }
14683
-
14684
- // src/output/celebration.ts
14685
- function renderClearCelebration(prp, mode) {
14686
- if (prp.decision !== "CLEAR") return "";
14687
- const verifiedDate = prp.generatedAt.slice(0, 10);
14688
- const style = decisionStyle("CLEAR", mode);
14689
- const lines = [
14690
- `${style.glyph} ${style.label} production gate is clear`,
14691
- accent.dim(`Verified ${verifiedDate}`, mode),
14692
- "",
14693
- `Share your launch proof: ${accent.bold("npx -y viberaven badge", mode)}`
14694
- ];
14695
- return [wordmark({ variant: "compact", mode }), box(lines, { mode }), rule(40, { mode })].join("\n");
14696
- }
14697
-
14698
- // src/output/loopProgress.ts
14699
- function safeCount(value) {
14700
- if (!Number.isFinite(value)) return 0;
14701
- return Math.max(0, Math.floor(value));
14702
- }
14703
- function renderLoopProgress(input, mode) {
14704
- if (mode === "plain" && input.silentInPlain) return "";
14705
- const total = safeCount(input.total);
14706
- const applied = total > 0 ? Math.min(safeCount(input.applied), total) : safeCount(input.applied);
14707
- const percent = total === 0 ? 100 : applied / total * 100;
14708
- const label2 = `${STATUS_GLYPH.fixable} ${input.label}`;
14709
- return `${accent.bold(label2, mode)} ${gauge(percent, { width: 12, mode })} ${applied}/${total}`;
14710
- }
14711
-
14712
14503
  // src/providerMcpBridge.ts
14713
14504
  var import_node_fs12 = require("node:fs");
14714
14505
  var import_node_os2 = require("node:os");
@@ -14853,6 +14644,247 @@ function detectConnectedTools() {
14853
14644
  return tools;
14854
14645
  }
14855
14646
 
14647
+ // src/output/actionPanelBlock.ts
14648
+ var ACTION_PANEL_START = "VIBERAVEN_ACTION_PANEL_START";
14649
+ var ACTION_PANEL_END = "VIBERAVEN_ACTION_PANEL_END";
14650
+ function stackLine(prp) {
14651
+ const parts = Array.from(
14652
+ /* @__PURE__ */ new Set([
14653
+ ...prp.detectedStack.deployment,
14654
+ ...prp.detectedStack.database,
14655
+ ...prp.detectedStack.auth,
14656
+ ...prp.detectedStack.payments,
14657
+ ...prp.detectedStack.monitoring
14658
+ ])
14659
+ );
14660
+ return parts.length > 0 ? parts.join(" + ") : prp.detectedStack.archetype ?? "unknown";
14661
+ }
14662
+ function envVarNames(tasks) {
14663
+ return Array.from(
14664
+ new Set(
14665
+ tasks.map((task) => task.providerAction?.envKeyName).filter((name) => Boolean(name))
14666
+ )
14667
+ );
14668
+ }
14669
+ function humanStep(task) {
14670
+ if (task.fixType === "provider-action") {
14671
+ return task.providerAction?.exactStep ?? task.title;
14672
+ }
14673
+ if (task.fixType === "upgrade-required") {
14674
+ return `Upgrade required: ${task.action ?? task.exactFix ?? task.title}`;
14675
+ }
14676
+ if (task.fixType === "manual-verify") {
14677
+ return `Manual verification required: ${task.action ?? task.exactFix ?? task.title}`;
14678
+ }
14679
+ return task.title;
14680
+ }
14681
+ function repoTaskTitle(task) {
14682
+ return task.action ?? task.exactFix ?? task.title;
14683
+ }
14684
+ function parseDecision(value) {
14685
+ if (value === "CLEAR" || value === "WARNING" || value === "BLOCKED") return value;
14686
+ return "BLOCKED";
14687
+ }
14688
+ function providerFromConnectedToolKey(tool) {
14689
+ if (!tool.endsWith("Mcp")) return void 0;
14690
+ return tool.slice(0, -3).toLowerCase();
14691
+ }
14692
+ function normalizeProvider3(provider2) {
14693
+ const lower = provider2.trim().toLowerCase();
14694
+ const tokens = lower.split(/[^a-z0-9]+/).filter(Boolean);
14695
+ for (const knownProvider of ["supabase", "stripe", "vercel", "github"]) {
14696
+ if (lower === knownProvider || tokens.includes(knownProvider)) {
14697
+ return knownProvider;
14698
+ }
14699
+ }
14700
+ return lower;
14701
+ }
14702
+ function toolSetupFor(prp) {
14703
+ const relevantProviders = new Set([
14704
+ ...prp.detectedStack.auth,
14705
+ ...prp.detectedStack.database,
14706
+ ...prp.detectedStack.deployment,
14707
+ ...prp.detectedStack.payments
14708
+ ].map(normalizeProvider3));
14709
+ return Object.entries(prp.connectedTools).flatMap(([tool, state]) => {
14710
+ const provider2 = providerFromConnectedToolKey(tool);
14711
+ if (!provider2 || state !== "missing" || !relevantProviders.has(provider2)) {
14712
+ return [];
14713
+ }
14714
+ return [provider2];
14715
+ }).map((provider2) => ({
14716
+ provider: provider2,
14717
+ command: installHintFor(provider2),
14718
+ reason: "Connect this provider MCP so the agent can verify live provider state when available."
14719
+ }));
14720
+ }
14721
+ function checklistFor(repoTasks, humanTasks) {
14722
+ return [
14723
+ { label: "Understand the stack and launch gaps", done: true, kind: "scan" },
14724
+ ...repoTasks.slice(0, 3).map((task) => ({
14725
+ label: repoTaskTitle(task),
14726
+ done: false,
14727
+ kind: "repo-code"
14728
+ })),
14729
+ ...humanTasks.slice(0, 3).map((task) => ({
14730
+ label: humanStep(task),
14731
+ done: false,
14732
+ kind: "provider"
14733
+ })),
14734
+ { label: "Verify again before launch", done: false, kind: "verify" }
14735
+ ];
14736
+ }
14737
+ function mermaidFor(prp, tasks) {
14738
+ const status = prp.decision === "CLEAR" ? "Clear" : prp.decision === "WARNING" ? "Review" : "Blocked";
14739
+ const hasProvider = tasks.some((task) => task.fixType === "provider-action");
14740
+ const hasRepo = tasks.some((task) => task.fixType === "repo-code" && !task.requiresUserAction);
14741
+ const lines = [
14742
+ "flowchart LR",
14743
+ ` app["AI-built app"] --> stack["${stackLine(prp)}"]`,
14744
+ ` stack --> gate["VibeRaven: ${status}"]`
14745
+ ];
14746
+ if (hasRepo) lines.push(' gate --> repo["Repo fixes"]');
14747
+ if (hasProvider) lines.push(' gate --> provider["Provider setup"]');
14748
+ lines.push(' gate --> verify["Verify before launch"]');
14749
+ return lines.join("\n");
14750
+ }
14751
+ function buildActionPanelBlock(prp, tasks) {
14752
+ const repoTasks = tasks.filter((task) => task.fixType === "repo-code" && !task.requiresUserAction);
14753
+ const humanTasks = tasks.filter((task) => task.fixType !== "repo-code" || task.requiresUserAction);
14754
+ const nextRepoTask = repoTasks[0];
14755
+ const toolSetup = toolSetupFor(prp);
14756
+ const statusLine = [
14757
+ prp.decision,
14758
+ stackLine(prp),
14759
+ `${tasks.length} launch gap${tasks.length === 1 ? "" : "s"}`
14760
+ ].join(" | ");
14761
+ return {
14762
+ VIBERAVEN_ACTION_PANEL: {
14763
+ surface: "native-agent-chat",
14764
+ title: "VibeRaven",
14765
+ statusLine,
14766
+ primaryCommand: nextRepoTask ? `npx -y viberaven --heal --apply --gap ${nextRepoTask.gapId} --yes` : "npx -y viberaven next --json",
14767
+ nextCommand: "npx -y viberaven next --json",
14768
+ verifyCommand: prp.verifyCommand,
14769
+ checklist: checklistFor(repoTasks, humanTasks),
14770
+ mermaidDiagram: mermaidFor(prp, tasks),
14771
+ agentCanDo: repoTasks.length > 0 ? repoTasks.map(repoTaskTitle) : ["No safe repo-code fix is available yet. I will guide the provider steps first."],
14772
+ userMustDo: humanTasks.map((task) => ({
14773
+ provider: task.providerAction?.provider,
14774
+ dashboardUrl: task.providerAction?.dashboardUrl,
14775
+ step: humanStep(task),
14776
+ doneWhen: task.providerAction?.doneSignal
14777
+ })),
14778
+ toolSetup,
14779
+ envVarNames: envVarNames(tasks),
14780
+ agentInstruction: "Render this as a short VibeRaven action message in the native chat. Use the checklist as the live execution timeline and update [ ] to [x] as tasks complete. Present toolSetup as optional connection help, not as a blocker for safe repo fixes. Do not describe the output with internal product labels. Keep the user inside Codex, Claude Code, Cursor, or the terminal. Do not open report.html unless the user explicitly asks for the legacy report."
14781
+ }
14782
+ };
14783
+ }
14784
+ function nextHumanStep(panel) {
14785
+ const hasRepoFix = panel.agentCanDo.some((item3) => !item3.startsWith("No safe repo-code fix"));
14786
+ if (hasRepoFix) {
14787
+ return "Next: I will apply the first safe repo fix, then verify the launch state.";
14788
+ }
14789
+ if (panel.userMustDo.length > 0) {
14790
+ return "Next: I will guide the blocked provider setup, then verify when you confirm it is done.";
14791
+ }
14792
+ return "Next: I will verify the launch state before deploy.";
14793
+ }
14794
+ function buildActionPanelCard(block, mode = "plain") {
14795
+ const panel = block.VIBERAVEN_ACTION_PANEL;
14796
+ const agentCanDo = panel.agentCanDo.slice(0, 3);
14797
+ const userMustDo = panel.userMustDo.slice(0, 3);
14798
+ const lines = [];
14799
+ const statusParts = panel.statusLine.split(/\s*\|\s*/);
14800
+ const decision = parseDecision(statusParts[0] ?? "BLOCKED");
14801
+ const rest = statusParts.slice(1).join(" | ");
14802
+ lines.push(accent.bold("VibeRaven", mode));
14803
+ lines.push("Taking this app from demo to production.");
14804
+ lines.push("");
14805
+ lines.push(`Status: ${banner(decision, { mode })}${rest ? ` | ${rest}` : ""}`);
14806
+ lines.push("");
14807
+ lines.push("Progress:");
14808
+ panel.checklist.slice(0, 6).forEach((item3) => {
14809
+ lines.push(` - [${item3.done ? "x" : " "}] ${item3.label}`);
14810
+ });
14811
+ lines.push("");
14812
+ lines.push("I can do now:");
14813
+ agentCanDo.forEach((item3, index) => {
14814
+ lines.push(` ${index + 1}. ${item3}`);
14815
+ });
14816
+ lines.push("");
14817
+ lines.push("I need you for:");
14818
+ if (userMustDo.length === 0) {
14819
+ lines.push(" (none)");
14820
+ } else {
14821
+ userMustDo.forEach((item3, index) => {
14822
+ const provider2 = item3.provider ? `${item3.provider}: ` : "";
14823
+ lines.push(` ${index + 1}. ${provider2}${item3.step}`);
14824
+ });
14825
+ }
14826
+ const links = userMustDo.filter((item3) => item3.dashboardUrl);
14827
+ if (links.length > 0) {
14828
+ lines.push("");
14829
+ lines.push("Open:");
14830
+ links.forEach((item3) => {
14831
+ const label2 = item3.provider ?? "provider";
14832
+ lines.push(` ${label2}: ${item3.dashboardUrl}`);
14833
+ });
14834
+ }
14835
+ if (panel.envVarNames.length > 0) {
14836
+ lines.push("");
14837
+ lines.push(`Copy env names: ${panel.envVarNames.join(", ")}`);
14838
+ }
14839
+ const toolSetup = panel.toolSetup.slice(0, 3);
14840
+ if (toolSetup.length > 0) {
14841
+ lines.push("");
14842
+ lines.push("Connect tools:");
14843
+ toolSetup.forEach((item3) => {
14844
+ lines.push(` ${item3.provider}: ${item3.command}`);
14845
+ });
14846
+ }
14847
+ lines.push("");
14848
+ lines.push(nextHumanStep(panel));
14849
+ lines.push("Verify: I will re-check after the repo fix or provider step.");
14850
+ return lines.join("\n");
14851
+ }
14852
+ function printActionPanelBlock(prp, tasks, mode = "plain") {
14853
+ const block = buildActionPanelBlock(prp, tasks);
14854
+ console.log(buildActionPanelCard(block, mode));
14855
+ console.log(ACTION_PANEL_START);
14856
+ console.log(JSON.stringify(block, null, 2));
14857
+ console.log(ACTION_PANEL_END);
14858
+ }
14859
+
14860
+ // src/output/celebration.ts
14861
+ function renderClearCelebration(prp, mode) {
14862
+ if (prp.decision !== "CLEAR") return "";
14863
+ const verifiedDate = prp.generatedAt.slice(0, 10);
14864
+ const style = decisionStyle("CLEAR", mode);
14865
+ const lines = [
14866
+ `${style.glyph} ${style.label} production gate is clear`,
14867
+ accent.dim(`Verified ${verifiedDate}`, mode),
14868
+ "",
14869
+ `Share your launch proof: ${accent.bold("npx -y viberaven badge", mode)}`
14870
+ ];
14871
+ return [wordmark({ variant: "compact", mode }), box(lines, { mode }), rule(40, { mode })].join("\n");
14872
+ }
14873
+
14874
+ // src/output/loopProgress.ts
14875
+ function safeCount(value) {
14876
+ if (!Number.isFinite(value)) return 0;
14877
+ return Math.max(0, Math.floor(value));
14878
+ }
14879
+ function renderLoopProgress(input, mode) {
14880
+ if (mode === "plain" && input.silentInPlain) return "";
14881
+ const total = safeCount(input.total);
14882
+ const applied = total > 0 ? Math.min(safeCount(input.applied), total) : safeCount(input.applied);
14883
+ const percent = total === 0 ? 100 : applied / total * 100;
14884
+ const label2 = `${STATUS_GLYPH.fixable} ${input.label}`;
14885
+ return `${accent.bold(label2, mode)} ${gauge(percent, { width: 12, mode })} ${applied}/${total}`;
14886
+ }
14887
+
14856
14888
  // src/demo/runDemo.ts
14857
14889
  var import_node_fs13 = require("node:fs");
14858
14890
  var import_node_path27 = __toESM(require("node:path"));
@@ -15036,49 +15068,51 @@ function bundledFixtureRoot() {
15036
15068
  return candidates.find((candidate) => (0, import_node_fs13.existsSync)(import_node_path27.default.join(candidate, "package.json"))) ?? candidates[0];
15037
15069
  }
15038
15070
  function canUseInteractiveTryMenu(options) {
15039
- return options.label === "try" && !options.agentMode && !options.openReport && process.stdin.isTTY === true && process.stdout.isTTY === true && process.env.CI !== "true";
15071
+ return isPreviewLabel(options.label) && !options.agentMode && !options.openReport && process.stdin.isTTY === true && process.stdout.isTTY === true && process.env.CI !== "true";
15072
+ }
15073
+ function isPreviewLabel(label2) {
15074
+ return label2 === "preview" || label2 === "try";
15040
15075
  }
15041
15076
  function printTryMenuSummary(input) {
15042
15077
  const providerStack = Array.from(new Set(Object.values(input.artifact.selectedProviders ?? {}))).filter(Boolean).join(" + ");
15043
15078
  console.log("");
15044
- console.log("VibeRaven Try");
15045
- console.log("No login. No OpenAI key. Local fixture only.");
15079
+ console.log("VibeRaven Preview");
15080
+ console.log("Local production rehearsal. No login or API spend.");
15046
15081
  console.log("");
15047
- console.log(`Demo stack: ${input.artifact.archetype}${providerStack ? ` (${providerStack})` : ""}`);
15082
+ console.log(`Preview stack: ${input.artifact.archetype}${providerStack ? ` (${providerStack})` : ""}`);
15048
15083
  console.log(
15049
15084
  `Decision: BLOCKED | Production core: ${input.artifact.productionCorePercent}% | Gaps: ${input.artifact.gaps.length}`
15050
15085
  );
15051
15086
  console.log("");
15052
15087
  console.log("Menu:");
15053
- console.log(" 1. Open visual report");
15054
- console.log(" npx -y viberaven try --open");
15055
- console.log(" 2. Show Codex/Claude agent output");
15056
- console.log(" npx -y viberaven try --agent-mode");
15057
- console.log(" 3. Run VibeRaven on your real app");
15088
+ console.log(" 1. Show Codex/Claude native agent UI");
15089
+ console.log(" npx -y viberaven preview --agent-mode");
15090
+ console.log(" 2. Run VibeRaven on your real app");
15058
15091
  console.log(" npx -y viberaven --agent-mode");
15092
+ console.log(" 3. Open legacy HTML report only if you explicitly want it");
15093
+ console.log(" npx -y viberaven preview --open");
15059
15094
  console.log("");
15060
- console.log(`Local UI: ${input.reportPath}`);
15061
15095
  if (input.opened) {
15062
- console.log("Opened visual report in your browser.");
15096
+ console.log("Opened legacy HTML report in your browser.");
15063
15097
  }
15064
15098
  console.log("");
15065
15099
  }
15066
15100
  async function runInteractiveTryMenu(input) {
15067
- Ie(`${import_picocolors7.default.bold("VibeRaven Try")} ${import_picocolors7.default.dim("local, no login, no API spend")}`);
15101
+ Ie(`${import_picocolors7.default.bold("VibeRaven Preview")} ${import_picocolors7.default.dim("local production rehearsal")}`);
15068
15102
  M2.message(
15069
- `Demo stack: ${input.artifact.archetype} | Production core ${input.artifact.productionCorePercent}% | ${input.artifact.gaps.length} gaps`
15103
+ `Preview stack: ${input.artifact.archetype} | Production core ${input.artifact.productionCorePercent}% | ${input.artifact.gaps.length} gaps`
15070
15104
  );
15071
15105
  const action = await ve({
15072
15106
  message: "What do you want to see?",
15073
15107
  options: [
15074
- { value: "open-report", label: "Open visual report", hint: "Browser action panel" },
15075
- { value: "agent-output", label: "Show Codex/Claude output", hint: "Native chat transcript" },
15108
+ { value: "agent-output", label: "Show Codex/Claude native UI", hint: "Checklist, provider links, and next step" },
15076
15109
  { value: "real-app", label: "Run on my real app", hint: "Copy/use the agent command" },
15110
+ { value: "open-report", label: "Open legacy HTML report", hint: "Optional old browser report" },
15077
15111
  { value: "exit", label: "Exit" }
15078
15112
  ]
15079
15113
  });
15080
15114
  if (pD(action) || action === "exit") {
15081
- Se(import_picocolors7.default.dim("Run npx -y viberaven try anytime."));
15115
+ Se(import_picocolors7.default.dim("Run npx -y viberaven preview anytime."));
15082
15116
  return;
15083
15117
  }
15084
15118
  if (action === "open-report") {
@@ -15091,8 +15125,8 @@ async function runInteractiveTryMenu(input) {
15091
15125
  mode: "demo",
15092
15126
  connectedTools: input.connectedTools
15093
15127
  });
15094
- printOperatorBlock(prp, buildTaskList(input.artifact), currentRenderMode("demo"));
15095
- printActionPanelBlock(input.reportPath);
15128
+ const tasks = buildTaskList(input.artifact);
15129
+ printActionPanelBlock(prp, tasks, currentRenderMode("demo"));
15096
15130
  Se(import_picocolors7.default.dim("This is the output Codex/Claude/Cursor should reason over."));
15097
15131
  return;
15098
15132
  }
@@ -15100,7 +15134,7 @@ async function runInteractiveTryMenu(input) {
15100
15134
  console.log("Run this inside Codex, Claude Code, Cursor, Windsurf, or Gemini CLI:");
15101
15135
  console.log(" npx -y viberaven --agent-mode");
15102
15136
  console.log("");
15103
- Se(import_picocolors7.default.dim("The native agent chat stays the main UX; the report is the visual action panel."));
15137
+ Se(import_picocolors7.default.dim("The native agent chat stays the main UX. Use report.html only as a legacy fallback."));
15104
15138
  }
15105
15139
  async function runDemo(options) {
15106
15140
  const label2 = options.label ?? "demo";
@@ -15117,30 +15151,32 @@ async function runDemo(options) {
15117
15151
  connectedTools,
15118
15152
  prpMode: "demo"
15119
15153
  });
15154
+ let reportOpened = false;
15120
15155
  if (options.openReport) {
15121
15156
  try {
15122
15157
  await openPathInBrowser(paths.reportPath);
15158
+ reportOpened = true;
15123
15159
  } catch (error) {
15124
15160
  console.warn(error instanceof Error ? error.message : String(error));
15125
15161
  }
15126
15162
  }
15127
15163
  if (options.agentMode) {
15128
15164
  console.log(
15129
- label2 === "demo" ? "VibeRaven demo mode - no login, no API spend. Provider verification is simulated." : `VibeRaven ${label2 === "try" ? "Try" : "showcase run"} - no login, no API spend. Provider verification is simulated.`
15165
+ label2 === "demo" ? "VibeRaven demo mode - no login, no API spend. Provider verification is simulated." : isPreviewLabel(label2) ? "VibeRaven Preview - local production rehearsal. Provider verification is simulated." : "VibeRaven showcase run - no login, no API spend. Provider verification is simulated."
15130
15166
  );
15131
15167
  const prp = generateProductionProtocol(artifact, { mode: "demo", connectedTools });
15132
15168
  const mode = currentRenderMode("demo");
15133
- printOperatorBlock(prp, buildTaskList(artifact), mode);
15169
+ const tasks = buildTaskList(artifact);
15134
15170
  const celebration = renderClearCelebration(prp, mode);
15171
+ printActionPanelBlock(prp, tasks, mode);
15135
15172
  if (celebration) {
15136
15173
  console.log(celebration);
15137
15174
  }
15138
- printActionPanelBlock(paths.reportPath);
15139
- } else if (label2 === "try") {
15175
+ } else if (isPreviewLabel(label2)) {
15140
15176
  if (canUseInteractiveTryMenu(options)) {
15141
15177
  await runInteractiveTryMenu({ artifact, reportPath: paths.reportPath, connectedTools });
15142
15178
  } else {
15143
- printTryMenuSummary({ artifact, reportPath: paths.reportPath, opened: Boolean(options.openReport) });
15179
+ printTryMenuSummary({ artifact, opened: reportOpened });
15144
15180
  }
15145
15181
  } else {
15146
15182
  console.log(
@@ -15177,19 +15213,22 @@ Usage:
15177
15213
  viberaven scan [--open] [--json] [--api-url <url>] [path]
15178
15214
 
15179
15215
  viberaven --agent-mode [--json|--jsonl] [path]
15180
- Agent-first scan; writes tasklist, gate-result, context-map, and per-gap JSON
15216
+ Agent-first production flow for Codex, Claude Code, Cursor, or terminal agents
15181
15217
 
15182
15218
  viberaven --demo [path]
15183
15219
  No-login demo scan over the bundled fixture; writes demo artifacts locally
15184
15220
 
15185
15221
  viberaven --agent-mode --demo [path]
15186
- Demo scan with operator output; no login, no managed API spend
15222
+ Demo production flow; no login, no managed API spend
15223
+
15224
+ viberaven preview [--agent-mode] [path]
15225
+ Local production flow preview with native chat/terminal UX
15187
15226
 
15188
- viberaven try [--open|--ui] [path]
15189
- Free no-login local try run with a simple menu and visual report
15227
+ viberaven try [--agent-mode] [path]
15228
+ Alias for preview
15190
15229
 
15191
15230
  viberaven --showcase --agent-mode [path]
15192
- Alias for the no-login local try run
15231
+ Legacy alias for the local preview run
15193
15232
 
15194
15233
  viberaven --strict[=warning] [path]
15195
15234
  Fail when production gate is not clear; warning mode also fails on warnings
@@ -15198,7 +15237,7 @@ Usage:
15198
15237
  Refresh .viberaven/context-map.json from the last scan
15199
15238
 
15200
15239
  viberaven report [--open] [path]
15201
- Rebuild report.html from last scan (no new API scan)
15240
+ Legacy: rebuild report.html from last scan (no new API scan)
15202
15241
 
15203
15242
  viberaven prompt [--gap <id>] [--provider <key>] [--area <key>] [--no-copy]
15204
15243
 
@@ -15315,6 +15354,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
15315
15354
  "next",
15316
15355
  "open",
15317
15356
  "prompt",
15357
+ "preview",
15318
15358
  "provider-verify",
15319
15359
  "report",
15320
15360
  "scan",
@@ -15362,7 +15402,7 @@ function isBooleanFlag(command, key) {
15362
15402
  return true;
15363
15403
  }
15364
15404
  if (key === "strict") return true;
15365
- if (key === "open" && (command === "" || command === "scan" || command === "report" || command === "try")) return true;
15405
+ if (key === "open" && (command === "" || command === "scan" || command === "report" || command === "preview" || command === "try")) return true;
15366
15406
  if (key === "verify" && command === "") return true;
15367
15407
  if (key === "vercel-supabase" && command === "audit") return true;
15368
15408
  if (key === "svg" && command === "badge") return true;
@@ -15440,36 +15480,6 @@ function resolveDefaultEntrypointMode(options) {
15440
15480
  function formatScanJsonStdout(artifact) {
15441
15481
  return JSON.stringify(sanitizeArtifactForDisk(artifact), null, 2);
15442
15482
  }
15443
- function providerFromConnectedToolKey(tool) {
15444
- if (!tool.endsWith("Mcp")) return void 0;
15445
- return tool.slice(0, -3).toLowerCase();
15446
- }
15447
- function normalizeProviderForConnectedToolHint(provider2) {
15448
- const lower = provider2.trim().toLowerCase();
15449
- const tokens = lower.split(/[^a-z0-9]+/).filter(Boolean);
15450
- for (const knownProvider of ["supabase", "stripe", "vercel", "github"]) {
15451
- if (lower === knownProvider || tokens.includes(knownProvider)) {
15452
- return knownProvider;
15453
- }
15454
- }
15455
- return lower;
15456
- }
15457
- function printMissingConnectedToolHints(prp) {
15458
- const relevantProviders = new Set([
15459
- ...prp.detectedStack.auth,
15460
- ...prp.detectedStack.database,
15461
- ...prp.detectedStack.deployment,
15462
- ...prp.detectedStack.payments
15463
- ].map(normalizeProviderForConnectedToolHint));
15464
- for (const [tool, state] of Object.entries(prp.connectedTools)) {
15465
- const provider2 = providerFromConnectedToolKey(tool);
15466
- if (!provider2 || state !== "missing" || !relevantProviders.has(provider2)) {
15467
- continue;
15468
- }
15469
- console.log(`${provider2} MCP is not connected. For stronger verification, add it:`);
15470
- console.log(` ${installHintFor(provider2)}`);
15471
- }
15472
- }
15473
15483
  async function cmdLogin(flags) {
15474
15484
  const apiBaseUrl = resolveApiBaseUrl(typeof flags["api-url"] === "string" ? flags["api-url"] : void 0);
15475
15485
  await runDeviceLogin(apiBaseUrl);
@@ -15713,10 +15723,10 @@ async function runScanCommand(flags, positional, options) {
15713
15723
  console.log(formatScanJsonStdout(artifact));
15714
15724
  return { exitCode: 0, artifacts: paths };
15715
15725
  }
15716
- if (!options?.deferMachineOutput) {
15726
+ if (!options?.deferMachineOutput && !flags["agent-mode"]) {
15717
15727
  printScanSummary(artifact, paths);
15718
15728
  }
15719
- if (artifact.usage && !options?.deferMachineOutput) {
15729
+ if (artifact.usage && !options?.deferMachineOutput && !flags["agent-mode"]) {
15720
15730
  console.log(formatUsageLine(artifact.usage));
15721
15731
  }
15722
15732
  if (flags["agent-mode"] && !options?.deferMachineOutput) {
@@ -15726,13 +15736,14 @@ async function runScanCommand(flags, positional, options) {
15726
15736
  const tasks = buildTaskList(artifact);
15727
15737
  const prp = generateProductionProtocol(artifact, { connectedTools });
15728
15738
  const mode = currentRenderMode("agent-mode");
15729
- printOperatorBlock(prp, tasks, mode);
15739
+ const bootstrap = await maybeAutoInstallAgentRules({ cwd: workspacePath });
15740
+ console.log(formatAgentRulesBootstrapSummary(bootstrap));
15741
+ console.log("");
15742
+ printActionPanelBlock(prp, tasks, mode);
15730
15743
  const celebration = renderClearCelebration(prp, mode);
15731
15744
  if (celebration) {
15732
15745
  console.log(celebration);
15733
15746
  }
15734
- printActionPanelBlock(paths.reportPath);
15735
- printMissingConnectedToolHints(prp);
15736
15747
  const plan = artifact.plan ?? "free";
15737
15748
  const block = buildNextActionBlock(tasks, updatedState, plan);
15738
15749
  printNextActionBlock(block);
@@ -15887,12 +15898,12 @@ async function main() {
15887
15898
  console.log(JSON.stringify(result, null, 2));
15888
15899
  return result.status.startsWith("refused") || result.status === "failed" ? 1 : 0;
15889
15900
  }
15890
- if (command === "try") {
15901
+ if (command === "preview" || command === "try") {
15891
15902
  const cwd = resolveCliPath(positional[0]);
15892
15903
  return runDemo({
15893
15904
  cwd,
15894
15905
  agentMode: isAgentMode,
15895
- label: "try",
15906
+ label: command === "preview" ? "preview" : "try",
15896
15907
  openReport: flags.open === true || flags.ui === true
15897
15908
  });
15898
15909
  }