# Hooks, plugins, timeline e IA

Extensiones y subsistemas diferidos del runtime con límites precisos de ejecución, registro y autoridad.

<span class="section-anchor" id="section-1"></span>

## Middleware de lifecycle

Los hooks reciben `(context, next)`. Llamar a `next()` permite continuar; omitirlo cancela la cadena. Una prioridad mayor se ejecuta antes. El registro devuelve una función de baja que debes conservar si el middleware tiene un lifecycle más corto que el shell. La declaración TypeScript de `use` indica `void`; el runtime sí proporciona ese cleanup.

```js
const remove = wu.hooks.use('beforeMount', async (context, next) => {
  console.log('Montando', context.appName);
  await next();
}, { name: 'mount-observer', priority: 10 });

// Después de observar el escenario:
remove();
```

Las fases son `beforeInit`, `afterInit`, `beforeLoad`, `afterLoad`, `beforeMount`, `afterMount`, `beforeUpdate`, `afterUpdate`, `beforeUnmount`, `afterUnmount`, `beforeDestroy` y `afterDestroy`. El contexto depende de la fase; no todos los hooks reciben lifecycle, sandbox o props.

Un middleware que lanza antes de `next` cancela por defecto; `failOpen: true` permite continuar ante ese fallo. Los helpers exportados `createSimpleHook`, `createConditionalHook`, `createGuardHook`, `createTransformHook` y `createTimedHook` construyen middleware. El helper timed registra su error y llama a next: no es apropiado como control que deba cerrar acceso ante timeout.

<span class="section-anchor" id="section-2"></span>

## Plugin con grants explícitos

```js
let stop = () => {};

await wu.pluginSystem.use({
  name: 'catalog-observer',
  permissions: ['events'],
  install(api) {
    stop = api.on('catalog:selected', (event) => {
      console.info('Selección observada', event.data);
    });
  },
  uninstall() { stop(); },
}, { grants: ['events'] });

// Al retirarlo:
await wu.pluginSystem.uninstall('catalog-observer');
```

`use` admite objeto o factory, espera instalación y valida permisos. `ready()` permite esperar instalaciones pendientes; `init` ya espera esa barrera. El timeout por defecto de hooks de plugins es 5000 ms.

Las factories reciben opciones, no el core. Los grants host se copian antes de llamar a la factory para que esta no amplíe sus opciones y se autorice a sí misma. Aun así, un plugin es código ejecutado en el host: la API filtrada no aísla closures ni acceso global que ya tenga ese código.

<span class="section-anchor" id="section-3"></span>

## Timeline y tiempo de carga

```js
await wu.timelineReady();
wu.timeline.record({ snapshotEvery: 64, maxEntries: 5000 });

wu.store.set('demo.counter', 1);
wu.store.set('demo.counter', 2);

await wu.timeline.stepBack();
console.log(wu.store.get('demo.counter'));
await wu.timeline.live();

const recording = await wu.timeline.export();
wu.timeline.stop();
```

`timelineReady()` carga el chunk antes de empezar. Si llamas `record()` por primera vez y escribes inmediatamente, la escritura puede ocurrir antes de armar el registro diferido. El facade conserva la intención de record/stop mientras llega el módulo; para capturar la siguiente escritura sin ambigüedad usa ready primero.

El journal registra escrituras del store, eventos y lifecycle/props que pasan por WU. Tiene límite por defecto de 5000 entradas y snapshots cada 64. `seek`, `stepBack`, `stepForward`, `live`, `export`, `import`, `entries` y `status` permiten inspeccionar ese registro.

Retroceder rematerializa proyecciones; no rebobina timers internos de apps, peticiones HTTP ni infraestructura. Cuando estás en el pasado, nuevas escrituras no se agregan al journal y volver a live las descarta. No existe branching del historial ni auditoría durable implícita.

<span class="section-anchor" id="section-4"></span>

## IA optativa

El import principal instala un proxy lazy. Métodos chainables como `provider`, `action`, `trigger`, `capability` y `workflow` pueden encolar configuración mientras llega el chunk; operaciones de valor requieren esperar al módulo real. `aiReady()` es la forma explícita de obtenerlo.

```js
const ai = await wu.aiReady();
ai.init({ permissions: { executeActions: true } });

ai.action('sum_local', {
  description: 'Suma dos valores de demostración sin efectos externos',
  parameters: {
    type: 'object',
    properties: {
      a: { type: 'number' },
      b: { type: 'number' },
    },
    required: ['a', 'b'],
  },
  handler: async ({ a, b }) => ({ total: a + b }),
});

const result = await ai.execute('sum_local', { a: 2, b: 3 });
console.log(result);
```

Registrar y ejecutar esta action local no requiere enviar datos a un modelo. Para conversación existen providers, `send`, `stream`, `json`, `agent`, triggers y workflows, con sus propios permisos y configuración. No uses una key de servicio privada en un bundle público.

Actions validan parámetros, verifican `executeActions`, consultan permisos adicionales/condicionales y pueden pedir confirmación. `dangerous: true` obliga confirmación en el código actual. Los resultados de ejecución usan un envelope `{ success, result? , reason? }`: un rechazo de permisos puede ser un resultado negativo y no una excepción.

Los defaults permiten `readStore` y `emitEvents`; comienzan desactivados `writeStore`, `readDOM`, `modifyDOM`, `readDiagnostics`, `navigate`, `executeActions`, `network` y `allowDirectKey`. Son flags del módulo IA, independientes de grants app y autorización servidor.

<span class="section-anchor" id="section-5"></span>

## MCP y automatización

`wu.mcp.connect(url, options)`, `disconnect()` e `isConnected()` exponen el bridge cliente diferido. El paquete incluye también el binario `wu-mcp-server` y su subpath. El bridge puede inspeccionar y mutar estado/interfaz según controles del módulo; no agrega por sí mismo dry-run vinculante, idempotencia, autorización de dominio, rollback o un registro permanente.

Para un agente que opere recursos reales, usa un servicio que reciba comandos validados y devuelva receipts. El store puede proyectar su progreso; la action no debe convertirse en un closure que ejecuta privilegios sin revalidación.

<span class="section-anchor" id="section-6"></span>

## Referencia de implementación

Hooks: `src/core/wu-hooks.js`; plugins: `src/core/wu-plugin.js`; facade timeline: `src/index.js`; journal: `src/core/wu-timeline.js`; IA: `src/ai/wu-ai.js`, `src/ai/wu-ai-actions.js`, `src/ai/wu-ai-actions.js`; defaults: `src/ai/wu-ai-permissions.js`; MCP: `src/index.js`. Pruebas: `tests/unit/plugin-security.test.js`, `tests/unit/timeline-facade.test.js`, `tests/unit/lazy-ai-proxy.test.js`, `tests/unit/ai-actions.test.js`, `tests/unit/mcp-bridge-security.test.js`.