feat(0036d): promote kind-aware (Group → clear group_id)

NodeGroups window kind=Group ahora expone un boton SmallButton(TI_ARROW_UP)
por fila que saca la entidad del grupo (group_id = NULL) y dispara
reload del grafo. kind=Table mantiene el comportamiento de issue 0011.

- entity_ops: nueva op `entity_clear_group_id(db, id)` idempotente. Si
  la columna group_id no existe (BD pre-0035a) retorna true como no-op.
  Falla solo si la entidad no existe o SQLite revienta.
- views.cpp: extra columna "promote" en kind=Group, tooltip header
  diferenciado por kind, boton conectado a app.want_clear_group_id_entity.
- main.cpp: handler que ejecuta entity_clear_group_id, marca windows
  como dirty, llama reload_after_mutation y loguea
  `[node_groups] promoted X out of group`.
- gx-cli: flag `node update --clear-group-id` (booleano) y exposicion
  MCP en inputSchema + MCP_DISPATCH defaults para que el agente Echo
  pueda promover via tool calls.
- tests: 3 nuevos CLI (clear, idempotente, combinable con --name) y
  4 MCP (defaults, schema, dispatch end-to-end, idempotente).

WSL: 102 passed (95 base + 7).
Windows: 91 passed, 11 skipped (84 base + 7).

Refs: issues/0036d-promote-kind-aware.md
This commit is contained in:
2026-05-04 01:03:11 +02:00
parent 98e744ea4e
commit f0d8a5ad04
8 changed files with 311 additions and 5 deletions
+12
View File
@@ -43,6 +43,18 @@ bool entity_delete(const char* db_path, const char* id);
bool entity_update_type(const char* db_path, const char* id, const char* new_type);
// Saca la entidad de su grupo: UPDATE entities SET group_id = NULL.
// Idempotente — si la entidad ya tenia group_id NULL, no falla. Devuelve
// true si la entidad existe (independientemente de si tenia o no grupo).
// Devuelve false si la entidad no existe o SQLite falla. En BDs antiguas
// sin la columna `group_id` retorna true como no-op (la entidad no puede
// pertenecer a un grupo si la columna no existe).
//
// Issue 0036d: pareja del flujo Promote en NodeGroups window cuando
// kind=Group — saca el nodo del grupo para que aparezca suelto en el
// canvas tras reload.
bool entity_clear_group_id(const char* db_path, const char* entity_id);
// Duplica una entidad existente. Mismo type/metadata, sufijo "_copy" en id
// y "(copia)" en name. Devuelve el nuevo id en out_id.
bool entity_duplicate(const char* db_path, const char* id,