feat: sync all plugins, skills, agents updates

New plugins: core-tools
New skills: auto-expense, ticket-triage, design, security-check,
  aiktop-tasks, daily-digest, imap-triage, index-update, mindmap,
  notebooklm, proc-creator, tasks-overview, validate-component,
  perfex-module, report, calendar-manager
New agents: design-critic, design-generator, design-lead,
  design-prompt-architect, design-researcher, compliance-auditor,
  metabase-analyst, gitea-integration-specialist
Updated: all plugin configs, knowledge datasets, existing skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 17:16:15 +00:00
parent f2b5171ea2
commit 9404af7ac9
184 changed files with 20865 additions and 1993 deletions

View File

@@ -0,0 +1,226 @@
<?php
/**
* Plugin Name: Descomplicar JetEngine Bridge
* Description: API Endpoint customizado para manipulação atómica de CCTs e Relações JetEngine.
* Expõe /descomplicar/v1/manage para integração com n8n e agentes IA.
* Version: 1.1.0
* Author: Descomplicar® Crescimento Digital
* Author URI: https://descomplicar.pt
*
* Instalar em: /wp-content/mu-plugins/descomplicar-jet-bridge.php
* Autenticação: WordPress Application Passwords
*/
if ( ! defined( 'ABSPATH' ) ) exit;
class Descomplicar_Jet_Bridge {
public function __construct() {
add_action( 'rest_api_init', [ $this, 'register_routes' ] );
}
public function register_routes() {
register_rest_route( 'descomplicar/v1', '/manage', [
'methods' => 'POST',
'callback' => [ $this, 'handle_request' ],
'permission_callback' => function() {
// Autenticar via WordPress Application Passwords no n8n:
// Header: Authorization: Basic base64(user:app-password)
return current_user_can( 'edit_posts' );
},
]);
}
public function handle_request( WP_REST_Request $request ) {
$params = $request->get_json_params();
$action = sanitize_text_field( $params['action'] ?? '' );
if ( ! function_exists( 'jet_engine' ) || ! class_exists( 'Jet_Engine' ) ) {
return new WP_Error( 'no_jet_engine', 'JetEngine não está activo.', [ 'status' => 500 ] );
}
switch ( $action ) {
case 'create_cct_item':
case 'update_cct_item':
return $this->handle_cct_write( $params );
case 'get_cct_item':
return $this->handle_cct_get( $params );
case 'delete_cct_item':
return $this->handle_cct_delete( $params );
case 'manage_relation':
return $this->handle_relation( $params );
default:
return new WP_Error(
'invalid_action',
'Acção inválida. Disponíveis: create_cct_item, update_cct_item, get_cct_item, delete_cct_item, manage_relation',
[ 'status' => 400 ]
);
}
}
/**
* Criar ou actualizar item CCT
*
* Payload: {
* "action": "create_cct_item",
* "cct_slug": "faturas",
* "item_data": {
* "titulo": "Fatura #1024",
* "valor": 500,
* "estado": "pendente"
* }
* }
* Para update, incluir "_ID": 42 em item_data.
*/
private function handle_cct_write( array $params ) {
$cct_slug = sanitize_key( $params['cct_slug'] ?? '' );
$item_data = $params['item_data'] ?? [];
if ( empty( $cct_slug ) ) {
return new WP_Error( 'missing_slug', 'cct_slug é obrigatório.', [ 'status' => 400 ] );
}
if ( empty( $item_data ) ) {
return new WP_Error( 'missing_data', 'item_data é obrigatório.', [ 'status' => 400 ] );
}
$handler = $this->get_cct_handler( $cct_slug );
if ( is_wp_error( $handler ) ) return $handler;
$result_id = $handler->update_item( $item_data );
if ( ! $result_id ) {
return new WP_Error( 'db_error', 'Falha ao guardar item na base de dados.', [ 'status' => 500 ] );
}
return rest_ensure_response( [
'success' => true,
'item_id' => $result_id,
'action' => isset( $item_data['_ID'] ) ? 'updated' : 'created',
] );
}
/**
* Ler item CCT por ID
*
* Payload: { "action": "get_cct_item", "cct_slug": "faturas", "item_id": 42 }
*/
private function handle_cct_get( array $params ) {
$cct_slug = sanitize_key( $params['cct_slug'] ?? '' );
$item_id = absint( $params['item_id'] ?? 0 );
if ( empty( $cct_slug ) || ! $item_id ) {
return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] );
}
$handler = $this->get_cct_handler( $cct_slug );
if ( is_wp_error( $handler ) ) return $handler;
$item = $handler->get_item( $item_id );
if ( ! $item ) {
return new WP_Error( 'not_found', "Item {$item_id} não encontrado no CCT '{$cct_slug}'.", [ 'status' => 404 ] );
}
return rest_ensure_response( [
'success' => true,
'item' => $item,
] );
}
/**
* Eliminar item CCT
*
* Payload: { "action": "delete_cct_item", "cct_slug": "faturas", "item_id": 42 }
*/
private function handle_cct_delete( array $params ) {
$cct_slug = sanitize_key( $params['cct_slug'] ?? '' );
$item_id = absint( $params['item_id'] ?? 0 );
if ( empty( $cct_slug ) || ! $item_id ) {
return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] );
}
$handler = $this->get_cct_handler( $cct_slug );
if ( is_wp_error( $handler ) ) return $handler;
$result = $handler->delete_item( $item_id );
return rest_ensure_response( [
'success' => (bool) $result,
'item_id' => $item_id,
'deleted' => (bool) $result,
] );
}
/**
* Criar ou remover relação entre dois items
*
* Payload: {
* "action": "manage_relation",
* "rel_key": "clientes-projetos",
* "parent_id": 10,
* "child_id": 20,
* "connect": true
* }
*/
private function handle_relation( array $params ) {
$rel_key = sanitize_text_field( $params['rel_key'] ?? '' );
$parent_id = absint( $params['parent_id'] ?? 0 );
$child_id = absint( $params['child_id'] ?? 0 );
$connect = (bool) ( $params['connect'] ?? true );
if ( empty( $rel_key ) || ! $parent_id || ! $child_id ) {
return new WP_Error(
'missing_data',
'rel_key, parent_id e child_id são obrigatórios.',
[ 'status' => 400 ]
);
}
if ( ! class_exists( '\Jet_Engine\Relations\Manager' ) ) {
return new WP_Error( 'no_relations', 'Módulo de Relações JetEngine não disponível.', [ 'status' => 500 ] );
}
\Jet_Engine\Relations\Manager::get_instance()->process_relation(
$rel_key,
$parent_id,
$child_id,
$connect
);
return rest_ensure_response( [
'success' => true,
'action' => $connect ? 'connected' : 'disconnected',
'rel_key' => $rel_key,
'parent' => $parent_id,
'child' => $child_id,
] );
}
/**
* Obter CCT handler com verificação de erro
*/
private function get_cct_handler( string $cct_slug ) {
$cct_module = jet_engine()->modules->get_module( 'custom-content-types' );
if ( ! $cct_module ) {
return new WP_Error( 'no_cct_module', 'Módulo CCT não está activo no JetEngine.', [ 'status' => 500 ] );
}
$manager = $cct_module->instance->manager;
$type = $manager->get_content_type_instance( $cct_slug );
if ( ! $type ) {
return new WP_Error( 'invalid_cct', "CCT '{$cct_slug}' não encontrado.", [ 'status' => 404 ] );
}
return $type->get_handler_instance();
}
}
new Descomplicar_Jet_Bridge();