@viberaven/cli 1.6.2 → 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/AGENTS.md +64 -64
- package/LICENSE +21 -21
- package/README.md +113 -113
- package/SECURITY.md +59 -59
- package/dist/cli.js +1196 -818
- package/dist/console/app.js +251 -251
- package/dist/console/index.html +46 -46
- package/dist/console/styles.css +267 -267
- package/dist/playbooks/_stack-default.json +11 -11
- package/dist/playbooks/auth-supabase.json +31 -31
- package/dist/playbooks/stripe.json +66 -66
- package/dist/playbooks/supabase.json +51 -51
- package/dist/playbooks/vercel.json +42 -42
- package/dist/report/assets/provider-authjs.svg +5 -5
- package/dist/report/assets/provider-aws.svg +5 -5
- package/dist/report/assets/provider-logrocket.svg +4 -4
- package/dist/report/report-cli.css +1466 -1466
- package/dist/report/station.css +11854 -11854
- package/dist/report/station.js +8319 -8319
- package/dist/stack/stack.css +1008 -1008
- package/dist/vendor/anime.umd.min.js +7 -7
- package/package.json +95 -84
- package/playbooks/_stack-default.json +11 -11
- package/playbooks/auth-supabase.json +31 -31
- package/playbooks/stripe.json +66 -66
- package/playbooks/supabase.json +51 -51
- package/playbooks/vercel.json +42 -42
- package/schemas/permissions-matrix.schema.json +90 -90
- package/templates/AGENTS.snippet.md +56 -56
- package/templates/CLAUDE.snippet.md +14 -14
- package/templates/CURSOR.snippet.md +14 -14
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
|
`);
|
|
@@ -10437,6 +10459,18 @@ var init_databaseEvidence = __esm({
|
|
|
10437
10459
|
});
|
|
10438
10460
|
|
|
10439
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
|
+
}
|
|
10440
10474
|
function hasFilePath(scan, pattern) {
|
|
10441
10475
|
return scan.files.some((f) => pattern.test(f.path));
|
|
10442
10476
|
}
|
|
@@ -10730,7 +10764,8 @@ function auditFindingSeeds(audit) {
|
|
|
10730
10764
|
detail: capLines(lines).join("\n"),
|
|
10731
10765
|
copyPrompt: fixes.length > 0 ? `${meta.prompt}
|
|
10732
10766
|
${capLines(fixes).join("\n")}` : meta.prompt,
|
|
10733
|
-
primaryMapCategory: meta.map
|
|
10767
|
+
primaryMapCategory: meta.map,
|
|
10768
|
+
locations: findingLocations(findings)
|
|
10734
10769
|
};
|
|
10735
10770
|
});
|
|
10736
10771
|
}
|
|
@@ -10929,6 +10964,7 @@ ${check.evidence.map((e2) => `- ${e2}`).join("\n")}` : "";
|
|
|
10929
10964
|
category: "SECURITY & AUTH",
|
|
10930
10965
|
severity: "warning",
|
|
10931
10966
|
title: "Stripe webhook does not verify the signature",
|
|
10967
|
+
locations: findingLocations(webhooks.unverified.map((u2) => ({ file: u2.path }))),
|
|
10932
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.`,
|
|
10933
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.',
|
|
10934
10970
|
primaryMapCategory: "payments"
|
|
@@ -10965,7 +11001,7 @@ ${check.evidence.map((e2) => `- ${e2}`).join("\n")}` : "";
|
|
|
10965
11001
|
severity: "warning",
|
|
10966
11002
|
title: `Env vars used in code but missing from ${target}`,
|
|
10967
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.`,
|
|
10968
|
-
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).`,
|
|
10969
11005
|
primaryMapCategory: "deployment"
|
|
10970
11006
|
});
|
|
10971
11007
|
} else {
|
|
@@ -11032,9 +11068,9 @@ function scoreFrom(gaps) {
|
|
|
11032
11068
|
}
|
|
11033
11069
|
return Math.max(5, Math.min(96, score));
|
|
11034
11070
|
}
|
|
11035
|
-
function
|
|
11071
|
+
function scoreLabelFor(score, criticalCount, warningCount) {
|
|
11036
11072
|
if (criticalCount > 0) return "Blocked";
|
|
11037
|
-
if (
|
|
11073
|
+
if (warningCount === 0) return "No blockers in repo checks";
|
|
11038
11074
|
if (score >= 60) return "Almost there";
|
|
11039
11075
|
return "Needs work";
|
|
11040
11076
|
}
|
|
@@ -11133,11 +11169,12 @@ async function buildLocalStationOutput(input) {
|
|
|
11133
11169
|
toolSuggestions: [],
|
|
11134
11170
|
mcpSuggestion: null,
|
|
11135
11171
|
primaryMapCategory: seed.primaryMapCategory,
|
|
11136
|
-
affectedMapCategories: [seed.primaryMapCategory]
|
|
11172
|
+
affectedMapCategories: [seed.primaryMapCategory],
|
|
11173
|
+
...seed.locations?.length ? { locations: seed.locations } : {}
|
|
11137
11174
|
}));
|
|
11138
11175
|
return {
|
|
11139
11176
|
score,
|
|
11140
|
-
scoreLabel:
|
|
11177
|
+
scoreLabel: scoreLabelFor(score, criticalCount, warningCount),
|
|
11141
11178
|
summary,
|
|
11142
11179
|
archetype,
|
|
11143
11180
|
gaps,
|
|
@@ -11593,6 +11630,28 @@ var init_runScan = __esm({
|
|
|
11593
11630
|
}
|
|
11594
11631
|
});
|
|
11595
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
|
+
|
|
11596
11655
|
// src/capabilities/classify.ts
|
|
11597
11656
|
function gapText(gap) {
|
|
11598
11657
|
return `${gap.id} ${gap.title} ${gap.detail} ${gap.primaryMapCategory}`.toLowerCase();
|
|
@@ -11780,6 +11839,37 @@ var init_capabilities = __esm({
|
|
|
11780
11839
|
}
|
|
11781
11840
|
});
|
|
11782
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
|
+
|
|
11783
11873
|
// src/contracts/commands.ts
|
|
11784
11874
|
function promptGapCommand(gapId) {
|
|
11785
11875
|
return `${PUBLIC_COMMAND} prompt --gap ${gapId}`;
|
|
@@ -11807,65 +11897,18 @@ var init_commands = __esm({
|
|
|
11807
11897
|
}
|
|
11808
11898
|
});
|
|
11809
11899
|
|
|
11810
|
-
// src/contracts/contextMap.ts
|
|
11811
|
-
function generateContextMap(artifact) {
|
|
11812
|
-
const criticalCount = artifact.gaps.filter((gap) => gap.severity === "critical").length;
|
|
11813
|
-
const warningCount = artifact.gaps.filter((gap) => gap.severity === "warning").length;
|
|
11814
|
-
return {
|
|
11815
|
-
$schema: "https://viberaven.dev/schemas/context-map.schema.json",
|
|
11816
|
-
schemaVersion: "v1",
|
|
11817
|
-
generatedAt: artifact.scannedAt,
|
|
11818
|
-
workspace: {
|
|
11819
|
-
root: artifact.workspacePath,
|
|
11820
|
-
packageManager: "unknown",
|
|
11821
|
-
languages: ["typescript"],
|
|
11822
|
-
frameworks: artifact.archetype ? [artifact.archetype] : []
|
|
11823
|
-
},
|
|
11824
|
-
agentContract: {
|
|
11825
|
-
readFirst: ".viberaven/agent-tasklist.md",
|
|
11826
|
-
machineResult: ".viberaven/gate-result.json",
|
|
11827
|
-
contextMap: ".viberaven/context-map.json",
|
|
11828
|
-
verifyCommand: PUBLIC_VERIFY_COMMAND,
|
|
11829
|
-
strictCommand: PUBLIC_STRICT_COMMAND,
|
|
11830
|
-
nextCommand: PUBLIC_NEXT_JSON_COMMAND
|
|
11831
|
-
},
|
|
11832
|
-
stack: {
|
|
11833
|
-
deployment: artifact.selectedProviders?.deployment ? [artifact.selectedProviders.deployment] : [],
|
|
11834
|
-
database: artifact.selectedProviders?.database ? [artifact.selectedProviders.database] : [],
|
|
11835
|
-
auth: artifact.selectedProviders?.auth ? [artifact.selectedProviders.auth] : [],
|
|
11836
|
-
payments: artifact.selectedProviders?.payments ? [artifact.selectedProviders.payments] : [],
|
|
11837
|
-
monitoring: artifact.selectedProviders?.monitoring ? [artifact.selectedProviders.monitoring] : []
|
|
11838
|
-
},
|
|
11839
|
-
capabilityGraph: summarizeCapabilities(artifact.gaps),
|
|
11840
|
-
productionGate: {
|
|
11841
|
-
status: criticalCount > 0 ? "not_clear" : warningCount > 0 ? "warning" : "clear",
|
|
11842
|
-
criticalCount,
|
|
11843
|
-
warningCount,
|
|
11844
|
-
providerDashboardChecksRequired: true
|
|
11845
|
-
},
|
|
11846
|
-
topGaps: artifact.gaps.slice(0, 10).map((gap) => ({
|
|
11847
|
-
id: gap.id,
|
|
11848
|
-
severity: gap.severity,
|
|
11849
|
-
title: gap.title,
|
|
11850
|
-
area: String(gap.primaryMapCategory),
|
|
11851
|
-
promptCommand: promptGapCommand(gap.id)
|
|
11852
|
-
}))
|
|
11853
|
-
};
|
|
11854
|
-
}
|
|
11855
|
-
var init_contextMap = __esm({
|
|
11856
|
-
"src/contracts/contextMap.ts"() {
|
|
11857
|
-
"use strict";
|
|
11858
|
-
init_capabilities();
|
|
11859
|
-
init_commands();
|
|
11860
|
-
}
|
|
11861
|
-
});
|
|
11862
|
-
|
|
11863
11900
|
// src/contracts/gateResult.ts
|
|
11864
11901
|
function gateStatus(criticalCount, warningCount) {
|
|
11865
11902
|
if (criticalCount > 0) return "not_clear";
|
|
11866
11903
|
if (warningCount > 0) return "warning";
|
|
11867
11904
|
return "clear";
|
|
11868
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
|
+
}
|
|
11869
11912
|
function runIdFrom(scannedAt) {
|
|
11870
11913
|
return `vr_${scannedAt.replace(/\D/g, "").slice(0, 14) || "scan"}`;
|
|
11871
11914
|
}
|
|
@@ -11883,7 +11926,7 @@ function generateGateResult(artifact, options = {}) {
|
|
|
11883
11926
|
generatedAt: artifact.scannedAt,
|
|
11884
11927
|
workspace: {
|
|
11885
11928
|
root: artifact.workspacePath,
|
|
11886
|
-
packageManager:
|
|
11929
|
+
packageManager: options.packageManager ?? detectPackageManager(artifact.workspacePath),
|
|
11887
11930
|
languages: ["typescript"],
|
|
11888
11931
|
frameworks: artifact.archetype ? [artifact.archetype] : []
|
|
11889
11932
|
},
|
|
@@ -11924,101 +11967,246 @@ var init_gateResult = __esm({
|
|
|
11924
11967
|
"src/contracts/gateResult.ts"() {
|
|
11925
11968
|
"use strict";
|
|
11926
11969
|
init_capabilities();
|
|
11970
|
+
init_packageManager();
|
|
11927
11971
|
init_commands();
|
|
11928
11972
|
}
|
|
11929
11973
|
});
|
|
11930
11974
|
|
|
11931
|
-
// src/contracts/
|
|
11932
|
-
function
|
|
11933
|
-
|
|
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;
|
|
11934
11986
|
}
|
|
11935
|
-
function
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
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) => ({
|
|
11941
12017
|
id: gap.id,
|
|
11942
12018
|
severity: gap.severity,
|
|
11943
|
-
capability: classifyGapCapability(gap),
|
|
11944
12019
|
title: gap.title,
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
healPlan: healPlanGapCommand(gap.id),
|
|
11950
|
-
verify: PUBLIC_VERIFY_COMMAND
|
|
11951
|
-
},
|
|
11952
|
-
providerBoundary: {
|
|
11953
|
-
requiresDashboardCheck: true,
|
|
11954
|
-
reason: "Repo evidence cannot prove live provider dashboard state."
|
|
11955
|
-
}
|
|
11956
|
-
}
|
|
11957
|
-
}));
|
|
12020
|
+
area: String(gap.primaryMapCategory),
|
|
12021
|
+
promptCommand: promptGapCommand(gap.id)
|
|
12022
|
+
}))
|
|
12023
|
+
};
|
|
11958
12024
|
}
|
|
11959
|
-
var
|
|
11960
|
-
"src/contracts/
|
|
12025
|
+
var init_contextMap = __esm({
|
|
12026
|
+
"src/contracts/contextMap.ts"() {
|
|
11961
12027
|
"use strict";
|
|
12028
|
+
init_detectedProviders();
|
|
12029
|
+
init_gateResult();
|
|
11962
12030
|
init_capabilities();
|
|
12031
|
+
init_packageManager();
|
|
11963
12032
|
init_commands();
|
|
11964
12033
|
}
|
|
11965
12034
|
});
|
|
11966
12035
|
|
|
11967
|
-
// src/
|
|
11968
|
-
function
|
|
11969
|
-
|
|
11970
|
-
|
|
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
|
+
}
|
|
11971
12069
|
}
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
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;
|
|
11975
12086
|
}
|
|
11976
|
-
|
|
11977
|
-
|
|
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]);
|
|
11978
12129
|
}
|
|
11979
|
-
|
|
11980
|
-
|
|
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
|
+
};
|
|
11981
12149
|
}
|
|
11982
|
-
|
|
11983
|
-
|
|
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
|
+
};
|
|
11984
12157
|
}
|
|
11985
|
-
|
|
11986
|
-
|
|
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
|
+
};
|
|
11987
12178
|
}
|
|
11988
|
-
return
|
|
12179
|
+
return { ok: true, file: `${dir}/${name}` };
|
|
11989
12180
|
}
|
|
11990
|
-
var
|
|
11991
|
-
var
|
|
11992
|
-
"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"() {
|
|
11993
12184
|
"use strict";
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
"stripe-product": "stripe",
|
|
12001
|
-
"stripe-keys": "stripe"
|
|
12002
|
-
};
|
|
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$/;
|
|
12003
12191
|
}
|
|
12004
12192
|
});
|
|
12005
12193
|
|
|
12006
12194
|
// src/playbooks/playbooksRoot.ts
|
|
12007
12195
|
function playbooksRoot() {
|
|
12008
|
-
const candidates = [(0,
|
|
12196
|
+
const candidates = [(0, import_node_path10.join)(__dirname, "playbooks"), (0, import_node_path10.join)(__dirname, "..", "..", "playbooks")];
|
|
12009
12197
|
for (const dir of candidates) {
|
|
12010
|
-
if ((0,
|
|
12198
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path10.join)(dir, "vercel.json"))) {
|
|
12011
12199
|
return dir;
|
|
12012
12200
|
}
|
|
12013
12201
|
}
|
|
12014
12202
|
throw new Error("VibeRaven playbooks directory not found (expected vercel.json)");
|
|
12015
12203
|
}
|
|
12016
|
-
var
|
|
12204
|
+
var import_node_fs6, import_node_path10;
|
|
12017
12205
|
var init_playbooksRoot = __esm({
|
|
12018
12206
|
"src/playbooks/playbooksRoot.ts"() {
|
|
12019
12207
|
"use strict";
|
|
12020
|
-
|
|
12021
|
-
|
|
12208
|
+
import_node_fs6 = require("node:fs");
|
|
12209
|
+
import_node_path10 = require("node:path");
|
|
12022
12210
|
}
|
|
12023
12211
|
});
|
|
12024
12212
|
|
|
@@ -12125,7 +12313,7 @@ async function loadPlaybook(provider2) {
|
|
|
12125
12313
|
`Unknown provider "${provider2}". Available: ${PLAYBOOK_PROVIDERS.join(", ")}`
|
|
12126
12314
|
);
|
|
12127
12315
|
}
|
|
12128
|
-
const path = (0,
|
|
12316
|
+
const path = (0, import_node_path11.join)(playbooksRoot(), `${normalized}.json`);
|
|
12129
12317
|
const raw = JSON.parse(await (0, import_promises7.readFile)(path, "utf-8"));
|
|
12130
12318
|
const playbook = parsePlaybook(raw);
|
|
12131
12319
|
if (playbook.provider !== normalized) {
|
|
@@ -12140,59 +12328,30 @@ function loadPlaybookSync(provider2) {
|
|
|
12140
12328
|
`Unknown provider "${provider2}". Available: ${PLAYBOOK_PROVIDERS.join(", ")}`
|
|
12141
12329
|
);
|
|
12142
12330
|
}
|
|
12143
|
-
const path = (0,
|
|
12144
|
-
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"));
|
|
12145
12333
|
const playbook = parsePlaybook(raw);
|
|
12146
12334
|
if (playbook.provider !== normalized) {
|
|
12147
12335
|
throw new Error(`Playbook file ${normalized}.json has mismatched provider field`);
|
|
12148
12336
|
}
|
|
12149
12337
|
return playbook;
|
|
12150
12338
|
}
|
|
12151
|
-
var
|
|
12339
|
+
var import_node_fs7, import_promises7, import_node_path11;
|
|
12152
12340
|
var init_loadPlaybook = __esm({
|
|
12153
12341
|
"src/playbooks/loadPlaybook.ts"() {
|
|
12154
12342
|
"use strict";
|
|
12155
|
-
|
|
12343
|
+
import_node_fs7 = require("node:fs");
|
|
12156
12344
|
import_promises7 = require("node:fs/promises");
|
|
12157
|
-
|
|
12345
|
+
import_node_path11 = require("node:path");
|
|
12158
12346
|
init_playbooksRoot();
|
|
12159
12347
|
init_types2();
|
|
12160
12348
|
init_validate();
|
|
12161
12349
|
}
|
|
12162
12350
|
});
|
|
12163
12351
|
|
|
12164
|
-
// src/
|
|
12165
|
-
function
|
|
12166
|
-
return
|
|
12167
|
-
}
|
|
12168
|
-
function collectManualChecks(artifact) {
|
|
12169
|
-
const refs = [];
|
|
12170
|
-
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12171
|
-
for (const mission of area.providerMissions) {
|
|
12172
|
-
for (const check of mission.checks) {
|
|
12173
|
-
if (!isManualProviderCheck(check)) {
|
|
12174
|
-
continue;
|
|
12175
|
-
}
|
|
12176
|
-
refs.push({
|
|
12177
|
-
areaLabel: area.label,
|
|
12178
|
-
providerLabel: mission.providerLabel,
|
|
12179
|
-
check,
|
|
12180
|
-
mapCategory: area.key
|
|
12181
|
-
});
|
|
12182
|
-
}
|
|
12183
|
-
}
|
|
12184
|
-
}
|
|
12185
|
-
return refs;
|
|
12186
|
-
}
|
|
12187
|
-
var init_manualChecks = __esm({
|
|
12188
|
-
"src/playbooks/manualChecks.ts"() {
|
|
12189
|
-
"use strict";
|
|
12190
|
-
}
|
|
12191
|
-
});
|
|
12192
|
-
|
|
12193
|
-
// src/tui/menu.ts
|
|
12194
|
-
function isScanNotFoundError(error) {
|
|
12195
|
-
return error instanceof ScanNotFoundError;
|
|
12352
|
+
// src/tui/menu.ts
|
|
12353
|
+
function isScanNotFoundError(error) {
|
|
12354
|
+
return error instanceof ScanNotFoundError;
|
|
12196
12355
|
}
|
|
12197
12356
|
function needsScanMessage(startDir) {
|
|
12198
12357
|
const cwd = startDir ?? process.cwd();
|
|
@@ -12239,7 +12398,7 @@ async function loadLastArtifact(startDir) {
|
|
|
12239
12398
|
if (!workspace) {
|
|
12240
12399
|
throw new ScanNotFoundError(needsScanMessage(startDir));
|
|
12241
12400
|
}
|
|
12242
|
-
const path = (0,
|
|
12401
|
+
const path = (0, import_node_path12.join)(getProjectArtifactsDir(workspace), "last-scan.json");
|
|
12243
12402
|
try {
|
|
12244
12403
|
const raw = await (0, import_promises8.readFile)(path, "utf-8");
|
|
12245
12404
|
return JSON.parse(raw);
|
|
@@ -12247,12 +12406,12 @@ async function loadLastArtifact(startDir) {
|
|
|
12247
12406
|
throw new ScanNotFoundError(needsScanMessage(startDir));
|
|
12248
12407
|
}
|
|
12249
12408
|
}
|
|
12250
|
-
var import_promises8,
|
|
12409
|
+
var import_promises8, import_node_path12, SEVERITY_RANK2, ScanNotFoundError;
|
|
12251
12410
|
var init_menu = __esm({
|
|
12252
12411
|
"src/tui/menu.ts"() {
|
|
12253
12412
|
"use strict";
|
|
12254
12413
|
import_promises8 = require("node:fs/promises");
|
|
12255
|
-
|
|
12414
|
+
import_node_path12 = require("node:path");
|
|
12256
12415
|
init_config();
|
|
12257
12416
|
SEVERITY_RANK2 = {
|
|
12258
12417
|
critical: 0,
|
|
@@ -12268,228 +12427,6 @@ var init_menu = __esm({
|
|
|
12268
12427
|
}
|
|
12269
12428
|
});
|
|
12270
12429
|
|
|
12271
|
-
// src/resolveNextAction.ts
|
|
12272
|
-
function resolveNextAction(artifact) {
|
|
12273
|
-
const repoGap = sortGapsByPriority(artifact.gaps)[0];
|
|
12274
|
-
if (repoGap) {
|
|
12275
|
-
return {
|
|
12276
|
-
type: "repo-fix",
|
|
12277
|
-
title: repoGap.title,
|
|
12278
|
-
detail: repoGap.detail,
|
|
12279
|
-
command: `viberaven prompt --gap ${repoGap.id}`
|
|
12280
|
-
};
|
|
12281
|
-
}
|
|
12282
|
-
const manual = collectManualChecks(artifact)[0];
|
|
12283
|
-
if (manual) {
|
|
12284
|
-
const provider2 = mapCheckToPlaybook(manual.check);
|
|
12285
|
-
let openUrl;
|
|
12286
|
-
try {
|
|
12287
|
-
const playbook = loadPlaybookSync(provider2);
|
|
12288
|
-
openUrl = playbook.steps[0]?.openUrl;
|
|
12289
|
-
} catch {
|
|
12290
|
-
openUrl = void 0;
|
|
12291
|
-
}
|
|
12292
|
-
return {
|
|
12293
|
-
type: "provider-guide",
|
|
12294
|
-
title: manual.check.label,
|
|
12295
|
-
detail: manual.check.promptHint || `Configure ${manual.providerLabel} in the provider dashboard (${manual.areaLabel}).`,
|
|
12296
|
-
provider: provider2,
|
|
12297
|
-
playbookStep: 1,
|
|
12298
|
-
command: `viberaven guide ${provider2} --step 1`,
|
|
12299
|
-
openUrl
|
|
12300
|
-
};
|
|
12301
|
-
}
|
|
12302
|
-
return {
|
|
12303
|
-
type: "done",
|
|
12304
|
-
title: "No blockers found",
|
|
12305
|
-
detail: "Re-scan after changes to confirm production readiness."
|
|
12306
|
-
};
|
|
12307
|
-
}
|
|
12308
|
-
var init_resolveNextAction = __esm({
|
|
12309
|
-
"src/resolveNextAction.ts"() {
|
|
12310
|
-
"use strict";
|
|
12311
|
-
init_checkMap();
|
|
12312
|
-
init_loadPlaybook();
|
|
12313
|
-
init_manualChecks();
|
|
12314
|
-
init_menu();
|
|
12315
|
-
}
|
|
12316
|
-
});
|
|
12317
|
-
|
|
12318
|
-
// src/report/agentSummary.ts
|
|
12319
|
-
function sortGaps(gaps) {
|
|
12320
|
-
return [...gaps].sort((a, b3) => {
|
|
12321
|
-
const sev = SEVERITY_ORDER2[a.severity] - SEVERITY_ORDER2[b3.severity];
|
|
12322
|
-
if (sev !== 0) {
|
|
12323
|
-
return sev;
|
|
12324
|
-
}
|
|
12325
|
-
return a.title.localeCompare(b3.title);
|
|
12326
|
-
});
|
|
12327
|
-
}
|
|
12328
|
-
function generateAgentSummary(artifact) {
|
|
12329
|
-
const lines = [];
|
|
12330
|
-
const topGaps = sortGaps(artifact.gaps).slice(0, 8);
|
|
12331
|
-
lines.push("# VibeRaven agent summary", "");
|
|
12332
|
-
lines.push(`Scanned: \`${artifact.workspacePath}\``);
|
|
12333
|
-
lines.push(`At: ${artifact.scannedAt}`);
|
|
12334
|
-
lines.push(
|
|
12335
|
-
`Production core: **${artifact.productionCorePercent}%** \xB7 Model score: **${artifact.score}** (${artifact.scoreLabel})`
|
|
12336
|
-
);
|
|
12337
|
-
lines.push("");
|
|
12338
|
-
const next = resolveNextAction(artifact);
|
|
12339
|
-
lines.push("## Next action", "");
|
|
12340
|
-
lines.push(`**${next.title}** \u2014 ${next.detail}`);
|
|
12341
|
-
if (next.command) {
|
|
12342
|
-
lines.push(`Command: \`${next.command}\``);
|
|
12343
|
-
}
|
|
12344
|
-
lines.push("");
|
|
12345
|
-
lines.push("## Suggested stack", "");
|
|
12346
|
-
lines.push(
|
|
12347
|
-
"React + Tailwind + shadcn/ui + Supabase + Vercel (agent-default stack for lowest launch friction)"
|
|
12348
|
-
);
|
|
12349
|
-
lines.push("");
|
|
12350
|
-
lines.push("## Summary");
|
|
12351
|
-
lines.push(artifact.summary || "_No summary returned._");
|
|
12352
|
-
lines.push("");
|
|
12353
|
-
lines.push("## Mission map (repo wiring)");
|
|
12354
|
-
lines.push("");
|
|
12355
|
-
lines.push("| Area | Provider | Readiness | Notes |");
|
|
12356
|
-
lines.push("|------|----------|-----------|-------|");
|
|
12357
|
-
for (const area of artifact.missionGraph.areas ?? []) {
|
|
12358
|
-
for (const mission of area.providerMissions) {
|
|
12359
|
-
const failed = mission.checks.filter(
|
|
12360
|
-
(c) => c.status === "missing" || c.status === "failed" || c.status === "needs-connection"
|
|
12361
|
-
).length;
|
|
12362
|
-
const notes = failed > 0 ? `${failed} open check${failed === 1 ? "" : "s"}` : `${mission.readinessPercent}% repo checks`;
|
|
12363
|
-
lines.push(
|
|
12364
|
-
`| ${area.label} | ${mission.providerLabel} | ${mission.readinessPercent}% | ${notes} |`
|
|
12365
|
-
);
|
|
12366
|
-
}
|
|
12367
|
-
}
|
|
12368
|
-
lines.push("");
|
|
12369
|
-
lines.push("## Agent-code actions");
|
|
12370
|
-
if (topGaps.length === 0) {
|
|
12371
|
-
lines.push("_No model gaps returned. Review mission map checks before changing code._");
|
|
12372
|
-
} else {
|
|
12373
|
-
topGaps.forEach((gap, index) => {
|
|
12374
|
-
lines.push(
|
|
12375
|
-
`${index + 1}. **${gap.title}** (\`${gap.id}\`, ${gap.severity}, map: \`${gap.primaryMapCategory}\`)`
|
|
12376
|
-
);
|
|
12377
|
-
lines.push(` - ${gap.detail}`);
|
|
12378
|
-
lines.push(` - Command: \`viberaven prompt --gap ${gap.id}\``);
|
|
12379
|
-
if (gap.copyPrompt) {
|
|
12380
|
-
lines.push(` - Prompt: ${gap.copyPrompt}`);
|
|
12381
|
-
}
|
|
12382
|
-
});
|
|
12383
|
-
}
|
|
12384
|
-
const manualChecks = (artifact.missionGraph.areas ?? []).flatMap(
|
|
12385
|
-
(area) => area.providerMissions.flatMap(
|
|
12386
|
-
(mission) => mission.checks.filter(
|
|
12387
|
-
(check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
|
|
12388
|
-
).map((check) => ({ area: area.label, provider: mission.providerLabel, check }))
|
|
12389
|
-
)
|
|
12390
|
-
);
|
|
12391
|
-
lines.push("");
|
|
12392
|
-
lines.push("## Human-provider actions");
|
|
12393
|
-
if (manualChecks.length === 0) {
|
|
12394
|
-
lines.push("_No manual provider actions were identified in this scan._");
|
|
12395
|
-
} else {
|
|
12396
|
-
manualChecks.slice(0, 8).forEach((item4, index) => {
|
|
12397
|
-
lines.push(`${index + 1}. **${item4.check.label}** (${item4.area} / ${item4.provider})`);
|
|
12398
|
-
lines.push(
|
|
12399
|
-
` - ${item4.check.promptHint || "Ask the user to confirm this in the provider dashboard or through read-only MCP."}`
|
|
12400
|
-
);
|
|
12401
|
-
});
|
|
12402
|
-
}
|
|
12403
|
-
lines.push("");
|
|
12404
|
-
lines.push("Do not claim human-provider actions as repo-code fixes.");
|
|
12405
|
-
lines.push("");
|
|
12406
|
-
lines.push("## Agent workflow");
|
|
12407
|
-
lines.push("1. Read `.viberaven/agent-tasklist.md` first for the production gate.");
|
|
12408
|
-
lines.push("2. Read `.viberaven/launch-playbook.md` for the full checklist.");
|
|
12409
|
-
lines.push("3. Run `viberaven next --json` - one action at a time.");
|
|
12410
|
-
lines.push("4. Repo fix: `viberaven prompt --gap <id>` then implement.");
|
|
12411
|
-
lines.push("5. Provider: `viberaven guide <provider> --step N` and `viberaven open <provider>`.");
|
|
12412
|
-
lines.push(`6. Run \`${PUBLIC_VERIFY_COMMAND}\` to rescan and refresh \`.viberaven/agent-tasklist.md\`.`);
|
|
12413
|
-
lines.push("");
|
|
12414
|
-
return `${lines.join("\n")}
|
|
12415
|
-
`;
|
|
12416
|
-
}
|
|
12417
|
-
var SEVERITY_ORDER2;
|
|
12418
|
-
var init_agentSummary = __esm({
|
|
12419
|
-
"src/report/agentSummary.ts"() {
|
|
12420
|
-
"use strict";
|
|
12421
|
-
init_commands();
|
|
12422
|
-
init_resolveNextAction();
|
|
12423
|
-
SEVERITY_ORDER2 = {
|
|
12424
|
-
critical: 0,
|
|
12425
|
-
warning: 1,
|
|
12426
|
-
info: 2
|
|
12427
|
-
};
|
|
12428
|
-
}
|
|
12429
|
-
});
|
|
12430
|
-
|
|
12431
|
-
// src/heal/rlsMigrationTarget.ts
|
|
12432
|
-
function rlsEnableStatements(tables) {
|
|
12433
|
-
return [...new Set(tables)].map((table2) => `alter table ${table2} enable row level security;`);
|
|
12434
|
-
}
|
|
12435
|
-
function migrationStamp(now) {
|
|
12436
|
-
return now.toISOString().replace(/\D/g, "").slice(0, 14);
|
|
12437
|
-
}
|
|
12438
|
-
function rlsMigrationTarget(cwd, evidence, now = /* @__PURE__ */ new Date()) {
|
|
12439
|
-
if (evidence.length === 0) return { ok: false, reason: "No table without row level security was found in the repo SQL." };
|
|
12440
|
-
const statementList = rlsEnableStatements(evidence.map((entry) => entry.table)).join(" ");
|
|
12441
|
-
const turnedOff = evidence.filter((entry) => entry.turnedOff);
|
|
12442
|
-
if (turnedOff.length > 0) {
|
|
12443
|
-
const where = turnedOff.map((entry) => `${entry.table} (${entry.file.replace(/\\/g, "/")})`).join(", ");
|
|
12444
|
-
return {
|
|
12445
|
-
ok: false,
|
|
12446
|
-
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}`
|
|
12447
|
-
};
|
|
12448
|
-
}
|
|
12449
|
-
const source = evidence[0].file.replace(/\\/g, "/");
|
|
12450
|
-
const dir = import_node_path11.posix.dirname(source);
|
|
12451
|
-
if (import_node_path11.posix.basename(dir) !== "migrations") {
|
|
12452
|
-
return {
|
|
12453
|
-
ok: false,
|
|
12454
|
-
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}`
|
|
12455
|
-
};
|
|
12456
|
-
}
|
|
12457
|
-
let existing;
|
|
12458
|
-
try {
|
|
12459
|
-
existing = (0, import_node_fs6.readdirSync)((0, import_node_path11.join)(cwd, dir)).filter((file) => file.endsWith(".sql")).sort();
|
|
12460
|
-
} catch {
|
|
12461
|
-
return { ok: false, reason: `VibeRaven could not read ${dir}. Add these statements by hand in a new migration: ${statementList}` };
|
|
12462
|
-
}
|
|
12463
|
-
const otherNaming = existing.find((file) => !TIMESTAMPED_MIGRATION.test(file));
|
|
12464
|
-
if (otherNaming) {
|
|
12465
|
-
return {
|
|
12466
|
-
ok: false,
|
|
12467
|
-
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}`
|
|
12468
|
-
};
|
|
12469
|
-
}
|
|
12470
|
-
const name = `${migrationStamp(now)}_viberaven_enable_rls.sql`;
|
|
12471
|
-
const last = existing[existing.length - 1];
|
|
12472
|
-
if (last && name <= last) {
|
|
12473
|
-
return {
|
|
12474
|
-
ok: false,
|
|
12475
|
-
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}`
|
|
12476
|
-
};
|
|
12477
|
-
}
|
|
12478
|
-
return { ok: true, file: `${dir}/${name}` };
|
|
12479
|
-
}
|
|
12480
|
-
var import_node_fs6, import_node_path11, RLS_TURNED_OFF_PHRASE, RLS_ASK_FIRST, RLS_NO_POLICIES_WARNING, TIMESTAMPED_MIGRATION;
|
|
12481
|
-
var init_rlsMigrationTarget = __esm({
|
|
12482
|
-
"src/heal/rlsMigrationTarget.ts"() {
|
|
12483
|
-
"use strict";
|
|
12484
|
-
import_node_fs6 = require("node:fs");
|
|
12485
|
-
import_node_path11 = require("node:path");
|
|
12486
|
-
RLS_TURNED_OFF_PHRASE = "has row level security turned off at";
|
|
12487
|
-
RLS_ASK_FIRST = "Ask the user first: enabling RLS without policies makes browser reads return no rows until policies exist.";
|
|
12488
|
-
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.";
|
|
12489
|
-
TIMESTAMPED_MIGRATION = /^\d{14}_.+\.sql$/;
|
|
12490
|
-
}
|
|
12491
|
-
});
|
|
12492
|
-
|
|
12493
12430
|
// src/buildTaskList.ts
|
|
12494
12431
|
function rlsMigrationFile(gap) {
|
|
12495
12432
|
if (gap.id !== "rls_disabled" || typeof gap.detail !== "string") return void 0;
|
|
@@ -12508,7 +12445,12 @@ function hasRecipe(gapId) {
|
|
|
12508
12445
|
const lower = gapId.toLowerCase();
|
|
12509
12446
|
return lower.includes("empty") && lower.includes("catch");
|
|
12510
12447
|
}
|
|
12511
|
-
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) {
|
|
12512
12454
|
const cat = gap.primaryMapCategory.toLowerCase();
|
|
12513
12455
|
if (cat === "deployment") return "vercel";
|
|
12514
12456
|
if (cat === "payments") return "stripe";
|
|
@@ -12521,9 +12463,9 @@ function gapToPlaybookProvider(gap) {
|
|
|
12521
12463
|
if (id.includes("auth")) return "auth-supabase";
|
|
12522
12464
|
return void 0;
|
|
12523
12465
|
}
|
|
12524
|
-
function hasPlaybook(gap) {
|
|
12466
|
+
function hasPlaybook(gap, inRepo) {
|
|
12525
12467
|
try {
|
|
12526
|
-
const provider2 = gapToPlaybookProvider(gap);
|
|
12468
|
+
const provider2 = gapToPlaybookProvider(gap, inRepo);
|
|
12527
12469
|
if (!provider2) return false;
|
|
12528
12470
|
return PLAYBOOK_PROVIDERS.includes(provider2);
|
|
12529
12471
|
} catch {
|
|
@@ -12553,13 +12495,20 @@ function buildProviderAction(gap, provider2) {
|
|
|
12553
12495
|
}
|
|
12554
12496
|
function buildTaskList(artifact) {
|
|
12555
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;
|
|
12556
12500
|
return sorted.map((gap, index) => {
|
|
12557
12501
|
const id = `TASK-${String(index + 1).padStart(3, "0")}`;
|
|
12558
12502
|
let fixType;
|
|
12559
12503
|
const migrationFile = rlsMigrationFile(gap);
|
|
12560
|
-
|
|
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) {
|
|
12561
12508
|
fixType = "repo-code";
|
|
12562
|
-
} else if (
|
|
12509
|
+
} else if (informational) {
|
|
12510
|
+
fixType = "manual-verify";
|
|
12511
|
+
} else if (hasPlaybook(gap, inRepo)) {
|
|
12563
12512
|
fixType = "provider-action";
|
|
12564
12513
|
} else {
|
|
12565
12514
|
fixType = "manual-verify";
|
|
@@ -12576,6 +12525,8 @@ function buildTaskList(artifact) {
|
|
|
12576
12525
|
if (fixType === "repo-code" && !hasRecipe(gap.id) && migrationFile) {
|
|
12577
12526
|
base.requiresUserAction = true;
|
|
12578
12527
|
base.file = migrationFile;
|
|
12528
|
+
base.userSteps = [APPLY_MIGRATION];
|
|
12529
|
+
if (location?.file === migrationFile && location.line !== void 0) base.line = location.line;
|
|
12579
12530
|
const target = rlsMigrationTarget(artifact.workspacePath, rlsEvidence2(gap.detail));
|
|
12580
12531
|
if (target.ok) {
|
|
12581
12532
|
base.mcpTool = "viberaven_heal_apply";
|
|
@@ -12587,6 +12538,28 @@ function buildTaskList(artifact) {
|
|
|
12587
12538
|
if (gap.copyPrompt) {
|
|
12588
12539
|
base.exactFix = gap.copyPrompt.trim();
|
|
12589
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
|
+
}
|
|
12590
12563
|
} else if (fixType === "repo-code") {
|
|
12591
12564
|
base.mcpTool = "viberaven_heal_apply";
|
|
12592
12565
|
base.mcpArgs = { gap: gap.id, yes: true };
|
|
@@ -12596,7 +12569,7 @@ function buildTaskList(artifact) {
|
|
|
12596
12569
|
}
|
|
12597
12570
|
} else if (fixType === "provider-action") {
|
|
12598
12571
|
try {
|
|
12599
|
-
const provider2 = gapToPlaybookProvider(gap);
|
|
12572
|
+
const provider2 = gapToPlaybookProvider(gap, inRepo);
|
|
12600
12573
|
if (provider2) {
|
|
12601
12574
|
const pa = buildProviderAction(gap, provider2);
|
|
12602
12575
|
if (pa) {
|
|
@@ -12614,7 +12587,7 @@ function buildTaskList(artifact) {
|
|
|
12614
12587
|
}
|
|
12615
12588
|
function buildTaskListMarkdown(tasks) {
|
|
12616
12589
|
if (tasks.length === 0) {
|
|
12617
|
-
return "# VibeRaven Agent Tasklist\n\n_No gaps found
|
|
12590
|
+
return "# VibeRaven Agent Tasklist\n\n_No gaps found in this scan._\n";
|
|
12618
12591
|
}
|
|
12619
12592
|
const lines = ["# VibeRaven Agent Tasklist", ""];
|
|
12620
12593
|
for (const task of tasks) {
|
|
@@ -12622,7 +12595,7 @@ function buildTaskListMarkdown(tasks) {
|
|
|
12622
12595
|
lines.push(`## ${task.id} \xB7 ${task.gapId} \xB7 ${severityLabel}`, "");
|
|
12623
12596
|
lines.push(`**Fix type:** ${task.fixType} `);
|
|
12624
12597
|
if (task.file) {
|
|
12625
|
-
lines.push(`**File:** \`${task.file}\` `);
|
|
12598
|
+
lines.push(`**File:** \`${task.file}${task.line !== void 0 ? `:${task.line}` : ""}\` `);
|
|
12626
12599
|
}
|
|
12627
12600
|
if (task.action) {
|
|
12628
12601
|
lines.push(`**Action:** ${task.action} `);
|
|
@@ -12630,62 +12603,387 @@ function buildTaskListMarkdown(tasks) {
|
|
|
12630
12603
|
if (task.exactFix) {
|
|
12631
12604
|
lines.push(`**Exact fix:** ${task.exactFix} `);
|
|
12632
12605
|
} else {
|
|
12633
|
-
lines.push(`**Exact fix:** No automated recipe
|
|
12606
|
+
lines.push(`**Exact fix:** No automated recipe; see the scanner hint in the gap detail. `);
|
|
12634
12607
|
}
|
|
12635
12608
|
lines.push(`**Verify:** \`${task.verifyCommand}\` `);
|
|
12636
12609
|
if (task.mcpTool && task.mcpArgs) {
|
|
12637
12610
|
lines.push(
|
|
12638
|
-
`**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}\`)`
|
|
12639
12934
|
);
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
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
|
+
});
|
|
12654
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("");
|
|
12655
12972
|
return `${lines.join("\n")}
|
|
12656
12973
|
`;
|
|
12657
12974
|
}
|
|
12658
|
-
var
|
|
12659
|
-
var
|
|
12660
|
-
"src/
|
|
12975
|
+
var SEVERITY_ORDER2;
|
|
12976
|
+
var init_agentSummary = __esm({
|
|
12977
|
+
"src/report/agentSummary.ts"() {
|
|
12661
12978
|
"use strict";
|
|
12662
12979
|
init_commands();
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
"empty_catch",
|
|
12671
|
-
"emptyCatch",
|
|
12672
|
-
// W3 env-add recipes
|
|
12673
|
-
"auth_secret_missing",
|
|
12674
|
-
"node_env_not_set",
|
|
12675
|
-
"database_url_missing",
|
|
12676
|
-
// W3 file-create recipes
|
|
12677
|
-
"missing_error_boundary",
|
|
12678
|
-
"missing_health_route",
|
|
12679
|
-
"missing_loading_state",
|
|
12680
|
-
"missing_404_page",
|
|
12681
|
-
// W3 file-patch recipes
|
|
12682
|
-
"missing_csp_header",
|
|
12683
|
-
"missing_rate_limit",
|
|
12684
|
-
"eslint_restricted_imports"
|
|
12685
|
-
// NOTE: 'rls_disabled' is intentionally NOT here. When the finding comes from repo SQL it is a repo action whose
|
|
12686
|
-
// recipe writes a new migration (see rlsMigrationFile and heal/recipes/supabaseRls.ts); without SQL evidence it
|
|
12687
|
-
// stays a provider action and heal refuses.
|
|
12688
|
-
]);
|
|
12980
|
+
init_resolveNextAction();
|
|
12981
|
+
init_inRepoMissions();
|
|
12982
|
+
SEVERITY_ORDER2 = {
|
|
12983
|
+
critical: 0,
|
|
12984
|
+
warning: 1,
|
|
12985
|
+
info: 2
|
|
12986
|
+
};
|
|
12689
12987
|
}
|
|
12690
12988
|
});
|
|
12691
12989
|
|
|
@@ -12695,12 +12993,21 @@ function generateLaunchPlaybook(artifact) {
|
|
|
12695
12993
|
lines.push("# VibeRaven launch playbook", "");
|
|
12696
12994
|
lines.push(`Generated from scan at ${artifact.scannedAt}. Work top to bottom.`, "");
|
|
12697
12995
|
lines.push("## Repo fixes (agent code)", "");
|
|
12698
|
-
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]);
|
|
12699
12999
|
if (repoGaps.length === 0) {
|
|
12700
13000
|
lines.push("_No repo-code gaps found._", "");
|
|
12701
13001
|
} else {
|
|
12702
13002
|
for (const gap of repoGaps) {
|
|
12703
|
-
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]}`);
|
|
12704
13011
|
}
|
|
12705
13012
|
lines.push("");
|
|
12706
13013
|
}
|
|
@@ -12712,7 +13019,7 @@ function generateLaunchPlaybook(artifact) {
|
|
|
12712
13019
|
for (const item4 of manuals) {
|
|
12713
13020
|
const provider2 = mapCheckToPlaybook(item4.check);
|
|
12714
13021
|
lines.push(
|
|
12715
|
-
`- [ ] ${item4.check.label} (${item4.areaLabel})
|
|
13022
|
+
provider2 ? `- [ ] ${item4.check.label} (${item4.areaLabel}): \`viberaven guide ${provider2} --step 1\`` : `- [ ] ${item4.check.label} (${item4.areaLabel})`
|
|
12716
13023
|
);
|
|
12717
13024
|
}
|
|
12718
13025
|
lines.push("");
|
|
@@ -12733,6 +13040,7 @@ var init_launchPlaybook = __esm({
|
|
|
12733
13040
|
init_manualChecks();
|
|
12734
13041
|
init_menu();
|
|
12735
13042
|
init_commands();
|
|
13043
|
+
init_repoFixes();
|
|
12736
13044
|
}
|
|
12737
13045
|
});
|
|
12738
13046
|
|
|
@@ -13061,25 +13369,25 @@ var init_reportHtml = __esm({
|
|
|
13061
13369
|
function getBundledReportAssetsDir() {
|
|
13062
13370
|
const base = __dirname;
|
|
13063
13371
|
const candidates = [
|
|
13064
|
-
(0,
|
|
13065
|
-
(0,
|
|
13066
|
-
(0,
|
|
13067
|
-
(0,
|
|
13068
|
-
(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")
|
|
13069
13377
|
];
|
|
13070
13378
|
for (const dir of candidates) {
|
|
13071
|
-
if ((0,
|
|
13379
|
+
if ((0, import_node_fs8.existsSync)((0, import_node_path13.join)(dir, "station.css"))) {
|
|
13072
13380
|
return dir;
|
|
13073
13381
|
}
|
|
13074
13382
|
}
|
|
13075
13383
|
throw new Error("Report assets missing. Run `npm run sync-report-assets` and `npm run build` in packages/cli.");
|
|
13076
13384
|
}
|
|
13077
|
-
var
|
|
13385
|
+
var import_node_fs8, import_node_path13, REPORT_ASSET_FILES;
|
|
13078
13386
|
var init_reportAssets = __esm({
|
|
13079
13387
|
"src/report/reportAssets.ts"() {
|
|
13080
13388
|
"use strict";
|
|
13081
|
-
|
|
13082
|
-
|
|
13389
|
+
import_node_fs8 = require("node:fs");
|
|
13390
|
+
import_node_path13 = require("node:path");
|
|
13083
13391
|
REPORT_ASSET_FILES = [
|
|
13084
13392
|
"station.css",
|
|
13085
13393
|
"station.js",
|
|
@@ -13267,9 +13575,10 @@ function deriveRepoCodeAction(task) {
|
|
|
13267
13575
|
gapId: task.gapId,
|
|
13268
13576
|
readiness: [...askFirst ? [askFirst] : [], task.exactFix ?? "Repo-code fix is available"],
|
|
13269
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}` },
|
|
13270
|
-
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,
|
|
13271
13579
|
verifyCommand: verifyActionCommand("pending"),
|
|
13272
|
-
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] } : {},
|
|
13273
13582
|
mcpTool: task.mcpTool,
|
|
13274
13583
|
mcpArgs: task.mcpArgs,
|
|
13275
13584
|
// Only a gap with an automatic recipe has a heal-apply fallback, and a task that needs the user's yes keeps it
|
|
@@ -13278,7 +13587,7 @@ function deriveRepoCodeAction(task) {
|
|
|
13278
13587
|
...task.requiresUserAction ? { requiresUserAction: true } : {}
|
|
13279
13588
|
};
|
|
13280
13589
|
}
|
|
13281
|
-
function deriveVerifyAction() {
|
|
13590
|
+
function deriveVerifyAction(waiting) {
|
|
13282
13591
|
return {
|
|
13283
13592
|
id: "pending",
|
|
13284
13593
|
actionKey: buildActionKey({
|
|
@@ -13290,8 +13599,9 @@ function deriveVerifyAction() {
|
|
|
13290
13599
|
revision: 1,
|
|
13291
13600
|
kind: "verify",
|
|
13292
13601
|
title: "Run Final Verification",
|
|
13293
|
-
|
|
13294
|
-
|
|
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"],
|
|
13295
13605
|
target: { type: "command", label: "Final strict gate", command: `${PUBLIC_COMMAND} --strict` },
|
|
13296
13606
|
verifyCommand: `${PUBLIC_COMMAND} --strict`,
|
|
13297
13607
|
resumeInstruction: "Final verification finished. Continue VibeRaven from pending."
|
|
@@ -13299,7 +13609,7 @@ function deriveVerifyAction() {
|
|
|
13299
13609
|
}
|
|
13300
13610
|
function deriveCurrentActions(input) {
|
|
13301
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));
|
|
13302
|
-
return [...primaryActions, deriveVerifyAction()];
|
|
13612
|
+
return [...primaryActions, deriveVerifyAction(primaryActions.length > 0)];
|
|
13303
13613
|
}
|
|
13304
13614
|
var init_derive = __esm({
|
|
13305
13615
|
"src/actions/derive.ts"() {
|
|
@@ -13314,7 +13624,7 @@ function emptyActionRegistry() {
|
|
|
13314
13624
|
return { version: 1, nextId: 1, actions: {} };
|
|
13315
13625
|
}
|
|
13316
13626
|
function actionRegistryPath(cwd) {
|
|
13317
|
-
return (0,
|
|
13627
|
+
return (0, import_node_path14.join)(getProjectArtifactsDir(cwd), "action-registry.json");
|
|
13318
13628
|
}
|
|
13319
13629
|
async function loadActionRegistry(cwd) {
|
|
13320
13630
|
try {
|
|
@@ -13386,7 +13696,8 @@ async function assignActionIds(input) {
|
|
|
13386
13696
|
title: action.title,
|
|
13387
13697
|
gapId: action.gapId,
|
|
13388
13698
|
kind: action.kind,
|
|
13389
|
-
provider: action.provider
|
|
13699
|
+
provider: action.provider,
|
|
13700
|
+
...action.userSteps?.length ? { userSteps: [...action.userSteps] } : {}
|
|
13390
13701
|
};
|
|
13391
13702
|
} else {
|
|
13392
13703
|
entry.status = "active";
|
|
@@ -13395,6 +13706,9 @@ async function assignActionIds(input) {
|
|
|
13395
13706
|
entry.gapId = action.gapId;
|
|
13396
13707
|
entry.kind = action.kind;
|
|
13397
13708
|
entry.provider = action.provider;
|
|
13709
|
+
if (action.userSteps?.length) entry.userSteps = [...action.userSteps];
|
|
13710
|
+
else delete entry.userSteps;
|
|
13711
|
+
delete entry.followUpShownAt;
|
|
13398
13712
|
if (entry.fingerprint !== fingerprint) {
|
|
13399
13713
|
entry.revision += 1;
|
|
13400
13714
|
entry.fingerprint = fingerprint;
|
|
@@ -13418,16 +13732,27 @@ async function assignActionIds(input) {
|
|
|
13418
13732
|
await saveActionRegistry(input.cwd, registry);
|
|
13419
13733
|
return { actions, registry };
|
|
13420
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
|
+
}
|
|
13421
13746
|
async function resolveActionById(cwd, id) {
|
|
13422
13747
|
const registry = await loadActionRegistry(cwd);
|
|
13423
13748
|
return Object.values(registry.actions).find((entry) => entry.id === id);
|
|
13424
13749
|
}
|
|
13425
|
-
var import_promises9,
|
|
13750
|
+
var import_promises9, import_node_path14;
|
|
13426
13751
|
var init_registry2 = __esm({
|
|
13427
13752
|
"src/actions/registry.ts"() {
|
|
13428
13753
|
"use strict";
|
|
13429
13754
|
import_promises9 = require("node:fs/promises");
|
|
13430
|
-
|
|
13755
|
+
import_node_path14 = require("node:path");
|
|
13431
13756
|
init_config();
|
|
13432
13757
|
init_canonical();
|
|
13433
13758
|
}
|
|
@@ -13438,7 +13763,7 @@ function gateStatus2(artifact) {
|
|
|
13438
13763
|
if (!Array.isArray(artifact.gaps)) {
|
|
13439
13764
|
return "unknown";
|
|
13440
13765
|
}
|
|
13441
|
-
return artifact.gaps
|
|
13766
|
+
return gateStatusForGaps(artifact.gaps);
|
|
13442
13767
|
}
|
|
13443
13768
|
async function writeActionArtifacts(input) {
|
|
13444
13769
|
const derived = deriveCurrentActions({
|
|
@@ -13459,7 +13784,9 @@ async function writeActionArtifacts(input) {
|
|
|
13459
13784
|
gateStatus: gateStatus2(input.artifact),
|
|
13460
13785
|
actions: assigned.actions
|
|
13461
13786
|
};
|
|
13462
|
-
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");
|
|
13463
13790
|
await (0, import_promises10.writeFile)(actionsPath, `${JSON.stringify(manifest, null, 2)}
|
|
13464
13791
|
`, "utf8");
|
|
13465
13792
|
return {
|
|
@@ -13468,13 +13795,14 @@ async function writeActionArtifacts(input) {
|
|
|
13468
13795
|
manifest
|
|
13469
13796
|
};
|
|
13470
13797
|
}
|
|
13471
|
-
var import_promises10,
|
|
13798
|
+
var import_promises10, import_node_path15;
|
|
13472
13799
|
var init_artifacts = __esm({
|
|
13473
13800
|
"src/actions/artifacts.ts"() {
|
|
13474
13801
|
"use strict";
|
|
13475
13802
|
import_promises10 = require("node:fs/promises");
|
|
13476
|
-
|
|
13803
|
+
import_node_path15 = require("node:path");
|
|
13477
13804
|
init_config();
|
|
13805
|
+
init_gateResult();
|
|
13478
13806
|
init_derive();
|
|
13479
13807
|
init_registry2();
|
|
13480
13808
|
}
|
|
@@ -13483,24 +13811,47 @@ var init_artifacts = __esm({
|
|
|
13483
13811
|
// src/artifacts.ts
|
|
13484
13812
|
async function copyReportAssets(reportAssetsDir) {
|
|
13485
13813
|
const sourceDir = getBundledReportAssetsDir();
|
|
13486
|
-
await (0, import_promises11.mkdir)((0,
|
|
13814
|
+
await (0, import_promises11.mkdir)((0, import_node_path16.join)(reportAssetsDir, "assets"), { recursive: true });
|
|
13487
13815
|
for (const rel of REPORT_ASSET_FILES) {
|
|
13488
|
-
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
|
+
}
|
|
13489
13840
|
}
|
|
13490
13841
|
}
|
|
13491
13842
|
async function writeScanArtifacts(options) {
|
|
13492
13843
|
const cwd = options.cwd ?? options.artifact.workspacePath;
|
|
13493
13844
|
const dir = getProjectArtifactsDir(cwd);
|
|
13494
13845
|
await (0, import_promises11.mkdir)(dir, { recursive: true });
|
|
13495
|
-
const jsonPath = (0,
|
|
13496
|
-
const gateResultPath = (0,
|
|
13497
|
-
const contextMapPath = (0,
|
|
13498
|
-
const gapsDir = (0,
|
|
13499
|
-
const tasklistPath = (0,
|
|
13500
|
-
const summaryPath = (0,
|
|
13501
|
-
const playbookPath = (0,
|
|
13502
|
-
const reportPath = (0,
|
|
13503
|
-
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");
|
|
13504
13855
|
await (0, import_promises11.mkdir)(gapsDir, { recursive: true });
|
|
13505
13856
|
const safe2 = sanitizeArtifactForDisk(options.artifact);
|
|
13506
13857
|
const json = `${JSON.stringify(safe2, null, 2)}
|
|
@@ -13510,26 +13861,27 @@ async function writeScanArtifacts(options) {
|
|
|
13510
13861
|
const html = generateReportHtml(safe2);
|
|
13511
13862
|
const tasks = buildTaskList(safe2);
|
|
13512
13863
|
const tasklist = buildTaskListMarkdown(tasks);
|
|
13513
|
-
const
|
|
13864
|
+
const packageManager = detectPackageManager(options.artifact.workspacePath);
|
|
13865
|
+
const gateResult = `${JSON.stringify(generateGateResult(safe2, { packageManager }), null, 2)}
|
|
13514
13866
|
`;
|
|
13515
|
-
const contextMap = `${JSON.stringify(generateContextMap(safe2), null, 2)}
|
|
13867
|
+
const contextMap = `${JSON.stringify(generateContextMap(safe2, { packageManager }), null, 2)}
|
|
13516
13868
|
`;
|
|
13517
13869
|
const gapEvidenceFiles = generateGapEvidenceFiles(safe2);
|
|
13518
13870
|
await copyReportAssets(reportAssetsDir);
|
|
13519
13871
|
await (0, import_promises11.writeFile)(gateResultPath, gateResult, "utf-8");
|
|
13520
13872
|
await (0, import_promises11.writeFile)(contextMapPath, contextMap, "utf-8");
|
|
13521
13873
|
for (const gap of gapEvidenceFiles) {
|
|
13522
|
-
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)}
|
|
13523
13875
|
`, "utf-8");
|
|
13524
13876
|
}
|
|
13525
13877
|
await (0, import_promises11.writeFile)(tasklistPath, tasklist, "utf-8");
|
|
13526
13878
|
let architectureMapPath;
|
|
13527
13879
|
if (typeof safe2.architectureMap === "string" && safe2.architectureMap.length > 0) {
|
|
13528
|
-
architectureMapPath = (0,
|
|
13880
|
+
architectureMapPath = (0, import_node_path16.join)(dir, "architecture-map.md");
|
|
13529
13881
|
await (0, import_promises11.writeFile)(architectureMapPath, safe2.architectureMap, "utf-8");
|
|
13530
13882
|
}
|
|
13531
13883
|
if (safe2.architectureData) {
|
|
13532
|
-
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)}
|
|
13533
13885
|
`, "utf-8");
|
|
13534
13886
|
}
|
|
13535
13887
|
await (0, import_promises11.writeFile)(jsonPath, json, "utf-8");
|
|
@@ -13542,6 +13894,7 @@ async function writeScanArtifacts(options) {
|
|
|
13542
13894
|
tasks,
|
|
13543
13895
|
paths: { reportPath, playbookPath }
|
|
13544
13896
|
});
|
|
13897
|
+
await removeStaleGapFiles(gapsDir, new Set(gapEvidenceFiles.map((gap) => `${gap.content.id}.json`)));
|
|
13545
13898
|
return {
|
|
13546
13899
|
dir,
|
|
13547
13900
|
jsonPath,
|
|
@@ -13558,14 +13911,15 @@ async function writeScanArtifacts(options) {
|
|
|
13558
13911
|
...architectureMapPath ? { architectureMapPath } : {}
|
|
13559
13912
|
};
|
|
13560
13913
|
}
|
|
13561
|
-
var import_promises11,
|
|
13914
|
+
var import_promises11, import_node_path16, GAP_SCHEMA;
|
|
13562
13915
|
var init_artifacts2 = __esm({
|
|
13563
13916
|
"src/artifacts.ts"() {
|
|
13564
13917
|
"use strict";
|
|
13565
13918
|
import_promises11 = require("node:fs/promises");
|
|
13566
|
-
|
|
13919
|
+
import_node_path16 = require("node:path");
|
|
13567
13920
|
init_contextMap();
|
|
13568
13921
|
init_gateResult();
|
|
13922
|
+
init_packageManager();
|
|
13569
13923
|
init_gapEvidence();
|
|
13570
13924
|
init_agentSummary();
|
|
13571
13925
|
init_buildTaskList();
|
|
@@ -13575,6 +13929,7 @@ var init_artifacts2 = __esm({
|
|
|
13575
13929
|
init_config();
|
|
13576
13930
|
init_sanitizeArtifact();
|
|
13577
13931
|
init_artifacts();
|
|
13932
|
+
GAP_SCHEMA = "https://viberaven.dev/schemas/gap.schema.json";
|
|
13578
13933
|
}
|
|
13579
13934
|
});
|
|
13580
13935
|
|
|
@@ -13672,12 +14027,12 @@ function createAppWindowOpenCommands(target, platform = process.platform, env =
|
|
|
13672
14027
|
];
|
|
13673
14028
|
if (platform === "win32") {
|
|
13674
14029
|
const candidates = [
|
|
13675
|
-
env.LOCALAPPDATA ? (0,
|
|
13676
|
-
env.PROGRAMFILES ? (0,
|
|
13677
|
-
env["PROGRAMFILES(X86)"] ? (0,
|
|
13678
|
-
env.LOCALAPPDATA ? (0,
|
|
13679
|
-
env.PROGRAMFILES ? (0,
|
|
13680
|
-
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") : "",
|
|
13681
14036
|
"chrome",
|
|
13682
14037
|
"msedge"
|
|
13683
14038
|
].filter(Boolean);
|
|
@@ -13711,7 +14066,7 @@ async function openWithSystemDefault(target) {
|
|
|
13711
14066
|
});
|
|
13712
14067
|
}
|
|
13713
14068
|
async function spawnDetached(command) {
|
|
13714
|
-
if (/^[A-Za-z]:[\\/]/.test(command.command) && !(0,
|
|
14069
|
+
if (/^[A-Za-z]:[\\/]/.test(command.command) && !(0, import_node_fs9.existsSync)(command.command)) {
|
|
13715
14070
|
throw new Error(`Browser not found: ${command.command}`);
|
|
13716
14071
|
}
|
|
13717
14072
|
await new Promise((resolve10, reject) => {
|
|
@@ -13754,13 +14109,13 @@ async function openUrlInBrowser(url) {
|
|
|
13754
14109
|
}
|
|
13755
14110
|
await openWithSystemDefault(trimmed);
|
|
13756
14111
|
}
|
|
13757
|
-
var import_node_child_process4,
|
|
14112
|
+
var import_node_child_process4, import_node_fs9, import_node_path17;
|
|
13758
14113
|
var init_openBrowser = __esm({
|
|
13759
14114
|
"src/openBrowser.ts"() {
|
|
13760
14115
|
"use strict";
|
|
13761
14116
|
import_node_child_process4 = require("node:child_process");
|
|
13762
|
-
|
|
13763
|
-
|
|
14117
|
+
import_node_fs9 = require("node:fs");
|
|
14118
|
+
import_node_path17 = require("node:path");
|
|
13764
14119
|
}
|
|
13765
14120
|
});
|
|
13766
14121
|
|
|
@@ -13817,9 +14172,9 @@ var init_clipboard = __esm({
|
|
|
13817
14172
|
}
|
|
13818
14173
|
});
|
|
13819
14174
|
|
|
13820
|
-
//
|
|
14175
|
+
// node_modules/picocolors/picocolors.js
|
|
13821
14176
|
var require_picocolors = __commonJS({
|
|
13822
|
-
"
|
|
14177
|
+
"node_modules/picocolors/picocolors.js"(exports2, module2) {
|
|
13823
14178
|
var p2 = process || {};
|
|
13824
14179
|
var argv = p2.argv || [];
|
|
13825
14180
|
var env = p2.env || {};
|
|
@@ -13889,46 +14244,6 @@ var require_picocolors = __commonJS({
|
|
|
13889
14244
|
}
|
|
13890
14245
|
});
|
|
13891
14246
|
|
|
13892
|
-
// src/report/missionSelection.ts
|
|
13893
|
-
function normalizeProviderToken2(value) {
|
|
13894
|
-
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "");
|
|
13895
|
-
}
|
|
13896
|
-
function missionMatchesProvider(mission, provider2) {
|
|
13897
|
-
const current = normalizeProviderToken2(provider2);
|
|
13898
|
-
return normalizeProviderToken2(mission.provider || mission.providerLabel || mission.key) === current || normalizeProviderToken2(mission.providerLabel || mission.provider || mission.key) === current;
|
|
13899
|
-
}
|
|
13900
|
-
function missionEvidenceScore(mission) {
|
|
13901
|
-
const repoVerified = mission.checks.filter((check) => check.evidenceClass === "repo-verified" || check.status === "passed").length;
|
|
13902
|
-
const missing = mission.checks.filter(
|
|
13903
|
-
(check) => check.evidenceClass === "missing-repo-fix" || check.status === "missing" || check.status === "failed"
|
|
13904
|
-
).length;
|
|
13905
|
-
return repoVerified * 100 + (mission.readinessPercent ?? 0) - missing;
|
|
13906
|
-
}
|
|
13907
|
-
function preferredMissionForArea(area, selectedProvider) {
|
|
13908
|
-
const missions = area?.providerMissions ?? [];
|
|
13909
|
-
if (missions.length === 0) {
|
|
13910
|
-
return void 0;
|
|
13911
|
-
}
|
|
13912
|
-
const selected = selectedProvider ? missions.find((mission) => missionMatchesProvider(mission, selectedProvider)) : void 0;
|
|
13913
|
-
if (selected) {
|
|
13914
|
-
return selected;
|
|
13915
|
-
}
|
|
13916
|
-
return [...missions].sort((a, b3) => missionEvidenceScore(b3) - missionEvidenceScore(a))[0] ?? missions[0];
|
|
13917
|
-
}
|
|
13918
|
-
function openChecksForMission(mission) {
|
|
13919
|
-
if (!mission) {
|
|
13920
|
-
return 0;
|
|
13921
|
-
}
|
|
13922
|
-
return mission.checks.filter(
|
|
13923
|
-
(check) => check.status === "missing" || check.status === "failed" || check.status === "needs-connection"
|
|
13924
|
-
).length;
|
|
13925
|
-
}
|
|
13926
|
-
var init_missionSelection = __esm({
|
|
13927
|
-
"src/report/missionSelection.ts"() {
|
|
13928
|
-
"use strict";
|
|
13929
|
-
}
|
|
13930
|
-
});
|
|
13931
|
-
|
|
13932
14247
|
// src/statusLabels.ts
|
|
13933
14248
|
function formatAgentStatus(label, message) {
|
|
13934
14249
|
return `${label}: ${message}`;
|
|
@@ -13970,7 +14285,7 @@ function gapTagColor(modelGaps, open2) {
|
|
|
13970
14285
|
}
|
|
13971
14286
|
function manualActionCheckCount(artifact) {
|
|
13972
14287
|
return (artifact.missionGraph.areas ?? []).reduce((areaTotal, area) => {
|
|
13973
|
-
return areaTotal + area.
|
|
14288
|
+
return areaTotal + inRepoMissions(artifact, area).reduce((missionTotal, mission) => {
|
|
13974
14289
|
return missionTotal + mission.checks.filter(
|
|
13975
14290
|
(check) => check.evidenceClass === "manual-dashboard" || check.evidenceClass === "mcp-verifier" || check.evidenceSource === "provider" || check.evidenceSource === "mcp" || check.status === "needs-connection" || check.status === "unknown"
|
|
13976
14291
|
).length;
|
|
@@ -13991,8 +14306,14 @@ function printScanSummary(artifact, paths) {
|
|
|
13991
14306
|
console.log(import_picocolors.default.dim("\u2514") + import_picocolors.default.dim("\u2500".repeat(width - 2)) + import_picocolors.default.dim("\u2518"));
|
|
13992
14307
|
console.log("");
|
|
13993
14308
|
for (const area of artifact.missionGraph.areas ?? []) {
|
|
13994
|
-
|
|
14309
|
+
if ((area.providerMissions ?? []).length === 0) {
|
|
14310
|
+
continue;
|
|
14311
|
+
}
|
|
14312
|
+
const mission = preferredInRepoMission(artifact, area);
|
|
13995
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}`);
|
|
13996
14317
|
continue;
|
|
13997
14318
|
}
|
|
13998
14319
|
const open2 = openChecksForMission(mission);
|
|
@@ -14038,14 +14359,15 @@ var init_terminalSummary = __esm({
|
|
|
14038
14359
|
"use strict";
|
|
14039
14360
|
import_picocolors = __toESM(require_picocolors());
|
|
14040
14361
|
init_missionSelection();
|
|
14362
|
+
init_inRepoMissions();
|
|
14041
14363
|
init_statusLabels();
|
|
14042
14364
|
init_resolveNextAction();
|
|
14043
14365
|
}
|
|
14044
14366
|
});
|
|
14045
14367
|
|
|
14046
|
-
//
|
|
14368
|
+
// node_modules/sisteransi/src/index.js
|
|
14047
14369
|
var require_src = __commonJS({
|
|
14048
|
-
"
|
|
14370
|
+
"node_modules/sisteransi/src/index.js"(exports2, module2) {
|
|
14049
14371
|
"use strict";
|
|
14050
14372
|
var ESC = "\x1B";
|
|
14051
14373
|
var CSI = `${ESC}[`;
|
|
@@ -14099,7 +14421,7 @@ var require_src = __commonJS({
|
|
|
14099
14421
|
}
|
|
14100
14422
|
});
|
|
14101
14423
|
|
|
14102
|
-
//
|
|
14424
|
+
// node_modules/@clack/core/dist/index.mjs
|
|
14103
14425
|
function DD({ onlyFirst: e2 = false } = {}) {
|
|
14104
14426
|
const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
|
|
14105
14427
|
return new RegExp(t, e2 ? void 0 : "g");
|
|
@@ -14211,7 +14533,7 @@ function fD({ input: e2 = import_node_process.stdin, output: u2 = import_node_pr
|
|
|
14211
14533
|
}
|
|
14212
14534
|
var import_sisteransi, import_node_process, g, import_node_readline, import_node_stream, uD, W, tD, eD, FD, sD, w, N, I, R, C, iD, rD, ED, d, oD, y, V, nD, G, _, z, K, aD, k, hD, lD, xD, B, AD, S, gD, vD, h, x, A, OD, PD, J, LD;
|
|
14213
14535
|
var init_dist = __esm({
|
|
14214
|
-
"
|
|
14536
|
+
"node_modules/@clack/core/dist/index.mjs"() {
|
|
14215
14537
|
import_sisteransi = __toESM(require_src(), 1);
|
|
14216
14538
|
import_node_process = require("node:process");
|
|
14217
14539
|
g = __toESM(require("node:readline"), 1);
|
|
@@ -14461,13 +14783,13 @@ var init_dist = __esm({
|
|
|
14461
14783
|
}
|
|
14462
14784
|
});
|
|
14463
14785
|
|
|
14464
|
-
//
|
|
14786
|
+
// node_modules/@clack/prompts/dist/index.mjs
|
|
14465
14787
|
function ce() {
|
|
14466
14788
|
return import_node_process2.default.platform !== "win32" ? import_node_process2.default.env.TERM !== "linux" : !!import_node_process2.default.env.CI || !!import_node_process2.default.env.WT_SESSION || !!import_node_process2.default.env.TERMINUS_SUBLIME || import_node_process2.default.env.ConEmuTask === "{cmd::Cmder}" || import_node_process2.default.env.TERM_PROGRAM === "Terminus-Sublime" || import_node_process2.default.env.TERM_PROGRAM === "vscode" || import_node_process2.default.env.TERM === "xterm-256color" || import_node_process2.default.env.TERM === "alacritty" || import_node_process2.default.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
14467
14789
|
}
|
|
14468
14790
|
var import_node_process2, import_picocolors2, import_sisteransi2, V2, u, le, L2, W2, C2, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D, U, K2, b2, G2, ve, xe, Ie, Se, M2, J2, Y2;
|
|
14469
14791
|
var init_dist2 = __esm({
|
|
14470
|
-
"
|
|
14792
|
+
"node_modules/@clack/prompts/dist/index.mjs"() {
|
|
14471
14793
|
init_dist();
|
|
14472
14794
|
init_dist();
|
|
14473
14795
|
import_node_process2 = __toESM(require("node:process"), 1);
|
|
@@ -14700,7 +15022,7 @@ var VERSION;
|
|
|
14700
15022
|
var init_version = __esm({
|
|
14701
15023
|
"src/version.ts"() {
|
|
14702
15024
|
"use strict";
|
|
14703
|
-
VERSION = "1.6.
|
|
15025
|
+
VERSION = "1.6.3";
|
|
14704
15026
|
}
|
|
14705
15027
|
});
|
|
14706
15028
|
|
|
@@ -15072,17 +15394,17 @@ async function initCursorRulesPack(options) {
|
|
|
15072
15394
|
const pack = buildCursorRulesPack();
|
|
15073
15395
|
for (const rule of pack) {
|
|
15074
15396
|
const file = `${CURSOR_RULES_DIR}/${rule.filename}`;
|
|
15075
|
-
const path = (0,
|
|
15397
|
+
const path = (0, import_node_path18.join)(options.cwd, file);
|
|
15076
15398
|
const existing = await readExistingFile(path);
|
|
15077
15399
|
const changed = !existing.exists || existing.content !== rule.content;
|
|
15078
15400
|
const action = !existing.exists ? "created" : changed ? "updated" : "unchanged";
|
|
15079
15401
|
if (!options.dryRun && changed) {
|
|
15080
|
-
await (0, import_promises12.mkdir)((0,
|
|
15402
|
+
await (0, import_promises12.mkdir)((0, import_node_path18.join)(options.cwd, CURSOR_RULES_DIR), { recursive: true });
|
|
15081
15403
|
await (0, import_promises12.writeFile)(path, rule.content, "utf-8");
|
|
15082
15404
|
}
|
|
15083
15405
|
results.push({ target: "cursor", file, path, action });
|
|
15084
15406
|
}
|
|
15085
|
-
const legacyPath = (0,
|
|
15407
|
+
const legacyPath = (0, import_node_path18.join)(options.cwd, LEGACY_CURSOR_RULE_FILE);
|
|
15086
15408
|
if (!options.dryRun && await fileExists(legacyPath)) {
|
|
15087
15409
|
await (0, import_promises12.rm)(legacyPath, { force: true });
|
|
15088
15410
|
}
|
|
@@ -15109,12 +15431,12 @@ async function fileExists(path) {
|
|
|
15109
15431
|
function isFileNotFoundError(error) {
|
|
15110
15432
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15111
15433
|
}
|
|
15112
|
-
var import_promises12,
|
|
15434
|
+
var import_promises12, import_node_path18, CURSOR_RULES_DIR, LEGACY_CURSOR_RULE_FILE, DOMAIN_PATH_POINTER;
|
|
15113
15435
|
var init_cursorRulesPack = __esm({
|
|
15114
15436
|
"src/commands/cursorRulesPack.ts"() {
|
|
15115
15437
|
"use strict";
|
|
15116
15438
|
import_promises12 = require("node:fs/promises");
|
|
15117
|
-
|
|
15439
|
+
import_node_path18 = require("node:path");
|
|
15118
15440
|
init_commands();
|
|
15119
15441
|
CURSOR_RULES_DIR = ".cursor/rules";
|
|
15120
15442
|
LEGACY_CURSOR_RULE_FILE = `${CURSOR_RULES_DIR}/viberaven.mdc`;
|
|
@@ -15214,8 +15536,8 @@ var init_agentTargets = __esm({
|
|
|
15214
15536
|
|
|
15215
15537
|
// src/commands/seedPackageJsonScripts.ts
|
|
15216
15538
|
async function seedPackageJsonScripts(options) {
|
|
15217
|
-
const packageJsonPath = (0,
|
|
15218
|
-
if (!(0,
|
|
15539
|
+
const packageJsonPath = (0, import_node_path19.join)(options.cwd, "package.json");
|
|
15540
|
+
if (!(0, import_node_fs10.existsSync)(packageJsonPath)) {
|
|
15219
15541
|
return null;
|
|
15220
15542
|
}
|
|
15221
15543
|
const raw = await (0, import_promises13.readFile)(packageJsonPath, "utf-8");
|
|
@@ -15252,13 +15574,13 @@ async function seedPackageJsonScripts(options) {
|
|
|
15252
15574
|
}
|
|
15253
15575
|
return { action: "updated", added, skipped, changed: true };
|
|
15254
15576
|
}
|
|
15255
|
-
var
|
|
15577
|
+
var import_node_fs10, import_promises13, import_node_path19, VIBERAVEN_PACKAGE_JSON_SCRIPTS;
|
|
15256
15578
|
var init_seedPackageJsonScripts = __esm({
|
|
15257
15579
|
"src/commands/seedPackageJsonScripts.ts"() {
|
|
15258
15580
|
"use strict";
|
|
15259
|
-
|
|
15581
|
+
import_node_fs10 = require("node:fs");
|
|
15260
15582
|
import_promises13 = require("node:fs/promises");
|
|
15261
|
-
|
|
15583
|
+
import_node_path19 = require("node:path");
|
|
15262
15584
|
init_commands();
|
|
15263
15585
|
VIBERAVEN_PACKAGE_JSON_SCRIPTS = {
|
|
15264
15586
|
"viberaven:gate": PUBLIC_AGENT_MODE_COMMAND,
|
|
@@ -15278,12 +15600,12 @@ async function initAgentRules(options) {
|
|
|
15278
15600
|
continue;
|
|
15279
15601
|
}
|
|
15280
15602
|
const file = AGENT_RULE_TARGETS[target].file;
|
|
15281
|
-
const path = (0,
|
|
15603
|
+
const path = (0, import_node_path20.join)(options.cwd, file);
|
|
15282
15604
|
const existing = await readExistingFile2(path);
|
|
15283
15605
|
const injected = injectAgentRulesBlock(existing.content, renderAgentRulesForTarget(target));
|
|
15284
15606
|
const action = !existing.exists ? "created" : injected.changed ? "updated" : "unchanged";
|
|
15285
15607
|
if (!options.dryRun && injected.changed) {
|
|
15286
|
-
await (0, import_promises14.mkdir)((0,
|
|
15608
|
+
await (0, import_promises14.mkdir)((0, import_node_path20.dirname)(path), { recursive: true });
|
|
15287
15609
|
await (0, import_promises14.writeFile)(path, injected.content, "utf-8");
|
|
15288
15610
|
}
|
|
15289
15611
|
results.push({ target, file, path, action });
|
|
@@ -15363,12 +15685,12 @@ async function readExistingFile2(path) {
|
|
|
15363
15685
|
function isFileNotFoundError2(error) {
|
|
15364
15686
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15365
15687
|
}
|
|
15366
|
-
var import_promises14,
|
|
15688
|
+
var import_promises14, import_node_path20;
|
|
15367
15689
|
var init_initRules = __esm({
|
|
15368
15690
|
"src/commands/initRules.ts"() {
|
|
15369
15691
|
"use strict";
|
|
15370
15692
|
import_promises14 = require("node:fs/promises");
|
|
15371
|
-
|
|
15693
|
+
import_node_path20 = require("node:path");
|
|
15372
15694
|
init_agentRulesBlock();
|
|
15373
15695
|
init_agentTargets();
|
|
15374
15696
|
init_cursorRulesPack();
|
|
@@ -15631,7 +15953,7 @@ async function runInteractiveSession(startDir = process.cwd()) {
|
|
|
15631
15953
|
Ie(`${import_picocolors4.default.bold("VibeRaven")} ${import_picocolors4.default.dim(VERSION)}`);
|
|
15632
15954
|
const cwd = await resolveWorkspaceRoot(startDir);
|
|
15633
15955
|
const artifactsAt = await findArtifactsWorkspace(startDir);
|
|
15634
|
-
if (artifactsAt && (0,
|
|
15956
|
+
if (artifactsAt && (0, import_node_path21.resolve)(artifactsAt) !== (0, import_node_path21.resolve)(startDir)) {
|
|
15635
15957
|
M2.message(import_picocolors4.default.dim(`Using scan from: ${artifactsAt}`));
|
|
15636
15958
|
} else {
|
|
15637
15959
|
M2.message(import_picocolors4.default.dim(`Project folder: ${cwd}`));
|
|
@@ -15690,11 +16012,11 @@ async function runInteractiveSession(startDir = process.cwd()) {
|
|
|
15690
16012
|
}
|
|
15691
16013
|
Se(import_picocolors4.default.dim("Run viberaven anytime for the interactive menu."));
|
|
15692
16014
|
}
|
|
15693
|
-
var
|
|
16015
|
+
var import_node_path21, import_picocolors4;
|
|
15694
16016
|
var init_runInteractive = __esm({
|
|
15695
16017
|
"src/tui/runInteractive.ts"() {
|
|
15696
16018
|
"use strict";
|
|
15697
|
-
|
|
16019
|
+
import_node_path21 = require("node:path");
|
|
15698
16020
|
init_dist2();
|
|
15699
16021
|
import_picocolors4 = __toESM(require_picocolors());
|
|
15700
16022
|
init_config();
|
|
@@ -15719,18 +16041,18 @@ var init_runInteractive = __esm({
|
|
|
15719
16041
|
// src/commands/condense.ts
|
|
15720
16042
|
async function runCondenseCommand(options) {
|
|
15721
16043
|
const dir = getProjectArtifactsDir(options.cwd);
|
|
15722
|
-
const artifact = JSON.parse(await (0, import_promises15.readFile)((0,
|
|
15723
|
-
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");
|
|
15724
16046
|
await (0, import_promises15.writeFile)(contextMapPath, `${JSON.stringify(generateContextMap(artifact), null, 2)}
|
|
15725
16047
|
`, "utf8");
|
|
15726
16048
|
return { contextMapPath };
|
|
15727
16049
|
}
|
|
15728
|
-
var import_promises15,
|
|
16050
|
+
var import_promises15, import_node_path22;
|
|
15729
16051
|
var init_condense = __esm({
|
|
15730
16052
|
"src/commands/condense.ts"() {
|
|
15731
16053
|
"use strict";
|
|
15732
16054
|
import_promises15 = require("node:fs/promises");
|
|
15733
|
-
|
|
16055
|
+
import_node_path22 = require("node:path");
|
|
15734
16056
|
init_config();
|
|
15735
16057
|
init_contextMap();
|
|
15736
16058
|
}
|
|
@@ -15738,9 +16060,9 @@ var init_condense = __esm({
|
|
|
15738
16060
|
|
|
15739
16061
|
// src/heal/pathSafety.ts
|
|
15740
16062
|
function assertSafeHealTarget(cwd, target) {
|
|
15741
|
-
const root = (0,
|
|
15742
|
-
const absolute = (0,
|
|
15743
|
-
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);
|
|
15744
16066
|
if (rel.startsWith("..") || rel === "" || /^[A-Za-z]:/.test(rel)) {
|
|
15745
16067
|
throw new Error("Heal target must stay inside the workspace");
|
|
15746
16068
|
}
|
|
@@ -15750,11 +16072,11 @@ function assertSafeHealTarget(cwd, target) {
|
|
|
15750
16072
|
}
|
|
15751
16073
|
return absolute;
|
|
15752
16074
|
}
|
|
15753
|
-
var
|
|
16075
|
+
var import_node_path23, BLOCKED_SEGMENTS;
|
|
15754
16076
|
var init_pathSafety = __esm({
|
|
15755
16077
|
"src/heal/pathSafety.ts"() {
|
|
15756
16078
|
"use strict";
|
|
15757
|
-
|
|
16079
|
+
import_node_path23 = require("node:path");
|
|
15758
16080
|
BLOCKED_SEGMENTS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", ".viberaven"]);
|
|
15759
16081
|
}
|
|
15760
16082
|
});
|
|
@@ -15780,11 +16102,11 @@ function newHealId(now = /* @__PURE__ */ new Date()) {
|
|
|
15780
16102
|
return `heal_${now.toISOString().replace(/\D/g, "").slice(0, 17)}_${(0, import_node_crypto.randomBytes)(3).toString("hex")}`;
|
|
15781
16103
|
}
|
|
15782
16104
|
async function createHealDir(cwd, makeId = () => newHealId()) {
|
|
15783
|
-
const parent = (0,
|
|
16105
|
+
const parent = (0, import_node_path24.join)(cwd, ".viberaven", "heal");
|
|
15784
16106
|
await (0, import_promises16.mkdir)(parent, { recursive: true });
|
|
15785
16107
|
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
15786
16108
|
const id = makeId();
|
|
15787
|
-
const dir = (0,
|
|
16109
|
+
const dir = (0, import_node_path24.join)(parent, id);
|
|
15788
16110
|
try {
|
|
15789
16111
|
await (0, import_promises16.mkdir)(dir);
|
|
15790
16112
|
return { id, dir };
|
|
@@ -15794,13 +16116,13 @@ async function createHealDir(cwd, makeId = () => newHealId()) {
|
|
|
15794
16116
|
}
|
|
15795
16117
|
throw new Error("Could not create a new heal directory under .viberaven/heal.");
|
|
15796
16118
|
}
|
|
15797
|
-
var import_node_crypto, import_promises16,
|
|
16119
|
+
var import_node_crypto, import_promises16, import_node_path24;
|
|
15798
16120
|
var init_healId = __esm({
|
|
15799
16121
|
"src/heal/healId.ts"() {
|
|
15800
16122
|
"use strict";
|
|
15801
16123
|
import_node_crypto = require("node:crypto");
|
|
15802
16124
|
import_promises16 = require("node:fs/promises");
|
|
15803
|
-
|
|
16125
|
+
import_node_path24 = require("node:path");
|
|
15804
16126
|
}
|
|
15805
16127
|
});
|
|
15806
16128
|
|
|
@@ -16267,7 +16589,7 @@ export const config = {
|
|
|
16267
16589
|
// src/heal/recipes/eslintRestrictedImports.ts
|
|
16268
16590
|
function detectEslintConfigFile(cwd) {
|
|
16269
16591
|
for (const candidate of ESLINT_CONFIG_CANDIDATES) {
|
|
16270
|
-
if ((0,
|
|
16592
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path25.join)(cwd, candidate))) {
|
|
16271
16593
|
return candidate;
|
|
16272
16594
|
}
|
|
16273
16595
|
}
|
|
@@ -16422,12 +16744,12 @@ function applyEslintRestrictedImportsRecipe(source, configFile) {
|
|
|
16422
16744
|
}
|
|
16423
16745
|
return applyLegacyModuleRecipe(source);
|
|
16424
16746
|
}
|
|
16425
|
-
var
|
|
16747
|
+
var import_node_fs11, import_node_path25, VIBERAVEN_ESLINT_MARKER, RESTRICTED_IMPORTS_MESSAGE, RESTRICTED_PATHS, RESTRICTED_PATTERNS, ESLINT_CONFIG_CANDIDATES;
|
|
16426
16748
|
var init_eslintRestrictedImports = __esm({
|
|
16427
16749
|
"src/heal/recipes/eslintRestrictedImports.ts"() {
|
|
16428
16750
|
"use strict";
|
|
16429
|
-
|
|
16430
|
-
|
|
16751
|
+
import_node_fs11 = require("node:fs");
|
|
16752
|
+
import_node_path25 = require("node:path");
|
|
16431
16753
|
init_commands();
|
|
16432
16754
|
VIBERAVEN_ESLINT_MARKER = "VibeRaven heal: eslint_restricted_imports";
|
|
16433
16755
|
RESTRICTED_IMPORTS_MESSAGE = `Restricted import. Run ${PUBLIC_AGENT_MODE_COMMAND} before substituting packages.`;
|
|
@@ -16478,13 +16800,13 @@ function defaultTargetFile(gapId) {
|
|
|
16478
16800
|
return map[gapId];
|
|
16479
16801
|
}
|
|
16480
16802
|
async function readSourceOrEmpty(absolutePath) {
|
|
16481
|
-
if (!(0,
|
|
16803
|
+
if (!(0, import_node_fs12.existsSync)(absolutePath)) return "";
|
|
16482
16804
|
return (0, import_promises17.readFile)(absolutePath, "utf8");
|
|
16483
16805
|
}
|
|
16484
16806
|
async function detectUpstash(cwd) {
|
|
16485
16807
|
try {
|
|
16486
|
-
const pkgPath = (0,
|
|
16487
|
-
if (!(0,
|
|
16808
|
+
const pkgPath = (0, import_node_path26.join)(cwd, "package.json");
|
|
16809
|
+
if (!(0, import_node_fs12.existsSync)(pkgPath)) return false;
|
|
16488
16810
|
const raw = await (0, import_promises17.readFile)(pkgPath, "utf8");
|
|
16489
16811
|
const pkg = JSON.parse(raw);
|
|
16490
16812
|
const deps = {
|
|
@@ -16500,7 +16822,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16500
16822
|
const targetFile = explicitTarget ?? defaultTargetFile(gapId);
|
|
16501
16823
|
if (targetFile === void 0) return null;
|
|
16502
16824
|
if (gapId === "auth_secret_missing" || gapId === "node_env_not_set" || gapId === "database_url_missing") {
|
|
16503
|
-
const absolutePath = (0,
|
|
16825
|
+
const absolutePath = (0, import_node_path26.join)(cwd, targetFile);
|
|
16504
16826
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16505
16827
|
let result;
|
|
16506
16828
|
if (gapId === "auth_secret_missing") result = applyAuthSecretRecipe(source);
|
|
@@ -16514,25 +16836,25 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16514
16836
|
};
|
|
16515
16837
|
}
|
|
16516
16838
|
if (gapId === "missing_error_boundary") {
|
|
16517
|
-
const absolutePath = (0,
|
|
16839
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/error.tsx");
|
|
16518
16840
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16519
16841
|
const result = applyErrorBoundaryRecipe(source);
|
|
16520
16842
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16521
16843
|
}
|
|
16522
16844
|
if (gapId === "missing_health_route") {
|
|
16523
|
-
const absolutePath = (0,
|
|
16845
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/api/health/route.ts");
|
|
16524
16846
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16525
16847
|
const result = applyHealthRouteRecipe(source);
|
|
16526
16848
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16527
16849
|
}
|
|
16528
16850
|
if (gapId === "missing_loading_state") {
|
|
16529
|
-
const absolutePath = (0,
|
|
16851
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/loading.tsx");
|
|
16530
16852
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16531
16853
|
const result = applyLoadingStateRecipe(source);
|
|
16532
16854
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
16533
16855
|
}
|
|
16534
16856
|
if (gapId === "missing_404_page") {
|
|
16535
|
-
const absolutePath = (0,
|
|
16857
|
+
const absolutePath = (0, import_node_path26.join)(cwd, "app/not-found.tsx");
|
|
16536
16858
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16537
16859
|
const result = applyNotFoundRecipe(source);
|
|
16538
16860
|
return { ...result, canAutoApply: true, recipeName: gapId };
|
|
@@ -16549,10 +16871,10 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16549
16871
|
}
|
|
16550
16872
|
if (gapId === "missing_csp_header") {
|
|
16551
16873
|
let configFile = "next.config.js";
|
|
16552
|
-
let absolutePath = (0,
|
|
16553
|
-
if (!(0,
|
|
16874
|
+
let absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16875
|
+
if (!(0, import_node_fs12.existsSync)(absolutePath)) {
|
|
16554
16876
|
configFile = "next.config.mjs";
|
|
16555
|
-
absolutePath = (0,
|
|
16877
|
+
absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16556
16878
|
}
|
|
16557
16879
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16558
16880
|
const result = applyCspHeaderRecipe(source);
|
|
@@ -16564,7 +16886,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16564
16886
|
}
|
|
16565
16887
|
if (gapId === "missing_rate_limit") {
|
|
16566
16888
|
const hasUpstash = await detectUpstash(cwd);
|
|
16567
|
-
const middlewarePath = (0,
|
|
16889
|
+
const middlewarePath = (0, import_node_path26.join)(cwd, "middleware.ts");
|
|
16568
16890
|
const source = await readSourceOrEmpty(middlewarePath);
|
|
16569
16891
|
const result = applyRateLimitRecipe(source, hasUpstash);
|
|
16570
16892
|
return {
|
|
@@ -16586,7 +16908,7 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16586
16908
|
recipeName: gapId
|
|
16587
16909
|
};
|
|
16588
16910
|
}
|
|
16589
|
-
const absolutePath = (0,
|
|
16911
|
+
const absolutePath = (0, import_node_path26.join)(cwd, configFile);
|
|
16590
16912
|
const source = await readSourceOrEmpty(absolutePath);
|
|
16591
16913
|
const result = applyEslintRestrictedImportsRecipe(source, configFile);
|
|
16592
16914
|
return {
|
|
@@ -16600,13 +16922,13 @@ async function dispatchRecipeByGapId(gapId, cwd, explicitTarget) {
|
|
|
16600
16922
|
}
|
|
16601
16923
|
return null;
|
|
16602
16924
|
}
|
|
16603
|
-
var
|
|
16925
|
+
var import_node_fs12, import_promises17, import_node_path26;
|
|
16604
16926
|
var init_recipes = __esm({
|
|
16605
16927
|
"src/heal/recipes/index.ts"() {
|
|
16606
16928
|
"use strict";
|
|
16607
|
-
|
|
16929
|
+
import_node_fs12 = require("node:fs");
|
|
16608
16930
|
import_promises17 = require("node:fs/promises");
|
|
16609
|
-
|
|
16931
|
+
import_node_path26 = require("node:path");
|
|
16610
16932
|
init_envAuthSecret();
|
|
16611
16933
|
init_envNodeEnv();
|
|
16612
16934
|
init_envDatabaseUrl();
|
|
@@ -16683,16 +17005,16 @@ async function applyHeal(options) {
|
|
|
16683
17005
|
rollback: { available: false, instructions: "Recipe matched but no change was needed (already applied or file already exists)." }
|
|
16684
17006
|
};
|
|
16685
17007
|
}
|
|
16686
|
-
const absoluteTarget = (0,
|
|
17008
|
+
const absoluteTarget = (0, import_node_path27.join)(options.cwd, dispatched.targetFile);
|
|
16687
17009
|
assertSafeHealTarget(options.cwd, dispatched.targetFile);
|
|
16688
|
-
await (0, import_promises18.mkdir)((0,
|
|
17010
|
+
await (0, import_promises18.mkdir)((0, import_node_path27.dirname)(absoluteTarget), { recursive: true });
|
|
16689
17011
|
const created2 = await createHealDir(options.cwd);
|
|
16690
17012
|
id = created2.id;
|
|
16691
17013
|
const healDir2 = created2.dir;
|
|
16692
|
-
await (0, import_promises18.mkdir)((0,
|
|
16693
|
-
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);
|
|
16694
17016
|
const beforeContent = existedBefore ? await (0, import_promises18.readFile)(absoluteTarget, "utf8") : "";
|
|
16695
|
-
await (0, import_promises18.writeFile)((0,
|
|
17017
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir2, "before", "target.txt"), beforeContent, "utf8");
|
|
16696
17018
|
await (0, import_promises18.writeFile)(absoluteTarget, dispatched.output, "utf8");
|
|
16697
17019
|
const patch2 = [
|
|
16698
17020
|
`--- ${dispatched.targetFile}`,
|
|
@@ -16703,7 +17025,7 @@ async function applyHeal(options) {
|
|
|
16703
17025
|
dispatched.output,
|
|
16704
17026
|
""
|
|
16705
17027
|
].join("\n");
|
|
16706
|
-
await (0, import_promises18.writeFile)((0,
|
|
17028
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir2, "patch.diff"), patch2, "utf8");
|
|
16707
17029
|
const result2 = {
|
|
16708
17030
|
$schema: "https://viberaven.dev/schemas/heal-result.schema.json",
|
|
16709
17031
|
schemaVersion: "v1",
|
|
@@ -16715,17 +17037,17 @@ async function applyHeal(options) {
|
|
|
16715
17037
|
recipe: dispatched.recipeName,
|
|
16716
17038
|
...dispatched.warnings?.length ? { warnings: dispatched.warnings } : {},
|
|
16717
17039
|
target: dispatched.targetFile,
|
|
16718
|
-
changedFiles: [(0,
|
|
17040
|
+
changedFiles: [(0, import_node_path27.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/")],
|
|
16719
17041
|
artifacts: {
|
|
16720
17042
|
patch: `.viberaven/heal/${id}/patch.diff`,
|
|
16721
17043
|
result: `.viberaven/heal/${id}/result.json`
|
|
16722
17044
|
},
|
|
16723
17045
|
rollback: {
|
|
16724
17046
|
available: true,
|
|
16725
|
-
instructions: rollbackInstructions(id, (0,
|
|
17047
|
+
instructions: rollbackInstructions(id, (0, import_node_path27.relative)(options.cwd, absoluteTarget).replace(/\\/g, "/"), existedBefore)
|
|
16726
17048
|
}
|
|
16727
17049
|
};
|
|
16728
|
-
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)}
|
|
16729
17051
|
`, "utf8");
|
|
16730
17052
|
return result2;
|
|
16731
17053
|
}
|
|
@@ -16765,8 +17087,8 @@ async function applyHeal(options) {
|
|
|
16765
17087
|
const created = await createHealDir(options.cwd);
|
|
16766
17088
|
id = created.id;
|
|
16767
17089
|
const healDir = created.dir;
|
|
16768
|
-
await (0, import_promises18.mkdir)((0,
|
|
16769
|
-
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");
|
|
16770
17092
|
await (0, import_promises18.writeFile)(absolute, recipe.output, "utf8");
|
|
16771
17093
|
const patch = [
|
|
16772
17094
|
`--- ${options.target}`,
|
|
@@ -16777,7 +17099,7 @@ async function applyHeal(options) {
|
|
|
16777
17099
|
recipe.output,
|
|
16778
17100
|
""
|
|
16779
17101
|
].join("\n");
|
|
16780
|
-
await (0, import_promises18.writeFile)((0,
|
|
17102
|
+
await (0, import_promises18.writeFile)((0, import_node_path27.join)(healDir, "patch.diff"), patch, "utf8");
|
|
16781
17103
|
const result = {
|
|
16782
17104
|
$schema: "https://viberaven.dev/schemas/heal-result.schema.json",
|
|
16783
17105
|
schemaVersion: "v1",
|
|
@@ -16788,7 +17110,7 @@ async function applyHeal(options) {
|
|
|
16788
17110
|
gapId: options.gapId,
|
|
16789
17111
|
recipe: "empty-catch-safe-response",
|
|
16790
17112
|
target: options.target,
|
|
16791
|
-
changedFiles: [(0,
|
|
17113
|
+
changedFiles: [(0, import_node_path27.relative)(options.cwd, absolute).replace(/\\/g, "/")],
|
|
16792
17114
|
artifacts: {
|
|
16793
17115
|
patch: `.viberaven/heal/${id}/patch.diff`,
|
|
16794
17116
|
result: `.viberaven/heal/${id}/result.json`
|
|
@@ -16796,20 +17118,20 @@ async function applyHeal(options) {
|
|
|
16796
17118
|
rollback: {
|
|
16797
17119
|
available: true,
|
|
16798
17120
|
// The empty-catch recipe only edits a file that already exists.
|
|
16799
|
-
instructions: rollbackInstructions(id, (0,
|
|
17121
|
+
instructions: rollbackInstructions(id, (0, import_node_path27.relative)(options.cwd, absolute).replace(/\\/g, "/"), true)
|
|
16800
17122
|
}
|
|
16801
17123
|
};
|
|
16802
|
-
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)}
|
|
16803
17125
|
`, "utf8");
|
|
16804
17126
|
return result;
|
|
16805
17127
|
}
|
|
16806
|
-
var import_promises18,
|
|
17128
|
+
var import_promises18, import_node_fs13, import_node_path27;
|
|
16807
17129
|
var init_apply = __esm({
|
|
16808
17130
|
"src/heal/apply.ts"() {
|
|
16809
17131
|
"use strict";
|
|
16810
17132
|
import_promises18 = require("node:fs/promises");
|
|
16811
|
-
|
|
16812
|
-
|
|
17133
|
+
import_node_fs13 = require("node:fs");
|
|
17134
|
+
import_node_path27 = require("node:path");
|
|
16813
17135
|
init_pathSafety();
|
|
16814
17136
|
init_emptyCatch();
|
|
16815
17137
|
init_healId();
|
|
@@ -16819,7 +17141,7 @@ var init_apply = __esm({
|
|
|
16819
17141
|
|
|
16820
17142
|
// src/heal/plan.ts
|
|
16821
17143
|
async function writeHealPlan(options) {
|
|
16822
|
-
const dir = (0,
|
|
17144
|
+
const dir = (0, import_node_path28.join)(options.cwd, ".viberaven");
|
|
16823
17145
|
await (0, import_promises19.mkdir)(dir, { recursive: true });
|
|
16824
17146
|
const id = newHealId();
|
|
16825
17147
|
const target = options.target ?? `gap:${options.gapId}`;
|
|
@@ -16872,18 +17194,18 @@ async function writeHealPlan(options) {
|
|
|
16872
17194
|
artifacts: { plan: ".viberaven/heal-plan.md" },
|
|
16873
17195
|
rollback: { available: false, instructions: "No source files were changed." }
|
|
16874
17196
|
};
|
|
16875
|
-
await (0, import_promises19.writeFile)((0,
|
|
16876
|
-
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)}
|
|
16877
17199
|
`, "utf8");
|
|
16878
17200
|
return result;
|
|
16879
17201
|
}
|
|
16880
|
-
var import_promises19,
|
|
17202
|
+
var import_promises19, import_node_path28;
|
|
16881
17203
|
var init_plan = __esm({
|
|
16882
17204
|
"src/heal/plan.ts"() {
|
|
16883
17205
|
"use strict";
|
|
16884
17206
|
import_promises19 = require("node:fs/promises");
|
|
16885
17207
|
init_healId();
|
|
16886
|
-
|
|
17208
|
+
import_node_path28 = require("node:path");
|
|
16887
17209
|
init_commands();
|
|
16888
17210
|
init_supabaseRls2();
|
|
16889
17211
|
}
|
|
@@ -16891,7 +17213,7 @@ var init_plan = __esm({
|
|
|
16891
17213
|
|
|
16892
17214
|
// src/heal/prompt.ts
|
|
16893
17215
|
async function writeHealPrompt(options) {
|
|
16894
|
-
const dir = (0,
|
|
17216
|
+
const dir = (0, import_node_path29.join)(options.cwd, ".viberaven");
|
|
16895
17217
|
await (0, import_promises20.mkdir)(dir, { recursive: true });
|
|
16896
17218
|
const id = newHealId();
|
|
16897
17219
|
const target = options.target ?? `gap:${options.gapId}`;
|
|
@@ -16919,16 +17241,16 @@ async function writeHealPrompt(options) {
|
|
|
16919
17241
|
artifacts: { prompt: ".viberaven/heal-prompt.md" },
|
|
16920
17242
|
rollback: { available: false, instructions: "No source files were changed." }
|
|
16921
17243
|
};
|
|
16922
|
-
await (0, import_promises20.writeFile)((0,
|
|
17244
|
+
await (0, import_promises20.writeFile)((0, import_node_path29.join)(dir, "heal-prompt.md"), prompt, "utf8");
|
|
16923
17245
|
return result;
|
|
16924
17246
|
}
|
|
16925
|
-
var import_promises20,
|
|
17247
|
+
var import_promises20, import_node_path29;
|
|
16926
17248
|
var init_prompt = __esm({
|
|
16927
17249
|
"src/heal/prompt.ts"() {
|
|
16928
17250
|
"use strict";
|
|
16929
17251
|
import_promises20 = require("node:fs/promises");
|
|
16930
17252
|
init_healId();
|
|
16931
|
-
|
|
17253
|
+
import_node_path29 = require("node:path");
|
|
16932
17254
|
init_commands();
|
|
16933
17255
|
}
|
|
16934
17256
|
});
|
|
@@ -17031,8 +17353,8 @@ var init_heal = __esm({
|
|
|
17031
17353
|
|
|
17032
17354
|
// src/stackRecommend.ts
|
|
17033
17355
|
async function recommendStack(cwd = process.cwd()) {
|
|
17034
|
-
const pkgPath = (0,
|
|
17035
|
-
if (!(0,
|
|
17356
|
+
const pkgPath = (0, import_node_path30.join)(cwd, "package.json");
|
|
17357
|
+
if (!(0, import_node_fs14.existsSync)(pkgPath)) {
|
|
17036
17358
|
return DEFAULT_STACK;
|
|
17037
17359
|
}
|
|
17038
17360
|
const pkg = JSON.parse(await (0, import_promises22.readFile)(pkgPath, "utf-8"));
|
|
@@ -17063,13 +17385,13 @@ async function recommendStack(cwd = process.cwd()) {
|
|
|
17063
17385
|
}
|
|
17064
17386
|
return rec;
|
|
17065
17387
|
}
|
|
17066
|
-
var import_promises22,
|
|
17388
|
+
var import_promises22, import_node_fs14, import_node_path30, DEFAULT_STACK;
|
|
17067
17389
|
var init_stackRecommend = __esm({
|
|
17068
17390
|
"src/stackRecommend.ts"() {
|
|
17069
17391
|
"use strict";
|
|
17070
17392
|
import_promises22 = require("node:fs/promises");
|
|
17071
|
-
|
|
17072
|
-
|
|
17393
|
+
import_node_fs14 = require("node:fs");
|
|
17394
|
+
import_node_path30 = require("node:path");
|
|
17073
17395
|
DEFAULT_STACK = {
|
|
17074
17396
|
frontend: "react",
|
|
17075
17397
|
ui: "tailwind + shadcn/ui",
|
|
@@ -17212,13 +17534,13 @@ async function readBlobs(cwd, shas) {
|
|
|
17212
17534
|
async function exportCommit(cwd, commit) {
|
|
17213
17535
|
const entries = parseTree(await git(cwd, ["ls-tree", "-r", "-z", "-l", "--full-tree", commit])).filter(wanted);
|
|
17214
17536
|
const blobs = await readBlobs(cwd, [...new Set(entries.map((entry) => entry.sha))]);
|
|
17215
|
-
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-"));
|
|
17216
17538
|
for (const entry of entries) {
|
|
17217
|
-
const target = (0,
|
|
17218
|
-
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;
|
|
17219
17541
|
const content = blobs.get(entry.sha);
|
|
17220
17542
|
if (!content) continue;
|
|
17221
|
-
await (0, import_promises23.mkdir)((0,
|
|
17543
|
+
await (0, import_promises23.mkdir)((0, import_node_path31.dirname)(target), { recursive: true });
|
|
17222
17544
|
await (0, import_promises23.writeFile)(target, content);
|
|
17223
17545
|
}
|
|
17224
17546
|
return root;
|
|
@@ -17288,14 +17610,14 @@ function renderCheckMarkdown({ head, change, version, score }) {
|
|
|
17288
17610
|
return `${lines.join("\n")}
|
|
17289
17611
|
`;
|
|
17290
17612
|
}
|
|
17291
|
-
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;
|
|
17292
17614
|
var init_checkChange = __esm({
|
|
17293
17615
|
"src/commands/checkChange.ts"() {
|
|
17294
17616
|
"use strict";
|
|
17295
17617
|
import_node_child_process6 = require("node:child_process");
|
|
17296
17618
|
import_promises23 = require("node:fs/promises");
|
|
17297
17619
|
import_node_os = require("node:os");
|
|
17298
|
-
|
|
17620
|
+
import_node_path31 = require("node:path");
|
|
17299
17621
|
import_node_util4 = require("node:util");
|
|
17300
17622
|
init_runScan();
|
|
17301
17623
|
init_safeGit();
|
|
@@ -17379,12 +17701,12 @@ async function hasGithubRemote(cwd) {
|
|
|
17379
17701
|
}
|
|
17380
17702
|
}
|
|
17381
17703
|
async function githubWorkflowStatus(cwd) {
|
|
17382
|
-
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) };
|
|
17383
17705
|
}
|
|
17384
17706
|
async function writeGithubWorkflow(cwd, options = {}) {
|
|
17385
|
-
const target = (0,
|
|
17386
|
-
if ((0,
|
|
17387
|
-
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 });
|
|
17388
17710
|
await (0, import_promises24.writeFile)(target, renderWorkflow(), "utf8");
|
|
17389
17711
|
return { written: true, status: await githubWorkflowStatus(cwd) };
|
|
17390
17712
|
}
|
|
@@ -17409,20 +17731,20 @@ async function runInitGithubCommand(options) {
|
|
|
17409
17731
|
if (!status.onGithub) console.log("This repository has no github.com remote yet: the workflow runs once it is pushed to GitHub.");
|
|
17410
17732
|
return 0;
|
|
17411
17733
|
}
|
|
17412
|
-
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;
|
|
17413
17735
|
var init_initGithub = __esm({
|
|
17414
17736
|
"src/commands/initGithub.ts"() {
|
|
17415
17737
|
"use strict";
|
|
17416
17738
|
import_node_child_process7 = require("node:child_process");
|
|
17417
|
-
|
|
17739
|
+
import_node_fs15 = require("node:fs");
|
|
17418
17740
|
import_promises24 = require("node:fs/promises");
|
|
17419
|
-
|
|
17741
|
+
import_node_path32 = require("node:path");
|
|
17420
17742
|
import_node_util5 = require("node:util");
|
|
17421
17743
|
init_safeGit();
|
|
17422
17744
|
init_version();
|
|
17423
17745
|
init_checkChange();
|
|
17424
17746
|
execFileAsync5 = (0, import_node_util5.promisify)(import_node_child_process7.execFile);
|
|
17425
|
-
WORKFLOW_PATH = (0,
|
|
17747
|
+
WORKFLOW_PATH = (0, import_node_path32.join)(".github", "workflows", "viberaven.yml");
|
|
17426
17748
|
DISPLAY_PATH = ".github/workflows/viberaven.yml";
|
|
17427
17749
|
}
|
|
17428
17750
|
});
|
|
@@ -17446,7 +17768,7 @@ function managedBlocks(content) {
|
|
|
17446
17768
|
async function checkAgentInjection(cwd) {
|
|
17447
17769
|
const checks = [];
|
|
17448
17770
|
for (const item4 of REQUIRED_EXISTENCE_CHECKS) {
|
|
17449
|
-
const exists = await fileExists2((0,
|
|
17771
|
+
const exists = await fileExists2((0, import_node_path33.join)(cwd, item4.file));
|
|
17450
17772
|
checks.push({
|
|
17451
17773
|
id: item4.id,
|
|
17452
17774
|
status: exists ? "pass" : "fail",
|
|
@@ -17454,17 +17776,17 @@ async function checkAgentInjection(cwd) {
|
|
|
17454
17776
|
});
|
|
17455
17777
|
}
|
|
17456
17778
|
for (const item4 of OPTIONAL_CURSOR_PACK_CHECKS) {
|
|
17457
|
-
const exists = await fileExists2((0,
|
|
17779
|
+
const exists = await fileExists2((0, import_node_path33.join)(cwd, item4.file));
|
|
17458
17780
|
checks.push({
|
|
17459
17781
|
id: item4.id,
|
|
17460
17782
|
status: exists ? "pass" : "fail",
|
|
17461
17783
|
message: exists ? `${item4.file} exists` : `Missing ${item4.file} \u2014 run npx -y viberaven init --agents all`
|
|
17462
17784
|
});
|
|
17463
17785
|
}
|
|
17464
|
-
const legacyCursorPath = (0,
|
|
17786
|
+
const legacyCursorPath = (0, import_node_path33.join)(cwd, ".cursor/rules/viberaven.mdc");
|
|
17465
17787
|
if (await fileExists2(legacyCursorPath)) {
|
|
17466
17788
|
const legacyContent = await (0, import_promises25.readFile)(legacyCursorPath, "utf-8");
|
|
17467
|
-
const hasCoreSplit = await fileExists2((0,
|
|
17789
|
+
const hasCoreSplit = await fileExists2((0, import_node_path33.join)(cwd, ".cursor/rules/viberaven-core.mdc"));
|
|
17468
17790
|
if (!hasCoreSplit || legacyContent.includes("alwaysApply: true")) {
|
|
17469
17791
|
checks.push({
|
|
17470
17792
|
id: "cursor-legacy-mdc",
|
|
@@ -17475,7 +17797,7 @@ async function checkAgentInjection(cwd) {
|
|
|
17475
17797
|
}
|
|
17476
17798
|
for (const target of CORE_AGENT_INJECTION_TARGETS) {
|
|
17477
17799
|
const file = target === "cursor" ? ".cursor/rules/viberaven-core.mdc" : AGENT_RULE_TARGETS[target].file;
|
|
17478
|
-
const path = (0,
|
|
17800
|
+
const path = (0, import_node_path33.join)(cwd, file);
|
|
17479
17801
|
const exists = await fileExists2(path);
|
|
17480
17802
|
if (!exists) {
|
|
17481
17803
|
checks.push({
|
|
@@ -17534,12 +17856,12 @@ async function fileExists2(path) {
|
|
|
17534
17856
|
return false;
|
|
17535
17857
|
}
|
|
17536
17858
|
}
|
|
17537
|
-
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;
|
|
17538
17860
|
var init_doctorAgents = __esm({
|
|
17539
17861
|
"src/commands/doctorAgents.ts"() {
|
|
17540
17862
|
"use strict";
|
|
17541
17863
|
import_promises25 = require("node:fs/promises");
|
|
17542
|
-
|
|
17864
|
+
import_node_path33 = require("node:path");
|
|
17543
17865
|
init_commands();
|
|
17544
17866
|
init_agentTargets();
|
|
17545
17867
|
REQUIRED_EXISTENCE_CHECKS = [
|
|
@@ -17810,7 +18132,7 @@ function buildContextCleanupPlan(input) {
|
|
|
17810
18132
|
const items = [];
|
|
17811
18133
|
const seen = /* @__PURE__ */ new Set();
|
|
17812
18134
|
for (const file of input.files) {
|
|
17813
|
-
const path = normalizePath5((0,
|
|
18135
|
+
const path = normalizePath5((0, import_node_path34.relative)(input.projectRoot, file.path) || file.path);
|
|
17814
18136
|
const fullPath = normalizePath5(file.path);
|
|
17815
18137
|
const category = categorizeCleanupFile(path, fullPath, file);
|
|
17816
18138
|
if (!category || seen.has(path)) {
|
|
@@ -17836,8 +18158,8 @@ async function collectCleanupFiles(projectRoot) {
|
|
|
17836
18158
|
return files;
|
|
17837
18159
|
}
|
|
17838
18160
|
async function writeCleanupPlan(projectRoot, plan) {
|
|
17839
|
-
const outputDir = (0,
|
|
17840
|
-
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");
|
|
17841
18163
|
await (0, import_promises26.mkdir)(outputDir, { recursive: true });
|
|
17842
18164
|
await (0, import_promises26.writeFile)(outputPath, renderCleanupPlan(plan), "utf8");
|
|
17843
18165
|
return outputPath;
|
|
@@ -17895,9 +18217,9 @@ async function walkCleanupFiles(root, dir, result, depth) {
|
|
|
17895
18217
|
if (SKIP_DIRECTORIES.has(entry.name)) {
|
|
17896
18218
|
continue;
|
|
17897
18219
|
}
|
|
17898
|
-
const absolute = (0,
|
|
18220
|
+
const absolute = (0, import_node_path34.join)(dir, entry.name);
|
|
17899
18221
|
if (entry.isDirectory()) {
|
|
17900
|
-
if (isCachePath(normalizePath5((0,
|
|
18222
|
+
if (isCachePath(normalizePath5((0, import_node_path34.relative)(root, absolute)))) {
|
|
17901
18223
|
result.push({ path: absolute, sizeBytes: 0, kind: "directory" });
|
|
17902
18224
|
continue;
|
|
17903
18225
|
}
|
|
@@ -17918,12 +18240,12 @@ async function walkCleanupFiles(root, dir, result, depth) {
|
|
|
17918
18240
|
function normalizePath5(path) {
|
|
17919
18241
|
return path.replace(/\\/g, "/");
|
|
17920
18242
|
}
|
|
17921
|
-
var import_promises26,
|
|
18243
|
+
var import_promises26, import_node_path34, MAX_WALK_DEPTH, LARGE_LOG_BYTES, SKIP_DIRECTORIES;
|
|
17922
18244
|
var init_cleanPlan = __esm({
|
|
17923
18245
|
"src/commands/cleanPlan.ts"() {
|
|
17924
18246
|
"use strict";
|
|
17925
18247
|
import_promises26 = require("node:fs/promises");
|
|
17926
|
-
|
|
18248
|
+
import_node_path34 = require("node:path");
|
|
17927
18249
|
MAX_WALK_DEPTH = 5;
|
|
17928
18250
|
LARGE_LOG_BYTES = 8192;
|
|
17929
18251
|
SKIP_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
@@ -18001,6 +18323,9 @@ function renderVerifyCommand(action) {
|
|
|
18001
18323
|
}
|
|
18002
18324
|
return ["Verify:", "```bash", redact(action.verifyCommand), "```"];
|
|
18003
18325
|
}
|
|
18326
|
+
function renderUserSteps(steps) {
|
|
18327
|
+
return steps?.length ? ["Outside the repo (tell the user):", ...steps.map((step) => `- ${redact(step)}`)] : [];
|
|
18328
|
+
}
|
|
18004
18329
|
function renderAction(action) {
|
|
18005
18330
|
return [
|
|
18006
18331
|
`[${action.id}] ${redact(action.title)}`,
|
|
@@ -18009,6 +18334,7 @@ function renderAction(action) {
|
|
|
18009
18334
|
...renderTarget(action.target),
|
|
18010
18335
|
...renderCopyPayload(action),
|
|
18011
18336
|
...renderVerifyCommand(action),
|
|
18337
|
+
...renderUserSteps(action.userSteps),
|
|
18012
18338
|
action.resumeInstruction ? `Resume: "${redact(action.resumeInstruction)}"` : void 0
|
|
18013
18339
|
].filter((line) => Boolean(line));
|
|
18014
18340
|
}
|
|
@@ -18024,6 +18350,9 @@ function renderActionSurface(manifest, options = {}) {
|
|
|
18024
18350
|
for (const action of visibleActions) {
|
|
18025
18351
|
lines.push(...renderAction(action), "");
|
|
18026
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
|
+
}
|
|
18027
18356
|
return `${lines.join("\n").trimEnd()}
|
|
18028
18357
|
`;
|
|
18029
18358
|
}
|
|
@@ -18036,7 +18365,7 @@ var init_render = __esm({
|
|
|
18036
18365
|
|
|
18037
18366
|
// src/commands/actions.ts
|
|
18038
18367
|
async function runActionsCommand(input) {
|
|
18039
|
-
const actionsPath = (0,
|
|
18368
|
+
const actionsPath = (0, import_node_path35.join)(getProjectArtifactsDir(input.cwd), "actions.json");
|
|
18040
18369
|
let raw;
|
|
18041
18370
|
try {
|
|
18042
18371
|
raw = await (0, import_promises27.readFile)(actionsPath, "utf8");
|
|
@@ -18053,12 +18382,12 @@ async function runActionsCommand(input) {
|
|
|
18053
18382
|
process.stdout.write(renderActionSurface(manifest));
|
|
18054
18383
|
return 0;
|
|
18055
18384
|
}
|
|
18056
|
-
var import_promises27,
|
|
18385
|
+
var import_promises27, import_node_path35;
|
|
18057
18386
|
var init_actions = __esm({
|
|
18058
18387
|
"src/commands/actions.ts"() {
|
|
18059
18388
|
"use strict";
|
|
18060
18389
|
import_promises27 = require("node:fs/promises");
|
|
18061
|
-
|
|
18390
|
+
import_node_path35 = require("node:path");
|
|
18062
18391
|
init_render();
|
|
18063
18392
|
init_config();
|
|
18064
18393
|
}
|
|
@@ -18067,7 +18396,7 @@ var init_actions = __esm({
|
|
|
18067
18396
|
// src/commands/verifyAction.ts
|
|
18068
18397
|
async function currentActionExists(cwd, actionId) {
|
|
18069
18398
|
try {
|
|
18070
|
-
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");
|
|
18071
18400
|
const manifest = JSON.parse(raw);
|
|
18072
18401
|
return manifest.actions.some((action) => action.id === actionId);
|
|
18073
18402
|
} catch {
|
|
@@ -18111,12 +18440,12 @@ This only looks the action up. Run \`npx -y viberaven --verify\` to scan the rep
|
|
|
18111
18440
|
);
|
|
18112
18441
|
return 0;
|
|
18113
18442
|
}
|
|
18114
|
-
var import_promises28,
|
|
18443
|
+
var import_promises28, import_node_path36;
|
|
18115
18444
|
var init_verifyAction = __esm({
|
|
18116
18445
|
"src/commands/verifyAction.ts"() {
|
|
18117
18446
|
"use strict";
|
|
18118
18447
|
import_promises28 = require("node:fs/promises");
|
|
18119
|
-
|
|
18448
|
+
import_node_path36 = require("node:path");
|
|
18120
18449
|
init_registry2();
|
|
18121
18450
|
init_config();
|
|
18122
18451
|
}
|
|
@@ -18271,6 +18600,7 @@ ${message}
|
|
|
18271
18600
|
return failing ? 1 : 0;
|
|
18272
18601
|
}
|
|
18273
18602
|
if (options.json) {
|
|
18603
|
+
const userFollowUps = await readUserFollowUps(paths.actionsPath);
|
|
18274
18604
|
console.log(
|
|
18275
18605
|
JSON.stringify(
|
|
18276
18606
|
{
|
|
@@ -18293,6 +18623,8 @@ ${message}
|
|
|
18293
18623
|
unchanged: change.unchanged.map((gap) => gap.id)
|
|
18294
18624
|
}
|
|
18295
18625
|
} : {},
|
|
18626
|
+
// Steps outside the repo for fixes already in it (MCP check and verify read this). Read only.
|
|
18627
|
+
...userFollowUps.length > 0 ? { userFollowUps } : {},
|
|
18296
18628
|
artifacts: paths
|
|
18297
18629
|
},
|
|
18298
18630
|
null,
|
|
@@ -18347,14 +18679,31 @@ ${message}
|
|
|
18347
18679
|
console.log(
|
|
18348
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}`
|
|
18349
18681
|
);
|
|
18682
|
+
await printUserFollowUps(paths.actionsPath);
|
|
18350
18683
|
console.log(`Fix: viberaven fix \xB7 Details: ${paths.tasklistPath}`);
|
|
18351
18684
|
console.log("");
|
|
18352
18685
|
return critical > 0 ? 1 : 0;
|
|
18353
18686
|
}
|
|
18354
|
-
|
|
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;
|
|
18355
18703
|
var init_check = __esm({
|
|
18356
18704
|
"src/commands/check.ts"() {
|
|
18357
18705
|
"use strict";
|
|
18706
|
+
import_promises29 = require("node:fs/promises");
|
|
18358
18707
|
init_runScan();
|
|
18359
18708
|
init_artifacts2();
|
|
18360
18709
|
init_statusLabels();
|
|
@@ -18803,8 +19152,8 @@ function isSqlError(error) {
|
|
|
18803
19152
|
}
|
|
18804
19153
|
function displayPath(projectDir, path) {
|
|
18805
19154
|
for (const base of [projectDir, process.cwd()]) {
|
|
18806
|
-
const rel = (0,
|
|
18807
|
-
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("/");
|
|
18808
19157
|
}
|
|
18809
19158
|
return path;
|
|
18810
19159
|
}
|
|
@@ -19408,26 +19757,26 @@ function verdictFor(summary) {
|
|
|
19408
19757
|
}
|
|
19409
19758
|
async function listMigrations(dir) {
|
|
19410
19759
|
try {
|
|
19411
|
-
const entries = await (0,
|
|
19760
|
+
const entries = await (0, import_promises30.readdir)(dir, { withFileTypes: true });
|
|
19412
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);
|
|
19413
19762
|
} catch {
|
|
19414
19763
|
return [];
|
|
19415
19764
|
}
|
|
19416
19765
|
}
|
|
19417
19766
|
async function runRlsTest(options) {
|
|
19418
|
-
const projectDir = (0,
|
|
19419
|
-
const matrixPath = (0,
|
|
19420
|
-
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"));
|
|
19421
19770
|
const timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
|
|
19422
|
-
if ((0,
|
|
19423
|
-
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.`);
|
|
19424
19773
|
}
|
|
19425
19774
|
const filesRead = [];
|
|
19426
19775
|
let matrixText;
|
|
19427
19776
|
try {
|
|
19428
|
-
const info = await (0,
|
|
19777
|
+
const info = await (0, import_promises30.stat)(matrixPath);
|
|
19429
19778
|
if (!info.isFile()) throw new Error("not a file");
|
|
19430
|
-
matrixText = normalise(await (0,
|
|
19779
|
+
matrixText = normalise(await (0, import_promises30.readFile)(matrixPath, "utf8"));
|
|
19431
19780
|
} catch {
|
|
19432
19781
|
throw new RlsInputError(
|
|
19433
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.`
|
|
@@ -19438,8 +19787,8 @@ async function runRlsTest(options) {
|
|
|
19438
19787
|
const names = await listMigrations(migrationsDir);
|
|
19439
19788
|
const migrationFiles = [];
|
|
19440
19789
|
for (const name of names) {
|
|
19441
|
-
const sql = normalise(await (0,
|
|
19442
|
-
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)));
|
|
19443
19792
|
migrationFiles.push({ name, sha256: sha256(sql), sql });
|
|
19444
19793
|
}
|
|
19445
19794
|
const migrationsHash = sha256(migrationFiles.map((f) => `${f.name}\0${f.sha256}`).join("\n"));
|
|
@@ -19639,15 +19988,15 @@ async function runTable(db, table2, badRoles, roleChecks) {
|
|
|
19639
19988
|
cells
|
|
19640
19989
|
};
|
|
19641
19990
|
}
|
|
19642
|
-
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;
|
|
19643
19992
|
var init_rlsRunner = __esm({
|
|
19644
19993
|
"src/rls/rlsRunner.ts"() {
|
|
19645
19994
|
"use strict";
|
|
19646
19995
|
import_node_child_process8 = require("node:child_process");
|
|
19647
19996
|
import_node_crypto3 = require("node:crypto");
|
|
19648
|
-
|
|
19997
|
+
import_promises30 = require("node:fs/promises");
|
|
19649
19998
|
import_node_net = __toESM(require("node:net"));
|
|
19650
|
-
|
|
19999
|
+
import_node_path37 = require("node:path");
|
|
19651
20000
|
import_node_util6 = require("node:util");
|
|
19652
20001
|
init_safeGit();
|
|
19653
20002
|
init_permissionsMatrix();
|
|
@@ -20475,7 +20824,7 @@ function buildMissionCards(artifact, providers) {
|
|
|
20475
20824
|
};
|
|
20476
20825
|
}
|
|
20477
20826
|
function projectNameFromPath(pathValue) {
|
|
20478
|
-
return (0,
|
|
20827
|
+
return (0, import_node_path38.basename)(pathValue.replace(/[\\/]$/, "")) || "current repo";
|
|
20479
20828
|
}
|
|
20480
20829
|
function gapSearchText(gap) {
|
|
20481
20830
|
return [
|
|
@@ -20666,7 +21015,7 @@ function mapProvider(template, artifact, projectName) {
|
|
|
20666
21015
|
const gaps = providerGaps(artifact, template.id);
|
|
20667
21016
|
const primaryGap2 = gaps[0];
|
|
20668
21017
|
const state = providerState(gaps);
|
|
20669
|
-
const launchGateClear = artifact.gaps
|
|
21018
|
+
const launchGateClear = gateStatusForGaps(artifact.gaps) === "clear";
|
|
20670
21019
|
const launchPath = template.items.map((item4, index) => ({
|
|
20671
21020
|
...item4,
|
|
20672
21021
|
state: itemState(primaryGap2, index, item4, launchGateClear),
|
|
@@ -20875,8 +21224,9 @@ function mapArtifactToLocalUiState(artifact, presentProviderIds) {
|
|
|
20875
21224
|
scannedAt: artifact.scannedAt
|
|
20876
21225
|
},
|
|
20877
21226
|
gate: {
|
|
20878
|
-
|
|
20879
|
-
|
|
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)],
|
|
20880
21230
|
score: artifact.score,
|
|
20881
21231
|
productionCorePercent: artifact.productionCorePercent
|
|
20882
21232
|
},
|
|
@@ -20886,25 +21236,31 @@ function mapArtifactToLocalUiState(artifact, presentProviderIds) {
|
|
|
20886
21236
|
selectedProviderId: selectedProvider.id,
|
|
20887
21237
|
currentPrompt: selectedProvider.nextFix?.prompt ?? "",
|
|
20888
21238
|
artifacts: {
|
|
20889
|
-
tasklist: (0,
|
|
20890
|
-
contextMap: (0,
|
|
20891
|
-
gateResult: (0,
|
|
20892
|
-
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")
|
|
20893
21243
|
},
|
|
20894
21244
|
empty: false
|
|
20895
21245
|
};
|
|
20896
21246
|
}
|
|
20897
|
-
var
|
|
21247
|
+
var import_node_path38, GATE_LABEL, CONNECT_PROVIDER_PRIORITY, providerDashboardUrls, providerHints, PROVIDER_OWNED_GAP;
|
|
20898
21248
|
var init_artifactAdapter = __esm({
|
|
20899
21249
|
"src/local-ui/artifactAdapter.ts"() {
|
|
20900
21250
|
"use strict";
|
|
20901
|
-
|
|
21251
|
+
import_node_path38 = require("node:path");
|
|
20902
21252
|
init_providerLogos();
|
|
20903
21253
|
init_buildTaskList();
|
|
20904
21254
|
init_prompts();
|
|
20905
21255
|
init_providerLaunchPaths();
|
|
20906
21256
|
init_launchRunway();
|
|
20907
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
|
+
};
|
|
20908
21264
|
CONNECT_PROVIDER_PRIORITY = ["supabase", "vercel", "stripe"];
|
|
20909
21265
|
providerDashboardUrls = {
|
|
20910
21266
|
supabase: "https://supabase.com/dashboard/projects",
|
|
@@ -21201,18 +21557,18 @@ var init_planLimits = __esm({
|
|
|
21201
21557
|
// src/hosted/credentials.ts
|
|
21202
21558
|
function defaultConfigDir(env = process.env, platform = process.platform) {
|
|
21203
21559
|
const override = env.VIBERAVEN_CONFIG_DIR?.trim();
|
|
21204
|
-
if (override) return (0,
|
|
21560
|
+
if (override) return (0, import_node_path39.resolve)(override);
|
|
21205
21561
|
if (platform === "win32") {
|
|
21206
|
-
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");
|
|
21207
21563
|
}
|
|
21208
21564
|
if (platform === "darwin") {
|
|
21209
|
-
return (0,
|
|
21565
|
+
return (0, import_node_path39.join)((0, import_node_os2.homedir)(), "Library", "Application Support", "viberaven");
|
|
21210
21566
|
}
|
|
21211
|
-
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");
|
|
21212
21568
|
}
|
|
21213
21569
|
function isInside(child, parent) {
|
|
21214
|
-
const rel = (0,
|
|
21215
|
-
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);
|
|
21216
21572
|
}
|
|
21217
21573
|
async function retryTransient(work) {
|
|
21218
21574
|
for (let attempt = 1; ; attempt += 1) {
|
|
@@ -21225,15 +21581,15 @@ async function retryTransient(work) {
|
|
|
21225
21581
|
}
|
|
21226
21582
|
}
|
|
21227
21583
|
}
|
|
21228
|
-
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;
|
|
21229
21585
|
var init_credentials = __esm({
|
|
21230
21586
|
"src/hosted/credentials.ts"() {
|
|
21231
21587
|
"use strict";
|
|
21232
21588
|
import_node_child_process9 = require("node:child_process");
|
|
21233
21589
|
import_node_crypto4 = require("node:crypto");
|
|
21234
|
-
|
|
21590
|
+
import_promises31 = require("node:fs/promises");
|
|
21235
21591
|
import_node_os2 = require("node:os");
|
|
21236
|
-
|
|
21592
|
+
import_node_path39 = require("node:path");
|
|
21237
21593
|
CREDENTIALS_FILE_NAME = "credentials.json";
|
|
21238
21594
|
CredentialLocationError = class extends Error {
|
|
21239
21595
|
};
|
|
@@ -21260,9 +21616,9 @@ var init_credentials = __esm({
|
|
|
21260
21616
|
constructor(configDir, workspacePath, options = {}) {
|
|
21261
21617
|
this.configDir = configDir;
|
|
21262
21618
|
this.workspacePath = workspacePath;
|
|
21263
|
-
this.path = (0,
|
|
21619
|
+
this.path = (0, import_node_path39.join)(configDir, CREDENTIALS_FILE_NAME);
|
|
21264
21620
|
this.restrict = options.restrict !== void 0 ? options.restrict : process.platform === "win32" ? restrictWithIcacls : null;
|
|
21265
|
-
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 };
|
|
21266
21622
|
}
|
|
21267
21623
|
path;
|
|
21268
21624
|
restrict;
|
|
@@ -21311,15 +21667,15 @@ var init_credentials = __esm({
|
|
|
21311
21667
|
`Refusing to store the VibeRaven sign-in inside this project (${this.configDir}). Set VIBERAVEN_CONFIG_DIR to a folder outside the repo.`
|
|
21312
21668
|
);
|
|
21313
21669
|
}
|
|
21314
|
-
await (0,
|
|
21670
|
+
await (0, import_promises31.mkdir)(this.configDir, { recursive: true, mode: 448 });
|
|
21315
21671
|
const temp = `${this.path}.${(0, import_node_crypto4.randomUUID)()}.tmp`;
|
|
21316
|
-
await (0,
|
|
21672
|
+
await (0, import_promises31.writeFile)(temp, `${JSON.stringify(body, null, 2)}
|
|
21317
21673
|
`, { encoding: "utf8", mode: 384 });
|
|
21318
|
-
await (0,
|
|
21674
|
+
await (0, import_promises31.chmod)(temp, 384).catch(() => void 0);
|
|
21319
21675
|
try {
|
|
21320
21676
|
if (this.restrict) await this.restrict(temp);
|
|
21321
21677
|
} catch (error) {
|
|
21322
|
-
await (0,
|
|
21678
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21323
21679
|
const code = error?.code;
|
|
21324
21680
|
const toolMissing = code === "ENOENT";
|
|
21325
21681
|
throw new CredentialPermissionError(
|
|
@@ -21330,17 +21686,17 @@ var init_credentials = __esm({
|
|
|
21330
21686
|
if (guard) {
|
|
21331
21687
|
const onDisk = await this.readFor(guard.apiBaseUrl);
|
|
21332
21688
|
if (onDisk?.accessToken !== guard.accessToken || guard.isCurrent && !guard.isCurrent()) {
|
|
21333
|
-
await (0,
|
|
21689
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21334
21690
|
return false;
|
|
21335
21691
|
}
|
|
21336
21692
|
}
|
|
21337
21693
|
try {
|
|
21338
21694
|
await retryTransient(() => this.fs.rename(temp, this.path));
|
|
21339
21695
|
} catch (error) {
|
|
21340
|
-
await (0,
|
|
21696
|
+
await (0, import_promises31.rm)(temp, { force: true });
|
|
21341
21697
|
throw error;
|
|
21342
21698
|
}
|
|
21343
|
-
await (0,
|
|
21699
|
+
await (0, import_promises31.chmod)(this.path, 384).catch(() => void 0);
|
|
21344
21700
|
return true;
|
|
21345
21701
|
}
|
|
21346
21702
|
/** Keeps the stored plan label in step with what the API last said. */
|
|
@@ -21709,7 +22065,7 @@ async function buildHostedCheckPayload(workspacePath) {
|
|
|
21709
22065
|
throw new Error("Could not assemble the full check request.");
|
|
21710
22066
|
}
|
|
21711
22067
|
function finalizePayload(payload) {
|
|
21712
|
-
const folder = (0,
|
|
22068
|
+
const folder = (0, import_node_path40.basename)(payload.workspacePath.split("\\").join("/").replace(/\/+$/, "")) || "project";
|
|
21713
22069
|
const redacted = redactPayload({ ...payload, workspacePath: folder });
|
|
21714
22070
|
return { payload: redacted.payload, redactions: redacted.count };
|
|
21715
22071
|
}
|
|
@@ -21740,13 +22096,13 @@ function splitSections(prompt) {
|
|
|
21740
22096
|
chars: section.length
|
|
21741
22097
|
}));
|
|
21742
22098
|
}
|
|
21743
|
-
var
|
|
22099
|
+
var import_node_path40, PayloadCaptured;
|
|
21744
22100
|
var init_payload = __esm({
|
|
21745
22101
|
"src/hosted/payload.ts"() {
|
|
21746
22102
|
"use strict";
|
|
21747
22103
|
init_fileScanner();
|
|
21748
22104
|
init_orchestrator();
|
|
21749
|
-
|
|
22105
|
+
import_node_path40 = require("node:path");
|
|
21750
22106
|
init_config();
|
|
21751
22107
|
init_redact();
|
|
21752
22108
|
PayloadCaptured = class extends Error {
|
|
@@ -22212,10 +22568,10 @@ async function connectProviderMcp(cwd, providerId) {
|
|
|
22212
22568
|
if (!recipe) {
|
|
22213
22569
|
return { ok: false, message: `No known MCP server for ${providerId} yet. Add one manually to .mcp.json.` };
|
|
22214
22570
|
}
|
|
22215
|
-
const configPath = (0,
|
|
22571
|
+
const configPath = (0, import_node_path41.join)(cwd, ".mcp.json");
|
|
22216
22572
|
let config = {};
|
|
22217
22573
|
try {
|
|
22218
|
-
const raw = await (0,
|
|
22574
|
+
const raw = await (0, import_promises32.readFile)(configPath, "utf8");
|
|
22219
22575
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
22220
22576
|
if (!isRecord5(parsed) || parsed.mcpServers !== void 0 && !isRecord5(parsed.mcpServers)) {
|
|
22221
22577
|
return { ok: false, message: "Existing .mcp.json has an unsupported structure. It was left unchanged." };
|
|
@@ -22232,7 +22588,7 @@ async function connectProviderMcp(cwd, providerId) {
|
|
|
22232
22588
|
}
|
|
22233
22589
|
servers[providerId] = recipe.entry;
|
|
22234
22590
|
const next = { ...config, mcpServers: servers };
|
|
22235
|
-
await (0,
|
|
22591
|
+
await (0, import_promises32.writeFile)(configPath, `${JSON.stringify(next, null, 2)}
|
|
22236
22592
|
`, "utf8");
|
|
22237
22593
|
const suffix = recipe.note ? ` ${recipe.note}` : "";
|
|
22238
22594
|
return { ok: true, message: `Added ${providerId} MCP server to .mcp.json.${suffix}`, path: ".mcp.json" };
|
|
@@ -22285,7 +22641,7 @@ async function defaultScanRunner(flags, positional) {
|
|
|
22285
22641
|
}
|
|
22286
22642
|
async function readPackageJson(cwd) {
|
|
22287
22643
|
try {
|
|
22288
|
-
const raw = await (0,
|
|
22644
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, "package.json"), "utf8");
|
|
22289
22645
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
22290
22646
|
return isRecord5(parsed) ? parsed : {};
|
|
22291
22647
|
} catch {
|
|
@@ -22308,7 +22664,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
|
|
|
22308
22664
|
if (files.length >= maxFiles) return;
|
|
22309
22665
|
let entries;
|
|
22310
22666
|
try {
|
|
22311
|
-
entries = await (0,
|
|
22667
|
+
entries = await (0, import_promises32.readdir)(dir, { withFileTypes: true });
|
|
22312
22668
|
} catch {
|
|
22313
22669
|
return;
|
|
22314
22670
|
}
|
|
@@ -22316,7 +22672,7 @@ async function listProjectFiles(cwd, maxFiles = 1800) {
|
|
|
22316
22672
|
if (files.length >= maxFiles) return;
|
|
22317
22673
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
22318
22674
|
if (entry.isDirectory()) {
|
|
22319
|
-
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);
|
|
22320
22676
|
continue;
|
|
22321
22677
|
}
|
|
22322
22678
|
if (entry.isFile()) files.push(rel.toLowerCase());
|
|
@@ -22335,7 +22691,7 @@ async function readEnvKeys(cwd) {
|
|
|
22335
22691
|
const keys = /* @__PURE__ */ new Set();
|
|
22336
22692
|
for (const name of [".env.example", ".env"]) {
|
|
22337
22693
|
try {
|
|
22338
|
-
const raw = await (0,
|
|
22694
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, name), "utf8");
|
|
22339
22695
|
for (const line of raw.split(/\r?\n/)) {
|
|
22340
22696
|
const trimmed = line.trim();
|
|
22341
22697
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -22653,7 +23009,7 @@ async function codexModelOptions() {
|
|
|
22653
23009
|
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }
|
|
22654
23010
|
];
|
|
22655
23011
|
try {
|
|
22656
|
-
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");
|
|
22657
23013
|
const parsed = JSON.parse(raw);
|
|
22658
23014
|
const list = Array.isArray(parsed) ? parsed : parsed.models ?? [];
|
|
22659
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 }));
|
|
@@ -22856,19 +23212,19 @@ function isPlaceholderProjectName(value) {
|
|
|
22856
23212
|
async function readMcpEvidence(cwd) {
|
|
22857
23213
|
const candidates = MCP_CONFIG_PATHS.map((relativePath) => ({
|
|
22858
23214
|
source: relativePath.replace(/\\/g, "/"),
|
|
22859
|
-
path: (0,
|
|
23215
|
+
path: (0, import_node_path41.resolve)(cwd, relativePath)
|
|
22860
23216
|
}));
|
|
22861
23217
|
const home = process.env.USERPROFILE || process.env.HOME;
|
|
22862
23218
|
if (home) {
|
|
22863
23219
|
candidates.push({
|
|
22864
23220
|
source: "~/.codex/config.toml",
|
|
22865
|
-
path: (0,
|
|
23221
|
+
path: (0, import_node_path41.resolve)(home, ".codex", "config.toml")
|
|
22866
23222
|
});
|
|
22867
23223
|
}
|
|
22868
23224
|
const evidence = [];
|
|
22869
23225
|
for (const candidate of candidates) {
|
|
22870
23226
|
try {
|
|
22871
|
-
const text = await (0,
|
|
23227
|
+
const text = await (0, import_promises32.readFile)(candidate.path, "utf8");
|
|
22872
23228
|
if (/mcp/i.test(text)) evidence.push({ source: candidate.source, text });
|
|
22873
23229
|
} catch {
|
|
22874
23230
|
}
|
|
@@ -22959,7 +23315,7 @@ async function enrichProjectMetadata(state, cwd) {
|
|
|
22959
23315
|
async function readState(cwd) {
|
|
22960
23316
|
let state;
|
|
22961
23317
|
try {
|
|
22962
|
-
const raw = await (0,
|
|
23318
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "last-scan.json"), "utf8");
|
|
22963
23319
|
const packageJson = await readPackageJson(cwd);
|
|
22964
23320
|
const deps = dependencyNames(packageJson);
|
|
22965
23321
|
const files = await listProjectFiles(cwd);
|
|
@@ -23226,7 +23582,7 @@ async function whereExe(command, cwd) {
|
|
|
23226
23582
|
}
|
|
23227
23583
|
function expandShimPath(value, base) {
|
|
23228
23584
|
const relative8 = value.replace(/^%(?:dp0%\\+|~dp0\\*)/i, "");
|
|
23229
|
-
return relative8 === value ? value : (0,
|
|
23585
|
+
return relative8 === value ? value : (0, import_node_path41.join)(base, ...relative8.split(/[\\/]+/));
|
|
23230
23586
|
}
|
|
23231
23587
|
function findShimTarget(lines, pattern, accept = () => true) {
|
|
23232
23588
|
for (const line of lines) {
|
|
@@ -23237,21 +23593,21 @@ function findShimTarget(lines, pattern, accept = () => true) {
|
|
|
23237
23593
|
}
|
|
23238
23594
|
async function resolveWindowsShimTarget(shimPath) {
|
|
23239
23595
|
try {
|
|
23240
|
-
const content = await (0,
|
|
23241
|
-
const base = (0,
|
|
23596
|
+
const content = await (0, import_promises32.readFile)(shimPath, "utf8");
|
|
23597
|
+
const base = (0, import_node_path41.dirname)(shimPath);
|
|
23242
23598
|
const lines = content.split(/\r?\n/);
|
|
23243
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("%"));
|
|
23244
23600
|
const script = findShimTarget(lines, /"%(?:dp0%\\+|~dp0\\*)([^"]+\.js)"/i);
|
|
23245
23601
|
if (script) {
|
|
23246
23602
|
return {
|
|
23247
23603
|
command: process.execPath,
|
|
23248
|
-
args: [(0,
|
|
23604
|
+
args: [(0, import_node_path41.join)(base, ...script.match[1].split(/[\\/]+/)), ...trailingArgs(script.line, script.match.index + script.match[0].length)]
|
|
23249
23605
|
};
|
|
23250
23606
|
}
|
|
23251
|
-
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");
|
|
23252
23608
|
if (binary) {
|
|
23253
23609
|
return {
|
|
23254
|
-
command: (0,
|
|
23610
|
+
command: (0, import_node_path41.join)(base, ...binary.match[1].split(/[\\/]+/)),
|
|
23255
23611
|
args: trailingArgs(binary.line, binary.match.index + binary.match[0].length)
|
|
23256
23612
|
};
|
|
23257
23613
|
}
|
|
@@ -23376,8 +23732,8 @@ async function writeChatContextArtifact(cwd, request, prompt) {
|
|
|
23376
23732
|
"",
|
|
23377
23733
|
prompt
|
|
23378
23734
|
].filter((line) => typeof line === "string");
|
|
23379
|
-
await (0,
|
|
23380
|
-
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")}
|
|
23381
23737
|
`, "utf8");
|
|
23382
23738
|
} catch {
|
|
23383
23739
|
}
|
|
@@ -23397,13 +23753,13 @@ async function runAgentChat(cwd, request) {
|
|
|
23397
23753
|
}
|
|
23398
23754
|
const prompt = await buildAgentChatPrompt(request, cwd);
|
|
23399
23755
|
await writeChatContextArtifact(cwd, request, prompt);
|
|
23400
|
-
const outputPath = request.cliId === "codex" ? (0,
|
|
23401
|
-
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 });
|
|
23402
23758
|
const { command, args, stdin } = commandForAgentChat(request, prompt, cwd, outputPath);
|
|
23403
23759
|
const result = await runAgentCommand(command, args, cwd, stdin, request.runId);
|
|
23404
23760
|
if (outputPath) {
|
|
23405
23761
|
try {
|
|
23406
|
-
const finalMessage = (await (0,
|
|
23762
|
+
const finalMessage = (await (0, import_promises32.readFile)(outputPath, "utf8")).trim();
|
|
23407
23763
|
if (finalMessage) return { ...result, output: finalMessage };
|
|
23408
23764
|
} catch {
|
|
23409
23765
|
}
|
|
@@ -23415,8 +23771,8 @@ function firstGapId(state) {
|
|
|
23415
23771
|
return state.providers.find((provider2) => provider2.nextFix?.id)?.nextFix?.id;
|
|
23416
23772
|
}
|
|
23417
23773
|
async function runLocalAction(cwd, intent) {
|
|
23418
|
-
const artifactDir = (0,
|
|
23419
|
-
await (0,
|
|
23774
|
+
const artifactDir = (0, import_node_path41.join)(cwd, ".viberaven");
|
|
23775
|
+
await (0, import_promises32.mkdir)(artifactDir, { recursive: true });
|
|
23420
23776
|
if (intent === "preview_rehearsal") {
|
|
23421
23777
|
const state2 = await readState(cwd);
|
|
23422
23778
|
const topProvider = state2.providers[0];
|
|
@@ -23457,7 +23813,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23457
23813
|
proof,
|
|
23458
23814
|
""
|
|
23459
23815
|
].join("\n");
|
|
23460
|
-
await (0,
|
|
23816
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "preview-rehearsal.md"), markdown, "utf8");
|
|
23461
23817
|
return {
|
|
23462
23818
|
title: "Preview rehearsal ready",
|
|
23463
23819
|
summary: `${projectName}: ${gateLabel} with ${state2.providers.length} provider beat${state2.providers.length === 1 ? "" : "s"}`,
|
|
@@ -23467,7 +23823,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23467
23823
|
if (intent === "audit_vercel_supabase") {
|
|
23468
23824
|
const auditInput = await collectVercelSupabaseAuditInput(cwd);
|
|
23469
23825
|
const result2 = buildVercelSupabaseAudit(auditInput);
|
|
23470
|
-
await (0,
|
|
23826
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "audit-vercel-supabase.txt"), `${renderVercelSupabaseAudit(result2)}
|
|
23471
23827
|
`, "utf8");
|
|
23472
23828
|
return {
|
|
23473
23829
|
title: result2.status === "pass" ? "Audit passed" : "Audit needs work",
|
|
@@ -23495,7 +23851,7 @@ async function runLocalAction(cwd, intent) {
|
|
|
23495
23851
|
const mode = intent === "heal_prompt" ? "prompt" : intent === "heal_apply" ? "apply" : "plan";
|
|
23496
23852
|
const result = await runHealCommand({ cwd, mode, gapId, yes: mode === "apply", noVerify: true });
|
|
23497
23853
|
if (mode === "apply") {
|
|
23498
|
-
await (0,
|
|
23854
|
+
await (0, import_promises32.writeFile)((0, import_node_path41.join)(artifactDir, "heal-apply-result.json"), `${JSON.stringify(result, null, 2)}
|
|
23499
23855
|
`, "utf8");
|
|
23500
23856
|
}
|
|
23501
23857
|
return {
|
|
@@ -23505,14 +23861,14 @@ async function runLocalAction(cwd, intent) {
|
|
|
23505
23861
|
};
|
|
23506
23862
|
}
|
|
23507
23863
|
async function sendArtifact(cwd, rel, response, contentType = "text/plain; charset=utf-8") {
|
|
23508
|
-
const absolute = (0,
|
|
23509
|
-
const root = (0,
|
|
23864
|
+
const absolute = (0, import_node_path41.resolve)(cwd, rel);
|
|
23865
|
+
const root = (0, import_node_path41.resolve)(cwd);
|
|
23510
23866
|
if (!absolute.startsWith(root)) {
|
|
23511
23867
|
sendText(response, 403, "Forbidden");
|
|
23512
23868
|
return;
|
|
23513
23869
|
}
|
|
23514
23870
|
try {
|
|
23515
|
-
const text = await (0,
|
|
23871
|
+
const text = await (0, import_promises32.readFile)(absolute, "utf8");
|
|
23516
23872
|
response.writeHead(200, { "content-type": contentType });
|
|
23517
23873
|
response.end(text);
|
|
23518
23874
|
} catch {
|
|
@@ -23521,7 +23877,7 @@ async function sendArtifact(cwd, rel, response, contentType = "text/plain; chars
|
|
|
23521
23877
|
}
|
|
23522
23878
|
async function sendReportArtifact(cwd, response) {
|
|
23523
23879
|
try {
|
|
23524
|
-
const text = await (0,
|
|
23880
|
+
const text = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "report.html"), "utf8");
|
|
23525
23881
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
23526
23882
|
response.end(text);
|
|
23527
23883
|
return;
|
|
@@ -23648,7 +24004,7 @@ async function sendReportArtifact(cwd, response) {
|
|
|
23648
24004
|
}
|
|
23649
24005
|
async function sendExtensionIcon(cwd, response) {
|
|
23650
24006
|
try {
|
|
23651
|
-
const body = await (0,
|
|
24007
|
+
const body = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, "media", "extension-icon.png"));
|
|
23652
24008
|
sendBinary(response, 200, "image/png", body);
|
|
23653
24009
|
} catch {
|
|
23654
24010
|
sendText(response, 404, "Icon not found");
|
|
@@ -23661,15 +24017,15 @@ async function sendMangaAsset(pathname, response) {
|
|
|
23661
24017
|
return;
|
|
23662
24018
|
}
|
|
23663
24019
|
const candidates = [
|
|
23664
|
-
(0,
|
|
24020
|
+
(0, import_node_path41.join)(__dirname, "manga", name),
|
|
23665
24021
|
// installed + dev: <pkg>/dist/manga
|
|
23666
|
-
(0,
|
|
24022
|
+
(0, import_node_path41.join)(__dirname, "..", "assets", "manga", name),
|
|
23667
24023
|
// fallback: <pkg>/assets/manga (source)
|
|
23668
|
-
(0,
|
|
24024
|
+
(0, import_node_path41.join)(__dirname, "..", "..", "assets", "manga", name)
|
|
23669
24025
|
];
|
|
23670
24026
|
for (const candidate of candidates) {
|
|
23671
24027
|
try {
|
|
23672
|
-
const body = await (0,
|
|
24028
|
+
const body = await (0, import_promises32.readFile)(candidate);
|
|
23673
24029
|
response.setHeader("cache-control", "no-cache");
|
|
23674
24030
|
sendBinary(response, 200, contentTypeForAsset(candidate), body);
|
|
23675
24031
|
return;
|
|
@@ -23679,7 +24035,7 @@ async function sendMangaAsset(pathname, response) {
|
|
|
23679
24035
|
sendText(response, 404, "Asset not found");
|
|
23680
24036
|
}
|
|
23681
24037
|
function contentTypeForAsset(pathname) {
|
|
23682
|
-
switch ((0,
|
|
24038
|
+
switch ((0, import_node_path41.extname)(pathname).toLowerCase()) {
|
|
23683
24039
|
case ".svg":
|
|
23684
24040
|
return "image/svg+xml; charset=utf-8";
|
|
23685
24041
|
case ".png":
|
|
@@ -23696,14 +24052,14 @@ function contentTypeForAsset(pathname) {
|
|
|
23696
24052
|
}
|
|
23697
24053
|
async function sendBundledReportAsset(pathname, response) {
|
|
23698
24054
|
const rel = decodeURIComponent(pathname.replace(/^\/report\//, ""));
|
|
23699
|
-
const assetRoot = (0,
|
|
23700
|
-
const absolute = (0,
|
|
24055
|
+
const assetRoot = (0, import_node_path41.resolve)(getBundledReportAssetsDir());
|
|
24056
|
+
const absolute = (0, import_node_path41.resolve)(assetRoot, rel);
|
|
23701
24057
|
if (!absolute.startsWith(assetRoot)) {
|
|
23702
24058
|
sendText(response, 403, "Forbidden");
|
|
23703
24059
|
return;
|
|
23704
24060
|
}
|
|
23705
24061
|
try {
|
|
23706
|
-
const body = await (0,
|
|
24062
|
+
const body = await (0, import_promises32.readFile)(absolute);
|
|
23707
24063
|
sendBinary(response, 200, contentTypeForAsset(absolute), body);
|
|
23708
24064
|
} catch {
|
|
23709
24065
|
sendText(response, 404, "Asset not found");
|
|
@@ -23725,18 +24081,18 @@ async function bundleStackClient(entryPath) {
|
|
|
23725
24081
|
return output.text;
|
|
23726
24082
|
}
|
|
23727
24083
|
async function sendStackAppJs(response) {
|
|
23728
|
-
const distPath = (0,
|
|
24084
|
+
const distPath = (0, import_node_path41.join)(__dirname, "stack", "app.js");
|
|
23729
24085
|
try {
|
|
23730
|
-
const body = await (0,
|
|
24086
|
+
const body = await (0, import_promises32.readFile)(distPath);
|
|
23731
24087
|
response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "cache-control": "no-store" });
|
|
23732
24088
|
response.end(body);
|
|
23733
24089
|
return;
|
|
23734
24090
|
} catch {
|
|
23735
24091
|
}
|
|
23736
|
-
const entryPath = (0,
|
|
24092
|
+
const entryPath = (0, import_node_path41.join)(__dirname, "stack", "main.ts");
|
|
23737
24093
|
let mtimeMs;
|
|
23738
24094
|
try {
|
|
23739
|
-
mtimeMs = (await (0,
|
|
24095
|
+
mtimeMs = (await (0, import_promises32.stat)(entryPath)).mtimeMs;
|
|
23740
24096
|
} catch {
|
|
23741
24097
|
sendText(response, 404, "Stack client entry not found: src/local-ui/stack/main.ts is missing.");
|
|
23742
24098
|
return;
|
|
@@ -23755,7 +24111,7 @@ async function sendStackAppJs(response) {
|
|
|
23755
24111
|
}
|
|
23756
24112
|
async function sendStackAppCss(response) {
|
|
23757
24113
|
try {
|
|
23758
|
-
const body = await (0,
|
|
24114
|
+
const body = await (0, import_promises32.readFile)((0, import_node_path41.join)(__dirname, "stack", "stack.css"));
|
|
23759
24115
|
response.writeHead(200, { "content-type": "text/css; charset=utf-8", "cache-control": "no-store" });
|
|
23760
24116
|
response.end(body);
|
|
23761
24117
|
} catch {
|
|
@@ -23764,7 +24120,7 @@ async function sendStackAppCss(response) {
|
|
|
23764
24120
|
}
|
|
23765
24121
|
async function readProviderVerifyLedger(cwd) {
|
|
23766
24122
|
try {
|
|
23767
|
-
const raw = await (0,
|
|
24123
|
+
const raw = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "provider-verify.json"), "utf8");
|
|
23768
24124
|
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
23769
24125
|
return isRecord5(parsed) ? parsed : {};
|
|
23770
24126
|
} catch {
|
|
@@ -23774,8 +24130,8 @@ async function readProviderVerifyLedger(cwd) {
|
|
|
23774
24130
|
async function writeProviderVerifyEntry(cwd, providerId, entry) {
|
|
23775
24131
|
const ledger = await readProviderVerifyLedger(cwd);
|
|
23776
24132
|
ledger[providerId] = entry;
|
|
23777
|
-
await (0,
|
|
23778
|
-
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)}
|
|
23779
24135
|
`, "utf8");
|
|
23780
24136
|
}
|
|
23781
24137
|
async function handleRequest(request, response, options) {
|
|
@@ -23848,13 +24204,13 @@ async function handleRequest(request, response, options) {
|
|
|
23848
24204
|
return;
|
|
23849
24205
|
}
|
|
23850
24206
|
if (request.method === "GET" && url.pathname === "/api/architecture-map") {
|
|
23851
|
-
const mapPath = (0,
|
|
23852
|
-
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);
|
|
23853
24209
|
if (markdown === null) {
|
|
23854
24210
|
sendJsonStatus(response, 404, { error: "No architecture map yet. Run a scan first (it is written on every scan)." });
|
|
23855
24211
|
return;
|
|
23856
24212
|
}
|
|
23857
|
-
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);
|
|
23858
24214
|
let data = null;
|
|
23859
24215
|
if (dataRaw) {
|
|
23860
24216
|
try {
|
|
@@ -23863,7 +24219,7 @@ async function handleRequest(request, response, options) {
|
|
|
23863
24219
|
data = null;
|
|
23864
24220
|
}
|
|
23865
24221
|
}
|
|
23866
|
-
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);
|
|
23867
24223
|
let gaps = [];
|
|
23868
24224
|
if (contextRaw) {
|
|
23869
24225
|
try {
|
|
@@ -24129,35 +24485,35 @@ async function handleRequest(request, response, options) {
|
|
|
24129
24485
|
return;
|
|
24130
24486
|
}
|
|
24131
24487
|
if (request.method === "GET" && url.pathname === "/api/artifacts/tasklist") {
|
|
24132
|
-
await sendArtifact(options.cwd, (0,
|
|
24488
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "agent-tasklist.md"), response);
|
|
24133
24489
|
return;
|
|
24134
24490
|
}
|
|
24135
24491
|
if (request.method === "GET" && url.pathname === "/api/artifacts/playbook") {
|
|
24136
|
-
await sendArtifact(options.cwd, (0,
|
|
24492
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "launch-playbook.md"), response);
|
|
24137
24493
|
return;
|
|
24138
24494
|
}
|
|
24139
24495
|
if (request.method === "GET" && url.pathname === "/api/artifacts/audit") {
|
|
24140
|
-
await sendArtifact(options.cwd, (0,
|
|
24496
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "audit-vercel-supabase.txt"), response);
|
|
24141
24497
|
return;
|
|
24142
24498
|
}
|
|
24143
24499
|
if (request.method === "GET" && url.pathname === "/api/artifacts/cleanup") {
|
|
24144
|
-
await sendArtifact(options.cwd, (0,
|
|
24500
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "context-cleanup.md"), response);
|
|
24145
24501
|
return;
|
|
24146
24502
|
}
|
|
24147
24503
|
if (request.method === "GET" && url.pathname === "/api/artifacts/preview") {
|
|
24148
|
-
await sendArtifact(options.cwd, (0,
|
|
24504
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "preview-rehearsal.md"), response);
|
|
24149
24505
|
return;
|
|
24150
24506
|
}
|
|
24151
24507
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-plan") {
|
|
24152
|
-
await sendArtifact(options.cwd, (0,
|
|
24508
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "heal-plan.md"), response);
|
|
24153
24509
|
return;
|
|
24154
24510
|
}
|
|
24155
24511
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-prompt") {
|
|
24156
|
-
await sendArtifact(options.cwd, (0,
|
|
24512
|
+
await sendArtifact(options.cwd, (0, import_node_path41.join)(".viberaven", "heal-prompt.md"), response);
|
|
24157
24513
|
return;
|
|
24158
24514
|
}
|
|
24159
24515
|
if (request.method === "GET" && url.pathname === "/api/artifacts/heal-apply") {
|
|
24160
|
-
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");
|
|
24161
24517
|
return;
|
|
24162
24518
|
}
|
|
24163
24519
|
if (request.method === "GET" && url.pathname === "/api/artifacts/report") {
|
|
@@ -24183,12 +24539,12 @@ async function handleRequest(request, response, options) {
|
|
|
24183
24539
|
}
|
|
24184
24540
|
if (request.method === "GET" && url.pathname === "/vendor/anime.umd.min.js") {
|
|
24185
24541
|
for (const candidate of [
|
|
24186
|
-
(0,
|
|
24187
|
-
(0,
|
|
24188
|
-
(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")
|
|
24189
24545
|
]) {
|
|
24190
24546
|
try {
|
|
24191
|
-
const body = await (0,
|
|
24547
|
+
const body = await (0, import_promises32.readFile)(candidate);
|
|
24192
24548
|
response.setHeader("cache-control", "public, max-age=604800, immutable");
|
|
24193
24549
|
sendBinary(response, 200, "text/javascript; charset=utf-8", body);
|
|
24194
24550
|
return;
|
|
@@ -24405,7 +24761,7 @@ function listen(server, startPort) {
|
|
|
24405
24761
|
});
|
|
24406
24762
|
}
|
|
24407
24763
|
async function startLocalUiServer(options) {
|
|
24408
|
-
const cwd = (0,
|
|
24764
|
+
const cwd = (0, import_node_path41.resolve)(options.cwd);
|
|
24409
24765
|
const scanRunner = options.scanRunner ?? defaultScanRunner;
|
|
24410
24766
|
const autoScan = { state: "idle" };
|
|
24411
24767
|
const fullCheck = new FullCheckService(cwd, options.fullCheck);
|
|
@@ -24422,7 +24778,7 @@ async function startLocalUiServer(options) {
|
|
|
24422
24778
|
});
|
|
24423
24779
|
const port = await listen(server, options.port ?? 4177);
|
|
24424
24780
|
guard.port = port;
|
|
24425
|
-
const hasArtifact = await (0,
|
|
24781
|
+
const hasArtifact = await (0, import_promises32.readFile)((0, import_node_path41.join)(cwd, ".viberaven", "last-scan.json"), "utf8").then(
|
|
24426
24782
|
() => true,
|
|
24427
24783
|
() => false
|
|
24428
24784
|
);
|
|
@@ -24461,16 +24817,16 @@ async function waitForServerShutdown() {
|
|
|
24461
24817
|
process.once("SIGTERM", done);
|
|
24462
24818
|
});
|
|
24463
24819
|
}
|
|
24464
|
-
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;
|
|
24465
24821
|
var init_server = __esm({
|
|
24466
24822
|
"src/local-ui/server.ts"() {
|
|
24467
24823
|
"use strict";
|
|
24468
24824
|
import_node_http = require("node:http");
|
|
24469
24825
|
import_node_child_process10 = require("node:child_process");
|
|
24470
24826
|
import_node_crypto6 = require("node:crypto");
|
|
24471
|
-
|
|
24827
|
+
import_promises32 = require("node:fs/promises");
|
|
24472
24828
|
import_node_os3 = require("node:os");
|
|
24473
|
-
|
|
24829
|
+
import_node_path41 = require("node:path");
|
|
24474
24830
|
init_initGithub();
|
|
24475
24831
|
init_cleanPlan();
|
|
24476
24832
|
init_audit();
|
|
@@ -24512,8 +24868,8 @@ var init_server = __esm({
|
|
|
24512
24868
|
MCP_CONFIG_PATHS = [
|
|
24513
24869
|
".mcp.json",
|
|
24514
24870
|
"mcp.json",
|
|
24515
|
-
(0,
|
|
24516
|
-
(0,
|
|
24871
|
+
(0, import_node_path41.join)(".cursor", "mcp.json"),
|
|
24872
|
+
(0, import_node_path41.join)(".vscode", "mcp.json")
|
|
24517
24873
|
];
|
|
24518
24874
|
MCP_PROVIDER_NEEDLES = {
|
|
24519
24875
|
supabase: ["supabase", "@supabase/mcp", "mcp-server-supabase"],
|
|
@@ -24595,6 +24951,7 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24595
24951
|
mcpTool: repoCodeTask.mcpTool,
|
|
24596
24952
|
mcpArgs: repoCodeTask.mcpArgs,
|
|
24597
24953
|
fallbackCommand: repoCodeTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${repoCodeTask.gapId} --yes` : void 0,
|
|
24954
|
+
...whereAndAfter(repoCodeTask),
|
|
24598
24955
|
requiresUserAction: false
|
|
24599
24956
|
};
|
|
24600
24957
|
}
|
|
@@ -24608,6 +24965,7 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24608
24965
|
mcpTool: userTask.mcpTool,
|
|
24609
24966
|
mcpArgs: userTask.mcpArgs,
|
|
24610
24967
|
fallbackCommand: userTask.mcpArgs ? `npx -y viberaven --heal --apply --gap ${userTask.gapId} --yes` : void 0,
|
|
24968
|
+
...whereAndAfter(userTask),
|
|
24611
24969
|
requiresUserAction: true
|
|
24612
24970
|
};
|
|
24613
24971
|
}
|
|
@@ -24623,10 +24981,17 @@ function buildNextActionBlock(tasks, loopState) {
|
|
|
24623
24981
|
return {
|
|
24624
24982
|
...base,
|
|
24625
24983
|
type: "done",
|
|
24626
|
-
title: "
|
|
24984
|
+
title: "No repo-code or provider tasks left; gate-result.json has the verdict",
|
|
24627
24985
|
requiresUserAction: false
|
|
24628
24986
|
};
|
|
24629
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
|
+
}
|
|
24630
24995
|
function resolveStallReason(tasks) {
|
|
24631
24996
|
if (tasks.length === 0) return "no-recipes";
|
|
24632
24997
|
const allProviderAction = tasks.every((t) => t.fixType === "provider-action");
|
|
@@ -24684,9 +25049,9 @@ var init_nextActionBlock = __esm({
|
|
|
24684
25049
|
function defaultMcpConfigPaths() {
|
|
24685
25050
|
const home = (0, import_node_os4.homedir)();
|
|
24686
25051
|
return [
|
|
24687
|
-
(0,
|
|
24688
|
-
(0,
|
|
24689
|
-
(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")
|
|
24690
25055
|
];
|
|
24691
25056
|
}
|
|
24692
25057
|
function resolveConfigPaths() {
|
|
@@ -24715,11 +25080,11 @@ function findServerEntry(servers, provider2) {
|
|
|
24715
25080
|
function findProviderMcpConfig(provider2, configPaths) {
|
|
24716
25081
|
const paths = configPaths ?? resolveConfigPaths();
|
|
24717
25082
|
for (const path of paths) {
|
|
24718
|
-
if (!(0,
|
|
25083
|
+
if (!(0, import_node_fs16.existsSync)(path)) {
|
|
24719
25084
|
continue;
|
|
24720
25085
|
}
|
|
24721
25086
|
try {
|
|
24722
|
-
const raw = JSON.parse((0,
|
|
25087
|
+
const raw = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
|
|
24723
25088
|
const servers = parseMcpServers(raw);
|
|
24724
25089
|
if (!servers) {
|
|
24725
25090
|
continue;
|
|
@@ -24763,13 +25128,13 @@ async function verifyProviderGap(options) {
|
|
|
24763
25128
|
fallbackCommand: FALLBACK_COMMAND
|
|
24764
25129
|
};
|
|
24765
25130
|
}
|
|
24766
|
-
var
|
|
25131
|
+
var import_node_fs16, import_node_os4, import_node_path42, FALLBACK_COMMAND, SUPPORTED_PROVIDERS, configPathsOverride;
|
|
24767
25132
|
var init_providerMcpBridge = __esm({
|
|
24768
25133
|
"src/providerMcpBridge.ts"() {
|
|
24769
25134
|
"use strict";
|
|
24770
|
-
|
|
25135
|
+
import_node_fs16 = require("node:fs");
|
|
24771
25136
|
import_node_os4 = require("node:os");
|
|
24772
|
-
|
|
25137
|
+
import_node_path42 = require("node:path");
|
|
24773
25138
|
FALLBACK_COMMAND = "npx -y viberaven audit --vercel-supabase --json";
|
|
24774
25139
|
SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["supabase", "vercel"]);
|
|
24775
25140
|
}
|
|
@@ -24992,7 +25357,7 @@ async function cmdProviderVerify(flags, positional) {
|
|
|
24992
25357
|
return result.verified ? 0 : 1;
|
|
24993
25358
|
}
|
|
24994
25359
|
async function cmdStatus(flags, positional) {
|
|
24995
|
-
const startDir = positional[0] ? (0,
|
|
25360
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
24996
25361
|
let artifact;
|
|
24997
25362
|
try {
|
|
24998
25363
|
artifact = await loadLastArtifact(startDir);
|
|
@@ -25031,7 +25396,7 @@ async function cmdStatus(flags, positional) {
|
|
|
25031
25396
|
return 0;
|
|
25032
25397
|
}
|
|
25033
25398
|
async function runScanCommand(flags, positional, options) {
|
|
25034
|
-
const workspacePath = positional[0] ? (0,
|
|
25399
|
+
const workspacePath = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : await resolveWorkspaceRoot(process.cwd());
|
|
25035
25400
|
if (!options?.deferMachineOutput) {
|
|
25036
25401
|
console.log(`Scanning ${workspacePath}\u2026 (local, offline)`);
|
|
25037
25402
|
}
|
|
@@ -25055,15 +25420,27 @@ async function runScanCommand(flags, positional, options) {
|
|
|
25055
25420
|
const updatedState = resetBatch(loopState, openGapCount);
|
|
25056
25421
|
const tasks = buildTaskList(artifact);
|
|
25057
25422
|
const block = buildNextActionBlock(tasks, updatedState);
|
|
25058
|
-
|
|
25059
|
-
printProviderActionBlock(tasks);
|
|
25423
|
+
let manifest;
|
|
25060
25424
|
try {
|
|
25061
|
-
|
|
25062
|
-
console.log(renderActionSurface(manifest, { limit: 5 }).trimEnd());
|
|
25425
|
+
manifest = JSON.parse(await (0, import_promises33.readFile)(paths.actionsPath, "utf8"));
|
|
25063
25426
|
} catch (error) {
|
|
25064
25427
|
console.warn(error instanceof Error ? error.message : String(error));
|
|
25065
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
|
+
}
|
|
25066
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
|
+
}
|
|
25067
25444
|
}
|
|
25068
25445
|
if (flags.open) {
|
|
25069
25446
|
try {
|
|
@@ -25075,7 +25452,7 @@ async function runScanCommand(flags, positional, options) {
|
|
|
25075
25452
|
return { exitCode: 0, artifacts: paths };
|
|
25076
25453
|
}
|
|
25077
25454
|
async function cmdReport(flags, positional) {
|
|
25078
|
-
const startDir = positional[0] ? (0,
|
|
25455
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25079
25456
|
try {
|
|
25080
25457
|
const paths = await refreshReportFromDisk(startDir);
|
|
25081
25458
|
console.log(`Report refreshed: ${paths.reportPath}`);
|
|
@@ -25097,7 +25474,7 @@ async function cmdReport(flags, positional) {
|
|
|
25097
25474
|
}
|
|
25098
25475
|
}
|
|
25099
25476
|
async function cmdPrompt(flags, positional) {
|
|
25100
|
-
const startDir = positional[0] ? (0,
|
|
25477
|
+
const startDir = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25101
25478
|
let artifact;
|
|
25102
25479
|
try {
|
|
25103
25480
|
artifact = await loadLastArtifact(startDir);
|
|
@@ -25194,7 +25571,7 @@ async function main() {
|
|
|
25194
25571
|
const wantsJsonl = hasFlag(flags, "jsonl");
|
|
25195
25572
|
const wantsStrict = hasFlag(flags, "strict");
|
|
25196
25573
|
if (flags.condense) {
|
|
25197
|
-
const cwd = positional[0] ? (0,
|
|
25574
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25198
25575
|
const result = await runCondenseCommand({ cwd });
|
|
25199
25576
|
console.log(`VibeRaven context map refreshed: ${result.contextMapPath}`);
|
|
25200
25577
|
return 0;
|
|
@@ -25214,18 +25591,18 @@ async function main() {
|
|
|
25214
25591
|
}
|
|
25215
25592
|
if (!command && flags.verify === true && typeof flags.action === "string") {
|
|
25216
25593
|
return runVerifyActionCommand({
|
|
25217
|
-
cwd: positional[0] ? (0,
|
|
25594
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25218
25595
|
actionId: flags.action
|
|
25219
25596
|
});
|
|
25220
25597
|
}
|
|
25221
25598
|
if (!command && (isAgentMode || flags.verify === true || wantsJson || wantsJsonl || wantsStrict)) {
|
|
25222
25599
|
const deferMachineOutput = wantsJson || wantsJsonl;
|
|
25223
|
-
const scanResult = await runScanCommand(flags, positional, { deferMachineOutput });
|
|
25600
|
+
const scanResult = await runScanCommand(flags, positional, { deferMachineOutput, markFollowUpsShown: true });
|
|
25224
25601
|
if ((wantsJson || wantsJsonl) && !scanResult.artifacts) {
|
|
25225
25602
|
console.error("VibeRaven could not produce machine output because scan artifacts were not written.");
|
|
25226
25603
|
return 3;
|
|
25227
25604
|
}
|
|
25228
|
-
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;
|
|
25229
25606
|
const strictExitCode = wantsStrict && gateResult ? exitCodeForStrictGate(gateResult, { failOnWarnings: flags.strict === "warning" }) : scanResult.exitCode;
|
|
25230
25607
|
if (wantsJson && gateResult) {
|
|
25231
25608
|
process.stdout.write(renderGateResultJson(gateResult));
|
|
@@ -25247,7 +25624,7 @@ async function main() {
|
|
|
25247
25624
|
env: process.env
|
|
25248
25625
|
});
|
|
25249
25626
|
if (mode === "local-ui") {
|
|
25250
|
-
const cwd = positional[0] ? (0,
|
|
25627
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25251
25628
|
const handle = await startLocalUiServer({ cwd, initialPath: stackInitialPath(flags) });
|
|
25252
25629
|
console.log(`VibeRaven local UI: ${handle.url}`);
|
|
25253
25630
|
await waitForServerShutdown();
|
|
@@ -25258,7 +25635,7 @@ async function main() {
|
|
|
25258
25635
|
await runInteractiveSession();
|
|
25259
25636
|
return 0;
|
|
25260
25637
|
}
|
|
25261
|
-
const scanResult = await runScanCommand({ "agent-mode": true }, positional);
|
|
25638
|
+
const scanResult = await runScanCommand({ "agent-mode": true }, positional, { markFollowUpsShown: true });
|
|
25262
25639
|
return scanResult.exitCode;
|
|
25263
25640
|
}
|
|
25264
25641
|
switch (command) {
|
|
@@ -25267,7 +25644,7 @@ async function main() {
|
|
|
25267
25644
|
await runInteractiveSession();
|
|
25268
25645
|
return 0;
|
|
25269
25646
|
case "ui": {
|
|
25270
|
-
const cwd = positional[0] ? (0,
|
|
25647
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25271
25648
|
const envPort = Number(process.env.PORT);
|
|
25272
25649
|
const handle = await startLocalUiServer({ cwd, port: Number.isFinite(envPort) && envPort > 0 ? envPort : void 0, initialPath: stackInitialPath(flags) });
|
|
25273
25650
|
console.log(`VibeRaven local UI: ${handle.url}`);
|
|
@@ -25279,14 +25656,14 @@ async function main() {
|
|
|
25279
25656
|
return cmdStatus(flags, positional);
|
|
25280
25657
|
case "check":
|
|
25281
25658
|
return runCheckCommand({
|
|
25282
|
-
cwd: positional[0] ? (0,
|
|
25659
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25283
25660
|
json: Boolean(flags.json),
|
|
25284
25661
|
quiet: Boolean(flags.quiet),
|
|
25285
25662
|
base: typeof flags.base === "string" ? flags.base : void 0,
|
|
25286
25663
|
markdown: flags.markdown === true
|
|
25287
25664
|
});
|
|
25288
25665
|
case "fix": {
|
|
25289
|
-
const fixCwd = positional[0] ? (0,
|
|
25666
|
+
const fixCwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25290
25667
|
const gapId = typeof flags.gap === "string" ? flags.gap : void 0;
|
|
25291
25668
|
if (!gapId) {
|
|
25292
25669
|
const artifact = await loadLastArtifact(fixCwd).catch(() => void 0);
|
|
@@ -25315,19 +25692,19 @@ async function main() {
|
|
|
25315
25692
|
}
|
|
25316
25693
|
case "actions":
|
|
25317
25694
|
return runActionsCommand({
|
|
25318
|
-
cwd: positional[0] ? (0,
|
|
25695
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25319
25696
|
json: Boolean(flags.json)
|
|
25320
25697
|
});
|
|
25321
25698
|
case "preview":
|
|
25322
25699
|
return runPreviewCommand({
|
|
25323
|
-
cwd: positional[0] ? (0,
|
|
25700
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25324
25701
|
agentMode: flags["agent-mode"] === true,
|
|
25325
25702
|
json: Boolean(flags.json)
|
|
25326
25703
|
});
|
|
25327
25704
|
case "next":
|
|
25328
25705
|
return runNextCommand({
|
|
25329
25706
|
json: Boolean(flags.json),
|
|
25330
|
-
cwd: positional[0] ? (0,
|
|
25707
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd()
|
|
25331
25708
|
});
|
|
25332
25709
|
case "guide": {
|
|
25333
25710
|
const provider2 = positional[0];
|
|
@@ -25349,7 +25726,7 @@ async function main() {
|
|
|
25349
25726
|
cwd: process.cwd()
|
|
25350
25727
|
});
|
|
25351
25728
|
case "scan": {
|
|
25352
|
-
const scanResult = await runScanCommand(flags, positional);
|
|
25729
|
+
const scanResult = await runScanCommand(flags, positional, { markFollowUpsShown: true });
|
|
25353
25730
|
return scanResult.exitCode;
|
|
25354
25731
|
}
|
|
25355
25732
|
case "report":
|
|
@@ -25361,7 +25738,7 @@ async function main() {
|
|
|
25361
25738
|
case "provider-verify":
|
|
25362
25739
|
return cmdProviderVerify(flags, positional);
|
|
25363
25740
|
case "init": {
|
|
25364
|
-
const cwd = positional[0] ? (0,
|
|
25741
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25365
25742
|
const agents = typeof flags.agents === "string" ? flags.agents : void 0;
|
|
25366
25743
|
if (flags.github === true) {
|
|
25367
25744
|
return runInitGithubCommand({ cwd, dryRun: flags["dry-run"] === true, force: flags.force === true });
|
|
@@ -25378,7 +25755,7 @@ async function main() {
|
|
|
25378
25755
|
return 1;
|
|
25379
25756
|
}
|
|
25380
25757
|
return runDoctorAgentsCommand({
|
|
25381
|
-
cwd: positional[0] ? (0,
|
|
25758
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd()
|
|
25382
25759
|
});
|
|
25383
25760
|
case "validate-npm-package":
|
|
25384
25761
|
return runValidateNpmPackageCommand({
|
|
@@ -25391,7 +25768,7 @@ async function main() {
|
|
|
25391
25768
|
return 1;
|
|
25392
25769
|
}
|
|
25393
25770
|
return runAuditCommand({
|
|
25394
|
-
cwd: positional[0] ? (0,
|
|
25771
|
+
cwd: positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd(),
|
|
25395
25772
|
json: Boolean(flags.json)
|
|
25396
25773
|
});
|
|
25397
25774
|
case "clean": {
|
|
@@ -25399,7 +25776,7 @@ async function main() {
|
|
|
25399
25776
|
console.error("Usage: viberaven clean --plan [path]");
|
|
25400
25777
|
return 1;
|
|
25401
25778
|
}
|
|
25402
|
-
const cwd = positional[0] ? (0,
|
|
25779
|
+
const cwd = positional[0] ? (0, import_node_path43.resolve)(process.cwd(), positional[0]) : process.cwd();
|
|
25403
25780
|
const plan = buildContextCleanupPlan({ projectRoot: cwd, files: await collectCleanupFiles(cwd) });
|
|
25404
25781
|
const outputPath = await writeCleanupPlan(cwd, plan);
|
|
25405
25782
|
console.log(`Wrote ${outputPath}
|
|
@@ -25409,9 +25786,9 @@ async function main() {
|
|
|
25409
25786
|
}
|
|
25410
25787
|
case "rls-test":
|
|
25411
25788
|
return runRlsTestCommand({
|
|
25412
|
-
cwd: positional[0] ? (0,
|
|
25413
|
-
matrix: typeof flags.matrix === "string" ? (0,
|
|
25414
|
-
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,
|
|
25415
25792
|
json: Boolean(flags.json)
|
|
25416
25793
|
});
|
|
25417
25794
|
default:
|
|
@@ -25420,11 +25797,11 @@ async function main() {
|
|
|
25420
25797
|
return 1;
|
|
25421
25798
|
}
|
|
25422
25799
|
}
|
|
25423
|
-
var
|
|
25800
|
+
var import_promises33, import_node_path43, STACK_AREAS;
|
|
25424
25801
|
var init_cli = __esm({
|
|
25425
25802
|
"src/cli.ts"() {
|
|
25426
|
-
|
|
25427
|
-
|
|
25803
|
+
import_promises33 = require("node:fs/promises");
|
|
25804
|
+
import_node_path43 = require("node:path");
|
|
25428
25805
|
init_config();
|
|
25429
25806
|
init_runScan();
|
|
25430
25807
|
init_artifacts2();
|
|
@@ -25466,6 +25843,7 @@ var init_cli = __esm({
|
|
|
25466
25843
|
init_buildTaskList();
|
|
25467
25844
|
init_providerMcpBridge();
|
|
25468
25845
|
init_render();
|
|
25846
|
+
init_registry2();
|
|
25469
25847
|
STACK_AREAS = /* @__PURE__ */ new Set(["database", "auth", "payments", "deployment", "monitoring", "security"]);
|
|
25470
25848
|
if (require.main === module) {
|
|
25471
25849
|
main().then((code) => {
|