Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
23ac5c1
Enforce maintained regression checks
parsakhaz May 14, 2026
1cdd1ca
ci: pin Windows quality runner
parsakhaz May 16, 2026
36993b8
fix: use target path semantics for worktree sync
parsakhaz May 17, 2026
cceb3ca
Extract runtime and event sink boundary
parsakhaz May 14, 2026
7a59c51
Add daemon boundary import regression test
parsakhaz May 14, 2026
debeee2
feat: add daemon protocol primitives
parsakhaz May 14, 2026
2b5440e
fix: preserve UTF-8 daemon socket frames
parsakhaz May 16, 2026
6dcc1dc
feat: add pane command registry core
parsakhaz May 14, 2026
2df25a1
feat: route data-domain IPC through command registry
parsakhaz May 14, 2026
01a2ffa
feat: route terminal runtime IPC through registry
parsakhaz May 14, 2026
0661906
feat: route session runtime IPC through registry
parsakhaz May 14, 2026
4ca9432
feat: route git status IPC through registry
parsakhaz May 14, 2026
777dd05
feat: route git mutator IPC through registry
parsakhaz May 14, 2026
0f59af7
feat: start local Pane daemon server
parsakhaz May 14, 2026
fc28896
fix: harden local daemon socket startup
parsakhaz May 16, 2026
0253759
fix: forward script state daemon events
parsakhaz May 16, 2026
9fee906
fix: drop backpressured daemon clients
parsakhaz May 16, 2026
e182d6c
fix: harden local daemon socket server
parsakhaz May 16, 2026
d866e62
fix: shorten unix daemon socket paths
parsakhaz May 17, 2026
e359c7f
feat: deliver hidden terminal output to daemon clients
parsakhaz May 14, 2026
4df5939
fix: preserve hidden terminal output on visibility change
parsakhaz May 16, 2026
30d7048
fix: flush buffered output before hiding terminals
parsakhaz May 16, 2026
66f142b
feat: route renderer daemon commands through bridge
parsakhaz May 14, 2026
4305372
test: harden daemon bridge boundary checks
parsakhaz May 14, 2026
8afaeb6
fix: restore live Electron daemon bridge boot
parsakhaz May 14, 2026
f596c08
test: lock preload daemon channel parity
parsakhaz May 14, 2026
39a22bb
feat: extract headless daemon host bootstrap
parsakhaz May 14, 2026
41a3016
feat: add remote daemon config surface
parsakhaz May 14, 2026
f505891
fix: reject empty remote daemon profiles
parsakhaz May 14, 2026
150c178
feat: add remote daemon HTTP transport
parsakhaz May 16, 2026
aabe811
fix: harden remote daemon HTTP transport
parsakhaz May 16, 2026
f14536c
feat: daemonize permission approval flow
parsakhaz May 16, 2026
a6ffe20
test: cover daemon permission dialog smoke
parsakhaz May 17, 2026
ae1fc51
feat: add Electron remote daemon client adapter
parsakhaz May 17, 2026
c372355
fix: harden remote daemon client transport
parsakhaz May 17, 2026
c2226a8
fix: keep retrying remote daemon connects
parsakhaz May 17, 2026
f330f90
fix: roll back failed remote activation
parsakhaz May 17, 2026
d55574b
fix: preserve remote daemon subpath routing
parsakhaz May 17, 2026
b9f9ab2
fix: resync remote clients after reconnect
parsakhaz May 17, 2026
72591ab
fix: normalize IPv6 remote pairing defaults
parsakhaz May 17, 2026
c7a80b0
fix: resync remote client on initial connect
parsakhaz May 17, 2026
b862e16
fix: preserve split CRLF SSE chunks
parsakhaz May 17, 2026
c84cc64
fix: forward active session hints to remote daemon
parsakhaz May 17, 2026
ab91d0b
fix: time out remote daemon SSE handshake
parsakhaz May 17, 2026
9408042
fix: block terminal file reveal in remote mode
parsakhaz May 17, 2026
6b465da
test: harden self-hosted remote validation
parsakhaz May 17, 2026
35ae00e
fix: add remote profile import flow
parsakhaz May 17, 2026
a7e9839
fix: seed IPv6 remote profile URLs
parsakhaz May 17, 2026
1b08ef3
feat: add hosted cloud workspace state contract
parsakhaz May 17, 2026
1d41adc
fix: surface daemon-only cloud state
parsakhaz May 17, 2026
e401ea0
fix: handle daemon-first hosted workspace state
parsakhaz May 17, 2026
3870d76
fix: hide hosted daemon stop controls
parsakhaz May 17, 2026
24b3f17
fix: preserve legacy cloud tunnel controls
parsakhaz May 17, 2026
2929e7f
fix: honor novnc fallback for hosted cloud
parsakhaz May 17, 2026
4dc2aa6
fix: fall back to hosted daemon state
parsakhaz May 17, 2026
de1547c
feat: link hosted cloud workspaces to remote profiles
parsakhaz May 17, 2026
2e087f1
fix: gate hosted daemon readiness on connection
parsakhaz May 17, 2026
df2bea2
fix: handle hosted cloud fallback states
parsakhaz May 17, 2026
00c68f8
fix: remove duplicate cloud smoke coverage
parsakhaz May 17, 2026
8e03d30
fix: resync after hosted cloud mode switch
parsakhaz May 17, 2026
0052efa
fix: handle hosted cloud reconnect edge cases
parsakhaz May 17, 2026
6029cf3
fix: surface hosted daemon connection failures
parsakhaz May 17, 2026
e77b1d4
fix: refresh config on remote resync
parsakhaz May 17, 2026
e5ad15d
fix: expose recovery for missing hosted profile
parsakhaz May 17, 2026
42405db
fix: mark missing hosted profiles as connection errors
parsakhaz May 17, 2026
7e111aa
feat: boot hosted cloud VMs into headless daemon
parsakhaz May 17, 2026
33d989e
Merge current main into nightly integration
parsakhaz May 17, 2026
ae136ee
feat(remote): add one-command daemon setup
parsakhaz May 17, 2026
ca72078
fix(remote): emit Linux headless daemon env
parsakhaz May 17, 2026
692290d
fix(remote): prioritize connection import settings
parsakhaz May 17, 2026
40ba5cc
fix(remote): polish settings and cloud stop behavior
parsakhaz May 17, 2026
f2ad657
fix(remote): detect setup args in packaged Windows
parsakhaz May 17, 2026
4c282f9
test(cloud): stub hosted workspace status smoke
parsakhaz May 18, 2026
d775eb1
test: stabilize remote daemon smoke coverage
parsakhaz May 18, 2026
15bfc6c
Fix settings font reload loop
parsakhaz May 18, 2026
419134c
Abort cloud stop when local switch fails
parsakhaz May 18, 2026
53980bf
Add manual nightly release workflow
parsakhaz May 18, 2026
f18ee53
feat: add in-app remote host setup
parsakhaz May 18, 2026
a20f13e
Clarify Remote Pane setup instructions
parsakhaz May 18, 2026
f438c0e
fix: require tailscale for remote setup
parsakhaz May 18, 2026
e7c2073
fix: disambiguate remote setup label
parsakhaz May 18, 2026
d140d42
fix: install tailscale during remote setup
parsakhaz May 18, 2026
d3c263b
Add interactive Tailscale remote setup
parsakhaz May 18, 2026
e0ec681
Fix interactive Tailscale Serve setup
parsakhaz May 18, 2026
a672567
Improve Tailscale client recovery UX
parsakhaz May 18, 2026
53dce73
Fix Tailscale setup recovery edge cases
parsakhaz May 18, 2026
c26dd4f
Use macOS Tailscale CLI formula fallback
parsakhaz May 18, 2026
0206bc2
Add Tailscale IP fallback for remote profiles
parsakhaz May 18, 2026
7d53b48
Avoid remote setup port collisions
parsakhaz May 18, 2026
762a46c
Fix Settings remote setup port selection
parsakhaz May 18, 2026
774ca01
Fix remote daemon liveness and status
parsakhaz May 18, 2026
d2cdd21
Clarify Tailscale Serve startup delay
parsakhaz May 18, 2026
bd38449
Show remote client device labels
parsakhaz May 18, 2026
c41f71d
Fix remote terminal visibility per viewer
parsakhaz May 18, 2026
6d0fe9b
Add remote host client controls
parsakhaz May 18, 2026
b574859
Add remote desktop shortcut
parsakhaz May 19, 2026
bcb1263
fix: normalize session timestamps in frontend
parsakhaz May 19, 2026
3980c68
test: fix remote daemon CI mocks
parsakhaz May 19, 2026
0edc89e
Fix runtime switch renderer resync
parsakhaz May 19, 2026
224f548
refactor: audit remote lifecycle transitions
parsakhaz May 19, 2026
3efd049
feat: add remote Pane PWA client
parsakhaz May 19, 2026
e8c779a
Add remote PWA preview deploy
parsakhaz May 20, 2026
2affedb
Fix remote PWA preview public routing
parsakhaz May 20, 2026
824f5cb
Fix Tailscale remote preview CORS
parsakhaz May 20, 2026
9d3cf61
Add remote host code cleanup
parsakhaz May 20, 2026
870fd14
Revoke remote host codes when forgotten
parsakhaz May 20, 2026
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
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**
!deploy/
!deploy/remote-pwa/
!deploy/remote-pwa/Dockerfile
!deploy/remote-pwa/nginx.conf
!frontend/
!frontend/dist/
!frontend/dist/**
96 changes: 96 additions & 0 deletions .github/workflows/deploy-remote-pwa-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Deploy Remote PWA Preview

on:
push:
branches: [nightly]
workflow_dispatch:

permissions:
contents: read
id-token: write

env:
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID || 'pane-pwa-preview' }}
GCP_REGION: ${{ vars.GCP_REGION || 'us-central1' }}
GAR_REPOSITORY: ${{ vars.GAR_REPOSITORY || 'pane-preview' }}
CLOUD_RUN_SERVICE: ${{ vars.CLOUD_RUN_SERVICE || 'pane-remote-pwa-preview' }}
CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT: ${{ vars.CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT || '' }}

jobs:
deploy:
name: Build and deploy preview
runs-on: ubuntu-latest

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: '22.15.1'
cache: 'pnpm'

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

- name: Build remote PWA assets
run: pnpm run build:frontend

- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_DEPLOY_SERVICE_ACCOUNT }}

- name: Setup Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2

- name: Configure Artifact Registry Docker auth
run: gcloud auth configure-docker "${GCP_REGION}-docker.pkg.dev" --quiet --project="${GCP_PROJECT_ID}"

- name: Build and push container
env:
IMAGE_TAG: ${{ github.sha }}
run: |
set -euo pipefail

image="${GCP_REGION}-docker.pkg.dev/${GCP_PROJECT_ID}/${GAR_REPOSITORY}/${CLOUD_RUN_SERVICE}:${IMAGE_TAG}"
docker build \
--file deploy/remote-pwa/Dockerfile \
--tag "$image" \
.
docker push "$image"
echo "IMAGE=$image" >> "$GITHUB_ENV"

- name: Deploy to Cloud Run
run: |
set -euo pipefail

runtime_service_account="${CLOUD_RUN_RUNTIME_SERVICE_ACCOUNT:-pane-remote-pwa-runtime@${GCP_PROJECT_ID}.iam.gserviceaccount.com}"

gcloud run deploy "$CLOUD_RUN_SERVICE" \
--project="$GCP_PROJECT_ID" \
--region="$GCP_REGION" \
--platform=managed \
--image="$IMAGE" \
--service-account="$runtime_service_account" \
--no-invoker-iam-check \
--min-instances=0 \
--max-instances=1 \
--cpu=1 \
--memory=256Mi \
--port=8080 \
--set-env-vars="PANE_REMOTE_PWA_PREVIEW_COMMIT=${GITHUB_SHA},PANE_REMOTE_PWA_PREVIEW_REF=${GITHUB_REF_NAME}" \
--quiet

- name: Print service URL
run: |
gcloud run services describe "$CLOUD_RUN_SERVICE" \
--project="$GCP_PROJECT_ID" \
--region="$GCP_REGION" \
--platform=managed \
--format='value(status.url)'
239 changes: 239 additions & 0 deletions .github/workflows/nightly-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
name: Nightly / Canary Release

on:
workflow_dispatch:
inputs:
channel:
description: 'Release channel'
type: choice
required: true
default: nightly
options:
- nightly
- canary
source_ref:
description: 'Branch, tag, or SHA to build'
type: string
required: true
default: nightly

permissions:
contents: write

jobs:
metadata:
runs-on: ubuntu-latest
outputs:
channel: ${{ steps.meta.outputs.channel }}
source_ref: ${{ steps.meta.outputs.source_ref }}
source_sha: ${{ steps.meta.outputs.source_sha }}
short_sha: ${{ steps.meta.outputs.short_sha }}
version: ${{ steps.meta.outputs.version }}
tag: ${{ steps.meta.outputs.tag }}
title: ${{ steps.meta.outputs.title }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.source_ref }}
fetch-depth: 0

- id: meta
shell: bash
run: |
set -euo pipefail

channel="${{ inputs.channel }}"
source_ref="${{ inputs.source_ref }}"
base_version="$(node -p "require('./package.json').version.replace(/-.*/, '')")"
source_sha="$(git rev-parse HEAD)"
short_sha="$(git rev-parse --short=7 HEAD)"
timestamp="$(date -u +%Y%m%d%H%M)"
version="${base_version}-${channel}.${timestamp}.${short_sha}.${{ github.run_number }}.${{ github.run_attempt }}"
tag="v${version}"
title="Pane ${channel^} ${version}"

if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$ ]]; then
echo "Generated version is not valid semver: $version" >&2
exit 1
fi

{
echo "channel=$channel"
echo "source_ref=$source_ref"
echo "source_sha=$source_sha"
echo "short_sha=$short_sha"
echo "version=$version"
echo "tag=$tag"
echo "title=$title"
} >> "$GITHUB_OUTPUT"

build:
needs: metadata
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
command: build:mac:ci
artifact_name: pane-macos
artifact_path: |
dist-electron/*.dmg
- os: ubuntu-latest
command: build:linux:ci
artifact_name: pane-linux
artifact_path: |
dist-electron/*.deb
dist-electron/*.AppImage
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.metadata.outputs.source_sha }}

- uses: actions/setup-python@v5
with:
python-version: '3.11'

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: '22.15.1'
cache: 'pnpm'

- uses: actions/cache@v4
with:
path: |
~/.cache/electron
~/.cache/electron-builder
key: ${{ runner.os }}-electron-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-electron-

- run: pnpm install --frozen-lockfile

- name: Stamp prerelease version
env:
NIGHTLY_VERSION: ${{ needs.metadata.outputs.version }}
run: |
node - <<'NODE'
const fs = require('fs');
const path = require('path');
const packagePath = path.resolve('package.json');
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
packageJson.version = process.env.NIGHTLY_VERSION;
fs.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
NODE

- name: Build ${{ matrix.os }} package
env:
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
CSC_DISABLE: 'true'
run: pnpm run ${{ matrix.command }}

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact_name }}-${{ needs.metadata.outputs.channel }}-${{ needs.metadata.outputs.tag }}
path: ${{ matrix.artifact_path }}
if-no-files-found: error
retention-days: 30

build-windows:
needs: metadata
strategy:
fail-fast: false
matrix:
arch:
- x64
- arm64
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.metadata.outputs.source_sha }}

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: '22.15.1'
cache: 'pnpm'

- uses: actions/cache@v4
with:
path: |
~/AppData/Local/electron/Cache
~/AppData/Local/electron-builder/Cache
key: windows-${{ matrix.arch }}-electron-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: windows-${{ matrix.arch }}-electron-

- run: pnpm install --frozen-lockfile

- name: Stamp prerelease version
env:
NIGHTLY_VERSION: ${{ needs.metadata.outputs.version }}
shell: bash
run: |
node - <<'NODE'
const fs = require('fs');
const path = require('path');
const packagePath = path.resolve('package.json');
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
packageJson.version = process.env.NIGHTLY_VERSION;
fs.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
NODE

- name: Build Windows ${{ matrix.arch }} package
run: node scripts/build-win.js ${{ matrix.arch }}

- uses: actions/upload-artifact@v4
with:
name: pane-windows-${{ matrix.arch }}-${{ needs.metadata.outputs.channel }}-${{ needs.metadata.outputs.tag }}
path: |
dist-electron/*-Windows-${{ matrix.arch }}.exe
if-no-files-found: error
retention-days: 30

publish:
needs:
- metadata
- build
- build-windows
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true

- name: Publish prerelease
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
CHANNEL: ${{ needs.metadata.outputs.channel }}
SOURCE_REF: ${{ needs.metadata.outputs.source_ref }}
SOURCE_SHA: ${{ needs.metadata.outputs.source_sha }}
SHORT_SHA: ${{ needs.metadata.outputs.short_sha }}
VERSION: ${{ needs.metadata.outputs.version }}
TAG: ${{ needs.metadata.outputs.tag }}
TITLE: ${{ needs.metadata.outputs.title }}
shell: bash
run: |
set -euo pipefail

find release-assets -maxdepth 1 -type f | sort
cat > release-notes.md <<EOF
Manual ${CHANNEL} build from \`${SOURCE_REF}\` at \`${SHORT_SHA}\`.

This is a GitHub prerelease for manual testing. It is not marked as Latest and does not include update metadata assets, so stable users will not be moved onto this channel by auto-update.

Build version: \`${VERSION}\`
Source commit: \`${SOURCE_SHA}\`
EOF

gh release create "$TAG" release-assets/* \
--repo "$GH_REPO" \
--target "$SOURCE_SHA" \
--title "$TITLE" \
--notes-file release-notes.md \
--prerelease \
--latest=false
Loading
Loading