mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
feat: add internal team-only roadmap page (#2590)
## Summary - Adds `/roadmap` page with visual flowchart showing codeflash-python and codeflash-agent planned work - Gated behind `isTeamMemberCheck` (same auth pattern as `/observability`) - Sidebar link visible only to team members - Status tracking with distinct visual treatments: compact left-accent for shipped, hero cards with glow for in-progress, dashed wireframe for planned ## Test plan - [ ] Visit `/roadmap` as a team member — page renders with status cards - [ ] Visit `/roadmap` as a non-team member — redirects to `/` - [ ] Sidebar shows roadmap link only for team members - [ ] Build passes (`npm run build`) - [ ] All tests pass (`npm test` — 39/39)
This commit is contained in:
parent
b43e9ba648
commit
e8561b9485
5 changed files with 736 additions and 25 deletions
43
.claude/handoffs/2026-04-01-handoff.md
Normal file
43
.claude/handoffs/2026-04-01-handoff.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
date: 2026-04-01
|
||||
branch: main
|
||||
---
|
||||
|
||||
## Accomplished
|
||||
- Created an internal employee-only `/roadmap` page in cf-webapp (Next.js)
|
||||
- Gated behind existing `isTeamMemberCheck` in middleware + server-side `isTeamMember()` check
|
||||
- Added `/roadmap` to `ConditionalLayout` exclusion list so it renders as a standalone page (no sidebar)
|
||||
- Added "Roadmap" link with Map icon to the sidebar, visible only to team members (same block as Observability)
|
||||
- Built a visual flowchart UI with amber-themed nodes, dot-grid background, numbered badges linking to detail cards below
|
||||
- Merged codeflash-python and codeflash-agent planned items into a single unified flow (3 branching nodes feed into 1 node below)
|
||||
- Wrote a rationale section explaining: original CLI's single-language design + fragile multi-lang bolt-on, the codeflash-python + codeflash-core rewrite, the OptimizationSession API gap (building blocks done, experiment loop stubbed), and the goal of making codeflash-python the autonomous orchestrator
|
||||
- Added a two-track strategy section: Consumer (codeflash --file / --all unchanged) vs B2B/Enterprise (agentic capabilities)
|
||||
- Applied avoid-ai-writing skill to clean up language: killed em dash overuse, hollow intensifiers, compulsive triads, indirect phrasing, vague B2B copy
|
||||
|
||||
## Current State
|
||||
- Branch: `main` (behind origin/main by 7 commits)
|
||||
- Uncommitted changes:
|
||||
- `js/cf-webapp/src/app/roadmap/page.tsx` (new file - the roadmap page)
|
||||
- `js/cf-webapp/src/middleware.ts` (added /roadmap to team gate + matcher)
|
||||
- `js/cf-webapp/src/components/conditional-layout.tsx` (added /roadmap to standalone page list)
|
||||
- `js/cf-webapp/src/components/dashboard/sidebar.tsx` (added Roadmap link + Map icon import)
|
||||
- `.tessl/RULES.md` (modified by tessl, not related to our work)
|
||||
- Tests: not run (TypeScript type-check passes clean via `npx tsc --noEmit`)
|
||||
|
||||
## Key Decisions
|
||||
- Used the same auth pattern as `/observability` (middleware redirect + server-side check) rather than inventing a new gate
|
||||
- Page renders standalone (no sidebar) via `ConditionalLayout` exclusion, same as observability
|
||||
- Roadmap data is hardcoded in the component as a TypeScript array, easy to edit manually
|
||||
- Used amber/gold accent color (not blue) to differentiate planned items and give a forward-looking feel
|
||||
- Unified all planned items (codeflash-python + codeflash-agent) into one flow rather than separate sections, per user preference
|
||||
- Rationale text explains the rewrite motivation: original CLI was Python-only, multi-language was bolted on, architecture doesn't support autonomous operation
|
||||
|
||||
## Blockers
|
||||
- None
|
||||
|
||||
## Next Steps
|
||||
1. Create a feature branch and commit all changes (currently on main, user hasn't asked to commit yet)
|
||||
2. Pull latest from origin/main (7 commits behind) and resolve any conflicts
|
||||
3. Run the dev server (`npm run dev` in js/cf-webapp) and visually verify the page
|
||||
4. Consider adding more planned items to the roadmap as they're defined
|
||||
5. The roadmap data structure supports `FlowRow` with "single" and "branch" types, so new items can be added as rows that connect vertically
|
||||
2
.tessl/.gitignore
vendored
Normal file
2
.tessl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
tiles/
|
||||
RULES.md
|
||||
|
|
@ -1,27 +1,3 @@
|
|||
# Agent Rules
|
||||
|
||||
This file is updated when running `tessl install`. If a linked file is missing, make sure to run the command to download any missing tiles from the registry.
|
||||
|
||||
## codeflash/codeflash-internal-rules — code-style
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/code-style.md [code-style](tiles/codeflash/codeflash-internal-rules/rules/code-style.md)
|
||||
|
||||
## codeflash/codeflash-internal-rules — architecture
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/architecture.md [architecture](tiles/codeflash/codeflash-internal-rules/rules/architecture.md)
|
||||
|
||||
## codeflash/codeflash-internal-rules — optimization-patterns
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/optimization-patterns.md [optimization-patterns](tiles/codeflash/codeflash-internal-rules/rules/optimization-patterns.md)
|
||||
|
||||
## codeflash/codeflash-internal-rules — git-conventions
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/git-conventions.md [git-conventions](tiles/codeflash/codeflash-internal-rules/rules/git-conventions.md)
|
||||
|
||||
## codeflash/codeflash-internal-rules — testing-rules
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/testing-rules.md [testing-rules](tiles/codeflash/codeflash-internal-rules/rules/testing-rules.md)
|
||||
|
||||
## codeflash/codeflash-internal-rules — multi-language-handlers
|
||||
|
||||
@tiles/codeflash/codeflash-internal-rules/rules/multi-language-handlers.md [multi-language-handlers](tiles/codeflash/codeflash-internal-rules/rules/multi-language-handlers.md)
|
||||
680
js/cf-webapp/src/app/roadmap/page.tsx
Normal file
680
js/cf-webapp/src/app/roadmap/page.tsx
Normal file
|
|
@ -0,0 +1,680 @@
|
|||
import { isTeamMember } from "@/app/utils/auth"
|
||||
import { redirect } from "next/navigation"
|
||||
import {
|
||||
Repeat,
|
||||
Wrench,
|
||||
Zap,
|
||||
Shield,
|
||||
Code,
|
||||
GitPullRequest,
|
||||
Network,
|
||||
LayoutDashboard,
|
||||
Package,
|
||||
FlaskConical,
|
||||
RefreshCw,
|
||||
BookOpen,
|
||||
Check,
|
||||
CircleDashed,
|
||||
type LucideIcon,
|
||||
} from "lucide-react"
|
||||
|
||||
type Status = "shipped" | "in-progress" | "planned"
|
||||
|
||||
interface Stage {
|
||||
name: string
|
||||
status: Status
|
||||
icon: LucideIcon
|
||||
description: string
|
||||
details?: string[]
|
||||
children?: Stage[]
|
||||
downstream?: Stage[]
|
||||
}
|
||||
|
||||
type FlowRow = { type: "single"; stage: Stage } | { type: "branch"; stages: Stage[] }
|
||||
|
||||
function countStages(rows: FlowRow[]): Record<Status, number> {
|
||||
const counts: Record<Status, number> = { shipped: 0, "in-progress": 0, planned: 0 }
|
||||
function walk(stage: Stage) {
|
||||
counts[stage.status]++
|
||||
stage.children?.forEach(walk)
|
||||
stage.downstream?.forEach(walk)
|
||||
}
|
||||
for (const row of rows) {
|
||||
if (row.type === "single") walk(row.stage)
|
||||
else row.stages.forEach(walk)
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
const roadmap: FlowRow[] = [
|
||||
{
|
||||
type: "branch",
|
||||
stages: [
|
||||
{
|
||||
name: "codeflash-python",
|
||||
status: "shipped",
|
||||
icon: Package,
|
||||
description:
|
||||
"The rebuilt Python optimization pipeline. All core stages complete \u2014 discovery, context extraction, test generation, benchmarking, verification, and orchestration.",
|
||||
details: [
|
||||
"OptimizationSession exposes each pipeline step as a callable method",
|
||||
"stdlib ast for discovery, Jedi-based context resolution, SQLite-backed reference graph with file-hash invalidation",
|
||||
"attrs models with to_dict() / from_dict() serialization throughout",
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "JS / Java Pipeline",
|
||||
status: "planned",
|
||||
icon: Code,
|
||||
description:
|
||||
"Add JavaScript and Java optimization stages using the LanguagePlugin interface in codeflash-core.",
|
||||
details: [
|
||||
"LanguagePlugin interface already defines the contract \u2014 each language implements discovery, context extraction, and verification",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cross-Function Optimization",
|
||||
status: "planned",
|
||||
icon: Network,
|
||||
description: "Optimize call chains together instead of one function at a time.",
|
||||
details: [
|
||||
"Reference graph in analysis/ already maps function dependencies",
|
||||
"Generate candidates that touch multiple related functions in the same call path",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Automated Code Refactoring",
|
||||
status: "planned",
|
||||
icon: RefreshCw,
|
||||
description:
|
||||
"Rewrite how a codebase uses its dependencies \u2014 tailored to what it actually needs.",
|
||||
details: [
|
||||
"Proven on ourselves: replaced libcst with stdlib ast, cached visitor dispatch tables \u2014 7.04s \u2192 1.60s (4.4x faster)",
|
||||
"Same approach generalizes: profile dependency usage, identify overkill, generate targeted replacements",
|
||||
],
|
||||
},
|
||||
],
|
||||
downstream: [
|
||||
{
|
||||
name: "RL Environment",
|
||||
status: "planned",
|
||||
icon: FlaskConical,
|
||||
description:
|
||||
"Code optimization evaluation environment in Harbor format for training and evaluating software engineering agents.",
|
||||
details: [
|
||||
"Each task: one function to optimize inside a real-world OSS codebase",
|
||||
"Evaluates correctness (behavioral equivalence), performance (runtime speedup), and quality",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "codeflash-agent",
|
||||
status: "in-progress",
|
||||
icon: Zap,
|
||||
description:
|
||||
"Fully autonomous optimization agent. Given a repository, it profiles, identifies bottlenecks, implements verified fixes, and ships results \u2014 no human in the loop.",
|
||||
details: [
|
||||
"Profiling spans CPU, memory, async, and structure dimensions to catch cross-cutting performance issues",
|
||||
"Each optimization: profile \u2192 reason \u2192 implement \u2192 test \u2192 benchmark \u2192 keep or discard \u2192 commit",
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "CI Mode",
|
||||
status: "in-progress",
|
||||
icon: GitPullRequest,
|
||||
description:
|
||||
"Acts like a team member that reviews every PR for performance. Open PRs are automatically profiled and optimized \u2014 like having a performance engineer on the team who never misses a review.",
|
||||
details: [],
|
||||
},
|
||||
{
|
||||
name: "Adversarial Review",
|
||||
status: "in-progress",
|
||||
icon: Shield,
|
||||
description:
|
||||
"6-pass independent code review that maps attack surfaces before shipping optimizations.",
|
||||
details: [
|
||||
"Correctness, performance, security, maintainability, edge cases, and integration passes",
|
||||
"Review gate runs automatically before session ends",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Research-Informed Optimization",
|
||||
status: "planned",
|
||||
icon: BookOpen,
|
||||
description:
|
||||
"Agents with access to research papers apply novel algorithmic improvements \u2014 not just mechanical refactoring.",
|
||||
details: [
|
||||
"arxiv access as a tool call \u2014 agents read papers and implement ideas directly",
|
||||
"Enables optimizations that haven\u2019t been tried publicly before",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "single",
|
||||
stage: {
|
||||
name: "Programmatic API",
|
||||
status: "in-progress",
|
||||
icon: Wrench,
|
||||
description:
|
||||
"Wire codeflash-python\u2019s OptimizationSession directly into the agent \u2014 replacing CLI shell-outs with programmatic method calls. Expose session methods as MCP tools.",
|
||||
details: [
|
||||
"Experiment loop: profile(), build_targets(), measure(), evaluate() \u2014 no LLM needed in the loop",
|
||||
"MCP tool layer: every method already accepts and returns JSON-serializable types",
|
||||
"Agent migration: actions become testable and composable \u2014 no more CLI parsing",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "single",
|
||||
stage: {
|
||||
name: "Continuous Optimization",
|
||||
status: "planned",
|
||||
icon: Repeat,
|
||||
description:
|
||||
"The pipeline runs itself. codeflash-python provides the experiment loop, the agent drives it autonomously \u2014 profile, optimize, verify, ship, repeat across an entire codebase without human intervention.",
|
||||
details: [
|
||||
"Combines the programmatic API with autonomous orchestration",
|
||||
"Iterative: each optimization pass feeds back into the next \u2014 targets are re-ranked by measured impact",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "single",
|
||||
stage: {
|
||||
name: "Enterprise Dashboard",
|
||||
status: "planned",
|
||||
icon: LayoutDashboard,
|
||||
description: "Org-level visibility into optimization results across repos and teams.",
|
||||
details: [],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
/* ─── Shipped: compact, left-accent, details hidden ─── */
|
||||
function ShippedCard({ stage }: { stage: Stage }) {
|
||||
const Icon = stage.icon
|
||||
return (
|
||||
<div className="group relative flex flex-col gap-1.5 rounded-lg border-l-4 border-emerald-400 dark:border-emerald-500 bg-zinc-50 dark:bg-zinc-800/40 pl-4 pr-5 py-3 w-full transition-all duration-200 hover:bg-zinc-100 dark:hover:bg-zinc-800/60">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="flex h-6 w-6 shrink-0 items-center justify-center rounded text-emerald-500 dark:text-emerald-400">
|
||||
<Check size={14} strokeWidth={3} />
|
||||
</div>
|
||||
<span className="text-sm font-semibold text-zinc-600 dark:text-zinc-300 leading-tight">
|
||||
{stage.name}
|
||||
</span>
|
||||
<Icon size={13} className="text-zinc-300 dark:text-zinc-600 ml-auto shrink-0" />
|
||||
</div>
|
||||
<p className="text-[11px] leading-relaxed text-zinc-400 dark:text-zinc-500 pl-[34px]">
|
||||
{stage.description}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* ─── In-progress: hero card, elevated, glowing ─── */
|
||||
function InProgressCard({ stage }: { stage: Stage }) {
|
||||
const Icon = stage.icon
|
||||
return (
|
||||
<div className="group relative w-full">
|
||||
{/* Outer glow */}
|
||||
<div className="absolute -inset-1 rounded-2xl bg-gradient-to-b from-amber-400/30 via-amber-300/15 to-transparent dark:from-amber-500/25 dark:via-amber-400/10 blur-sm" />
|
||||
<div className="relative flex flex-col gap-4 rounded-2xl border-2 border-amber-400 dark:border-amber-500/70 bg-gradient-to-b from-white via-white to-amber-50/30 dark:from-zinc-800 dark:via-zinc-800/95 dark:to-amber-950/30 px-7 py-6 shadow-xl shadow-amber-200/40 dark:shadow-amber-900/30 transition-all duration-300 hover:shadow-2xl hover:shadow-amber-300/40 dark:hover:shadow-amber-800/35">
|
||||
{/* Status indicator */}
|
||||
<div className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-widest text-amber-500 dark:text-amber-300">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-amber-400 opacity-75" />
|
||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-amber-500" />
|
||||
</span>
|
||||
Building now
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl bg-amber-100 dark:bg-amber-800/50 text-amber-600 dark:text-amber-300 ring-2 ring-amber-200/60 dark:ring-amber-600/40">
|
||||
<Icon size={22} />
|
||||
</div>
|
||||
<span className="text-lg font-bold text-zinc-900 dark:text-zinc-50 leading-tight tracking-tight">
|
||||
{stage.name}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed text-zinc-700 dark:text-zinc-300">
|
||||
{stage.description}
|
||||
</p>
|
||||
{stage.details && stage.details.length > 0 && (
|
||||
<ul className="space-y-2 border-t border-amber-200/40 dark:border-amber-700/30 pt-4">
|
||||
{stage.details.map((detail, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="flex items-start gap-2.5 text-xs text-zinc-700 dark:text-zinc-300"
|
||||
>
|
||||
<span className="mt-[5px] h-1.5 w-1.5 rounded-full bg-amber-400 dark:bg-amber-500 shrink-0" />
|
||||
{detail}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* ─── Planned: wireframe, dashed, ghosted ─── */
|
||||
function PlannedCard({ stage }: { stage: Stage }) {
|
||||
const Icon = stage.icon
|
||||
return (
|
||||
<div className="group relative flex flex-col gap-2.5 rounded-xl border border-dashed border-zinc-300 dark:border-zinc-700 bg-transparent px-5 py-4 w-full transition-all duration-200 hover:bg-zinc-50/50 dark:hover:bg-zinc-800/20 hover:border-zinc-400 dark:hover:border-zinc-600">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-dashed border-zinc-300 dark:border-zinc-700 text-zinc-400 dark:text-zinc-600">
|
||||
<Icon size={15} />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-zinc-400 dark:text-zinc-500 leading-tight">
|
||||
{stage.name}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs leading-relaxed text-zinc-400 dark:text-zinc-600 pl-11">
|
||||
{stage.description}
|
||||
</p>
|
||||
{stage.details && stage.details.length > 0 && (
|
||||
<ul className="space-y-1 pl-11">
|
||||
{stage.details.map((detail, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="flex items-start gap-2 text-[11px] text-zinc-300 dark:text-zinc-600"
|
||||
>
|
||||
<CircleDashed size={8} className="mt-[3px] shrink-0" />
|
||||
{detail}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function StageCard({ stage }: { stage: Stage }) {
|
||||
if (stage.status === "shipped") return <ShippedCard stage={stage} />
|
||||
if (stage.status === "in-progress") return <InProgressCard stage={stage} />
|
||||
return <PlannedCard stage={stage} />
|
||||
}
|
||||
|
||||
function Connector({ to }: { to?: Status }) {
|
||||
if (to === "planned") {
|
||||
return (
|
||||
<div className="flex justify-center py-1">
|
||||
<div className="w-px h-6 border-l border-dashed border-zinc-300 dark:border-zinc-700" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="flex justify-center py-1">
|
||||
<div className="w-px h-6 bg-zinc-200 dark:bg-zinc-700" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function StageNode({ stage }: { stage: Stage }) {
|
||||
return (
|
||||
<div className="flex flex-col items-center w-full">
|
||||
<StageCard stage={stage} />
|
||||
{stage.children && stage.children.length > 0 && (
|
||||
<>
|
||||
<Connector to={stage.children[0]?.status} />
|
||||
{stage.children.length === 1 ? (
|
||||
<StageCard stage={stage.children[0]} />
|
||||
) : (
|
||||
<div className="relative w-full">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{stage.children.map((child, j) => {
|
||||
const isLastOdd =
|
||||
j === stage.children!.length - 1 && stage.children!.length % 2 !== 0
|
||||
return (
|
||||
<div
|
||||
key={j}
|
||||
className={`flex flex-col items-center ${isLastOdd ? "col-span-2" : ""}`}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col items-center w-full ${isLastOdd ? "max-w-[calc(50%-6px)] mx-auto" : ""}`}
|
||||
>
|
||||
<Connector to={child.status} />
|
||||
<StageCard stage={child} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{stage.downstream && stage.downstream.length > 0 && (
|
||||
<>
|
||||
<Connector to={stage.downstream[0]?.status} />
|
||||
<div className="w-full max-w-md">
|
||||
{stage.downstream.map((ds, j) => (
|
||||
<StageCard key={j} stage={ds} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FlowChart({ rows }: { rows: FlowRow[] }) {
|
||||
return (
|
||||
<div className="relative rounded-2xl border border-zinc-200/60 dark:border-zinc-700/40 bg-white/80 dark:bg-zinc-900/50 p-10 lg:p-12 overflow-hidden">
|
||||
{/* Subtle grid background */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.03] dark:opacity-[0.05]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(to right, currentColor 1px, transparent 1px), linear-gradient(to bottom, currentColor 1px, transparent 1px)",
|
||||
backgroundSize: "48px 48px",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="relative flex flex-col items-center">
|
||||
{rows.map((row, rowIdx) => (
|
||||
<div key={rowIdx} className="flex flex-col items-center w-full">
|
||||
{rowIdx > 0 && (
|
||||
<div className="flex justify-center py-1">
|
||||
<div className="w-px h-8 bg-zinc-200 dark:bg-zinc-700" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{row.type === "single" && (
|
||||
<div className="w-full max-w-2xl">
|
||||
<StageNode stage={row.stage} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{row.type === "branch" && (
|
||||
<div className="relative w-full max-w-full">
|
||||
<div
|
||||
className="absolute top-0 h-px bg-zinc-200 dark:bg-zinc-700"
|
||||
style={{
|
||||
left: `${100 / (2 * row.stages.length)}%`,
|
||||
right: `${100 / (2 * row.stages.length)}%`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="grid"
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${row.stages.length}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
{row.stages.map((stage, j) => (
|
||||
<div key={j} className="flex flex-col items-center px-3">
|
||||
<Connector />
|
||||
<StageNode stage={stage} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Metrics() {
|
||||
const counts = countStages(roadmap)
|
||||
const total = counts.shipped + counts["in-progress"] + counts.planned
|
||||
const shippedPct = (counts.shipped / total) * 100
|
||||
const inProgressPct = (counts["in-progress"] / total) * 100
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Counters */}
|
||||
<div className="flex items-baseline gap-8">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-mono font-bold text-emerald-500 dark:text-emerald-400 tabular-nums">
|
||||
{counts.shipped}
|
||||
</span>
|
||||
<span className="text-xs font-medium text-zinc-400 dark:text-zinc-500 uppercase tracking-wider">
|
||||
shipped
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-mono font-bold text-amber-500 dark:text-amber-400 tabular-nums">
|
||||
{counts["in-progress"]}
|
||||
</span>
|
||||
<span className="text-xs font-medium text-zinc-400 dark:text-zinc-500 uppercase tracking-wider">
|
||||
active
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-mono font-bold text-zinc-300 dark:text-zinc-600 tabular-nums">
|
||||
{counts.planned}
|
||||
</span>
|
||||
<span className="text-xs font-medium text-zinc-300 dark:text-zinc-600 uppercase tracking-wider">
|
||||
planned
|
||||
</span>
|
||||
</div>
|
||||
<span className="ml-auto text-sm font-mono text-zinc-400 dark:text-zinc-500 tabular-nums">
|
||||
{Math.round(shippedPct)}%
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Segmented bar */}
|
||||
<div className="h-1.5 w-full rounded-full bg-zinc-100 dark:bg-zinc-800 overflow-hidden flex">
|
||||
<div
|
||||
className="h-full bg-emerald-400 dark:bg-emerald-500 rounded-l-full"
|
||||
style={{ width: `${shippedPct}%` }}
|
||||
/>
|
||||
<div
|
||||
className="h-full bg-amber-400 dark:bg-amber-500"
|
||||
style={{ width: `${inProgressPct}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default async function RoadmapPage() {
|
||||
const teamMember = await isTeamMember()
|
||||
if (!teamMember) {
|
||||
redirect("/")
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-zinc-50 dark:bg-zinc-900">
|
||||
<div className="border-b border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800">
|
||||
<div className="max-w-[1600px] mx-auto px-8 py-8 space-y-6">
|
||||
<h1 className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-zinc-50">
|
||||
Roadmap
|
||||
</h1>
|
||||
<Metrics />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-[1600px] mx-auto px-8 py-10">
|
||||
{/* Rationale */}
|
||||
<div className="mb-12 space-y-6">
|
||||
<h2 className="text-base font-mono font-semibold text-zinc-800 dark:text-zinc-200 tracking-tight">
|
||||
Why
|
||||
</h2>
|
||||
<div className="space-y-4 text-sm leading-relaxed text-zinc-600 dark:text-zinc-400">
|
||||
<p>
|
||||
The original codeflash CLI was designed for Python only. When multi-language support
|
||||
was added, it was bolted on in a way that doesn't extend well. Discovery, context
|
||||
extraction, AI calls, verification, and PR creation are all coupled together across
|
||||
181 files. It works. But you can't run pieces on their own, call them from code,
|
||||
or have the pipeline run itself.
|
||||
</p>
|
||||
<p>
|
||||
We rebuilt the pipeline as two packages in a{" "}
|
||||
<span className="font-mono text-zinc-800 dark:text-zinc-200">uv</span> workspace. The
|
||||
original CLI packed everything into one class (
|
||||
<span className="font-mono text-zinc-800 dark:text-zinc-200">FunctionOptimizer</span>
|
||||
). The rewrite decomposes it into focused modules. Code was ported from the original
|
||||
where possible, not rewritten from scratch, and we optimized the hot paths: stdlib{" "}
|
||||
<span className="font-mono text-xs">ast</span> for discovery instead of libcst,
|
||||
class-level visitor dispatch caching, type-identity fast-paths in the comparator, Jedi
|
||||
refs caching with RO/TESTGEN deduplication in context extraction, SQLite-backed
|
||||
reference graph with file-hash invalidation, and single CST parse reused across all
|
||||
four context types. All models use{" "}
|
||||
<span className="font-mono text-zinc-800 dark:text-zinc-200">attrs</span> with{" "}
|
||||
<span className="font-mono text-xs">to_dict()</span> /{" "}
|
||||
<span className="font-mono text-xs">from_dict()</span> for serialization.
|
||||
</p>
|
||||
<div className="mt-4 space-y-3">
|
||||
<div className="rounded-lg border border-zinc-200/60 dark:border-zinc-700/40 bg-white/60 dark:bg-zinc-800/40 px-5 py-4">
|
||||
<div className="flex items-center gap-2 mb-2.5">
|
||||
<span className="font-mono text-sm font-semibold text-zinc-800 dark:text-zinc-200">
|
||||
codeflash-core
|
||||
</span>
|
||||
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded bg-zinc-100 dark:bg-zinc-700 text-zinc-500 dark:text-zinc-400">
|
||||
language-agnostic
|
||||
</span>
|
||||
</div>
|
||||
<ul className="grid grid-cols-2 gap-x-6 gap-y-1.5">
|
||||
{(
|
||||
[
|
||||
["AIClient", "AI service communication"],
|
||||
["Models", "shared types (Candidate, OptimizationRequest, etc.)"],
|
||||
["Git", "repository operations"],
|
||||
["Telemetry", "PostHog instrumentation"],
|
||||
["Platform", "CodeFlash API client"],
|
||||
["Pipeline", "candidate tree and ranking"],
|
||||
["Plugin", "LanguagePlugin interface"],
|
||||
] as const
|
||||
).map(([name, desc], i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="flex items-start gap-2 text-xs text-zinc-500 dark:text-zinc-400"
|
||||
>
|
||||
<span className="mt-[5px] h-1 w-1 rounded-full bg-zinc-400/50 shrink-0" />
|
||||
<span>
|
||||
<span className="font-mono text-zinc-700 dark:text-zinc-300">{name}</span>
|
||||
{" \u2014 "}
|
||||
{desc}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="rounded-lg border border-zinc-200/60 dark:border-zinc-700/40 bg-white/60 dark:bg-zinc-800/40 px-5 py-4">
|
||||
<div className="flex items-center gap-2 mb-2.5">
|
||||
<span className="font-mono text-sm font-semibold text-zinc-800 dark:text-zinc-200">
|
||||
codeflash-python
|
||||
</span>
|
||||
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded-full bg-emerald-500 text-white flex items-center gap-0.5">
|
||||
<Check size={8} strokeWidth={3} />
|
||||
shipped
|
||||
</span>
|
||||
</div>
|
||||
<ul className="grid grid-cols-2 gap-x-6 gap-y-1.5">
|
||||
{(
|
||||
[
|
||||
[
|
||||
"analysis/",
|
||||
"discovery, extraction, ranking, coverage, reference graph, call graph",
|
||||
],
|
||||
["context/", "dependency resolution, import mapping, enrichment, pruning"],
|
||||
["test_discovery/", "pytest/unittest discovery, filtering, linking"],
|
||||
[
|
||||
"testing/",
|
||||
"instrumentation, generation, pytest plugin, concolic validation",
|
||||
],
|
||||
["benchmarking/", "profiling, tracing, result parsing, comparison"],
|
||||
[
|
||||
"verification/",
|
||||
"baseline, comparator, critic, ranking, candidate evaluation",
|
||||
],
|
||||
["codegen/", "code replacement, PR generation"],
|
||||
["ai/", "refinement, repair, adaptive optimization"],
|
||||
[
|
||||
"pipeline/",
|
||||
"orchestration (module prep \u2192 function optimizer \u2192 end-to-end)",
|
||||
],
|
||||
["api/", "OptimizationSession programmatic interface"],
|
||||
] as const
|
||||
).map(([dir, desc], i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="flex items-start gap-2 text-xs text-zinc-500 dark:text-zinc-400"
|
||||
>
|
||||
<span className="mt-[5px] h-1 w-1 rounded-full bg-zinc-400/50 shrink-0" />
|
||||
<span>
|
||||
<span className="font-mono text-zinc-700 dark:text-zinc-300">{dir}</span>{" "}
|
||||
{desc}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="rounded-lg border border-zinc-200/60 dark:border-zinc-700/40 bg-white/60 dark:bg-zinc-800/40 px-5 py-4">
|
||||
<div className="flex items-center gap-2 mb-2.5">
|
||||
<span className="font-mono text-sm font-semibold text-zinc-800 dark:text-zinc-200">
|
||||
codeflash-agent
|
||||
</span>
|
||||
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded-full bg-amber-500 text-white flex items-center gap-0.5">
|
||||
in progress
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs leading-relaxed text-zinc-500 dark:text-zinc-400 mb-3">
|
||||
A Claude Code plugin that autonomously optimizes an entire codebase. Given a
|
||||
repository, it profiles across CPU, memory, async, and structure dimensions,
|
||||
identifies performance bottlenecks, implements and verifies fixes, and ships
|
||||
results — no human in the loop. Includes CI mode for automatic optimization
|
||||
on PRs and adversarial review before shipping. Currently invokes the CLI for
|
||||
pipeline steps — the Programmatic API replaces this with direct
|
||||
OptimizationSession calls.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FlowChart rows={roadmap} />
|
||||
|
||||
{/* Two-track strategy */}
|
||||
<div className="mt-12 space-y-6">
|
||||
<h2 className="text-base font-mono font-semibold text-zinc-800 dark:text-zinc-200 tracking-tight">
|
||||
Two tracks
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="rounded-xl border border-zinc-200/80 dark:border-zinc-700/50 bg-white dark:bg-zinc-800/60 p-5">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-xs font-mono font-semibold uppercase tracking-wider text-zinc-500 dark:text-zinc-400">
|
||||
Consumer
|
||||
</span>
|
||||
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded bg-zinc-100 dark:bg-zinc-700 text-zinc-600 dark:text-zinc-300">
|
||||
unchanged
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||
The existing{" "}
|
||||
<span className="font-mono text-zinc-800 dark:text-zinc-200">codeflash --file</span>{" "}
|
||||
/{" "}
|
||||
<span className="font-mono text-zinc-800 dark:text-zinc-200">codeflash --all</span>{" "}
|
||||
workflow stays as-is. Single-function and whole-project optimization continues to
|
||||
run the same pipeline it does today.
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-xl border border-amber-300/40 dark:border-amber-500/20 bg-gradient-to-b from-amber-50/50 to-white dark:from-amber-950/20 dark:to-zinc-800/60 p-5">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-xs font-mono font-semibold uppercase tracking-wider text-amber-600 dark:text-amber-400">
|
||||
B2B / Enterprise
|
||||
</span>
|
||||
<span className="text-[10px] font-medium px-1.5 py-0.5 rounded bg-amber-100 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300">
|
||||
new
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||
The autonomous experiment loop and agentic capabilities target B2B and enterprise
|
||||
contracts. Multi-domain profiling, cross-cutting optimization, and iterative
|
||||
measurement across an entire codebase, without a human driving each step.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import {
|
|||
Loader2,
|
||||
Zap,
|
||||
BarChart3,
|
||||
Map,
|
||||
} from "lucide-react"
|
||||
import type { User as UserProfile } from "@auth0/nextjs-auth0/types"
|
||||
import { SignOut } from "../ui/SignOut"
|
||||
|
|
@ -320,6 +321,15 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
Observability
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/roadmap" className="block mb-1">
|
||||
<Button
|
||||
variant={currentRoute?.startsWith("/roadmap") ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
>
|
||||
<Map size={16} className="mr-2 h-4 w-4 shrink-0" />
|
||||
Roadmap
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue