Security audit follow-ups on the DeepSeek Harness provider. - **Decompression bomb.** Every zstd frame was decoded with no output bound, so a 16 KB crafted log expanded to ~916 MB of RSS (a 65 KB one declares 2 GB). Each frame now decodes under a 64 MB per-call cap, and the caps chain into a running per-file budget of MAX_SESSION_FILE_BYTES: a frame is given only the bytes the file has left, so node throws ERR_BUFFER_TOO_LARGE without allocating past the cap. The throw propagates out of the existing skip path, which discards the whole file rather than counting the frames read before the bomb, so a crafted tail cannot poison a partial total. The discovery header read takes the same per-frame cap. Measured on a 65 KB / 2 GB bomb: 916 MB -> 67 MB peak, zero calls emitted, one notice. Lines are still materialized eagerly; the byte budget bounds that, and making the read lazy would change readEventLines' contract for no further bound. - **Usage type confusion.** Token fields were read with `?? 0` and never type-checked, so a string or array inputTokens flowed into the global totals and the persisted cache, where `0 + [1, 2]` becomes "01,2". They now go through numberOrZero (copilot.ts semantics: finite, positive, else 0). All-zero calls are still skipped. - **Snap over-scope.** The personal-files read entry is `$HOME/.dsh/sessions` rather than all of `$HOME/.dsh`; the provider reads nothing else. - **Third-party notice.** scanZstdFrames is transcribed from @deepseek-ai/dsh-session-persistence-jsonl. The published npm package is BSD-3-Clause (Copyright (c) 2026, DeepSeek) while the monorepo source declares MIT for the same package; THIRD_PARTY_NOTICES.md reproduces the stricter of the two and ships via package.json `files`. |
||
|---|---|---|
| .. | ||
| build | ||
| electron | ||
| flathub | ||
| renderer | ||
| scripts | ||
| .gitignore | ||
| DISTRIBUTION.md | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.electron.json | ||
| tsconfig.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
CodeBurn Desktop
Electron desktop shell for CodeBurn's local-first usage views. M1 runs as a developer app and reads data by spawning the installed codeburn CLI; it does not run a daemon or HTTP server.
Development
npm --prefix app install
npm --prefix app run dev
Validation:
npm --prefix app run test
npm --prefix app run typecheck
CLI Dependency
Packaged builds ship their own version-matched copy of the codeburn CLI and require nothing installed — the app spawns the bundled CLI with Electron's own binary as Node (ELECTRON_RUN_AS_NODE). In development (Vite dev server) the app uses the repo's freshly-built CLI, and either can be overridden with CODEBURN_BIN or a persisted path file. See DISTRIBUTION.md for the bundling and resolution details. Electron resolves and spawns the CLI from the main process, then sends decoded JSON through the secure preload bridge into the renderer.
This follows the menubar pattern:
contextIsolation: true,nodeIntegration: false, andsandbox: true.- Renderer code calls
window.codeburnonly throughapp/renderer/lib/ipc.ts. - Main process handlers return JSON envelopes so structured CLI errors survive IPC.
- Missing CLI, bad JSON, timeout, and nonzero exits are surfaced as honest UI states.
- The renderer never imports CodeBurn engine code from
src/; the data contract is spawn CLI, decode JSON, poll.
Data Contract
Current bridge calls:
- Overview:
codeburn status --format menubar-json --period <period> [--provider <provider>] - Plans:
codeburn status --format json --period <period> - Models:
codeburn models --format json --period <period> [--provider <provider>] [--by-task] - Optimize:
codeburn yield --format json --period <period> - Spend flow:
codeburn spend --format flow-json --period <period> [--provider <provider>] - Devices:
codeburn devices --format json --period <period> - Device scan:
codeburn devices scan --format json - Share status:
codeburn share status --format json - Identity:
codeburn identity --format json
Supported M1 periods are today, week, 30days, month, and all. Provider filtering is passed through where the CLI command supports it.
Sections
- Overview: daily spend, spend stats, waste summary, and expensive sessions from
menubar-json. - Spend: project/activity/tool/MCP/subagent lenses plus model-to-project flow.
- Optimize: waste findings from
menubar-jsonand reverted/abandoned yield data. - Models: model and task tables from
models --format json. - Plans: plan pacing from
status --format json. - Settings: device identity, nearby scan results, paired-device usage, and M2 visual affordances.
Packaging
npm run package produces an ad-hoc-signed macOS .dmg/.zip (arm64 and x64) via electron-builder, no paid Apple Developer account required. Packaging rebuilds the root CLI and bundles it into the app (Resources/cli), so installs need nothing on the target machine. See DISTRIBUTION.md for build instructions, the bundled-CLI mechanism, artifact locations, and the Gatekeeper first-open story.
M2 Backlog
- Add Electron
autoUpdater(the app already bundles its own version-matched CLI, so end-user installs need nothing on the machine; auto-update is the remaining piece). - Keep npm as a separate CLI-user channel at the same version as the desktop app.
- Add macOS code signing with a paid Developer ID and notarization (ad-hoc packaging exists today; see
DISTRIBUTION.md). - Add a
codeburn desktoplauncher subcommand. - Implement in-app pairing, approve, pull, and visibility mutations currently shown as M2 affordances.
- Build the Models Compare sheet.
- Add light theme support.
- Expand
codeburn optimize --format jsonwith evidence and fix commands so Optimize can show richer actionable fixes.