Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Describe and preserve what is already true in the repo today.
- The empty state explains the product and exposes sample fragment presets.
- A built-in link creator can generate fragment-based links locally in the browser.
- When a valid fragment is present, the app switches to a viewer-first artifact layout.
- The artifact stage toolbar exposes copy-to-clipboard, file download, and (for markdown) browser print-to-PDF.
- The artifact stage toolbar exposes copy-to-clipboard, file download, (for markdown) browser print-to-PDF, and an editor that regenerates a new fragment link from the currently open artifact.
- `activeArtifactId` controls which artifact opens first.
- Internal diff file navigation stays in UI state and does not repurpose the fragment.

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to `agent-render` will be documented in this file.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses semantic versioning while it is published as tagged releases.

## [Unreleased]

### Added

- In-viewer edit-and-reshare: open any artifact, correct its content, and generate a new fragment link without leaving the viewer.

## [0.1.0] - 2026-05-05

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Built for the OpenClaw ecosystem, `agent-render` focuses on fragment-based shari
- Markdown, code, diff, CSV, and JSON all render in the static shell
- Fragment transport supports `plain`, `lz`, `deflate`, `arx`, `arx2`, `arx3`, and `arx4`, with automatic shortest-fragment selection across available wire formats
- The `arx` substitution dictionary is served at `/arx-dictionary.json` with a pre-compressed `/arx-dictionary.json.br` variant; the `arx2` tuple-envelope overlay is served at `/arx2-dictionary.json` with a pre-compressed `/arx2-dictionary.json.br` variant; `arx3` reuses those proven bytes and optimizes for compact visible Unicode fragments; `arx4` adds the curated context-mixer priors at `/arx4-priors.json` with a pre-compressed `/arx4-priors.json.br` variant
- The viewer toolbar copies artifact bodies to the clipboard, downloads them as files, and (for markdown) supports browser print-to-PDF
- The viewer toolbar copies artifact bodies to the clipboard, downloads them as files, (for markdown) supports browser print-to-PDF, and can edit the open artifact then reshare it as a new fragment link
- Deployment target: static hosting, including Cloudflare Pages

## Included Renderers
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The static export also emits `sitemap.xml` at the site root (and under `NEXT_PUB

The viewer shell now routes all five artifact kinds through dynamically imported client-only renderers so the landing shell stays light and static-host friendly.

When a valid fragment is present, the shell switches into a viewer-first layout with bundle navigation beside the active artifact. The active artifact header includes copy, download, and markdown print actions. The landing/samples experience is only the empty state.
When a valid fragment is present, the shell switches into a viewer-first layout with bundle navigation beside the active artifact. The active artifact header includes copy, download, markdown print, and edit-and-reshare actions. Edit regenerates a new fragment link from the current artifact (or the current artifact inside a bundle) without writing anything to a server. The landing/samples experience is only the empty state.

Diff file navigation is intentionally internal UI state now. The URL fragment remains reserved for payload transport and active-artifact selection instead of being reused as an in-page file anchor system.

Expand Down
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Playwright visual tests live in `tests/e2e/visual.spec.ts`.

The suite is intentionally split by responsibility:

- browser tests protect exported-app behavior, fragment-driven rendering, downloads, clipboard copy, print flow, themes, and layout hierarchy (including mobile toolbar and default code-wrap checks in `tests/e2e/viewer.spec.ts`)
- browser tests protect exported-app behavior, fragment-driven rendering, downloads, clipboard copy, print flow, in-viewer edit-and-reshare, themes, and layout hierarchy (including mobile toolbar and default code-wrap checks in `tests/e2e/viewer.spec.ts`)
- visual tests protect empty state, artifact views, theme presentation, and compact-content spacing
- component tests protect selector/disclosure UI contracts
- unit tests protect transport codecs, envelope validation, diff parsing, and language inference
Expand Down
2 changes: 1 addition & 1 deletion skills/selfhosted-agent-render/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Returns `200 { "status": "ok" }` when the server is up and the database is reach

## Viewer links

When a user visits `/{uuid}`, the server looks up the stored payload, injects it into the viewer page, and renders the same UI as the fragment-based product. All viewer features work: copy, download, print-to-PDF, diff modes, artifact switching, raw toggle.
When a user visits `/{uuid}`, the server looks up the stored payload, injects it into the viewer page, and renders the same UI as the fragment-based product. All viewer features work: copy, download, print-to-PDF, edit-and-reshare (which emits a new fragment link), diff modes, artifact switching, raw toggle.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 UUID resharing exceeds fragment budget

When a self-hosted UUID contains a payload whose encoded fragment exceeds 8,192 characters, the viewer accepts the injected payload but link generation rejects it, causing the documented edit-and-reshare feature to fail for supported large UUID artifacts.

Context Used: AGENTS.md (source)

Fix in Codex


Construct viewer links as:

Expand Down
12 changes: 12 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,18 @@ select {
padding: 0.95rem;
}

.artifact-editor {
display: grid;
gap: 1.15rem;
padding: 1.5rem;
}

@media (min-width: 768px) {
.artifact-editor {
padding: 2rem 2.5rem;
}
}

.viewer-toolbar {
display: flex;
flex-wrap: wrap;
Expand Down
8 changes: 6 additions & 2 deletions src/components/viewer-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,16 @@ export function ViewerShell() {
useEffect(() => {
rendererReadyKeyRef.current = rendererReadyKey;

if (!activeArtifact) {
if (!rendererReadyKey) {
setRendererReady(true);
return;
}

// Reset only when the hash/artifact-id key changes. A later decode that only
// replaces artifact contents (same id, new fragment) must not clear a ready
// signal the remounted renderer already reported for that key.
setRendererReady(false);
}, [activeArtifact, rendererReadyKey]);
}, [rendererReadyKey]);

const markRendererReady = useCallback((readyKey: string) => {
if (rendererReadyKeyRef.current === readyKey) {
Expand Down Expand Up @@ -415,6 +418,7 @@ export function ViewerShell() {
fragmentLength={fragmentLength}
hash={hash}
onArtifactSelect={handleArtifactSelect}
onPreviewHash={setFragmentHash}
onRendererReady={markRendererReady}
rendererReadyKey={rendererReadyKey}
statusTone={statusTone}
Expand Down
Loading
Loading