Merge issue 0013 — Paste & Extract panel

- Panel ImGui dockable: textarea, Extract button, preview tables (entities + relations)
- Subprocess directo a enrichers/paste_extract/run.py (no usa jobs system; preview puro)
- Pipeline Python emite preview JSON; commit a operations.db lo hace C++ con dedupe (type_ref, name)
- 12 tests pytest nuevos (paste_extract enricher + extract_panel logic)
- GLiNER/GLiREL path cableado pero no ejercitado en tests (modelos pesados); validacion interactiva pendiente

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-04 14:31:54 +02:00
10 changed files with 1923 additions and 0 deletions
+15
View File
@@ -30,6 +30,7 @@
#include "jobs.h"
#include "enrichers.h"
#include "chat.h"
#include "extract_panel.h"
#include "../../../../cpp/vendor/sqlite3/sqlite3.h"
@@ -1235,6 +1236,7 @@ static fn_ui::PanelToggle g_panels[] = {
{"Table", nullptr, &g_app.panel_table},
{"Jobs", nullptr, &g_app.panel_jobs},
{"Echo", nullptr, &g_app.panel_chat},
{"Extract", nullptr, &g_app.panel_extract},
};
static void render() {
@@ -2178,6 +2180,12 @@ static void render() {
ImGui::SetNextWindowSize(ImVec2(520.0f, 720.0f), ImGuiCond_FirstUseEver);
ge::chat_render(&g_app.panel_chat);
// Extract panel (issue 0013) — flotante, dockeable.
ImGui::SetNextWindowPos (ImVec2(vp->WorkPos.x + W * 0.30f, top + 50.0f),
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(720.0f, 640.0f), ImGuiCond_FirstUseEver);
ge::extract_panel_render(g_app);
// Enricher config window (abierto desde context menu Run enricher).
render_enricher_config_window();
@@ -2484,6 +2492,12 @@ int main(int argc, char** argv) {
(int)ge::enrichers_all().size());
}
// Extract panel (issue 0013) — invoca enrichers/paste_extract/run.py
// directamente en su propio hilo, sin pasar por el sistema de jobs.
ge::extract_panel_init(enrichers_dir.c_str(),
app_dir.c_str(),
registry_root.c_str());
// Chat panel (claude -p) — el agente invoca gx-cli para mutar
// operations.db. agent_mutations counter en graph_explorer.db dispara
// reload del viewport en cada cambio.
@@ -2573,6 +2587,7 @@ int main(int argc, char** argv) {
// Cleanup
ge::chat_shutdown();
ge::extract_panel_shutdown();
ge::jobs_shutdown();
if (g_layout_storage) {
fn_ui::layout_storage_close(g_layout_storage);