Skip to content

Latest commit

 

History

History
185 lines (151 loc) · 9.46 KB

File metadata and controls

185 lines (151 loc) · 9.46 KB

Developing the SplitScript VS Code extension

The extension is a thin TypeScript host around the same Rust compiler used by native splitc and splitls. This document covers repository development; the packaged README is written for extension users.

Build and check

From editors/vscode:

npm install
npm run check
npm run test
npm run compile

npm run compile builds the release-profile wasm32-unknown-unknown compiler adapter, compiles the TypeScript extension and its language/build workers, and copies the compiler module into the ignored dist package directory. Native splitc and splitls builds remain independent from the repository root.

When the complete repository is open in VS Code, Run SplitScript Extension builds both halves before opening an Extension Development Host.

Package a VSIX

Run the root package SplitScript VSIX task, or run this command here:

npm run package:vsix

The production build runs automatically and writes splitscript-<version>.vsix in this directory. Local packages use the checked-in manifest version and VSCE's pre-release marker. Published versions are generated by CI, so releasing does not require editing package.json or the lockfile. The Marketplace cannot reuse a version number, including moving that version between pre-release and stable channels. It uses the Rust max-opt profile for the embedded compiler: full LTO, one code generation unit, aborting panics, and symbol stripping. The artifact is copied from target/wasm32-unknown-unknown/max-opt. Normal extension development builds continue to use release. These Rust profiles do not change which SplitScript debug/release builds the extension can produce.

CI runs complete verification and native bridge builds on Windows x64, Linux x64/ARM64, and macOS Intel/Apple Silicon runners. A separate assembly job downloads those five .node files, runs the production extension build, verifies that every bridge is present, packages the VSIX with the selected version and channel, and uploads the VSIX and its checksum/source receipt as a workflow artifact. This assembly also runs for pull requests, so packaging failures are caught before a merge. On master, the GitHub release job moves the latest tag to the verified commit and replaces the assets on the existing Latest SplitScript preview release. A version-tag build creates a full GitHub release containing the versioned VSIX and the same five native CLI/LSP archives.

Automatic publishing

Every successful master build publishes a Marketplace pre-release. Its version is <major>.<next minor>.<Check workflow run number>, based on the highest numeric vX.Y.Z release tag. Before the first full release, this produces 0.1.<run number>. After v0.2.0, it produces 0.3.<run number>. Run numbers may have gaps because pull requests and tag builds use the same counter. Rerunning a workflow keeps its run number, and distribution metadata is frozen before any native builds.

Push a vX.Y.Z tag to publish a full release, for example:

git tag v0.2.0
git push upstream v0.2.0

The tag supplies the packaged version; the checked-in extension manifest does not need to match it. Full releases have no odd/even minor-version restriction. Use a version that has not already been published in either Marketplace channel. SemVer suffixes such as -beta are not accepted by the Marketplace; branch/tag selection supplies the channel instead. Creating or editing a GitHub release manually is not the trigger. CI creates the full GitHub release after the tagged commit passes verification.

marketplace.yml runs after the entire Check workflow succeeds. It downloads that run's audited VSIX, checks its receipt, source commit/ref, embedded version, channel, and SHA-256, then publishes those exact bytes without rebuilding. Pull requests, forks, and other branches do not publish. Superseded master commits and already-published versions are skipped. A failed upload can be retried by rerunning the Marketplace workflow; an existing version is never replaced. Upload success can precede the Marketplace's own validation.

One-time publishing identity setup

The publish job uses GitHub OIDC and VSCE's --azure-credential authentication. No PAT is stored in GitHub. Set up the following once:

  1. Create a dedicated Microsoft Entra application/service principal for SplitScript publishing. Record its client ID and tenant ID.

  2. Configure its federated credential with issuer https://token.actions.githubusercontent.com, audience api://AzureADTokenExchange, and subject repo:LiveSplit@8258479/SplitScript@1318703401:environment:vscode-marketplace. This repository uses GitHub's immutable subject format, which includes its owner and repository IDs. In Entra's GitHub Actions scenario, enter organization LiveSplit, organization ID 8258479, repository SplitScript, repository ID 1318703401, entity type Environment, and environment vscode-marketplace. Do not use the older name-only subject. Before setting up a different repository or after a rename/transfer, check its actual subject prefix with gh api repos/LiveSplit/SplitScript/actions/oidc/customization/sub; use that prefix followed by :environment:vscode-marketplace.

  3. Create the GitHub environment vscode-marketplace, restrict it to master (the publishing workflow runs on the default branch), and add environment variables MARKETPLACE_CLIENT_ID and MARKETPLACE_TENANT_ID. Required reviewers are optional; leave them unset for automatic uploads.

  4. Authenticate as the publishing app, not its human owner, and retrieve its Marketplace User ID with Microsoft's Profile API. For secretless setup, use a temporary manual GitHub workflow on master with environment vscode-marketplace, id-token: write, and azure/login using the environment variables above and allow-no-subscriptions: true. After login, run:

    az rest --url https://app.vssps.visualstudio.com/_apis/profile/profiles/me --resource 499b84ac-1321-427f-aa17-267ca6975798 --query id --output tsv

    Print only the non-secret profile ID; do not log access tokens or publish an extension during this setup check. Remove the temporary workflow afterward.

  5. Under the existing LiveSplit Marketplace publisher's Members tab, add the returned User ID with the Contributor role. Use the Profile API's ID, not the Entra application/client ID or either Entra Object ID.

The workflow uses azure/login with allow-no-subscriptions: true; publishing does not require provisioning application hosting or an Azure subscription. See Microsoft's Marketplace identity setup and GitHub OIDC authentication for the account-side configuration. See GitHub's immutable subject format for why the numeric IDs must match as well as the names.

Native process bridges

For a local build, build-native.mjs builds the bridge for the current supported host. CI supplies a directory of prebuilt platform folders through SPLITSCRIPT_NATIVE_ARTIFACTS; the shared native-platform manifest makes a missing supported artifact fail the build rather than silently producing a partial VSIX. SPLITSCRIPT_REQUIRED_NATIVE_PLATFORMS can narrow that manifest for a custom assembly. The Windows and Linux jobs probe a spawned fixture end to end. GitHub-hosted macOS runners cannot provide interactive task_for_pid authorization, so the macOS jobs probe discovery, modules, mapped ranges, and Mach memory reads against the current Node process instead. This keeps native behavior covered without pretending that CI can grant permission to inspect another process.

Worker architecture

The language client gives the language server its own worker and Wasm instance. A separate build worker owns debug-watch and release compilation. Compilation uses immutable source snapshots tagged with the exact VS Code document revision and writes generated bytes through workspace.fs; it never discovers or spawns a native splitc executable.

The manifest provides desktop and browser entries. The browser entry uses vscode-languageclient/browser and dedicated browser workers for compilation and LSP traffic. Extension, workspace, and generated files are addressed with VS Code URIs so virtual workspaces do not require native filesystem paths.

Browser-host tests

npm run test:web-host launches the bundled browser entry headlessly in a real Chromium VS Code web host with a virtual workspace. It verifies language-server startup and restart, hover, release compilation, debug watch, virtual-file writes, and rebuilding after a save. The first run downloads the pinned VS Code web test build into the ignored .vscode-test-web cache.

To inspect the same environment interactively:

npm run compile
npm run open:web-host

The browser remains open until it is closed or the command is stopped. Its test workspace uses an in-memory virtual filesystem, so edits there do not modify the checked-in test-workspace files. Run SplitScript Web Extension is the corresponding checked-in launch configuration.