Development Guide
Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Node.js | v20+ (v22 recommended) | |
| Go | v1.22+ | CGO must be enabled |
| C compiler | any | Required by CGO — gcc on Linux, Xcode CLT on macOS, MinGW on Windows |
| Trivy CLI | optional | For image vulnerability scanning in Security Hub |
Install Trivy (macOS):
brew install trivy
Setup
# Install Node dependencies (also runs postinstall which rebuilds node-pty)
npm install
# Build the Go sidecar — required before first dev run
cd go-core && go build ./cmd/podscape-core/ && cd ..
Development
npm run dev # Start Electron + Vite dev server with hot reload
Note: If
window.kubectl.*methods appear asundefinedat runtime, the preload build is stale. Restartnpm run dev.
Running Tests
# Frontend (Vitest)
npm run test
npm run test:watch # watch mode
# Go sidecar (handlers, rbac, helm, portforward, prometheus, ownerchain)
cd go-core && go test ./...
Building
The full build compiles the Go sidecar first, then runs electron-vite:
npm run build # Go sidecar + renderer + main + preload
Individual steps:
cd go-core && go build ./cmd/podscape-core/ # sidecar binary only
cd go-core && go build ./cmd/podscape-mcp/ # MCP server binary only
npx electron-vite build # Electron assets only
Distribution
Packages are produced by electron-builder. Artifacts land in dist/.
npm run build:mac # macOS — .dmg + .zip (arm64 and x64 separately)
npm run build:win # Windows — NSIS installer (.exe)
npm run build:linux # Linux — AppImage + .deb
Icon generation
Icons must be generated before packaging if they don’t already exist:
npm run icon:icns # macOS .icns from resources/icon.png
npm run icon:ico # Windows .ico from resources/icon.png
Requirements: imagemagick (Linux/macOS) or the scripts handle it via sips on macOS.
CI / Release
Releases are triggered by pushing a v* git tag. The workflow (.github/workflows/release.yml) runs three parallel jobs:
| Job | Runner | Output |
|---|---|---|
release-mac (arm64) | macos-latest | .dmg + .zip for Apple Silicon |
release-mac (x64) | macos-13 | .dmg + .zip for Intel |
release-win | windows-latest | .exe NSIS installer |
release-linux | ubuntu-latest | .AppImage + .deb |
Each job also uploads a checksums-<platform>.txt file to the GitHub release so users can verify downloads with SHA256.
# Create and push a release tag
git tag v2.3.0
git push origin v2.3.0
Required GitHub secret: GH_TOKEN with contents: write permission on the repository.
Settings Schema
App settings are stored in ~/.podscape/settings.json. The file is created automatically on first write. All fields are optional — missing keys fall back to the defaults shown below.
{
"kubeconfigPath": "",
"shellPath": "",
"theme": "dark",
"prodContexts": [],
"prometheusUrls": {}
}
| Field | Type | Default | Description |
|---|---|---|---|
kubeconfigPath | string | "" | Absolute path to a kubeconfig file. Empty string means use $KUBECONFIG env var, then ~/.kube/config. |
shellPath | string | "" | Absolute path to the shell binary used for PTY terminals (e.g. /bin/zsh). Empty string means auto-detect from the user’s environment. |
theme | "dark" \| "light" \| "" | "dark" | UI colour theme. Empty string defers to the last-used or OS preference. |
prodContexts | string[] | [] | List of kubeconfig context names to treat as production. Any matching context activates the red border + banner in the UI. |
prometheusUrls | Record<string, string> | {} | Per-context manual Prometheus base URLs (e.g. { "my-ctx": "https://prometheus.example.com" }). Empty string for a context means auto-discover via Kubernetes service proxy. |
The settings file is read and written by src/main/settings/settings_storage.ts (getSettings / saveSettings). IPC handlers in src/main/ipc/settings.ts expose settings:get and settings:set channels to the renderer via window.settings.
Auto-Updater
Podscape uses electron-updater to deliver in-app updates. The updater is configured in src/main/system/updater.ts and only activates in production builds (is.dev guard — no update checks during npm run dev).
Update source: electron-updater reads the publish configuration from package.json (GitHub releases). It fetches latest.yml / latest-mac.yml from the GitHub release assets to compare the current version against the latest published release.
Behaviour:
autoDownloadis set tofalse— updates are downloaded only when the user explicitly confirms.autoInstallOnAppQuitistrue— a downloaded update is installed automatically the next time the app quits.- An initial check fires 5 seconds after launch (delayed to avoid racing with sidecar startup). The timer is cancelled on
before-quitto prevent a network request into a partially torn-down process. - Events fired before the renderer window is ready are queued (up to 20) and flushed once
did-finish-loadfires, so no update notification is lost on a fast machine.
IPC channels:
| Channel | Direction | Description |
|---|---|---|
updater:check | Renderer → Main (handle) | Trigger an immediate update check |
updater:download | Renderer → Main (handle) | Start downloading the available update |
updater:install | Renderer → Main (handle) | Quit and install the downloaded update |
updater:checking | Main → Renderer (send) | Update check started |
updater:available | Main → Renderer (send) | New version found; payload is the UpdateInfo object |
updater:not-available | Main → Renderer (send) | Already on the latest version |
updater:progress | Main → Renderer (send) | Download progress; payload is a ProgressInfo object |
updater:downloaded | Main → Renderer (send) | Download complete; payload is the UpdateDownloadedEvent object |
updater:error | Main → Renderer (send) | Error during check or download; payload is the error message string |
The UpdateBanner component in src/renderer/components/core/UpdateBanner.tsx listens for these events and renders an in-app notification bar when an update is available or has been downloaded.
Testing updates locally: electron-updater skips the update check entirely when is.dev is true, so local testing requires a production build. Point autoUpdater.updateConfigPath to a local dev-app-update.yml file or use autoUpdater.forceDevUpdateConfig = true with a matching release on a local file server.
Known Build Notes
node-ptynative rebuild:npm installrunselectron-builder install-app-depsviapostinstall, which rebuildsnode-ptyfor the target Electron version. On macOS the prebuiltspawn-helperbinaries may lack execute permission — thepostinstallscript applieschmod +xautomatically.- CGO on Windows: MinGW must be on
PATHbefore building the Go sidecar. The CI workflow adds it via$env:PATH. - Sidecar location: In dev, the binary is expected at
go-core/podscape-core. In production, electron-builder copies it toresources/bin/podscape-coreviaextraResources.