diff --git a/.github/workflows/release-pi.yml b/.github/workflows/release-pi.yml new file mode 100644 index 0000000..d48f290 --- /dev/null +++ b/.github/workflows/release-pi.yml @@ -0,0 +1,73 @@ +name: Release pi package + +on: + push: + tags: + - 'pi-v*' + workflow_dispatch: + inputs: + publish: + description: Publish to npm (unchecked = dry run only) + type: boolean + required: false + default: false + +permissions: + contents: read + id-token: write + +concurrency: + group: release-pi + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Read package metadata + id: pkg + run: | + echo "name=$(node -p \"require('./pi/package.json').name\")" >> "$GITHUB_OUTPUT" + echo "version=$(node -p \"require('./pi/package.json').version\")" >> "$GITHUB_OUTPUT" + + - name: Validate release tag matches package version + if: github.event_name == 'push' + run: | + expected="pi-v${{ steps.pkg.outputs.version }}" + if [ "${GITHUB_REF_NAME}" != "$expected" ]; then + echo "::error title=Tag/version mismatch::Expected tag $expected for version ${{ steps.pkg.outputs.version }}, got ${GITHUB_REF_NAME}." + exit 1 + fi + + - name: Ensure npm version is not already published + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish) + run: | + if npm view "${{ steps.pkg.outputs.name }}@${{ steps.pkg.outputs.version }}" version >/dev/null 2>&1; then + echo "::error title=Version already published::${{ steps.pkg.outputs.name }}@${{ steps.pkg.outputs.version }} already exists on npm." + exit 1 + fi + + - name: Validate package contents + working-directory: pi + run: npm pack --dry-run + + - name: Publish to npm + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish) + working-directory: pi + run: npm publish --access public --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Dry-run summary + if: github.event_name == 'workflow_dispatch' && !inputs.publish + run: | + echo "Dry run complete for ${{ steps.pkg.outputs.name }}@${{ steps.pkg.outputs.version }}." + echo "Re-run this workflow with publish=true to publish." diff --git a/README.md b/README.md index 407ef22..459fc2f 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,16 @@ Paste a screenshot in your browser, your agent gets the URL instantly. ## Available plugins -| Agent | Directory | Status | -|---|---|---| -| [pi](https://github.com/mariozechner/pi) | [`pi/`](pi/) | ✅ | -| [OpenCode](https://github.com/anomalyco/opencode) | [`opencode/`](opencode/) | ✅ | +| Agent | Directory | npm package | Install | +|---|---|---|---| +| [pi](https://github.com/mariozechner/pi) | [`pi/`](pi/) | `@modem-dev/glance-pi` | `pi install npm:@modem-dev/glance-pi` | +| [OpenCode](https://github.com/anomalyco/opencode) | [`opencode/`](opencode/) | — | See [`opencode/README.md`](opencode/README.md) | ## How it works Each plugin creates a live session on glance.sh, gives you a URL to open, and waits for you to paste an image. The image URL is returned to the agent over SSE — no manual copy-paste needed. -``` +```text agent ──POST /api/session──▶ { id, url } agent ──GET /api/session//events──▶ SSE (waiting…) user ──opens /s/, pastes image──▶ agent receives URL @@ -27,14 +27,20 @@ user ──opens /s/, pastes image──▶ agent receives URL Sessions are anonymous and ephemeral (10-minute TTL). Images expire after 30 minutes. -## Adding a new plugin +## Packaging policy + +New plugins should be published as installable packages (npm where possible) with a one-command install path in their README. -Create a directory for your agent (e.g. `cursor/`, `cline/`) with: +Each plugin directory should include: -1. The integration code -2. A `README.md` with install instructions +1. Integration code +2. `README.md` with install / verify / update / remove steps +3. `package.json` (if the target agent supports package-based install) +4. Release automation (GitHub Actions workflow + documented version/tag convention) + +## Adding a new plugin -Open a PR. +Create a directory for your agent (e.g. `cursor/`, `cline/`) with the files above and open a PR. ## License diff --git a/pi/README.md b/pi/README.md index 888648d..da2d78d 100644 --- a/pi/README.md +++ b/pi/README.md @@ -13,21 +13,75 @@ Maintains a **persistent background session** on glance.sh. Paste an image anyti ## Install -Symlink or copy `glance.ts` into your pi extensions directory: +Recommended (npm package): ```bash -# symlink (recommended — stays up to date with git pulls) -ln -s "$(pwd)/glance.ts" ~/.pi/extensions/glance.ts +pi install npm:@modem-dev/glance-pi +``` + +If you are working from a local checkout instead: + +```bash +# from this directory (agent-plugins/pi) +pi install . -# or copy -cp glance.ts ~/.pi/extensions/glance.ts +# from the main repo root +pi install ./agent-plugins/pi ``` -Restart pi. The background session starts automatically. +Then restart pi or run `/reload`. -## How it works +## Verify + +Run: + +```text +/glance +``` + +You should see a session URL like `https://glance.sh/s/`. + +## Update / remove + +```bash +pi update +pi remove npm:@modem-dev/glance-pi +``` + +For a local path install, remove that path from your pi settings (or run `pi remove` with the same path you installed). +## Publishing (maintainers) + +Releases are automated via GitHub Actions. + +Prerequisite: configure `NPM_TOKEN` in the `glance-agent-plugins` repository with publish access to `@modem-dev/glance-pi`. + +1. Bump `version` in `pi/package.json`. +2. Commit and push to `main`. +3. Create and push a matching tag: + +```bash +git tag pi-v0.1.0 +git push origin pi-v0.1.0 +``` + +The `Release pi package` workflow validates the tag/version match and publishes with npm provenance. +You can also run the workflow manually in dry-run mode from Actions. + +## Manual install (legacy) + +If you prefer manual file management, symlink or copy `glance.ts` into your pi extensions directory: + +```bash +mkdir -p ~/.pi/agent/extensions +ln -s "$(pwd)/glance.ts" ~/.pi/agent/extensions/glance.ts +# or: +cp glance.ts ~/.pi/agent/extensions/glance.ts ``` + +## How it works + +```text pi starts └─▶ create session on glance.sh └─▶ connect SSE (background, auto-reconnect) diff --git a/pi/glance.ts b/pi/glance.ts index 3eec1d2..004db9b 100644 --- a/pi/glance.ts +++ b/pi/glance.ts @@ -10,8 +10,10 @@ * - `glance` tool — the LLM can call it to request a screenshot; * it surfaces the existing session URL and waits for a paste. * - * Install: symlink or copy this file into your pi extensions directory, - * e.g. ~/.pi/extensions/glance.ts + * Install: + * - Recommended: `pi install npm:@modem-dev/glance-pi` + * - Local checkout: `pi install /path/to/glance-agent-plugins/pi` + * - Manual fallback: symlink/copy into ~/.pi/agent/extensions/glance.ts */ import { Type } from "@mariozechner/pi-ai"; diff --git a/pi/package.json b/pi/package.json new file mode 100644 index 0000000..0bed5e7 --- /dev/null +++ b/pi/package.json @@ -0,0 +1,37 @@ +{ + "name": "@modem-dev/glance-pi", + "version": "0.1.0", + "description": "glance.sh extension package for pi", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/modem-dev/glance-agent-plugins.git", + "directory": "pi" + }, + "homepage": "https://github.com/modem-dev/glance-agent-plugins/tree/main/pi", + "bugs": { + "url": "https://github.com/modem-dev/glance-agent-plugins/issues" + }, + "keywords": [ + "pi-package", + "pi-extension", + "pi", + "glance", + "screenshot", + "agent" + ], + "files": [ + "glance.ts", + "README.md" + ], + "pi": { + "extensions": [ + "./glance.ts" + ] + }, + "peerDependencies": { + "@mariozechner/pi-ai": "*", + "@mariozechner/pi-coding-agent": "*", + "@mariozechner/pi-tui": "*" + } +}