{"items":[{"id":"cedd107e-8324-4bd1-8c76-393331655e12","type":"pull_request","org":"EpicenterHQ","repo":"epicenter","title":"Server gets streaming AI chat","summary":"New `/ai/chat` SSE endpoint lets the extension stream LLM responses via TanStack AI without ever embedding or storing API keys client-side. Supports OpenAI, Anthropic, Gemini, Grok, and local Ollama out of the box, with per-request `x-provider-api-key` passthrough, solid abort handling (no orphaned calls), and clear error codes (401/499/502).","url":"https://nomit.dev/EpicenterHQ/epicenter/status/dd38a80544bcd719239a4d904746180d94f7dd865a3d732f7ee89eb5d7c861c1","author":"braden-w","contributors":["braden-w"],"updated_at":"2026-02-20T23:59:25+00:00"},{"id":"99ce1843-047d-46f3-ba97-b6b91835c6de","type":"pull_request","org":"EpicenterHQ","repo":"epicenter","title":"Flattened Extension API + lifecycle fix","summary":"Big refactor: extension factories now return a single flat object (`{...exports, whenReady?, destroy?}`) and a new `defineExtension()` normalizer guarantees consistent `whenReady` + `destroy` handling. This improves extension ergonomics and fixes a real bug where sqlite cleanup was being silently dropped—users should see more reliable teardown and a cleaner API surface.","url":"https://nomit.dev/EpicenterHQ/epicenter/status/25840672ee207710f35460f27c5dcd914c0185c6cb3537eb8a17fd62ea70b345","author":"braden-w","contributors":["braden-w"],"updated_at":"2026-02-20T23:55:57+00:00"},{"id":"d11179f3-73cb-4509-88f6-9c52dc0569a2","type":"pull_request","org":"EpicenterHQ","repo":"epicenter","title":"DocumentHandle API lands in static","summary":"Static bindings now return a DocumentHandle from `open()`, so you open once and do sync `read()`/`write()`, exports, and lifecycle ops off the handle—no more threading the same ID through every call. `destroy` is renamed to `close` (memory cleanup without nuking persisted data), and extensions get a typed `extensions` map + `whenReady` for better interop. Big ergonomics + clarity win for callers building document workflows.","url":"https://nomit.dev/EpicenterHQ/epicenter/status/200a1c532592e6ac2b5c61067fbfc69dc97600f52fce8c561a89ba979f892191","author":"braden-w","contributors":["braden-w"],"updated_at":"2026-02-20T23:55:39+00:00"},{"id":"e58bc35a-dadc-4705-943f-dbf10c52fc3d","type":"push","org":"EpicenterHQ","repo":"epicenter","title":"Sync endpoints simplified to one URL","summary":"Sync routes were refactored so rooms live at a single canonical path: `/rooms/:id` now handles WS upgrade + GET/POST doc state (replacing `/sync` + `/doc`). This makes client configs simpler and more REST-y—but it’s a breaking change for anyone still pointing at the old `/rooms/{id}/sync` or `/rooms/{id}/doc` URLs. ⚠️","url":"https://nomit.dev/EpicenterHQ/epicenter/status/44376d58534ab1392b3cf78060e004a171fd583e0f537b196354371b13d58ff6","author":"braden-w","contributors":["braden-w"],"updated_at":"2026-02-20T23:47:48+00:00"},{"id":"93055ce2-9e92-46dc-a8cd-1b005c89cd9b","type":"push","org":"EpicenterHQ","repo":"epicenter","title":"Extension API flattened + lifecycle fix","summary":"Big refactor: Extensions now return a flat object ({ ...exports, whenReady?, destroy? }) instead of nested { exports, lifecycle }, with an internal normalizer ensuring whenReady is always a Promise and destroy is always callable—so you can await per-extension readiness via extensions.X.whenReady. This also fixes a real bug where sqlite’s top-level destroy hook was being dropped, improving cleanup reliability across workspaces. 🚀","url":"https://nomit.dev/EpicenterHQ/epicenter/status/72ce6857a07f28ffce12f6fba296721500e574c8e42772d8d129a082e2fa9857","author":"braden-w","contributors":["braden-w"],"updated_at":"2026-02-20T23:44:08+00:00"}],"pagination":{"offset":0,"limit":5,"has_more":true}}