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
84 changes: 84 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,90 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.8.0] - 2026-07-31

A full rebuild of the web canvas interface. A UI audit of all 15 frontend components found 45
defects: 12 correctness, 11 accessibility, 6 responsive, 7 design-system, 9 content. This
release closes every one of them. No backend contract changes, so the CLI, the MCP server and
every API route behave exactly as in 1.7.0.

### Added

- **A design-token stylesheet and a dark theme.** `packages/web/frontend/src/styles.css` holds
every colour, space, radius, shadow and type step as a CSS custom property. `[data-theme="dark"]`
re-points the same tokens. The theme follows `prefers-color-scheme` until the user picks a side,
then keeps that choice in `localStorage`. Nothing downloads a web font, so the strict
Content-Security-Policy the server sends stays intact.
- **A responsive layout.** The frontend had zero media queries. It now has breakpoints at 1180px,
900px and 620px. Below 900px the fixed 420px sidebar becomes a two-pane switch between Chat and
Workspace. The nine workspace tabs scroll sideways instead of clipping. The shell uses
`100dvh`, so the composer stays above the iOS URL bar.
- **The WAI-ARIA tabs pattern.** `role="tablist"`, `role="tab"`, `aria-selected`, `aria-controls`,
roving `tabindex`, and Arrow/Home/End keys. Each panel is a `role="tabpanel"` section.
- **Keyboard shortcuts and a skip link.** `Cmd/Ctrl+K` focuses the composer, `Cmd/Ctrl+1..9` picks
a tab, `Escape` closes the catalog drawer and the node panel.
- **A stop button.** An `AbortController` now cancels a running design or change.
- **Error toasts.** A polite live region surfaces the failures the old code swallowed.
- **OpenTofu, Pulumi TypeScript and Pulumi Python in the Export tab.** All three shipped in
`cloudwright.exporter.FORMATS` but had no button in the web UI. The tab now offers 13 formats in
three groups.
- **`scripts/ui_screenshots.py`.** It screenshots every tab at three widths in both themes against
the mock-LLM server, and `--readme` regenerates the exact `docs/screenshots/` filenames.
- **`packages/web/tests/test_static_bundle.py`.** Eight checks read the bundle in
`cloudwright_web/static/`. They confirm that the hashed assets match `index.html`, that the tokens
and the dark theme survive minification, that breakpoints exist, that the focus ring holds, and
that no em-dash reaches user copy. A frontend change that never reaches the wheel now fails CI.

### Fixed

- **A mid-stream error billed a second generation.** `streamSucceeded` only became true after the
stream loop returned, so an `error` event after the spec arrived left it false. The non-streaming
fallback then ran a second design call and its result replaced the first. The fallback now runs
only when the stream produced no spec.
- **Panel results no longer die on a tab switch.** Validation, compliance, plan and review results
lived in component state that unmounted whenever the user changed tab. Panels now mount on first
use and stay mounted.
- **The catalog drawer no longer covers the diagram on load.** It defaulted to open.
- **Silent failures now speak.** Diagram SVG/PNG export, module insertion, the standards check and
the spec download all returned on `!res.ok` with no message.
- **The YAML tab shows the server's YAML.** It rendered a hand-written client-side serialiser that
quoted nothing, so a value such as `no` or `2.0` read back as a boolean or a number. The panel now
asks the server for the authoritative YAML, and the local serialiser (still the offline fallback)
quotes anything that would change type.
- **Contrast.** 27 uses of `#94a3b8` (2.84:1 on white) and 2 of `#cbd5e1` (1.61:1) fell below the
WCAG 1.4.3 AA floor. Every token now clears 4.5:1 in both themes.
- **Focus visibility.** Four `outline: none` rules removed the focus ring with no replacement, which
fails WCAG 2.4.7. There is now one `:focus-visible` ring for the whole application.
- **The closed node panel left the tab order.** It stayed in the DOM at `translateX(100%)`, so
keyboard focus walked into inputs parked off-screen. It unmounts when closed.
- **The streaming indicator animates.** It referenced a `pulse` keyframe that no file defined.
- **An input method no longer submits mid-word.** Enter now checks `isComposing`, so confirming a
Japanese, Chinese or Korean candidate does not send the message.
- **A native `<dialog>` replaces `window.confirm`.** Three destructive actions used the browser
dialog, which takes no styling and drops focus out of the page.
- **Error copy carries no em-dash.** `formatApiError` joined the message and the suggestion with
one.
- **The dead session write is gone.** The reset button wrote `cloudwright_last_session` to
`localStorage` and nothing ever read it.
- **The diagram fits its viewport.** `fitView` ran before the effect built any nodes, so the graph
rendered at default zoom in a corner. It now refits when the node set changes, and leaves a
hand-placed layout alone during a drag.
- **Diagram chrome stops overlapping.** The legend covered the React Flow zoom controls, and on a
phone the Add Resource button sat on top of the export toolbar.

### Changed

- **The 90-line duplicate of the send path is gone.** The `Modify` tab re-implemented streaming,
fallback, costing and error handling inline in a JSX prop. Both entry points now call one
`runTurn`.
- **Empty states name the next action.** Six panels said "Design an architecture first." and stopped.
- **The composer is a textarea.** It grows with its content, Enter sends, Shift+Enter adds a line.
- **Browser tests use stable selectors.** Two assertions matched on inline style strings
(`[style*="background: rgb(241, 245, 249)"]`), which a stylesheet removes. They now use
`data-testid`. Nine new browser tests cover the tab pattern, the theme, panel persistence and the
dialog.
- **Fresh screenshots and both web demo GIFs**, recorded against the new interface.

## [1.7.0] - 2026-07-08

Closes the July 2026 product audit findings. The differentiating features (offline review,
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,25 @@ hcl = export_spec(spec, "terraform", output_dir="./infra")

<a id="whats-new"></a>

## What's new in v1.8.0

The web canvas got a full interface rebuild. It has a dark theme, it works down to a phone, and it follows the WAI-ARIA tabs pattern. Twelve behaviour bugs went with it. One of them billed a second architecture generation after a mid-stream error.

<p align="center">
<img src="docs/screenshots/cloudwright-light-1-diagram.png" alt="Cloudwright web canvas: chat panel on the left, tabbed workspace with the boundary-aware diagram on the right" width="900">
</p>

- **One stylesheet, one token set, and a dark theme.** Colour, spacing, radius and type come from CSS custom properties. The theme follows the operating system until you pick a side. Every text colour clears the 4.5:1 contrast floor. 29 sites did not.
- **It works on a phone.** The layout was a hard 420px sidebar and no media query anywhere. Below 900px it is now a two-pane switch. The nine tabs scroll instead of clipping. `100dvh` keeps the composer above the iOS URL bar.
- **Keyboard and screen reader.** The tab bar is a real `tablist` with arrow-key roving focus. Every control shows a focus ring. A live region announces design progress. `Cmd/Ctrl+K` focuses the composer and `Cmd/Ctrl+1..9` picks a tab.
- **A mid-stream error no longer bills twice.** The stream could fail after the spec arrived. The fallback then ran a second generation, and that architecture replaced the first. The retry now runs only when the stream gives nothing.
- **Panel results survive a tab switch.** Run a HIPAA scan, look at Cost, come back. The panel used to be empty.
- **Three more export formats.** OpenTofu, Pulumi TypeScript and Pulumi Python shipped in the exporter with no button. The Export tab now offers all thirteen, in groups.
- **Failures say so.** Diagram export, module insert, the standards check and the download failed silently. Each one now raises a toast with the server message.
- **The YAML tab shows the server YAML.** A client-side serialiser quoted nothing, so `region: no` read back as the boolean false.
- **The catalog drawer starts closed.** It opened over the diagram on every page load.
- **The composer is a textarea.** Shift+Enter adds a line. An input-method candidate no longer submits mid-word. You can stop a running generation.

## What's new in v1.7.0

Cloudwright's design-time checks now reach every coding agent, not just its own CLI. Almost every popular AI coding harness speaks MCP, so one server puts `review`, `compliance`, and `plan` inside their agent loops.
Expand Down
30 changes: 29 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,42 @@ pip install 'cloudwright-ai[web]'
cloudwright chat --web
```

Opens `http://localhost:8765`. The canvas lets you chat to design, drag and drop components, edit fields, add resources from the catalog drawer, and run Compliance and Plan checks in the UI.
Opens `http://localhost:8765`. Chat to design, then drag components, edit fields, and add
resources from the catalog drawer. Compliance, Plan, Review and Export all run in the UI.

Use a different port:

```bash
cloudwright chat --web --port 9000
```

### Nine workspace tabs

`diagram`, `cost`, `validate`, `compliance`, `plan`, `review`, `export`, `spec`, `modify`.
Each tab keeps its own results. A tab switch never throws away a finished scan.

### Keyboard

| Keys | Action |
|---|---|
| `Cmd/Ctrl` + `K` | Focus the chat composer |
| `Cmd/Ctrl` + `1` to `9` | Open the tab at that position |
| `Enter` | Send the message |
| `Shift` + `Enter` | Add a line to the message |
| `Left` / `Right` / `Home` / `End` | Move across the tab bar, once a tab has focus |
| `Escape` | Close the catalog drawer, the node panel, or a dialog |

### Theme

The canvas follows your operating system light or dark setting. The moon or sun button in the
top left pins it, and the choice survives a reload. Every colour clears the WCAG AA 4.5:1
contrast floor in both themes.

### Small screens

Below 900px wide the canvas splits into two panes, Chat and Workspace. A switch sits at the
bottom of each pane. The tab bar scrolls sideways.

---

## Machine-readable output
Expand Down
Binary file modified docs/screenshots/cloudwright-compliance-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-1-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-1-ecommerce.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-2-analytics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-2-cost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-3-cost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-3-validate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-4-canvas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-light-4-validate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/cloudwright-plan-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/cloudwright-controls-web-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/cloudwright-smart-canvas-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/cli/cloudwright_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.7.0"
__version__ = "1.8.0"
2 changes: 1 addition & 1 deletion packages/core/cloudwright/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
ValidationResult,
)

__version__ = "1.7.0"
__version__ = "1.8.0"

__all__ = [
"Alternative",
Expand Down
8 changes: 4 additions & 4 deletions packages/core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ dependencies = [
]

[project.optional-dependencies]
cli = ["cloudwright-ai-cli==1.7.0"]
web = ["cloudwright-ai-cli==1.7.0", "cloudwright-ai-web==1.7.0"]
mcp = ["cloudwright-ai-mcp==1.7.0"]
all = ["cloudwright-ai-cli==1.7.0", "cloudwright-ai-web==1.7.0", "cloudwright-ai-mcp==1.7.0", "databricks-sdk>=0.38.0"]
cli = ["cloudwright-ai-cli==1.8.0"]
web = ["cloudwright-ai-cli==1.8.0", "cloudwright-ai-web==1.8.0"]
mcp = ["cloudwright-ai-mcp==1.8.0"]
all = ["cloudwright-ai-cli==1.8.0", "cloudwright-ai-web==1.8.0", "cloudwright-ai-mcp==1.8.0", "databricks-sdk>=0.38.0"]
pdf = ["weasyprint", "markdown2"]
databricks = ["databricks-sdk>=0.38.0"]
live-import = [
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp/cloudwright_mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.7.0"
__version__ = "1.8.0"
2 changes: 1 addition & 1 deletion packages/web/cloudwright_web/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Cloudwright Web — FastAPI backend for architecture intelligence."""

__version__ = "1.7.0"
__version__ = "1.8.0"


def __getattr__(name: str):
Expand Down
Loading
Loading