codeburn/app
iamtoruk 4eabda17d7 fix: bound the serve drain, reap orphans on Windows, and de-flake the grace test
G1a - the stdin-EOF drain is now bounded (Promise.race against 45s, overridable
via CODEBURN_SERVE_DRAIN_MS for the test). Generous enough that no legitimate
request answered at EOF comes near it, and an async-wedged one releases the
child instead of turning it into the orphan the drain was added to prevent. The
comment names the ceiling: a SYNCHRONOUSLY wedged parse never yields to this
timer or to any other JS path, and only a signal can end that process.

G1b - Windows is the majority of the desktop fleet and had no orphan escape at
all: no ps, and no stdin-close recourse once the app has crashed. The reap now
works there. tasklist cannot report argv (image name and window title only) and
wmic is gone from current Windows, so the command line comes from
Get-CimInstance Win32_Process. Match discipline is unchanged - exact argv - with
quoting normalized on both sides, because we record a plain space-joined argv
while Windows reports the real quoted command line; a path with spaces still
round-trips. serveCommandMatches is extracted and tested directly.

G2 - the grace test raced node's cold boot (a 300ms window). The child now emits
one byte the moment it is ready, so the watchdog window is measured from
READINESS, not from spawn: boot cost cannot eat it at any machine speed. Timeout
raised on top of that. 6/6 green under 8 busy loops.

G3 - a served request heartbeats for its whole duration now, not just its parse:
the wrap moved to the one seam (runCaptured) that also covers aggregation and
payload serialization, whose ~8s tail lands back-to-back with the parse's own
quiet stretches. The one-shot path keeps the parse-only wrap, where an 8s tail
is comfortably inside the window on its own, and the CHANGELOG now says exactly
that instead of claiming every phase.

G4 - stillCold() anchors to coldStartBegan ?? bootedAt.

Text: the cold-timeout bound no longer claims to restore the "locate the CLI"
recovery (that is a not-found state, never cold-flagged), and the CHANGELOG
states the >15min case honestly - the ceiling still ends it, but partial cache
saves mean successive polls converge rather than each rescanning from nothing.
2026-08-22 10:36:58 -07:00
..
build desktop: add Microsoft Store package workflow 2026-07-22 00:15:14 +02:00
electron fix: bound the serve drain, reap orphans on Windows, and de-flake the grace test 2026-08-22 10:36:58 -07:00
flathub flathub: arch restriction file used in the submission 2026-08-12 06:12:06 -07:00
renderer fix: address adversarial review of the timeout watchdog (F1-F7) 2026-08-22 09:58:59 -07:00
scripts snap: scope the entries main gained after the tightening 2026-08-21 03:42:09 -07:00
.gitignore feat(app): bundle the CLI inside the packaged app 2026-07-16 09:27:46 -07:00
DISTRIBUTION.md docs: clarify authoritative Windows installer build 2026-08-13 20:17:28 +05:30
package-lock.json chore: bump to 0.9.20 2026-08-10 15:38:47 -07:00
package.json snap: scope the entries main gained after the tightening 2026-08-21 03:42:09 -07:00
README.md feat(app): bundle the CLI inside the packaged app 2026-07-16 09:27:46 -07:00
tsconfig.electron.json feat(app): scaffold Electron+Vite package and codeburn CLI spawn 2026-07-10 15:16:55 -07:00
tsconfig.json fix(app): clean build stamp, splash without hash, About checks for updates 2026-07-17 14:30:00 -07:00
vite.config.ts fix(app): clean build stamp, splash without hash, About checks for updates 2026-07-17 14:30:00 -07:00
vitest.config.ts fix(app): clean build stamp, splash without hash, About checks for updates 2026-07-17 14:30:00 -07:00

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, and sandbox: true.
  • Renderer code calls window.codeburn only through app/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-json and 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 desktop launcher 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 json with evidence and fix commands so Optimize can show richer actionable fixes.