Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
524 commits
Select commit Hold shift + click to select a range
9446101
fix(editor): keep the preview's boosted audio from clipping at the sp…
EtienneLescot Sep 30, 2026
a4d92a7
fix(macos): size the video bitrate from the actual capture, not the 4…
EtienneLescot Sep 30, 2026
345e225
fix(linux): convert and tag the PipeWire helper's video as BT.709
EtienneLescot Sep 30, 2026
af5d8fd
fix(windows): stop the audio mixer from punching holes in a continuou…
EtienneLescot Sep 30, 2026
025b2b2
fix(windows): keep the mixer's cushion across an instant resume and a…
EtienneLescot Sep 30, 2026
32857bb
docs: describe the mixer's resume handshake and clock anchoring
EtienneLescot Sep 30, 2026
2ad2293
fix(macos): pin the H.264 keyframe interval to 1 s and count dropped …
EtienneLescot Sep 30, 2026
e943004
perf(windows): raise the capture helpers' timer resolution and use MMCSS
EtienneLescot Sep 30, 2026
ab7d9dd
test(windows): retry the timer check so a busy host cannot fail the b…
EtienneLescot Sep 30, 2026
303eb7d
fix: keep the display awake while a recording runs
EtienneLescot Sep 30, 2026
63ae10e
fix: report a failed browser recording as stopped to the main process
EtienneLescot Sep 30, 2026
38c1239
fix(linux): keep the capture clock ticking while cursor messages flow
EtienneLescot Sep 30, 2026
1f5d9d8
perf(windows): skip the webcam frame copy when its sequence has not c…
EtienneLescot Sep 30, 2026
f9c4035
fix(windows): end the audio track where the video ends
EtienneLescot Sep 30, 2026
c729834
fix(windows): encode H.264 High with BT.709 colour the compositor exp…
EtienneLescot Sep 30, 2026
ea6a978
test(windows): widen the temp path through the ANSI code page
EtienneLescot Sep 30, 2026
da9b188
build(windows): link avrt into the encoder colour test, which compile…
EtienneLescot Sep 30, 2026
c9c5642
fix(stt): start each word at the end of the token before it
EtienneLescot Sep 30, 2026
ec93475
fix(linux): write fragmented MP4 so a killed helper keeps its take
EtienneLescot Sep 30, 2026
48da0dd
test(linux): give the killed-muxer test a per-process file and remove it
EtienneLescot Sep 30, 2026
9e45f7c
perf(windows): repeat the last frame instead of reading back an uncha…
EtienneLescot Sep 30, 2026
0511659
test(windows): widen the repeat tests' temp paths through the ANSI co…
EtienneLescot Sep 30, 2026
e04943a
fix(macos): capture and tag the screen track as BT.709 studio range
EtienneLescot Sep 30, 2026
c53ec9b
feat(stt): align words with character-level DTW
EtienneLescot Oct 1, 2026
9c86e71
docs(stt): match the char-dtw comment to the measured numbers
EtienneLescot Oct 1, 2026
04b7d15
fix(stt): fail configure if the patched whisper.cpp is not compiled; …
EtienneLescot Oct 1, 2026
14bf04b
feat(stt): re-time whisper's words on a CTC forced aligner
EtienneLescot Oct 1, 2026
f2051ca
fix(stt): never hold a chunk on the word aligner's download
EtienneLescot Oct 1, 2026
2c7604e
feat(stt): run the word aligner on the GPU only, measured against pha…
EtienneLescot Oct 1, 2026
50e8e64
docs(stt): correct the French take reading, and record the silent-let…
EtienneLescot Oct 1, 2026
341a72f
fix(stt-eval): say so when real-check has no word to compare
EtienneLescot Oct 1, 2026
75849dd
fix(hud): report the stack rect from the allocation, not a measurement
EtienneLescot Oct 1, 2026
05d3514
fix(release): read every helper build when staging, and say why one i…
EtienneLescot Oct 1, 2026
292c5f8
fix(release): list helper builds unfiltered into a file, and fail on …
EtienneLescot Oct 1, 2026
6f89b9d
docs(e2e): log the v2.0.0-rc.1 and rc.6 Windows passes
EtienneLescot Oct 1, 2026
a04329a
docs(e2e): record the rc.6 mixer check once the speakers were back on
EtienneLescot Oct 1, 2026
f459f0c
feat(camera): square camera by default, "Original" keeps the camera's…
EtienneLescot Oct 1, 2026
32c9370
fix(camera): fall back to the given shape's own default roundness
EtienneLescot Oct 1, 2026
899372c
fix(stt): keep a sentence's last word in the stretch it closes
EtienneLescot Oct 1, 2026
57684a9
fix(stt): stop a sentence end's punctuation scan at an opening bracket
EtienneLescot Oct 1, 2026
73e9b44
fix(main): quit when the hidden countdown overlay is the last window …
EtienneLescot Oct 1, 2026
12003a4
docs(testing): log the v2.0.0-rc.8 e2e pass and fix the export peak c…
EtienneLescot Oct 1, 2026
507c6d4
docs(testing): state the output level the rc.8 loudness export used
EtienneLescot Oct 1, 2026
b834416
fix(preview): hand out no native view while the view for a new source…
EtienneLescot Oct 1, 2026
3bee2d2
fix(editor): keep wordmark menu rows on one line in long locales
EtienneLescot Oct 2, 2026
c2a8559
fix(macos): keep the HUD out of takes after the editor round trip
EtienneLescot Oct 2, 2026
358c338
fix(timeline): show the bound shortcut in the empty-lane hints
EtienneLescot Oct 2, 2026
73879f9
fix(hud): keep camEnabled off when no camera can be opened
EtienneLescot Oct 2, 2026
cb8bb1e
fix(hud): clear a stored camera when the toggle finds none
EtienneLescot Oct 2, 2026
6b56f7b
fix(stt): show a readable message when transcription cannot read the …
EtienneLescot Oct 2, 2026
a1a2a76
fix(stt): key unreadable media on an extraction marker, not on wording
EtienneLescot Oct 2, 2026
bbeb37f
fix(stt): only mark an extraction timeout unreadable when nothing was…
EtienneLescot Oct 2, 2026
e73097c
perf(preview): stop decoding pictures the hidden media elements never…
EtienneLescot Oct 2, 2026
58f7fdf
perf(preview): hand composed frames to the canvas as shared GPU textures
EtienneLescot Oct 2, 2026
beddfc2
perf(preview): pull frames by the clock, not by display ticks
EtienneLescot Oct 2, 2026
33a6856
fix(preview): republish a frame that found no free slot, and drop the…
EtienneLescot Oct 2, 2026
7619e5f
fix(preview): never rewrite a shared slot Chromium still holds
EtienneLescot Oct 2, 2026
e358d77
fix(preview): stop re-seeking the native view at every cut and in spe…
EtienneLescot Oct 2, 2026
b519f23
fix(preview): count native drift in seconds of playback, and catch a …
EtienneLescot Oct 2, 2026
227b9b8
fix(preview): land on the last frame when a clip is entered past it
EtienneLescot Oct 2, 2026
83fbcec
fix(preview): hold the last frame for the webcam too when presenting …
EtienneLescot Oct 2, 2026
db8e7ed
feat(website): show the feature pages' demo loops, lazily, from R2
EtienneLescot Oct 2, 2026
55fa624
fix(website): start a loop that is already on screen when its sources…
EtienneLescot Oct 2, 2026
9658e0a
feat(website): film the homepage below the editor
EtienneLescot Oct 2, 2026
2eeb183
fix(website): smooth every loop, and blur the camera instead of cutti…
EtienneLescot Oct 2, 2026
d74e092
fix(website): give the format-and-blur block a title that reads as a …
EtienneLescot Oct 2, 2026
eba902a
fix(website): an agent claim that stands on its own, and du throughou…
EtienneLescot Oct 2, 2026
b879369
fix(website): address the review of the demo loops
EtienneLescot Oct 2, 2026
9f1a5b2
fix(website): give the recreation's lane hints their {{key}}
EtienneLescot Oct 2, 2026
bb4124d
feat(website): record the published demo loops, and check them in CI
EtienneLescot Oct 2, 2026
8e4d926
feat(website): declare each demo loop as a VideoObject where it is shown
EtienneLescot Oct 2, 2026
79bed86
perf(website): paint a loop's poster without waiting for script, and …
EtienneLescot Oct 2, 2026
de2fc91
fix(website): make the loop tooling refuse what would corrupt a cut
EtienneLescot Oct 2, 2026
69c14ad
docs(readme): show the current editor in the demo GIF
EtienneLescot Oct 2, 2026
acfc10f
fix(compositor): keep the 3D models out of the Linux layer pipeline
EtienneLescot Oct 2, 2026
4544fdd
perf(compositor): evaluate one corner distance per pixel on Linux
EtienneLescot Oct 2, 2026
6374638
perf(compositor): scissor the Linux cursor trail composite to the trail
EtienneLescot Oct 2, 2026
cafcdb6
perf(compositor): copy a static background instead of redrawing it on…
EtienneLescot Oct 2, 2026
f055ec4
docs(perf): record the Linux export regression of 2.0 and its fixes
EtienneLescot Oct 2, 2026
61f3c73
fix(compositor): pick the Linux layer pipeline from the layer's mode
EtienneLescot Oct 2, 2026
8caaa20
fix(compositor): keep the 3D models out of the D3D11 and Metal layer …
EtienneLescot Oct 2, 2026
2fb994e
perf(compositor): evaluate one corner distance per pixel on Windows a…
EtienneLescot Oct 2, 2026
39dafaf
docs(perf): record the per-mode pipeline choice and what Windows and …
EtienneLescot Oct 2, 2026
f698032
perf(compositor): compare the background key without copying the back…
EtienneLescot Oct 2, 2026
dd5e914
perf(compositor): bring the background cache and the trail scissor to…
EtienneLescot Oct 2, 2026
57da8eb
docs(perf): note the background cache and trail scissor on Windows an…
EtienneLescot Oct 2, 2026
0624c14
perf(compositor): reuse the kept background's texture on Windows and …
EtienneLescot Oct 2, 2026
b8bd917
docs(perf): record the Windows A/B of the layer-shader fix
EtienneLescot Oct 2, 2026
b2e8635
docs(perf): limit the byte-identical claim to the exports that were
EtienneLescot Oct 3, 2026
746277d
docs(testing): log the v2.0.0-rc.13 computer-use e2e pass
EtienneLescot Oct 3, 2026
845f58f
feat(timeline): show scissors on the trim tool
EtienneLescot Oct 3, 2026
db9ba2a
feat(webcam): default the camera to 40% and let it grow to 60%
EtienneLescot Oct 3, 2026
93e3ed0
docs(testing): log the v2.0.0-rc.13 macOS computer-use e2e pass
EtienneLescot Oct 3, 2026
40d062f
docs(testing): restore the macOS RC passes that never reached the res…
EtienneLescot Oct 3, 2026
54f4ea9
perf(preview): stop decoding the stand-in camera when a clip has none
EtienneLescot Oct 3, 2026
7d9ad96
docs(preview): record the free-run decode budget and what still falls…
EtienneLescot Oct 3, 2026
69b791b
test(preview): prove the stand-in never moves, and stop at a source t…
EtienneLescot Oct 3, 2026
821902a
chore(release): bump to 2.0.0-rc.1 [skip ci]
EtienneLescot Sep 27, 2026
fe52810
chore(release): bump to 2.0.0-rc.2 [skip ci]
github-actions[bot] Sep 30, 2026
2a9a01e
chore(release): bump to 2.0.0-rc.3 [skip ci]
github-actions[bot] Sep 30, 2026
c8512b6
chore(release): bump to 2.0.0-rc.4 [skip ci]
github-actions[bot] Oct 1, 2026
ca8126d
chore(release): bump to 2.0.0-rc.5 [skip ci]
github-actions[bot] Oct 1, 2026
f993b24
chore(release): bump to 2.0.0-rc.6 [skip ci]
github-actions[bot] Oct 1, 2026
c69ebaf
chore(release): bump to 2.0.0-rc.7 [skip ci]
github-actions[bot] Oct 1, 2026
4eabce5
chore(release): bump to 2.0.0-rc.8 [skip ci]
github-actions[bot] Oct 1, 2026
509242a
chore(release): bump to 2.0.0-rc.9 [skip ci]
github-actions[bot] Oct 1, 2026
5b9be8d
chore(release): bump to 2.0.0-rc.10 [skip ci]
github-actions[bot] Oct 2, 2026
836a2e8
chore(release): bump to 2.0.0-rc.11 [skip ci]
github-actions[bot] Oct 2, 2026
9af5662
chore(release): bump to 2.0.0-rc.12 [skip ci]
github-actions[bot] Oct 2, 2026
99cdc8d
chore(release): bump to 2.0.0-rc.13 [skip ci]
github-actions[bot] Oct 2, 2026
cbe7a92
chore(release): bump to 2.0.0-rc.14 [skip ci]
github-actions[bot] Oct 3, 2026
cbe97dd
chore(release): bump to 2.0.0-rc.15 [skip ci]
github-actions[bot] Oct 3, 2026
1d94186
chore(release): bump to 2.0.0 [skip ci]
github-actions[bot] Oct 3, 2026
981c914
feat(website): show a live demo in the hero
EtienneLescot Oct 3, 2026
359171a
fix(website): smooth docking and align the responsive preview
EtienneLescot Oct 3, 2026
8a14071
fix(website): keep framing aligned during pane transitions
EtienneLescot Oct 3, 2026
4246ca7
style(website): give the timeline tool palette more room
EtienneLescot Oct 3, 2026
9644d72
feat(website): announce v2 above the new homepage promise
EtienneLescot Oct 3, 2026
7a01d4d
fix(website): announce that OpenScreen v2 is here
EtienneLescot Oct 3, 2026
b60a519
fix(website): stabilize preview resizing and timeline spacing
EtienneLescot Oct 3, 2026
f9f422c
style(website): announce v2 with a compact hero badge
EtienneLescot Oct 3, 2026
f2c2146
style(website): remove the clipped preview glow
EtienneLescot Oct 3, 2026
9ba7955
style(website): cap the editor and footage width
EtienneLescot Oct 3, 2026
ea6e940
fix(website): retain larger footage at its natural ratio
EtienneLescot Oct 3, 2026
ad06bdc
style(website): give the homepage introduction more room
EtienneLescot Oct 3, 2026
f27f766
feat(website): detect the platform for direct downloads
EtienneLescot Oct 3, 2026
2c64f7e
perf(website): serve responsive wallpapers from Cloudflare R2
EtienneLescot Oct 3, 2026
ddd73e6
style(website): update the demo headline and translations
EtienneLescot Oct 3, 2026
fcc8e97
docs(testing): log the v2.0.0-rc.15 computer-use e2e pass
EtienneLescot Oct 3, 2026
2e0733e
docs(testing): link the rc.15 defects to their issues
EtienneLescot Oct 3, 2026
bf8efb9
docs: add missing third-party notices
EtienneLescot Oct 4, 2026
8563665
docs: limit the Recordly notice to the code taken from it
EtienneLescot Oct 4, 2026
8f3046c
docs: drop the upstream link from the Recordly notice
EtienneLescot Oct 4, 2026
16c5ecc
fix(preview): hold the webcam's last frame when a clip is entered pas…
EtienneLescot Oct 6, 2026
05e2f5b
fix(record): keep the Camera row off when no camera can be opened
EtienneLescot Oct 6, 2026
dbfec5a
fix(record): run one camera check for a double click
EtienneLescot Oct 6, 2026
682f809
ci: start release notes at the previous stable tag, by SemVer
EtienneLescot Oct 6, 2026
5154b1c
fix(editor): keep Edit clip's Apply in view and its edit through a ba…
EtienneLescot Oct 6, 2026
ebef143
fix(timeline): copy anchored modifiers onto a duplicated clip
EtienneLescot Oct 6, 2026
c4c761b
fix(editor): close top-bar menus on a click on the empty bar
EtienneLescot Oct 6, 2026
01978b8
fix: close menus on Escape and hand focus back to their trigger
EtienneLescot Oct 6, 2026
e2d9889
fix(transcript): keep a skipped word's restore control beside it
EtienneLescot Oct 6, 2026
ef014f7
fix(transcript): let Ctrl/Cmd+Z in the transcript undo a cut
EtienneLescot Oct 6, 2026
68d3a23
fix(editor): draw the Edit clip menu above the timeline
EtienneLescot Oct 6, 2026
2ac20cf
fix(ui): open a tooltip on keyboard focus, not on any focus
EtienneLescot Oct 6, 2026
c4e43e2
fix(export): stop an MP4 export between frames, publish only a finish…
EtienneLescot Oct 6, 2026
f2012f9
fix(export): enable Cancel during an MP4 export (#1014)
EtienneLescot Oct 6, 2026
eecb7e1
docs: describe MP4 export cancellation and its manual check
EtienneLescot Oct 6, 2026
f22cc8a
fix(audio): keep each take on its own clips through a clip edit (#1011)
EtienneLescot Oct 6, 2026
cab5ad8
fix(audio): relabel a joined clip's takes without re-cutting them (#1…
EtienneLescot Oct 6, 2026
e2223a9
fix(timeline): keep a dragged region whole when it repels (#1008)
EtienneLescot Oct 6, 2026
25532ef
fix(timeline): keep a boundary piece that rounds to a whole millisecond
EtienneLescot Oct 6, 2026
1509e6f
fix(hud): keep the HUD's size while it is dragged at fractional scali…
EtienneLescot Oct 6, 2026
98411d6
fix(hud): refuse an empty size from the renderer
EtienneLescot Oct 6, 2026
3170d3f
fix(preview): stop the free-run at the end of the programme (#997)
EtienneLescot Oct 6, 2026
910da20
fix(preview): hold the last clip's own last frame, not the first one …
EtienneLescot Oct 6, 2026
f7615d4
test(preview): check the view played up to the last clip's end
EtienneLescot Oct 6, 2026
9b5f867
fix(timeline): edit one region of a merged pill, not the whole pill (…
EtienneLescot Oct 6, 2026
ed0798c
fix(timeline): keep a 1 ms overlap in one edit group; refresh the con…
EtienneLescot Oct 6, 2026
b7e107d
feat(mcp): checkpoints to revert a whole agent turn in one step
EtienneLescot Oct 7, 2026
c3b2cad
docs(mcp): list restoreCheckpoint among the destructive tools
EtienneLescot Oct 7, 2026
08604ab
fix(transcript): refuse every native edit the block does not handle (…
EtienneLescot Oct 7, 2026
1c58dad
fix(hud): arrow-key navigation in the language menu (#1015)
EtienneLescot Oct 7, 2026
3e9ae72
fix(ai-edition): fan speed and Full Camera regions out to both halves…
EtienneLescot Oct 7, 2026
b113487
fix(chat): close the reasoning menu and model quick-pick on Escape (#…
EtienneLescot Oct 7, 2026
f82c20a
fix: leave Escape to the rewind confirmation over the model quick-pick
EtienneLescot Oct 7, 2026
798d590
fix(record): never record a microphone the OS does not list (#995)
EtienneLescot Oct 7, 2026
8650f9d
fix(record): let a second click during the microphone check take the …
EtienneLescot Oct 7, 2026
6e27423
fix(record): drop a pending microphone turn-on once the take starts
EtienneLescot Oct 7, 2026
f261fa4
fix(mac): count the HUD timer from the helper's first frame (#901)
EtienneLescot Oct 7, 2026
9317871
docs(stt): record why transcript cuts are not snapped to quiet points…
EtienneLescot Oct 7, 2026
ebe6935
feat(timeline): measure zoom transition windows on the timeline (#1028)
EtienneLescot Oct 7, 2026
3954ca0
feat(ai-edition): tell the agent and MCP clients where zoom transitio…
EtienneLescot Oct 7, 2026
349b42a
fix(ai-edition): measure a trim without clipId on every clip of its a…
EtienneLescot Oct 7, 2026
4ebe3ce
fix(windows): keep the screen video on the clock when the writer miss…
EtienneLescot Oct 7, 2026
e8b8544
fix(windows): give the screen and webcam clocks one origin per tick
EtienneLescot Oct 7, 2026
a17e19a
fix(gif): build the same palette for the same frame (#952)
EtienneLescot Oct 7, 2026
528ce5d
perf(gif): prune the nearest-colour search on a red-sorted palette (#…
EtienneLescot Oct 7, 2026
0a814fb
perf(gif): map and LZW-encode frames on a worker pool (#952)
EtienneLescot Oct 7, 2026
724d4c6
docs(perf): record where GIF export time went (#952)
EtienneLescot Oct 7, 2026
0ef120a
fix(gif): bound frames submitted but not yet written
EtienneLescot Oct 7, 2026
db8a31c
feat(timeline): draw each zoom's move-in and move-out as trails (#1028)
EtienneLescot Oct 7, 2026
ed320b2
fix(editor): name the inspector's icon controls in the shared tooltip
EtienneLescot Oct 8, 2026
1dd3869
chore: bump nix package to v2.0.0
github-actions[bot] Oct 3, 2026
6bf3060
feat(timeline): show and report the pan between chained zooms (#1028)
EtienneLescot Oct 8, 2026
6927255
feat(stt): pass a prompt field to whisper as its initial prompt
EtienneLescot Oct 8, 2026
13db77e
feat(transcription): per-project names and terms for Whisper
EtienneLescot Oct 8, 2026
e63e8ee
test: declare the names and terms save in the write audit
EtienneLescot Oct 8, 2026
df33fc1
fix(stt): frame the names and terms as a glossary prompt
EtienneLescot Oct 8, 2026
0fee0f1
fix(media): save the terms on the latest document, regenerate after t…
EtienneLescot Oct 8, 2026
5811533
fix(media): regenerate only after the terms saved
EtienneLescot Oct 8, 2026
c593090
fix(preview): stop Chromium decoding a soundless recording's picture
EtienneLescot Oct 8, 2026
d0091da
fix(preview): end a wall-clock element whose duration arrives late
EtienneLescot Oct 8, 2026
1214a74
ci(nix): build PRs that touch the PipeWire and whisper sources, and a…
EtienneLescot Sep 14, 2026
b96b666
feat(timeline): flag zoom moves a clip junction cuts (#1028)
EtienneLescot Oct 8, 2026
1af6182
fix(compositor): keep Full Camera full across a trim inside it
EtienneLescot Oct 8, 2026
3ae6a49
fix(capture): enumerate screens and windows in separate calls on X11
EtienneLescot Oct 8, 2026
9bc6e1d
ci(nix): require every sources attempt to report a display
EtienneLescot Oct 8, 2026
c12a6cd
ci(release): refresh the Nix npm hash in the version-bump commit
EtienneLescot Oct 8, 2026
870196c
ci(release): run the hash refresh from the dispatched ref
EtienneLescot Oct 8, 2026
89f89ff
fix: #966
marcgabe15 Oct 9, 2026
2eb2830
docs(macos): say a picker capture leaves out every OpenScreen window
EtienneLescot Oct 10, 2026
5c4dcbc
fix(agent): preserve recorded cursor visibility
satwiksharma01 Oct 9, 2026
91b0fe6
docs(agent): name visible:false in the getCursorTrack tool description
EtienneLescot Oct 10, 2026
52eda0e
fix(macos): say when a restart discarded the take and drop the empty …
entity-0-0-2 Oct 9, 2026
695f100
fix(i18n): translate the failed-restart toast
EtienneLescot Oct 10, 2026
eddab6e
test(macos): cover the empty-file cleanup after a failed start
EtienneLescot Oct 10, 2026
53f8f1e
fix(i18n): polish Simplified Chinese tooltips
auberginewly Oct 9, 2026
7519cce
fix(i18n): keep control names in zh-CN icon tooltips
EtienneLescot Oct 10, 2026
a9fc99c
docs(i18n): match zh-CN docs to the renamed app labels
EtienneLescot Oct 10, 2026
f13253f
fix(linux): respect an explicit Ozone display backend
mcmah309 Oct 9, 2026
3116651
refactor(linux): share the Wayland session check with source enumeration
EtienneLescot Oct 10, 2026
42bcce2
fix(stt): preserve media-clock audio offsets
satwiksharma01 Oct 9, 2026
0cd0c9d
feat(cursor): add Glass Lens, a glass cursor that refracts the pictur…
EtienneLescot Oct 4, 2026
5cf2db3
test(cursor): count Glass Lens in the theme picker, and document glas…
EtienneLescot Oct 4, 2026
b214eca
docs(cursor): add the compositor's Glass Lens renders
EtienneLescot Oct 4, 2026
27ed325
docs(perf): record the shader and background-cache fixes on a Mac min…
EtienneLescot Oct 3, 2026
d659ffd
fix(nix): use wrapped Electron in dev shell
bet4it Oct 6, 2026
44e65b6
fix(nix): point the dev shell at bin/ on every system
EtienneLescot Oct 10, 2026
07e0467
test(compositor): share the D3D11 render-test harness
quotentiroler Sep 30, 2026
f2a7035
test(compositor): silence the unused re-export in the shared harness
EtienneLescot Oct 10, 2026
146fe92
build: ship the third-party licence texts in the installers
EtienneLescot Oct 4, 2026
b3d37c9
fix(build): read a crate's license-file and fail when cargo cannot li…
EtienneLescot Oct 10, 2026
a34f1a0
fix(linux): retry PipeWire capture with shared memory
kiwikreativo Oct 8, 2026
e72abcf
fix(linux): only fail video sessions on early stream errors
EtienneLescot Oct 10, 2026
9b96383
fix(linux): fail cursor-only sessions on errors before streaming
EtienneLescot Oct 10, 2026
feb6c92
fix(cli): let the Linux portal select recording sources
mcmah309 Oct 9, 2026
d77c92b
fix(cli): log that the portal picks the source and --display/--window…
EtienneLescot Oct 10, 2026
e3bde93
feat(linux): add standard AppImage update metadata
satwiksharma01 Oct 8, 2026
8bbc0d3
feat(workbench): keep versioned measurements and offline replay
My-Denia Sep 13, 2026
5272868
fix(workbench): bind the replay sample to its standalone source
My-Denia Sep 13, 2026
e6f2843
fix(workbench): reject transport failures and keep compare weights ho…
My-Denia Sep 13, 2026
31222ac
fix(workbench): keep compare identity request-bound
My-Denia Sep 13, 2026
bce3888
fix(workbench): hash the request contract once for compare identity
My-Denia Sep 13, 2026
019e6c8
fix(workbench): share the judge budget and hash transport once
My-Denia Sep 13, 2026
11979d1
fix(workbench): bind retry evidence, fingerprints, and Chat model ide…
My-Denia Sep 13, 2026
72c2111
test(workbench): regenerate the transport-bound scripted control
My-Denia Sep 13, 2026
883176c
fix(workbench): keep pre-round retry failures in attempt evidence
My-Denia Sep 13, 2026
cd940e7
test(workbench): retie the scripted control to the retry-evidence fix
My-Denia Sep 13, 2026
ed3e8b5
fix(workbench): adopt only the retained attempt cassette
My-Denia Sep 14, 2026
8578ece
test(workbench): retie the scripted control to the retained-attempt fix
My-Denia Sep 14, 2026
2f7a577
fix(workbench): score undecided repetitions and compare fractional tr…
My-Denia Sep 20, 2026
1f8d66e
fix(workbench): attribute judge evidence correctly
My-Denia Sep 20, 2026
05343d4
fix(workbench): scan decoded Responses requests before adoption
My-Denia Sep 20, 2026
084266f
test(workbench): regenerate the scripted control on the final source …
My-Denia Sep 20, 2026
9bc143c
fix(workbench): inspect response evidence before adoption
My-Denia Sep 21, 2026
1537882
fix(workbench): validate fingerprints and judge evidence
My-Denia Oct 2, 2026
55be9cf
perf(workbench): capture the judge source identity once per invocation
EtienneLescot Oct 10, 2026
de3c527
docs(workbench): say the scripted control only replays on its own sou…
EtienneLescot Oct 10, 2026
51df858
docs(ai-edition): note maxRetries only reaches the OpenAI-compatible …
EtienneLescot Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ CMakeLists.txt text eol=lf
# so the next one-line edit showed up as a whole-file rewrite in two locales.
*.md text eol=lf
*.mdx text eol=lf

# Adopted measurement manifests hash exact bytes; keep their artifacts unchanged.
workbench/measurements/** -text
41 changes: 41 additions & 0 deletions .github/scripts/previous-stable-tag.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Prints the tag a release's notes start from: the highest stable tag (vX.Y.Z,
// no suffix) below the given version, by SemVer, or an empty line when there is
// none. The tags come on stdin as `git tag -l 'v*'` lists them: every tag,
// whether or not it is reachable from the release commit.
//
// build.yml used to guess that tag's name by arithmetic and fall back to
// `git describe` when the guess did not exist (#1002). 2.0.0 guessed v1.0.0,
// which never existed, and `git describe` on release/v2.0.0 found the release's
// own last RC: v2.0.0 shipped with an empty changelog. A guess that did exist
// could still be wrong: 1.13.0 compared against v1.12.0 and repeated the PRs of
// v1.12.1 and v1.12.2. Only a tag that exists can come out of here, which also
// keeps the RC notes' `git log <tag>..` from dying on `unknown revision`, as
// v1.9.4-rc.1's did when the guess named a 1.9.3 that never shipped.

import { readFileSync } from "node:fs";
import { argv } from "node:process";

const STABLE_TAG = /^v(\d+)\.(\d+)\.(\d+)$/;

const parse = (tag) => tag.match(STABLE_TAG)?.slice(1).map(Number);
const compare = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];

/**
* @param {string} version Stable version being released, e.g. "2.0.0".
* @param {string[]} tags Tag names; anything but vX.Y.Z is ignored.
* @returns {string} The highest vX.Y.Z below `version`, or "" when there is none.
*/
export function previousStableTag(version, tags) {
const current = parse(`v${version}`);
if (!current) throw new Error(`invalid version ${JSON.stringify(version)}; expected X.Y.Z`);
const below = tags
.map((tag) => [tag, parse(tag)])
.filter(([, parts]) => parts && compare(parts, current) < 0);
below.sort(([, a], [, b]) => compare(b, a));
return below[0]?.[0] ?? "";
}

// Only run when invoked directly, so the test can import the function.
if (import.meta.filename === argv[1]) {
console.log(previousStableTag(argv[2], readFileSync(0, "utf8").split(/\s+/)));
}
78 changes: 78 additions & 0 deletions .github/scripts/previous-stable-tag.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { previousStableTag } from "./previous-stable-tag.mjs";

// Real tags of this repository, in the order `git tag -l` prints them: by name, so v1.9.x
// comes after v1.13.0 and picking by position or as text gets it wrong. The v0.0.0-* tags
// host release assets; `git describe` once picked one of them for v2.0.0-rc.1's notes.
const TAGS = [
"v0.0.0",
"v0.0.0-onnxruntime-1.27.1",
"v1.0.1",
"v1.10.0",
"v1.12.0",
"v1.12.1",
"v1.12.1-rc.1",
"v1.12.2",
"v1.12.2-rc.1",
"v1.13.0",
"v1.13.0-rc.6",
"v1.9.2",
"v1.9.3-rc.1",
"v1.9.6",
"v2.0.0",
"v2.0.0-rc.15",
];

describe("previousStableTag", () => {
it("compares a major against the last stable of the line before", () => {
// The arithmetic guessed v1.0.0, which does not exist, and the fallback found
// v2.0.0-rc.15: v2.0.0 shipped with an empty changelog (#1002).
expect(previousStableTag("2.0.0", TAGS)).toBe("v1.13.0");
});

it("compares a minor against the last patch, not the .0", () => {
// Against v1.12.0, 1.13.0's notes repeated every PR of v1.12.1 and v1.12.2.
expect(previousStableTag("1.13.0", TAGS)).toBe("v1.12.2");
});

it("compares a patch against the patch before it", () => {
expect(previousStableTag("1.12.2", TAGS)).toBe("v1.12.1");
});

it("is empty when no stable tag sorts below", () => {
// A first release: its RCs exist, nothing before them does.
expect(previousStableTag("1.0.0", ["v1.0.0", "v1.0.0-rc.1", "v1.0.0-rc.2"])).toBe("");
});

it("ignores pre-release tags", () => {
// 1.9.3 shipped only as rc.1, so the last release before 1.9.4 is v1.9.2.
expect(previousStableTag("1.9.4", TAGS)).toBe("v1.9.2");
});

it("rejects a version that is not X.Y.Z", () => {
expect(() => previousStableTag("2.0.0-rc.1", TAGS)).toThrow(/invalid version/);
});

// The direct-invocation guard makes the script print nothing at all if it ever stops
// matching, and the workflow would read that as "no previous release". So this runs it
// exactly as build.yml does: relative path from the repo root, the tags on stdin.
it("runs the way build.yml invokes it", () => {
const repoRoot = join(import.meta.dirname, "../..");
const workflow = readFileSync(join(repoRoot, ".github/workflows/build.yml"), "utf8");
expect(workflow).toContain(
`git tag -l 'v*' | node .github/scripts/previous-stable-tag.mjs "$STABLE_VERSION"`,
);

const run = (version) =>
execFileSync("node", [".github/scripts/previous-stable-tag.mjs", version], {
cwd: repoRoot,
input: `${TAGS.join("\n")}\n`,
encoding: "utf8",
});
expect(run("2.0.0")).toBe("v1.13.0\n");
expect(run("0.0.0")).toBe("\n");
});
});
20 changes: 20 additions & 0 deletions .github/scripts/refresh-nix-npm-hash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Rewrites `npmDepsHash` in nix/package.nix for the package-lock.json in the working tree.
#
# Called by prerelease.yml and promote.yml right after set-release-version.mjs, in the same
# commit. The lockfile's root `version` is part of what the hash covers, so every version bump
# changes it; that commit is `[skip ci]`, and refreshing the hash anywhere later left `nix build`
# red from the release until a separate bump PR landed. Needs Nix on PATH.
set -euo pipefail

hash=$(nix run nixpkgs#prefetch-npm-deps -- package-lock.json)
if [[ -z "$hash" ]]; then
echo "::error::prefetch-npm-deps returned an empty hash"
exit 1
fi
sed -i -E "s|^([[:space:]]*npmDepsHash[[:space:]]*=[[:space:]]*)\"[^\"]*\";|\1\"${hash}\";|" nix/package.nix
grep -q "npmDepsHash = \"${hash}\";" nix/package.nix || {
echo "::error::npmDepsHash line not found in nix/package.nix"
exit 1
}
echo "npmDepsHash: ${hash}"
82 changes: 38 additions & 44 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ jobs:
uses: ./.github/actions/setup

# STT is the bundled whisper-stt-server (whisper.cpp with native DTW token
# timestamps); no VAD model is fetched here. The binary is built by
# build-whisper-stt.yml and staged below — without that step the installer
# ships without speech-to-text. See
# technical-documentation/architecture/transcription-and-captions.md.
# timestamps); no model is fetched here. The binary is built by
# build-whisper-stt.yml and staged below, from the run built from this
# commit's helper sources — without that step the installer ships without
# speech-to-text. See
# technical-documentation/architecture/transcription-and-captions.md, and
# technical-documentation/engineering/release-and-secrets.md for the run.
- name: Stage whisper-stt binaries
shell: bash
env:
Expand Down Expand Up @@ -376,6 +378,13 @@ jobs:
- name: Stage ONNX Runtime
run: npm run fetch:onnxruntime

# Fourth step spelled out for the same reason: `build:mac`, `build:win` and
# `build:linux` chain it before electron-builder. It writes the licence texts of the
# bundled npm packages and of the crates in the addon; scripts/before-pack.cjs
# refuses to package without them.
- name: Generate third-party licences
run: npm run licenses:generate

- name: Package .app bundle
run: npx electron-builder --mac --${{ matrix.arch }} --dir --publish never
env:
Expand Down Expand Up @@ -649,9 +658,9 @@ jobs:

# bsdtar (libarchive-tools) is fpm's mtree generator for the pacman target.
# rpmbuild (rpm) is what fpm shells out to for the rpm target; without it the
# build fails at packaging, not at config parse.
# build fails at packaging, not at config parse. zsync generates AppImageUpdate sidecars.
- name: Install Linux packaging dependencies
run: sudo apt-get update && sudo apt-get install -y libarchive-tools rpm
run: sudo apt-get update && sudo apt-get install -y libarchive-tools rpm zsync

# patchelf is what build-linux-compositor-addon.mjs renames the ffmpeg symbols
# with, so the addon cannot bind to Chromium's bundled ffmpeg — an unconditional
Expand Down Expand Up @@ -706,6 +715,21 @@ jobs:
exit 1
fi

- name: Verify AppImage update information and sidecars
run: |
VERSION="$(node -p 'require("./package.json").version')"
EXPECTED='gh-releases-zsync|getopenscreen|openscreen|latest|Openscreen-Linux-*.AppImage.zsync'
# Helper-only prereleases can be selected by AppImageUpdate's latest-all channel.
# RCs keep using electron-updater; their .zsync is available by its explicit URL.
if [[ "$VERSION" == *-* ]]; then EXPECTED=''; fi
while IFS= read -r -d '' IMAGE; do
test -s "${IMAGE}.zsync" \
|| { echo "::error::${IMAGE}.zsync missing — external AppImage updates have no sidecar"; exit 1; }
INFO="$("$IMAGE" --appimage-updateinformation)"
[[ "$INFO" == "$EXPECTED" ]] \
|| { echo "::error::Unexpected AppImage update information in ${IMAGE}: ${INFO}"; exit 1; }
done < <(find release -type f -name '*.AppImage' -print0)

# The Linux counterpart of the Windows job's "Verify native binaries load under
# package identity", added for the same reason and after the same kind of miss:
# 1.9.1 shipped three sonames that nothing declared and nothing bundled — libgbm.so.1
Expand Down Expand Up @@ -745,16 +769,12 @@ jobs:
name: openscreen-linux
path: |
release/**/*.AppImage
release/**/*.AppImage.zsync
release/**/*.deb
release/**/*.pacman
release/**/*.rpm
release/**/latest-linux.yml
# Still no *.zsync, and there never will be: zsync was electron-updater's old delta
# format and app-builder-lib 26.x dropped it in favour of the block map it embeds
# directly in the AppImage. That glob had matched nothing since the dependency bump,
# silently — `if-no-files-found: error` evaluates the union of these patterns, so one
# dead glob among live ones never fails. Hence the explicit assertion below.
#
# .zsync serves external AppImage tools; electron-updater uses the embedded blockmap.
# latest-linux.yml serves all four formats from one file: each updater picks its own
# extension out of the `files:` list. app-update.yml and the `package-type` marker are
# already inside the deb/rpm/pacman payloads — only this feed was missing.
Expand All @@ -778,8 +798,8 @@ jobs:
- name: Checkout code
uses: actions/checkout@v7
with:
# Full history + tags: the RC notes below are built from `git log` over the
# range since the previous RC tag, and resolving that tag needs the tags.
# Full history + tags: the previous release's tag is picked from every tag in the
# repo, and the RC notes below are built from `git log` over the range since it.
fetch-depth: 0

- name: Resolve release tag
Expand Down Expand Up @@ -818,16 +838,11 @@ jobs:
# Compute the previous stable tag for auto-generated release notes. We don't use
# GitHub's "most recent prior release by date" because the fork carries re-published
# upstream releases whose published_at is more recent than the fork's own first release.
# For SemVer X.Y.Z: previous is vX.Y.(Z-1) if Z>0, else vX.(Y-1).0, else v(X-1).0.0.
# Picked by SemVer among the tags that exist, never guessed from the version number:
# the script says what guessing cost (#1002). Left EMPTY when no stable tag sorts
# below this version; each consumer below decides what "no previous release" means.
STABLE_VERSION="${VERSION%%-*}"
IFS='.' read -r PX PY PZ <<< "$STABLE_VERSION"
if (( PZ > 0 )); then
NOTES_START_TAG="v${PX}.${PY}.$((PZ - 1))"
elif (( PY > 0 )); then
NOTES_START_TAG="v${PX}.$((PY - 1)).0"
else
NOTES_START_TAG="v$((PX - 1)).0.0"
fi
NOTES_START_TAG="$(git tag -l 'v*' | node .github/scripts/previous-stable-tag.mjs "$STABLE_VERSION")"
# For an RC, compare against the PREVIOUS RC of the same line, not the previous
# stable. Deriving the start tag from STABLE_VERSION alone made every RC of a
# line span the same range, so each re-cut just repeated the last RC's notes
Expand All @@ -843,27 +858,6 @@ jobs:
fi
done
fi
# Everything above computes what the previous release was *called* and
# never checks that it exists. A version line that stopped at its RC
# makes that a name for nothing: 1.9.3 shipped only as rc.1, so
# v1.9.4-rc.1 asked git for v1.9.3..v1.9.4-rc.1 and the publish step
# died on `unknown revision` -- after all four platforms had already
# built, and with publish-msstore sitting behind publish-release, so
# the same gap would silently block a stable release's Store
# deployment too. The rc walk-down above handles a skipped RC; nothing
# handled a skipped stable, and it does not run at all for an rc.1.
if ! git rev-parse -q --verify "refs/tags/${NOTES_START_TAG}" >/dev/null; then
# The nearest tag reachable from the release commit's parent, which
# is what "since the last release" meant in the first place. Left
# EMPTY when no tag is reachable at all, rather than filled with the
# root commit: the stable path hands this to `gh release create
# --notes-start-tag`, which is the API's previous_tag_name and takes
# a tag NAME -- a commit SHA there is not a lenient fallback, it is
# an invalid argument. Each consumer below decides what "no previous
# release" means for it.
NOTES_START_TAG="$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || true)"
echo "Previous-release tag did not exist; using ${NOTES_START_TAG:-<none>}"
fi
echo "Computed notes_start_tag=${NOTES_START_TAG} for tag=${TAG}"

echo "tag=$TAG" >> "$GITHUB_OUTPUT"
Expand Down
Loading
Loading