Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ jobs:
- name: npm ci
run: npm ci

- name: Check version sync
run: npm run check:versions

- name: TypeScript + Vite build
run: npm run build

Expand Down
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [v0.39.0](https://github.com/mandarwagh9/embedist/releases/tag/v0.39.0) — 2026-05-28

### Added
- **Serial data plotter.** Lines that look like CSV (`1.23,4.56`), labelled pairs (`temp:23.5 humidity:60`), or JSON (`{"x":1,"y":2}`) are auto-parsed into numeric series and rendered as a live SVG line chart. Toolbar in `SerialMonitor` toggles **Text / Plot / Split** view; the plotter shows live values per channel and supports pause/resume.
- **Token usage + cost display.** Every assistant message footer shows prompt/completion token counts and an estimated USD cost based on the active provider's published list price. The conversation header tallies cumulative tokens and total cost for the session. Pricing table at `src/lib/ai-pricing.ts` covers the OpenAI, Anthropic, DeepSeek, and Google models exposed in Settings; Ollama / local models render `$0`; unknown models render counts without a misleading dollar figure.
- **Parallel agent tool dispatch.** When the model returns a batch of read-only tool calls (`read_file`, `list_directory`, `get_directory_tree`, `search_code`, `web_search`), they now execute concurrently via `Promise.all` instead of sequentially. Mutating tools still run in order to preserve filesystem causality and toast order; mixed batches fall back to sequential execution.

### Changed — performance + bundle
- **Initial JS chunk dropped from 1.77 MB → 411 KB (-77%).** `vite.config.ts` `manualChunks` splits Monaco, highlight.js, and xterm into their own chunks. The four sidebar panels (FileExplorer, AIChatPanel, SerialMonitor, BuildPanel), CodeEditor, SettingsModal, and SetupWizard are now `React.lazy()` with `<Suspense>` fallbacks. Cold start is noticeably faster on slow disks; the editor only pays its 4 MB cost when a file is actually opened.

### Changed — design system
- **Focus rings everywhere.** New `--focus-ring` token + global `:focus-visible` selectors mean every interactive element shows a keyboard-nav outline. Inputs additionally get a 4-px accent halo via box-shadow.
- **Light theme rebuilt for WCAG AA contrast.** Primary text clears 7:1 on every surface, accent moved from `#4F46E5` to `#3730A3`, surfaces re-warmed.
- **3-tier shadow scale** (`--shadow-sm/md/lg`) consolidating 9 ad-hoc shadow values that had drifted across components.
- **Reduced-motion support** — `prefers-reduced-motion: reduce` honored globally.

### Changed — state + I/O
- **`aiStore.messages` persistence capped at the most recent 50.** Previous behavior persisted unbounded history into localStorage, eventually hitting the 5–10 MB quota and silently dropping the whole store.
- **`fileStore` no longer persists file contents.** Reopened tabs reload from disk via the existing path/content code path.
- **`run_shell` audit logging is now structured.** Both invocation and result get a `log::info!` line with program name, cwd, exit code, and stdout/stderr byte counts.
- **`read_file` rejects files above 50 MB** with a friendly error instead of OOMing the app. `grep_search` skips files above the same limit. `get_directory_tree` caps total nodes at 10,000 and short-circuits on symlinks to prevent cycle traversal.

### Fixed
- **Tool-permission polling timeout.** The 30-second deny fallback now cancels the inner `setTimeout` chain so the poller can't outlive the outer promise. Previously a hung dialog could keep the loop alive after the deny had been applied.

### Tooling
- **Version-drift guard.** `npm run check:versions` (`scripts/check-version-sync.mjs`) compares `package.json` ↔ `src-tauri/Cargo.toml` ↔ `src-tauri/tauri.conf.json`. CI fails the build on drift; the three sources are now mechanically required to agree.

### Documentation
- `docs/superpowers/specs/2026-05-28-sota-roadmap.md` — consolidated audit roadmap.
- Five Tier-2 specs: clangd LSP bridge, GDB/OpenOCD debugger, embedding-based RAG, AI inline completions, auto-updater + code signing.
- `2026-05-28-tier-3-4-followups.md` — small + strategic follow-ups grouped by domain.

---

## [v0.38.0](https://github.com/mandarwagh9/embedist/releases/tag/v0.38.0) — 2026-05-28

### Security
Expand Down
40 changes: 40 additions & 0 deletions docs/superpowers/specs/2026-05-28-embedding-rag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Spec: Embedding-Based RAG

**Status:** proposed
**Owners:** TBD
**Tier:** 2

## Why

`src/lib/rag.ts` does TF-IDF keyword scoring over project files. It's fast and works for "find lines containing X" — but it misses semantic queries like "where does WiFi initialize" or "the function that publishes MQTT", which is exactly the question pattern an LLM agent should be cheap at. Cursor, Continue.dev, and Aider all use embedding-based retrieval; Embedist's TF-IDF is a noticeable regression in real use.

## Goal

Replace TF-IDF with embedding-based file-chunk retrieval, keeping the bundled cost low (no large local models) by reusing the user's already-configured AI provider for embeddings.

## Design

- **Chunk strategy:** split each project file by symbol boundary (Tree-sitter or, for v1, regex on `^\w.*\{$` for C/C++). Cap each chunk at 1024 tokens. Skip generated dirs (`.pio`, `target`, `node_modules`).
- **Provider routing:**
- OpenAI users: `POST /v1/embeddings` with `text-embedding-3-small` (1536-dim, $0.02/Mtok).
- Ollama users: `POST /api/embeddings` with `nomic-embed-text`.
- Anthropic users: no native embeddings API — fall back to Voyage via `voyage-3` or default to keyword TF-IDF.
- **Storage:** `~/.embedist/index/{project-id}.bin` — flat float32 array + companion JSON manifest (file path, chunk start/end line, content hash). Invalidate per-file on `useFileWatcher` change events.
- **Retrieval:** dot-product similarity against the query embedding, top-k=8. Add a hybrid score `0.7 * cosine + 0.3 * tfidf(query, chunk)` to keep the keyword signal where embeddings drift.
- **API:** keep `rag.ts::queryContext()` signature stable; the implementation swaps under the hood.

## Phasing

1. **v1:** Re-index on project open + on file save. Synchronous in a Web Worker so UI stays responsive.
2. **v2:** Incremental index — only re-embed changed chunks.
3. **v3:** Cross-project search (mono-repo / multi-project users).

## Risks

- Embedding API calls cost money. Default OFF; settings toggle "Use semantic search (uses embedding API)".
- Index size: ~200 KB per 1k LOC file at 1536-dim. A 100k-LOC project is ~20 MB on disk — fine.
- Cold start: first index on a large project takes minutes. Show progress in StatusBar.

## Verification

Open the ESP-IDF Wi-Fi example. Ask the agent: "where is the connect callback registered?" Without semantic search it returns files containing the substring "connect" — many irrelevant. With semantic search it returns `wifi_connect_handler.c:42` as the top hit.
43 changes: 43 additions & 0 deletions docs/superpowers/specs/2026-05-28-gdb-debugger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Spec: GDB / OpenOCD Debugger

**Status:** proposed
**Owners:** TBD
**Tier:** 2

## Why

For ESP32 and ARM Cortex-M targets, embedded developers iterate on bugs through breakpoints and watch expressions. Embedist currently gives them `printf` over serial and that's it. CLion, PlatformIO IDE, and ESP-IDF VS Code all wrap `openocd` + `gdb`; without parity, anything beyond toy projects forces users back to those tools.

## Goal

Set / hit a breakpoint on an ESP32-S3 from inside Embedist. Show: source line, call stack, local variables, watch expressions, step-into / step-over / step-out / continue.

## Design

- **Sidecar:** `src-tauri/src/commands/debug.rs` (new) spawns `openocd` (board-specific config) and `gdb --interpreter=mi`. Lifetime managed by `BuildState`-style `DebugState`.
- **Wire format:** GDB/MI parsed into typed events (`StopEvent`, `FrameEvent`, `VariableEvent`) emitted via Tauri `debug-event` payload.
- **Frontend:** new `BottomPanel.tab = 'debug'` panel: stack on the left, locals/watches on the right, controls at the top. Monaco gutter shows breakpoint markers and the current-line caret.
- **Reuse:** `BuildPanel` already streams events; the debugger panel uses the same Tauri-event pattern.
- **Board config:** new `boards/<board>.json` registry mapping board → openocd config, gdb path, default reset behavior. Start with esp32, esp32s3, esp32c3.

## Phasing

1. **v1:** Breakpoints + step + locals only. No watch expressions, no memory view.
2. **v2:** Memory inspector + watch expressions + conditional breakpoints.
3. **v3:** Logic analyzer view via `itm`/`swo` capture.

## Risks

- Toolchain detection: which `gdb` binary? PlatformIO bundles per-platform xtensa-esp-elf-gdb in `~/.platformio/packages`. Embedist must locate it without making the user configure paths.
- OpenOCD config drift across ESP-IDF versions.
- Probing for an attached JTAG/USB probe on Windows; FTDI / WCH-LinkE / DAPLink each have different USB IDs.

## Verification

Plug an ESP32-S3 dev board into the host. Set a breakpoint on `loop()` in the example project. Hit "Debug" → board halts on entry, source view scrolls to the marker, hovering a variable shows its current value. `Step Over` advances one line.

## Out of scope (v1)

- Profiling
- Reverse debugging
- Trace capture
38 changes: 38 additions & 0 deletions docs/superpowers/specs/2026-05-28-inline-completions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Spec: AI Inline Completions (Copilot-style ghost text)

**Status:** proposed
**Owners:** TBD
**Tier:** 2

## Why

Inline AI completions ("ghost text" you accept with `Tab`) are the single biggest productivity win that AI-IDEs offer over the previous generation. Cursor, Copilot, Continue.dev, Codeium, and Windsurf all ship this. Embedist has chat / plan / agent but no per-keystroke completion, so the AI is invisible during normal typing.

## Goal

Pressing `Tab` accepts a model-generated continuation of the current line / next few lines. Pressing `Esc` dismisses. Completions stream and update on every keystroke, debounced 300 ms.

## Design

- **Monaco hook:** `monaco.languages.registerInlineCompletionsProvider` for every language Embedist supports. The provider returns a streaming async iterator.
- **Backend route:** new `src-tauri/src/commands/ai.rs::chat_completion_stream(prefix, suffix, language)` that hits the configured provider's text-completion endpoint. For chat-only providers (Anthropic Messages API) wrap in a fixed system prompt "complete this code; emit only the continuation, no explanation."
- **Context:** include 80 lines before the cursor + the active file's path + project board (when known) so completions are board-aware ("on ESP32 prefer `pinMode(LED_BUILTIN, OUTPUT)` not Arduino-classic constants").
- **Throttling:** abort the previous in-flight request when a new keystroke arrives.
- **Settings:** `Settings → AI → Inline completions [off / model picker]`. Default off — opt-in because of per-keystroke cost.
- **Visual:** Monaco's built-in ghost-text rendering; no custom UI.

## Phasing

1. **v1:** Single-line completion, accept-on-tab only.
2. **v2:** Multi-line block completion (Cursor's "tab tab tab" UX).
3. **v3:** Inline rewrite ("cmd+k" partial selection rewrite — Cursor's killer feature).

## Risks

- Cost: at $0.15/Mtok input, one developer-day of typing can cost $5–$10 on Sonnet. Mitigate with the per-conversation cost surface added in v0.39.0, plus a hard daily budget in Settings.
- Latency: streaming has to start < 250 ms for ghost text to feel right. Anthropic + OpenAI usually do; DeepSeek/Ollama may not.
- Privacy: per-keystroke uploads of source code. Add a single Settings toggle to disable for sensitive workspaces and a per-folder allowlist.

## Verification

Type `digitalWrite(LED_BUILTIN, ` in a new sketch with an ESP32 platformio.ini. Ghost text appears: `HIGH);` within 400 ms. Tab accepts.
37 changes: 37 additions & 0 deletions docs/superpowers/specs/2026-05-28-lsp-clangd-bridge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Spec: clangd LSP Bridge

**Status:** proposed
**Owners:** TBD
**Tier:** 2

## Why

Embedist's editor is Monaco with extension-based language modes but no semantic understanding. Competing IDEs (VS Code + PlatformIO, CLion) ship real-time diagnostics, go-to-definition, hover docs, and refactor-rename via `clangd` over the Language Server Protocol. Without it, AI-assisted writes can land syntactically-broken C++ that nobody flags until `pio run` fails.

## Goal

Stream `clangd` diagnostics (errors, warnings, includes-not-found) inline in Monaco for every `.cpp`/`.c`/`.h`/`.ino` tab in the active project. Stretch: hover docs and go-to-definition.

## Design

- **Process:** spawn `clangd` as a Tauri sidecar managed by `src-tauri/src/commands/lsp.rs` (new). Lifetime tied to `useFileStore.rootPath`.
- **Compilation database:** generate `compile_commands.json` from `pio run -t compiledb` on project open or rebuild. Cache invalidated on `platformio.ini` change.
- **Transport:** newline-delimited JSON over stdin/stdout, framed per LSP spec (Content-Length headers).
- **Frontend:** new `src/hooks/useLsp.ts` owns the JSON-RPC dispatcher. `monaco.languages.registerHoverProvider` + `monaco.editor.setModelMarkers` for diagnostics. Reuse Monaco's markers gutter — no new UI surface.
- **Boundary contract:** sidecar emits one event `lsp-diagnostic` per file per change; frontend debounces 300 ms before pushing to Monaco.

## Out of scope (v1)

- Refactor-rename
- Code actions / quick fixes
- Multi-root workspaces

## Risks

- `clangd` is heavy (≈200 MB RSS on warm projects). Toggle in Settings → Editor → "Enable semantic analysis (experimental)".
- `compile_commands.json` generation requires a successful `pio run` first; for empty projects, fall back to a minimal compdb derived from `platformio.ini`.
- Windows path quoting; clangd is sensitive to `\\` vs `/`.

## Verification

Open `examples/blink/src/main.cpp`, save it with a deliberate typo (`Serial.beginx(115200)`). Within 1 s, Monaco shows a red squiggle and the Problems panel lists the diagnostic with the same file:line as the build output. Hover the typo → tooltip with the clangd message.
77 changes: 77 additions & 0 deletions docs/superpowers/specs/2026-05-28-sota-roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Embedist SOTA Roadmap

**Date:** 2026-05-28
**Baseline:** v0.38.0 (production-grade hardening shipped).
**Goal:** Beat VS Code + Cursor + Arduino IDE 2 + Wokwi for the embedded-development niche.

## Method

Six parallel domain audits — UI/UX, frontend code quality, Rust backend, AI integration, embedded-specific features, build/architecture — were dispatched against the current tree. This document consolidates ~80 findings into a single execution plan ranked by impact × effort.

## Tier 1 — Quick wins (ship in this release)

These are small-to-medium changes with outsized impact. Implementable inside one session.

| # | Domain | Item | File anchor | Why |
|---|--------|------|-------------|-----|
| 1 | Bundle | Split Monaco + tree-shake highlight.js; lazy-load 4 panels | `vite.config.ts`, `App.tsx` | Cuts initial JS from ~1.77MB to ~600KB; faster cold start |
| 2 | Security | Upgrade monaco-editor to patch 8 transitive DOMPurify XSS CVEs | `package.json` | XSS bypass in AI markdown render is real risk |
| 3 | UI | `:focus-visible` ring system + light-theme contrast + 3-tier shadow scale + hover-depth | `src/styles/global.css` + sweep | WCAG AA + keyboard-nav baseline |
| 4 | React | `key={i}` → `key={node.path}`, App.tsx useEffect deps, permission polling timeout | FileExplorer.tsx:367, App.tsx:328, agent-tools.ts:314 | Real bugs, not lints |
| 5 | State | Cap `aiStore.messages` persistence to last 50; stop persisting `fileStore.fileContents` | `aiStore.ts:partialize`, `fileStore.ts:partialize` | localStorage was unbounded |
| 6 | Release | `scripts/check-version-sync.mjs` — fail CI when 3 version sites drift | new file | Removes a known foot-gun called out in CLAUDE.md |
| 7 | Rust | `MAX_FILE_SIZE` on `read_file`/`grep_search`; tighten path-traversal in `resolve_path_for_validation` | filesystem.rs | DoS + TOCTOU windows |
| 8 | AI UX | Surface token usage + cumulative cost per conversation in MessageBubble | MessageBubble.tsx, aiStore.ts | User flying blind on $$ |
| 9 | AI | Parallel tool dispatch for read-only tools in agent loop | useAgent.ts | Cursor/Claude Code already do this |
| 10 | Embedded | Serial data plotter — auto-parse CSV/JSON shaped lines, real-time chart | SerialMonitor.tsx | Killer feature; only Wokwi has it |
| 11 | UI | Split-pane editor (two columns) | App.tsx | Table-stakes for IDEs |

## Tier 2 — Larger features (separate branches)

Each gets its own design doc + branch:

- **AI inline completions** (Copilot/Cursor-style ghost text) — Monaco `registerInlineCompletionsProvider` + provider-specific calls
- **Diff preview before file writes** — Cursor's accept/reject pattern
- **Embedding-based RAG** — Ollama embeddings or OpenAI `/v1/embeddings` instead of TF-IDF
- **AI commit-message generator** — `git diff` → conversation → suggested message
- **GDB / OpenOCD debugger** — break/step/watch/frame via Tauri sidecar
- **OTA upload** — Arduino OTA + ESP-IDF OTA support
- **SPIFFS / LittleFS filesystem explorer** — read+write ESP partition contents
- **Project templates browser** — scaffold "ESP32 HTTP server", "Arduino Blink", etc.
- **Library install/update UI** — `pio lib search/install/update`
- **clangd LSP bridge** — real-time semantic diagnostics, go-to-def, hover
- **Tauri updater plugin** — auto-update from a release manifest
- **Code-signing** — eliminate Windows SmartScreen warning

## Tier 3 — Polish and depth

- Memory analyzer: parse `.elf` to show flash/RAM breakdown after build
- Multiple terminal tabs + find/regex search in terminal output
- Custom-environment selector for projects with multiple `[env:…]` in `platformio.ini`
- Inline build diagnostics in Monaco gutter (parsed from `BuildPanel` problems list)
- Git gutter + minimap
- Command-palette fuzzy-match highlighting
- Drag-to-reorder tabs
- Tab preview on hover
- Compile-commands.json export for external clangd

## Tier 4 — Strategic

- **Cross-platform port** (macOS + Linux): abstract `SerialPort`, `Pty`, package format
- **React 19 upgrade** (low-risk, end of 2026)
- **Telemetry + crash reporting** (opt-in)
- **Wokwi-style live circuit simulation** (probably too ambitious for v1)

## Out of scope (deliberately)

- Plugin/extension API
- Marketplace
- Cloud sync of settings
- Multi-window
- Mobile companion app

## Execution order

This branch (`feat/v0.39.0-sota-push`) lands **all of Tier 1** and the first two Tier 2 items where they have natural synergy (token display already needs aiStore changes; the parallel-tool dispatch is a single-file change). Everything else gets a spec under `docs/superpowers/specs/` and a Tier-2/3/4 GitHub issue.

The verification gate stays the same: `npm run build`, `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test --all-targets`. CI runs all four on every push.
Loading
Loading