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
84 changes: 84 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,90 @@ jobs:
gh release upload "v${VERSION}" SHA256SUMS.txt \
--repo dcouple/Pane --clobber

validate-runpane-packages:
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: '22.15.1'
cache: 'pnpm'
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pnpm install --filter runpane --ignore-scripts
- run: pnpm run check:runpane-package-versions
- run: pnpm --filter runpane build
- run: pnpm run test:runpane-contract
- run: pnpm run test:runpane-package-smoke

publish-npm:
if: github.ref_type == 'tag'
needs: [checksums, validate-runpane-packages]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: '22.15.1'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- name: Ensure npm supports trusted publishing
run: npm install -g npm@^11.5.1
- run: pnpm install
- run: pnpm --filter runpane build
- name: Publish runpane to npm with token fallback
if: ${{ env.NPM_TOKEN != '' }}
working-directory: packages/runpane
env:
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
run: npm publish --access public
- name: Publish runpane to npm with trusted publishing
if: ${{ env.NPM_TOKEN == '' }}
working-directory: packages/runpane
run: npm publish --access public

publish-pypi:
if: github.ref_type == 'tag'
needs: [checksums, validate-runpane-packages]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/runpane
permissions:
contents: read
id-token: write
env:
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build Python distribution
run: |
python -m pip install --upgrade build
python -m build packages/runpane-py
- name: Publish runpane to PyPI with token fallback
if: ${{ env.PYPI_API_TOKEN != '' }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: packages/runpane-py/dist
password: ${{ env.PYPI_API_TOKEN }}
- name: Publish runpane to PyPI with trusted publishing
if: ${{ env.PYPI_API_TOKEN == '' }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: packages/runpane-py/dist

build-windows:
strategy:
fail-fast: false
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,49 @@ jobs:
env:
PANE_DIR: ${{ runner.temp }}/pane-ci

runpane-wrapper-tests:
name: Runpane Wrapper (${{ matrix.os }}, Node ${{ matrix.node-version }}, Python ${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-2022]
node-version: ['18.17.0', '22.15.1']
python-version: ['3.8', '3.13']

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install wrapper dependencies
run: pnpm install --filter runpane --ignore-scripts

- name: Check wrapper package versions
run: node scripts/sync-runpane-package-versions.js --check

- name: Build npm wrapper
run: pnpm --filter runpane build

- name: Run wrapper contract tests
run: node scripts/test-runpane-contract.js

- name: Run package manager smoke tests
run: node scripts/test-runpane-package-smoke.js

cross-os-main-tests:
name: Main Process Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
node_modules/
.pnpm-store/
package-lock.json
*.egg-info/

# Build outputs
dist/
Expand Down
50 changes: 43 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@

**Quick install (recommended)**

<sub>Package manager</sub><br />
<pre><code>npx --yes runpane@latest install client</code></pre>

<sub>pnpm</sub><br />
<pre><code>pnpm dlx runpane@latest install client</code></pre>

<sub>Python tools</sub><br />
<pre><code>pipx run runpane install client</code></pre>

<sub>or use the shell installers</sub><br />

<sub>Mac / Linux</sub><br />
<pre><code>curl -fsSL https://runpane.com/install.sh | sh</code></pre>

Expand Down Expand Up @@ -107,22 +118,40 @@ The easiest setup path is in the app:
4. On another desktop, open Pane, go to `Settings > Remote Pane`, paste the code, and connect.
5. On a phone or tablet, open [runpane.com/app](https://runpane.com/app/), paste the same code, and connect.

For a headless VM or server, use the remote installer instead:
For a headless VM or server, use `runpane`:

```bash
curl -fsSL https://runpane.com/install-remote.sh | sh -s -- --label "My Server"
npx --yes runpane@latest install daemon --label "My Server"
```

Windows PowerShell:
pnpm:

```powershell
& ([scriptblock]::Create((irm https://runpane.com/install-remote.ps1))) -Label "My Server"
```bash
pnpm dlx runpane@latest install daemon --label "My Server"
```

Prefer SSH instead of Tailscale:
Python tools:

```bash
pnpm remote:setup -- --label "My Server" --prefer-tunnel ssh
pipx run runpane install daemon --label "My Server"
```

Use SSH instead of Tailscale:

```bash
npx --yes runpane@latest install daemon --label "My Server" --prefer-tunnel ssh
```

The hosted shell installers remain available:

```bash
curl -fsSL https://runpane.com/install-remote.sh | sh -s -- --label "My Server"
```

Windows PowerShell:

```powershell
& ([scriptblock]::Create((irm https://runpane.com/install-remote.ps1))) -Label "My Server"
```

The CLI setup command prints the same connection code and, for SSH mode, the forwarding command. See the [Remote Daemon docs](https://runpane.com/docs/remote-daemon) for the full step-by-step setup, mobile install instructions, API key notes, and security model.
Expand Down Expand Up @@ -160,6 +189,13 @@ Other tools build custom chat UIs that only work with agents they've explicitly

### Quick Install

**Package manager:**
```bash
npx --yes runpane@latest install client
pnpm dlx runpane@latest install client
pipx run runpane install client
```

**Mac / Linux:**
```bash
curl -fsSL https://runpane.com/install.sh | sh
Expand Down
32 changes: 32 additions & 0 deletions docs/RELEASE_INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Pane releases are cut from a clean `main` checkout with `scripts/release.js`.
The script updates `package.json`, commits `release: vX.Y.Z`, tags the same
commit, pushes `HEAD:main`, and pushes the tag.

The same release commit also keeps the npm and PyPI wrapper package versions in
sync through `scripts/sync-runpane-package-versions.js`.

## Mechanical Invariants

Before a release, these facts must be true:
Expand All @@ -12,6 +15,8 @@ Before a release, these facts must be true:
- `HEAD` matches `origin/main`.
- For inferred bumps (`patch`, `minor`, `major`), `package.json` version matches
the latest `v*` semver tag.
- `packages/runpane/package.json`, `packages/runpane-py/pyproject.toml`, and
`packages/runpane-py/src/runpane/__init__.py` match the root release version.
- The release tag does not already exist locally or on `origin`.
- Dependencies are installed before running the release script so commit hooks can
run successfully.
Expand All @@ -34,6 +39,9 @@ node -p "require('./package.json').version"

pnpm typecheck
pnpm lint
pnpm run check:runpane-package-versions
pnpm run test:runpane-contract
pnpm run test:runpane-package-smoke
pnpm test:ci:minimal

pnpm run release patch
Expand All @@ -58,6 +66,7 @@ Pull requests to `main` run:
- `Code Quality`
- typecheck
- lint
- runpane wrapper compatibility tests across Node, Python, Linux, macOS, and Windows
- main process tests on Linux, macOS, and Windows
- frontend unit tests
- maintained Playwright smoke tests
Expand All @@ -76,6 +85,8 @@ Pushes to `main` run:
- Windows arm64 installer
- GitHub release publishing
- `SHA256SUMS.txt`
- npm `runpane` publish
- PyPI `runpane` publish
- `Notify website on release`

The release is not considered complete until the tag-triggered `Build & Release`
Expand All @@ -99,6 +110,8 @@ Confirm:
- `HEAD` and `origin/main` point at the release commit.
- The release commit has the expected `vX.Y.Z` tag.
- `Build & Release` succeeded for the tag.
- `npm view runpane version` reports `X.Y.Z`.
- `python3 -m pip index versions runpane` includes `X.Y.Z`.
- `Notify website on release` succeeded for the tag.
- `Code Quality` succeeded for the release commit on `main`.
- `Deploy Remote PWA Preview` succeeded for the release commit on `main`.
Expand All @@ -107,6 +120,23 @@ Confirm:

GitHub Actions provides `GITHUB_TOKEN` automatically.

The npm and PyPI packages should publish through trusted publishing:

- npm: configure a trusted publisher for package `runpane` on npmjs.com with
repository `dcouple/Pane`, workflow filename `build.yml`, and `npm publish`
permission. The workflow installs npm `11.5.1` or newer for OIDC support.
- PyPI: configure a trusted publisher for project `runpane` with repository
`dcouple/Pane`, workflow filename `build.yml`, and GitHub environment `pypi`.

Fallback token publishing is allowed only for first package reservation or
manual recovery. Use `NPM_TOKEN` or `PYPI_API_TOKEN` as local environment
variables or GitHub Actions secrets, do not commit token files such as `.npmrc`
or `.pypirc`, and revoke or rotate the tokens after use.

If the source repository remains private, do not promise npm provenance:
npm trusted publishing can still be used, but npm provenance attestations are
not generated for private repositories.

The release and preview workflows also depend on repository secrets and
variables configured in GitHub Actions. Relevant examples include:

Expand All @@ -127,6 +157,8 @@ The build process generates update metadata and installers under
- macOS `.dmg` and `.zip`
- Linux `.deb` and `.AppImage`
- Windows `.exe`
- npm package `runpane`
- PyPI package `runpane`

## Rollback

Expand Down
Loading
Loading