From 99ca72833af8c8d367fb1ace85d13fe6f9b8efb8 Mon Sep 17 00:00:00 2001 From: Sam Clark Date: Wed, 19 Aug 2026 13:50:04 -0500 Subject: [PATCH] Publish a kernel-less win32-arm64 VSIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Positron's bootstrap appends ?targetPlatform= to the gallery asset URL, and the gallery matches that value exactly. A target that was never published answers HTTP 403 rather than falling back to the untargeted build, so omitting win32-arm64 fails Positron's own Windows arm64 build instead of degrading to the universal VSIX. Measured against the live registry: the untargeted ggsql VSIX answers 200 with no targetPlatform and 403 for every target, while posit.air-vscode answers 200 per published target and 403 with none. No runner builds a Windows arm64 kernel yet, so publish the target carrying no kernel. It answers 200, the bootstrapExtensions entry can land, and the extension falls back to a host-installed kernel there — the behaviour every platform had before bundling. A real kernel drops into the same target later with no change on the Positron side. The build-vsix matrix now carries an explicit `kernel` flag per entry rather than testing for the universal target by name, since two targets now ship without one. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release-packages.yml | 53 +++++++++++++++++--------- CHANGELOG.md | 4 +- ggsql-vscode/CHANGELOG.md | 3 +- ggsql-vscode/CLAUDE.md | 7 ++-- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 19fc171e..50e87fcb 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -606,16 +606,33 @@ jobs: strategy: fail-fast: false matrix: - # win32-arm64 is deliberately absent: no runner builds that kernel yet. - # "universal" carries no kernel and is what users on any other platform - # install, alongside the kernel from a native installer. - target: - - darwin-arm64 - - darwin-x64 - - linux-arm64 - - linux-x64 - - win32-x64 - - universal + # `kernel: false` targets are packaged and published like any other, but + # ship without a kernel and fall back to a host-installed one. + # + # win32-arm64 is published that way because no runner builds that kernel + # yet. It is still published: Positron's bootstrap asks the gallery for + # an asset by exact targetPlatform, and a target that was never + # published answers 403 rather than falling back to the untargeted + # build, which fails Positron's own Windows arm64 build. A kernel-less + # target answers 200, so the entry can land, and gains a kernel later + # with no change on the Positron side. + # + # "universal" answers requests that carry no targetPlatform at all. + include: + - target: darwin-arm64 + kernel: true + - target: darwin-x64 + kernel: true + - target: linux-arm64 + kernel: true + - target: linux-x64 + kernel: true + - target: win32-x64 + kernel: true + - target: win32-arm64 + kernel: false + - target: universal + kernel: false steps: - name: Checkout code @@ -636,7 +653,7 @@ jobs: run: npm ci - name: Download ggsql-jupyter kernel (${{ matrix.target }}) - if: matrix.target != 'universal' + if: matrix.kernel uses: actions/download-artifact@v4 with: name: ggsql-jupyter-${{ matrix.target }} @@ -646,7 +663,7 @@ jobs: # Artifact upload and download do not preserve the executable bit. The # extension repairs it at runtime too, but it has to be right inside the # VSIX for a fresh install to start a session. - if: matrix.target != 'universal' + if: matrix.kernel run: | chmod +x ggsql-vscode/bundled/bin/* ls -l ggsql-vscode/bundled/bin @@ -672,18 +689,19 @@ jobs: working-directory: ggsql-vscode env: TARGET: ${{ matrix.target }} + KERNEL: ${{ matrix.kernel }} VSIX: ${{ steps.package.outputs.vsix }} run: | unzip -l "$VSIX" unzip -p "$VSIX" extension.vsixmanifest \ | grep -o 'TargetPlatform="[^"]*"' || echo 'no TargetPlatform: universal' - if [ "$TARGET" = universal ]; then - if unzip -l "$VSIX" | grep -q 'extension/bundled/'; then - echo "::error::the universal VSIX must not carry a kernel" + if [ "$KERNEL" = true ]; then + if ! unzip -l "$VSIX" | grep -q 'extension/bundled/bin/ggsql-jupyter'; then + echo "::error::the $TARGET VSIX is missing its bundled kernel" exit 1 fi - elif ! unzip -l "$VSIX" | grep -q 'extension/bundled/bin/ggsql-jupyter'; then - echo "::error::the $TARGET VSIX is missing its bundled kernel" + elif unzip -l "$VSIX" | grep -q 'extension/bundled/'; then + echo "::error::the $TARGET VSIX must not carry a kernel" exit 1 fi @@ -712,6 +730,7 @@ jobs: - linux-arm64 - linux-x64 - win32-x64 + - win32-arm64 - universal steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d96cda..67c520ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,8 +41,8 @@ installing the extension is all that is needed to run queries — no separate native install. The per-platform builds (`darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`, `win32-x64`) each carry the same signed kernel - binary the matching installer does, and a kernel-less universal build remains - for any other platform, where the installer is still required. A new + binary the matching installer does. `win32-arm64` and a universal build are + published without a kernel, and still require the native installer. A new `ggsql.kernelStrategy` setting picks between the bundled kernel (the default), a kernel installed on the machine, and a fixed path in `ggsql.kernelPath`; configuring `ggsql.kernelPath` alone continues to mean that path is used. diff --git a/ggsql-vscode/CHANGELOG.md b/ggsql-vscode/CHANGELOG.md index eaa6ab97..0fe10a2b 100644 --- a/ggsql-vscode/CHANGELOG.md +++ b/ggsql-vscode/CHANGELOG.md @@ -5,7 +5,8 @@ - The extension now ships the `ggsql-jupyter` kernel, so installing it is enough to run queries in Positron. `ggsql.kernelStrategy` picks between the bundled kernel (the default), a kernel installed on this machine, and a fixed path in - `ggsql.kernelPath`. + `ggsql.kernelPath`. On Windows arm64 the extension ships without a kernel and + uses one installed on the machine. - Fixed: no ggsql runtime is offered when no kernel can be found, rather than one that fails at session start with `KS-19: Kernel path not found`. diff --git a/ggsql-vscode/CLAUDE.md b/ggsql-vscode/CLAUDE.md index c999ebe1..dab22fdb 100644 --- a/ggsql-vscode/CLAUDE.md +++ b/ggsql-vscode/CLAUDE.md @@ -155,14 +155,15 @@ code --install-extension ggsql-.vsix A local `vsce package` produces the kernel-less VSIX, since `bundled/` only exists in a release build. -**Release builds** live in [`/.github/workflows/release-packages.yml`](../.github/workflows/release-packages.yml), not in a workflow of their own. Its `build-vsix` job runs a matrix of six — the five platform targets plus `universal` — downloading the `ggsql-jupyter-` artifact each platform job uploaded between signing and installer packaging, restoring the executable bit, and running `vsce package --target `. `publish-openvsx` then publishes the packaged file to Open VSX. +**Release builds** live in [`/.github/workflows/release-packages.yml`](../.github/workflows/release-packages.yml), not in a workflow of their own. Its `build-vsix` job runs a matrix of seven, each entry carrying a `kernel` flag. The five `kernel: true` targets download the `ggsql-jupyter-` artifact each platform job uploaded between signing and installer packaging, restore the executable bit, and run `vsce package --target `. `win32-arm64` and `universal` are `kernel: false` and skip the download. `publish-openvsx` then publishes the packaged file to Open VSX. -Four things about that arrangement are deliberate: +Five things about that arrangement are deliberate: - **The VSIX build cannot live in its own workflow.** Actions artifacts are scoped to a single workflow run, and two workflows triggered by the same tag run in parallel, so a separate workflow could not download the kernels. Building in the same run also means the kernel and the extension always come from one commit. - **The executable bit has to be restored after download.** Artifact upload and download drop it. It does survive `vsce package` into the VSIX itself, so restoring it once in CI is enough; `ensureExecutable()` in `manager.ts` is belt-and-braces for an install that loses it. - **The published artefact is the packaged `.vsix`, with no `target` passed to the publish action.** Open VSX reads the platform from the `TargetPlatform` attribute that `vsce package --target` writes into `extension.vsixmanifest`, and defaults to `universal` when it is absent; `ovsx` discards a target option when handed an already-packaged vsix. -- **`win32-arm64` is not built.** No runner produces that kernel yet. Positron's bootstrap appends `?targetPlatform=` and gets an HTTP 403 rather than the universal build for a target that was never published, so the universal VSIX is not a fallback for it — see posit-dev/positron#14954. +- **`win32-arm64` is published without a kernel.** No runner produces that kernel yet, but the target is published anyway. Positron's bootstrap appends `?targetPlatform=` to the gallery asset URL and a target that was never published answers HTTP 403, not the universal build — so an absent `win32-arm64` fails Positron's own Windows arm64 build rather than degrading to universal. Publishing the target with no kernel answers 200, and the extension falls back to a host-installed kernel there. It gains a real kernel later with no change on the Positron side. See posit-dev/positron#14954. +- **`universal` is not a fallback for any target.** The gallery matches `targetPlatform` exactly, in both directions: a universal build does not answer a targeted request, and targeted builds do not answer an untargeted one. `universal` exists for clients that ask without a target at all. Watch mode for development: `npm run watch` (runs esbuild + tsc in parallel).