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
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
pull_request:
push:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Enable Corepack
run: corepack enable

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
*.log
node_modules/
.omx/
103 changes: 65 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,100 +44,127 @@ Instead it:

| Command | Result |
|---|---|
| `/html-last` | Opens a render-mode chooser |
| `/html-last` | Opens quick local HTML without starting a Pi model turn |
| `/html-last choose` | Opens a render-mode chooser |
| `/html-last local` | Forces quick local HTML |
| `/html-last pi` | Forces designed HTML via the current Pi model |
| `/html-last gemini` | Forces designed HTML via Gemini CLI |
| `/html-last-version` | Shows the loaded extension version |

## Installation
## Quick start

### Oh My Pi / OMP
Native Pi npm install:

OMP auto-discovers native extensions from `~/.omp/agent/extensions`.
```bash
pi install npm:pi-html-long-answer-extension
```

Native Pi git install:

```bash
pi install git:https://github.com/zakelfassi/pi-html-long-answer-extension.git
```

Global install:
Oh My Pi / OMP global install:

```bash
mkdir -p ~/.omp/agent/extensions
git clone https://github.com/zakelfassi/pi-html-long-answer-extension.git \
~/.omp/agent/extensions/html-long-answer
```

One-off test without installing globally:
Then ask for a long answer and run:

```bash
omp -e /absolute/path/to/index.js
```text
/html-last-version
/html-last local
```

### Legacy Pi
## Installation and compatibility matrix

Pi supports extension installation from git and also supports direct extension loading.
This package is published to npm for Pi package discovery and remains installable directly from git for pinned or source-reviewed installs.

Install from git:
| Harness / platform | Install or load path | Verify after install | Expected result | Status |
|---|---|---|---|---|
| Native Pi npm package | `pi install npm:pi-html-long-answer-extension` | Run `/html-last-version`, then `/html-last local` after a long answer | Version notification, then a browser-opened local HTML export | Supported package path; appears in npm-backed Pi package discovery |
| Native / legacy Pi git | `pi install git:https://github.com/zakelfassi/pi-html-long-answer-extension.git` | Run `/html-last-version`, then `/html-last local` after a long answer | Version notification, then a browser-opened local HTML export | Supported source install path; verify on your installed Pi version |
| Manual Pi extension root | Clone to `~/.pi/agent/extensions/html-long-answer` | Restart/load Pi, then run `/html-last-version` and `/html-last local` | Extension auto-loads from the global root | Supported path; verify on your installed Pi version |
| Oh My Pi / OMP | Clone to `~/.omp/agent/extensions/html-long-answer` | Restart/load OMP, then run `/html-last-version` and `/html-last local` | Extension auto-loads from the OMP global root | Supported path; verify on your installed OMP version |
| OMP one-off test | `omp -e /absolute/path/to/index.js` | Run `/html-last-version` | Version notification appears | Supported one-off smoke path |
| Pi-compatible derived harnesses | Use the Pi npm/git/manual instructions if the harness honors Pi `package.json.pi.extensions` or Pi extension roots | Run `/html-last-version` and `/html-last local` | Same command behavior as Pi | Harness-specific commands are unverified |
| LazyPi | No LazyPi-specific command is documented here | Use the Pi-compatible row only if your LazyPi setup exposes Pi-compatible extension loading | Do not assume a LazyPi-only install command | Exact LazyPi third-party extension flow unverified |
| Gemini CLI | Optional external renderer used by `/html-last gemini` | Run `/html-last gemini` after a long answer | Designed HTML export, or a clean fallback to local HTML if Gemini is unavailable/invalid | Optional |

```bash
pi install git:https://github.com/zakelfassi/pi-html-long-answer-extension.git
```
## Verify after install

Or place it manually in the legacy global extension root:
| Command | Expected result |
|---|---|
| `/html-last-version` | Shows the loaded `html-long-answer` version |
| `/html-last` | Writes a local HTML artifact and opens it in the default browser without starting a Pi model turn |
| `/html-last choose` | Opens the render-mode chooser when UI selection is available |
| `/html-last local` | Writes a local HTML artifact and opens it in the default browser |
| `/html-last pi` | Queues a current-model designed HTML pass, then writes the result or falls back safely |
| `/html-last gemini` | Uses Gemini CLI when available; invalid/unsafe/non-HTML output falls back to local HTML |

For reproducible installs, pin an npm version or a git ref/tag once you choose a release:

```bash
mkdir -p ~/.pi/agent/extensions
git clone https://github.com/zakelfassi/pi-html-long-answer-extension.git \
~/.pi/agent/extensions/html-long-answer
pi install npm:pi-html-long-answer-extension@0.2.0
pi install git:https://github.com/zakelfassi/pi-html-long-answer-extension.git@v0.2.0
```

### Shipping support for both runtimes

This repo includes both extension manifest keys in `package.json`:
- `omp.extensions`
- `pi.extensions`

That keeps directory/package resolution compatible with both ecosystems.

## Runtime behavior

- Long answers are detected from message length / line / paragraph thresholds.
- Long answers are captured into session state so `/html-last` can work on prior assistant replies.
- Local and designed exports open automatically in the browser after the file is written.
- Raw URLs such as `https://example.com` are linkified in local exports.
- Gemini rich renders are validated for actual HTML; invalid output falls back to the local renderer.
- Rich Pi/Gemini renders must be standalone HTML documents with inline CSS only.
- Rich HTML is validated before writing: scripts, event-handler attributes, `javascript:` URLs, external assets, external CSS URLs, unsafe tags, oversized output, and overly complex output are rejected or routed to fallback behavior.
- Invalid, unsafe, or non-HTML rich output falls back to the local renderer instead of writing a malformed nested document.

## Repo layout

```text
html-long-answer/
├── .github/
│ └── workflows/
│ └── ci.yml
├── assets/
│ ├── flow.svg
│ ├── hero.svg
│ └── render-modes.svg
├── test/
│ └── extension.test.js
├── index.js
├── package.json
├── pnpm-lock.yaml
├── README.md
└── .gitignore
```

## Development notes

The extension currently lives and runs as a single-file runtime module (`index.js`) so it is easy to install directly into an extension root.
The extension runtime still lives in a single file (`index.js`) so it is easy to install directly into a Pi or OMP extension root. Tests and CI live outside the runtime path.

Use PNPM:

```bash
pnpm install
pnpm test
```

If you modify it, re-test these flows:
- long answer -> lightweight notice only
- `/html-last` -> chooser appears
- `/html-last` -> local HTML writes and opens without starting a Pi model turn
- `/html-last choose` -> chooser appears
- `/html-last local` -> HTML writes and opens
- `/html-last pi` -> second-pass render path queues/runs
- `/html-last pi` -> second-pass render path queues/runs and validates rich HTML
- `/html-last gemini` -> Gemini render path succeeds or cleanly falls back
- `/html-last-version` -> version shown in-session

## Trust and security

Extensions run with your user permissions. Only install from sources you trust.

## Compatibility notes

This repo is designed to ship to:
- Oh My Pi / OMP users through `~/.omp/agent/extensions`
- legacy Pi users through `pi install ...` or `~/.pi/agent/extensions`
Extensions run with your user permissions. Only install from sources you trust, review the source before installing, and pin a git ref or tag when you need reproducible behavior.

The install paths and dual manifest strategy are based on the upstream Pi and OMP extension-loading models.
Rich HTML generated by Pi or Gemini is treated as untrusted until it passes this extension's validation. The validator is intentionally conservative: if rich output includes active scripts, event handlers, external assets, or unsafe URLs, the extension falls back to local HTML rather than writing the rich document.
Loading
Loading