diff --git a/README.md b/README.md index 0f251ac..c8a3a0f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE) -Ask your agent to explain a system architecture, review a diff, or compare requirements against a plan. Instead of ASCII art and box-drawing tables, it generates a self-contained HTML page and opens it in your browser. +Ask your agent to explain a system architecture, review a diff, or compare requirements against a plan. Instead of ASCII art and box-drawing tables, it generates a self-contained HTML page and opens it with Pi's Glimpse native UI when available, falling back to your browser. ``` > draw a diagram of our authentication flow @@ -168,13 +168,13 @@ plugins/ └── share.sh ← deploy HTML to Vercel for sharing ``` -**Output:** `~/.agent/diagrams/filename.html` → opens in browser +**Output:** `~/.agent/diagrams/filename.html` → opens with Glimpse when available, browser fallback The skill routes to the right approach automatically: Mermaid for flowcharts and diagrams, CSS Grid for architecture overviews, HTML tables for data, Chart.js for dashboards. ## Limitations -- Generated HTML is portable and self-contained, but auto-opening depends on the harness, browser access, and sandbox rules. +- Generated HTML is portable and self-contained. In Pi, `scripts/open.sh` uses Glimpse when available and falls back to the system browser; other harnesses still depend on browser access and sandbox rules. - All harnesses write visual output to `~/.agent/diagrams/` unless the user asks for a different path. - Switching OS theme requires a page refresh for Mermaid SVGs. - `/share-page` uses `plugins/visual-explainer/scripts/share.sh`, which expects a Pi-compatible `vercel-deploy` skill in a standard Pi skill location. Other harnesses can still generate and open pages, but sharing may need that dependency installed separately. diff --git a/configs/pi/AGENTS.md b/configs/pi/AGENTS.md index 5fcb60c..dfeb681 100644 --- a/configs/pi/AGENTS.md +++ b/configs/pi/AGENTS.md @@ -4,6 +4,6 @@ For Pi, prefer `pi install git:github.com/nicobailon/visual-explainer` or instal Do not keep the old manual installer copies alongside a package install. If you previously used `install-pi.sh`, remove `~/.pi/agent/skills/visual-explainer` and the copied `~/.pi/agent/prompts/{diff-review,fact-check,generate-slides,generate-visual-plan,generate-web-diagram,plan-review,project-recap,share-page}.md` files before relying on the package. -Activate with `$visual-explainer` or slash commands such as `/diff-review`, `/plan-review`, `/generate-web-diagram`, `/generate-slides`, and `/share-page` after restarting Pi. Generated pages go to `~/.agent/diagrams/` and should be opened in a browser when possible. +Activate with `$visual-explainer` or slash commands such as `/diff-review`, `/plan-review`, `/generate-web-diagram`, `/generate-slides`, and `/share-page` after restarting Pi. Generated pages go to `~/.agent/diagrams/` and should be opened with `scripts/open.sh`, which uses Pi's Glimpse native UI when available and falls back to the system browser. Command templates are convenience prompts; the skill itself is the source of behavior. `/share-page` requires a Pi-compatible `vercel-deploy` skill, normally installed with `pi install npm:vercel-deploy`. diff --git a/plugins/visual-explainer/SKILL.md b/plugins/visual-explainer/SKILL.md index e4a2a3b..ebc795e 100644 --- a/plugins/visual-explainer/SKILL.md +++ b/plugins/visual-explainer/SKILL.md @@ -2,7 +2,7 @@ name: visual-explainer description: Generate beautiful, self-contained HTML pages that visually explain systems, code changes, plans, and data. Use when the user asks for a diagram, architecture overview, diff review, plan review, project recap, comparison table, or any visual explanation of technical concepts. Also use proactively when you are about to render a complex ASCII table (4+ rows or 3+ columns) — present it as a styled HTML page instead. license: MIT -compatibility: Requires a browser to view generated HTML files. Optional surf-cli for AI image generation. +compatibility: Uses Pi's Glimpse native UI when available; falls back to opening generated HTML files in the browser. Optional surf-cli for AI image generation. metadata: author: nicobailon version: "0.6.3" @@ -10,7 +10,7 @@ metadata: # Visual Explainer -Generate self-contained HTML files for technical diagrams, visualizations, and data tables. Always open the result in the browser. Never fall back to ASCII art when this skill is loaded. +Generate self-contained HTML files for technical diagrams, visualizations, and data tables. Always open the result with the provided opener: it uses Pi's Glimpse native UI when available and falls back to the system browser. Never fall back to ASCII art when this skill is loaded. **Proactive table rendering.** When you're about to present tabular data as an ASCII box-drawing table in the terminal (comparisons, audits, feature matrices, status reports, any structured rows/columns), generate an HTML page instead. The threshold: if the table has 4+ rows or 3+ columns, it belongs in the browser. Don't wait for the user to ask — render it as HTML automatically and tell them the file path. You can still include a brief text summary in the chat, but the table itself should be the HTML page. @@ -193,9 +193,12 @@ Keep animations purposeful: entrance reveals, hover feedback, and user-initiated **Output location:** Write to `~/.agent/diagrams/`. Use a descriptive filename based on content: `modem-architecture.html`, `pipeline-flow.html`, `schema-overview.html`. The directory persists across sessions. -**Open in browser:** -- macOS: `open ~/.agent/diagrams/filename.html` -- Linux: `xdg-open ~/.agent/diagrams/filename.html` +**Open with Glimpse when available, browser otherwise:** +```bash +./plugins/visual-explainer/scripts/open.sh ~/.agent/diagrams/filename.html +``` + +If the skill is installed elsewhere, run `scripts/open.sh` from that installed skill directory. The opener detects Pi's Glimpse native UI from common Pi/package locations and uses it when present. If Glimpse is not available or fails to start, it falls back to the system browser (`open`, `xdg-open`, or `start`). **Tell the user** the file path so they can re-open or share it. diff --git a/plugins/visual-explainer/commands/diff-review.md b/plugins/visual-explainer/commands/diff-review.md index bfe9377..a674dbd 100644 --- a/plugins/visual-explainer/commands/diff-review.md +++ b/plugins/visual-explainer/commands/diff-review.md @@ -61,7 +61,7 @@ Verify each claim against the code. If something cannot be verified, mark it as **Optional illustrations** — if `surf` CLI is available (`which surf`), consider generating a hero banner or conceptual illustration via `surf gemini --generate-image` when it would enhance the page. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip if surf isn't available or the diff is purely structural. -Include responsive section navigation. Use diff-style visual language throughout: red for removed/before, green for added/after, yellow for modified, blue for neutral context. Write to `~/.agent/diagrams/` and open in browser. +Include responsive section navigation. Use diff-style visual language throughout: red for removed/before, green for added/after, yellow for modified, blue for neutral context. Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. Ultrathink. diff --git a/plugins/visual-explainer/commands/fact-check.md b/plugins/visual-explainer/commands/fact-check.md index b4ff7f6..8c50084 100644 --- a/plugins/visual-explainer/commands/fact-check.md +++ b/plugins/visual-explainer/commands/fact-check.md @@ -52,7 +52,7 @@ Include in the summary: - Corrections made (with brief list of what was fixed: "Changed `processCleanup` to `runCleanup` to match actual function name in `worker.ts:45`") - Unverifiable claims flagged (if any) -**Phase 5: Report.** Tell the user what was checked, what was corrected, and open the file (HTML in browser, markdown path in chat). If nothing needed correction, say so — the verification still has value as confirmation. +**Phase 5: Report.** Tell the user what was checked, what was corrected, and open the file (HTML via `scripts/open.sh` with Glimpse/browser fallback, markdown path in chat). If nothing needed correction, say so — the verification still has value as confirmation. This is not a re-review. It does not second-guess analysis, opinions, or design judgments. It does not change the document's structure or organization. It is a fact-checker — it verifies that the data presented matches reality, corrects what doesn't, and leaves everything else alone. diff --git a/plugins/visual-explainer/commands/generate-slides.md b/plugins/visual-explainer/commands/generate-slides.md index 0109be1..7bfee8d 100644 --- a/plugins/visual-explainer/commands/generate-slides.md +++ b/plugins/visual-explainer/commands/generate-slides.md @@ -15,4 +15,4 @@ Follow the visual-explainer skill workflow. Read the reference template at `./te **Compositional variety:** Consecutive slides must vary their spatial approach. Alternate between centered, left-heavy, right-heavy, split, edge-aligned, and full-bleed. Three centered slides in a row means push one off-axis. -Write to `~/.agent/diagrams/` and open the result in the browser. +Write to `~/.agent/diagrams/` and open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. diff --git a/plugins/visual-explainer/commands/generate-visual-plan.md b/plugins/visual-explainer/commands/generate-visual-plan.md index 8ba7460..c13c3e3 100644 --- a/plugins/visual-explainer/commands/generate-visual-plan.md +++ b/plugins/visual-explainer/commands/generate-visual-plan.md @@ -102,6 +102,6 @@ Verify each against the code. If something cannot be verified, mark it as uncert - Never use `display: flex` on `
  • ` for markers — use absolute positioning - Test tables with wide content don't overflow their container -Write to `~/.agent/diagrams/` with a descriptive filename (e.g., `feature-name-plan.html`). Open the result in the browser. Tell the user the file path. +Write to `~/.agent/diagrams/` with a descriptive filename (e.g., `feature-name-plan.html`). Open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. Tell the user the file path. Ultrathink. diff --git a/plugins/visual-explainer/commands/generate-web-diagram.md b/plugins/visual-explainer/commands/generate-web-diagram.md index 64e5e1d..aeb7fef 100644 --- a/plugins/visual-explainer/commands/generate-web-diagram.md +++ b/plugins/visual-explainer/commands/generate-web-diagram.md @@ -1,5 +1,5 @@ --- -description: Generate a beautiful standalone HTML diagram and open it in the browser +description: Generate a beautiful standalone HTML diagram and open it with Glimpse when available, browser fallback --- Load the visual-explainer skill, then generate an HTML diagram for: $@ @@ -7,4 +7,4 @@ Follow the visual-explainer skill workflow. Read the reference template and CSS If `surf` CLI is available (`which surf`), consider generating an AI illustration via `surf gemini --generate-image` when an image would genuinely enhance the page — a hero banner, conceptual illustration, or educational diagram that Mermaid can't express. Match the image style to the page's palette. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip images when the topic is purely structural or data-driven. -Write to `~/.agent/diagrams/` and open the result in the browser. +Write to `~/.agent/diagrams/` and open the result with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. diff --git a/plugins/visual-explainer/commands/plan-review.md b/plugins/visual-explainer/commands/plan-review.md index 238959d..494ef71 100644 --- a/plugins/visual-explainer/commands/plan-review.md +++ b/plugins/visual-explainer/commands/plan-review.md @@ -79,7 +79,7 @@ Verify each claim against the code and the plan. If something cannot be verified **Optional illustrations** — if `surf` CLI is available (`which surf`), consider generating a conceptual illustration of the planned system via `surf gemini --generate-image` when it would help the reader visualize the change. Embed as base64 data URI. See css-patterns.md "Generated Images" for container styles. Skip if surf isn't available or the plan is purely structural. -Include responsive section navigation. Use a current-vs-planned visual language throughout: blue/neutral for current state, green/purple for planned additions, amber for areas of concern, red for gaps or risks. Write to `~/.agent/diagrams/` and open in browser. +Include responsive section navigation. Use a current-vs-planned visual language throughout: blue/neutral for current state, green/purple for planned additions, amber for areas of concern, red for gaps or risks. Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. Ultrathink. diff --git a/plugins/visual-explainer/commands/project-recap.md b/plugins/visual-explainer/commands/project-recap.md index e57bf3f..6a610bb 100644 --- a/plugins/visual-explainer/commands/project-recap.md +++ b/plugins/visual-explainer/commands/project-recap.md @@ -54,7 +54,7 @@ Verify each claim against the code. If something cannot be verified, mark it as - Flag each with a severity and a concrete suggestion (e.g., "add a doc comment to `buildCoordinationInstructions` explaining the 4 coordination levels — this function is called from 3 places and the behavior is non-obvious") 8. **Next steps** — inferred from recent activity, open TODOs, project trajectory. Not prescriptive — just "here's where the momentum was pointing when you left." Include any explicit next-step notes from progress docs or plan files. -Include responsive section navigation. Use a warm, approachable visual language: muted blues and greens for architecture, amber callouts for cognitive debt hotspots, green/blue/amber/red for state-of-things status. Overflow prevention on any side-by-side or grid-based sections: apply `min-width: 0` on all grid/flex children and `overflow-wrap: break-word`. Never use `display: flex` on `
  • ` for marker characters — use absolute positioning instead (see css-patterns.md Overflow Protection). Write to `~/.agent/diagrams/` and open in browser. +Include responsive section navigation. Use a warm, approachable visual language: muted blues and greens for architecture, amber callouts for cognitive debt hotspots, green/blue/amber/red for state-of-things status. Overflow prevention on any side-by-side or grid-based sections: apply `min-width: 0` on all grid/flex children and `overflow-wrap: break-word`. Never use `display: flex` on `
  • ` for marker characters — use absolute positioning instead (see css-patterns.md Overflow Protection). Write to `~/.agent/diagrams/` and open with `scripts/open.sh` so it uses Pi's Glimpse when available and browser fallback otherwise. Ultrathink. diff --git a/plugins/visual-explainer/scripts/open-with-glimpse.mjs b/plugins/visual-explainer/scripts/open-with-glimpse.mjs new file mode 100755 index 0000000..67bb0b3 --- /dev/null +++ b/plugins/visual-explainer/scripts/open-with-glimpse.mjs @@ -0,0 +1,86 @@ +#!/usr/bin/env node +import { access, readFile } from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import { spawn } from 'node:child_process'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { createRequire } from 'node:module'; + +const require = createRequire(import.meta.url); +const here = dirname(fileURLToPath(import.meta.url)); + +function expandHome(path) { + if (!path) return path; + return path.startsWith('~/') ? `${process.env.HOME}${path.slice(1)}` : path; +} + +function browserOpen(file) { + const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open'; + const args = process.platform === 'win32' ? ['/c', 'start', '', file] : [file]; + const child = spawn(command, args, { detached: true, stdio: 'ignore' }); + child.unref(); +} + +async function firstExisting(paths) { + for (const candidate of paths) { + if (!candidate) continue; + const resolved = expandHome(candidate); + try { + await access(resolved); + return resolved; + } catch {} + } + return null; +} + +async function resolveGlimpseModule() { + try { + return require.resolve('glimpseui/src/glimpse.mjs'); + } catch {} + + const envPath = process.env.GLIMPSE_MODULE || process.env.GLIMPSE_PATH; + const packageRoot = resolve(here, '../../../..'); + return firstExisting([ + envPath, + resolve(packageRoot, 'node_modules/glimpseui/src/glimpse.mjs'), + '~/.pi/agent/git/github.com/hazat/glimpse/src/glimpse.mjs', + '~/.bun/install/global/node_modules/glimpseui/src/glimpse.mjs', + '~/.bun/install/cache/glimpseui@0.8.0@@@1/src/glimpse.mjs', + ]); +} + +const args = process.argv.slice(2); +if (args.includes('--check')) { + process.exit((await resolveGlimpseModule()) ? 0 : 1); +} + +const fileArg = args.find((arg) => !arg.startsWith('--')); +if (!fileArg) { + console.error('Usage: open-with-glimpse.mjs [--check] '); + process.exit(2); +} + +const htmlFile = resolve(expandHome(fileArg)); +const title = args.includes('--title') ? args[args.indexOf('--title') + 1] : `Visual Explainer — ${htmlFile.split('/').pop()}`; +const glimpseModule = await resolveGlimpseModule(); + +if (!glimpseModule) { + browserOpen(htmlFile); + process.exit(0); +} + +try { + const { open } = await import(pathToFileURL(glimpseModule).href); + const html = await readFile(htmlFile, 'utf8'); + const win = open(html, { + title, + width: 1200, + height: 850, + openLinks: true, + }); + win.on('closed', () => process.exit(0)); +} catch (error) { + console.error(`Glimpse failed, opening in browser instead: ${error.message}`); + browserOpen(htmlFile); + process.exit(0); +} diff --git a/plugins/visual-explainer/scripts/open.sh b/plugins/visual-explainer/scripts/open.sh new file mode 100755 index 0000000..a84483c --- /dev/null +++ b/plugins/visual-explainer/scripts/open.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 " >&2 + exit 2 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HTML_FILE="$1" + +if node "$SCRIPT_DIR/open-with-glimpse.mjs" --check >/dev/null 2>&1; then + node "$SCRIPT_DIR/open-with-glimpse.mjs" "$HTML_FILE" >/tmp/visual-explainer-glimpse.log 2>&1 & + disown || true +else + case "$(uname -s)" in + Darwin) open "$HTML_FILE" ;; + Linux) xdg-open "$HTML_FILE" ;; + MINGW*|MSYS*|CYGWIN*) start "" "$HTML_FILE" ;; + *) echo "No opener known for this OS. File: $HTML_FILE" >&2 ;; + esac +fi