Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
9a17ee0
Rebrand: Polish the leftovers, and announce the rename (#488)
mmtr Aug 5, 2026
38f5d3c
Editor preview: make it live in the classic editor, and stop the hang…
AllTerrainDeveloper Aug 5, 2026
6f19092
Plugins: Only link to WordPress.org for plugins listed there (#495)
mmtr Aug 5, 2026
e5c077b
Admin bar: Keep the fullscreen tooltip in sync with the button state …
mmtr Aug 5, 2026
0e6dcd6
Revisions: Fix the classic revisions screen in a desktop window (#498)
mmtr Aug 5, 2026
46fb0a7
Selection: hold more than one thing at a time (#501)
AllTerrainDeveloper Aug 5, 2026
7a87ccc
Shell: Rename the site folder to WP Explorer, Settings to Preferences…
mmtr Aug 5, 2026
9d427a5
Admin bar: stop the snap-checkbox poll from running forever (#504)
AllTerrainDeveloper Aug 5, 2026
56cd0b7
Dialogs: give the rename field back to the palette (#503)
AllTerrainDeveloper Aug 5, 2026
c4eba48
Mio: ship the mascot as a standalone drop-in script (#505)
AllTerrainDeveloper Aug 6, 2026
2cb62cb
fix: decode commenter names in comments widget (#507)
Pranjal1423 Aug 6, 2026
a763b50
Chromeless: keep Quick Edit and Bulk Edit alive across a soft reload …
mmtr Aug 6, 2026
591b14c
Use the theme outline token for dock status indicators (#509)
KarunyaChavan Aug 6, 2026
5379364
Dialogs: rework the rebrand announcement and fix the hero shimmer (#511)
mmtr Aug 6, 2026
f5da683
Activity channels: Drop the pre-rebrand desktop-mode prefix (#512)
mmtr Aug 6, 2026
4cee78e
Segmented control: Fix the selected pill size on first paint (#515)
mmtr Aug 7, 2026
b8555d4
Migrations: don't flag a fresh install as a pre-rebrand one (#514)
mmtr Aug 7, 2026
e90ccd4
Docs: Strip version-history annotations that slipped back in (#520)
mmtr Aug 7, 2026
7fd4722
Docs: Fix the index links, version claims, and missing migration entr…
mmtr Aug 7, 2026
398039d
Docs: Fill the filter reference gaps, and drop the brand-map filter (…
mmtr Aug 7, 2026
3317a7e
chore(deps): bump anthropics/claude-code-action from 1.0.165 to 1.0.1…
dependabot[bot] Aug 7, 2026
90f7caa
i18n: Fix the POT headers and the release-time extraction order (#522)
mmtr Aug 7, 2026
47f1d42
chore(deps): bump actions/setup-node from 6 to 7 (#471)
dependabot[bot] Aug 7, 2026
0459093
chore(deps): bump actions/checkout from 4.3.1 to 7.0.1 (#469)
dependabot[bot] Aug 7, 2026
49d66e4
Context menus: Clamp to the viewport after the menu has rendered (#523)
mmtr Aug 7, 2026
4fa94c0
PR previews: Resolve fork pull requests when publishing (#528)
mmtr Aug 7, 2026
ae0a73a
Windows: Stop the loading spinner from fading over painted content (#…
mmtr Aug 7, 2026
56a50a2
AGENTS.md: drop the table of contents (#516)
epeicher Aug 7, 2026
e516fc0
Fix(window): refine page-title-action button redundancy and layout po…
CookieDarb Aug 7, 2026
a5c7124
App icons: one family for the four built-ins (#513)
nuriapenya Aug 7, 2026
9e35da0
chore: bump to 1.0.0
AllTerrainDeveloper Aug 7, 2026
b6474ad
fix(release): resolve GitHub repository dynamically for CI commands
AllTerrainDeveloper Aug 7, 2026
44aae87
Fix the WordPress.org deploy after the repo rename (#534)
AllTerrainDeveloper Aug 7, 2026
40fb0a5
fix(release): pass VERSION explicitly to the wp.org deploy (#535)
AllTerrainDeveloper Aug 7, 2026
31124ee
Tile contrast, comments-window styling, Overview clicks, and preview …
AllTerrainDeveloper Aug 8, 2026
e7591a3
docs(readme): expand the wp.org plugin title (#539)
AllTerrainDeveloper Aug 8, 2026
cf885c5
Always show the Agents section in WP Explorer (#540)
AllTerrainDeveloper Aug 8, 2026
0f70fdd
Preserve fullscreen state across Overview (#536)
joenermunch Aug 8, 2026
3e1a767
fix: decode HTML entities in plugin install toast (#529)
Pranjal1423 Aug 8, 2026
516efa7
Settle a pending Overview exit before re-entering (#541)
AllTerrainDeveloper Aug 8, 2026
54fb1f8
AI: surface an empty final answer as an error instead of a silent suc…
juanlentino Aug 10, 2026
f46be22
Set OpenStation windows free into real OS windows (Electron adapter) …
AllTerrainDeveloper Aug 10, 2026
478fab6
chore: bump to 1.0.1
AllTerrainDeveloper Aug 11, 2026
35f6877
Add docblocks to desktop-file type classes and REST handlers (#546)
shsajalchowdhury Aug 11, 2026
c6b272e
AI: add a filter for the model config sent to the provider (#549)
mmtr Aug 11, 2026
b292841
fix: use correct trash labels in pages window (#550)
Pranjal1423 Aug 11, 2026
6ab2ed8
Pages window: Use page wording in the pager, and cover it with tests …
mmtr Aug 11, 2026
c670170
Consolidate navigation into a single dock (#545)
nuriapenya Aug 11, 2026
a744631
Notes: Merge the sticky-notes into pinned notes (#497)
mmtr Aug 11, 2026
e7a3c34
Confirm dialog: route Enter to the focused button, trap and restore f…
AllTerrainDeveloper Aug 12, 2026
0831075
Posts window: Pluralize the bulk-action confirm text (#561)
mmtr Aug 12, 2026
ee438b6
Windows: Fix the accessibility semantics of controls, tabs and loadin…
AllTerrainDeveloper Aug 12, 2026
13cf2a9
Make the active window tab a frosted plate that slides (#551)
nuriapenya Aug 12, 2026
d4440c4
A11y: keep actionable toasts alive while attended, trap focus in firs…
AllTerrainDeveloper Aug 12, 2026
f5f070c
Add the missing Domain Path header (#572)
mmtr Aug 12, 2026
372421e
AI: Internationalize the assistant overlay (#563)
mmtr Aug 12, 2026
f52e65e
Dashboard: Stop the welcome panel dismiss opening a stray window (#565)
mmtr Aug 12, 2026
1c69c88
Shell: exit OpenStation when the plugin stops being active (#566)
mmtr Aug 12, 2026
466b307
AI: Drop the SSE transport and answer over a single request (#574)
mmtr Aug 12, 2026
b9381bd
Activity indicator: settle on the response, not on the promise (#573)
AllTerrainDeveloper Aug 12, 2026
ea4afa2
fix: set empty state heading color in feed-buddy (#599)
Pranjal1423 Aug 13, 2026
a090ded
Native windows: Remove the first-open intro modals (#579)
mmtr Aug 13, 2026
baef356
Woo relations: a refund is not a purchase; user tiles: carry their ke…
AllTerrainDeveloper Aug 13, 2026
ee6ea13
Settings: Redesign of this panel and regrouping (#600)
nuriapenya Aug 14, 2026
c799ebb
fix: refresh folder share action on settings save (#604)
Pranjal1423 Aug 14, 2026
13d9394
Audit part 2: silent settings loss, folder-sharing visibility, and wa…
AllTerrainDeveloper Aug 14, 2026
86fe4dc
Dock: Move the admin bar's jobs into the dock and a notch (#608)
mmtr Aug 14, 2026
2581a2c
Trash: Drop the desktop icon, and let a placeable tile choose its rai…
mmtr Aug 14, 2026
f28b64b
docs: rewrite WordPress.org readme (#575)
nickhamze Aug 14, 2026
64cbb98
chore: bump to 1.1.0
AllTerrainDeveloper Aug 14, 2026
6159113
Make release packaging work with macOS Bash
nickhamze Aug 4, 2026
7f916b0
Add Gutenberg editor sidecar
nickhamze Aug 17, 2026
f848f32
Wait for Gutenberg before showing sidecar
nickhamze Aug 17, 2026
863415d
Avoid duplicate sidecar readiness repaint
nickhamze Aug 17, 2026
caa9c59
Use PHP 8.4 for Sidecar Playground
nickhamze Aug 17, 2026
1552f15
Present Gutenberg sidebar as attached window
nickhamze Aug 17, 2026
155295e
Open Sidebar Window as managed sibling
nickhamze Aug 17, 2026
8a8b94c
Attach Sidebar Window at Gutenberg width
nickhamze Aug 18, 2026
f08b9c5
Fix default windows on subdirectory installs
nickhamze Aug 18, 2026
d13c0c4
Preserve sidecar auto-open through clean URLs
nickhamze Aug 18, 2026
8791c2b
Add selectable plugin sidebars to Sidecar
nickhamze Aug 18, 2026
819b4d2
Keep Jetpack in Playground offline mode
nickhamze Aug 18, 2026
17cfded
Restore Blueprint test formatting
nickhamze Aug 18, 2026
ed3afff
Enable Jetpack sidebar in Playground demo
nickhamze Aug 18, 2026
5338049
Add persistent Sidebar panel selector
nickhamze Aug 18, 2026
724b93b
Route Gutenberg sidebar buttons to Sidecar
nickhamze Aug 18, 2026
e30531f
Present Sidecar as an attached inspector
nickhamze Aug 18, 2026
903accd
Keep the connected editor visually focused
nickhamze Aug 18, 2026
d8f3a20
Present Sidecar as an inspector drawer
nickhamze Aug 18, 2026
0ca63b1
Unify the Sidecar title bar
nickhamze Aug 18, 2026
5f58fe8
Keep both Gutenberg sidebars open
nickhamze Aug 18, 2026
ab2ebb4
Replace Sidecar dropdown with Gutenberg icons
nickhamze Aug 18, 2026
9124dbc
Ignore Gutenberg tab controls in Sidecar
nickhamze Aug 18, 2026
92fa83c
Inherit OpenStation palette in Sidecar chrome
nickhamze Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 26 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ jobs:
name: Lint · Types · Vitest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7.0.1
with:
# Don't leave the GITHUB_TOKEN in .git/config; later steps run
# PR-authored code (npm scripts, build) and this job never needs
# git auth after checkout.
persist-credentials: false

- name: Set up Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
Expand Down Expand Up @@ -58,6 +58,26 @@ jobs:
npm --prefix extensions/desktop-mode-feed-buddy run build
git diff --exit-code -- extensions/desktop-mode-feed-buddy/assets/js

- name: Electron adapter extension checks
env:
# Nothing in this job launches Electron — this is lint, types,
# unit tests and the bundles. The `electron` package still
# installs (its type definitions are what `app/tsconfig.json`
# compiles against); only the ~100 MB binary download is
# skipped.
ELECTRON_SKIP_BINARY_DOWNLOAD: '1'
run: |
npm --prefix extensions/openstation-electron-adapter ci
# The package's own `verify`, rather than a sequence spelled
# out again here. It builds BEFORE it tests, and that order is
# load-bearing: `connect-bundle.test.ts` asserts against
# `app/dist/renderer/connect.js`, so a run that tests first
# passes only on a machine that happens to have built already.
# Deferring to `verify` also means a developer running it
# locally is running what CI runs.
npm --prefix extensions/openstation-electron-adapter run verify
git diff --exit-code -- extensions/openstation-electron-adapter/assets/js

php:
name: PHPUnit · PHP ${{ matrix.php }}
runs-on: ubuntu-latest
Expand All @@ -67,15 +87,15 @@ jobs:
php: [ '8.3', '8.4' ]

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7.0.1
with:
# Don't leave the GITHUB_TOKEN in .git/config; later steps run
# PR-authored code (npm scripts, build) and this job never needs
# git auth after checkout.
persist-credentials: false

- name: Set up Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
Expand Down Expand Up @@ -130,15 +150,15 @@ jobs:
name: Plugin Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7.0.1
with:
# Don't leave the GITHUB_TOKEN in .git/config; later steps run
# PR-authored code (npm scripts, build) and this job never needs
# git auth after checkout.
persist-credentials: false

- name: Set up Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ jobs:
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@558b1d6cab4085c7753fe402c10bef0fbb92ac7a # v1.0.165
uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1.0.183
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr-preview-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7.0.1

- name: Set up Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
Expand Down
58 changes: 45 additions & 13 deletions .github/workflows/pr-preview-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,65 @@ jobs:
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7.0.1

- name: Resolve PR from trusted workflow_run data
id: meta
uses: actions/github-script@v9
with:
script: |
// The `pr-meta` artifact is written by the fork-controlled build
// run, so its contents are untrusted — a malicious PR could point
// the preview comment at any PR. Derive the identity from the
// `workflow_run` event instead: GitHub sets `head_sha` and it
// cannot be spoofed by PR code. `workflow_run.pull_requests` is
// empty for fork PRs, so resolve the PR number via the API and
// require its head SHA to match before publishing anything.
const headSha = context.payload.workflow_run.head_sha;
// PR identity is never taken from the build run's artifacts — that
// run executes fork-controlled code and can write whatever it
// likes, so a malicious PR could aim the preview comment at any
// PR. Derive it from the `workflow_run` event instead: GitHub sets
// `head_sha`, `head_repository` and `head_branch`, and PR code
// cannot spoof any of them.
//
// Resolve the PR by head repo + branch. `workflow_run.pull_requests`
// is empty for fork PRs, and so is
// `listPullRequestsAssociatedWithCommit` — that endpoint does not
// resolve commits living in a fork, which left every fork PR
// without a preview.
//
// The `head` filter is server-side and fails open: a value GitHub
// does not recognise is ignored rather than rejected, and the call
// then returns every PR. Re-check owner, branch and SHA against the
// payload below so ownership is an invariant enforced here, not a
// bet on that filter's behaviour.
const run = context.payload.workflow_run;
const headSha = run.head_sha;
if (!/^[0-9a-f]{40}$/.test(headSha)) {
core.setFailed(`Unexpected workflow_run head SHA: ${headSha}`);
return;
}
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
const headOwner = run.head_repository?.owner?.login;
const headBranch = run.head_branch;
if (!headOwner || !headBranch) {
core.setFailed(`Incomplete workflow_run head data: owner=${headOwner} branch=${headBranch}`);
return;
}
// `state: 'all'` because a PR can merge between the build finishing
// and this run starting; the old lookup published in that window
// and there's no reason to start failing there. A branch reused
// across several PRs can match more than once, so prefer the open
// one.
const prs = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: headSha,
state: 'all',
head: `${headOwner}:${headBranch}`,
per_page: 100,
});
const pr = prs.find((p) => p.head.sha === headSha);
// `head.repo` is null when the head fork has been deleted.
const matches = prs.filter(
(p) =>
p.head.sha === headSha &&
p.head.repo?.owner?.login === headOwner &&
p.head.ref === headBranch
);
const pr = matches.find((p) => p.state === 'open') ?? matches[0];
if (!pr) {
core.setFailed(`No pull request found with head SHA ${headSha}; refusing to publish a preview.`);
core.setFailed(`No pull request for ${headOwner}:${headBranch} at head SHA ${headSha}; refusing to publish a preview.`);
return;
}
core.setOutput('pr-number', String(pr.number));
Expand Down
68 changes: 55 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
name: Release

# Triggered by pushing a vX.Y.Z tag. Builds the plugin zip and creates a
# GitHub Release with it attached. Use `bin/release.sh` locally to cut a
# release end-to-end (bump + commit + tag + push).
# Triggered by pushing a vX.Y.Z tag. Builds the plugin zip, creates a GitHub
# Release with it attached, then deploys stable tags to WordPress.org. Use
# `bin/release.sh` locally to cut a release end-to-end (bump + commit + tag
# + push).
#
# Also runnable manually against an already-published tag, which re-attempts
# the WordPress.org deploy and leaves the GitHub Release untouched:
#
# gh workflow run release.yml --ref trunk -f tag=v1.0.0
#
# That exists because a tag push runs the workflow definition frozen into
# that tag's commit, so a deploy that fails for a workflow-level reason can
# never be fixed by re-running it. Dispatching from trunk runs the current
# definition instead.

on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Published tag to deploy to WordPress.org (e.g. v1.0.0)'
required: true
type: string

permissions:
contents: write
Expand All @@ -16,11 +33,18 @@ jobs:
release:
name: Build & publish release
runs-on: ubuntu-latest
env:
# The tag being released: the pushed ref, or the dispatch input.
# Consumed as a shell variable rather than interpolated into `run:`
# bodies, so the dispatch input can't inject into the script.
TAG: ${{ inputs.tag || github.ref_name }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.tag || github.ref_name }}

- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
cache: 'npm'
Expand All @@ -31,8 +55,7 @@ jobs:

- name: Verify tag matches plugin version
run: |
tag="${{ github.ref_name }}"
tag="${tag#v}"
tag="${TAG#v}"
pkg=$(node -p "require('./package.json').version")
header=$(grep -oP '^\s*\*\s*Version:\s*\K\S+' desktop-mode.php)
constant=$(grep -oP "OPENSTATION_VERSION',\s*'\K[^']+" desktop-mode.php)
Expand All @@ -41,36 +64,55 @@ jobs:
echo "::error::Version mismatch — tag '$tag' vs package.json=$pkg header=$header OPENSTATION_VERSION=$constant readme.txt Stable tag=$stable"
exit 1
fi
# The deploy action derives VERSION from GITHUB_REF, which is only a
# tag ref on a tag push — on a dispatch it resolves to the branch ref
# and the SVN tag copy becomes `tags/refs/heads/trunk`. Publish the
# version that was just checked against all four locations, so the
# deploy uses a verified value however the workflow was triggered.
echo "VERSION=$tag" >> "$GITHUB_ENV"

- name: Build
run: npm run build

- name: Package plugin zip
run: bin/package.sh

# Skipped on a manual dispatch: the Release already exists, and
# `gh release create` is not idempotent — it would fail the job
# before it ever reached the deploy.
- name: Create GitHub Release
if: github.event_name == 'push'
env:
GH_TOKEN: ${{ github.token }}
run: |
tag="${{ github.ref_name }}"
flags=()
if [[ "$tag" == *-* ]]; then
if [[ "$TAG" == *-* ]]; then
flags+=(--prerelease)
fi
gh release create "$tag" \
--title "$tag" \
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
"${flags[@]}" \
openstation.zip

- name: Unpack zip for wp.org deploy
if: ${{ !contains(github.ref_name, '-') }}
if: ${{ !contains(env.TAG, '-') }}
run: unzip -q openstation.zip -d build/

- name: Deploy to WordPress.org
if: ${{ !contains(github.ref_name, '-') }}
if: ${{ !contains(env.TAG, '-') }}
uses: 10up/action-wordpress-plugin-deploy@54bd289b8525fd23a5c365ec369185f2966529c2 # 2.3.0
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
# The wp.org slug is frozen at `desktop-mode` (see AGENTS.md) — it is
# the published plugin's SVN path and install directory, and renaming
# it would orphan every existing install's update check. Set it
# explicitly: the action otherwise defaults SLUG to the GitHub repo
# name, which used to coincide with the wp.org slug and stopped
# doing so when this repo was renamed to `openstation`.
SLUG: desktop-mode
BUILD_DIR: ./build/desktop-mode
# VERSION comes from the verify step via $GITHUB_ENV — see the note
# there. Both it and SLUG default off a GitHub context that is only
# correct for a tag push, so neither is left implicit.
Loading