Releases: bjb2/omp-deck
v0.6.1 — In-app update notification
Small follow-up to v0.6.0. Adds a passive update-check pill in the StatusBar so future releases (this one and onward) become discoverable from inside the deck instead of requiring users to run npm outdated -g.
Added
↑ X.Y.Z availablepill at the bottom-right of the deck chrome whenever the running version is behind what's published on npm. Click → opens the GitHub release notes in a new tab. The user runsnpm install -g omp-deck@latestthemselves; the deck never auto-updates. (#10)GET /api/versionreturns{ current, latest, updateAvailable, lastCheckedAt, releaseUrl, packageUrl, disabled }. The pill is just a thin renderer over this.- 24-hour cached version check against
https://registry.npmjs.org/omp-deck. Same destination asnpm install; no version-as-fingerprint, no analytics, no extra outbound traffic beyond one ~1 KB request per day. - Kill switch:
OMP_DECK_DISABLE_UPDATE_CHECK=1short-circuits the entire feature (no cache read, no network, no pill). Set it in your managed.envif you're on a locked-down network or just don't want the chrome. - Cache lives at
<dataDir>/update-check.jsonand is graceful on every failure mode (registry down, parse error, env disabled, malformed cache, version-compare failure) — the pill simply doesn't render. - Semver-aware comparison via
Bun.semver.order(so0.10.0 > 0.9.0, prereleases handled correctly). - New protocol type:
VersionInfo. - 10 new tests on the update-check module (33 assertions): disabled-flag handling, cache hits at newer / same / older versions, semver edge cases, registry-error state, first-call empty-state + background refresh, response-shape sanity.
v0.6.0 — First-run onboarding + provider clarity + reliability fixes
Quality-of-life release driven by three live-demo reports plus a deliberate first-run-experience rewrite.
For existing users: see docs/upgrading.md — the onboarding wizard does NOT trigger for installs with existing sessions or a moved welcome task. Everything you have keeps working.
Onboarding wizard (#9)
- Five-step first-run flow at
/onboarding, gated by a server-detectedneedsOnboardingflag. Brand-new users get walked through: kb scaffold → provider auth (Claude Pro/Max or ChatGPT Plus/Pro OAuth, or OpenRouter API key) → optional/startgreeting → handoff to chat. - Returning-user detection is silent: any existing session OR a welcome task that's not in backlog marks onboarding settled without ever showing the wizard. Existing installs upgrade cleanly.
- Welcome task tile on
SessionPickersurfaces the seededT-1task even if the user never clicks the Tasks tab. - Skip-but-remind toast appears on the chat view if onboarding was X-ed out, pointing at
/onboardingfor a re-run. - New server module
apps/server/src/onboarding-state.ts+ routes at/api/onboarding/{state,complete,seed-kb-system}. Reuses existing endpoints (/api/kb/init,/api/orientation/start,/api/settings/env,/api/auth/oauth/*) for the actual work. - The wizard's
/starttemplate is static but the AGENT re-fetches live state on every fire (kb files,/api/{tasks,routines,inbox}), so it stays accurate as the deck grows.
Model-picker clarity (#7)
subscriptionbadge in the model picker for genuine consumer-subscription providers (Claude Pro/Max, ChatGPT Plus/Pro, GitHub Copilot, Cursor, Perplexity Pro/Max, coding plans). Explicit allowlist — not the SDK's broadergetOAuthProviders()which would have falsely badged Ollama / LM Studio / gateway services as "subscription."- Placeholder API keys suppressed.
OPENAI_API_KEY=sk-your-XXXXhere(and other.env.exampleleftovers —your-api-key,<your-key>,changeme, length-too-short keys per prefix family) no longer mark API-key providers as authenticated. The picker hides those rows from the default view instead of letting users click them and get back a 401. - 401-recovery notification. When a chat call returns auth-shaped error (
401,incorrect api key,unauthorized) on an API-key provider AND a subscription provider carries the same model id with a real OAuth credential, the deck fires awarnnotification suggesting the switch.
OAuth flow lifecycle (#7)
- 5-minute server-side timeout per OAuth flow. The SDK's own timeout only fires on the loopback callback listener — flows driven by
onPrompt(e.g. Ollama endpoint input) could sit pending forever, blocking subsequent attempts with409 already-in-flight. Now force-cancelled. - Stale-flow eviction on
POST /:provider/start. If a duplicate start arrives and the held flow is past the timeout window, evict it inline instead of 409-ing forever. abortFlowhelper drainspromptResolverstoo (latent bug — pre-fixcancelonly rejectedmanualCode, leavingonPromptdeferreds hanging).- OAuth consent button now uses
variant="primary"instead of inheriting the low-contrast default ghost variant.
Cross-platform reliability (#8)
- Bun executable resolution falls back to
Bun.which("bun")whenprocess.execPathpoints at a dead path. Fixes a macOS-reportedposix_spawn ENOENT '~/.bun/bin/bun'when the user reinstalled Bun via Homebrew / asdf / mise after deck boot. Affects both telegram-bridge spawn andscheduleRestart.
Added
docs/upgrading.md— version-by-version migration notes.- README "Global install" section rewritten to explicitly call out:
ompCLI not required; Bun + Node prereqs; post-boot auth paths (OAuth or API key); and how the deck self-bootstraps~/.omp/agent/on first boot. apps/server/src/credential-quality.tswithlooksLikePlaceholderKey(44 unit-test assertions).apps/server/src/runtime-bun.tswithresolveBunExecutable(4 tests).apps/server/src/onboarding-state.ts+routes-onboarding.ts(4 tests).apps/server/src/routes-auth-oauth.test.ts— 6 tests for the newabortFlowcleanup helper.ModelInfo.isSubscriptionfield in@omp-deck/protocol.OnboardingState+SeedKbSystem*types in@omp-deck/protocol.
v0.5.0 — Cross-platform CI, Linux container, Mac/Linux launcher
Infrastructure release. v0.4.0 advertised macOS and Linux support but had never been empirically verified — every release shipped "tested on a Windows box, presumed to work elsewhere." v0.5.0 closes that gap: every push to main now runs the gates on all three platforms under the same Bun version, the Docker image actually boots end-to-end, and Mac/Linux users get a launcher with parity to the Windows one.
Two real Linux bugs surfaced during the validation work and are fixed in this release.
Cross-platform CI matrix
.github/workflows/ci.yml runs on every push to main and every pull request:
| Job | Runner | What it runs |
|---|---|---|
ubuntu-latest · bun 1.3.14 |
Ubuntu | bun install --frozen-lockfile, bun run typecheck, bun test, bun --cwd apps/web run build |
macos-latest · bun 1.3.14 |
macOS | same |
windows-latest · bun 1.3.14 |
Windows | same |
docker build + boot smoke |
Ubuntu | docker build, container boot, curl /api/health, curl /api/tasks |
The first run was green across all four jobs. The matrix is fail-fast disabled so a regression on one platform doesn't mask issues on the others. Concurrency group cancels in-flight runs on the same ref so rapid pushes don't queue duplicate work.
What this means in practice:
- No more "should work on Mac/Linux" claims — every release ships with empirical verification.
- Platform-divergent regressions are caught at PR time instead of at user-install time.
- The Docker
Dockerfileis exercised end-to-end on every push — if anyone breaks the container path, the next push tells them.
Total CI wall-clock on a typical push: about 2.5 minutes.
Fixed: Docker build is now correct end-to-end on Linux
Two regressions were silently broken before this release, even though docs/deployment.md advertised the path:
1. Lockfile workspace mismatch. The Dockerfile copied four workspace manifests (packages/protocol, apps/server, apps/web, root) but the lockfile knows about five — the telegram bridge under apps/bridges/telegram was missing. bun install --frozen-lockfile failed with lockfile had changes, but lockfile is frozen. Fix: both build stages now copy the telegram manifest alongside the rest. The bridge itself is still opt-in at runtime; the manifest just needs to exist for the workspace graph to match the lockfile.
2. Alpine vs glibc. The base image was oven/bun:1.3.14-alpine (musl libc). @oh-my-pi/pi-natives ships prebuilt .node binaries for linux-x64-modern and linux-x64-baseline, both linked against glibc's ld-linux-x86-64.so.2. There is no linux-x64-musl variant, so the container booted, crashed at agent-session init, and exited. Fix: base image switched to oven/bun:1.3.14 (Debian-slim, glibc). The image is about 40 MB larger; the trade is a runtime that actually boots.
Added: Start-OMP-Deck.sh for macOS and Linux
Bash sibling to the Windows Start-OMP-Deck.cmd launcher. Same shape — start the dev server + Vite together, write logs under .logs/, open the deck in the default browser — plus start / stop / status subcommands for "set it and forget it" usage:
chmod +x Start-OMP-Deck.sh # one-time
./Start-OMP-Deck.sh start # background, opens browser
./Start-OMP-Deck.sh status # check
./Start-OMP-Deck.sh stop # tears down server + vite + child processes
./Start-OMP-Deck.sh # foreground, same as `bun run dev`Stop handling kills the whole process group, so vite and the bun server both exit together — no orphan listeners on the dev port.
Added: .gitattributes enforcing LF on POSIX-executed files
Locks *.sh, *.bash, and Dockerfile to LF line endings. Without this, Windows clones with core.autocrlf=true (Git for Windows default) silently convert these to CRLF; the file commits clean, then the shebang lookup fails on POSIX (bash\r: not found). This was a latent landmine and is now defused.
Install / upgrade
Fresh install:
git clone https://github.com/bjb2/omp-deck.git
cd omp-deck
bun install
bun run devUpgrade from v0.4.0 — no migrations needed:
git pull
bun install
bun run devDocker (now actually works):
docker build -t omp-deck .
docker run --rm -p 127.0.0.1:8787:8787 omp-deck
# → http://127.0.0.1:8787Full changelog: v0.4.0...v0.5.0 · See CHANGELOG.md for the full detail.
v0.4.0 — Plan mode, queued-prompt editing, todo live-sync
Mid-cycle release focused on user-visible polish to the chat loop. Plan mode brings TUI parity to the deck so the agent can propose work before it executes. Queued prompts you sent mid-stream can now be edited or cancelled. The Inspector's todo panel updates intra-turn instead of waiting for SDK reminder ticks. Session rename failures surface their error instead of silently reverting.
✨ Plan mode (T-105)
Shift+Tab in the composer — or /plan [on|off] from the slash picker — toggles plan mode for the active session. While active, the agent gets the SDK's plan-mode system prompt + the resolve tool, so writes are gated until you approve.
When the agent submits a plan, the chat surfaces an inline PlanApproval card with:
- Reject — exits plan mode cleanly, no rename, no execute.
- Approve — renames
local://PLAN.mdtolocal://<title>.mdand queues a synthetic execute prompt that runs in a new turn with the full tool set restored. - Edit & approve — opens an inline textarea pre-filled with the plan body; saves the edited content back to
PLAN.mdbefore the rename.
Five discoverability surfaces, all keyboard-/touch-friendly:
| Entry point | Where |
|---|---|
Shift+Tab |
Composer keyboard (matches TUI muscle memory) |
/plan |
Slash picker — client-virtual, never round-trips to the agent |
| Header pill | Top of session pane |
| Composer border tint | accent-plan color around the textarea |
| Sidebar badge | On the active session row |
Robust to reconnect: pending proposals are replayed via the bridge's subscribePlanModeFrames mechanism, so a page reload mid-approval re-renders the card.
15 unit tests covering enter / idempotent re-enter / exit / approve happy path / edit-and-approve / title-override / path-traversal-rejection / reject / double-click CAS / cancel-mid-approval / dispose / snapshot-replay.
✏️ Queued-prompt edit + cancel
Hover any queued bubble to reveal Pencil + X. Edit opens an inline textarea (Enter saves, Esc discards, empty save = cancel). Cancel drops the entry without prompting.
Under the hood, the bridge maintains a shadow queue mirrored from the SDK; cancel/edit rebuild the SDK queue (synchronous popLastQueuedMessage loop + parallel re-enqueue) preserving order + ids so bubbles don't re-key. queue_state event re-broadcasts the canonical queue after every mutation; reducer replaces wholesale.
Session snapshot now carries queuedPrompts, so a page reload subscriber sees the queue immediately.
⚡ Todo panel live-sync (T-106)
The Inspector's TodoPanel was visibly stale between an agent's todo_write call and the SDK's next todo_reminder tick (those fire only on reminder cycles, typically at turn boundaries). For long turns with many todo updates, the panel showed pre-tick state until the cycle caught up.
The bridge now extends the existing session.subscribe listener to detect tool_execution_end with toolName=todo_write and emit a synthetic todo_phases_set event carrying session.getTodoPhases(). Inspector updates intra-turn.
🐛 Session rename — surface failures
The omp SDK's setSessionName performs an atomic-replace on the session journal: write to .jsonl.tmp, fs.rename over the original. On Windows fs.rename fails with EPERM when the destination is held open — and the live session always holds the journal open. So pressing Enter to rename produced a 500 error the store swallowed via console.warn; the input closed; the UI showed the old name with no indication anything had failed.
Now the input stays open on failure and renders an inline danger-toned error span with role=alert + aria-describedby. Successful renames still close as before.
The underlying Windows EPERM bug is in the SDK's atomic-rename helper — to be raised separately upstream.
⌨️ Universal Ctrl+. / Cmd+. abort
Window-level keybinding to abort the active session if it's streaming. Same convention as ChatGPT and VS Code. Composer's Stop button also gains an explicit Ctrl+. hint.
🩹 Fixed
- Fresh-clone
bun run devno longer fails on missingTELEGRAM_BOT_TOKEN. The rootdevscript previously fanned out across every workspace (--filter='@omp-deck/*') and brought the standalone telegram bridge along with the deck server + web — the bridge's config validator throws if no bot token is set, so first-run users would hit an error before the UI ever came up. The bridge has always been opt-in; the dev script now restricts itself to@omp-deck/server+@omp-deck/web. (#1)
📚 Docs
- README rewritten human-forward — leads with the feeling of using the cockpit (track work as work, ask from anywhere, decide carefully, capture without context-switching, remember across sessions) rather than a feature inventory.
docs/tui-parity.md: plan mode + ask tool moved from Future to ✓. Themes row adds Horizon. New row for queued-prompt edit/cancel. Todos panel mentions the synthesis.docs/slash-commands.md:/plansection + client-virtual mechanism explanation.docs/architecture.md: synthetic events expanded (todo_phases_set,prompt_queued+queue_state, plan-mode trio,ext_ui_dialogpair). DB tables list fleshed out.docs/themes.md: Horizon documented.docs/configuration.md:OMP_DECK_AUTO_STARTdefault corrected from "empty (disabled)" to/start(the actual default — it's opt-OUT, not opt-in).CONTRIBUTING.md: "No unit-test harness" claim retired — 149+ server + 16+ web/reducer tests; coverage is partial but real.
Install / upgrade
Fresh install:
git clone https://github.com/bjb2/omp-deck.git
cd omp-deck
bun install
bun run devUpgrade from v0.3.0:
git pull
bun install
bun run devNo migrations needed beyond the automatic SQLite ones; deck DB is forward-compatible.
Tested fresh install path verified end-to-end on Bun 1.3.14 — see install docs.
Full changelog: v0.3.0...v0.4.0 · See CHANGELOG.md for the section-by-section detail.