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.
From editors/vscode:
npm install
npm run check
npm run test
npm run compilenpm 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.
Run the root package SplitScript VSIX task, or run this command here:
npm run package:vsixThe 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.
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.0The 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.
The publish job uses GitHub OIDC and VSCE's --azure-credential authentication.
No PAT is stored in GitHub. Set up the following once:
-
Create a dedicated Microsoft Entra application/service principal for SplitScript publishing. Record its client ID and tenant ID.
-
Configure its federated credential with issuer
https://token.actions.githubusercontent.com, audienceapi://AzureADTokenExchange, and subjectrepo: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 organizationLiveSplit, organization ID8258479, repositorySplitScript, repository ID1318703401, entity type Environment, and environmentvscode-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 withgh api repos/LiveSplit/SplitScript/actions/oidc/customization/sub; use that prefix followed by:environment:vscode-marketplace. -
Create the GitHub environment
vscode-marketplace, restrict it tomaster(the publishing workflow runs on the default branch), and add environment variablesMARKETPLACE_CLIENT_IDandMARKETPLACE_TENANT_ID. Required reviewers are optional; leave them unset for automatic uploads. -
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
masterwith environmentvscode-marketplace,id-token: write, andazure/loginusing the environment variables above andallow-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 tsvPrint only the non-secret profile ID; do not log access tokens or publish an extension during this setup check. Remove the temporary workflow afterward.
-
Under the existing
LiveSplitMarketplace 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.
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.
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.
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-hostThe 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.