Repository navigation
Conversation
Add the same _BACKEND_ROOT/sys.path bootstrap used by test_paths.py, test_asr_adapter.py and test_rpc_bridge.py to: - test_video_call_state.py - test_memory_dreamer.py - test_storage_migration.py Refs: #1
Widen the here-local:// extension allow-list to include bmp/mov/avi/mkv so character_assets, character_image, and character_animation pickers no longer offer formats the serving layer rejects. Extract the allow-list into a shared module and derive the character picker filters from it, with a regression test asserting every picker extension is accepted.
Skip non-dict character entries and non-dict sprite entries, and treat a None/non-list sprites field as empty instead of crashing with AttributeError/TypeError. Legal here configurations keep the same migration behavior and idempotency.
Bring persona video call, sys.path test bootstrap, and malformed characters/sprites migration defense onto main. Resolve the only content conflict in src/main/main.ts by keeping PR #2 isLocalAssetExtension whitelist together with the token LRU.
Honor the public timezone parameter (default Asia/Shanghai) for both the next-midnight wake and MemoryDreamer .dream-date markers, reusing core.timezone ZoneInfo resolution with tzdata fallbacks.
Same ZoneInfo datetime subtraction ignores offset changes, so the scheduler now uses timestamps and regression-tests New York spring and fall transitions.
…/types.ts The Electron-native chat stack never ran: runtime chat and legacy import already go through the Python sidecar (`chat` / `import_legacy` RPC). The four modules only referenced each other and were built by tsconfig alone. - Delete src/main/chat-service.ts, src/main/legacy-importer.ts, src/main/config-store.ts and src/shared/defaults.ts. - Drop the now-orphaned legacy models from src/shared/types.ts (AppConfig, ApiSettings, SystemSettings, ProactiveSettings, Character, SpriteSource, Emotion, ChatMessage, ChatRequest, ChatEvent, AppState); keep Attachment, LegacyImportReport and HereDesktopApi untouched. - Drop the `yaml` dependency, used only by the removed legacy importer. - Prune dist-electron before build so electron-builder cannot package JS left behind for removed sources. Refs #6
…rs from main.ts Issue #7 phase 1 (staged, renderer-first). Pure mechanical extraction, no behavior change: moved code is copied verbatim, only signature params/imports added. - src/renderer/dom.ts (new): $, $$, esc, clone, call-pixel icons, refreshIcons, updateCallControl, switchRow, field, pathField, selectField, editableChoiceField, pageHeader. - src/renderer/settings-html.ts (new): adapter label maps, schemaFields, delivery/capability helpers, profile helpers, renderPlatformSettings, renderCharacterSettings, renderSpriteSettings (+ editor/slot helpers), renderMemorySettings, renderStorageSettings. DesktopState is now an explicit parameter instead of a module-level closure. - src/renderer/main.ts: 3016 -> 2503 lines; keeps startup/assembly, DOM writes, event binding and chat/audio/ASR/sprite runtime (stateful orchestration stays centralized; deferred to a later phase).
Keep protocol I/O, startup order, dispatch, and patchable names in rpc_bridge.py. Move method bodies into bridge/ helpers that resolve event/ASR/migration symbols through late-bound hooks so existing patch.object(rpc_bridge, ...) tests stay valid.
python rpc_bridge.py registers the sidecar as __main__, so hooks that only looked up sys.modules['rpc_bridge'] crashed on BACKEND_ROOT before ready. Alias the running module before importing bridge, accept either name at lookup time, and cover the real script entry with a subprocess ready/ping JSON regression.
sprite_prefix is user-editable and was joined into shutil.rmtree without checking ownership. Require a single safe path segment, refuse absolute paths, traversal, the storage root, outbound symlinks, and shared prefixes, and skip file deletion when the prefix is unsafe so unrelated files stay.
Ensures consistent UTF-8 encoding for Python subprocess I/O on all platforms. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves GHSA-55q2-fjhq-7xh7 (moderate severity XSS in DOMPurify <=3.4.12) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Update vitest from 4.0.0 to 4.1.11 to get latest fixes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
修复 Issue #9,防止角色删除时误删资产根以外目录。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… paths After storage migration, reload_runtime() was reloading config but keeping the old MemoryStore instance with the stale root path. This caused new memories to be written to the old directory even after migration succeeded. Fixed by recreating self.memory = AgentMemoryStore() after config.reload() so it picks up the updated paths.memory_dir from the freshly reloaded config. Fixes #10 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Previously, _save_single_config used open(file,'w') which truncates the file immediately, then yaml.dump. If dump failed (disk full, serialization error), the original config was already lost and the error was only printed, not raised. Now using atomic write-and-replace pattern: 1. Serialize to temp file in same directory (ensures same filesystem) 2. If successful, atomically replace original with os.replace() 3. If any stage fails, clean up temp file and raise RuntimeError 4. Original file is never touched until write succeeds Added comprehensive tests covering: - yaml.dump failure preserves original - write I/O error preserves original - successful save works correctly - no temp file leaks on any failure path All 55 backend tests pass (51 existing + 4 new). Fixes #11 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rename_character compared Path strings, so on case-insensitive filesystems (macOS) 'here' vs 'HERE' looked like different folders. The merge copied the home into itself and then shutil.rmtree removed it, destroying MEMORY.md/USER.md/SOUL.md and all other data. Detect the same directory via os.path.samefile (inode) and treat same-path renames as no-ops. Genuine renames and merges are unchanged. Tests: backend.tests.test_memory_rename + RPC save_config regression.
import_legacy copied the legacy config verbatim, including storage_paths.yaml. When the old install used custom absolute or relative memory/asset folders, Electron kept writing back into them while only the fixed memory/characters subdirectories were copied. Read the legacy storage layout, copy the real memory/asset folders (and the other data dirs) into the Electron app home, copy config without the legacy storage_paths.yaml, then rewrite absolute character asset paths onto the Electron folders. Failures never adopt the legacy layout. Also resolve paths through symlinked roots when rewriting migrated paths (macOS /var vs /private/var). Tests: subprocess legacy import probe (relative + absolute custom storage) plus symlinked-root migration regression.
import_character_state_assets deleted the existing state folder before decoding the new GIF/WebP, importing OpenCV, extracting video frames or copying files. Any later failure left the previous sprite destroyed while the config still referenced it. Generate all frames in a sibling staging folder, then swap it in while keeping the old folder as a backup. Restore the backup when the config save or sprite update fails, and clean up staging on any error, so a failed replacement never removes working assets. Tests: corrupt GIF, undecodable video, copy failure, config-save failure, and source-file-inside-target replacement.
OpenCV reports frame write failures (for example a full disk) by returning False instead of raising. The staging code skipped the frame and still committed the incomplete folder, deleting the previous assets. Treat any False return as an error so the rollback keeps the old sprites and config. Test injects a two-frame video where the first frame writes and the second returns False, and asserts the previous bytes, in-memory config and on-disk config are unchanged with no staging leftovers.
import_legacy copied legacy assets into the Electron asset folder but only rewrote absolute paths under the old asset root. Characters that referenced assets with the supported relative forms (characters/... or defaults/characters/...) kept those strings, so with a custom Electron asset folder they resolved against the Electron root and pointed at missing files. Resolve each character asset field with the legacy AppPaths layout (instead of the process working directory) and map it onto the Electron asset root. Covers sprite path, frames, spritesheet_path and visual_reference_image. Tests: unit coverage for relative references and untouched external paths, plus an end-to-end import with a custom Electron asset folder and relative legacy references.
The sprite_prefix guard proved a folder belongs to the character but not that a file is unused. Deleting one sprite reference could therefore remove a file another character or another sprite still pointed at, and replacing a state folder could clobber shared frames. Add reference tracking on top of the ownership guard: collect every resolved asset path (path, frames, spritesheet_path, voice_path) held by surviving sprites, then skip physical deletion of any file that is still referenced, any directory that still contains a referenced file, and refuse a state-folder replacement that would destroy one. Wired into the RPC delete_character_sprite / import_character_state_assets and the CharacterManager delete_character / delete_all_sprites / delete_single_sprite entry points.
…rences Two review findings on the shared-reference guard: - CharacterManager collected references with the raw path string, so supported characters/... references were resolved against the process working directory instead of the app layout. Whole-character deletion through HereBackend.delete_character could therefore miss a surviving reference and remove the file. Use resolve_character_asset_path with the configured AppPaths, matching the RPC/runtime behaviour. - Reference collection only scanned sprites and ignored the character-level visual_reference_image, which is a persisted and consumed asset. Include it for every surviving character, keep it when only a character's sprites are cleared, and retarget it in the same commit when a replaced state folder held it (restoring it on rollback).
install_dependencies announced busy=true before running pip, but only the success path published busy=false. A non-zero exit, a 30 minute timeout, or a subprocess start failure left the renderer's global busy bar on until the backend restarted. Wrap the install in try/except/finally so every path publishes exactly one matching busy=false, with the completion text on success and a readable error message (failure tail, timeout detail, or OSError text) otherwise. Non-zero exits keep the last 12 stdout lines as before.
The README only covered backend:setup/backend:setup:full and described backend:runtime as always installing Vosk/PyAudio, which is wrong on Linux because requirements-runtime.txt gates pyaudio/vosk on macOS/Windows. - Distinguish development installs, the settings-page on-demand install (RPC install_dependencies) and the release runtime build. - Describe backend:runtime accurately (uv, standalone CPython, macOS Homebrew PortAudio bundling/re-signing, prune and RPC smoke test). - Add a platform table for pyaudio/vosk in the release runtime. - Document the network, writable data dir and post-install re-check or restart requirements, plus troubleshooting for failed installs, missing system audio libraries and still-missing dependencies.
setup-full only installs requirements-asr.txt and requirements-hermes.txt; neither contains opencv-python, so importing video sprites after setup:full can still fail on a missing cv2. State that video is on-demand only: it is absent from setup:full and from the release runtime requirements, and is installed from the settings page or manually into backend/.venv.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
同步本地 main 分支的 43 个提交到远端 main。已通过前端测试、后端测试、TypeScript 类型检查和生产构建。