Fix Editor manual open behavior

Open the Editor file browser from the active project context before falling back to the configured workdir. Keep manual Editor launches on the empty start page instead of auto-creating blank Markdown files, while preserving explicit Markdown creation from the empty state. Add static regression coverage for both behaviors.

Alessandro committed Jun 4, 2026 at 15:16 UTC 16f724226a10f94e60f8446ed34b6de8598cd522
2 files changed +28 -18
plugins/_editor/webui/editor-store.js
+9 -16
@@ -225,7 +225,6 @@ const model = {
225 _previewEnhanceTimer: null,
226 _staticHighlightPromise: null,
227 _pendingPreviewFragment: "",
228 - _initialCreatePromise: null,
228
229 async init() {
230 if (this._initialized) return;
@@ -244,7 +243,6 @@ const model = {
243 this._mode = options?.mode === "canvas" ? "canvas" : "modal";
244 if (this._mode === "modal") {
245 this.setupMarkdownModal(element);
247 - await this.ensureInitialMarkdownFile();
246 }
247 this.scheduleSourceEditorInit();
248 },
@@ -261,7 +259,6 @@ const model = {
259 });
260 return;
261 }
264 - await this.ensureInitialMarkdownFile();
262 },
263
264 beforeHostHidden() {
@@ -848,24 +845,20 @@ const model = {
845 });
846 },
847
851 - async ensureInitialMarkdownFile() {
852 - if (this.session || this.visibleTabs().length > 0 || this.loading) return null;
853 - if (!this._root || this._initialCreatePromise) return this._initialCreatePromise;
854 - this._initialCreatePromise = this.create("document", "md").finally(() => {
855 - this._initialCreatePromise = null;
856 - });
857 - return await this._initialCreatePromise;
858 - },
859 -
848 async openFileBrowser() {
849 let workdirPath = "/a0/usr/workdir";
850 try {
863 - const response = await callJsonApi("settings_get", null);
864 - workdirPath = response?.settings?.workdir_path || workdirPath;
851 + const home = await callEditor("home");
852 + if (home?.path) {
853 + workdirPath = home.path;
854 + } else {
855 + const response = await callJsonApi("settings_get", null);
856 + workdirPath = response?.settings?.workdir_path || workdirPath;
857 + }
858 } catch {
859 try {
867 - const home = await callEditor("home");
868 - workdirPath = home?.path || workdirPath;
860 + const response = await callJsonApi("settings_get", null);
861 + workdirPath = response?.settings?.workdir_path || workdirPath;
862 } catch {
863 // The file browser can still open with the static fallback.
864 }
tests/test_office_canvas_setup.py
+19 -2
@@ -140,10 +140,13 @@ def test_right_canvas_uses_desktop_surface_id_and_migrates_legacy_office_state()
140 assert "editor-preview-title" in editor_web_panel
141 assert "editor-preview-page-editor" in editor_web_panel
142 assert "editor-table-wrap" in editor_web_panel
143 + assert "editor-empty" in editor_web_panel
144 + assert "runNewMenuAction('open')" in editor_web_panel
145 + assert "runNewMenuAction('markdown')" in editor_web_panel
146 assert "closeAllFiles" in editor_store
147 assert "confirmPendingClose" in editor_store
145 - assert "ensureInitialMarkdownFile" in editor_store
146 - assert "await this.ensureInitialMarkdownFile();" in editor_store
148 + assert "ensureInitialMarkdownFile" not in editor_store
149 + assert "_initialCreatePromise" not in editor_store
150 assert "startPreviewEdit" in editor_store
151 assert "applyPreviewEdit" in editor_store
152 assert "previewEditDirty" in editor_store
@@ -502,6 +505,20 @@ def test_editor_plugin_owns_markdown_sessions_and_active_context_extras():
505 assert "syncTextEditorResultsIntoOpenEditor" in editor_result_sync
506
507
508 +def test_editor_open_file_browser_prefers_context_home_before_workdir_fallback():
509 + editor_store = read("plugins", "_editor", "webui", "editor-store.js")
510 + start = editor_store.index("async openFileBrowser()")
511 + end = editor_store.index("\n async openPath", start)
512 + open_file_browser = editor_store[start:end]
513 +
514 + home_lookup = open_file_browser.index('const home = await callEditor("home");')
515 + settings_fallback = open_file_browser.index('const response = await callJsonApi("settings_get", null);')
516 +
517 + assert home_lookup < settings_fallback
518 + assert "workdirPath = home.path;" in open_file_browser
519 + assert "workdirPath = response?.settings?.workdir_path || workdirPath;" in open_file_browser
520 +
521 +
522 def test_office_and_desktop_skills_are_rehomed_and_renamed():
523 office_skills = PROJECT_ROOT / "plugins" / "_office" / "skills"
524 desktop_skills = PROJECT_ROOT / "plugins" / "_desktop" / "skills"