feat: add wow features foundation + single-click packaging#8
feat: add wow features foundation + single-click packaging#8Manish0Jha merged 36 commits intomainfrom
Conversation
- Add Cronos package for cron expression parsing - Add enums: MatchStrategy, DecisionStepType, MilestoneType - Add models: DejaVuAlert, SessionSummary, DecisionChain, BlastRadius, GrowthModels - Add interfaces: IDeadEndStore, IAlertSink - Extend AgentContext with IDeadEndStore - Extend IGraphStore with multi-edge-type GetNeighbors overload - Extend IObservationStore with GetSessionObservations - Extend AgentOutputType with 5 new members - Add centralized Prompts.cs with all LLM prompt templates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tables: deja_vu_alerts, session_summaries, developer_metrics, milestones, growth_reports with appropriate indexes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…multi-edge GetNeighbors - SqliteDeadEndStore with CRUD, FindByFiles, FindSimilar - GetSessionObservations on SqliteObservationStore - Multi-edge-type GetNeighbors overload on SqliteGraphStore - 7 new tests, all passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace stub IsCronDue with Cronos-based cron expression parsing - Persist DeadEndDetected outputs via IDeadEndStore in AgentScheduler - Migrate BriefingAgent and CompressionAgent to use Prompts.cs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wire IDeadEndStore and DecisionChainAgent in Program.cs - Implement DecisionChainAgent with LLM-powered causal edge classification - Update LinkerAgentTests for new AgentContext shape - Add DecisionChainAgent tests with mock LLM service - All 32 tests passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical fixes: - Replace string.Format with Prompts.Fill() using named placeholders to prevent FormatException on content with braces - Replace fragile JSON round-trip with concrete DeadEndOutputData DTO in AgentScheduler dead-end persistence - Add SQL LIKE pre-filter in FindByFiles to avoid full-table scan High priority fixes: - Add IGraphStore.GetNodeBySourceId for O(1) indexed lookups, replacing O(N) GetNodesByType scans in DecisionChainAgent - Move IDeadEndStore to end of AgentContext parameter list to preserve backward compatibility for positional constructors - Re-throw OperationCanceledException in DecisionChainAgent to support clean shutdown Medium fixes: - Extract project from observations in dead-end persistence (was hardcoded "unknown") - Extract shared NullVectorStore/NullLlmService/NullDeadEndStore into TestHelpers.cs to eliminate duplication - Lower FindSimilar keyword minimum length from 4 to 3 chars All 55 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IAlertStore with Add, GetActive, GetAll, Dismiss, Exists - SqliteAlertStore persists to deja_vu_alerts table - Dedup via Exists(threadId, deadEndId) ignoring dismissed - 5 tests covering CRUD, dismiss, and dedup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Triggers on FileChange and Error events - Groups observations by thread, matches against dead-end store - Confidence threshold 0.5 (file overlap ratio) - Deduplicates via IAlertStore.Exists - Optional IAlertSink for SSE broadcast - 4 tests covering match, threshold, dedup, and threadId guard Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AlertChannel implements IAlertSink via bounded Channel<T>
- REST endpoints: GET /alerts, GET /alerts/all, POST /alerts/{id}/dismiss
- SSE endpoint: GET /alerts/stream for real-time push
- Wire IAlertStore, AlertChannel, DejaVuAgent in Program.cs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DejaVuAlert type and API methods in client.ts - Alerts page with dismiss buttons and show-dismissed toggle - AlertBanner component polls every 10s, shows at top of all pages - Route and nav link for /alerts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical: - Guard against division-by-zero when deadEnd.FilesInvolved is empty High: - AlertChannel uses DropOldest to prevent blocking agents - Document single-consumer SSE limitation Medium: - Dismiss endpoint returns 404 on nonexistent alert IDs - IAlertStore.Dismiss returns bool for row-found check - CLI URL-encodes alert ID with Uri.EscapeDataString - StreamWriter in SSE uses await using for proper disposal - Limit cap (max 1000) on /alerts/all endpoint Low: - Remove unused includeStatus parameter from CLI PrintAlerts - Add IAlertSink integration test (CapturingAlertSink) - Add test for empty FilesInvolved guard All 66 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…torytellerAgent - ISessionStore with Add, GetBySessionId, GetAll, GetLatest - SqliteSessionStore persists to session_summaries table - StorytellerAgent: phase detection, turning points, LLM synthesis - Phase classification: Exploration, Implementation, Debugging, Refactoring - 4 store tests + 5 agent tests (including phase/turning point unit tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SessionEndpoints: GET /sessions, GET /sessions/{id}, GET/POST /sessions/{id}/story
- StoryCommand CLI: devbrain story [--session id]
- Sessions dashboard page with phase bar, expandable narrative, copy-as-markdown
- Wire ISessionStore, StorytellerAgent in Program.cs
- API client types + methods for SessionSummary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical:
- Remove dead durationSeconds fallback in CLI, display TimeSpan directly
- Replace fragile RawContent slicing with safe Truncate() helper
High:
- POST /sessions/{id}/story now honest about being validation-only (v1)
- Add ISessionStore.GetByDateRange for Growth Tracker needs
- Rename route params from {id} to {sessionId} for clarity
Medium:
- DetectPhases handles sessions shorter than 10 min / same timestamp
- "Error resolved" label changed to "Error at X, no recurrence after"
with guard requiring subsequent non-error activity
- Fix case sensitivity inconsistency in sessionFiles Distinct()
- Add INSERT OR IGNORE for TOCTOU safety on session_summaries
- Wrap dashboard phase labels in same conditional as phase bar
Low:
- CLI differentiates 404 vs other HTTP errors
- Add 4 new tests: single window, same timestamp, empty observations,
LLM failure path
All 79 tests passing, dashboard builds clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DecisionChainBuilder: traverses causal graph edges to build
chronological decision chains for files and decision nodes
- ReplayEndpoints: GET /replay/file/{path}, GET /replay/decision/{nodeId}
- ReplayCommand CLI: devbrain replay <path> [--decision <id>]
- Dashboard Replay page with vertical timeline visualization,
color-coded step types, file tags, and narrative summary
- 5 new tests for DecisionChainBuilder (chain building, dead ends,
empty file, causal traversal, nonexistent node)
- Wire DecisionChainBuilder in Program.cs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical: - BuildForDecision rejects non-Decision/Bug root nodes (returns null) - Extract TraverseCausalGraph() method for Blast Radius reuse - CausalEdgeTypes now IReadOnlyList<string> (immutable) - BuildSteps type filter prevents non-decision nodes from leaking - Batch observation lookups via obsMap (eliminates N+1 queries) High: - Remove unpopulated AlternativesRejected from DecisionStep model - RootNodeId now deterministic (chronologically earliest step) Medium: - CLI path argument is now optional when using --decision - Dashboard error handling improved (structured check vs string match) - 3 new tests: non-Decision root rejection, deterministic root, hops limit verification All 87 tests passing, dashboard builds clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- BlastRadiusCalculator: reuses TraverseCausalGraph from DecisionChainBuilder,
collects downstream files, computes risk scores per spec formula
- Risk = (1/chainLength) * deadEndMultiplier * recencyDecay
- BlastRadiusEndpoints: GET /blast-radius/{path}?hops=N (max 5)
- BlastCommand CLI: devbrain blast <path> with color-coded risk output
- Dashboard BlastRadius page with risk bars, dead-end warnings, file cards
- 8 new tests: affected files, source exclusion, dead ends, unknown file,
causal chain traversal, risk score unit tests (3)
- InternalsVisibleTo for Storage.Tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
High: - Clamp risk score to [0, 1] with Math.Min(1.0, raw) - Replace EstimateChainLength with real depth tracking via TraverseCausalGraphWithDepth (BFS with per-node depth) - deadEndsInChain now per-node (Bug type = 1, else 0) instead of global count inflating all scores equally Medium: - Remove dead sourceFileNorm variable Low: - Clamp hops parameter: Math.Clamp(hops ?? 3, 1, 5) - Rename DecisionChain field to LinkedDecisionId (was always 1 element) - Add --hops option to CLI BlastCommand - Fix test name typo: Folls -> Follows - 2 new tests: score clamped to 1.0, closer files get higher risk All 97 tests passing, dashboard builds clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IGrowthStore with metrics, milestones, reports CRUD + Clear - SqliteGrowthStore persists to developer_metrics, milestones, growth_reports - GrowthAgent (weekly cron): computes 8 metric dimensions (debugging_speed, dead_end_rate, exploration_breadth, decision_velocity, retry_rate, tool_repertoire, problem_complexity, code_quality) - Milestone detection: first-project, 20%+ improvement, composite complexity-up-quality-holding insight - LLM narrative via Prompts.GrowthNarrative (PreferLocal) - GrowthEndpoints: GET /growth, /growth/history, /growth/milestones - GrowthCommand CLI: devbrain growth, growth milestones, growth reset - Growth dashboard page with narrative card, metrics grid, milestone timeline - 5 store tests + 7 agent tests (metrics computation, milestone detection) - Wire IGrowthStore, GrowthAgent in Program.cs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical: - Fix MapReport to hydrate Metrics and Milestones from stored IDs (was returning empty collections, making dashboard non-functional) - Fix ComputeDebuggingSpeed to measure first-error-to-resolution instead of error span (lastError - firstError) - Rework complexity normalization: 1.0 + raw with better weights so scores actually vary across thread sizes (was clamping all to 1.0) High: - Detect milestones BEFORE persisting metrics to avoid consuming history slots with current week's data - Add Before filter to weekly observation query - Reduce historical project query from 5000 to 500 Medium: - Add DELETE /growth endpoint for reset functionality - Fix CLI reset command to use API instead of dead-end message Low: - Add streak milestone detection for zero dead-end weeks - 5 new tests: error-to-resolution, zero errors, complexity variation, report round-trip with hydrated metrics, multi-session retry rate - Fix existing debugging speed test for new correct behavior All 114 tests passing, dashboard builds clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers cross-platform package manager distribution (winget, brew, apt), Electron tray app for daemon lifecycle, Ollama auto-bootstrap, and CI/CD pipeline for building and publishing packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 tasks covering Electron tray app (health, daemon, bootstrap), CLI/tray coordination, electron-builder config, package manager manifests (Homebrew, winget, APT), and CI/CD pipeline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ntinel Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…shing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Write stopped sentinel in daemon.stop() before killing process - Add immediate health check on monitor start - Fix tag detection logic in CI workflow - Remove nonexistent DevBrain.app from Homebrew formula - Remove unused electron-log dependency Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces the “Wow Features” foundation (alerts, decision replay, blast radius, session storytelling, growth tracking) across core models, storage, agents, API, CLI, and dashboard, and adds a single-click packaging flow via an Electron tray app and package-manager publishing.
Changes:
- Add new Core models + Storage stores/calculators for alerts, sessions, growth, decision chains, and blast radius.
- Add new Agents + API endpoints + CLI commands + Dashboard pages to surface these features end-to-end.
- Add Electron tray app + packaging manifests + CI workflow to build and publish installable artifacts.
Reviewed changes
Copilot reviewed 107 out of 109 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/DevBrain.Storage.Tests/SqliteSessionStoreTests.cs | Tests for session story storage |
| tests/DevBrain.Storage.Tests/SqliteGrowthStoreTests.cs | Tests for growth store CRUD/hydration |
| tests/DevBrain.Storage.Tests/SqliteGraphStoreMultiEdgeTests.cs | Tests multi-edge-type neighbor traversal |
| tests/DevBrain.Storage.Tests/SqliteDeadEndStoreTests.cs | Tests dead-end storage querying/matching |
| tests/DevBrain.Storage.Tests/SqliteAlertStoreTests.cs | Tests alert store add/dismiss/dedup |
| tests/DevBrain.Storage.Tests/DecisionChainBuilderTests.cs | Tests decision chain building logic |
| tests/DevBrain.Storage.Tests/BlastRadiusCalculatorTests.cs | Tests blast radius + risk scoring |
| tests/DevBrain.Agents.Tests/TestHelpers.cs | Shared null test doubles for agents |
| tests/DevBrain.Agents.Tests/StorytellerAgentTests.cs | Tests session storytelling agent |
| tests/DevBrain.Agents.Tests/LinkerAgentTests.cs | Update context wiring for new deps |
| tests/DevBrain.Agents.Tests/GrowthAgentTests.cs | Tests growth agent metrics/milestones |
| tests/DevBrain.Agents.Tests/DejaVuAgentTests.cs | Tests alert firing + dedup behavior |
| tests/DevBrain.Agents.Tests/DecisionChainAgentTests.cs | Tests decision-linking agent |
| src/DevBrain.Storage/SqliteSessionStore.cs | Session summaries persistence + queries |
| src/DevBrain.Storage/SqliteObservationStore.cs | Add session observation retrieval |
| src/DevBrain.Storage/SqliteGrowthStore.cs | Growth metrics/milestones/report storage |
| src/DevBrain.Storage/SqliteGraphStore.cs | Add node lookup + multi-edge neighbor query |
| src/DevBrain.Storage/SqliteDeadEndStore.cs | Dead-end store implementation |
| src/DevBrain.Storage/SqliteAlertStore.cs | Alert store implementation |
| src/DevBrain.Storage/Schema/SchemaManager.cs | New tables/indexes for wow features |
| src/DevBrain.Storage/DevBrain.Storage.csproj | InternalsVisibleTo for tests |
| src/DevBrain.Storage/DecisionChainBuilder.cs | Shared causal traversal + chain building |
| src/DevBrain.Storage/BlastRadiusCalculator.cs | Blast radius computation + risk scoring |
| src/DevBrain.Core/Prompts.cs | Centralized prompt templates + filler |
| src/DevBrain.Core/Models/SessionSummary.cs | Session story model |
| src/DevBrain.Core/Models/GrowthModels.cs | Growth tracker models |
| src/DevBrain.Core/Models/DejaVuAlert.cs | Alert model |
| src/DevBrain.Core/Models/DecisionChain.cs | Decision chain model |
| src/DevBrain.Core/Models/BlastRadius.cs | Blast radius model |
| src/DevBrain.Core/Models/AgentOutput.cs | New agent output types + payload |
| src/DevBrain.Core/Interfaces/ISessionStore.cs | Session store contract |
| src/DevBrain.Core/Interfaces/IObservationStore.cs | Add session-observations API |
| src/DevBrain.Core/Interfaces/IIntelligenceAgent.cs | Add DeadEnds to AgentContext |
| src/DevBrain.Core/Interfaces/IGrowthStore.cs | Growth store contract |
| src/DevBrain.Core/Interfaces/IGraphStore.cs | Graph store additions/overloads |
| src/DevBrain.Core/Interfaces/IDeadEndStore.cs | Dead-end store contract |
| src/DevBrain.Core/Interfaces/IAlertStore.cs | Alert store contract |
| src/DevBrain.Core/Interfaces/IAlertSink.cs | Alert sink contract |
| src/DevBrain.Core/Enums/MilestoneType.cs | Growth milestone types |
| src/DevBrain.Core/Enums/MatchStrategy.cs | Alert matching strategies |
| src/DevBrain.Core/Enums/DecisionStepType.cs | Decision chain step types |
| src/DevBrain.Cli/Program.cs | Register new CLI commands |
| src/DevBrain.Cli/Commands/StoryCommand.cs | CLI for session stories |
| src/DevBrain.Cli/Commands/StopCommand.cs | Tray coordination via sentinel |
| src/DevBrain.Cli/Commands/StartCommand.cs | Avoid conflicting with tray manager |
| src/DevBrain.Cli/Commands/ReplayCommand.cs | CLI for decision replay |
| src/DevBrain.Cli/Commands/GrowthCommand.cs | CLI for growth reporting/reset |
| src/DevBrain.Cli/Commands/BlastCommand.cs | CLI for blast radius analysis |
| src/DevBrain.Cli/Commands/AlertsCommand.cs | CLI for alert listing/dismiss |
| src/DevBrain.Api/Services/AlertChannel.cs | SSE channel for alert streaming |
| src/DevBrain.Api/Program.cs | Wire stores/agents/endpoints |
| src/DevBrain.Api/Endpoints/SessionEndpoints.cs | Sessions/story endpoints |
| src/DevBrain.Api/Endpoints/ReplayEndpoints.cs | Replay endpoints for file/decision |
| src/DevBrain.Api/Endpoints/GrowthEndpoints.cs | Growth endpoints |
| src/DevBrain.Api/Endpoints/BlastRadiusEndpoints.cs | Blast radius endpoint |
| src/DevBrain.Api/Endpoints/AlertEndpoints.cs | Alerts endpoints + SSE stream |
| src/DevBrain.Agents/StorytellerAgent.cs | Generate session narratives |
| src/DevBrain.Agents/DevBrain.Agents.csproj | Add Cronos + test visibility |
| src/DevBrain.Agents/DejaVuAgent.cs | Fire alerts from dead-end matches |
| src/DevBrain.Agents/DecisionChainAgent.cs | Link decisions + resolve dead ends |
| src/DevBrain.Agents/DeadEndAgent.cs | Typed payload for persisted outputs |
| src/DevBrain.Agents/CompressionAgent.cs | Use centralized prompt templates |
| src/DevBrain.Agents/BriefingAgent.cs | Use centralized prompt templates |
| src/DevBrain.Agents/AgentScheduler.cs | Cron scheduling + dead-end persistence |
| packages/winget/DevBrain.DevBrain.yaml | winget manifest for installer |
| packages/tray/tsconfig.json | Tray TS compiler config |
| packages/tray/src/paths.ts | Tray filesystem/binary path helpers |
| packages/tray/src/notifications.ts | Tray notifications wrapper |
| packages/tray/src/main.ts | Electron tray UX + lifecycle |
| packages/tray/src/health.ts | Daemon health polling |
| packages/tray/src/daemon.ts | Daemon start/stop/restart + crash loop |
| packages/tray/src/bootstrap.ts | First-run bootstrap (config + Ollama) |
| packages/tray/package.json | Tray scripts/deps |
| packages/tray/jest.config.js | Tray Jest config |
| packages/tray/electron-builder.yml | Electron packaging config |
| packages/tray/build/linux-after-remove.sh | Linux uninstall hooks |
| packages/tray/build/linux-after-install.sh | Linux install hooks |
| packages/tray/build/installer.nsh | Windows NSIS customization |
| packages/tray/assets/icon.png | Tray icon asset |
| packages/tray/assets/icon.ico | Windows icon asset |
| packages/tray/assets/icon.icns | macOS icon asset |
| packages/tray/assets/icon-yellow.png | Tray “starting” icon |
| packages/tray/assets/icon-red.png | Tray “unhealthy” icon |
| packages/tray/tests/health.test.ts | Health monitor tests |
| packages/tray/tests/daemon.test.ts | Daemon manager tests |
| packages/tray/tests/bootstrap.test.ts | Bootstrap tests |
| packages/homebrew/devbrain.rb | Homebrew formula for CLI binaries |
| packages/apt/debian/rules | Debian packaging rules |
| packages/apt/debian/prerm | Debian pre-remove script |
| packages/apt/debian/postinst | Debian post-install script |
| packages/apt/debian/devbrain.desktop | Autostart desktop entry |
| packages/apt/debian/control | Debian package metadata |
| package.json | Workspace root for tray/dashboard |
| dashboard/src/pages/Sessions.tsx | Sessions UI |
| dashboard/src/pages/Replay.tsx | Replay UI |
| dashboard/src/pages/Growth.tsx | Growth UI |
| dashboard/src/pages/BlastRadius.tsx | Blast radius UI |
| dashboard/src/pages/Alerts.tsx | Alerts UI |
| dashboard/src/components/Navigation.tsx | Add nav links |
| dashboard/src/components/AlertBanner.tsx | Alert polling banner |
| dashboard/src/App.tsx | Route new pages + banner |
| dashboard/src/api/client.ts | Client types + endpoints |
| CLAUDE.md | Updated build/workflow guidance |
| .gitignore | Ignore tray build/artifacts |
| .github/workflows/package.yml | Packaging CI workflow |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| FROM neighbors n | ||
| JOIN graph_edges e ON (e.source_id = n.node_id OR e.target_id = n.node_id) | ||
| {inClause} | ||
| WHERE n.depth < @hops | ||
| AND instr(n.path, CASE WHEN e.source_id = n.node_id THEN e.target_id ELSE e.source_id END) = 0 |
There was a problem hiding this comment.
The recursive CTE cycle check uses instr(n.path, <nextId>) = 0 while path is a comma-separated string of node IDs. This can produce false positives when one ID is a substring of another (e.g., ...,'1','11',...), incorrectly blocking traversal and returning incomplete neighbor sets. Consider storing the path with leading/trailing delimiters (e.g., ',' || id || ',') and checking instr(path, ',' || nextId || ',') = 0 (or use a dedicated visited table in the CTE).
| CREATE TABLE IF NOT EXISTS deja_vu_alerts ( | ||
| id TEXT PRIMARY KEY, | ||
| thread_id TEXT NOT NULL, | ||
| matched_dead_end_id TEXT NOT NULL, | ||
| confidence REAL NOT NULL, |
There was a problem hiding this comment.
deja_vu_alerts has no uniqueness constraint for (thread_id, matched_dead_end_id). Since deduplication currently relies on a separate Exists() check, concurrent agent runs can still insert duplicate active alerts. Consider enforcing this at the DB level via a UNIQUE index (ideally a partial unique index like UNIQUE(thread_id, matched_dead_end_id) WHERE dismissed = 0) and handling constraint violations gracefully in the store.
| cmd.CommandText = """ | ||
| INSERT OR IGNORE INTO session_summaries (id, session_id, narrative, outcome, | ||
| duration_seconds, observation_count, files_touched, dead_ends_hit, | ||
| phases, created_at) | ||
| VALUES (@id, @sessionId, @narrative, @outcome, | ||
| @durationSeconds, @observationCount, @filesTouched, @deadEndsHit, | ||
| @phases, @createdAt) | ||
| """; |
There was a problem hiding this comment.
Add() uses INSERT OR IGNORE but always returns the passed-in summary without indicating whether the insert actually happened. With the session_id UNIQUE constraint, callers can believe a story was persisted when it was silently ignored. Consider using an UPSERT (ON CONFLICT(session_id) DO UPDATE), or check the affected row count and either return the existing row / throw to make the behavior explicit.
| var metrics = new List<DeveloperMetric>(); | ||
| foreach (var id in shell.MetricIds) | ||
| { | ||
| using var cmd = _connection.CreateCommand(); | ||
| cmd.CommandText = "SELECT * FROM developer_metrics WHERE id = @id"; | ||
| cmd.Parameters.AddWithValue("@id", id); | ||
| using var reader = await cmd.ExecuteReaderAsync(); | ||
| if (await reader.ReadAsync()) | ||
| metrics.Add(MapMetric(reader)); | ||
| } | ||
|
|
||
| var milestones = new List<GrowthMilestone>(); | ||
| foreach (var id in shell.MilestoneIds) | ||
| { | ||
| using var cmd = _connection.CreateCommand(); | ||
| cmd.CommandText = "SELECT * FROM milestones WHERE id = @id"; | ||
| cmd.Parameters.AddWithValue("@id", id); | ||
| using var reader = await cmd.ExecuteReaderAsync(); | ||
| if (await reader.ReadAsync()) | ||
| milestones.Add(MapMilestone(reader)); |
There was a problem hiding this comment.
HydrateReport() performs one SQL query per metric ID and milestone ID, which can become an N+1 pattern as reports grow (and it runs again in GetReports). Consider fetching all metrics/milestones in a single query each using WHERE id IN (...) (with generated parameters) and then re-ordering them to match the stored ID lists.
| this.process.on("exit", (code) => { | ||
| if (fs.existsSync(stoppedSentinelPath())) { | ||
| return; | ||
| } | ||
|
|
||
| if (code !== 0 && code !== null) { | ||
| this.recordCrash(); | ||
| this.onCrashCallback?.(); | ||
|
|
||
| if (this.shouldRestart()) { | ||
| this.start(); | ||
| } else { |
There was a problem hiding this comment.
The exit handler triggers an async restart via this.start() without awaiting/handling the returned promise. If start() fails (e.g., missing binary, filesystem issues), this can become an unhandled rejection and the manager may repeatedly try to restart without surfacing the error. Consider making the handler async and awaiting (or at least .catch(...)ing) the restart attempt.
| @@ -0,0 +1 @@ | |||
| placeholder | |||
There was a problem hiding this comment.
This file is committed as plain text (placeholder) but is referenced as the application icon by electron-builder. electron-builder/platform installers expect a valid PNG/ICO/ICNS binary; this will break packaging. Replace this placeholder with an actual icon asset (and ensure the platform-specific formats are valid).
| placeholder | |
| [REPLACE THIS FILE'S CONTENTS WITH A VALID PNG BINARY IMAGE, NOT TEXT. For example, overwrite `packages/tray/assets/icon.png` with the real application icon exported as PNG.] |
| @@ -0,0 +1 @@ | |||
| placeholder | |||
There was a problem hiding this comment.
This is committed as plain text (placeholder) but is configured as the Windows icon (win.icon / nsis.installerIcon) in electron-builder. Windows packaging expects a valid .ico binary; this will fail during build or produce a broken installer icon. Replace with a real ICO asset.
| placeholder | |
| [binary ICO asset data replacing the entire file] |
| @@ -0,0 +1 @@ | |||
| placeholder | |||
There was a problem hiding this comment.
This is committed as plain text (placeholder) but is configured as the macOS app icon (mac.icon) in electron-builder. macOS packaging expects a valid .icns binary; replace this placeholder with a real icon file to avoid build failures / missing icons.
| placeholder | |
| <replace this placeholder file with the actual binary contents of a valid macOS .icns icon file> |
| @@ -0,0 +1 @@ | |||
| placeholder | |||
There was a problem hiding this comment.
The tray uses this asset for the unhealthy (red) status icon, but it is committed as plain text (placeholder) rather than a valid PNG. Replace with a real PNG to avoid runtime failures when nativeImage.createFromPath loads the icon.
| placeholder | |
| <replace this file's contents with a valid PNG binary for the red status icon; the current text placeholder must not remain> |
| this.process.on("exit", (code) => { | ||
| if (fs.existsSync(stoppedSentinelPath())) { | ||
| return; | ||
| } | ||
|
|
||
| if (code !== 0 && code !== null) { | ||
| this.recordCrash(); | ||
| this.onCrashCallback?.(); | ||
|
|
There was a problem hiding this comment.
The exit handler only treats non-zero numeric exit codes as crashes (code !== 0 && code !== null). If the daemon terminates via signal (where code is null and a signal is provided), it will be treated as a non-crash and won’t restart, potentially leaving the tray thinking the daemon is down with no recovery. Consider handling the signal argument (and/or treating code === null as a crash unless the stopped sentinel is present).
Critical: - Ollama install: prefer winget/brew over raw downloads, add Authenticode signature verification on Windows, remove curl|sh on macOS (require brew) - GPG key: use temp file with restricted permissions instead of echo High: - PID reuse: verify process name before killing (tasklist/ps check) - Daemon stderr: redirect to log file for debugging startup failures - electron-builder: set explicit output directory, fix CI artifact paths - StopCommand: verify process name matches devbrain-daemon before kill Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Key Changes
Wow Features (20 commits)
Packaging (14 commits)
packages/tray/) with health monitor, daemon manager, bootstrap orchestratortray.lock+stoppedsentinelpackage.yml) for Electron build + package manager publishingdocs/superpowers/Test plan
dotnet build DevBrain.slnx)cd packages/tray && npm run build)electron-builder --dirproduces unpacked apppackage.ymlworkflow triggers correctly on tag push🤖 Generated with Claude Code