- one version: package.json's version is the desktop app's too (desktopVersion removed); tools/desktop-version.ts
keeps the plugin manifests and the app's copies equal, desktop-release publish refuses another version, release
order app first then npm publish; the unpublished desktop 0.1.0 candidate is noted in the docs and CHANGELOG
- storebound desktop installs (per user, no admin: macOS DMG -> /Applications or ~/Applications, Windows NSIS /S,
Linux AppImage + .desktop with the storebound:// handler), updates an older app, notes a newer one (downgrade only
with --force), asks once ([Y/n], --yes, exit 3 without a terminal), opens on the folder; --dry / --json / --download;
the install steps are pure plans (cli/lib/desktop-install.ts); the version's own manifest dl/<version>/latest.json
- credentials: one store, the CLI's credential profiles in ~/.storebound/credentials; the desktop writes and reads
them (profiles.rs, files 0600), moves old keychain accounts into profiles on first start, shows profiles the CLI
made; precedence env > named profile > project file > default profile; config `account`, "account" in the
project's credentials.json; storebound accounts list | import (dedup by key id / service account e-mail, key files
copied 0600, project file keeps keystore and review contact, backup, --dry, never prints values) | use
- app folders: one list ~/.storebound/projects.json shared by the desktop (registry.rs), storebound desktop,
apps folders | add | remove, ws init and ws without a workspace file
- desktop: notice when a folder pins another storebound version; storebound-desktop --version
- tests: version drift, desktop decisions and per-OS plans, credential precedence and import, registry (TS + Rust),
keychain migration and profile round trip (Rust), boot check with old keychain state and the new shared state
- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and
"Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot,
config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it
- tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded
(replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci
- package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20
- bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help,
init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/
- install writes npx MCP commands when run with Node; bin/storebound falls back to Node
- docs: npx storebound init (Node 20+) or bunx storebound init
- storebound.workspace.json: app folders (globs), studios with accounts by credential profile, ignore list, the
desktop's pairing overrides; ws init | list | status | check | validate | run | apps import | desktop export/import
- credential profiles in ~/.storebound/credentials/<profile>.json or env, --account <profile> on any command
- release status / release plan <version>, table or --json; MCP workspace_list, workspace_status, release_status,
release_plan (read-only)
- pairing rules (cli/lib/identity.ts), release lanes (cli/lib/train.ts) and the per-app status read
(cli/lib/app-status.ts) shared with the desktop instead of copied
- tests with sanitized fixtures, README, skills, CHANGELOG