Skip to content
Open
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
683 commits
Select commit Hold shift + click to select a range
a9fba26
feat(computer-use): make supervisor window resizable
alichherawalla Aug 28, 2026
11b3c6a
chore(pro): wire saved task playback
alichherawalla Aug 28, 2026
51e4de5
feat(tasks): materialize synced visual steps
alichherawalla Aug 28, 2026
b1623ae
chore(pro): wire fixed Computer Use live PiP
alichherawalla Aug 28, 2026
b4e597c
feat(navigation): route internal tabs
alichherawalla Aug 28, 2026
98ec30e
chore(pro): wire routed tabs
alichherawalla Aug 28, 2026
8e21fcc
chore(pro): wire immediate task sync
alichherawalla Aug 28, 2026
757e419
chore(pro): wire task playback evidence pane
alichherawalla Aug 28, 2026
8d04f3d
fix(settings): refresh open chat projections
alichherawalla Aug 28, 2026
b027bd6
fix(actions): run Chat mutations through engine
alichherawalla Aug 28, 2026
5e3040c
fix(notifications): keep approvals in Actions
alichherawalla Aug 28, 2026
6fb5eab
fix(tasks): ignore stale attention events
alichherawalla Aug 28, 2026
d43b47e
fix(chat): block resend during active replies
alichherawalla Aug 28, 2026
c19be2f
fix(computer-use): make PiP visibility reversible
alichherawalla Aug 28, 2026
c86d132
fix(connectors): run Chat mutations through engine
alichherawalla Aug 28, 2026
c6c04cd
fix(notifications): remove approval route
alichherawalla Aug 28, 2026
69c3b15
fix(chat): restore thinking and cancel transcription
alichherawalla Aug 28, 2026
0949d7d
fix(computer-use): bound repeated focus clicks
alichherawalla Aug 28, 2026
bae7fb9
chore(pro): update Computer Use PiP plan
alichherawalla Aug 28, 2026
3ae7e7d
test(voice): exercise request-scoped transcription IPC
alichherawalla Aug 29, 2026
cb68e58
fix(computer-use): exclude supervisor from capture
alichherawalla Aug 29, 2026
314aba2
fix(navigation): preserve internal tab routes
alichherawalla Aug 29, 2026
79c565d
fix(computer-use): exclude supervisor with native capture
alichherawalla Aug 29, 2026
aa71141
test(computer-use): exercise native excluded capture
alichherawalla Aug 29, 2026
60fe1ad
style(computer-use): format capture boundary
alichherawalla Aug 29, 2026
ca0a3f0
test(release): require Computer Use capture helper
alichherawalla Aug 29, 2026
d752d17
refactor(actions): keep task approval source-owned
alichherawalla Aug 29, 2026
e3a8127
fix(mcp): enforce selected Desktop task target
alichherawalla Aug 29, 2026
d715514
chore(pro): wire accurate approval presentation
alichherawalla Aug 29, 2026
d4cb077
style(mcp): format target validation journey
alichherawalla Aug 29, 2026
4b509dc
test(pro): wire settings approval migration
alichherawalla Aug 29, 2026
49a1682
fix(voice): stop cancelled resident inference
alichherawalla Aug 29, 2026
6608694
refactor(browser): remove superseded semantic runtime
alichherawalla Aug 29, 2026
e152a1f
fix(privacy): gate remote screen image sharing
alichherawalla Aug 29, 2026
fd2660f
fix(chat): preflight remote tool support
alichherawalla Aug 29, 2026
e20f258
feat(computer-use): orchestrate text plus specialist
alichherawalla Aug 29, 2026
1242001
test(computer-use): cover hybrid Electron journey
alichherawalla Aug 29, 2026
b9541b2
fix(privacy): bind screen tasks to one model session
alichherawalla Aug 29, 2026
8c6e4c2
fix(voice): recover Hindi transcription script
alichherawalla Aug 29, 2026
6cf3e1f
chore(pro): include Web Use live controls
alichherawalla Aug 29, 2026
bd79188
fix(tasks): retain authenticated launch identity
alichherawalla Aug 29, 2026
710554c
chore(pro): include bounded sync invalidation
alichherawalla Aug 29, 2026
6398a07
chore(pro): include sync heartbeat regression proof
alichherawalla Aug 29, 2026
86b72ec
chore(pro): include authenticated task launch ordering
alichherawalla Aug 29, 2026
7892680
fix(sync): expose task launch entity to Pro
alichherawalla Aug 29, 2026
4314b4a
test(computer-use): exercise macOS capture in CI
alichherawalla Aug 29, 2026
4f4612a
test(voice): complete Electron sender boundary
alichherawalla Aug 29, 2026
952a30a
test(voice): allow native UI journey time in CI
alichherawalla Aug 29, 2026
9f4400c
test(ci): stabilize voice and capture DB journeys
alichherawalla Aug 29, 2026
1622274
chore(pro): include release 107 DB fixture fixes
alichherawalla Aug 29, 2026
2bd749c
test(routes): wait for Models view transitions
alichherawalla Aug 29, 2026
d1dabf5
chore(pro): include stable ambient sharing gate
alichherawalla Aug 29, 2026
c8ab2ec
fix(ci): probe Electron SQLite across platforms
alichherawalla Aug 29, 2026
7bb5359
fix(tasks): isolate retry runtime composition
alichherawalla Aug 29, 2026
bee5173
test(tasks): boot the production task composition
alichherawalla Aug 29, 2026
87a287e
test(voice): allow native speech startup under CI load
alichherawalla Aug 29, 2026
d70b04e
fix(health): isolate idle chat status probe
alichherawalla Aug 29, 2026
8220c98
fix(sync): consume semantic invalidations
alichherawalla Aug 29, 2026
653ad6c
fix(chat): remove idle model and settings churn
alichherawalla Aug 29, 2026
0e82736
fix(sync): use semantic shared-file status
alichherawalla Aug 29, 2026
a849e9f
fix(chat): keep meeting search summaries accurate
alichherawalla Aug 29, 2026
0c98622
fix(sync): keep notification reads scoped
alichherawalla Aug 29, 2026
16a00ce
fix(health): publish model lifecycle status
alichherawalla Aug 29, 2026
c95f2a2
feat(models): link active models and settings panels
alichherawalla Aug 29, 2026
82a1c07
ui: compact remote server settings
alichherawalla Aug 29, 2026
c58e3fe
perf(computer-use): keep remote specialist resident
alichherawalla Aug 29, 2026
7663481
fix(chat): preserve task outcomes in work status
alichherawalla Aug 29, 2026
ab1aaef
fix(models): use standard panel close controls
alichherawalla Aug 29, 2026
9c82990
fix(computer-use): recover through app launcher
alichherawalla Aug 29, 2026
3ff6bfc
feat(models): offer Holo 4B for computer use
alichherawalla Aug 29, 2026
c405488
fix(tasks): return chat control immediately
alichherawalla Aug 29, 2026
4d237ed
refactor(tasks): persist shared automation vocabulary
alichherawalla Aug 29, 2026
a52569e
feat(web-use): harden Playwright boundary
alichherawalla Aug 29, 2026
1bc53bf
fix(automation): unify task lifecycle controls
alichherawalla Aug 29, 2026
c266ada
fix(computer-use): target native apps before vision
alichherawalla Aug 29, 2026
041780e
fix(computer-use): retain accessibility frames
alichherawalla Aug 29, 2026
75bb63c
fix(health): stop idle full-system polling
alichherawalla Aug 29, 2026
76210ca
fix(sync): acknowledge settled peer records
alichherawalla Aug 30, 2026
3e02a40
fix(web-use): attach browser pages to a context
alichherawalla Aug 30, 2026
da3052d
feat(navigation): keep sidebar sections consistent at both widths
alichherawalla Aug 30, 2026
7385e41
fix(web-use): harden task controls and semantic evidence
alichherawalla Aug 30, 2026
a64fc6b
feat(computer-use): complete native task execution controls
alichherawalla Aug 30, 2026
130adad
feat(models): add Release 107 remote model parity
alichherawalla Aug 30, 2026
0d6bd3f
feat(runtime): secure remote tools and proposal workflows
alichherawalla Aug 30, 2026
36ab27c
docs(release): update Release 107 gates and Pro revision
alichherawalla Aug 30, 2026
6892a54
test(release): align task control journeys
alichherawalla Aug 30, 2026
1693a40
test(e2e): dismiss optional model setup nudge
alichherawalla Aug 30, 2026
0611b09
test(models): use stable unavailable fixture
alichherawalla Aug 30, 2026
d55b1dd
test(input): cover native actuation contract
alichherawalla Aug 30, 2026
ba1a067
test(coverage): measure input adapter once
alichherawalla Aug 30, 2026
bcb86a0
fix(release): close desktop verification gates
alichherawalla Aug 30, 2026
3c9c868
fix(web-use): remove task support dependency cycle
alichherawalla Aug 30, 2026
ca73a4f
feat(command-palette): index internal subroutes
alichherawalla Aug 30, 2026
423bbd3
chore(pro): update sync mesh services
alichherawalla Aug 30, 2026
c9ee4af
fix(tasks): preserve execution plans across state updates
alichherawalla Aug 31, 2026
33dbd15
fix(tasks): keep synced task evidence readable
alichherawalla Aug 31, 2026
5071d99
feat(explore): collect run briefs in chat
alichherawalla Aug 31, 2026
ca04e4f
feat(chat): review actions before task start
alichherawalla Aug 31, 2026
b6011b2
feat(explore): compact flows and recommend connectors
alichherawalla Aug 31, 2026
69fadf8
fix(explore): honor connected Gmail status
alichherawalla Aug 31, 2026
f0c795c
fix(actions): project chat task results to approvals
alichherawalla Aug 31, 2026
6d5e103
feat(models): configure maximum tool calls
alichherawalla Aug 31, 2026
1fb9994
fix(models): sync remote desktop selection to mobile
alichherawalla Aug 31, 2026
8e712bd
fix(gateway): honor remote transcription language
alichherawalla Aug 31, 2026
c5907d0
fix(gateway): route mobile chat to selected remote model
alichherawalla Aug 31, 2026
3c694e2
fix(gateway): publish remote model capabilities
alichherawalla Aug 31, 2026
c7a9068
refactor(models): compose desktop model service
alichherawalla Sep 1, 2026
cb18341
refactor(models): persist canonical desktop routes
alichherawalla Sep 1, 2026
cc2532c
refactor(llm): expose route-specific generation engines
alichherawalla Sep 1, 2026
053e83e
refactor(models): expose remote route transport
alichherawalla Sep 1, 2026
8333d11
refactor(models): compose desktop generation adapters
alichherawalla Sep 1, 2026
56d0d2f
refactor(chat): route desktop streams through shared generation
alichherawalla Sep 1, 2026
617b54a
refactor(web-use): route semantic decisions through shared generation
alichherawalla Sep 1, 2026
9553d26
refactor(models): publish desktop policy routes
alichherawalla Sep 1, 2026
4ecadf0
refactor(generation): add desktop shared client boundary
alichherawalla Sep 1, 2026
5b3c266
refactor(ipc): route generation through desktop client
alichherawalla Sep 1, 2026
897c842
refactor(rag): route image captions through generation service
alichherawalla Sep 1, 2026
5255126
refactor(tasks): route plan generation through shared service
alichherawalla Sep 1, 2026
a1d5c50
refactor(mcp): route text generation through shared service
alichherawalla Sep 1, 2026
eb8e837
feat(models): integrate shared reasoning policy
alichherawalla Sep 1, 2026
b946ce2
refactor(tools): route generation through shared service
alichherawalla Sep 1, 2026
19f803f
docs(planner): describe shared decision route
alichherawalla Sep 1, 2026
1609b79
refactor(actions): route desktop decisions through shared generation
alichherawalla Sep 1, 2026
c47abd4
refactor(models): route desktop multimodal generation
alichherawalla Sep 1, 2026
118a0f2
test(vision): exercise shared generation boundary
alichherawalla Sep 1, 2026
80e3fe9
refactor(actions): project shared computer use policy
alichherawalla Sep 1, 2026
961f2f0
refactor(models): centralize desktop residency decisions
alichherawalla Sep 1, 2026
91dddb9
refactor(models): remove duplicate chat admission
alichherawalla Sep 1, 2026
8924231
refactor(rag): consume shared domain package
alichherawalla Sep 1, 2026
9761ed7
fix(tests): run sqlite suites on Electron ABI
alichherawalla Sep 1, 2026
1003dfe
refactor(models): consume shared gateway contracts
alichherawalla Sep 1, 2026
68b0261
docs(tests): require ABI-safe Vitest runner
alichherawalla Sep 1, 2026
c3a266a
refactor(llm): use shared text runtime policy
alichherawalla Sep 1, 2026
b84880f
refactor(models): consume shared transcription policy
alichherawalla Sep 1, 2026
4d7d81a
refactor(models): share image runtime policy
alichherawalla Sep 1, 2026
5c7911e
refactor(remote): use shared server identity policy
alichherawalla Sep 1, 2026
e9c68e5
refactor(models): share desktop tool policy
alichherawalla Sep 1, 2026
b92d755
refactor(tools): use shared core schemas
alichherawalla Sep 1, 2026
aa5c226
fix(tools): honor emergency call limit
alichherawalla Sep 1, 2026
7f10a40
refactor(transcription): route native engines through generation
alichherawalla Sep 1, 2026
76e9b27
chore(pro): update shared generation integration
alichherawalla Sep 1, 2026
ee46d1a
fix(tools): reuse shared embedding cache
alichherawalla Sep 1, 2026
8378351
fix(rag): match shared async lookup port
alichherawalla Sep 1, 2026
b5b4e4b
refactor(models): enforce shared execution boundaries
alichherawalla Sep 1, 2026
ddb8043
chore(pro): update async RAG sync contract
alichherawalla Sep 1, 2026
f6fac9b
chore(pro): update state sync materialization
alichherawalla Sep 1, 2026
feee515
test(desktop): repair shutdown and ASAR fixtures
alichherawalla Sep 1, 2026
50c49bd
test(desktop): register compatible generation routes
alichherawalla Sep 1, 2026
c518f87
fix(models): preserve thinking on tool-selection routes
alichherawalla Sep 1, 2026
f19a1a4
test(models): preserve remote planner reasoning route
alichherawalla Sep 1, 2026
2e0cba1
fix(models): persist canonical image selection
alichherawalla Sep 1, 2026
376071e
test(desktop): expect balanced image co-residency
alichherawalla Sep 1, 2026
52195a4
fix(pro): preserve bottom-aware computer use view
alichherawalla Sep 1, 2026
762ee5c
chore(pro): update CRM generation tests
alichherawalla Sep 1, 2026
90903c0
test(desktop): compose visual lifecycle boundaries
alichherawalla Sep 1, 2026
377d56f
fix(models): migrate Holo out of chat routing
alichherawalla Sep 1, 2026
7086e57
test(models): provide routed fake inventory
alichherawalla Sep 1, 2026
3f032a2
chore(pro): advance shared control plane
alichherawalla Sep 1, 2026
ffa58d0
test(desktop): await Web Use chat boundary
alichherawalla Sep 1, 2026
0e9ed7c
fix(tests): select XCTest for Swift gate
alichherawalla Sep 1, 2026
b13747a
test(packaging): complete macOS helper fixtures
alichherawalla Sep 1, 2026
d053c68
fix(e2e): bind Playwright test runner
alichherawalla Sep 1, 2026
ee28625
fix(models): preserve canonical gateway routes
alichherawalla Sep 1, 2026
4ae519c
fix(models): admit startup text runtime through residency
alichherawalla Sep 1, 2026
7545b2c
refactor(models): centralize desktop selection writes
alichherawalla Sep 1, 2026
99c5919
Route grounder swaps through model residency
alichherawalla Sep 1, 2026
93c8fef
refactor(models): delegate download policy to shared
alichherawalla Sep 1, 2026
7da2dbc
refactor(imagegen): use shared download adapter
alichherawalla Sep 1, 2026
782376b
refactor(models): reduce downloads to native adapters
alichherawalla Sep 1, 2026
28044fc
refactor(models): unify desktop selection authority
alichherawalla Sep 1, 2026
41ec47a
refactor(chat): route desktop turns through shared session
alichherawalla Sep 1, 2026
68954f2
refactor(chat): route desktop tool turns through shared session
alichherawalla Sep 1, 2026
aa7507d
refactor(models): use residency leases
alichherawalla Sep 1, 2026
17a4945
refactor(chat): route desktop image turns through shared session
alichherawalla Sep 1, 2026
ae9cde6
refactor(chat): delegate main orchestration policy
alichherawalla Sep 1, 2026
5e99486
refactor(chat): use shared queue and persist canonical turns
alichherawalla Sep 1, 2026
3dce7db
refactor(chat): delegate desktop replay to shared session
alichherawalla Sep 1, 2026
08ab4d4
refactor(chat): remove legacy desktop queue
alichherawalla Sep 1, 2026
d49df42
refactor(llm): make desktop text runtime an adapter
alichherawalla Sep 1, 2026
df0b94a
refactor(models): thin desktop multimodal adapters
alichherawalla Sep 1, 2026
7ed8316
refactor(image): route lifecycle through shared owner
alichherawalla Sep 1, 2026
2fc696a
refactor(llm): thin text stream adapters
alichherawalla Sep 1, 2026
0606f10
feat(models): route desktop media through shared control plane
alichherawalla Sep 1, 2026
b1ebdaf
refactor(llm): remove legacy text routes
alichherawalla Sep 1, 2026
c6f1792
refactor(sync): route Pro model control through shared services
alichherawalla Sep 1, 2026
b3e220d
refactor(sync): share portable model settings policy
alichherawalla Sep 1, 2026
0d6c4ce
feat(models): complete desktop remote media control plane
alichherawalla Sep 1, 2026
9e7ed03
test(models): enforce desktop architecture boundaries
alichherawalla Sep 1, 2026
aee85c9
refactor(models): inject Hugging Face transport
alichherawalla Sep 1, 2026
b451f71
refactor(models): close desktop architecture bypasses
alichherawalla Sep 1, 2026
0809821
refactor(models): share transfer manifest policy
alichherawalla Sep 1, 2026
bfe3eab
refactor(models): remove active model compatibility owner
alichherawalla Sep 1, 2026
af4a1fd
test(architecture): recognize Electron original-fs boundary
alichherawalla Sep 1, 2026
f0386f2
refactor(models): delegate activation reconciliation policy
alichherawalla Sep 1, 2026
e11ced8
chore(pro): advance remote tool policy
alichherawalla Sep 1, 2026
a7f559e
refactor(models): remove desktop runtime cycles
alichherawalla Sep 1, 2026
edc896b
refactor(models): consume shared LLM defaults
alichherawalla Sep 1, 2026
a6fbfdd
fix(desktop): align regression tests with shared model services
alichherawalla Sep 1, 2026
173600e
docs(models): document shared desktop boundary
alichherawalla Sep 1, 2026
9677094
refactor(desktop): unify chat generation boundary
alichherawalla Sep 1, 2026
0df3095
refactor(desktop): route tool policy through shared models
alichherawalla Sep 1, 2026
4b03414
refactor(desktop): use shared image application service
alichherawalla Sep 1, 2026
d68898a
refactor(models): delegate model library workflows
alichherawalla Sep 1, 2026
638da4c
docs(models): record platform integration sweep
alichherawalla Sep 1, 2026
aa1f6ef
refactor(models): delegate guided setup to shared
alichherawalla Sep 1, 2026
7e4ddff
refactor(models): use shared remote control policy
alichherawalla Sep 1, 2026
918ac88
fix(models): route desktop startup through shared residency
alichherawalla Sep 1, 2026
932a299
make desktop image runtime a native adapter
alichherawalla Sep 1, 2026
6ba4d46
fix(models): use shared settings sync codec
alichherawalla Sep 1, 2026
7c51e29
refactor(models): remove residency lifecycle alias
alichherawalla Sep 1, 2026
3e559c6
refactor(models): project shared text configuration
alichherawalla Sep 1, 2026
ce4e6ec
test(models): expect versioned settings envelope
alichherawalla Sep 1, 2026
000e313
refactor(models): use shared runtime text defaults
alichherawalla Sep 1, 2026
d6b7ebb
delegate desktop model integrity to shared
alichherawalla Sep 1, 2026
2109bb1
docs(models): remove retired voice catalog guidance
alichherawalla Sep 1, 2026
c1d1b69
refactor(desktop): project shared engine lifecycle
alichherawalla Sep 1, 2026
8466df2
refactor(rag): consume shared runtime profile
alichherawalla Sep 1, 2026
4bbf68a
refactor(desktop): execute shared computer use policy
alichherawalla Sep 1, 2026
32d3495
refactor(models): route desktop remote control through shared
alichherawalla Sep 1, 2026
c21e154
refactor(models): route UI activation through shared commands
alichherawalla Sep 1, 2026
38181e1
test(models): guard shared activation ownership
alichherawalla Sep 1, 2026
3ebbd9a
refactor(desktop): consume shared tool orchestration
alichherawalla Sep 1, 2026
7ec4ffc
test(desktop): guard shared tool orchestration
alichherawalla Sep 1, 2026
602d135
refactor(models): canonical catalog identity, download recovery and r…
alichherawalla Sep 2, 2026
d51bb6a
fix(imagegen): owned-path identity, durable sidecar commit and typed …
alichherawalla Sep 2, 2026
7e34523
fix(vision): fail-closed vision availability and model admission
alichherawalla Sep 2, 2026
716380d
refactor(generation): cancellation awaits native result and typed met…
alichherawalla Sep 2, 2026
d1b3d87
refactor(tools): shared tool orchestration and connector policy
alichherawalla Sep 2, 2026
cb9b268
refactor(ipc): typed model-control preload port
alichherawalla Sep 2, 2026
d93d82a
test(main): model-control, imagegen and generation integration coverage
alichherawalla Sep 2, 2026
4aa7306
refactor(renderer): model-control application service over the typed …
alichherawalla Sep 2, 2026
68eba36
refactor(renderer): chat, model picker and settings consume canonical…
alichherawalla Sep 2, 2026
c821e25
test(e2e): screen-recording precondition guard and model-control jour…
alichherawalla Sep 2, 2026
f3f9716
chore(desktop): architecture gate and coverage script updates
alichherawalla Sep 2, 2026
4de1ea0
chore(pro): bump desktop-pro to model-control consolidation
alichherawalla Sep 2, 2026
1730d41
fix(models): reclassification reads the canonical selection routes
alichherawalla Sep 2, 2026
359bc3c
chore(pro): bump desktop-pro with typecheck and fixture fixes
alichherawalla Sep 2, 2026
02bcf7e
refactor(update): one owner for the GitHub release provider
alichherawalla Sep 2, 2026
93ea944
test(e2e): skip the packaged rollback journey when the live release f…
alichherawalla Sep 2, 2026
e513c18
test(e2e): image cancel journey takes the real Run anyway path under …
alichherawalla Sep 2, 2026
ddb56ff
test(e2e): skip the image cancel journey when the shared admission ru…
alichherawalla Sep 2, 2026
4ec5def
test(e2e): refresh screenshots from the latest green journeys
alichherawalla Sep 2, 2026
39a5fa4
fix(main): mint turn and notification ids with randomUUID instead of …
alichherawalla Sep 2, 2026
75eb108
ci: build every shared package desktop depends on, so @offgrid/rag ty…
alichherawalla Sep 2, 2026
970106c
docs: mirror the shared doctrine (shared owns model business logic)
alichherawalla Sep 2, 2026
5370e5c
docs: rules live in rules.md; CLAUDE.md is a pointer; bump desktop-pr…
alichherawalla Sep 2, 2026
2c66f26
ci: stop rebuilding SQLite for plain Node; the vitest runner is Elect…
alichherawalla Sep 2, 2026
303ceb6
test: one harness makes the real local text route ready over the fake…
alichherawalla Sep 2, 2026
0ca956d
docs: mirror the shared doctrine (where the logs live)
alichherawalla Sep 2, 2026
7e58f89
chore: bump desktop-pro (CRM + Day tests ready the fake text route; d…
alichherawalla Sep 2, 2026
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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
npm --prefix ../shared ci
npm --prefix ../shared/packages/sync run build
npm --prefix ../shared/packages/models run build
npm --prefix ../shared/packages/speech run build
- run: npm ci
# Hard gates: types + the full test suite.
- name: Typecheck (core)
Expand All @@ -116,6 +117,12 @@ jobs:
if: ${{ hashFiles('pro/tsconfig.json') != '' }}
timeout-minutes: 6
run: cd pro && npx tsc --noEmit -p tsconfig.json
# npm's Electron install hooks leave sqlite compiled for Electron's ABI. The
# Vitest process is plain Node, and some default integration tests open the
# real database, so put the native module on Node's ABI before that gate.
# The later DB journey script restores the Electron ABI in its EXIT trap.
- name: Rebuild SQLite for the Node test runner
run: npm rebuild better-sqlite3-multiple-ciphers
# Runs the full vitest suite AND enforces the coverage ratchet floor
# (vitest.config.ts `thresholds`) — the same gate as the pre-push hook, so a
# coverage regression fails CI, not just local pushes. The pro/** threshold
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The window is WIDE. A list of cards/rows stretched edge-to-edge in a single colu
- **Tight, consistent spacing on a 4/8/12px scale.** Dense data UIs use narrow gutters (8-12px) and small padding, NOT the 16-24px editorial spacing. Body text ~12-14px, compact line-height. Flat and sharp, per the brand.
- **Group, then separate.** Reduce gaps _within_ a group (rows in a section) but keep clear separation _between_ functional groups (filters vs data, "On this device" vs "Available"). Section headers over a wall of identical rows.
- **Progressive disclosure.** Secondary info and rarely-used controls go behind a detail panel / "…" / hover affordance — don't lay everything flat. Master list stays scannable; depth lives in the side panel or slide-over.
- **Side panels, not desktop modals.** Open settings, editors, previews, and other multi-step detail flows in the shared `SidePanel`. It must close with Escape, an outside click, and its close control. Reserve a centered dialog only for a short confirmation that blocks one immediate action, such as confirming a destructive delete.
- **Sticky context.** Fix headers, tabs, filter bars, and column labels while the body scrolls, so context never scrolls away.
- **Finesse the interactions.** Every click gets a small micro-interaction — `transition-all duration-150`, `active:scale-95` on buttons, slide+fade (not abrupt mount) for panels/slide-overs. State changes animate; nothing pops in or out hard.
- **Offer density where it matters**, but the default IS dense — this is a terminal/brutalist desktop app, not a spacious mobile-first card feed.
Expand Down
26 changes: 26 additions & 0 deletions docs/GAPS_BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1286,3 +1286,29 @@ Follow up with an isolated physical-device benchmark on a strong 5 GHz or 6 GHz
desktop-to-phone transfer at a time, separate checksum preparation from wire time, and compare both
directions. Also persist verified file checksums so a repeat send does not hash the same multi-GB
model again after an app restart. Keep the 4 MiB authenticated frame format and bounded memory.

---

## Desktop voice modes need the final physical audio pass

**Status:** automation-backed; manual device verification is open. Filed 2026-08-24.

The rendered Chat journey now proves Manual start/stop and cancellation, Auto end-on-silence,
Hands-free speech detection, the generation and playback lock, the two-second speaker-drain wait,
automatic rearming, pause, and the transition back to text mode. The global dictation reducer also
proves Hold, Toggle, and Both, including auto-repeat protection. The focused suites pass 41 tests.

The remaining boundary is the installed macOS app with real hardware and models. On the release Mac:

1. Select a Whisper model and a Parakeet model in turn. Confirm Chat reports and uses the selected
transcription model without changing the chat model.
2. Speak one turn in Manual, Auto, and Hands-free. Confirm Auto does not cut off a normal pause and
Hands-free does not record its own Kokoro reply.
3. Interrupt and pause Hands-free, switch to text during an active recording, deny and restore
microphone permission, and cancel during transcription. Confirm the mic indicator and audio output
stop and no discarded transcript appears.
4. In TextEdit and one other app, verify the Pro Voice Hold, Toggle, and Both gestures and confirm one
transcript is pasted for each completed turn.

Close this gap only with the exact packaged build, an audible reply, the real macOS microphone
indicator, and a saved diagnostic excerpt that identifies the active speech-to-text model.
33 changes: 30 additions & 3 deletions docs/features/voice.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

[← All features](../FEATURES.md)

- **Speech → text** with `whisper.cpp` (tiny → large-v3-turbo).
- **Text → speech** with Kokoro (multiple voices) — tap **Speak** on any message.
- **Voice mode** turns chat into a hands-free, voice-note conversation.
Speak instead of typing, and hear a reply without sending your words to a cloud service.

## In Chat

Select the voice-mode button at the top of Chat. Then select how each turn works:

- **Manual:** Select the microphone to start. Select it again to stop and send.
- **Auto:** Select the microphone to start. Off Grid stops and sends after you stop speaking.
- **Hands-free:** Off Grid listens for your voice, sends after you stop speaking, plays the reply,
and then listens again. Select the microphone to pause or resume.

During transcription, the microphone shows the installed speech-to-text model that is in use. Select
the cancel control to discard that turn. When you return to text mode, Off Grid stops the active
recording and keeps the text composer ready.

## Dictation in other apps (Pro)

Open **Voice** and set the Option+Space gesture:

- **Hold:** Hold Option+Space while you speak. Release it to stop.
- **Toggle:** Press Option+Space once to start. Press it again to stop.
- **Both:** A quick press toggles recording. A hold works as push-to-talk.

Off Grid transcribes with the active Whisper or Parakeet model. Auto-send can paste the result at the
current cursor. Saved recordings stay searchable in Voice.

## Hear a reply

Select **Speak** on a text reply, or play a voice-mode reply. Off Grid uses the selected Kokoro
language and voice. Only one reply plays at a time.
4 changes: 2 additions & 2 deletions integration-tests/memory-chat-tts.ui.integration.dbtest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,10 @@
await user.click(await screen.findByTitle('Voice mode off'))
await waitFor(() => expect(database.getSetting('composerVoiceMode', false)).toBe(true))

await user.click(screen.getByText('Tap to record a voice note'))
await user.click(screen.getByText('Click to record a voice note'))
expect(RecorderBoundary.instances).toHaveLength(1)
expect(RecorderBoundary.instances[0]!.state).toBe('recording')
await user.click(screen.getByText('Recording — tap to send'))
await user.click(screen.getByText('Recording - click to send'))

await waitFor(() => expect(screen.getAllByText('Show transcript')).toHaveLength(2), {
timeout: 10_000
Expand Down Expand Up @@ -376,7 +376,7 @@
await user.click(screen.getByTitle('Voice mode on — speak and listen in voice notes'))
await waitFor(() => expect(database.getSetting('composerVoiceMode', true)).toBe(false))
const composer = await screen.findByPlaceholderText(/^ask /i)
fireEvent.change(composer, { target: { value: 'Typed chat remains usable after voice recovery' } })

Check warning on line 379 in integration-tests/memory-chat-tts.ui.integration.dbtest.ts

View workflow job for this annotation

GitHub Actions / ci

Replace `·target:·{·value:·'Typed·chat·remains·usable·after·voice·recovery'·}` with `⏎······target:·{·value:·'Typed·chat·remains·usable·after·voice·recovery'·}⏎···`
expect((screen.getByPlaceholderText(/^ask /i) as HTMLTextAreaElement).value).toBe(
'Typed chat remains usable after voice recovery'
)
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@offgrid/clipboard": "file:./packages/clipboard",
"@offgrid/design": "file:./packages/design",
"@offgrid/models": "file:../shared/packages/models",
"@offgrid/speech": "file:../shared/packages/speech",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"@offgrid/rag": "file:./packages/rag",
"@offgrid/sync": "file:../shared/packages/sync",
"@phosphor-icons/react": "^2.1.10",
Expand Down
2 changes: 1 addition & 1 deletion pro
Submodule pro updated from 898703 to cf490e
23 changes: 23 additions & 0 deletions scripts/hooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ fi
# So: run each suite, keep its report, gate once on the union. The floors are a RATCHET recording what this
# branch achieves. Raise them as coverage rises; do not lower them to pass.
echo "[pre-push] coverage 1/3 — unit + integration"
# The app keeps SQLite built for Electron. The fast suite also contains real product
# integrations that open SQLite under Node, so give them Node's ABI before Vitest starts.
# The DB journey immediately below restores Electron's ABI in its EXIT trap.
sqlite_needs_electron_restore=0
restore_electron_sqlite() {
if [ "$sqlite_needs_electron_restore" != "1" ]; then
return
fi
sqlite_needs_electron_restore=0
echo "[pre-push] restoring SQLite for Electron"
npx electron-rebuild -f -w better-sqlite3-multiple-ciphers >/dev/null 2>&1 || \
npx electron-builder install-app-deps >/dev/null 2>&1 || true
Comment thread
alichherawalla marked this conversation as resolved.
Outdated
./scripts/probe-electron-sqlite.sh '[pre-push]'
}
trap restore_electron_sqlite EXIT
if ! npm rebuild better-sqlite3-multiple-ciphers >/dev/null 2>&1; then
echo "[pre-push] BLOCKED: could not rebuild SQLite for the Node test runner."
exit 1
fi
Comment thread
alichherawalla marked this conversation as resolved.
Outdated
sqlite_needs_electron_restore=1
if ! npm run --silent test:coverage; then
echo ""
echo "[pre-push] NOTE: the fast suite reported failures or missed its own thresholds. The aggregate gate"
Expand All @@ -46,6 +66,9 @@ echo "[pre-push] coverage 2/3 — DB journeys (real SQLite)"
if ! OFFGRID_DB_VITEST_CONFIG=vitest.db.coverage.config.ts npm run --silent test:db -- --coverage; then
echo "[pre-push] NOTE: the DB journeys reported failures; their contribution may be missing below."
fi
# test-db.sh restores Electron's ABI in its own EXIT trap. The parent trap above
# remains the interruption guard for every earlier exit path.
sqlite_needs_electron_restore=0

# Full Playwright e2e on the built app — the one gate the unit/integration suite can't give:
# does the built app actually render + drive its surfaces. Specs needing real models/engine binaries
Expand Down
13 changes: 13 additions & 0 deletions scripts/probe-electron-sqlite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

# Verify the native SQLite module with Electron's ABI after Node-based database tests. The optional
# executable argument is the external-process boundary used by the regression test.
prefix="${1:-[sqlite]}"
electron_binary="${2:-./node_modules/electron/dist/Electron.app/Contents/MacOS/Electron}"

if ELECTRON_RUN_AS_NODE=1 "$electron_binary" \
-e 'new (require("better-sqlite3-multiple-ciphers"))(":memory:")' >/dev/null 2>&1; then
echo "$prefix Electron ABI restored (app can load sqlite)."
else
echo "$prefix WARNING: Electron cannot load sqlite - run 'npx electron-rebuild -f -w better-sqlite3-multiple-ciphers' before launching the app."
fi
5 changes: 1 addition & 4 deletions scripts/test-db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ restore() {
# no-op from cache). Verify the app can actually load it; warn loudly if not.
npx electron-rebuild -f -w better-sqlite3-multiple-ciphers >/dev/null 2>&1 \
|| npx electron-builder install-app-deps >/dev/null 2>&1 || true
ELECTRON_RUN_AS_NODE=1 ./node_modules/electron/dist/Electron.app/Contents/MacOS/Electron \
-e 'new (require("better-sqlite3-multiple-ciphers"))(":memory:")' >/dev/null 2>&1 \
&& echo "[test:db] Electron ABI restored (app can load sqlite)." \
|| echo "[test:db] WARNING: Electron cannot load sqlite - run 'npx electron-rebuild -f -w better-sqlite3-multiple-ciphers' before launching the app."
./scripts/probe-electron-sqlite.sh '[test:db]'
}
trap restore EXIT

Expand Down
28 changes: 28 additions & 0 deletions src/main/__tests__/electron-sqlite-probe.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { spawnSync } from 'node:child_process'
import path from 'node:path'
import { describe, expect, it } from 'vitest'

const PROBE = path.resolve(process.cwd(), 'scripts/probe-electron-sqlite.sh')

function runProbe(executable: '/usr/bin/true' | '/usr/bin/false'): string {
const result = spawnSync('/bin/sh', [PROBE, '[pre-push]', executable], {
encoding: 'utf8'
})
expect(result.status).toBe(0)
expect(result.stderr).toBe('')
return result.stdout.trim()
}

describe('Electron SQLite restoration probe', () => {
it('reports that Electron can load the restored native module', () => {
expect(runProbe('/usr/bin/true')).toBe(
'[pre-push] Electron ABI restored (app can load sqlite).'
)
})

it('reports the exact rebuild action when Electron cannot load SQLite', () => {
expect(runProbe('/usr/bin/false')).toBe(
"[pre-push] WARNING: Electron cannot load sqlite - run 'npx electron-rebuild -f -w better-sqlite3-multiple-ciphers' before launching the app."
)
})
})
47 changes: 47 additions & 0 deletions src/main/__tests__/mcp-oauth-cancellation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { describe, expect, it, vi } from 'vitest'
import { beginOAuthAuthorization, cancelOAuthAuthorization } from '../mcp-oauth-cancellation'

describe('connector OAuth cancellation registry', () => {
it('cancels only the named connector and clears the registration', () => {
const first = vi.fn()
const second = vi.fn()
beginOAuthAuthorization(101, first)
beginOAuthAuthorization(202, second)

expect(cancelOAuthAuthorization(101)).toBe(true)
expect(first).toHaveBeenCalledWith(
expect.objectContaining({ message: 'Authorization cancelled' })
)
expect(second).not.toHaveBeenCalled()
expect(cancelOAuthAuthorization(101)).toBe(false)

cancelOAuthAuthorization(202)
})

it('cancels an older attempt when a connector starts a new one', () => {
const older = vi.fn()
const newer = vi.fn()
beginOAuthAuthorization(303, older)
const finishNewer = beginOAuthAuthorization(303, newer)

expect(older).toHaveBeenCalledWith(
expect.objectContaining({ message: 'Authorization superseded by a newer request' })
)
finishNewer()
expect(cancelOAuthAuthorization(303)).toBe(false)
expect(newer).not.toHaveBeenCalled()
})

it('does not let an older completion clear a newer attempt', () => {
const older = vi.fn()
const newer = vi.fn()
const finishOlder = beginOAuthAuthorization(404, older)
beginOAuthAuthorization(404, newer)

finishOlder()
expect(cancelOAuthAuthorization(404)).toBe(true)
expect(newer).toHaveBeenCalledWith(
expect.objectContaining({ message: 'Authorization cancelled' })
)
})
})
40 changes: 40 additions & 0 deletions src/main/__tests__/mcp-oauth-pkce.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it } from 'vitest'
import { OAuthPkceVerifier } from '../mcp-oauth-pkce'

describe('OAuth PKCE verifier lifecycle', () => {
it('keeps the verifier when the SDK invalidates all credentials before an exchange retry', () => {
const verifier = new OAuthPkceVerifier()
verifier.save('attempt-verifier')

verifier.invalidate('all')

expect(verifier.read()).toBe('attempt-verifier')
})

it('clears the verifier after tokens are saved', () => {
const verifier = new OAuthPkceVerifier()
verifier.save('attempt-verifier')

verifier.complete()

expect(() => verifier.read()).toThrow('missing PKCE code verifier')
})

it('clears the verifier when authorization is cancelled', () => {
const verifier = new OAuthPkceVerifier()
verifier.save('attempt-verifier')

verifier.cancel()

expect(() => verifier.read()).toThrow('missing PKCE code verifier')
})

it('honors explicit verifier invalidation during an active attempt', () => {
const verifier = new OAuthPkceVerifier()
verifier.save('attempt-verifier')

verifier.invalidate('verifier')

expect(() => verifier.read()).toThrow('missing PKCE code verifier')
})
})
Loading
Loading