feat: add company builder wizard with AI-powered org generation (#73)

* feat: add company builder wizard with AI-powered org generation

Adds a new "Build Your Company" step to the onboarding wizard that lets
users describe their business and generates a full agent org structure
using OpenClaw's AI. Includes company plan generation, role deduplication,
agent bootstrap with main-agent reuse, org chart preview, confetti on
success, CSS voxel running-avatar loader, amber theme unification, and
best-effort SSH workspace cleanup.

Made-with: Cursor

* fix: resolve lint errors in CompanyBuilderModal

Replace setState-in-effect pattern with a direct callback, escape
apostrophes in JSX text, and derive org chart hover state without
side effects.

Made-with: Cursor

---------

Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
This commit is contained in:
Luke The Dev
2026-03-27 12:59:44 -05:00
committed by GitHub
parent 3da1694085
commit a953c5fda6
31 changed files with 3308 additions and 124 deletions
@@ -1,38 +1,91 @@
"use client";
/**
* CompleteStep — Final wizard screen before entering the office.
*/
import { useEffect, useRef } from "react";
import confetti from "canvas-confetti";
import { Building2, Rocket } from "lucide-react";
export const CompleteStep = () => (
<div className="flex flex-col items-center justify-center gap-5 py-4">
<div className="flex h-14 w-14 items-center justify-center rounded-full bg-emerald-500/15">
<Rocket className="h-7 w-7 text-emerald-400" />
</div>
export const CompleteStep = ({
companyCreated = false,
companyName = null,
}: {
companyCreated?: boolean;
companyName?: string | null;
}) => {
const hasFiredConfettiRef = useRef(false);
<div className="space-y-2 text-center">
<p className="text-base font-semibold text-white">
Welcome to your AI office
</p>
<p className="max-w-sm text-sm text-white/60">
Your gateway is connected and your agents are ready. Step inside and
explore the 3D workspace where your AI team operates.
</p>
</div>
useEffect(() => {
if (!companyCreated || hasFiredConfettiRef.current) return;
hasFiredConfettiRef.current = true;
const defaults = {
spread: 68,
startVelocity: 32,
ticks: 220,
gravity: 1.05,
zIndex: 100130,
colors: ["#67e8f9", "#fbbf24", "#fde047", "#f472b6", "#c4b5fd"],
};
void confetti({
...defaults,
particleCount: 90,
origin: { x: 0.5, y: 0.35 },
});
window.setTimeout(() => {
void confetti({
...defaults,
particleCount: 70,
angle: 60,
origin: { x: 0.15, y: 0.45 },
});
void confetti({
...defaults,
particleCount: 70,
angle: 120,
origin: { x: 0.85, y: 0.45 },
});
}, 180);
}, [companyCreated]);
<div className="w-full max-w-xs space-y-2">
<div className="flex items-center gap-2.5 rounded-lg border border-white/8 bg-white/[0.03] px-3.5 py-2.5">
<Building2 className="h-4 w-4 shrink-0 text-emerald-400" />
<div>
<p className="text-xs font-medium text-white">Explore the Office</p>
<p className="text-[10px] text-white/45">
Navigate rooms, watch agents, and interact
</p>
return (
<div className="relative flex flex-col items-center justify-center gap-5 py-4">
<div className="flex h-14 w-14 items-center justify-center rounded-full bg-amber-400/15">
<Rocket className="h-7 w-7 text-amber-300" />
</div>
<div className="space-y-2 text-center">
<p className="text-base font-semibold text-white">
{companyCreated
? `${companyName?.trim() || "Your company"} created successfully`
: "Welcome to your AI office"}
</p>
<p className="max-w-sm text-sm text-white/60">
{companyCreated
? `${companyName?.trim() || "Your company"} is ready. Your new team has been created in OpenClaw and placed into the office.`
: "Your gateway is connected and your agents are ready. Step inside and explore the 3D workspace where your AI team operates."}
</p>
</div>
<div className="w-full max-w-xs space-y-2">
<div className="flex items-center gap-2.5 rounded-lg border border-white/8 bg-white/[0.03] px-3.5 py-2.5">
<Building2 className="h-4 w-4 shrink-0 text-amber-300" />
<div>
<p className="text-xs font-medium text-white">
{companyCreated ? "Meet Your New Team" : "Explore the Office"}
</p>
<p className="text-[10px] text-white/45">
{companyCreated
? "Walk the office, inspect the new roles, and start delegating work."
: "Navigate rooms, watch agents, and interact"}
</p>
</div>
</div>
</div>
</div>
<p className="text-[11px] text-white/35">
You can always re-run onboarding from Studio settings.
</p>
</div>
);
<p className="text-[11px] text-white/35">
You can always re-run onboarding from Studio settings.
</p>
</div>
);
};