Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/design-review-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@reddb-io/redcode": patch
---

Restore a compact Design review surface with cyan actions, system light/dark themes, a viewport-sized preview, and keyboard-accessible Review, Assets and Details panels. Keep control styles inside Shadow DOM and prototype styles inside their sandboxed iframe, without adding Tailwind or a global reset.
5 changes: 5 additions & 0 deletions .changeset/lsp-node-recovery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@reddb-io/redcode": patch
---

Fix LSP recovery from rejected NODE_OPTIONS, including Biome startup with --user-system-ca. Keep retries isolated per server, preserve quoted options, and monitor the successfully restarted process instead of the exited original.
5 changes: 5 additions & 0 deletions .changeset/restore-design-tui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@reddb-io/redcode": patch
---

Restore Design as the cyan third mode in the fullscreen TUI, alongside Build and Plan. Keep prototyping, browser feedback, image assets, SVG-to-GIF exports and approved Plan handoffs attached to the same conversation. Reopen pre-0.22 prototypes without overwriting their sources, and retain the new Design revision and rendering services.
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,15 @@ HTTP endpoint. Set `REDCODE_RPC_URL` to the printed URL. It reuses

## Modes

Build, Plan and Design define what the agent may change. The full-screen TUI uses its existing
session runtime for Build and Plan; `Tab` switches between available agents. Design now starts in
its own SessionV2 terminal with `redcode design`, or in a SessionV2 session in the web app. The
TUI's `/design` command shows how to open that terminal. Existing conversations are preserved;
a legacy session ID cannot be adopted as a V2 session.
Build, Plan and Design are the three primary modes in the full-screen TUI. Press `Tab`
to cycle between them: Build is red, Plan is gold and Design is cyan. `/design` selects
Design in the current conversation; `/design-review` reopens its browser review. Prototype
changes, generated assets, browser feedback and approved handoffs remain in that same
conversation. Design edits only its prototype work directory.

In `redcode design`, use `/mode design|plan|build` to change the active mode explicitly. Mode
changes keep the current SessionV2 history; they do not expand an existing Goal's scope.
The web app and the optional `redcode design` terminal also use the shared Design
storage and rendering services. Existing TUI sessions keep their history and execution
runtime; using Design does not require moving to another terminal.

<img src="docs/modes/build.svg" alt="Build mode" width="100%" />

Expand All @@ -275,18 +276,18 @@ reuse application components and design-system evidence through authorized reads

## Design Mode

Design combines a resumable terminal session with a browser review surface. It supports HTML,
Design combines the full-screen TUI conversation with a browser review surface. It supports HTML,
React and Solid prototypes, versioned assets, editable SVG-to-GIF exports, and recorded approval.

### Start

```sh
redcode design "Explore the settings screen"
redcode design --model provider/model
redcode design --session ses_existing_v2
redcode
# Press Tab to select Design, or use /design.
# Use /design-review to reopen the current conversation’s browser review.
```

Use `/review` inside the terminal to open the browser. Choose a starting point, the target
Use `/design-review` inside the terminal to open the browser. Choose a starting point, the target
application, an engine and an objective. The agent publishes revisions with `design_preview`.
The web app opens the same review implementation in its **Design** tab.

Expand Down Expand Up @@ -339,10 +340,12 @@ streaming and migration of the full-screen TUI renderer remain future work.
| The plan's marked Design section | Reviewed scope and evidence for the implementation handoff |
| `DESIGN.md` or `.red/DESIGN.md` | Project design guidance used as source evidence |

Version 0.22 moves Design off the legacy agents and `/design` HTTP routes. Existing V1 Design
state and `design.json` files are not migrated automatically. Keep old artifacts when upgrading;
new reviews use `/api/session/:sessionID/design/review`. Legacy Design configuration options do
not configure the new review surface.
Design is available in the existing full-screen TUI again. New documents use the shared
revision and asset store. When continuing a pre-0.22 prototype, `design_preview` still
accepts its original `path`: it imports the source into a new document, keeps private
review files out of the published snapshot, and preserves the original directory.
TUI feedback and approvals return through `/design/session/:sessionID`; web-app sessions
use `/api/session/:sessionID/design`.

See [Design Studio](specs/design/studio.md) for storage, permissions, exports and MCP configuration,
and [Design terminal](specs/design/terminal.md) for connection and interaction commands.
Expand Down
3 changes: 2 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/app/src/i18n/design-goal-br.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const designGoalPortuguese: Record<string, string> = {
"session.design.studio.title": "Design",
"session.design.studio.details": "Detalhes",
"session.design.studio.create": "Criar design",
"session.design.studio.name": "Nome",
"session.design.studio.journey": "Ponto de partida",
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/i18n/design-goal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { DESKTOP_NATIVE_LOCALES, DESKTOP_NATIVE_LOCALE_TAGS } from "./desktop-na
describe("Design and Goal localization coverage", () => {
test("declares English fallback separately from completed translations", () => {
expect(designGoalLocales).toEqual(["en", "br"])
expect(designGoalKeys).toHaveLength(95)
expect(designGoalKeys).toHaveLength(96)
expect(designGoalCoverage("en")).toEqual({ sourceLocale: "en", translated: [], fallback: [] })
expect(designGoalCoverage("br")).toEqual({ sourceLocale: "br", translated: designGoalKeys, fallback: [] })
for (const locale of DESKTOP_NATIVE_LOCALES.filter((locale) => locale !== "en" && locale !== "br")) {
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/design/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function review(storage: string, design: string, id: string, index:
await atomic(path.join(directory, `${id}-${index}.excalidraw`), scene)
}

export async function snapshot(root: string, blobs: string) {
export async function snapshot(root: string, blobs: string, read?: (file: string) => Promise<void>) {
const files: Record<string, string> = {}
const budget = { bytes: 0 }
const walk = async (directory: string) => {
Expand All @@ -62,7 +62,9 @@ export async function snapshot(root: string, blobs: string) {
if (!entry.isFile()) continue
if (Object.keys(files).length >= 2000)
throw new Design.Error({ code: "invalid", message: "Design contains more than 2000 files" })
const source = Bun.file(await resolve(root, file))
const resolved = await resolve(root, file)
await read?.(resolved)
const source = Bun.file(resolved)
budget.bytes += source.size
if (source.size > 25 * 1024 * 1024 || budget.bytes > 100 * 1024 * 1024)
throw new Design.Error({ code: "invalid", message: "Snapshot limits: 25 MB per file and 100 MB in total" })
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/v1/config/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ export * as ConfigMCPV1 from "./mcp"
import { Schema } from "effect"
import { PositiveInt } from "../../schema"

const Media = Schema.Record(
Schema.String,
Schema.Struct({
operations: Schema.mutable(Schema.Array(Schema.Literals(["generate", "edit", "reference"]))),
formats: Schema.mutable(Schema.Array(Schema.String)),
transparency: Schema.Boolean,
}),
)

export const Local = Schema.Struct({
media: Schema.optional(Media),
type: Schema.Literal("local").annotate({ description: "Type of MCP server connection" }),
command: Schema.mutable(Schema.Array(Schema.String)).annotate({
description: "Command and arguments to run the MCP server",
Expand Down Expand Up @@ -42,6 +52,7 @@ export const OAuth = Schema.Struct({
export type OAuth = Schema.Schema.Type<typeof OAuth>

export const Remote = Schema.Struct({
media: Schema.optional(Media),
type: Schema.Literal("remote").annotate({ description: "Type of MCP server connection" }),
url: Schema.String.annotate({ description: "URL of the remote MCP server" }),
enabled: Schema.optional(Schema.Boolean).annotate({
Expand Down
1 change: 1 addition & 0 deletions packages/design/src/copy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const reviewCopy = {
title: "Design",
details: "Details",
create: "Create design",
name: "Name",
journey: "Starting point",
Expand Down
Loading
Loading