@viberaven/cli 1.6.1 → 1.6.3
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 +1200 -812
- package/package.json +17 -6
package/dist/cli.js
CHANGED
|
@@ -656,9 +656,30 @@ function normalizeGap(v) {
|
|
|
656
656
|
toolSuggestions,
|
|
657
657
|
mcpSuggestion: typeof v.mcpSuggestion === "string" ? v.mcpSuggestion : null,
|
|
658
658
|
primaryMapCategory: affectedMapCategories[0],
|
|
659
|
-
affectedMapCategories
|
|
659
|
+
affectedMapCategories,
|
|
660
|
+
...normalizeLocations(v.locations)
|
|
660
661
|
};
|
|
661
662
|
}
|
|
663
|
+
function normalizeLocations(v) {
|
|
664
|
+
if (!Array.isArray(v)) return {};
|
|
665
|
+
const locations = [];
|
|
666
|
+
for (const item4 of v) {
|
|
667
|
+
if (!isRecord(item4) || typeof item4.file !== "string" || !item4.file.trim()) continue;
|
|
668
|
+
const line = typeof item4.line === "number" && Number.isInteger(item4.line) && item4.line > 0 ? item4.line : void 0;
|
|
669
|
+
locations.push(line === void 0 ? { file: item4.file } : { file: item4.file, line });
|
|
670
|
+
}
|
|
671
|
+
return locations.length > 0 ? { locations } : {};
|
|
672
|
+
}
|
|
673
|
+
function mergeLocations(a, b3) {
|
|
674
|
+
const seen = /* @__PURE__ */ new Set();
|
|
675
|
+
const merged = [...a ?? [], ...b3 ?? []].filter((location) => {
|
|
676
|
+
const key = `${location.file}:${location.line ?? ""}`;
|
|
677
|
+
if (seen.has(key)) return false;
|
|
678
|
+
seen.add(key);
|
|
679
|
+
return true;
|
|
680
|
+
});
|
|
681
|
+
return merged.length > 0 ? { locations: merged } : {};
|
|
682
|
+
}
|
|
662
683
|
function rootGapKey(gap) {
|
|
663
684
|
const titleKey = slugify(gap.title);
|
|
664
685
|
if (titleKey) {
|
|
@@ -688,7 +709,8 @@ function mergeRootGaps(a, b3) {
|
|
|
688
709
|
toolSuggestions: mergeToolSuggestions(a.toolSuggestions, b3.toolSuggestions),
|
|
689
710
|
mcpSuggestion: a.mcpSuggestion ?? b3.mcpSuggestion,
|
|
690
711
|
primaryMapCategory: a.primaryMapCategory,
|
|
691
|
-
affectedMapCategories: a.affectedMapCategories
|
|
712
|
+
affectedMapCategories: a.affectedMapCategories,
|
|
713
|
+
...mergeLocations(a.locations, b3.locations)
|
|
692
714
|
};
|
|
693
715
|
}
|
|
694
716
|
function dedupeRootGaps(gaps) {
|
|
@@ -3304,11 +3326,11 @@ var init_providerTruth = __esm({
|
|
|
3304
3326
|
// ../../src/station/promptBuilder.ts
|
|
3305
3327
|
function buildAnalysisPrompt(scan, specContent, productionConnectionContext, scannerEvidenceContext, stackWiringContext, stackAutomationContext) {
|
|
3306
3328
|
const sections = [];
|
|
3307
|
-
const
|
|
3329
|
+
const detectedStack2 = Object.entries(scan.stackSignals).filter(([, v]) => v === true).map(([k3]) => k3).join(", ");
|
|
3308
3330
|
sections.push(`## PROJECT CONTEXT
|
|
3309
3331
|
Total files in repo: ${scan.totalFilesScanned}
|
|
3310
3332
|
Files analyzed: ${scan.files.length}
|
|
3311
|
-
Detected stack signals: ${
|
|
3333
|
+
Detected stack signals: ${detectedStack2 || "none detected"}
|
|
3312
3334
|
All dependencies: ${scan.packageDeps.join(", ") || "none found"}
|
|
3313
3335
|
Secret files found (contents not read): ${scan.secretsFound.join(", ") || "none"}
|
|
3314
3336
|
`);
|
|
@@ -8563,6 +8585,16 @@ function safe(text) {
|
|
|
8563
8585
|
function at(loc) {
|
|
8564
8586
|
return loc ? `${loc.file}:${loc.line}` : "an unknown location";
|
|
8565
8587
|
}
|
|
8588
|
+
function policyNameNote(name) {
|
|
8589
|
+
if (/\bservice[ _-]?role\b/i.test(name)) {
|
|
8590
|
+
return ` The name mentions the service role, but the service role bypasses row level security and never needs a policy, so this one only opens the table to everyone else.`;
|
|
8591
|
+
}
|
|
8592
|
+
const promise = name.match(/\b(?:own|owner|owners|their|admins?|teachers?|creators?|authors?|members?|self)\b/i);
|
|
8593
|
+
if (promise) {
|
|
8594
|
+
return ` The name says "${name}", but nothing in the policy checks who the caller is.`;
|
|
8595
|
+
}
|
|
8596
|
+
return "";
|
|
8597
|
+
}
|
|
8566
8598
|
function audience(roles) {
|
|
8567
8599
|
const set = new Set(roles);
|
|
8568
8600
|
if (set.has("public") || set.has("anon") && set.has("authenticated")) return "anyone, signed in or not,";
|
|
@@ -8618,7 +8650,7 @@ function analyzeRls(replay) {
|
|
|
8618
8650
|
id: "rls_policy_allows_all_read",
|
|
8619
8651
|
severity: "high",
|
|
8620
8652
|
message: safe(
|
|
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
|
|
8653
|
+
`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.${policyNameNote(policy.name)}`
|
|
8622
8654
|
),
|
|
8623
8655
|
file: policy.loc.file,
|
|
8624
8656
|
line: policy.loc.line,
|
|
@@ -8650,7 +8682,7 @@ function analyzeRls(replay) {
|
|
|
8650
8682
|
permissive.push({
|
|
8651
8683
|
id: "rls_policy_allows_all_write",
|
|
8652
8684
|
severity,
|
|
8653
|
-
message: safe(`Policy "${policy.name}" on ${table2.display} (${at(policy.loc)}) lets ${who} ${verb}: ${clause}
|
|
8685
|
+
message: safe(`Policy "${policy.name}" on ${table2.display} (${at(policy.loc)}) lets ${who} ${verb}: ${clause}.${severity === "critical" ? policyNameNote(policy.name) : ""}`),
|
|
8654
8686
|
file: policy.loc.file,
|
|
8655
8687
|
line: policy.loc.line,
|
|
8656
8688
|
table: table2.display,
|
|
@@ -10427,6 +10459,18 @@ var init_databaseEvidence = __esm({
|
|
|
10427
10459
|
});
|
|
10428
10460
|
|
|
10429
10461
|
// src/localStation.ts
|
|
10462
|
+
function findingLocations(findings) {
|
|
10463
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10464
|
+
const out = [];
|
|
10465
|
+
for (const finding of findings) {
|
|
10466
|
+
if (!finding.file) continue;
|
|
10467
|
+
const key = `${finding.file}:${finding.line ?? ""}`;
|
|
10468
|
+
if (seen.has(key)) continue;
|
|
10469
|
+
seen.add(key);
|
|
10470
|
+
out.push(finding.line ? { file: finding.file, line: finding.line } : { file: finding.file });
|
|
10471
|
+
}
|
|
10472
|
+
return out.slice(0, DETAIL_MAX_FINDINGS);
|
|
10473
|
+
}
|
|
10430
10474
|
function hasFilePath(scan, pattern) {
|
|
10431
10475
|
return scan.files.some((f) => pattern.test(f.path));
|
|
10432
10476
|
}
|
|
@@ -10720,7 +10764,8 @@ function auditFindingSeeds(audit) {
|
|
|
10720
10764
|
detail: capLines(lines).join("\n"),
|
|
10721
10765
|
copyPrompt: fixes.length > 0 ? `${meta.prompt}
|
|
10722
10766
|
${capLines(fixes).join("\n")}` : meta.prompt,
|
|
10723
|
-
primaryMapCategory: meta.map
|
|
10767
|
+
primaryMapCategory: meta.map,
|
|
10768
|
+
locations: findingLocations(findings)
|
|
10724
10769
|
};
|
|
10725
10770
|
});
|
|
10726
10771
|
}
|
|
@@ -10919,6 +10964,7 @@ ${check.evidence.map((e2) => `- ${e2}`).join("\n")}` : "";
|
|
|
10919
10964
|
category: "SECURITY & AUTH",
|
|
10920
10965
|
severity: "warning",
|
|
10921
10966
|
title: "Stripe webhook does not verify the signature",
|
|
10967
|
+
locations: findingLocations(webhooks.unverified.map((u2) => ({ file: u2.path }))),
|
|
10922
10968
|
detail: `${webhooks.unverified.length} Stripe webhook handler${webhooks.unverified.length === 1 ? "" : "s"} without signature verification over the raw body: ${capLines(lines).join("; ")}. Anyone who finds the URL can post a fake event, for example a paid checkout.`,
|
|
10923
10969
|
copyPrompt: 'In each listed handler, read the raw request body (await req.text() in Next.js route handlers and Deno, express.raw({ type: "application/json" }) in Express), read the stripe-signature header, and pass both to stripe.webhooks.constructEvent (constructEventAsync on Deno or edge runtimes) with STRIPE_WEBHOOK_SECRET before trusting event.type. Return 400 when verification throws.',
|
|
10924
10970
|
primaryMapCategory: "payments"
|
|
@@ -10955,7 +11001,7 @@ ${check.evidence.map((e2) => `- ${e2}`).join("\n")}` : "";
|
|
|
10955
11001
|
severity: "warning",
|
|
10956
11002
|
title: `Env vars used in code but missing from ${target}`,
|
|
10957
11003
|
detail: `Code reads ${count} that ${contract.templates.length === 1 ? target : `no env template (${contract.templates.join(", ")})`} does not document (${shown}${more}). Fresh clones, CI, and the production deploy can silently run without them.`,
|
|
10958
|
-
copyPrompt: `Add placeholder entries for these variables to ${contract.templates.length === 1 ? target : contract.templates[0]} (never real values): ${shown}${drifted.length > 5 ? " and the rest" : ""}. Then confirm each one is set in the deployment environment (
|
|
11004
|
+
copyPrompt: `Add placeholder entries for these variables to ${contract.templates.length === 1 ? target : contract.templates[0]} (never real values): ${shown}${drifted.length > 5 ? " and the rest" : ""}. Then confirm each one is set in the deployment environment (the hosting provider's project settings).`,
|
|
10959
11005
|
primaryMapCategory: "deployment"
|
|
10960
11006
|
});
|
|
10961
11007
|
} else {
|
|
@@ -11022,9 +11068,9 @@ function scoreFrom(gaps) {
|
|
|
11022
11068
|
}
|
|
11023
11069
|
return Math.max(5, Math.min(96, score));
|
|
11024
11070
|
}
|
|
11025
|
-
function
|
|
11071
|
+
function scoreLabelFor(score, criticalCount, warningCount) {
|
|
11026
11072
|
if (criticalCount > 0) return "Blocked";
|
|
11027
|
-
if (
|
|
11073
|
+
if (warningCount === 0) return "No blockers in repo checks";
|
|
11028
11074
|
if (score >= 60) return "Almost there";
|
|
11029
11075
|
return "Needs work";
|
|
11030
11076
|
}
|
|
@@ -11123,11 +11169,12 @@ async function buildLocalStationOutput(input) {
|
|
|
11123
11169
|
toolSuggestions: [],
|
|
11124
11170
|
mcpSuggestion: null,
|
|
11125
11171
|
primaryMapCategory: seed.primaryMapCategory,
|
|
11126
|
-
affectedMapCategories: [seed.primaryMapCategory]
|
|
11172
|
+
affectedMapCategories: [seed.primaryMapCategory],
|
|
11173
|
+
...seed.locations?.length ? { locations: seed.locations } : {}
|
|
11127
11174
|
}));
|
|
11128
11175
|
return {
|
|
11129
11176
|
score,
|
|
11130
|
-
scoreLabel:
|
|
11177
|
+
scoreLabel: scoreLabelFor(score, criticalCount, warningCount),
|
|
11131
11178
|
summary,
|
|
11132
11179
|
archetype,
|
|
11133
11180
|
gaps,
|
|
@@ -11583,6 +11630,28 @@ var init_runScan = __esm({
|
|
|
11583
11630
|
}
|
|
11584
11631
|
});
|
|
11585
11632
|
|
|
11633
|
+
// src/contracts/detectedProviders.ts
|
|
11634
|
+
function isProviderInRepo(row) {
|
|
11635
|
+
if ((row.roles ?? []).includes("runtime-code")) return true;
|
|
11636
|
+
const evidence = (row.evidence ?? []).filter((item4) => item4.kind !== "docs-mention");
|
|
11637
|
+
if (!evidence.some((item4) => PACKAGE_OR_CONFIG.has(item4.kind))) return false;
|
|
11638
|
+
return !evidence.every((item4) => item4.kind === "package-installed");
|
|
11639
|
+
}
|
|
11640
|
+
function providersInRepo(artifact) {
|
|
11641
|
+
const areas = artifact.providerTruth?.areas;
|
|
11642
|
+
if (!Array.isArray(areas)) return void 0;
|
|
11643
|
+
return areas.flatMap(
|
|
11644
|
+
(area) => (area.rows ?? []).filter(isProviderInRepo).map((row) => ({ area: String(area.area), provider: String(row.provider) }))
|
|
11645
|
+
);
|
|
11646
|
+
}
|
|
11647
|
+
var PACKAGE_OR_CONFIG;
|
|
11648
|
+
var init_detectedProviders = __esm({
|
|
11649
|
+
"src/contracts/detectedProviders.ts"() {
|
|
11650
|
+
"use strict";
|
|
11651
|
+
PACKAGE_OR_CONFIG = /* @__PURE__ */ new Set(["package-installed", "deployment-config", "provider-config"]);
|
|
11652
|
+
}
|
|
11653
|
+
});
|
|
11654
|
+
|
|
11586
11655
|
// src/capabilities/classify.ts
|
|
11587
11656
|
function gapText(gap) {
|
|
11588
11657
|
return `${gap.id} ${gap.title} ${gap.detail} ${gap.primaryMapCategory}`.toLowerCase();
|
|
@@ -11770,6 +11839,37 @@ var init_capabilities = __esm({
|
|
|
11770
11839
|
}
|
|
11771
11840
|
});
|
|
11772
11841
|
|
|
11842
|
+
// src/contracts/packageManager.ts
|
|
11843
|
+
function detectPackageManager(workspacePath) {
|
|
11844
|
+
if (!workspacePath) return "unknown";
|
|
11845
|
+
try {
|
|
11846
|
+
const manifest = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path8.join)(workspacePath, "package.json"), "utf8").replace(/^\uFEFF/, ""));
|
|
11847
|
+
const named = typeof manifest.packageManager === "string" ? manifest.packageManager.split("@")[0] : "";
|
|
11848
|
+
if (named === "npm" || named === "pnpm" || named === "yarn" || named === "bun") return named;
|
|
11849
|
+
} catch {
|
|
11850
|
+
}
|
|
11851
|
+
for (const [file, manager] of LOCKFILES) {
|
|
11852
|
+
if ((0, import_node_fs4.existsSync)((0, import_node_path8.join)(workspacePath, file))) return manager;
|
|
11853
|
+
}
|
|
11854
|
+
return "unknown";
|
|
11855
|
+
}
|
|
11856
|
+
var import_node_fs4, import_node_path8, LOCKFILES;
|
|
11857
|
+
var init_packageManager = __esm({
|
|
11858
|
+
"src/contracts/packageManager.ts"() {
|
|
11859
|
+
"use strict";
|
|
11860
|
+
import_node_fs4 = require("node:fs");
|
|
11861
|
+
import_node_path8 = require("node:path");
|
|
11862
|
+
LOCKFILES = [
|
|
11863
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
11864
|
+
["yarn.lock", "yarn"],
|
|
11865
|
+
["bun.lock", "bun"],
|
|
11866
|
+
["bun.lockb", "bun"],
|
|
11867
|
+
["package-lock.json", "npm"],
|
|
11868
|
+
["npm-shrinkwrap.json", "npm"]
|
|
11869
|
+
];
|
|
11870
|
+
}
|
|
11871
|
+
});
|
|
11872
|
+
|
|
11773
11873
|
// src/contracts/commands.ts
|
|
11774
11874
|
function promptGapCommand(gapId) {
|
|
11775
11875
|
return `${PUBLIC_COMMAND} prompt --gap ${gapId}`;
|
|
@@ -11797,65 +11897,18 @@ var init_commands = __esm({
|
|
|
11797
11897
|
}
|
|
11798
11898
|
});
|
|
11799
11899
|
|
|
11800
|
-
// src/contracts/contextMap.ts
|
|
11801
|
-
function generateContextMap(artifact) {
|
|
11802
|
-
const criticalCount = artifact.gaps.filter((gap) => gap.severity === "critical").length;
|
|
11803
|
-
const warningCount = artifact.gaps.filter((gap) => gap.severity === "warning").length;
|
|
11804
|
-
return {
|
|
11805
|
-
$schema: "https://viberaven.dev/schemas/context-map.schema.json",
|
|
11806
|
-
schemaVersion: "v1",
|
|
11807
|
-
generatedAt: artifact.scannedAt,
|
|
11808
|
-
workspace: {
|
|
11809
|
-
root: artifact.workspacePath,
|
|
11810
|
-
packageManager: "unknown",
|
|
11811
|
-
languages: ["typescript"],
|
|
11812
|
-
frameworks: artifact.archetype ? [artifact.archetype] : []
|
|
11813
|
-
},
|
|
11814
|
-
agentContract: {
|
|
11815
|
-
readFirst: ".viberaven/agent-tasklist.md",
|
|
11816
|
-
machineResult: ".viberaven/gate-result.json",
|
|
11817
|
-
contextMap: ".viberaven/context-map.json",
|
|
11818
|
-
verifyCommand: PUBLIC_VERIFY_COMMAND,
|
|
11819
|
-
strictCommand: PUBLIC_STRICT_COMMAND,
|
|
11820
|
-
nextCommand: PUBLIC_NEXT_JSON_COMMAND
|
|
11821
|
-
},
|
|
11822
|
-
stack: {
|
|
11823
|
-
deployment: artifact.selectedProviders?.deployment ? [artifact.selectedProviders.deployment] : [],
|
|
11824
|
-
database: artifact.selectedProviders?.database ? [artifact.selectedProviders.database] : [],
|
|
11825
|
-
auth: artifact.selectedProviders?.auth ? [artifact.selectedProviders.auth] : [],
|
|
11826
|
-
payments: artifact.selectedProviders?.payments ? [artifact.selectedProviders.payments] : [],
|
|
11827
|
-
monitoring: artifact.selectedProviders?.monitoring ? [artifact.selectedProviders.monitoring] : []
|
|
11828
|
-
},
|
|
11829
|
-
capabilityGraph: summarizeCapabilities(artifact.gaps),
|
|
11830
|
-
productionGate: {
|
|
11831
|
-
status: criticalCount > 0 ? "not_clear" : warningCount > 0 ? "warning" : "clear",
|
|
11832
|
-
criticalCount,
|
|
11833
|
-
warningCount,
|
|
11834
|
-
providerDashboardChecksRequired: true
|
|
11835
|
-
},
|
|
11836
|
-
topGaps: artifact.gaps.slice(0, 10).map((gap) => ({
|
|
11837
|
-
id: gap.id,
|
|
11838
|
-
severity: gap.severity,
|
|
11839
|
-
title: gap.title,
|
|
11840
|
-
area: String(gap.primaryMapCategory),
|
|
11841
|
-
promptCommand: promptGapCommand(gap.id)
|
|
11842
|
-
}))
|
|
11843
|
-
};
|
|
11844
|
-
}
|
|
11845
|
-
var init_contextMap = __esm({
|
|
11846
|
-
"src/contracts/contextMap.ts"() {
|
|
11847
|
-
"use strict";
|
|
11848
|
-
init_capabilities();
|
|
11849
|
-
init_commands();
|
|
11850
|
-
}
|
|
11851
|
-
});
|
|
11852
|
-
|
|
11853
11900
|
// src/contracts/gateResult.ts
|
|
11854
11901
|
function gateStatus(criticalCount, warningCount) {
|
|
11855
11902
|
if (criticalCount > 0) return "not_clear";
|
|
11856
11903
|
if (warningCount > 0) return "warning";
|
|
11857
11904
|
return "clear";
|
|
11858
11905
|
}
|
|
11906
|
+
function gateStatusForGaps(gaps) {
|
|
11907
|
+
return gateStatus(
|
|
11908
|
+
gaps.filter((gap) => gap.severity === "critical").length,
|
|
11909
|
+
gaps.filter((gap) => gap.severity === "warning").length
|
|
11910
|
+
);
|
|
11911
|
+
}
|
|
11859
11912
|
function runIdFrom(scannedAt) {
|
|
11860
11913
|
return `vr_${scannedAt.replace(/\D/g, "").slice(0, 14) || "scan"}`;
|
|
11861
11914
|
}
|
|
@@ -11873,7 +11926,7 @@ function generateGateResult(artifact, options = {}) {
|
|
|
11873
11926
|
generatedAt: artifact.scannedAt,
|
|
11874
11927
|
workspace: {
|
|
11875
11928
|
root: artifact.workspacePath,
|
|
11876
|
-
packageManager:
|
|
11929
|
+
packageManager: options.packageManager ?? detectPackageManager(artifact.workspacePath),
|
|
11877
11930
|
languages: ["typescript"],
|
|
11878
11931
|
frameworks: artifact.archetype ? [artifact.archetype] : []
|
|
11879
11932
|
},
|
|
@@ -11914,101 +11967,246 @@ var init_gateResult = __esm({
|
|
|
11914
11967
|
"src/contracts/gateResult.ts"() {
|
|
11915
11968
|
"use strict";
|
|
11916
11969
|
init_capabilities();
|
|
11970
|
+
init_packageManager();
|
|
11917
11971
|
init_commands();
|
|
11918
11972
|
}
|
|
11919
11973
|
});
|
|
11920
11974
|
|
|
11921
|
-
// src/contracts/
|
|
11922
|
-
function
|
|
11923
|
-
|
|
11975
|
+
// src/contracts/contextMap.ts
|
|
11976
|
+
function detectedStack(artifact) {
|
|
11977
|
+
const stack = { deployment: [], database: [], auth: [], payments: [], monitoring: [] };
|
|
11978
|
+
const add = (area, provider2) => {
|
|
11979
|
+
if (!(area in stack) || typeof provider2 !== "string" || !provider2) return;
|
|
11980
|
+
const list = stack[area];
|
|
11981
|
+
if (!list.includes(provider2)) list.push(provider2);
|
|
11982
|
+
};
|
|
11983
|
+
for (const entry of providersInRepo(artifact) ?? []) add(entry.area, entry.provider);
|
|
11984
|
+
for (const [area, provider2] of Object.entries(artifact.selectedProviders ?? {})) add(area, provider2);
|
|
11985
|
+
return stack;
|
|
11924
11986
|
}
|
|
11925
|
-
function
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11987
|
+
function generateContextMap(artifact, options = {}) {
|
|
11988
|
+
const criticalCount = artifact.gaps.filter((gap) => gap.severity === "critical").length;
|
|
11989
|
+
const warningCount = artifact.gaps.filter((gap) => gap.severity === "warning").length;
|
|
11990
|
+
return {
|
|
11991
|
+
$schema: "https://viberaven.dev/schemas/context-map.schema.json",
|
|
11992
|
+
schemaVersion: "v1",
|
|
11993
|
+
generatedAt: artifact.scannedAt,
|
|
11994
|
+
workspace: {
|
|
11995
|
+
root: artifact.workspacePath,
|
|
11996
|
+
packageManager: options.packageManager ?? detectPackageManager(artifact.workspacePath),
|
|
11997
|
+
languages: ["typescript"],
|
|
11998
|
+
frameworks: artifact.archetype ? [artifact.archetype] : []
|
|
11999
|
+
},
|
|
12000
|
+
agentContract: {
|
|
12001
|
+
readFirst: ".viberaven/agent-tasklist.md",
|
|
12002
|
+
machineResult: ".viberaven/gate-result.json",
|
|
12003
|
+
contextMap: ".viberaven/context-map.json",
|
|
12004
|
+
verifyCommand: PUBLIC_VERIFY_COMMAND,
|
|
12005
|
+
strictCommand: PUBLIC_STRICT_COMMAND,
|
|
12006
|
+
nextCommand: PUBLIC_NEXT_JSON_COMMAND
|
|
12007
|
+
},
|
|
12008
|
+
stack: detectedStack(artifact),
|
|
12009
|
+
capabilityGraph: summarizeCapabilities(artifact.gaps),
|
|
12010
|
+
productionGate: {
|
|
12011
|
+
status: gateStatusForGaps(artifact.gaps),
|
|
12012
|
+
criticalCount,
|
|
12013
|
+
warningCount,
|
|
12014
|
+
providerDashboardChecksRequired: true
|
|
12015
|
+
},
|
|
12016
|
+
topGaps: artifact.gaps.slice(0, 10).map((gap) => ({
|
|
11931
12017
|
id: gap.id,
|
|
11932
12018
|
severity: gap.severity,
|
|
11933
|
-
capability: classifyGapCapability(gap),
|
|
11934
12019
|
title: gap.title,
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
healPlan: healPlanGapCommand(gap.id),
|
|
11940
|
-
verify: PUBLIC_VERIFY_COMMAND
|
|
11941
|
-
},
|
|
11942
|
-
providerBoundary: {
|
|
11943
|
-
requiresDashboardCheck: true,
|
|
11944
|
-
reason: "Repo evidence cannot prove live provider dashboard state."
|
|
11945
|
-
}
|
|
11946
|
-
}
|
|
11947
|
-
}));
|
|
12020
|
+
area: String(gap.primaryMapCategory),
|
|
12021
|
+
promptCommand: promptGapCommand(gap.id)
|
|
12022
|
+
}))
|
|
12023
|
+
};
|
|
11948
12024
|
}
|
|
11949
|
-
var
|
|
11950
|
-
"src/contracts/
|
|
12025
|
+
var init_contextMap = __esm({
|
|
12026
|
+
"src/contracts/contextMap.ts"() {
|
|
11951
12027
|
"use strict";
|
|
12028
|
+
init_detectedProviders();
|
|
12029
|
+
init_gateResult();
|
|
11952
12030
|
init_capabilities();
|
|
12031
|
+
init_packageManager();
|
|
11953
12032
|
init_commands();
|
|
11954
12033
|
}
|
|
11955
12034
|
});
|
|
11956
12035
|
|
|
11957
|
-
// src/
|
|
11958
|
-
function
|
|
11959
|
-
|
|
11960
|
-
|
|
12036
|
+
// src/contracts/gapLocations.ts
|
|
12037
|
+
function locationsForGap(gap) {
|
|
12038
|
+
return gap.locations && gap.locations.length > 0 ? gap.locations : gapLocations(gap.detail);
|
|
12039
|
+
}
|
|
12040
|
+
function withoutUrlsAndAddresses(text) {
|
|
12041
|
+
return text.split(/(\s+)/).map((word) => /:\/\/|@|=/.test(word) ? " " : word).join("");
|
|
12042
|
+
}
|
|
12043
|
+
function gapLocations(detail) {
|
|
12044
|
+
if (typeof detail !== "string") return [];
|
|
12045
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12046
|
+
const out = [];
|
|
12047
|
+
for (const rawLine of detail.split(/\r?\n/)) {
|
|
12048
|
+
const text = withoutUrlsAndAddresses(rawLine.split(" Fix:")[0]);
|
|
12049
|
+
for (const match of text.matchAll(LOCATION)) {
|
|
12050
|
+
const folder = match[1].replace(/\\/g, "/");
|
|
12051
|
+
const name = match[2];
|
|
12052
|
+
const file = `${folder}${name}`;
|
|
12053
|
+
const line = match[3] ? Number(match[3]) : void 0;
|
|
12054
|
+
if (line !== void 0 && !(line > 0)) continue;
|
|
12055
|
+
const envFile = name.startsWith(".env");
|
|
12056
|
+
if (!envFile && (VERSION_LIKE.test(name) || VERSION_LIKE.test(name.replace(/\.[A-Za-z0-9]+$/, "")))) continue;
|
|
12057
|
+
const codeFile = CODE_EXTENSION.test(name) && !(folder === "" && PROSE_NAME.test(name));
|
|
12058
|
+
const configFile = CONFIG_EXTENSION.test(name);
|
|
12059
|
+
if (line !== void 0) {
|
|
12060
|
+
if (!envFile && !codeFile && !configFile) continue;
|
|
12061
|
+
} else if (!envFile && !codeFile && !(configFile && folder !== "")) {
|
|
12062
|
+
continue;
|
|
12063
|
+
}
|
|
12064
|
+
const key = `${file}:${line ?? ""}`;
|
|
12065
|
+
if (seen.has(key)) continue;
|
|
12066
|
+
seen.add(key);
|
|
12067
|
+
out.push(line === void 0 ? { file } : { file, line });
|
|
12068
|
+
}
|
|
11961
12069
|
}
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
12070
|
+
return out;
|
|
12071
|
+
}
|
|
12072
|
+
var SEGMENT, NAME, LOCATION, CODE_EXTENSION, CONFIG_EXTENSION, PROSE_NAME, VERSION_LIKE;
|
|
12073
|
+
var init_gapLocations = __esm({
|
|
12074
|
+
"src/contracts/gapLocations.ts"() {
|
|
12075
|
+
"use strict";
|
|
12076
|
+
SEGMENT = String.raw`(?:\([\w.-]+\)|\[[\w.-]+\]|[\w-][\w.-]*)`;
|
|
12077
|
+
NAME = String.raw`(\.env(?:\.[\w-]+)*|(?:\[[\w.-]+\]|[\w-][\w.-]*?)\.[A-Za-z0-9]+)`;
|
|
12078
|
+
LOCATION = new RegExp(
|
|
12079
|
+
String.raw`(?<![\w./\\:-])((?:[A-Za-z]:[\\/])?(?:${SEGMENT}[\\/])*)${NAME}(?::(\d+))?(?!\.?[\w\\/])`,
|
|
12080
|
+
"g"
|
|
12081
|
+
);
|
|
12082
|
+
CODE_EXTENSION = /\.(?:sql|[cm]?[jt]sx?|py|rb|php|go|rs|java|kt|cs|swift|ex|exs|vue|svelte|astro)$/i;
|
|
12083
|
+
CONFIG_EXTENSION = /\.(?:json|toml|ya?ml)$/i;
|
|
12084
|
+
PROSE_NAME = /^(?:next|node|nuxt|vue|express|nest|react|three|chart|solid|ember|backbone|angular|alpine|d3)\.js$/i;
|
|
12085
|
+
VERSION_LIKE = /^v?\d+(?:\.\d+)+$/i;
|
|
11965
12086
|
}
|
|
11966
|
-
|
|
11967
|
-
|
|
12087
|
+
});
|
|
12088
|
+
|
|
12089
|
+
// src/contracts/repoFixes.ts
|
|
12090
|
+
var APPLY_MIGRATION, ROTATE_KEY, REPO_FIX_GAPS, INFORMATIONAL_GAPS, REPO_ONLY_RECIPE_GAPS, RECIPE_GAPS_WITH_OUTSIDE_STEP, KNOWN_RECIPE_GAP_IDS, REPO_ONLY_GAPS;
|
|
12091
|
+
var init_repoFixes = __esm({
|
|
12092
|
+
"src/contracts/repoFixes.ts"() {
|
|
12093
|
+
"use strict";
|
|
12094
|
+
APPLY_MIGRATION = "Apply the new migration to the live database the way this project applies migrations.";
|
|
12095
|
+
ROTATE_KEY = "Rotate the service role key in the Supabase dashboard if this key was ever deployed or committed with a real value.";
|
|
12096
|
+
REPO_FIX_GAPS = {
|
|
12097
|
+
rls_policy_allows_all_write: [APPLY_MIGRATION],
|
|
12098
|
+
rls_policy_allows_all_read: [APPLY_MIGRATION],
|
|
12099
|
+
data_api_grant_without_rls: [APPLY_MIGRATION],
|
|
12100
|
+
data_api_grant_missing: [APPLY_MIGRATION],
|
|
12101
|
+
security_definer_function_executable: [APPLY_MIGRATION],
|
|
12102
|
+
service_role_key_in_client_env: [ROTATE_KEY],
|
|
12103
|
+
service_role_key_in_client_code: [ROTATE_KEY],
|
|
12104
|
+
env_var_drift: ["Set each of these variables in the environment where the app is deployed."],
|
|
12105
|
+
unverified_stripe_webhook: [
|
|
12106
|
+
"Set STRIPE_WEBHOOK_SECRET where the handler runs to the signing secret of this endpoint in the Stripe dashboard, then deploy the handler."
|
|
12107
|
+
]
|
|
12108
|
+
};
|
|
12109
|
+
INFORMATIONAL_GAPS = {
|
|
12110
|
+
rls_no_policies: "Informational. Nothing to change if only the server uses this table. If the frontend reads or writes it, add policies in a new migration."
|
|
12111
|
+
};
|
|
12112
|
+
REPO_ONLY_RECIPE_GAPS = [
|
|
12113
|
+
// emptyCatch (original recipe)
|
|
12114
|
+
"empty-catch",
|
|
12115
|
+
"empty_catch",
|
|
12116
|
+
"emptyCatch",
|
|
12117
|
+
// file-create recipes
|
|
12118
|
+
"missing_error_boundary",
|
|
12119
|
+
"missing_health_route",
|
|
12120
|
+
"missing_loading_state",
|
|
12121
|
+
"missing_404_page",
|
|
12122
|
+
// file-patch recipes
|
|
12123
|
+
"missing_csp_header",
|
|
12124
|
+
"eslint_restricted_imports"
|
|
12125
|
+
];
|
|
12126
|
+
RECIPE_GAPS_WITH_OUTSIDE_STEP = ["auth_secret_missing", "node_env_not_set", "database_url_missing", "missing_rate_limit"];
|
|
12127
|
+
KNOWN_RECIPE_GAP_IDS = /* @__PURE__ */ new Set([...REPO_ONLY_RECIPE_GAPS, ...RECIPE_GAPS_WITH_OUTSIDE_STEP]);
|
|
12128
|
+
REPO_ONLY_GAPS = /* @__PURE__ */ new Set([...Object.keys(INFORMATIONAL_GAPS), ...REPO_ONLY_RECIPE_GAPS]);
|
|
11968
12129
|
}
|
|
11969
|
-
|
|
11970
|
-
|
|
12130
|
+
});
|
|
12131
|
+
|
|
12132
|
+
// src/heal/rlsMigrationTarget.ts
|
|
12133
|
+
function rlsEnableStatements(tables) {
|
|
12134
|
+
return [...new Set(tables)].map((table2) => `alter table ${table2} enable row level security;`);
|
|
12135
|
+
}
|
|
12136
|
+
function migrationStamp(now) {
|
|
12137
|
+
return now.toISOString().replace(/\D/g, "").slice(0, 14);
|
|
12138
|
+
}
|
|
12139
|
+
function rlsMigrationTarget(cwd, evidence, now = /* @__PURE__ */ new Date()) {
|
|
12140
|
+
if (evidence.length === 0) return { ok: false, reason: "No table without row level security was found in the repo SQL." };
|
|
12141
|
+
const statementList = rlsEnableStatements(evidence.map((entry) => entry.table)).join(" ");
|
|
12142
|
+
const turnedOff = evidence.filter((entry) => entry.turnedOff);
|
|
12143
|
+
if (turnedOff.length > 0) {
|
|
12144
|
+
const where = turnedOff.map((entry) => `${entry.table} (${entry.file.replace(/\\/g, "/")})`).join(", ");
|
|
12145
|
+
return {
|
|
12146
|
+
ok: false,
|
|
12147
|
+
reason: `The latest migration that touches ${where} turns row level security off on purpose, so VibeRaven will not turn it back on automatically. If the user wants it on, add these statements by hand in a new migration, with the policies the app needs: ${statementList}`
|
|
12148
|
+
};
|
|
11971
12149
|
}
|
|
11972
|
-
|
|
11973
|
-
|
|
12150
|
+
const source = evidence[0].file.replace(/\\/g, "/");
|
|
12151
|
+
const dir = import_node_path9.posix.dirname(source);
|
|
12152
|
+
if (import_node_path9.posix.basename(dir) !== "migrations") {
|
|
12153
|
+
return {
|
|
12154
|
+
ok: false,
|
|
12155
|
+
reason: `The tables come from ${source}, which is not in a migrations folder, so VibeRaven will not guess where a migration goes. Add these statements by hand where this project keeps its schema: ${statementList}`
|
|
12156
|
+
};
|
|
11974
12157
|
}
|
|
11975
|
-
|
|
11976
|
-
|
|
12158
|
+
let existing;
|
|
12159
|
+
try {
|
|
12160
|
+
existing = (0, import_node_fs5.readdirSync)((0, import_node_path9.join)(cwd, dir)).filter((file) => file.endsWith(".sql")).sort();
|
|
12161
|
+
} catch {
|
|
12162
|
+
return { ok: false, reason: `VibeRaven could not read ${dir}. Add these statements by hand in a new migration: ${statementList}` };
|
|
12163
|
+
}
|
|
12164
|
+
const otherNaming = existing.find((file) => !TIMESTAMPED_MIGRATION.test(file));
|
|
12165
|
+
if (otherNaming) {
|
|
12166
|
+
return {
|
|
12167
|
+
ok: false,
|
|
12168
|
+
reason: `The migrations in ${dir} are not named <14-digit timestamp>_name.sql (for example ${otherNaming}), so a timestamped file from VibeRaven could run in the wrong order next to them. Add these statements by hand in a new migration that follows this project's naming: ${statementList}`
|
|
12169
|
+
};
|
|
12170
|
+
}
|
|
12171
|
+
const name = `${migrationStamp(now)}_viberaven_enable_rls.sql`;
|
|
12172
|
+
const last = existing[existing.length - 1];
|
|
12173
|
+
if (last && name <= last) {
|
|
12174
|
+
return {
|
|
12175
|
+
ok: false,
|
|
12176
|
+
reason: `A new migration named ${name} would not run after ${last} in ${dir}, so VibeRaven will not write it. Add these statements by hand in a migration that runs last: ${statementList}`
|
|
12177
|
+
};
|
|
11977
12178
|
}
|
|
11978
|
-
return
|
|
12179
|
+
return { ok: true, file: `${dir}/${name}` };
|
|
11979
12180
|
}
|
|
11980
|
-
var
|
|
11981
|
-
var
|
|
11982
|
-
"src/
|
|
12181
|
+
var import_node_fs5, import_node_path9, RLS_TURNED_OFF_PHRASE, RLS_ASK_FIRST, RLS_NO_POLICIES_WARNING, TIMESTAMPED_MIGRATION;
|
|
12182
|
+
var init_rlsMigrationTarget = __esm({
|
|
12183
|
+
"src/heal/rlsMigrationTarget.ts"() {
|
|
11983
12184
|
"use strict";
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
"stripe-product": "stripe",
|
|
11991
|
-
"stripe-keys": "stripe"
|
|
11992
|
-
};
|
|
12185
|
+
import_node_fs5 = require("node:fs");
|
|
12186
|
+
import_node_path9 = require("node:path");
|
|
12187
|
+
RLS_TURNED_OFF_PHRASE = "has row level security turned off at";
|
|
12188
|
+
RLS_ASK_FIRST = "Ask the user first: enabling RLS without policies makes browser reads return no rows until policies exist.";
|
|
12189
|
+
RLS_NO_POLICIES_WARNING = "This migration enables row level security with no policies. Until you add policies, the anon and authenticated roles get no rows from these tables through the Data API, so browser reads return nothing and browser writes fail. `check` then reports the tables only as info (rls_no_policies), not as a blocker. Add the policies the app needs before you apply the migration to the database.";
|
|
12190
|
+
TIMESTAMPED_MIGRATION = /^\d{14}_.+\.sql$/;
|
|
11993
12191
|
}
|
|
11994
12192
|
});
|
|
11995
12193
|
|
|
11996
12194
|
// src/playbooks/playbooksRoot.ts
|
|
11997
12195
|
function playbooksRoot() {
|
|
11998
|
-
const candidates = [(0,
|
|
12196
|
+
const candidates = [(0, import_node_path10.join)(__dirname, "playbooks"), (0, import_node_path10.join)(__dirname, "..", "..", "playbooks")];
|
|
11999
12197
|
for (const dir of candidates) {
|
|
12000
|
-
if ((0,
|
|
12198
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path10.join)(dir, "vercel.json"))) {
|
|
12001
12199
|
return dir;
|
|
12002
12200
|
}
|
|
12003
12201
|
}
|
|
12004
12202
|
throw new Error("VibeRaven playbooks directory not found (expected vercel.json)");
|
|
12005
12203
|
}
|
|
12006
|
-
var
|
|
12204
|
+
var import_node_fs6, import_node_path10;
|
|
12007
12205
|
var init_playbooksRoot = __esm({
|
|
12008
12206
|
"src/playbooks/playbooksRoot.ts"() {
|
|
12009
12207
|
"use strict";
|
|
12010
|
-
|
|
12011
|
-
|
|
12208
|
+
import_node_fs6 = require("node:fs");
|
|
12209
|
+
import_node_path10 = require("node:path");
|
|
12012
12210
|
}
|
|
12013
12211
|
});
|
|
12014
12212
|
|
|
@@ -12115,7 +12313,7 @@ async function loadPlaybook(provider2) {
|
|
|
12115
12313
|
`Unknown provider "${provider2}". Available: ${PLAYBOOK_PROVIDERS.join(", ")}`
|
|
12116
12314
|
);
|
|
12117
12315
|
}
|
|
12118
|
-
const path = (0,
|
|
12316
|
+
const path = (0, import_node_path11.join)(playbooksRoot(), `${normalized}.json`);
|
|
12119
12317
|
const raw = JSON.parse(await (0, import_promises7.readFile)(path, "utf-8"));
|
|
12120
12318
|
const playbook = parsePlaybook(raw);
|
|
12121
12319
|
if (playbook.provider !== normalized) {
|
|
@@ -12130,59 +12328,30 @@ function loadPlaybookSync(provider2) {
|
|
|
12130
12328
|
`Unknown provider "${provider2}". Available: ${PLAYBOOK_PROVIDERS.join(", ")}`
|
|
12131
12329
|
);
|
|
12132
12330
|
}
|
|
12133
|
-
const path = (0,
|
|
12134
|
-
const raw = JSON.parse((0,
|
|
12331
|
+
const path = (0, import_node_path11.join)(playbooksRoot(), `${normalized}.json`);
|
|
12332
|
+
const raw = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf-8"));
|
|
12135
12333
|
const playbook = parsePlaybook(raw);
|
|
12136
12334
|
if (playbook.provider !== normalized) {
|
|
12137
12335
|
throw new Error(`Playbook file ${normalized}.json has mismatched provider field`);
|
|
12138
12336
|
}
|
|
12139
12337
|
return playbook;
|
|
12140
12338
|
}
|
|
12141
|
-
var
|
|
12339
|
+
var import_node_fs7, import_promises7, import_node_path11;
|
|
12142
12340
|
var init_loadPlaybook = __esm({
|
|
12143
12341
|
"src/playbooks/loadPlaybook.ts"() {
|
|
12144
12342
|
"use strict";
|
|
12145
|
-
|
|
12343
|
+
import_node_fs7 = require("node:fs");
|
|
12146
12344
|
import_promises7 = require("node:fs/promises");
|
|
12147
|
-
|
|
12345
|
+
import_node_path11 = require("node:path");
|
|
12148
12346
|
init_playbooksRoot();
|
|
12149
12347
|
init_types2();
|
|
12150
12348
|
init_validate();
|
|
12151
12349
|
}
|
|
12152
12350
|
});
|
|
12153
12351
|
|
|
12154
|
-
// src/
|
|
12155
|
-
function
|
|
12156
|
-
return
|
|
12157
|
-
}
|
|
12158
|
-
function collectManualChecks(artifact) {
|
|
12159
|
-
const refs = [];
|
|
12160
|
-
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12161
|
-
for (const mission of area.providerMissions) {
|
|
12162
|
-
for (const check of mission.checks) {
|
|
12163
|
-
if (!isManualProviderCheck(check)) {
|
|
12164
|
-
continue;
|
|
12165
|
-
}
|
|
12166
|
-
refs.push({
|
|
12167
|
-
areaLabel: area.label,
|
|
12168
|
-
providerLabel: mission.providerLabel,
|
|
12169
|
-
check,
|
|
12170
|
-
mapCategory: area.key
|
|
12171
|
-
});
|
|
12172
|
-
}
|
|
12173
|
-
}
|
|
12174
|
-
}
|
|
12175
|
-
return refs;
|
|
12176
|
-
}
|
|
12177
|
-
var init_manualChecks = __esm({
|
|
12178
|
-
"src/playbooks/manualChecks.ts"() {
|
|
12179
|
-
"use strict";
|
|
12180
|
-
}
|
|
12181
|
-
});
|
|
12182
|
-
|
|
12183
|
-
// src/tui/menu.ts
|
|
12184
|
-
function isScanNotFoundError(error) {
|
|
12185
|
-
return error instanceof ScanNotFoundError;
|
|
12352
|
+
// src/tui/menu.ts
|
|
12353
|
+
function isScanNotFoundError(error) {
|
|
12354
|
+
return error instanceof ScanNotFoundError;
|
|
12186
12355
|
}
|
|
12187
12356
|
function needsScanMessage(startDir) {
|
|
12188
12357
|
const cwd = startDir ?? process.cwd();
|
|
@@ -12229,7 +12398,7 @@ async function loadLastArtifact(startDir) {
|
|
|
12229
12398
|
if (!workspace) {
|
|
12230
12399
|
throw new ScanNotFoundError(needsScanMessage(startDir));
|
|
12231
12400
|
}
|
|
12232
|
-
const path = (0,
|
|
12401
|
+
const path = (0, import_node_path12.join)(getProjectArtifactsDir(workspace), "last-scan.json");
|
|
12233
12402
|
try {
|
|
12234
12403
|
const raw = await (0, import_promises8.readFile)(path, "utf-8");
|
|
12235
12404
|
return JSON.parse(raw);
|
|
@@ -12237,12 +12406,12 @@ async function loadLastArtifact(startDir) {
|
|
|
12237
12406
|
throw new ScanNotFoundError(needsScanMessage(startDir));
|
|
12238
12407
|
}
|
|
12239
12408
|
}
|
|
12240
|
-
var import_promises8,
|
|
12409
|
+
var import_promises8, import_node_path12, SEVERITY_RANK2, ScanNotFoundError;
|
|
12241
12410
|
var init_menu = __esm({
|
|
12242
12411
|
"src/tui/menu.ts"() {
|
|
12243
12412
|
"use strict";
|
|
12244
12413
|
import_promises8 = require("node:fs/promises");
|
|
12245
|
-
|
|
12414
|
+
import_node_path12 = require("node:path");
|
|
12246
12415
|
init_config();
|
|
12247
12416
|
SEVERITY_RANK2 = {
|
|
12248
12417
|
critical: 0,
|
|
@@ -12258,228 +12427,6 @@ var init_menu = __esm({
|
|
|
12258
12427
|
}
|
|
12259
12428
|
});
|
|
12260
12429
|
|
|
12261
|
-
// src/resolveNextAction.ts
|
|
12262
|
-
function resolveNextAction(artifact) {
|
|
12263
|
-
const repoGap = sortGapsByPriority(artifact.gaps)[0];
|
|
12264
|
-
if (repoGap) {
|
|
12265
|
-
return {
|
|
12266
|
-
type: "repo-fix",
|
|
12267
|
-
title: repoGap.title,
|
|
12268
|
-
detail: repoGap.detail,
|
|
12269
|
-
command: `viberaven prompt --gap ${repoGap.id}`
|
|
12270
|
-
};
|
|
12271
|
-
}
|
|
12272
|
-
const manual = collectManualChecks(artifact)[0];
|
|
12273
|
-
if (manual) {
|
|
12274
|
-
const provider2 = mapCheckToPlaybook(manual.check);
|
|
12275
|
-
let openUrl;
|
|
12276
|
-
try {
|
|
12277
|
-
const playbook = loadPlaybookSync(provider2);
|
|
12278
|
-
openUrl = playbook.steps[0]?.openUrl;
|
|
12279
|
-
} catch {
|
|
12280
|
-
openUrl = void 0;
|
|
12281
|
-
}
|
|
12282
|
-
return {
|
|
12283
|
-
type: "provider-guide",
|
|
12284
|
-
title: manual.check.label,
|
|
12285
|
-
detail: manual.check.promptHint || `Configure ${manual.providerLabel} in the provider dashboard (${manual.areaLabel}).`,
|
|
12286
|
-
provider: provider2,
|
|
12287
|
-
playbookStep: 1,
|
|
12288
|
-
command: `viberaven guide ${provider2} --step 1`,
|
|
12289
|
-
openUrl
|
|
12290
|
-
};
|
|
12291
|
-
}
|
|
12292
|
-
return {
|
|
12293
|
-
type: "done",
|
|
12294
|
-
title: "No blockers found",
|
|
12295
|
-
detail: "Re-scan after changes to confirm production readiness."
|
|
12296
|
-
};
|
|
12297
|
-
}
|
|
12298
|
-
var init_resolveNextAction = __esm({
|
|
12299
|
-
"src/resolveNextAction.ts"() {
|
|
12300
|
-
"use strict";
|
|
12301
|
-
init_checkMap();
|
|
12302
|
-
init_loadPlaybook();
|
|
12303
|
-
init_manualChecks();
|
|
12304
|
-
init_menu();
|
|
12305
|
-
}
|
|
12306
|
-
});
|
|
12307
|
-
|
|
12308
|
-
// src/report/agentSummary.ts
|
|
12309
|
-
function sortGaps(gaps) {
|
|
12310
|
-
return [...gaps].sort((a, b3) => {
|
|
12311
|
-
const sev = SEVERITY_ORDER2[a.severity] - SEVERITY_ORDER2[b3.severity];
|
|
12312
|
-
if (sev !== 0) {
|
|
12313
|
-
return sev;
|
|
12314
|
-
}
|
|
12315
|
-
return a.title.localeCompare(b3.title);
|
|
12316
|
-
});
|
|
12317
|
-
}
|
|
12318
|
-
function generateAgentSummary(artifact) {
|
|
12319
|
-
const lines = [];
|
|
12320
|
-
const topGaps = sortGaps(artifact.gaps).slice(0, 8);
|
|
12321
|
-
lines.push("# VibeRaven agent summary", "");
|
|
12322
|
-
lines.push(`Scanned: \`${artifact.workspacePath}\``);
|
|
12323
|
-
lines.push(`At: ${artifact.scannedAt}`);
|
|
12324
|
-
lines.push(
|
|
12325
|
-
`Production core: **${artifact.productionCorePercent}%** \xB7 Model score: **${artifact.score}** (${artifact.scoreLabel})`
|
|
12326
|
-
);
|
|
12327
|
-
lines.push("");
|
|
12328
|
-
const next = resolveNextAction(artifact);
|
|
12329
|
-
lines.push("## Next action", "");
|
|
12330
|
-
lines.push(`**${next.title}** \u2014 ${next.detail}`);
|
|
12331
|
-
if (next.command) {
|
|
12332
|
-
lines.push(`Command: \`${next.command}\``);
|
|
12333
|
-
}
|
|
12334
|
-
lines.push("");
|
|
12335
|
-
lines.push("## Suggested stack", "");
|
|
12336
|
-
lines.push(
|
|
12337
|
-
"React + Tailwind + shadcn/ui + Supabase + Vercel (agent-default stack for lowest launch friction)"
|
|
12338
|
-
);
|
|
12339
|
-
lines.push("");
|
|
12340
|
-
lines.push("## Summary");
|
|
12341
|
-
lines.push(artifact.summary || "_No summary returned._");
|
|
12342
|
-
lines.push("");
|
|
12343
|
-
lines.push("## Mission map (repo wiring)");
|
|
12344
|
-
lines.push("");
|
|
12345
|
-
lines.push("| Area | Provider | Readiness | Notes |");
|
|
12346
|
-
lines.push("|------|----------|-----------|-------|");
|
|
12347
|
-
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12348
|
-
for (const mission of area.providerMissions) {
|
|
12349
|
-
const failed = mission.checks.filter(
|
|
12350
|
-
(c) => c.status === "missing" || c.status === "failed" || c.status === "needs-connection"
|
|
12351
|
-
).length;
|
|
12352
|
-
const notes = failed > 0 ? `${failed} open check${failed === 1 ? "" : "s"}` : `${mission.readinessPercent}% repo checks`;
|
|
12353
|
-
lines.push(
|
|
12354
|
-
`| ${area.label} | ${mission.providerLabel} | ${mission.readinessPercent}% | ${notes} |`
|
|
12355
|
-
);
|
|
12356
|
-
}
|
|
12357
|
-
}
|
|
12358
|
-
lines.push("");
|
|
12359
|
-
lines.push("## Agent-code actions");
|
|
12360
|
-
if (topGaps.length === 0) {
|
|
12361
|
-
lines.push("_No model gaps returned. Review mission map checks before changing code._");
|
|
12362
|
-
} else {
|
|
12363
|
-
topGaps.forEach((gap, index) => {
|
|
12364
|
-
lines.push(
|
|
12365
|
-
`${index + 1}. **${gap.title}** (\`${gap.id}\`, ${gap.severity}, map: \`${gap.primaryMapCategory}\`)`
|
|
12366
|
-
);
|
|
12367
|
-
lines.push(` - ${gap.detail}`);
|
|
12368
|
-
lines.push(` - Command: \`viberaven prompt --gap ${gap.id}\``);
|
|
12369
|
-
if (gap.copyPrompt) {
|
|
12370
|
-
lines.push(` - Prompt: ${gap.copyPrompt}`);
|
|
12371
|
-
}
|
|
12372
|
-
});
|
|
12373
|
-
}
|
|
12374
|
-
const manualChecks = (artifact.missionGraph.areas ?? []).flatMap(
|
|
12375
|
-
(area) => area.providerMissions.flatMap(
|
|
12376
|
-
(mission) => mission.checks.filter(
|
|
12377
|
-
(check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
|
|
12378
|
-
).map((check) => ({ area: area.label, provider: mission.providerLabel, check }))
|
|
12379
|
-
)
|
|
12380
|
-
);
|
|
12381
|
-
lines.push("");
|
|
12382
|
-
lines.push("## Human-provider actions");
|
|
12383
|
-
if (manualChecks.length === 0) {
|
|
12384
|
-
lines.push("_No manual provider actions were identified in this scan._");
|
|
12385
|
-
} else {
|
|
12386
|
-
manualChecks.slice(0, 8).forEach((item4, index) => {
|
|
12387
|
-
lines.push(`${index + 1}. **${item4.check.label}** (${item4.area} / ${item4.provider})`);
|
|
12388
|
-
lines.push(
|
|
12389
|
-
` - ${item4.check.promptHint || "Ask the user to confirm this in the provider dashboard or through read-only MCP."}`
|
|
12390
|
-
);
|
|
12391
|
-
});
|
|
12392
|
-
}
|
|
12393
|
-
lines.push("");
|
|
12394
|
-
lines.push("Do not claim human-provider actions as repo-code fixes.");
|
|
12395
|
-
lines.push("");
|
|
12396
|
-
lines.push("## Agent workflow");
|
|
12397
|
-
lines.push("1. Read `.viberaven/agent-tasklist.md` first for the production gate.");
|
|
12398
|
-
lines.push("2. Read `.viberaven/launch-playbook.md` for the full checklist.");
|
|
12399
|
-
lines.push("3. Run `viberaven next --json` - one action at a time.");
|
|
12400
|
-
lines.push("4. Repo fix: `viberaven prompt --gap <id>` then implement.");
|
|
12401
|
-
lines.push("5. Provider: `viberaven guide <provider> --step N` and `viberaven open <provider>`.");
|
|
12402
|
-
lines.push(`6. Run \`${PUBLIC_VERIFY_COMMAND}\` to rescan and refresh \`.viberaven/agent-tasklist.md\`.`);
|
|
12403
|
-
lines.push("");
|
|
12404
|
-
return `${lines.join("\n")}
|
|
12405
|
-
`;
|
|
12406
|
-
}
|
|
12407
|
-
var SEVERITY_ORDER2;
|
|
12408
|
-
var init_agentSummary = __esm({
|
|
12409
|
-
"src/report/agentSummary.ts"() {
|
|
12410
|
-
"use strict";
|
|
12411
|
-
init_commands();
|
|
12412
|
-
init_resolveNextAction();
|
|
12413
|
-
SEVERITY_ORDER2 = {
|
|
12414
|
-
critical: 0,
|
|
12415
|
-
warning: 1,
|
|
12416
|
-
info: 2
|
|
12417
|
-
};
|
|
12418
|
-
}
|
|
12419
|
-
});
|
|
12420
|
-
|
|
12421
|
-
// src/heal/rlsMigrationTarget.ts
|
|
12422
|
-
function rlsEnableStatements(tables) {
|
|
12423
|
-
return [...new Set(tables)].map((table2) => `alter table ${table2} enable row level security;`);
|
|
12424
|
-
}
|
|
12425
|
-
function migrationStamp(now) {
|
|
12426
|
-
return now.toISOString().replace(/\D/g, "").slice(0, 14);
|
|
12427
|
-
}
|
|
12428
|
-
function rlsMigrationTarget(cwd, evidence, now = /* @__PURE__ */ new Date()) {
|
|
12429
|
-
if (evidence.length === 0) return { ok: false, reason: "No table without row level security was found in the repo SQL." };
|
|
12430
|
-
const statementList = rlsEnableStatements(evidence.map((entry) => entry.table)).join(" ");
|
|
12431
|
-
const turnedOff = evidence.filter((entry) => entry.turnedOff);
|
|
12432
|
-
if (turnedOff.length > 0) {
|
|
12433
|
-
const where = turnedOff.map((entry) => `${entry.table} (${entry.file.replace(/\\/g, "/")})`).join(", ");
|
|
12434
|
-
return {
|
|
12435
|
-
ok: false,
|
|
12436
|
-
reason: `The latest migration that touches ${where} turns row level security off on purpose, so VibeRaven will not turn it back on automatically. If the user wants it on, add these statements by hand in a new migration, with the policies the app needs: ${statementList}`
|
|
12437
|
-
};
|
|
12438
|
-
}
|
|
12439
|
-
const source = evidence[0].file.replace(/\\/g, "/");
|
|
12440
|
-
const dir = import_node_path11.posix.dirname(source);
|
|
12441
|
-
if (import_node_path11.posix.basename(dir) !== "migrations") {
|
|
12442
|
-
return {
|
|
12443
|
-
ok: false,
|
|
12444
|
-
reason: `The tables come from ${source}, which is not in a migrations folder, so VibeRaven will not guess where a migration goes. Add these statements by hand where this project keeps its schema: ${statementList}`
|
|
12445
|
-
};
|
|
12446
|
-
}
|
|
12447
|
-
let existing;
|
|
12448
|
-
try {
|
|
12449
|
-
existing = (0, import_node_fs6.readdirSync)((0, import_node_path11.join)(cwd, dir)).filter((file) => file.endsWith(".sql")).sort();
|
|
12450
|
-
} catch {
|
|
12451
|
-
return { ok: false, reason: `VibeRaven could not read ${dir}. Add these statements by hand in a new migration: ${statementList}` };
|
|
12452
|
-
}
|
|
12453
|
-
const otherNaming = existing.find((file) => !TIMESTAMPED_MIGRATION.test(file));
|
|
12454
|
-
if (otherNaming) {
|
|
12455
|
-
return {
|
|
12456
|
-
ok: false,
|
|
12457
|
-
reason: `The migrations in ${dir} are not named <14-digit timestamp>_name.sql (for example ${otherNaming}), so a timestamped file from VibeRaven could run in the wrong order next to them. Add these statements by hand in a new migration that follows this project's naming: ${statementList}`
|
|
12458
|
-
};
|
|
12459
|
-
}
|
|
12460
|
-
const name = `${migrationStamp(now)}_viberaven_enable_rls.sql`;
|
|
12461
|
-
const last = existing[existing.length - 1];
|
|
12462
|
-
if (last && name <= last) {
|
|
12463
|
-
return {
|
|
12464
|
-
ok: false,
|
|
12465
|
-
reason: `A new migration named ${name} would not run after ${last} in ${dir}, so VibeRaven will not write it. Add these statements by hand in a migration that runs last: ${statementList}`
|
|
12466
|
-
};
|
|
12467
|
-
}
|
|
12468
|
-
return { ok: true, file: `${dir}/${name}` };
|
|
12469
|
-
}
|
|
12470
|
-
var import_node_fs6, import_node_path11, RLS_TURNED_OFF_PHRASE, RLS_ASK_FIRST, RLS_NO_POLICIES_WARNING, TIMESTAMPED_MIGRATION;
|
|
12471
|
-
var init_rlsMigrationTarget = __esm({
|
|
12472
|
-
"src/heal/rlsMigrationTarget.ts"() {
|
|
12473
|
-
"use strict";
|
|
12474
|
-
import_node_fs6 = require("node:fs");
|
|
12475
|
-
import_node_path11 = require("node:path");
|
|
12476
|
-
RLS_TURNED_OFF_PHRASE = "has row level security turned off at";
|
|
12477
|
-
RLS_ASK_FIRST = "Ask the user first: enabling RLS without policies makes browser reads return no rows until policies exist.";
|
|
12478
|
-
RLS_NO_POLICIES_WARNING = "This migration enables row level security with no policies. Until you add policies, the anon and authenticated roles get no rows from these tables through the Data API, so browser reads return nothing and browser writes fail. `check` then reports the tables only as info (rls_no_policies), not as a blocker. Add the policies the app needs before you apply the migration to the database.";
|
|
12479
|
-
TIMESTAMPED_MIGRATION = /^\d{14}_.+\.sql$/;
|
|
12480
|
-
}
|
|
12481
|
-
});
|
|
12482
|
-
|
|
12483
12430
|
// src/buildTaskList.ts
|
|
12484
12431
|
function rlsMigrationFile(gap) {
|
|
12485
12432
|
if (gap.id !== "rls_disabled" || typeof gap.detail !== "string") return void 0;
|
|
@@ -12498,7 +12445,12 @@ function hasRecipe(gapId) {
|
|
|
12498
12445
|
const lower = gapId.toLowerCase();
|
|
12499
12446
|
return lower.includes("empty") && lower.includes("catch");
|
|
12500
12447
|
}
|
|
12501
|
-
function gapToPlaybookProvider(gap) {
|
|
12448
|
+
function gapToPlaybookProvider(gap, inRepo) {
|
|
12449
|
+
const provider2 = playbookByCategoryOrId(gap);
|
|
12450
|
+
if (!provider2 || !inRepo) return provider2;
|
|
12451
|
+
return inRepo.has(PLAYBOOK_TOKEN[provider2] ?? provider2) ? provider2 : void 0;
|
|
12452
|
+
}
|
|
12453
|
+
function playbookByCategoryOrId(gap) {
|
|
12502
12454
|
const cat = gap.primaryMapCategory.toLowerCase();
|
|
12503
12455
|
if (cat === "deployment") return "vercel";
|
|
12504
12456
|
if (cat === "payments") return "stripe";
|
|
@@ -12511,9 +12463,9 @@ function gapToPlaybookProvider(gap) {
|
|
|
12511
12463
|
if (id.includes("auth")) return "auth-supabase";
|
|
12512
12464
|
return void 0;
|
|
12513
12465
|
}
|
|
12514
|
-
function hasPlaybook(gap) {
|
|
12466
|
+
function hasPlaybook(gap, inRepo) {
|
|
12515
12467
|
try {
|
|
12516
|
-
const provider2 = gapToPlaybookProvider(gap);
|
|
12468
|
+
const provider2 = gapToPlaybookProvider(gap, inRepo);
|
|
12517
12469
|
if (!provider2) return false;
|
|
12518
12470
|
return PLAYBOOK_PROVIDERS.includes(provider2);
|
|
12519
12471
|
} catch {
|
|
@@ -12543,13 +12495,20 @@ function buildProviderAction(gap, provider2) {
|
|
|
12543
12495
|
}
|
|
12544
12496
|
function buildTaskList(artifact) {
|
|
12545
12497
|
const sorted = sortGapsByPriority(artifact.gaps);
|
|
12498
|
+
const providers = providersInRepo(artifact);
|
|
12499
|
+
const inRepo = providers ? new Set(providers.map((entry) => entry.provider.toLowerCase())) : void 0;
|
|
12546
12500
|
return sorted.map((gap, index) => {
|
|
12547
12501
|
const id = `TASK-${String(index + 1).padStart(3, "0")}`;
|
|
12548
12502
|
let fixType;
|
|
12549
12503
|
const migrationFile = rlsMigrationFile(gap);
|
|
12550
|
-
|
|
12504
|
+
const location = locationsForGap(gap)[0];
|
|
12505
|
+
const repoFixUserSteps = REPO_FIX_GAPS[gap.id];
|
|
12506
|
+
const informational = INFORMATIONAL_GAPS[gap.id];
|
|
12507
|
+
if (hasRecipe(gap.id) || migrationFile || repoFixUserSteps) {
|
|
12551
12508
|
fixType = "repo-code";
|
|
12552
|
-
} else if (
|
|
12509
|
+
} else if (informational) {
|
|
12510
|
+
fixType = "manual-verify";
|
|
12511
|
+
} else if (hasPlaybook(gap, inRepo)) {
|
|
12553
12512
|
fixType = "provider-action";
|
|
12554
12513
|
} else {
|
|
12555
12514
|
fixType = "manual-verify";
|
|
@@ -12566,6 +12525,8 @@ function buildTaskList(artifact) {
|
|
|
12566
12525
|
if (fixType === "repo-code" && !hasRecipe(gap.id) && migrationFile) {
|
|
12567
12526
|
base.requiresUserAction = true;
|
|
12568
12527
|
base.file = migrationFile;
|
|
12528
|
+
base.userSteps = [APPLY_MIGRATION];
|
|
12529
|
+
if (location?.file === migrationFile && location.line !== void 0) base.line = location.line;
|
|
12569
12530
|
const target = rlsMigrationTarget(artifact.workspacePath, rlsEvidence2(gap.detail));
|
|
12570
12531
|
if (target.ok) {
|
|
12571
12532
|
base.mcpTool = "viberaven_heal_apply";
|
|
@@ -12577,6 +12538,28 @@ function buildTaskList(artifact) {
|
|
|
12577
12538
|
if (gap.copyPrompt) {
|
|
12578
12539
|
base.exactFix = gap.copyPrompt.trim();
|
|
12579
12540
|
}
|
|
12541
|
+
} else if (fixType === "repo-code" && !hasRecipe(gap.id) && repoFixUserSteps) {
|
|
12542
|
+
base.requiresUserAction = false;
|
|
12543
|
+
if (location) {
|
|
12544
|
+
base.file = location.file;
|
|
12545
|
+
if (location.line !== void 0) base.line = location.line;
|
|
12546
|
+
} else {
|
|
12547
|
+
base.action = "Edit the files named in the gap detail (`npx -y viberaven prompt --gap " + gap.id + "`).";
|
|
12548
|
+
}
|
|
12549
|
+
if (gap.copyPrompt) {
|
|
12550
|
+
base.exactFix = gap.copyPrompt.trim();
|
|
12551
|
+
}
|
|
12552
|
+
base.userSteps = [...repoFixUserSteps];
|
|
12553
|
+
} else if (fixType === "manual-verify" && informational) {
|
|
12554
|
+
base.requiresUserAction = false;
|
|
12555
|
+
base.action = informational;
|
|
12556
|
+
if (location) {
|
|
12557
|
+
base.file = location.file;
|
|
12558
|
+
if (location.line !== void 0) base.line = location.line;
|
|
12559
|
+
}
|
|
12560
|
+
if (gap.copyPrompt) {
|
|
12561
|
+
base.exactFix = gap.copyPrompt.trim();
|
|
12562
|
+
}
|
|
12580
12563
|
} else if (fixType === "repo-code") {
|
|
12581
12564
|
base.mcpTool = "viberaven_heal_apply";
|
|
12582
12565
|
base.mcpArgs = { gap: gap.id, yes: true };
|
|
@@ -12586,7 +12569,7 @@ function buildTaskList(artifact) {
|
|
|
12586
12569
|
}
|
|
12587
12570
|
} else if (fixType === "provider-action") {
|
|
12588
12571
|
try {
|
|
12589
|
-
const provider2 = gapToPlaybookProvider(gap);
|
|
12572
|
+
const provider2 = gapToPlaybookProvider(gap, inRepo);
|
|
12590
12573
|
if (provider2) {
|
|
12591
12574
|
const pa = buildProviderAction(gap, provider2);
|
|
12592
12575
|
if (pa) {
|
|
@@ -12604,7 +12587,7 @@ function buildTaskList(artifact) {
|
|
|
12604
12587
|
}
|
|
12605
12588
|
function buildTaskListMarkdown(tasks) {
|
|
12606
12589
|
if (tasks.length === 0) {
|
|
12607
|
-
return "# VibeRaven Agent Tasklist\n\n_No gaps found
|
|
12590
|
+
return "# VibeRaven Agent Tasklist\n\n_No gaps found in this scan._\n";
|
|
12608
12591
|
}
|
|
12609
12592
|
const lines = ["# VibeRaven Agent Tasklist", ""];
|
|
12610
12593
|
for (const task of tasks) {
|
|
@@ -12612,7 +12595,7 @@ function buildTaskListMarkdown(tasks) {
|
|
|
12612
12595
|
lines.push(`## ${task.id} \xB7 ${task.gapId} \xB7 ${severityLabel}`, "");
|
|
12613
12596
|
lines.push(`**Fix type:** ${task.fixType} `);
|
|
12614
12597
|
if (task.file) {
|
|
12615
|
-
lines.push(`**File:** \`${task.file}\` `);
|
|
12598
|
+
lines.push(`**File:** \`${task.file}${task.line !== void 0 ? `:${task.line}` : ""}\` `);
|
|
12616
12599
|
}
|
|
12617
12600
|
if (task.action) {
|
|
12618
12601
|
lines.push(`**Action:** ${task.action} `);
|
|
@@ -12620,62 +12603,387 @@ function buildTaskListMarkdown(tasks) {
|
|
|
12620
12603
|
if (task.exactFix) {
|
|
12621
12604
|
lines.push(`**Exact fix:** ${task.exactFix} `);
|
|
12622
12605
|
} else {
|
|
12623
|
-
lines.push(`**Exact fix:** No automated recipe
|
|
12606
|
+
lines.push(`**Exact fix:** No automated recipe; see the scanner hint in the gap detail. `);
|
|
12624
12607
|
}
|
|
12625
12608
|
lines.push(`**Verify:** \`${task.verifyCommand}\` `);
|
|
12626
12609
|
if (task.mcpTool && task.mcpArgs) {
|
|
12627
12610
|
lines.push(
|
|
12628
|
-
`**MCP:** \`${task.mcpTool} ${JSON.stringify(task.mcpArgs)}\` `
|
|
12611
|
+
`**MCP:** \`${task.mcpTool} ${JSON.stringify(task.mcpArgs)}\` `
|
|
12612
|
+
);
|
|
12613
|
+
}
|
|
12614
|
+
lines.push(`**Requires user action:** ${task.requiresUserAction}`);
|
|
12615
|
+
if (task.userSteps && task.userSteps.length > 0) {
|
|
12616
|
+
lines.push("");
|
|
12617
|
+
lines.push("**Outside the repo (needs the user):**");
|
|
12618
|
+
for (const step of task.userSteps) lines.push(`- ${step}`);
|
|
12619
|
+
}
|
|
12620
|
+
if (task.providerAction) {
|
|
12621
|
+
const pa = task.providerAction;
|
|
12622
|
+
lines.push("");
|
|
12623
|
+
lines.push("**Provider action:**");
|
|
12624
|
+
lines.push(`- Provider: ${pa.provider}`);
|
|
12625
|
+
lines.push(`- Dashboard: ${pa.dashboardUrl}`);
|
|
12626
|
+
lines.push(`- Step: ${pa.exactStep}`);
|
|
12627
|
+
if (pa.envKeyName) lines.push(`- Env key: \`${pa.envKeyName}\``);
|
|
12628
|
+
if (pa.doneSignal) lines.push(`- Done when: ${pa.doneSignal}`);
|
|
12629
|
+
if (pa.mcpAlternative) lines.push(`- MCP alternative: \`${pa.mcpAlternative}\``);
|
|
12630
|
+
}
|
|
12631
|
+
lines.push("");
|
|
12632
|
+
}
|
|
12633
|
+
return `${lines.join("\n")}
|
|
12634
|
+
`;
|
|
12635
|
+
}
|
|
12636
|
+
var PLAYBOOK_TOKEN;
|
|
12637
|
+
var init_buildTaskList = __esm({
|
|
12638
|
+
"src/buildTaskList.ts"() {
|
|
12639
|
+
"use strict";
|
|
12640
|
+
init_commands();
|
|
12641
|
+
init_rlsMigrationTarget();
|
|
12642
|
+
init_gapLocations();
|
|
12643
|
+
init_repoFixes();
|
|
12644
|
+
init_detectedProviders();
|
|
12645
|
+
init_loadPlaybook();
|
|
12646
|
+
init_types2();
|
|
12647
|
+
init_menu();
|
|
12648
|
+
PLAYBOOK_TOKEN = { vercel: "vercel", stripe: "stripe", supabase: "supabase", "auth-supabase": "supabase" };
|
|
12649
|
+
}
|
|
12650
|
+
});
|
|
12651
|
+
|
|
12652
|
+
// src/contracts/gapEvidence.ts
|
|
12653
|
+
function summarizeGap(gap) {
|
|
12654
|
+
return `${gap.title}. See the tasklist and original scan for redacted detail.`;
|
|
12655
|
+
}
|
|
12656
|
+
function evidenceFor2(gap) {
|
|
12657
|
+
const kind = String(gap.primaryMapCategory);
|
|
12658
|
+
const located = locationsForGap(gap).map((location) => ({ kind, ...location, redacted: true }));
|
|
12659
|
+
return located.length > 0 ? located : [{ kind, redacted: true }];
|
|
12660
|
+
}
|
|
12661
|
+
function userStepsFor(gap) {
|
|
12662
|
+
if (REPO_FIX_GAPS[gap.id]) return { userSteps: [...REPO_FIX_GAPS[gap.id]] };
|
|
12663
|
+
if (rlsMigrationFile(gap)) return { userSteps: [APPLY_MIGRATION] };
|
|
12664
|
+
return {};
|
|
12665
|
+
}
|
|
12666
|
+
function generateGapEvidenceFiles(artifact) {
|
|
12667
|
+
return artifact.gaps.slice(0, 50).map((gap) => ({
|
|
12668
|
+
path: `.viberaven/gaps/${gap.id}.json`,
|
|
12669
|
+
content: {
|
|
12670
|
+
$schema: "https://viberaven.dev/schemas/gap.schema.json",
|
|
12671
|
+
schemaVersion: "v1",
|
|
12672
|
+
id: gap.id,
|
|
12673
|
+
severity: gap.severity,
|
|
12674
|
+
capability: classifyGapCapability(gap),
|
|
12675
|
+
title: gap.title,
|
|
12676
|
+
summary: summarizeGap(gap),
|
|
12677
|
+
evidence: evidenceFor2(gap),
|
|
12678
|
+
commands: {
|
|
12679
|
+
prompt: promptGapCommand(gap.id),
|
|
12680
|
+
healPlan: healPlanGapCommand(gap.id),
|
|
12681
|
+
verify: PUBLIC_VERIFY_COMMAND
|
|
12682
|
+
},
|
|
12683
|
+
...userStepsFor(gap),
|
|
12684
|
+
providerBoundary: REPO_ONLY_GAPS.has(gap.id) ? { requiresDashboardCheck: false, reason: "The fix is a repo change; no provider dashboard state is involved." } : { requiresDashboardCheck: true, reason: "Repo evidence cannot prove live provider dashboard state." }
|
|
12685
|
+
}
|
|
12686
|
+
}));
|
|
12687
|
+
}
|
|
12688
|
+
var init_gapEvidence = __esm({
|
|
12689
|
+
"src/contracts/gapEvidence.ts"() {
|
|
12690
|
+
"use strict";
|
|
12691
|
+
init_capabilities();
|
|
12692
|
+
init_gapLocations();
|
|
12693
|
+
init_repoFixes();
|
|
12694
|
+
init_buildTaskList();
|
|
12695
|
+
init_commands();
|
|
12696
|
+
}
|
|
12697
|
+
});
|
|
12698
|
+
|
|
12699
|
+
// src/playbooks/checkMap.ts
|
|
12700
|
+
function mapCheckToPlaybook(check) {
|
|
12701
|
+
if (CHECK_TO_PLAYBOOK[check.id]) {
|
|
12702
|
+
return CHECK_TO_PLAYBOOK[check.id];
|
|
12703
|
+
}
|
|
12704
|
+
const providerKey = String(check.providerKey ?? "").toLowerCase();
|
|
12705
|
+
if (providerKey.includes("vercel")) {
|
|
12706
|
+
return "vercel";
|
|
12707
|
+
}
|
|
12708
|
+
if (providerKey.includes("stripe")) {
|
|
12709
|
+
return "stripe";
|
|
12710
|
+
}
|
|
12711
|
+
if (providerKey.includes("supabase")) {
|
|
12712
|
+
return check.area === "auth" ? "auth-supabase" : "supabase";
|
|
12713
|
+
}
|
|
12714
|
+
return void 0;
|
|
12715
|
+
}
|
|
12716
|
+
var CHECK_TO_PLAYBOOK;
|
|
12717
|
+
var init_checkMap = __esm({
|
|
12718
|
+
"src/playbooks/checkMap.ts"() {
|
|
12719
|
+
"use strict";
|
|
12720
|
+
CHECK_TO_PLAYBOOK = {
|
|
12721
|
+
"vercel-deployment": "vercel",
|
|
12722
|
+
"vercel-project": "vercel",
|
|
12723
|
+
"supabase-project": "supabase",
|
|
12724
|
+
"supabase-env": "supabase",
|
|
12725
|
+
"stripe-webhook": "stripe",
|
|
12726
|
+
"stripe-product": "stripe",
|
|
12727
|
+
"stripe-keys": "stripe"
|
|
12728
|
+
};
|
|
12729
|
+
}
|
|
12730
|
+
});
|
|
12731
|
+
|
|
12732
|
+
// src/report/missionSelection.ts
|
|
12733
|
+
function normalizeProviderToken2(value) {
|
|
12734
|
+
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "");
|
|
12735
|
+
}
|
|
12736
|
+
function missionMatchesProvider(mission, provider2) {
|
|
12737
|
+
const current = normalizeProviderToken2(provider2);
|
|
12738
|
+
return normalizeProviderToken2(mission.provider || mission.providerLabel || mission.key) === current || normalizeProviderToken2(mission.providerLabel || mission.provider || mission.key) === current;
|
|
12739
|
+
}
|
|
12740
|
+
function missionEvidenceScore(mission) {
|
|
12741
|
+
const repoVerified = mission.checks.filter((check) => check.evidenceClass === "repo-verified" || check.status === "passed").length;
|
|
12742
|
+
const missing = mission.checks.filter(
|
|
12743
|
+
(check) => check.evidenceClass === "missing-repo-fix" || check.status === "missing" || check.status === "failed"
|
|
12744
|
+
).length;
|
|
12745
|
+
return repoVerified * 100 + (mission.readinessPercent ?? 0) - missing;
|
|
12746
|
+
}
|
|
12747
|
+
function openChecksForMission(mission) {
|
|
12748
|
+
if (!mission) {
|
|
12749
|
+
return 0;
|
|
12750
|
+
}
|
|
12751
|
+
return mission.checks.filter(
|
|
12752
|
+
(check) => check.status === "missing" || check.status === "failed" || check.status === "needs-connection"
|
|
12753
|
+
).length;
|
|
12754
|
+
}
|
|
12755
|
+
var init_missionSelection = __esm({
|
|
12756
|
+
"src/report/missionSelection.ts"() {
|
|
12757
|
+
"use strict";
|
|
12758
|
+
}
|
|
12759
|
+
});
|
|
12760
|
+
|
|
12761
|
+
// src/report/inRepoMissions.ts
|
|
12762
|
+
function detectedProviderTokens(artifact) {
|
|
12763
|
+
const providers = providersInRepo(artifact);
|
|
12764
|
+
if (!providers) return void 0;
|
|
12765
|
+
return new Set(providers.map((entry) => normalizeProviderToken2(entry.provider)));
|
|
12766
|
+
}
|
|
12767
|
+
function missionInRepo(mission, detected) {
|
|
12768
|
+
const provider2 = String(mission.provider || mission.key || "");
|
|
12769
|
+
if (detected.has(normalizeProviderToken2(provider2))) return true;
|
|
12770
|
+
if (PRACTICES.has(provider2)) return true;
|
|
12771
|
+
const identity = mission.checks.find((check) => IDENTITY_CHECK.test(check.id));
|
|
12772
|
+
return identity?.status === "passed";
|
|
12773
|
+
}
|
|
12774
|
+
function inRepoMissions(artifact, area) {
|
|
12775
|
+
const missions = area.providerMissions ?? [];
|
|
12776
|
+
const detected = detectedProviderTokens(artifact);
|
|
12777
|
+
if (!detected) return missions;
|
|
12778
|
+
const selected = artifact.selectedProviders?.[area.key] ?? "";
|
|
12779
|
+
return missions.filter((mission) => missionInRepo(mission, detected) || selected && missionMatchesProvider(mission, selected));
|
|
12780
|
+
}
|
|
12781
|
+
function preferredInRepoMission(artifact, area) {
|
|
12782
|
+
const missions = inRepoMissions(artifact, area);
|
|
12783
|
+
if (missions.length === 0) return void 0;
|
|
12784
|
+
const selected = artifact.selectedProviders?.[area.key] ?? "";
|
|
12785
|
+
const picked = selected ? missions.find((mission) => missionMatchesProvider(mission, selected)) : void 0;
|
|
12786
|
+
return picked ?? [...missions].sort((a, b3) => missionEvidenceScore(b3) - missionEvidenceScore(a))[0];
|
|
12787
|
+
}
|
|
12788
|
+
var IDENTITY_CHECK, PRACTICES, NONE_FOUND;
|
|
12789
|
+
var init_inRepoMissions = __esm({
|
|
12790
|
+
"src/report/inRepoMissions.ts"() {
|
|
12791
|
+
"use strict";
|
|
12792
|
+
init_detectedProviders();
|
|
12793
|
+
init_missionSelection();
|
|
12794
|
+
IDENTITY_CHECK = /^(?:package-installed|package-or-config-found|package-or-widget-found|api-client-found|storybook-package-found|server-runtime-found|rails-runtime-found|go-runtime-found)$/;
|
|
12795
|
+
PRACTICES = /* @__PURE__ */ new Set(["route-map", "product-spec", "secrets-hygiene"]);
|
|
12796
|
+
NONE_FOUND = "none found";
|
|
12797
|
+
}
|
|
12798
|
+
});
|
|
12799
|
+
|
|
12800
|
+
// src/playbooks/manualChecks.ts
|
|
12801
|
+
function isManualProviderCheck(check) {
|
|
12802
|
+
return check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown";
|
|
12803
|
+
}
|
|
12804
|
+
function collectManualChecks(artifact) {
|
|
12805
|
+
const refs = [];
|
|
12806
|
+
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12807
|
+
for (const mission of inRepoMissions(artifact, area)) {
|
|
12808
|
+
for (const check of mission.checks) {
|
|
12809
|
+
if (!isManualProviderCheck(check)) {
|
|
12810
|
+
continue;
|
|
12811
|
+
}
|
|
12812
|
+
refs.push({
|
|
12813
|
+
areaLabel: area.label,
|
|
12814
|
+
providerLabel: mission.providerLabel,
|
|
12815
|
+
check,
|
|
12816
|
+
mapCategory: area.key
|
|
12817
|
+
});
|
|
12818
|
+
}
|
|
12819
|
+
}
|
|
12820
|
+
}
|
|
12821
|
+
return refs;
|
|
12822
|
+
}
|
|
12823
|
+
var init_manualChecks = __esm({
|
|
12824
|
+
"src/playbooks/manualChecks.ts"() {
|
|
12825
|
+
"use strict";
|
|
12826
|
+
init_inRepoMissions();
|
|
12827
|
+
}
|
|
12828
|
+
});
|
|
12829
|
+
|
|
12830
|
+
// src/resolveNextAction.ts
|
|
12831
|
+
function resolveNextAction(artifact) {
|
|
12832
|
+
const repoGap = sortGapsByPriority(artifact.gaps)[0];
|
|
12833
|
+
if (repoGap) {
|
|
12834
|
+
return {
|
|
12835
|
+
type: "repo-fix",
|
|
12836
|
+
title: repoGap.title,
|
|
12837
|
+
detail: repoGap.detail,
|
|
12838
|
+
command: `viberaven prompt --gap ${repoGap.id}`
|
|
12839
|
+
};
|
|
12840
|
+
}
|
|
12841
|
+
const manual = collectManualChecks(artifact)[0];
|
|
12842
|
+
if (manual) {
|
|
12843
|
+
const provider2 = mapCheckToPlaybook(manual.check);
|
|
12844
|
+
let openUrl;
|
|
12845
|
+
try {
|
|
12846
|
+
openUrl = provider2 ? loadPlaybookSync(provider2).steps[0]?.openUrl : void 0;
|
|
12847
|
+
} catch {
|
|
12848
|
+
openUrl = void 0;
|
|
12849
|
+
}
|
|
12850
|
+
return {
|
|
12851
|
+
type: "provider-guide",
|
|
12852
|
+
title: manual.check.label,
|
|
12853
|
+
detail: manual.check.promptHint || `Configure ${manual.providerLabel} in the provider dashboard (${manual.areaLabel}).`,
|
|
12854
|
+
...provider2 ? { provider: provider2, playbookStep: 1, command: `viberaven guide ${provider2} --step 1` } : {},
|
|
12855
|
+
openUrl
|
|
12856
|
+
};
|
|
12857
|
+
}
|
|
12858
|
+
return {
|
|
12859
|
+
type: "done",
|
|
12860
|
+
title: "No blockers found",
|
|
12861
|
+
detail: "Re-scan after changes to confirm production readiness."
|
|
12862
|
+
};
|
|
12863
|
+
}
|
|
12864
|
+
var init_resolveNextAction = __esm({
|
|
12865
|
+
"src/resolveNextAction.ts"() {
|
|
12866
|
+
"use strict";
|
|
12867
|
+
init_checkMap();
|
|
12868
|
+
init_loadPlaybook();
|
|
12869
|
+
init_manualChecks();
|
|
12870
|
+
init_menu();
|
|
12871
|
+
}
|
|
12872
|
+
});
|
|
12873
|
+
|
|
12874
|
+
// src/report/agentSummary.ts
|
|
12875
|
+
function sortGaps(gaps) {
|
|
12876
|
+
return [...gaps].sort((a, b3) => {
|
|
12877
|
+
const sev = SEVERITY_ORDER2[a.severity] - SEVERITY_ORDER2[b3.severity];
|
|
12878
|
+
if (sev !== 0) {
|
|
12879
|
+
return sev;
|
|
12880
|
+
}
|
|
12881
|
+
return a.title.localeCompare(b3.title);
|
|
12882
|
+
});
|
|
12883
|
+
}
|
|
12884
|
+
function generateAgentSummary(artifact) {
|
|
12885
|
+
const lines = [];
|
|
12886
|
+
const topGaps = sortGaps(artifact.gaps).slice(0, 8);
|
|
12887
|
+
lines.push("# VibeRaven agent summary", "");
|
|
12888
|
+
lines.push(`Scanned: \`${artifact.workspacePath}\``);
|
|
12889
|
+
lines.push(`At: ${artifact.scannedAt}`);
|
|
12890
|
+
lines.push(
|
|
12891
|
+
`Production core: **${artifact.productionCorePercent}%** \xB7 Model score: **${artifact.score}** (${artifact.scoreLabel})`
|
|
12892
|
+
);
|
|
12893
|
+
lines.push("");
|
|
12894
|
+
const next = resolveNextAction(artifact);
|
|
12895
|
+
lines.push("## Next action", "");
|
|
12896
|
+
lines.push(`**${next.title}**: ${next.detail}`);
|
|
12897
|
+
if (next.command) {
|
|
12898
|
+
lines.push(`Command: \`${next.command}\``);
|
|
12899
|
+
}
|
|
12900
|
+
lines.push("");
|
|
12901
|
+
lines.push("## Stack", "");
|
|
12902
|
+
lines.push("The mission map below lists the providers detected in this repo. For a suggestion, run `npx -y viberaven stack recommend`.");
|
|
12903
|
+
lines.push("");
|
|
12904
|
+
lines.push("## Summary");
|
|
12905
|
+
lines.push(artifact.summary || "_No summary returned._");
|
|
12906
|
+
lines.push("");
|
|
12907
|
+
lines.push("## Mission map (repo wiring)");
|
|
12908
|
+
lines.push("");
|
|
12909
|
+
lines.push("| Area | Provider | Readiness | Notes |");
|
|
12910
|
+
lines.push("|------|----------|-----------|-------|");
|
|
12911
|
+
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12912
|
+
const missions = inRepoMissions(artifact, area);
|
|
12913
|
+
if (missions.length === 0 && (area.providerMissions ?? []).length > 0) {
|
|
12914
|
+
lines.push(`| ${area.label} | ${NONE_FOUND} | - | - |`);
|
|
12915
|
+
}
|
|
12916
|
+
for (const mission of missions) {
|
|
12917
|
+
const failed = mission.checks.filter(
|
|
12918
|
+
(c) => c.status === "missing" || c.status === "failed" || c.status === "needs-connection"
|
|
12919
|
+
).length;
|
|
12920
|
+
const notes = failed > 0 ? `${failed} open check${failed === 1 ? "" : "s"}` : `${mission.readinessPercent}% repo checks`;
|
|
12921
|
+
lines.push(
|
|
12922
|
+
`| ${area.label} | ${mission.providerLabel} | ${mission.readinessPercent}% | ${notes} |`
|
|
12923
|
+
);
|
|
12924
|
+
}
|
|
12925
|
+
}
|
|
12926
|
+
lines.push("");
|
|
12927
|
+
lines.push("## Agent-code actions");
|
|
12928
|
+
if (topGaps.length === 0) {
|
|
12929
|
+
lines.push("_No model gaps returned. Review mission map checks before changing code._");
|
|
12930
|
+
} else {
|
|
12931
|
+
topGaps.forEach((gap, index) => {
|
|
12932
|
+
lines.push(
|
|
12933
|
+
`${index + 1}. **${gap.title}** (\`${gap.id}\`, ${gap.severity}, map: \`${gap.primaryMapCategory}\`)`
|
|
12629
12934
|
);
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12935
|
+
lines.push(` - ${gap.detail}`);
|
|
12936
|
+
lines.push(` - Command: \`viberaven prompt --gap ${gap.id}\``);
|
|
12937
|
+
if (gap.copyPrompt) {
|
|
12938
|
+
lines.push(` - Prompt: ${gap.copyPrompt}`);
|
|
12939
|
+
}
|
|
12940
|
+
});
|
|
12941
|
+
}
|
|
12942
|
+
const manualChecks = (artifact.missionGraph.areas ?? []).flatMap(
|
|
12943
|
+
(area) => inRepoMissions(artifact, area).flatMap(
|
|
12944
|
+
(mission) => mission.checks.filter(
|
|
12945
|
+
(check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
|
|
12946
|
+
).map((check) => ({ area: area.label, provider: mission.providerLabel, check }))
|
|
12947
|
+
)
|
|
12948
|
+
);
|
|
12949
|
+
lines.push("");
|
|
12950
|
+
lines.push("## Human-provider actions");
|
|
12951
|
+
if (manualChecks.length === 0) {
|
|
12952
|
+
lines.push("_No manual provider actions were identified in this scan._");
|
|
12953
|
+
} else {
|
|
12954
|
+
manualChecks.slice(0, 8).forEach((item4, index) => {
|
|
12955
|
+
lines.push(`${index + 1}. **${item4.check.label}** (${item4.area} / ${item4.provider})`);
|
|
12956
|
+
lines.push(
|
|
12957
|
+
` - ${item4.check.promptHint || "Ask the user to confirm this in the provider dashboard or through read-only MCP."}`
|
|
12958
|
+
);
|
|
12959
|
+
});
|
|
12644
12960
|
}
|
|
12961
|
+
lines.push("");
|
|
12962
|
+
lines.push("Do not claim human-provider actions as repo-code fixes.");
|
|
12963
|
+
lines.push("");
|
|
12964
|
+
lines.push("## Agent workflow");
|
|
12965
|
+
lines.push("1. Read `.viberaven/agent-tasklist.md` first for the production gate.");
|
|
12966
|
+
lines.push("2. Read `.viberaven/launch-playbook.md` for the full checklist.");
|
|
12967
|
+
lines.push("3. Run `viberaven next --json` - one action at a time.");
|
|
12968
|
+
lines.push("4. Repo fix: `viberaven prompt --gap <id>` then implement.");
|
|
12969
|
+
lines.push("5. Provider: `viberaven guide <provider> --step N` and `viberaven open <provider>`.");
|
|
12970
|
+
lines.push(`6. Run \`${PUBLIC_VERIFY_COMMAND}\` to rescan and refresh \`.viberaven/agent-tasklist.md\`.`);
|
|
12971
|
+
lines.push("");
|
|
12645
12972
|
return `${lines.join("\n")}
|
|
12646
12973
|
`;
|
|
12647
12974
|
}
|
|
12648
|
-
var
|
|
12649
|
-
var
|
|
12650
|
-
"src/
|
|
12975
|
+
var SEVERITY_ORDER2;
|
|
12976
|
+
var init_agentSummary = __esm({
|
|
12977
|
+
"src/report/agentSummary.ts"() {
|
|
12651
12978
|
"use strict";
|
|
12652
12979
|
init_commands();
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
"empty_catch",
|
|
12661
|
-
"emptyCatch",
|
|
12662
|
-
// W3 env-add recipes
|
|
12663
|
-
"auth_secret_missing",
|
|
12664
|
-
"node_env_not_set",
|
|
12665
|
-
"database_url_missing",
|
|
12666
|
-
// W3 file-create recipes
|
|
12667
|
-
"missing_error_boundary",
|
|
12668
|
-
"missing_health_route",
|
|
12669
|
-
"missing_loading_state",
|
|
12670
|
-
"missing_404_page",
|
|
12671
|
-
// W3 file-patch recipes
|
|
12672
|
-
"missing_csp_header",
|
|
12673
|
-
"missing_rate_limit",
|
|
12674
|
-
"eslint_restricted_imports"
|
|
12675
|
-
// NOTE: 'rls_disabled' is intentionally NOT here. When the finding comes from repo SQL it is a repo action whose
|
|
12676
|
-
// recipe writes a new migration (see rlsMigrationFile and heal/recipes/supabaseRls.ts); without SQL evidence it
|
|
12677
|
-
// stays a provider action and heal refuses.
|
|
12678
|
-
]);
|
|
12980
|
+
init_resolveNextAction();
|
|
12981
|
+
init_inRepoMissions();
|
|
12982
|
+
SEVERITY_ORDER2 = {
|
|
12983
|
+
critical: 0,
|
|
12984
|
+
warning: 1,
|
|
12985
|
+
info: 2
|
|
12986
|
+
};
|
|
12679
12987
|
}
|
|
12680
12988
|
});
|
|
12681
12989
|
|
|
@@ -12685,12 +12993,21 @@ function generateLaunchPlaybook(artifact) {
|
|
|
12685
12993
|
lines.push("# VibeRaven launch playbook", "");
|
|
12686
12994
|
lines.push(`Generated from scan at ${artifact.scannedAt}. Work top to bottom.`, "");
|
|
12687
12995
|
lines.push("## Repo fixes (agent code)", "");
|
|
12688
|
-
const
|
|
12996
|
+
const sorted = sortGapsByPriority(artifact.gaps);
|
|
12997
|
+
const repoGaps = sorted.filter((gap) => !INFORMATIONAL_GAPS[gap.id]);
|
|
12998
|
+
const informational = sorted.filter((gap) => INFORMATIONAL_GAPS[gap.id]);
|
|
12689
12999
|
if (repoGaps.length === 0) {
|
|
12690
13000
|
lines.push("_No repo-code gaps found._", "");
|
|
12691
13001
|
} else {
|
|
12692
13002
|
for (const gap of repoGaps) {
|
|
12693
|
-
lines.push(`- [ ] ${gap.title}
|
|
13003
|
+
lines.push(`- [ ] ${gap.title}: \`viberaven prompt --gap ${gap.id}\``);
|
|
13004
|
+
}
|
|
13005
|
+
lines.push("");
|
|
13006
|
+
}
|
|
13007
|
+
if (informational.length > 0) {
|
|
13008
|
+
lines.push("## Informational", "");
|
|
13009
|
+
for (const gap of informational) {
|
|
13010
|
+
lines.push(`- ${gap.title} (\`${gap.id}\`): ${INFORMATIONAL_GAPS[gap.id]}`);
|
|
12694
13011
|
}
|
|
12695
13012
|
lines.push("");
|
|
12696
13013
|
}
|
|
@@ -12702,7 +13019,7 @@ function generateLaunchPlaybook(artifact) {
|
|
|
12702
13019
|
for (const item4 of manuals) {
|
|
12703
13020
|
const provider2 = mapCheckToPlaybook(item4.check);
|
|
12704
13021
|
lines.push(
|
|
12705
|
-
`- [ ] ${item4.check.label} (${item4.areaLabel})
|
|
13022
|
+
provider2 ? `- [ ] ${item4.check.label} (${item4.areaLabel}): \`viberaven guide ${provider2} --step 1\`` : `- [ ] ${item4.check.label} (${item4.areaLabel})`
|
|
12706
13023
|
);
|
|
12707
13024
|
}
|
|
12708
13025
|
lines.push("");
|
|
@@ -12723,6 +13040,7 @@ var init_launchPlaybook = __esm({
|
|
|
12723
13040
|
init_manualChecks();
|
|
12724
13041
|
init_menu();
|
|
12725
13042
|
init_commands();
|
|
13043
|
+
init_repoFixes();
|
|
12726
13044
|
}
|
|
12727
13045
|
});
|
|
12728
13046
|
|
|
@@ -13051,25 +13369,25 @@ var init_reportHtml = __esm({
|
|
|
13051
13369
|
function getBundledReportAssetsDir() {
|
|
13052
13370
|
const base = __dirname;
|
|
13053
13371
|
const candidates = [
|
|
13054
|
-
(0,
|
|
13055
|
-
(0,
|
|
13056
|
-
(0,
|
|
13057
|
-
(0,
|
|
13058
|
-
(0,
|
|
13372
|
+
(0, import_node_path13.join)(base, "report"),
|
|
13373
|
+
(0, import_node_path13.join)(base, "..", "assets", "report"),
|
|
13374
|
+
(0, import_node_path13.join)(base, "..", "..", "assets", "report"),
|
|
13375
|
+
(0, import_node_path13.join)(process.cwd(), "packages", "cli", "assets", "report"),
|
|
13376
|
+
(0, import_node_path13.join)(process.cwd(), "assets", "report")
|
|
13059
13377
|
];
|
|
13060
13378
|
for (const dir of candidates) {
|
|
13061
|
-
if ((0,
|
|
13379
|
+
if ((0, import_node_fs8.existsSync)((0, import_node_path13.join)(dir, "station.css"))) {
|
|
13062
13380
|
return dir;
|
|
13063
13381
|
}
|
|
13064
13382
|
}
|
|
13065
13383
|
throw new Error("Report assets missing. Run `npm run sync-report-assets` and `npm run build` in packages/cli.");
|
|
13066
13384
|
}
|
|
13067
|
-
var
|
|
13385
|
+
var import_node_fs8, import_node_path13, REPORT_ASSET_FILES;
|
|
13068
13386
|
var init_reportAssets = __esm({
|
|
13069
13387
|
"src/report/reportAssets.ts"() {
|
|
13070
13388
|
"use strict";
|
|
13071
|
-
|
|
13072
|
-
|
|
13389
|
+
import_node_fs8 = require("node:fs");
|
|
13390
|
+
import_node_path13 = require("node:path");
|
|
13073
13391
|
REPORT_ASSET_FILES = [
|
|
13074
13392
|
"station.css",
|
|
13075
13393
|
"station.js",
|
|
@@ -13257,9 +13575,10 @@ function deriveRepoCodeAction(task) {
|
|
|
13257
13575
|
gapId: task.gapId,
|
|
13258
13576
|
readiness: [...askFirst ? [askFirst] : [], task.exactFix ?? "Repo-code fix is available"],
|
|
13259
13577
|
target: task.file ? { type: "file", label: "Repo target", path: displayFile } : { type: "command", label: "Apply repo fix", command: task.mcpTool ?? `${PUBLIC_COMMAND} prompt --gap ${task.gapId}` },
|
|
13260
|
-
fileTargets: task.file ? [{ path: displayFile, reason: task.exactFix }] : void 0,
|
|
13578
|
+
fileTargets: task.file ? [{ path: displayFile, ...task.line !== void 0 ? { line: task.line } : {}, reason: task.exactFix }] : void 0,
|
|
13261
13579
|
verifyCommand: verifyActionCommand("pending"),
|
|
13262
|
-
resumeInstruction: `${task.title} is complete. Continue VibeRaven from pending
|
|
13580
|
+
resumeInstruction: `${task.title} is complete. Continue VibeRaven from pending.${task.userSteps?.length ? ` Then tell the user what is left outside the repo: ${task.userSteps.join(" ")}` : ""}`,
|
|
13581
|
+
...task.userSteps?.length ? { userSteps: [...task.userSteps] } : {},
|
|
13263
13582
|
mcpTool: task.mcpTool,
|
|
13264
13583
|
mcpArgs: task.mcpArgs,
|
|
13265
13584
|
// Only a gap with an automatic recipe has a heal-apply fallback, and a task that needs the user's yes keeps it
|
|
@@ -13268,7 +13587,7 @@ function deriveRepoCodeAction(task) {
|
|
|
13268
13587
|
...task.requiresUserAction ? { requiresUserAction: true } : {}
|
|
13269
13588
|
};
|
|
13270
13589
|
}
|
|
13271
|
-
function deriveVerifyAction() {
|
|
13590
|
+
function deriveVerifyAction(waiting) {
|
|
13272
13591
|
return {
|
|
13273
13592
|
id: "pending",
|
|
13274
13593
|
actionKey: buildActionKey({
|
|
@@ -13280,8 +13599,9 @@ function deriveVerifyAction() {
|
|
|
13280
13599
|
revision: 1,
|
|
13281
13600
|
kind: "verify",
|
|
13282
13601
|
title: "Run Final Verification",
|
|
13283
|
-
|
|
13284
|
-
|
|
13602
|
+
// Blocked only while repo-code or provider actions come first; with none left it is the next step.
|
|
13603
|
+
status: waiting ? "blocked" : "active",
|
|
13604
|
+
readiness: [waiting ? "Run after provider and repo-code actions are complete" : "No repo-code or provider actions left in this scan"],
|
|
13285
13605
|
target: { type: "command", label: "Final strict gate", command: `${PUBLIC_COMMAND} --strict` },
|
|
13286
13606
|
verifyCommand: `${PUBLIC_COMMAND} --strict`,
|
|
13287
13607
|
resumeInstruction: "Final verification finished. Continue VibeRaven from pending."
|
|
@@ -13289,7 +13609,7 @@ function deriveVerifyAction() {
|
|
|
13289
13609
|
}
|
|
13290
13610
|
function deriveCurrentActions(input) {
|
|
13291
13611
|
const primaryActions = input.tasks.filter((task) => task.fixType === "provider-action" || task.fixType === "repo-code").map((task) => task.fixType === "provider-action" ? deriveProviderAction(task) : deriveRepoCodeAction(task));
|
|
13292
|
-
return [...primaryActions, deriveVerifyAction()];
|
|
13612
|
+
return [...primaryActions, deriveVerifyAction(primaryActions.length > 0)];
|
|
13293
13613
|
}
|
|
13294
13614
|
var init_derive = __esm({
|
|
13295
13615
|
"src/actions/derive.ts"() {
|
|
@@ -13304,7 +13624,7 @@ function emptyActionRegistry() {
|
|
|
13304
13624
|
return { version: 1, nextId: 1, actions: {} };
|
|
13305
13625
|
}
|
|
13306
13626
|
function actionRegistryPath(cwd) {
|
|
13307
|
-
return (0,
|
|
13627
|
+
return (0, import_node_path14.join)(getProjectArtifactsDir(cwd), "action-registry.json");
|
|
13308
13628
|
}
|
|
13309
13629
|
async function loadActionRegistry(cwd) {
|
|
13310
13630
|
try {
|
|
@@ -13376,7 +13696,8 @@ async function assignActionIds(input) {
|
|
|
13376
13696
|
title: action.title,
|
|
13377
13697
|
gapId: action.gapId,
|
|
13378
13698
|
kind: action.kind,
|
|
13379
|
-
provider: action.provider
|
|
13699
|
+
provider: action.provider,
|
|
13700
|
+
...action.userSteps?.length ? { userSteps: [...action.userSteps] } : {}
|
|
13380
13701
|
};
|
|
13381
13702
|
} else {
|
|
13382
13703
|
entry.status = "active";
|
|
@@ -13385,6 +13706,9 @@ async function assignActionIds(input) {
|
|
|
13385
13706
|
entry.gapId = action.gapId;
|
|
13386
13707
|
entry.kind = action.kind;
|
|
13387
13708
|
entry.provider = action.provider;
|
|
13709
|
+
if (action.userSteps?.length) entry.userSteps = [...action.userSteps];
|
|
13710
|
+
else delete entry.userSteps;
|
|
13711
|
+
delete entry.followUpShownAt;
|
|
13388
13712
|
if (entry.fingerprint !== fingerprint) {
|
|
13389
13713
|
entry.revision += 1;
|
|
13390
13714
|
entry.fingerprint = fingerprint;
|
|
@@ -13408,16 +13732,27 @@ async function assignActionIds(input) {
|
|
|
13408
13732
|
await saveActionRegistry(input.cwd, registry);
|
|
13409
13733
|
return { actions, registry };
|
|
13410
13734
|
}
|
|
13735
|
+
function pendingUserFollowUps(registry) {
|
|
13736
|
+
return Object.values(registry.actions).filter((entry) => entry.status === "resolved" && entry.userSteps?.length && !entry.followUpShownAt).map((entry) => ({ id: entry.id, gapId: entry.gapId, title: entry.title, userSteps: [...entry.userSteps ?? []] }));
|
|
13737
|
+
}
|
|
13738
|
+
async function markUserFollowUpsShown(cwd, ids, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
13739
|
+
if (ids.length === 0) return;
|
|
13740
|
+
const registry = await loadActionRegistry(cwd);
|
|
13741
|
+
for (const entry of Object.values(registry.actions)) {
|
|
13742
|
+
if (ids.includes(entry.id)) entry.followUpShownAt = now;
|
|
13743
|
+
}
|
|
13744
|
+
await saveActionRegistry(cwd, registry);
|
|
13745
|
+
}
|
|
13411
13746
|
async function resolveActionById(cwd, id) {
|
|
13412
13747
|
const registry = await loadActionRegistry(cwd);
|
|
13413
13748
|
return Object.values(registry.actions).find((entry) => entry.id === id);
|
|
13414
13749
|
}
|
|
13415
|
-
var import_promises9,
|
|
13750
|
+
var import_promises9, import_node_path14;
|
|
13416
13751
|
var init_registry2 = __esm({
|
|
13417
13752
|
"src/actions/registry.ts"() {
|
|
13418
13753
|
"use strict";
|
|
13419
13754
|
import_promises9 = require("node:fs/promises");
|
|
13420
|
-
|
|
13755
|
+
import_node_path14 = require("node:path");
|
|
13421
13756
|
init_config();
|
|
13422
13757
|
init_canonical();
|
|
13423
13758
|
}
|
|
@@ -13428,7 +13763,7 @@ function gateStatus2(artifact) {
|
|
|
13428
13763
|
if (!Array.isArray(artifact.gaps)) {
|
|
13429
13764
|
return "unknown";
|
|
13430
13765
|
}
|
|
13431
|
-
return artifact.gaps
|
|
13766
|
+
return gateStatusForGaps(artifact.gaps);
|
|
13432
13767
|
}
|
|
13433
13768
|
async function writeActionArtifacts(input) {
|
|
13434
13769
|
const derived = deriveCurrentActions({
|
|
@@ -13449,7 +13784,9 @@ async function writeActionArtifacts(input) {
|
|
|
13449
13784
|
gateStatus: gateStatus2(input.artifact),
|
|
13450
13785
|
actions: assigned.actions
|
|
13451
13786
|
};
|
|
13452
|
-
const
|
|
13787
|
+
const followUps = pendingUserFollowUps(assigned.registry);
|
|
13788
|
+
if (followUps.length > 0) manifest.userFollowUps = followUps;
|
|
13789
|
+
const actionsPath = (0, import_node_path15.join)(getProjectArtifactsDir(input.cwd), "actions.json");
|
|
13453
13790
|
await (0, import_promises10.writeFile)(actionsPath, `${JSON.stringify(manifest, null, 2)}
|
|
13454
13791
|
`, "utf8");
|
|
13455
13792
|
return {
|
|
@@ -13458,13 +13795,14 @@ async function writeActionArtifacts(input) {
|
|
|
13458
13795
|
manifest
|
|
13459
13796
|
};
|
|
13460
13797
|
}
|
|
13461
|
-
var import_promises10,
|
|
13798
|
+
var import_promises10, import_node_path15;
|
|
13462
13799
|
var init_artifacts = __esm({
|
|
13463
13800
|
"src/actions/artifacts.ts"() {
|
|
13464
13801
|
"use strict";
|
|
13465
13802
|
import_promises10 = require("node:fs/promises");
|
|
13466
|
-
|
|
13803
|
+
import_node_path15 = require("node:path");
|
|
13467
13804
|
init_config();
|
|
13805
|
+
init_gateResult();
|
|
13468
13806
|
init_derive();
|
|
13469
13807
|
init_registry2();
|
|
13470
13808
|
}
|
|
@@ -13473,24 +13811,47 @@ var init_artifacts = __esm({
|
|
|
13473
13811
|
// src/artifacts.ts
|
|
13474
13812
|
async function copyReportAssets(reportAssetsDir) {
|
|
13475
13813
|
const sourceDir = getBundledReportAssetsDir();
|
|
13476
|
-
await (0, import_promises11.mkdir)((0,
|
|
13814
|
+
await (0, import_promises11.mkdir)((0, import_node_path16.join)(reportAssetsDir, "assets"), { recursive: true });
|
|
13477
13815
|
for (const rel of REPORT_ASSET_FILES) {
|
|
13478
|
-
await (0, import_promises11.copyFile)((0,
|
|
13816
|
+
await (0, import_promises11.copyFile)((0, import_node_path16.join)(sourceDir, rel), (0, import_node_path16.join)(reportAssetsDir, rel));
|
|
13817
|
+
}
|
|
13818
|
+
}
|
|
13819
|
+
async function isGapEvidenceFile(path) {
|
|
13820
|
+
try {
|
|
13821
|
+
return JSON.parse(await (0, import_promises11.readFile)(path, "utf8")).$schema === GAP_SCHEMA;
|
|
13822
|
+
} catch {
|
|
13823
|
+
return false;
|
|
13824
|
+
}
|
|
13825
|
+
}
|
|
13826
|
+
async function removeStaleGapFiles(gapsDir, current) {
|
|
13827
|
+
let entries;
|
|
13828
|
+
try {
|
|
13829
|
+
entries = await (0, import_promises11.readdir)(gapsDir, { withFileTypes: true });
|
|
13830
|
+
} catch {
|
|
13831
|
+
return;
|
|
13832
|
+
}
|
|
13833
|
+
for (const entry of entries) {
|
|
13834
|
+
if (!entry.isFile() || !entry.name.endsWith(".json") || current.has(entry.name)) continue;
|
|
13835
|
+
const path = (0, import_node_path16.join)(gapsDir, entry.name);
|
|
13836
|
+
try {
|
|
13837
|
+
if (await isGapEvidenceFile(path)) await (0, import_promises11.rm)(path, { force: true });
|
|
13838
|
+
} catch {
|
|
13839
|
+
}
|
|
13479
13840
|
}
|
|
13480
13841
|
}
|
|
13481
13842
|
async function writeScanArtifacts(options) {
|
|
13482
13843
|
const cwd = options.cwd ?? options.artifact.workspacePath;
|
|
13483
13844
|
const dir = getProjectArtifactsDir(cwd);
|
|
13484
13845
|
await (0, import_promises11.mkdir)(dir, { recursive: true });
|
|
13485
|
-
const jsonPath = (0,
|
|
13486
|
-
const gateResultPath = (0,
|
|
13487
|
-
const contextMapPath = (0,
|
|
13488
|
-
const gapsDir = (0,
|
|
13489
|
-
const tasklistPath = (0,
|
|
13490
|
-
const summaryPath = (0,
|
|
13491
|
-
const playbookPath = (0,
|
|
13492
|
-
const reportPath = (0,
|
|
13493
|
-
const reportAssetsDir = (0,
|
|
13846
|
+
const jsonPath = (0, import_node_path16.join)(dir, "last-scan.json");
|
|
13847
|
+
const gateResultPath = (0, import_node_path16.join)(dir, "gate-result.json");
|
|
13848
|
+
const contextMapPath = (0, import_node_path16.join)(dir, "context-map.json");
|
|
13849
|
+
const gapsDir = (0, import_node_path16.join)(dir, "gaps");
|
|
13850
|
+
const tasklistPath = (0, import_node_path16.join)(dir, "agent-tasklist.md");
|
|
13851
|
+
const summaryPath = (0, import_node_path16.join)(dir, "agent-summary.md");
|
|
13852
|
+
const playbookPath = (0, import_node_path16.join)(dir, "launch-playbook.md");
|
|
13853
|
+
const reportPath = (0, import_node_path16.join)(dir, "report.html");
|
|
13854
|
+
const reportAssetsDir = (0, import_node_path16.join)(dir, "report");
|
|
13494
13855
|
await (0, import_promises11.mkdir)(gapsDir, { recursive: true });
|
|
13495
13856
|
const safe2 = sanitizeArtifactForDisk(options.artifact);
|
|
13496
13857
|
const json = `${JSON.stringify(safe2, null, 2)}
|
|
@@ -13500,26 +13861,27 @@ async function writeScanArtifacts(options) {
|
|
|
13500
13861
|
const html = generateReportHtml(safe2);
|
|
13501
13862
|
const tasks = buildTaskList(safe2);
|
|
13502
13863
|
const tasklist = buildTaskListMarkdown(tasks);
|
|
13503
|
-
const
|
|
13864
|
+
const packageManager = detectPackageManager(options.artifact.workspacePath);
|
|
13865
|
+
const gateResult = `${JSON.stringify(generateGateResult(safe2, { packageManager }), null, 2)}
|
|
13504
13866
|
`;
|
|
13505
|
-
const contextMap = `${JSON.stringify(generateContextMap(safe2), null, 2)}
|
|
13867
|
+
const contextMap = `${JSON.stringify(generateContextMap(safe2, { packageManager }), null, 2)}
|
|
13506
13868
|
`;
|
|
13507
13869
|
const gapEvidenceFiles = generateGapEvidenceFiles(safe2);
|
|
13508
13870
|
await copyReportAssets(reportAssetsDir);
|
|
13509
13871
|
await (0, import_promises11.writeFile)(gateResultPath, gateResult, "utf-8");
|
|
13510
13872
|
await (0, import_promises11.writeFile)(contextMapPath, contextMap, "utf-8");
|
|
13511
13873
|
for (const gap of gapEvidenceFiles) {
|
|
13512
|
-
await (0, import_promises11.writeFile)((0,
|
|
13874
|
+
await (0, import_promises11.writeFile)((0, import_node_path16.join)(dir, "gaps", `${gap.content.id}.json`), `${JSON.stringify(gap.content, null, 2)}
|
|
13513
13875
|
`, "utf-8");
|
|
13514
13876
|
}
|
|
13515
13877
|
await (0, import_promises11.writeFile)(tasklistPath, tasklist, "utf-8");
|
|
13516
13878
|
let architectureMapPath;
|
|
13517
13879
|
if (typeof safe2.architectureMap === "string" && safe2.architectureMap.length > 0) {
|
|
13518
|
-
architectureMapPath = (0,
|
|
13880
|
+
architectureMapPath = (0, import_node_path16.join)(dir, "architecture-map.md");
|
|
13519
13881
|
await (0, import_promises11.writeFile)(architectureMapPath, safe2.architectureMap, "utf-8");
|
|
13520
13882
|
}
|
|
13521
13883
|
if (safe2.architectureData) {
|
|
13522
|
-
await (0, import_promises11.writeFile)((0,
|
|
13884
|
+
await (0, import_promises11.writeFile)((0, import_node_path16.join)(dir, "architecture-map.json"), `${JSON.stringify(safe2.architectureData, null, 2)}
|
|
13523
13885
|
`, "utf-8");
|
|
13524
13886
|
}
|
|
13525
13887
|
await (0, import_promises11.writeFile)(jsonPath, json, "utf-8");
|
|
@@ -13532,6 +13894,7 @@ async function writeScanArtifacts(options) {
|
|
|
13532
13894
|
tasks,
|
|
13533
13895
|
paths: { reportPath, playbookPath }
|
|
13534
13896
|
});
|
|
13897
|
+
await removeStaleGapFiles(gapsDir, new Set(gapEvidenceFiles.map((gap) => `${gap.content.id}.json`)));
|
|
13535
13898
|
return {
|
|
13536
13899
|
dir,
|
|
13537
13900
|
jsonPath,
|
|
@@ -13548,14 +13911,15 @@ async function writeScanArtifacts(options) {
|
|
|
13548
13911
|
...architectureMapPath ? { architectureMapPath } : {}
|
|
13549
13912
|
};
|
|
13550
13913
|
}
|
|
13551
|
-
var import_promises11,
|
|
13914
|
+
var import_promises11, import_node_path16, GAP_SCHEMA;
|
|
13552
13915
|
var init_artifacts2 = __esm({
|
|
13553
13916
|
"src/artifacts.ts"() {
|
|
13554
13917
|
"use strict";
|
|
13555
13918
|
import_promises11 = require("node:fs/promises");
|
|
13556
|
-
|
|
13919
|
+
import_node_path16 = require("node:path");
|
|
13557
13920
|
init_contextMap();
|
|
13558
13921
|
init_gateResult();
|
|
13922
|
+
init_packageManager();
|
|
13559
13923
|
init_gapEvidence();
|
|
13560
13924
|
init_agentSummary();
|
|
13561
13925
|
init_buildTaskList();
|
|
@@ -13565,6 +13929,7 @@ var init_artifacts2 = __esm({
|
|
|
13565
13929
|
init_config();
|
|
13566
13930
|
init_sanitizeArtifact();
|
|
13567
13931
|
init_artifacts();
|
|
13932
|
+
GAP_SCHEMA = "https://viberaven.dev/schemas/gap.schema.json";
|
|
13568
13933
|
}
|
|
13569
13934
|
});
|
|
13570
13935
|
|
|
@@ -13662,12 +14027,12 @@ function createAppWindowOpenCommands(target, platform = process.platform, env =
|
|
|
13662
14027
|
];
|
|
13663
14028
|
if (platform === "win32") {
|
|
13664
14029
|
const candidates = [
|
|
13665
|
-
env.LOCALAPPDATA ? (0,
|
|
13666
|
-
env.PROGRAMFILES ? (0,
|
|
13667
|
-
env["PROGRAMFILES(X86)"] ? (0,
|
|
13668
|
-
env.LOCALAPPDATA ? (0,
|
|
13669
|
-
env.PROGRAMFILES ? (0,
|
|
13670
|
-
env["PROGRAMFILES(X86)"] ? (0,
|
|
14030
|
+
env.LOCALAPPDATA ? (0, import_node_path17.join)(env.LOCALAPPDATA, "Google", "Chrome", "Application", "chrome.exe") : "",
|
|
14031
|
+
env.PROGRAMFILES ? (0, import_node_path17.join)(env.PROGRAMFILES, "Google", "Chrome", "Application", "chrome.exe") : "",
|
|
14032
|
+
env["PROGRAMFILES(X86)"] ? (0, import_node_path17.join)(env["PROGRAMFILES(X86)"], "Google", "Chrome", "Application", "chrome.exe") : "",
|
|
14033
|
+
env.LOCALAPPDATA ? (0, import_node_path17.join)(env.LOCALAPPDATA, "Microsoft", "Edge", "Application", "msedge.exe") : "",
|
|
14034
|
+
env.PROGRAMFILES ? (0, import_node_path17.join)(env.PROGRAMFILES, "Microsoft", "Edge", "Application", "msedge.exe") : "",
|
|
14035
|
+
env["PROGRAMFILES(X86)"] ? (0, import_node_path17.join)(env["PROGRAMFILES(X86)"], "Microsoft", "Edge", "Application", "msedge.exe") : "",
|
|
13671
14036
|
"chrome",
|
|
13672
14037
|
"msedge"
|
|
13673
14038
|
].filter(Boolean);
|
|
@@ -13701,7 +14066,7 @@ async function openWithSystemDefault(target) {
|
|
|
13701
14066
|
});
|
|
13702
14067
|
}
|
|
13703
14068
|
async function spawnDetached(command) {
|
|
13704
|
-
if (/^[A-Za-z]:[\\/]/.test(command.command) && !(0,
|
|
14069
|
+
if (/^[A-Za-z]:[\\/]/.test(command.command) && !(0, import_node_fs9.existsSync)(command.command)) {
|
|
13705
14070
|
throw new Error(`Browser not found: ${command.command}`);
|
|
13706
14071
|
}
|
|
13707
14072
|
await new Promise((resolve10, reject) => {
|
|
@@ -13744,13 +14109,13 @@ async function openUrlInBrowser(url) {
|
|
|
13744
14109
|
}
|
|
13745
14110
|
await openWithSystemDefault(trimmed);
|
|
13746
14111
|
}
|
|
13747
|
-
var import_node_child_process4,
|
|
14112
|
+
var import_node_child_process4, import_node_fs9, import_node_path17;
|
|
13748
14113
|
var init_openBrowser = __esm({
|
|
13749
14114
|
"src/openBrowser.ts"() {
|
|
13750
14115
|
"use strict";
|
|
13751
14116
|
import_node_child_process4 = require("node:child_process");
|
|
13752
|
-
|
|
13753
|
-
|
|
14117
|
+
import_node_fs9 = require("node:fs");
|
|
14118
|
+
import_node_path17 = require("node:path");
|
|
13754
14119
|
}
|
|
13755
14120
|
});
|
|
13756
14121
|
|
|
@@ -13879,46 +14244,6 @@ var require_picocolors = __commonJS({
|
|
|
13879
14244
|
}
|
|
13880
14245
|
});
|
|
13881
14246
|
|
|
13882
|
-
// src/report/missionSelection.ts
|
|
13883
|
-
function normalizeProviderToken2(value) {
|
|
13884
|
-
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "");
|
|
13885
|
-
}
|
|
13886
|
-
function missionMatchesProvider(mission, provider2) {
|
|
13887
|
-
const current = normalizeProviderToken2(provider2);
|
|
13888
|
-
return normalizeProviderToken2(mission.provider || mission.providerLabel || mission.key) === current || normalizeProviderToken2(mission.providerLabel || mission.provider || mission.key) === current;
|
|
13889
|
-
}
|
|
13890
|
-
function missionEvidenceScore(mission) {
|
|
13891
|
-
const repoVerified = mission.checks.filter((check) => check.evidenceClass === "repo-verified" || check.status === "passed").length;
|
|
13892
|
-
const missing = mission.checks.filter(
|
|
13893
|
-
(check) => check.evidenceClass === "missing-repo-fix" || check.status === "missing" || check.status === "failed"
|
|
13894
|
-
).length;
|
|
13895
|
-
return repoVerified * 100 + (mission.readinessPercent ?? 0) - missing;
|
|
13896
|
-
}
|
|
13897
|
-
function preferredMissionForArea(area, selectedProvider) {
|
|
13898
|
-
const missions = area?.providerMissions ?? [];
|
|
13899
|
-
if (missions.length === 0) {
|
|
13900
|
-
return void 0;
|
|
13901
|
-
}
|
|
13902
|
-
const selected = selectedProvider ? missions.find((mission) => missionMatchesProvider(mission, selectedProvider)) : void 0;
|
|
13903
|
-
if (selected) {
|
|
13904
|
-
return selected;
|
|
13905
|
-
}
|
|
13906
|
-
return [...missions].sort((a, b3) => missionEvidenceScore(b3) - missionEvidenceScore(a))[0] ?? missions[0];
|
|
13907
|
-
}
|
|
13908
|
-
function openChecksForMission(mission) {
|
|
13909
|
-
if (!mission) {
|
|
13910
|
-
return 0;
|
|
13911
|
-
}
|
|
13912
|
-
return mission.checks.filter(
|
|
13913
|
-
(check) => check.status === "missing" || check.status === "failed" || check.status === "needs-connection"
|
|
13914
|
-
).length;
|
|
13915
|
-
}
|
|
13916
|
-
var init_missionSelection = __esm({
|
|
13917
|
-
"src/report/missionSelection.ts"() {
|
|
13918
|
-
"use strict";
|
|
13919
|
-
}
|
|
13920
|
-
});
|
|
13921
|
-
|
|
13922
14247
|
// src/statusLabels.ts
|
|
13923
14248
|
function formatAgentStatus(label, message) {
|
|
13924
14249
|
return `${label}: ${message}`;
|
|
@@ -13960,7 +14285,7 @@ function gapTagColor(modelGaps, open2) {
|
|
|
13960
14285
|
}
|
|
13961
14286
|
function manualActionCheckCount(artifact) {
|
|
13962
14287
|
return (artifact.missionGraph.areas ?? []).reduce((areaTotal, area) => {
|
|
13963
|
-
return areaTotal + area.
|
|
14288
|
+
return areaTotal + inRepoMissions(artifact, area).reduce((missionTotal, mission) => {
|
|
13964
14289
|
return missionTotal + mission.checks.filter(
|
|
13965
14290
|
(check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
|
|
13966
14291
|
).length;
|
|
@@ -13981,8 +14306,14 @@ function printScanSummary(artifact, paths) {
|
|
|
13981
14306
|
console.log(import_picocolors.default.dim("\u2514") + import_picocolors.default.dim("\u2500".repeat(width - 2)) + import_picocolors.default.dim("\u2518"));
|
|
13982
14307
|
console.log("");
|
|
13983
14308
|
for (const area of artifact.missionGraph.areas ?? []) {
|
|
13984
|
-
|
|
14309
|
+
if ((area.providerMissions ?? []).length === 0) {
|
|
14310
|
+
continue;
|
|
14311
|
+
}
|
|
14312
|
+
const mission = preferredInRepoMission(artifact, area);
|
|
13985
14313
|
if (!mission) {
|
|
14314
|
+
const modelGaps2 = artifact.gaps.filter((g2) => g2.primaryMapCategory === area.key).length;
|
|
14315
|
+
const tag2 = modelGaps2 > 0 ? import_picocolors.default.red(` GAP ${modelGaps2}`) : "";
|
|
14316
|
+
console.log(` ${import_picocolors.default.dim(area.label.padEnd(18))} ${import_picocolors.default.dim(NONE_FOUND)}${tag2}`);
|
|
13986
14317
|
continue;
|
|
13987
14318
|
}
|
|
13988
14319
|
const open2 = openChecksForMission(mission);
|
|
@@ -14028,6 +14359,7 @@ var init_terminalSummary = __esm({
|
|
|
14028
14359
|
"use strict";
|
|
14029
14360
|
import_picocolors = __toESM(require_picocolors());
|
|
14030
14361
|
init_missionSelection();
|
|
14362
|
+
init_inRepoMissions();
|
|
14031
14363
|
init_statusLabels();
|
|
14032
14364
|
init_resolveNextAction();
|
|
14033
14365
|
}
|
|
@@ -14690,7 +15022,7 @@ var VERSION;
|
|
|
14690
15022
|
var init_version = __esm({
|
|
14691
15023
|
"src/version.ts"() {
|
|
14692
15024
|
"use strict";
|
|
14693
|
-
VERSION = "1.6.
|
|
15025
|
+
VERSION = "1.6.3";
|
|
14694
15026
|
}
|
|
14695
15027
|
});
|
|
14696
15028
|
|
|
@@ -15062,17 +15394,17 @@ async function initCursorRulesPack(options) {
|
|
|
15062
15394
|
const pack = buildCursorRulesPack();
|
|
15063
15395
|
for (const rule of pack) {
|
|
15064
15396
|
const file = `${CURSOR_RULES_DIR}/${rule.filename}`;
|
|
15065
|
-
const path = (0,
|
|
15397
|
+
const path = (0, import_node_path18.join)(options.cwd, file);
|
|
15066
15398
|
const existing = await readExistingFile(path);
|
|
15067
15399
|
const changed = !existing.exists || existing.content !== rule.content;
|
|
15068
15400
|
const action = !existing.exists ? "created" : changed ? "updated" : "unchanged";
|
|
15069
15401
|
if (!options.dryRun && changed) {
|
|
15070
|
-
await (0, import_promises12.mkdir)((0,
|
|
15402
|
+
await (0, import_promises12.mkdir)((0, import_node_path18.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
|
|
15071
15403
|
await (0, import_promises12.writeFile)(path, rule.content, "utf-8");
|
|
15072
15404
|
}
|
|
15073
15405
|
results.push({ target: "cursor", file, path, action });
|
|
15074
15406
|
}
|
|
15075
|
-
const legacyPath = (0,
|
|
15407
|
+
const legacyPath = (0, import_node_path18.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
|
|
15076
15408
|
if (!options.dryRun && await fileExists(legacyPath)) {
|
|
15077
15409
|
await (0, import_promises12.rm)(legacyPath, { force: true });
|
|
15078
15410
|
}
|
|
@@ -15099,12 +15431,12 @@ async function fileExists(path) {
|
|
|
15099
15431
|
function isFileNotFoundError(error) {
|
|
15100
15432
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15101
15433
|
}
|
|
15102
|
-
var import_promises12,
|
|
15434
|
+
var import_promises12, import_node_path18, CURSOR_RULES_DIR, LEGACY_CURSOR_RULE_FILE, DOMAIN_PATH_POINTER;
|
|
15103
15435
|
var init_cursorRulesPack = __esm({
|
|
15104
15436
|
"src/commands/cursorRulesPack.ts"() {
|
|
15105
15437
|
"use strict";
|
|
15106
15438
|
import_promises12 = require("node:fs/promises");
|
|
15107
|
-
|
|
15439
|
+
import_node_path18 = require("node:path");
|
|
15108
15440
|
init_commands();
|
|
15109
15441
|
CURSOR_RULES_DIR = ".cursor/rules";
|
|
15110
15442
|
LEGACY_CURSOR_RULE_FILE = `${CURSOR_RULES_DIR}/viberaven.mdc`;
|
|
@@ -15204,8 +15536,8 @@ var init_agentTargets = __esm({
|
|
|
15204
15536
|
|
|
15205
15537
|
// src/commands/seedPackageJsonScripts.ts
|
|
15206
15538
|
async function seedPackageJsonScripts(options) {
|
|
15207
|
-
const packageJsonPath = (0,
|
|
15208
|
-
if (!(0,
|
|
15539
|
+
const packageJsonPath = (0, import_node_path19.join)(options.cwd, "package.json");
|
|
15540
|
+
if (!(0, import_node_fs10.existsSync)(packageJsonPath)) {
|
|
15209
15541
|
return null;
|
|
15210
15542
|
}
|
|
15211
15543
|
const raw = await (0, import_promises13.readFile)(packageJsonPath, "utf-8");
|
|
@@ -15242,13 +15574,13 @@ async function seedPackageJsonScripts(options) {
|
|
|
15242
15574
|
}
|
|
15243
15575
|
return { action: "updated", added, skipped, changed: true };
|
|
15244
15576
|
}
|
|
15245
|
-
var
|
|
15577
|
+
var import_node_fs10, import_promises13, import_node_path19, VIBERAVEN_PACKAGE_JSON_SCRIPTS;
|
|
15246
15578
|
var init_seedPackageJsonScripts = __esm({
|
|
15247
15579
|
"src/commands/seedPackageJsonScripts.ts"() {
|
|
15248
15580
|
"use strict";
|
|
15249
|
-
|
|
15581
|
+
import_node_fs10 = require("node:fs");
|
|
15250
15582
|
import_promises13 = require("node:fs/promises");
|
|
15251
|
-
|
|
15583
|
+
import_node_path19 = require("node:path");
|
|
15252
15584
|
init_commands();
|
|
15253
15585
|
VIBERAVEN_PACKAGE_JSON_SCRIPTS = {
|
|
15254
15586
|
"viberaven:gate": PUBLIC_AGENT_MODE_COMMAND,
|
|
@@ -15268,12 +15600,12 @@ async function initAgentRules(options) {
|
|
|
15268
15600
|
continue;
|
|
15269
15601
|
}
|
|
15270
15602
|
const file = AGENT_RULE_TARGETS[target].file;
|
|
15271
|
-
const path = (0,
|
|
15603
|
+
const path = (0, import_node_path20.join)(options.cwd, file);
|
|
15272
15604
|
const existing = await readExistingFile2(path);
|
|
15273
15605
|
const injected = injectAgentRulesBlock(existing.content, renderAgentRulesForTarget(target));
|
|
15274
15606
|
const action = !existing.exists ? "created" : injected.changed ? "updated" : "unchanged";
|
|
15275
15607
|
if (!options.dryRun && injected.changed) {
|
|
15276
|
-
await (0, import_promises14.mkdir)((0,
|
|
15608
|
+
await (0, import_promises14.mkdir)((0, import_node_path20.dirname)(path), { recursive: true });
|
|
15277
15609
|
await (0, import_promises14.writeFile)(path, injected.content, "utf-8");
|
|
15278
15610
|
}
|
|
15279
15611
|
results.push({ target, file, path, action });
|
|
@@ -15353,12 +15685,12 @@ async function readExistingFile2(path) {
|
|
|
15353
15685
|
function isFileNotFoundError2(error) {
|
|
15354
15686
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15355
15687
|
}
|
|
15356
|
-
var import_promises14,
|
|
15688
|
+
var import_promises14, import_node_path20;
|
|
15357
15689
|
var init_initRules = __esm({
|
|
15358
15690
|
"src/commands/initRules.ts"() {
|
|
15359
15691
|
"use strict";
|
|
15360
15692
|
import_promises14 = require("node:fs/promises");
|
|
15361
|
-
|
|
15693
|
+
import_node_path20 = require("node:path");
|
|
15362
15694
|
init_agentRulesBlock();
|
|
15363
15695
|
init_agentTargets();
|
|
15364
15696
|
init_cursorRulesPack();
|
|
@@ -15621,7 +15953,7 @@ async function runInteractiveSession(startDir = process.cwd()) {
|
|
|
15621
15953
|
Ie(`${import_picocolors4.default.bold("VibeRaven")} ${import_picocolors4.default.dim(VERSION)}`);
|
|
15622
15954
|
const cwd = await resolveWorkspaceRoot(startDir);
|
|
15623
15955
|
const artifactsAt = await findArtifactsWorkspace(startDir);
|
|
15624
|
-
if (artifactsAt && (0,
|
|
15956
|
+
if (artifactsAt && (0, import_node_path21.resolve)(artifactsAt) !== (0, import_node_path21.resolve)(startDir)) {
|
|
15625
15957
|
M2.message(import_picocolors4.default.dim(`Using scan from: ${artifactsAt}`));
|
|
15626
15958
|
} else {
|
|
15627
15959
|
M2.message(import_picocolors4.default.dim(`Project folder: ${cwd}`));
|
|
@@ -15680,11 +16012,11 @@ async function runInteractiveSession(startDir = process.cwd()) {
|
|
|
15680
16012
|
}
|
|
15681
16013
|
Se(import_picocolors4.default.dim("Run viberaven anytime for the interactive menu."));
|
|
15682
16014
|
}
|
|
15683
|
-
var
|
|
16015
|
+
var import_node_path21, import_picocolors4;
|
|
15684
16016
|
var init_runInteractive = __esm({
|
|
15685
16017
|
"src/tui/runInteractive.ts"() {
|
|
15686
16018
|
"use strict";
|
|
15687
|
-
|
|
16019
|
+
import_node_path21 = require("node:path");
|
|
15688
16020
|
init_dist2();
|
|
15689
16021
|
import_picocolors4 = __toESM(require_picocolors());
|
|
15690
16022
|
init_config();
|
|
@@ -15709,18 +16041,18 @@ var init_runInteractive = __esm({
|
|
|
15709
16041
|
// src/commands/condense.ts
|
|
15710
16042
|
async function runCondenseCommand(options) {
|
|
15711
16043
|
const dir = getProjectArtifactsDir(options.cwd);
|
|
15712
|
-
const artifact = JSON.parse(await (0, import_promises15.readFile)((0,
|
|
15713
|
-
const contextMapPath = (0,
|
|
16044
|
+
const artifact = JSON.parse(await (0, import_promises15.readFile)((0, import_node_path22.join)(dir, "last-scan.json"), "utf8"));
|
|
16045
|
+
const contextMapPath = (0, import_node_path22.join)(dir, "context-map.json");
|
|
15714
16046
|
await (0, import_promises15.writeFile)(contextMapPath, `${JSON.stringify(generateContextMap(artifact), null, 2)}
|
|
15715
16047
|
`, "utf8");
|
|
15716
16048
|
return { contextMapPath };
|
|
15717
16049
|
}
|
|
15718
|
-
var import_promises15,
|
|
16050
|
+
var import_promises15, import_node_path22;
|
|
15719
16051
|
var init_condense = __esm({
|
|
15720
16052
|
"src/commands/condense.ts"() {
|
|
15721
16053
|
"use strict";
|
|
15722
16054
|
import_promises15 = require("node:fs/promises");
|
|
15723
|
-
|
|
16055
|
+
import_node_path22 = require("node:path");
|
|
15724
16056
|
init_config();
|
|
15725
16057
|
init_contextMap();
|
|
15726
16058
|
}
|
|
@@ -15728,9 +16060,9 @@ var init_condense = __esm({
|
|
|
15728
16060
|
|
|
15729
16061
|
// src/heal/pathSafety.ts
|
|
15730
16062
|
function assertSafeHealTarget(cwd, target) {
|
|
15731
|
-
const root = (0,
|
|
15732
|
-
const absolute = (0,
|
|
15733
|
-
const rel = (0,
|
|
16063
|
+
const root = (0, import_node_path23.resolve)(cwd);
|
|
16064
|
+
const absolute = (0, import_node_path23.resolve)(root, target);
|
|
16065
|
+
const rel = (0, import_node_path23.relative)(root, absolute);
|
|
15734
16066
|
if (rel.startsWith("..") || rel === "" || /^[A-Za-z]:/.test(rel)) {
|
|
15735
16067
|
throw new Error("Heal target must stay inside the workspace");
|
|
15736
16068
|
}
|
|
@@ -15740,11 +16072,11 @@ function assertSafeHealTarget(cwd, target) {
|
|
|
15740
16072
|
}
|
|
15741
16073
|
return absolute;
|
|
15742
16074
|
}
|
|
15743
|
-
var
|
|
16075
|
+
var import_node_path23, BLOCKED_SEGMENTS;
|
|
15744
16076
|
var init_pathSafety = __esm({
|
|
15745
16077
|
"src/heal/pathSafety.ts"() {
|
|
15746
16078
|
"use strict";
|
|
15747
|
-
|
|
16079
|
+
import_node_path23 = require("node:path");
|
|
15748
16080
|
BLOCKED_SEGMENTS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", ".viberaven"]);
|
|
15749
16081
|
}
|
|
15750
16082
|
});
|
|
@@ -15770,11 +16102,11 @@ function newHealId(now = /* @__PURE__ */ new Date()) {
|
|
|
15770
16102
|
return `heal_${now.toISOString().replace(/\D/g, "").slice(0, 17)}_${(0, import_node_crypto.randomBytes)(3).toString("hex")}`;
|
|
15771
16103
|
}
|
|
15772
16104
|
async function createHealDir(cwd, makeId = () => newHealId()) {
|
|
15773
|
-
const parent = (0,
|
|
16105
|
+
const parent = (0, import_node_path24.join)(cwd, ".viberaven", "heal");
|
|
15774
16106
|
await (0, import_promises16.mkdir)(parent, { recursive: true });
|
|
15775
16107
|
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
15776
16108
|
const id = makeId();
|
|
15777
|
-
const dir = (0,
|
|
16109
|
+
const dir = (0, import_node_path24.join)(parent, id);
|
|
15778
16110
|
try {
|
|
15779
16111
|
await (0, import_promises16.mkdir)(dir);
|
|
15780
16112
|
return { id, dir };
|
|
@@ -15784,13 +16116,13 @@ async function createHealDir(cwd, makeId = () => newHealId()) {
|
|
|
15784
16116
|
}
|
|
15785
16117
|
throw new Error("Could not create a new heal directory under .viberaven/heal.");
|
|
15786
16118
|
}
|
|
15787
|
-
var import_node_crypto, import_promises16,
|
|
16119
|
+
var import_node_crypto, import_promises16, import_node_path24;
|
|
15788
16120
|
var init_healId = __esm({
|
|
15789
16121
|
"src/heal/healId.ts"() {
|
|
15790
16122
|
"use strict";
|
|
15791
16123
|
import_node_crypto = require("node:crypto");
|
|
15792
16124
|
import_promises16 = require("node:fs/promises");
|
|
15793
|
-
|
|
16125
|
+
import_node_path24 = require("node:path");
|
|
15794
16126
|
}
|
|
15795
16127
|
});
|
|
15796
16128
|
|
|
@@ -16257,7 +16589,7 @@ export const config = {
|
|
|
16257
16589
|
// src/heal/recipes/eslintRestrictedImports.ts
|
|
16258
16590
|
function detectEslintConfigFile(cwd) {
|
|
16259
16591
|
for (const candidate of ESLINT_CONFIG_CANDIDATES) {
|
|
16260
|
-
if ((0,
|
|
16592
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path25.join)(cwd, candidate))) {
|
|
16261
16593
|
return candidate;
|
|
16262
16594
|
}
|
|
16263
16595
|
}
|
|
@@ -16412,12 +16744,12 @@ function applyEslintRestrictedImportsRecipe(source, configFile) {
|
|
|
16412
16744
|
}
|
|
16413
16745
|
return applyLegacyModuleRecipe(source);
|
|
16414
16746
|
}
|
|
16415
|
-
var
|
|
16747
|
+
var import_node_fs11, import_node_path25, VIBERAVEN_ESLINT_MARKER, RESTRICTED_IMPORTS_MESSAGE, RESTRICTED_PATHS, RESTRICTED_PATTERNS, ESLINT_CONFIG_CANDIDATES;
|
|
16416
16748
|
var init_eslintRestrictedImports = __esm({
|
|
16417
16749
|
"src/heal/recipes/eslintRestrictedImports.ts"() {
|
|
16418
16750
|
"use strict";
|
|
16419
|
-
|
|
16420
|
-
|
|
16751
|
+
import_node_fs11 = require("node:fs");
|
|
16752
|
+
import_node_path25 = require("node:path");
|
|
16421
16753
|
init_commands();
|
|
16422
16754
|
VIBERAVEN_ESLINT_MARKER = "VibeRaven heal: eslint_restricted_imports";
|
|
16423
16755
|
RESTRICTED_IMPORTS_MESSAGE = `Restricted import. Run ${PUBLIC_AGENT_MODE_COMMAND} before substituting packages.`;
|
|
@@ -16468,13 +16800,13 @@ function defaultTargetFile(gapId) {
|
|
|
16468
16800
|
return map[gapId];
|
|
16469
16801
|
}
|
|
16470
16802
|
async function readSourceOrEmpty(absolutePath) {
|
|
16471
|
-
if (!(0,
|
|
16803
|
+
if (!(0, import_node_fs12.existsSync)(absolutePath)) return "";
|
|
16472
16804
|
return (0, import_promises17.readFile)(absolutePath, "utf8");
|
|
16473
16805
|
}
|
|
16474
16806
|
async function detectUpstash(cwd) {
|
|
16475
16807
|
try {
|
|
16476
|
-
const pkgPath = (0,
|
|
16477
|
-
if (!(0,
|
|
16808
|
+
const pkgPath = (0, import_node_path26.join)(cwd, "package.json");
|
|
16809
|
+
if (!(0, import_node_fs12.existsSync)(pkgPath)) return false;
|
|
16478
16810
|
const raw = await (0, import_promises17.readFile)(pkgPath, "utf8");
|
|
16479
16811
|
const pkg = JSON.parse(raw);
|
|
16480
16812
|
const deps = {
|
|
@@ -16490,7 +16822,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16490
16822
|
const targetFile = explicitTarget ?? defaultTargetFile(gapId);
|
|
16491
16823
|
if (targetFile === void 0) return null;
|
|
16492
16824
|
if (gapId === "auth_secret_missing" || gapId === "node_env_not_set" || gapId === "database_url_missing") {
|
|
16493
|
-
const absolutePath = (0,
|
|
16825
|
+
const absolutePath = (0, import_node_path26.join)(cwd, targetFile);
|
|
16494
16826
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16495
16827
|
let result;
|
|
16496
16828
|
if (gapId === "auth_secret_missing") result = applyAuthSecretRecipe(source);
|
|
@@ -16504,25 +16836,25 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16504
16836
|
};
|
|
16505
16837
|
}
|
|
16506
16838
|
if (gapId === "missing_error_boundary") {
|
|
16507
|
-
const absolutePath = (0,
|
|
16839
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/error.tsx");
|
|
16508
16840
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16509
16841
|
const result = applyErrorBoundaryRecipe(source);
|
|
16510
16842
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16511
16843
|
}
|
|
16512
16844
|
if (gapId === "missing_health_route") {
|
|
16513
|
-
const absolutePath = (0,
|
|
16845
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/api/health/route.ts");
|
|
16514
16846
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16515
16847
|
const result = applyHealthRouteRecipe(source);
|
|
16516
16848
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16517
16849
|
}
|
|
16518
16850
|
if (gapId === "missing_loading_state") {
|
|
16519
|
-
const absolutePath = (0,
|
|
16851
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/loading.tsx");
|
|
16520
16852
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16521
16853
|
const result = applyLoadingStateRecipe(source);
|
|
16522
16854
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16523
16855
|
}
|
|
16524
16856
|
if (gapId === "missing_404_page") {
|
|
16525
|
-
const absolutePath = (0,
|
|
16857
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/not-found.tsx");
|
|
16526
16858
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16527
16859
|
const result = applyNotFoundRecipe(source);
|
|
16528
16860
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
@@ -16539,10 +16871,10 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16539
16871
|
}
|
|
16540
16872
|
if (gapId === "missing_csp_header") {
|
|
16541
16873
|
let configFile = "next.config.js";
|
|
16542
|
-
let absolutePath = (0,
|
|
16543
|
-
if (!(0,
|
|
16874
|
+
let absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16875
|
+
if (!(0, import_node_fs12.existsSync)(absolutePath)) {
|
|
16544
16876
|
configFile = "next.config.mjs";
|
|
16545
|
-
absolutePath = (0,
|
|
16877
|
+
absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16546
16878
|
}
|
|
16547
16879
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16548
16880
|
const result = applyCspHeaderRecipe(source);
|
|
@@ -16554,7 +16886,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16554
16886
|
}
|
|
16555
16887
|
if (gapId === "missing_rate_limit") {
|
|
16556
16888
|
const hasUpstash = await detectUpstash(cwd);
|
|
16557
|
-
const middlewarePath = (0,
|
|
16889
|
+
const middlewarePath = (0, import_node_path26.join)(cwd, "middleware.ts");
|
|
16558
16890
|
const source = await readSourceOrEmpty(middlewarePath);
|
|
16559
16891
|
const result = applyRateLimitRecipe(source, hasUpstash);
|
|
16560
16892
|
return {
|
|
@@ -16576,7 +16908,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16576
16908
|
recipeName: gapId
|
|
16577
16909
|
};
|
|
16578
16910
|
}
|
|
16579
|
-
const absolutePath = (0,
|
|
16911
|
+
const absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16580
16912
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16581
16913
|
const result = applyEslintRestrictedImportsRecipe(source, configFile);
|
|
16582
16914
|
return {
|
|
@@ -16590,13 +16922,13 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16590
16922
|
}
|
|
16591
16923
|
return null;
|
|
16592
16924
|
}
|
|
16593
|
-
var
|
|
16925
|
+
var import_node_fs12, import_promises17, import_node_path26;
|
|
16594
16926
|
var init_recipes = __esm({
|
|
16595
16927
|
"src/heal/recipes/index.ts"() {
|
|
16596
16928
|
"use strict";
|
|
16597
|
-
|
|
16929
|
+
import_node_fs12 = require("node:fs");
|
|
16598
16930
|
import_promises17 = require("node:fs/promises");
|
|
16599
|
-
|
|
16931
|
+
import_node_path26 = require("node:path");
|
|
16600
16932
|
init_envAuthSecret();
|
|
16601
16933
|
init_envNodeEnv();
|
|
16602
16934
|
init_envDatabaseUrl();
|
|
@@ -16673,16 +17005,16 @@ async function applyHeal(options) {
|
|
|
16673
17005
|
rollback: { available: false, instructions: "Recipe matched but no change was needed (already applied or file already exists)." }
|
|
16674
17006
|
};
|
|
16675
17007
|
}
|
|
16676
|
-
const absoluteTarget = (0,
|
|
17008
|
+
const absoluteTarget = (0, import_node_path27.join)(options.cwd, dispatched.targetFile);
|
|
16677
17009
|
assertSafeHealTarget(options.cwd, dispatched.targetFile);
|
|
16678
|
-
await (0, import_promises18.mkdir)((0,
|
|
17010
|
+
await (0, import_promises18.mkdir)((0, import_node_path27.dirname)(absoluteTarget), { recursive: true });
|
|
16679
17011
|
const created2 = await createHealDir(options.cwd);
|
|
16680
17012
|
id = created2.id;
|
|
16681
17013
|
const healDir2 = created2.dir;
|
|
16682
|
-
await (0, import_promises18.mkdir)((0,
|
|
16683
|
-
const existedBefore = (0,
|
|
17014
|
+
await (0, import_promises18.mkdir)((0, import_node_path27.join)(healDir2, "before"));
|
|
17015
|
+
const existedBefore = (0, import_node_fs13.existsSync)(absoluteTarget);
|
|
16684
17016
|
const beforeContent = existedBefore ? await (0, import_promises18.readFile)(absoluteTarget, "utf8") : "";
|
|
16685
|
-
await (0, import_promises18.writeFile)((0,
|
|
17017
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
|
|
16686
17018
|
await (0, import_promises18.writeFile)(absoluteTarget, dispatched.output, "utf8");
|
|
16687
17019
|
const patch2 = [
|
|
16688
17020
|
`--- ${dispatched.targetFile}`,
|
|
@@ -16693,7 +17025,7 @@ async function applyHeal(options) {
|
|
|
16693
17025
|
dispatched.output,
|
|
16694
17026
|
""
|
|
16695
17027
|
].join("\n");
|
|
16696
|
-
await (0, import_promises18.writeFile)((0,
|
|
17028
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir2, "patch.diff"), patch2, "utf8");
|
|
16697
17029
|
const result2 = {
|
|
16698
17030
|
$schema: "https://viberaven.dev/schemas/heal-result.schema.json",
|
|
16699
17031
|
schemaVersion: "v1",
|
|
@@ -16705,17 +17037,17 @@ async function applyHeal(options) {
|
|
|
16705
17037
|
recipe: dispatched.recipeName,
|
|
16706
17038
|
...dispatched.warnings?.length ? { warnings: dispatched.warnings } : {},
|
|
16707
17039
|
target: dispatched.targetFile,
|
|
16708
|
-
changedFiles: [(0,
|
|
17040
|
+
changedFiles: [(0, import_node_path27.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
|
|
16709
17041
|
artifacts: {
|
|
16710
17042
|
patch: `.viberaven/heal/${id}/patch.diff`,
|
|
16711
17043
|
result: `.viberaven/heal/${id}/result.json`
|
|
16712
17044
|
},
|
|
16713
17045
|
rollback: {
|
|
16714
17046
|
available: true,
|
|
16715
|
-
instructions: rollbackInstructions(id, (0,
|
|
17047
|
+
instructions: rollbackInstructions(id, (0, import_node_path27.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/"), existedBefore)
|
|
16716
17048
|
}
|
|
16717
17049
|
};
|
|
16718
|
-
await (0, import_promises18.writeFile)((0,
|
|
17050
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir2, "result.json"), `${JSON.stringify(result2, null, 2)}
|
|
16719
17051
|
`, "utf8");
|
|
16720
17052
|
return result2;
|
|
16721
17053
|
}
|
|
@@ -16755,8 +17087,8 @@ async function applyHeal(options) {
|
|
|
16755
17087
|
const created = await createHealDir(options.cwd);
|
|
16756
17088
|
id = created.id;
|
|
16757
17089
|
const healDir = created.dir;
|
|
16758
|
-
await (0, import_promises18.mkdir)((0,
|
|
16759
|
-
await (0, import_promises18.writeFile)((0,
|
|
17090
|
+
await (0, import_promises18.mkdir)((0, import_node_path27.join)(healDir, "before"));
|
|
17091
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir, "before", "target.txt"), before, "utf8");
|
|
16760
17092
|
await (0, import_promises18.writeFile)(absolute, recipe.output, "utf8");
|
|
16761
17093
|
const patch = [
|
|
16762
17094
|
`--- ${options.target}`,
|
|
@@ -16767,7 +17099,7 @@ async function applyHeal(options) {
|
|
|
16767
17099
|
recipe.output,
|
|
16768
17100
|
""
|
|
16769
17101
|
].join("\n");
|
|
16770
|
-
await (0, import_promises18.writeFile)((0,
|
|
17102
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir, "patch.diff"), patch, "utf8");
|
|
16771
17103
|
const result = {
|
|
16772
17104
|
$schema: "https://viberaven.dev/schemas/heal-result.schema.json",
|
|
16773
17105
|
schemaVersion: "v1",
|
|
@@ -16778,7 +17110,7 @@ async function applyHeal(options) {
|
|
|
16778
17110
|
gapId: options.gapId,
|
|
16779
17111
|
recipe: "empty-catch-safe-response",
|
|
16780
17112
|
target: options.target,
|
|
16781
|
-
changedFiles: [(0,
|
|
17113
|
+
changedFiles: [(0, import_node_path27.relative)(options.cwd, absolute).replace(/\\/g, "/")],
|
|
16782
17114
|
artifacts: {
|
|
16783
17115
|
patch: `.viberaven/heal/${id}/patch.diff`,
|
|
16784
17116
|
result: `.viberaven/heal/${id}/result.json`
|
|
@@ -16786,20 +17118,20 @@ async function applyHeal(options) {
|
|
|
16786
17118
|
rollback: {
|
|
16787
17119
|
available: true,
|
|
16788
17120
|
// The empty-catch recipe only edits a file that already exists.
|
|
16789
|
-
instructions: rollbackInstructions(id, (0,
|
|
17121
|
+
instructions: rollbackInstructions(id, (0, import_node_path27.relative)(options.cwd, absolute).replace(/\\/g, "/"), true)
|
|
16790
17122
|
}
|
|
16791
17123
|
};
|
|
16792
|
-
await (0, import_promises18.writeFile)((0,
|
|
17124
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir, "result.json"), `${JSON.stringify(result, null, 2)}
|
|
16793
17125
|
`, "utf8");
|
|
16794
17126
|
return result;
|
|
16795
17127
|
}
|
|
16796
|
-
var import_promises18,
|
|
17128
|
+
var import_promises18, import_node_fs13, import_node_path27;
|
|
16797
17129
|
var init_apply = __esm({
|
|
16798
17130
|
"src/heal/apply.ts"() {
|
|
16799
17131
|
"use strict";
|
|
16800
17132
|
import_promises18 = require("node:fs/promises");
|
|
16801
|
-
|
|
16802
|
-
|
|
17133
|
+
import_node_fs13 = require("node:fs");
|
|
17134
|
+
import_node_path27 = require("node:path");
|
|
16803
17135
|
init_pathSafety();
|
|
16804
17136
|
init_emptyCatch();
|
|
16805
17137
|
init_healId();
|
|
@@ -16809,7 +17141,7 @@ var init_apply = __esm({
|
|
|
16809
17141
|
|
|
16810
17142
|
// src/heal/plan.ts
|
|
16811
17143
|
async function writeHealPlan(options) {
|
|
16812
|
-
const dir = (0,
|
|
17144
|
+
const dir = (0, import_node_path28.join)(options.cwd, ".viberaven");
|
|
16813
17145
|
await (0, import_promises19.mkdir)(dir, { recursive: true });
|
|
16814
17146
|
const id = newHealId();
|
|
16815
17147
|
const target = options.target ?? `gap:${options.gapId}`;
|
|
@@ -16862,18 +17194,18 @@ async function writeHealPlan(options) {
|
|
|
16862
17194
|
artifacts: { plan: ".viberaven/heal-plan.md" },
|
|
16863
17195
|
rollback: { available: false, instructions: "No source files were changed." }
|
|
16864
17196
|
};
|
|
16865
|
-
await (0, import_promises19.writeFile)((0,
|
|
16866
|
-
await (0, import_promises19.writeFile)((0,
|
|
17197
|
+
await (0, import_promises19.writeFile)((0, import_node_path28.join)(dir, "heal-plan.md"), markdown, "utf8");
|
|
17198
|
+
await (0, import_promises19.writeFile)((0, import_node_path28.join)(dir, "heal-plan.json"), `${JSON.stringify(result, null, 2)}
|
|
16867
17199
|
`, "utf8");
|
|
16868
17200
|
return result;
|
|
16869
17201
|
}
|
|
16870
|
-
var import_promises19,
|
|
17202
|
+
var import_promises19, import_node_path28;
|
|
16871
17203
|
var init_plan = __esm({
|
|
16872
17204
|
"src/heal/plan.ts"() {
|
|
16873
17205
|
"use strict";
|
|
16874
17206
|
import_promises19 = require("node:fs/promises");
|
|
16875
17207
|
init_healId();
|
|
16876
|
-
|
|
17208
|
+
import_node_path28 = require("node:path");
|
|
16877
17209
|
init_commands();
|
|
16878
17210
|
init_supabaseRls2();
|
|
16879
17211
|
}
|
|
@@ -16881,7 +17213,7 @@ var init_plan = __esm({
|
|
|
16881
17213
|
|
|
16882
17214
|
// src/heal/prompt.ts
|
|
16883
17215
|
async function writeHealPrompt(options) {
|
|
16884
|
-
const dir = (0,
|
|
17216
|
+
const dir = (0, import_node_path29.join)(options.cwd, ".viberaven");
|
|
16885
17217
|
await (0, import_promises20.mkdir)(dir, { recursive: true });
|
|
16886
17218
|
const id = newHealId();
|
|
16887
17219
|
const target = options.target ?? `gap:${options.gapId}`;
|
|
@@ -16909,16 +17241,16 @@ async function writeHealPrompt(options) {
|
|
|
16909
17241
|
artifacts: { prompt: ".viberaven/heal-prompt.md" },
|
|
16910
17242
|
rollback: { available: false, instructions: "No source files were changed." }
|
|
16911
17243
|
};
|
|
16912
|
-
await (0, import_promises20.writeFile)((0,
|
|
17244
|
+
await (0, import_promises20.writeFile)((0, import_node_path29.join)(dir, "heal-prompt.md"), prompt, "utf8");
|
|
16913
17245
|
return result;
|
|
16914
17246
|
}
|
|
16915
|
-
var import_promises20,
|
|
17247
|
+
var import_promises20, import_node_path29;
|
|
16916
17248
|
var init_prompt = __esm({
|
|
16917
17249
|
"src/heal/prompt.ts"() {
|
|
16918
17250
|
"use strict";
|
|
16919
17251
|
import_promises20 = require("node:fs/promises");
|
|
16920
17252
|
init_healId();
|
|
16921
|
-
|
|
17253
|
+
import_node_path29 = require("node:path");
|
|
16922
17254
|
init_commands();
|
|
16923
17255
|
}
|
|
16924
17256
|
});
|
|
@@ -17021,8 +17353,8 @@ var init_heal = __esm({
|
|
|
17021
17353
|
|
|
17022
17354
|
// src/stackRecommend.ts
|
|
17023
17355
|
async function recommendStack(cwd = process.cwd()) {
|
|
17024
|
-
const pkgPath = (0,
|
|
17025
|
-
if (!(0,
|
|
17356
|
+
const pkgPath = (0, import_node_path30.join)(cwd, "package.json");
|
|
17357
|
+
if (!(0, import_node_fs14.existsSync)(pkgPath)) {
|
|
17026
17358
|
return DEFAULT_STACK;
|
|
17027
17359
|
}
|
|
17028
17360
|
const pkg = JSON.parse(await (0, import_promises22.readFile)(pkgPath, "utf-8"));
|
|
@@ -17053,13 +17385,13 @@ async function recommendStack(cwd = process.cwd()) {
|
|
|
17053
17385
|
}
|
|
17054
17386
|
return rec;
|
|
17055
17387
|
}
|
|
17056
|
-
var import_promises22,
|
|
17388
|
+
var import_promises22, import_node_fs14, import_node_path30, DEFAULT_STACK;
|
|
17057
17389
|
var init_stackRecommend = __esm({
|
|
17058
17390
|
"src/stackRecommend.ts"() {
|
|
17059
17391
|
"use strict";
|
|
17060
17392
|
import_promises22 = require("node:fs/promises");
|
|
17061
|
-
|
|
17062
|
-
|
|
17393
|
+
import_node_fs14 = require("node:fs");
|
|
17394
|
+
import_node_path30 = require("node:path");
|
|
17063
17395
|
DEFAULT_STACK = {
|
|
17064
17396
|
frontend: "react",
|
|
17065
17397
|
ui: "tailwind + shadcn/ui",
|
|
@@ -17202,13 +17534,13 @@ async function readBlobs(cwd, shas) {
|
|
|
17202
17534
|
async function exportCommit(cwd, commit) {
|
|
17203
17535
|
const entries = parseTree(await git(cwd, ["ls-tree", "-r", "-z", "-l", "--full-tree", commit])).filter(wanted);
|
|
17204
17536
|
const blobs = await readBlobs(cwd, [...new Set(entries.map((entry) => entry.sha))]);
|
|
17205
|
-
const root = await (0, import_promises23.mkdtemp)((0,
|
|
17537
|
+
const root = await (0, import_promises23.mkdtemp)((0, import_node_path31.join)((0, import_node_os.tmpdir)(), "viberaven-base-"));
|
|
17206
17538
|
for (const entry of entries) {
|
|
17207
|
-
const target = (0,
|
|
17208
|
-
if (!target.startsWith(root +
|
|
17539
|
+
const target = (0, import_node_path31.resolve)(root, ...entry.path.split("/"));
|
|
17540
|
+
if (!target.startsWith(root + import_node_path31.sep)) continue;
|
|
17209
17541
|
const content = blobs.get(entry.sha);
|
|
17210
17542
|
if (!content) continue;
|
|
17211
|
-
await (0, import_promises23.mkdir)((0,
|
|
17543
|
+
await (0, import_promises23.mkdir)((0, import_node_path31.dirname)(target), { recursive: true });
|
|
17212
17544
|
await (0, import_promises23.writeFile)(target, content);
|
|
17213
17545
|
}
|
|
17214
17546
|
return root;
|
|
@@ -17278,14 +17610,14 @@ function renderCheckMarkdown({ head, change, version, score }) {
|
|
|
17278
17610
|
return `${lines.join("\n")}
|
|
17279
17611
|
`;
|
|
17280
17612
|
}
|
|
17281
|
-
var import_node_child_process6, import_promises23, import_node_os,
|
|
17613
|
+
var import_node_child_process6, import_promises23, import_node_os, import_node_path31, import_node_util4, execFileAsync4, MAX_BLOB_BYTES, SKIP_SEGMENTS, SEVERITY_RANK3, LOCATION_TEXT, SUBJECT, COMMENT_MARKER, DOT;
|
|
17282
17614
|
var init_checkChange = __esm({
|
|
17283
17615
|
"src/commands/checkChange.ts"() {
|
|
17284
17616
|
"use strict";
|
|
17285
17617
|
import_node_child_process6 = require("node:child_process");
|
|
17286
17618
|
import_promises23 = require("node:fs/promises");
|
|
17287
17619
|
import_node_os = require("node:os");
|
|
17288
|
-
|
|
17620
|
+
import_node_path31 = require("node:path");
|
|
17289
17621
|
import_node_util4 = require("node:util");
|
|
17290
17622
|
init_runScan();
|
|
17291
17623
|
init_safeGit();
|
|
@@ -17369,12 +17701,12 @@ async function hasGithubRemote(cwd) {
|
|
|
17369
17701
|
}
|
|
17370
17702
|
}
|
|
17371
17703
|
async function githubWorkflowStatus(cwd) {
|
|
17372
|
-
return { exists: (0,
|
|
17704
|
+
return { exists: (0, import_node_fs15.existsSync)((0, import_node_path32.join)(cwd, WORKFLOW_PATH)), path: DISPLAY_PATH, onGithub: await hasGithubRemote(cwd) };
|
|
17373
17705
|
}
|
|
17374
17706
|
async function writeGithubWorkflow(cwd, options = {}) {
|
|
17375
|
-
const target = (0,
|
|
17376
|
-
if ((0,
|
|
17377
|
-
await (0, import_promises24.mkdir)((0,
|
|
17707
|
+
const target = (0, import_node_path32.join)(cwd, WORKFLOW_PATH);
|
|
17708
|
+
if ((0, import_node_fs15.existsSync)(target) && !options.force) return { written: false, status: await githubWorkflowStatus(cwd) };
|
|
17709
|
+
await (0, import_promises24.mkdir)((0, import_node_path32.dirname)(target), { recursive: true });
|
|
17378
17710
|
await (0, import_promises24.writeFile)(target, renderWorkflow(), "utf8");
|
|
17379
17711
|
return { written: true, status: await githubWorkflowStatus(cwd) };
|
|
17380
17712
|
}
|
|
@@ -17399,20 +17731,20 @@ async function runInitGithubCommand(options) {
|
|
|
17399
17731
|
if (!status.onGithub) console.log("This repository has no github.com remote yet: the workflow runs once it is pushed to GitHub.");
|
|
17400
17732
|
return 0;
|
|
17401
17733
|
}
|
|
17402
|
-
var import_node_child_process7,
|
|
17734
|
+
var import_node_child_process7, import_node_fs15, import_promises24, import_node_path32, import_node_util5, execFileAsync5, WORKFLOW_PATH, DISPLAY_PATH;
|
|
17403
17735
|
var init_initGithub = __esm({
|
|
17404
17736
|
"src/commands/initGithub.ts"() {
|
|
17405
17737
|
"use strict";
|
|
17406
17738
|
import_node_child_process7 = require("node:child_process");
|
|
17407
|
-
|
|
17739
|
+
import_node_fs15 = require("node:fs");
|
|
17408
17740
|
import_promises24 = require("node:fs/promises");
|
|
17409
|
-
|
|
17741
|
+
import_node_path32 = require("node:path");
|
|
17410
17742
|
import_node_util5 = require("node:util");
|
|
17411
17743
|
init_safeGit();
|
|
17412
17744
|
init_version();
|
|
17413
17745
|
init_checkChange();
|
|
17414
17746
|
execFileAsync5 = (0, import_node_util5.promisify)(import_node_child_process7.execFile);
|
|
17415
|
-
WORKFLOW_PATH = (0,
|
|
17747
|
+
WORKFLOW_PATH = (0, import_node_path32.join)(".github", "workflows", "viberaven.yml");
|
|
17416
17748
|
DISPLAY_PATH = ".github/workflows/viberaven.yml";
|
|
17417
17749
|
}
|
|
17418
17750
|
});
|
|
@@ -17436,7 +17768,7 @@ function managedBlocks(content) {
|
|
|
17436
17768
|
async function checkAgentInjection(cwd) {
|
|
17437
17769
|
const checks = [];
|
|
17438
17770
|
for (const item4 of REQUIRED_EXISTENCE_CHECKS) {
|
|
17439
|
-
const exists = await fileExists2((0,
|
|
17771
|
+
const exists = await fileExists2((0, import_node_path33.join)(cwd, item4.file));
|
|
17440
17772
|
checks.push({
|
|
17441
17773
|
id: item4.id,
|
|
17442
17774
|
status: exists ? "pass" : "fail",
|
|
@@ -17444,17 +17776,17 @@ async function checkAgentInjection(cwd) {
|
|
|
17444
17776
|
});
|
|
17445
17777
|
}
|
|
17446
17778
|
for (const item4 of OPTIONAL_CURSOR_PACK_CHECKS) {
|
|
17447
|
-
const exists = await fileExists2((0,
|
|
17779
|
+
const exists = await fileExists2((0, import_node_path33.join)(cwd, item4.file));
|
|
17448
17780
|
checks.push({
|
|
17449
17781
|
id: item4.id,
|
|
17450
17782
|
status: exists ? "pass" : "fail",
|
|
17451
17783
|
message: exists ? `${item4.file} exists` : `Missing ${item4.file} \u2014 run npx -y viberaven init --agents all`
|
|
17452
17784
|
});
|
|
17453
17785
|
}
|
|
17454
|
-
const legacyCursorPath = (0,
|
|
17786
|
+
const legacyCursorPath = (0, import_node_path33.join)(cwd, ".cursor/rules/viberaven.mdc");
|
|
17455
17787
|
if (await fileExists2(legacyCursorPath)) {
|
|
17456
17788
|
const legacyContent = await (0, import_promises25.readFile)(legacyCursorPath, "utf-8");
|
|
17457
|
-
const hasCoreSplit = await fileExists2((0,
|
|
17789
|
+
const hasCoreSplit = await fileExists2((0, import_node_path33.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
|
|
17458
17790
|
if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
|
|
17459
17791
|
checks.push({
|
|
17460
17792
|
id: "cursor-legacy-mdc",
|
|
@@ -17465,7 +17797,7 @@ async function checkAgentInjection(cwd) {
|
|
|
17465
17797
|
}
|
|
17466
17798
|
for (const target of CORE_AGENT_INJECTION_TARGETS) {
|
|
17467
17799
|
const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
|
|
17468
|
-
const path = (0,
|
|
17800
|
+
const path = (0, import_node_path33.join)(cwd, file);
|
|
17469
17801
|
const exists = await fileExists2(path);
|
|
17470
17802
|
if (!exists) {
|
|
17471
17803
|
checks.push({
|
|
@@ -17524,12 +17856,12 @@ async function fileExists2(path) {
|
|
|
17524
17856
|
return false;
|
|
17525
17857
|
}
|
|
17526
17858
|
}
|
|
17527
|
-
var import_promises25,
|
|
17859
|
+
var import_promises25, import_node_path33, REQUIRED_EXISTENCE_CHECKS, OPTIONAL_CURSOR_PACK_CHECKS, STALE_PATTERNS, GATE_RULE_PHRASES_1_5_2;
|
|
17528
17860
|
var init_doctorAgents = __esm({
|
|
17529
17861
|
"src/commands/doctorAgents.ts"() {
|
|
17530
17862
|
"use strict";
|
|
17531
17863
|
import_promises25 = require("node:fs/promises");
|
|
17532
|
-
|
|
17864
|
+
import_node_path33 = require("node:path");
|
|
17533
17865
|
init_commands();
|
|
17534
17866
|
init_agentTargets();
|
|
17535
17867
|
REQUIRED_EXISTENCE_CHECKS = [
|
|
@@ -17800,7 +18132,7 @@ function buildContextCleanupPlan(input) {
|
|
|
17800
18132
|
const items = [];
|
|
17801
18133
|
const seen = /* @__PURE__ */ new Set();
|
|
17802
18134
|
for (const file of input.files) {
|
|
17803
|
-
const path = normalizePath5((0,
|
|
18135
|
+
const path = normalizePath5((0, import_node_path34.relative)(input.projectRoot, file.path) || file.path);
|
|
17804
18136
|
const fullPath = normalizePath5(file.path);
|
|
17805
18137
|
const category = categorizeCleanupFile(path, fullPath, file);
|
|
17806
18138
|
if (!category || seen.has(path)) {
|
|
@@ -17826,8 +18158,8 @@ async function collectCleanupFiles(projectRoot) {
|
|
|
17826
18158
|
return files;
|
|
17827
18159
|
}
|
|
17828
18160
|
async function writeCleanupPlan(projectRoot, plan) {
|
|
17829
|
-
const outputDir = (0,
|
|
17830
|
-
const outputPath = (0,
|
|
18161
|
+
const outputDir = (0, import_node_path34.join)(projectRoot, ".viberaven");
|
|
18162
|
+
const outputPath = (0, import_node_path34.join)(outputDir, "context-cleanup.md");
|
|
17831
18163
|
await (0, import_promises26.mkdir)(outputDir, { recursive: true });
|
|
17832
18164
|
await (0, import_promises26.writeFile)(outputPath, renderCleanupPlan(plan), "utf8");
|
|
17833
18165
|
return outputPath;
|
|
@@ -17885,9 +18217,9 @@ async function walkCleanupFiles(root, dir, result, depth) {
|
|
|
17885
18217
|
if (SKIP_DIRECTORIES.has(entry.name)) {
|
|
17886
18218
|
continue;
|
|
17887
18219
|
}
|
|
17888
|
-
const absolute = (0,
|
|
18220
|
+
const absolute = (0, import_node_path34.join)(dir, entry.name);
|
|
17889
18221
|
if (entry.isDirectory()) {
|
|
17890
|
-
if (isCachePath(normalizePath5((0,
|
|
18222
|
+
if (isCachePath(normalizePath5((0, import_node_path34.relative)(root, absolute)))) {
|
|
17891
18223
|
result.push({ path: absolute, sizeBytes: 0, kind: "directory" });
|
|
17892
18224
|
continue;
|
|
17893
18225
|
}
|
|
@@ -17908,12 +18240,12 @@ async function walkCleanupFiles(root, dir, result, depth) {
|
|
|
17908
18240
|
function normalizePath5(path) {
|
|
17909
18241
|
return path.replace(/\\/g, "/");
|
|
17910
18242
|
}
|
|
17911
|
-
var import_promises26,
|
|
18243
|
+
var import_promises26, import_node_path34, MAX_WALK_DEPTH, LARGE_LOG_BYTES, SKIP_DIRECTORIES;
|
|
17912
18244
|
var init_cleanPlan = __esm({
|
|
17913
18245
|
"src/commands/cleanPlan.ts"() {
|
|
17914
18246
|
"use strict";
|
|
17915
18247
|
import_promises26 = require("node:fs/promises");
|
|
17916
|
-
|
|
18248
|
+
import_node_path34 = require("node:path");
|
|
17917
18249
|
MAX_WALK_DEPTH = 5;
|
|
17918
18250
|
LARGE_LOG_BYTES = 8192;
|
|
17919
18251
|
SKIP_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
@@ -17991,6 +18323,9 @@ function renderVerifyCommand(action) {
|
|
|
17991
18323
|
}
|
|
17992
18324
|
return ["Verify:", "```bash", redact(action.verifyCommand), "```"];
|
|
17993
18325
|
}
|
|
18326
|
+
function renderUserSteps(steps) {
|
|
18327
|
+
return steps?.length ? ["Outside the repo (tell the user):", ...steps.map((step) => `- ${redact(step)}`)] : [];
|
|
18328
|
+
}
|
|
17994
18329
|
function renderAction(action) {
|
|
17995
18330
|
return [
|
|
17996
18331
|
`[${action.id}] ${redact(action.title)}`,
|
|
@@ -17999,6 +18334,7 @@ function renderAction(action) {
|
|
|
17999
18334
|
...renderTarget(action.target),
|
|
18000
18335
|
...renderCopyPayload(action),
|
|
18001
18336
|
...renderVerifyCommand(action),
|
|
18337
|
+
...renderUserSteps(action.userSteps),
|
|
18002
18338
|
action.resumeInstruction ? `Resume: "${redact(action.resumeInstruction)}"` : void 0
|
|
18003
18339
|
].filter((line) => Boolean(line));
|
|
18004
18340
|
}
|
|
@@ -18014,6 +18350,9 @@ function renderActionSurface(manifest, options = {}) {
|
|
|
18014
18350
|
for (const action of visibleActions) {
|
|
18015
18351
|
lines.push(...renderAction(action), "");
|
|
18016
18352
|
}
|
|
18353
|
+
for (const followUp of options.followUps === false ? [] : manifest.userFollowUps ?? []) {
|
|
18354
|
+
lines.push(`[${followUp.id}] ${redact(followUp.title ?? followUp.gapId ?? "Fixed in the repo")}`, "Status: resolved in the repo", ...renderUserSteps(followUp.userSteps), "");
|
|
18355
|
+
}
|
|
18017
18356
|
return `${lines.join("\n").trimEnd()}
|
|
18018
18357
|
`;
|
|
18019
18358
|
}
|
|
@@ -18026,7 +18365,7 @@ var init_render = __esm({
|
|
|
18026
18365
|
|
|
18027
18366
|
// src/commands/actions.ts
|
|
18028
18367
|
async function runActionsCommand(input) {
|
|
18029
|
-
const actionsPath = (0,
|
|
18368
|
+
const actionsPath = (0, import_node_path35.join)(getProjectArtifactsDir(input.cwd), "actions.json");
|
|
18030
18369
|
let raw;
|
|
18031
18370
|
try {
|
|
18032
18371
|
raw = await (0, import_promises27.readFile)(actionsPath, "utf8");
|
|
@@ -18043,12 +18382,12 @@ async function runActionsCommand(input) {
|
|
|
18043
18382
|
process.stdout.write(renderActionSurface(manifest));
|
|
18044
18383
|
return 0;
|
|
18045
18384
|
}
|
|
18046
|
-
var import_promises27,
|
|
18385
|
+
var import_promises27, import_node_path35;
|
|
18047
18386
|
var init_actions = __esm({
|
|
18048
18387
|
"src/commands/actions.ts"() {
|
|
18049
18388
|
"use strict";
|
|
18050
18389
|
import_promises27 = require("node:fs/promises");
|
|
18051
|
-
|
|
18390
|
+
import_node_path35 = require("node:path");
|
|
18052
18391
|
init_render();
|
|
18053
18392
|
init_config();
|
|
18054
18393
|
}
|
|
@@ -18057,7 +18396,7 @@ var init_actions = __esm({
|
|
|
18057
18396
|
// src/commands/verifyAction.ts
|
|
18058
18397
|
async function currentActionExists(cwd, actionId) {
|
|
18059
18398
|
try {
|
|
18060
|
-
const raw = await (0, import_promises28.readFile)((0,
|
|
18399
|
+
const raw = await (0, import_promises28.readFile)((0, import_node_path36.join)(getProjectArtifactsDir(cwd), "actions.json"), "utf8");
|
|
18061
18400
|
const manifest = JSON.parse(raw);
|
|
18062
18401
|
return manifest.actions.some((action) => action.id === actionId);
|
|
18063
18402
|
} catch {
|
|
@@ -18101,12 +18440,12 @@ This only looks the action up. Run \`npx -y viberaven --verify\` to scan the rep
|
|
|
18101
18440
|
);
|
|
18102
18441
|
return 0;
|
|
18103
18442
|
}
|
|
18104
|
-
var import_promises28,
|
|
18443
|
+
var import_promises28, import_node_path36;
|
|
18105
18444
|
var init_verifyAction = __esm({
|
|
18106
18445
|
"src/commands/verifyAction.ts"() {
|
|
18107
18446
|
"use strict";
|
|
18108
18447
|
import_promises28 = require("node:fs/promises");
|
|
18109
|
-
|
|
18448
|
+
import_node_path36 = require("node:path");
|
|
18110
18449
|
init_registry2();
|
|
18111
18450
|
init_config();
|
|
18112
18451
|
}
|
|
@@ -18261,6 +18600,7 @@ ${message}
|
|
|
18261
18600
|
return failing ? 1 : 0;
|
|
18262
18601
|
}
|
|
18263
18602
|
if (options.json) {
|
|
18603
|
+
const userFollowUps = await readUserFollowUps(paths.actionsPath);
|
|
18264
18604
|
console.log(
|
|
18265
18605
|
JSON.stringify(
|
|
18266
18606
|
{
|
|
@@ -18283,6 +18623,8 @@ ${message}
|
|
|
18283
18623
|
unchanged: change.unchanged.map((gap) => gap.id)
|
|
18284
18624
|
}
|
|
18285
18625
|
} : {},
|
|
18626
|
+
// Steps outside the repo for fixes already in it (MCP check and verify read this). Read only.
|
|
18627
|
+
...userFollowUps.length > 0 ? { userFollowUps } : {},
|
|
18286
18628
|
artifacts: paths
|
|
18287
18629
|
},
|
|
18288
18630
|
null,
|
|
@@ -18337,14 +18679,31 @@ ${message}
|
|
|
18337
18679
|
console.log(
|
|
18338
18680
|
critical > 0 ? `Verdict: \u274C ${critical} blocker${critical === 1 ? "" : "s"}, ${warnings} warning${warnings === 1 ? "" : "s"} \xB7 score ${artifact.score}` : `Verdict: \u2705 no blockers, ${warnings} warning${warnings === 1 ? "" : "s"} \xB7 score ${artifact.score}`
|
|
18339
18681
|
);
|
|
18682
|
+
await printUserFollowUps(paths.actionsPath);
|
|
18340
18683
|
console.log(`Fix: viberaven fix \xB7 Details: ${paths.tasklistPath}`);
|
|
18341
18684
|
console.log("");
|
|
18342
18685
|
return critical > 0 ? 1 : 0;
|
|
18343
18686
|
}
|
|
18344
|
-
|
|
18687
|
+
async function readUserFollowUps(actionsPath) {
|
|
18688
|
+
try {
|
|
18689
|
+
return JSON.parse(await (0, import_promises29.readFile)(actionsPath, "utf8")).userFollowUps ?? [];
|
|
18690
|
+
} catch {
|
|
18691
|
+
return [];
|
|
18692
|
+
}
|
|
18693
|
+
}
|
|
18694
|
+
async function printUserFollowUps(actionsPath) {
|
|
18695
|
+
const followUps = await readUserFollowUps(actionsPath);
|
|
18696
|
+
if (followUps.length === 0) return;
|
|
18697
|
+
console.log("Outside the repo, still on you:");
|
|
18698
|
+
for (const followUp of followUps) {
|
|
18699
|
+
for (const step of followUp.userSteps) console.log(` - ${step} (${followUp.gapId ?? followUp.id})`);
|
|
18700
|
+
}
|
|
18701
|
+
}
|
|
18702
|
+
var import_promises29, SEVERITY_ICON, SEVERITY_ORDER3;
|
|
18345
18703
|
var init_check = __esm({
|
|
18346
18704
|
"src/commands/check.ts"() {
|
|
18347
18705
|
"use strict";
|
|
18706
|
+
import_promises29 = require("node:fs/promises");
|
|
18348
18707
|
init_runScan();
|
|
18349
18708
|
init_artifacts2();
|
|
18350
18709
|
init_statusLabels();
|
|
@@ -18793,8 +19152,8 @@ function isSqlError(error) {
|
|
|
18793
19152
|
}
|
|
18794
19153
|
function displayPath(projectDir, path) {
|
|
18795
19154
|
for (const base of [projectDir, process.cwd()]) {
|
|
18796
|
-
const rel = (0,
|
|
18797
|
-
if (rel && !rel.startsWith("..") && !(0,
|
|
19155
|
+
const rel = (0, import_node_path37.relative)(base, path);
|
|
19156
|
+
if (rel && !rel.startsWith("..") && !(0, import_node_path37.isAbsolute)(rel)) return rel.split("\\").join("/");
|
|
18798
19157
|
}
|
|
18799
19158
|
return path;
|
|
18800
19159
|
}
|
|
@@ -19398,26 +19757,26 @@ function verdictFor(summary) {
|
|
|
19398
19757
|
}
|
|
19399
19758
|
async function listMigrations(dir) {
|
|
19400
19759
|
try {
|
|
19401
|
-
const entries = await (0,
|
|
19760
|
+
const entries = await (0, import_promises30.readdir)(dir, { withFileTypes: true });
|
|
19402
19761
|
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);
|
|
19403
19762
|
} catch {
|
|
19404
19763
|
return [];
|
|
19405
19764
|
}
|
|
19406
19765
|
}
|
|
19407
19766
|
async function runRlsTest(options) {
|
|
19408
|
-
const projectDir = (0,
|
|
19409
|
-
const matrixPath = (0,
|
|
19410
|
-
const migrationsDir = (0,
|
|
19767
|
+
const projectDir = (0, import_node_path37.resolve)(options.projectDir);
|
|
19768
|
+
const matrixPath = (0, import_node_path37.resolve)(projectDir, options.matrixPath ?? DEFAULT_MATRIX_FILE);
|
|
19769
|
+
const migrationsDir = (0, import_node_path37.resolve)(projectDir, options.migrationsDir ?? (0, import_node_path37.join)("supabase", "migrations"));
|
|
19411
19770
|
const timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
|
|
19412
|
-
if ((0,
|
|
19413
|
-
throw new RlsInputError(`Refusing to read ${(0,
|
|
19771
|
+
if ((0, import_node_path37.basename)(matrixPath).toLowerCase().startsWith(".env")) {
|
|
19772
|
+
throw new RlsInputError(`Refusing to read ${(0, import_node_path37.basename)(matrixPath)}: rls-test never reads .env files. Point --matrix at a viberaven.permissions.json.`);
|
|
19414
19773
|
}
|
|
19415
19774
|
const filesRead = [];
|
|
19416
19775
|
let matrixText;
|
|
19417
19776
|
try {
|
|
19418
|
-
const info = await (0,
|
|
19777
|
+
const info = await (0, import_promises30.stat)(matrixPath);
|
|
19419
19778
|
if (!info.isFile()) throw new Error("not a file");
|
|
19420
|
-
matrixText = normalise(await (0,
|
|
19779
|
+
matrixText = normalise(await (0, import_promises30.readFile)(matrixPath, "utf8"));
|
|
19421
19780
|
} catch {
|
|
19422
19781
|
throw new RlsInputError(
|
|
19423
19782
|
`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.`
|
|
@@ -19428,8 +19787,8 @@ async function runRlsTest(options) {
|
|
|
19428
19787
|
const names = await listMigrations(migrationsDir);
|
|
19429
19788
|
const migrationFiles = [];
|
|
19430
19789
|
for (const name of names) {
|
|
19431
|
-
const sql = normalise(await (0,
|
|
19432
|
-
filesRead.push(displayPath(projectDir, (0,
|
|
19790
|
+
const sql = normalise(await (0, import_promises30.readFile)((0, import_node_path37.join)(migrationsDir, name), "utf8"));
|
|
19791
|
+
filesRead.push(displayPath(projectDir, (0, import_node_path37.join)(migrationsDir, name)));
|
|
19433
19792
|
migrationFiles.push({ name, sha256: sha256(sql), sql });
|
|
19434
19793
|
}
|
|
19435
19794
|
const migrationsHash = sha256(migrationFiles.map((f) => `${f.name}\0${f.sha256}`).join("\n"));
|
|
@@ -19629,15 +19988,15 @@ async function runTable(db, table2, badRoles, roleChecks) {
|
|
|
19629
19988
|
cells
|
|
19630
19989
|
};
|
|
19631
19990
|
}
|
|
19632
|
-
var import_node_child_process8, import_node_crypto3,
|
|
19991
|
+
var import_node_child_process8, import_node_crypto3, import_promises30, import_node_net, import_node_path37, 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;
|
|
19633
19992
|
var init_rlsRunner = __esm({
|
|
19634
19993
|
"src/rls/rlsRunner.ts"() {
|
|
19635
19994
|
"use strict";
|
|
19636
19995
|
import_node_child_process8 = require("node:child_process");
|
|
19637
19996
|
import_node_crypto3 = require("node:crypto");
|
|
19638
|
-
|
|
19997
|
+
import_promises30 = require("node:fs/promises");
|
|
19639
19998
|
import_node_net = __toESM(require("node:net"));
|
|
19640
|
-
|
|
19999
|
+
import_node_path37 = require("node:path");
|
|
19641
20000
|
import_node_util6 = require("node:util");
|
|
19642
20001
|
init_safeGit();
|
|
19643
20002
|
init_permissionsMatrix();
|
|
@@ -20465,7 +20824,7 @@ function buildMissionCards(artifact, providers) {
|
|
|
20465
20824
|
};
|
|
20466
20825
|
}
|
|
20467
20826
|
function projectNameFromPath(pathValue) {
|
|
20468
|
-
return (0,
|
|
20827
|
+
return (0, import_node_path38.basename)(pathValue.replace(/[\\/]$/, "")) || "current repo";
|
|
20469
20828
|
}
|
|
20470
20829
|
function gapSearchText(gap) {
|
|
20471
20830
|
return [
|
|
@@ -20656,7 +21015,7 @@ function mapProvider(template, artifact, projectName) {
|
|
|
20656
21015
|
const gaps = providerGaps(artifact, template.id);
|
|
20657
21016
|
const primaryGap2 = gaps[0];
|
|
20658
21017
|
const state = providerState(gaps);
|
|
20659
|
-
const launchGateClear = artifact.gaps
|
|
21018
|
+
const launchGateClear = gateStatusForGaps(artifact.gaps) === "clear";
|
|
20660
21019
|
const launchPath = template.items.map((item4, index) => ({
|
|
20661
21020
|
...item4,
|
|
20662
21021
|
state: itemState(primaryGap2, index, item4, launchGateClear),
|
|
@@ -20865,8 +21224,9 @@ function mapArtifactToLocalUiState(artifact, presentProviderIds) {
|
|
|
20865
21224
|
scannedAt: artifact.scannedAt
|
|
20866
21225
|
},
|
|
20867
21226
|
gate: {
|
|
20868
|
-
|
|
20869
|
-
|
|
21227
|
+
// The same rule as gate-result.json, so the Studio never shows a different verdict.
|
|
21228
|
+
status: gateStatusForGaps(artifact.gaps),
|
|
21229
|
+
label: GATE_LABEL[gateStatusForGaps(artifact.gaps)],
|
|
20870
21230
|
score: artifact.score,
|
|
20871
21231
|
productionCorePercent: artifact.productionCorePercent
|
|
20872
21232
|
},
|
|
@@ -20876,25 +21236,31 @@ function mapArtifactToLocalUiState(artifact, presentProviderIds) {
|
|
|
20876
21236
|
selectedProviderId: selectedProvider.id,
|
|
20877
21237
|
currentPrompt: selectedProvider.nextFix?.prompt ?? "",
|
|
20878
21238
|
artifacts: {
|
|
20879
|
-
tasklist: (0,
|
|
20880
|
-
contextMap: (0,
|
|
20881
|
-
gateResult: (0,
|
|
20882
|
-
lastScan: (0,
|
|
21239
|
+
tasklist: (0, import_node_path38.join)(".viberaven", "agent-tasklist.md"),
|
|
21240
|
+
contextMap: (0, import_node_path38.join)(".viberaven", "context-map.json"),
|
|
21241
|
+
gateResult: (0, import_node_path38.join)(".viberaven", "gate-result.json"),
|
|
21242
|
+
lastScan: (0, import_node_path38.join)(".viberaven", "last-scan.json")
|
|
20883
21243
|
},
|
|
20884
21244
|
empty: false
|
|
20885
21245
|
};
|
|
20886
21246
|
}
|
|
20887
|
-
var
|
|
21247
|
+
var import_node_path38, GATE_LABEL, CONNECT_PROVIDER_PRIORITY, providerDashboardUrls, providerHints, PROVIDER_OWNED_GAP;
|
|
20888
21248
|
var init_artifactAdapter = __esm({
|
|
20889
21249
|
"src/local-ui/artifactAdapter.ts"() {
|
|
20890
21250
|
"use strict";
|
|
20891
|
-
|
|
21251
|
+
import_node_path38 = require("node:path");
|
|
20892
21252
|
init_providerLogos();
|
|
20893
21253
|
init_buildTaskList();
|
|
20894
21254
|
init_prompts();
|
|
20895
21255
|
init_providerLaunchPaths();
|
|
20896
21256
|
init_launchRunway();
|
|
20897
21257
|
init_providerGrade();
|
|
21258
|
+
init_gateResult();
|
|
21259
|
+
GATE_LABEL = {
|
|
21260
|
+
clear: "No blockers in repo checks",
|
|
21261
|
+
warning: "Warnings to review",
|
|
21262
|
+
not_clear: "Gate not clear"
|
|
21263
|
+
};
|
|
20898
21264
|
CONNECT_PROVIDER_PRIORITY = ["supabase", "vercel", "stripe"];
|
|
20899
21265
|
providerDashboardUrls = {
|
|
20900
21266
|
supabase: "https://supabase.com/dashboard/projects",
|
|
@@ -21191,18 +21557,18 @@ var init_planLimits = __esm({
|
|
|
21191
21557
|
// src/hosted/credentials.ts
|
|
21192
21558
|
function defaultConfigDir(env = process.env, platform = process.platform) {
|
|
21193
21559
|
const override = env.VIBERAVEN_CONFIG_DIR?.trim();
|
|
21194
|
-
if (override) return (0,
|
|
21560
|
+
if (override) return (0, import_node_path39.resolve)(override);
|
|
21195
21561
|
if (platform === "win32") {
|
|
21196
|
-
return (0,
|
|
21562
|
+
return (0, import_node_path39.join)(env.APPDATA?.trim() || (0, import_node_path39.join)((0, import_node_os2.homedir)(), "AppData", "Roaming"), "viberaven");
|
|
21197
21563
|
}
|
|
21198
21564
|
if (platform === "darwin") {
|
|
21199
|
-
return (0,
|
|
21565
|
+
return (0, import_node_path39.join)((0, import_node_os2.homedir)(), "Library", "Application Support", "viberaven");
|
|
21200
21566
|
}
|
|
21201
|
-
return (0,
|
|
21567
|
+
return (0, import_node_path39.join)(env.XDG_CONFIG_HOME?.trim() || (0, import_node_path39.join)((0, import_node_os2.homedir)(), ".config"), "viberaven");
|
|
21202
21568
|
}
|
|
21203
21569
|
function isInside(child, parent) {
|
|
21204
|
-
const rel = (0,
|
|
21205
|
-
return rel === "" || !rel.startsWith("..") && !(0,
|
|
21570
|
+
const rel = (0, import_node_path39.relative)((0, import_node_path39.resolve)(parent), (0, import_node_path39.resolve)(child));
|
|
21571
|
+
return rel === "" || !rel.startsWith("..") && !(0, import_node_path39.isAbsolute)(rel);
|
|
21206
21572
|
}
|
|
21207
21573
|
async function retryTransient(work) {
|
|
21208
21574
|
for (let attempt = 1; ; attempt += 1) {
|
|
@@ -21215,15 +21581,15 @@ async function retryTransient(work) {
|
|
|
21215
21581
|
}
|
|
21216
21582
|
}
|
|
21217
21583
|
}
|
|
21218
|
-
var import_node_child_process9, import_node_crypto4,
|
|
21584
|
+
var import_node_child_process9, import_node_crypto4, import_promises31, import_node_os2, import_node_path39, CREDENTIALS_FILE_NAME, CredentialLocationError, CredentialPermissionError, restrictWithIcacls, TRANSIENT_FS_CODES, FS_ATTEMPTS, FS_BACKOFF_MS, CredentialStore;
|
|
21219
21585
|
var init_credentials = __esm({
|
|
21220
21586
|
"src/hosted/credentials.ts"() {
|
|
21221
21587
|
"use strict";
|
|
21222
21588
|
import_node_child_process9 = require("node:child_process");
|
|
21223
21589
|
import_node_crypto4 = require("node:crypto");
|
|
21224
|
-
|
|
21590
|
+
import_promises31 = require("node:fs/promises");
|
|
21225
21591
|
import_node_os2 = require("node:os");
|
|
21226
|
-
|
|
21592
|
+
import_node_path39 = require("node:path");
|
|
21227
21593
|
CREDENTIALS_FILE_NAME = "credentials.json";
|
|
21228
21594
|
CredentialLocationError = class extends Error {
|
|
21229
21595
|
};
|
|
@@ -21250,9 +21616,9 @@ var init_credentials = __esm({
|
|
|
21250
21616
|
constructor(configDir, workspacePath, options = {}) {
|
|
21251
21617
|
this.configDir = configDir;
|
|
21252
21618
|
this.workspacePath = workspacePath;
|
|
21253
|
-
this.path = (0,
|
|
21619
|
+
this.path = (0, import_node_path39.join)(configDir, CREDENTIALS_FILE_NAME);
|
|
21254
21620
|
this.restrict = options.restrict !== void 0 ? options.restrict : process.platform === "win32" ? restrictWithIcacls : null;
|
|
21255
|
-
this.fs = { readFile: (path, encoding) => (0,
|
|
21621
|
+
this.fs = { readFile: (path, encoding) => (0, import_promises31.readFile)(path, encoding), rename: (from, to) => (0, import_promises31.rename)(from, to), rm: (path) => (0, import_promises31.rm)(path, { force: true }), ...options.fs };
|
|
21256
21622
|
}
|
|
21257
21623
|
path;
|
|
21258
21624
|
restrict;
|
|
@@ -21301,15 +21667,15 @@ var init_credentials = __esm({
|
|
|
21301
21667
|
`Refusing to store the VibeRaven sign-in inside this project (${this.configDir}). Set VIBERAVEN_CONFIG_DIR to a folder outside the repo.`
|
|
21302
21668
|
);
|
|
21303
21669
|
}
|
|
21304
|
-
await (0,
|
|
21670
|
+
await (0, import_promises31.mkdir)(this.configDir, { recursive: true, mode: 448 });
|
|
21305
21671
|
const temp = `${this.path}.${(0, import_node_crypto4.randomUUID)()}.tmp`;
|
|
21306
|
-
await (0,
|
|
21672
|
+
await (0, import_promises31.writeFile)(temp, `${JSON.stringify(body, null, 2)}
|
|
21307
21673
|
`, { encoding: "utf8", mode: 384 });
|
|
21308
|
-
await (0,
|
|
21674
|
+
await (0, import_promises31.chmod)(temp, 384).catch(() => void 0);
|
|
21309
21675
|
try {
|
|
21310
21676
|
if (this.restrict) await this.restrict(temp);
|
|
21311
21677
|
} catch (error) {
|
|
21312
|
-
await (0,
|
|
21678
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21313
21679
|
const code = error?.code;
|
|
21314
21680
|
const toolMissing = code === "ENOENT";
|
|
21315
21681
|
throw new CredentialPermissionError(
|
|
@@ -21320,17 +21686,17 @@ var init_credentials = __esm({
|
|
|
21320
21686
|
if (guard) {
|
|
21321
21687
|
const onDisk = await this.readFor(guard.apiBaseUrl);
|
|
21322
21688
|
if (onDisk?.accessToken !== guard.accessToken || guard.isCurrent && !guard.isCurrent()) {
|
|
21323
|
-
await (0,
|
|
21689
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21324
21690
|
return false;
|
|
21325
21691
|
}
|
|
21326
21692
|
}
|
|
21327
21693
|
try {
|
|
21328
21694
|
await retryTransient(() => this.fs.rename(temp, this.path));
|
|
21329
21695
|
} catch (error) {
|
|
21330
|
-
await (0,
|
|
21696
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21331
21697
|
throw error;
|
|
21332
21698
|
}
|
|
21333
|
-
await (0,
|
|
21699
|
+
await (0, import_promises31.chmod)(this.path, 384).catch(() => void 0);
|
|
21334
21700
|
return true;
|
|
21335
21701
|
}
|
|
21336
21702
|
/** Keeps the stored plan label in step with what the API last said. */
|
|
@@ -21699,7 +22065,7 @@ async function buildHostedCheckPayload(workspacePath) {
|
|
|
21699
22065
|
throw new Error("Could not assemble the full check request.");
|
|
21700
22066
|
}
|
|
21701
22067
|
function finalizePayload(payload) {
|
|
21702
|
-
const folder = (0,
|
|
22068
|
+
const folder = (0, import_node_path40.basename)(payload.workspacePath.split("\\").join("/").replace(/\/+$/, "")) || "project";
|
|
21703
22069
|
const redacted = redactPayload({ ...payload, workspacePath: folder });
|
|
21704
22070
|
return { payload: redacted.payload, redactions: redacted.count };
|
|
21705
22071
|
}
|
|
@@ -21730,13 +22096,13 @@ function splitSections(prompt) {
|
|
|
21730
22096
|
chars: section.length
|
|
21731
22097
|
}));
|
|
21732
22098
|
}
|
|
21733
|
-
var
|
|
22099
|
+
var import_node_path40, PayloadCaptured;
|
|
21734
22100
|
var init_payload = __esm({
|
|
21735
22101
|
"src/hosted/payload.ts"() {
|
|
21736
22102
|
"use strict";
|
|
21737
22103
|
init_fileScanner();
|
|
21738
22104
|
init_orchestrator();
|
|
21739
|
-
|
|
22105
|
+
import_node_path40 = require("node:path");
|
|
21740
22106
|
init_config();
|
|
21741
22107
|
init_redact();
|
|
21742
22108
|
PayloadCaptured = class extends Error {
|
|
@@ -22202,10 +22568,10 @@ async function connectProviderMcp(cwd, providerId) {
|
|
|
22202
22568
|
if (!recipe) {
|
|
22203
22569
|
return { ok: false, message: `No known MCP server for ${providerId} yet. Add one manually to .mcp.json.` };
|
|
22204
22570
|
}
|
|
22205
|
-
const configPath = (0,
|
|
22571
|
+
const configPath = (0, import_node_path41.join)(cwd, ".mcp.json");
|
|
22206
22572
|
let config = {};
|
|
22207
22573
|
try {
|
|
22208
|
-
const raw = await (0,
|
|
22574
|
+
const raw = await (0, import_promises32.readFile)(configPath, "utf8");
|
|
22209
22575
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
22210
22576
|
if (!isRecord5(parsed) || parsed.mcpServers !== void 0 && !isRecord5(parsed.mcpServers)) {
|
|
22211
22577
|
return { ok: false, message: "Existing .mcp.json has an unsupported structure. It was left unchanged." };
|
|
@@ -22222,7 +22588,7 @@ async function connectProviderMcp(cwd, providerId) {
|
|
|
22222
22588
|
}
|
|
22223
22589
|
servers[providerId] = recipe.entry;
|
|
22224
22590
|
const next = { ...config, mcpServers: servers };
|
|
22225
|
-
await (0,
|
|
22591
|
+
await (0, import_promises32.writeFile)(configPath, `${JSON.stringify(next, null, 2)}
|
|
22226
22592
|
`, "utf8");
|
|
22227
22593
|
const suffix = recipe.note ? ` ${recipe.note}` : "";
|
|
22228
22594
|
return { ok: true, message: `Added ${providerId} MCP server to .mcp.json.${suffix}`, path: ".mcp.json" };
|
|
@@ -22275,7 +22641,7 @@ async function defaultScanRunner(flags, positional) {
|
|
|
22275
22641
|
}
|
|
22276
22642
|
async function readPackageJson(cwd) {
|
|
22277
22643
|
try {
|
|
22278
|
-
const raw = await (0,
|
|
22644
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, "package.json"), "utf8");
|
|
22279
22645
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
22280
22646
|
return isRecord5(parsed) ? parsed : {};
|
|
22281
22647
|
} catch {
|
|
@@ -22298,7 +22664,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
|
|
|
22298
22664
|
if (files.length >= maxFiles) return;
|
|
22299
22665
|
let entries;
|
|
22300
22666
|
try {
|
|
22301
|
-
entries = await (0,
|
|
22667
|
+
entries = await (0, import_promises32.readdir)(dir, { withFileTypes: true });
|
|
22302
22668
|
} catch {
|
|
22303
22669
|
return;
|
|
22304
22670
|
}
|
|
@@ -22306,7 +22672,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
|
|
|
22306
22672
|
if (files.length >= maxFiles) return;
|
|
22307
22673
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
22308
22674
|
if (entry.isDirectory()) {
|
|
22309
|
-
if (!skipped.has(entry.name)) await walk((0,
|
|
22675
|
+
if (!skipped.has(entry.name)) await walk((0, import_node_path41.join)(dir, entry.name), rel);
|
|
22310
22676
|
continue;
|
|
22311
22677
|
}
|
|
22312
22678
|
if (entry.isFile()) files.push(rel.toLowerCase());
|
|
@@ -22325,7 +22691,7 @@ async function readEnvKeys(cwd) {
|
|
|
22325
22691
|
const keys = /* @__PURE__ */ new Set();
|
|
22326
22692
|
for (const name of [".env.example", ".env"]) {
|
|
22327
22693
|
try {
|
|
22328
|
-
const raw = await (0,
|
|
22694
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, name), "utf8");
|
|
22329
22695
|
for (const line of raw.split(/\r?\n/)) {
|
|
22330
22696
|
const trimmed = line.trim();
|
|
22331
22697
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -22643,7 +23009,7 @@ async function codexModelOptions() {
|
|
|
22643
23009
|
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }
|
|
22644
23010
|
];
|
|
22645
23011
|
try {
|
|
22646
|
-
const raw = await (0,
|
|
23012
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)((0, import_node_os3.homedir)(), ".codex", "models_cache.json"), "utf8");
|
|
22647
23013
|
const parsed = JSON.parse(raw);
|
|
22648
23014
|
const list = Array.isArray(parsed) ? parsed : parsed.models ?? [];
|
|
22649
23015
|
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 }));
|
|
@@ -22846,19 +23212,19 @@ function isPlaceholderProjectName(value) {
|
|
|
22846
23212
|
async function readMcpEvidence(cwd) {
|
|
22847
23213
|
const candidates = MCP_CONFIG_PATHS.map((relativePath) => ({
|
|
22848
23214
|
source: relativePath.replace(/\\/g, "/"),
|
|
22849
|
-
path: (0,
|
|
23215
|
+
path: (0, import_node_path41.resolve)(cwd, relativePath)
|
|
22850
23216
|
}));
|
|
22851
23217
|
const home = process.env.USERPROFILE || process.env.HOME;
|
|
22852
23218
|
if (home) {
|
|
22853
23219
|
candidates.push({
|
|
22854
23220
|
source: "~/.codex/config.toml",
|
|
22855
|
-
path: (0,
|
|
23221
|
+
path: (0, import_node_path41.resolve)(home, ".codex", "config.toml")
|
|
22856
23222
|
});
|
|
22857
23223
|
}
|
|
22858
23224
|
const evidence = [];
|
|
22859
23225
|
for (const candidate of candidates) {
|
|
22860
23226
|
try {
|
|
22861
|
-
const text = await (0,
|
|
23227
|
+
const text = await (0, import_promises32.readFile)(candidate.path, "utf8");
|
|
22862
23228
|
if (/mcp/i.test(text)) evidence.push({ source: candidate.source, text });
|
|
22863
23229
|
} catch {
|
|
22864
23230
|
}
|
|
@@ -22949,7 +23315,7 @@ async function enrichProjectMetadata(state, cwd) {
|
|
|
22949
23315
|
async function readState(cwd) {
|
|
22950
23316
|
let state;
|
|
22951
23317
|
try {
|
|
22952
|
-
const raw = await (0,
|
|
23318
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "last-scan.json"), "utf8");
|
|
22953
23319
|
const packageJson = await readPackageJson(cwd);
|
|
22954
23320
|
const deps = dependencyNames(packageJson);
|
|
22955
23321
|
const files = await listProjectFiles(cwd);
|
|
@@ -23216,7 +23582,7 @@ async function whereExe(command, cwd) {
|
|
|
23216
23582
|
}
|
|
23217
23583
|
function expandShimPath(value, base) {
|
|
23218
23584
|
const relative8 = value.replace(/^%(?:dp0%\\+|~dp0\\*)/i, "");
|
|
23219
|
-
return relative8 === value ? value : (0,
|
|
23585
|
+
return relative8 === value ? value : (0, import_node_path41.join)(base, ...relative8.split(/[\\/]+/));
|
|
23220
23586
|
}
|
|
23221
23587
|
function findShimTarget(lines, pattern, accept = () => true) {
|
|
23222
23588
|
for (const line of lines) {
|
|
@@ -23227,21 +23593,21 @@ function findShimTarget(lines, pattern, accept = () => true) {
|
|
|
23227
23593
|
}
|
|
23228
23594
|
async function resolveWindowsShimTarget(shimPath) {
|
|
23229
23595
|
try {
|
|
23230
|
-
const content = await (0,
|
|
23231
|
-
const base = (0,
|
|
23596
|
+
const content = await (0, import_promises32.readFile)(shimPath, "utf8");
|
|
23597
|
+
const base = (0, import_node_path41.dirname)(shimPath);
|
|
23232
23598
|
const lines = content.split(/\r?\n/);
|
|
23233
23599
|
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("%"));
|
|
23234
23600
|
const script = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.js)"/i);
|
|
23235
23601
|
if (script) {
|
|
23236
23602
|
return {
|
|
23237
23603
|
command: process.execPath,
|
|
23238
|
-
args: [(0,
|
|
23604
|
+
args: [(0, import_node_path41.join)(base, ...script.match[1].split(/[\\/]+/)), ...trailingArgs(script.line, script.match.index + script.match[0].length)]
|
|
23239
23605
|
};
|
|
23240
23606
|
}
|
|
23241
|
-
const binary = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.exe)"/i, (target) => (0,
|
|
23607
|
+
const binary = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.exe)"/i, (target) => (0, import_node_path41.basename)(target).toLowerCase() !== "node.exe");
|
|
23242
23608
|
if (binary) {
|
|
23243
23609
|
return {
|
|
23244
|
-
command: (0,
|
|
23610
|
+
command: (0, import_node_path41.join)(base, ...binary.match[1].split(/[\\/]+/)),
|
|
23245
23611
|
args: trailingArgs(binary.line, binary.match.index + binary.match[0].length)
|
|
23246
23612
|
};
|
|
23247
23613
|
}
|
|
@@ -23366,8 +23732,8 @@ async function writeChatContextArtifact(cwd, request, prompt) {
|
|
|
23366
23732
|
"",
|
|
23367
23733
|
prompt
|
|
23368
23734
|
].filter((line) => typeof line === "string");
|
|
23369
|
-
await (0,
|
|
23370
|
-
await (0,
|
|
23735
|
+
await (0, import_promises32.mkdir)((0, import_node_path41.join)(cwd, ".viberaven"), { recursive: true });
|
|
23736
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(cwd, ".viberaven", "chat-context.md"), `${lines.join("\n")}
|
|
23371
23737
|
`, "utf8");
|
|
23372
23738
|
} catch {
|
|
23373
23739
|
}
|
|
@@ -23387,13 +23753,13 @@ async function runAgentChat(cwd, request) {
|
|
|
23387
23753
|
}
|
|
23388
23754
|
const prompt = await buildAgentChatPrompt(request, cwd);
|
|
23389
23755
|
await writeChatContextArtifact(cwd, request, prompt);
|
|
23390
|
-
const outputPath = request.cliId === "codex" ? (0,
|
|
23391
|
-
if (outputPath) await (0,
|
|
23756
|
+
const outputPath = request.cliId === "codex" ? (0, import_node_path41.join)(cwd, ".viberaven", `studio-agent-${Date.now()}-${Math.random().toString(36).slice(2)}.md`) : void 0;
|
|
23757
|
+
if (outputPath) await (0, import_promises32.mkdir)((0, import_node_path41.dirname)(outputPath), { recursive: true });
|
|
23392
23758
|
const { command, args, stdin } = commandForAgentChat(request, prompt, cwd, outputPath);
|
|
23393
23759
|
const result = await runAgentCommand(command, args, cwd, stdin, request.runId);
|
|
23394
23760
|
if (outputPath) {
|
|
23395
23761
|
try {
|
|
23396
|
-
const finalMessage = (await (0,
|
|
23762
|
+
const finalMessage = (await (0, import_promises32.readFile)(outputPath, "utf8")).trim();
|
|
23397
23763
|
if (finalMessage) return { ...result, output: finalMessage };
|
|
23398
23764
|
} catch {
|
|
23399
23765
|
}
|
|
@@ -23405,8 +23771,8 @@ function firstGapId(state) {
|
|
|
23405
23771
|
return state.providers.find((provider2) => provider2.nextFix?.id)?.nextFix?.id;
|
|
23406
23772
|
}
|
|
23407
23773
|
async function runLocalAction(cwd, intent) {
|
|
23408
|
-
const artifactDir = (0,
|
|
23409
|
-
await (0,
|
|
23774
|
+
const artifactDir = (0, import_node_path41.join)(cwd, ".viberaven");
|
|
23775
|
+
await (0, import_promises32.mkdir)(artifactDir, { recursive: true });
|
|
23410
23776
|
if (intent === "preview_rehearsal") {
|
|
23411
23777
|
const state2 = await readState(cwd);
|
|
23412
23778
|
const topProvider = state2.providers[0];
|
|
@@ -23447,7 +23813,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23447
23813
|
proof,
|
|
23448
23814
|
""
|
|
23449
23815
|
].join("\n");
|
|
23450
|
-
await (0,
|
|
23816
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "preview-rehearsal.md"), markdown, "utf8");
|
|
23451
23817
|
return {
|
|
23452
23818
|
title: "Preview rehearsal ready",
|
|
23453
23819
|
summary: `${projectName}: ${gateLabel} with ${state2.providers.length} provider beat${state2.providers.length === 1 ? "" : "s"}`,
|
|
@@ -23457,7 +23823,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23457
23823
|
if (intent === "audit_vercel_supabase") {
|
|
23458
23824
|
const auditInput = await collectVercelSupabaseAuditInput(cwd);
|
|
23459
23825
|
const result2 = buildVercelSupabaseAudit(auditInput);
|
|
23460
|
-
await (0,
|
|
23826
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "audit-vercel-supabase.txt"), `${renderVercelSupabaseAudit(result2)}
|
|
23461
23827
|
`, "utf8");
|
|
23462
23828
|
return {
|
|
23463
23829
|
title: result2.status === "pass" ? "Audit passed" : "Audit needs work",
|
|
@@ -23485,7 +23851,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23485
23851
|
const mode = intent === "heal_prompt" ? "prompt" : intent === "heal_apply" ? "apply" : "plan";
|
|
23486
23852
|
const result = await runHealCommand({ cwd, mode, gapId, yes: mode === "apply", noVerify: true });
|
|
23487
23853
|
if (mode === "apply") {
|
|
23488
|
-
await (0,
|
|
23854
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "heal-apply-result.json"), `${JSON.stringify(result, null, 2)}
|
|
23489
23855
|
`, "utf8");
|
|
23490
23856
|
}
|
|
23491
23857
|
return {
|
|
@@ -23495,14 +23861,14 @@ async function runLocalAction(cwd, intent) {
|
|
|
23495
23861
|
};
|
|
23496
23862
|
}
|
|
23497
23863
|
async function sendArtifact(cwd, rel, response, contentType = "text/plain; charset=utf-8") {
|
|
23498
|
-
const absolute = (0,
|
|
23499
|
-
const root = (0,
|
|
23864
|
+
const absolute = (0, import_node_path41.resolve)(cwd, rel);
|
|
23865
|
+
const root = (0, import_node_path41.resolve)(cwd);
|
|
23500
23866
|
if (!absolute.startsWith(root)) {
|
|
23501
23867
|
sendText(response, 403, "Forbidden");
|
|
23502
23868
|
return;
|
|
23503
23869
|
}
|
|
23504
23870
|
try {
|
|
23505
|
-
const text = await (0,
|
|
23871
|
+
const text = await (0, import_promises32.readFile)(absolute, "utf8");
|
|
23506
23872
|
response.writeHead(200, { "content-type": contentType });
|
|
23507
23873
|
response.end(text);
|
|
23508
23874
|
} catch {
|
|
@@ -23511,7 +23877,7 @@ async function sendArtifact(cwd, rel, response, contentType = "text/plain; chars
|
|
|
23511
23877
|
}
|
|
23512
23878
|
async function sendReportArtifact(cwd, response) {
|
|
23513
23879
|
try {
|
|
23514
|
-
const text = await (0,
|
|
23880
|
+
const text = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "report.html"), "utf8");
|
|
23515
23881
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
23516
23882
|
response.end(text);
|
|
23517
23883
|
return;
|
|
@@ -23638,7 +24004,7 @@ async function sendReportArtifact(cwd, response) {
|
|
|
23638
24004
|
}
|
|
23639
24005
|
async function sendExtensionIcon(cwd, response) {
|
|
23640
24006
|
try {
|
|
23641
|
-
const body = await (0,
|
|
24007
|
+
const body = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, "media", "extension-icon.png"));
|
|
23642
24008
|
sendBinary(response, 200, "image/png", body);
|
|
23643
24009
|
} catch {
|
|
23644
24010
|
sendText(response, 404, "Icon not found");
|
|
@@ -23651,15 +24017,15 @@ async function sendMangaAsset(pathname, response) {
|
|
|
23651
24017
|
return;
|
|
23652
24018
|
}
|
|
23653
24019
|
const candidates = [
|
|
23654
|
-
(0,
|
|
24020
|
+
(0, import_node_path41.join)(__dirname, "manga", name),
|
|
23655
24021
|
// installed + dev: <pkg>/dist/manga
|
|
23656
|
-
(0,
|
|
24022
|
+
(0, import_node_path41.join)(__dirname, "..", "assets", "manga", name),
|
|
23657
24023
|
// fallback: <pkg>/assets/manga (source)
|
|
23658
|
-
(0,
|
|
24024
|
+
(0, import_node_path41.join)(__dirname, "..", "..", "assets", "manga", name)
|
|
23659
24025
|
];
|
|
23660
24026
|
for (const candidate of candidates) {
|
|
23661
24027
|
try {
|
|
23662
|
-
const body = await (0,
|
|
24028
|
+
const body = await (0, import_promises32.readFile)(candidate);
|
|
23663
24029
|
response.setHeader("cache-control", "no-cache");
|
|
23664
24030
|
sendBinary(response, 200, contentTypeForAsset(candidate), body);
|
|
23665
24031
|
return;
|
|
@@ -23669,7 +24035,7 @@ async function sendMangaAsset(pathname, response) {
|
|
|
23669
24035
|
sendText(response, 404, "Asset not found");
|
|
23670
24036
|
}
|
|
23671
24037
|
function contentTypeForAsset(pathname) {
|
|
23672
|
-
switch ((0,
|
|
24038
|
+
switch ((0, import_node_path41.extname)(pathname).toLowerCase()) {
|
|
23673
24039
|
case ".svg":
|
|
23674
24040
|
return "image/svg+xml; charset=utf-8";
|
|
23675
24041
|
case ".png":
|
|
@@ -23686,14 +24052,14 @@ function contentTypeForAsset(pathname) {
|
|
|
23686
24052
|
}
|
|
23687
24053
|
async function sendBundledReportAsset(pathname, response) {
|
|
23688
24054
|
const rel = decodeURIComponent(pathname.replace(/^\/report\//, ""));
|
|
23689
|
-
const assetRoot = (0,
|
|
23690
|
-
const absolute = (0,
|
|
24055
|
+
const assetRoot = (0, import_node_path41.resolve)(getBundledReportAssetsDir());
|
|
24056
|
+
const absolute = (0, import_node_path41.resolve)(assetRoot, rel);
|
|
23691
24057
|
if (!absolute.startsWith(assetRoot)) {
|
|
23692
24058
|
sendText(response, 403, "Forbidden");
|
|
23693
24059
|
return;
|
|
23694
24060
|
}
|
|
23695
24061
|
try {
|
|
23696
|
-
const body = await (0,
|
|
24062
|
+
const body = await (0, import_promises32.readFile)(absolute);
|
|
23697
24063
|
sendBinary(response, 200, contentTypeForAsset(absolute), body);
|
|
23698
24064
|
} catch {
|
|
23699
24065
|
sendText(response, 404, "Asset not found");
|
|
@@ -23715,18 +24081,18 @@ async function bundleStackClient(entryPath) {
|
|
|
23715
24081
|
return output.text;
|
|
23716
24082
|
}
|
|
23717
24083
|
async function sendStackAppJs(response) {
|
|
23718
|
-
const distPath = (0,
|
|
24084
|
+
const distPath = (0, import_node_path41.join)(__dirname, "stack", "app.js");
|
|
23719
24085
|
try {
|
|
23720
|
-
const body = await (0,
|
|
24086
|
+
const body = await (0, import_promises32.readFile)(distPath);
|
|
23721
24087
|
response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "cache-control": "no-store" });
|
|
23722
24088
|
response.end(body);
|
|
23723
24089
|
return;
|
|
23724
24090
|
} catch {
|
|
23725
24091
|
}
|
|
23726
|
-
const entryPath = (0,
|
|
24092
|
+
const entryPath = (0, import_node_path41.join)(__dirname, "stack", "main.ts");
|
|
23727
24093
|
let mtimeMs;
|
|
23728
24094
|
try {
|
|
23729
|
-
mtimeMs = (await (0,
|
|
24095
|
+
mtimeMs = (await (0, import_promises32.stat)(entryPath)).mtimeMs;
|
|
23730
24096
|
} catch {
|
|
23731
24097
|
sendText(response, 404, "Stack client entry not found: src/local-ui/stack/main.ts is missing.");
|
|
23732
24098
|
return;
|
|
@@ -23745,7 +24111,7 @@ async function sendStackAppJs(response) {
|
|
|
23745
24111
|
}
|
|
23746
24112
|
async function sendStackAppCss(response) {
|
|
23747
24113
|
try {
|
|
23748
|
-
const body = await (0,
|
|
24114
|
+
const body = await (0, import_promises32.readFile)((0, import_node_path41.join)(__dirname, "stack", "stack.css"));
|
|
23749
24115
|
response.writeHead(200, { "content-type": "text/css; charset=utf-8", "cache-control": "no-store" });
|
|
23750
24116
|
response.end(body);
|
|
23751
24117
|
} catch {
|
|
@@ -23754,7 +24120,7 @@ async function sendStackAppCss(response) {
|
|
|
23754
24120
|
}
|
|
23755
24121
|
async function readProviderVerifyLedger(cwd) {
|
|
23756
24122
|
try {
|
|
23757
|
-
const raw = await (0,
|
|
24123
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "provider-verify.json"), "utf8");
|
|
23758
24124
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
23759
24125
|
return isRecord5(parsed) ? parsed : {};
|
|
23760
24126
|
} catch {
|
|
@@ -23764,8 +24130,8 @@ async function readProviderVerifyLedger(cwd) {
|
|
|
23764
24130
|
async function writeProviderVerifyEntry(cwd, providerId, entry) {
|
|
23765
24131
|
const ledger = await readProviderVerifyLedger(cwd);
|
|
23766
24132
|
ledger[providerId] = entry;
|
|
23767
|
-
await (0,
|
|
23768
|
-
await (0,
|
|
24133
|
+
await (0, import_promises32.mkdir)((0, import_node_path41.join)(cwd, ".viberaven"), { recursive: true });
|
|
24134
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(cwd, ".viberaven", "provider-verify.json"), `${JSON.stringify(ledger, null, 2)}
|
|
23769
24135
|
`, "utf8");
|
|
23770
24136
|
}
|
|
23771
24137
|
async function handleRequest(request, response, options) {
|
|
@@ -23838,13 +24204,13 @@ async function handleRequest(request, response, options) {
|
|
|
23838
24204
|
return;
|
|
23839
24205
|
}
|
|
23840
24206
|
if (request.method === "GET" && url.pathname === "/api/architecture-map") {
|
|
23841
|
-
const mapPath = (0,
|
|
23842
|
-
const markdown = await (0,
|
|
24207
|
+
const mapPath = (0, import_node_path41.join)(options.cwd, ".viberaven", "architecture-map.md");
|
|
24208
|
+
const markdown = await (0, import_promises32.readFile)(mapPath, "utf8").catch(() => null);
|
|
23843
24209
|
if (markdown === null) {
|
|
23844
24210
|
sendJsonStatus(response, 404, { error: "No architecture map yet. Run a scan first (it is written on every scan)." });
|
|
23845
24211
|
return;
|
|
23846
24212
|
}
|
|
23847
|
-
const dataRaw = await (0,
|
|
24213
|
+
const dataRaw = await (0, import_promises32.readFile)((0, import_node_path41.join)(options.cwd, ".viberaven", "architecture-map.json"), "utf8").catch(() => null);
|
|
23848
24214
|
let data = null;
|
|
23849
24215
|
if (dataRaw) {
|
|
23850
24216
|
try {
|
|
@@ -23853,7 +24219,7 @@ async function handleRequest(request, response, options) {
|
|
|
23853
24219
|
data = null;
|
|
23854
24220
|
}
|
|
23855
24221
|
}
|
|
23856
|
-
const contextRaw = await (0,
|
|
24222
|
+
const contextRaw = await (0, import_promises32.readFile)((0, import_node_path41.join)(options.cwd, ".viberaven", "context-map.json"), "utf8").catch(() => null);
|
|
23857
24223
|
let gaps = [];
|
|
23858
24224
|
if (contextRaw) {
|
|
23859
24225
|
try {
|
|
@@ -24119,35 +24485,35 @@ async function handleRequest(request, response, options) {
|
|
|
24119
24485
|
return;
|
|
24120
24486
|
}
|
|
24121
24487
|
if (request.method === "GET" && url.pathname === "/api/artifacts/tasklist") {
|
|
24122
|
-
await sendArtifact(options.cwd, (0,
|
|
24488
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "agent-tasklist.md"), response);
|
|
24123
24489
|
return;
|
|
24124
24490
|
}
|
|
24125
24491
|
if (request.method === "GET" && url.pathname === "/api/artifacts/playbook") {
|
|
24126
|
-
await sendArtifact(options.cwd, (0,
|
|
24492
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "launch-playbook.md"), response);
|
|
24127
24493
|
return;
|
|
24128
24494
|
}
|
|
24129
24495
|
if (request.method === "GET" && url.pathname === "/api/artifacts/audit") {
|
|
24130
|
-
await sendArtifact(options.cwd, (0,
|
|
24496
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "audit-vercel-supabase.txt"), response);
|
|
24131
24497
|
return;
|
|
24132
24498
|
}
|
|
24133
24499
|
if (request.method === "GET" && url.pathname === "/api/artifacts/cleanup") {
|
|
24134
|
-
await sendArtifact(options.cwd, (0,
|
|
24500
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "context-cleanup.md"), response);
|
|
24135
24501
|
return;
|
|
24136
24502
|
}
|
|
24137
24503
|
if (request.method === "GET" && url.pathname === "/api/artifacts/preview") {
|
|
24138
|
-
await sendArtifact(options.cwd, (0,
|
|
24504
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "preview-rehearsal.md"), response);
|
|
24139
24505
|
return;
|
|
24140
24506
|
}
|
|
24141
24507
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-plan") {
|
|
24142
|
-
await sendArtifact(options.cwd, (0,
|
|
24508
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "heal-plan.md"), response);
|
|
24143
24509
|
return;
|
|
24144
24510
|
}
|
|
24145
24511
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-prompt") {
|
|
24146
|
-
await sendArtifact(options.cwd, (0,
|
|
24512
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "heal-prompt.md"), response);
|
|
24147
24513
|
return;
|
|
24148
24514
|
}
|
|
24149
24515
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-apply") {
|
|
24150
|
-
await sendArtifact(options.cwd, (0,
|
|
24516
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "heal-apply-result.json"), response, "application/json; charset=utf-8");
|
|
24151
24517
|
return;
|
|
24152
24518
|
}
|
|
24153
24519
|
if (request.method === "GET" && url.pathname === "/api/artifacts/report") {
|
|
@@ -24173,12 +24539,12 @@ async function handleRequest(request, response, options) {
|
|
|
24173
24539
|
}
|
|
24174
24540
|
if (request.method === "GET" && url.pathname === "/vendor/anime.umd.min.js") {
|
|
24175
24541
|
for (const candidate of [
|
|
24176
|
-
(0,
|
|
24177
|
-
(0,
|
|
24178
|
-
(0,
|
|
24542
|
+
(0, import_node_path41.join)(__dirname, "vendor", "anime.umd.min.js"),
|
|
24543
|
+
(0, import_node_path41.join)(__dirname, "..", "assets", "vendor", "anime.umd.min.js"),
|
|
24544
|
+
(0, import_node_path41.join)(__dirname, "..", "..", "assets", "vendor", "anime.umd.min.js")
|
|
24179
24545
|
]) {
|
|
24180
24546
|
try {
|
|
24181
|
-
const body = await (0,
|
|
24547
|
+
const body = await (0, import_promises32.readFile)(candidate);
|
|
24182
24548
|
response.setHeader("cache-control", "public, max-age=604800, immutable");
|
|
24183
24549
|
sendBinary(response, 200, "text/javascript; charset=utf-8", body);
|
|
24184
24550
|
return;
|
|
@@ -24395,7 +24761,7 @@ function listen(server, startPort) {
|
|
|
24395
24761
|
});
|
|
24396
24762
|
}
|
|
24397
24763
|
async function startLocalUiServer(options) {
|
|
24398
|
-
const cwd = (0,
|
|
24764
|
+
const cwd = (0, import_node_path41.resolve)(options.cwd);
|
|
24399
24765
|
const scanRunner = options.scanRunner ?? defaultScanRunner;
|
|
24400
24766
|
const autoScan = { state: "idle" };
|
|
24401
24767
|
const fullCheck = new FullCheckService(cwd, options.fullCheck);
|
|
@@ -24412,7 +24778,7 @@ async function startLocalUiServer(options) {
|
|
|
24412
24778
|
});
|
|
24413
24779
|
const port = await listen(server, options.port ?? 4177);
|
|
24414
24780
|
guard.port = port;
|
|
24415
|
-
const hasArtifact = await (0,
|
|
24781
|
+
const hasArtifact = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "last-scan.json"), "utf8").then(
|
|
24416
24782
|
() => true,
|
|
24417
24783
|
() => false
|
|
24418
24784
|
);
|
|
@@ -24451,16 +24817,16 @@ async function waitForServerShutdown() {
|
|
|
24451
24817
|
process.once("SIGTERM", done);
|
|
24452
24818
|
});
|
|
24453
24819
|
}
|
|
24454
|
-
var import_node_http, import_node_child_process10, import_node_crypto6,
|
|
24820
|
+
var import_node_http, import_node_child_process10, import_node_crypto6, import_promises32, import_node_os3, import_node_path41, 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;
|
|
24455
24821
|
var init_server = __esm({
|
|
24456
24822
|
"src/local-ui/server.ts"() {
|
|
24457
24823
|
"use strict";
|
|
24458
24824
|
import_node_http = require("node:http");
|
|
24459
24825
|
import_node_child_process10 = require("node:child_process");
|
|
24460
24826
|
import_node_crypto6 = require("node:crypto");
|
|
24461
|
-
|
|
24827
|
+
import_promises32 = require("node:fs/promises");
|
|
24462
24828
|
import_node_os3 = require("node:os");
|
|
24463
|
-
|
|
24829
|
+
import_node_path41 = require("node:path");
|
|
24464
24830
|
init_initGithub();
|
|
24465
24831
|
init_cleanPlan();
|
|
24466
24832
|
init_audit();
|
|
@@ -24502,8 +24868,8 @@ var init_server = __esm({
|
|
|
24502
24868
|
MCP_CONFIG_PATHS = [
|
|
24503
24869
|
".mcp.json",
|
|
24504
24870
|
"mcp.json",
|
|
24505
|
-
(0,
|
|
24506
|
-
(0,
|
|
24871
|
+
(0, import_node_path41.join)(".cursor", "mcp.json"),
|
|
24872
|
+
(0, import_node_path41.join)(".vscode", "mcp.json")
|
|
24507
24873
|
];
|
|
24508
24874
|
MCP_PROVIDER_NEEDLES = {
|
|
24509
24875
|
supabase: ["supabase", "@supabase/mcp", "mcp-server-supabase"],
|
|
@@ -24585,6 +24951,7 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24585
24951
|
mcpTool: repoCodeTask.mcpTool,
|
|
24586
24952
|
mcpArgs: repoCodeTask.mcpArgs,
|
|
24587
24953
|
fallbackCommand: repoCodeTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${repoCodeTask.gapId} --yes` : void 0,
|
|
24954
|
+
...whereAndAfter(repoCodeTask),
|
|
24588
24955
|
requiresUserAction: false
|
|
24589
24956
|
};
|
|
24590
24957
|
}
|
|
@@ -24598,6 +24965,7 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24598
24965
|
mcpTool: userTask.mcpTool,
|
|
24599
24966
|
mcpArgs: userTask.mcpArgs,
|
|
24600
24967
|
fallbackCommand: userTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${userTask.gapId} --yes` : void 0,
|
|
24968
|
+
...whereAndAfter(userTask),
|
|
24601
24969
|
requiresUserAction: true
|
|
24602
24970
|
};
|
|
24603
24971
|
}
|
|
@@ -24613,10 +24981,17 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24613
24981
|
return {
|
|
24614
24982
|
...base,
|
|
24615
24983
|
type: "done",
|
|
24616
|
-
title: "
|
|
24984
|
+
title: "No repo-code or provider tasks left; gate-result.json has the verdict",
|
|
24617
24985
|
requiresUserAction: false
|
|
24618
24986
|
};
|
|
24619
24987
|
}
|
|
24988
|
+
function whereAndAfter(task) {
|
|
24989
|
+
return {
|
|
24990
|
+
...task.file ? { file: task.file } : {},
|
|
24991
|
+
...task.line !== void 0 ? { line: task.line } : {},
|
|
24992
|
+
...task.userSteps?.length ? { userSteps: [...task.userSteps] } : {}
|
|
24993
|
+
};
|
|
24994
|
+
}
|
|
24620
24995
|
function resolveStallReason(tasks) {
|
|
24621
24996
|
if (tasks.length === 0) return "no-recipes";
|
|
24622
24997
|
const allProviderAction = tasks.every((t) => t.fixType === "provider-action");
|
|
@@ -24674,9 +25049,9 @@ var init_nextActionBlock = __esm({
|
|
|
24674
25049
|
function defaultMcpConfigPaths() {
|
|
24675
25050
|
const home = (0, import_node_os4.homedir)();
|
|
24676
25051
|
return [
|
|
24677
|
-
(0,
|
|
24678
|
-
(0,
|
|
24679
|
-
(0,
|
|
25052
|
+
(0, import_node_path42.join)(home, ".config", "claude", "claude_desktop_config.json"),
|
|
25053
|
+
(0, import_node_path42.join)(home, ".cursor", "mcp.json"),
|
|
25054
|
+
(0, import_node_path42.join)(home, ".gemini", "antigravity", "mcp_config.json")
|
|
24680
25055
|
];
|
|
24681
25056
|
}
|
|
24682
25057
|
function resolveConfigPaths() {
|
|
@@ -24705,11 +25080,11 @@ function findServerEntry(servers, provider2) {
|
|
|
24705
25080
|
function findProviderMcpConfig(provider2, configPaths) {
|
|
24706
25081
|
const paths = configPaths ?? resolveConfigPaths();
|
|
24707
25082
|
for (const path of paths) {
|
|
24708
|
-
if (!(0,
|
|
25083
|
+
if (!(0, import_node_fs16.existsSync)(path)) {
|
|
24709
25084
|
continue;
|
|
24710
25085
|
}
|
|
24711
25086
|
try {
|
|
24712
|
-
const raw = JSON.parse((0,
|
|
25087
|
+
const raw = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
|
|
24713
25088
|
const servers = parseMcpServers(raw);
|
|
24714
25089
|
if (!servers) {
|
|
24715
25090
|
continue;
|
|
@@ -24753,13 +25128,13 @@ async function verifyProviderGap(options) {
|
|
|
24753
25128
|
fallbackCommand: FALLBACK_COMMAND
|
|
24754
25129
|
};
|
|
24755
25130
|
}
|
|
24756
|
-
var
|
|
25131
|
+
var import_node_fs16, import_node_os4, import_node_path42, FALLBACK_COMMAND, SUPPORTED_PROVIDERS, configPathsOverride;
|
|
24757
25132
|
var init_providerMcpBridge = __esm({
|
|
24758
25133
|
"src/providerMcpBridge.ts"() {
|
|
24759
25134
|
"use strict";
|
|
24760
|
-
|
|
25135
|
+
import_node_fs16 = require("node:fs");
|
|
24761
25136
|
import_node_os4 = require("node:os");
|
|
24762
|
-
|
|
25137
|
+
import_node_path42 = require("node:path");
|
|
24763
25138
|
FALLBACK_COMMAND = "npx -y viberaven audit --vercel-supabase --json";
|
|
24764
25139
|
SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["supabase", "vercel"]);
|
|
24765
25140
|
}
|
|
@@ -24982,7 +25357,7 @@ async function cmdProviderVerify(flags, positional) {
|
|
|
24982
25357
|
return result.verified ? 0 : 1;
|
|
24983
25358
|
}
|
|
24984
25359
|
async function cmdStatus(flags, positional) {
|
|
24985
|
-
const startDir = positional[0] ? (0,
|
|
25360
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
24986
25361
|
let artifact;
|
|
24987
25362
|
try {
|
|
24988
25363
|
artifact = await loadLastArtifact(startDir);
|
|
@@ -25021,7 +25396,7 @@ async function cmdStatus(flags, positional) {
|
|
|
25021
25396
|
return 0;
|
|
25022
25397
|
}
|
|
25023
25398
|
async function runScanCommand(flags, positional, options) {
|
|
25024
|
-
const workspacePath = positional[0] ? (0,
|
|
25399
|
+
const workspacePath = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
|
|
25025
25400
|
if (!options?.deferMachineOutput) {
|
|
25026
25401
|
console.log(`Scanning ${workspacePath}\u2026 (local, offline)`);
|
|
25027
25402
|
}
|
|
@@ -25045,15 +25420,27 @@ async function runScanCommand(flags, positional, options) {
|
|
|
25045
25420
|
const updatedState = resetBatch(loopState, openGapCount);
|
|
25046
25421
|
const tasks = buildTaskList(artifact);
|
|
25047
25422
|
const block = buildNextActionBlock(tasks, updatedState);
|
|
25048
|
-
|
|
25049
|
-
printProviderActionBlock(tasks);
|
|
25423
|
+
let manifest;
|
|
25050
25424
|
try {
|
|
25051
|
-
|
|
25052
|
-
console.log(renderActionSurface(manifest, { limit: 5 }).trimEnd());
|
|
25425
|
+
manifest = JSON.parse(await (0, import_promises33.readFile)(paths.actionsPath, "utf8"));
|
|
25053
25426
|
} catch (error) {
|
|
25054
25427
|
console.warn(error instanceof Error ? error.message : String(error));
|
|
25055
25428
|
}
|
|
25429
|
+
const followUps = manifest?.userFollowUps ?? [];
|
|
25430
|
+
if (followUps.length > 0) block.userFollowUps = followUps;
|
|
25431
|
+
printNextActionBlock(block);
|
|
25432
|
+
printProviderActionBlock(tasks);
|
|
25433
|
+
if (manifest) {
|
|
25434
|
+
console.log(renderActionSurface(manifest, { limit: 5, followUps: false }).trimEnd());
|
|
25435
|
+
}
|
|
25056
25436
|
await saveLoopState(workspacePath, updatedState);
|
|
25437
|
+
if (options?.markFollowUpsShown && followUps.length > 0) {
|
|
25438
|
+
try {
|
|
25439
|
+
await markUserFollowUpsShown(workspacePath, followUps.map((followUp) => followUp.id));
|
|
25440
|
+
} catch (error) {
|
|
25441
|
+
console.warn(`Could not record that the outside-the-repo steps were shown (${error instanceof Error ? error.message : String(error)}); they will be shown again.`);
|
|
25442
|
+
}
|
|
25443
|
+
}
|
|
25057
25444
|
}
|
|
25058
25445
|
if (flags.open) {
|
|
25059
25446
|
try {
|
|
@@ -25065,7 +25452,7 @@ async function runScanCommand(flags, positional, options) {
|
|
|
25065
25452
|
return { exitCode: 0, artifacts: paths };
|
|
25066
25453
|
}
|
|
25067
25454
|
async function cmdReport(flags, positional) {
|
|
25068
|
-
const startDir = positional[0] ? (0,
|
|
25455
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25069
25456
|
try {
|
|
25070
25457
|
const paths = await refreshReportFromDisk(startDir);
|
|
25071
25458
|
console.log(`Report refreshed: ${paths.reportPath}`);
|
|
@@ -25087,7 +25474,7 @@ async function cmdReport(flags, positional) {
|
|
|
25087
25474
|
}
|
|
25088
25475
|
}
|
|
25089
25476
|
async function cmdPrompt(flags, positional) {
|
|
25090
|
-
const startDir = positional[0] ? (0,
|
|
25477
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25091
25478
|
let artifact;
|
|
25092
25479
|
try {
|
|
25093
25480
|
artifact = await loadLastArtifact(startDir);
|
|
@@ -25184,7 +25571,7 @@ async function main() {
|
|
|
25184
25571
|
const wantsJsonl = hasFlag(flags, "jsonl");
|
|
25185
25572
|
const wantsStrict = hasFlag(flags, "strict");
|
|
25186
25573
|
if (flags.condense) {
|
|
25187
|
-
const cwd = positional[0] ? (0,
|
|
25574
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25188
25575
|
const result = await runCondenseCommand({ cwd });
|
|
25189
25576
|
console.log(`VibeRaven context map refreshed: ${result.contextMapPath}`);
|
|
25190
25577
|
return 0;
|
|
@@ -25204,18 +25591,18 @@ async function main() {
|
|
|
25204
25591
|
}
|
|
25205
25592
|
if (!command && flags.verify === true && typeof flags.action === "string") {
|
|
25206
25593
|
return runVerifyActionCommand({
|
|
25207
|
-
cwd: positional[0] ? (0,
|
|
25594
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25208
25595
|
actionId: flags.action
|
|
25209
25596
|
});
|
|
25210
25597
|
}
|
|
25211
25598
|
if (!command && (isAgentMode || flags.verify === true || wantsJson || wantsJsonl || wantsStrict)) {
|
|
25212
25599
|
const deferMachineOutput = wantsJson || wantsJsonl;
|
|
25213
|
-
const scanResult = await runScanCommand(flags, positional, { deferMachineOutput });
|
|
25600
|
+
const scanResult = await runScanCommand(flags, positional, { deferMachineOutput, markFollowUpsShown: true });
|
|
25214
25601
|
if ((wantsJson || wantsJsonl) && !scanResult.artifacts) {
|
|
25215
25602
|
console.error("VibeRaven could not produce machine output because scan artifacts were not written.");
|
|
25216
25603
|
return 3;
|
|
25217
25604
|
}
|
|
25218
|
-
const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0,
|
|
25605
|
+
const gateResult = scanResult.artifacts && (wantsJson || wantsJsonl || wantsStrict) ? JSON.parse(await (0, import_promises33.readFile)(scanResult.artifacts.gateResultPath, "utf8")) : void 0;
|
|
25219
25606
|
const strictExitCode = wantsStrict && gateResult ? exitCodeForStrictGate(gateResult, { failOnWarnings: flags.strict === "warning" }) : scanResult.exitCode;
|
|
25220
25607
|
if (wantsJson && gateResult) {
|
|
25221
25608
|
process.stdout.write(renderGateResultJson(gateResult));
|
|
@@ -25237,7 +25624,7 @@ async function main() {
|
|
|
25237
25624
|
env: process.env
|
|
25238
25625
|
});
|
|
25239
25626
|
if (mode === "local-ui") {
|
|
25240
|
-
const cwd = positional[0] ? (0,
|
|
25627
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25241
25628
|
const handle = await startLocalUiServer({ cwd, initialPath: stackInitialPath(flags) });
|
|
25242
25629
|
console.log(`VibeRaven local UI: ${handle.url}`);
|
|
25243
25630
|
await waitForServerShutdown();
|
|
@@ -25248,7 +25635,7 @@ async function main() {
|
|
|
25248
25635
|
await runInteractiveSession();
|
|
25249
25636
|
return 0;
|
|
25250
25637
|
}
|
|
25251
|
-
const scanResult = await runScanCommand({ "agent-mode": true }, positional);
|
|
25638
|
+
const scanResult = await runScanCommand({ "agent-mode": true }, positional, { markFollowUpsShown: true });
|
|
25252
25639
|
return scanResult.exitCode;
|
|
25253
25640
|
}
|
|
25254
25641
|
switch (command) {
|
|
@@ -25257,7 +25644,7 @@ async function main() {
|
|
|
25257
25644
|
await runInteractiveSession();
|
|
25258
25645
|
return 0;
|
|
25259
25646
|
case "ui": {
|
|
25260
|
-
const cwd = positional[0] ? (0,
|
|
25647
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25261
25648
|
const envPort = Number(process.env.PORT);
|
|
25262
25649
|
const handle = await startLocalUiServer({ cwd, port: Number.isFinite(envPort) && envPort > 0 ? envPort : void 0, initialPath: stackInitialPath(flags) });
|
|
25263
25650
|
console.log(`VibeRaven local UI: ${handle.url}`);
|
|
@@ -25269,14 +25656,14 @@ async function main() {
|
|
|
25269
25656
|
return cmdStatus(flags, positional);
|
|
25270
25657
|
case "check":
|
|
25271
25658
|
return runCheckCommand({
|
|
25272
|
-
cwd: positional[0] ? (0,
|
|
25659
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25273
25660
|
json: Boolean(flags.json),
|
|
25274
25661
|
quiet: Boolean(flags.quiet),
|
|
25275
25662
|
base: typeof flags.base === "string" ? flags.base : void 0,
|
|
25276
25663
|
markdown: flags.markdown === true
|
|
25277
25664
|
});
|
|
25278
25665
|
case "fix": {
|
|
25279
|
-
const fixCwd = positional[0] ? (0,
|
|
25666
|
+
const fixCwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25280
25667
|
const gapId = typeof flags.gap === "string" ? flags.gap : void 0;
|
|
25281
25668
|
if (!gapId) {
|
|
25282
25669
|
const artifact = await loadLastArtifact(fixCwd).catch(() => void 0);
|
|
@@ -25305,19 +25692,19 @@ async function main() {
|
|
|
25305
25692
|
}
|
|
25306
25693
|
case "actions":
|
|
25307
25694
|
return runActionsCommand({
|
|
25308
|
-
cwd: positional[0] ? (0,
|
|
25695
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25309
25696
|
json: Boolean(flags.json)
|
|
25310
25697
|
});
|
|
25311
25698
|
case "preview":
|
|
25312
25699
|
return runPreviewCommand({
|
|
25313
|
-
cwd: positional[0] ? (0,
|
|
25700
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25314
25701
|
agentMode: flags["agent-mode"] === true,
|
|
25315
25702
|
json: Boolean(flags.json)
|
|
25316
25703
|
});
|
|
25317
25704
|
case "next":
|
|
25318
25705
|
return runNextCommand({
|
|
25319
25706
|
json: Boolean(flags.json),
|
|
25320
|
-
cwd: positional[0] ? (0,
|
|
25707
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd()
|
|
25321
25708
|
});
|
|
25322
25709
|
case "guide": {
|
|
25323
25710
|
const provider2 = positional[0];
|
|
@@ -25339,7 +25726,7 @@ async function main() {
|
|
|
25339
25726
|
cwd: process.cwd()
|
|
25340
25727
|
});
|
|
25341
25728
|
case "scan": {
|
|
25342
|
-
const scanResult = await runScanCommand(flags, positional);
|
|
25729
|
+
const scanResult = await runScanCommand(flags, positional, { markFollowUpsShown: true });
|
|
25343
25730
|
return scanResult.exitCode;
|
|
25344
25731
|
}
|
|
25345
25732
|
case "report":
|
|
@@ -25351,7 +25738,7 @@ async function main() {
|
|
|
25351
25738
|
case "provider-verify":
|
|
25352
25739
|
return cmdProviderVerify(flags, positional);
|
|
25353
25740
|
case "init": {
|
|
25354
|
-
const cwd = positional[0] ? (0,
|
|
25741
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25355
25742
|
const agents = typeof flags.agents === "string" ? flags.agents : void 0;
|
|
25356
25743
|
if (flags.github === true) {
|
|
25357
25744
|
return runInitGithubCommand({ cwd, dryRun: flags["dry-run"] === true, force: flags.force === true });
|
|
@@ -25368,7 +25755,7 @@ async function main() {
|
|
|
25368
25755
|
return 1;
|
|
25369
25756
|
}
|
|
25370
25757
|
return runDoctorAgentsCommand({
|
|
25371
|
-
cwd: positional[0] ? (0,
|
|
25758
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd()
|
|
25372
25759
|
});
|
|
25373
25760
|
case "validate-npm-package":
|
|
25374
25761
|
return runValidateNpmPackageCommand({
|
|
@@ -25381,7 +25768,7 @@ async function main() {
|
|
|
25381
25768
|
return 1;
|
|
25382
25769
|
}
|
|
25383
25770
|
return runAuditCommand({
|
|
25384
|
-
cwd: positional[0] ? (0,
|
|
25771
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25385
25772
|
json: Boolean(flags.json)
|
|
25386
25773
|
});
|
|
25387
25774
|
case "clean": {
|
|
@@ -25389,7 +25776,7 @@ async function main() {
|
|
|
25389
25776
|
console.error("Usage: viberaven clean --plan [path]");
|
|
25390
25777
|
return 1;
|
|
25391
25778
|
}
|
|
25392
|
-
const cwd = positional[0] ? (0,
|
|
25779
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25393
25780
|
const plan = buildContextCleanupPlan({ projectRoot: cwd, files: await collectCleanupFiles(cwd) });
|
|
25394
25781
|
const outputPath = await writeCleanupPlan(cwd, plan);
|
|
25395
25782
|
console.log(`Wrote ${outputPath}
|
|
@@ -25399,9 +25786,9 @@ async function main() {
|
|
|
25399
25786
|
}
|
|
25400
25787
|
case "rls-test":
|
|
25401
25788
|
return runRlsTestCommand({
|
|
25402
|
-
cwd: positional[0] ? (0,
|
|
25403
|
-
matrix: typeof flags.matrix === "string" ? (0,
|
|
25404
|
-
migrations: typeof flags.migrations === "string" ? (0,
|
|
25789
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25790
|
+
matrix: typeof flags.matrix === "string" ? (0, import_node_path43.resolve)(process.cwd(), flags.matrix) : void 0,
|
|
25791
|
+
migrations: typeof flags.migrations === "string" ? (0, import_node_path43.resolve)(process.cwd(), flags.migrations) : void 0,
|
|
25405
25792
|
json: Boolean(flags.json)
|
|
25406
25793
|
});
|
|
25407
25794
|
default:
|
|
@@ -25410,11 +25797,11 @@ async function main() {
|
|
|
25410
25797
|
return 1;
|
|
25411
25798
|
}
|
|
25412
25799
|
}
|
|
25413
|
-
var
|
|
25800
|
+
var import_promises33, import_node_path43, STACK_AREAS;
|
|
25414
25801
|
var init_cli = __esm({
|
|
25415
25802
|
"src/cli.ts"() {
|
|
25416
|
-
|
|
25417
|
-
|
|
25803
|
+
import_promises33 = require("node:fs/promises");
|
|
25804
|
+
import_node_path43 = require("node:path");
|
|
25418
25805
|
init_config();
|
|
25419
25806
|
init_runScan();
|
|
25420
25807
|
init_artifacts2();
|
|
@@ -25456,6 +25843,7 @@ var init_cli = __esm({
|
|
|
25456
25843
|
init_buildTaskList();
|
|
25457
25844
|
init_providerMcpBridge();
|
|
25458
25845
|
init_render();
|
|
25846
|
+
init_registry2();
|
|
25459
25847
|
STACK_AREAS = /* @__PURE__ */ new Set(["database", "auth", "payments", "deployment", "monitoring", "security"]);
|
|
25460
25848
|
if (require.main === module) {
|
|
25461
25849
|
main().then((code) => {
|