Add explore skill: interactive pseudocode browser
Serves a localhost page in the pseudo-skill register with the reference markers as clickable buttons: clicks land in <workdir>/events.jsonl, a persistent Monitor tail wakes the session, the session rewrites page.html, and the browser live-reloads over SSE. Actions per marker: expand / show real code / explain / ask, plus a page-level ask box; anchors become forge deep-links when the project has a reachable remote; incidental findings are surfaced on the page as anchored notes. The port is configured in one place (the PORT constant atop scripts/server.py; --port overrides per run). Mechanics proven live against the aura repo before extraction into this skill.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: explore
|
||||
description: Use when the user wants to explore a project interactively in the browser — invoked as `/explore <project>` or when the user asks for a clickable/served pseudocode page. Serves a localhost page showing the project as commented pseudocode in the pseudo-skill register, with the reference markers rendered as clickable buttons; every click (expand / show real code / explain / ask, plus a free-text box) lands as an event that wakes the session through a Monitor back-channel, the session rewrites the page, and the browser live-reloads via SSE. Anchors become forge deep-links when the project has a web-reachable remote; incidental findings (doc/code drift, stale comments) are surfaced on the page itself as anchored finding notes.
|
||||
---
|
||||
|
||||
# explore — interactive pseudocode browser
|
||||
|
||||
## Overview
|
||||
|
||||
`/explore <project>` turns the `pseudo` skill's register into a served,
|
||||
clickable page. The user reads pseudocode in the browser and zooms by
|
||||
clicking instead of typing: each marker is a button, each click wakes
|
||||
the session, the session rewrites the page, SSE reloads the browser.
|
||||
|
||||
The loop:
|
||||
|
||||
```
|
||||
browser click ──POST /event──▶ server.py ──append──▶ <workdir>/events.jsonl
|
||||
│
|
||||
Monitor "tail -F -n 0 events.jsonl"
|
||||
│
|
||||
this session
|
||||
│
|
||||
browser ◀──SSE "reload"── server.py ◀──mtime── rewrites <workdir>/page.html
|
||||
```
|
||||
|
||||
Latency expectations are conversational, not app-like: every click costs
|
||||
one thinking cycle. Tell the user this once at start.
|
||||
|
||||
## Moving parts
|
||||
|
||||
- `scripts/server.py` — stdlib localhost server. **The port is
|
||||
configured in exactly one place: the `PORT` constant at the top of
|
||||
this file.** A per-run override exists (`--port N`) for a second
|
||||
concurrent instance; the constant is the default every instance
|
||||
shares.
|
||||
- `templates/page.html` — the page scaffold (CSS, click menu, ask box,
|
||||
SSE client). Placeholders: `{{TITLE}}` (project name, appears in
|
||||
tab and header), `{{HINT}}` (one line: what the project is + current
|
||||
altitude), `{{CONTENT}}` (the pseudocode block, see content rules).
|
||||
- Workdir `~/.cache/explore/<project-slug>/` — holds the generated
|
||||
`page.html` and `events.jsonl`. Scratch, never committed, safe to
|
||||
delete after the session.
|
||||
|
||||
## Start procedure
|
||||
|
||||
1. `mkdir -p ~/.cache/explore/<project-slug>`
|
||||
2. Generate `<workdir>/page.html` from `templates/page.html`, filling
|
||||
the three placeholders. `{{CONTENT}}` starts at the project's main
|
||||
entry point (pseudo rule 9) unless the user pointed elsewhere.
|
||||
3. Start the server in the background:
|
||||
`python3 <skill-dir>/scripts/server.py <workdir>` (add `--port N`
|
||||
only for a second concurrent instance).
|
||||
4. Arm the back-channel as a persistent Monitor:
|
||||
`tail -F -n 0 <workdir>/events.jsonl` (`-n 0` is load-bearing:
|
||||
without it, stale events replay at arm time).
|
||||
5. Give the user the URL the server printed.
|
||||
|
||||
## Content rules
|
||||
|
||||
The `pseudo` skill's Iron Law governs everything inside `{{CONTENT}}`:
|
||||
anchor line first, one altitude per view, markers as pointing handles
|
||||
explained inline (never a legend), data shapes beside control flow,
|
||||
reduce/omit the rest. Read that skill's rules before generating the
|
||||
first page. On top of it, the served medium adds:
|
||||
|
||||
- **Escape first, tag second.** `{{CONTENT}}` and every `.note` body
|
||||
are substituted into HTML: escape `&`, `<`, `>` in all source and
|
||||
pseudocode text before insertion (Rust is full of `Vec<T>`, `&mut`,
|
||||
`a < b`), and only then wrap tokens in highlight spans. A stray `<`
|
||||
swallows the rest of the page, including the SSE script.
|
||||
- **Markers are buttons.** `[N]` renders as
|
||||
`<button class="marker" data-marker="N">[N]</button>`. Expansions
|
||||
introduce sub-markers (`4a`, `4b`) — the zoom is recursive.
|
||||
- **Anchors are links.** When the project has a web-reachable forge
|
||||
remote (Gitea/GitHub), every file anchor becomes an
|
||||
`<a class="src" href="…#L10-L20" target="_blank" rel="noopener">`
|
||||
deep-link. Verify the URL pattern once per project (curl the file
|
||||
URL, expect 200) before emitting the first link; skip links when
|
||||
there is no reachable remote.
|
||||
- **Real code** (`code` action): a `.note.code` block at the marker —
|
||||
caption line = linked `file:from–to` anchor, then the code verbatim
|
||||
with light span highlighting (`.c` comments, `.k` keywords, `.s`
|
||||
strings).
|
||||
- **Explanations** (`explain` action): a `.note` block anchored at the
|
||||
marker. Page-level `ask` answers go in a `<section id="qa">` between
|
||||
the pseudocode and the menu div (question dimmed in `.q`, answer in
|
||||
`.note`).
|
||||
- **Findings.** Anything noticed in passing — doc/code drift, a stale
|
||||
comment, a suspicious contract — is surfaced on the page itself: an
|
||||
amber `.note.finding` (⚠) anchored at the spot with deep-links to
|
||||
the evidence, and a wavy `.warn` span (with `title` tooltip) on the
|
||||
stale phrase where it is displayed. A one-line chat mention suffices
|
||||
beside it; filing a tracker issue stays a separate ask.
|
||||
- **Language.** Scaffold and pseudocode are English (repo register).
|
||||
Answers to `ask` events are written in the user's language.
|
||||
|
||||
## Handling events
|
||||
|
||||
Each Monitor line is one click: `{marker, action, text?, ts}`
|
||||
(`marker: null` = page-level; `text` only on `ask`). Respond by
|
||||
rewriting `<workdir>/page.html` — the SSE watcher reloads the browser
|
||||
automatically, so the rewrite IS the reply. Every rewrite MUST
|
||||
preserve the full template scaffold: the SSE `<script>` (EventSource +
|
||||
reload listener), the `#menu` div, and the `#ask` form — after each
|
||||
reload that script is what re-binds every marker button. Edit only the
|
||||
pseudocode, the anchored notes, and the `#qa` section; dropping the
|
||||
scaffold silently kills the loop. Read the real source
|
||||
before expanding or explaining; keep each response at the altitude the
|
||||
click asked for. Batch related edits into as few writes as possible
|
||||
(each write triggers a visible reload).
|
||||
|
||||
## Stop
|
||||
|
||||
`TaskStop` the server task and the Monitor. The workdir is scratch and
|
||||
may be deleted. To switch projects: stop the server, start it again on
|
||||
the new project's workdir, and re-arm the Monitor on the NEW workdir's
|
||||
`events.jsonl` — server and monitor are both bound to one workdir at
|
||||
startup, so neither survives a workdir switch.
|
||||
Reference in New Issue
Block a user