Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .release-please-manifest.develop.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
".": "0.1.0-alpha.10",
"apps/web": "0.1.0-alpha.10",
".": "0.1.0-alpha.11",
"apps/web": "0.1.0-alpha.11",
"apps/worker": "0.1.0-alpha.3"
}
16 changes: 16 additions & 0 deletions CHANGELOG-DEVELOP.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [0.1.0-alpha.11](https://github.com/devakone/vibe-coding-profiler/compare/vibe-coding-profiler-v0.1.0-alpha.10...vibe-coding-profiler-v0.1.0-alpha.11) (2026-02-01)


### Features

* replace Montoya slash with vibe echo effect ([f3d869d](https://github.com/devakone/vibe-coding-profiler/commit/f3d869d7d1a5565736948ea80e507a9b476c9018))
* unify brand colors and add Montoya slash flourish ([e699083](https://github.com/devakone/vibe-coding-profiler/commit/e699083367370545957ff0d0f9cf428166c113df))


### Bug Fixes

* enable share image generation for repo analysis pages ([01a4d0c](https://github.com/devakone/vibe-coding-profiler/commit/01a4d0ce920a057e551255fdfbde96969000f2a1))
* remove old vibed.dev fallbacks and update branding references ([0954d0b](https://github.com/devakone/vibe-coding-profiler/commit/0954d0b9bb7c42cd83cfde00df015c86a094852e))
* restore rounded corners on analysis cards after overflow-hidden removal ([6416a65](https://github.com/devakone/vibe-coding-profiler/commit/6416a654b20907ed24dbac574a579c729ce8fdde))
* use maybeSingle for profile share route to avoid PGRST116 crash ([6193cea](https://github.com/devakone/vibe-coding-profiler/commit/6193cea160fd8a130b67ee8e7fa18a735e8e4f7f))

## [0.1.0-alpha.10](https://github.com/devakone/vibe-coding-profiler/compare/vibe-coding-profiler-v0.1.0-alpha.9...vibe-coding-profiler-v0.1.0-alpha.10) (2026-01-31)


Expand Down
16 changes: 16 additions & 0 deletions apps/web/CHANGELOG-DEVELOP.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [0.1.0-alpha.11](https://github.com/devakone/vibe-coding-profiler/compare/web-v0.1.0-alpha.10...web-v0.1.0-alpha.11) (2026-02-01)


### Features

* replace Montoya slash with vibe echo effect ([f3d869d](https://github.com/devakone/vibe-coding-profiler/commit/f3d869d7d1a5565736948ea80e507a9b476c9018))
* unify brand colors and add Montoya slash flourish ([e699083](https://github.com/devakone/vibe-coding-profiler/commit/e699083367370545957ff0d0f9cf428166c113df))


### Bug Fixes

* enable share image generation for repo analysis pages ([01a4d0c](https://github.com/devakone/vibe-coding-profiler/commit/01a4d0ce920a057e551255fdfbde96969000f2a1))
* remove old vibed.dev fallbacks and update branding references ([0954d0b](https://github.com/devakone/vibe-coding-profiler/commit/0954d0b9bb7c42cd83cfde00df015c86a094852e))
* restore rounded corners on analysis cards after overflow-hidden removal ([6416a65](https://github.com/devakone/vibe-coding-profiler/commit/6416a654b20907ed24dbac574a579c729ce8fdde))
* use maybeSingle for profile share route to avoid PGRST116 crash ([6193cea](https://github.com/devakone/vibe-coding-profiler/commit/6193cea160fd8a130b67ee8e7fa18a735e8e4f7f))

## [0.1.0-alpha.10](https://github.com/devakone/vibe-coding-profiler/compare/web-v0.1.0-alpha.9...web-v0.1.0-alpha.10) (2026-01-31)


Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/app/admin/jobs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ export default async function AdminJobsPage({
</td>
<td className="px-4 py-3">
{job.profile_updated ? (
<span className="inline-flex items-center gap-1 rounded-full bg-fuchsia-100 px-2 py-1 text-xs font-medium text-fuchsia-700">
<span className="text-fuchsia-500">βœ“</span>
<span className="inline-flex items-center gap-1 rounded-full bg-violet-100 px-2 py-1 text-xs font-medium text-violet-700">
<span className="text-violet-500">βœ“</span>
{job.profile_persona ? (
<span title={job.profile_persona}>Updated</span>
) : (
Expand Down Expand Up @@ -182,7 +182,7 @@ function StatusBadge({ status }: { status: string }) {
const styles: Record<string, string> = {
done: "bg-emerald-100 text-emerald-700",
queued: "bg-amber-100 text-amber-700",
running: "bg-blue-100 text-blue-700",
running: "bg-indigo-100 text-indigo-700",
failed: "bg-red-100 text-red-700",
};

Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/admin/users/[userId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ function StatusBadge({ status }: { status: string }) {
const styles: Record<string, string> = {
done: "bg-emerald-100 text-emerald-700",
queued: "bg-amber-100 text-amber-700",
running: "bg-blue-100 text-blue-700",
running: "bg-indigo-100 text-indigo-700",
failed: "bg-red-100 text-red-700",
};

Expand Down
12 changes: 6 additions & 6 deletions apps/web/src/app/analysis/AnalysisListClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface AnalysisListClientProps {

const STATUS_COLORS: Record<string, { bg: string; text: string; dot: string }> = {
pending: { bg: "bg-amber-50", text: "text-amber-700", dot: "bg-amber-400" },
running: { bg: "bg-blue-50", text: "text-blue-700", dot: "bg-blue-400 animate-pulse" },
running: { bg: "bg-indigo-50", text: "text-indigo-700", dot: "bg-indigo-400 animate-pulse" },
done: { bg: "bg-green-50", text: "text-green-700", dot: "bg-green-500" },
failed: { bg: "bg-red-50", text: "text-red-700", dot: "bg-red-500" },
};
Expand Down Expand Up @@ -128,8 +128,8 @@ export default function AnalysisListClient({ initialReports, initialJobs }: Anal
>
Jobs
{activeJobsCount > 0 && (
<span className="ml-2 inline-flex items-center gap-1 rounded-full bg-blue-100 px-2 py-0.5 text-xs text-blue-700">
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-blue-500" />
<span className="ml-2 inline-flex items-center gap-1 rounded-full bg-indigo-100 px-2 py-0.5 text-xs text-indigo-700">
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-indigo-500" />
{activeJobsCount}
</span>
)}
Expand Down Expand Up @@ -223,7 +223,7 @@ export default function AnalysisListClient({ initialReports, initialJobs }: Anal
<p className="text-sm text-zinc-600">
{isPolling ? (
<span className="inline-flex items-center gap-2">
<span className="h-2 w-2 animate-pulse rounded-full bg-blue-500" />
<span className="h-2 w-2 animate-pulse rounded-full bg-indigo-500" />
Watching for updates...
</span>
) : (
Expand Down Expand Up @@ -254,7 +254,7 @@ export default function AnalysisListClient({ initialReports, initialJobs }: Anal
key={job.id}
className={`rounded-xl border p-4 transition-colors ${
job.status === "running"
? "border-blue-200 bg-blue-50/50"
? "border-indigo-200 bg-indigo-50/50"
: job.status === "failed"
? "border-red-200 bg-red-50/50"
: "border-black/5 bg-white/70"
Expand Down Expand Up @@ -289,7 +289,7 @@ export default function AnalysisListClient({ initialReports, initialJobs }: Anal
</Link>
)}
{job.status === "running" && (
<div className="flex items-center gap-2 text-xs text-blue-600">
<div className="flex items-center gap-2 text-xs text-indigo-600">
<svg className="h-4 w-4 animate-spin" viewBox="0 0 24 24" fill="none">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
Expand Down
23 changes: 12 additions & 11 deletions apps/web/src/app/analysis/[jobId]/AnalysisClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
if (job.status === "queued" || job.status === "running") {
return (
<div className="flex flex-col items-center justify-center gap-4 py-16">
<div className="h-8 w-8 animate-spin rounded-full border-4 border-zinc-200 border-t-fuchsia-500" />
<div className="h-8 w-8 animate-spin rounded-full border-4 border-zinc-200 border-t-violet-500" />
<p className="text-sm text-zinc-600">
{job.status === "queued" ? "Waiting to analyze…" : "Analyzing your commits…"}
</p>
Expand Down Expand Up @@ -779,14 +779,14 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
? "border-red-200 bg-red-50"
: profileRebuildStatus === "success"
? "border-green-200 bg-green-50"
: "border-fuchsia-200 bg-fuchsia-50"
: "border-violet-200 bg-violet-50"
}`}
>
<div className="flex items-center gap-3">
{rebuildingProfile ? (
<>
<div className="h-4 w-4 animate-spin rounded-full border-2 border-fuchsia-200 border-t-fuchsia-500" />
<p className="text-sm font-medium text-fuchsia-800">
<div className="h-4 w-4 animate-spin rounded-full border-2 border-violet-200 border-t-violet-500" />
<p className="text-sm font-medium text-violet-800">
Rebuilding your Unified VCP with latest analysis...
</p>
</>
Expand Down Expand Up @@ -832,7 +832,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
footer={{
left: process.env.NEXT_PUBLIC_APP_URL
? new URL(process.env.NEXT_PUBLIC_APP_URL).hostname
: "vibed.dev",
: "Vibe Coding Profiler",
right: `${wrapped.totals.commits} commits${metricsJson?.active_days ? ` Β· ${metricsJson.active_days} active days` : ""}`,
}}
colors={shareTemplate.colors}
Expand All @@ -846,6 +846,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
shareHeadline={shareTemplate.headline}
shareTemplate={shareImageTemplate}
entityId={jobId}
userId={data?.userId ?? undefined}
storyEndpoint={storyEndpoint}
/>
</div>
Expand All @@ -857,7 +858,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
<div className="flex items-center gap-2">
<span className="text-xs font-medium text-zinc-500">Version:</span>
<select
className="rounded-lg border border-black/10 bg-white px-3 py-1.5 text-sm font-medium text-zinc-700 shadow-sm focus:border-fuchsia-500 focus:outline-none focus:ring-1 focus:ring-fuchsia-500"
className="rounded-lg border border-black/10 bg-white px-3 py-1.5 text-sm font-medium text-zinc-700 shadow-sm focus:border-violet-500 focus:outline-none focus:ring-1 focus:ring-violet-500"
value={jobId}
onChange={(e) => {
if (e.target.value !== jobId) {
Expand Down Expand Up @@ -908,8 +909,8 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
</div>

{/* Detailed Analysis Card */}
<div className="relative overflow-hidden rounded-[2rem] border border-black/5 bg-white shadow-sm">
<div className="absolute inset-0 bg-gradient-to-br from-violet-500/8 via-transparent to-indigo-500/8" />
<div className="vibe-echo relative rounded-[2rem] border border-black/5 bg-white shadow-sm">
<div className="absolute inset-0 rounded-[inherit] bg-gradient-to-br from-violet-500/8 via-transparent to-indigo-500/8" />
<div className="relative p-8">
<RepoIdentitySection
persona={persona}
Expand Down Expand Up @@ -942,7 +943,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
<span
className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${
wrapped.artifact_traceability.workflow_style === "orchestrator"
? "bg-cyan-100 text-cyan-800"
? "bg-indigo-100 text-indigo-800"
: wrapped.artifact_traceability.workflow_style === "conductor"
? "bg-amber-100 text-amber-800"
: "bg-violet-100 text-violet-800"
Expand Down Expand Up @@ -999,7 +1000,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
{wrapped.artifact_traceability.scores ? (
<div className="mt-4 flex items-center justify-center gap-4 text-xs text-zinc-500">
<span>
Orchestrator: <span className="font-semibold text-cyan-700">{wrapped.artifact_traceability.scores.orchestrator_score}</span>
Orchestrator: <span className="font-semibold text-indigo-700">{wrapped.artifact_traceability.scores.orchestrator_score}</span>
</span>
<span>vs</span>
<span>
Expand Down Expand Up @@ -1113,7 +1114,7 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
</div>
</div>

<details className="rounded-3xl border border-black/5 bg-white p-6 shadow-sm">
<details className="vibe-echo rounded-3xl border border-black/5 bg-white p-6 shadow-sm">
<summary className="cursor-pointer text-sm font-semibold text-zinc-900">
Timeline and details
</summary>
Expand Down
79 changes: 66 additions & 13 deletions apps/web/src/app/api/share/[format]/[userId]/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export async function GET(
) {
try {
const { format, userId } = await params;

const jobId = new URL(request.url).searchParams.get("jobId");

if (!["og", "square", "story"].includes(format)) {
return new Response("Invalid format", { status: 400 });
}
Expand Down Expand Up @@ -60,21 +61,73 @@ export async function GET(

const supabase = createClient(supabaseUrl, supabaseKey);

// Fetch Profile
const { data: profile, error } = await supabase
.from("user_profiles")
.select("persona_id, persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, narrative_json")
.eq("user_id", userId)
.single();
// Fetch data: job-specific or unified profile
let profile: {
persona_id: string;
persona_name: string | null;
persona_tagline: string | null;
persona_confidence: string | null;
total_repos: number | null;
total_commits: number | null;
axes_json: Record<string, { score: number }> | null;
narrative_json: { insight?: string; summary?: string } | null;
} | null = null;

if (jobId) {
// Job-specific share: fetch from vibe_insights + analysis_jobs
const [vibeResult, jobResult, insightsResult] = await Promise.all([
supabase
.from("vibe_insights")
.select("persona_id, persona_name, persona_tagline, persona_confidence, axes_json")
.eq("job_id", jobId)
.maybeSingle(),
supabase
.from("analysis_jobs")
.select("commit_count")
.eq("id", jobId)
.eq("user_id", userId)
.maybeSingle(),
supabase
.from("analysis_insights")
.select("persona_label, persona_confidence, persona_id, narrative_json")
.eq("job_id", jobId)
.maybeSingle(),
]);

if (error) {
console.error("Supabase error:", error);
throw new Error(`Profile fetch failed: ${error.message}`);
const vibe = vibeResult.data;
const job = jobResult.data;
const insights = insightsResult.data;

if (vibe || insights) {
profile = {
persona_id: vibe?.persona_id ?? insights?.persona_id ?? "balanced_builder",
persona_name: vibe?.persona_name ?? insights?.persona_label ?? null,
persona_tagline: vibe?.persona_tagline ?? null,
persona_confidence: vibe?.persona_confidence ?? insights?.persona_confidence ?? null,
total_repos: 1,
total_commits: job?.commit_count ?? null,
axes_json: vibe?.axes_json ?? null,
narrative_json: insights?.narrative_json ?? null,
};
}
} else {
// Unified profile share
const { data, error } = await supabase
.from("user_profiles")
.select("persona_id, persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, narrative_json")
.eq("user_id", userId)
.maybeSingle();

if (error) {
console.error("Supabase error:", error);
throw new Error(`Profile fetch failed: ${error.message}`);
}
profile = data;
}

if (!profile) {
console.error(`Profile not found for userId: ${userId}`);
return new Response("Profile not found - check if userId is correct or if RLS policies prevent access (Service Role Key required for private profiles)", { status: 404 });
console.error(`Profile not found for userId: ${userId}${jobId ? `, jobId: ${jobId}` : ""}`);
return new Response("Profile not found", { status: 404 });
}

// Prepare Data
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/share/story/[userId]/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ async function buildProfileStory(
const topAxes = axes ? formatAxesList(axes) : [];

return {
headline: "My Vibed Profile",
headline: "My Vibe Coding Profile",
subhead,
personaName: profileRow.persona_name ?? "Vibe Coder",
personaTagline: subhead,
Expand Down
Loading
Loading