From 576ad94d0e334f4617fe9ecb970757e48478d810 Mon Sep 17 00:00:00 2001
From: Roy Lin <19165061825@163.com>
Date: Mon, 27 Jul 2026 23:17:52 +0800
Subject: [PATCH] docs: add interactive component catalog and runtime tutorial
---
website/docs/v6/en/_nav.json | 8 +-
website/docs/v6/en/api/index.mdx | 2 +-
website/docs/v6/en/guide/_meta.json | 4 +-
.../docs/v6/en/guide/components/_meta.json | 17 +
website/docs/v6/en/guide/components/index.mdx | 28 +
.../v6/en/guide/components/tui/_meta.json | 1 +
.../v6/en/guide/components/tui/activity.mdx | 20 +
.../docs/v6/en/guide/components/tui/data.mdx | 24 +
.../v6/en/guide/components/tui/feedback.mdx | 30 +
.../docs/v6/en/guide/components/tui/index.mdx | 21 +
.../docs/v6/en/guide/components/tui/input.mdx | 24 +
.../v6/en/guide/components/tui/navigation.mdx | 18 +
.../v6/en/guide/components/web/_meta.json | 9 +
.../en/guide/components/web/coordination.mdx | 18 +
.../v6/en/guide/components/web/execution.mdx | 24 +
.../docs/v6/en/guide/components/web/index.mdx | 22 +
.../en/guide/components/web/permissions.mdx | 18 +
.../v6/en/guide/components/web/results.mdx | 24 +
.../docs/v6/en/guide/components/web/tasks.mdx | 18 +
.../v6/en/guide/components/web/workspace.mdx | 18 +
website/docs/v6/en/guide/index.mdx | 4 +-
website/docs/v6/en/guide/persistence.mdx | 4 +-
.../docs/v6/en/guide/playground/_meta.json | 1 -
website/docs/v6/en/guide/playground/index.mdx | 40 -
website/docs/v6/en/guide/playground/tui.mdx | 47 -
website/docs/v6/en/guide/playground/web.mdx | 41 -
website/docs/v6/en/guide/security.mdx | 2 +-
website/docs/v6/en/guide/sessions.mdx | 2 +-
website/docs/v6/en/guide/tasks.mdx | 2 +-
website/docs/v6/en/guide/tools.mdx | 4 +-
website/docs/v6/en/guide/tui.mdx | 4 +-
website/docs/v6/en/guide/verification.mdx | 2 +-
website/docs/v6/zh/_nav.json | 8 +-
website/docs/v6/zh/api/index.mdx | 2 +-
website/docs/v6/zh/guide/_meta.json | 4 +-
.../docs/v6/zh/guide/components/_meta.json | 17 +
website/docs/v6/zh/guide/components/index.mdx | 28 +
.../v6/zh/guide/components/tui/_meta.json | 1 +
.../v6/zh/guide/components/tui/activity.mdx | 20 +
.../docs/v6/zh/guide/components/tui/data.mdx | 24 +
.../v6/zh/guide/components/tui/feedback.mdx | 30 +
.../docs/v6/zh/guide/components/tui/index.mdx | 20 +
.../docs/v6/zh/guide/components/tui/input.mdx | 24 +
.../v6/zh/guide/components/tui/navigation.mdx | 18 +
.../v6/zh/guide/components/web/_meta.json | 9 +
.../zh/guide/components/web/coordination.mdx | 18 +
.../v6/zh/guide/components/web/execution.mdx | 24 +
.../docs/v6/zh/guide/components/web/index.mdx | 21 +
.../zh/guide/components/web/permissions.mdx | 18 +
.../v6/zh/guide/components/web/results.mdx | 24 +
.../docs/v6/zh/guide/components/web/tasks.mdx | 18 +
.../v6/zh/guide/components/web/workspace.mdx | 18 +
website/docs/v6/zh/guide/index.mdx | 2 +-
website/docs/v6/zh/guide/persistence.mdx | 2 +-
.../docs/v6/zh/guide/playground/_meta.json | 1 -
website/docs/v6/zh/guide/playground/index.mdx | 34 -
website/docs/v6/zh/guide/playground/tui.mdx | 44 -
website/docs/v6/zh/guide/playground/web.mdx | 38 -
website/docs/v6/zh/guide/security.mdx | 2 +-
website/docs/v6/zh/guide/sessions.mdx | 2 +-
website/docs/v6/zh/guide/tasks.mdx | 2 +-
website/docs/v6/zh/guide/tools.mdx | 4 +-
website/docs/v6/zh/guide/tui.mdx | 2 +-
website/docs/v6/zh/guide/verification.mdx | 2 +-
website/package-lock.json | 47 +-
website/package.json | 5 +-
website/rspress.config.ts | 3 +-
website/scripts/generate-runtime-tutorial.mjs | 354 +++
website/theme/component-docs.css | 2130 +++++++++++++++++
website/theme/components/A3SComponentDemo.tsx | 1671 +++++++++++++
.../theme/components/AgentBuildingBlocks.tsx | 6 +-
website/theme/components/HomeLayout.tsx | 402 +++-
website/theme/components/TuiPlayground.tsx | 505 ----
website/theme/components/WebPlayground.tsx | 474 ----
website/theme/generated/runtime-tutorial.json | 1046 ++++++++
website/theme/index.css | 1187 ++++++++-
website/theme/index.tsx | 2 +-
website/theme/playgrounds.css | 1791 --------------
78 files changed, 7449 insertions(+), 3156 deletions(-)
create mode 100644 website/docs/v6/en/guide/components/_meta.json
create mode 100644 website/docs/v6/en/guide/components/index.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/_meta.json
create mode 100644 website/docs/v6/en/guide/components/tui/activity.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/data.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/feedback.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/index.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/input.mdx
create mode 100644 website/docs/v6/en/guide/components/tui/navigation.mdx
create mode 100644 website/docs/v6/en/guide/components/web/_meta.json
create mode 100644 website/docs/v6/en/guide/components/web/coordination.mdx
create mode 100644 website/docs/v6/en/guide/components/web/execution.mdx
create mode 100644 website/docs/v6/en/guide/components/web/index.mdx
create mode 100644 website/docs/v6/en/guide/components/web/permissions.mdx
create mode 100644 website/docs/v6/en/guide/components/web/results.mdx
create mode 100644 website/docs/v6/en/guide/components/web/tasks.mdx
create mode 100644 website/docs/v6/en/guide/components/web/workspace.mdx
delete mode 100644 website/docs/v6/en/guide/playground/_meta.json
delete mode 100644 website/docs/v6/en/guide/playground/index.mdx
delete mode 100644 website/docs/v6/en/guide/playground/tui.mdx
delete mode 100644 website/docs/v6/en/guide/playground/web.mdx
create mode 100644 website/docs/v6/zh/guide/components/_meta.json
create mode 100644 website/docs/v6/zh/guide/components/index.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/_meta.json
create mode 100644 website/docs/v6/zh/guide/components/tui/activity.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/data.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/feedback.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/index.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/input.mdx
create mode 100644 website/docs/v6/zh/guide/components/tui/navigation.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/_meta.json
create mode 100644 website/docs/v6/zh/guide/components/web/coordination.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/execution.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/index.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/permissions.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/results.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/tasks.mdx
create mode 100644 website/docs/v6/zh/guide/components/web/workspace.mdx
delete mode 100644 website/docs/v6/zh/guide/playground/_meta.json
delete mode 100644 website/docs/v6/zh/guide/playground/index.mdx
delete mode 100644 website/docs/v6/zh/guide/playground/tui.mdx
delete mode 100644 website/docs/v6/zh/guide/playground/web.mdx
create mode 100644 website/scripts/generate-runtime-tutorial.mjs
create mode 100644 website/theme/component-docs.css
create mode 100644 website/theme/components/A3SComponentDemo.tsx
delete mode 100644 website/theme/components/TuiPlayground.tsx
delete mode 100644 website/theme/components/WebPlayground.tsx
create mode 100644 website/theme/generated/runtime-tutorial.json
delete mode 100644 website/theme/playgrounds.css
diff --git a/website/docs/v6/en/_nav.json b/website/docs/v6/en/_nav.json
index b81685f..9318a35 100644
--- a/website/docs/v6/en/_nav.json
+++ b/website/docs/v6/en/_nav.json
@@ -2,12 +2,12 @@
{
"text": "Docs",
"link": "/guide/",
- "activeMatch": "^/guide/(?!examples/|playground/)"
+ "activeMatch": "^/guide/(?!examples/|components/)"
},
{
- "text": "Playground",
- "link": "/guide/playground/",
- "activeMatch": "^/guide/playground/"
+ "text": "Components",
+ "link": "/guide/components/",
+ "activeMatch": "^/guide/components/"
},
{
"text": "Examples",
diff --git a/website/docs/v6/en/api/index.mdx b/website/docs/v6/en/api/index.mdx
index f740aca..c9ceee2 100644
--- a/website/docs/v6/en/api/index.mdx
+++ b/website/docs/v6/en/api/index.mdx
@@ -45,4 +45,4 @@ When connecting your own infrastructure, you can replace `LlmClient`,
`ContextProvider`, `MemoryStore`, `SessionStore`, Workspace services, tools,
permission confirmation, hooks, MCP transports, and graph stores. To see how
events reach a UI first, open the
-[A3S TUI and Web Playground](/guide/playground/).
+[A3S TUI and A3S Web component docs](/guide/components/).
diff --git a/website/docs/v6/en/guide/_meta.json b/website/docs/v6/en/guide/_meta.json
index 903e8c3..5f68543 100644
--- a/website/docs/v6/en/guide/_meta.json
+++ b/website/docs/v6/en/guide/_meta.json
@@ -3,8 +3,8 @@
"tui",
{
"type": "dir",
- "name": "playground",
- "label": "Playground",
+ "name": "components",
+ "label": "Components",
"collapsible": true,
"collapsed": false
},
diff --git a/website/docs/v6/en/guide/components/_meta.json b/website/docs/v6/en/guide/components/_meta.json
new file mode 100644
index 0000000..bf7113a
--- /dev/null
+++ b/website/docs/v6/en/guide/components/_meta.json
@@ -0,0 +1,17 @@
+[
+ "index",
+ {
+ "type": "dir",
+ "name": "tui",
+ "label": "A3S TUI",
+ "collapsible": true,
+ "collapsed": false
+ },
+ {
+ "type": "dir",
+ "name": "web",
+ "label": "A3S Web",
+ "collapsible": true,
+ "collapsed": false
+ }
+]
diff --git a/website/docs/v6/en/guide/components/index.mdx b/website/docs/v6/en/guide/components/index.mdx
new file mode 100644
index 0000000..6363f31
--- /dev/null
+++ b/website/docs/v6/en/guide/components/index.mdx
@@ -0,0 +1,28 @@
+---
+title: 'Components'
+description: 'Inspect and operate individual A3S TUI and A3S Web components'
+---
+
+# Components
+
+These pages do not simulate one prebuilt task flow. Every example isolates one component and exposes
+its important states. Edit an input, change a status, or make a decision to see the component respond.
+
+| Library | Documentation |
+| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| A3S TUI | [Activity](/guide/components/tui/activity), [input and confirmation](/guide/components/tui/input), [navigation](/guide/components/tui/navigation), [data and changes](/guide/components/tui/data), [feedback](/guide/components/tui/feedback) |
+| A3S Web | [Task input](/guide/components/web/tasks), [execution](/guide/components/web/execution), [permissions and recovery](/guide/components/web/permissions), [coordination](/guide/components/web/coordination), [results](/guide/components/web/results), [workspace](/guide/components/web/workspace) |
+
+## Where each component appears
+
+
+
+The map follows the runtime stages of a task. The component pages answer the more concrete question:
+how should one event, approval request, or result appear to the user?
+
+## Example scope
+
+- Interactions change local React state only. They do not connect to a model, run commands, or edit files.
+- Examples are redrawn for the documentation width and do not replace the production products.
+- [`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI) is the source of truth for TUI components.
+- [`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web) is the source of truth for Web components.
diff --git a/website/docs/v6/en/guide/components/tui/_meta.json b/website/docs/v6/en/guide/components/tui/_meta.json
new file mode 100644
index 0000000..fd7d11f
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/_meta.json
@@ -0,0 +1 @@
+["index", "activity", "input", "navigation", "data", "feedback"]
diff --git a/website/docs/v6/en/guide/components/tui/activity.mdx b/website/docs/v6/en/guide/components/tui/activity.mdx
new file mode 100644
index 0000000..3d3d6a5
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/activity.mdx
@@ -0,0 +1,20 @@
+---
+title: 'Activity'
+description: 'Operate ActivityBlock and Checklist in isolation'
+---
+
+# Activity
+
+## ActivityBlock
+
+A summary for one reasoning or tool activity. Change its status, then select the body to reveal its log.
+
+
+
+## Checklist
+
+A list of plan items. Select an item to cycle through todo, in progress, and complete.
+
+
+
+These components render tool and plan events. They display scheduling state; they do not schedule work.
diff --git a/website/docs/v6/en/guide/components/tui/data.mdx b/website/docs/v6/en/guide/components/tui/data.mdx
new file mode 100644
index 0000000..ffbae70
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/data.mdx
@@ -0,0 +1,24 @@
+---
+title: 'Data and changes'
+description: 'Operate DataTable, DiffView, and ToolLogView in isolation'
+---
+
+# Data and changes
+
+## DataTable
+
+For structured tool-call, Run, or Artifact data. Change the sort key and select a row.
+
+
+
+## DiffView
+
+Shows file changes. Switch between unified and split views, or reveal whitespace.
+
+
+
+## ToolLogView
+
+Organizes output by tool call. Filter active calls or expand an individual result.
+
+
diff --git a/website/docs/v6/en/guide/components/tui/feedback.mdx b/website/docs/v6/en/guide/components/tui/feedback.mdx
new file mode 100644
index 0000000..d0bea1a
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/feedback.mdx
@@ -0,0 +1,30 @@
+---
+title: 'Feedback'
+description: 'Operate Alert, Progress, Toast, and SessionStatus in isolation'
+---
+
+# Feedback
+
+## Alert
+
+Info, success, warning, and error states use distinct semantic colors with one stable layout.
+
+
+
+## Progress
+
+A pausable progress display. Move the slider to inspect any completion value.
+
+
+
+## Toast
+
+Short feedback that leaves terminal content visible. Trigger or dismiss it.
+
+
+
+## SessionStatus
+
+Collects the work mode, model settings, context use, and keyboard hints.
+
+
diff --git a/website/docs/v6/en/guide/components/tui/index.mdx b/website/docs/v6/en/guide/components/tui/index.mdx
new file mode 100644
index 0000000..7f1e445
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/index.mdx
@@ -0,0 +1,21 @@
+---
+title: 'A3S TUI components'
+description: 'Activity, input, navigation, data, and feedback components from A3S TUI'
+---
+
+# A3S TUI components
+
+A3S TUI renders `AgentEvent`, plans, tool logs, diffs, and Session state in a terminal. The pages
+below isolate the components, so you do not need to understand a complete screen first.
+
+| Category | Components |
+| ----------------------------------------------------- | --------------------------------------------- |
+| [Activity](/guide/components/tui/activity) | `ActivityBlock`, `Checklist` |
+| [Input and confirmation](/guide/components/tui/input) | `ChoicePrompt`, `Confirm`, `TextInput` |
+| [Navigation](/guide/components/tui/navigation) | `Tabs`, `TreePicker` |
+| [Data and changes](/guide/components/tui/data) | `DataTable`, `DiffView`, `ToolLogView` |
+| [Feedback](/guide/components/tui/feedback) | `Alert`, `Progress`, `Toast`, `SessionStatus` |
+
+See
+[`src/components/mod.rs`](https://github.com/A3S-Lab/TUI/blob/main/src/components/mod.rs)
+for the complete export list.
diff --git a/website/docs/v6/en/guide/components/tui/input.mdx b/website/docs/v6/en/guide/components/tui/input.mdx
new file mode 100644
index 0000000..3779c47
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/input.mdx
@@ -0,0 +1,24 @@
+---
+title: 'Input and confirmation'
+description: 'Operate ChoicePrompt, Confirm, and TextInput in isolation'
+---
+
+# Input and confirmation
+
+## ChoicePrompt
+
+Use it for a short set of mutually exclusive options. Select an option to inspect focus and selection.
+
+
+
+## Confirm
+
+Renders a human approval request from the runtime. Allow and deny only update this local example.
+
+
+
+## TextInput
+
+A single-line instruction input with length, empty, and submit feedback.
+
+
diff --git a/website/docs/v6/en/guide/components/tui/navigation.mdx b/website/docs/v6/en/guide/components/tui/navigation.mdx
new file mode 100644
index 0000000..0e2c738
--- /dev/null
+++ b/website/docs/v6/en/guide/components/tui/navigation.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Navigation'
+description: 'Operate Tabs and TreePicker in isolation'
+---
+
+# Navigation
+
+## Tabs
+
+Move between Transcript, Changes, and Artifacts without leaving the current Session.
+
+
+
+## TreePicker
+
+Expand a directory and pick files for context. Expansion and selection remain independent.
+
+
diff --git a/website/docs/v6/en/guide/components/web/_meta.json b/website/docs/v6/en/guide/components/web/_meta.json
new file mode 100644
index 0000000..1c0c0a8
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/_meta.json
@@ -0,0 +1,9 @@
+[
+ "index",
+ "tasks",
+ "execution",
+ "permissions",
+ "coordination",
+ "results",
+ "workspace"
+]
diff --git a/website/docs/v6/en/guide/components/web/coordination.mdx b/website/docs/v6/en/guide/components/web/coordination.mdx
new file mode 100644
index 0000000..d4f7031
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/coordination.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Coordination'
+description: 'Operate the runtime plan and subagent lists in isolation'
+---
+
+# Coordination
+
+## TaskRuntimePlanList
+
+Shows the current plan and completion ratio. Select an item to cycle its state.
+
+
+
+## TaskRuntimeSubagentList
+
+Shows subagent status and progress. Selecting an item does not cancel or restart it.
+
+
diff --git a/website/docs/v6/en/guide/components/web/execution.mdx b/website/docs/v6/en/guide/components/web/execution.mdx
new file mode 100644
index 0000000..8c70c2a
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/execution.mdx
@@ -0,0 +1,24 @@
+---
+title: 'Execution'
+description: 'Operate ExecutionStream, ReasoningDisclosure, and ToolCallTimeline in isolation'
+---
+
+# Execution
+
+## ExecutionStream
+
+Appends runtime events in arrival order. Select `next event` to add them one at a time.
+
+
+
+## ReasoningDisclosure
+
+A collapsible reasoning summary with distinct live and complete states.
+
+
+
+## ToolCallTimeline
+
+One tool call with its status, command, and output. Status and expansion remain local to the component.
+
+
diff --git a/website/docs/v6/en/guide/components/web/index.mdx b/website/docs/v6/en/guide/components/web/index.mdx
new file mode 100644
index 0000000..3b892ba
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/index.mdx
@@ -0,0 +1,22 @@
+---
+title: 'A3S Web components'
+description: 'Task, execution, permission, coordination, result, and workspace components from A3S Web'
+---
+
+# A3S Web components
+
+A3S Web consumes runtime Sessions, event streams, permission requests, Artifacts, and Memory data.
+These pages group components by responsibility instead of placing everything in one fixed flow.
+
+| Category | Components |
+| ------------------------------------------------------------- | ------------------------------------------------------------ |
+| [Task input](/guide/components/web/tasks) | `TaskComposer`, `TaskLibrary` |
+| [Execution](/guide/components/web/execution) | `ExecutionStream`, `ReasoningDisclosure`, `ToolCallTimeline` |
+| [Permissions and recovery](/guide/components/web/permissions) | `PermissionDecision`, `RecoveryNotice` |
+| [Coordination](/guide/components/web/coordination) | `TaskRuntimePlanList`, `TaskRuntimeSubagentList` |
+| [Results](/guide/components/web/results) | `DeliverySummary`, `ArtifactEntries`, `ChangesInspector` |
+| [Workspace](/guide/components/web/workspace) | `WorkspaceEditor`, `MemoryGraph` |
+
+See
+[`apps/web/docs/COMPONENT_SPEC.md`](https://github.com/A3S-Lab/a3s/blob/main/apps/web/docs/COMPONENT_SPEC.md)
+for the complete component boundary.
diff --git a/website/docs/v6/en/guide/components/web/permissions.mdx b/website/docs/v6/en/guide/components/web/permissions.mdx
new file mode 100644
index 0000000..fe07be4
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/permissions.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Permissions and recovery'
+description: 'Operate PermissionDecision and RecoveryNotice in isolation'
+---
+
+# Permissions and recovery
+
+## PermissionDecision
+
+Keeps the operation, scope, and decision in one approval panel. Reset after allowing or denying.
+
+
+
+## RecoveryNotice
+
+The recovery entry point after a Session is interrupted. Dismiss it or enter the restoring state.
+
+
diff --git a/website/docs/v6/en/guide/components/web/results.mdx b/website/docs/v6/en/guide/components/web/results.mdx
new file mode 100644
index 0000000..1696564
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/results.mdx
@@ -0,0 +1,24 @@
+---
+title: 'Results'
+description: 'Operate DeliverySummary, ArtifactEntries, and ChangesInspector in isolation'
+---
+
+# Results
+
+## DeliverySummary
+
+Combines completion state, verification, and a change summary with optional details.
+
+
+
+## ArtifactEntries
+
+Select an Artifact from the current Run and inspect its type, size, and URI.
+
+
+
+## ChangesInspector
+
+Select a file and switch between unified and split diffs.
+
+
diff --git a/website/docs/v6/en/guide/components/web/tasks.mdx b/website/docs/v6/en/guide/components/web/tasks.mdx
new file mode 100644
index 0000000..e362c2a
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/tasks.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Task input'
+description: 'Operate TaskComposer and TaskLibrary in isolation'
+---
+
+# Task input
+
+## TaskComposer
+
+Combines task input, context entry, mode, and reasoning effort. Edit the text, change mode, and submit.
+
+
+
+## TaskLibrary
+
+Filters and selects recent tasks. Searching does not discard the current selection.
+
+
diff --git a/website/docs/v6/en/guide/components/web/workspace.mdx b/website/docs/v6/en/guide/components/web/workspace.mdx
new file mode 100644
index 0000000..057115d
--- /dev/null
+++ b/website/docs/v6/en/guide/components/web/workspace.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Workspace'
+description: 'Operate WorkspaceEditor and MemoryGraph in isolation'
+---
+
+# Workspace
+
+## WorkspaceEditor
+
+Switch files, edit a line, and inspect the unsaved state.
+
+
+
+## MemoryGraph
+
+Switch between relation graph and timeline modes. Select a memory node in the graph.
+
+
diff --git a/website/docs/v6/en/guide/index.mdx b/website/docs/v6/en/guide/index.mdx
index 54418ce..0f7e900 100644
--- a/website/docs/v6/en/guide/index.mdx
+++ b/website/docs/v6/en/guide/index.mdx
@@ -30,7 +30,7 @@ agent loop.
| Area | What A3S Code provides |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent sessions | Create a Workspace-bound `AgentSession` with `SessionBuilder`; send, run, stream, cancel, save, resume, and close it. Concurrent transcript operations fail immediately instead of racing. |
-| User interfaces | [`a3s code`](/guide/tui) renders the event stream in a terminal. The [Playground](/guide/playground/) shows the TUI and A3S Web flows in the docs. |
+| User interfaces | [`a3s code`](/guide/tui) renders the event stream in a terminal. The [component docs](/guide/components/) isolate the core A3S TUI and A3S Web controls. |
| Project files | [Filesystem-first](/guide/filesystem-first) explains `AGENTS.md`, ACL config, `.a3s/agents/`, `skills/`, `tools/`, and `schedules/`. |
| Tools | Built-in files, search, shell, Git, web, batch, structured output, QuickJS, Skills, MCP, and child-task tools. Model calls pass through argument, permission, confirmation, and cancellation checks. |
| Commands | [Commands](/guide/commands) covers TUI slash commands and custom `/command` handlers registered by an application. |
@@ -183,7 +183,7 @@ Check access in your application before exposing them to users.
## Continue reading
-- [Playground](/guide/playground/) shows the A3S TUI, A3S Web, and the components used at each stage of a task.
+- [Component docs](/guide/components/) provide isolated, interactive examples for A3S TUI and A3S Web.
- [A3S Code TUI](/guide/tui) explains installation, config discovery, slash commands, and effort profiles.
- [Filesystem-first](/guide/filesystem-first) covers `AGENTS.md`, ACL, AgentDir, Skills, tools, and schedules.
- [API contract](/guide/api-contract) lists the Node.js API covered by integration tests.
diff --git a/website/docs/v6/en/guide/persistence.mdx b/website/docs/v6/en/guide/persistence.mdx
index 71fbb3f..e47aee7 100644
--- a/website/docs/v6/en/guide/persistence.mdx
+++ b/website/docs/v6/en/guide/persistence.mdx
@@ -8,8 +8,8 @@ description: 'Saving and resuming sessions'
Persistence lets a session survive process restarts and gives product surfaces a stable session ID.
A resumed session can repopulate task lists, execution history, and delivery
-summaries. The [Playground](/guide/playground/) shows how the TUI and Web clients
-arrange that information.
+summaries. The [result components](/guide/components/web/results) show how the
+Web client arranges that information.
A3S Code persists three related but different things:
diff --git a/website/docs/v6/en/guide/playground/_meta.json b/website/docs/v6/en/guide/playground/_meta.json
deleted file mode 100644
index 27bcc96..0000000
--- a/website/docs/v6/en/guide/playground/_meta.json
+++ /dev/null
@@ -1 +0,0 @@
-["index", "tui", "web"]
diff --git a/website/docs/v6/en/guide/playground/index.mdx b/website/docs/v6/en/guide/playground/index.mdx
deleted file mode 100644
index 7a4dbaf..0000000
--- a/website/docs/v6/en/guide/playground/index.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: 'Overview'
-description: 'Explore A3S TUI, A3S Web, and the main components used to build a coding agent'
----
-
-# Playground
-
-These previews are rendered directly in MDX. You can click through their states,
-and they stay versioned with the docs. They do not connect to a model or run
-commands; use them to understand how a UI consumes runtime events before
-integrating the SDK.
-
-| Preview | What it shows |
-| -------------------------------- | ---------------------------------------------------------------------------- |
-| [A3S TUI](/guide/playground/tui) | Themes, run state, diffs, the file tree, and common terminal widgets |
-| [A3S Web](/guide/playground/web) | The complete UI path from task input and tool calls to approval and delivery |
-
-## Components used to build an agent
-
-Select a stage to see what A3S Code already provides and where each component is
-documented.
-
-
-
-The map follows a real task: define the agent and project rules, assemble
-context, expose tools, check access, delegate work, then present events and save
-the result. Each card links to the relevant chapter.
-
-## Preview scope
-
-- The playground changes local React state only. It never calls the A3S Code API.
-- The TUI preview uses `a3s-tui` component names, its four built-in themes, and
- the terminal layout used by the product.
-- The Web preview follows the task flow and design tokens in `apps/web`. The
- production application also connects sessions, workspaces, memory, and account
- services.
-- The implementation in
- [`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI) and
- [`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web)
- remains the source of truth.
diff --git a/website/docs/v6/en/guide/playground/tui.mdx b/website/docs/v6/en/guide/playground/tui.mdx
deleted file mode 100644
index dfd8737..0000000
--- a/website/docs/v6/en/guide/playground/tui.mdx
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: 'A3S TUI Playground'
-description: 'Switch A3S TUI themes, run scenes, and terminal components directly in the docs'
----
-
-# A3S TUI Playground
-
-Use the scene tabs to inspect a coding run, code changes, the Workspace tree, and
-common terminal widgets. The four swatches select Dark, Light, Catppuccin, and
-Tokyo Night. The checklist and component menu are interactive too.
-
-
-
-## Components represented in the preview
-
-| Scene | `a3s-tui` components |
-| ---------- | ------------------------------------------------------------------------ |
-| Run | `ActivityBlock`, `Checklist`, `TaskQueue`, `ToolStatusLine`, `StatusBar` |
-| Changes | `DiffView`, `SectionHeader`, `GutterBlock`, `OutputBlock` |
-| Workspace | `SplitPane`, `Tree`, `Breadcrumb`, `PreviewPanel`, `Viewport` |
-| Components | `MenuPanel`, `Tabs`, `DataTable`, `Progress`, `ChoicePrompt`, `Toast` |
-
-`a3s-tui` also ships input, modal, log, metric, timeline, and subagent-status
-components. See
-[`src/components/mod.rs`](https://github.com/A3S-Lab/TUI/blob/main/src/components/mod.rs)
-for the current exports.
-
-## How it consumes A3S Code events
-
-`a3s code` subscribes to `AgentSession::stream()`. Text deltas feed the
-transcript, tool events update activity and tool logs, plans update checklists,
-permission requests open a confirmation, and verification results feed output
-and diff views.
-
-```text
-AgentSession::stream()
- -> TextDelta -> transcript
- -> ToolCall* -> ActivityBlock / ToolLogView
- -> Plan* -> Checklist / TaskQueue
- -> PermissionAsk -> Confirm
- -> Verification* -> OutputBlock / DiffView
- -> End -> SessionStatus / StatusBar
-```
-
-The preview is rearranged to fit a documentation page and is not a replacement
-for the terminal application. See [A3S Code TUI](/guide/tui) for installation
-and commands, and [`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI) for source.
diff --git a/website/docs/v6/en/guide/playground/web.mdx b/website/docs/v6/en/guide/playground/web.mdx
deleted file mode 100644
index 9bb0149..0000000
--- a/website/docs/v6/en/guide/playground/web.mdx
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: 'A3S Web Playground'
-description: 'Try the A3S Web flow from task input through approval and delivery'
----
-
-# A3S Web Playground
-
-The composer, execution stream, permission card, and result view are
-interactive. Select “Run demo,” open the confirmation step, then allow the
-operation to see the delivery summary. Denying it keeps the task at the current
-tool call.
-
-
-
-## UI stages in a task
-
-| Stage | Main components | Data consumed |
-| ---------- | ---------------------------------------------------------------------------- | --------------------------------------------------------- |
-| Prepare | `NewTaskPreparation`, `TaskComposer`, `NewTaskWorkspaceControl` | Instructions, files, Skills, model, mode, and Workspace |
-| Run | `ExecutionStream`, `ReasoningDisclosure`, `ToolCallTimeline` | Text, reasoning, tool lifecycle, and output |
-| Confirm | `PermissionDecision` | Operation, reason, scope, risk, and timeout |
-| Coordinate | `TaskRuntimeFloatingPanel`, `TaskRuntimePlanList`, `TaskRuntimeSubagentList` | Plans, child tasks, and their results |
-| Deliver | `DeliverySummary`, `ChangesInspector`, `WorkspaceEditor` | Final response, verification, artifacts, and file changes |
-
-These components do not implement a second agent runtime. A3S Web projects A3S
-Code session, event, permission, and Workspace data into a desktop UI. The same
-backend can drive the TUI, an IDE extension, or your own frontend.
-
-## Where to start when integrating
-
-1. Create the task and subscribe to events with [sessions](/guide/sessions).
-2. Update `ToolCallTimeline` from the lifecycle described under [tools](/guide/tools).
-3. Connect approval buttons to Ask decisions from [security](/guide/security).
-4. Present [plans and child tasks](/guide/tasks) in the runtime panel.
-5. Read delivery state from [verification](/guide/verification) and
- [persistence](/guide/persistence).
-
-See
-[`COMPONENT_SPEC.md`](https://github.com/A3S-Lab/a3s/blob/main/apps/web/docs/COMPONENT_SPEC.md)
-for the component contract and
-[`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web) for source.
diff --git a/website/docs/v6/en/guide/security.mdx b/website/docs/v6/en/guide/security.mdx
index 4ef9acb..19ccaa0 100644
--- a/website/docs/v6/en/guide/security.mdx
+++ b/website/docs/v6/en/guide/security.mdx
@@ -21,7 +21,7 @@ policy.
`PermissionDecision` should explain the operation, reason, scope, and risk—not
just present two buttons. You can interact with it in the
-[Confirm step of the Web Playground](/guide/playground/web).
+[interactive PermissionDecision example](/guide/components/web/permissions).
## Enforced Execution Boundary
diff --git a/website/docs/v6/en/guide/sessions.mdx b/website/docs/v6/en/guide/sessions.mdx
index 407477f..55dedbd 100644
--- a/website/docs/v6/en/guide/sessions.mdx
+++ b/website/docs/v6/en/guide/sessions.mdx
@@ -8,7 +8,7 @@ description: 'Creating, streaming, resuming, and saving workspace-bound sessions
`Agent` owns configuration and provider state. `Session` binds that agent to one workspace and one conversation lifecycle.
This is where UI integration usually begins. The
-[A3S Web Playground](/guide/playground/web) shows how `ExecutionStream`
+[A3S Web execution components](/guide/components/web/execution) show how `ExecutionStream`
presents session events as task progress.
```ts
diff --git a/website/docs/v6/en/guide/tasks.mdx b/website/docs/v6/en/guide/tasks.mdx
index 828d164..dda43fb 100644
--- a/website/docs/v6/en/guide/tasks.mdx
+++ b/website/docs/v6/en/guide/tasks.mdx
@@ -14,7 +14,7 @@ high-confidence work, and disable only automatic parallel fan-out with
Web clients can present these states with `TaskRuntimePlanList` and
`TaskRuntimeSubagentList`. The
-[Web Playground](/guide/playground/web) shows the matching runtime-panel layout.
+[coordination components](/guide/components/web/coordination) show the matching plan and subagent layout.
## Built-in Subagents
diff --git a/website/docs/v6/en/guide/tools.mdx b/website/docs/v6/en/guide/tools.mdx
index 202328f..3cd2451 100644
--- a/website/docs/v6/en/guide/tools.mdx
+++ b/website/docs/v6/en/guide/tools.mdx
@@ -11,8 +11,8 @@ set plus session-level integrations, so a non-local workspace can intentionally
hide tools it cannot service.
To see tool events in a UI first, open the Run step in the
-[A3S Web Playground](/guide/playground/web) or the Run scene in the
-[TUI Playground](/guide/playground/tui).
+[A3S Web execution components](/guide/components/web/execution) or
+`ToolLogView` in the [TUI data components](/guide/components/tui/data).
## Tool Surface
diff --git a/website/docs/v6/en/guide/tui.mdx b/website/docs/v6/en/guide/tui.mdx
index 7265216..65aa7b1 100644
--- a/website/docs/v6/en/guide/tui.mdx
+++ b/website/docs/v6/en/guide/tui.mdx
@@ -15,8 +15,8 @@ Use the TUI when you want the ready coding-agent product in a terminal. Use
runner, IDE bridge, or controlled product surface.
:::tip See the UI first
-The [TUI Playground](/guide/playground/tui) lets you switch all four themes and
-inspect run, diff, file-tree, and component views without installing the CLI.
+The [TUI component docs](/guide/components/tui/) isolate run, diff, file-tree,
+and feedback controls without requiring the CLI.
:::
## Surface Map
diff --git a/website/docs/v6/en/guide/verification.mdx b/website/docs/v6/en/guide/verification.mdx
index 42c921c..e1f905c 100644
--- a/website/docs/v6/en/guide/verification.mdx
+++ b/website/docs/v6/en/guide/verification.mdx
@@ -18,7 +18,7 @@ exit status and output, and rolls every report up into a single summary that
travels alongside the turn result.
Product UIs can place the summary in `DeliverySummary` and file-level results in
-`ChangesInspector`. The [Web Playground result view](/guide/playground/web)
+`ChangesInspector`. The [Web result components](/guide/components/web/results)
shows that composition.
## Running Verification Commands
diff --git a/website/docs/v6/zh/_nav.json b/website/docs/v6/zh/_nav.json
index 4d76d68..6100f63 100644
--- a/website/docs/v6/zh/_nav.json
+++ b/website/docs/v6/zh/_nav.json
@@ -2,12 +2,12 @@
{
"text": "文档",
"link": "/guide/",
- "activeMatch": "^/guide/(?!examples/|playground/)"
+ "activeMatch": "^/guide/(?!examples/|components/)"
},
{
- "text": "Playground",
- "link": "/guide/playground/",
- "activeMatch": "^/guide/playground/"
+ "text": "组件",
+ "link": "/guide/components/",
+ "activeMatch": "^/guide/components/"
},
{
"text": "示例",
diff --git a/website/docs/v6/zh/api/index.mdx b/website/docs/v6/zh/api/index.mdx
index 0e55ef8..bec2b29 100644
--- a/website/docs/v6/zh/api/index.mdx
+++ b/website/docs/v6/zh/api/index.mdx
@@ -42,4 +42,4 @@ python -m pip install a3s-code
接入自己的基础设施时,可以替换 `LlmClient`、`ContextProvider`、
`MemoryStore`、`SessionStore`、Workspace 服务、工具、权限确认、Hook、MCP
Transport 和 Graph Store。想先看事件怎样进入界面,可以打开
-[A3S TUI 与 Web Playground](/guide/playground/)。
+[A3S TUI 与 A3S Web 组件文档](/guide/components/)。
diff --git a/website/docs/v6/zh/guide/_meta.json b/website/docs/v6/zh/guide/_meta.json
index c31b5e7..9786726 100644
--- a/website/docs/v6/zh/guide/_meta.json
+++ b/website/docs/v6/zh/guide/_meta.json
@@ -3,8 +3,8 @@
"tui",
{
"type": "dir",
- "name": "playground",
- "label": "Playground",
+ "name": "components",
+ "label": "组件",
"collapsible": true,
"collapsed": false
},
diff --git a/website/docs/v6/zh/guide/components/_meta.json b/website/docs/v6/zh/guide/components/_meta.json
new file mode 100644
index 0000000..bf7113a
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/_meta.json
@@ -0,0 +1,17 @@
+[
+ "index",
+ {
+ "type": "dir",
+ "name": "tui",
+ "label": "A3S TUI",
+ "collapsible": true,
+ "collapsed": false
+ },
+ {
+ "type": "dir",
+ "name": "web",
+ "label": "A3S Web",
+ "collapsible": true,
+ "collapsed": false
+ }
+]
diff --git a/website/docs/v6/zh/guide/components/index.mdx b/website/docs/v6/zh/guide/components/index.mdx
new file mode 100644
index 0000000..fdd8f7f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/index.mdx
@@ -0,0 +1,28 @@
+---
+title: '组件'
+description: '逐个查看并操作 A3S TUI 与 A3S Web 的核心组件'
+---
+
+# 组件
+
+这里不演示一条拼好的任务流程。每个示例只放一个组件,并把它最重要的状态单独露出来。
+你可以改输入、切状态、做选择,直接看组件怎样响应。
+
+| 组件库 | 文档 |
+| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| A3S TUI | [执行状态](/guide/components/tui/activity)、[输入与确认](/guide/components/tui/input)、[导航](/guide/components/tui/navigation)、[数据与改动](/guide/components/tui/data)、[反馈](/guide/components/tui/feedback) |
+| A3S Web | [任务输入](/guide/components/web/tasks)、[执行流](/guide/components/web/execution)、[权限与恢复](/guide/components/web/permissions)、[任务协调](/guide/components/web/coordination)、[结果](/guide/components/web/results)、[工作区](/guide/components/web/workspace) |
+
+## 它们在 Agent 的哪个阶段出现
+
+
+
+上图按一次任务的顺序整理 Runtime 能力;组件页则回答更具体的问题:这一条事件、一次确认
+或一份结果,应该怎样呈现给用户。
+
+## 示例范围
+
+- 所有交互只改变当前页面的 React 状态,不会连接模型、运行命令或修改文件。
+- 示例按文档宽度重绘,重点是状态与交互,不代替正式产品。
+- TUI 实现以 [`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI) 为准。
+- Web 实现以 [`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web) 为准。
diff --git a/website/docs/v6/zh/guide/components/tui/_meta.json b/website/docs/v6/zh/guide/components/tui/_meta.json
new file mode 100644
index 0000000..fd7d11f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/_meta.json
@@ -0,0 +1 @@
+["index", "activity", "input", "navigation", "data", "feedback"]
diff --git a/website/docs/v6/zh/guide/components/tui/activity.mdx b/website/docs/v6/zh/guide/components/tui/activity.mdx
new file mode 100644
index 0000000..bee7f7f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/activity.mdx
@@ -0,0 +1,20 @@
+---
+title: '执行状态'
+description: '单独操作 ActivityBlock 与 Checklist'
+---
+
+# 执行状态
+
+## ActivityBlock
+
+一项推理或工具活动的摘要。切换等待、执行中、完成和失败状态,再点击主体展开日志。
+
+
+
+## Checklist
+
+计划项的状态列表。点击任意一项,会在待处理、进行中和完成之间循环。
+
+
+
+这两类组件通常分别接收工具事件与 Plan 更新;它们只负责显示状态,不负责调度任务。
diff --git a/website/docs/v6/zh/guide/components/tui/data.mdx b/website/docs/v6/zh/guide/components/tui/data.mdx
new file mode 100644
index 0000000..8fe943f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/data.mdx
@@ -0,0 +1,24 @@
+---
+title: '数据与改动'
+description: '单独操作 DataTable、DiffView 与 ToolLogView'
+---
+
+# 数据与改动
+
+## DataTable
+
+适合工具调用、Run 或 Artifact 这类结构化数据。可以切换排序字段并选择一行。
+
+
+
+## DiffView
+
+展示文件改动。示例支持统一与分栏视图,也可以显示空白字符。
+
+
+
+## ToolLogView
+
+按工具调用组织输出。可以只看活动项,也可以展开单次调用的结果。
+
+
diff --git a/website/docs/v6/zh/guide/components/tui/feedback.mdx b/website/docs/v6/zh/guide/components/tui/feedback.mdx
new file mode 100644
index 0000000..6798d8f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/feedback.mdx
@@ -0,0 +1,30 @@
+---
+title: '反馈'
+description: '单独操作 Alert、Progress、Toast 与 SessionStatus'
+---
+
+# 反馈
+
+## Alert
+
+信息、成功、警告与错误使用不同语义色,但保持同一布局。
+
+
+
+## Progress
+
+可暂停的进度显示。拖动滑块可以检查任意完成比例。
+
+
+
+## Toast
+
+不遮挡当前终端内容的短反馈,可触发或关闭。
+
+
+
+## SessionStatus
+
+集中显示工作模式、模型配置、上下文占用与快捷键。
+
+
diff --git a/website/docs/v6/zh/guide/components/tui/index.mdx b/website/docs/v6/zh/guide/components/tui/index.mdx
new file mode 100644
index 0000000..84d8be2
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/index.mdx
@@ -0,0 +1,20 @@
+---
+title: 'A3S TUI 组件'
+description: 'A3S TUI 的执行、输入、导航、数据与反馈组件'
+---
+
+# A3S TUI 组件
+
+A3S TUI 把 `AgentEvent`、任务计划、工具日志、Diff 和 Session 状态放进终端。下面按用途
+拆开,不要求先理解整套页面布局。
+
+| 分类 | 组件 |
+| ------------------------------------------ | --------------------------------------------- |
+| [执行状态](/guide/components/tui/activity) | `ActivityBlock`、`Checklist` |
+| [输入与确认](/guide/components/tui/input) | `ChoicePrompt`、`Confirm`、`TextInput` |
+| [导航](/guide/components/tui/navigation) | `Tabs`、`TreePicker` |
+| [数据与改动](/guide/components/tui/data) | `DataTable`、`DiffView`、`ToolLogView` |
+| [反馈](/guide/components/tui/feedback) | `Alert`、`Progress`、`Toast`、`SessionStatus` |
+
+完整导出列表见
+[`src/components/mod.rs`](https://github.com/A3S-Lab/TUI/blob/main/src/components/mod.rs)。
diff --git a/website/docs/v6/zh/guide/components/tui/input.mdx b/website/docs/v6/zh/guide/components/tui/input.mdx
new file mode 100644
index 0000000..17581c3
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/input.mdx
@@ -0,0 +1,24 @@
+---
+title: '输入与确认'
+description: '单独操作 ChoicePrompt、Confirm 与 TextInput'
+---
+
+# 输入与确认
+
+## ChoicePrompt
+
+用于少量、互斥的选择。点击选项可以直接观察焦点项和选中项的样式。
+
+
+
+## Confirm
+
+承接 Runtime 的人工确认请求。允许和拒绝都只改变当前示例的结果。
+
+
+
+## TextInput
+
+单行指令输入,包含长度、空值与提交提示。
+
+
diff --git a/website/docs/v6/zh/guide/components/tui/navigation.mdx b/website/docs/v6/zh/guide/components/tui/navigation.mdx
new file mode 100644
index 0000000..bc1799f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/tui/navigation.mdx
@@ -0,0 +1,18 @@
+---
+title: '导航'
+description: '单独操作 Tabs 与 TreePicker'
+---
+
+# 导航
+
+## Tabs
+
+在 Transcript、Changes 与 Artifacts 之间切换,不丢失当前 Session。
+
+
+
+## TreePicker
+
+展开目录并勾选要放进上下文的文件。文件选择和目录展开是两套独立状态。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/_meta.json b/website/docs/v6/zh/guide/components/web/_meta.json
new file mode 100644
index 0000000..1c0c0a8
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/_meta.json
@@ -0,0 +1,9 @@
+[
+ "index",
+ "tasks",
+ "execution",
+ "permissions",
+ "coordination",
+ "results",
+ "workspace"
+]
diff --git a/website/docs/v6/zh/guide/components/web/coordination.mdx b/website/docs/v6/zh/guide/components/web/coordination.mdx
new file mode 100644
index 0000000..68a1c15
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/coordination.mdx
@@ -0,0 +1,18 @@
+---
+title: '任务协调'
+description: '单独操作计划列表与子 Agent 列表'
+---
+
+# 任务协调
+
+## TaskRuntimePlanList
+
+显示当前计划与完成比例。点击条目可以循环它的状态。
+
+
+
+## TaskRuntimeSubagentList
+
+显示子 Agent 的状态和进度。选择一项不会取消或重启任务。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/execution.mdx b/website/docs/v6/zh/guide/components/web/execution.mdx
new file mode 100644
index 0000000..477717e
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/execution.mdx
@@ -0,0 +1,24 @@
+---
+title: '执行流'
+description: '单独操作 ExecutionStream、ReasoningDisclosure 与 ToolCallTimeline'
+---
+
+# 执行流
+
+## ExecutionStream
+
+按发生顺序接收并追加 Runtime 事件。点击 `next event` 可以逐条加入事件。
+
+
+
+## ReasoningDisclosure
+
+推理摘要可以折叠,并区分直播中与已结束。
+
+
+
+## ToolCallTimeline
+
+一次工具调用的状态、命令与输出。切状态或展开结果都不会影响其他组件。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/index.mdx b/website/docs/v6/zh/guide/components/web/index.mdx
new file mode 100644
index 0000000..e65f2bc
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/index.mdx
@@ -0,0 +1,21 @@
+---
+title: 'A3S Web 组件'
+description: 'A3S Web 的任务、执行、权限、协调、结果与工作区组件'
+---
+
+# A3S Web 组件
+
+A3S Web 使用 Runtime 的 Session、事件流、权限请求、Artifact 与 Memory 数据。这里按
+职责拆开查看,不再把所有组件塞进一条固定流程。
+
+| 分类 | 组件 |
+| ----------------------------------------------- | ------------------------------------------------------------ |
+| [任务输入](/guide/components/web/tasks) | `TaskComposer`、`TaskLibrary` |
+| [执行流](/guide/components/web/execution) | `ExecutionStream`、`ReasoningDisclosure`、`ToolCallTimeline` |
+| [权限与恢复](/guide/components/web/permissions) | `PermissionDecision`、`RecoveryNotice` |
+| [任务协调](/guide/components/web/coordination) | `TaskRuntimePlanList`、`TaskRuntimeSubagentList` |
+| [结果](/guide/components/web/results) | `DeliverySummary`、`ArtifactEntries`、`ChangesInspector` |
+| [工作区](/guide/components/web/workspace) | `WorkspaceEditor`、`MemoryGraph` |
+
+完整组件边界见
+[`apps/web/docs/COMPONENT_SPEC.md`](https://github.com/A3S-Lab/a3s/blob/main/apps/web/docs/COMPONENT_SPEC.md)。
diff --git a/website/docs/v6/zh/guide/components/web/permissions.mdx b/website/docs/v6/zh/guide/components/web/permissions.mdx
new file mode 100644
index 0000000..565b2a1
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/permissions.mdx
@@ -0,0 +1,18 @@
+---
+title: '权限与恢复'
+description: '单独操作 PermissionDecision 与 RecoveryNotice'
+---
+
+# 权限与恢复
+
+## PermissionDecision
+
+把操作、范围与决定放在同一个确认面板中。允许或拒绝后仍可重置。
+
+
+
+## RecoveryNotice
+
+Session 中断后的恢复入口。可以忽略提示,也可以进入恢复状态。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/results.mdx b/website/docs/v6/zh/guide/components/web/results.mdx
new file mode 100644
index 0000000..2ab8631
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/results.mdx
@@ -0,0 +1,24 @@
+---
+title: '结果'
+description: '单独操作 DeliverySummary、ArtifactEntries 与 ChangesInspector'
+---
+
+# 结果
+
+## DeliverySummary
+
+把完成状态、验证结果和改动摘要放在一起,详情可以展开。
+
+
+
+## ArtifactEntries
+
+选择一次 Run 生成的 Artifact,并查看类型、大小和 URI。
+
+
+
+## ChangesInspector
+
+选择文件并切换统一或分栏 Diff。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/tasks.mdx b/website/docs/v6/zh/guide/components/web/tasks.mdx
new file mode 100644
index 0000000..7f2eb2f
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/tasks.mdx
@@ -0,0 +1,18 @@
+---
+title: '任务输入'
+description: '单独操作 TaskComposer 与 TaskLibrary'
+---
+
+# 任务输入
+
+## TaskComposer
+
+任务输入、上下文入口、模式和推理强度放在一个组件里。可以改文字、切换模式并提交。
+
+
+
+## TaskLibrary
+
+最近任务的筛选与选择。搜索不会改变当前选中的任务。
+
+
diff --git a/website/docs/v6/zh/guide/components/web/workspace.mdx b/website/docs/v6/zh/guide/components/web/workspace.mdx
new file mode 100644
index 0000000..45e6121
--- /dev/null
+++ b/website/docs/v6/zh/guide/components/web/workspace.mdx
@@ -0,0 +1,18 @@
+---
+title: '工作区'
+description: '单独操作 WorkspaceEditor 与 MemoryGraph'
+---
+
+# 工作区
+
+## WorkspaceEditor
+
+切换文件、编辑一行内容,并观察未保存状态。
+
+
+
+## MemoryGraph
+
+在关系图和时间线之间切换。图模式下可以选择记忆节点。
+
+
diff --git a/website/docs/v6/zh/guide/index.mdx b/website/docs/v6/zh/guide/index.mdx
index 30f5cd2..95821d5 100644
--- a/website/docs/v6/zh/guide/index.mdx
+++ b/website/docs/v6/zh/guide/index.mdx
@@ -151,7 +151,7 @@ await agent.close();
## 接着看
-- [Playground](/guide/playground/) 展示 A3S TUI、A3S Web,以及任务各阶段会用到的组件。
+- [组件文档](/guide/components/) 可以逐个操作 A3S TUI 与 A3S Web 的核心组件。
- [A3S Code TUI](/guide/tui) 说明安装、配置发现、斜杠命令和 Effort。
- [文件系统优先](/guide/filesystem-first) 介绍 `AGENTS.md`、ACL、AgentDir、Skill、工具和定时任务。
- [API 契约](/guide/api-contract) 列出经过集成测试的 Node.js API。
diff --git a/website/docs/v6/zh/guide/persistence.mdx b/website/docs/v6/zh/guide/persistence.mdx
index eb7f659..952cd0b 100644
--- a/website/docs/v6/zh/guide/persistence.mdx
+++ b/website/docs/v6/zh/guide/persistence.mdx
@@ -8,7 +8,7 @@ description: '保存与恢复 session'
持久化让 session 可以跨进程恢复,也让产品界面拥有稳定 session ID。
恢复后的 Session 可以重新填充任务列表、执行记录和交付摘要。
-[Playground](/guide/playground/) 展示了 TUI 与 Web 分别怎样安排这些信息。
+[结果组件](/guide/components/web/results) 展示了 Web 怎样安排 Artifact、改动和交付摘要。
A3S Code 会持久化三种相关但不同的对象:
diff --git a/website/docs/v6/zh/guide/playground/_meta.json b/website/docs/v6/zh/guide/playground/_meta.json
deleted file mode 100644
index 27bcc96..0000000
--- a/website/docs/v6/zh/guide/playground/_meta.json
+++ /dev/null
@@ -1 +0,0 @@
-["index", "tui", "web"]
diff --git a/website/docs/v6/zh/guide/playground/index.mdx b/website/docs/v6/zh/guide/playground/index.mdx
deleted file mode 100644
index 469992b..0000000
--- a/website/docs/v6/zh/guide/playground/index.mdx
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: '组件总览'
-description: '直接查看 A3S TUI、A3S Web 和构建编码 Agent 所需的主要组件'
----
-
-# Playground
-
-这里的预览直接由 MDX 渲染,可以点击、切换状态,也能跟随文档一起维护。它们不会
-连接模型或执行命令,适合在接入 SDK 前了解界面如何承接运行时事件。
-
-| 预览 | 可以查看什么 |
-| -------------------------------- | ------------------------------------------------------ |
-| [A3S TUI](/guide/playground/tui) | 主题、执行状态、Diff、文件树,以及常用终端组件 |
-| [A3S Web](/guide/playground/web) | 从任务输入、工具执行、权限确认到交付结果的完整界面流程 |
-
-## 构建 Agent 要用到哪些组件
-
-选择一个阶段,可以看到 A3S Code 已经提供的组件,以及它们在文档中的位置。
-
-
-
-这张图按一次任务的实际顺序排列:先定义 Agent 和项目规则,再准备上下文、开放工具、
-检查权限、拆分任务,最后把事件交给界面并保存结果。点击卡片可进入对应章节。
-
-## 预览与正式产品的区别
-
-- Playground 只切换本地 React 状态,不会调用 A3S Code API。
-- TUI 预览使用 `a3s-tui` 的组件名称、四套内置主题和实际终端布局。
-- Web 预览参照 `apps/web` 的任务流程和设计 Token,正式应用还会连接 Session、
- Workspace、Memory 与账号服务。
-- 组件实现以
- [`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI) 和
- [`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web)
- 源码为准。
diff --git a/website/docs/v6/zh/guide/playground/tui.mdx b/website/docs/v6/zh/guide/playground/tui.mdx
deleted file mode 100644
index e0c1474..0000000
--- a/website/docs/v6/zh/guide/playground/tui.mdx
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: 'A3S TUI Playground'
-description: '在文档中切换 A3S TUI 的主题、执行场景和终端组件'
----
-
-# A3S TUI Playground
-
-切换上方场景可以查看一次编码任务的执行状态、代码 Diff、Workspace 文件树和常用
-终端组件;右上角四个色块分别对应 Dark、Light、Catppuccin 和 Tokyo Night。
-任务清单和组件菜单也可以点击。
-
-
-
-## 预览里用了哪些组件
-
-| 场景 | 对应的 `a3s-tui` 组件 |
-| --------- | ------------------------------------------------------------------------ |
-| 执行 | `ActivityBlock`、`Checklist`、`TaskQueue`、`ToolStatusLine`、`StatusBar` |
-| 代码改动 | `DiffView`、`SectionHeader`、`GutterBlock`、`OutputBlock` |
-| Workspace | `SplitPane`、`Tree`、`Breadcrumb`、`PreviewPanel`、`Viewport` |
-| 组件浏览 | `MenuPanel`、`Tabs`、`DataTable`、`Progress`、`ChoicePrompt`、`Toast` |
-
-`a3s-tui` 还提供输入、弹窗、日志、指标、时间线和子 Agent 状态等组件。完整导出列表见
-[`src/components/mod.rs`](https://github.com/A3S-Lab/TUI/blob/main/src/components/mod.rs)。
-
-## 它怎样接收 A3S Code 事件
-
-`a3s code` 订阅 `AgentSession::stream()`。文本增量写入对话区,工具事件更新
-Activity 与 ToolLog,Plan 更新 Checklist,权限请求打开 Confirm,验证结果进入
-Output 和 Diff,Session 状态最终写入 StatusBar。
-
-```text
-AgentSession::stream()
- -> TextDelta -> transcript
- -> ToolCall* -> ActivityBlock / ToolLogView
- -> Plan* -> Checklist / TaskQueue
- -> PermissionAsk -> Confirm
- -> Verification* -> OutputBlock / DiffView
- -> End -> SessionStatus / StatusBar
-```
-
-预览采用文档尺寸重新排版,并不替代可运行的终端应用。安装和命令说明见
-[A3S Code TUI](/guide/tui),组件源码见
-[`A3S-Lab/TUI`](https://github.com/A3S-Lab/TUI)。
diff --git a/website/docs/v6/zh/guide/playground/web.mdx b/website/docs/v6/zh/guide/playground/web.mdx
deleted file mode 100644
index 4581382..0000000
--- a/website/docs/v6/zh/guide/playground/web.mdx
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: 'A3S Web Playground'
-description: '在文档中体验 A3S Web 从任务输入到权限确认和结果交付的界面流程'
----
-
-# A3S Web Playground
-
-输入框、执行记录、权限卡片和结果页都可以操作。点击“运行演示”,再进入确认步骤;
-允许后会看到交付摘要,拒绝则停在当前工具调用。
-
-
-
-## 一次任务会经过哪些界面
-
-| 阶段 | 主要组件 | 接收的数据 |
-| ---- | ---------------------------------------------------------------------------- | ----------------------------------------- |
-| 准备 | `NewTaskPreparation`、`TaskComposer`、`NewTaskWorkspaceControl` | 指令、文件、Skill、模型、模式和 Workspace |
-| 执行 | `ExecutionStream`、`ReasoningDisclosure`、`ToolCallTimeline` | 文本、推理、工具生命周期和输出 |
-| 确认 | `PermissionDecision` | 操作、原因、影响范围、风险和确认时限 |
-| 协作 | `TaskRuntimeFloatingPanel`、`TaskRuntimePlanList`、`TaskRuntimeSubagentList` | Plan、子任务及其结果 |
-| 交付 | `DeliverySummary`、`ChangesInspector`、`WorkspaceEditor` | 最终回复、验证状态、Artifact 和文件改动 |
-
-这些组件不是另一套 Agent Runtime。A3S Web 把 A3S Code 的 Session、Event、
-Permission 和 Workspace 数据投影成桌面界面;同一个后端也可以换成 TUI、IDE
-扩展或自己的前端。
-
-## 接入时从哪里开始
-
-1. 用 [Session](/guide/sessions) 创建任务,并订阅事件流。
-2. 按 [工具](/guide/tools) 的生命周期更新 `ToolCallTimeline`。
-3. 遇到 Ask 决策时,用 [权限与安全](/guide/security) 对接确认按钮。
-4. 把 [Plan 与子任务](/guide/tasks) 显示在运行面板。
-5. 从 [验证](/guide/verification) 和 [持久化](/guide/persistence) 读取交付状态。
-
-完整的组件约定见
-[`COMPONENT_SPEC.md`](https://github.com/A3S-Lab/a3s/blob/main/apps/web/docs/COMPONENT_SPEC.md),
-实现位于
-[`apps/web`](https://github.com/A3S-Lab/a3s/tree/main/apps/web)。
diff --git a/website/docs/v6/zh/guide/security.mdx b/website/docs/v6/zh/guide/security.mdx
index ea1395f..71725ef 100644
--- a/website/docs/v6/zh/guide/security.mdx
+++ b/website/docs/v6/zh/guide/security.mdx
@@ -10,7 +10,7 @@ A3S Code 在创建 session 时暴露安全控制,并通过 session hook 暴露
委派子运行会继承所选 subagent 或 worker spec 的有边界权限。使用 `confirmationInheritance` 控制子运行的 Ask 决策,并把高风险发布命令放在显式 policy 后面。
`PermissionDecision` 应该向用户说明操作、原因、影响范围和风险,而不只是放两个按钮。
-[Web Playground 的“确认”步骤](/guide/playground/web) 可以直接操作这个组件。
+[PermissionDecision 示例](/guide/components/web/permissions) 可以直接操作这个组件。
```ts
const session = agent.session('/repo', {
diff --git a/website/docs/v6/zh/guide/sessions.mdx b/website/docs/v6/zh/guide/sessions.mdx
index 99d71cd..010a550 100644
--- a/website/docs/v6/zh/guide/sessions.mdx
+++ b/website/docs/v6/zh/guide/sessions.mdx
@@ -7,7 +7,7 @@ description: '创建、流式输出、恢复和保存工作区绑定的 session'
`Agent` 持有配置和 provider 状态。`Session` 把这个 agent 绑定到一个工作区和一次对话生命周期。
-界面通常从这里开始接入:[A3S Web Playground](/guide/playground/web) 展示了
+界面通常从这里开始接入:[A3S Web 执行流组件](/guide/components/web/execution) 展示了
`ExecutionStream` 如何把 Session 事件显示成任务进度。
```ts
diff --git a/website/docs/v6/zh/guide/tasks.mdx b/website/docs/v6/zh/guide/tasks.mdx
index 5c87244..0bb9f27 100644
--- a/website/docs/v6/zh/guide/tasks.mdx
+++ b/website/docs/v6/zh/guide/tasks.mdx
@@ -12,7 +12,7 @@ specialist 子 agent 时启用它;如果只想让自动委派串行执行,
`autoParallel: false` 关闭自动并行 fan-out。
Web 界面可以用 `TaskRuntimePlanList` 和 `TaskRuntimeSubagentList` 展示这些状态。
-[Web Playground](/guide/playground/web) 中的执行面板给出了对应布局。
+[任务协调组件](/guide/components/web/coordination) 给出了计划与子 Agent 的对应布局。
## 内置 Subagents
diff --git a/website/docs/v6/zh/guide/tools.mdx b/website/docs/v6/zh/guide/tools.mdx
index c02b7f6..d5cfba9 100644
--- a/website/docs/v6/zh/guide/tools.mdx
+++ b/website/docs/v6/zh/guide/tools.mdx
@@ -9,8 +9,8 @@ A3S Code 会保留工具注册表。`toolNames()` 返回当前 session 的工具
workspace capability 与 session 级集成共同组装;因此非本地 workspace 可以有意隐藏它无法提供服务的工具。
想先看工具事件在界面中的效果,可以打开
-[A3S Web Playground](/guide/playground/web) 的“执行”步骤,或
-[TUI Playground](/guide/playground/tui) 的“执行”场景。
+[A3S Web 执行流组件](/guide/components/web/execution),或
+[TUI 数据组件](/guide/components/tui/data) 中的 `ToolLogView`。
## 工具表面
diff --git a/website/docs/v6/zh/guide/tui.mdx b/website/docs/v6/zh/guide/tui.mdx
index a7b3411..eddb44e 100644
--- a/website/docs/v6/zh/guide/tui.mdx
+++ b/website/docs/v6/zh/guide/tui.mdx
@@ -14,7 +14,7 @@ description: '安装、配置并使用 a3s code 终端应用'
server worker、workflow runner 或产品 UI 时使用 SDK 包。
:::tip 先看界面
-[TUI Playground](/guide/playground/tui) 可以切换四套主题,并查看执行、Diff、
+[TUI 组件文档](/guide/components/tui/) 可以逐个查看执行、Diff、
文件树和常用组件。不需要安装 CLI。
:::
diff --git a/website/docs/v6/zh/guide/verification.mdx b/website/docs/v6/zh/guide/verification.mdx
index 45cc5c7..dbb040f 100644
--- a/website/docs/v6/zh/guide/verification.mdx
+++ b/website/docs/v6/zh/guide/verification.mdx
@@ -12,7 +12,7 @@ import { Tab, Tabs } from '@rspress/core/theme';
验证是会话级的。Rust 核心运行每条命令,记录其退出状态和输出,并将每份报告汇总为一份随回合结果一同返回的摘要。
产品界面可以把摘要放进 `DeliverySummary`,把文件级结果放进
-`ChangesInspector`。[Web Playground 的结果页](/guide/playground/web) 展示了这种组合。
+`ChangesInspector`。[Web 结果组件](/guide/components/web/results) 展示了这种组合。
## 运行验证命令
diff --git a/website/package-lock.json b/website/package-lock.json
index 3dc949a..b2e791a 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -8,7 +8,8 @@
"name": "a3s-code-website",
"version": "0.0.0",
"dependencies": {
- "@rspress/core": "^2.0.17"
+ "@rspress/core": "^2.0.17",
+ "codehike": "^1.1.0"
},
"devDependencies": {
"@rslint/core": "^0.5.3",
@@ -21,6 +22,18 @@
"typescript": "^6.0.3"
}
},
+ "node_modules/@code-hike/lighter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@code-hike/lighter/-/lighter-1.0.1.tgz",
+ "integrity": "sha512-mccvcsk5UTScRrE02oBz1/qzckyhD8YE3VQlQv++2bSVVZgNuCUX8MpokSCi5OmfRAAxbj6kmNiqq1Um8eXPrw==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-sequence-parser": "1.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/code-hike"
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
@@ -827,6 +840,12 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/ansi-sequence-parser": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
+ "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
+ "license": "MIT"
+ },
"node_modules/astring": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
@@ -911,6 +930,23 @@
"node": ">=6"
}
},
+ "node_modules/codehike": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/codehike/-/codehike-1.1.0.tgz",
+ "integrity": "sha512-hOxqmTHjiOxhlcVEuDTCoAQ8TW358HVrNKlOwuKcnbwkuTpbGtwj5TnQ7AZjnZiQvJ3LeXohrd1E7qfYYN0Rdg==",
+ "license": "MIT",
+ "dependencies": {
+ "@code-hike/lighter": "1.0.1",
+ "diff": "^5.1.0",
+ "estree-util-visit": "^2.0.0",
+ "mdast-util-mdx-jsx": "^3.0.0",
+ "unist-util-visit": "^5.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/code-hike"
+ }
+ },
"node_modules/collapse-white-space": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
@@ -1017,6 +1053,15 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/diff": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
+ "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
diff --git a/website/package.json b/website/package.json
index bdd71ad..7a62ad3 100644
--- a/website/package.json
+++ b/website/package.json
@@ -9,13 +9,16 @@
"check:site": "node scripts/check-built-site.mjs",
"dev": "rspress dev",
"format": "prettier --write .",
+ "generate:tutorial": "node scripts/generate-runtime-tutorial.mjs",
"format:check": "prettier --check .",
"lint": "rslint && tsc --noEmit && node scripts/check-language-parity.mjs",
"normalize:docs": "node scripts/normalize-imported-docs.mjs",
+ "prebuild": "npm run generate:tutorial",
"preview": "rspress preview"
},
"dependencies": {
- "@rspress/core": "^2.0.17"
+ "@rspress/core": "^2.0.17",
+ "codehike": "^1.1.0"
},
"devDependencies": {
"@rslint/core": "^0.5.3",
diff --git a/website/rspress.config.ts b/website/rspress.config.ts
index 4d92811..4552f97 100644
--- a/website/rspress.config.ts
+++ b/website/rspress.config.ts
@@ -20,8 +20,7 @@ export default defineConfig({
markdown: {
globalComponents: [
path.join(__dirname, 'theme/components/AgentBuildingBlocks.tsx'),
- path.join(__dirname, 'theme/components/TuiPlayground.tsx'),
- path.join(__dirname, 'theme/components/WebPlayground.tsx'),
+ path.join(__dirname, 'theme/components/A3SComponentDemo.tsx'),
],
},
multiVersion: {
diff --git a/website/scripts/generate-runtime-tutorial.mjs b/website/scripts/generate-runtime-tutorial.mjs
new file mode 100644
index 0000000..b685d2a
--- /dev/null
+++ b/website/scripts/generate-runtime-tutorial.mjs
@@ -0,0 +1,354 @@
+import { mkdir, writeFile } from 'node:fs/promises';
+import { fileURLToPath } from 'node:url';
+import path from 'node:path';
+import { highlight } from 'codehike/code';
+import { format } from 'prettier';
+
+const here = path.dirname(fileURLToPath(import.meta.url));
+const outputPath = path.join(
+ here,
+ '..',
+ 'theme',
+ 'generated',
+ 'runtime-tutorial.json',
+);
+
+const theme = {
+ name: 'a3s-runtime',
+ type: 'dark',
+ colors: {
+ 'editor.background': '#0b0d11',
+ 'editor.foreground': '#c9ced8',
+ 'editorLineNumber.foreground': '#444b57',
+ 'editorLineNumber.activeForeground': '#8c96a7',
+ 'editor.selectionBackground': '#233653',
+ },
+ tokenColors: [
+ {
+ scope: ['comment', 'punctuation.definition.comment'],
+ settings: { foreground: '#626b78', fontStyle: 'italic' },
+ },
+ {
+ scope: [
+ 'keyword',
+ 'storage',
+ 'storage.type',
+ 'storage.modifier',
+ 'keyword.control',
+ ],
+ settings: { foreground: '#91acd8' },
+ },
+ {
+ scope: ['entity.name.function', 'support.function', 'meta.function-call'],
+ settings: { foreground: '#dfbd7c' },
+ },
+ {
+ scope: [
+ 'entity.name.type',
+ 'entity.name.class',
+ 'support.type',
+ 'support.class',
+ ],
+ settings: { foreground: '#b5a4d2' },
+ },
+ {
+ scope: ['string', 'string.quoted', 'string.template'],
+ settings: { foreground: '#91c4a6' },
+ },
+ {
+ scope: ['constant.numeric', 'constant.language', 'constant.character'],
+ settings: { foreground: '#d79d77' },
+ },
+ {
+ scope: [
+ 'variable.parameter',
+ 'variable.other',
+ 'meta.object-literal.key',
+ ],
+ settings: { foreground: '#cbd1da' },
+ },
+ {
+ scope: ['punctuation', 'meta.brace', 'meta.delimiter'],
+ settings: { foreground: '#7a8492' },
+ },
+ {
+ scope: ['keyword.operator', 'operator'],
+ settings: { foreground: '#7ea8b8' },
+ },
+ ],
+};
+
+const steps = [
+ {
+ id: 'surfaces',
+ layer: 'L01 / SURFACES',
+ filename: 'src/main.rs',
+ title: {
+ zh: '先选一个接入入口',
+ en: 'Choose an entry point',
+ },
+ body: {
+ zh: '终端可以直接跑;要嵌进产品,就从 Rust、Node.js 或 Python SDK 开始。下面用 Rust 把完整路径走一遍。',
+ en: 'Run the terminal app directly, or embed the Rust, Node.js, or Python SDK. The walkthrough below follows the Rust path.',
+ },
+ note: {
+ zh: '同一个 Runtime,不同的产品外壳。',
+ en: 'One runtime behind different product surfaces.',
+ },
+ tags: ['Terminal', 'Rust', 'Node.js', 'Python'],
+ focus: [1, 6],
+ code: `use a3s_code_core::{Agent, AgentEvent};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ Ok(())
+}`,
+ },
+ {
+ id: 'session',
+ layer: 'L02 / AGENT API',
+ filename: 'src/main.rs',
+ title: {
+ zh: '把 Agent 绑到一个项目',
+ en: 'Bind the agent to a project',
+ },
+ body: {
+ zh: 'Agent 读取 ACL 和共享能力;AgentSession 负责当前 Workspace 与这一段对话。异步 build 会在第一轮开始前准备好相关资源。',
+ en: 'Agent loads ACL and shared capabilities. AgentSession owns the current workspace and conversation, resolving resources before the first turn.',
+ },
+ note: {
+ zh: 'Agent 可以复用,Session 与 Workspace 一一对应。',
+ en: 'Reuse the Agent; bind each Session to a workspace.',
+ },
+ tags: ['Agent', 'AgentSession', 'Workspace'],
+ focus: [5, 8],
+ code: `use a3s_code_core::{Agent, AgentEvent};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ let agent = Agent::new("agent.acl").await?;
+ let session = agent
+ .session_builder(".")
+ .build()
+ .await?;
+
+ Ok(())
+}`,
+ },
+ {
+ id: 'context',
+ layer: 'L03 / INTELLIGENCE',
+ filename: 'src/main.rs',
+ title: {
+ zh: '给上下文设好边界',
+ en: 'Put a boundary around context',
+ },
+ body: {
+ zh: '自动压缩、token 上限和触发阈值属于 Session 配置,不需要藏进界面层。ContextAssembler 与 Memory 会据此准备模型输入。',
+ en: 'Compaction, token limits, and thresholds belong to SessionOptions rather than UI code. ContextAssembler and memory use them when preparing model input.',
+ },
+ note: {
+ zh: '大结果会变成 Artifact,模型只拿到受控预览。',
+ en: 'Large results become artifacts; the model receives a bounded preview.',
+ },
+ tags: ['ContextAssembler', 'Memory', 'LlmClient'],
+ focus: [6, 10],
+ code: `use a3s_code_core::{Agent, AgentEvent, SessionOptions};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ let options = SessionOptions::new()
+ .with_auto_compact(true)
+ .with_max_context_tokens(200_000)
+ .with_auto_compact_threshold(0.8);
+
+ let agent = Agent::new("agent.acl").await?;
+ let session = agent
+ .session_builder(".")
+ .options(options)
+ .build()
+ .await?;
+
+ Ok(())
+}`,
+ },
+ {
+ id: 'governance',
+ layer: 'L04 / GOVERNANCE',
+ filename: 'src/main.rs',
+ title: {
+ zh: '在工具执行前定规则',
+ en: 'Set policy before tools run',
+ },
+ body: {
+ zh: 'read 自动放行,write 每次询问,危险的 shell 命令直接拒绝。规则按 deny、allow、ask 的顺序求值。',
+ en: 'Allow reads, ask before writes, and deny a dangerous shell pattern. Rules evaluate in deny, allow, then ask order.',
+ },
+ note: {
+ zh: '权限、确认、预算与沙箱共用一条执行链。',
+ en: 'Permission, approval, budgets, and sandboxing share one path.',
+ },
+ tags: ['validate', 'permission', 'confirm', 'sandbox'],
+ focus: [8, 12],
+ code: `use a3s_code_core::{
+ permissions::PermissionPolicy,
+ Agent, AgentEvent, SessionOptions,
+};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ let policy = PermissionPolicy::new()
+ .allow("read(*)")
+ .ask("write(*)")
+ .deny("bash(rm:*)");
+
+ let options = SessionOptions::new()
+ .with_auto_compact(true)
+ .with_permission_policy(policy);
+
+ let agent = Agent::new("agent.acl").await?;
+ let session = agent
+ .session_builder(".")
+ .options(options)
+ .build()
+ .await?;
+
+ Ok(())
+}`,
+ },
+ {
+ id: 'tools',
+ layer: 'L05 / WORKSPACE',
+ filename: 'src/main.rs',
+ title: {
+ zh: '让 Workspace 决定可用工具',
+ en: 'Let the workspace expose its tools',
+ },
+ body: {
+ zh: 'Session 只注册当前 Workspace 真正支持、且权限允许的工具。发起 stream 后,模型调用 read、search、shell 或 Git 都会经过同一条受控路径。',
+ en: 'A Session registers only tools the current workspace supports and policy permits. Every read, search, shell, or Git call follows the same governed path.',
+ },
+ note: {
+ zh: '对象存储后端不支持本地命令时,Bash 与 Git 不会出现。',
+ en: 'If a workspace cannot run local commands, Bash and Git stay hidden.',
+ },
+ tags: ['files', 'search', 'shell', 'git', 'MCP'],
+ focus: [23, 26],
+ code: `use a3s_code_core::{
+ permissions::PermissionPolicy,
+ Agent, AgentEvent, SessionOptions,
+};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ let policy = PermissionPolicy::new()
+ .allow("read(*)")
+ .ask("write(*)")
+ .deny("bash(rm:*)");
+
+ let options = SessionOptions::new()
+ .with_auto_compact(true)
+ .with_permission_policy(policy);
+
+ let agent = Agent::new("agent.acl").await?;
+ let session = agent
+ .session_builder(".")
+ .options(options)
+ .build()
+ .await?;
+
+ let (mut events, lifecycle) = session
+ .stream("Find the authentication entry points.", None)
+ .await?;
+
+ Ok(())
+}`,
+ },
+ {
+ id: 'evidence',
+ layer: 'L06 / DURABILITY',
+ filename: 'src/main.rs',
+ title: {
+ zh: '把过程交给界面,把现场留给下一次',
+ en: 'Stream the run and keep the evidence',
+ },
+ body: {
+ zh: '界面消费 AgentEvent;配置 SessionStore 后,save 会把会话、运行记录、Artifact、Trace 和验证结果作为同一代快照提交。',
+ en: 'The UI consumes AgentEvent. With a SessionStore configured, save commits the session, runs, artifacts, traces, and verification data as one snapshot generation.',
+ },
+ note: {
+ zh: '终端、Web 与 SDK 看到的是同一条事件协议。',
+ en: 'Terminal, Web, and SDK clients share the same event protocol.',
+ },
+ tags: ['AgentEvent', 'Run', 'Artifact', 'Snapshot'],
+ focus: [29, 39],
+ code: `use a3s_code_core::{
+ permissions::PermissionPolicy,
+ Agent, AgentEvent, SessionOptions,
+};
+
+#[tokio::main]
+async fn main() -> a3s_code_core::Result<()> {
+ let policy = PermissionPolicy::new()
+ .allow("read(*)")
+ .ask("write(*)")
+ .deny("bash(rm:*)");
+
+ let options = SessionOptions::new()
+ .with_auto_compact(true)
+ .with_permission_policy(policy)
+ .with_file_session_store(".a3s/sessions");
+
+ let agent = Agent::new("agent.acl").await?;
+ let session = agent
+ .session_builder(".")
+ .options(options)
+ .build()
+ .await?;
+
+ let (mut events, lifecycle) = session
+ .stream("Find the authentication entry points.", None)
+ .await?;
+
+ while let Some(event) = events.recv().await {
+ match event {
+ AgentEvent::TextDelta { text } => print!("{text}"),
+ AgentEvent::End { .. } => break,
+ _ => {}
+ }
+ }
+
+ let _ = lifecycle.await;
+ session.save().await?;
+ Ok(())
+}`,
+ },
+];
+
+const result = [];
+for (const step of steps) {
+ const highlighted = await highlight(
+ {
+ value: step.code,
+ lang: 'rust',
+ meta: step.filename,
+ },
+ theme,
+ );
+ highlighted.annotations = [
+ {
+ name: 'focus',
+ query: step.id,
+ fromLineNumber: step.focus[0],
+ toLineNumber: step.focus[1],
+ },
+ ];
+ result.push({
+ ...step,
+ highlighted,
+ });
+}
+
+await mkdir(path.dirname(outputPath), { recursive: true });
+const output = await format(JSON.stringify(result), { parser: 'json' });
+await writeFile(outputPath, output, 'utf8');
diff --git a/website/theme/component-docs.css b/website/theme/component-docs.css
new file mode 100644
index 0000000..b10ded1
--- /dev/null
+++ b/website/theme/component-docs.css
@@ -0,0 +1,2130 @@
+.a3s-component-demo,
+.a3s-component-demo * {
+ box-sizing: border-box;
+}
+
+.a3s-component-demo {
+ overflow: hidden;
+ margin: 24px 0 52px;
+ border: 1px solid #323640;
+ border-radius: 3px;
+ background: #0d0f13;
+ color: #e8ebf1;
+ box-shadow: 0 22px 58px rgba(0, 0, 0, 0.2);
+}
+
+.a3s-component-demo button,
+.a3s-component-demo input,
+.a3s-component-demo textarea {
+ font: inherit;
+}
+
+.a3s-component-demo button:focus-visible,
+.a3s-component-demo input:focus-visible,
+.a3s-component-demo textarea:focus-visible {
+ outline: 2px solid #b9d1fa;
+ outline-offset: 2px;
+}
+
+.a3s-component-demo-header {
+ display: grid;
+ min-height: 48px;
+ padding: 0 16px;
+ border-bottom: 1px solid #2b2f37;
+ background: #101217;
+ align-items: center;
+ grid-template-columns: 1fr auto 1fr;
+}
+
+.a3s-component-demo-header > span {
+ display: flex;
+ color: #737c89;
+ align-items: center;
+ gap: 8px;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.09em;
+}
+
+.a3s-component-demo-header > span i {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: #3ccf91;
+ box-shadow: 0 0 10px rgba(60, 207, 145, 0.6);
+}
+
+.a3s-component-demo-header strong {
+ color: #dce1e9;
+ font-family: var(--a3s-mono);
+ font-size: 11px;
+ font-weight: 650;
+}
+
+.a3s-component-demo-header small {
+ color: #525a67;
+ justify-self: end;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.1em;
+}
+
+.a3s-component-demo-stage {
+ display: flex;
+ min-height: 510px;
+ padding: 30px;
+ background:
+ linear-gradient(rgba(108, 163, 255, 0.035) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(108, 163, 255, 0.035) 1px, transparent 1px),
+ radial-gradient(
+ circle at 50% 20%,
+ rgba(68, 109, 167, 0.11),
+ transparent 48%
+ ),
+ #0c0e12;
+ background-size:
+ 28px 28px,
+ 28px 28px,
+ auto,
+ auto;
+ align-items: center;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.a3s-component-demo > footer {
+ display: flex;
+ min-height: 40px;
+ padding: 0 14px;
+ border-top: 1px solid #2b2f37;
+ background: #101217;
+ color: #515966;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 7px;
+ letter-spacing: 0.07em;
+}
+
+.a3s-demo-controls {
+ display: flex;
+ width: min(100%, 760px);
+ min-height: 40px;
+ margin-bottom: 12px;
+ padding: 5px;
+ border: 1px solid #30353f;
+ background: rgba(15, 17, 22, 0.96);
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 5px;
+}
+
+.a3s-demo-controls button {
+ min-height: 28px;
+ padding: 0 10px;
+ border: 1px solid transparent;
+ background: transparent;
+ color: #747d8b;
+ cursor: pointer;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ text-transform: uppercase;
+}
+
+.a3s-demo-controls button:hover {
+ background: #181b22;
+ color: #c9d0da;
+}
+
+.a3s-demo-controls button.is-active {
+ border-color: #47658e;
+ background: #151b25;
+ color: #bdd3f5;
+}
+
+.a3s-demo-controls > span {
+ margin-left: auto;
+ padding: 0 8px;
+ color: #59616d;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-demo-controls input[type='range'] {
+ width: 150px;
+ accent-color: #6ca3ff;
+}
+
+.a3s-demo-controls input:not([type='range']) {
+ min-width: 180px;
+ min-height: 28px;
+ padding: 0 9px;
+ border: 1px solid #333944;
+ background: #0c0e12;
+ color: #cbd1da;
+ font-size: 10px;
+}
+
+/* TUI surface */
+
+.a3s-demo-tui-window {
+ --demo-blue: #6ca3ff;
+ --demo-green: #46d39a;
+ --demo-amber: #efb354;
+ --demo-red: #ef767a;
+ display: grid;
+ overflow: hidden;
+ width: min(100%, 760px);
+ min-height: 350px;
+ border: 1px solid #363c48;
+ background: #090b10;
+ box-shadow:
+ 0 28px 65px rgba(0, 0, 0, 0.38),
+ inset 0 0 0 1px rgba(255, 255, 255, 0.018);
+ grid-template-rows: 32px minmax(270px, 1fr) 28px;
+}
+
+.a3s-demo-tui-window > header,
+.a3s-demo-tui-window > footer {
+ display: flex;
+ padding: 0 11px;
+ background: #11141a;
+ color: #626c7a;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 7px;
+ letter-spacing: 0.07em;
+}
+
+.a3s-demo-tui-window > header {
+ border-bottom: 1px solid #292f39;
+}
+
+.a3s-demo-tui-window > header > span:first-child {
+ color: #9fb8dd;
+}
+
+.a3s-demo-tui-window > footer {
+ border-top: 1px solid #292f39;
+ color: #556171;
+}
+
+.a3s-demo-tui-body {
+ display: flex;
+ min-width: 0;
+ padding: 26px;
+ align-items: center;
+ justify-content: center;
+}
+
+.a3s-tui-activity-block {
+ display: grid;
+ width: min(100%, 590px);
+ min-height: 64px;
+ padding: 10px 13px;
+ border: 1px solid #323a47;
+ background: #10141a;
+ color: #aeb7c4;
+ cursor: pointer;
+ align-items: center;
+ gap: 11px;
+ grid-template-columns: 18px minmax(0, 1fr) 18px;
+ text-align: left;
+}
+
+.a3s-tui-activity-block > span:first-child {
+ color: var(--demo-blue);
+ font-family: var(--a3s-mono);
+}
+
+.a3s-tui-activity-block.is-success > span:first-child {
+ color: var(--demo-green);
+}
+
+.a3s-tui-activity-block.is-error > span:first-child {
+ color: var(--demo-red);
+}
+
+.a3s-tui-activity-block > span:nth-child(2) {
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.a3s-tui-activity-block strong {
+ overflow: hidden;
+ color: #e0e5ed;
+ font-family: var(--a3s-mono);
+ font-size: 11px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-tui-activity-block small {
+ color: #687483;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-activity-block i {
+ color: #56606e;
+ font-style: normal;
+}
+
+.a3s-tui-activity-detail {
+ width: min(100%, 590px);
+ padding: 14px 17px 10px 41px;
+ border-right: 1px solid #2f3540;
+ border-bottom: 1px solid #2f3540;
+ border-left: 1px solid #2f3540;
+ background: #0d1015;
+}
+
+.a3s-tui-activity-detail p {
+ margin: 0 0 10px;
+ color: #7f8997;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-activity-detail p > span {
+ display: inline-block;
+ width: 18px;
+ color: var(--demo-green);
+}
+
+.a3s-tui-activity-detail p.is-running > span {
+ color: var(--demo-amber);
+}
+
+.a3s-tui-activity-detail code {
+ color: #b8c2d0;
+}
+
+.a3s-tui-checklist-demo,
+.a3s-tui-choice,
+.a3s-tui-confirm,
+.a3s-tui-input-demo,
+.a3s-tui-tabs-demo,
+.a3s-tui-tree-demo,
+.a3s-tui-log-demo,
+.a3s-tui-progress-demo {
+ width: min(100%, 590px);
+}
+
+.a3s-tui-checklist-demo > header,
+.a3s-tui-log-demo > header {
+ display: flex;
+ padding: 0 5px 11px;
+ border-bottom: 1px solid #303641;
+ color: #9aa4b2;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-checklist-demo > button {
+ display: grid;
+ width: 100%;
+ min-height: 48px;
+ padding: 0 9px;
+ border: 0;
+ border-bottom: 1px solid #222831;
+ background: transparent;
+ color: #a6afbb;
+ cursor: pointer;
+ align-items: center;
+ gap: 10px;
+ grid-template-columns: 18px minmax(0, 1fr) auto;
+ text-align: left;
+}
+
+.a3s-tui-checklist-demo > button:hover {
+ background: #11151c;
+}
+
+.a3s-tui-checklist-demo > button > span:first-child {
+ color: #687381;
+ font-family: var(--a3s-mono);
+}
+
+.a3s-tui-checklist-demo > button.is-done > span:first-child {
+ color: var(--demo-green);
+}
+
+.a3s-tui-checklist-demo > button.is-doing > span:first-child {
+ color: var(--demo-amber);
+}
+
+.a3s-tui-checklist-demo > button.is-done > span:nth-child(2) {
+ color: #6f7885;
+ text-decoration: line-through;
+}
+
+.a3s-tui-checklist-demo > button small {
+ color: #4e5763;
+ font-family: var(--a3s-mono);
+ font-size: 7px;
+ text-transform: uppercase;
+}
+
+.a3s-tui-choice > span,
+.a3s-tui-confirm > span,
+.a3s-tui-input-demo > label {
+ color: #7093c3;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.09em;
+}
+
+.a3s-tui-choice h4,
+.a3s-tui-confirm h4 {
+ margin: 12px 0 20px;
+ color: #e1e6ee;
+ font-size: 15px;
+ font-weight: 580;
+}
+
+.a3s-tui-choice > button {
+ display: flex;
+ width: 100%;
+ min-height: 42px;
+ padding: 0 12px;
+ border: 1px solid transparent;
+ background: transparent;
+ color: #8993a1;
+ cursor: pointer;
+ align-items: center;
+ gap: 10px;
+ text-align: left;
+}
+
+.a3s-tui-choice > button.is-active {
+ border-color: #44648e;
+ background: #121a25;
+ color: #dce6f5;
+}
+
+.a3s-tui-choice > button span {
+ color: var(--demo-blue);
+ font-family: var(--a3s-mono);
+}
+
+.a3s-tui-confirm {
+ max-width: 520px;
+ padding: 22px;
+ border: 1px solid #66512e;
+ background:
+ linear-gradient(120deg, rgba(239, 179, 84, 0.07), transparent), #12110e;
+}
+
+.a3s-tui-confirm > span.a3s-demo-risk {
+ color: var(--demo-amber);
+}
+
+.a3s-tui-confirm > code {
+ display: block;
+ padding: 13px;
+ border: 1px solid #3b3529;
+ background: #0b0c0d;
+ color: #c9b78f;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+}
+
+.a3s-tui-confirm > p {
+ margin: 14px 0 0;
+ color: #817969;
+ font-size: 10px;
+}
+
+.a3s-tui-confirm > footer {
+ display: flex;
+ margin-top: 22px;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.a3s-tui-confirm > footer button {
+ min-height: 34px;
+ padding: 0 13px;
+ border: 1px solid #3e4249;
+ background: #15171b;
+ color: #9aa1ac;
+ cursor: pointer;
+ font-size: 10px;
+}
+
+.a3s-tui-confirm > footer button.is-primary {
+ border-color: #c5cbd4;
+ background: #e3e7ed;
+ color: #101217;
+}
+
+.a3s-tui-confirm output {
+ display: block;
+ margin-top: 18px;
+ padding: 10px;
+ border: 1px solid #315c4d;
+ color: #7fc5a8;
+ font-size: 10px;
+}
+
+.a3s-tui-confirm output.is-deny {
+ border-color: #653b3f;
+ color: #df8a90;
+}
+
+.a3s-tui-input-demo > div {
+ display: grid;
+ min-height: 52px;
+ margin-top: 12px;
+ border: 1px solid #42628d;
+ background: #0e141d;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 18px minmax(0, 1fr) auto;
+ padding: 0 12px;
+}
+
+.a3s-tui-input-demo > div > span {
+ color: var(--demo-blue);
+ font-family: var(--a3s-mono);
+}
+
+.a3s-tui-input-demo input {
+ min-width: 0;
+ border: 0;
+ background: transparent;
+ color: #d9e0ea;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+ outline: none;
+}
+
+.a3s-tui-input-demo small,
+.a3s-tui-input-demo p {
+ color: #596575;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-tabs-demo {
+ border: 1px solid #303640;
+}
+
+.a3s-tui-tabs-demo nav {
+ display: flex;
+ border-bottom: 1px solid #303640;
+ background: #101319;
+}
+
+.a3s-tui-tabs-demo nav button {
+ min-height: 40px;
+ padding: 0 14px;
+ border: 0;
+ border-right: 1px solid #2d333d;
+ background: transparent;
+ color: #65707f;
+ cursor: pointer;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-tabs-demo nav button[aria-selected='true'] {
+ background: #161b23;
+ color: #d3dbe6;
+ box-shadow: inset 0 -2px #6ca3ff;
+}
+
+.a3s-tui-tabs-demo > div {
+ min-height: 160px;
+ padding: 28px;
+}
+
+.a3s-tui-tabs-demo > div > span {
+ color: #5f6b7b;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.08em;
+}
+
+.a3s-tui-tabs-demo > div p {
+ max-width: 400px;
+ color: #929ba8;
+ font-size: 11px;
+ line-height: 1.7;
+}
+
+.a3s-tui-tree-demo {
+ font-family: var(--a3s-mono);
+}
+
+.a3s-tui-tree-demo > header {
+ padding-bottom: 12px;
+ border-bottom: 1px solid #2b323c;
+ color: #9da8b6;
+ font-size: 9px;
+}
+
+.a3s-tui-tree-demo > button {
+ display: flex;
+ width: 100%;
+ min-height: 38px;
+ padding: 0 8px;
+ border: 0;
+ background: transparent;
+ color: #8c96a4;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ font-size: 9px;
+ text-align: left;
+}
+
+.a3s-tui-tree-demo > button:hover {
+ background: #131820;
+ color: #d3d9e2;
+}
+
+.a3s-tui-tree-demo > button > span {
+ color: #505a68;
+ white-space: pre;
+}
+
+.a3s-tui-tree-demo > button > i {
+ color: #6ca3ff;
+ font-style: normal;
+}
+
+.a3s-tui-table-demo {
+ width: min(100%, 620px);
+ border-collapse: collapse;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-table-demo caption {
+ padding: 0 0 13px;
+ color: #99a3b1;
+ text-align: left;
+}
+
+.a3s-tui-table-demo th,
+.a3s-tui-table-demo td {
+ height: 43px;
+ padding: 0 13px;
+ border: 1px solid #2b323c;
+ color: #798493;
+ text-align: left;
+}
+
+.a3s-tui-table-demo th {
+ background: #11151b;
+ color: #596575;
+ font-size: 7px;
+}
+
+.a3s-tui-table-demo tr {
+ cursor: pointer;
+}
+
+.a3s-tui-table-demo tr.is-active td {
+ background: #121a25;
+ color: #c5d5ea;
+}
+
+.a3s-tui-diff-demo {
+ overflow: hidden;
+ width: min(100%, 640px);
+ border: 1px solid #303640;
+}
+
+.a3s-tui-diff-demo > header {
+ display: flex;
+ min-height: 38px;
+ padding: 0 12px;
+ border-bottom: 1px solid #303640;
+ background: #11151b;
+ color: #a5afbc;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-diff-demo > header span {
+ color: #71c9a2;
+}
+
+.a3s-tui-diff-demo pre {
+ overflow: auto;
+ margin: 0;
+ padding: 14px 0;
+ background: #0a0c10;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ line-height: 1.75;
+}
+
+.a3s-tui-diff-demo pre > span {
+ display: block;
+ min-width: max-content;
+ padding: 0 14px;
+ color: #88929f;
+}
+
+.a3s-tui-diff-demo pre i {
+ display: inline-block;
+ width: 28px;
+ color: #424a55;
+ font-style: normal;
+}
+
+.a3s-tui-diff-demo pre span.is-added {
+ background: rgba(60, 207, 145, 0.09);
+ color: #9bcdb8;
+}
+
+.a3s-tui-diff-demo pre span.is-removed {
+ background: rgba(239, 118, 122, 0.09);
+ color: #cc9699;
+}
+
+.a3s-tui-diff-demo.is-split pre {
+ column-count: 2;
+ column-rule: 1px solid #303640;
+}
+
+.a3s-tui-log-demo > button {
+ display: grid;
+ width: 100%;
+ min-height: 44px;
+ padding: 8px 7px;
+ border: 0;
+ border-bottom: 1px solid #242a33;
+ background: transparent;
+ color: #8993a0;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 18px minmax(0, 1fr) 18px;
+ text-align: left;
+}
+
+.a3s-tui-log-demo > button:hover {
+ background: #11161d;
+}
+
+.a3s-tui-log-demo button > span {
+ color: var(--demo-green);
+}
+
+.a3s-tui-log-demo button.is-active > span {
+ color: var(--demo-amber);
+}
+
+.a3s-tui-log-demo button strong {
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ font-weight: 500;
+}
+
+.a3s-tui-log-demo button i {
+ color: #4e5865;
+ font-style: normal;
+}
+
+.a3s-tui-log-demo button small {
+ padding: 8px 0 2px 27px;
+ color: #647181;
+ grid-column: 1 / -1;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-alert {
+ display: grid;
+ width: min(100%, 580px);
+ min-height: 105px;
+ padding: 18px;
+ border: 1px solid #3a526f;
+ background: #101722;
+ align-items: start;
+ gap: 14px;
+ grid-template-columns: 24px minmax(0, 1fr);
+}
+
+.a3s-tui-alert > span {
+ display: flex;
+ width: 22px;
+ height: 22px;
+ border: 1px solid #55769d;
+ color: #94b9e5;
+ align-items: center;
+ justify-content: center;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+}
+
+.a3s-tui-alert strong {
+ color: #8fb4df;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-alert p {
+ margin: 8px 0 0;
+ color: #9aa8b9;
+ font-size: 11px;
+}
+
+.a3s-tui-alert.is-success {
+ border-color: #315f4d;
+ background: #0f1714;
+}
+
+.a3s-tui-alert.is-success > span {
+ border-color: #438066;
+ color: #80c9a8;
+}
+
+.a3s-tui-alert.is-success strong {
+ color: #7fc5a6;
+}
+
+.a3s-tui-alert.is-warning {
+ border-color: #6f582f;
+ background: #17140e;
+}
+
+.a3s-tui-alert.is-warning > span {
+ border-color: #8a6a34;
+ color: #e2b667;
+}
+
+.a3s-tui-alert.is-warning strong {
+ color: #d9ad60;
+}
+
+.a3s-tui-alert.is-error {
+ border-color: #693c42;
+ background: #1a1012;
+}
+
+.a3s-tui-alert.is-error > span {
+ border-color: #8a4a51;
+ color: #e68c93;
+}
+
+.a3s-tui-alert.is-error strong {
+ color: #df858c;
+}
+
+.a3s-tui-progress-demo > header {
+ display: flex;
+ color: #9aa4b2;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-progress-demo > header span {
+ color: #d7a958;
+ font-size: 7px;
+}
+
+.a3s-tui-progress-demo > div {
+ overflow: hidden;
+ height: 7px;
+ margin-top: 22px;
+ border: 1px solid #303743;
+ background: #101319;
+}
+
+.a3s-tui-progress-demo > div i {
+ display: block;
+ height: 100%;
+ background: linear-gradient(90deg, #4c7fc5, #70b7d8);
+ transition: width 180ms ease;
+}
+
+.a3s-tui-progress-demo p {
+ display: flex;
+ color: #4d5663;
+ align-items: center;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-progress-demo p > span:first-child {
+ color: #6ca3ff;
+}
+
+.a3s-tui-progress-demo p small {
+ margin-left: auto;
+ color: #66717f;
+}
+
+.a3s-tui-toast-stage {
+ position: relative;
+ width: 100%;
+ min-height: 220px;
+ color: #5e6876;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-toast {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ display: grid;
+ min-width: 250px;
+ min-height: 52px;
+ padding: 0 12px;
+ border: 1px solid #3b6b58;
+ background: #111a17;
+ color: #a8d7c2;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 18px 1fr 22px;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tui-toast > span {
+ color: var(--demo-green);
+}
+
+.a3s-tui-toast button {
+ border: 0;
+ background: transparent;
+ color: #678576;
+ cursor: pointer;
+}
+
+.a3s-tui-status-stage {
+ display: flex;
+ width: 100%;
+ min-height: 220px;
+ color: #6d7683;
+ flex-direction: column;
+ justify-content: flex-end;
+}
+
+.a3s-tui-status-stage > footer {
+ display: grid;
+ min-height: 34px;
+ padding: 0 10px;
+ border: 1px solid #303743;
+ background: #12161d;
+ color: #6f7b8a;
+ align-items: center;
+ gap: 15px;
+ grid-template-columns: auto auto auto 1fr;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-tui-status-stage > footer span:first-child {
+ color: #a9c4eb;
+}
+
+.a3s-tui-status-stage > footer span:last-child {
+ justify-self: end;
+}
+
+.a3s-tui-status-stage > footer span.is-warning {
+ color: #e0ad59;
+}
+
+/* Web surface */
+
+.a3s-demo-web-panel {
+ overflow: hidden;
+ width: min(100%, 760px);
+ min-height: 380px;
+ border: 1px solid #d6dae1;
+ border-radius: 8px;
+ background: #f7f8fa;
+ color: #1d222b;
+ box-shadow: 0 28px 65px rgba(0, 0, 0, 0.34);
+}
+
+.a3s-demo-web-panel > header {
+ display: flex;
+ height: 42px;
+ padding: 0 14px;
+ border-bottom: 1px solid #dfe2e7;
+ background: #fff;
+ color: #737b87;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.07em;
+}
+
+.a3s-demo-web-panel > header > span:first-child {
+ display: flex;
+ color: #343a44;
+ align-items: center;
+ gap: 8px;
+ font-weight: 650;
+}
+
+.a3s-demo-web-panel > header i {
+ width: 7px;
+ height: 7px;
+ border-radius: 2px;
+ background: #476dd0;
+}
+
+.a3s-demo-web-panel > div {
+ display: flex;
+ min-height: 338px;
+ padding: 28px;
+ align-items: center;
+ justify-content: center;
+}
+
+.a3s-web-composer-demo {
+ position: relative;
+ width: min(100%, 610px);
+ border: 1px solid #cfd4dc;
+ border-radius: 10px;
+ background: #fff;
+ box-shadow: 0 10px 28px rgba(22, 30, 44, 0.08);
+}
+
+.a3s-web-composer-demo textarea {
+ display: block;
+ width: 100%;
+ min-height: 118px;
+ padding: 17px 18px;
+ border: 0;
+ border-radius: inherit;
+ background: transparent;
+ color: #272d36;
+ resize: vertical;
+ font-size: 13px;
+ line-height: 1.6;
+ outline: none;
+}
+
+.a3s-web-composer-demo > footer {
+ display: flex;
+ min-height: 50px;
+ padding: 8px 10px;
+ border-top: 1px solid #ebedf0;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.a3s-web-composer-demo > footer > div {
+ display: flex;
+ gap: 5px;
+}
+
+.a3s-web-composer-demo button {
+ min-height: 30px;
+ padding: 0 9px;
+ border: 0;
+ border-radius: 5px;
+ background: #f2f4f7;
+ color: #666f7c;
+ cursor: pointer;
+ font-size: 9px;
+}
+
+.a3s-web-composer-demo button.is-send {
+ width: 32px;
+ padding: 0;
+ background: #20242b;
+ color: #fff;
+ font-size: 15px;
+}
+
+.a3s-web-composer-demo button:disabled {
+ cursor: not-allowed;
+ opacity: 0.45;
+}
+
+.a3s-web-composer-demo output {
+ position: absolute;
+ top: calc(100% + 9px);
+ right: 0;
+ padding: 7px 10px;
+ border: 1px solid #b8d8c8;
+ border-radius: 5px;
+ background: #eff8f3;
+ color: #3b795c;
+ font-size: 9px;
+}
+
+.a3s-web-library-demo {
+ width: min(100%, 360px);
+ min-height: 285px;
+ padding: 13px;
+ border: 1px solid #d6dbe2;
+ border-radius: 7px;
+ background: #fff;
+}
+
+.a3s-web-library-demo > header {
+ display: flex;
+ min-height: 34px;
+ color: #252b34;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 12px;
+}
+
+.a3s-web-library-demo > header button {
+ width: 26px;
+ height: 26px;
+ border: 1px solid #d9dde3;
+ border-radius: 5px;
+ background: #fff;
+ color: #5d6672;
+ cursor: pointer;
+}
+
+.a3s-web-library-demo > button {
+ display: flex;
+ width: 100%;
+ min-height: 38px;
+ padding: 0 9px;
+ border: 0;
+ border-radius: 5px;
+ background: transparent;
+ color: #5e6672;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ font-size: 10px;
+ text-align: left;
+}
+
+.a3s-web-library-demo > button.is-new {
+ margin: 7px 0 14px;
+ border: 1px solid #d9dde3;
+ color: #343a43;
+}
+
+.a3s-web-library-demo > button.is-active {
+ background: #edf2fb;
+ color: #254f94;
+}
+
+.a3s-web-library-demo > button i {
+ color: #7995c4;
+ font-size: 7px;
+ font-style: normal;
+}
+
+.a3s-web-library-demo > small {
+ display: block;
+ margin: 0 9px 5px;
+ color: #9ba2ac;
+ font-size: 7px;
+ letter-spacing: 0.08em;
+}
+
+.a3s-web-library-demo > p {
+ color: #959ca6;
+ font-size: 10px;
+ text-align: center;
+}
+
+.a3s-web-stream-demo {
+ width: min(100%, 610px);
+}
+
+.a3s-web-stream-demo > article {
+ margin-bottom: 14px;
+ padding: 14px 16px;
+ border: 1px solid #d8dce2;
+ border-radius: 7px;
+ background: #fff;
+ color: #414852;
+ font-size: 11px;
+}
+
+.a3s-web-stream-demo > div {
+ display: grid;
+ min-height: 48px;
+ padding: 0 12px;
+ border-bottom: 1px solid #e2e5e9;
+ color: #69727e;
+ align-items: center;
+ gap: 10px;
+ grid-template-columns: 18px minmax(0, 1fr) auto;
+}
+
+.a3s-web-stream-demo > div > span {
+ color: #3f9a71;
+}
+
+.a3s-web-stream-demo > div.is-current > span {
+ color: #b77721;
+}
+
+.a3s-web-stream-demo > div strong {
+ overflow: hidden;
+ color: #3d444e;
+ font-size: 10px;
+ font-weight: 550;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-web-stream-demo > div small {
+ color: #9aa1ab;
+ font-size: 8px;
+}
+
+.a3s-web-reasoning-demo {
+ width: min(100%, 610px);
+ border: 1px solid #d5dae1;
+ border-radius: 7px;
+ background: #fff;
+}
+
+.a3s-web-reasoning-demo > button {
+ display: grid;
+ width: 100%;
+ min-height: 62px;
+ padding: 0 14px;
+ border: 0;
+ background: transparent;
+ color: #49515d;
+ cursor: pointer;
+ align-items: center;
+ gap: 11px;
+ grid-template-columns: 22px minmax(0, 1fr) 18px;
+ text-align: left;
+}
+
+.a3s-web-reasoning-demo > button > span:first-child {
+ color: #647eaa;
+ font-size: 18px;
+}
+
+.a3s-web-reasoning-demo > button > span:nth-child(2) {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.a3s-web-reasoning-demo strong {
+ color: #333a44;
+ font-size: 11px;
+}
+
+.a3s-web-reasoning-demo small {
+ color: #929aa5;
+ font-size: 7px;
+}
+
+.a3s-web-reasoning-demo i {
+ color: #8b929c;
+ font-style: normal;
+}
+
+.a3s-web-reasoning-demo > p {
+ margin: 0;
+ padding: 0 48px 20px;
+ color: #707986;
+ font-size: 10px;
+ line-height: 1.65;
+}
+
+.a3s-web-tool-demo {
+ overflow: hidden;
+ width: min(100%, 610px);
+ border: 1px solid #d6dbe2;
+ border-radius: 7px;
+ background: #fff;
+}
+
+.a3s-web-tool-demo > button {
+ display: grid;
+ width: 100%;
+ min-height: 62px;
+ padding: 0 14px;
+ border: 0;
+ background: transparent;
+ color: #626c78;
+ cursor: pointer;
+ align-items: center;
+ gap: 10px;
+ grid-template-columns: 20px minmax(0, 1fr) 16px;
+ text-align: left;
+}
+
+.a3s-web-tool-demo > button > span:first-child {
+ color: #bf7f28;
+}
+
+.a3s-web-tool-demo.is-success > button > span:first-child {
+ color: #3b956d;
+}
+
+.a3s-web-tool-demo.is-error > button > span:first-child {
+ color: #c0525b;
+}
+
+.a3s-web-tool-demo > button > span:nth-child(2) {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.a3s-web-tool-demo strong {
+ color: #343b45;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+}
+
+.a3s-web-tool-demo small {
+ color: #929aa5;
+ font-size: 8px;
+}
+
+.a3s-web-tool-demo i {
+ color: #8e96a1;
+ font-style: normal;
+}
+
+.a3s-web-tool-demo pre {
+ overflow: auto;
+ margin: 0;
+ padding: 16px 48px;
+ border-top: 1px solid #e1e4e8;
+ background: #f3f5f7;
+ color: #626b77;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ line-height: 1.7;
+}
+
+.a3s-web-permission-demo {
+ width: min(100%, 520px);
+ padding: 20px;
+ border: 1px solid #d2d7df;
+ border-radius: 9px;
+ background: #fff;
+ box-shadow: 0 13px 32px rgba(25, 32, 44, 0.08);
+}
+
+.a3s-web-permission-demo > header {
+ display: flex;
+ align-items: center;
+ gap: 11px;
+}
+
+.a3s-web-permission-demo > header > span:first-child {
+ display: flex;
+ width: 34px;
+ height: 34px;
+ border-radius: 8px;
+ background: #fff4df;
+ color: #9b691e;
+ align-items: center;
+ justify-content: center;
+}
+
+.a3s-web-permission-demo > header > span:last-child {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.a3s-web-permission-demo strong {
+ color: #2b313a;
+ font-size: 12px;
+}
+
+.a3s-web-permission-demo small {
+ color: #8e96a0;
+ font-size: 8px;
+}
+
+.a3s-web-permission-demo dl {
+ margin: 18px 0;
+ border: 1px solid #e0e3e7;
+ border-radius: 6px;
+}
+
+.a3s-web-permission-demo dl > div {
+ display: grid;
+ min-height: 48px;
+ padding: 9px 12px;
+ border-bottom: 1px solid #e5e7ea;
+ gap: 12px;
+ grid-template-columns: 84px minmax(0, 1fr);
+}
+
+.a3s-web-permission-demo dl > div:last-child {
+ border-bottom: 0;
+}
+
+.a3s-web-permission-demo dt {
+ color: #8b929c;
+ font-size: 8px;
+}
+
+.a3s-web-permission-demo dd {
+ margin: 0;
+ color: #4b535e;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-web-permission-demo > footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.a3s-web-permission-demo button,
+.a3s-web-recovery-demo button,
+.a3s-web-delivery-demo > button {
+ min-height: 34px;
+ padding: 0 12px;
+ border: 1px solid #d4d8de;
+ border-radius: 5px;
+ background: #fff;
+ color: #626a75;
+ cursor: pointer;
+ font-size: 9px;
+}
+
+.a3s-web-permission-demo button.is-primary {
+ border-color: #242932;
+ background: #242932;
+ color: #fff;
+}
+
+.a3s-web-permission-demo output {
+ display: block;
+ padding: 10px;
+ border-radius: 5px;
+ background: #edf7f1;
+ color: #3d7d5e;
+ font-size: 9px;
+}
+
+.a3s-web-permission-demo output.is-deny {
+ background: #f9eeee;
+ color: #a94b54;
+}
+
+.a3s-web-recovery-stage {
+ width: min(100%, 610px);
+}
+
+.a3s-web-recovery-stage > button {
+ min-height: 38px;
+ border: 1px solid #d4d9e0;
+ border-radius: 6px;
+ background: #fff;
+ color: #58616d;
+ cursor: pointer;
+ font-size: 10px;
+}
+
+.a3s-web-recovery-demo {
+ display: grid;
+ padding: 17px;
+ border: 1px solid #ecd4a9;
+ border-radius: 7px;
+ background: #fffaf0;
+ align-items: center;
+ gap: 12px;
+ grid-template-columns: 28px minmax(0, 1fr) auto;
+}
+
+.a3s-web-recovery-demo > span {
+ display: flex;
+ width: 26px;
+ height: 26px;
+ border-radius: 50%;
+ background: #f5dfb8;
+ color: #9a671d;
+ align-items: center;
+ justify-content: center;
+ font-weight: 700;
+}
+
+.a3s-web-recovery-demo strong {
+ color: #493d2c;
+ font-size: 11px;
+}
+
+.a3s-web-recovery-demo p {
+ margin: 4px 0 0;
+ color: #88765b;
+ font-size: 9px;
+}
+
+.a3s-web-recovery-demo > footer {
+ display: flex;
+ gap: 6px;
+}
+
+.a3s-web-recovery-demo > footer button:last-child {
+ border-color: #816533;
+ background: #8c6e38;
+ color: #fff;
+}
+
+.a3s-web-plan-demo,
+.a3s-web-agent-demo {
+ width: min(100%, 450px);
+ border: 1px solid #d7dce2;
+ border-radius: 7px;
+ background: #fff;
+}
+
+.a3s-web-plan-demo > header,
+.a3s-web-agent-demo > header {
+ display: flex;
+ min-height: 48px;
+ padding: 0 14px;
+ border-bottom: 1px solid #e1e4e8;
+ color: #343b45;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 11px;
+}
+
+.a3s-web-plan-demo > header span,
+.a3s-web-agent-demo > header span {
+ color: #8b939e;
+ font-size: 8px;
+}
+
+.a3s-web-plan-demo > button {
+ display: grid;
+ width: 100%;
+ min-height: 52px;
+ padding: 0 14px;
+ border: 0;
+ border-bottom: 1px solid #e8eaed;
+ background: transparent;
+ color: #646d78;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 18px minmax(0, 1fr) auto;
+ text-align: left;
+}
+
+.a3s-web-plan-demo > button:last-child {
+ border-bottom: 0;
+}
+
+.a3s-web-plan-demo button span {
+ color: #a1a8b1;
+}
+
+.a3s-web-plan-demo button.is-done span {
+ color: #3d966f;
+}
+
+.a3s-web-plan-demo button.is-doing span {
+ color: #b77927;
+}
+
+.a3s-web-plan-demo button strong {
+ color: #4b535e;
+ font-size: 10px;
+ font-weight: 520;
+}
+
+.a3s-web-plan-demo button small {
+ color: #a0a6af;
+ font-size: 7px;
+}
+
+.a3s-web-agent-demo {
+ padding-bottom: 8px;
+}
+
+.a3s-web-agent-demo > button {
+ display: grid;
+ width: calc(100% - 16px);
+ min-height: 62px;
+ margin: 8px;
+ padding: 0 10px;
+ border: 1px solid transparent;
+ border-radius: 6px;
+ background: transparent;
+ color: #626b77;
+ cursor: pointer;
+ align-items: center;
+ gap: 10px;
+ grid-template-columns: 32px minmax(0, 1fr) 70px;
+ text-align: left;
+}
+
+.a3s-web-agent-demo > button.is-active {
+ border-color: #c7d5eb;
+ background: #f1f5fb;
+}
+
+.a3s-web-agent-demo > button > span:first-child {
+ display: flex;
+ width: 30px;
+ height: 30px;
+ border-radius: 7px;
+ background: #e8edf5;
+ color: #5373a5;
+ align-items: center;
+ justify-content: center;
+ font-size: 10px;
+ font-weight: 650;
+}
+
+.a3s-web-agent-demo > button > span:nth-child(2) {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.a3s-web-agent-demo strong {
+ color: #3e4650;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-web-agent-demo small {
+ color: #939aa4;
+ font-size: 7px;
+}
+
+.a3s-web-agent-demo button > i {
+ overflow: hidden;
+ height: 4px;
+ border-radius: 2px;
+ background: #e2e5e9;
+}
+
+.a3s-web-agent-demo button > i b {
+ display: block;
+ height: 100%;
+ background: #5f85bd;
+}
+
+.a3s-web-delivery-demo {
+ width: min(100%, 580px);
+ text-align: center;
+}
+
+.a3s-web-delivery-demo > span {
+ display: flex;
+ width: 42px;
+ height: 42px;
+ margin: 0 auto 13px;
+ border-radius: 50%;
+ background: #e6f4ec;
+ color: #37865f;
+ align-items: center;
+ justify-content: center;
+ font-size: 17px;
+}
+
+.a3s-web-delivery-demo > small {
+ color: #8e96a0;
+ font-size: 7px;
+ letter-spacing: 0.08em;
+}
+
+.a3s-web-delivery-demo h4 {
+ margin: 7px 0 8px;
+ color: #252b33;
+ font-size: 21px;
+}
+
+.a3s-web-delivery-demo > p {
+ margin: 0;
+ color: #747d88;
+ font-size: 10px;
+}
+
+.a3s-web-delivery-demo > div {
+ display: flex;
+ margin: 20px 0 14px;
+ padding: 12px;
+ border: 1px solid #dfe3e8;
+ border-radius: 7px;
+ background: #fff;
+ color: #68717c;
+ justify-content: center;
+ gap: 20px;
+ font-size: 9px;
+}
+
+.a3s-web-delivery-demo > div span:first-child {
+ color: #3f8c69;
+}
+
+.a3s-web-delivery-demo ul {
+ margin: 12px 0 0;
+ padding: 0;
+ border: 1px solid #dfe3e8;
+ border-radius: 6px;
+ background: #fff;
+ list-style: none;
+ text-align: left;
+}
+
+.a3s-web-delivery-demo li {
+ display: flex;
+ min-height: 36px;
+ padding: 0 11px;
+ border-bottom: 1px solid #e8eaed;
+ color: #59626e;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-web-delivery-demo li:last-child {
+ border-bottom: 0;
+}
+
+.a3s-web-delivery-demo li span {
+ color: #3e9a70;
+}
+
+.a3s-web-artifact-demo,
+.a3s-web-changes-demo {
+ display: grid;
+ overflow: hidden;
+ width: min(100%, 650px);
+ min-height: 270px;
+ border: 1px solid #d6dbe2;
+ border-radius: 7px;
+ background: #fff;
+ grid-template-columns: 230px minmax(0, 1fr);
+}
+
+.a3s-web-artifact-demo > aside,
+.a3s-web-changes-demo > aside {
+ border-right: 1px solid #e0e3e7;
+ background: #fafbfc;
+}
+
+.a3s-web-artifact-demo aside > header,
+.a3s-web-changes-demo aside > header {
+ display: flex;
+ min-height: 44px;
+ padding: 0 12px;
+ border-bottom: 1px solid #e0e3e7;
+ color: #4a525d;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 10px;
+}
+
+.a3s-web-artifact-demo aside > button,
+.a3s-web-changes-demo aside > button {
+ display: grid;
+ width: 100%;
+ min-height: 56px;
+ padding: 0 10px;
+ border: 0;
+ border-bottom: 1px solid #e9ebee;
+ background: transparent;
+ color: #68717c;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 28px minmax(0, 1fr) auto;
+ text-align: left;
+}
+
+.a3s-web-artifact-demo aside > button.is-active,
+.a3s-web-changes-demo aside > button.is-active {
+ background: #edf3fc;
+ color: #315a96;
+}
+
+.a3s-web-artifact-demo aside button > span:first-child,
+.a3s-web-changes-demo aside button > span:first-child {
+ display: flex;
+ width: 26px;
+ height: 26px;
+ border-radius: 5px;
+ background: #e7ebf1;
+ color: #65748a;
+ align-items: center;
+ justify-content: center;
+ font-size: 7px;
+ font-weight: 650;
+}
+
+.a3s-web-artifact-demo aside button > span:last-child {
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.a3s-web-artifact-demo aside button strong,
+.a3s-web-changes-demo aside button strong {
+ overflow: hidden;
+ font-size: 9px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-web-artifact-demo aside button small,
+.a3s-web-changes-demo aside button small {
+ color: #9ba2ac;
+ font-size: 7px;
+}
+
+.a3s-web-artifact-demo > div {
+ display: flex;
+ padding: 30px;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.a3s-web-artifact-demo > div small {
+ color: #939ba6;
+ font-size: 8px;
+}
+
+.a3s-web-artifact-demo > div strong {
+ margin-top: 8px;
+ color: #303741;
+ font-size: 14px;
+}
+
+.a3s-web-artifact-demo > div code {
+ margin-top: 18px;
+ padding: 12px;
+ border: 1px solid #e0e3e7;
+ background: #f5f6f8;
+ color: #66707c;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-web-changes-demo > pre {
+ overflow: auto;
+ margin: 0;
+ padding: 28px 0;
+ background: #fbfcfd;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ line-height: 2;
+}
+
+.a3s-web-changes-demo > pre > * {
+ display: block;
+ min-width: max-content;
+ padding: 0 18px;
+ color: #7a838f;
+ font-style: normal;
+}
+
+.a3s-web-changes-demo > pre > span {
+ color: #788ba8;
+}
+
+.a3s-web-changes-demo > pre > i {
+ background: #fff0f1;
+ color: #a75860;
+}
+
+.a3s-web-changes-demo > pre > b {
+ background: #eef8f2;
+ color: #3e7f5f;
+ font-weight: 400;
+}
+
+.a3s-web-changes-demo.is-split > pre {
+ background: linear-gradient(90deg, #fff4f4 0 50%, #f0f8f3 50% 100%);
+}
+
+.a3s-web-editor-demo {
+ overflow: hidden;
+ width: min(100%, 650px);
+ border: 1px solid #d6dbe2;
+ border-radius: 7px;
+ background: #fff;
+}
+
+.a3s-web-editor-demo > nav {
+ display: flex;
+ min-height: 40px;
+ border-bottom: 1px solid #dfe3e7;
+ background: #f4f5f7;
+}
+
+.a3s-web-editor-demo > nav button {
+ padding: 0 13px;
+ border: 0;
+ border-right: 1px solid #dfe3e7;
+ background: transparent;
+ color: #7b838e;
+ cursor: pointer;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-web-editor-demo > nav button.is-active {
+ background: #fff;
+ color: #354052;
+ box-shadow: inset 0 2px #5f83bb;
+}
+
+.a3s-web-editor-demo > div {
+ display: grid;
+ min-height: 190px;
+ padding: 24px 0;
+ grid-template-columns: 42px minmax(0, 1fr);
+}
+
+.a3s-web-editor-demo > div > span {
+ padding-top: 4px;
+ color: #a2a8b1;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ text-align: center;
+}
+
+.a3s-web-editor-demo textarea {
+ min-height: 95px;
+ padding: 4px 14px;
+ border: 0;
+ border-left: 2px solid #dbe6f6;
+ background: #f8fbff;
+ color: #3f526d;
+ resize: none;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+ outline: none;
+}
+
+.a3s-web-editor-demo > footer {
+ display: flex;
+ min-height: 28px;
+ padding: 0 10px;
+ border-top: 1px solid #dfe3e7;
+ background: #f3f5f7;
+ color: #89919c;
+ align-items: center;
+ justify-content: flex-end;
+ font-family: var(--a3s-mono);
+ font-size: 7px;
+}
+
+.a3s-web-memory-demo {
+ width: min(100%, 650px);
+ min-height: 270px;
+ border: 1px solid #d7dce2;
+ border-radius: 7px;
+ background:
+ linear-gradient(#eef1f5 1px, transparent 1px),
+ linear-gradient(90deg, #eef1f5 1px, transparent 1px), #fff;
+ background-size: 22px 22px;
+}
+
+.a3s-web-memory-demo svg {
+ display: block;
+ width: 100%;
+ height: 220px;
+}
+
+.a3s-web-memory-demo svg path {
+ fill: none;
+ stroke: #c4ccd8;
+ stroke-width: 1.5;
+}
+
+.a3s-web-memory-demo svg g {
+ cursor: pointer;
+}
+
+.a3s-web-memory-demo svg circle {
+ fill: #f4f6f9;
+ stroke: #9eabba;
+ stroke-width: 1.5;
+}
+
+.a3s-web-memory-demo svg g.is-active circle {
+ fill: #e9f0fb;
+ stroke: #547bb6;
+ stroke-width: 2;
+}
+
+.a3s-web-memory-demo svg text {
+ fill: #65707e;
+ font-size: 9px;
+}
+
+.a3s-web-memory-demo svg g.is-active text {
+ fill: #315b98;
+ font-weight: 650;
+}
+
+.a3s-web-memory-demo > p {
+ margin: 0;
+ padding: 10px 14px;
+ border-top: 1px solid #e0e3e7;
+ background: rgba(255, 255, 255, 0.9);
+ color: #747d88;
+ font-size: 9px;
+}
+
+.a3s-web-memory-demo > p strong {
+ color: #365f9b;
+}
+
+.a3s-web-memory-demo ol {
+ margin: 0;
+ padding: 38px 40px;
+ list-style: none;
+}
+
+.a3s-web-memory-demo li {
+ position: relative;
+ min-height: 58px;
+ padding-left: 32px;
+ border-left: 1px solid #bcc7d4;
+ color: #535d69;
+ font-size: 10px;
+}
+
+.a3s-web-memory-demo li::before {
+ position: absolute;
+ top: 0;
+ left: -5px;
+ width: 9px;
+ height: 9px;
+ border: 2px solid #6d8ebd;
+ border-radius: 50%;
+ background: #fff;
+ content: '';
+}
+
+.a3s-web-memory-demo li span {
+ display: inline-block;
+ width: 55px;
+ color: #89939f;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+}
+
+.a3s-component-demo-missing {
+ padding: 18px;
+ border: 1px solid #6a3d43;
+ background: #1a1012;
+ color: #e08b92;
+}
+
+@media (max-width: 720px) {
+ .a3s-component-demo-stage {
+ min-height: 430px;
+ padding: 18px 12px;
+ }
+
+ .a3s-component-demo-header {
+ grid-template-columns: 1fr auto;
+ }
+
+ .a3s-component-demo-header > span {
+ display: none;
+ }
+
+ .a3s-component-demo-header strong {
+ justify-self: start;
+ }
+
+ .a3s-demo-controls {
+ overflow-x: auto;
+ flex-wrap: nowrap;
+ }
+
+ .a3s-demo-controls button,
+ .a3s-demo-controls span {
+ white-space: nowrap;
+ }
+
+ .a3s-demo-tui-body,
+ .a3s-demo-web-panel > div {
+ padding: 17px 12px;
+ }
+
+ .a3s-demo-tui-window {
+ grid-template-rows: 30px minmax(260px, 1fr) 28px;
+ }
+
+ .a3s-demo-tui-window > header > span:nth-child(2) {
+ display: none;
+ }
+
+ .a3s-tui-diff-demo.is-split pre {
+ column-count: 1;
+ }
+
+ .a3s-tui-status-stage > footer {
+ gap: 8px;
+ grid-template-columns: auto auto auto;
+ }
+
+ .a3s-tui-status-stage > footer span:last-child {
+ display: none;
+ }
+
+ .a3s-web-recovery-demo {
+ grid-template-columns: 24px minmax(0, 1fr);
+ }
+
+ .a3s-web-recovery-demo > footer {
+ margin-top: 8px;
+ grid-column: 1 / -1;
+ justify-content: flex-end;
+ }
+
+ .a3s-web-artifact-demo,
+ .a3s-web-changes-demo {
+ grid-template-columns: 150px minmax(0, 1fr);
+ }
+
+ .a3s-web-artifact-demo aside button > span:first-child,
+ .a3s-web-changes-demo aside button > span:first-child {
+ display: none;
+ }
+
+ .a3s-web-artifact-demo aside > button,
+ .a3s-web-changes-demo aside > button {
+ padding: 0 8px;
+ grid-template-columns: minmax(0, 1fr);
+ }
+
+ .a3s-web-delivery-demo > div {
+ align-items: center;
+ flex-direction: column;
+ gap: 7px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .a3s-component-demo * {
+ transition: none !important;
+ }
+}
diff --git a/website/theme/components/A3SComponentDemo.tsx b/website/theme/components/A3SComponentDemo.tsx
new file mode 100644
index 0000000..bc5881a
--- /dev/null
+++ b/website/theme/components/A3SComponentDemo.tsx
@@ -0,0 +1,1671 @@
+import { type ReactNode, useMemo, useState } from 'react';
+import { useLang } from '@rspress/core/runtime';
+
+type Locale = 'zh' | 'en';
+type Status = 'idle' | 'running' | 'success' | 'error';
+
+type DemoProps = {
+ locale: Locale;
+};
+
+const labels = {
+ zh: {
+ live: '可交互示例',
+ local: '只改变本地状态,不会调用 API',
+ reset: '重置',
+ idle: '等待',
+ running: '执行中',
+ success: '完成',
+ error: '失败',
+ details: '详情',
+ collapse: '收起',
+ empty: '暂无内容',
+ },
+ en: {
+ live: 'INTERACTIVE EXAMPLE',
+ local: 'Local state only; no API calls',
+ reset: 'Reset',
+ idle: 'Idle',
+ running: 'Running',
+ success: 'Complete',
+ error: 'Failed',
+ details: 'Details',
+ collapse: 'Collapse',
+ empty: 'Nothing here',
+ },
+} as const;
+
+const tuiNames = new Set([
+ 'ActivityBlock',
+ 'Checklist',
+ 'ChoicePrompt',
+ 'Confirm',
+ 'TextInput',
+ 'Tabs',
+ 'TreePicker',
+ 'DataTable',
+ 'DiffView',
+ 'ToolLogView',
+ 'Alert',
+ 'Progress',
+ 'Toast',
+ 'SessionStatus',
+]);
+
+function Controls({
+ children,
+ label,
+}: {
+ children: ReactNode;
+ label?: string;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+function ControlButton({
+ active,
+ children,
+ onClick,
+}: {
+ active?: boolean;
+ children: ReactNode;
+ onClick: () => void;
+}) {
+ return (
+
+ );
+}
+
+function TuiWindow({
+ children,
+ footer = 'default · medium ctx 38%',
+}: {
+ children: ReactNode;
+ footer?: string;
+}) {
+ return (
+
+
+ A3S CODE
+ ~/workspace
+ 80 × 24
+
+
{children}
+
+
+ );
+}
+
+function WebPanel({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+ A3S Web
+
+ LOCAL PREVIEW
+
+
{children}
+
+ );
+}
+
+function StatusControls({
+ onChange,
+ status,
+}: {
+ onChange: (status: Status) => void;
+ status: Status;
+}) {
+ return (
+
+ {(['idle', 'running', 'success', 'error'] as Status[]).map((item) => (
+ onChange(item)}
+ >
+ {item}
+
+ ))}
+
+ );
+}
+
+function ActivityBlockDemo({ locale }: DemoProps) {
+ const copy = labels[locale];
+ const [status, setStatus] = useState('running');
+ const [open, setOpen] = useState(true);
+ const statusIcon = {
+ idle: '·',
+ running: '◌',
+ success: '✓',
+ error: '×',
+ }[status];
+
+ return (
+ <>
+
+
+
+ {open && (
+
+
+ ✓ read src/auth/session.rs
+
+
+ ✓ grep refresh_token
+
+
+ {status === 'running' ? '◌' : '·'}{' '}
+ {locale === 'zh' ? '整理调用关系' : 'Map the call graph'}
+
+
+ )}
+
+ >
+ );
+}
+
+type CheckState = 'todo' | 'doing' | 'done';
+
+function ChecklistDemo({ locale }: DemoProps) {
+ const initial: CheckState[] = ['done', 'doing', 'todo'];
+ const [items, setItems] = useState(initial);
+ const text =
+ locale === 'zh'
+ ? ['定位失效分支', '更新会话恢复逻辑', '补充回归测试']
+ : [
+ 'Locate the expiry branch',
+ 'Update session recovery',
+ 'Add a regression test',
+ ];
+
+ function cycle(index: number) {
+ const next: Record = {
+ todo: 'doing',
+ doing: 'done',
+ done: 'todo',
+ };
+ setItems((current) =>
+ current.map((item, itemIndex) =>
+ itemIndex === index ? next[item] : item,
+ ),
+ );
+ }
+
+ return (
+ <>
+
+
+
+ {items.filter((item) => item === 'done').length} / {items.length}
+
+
+
+
+
+ {locale === 'zh' ? '任务清单' : 'Checklist'}
+ {items.filter((item) => item === 'done').length}/3
+
+ {items.map((state, index) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+function ChoicePromptDemo({ locale }: DemoProps) {
+ const [selected, setSelected] = useState(1);
+ const options =
+ locale === 'zh'
+ ? ['只运行相关测试', '运行完整测试套件', '先不运行']
+ : ['Run related tests', 'Run the full suite', 'Skip for now'];
+
+ return (
+ <>
+
+ selected: {selected + 1}
+
+
+
+
+ QUESTION
+
+ {locale === 'zh'
+ ? '修改完成后要运行哪些测试?'
+ : 'Which tests should run after the change?'}
+
+ {options.map((option, index) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+function ConfirmDemo({ locale }: DemoProps) {
+ const [decision, setDecision] = useState<'allow' | 'deny' | null>(null);
+
+ return (
+ <>
+
+ decision: {decision ?? 'pending'}
+
+
+
+
+ CONFIRM
+
+ {locale === 'zh' ? '允许运行本地命令?' : 'Allow a local command?'}
+
+ cargo test auth::session
+
+ {locale === 'zh'
+ ? '命令只在当前 Workspace 内运行。'
+ : 'The command runs only in the current workspace.'}
+
+ {decision ? (
+
+ ) : (
+
+ )}
+
+
+ >
+ );
+}
+
+function TextInputDemo({ locale }: DemoProps) {
+ const initial =
+ locale === 'zh'
+ ? '检查登录流程并补上测试'
+ : 'Inspect the login flow and add tests';
+ const [value, setValue] = useState(initial);
+
+ return (
+ <>
+
+ length: {value.length}
+
+
+
+
+
+ >
+ );
+}
+
+function TabsDemo({ locale }: DemoProps) {
+ const tabs = ['Transcript', 'Changes', 'Artifacts'];
+ const [active, setActive] = useState(tabs[0]);
+
+ return (
+ <>
+
+ active: {active}
+
+
+
+
+
+
{active.toUpperCase()}
+
+ {active === 'Transcript'
+ ? locale === 'zh'
+ ? '显示用户消息、推理与工具活动。'
+ : 'User messages, reasoning, and tool activity.'
+ : active === 'Changes'
+ ? locale === 'zh'
+ ? '2 个文件已修改,+18 −6。'
+ : '2 files changed, +18 −6.'
+ : locale === 'zh'
+ ? '当前 Run 生成了 3 个 Artifact。'
+ : 'The current run produced 3 artifacts.'}
+
+
+
+
+ >
+ );
+}
+
+function TreePickerDemo({ locale }: DemoProps) {
+ const [expanded, setExpanded] = useState(true);
+ const [selected, setSelected] = useState(['src/auth/session.rs']);
+ const files = ['src/auth/session.rs', 'src/auth/token.rs', 'Cargo.toml'];
+
+ function toggle(file: string) {
+ setSelected((current) =>
+ current.includes(file)
+ ? current.filter((item) => item !== file)
+ : [...current, file],
+ );
+ }
+
+ return (
+ <>
+
+ {selected.length} selected
+
+
+
+
+
+ {locale === 'zh' ? '选择上下文文件' : 'Pick context files'}
+
+
+ {expanded &&
+ files.slice(0, 2).map((file) => (
+
+ ))}
+
+
+
+ >
+ );
+}
+
+type SortKey = 'name' | 'duration' | 'status';
+
+function DataTableDemo({ locale }: DemoProps) {
+ const [sort, setSort] = useState('duration');
+ const [selected, setSelected] = useState('read');
+ const rows = useMemo(
+ () => [
+ { name: 'read', duration: 42, status: 'done' },
+ { name: 'grep', duration: 118, status: 'done' },
+ { name: 'bash', duration: 934, status: 'running' },
+ ],
+ [],
+ );
+ const sorted = [...rows].sort((a, b) =>
+ sort === 'duration'
+ ? b.duration - a.duration
+ : a[sort].localeCompare(b[sort]),
+ );
+
+ return (
+ <>
+
+ {(['name', 'duration', 'status'] as SortKey[]).map((key) => (
+ setSort(key)}
+ >
+ {key}
+
+ ))}
+
+
+
+ {locale === 'zh' ? '工具调用' : 'Tool calls'}
+
+
+ | TOOL |
+ STATUS |
+ DURATION |
+
+
+
+ {sorted.map((row) => (
+ setSelected(row.name)}
+ >
+ | {row.name} |
+ {row.status} |
+ {row.duration} ms |
+
+ ))}
+
+
+
+ >
+ );
+}
+
+function DiffViewDemo({ locale: _locale }: DemoProps) {
+ const [view, setView] = useState<'unified' | 'split'>('unified');
+ const [whitespace, setWhitespace] = useState(false);
+
+ return (
+ <>
+
+ setView('unified')}
+ >
+ unified
+
+ setView('split')}
+ >
+ split
+
+ setWhitespace((value) => !value)}
+ >
+ whitespace
+
+
+
+
+
+ src/auth/session.rs
+ +4 −1
+
+
+
+ 42 match refresh_token(state).await {'{'}
+
+
+ 43- Err(_) => AuthError::Expired,
+
+
+ 43+ Err(AuthError::Expired) => {'{'}
+
+
+ 44+ {' '}session.require_login().await?;
+
+
+ 45+ {' '}session.retry_refresh().await
+ {whitespace ? '··' : ''}
+
+
+ 46+ {'}'}
+
+
+
+
+ >
+ );
+}
+
+function ToolLogViewDemo({ locale }: DemoProps) {
+ const [filter, setFilter] = useState<'all' | 'active'>('all');
+ const [open, setOpen] = useState('bash');
+ const entries = [
+ { id: 'read', state: 'done', text: 'read src/auth/session.rs' },
+ { id: 'grep', state: 'done', text: 'grep refresh_token' },
+ { id: 'bash', state: 'active', text: 'cargo test auth::session' },
+ ];
+
+ return (
+ <>
+
+ setFilter('all')}
+ >
+ all
+
+ setFilter('active')}
+ >
+ active
+
+
+
+
+
+ {entries
+ .filter((entry) => filter === 'all' || entry.state === 'active')
+ .map((entry) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+function AlertDemo({ locale }: DemoProps) {
+ const [kind, setKind] = useState<'info' | 'success' | 'warning' | 'error'>(
+ 'warning',
+ );
+ const copy = {
+ info:
+ locale === 'zh'
+ ? 'Session 已连接到当前 Workspace。'
+ : 'Session connected to the current workspace.',
+ success:
+ locale === 'zh'
+ ? '验证完成,4 项测试通过。'
+ : 'Verified: 4 tests passed.',
+ warning:
+ locale === 'zh'
+ ? '上下文已达到 80%,下一轮将自动压缩。'
+ : 'Context reached 80%; the next turn will compact it.',
+ error:
+ locale === 'zh'
+ ? '命令被当前权限规则拒绝。'
+ : 'The current permission policy denied the command.',
+ };
+
+ return (
+ <>
+
+ {(Object.keys(copy) as (keyof typeof copy)[]).map((item) => (
+ setKind(item)}
+ >
+ {item}
+
+ ))}
+
+
+
+
+ {kind === 'success'
+ ? '✓'
+ : kind === 'error'
+ ? '×'
+ : kind === 'warning'
+ ? '!'
+ : 'i'}
+
+
+
{kind.toUpperCase()}
+
{copy[kind]}
+
+
+
+ >
+ );
+}
+
+function ProgressDemo({ locale }: DemoProps) {
+ const [value, setValue] = useState(64);
+ const [running, setRunning] = useState(true);
+
+ return (
+ <>
+
+
+ setValue(Number(event.target.value))}
+ type="range"
+ value={value}
+ />
+ {value}%
+
+
+
+
+ {locale === 'zh' ? '运行测试' : 'Run tests'}
+ {running ? 'RUNNING' : 'PAUSED'}
+
+
+
+
+
+ {'■'.repeat(Math.round(value / 10))}
+ {'□'.repeat(10 - Math.round(value / 10))}
+ {value} / 100
+
+
+
+ >
+ );
+}
+
+function ToastDemo({ locale }: DemoProps) {
+ const [visible, setVisible] = useState(true);
+ const [kind, setKind] = useState<'saved' | 'copied'>('saved');
+
+ return (
+ <>
+
+ {
+ setKind('saved');
+ setVisible(true);
+ }}
+ >
+ saved
+
+ {
+ setKind('copied');
+ setVisible(true);
+ }}
+ >
+ copied
+
+
+
+
+
+
+ {locale === 'zh'
+ ? '终端内容保持可见。'
+ : 'Terminal content stays visible.'}
+
+ {visible && (
+
+ )}
+
+
+ >
+ );
+}
+
+function SessionStatusDemo({ locale }: DemoProps) {
+ const [mode, setMode] = useState<'code' | 'plan'>('code');
+ const [context, setContext] = useState(38);
+
+ return (
+ <>
+
+ setMode('code')}>
+ code
+
+ setMode('plan')}>
+ plan
+
+ setContext(Number(event.target.value))}
+ type="range"
+ value={context}
+ />
+
+
+
+
+ {locale === 'zh'
+ ? '当前 Session 正在运行。'
+ : 'The current Session is active.'}
+
+
+
+
+ >
+ );
+}
+
+function TaskComposerDemo({ locale }: DemoProps) {
+ const initial =
+ locale === 'zh'
+ ? '检查登录流程,修复 refresh token 失效后的恢复逻辑。'
+ : 'Inspect the login flow and repair recovery after refresh-token expiry.';
+ const [value, setValue] = useState(initial);
+ const [mode, setMode] = useState<'Code' | 'Plan'>('Code');
+ const [submitted, setSubmitted] = useState(false);
+
+ return (
+ <>
+
+ setMode('Code')}>
+ Code
+
+ setMode('Plan')}>
+ Plan
+
+ {value.length}/1200
+
+
+
+
+ >
+ );
+}
+
+function TaskLibraryDemo({ locale }: DemoProps) {
+ const tasks =
+ locale === 'zh'
+ ? ['修复登录会话续期', '整理发布说明', '检查 API 兼容性']
+ : [
+ 'Repair login session renewal',
+ 'Prepare release notes',
+ 'Check API compatibility',
+ ];
+ const [query, setQuery] = useState('');
+ const [active, setActive] = useState(tasks[0]);
+ const filtered = tasks.filter((task) =>
+ task.toLowerCase().includes(query.toLowerCase()),
+ );
+
+ return (
+ <>
+
+ setQuery(event.target.value)}
+ placeholder={locale === 'zh' ? '筛选任务' : 'Filter tasks'}
+ value={query}
+ />
+ {filtered.length} items
+
+
+
+
+ >
+ );
+}
+
+const streamEvents = [
+ ['reasoning', 'Inspect authentication call paths'],
+ ['read', 'Read src/auth/session.rs'],
+ ['search', 'Search refresh_token'],
+ ['test', 'Run auth::session tests'],
+] as const;
+
+function ExecutionStreamDemo({ locale }: DemoProps) {
+ const [count, setCount] = useState(2);
+
+ return (
+ <>
+
+
+
+ {count}/4
+
+
+
+
+ {locale === 'zh'
+ ? '修复 refresh token 失效后的恢复逻辑。'
+ : 'Repair recovery after refresh-token expiry.'}
+
+ {streamEvents.slice(0, count).map(([kind, text], index) => (
+
+ {index === count - 1 ? '◌' : '✓'}
+
+ {locale === 'zh'
+ ? {
+ reasoning: '检查认证调用路径',
+ read: '读取 src/auth/session.rs',
+ search: '搜索 refresh_token',
+ test: '运行 auth::session 测试',
+ }[kind]
+ : text}
+
+ {kind}
+
+ ))}
+
+
+ >
+ );
+}
+
+function ReasoningDisclosureDemo({ locale }: DemoProps) {
+ const [open, setOpen] = useState(true);
+ const [live, setLive] = useState(true);
+
+ return (
+ <>
+
+ setOpen((value) => !value)}>
+ expanded
+
+ setLive((value) => !value)}>
+ live
+
+
+
+
+
+ {open && (
+
+ {locale === 'zh'
+ ? '先定位 refresh token 的读取与续期分支,再确认失效状态怎样回到登录流程。'
+ : 'Locate refresh-token reads and renewal branches, then trace how expiry returns to login.'}
+
+ )}
+
+
+ >
+ );
+}
+
+function ToolCallTimelineDemo({ locale }: DemoProps) {
+ const [status, setStatus] = useState('running');
+ const [open, setOpen] = useState(true);
+
+ return (
+ <>
+
+
+
+
+ {open && (
+
+ {status === 'error'
+ ? 'test auth::session ... FAILED\nexit code: 101'
+ : status === 'success'
+ ? 'running 4 tests\n....\ntest result: ok. 4 passed'
+ : '$ cargo test auth::session\ncompiling a3s-code-core ...'}
+
+ )}
+
+
+ >
+ );
+}
+
+function PermissionDecisionDemo({ locale }: DemoProps) {
+ const [decision, setDecision] = useState<'allow' | 'deny' | null>(null);
+
+ return (
+ <>
+
+ decision: {decision ?? 'pending'}
+
+
+
+
+
+ ♢
+
+
+ {locale === 'zh' ? '需要你的确认' : 'Confirmation required'}
+
+
+ {locale === 'zh' ? '只影响当前操作' : 'This operation only'}
+
+
+
+
+
+
- {locale === 'zh' ? '即将执行' : 'Operation'}
+ - cargo test auth::session
+
+
+
- {locale === 'zh' ? '影响范围' : 'Scope'}
+ -
+ {locale === 'zh' ? '当前 Workspace' : 'Current workspace'}
+
+
+
+ {decision ? (
+
+ ) : (
+
+ )}
+
+
+ >
+ );
+}
+
+function RecoveryNoticeDemo({ locale }: DemoProps) {
+ const [state, setState] = useState<'ready' | 'retrying' | 'dismissed'>(
+ 'ready',
+ );
+
+ return (
+ <>
+
+
+ {state}
+
+
+
+ {state === 'dismissed' ? (
+
+ ) : (
+
+ !
+
+
+ {state === 'retrying'
+ ? locale === 'zh'
+ ? '正在恢复 Session…'
+ : 'Restoring Session…'
+ : locale === 'zh'
+ ? '上一次执行意外中断'
+ : 'The previous run was interrupted'}
+
+
+ {locale === 'zh'
+ ? '可以从最近一次 Checkpoint 继续。'
+ : 'Continue from the latest checkpoint.'}
+
+
+
+
+ )}
+
+
+ >
+ );
+}
+
+function PlanListDemo({ locale }: DemoProps) {
+ const [states, setStates] = useState(['done', 'doing', 'todo']);
+ const items =
+ locale === 'zh'
+ ? ['定位失效分支', '更新恢复逻辑', '补充回归测试']
+ : ['Locate expiry branch', 'Update recovery', 'Add regression test'];
+
+ function advance(index: number) {
+ const next: Record = {
+ todo: 'doing',
+ doing: 'done',
+ done: 'todo',
+ };
+ setStates((current) =>
+ current.map((state, itemIndex) =>
+ itemIndex === index ? next[state] : state,
+ ),
+ );
+ }
+
+ return (
+ <>
+
+
+ {states.filter((state) => state === 'done').length}/3 complete
+
+
+
+
+
+ {locale === 'zh' ? '计划' : 'Plan'}
+ {states.filter((state) => state === 'done').length} / 3
+
+ {items.map((item, index) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+function SubagentListDemo({ locale }: DemoProps) {
+ const [active, setActive] = useState('explorer');
+ const agents = [
+ { id: 'explorer', name: 'explorer', status: 'running', progress: 68 },
+ { id: 'reviewer', name: 'reviewer', status: 'waiting', progress: 0 },
+ { id: 'verifier', name: 'verifier', status: 'done', progress: 100 },
+ ];
+
+ return (
+ <>
+
+ selected: {active}
+
+
+
+
+ {locale === 'zh' ? '子任务' : 'Subagents'}
+ 3
+
+ {agents.map((agent) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+function DeliverySummaryDemo({ locale }: DemoProps) {
+ const [open, setOpen] = useState(true);
+
+ return (
+ <>
+
+ setOpen((value) => !value)}>
+ details
+
+
+
+
+ ✓
+ {locale === 'zh' ? '交付摘要' : 'DELIVERY SUMMARY'}
+ {locale === 'zh' ? '任务已完成' : 'Task complete'}
+
+ {locale === 'zh'
+ ? 'refresh token 失效后会重新要求登录。'
+ : 'Expired refresh tokens now require a new sign-in.'}
+
+
+ ✓ {locale === 'zh' ? '验证通过' : 'Verified'}
+ 2 {locale === 'zh' ? '个文件' : 'files'}
+ 4 {locale === 'zh' ? '项测试' : 'tests'}
+
+
+ {open && (
+
+ -
+ src/auth/session.rs +12 −4
+
+ -
+ tests/auth_session.rs +6 −2
+
+
+ )}
+
+
+ >
+ );
+}
+
+function ArtifactEntriesDemo({ locale }: DemoProps) {
+ const artifacts = [
+ { name: 'test-output.txt', type: 'TEXT', size: '4.2 KB' },
+ { name: 'auth-flow.svg', type: 'IMAGE', size: '18 KB' },
+ { name: 'run-trace.json', type: 'JSON', size: '31 KB' },
+ ];
+ const [selected, setSelected] = useState(artifacts[0]);
+
+ return (
+ <>
+
+ {selected.name}
+
+
+
+
+
+ {selected.type}
+ {selected.name}
+ artifact://run-01/{selected.name}
+
+
+
+ >
+ );
+}
+
+function ChangesInspectorDemo({ locale }: DemoProps) {
+ const [file, setFile] = useState('session.rs');
+ const [view, setView] = useState<'unified' | 'split'>('unified');
+
+ return (
+ <>
+
+ setView('unified')}
+ >
+ unified
+
+ setView('split')}
+ >
+ split
+
+
+
+
+
+
+ @@ -42,2 +42,5 @@
+ - return Err(AuthError::Expired)
+ + session.require_login().await?;
+ + session.retry_refresh().await
+
+
+
+ >
+ );
+}
+
+function WorkspaceEditorDemo({ locale }: DemoProps) {
+ const [active, setActive] = useState('session.rs');
+ const [dirty, setDirty] = useState(false);
+ const [line, setLine] = useState('session.require_login().await?;');
+
+ return (
+ <>
+
+ {dirty ? 'modified' : 'saved'}
+
+
+
+
+
+
+ 43
+
+
+
+
+ >
+ );
+}
+
+function MemoryGraphDemo({ locale }: DemoProps) {
+ const [mode, setMode] = useState<'graph' | 'timeline'>('graph');
+ const [active, setActive] = useState('session');
+
+ return (
+ <>
+
+ setMode('graph')}
+ >
+ graph
+
+ setMode('timeline')}
+ >
+ timeline
+
+
+
+
+ {mode === 'graph' ? (
+ <>
+
+
+ {active}
+ {locale === 'zh'
+ ? ' · 点击节点查看关联记忆'
+ : ' · select a node to inspect relations'}
+
+ >
+ ) : (
+
+ -
+ 09:14 Session created
+
+ -
+ 09:16 Procedure recalled
+
+ -
+ 09:21 Verification saved
+
+
+ )}
+
+
+ >
+ );
+}
+
+const demos: Record ReactNode> = {
+ ActivityBlock: ActivityBlockDemo,
+ Alert: AlertDemo,
+ ArtifactEntries: ArtifactEntriesDemo,
+ ChangesInspector: ChangesInspectorDemo,
+ Checklist: ChecklistDemo,
+ ChoicePrompt: ChoicePromptDemo,
+ Confirm: ConfirmDemo,
+ DataTable: DataTableDemo,
+ DeliverySummary: DeliverySummaryDemo,
+ DiffView: DiffViewDemo,
+ ExecutionStream: ExecutionStreamDemo,
+ MemoryGraph: MemoryGraphDemo,
+ PermissionDecision: PermissionDecisionDemo,
+ Progress: ProgressDemo,
+ ReasoningDisclosure: ReasoningDisclosureDemo,
+ RecoveryNotice: RecoveryNoticeDemo,
+ SessionStatus: SessionStatusDemo,
+ TaskComposer: TaskComposerDemo,
+ TaskLibrary: TaskLibraryDemo,
+ TaskRuntimePlanList: PlanListDemo,
+ TaskRuntimeSubagentList: SubagentListDemo,
+ Tabs: TabsDemo,
+ TextInput: TextInputDemo,
+ Toast: ToastDemo,
+ ToolCallTimeline: ToolCallTimelineDemo,
+ ToolLogView: ToolLogViewDemo,
+ TreePicker: TreePickerDemo,
+ WorkspaceEditor: WorkspaceEditorDemo,
+};
+
+export default function A3SComponentDemo({ name }: { name: string }) {
+ const locale: Locale = useLang() === 'zh' ? 'zh' : 'en';
+ const Demo = demos[name];
+ const surface = tuiNames.has(name) ? 'TUI' : 'WEB';
+
+ if (!Demo) {
+ return (
+
+ Unknown component: {name}
+
+ );
+ }
+
+ return (
+
+
+
+
+ {labels[locale].live}
+
+ {name}
+ {surface}
+
+
+
+
+
+
+ );
+}
diff --git a/website/theme/components/AgentBuildingBlocks.tsx b/website/theme/components/AgentBuildingBlocks.tsx
index 1165e8c..5bc6cc2 100644
--- a/website/theme/components/AgentBuildingBlocks.tsx
+++ b/website/theme/components/AgentBuildingBlocks.tsx
@@ -259,10 +259,10 @@ const groups: BuildingBlockGroup[] = [
{
name: 'A3S TUI / Web',
description: {
- zh: '把同一套运行事件显示成终端或桌面界面。',
- en: 'Render the same runtime events in terminal or desktop interfaces.',
+ zh: '逐个查看终端与网页组件怎样承接运行事件。',
+ en: 'Inspect how individual terminal and Web components render runtime events.',
},
- path: '/guide/playground/',
+ path: '/guide/components/',
},
],
},
diff --git a/website/theme/components/HomeLayout.tsx b/website/theme/components/HomeLayout.tsx
index 0b3ca10..fb5c1ca 100644
--- a/website/theme/components/HomeLayout.tsx
+++ b/website/theme/components/HomeLayout.tsx
@@ -1,6 +1,17 @@
import { useState } from 'react';
-import type { CSSProperties } from 'react';
import { useLang, useSite, useVersion, withBase } from '@rspress/core/runtime';
+import {
+ InnerLine,
+ Pre,
+ type AnnotationHandler,
+ type HighlightedCode,
+} from 'codehike/code';
+import {
+ Selectable,
+ SelectionProvider,
+ useSelectedIndex,
+} from 'codehike/utils/selection';
+import runtimeTutorialData from '../generated/runtime-tutorial.json';
type Locale = 'zh' | 'en';
@@ -16,6 +27,22 @@ type Feature = {
tags: string[];
};
+type RuntimeTutorialStep = {
+ id: string;
+ layer: string;
+ filename: string;
+ title: Localized;
+ body: Localized;
+ note: Localized;
+ tags: string[];
+ focus: [number, number];
+ code: string;
+ highlighted: HighlightedCode;
+};
+
+const runtimeTutorialSteps =
+ runtimeTutorialData as unknown as RuntimeTutorialStep[];
+
const installCommands = [
{
id: 'terminal',
@@ -281,7 +308,7 @@ const copy = {
titleAccent: '接进你的产品',
subtitle:
'A3S Code 是一个用 Rust 写的 Agent 运行时。它负责 Agent Loop、工具调用、权限确认、事件流和任务恢复,并提供 Rust、Node.js、Python API。',
- docs: '查看文档',
+ docs: '开始使用',
github: '查看 GitHub',
copy: '复制',
copied: '已复制',
@@ -300,9 +327,9 @@ const copy = {
whyBody:
'模型可以读写文件、运行命令和操作 Git,但每次调用仍会先检查参数和权限。你的应用决定给它哪些工具,也能拿到完整的执行记录。',
architectureEyebrow: 'HOW IT RUNS',
- architectureTitle: '一层一层看清 Agent 在做什么。',
+ architectureTitle: '用一段真实代码,走完 Runtime 的六层职责。',
architectureBody:
- '从产品入口到 AgentSession、模型、权限检查、Workspace 工具和运行记录,每一层只负责一件事。把鼠标移到分层图上,可以查看它们各自的作用。',
+ '向下滚动或点击步骤。代码会逐步补全,右侧分层图也会同步标出这一段由谁负责。',
architectureAlt:
'A3S Code 运行时分层图,展示接入方式、AgentSession、上下文、权限检查、工具与运行记录。',
capabilitiesEyebrow: 'WHAT YOU GET',
@@ -313,6 +340,13 @@ const copy = {
surfacesTitle: '想直接用,或接进自己的应用,都可以。',
surfacesBody:
'终端版可以立即运行;Rust crate、Node.js 和 Python 包提供同一套 Runtime,适合 IDE、Runner、服务端和自己的界面。',
+ componentsEyebrow: 'BUILD THE INTERFACE',
+ componentsTitle: '先看组件本身,再决定怎样组合。',
+ componentsBody:
+ 'A3S TUI 与 A3S Web 的核心组件都有独立示例。可以切状态、改输入、做选择,不需要先跑完整任务。',
+ componentsLink: '打开组件文档',
+ componentsTui: '终端里的输入、执行、Diff 与反馈组件。',
+ componentsWeb: '网页里的任务、权限、结果与工作区组件。',
boundariesEyebrow: 'WHAT STAYS YOURS',
boundariesTitle: '执行交给 Runtime,账号和权限留在你的应用里。',
boundaryItems: [
@@ -327,15 +361,19 @@ const copy = {
boundaryHostLabel: '你的应用',
boundaryHostRole: '账号、权限与界面',
stackTitle: 'A3S CODE / 分层图',
- stackHint: '移入查看这一层',
+ stackHint: '滚动或点击切换',
stackTop: '产品',
stackBottom: '记录',
+ tutorialStep: '步骤',
+ tutorialCode: '代码',
+ tutorialLayers: '当前负责的层',
+ tutorialScroll: '继续向下',
ctaEyebrow: 'TRY IT',
ctaTitle: '先在一个项目里跑起来。',
ctaBody:
'安装 a3s code 直接体验,或者选择 Rust、Node.js、Python 包接入自己的产品。',
ctaPrimary: '查看快速开始',
- ctaSecondary: '打开 Playground',
+ ctaSecondary: '查看组件',
footer: 'MIT 开源 · Rust 编写 · 支持 Terminal / Rust / Node.js / Python',
},
en: {
@@ -344,7 +382,7 @@ const copy = {
titleAccent: 'to your product',
subtitle:
'A3S Code is a Rust agent runtime. It handles the agent loop, tool calls, approval, event streaming, and recovery, with APIs for Rust, Node.js, and Python.',
- docs: 'Read the docs',
+ docs: 'Get started',
github: 'View on GitHub',
copy: 'Copy',
copied: 'Copied',
@@ -363,9 +401,9 @@ const copy = {
whyBody:
'The model can edit files, run commands, and operate Git, but every call is checked first. Your application decides which tools it gets and receives the full execution stream.',
architectureEyebrow: 'HOW IT RUNS',
- architectureTitle: 'See what each part of the runtime does.',
+ architectureTitle: 'Walk through all six runtime layers in real code.',
architectureBody:
- 'The stack runs from product entry points through AgentSession, models, permission checks, workspace tools, and run records. Hover a layer to inspect its job.',
+ 'Scroll or choose a step. The example grows with you, while the layer map marks the part responsible for each line.',
architectureAlt:
'A3S Code runtime layers showing entry points, AgentSession, context, permission checks, tools, and run records.',
capabilitiesEyebrow: 'WHAT YOU GET',
@@ -376,6 +414,14 @@ const copy = {
surfacesTitle: 'Run it in a terminal or embed it in your app.',
surfacesBody:
'The terminal app is ready to use. The Rust crate, Node.js package, and Python package bring the same runtime to an IDE, runner, server, or custom UI.',
+ componentsEyebrow: 'BUILD THE INTERFACE',
+ componentsTitle: 'Inspect each component before composing a screen.',
+ componentsBody:
+ 'Core A3S TUI and A3S Web components have isolated examples. Change state, edit inputs, and make decisions without running a complete task.',
+ componentsLink: 'Open component docs',
+ componentsTui:
+ 'Terminal input, execution, diff, navigation, and feedback components.',
+ componentsWeb: 'Web task, permission, result, and workspace components.',
boundariesEyebrow: 'WHAT STAYS YOURS',
boundariesTitle: 'The runtime executes. Your app controls access.',
boundaryItems: [
@@ -390,15 +436,19 @@ const copy = {
boundaryHostLabel: 'YOUR APP',
boundaryHostRole: 'OWNS UI + ACCESS',
stackTitle: 'A3S CODE / RUNTIME LAYERS',
- stackHint: 'HOVER A LAYER',
+ stackHint: 'SCROLL OR SELECT',
stackTop: 'PRODUCT',
stackBottom: 'RECORDS',
+ tutorialStep: 'STEP',
+ tutorialCode: 'CODE',
+ tutorialLayers: 'ACTIVE LAYER',
+ tutorialScroll: 'KEEP SCROLLING',
ctaEyebrow: 'TRY IT',
ctaTitle: 'Try it in a real repository.',
ctaBody:
'Install a3s code to start immediately, or choose the Rust, Node.js, or Python package for your own product.',
ctaPrimary: 'Open the quick start',
- ctaSecondary: 'Open the playground',
+ ctaSecondary: 'Browse components',
footer: 'MIT licensed · Built in Rust · Terminal / Rust / Node.js / Python',
},
};
@@ -528,96 +578,215 @@ function RuntimeDiagram({ labels }: { labels: (typeof copy)[Locale] }) {
);
}
-type RuntimeLayerStyle = CSSProperties & {
- '--layer-index': number;
+const runtimeFocusHandler: AnnotationHandler = {
+ name: 'focus',
+ onlyIfAnnotated: true,
+ Line: (props) => (
+
+ ),
+ AnnotatedLine: ({ annotation: _annotation, ...props }) => (
+
+ ),
};
-function LayeredRuntime({
- locale,
+function TutorialCode({
labels,
+ step,
}: {
- locale: Locale;
labels: (typeof copy)[Locale];
+ step: RuntimeTutorialStep;
}) {
- const [activeId, setActiveId] = useState('governance');
- const activeLayer =
- runtimeLayers.find((layer) => layer.id === activeId) ?? runtimeLayers[3];
+ const [copied, setCopied] = useState(false);
+
+ async function copyCode() {
+ await navigator.clipboard.writeText(step.code);
+ setCopied(true);
+ window.setTimeout(() => setCopied(false), 1400);
+ }
return (
- setActiveId('governance')}
- >
-
-
{labels.stackTitle}
+
+
- {labels.stackHint}
+
+ {step.filename}
-
-
-
- {labels.stackTop}
-
- {labels.stackBottom}
-
+
RUST
+
+
+
+
+ );
+}
+
+function RuntimeLayerRail({
+ activeIndex,
+ labels,
+ locale,
+ setActiveIndex,
+}: {
+ activeIndex: number;
+ labels: (typeof copy)[Locale];
+ locale: Locale;
+ setActiveIndex: (index: number) => void;
+}) {
+ return (
+
+
+ {labels.tutorialLayers}
+ {labels.stackHint}
+
+
{runtimeLayers.map((layer, index) => (
))}
- {runtimeLayers.map((layer, index) => (
-
setActiveId(layer.id)}
- style={{ '--layer-index': index } as RuntimeLayerStyle}
- >
- {layer.code}
-
-
- ))}
-
-
- {String(runtimeLayers.indexOf(activeLayer) + 1).padStart(2, '0')}
-
-
-
{activeLayer.code}
-
{localeValue(activeLayer.title, locale)}
-
{localeValue(activeLayer.body, locale)}
-
-
- {activeLayer.tags.map((tag) => (
- {tag}
- ))}
+
+ );
+}
+
+function RuntimeTutorialStage({
+ locale,
+ labels,
+}: {
+ locale: Locale;
+ labels: (typeof copy)[Locale];
+}) {
+ const [selectedIndex, setSelectedIndex] = useSelectedIndex();
+ const activeIndex = Math.min(
+ Math.max(selectedIndex, 0),
+ runtimeTutorialSteps.length - 1,
+ );
+ const step = runtimeTutorialSteps[activeIndex];
+
+ return (
+
+
+ {labels.stackTitle}
+
+ {labels.tutorialStep} {String(activeIndex + 1).padStart(2, '0')} /{' '}
+ {String(runtimeTutorialSteps.length).padStart(2, '0')}
+
+
+
+
+
+
+
+
{step.layer}
+
{localeValue(step.note, locale)}
+
);
}
+function RuntimeTutorialSteps({
+ labels,
+ locale,
+}: {
+ labels: (typeof copy)[Locale];
+ locale: Locale;
+}) {
+ const [, setSelectedIndex] = useSelectedIndex();
+
+ return (
+
+ {runtimeTutorialSteps.map((step, index) => (
+
+
+
+
+ {labels.tutorialLayers}
+ {localeValue(runtimeLayers[index].title, locale)}
+
+
+
+
+ ))}
+
+ );
+}
+
+function RuntimeTutorial({
+ labels,
+ locale,
+}: {
+ labels: (typeof copy)[Locale];
+ locale: Locale;
+}) {
+ return (
+
+
+
+
+ );
+}
+
function MarkdownHome({
locale,
labels,
@@ -759,21 +928,23 @@ export function HomeLayout() {
-
-
-
-
-
+
@@ -805,6 +976,55 @@ export function HomeLayout() {
+
+
@@ -876,7 +1096,7 @@ export function HomeLayout() {
{labels.ctaSecondary}
diff --git a/website/theme/components/TuiPlayground.tsx b/website/theme/components/TuiPlayground.tsx
deleted file mode 100644
index 6063798..0000000
--- a/website/theme/components/TuiPlayground.tsx
+++ /dev/null
@@ -1,505 +0,0 @@
-import { type CSSProperties, useState } from 'react';
-import { useLang } from '@rspress/core/runtime';
-
-type Locale = 'zh' | 'en';
-type SceneId = 'session' | 'diff' | 'workspace' | 'components';
-type ThemeId = 'dark' | 'light' | 'catppuccin' | 'tokyo-night';
-
-type Theme = {
- id: ThemeId;
- name: string;
- palette: {
- bg: string;
- panel: string;
- panelStrong: string;
- text: string;
- muted: string;
- line: string;
- blue: string;
- green: string;
- amber: string;
- red: string;
- purple: string;
- };
-};
-
-const themes: Theme[] = [
- {
- id: 'dark',
- name: 'Dark',
- palette: {
- bg: '#090b10',
- panel: '#0f1218',
- panelStrong: '#171b24',
- text: '#e8edf4',
- muted: '#7f8999',
- line: '#29303c',
- blue: '#6ca3ff',
- green: '#46d39a',
- amber: '#efb354',
- red: '#ef767a',
- purple: '#b493ff',
- },
- },
- {
- id: 'light',
- name: 'Light',
- palette: {
- bg: '#f4f5f7',
- panel: '#ffffff',
- panelStrong: '#e9ebef',
- text: '#1d222b',
- muted: '#687180',
- line: '#d5d9df',
- blue: '#2465d8',
- green: '#16845f',
- amber: '#a8650c',
- red: '#c33f48',
- purple: '#6f50bf',
- },
- },
- {
- id: 'catppuccin',
- name: 'Catppuccin',
- palette: {
- bg: '#1e1e2e',
- panel: '#181825',
- panelStrong: '#313244',
- text: '#cdd6f4',
- muted: '#9399b2',
- line: '#45475a',
- blue: '#89b4fa',
- green: '#a6e3a1',
- amber: '#f9e2af',
- red: '#f38ba8',
- purple: '#cba6f7',
- },
- },
- {
- id: 'tokyo-night',
- name: 'Tokyo Night',
- palette: {
- bg: '#16161e',
- panel: '#1a1b26',
- panelStrong: '#24283b',
- text: '#c0caf5',
- muted: '#787c99',
- line: '#3b4261',
- blue: '#7aa2f7',
- green: '#9ece6a',
- amber: '#e0af68',
- red: '#f7768e',
- purple: '#bb9af7',
- },
- },
-];
-
-const copy = {
- zh: {
- aria: 'A3S TUI 组件预览',
- themes: '主题',
- scenes: {
- session: '执行',
- diff: '代码改动',
- workspace: 'Workspace',
- components: '组件',
- },
- demo: '文档预览',
- noBackend: '这里演示组件状态,不会运行命令或连接模型。',
- taskTitle: '修复登录会话续期',
- userPrompt:
- '检查登录流程,修复 refresh token 失效后没有重新登录的问题,并补上测试。',
- thinking: '正在检查 session 与 token 的调用路径',
- readDone: '已读取 src/auth/session.rs',
- searchDone: '找到 4 处 refresh_token 引用',
- testRunning: '正在运行 auth::session 测试',
- checklist: '任务清单',
- items: ['定位失效分支', '更新会话恢复逻辑', '补充回归测试'],
- changed: '2 个文件已修改',
- diffSummary: '+18 -6',
- workspaceTitle: '项目文件',
- previewTitle: 'session.rs',
- componentsTitle: '同一框架中的组件',
- componentsHint: '选择一项查看终端组件如何组合。',
- status: 'default · medium',
- keys: 'Ctrl+T transcript /help commands Esc close',
- },
- en: {
- aria: 'A3S TUI component preview',
- themes: 'Themes',
- scenes: {
- session: 'Run',
- diff: 'Changes',
- workspace: 'Workspace',
- components: 'Components',
- },
- demo: 'Docs preview',
- noBackend:
- 'This demonstrates component states; it does not run commands or connect to a model.',
- taskTitle: 'Repair login session renewal',
- userPrompt:
- 'Inspect the login flow, fix re-authentication after a refresh token expires, and add tests.',
- thinking: 'Inspecting session and token call paths',
- readDone: 'Read src/auth/session.rs',
- searchDone: 'Found 4 refresh_token references',
- testRunning: 'Running auth::session tests',
- checklist: 'Checklist',
- items: [
- 'Locate the expiry branch',
- 'Update session recovery',
- 'Add a regression test',
- ],
- changed: '2 files changed',
- diffSummary: '+18 -6',
- workspaceTitle: 'Project files',
- previewTitle: 'session.rs',
- componentsTitle: 'Components in the same framework',
- componentsHint:
- 'Select an item to see how terminal components fit together.',
- status: 'default · medium',
- keys: 'Ctrl+T transcript /help commands Esc close',
- },
-};
-
-const componentSets = [
- {
- name: 'Navigation',
- components: 'MenuPanel · Tabs · Tree · TreePicker · Breadcrumb',
- preview: 'menu',
- },
- {
- name: 'Agent activity',
- components:
- 'ActivityBlock · Checklist · TaskQueue · SubagentTracker · Timeline',
- preview: 'activity',
- },
- {
- name: 'Tools & output',
- components:
- 'ToolLogView · ToolStatusLine · DiffView · OutputBlock · LogView',
- preview: 'tools',
- },
- {
- name: 'Input & feedback',
- components: 'PromptLine · Textarea · ChoicePrompt · Confirm · Toast',
- preview: 'input',
- },
-];
-
-function terminalStyle(theme: Theme): CSSProperties {
- return {
- '--tui-bg': theme.palette.bg,
- '--tui-panel': theme.palette.panel,
- '--tui-panel-strong': theme.palette.panelStrong,
- '--tui-text': theme.palette.text,
- '--tui-muted': theme.palette.muted,
- '--tui-line': theme.palette.line,
- '--tui-blue': theme.palette.blue,
- '--tui-green': theme.palette.green,
- '--tui-amber': theme.palette.amber,
- '--tui-red': theme.palette.red,
- '--tui-purple': theme.palette.purple,
- } as CSSProperties;
-}
-
-export default function TuiPlayground() {
- const locale: Locale = useLang() === 'zh' ? 'zh' : 'en';
- const labels = copy[locale];
- const [themeId, setThemeId] = useState
('dark');
- const [scene, setScene] = useState('session');
- const [checked, setChecked] = useState([true, true, false]);
- const [componentIndex, setComponentIndex] = useState(1);
- const theme = themes.find((item) => item.id === themeId) ?? themes[0];
-
- const toggleCheck = (index: number) => {
- setChecked((current) =>
- current.map((value, itemIndex) => (itemIndex === index ? !value : value)),
- );
- };
-
- return (
-
-
-
-
- A3S TUI
- {labels.demo}
-
-
- {themes.map((item) => (
-
- ))}
-
-
-
-
- {(Object.keys(labels.scenes) as SceneId[]).map((id) => (
-
- ))}
-
-
-
-
- A3S CODE
- ~/workspaces/a3s-code
- 80 × 24
-
-
-
-
-
-
- {scene === 'session' && (
-
-
-
-
- {labels.taskTitle}
-
- 00:42
-
-
-
YOU
-
{labels.userPrompt}
-
-
-
- ◆ {labels.thinking}
-
-
- ✓ {labels.readDone}
-
-
- ✓ {labels.searchDone}
-
-
- ◌ {labels.testRunning}
-
-
-
- {labels.checklist}
- {labels.items.map((item, index) => (
-
- ))}
-
-
- )}
-
- {scene === 'diff' && (
-
-
- DIFF VIEW
- {labels.changed}
- {labels.diffSummary}
-
-
- ▾
- src/auth/session.rs
- +12 -4
-
-
-
- 42 {' '}match refresh_token(state).await {'{'}
-
-
- 43- {' '}Err(_) => return
- Err(AuthError::Expired),
-
-
- 43+ {' '}Err(AuthError::Expired) => {'{'}
-
-
- 44+ {' '}session.require_login().await?;
-
-
- 45+ {' '}session.retry_refresh().await
-
-
- 46+ {' }\n'}
-
-
- 47 {' '}result => result,
-
-
- 48 {' }'}
-
-
-
- ›
- tests/auth_session.rs
- +6 -2
-
-
- )}
-
- {scene === 'workspace' && (
-
-
-
-
- ▾ a3s-code
-
-
- │ ▾ src
-
-
- │ │ session.rs
-
-
- │ │ permissions.rs
-
-
- │ └ tools.rs
-
-
- ├ ▸ tests
-
-
- └ Cargo.toml
-
-
-
-
- {labels.previewTitle}
- Rust
-
-
-
- 1
- pub async fn refresh(
-
-
- 2
- {' '}session: &mut Session,
-
-
- 3) -> Result<Token> {'{'}
-
-
- 4
- {' '}session.ensure_active().await?;
-
-
- 5
- {' '}session.token().await
-
-
- 6
- {'\u007d'}
-
-
-
-
- )}
-
- {scene === 'components' && (
-
-
- {labels.componentsTitle}
- {labels.componentsHint}
-
-
-
-
- {componentSets[componentIndex].name}
- {componentSets[componentIndex].components}
-
- READY
- ■■■■■■□□ 75%
- ✓ workspace checked
- › Continue
-
-
-
-
- )}
-
-
-
-
-
-
- {labels.noBackend}
-
- );
-}
diff --git a/website/theme/components/WebPlayground.tsx b/website/theme/components/WebPlayground.tsx
deleted file mode 100644
index c1dc183..0000000
--- a/website/theme/components/WebPlayground.tsx
+++ /dev/null
@@ -1,474 +0,0 @@
-import { useState } from 'react';
-import { useLang } from '@rspress/core/runtime';
-
-type Locale = 'zh' | 'en';
-type ViewId = 'compose' | 'run' | 'permission' | 'result';
-type Decision = 'allowed' | 'denied' | null;
-
-const copy = {
- zh: {
- aria: 'A3S Web 任务流程预览',
- demo: '文档预览',
- noBackend:
- '这里演示 A3S Web 的组件与状态切换,不会发送请求、修改文件或连接模型。',
- tabs: {
- compose: '准备',
- run: '执行',
- permission: '确认',
- result: '结果',
- },
- taskLibrary: '任务',
- newTask: '新任务',
- sessions: ['修复登录会话续期', '整理发布说明', '检查 API 兼容性'],
- startTitle: '今天要处理什么?',
- startHint: '描述任务,也可以加入文件、Skill 和 Workspace。',
- prompt:
- '检查登录流程,修复 refresh token 失效后没有重新登录的问题,并补上测试。',
- attach: '添加上下文',
- mode: 'Code',
- effort: 'Medium',
- send: '运行演示',
- runningTitle: '修复登录会话续期',
- runningHint: 'A3S Code 正在处理当前 Workspace',
- instruction:
- '检查登录流程,修复 refresh token 失效后没有重新登录的问题,并补上测试。',
- reasoningTitle: '检查认证调用路径',
- reasoning:
- '先定位 refresh token 的读取与续期分支,再检查失效状态如何回到登录流程。',
- toolRead: '读取 src/auth/session.rs',
- toolSearch: '搜索 refresh_token',
- toolTest: '运行 auth::session 测试',
- plan: '计划',
- planItems: ['定位失效分支', '更新会话恢复逻辑', '补充回归测试'],
- nextPermission: '查看确认组件',
- permissionTitle: '需要你的确认',
- permissionHint: '只影响当前这一次操作',
- operation: '即将执行',
- operationValue: '运行 cargo test auth::session',
- reason: '为什么需要',
- reasonValue: '该命令会启动本地进程,当前权限规则要求先确认。',
- scope: '影响范围',
- scopeValue: '当前任务的 Workspace',
- risk: '需要注意',
- riskValue: '测试可能创建临时构建文件,不会访问 Workspace 之外的路径。',
- deny: '拒绝',
- allow: '允许一次',
- denied: '已拒绝,本次操作不会执行。',
- reset: '重新演示',
- resultTitle: '任务已完成',
- resultHint: '登录会话现在会在 refresh token 失效后要求重新登录。',
- verified: '验证通过',
- filesChanged: '2 个文件已修改',
- tests: '4 项测试通过',
- openChanges: '查看改动',
- delivery: '交付摘要',
- changedFiles: ['src/auth/session.rs', 'tests/auth_session.rs'],
- },
- en: {
- aria: 'A3S Web task-flow preview',
- demo: 'Docs preview',
- noBackend:
- 'This demonstrates A3S Web components and state changes; it does not send requests, edit files, or connect to a model.',
- tabs: {
- compose: 'Prepare',
- run: 'Run',
- permission: 'Confirm',
- result: 'Result',
- },
- taskLibrary: 'Tasks',
- newTask: 'New task',
- sessions: [
- 'Repair login session renewal',
- 'Prepare release notes',
- 'Check API compatibility',
- ],
- startTitle: 'What would you like to work on?',
- startHint:
- 'Describe the task and optionally add files, Skills, and a Workspace.',
- prompt:
- 'Inspect the login flow, fix re-authentication after a refresh token expires, and add tests.',
- attach: 'Add context',
- mode: 'Code',
- effort: 'Medium',
- send: 'Run demo',
- runningTitle: 'Repair login session renewal',
- runningHint: 'A3S Code is working in the current Workspace',
- instruction:
- 'Inspect the login flow, fix re-authentication after a refresh token expires, and add tests.',
- reasoningTitle: 'Inspect authentication call paths',
- reasoning:
- 'First locate refresh-token reads and renewal branches, then trace how an expired state returns to login.',
- toolRead: 'Read src/auth/session.rs',
- toolSearch: 'Search refresh_token',
- toolTest: 'Run auth::session tests',
- plan: 'Plan',
- planItems: [
- 'Locate the expiry branch',
- 'Update session recovery',
- 'Add a regression test',
- ],
- nextPermission: 'Open confirmation',
- permissionTitle: 'Your confirmation is required',
- permissionHint: 'This applies only to this operation',
- operation: 'About to run',
- operationValue: 'cargo test auth::session',
- reason: 'Why this is needed',
- reasonValue:
- 'This command starts a local process, so the current permission rules require confirmation.',
- scope: 'Scope',
- scopeValue: 'The current task Workspace',
- risk: 'What to know',
- riskValue:
- 'The test may create temporary build files, but it cannot access paths outside the Workspace.',
- deny: 'Deny',
- allow: 'Allow once',
- denied: 'Denied. This operation will not run.',
- reset: 'Start over',
- resultTitle: 'Task complete',
- resultHint:
- 'The login session now asks the user to sign in again after the refresh token expires.',
- verified: 'Verified',
- filesChanged: '2 files changed',
- tests: '4 tests passed',
- openChanges: 'Review changes',
- delivery: 'Delivery summary',
- changedFiles: ['src/auth/session.rs', 'tests/auth_session.rs'],
- },
-};
-
-function BrandMark() {
- return (
-
- );
-}
-
-export default function WebPlayground() {
- const locale: Locale = useLang() === 'zh' ? 'zh' : 'en';
- const labels = copy[locale];
- const [view, setView] = useState('compose');
- const [decision, setDecision] = useState(null);
- const [prompt, setPrompt] = useState(labels.prompt);
-
- const restart = () => {
- setDecision(null);
- setView('compose');
- setPrompt(labels.prompt);
- };
-
- const allow = () => {
- setDecision('allowed');
- setView('result');
- };
-
- return (
-
-
-
-
-
-
-
-
-
- {view === 'compose' && (
-
-
-
-
-
-
{labels.startTitle}
-
{labels.startHint}
-
-
-
-
- )}
-
- {view === 'run' && (
-
-
-
-
-
- {labels.instruction}
-
-
-
- ◇
- {labels.reasoningTitle}
- 12s
-
- {labels.reasoning}
-
-
- ✓
- {labels.toolRead}
- session.rs
-
-
- ✓
- {labels.toolSearch}
- 4 {locale === 'zh' ? '处结果' : 'matches'}
-
-
- ◌
- {labels.toolTest}
- cargo test
-
-
-
-
-
-
- )}
-
- {view === 'permission' && (
-
-
-
-
-
- ♢
-
- {labels.permissionTitle}
- {labels.permissionHint}
-
-
-
-
-
- {labels.operation}
- - {labels.operationValue}
-
-
-
- {labels.reason}
- - {labels.reasonValue}
-
-
-
- {labels.scope}
- - {labels.scopeValue}
-
-
-
- {labels.risk}
- - {labels.riskValue}
-
-
- {decision === 'denied' ? (
-
- ) : (
-
- )}
-
-
-
- )}
-
- {view === 'result' && (
-
-
✓
-
{labels.delivery}
-
{labels.resultTitle}
-
{labels.resultHint}
-
-
- ✓ {labels.verified}
-
- {labels.filesChanged}
- {labels.tests}
-
-
-
- {labels.openChanges}
- +18 −6
-
- {labels.changedFiles.map((file, index) => (
-
- {index === 0 ? 'RS' : 'TS'}
- {file}
- {index === 0 ? '+12 −4' : '+6 −2'}
-
- ))}
-
-
-
- )}
-
-
-
- {labels.noBackend}
-
- );
-}
diff --git a/website/theme/generated/runtime-tutorial.json b/website/theme/generated/runtime-tutorial.json
new file mode 100644
index 0000000..9e7adf7
--- /dev/null
+++ b/website/theme/generated/runtime-tutorial.json
@@ -0,0 +1,1046 @@
+[
+ {
+ "id": "surfaces",
+ "layer": "L01 / SURFACES",
+ "filename": "src/main.rs",
+ "title": { "zh": "先选一个接入入口", "en": "Choose an entry point" },
+ "body": {
+ "zh": "终端可以直接跑;要嵌进产品,就从 Rust、Node.js 或 Python SDK 开始。下面用 Rust 把完整路径走一遍。",
+ "en": "Run the terminal app directly, or embed the Rust, Node.js, or Python SDK. The walkthrough below follows the Rust path."
+ },
+ "note": {
+ "zh": "同一个 Runtime,不同的产品外壳。",
+ "en": "One runtime behind different product surfaces."
+ },
+ "tags": ["Terminal", "Rust", "Node.js", "Python"],
+ "focus": [1, 6],
+ "code": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "surfaces",
+ "fromLineNumber": 1,
+ "toLineNumber": 6
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ },
+ {
+ "id": "session",
+ "layer": "L02 / AGENT API",
+ "filename": "src/main.rs",
+ "title": {
+ "zh": "把 Agent 绑到一个项目",
+ "en": "Bind the agent to a project"
+ },
+ "body": {
+ "zh": "Agent 读取 ACL 和共享能力;AgentSession 负责当前 Workspace 与这一段对话。异步 build 会在第一轮开始前准备好相关资源。",
+ "en": "Agent loads ACL and shared capabilities. AgentSession owns the current workspace and conversation, resolving resources before the first turn."
+ },
+ "note": {
+ "zh": "Agent 可以复用,Session 与 Workspace 一一对应。",
+ "en": "Reuse the Agent; bind each Session to a workspace."
+ },
+ "tags": ["Agent", "AgentSession", "Workspace"],
+ "focus": [5, 8],
+ "code": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .build()\n .await?;\n\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .build()\n .await?;\n\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{Agent, AgentEvent};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .build()\n .await?;\n\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["Agent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["agent.acl", "#91C4A6"],
+ ["\")", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["session", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["session_builder", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["build", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "session",
+ "fromLineNumber": 5,
+ "toLineNumber": 8
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ },
+ {
+ "id": "context",
+ "layer": "L03 / INTELLIGENCE",
+ "filename": "src/main.rs",
+ "title": {
+ "zh": "给上下文设好边界",
+ "en": "Put a boundary around context"
+ },
+ "body": {
+ "zh": "自动压缩、token 上限和触发阈值属于 Session 配置,不需要藏进界面层。ContextAssembler 与 Memory 会据此准备模型输入。",
+ "en": "Compaction, token limits, and thresholds belong to SessionOptions rather than UI code. ContextAssembler and memory use them when preparing model input."
+ },
+ "note": {
+ "zh": "大结果会变成 Artifact,模型只拿到受控预览。",
+ "en": "Large results become artifacts; the model receives a bounded preview."
+ },
+ "tags": ["ContextAssembler", "Memory", "LlmClient"],
+ "focus": [6, 10],
+ "code": "use a3s_code_core::{Agent, AgentEvent, SessionOptions};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_max_context_tokens(200_000)\n .with_auto_compact_threshold(0.8);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{Agent, AgentEvent, SessionOptions};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_max_context_tokens(200_000)\n .with_auto_compact_threshold(0.8);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{Agent, AgentEvent, SessionOptions};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_max_context_tokens(200_000)\n .with_auto_compact_threshold(0.8);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["options", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_auto_compact", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["true", "#D79D77"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_max_context_tokens", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["200_000", "#D79D77"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_auto_compact_threshold", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["0", "#D79D77"],
+ [".", "#7A8492"],
+ ["8", "#D79D77"],
+ [");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["Agent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["agent.acl", "#91C4A6"],
+ ["\")", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["session", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["session_builder", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["options", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["options", "#CBD1DA"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["build", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "context",
+ "fromLineNumber": 6,
+ "toLineNumber": 10
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ },
+ {
+ "id": "governance",
+ "layer": "L04 / GOVERNANCE",
+ "filename": "src/main.rs",
+ "title": {
+ "zh": "在工具执行前定规则",
+ "en": "Set policy before tools run"
+ },
+ "body": {
+ "zh": "read 自动放行,write 每次询问,危险的 shell 命令直接拒绝。规则按 deny、allow、ask 的顺序求值。",
+ "en": "Allow reads, ask before writes, and deny a dangerous shell pattern. Rules evaluate in deny, allow, then ask order."
+ },
+ "note": {
+ "zh": "权限、确认、预算与沙箱共用一条执行链。",
+ "en": "Permission, approval, budgets, and sandboxing share one path."
+ },
+ "tags": ["validate", "permission", "confirm", "sandbox"],
+ "focus": [8, 12],
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ "\n ",
+ ["permissions", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["PermissionPolicy", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n ",
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n",
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["policy", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["PermissionPolicy", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["allow", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["read(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["ask", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["write(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["deny", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["bash(rm:*)", "#91C4A6"],
+ ["\");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["options", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_auto_compact", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["true", "#D79D77"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_permission_policy", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["policy", "#CBD1DA"],
+ [");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["Agent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["agent.acl", "#91C4A6"],
+ ["\")", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["session", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["session_builder", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["options", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["options", "#CBD1DA"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["build", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "governance",
+ "fromLineNumber": 8,
+ "toLineNumber": 12
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ },
+ {
+ "id": "tools",
+ "layer": "L05 / WORKSPACE",
+ "filename": "src/main.rs",
+ "title": {
+ "zh": "让 Workspace 决定可用工具",
+ "en": "Let the workspace expose its tools"
+ },
+ "body": {
+ "zh": "Session 只注册当前 Workspace 真正支持、且权限允许的工具。发起 stream 后,模型调用 read、search、shell 或 Git 都会经过同一条受控路径。",
+ "en": "A Session registers only tools the current workspace supports and policy permits. Every read, search, shell, or Git call follows the same governed path."
+ },
+ "note": {
+ "zh": "对象存储后端不支持本地命令时,Bash 与 Git 不会出现。",
+ "en": "If a workspace cannot run local commands, Bash and Git stay hidden."
+ },
+ "tags": ["files", "search", "shell", "git", "MCP"],
+ "focus": [23, 26],
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy);\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ "\n ",
+ ["permissions", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["PermissionPolicy", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n ",
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n",
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["policy", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["PermissionPolicy", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["allow", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["read(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["ask", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["write(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["deny", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["bash(rm:*)", "#91C4A6"],
+ ["\");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["options", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_auto_compact", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["true", "#D79D77"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_permission_policy", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["policy", "#CBD1DA"],
+ [");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["Agent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["agent.acl", "#91C4A6"],
+ ["\")", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["session", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["session_builder", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["options", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["options", "#CBD1DA"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["build", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["(", "#7A8492"],
+ ["mut", "#91ACD8"],
+ " ",
+ ["events", "#CBD1DA"],
+ [",", "#7A8492"],
+ " ",
+ ["lifecycle", "#CBD1DA"],
+ [")", "#7A8492"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["session", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["stream", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["Find the authentication entry points.", "#91C4A6"],
+ ["\",", "#7A8492"],
+ " ",
+ ["None", "#B5A4D2"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "tools",
+ "fromLineNumber": 23,
+ "toLineNumber": 26
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ },
+ {
+ "id": "evidence",
+ "layer": "L06 / DURABILITY",
+ "filename": "src/main.rs",
+ "title": {
+ "zh": "把过程交给界面,把现场留给下一次",
+ "en": "Stream the run and keep the evidence"
+ },
+ "body": {
+ "zh": "界面消费 AgentEvent;配置 SessionStore 后,save 会把会话、运行记录、Artifact、Trace 和验证结果作为同一代快照提交。",
+ "en": "The UI consumes AgentEvent. With a SessionStore configured, save commits the session, runs, artifacts, traces, and verification data as one snapshot generation."
+ },
+ "note": {
+ "zh": "终端、Web 与 SDK 看到的是同一条事件协议。",
+ "en": "Terminal, Web, and SDK clients share the same event protocol."
+ },
+ "tags": ["AgentEvent", "Run", "Artifact", "Snapshot"],
+ "focus": [29, 39],
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy)\n .with_file_session_store(\".a3s/sessions\");\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n while let Some(event) = events.recv().await {\n match event {\n AgentEvent::TextDelta { text } => print!(\"{text}\"),\n AgentEvent::End { .. } => break,\n _ => {}\n }\n }\n\n let _ = lifecycle.await;\n session.save().await?;\n Ok(())\n}",
+ "highlighted": {
+ "value": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy)\n .with_file_session_store(\".a3s/sessions\");\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n while let Some(event) = events.recv().await {\n match event {\n AgentEvent::TextDelta { text } => print!(\"{text}\"),\n AgentEvent::End { .. } => break,\n _ => {}\n }\n }\n\n let _ = lifecycle.await;\n session.save().await?;\n Ok(())\n}",
+ "lang": "rust",
+ "meta": "src/main.rs",
+ "code": "use a3s_code_core::{\n permissions::PermissionPolicy,\n Agent, AgentEvent, SessionOptions,\n};\n\n#[tokio::main]\nasync fn main() -> a3s_code_core::Result<()> {\n let policy = PermissionPolicy::new()\n .allow(\"read(*)\")\n .ask(\"write(*)\")\n .deny(\"bash(rm:*)\");\n\n let options = SessionOptions::new()\n .with_auto_compact(true)\n .with_permission_policy(policy)\n .with_file_session_store(\".a3s/sessions\");\n\n let agent = Agent::new(\"agent.acl\").await?;\n let session = agent\n .session_builder(\".\")\n .options(options)\n .build()\n .await?;\n\n let (mut events, lifecycle) = session\n .stream(\"Find the authentication entry points.\", None)\n .await?;\n\n while let Some(event) = events.recv().await {\n match event {\n AgentEvent::TextDelta { text } => print!(\"{text}\"),\n AgentEvent::End { .. } => break,\n _ => {}\n }\n }\n\n let _ = lifecycle.await;\n session.save().await?;\n Ok(())\n}",
+ "tokens": [
+ ["use", "#91ACD8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["{", "#7A8492"],
+ "\n ",
+ ["permissions", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["PermissionPolicy", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n ",
+ ["Agent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["AgentEvent", "#B5A4D2"],
+ [",", "#7A8492"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ [",", "#7A8492"],
+ "\n",
+ ["};", "#7A8492"],
+ "\n\n",
+ ["#[", "#7A8492"],
+ ["tokio", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["main", "#C9CED8"],
+ ["]", "#7A8492"],
+ "\n",
+ ["async fn", "#91ACD8"],
+ " ",
+ ["main", "#DFBD7C"],
+ ["()", "#7A8492"],
+ " ",
+ ["->", "#7EA8B8"],
+ " ",
+ ["a3s_code_core", "#C9CED8"],
+ ["::", "#7EA8B8"],
+ ["Result", "#B5A4D2"],
+ ["<()> {", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["policy", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["PermissionPolicy", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["allow", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["read(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["ask", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["write(*)", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["deny", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["bash(rm:*)", "#91C4A6"],
+ ["\");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["options", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["SessionOptions", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_auto_compact", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["true", "#D79D77"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_permission_policy", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["policy", "#CBD1DA"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["with_file_session_store", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".a3s/sessions", "#91C4A6"],
+ ["\");", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["Agent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["new", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["agent.acl", "#91C4A6"],
+ ["\")", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["session", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["agent", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["session_builder", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ [".", "#91C4A6"],
+ ["\")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["options", "#DFBD7C"],
+ ["(", "#7A8492"],
+ ["options", "#CBD1DA"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["build", "#DFBD7C"],
+ ["()", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["(", "#7A8492"],
+ ["mut", "#91ACD8"],
+ " ",
+ ["events", "#CBD1DA"],
+ [",", "#7A8492"],
+ " ",
+ ["lifecycle", "#CBD1DA"],
+ [")", "#7A8492"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["session", "#CBD1DA"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["stream", "#DFBD7C"],
+ ["(\"", "#7A8492"],
+ ["Find the authentication entry points.", "#91C4A6"],
+ ["\",", "#7A8492"],
+ " ",
+ ["None", "#B5A4D2"],
+ [")", "#7A8492"],
+ "\n ",
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n\n ",
+ ["while let", "#91ACD8"],
+ " ",
+ ["Some", "#B5A4D2"],
+ ["(", "#7A8492"],
+ ["event", "#CBD1DA"],
+ [")", "#7A8492"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["events", "#CBD1DA"],
+ [".", "#7EA8B8"],
+ ["recv", "#DFBD7C"],
+ ["()", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ " ",
+ ["{", "#7A8492"],
+ "\n ",
+ ["match", "#91ACD8"],
+ " ",
+ ["event", "#CBD1DA"],
+ " ",
+ ["{", "#7A8492"],
+ "\n ",
+ ["AgentEvent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["TextDelta", "#B5A4D2"],
+ " ",
+ ["{", "#7A8492"],
+ " ",
+ ["text", "#CBD1DA"],
+ " ",
+ ["}", "#7A8492"],
+ " ",
+ ["=>", "#7EA8B8"],
+ " ",
+ ["print!", "#DFBD7C"],
+ ["(\"{", "#7A8492"],
+ ["text", "#91C4A6"],
+ ["}\"),", "#7A8492"],
+ "\n ",
+ ["AgentEvent", "#B5A4D2"],
+ ["::", "#7EA8B8"],
+ ["End", "#B5A4D2"],
+ " ",
+ ["{", "#7A8492"],
+ " ",
+ ["..", "#7EA8B8"],
+ " ",
+ ["}", "#7A8492"],
+ " ",
+ ["=>", "#7EA8B8"],
+ " ",
+ ["break", "#91ACD8"],
+ [",", "#7A8492"],
+ "\n ",
+ ["_", "#CBD1DA"],
+ " ",
+ ["=>", "#7EA8B8"],
+ " ",
+ ["{}", "#7A8492"],
+ "\n ",
+ ["}", "#7A8492"],
+ "\n ",
+ ["}", "#7A8492"],
+ "\n\n ",
+ ["let", "#91ACD8"],
+ " ",
+ ["_", "#CBD1DA"],
+ " ",
+ ["=", "#7EA8B8"],
+ " ",
+ ["lifecycle", "#CBD1DA"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["session", "#CBD1DA"],
+ [".", "#7EA8B8"],
+ ["save", "#DFBD7C"],
+ ["()", "#7A8492"],
+ [".", "#7EA8B8"],
+ ["await", "#91ACD8"],
+ ["?", "#7EA8B8"],
+ [";", "#7A8492"],
+ "\n ",
+ ["Ok", "#B5A4D2"],
+ ["(())", "#7A8492"],
+ "\n",
+ ["}", "#7A8492"]
+ ],
+ "annotations": [
+ {
+ "name": "focus",
+ "query": "evidence",
+ "fromLineNumber": 29,
+ "toLineNumber": 39
+ }
+ ],
+ "themeName": "a3s-runtime",
+ "style": {
+ "color": "#c9ced8",
+ "background": "#0b0d11",
+ "colorScheme": "dark"
+ }
+ }
+ }
+]
diff --git a/website/theme/index.css b/website/theme/index.css
index 19958a7..b55b922 100644
--- a/website/theme/index.css
+++ b/website/theme/index.css
@@ -104,7 +104,7 @@ body {
.a3s-home {
position: relative;
- overflow: hidden;
+ overflow: clip;
width: 100%;
background:
linear-gradient(rgba(255, 255, 255, 0.021) 1px, transparent 1px),
@@ -244,14 +244,74 @@ body {
}
.a3s-button--primary {
- border-color: #e9edf5;
- background: #f3f5f8;
- color: #111216 !important;
+ --a3s-button-border-angle: 0deg;
+ position: relative;
+ border-color: transparent;
+ border-radius: 10px;
+ background:
+ linear-gradient(#111319, #111319) padding-box,
+ linear-gradient(115deg, #693cff, #55d9ff 48%, #f3f6ff 70%, #8b43ff)
+ border-box;
+ color: #f7f8fb !important;
+ box-shadow:
+ 0 0 0 1px rgba(117, 74, 255, 0.18),
+ 0 10px 28px rgba(0, 0, 0, 0.28);
+ isolation: isolate;
+}
+
+.a3s-button--primary::before {
+ position: absolute;
+ z-index: -1;
+ padding: 2px;
+ border-radius: inherit;
+ background: conic-gradient(
+ from var(--a3s-button-border-angle),
+ #7346ff 0deg,
+ #7346ff 75deg,
+ #60e5ff 120deg,
+ #f5f7ff 150deg,
+ #a148ff 205deg,
+ #7346ff 360deg
+ );
+ content: '';
+ inset: -1px;
+ mask:
+ linear-gradient(#000 0 0) content-box,
+ linear-gradient(#000 0 0);
+ mask-composite: exclude;
+ pointer-events: none;
}
.a3s-button--primary:hover {
- border-color: #fff;
- background: #fff;
+ border-color: transparent;
+ background:
+ linear-gradient(#171a21, #111319) padding-box,
+ transparent border-box;
+ box-shadow:
+ 0 0 0 1px rgba(111, 76, 255, 0.2),
+ 0 0 24px rgba(99, 100, 255, 0.18),
+ 0 12px 32px rgba(0, 0, 0, 0.34);
+}
+
+.a3s-button--primary:hover::before {
+ animation: a3s-button-border-flow 1.8s linear infinite;
+}
+
+.a3s-button--primary:focus-visible {
+ outline: 2px solid #d9e7ff;
+ outline-offset: 4px;
+}
+
+@property --a3s-button-border-angle {
+ syntax: '';
+ inherits: false;
+ initial-value: 0deg;
+}
+
+@keyframes a3s-button-border-flow {
+ to {
+ --a3s-button-border-angle: 360deg;
+ }
}
.a3s-button--secondary {
@@ -2118,3 +2178,1118 @@ body {
transition: none !important;
}
}
+
+/* Home layout refinement */
+
+.a3s-hero {
+ min-height: 640px;
+ grid-template-columns: minmax(0, 58%) minmax(0, 42%);
+}
+
+.a3s-hero-copy {
+ padding: 72px 68px 48px;
+}
+
+.a3s-hero h1 {
+ max-width: 760px;
+ font-size: clamp(54px, 5vw, 74px);
+}
+
+.a3s-install {
+ margin-top: 42px;
+ padding-top: 0;
+}
+
+.a3s-hero-visual {
+ padding: 38px;
+}
+
+.a3s-runtime-visual {
+ min-height: 526px;
+}
+
+.a3s-section-header {
+ min-height: 250px;
+ padding-top: 64px;
+ padding-bottom: 56px;
+}
+
+.a3s-feature-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.14fr) minmax(0, 0.86fr);
+ grid-template-rows: repeat(3, minmax(0, 1fr));
+}
+
+.a3s-feature-card {
+ min-height: 0;
+ padding: 28px 30px;
+ border-right: 0;
+ border-bottom: 1px solid var(--a3s-line);
+}
+
+.a3s-feature-card:first-child {
+ min-height: 570px;
+ border-right: 1px solid var(--a3s-line);
+ border-bottom: 0;
+ grid-row: 1 / span 3;
+}
+
+.a3s-feature-card:last-child {
+ border-bottom: 0;
+}
+
+.a3s-feature-card h3 {
+ min-height: 0;
+ margin: 24px 0 12px;
+}
+
+.a3s-feature-card:first-child h3 {
+ max-width: 430px;
+ margin-top: 118px;
+ font-size: clamp(28px, 2.5vw, 38px);
+}
+
+.a3s-feature-card:first-child p {
+ max-width: 510px;
+ font-size: 15px;
+}
+
+.a3s-feature-card:not(:first-child) {
+ display: grid;
+ align-content: center;
+ gap: 0;
+ grid-template-columns: 42px minmax(0, 1fr);
+}
+
+.a3s-feature-card:not(:first-child) .a3s-feature-number {
+ padding-top: 28px;
+ grid-row: 1 / span 3;
+}
+
+.a3s-feature-card:not(:first-child) h3,
+.a3s-feature-card:not(:first-child) p,
+.a3s-feature-card:not(:first-child) .a3s-tag-row {
+ grid-column: 2;
+}
+
+.a3s-feature-card:not(:first-child) .a3s-tag-row {
+ margin-top: 0;
+ padding-top: 16px;
+}
+
+/* Code Hike spotlight, restyled for the A3S runtime */
+
+.a3s-tutorial-header > div:last-child {
+ align-self: end;
+}
+
+.a3s-tutorial-header p {
+ max-width: 570px;
+ margin: 0;
+ color: var(--a3s-muted);
+ font-size: 16px;
+ line-height: 1.75;
+}
+
+.a3s-tutorial-header a,
+.a3s-component-entry-copy > a {
+ display: inline-flex;
+ width: fit-content;
+ margin-top: 24px;
+ padding-bottom: 6px;
+ border-bottom: 1px solid #555b65;
+ color: #d7dbe3;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.a3s-tutorial-header a:hover,
+.a3s-component-entry-copy > a:hover {
+ border-color: var(--a3s-blue);
+ color: #fff;
+}
+
+.a3s-runtime-tutorial {
+ display: grid;
+ align-items: stretch;
+ background: #0d0e12;
+ grid-template-columns: minmax(300px, 0.62fr) minmax(0, 1.38fr);
+}
+
+.a3s-tutorial-steps {
+ border-right: 1px solid var(--a3s-line);
+}
+
+.a3s-tutorial-step {
+ position: relative;
+ min-height: 370px;
+ border-bottom: 1px solid var(--a3s-line);
+ background: #0d0e12;
+ transition: background 220ms ease;
+}
+
+.a3s-tutorial-step:last-child {
+ border-bottom: 0;
+}
+
+.a3s-tutorial-step::before {
+ position: absolute;
+ z-index: 2;
+ top: 0;
+ bottom: 0;
+ left: -1px;
+ width: 2px;
+ background: linear-gradient(var(--a3s-blue), #93b9f5);
+ content: '';
+ opacity: 0;
+ transform: scaleY(0.25);
+ transition:
+ opacity 180ms ease,
+ transform 240ms ease;
+}
+
+.a3s-tutorial-step[data-selected='true'] {
+ background:
+ linear-gradient(100deg, rgba(108, 163, 255, 0.085), transparent 72%),
+ #101217;
+}
+
+.a3s-tutorial-step[data-selected='true']::before {
+ opacity: 1;
+ transform: scaleY(1);
+}
+
+.a3s-tutorial-step > button {
+ position: relative;
+ display: flex;
+ width: 100%;
+ min-height: 370px;
+ padding: 48px 48px 42px;
+ border: 0;
+ background: transparent;
+ color: inherit;
+ cursor: pointer;
+ flex-direction: column;
+ font-family: inherit;
+ text-align: left;
+}
+
+.a3s-tutorial-step > button:focus-visible {
+ outline: 2px solid #b8d1ff;
+ outline-offset: -5px;
+}
+
+.a3s-tutorial-step-number {
+ color: #4e5561;
+ font-family: var(--a3s-mono);
+ font-size: 11px;
+ letter-spacing: 0.08em;
+}
+
+.a3s-tutorial-step-layer {
+ margin-top: 38px;
+ color: #7796c4;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ font-weight: 650;
+ letter-spacing: 0.08em;
+}
+
+.a3s-tutorial-step h3 {
+ max-width: 410px;
+ margin: 13px 0 14px;
+ color: #e8ebf1;
+ font-size: 25px;
+ font-weight: 600;
+ letter-spacing: -0.035em;
+ line-height: 1.25;
+}
+
+.a3s-tutorial-step p {
+ max-width: 455px;
+ margin: 0;
+ color: #8c929d;
+ font-size: 13px;
+ line-height: 1.72;
+}
+
+.a3s-tutorial-step-tags {
+ display: flex;
+ margin-top: auto;
+ padding-top: 26px;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+.a3s-tutorial-step-tags i {
+ padding: 5px 7px;
+ border: 1px solid #292d35;
+ background: rgba(255, 255, 255, 0.018);
+ color: #626a77;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ font-style: normal;
+}
+
+.a3s-tutorial-step-progress {
+ position: absolute;
+ top: 48px;
+ right: 30px;
+ width: 34px;
+ height: 1px;
+ background: #30343c;
+}
+
+.a3s-tutorial-step-progress::after {
+ display: block;
+ width: 0;
+ height: 1px;
+ background: var(--a3s-blue);
+ content: '';
+ transition: width 220ms ease;
+}
+
+.a3s-tutorial-step[data-selected='true'] .a3s-tutorial-step-progress::after {
+ width: 100%;
+}
+
+.a3s-tutorial-sticky {
+ position: relative;
+ min-width: 0;
+ padding: 22px;
+ background:
+ linear-gradient(rgba(122, 139, 167, 0.035) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(122, 139, 167, 0.035) 1px, transparent 1px),
+ radial-gradient(
+ circle at 65% 28%,
+ rgba(108, 92, 255, 0.08),
+ transparent 34%
+ );
+ background-size:
+ 32px 32px,
+ 32px 32px,
+ auto;
+}
+
+.a3s-tutorial-stage {
+ position: sticky;
+ top: calc(var(--rp-nav-height) + 16px);
+ overflow: hidden;
+ min-height: min(720px, calc(100vh - var(--rp-nav-height) - 42px));
+ border: 1px solid #343842;
+ background: #0b0d11;
+ box-shadow: 0 28px 75px rgba(0, 0, 0, 0.28);
+}
+
+.a3s-tutorial-stage-toolbar {
+ display: flex;
+ height: 44px;
+ padding: 0 15px;
+ border-bottom: 1px solid #292d35;
+ color: #6d7582;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.09em;
+}
+
+.a3s-tutorial-stage-toolbar > span:last-child {
+ color: #849fc8;
+}
+
+.a3s-tutorial-stage-grid {
+ display: grid;
+ min-height: calc(
+ min(720px, calc(100vh - var(--rp-nav-height) - 42px)) - 44px
+ );
+ grid-template-columns: minmax(0, 1.55fr) minmax(210px, 0.75fr);
+}
+
+.a3s-tutorial-code {
+ display: flex;
+ overflow: hidden;
+ min-width: 0;
+ background:
+ linear-gradient(rgba(108, 163, 255, 0.025) 1px, transparent 1px), #0b0d11;
+ background-size: 100% 25px;
+ flex-direction: column;
+}
+
+.a3s-tutorial-code > header {
+ display: flex;
+ min-height: 42px;
+ padding: 0 13px;
+ border-bottom: 1px solid #242831;
+ background: #101217;
+ color: #727a87;
+ align-items: center;
+ gap: 12px;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-tutorial-code > header > span:first-child {
+ display: inline-flex;
+ color: #acb4c0;
+ align-items: center;
+ gap: 8px;
+}
+
+.a3s-tutorial-code > header i {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #d69a65;
+ box-shadow: 0 0 9px rgba(214, 154, 101, 0.34);
+}
+
+.a3s-tutorial-code > header > span:nth-child(2) {
+ color: #4e5663;
+}
+
+.a3s-tutorial-code > header > button {
+ margin-left: auto;
+ padding: 5px 7px;
+ border: 1px solid transparent;
+ background: transparent;
+ color: #69717e;
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 8px;
+}
+
+.a3s-tutorial-code > header > button:hover,
+.a3s-tutorial-code > header > button:focus-visible {
+ border-color: #39404b;
+ color: #d7dce5;
+ outline: none;
+}
+
+.a3s-tutorial-code pre {
+ overflow: auto;
+ min-height: 0;
+ margin: 0;
+ padding: 22px 0 30px;
+ background: transparent;
+ color: #c9ced8;
+ flex: 1;
+ font-family: var(--a3s-mono);
+ font-size: clamp(10px, 0.76vw, 12px);
+ line-height: 1.72;
+ tab-size: 4;
+}
+
+.a3s-code-line {
+ position: relative;
+ display: block;
+ min-width: max-content;
+ min-height: 1.72em;
+ padding: 0 20px 0 57px;
+ border-left: 2px solid transparent;
+ opacity: 0.28;
+ transition:
+ background 180ms ease,
+ opacity 180ms ease;
+}
+
+.a3s-code-line::before {
+ position: absolute;
+ left: 16px;
+ width: 22px;
+ color: #3e4551;
+ content: attr(data-line-number);
+ font-size: 9px;
+ text-align: right;
+}
+
+.a3s-code-line.is-focused {
+ border-left-color: #608dcc;
+ background:
+ linear-gradient(90deg, rgba(91, 137, 202, 0.13), transparent 82%),
+ rgba(255, 255, 255, 0.012);
+ opacity: 1;
+}
+
+.a3s-code-line.is-focused::before {
+ color: #778ba8;
+}
+
+.a3s-tutorial-stage-side {
+ display: grid;
+ min-width: 0;
+ border-left: 1px solid #292d35;
+ background: #0e1014;
+ grid-template-rows: 1fr auto;
+}
+
+.a3s-tutorial-layers > header {
+ display: flex;
+ min-height: 42px;
+ padding: 0 13px;
+ border-bottom: 1px solid #242831;
+ color: #6d7582;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.06em;
+}
+
+.a3s-tutorial-layers > header small {
+ color: #414852;
+ font-size: 7px;
+}
+
+.a3s-tutorial-layers > div {
+ position: relative;
+ padding: 14px 12px;
+}
+
+.a3s-tutorial-layers > div::before {
+ position: absolute;
+ top: 31px;
+ bottom: 31px;
+ left: 27px;
+ width: 1px;
+ background: #303640;
+ content: '';
+}
+
+.a3s-tutorial-layers button {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ width: 100%;
+ min-height: 58px;
+ padding: 8px 8px;
+ border: 1px solid transparent;
+ background: transparent;
+ color: #626a76;
+ cursor: pointer;
+ align-items: center;
+ gap: 9px;
+ grid-template-columns: 24px minmax(0, 1fr) 6px;
+ text-align: left;
+ transition:
+ border-color 180ms ease,
+ background 180ms ease,
+ color 180ms ease;
+}
+
+.a3s-tutorial-layers button:hover {
+ background: rgba(255, 255, 255, 0.025);
+ color: #aeb6c2;
+}
+
+.a3s-tutorial-layers button.is-active {
+ border-color: #36557e;
+ background:
+ linear-gradient(90deg, rgba(108, 163, 255, 0.11), transparent), #11151c;
+ color: #e1e6ef;
+}
+
+.a3s-tutorial-layers button > span:first-child {
+ display: flex;
+ width: 20px;
+ height: 20px;
+ border: 1px solid #373d47;
+ border-radius: 50%;
+ background: #0e1014;
+ color: #555e6b;
+ align-items: center;
+ justify-content: center;
+ font-family: var(--a3s-mono);
+ font-size: 7px;
+}
+
+.a3s-tutorial-layers button.is-active > span:first-child {
+ border-color: #6b9cdd;
+ color: #bcd4f8;
+ box-shadow: 0 0 0 4px rgba(108, 163, 255, 0.07);
+}
+
+.a3s-tutorial-layers button.is-complete > span:first-child {
+ border-color: #356754;
+ color: #7ac8a5;
+}
+
+.a3s-tutorial-layers button > span:nth-child(2) {
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.a3s-tutorial-layers button small {
+ overflow: hidden;
+ color: #4c5460;
+ font-family: var(--a3s-mono);
+ font-size: 6px;
+ letter-spacing: 0.06em;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-tutorial-layers button strong {
+ overflow: hidden;
+ font-size: 10px;
+ font-weight: 580;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-tutorial-layers button > i {
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background: #343a44;
+}
+
+.a3s-tutorial-layers button.is-active > i {
+ background: var(--a3s-blue);
+ box-shadow: 0 0 10px rgba(108, 163, 255, 0.7);
+}
+
+.a3s-tutorial-note {
+ min-height: 116px;
+ padding: 18px;
+ border-top: 1px solid #292d35;
+ background:
+ linear-gradient(135deg, rgba(240, 180, 77, 0.055), transparent 70%), #111217;
+}
+
+.a3s-tutorial-note span {
+ color: #aa8350;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ letter-spacing: 0.06em;
+}
+
+.a3s-tutorial-note p {
+ margin: 9px 0 0;
+ color: #9299a5;
+ font-size: 11px;
+ line-height: 1.6;
+}
+
+.a3s-tutorial-mobile-preview {
+ display: none;
+}
+
+/* Component documentation entry */
+
+.a3s-component-entry {
+ display: grid;
+ min-height: 610px;
+ grid-template-columns: minmax(320px, 0.72fr) minmax(0, 1.28fr);
+}
+
+.a3s-component-entry-copy {
+ display: flex;
+ padding: 76px 54px 60px 68px;
+ border-right: 1px solid var(--a3s-line);
+ flex-direction: column;
+ justify-content: center;
+}
+
+.a3s-component-entry-copy h2 {
+ max-width: 520px;
+ margin: 18px 0 0;
+ color: var(--a3s-text);
+ font-size: clamp(40px, 3.6vw, 54px);
+ font-weight: 620;
+ letter-spacing: -0.055em;
+ line-height: 1.04;
+}
+
+.a3s-component-entry-copy p {
+ max-width: 500px;
+ margin: 28px 0 0;
+ color: var(--a3s-muted);
+ font-size: 15px;
+ line-height: 1.75;
+}
+
+.a3s-component-entry-list {
+ display: grid;
+ min-width: 0;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.a3s-component-entry-list > a {
+ position: relative;
+ display: flex;
+ overflow: hidden;
+ min-width: 0;
+ padding: 42px 34px 36px;
+ flex-direction: column;
+ transition: background 200ms ease;
+}
+
+.a3s-component-entry-list > a:first-child {
+ border-right: 1px solid var(--a3s-line);
+}
+
+.a3s-component-entry-list > a:hover {
+ background:
+ linear-gradient(180deg, rgba(108, 163, 255, 0.055), transparent 65%),
+ #101115;
+}
+
+.a3s-component-entry-list > a > span {
+ display: flex;
+ flex-direction: column;
+ gap: 7px;
+}
+
+.a3s-component-entry-list small {
+ color: #66707e;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+ letter-spacing: 0.09em;
+}
+
+.a3s-component-entry-list strong {
+ color: #e1e5ec;
+ font-size: 19px;
+ font-weight: 590;
+}
+
+.a3s-component-entry-list > a > p {
+ margin: auto 0 0;
+ padding-top: 30px;
+ color: #777f8c;
+ font-size: 12px;
+ line-height: 1.65;
+}
+
+.a3s-component-entry-list > a > svg {
+ position: absolute;
+ right: 28px;
+ bottom: 34px;
+ color: #59616e;
+}
+
+.a3s-home-tui-sample,
+.a3s-home-web-sample {
+ min-height: 238px;
+ margin-top: 54px;
+ border: 1px solid #313640;
+ background: #0b0d11;
+ box-shadow: 0 22px 48px rgba(0, 0, 0, 0.25);
+}
+
+.a3s-home-tui-sample {
+ padding: 45px 24px;
+ color: #9aa2ae;
+ font-family: var(--a3s-mono);
+ font-size: 10px;
+}
+
+.a3s-home-tui-sample::before {
+ display: block;
+ margin: -27px -7px 28px;
+ color: #4d5664;
+ content: 'A3S CODE / ACTIVITY';
+ font-size: 7px;
+ letter-spacing: 0.1em;
+}
+
+.a3s-home-tui-sample p {
+ display: flex;
+ margin: 0 0 22px;
+ align-items: center;
+ gap: 9px;
+}
+
+.a3s-home-tui-sample p i {
+ color: var(--a3s-green);
+ font-style: normal;
+}
+
+.a3s-home-tui-sample p.is-running i {
+ color: var(--a3s-amber);
+}
+
+.a3s-home-tui-sample code {
+ overflow: hidden;
+ color: #c8d0db;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.a3s-home-tui-sample > span {
+ color: #6ca3ff;
+}
+
+.a3s-home-web-sample {
+ display: flex;
+ padding: 34px 27px;
+ background:
+ radial-gradient(
+ circle at 50% 0,
+ rgba(108, 163, 255, 0.08),
+ transparent 60%
+ ),
+ #101217;
+ flex-direction: column;
+}
+
+.a3s-home-web-sample > span {
+ color: #d7dce5;
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.a3s-home-web-sample > code {
+ margin-top: 24px;
+ padding: 16px 13px;
+ border: 1px solid #303641;
+ background: #0b0d11;
+ color: #aeb7c5;
+ font-family: var(--a3s-mono);
+ font-size: 9px;
+}
+
+.a3s-home-web-sample > div {
+ display: flex;
+ margin-top: auto;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.a3s-home-web-sample i {
+ padding: 8px 11px;
+ border: 1px solid #343b46;
+ color: #8b94a2;
+ font-size: 9px;
+ font-style: normal;
+}
+
+.a3s-home-web-sample i:last-child {
+ border-color: #d5dbe4;
+ background: #e7ebf1;
+ color: #111318;
+}
+
+.a3s-surface-grid {
+ grid-template-columns: minmax(0, 1.35fr) repeat(3, minmax(0, 1fr));
+}
+
+.a3s-surface-card:first-child {
+ background:
+ linear-gradient(135deg, rgba(108, 163, 255, 0.06), transparent 65%), #101115;
+}
+
+@media (max-width: 1180px) {
+ .a3s-hero-copy {
+ padding-right: 45px;
+ padding-left: 45px;
+ }
+
+ .a3s-feature-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ grid-template-rows: auto;
+ }
+
+ .a3s-feature-card:first-child {
+ min-height: 430px;
+ border-right: 0;
+ border-bottom: 1px solid var(--a3s-line);
+ grid-column: 1 / -1;
+ grid-row: auto;
+ }
+
+ .a3s-feature-card:nth-child(2),
+ .a3s-feature-card:nth-child(4) {
+ border-right: 1px solid var(--a3s-line);
+ }
+
+ .a3s-feature-card:nth-child(3) {
+ border-right: 0;
+ }
+
+ .a3s-feature-card:last-child {
+ min-height: 250px;
+ border-top: 0;
+ grid-column: 1 / -1;
+ }
+
+ .a3s-tutorial-step > button {
+ padding-right: 34px;
+ padding-left: 34px;
+ }
+
+ .a3s-tutorial-stage-grid {
+ grid-template-columns: minmax(0, 1.35fr) minmax(190px, 0.75fr);
+ }
+
+ .a3s-code-line {
+ padding-right: 14px;
+ padding-left: 48px;
+ }
+
+ .a3s-code-line::before {
+ left: 9px;
+ }
+
+ .a3s-component-entry-copy {
+ padding-right: 45px;
+ padding-left: 45px;
+ }
+
+ .a3s-surface-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
+
+@media (max-width: 920px) {
+ .a3s-hero {
+ grid-template-columns: 1fr;
+ }
+
+ .a3s-hero-copy {
+ min-height: 0;
+ padding-top: 64px;
+ padding-bottom: 54px;
+ }
+
+ .a3s-install {
+ margin-top: 42px;
+ }
+
+ .a3s-hero-visual {
+ min-height: 610px;
+ }
+
+ .a3s-tutorial-header > div:last-child {
+ align-self: auto;
+ }
+
+ .a3s-runtime-tutorial {
+ display: block;
+ }
+
+ .a3s-tutorial-steps {
+ border-right: 0;
+ }
+
+ .a3s-tutorial-step,
+ .a3s-tutorial-step > button {
+ min-height: 0;
+ }
+
+ .a3s-tutorial-step > button {
+ padding: 48px 45px 42px;
+ }
+
+ .a3s-tutorial-step-layer {
+ margin-top: 30px;
+ }
+
+ .a3s-tutorial-step-tags {
+ margin-top: 4px;
+ }
+
+ .a3s-tutorial-sticky {
+ display: none;
+ }
+
+ .a3s-tutorial-mobile-preview {
+ display: none;
+ padding: 0 45px 46px;
+ }
+
+ .a3s-tutorial-step[data-selected='true'] .a3s-tutorial-mobile-preview {
+ display: block;
+ }
+
+ .a3s-tutorial-mobile-preview > div:first-child {
+ display: flex;
+ min-height: 44px;
+ padding: 0 13px;
+ border: 1px solid #303640;
+ border-bottom: 0;
+ background: #111319;
+ color: #5d6673;
+ align-items: center;
+ justify-content: space-between;
+ font-family: var(--a3s-mono);
+ font-size: 8px;
+ }
+
+ .a3s-tutorial-mobile-preview > div:first-child strong {
+ color: #aeb9c9;
+ font-size: 9px;
+ }
+
+ .a3s-tutorial-mobile-preview .a3s-tutorial-code {
+ min-height: 470px;
+ border: 1px solid #303640;
+ }
+
+ .a3s-tutorial-mobile-preview .a3s-tutorial-code pre {
+ max-height: 470px;
+ font-size: 11px;
+ }
+
+ .a3s-component-entry {
+ grid-template-columns: 1fr;
+ }
+
+ .a3s-component-entry-copy {
+ min-height: 430px;
+ border-right: 0;
+ border-bottom: 1px solid var(--a3s-line);
+ }
+}
+
+@media (max-width: 640px) {
+ .a3s-hero-copy {
+ min-height: 0;
+ padding: 52px 24px 44px;
+ }
+
+ .a3s-hero h1 {
+ font-size: 48px;
+ }
+
+ .a3s-hero-visual {
+ min-height: 555px;
+ padding: 24px 18px;
+ }
+
+ .a3s-runtime-visual {
+ min-height: 505px;
+ }
+
+ .a3s-feature-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .a3s-feature-card,
+ .a3s-feature-card:nth-child(n),
+ .a3s-feature-card:first-child,
+ .a3s-feature-card:last-child {
+ display: flex;
+ min-height: 330px;
+ padding: 34px 24px;
+ border-right: 0;
+ border-bottom: 1px solid var(--a3s-line);
+ grid-column: auto;
+ grid-row: auto;
+ }
+
+ .a3s-feature-card:last-child {
+ border-bottom: 0;
+ }
+
+ .a3s-feature-card h3,
+ .a3s-feature-card:first-child h3,
+ .a3s-feature-card:not(:first-child) h3 {
+ margin: 48px 0 14px;
+ font-size: 22px;
+ grid-column: auto;
+ }
+
+ .a3s-feature-card p,
+ .a3s-feature-card .a3s-tag-row,
+ .a3s-feature-card:not(:first-child) p,
+ .a3s-feature-card:not(:first-child) .a3s-tag-row {
+ grid-column: auto;
+ }
+
+ .a3s-feature-card:not(:first-child) .a3s-feature-number {
+ padding-top: 0;
+ grid-row: auto;
+ }
+
+ .a3s-feature-card .a3s-tag-row {
+ margin-top: auto;
+ padding-top: 22px;
+ }
+
+ .a3s-tutorial-step > button {
+ padding: 42px 24px 36px;
+ }
+
+ .a3s-tutorial-step h3 {
+ font-size: 23px;
+ }
+
+ .a3s-tutorial-step-progress {
+ top: 43px;
+ right: 24px;
+ }
+
+ .a3s-tutorial-mobile-preview {
+ padding: 0 16px 36px;
+ }
+
+ .a3s-tutorial-mobile-preview .a3s-tutorial-code {
+ min-height: 390px;
+ }
+
+ .a3s-tutorial-mobile-preview .a3s-tutorial-code pre {
+ max-height: 390px;
+ font-size: 9px;
+ }
+
+ .a3s-code-line {
+ padding-right: 12px;
+ padding-left: 43px;
+ }
+
+ .a3s-code-line::before {
+ left: 5px;
+ }
+
+ .a3s-component-entry-copy {
+ min-height: 0;
+ padding: 58px 24px;
+ }
+
+ .a3s-component-entry-copy h2 {
+ font-size: 39px;
+ }
+
+ .a3s-component-entry-list {
+ grid-template-columns: 1fr;
+ }
+
+ .a3s-component-entry-list > a {
+ min-height: 500px;
+ padding: 38px 24px 32px;
+ }
+
+ .a3s-component-entry-list > a:first-child {
+ border-right: 0;
+ border-bottom: 1px solid var(--a3s-line);
+ }
+
+ .a3s-home-tui-sample,
+ .a3s-home-web-sample {
+ min-height: 220px;
+ margin-top: 42px;
+ }
+
+ .a3s-component-entry-list > a > svg {
+ right: 24px;
+ bottom: 31px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .a3s-button--primary:hover::before {
+ animation: none;
+ }
+
+ .a3s-tutorial-step::before,
+ .a3s-code-line,
+ .a3s-tutorial-layers button {
+ transition: none;
+ }
+}
diff --git a/website/theme/index.tsx b/website/theme/index.tsx
index 0c80f16..cff172a 100644
--- a/website/theme/index.tsx
+++ b/website/theme/index.tsx
@@ -1,5 +1,5 @@
import './index.css';
-import './playgrounds.css';
+import './component-docs.css';
export { HomeLayout } from './components/HomeLayout';
export * from '@rspress/core/theme-original';
diff --git a/website/theme/playgrounds.css b/website/theme/playgrounds.css
deleted file mode 100644
index 705e7dc..0000000
--- a/website/theme/playgrounds.css
+++ /dev/null
@@ -1,1791 +0,0 @@
-.a3s-playground,
-.a3s-playground *,
-.a3s-building-blocks,
-.a3s-building-blocks * {
- box-sizing: border-box;
-}
-
-.a3s-playground button,
-.a3s-building-blocks button {
- font: inherit;
-}
-
-.a3s-playground {
- width: 100%;
- margin: 28px 0 20px;
- border: 1px solid #2b2e35;
- border-radius: 18px;
- overflow: hidden;
- background: #0d0e12;
- color: #f2f4f7;
- box-shadow: 0 24px 80px rgb(0 0 0 / 28%);
- font-family:
- Inter,
- ui-sans-serif,
- -apple-system,
- BlinkMacSystemFont,
- 'Segoe UI',
- sans-serif;
- line-height: 1.5;
-}
-
-.a3s-playground button {
- border: 0;
- color: inherit;
- cursor: pointer;
-}
-
-.a3s-playground button:focus-visible,
-.a3s-building-blocks button:focus-visible,
-.a3s-building-blocks a:focus-visible {
- outline: 2px solid #6ca3ff;
- outline-offset: 2px;
-}
-
-.a3s-playground-toolbar {
- display: flex;
- min-height: 62px;
- padding: 0 18px;
- border-bottom: 1px solid #292c33;
- background: #111217;
- align-items: center;
- justify-content: space-between;
- gap: 20px;
-}
-
-.a3s-playground-toolbar > div:first-child {
- display: flex;
- min-width: max-content;
- align-items: center;
- gap: 9px;
-}
-
-.a3s-playground-toolbar strong {
- color: #f5f7fa;
- font-size: 13px;
- font-weight: 670;
-}
-
-.a3s-playground-toolbar small {
- padding: 3px 7px;
- border: 1px solid #30343d;
- border-radius: 999px;
- color: #858c98;
- font-size: 9px;
- font-weight: 650;
- letter-spacing: 0.07em;
- text-transform: uppercase;
-}
-
-.a3s-playground-live {
- width: 7px;
- height: 7px;
- border-radius: 50%;
- background: #3ccf91;
- box-shadow: 0 0 12px rgb(60 207 145 / 70%);
-}
-
-.a3s-playground-tabs {
- display: flex;
- min-height: 45px;
- padding: 0 14px;
- border-bottom: 1px solid #292c33;
- background: #0e0f13;
- align-items: stretch;
- gap: 4px;
-}
-
-.a3s-playground-tabs button {
- position: relative;
- padding: 0 13px;
- background: transparent;
- color: #777e8a;
- font-size: 11px;
- font-weight: 620;
-}
-
-.a3s-playground-tabs button::after {
- position: absolute;
- right: 12px;
- bottom: -1px;
- left: 12px;
- height: 2px;
- border-radius: 2px 2px 0 0;
- background: transparent;
- content: '';
-}
-
-.a3s-playground-tabs button:hover,
-.a3s-playground-tabs button[aria-selected='true'] {
- color: #f0f2f6;
-}
-
-.a3s-playground-tabs button[aria-selected='true']::after {
- background: #6ca3ff;
-}
-
-.a3s-playground-note {
- margin: 0 !important;
- padding: 11px 18px;
- border-top: 1px solid #292c33;
- background: #101116;
- color: #777e89;
- font-size: 10px;
- line-height: 1.55;
- text-align: center;
-}
-
-/* Agent building blocks */
-
-.a3s-building-blocks {
- display: grid;
- width: 100%;
- min-height: 420px;
- margin: 28px 0;
- border: 1px solid #292c33;
- border-radius: 16px;
- overflow: hidden;
- background: #0d0e12;
- color: #edf0f5;
- grid-template-columns: 245px minmax(0, 1fr);
-}
-
-.a3s-building-block-nav {
- display: flex;
- padding: 12px;
- border-right: 1px solid #292c33;
- background: #111217;
- flex-direction: column;
- gap: 3px;
-}
-
-.a3s-building-block-nav button {
- display: grid;
- min-height: 56px;
- padding: 0 13px;
- border: 1px solid transparent;
- border-radius: 9px;
- background: transparent;
- color: #8c929d;
- align-items: center;
- gap: 12px;
- grid-template-columns: 25px minmax(0, 1fr);
- font-size: 12px;
- font-weight: 620;
- text-align: left;
-}
-
-.a3s-building-block-nav button > span {
- color: #555c68;
- font-family: var(--a3s-mono);
- font-size: 9px;
-}
-
-.a3s-building-block-nav button:hover {
- background: #17191f;
- color: #dfe3e9;
-}
-
-.a3s-building-block-nav button.is-active {
- border-color: #354b70;
- background: rgb(108 163 255 / 10%);
- color: #eef4ff;
-}
-
-.a3s-building-block-nav button.is-active > span {
- color: #6ca3ff;
-}
-
-.a3s-building-block-detail {
- padding: 32px;
- background:
- radial-gradient(circle at 100% 0, rgb(108 163 255 / 9%), transparent 38%),
- #0d0e12;
-}
-
-.a3s-building-block-detail > header {
- max-width: 700px;
- margin-bottom: 25px;
-}
-
-.a3s-building-block-detail > header > span {
- color: #6ca3ff;
- font-family: var(--a3s-mono);
- font-size: 10px;
- font-weight: 680;
- letter-spacing: 0.1em;
- text-transform: uppercase;
-}
-
-.a3s-building-block-detail > header p {
- margin: 10px 0 0;
- color: #a0a6b0;
- font-size: 14px;
- line-height: 1.7;
-}
-
-.a3s-building-block-grid {
- display: grid;
- gap: 10px;
- grid-template-columns: repeat(2, minmax(0, 1fr));
-}
-
-.a3s-building-block-grid a {
- display: flex;
- min-height: 132px;
- padding: 17px;
- border: 1px solid #292c33;
- border-radius: 11px;
- background: #121318;
- color: inherit;
- flex-direction: column;
- text-decoration: none;
- transition:
- border-color 160ms ease,
- background 160ms ease,
- transform 160ms ease;
-}
-
-.a3s-building-block-grid a:hover {
- border-color: #465a7a;
- background: #161922;
- transform: translateY(-2px);
-}
-
-.a3s-building-block-grid strong {
- color: #f1f3f6;
- font-family: var(--a3s-mono);
- font-size: 12px;
- font-weight: 680;
-}
-
-.a3s-building-block-grid a > span {
- margin-top: 8px;
- color: #898f9a;
- font-size: 11px;
- line-height: 1.55;
-}
-
-.a3s-building-block-grid small {
- margin-top: auto;
- padding-top: 10px;
- color: #6ca3ff;
- font-size: 9px;
- font-weight: 650;
-}
-
-/* TUI playground */
-
-.a3s-playground-theme {
- display: flex;
- align-items: center;
- gap: 6px;
-}
-
-.a3s-playground-theme button {
- display: grid;
- width: 27px;
- height: 27px;
- padding: 4px;
- border: 1px solid transparent;
- border-radius: 8px;
- background: transparent;
- place-items: center;
-}
-
-.a3s-playground-theme button:hover,
-.a3s-playground-theme button[aria-pressed='true'] {
- border-color: #424752;
- background: #1b1d24;
-}
-
-.a3s-playground-theme button > span {
- display: block;
- width: 15px;
- height: 15px;
- border: 1px solid rgb(255 255 255 / 18%);
- border-radius: 4px;
-}
-
-.a3s-tui-frame {
- overflow: hidden;
- margin: 18px;
- border: 1px solid var(--tui-line);
- border-radius: 10px;
- background: var(--tui-bg);
- color: var(--tui-text);
- box-shadow: 0 18px 50px rgb(0 0 0 / 32%);
- font-family: var(--a3s-mono);
- transition:
- background 180ms ease,
- color 180ms ease,
- border-color 180ms ease;
-}
-
-.a3s-tui-titlebar {
- display: grid;
- height: 34px;
- padding: 0 10px;
- border-bottom: 1px solid var(--tui-line);
- background: var(--tui-panel-strong);
- color: var(--tui-muted);
- align-items: center;
- grid-template-columns: 1fr auto 1fr;
- font-size: 8px;
- letter-spacing: 0.06em;
-}
-
-.a3s-tui-titlebar span:first-child {
- color: var(--tui-blue);
- font-weight: 700;
-}
-
-.a3s-tui-titlebar span:last-child {
- justify-self: end;
-}
-
-.a3s-tui-screen {
- display: grid;
- min-height: 480px;
- grid-template-columns: 164px minmax(0, 1fr);
-}
-
-.a3s-tui-sidebar {
- display: flex;
- padding: 17px 9px 9px;
- border-right: 1px solid var(--tui-line);
- background: var(--tui-panel);
- flex-direction: column;
- gap: 3px;
-}
-
-.a3s-tui-sidebar > strong {
- margin: 0 8px 12px;
- color: var(--tui-muted);
- font-size: 8px;
- letter-spacing: 0.13em;
-}
-
-.a3s-tui-sidebar button {
- display: grid;
- min-height: 31px;
- padding: 0 8px;
- border-radius: 4px;
- background: transparent;
- color: var(--tui-muted);
- align-items: center;
- gap: 5px;
- grid-template-columns: 8px minmax(0, 1fr) auto;
- font-size: 9px;
- text-align: left;
-}
-
-.a3s-tui-sidebar button:hover,
-.a3s-tui-sidebar button.is-active {
- background: var(--tui-panel-strong);
- color: var(--tui-text);
-}
-
-.a3s-tui-sidebar button.is-active > span:first-child {
- color: var(--tui-blue);
-}
-
-.a3s-tui-sidebar button small {
- color: var(--tui-muted);
- font-size: 8px;
-}
-
-.a3s-tui-sidebar > div {
- flex: 1;
-}
-
-.a3s-tui-main {
- min-width: 0;
- background:
- linear-gradient(rgb(255 255 255 / 1.2%) 1px, transparent 1px), var(--tui-bg);
- background-size: 100% 24px;
-}
-
-.a3s-tui-session,
-.a3s-tui-diff,
-.a3s-tui-components {
- min-height: 480px;
- padding: 20px 22px;
-}
-
-.a3s-tui-session > header {
- display: flex;
- padding-bottom: 14px;
- border-bottom: 1px solid var(--tui-line);
- align-items: center;
- justify-content: space-between;
-}
-
-.a3s-tui-session > header > div {
- display: flex;
- min-width: 0;
- align-items: center;
- gap: 8px;
-}
-
-.a3s-tui-session > header strong {
- overflow: hidden;
- color: var(--tui-text);
- font-size: 10px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.a3s-tui-session > header small {
- color: var(--tui-muted);
- font-size: 8px;
-}
-
-.a3s-tui-dot {
- width: 6px;
- height: 6px;
- border-radius: 50%;
- background: var(--tui-green);
- box-shadow: 0 0 8px var(--tui-green);
-}
-
-.a3s-tui-user {
- margin-top: 18px;
- padding: 13px 14px;
- border-left: 2px solid var(--tui-blue);
- background: var(--tui-panel);
-}
-
-.a3s-tui-user > span {
- color: var(--tui-blue);
- font-size: 7px;
- font-weight: 700;
- letter-spacing: 0.12em;
-}
-
-.a3s-tui-user p {
- margin: 5px 0 0 !important;
- color: var(--tui-text);
- font-size: 9px;
- line-height: 1.65;
-}
-
-.a3s-tui-activity {
- padding: 15px 2px 12px;
-}
-
-.a3s-tui-activity p {
- display: flex;
- margin: 0 !important;
- padding: 5px 0;
- color: var(--tui-muted);
- align-items: center;
- gap: 8px;
- font-size: 9px;
-}
-
-.a3s-tui-activity p > span {
- width: 11px;
- color: var(--tui-green);
- text-align: center;
-}
-
-.a3s-tui-activity p.is-running {
- color: var(--tui-text);
-}
-
-.a3s-tui-activity p.is-running > span {
- color: var(--tui-amber);
-}
-
-.a3s-tui-checklist {
- padding: 10px 12px;
- border: 1px solid var(--tui-line);
- background: var(--tui-panel);
-}
-
-.a3s-tui-checklist > strong {
- display: block;
- margin-bottom: 5px;
- color: var(--tui-purple);
- font-size: 8px;
- letter-spacing: 0.07em;
- text-transform: uppercase;
-}
-
-.a3s-tui-checklist button {
- display: flex;
- width: 100%;
- padding: 4px 0;
- background: transparent;
- color: var(--tui-text);
- align-items: center;
- gap: 8px;
- font-size: 9px;
- text-align: left;
-}
-
-.a3s-tui-checklist button > span:first-child {
- width: 11px;
- color: var(--tui-green);
-}
-
-.a3s-tui-checklist .is-checked {
- color: var(--tui-muted);
- text-decoration: line-through;
-}
-
-.a3s-tui-diff > header,
-.a3s-tui-file-heading {
- display: flex;
- min-height: 36px;
- align-items: center;
- gap: 9px;
-}
-
-.a3s-tui-diff > header {
- padding: 0 9px 10px;
- border-bottom: 1px solid var(--tui-line);
-}
-
-.a3s-tui-diff > header strong {
- color: var(--tui-blue);
- font-size: 8px;
- letter-spacing: 0.1em;
-}
-
-.a3s-tui-diff > header span {
- color: var(--tui-muted);
- font-size: 8px;
-}
-
-.a3s-tui-diff > header small {
- margin-left: auto;
- color: var(--tui-green);
- font-size: 8px;
-}
-
-.a3s-tui-file-heading {
- padding: 0 9px;
- background: var(--tui-panel);
- font-size: 9px;
-}
-
-.a3s-tui-file-heading > span {
- color: var(--tui-blue);
-}
-
-.a3s-tui-file-heading small {
- margin-left: auto;
- color: var(--tui-green);
- font-size: 8px;
-}
-
-.a3s-tui-diff pre,
-.a3s-tui-workspace pre {
- margin: 0 !important;
- padding: 10px 0;
- border: 0;
- border-radius: 0;
- overflow: hidden;
- background: transparent;
- color: var(--tui-text);
- font-family: inherit;
- font-size: 8px;
- line-height: 1.75;
-}
-
-.a3s-tui-diff pre .line {
- display: block;
- padding: 0 10px;
- white-space: pre;
-}
-
-.a3s-tui-diff pre .line i,
-.a3s-tui-workspace pre i {
- display: inline-block;
- width: 28px;
- color: var(--tui-muted);
- font-style: normal;
- text-align: right;
-}
-
-.a3s-tui-diff pre .line.added {
- background: color-mix(in srgb, var(--tui-green) 13%, transparent);
- color: var(--tui-green);
-}
-
-.a3s-tui-diff pre .line.removed {
- background: color-mix(in srgb, var(--tui-red) 13%, transparent);
- color: var(--tui-red);
-}
-
-.a3s-tui-workspace {
- display: grid;
- min-height: 480px;
- grid-template-columns: 205px minmax(0, 1fr);
-}
-
-.a3s-tui-workspace > section:first-child {
- border-right: 1px solid var(--tui-line);
- background: var(--tui-panel);
-}
-
-.a3s-tui-workspace section > header {
- display: flex;
- min-height: 38px;
- padding: 0 12px;
- border-bottom: 1px solid var(--tui-line);
- color: var(--tui-muted);
- align-items: center;
- justify-content: space-between;
- font-size: 8px;
- font-weight: 700;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
-.a3s-tui-workspace section > header small {
- color: var(--tui-blue);
- font-size: 7px;
-}
-
-.a3s-tui-workspace section > p {
- display: flex;
- margin: 0 !important;
- min-height: 27px;
- padding: 0 11px;
- color: var(--tui-muted);
- align-items: center;
- gap: 8px;
- font-size: 8px;
- white-space: pre;
-}
-
-.a3s-tui-workspace section > p.is-active {
- background: var(--tui-panel-strong);
- color: var(--tui-text);
-}
-
-.a3s-tui-workspace section > p > span {
- color: var(--tui-blue);
-}
-
-.a3s-tui-workspace pre span {
- display: block;
- min-height: 24px;
- padding: 0 16px 0 0;
-}
-
-.a3s-tui-workspace pre span.is-highlighted {
- background: var(--tui-panel-strong);
-}
-
-.a3s-tui-workspace pre b {
- color: var(--tui-purple);
- font-weight: 500;
-}
-
-.a3s-tui-workspace pre em {
- color: var(--tui-amber);
- font-style: normal;
-}
-
-.a3s-tui-components > header {
- display: flex;
- padding-bottom: 15px;
- border-bottom: 1px solid var(--tui-line);
- flex-direction: column;
- gap: 4px;
-}
-
-.a3s-tui-components > header strong {
- color: var(--tui-text);
- font-size: 10px;
-}
-
-.a3s-tui-components > header small {
- color: var(--tui-muted);
- font-size: 8px;
-}
-
-.a3s-tui-components > div {
- display: grid;
- min-height: 350px;
- padding-top: 18px;
- gap: 20px;
- grid-template-columns: 180px minmax(0, 1fr);
-}
-
-.a3s-tui-components nav {
- display: flex;
- flex-direction: column;
- gap: 3px;
-}
-
-.a3s-tui-components nav button {
- display: flex;
- min-height: 31px;
- padding: 0 9px;
- border-radius: 4px;
- background: transparent;
- color: var(--tui-muted);
- align-items: center;
- gap: 7px;
- font-size: 8px;
- text-align: left;
-}
-
-.a3s-tui-components nav button.is-active {
- background: var(--tui-panel-strong);
- color: var(--tui-text);
-}
-
-.a3s-tui-components nav button span {
- color: var(--tui-blue);
-}
-
-.a3s-tui-components > div > section {
- padding: 14px;
- border: 1px solid var(--tui-line);
- background: var(--tui-panel);
-}
-
-.a3s-tui-components > div > section > strong {
- color: var(--tui-blue);
- font-size: 9px;
-}
-
-.a3s-tui-components > div > section > p {
- margin: 8px 0 18px !important;
- color: var(--tui-muted);
- font-size: 8px;
- line-height: 1.7;
-}
-
-.a3s-tui-mini {
- display: grid;
- min-height: 160px;
- padding: 15px;
- border: 1px solid var(--tui-line);
- background: var(--tui-bg);
- color: var(--tui-text);
- align-content: center;
- gap: 10px;
- font-size: 8px;
-}
-
-.a3s-tui-mini span:first-child {
- color: var(--tui-green);
- font-weight: 700;
-}
-
-.a3s-tui-mini span:nth-child(2) {
- color: var(--tui-blue);
-}
-
-.a3s-tui-mini span:nth-child(3) {
- color: var(--tui-muted);
-}
-
-.a3s-tui-mini span:last-child {
- padding: 5px 7px;
- background: var(--tui-panel-strong);
- color: var(--tui-text);
-}
-
-.a3s-tui-status {
- display: grid;
- min-height: 27px;
- padding: 0 9px;
- border-top: 1px solid var(--tui-line);
- background: var(--tui-panel-strong);
- color: var(--tui-muted);
- align-items: center;
- gap: 12px;
- grid-template-columns: auto auto auto 1fr;
- font-size: 7px;
-}
-
-.a3s-tui-status span:first-child {
- padding: 2px 5px;
- background: var(--tui-blue);
- color: var(--tui-bg);
- font-weight: 800;
-}
-
-.a3s-tui-status span:last-child {
- overflow: hidden;
- text-align: right;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-/* Web playground — follows apps/web design tokens */
-
-.a3s-web-playground {
- background: #f7f7f8;
-}
-
-.a3s-web-steps {
- display: flex;
- min-width: 0;
- align-items: center;
- gap: 3px;
-}
-
-.a3s-web-steps button {
- display: flex;
- min-height: 30px;
- padding: 0 9px;
- border-radius: 7px;
- background: transparent;
- color: #888e99;
- align-items: center;
- gap: 6px;
- font-size: 10px;
- font-weight: 600;
-}
-
-.a3s-web-steps button > span {
- display: grid;
- width: 17px;
- height: 17px;
- border: 1px solid #3a3e47;
- border-radius: 50%;
- color: #8f96a2;
- place-items: center;
- font-size: 8px;
-}
-
-.a3s-web-steps button:hover,
-.a3s-web-steps button.is-active {
- background: #1a1c22;
- color: #f1f3f6;
-}
-
-.a3s-web-steps button.is-active > span {
- border-color: #6ca3ff;
- background: #6ca3ff;
- color: #101118;
-}
-
-.a3s-web-frame {
- display: grid;
- min-height: 610px;
- background: #f7f7f8;
- color: #17181a;
- grid-template-columns: 52px 200px minmax(0, 1fr);
-}
-
-.a3s-web-activity {
- display: flex;
- padding: 8px 7px;
- border-right: 1px solid #e2e4e8;
- background: #fff;
- flex-direction: column;
- align-items: center;
- gap: 5px;
-}
-
-.a3s-web-activity button,
-.a3s-web-brand {
- display: grid;
- width: 36px;
- height: 36px;
- border-radius: 9px;
- background: transparent;
- color: #8d929b;
- place-items: center;
- font-size: 17px;
-}
-
-.a3s-web-brand {
- margin-bottom: 10px;
- background: linear-gradient(135deg, #2587f5, #3b53dc 48%, #5221bd);
- color: #fff;
-}
-
-.a3s-web-brand svg,
-.a3s-web-welcome-mark svg {
- width: 21px;
- height: 21px;
- fill: none;
- stroke: currentcolor;
- stroke-linecap: round;
- stroke-linejoin: round;
- stroke-width: 1.55;
-}
-
-.a3s-web-activity button:hover,
-.a3s-web-activity button.is-active {
- background: #f0f2f5;
- color: #2864e8;
-}
-
-.a3s-web-activity button:last-child {
- margin-top: auto;
-}
-
-.a3s-web-library {
- display: flex;
- padding: 14px 10px;
- border-right: 1px solid #e2e4e8;
- background: #f7f7f8;
- flex-direction: column;
- gap: 4px;
-}
-
-.a3s-web-library > header {
- display: flex;
- height: 36px;
- padding: 0 5px;
- align-items: center;
- justify-content: space-between;
-}
-
-.a3s-web-library > header strong {
- color: #282a2e;
- font-size: 12px;
- font-weight: 650;
-}
-
-.a3s-web-library > header button {
- width: 26px;
- height: 26px;
- border-radius: 7px;
- background: transparent;
- color: #747982;
- font-size: 17px;
-}
-
-.a3s-web-library > header button:hover {
- background: #e9ebef;
- color: #2864e8;
-}
-
-.a3s-web-library > button {
- display: flex;
- min-height: 34px;
- padding: 0 9px;
- border-radius: 8px;
- overflow: hidden;
- background: transparent;
- color: #656a73;
- align-items: center;
- gap: 8px;
- font-size: 10px;
- text-align: left;
-}
-
-.a3s-web-library > button > span:last-child {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.a3s-web-library > button:hover,
-.a3s-web-library > button.is-active {
- background: #e9ebef;
- color: #25272b;
-}
-
-.a3s-web-library > button.is-active > span:first-child {
- color: #14a675;
-}
-
-.a3s-web-library > button.a3s-web-new-task {
- margin-bottom: 12px;
- background: #242424;
- color: #fff;
- justify-content: center;
- font-weight: 620;
-}
-
-.a3s-web-library > small {
- margin: 4px 9px;
- color: #9a9fa7;
- font-size: 8px;
- font-weight: 700;
- letter-spacing: 0.09em;
-}
-
-.a3s-web-main {
- min-width: 0;
- background:
- radial-gradient(circle at 50% 20%, rgb(40 100 232 / 5%), transparent 36%),
- #fff;
-}
-
-.a3s-web-compose {
- display: flex;
- min-height: 610px;
- padding: 52px 32px 34px;
- align-items: center;
- flex-direction: column;
-}
-
-.a3s-web-welcome {
- margin: auto 0 27px;
- text-align: center;
-}
-
-.a3s-web-welcome-mark {
- display: grid;
- width: 48px;
- height: 48px;
- margin: 0 auto 15px;
- border-radius: 14px;
- background: linear-gradient(135deg, #2587f5, #3b53dc 48%, #5221bd);
- color: #fff;
- box-shadow: 0 13px 30px rgb(59 83 220 / 20%);
- place-items: center;
-}
-
-.a3s-web-welcome h3 {
- margin: 0;
- color: #17181a;
- font-size: 20px;
- font-weight: 660;
- letter-spacing: -0.035em;
-}
-
-.a3s-web-welcome p {
- margin: 6px 0 0 !important;
- color: #7a7f88;
- font-size: 11px;
-}
-
-.a3s-web-composer {
- width: min(610px, 100%);
- padding: 12px 13px 10px;
- border: 1px solid #d9dce2;
- border-radius: 15px;
- background: #fff;
- box-shadow: 0 12px 38px rgb(20 24 40 / 9%);
-}
-
-.a3s-web-composer:focus-within {
- border-color: rgb(40 100 232 / 55%);
- box-shadow:
- 0 12px 38px rgb(20 24 40 / 9%),
- 0 0 0 3px rgb(40 100 232 / 7%);
-}
-
-.a3s-web-composer textarea {
- width: 100%;
- min-height: 92px;
- padding: 3px 4px;
- resize: none;
- border: 0;
- outline: 0;
- background: transparent;
- color: #1f2125;
- font: inherit;
- font-size: 12px;
- line-height: 1.65;
-}
-
-.a3s-web-composer footer {
- display: flex;
- min-height: 33px;
- align-items: center;
- justify-content: space-between;
- gap: 8px;
-}
-
-.a3s-web-composer footer > div {
- display: flex;
- min-width: 0;
- flex-wrap: wrap;
- gap: 4px;
-}
-
-.a3s-web-composer footer button {
- min-height: 28px;
- padding: 0 8px;
- border-radius: 7px;
- background: #f2f3f5;
- color: #676c75;
- font-size: 9px;
-}
-
-.a3s-web-composer footer button:hover {
- background: #e9ebef;
- color: #2864e8;
-}
-
-.a3s-web-composer footer button.a3s-web-send {
- width: 30px;
- padding: 0;
- border-radius: 9px;
- background: #242424;
- color: #fff;
- font-size: 16px;
-}
-
-.a3s-web-composer footer button:disabled,
-.a3s-web-demo-action:disabled {
- cursor: not-allowed;
- opacity: 0.42;
-}
-
-.a3s-web-playground .a3s-web-demo-action {
- min-height: 34px;
- margin-top: 16px;
- padding: 0 14px;
- border-radius: 8px;
- background: #242424;
- color: #fff;
- font-size: 10px;
- font-weight: 620;
-}
-
-.a3s-web-playground .a3s-web-demo-action:hover {
- background: #111;
- transform: translateY(-1px);
-}
-
-.a3s-web-task {
- min-height: 610px;
-}
-
-.a3s-web-task-header {
- display: flex;
- min-height: 64px;
- padding: 0 16px;
- border-bottom: 1px solid #e2e4e8;
- background: #fff;
- align-items: center;
- justify-content: space-between;
- gap: 16px;
-}
-
-.a3s-web-task-header > div {
- display: flex;
- min-width: 0;
- align-items: center;
- gap: 9px;
-}
-
-.a3s-web-task-icon {
- display: grid;
- width: 32px;
- height: 32px;
- flex: 0 0 32px;
- border: 1px solid rgb(40 100 232 / 18%);
- border-radius: 9px;
- background: rgb(40 100 232 / 7%);
- color: #2864e8;
- place-items: center;
-}
-
-.a3s-web-task-header > div > span:last-child {
- display: flex;
- min-width: 0;
- flex-direction: column;
-}
-
-.a3s-web-task-header strong {
- overflow: hidden;
- color: #17181a;
- font-size: 12px;
- font-weight: 650;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.a3s-web-task-header small {
- overflow: hidden;
- color: #858a93;
- font-size: 9px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.a3s-web-running {
- display: flex;
- padding: 4px 8px;
- border-radius: 999px;
- background: rgb(20 166 117 / 9%);
- color: #128760;
- align-items: center;
- gap: 6px;
- font-size: 9px;
- font-weight: 650;
-}
-
-.a3s-web-running i {
- width: 6px;
- height: 6px;
- border-radius: 50%;
- background: #14a675;
- box-shadow: 0 0 8px rgb(20 166 117 / 45%);
-}
-
-.a3s-web-task-body {
- display: grid;
- min-height: 546px;
- grid-template-columns: minmax(0, 1fr) 210px;
-}
-
-.a3s-web-stream {
- padding: 26px min(4vw, 36px);
- border-right: 1px solid #e2e4e8;
- overflow: hidden;
-}
-
-.a3s-web-instruction {
- margin-left: auto;
- max-width: 85%;
- padding: 10px 12px;
- border-radius: 12px 12px 3px 12px;
- background: #f0f2f5;
- color: #35383d;
- font-size: 10px;
- line-height: 1.6;
-}
-
-.a3s-web-reasoning {
- margin-top: 22px;
- padding: 12px;
- border: 1px solid #e2e4e8;
- border-radius: 10px;
- background: #fff;
-}
-
-.a3s-web-reasoning header {
- display: flex;
- align-items: center;
- gap: 7px;
-}
-
-.a3s-web-reasoning header > span {
- color: #5420bd;
-}
-
-.a3s-web-reasoning header strong {
- color: #34363a;
- font-size: 10px;
- font-weight: 630;
-}
-
-.a3s-web-reasoning header small {
- margin-left: auto;
- color: #979ba3;
- font-size: 8px;
-}
-
-.a3s-web-reasoning p {
- margin: 6px 0 0 20px !important;
- color: #7a7f87;
- font-size: 9px;
- line-height: 1.6;
-}
-
-.a3s-web-tool-call {
- display: grid;
- min-height: 39px;
- margin-top: 7px;
- padding: 0 10px;
- border: 1px solid #e2e4e8;
- border-radius: 8px;
- background: #fff;
- color: #34363b;
- align-items: center;
- gap: 7px;
- grid-template-columns: 14px minmax(0, 1fr) auto;
- font-size: 9px;
-}
-
-.a3s-web-tool-call > span {
- color: #14a675;
-}
-
-.a3s-web-tool-call.is-running > span {
- color: #c97816;
-}
-
-.a3s-web-tool-call strong {
- overflow: hidden;
- font-weight: 580;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.a3s-web-tool-call small {
- color: #959aa3;
- font-size: 8px;
-}
-
-.a3s-web-stream > .a3s-web-demo-action {
- float: right;
-}
-
-.a3s-web-plan {
- padding: 18px 14px;
- background: #f7f7f8;
-}
-
-.a3s-web-plan > header {
- display: flex;
- margin-bottom: 12px;
- color: #34363b;
- align-items: center;
- justify-content: space-between;
- font-size: 10px;
-}
-
-.a3s-web-plan > header span {
- color: #90959e;
- font-size: 8px;
-}
-
-.a3s-web-plan p {
- display: grid;
- margin: 0 !important;
- min-height: 37px;
- color: #777c85;
- align-items: center;
- gap: 7px;
- grid-template-columns: 13px minmax(0, 1fr);
- font-size: 9px;
- line-height: 1.45;
-}
-
-.a3s-web-plan p.is-complete > span {
- color: #14a675;
-}
-
-.a3s-web-plan p.is-running {
- color: #2d3035;
-}
-
-.a3s-web-plan p.is-running > span {
- color: #c97816;
-}
-
-.a3s-web-permission-wrap {
- display: grid;
- min-height: 546px;
- padding: 30px;
- background:
- radial-gradient(circle at 50% 30%, rgb(201 120 22 / 6%), transparent 34%),
- #f7f7f8;
- place-items: center;
-}
-
-.a3s-web-permission {
- width: min(500px, 100%);
- padding: 15px;
- border: 1px solid #e1d4c1;
- border-radius: 13px;
- background: #fff;
- box-shadow: 0 18px 50px rgb(20 24 40 / 10%);
-}
-
-.a3s-web-permission > header {
- display: flex;
- padding-bottom: 13px;
- border-bottom: 1px solid #ece4d8;
- align-items: center;
- gap: 10px;
-}
-
-.a3s-web-permission > header > span:first-child {
- display: grid;
- width: 31px;
- height: 31px;
- border-radius: 9px;
- background: rgb(201 120 22 / 10%);
- color: #c97816;
- place-items: center;
- font-size: 17px;
-}
-
-.a3s-web-permission > header > span:last-child {
- display: flex;
- flex-direction: column;
-}
-
-.a3s-web-permission > header strong {
- color: #24262a;
- font-size: 11px;
- font-weight: 660;
-}
-
-.a3s-web-permission > header small {
- color: #8b9098;
- font-size: 8px;
-}
-
-.a3s-web-permission dl {
- margin: 7px 0 12px;
-}
-
-.a3s-web-permission dl > div {
- display: grid;
- padding: 7px 3px;
- gap: 12px;
- grid-template-columns: 82px minmax(0, 1fr);
-}
-
-.a3s-web-permission dt {
- color: #92969e;
- font-size: 8px;
-}
-
-.a3s-web-permission dd {
- margin: 0;
- color: #4e5259;
- font-size: 9px;
- line-height: 1.55;
-}
-
-.a3s-web-permission > footer {
- display: flex;
- padding-top: 12px;
- border-top: 1px solid #eceef1;
- justify-content: flex-end;
- gap: 7px;
-}
-
-.a3s-web-permission > footer button,
-.a3s-web-permission output button {
- min-height: 31px;
- padding: 0 11px;
- border: 1px solid #dfe2e7;
- border-radius: 8px;
- background: #fff;
- color: #656a72;
- font-size: 9px;
- font-weight: 620;
-}
-
-.a3s-web-permission > footer button.is-primary {
- border-color: #242424;
- background: #242424;
- color: #fff;
-}
-
-.a3s-web-permission output {
- display: flex;
- padding: 11px;
- border-radius: 8px;
- background: rgb(216 75 79 / 7%);
- color: #c94348;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- font-size: 9px;
-}
-
-.a3s-web-permission output button {
- border-color: rgb(216 75 79 / 20%);
- background: transparent;
- color: #b83a40;
-}
-
-.a3s-web-result {
- display: flex;
- min-height: 610px;
- padding: 42px 28px 28px;
- align-items: center;
- flex-direction: column;
- text-align: center;
-}
-
-.a3s-web-result-mark {
- display: grid;
- width: 46px;
- height: 46px;
- margin-bottom: 13px;
- border-radius: 50%;
- background: rgb(20 166 117 / 10%);
- color: #14a675;
- place-items: center;
- font-size: 21px;
- font-weight: 700;
-}
-
-.a3s-web-result-label {
- color: #14a675;
- font-size: 8px;
- font-weight: 700;
- letter-spacing: 0.12em;
- text-transform: uppercase;
-}
-
-.a3s-web-result h3 {
- margin: 6px 0 0;
- color: #17181a;
- font-size: 20px;
- font-weight: 660;
- letter-spacing: -0.035em;
-}
-
-.a3s-web-result > p {
- max-width: 550px;
- margin: 7px 0 0 !important;
- color: #747982;
- font-size: 10px;
-}
-
-.a3s-web-result-stats {
- display: flex;
- margin-top: 18px;
- padding: 7px;
- border: 1px solid #e2e4e8;
- border-radius: 10px;
- background: #f7f7f8;
- flex-wrap: wrap;
- gap: 4px;
-}
-
-.a3s-web-result-stats span {
- padding: 4px 8px;
- color: #656a73;
- font-size: 8px;
-}
-
-.a3s-web-result-stats i {
- color: #14a675;
- font-style: normal;
-}
-
-.a3s-web-changes {
- width: min(520px, 100%);
- margin-top: 20px;
- border: 1px solid #e2e4e8;
- border-radius: 11px;
- overflow: hidden;
- background: #fff;
- text-align: left;
-}
-
-.a3s-web-changes > header {
- display: flex;
- min-height: 38px;
- padding: 0 12px;
- border-bottom: 1px solid #e2e4e8;
- background: #f7f7f8;
- color: #3b3e43;
- align-items: center;
- justify-content: space-between;
- font-size: 9px;
-}
-
-.a3s-web-changes > header small {
- color: #14a675;
- font-size: 8px;
-}
-
-.a3s-web-changes > p {
- display: grid;
- margin: 0 !important;
- min-height: 43px;
- padding: 0 12px;
- border-bottom: 1px solid #eceef1;
- color: #3e4146;
- align-items: center;
- gap: 9px;
- grid-template-columns: 24px minmax(0, 1fr) auto;
- font-size: 9px;
-}
-
-.a3s-web-changes > p:last-child {
- border-bottom: 0;
-}
-
-.a3s-web-changes > p > span {
- display: grid;
- width: 22px;
- height: 22px;
- border-radius: 6px;
- background: rgb(49 120 198 / 9%);
- color: #3178c6;
- place-items: center;
- font-size: 7px;
- font-weight: 700;
-}
-
-.a3s-web-changes > p small {
- color: #14a675;
- font-size: 8px;
-}
-
-@media (max-width: 900px) {
- .a3s-building-blocks {
- grid-template-columns: 190px minmax(0, 1fr);
- }
-
- .a3s-building-block-detail {
- padding: 24px;
- }
-
- .a3s-web-frame {
- grid-template-columns: 48px 168px minmax(0, 1fr);
- }
-
- .a3s-web-library {
- padding-right: 7px;
- padding-left: 7px;
- }
-
- .a3s-web-task-body {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .a3s-web-plan {
- display: grid;
- border-top: 1px solid #e2e4e8;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 7px;
- }
-
- .a3s-web-plan > header {
- grid-column: 1 / -1;
- }
-}
-
-@media (max-width: 680px) {
- .a3s-playground-toolbar {
- padding: 10px 13px;
- align-items: flex-start;
- flex-direction: column;
- gap: 9px;
- }
-
- .a3s-web-steps {
- width: 100%;
- overflow-x: auto;
- }
-
- .a3s-web-steps button {
- padding: 0 7px;
- white-space: nowrap;
- }
-
- .a3s-building-blocks {
- display: block;
- }
-
- .a3s-building-block-nav {
- overflow-x: auto;
- border-right: 0;
- border-bottom: 1px solid #292c33;
- flex-direction: row;
- }
-
- .a3s-building-block-nav button {
- min-width: 145px;
- }
-
- .a3s-building-block-grid {
- grid-template-columns: 1fr;
- }
-
- .a3s-tui-frame {
- margin: 10px;
- }
-
- .a3s-tui-titlebar {
- grid-template-columns: 1fr auto;
- }
-
- .a3s-tui-titlebar span:nth-child(2),
- .a3s-tui-sidebar {
- display: none;
- }
-
- .a3s-tui-screen {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .a3s-tui-session,
- .a3s-tui-diff,
- .a3s-tui-components {
- padding: 15px 13px;
- }
-
- .a3s-tui-workspace {
- grid-template-columns: 145px minmax(0, 1fr);
- }
-
- .a3s-tui-components > div {
- grid-template-columns: 1fr;
- }
-
- .a3s-tui-components nav {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .a3s-tui-status {
- grid-template-columns: auto auto 1fr;
- }
-
- .a3s-tui-status span:last-child {
- display: none;
- }
-
- .a3s-web-frame {
- min-height: 570px;
- grid-template-columns: minmax(0, 1fr);
- }
-
- .a3s-web-activity,
- .a3s-web-library {
- display: none;
- }
-
- .a3s-web-compose,
- .a3s-web-task,
- .a3s-web-result {
- min-height: 570px;
- }
-
- .a3s-web-compose {
- padding: 38px 15px 25px;
- }
-
- .a3s-web-task-header {
- padding: 0 12px;
- }
-
- .a3s-web-task-header small,
- .a3s-web-running {
- display: none;
- }
-
- .a3s-web-stream {
- padding: 20px 14px;
- border-right: 0;
- }
-
- .a3s-web-plan {
- grid-template-columns: 1fr;
- }
-
- .a3s-web-permission-wrap {
- padding: 18px 12px;
- }
-
- .a3s-web-permission dl > div {
- gap: 3px;
- grid-template-columns: 1fr;
- }
-
- .a3s-web-result {
- padding-right: 15px;
- padding-left: 15px;
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .a3s-playground *,
- .a3s-building-blocks * {
- scroll-behavior: auto !important;
- transition: none !important;
- }
-}