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}
+
{footer}
+
+ ); +} + +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 ? ( + + {decision === 'allow' + ? locale === 'zh' + ? '已允许这一次操作' + : 'Allowed for this operation' + : locale === 'zh' + ? '已拒绝,不会执行' + : 'Denied; nothing will run'} + + ) : ( +
+ + +
+ )} +
+
+ + ); +} + +function TextInputDemo({ locale }: DemoProps) { + const initial = + locale === 'zh' + ? '检查登录流程并补上测试' + : 'Inspect the login flow and add tests'; + const [value, setValue] = useState(initial); + + return ( + <> + + length: {value.length} + + + +
+ +
+ + setValue(event.target.value)} + spellCheck="false" + value={value} + /> + {value.length}/240 +
+

+ {value.trim() + ? locale === 'zh' + ? 'Enter 发送' + : 'Press Enter to send' + : locale === 'zh' + ? '请输入内容' + : 'Type an instruction'} +

+
+
+ + ); +} + +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} + + ))} + + + + + + + + + + + + + {sorted.map((row) => ( + setSelected(row.name)} + > + + + + + ))} + +
{locale === 'zh' ? '工具调用' : 'Tool calls'}
TOOLSTATUSDURATION
{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 + + + +
+
TOOL LOG
+ {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 && ( + + + {kind === 'saved' + ? locale === 'zh' + ? '会话已保存' + : 'Session saved' + : locale === 'zh' + ? '路径已复制' + : 'Path copied'} + + + )} +
+
+ + ); +} + +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.'} +

+
+ {mode.toUpperCase()} + default · medium + 79 ? 'is-warning' : undefined}> + ctx {context}% + + Ctrl+T transcript · /help +
+
+
+ + ); +} + +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 + + +
+