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:
2026-10-18 17:10:36 +01:00
co-authored by Claude Opus 5.5
parent 81e4a8aecc
commit 3286b80029
340 changed files with 3161 additions and 12060 deletions
@@ -1,6 +1,6 @@
import type {
BUN_SQLITE_BSQLITE_USER_TYPES,
BUN_SQLITE_BSQLITE_USERS,
BUN_SQLITE_COBBLE_USER_TYPES,
BUN_SQLITE_COBBLE_USERS,
} from "@/db/types/db";
import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler";
import clientDeleteMediaHandler from "@/src/functions/frontend/client-delete-media-handler";
@@ -26,7 +26,7 @@ export default async function submitUserForm({
return;
}
const new_user_data: BUN_SQLITE_BSQLITE_USERS = _.pick<
const new_user_data: BUN_SQLITE_COBBLE_USERS = _.pick<
UserFormObject,
keyof UserFormObject
>(form, ["first_name", "last_name", "email", "username", "bio"]);
@@ -99,7 +99,7 @@ export default async function submitUserForm({
if (user_types?.[0]) {
const add_user_types =
await adminCrudHandler<BUN_SQLITE_BSQLITE_USER_TYPES>({
await adminCrudHandler<BUN_SQLITE_COBBLE_USER_TYPES>({
action: "insert",
table: "user_types",
insert_data: user_types.map((ut) => ({
@@ -1,7 +1,7 @@
import Form from "@moduletrace/twui/form/Form";
import LoadingOverlay from "@moduletrace/twui/elements/LoadingOverlay";
import useFormInit from "@/src/hooks/use-form-init";
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import submitUserForm from "../../(functions)/submit-user-form";
import UserFormName from "./user-form-name";
import Tag from "@moduletrace/twui/elements/Tag";
@@ -16,7 +16,7 @@ import UserFormImage from "./user-form-image";
type Props = {
existing_user?: UserFormObject;
existing_user_full?: BUN_SQLITE_BSQLITE_USERS;
existing_user_full?: BUN_SQLITE_COBBLE_USERS;
};
export default function UserForm({ existing_user, existing_user_full }: Props) {
@@ -1,4 +1,4 @@
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import Button from "@moduletrace/twui/layout/Button";
import useFormInit from "@/src/hooks/use-form-init";
@@ -6,7 +6,7 @@ export default function UserFormAction({
setForm,
existing,
existing_full,
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
const title = existing_full?.id ? "Update User" : "Create New User";
return (
@@ -1,4 +1,4 @@
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import TinyMCEEditor from "@moduletrace/twui/editors/TinyMCE";
import Button from "@moduletrace/twui/layout/Button";
import useFormInit from "@/src/hooks/use-form-init";
@@ -8,7 +8,7 @@ export default function UserFormBio({
existing,
existing_full,
form,
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
const title = existing_full?.id ? "Update User" : "Create New User";
return (
@@ -1,11 +1,11 @@
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import Input from "@moduletrace/twui/form/Input";
import useFormInit from "@/src/hooks/use-form-init";
export default function UserFormEmail({
setForm,
form,
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
return (
<>
<Input
@@ -2,7 +2,7 @@ import ImageUpload from "@moduletrace/twui/form/ImageUpload";
import grabMediaURL from "@/src/functions/backend/media/grab-media-url";
import useFormInit from "@/src/hooks/use-form-init";
import type { UserFormObject } from "@/src/types";
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
export default function UserFormImage({
setForm,
@@ -11,7 +11,7 @@ export default function UserFormImage({
}: ReturnType<typeof useFormInit<UserFormObject>>) {
const title = existing_full?.id ? "Update User" : "Create New User";
const person = existing_full as BUN_SQLITE_BSQLITE_USERS_JOIN | undefined;
const person = existing_full as BUN_SQLITE_COBBLE_USERS_JOIN | undefined;
const user_image_url = person?.profile_media_id
? grabMediaURL({
@@ -1,4 +1,4 @@
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import Input from "@moduletrace/twui/form/Input";
import Row from "@moduletrace/twui/layout/Row";
import useFormInit from "@/src/hooks/use-form-init";
@@ -6,7 +6,7 @@ import useFormInit from "@/src/hooks/use-form-init";
export default function UserFormName({
setForm,
form,
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
return (
<Row className="w-full grid xl:grid-cols-2">
<Input
@@ -1,11 +1,11 @@
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
import Input from "@moduletrace/twui/form/Input";
import useFormInit from "@/src/hooks/use-form-init";
export default function UserFormUsername({
setForm,
form,
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
return (
<>
<Input