Skip to content
Open
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
416 commits
Select commit Hold shift + click to select a range
308347e
feat(mcp): gate the action tools behind a per-device pairing token
siddWednesday Aug 19, 2026
52c1b3b
feat(pairing): LAN-address + pairing-payload building blocks for QR p…
siddWednesday Aug 20, 2026
17e2497
feat(pairing): desktop "Pair a device" panel with QR + copyable code
siddWednesday Aug 20, 2026
2f3c511
refactor(pairing): drop the standalone "Pair a device" Settings panel
siddWednesday Aug 20, 2026
9c4e7ca
build(deps): re-add qrcode.react for the Devices pairing QR
siddWednesday Aug 20, 2026
0cdd0b5
feat(explore): the demo-preset catalog (SSOT for the showcase)
siddWednesday Aug 21, 2026
31c035f
feat(explore): ExploreSection - capability-grouped preset cards
siddWednesday Aug 21, 2026
70d870e
feat(explore): surface demo presets in the chat empty state
siddWednesday Aug 21, 2026
183e6b6
feat(explore): add Explore landing view + seed-prompt handoff
siddWednesday Aug 21, 2026
2bb50b1
fix(explore): use the brand name "Off Grid AI" in the Explore header
siddWednesday Aug 21, 2026
a961ce4
fix(rag): stop a hyphenated query from crashing the whole chat retrieval
siddWednesday Aug 21, 2026
4cb26ee
fix(explore): make the Play-music preset concrete and drop the volume…
siddWednesday Aug 21, 2026
c064376
feat(approvals): show the inline chat card for computer-use gates in …
siddWednesday Aug 21, 2026
964fd72
feat(approvals): core seam for the auto/ask computer-task approval mode
siddWednesday Aug 21, 2026
d9bf87c
feat(approvals): multi-subscriber inline gate surface (fan out to car…
siddWednesday Aug 21, 2026
a7eeefe
test(chat): render clean desktop previews
alichherawalla Aug 22, 2026
9a1f4e2
feat(explore): capability panels + label titles, never the raw prompt
siddWednesday Aug 23, 2026
59aab3c
test(e2e): explore surfaces render label-only cards on both placements
siddWednesday Aug 23, 2026
5fed910
feat(explore): per-preset icons + runs count on each capability panel
siddWednesday Aug 23, 2026
5e45465
fix(browser): stop the agent browser's audio when it's hidden or the …
siddWednesday Aug 23, 2026
4463ae1
fix(chat): remove the grounder-model nudge from the chat
siddWednesday Aug 23, 2026
c65db99
fix(approvals): dismiss the gate card the instant the user decides
siddWednesday Aug 23, 2026
b96cdfe
fix(browser): make the watched-pane resize handle grabbable with a gr…
siddWednesday Aug 23, 2026
df28524
fix(browser): stream web-task steps in the chat, not below the browser
siddWednesday Aug 23, 2026
f750019
refine(explore): make preset prompts concrete and self-explanatory
siddWednesday Aug 23, 2026
37cb1d8
Merge remote-tracking branch 'origin/main' into feat/chat-approvals
siddWednesday Aug 23, 2026
14090a3
fix(merge): bump pro pointer + resolve pre-existing failures surfaced…
siddWednesday Aug 23, 2026
dc00ac0
feat(win/vision): DPI-aware coordinate mapping for the computer-use rail
siddWednesday Aug 23, 2026
2f26fac
ci(win): fail loud if the computer-use input addon (nut.js) is absent
siddWednesday Aug 23, 2026
08c92ff
docs(win): record action-rails + computer-use Windows status
siddWednesday Aug 23, 2026
d3e8504
ci(win): build @offgrid/models + let dispatch pin the shared ref
siddWednesday Aug 23, 2026
a18819c
feat(vision): fall back to the active model when the grounder isn't d…
siddWednesday Aug 23, 2026
b06280c
feat(speech): configure transcription language
alichherawalla Aug 24, 2026
9e67b85
fix(ui): standardize dismissible side panels
alichherawalla Aug 24, 2026
cb36e36
fix(chat): open safe markdown links
alichherawalla Aug 24, 2026
fd952ef
feat(search): add Activity and Files commands
alichherawalla Aug 24, 2026
4dcac8a
test(models): cover transcription settings navigation
alichherawalla Aug 24, 2026
1afea0f
chore(pro): update release feedback features
alichherawalla Aug 24, 2026
09e49ff
test(speech): cover configured language fallback
alichherawalla Aug 24, 2026
b142106
refactor(speech): centralize transcription status
alichherawalla Aug 24, 2026
f07824d
test(speech): cover transcription status
alichherawalla Aug 24, 2026
5317125
ci(shared): build speech package before desktop checks
alichherawalla Aug 24, 2026
0d0afeb
test(speech): cover transcription language IPC
alichherawalla Aug 24, 2026
8af7828
chore(pro): update release feedback dependency
alichherawalla Aug 24, 2026
3875d25
fix(speech): reconcile transferred transcription settings
alichherawalla Aug 24, 2026
036819c
fix(ui): make panels and palette keyboard safe
alichherawalla Aug 24, 2026
a9c3a15
ci: test SQLite with the Node ABI
alichherawalla Aug 24, 2026
de7d010
fix(speech): fall back from stale transcription picks
alichherawalla Aug 24, 2026
090e34f
ci: prepare SQLite before fast integration tests
alichherawalla Aug 24, 2026
434f4c6
ci: align Desktop Pro feedback head
alichherawalla Aug 24, 2026
476d479
ci: restore Electron SQLite after interrupted pushes
alichherawalla Aug 24, 2026
2597a8b
fix(ui): close final navigation and focus gaps
alichherawalla Aug 24, 2026
ce64ee6
ci: report failed Electron ABI restoration
alichherawalla Aug 24, 2026
04cfe08
fix(ui): harden routes and panel focus
alichherawalla Aug 24, 2026
098af0f
chore(pro): align feedback integration head
alichherawalla Aug 24, 2026
f459c71
feat(win/ax): Windows accessibility rail via PowerShell + UI Automation
siddWednesday Aug 24, 2026
5a1fbd3
fix(integrations): route provider verification
alichherawalla Aug 24, 2026
f84f1ea
fix(integrations): share Google OAuth callback
alichherawalla Aug 24, 2026
7978b1d
chore(pro): align Calendar scope fix
alichherawalla Aug 24, 2026
15776a6
chore(pro): bump submodule to the eviction/license fix (420b3c6)
siddWednesday Aug 24, 2026
02e9a49
feat: complete Google connector authorization
alichherawalla Aug 24, 2026
82f4bc3
refactor: animate shared side panels
alichherawalla Aug 24, 2026
5cacb52
feat: add complete Desktop voice turns
alichherawalla Aug 24, 2026
9810c20
chore: update Desktop Pro sync bridge
alichherawalla Aug 24, 2026
a6a8b35
feat(mcp): action-tool auth reads live per-device tokens
siddWednesday Aug 24, 2026
b10addf
ci(release): add artifact_only mode (signed DMG as a run artifact, no…
siddWednesday Aug 24, 2026
ca61029
test: cover Electron SQLite restoration
alichherawalla Aug 24, 2026
70cf5ad
test: prove connector source lifecycle
alichherawalla Aug 24, 2026
ebd2f4a
refactor: simplify Desktop voice state presentation
alichherawalla Aug 24, 2026
46a47ce
refactor: isolate connector authorization controls
alichherawalla Aug 24, 2026
c15d0ec
fix: validate persisted Desktop voice settings
alichherawalla Aug 24, 2026
54e8548
refactor: clarify Desktop navigation and focus
alichherawalla Aug 24, 2026
9057474
fix: make connector controls immutable
alichherawalla Aug 24, 2026
b3173f8
chore: update Pro browsing state boundary
alichherawalla Aug 24, 2026
ec9d16f
chore: update Pro advertising state boundary
alichherawalla Aug 24, 2026
e3791d7
docs: add Google OAuth and mesh release guide
alichherawalla Aug 24, 2026
13ec731
chore: update Pro CI policy pointer
alichherawalla Aug 24, 2026
ef99f3d
feat(audio): show runtime voice readiness
alichherawalla Aug 24, 2026
dd3f0db
fix(time): share local calendar-day helpers
alichherawalla Aug 25, 2026
3784408
Merge branch 'feat/windows-parity' into release/107-feedback
alichherawalla Aug 25, 2026
00f7ecd
fix(chat): resolve Windows parity merge imports
alichherawalla Aug 25, 2026
976b828
feat(speech): integrate private ExecuTorch runtime
alichherawalla Aug 25, 2026
8929844
feat(chat): connect structured search tools
alichherawalla Aug 25, 2026
5c06ccb
feat(settings): unify model and voice controls
alichherawalla Aug 25, 2026
0197806
feat(chat): unify voice and source navigation
alichherawalla Aug 25, 2026
8adb7e7
chore(pro): include chat tools and Windows parity
alichherawalla Aug 25, 2026
d40d761
Merge Windows parity into release/107-feedback
alichherawalla Aug 25, 2026
5b116b0
fix(speech): show every runtime voice
alichherawalla Aug 25, 2026
7248145
test(actions): preserve native DB test ABI
alichherawalla Aug 25, 2026
44ad62b
fix(computer-use): retain recent vision steps
alichherawalla Aug 25, 2026
fe1b622
fix(tools): skip planning plain questions
alichherawalla Aug 25, 2026
6589dcc
feat(explore): add local proposal deck skill
alichherawalla Aug 25, 2026
a703080
feat(actions): route approvals to execution chat
alichherawalla Aug 25, 2026
2002819
chore(pro): include time transfer and action flows
alichherawalla Aug 25, 2026
3b96309
fix(explore): use full-width proposal intake
alichherawalla Aug 25, 2026
3c08902
feat(tasks): add persistent web and computer tabs
alichherawalla Aug 25, 2026
1f5d63a
fix(explore): clarify proposal style references
alichherawalla Aug 25, 2026
9e37ac3
fix(tasks): always open task history
alichherawalla Aug 25, 2026
0052eff
feat(chat): explain completed work inline
alichherawalla Aug 25, 2026
c27dbfd
feat(chat): link installed skill mentions
alichherawalla Aug 25, 2026
ebbff37
feat(actions): continue approvals in chat
alichherawalla Aug 25, 2026
a853cb7
chore(pro): use one approval sync path
alichherawalla Aug 25, 2026
de40f64
fix(actions): use chat-only approval sync
alichherawalla Aug 25, 2026
6fa6719
feat(progress): emit complete download facts
alichherawalla Aug 25, 2026
f829bc1
feat(progress): show complete download status
alichherawalla Aug 25, 2026
83622c2
feat(browser): manage independent tab sessions
alichherawalla Aug 25, 2026
7ab66a1
feat(tasks): retain computer use step details
alichherawalla Aug 25, 2026
f56fd42
feat(computer-use): add grounded runtime controls
alichherawalla Aug 25, 2026
50c3a73
feat(computer-use): add UI-Mate policy adapter
alichherawalla Aug 25, 2026
e4d2e89
feat(tasks): add managed browser workspace
alichherawalla Aug 25, 2026
7af051e
test(tasks): cover computer use settings route
alichherawalla Aug 25, 2026
743e3eb
feat(computer-use): retain AX planning evidence
alichherawalla Aug 25, 2026
21644d0
feat(computer-use): run UI-Mate vision policy
alichherawalla Aug 25, 2026
47159c7
feat(computer-use): build model-governed vision pipeline
alichherawalla Aug 26, 2026
8816c84
feat(desktop): add docked task workspace and live evidence
alichherawalla Aug 26, 2026
5dbee0b
test(computer-use): cover governed web task journeys
alichherawalla Aug 26, 2026
101eb4c
build(computer-use): add graph and secure-input support
alichherawalla Aug 26, 2026
ce1b7f9
docs(computer-use): record pipeline contract and gaps
alichherawalla Aug 26, 2026
df866c0
fix(computer-use): preserve immersive retry workspace
alichherawalla Aug 26, 2026
a054daa
feat(pro): gate browser and computer use
alichherawalla Aug 26, 2026
6c537ec
build(pro): update desktop pro dependency
alichherawalla Aug 26, 2026
84ea0e2
test(computer-use): assert immersive retry detail
alichherawalla Aug 26, 2026
3395821
fix(pro): accept typed IPC handler boundaries
alichherawalla Aug 26, 2026
2602008
build(pro): update desktop pro checks
alichherawalla Aug 26, 2026
6df305e
test(renderer): align integration fixtures with live UI
alichherawalla Aug 26, 2026
50bbbad
test(audio): require complete engine round trip
alichherawalla Aug 26, 2026
c26a2b1
build(pro): update desktop pro dependency
alichherawalla Aug 26, 2026
3112cbc
test(e2e): preserve agentic evidence diagnostics
alichherawalla Aug 26, 2026
e4d7254
ci: secure cross-repo runtime checkout
alichherawalla Aug 26, 2026
25a7cf2
ci(shared): build desktop ui dependency
alichherawalla Aug 26, 2026
1769c2a
ci: allow complete coverage aggregation
alichherawalla Aug 26, 2026
5f5d3ab
refactor(pro): move task surfaces behind private slots
alichherawalla Aug 26, 2026
d879714
test(pro): activate private task activity
alichherawalla Aug 26, 2026
c6309da
ci: allow manual verification runs
alichherawalla Aug 26, 2026
f1c12b6
fix(licensing): preserve effective pro status
alichherawalla Aug 26, 2026
1c9475b
fix(tasks): verify smooth disclosure motion
alichherawalla Aug 26, 2026
41a028e
ci(pro): use complete private verification workflow
alichherawalla Aug 26, 2026
ef29baa
fix(ci): close coverage hang and quality gate
alichherawalla Aug 26, 2026
3989d26
fix(vision): route visual decisions through graph commands
alichherawalla Aug 26, 2026
b45b48c
fix(ci): gate aggregate new-code coverage
alichherawalla Aug 26, 2026
f2121f7
fix(chat): dock tasks below the chat header
alichherawalla Aug 26, 2026
6de6360
chore(pro): update task workspace integration
alichherawalla Aug 26, 2026
c6a055a
fix(navigation): collapse the sidebar until hover
alichherawalla Aug 26, 2026
031f899
fix(vision): normalize model action coordinates
alichherawalla Aug 26, 2026
aadc039
fix(browser): execute history hotkeys semantically
alichherawalla Aug 26, 2026
ca27f80
fix(ci): update DB journey contracts
alichherawalla Aug 26, 2026
1e5b5d1
fix(browser): expose semantic navigation controls
alichherawalla Aug 26, 2026
d64ff0b
fix(startup): restore Electron SQLite ABI
alichherawalla Aug 26, 2026
c23e8f8
chore(pro): update task and startup fixes
alichherawalla Aug 26, 2026
1b85374
fix(chat): show live edited Web Use progress
alichherawalla Aug 26, 2026
f255312
fix(chat): stream remote reasoning details
alichherawalla Aug 26, 2026
b1e3322
fix(chat): allow live task projection without result
alichherawalla Aug 26, 2026
d60fd3f
show Computer Use in active models
alichherawalla Aug 26, 2026
5820a74
fix(browser): repaint live native surface
alichherawalla Aug 26, 2026
ee1f7d0
fix(browser): handle F5 as a native reload
alichherawalla Aug 26, 2026
b1c71cc
fix(tools): stop after launching a task
alichherawalla Aug 26, 2026
9020c9e
fix(web-use): use one specialist lifecycle owner
alichherawalla Aug 26, 2026
6c37d4b
test(chat): cover reasoning after message edit
alichherawalla Aug 26, 2026
6bed3df
fix(computer-use): preflight macOS permissions
alichherawalla Aug 26, 2026
4944c40
feat(computer-use): use native vision tools
alichherawalla Aug 26, 2026
338b01d
fix(computer-use): honor specialist action protocols
alichherawalla Aug 26, 2026
6c21462
fix(computer-use): own specialist lifecycle once
alichherawalla Aug 26, 2026
57c9a80
refactor(computer-use): share the vision task graph
alichherawalla Aug 26, 2026
a2b2cd3
test(computer-use): cover macOS graph journey
alichherawalla Aug 26, 2026
705a78d
fix(ui-mate): use the exact current coordinate frame
alichherawalla Aug 26, 2026
45ee0a5
fix(browser): keep live pointer visible
alichherawalla Aug 26, 2026
48e5f25
fix(tasks): show exact model screenshot
alichherawalla Aug 26, 2026
d12c55b
fix(tasks): keep pane open when expanding chat
alichherawalla Aug 26, 2026
067db5e
fix(vision): reject mismatched model frames
alichherawalla Aug 26, 2026
8c355a6
fix(tasks): restore chat beside task pane
alichherawalla Aug 26, 2026
d23242f
fix(web-use): gate completion on every milestone
alichherawalla Aug 26, 2026
0e96912
fix(web-use): generate distinct visible milestones
alichherawalla Aug 26, 2026
2be7bf4
fix(ui-mate): scope completion to active milestone
alichherawalla Aug 26, 2026
08112a4
fix(computer-use): normalize UI-Mate scroll distance
alichherawalla Aug 26, 2026
aea8ae1
fix(ui): centralize chat task pane state
alichherawalla Aug 26, 2026
c415534
fix(web-use): stabilize visual coordinate grounding
alichherawalla Aug 26, 2026
b07e83d
feat(web-use): unify browser control guidance
alichherawalla Aug 26, 2026
797a8f4
fix(ui-mate): advance focused task milestones
alichherawalla Aug 26, 2026
f1125a7
fix(ui): open dropdown menus above side panels
alichherawalla Aug 27, 2026
332e483
docs(brand): say "Off Grid AI" everywhere
alichherawalla Aug 27, 2026
2ff3524
feat(settings): let you cap what the model spends on thinking
alichherawalla Aug 27, 2026
64d98d9
refactor(chat): move the image lightbox into its own component
alichherawalla Aug 27, 2026
b88c3ca
refactor(chat): let the pane controller decide the toggle label
alichherawalla Aug 27, 2026
b46c6a6
refactor(vision): delete the superseded task runner
alichherawalla Aug 27, 2026
9751ae3
refactor(vision): one owner for the scroll step and point mapping
alichherawalla Aug 27, 2026
bdc6378
refactor(vision): drop the redundant first-load branch
alichherawalla Aug 27, 2026
16c9e9d
perf(vision): build the coordinate grid once per frame size
alichherawalla Aug 27, 2026
d07085d
refactor(vision): read permissions through the shared checks
alichherawalla Aug 27, 2026
c8677cd
perf(web-use): encode each captured frame once
alichherawalla Aug 27, 2026
9c652b2
perf(web-use): only touch the native view when something changed
alichherawalla Aug 27, 2026
f89e1e8
refactor(web-use): one table for the browser shortcuts
alichherawalla Aug 27, 2026
96dc804
refactor(tools): make "is a task" a property of the tool
alichherawalla Aug 27, 2026
d373786
docs(gaps): log the duplicated Computer Use model rule
alichherawalla Aug 27, 2026
aed1392
test(tools): assert the pro refusal is authoritative
alichherawalla Aug 27, 2026
9bf2ab5
feat(tasks): open Computer Use screenshots full size
alichherawalla Aug 27, 2026
6a24f8b
chore(pro): bump the submodule
alichherawalla Aug 27, 2026
e94d2b2
test(e2e): add the agentic studio screenshots
alichherawalla Aug 27, 2026
999725c
fix(speech): stop the audio seam pulling the app database into every …
alichherawalla Aug 27, 2026
2870c76
fix(ui): make the side panel flush to the window edge
alichherawalla Aug 27, 2026
3ba66a5
fix(settings): give the tab row room instead of slicing a tab off
alichherawalla Aug 27, 2026
40ed16e
docs(doctrine): sync the mirrored debugging doctrine
alichherawalla Aug 27, 2026
d4789a6
fix(tools): list the native actions in the Tools tab
alichherawalla Aug 27, 2026
f8f26c1
perf(embeddings): run the embedding pipeline off the main thread
alichherawalla Aug 27, 2026
e08ef1c
perf(tasks): redact step details once, on write, not on every read
alichherawalla Aug 27, 2026
85a59fa
perf(tasks): parse a step-details blob once, not once per token
alichherawalla Aug 27, 2026
68ff14e
fix(models): ring the whole search field, not the bare input
alichherawalla Aug 27, 2026
68ccd4e
perf(tasks): stop streaming display state through the durable store
alichherawalla Aug 27, 2026
18b976c
fix(tasks): resume a retry at the phase it reached, not phase 1
alichherawalla Aug 27, 2026
b24717e
test(models): derive Computer Use counts from the catalog
alichherawalla Aug 27, 2026
8771a29
fix(settings): honour the thinking cap on remote models, and nest the…
alichherawalla Aug 27, 2026
ce05218
fix(llm): clear the two lint errors in the remote chat stream
alichherawalla Aug 27, 2026
f4ccb73
refactor(llm): decompose the remote chat transport
alichherawalla Aug 27, 2026
c963af9
feat(web-use): float a running task in an always-on-top window
alichherawalla Aug 27, 2026
a7190ec
fix(vision): retry a model that reasons but calls no tool
alichherawalla Aug 27, 2026
1bf05cf
Revert "feat(web-use): float a running task in an always-on-top window"
alichherawalla Aug 27, 2026
e1e1224
fix(nav,vision): match sidebar states, drop the leave prompt, replay …
alichherawalla Aug 27, 2026
9c85617
fix(vision): Same as Chat uses the general operator, whatever the mod…
alichherawalla Aug 27, 2026
ce9707e
fix(vision): a specialist parser claims only what it can parse
alichherawalla Aug 27, 2026
9d6b827
fix(vision,browser): retry as a user turn, and one real cursor
alichherawalla Aug 27, 2026
41aa235
feat(chat): answer the chat-icon question from the current view
alichherawalla Aug 27, 2026
5cca388
fix(browser): paint the agent cursor with CSS so Trusted Types cannot…
alichherawalla Aug 27, 2026
6d5443a
feat(tasks): let the docked task surface declare that it is on screen
alichherawalla Aug 27, 2026
133a2d0
feat(browser): main decides which surface hosts the live page
alichherawalla Aug 28, 2026
0153745
fix(browser): size the viewport tolerance to the zoom, and say why a …
alichherawalla Aug 28, 2026
057932c
fix(browser): give every named key a real keycode, and hide the chat …
alichherawalla Aug 28, 2026
d4bef06
test: give jsdom a scrollIntoView
alichherawalla Aug 28, 2026
b6a8f53
feat(llm): measure what a generation cost
alichherawalla Aug 28, 2026
c0a548d
feat(vision): measure capture time and model time per step
alichherawalla Aug 28, 2026
614d50f
feat(chat): show what a generation cost under the answer
alichherawalla Aug 28, 2026
673db50
feat(chat): put generation details behind a preference, off by default
alichherawalla Aug 28, 2026
02625e4
perf(tasks): stop persisting the model prompt with every step
alichherawalla Aug 28, 2026
1c67ac8
chore: bump pro for the floating-card tests
alichherawalla Aug 28, 2026
0d73c78
fix(embeddings): keep source search on vector path
alichherawalla Aug 28, 2026
3870fd2
fix(speech): migrate legacy voices and journeys
alichherawalla Aug 28, 2026
d395736
chore(pro): advance verified release runtime
alichherawalla Aug 28, 2026
b932479
fix(transcription): retry Hindi script misses
alichherawalla Aug 28, 2026
1dbb72a
feat(voice): add tested resend action
alichherawalla Aug 28, 2026
be4977c
fix(chat): explain unavailable remote thinking
alichherawalla Aug 28, 2026
bccc881
fix(browser): harden driver identity and shortcuts
alichherawalla Aug 28, 2026
72769cb
ci: run database journeys on Node 26
alichherawalla Aug 28, 2026
a7496bc
ci: use compatible Node for SQLite journeys
alichherawalla Aug 28, 2026
167aac6
fix(computer-use): make task controls terminal
alichherawalla Aug 28, 2026
bc7da76
refactor(web-use): retire the web_task tool name
alichherawalla Aug 28, 2026
2782eef
fix(actions): keep task approval in its owner
alichherawalla Aug 28, 2026
56b0f2d
fix(computer-use): publish AX frames to supervisor
alichherawalla Aug 28, 2026
cbc952f
chore(release): integrate Computer Use supervisor fixes
alichherawalla Aug 28, 2026
674a12d
test(computer-use): prove Stop crosses the live control path
alichherawalla Aug 28, 2026
e5dfd07
test(actions): bind inline gate fixture to its chat
alichherawalla Aug 28, 2026
8d40754
fix(computer-use): bound screen capture failure
alichherawalla Aug 28, 2026
1fd58ba
chore(release): integrate final Pro journey tests
alichherawalla Aug 28, 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.
Outdated
"@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.
./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.
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