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.6",
"apps/web": "0.1.0-alpha.6",
".": "0.1.0-alpha.8",
"apps/web": "0.1.0-alpha.8",
"apps/worker": "0.1.0-alpha.3"
}
135 changes: 135 additions & 0 deletions CHANGELOG-DEVELOP.md

Large diffs are not rendered by default.

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

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


### Bug Fixes

* resolve all lint errors and type issues across codebase ([78d96a6](https://github.com/devakone/vibe-coding-profiler/commit/78d96a6ee602017b3d9a5329dfbcec31a817c93e))
* resolve all npm audit vulnerabilities ([6d5d2b5](https://github.com/devakone/vibe-coding-profiler/commit/6d5d2b531a023f4644d300a3806c2627bf330191))

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


### Features

* add AI coding tool detection with per-tool metrics and VCP display ([f6fa433](https://github.com/devakone/vibe-coding-profiler/commit/f6fa4334108ec6e7d6f2411262e6097f5e6b5b8b))
* add public profile pages with username system and privacy controls ([6276317](https://github.com/devakone/vibe-coding-profiler/commit/62763172a04e982c24f1138e8291469bbefce050))
* generate share images with detailed persona metrics ([404b273](https://github.com/devakone/vibe-coding-profiler/commit/404b2739b0cb973c749382dfde87cf2388e42b87))
* reorder settings tabs and add `shareJson` to `ShareProps` for exporting data. ([2622244](https://github.com/devakone/vibe-coding-profiler/commit/262224426c00c8ec06ed7d3f86d34d76ea3bc163))


### Bug Fixes

* fix JSON export functionality for profile share data. ([02d170c](https://github.com/devakone/vibe-coding-profiler/commit/02d170c08dc1f0e580037c7a342bd1a30a8be8d2))

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


Expand Down
16 changes: 9 additions & 7 deletions apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@vibed/web",
"name": "@vibe-coding-profiler/web",
"version": "0.2.0",
"private": true,
"scripts": {
Expand All @@ -18,30 +18,32 @@
"@supabase/ssr": "^0.5.2",
"@supabase/supabase-js": "^2.47.14",
"@vercel/og": "^0.8.6",
"@vibed/core": "*",
"@vibed/db": "*",
"@vibe-coding-profiler/core": "*",
"@vibe-coding-profiler/db": "*",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"inngest": "^3.49.3",
"lucide-react": "^0.562.0",
"next": "16.1.2",
"next": "16.1.6",
"qrcode": "^1.5.4",
"react": "19.2.3",
"react-dom": "19.2.3",
"sharp": "^0.34.5",
"tailwind-merge": "^3.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"vitest": "^1",
"@types/qrcode": "^1.5.6",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.1.2",
"eslint-config-next": "16.1.6",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5"
"typescript": "^5",
"vite": "^7",
"vitest": "^3"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/aura-icons/icon-infra-weaver.png
Binary file added apps/web/public/aura-icons/icon-orchestrator.png
45 changes: 45 additions & 0 deletions apps/web/scripts/convert-assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

import fs from "fs";
import path from "path";
import sharp from "sharp";

const DIRECTORIES = [
"public/aura-backgrounds",
"public/aura-icons"
];

async function convert() {
const rootDir = path.resolve(__dirname, "../"); // apps/web

for (const dirRelative of DIRECTORIES) {
const dirPath = path.join(rootDir, dirRelative);

if (!fs.existsSync(dirPath)) {
console.warn(`Directory not found: ${dirPath}`);
continue;
}

console.log(`Processing directory: ${dirRelative}`);
const files = fs.readdirSync(dirPath).filter(f => f.toLowerCase().endsWith(".webp"));

for (const file of files) {
const inputPath = path.join(dirPath, file);
const outputPath = path.join(dirPath, file.replace(/\.webp$/i, ".png"));

if (fs.existsSync(outputPath)) {
console.log(` Skipping ${file} (PNG already exists)`);
continue;
}

console.log(` Converting ${file} -> PNG...`);
try {
await sharp(inputPath).png().toFile(outputPath);
} catch (e) {
console.error(` Failed to convert ${file}:`, e);
}
}
}
console.log("Conversion complete!");
}

convert();
2 changes: 1 addition & 1 deletion apps/web/src/app/admin/AdminClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function AdminClient({
}: {
initialReports: CoverageReport[];
}) {
const [reports, setReports] = useState<CoverageReport[]>(initialReports);
const [reports] = useState<CoverageReport[]>(initialReports);
const [isPending, startTransition] = useTransition();
const [stepSize, setStepSize] = useState(20);
const [notes, setNotes] = useState("");
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/admin/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
detectVibePersona,
type VibeAxes,
type PersonaCoverageResult,
} from "@vibed/core";
} from "@vibe-coding-profiler/core";

interface RunCoverageAnalysisResult {
success: boolean;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/admin/llm-status/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from "next/link";
import { isCurrentUserAdmin } from "@/lib/admin";
import { wrappedTheme } from "@/lib/theme";
import { getPlatformLLMConfigFull } from "@/lib/llm-config";
import { PROVIDER_INFO, LLM_PROVIDERS, type LLMProvider } from "@vibed/core";
import { PROVIDER_INFO, LLM_PROVIDERS, type LLMProvider } from "@vibe-coding-profiler/core";
import { createSupabaseServiceClient } from "@/lib/supabase/service";

interface LLMUsageStats {
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/app/admin/users/[userId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default async function AdminUserDetailPage({
}

const { userId } = await params;
const { success, user, error } = await getAdminUserDetail(userId);
const { success, user } = await getAdminUserDetail(userId);

if (!success || !user) {
notFound();
Expand All @@ -43,6 +43,7 @@ export default async function AdminUserDetailPage({
</Link>
<div className="mt-4 flex items-center gap-4">
{user.avatar_url ? (
/* eslint-disable-next-line @next/next/no-img-element -- admin page, external avatar URL */
<img
src={user.avatar_url}
alt=""
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/app/admin/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export default async function AdminUsersPage({
<td className="px-4 py-3">
<div className="flex items-center gap-3">
{user.avatar_url ? (
/* eslint-disable-next-line @next/next/no-img-element -- admin page, external avatar URL */
<img
src={user.avatar_url}
alt=""
Expand Down
40 changes: 38 additions & 2 deletions apps/web/src/app/analysis/[jobId]/AnalysisClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import { computeAnalysisInsights } from "@vibed/core";
import type { AnalysisInsights, AnalysisMetrics, CommitEvent } from "@vibed/core";
import { computeAnalysisInsights } from "@vibe-coding-profiler/core";
import type { AnalysisInsights, AnalysisMetrics, CommitEvent, AIToolMetrics } from "@vibe-coding-profiler/core";
import { formatMetricLabel, formatMetricValue } from "@/lib/format-labels";
import { computeShareCardMetrics } from "@/lib/vcp/metrics";
import { isVibeAxes } from "@/lib/vcp/validators";
Expand All @@ -15,6 +15,7 @@ import {
RepoMetricsGrid,
ProfileContributionCard,
} from "@/components/vcp/repo";
import { VCPAIToolsSection } from "@/components/vcp/blocks";

type Job = {
id: string;
Expand Down Expand Up @@ -103,6 +104,7 @@ type VibeInsightsRow = {
persona_tagline: string | null;
persona_confidence: string;
persona_score: number | null;
ai_tools_json?: unknown;
};

type InsightHistoryEntry = {
Expand Down Expand Up @@ -453,6 +455,33 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
const persona = wrapped.persona;
const shareTemplate = wrapped.share_template;

// AI tool metrics β€” prefer vibe_insights data, fall back to analysis_insights signals
const aiToolMetrics = useMemo<AIToolMetrics | null>(() => {
const vibeAiTools = parsedVibeInsights?.ai_tools_json;
if (vibeAiTools && typeof vibeAiTools === "object" && "detected" in (vibeAiTools as Record<string, unknown>)) {
return vibeAiTools as unknown as AIToolMetrics;
}
// Fall back to tool_co_authors from analysis insights
const toolCoAuthors = wrapped.multi_agent_signals?.tool_co_authors;
if (!toolCoAuthors || toolCoAuthors.length === 0) return null;
const totalAiCommits = toolCoAuthors.reduce((s, t) => s + t.commit_count, 0);
const totalCommits = wrapped.totals?.commits ?? 0;
return {
detected: true,
ai_assisted_commits: totalAiCommits,
ai_collaboration_rate: totalCommits > 0 ? totalAiCommits / totalCommits : 0,
primary_tool: { id: toolCoAuthors[0].tool_id, name: toolCoAuthors[0].tool_name },
tool_diversity: toolCoAuthors.length,
tools: toolCoAuthors.map((t) => ({
tool_id: t.tool_id,
tool_name: t.tool_name,
commit_count: t.commit_count,
percentage: totalAiCommits > 0 ? Math.round((t.commit_count / totalAiCommits) * 100) : 0,
})),
confidence: totalAiCommits >= 10 ? "high" : totalAiCommits >= 3 ? "medium" : "low",
} satisfies AIToolMetrics;
}, [parsedVibeInsights, wrapped]);

const shareText = useMemo(() => {
if (!shareTemplate) return "";
const metricsLine = shareTemplate.metrics
Expand Down Expand Up @@ -1063,6 +1092,13 @@ export default function AnalysisClient({ jobId }: { jobId: string }) {
)}
</div>

{/* AI Coding Tools Section */}
{aiToolMetrics?.detected ? (
<div className="mt-6 rounded-2xl border border-black/5 bg-white/60 p-5 backdrop-blur">
<VCPAIToolsSection aiTools={aiToolMetrics} />
</div>
) : null}

{profileContribution ? (
<ProfileContributionCard
contribution={profileContribution}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/admin/llm-config/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LLM_PROVIDERS,
PROVIDER_INFO,
getDefaultModel,
} from "@vibed/core";
} from "@vibe-coding-profiler/core";
import { encryptLLMKey, isLLMKeyEncryptionConfigured, maskApiKey } from "@/lib/llmKey";

export const runtime = "nodejs";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type AnalysisReport,
type CommitEvent,
type LLMKeySource,
} from "@vibed/core";
} from "@vibe-coding-profiler/core";
import { createSupabaseServerClient } from "@/lib/supabase/server";
import { createSupabaseServiceClient } from "@/lib/supabase/service";
import { generateNarrativeWithLLM, toNarrativeFallback } from "@/inngest/functions/analyze-repo";
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/app/api/analysis/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
type RepoInsightSummary,
type VibeAxes,
type VibeCommitEvent,
} from "@vibed/core";
} from "@vibe-coding-profiler/core";

export const runtime = "nodejs";

Expand Down Expand Up @@ -324,7 +324,7 @@ export async function GET(
const { data: v } = await (supabase as unknown as SupabaseQueryLike)
.from("vibe_insights")
.select(
"job_id, axes_json, persona_id, persona_name, persona_tagline, persona_confidence, persona_score, cards_json"
"job_id, axes_json, persona_id, persona_name, persona_tagline, persona_confidence, persona_score, cards_json, ai_tools_json"
)
.eq("job_id", id)
.single();
Expand Down Expand Up @@ -402,6 +402,7 @@ export async function GET(
persona_confidence: computed.persona.confidence,
persona_score: computed.persona.score,
cards_json: computed.cards,
ai_tools_json: computed.ai_tools,
};
}
return null;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/auth/[provider]/callback/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { encryptString } from "@vibed/core";
import { encryptString } from "@vibe-coding-profiler/core";
import { NextResponse } from "next/server";
import { createSupabaseServiceClient } from "@/lib/supabase/service";
import { createSupabaseServerClient } from "@/lib/supabase/server";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/debug/profile/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { createSupabaseServerClient } from "@/lib/supabase/server";
import { detectVibePersona, type VibeAxes } from "@vibed/core";
import { detectVibePersona, type VibeAxes } from "@vibe-coding-profiler/core";

export const runtime = "nodejs";

Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/og/analysis/[jobId]/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { computeShareCardMetrics } from "@/lib/vcp/metrics";
import { isVibeAxes } from "@/lib/vcp/validators";
import { getPersonaAura } from "@/lib/persona-auras";
import type { ShareCardColors, ShareCardMetric } from "@/components/share/types";
import type { VibeAxes } from "@vibed/core";
import type { VibeAxes } from "@vibe-coding-profiler/core";
import { NextRequest } from "next/server";

export const runtime = "edge";
Expand Down
Loading
Loading