Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:
cancel-in-progress: false
env:
# Immutable commit in A3S-Lab/a3s containing the Web workspace sources.
A3S_WEB_SOURCE_REF: dadabffcadc86b643da8622607823f6d32583e06
A3S_WEB_SOURCE_REF: f5db7e68b5e91d21b5c0fbe003aae92b3d4efb75
# Exact companion prerequisite; preflight rejects an absent or incomplete release.
A3S_WEBVIEW_VERSION: 0.1.5
A3S_CODE_CORE_VERSION: 6.5.1
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.10.12] - 2026-07-28

### Added

- Added a persistent, resizable A3S Work live-preview panel for static sites,
loopback development servers, text, images, PDFs, and supported Office files.
Static sites reload after debounced workspace changes and provide responsive
device, zoom, refresh, pause, and external-window controls.
- Added `/preview <path|localhost-url>`, `/preview status`, and `/preview stop`
to the Code TUI. The workspace IDE also opens the selected item with `p`, and
`:preview` saves a dirty editor buffer before opening it.

### Security

- Confined file previews to canonical active-workspace paths, blocked traversal,
hidden and sensitive files, escaping symbolic links, and oversized assets,
and limited URL previews to HTTP(S) loopback hosts. Static HTML runs in an
opaque-origin CSP sandbox, and preview descriptors and content now expire at
their declared deadline.
- Kept native preview-window ownership separate from the shared Web process.
Preview replacement, stop, and TUI exit close only the exact tracked window,
and the window receives no A3S OS access or refresh token.

### Fixed

- Kept structured generation compatible with Kimi thinking-only models by
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "a3s"
version = "0.10.11"
version = "0.10.12"
edition = "2021"
description = "a3s — A3S coding agent CLI; `a3s code` launches the interactive TUI"
license = "MIT"
Expand Down
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,28 @@ never terminated. Port binding and asset validation happen before
configuration-heavy session restoration, so conflicts and broken installations
fail quickly without unrelated restore warnings.

Open a workspace artifact or local development server from inside the TUI:

```text
/preview site/index.html
/preview docs/Product brief.pdf
/preview localhost:5173
/preview status
/preview stop
```

`/preview` reuses a compatible managed Web instance for the current workspace
or starts one on an ephemeral loopback port. It opens Work's persistent preview
panel in a native `a3s-webview` window when available and uses the system browser
as a fallback. Replacing a preview, `/preview stop`, and TUI exit close only the
exact native preview window; the shared Web service remains running. A browser
fallback is user-owned and cannot be closed safely by the TUI.

Inside `/ide`, press `p` on the selected workspace item. In an open editor, run
`:preview`; a dirty buffer is saved through the normal workspace path before
the preview opens. Static sites reload after debounced workspace changes, while
loopback URLs retain their development server's own navigation and HMR.

Web tasks, visible messages, titles, goals, effort, model selection, and
execution mode are saved under `~/.a3s/code-web` and restored before the API
starts accepting requests. Set `A3S_CODE_WEB_STATE_DIR` to isolate that store.
Expand Down Expand Up @@ -872,6 +894,7 @@ input prefixes:
/tasks
/permissions
/ide
/preview site/index.html
/login
/agent
/mcp
Expand All @@ -893,7 +916,7 @@ input prefixes:
| Coding loop | Chat with the coding agent, stream semantic tool cards, choose Default, Plan, or Auto execution, inspect and control pending follow-ups with `/queue`, and inspect or safely cancel delegated work with `/tasks` or `Ctrl+B`. Run direct shell turns with `!`, run a durable Ultracode `/goal`, and fork, rewind, or clear sessions when needed. `/relay` pins the current session, searches a bounded 64-row catalog per source, preserves semantic selection across refreshes, shows saved state, model, age, unfinished runs, and live background-agent counts, or hands the latest task from a workspace-scoped external transcript to the active session. |
| Permission review | Gated calls enter a FIFO approval queue backed by the authoritative tool name and arguments. The overlay can allow once, grant that exact capability for the current session, atomically add the reviewed capability to `.a3s/permissions.acl`, or collect denial feedback for the agent. `/permissions` searches session and project grants, opens their canonical arguments, and revokes only after a second matching action. Project rules are bounded, parsed and generated with `a3s-acl`, reject symbolic-link targets, and remain narrower than hard workspace guardrails. Revocation affects future checks, not tools already running. |
| Execution modes | Default runs bounded workspace file changes directly. A shared Rust guardrail silently admits a narrow, proven read-only host Bash subset; unproven commands, protected metadata, mutating Git operations, and annotated external side effects enter HITL, while critical commands fail closed. Plan exposes only read-only discovery tools and denies Bash. Auto never enters HITL: it admits only Rust-proven read-only Bash and denies other host commands, protected metadata, and mutating Git operations. A queued turn retains the mode captured when it was submitted. |
| Workspace UI | `/ide` opens a superfile-style tree and editor with terminal-stable file marks, `/config` edits the active config in the same editor, `Ctrl+T` opens the complete semantic transcript, and file edits render bounded diffs through the shared `DiffView` component. Diff headers use green `+N` and red `-N` counts; Markdown uses Codex-spaced section headings, responsive tables, syntax highlighting, and terminal hyperlinks. |
| Workspace UI | `/ide` opens a superfile-style tree and editor with terminal-stable file marks, `p` previews the selected item, and `:preview` saves and previews the open buffer. `/preview <path\|localhost-url>` opens the same persistent Work surface from the transcript. `/config` edits the active config in the shared editor, `Ctrl+T` opens the complete semantic transcript, and file edits render bounded diffs through the shared `DiffView` component. |
| Models and effort | `/model` switches configured providers, OS gateway models, and signed-in account tabs. Codex account discovery delegates refresh and entitlement checks to the installed Codex CLI, so an expired identity token does not hide models while reusable account access remains. WorkBuddy `hy3` tagged calls are converted into native tool events without exposing protocol markup in streamed messages. `/effort` scales thinking budget, tool-round budget, auto-continuation, and model-agnostic rigor guidance from `low` through `max` and `ultracode`. A3S Code 5.2.4 structured calls use native JSON Schema or forced-tool output only when the active client advertises that capability; unknown custom OpenAI-compatible endpoints retain the bounded prompt fallback instead of receiving an assumed `tool_choice`. |
| Dynamic workflows | `ultracode` and `?` DeepResearch can use `DynamicWorkflowRuntime`, a local A3S Flow-backed workflow runner. It records workflow/step history while PTC scripts perform ordinary tool work. This is separate from `/flow`, which is OS Workflow as a Service for persisted workflow assets. |
| Local and remote parallelism | Local subagent fan-out uses the host-side `parallel_task` tool. QuickJS/PTC scripts do not call `parallel_task` directly; dynamic workflows schedule a Flow step named `parallel_task`, and the host executes it natively. After `/login`, the signed-in `runtime` tool is available to workflow steps and model turns for OS Runtime batch execution. |
Expand Down Expand Up @@ -1038,6 +1061,7 @@ permissions, tools, panels, and follow-up evidence are needed.
| --- | --- | --- |
| Repository orientation | Start with `/init`, ask for a map of the codebase, attach files with `@`, and open `/ide` when you need to browse or edit directly. | `/init`, `/ide`, `@<path>`, `/ctx`, `/help` |
| Focused coding | Ask for a change, review streamed reads/searches/diffs, approve gated writes, and let the agent run focused checks before summarizing what changed. | Tool cards, approval overlay, `DiffView`, `Ctrl+T`, `! <command>` |
| Artifact inspection | Keep a static site, local development server, document, image, PDF, or source file visible in Work while coding continues; use the IDE shortcuts when already browsing or editing. | `/preview <target>`, `/preview status`, `/preview stop`, IDE `p`, editor `:preview` |
| Debugging and verification | Let the model inspect logs, grep call sites, run shell or test commands, and keep the exact tool evidence visible in the semantic transcript. | `grep`, `read`, `bash`, `git`, `Ctrl+T`, `a3s top` |
| Context carry-over | Search previous sessions, attach relevant transcript windows, save durable facts, and compact when the context meter gets high. | `/ctx <query>`, `/ctx <n>`, `/ctx save <n>`, `/memory`, `/sleep`, `/compact` |
| Deep work | Raise `/effort`, use `ultracode` for complex turns, and let the host decide whether planning, goal tracking, dynamic workflow execution, or parallel fan-out is justified. | `/effort`, `/goal`, `dynamic_workflow`, `task`, `parallel_task` |
Expand Down Expand Up @@ -1127,7 +1151,7 @@ cells adding or doubling their own outer padding.
| System agent island | Enabled by default. `/island on`, `/island off`, and `/island status` persist or inspect the user preference, and the expanded island also offers `Turn off`. A fresh exact non-idle A3S lifecycle or recognized coding-agent process requests one native per-user window at the physical screen's top center; the shared lock prevents multiple `a3s code` TUIs from rendering duplicate islands. On notched Macs, native safe-area geometry makes the surface meet the physical top edge while its compact content occupies the two unobstructed side wings. A dedicated handle moves the window; periodic centering stops after a successful drag, and expand/collapse preserves the moved surface's top-center. Live `All`, `Needs you`, `Running`, and `Recent` filters preserve parent context and show direct-child progress. Every row shows state and elapsed time with an original vendor-colored robot; terminal durations freeze. Exact approval rows display a bounded reason, expose larger `Allow` / `Always` / `Deny` controls, and offer a direct reply composer; live parent rows can also accept replies or expose `Stop`, while running children may expose `Cancel`. Recognized Codex and other process-only rows are labeled `detected / process`, count as running evidence, trigger and keep the island visible, and never receive controls. Any exact planning/working row or recognized process enables the diffuse multicolor neon breathing border. The standalone Tao/Wry helper embeds offline HTML/CSS/JavaScript and does not use the GUI crate, React, or Next.js. Standard Wayland compositors may constrain exact global placement. |
| Tool calls | Live tool status appears inline while running. Inline `program` calls summarize structured intent, research scope, workflow phase, and completed nested-call results instead of repeating JavaScript wrapper source. |
| Semantic transcript | `Ctrl+T` opens the complete live session transcript in a dedicated full-width viewport, preserving user-surface, tool-state, and diff colors while showing reasoning, plans, every tool lifecycle and full output, subagent state, and the current live Markdown tail. |
| Workspace editor | `/ide` opens a full-screen file browser/editor. `/config` reuses the editor for the active ACL config. Both surfaces use terminal-safe, type-aware file and folder sigils, semantic icon colors, aligned disclosure rows, icon-bearing breadcrumbs, and a ruled line-number gutter while keeping edits inside the workspace backend and normal permission path. |
| Workspace editor | `/ide` opens a full-screen file browser/editor. Press `p` on a workspace-tree item to open Live Preview, or use `:preview` in the editor to save a dirty buffer and preview it. `/config` reuses the editor for the active ACL config. These surfaces keep edits and preview targets inside the workspace backend and normal permission path. |
| Memory and knowledge | `/memory` opens the durable memory graph. `/ctx` searches past sessions and can attach or save hits. `/kb` opens the local personal knowledge vault. `/okf` manages shareable knowledge packages. |
| Asset panels | `/agent`, `/mcp`, `/skill`, and `/okf` keep an active local asset visible while you iterate. `/flow` selects or drafts workflow DAG assets for OS Workflow as a Service rather than entering a persistent local dev mode. |
| Operations panels | `/model`, `/effort`, `/history`, `/tasks`, `/permissions`, `/loop`, `/plugin`, `/theme`, `/help`, `/terminal`, and asset `activity` commands open focused panels or diagnostics without losing the current conversation. |
Expand All @@ -1143,7 +1167,6 @@ Key interactions:
| `Up` / `Down` | Recall input history or move through menus/panels. |
| `PgUp` / `PgDn` | Scroll the transcript or the active full-screen panel. |
| `Shift+End` | Jump to the latest transcript output. |
| `Ctrl+R` | Fuzzy-search prompts from the current session without replacing the current draft until a result is accepted. Press it again to cycle matches. |
| `Ctrl+T` | Open the complete live semantic session transcript, including full tool output and the current streaming tail. |
| `Ctrl+R` | Fuzzy-search current-session prompts; repeated Ctrl+R cycles matches. |
| `Ctrl+B` | Open or close delegated-task control without interrupting the parent turn. |
Expand Down Expand Up @@ -1650,6 +1673,7 @@ These commands are available outside the asset-specific flows:
| `/theme` | Cycle syntax highlighting themes. |
| `/login` / `/logout` | Sign in or out of the configured OS account; login registers OS capabilities and the `runtime` tool. |
| `/ide` | Open the workspace file browser and editor. |
| `/preview <path\|localhost-url>` | Open the target in Work's persistent Live Preview. `/preview status` reports the tracked window and `/preview stop` closes only the owned native window, leaving the shared Web service running. |
| `/memory` | Browse durable memory as an event/entity graph with tiers, aliases, relations, conflicts, and forget candidates. |
| `/evolution` | Review LLM-authored reusable preferences, Skills, and OKF candidates; inspect evidence, activation state, audit history, and immutable versions; save, reject, reconsider, restore a version, or return to the unmaterialized baseline. Mature conflict-free candidates may save locally automatically, but are never published. |
| `/ctx <query>` | Search past ctx-indexed sessions. |
Expand Down
2 changes: 2 additions & 0 deletions src/api/code_web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod module;
mod os;
mod permissions;
mod plugins;
mod previews;
mod processes;
mod remote;
mod session_runtime;
Expand All @@ -24,5 +25,6 @@ mod workspace_backend_cache;

pub(super) use kernel::KernelService;
pub(super) use module::CodeWebModule;
pub(in crate::api) use previews::content_router as preview_content_router;
pub(super) use session_store::CodeWebSessionRepository;
pub(super) use state::CodeWebState;
2 changes: 2 additions & 0 deletions src/api/code_web/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::knowledge::KnowledgeModule;
use super::loops::LoopsModule;
use super::os::OsModule;
use super::plugins::PluginsModule;
use super::previews::PreviewsModule;
use super::processes::ProcessesModule;
use super::state::CodeWebState;
use super::weixin::WeixinModule;
Expand Down Expand Up @@ -48,6 +49,7 @@ impl Module for CodeWebModule {
Arc::new(EvolutionModule),
Arc::new(KernelModule),
Arc::new(ProcessesModule),
Arc::new(PreviewsModule),
Arc::new(LoopsModule),
Arc::new(PluginsModule),
Arc::new(OsModule),
Expand Down
37 changes: 37 additions & 0 deletions src/api/code_web/previews/controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::sync::Arc;

use a3s_boot::{controller, Result as BootResult};

use super::model::{CreatePreviewRequest, PreviewDescriptor};
use super::service::PreviewsService;

pub(super) struct PreviewsController {
service: Arc<PreviewsService>,
}

impl PreviewsController {
pub(super) fn new(service: Arc<PreviewsService>) -> Self {
Self { service }
}
}

#[controller("/")]
impl PreviewsController {
#[post("/v1/previews")]
async fn create_preview(
&self,
#[body] request: CreatePreviewRequest,
) -> BootResult<PreviewDescriptor> {
self.service.create(request).await
}

#[get("/v1/previews/{id}")]
async fn preview(&self, #[param("id")] id: String) -> BootResult<PreviewDescriptor> {
self.service.get(&id).await
}

#[delete("/v1/previews/{id}")]
async fn stop_preview(&self, #[param("id")] id: String) -> BootResult<serde_json::Value> {
self.service.remove(&id).await
}
}
Loading
Loading