@codexview/react 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +56 -0
  2. package/dist/components/CodexTranscript.d.ts +41 -0
  3. package/dist/components/ErrorBlock.d.ts +7 -0
  4. package/dist/components/ExecBlock.d.ts +9 -0
  5. package/dist/components/ItemErrorBoundary.d.ts +16 -0
  6. package/dist/components/Markdown.d.ts +20 -0
  7. package/dist/components/MessageBubble.d.ts +10 -0
  8. package/dist/components/PatchBlock.d.ts +9 -0
  9. package/dist/components/RawEventBlock.d.ts +7 -0
  10. package/dist/components/ReasoningBlock.d.ts +11 -0
  11. package/dist/components/SearchBlock.d.ts +10 -0
  12. package/dist/components/StatusBar.d.ts +10 -0
  13. package/dist/components/TodoListBlock.d.ts +9 -0
  14. package/dist/components/ToolCallBlock.d.ts +9 -0
  15. package/dist/components/TurnContainer.d.ts +7 -0
  16. package/dist/components/_shared.d.ts +2 -0
  17. package/dist/components/icons.d.ts +16 -0
  18. package/dist/hooks/useCodexTranscript.d.ts +10 -0
  19. package/dist/hooks/useSmoothStream.d.ts +7 -0
  20. package/dist/index.d.ts +38 -0
  21. package/dist/index.js +13520 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/reducer/status.d.ts +2 -0
  24. package/dist/reducer/transcript.d.ts +4 -0
  25. package/dist/styles.css +493 -0
  26. package/dist/types/events.d.ts +164 -0
  27. package/dist/types/model.d.ts +75 -0
  28. package/docs/api.md +156 -0
  29. package/docs/changelog.md +40 -0
  30. package/docs/events.md +65 -0
  31. package/docs/integration-agentweb.md +112 -0
  32. package/docs/styling.md +81 -0
  33. package/docs/superpowers/plans/2026-05-15-codexview-implementation.md +3903 -0
  34. package/docs/superpowers/specs/2026-05-15-codexview-design.md +661 -0
  35. package/package.json +84 -0
@@ -0,0 +1,75 @@
1
+ import { PatchFile, SearchResult, TodoEntry, TokenUsage } from './events.js';
2
+ /** Item-level lifecycle status (5 states per spec §5.1). */
3
+ export type ItemStatus = 'pending' | 'running' | 'completed' | 'failed' | 'stopped';
4
+ /** Discriminated kind of a rendered item. */
5
+ export type ItemKind = 'user_message' | 'reasoning' | 'assistant_text' | 'tool_call' | 'exec' | 'search' | 'patch' | 'todo_list' | 'error' | 'raw';
6
+ interface ItemViewBase {
7
+ id: string;
8
+ kind: ItemKind;
9
+ status: ItemStatus;
10
+ startedAt: number;
11
+ updatedAt: number;
12
+ }
13
+ export type ItemView = (ItemViewBase & {
14
+ kind: 'user_message';
15
+ text: string;
16
+ }) | (ItemViewBase & {
17
+ kind: 'reasoning';
18
+ text: string;
19
+ }) | (ItemViewBase & {
20
+ kind: 'assistant_text';
21
+ text: string;
22
+ }) | (ItemViewBase & {
23
+ kind: 'tool_call';
24
+ name: string;
25
+ server?: string;
26
+ args: unknown;
27
+ result?: unknown;
28
+ error?: string;
29
+ }) | (ItemViewBase & {
30
+ kind: 'exec';
31
+ command: string;
32
+ exit?: number;
33
+ stdout?: string;
34
+ stderr?: string;
35
+ durationMs?: number;
36
+ }) | (ItemViewBase & {
37
+ kind: 'search';
38
+ query: string;
39
+ results?: SearchResult[];
40
+ }) | (ItemViewBase & {
41
+ kind: 'patch';
42
+ files: PatchFile[];
43
+ ok?: boolean;
44
+ }) | (ItemViewBase & {
45
+ kind: 'todo_list';
46
+ items: TodoEntry[];
47
+ }) | (ItemViewBase & {
48
+ kind: 'error';
49
+ message: string;
50
+ }) | (ItemViewBase & {
51
+ kind: 'raw';
52
+ payload: unknown;
53
+ });
54
+ export interface TurnView {
55
+ turnId: string;
56
+ startedAt: number;
57
+ completedAt?: number;
58
+ status: 'running' | 'completed' | 'failed' | 'aborted';
59
+ items: ItemView[];
60
+ usage?: TokenUsage;
61
+ error?: {
62
+ message: string;
63
+ code?: string;
64
+ };
65
+ }
66
+ export interface TranscriptModel {
67
+ threadId?: string;
68
+ turns: TurnView[];
69
+ lastEventAt: number;
70
+ }
71
+ /** Empty initial model. Always safe to start reducing from here. */
72
+ export declare const EMPTY_MODEL: TranscriptModel;
73
+ /** Session-level status (5 states per spec §5.3). */
74
+ export type TranscriptStatus = 'idle' | 'working' | 'completed' | 'stopped' | 'failed';
75
+ export {};
package/docs/api.md ADDED
@@ -0,0 +1,156 @@
1
+ # API Reference
2
+
3
+ All exports from `codexview`. Import via `import { ... } from 'codexview'`.
4
+
5
+ ## Components
6
+
7
+ ### `<CodexTranscript>`
8
+
9
+ Top-level transcript renderer.
10
+
11
+ ```tsx
12
+ <CodexTranscript
13
+ events={events}
14
+ status?={status}
15
+ error?={{ message, details? }}
16
+ className?={string}
17
+ maxItems?={number}
18
+ emptyState?={ReactNode}
19
+ onItemClick?={(id) => void}
20
+ components?={Partial<CodexTranscriptComponents>}
21
+ disableSmoothStream?={boolean}
22
+ onInternalError?={(err, event?) => void}
23
+ />
24
+ ```
25
+
26
+ | Prop | Default | Notes |
27
+ |------|---------|-------|
28
+ | `events` | required | Append-only is most efficient; full replace also works. Reference equality skips re-reduce. |
29
+ | `status` | inferred | When provided, fully replaces `inferStatus(model)`. |
30
+ | `error` | undefined | Shown inside `StatusBar` when status is `failed` or `stopped`. |
31
+ | `className` | undefined | Appended to `.codexview-root` class list. |
32
+ | `maxItems` | unlimited | Trims oldest items, shows "已省略最早的 X 条" hint at the top. |
33
+ | `emptyState` | `'暂无对话'` | Rendered when `events` is empty. |
34
+ | `onItemClick` | undefined | Receives `item.id` of the clicked item. |
35
+ | `components` | builtin | Replace any subcomponent (e.g. `{ ToolCallBlock: MyTool }`). |
36
+ | `disableSmoothStream` | `false` | Disables the typewriter effect for `assistant_text` and `reasoning`. |
37
+ | `onInternalError` | undefined | Called when reducer or item render throws; component falls back without crashing. |
38
+
39
+ #### Minimal example
40
+
41
+ ```tsx
42
+ const events = useAtomValue(streamingAtomFamily(sessionId));
43
+ return <CodexTranscript events={events.list} />;
44
+ ```
45
+
46
+ ### `<StatusBar>`
47
+
48
+ ```tsx
49
+ <StatusBar status={status} label?={string} error?={{ message, details? }} />
50
+ ```
51
+
52
+ Returns `null` when `status === 'idle'`.
53
+
54
+ ### `<TurnContainer>`
55
+
56
+ ```tsx
57
+ <TurnContainer turn={turn}>{children}</TurnContainer>
58
+ ```
59
+
60
+ ### `<MessageBubble>`
61
+
62
+ ```tsx
63
+ <MessageBubble item={userOrAssistantItem} smoothStream?={boolean} />
64
+ ```
65
+
66
+ ### `<ReasoningBlock>`
67
+
68
+ ```tsx
69
+ <ReasoningBlock item={reasoningItem} defaultOpen?={boolean} smoothStream?={boolean} />
70
+ ```
71
+
72
+ ### `<ToolCallBlock>`
73
+
74
+ ```tsx
75
+ <ToolCallBlock item={toolCallItem} />
76
+ ```
77
+
78
+ Renders args inline; result inline if small, collapsed in `<details>` if long (`>500` chars, `>4` lines, or `>3` JSON depth).
79
+
80
+ ### `<ExecBlock>`
81
+
82
+ ```tsx
83
+ <ExecBlock item={execItem} />
84
+ ```
85
+
86
+ Shimmer bar shown while `status === 'running'`. stdout/stderr collapsed beyond size threshold.
87
+
88
+ ### `<SearchBlock>`
89
+
90
+ ```tsx
91
+ <SearchBlock item={searchItem} initialVisible?={number} />
92
+ ```
93
+
94
+ Shows first 3 results by default; "展开剩余 N 条" reveals the rest.
95
+
96
+ ### `<PatchBlock>`
97
+
98
+ ```tsx
99
+ <PatchBlock item={patchItem} />
100
+ ```
101
+
102
+ Each file is collapsed; expanding shows diff with git-style coloring.
103
+
104
+ ### `<RawEventBlock>`
105
+
106
+ ```tsx
107
+ <RawEventBlock item={rawItem} />
108
+ ```
109
+
110
+ Used as fallback for unknown event types.
111
+
112
+ ### `<ItemErrorBoundary>`
113
+
114
+ ```tsx
115
+ <ItemErrorBoundary fallback?={ReactNode} onError?={(err, info) => void}>
116
+ {children}
117
+ </ItemErrorBoundary>
118
+ ```
119
+
120
+ ## Hooks
121
+
122
+ ### `useCodexTranscript(events, options?)`
123
+
124
+ ```ts
125
+ const { model, status } = useCodexTranscript(events, { status?, onInternalError? });
126
+ ```
127
+
128
+ Internally caches the last reduced model and uses prefix detection for incremental reduction.
129
+
130
+ ### `useSmoothStream(text, options?)`
131
+
132
+ ```ts
133
+ const display = useSmoothStream(fullText, { enabled?, charsPerFrame?, minDelayMs? });
134
+ ```
135
+
136
+ Returns the substring revealed so far. Resets when input shrinks. Returns full text immediately if `enabled === false` or `prefers-reduced-motion: reduce`.
137
+
138
+ ## Pure functions
139
+
140
+ ### `reduceTranscript(prev, event) => next`
141
+
142
+ Pure reducer. Use directly to drive your own state container.
143
+
144
+ ### `inferStatus(model) => TranscriptStatus`
145
+
146
+ Returns `'idle' | 'working' | 'completed' | 'stopped' | 'failed'`.
147
+
148
+ ### `EMPTY_MODEL`
149
+
150
+ Frozen initial `TranscriptModel`. Always safe to start reducing from this.
151
+
152
+ ## Types
153
+
154
+ `ChatStreamEvent`, `ChatStreamEventType`, `TokenUsage`, `SearchResult`, `PatchFile`, `TranscriptModel`, `TurnView`, `ItemView`, `ItemKind`, `ItemStatus`, `TranscriptStatus`, `CodexTranscriptComponents`, `UseCodexTranscriptOptions`, `UseSmoothStreamOptions`, plus per-component prop types (`StatusBarProps`, etc.).
155
+
156
+ See [docs/events.md](events.md) for the full `ChatStreamEvent` shape.
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ All notable changes documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
+
5
+ ## [0.1.1] — 2026-05-15
6
+
7
+ ### Added
8
+
9
+ - New item kinds aligned with the official [OpenAI Codex SDK](https://github.com/openai/codex/tree/main/sdk/typescript):
10
+ - `todo_list` — plan / TODO list with completion tracking; new `<TodoListBlock>` component
11
+ - `error` — non-fatal item-level error (distinct from `turn_failed`); new `<ErrorBlock>` component
12
+ - `<Markdown>` component (powered by `react-markdown` + `remark-gfm`): tables, task lists, autolinks, inline code, fenced code blocks, blockquotes
13
+ - Markdown rendering integrated into `MessageBubble`, `ReasoningBlock`, and `ToolCallBlock` (string-typed results auto-detected as Markdown)
14
+ - New event types: `todo_list`, `error_item`
15
+ - New exported types: `TodoEntry`, `MarkdownProps`, `TodoListBlockProps`, `ErrorBlockProps`
16
+
17
+ ### Changed
18
+
19
+ - All tool-related blocks (`ToolCallBlock`, `ExecBlock`, `SearchBlock`, `PatchBlock`) are now collapsed by default. They auto-open while their status is `pending` or `running`. New `defaultOpen` prop available on each.
20
+ - `MessageBubble` and `ReasoningBlock` accept a `markdown` prop (default `true`) to render text as Markdown. Streaming partial text falls back to plain text until completion to avoid janky partial-Markdown rendering.
21
+
22
+ ### Dependencies
23
+
24
+ - Added: `react-markdown` `^10.1.0`, `remark-gfm` `^4.0.1`
25
+
26
+ ## [0.1.0] — 2026-05-15
27
+
28
+ ### Added
29
+
30
+ - `<CodexTranscript>` main component (consumes `ChatStreamEvent[]`)
31
+ - Subcomponents: `StatusBar`, `TurnContainer`, `MessageBubble`, `ReasoningBlock`, `ToolCallBlock`, `ExecBlock`, `SearchBlock`, `PatchBlock`, `RawEventBlock`, `ItemErrorBoundary`
32
+ - Hooks: `useCodexTranscript`, `useSmoothStream`
33
+ - Pure functions: `reduceTranscript`, `inferStatus`, `EMPTY_MODEL`
34
+ - 8 supported event item kinds + raw fallback for unknown types
35
+ - 5-state item status machine, 4-state turn status machine, 5-state session status
36
+ - CSS Modules styling with overridable CSS variables
37
+ - `lucide-react` icon system as peerDependency
38
+ - `prefers-reduced-motion` honored by all animations
39
+ - 6 fixtures + replay integration tests
40
+ - Docs: API reference, event contract, styling, agentweb integration guide
package/docs/events.md ADDED
@@ -0,0 +1,65 @@
1
+ # Event contract
2
+
3
+ CodexView consumes a discriminated union `ChatStreamEvent`. The host (e.g. agentweb backend) is expected to emit events that match these shapes. Unknown event types are not errors — they fall through to `kind: 'raw'` and render via `RawEventBlock`.
4
+
5
+ All events carry `at: number` (epoch ms).
6
+
7
+ ## Lifecycle
8
+
9
+ | Type | Required fields | Reducer effect |
10
+ |------|-----------------|----------------|
11
+ | `thread_started` | `threadId` | sets `model.threadId` |
12
+ | `turn_started` | `turnId` | appends new `TurnView { status: 'running' }` |
13
+ | `turn_completed` | `turnId`, optional `usage` | turn → `completed`; flips unfinished items → `completed` |
14
+ | `turn_failed` | `turnId`, `error: { message, code? }` | turn → `failed`; flips unfinished items → `failed` |
15
+ | `turn_aborted` | `turnId`, optional `reason` | turn → `aborted`; flips unfinished items → `stopped` |
16
+
17
+ ## Messages
18
+
19
+ | Type | Required fields | ItemView produced |
20
+ |------|-----------------|-------------------|
21
+ | `user_message` | `turnId`, `itemId`, `text` | `kind: 'user_message'`, status `completed` |
22
+ | `agent_message` | `turnId`, `itemId`, `text`, `partial` | `kind: 'assistant_text'`; same `itemId` updates in place; `partial: false` flips to `completed` |
23
+ | `reasoning` | same as `agent_message` | `kind: 'reasoning'`; **never merged** with assistant_text |
24
+
25
+ ## Tool calls (paired by `callId`)
26
+
27
+ | Type | Required fields | Reducer effect |
28
+ |------|-----------------|----------------|
29
+ | `function_call` | `turnId`, `callId`, `name`, `args` | appends `tool_call`, status `pending` |
30
+ | `function_call_output` | `turnId`, `callId`, optional `output` or `error` | finds matching `tool_call`, sets `result` or `error`, flips status |
31
+ | `mcp_tool_call` | `turnId`, `callId`, `server`, `name`, `args` | same as `function_call` plus `server` |
32
+ | `mcp_tool_call_output` | `turnId`, `callId`, optional `output` or `error` | same as `function_call_output` |
33
+
34
+ ## Shell exec
35
+
36
+ | Type | Required fields | Reducer effect |
37
+ |------|-----------------|----------------|
38
+ | `exec_command_begin` | `turnId`, `callId`, `command` | appends `exec`, status `running` |
39
+ | `exec_command_end` | `turnId`, `callId`, `exit`, `stdout`, `stderr`, `durationMs` | finds matching `exec`, fills outputs, status `completed` if `exit === 0` else `failed` |
40
+
41
+ ## Web search
42
+
43
+ | Type | Required fields | Reducer effect |
44
+ |------|-----------------|----------------|
45
+ | `web_search_call` | `turnId`, `callId`, `query` | appends `search`, status `pending` |
46
+ | `web_search_end` | `turnId`, `callId`, `results: SearchResult[]` | finds matching `search`, fills results, status `completed` |
47
+
48
+ ## Patch apply
49
+
50
+ | Type | Required fields | Reducer effect |
51
+ |------|-----------------|----------------|
52
+ | `patch_apply_end` | `turnId`, `callId`, `files: PatchFile[]`, `ok: boolean` | appends `patch`, status `completed` if `ok` else `failed` |
53
+
54
+ ## Fallback
55
+
56
+ | Type | Required fields | Reducer effect |
57
+ |------|-----------------|----------------|
58
+ | `raw` | optional `turnId`, `payload: unknown` | if `turnId` present, appends `raw` ItemView; else only updates `lastEventAt` |
59
+
60
+ ## Invariants
61
+
62
+ 1. Reducer never throws on any input.
63
+ 2. Bulk `events.reduce(reduceTranscript, EMPTY_MODEL)` equals incremental reduce of the same series.
64
+ 3. Reducer is a pure function — no global state, no I/O.
65
+ 4. Unknown payload `type` is preserved verbatim in the produced `raw` ItemView.
@@ -0,0 +1,112 @@
1
+ # Integrating CodexView into agentweb
2
+
3
+ This is a drop-in replacement for `frontend/src/codex/components/MessageBubble.tsx`, `StreamingBubble.tsx`, and `ToolUseBlock.tsx`. The agentweb backend (`backend/src/codex/eventMap.ts`) produces a normalized event stream that is conceptually equivalent to `ChatStreamEvent`, but uses different field names.
4
+
5
+ ## Adapter required
6
+
7
+ The agentweb backend's `NormalizedEvent` and CodexView's `ChatStreamEvent` are conceptually equivalent but use different field names (e.g., agentweb uses `kind: 'text_delta'`, CodexView uses `type: 'agent_message'`). A small adapter function in agentweb (`frontend/src/codex/adapters/codexview.ts`) is needed to map between them. The Step 3 code example below is illustrative — replace `adapter(stream)` with the adapter-produced array and `stream.connected` with whatever connection-state field your `streamingAtomFamily` actually exposes.
8
+
9
+ ## Step 1 — install (development)
10
+
11
+ From the agentweb repo root:
12
+
13
+ ```bash
14
+ pnpm --filter frontend add file:../CodexView
15
+ pnpm --filter frontend add lucide-react
16
+ ```
17
+
18
+ (Once `codexview` is published to a registry, replace `file:../CodexView` with the version range.)
19
+
20
+ ## Step 2 — load styles + bridge tokens
21
+
22
+ In `frontend/src/main.tsx` (or another global entry):
23
+
24
+ ```ts
25
+ import 'codexview/styles.css';
26
+ ```
27
+
28
+ In `frontend/src/codex/styles/tokens.css` (append):
29
+
30
+ ```css
31
+ .aw-codex-transcript {
32
+ --cv-bg-user-bubble: var(--aw-bg-bubble-user);
33
+ --cv-bg-assistant-bubble: var(--aw-bg-bubble-bot);
34
+ --cv-text: var(--aw-text-primary);
35
+ --cv-axis-color: var(--aw-border-subtle);
36
+ --cv-bg-raised: var(--aw-bg-raised);
37
+ }
38
+ ```
39
+
40
+ (Match the variable list in `docs/styling.md` against agentweb's tokens.)
41
+
42
+ ## Step 3 — replace ChatThread internals
43
+
44
+ `frontend/src/codex/components/ChatThread.tsx`:
45
+
46
+ ```tsx
47
+ import { useAtomValue } from 'jotai';
48
+ import { CodexTranscript } from 'codexview';
49
+ import { streamingAtomFamily } from '../atoms/streaming';
50
+ import { adaptStreamEvents } from '../adapters/codexview'; // adapter required — see "Adapter required" section above
51
+
52
+ export function ChatThread({ sessionId }: { sessionId: string }) {
53
+ const stream = useAtomValue(streamingAtomFamily(sessionId));
54
+ return (
55
+ <CodexTranscript
56
+ events={adaptStreamEvents(stream)} // replace with adapter-produced ChatStreamEvent[]
57
+ status={stream.connected ? undefined : 'stopped'} // replace stream.connected with actual field name
58
+ className="aw-codex-transcript"
59
+ />
60
+ );
61
+ }
62
+ ```
63
+
64
+ The adapter maps agentweb's `NormalizedEvent` (with `kind` field) to CodexView's `ChatStreamEvent` (with `type` field). Adjust all property names to match the actual `streamingAtomFamily` shape.
65
+
66
+ ## Step 4 — clean up + handle approval
67
+
68
+ Delete from `frontend/src/codex/components/`:
69
+
70
+ - `MessageBubble.tsx`
71
+ - `StreamingBubble.tsx`
72
+ - `ToolUseBlock.tsx`
73
+
74
+ **Keep** approval logic. CodexView v0.1 deliberately does **not** ship an approval-bubble component (see spec §11). If `StreamingBubble.tsx` carried that responsibility, extract the approval portion into a standalone `ApprovalBubble.tsx` component within agentweb and render it next to `<CodexTranscript>` (e.g. as a sibling overlay), feeding it the same approval events.
75
+
76
+ ## Verify
77
+
78
+ ```bash
79
+ pnpm --filter frontend test
80
+ pnpm --filter frontend dev
81
+ ```
82
+
83
+ In the browser:
84
+
85
+ 1. Start a Codex session.
86
+ 2. Confirm streaming text appears with smooth typewriter effect.
87
+ 3. Trigger a tool call — confirm collapsible result.
88
+ 4. Trigger an exec — confirm shimmer while running.
89
+ 5. Disconnect the network — confirm StatusBar shows "已停止" once you set `status="stopped"`.
90
+
91
+ ## Rollback
92
+
93
+ ```bash
94
+ git revert <integration-commit-sha>
95
+ ```
96
+
97
+ Backend `ChatStreamEvent` shape and SSE endpoints do not change, so revert is purely frontend.
98
+
99
+ ## Type-safety guard
100
+
101
+ Add to `frontend/src/codex/types/eventCheck.ts`:
102
+
103
+ ```ts
104
+ import type { ChatStreamEvent as CV } from 'codexview';
105
+ import type { ChatStreamEvent as AW } from '../../../../backend/src/codex/eventMap';
106
+
107
+ // Will fail to compile if shapes drift.
108
+ type _AssertEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : never;
109
+ type _Check = _AssertEqual<CV, AW>;
110
+ ```
111
+
112
+ When the agentweb backend adds an event type, this assertion fails until codexview is updated.
@@ -0,0 +1,81 @@
1
+ # Styling
2
+
3
+ CodexView ships its own styles (`codexview/styles.css`) plus a `.codexview-root` reset to isolate from host CSS. All visual tokens are CSS variables you can override.
4
+
5
+ ## Loading
6
+
7
+ ```ts
8
+ import 'codexview/styles.css';
9
+ ```
10
+
11
+ ## Variable reference
12
+
13
+ Set these on `.codexview-root` (or any ancestor) to theme.
14
+
15
+ ### Layout
16
+
17
+ | Variable | Default | Notes |
18
+ |----------|---------|-------|
19
+ | `--cv-font-family` | system-ui stack | |
20
+ | `--cv-font-mono` | ui-monospace stack | |
21
+ | `--cv-font-size` | `14px` | base text size |
22
+ | `--cv-line-height` | `1.55` | |
23
+ | `--cv-radius` | `12px` | bubble radius |
24
+ | `--cv-radius-sm` | `8px` | block radius |
25
+ | `--cv-spacing-xs/-sm/-md/-lg` | 4/8/12/16 px | spacing scale |
26
+
27
+ ### Colors
28
+
29
+ | Variable | Default (light) | Notes |
30
+ |----------|-----------------|-------|
31
+ | `--cv-text` | `#1f2328` | primary text |
32
+ | `--cv-text-muted` | `#6e7781` | reasoning, captions |
33
+ | `--cv-text-inverse` | `#ffffff` | text on user bubble |
34
+ | `--cv-bg` | `#ffffff` | transcript background |
35
+ | `--cv-bg-raised` | `#f6f8fa` | StatusBar, tool block surface |
36
+ | `--cv-bg-user-bubble` | `#2f6feb` | user bubble |
37
+ | `--cv-bg-assistant-bubble` | `#f6f8fa` | assistant bubble |
38
+ | `--cv-bg-code` | `#0d1117` | exec / code background |
39
+ | `--cv-fg-code` | `#e6edf3` | code foreground |
40
+ | `--cv-border` | `#d0d7de` | dividers |
41
+ | `--cv-axis-color` | `#d0d7de` | turn timeline axis |
42
+ | `--cv-shimmer-color` | `rgba(31,35,40,0.08)` | exec shimmer |
43
+
44
+ ### Status colors
45
+
46
+ | Variable | Default | Status |
47
+ |----------|---------|--------|
48
+ | `--cv-status-pending` | `#6e7781` | gray |
49
+ | `--cv-status-running` | `#2f6feb` | blue |
50
+ | `--cv-status-completed` | `#1a7f37` | green |
51
+ | `--cv-status-failed` | `#cf222e` | red |
52
+ | `--cv-status-stopped` | `#6e7781` | gray |
53
+
54
+ ### Diff colors
55
+
56
+ | Variable | Default |
57
+ |----------|---------|
58
+ | `--cv-diff-add-bg` | `#ddf4e4` |
59
+ | `--cv-diff-del-bg` | `#ffebe9` |
60
+
61
+ ## Dark theme example
62
+
63
+ ```css
64
+ .dark .codexview-root {
65
+ --cv-text: #e6edf3;
66
+ --cv-text-muted: #8b949e;
67
+ --cv-bg: #0d1117;
68
+ --cv-bg-raised: #161b22;
69
+ --cv-bg-assistant-bubble: #161b22;
70
+ --cv-bg-user-bubble: #1f6feb;
71
+ --cv-border: #30363d;
72
+ --cv-axis-color: #30363d;
73
+ --cv-shimmer-color: rgba(255,255,255,0.05);
74
+ --cv-bg-code: #010409;
75
+ --cv-fg-code: #c9d1d9;
76
+ }
77
+ ```
78
+
79
+ ## Reduced motion
80
+
81
+ All animations (pulse, shimmer, blink caret, smooth stream) honor `prefers-reduced-motion: reduce` and degrade to static states automatically.