| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(import): start every URL in a download batch download_media and push_asset stopped starting URLs 75 seconds into a batch, and the tool description asked the model for at most three URLs per call. The window (b6667db6) only kept a batch inside the AI SDK chunk watchdog, which used to keep counting while a tool ran. Since ai 7.0.136 the watchdog stops when the model response ends and tool time only counts against the run's step and tool timeouts, so the window did nothing but turn work away. Each URL stays bounded on its own by the connect and response-header limits of /api/import-url. serialBatch now runs every URL in order, one at a time, with one row per URL. The tool description and the generated server tool catalog drop the window and the three-URL advice, and stock-tools.verify checks the order, the one-at-a-time execution and that a failed row does not stop the URLs after it. Verification: npx tsc -b, npm run lint, npm test (197 segments) and npm run build pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
fix(editor): explain the HTTPS requirement instead of a blank editor Over plain HTTP from another machine (a LAN IP or reverse proxy) the page is not a secure context, so browsers withhold crypto.randomUUID, crypto.subtle, WebCodecs and the async clipboard. The lazy editor threw on import and, with no error boundary, blanked the whole app; a UUID fallback would only move the crash. EditorRoute now checks window.isSecureContext before the editor chunk is requested and shows a localized localhost-or-HTTPS requirement with the current origin, keeping the project list usable. An error boundary around the lazy editor turns any other load or render failure into an error with a reload action. The desktop app loads a loopback origin and is unaffected. Fixes #183 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 24 天前 | |
fix: make local VAD silence removal reachable and warm installed local models Three capabilities existed in the tree but could never run. The VAD-backed silence removal was gated only by the build-time VITE_ENABLE_VAD_SILENCE_REMOVAL flag, so released builds carried the tracked Silero model (public/models/silero-vad, ~13MB) as unreachable bytes and remove_silence always refused to cut. The three desktop native warm-up entry points and ensureSileroVad had zero call sites, so those workers always cold-started on first use. runAgent had no production and no test caller. - Add src/audio/vadPreference.ts: a device-local tri-state preference (cc.vadSilenceRemoval). An unchosen preference still defers to the build flag, so builds that shipped the flag keep their behaviour and every other build stays disabled until the user opts in. - Move the single gate vadSilenceRemovalEnabled(storage?, buildFlag?) out of vad.ts so both inputs are injectable and truthiness is normalized in exactly one place; vad.ts keeps runner registration and evidence logic only. - Expose the toggle in Settings > Local models > Local transcription with zh/en/it/ru copy, and point the disabled remove_silence note at that location so the agent can guide the user. - Warm only model packs already reported installed. Pack status is checked first because a load request for a missing pack fails pack verification, and the rhythm and CLAP adapters treat a failed load as "native unavailable for this session", which would disable the native path until reload. Preloading never downloads a model. - Warm the bundled Silero model on idle only when the preference is on. - Remove runAgent together with the helpers it exclusively owned (runPreparedAgent, runCodexBackend, createContextRepreparer, contextRecord, toCodexToolSpec) and the orphaned imports. The comment claiming three verifies keep it alive was wrong: those verifies exercise runCodexAgent and runApiAgent directly. runtime.ts drops from 427 to 179 lines and the runtime chunk from 231.63 kB to 194.60 kB (gzip 71.01 -> 59.56). Shared paths touched, and the evidence they stay intact: - Silence gate (src/audio/vad.ts, src/audio/silence.ts): with no stored preference the gate is false and analyzeClipSilence short-circuits before fetching the source; a real browser session issues zero silero/ort requests when the editor opens. - src/agent/runtime.ts, which hosts the live executeCodexTool used by every server-run tool call: a real DeepSeek turn executed read_project in the browser and answered "Canvas width x height: 1080 x 1920. No modifications made (read-only)." - src/hooks/useInferenceWarmup.ts: the existing ASR warm-up path is unchanged; native warm-up runs only for installed packs and the VAD warm-up only for opted-in users. - src/components/settings/LocalAsrPane.tsx: the toggle renders, reflects the stored value, persists '0'/'1', and keeps its state across a panel reopen. Enabled-path proof: on a 5.18s Chinese speech sample Silero returned confidence 0.942 with speech spans 160-480 ms and 576-5152 ms in 773 ms, and the conservative intersection correctly removed nothing because the clip is speech throughout. Verification: tsc -b clean, oxlint clean, npm run build clean, npm test 178/179 segments pass. The single failure is pre-existing on main and untouched here: verify-gate-coverage flags server/keystore.ts at 502 lines. The new verify src/audio/vadPreference.verify.ts is registered in verify:captions. | 1 个月前 | |
fix(editor): serialize caption fonts and preserve backdrop borders | 17 天前 | |
docs: translate code comments to English | 2 个月前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 1 天前 | |
fix(editor): a split motion graphic continues its animation instead of restarting Splitting a motion graphic gave two clips that each played the template from frame 0: the second piece replayed the intro, and both faded out at their own ends, so a cut in the middle of an animation showed the opening scene again. Both pieces now keep the length of the whole design (designDurationInFrames) and play their own window of it from srcInFrame. The template's clock is shifted through the enclosing sequence, so useCurrentFrame and useVideoConfig see the design's time and length. A split piece trims like video: its start cuts into or back out of the animation, and its end stops at the design's last frame. Unsplit clips are unchanged. The split tool description and the motion-graphic skills say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
chore(build): upgrade TypeScript to 7 TS 7's root package no longer exposes the compiler API, so the i18n AST scans move to @babel/parser. Remotion 4.0.537 is required for its TS 7-aware bundler; the WebCodecs pre-flight follows Mediabunny 1.61.6 rate control. | 1 天前 | |
fix(editor): serialize caption fonts and preserve backdrop borders | 17 天前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 1 天前 | |
Merge PR #123 (FlexCrop) — crop feature only, agent governor excluded Trial merge of J160KU's FlexCrop onto v0.2.12 for CI validation. Two things had to be resolved beyond ordinary conflicts. The PR does not build. npm run build runs tsc -b, and on the PR branch alone that fails four ways: two unused imports in systemPrompt.ts and a cast in read-project-tools-check.verify.ts that omits selectedIds/selectedId and then reads them. npx tsc --noEmit passes, which is presumably what was run. Fixed here by completing the cast; the systemPrompt errors disappear with the revert below. The PR also carries 192 lines of agent-behaviour change that its title and summary do not mention, so those are left out of this merge: - src/agent/inspect-loop.ts hooks guardFlexCropToolLoop into tools.ts, the central dispatcher, where it can short-circuit ANY tool call. It caps frame inspection at 6 looks for every agent run — its own comment notes caption/MG verification needs more — and injects "stop", "do not recheck frames", "do not call run_code" into the result stream. - src/agent/sandbox-unavailable.ts turns run_code/probe_media into {ok: true, skipped: true} when E2B is unconfigured. Reporting an unavailable capability as success is the shape of open issue #114, which is fixed on main. - frames-tool.ts raises the frame-sampling cap from 8 back to 16, undoing the hardening in aafac5dc. tools.ts, systemPrompt.ts, probe-tools.ts, run-code-tools.ts, known-errors/SKILL.md and frames-tool.ts are therefore taken from main, and the two new modules plus their verifies are dropped along with their entries in the verify:agent-tools script. tools.ts contained nothing else, so FlexCrop loses nothing by this. FlexCrop itself is sound: storage stays a 0-1 canvas fraction so no migration is needed, pixel conversion is isolated in src/editor/flexCrop.ts with its own verify, edit_item previously rejected transform.crop as an unknown field so no existing agent call changes meaning, and every new verify was registered in test:serial by the author. CHANGELOG keeps the released 0.2.12 section and files FlexCrop under [Unreleased]; the tool catalog was regenerated rather than hand-merged. Local: tsc -b, lint (0 warnings), npm test (162 segments) all pass. | 1 个月前 | |
fix(render): decode GL transition inputs with the export's video decoder The macOS frame-sync job failed intermittently in its Windows-decoder step (3 of 9 recent runs): a "Rendering <Html5Video /> ..." delayRender on a transition frame never cleared, and the render failed after 598 s. GlTransition fed its two inputs from <Video> from 'remotion', which is <Html5Video>, whatever decoder the server picked. So every GLSL transition in a Windows server export, cross-dissolve included, still depended on Chrome's HTML5 seek next to the <OffthreadVideo> layers. #162 moved every other layer off that path. A seek that hangs there holds the export on that frame until the ten-minute budget runs out, the symptom #162 reported. When those inputs did not hang, they showed the wrong frames, on every platform. The GL pass draws in a layout effect. <Html5Video> seeks in a passive effect, which runs after it. So each render tab drew whatever its <video> showed before seeking, and only the first window frame a tab mounted was current. A split-screen transition rendered with 8 tabs got all 20 window frames wrong, with both the webcodecs and the offthread decoder. Frames 43-54 showed content from about 8 frames earlier. The first 8 showed the outgoing clip one source frame later than the Player. In a server render GlTransition now decodes both inputs with the export's decoder, as the clip layers under the window do. That is <OffthreadVideo> under 'offthread', with the trim that matches the Player and WebM alpha, and @remotion/media otherwise. A stable onVideoFrame (src/gl/capturedFrame.ts) copies each decoded frame and tags it with the frame it belongs to. The GL pass draws only once both inputs hold the current frame. The Player keeps its live <video> elements. Tests: - remotion/video-decoder-render.verify.mjs: a split-screen GLSL transition must show the Player's frame on both halves of every window frame, for each server decoder. With the old inputs it fails (frame 28 showed source frames [24, 0], not [28, 4]); it passes now. It runs in the macOS frame-sync job. - clipFxExport.offthread.verify.mjs passed 15 consecutive local runs; clipFxExport.verify.mjs, the preview, transition and decoder verifies, tsc -b and lint pass. - A transition whose outgoing handle runs past the source's last frame still renders with both decoders, frozen on that last frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 24 天前 | |
fix: make local VAD silence removal reachable and warm installed local models Three capabilities existed in the tree but could never run. The VAD-backed silence removal was gated only by the build-time VITE_ENABLE_VAD_SILENCE_REMOVAL flag, so released builds carried the tracked Silero model (public/models/silero-vad, ~13MB) as unreachable bytes and remove_silence always refused to cut. The three desktop native warm-up entry points and ensureSileroVad had zero call sites, so those workers always cold-started on first use. runAgent had no production and no test caller. - Add src/audio/vadPreference.ts: a device-local tri-state preference (cc.vadSilenceRemoval). An unchosen preference still defers to the build flag, so builds that shipped the flag keep their behaviour and every other build stays disabled until the user opts in. - Move the single gate vadSilenceRemovalEnabled(storage?, buildFlag?) out of vad.ts so both inputs are injectable and truthiness is normalized in exactly one place; vad.ts keeps runner registration and evidence logic only. - Expose the toggle in Settings > Local models > Local transcription with zh/en/it/ru copy, and point the disabled remove_silence note at that location so the agent can guide the user. - Warm only model packs already reported installed. Pack status is checked first because a load request for a missing pack fails pack verification, and the rhythm and CLAP adapters treat a failed load as "native unavailable for this session", which would disable the native path until reload. Preloading never downloads a model. - Warm the bundled Silero model on idle only when the preference is on. - Remove runAgent together with the helpers it exclusively owned (runPreparedAgent, runCodexBackend, createContextRepreparer, contextRecord, toCodexToolSpec) and the orphaned imports. The comment claiming three verifies keep it alive was wrong: those verifies exercise runCodexAgent and runApiAgent directly. runtime.ts drops from 427 to 179 lines and the runtime chunk from 231.63 kB to 194.60 kB (gzip 71.01 -> 59.56). Shared paths touched, and the evidence they stay intact: - Silence gate (src/audio/vad.ts, src/audio/silence.ts): with no stored preference the gate is false and analyzeClipSilence short-circuits before fetching the source; a real browser session issues zero silero/ort requests when the editor opens. - src/agent/runtime.ts, which hosts the live executeCodexTool used by every server-run tool call: a real DeepSeek turn executed read_project in the browser and answered "Canvas width x height: 1080 x 1920. No modifications made (read-only)." - src/hooks/useInferenceWarmup.ts: the existing ASR warm-up path is unchanged; native warm-up runs only for installed packs and the VAD warm-up only for opted-in users. - src/components/settings/LocalAsrPane.tsx: the toggle renders, reflects the stored value, persists '0'/'1', and keeps its state across a panel reopen. Enabled-path proof: on a 5.18s Chinese speech sample Silero returned confidence 0.942 with speech spans 160-480 ms and 576-5152 ms in 773 ms, and the conservative intersection correctly removed nothing because the clip is speech throughout. Verification: tsc -b clean, oxlint clean, npm run build clean, npm test 178/179 segments pass. The single failure is pre-existing on main and untouched here: verify-gate-coverage flags server/keystore.ts at 502 lines. The new verify src/audio/vadPreference.verify.ts is registered in verify:captions. | 1 个月前 | |
chore(build): upgrade TypeScript to 7 TS 7's root package no longer exposes the compiler API, so the i18n AST scans move to @babel/parser. Remotion 4.0.537 is required for its TS 7-aware bundler; the WebCodecs pre-flight follows Mediabunny 1.61.6 rate control. | 1 天前 | |
fix(media): recount media that lands after a frame-rate change Pool durations are frame counts at the project rate, but an import counts them at the rate it started with. Switching to 24 fps while a 6 s upload was still transcoding recounted the placeholder to 144 frames, then the finished import wrote back 180, so the card read 0:08. Relinked files, phone and watch-folder imports, and agent media landing on a project whose rate changed during the run did the same; template media kept the template's rate. addAsset and pool.relinkAsset now carry the rate their duration was counted at (durationFps), and the reducer recounts it into the project rate as it writes the pool; source identity stays the probed file's. Imports pass the rate they probed at and the commands default to the doc's own rate, so an agent draft's media is recounted when it lands on the live project. The pool import run moves to poolImportRun.ts to keep useEditorMediaIngest.ts under the size cap; the asset it returns to callers that place it right away is recounted too. Fixes #184 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 24 天前 | |
feat(agent): browse and import local media from a browser-hosted editor The built-in Agent's browse_local_media and import_* tools only had an Electron bridge, so a browser-hosted editor answered "desktop app only" even though the server already owns the probe/hash/reference/dedupe chain that offline MCP and occ use. Fall back to same-origin /api/local-media routes that run that same core and prefer the Electron bridge whenever it exists, so desktop behavior is unchanged. The routes share the editor's existing local-device write gate and deliberately do not inherit the desktop "empty AGENT_IMPORT_ROOTS allows everything" default: a page load carries no OS folder grant, so an empty allowlist refuses instead of exposing the machine. Out-of-root paths and symlink escapes are rejected by the existing core. Validated with lint, typecheck, the production build, the new route verify and the tool verify; the local test failures are pre-existing Windows-only issues that reproduce on a clean checkout. | 14 天前 | |
chore(release): prepare v0.2.0 Harden project storage, upload finalization, export recovery, watched-folder ownership, and native inference lifecycle boundaries. Add cross-platform desktop update packaging and checksum-gated GitHub Release publication while preserving the public v3 project schema, existing media URL semantics, and opt-in defaults. Verified with TypeScript project builds, zero-warning lint, the full test suite, production build, and a browser create/import/edit/reload/close-reopen smoke. | 2 个月前 | |
fix(persist): retain media references from unreadable snapshots | 22 天前 | |
feat(agent): read installed plugin packs into the headless template catalog Headless sessions now see the same template catalog the renderer does, pack templates included: - server/plugins/extension-store.ts exports readInstalledPacks(), the on-disk reader behind the renderer's hydration. - offline-catalogs.ts merges those packs through pluginTemplates() — the very mapping the UI uses — after validating the envelope at the boundary: a pack whose mg-template items lack id/name/code is dropped rather than half-mapped into a template, and an unreadable pack store degrades to the bundled set. - offline-runtime.ts loads the catalog once per session (create() is async) and hands it to the AgentContext, so list_templates / search_templates / add_motion_graphic answer the same thing with or without a renderer. This closes the capability gap the previous commit documented. Supporting split: the pure pack → Tpl/zoom mapping moved out of src/library/pluginResources.ts (which imports ResourceBrowser.tsx) into src/library/pluginTemplateCatalog.ts, because the node-side build has no --jsx and pulled the component in. pluginResources.ts keeps the React hook and the resource-card mapping; the four import sites were updated. offline-runtime.ts also moved its context/status/failure projections into offline-session-view.ts — it had crossed the 500-line gate. Shared paths touched: the extension store gains one exported reader; the offline runtime splits two modules; the library split keeps one mapping implementation. Renderer behavior is unchanged (same function, same inputs). Verification: cli/cli.verify.ts installs a fixture pack into a throwaway HOME and asserts search_templates returns its template — the merge path, not just the bundled list; resourcePreview, offline-runtime, offline-mcp and verify:mcp pass; npm run build and npm run desktop:build:main pass; tsc -b clean; lint 0 warnings; registration and gate coverage pass; npm test 181/181 green. | 1 个月前 | |
fix(quality): revive watchdogs, fix orphan checks, and unify skill count Resurrect two silent quality gateways and wire them into the test suite, catch up CHANGELOG and skill-count docs, and convert every orphaned verify/check file into a tracked, npm-wired regression. Quality watchdogs (now in pretest): - verify:shortcuts: catalog count 54->56, keymap scope, native-copy - verify:i18n: check-i18n.mjs now exempts test files; 4 real UI files wrapped in t(); 62 missing en keys added across 9 dict slices - Fixed stableOverrideKeys merging distinct legacy caption overrides when wordRef is empty (3 overrides collapsed to one key) - Fixed buildFollowupWidget silently dropping option-less choice fields (now degrades to a prompt line) - Fixed apply_script repack being silently rejected by the same-track overlap guard: reorderTrackItems now accepts explicit starts and apply_script rebuys atomically per track Docs: - CHANGELOG [Unreleased]: SQLite migration, session-recovery, chat-load-perf, Geist fonts, platform inference routing; fixed link refs - Skill count unified to 26 (README/README_ZH/AGENTS.md/tools.ts) Verify/check cleanup: - Promoted 81 .check.ts to tracked .verify.ts and deleted the originals - Fixed 20+ stale assertions (PROJECT_VERSION 3->7, sourceRevision, caption-track structure, legacy index selectors, shader hash re-pins, abort wiring refactor, stock orientation enum) - 8 new verify groups (editor/captions/agent-tools/components/ media-persist/export-gl/server-extra/sqlite-migration) wired into pretest - Orphan verify count: 158 -> 0 Full npm test, tsc -b --force, and npm run lint all pass. | 2 个月前 | |
feat: land professional timeline, durable jobs, and safe media flows Add slip/rate-stretch, nested sequences, multicam sync, durable generation/export recovery, media intelligence, and hardened MCP/media boundaries while keeping the implementation local-first and cross-platform. | 2 个月前 | |
feat(ui): self-hosted Geist + Geist Mono as the UI typeface Ships Geist (400/500/600/700) and Geist Mono (400/500/600/700) woff2 from the OFL-1.1 geist package under public/fonts and swaps every UI font-family literal from the system stack to 'Geist, system-ui, ...' / 'Geist Mono, ui-monospace, ...'. Chinese glyphs are not covered by Geist and fall back to system UI fonts via the trailing stack entries. Caption/export fonts (Inter, Noto Sans SC, ...) are untouched — they render into exported video, not the editor UI. | 2 个月前 | |
fix(quality): revive watchdogs, fix orphan checks, and unify skill count Resurrect two silent quality gateways and wire them into the test suite, catch up CHANGELOG and skill-count docs, and convert every orphaned verify/check file into a tracked, npm-wired regression. Quality watchdogs (now in pretest): - verify:shortcuts: catalog count 54->56, keymap scope, native-copy - verify:i18n: check-i18n.mjs now exempts test files; 4 real UI files wrapped in t(); 62 missing en keys added across 9 dict slices - Fixed stableOverrideKeys merging distinct legacy caption overrides when wordRef is empty (3 overrides collapsed to one key) - Fixed buildFollowupWidget silently dropping option-less choice fields (now degrades to a prompt line) - Fixed apply_script repack being silently rejected by the same-track overlap guard: reorderTrackItems now accepts explicit starts and apply_script rebuys atomically per track Docs: - CHANGELOG [Unreleased]: SQLite migration, session-recovery, chat-load-perf, Geist fonts, platform inference routing; fixed link refs - Skill count unified to 26 (README/README_ZH/AGENTS.md/tools.ts) Verify/check cleanup: - Promoted 81 .check.ts to tracked .verify.ts and deleted the originals - Fixed 20+ stale assertions (PROJECT_VERSION 3->7, sourceRevision, caption-track structure, legacy index selectors, shader hash re-pins, abort wiring refactor, stock orientation enum) - 8 new verify groups (editor/captions/agent-tools/components/ media-persist/export-gl/server-extra/sqlite-migration) wired into pretest - Orphan verify count: 158 -> 0 Full npm test, tsc -b --force, and npm run lint all pass. | 2 个月前 | |
fix(shortcuts): match an explicit Ctrl chord on Windows and Linux The catalog's Ctrl + E / Ctrl + R rows never matched off Mac: the wanted modifier was read as chord.mod only, so the explicit-Ctrl chord disagreed with hasMod (ctrlKey) and was dropped before the chord.ctrl branch. Treat Ctrl as Mod on non-Mac, where there is no separate Control modifier, and assert in catalog.verify that every row dispatches its own advertised chord on both platforms. | 13 天前 | |
feat(ui): self-hosted Geist + Geist Mono as the UI typeface Ships Geist (400/500/600/700) and Geist Mono (400/500/600/700) woff2 from the OFL-1.1 geist package under public/fonts and swaps every UI font-family literal from the system stack to 'Geist, system-ui, ...' / 'Geist Mono, ui-monospace, ...'. Chinese glyphs are not covered by Geist and fall back to system UI fonts via the trailing stack entries. Caption/export fonts (Inter, Noto Sans SC, ...) are untouched — they render into exported video, not the editor UI. | 2 个月前 | |
fix(transcript): a zero-length word blacked out the whole preview ASR sometimes emits a word whose start and end round to the same frame ("Music" 24420->24440ms is f733 at both ends, on a junk auto-transcript attached to an SFX clip). keptSegments floored durFrames at 1 but left srcEndFrame unclamped, so the segment rendered <Audio trimBefore={733} trimAfter={733}> and Remotion threw "trimAfter prop must be greater than trimBefore prop." That throw unmounts the entire preview composition: the Player swaps in its bare warning fallback, so playback goes black and silent while the transport still reports "playing", and no restart clears it. Premount (fps * 1) detonates the bad segment a second before its clip, so the stall lands ~30 frames earlier than the offending item. Clamp srcEndFrame to srcStart + 1, matching what durFrames already did; timeline timing is unchanged because those segments were already one frame long. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 11 天前 | |
perf(ui): load the ten dialogs on demand instead of at startup Both shells imported every dialog statically even though each one renders only while its own flag is set — five overlays in the editor (export, settings, design style, version history, shortcuts) and five on the project list (settings, shortcuts, MCP guide, media cleanup, storage migration). Their dependency closures are not small: the export pipeline, the provider catalogs and their vendor icons, the design-style transfer code. All of it had to arrive before a project list could be drawn. They are lazy() now, behind a Suspense boundary with a null fallback — an overlay that has not loaded shows nothing, which is what it showed before it was opened. Code-splitting a dialog trades bytes for a stall on first open, so src/ui/idlePrefetch.ts buys the stall back: both shells warm their dialog chunks on requestIdleCallback after first paint, using the same import thunks the lazy components use, so the click resolves from the module cache. Prefetch failures are swallowed on purpose — the real import on open retries and reports the problem where the user can act on it. First load, cumulative with the previous commit: 3062 KB raw / ~900 KB gzip -> 689 KB raw / 198 KB gzip The editor route drops 148 KB raw / 47 KB gzip on top of that. Validation: tsc --noEmit, oxlint, npm test (161 segments). In the browser, all ten dialogs open with content (settings renders its provider panes) and the console stays clean; the editor still loads a real project. | 1 个月前 | |
fix(editor): explain the HTTPS requirement instead of a blank editor Over plain HTTP from another machine (a LAN IP or reverse proxy) the page is not a secure context, so browsers withhold crypto.randomUUID, crypto.subtle, WebCodecs and the async clipboard. The lazy editor threw on import and, with no error boundary, blanked the whole app; a UUID fallback would only move the crash. EditorRoute now checks window.isSecureContext before the editor chunk is requested and shows a localized localhost-or-HTTPS requirement with the current origin, keeping the project list usable. An error boundary around the lazy editor turns any other load or render failure into an error with a reload action. The desktop app loads a loopback origin and is unaffected. Fixes #183 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 24 天前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix(desktop): transcript window pulls its payload; smoke exits cannot wedge The re-run v0.2.12 Windows smoke — now with captured output — failed in minutes instead of hanging, and the log named both defects: - "transcript payload timed out": the floating transcript window's payload was push-only, sent once at did-finish-load. The page registers its IPC listener in a React effect, which on a slow machine runs after that push (the renderer cold-boots locale dicts and lazy chunks first), so the payload was lost and the window stayed permanently blank — for real users too, not just CI. The window now pulls the current payload once its subscription is in place; a push that lands first is fresher and wins. - The process then printed "boot failed", called app.exit(1) — and lived until the CI step killed it at 420s. app.exit() wedges on Windows while a crashed renderer is mid-reload, which is also why the previous run's 240s watchdog changed nothing. Smoke exit paths (success, watchdog, boot failure) now follow app.exit with process.exit; a smoke process has nothing to clean up. The smoke's transcript wait gets 30s instead of 10s: a fresh BrowserWindow cold-boots an entire renderer before the transcript view mounts, and 10s is too tight on a throttled CI machine even with the pull path. | 1 个月前 | |
feat(agent): run edit_item and manage_effects without the browser The offline MCP executor — and therefore the occ CLI — can now run the two tools whose validators consult the GL catalogs. Shader sources: GL catalogs no longer import ./x.frag?raw. That suffix only resolves inside Vite's own client build graph; Node, the desktop esbuild bundle and the rolldown step that bundles config/vite.config.ts all fail on it, which is how reaching these modules broke npm run build. Every .frag keeps a generated .frag.ts twin next to it (scripts/sync-shader-sources.mjs), enforced by scripts/shader-sources.verify.mjs in npm test and prebuild, so the shader text is still authored once and every host resolves it identically. Whitelist: edit_item and manage_effects join the server-direct set after review — both only touch the draft's EditorCore commands plus state/doc. edit_item's template-add path degrades with an explicit error because the offline context carries no template catalog; that is a capability gap, not a silent no-op. Executor: both schemas are exposed offline and dispatched through a lazy import, so a bare tsx host that never calls them never loads the GL modules. Shared paths touched: src/gl (import form only — shader text unchanged and the twins are verified byte-for-byte equal), the external-tool-policy whitelist, the offline tool catalog and executor, package.json (two scripts, one command in test:serial, one prebuild check). Preview, export and the Remotion render path are untouched. Verification: npm test 181/181 green (including the two new verifies); npm run build; npm run desktop:build:main (51 shaders inlined into app-main.mjs); npm run verify:mcp; cli/cli.verify.ts drives edit_item through an offline session and reads the written opacity back; offline-runtime, offline-mcp and offline-mcp-process-recovery verifies; chroma-key, clipFxPreview and clipFxExport GL verifies; tsc -b; lint 0 warnings; registration and gate coverage. | 1 个月前 | |
feat(editor): choose the project frame rate from the timeline toolbar Every GUI path created 30 fps timelines. "New project" hardcodes 30, and "+ Sequence" and duplicate copy the active rate. Only MCP create_project could make a 60 fps timeline. A 60 fps export of a 30 fps timeline cannot use the browser path ("cannot retime the timeline yet") and is retimed by the local renderer. The timeline toolbar now shows the project frame rate next to the aspect-ratio picker, which is where the other canvas setting already lives, and lets you change it until anything is placed. It offers 24/25/30/50/60, the rates every export route renders without retiming. The browser path needs export fps == timeline fps, and the local renderer only accepts these as retime targets. A rate set elsewhere, such as 59.94 through MCP, is shown as the current value but cannot be picked again once changed. The rate is project-wide and locks once any timeline has clips, transitions, markers, link or multicam groups, or captions. All of those are frame counts at the current rate, and converting them all would be a much larger change than this issue needs. It is project-wide because nested sequences must share a rate and pool durations are counted in it. When the rate changes, time-based pool assets (video, audio, image, gif, svg) are recounted so they keep their seconds. Motion graphics keep their authored frame length, as they do when added from the library. The change is a reducer action (tl.setFps), so it is undoable, and agent drafts record it like any other edit. New timelines do not adopt the first clip's frame rate. Source fps is only known after server normalization and is not stored on the asset. Desktop imports skip that probe, and clips are placed before durations settle. Adopting on drop would mean re-probing and retiming placed clips inside the import pipeline. The export dialog now starts at the export rate nearest the timeline's own. It used to fall back to 30 for any rate outside the list, so a 59.94 timeline exported at 30 by default. Fixes #175. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 25 天前 | |
perf(bundle): cut the first-load payload from ~900 KB to 247 KB gzip Two independent problems put ~650 KB gzip of JavaScript in front of the first frame that no first screen needs. 1. React shipped inside the Remotion chunk. codeSplitting.groups leaves includeDependenciesRecursively at its default of TRUE, which drags a group's whole dependency closure into it, and the highest-priority group wins. So remotion (priority 20) claimed react and react-dom before the react group (10) could — the react chunk came out empty and the entry chunk imported 2 MB of Remotion just to get React. The project list route has no player on it. Every group here matches the package it is named after and wants only its own modules, so they all opt out of recursive dependency inclusion, the way templates already did. 2. All four locale dictionaries were statically imported. ~560 kB of source across zh/en/it/ru, so each user downloaded and parsed three languages they cannot read. src/i18n/dictRegistry.ts fetches one locale on demand; t()/tData() stay synchronous, reading a snapshot that is replaced rather than mutated, and fall back to the Chinese original — which is also the dictionary key — so the "never go blank" contract holds while a fetch is in flight. main.tsx starts that fetch before the rest of boot so it overlaps, and gates the first render on it, so no frame renders untranslated copy. The remaining languages warm on idle after first paint, keeping the switcher instant. Eager entry payload: 3062 KB raw / ~900 KB gzip -> 847 KB / 247 KB. Behaviour is unchanged. src/i18n/dictRegistry.verify.ts pins the per-locale lookup rules that used to be inlined in locale.ts, including the two that are easy to lose: Italian falls back to English while Russian does NOT (untranslated Russian keys stay Chinese), and the in-flight fallback never yields an empty string. Validation: tsc --noEmit, oxlint, web build, the new verify, locale.verify and template-reference-localization.verify. Browser: cold boot with a Russian dictionary renders Russian at FCP (218 ms) with no Chinese flash, switching EN->IT->RU->ZH applies within one frame, zero console errors. npm test is 103/104; the failure is timeline-target-tools.verify, which fails identically on HEAD with these changes stashed. | 1 个月前 | |
docs: translate code comments to English | 2 个月前 | |
docs: translate code comments to English | 2 个月前 | |
chore(deps): upgrade AI SDK stack and tooling Move to ai@7.0.148 with current provider packages (xAI 5.x Responses-only), React 19.3, Vite 8.3, AWS SDK, MCP SDK, E2B and same-major tooling. Adapt oxlint 1.89 ignore patterns and the Babel 8 nullable transform. Keep @github/copilot-sdk pinned to 1.0.11 because 1.0.24 changed its platform runtime packaging. | 1 天前 | |
feat(ui): adapt editor layout to viewport Preserve splitter choices as ratios and compact dense editor controls and track labels across viewport sizes. | 2 个月前 | |
docs: translate code comments to English | 2 个月前 | |
Initial commit | 3 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 天前 | ||
| 24 天前 | ||
| 1 个月前 | ||
| 17 天前 | ||
| 2 个月前 | ||
| 1 天前 | ||
| 5 天前 | ||
| 1 天前 | ||
| 17 天前 | ||
| 1 天前 | ||
| 1 个月前 | ||
| 24 天前 | ||
| 1 个月前 | ||
| 1 天前 | ||
| 24 天前 | ||
| 14 天前 | ||
| 2 个月前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 13 天前 | ||
| 2 个月前 | ||
| 11 天前 | ||
| 1 个月前 | ||
| 24 天前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 25 天前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 3 个月前 |