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
59 changes: 30 additions & 29 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,34 +52,34 @@ conversation with the agent. Every pixel must earn its place.

### Typography

| Role | Size | Weight | Tracking | Font Stack |
|------|------|--------|----------|------------|
| Thread title (sidebar) | `text-xs` (0.75rem) | `font-normal` | default | Inter, system-ui, sans-serif |
| Thread subtitle / metadata | `text-[10px]` | `font-normal` | default | Inter, system-ui, sans-serif |
| Badge text | `text-[10px]` | `font-medium` | default | Inter, system-ui, sans-serif |
| Button text | `text-sm` (0.875rem) | `font-medium` | default | Inter, system-ui, sans-serif |
| Heading / dialog title | `text-lg` (1.125rem) | `font-semibold` | `-0.01em` | Inter, system-ui, sans-serif |
| Code / terminal | `text-sm` | `font-normal` | default | SF Mono, Consolas, monospace |
| Project name | `text-xs` | `font-semibold` | default | Inter, system-ui, sans-serif |
| Role | Size | Weight | Tracking | Font Stack |
| -------------------------- | -------------------- | --------------- | --------- | ---------------------------- |
| Thread title (sidebar) | `text-xs` (0.75rem) | `font-normal` | default | Inter, system-ui, sans-serif |
| Thread subtitle / metadata | `text-[10px]` | `font-normal` | default | Inter, system-ui, sans-serif |
| Badge text | `text-[10px]` | `font-medium` | default | Inter, system-ui, sans-serif |
| Button text | `text-sm` (0.875rem) | `font-medium` | default | Inter, system-ui, sans-serif |
| Heading / dialog title | `text-lg` (1.125rem) | `font-semibold` | `-0.01em` | Inter, system-ui, sans-serif |
| Code / terminal | `text-sm` | `font-normal` | default | SF Mono, Consolas, monospace |
| Project name | `text-xs` | `font-semibold` | default | Inter, system-ui, sans-serif |

### Color Semantics

Colors are referenced through CSS custom properties, never hardcoded hex values.

| Token | Usage |
|-------|-------|
| `text-foreground` | Primary text |
| `text-muted-foreground` | Secondary/deemphasized text |
| Token | Usage |
| -------------------------- | ------------------------------------------------- |
| `text-foreground` | Primary text |
| `text-muted-foreground` | Secondary/deemphasized text |
| `text-muted-foreground/50` | Tertiary/metadata text (branch names, timestamps) |
| `bg-background` | Page background |
| `bg-accent` | Hover state, active row highlight |
| `bg-accent/60` | Active sidebar item |
| `bg-accent/40` | Selected sidebar item |
| `text-emerald-600` | Additions / success (green) |
| `text-rose-500` | Deletions / error (red) |
| `text-warning` | Warning states, behind-upstream |
| `text-destructive` | Destructive actions (delete) |
| `border-border/60` | Subtle badge borders |
| `bg-background` | Page background |
| `bg-accent` | Hover state, active row highlight |
| `bg-accent/60` | Active sidebar item |
| `bg-accent/40` | Selected sidebar item |
| `text-emerald-600` | Additions / success (green) |
| `text-rose-500` | Deletions / error (red) |
| `text-warning` | Warning states, behind-upstream |
| `text-destructive` | Destructive actions (delete) |
| `border-border/60` | Subtle badge borders |

### Spacing Rules

Expand All @@ -95,13 +95,13 @@ Colors are referenced through CSS custom properties, never hardcoded hex values.

Five premium themes, each with light and dark variants:

| Theme | Vibe |
|-------|------|
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Carbon** | Stark, modern, performance-focused |
| **Vapor** | Refined, fluid, purposeful |
| **Cotton Candy** | Sweet, dreamy, pink and blue |
| **Cathedral Circuit** | Sacred machine, techno-gothic |
| Theme | Vibe |
| --------------------- | ------------------------------------- |
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Carbon** | Stark, modern, performance-focused |
| **Vapor** | Refined, fluid, purposeful |
| **Cotton Candy** | Sweet, dreamy, pink and blue |
| **Cathedral Circuit** | Sacred machine, techno-gothic |

All themes define the same set of CSS custom properties. Components must use semantic
tokens (`bg-accent`, `text-muted-foreground`) — never theme-specific values.
Expand Down Expand Up @@ -249,6 +249,7 @@ a single flow:
```

Quick action resolves automatically based on git state:

- Has changes + no PR → "Commit, push & PR"
- Has changes + existing PR → "Commit & push"
- No changes + ahead → "Push & create PR"
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/openclaw/GatewayClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ export class OpenclawGatewayClient {

if (frame.type === "event" && typeof frame.event === "string") {
let matchedWaiter = false;
for (const waiter of [...this.pendingEventWaiters]) {
for (const waiter of this.pendingEventWaiters) {
if (waiter.eventName === frame.event) {
matchedWaiter = true;
this.pendingEventWaiters.delete(waiter);
Expand Down
39 changes: 39 additions & 0 deletions apps/server/src/prReview/Layers/PrReview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ query PullRequestReviewDashboard($owner: String!, $name: String!, $number: Int!)
headRefName
baseRefOid
headRefOid
reviews(last: 100) {
nodes {
state
body
submittedAt
authorAssociation
author {
login
}
}
}
labels(first: 20) {
nodes { name color }
}
Expand Down Expand Up @@ -300,6 +311,32 @@ function normalizeStatusChecks(raw: unknown): PrReviewSummary["statusChecks"] {
return statusChecks;
}

function normalizeRecentReviews(raw: unknown): PrReviewSummary["recentReviews"] {
if (!Array.isArray(raw)) return [];
const maintainerAssociations = new Set(["COLLABORATOR", "MEMBER", "OWNER"]);
return raw
.map((entry) => {
if (!entry || typeof entry !== "object") return null;
const record = entry as Record<string, unknown>;
if (!maintainerAssociations.has(asString(record.authorAssociation) ?? "")) return null;
const submittedAt = asString(record.submittedAt);
const state = asString(record.state);
const author =
record.author && typeof record.author === "object"
? asString((record.author as Record<string, unknown>).login)
: null;
if (!submittedAt || !state || !author) return null;
return {
authorLogin: author,
state,
body: typeof record.body === "string" ? record.body : "",
submittedAt,
} satisfies PrReviewSummary["recentReviews"][number];
})
.filter((entry): entry is PrReviewSummary["recentReviews"][number] => entry !== null)
.toSorted((a, b) => Date.parse(b.submittedAt) - Date.parse(a.submittedAt));
}

function normalizeDashboardResponse(
raw: unknown,
): Pick<PrReviewDashboardResult, "pullRequest" | "threads"> {
Expand Down Expand Up @@ -343,6 +380,7 @@ function normalizeDashboardResponse(
((pullRequest.commits as any)?.nodes?.[0] as any)?.commit?.statusCheckRollup?.contexts?.nodes ??
[],
);
const recentReviews = normalizeRecentReviews((pullRequest.reviews as any)?.nodes ?? []);

const threads = Array.isArray((pullRequest.reviewThreads as any)?.nodes)
? ((pullRequest.reviewThreads as any).nodes as unknown[])
Expand Down Expand Up @@ -394,6 +432,7 @@ function normalizeDashboardResponse(
.map((entry) => normalizeUser(entry))
.filter((entry): entry is GitHubUserPreview => entry !== null)
.map((user) => ({ user, role: "requestedReviewer" as const })),
recentReviews,
totalThreadCount: threads.length,
unresolvedThreadCount: threads.filter((thread) => !thread.isResolved).length,
headSha: asString(pullRequest.headRefOid),
Expand Down
Loading
Loading