feat(editeur): #93 edition inline — Editer/Forge remplacent la vue lecture
Le conteneur d'edition (#editor-container, CodeMirror ou iframe Forge) est deplace dans la zone de contenu du document (#content-area ou pane active) au lieu de l'overlay plein ecran : le mode edition remplace la vue lecture. L'overlay reste monte (transparent, pointer-events: none) car le ruban d'edition mobile y est ancre ; il ne sert plus que de repli quand la cible n'est pas le document affiche. Garde-fou dans renderFile() pour liberer proprement la session (destroy CodeMirror/Yjs, retrait de l'iframe Forge) ; forge-close passe par closeEditor() ; cache d'onglet invalide au retour en lecture. Assistant IA : app_context.editing annonce le document en cours d'edition (frontend bookslm.js + backend bookslm.py), et chaque ecriture d'outil (edit_file, append_to_file, create_file, restore_backup) recharge le document affiche (obsigate:file-written) — tampon CodeMirror remplace avec auto-save neutralisee, parent-reload pour l'iframe Forge, re-rendu de la vue lecture sinon. Tests : tests/frontend/editor-inline.test.mjs (19), tests/test_bookslm.py::TestGeneralPrompt (3 nouveaux). Fiche : docs/features/editeur-inline.md.
This commit is contained in:
@@ -781,6 +781,12 @@ class BooksLM {
|
||||
ctx.open_documents = docs.map((d) => ({ vault: d.vault, path: d.path }));
|
||||
}
|
||||
|
||||
// #93 — Live edition session: the document currently replaced by the
|
||||
// editor/Forge surface. Knowing it lets the assistant target "le document
|
||||
// que je suis en train d'éditer" and update it in place.
|
||||
const editing = this._editingDocument();
|
||||
if (editing) ctx.editing = editing;
|
||||
|
||||
const query = state.advancedSearchLastQuery;
|
||||
if (query) {
|
||||
ctx.search_query = query;
|
||||
@@ -803,6 +809,43 @@ class BooksLM {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* #93 — The document currently being edited, i.e. the one the editor/Forge
|
||||
* surface replaced the read view with, or null. Sent as `app_context.editing`
|
||||
* so the assistant can target "le document que je suis en train d'éditer".
|
||||
*/
|
||||
_editingDocument() {
|
||||
try {
|
||||
const modal = document.getElementById('editor-modal');
|
||||
if (!modal || !modal.classList.contains('active')) return null;
|
||||
const vault = state.editorVault;
|
||||
const path = state.editorPath;
|
||||
if (!vault || !path) return null;
|
||||
return { vault, path, surface: document.getElementById('forge-iframe') ? 'forge' : 'editor' };
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* #93 — A write tool just modified a vault file. Notify the UI so the
|
||||
* displayed document is reloaded from disk: otherwise the read view keeps the
|
||||
* stale content, and an open editor buffer autosaves the old text back over
|
||||
* the assistant's change (see utils.reloadExternalWrite).
|
||||
*/
|
||||
_notifyFileWritten(data) {
|
||||
if (!data || data.ok === false) return;
|
||||
const WRITE_TOOLS = ['edit_file', 'append_to_file', 'create_file', 'restore_backup'];
|
||||
if (WRITE_TOOLS.indexOf(data.name) === -1) return;
|
||||
const args = data.arguments || {};
|
||||
if (!args.vault || !args.path) return;
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('obsigate:file-written', {
|
||||
detail: { vault: args.vault, path: args.path, tool: data.name },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Rendering ───────────────────────────────────────────────────────
|
||||
|
||||
_render() {
|
||||
@@ -2575,6 +2618,8 @@ class BooksLM {
|
||||
step: data.step || null,
|
||||
sources: Array.isArray(data.sources) ? data.sources : [],
|
||||
});
|
||||
// #93 — a vault write must be reflected in the displayed document.
|
||||
this._notifyFileWritten(data);
|
||||
this._setActivity('working', t('ai.activity_tool', { name: data.name }));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user