@viberaven/cli 1.5.3 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6970,7 +6970,7 @@ var init_mockSupabaseVerifier = __esm({
6970
6970
  providerObservationMet: false,
6971
6971
  fixType: "mcp-connect",
6972
6972
  severity: tables.length > 0 ? "critical" : "info",
6973
- repoSignals: tables.map((table) => `table referenced: ${table}`),
6973
+ repoSignals: tables.map((table2) => `table referenced: ${table2}`),
6974
6974
  providerSignals: ["Supabase policy list API or MCP"],
6975
6975
  requiredEvidence: ["Policies exist for tables used in application code"]
6976
6976
  }),
@@ -6986,7 +6986,7 @@ var init_mockSupabaseVerifier = __esm({
6986
6986
  providerObservationMet: false,
6987
6987
  fixType: "provider-config",
6988
6988
  severity: "warning",
6989
- repoSignals: tables.map((table) => `.from("${table}")`),
6989
+ repoSignals: tables.map((table2) => `.from("${table2}")`),
6990
6990
  providerSignals: ["Live table policy map"],
6991
6991
  requiredEvidence: ["Each referenced public table has RLS + policy in production"]
6992
6992
  })
@@ -7008,7 +7008,7 @@ var init_mockSupabaseVerifier = __esm({
7008
7008
  providerActual: "Live RLS state unknown without Supabase MCP",
7009
7009
  severity: "critical",
7010
7010
  suggestedFix: "repo-fix",
7011
- evidenceRefs: tables.map((table) => `table: ${table}`)
7011
+ evidenceRefs: tables.map((table2) => `table: ${table2}`)
7012
7012
  });
7013
7013
  }
7014
7014
  if (rlsInRepo) {
@@ -8303,7 +8303,7 @@ function replayProject(files, root) {
8303
8303
  }
8304
8304
  }
8305
8305
  const replayed = [...tables.values()];
8306
- for (const table of replayed) table.root = root;
8306
+ for (const table2 of replayed) table2.root = root;
8307
8307
  return { tables: replayed, functions: [...functions.values()], statementsSeen };
8308
8308
  }
8309
8309
  function isSqlTestPath(path) {
@@ -8574,38 +8574,38 @@ function analyzeRls(replay) {
8574
8574
  const noPolicies = [];
8575
8575
  const permissive = [];
8576
8576
  const rlsEnabledEvidence = [];
8577
- for (const table of replay.tables) {
8578
- if (table.schema !== "public") continue;
8579
- if (table.rls) {
8580
- rlsEnabledEvidence.push(`${at(table.rlsLoc)}: row level security enabled on ${safe(table.display)}`);
8577
+ for (const table2 of replay.tables) {
8578
+ if (table2.schema !== "public") continue;
8579
+ if (table2.rls) {
8580
+ rlsEnabledEvidence.push(`${at(table2.rlsLoc)}: row level security enabled on ${safe(table2.display)}`);
8581
8581
  }
8582
- if (!table.rls && (table.created || table.disabledLoc)) {
8583
- const where = table.disabledLoc ?? table.arrivedLoc ?? table.created;
8582
+ if (!table2.rls && (table2.created || table2.disabledLoc)) {
8583
+ const where = table2.disabledLoc ?? table2.arrivedLoc ?? table2.created;
8584
8584
  const risk = "Anyone holding the anon key your frontend ships can read and change every row through the Data API (unless the table's grants were revoked).";
8585
- const message = table.disabledLoc ? `${table.display} has row level security turned off at ${at(table.disabledLoc)}. ${risk}` : table.arrivedLoc ? `${table.display} is moved into public at ${at(table.arrivedLoc)} without row level security, and no later migration enables it. ${risk}` : `${table.display} is created at ${at(table.created)} and no migration enables row level security on it. ${risk}`;
8585
+ const message = table2.disabledLoc ? `${table2.display} has row level security turned off at ${at(table2.disabledLoc)}. ${risk}` : table2.arrivedLoc ? `${table2.display} is moved into public at ${at(table2.arrivedLoc)} without row level security, and no later migration enables it. ${risk}` : `${table2.display} is created at ${at(table2.created)} and no migration enables row level security on it. ${risk}`;
8586
8586
  missingRls.push({
8587
8587
  id: "rls_disabled",
8588
8588
  severity: "critical",
8589
8589
  message: safe(message),
8590
8590
  file: where?.file,
8591
8591
  line: where?.line,
8592
- table: table.display,
8593
- fix: `alter table ${table.display} enable row level security;`
8592
+ table: table2.display,
8593
+ fix: `alter table ${table2.display} enable row level security;`
8594
8594
  });
8595
8595
  }
8596
- if (table.rls && table.policies.size === 0) {
8596
+ if (table2.rls && table2.policies.size === 0) {
8597
8597
  noPolicies.push({
8598
8598
  id: "rls_no_policies",
8599
8599
  severity: "info",
8600
8600
  message: safe(
8601
- `${table.display} has row level security on and no policies, so it is locked to the service role: the browser client gets no rows back and cannot write. Fine for server-only tables; add policies if the app reads it from the frontend.`
8601
+ `${table2.display} has row level security on and no policies, so it is locked to the service role: the browser client gets no rows back and cannot write. Fine for server-only tables; add policies if the app reads it from the frontend.`
8602
8602
  ),
8603
- file: table.rlsLoc?.file,
8604
- line: table.rlsLoc?.line,
8605
- table: table.display
8603
+ file: table2.rlsLoc?.file,
8604
+ line: table2.rlsLoc?.line,
8605
+ table: table2.display
8606
8606
  });
8607
8607
  }
8608
- for (const policy of table.policies.values()) {
8608
+ for (const policy of table2.policies.values()) {
8609
8609
  if (!policy.permissive) continue;
8610
8610
  const roles = policy.roles.filter((r) => r === "public" || r === "anon" || r === "authenticated");
8611
8611
  if (roles.length === 0) continue;
@@ -8618,11 +8618,11 @@ function analyzeRls(replay) {
8618
8618
  id: "rls_policy_allows_all_read",
8619
8619
  severity: "high",
8620
8620
  message: safe(
8621
- `Policy "${policy.name}" on ${table.display} (${at(policy.loc)}) lets ${who} read every row: using (true). Fine for truly public content; wrong for anything per-user.`
8621
+ `Policy "${policy.name}" on ${table2.display} (${at(policy.loc)}) lets ${who} read every row: using (true). Fine for truly public content; wrong for anything per-user.`
8622
8622
  ),
8623
8623
  file: policy.loc.file,
8624
8624
  line: policy.loc.line,
8625
- table: table.display,
8625
+ table: table2.display,
8626
8626
  policy: policy.name
8627
8627
  });
8628
8628
  continue;
@@ -8650,10 +8650,10 @@ function analyzeRls(replay) {
8650
8650
  permissive.push({
8651
8651
  id: "rls_policy_allows_all_write",
8652
8652
  severity,
8653
- message: safe(`Policy "${policy.name}" on ${table.display} (${at(policy.loc)}) lets ${who} ${verb}: ${clause}.`),
8653
+ message: safe(`Policy "${policy.name}" on ${table2.display} (${at(policy.loc)}) lets ${who} ${verb}: ${clause}.`),
8654
8654
  file: policy.loc.file,
8655
8655
  line: policy.loc.line,
8656
- table: table.display,
8656
+ table: table2.display,
8657
8657
  policy: policy.name
8658
8658
  });
8659
8659
  }
@@ -8733,35 +8733,35 @@ function analyzeGrants(replay, uses, autoExpose) {
8733
8733
  if (existing) use.ops.forEach((op) => existing.ops.add(op));
8734
8734
  else byName.set(use.table, { ...use, ops: new Set(use.ops) });
8735
8735
  }
8736
- for (const table of replay.tables) {
8737
- if (table.schema !== "public") continue;
8738
- const granted = table.grants.size > 0;
8739
- if (granted && !table.rls) {
8740
- const roles2 = [...new Set([...table.grants].map((g2) => g2.split(":")[0]))].join(" and ");
8736
+ for (const table2 of replay.tables) {
8737
+ if (table2.schema !== "public") continue;
8738
+ const granted = table2.grants.size > 0;
8739
+ if (granted && !table2.rls) {
8740
+ const roles2 = [...new Set([...table2.grants].map((g2) => g2.split(":")[0]))].join(" and ");
8741
8741
  out.push({
8742
8742
  id: "data_api_grant_without_rls",
8743
8743
  severity: "critical",
8744
8744
  message: safe(
8745
- `${table.display} is granted to ${roles2} (${at(table.grantLoc)}) but row level security is off. A grant without RLS is the dangerous combination: the Data API serves every row to that role. Enable RLS and add policies before granting.`
8745
+ `${table2.display} is granted to ${roles2} (${at(table2.grantLoc)}) but row level security is off. A grant without RLS is the dangerous combination: the Data API serves every row to that role. Enable RLS and add policies before granting.`
8746
8746
  ),
8747
- file: table.grantLoc?.file,
8748
- line: table.grantLoc?.line,
8749
- table: table.display,
8750
- fix: `alter table ${table.display} enable row level security;`
8747
+ file: table2.grantLoc?.file,
8748
+ line: table2.grantLoc?.line,
8749
+ table: table2.display,
8750
+ fix: `alter table ${table2.display} enable row level security;`
8751
8751
  });
8752
8752
  continue;
8753
8753
  }
8754
- if (!table.created || !table.rls) continue;
8754
+ if (!table2.created || !table2.rls) continue;
8755
8755
  const configOff = autoExpose && !autoExpose.value ? autoExpose : void 0;
8756
- const revokedAtCreate = table.defaultsRevoked ?? /* @__PURE__ */ new Set();
8756
+ const revokedAtCreate = table2.defaultsRevoked ?? /* @__PURE__ */ new Set();
8757
8757
  if (revokedAtCreate.size === 0 && !configOff) continue;
8758
- const use = byName.get(table.name);
8758
+ const use = byName.get(table2.name);
8759
8759
  if (!use) continue;
8760
- const lacks = (role, priv) => !table.grants.has(`${role}:${priv}`) && (configOff !== void 0 || revokedAtCreate.has(`${role}:${priv}`));
8760
+ const lacks = (role, priv) => !table2.grants.has(`${role}:${priv}`) && (configOff !== void 0 || revokedAtCreate.has(`${role}:${priv}`));
8761
8761
  const rolesFor = (priv) => {
8762
- if (!table.rls) return [...DATA_API_ROLES];
8762
+ if (!table2.rls) return [...DATA_API_ROLES];
8763
8763
  return expandRoles(
8764
- [...table.policies.values()].filter((p2) => p2.permissive && (p2.command === priv || p2.command === "all")).flatMap((p2) => p2.roles)
8764
+ [...table2.policies.values()].filter((p2) => p2.permissive && (p2.command === priv || p2.command === "all")).flatMap((p2) => p2.roles)
8765
8765
  );
8766
8766
  };
8767
8767
  const blocked = /* @__PURE__ */ new Map();
@@ -8773,17 +8773,17 @@ function analyzeGrants(replay, uses, autoExpose) {
8773
8773
  if (blocked.size === 0) continue;
8774
8774
  const privs = [...blocked.keys()];
8775
8775
  const roles = [...new Set([...blocked.values()].flat())];
8776
- const reason = configOff ? `${configOff.file}:${configOff.line} sets auto_expose_new_tables = false, so new public tables get no default grants` : `the default grants for new public tables are revoked at ${at(table.defaultsRevokedLoc)}`;
8777
- const fix = `grant ${privs.join(", ")} on table ${table.display} to ${roles.join(", ")};`;
8776
+ const reason = configOff ? `${configOff.file}:${configOff.line} sets auto_expose_new_tables = false, so new public tables get no default grants` : `the default grants for new public tables are revoked at ${at(table2.defaultsRevokedLoc)}`;
8777
+ const fix = `grant ${privs.join(", ")} on table ${table2.display} to ${roles.join(", ")};`;
8778
8778
  out.push({
8779
8779
  id: "data_api_grant_missing",
8780
8780
  severity: "warning",
8781
8781
  message: safe(
8782
- `${table.display} is used from the client (${use.file}:${use.line}) for ${privs.join(", ")}, but ${roles.join(" and ")} ${roles.length === 1 ? "has" : "have"} no ${privs.join("/")} grant on it: ${reason}, and no migration grants it back. Those calls get "permission denied for table ${table.name}". Add to a migration: ${fix}`
8782
+ `${table2.display} is used from the client (${use.file}:${use.line}) for ${privs.join(", ")}, but ${roles.join(" and ")} ${roles.length === 1 ? "has" : "have"} no ${privs.join("/")} grant on it: ${reason}, and no migration grants it back. Those calls get "permission denied for table ${table2.name}". Add to a migration: ${fix}`
8783
8783
  ),
8784
- file: table.created.file,
8785
- line: table.created.line,
8786
- table: table.display,
8784
+ file: table2.created.file,
8785
+ line: table2.created.line,
8786
+ table: table2.display,
8787
8787
  fix
8788
8788
  });
8789
8789
  }
@@ -10291,10 +10291,10 @@ async function listTrackedIgnoredFiles(workspacePath) {
10291
10291
  return { paths: [], incomplete: false };
10292
10292
  }
10293
10293
  try {
10294
- const git = await safeGitInvocation(workspacePath, ["ls-files", "-c", "-i", "--exclude-standard", "-z"]);
10295
- const { stdout } = await execFileAsync2("git", git.args, {
10294
+ const git2 = await safeGitInvocation(workspacePath, ["ls-files", "-c", "-i", "--exclude-standard", "-z"]);
10295
+ const { stdout } = await execFileAsync2("git", git2.args, {
10296
10296
  cwd: workspacePath,
10297
- env: git.env,
10297
+ env: git2.env,
10298
10298
  timeout: GIT_TIMEOUT_MS,
10299
10299
  maxBuffer: GIT_MAX_OUTPUT_BYTES,
10300
10300
  windowsHide: true
@@ -10318,14 +10318,14 @@ async function collectDatabaseEvidence(workspacePath, scan) {
10318
10318
  [...scan.fileTree.split("\n"), ...scan.secretsFound, ...walk.listed, ...trackedIgnored.paths].map((p2) => normalizedPath(p2.trim()))
10319
10319
  )
10320
10320
  ].filter((p2) => p2.length > 0 && !isOwnArtifact(p2) && !fullyLoaded.has(p2));
10321
- const wanted = [
10321
+ const wanted2 = [
10322
10322
  ...candidates.filter((p2) => EVIDENCE_MANIFEST.test(p2)),
10323
10323
  ...candidates.filter((p2) => !EVIDENCE_MANIFEST.test(p2) && EVIDENCE_CODE.test(p2))
10324
10324
  ];
10325
- if (wanted.length > EVIDENCE_MAX_FILES) incomplete = true;
10325
+ if (wanted2.length > EVIDENCE_MAX_FILES) incomplete = true;
10326
10326
  const files = [];
10327
10327
  let bytesRead = 0;
10328
- for (const path of wanted.slice(0, EVIDENCE_MAX_FILES)) {
10328
+ for (const path of wanted2.slice(0, EVIDENCE_MAX_FILES)) {
10329
10329
  if (bytesRead >= EVIDENCE_MAX_TOTAL_BYTES) {
10330
10330
  incomplete = true;
10331
10331
  break;
@@ -10669,8 +10669,8 @@ function noReleaseTagsSeed(commitCount) {
10669
10669
  }
10670
10670
  async function detectReleaseTagGap(workspacePath) {
10671
10671
  try {
10672
- const git = (args) => safeGitInvocation(workspacePath, args).then((call) => execFileAsync3("git", call.args, { cwd: workspacePath, env: call.env, windowsHide: true }));
10673
- const [tags, count] = await Promise.all([git(["tag", "--list"]), git(["rev-list", "--count", "HEAD"])]);
10672
+ const git2 = (args) => safeGitInvocation(workspacePath, args).then((call) => execFileAsync3("git", call.args, { cwd: workspacePath, env: call.env, windowsHide: true }));
10673
+ const [tags, count] = await Promise.all([git2(["tag", "--list"]), git2(["rev-list", "--count", "HEAD"])]);
10674
10674
  const tagCount = tags.stdout.split("\n").filter((line) => line.trim().length > 0).length;
10675
10675
  const commitCount = Number.parseInt(count.stdout.trim(), 10) || 0;
10676
10676
  if (tagCount === 0 && commitCount >= 20) {
@@ -12420,7 +12420,7 @@ var init_agentSummary = __esm({
12420
12420
 
12421
12421
  // src/heal/rlsMigrationTarget.ts
12422
12422
  function rlsEnableStatements(tables) {
12423
- return [...new Set(tables)].map((table) => `alter table ${table} enable row level security;`);
12423
+ return [...new Set(tables)].map((table2) => `alter table ${table2} enable row level security;`);
12424
12424
  }
12425
12425
  function migrationStamp(now) {
12426
12426
  return now.toISOString().replace(/\D/g, "").slice(0, 14);
@@ -13688,12 +13688,12 @@ function createAppWindowOpenCommands(target, platform = process.platform, env =
13688
13688
  }
13689
13689
  async function openWithSystemDefault(target) {
13690
13690
  const { command, args, shell } = createOpenCommand(target);
13691
- await new Promise((resolve9, reject) => {
13691
+ await new Promise((resolve10, reject) => {
13692
13692
  const child = (0, import_node_child_process4.spawn)(command, args, { stdio: "ignore", shell });
13693
13693
  child.on("error", reject);
13694
13694
  child.on("exit", (code) => {
13695
13695
  if (code === 0) {
13696
- resolve9();
13696
+ resolve10();
13697
13697
  } else {
13698
13698
  reject(new Error(`Could not open browser (exit ${code ?? "unknown"}). Open manually: ${target}`));
13699
13699
  }
@@ -13704,7 +13704,7 @@ async function spawnDetached(command) {
13704
13704
  if (/^[A-Za-z]:[\\/]/.test(command.command) && !(0, import_node_fs8.existsSync)(command.command)) {
13705
13705
  throw new Error(`Browser not found: ${command.command}`);
13706
13706
  }
13707
- await new Promise((resolve9, reject) => {
13707
+ await new Promise((resolve10, reject) => {
13708
13708
  const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
13709
13709
  detached: true,
13710
13710
  stdio: "ignore",
@@ -13712,7 +13712,7 @@ async function spawnDetached(command) {
13712
13712
  });
13713
13713
  child.once("spawn", () => {
13714
13714
  child.unref();
13715
- resolve9();
13715
+ resolve10();
13716
13716
  });
13717
13717
  child.once("error", reject);
13718
13718
  });
@@ -13780,12 +13780,12 @@ async function copyToClipboard(text) {
13780
13780
  }
13781
13781
  }
13782
13782
  function pipeToCommand(command, text, extraArgs = []) {
13783
- return new Promise((resolve9, reject) => {
13783
+ return new Promise((resolve10, reject) => {
13784
13784
  const child = (0, import_node_child_process5.spawn)(command, extraArgs, { stdio: ["pipe", "ignore", "ignore"] });
13785
13785
  child.on("error", reject);
13786
13786
  child.on("close", (code) => {
13787
13787
  if (code === 0) {
13788
- resolve9();
13788
+ resolve10();
13789
13789
  } else {
13790
13790
  reject(new Error(`${command} exited with code ${code ?? "unknown"}`));
13791
13791
  }
@@ -14690,7 +14690,7 @@ var VERSION;
14690
14690
  var init_version = __esm({
14691
14691
  "src/version.ts"() {
14692
14692
  "use strict";
14693
- VERSION = "1.5.3";
14693
+ VERSION = "1.6.1";
14694
14694
  }
14695
14695
  });
14696
14696
 
@@ -17100,6 +17100,334 @@ var init_runInit = __esm({
17100
17100
  }
17101
17101
  });
17102
17102
 
17103
+ // src/commands/checkChange.ts
17104
+ function findingKey(finding) {
17105
+ return `${finding.id}\0${finding.title}`;
17106
+ }
17107
+ function findingSubjects(finding) {
17108
+ const line = (finding.detail.split("\n").find((part) => part.trim()) ?? "").replace(LOCATION_TEXT, " ");
17109
+ return [...new Set((line.match(SUBJECT) ?? []).map((subject) => subject.toLowerCase()))].sort();
17110
+ }
17111
+ function bySeverity(a, b3) {
17112
+ return SEVERITY_RANK3[a.severity] - SEVERITY_RANK3[b3.severity] || a.title.localeCompare(b3.title);
17113
+ }
17114
+ function compareFindings(base, head, ref, baseCommit) {
17115
+ const baseByKey = new Map(base.map((finding) => [findingKey(finding), finding]));
17116
+ const headKeys = new Set(head.map(findingKey));
17117
+ const introduced = [];
17118
+ const resolved = base.filter((finding) => !headKeys.has(findingKey(finding)));
17119
+ const unchanged = [];
17120
+ for (const finding of head) {
17121
+ const before = baseByKey.get(findingKey(finding));
17122
+ if (!before) {
17123
+ introduced.push(finding);
17124
+ continue;
17125
+ }
17126
+ const was = new Set(findingSubjects(before));
17127
+ const now = findingSubjects(finding);
17128
+ const added = now.filter((subject) => !was.has(subject));
17129
+ const removed = [...was].filter((subject) => !now.includes(subject));
17130
+ if (added.length) introduced.push({ ...finding, subjects: added });
17131
+ else unchanged.push(finding);
17132
+ if (removed.length) resolved.push({ ...before, subjects: removed });
17133
+ }
17134
+ return { base: ref, baseCommit, introduced: introduced.sort(bySeverity), resolved: resolved.sort(bySeverity), unchanged: unchanged.sort(bySeverity) };
17135
+ }
17136
+ async function git(cwd, args) {
17137
+ const call = await safeGitInvocation(cwd, args);
17138
+ const { stdout } = await execFileAsync4("git", call.args, { cwd, env: call.env, windowsHide: true, maxBuffer: 64 * 1024 * 1024 });
17139
+ return stdout;
17140
+ }
17141
+ async function resolveBaseCommit(cwd, ref) {
17142
+ let commit;
17143
+ try {
17144
+ commit = (await git(cwd, ["rev-parse", "--verify", "--end-of-options", `${ref}^{commit}`])).trim();
17145
+ } catch {
17146
+ throw new Error(
17147
+ `Could not find "${ref}" in this repository. Fetch it first (git fetch origin ${ref.replace(/^origin\//, "")}); in GitHub Actions, check out with fetch-depth: 0.`
17148
+ );
17149
+ }
17150
+ try {
17151
+ const mergeBase = (await git(cwd, ["merge-base", commit, "HEAD"])).trim();
17152
+ return mergeBase || commit;
17153
+ } catch {
17154
+ return commit;
17155
+ }
17156
+ }
17157
+ function parseTree(output) {
17158
+ const entries = [];
17159
+ for (const record of output.split("\0")) {
17160
+ if (!record) continue;
17161
+ const tab = record.indexOf(" ");
17162
+ const [mode, type, sha, size] = record.slice(0, tab).trim().split(/\s+/);
17163
+ entries.push({ mode, type, sha, size: Number.parseInt(size, 10) || 0, path: record.slice(tab + 1) });
17164
+ }
17165
+ return entries;
17166
+ }
17167
+ function wanted(entry) {
17168
+ if (entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") return false;
17169
+ if (entry.size > MAX_BLOB_BYTES) return false;
17170
+ return !entry.path.split("/").some((segment) => SKIP_SEGMENTS.has(segment));
17171
+ }
17172
+ async function readBlobs(cwd, shas) {
17173
+ const blobs = /* @__PURE__ */ new Map();
17174
+ if (!shas.length) return blobs;
17175
+ const call = await safeGitInvocation(cwd, ["cat-file", "--batch"]);
17176
+ const output = await new Promise((resolveOutput, reject) => {
17177
+ const child = (0, import_node_child_process6.spawn)("git", call.args, { cwd, env: call.env, windowsHide: true });
17178
+ const chunks = [];
17179
+ let stderr = "";
17180
+ child.stdout.on("data", (chunk) => chunks.push(chunk));
17181
+ child.stderr.on("data", (chunk) => {
17182
+ stderr += chunk.toString();
17183
+ });
17184
+ child.on("error", reject);
17185
+ child.on("close", (code) => code === 0 ? resolveOutput(Buffer.concat(chunks)) : reject(new Error(stderr.trim() || `git cat-file exited with ${code}`)));
17186
+ child.stdin.end(`${shas.join("\n")}
17187
+ `);
17188
+ });
17189
+ let offset = 0;
17190
+ while (offset < output.length) {
17191
+ const newline = output.indexOf(10, offset);
17192
+ if (newline === -1) break;
17193
+ const [sha, type, sizeText] = output.subarray(offset, newline).toString().split(" ");
17194
+ offset = newline + 1;
17195
+ if (type === "missing" || sizeText === void 0) continue;
17196
+ const size = Number.parseInt(sizeText, 10);
17197
+ blobs.set(sha, output.subarray(offset, offset + size));
17198
+ offset += size + 1;
17199
+ }
17200
+ return blobs;
17201
+ }
17202
+ async function exportCommit(cwd, commit) {
17203
+ const entries = parseTree(await git(cwd, ["ls-tree", "-r", "-z", "-l", "--full-tree", commit])).filter(wanted);
17204
+ const blobs = await readBlobs(cwd, [...new Set(entries.map((entry) => entry.sha))]);
17205
+ const root = await (0, import_promises23.mkdtemp)((0, import_node_path30.join)((0, import_node_os.tmpdir)(), "viberaven-base-"));
17206
+ for (const entry of entries) {
17207
+ const target = (0, import_node_path30.resolve)(root, ...entry.path.split("/"));
17208
+ if (!target.startsWith(root + import_node_path30.sep)) continue;
17209
+ const content = blobs.get(entry.sha);
17210
+ if (!content) continue;
17211
+ await (0, import_promises23.mkdir)((0, import_node_path30.dirname)(target), { recursive: true });
17212
+ await (0, import_promises23.writeFile)(target, content);
17213
+ }
17214
+ return root;
17215
+ }
17216
+ async function checkChange(cwd, ref, head) {
17217
+ const baseCommit = await resolveBaseCommit(cwd, ref);
17218
+ const folder = await exportCommit(cwd, baseCommit);
17219
+ try {
17220
+ const result = await runProjectScan({ workspacePath: folder });
17221
+ if (!result.ok) throw new Error(`The check on ${ref} did not finish: ${result.message}`);
17222
+ return compareFindings(result.artifact.gaps, head, ref, baseCommit);
17223
+ } finally {
17224
+ await (0, import_promises23.rm)(folder, { recursive: true, force: true, maxRetries: 3, retryDelay: 200 }).catch(() => void 0);
17225
+ }
17226
+ }
17227
+ function cell(text) {
17228
+ return text.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
17229
+ }
17230
+ function firstLine(detail) {
17231
+ const line = detail.split("\n").map((part) => part.trim()).find(Boolean) ?? "";
17232
+ return line.length > 180 ? `${line.slice(0, 177)}\u2026` : line;
17233
+ }
17234
+ function plural2(count, word) {
17235
+ return `${count} ${word}${count === 1 ? "" : "s"}`;
17236
+ }
17237
+ function table(findings) {
17238
+ return [
17239
+ "| | Finding | Check |",
17240
+ "|---|---|---|",
17241
+ ...findings.map((finding) => {
17242
+ const why = finding.subjects?.length ? `New in this change: ${finding.subjects.join(", ")}` : firstLine(finding.detail);
17243
+ return `| ${DOT[finding.severity]} | **${cell(finding.title)}**${why ? `<br>${cell(why)}` : ""} | \`${cell(finding.id)}\` |`;
17244
+ })
17245
+ ];
17246
+ }
17247
+ function fixedLabel(finding) {
17248
+ return `\u2705 ${cell(finding.title)}${finding.subjects?.length ? ` for ${cell(finding.subjects.join(", "))}` : ""} (\`${cell(finding.id)}\`)`;
17249
+ }
17250
+ function renderCheckMarkdown({ head, change, version, score }) {
17251
+ const lines = [COMMENT_MARKER];
17252
+ const sorted = [...head].sort(bySeverity);
17253
+ const critical = sorted.filter((finding) => finding.severity === "critical").length;
17254
+ const warnings = sorted.filter((finding) => finding.severity === "warning").length;
17255
+ if (change) {
17256
+ const newCritical = change.introduced.filter((finding) => finding.severity === "critical").length;
17257
+ const headline = newCritical ? `${plural2(newCritical, "new blocker")} in this change` : change.introduced.length ? `${plural2(change.introduced.length, "new finding")} in this change, no new blockers` : "No new findings in this change";
17258
+ lines.push(`### VibeRaven \xB7 ${headline}`, "");
17259
+ lines.push(`Compared with \`${change.base}\` (${change.baseCommit.slice(0, 7)}).${change.resolved.length ? ` This change fixes ${plural2(change.resolved.length, "finding")}.` : ""}`, "");
17260
+ if (change.introduced.length) lines.push(...table(change.introduced), "");
17261
+ if (change.resolved.length) {
17262
+ lines.push(`**Fixed by this change:** ${change.resolved.map(fixedLabel).join(" \xB7 ")}`, "");
17263
+ }
17264
+ if (change.unchanged.length) {
17265
+ lines.push(`<details><summary>Already in ${cell(change.base)} before this change (${change.unchanged.length})</summary>`, "", ...table(change.unchanged), "", "</details>", "");
17266
+ }
17267
+ const firstNew = change.introduced.find((finding) => finding.severity === "critical") ?? change.introduced[0];
17268
+ if (firstNew) lines.push(`Fix it with your coding agent: \`npx -y viberaven fix --gap ${firstNew.id}\`, or open the Studio with \`npx -y viberaven\`.`, "");
17269
+ } else {
17270
+ const headline = critical ? `${plural2(critical, "blocker")}, ${plural2(warnings, "warning")}` : `No blockers, ${plural2(warnings, "warning")}`;
17271
+ lines.push(`### VibeRaven \xB7 ${headline}`, "");
17272
+ if (sorted.length) lines.push(...table(sorted), "");
17273
+ else lines.push("No launch findings in the repo evidence.", "");
17274
+ }
17275
+ lines.push(
17276
+ `<sub>viberaven ${version}${typeof score === "number" ? ` \xB7 readiness ${score}/100` : ""} \xB7 checked where it ran, nothing was uploaded. Advice, not a gate: a clear result reads the repo, it is not a security audit.</sub>`
17277
+ );
17278
+ return `${lines.join("\n")}
17279
+ `;
17280
+ }
17281
+ var import_node_child_process6, import_promises23, import_node_os, import_node_path30, import_node_util4, execFileAsync4, MAX_BLOB_BYTES, SKIP_SEGMENTS, SEVERITY_RANK3, LOCATION_TEXT, SUBJECT, COMMENT_MARKER, DOT;
17282
+ var init_checkChange = __esm({
17283
+ "src/commands/checkChange.ts"() {
17284
+ "use strict";
17285
+ import_node_child_process6 = require("node:child_process");
17286
+ import_promises23 = require("node:fs/promises");
17287
+ import_node_os = require("node:os");
17288
+ import_node_path30 = require("node:path");
17289
+ import_node_util4 = require("node:util");
17290
+ init_runScan();
17291
+ init_safeGit();
17292
+ execFileAsync4 = (0, import_node_util4.promisify)(import_node_child_process6.execFile);
17293
+ MAX_BLOB_BYTES = 1e6;
17294
+ SKIP_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", ".turbo", ".vercel", ".output", "dist", "build", "coverage"]);
17295
+ SEVERITY_RANK3 = { critical: 0, warning: 1, info: 2 };
17296
+ LOCATION_TEXT = /[\w./\\-]+\.(?:sql|tsx?|jsx?|mjs|cjs|json|toml|ya?ml|env|prisma|md)(?::\d+)?/gi;
17297
+ SUBJECT = /\b[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*\b/gi;
17298
+ COMMENT_MARKER = "<!-- viberaven-check -->";
17299
+ DOT = { critical: "\u{1F534}", warning: "\u{1F7E1}", info: "\u26AA" };
17300
+ }
17301
+ });
17302
+
17303
+ // src/commands/initGithub.ts
17304
+ function renderWorkflow(version = VERSION) {
17305
+ return [
17306
+ "# VibeRaven checks every pull request in this repository's own GitHub Actions run.",
17307
+ "# The code is read on the runner and never uploaded. Written by `npx -y viberaven init --github`.",
17308
+ "name: VibeRaven",
17309
+ "",
17310
+ "on:",
17311
+ " pull_request:",
17312
+ "",
17313
+ "permissions:",
17314
+ " contents: read",
17315
+ " pull-requests: write",
17316
+ "",
17317
+ "jobs:",
17318
+ " check:",
17319
+ " name: Launch check",
17320
+ " runs-on: ubuntu-latest",
17321
+ " steps:",
17322
+ " - uses: actions/checkout@v4",
17323
+ " with:",
17324
+ " fetch-depth: 0",
17325
+ "",
17326
+ " - uses: actions/setup-node@v4",
17327
+ " with:",
17328
+ " node-version: 20",
17329
+ "",
17330
+ " - name: Check this change",
17331
+ " id: check",
17332
+ " env:",
17333
+ " BASE_REF: ${{ github.base_ref }}",
17334
+ " run: |",
17335
+ " code=0",
17336
+ ` npx -y viberaven@${version} check --base "origin/$BASE_REF" --markdown > viberaven-check.md || code=$?`,
17337
+ ' cat viberaven-check.md >> "$GITHUB_STEP_SUMMARY"',
17338
+ ' echo "code=$code" >> "$GITHUB_OUTPUT"',
17339
+ "",
17340
+ " # Pull requests from forks get a read-only token: they keep the job summary and skip the comment.",
17341
+ " - name: Comment on the pull request",
17342
+ " if: github.event.pull_request.head.repo.full_name == github.repository",
17343
+ " env:",
17344
+ " GH_TOKEN: ${{ github.token }}",
17345
+ " PR: ${{ github.event.pull_request.number }}",
17346
+ " run: |",
17347
+ ` id=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR/comments" --paginate --jq '.[] | select(.body | contains("${COMMENT_MARKER}")) | .id' | tail -n 1)`,
17348
+ ' if [ -n "$id" ]; then',
17349
+ ' gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$id" -F body=@viberaven-check.md > /dev/null',
17350
+ " else",
17351
+ ' gh pr comment "$PR" --body-file viberaven-check.md',
17352
+ " fi",
17353
+ "",
17354
+ " # Advice, not a gate. To block merging when a change adds a launch blocker, uncomment this step",
17355
+ ' # and mark "Launch check" as required in the branch protection settings.',
17356
+ " # - name: Fail on new blockers",
17357
+ " # if: steps.check.outputs.code == '1'",
17358
+ " # run: exit 1",
17359
+ ""
17360
+ ].join("\n");
17361
+ }
17362
+ async function hasGithubRemote(cwd) {
17363
+ try {
17364
+ const call = await safeGitInvocation(cwd, ["remote", "-v"]);
17365
+ const { stdout } = await execFileAsync5("git", call.args, { cwd, env: call.env, windowsHide: true });
17366
+ return /github\.com[:/]/i.test(stdout);
17367
+ } catch {
17368
+ return false;
17369
+ }
17370
+ }
17371
+ async function githubWorkflowStatus(cwd) {
17372
+ return { exists: (0, import_node_fs14.existsSync)((0, import_node_path31.join)(cwd, WORKFLOW_PATH)), path: DISPLAY_PATH, onGithub: await hasGithubRemote(cwd) };
17373
+ }
17374
+ async function writeGithubWorkflow(cwd, options = {}) {
17375
+ const target = (0, import_node_path31.join)(cwd, WORKFLOW_PATH);
17376
+ if ((0, import_node_fs14.existsSync)(target) && !options.force) return { written: false, status: await githubWorkflowStatus(cwd) };
17377
+ await (0, import_promises24.mkdir)((0, import_node_path31.dirname)(target), { recursive: true });
17378
+ await (0, import_promises24.writeFile)(target, renderWorkflow(), "utf8");
17379
+ return { written: true, status: await githubWorkflowStatus(cwd) };
17380
+ }
17381
+ async function runInitGithubCommand(options) {
17382
+ if (options.dryRun) {
17383
+ console.log(`Would write ${DISPLAY_PATH}:
17384
+ `);
17385
+ console.log(renderWorkflow());
17386
+ return 0;
17387
+ }
17388
+ const { written, status } = await writeGithubWorkflow(options.cwd, { force: options.force });
17389
+ if (!written) {
17390
+ console.log(`${DISPLAY_PATH} already exists. Nothing changed. Run with --force to replace it.`);
17391
+ return 0;
17392
+ }
17393
+ console.log(`Wrote ${DISPLAY_PATH}.`);
17394
+ console.log("");
17395
+ console.log("Commit it, and every pull request gets one VibeRaven comment with what the change added or fixed:");
17396
+ console.log(` git add ${DISPLAY_PATH} && git commit -m "Check pull requests with VibeRaven"`);
17397
+ console.log("");
17398
+ console.log("It runs in your own GitHub Actions, so private repositories work and the code is never uploaded.");
17399
+ if (!status.onGithub) console.log("This repository has no github.com remote yet: the workflow runs once it is pushed to GitHub.");
17400
+ return 0;
17401
+ }
17402
+ var import_node_child_process7, import_node_fs14, import_promises24, import_node_path31, import_node_util5, execFileAsync5, WORKFLOW_PATH, DISPLAY_PATH;
17403
+ var init_initGithub = __esm({
17404
+ "src/commands/initGithub.ts"() {
17405
+ "use strict";
17406
+ import_node_child_process7 = require("node:child_process");
17407
+ import_node_fs14 = require("node:fs");
17408
+ import_promises24 = require("node:fs/promises");
17409
+ import_node_path31 = require("node:path");
17410
+ import_node_util5 = require("node:util");
17411
+ init_safeGit();
17412
+ init_version();
17413
+ init_checkChange();
17414
+ execFileAsync5 = (0, import_node_util5.promisify)(import_node_child_process7.execFile);
17415
+ WORKFLOW_PATH = (0, import_node_path31.join)(".github", "workflows", "viberaven.yml");
17416
+ DISPLAY_PATH = ".github/workflows/viberaven.yml";
17417
+ }
17418
+ });
17419
+
17420
+ // src/local-ui/stack/setupLink.ts
17421
+ function setupFragment(ids) {
17422
+ const safe2 = [...new Set(ids.filter((id) => /^[a-z][a-z0-9-]{0,39}$/.test(id)))].slice(0, 30);
17423
+ return `#${new URLSearchParams({ stack: safe2.join(",") })}`;
17424
+ }
17425
+ var init_setupLink = __esm({
17426
+ "src/local-ui/stack/setupLink.ts"() {
17427
+ "use strict";
17428
+ }
17429
+ });
17430
+
17103
17431
  // src/commands/doctorAgents.ts
17104
17432
  function managedBlocks(content) {
17105
17433
  const blocks = content.match(/<!-- (?:VIBERAVEN:START|viberaven:agent-rules:start) -->[\s\S]*?<!-- (?:VIBERAVEN:END|viberaven:agent-rules:end) -->/g);
@@ -17108,7 +17436,7 @@ function managedBlocks(content) {
17108
17436
  async function checkAgentInjection(cwd) {
17109
17437
  const checks = [];
17110
17438
  for (const item4 of REQUIRED_EXISTENCE_CHECKS) {
17111
- const exists = await fileExists2((0, import_node_path30.join)(cwd, item4.file));
17439
+ const exists = await fileExists2((0, import_node_path32.join)(cwd, item4.file));
17112
17440
  checks.push({
17113
17441
  id: item4.id,
17114
17442
  status: exists ? "pass" : "fail",
@@ -17116,17 +17444,17 @@ async function checkAgentInjection(cwd) {
17116
17444
  });
17117
17445
  }
17118
17446
  for (const item4 of OPTIONAL_CURSOR_PACK_CHECKS) {
17119
- const exists = await fileExists2((0, import_node_path30.join)(cwd, item4.file));
17447
+ const exists = await fileExists2((0, import_node_path32.join)(cwd, item4.file));
17120
17448
  checks.push({
17121
17449
  id: item4.id,
17122
17450
  status: exists ? "pass" : "fail",
17123
17451
  message: exists ? `${item4.file} exists` : `Missing ${item4.file} \u2014 run npx -y viberaven init --agents all`
17124
17452
  });
17125
17453
  }
17126
- const legacyCursorPath = (0, import_node_path30.join)(cwd, ".cursor/rules/viberaven.mdc");
17454
+ const legacyCursorPath = (0, import_node_path32.join)(cwd, ".cursor/rules/viberaven.mdc");
17127
17455
  if (await fileExists2(legacyCursorPath)) {
17128
- const legacyContent = await (0, import_promises23.readFile)(legacyCursorPath, "utf-8");
17129
- const hasCoreSplit = await fileExists2((0, import_node_path30.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
17456
+ const legacyContent = await (0, import_promises25.readFile)(legacyCursorPath, "utf-8");
17457
+ const hasCoreSplit = await fileExists2((0, import_node_path32.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
17130
17458
  if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
17131
17459
  checks.push({
17132
17460
  id: "cursor-legacy-mdc",
@@ -17137,7 +17465,7 @@ async function checkAgentInjection(cwd) {
17137
17465
  }
17138
17466
  for (const target of CORE_AGENT_INJECTION_TARGETS) {
17139
17467
  const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
17140
- const path = (0, import_node_path30.join)(cwd, file);
17468
+ const path = (0, import_node_path32.join)(cwd, file);
17141
17469
  const exists = await fileExists2(path);
17142
17470
  if (!exists) {
17143
17471
  checks.push({
@@ -17147,7 +17475,7 @@ async function checkAgentInjection(cwd) {
17147
17475
  });
17148
17476
  continue;
17149
17477
  }
17150
- const content = await (0, import_promises23.readFile)(path, "utf-8");
17478
+ const content = await (0, import_promises25.readFile)(path, "utf-8");
17151
17479
  const hasCommand = content.includes(PUBLIC_CHECK_COMMAND);
17152
17480
  checks.push({
17153
17481
  id: `canonical-${target}`,
@@ -17190,18 +17518,18 @@ function formatDoctorAgentsReport(report) {
17190
17518
  }
17191
17519
  async function fileExists2(path) {
17192
17520
  try {
17193
- await (0, import_promises23.access)(path);
17521
+ await (0, import_promises25.access)(path);
17194
17522
  return true;
17195
17523
  } catch {
17196
17524
  return false;
17197
17525
  }
17198
17526
  }
17199
- var import_promises23, import_node_path30, REQUIRED_EXISTENCE_CHECKS, OPTIONAL_CURSOR_PACK_CHECKS, STALE_PATTERNS, GATE_RULE_PHRASES_1_5_2;
17527
+ var import_promises25, import_node_path32, REQUIRED_EXISTENCE_CHECKS, OPTIONAL_CURSOR_PACK_CHECKS, STALE_PATTERNS, GATE_RULE_PHRASES_1_5_2;
17200
17528
  var init_doctorAgents = __esm({
17201
17529
  "src/commands/doctorAgents.ts"() {
17202
17530
  "use strict";
17203
- import_promises23 = require("node:fs/promises");
17204
- import_node_path30 = require("node:path");
17531
+ import_promises25 = require("node:fs/promises");
17532
+ import_node_path32 = require("node:path");
17205
17533
  init_commands();
17206
17534
  init_agentTargets();
17207
17535
  REQUIRED_EXISTENCE_CHECKS = [
@@ -17472,7 +17800,7 @@ function buildContextCleanupPlan(input) {
17472
17800
  const items = [];
17473
17801
  const seen = /* @__PURE__ */ new Set();
17474
17802
  for (const file of input.files) {
17475
- const path = normalizePath5((0, import_node_path31.relative)(input.projectRoot, file.path) || file.path);
17803
+ const path = normalizePath5((0, import_node_path33.relative)(input.projectRoot, file.path) || file.path);
17476
17804
  const fullPath = normalizePath5(file.path);
17477
17805
  const category = categorizeCleanupFile(path, fullPath, file);
17478
17806
  if (!category || seen.has(path)) {
@@ -17498,10 +17826,10 @@ async function collectCleanupFiles(projectRoot) {
17498
17826
  return files;
17499
17827
  }
17500
17828
  async function writeCleanupPlan(projectRoot, plan) {
17501
- const outputDir = (0, import_node_path31.join)(projectRoot, ".viberaven");
17502
- const outputPath = (0, import_node_path31.join)(outputDir, "context-cleanup.md");
17503
- await (0, import_promises24.mkdir)(outputDir, { recursive: true });
17504
- await (0, import_promises24.writeFile)(outputPath, renderCleanupPlan(plan), "utf8");
17829
+ const outputDir = (0, import_node_path33.join)(projectRoot, ".viberaven");
17830
+ const outputPath = (0, import_node_path33.join)(outputDir, "context-cleanup.md");
17831
+ await (0, import_promises26.mkdir)(outputDir, { recursive: true });
17832
+ await (0, import_promises26.writeFile)(outputPath, renderCleanupPlan(plan), "utf8");
17505
17833
  return outputPath;
17506
17834
  }
17507
17835
  function categorizeCleanupFile(relativePath, fullPath, file) {
@@ -17549,7 +17877,7 @@ async function walkCleanupFiles(root, dir, result, depth) {
17549
17877
  }
17550
17878
  let entries;
17551
17879
  try {
17552
- entries = await (0, import_promises24.readdir)(dir, { withFileTypes: true });
17880
+ entries = await (0, import_promises26.readdir)(dir, { withFileTypes: true });
17553
17881
  } catch {
17554
17882
  return;
17555
17883
  }
@@ -17557,9 +17885,9 @@ async function walkCleanupFiles(root, dir, result, depth) {
17557
17885
  if (SKIP_DIRECTORIES.has(entry.name)) {
17558
17886
  continue;
17559
17887
  }
17560
- const absolute = (0, import_node_path31.join)(dir, entry.name);
17888
+ const absolute = (0, import_node_path33.join)(dir, entry.name);
17561
17889
  if (entry.isDirectory()) {
17562
- if (isCachePath(normalizePath5((0, import_node_path31.relative)(root, absolute)))) {
17890
+ if (isCachePath(normalizePath5((0, import_node_path33.relative)(root, absolute)))) {
17563
17891
  result.push({ path: absolute, sizeBytes: 0, kind: "directory" });
17564
17892
  continue;
17565
17893
  }
@@ -17570,7 +17898,7 @@ async function walkCleanupFiles(root, dir, result, depth) {
17570
17898
  continue;
17571
17899
  }
17572
17900
  try {
17573
- const fileStat = await (0, import_promises24.stat)(absolute);
17901
+ const fileStat = await (0, import_promises26.stat)(absolute);
17574
17902
  result.push({ path: absolute, sizeBytes: fileStat.size, kind: "file" });
17575
17903
  } catch {
17576
17904
  continue;
@@ -17580,12 +17908,12 @@ async function walkCleanupFiles(root, dir, result, depth) {
17580
17908
  function normalizePath5(path) {
17581
17909
  return path.replace(/\\/g, "/");
17582
17910
  }
17583
- var import_promises24, import_node_path31, MAX_WALK_DEPTH, LARGE_LOG_BYTES, SKIP_DIRECTORIES;
17911
+ var import_promises26, import_node_path33, MAX_WALK_DEPTH, LARGE_LOG_BYTES, SKIP_DIRECTORIES;
17584
17912
  var init_cleanPlan = __esm({
17585
17913
  "src/commands/cleanPlan.ts"() {
17586
17914
  "use strict";
17587
- import_promises24 = require("node:fs/promises");
17588
- import_node_path31 = require("node:path");
17915
+ import_promises26 = require("node:fs/promises");
17916
+ import_node_path33 = require("node:path");
17589
17917
  MAX_WALK_DEPTH = 5;
17590
17918
  LARGE_LOG_BYTES = 8192;
17591
17919
  SKIP_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
@@ -17698,10 +18026,10 @@ var init_render = __esm({
17698
18026
 
17699
18027
  // src/commands/actions.ts
17700
18028
  async function runActionsCommand(input) {
17701
- const actionsPath = (0, import_node_path32.join)(getProjectArtifactsDir(input.cwd), "actions.json");
18029
+ const actionsPath = (0, import_node_path34.join)(getProjectArtifactsDir(input.cwd), "actions.json");
17702
18030
  let raw;
17703
18031
  try {
17704
- raw = await (0, import_promises25.readFile)(actionsPath, "utf8");
18032
+ raw = await (0, import_promises27.readFile)(actionsPath, "utf8");
17705
18033
  } catch {
17706
18034
  process.stderr.write("No VibeRaven actions found. Run `npx -y viberaven --agent-mode` first.\n");
17707
18035
  return 1;
@@ -17715,12 +18043,12 @@ async function runActionsCommand(input) {
17715
18043
  process.stdout.write(renderActionSurface(manifest));
17716
18044
  return 0;
17717
18045
  }
17718
- var import_promises25, import_node_path32;
18046
+ var import_promises27, import_node_path34;
17719
18047
  var init_actions = __esm({
17720
18048
  "src/commands/actions.ts"() {
17721
18049
  "use strict";
17722
- import_promises25 = require("node:fs/promises");
17723
- import_node_path32 = require("node:path");
18050
+ import_promises27 = require("node:fs/promises");
18051
+ import_node_path34 = require("node:path");
17724
18052
  init_render();
17725
18053
  init_config();
17726
18054
  }
@@ -17729,7 +18057,7 @@ var init_actions = __esm({
17729
18057
  // src/commands/verifyAction.ts
17730
18058
  async function currentActionExists(cwd, actionId) {
17731
18059
  try {
17732
- const raw = await (0, import_promises26.readFile)((0, import_node_path33.join)(getProjectArtifactsDir(cwd), "actions.json"), "utf8");
18060
+ const raw = await (0, import_promises28.readFile)((0, import_node_path35.join)(getProjectArtifactsDir(cwd), "actions.json"), "utf8");
17733
18061
  const manifest = JSON.parse(raw);
17734
18062
  return manifest.actions.some((action) => action.id === actionId);
17735
18063
  } catch {
@@ -17773,12 +18101,12 @@ This only looks the action up. Run \`npx -y viberaven --verify\` to scan the rep
17773
18101
  );
17774
18102
  return 0;
17775
18103
  }
17776
- var import_promises26, import_node_path33;
18104
+ var import_promises28, import_node_path35;
17777
18105
  var init_verifyAction = __esm({
17778
18106
  "src/commands/verifyAction.ts"() {
17779
18107
  "use strict";
17780
- import_promises26 = require("node:fs/promises");
17781
- import_node_path33 = require("node:path");
18108
+ import_promises28 = require("node:fs/promises");
18109
+ import_node_path35 = require("node:path");
17782
18110
  init_registry2();
17783
18111
  init_config();
17784
18112
  }
@@ -17902,11 +18230,36 @@ var init_preview = __esm({
17902
18230
  async function runCheckCommand(options) {
17903
18231
  const result = await runProjectScan({ workspacePath: options.cwd });
17904
18232
  if (!result.ok) {
18233
+ if (options.markdown) console.log(`${COMMENT_MARKER}
18234
+ ### VibeRaven could not check this change
18235
+
18236
+ ${result.message}
18237
+ `);
17905
18238
  console.error(formatAgentStatus(ERROR, result.message));
17906
18239
  return 2;
17907
18240
  }
17908
18241
  const artifact = result.artifact;
17909
18242
  const paths = await writeScanArtifacts({ artifact, cwd: options.cwd });
18243
+ let change;
18244
+ if (options.base) {
18245
+ try {
18246
+ change = await checkChange(options.cwd, options.base, artifact.gaps);
18247
+ } catch (error) {
18248
+ const message = error instanceof Error ? error.message : String(error);
18249
+ if (options.markdown) console.log(`${COMMENT_MARKER}
18250
+ ### VibeRaven could not compare this change
18251
+
18252
+ ${message}
18253
+ `);
18254
+ console.error(formatAgentStatus(ERROR, message));
18255
+ return 2;
18256
+ }
18257
+ }
18258
+ const failing = change ? change.introduced.some((g2) => g2.severity === "critical") : artifact.gaps.some((g2) => g2.severity === "critical");
18259
+ if (options.markdown) {
18260
+ console.log(renderCheckMarkdown({ head: artifact.gaps, change, version: VERSION, score: artifact.score }));
18261
+ return failing ? 1 : 0;
18262
+ }
17910
18263
  if (options.json) {
17911
18264
  console.log(
17912
18265
  JSON.stringify(
@@ -17921,13 +18274,22 @@ async function runCheckCommand(options) {
17921
18274
  title: gap.title,
17922
18275
  detail: gap.detail
17923
18276
  })),
18277
+ ...change ? {
18278
+ change: {
18279
+ base: change.base,
18280
+ baseCommit: change.baseCommit,
18281
+ introduced: change.introduced.map((gap) => gap.id),
18282
+ resolved: change.resolved.map((gap) => gap.id),
18283
+ unchanged: change.unchanged.map((gap) => gap.id)
18284
+ }
18285
+ } : {},
17924
18286
  artifacts: paths
17925
18287
  },
17926
18288
  null,
17927
18289
  2
17928
18290
  )
17929
18291
  );
17930
- return artifact.gaps.some((g2) => g2.severity === "critical") ? 1 : 0;
18292
+ return failing ? 1 : 0;
17931
18293
  }
17932
18294
  const sorted = [...artifact.gaps].sort(
17933
18295
  (a, b3) => SEVERITY_ORDER3[a.severity] - SEVERITY_ORDER3[b3.severity]
@@ -17937,14 +18299,37 @@ async function runCheckCommand(options) {
17937
18299
  console.log("");
17938
18300
  console.log(`viberaven check \xB7 ${options.cwd}`);
17939
18301
  console.log("");
18302
+ if (change) {
18303
+ const line = (gap) => `${SEVERITY_ICON[gap.severity]} ${gap.title} (${gap.id})`;
18304
+ console.log(`Compared with ${change.base} (${change.baseCommit.slice(0, 7)})`);
18305
+ console.log("");
18306
+ console.log(change.introduced.length ? "New in this change:" : "New in this change: nothing");
18307
+ for (const gap of change.introduced) {
18308
+ console.log(` ${line(gap)}${gap.subjects?.length ? ` new: ${gap.subjects.join(", ")}` : ""}`);
18309
+ if (!options.quiet && !gap.subjects?.length && gap.detail) console.log(` ${gap.detail.split("\n")[0]}`);
18310
+ }
18311
+ if (change.resolved.length) {
18312
+ console.log("Fixed by this change:");
18313
+ for (const gap of change.resolved) console.log(` \u2705 ${gap.title}${gap.subjects?.length ? ` for ${gap.subjects.join(", ")}` : ""} (${gap.id})`);
18314
+ }
18315
+ if (change.unchanged.length) console.log(`Already there before: ${change.unchanged.length}`);
18316
+ const newCritical = change.introduced.filter((g2) => g2.severity === "critical").length;
18317
+ console.log("");
18318
+ console.log(
18319
+ newCritical > 0 ? `Verdict: \u274C ${newCritical} new blocker${newCritical === 1 ? "" : "s"} in this change \xB7 score ${artifact.score}` : `Verdict: \u2705 no new blockers in this change \xB7 score ${artifact.score}`
18320
+ );
18321
+ console.log(`Fix: viberaven fix \xB7 Details: ${paths.tasklistPath}`);
18322
+ console.log("");
18323
+ return failing ? 1 : 0;
18324
+ }
17940
18325
  if (sorted.length === 0) {
17941
18326
  console.log("\u2705 No launch blockers found in repo evidence.");
17942
18327
  } else {
17943
18328
  for (const gap of sorted) {
17944
18329
  console.log(`${SEVERITY_ICON[gap.severity]} ${gap.title} (${gap.id})`);
17945
18330
  if (!options.quiet && gap.detail) {
17946
- const firstLine2 = gap.detail.split("\n")[0];
17947
- console.log(` ${firstLine2}`);
18331
+ const firstLine3 = gap.detail.split("\n")[0];
18332
+ console.log(` ${firstLine3}`);
17948
18333
  }
17949
18334
  }
17950
18335
  }
@@ -17963,6 +18348,8 @@ var init_check = __esm({
17963
18348
  init_runScan();
17964
18349
  init_artifacts2();
17965
18350
  init_statusLabels();
18351
+ init_version();
18352
+ init_checkChange();
17966
18353
  SEVERITY_ICON = {
17967
18354
  critical: "\u{1F534}",
17968
18355
  // red circle
@@ -18006,12 +18393,12 @@ function parsePermissionsMatrix(text) {
18006
18393
  } else {
18007
18394
  const seen = /* @__PURE__ */ new Set();
18008
18395
  for (const [key, value] of Object.entries(raw.tables)) {
18009
- const table = parseTable(key, value, problems);
18010
- if (!table) continue;
18011
- const full = `${table.schema}.${table.name}`;
18396
+ const table2 = parseTable(key, value, problems);
18397
+ if (!table2) continue;
18398
+ const full = `${table2.schema}.${table2.name}`;
18012
18399
  if (seen.has(full)) problems.push(`tables[${show(key)}]: ${full} is listed twice`);
18013
18400
  seen.add(full);
18014
- tables.push(table);
18401
+ tables.push(table2);
18015
18402
  }
18016
18403
  }
18017
18404
  if (problems.length > 0) throw new MatrixError(problems);
@@ -18085,10 +18472,10 @@ function parseTable(key, value, problems) {
18085
18472
  }
18086
18473
  const parsed = {};
18087
18474
  for (const action of MATRIX_ACTIONS) {
18088
- const cell = cells[action];
18089
- if (cell === void 0) problems.push(`${actorAt}.${action}: missing; write ${quoteList(CELL_VALUES)}`);
18090
- else if (!CELL_VALUES.includes(cell)) problems.push(`${actorAt}.${action}: must be ${quoteList(CELL_VALUES)} (got ${show(cell)})`);
18091
- else parsed[action] = cell;
18475
+ const cell2 = cells[action];
18476
+ if (cell2 === void 0) problems.push(`${actorAt}.${action}: missing; write ${quoteList(CELL_VALUES)}`);
18477
+ else if (!CELL_VALUES.includes(cell2)) problems.push(`${actorAt}.${action}: must be ${quoteList(CELL_VALUES)} (got ${show(cell2)})`);
18478
+ else parsed[action] = cell2;
18092
18479
  }
18093
18480
  if (cells.reassign !== void 0) {
18094
18481
  if (!CELL_VALUES.includes(cells.reassign)) problems.push(`${actorAt}.reassign: must be ${quoteList(CELL_VALUES)} (got ${show(cells.reassign)})`);
@@ -18308,13 +18695,13 @@ async function createWorkerDatabase(options) {
18308
18695
  const call = (message, timeoutMs) => {
18309
18696
  if (dead) return Promise.reject(dead);
18310
18697
  const id = ++nextId;
18311
- return new Promise((resolve9, reject) => {
18698
+ return new Promise((resolve10, reject) => {
18312
18699
  const timer = setTimeout(() => {
18313
18700
  const error = new RlsTimeoutError(`timed out after ${Math.round(timeoutMs / 1e3)} s`);
18314
18701
  failAll(error);
18315
18702
  void worker.terminate();
18316
18703
  }, timeoutMs);
18317
- pending.set(id, { resolve: resolve9, reject, timer });
18704
+ pending.set(id, { resolve: resolve10, reject, timer });
18318
18705
  worker.postMessage({ ...message, id });
18319
18706
  });
18320
18707
  };
@@ -18399,22 +18786,22 @@ parentPort.on('message', async (m) => {
18399
18786
  // src/rls/rlsRunner.ts
18400
18787
  function sqlError(error) {
18401
18788
  const e2 = error;
18402
- return { code: typeof e2?.code === "string" ? e2.code : "unknown", message: firstLine(typeof e2?.message === "string" ? e2.message : String(error)) };
18789
+ return { code: typeof e2?.code === "string" ? e2.code : "unknown", message: firstLine2(typeof e2?.message === "string" ? e2.message : String(error)) };
18403
18790
  }
18404
18791
  function isSqlError(error) {
18405
18792
  return !(error instanceof RlsTimeoutError) && typeof error?.code === "string";
18406
18793
  }
18407
18794
  function displayPath(projectDir, path) {
18408
18795
  for (const base of [projectDir, process.cwd()]) {
18409
- const rel = (0, import_node_path34.relative)(base, path);
18410
- if (rel && !rel.startsWith("..") && !(0, import_node_path34.isAbsolute)(rel)) return rel.split("\\").join("/");
18796
+ const rel = (0, import_node_path36.relative)(base, path);
18797
+ if (rel && !rel.startsWith("..") && !(0, import_node_path36.isAbsolute)(rel)) return rel.split("\\").join("/");
18411
18798
  }
18412
18799
  return path;
18413
18800
  }
18414
18801
  async function gitCommit(projectDir, paths) {
18415
18802
  const run = async (args) => {
18416
18803
  const call = await safeGitInvocation(projectDir, args);
18417
- const { stdout } = await (0, import_node_util4.promisify)(import_node_child_process6.execFile)("git", call.args, { cwd: projectDir, env: call.env, windowsHide: true, timeout: 5e3, encoding: "utf8" });
18804
+ const { stdout } = await (0, import_node_util6.promisify)(import_node_child_process8.execFile)("git", call.args, { cwd: projectDir, env: call.env, windowsHide: true, timeout: 5e3, encoding: "utf8" });
18418
18805
  return String(stdout);
18419
18806
  };
18420
18807
  let sha;
@@ -18487,11 +18874,11 @@ function valueCandidates(column, label) {
18487
18874
  if (column.category === "A") return u2 ? [] : ["{}"];
18488
18875
  return [];
18489
18876
  }
18490
- async function describeTable(db, table) {
18491
- const display = `${table.schema}.${table.name}`;
18877
+ async function describeTable(db, table2) {
18878
+ const display = `${table2.schema}.${table2.name}`;
18492
18879
  const rel = await db.query(
18493
18880
  `select c.oid::int as oid, c.relkind::text as kind from pg_class c join pg_namespace n on n.oid = c.relnamespace where n.nspname = $1 and c.relname = $2`,
18494
- [table.schema, table.name]
18881
+ [table2.schema, table2.name]
18495
18882
  );
18496
18883
  if (rel.rows.length === 0) return { reason: `${display} does not exist after the migrations; check the table name in the matrix.` };
18497
18884
  const kind = String(rel.rows[0].kind);
@@ -18530,35 +18917,35 @@ async function describeTable(db, table) {
18530
18917
  };
18531
18918
  });
18532
18919
  const byName = new Map(columns.map((c) => [c.name, c]));
18533
- const owner = byName.get(table.ownerColumn);
18534
- if (!owner) return { reason: `${display} has no column ${table.ownerColumn} (the matrix owner column).` };
18920
+ const owner = byName.get(table2.ownerColumn);
18921
+ if (!owner) return { reason: `${display} has no column ${table2.ownerColumn} (the matrix owner column).` };
18535
18922
  if (owner.typname !== "uuid" && owner.category !== "S") {
18536
- return { reason: `${display}.${table.ownerColumn} is ${owner.type}; the owner column must hold auth.uid() (uuid or text).` };
18923
+ return { reason: `${display}.${table2.ownerColumn} is ${owner.type}; the owner column must hold auth.uid() (uuid or text).` };
18537
18924
  }
18538
18925
  const pk = columns.filter((c) => c.isPk);
18539
18926
  if (pk.length === 0) return { reason: `${display} has no primary key; rls-test targets the owner's row by primary key.` };
18540
- for (const column of Object.keys(table.seed)) {
18927
+ for (const column of Object.keys(table2.seed)) {
18541
18928
  if (!byName.has(column)) return { reason: `the matrix seeds ${display}.${column}, which does not exist.` };
18542
18929
  }
18543
- if (table.updateColumn) {
18544
- const column = byName.get(table.updateColumn);
18545
- if (!column) return { reason: `the matrix updateColumn ${display}.${table.updateColumn} does not exist.` };
18930
+ if (table2.updateColumn) {
18931
+ const column = byName.get(table2.updateColumn);
18932
+ if (!column) return { reason: `the matrix updateColumn ${display}.${table2.updateColumn} does not exist.` };
18546
18933
  if (valueCandidates(column, "u").length === 0) return { reason: `the test cannot invent a new value for ${display}.${column.name} (${column.type}); pick another updateColumn.` };
18547
18934
  }
18548
18935
  const writable = (c) => c.identity === "" && c.generated === "";
18549
- const required = columns.filter((c) => c.name !== owner.name && c.notNull && !c.hasDefault && writable(c) && !(c.name in table.seed));
18936
+ const required = columns.filter((c) => c.name !== owner.name && c.notNull && !c.hasDefault && writable(c) && !(c.name in table2.seed));
18550
18937
  for (const column of required) {
18551
18938
  if (column.isFk) return { reason: `${display}.${column.name} is a NOT NULL foreign key the test cannot invent; give it a value under "seed" in the matrix.` };
18552
18939
  if (valueCandidates(column, "a").length === 0) {
18553
18940
  return { reason: `${display}.${column.name} (${column.type}) is NOT NULL and the test cannot invent a value; give it one under "seed" in the matrix.` };
18554
18941
  }
18555
18942
  }
18556
- const seedColumns = Object.keys(table.seed);
18943
+ const seedColumns = Object.keys(table2.seed);
18557
18944
  return {
18558
18945
  shape: {
18559
- table,
18946
+ table: table2,
18560
18947
  oid,
18561
- qualified: `${quoteIdent2(table.schema)}.${quoteIdent2(table.name)}`,
18948
+ qualified: `${quoteIdent2(table2.schema)}.${quoteIdent2(table2.name)}`,
18562
18949
  display,
18563
18950
  columns,
18564
18951
  pk,
@@ -18566,7 +18953,7 @@ async function describeTable(db, table) {
18566
18953
  ownerUnique: unique3.has(owner.name),
18567
18954
  ownerInPk: pk.some((c) => c.name === owner.name),
18568
18955
  insertColumns: [owner.name, ...seedColumns, ...required.map((c) => c.name)],
18569
- rowValues: (label, ownerId) => [ownerId, ...seedColumns.map((c) => table.seed[c]), ...required.map((c) => valueCandidates(c, label)[0])]
18956
+ rowValues: (label, ownerId) => [ownerId, ...seedColumns.map((c) => table2.seed[c]), ...required.map((c) => valueCandidates(c, label)[0])]
18570
18957
  }
18571
18958
  };
18572
18959
  }
@@ -18662,10 +19049,10 @@ function writeControl(filtered, changed) {
18662
19049
  if (!changed(run)) {
18663
19050
  return {
18664
19051
  ok: false,
18665
- detail: filtered ? `as the superuser the same statement changed ${plural2(run.affected ?? 0, "row")}, expected 1` : "as the superuser the same statement did not change the owner row"
19052
+ detail: filtered ? `as the superuser the same statement changed ${plural3(run.affected ?? 0, "row")}, expected 1` : "as the superuser the same statement did not change the owner row"
18666
19053
  };
18667
19054
  }
18668
- return { ok: true, detail: `as the superuser the same statement changed ${plural2(filtered ? run.affected ?? 0 : 1, "row")}` };
19055
+ return { ok: true, detail: `as the superuser the same statement changed ${plural3(filtered ? run.affected ?? 0 : 1, "row")}` };
18669
19056
  };
18670
19057
  }
18671
19058
  async function differingValue(db, shape, target, column) {
@@ -18692,7 +19079,7 @@ async function selectPlans(c) {
18692
19079
  return [
18693
19080
  {
18694
19081
  stmt: { name: "select", sql: `select ${pkList} from ${shape.qualified} where ${pkCondition(shape, 1)}`, params: target, display: `select the owner's row from ${shape.display} by primary key`, filtered: true, select: "pk" },
18695
- controlOk: (run) => run.error ? { ok: false, detail: `as the superuser the same statement failed: ${run.error.message} (${run.error.code})` } : run.rows?.length === 1 ? { ok: true, detail: "as the superuser the same statement returned 1 row" } : { ok: false, detail: `as the superuser the same statement returned ${plural2(run.rows?.length ?? 0, "row")}, expected 1` },
19082
+ controlOk: (run) => run.error ? { ok: false, detail: `as the superuser the same statement failed: ${run.error.message} (${run.error.code})` } : run.rows?.length === 1 ? { ok: true, detail: "as the superuser the same statement returned 1 row" } : { ok: false, detail: `as the superuser the same statement returned ${plural3(run.rows?.length ?? 0, "row")}, expected 1` },
18696
19083
  judge: (run) => {
18697
19084
  const denied = privilegeDenied(run);
18698
19085
  if (denied) return denied;
@@ -18747,7 +19134,7 @@ function insertPlans(c) {
18747
19134
  prep,
18748
19135
  controlOk: (run) => {
18749
19136
  if (run.error) return { ok: false, detail: `as the superuser the same statement failed: ${run.error.message} (${run.error.code})` };
18750
- return added(run) ? { ok: true, detail: "as the superuser the same statement changed 1 row" } : { ok: false, detail: `as the superuser the same statement changed ${plural2(run.affected ?? 0, "row")}, expected 1` };
19137
+ return added(run) ? { ok: true, detail: "as the superuser the same statement changed 1 row" } : { ok: false, detail: `as the superuser the same statement changed ${plural3(run.affected ?? 0, "row")}, expected 1` };
18751
19138
  },
18752
19139
  judge: (run) => {
18753
19140
  if (isRlsRefusal(run)) return { verdict: "unknown", detail: `refused by WITH CHECK: ${run.error.message} (42501). Only the generated row was tried; other values may allow insertion` };
@@ -18759,7 +19146,7 @@ function insertPlans(c) {
18759
19146
  if ((run.affected ?? 0) === 0 && run.after.digest === run.before.digest) return { verdict: "denied", detail: "0 rows added, table unchanged" };
18760
19147
  return {
18761
19148
  verdict: "unknown",
18762
- detail: `reported ${plural2(run.affected ?? 0, "row")}, but the table went from ${run.before.count} to ${run.after.count} rows and the owner's rows from ${run.before.owned} to ${run.after.owned}`
19149
+ detail: `reported ${plural3(run.affected ?? 0, "row")}, but the table went from ${run.before.count} to ${run.after.count} rows and the owner's rows from ${run.before.owned} to ${run.after.owned}`
18763
19150
  };
18764
19151
  }
18765
19152
  }
@@ -18807,7 +19194,7 @@ async function updatePlans(c) {
18807
19194
  if (changed(run)) return { verdict: "allowed", detail: noop ? "1 row updated (rewrote its own value)" : `${changedRows(filtered ? run.affected : 1)} (${sets.map((s) => s.column).join(" and ")} rewritten)` };
18808
19195
  if (!filtered) return { verdict: "denied", detail: "the owner row is unchanged" };
18809
19196
  if ((run.affected ?? 0) === 0 && run.after.digest === run.before.digest) return { verdict: "denied", detail: "0 rows changed, the row is still there and unchanged" };
18810
- return { verdict: "unknown", detail: `reported ${plural2(run.affected ?? 0, "row")}, but the owner row ${run.after.target === null ? "is gone" : "did not change"} and the table ${run.after.digest === run.before.digest ? "did not" : "did"} change` };
19197
+ return { verdict: "unknown", detail: `reported ${plural3(run.affected ?? 0, "row")}, but the owner row ${run.after.target === null ? "is gone" : "did not change"} and the table ${run.after.digest === run.before.digest ? "did not" : "did"} change` };
18811
19198
  }
18812
19199
  });
18813
19200
  };
@@ -18859,7 +19246,7 @@ function reassignPlans(c) {
18859
19246
  if (moved(run)) return { verdict: "allowed", detail: `the owner row now belongs to the other user` };
18860
19247
  if (!filtered && run.after.target === run.before.target) return { verdict: "denied", detail: "the owner row is unchanged" };
18861
19248
  if ((run.affected ?? 0) === 0 && run.after.digest === run.before.digest) return { verdict: "denied", detail: "0 rows changed, the row is still there and unchanged" };
18862
- return { verdict: "unknown", detail: `reported ${plural2(run.affected ?? 0, "row")}, but the owner column did not move` };
19249
+ return { verdict: "unknown", detail: `reported ${plural3(run.affected ?? 0, "row")}, but the owner column did not move` };
18863
19250
  }
18864
19251
  }
18865
19252
  ];
@@ -18888,7 +19275,7 @@ function deletePlans(c) {
18888
19275
  if ((run.affected ?? 0) === 0 && run.after.digest === run.before.digest) return { verdict: "denied", detail: "0 rows changed, the row is still there and unchanged" };
18889
19276
  return {
18890
19277
  verdict: "unknown",
18891
- detail: `reported ${plural2(run.affected ?? 0, "row")}, but the owner row is ${run.after.target === null ? "gone" : "still there"} and the table ${run.after.digest === run.before.digest ? "did not" : "did"} change`
19278
+ detail: `reported ${plural3(run.affected ?? 0, "row")}, but the owner row is ${run.after.target === null ? "gone" : "still there"} and the table ${run.after.digest === run.before.digest ? "did not" : "did"} change`
18892
19279
  };
18893
19280
  }
18894
19281
  }
@@ -18959,25 +19346,25 @@ async function runCell(ctx, privilegesByRole, actor, action, expected) {
18959
19346
  const reason = pass ? `Expected ${expected}, observed ${allowed ? "allowed" : "denied"}.` : want ? `Expected ${actorText} to be allowed to ${action}, but ${observed.summary}.${action !== "select" && !r.error ? " Postgres reports rows no policy allows as 0 rows, not as an error, so the app sees no failure." : ""}` : `Expected ${actorText} to be denied ${action}, but ${observed.summary}.`;
18960
19347
  return { ...base, outcome: pass ? "Pass" : "Fail", observed, reason };
18961
19348
  }
18962
- function cellsFor(table) {
19349
+ function cellsFor(table2) {
18963
19350
  const out = [];
18964
19351
  for (const actor of TESTED_ACTORS) {
18965
- for (const action of MATRIX_ACTIONS) out.push({ actor, action, expected: table.expect[actor][action] });
18966
- const reassign = table.expect[actor].reassign;
19352
+ for (const action of MATRIX_ACTIONS) out.push({ actor, action, expected: table2.expect[actor][action] });
19353
+ const reassign = table2.expect[actor].reassign;
18967
19354
  if (reassign) out.push({ actor, action: "reassign", expected: reassign });
18968
19355
  }
18969
19356
  return out;
18970
19357
  }
18971
- function unknownCells(table, reason, summary) {
18972
- const display = `${table.schema}.${table.name}`;
18973
- const cells = cellsFor(table).map(
19358
+ function unknownCells(table2, reason, summary) {
19359
+ const display = `${table2.schema}.${table2.name}`;
19360
+ const cells = cellsFor(table2).map(
18974
19361
  ({ actor, action, expected }) => expected === "skip" ? { table: display, actor, action, expected, outcome: "N/A", observed: { summary: "not tested (skip in the matrix)" }, reason: "The matrix marks this cell skip." } : { table: display, actor, action, expected, outcome: "Unknown", observed: { summary }, reason }
18975
19362
  );
18976
- return [...cells, ...serviceRoleCells(table)];
19363
+ return [...cells, ...serviceRoleCells(table2)];
18977
19364
  }
18978
- function serviceRoleCells(table) {
18979
- if (!table.serviceRoleExcluded) return [];
18980
- const display = `${table.schema}.${table.name}`;
19365
+ function serviceRoleCells(table2) {
19366
+ if (!table2.serviceRoleExcluded) return [];
19367
+ const display = `${table2.schema}.${table2.name}`;
18981
19368
  return MATRIX_ACTIONS.map((action) => ({
18982
19369
  table: display,
18983
19370
  actor: "service_role",
@@ -18997,40 +19384,40 @@ function summarise(tables) {
18997
19384
  function verdictFor(summary) {
18998
19385
  if (summary.fail > 0) {
18999
19386
  return {
19000
- verdict: `Not ready within tested scope: ${plural2(summary.fail, "cell does", "cells do")} not match the matrix; ${plural2(summary.unknown, "unknown")}.`,
19387
+ verdict: `Not ready within tested scope: ${plural3(summary.fail, "cell does", "cells do")} not match the matrix; ${plural3(summary.unknown, "unknown")}.`,
19001
19388
  exitCode: 1
19002
19389
  };
19003
19390
  }
19004
19391
  if (summary.pass === 0) {
19005
- return { verdict: `Nothing was observed: ${plural2(summary.unknown, "unknown")}, ${summary.notApplicable} N/A.`, exitCode: 2 };
19392
+ return { verdict: `Nothing was observed: ${plural3(summary.unknown, "unknown")}, ${summary.notApplicable} N/A.`, exitCode: 2 };
19006
19393
  }
19007
19394
  if (summary.unknown > 0) {
19008
- return { verdict: `No blockers found within tested scope; ${plural2(summary.unknown, "unknown")}.`, exitCode: 2 };
19395
+ return { verdict: `No blockers found within tested scope; ${plural3(summary.unknown, "unknown")}.`, exitCode: 2 };
19009
19396
  }
19010
19397
  return { verdict: "No blockers found within tested scope; 0 unknowns. Scenario passed locally.", exitCode: 0 };
19011
19398
  }
19012
19399
  async function listMigrations(dir) {
19013
19400
  try {
19014
- const entries = await (0, import_promises27.readdir)(dir, { withFileTypes: true });
19401
+ const entries = await (0, import_promises29.readdir)(dir, { withFileTypes: true });
19015
19402
  return entries.filter((e2) => e2.isFile() && /\.sql$/i.test(e2.name) && !e2.name.startsWith(".")).map((e2) => e2.name).sort((a, b3) => a < b3 ? -1 : a > b3 ? 1 : 0);
19016
19403
  } catch {
19017
19404
  return [];
19018
19405
  }
19019
19406
  }
19020
19407
  async function runRlsTest(options) {
19021
- const projectDir = (0, import_node_path34.resolve)(options.projectDir);
19022
- const matrixPath = (0, import_node_path34.resolve)(projectDir, options.matrixPath ?? DEFAULT_MATRIX_FILE);
19023
- const migrationsDir = (0, import_node_path34.resolve)(projectDir, options.migrationsDir ?? (0, import_node_path34.join)("supabase", "migrations"));
19408
+ const projectDir = (0, import_node_path36.resolve)(options.projectDir);
19409
+ const matrixPath = (0, import_node_path36.resolve)(projectDir, options.matrixPath ?? DEFAULT_MATRIX_FILE);
19410
+ const migrationsDir = (0, import_node_path36.resolve)(projectDir, options.migrationsDir ?? (0, import_node_path36.join)("supabase", "migrations"));
19024
19411
  const timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
19025
- if ((0, import_node_path34.basename)(matrixPath).toLowerCase().startsWith(".env")) {
19026
- throw new RlsInputError(`Refusing to read ${(0, import_node_path34.basename)(matrixPath)}: rls-test never reads .env files. Point --matrix at a viberaven.permissions.json.`);
19412
+ if ((0, import_node_path36.basename)(matrixPath).toLowerCase().startsWith(".env")) {
19413
+ throw new RlsInputError(`Refusing to read ${(0, import_node_path36.basename)(matrixPath)}: rls-test never reads .env files. Point --matrix at a viberaven.permissions.json.`);
19027
19414
  }
19028
19415
  const filesRead = [];
19029
19416
  let matrixText;
19030
19417
  try {
19031
- const info = await (0, import_promises27.stat)(matrixPath);
19418
+ const info = await (0, import_promises29.stat)(matrixPath);
19032
19419
  if (!info.isFile()) throw new Error("not a file");
19033
- matrixText = normalise(await (0, import_promises27.readFile)(matrixPath, "utf8"));
19420
+ matrixText = normalise(await (0, import_promises29.readFile)(matrixPath, "utf8"));
19034
19421
  } catch {
19035
19422
  throw new RlsInputError(
19036
19423
  `No permissions matrix at ${matrixPath}. Write one by hand (schema: schemas/permissions-matrix.schema.json in the @viberaven/cli package); rls-test never infers it from your policies.`
@@ -19041,8 +19428,8 @@ async function runRlsTest(options) {
19041
19428
  const names = await listMigrations(migrationsDir);
19042
19429
  const migrationFiles = [];
19043
19430
  for (const name of names) {
19044
- const sql = normalise(await (0, import_promises27.readFile)((0, import_node_path34.join)(migrationsDir, name), "utf8"));
19045
- filesRead.push(displayPath(projectDir, (0, import_node_path34.join)(migrationsDir, name)));
19431
+ const sql = normalise(await (0, import_promises29.readFile)((0, import_node_path36.join)(migrationsDir, name), "utf8"));
19432
+ filesRead.push(displayPath(projectDir, (0, import_node_path36.join)(migrationsDir, name)));
19046
19433
  migrationFiles.push({ name, sha256: sha256(sql), sql });
19047
19434
  }
19048
19435
  const migrationsHash = sha256(migrationFiles.map((f) => `${f.name}\0${f.sha256}`).join("\n"));
@@ -19094,7 +19481,7 @@ async function runRlsTest(options) {
19094
19481
  engineLoaded = true;
19095
19482
  db = await engine.create({ env: allowlistedEnv(process.env), statementTimeoutMs: timeouts.statementMs });
19096
19483
  } catch (error) {
19097
- result.engine.error = firstLine(error instanceof Error ? error.message : String(error));
19484
+ result.engine.error = firstLine2(error instanceof Error ? error.message : String(error));
19098
19485
  if (engineLoaded) return allUnknown(`PGlite could not start: ${result.engine.error}. Nothing was tested.`, "not run: PGlite startup failed");
19099
19486
  const missing = error?.code === "MODULE_NOT_FOUND" || error?.code === "ERR_MODULE_NOT_FOUND";
19100
19487
  return missing ? allUnknown(PGLITE_INSTALL_HINT, "not run: PGlite is not installed") : allUnknown(`PGlite could not load: ${result.engine.error}. Nothing was tested.`, "not run: PGlite loading failed");
@@ -19154,13 +19541,13 @@ async function runRlsTest(options) {
19154
19541
  result.roleChecks.push({ role, ok, detail: row ? `superuser ${Boolean(row.su)}, BYPASSRLS ${Boolean(row.bypass)}` : "the role does not exist after the migrations" });
19155
19542
  }
19156
19543
  const badRoles = result.roleChecks.filter((c) => !c.ok);
19157
- for (const table of matrix.tables) {
19158
- result.tables.push(await runTable(db, table, badRoles, result.roleChecks));
19544
+ for (const table2 of matrix.tables) {
19545
+ result.tables.push(await runTable(db, table2, badRoles, result.roleChecks));
19159
19546
  }
19160
19547
  return finish();
19161
19548
  } catch (error) {
19162
19549
  if (error instanceof RlsTimeoutError || !isSqlError(error)) {
19163
- const message = firstLine(error instanceof Error ? error.message : String(error));
19550
+ const message = firstLine2(error instanceof Error ? error.message : String(error));
19164
19551
  return allUnknown(
19165
19552
  error instanceof RlsTimeoutError ? `A statement did not finish within ${Math.round(timeouts.statementMs / 1e3)} s, so the PGlite worker was stopped and no cell is reported as passed.` : `The PGlite worker stopped (${message}), so no cell is reported as passed.`,
19166
19553
  "not run: the database stopped"
@@ -19186,13 +19573,13 @@ async function seedRow(db, shape, label, userId) {
19186
19573
  if (r.rows.length !== 1) throw Object.assign(new Error("the insert returned no row (a trigger or rule may drop it)"), { code: "vr000" });
19187
19574
  return { key: keyOf2(r.rows[0]), reused: false };
19188
19575
  }
19189
- async function runTable(db, table, badRoles, roleChecks) {
19190
- const display = `${table.schema}.${table.name}`;
19191
- const unknownTable = (reason, extra = {}) => ({ name: display, ...extra, unknownReason: reason, cells: unknownCells(table, reason, "not run") });
19576
+ async function runTable(db, table2, badRoles, roleChecks) {
19577
+ const display = `${table2.schema}.${table2.name}`;
19578
+ const unknownTable = (reason, extra = {}) => ({ name: display, ...extra, unknownReason: reason, cells: unknownCells(table2, reason, "not run") });
19192
19579
  if (badRoles.length > 0) {
19193
19580
  return unknownTable(`Role check failed (${badRoles.map((c) => `${c.role}: ${c.detail}`).join("; ")}), so RLS would not apply to the probes the way it does for the Data API.`);
19194
19581
  }
19195
- const described = await describeTable(db, table);
19582
+ const described = await describeTable(db, table2);
19196
19583
  if (!described.shape) return unknownTable(described.reason ?? "unknown table problem");
19197
19584
  const shape = described.shape;
19198
19585
  const rel = await db.query(
@@ -19226,15 +19613,15 @@ async function runTable(db, table, badRoles, roleChecks) {
19226
19613
  const privilegesByRole = /* @__PURE__ */ new Map();
19227
19614
  for (const role of ["anon", "authenticated"]) privilegesByRole.set(role, await privilegesFor(db, shape, role));
19228
19615
  const cells = [];
19229
- for (const { actor, action, expected } of cellsFor(table)) {
19616
+ for (const { actor, action, expected } of cellsFor(table2)) {
19230
19617
  cells.push(await runCell({ db, shape, target: ownerSeed.key }, privilegesByRole, actor, action, expected));
19231
19618
  }
19232
- cells.push(...serviceRoleCells(table));
19619
+ cells.push(...serviceRoleCells(table2));
19233
19620
  const columns = {};
19234
19621
  shape.insertColumns.forEach((c) => {
19235
19622
  columns[c] = c === shape.owner.name ? "the test user id" : "generated test value";
19236
19623
  });
19237
- for (const c of Object.keys(table.seed)) columns[c] = "from the matrix seed";
19624
+ for (const c of Object.keys(table2.seed)) columns[c] = "from the matrix seed";
19238
19625
  return {
19239
19626
  name: display,
19240
19627
  rls,
@@ -19242,16 +19629,16 @@ async function runTable(db, table, badRoles, roleChecks) {
19242
19629
  cells
19243
19630
  };
19244
19631
  }
19245
- var import_node_child_process6, import_node_crypto3, import_promises27, import_node_net, import_node_path34, import_node_util4, NON_AUTHORITATIVE_LABEL, PGLITE_INSTALL_HINT, ENV_ALLOWLIST, PERMISSION_DENIED, RLS_REFUSAL, DEFAULT_TIMEOUTS, RlsInputError, normalise, quoteIdent2, firstLine, plural2, NUMBERS, ACTOR_SESSION, changedRows, isRlsRefusal, isPrivilegeRefusal, SELF, PROBE_EXCLUSIONS, SEED_HINTS;
19632
+ var import_node_child_process8, import_node_crypto3, import_promises29, import_node_net, import_node_path36, import_node_util6, NON_AUTHORITATIVE_LABEL, PGLITE_INSTALL_HINT, ENV_ALLOWLIST, PERMISSION_DENIED, RLS_REFUSAL, DEFAULT_TIMEOUTS, RlsInputError, normalise, quoteIdent2, firstLine2, plural3, NUMBERS, ACTOR_SESSION, changedRows, isRlsRefusal, isPrivilegeRefusal, SELF, PROBE_EXCLUSIONS, SEED_HINTS;
19246
19633
  var init_rlsRunner = __esm({
19247
19634
  "src/rls/rlsRunner.ts"() {
19248
19635
  "use strict";
19249
- import_node_child_process6 = require("node:child_process");
19636
+ import_node_child_process8 = require("node:child_process");
19250
19637
  import_node_crypto3 = require("node:crypto");
19251
- import_promises27 = require("node:fs/promises");
19638
+ import_promises29 = require("node:fs/promises");
19252
19639
  import_node_net = __toESM(require("node:net"));
19253
- import_node_path34 = require("node:path");
19254
- import_node_util4 = require("node:util");
19640
+ import_node_path36 = require("node:path");
19641
+ import_node_util6 = require("node:util");
19255
19642
  init_safeGit();
19256
19643
  init_permissionsMatrix();
19257
19644
  init_supabaseImitation();
@@ -19267,15 +19654,15 @@ var init_rlsRunner = __esm({
19267
19654
  };
19268
19655
  normalise = (text) => text.replace(/\r\n/g, "\n");
19269
19656
  quoteIdent2 = (name) => `"${name.replace(/"/g, '""')}"`;
19270
- firstLine = (message) => message.split("\n")[0].trim();
19271
- plural2 = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
19657
+ firstLine2 = (message) => message.split("\n")[0].trim();
19658
+ plural3 = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
19272
19659
  NUMBERS = { a: ["1001"], b: ["1002"], i: ["1003"], u: ["1004", "7", "1"] };
19273
19660
  ACTOR_SESSION = {
19274
19661
  owner: { role: "authenticated", uid: OWNER_ID, claims: { sub: OWNER_ID, role: "authenticated", aud: "authenticated", email: "owner@example.test" } },
19275
19662
  other_user: { role: "authenticated", uid: OTHER_USER_ID, claims: { sub: OTHER_USER_ID, role: "authenticated", aud: "authenticated", email: "other-user@example.test" } },
19276
19663
  anon: { role: "anon", uid: null, claims: { role: "anon" } }
19277
19664
  };
19278
- changedRows = (n) => `${plural2(n ?? 0, "row")} changed`;
19665
+ changedRows = (n) => `${plural3(n ?? 0, "row")} changed`;
19279
19666
  isRlsRefusal = (run) => run.error?.code === PERMISSION_DENIED && RLS_REFUSAL.test(run.error.message);
19280
19667
  isPrivilegeRefusal = (run) => run.error?.code === PERMISSION_DENIED && !RLS_REFUSAL.test(run.error.message);
19281
19668
  SELF = Symbol("self");
@@ -19322,25 +19709,25 @@ function renderRlsText(result) {
19322
19709
  lines.push("");
19323
19710
  if (result.engine.error) lines.push(`(${result.engine.error})`);
19324
19711
  }
19325
- for (const table of result.tables) {
19712
+ for (const table2 of result.tables) {
19326
19713
  lines.push("");
19327
- const rls = table.rls ? `RLS ${table.rls.enabled ? "on" : "off"}${table.rls.forced ? ", forced" : ""}, owner ${table.rls.owner}` : "not inspected";
19328
- lines.push(`${table.name} (${rls})`);
19329
- if (table.seed) {
19330
- const reused = [table.seed.reused.owner ? "the owner" : "", table.seed.reused.otherUser ? "the other user" : ""].filter(Boolean);
19714
+ const rls = table2.rls ? `RLS ${table2.rls.enabled ? "on" : "off"}${table2.rls.forced ? ", forced" : ""}, owner ${table2.rls.owner}` : "not inspected";
19715
+ lines.push(`${table2.name} (${rls})`);
19716
+ if (table2.seed) {
19717
+ const reused = [table2.seed.reused.owner ? "the owner" : "", table2.seed.reused.otherUser ? "the other user" : ""].filter(Boolean);
19331
19718
  lines.push(
19332
- ` One row for the owner and one for another user (${table.seed.rowsBefore} rows in the table)${reused.length > 0 ? `; reused the rows the migrations created for ${reused.join(" and ")}` : ""}.`
19719
+ ` One row for the owner and one for another user (${table2.seed.rowsBefore} rows in the table)${reused.length > 0 ? `; reused the rows the migrations created for ${reused.join(" and ")}` : ""}.`
19333
19720
  );
19334
19721
  }
19335
- if (table.unknownReason) lines.push(` Unknown: ${table.unknownReason}`);
19336
- const tested = table.cells.filter((c) => c.actor !== "service_role");
19722
+ if (table2.unknownReason) lines.push(` Unknown: ${table2.unknownReason}`);
19723
+ const tested = table2.cells.filter((c) => c.actor !== "service_role");
19337
19724
  const actorWidth = 14;
19338
19725
  const actionWidth = 10;
19339
19726
  lines.push(` ${"actor".padEnd(actorWidth)}${"action".padEnd(actionWidth)}${"expected".padEnd(10)}${"result".padEnd(9)}observed`);
19340
- for (const cell of tested) {
19341
- lines.push(` ${cell.actor.padEnd(actorWidth)}${cell.action.padEnd(actionWidth)}${cell.expected.padEnd(10)}${cell.outcome.padEnd(9)}${cell.observed.summary}`);
19727
+ for (const cell2 of tested) {
19728
+ lines.push(` ${cell2.actor.padEnd(actorWidth)}${cell2.action.padEnd(actionWidth)}${cell2.expected.padEnd(10)}${cell2.outcome.padEnd(9)}${cell2.observed.summary}`);
19342
19729
  }
19343
- const service = table.cells.filter((c) => c.actor === "service_role");
19730
+ const service = table2.cells.filter((c) => c.actor === "service_role");
19344
19731
  if (service.length > 0) lines.push(` ${"service_role".padEnd(actorWidth)}${"all".padEnd(actionWidth)}${"excluded".padEnd(10)}${"N/A".padEnd(9)}bypasses RLS by design, not tested`);
19345
19732
  }
19346
19733
  const s = result.summary;
@@ -19348,8 +19735,8 @@ function renderRlsText(result) {
19348
19735
  lines.push(`Result: ${s.pass} Pass, ${s.fail} Fail, ${s.unknown} Unknown, ${s.notApplicable} N/A \xB7 ${s.pass + s.fail} of ${s.tested} tested cells observed (${s.total} cells in the matrix)`);
19349
19736
  lines.push(result.verdict);
19350
19737
  const failed = result.tables.flatMap((t) => t.cells).filter((c) => c.outcome === "Fail");
19351
- for (const cell of failed) {
19352
- lines.push(` Fail ${cell.actor} ${cell.action} on ${cell.table}: ${cell.reason}`);
19738
+ for (const cell2 of failed) {
19739
+ lines.push(` Fail ${cell2.actor} ${cell2.action} on ${cell2.table}: ${cell2.reason}`);
19353
19740
  }
19354
19741
  const unknown = result.tables.flatMap((t) => t.cells).filter((c) => c.outcome === "Unknown");
19355
19742
  const unknownReasons = [...new Set(unknown.map((c) => c.reason))];
@@ -20078,7 +20465,7 @@ function buildMissionCards(artifact, providers) {
20078
20465
  };
20079
20466
  }
20080
20467
  function projectNameFromPath(pathValue) {
20081
- return (0, import_node_path35.basename)(pathValue.replace(/[\\/]$/, "")) || "current repo";
20468
+ return (0, import_node_path37.basename)(pathValue.replace(/[\\/]$/, "")) || "current repo";
20082
20469
  }
20083
20470
  function gapSearchText(gap) {
20084
20471
  return [
@@ -20489,19 +20876,19 @@ function mapArtifactToLocalUiState(artifact, presentProviderIds) {
20489
20876
  selectedProviderId: selectedProvider.id,
20490
20877
  currentPrompt: selectedProvider.nextFix?.prompt ?? "",
20491
20878
  artifacts: {
20492
- tasklist: (0, import_node_path35.join)(".viberaven", "agent-tasklist.md"),
20493
- contextMap: (0, import_node_path35.join)(".viberaven", "context-map.json"),
20494
- gateResult: (0, import_node_path35.join)(".viberaven", "gate-result.json"),
20495
- lastScan: (0, import_node_path35.join)(".viberaven", "last-scan.json")
20879
+ tasklist: (0, import_node_path37.join)(".viberaven", "agent-tasklist.md"),
20880
+ contextMap: (0, import_node_path37.join)(".viberaven", "context-map.json"),
20881
+ gateResult: (0, import_node_path37.join)(".viberaven", "gate-result.json"),
20882
+ lastScan: (0, import_node_path37.join)(".viberaven", "last-scan.json")
20496
20883
  },
20497
20884
  empty: false
20498
20885
  };
20499
20886
  }
20500
- var import_node_path35, CONNECT_PROVIDER_PRIORITY, providerDashboardUrls, providerHints, PROVIDER_OWNED_GAP;
20887
+ var import_node_path37, CONNECT_PROVIDER_PRIORITY, providerDashboardUrls, providerHints, PROVIDER_OWNED_GAP;
20501
20888
  var init_artifactAdapter = __esm({
20502
20889
  "src/local-ui/artifactAdapter.ts"() {
20503
20890
  "use strict";
20504
- import_node_path35 = require("node:path");
20891
+ import_node_path37 = require("node:path");
20505
20892
  init_providerLogos();
20506
20893
  init_buildTaskList();
20507
20894
  init_prompts();
@@ -20804,18 +21191,18 @@ var init_planLimits = __esm({
20804
21191
  // src/hosted/credentials.ts
20805
21192
  function defaultConfigDir(env = process.env, platform = process.platform) {
20806
21193
  const override = env.VIBERAVEN_CONFIG_DIR?.trim();
20807
- if (override) return (0, import_node_path36.resolve)(override);
21194
+ if (override) return (0, import_node_path38.resolve)(override);
20808
21195
  if (platform === "win32") {
20809
- return (0, import_node_path36.join)(env.APPDATA?.trim() || (0, import_node_path36.join)((0, import_node_os.homedir)(), "AppData", "Roaming"), "viberaven");
21196
+ return (0, import_node_path38.join)(env.APPDATA?.trim() || (0, import_node_path38.join)((0, import_node_os2.homedir)(), "AppData", "Roaming"), "viberaven");
20810
21197
  }
20811
21198
  if (platform === "darwin") {
20812
- return (0, import_node_path36.join)((0, import_node_os.homedir)(), "Library", "Application Support", "viberaven");
21199
+ return (0, import_node_path38.join)((0, import_node_os2.homedir)(), "Library", "Application Support", "viberaven");
20813
21200
  }
20814
- return (0, import_node_path36.join)(env.XDG_CONFIG_HOME?.trim() || (0, import_node_path36.join)((0, import_node_os.homedir)(), ".config"), "viberaven");
21201
+ return (0, import_node_path38.join)(env.XDG_CONFIG_HOME?.trim() || (0, import_node_path38.join)((0, import_node_os2.homedir)(), ".config"), "viberaven");
20815
21202
  }
20816
21203
  function isInside(child, parent) {
20817
- const rel = (0, import_node_path36.relative)((0, import_node_path36.resolve)(parent), (0, import_node_path36.resolve)(child));
20818
- return rel === "" || !rel.startsWith("..") && !(0, import_node_path36.isAbsolute)(rel);
21204
+ const rel = (0, import_node_path38.relative)((0, import_node_path38.resolve)(parent), (0, import_node_path38.resolve)(child));
21205
+ return rel === "" || !rel.startsWith("..") && !(0, import_node_path38.isAbsolute)(rel);
20819
21206
  }
20820
21207
  async function retryTransient(work) {
20821
21208
  for (let attempt = 1; ; attempt += 1) {
@@ -20828,15 +21215,15 @@ async function retryTransient(work) {
20828
21215
  }
20829
21216
  }
20830
21217
  }
20831
- var import_node_child_process7, import_node_crypto4, import_promises28, import_node_os, import_node_path36, CREDENTIALS_FILE_NAME, CredentialLocationError, CredentialPermissionError, restrictWithIcacls, TRANSIENT_FS_CODES, FS_ATTEMPTS, FS_BACKOFF_MS, CredentialStore;
21218
+ var import_node_child_process9, import_node_crypto4, import_promises30, import_node_os2, import_node_path38, CREDENTIALS_FILE_NAME, CredentialLocationError, CredentialPermissionError, restrictWithIcacls, TRANSIENT_FS_CODES, FS_ATTEMPTS, FS_BACKOFF_MS, CredentialStore;
20832
21219
  var init_credentials = __esm({
20833
21220
  "src/hosted/credentials.ts"() {
20834
21221
  "use strict";
20835
- import_node_child_process7 = require("node:child_process");
21222
+ import_node_child_process9 = require("node:child_process");
20836
21223
  import_node_crypto4 = require("node:crypto");
20837
- import_promises28 = require("node:fs/promises");
20838
- import_node_os = require("node:os");
20839
- import_node_path36 = require("node:path");
21224
+ import_promises30 = require("node:fs/promises");
21225
+ import_node_os2 = require("node:os");
21226
+ import_node_path38 = require("node:path");
20840
21227
  CREDENTIALS_FILE_NAME = "credentials.json";
20841
21228
  CredentialLocationError = class extends Error {
20842
21229
  };
@@ -20847,10 +21234,10 @@ var init_credentials = __esm({
20847
21234
  }
20848
21235
  };
20849
21236
  restrictWithIcacls = (path) => {
20850
- const name = (0, import_node_os.userInfo)().username;
21237
+ const name = (0, import_node_os2.userInfo)().username;
20851
21238
  const user = process.env.USERDOMAIN ? `${process.env.USERDOMAIN}\\${name}` : name;
20852
21239
  return new Promise((resolveRestrict, reject) => {
20853
- (0, import_node_child_process7.execFile)("icacls", [path, "/inheritance:r", "/grant:r", `${user}:F`], { windowsHide: true, timeout: 1e4 }, (error) => {
21240
+ (0, import_node_child_process9.execFile)("icacls", [path, "/inheritance:r", "/grant:r", `${user}:F`], { windowsHide: true, timeout: 1e4 }, (error) => {
20854
21241
  if (error) reject(error);
20855
21242
  else resolveRestrict();
20856
21243
  });
@@ -20863,9 +21250,9 @@ var init_credentials = __esm({
20863
21250
  constructor(configDir, workspacePath, options = {}) {
20864
21251
  this.configDir = configDir;
20865
21252
  this.workspacePath = workspacePath;
20866
- this.path = (0, import_node_path36.join)(configDir, CREDENTIALS_FILE_NAME);
21253
+ this.path = (0, import_node_path38.join)(configDir, CREDENTIALS_FILE_NAME);
20867
21254
  this.restrict = options.restrict !== void 0 ? options.restrict : process.platform === "win32" ? restrictWithIcacls : null;
20868
- this.fs = { readFile: (path, encoding) => (0, import_promises28.readFile)(path, encoding), rename: (from, to) => (0, import_promises28.rename)(from, to), rm: (path) => (0, import_promises28.rm)(path, { force: true }), ...options.fs };
21255
+ this.fs = { readFile: (path, encoding) => (0, import_promises30.readFile)(path, encoding), rename: (from, to) => (0, import_promises30.rename)(from, to), rm: (path) => (0, import_promises30.rm)(path, { force: true }), ...options.fs };
20869
21256
  }
20870
21257
  path;
20871
21258
  restrict;
@@ -20914,15 +21301,15 @@ var init_credentials = __esm({
20914
21301
  `Refusing to store the VibeRaven sign-in inside this project (${this.configDir}). Set VIBERAVEN_CONFIG_DIR to a folder outside the repo.`
20915
21302
  );
20916
21303
  }
20917
- await (0, import_promises28.mkdir)(this.configDir, { recursive: true, mode: 448 });
21304
+ await (0, import_promises30.mkdir)(this.configDir, { recursive: true, mode: 448 });
20918
21305
  const temp = `${this.path}.${(0, import_node_crypto4.randomUUID)()}.tmp`;
20919
- await (0, import_promises28.writeFile)(temp, `${JSON.stringify(body, null, 2)}
21306
+ await (0, import_promises30.writeFile)(temp, `${JSON.stringify(body, null, 2)}
20920
21307
  `, { encoding: "utf8", mode: 384 });
20921
- await (0, import_promises28.chmod)(temp, 384).catch(() => void 0);
21308
+ await (0, import_promises30.chmod)(temp, 384).catch(() => void 0);
20922
21309
  try {
20923
21310
  if (this.restrict) await this.restrict(temp);
20924
21311
  } catch (error) {
20925
- await (0, import_promises28.rm)(temp, { force: true });
21312
+ await (0, import_promises30.rm)(temp, { force: true });
20926
21313
  const code = error?.code;
20927
21314
  const toolMissing = code === "ENOENT";
20928
21315
  throw new CredentialPermissionError(
@@ -20933,17 +21320,17 @@ var init_credentials = __esm({
20933
21320
  if (guard) {
20934
21321
  const onDisk = await this.readFor(guard.apiBaseUrl);
20935
21322
  if (onDisk?.accessToken !== guard.accessToken || guard.isCurrent && !guard.isCurrent()) {
20936
- await (0, import_promises28.rm)(temp, { force: true });
21323
+ await (0, import_promises30.rm)(temp, { force: true });
20937
21324
  return false;
20938
21325
  }
20939
21326
  }
20940
21327
  try {
20941
21328
  await retryTransient(() => this.fs.rename(temp, this.path));
20942
21329
  } catch (error) {
20943
- await (0, import_promises28.rm)(temp, { force: true });
21330
+ await (0, import_promises30.rm)(temp, { force: true });
20944
21331
  throw error;
20945
21332
  }
20946
- await (0, import_promises28.chmod)(this.path, 384).catch(() => void 0);
21333
+ await (0, import_promises30.chmod)(this.path, 384).catch(() => void 0);
20947
21334
  return true;
20948
21335
  }
20949
21336
  /** Keeps the stored plan label in step with what the API last said. */
@@ -21312,7 +21699,7 @@ async function buildHostedCheckPayload(workspacePath) {
21312
21699
  throw new Error("Could not assemble the full check request.");
21313
21700
  }
21314
21701
  function finalizePayload(payload) {
21315
- const folder = (0, import_node_path37.basename)(payload.workspacePath.split("\\").join("/").replace(/\/+$/, "")) || "project";
21702
+ const folder = (0, import_node_path39.basename)(payload.workspacePath.split("\\").join("/").replace(/\/+$/, "")) || "project";
21316
21703
  const redacted = redactPayload({ ...payload, workspacePath: folder });
21317
21704
  return { payload: redacted.payload, redactions: redacted.count };
21318
21705
  }
@@ -21343,13 +21730,13 @@ function splitSections(prompt) {
21343
21730
  chars: section.length
21344
21731
  }));
21345
21732
  }
21346
- var import_node_path37, PayloadCaptured;
21733
+ var import_node_path39, PayloadCaptured;
21347
21734
  var init_payload = __esm({
21348
21735
  "src/hosted/payload.ts"() {
21349
21736
  "use strict";
21350
21737
  init_fileScanner();
21351
21738
  init_orchestrator();
21352
- import_node_path37 = require("node:path");
21739
+ import_node_path39 = require("node:path");
21353
21740
  init_config();
21354
21741
  init_redact();
21355
21742
  PayloadCaptured = class extends Error {
@@ -21387,7 +21774,7 @@ function shapeResult(response, now = /* @__PURE__ */ new Date()) {
21387
21774
  const usage = toUsage(response.usage);
21388
21775
  const freeKeys = new Set(FREE_TRIAL_UNLOCKED_MAP_CATEGORY_KEYS);
21389
21776
  const unlocked = (key) => usage.plan === "pro" || freeKeys.has(key) && response.usage.unlockedMapCategoryKeys.includes(key);
21390
- const sorted = [...output.gaps].sort((a, b3) => SEVERITY_RANK3[a.severity] - SEVERITY_RANK3[b3.severity]);
21777
+ const sorted = [...output.gaps].sort((a, b3) => SEVERITY_RANK4[a.severity] - SEVERITY_RANK4[b3.severity]);
21391
21778
  const areas = PRODUCTION_MAP_LANES.map((lane) => {
21392
21779
  const gaps = sorted.filter((gap) => gap.primaryMapCategory === lane.extensionKey);
21393
21780
  const locked = !unlocked(lane.extensionKey);
@@ -21425,7 +21812,7 @@ function readServerMessage(body) {
21425
21812
  return body.slice(0, 300);
21426
21813
  }
21427
21814
  }
21428
- var import_node_crypto5, PRICING_URL, FREE_LIMIT_MESSAGE, PREVIEW_TTL_MS, STATUS_TIMEOUT_MS, STATUS_CACHE_MS, MAX_PREVIEWS, TRANSIENT_REASONS, SEVERITY_RANK3, FullCheckService;
21815
+ var import_node_crypto5, PRICING_URL, FREE_LIMIT_MESSAGE, PREVIEW_TTL_MS, STATUS_TIMEOUT_MS, STATUS_CACHE_MS, MAX_PREVIEWS, TRANSIENT_REASONS, SEVERITY_RANK4, FullCheckService;
21429
21816
  var init_fullCheck = __esm({
21430
21817
  "src/hosted/fullCheck.ts"() {
21431
21818
  "use strict";
@@ -21444,7 +21831,7 @@ var init_fullCheck = __esm({
21444
21831
  STATUS_CACHE_MS = 5e3;
21445
21832
  MAX_PREVIEWS = 5;
21446
21833
  TRANSIENT_REASONS = /* @__PURE__ */ new Set(["network", "timeout", "server", "rate_limited", "busy"]);
21447
- SEVERITY_RANK3 = { critical: 0, warning: 1, info: 2 };
21834
+ SEVERITY_RANK4 = { critical: 0, warning: 1, info: 2 };
21448
21835
  FullCheckService = class {
21449
21836
  constructor(workspacePath, options = {}) {
21450
21837
  this.workspacePath = workspacePath;
@@ -21815,10 +22202,10 @@ async function connectProviderMcp(cwd, providerId) {
21815
22202
  if (!recipe) {
21816
22203
  return { ok: false, message: `No known MCP server for ${providerId} yet. Add one manually to .mcp.json.` };
21817
22204
  }
21818
- const configPath = (0, import_node_path38.join)(cwd, ".mcp.json");
22205
+ const configPath = (0, import_node_path40.join)(cwd, ".mcp.json");
21819
22206
  let config = {};
21820
22207
  try {
21821
- const raw = await (0, import_promises29.readFile)(configPath, "utf8");
22208
+ const raw = await (0, import_promises31.readFile)(configPath, "utf8");
21822
22209
  const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
21823
22210
  if (!isRecord5(parsed) || parsed.mcpServers !== void 0 && !isRecord5(parsed.mcpServers)) {
21824
22211
  return { ok: false, message: "Existing .mcp.json has an unsupported structure. It was left unchanged." };
@@ -21835,7 +22222,7 @@ async function connectProviderMcp(cwd, providerId) {
21835
22222
  }
21836
22223
  servers[providerId] = recipe.entry;
21837
22224
  const next = { ...config, mcpServers: servers };
21838
- await (0, import_promises29.writeFile)(configPath, `${JSON.stringify(next, null, 2)}
22225
+ await (0, import_promises31.writeFile)(configPath, `${JSON.stringify(next, null, 2)}
21839
22226
  `, "utf8");
21840
22227
  const suffix = recipe.note ? ` ${recipe.note}` : "";
21841
22228
  return { ok: true, message: `Added ${providerId} MCP server to .mcp.json.${suffix}`, path: ".mcp.json" };
@@ -21888,7 +22275,7 @@ async function defaultScanRunner(flags, positional) {
21888
22275
  }
21889
22276
  async function readPackageJson(cwd) {
21890
22277
  try {
21891
- const raw = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, "package.json"), "utf8");
22278
+ const raw = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, "package.json"), "utf8");
21892
22279
  const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
21893
22280
  return isRecord5(parsed) ? parsed : {};
21894
22281
  } catch {
@@ -21911,7 +22298,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
21911
22298
  if (files.length >= maxFiles) return;
21912
22299
  let entries;
21913
22300
  try {
21914
- entries = await (0, import_promises29.readdir)(dir, { withFileTypes: true });
22301
+ entries = await (0, import_promises31.readdir)(dir, { withFileTypes: true });
21915
22302
  } catch {
21916
22303
  return;
21917
22304
  }
@@ -21919,7 +22306,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
21919
22306
  if (files.length >= maxFiles) return;
21920
22307
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
21921
22308
  if (entry.isDirectory()) {
21922
- if (!skipped.has(entry.name)) await walk((0, import_node_path38.join)(dir, entry.name), rel);
22309
+ if (!skipped.has(entry.name)) await walk((0, import_node_path40.join)(dir, entry.name), rel);
21923
22310
  continue;
21924
22311
  }
21925
22312
  if (entry.isFile()) files.push(rel.toLowerCase());
@@ -21938,7 +22325,7 @@ async function readEnvKeys(cwd) {
21938
22325
  const keys = /* @__PURE__ */ new Set();
21939
22326
  for (const name of [".env.example", ".env"]) {
21940
22327
  try {
21941
- const raw = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, name), "utf8");
22328
+ const raw = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, name), "utf8");
21942
22329
  for (const line of raw.split(/\r?\n/)) {
21943
22330
  const trimmed = line.trim();
21944
22331
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -22032,7 +22419,7 @@ function applyProviderDetection(state, deps, files) {
22032
22419
  }
22033
22420
  function runGit(cwd, args, timeoutMs = 1500) {
22034
22421
  return safeGitInvocation(cwd, args).then(
22035
- (git) => spawnGit(cwd, git.args, git.env, timeoutMs),
22422
+ (git2) => spawnGit(cwd, git2.args, git2.env, timeoutMs),
22036
22423
  (error) => {
22037
22424
  if (error instanceof SafeGitRefusal) throw error;
22038
22425
  return "";
@@ -22041,7 +22428,7 @@ function runGit(cwd, args, timeoutMs = 1500) {
22041
22428
  }
22042
22429
  function spawnGit(cwd, args, env, timeoutMs) {
22043
22430
  return new Promise((resolveGit) => {
22044
- const child = (0, import_node_child_process8.spawn)("git", args, {
22431
+ const child = (0, import_node_child_process10.spawn)("git", args, {
22045
22432
  cwd,
22046
22433
  env,
22047
22434
  windowsHide: true,
@@ -22104,7 +22491,7 @@ function parseGitShortstat(raw) {
22104
22491
  }
22105
22492
  function runGitCommand(cwd, args, timeoutMs = 5e3) {
22106
22493
  return safeGitInvocation(cwd, args).then(
22107
- (git) => spawnGitCommand(cwd, git.args, git.env, timeoutMs),
22494
+ (git2) => spawnGitCommand(cwd, git2.args, git2.env, timeoutMs),
22108
22495
  (error) => ({
22109
22496
  code: 1,
22110
22497
  stdout: "",
@@ -22114,7 +22501,7 @@ function runGitCommand(cwd, args, timeoutMs = 5e3) {
22114
22501
  }
22115
22502
  function spawnGitCommand(cwd, args, env, timeoutMs) {
22116
22503
  return new Promise((resolveCommand) => {
22117
- const child = (0, import_node_child_process8.spawn)("git", args, {
22504
+ const child = (0, import_node_child_process10.spawn)("git", args, {
22118
22505
  cwd,
22119
22506
  env,
22120
22507
  windowsHide: true,
@@ -22256,7 +22643,7 @@ async function codexModelOptions() {
22256
22643
  { id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }
22257
22644
  ];
22258
22645
  try {
22259
- const raw = await (0, import_promises29.readFile)((0, import_node_path38.join)((0, import_node_os2.homedir)(), ".codex", "models_cache.json"), "utf8");
22646
+ const raw = await (0, import_promises31.readFile)((0, import_node_path40.join)((0, import_node_os3.homedir)(), ".codex", "models_cache.json"), "utf8");
22260
22647
  const parsed = JSON.parse(raw);
22261
22648
  const list = Array.isArray(parsed) ? parsed : parsed.models ?? [];
22262
22649
  const options = list.filter((model) => typeof model?.slug === "string").filter((model) => !/auto-review|reserve/i.test(model.slug)).map((model) => ({ id: model.slug, label: model.display_name?.trim() || model.slug }));
@@ -22280,7 +22667,7 @@ function cliModelDefaults(id) {
22280
22667
  }
22281
22668
  function detectCommand(command, cwd) {
22282
22669
  return new Promise((resolveDetect) => {
22283
- const child = (0, import_node_child_process8.spawn)(process.platform === "win32" ? "where.exe" : "sh", process.platform === "win32" ? [command] : ["-lc", `command -v ${command}`], {
22670
+ const child = (0, import_node_child_process10.spawn)(process.platform === "win32" ? "where.exe" : "sh", process.platform === "win32" ? [command] : ["-lc", `command -v ${command}`], {
22284
22671
  cwd,
22285
22672
  windowsHide: true,
22286
22673
  stdio: ["ignore", "pipe", "pipe"]
@@ -22307,7 +22694,7 @@ function commandMissingFromOutput(text) {
22307
22694
  return /not recognized|not found|unknown command|no such file|command not found|is not recognized as an internal or external command/.test(text.toLowerCase());
22308
22695
  }
22309
22696
  function redactProbeOutput(output) {
22310
- const home = (0, import_node_os2.homedir)();
22697
+ const home = (0, import_node_os3.homedir)();
22311
22698
  const homeVariants = [home, home.split("\\").join("\\\\"), home.split("\\").join("/")].filter((value) => value.length > 3);
22312
22699
  let scrubbed = output;
22313
22700
  for (const variant of homeVariants) scrubbed = scrubbed.split(variant).join("~");
@@ -22367,7 +22754,7 @@ function setupCommandFor(cliId, step) {
22367
22754
  function runShellCommand(command, cwd, timeoutMs = 18e4) {
22368
22755
  return new Promise((resolveRun) => {
22369
22756
  const useCmd = process.platform === "win32";
22370
- const child = (0, import_node_child_process8.spawn)(useCmd ? process.env.ComSpec || "cmd.exe" : "sh", useCmd ? ["/d", "/s", "/c", command] : ["-lc", command], {
22757
+ const child = (0, import_node_child_process10.spawn)(useCmd ? process.env.ComSpec || "cmd.exe" : "sh", useCmd ? ["/d", "/s", "/c", command] : ["-lc", command], {
22371
22758
  cwd,
22372
22759
  windowsHide: true,
22373
22760
  stdio: ["ignore", "pipe", "pipe"]
@@ -22401,7 +22788,7 @@ function openSystemTerminal(command, cwd) {
22401
22788
  const fullCommand = process.platform === "win32" ? `cd /d ${quotedCwd} && ${command}` : `cd ${quotedCwd} && ${command}`;
22402
22789
  let child;
22403
22790
  if (process.platform === "win32") {
22404
- child = (0, import_node_child_process8.spawn)("cmd.exe", ["/c", "start", "cmd.exe", "/k", fullCommand], {
22791
+ child = (0, import_node_child_process10.spawn)("cmd.exe", ["/c", "start", "cmd.exe", "/k", fullCommand], {
22405
22792
  cwd,
22406
22793
  windowsHide: true,
22407
22794
  stdio: "ignore",
@@ -22409,9 +22796,9 @@ function openSystemTerminal(command, cwd) {
22409
22796
  });
22410
22797
  } else if (process.platform === "darwin") {
22411
22798
  const script = `tell application "Terminal" to do script "${fullCommand.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
22412
- child = (0, import_node_child_process8.spawn)("osascript", ["-e", script], { cwd, windowsHide: true, stdio: "ignore", detached: true });
22799
+ child = (0, import_node_child_process10.spawn)("osascript", ["-e", script], { cwd, windowsHide: true, stdio: "ignore", detached: true });
22413
22800
  } else {
22414
- child = (0, import_node_child_process8.spawn)("x-terminal-emulator", ["-e", `bash -lc ${JSON.stringify(fullCommand)}`], {
22801
+ child = (0, import_node_child_process10.spawn)("x-terminal-emulator", ["-e", `bash -lc ${JSON.stringify(fullCommand)}`], {
22415
22802
  cwd,
22416
22803
  windowsHide: true,
22417
22804
  stdio: "ignore",
@@ -22459,19 +22846,19 @@ function isPlaceholderProjectName(value) {
22459
22846
  async function readMcpEvidence(cwd) {
22460
22847
  const candidates = MCP_CONFIG_PATHS.map((relativePath) => ({
22461
22848
  source: relativePath.replace(/\\/g, "/"),
22462
- path: (0, import_node_path38.resolve)(cwd, relativePath)
22849
+ path: (0, import_node_path40.resolve)(cwd, relativePath)
22463
22850
  }));
22464
22851
  const home = process.env.USERPROFILE || process.env.HOME;
22465
22852
  if (home) {
22466
22853
  candidates.push({
22467
22854
  source: "~/.codex/config.toml",
22468
- path: (0, import_node_path38.resolve)(home, ".codex", "config.toml")
22855
+ path: (0, import_node_path40.resolve)(home, ".codex", "config.toml")
22469
22856
  });
22470
22857
  }
22471
22858
  const evidence = [];
22472
22859
  for (const candidate of candidates) {
22473
22860
  try {
22474
- const text = await (0, import_promises29.readFile)(candidate.path, "utf8");
22861
+ const text = await (0, import_promises31.readFile)(candidate.path, "utf8");
22475
22862
  if (/mcp/i.test(text)) evidence.push({ source: candidate.source, text });
22476
22863
  } catch {
22477
22864
  }
@@ -22562,7 +22949,7 @@ async function enrichProjectMetadata(state, cwd) {
22562
22949
  async function readState(cwd) {
22563
22950
  let state;
22564
22951
  try {
22565
- const raw = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, ".viberaven", "last-scan.json"), "utf8");
22952
+ const raw = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, ".viberaven", "last-scan.json"), "utf8");
22566
22953
  const packageJson = await readPackageJson(cwd);
22567
22954
  const deps = dependencyNames(packageJson);
22568
22955
  const files = await listProjectFiles(cwd);
@@ -22808,7 +23195,7 @@ function quoteWindowsCmdArg(value) {
22808
23195
  }
22809
23196
  async function whereExe(command, cwd) {
22810
23197
  return new Promise((resolvePath) => {
22811
- const child = (0, import_node_child_process8.spawn)("where.exe", [command], {
23198
+ const child = (0, import_node_child_process10.spawn)("where.exe", [command], {
22812
23199
  cwd,
22813
23200
  windowsHide: true,
22814
23201
  stdio: ["ignore", "pipe", "ignore"]
@@ -22829,7 +23216,7 @@ async function whereExe(command, cwd) {
22829
23216
  }
22830
23217
  function expandShimPath(value, base) {
22831
23218
  const relative8 = value.replace(/^%(?:dp0%\\+|~dp0\\*)/i, "");
22832
- return relative8 === value ? value : (0, import_node_path38.join)(base, ...relative8.split(/[\\/]+/));
23219
+ return relative8 === value ? value : (0, import_node_path40.join)(base, ...relative8.split(/[\\/]+/));
22833
23220
  }
22834
23221
  function findShimTarget(lines, pattern, accept = () => true) {
22835
23222
  for (const line of lines) {
@@ -22840,21 +23227,21 @@ function findShimTarget(lines, pattern, accept = () => true) {
22840
23227
  }
22841
23228
  async function resolveWindowsShimTarget(shimPath) {
22842
23229
  try {
22843
- const content = await (0, import_promises29.readFile)(shimPath, "utf8");
22844
- const base = (0, import_node_path38.dirname)(shimPath);
23230
+ const content = await (0, import_promises31.readFile)(shimPath, "utf8");
23231
+ const base = (0, import_node_path40.dirname)(shimPath);
22845
23232
  const lines = content.split(/\r?\n/);
22846
23233
  const trailingArgs = (line, after) => [...line.slice(after).split("%*")[0].matchAll(/"([^"]*)"|([^\s"&|<>]+)/g)].map((token) => expandShimPath(token[1] ?? token[2], base)).filter((value) => value.length > 0 && !value.includes("%"));
22847
23234
  const script = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.js)"/i);
22848
23235
  if (script) {
22849
23236
  return {
22850
23237
  command: process.execPath,
22851
- args: [(0, import_node_path38.join)(base, ...script.match[1].split(/[\\/]+/)), ...trailingArgs(script.line, script.match.index + script.match[0].length)]
23238
+ args: [(0, import_node_path40.join)(base, ...script.match[1].split(/[\\/]+/)), ...trailingArgs(script.line, script.match.index + script.match[0].length)]
22852
23239
  };
22853
23240
  }
22854
- const binary = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.exe)"/i, (target) => (0, import_node_path38.basename)(target).toLowerCase() !== "node.exe");
23241
+ const binary = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.exe)"/i, (target) => (0, import_node_path40.basename)(target).toLowerCase() !== "node.exe");
22855
23242
  if (binary) {
22856
23243
  return {
22857
- command: (0, import_node_path38.join)(base, ...binary.match[1].split(/[\\/]+/)),
23244
+ command: (0, import_node_path40.join)(base, ...binary.match[1].split(/[\\/]+/)),
22858
23245
  args: trailingArgs(binary.line, binary.match.index + binary.match[0].length)
22859
23246
  };
22860
23247
  }
@@ -22875,7 +23262,7 @@ function killProcessTree(pid, fallback) {
22875
23262
  return;
22876
23263
  }
22877
23264
  if (process.platform === "win32") {
22878
- const killer = (0, import_node_child_process8.spawn)("taskkill", ["/pid", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" });
23265
+ const killer = (0, import_node_child_process10.spawn)("taskkill", ["/pid", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" });
22879
23266
  killer.once("error", fallback);
22880
23267
  killer.once("close", (code) => {
22881
23268
  if (code !== 0) fallback();
@@ -22900,7 +23287,7 @@ async function runAgentCommand(command, args, cwd, stdin, runId) {
22900
23287
  const spawnCommand = shim?.command ?? (useCmdShim ? process.env.ComSpec || "cmd.exe" : command);
22901
23288
  const spawnArgs = shim ? [...shim.args, ...args] : useCmdShim ? ["/d", "/s", "/c", [command, ...args.map(quoteWindowsCmdArg)].join(" ")] : args;
22902
23289
  return new Promise((resolveRun) => {
22903
- const child = (0, import_node_child_process8.spawn)(spawnCommand, spawnArgs, {
23290
+ const child = (0, import_node_child_process10.spawn)(spawnCommand, spawnArgs, {
22904
23291
  cwd,
22905
23292
  windowsHide: true,
22906
23293
  // A separate process group lets Stop and timeout terminate descendants on Unix too.
@@ -22979,8 +23366,8 @@ async function writeChatContextArtifact(cwd, request, prompt) {
22979
23366
  "",
22980
23367
  prompt
22981
23368
  ].filter((line) => typeof line === "string");
22982
- await (0, import_promises29.mkdir)((0, import_node_path38.join)(cwd, ".viberaven"), { recursive: true });
22983
- await (0, import_promises29.writeFile)((0, import_node_path38.join)(cwd, ".viberaven", "chat-context.md"), `${lines.join("\n")}
23369
+ await (0, import_promises31.mkdir)((0, import_node_path40.join)(cwd, ".viberaven"), { recursive: true });
23370
+ await (0, import_promises31.writeFile)((0, import_node_path40.join)(cwd, ".viberaven", "chat-context.md"), `${lines.join("\n")}
22984
23371
  `, "utf8");
22985
23372
  } catch {
22986
23373
  }
@@ -23000,13 +23387,13 @@ async function runAgentChat(cwd, request) {
23000
23387
  }
23001
23388
  const prompt = await buildAgentChatPrompt(request, cwd);
23002
23389
  await writeChatContextArtifact(cwd, request, prompt);
23003
- const outputPath = request.cliId === "codex" ? (0, import_node_path38.join)(cwd, ".viberaven", `studio-agent-${Date.now()}-${Math.random().toString(36).slice(2)}.md`) : void 0;
23004
- if (outputPath) await (0, import_promises29.mkdir)((0, import_node_path38.dirname)(outputPath), { recursive: true });
23390
+ const outputPath = request.cliId === "codex" ? (0, import_node_path40.join)(cwd, ".viberaven", `studio-agent-${Date.now()}-${Math.random().toString(36).slice(2)}.md`) : void 0;
23391
+ if (outputPath) await (0, import_promises31.mkdir)((0, import_node_path40.dirname)(outputPath), { recursive: true });
23005
23392
  const { command, args, stdin } = commandForAgentChat(request, prompt, cwd, outputPath);
23006
23393
  const result = await runAgentCommand(command, args, cwd, stdin, request.runId);
23007
23394
  if (outputPath) {
23008
23395
  try {
23009
- const finalMessage = (await (0, import_promises29.readFile)(outputPath, "utf8")).trim();
23396
+ const finalMessage = (await (0, import_promises31.readFile)(outputPath, "utf8")).trim();
23010
23397
  if (finalMessage) return { ...result, output: finalMessage };
23011
23398
  } catch {
23012
23399
  }
@@ -23018,8 +23405,8 @@ function firstGapId(state) {
23018
23405
  return state.providers.find((provider2) => provider2.nextFix?.id)?.nextFix?.id;
23019
23406
  }
23020
23407
  async function runLocalAction(cwd, intent) {
23021
- const artifactDir = (0, import_node_path38.join)(cwd, ".viberaven");
23022
- await (0, import_promises29.mkdir)(artifactDir, { recursive: true });
23408
+ const artifactDir = (0, import_node_path40.join)(cwd, ".viberaven");
23409
+ await (0, import_promises31.mkdir)(artifactDir, { recursive: true });
23023
23410
  if (intent === "preview_rehearsal") {
23024
23411
  const state2 = await readState(cwd);
23025
23412
  const topProvider = state2.providers[0];
@@ -23060,7 +23447,7 @@ async function runLocalAction(cwd, intent) {
23060
23447
  proof,
23061
23448
  ""
23062
23449
  ].join("\n");
23063
- await (0, import_promises29.writeFile)((0, import_node_path38.join)(artifactDir, "preview-rehearsal.md"), markdown, "utf8");
23450
+ await (0, import_promises31.writeFile)((0, import_node_path40.join)(artifactDir, "preview-rehearsal.md"), markdown, "utf8");
23064
23451
  return {
23065
23452
  title: "Preview rehearsal ready",
23066
23453
  summary: `${projectName}: ${gateLabel} with ${state2.providers.length} provider beat${state2.providers.length === 1 ? "" : "s"}`,
@@ -23070,7 +23457,7 @@ async function runLocalAction(cwd, intent) {
23070
23457
  if (intent === "audit_vercel_supabase") {
23071
23458
  const auditInput = await collectVercelSupabaseAuditInput(cwd);
23072
23459
  const result2 = buildVercelSupabaseAudit(auditInput);
23073
- await (0, import_promises29.writeFile)((0, import_node_path38.join)(artifactDir, "audit-vercel-supabase.txt"), `${renderVercelSupabaseAudit(result2)}
23460
+ await (0, import_promises31.writeFile)((0, import_node_path40.join)(artifactDir, "audit-vercel-supabase.txt"), `${renderVercelSupabaseAudit(result2)}
23074
23461
  `, "utf8");
23075
23462
  return {
23076
23463
  title: result2.status === "pass" ? "Audit passed" : "Audit needs work",
@@ -23098,7 +23485,7 @@ async function runLocalAction(cwd, intent) {
23098
23485
  const mode = intent === "heal_prompt" ? "prompt" : intent === "heal_apply" ? "apply" : "plan";
23099
23486
  const result = await runHealCommand({ cwd, mode, gapId, yes: mode === "apply", noVerify: true });
23100
23487
  if (mode === "apply") {
23101
- await (0, import_promises29.writeFile)((0, import_node_path38.join)(artifactDir, "heal-apply-result.json"), `${JSON.stringify(result, null, 2)}
23488
+ await (0, import_promises31.writeFile)((0, import_node_path40.join)(artifactDir, "heal-apply-result.json"), `${JSON.stringify(result, null, 2)}
23102
23489
  `, "utf8");
23103
23490
  }
23104
23491
  return {
@@ -23108,14 +23495,14 @@ async function runLocalAction(cwd, intent) {
23108
23495
  };
23109
23496
  }
23110
23497
  async function sendArtifact(cwd, rel, response, contentType = "text/plain; charset=utf-8") {
23111
- const absolute = (0, import_node_path38.resolve)(cwd, rel);
23112
- const root = (0, import_node_path38.resolve)(cwd);
23498
+ const absolute = (0, import_node_path40.resolve)(cwd, rel);
23499
+ const root = (0, import_node_path40.resolve)(cwd);
23113
23500
  if (!absolute.startsWith(root)) {
23114
23501
  sendText(response, 403, "Forbidden");
23115
23502
  return;
23116
23503
  }
23117
23504
  try {
23118
- const text = await (0, import_promises29.readFile)(absolute, "utf8");
23505
+ const text = await (0, import_promises31.readFile)(absolute, "utf8");
23119
23506
  response.writeHead(200, { "content-type": contentType });
23120
23507
  response.end(text);
23121
23508
  } catch {
@@ -23124,7 +23511,7 @@ async function sendArtifact(cwd, rel, response, contentType = "text/plain; chars
23124
23511
  }
23125
23512
  async function sendReportArtifact(cwd, response) {
23126
23513
  try {
23127
- const text = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, ".viberaven", "report.html"), "utf8");
23514
+ const text = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, ".viberaven", "report.html"), "utf8");
23128
23515
  response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
23129
23516
  response.end(text);
23130
23517
  return;
@@ -23251,7 +23638,7 @@ async function sendReportArtifact(cwd, response) {
23251
23638
  }
23252
23639
  async function sendExtensionIcon(cwd, response) {
23253
23640
  try {
23254
- const body = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, "media", "extension-icon.png"));
23641
+ const body = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, "media", "extension-icon.png"));
23255
23642
  sendBinary(response, 200, "image/png", body);
23256
23643
  } catch {
23257
23644
  sendText(response, 404, "Icon not found");
@@ -23264,15 +23651,15 @@ async function sendMangaAsset(pathname, response) {
23264
23651
  return;
23265
23652
  }
23266
23653
  const candidates = [
23267
- (0, import_node_path38.join)(__dirname, "manga", name),
23654
+ (0, import_node_path40.join)(__dirname, "manga", name),
23268
23655
  // installed + dev: <pkg>/dist/manga
23269
- (0, import_node_path38.join)(__dirname, "..", "assets", "manga", name),
23656
+ (0, import_node_path40.join)(__dirname, "..", "assets", "manga", name),
23270
23657
  // fallback: <pkg>/assets/manga (source)
23271
- (0, import_node_path38.join)(__dirname, "..", "..", "assets", "manga", name)
23658
+ (0, import_node_path40.join)(__dirname, "..", "..", "assets", "manga", name)
23272
23659
  ];
23273
23660
  for (const candidate of candidates) {
23274
23661
  try {
23275
- const body = await (0, import_promises29.readFile)(candidate);
23662
+ const body = await (0, import_promises31.readFile)(candidate);
23276
23663
  response.setHeader("cache-control", "no-cache");
23277
23664
  sendBinary(response, 200, contentTypeForAsset(candidate), body);
23278
23665
  return;
@@ -23282,7 +23669,7 @@ async function sendMangaAsset(pathname, response) {
23282
23669
  sendText(response, 404, "Asset not found");
23283
23670
  }
23284
23671
  function contentTypeForAsset(pathname) {
23285
- switch ((0, import_node_path38.extname)(pathname).toLowerCase()) {
23672
+ switch ((0, import_node_path40.extname)(pathname).toLowerCase()) {
23286
23673
  case ".svg":
23287
23674
  return "image/svg+xml; charset=utf-8";
23288
23675
  case ".png":
@@ -23299,14 +23686,14 @@ function contentTypeForAsset(pathname) {
23299
23686
  }
23300
23687
  async function sendBundledReportAsset(pathname, response) {
23301
23688
  const rel = decodeURIComponent(pathname.replace(/^\/report\//, ""));
23302
- const assetRoot = (0, import_node_path38.resolve)(getBundledReportAssetsDir());
23303
- const absolute = (0, import_node_path38.resolve)(assetRoot, rel);
23689
+ const assetRoot = (0, import_node_path40.resolve)(getBundledReportAssetsDir());
23690
+ const absolute = (0, import_node_path40.resolve)(assetRoot, rel);
23304
23691
  if (!absolute.startsWith(assetRoot)) {
23305
23692
  sendText(response, 403, "Forbidden");
23306
23693
  return;
23307
23694
  }
23308
23695
  try {
23309
- const body = await (0, import_promises29.readFile)(absolute);
23696
+ const body = await (0, import_promises31.readFile)(absolute);
23310
23697
  sendBinary(response, 200, contentTypeForAsset(absolute), body);
23311
23698
  } catch {
23312
23699
  sendText(response, 404, "Asset not found");
@@ -23328,18 +23715,18 @@ async function bundleStackClient(entryPath) {
23328
23715
  return output.text;
23329
23716
  }
23330
23717
  async function sendStackAppJs(response) {
23331
- const distPath = (0, import_node_path38.join)(__dirname, "stack", "app.js");
23718
+ const distPath = (0, import_node_path40.join)(__dirname, "stack", "app.js");
23332
23719
  try {
23333
- const body = await (0, import_promises29.readFile)(distPath);
23720
+ const body = await (0, import_promises31.readFile)(distPath);
23334
23721
  response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "cache-control": "no-store" });
23335
23722
  response.end(body);
23336
23723
  return;
23337
23724
  } catch {
23338
23725
  }
23339
- const entryPath = (0, import_node_path38.join)(__dirname, "stack", "main.ts");
23726
+ const entryPath = (0, import_node_path40.join)(__dirname, "stack", "main.ts");
23340
23727
  let mtimeMs;
23341
23728
  try {
23342
- mtimeMs = (await (0, import_promises29.stat)(entryPath)).mtimeMs;
23729
+ mtimeMs = (await (0, import_promises31.stat)(entryPath)).mtimeMs;
23343
23730
  } catch {
23344
23731
  sendText(response, 404, "Stack client entry not found: src/local-ui/stack/main.ts is missing.");
23345
23732
  return;
@@ -23358,7 +23745,7 @@ async function sendStackAppJs(response) {
23358
23745
  }
23359
23746
  async function sendStackAppCss(response) {
23360
23747
  try {
23361
- const body = await (0, import_promises29.readFile)((0, import_node_path38.join)(__dirname, "stack", "stack.css"));
23748
+ const body = await (0, import_promises31.readFile)((0, import_node_path40.join)(__dirname, "stack", "stack.css"));
23362
23749
  response.writeHead(200, { "content-type": "text/css; charset=utf-8", "cache-control": "no-store" });
23363
23750
  response.end(body);
23364
23751
  } catch {
@@ -23367,7 +23754,7 @@ async function sendStackAppCss(response) {
23367
23754
  }
23368
23755
  async function readProviderVerifyLedger(cwd) {
23369
23756
  try {
23370
- const raw = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, ".viberaven", "provider-verify.json"), "utf8");
23757
+ const raw = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, ".viberaven", "provider-verify.json"), "utf8");
23371
23758
  const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
23372
23759
  return isRecord5(parsed) ? parsed : {};
23373
23760
  } catch {
@@ -23377,8 +23764,8 @@ async function readProviderVerifyLedger(cwd) {
23377
23764
  async function writeProviderVerifyEntry(cwd, providerId, entry) {
23378
23765
  const ledger = await readProviderVerifyLedger(cwd);
23379
23766
  ledger[providerId] = entry;
23380
- await (0, import_promises29.mkdir)((0, import_node_path38.join)(cwd, ".viberaven"), { recursive: true });
23381
- await (0, import_promises29.writeFile)((0, import_node_path38.join)(cwd, ".viberaven", "provider-verify.json"), `${JSON.stringify(ledger, null, 2)}
23767
+ await (0, import_promises31.mkdir)((0, import_node_path40.join)(cwd, ".viberaven"), { recursive: true });
23768
+ await (0, import_promises31.writeFile)((0, import_node_path40.join)(cwd, ".viberaven", "provider-verify.json"), `${JSON.stringify(ledger, null, 2)}
23382
23769
  `, "utf8");
23383
23770
  }
23384
23771
  async function handleRequest(request, response, options) {
@@ -23421,6 +23808,18 @@ async function handleRequest(request, response, options) {
23421
23808
  sendText(response, 404, "This VibeRaven surface has been removed. Use the Launch Canvas at /.");
23422
23809
  return;
23423
23810
  }
23811
+ if (request.method === "GET" && url.pathname === "/api/github-workflow") {
23812
+ sendJson(response, await githubWorkflowStatus(options.cwd));
23813
+ return;
23814
+ }
23815
+ if (request.method === "POST" && url.pathname === "/api/github-workflow") {
23816
+ try {
23817
+ sendJson(response, await writeGithubWorkflow(options.cwd));
23818
+ } catch (error) {
23819
+ sendJsonStatus(response, 500, { error: `Could not write the workflow: ${error instanceof Error ? error.message : String(error)}` });
23820
+ }
23821
+ return;
23822
+ }
23424
23823
  if (request.method === "GET" && url.pathname === "/api/project") {
23425
23824
  sendJson(response, await readState(options.cwd));
23426
23825
  return;
@@ -23439,13 +23838,13 @@ async function handleRequest(request, response, options) {
23439
23838
  return;
23440
23839
  }
23441
23840
  if (request.method === "GET" && url.pathname === "/api/architecture-map") {
23442
- const mapPath = (0, import_node_path38.join)(options.cwd, ".viberaven", "architecture-map.md");
23443
- const markdown = await (0, import_promises29.readFile)(mapPath, "utf8").catch(() => null);
23841
+ const mapPath = (0, import_node_path40.join)(options.cwd, ".viberaven", "architecture-map.md");
23842
+ const markdown = await (0, import_promises31.readFile)(mapPath, "utf8").catch(() => null);
23444
23843
  if (markdown === null) {
23445
23844
  sendJsonStatus(response, 404, { error: "No architecture map yet. Run a scan first (it is written on every scan)." });
23446
23845
  return;
23447
23846
  }
23448
- const dataRaw = await (0, import_promises29.readFile)((0, import_node_path38.join)(options.cwd, ".viberaven", "architecture-map.json"), "utf8").catch(() => null);
23847
+ const dataRaw = await (0, import_promises31.readFile)((0, import_node_path40.join)(options.cwd, ".viberaven", "architecture-map.json"), "utf8").catch(() => null);
23449
23848
  let data = null;
23450
23849
  if (dataRaw) {
23451
23850
  try {
@@ -23454,7 +23853,7 @@ async function handleRequest(request, response, options) {
23454
23853
  data = null;
23455
23854
  }
23456
23855
  }
23457
- const contextRaw = await (0, import_promises29.readFile)((0, import_node_path38.join)(options.cwd, ".viberaven", "context-map.json"), "utf8").catch(() => null);
23856
+ const contextRaw = await (0, import_promises31.readFile)((0, import_node_path40.join)(options.cwd, ".viberaven", "context-map.json"), "utf8").catch(() => null);
23458
23857
  let gaps = [];
23459
23858
  if (contextRaw) {
23460
23859
  try {
@@ -23720,35 +24119,35 @@ async function handleRequest(request, response, options) {
23720
24119
  return;
23721
24120
  }
23722
24121
  if (request.method === "GET" && url.pathname === "/api/artifacts/tasklist") {
23723
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "agent-tasklist.md"), response);
24122
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "agent-tasklist.md"), response);
23724
24123
  return;
23725
24124
  }
23726
24125
  if (request.method === "GET" && url.pathname === "/api/artifacts/playbook") {
23727
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "launch-playbook.md"), response);
24126
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "launch-playbook.md"), response);
23728
24127
  return;
23729
24128
  }
23730
24129
  if (request.method === "GET" && url.pathname === "/api/artifacts/audit") {
23731
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "audit-vercel-supabase.txt"), response);
24130
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "audit-vercel-supabase.txt"), response);
23732
24131
  return;
23733
24132
  }
23734
24133
  if (request.method === "GET" && url.pathname === "/api/artifacts/cleanup") {
23735
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "context-cleanup.md"), response);
24134
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "context-cleanup.md"), response);
23736
24135
  return;
23737
24136
  }
23738
24137
  if (request.method === "GET" && url.pathname === "/api/artifacts/preview") {
23739
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "preview-rehearsal.md"), response);
24138
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "preview-rehearsal.md"), response);
23740
24139
  return;
23741
24140
  }
23742
24141
  if (request.method === "GET" && url.pathname === "/api/artifacts/heal-plan") {
23743
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "heal-plan.md"), response);
24142
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "heal-plan.md"), response);
23744
24143
  return;
23745
24144
  }
23746
24145
  if (request.method === "GET" && url.pathname === "/api/artifacts/heal-prompt") {
23747
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "heal-prompt.md"), response);
24146
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "heal-prompt.md"), response);
23748
24147
  return;
23749
24148
  }
23750
24149
  if (request.method === "GET" && url.pathname === "/api/artifacts/heal-apply") {
23751
- await sendArtifact(options.cwd, (0, import_node_path38.join)(".viberaven", "heal-apply-result.json"), response, "application/json; charset=utf-8");
24150
+ await sendArtifact(options.cwd, (0, import_node_path40.join)(".viberaven", "heal-apply-result.json"), response, "application/json; charset=utf-8");
23752
24151
  return;
23753
24152
  }
23754
24153
  if (request.method === "GET" && url.pathname === "/api/artifacts/report") {
@@ -23774,12 +24173,12 @@ async function handleRequest(request, response, options) {
23774
24173
  }
23775
24174
  if (request.method === "GET" && url.pathname === "/vendor/anime.umd.min.js") {
23776
24175
  for (const candidate of [
23777
- (0, import_node_path38.join)(__dirname, "vendor", "anime.umd.min.js"),
23778
- (0, import_node_path38.join)(__dirname, "..", "assets", "vendor", "anime.umd.min.js"),
23779
- (0, import_node_path38.join)(__dirname, "..", "..", "assets", "vendor", "anime.umd.min.js")
24176
+ (0, import_node_path40.join)(__dirname, "vendor", "anime.umd.min.js"),
24177
+ (0, import_node_path40.join)(__dirname, "..", "assets", "vendor", "anime.umd.min.js"),
24178
+ (0, import_node_path40.join)(__dirname, "..", "..", "assets", "vendor", "anime.umd.min.js")
23780
24179
  ]) {
23781
24180
  try {
23782
- const body = await (0, import_promises29.readFile)(candidate);
24181
+ const body = await (0, import_promises31.readFile)(candidate);
23783
24182
  response.setHeader("cache-control", "public, max-age=604800, immutable");
23784
24183
  sendBinary(response, 200, "text/javascript; charset=utf-8", body);
23785
24184
  return;
@@ -23996,7 +24395,7 @@ function listen(server, startPort) {
23996
24395
  });
23997
24396
  }
23998
24397
  async function startLocalUiServer(options) {
23999
- const cwd = (0, import_node_path38.resolve)(options.cwd);
24398
+ const cwd = (0, import_node_path40.resolve)(options.cwd);
24000
24399
  const scanRunner = options.scanRunner ?? defaultScanRunner;
24001
24400
  const autoScan = { state: "idle" };
24002
24401
  const fullCheck = new FullCheckService(cwd, options.fullCheck);
@@ -24013,7 +24412,7 @@ async function startLocalUiServer(options) {
24013
24412
  });
24014
24413
  const port = await listen(server, options.port ?? 4177);
24015
24414
  guard.port = port;
24016
- const hasArtifact = await (0, import_promises29.readFile)((0, import_node_path38.join)(cwd, ".viberaven", "last-scan.json"), "utf8").then(
24415
+ const hasArtifact = await (0, import_promises31.readFile)((0, import_node_path40.join)(cwd, ".viberaven", "last-scan.json"), "utf8").then(
24017
24416
  () => true,
24018
24417
  () => false
24019
24418
  );
@@ -24052,16 +24451,17 @@ async function waitForServerShutdown() {
24052
24451
  process.once("SIGTERM", done);
24053
24452
  });
24054
24453
  }
24055
- var import_node_http, import_node_child_process8, import_node_crypto6, import_promises29, import_node_os2, import_node_path38, CLI_AGENT_SETUP, MCP_CONFIG_PATHS, MCP_PROVIDER_NEEDLES, MCP_CONNECT_COMMANDS, MCP_SERVER_RECIPES, STUDIO_TOKEN_HEADER, PROVIDER_IDS, STUDIO_STATUS_ARGS, CLI_AUTH_PROBE, AGENT_RUN_TIMEOUT_MS, activeAgentRuns, stackBundleCache;
24454
+ var import_node_http, import_node_child_process10, import_node_crypto6, import_promises31, import_node_os3, import_node_path40, CLI_AGENT_SETUP, MCP_CONFIG_PATHS, MCP_PROVIDER_NEEDLES, MCP_CONNECT_COMMANDS, MCP_SERVER_RECIPES, STUDIO_TOKEN_HEADER, PROVIDER_IDS, STUDIO_STATUS_ARGS, CLI_AUTH_PROBE, AGENT_RUN_TIMEOUT_MS, activeAgentRuns, stackBundleCache;
24056
24455
  var init_server = __esm({
24057
24456
  "src/local-ui/server.ts"() {
24058
24457
  "use strict";
24059
24458
  import_node_http = require("node:http");
24060
- import_node_child_process8 = require("node:child_process");
24459
+ import_node_child_process10 = require("node:child_process");
24061
24460
  import_node_crypto6 = require("node:crypto");
24062
- import_promises29 = require("node:fs/promises");
24063
- import_node_os2 = require("node:os");
24064
- import_node_path38 = require("node:path");
24461
+ import_promises31 = require("node:fs/promises");
24462
+ import_node_os3 = require("node:os");
24463
+ import_node_path40 = require("node:path");
24464
+ init_initGithub();
24065
24465
  init_cleanPlan();
24066
24466
  init_audit();
24067
24467
  init_heal();
@@ -24102,8 +24502,8 @@ var init_server = __esm({
24102
24502
  MCP_CONFIG_PATHS = [
24103
24503
  ".mcp.json",
24104
24504
  "mcp.json",
24105
- (0, import_node_path38.join)(".cursor", "mcp.json"),
24106
- (0, import_node_path38.join)(".vscode", "mcp.json")
24505
+ (0, import_node_path40.join)(".cursor", "mcp.json"),
24506
+ (0, import_node_path40.join)(".vscode", "mcp.json")
24107
24507
  ];
24108
24508
  MCP_PROVIDER_NEEDLES = {
24109
24509
  supabase: ["supabase", "@supabase/mcp", "mcp-server-supabase"],
@@ -24272,11 +24672,11 @@ var init_nextActionBlock = __esm({
24272
24672
 
24273
24673
  // src/providerMcpBridge.ts
24274
24674
  function defaultMcpConfigPaths() {
24275
- const home = (0, import_node_os3.homedir)();
24675
+ const home = (0, import_node_os4.homedir)();
24276
24676
  return [
24277
- (0, import_node_path39.join)(home, ".config", "claude", "claude_desktop_config.json"),
24278
- (0, import_node_path39.join)(home, ".cursor", "mcp.json"),
24279
- (0, import_node_path39.join)(home, ".gemini", "antigravity", "mcp_config.json")
24677
+ (0, import_node_path41.join)(home, ".config", "claude", "claude_desktop_config.json"),
24678
+ (0, import_node_path41.join)(home, ".cursor", "mcp.json"),
24679
+ (0, import_node_path41.join)(home, ".gemini", "antigravity", "mcp_config.json")
24280
24680
  ];
24281
24681
  }
24282
24682
  function resolveConfigPaths() {
@@ -24305,11 +24705,11 @@ function findServerEntry(servers, provider2) {
24305
24705
  function findProviderMcpConfig(provider2, configPaths) {
24306
24706
  const paths = configPaths ?? resolveConfigPaths();
24307
24707
  for (const path of paths) {
24308
- if (!(0, import_node_fs14.existsSync)(path)) {
24708
+ if (!(0, import_node_fs15.existsSync)(path)) {
24309
24709
  continue;
24310
24710
  }
24311
24711
  try {
24312
- const raw = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
24712
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(path, "utf8"));
24313
24713
  const servers = parseMcpServers(raw);
24314
24714
  if (!servers) {
24315
24715
  continue;
@@ -24353,13 +24753,13 @@ async function verifyProviderGap(options) {
24353
24753
  fallbackCommand: FALLBACK_COMMAND
24354
24754
  };
24355
24755
  }
24356
- var import_node_fs14, import_node_os3, import_node_path39, FALLBACK_COMMAND, SUPPORTED_PROVIDERS, configPathsOverride;
24756
+ var import_node_fs15, import_node_os4, import_node_path41, FALLBACK_COMMAND, SUPPORTED_PROVIDERS, configPathsOverride;
24357
24757
  var init_providerMcpBridge = __esm({
24358
24758
  "src/providerMcpBridge.ts"() {
24359
24759
  "use strict";
24360
- import_node_fs14 = require("node:fs");
24361
- import_node_os3 = require("node:os");
24362
- import_node_path39 = require("node:path");
24760
+ import_node_fs15 = require("node:fs");
24761
+ import_node_os4 = require("node:os");
24762
+ import_node_path41 = require("node:path");
24363
24763
  FALLBACK_COMMAND = "npx -y viberaven audit --vercel-supabase --json";
24364
24764
  SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["supabase", "vercel"]);
24365
24765
  }
@@ -24373,7 +24773,8 @@ __export(cli_exports, {
24373
24773
  parseArgs: () => parseArgs,
24374
24774
  printHelp: () => printHelp,
24375
24775
  resolveDefaultEntrypointMode: () => resolveDefaultEntrypointMode,
24376
- runScanCommand: () => runScanCommand
24776
+ runScanCommand: () => runScanCommand,
24777
+ stackInitialPath: () => stackInitialPath
24377
24778
  });
24378
24779
  module.exports = __toCommonJS(cli_exports);
24379
24780
  function printHelp() {
@@ -24388,6 +24789,9 @@ Usage:
24388
24789
  viberaven tui Interactive terminal menu
24389
24790
 
24390
24791
  viberaven check [--json] [--quiet] [path]
24792
+ viberaven --stack supabase,vercel,stripe Open the Studio with these services already picked
24793
+ viberaven check --base <ref> [--markdown] What this change introduced and fixed, compared with <ref>
24794
+ viberaven init --github [--dry-run] Check every pull request in GitHub Actions
24391
24795
  Local production check: one line per finding, exit 1 on blockers
24392
24796
 
24393
24797
  viberaven fix [--gap <id>] [--dry-run] [path]
@@ -24537,12 +24941,20 @@ function isBooleanFlag(command, key) {
24537
24941
  if (key === "open" && (command === "" || command === "scan" || command === "report")) return true;
24538
24942
  if (key === "verify" && command === "") return true;
24539
24943
  if (key === "quiet" && command === "check") return true;
24944
+ if (key === "markdown" && command === "check") return true;
24945
+ if (key === "github" && command === "init") return true;
24946
+ if (key === "force" && command === "init") return true;
24540
24947
  if (key === "vercel-supabase" && command === "audit") return true;
24541
24948
  if (key === "json" && command === "validate-npm-package") return true;
24542
24949
  if (key === "dry-run" && (command === "init" || command === "fix")) return true;
24543
24950
  if (key === "agents" && command === "doctor") return true;
24544
24951
  return false;
24545
24952
  }
24953
+ function stackInitialPath(flags) {
24954
+ if (typeof flags.stack !== "string") return void 0;
24955
+ const ids = flags.stack.split(",").map((id) => id.trim().toLowerCase()).filter(Boolean);
24956
+ return ids.length ? `/${setupFragment(ids)}` : void 0;
24957
+ }
24546
24958
  function hasFlag(flags, key) {
24547
24959
  return flags[key] === true || typeof flags[key] === "string";
24548
24960
  }
@@ -24570,7 +24982,7 @@ async function cmdProviderVerify(flags, positional) {
24570
24982
  return result.verified ? 0 : 1;
24571
24983
  }
24572
24984
  async function cmdStatus(flags, positional) {
24573
- const startDir = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
24985
+ const startDir = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24574
24986
  let artifact;
24575
24987
  try {
24576
24988
  artifact = await loadLastArtifact(startDir);
@@ -24609,7 +25021,7 @@ async function cmdStatus(flags, positional) {
24609
25021
  return 0;
24610
25022
  }
24611
25023
  async function runScanCommand(flags, positional, options) {
24612
- const workspacePath = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
25024
+ const workspacePath = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
24613
25025
  if (!options?.deferMachineOutput) {
24614
25026
  console.log(`Scanning ${workspacePath}\u2026 (local, offline)`);
24615
25027
  }
@@ -24636,7 +25048,7 @@ async function runScanCommand(flags, positional, options) {
24636
25048
  printNextActionBlock(block);
24637
25049
  printProviderActionBlock(tasks);
24638
25050
  try {
24639
- const manifest = JSON.parse(await (0, import_promises30.readFile)(paths.actionsPath, "utf8"));
25051
+ const manifest = JSON.parse(await (0, import_promises32.readFile)(paths.actionsPath, "utf8"));
24640
25052
  console.log(renderActionSurface(manifest, { limit: 5 }).trimEnd());
24641
25053
  } catch (error) {
24642
25054
  console.warn(error instanceof Error ? error.message : String(error));
@@ -24653,7 +25065,7 @@ async function runScanCommand(flags, positional, options) {
24653
25065
  return { exitCode: 0, artifacts: paths };
24654
25066
  }
24655
25067
  async function cmdReport(flags, positional) {
24656
- const startDir = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25068
+ const startDir = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24657
25069
  try {
24658
25070
  const paths = await refreshReportFromDisk(startDir);
24659
25071
  console.log(`Report refreshed: ${paths.reportPath}`);
@@ -24675,7 +25087,7 @@ async function cmdReport(flags, positional) {
24675
25087
  }
24676
25088
  }
24677
25089
  async function cmdPrompt(flags, positional) {
24678
- const startDir = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25090
+ const startDir = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24679
25091
  let artifact;
24680
25092
  try {
24681
25093
  artifact = await loadLastArtifact(startDir);
@@ -24772,7 +25184,7 @@ async function main() {
24772
25184
  const wantsJsonl = hasFlag(flags, "jsonl");
24773
25185
  const wantsStrict = hasFlag(flags, "strict");
24774
25186
  if (flags.condense) {
24775
- const cwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25187
+ const cwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24776
25188
  const result = await runCondenseCommand({ cwd });
24777
25189
  console.log(`VibeRaven context map refreshed: ${result.contextMapPath}`);
24778
25190
  return 0;
@@ -24792,7 +25204,7 @@ async function main() {
24792
25204
  }
24793
25205
  if (!command && flags.verify === true && typeof flags.action === "string") {
24794
25206
  return runVerifyActionCommand({
24795
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
25207
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
24796
25208
  actionId: flags.action
24797
25209
  });
24798
25210
  }
@@ -24803,7 +25215,7 @@ async function main() {
24803
25215
  console.error("VibeRaven could not produce machine output because scan artifacts were not written.");
24804
25216
  return 3;
24805
25217
  }
24806
- const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0, import_promises30.readFile)(scanResult.artifacts.gateResultPath, "utf8")) : void 0;
25218
+ const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0, import_promises32.readFile)(scanResult.artifacts.gateResultPath, "utf8")) : void 0;
24807
25219
  const strictExitCode = wantsStrict && gateResult ? exitCodeForStrictGate(gateResult, { failOnWarnings: flags.strict === "warning" }) : scanResult.exitCode;
24808
25220
  if (wantsJson && gateResult) {
24809
25221
  process.stdout.write(renderGateResultJson(gateResult));
@@ -24825,8 +25237,8 @@ async function main() {
24825
25237
  env: process.env
24826
25238
  });
24827
25239
  if (mode === "local-ui") {
24828
- const cwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
24829
- const handle = await startLocalUiServer({ cwd });
25240
+ const cwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
25241
+ const handle = await startLocalUiServer({ cwd, initialPath: stackInitialPath(flags) });
24830
25242
  console.log(`VibeRaven local UI: ${handle.url}`);
24831
25243
  await waitForServerShutdown();
24832
25244
  await handle.close();
@@ -24845,9 +25257,9 @@ async function main() {
24845
25257
  await runInteractiveSession();
24846
25258
  return 0;
24847
25259
  case "ui": {
24848
- const cwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25260
+ const cwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24849
25261
  const envPort = Number(process.env.PORT);
24850
- const handle = await startLocalUiServer({ cwd, port: Number.isFinite(envPort) && envPort > 0 ? envPort : void 0 });
25262
+ const handle = await startLocalUiServer({ cwd, port: Number.isFinite(envPort) && envPort > 0 ? envPort : void 0, initialPath: stackInitialPath(flags) });
24851
25263
  console.log(`VibeRaven local UI: ${handle.url}`);
24852
25264
  await waitForServerShutdown();
24853
25265
  await handle.close();
@@ -24857,12 +25269,14 @@ async function main() {
24857
25269
  return cmdStatus(flags, positional);
24858
25270
  case "check":
24859
25271
  return runCheckCommand({
24860
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
25272
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
24861
25273
  json: Boolean(flags.json),
24862
- quiet: Boolean(flags.quiet)
25274
+ quiet: Boolean(flags.quiet),
25275
+ base: typeof flags.base === "string" ? flags.base : void 0,
25276
+ markdown: flags.markdown === true
24863
25277
  });
24864
25278
  case "fix": {
24865
- const fixCwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25279
+ const fixCwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24866
25280
  const gapId = typeof flags.gap === "string" ? flags.gap : void 0;
24867
25281
  if (!gapId) {
24868
25282
  const artifact = await loadLastArtifact(fixCwd).catch(() => void 0);
@@ -24891,19 +25305,19 @@ async function main() {
24891
25305
  }
24892
25306
  case "actions":
24893
25307
  return runActionsCommand({
24894
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
25308
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
24895
25309
  json: Boolean(flags.json)
24896
25310
  });
24897
25311
  case "preview":
24898
25312
  return runPreviewCommand({
24899
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
25313
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
24900
25314
  agentMode: flags["agent-mode"] === true,
24901
25315
  json: Boolean(flags.json)
24902
25316
  });
24903
25317
  case "next":
24904
25318
  return runNextCommand({
24905
25319
  json: Boolean(flags.json),
24906
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd()
25320
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd()
24907
25321
  });
24908
25322
  case "guide": {
24909
25323
  const provider2 = positional[0];
@@ -24937,8 +25351,11 @@ async function main() {
24937
25351
  case "provider-verify":
24938
25352
  return cmdProviderVerify(flags, positional);
24939
25353
  case "init": {
24940
- const cwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25354
+ const cwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24941
25355
  const agents = typeof flags.agents === "string" ? flags.agents : void 0;
25356
+ if (flags.github === true) {
25357
+ return runInitGithubCommand({ cwd, dryRun: flags["dry-run"] === true, force: flags.force === true });
25358
+ }
24942
25359
  return runInitCommand({
24943
25360
  cwd,
24944
25361
  agents,
@@ -24951,7 +25368,7 @@ async function main() {
24951
25368
  return 1;
24952
25369
  }
24953
25370
  return runDoctorAgentsCommand({
24954
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd()
25371
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd()
24955
25372
  });
24956
25373
  case "validate-npm-package":
24957
25374
  return runValidateNpmPackageCommand({
@@ -24964,7 +25381,7 @@ async function main() {
24964
25381
  return 1;
24965
25382
  }
24966
25383
  return runAuditCommand({
24967
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
25384
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
24968
25385
  json: Boolean(flags.json)
24969
25386
  });
24970
25387
  case "clean": {
@@ -24972,7 +25389,7 @@ async function main() {
24972
25389
  console.error("Usage: viberaven clean --plan [path]");
24973
25390
  return 1;
24974
25391
  }
24975
- const cwd = positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd();
25392
+ const cwd = positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd();
24976
25393
  const plan = buildContextCleanupPlan({ projectRoot: cwd, files: await collectCleanupFiles(cwd) });
24977
25394
  const outputPath = await writeCleanupPlan(cwd, plan);
24978
25395
  console.log(`Wrote ${outputPath}
@@ -24982,9 +25399,9 @@ async function main() {
24982
25399
  }
24983
25400
  case "rls-test":
24984
25401
  return runRlsTestCommand({
24985
- cwd: positional[0] ? (0, import_node_path40.resolve)(process.cwd(), positional[0]) : process.cwd(),
24986
- matrix: typeof flags.matrix === "string" ? (0, import_node_path40.resolve)(process.cwd(), flags.matrix) : void 0,
24987
- migrations: typeof flags.migrations === "string" ? (0, import_node_path40.resolve)(process.cwd(), flags.migrations) : void 0,
25402
+ cwd: positional[0] ? (0, import_node_path42.resolve)(process.cwd(), positional[0]) : process.cwd(),
25403
+ matrix: typeof flags.matrix === "string" ? (0, import_node_path42.resolve)(process.cwd(), flags.matrix) : void 0,
25404
+ migrations: typeof flags.migrations === "string" ? (0, import_node_path42.resolve)(process.cwd(), flags.migrations) : void 0,
24988
25405
  json: Boolean(flags.json)
24989
25406
  });
24990
25407
  default:
@@ -24993,11 +25410,11 @@ async function main() {
24993
25410
  return 1;
24994
25411
  }
24995
25412
  }
24996
- var import_promises30, import_node_path40, STACK_AREAS;
25413
+ var import_promises32, import_node_path42, STACK_AREAS;
24997
25414
  var init_cli = __esm({
24998
25415
  "src/cli.ts"() {
24999
- import_promises30 = require("node:fs/promises");
25000
- import_node_path40 = require("node:path");
25416
+ import_promises32 = require("node:fs/promises");
25417
+ import_node_path42 = require("node:path");
25001
25418
  init_config();
25002
25419
  init_runScan();
25003
25420
  init_artifacts2();
@@ -25021,6 +25438,8 @@ var init_cli = __esm({
25021
25438
  init_stackRecommend();
25022
25439
  init_commands();
25023
25440
  init_runInit();
25441
+ init_initGithub();
25442
+ init_setupLink();
25024
25443
  init_runDoctor();
25025
25444
  init_runValidateNpmPackage();
25026
25445
  init_runAudit();
@@ -25058,5 +25477,6 @@ init_cli();
25058
25477
  parseArgs,
25059
25478
  printHelp,
25060
25479
  resolveDefaultEntrypointMode,
25061
- runScanCommand
25480
+ runScanCommand,
25481
+ stackInitialPath
25062
25482
  });