emrg: evolution workspace self-heal — clone on demand + projects/tasks bootstrap (rant 20:42) - #489
Conversation
…s bootstrap (rant 20:42)
Packaged installs run the daemon from a .git-less source snapshot, so
evolution cannot commit/push/PR. Per 方案 C:
- EvolutionHandler._ensure_evolution_workspace() at each cycle start:
- dev machine (source_dir is a real git repo) → untouched
- otherwise clone EMRG into ~/.emrg/evolution/emrg/ (repo URL from
install-info.json 'repo' field, fallback built-in default), align to
the installed release tag (v<version.txt>, fallback master), set git
identity if missing (GIT_AUTHOR_NAME/EMAIL, defaults EMRG Evolution)
- clone failure (no network) → log + skip cycle (GUI unaffected)
- projects.yml self-heal: add/update emrg entry → evolution workspace
- TaskScheduler._ensure_self_evolution_task() at load_and_start():
- tasks.yml missing emrg evolution task → append emrg-task
(type=evolution, config.project=emrg, interval=60, enabled)
- idempotent; runs at scheduler level because a missing task means no
handler is ever started
Tests: 5 new (task bootstrap, idempotency, dev-repo untouched, clone+align
+projects self-heal, clone-failure skip) + 5 updated for new behavior.
Full suite: 478 passed.
…mrg/install) test_ensure_evolution_workspace_clones_and_aligns read the REAL ~/.emrg/install/version.txt via Path.home() — passed on dev hosts but failed in CI (no ~/.emrg/install → no tag → no checkout). Patch pathlib.Path.home to tmp_path so the test is self-contained.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-204218. Verified: (1) workspace self-heal gated to the emrg self-task (config.project==emrg, repo==emrg); dev machine with a real git repo is untouched (tested with an actual git repo); (2) clone → tag alignment (v<version.txt> via git checkout -B master, keeps branch flow) → git identity fallback (GIT_AUTHOR_NAME/EMAIL → EMRG Evolution) → projects.yml self-heal, all idempotent; (3) clone failure returns False and skips the cycle without affecting GUI; (4) tasks.yml bootstrap lives in TaskScheduler.load_and_start() — correct, because a missing emrg-task means no handler would ever start; (5) first CI run caught a non-hermetic test (Path.home version.txt) — fixed by patching home, CI green 478 passed. Rant 20:42 acceptance items map 1:1.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-205521. Second vote. Re-checked against master 91b03c9 (#487 merged GUI P2 — no overlap with scheduler.py; merge-base clean). CI green (run 31103284600). Self-heal wiring verified: _ensure_evolution_workspace() gated to emrg task, clone-failure skip, _ensure_self_evolution_task() idempotent. Ready to merge after one more LGTM.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-2056. Independently re-verified: (1) _ensure_evolution_workspace gating is correct (only emrg self-task, paper/open-source/promote pass through), dev-machine path untouched when _is_usable_git_repo is true; (2) clone → _align_to_installed_version (checkout -B master keeps branch flow) → _ensure_git_identity (env fallback to EMRG Evolution) → _ensure_project_entry (idempotent, atomic_write_yaml); (3) non-git existing dir → skip + log to avoid data loss; (4) _ensure_self_evolution_task in TaskScheduler.load_and_start is the right layer — no handler exists without the task; (5) tests: 5 new unit tests incl. clone-failure and idempotency, hermetic version.txt test patches Path.home — 478 passed locally. Rant 20:42 acceptance items map 1:1.
…elf-heal (rant 20:42) (#490) _cache_tool_paths now also writes 'repo' = https://github.com/argszero/emrg.git alongside git_path/gh_path. Complements PR #489's read side: packaged installs have no git remote to detect, so the clone-on-demand self-heal needs a repo source persisted at runtime. 2 new tests (repo field written, existing fields preserved). Co-authored-by: EMRG Evolution <emrg@argszero.dev>
* emrg: persist repo URL in install-info.json for evolution workspace self-heal (rant 20:42) _cache_tool_paths now also writes 'repo' = https://github.com/argszero/emrg.git alongside git_path/gh_path. Complements PR #489's read side: packaged installs have no git remote to detect, so the clone-on-demand self-heal needs a repo source persisted at runtime. 2 new tests (repo field written, existing fields preserved). * emrg: GUI / 指令 P3 — 模型/记忆/技能类指令(/model /memory /skills,rant 19:44) Phase 3 of GUI slash-command support (rant 2026-08-06T19:44:38; P1 #486, P2 #487 merged). Opens /model /memory /skills in the GUI: - /model → triggers the existing model switcher (click .model-switcher) - /memory [session|<id>] → memory browser dialog: list_memories → click a memory → read_memory → inline detail panel - /skills → skills list dialog (main process reads ~/.emrg/skills and <projectDir>/.emrg/skills frontmatter; daemon has no skills protocol, mirrors TUI's local load_skills) main.js: new IPC emrg:listMemories / emrg:readMemory (daemon list_memories/read_memory protocol, session scope validated) / emrg:listSkills (local fs read, no daemon change). preload.js exposes them. index.html: memory-dialog + skills-dialog. components.css: .memory-detail styles. commands.js phase comments updated. Tests: app-commands +4 P3 route tests (55 total GUI, was 51); smoke element IDs updated. pytest 475 passed; import + --help OK. --------- Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Version bump 0.2.7 → 0.2.8 across all 6 version sources (pyproject.toml / emrg/__init__.py / make-installer.sh / build-runtime.sh / gui/package.json / uv.lock). Release includes #486/#487/#491 GUI slash commands P1-P3, #488/#492/#493 i18n prompts, #489/#490 evolution workspace self-heal, #484/#485 README/language policy, #483 docs cleanup. test_version_sync all green. Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Summary
Self-heal for the evolution workspace on packaged installs (rant 2026-08-06T20:42:05, 方案 C). Packaged installs run the daemon from
~/.emrg/install/source/emrg— a.git-less source snapshot — so the evolution task cannot commit/push/PR. This PR makes the evolution workspace bootstrap itself on demand.Changes
emrg/server/scheduler.pyEvolutionHandler._ensure_evolution_workspace()— called at the start of every evolution cycle:source_diris a real writable git repo) → untouched, no clone~/.emrg/evolution/emrg/:install-info.jsonrepofield, falling back to the built-inhttps://github.com/argszero/emrg.git~/.emrg/install/version.txt(e.g.0.2.7) and checks out tagv0.2.7if present (viagit checkout -B master <tag>so evolution's branch-from-master flow still works), else stays on masterGIT_AUTHOR_NAME/GIT_AUTHOR_EMAILenv, defaultsEMRG Evolution <emrg@argszero.dev>)EvolutionHandler._ensure_project_entry()— self-healsprojects.yml: adds/updates theemrgentry pointing at the evolution workspace (idempotent).TaskScheduler._ensure_self_evolution_task()— atload_and_start(): iftasks.ymlhas noevolutiontask withconfig.project == emrg, appendsemrg-task(interval 60, enabled). This runs at the scheduler level because a missing task means noEvolutionHandleris ever created — the handler-level self-heal alone could never fire.Verification
load_and_starttests updated for the new bootstrap behavioruv run python -c "from emrg.client.app import run_client"+emrg --helpOKAcceptance mapping