Build Cobble project structure from the handoff
- Remove the preset document suite (letters, emails, invoices, quotes, PDF generation, line items) with its routes, API handlers and tables - Rebrand to Cobble: site data, Lato, handoff design tokens (light and dark) in main.css, brand assets in public/brand, ember stone logo and regenerated favicons - Add bots, bot_messages, bot_tasks and bot_task_steps tables, regenerate DB types (BUN_SQLITE_COBBLE_*) and add a sample crew seed (seed:bots) - Add the chat shell at /admin/bots: rail with pinned coordinator and user popover, bottom-anchored conversation with composer, working-on panel, and a send-message API scoped to the session user - Add BotStone and Wordmark components, crew status and relative time utils with tests, and update AGENTS.md Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Bot identity hues. A bot keeps its hue for life; a hue never means state.
|
||||
* The coordinator has no hue.
|
||||
*/
|
||||
export const BotHues = [
|
||||
{
|
||||
title: "Ember",
|
||||
value: "ember",
|
||||
},
|
||||
{
|
||||
title: "Amber",
|
||||
value: "amber",
|
||||
},
|
||||
{
|
||||
title: "Moss",
|
||||
value: "moss",
|
||||
},
|
||||
{
|
||||
title: "Teal",
|
||||
value: "teal",
|
||||
},
|
||||
{
|
||||
title: "Cobalt",
|
||||
value: "cobalt",
|
||||
},
|
||||
{
|
||||
title: "Violet",
|
||||
value: "violet",
|
||||
},
|
||||
{
|
||||
title: "Rose",
|
||||
value: "rose",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotHue = (typeof BotHues)[number]["value"];
|
||||
|
||||
export const BotKinds = [
|
||||
{
|
||||
title: "Worker",
|
||||
value: "worker",
|
||||
},
|
||||
{
|
||||
title: "Coordinator",
|
||||
value: "coordinator",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotKind = (typeof BotKinds)[number]["value"];
|
||||
|
||||
/**
|
||||
* A bot's face is its status. There are no badges or spinners.
|
||||
*/
|
||||
export const BotFaces = [
|
||||
{
|
||||
title: "Idle",
|
||||
value: "idle",
|
||||
},
|
||||
{
|
||||
title: "Working",
|
||||
value: "working",
|
||||
},
|
||||
{
|
||||
title: "Done",
|
||||
value: "done",
|
||||
},
|
||||
{
|
||||
title: "Asleep",
|
||||
value: "asleep",
|
||||
},
|
||||
{
|
||||
title: "Needs you",
|
||||
value: "needs-you",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotFace = (typeof BotFaces)[number]["value"];
|
||||
|
||||
export const BotMessageAuthors = [
|
||||
{
|
||||
title: "Bot",
|
||||
value: "bot",
|
||||
},
|
||||
{
|
||||
title: "User",
|
||||
value: "user",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotMessageAuthor = (typeof BotMessageAuthors)[number]["value"];
|
||||
|
||||
export const BotTaskStatuses = [
|
||||
{
|
||||
title: "Active",
|
||||
value: "active",
|
||||
},
|
||||
{
|
||||
title: "Done",
|
||||
value: "done",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotTaskStatus = (typeof BotTaskStatuses)[number]["value"];
|
||||
|
||||
export const BotTaskStepStates = [
|
||||
{
|
||||
title: "Done",
|
||||
value: "done",
|
||||
},
|
||||
{
|
||||
title: "Active",
|
||||
value: "active",
|
||||
},
|
||||
{
|
||||
title: "Pending",
|
||||
value: "pending",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type BotTaskStepState = (typeof BotTaskStepStates)[number]["value"];
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { BotHue } from "./bot-dict";
|
||||
|
||||
/**
|
||||
* Static Tailwind class names per hue, so the classes survive the build.
|
||||
*/
|
||||
export const BotHueFillClasses: Record<BotHue, string> = {
|
||||
ember: "fill-hue-ember",
|
||||
amber: "fill-hue-amber",
|
||||
moss: "fill-hue-moss",
|
||||
teal: "fill-hue-teal",
|
||||
cobalt: "fill-hue-cobalt",
|
||||
violet: "fill-hue-violet",
|
||||
rose: "fill-hue-rose",
|
||||
};
|
||||
|
||||
export const BotHueBgClasses: Record<BotHue, string> = {
|
||||
ember: "bg-hue-ember",
|
||||
amber: "bg-hue-amber",
|
||||
moss: "bg-hue-moss",
|
||||
teal: "bg-hue-teal",
|
||||
cobalt: "bg-hue-cobalt",
|
||||
violet: "bg-hue-violet",
|
||||
rose: "bg-hue-rose",
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
export const EmailStatuses = [
|
||||
{
|
||||
title: "Draft",
|
||||
value: "draft",
|
||||
},
|
||||
{
|
||||
title: "Sent",
|
||||
value: "sent",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type EmailStatus = (typeof EmailStatuses)[number]["value"];
|
||||
|
||||
export const EmailAttachmentTypes = [
|
||||
{
|
||||
title: "Letter",
|
||||
value: "letter",
|
||||
},
|
||||
{
|
||||
title: "Invoice",
|
||||
value: "invoice",
|
||||
},
|
||||
{
|
||||
title: "Quote",
|
||||
value: "quote",
|
||||
},
|
||||
{
|
||||
title: "File",
|
||||
value: "file",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type EmailAttachmentType = (typeof EmailAttachmentTypes)[number]["value"];
|
||||
|
||||
export const InvoiceStatuses = [
|
||||
{
|
||||
title: "Draft",
|
||||
value: "draft",
|
||||
},
|
||||
{
|
||||
title: "Issued",
|
||||
value: "issued",
|
||||
},
|
||||
{
|
||||
title: "Paid",
|
||||
value: "paid",
|
||||
},
|
||||
{
|
||||
title: "Cancelled",
|
||||
value: "cancelled",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type InvoiceStatus = (typeof InvoiceStatuses)[number]["value"];
|
||||
|
||||
export const QuoteStatuses = [
|
||||
{
|
||||
title: "Draft",
|
||||
value: "draft",
|
||||
},
|
||||
{
|
||||
title: "Sent",
|
||||
value: "sent",
|
||||
},
|
||||
{
|
||||
title: "Accepted",
|
||||
value: "accepted",
|
||||
},
|
||||
{
|
||||
title: "Declined",
|
||||
value: "declined",
|
||||
},
|
||||
{
|
||||
title: "Expired",
|
||||
value: "expired",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type QuoteStatus = (typeof QuoteStatuses)[number]["value"];
|
||||
Reference in New Issue
Block a user