Commit graph

22 commits

Author SHA1 Message Date
iamtoruk
c73d8ff6c8 snap: scope the entries main gained after the tightening
The ported declaration was written against main as of c9e6e2ec. Main has since
added dsh and carries five entries that commit never saw, all of them still bare
tool roots, so the port dropped them rather than reintroduce what the store
rejected. Each is restored at the path its provider opens:

  .dsh/sessions                          dsh.ts reads <DSH_HOME>/sessions only
  .kiro/sessions                         CLI store at sessions/cli, v2 IDE store
                                         at sessions/<hash> — siblings
  .quickwork/{profiles.json,sessions,metrics}
                                         profiles.json names the profile bases;
                                         the legacy layout is sessions/sessions.db
                                         plus metrics/
  .config/Claude/local-agent-mode-sessions
                                         Claude Desktop's local-agent-mode store
  .config/Open Design/{runs,data/runs,namespaces}
                                         the three discovery roots open-design.ts
                                         probes under its data dir

.lingtai and .lingtai-tui stay dropped. A LingTai ledger lives at
.lingtai/<agent>/logs/token_ledger.jsonl, and personal-files has no wildcard for
the agent segment; .lingtai-tui only exists to enumerate project homes that could
not be read anyway. Goose is narrowed to .local/share/goose/sessions, which holds
the only file it opens.

Four entries stay whole roots because the provider reads a file sitting directly
in the root: .config/github-copilot (JetBrains stores nest under a variable
<ide>/<kind>/<storeId>) and .local/share/{opencode,crush,kilo}. The new
app/scripts/snap-grants.test.ts asserts every other entry is at least one level
below its tool root, so a bare root cannot come back unnoticed.
2026-08-21 03:42:09 -07:00
iamtoruk
3168699927 snap: scope personal-files to log subdirectories
Snap Store review found the declaration requested each tool's entire root
directory. Those roots hold configuration and, in several cases, credentials,
and personal-files read is recursive, so the request granted read of every AI
tool's credential store.

Every path is now the subdirectory the provider actually opens: .claude/projects,
.codex/sessions, .cline/data, .vibe/logs/session, .hermes/profiles, .mux/sessions
and so on; two are single files (.forge/.forge.db, .zcode/cli/db/db.sqlite). The
editor entries name only the extension folders that hold transcripts rather than
the editor's whole configuration. No bare tool root remains.

One credential file is requested openly instead of implicitly: .claude/.credentials.json,
read-only, used to call Anthropic's usage endpoint for the live plan gauge.

Codex's equivalent needs read-write on the Codex CLI's auth.json to rotate the
token, so neither that file nor a Codex root is declared and the Codex live
gauge is disabled under $SNAP. Codex usage and cost analytics are unaffected;
they come from the session rollouts.

Also declares five providers that were missing entirely and would have shown no
data under the snap: opencode, crush, goose, kilo, kimi-code. Drops .lingtai,
whose per-agent directory sits above the log folder and cannot be expressed
without wildcards.

Ports 4fe760aafe0492a674476c1ca64bf0dbdc673dde onto current main; the entries
main gained since that commit are reconciled separately.
2026-08-21 03:38:25 -07:00
iamtoruk
09965f93ae fix(dsh): cap zstd decode, coerce usage fields, scope the snap read
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`.
2026-08-17 17:28:41 -07:00
iamtoruk
d9a9486b6d docs(dsh): finish the provider registration checklist
docs/providers/NEW_PROVIDER.md items the PR had not reached yet, plus the two
surfaces that are functional rather than cosmetic:

- docs/providers/dsh.md and its row in the provider index, documenting the
  storage layout, the JSONL-backend-only scope (the opt-in SQLite persistence
  backend is not read), and that DSH is a developer preview whose format
  version 0 implies no compatibility.
- CHANGELOG entry under Unreleased.
- README provider count 40 -> 41 and a data-locations row.
- app/package.json: $HOME/.dsh in the snap personal-files allowlist, without
  which the Linux snap build cannot read DSH sessions at all.
- UsageDataChangeGuard: the DSH sessions root, without which the menubar never
  notices a new session and does not refresh.
- Bumps the dsh parse version, since the parser's attribution changed.
2026-08-17 10:59:58 -07:00
iamtoruk
c755a3c521 snap: strict confinement with read-only personal-files plug
Classic has no fitting store category (per forum feedback) and strict is
electron-builder's well-supported path. One personal-files plug grants
read-only access to the dot-directories the supported tools write session
logs into; the app's own config and cache stay in the snap's private area.
2026-08-12 05:20:15 -07:00
iamtoruk
7e99b875d5 packaging: Snap Store target and CI, Flathub manifest
- electron-builder snap target (classic confinement) with package:snap script
- build-snap.yml: builds on ubuntu, uploads artifact, optional store publish
  gated on workflow_dispatch input + SNAPCRAFT_STORE_CREDENTIALS secret
- app/flathub: manifest repacking the released deb, desktop file, AppStream
  metainfo, and submission runbook
2026-08-11 08:16:39 -07:00
iamtoruk
0090decf7d chore: bump to 0.9.20 2026-08-10 15:38:47 -07:00
reviewer
4c1aba1ae2 desktop: add Microsoft Store package workflow 2026-07-22 00:15:14 +02:00
Resham Joshi
af291ae621
release: 0.9.19 (#774)
0.9.18 was packaged from the pre-fix commit (364eed4) before the final
nine commits landed; npm versions are immutable, so the corrected
release ships as 0.9.19 everywhere. The changelog entry carries over
with a supersede note.

Co-authored-by: reviewer <review@local>
2026-07-20 09:35:32 -07:00
iamtoruk
8386df5f3c chore: release 0.9.18 2026-07-20 07:17:05 -07:00
iamtoruk
7946b4f369 chore(app): desktop 0.9.17
Patch release: Windows bundled-CLI fix (was not-found on 100% of
Windows), enriched cli_error telemetry, and the unified solid-flame
brand. CLI/menubar stay 0.9.16 (no changes needing an npm/menubar
republish; the desktop bundles current main's CLI).
2026-07-17 13:55:48 -07:00
Resham Joshi
eb513d3f68
desktop: ship .deb and .rpm for Linux, surface all download targets (#729)
The AppImage-only Linux build hit users with a no-application-installed
error on double-click, because AppImages do not self-register and need
chmod plus libfuse2 on newer distros. Add deb and rpm electron-builder
targets so Linux users get a native install that lands in the app menu
with no manual steps; the deb ships a .desktop entry for exactly that.

README hero grid now lists Debian/.deb, Fedora/.rpm, and AppImage
alongside the macOS and Windows buttons, and the desktop release notes
explain the deb/rpm path plus the AppImage FUSE requirement.
2026-07-17 12:53:58 -07:00
Resham Joshi
3cbc96a5de
release: desktop 0.9.16 (#721)
Some checks are pending
CI / semgrep (push) Waiting to run
Bump the desktop app version and point the README download badges at the
desktop-v0.9.16 release assets.
2026-07-16 19:34:43 -07:00
iamtoruk
e9655fa03c fix: hydration completeness markers, cold-only splash, honest switching, prefetch
P0: an interrupted cold hydration left partial caches that the
emptiness check read as warm — the daily backfill froze (missing older
days) while session parsing healed gradually (drifting totals),
poisoning every surface sharing the cache. Both caches now carry an
explicit complete marker: partial resumes cold under the hydration
lock; unmarked caches self-heal with one re-hydration. Regression test
seeds the exact frozen artifact and asserts bit-for-bit convergence
with a never-interrupted run.

- splash indexing reveals only on genuinely cold scans (explicit cold
  flag in the progress protocol), never on warm incremental re-parses
- uncached filter switches clear to skeleton instead of showing the
  previous filter's numbers; cached switches paint same-commit;
  background prefetch warms every detected provider after idle
- build stamp (git sha + date) in splash and About ends build ambiguity
- payload parity test: identical payloads on identical cache, and
  payload totals equal the CLI report path
- Sessions empty state keeps the provider filter row; zero savings
  line hidden; TCC usage-description strings + Full Disk Access docs
- warm profile documented: optimize scan ~1.47s dominant (safe
  refactor deferred), parse ~1s, aggregation ~30ms

Root 1848, app 320, typechecks clean.
2026-07-16 14:05:11 -07:00
iamtoruk
4a100d9d06 feat(app): bundle the CLI inside the packaged app
The packaged app resolved whatever codeburn was on PATH — for real
users the published npm release, which predates every JSON surface the
app calls. The app now ships its own CLI copy under resources/cli
(staged production node_modules tree; tsup output is not
self-contained) and spawns it with Electron's own binary via
ELECTRON_RUN_AS_NODE. No install prerequisite remains.

- resolution order: CODEBURN_BIN, dev repo CLI, bundled, persisted
  path, PATH search
- launch.js shim strips the extra argv element commander mis-slices
  under packaged Electron-as-node (process.versions.electron is set),
  which reproduced the 'too many arguments' class of error
- afterPack hook copies the staged tree (extraResources runs
  node_modules through the production-dep filter and ships it empty);
  lands before signing, signature verified intact
- packaging always restages from src via root build:cli (tsup only,
  no network); ~12MB compressed per artifact

Verified on the built app: Electron-as-node CLI emits current JSON
(providerDetails, currency), and a minimal-PATH GUI launch spawns the
bundled CLI with zero external dependencies. 290/290.
2026-07-16 09:27:46 -07:00
iamtoruk
69c1946c1c feat(app): Windows NSIS and Linux AppImage packaging targets
Cross-built from macOS alongside the existing mac config: nsis x64
(oneClick false, clean CodeBurn-Setup-<version>.exe artifact name) and
AppImage x64. DISTRIBUTION.md covers the new build commands, the
unsigned-build first-run steps per platform, and the desktop-v<version>
release tag convention the website pins.
2026-07-16 08:06:03 -07:00
iamtoruk
3ea43ea5a5 chore(app): version tracks the CLI (0.9.15)
One CodeBurn version across CLI, menubar, and desktop; splash, About,
and artifact names all read app/package.json. Documented in
DISTRIBUTION.md.
2026-07-16 07:30:49 -07:00
iamtoruk
2c66601b47 feat(app): package the desktop app for unsigned macOS distribution
electron-builder config with ad-hoc signing (identity "-", not null,
which skips signing and breaks Apple Silicon), dmg+zip for arm64 and
x64, org.agentseal.codeburn-desktop bundle id matching the menubar
convention, icon reused from build/icon.png. DISTRIBUTION.md documents
the build, verification, the Gatekeeper first-open steps for
unnotarized builds, and the later paid-notarization upgrade path.
2026-07-16 07:16:34 -07:00
iamtoruk
1320807de2 polish(app): splash wordmark in brand orange + version line
CodeBurn wordmark on the splash now uses --accent (matching the
website/sidebar brand treatment) with the app version (v0.1.0, from
package.json at build time) in muted small text below. App version
bumped 0.0.0 -> 0.1.0.

253/253, build green.
2026-07-16 05:15:35 -07:00
iamtoruk
daf944e714 feat(app): motion layer (gsap) — count-ups, chart grow-in, section fade, skeletons, toasts
- one gate (motionEnabled): off under reduced-motion, missing matchMedia,
  and vitest; every path checks it first
- mount/filter-change only: count-up and bar grow-in key off the
  period|provider|range key, so 30s poll refreshes snap values silently
  instead of re-animating
- first-load skeleton shimmer replaces bare scanning text (kept sr-only
  for screen readers); slide-in toast host for Settings/export feedback
  (validation errors stay inline); CSS hover-lift + press micro-
  interactions, all with a reduced-motion escape hatch
- gsap 3.15.0 + @gsap/react 2.1.2 (+74KB raw JS; G4 flame work shares it)

244/244, typecheck + build green.
2026-07-16 04:39:09 -07:00
iamtoruk
86bfdc9f83 fix(app): bind Vite dev server to 127.0.0.1 so the dev launcher starts Electron (was IPv6-only)
`npm run dev` hung: Vite bound to [::1]:5173 (IPv6) while `wait-on tcp:127.0.0.1:5173`
polled IPv4 — never satisfied, so Electron never launched. Pin Vite host to 127.0.0.1
and point Electron's VITE_DEV_SERVER_URL at 127.0.0.1 too; all three now agree on IPv4.
Caught by the live-run smoke (the one thing the no-display build env couldn't verify).
2026-07-11 02:06:17 -07:00
iamtoruk
5736c95324 feat(app): scaffold Electron+Vite package and codeburn CLI spawn
New standalone `app/` package (own package.json, like dash/) for the
CodeBurn Desktop Electron app. Adds the Vite 6 + React 19 + Vitest
toolchain, the verbatim wireframe CSS port (renderer/styles/indigo.css),
and the main-process `codeburn` CLI resolver + spawner:

- resolveCodeburnPath(): CODEBURN_BIN override → persisted-path file →
  PATH/brew/nvm/volta/asdf → null (mirrors mac/CodeburnCLI.swift).
- spawnCli(args, {timeoutMs}): plain argv (no shell), collect stdout,
  JSON.parse, structured CliError{kind: not-found|nonzero|bad-json|timeout}.
- cli.test.ts covers success / nonzero / bad-json / timeout / not-found.
2026-07-10 15:16:55 -07:00