feat: implement Stories 3.4, 3.5, 3.6 — AI proposals, wizard, hover & palette
Some checks failed
CI / Tests / 🧪 Test (push) Has been cancelled

Story 3.4: AI semantic suggestions with accept/reject workflow
- ProposalBar overlay with visual diff
- Accept/reject flow with graph snapshot restore
- useProposalDiff hook for change summary
- System prompt scoping for selected elements

Story 3.5: New diagram wizard with AI type inference
- CreateDiagramDialog with AI type inference (Haiku)
- initialDescription prop for chat-first flow
- Auto-send on mount with hasSentInitial ref guard
- DB migration for diagram description column

Story 3.6: Hover affordances and command palette
- HoverAffordances toolbar (5 AI actions, debounced)
- CommandPalette (Cmd+K) with AI, nav, Go to Node
- prefillChat/fitViewRequested/focusNodeId actions
- Code review: getNodesBounds, onOpenRightPanel,
  timer cleanup, test count fix

374 tests passing (251 web + 123 AI).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-03-01 08:55:06 +00:00
parent 6591d6385a
commit c4379afe1f
32 changed files with 5828 additions and 81 deletions

View File

@@ -3,6 +3,7 @@ import * as z from "zod";
import { getCopilotHistory, streamCopilot } from "@turbostarter/ai/copilot/api";
import { copilotMessageSchema } from "@turbostarter/ai/copilot/schema";
import { inferDiagramType } from "@turbostarter/ai/copilot/type-inference";
import { enforceAuth, deductCredits, rateLimiter, validate } from "../../../middleware";
@@ -12,6 +13,10 @@ const chatIdQuerySchema = z.object({
chatId: z.string(),
});
const inferTypeSchema = z.object({
description: z.string().min(3).max(500),
});
export const copilotRouter = new Hono<{
Variables: {
user: User;
@@ -27,6 +32,17 @@ export const copilotRouter = new Hono<{
return c.json(messages);
},
)
.post(
"/infer-type",
enforceAuth,
rateLimiter,
validate("json", inferTypeSchema),
async (c) => {
const { description } = c.req.valid("json");
const result = await inferDiagramType(description);
return c.json(result);
},
)
.post(
"/",
enforceAuth,

View File

@@ -24,12 +24,14 @@ export const createDiagramSchema = z.object({
"sequence",
"flowchart",
]),
description: z.string().max(500).optional(),
projectId: z.string().optional(),
});
export const updateDiagramBodySchema = z
.object({
title: z.string().min(1).max(255).optional(),
description: z.string().max(500).optional(),
projectId: z.string().nullable().optional(),
sortOrder: z.number().int().min(0).optional(),
graphData: z
@@ -45,6 +47,7 @@ export const updateDiagramBodySchema = z
.refine(
(data) =>
data.title !== undefined ||
data.description !== undefined ||
data.projectId !== undefined ||
data.sortOrder !== undefined ||
data.graphData !== undefined,