A VS Code extension for managing Crestron systems running PepperDash Essentials.
- Track and update package versions against live GitHub releases.
- Deploy files to Crestron processors and touch panels over SSH.
- Build release bundles.
- All from one sidebar panel.
Ships with the public PepperDash org configured out of the box. Private orgs and any GitHub Enterprise sources are added manually via Setup → Package sources — once added, they persist in your VS Code user settings across restarts and updates.
🎥 Watch the demo video — a quick walkthrough of the extension in action.
Contents
Quick Start
- Install the extension from the Marketplace — open the Extensions view (
Cmd+Shift+X / Ctrl+Shift+X), search PepperDash Toolkit, click Install.
- Open a workspace containing a
*configurationFile*.json (e.g. a PepperDash super-project folder). The extension activates automatically.
- Click the PepperDash Toolkit icon in the Activity Bar to open its sidebar.
- From the sidebar's welcome screen, click Open System Config Folder and pick your system's folder.
- Picks up any
*configurationFile*.json (opens the Versions tab) found in the folder or its subfolders.
- Picks up any
deploy.json (opens the Deploy / Bundle tabs) found in the folder or its subfolders.
- The folder picker recognizes a super-project's per-system layout.
- The panel opens beside the editor with four tabs: Setup, Versions, Deploy (labeled System Deployments), and Bundle.
- Head to Setup first — sources, directories, and solution identity there are used by the other three tabs.
The first time you need authenticated GitHub access, you'll be prompted to sign in — see Requirements for details.
Upgrading an existing install? Earlier releases used the essentialsVersions.* settings/storage namespace, from before the PepperDash Toolkit rename.
- Upgrading in place migrates your sources, saved directories, stored PATs, and Personal Address Book entries (including their passwords) to the new
pepperdash.toolkit.* / pepperdashToolkit.* namespace automatically and silently the first time this version activates — no action needed.
- The old
essentialsVersions.* settings keys can be removed from settings.json once you've confirmed the new ones carried over.
essentialsVersions.ghPath and essentialsVersions.ghTimeoutMs are gone outright, not migrated — see pepperdash.toolkit.requestTimeoutMs below.
Setup
The Setup tab has two cards: Extension settings (personal, saved automatically) and Project setup (shared, written to pepperdash.toolkit.json). Configure this tab before using Versions, Deploy, or Bundle — it supplies the sources, directories, and solution identity they all rely on.
Package sources
Personal VS Code settings, not part of the shared pepperdash.toolkit.json. Manage the GitHub sources used when searching for packages and see live authentication status per host.
- Add source / edit / delete — each source has a label, host, org, and kind (
public, private, or onprem).
- Authentication status per host:
github.com — Sign in with GitHub opens the VS Code account flow; sign out via the VS Code Accounts menu.
- GitHub Enterprise hosts — Set personal access token prompts for a PAT (stored in secret storage); Clear token removes it.
- Public-only hosts show a Public access only badge with an option to sign in for private-repo access.
- Re-check — re-runs the auth check for a host.
- Local plugin index — build/refresh an offline index of each source's plugin repos, used by Versions's Add Package search:
- Click the Build/Refresh icon on a source card, or Update all indexes in the section header.
- This is the only part of Setup that talks to GitHub, and it's subject to GitHub's 10-requests/minute code-search rate limit (shared across every source in one build, so a build that would exceed it skips the remaining sources rather than silently under-indexing them — run it again to pick up where it left off).
Diagnostics
- Open log shows the extension's output channel (every GitHub API call, deploy/bundle progress, and errors) — useful when reporting an issue.
Project setup
Edits pepperdash.toolkit.json, a small file committed at the workspace root that holds solution-level defaults shared by everyone working in the same super-project.
- Directories — relative folder names for
systemConfigurations (per-system config folders), dependencies (restore target for versions-object artifacts), artifacts (Bundle output root), and sourceFiles (destination for the Versions tab's Source Files download). Each field has a Browse button and an info icon with more detail on hover.
- Solution identity — default
Solution ID, Solution name, and Solution version, used as fallbacks wherever the Bundle tab needs them; any system can still override them individually.
- Unlike the Versions/Deploy/Bundle files,
pepperdash.toolkit.json is written directly to disk (not through an editor you save yourself) — Save commits your changes immediately, and the tab shows an Unsaved changes / Saved indicator while you edit.
- Because it's a normal tracked file, review and undo work the same way as anywhere else in the repo:
git diff / git checkout.
Versions
The Versions tab reads the versions block of your *configurationFile*.json and groups entries into four sections: Essentials (core framework), Packages (plugins), User Interfaces, and Touchpanel Wrapper.
Each card shows the entry's Name (click to rename inline), Package ID, current Version with a badge for the latest GitHub release, and a clickable Repo link.
Check for updates:
- Click Check on a single card, or Check all in the toolbar to fetch latest releases for every entry in parallel.
Apply an update:
- Click Update →
<tag> on a card, or Update all in the toolbar to apply every available update in one edit.
- The JSON file goes dirty in the editor — save with Ctrl+S / Cmd+S to persist. Nothing writes to disk until you save.
Add a new package or UI entry:
- Click Add package / Add UI.
- Choose Search or Paste URL (any GitHub repo URL).
Search mode:
- Check every configured source you want to search — they're listed in priority order (PepperDash's own orgs first, then any other sources you've added) and run in parallel.
- Type a query and press Enter or click Search.
- Results from every checked source are merged into one deduped list; a repo that shows up under more than one source displays a small badge per source.
- If a checked source actually fails (auth/network), it's called out just below the query field — a source simply having no matches is not treated as an error.
- Your checked-source selection is remembered (per user, across workspaces) so you don't have to re-check them every time.
- Checking a source is only required for the GitHub half of a search — the local plugin index still searches with nothing checked at all.
Search by device/room type (Add package only):
- The dialog scans the system's
*configurationFile*.json for every distinct devices[].type / rooms[].type value (e.g. sonyBravia, qscDsp) and shows them as clickable chips above the query field — click one to search for a matching plugin package instead of retyping the type by hand.
- Search all types automates this across every scanned type at once, merging results into one combined list instead of just the last type's.
- Local-first: every type checks the (free, unlimited) local plugin index first, and only a type the index has nothing for falls back to a real GitHub search. A well-built index typically answers most or all of a config's types, so this usually means little or no GitHub traffic at all.
- The GitHub fallback that does run is sequential and rate-limit-budgeted — it stops issuing requests, rather than failing, if a run would approach GitHub's repo-search rate limit. A warning names which types were affected and that nothing was found for them this run.
- One consequence of "fallback only": a brand-new plugin published after the index was last built won't be found for a type if some other, already-indexed repo happens to register a similarly-named type — the index answering something stops the GitHub fallback from ever running for that type. Rebuilding the index (Setup → Package sources) picks up the new plugin.
- A type that was actually fully checked (local index, and GitHub too if it ran) and still matched nothing lands in its own Not found list, distinct from the rate-limit skip warning — "we looked and found nothing" isn't the same claim as "we didn't get to look," and a budget-skipped type is never shown as not-found.
- Not shown when adding a UI entry, since a device/room type maps to a plugin package, not a UI bundle.
Plugin index matches:
- Once a source is indexed (see Package sources), adding a package — typing in the Query field or clicking a device/room type chip — also checks the index locally with no further GitHub request.
- Any repo it finds shows up under Plugin index matches as one entry per plugin, listing every type it registers (a plugin covering several device models, e.g. multiple Sony Bravia TVs, is one row with all of its types badged, not a duplicate row per type).
- A query that only matches a repo's name rather than any of its registered types falls back to a flat By repo name list instead.
- A source that hasn't been indexed yet is called out in the dialog, with a link back to Setup, so a "no matches" result there is never mistaken for a confirmed absence.
Set the Essentials / Touchpanel Wrapper core version:
- Click Essentials or Touchpanel Wrapper in the Core section header to pick a release, including pre-releases.
Compare against a live processor:
- Click Fetch from processor in the toolbar to connect to a Crestron processor and diff its installed package manifest against the file.
- Changes are grouped and badged New / Changed / Unchanged.
- Click Apply to update the JSON in one edit.
Download source archives:
- Click Source Files in the toolbar to download every tracked entry's GitHub Source code (zip) (the auto-generated
zipball, not a release asset) for its pinned version.
- Files are named
<repo>-<version>-source.zip and land in the folder configured on the Setup tab's Source files directory field — or a folder picker on demand if it isn't set.
- Entries with no
repoUrl (common for userInterfaces) or no pinned version are skipped and noted in the log rather than treated as errors; a missing tag/release warns and the rest of the batch continues.
- Progress streams into a per-entry log the same way the Deploy tab does.
Restore packages:
- Click Restore in the toolbar to download every tracked entry's pinned-version release assets into the folder configured on the Setup tab's Dependencies directory field (or a folder picker on demand if it isn't set) — the same target every time, no re-picking a folder per run.
- Each card also has its own Restore this package icon button (the archive icon, next to Update/Collapse) to re-download just that one entry instead of the whole set — e.g. after bumping a single plugin's version and wanting its files without a full restore.
- Either way, if the output folder already has file(s) belonging to that same package but a different version, you're asked to Delete and Download (removes just those stale files, then downloads the pinned version) or Keep Existing (leaves them alone, downloads nothing) — never a silent overwrite or a silently-orphaned old copy sitting next to the new one.
Reorder entries:
- Drag a card by its handle within the Packages or User Interfaces section to change its position — order is otherwise just insertion order and has no effect on behavior, but a consistent order can make a long list easier to scan.
- Not available across sections (Essentials/Touchpanel Wrapper are single entries, not arrays).
Other toolbar actions: Open / Save and Reload (re-read from disk). GitHub sources and the output log live on the Setup tab.
All writes go through WorkspaceEdit — the JSON file goes dirty in the editor and you save explicitly. No surprise disk writes.
Opening a config file with no versions block (predates version tracking): the extension asks whether to Use this file or Create packages.json.
- Use this file doesn't add an empty
versions object up front — it's written automatically the first time you add an entry, and the tab shows a hint until then.
- Dismissing the prompt leaves the file untouched and asks again next time.
Opening a system folder missing a *configurationFile*.json or deploy.json: a target is required for both the Versions and Deploy tabs, so neither keeps showing a stale, previously-opened system's data. Each missing file shows a modal prompt to Create packages.json / Create deploy.json; declining cancels opening the folder.
Deploy
The Deploy tab (labeled System Deployments in the panel) handles SSH-based file deployment, backed by a per-workspace deploy.json (separate from configurationFile.json).
- Project root — every mapping's local-root path (and the Bundle tab's output folder) resolves against a super-project root.
- This comes from the Setup tab: once you've saved
pepperdash.toolkit.json, the workspace root itself is the project root, shown read-only above the device list (with a note on where it came from).
- Systems that haven't gone through Setup yet fall back to a legacy
projectRoot value stored directly in deploy.json, or auto-detection via a *.workspace/*.code-workspace marker file.
- Add a device — click Add device, choose Processor or Touch Panel.
- Click the device name to rename it inline; collapse the card body with the chevron to keep the panel tidy. Collapsing hides credentials and file mappings but keeps the deploy bar visible, so you can set several devices up, collapse them all, and fire each one from a short list without expanding anything.
- Drag a device card by its handle to reorder the device list.
- On a touch panel card, click the clone icon to create a copy directly below it with the same credentials and file mappings, then adjust the differing path(s) — 1Password vault/item UUIDs and Personal Address Book selections carry over fully; manual (session-only) passwords are never stored and must be re-entered. Not yet available for processors.
- Set credentials — three sources:
- 1Password (Vault UUID + Item UUID; host IP read from the item's saved URLs; requires the
op CLI).
- Personal Address Book — a saved connection (host, port, username, password) picked from a per-user, per-machine list, for environments where 1Password isn't available.
- Click Manage… to open the dialog: add/edit/delete entries, organize them into groups (a built-in Default group can't be renamed or deleted), filter/sort, and select one to fill the device's credentials.
- The password is stored in your OS-native credential store (Windows Credential Manager, macOS Keychain, or libsecret/kwallet on Linux) via VS Code's secret storage — never written to
deploy.json or any committed file.
- Only a stable
connectionId (derived from host + username + password, so it resolves to the same entry across teammates' machines) is saved in deploy.json; each person still needs the matching entry saved locally.
- Manual (session only) — prompted each time, nothing stored.
- The SSH Port field defaults to
22 and applies to every source; it is saved in deploy.json as credential.port (omitted at 22). Entering host:port in the manual Host field — or a port in the 1Password item URL — is also honored, with the explicit SSH Port field taking precedence.
- Test connection — click Test connection to verify SSH access before deploying; a "Connected" badge confirms success.
- Configure file mappings — each mapping has a pattern (glob), a local root folder, and a remote directory.
.cpz/.lpz patterns auto-expand to include supporting files (config JSON, plugins, IR files, mobile control zips) with correct remote paths for the chosen program slot.
- Click a mapping row to edit it, or drag rows by their handle to reorder them.
- Each supporting file has its own checkbox (checked by default); a mapping with supporting files also gets a checkbox for its own program file, so you can deploy just one file by unchecking the rest.
- A Select all toggle in the File Mappings header checks or clears every one of those checkboxes across the whole device at once.
- If a pattern glob matches more than one archive on disk, deploying prompts you to pick which one instead of guessing or deploying all of them.
- Deploy:
- Each program mapping row ends in a Deploy button and the commands that qualify it, boxed together, followed by edit and remove. Deploy on its own uploads exactly whatever's checked (the program file and/or supporting files) in one connection and nothing else.
- Beside it are checkboxes labelled with the console command each one appends to that deploy —
progload (reload the program) and progres (restart it without a full reload). Hovering shows the full command including the row's slot. They're mutually exclusive: checking one clears the other, and clicking the checked one again clears it back to upload-only.
progload always includes the program file — if it isn't checked, it's checked for you and noted in the log, since reloading the program needs it present. progres just respects whatever's checked, same as a plain Deploy.
- Touch panel rows offer
projectload and .ch5z HTML mappings offer csprojectload in the same slot. Both follow the same always-include-the-project-file rule, and neither has a progres equivalent, so those rows show a single command.
- The card footer is the device-wide version, same shape: the blue Upload All Mapped Files button (relabelled Upload All & Load All Programs or Upload All & Restart All Programs when
progload/progres is checked) boxed with its Deploy Actions group, uploads whatever's checked across every mapping on a processor (a touch panel has no per-mapping checkboxes, so every mapping's file is included). Processors get progload (sent as progload -p:all, auto-selecting and warning about any unchecked program file) and progres (progres -p:all); touch panels get projectload. The footer's group is the only one it consults — a row's own command applies solely to that row's Deploy button.
- With nothing checked, the footer button uploads and stops there. Its tooltip says which of the three it will do in every state, including that one.
Bundle
The Bundle tab builds release artifacts for a system into the super-project root's output folder (set on the Deploy tab).
Four artifact types, each independently selectable:
| Type |
Contents |
| System Compiled Bundle |
Compiled programs, plugins, configs, and touchpanel files |
| System Source Archive |
Compiled bundle plus *_compiled.zip and touchpanel source companions, plus the Setup tab's Source files folder (fetched first if empty), included at the archive root under that folder's own name |
| Asset |
Flat zip of the Essentials program's user files (config, plugins, IR, mobile control app) |
| Essentials with embedded Asset |
Copy of the Essentials .cpz with the asset zip injected |
- Solution — Solution ID and name; auto-detected from
packages.json at the project root when present, or entered manually (required for System bundles).
- Version — a
X.Y.Z version string plus an optional suffix (e.g. RC1).
- Output folder — relative to the super-project root; artifacts land in
<output>/bundles/, <output>/assets/, and <output>/cpz/.
- Preview — shows the exact file tree each selected artifact will contain before building.
- Build bundles — runs the bundle, streaming progress (staging, zipping, done/error) to the log below.
Reference
Requirements
- VS Code
^1.90.0
- GitHub authentication — no
gh CLI required:
github.com sources use VS Code's built-in GitHub sign-in (prompted the first time you need authenticated access, or triggered manually from Setup → Package sources).
- GitHub Enterprise (on-prem) sources use a personal access token, stored in VS Code's encrypted secret storage via Setup → Package sources or the PepperDash Toolkit: Set GHE PAT command.
- 1Password CLI (
op) (optional) — required only if you use 1Password as your deploy credential source.
Commands
Available from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P), searching PepperDash Toolkit. Most day-to-day actions have a UI equivalent; these are useful when a panel isn't open yet or for keybinding/task automation.
| Command |
Title |
Notes |
pepperdashToolkit.open |
Open Versions Panel |
With no file already open, scans the workspace for *configurationFile*.json; prompts a picker if it finds more than one, or falls back to New Versions File if it finds none. |
pepperdashToolkit.openSystemFolder |
Open System Config Folder |
Same picker as the sidebar welcome screen — see Quick Start. |
pepperdashToolkit.new |
New Versions File |
Opens an unsaved, in-memory versions doc in the panel — use Save to write it out as your *configurationFile*.json. |
pepperdashToolkit.openFile |
Open Versions File |
Opens an existing one via file picker. |
pepperdashToolkit.newDeployFile |
New Deploy File |
Prompts for a save location, then writes a default deploy.json there immediately. |
pepperdashToolkit.openDeployFile |
Open Deploy File |
Opens an existing one via file picker. |
pepperdashToolkit.openSetup |
Open Setup |
Jumps straight to the Setup tab. |
pepperdashToolkit.manageSources |
Manage GitHub Sources |
Jumps to Setup → Package sources. |
pepperdashToolkit.setGhePat |
Set GHE PAT |
Prompts for a personal access token for a GitHub Enterprise host. |
pepperdashToolkit.clearGhePat |
Clear GHE PAT |
Removes a stored GHE token. |
pepperdashToolkit.showLog |
Show Output Log |
Same as Setup → Diagnostics → Open log. |
pepperdashToolkit.resetVersionsPromptChoice |
Reset No-Versions Prompt Choice |
Clears the "don't ask again" choice for the no-versions-block prompt — re-run it against a file you previously dismissed once and for all. |
Deprecated
essentialsVersions.* settings namespace — replaced by pepperdash.toolkit.* / pepperdashToolkit.*. Migrated automatically on upgrade — see the Upgrading an existing install note above.
essentialsVersions.ghPath / essentialsVersions.ghTimeoutMs — removed outright, not migrated. The gh CLI dependency they configured is gone; GitHub access is Octokit + vscode.authentication / a stored PAT. pepperdash.toolkit.requestTimeoutMs replaces the timeout.
deploy.json's projectRoot field — superseded by the Setup tab's pepperdash.toolkit.json, which now owns project-root resolution. Still read as a fallback for systems that haven't gone through Setup yet (see Deploy, step 1), but new setups should use Setup instead.
Installation from a VSIX
For pre-release or local builds instead of the Marketplace:
- Download the VSIX from the Releases page.
- Open the Extensions view, click the
… menu → Install from VSIX… → select the downloaded file.
# or from the terminal
code --install-extension pepperdash-toolkit-<version>.vsix
To update a VSIX install, install the newer file over the existing one — settings are preserved.
Settings
| Setting |
Default |
Description |
pepperdash.toolkit.sources |
1 PepperDash default |
Array of { label, host, org, kind } sources available when adding entries. Managed via Setup → Package sources or VS Code settings directly; stored at the User (Global) scope, so entries you add persist across VS Code restarts and updates. |
pepperdash.toolkit.requestTimeoutMs |
15000 |
Timeout (ms) for individual GitHub API requests. |
pepperdash.toolkit.deployTimeoutMs |
30000 |
Timeout (ms) for SSH connections during deployment. |
pepperdash.toolkit.deploySshCompatMode |
auto |
SSH algorithm profile for deploy connections. auto tries the standard profile and retries once with a minimal profile on VPN/MTU-style handshake failures; standard and minimal pin one profile with no retry (minimal is useful when VS Code runs in a VM behind a host-level VPN, e.g. Parallels on macOS). |
pepperdash.toolkit.deploySftpConcurrency |
4 |
Number of SFTP write requests kept in flight (unacknowledged) at once when uploading a file. Lower it (e.g. 1) if uploads drop mid-transfer on an unreliable connection. |
Default sources:
| Label |
Host |
Org |
Kind |
| PepperDash |
github.com |
pepperdash |
public |
For a GitHub Enterprise source, use the GHE hostname and "kind": "onprem".
License
MIT
| |