orquestra-mcp 1.16.1 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/package.json +1 -1
- package/src/platformPlaybooks.mjs +2 -2
- package/src/server.mjs +29 -18
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# orquestra-mcp
|
|
2
2
|
|
|
3
|
-
Servidor MCP (Model Context Protocol) para Orquestra. Expone **
|
|
3
|
+
Servidor MCP (Model Context Protocol) para Orquestra. Expone **89 tools**
|
|
4
4
|
que llaman a la API de `orquestra-infra`: lectura de contexto/dashboard/
|
|
5
5
|
workspace/infra/paridad/listados, escritura de tareas/ideas/changelog/
|
|
6
6
|
notas/docs/módulos/flujo/categorías/infra/proyectos, y corridas de QA —
|
|
@@ -192,11 +192,13 @@ create/update sigue siendo criterio del agente y del humano.
|
|
|
192
192
|
|
|
193
193
|
## Estado
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
89 tools: lectura (contexto, dashboard, workspace, infra, paridad, standup,
|
|
196
|
+
sync report, setup guide, playbooks de etapa y de plataforma, catálogo de
|
|
197
|
+
skills, search) + `list_*` de cada colección + creación/edición de tareas
|
|
198
|
+
(con checklist, tiempo, adjuntos, merge), ideas (con comentarios), notas,
|
|
199
|
+
docs, changelog (con corte de versión), módulos, flujo, categorías,
|
|
200
|
+
infraestructura, proyecto, contenido (canales, campañas, contenido,
|
|
201
|
+
Postproxy), agentes, skills y sugerencias + compuestas (init_project,
|
|
202
|
+
apply_stage_playbook, apply_platform_playbook, install_skill). Sin
|
|
203
|
+
`delete_*` salvo adjuntos e ítems de checklist. Publicado en npm como
|
|
204
|
+
`orquestra-mcp` (unscoped) -- `npx orquestra-mcp setup`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orquestra-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "Servidor MCP de Orquestra -- 89 tools para leer y escribir tareas, ideas, changelog, infraestructura, contenido, QA y más desde un agente de IA",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -102,7 +102,7 @@ export const PLATFORM_PLAYBOOKS = {
|
|
|
102
102
|
{
|
|
103
103
|
title: 'Preparar capturas de pantalla en los tamaños exactos que pide App Store Connect',
|
|
104
104
|
description: 'Las dimensiones válidas cambian con cada generación de iPhone/iPad -- si App Store Connect rechaza una captura al subirla, el mensaje de error indica el tamaño exacto que espera para ese dispositivo; ajusta según ese mensaje real, no de memoria.',
|
|
105
|
-
type: 'business', priority: 'medium', tags: ['publicacion', 'ios'], offsetDays: 7,
|
|
105
|
+
type: 'business', priority: 'medium', tags: ['publicacion', 'ios'], offsetDays: 7, checklistTool: 'screenshots',
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
title: 'Completar el cuestionario de privacidad de la tienda (Data Collection)',
|
|
@@ -251,7 +251,7 @@ export const PLATFORM_PLAYBOOKS = {
|
|
|
251
251
|
{
|
|
252
252
|
title: 'Preparar capturas de pantalla en los tamaños exactos que pide Play Console',
|
|
253
253
|
description: 'Mínimo 2 capturas de teléfono, más el gráfico destacado (1024x500) y el ícono (512x512) -- Play Console valida las dimensiones al subir, ajusta según lo que rechace.',
|
|
254
|
-
type: 'business', priority: 'medium', tags: ['publicacion', 'android'], offsetDays: 7,
|
|
254
|
+
type: 'business', priority: 'medium', tags: ['publicacion', 'android'], offsetDays: 7, checklistTool: 'screenshots',
|
|
255
255
|
},
|
|
256
256
|
{
|
|
257
257
|
title: 'Completar el formulario de seguridad de los datos (Data safety)',
|
package/src/server.mjs
CHANGED
|
@@ -10,6 +10,10 @@ import { PLATFORM_PLAYBOOKS } from './platformPlaybooks.mjs'
|
|
|
10
10
|
import { SKILLS_CATALOG } from './skillsCatalog.mjs'
|
|
11
11
|
import { parseSource, previewSkill, installSkill } from './skillInstall.mjs'
|
|
12
12
|
|
|
13
|
+
// Versión leída de package.json (3 sep 2026) -- antes estaba hardcodeada
|
|
14
|
+
// acá y quedaba atrás en cada bump (decía 1.16.0 con package.json en 1.16.2).
|
|
15
|
+
const PKG_VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version
|
|
16
|
+
|
|
13
17
|
function errorResult(err) {
|
|
14
18
|
const text = err instanceof ApiError ? `Error (${err.status}): ${err.message}` : `Error: ${err.message}`
|
|
15
19
|
return { content: [{ type: 'text', text }], isError: true }
|
|
@@ -93,6 +97,7 @@ Durante el trabajo normal de código, sin que el usuario te lo pida explícitame
|
|
|
93
97
|
- Si una nota que vas a crear (create_note) es claramente sobre un módulo o una tarea específica -- por ejemplo durante un setup guiado donde acabas de crear ambos -- mándale moduleId/taskId para ligarla, en vez de dejarla suelta. No inventes la relación si no es clara.
|
|
94
98
|
- create_changelog_entry SIEMPRE deja la entrada en Unreleased (nunca mandes version salvo que el usuario te haya dado un número real) -- cortar una versión es release_changelog_version, una acción DELIBERADA que solo se llama si el usuario la pide explícitamente ("cortá la versión", "hacé el release de X") o confirma un número/fecha real que vos propusiste. No la dispares solo porque terminaste una tarea o un lote de trabajo grande.
|
|
95
99
|
- Si tienes acceso al repo real de una distribución (ej. puedes correr "git remote get-url origin" en ese código), llena repoUrl en create_distribution/update_distribution sin preguntar -- es solo informativo, no requiere credenciales. Esto es distinto de conectar el repo con PAT para el changelog automático (Workspace → Conexiones en orquestra-web): eso sí es un paso deliberado del usuario, con una credencial real -- nunca lo hagas tú solo ni sugieras que ya está conectado por haber llenado repoUrl.
|
|
100
|
+
- Paridad por producto: las distribuciones que son el mismo producto en distintas plataformas (típicamente Web/iOS/Android) comparten un productKey (list_distributions lo muestra). Si al crear una tarea con scope en una de ellas la respuesta trae parityAddedDistIds, el server sumó las hermanas como pendientes -- dícelo al usuario ("también quedó pendiente en iOS y Android") y no lo deshagas salvo que el trabajo sea genuinamente de una sola plataforma (entonces skipParity:true, o quítalas con update_task/scope explicando por qué). Al cerrar una tarea con scope multiplataforma, marca done:true SOLO en la plataforma donde de verdad se hizo (update_task/scope) -- el estatus "Listo" no mueve esos flags solo; dejar las hermanas en done:false es exactamente lo que hace que el desfase aparezca en get_parity_summary y en la revisión de sincronización (tasksClosedWithParityPending), que es el punto: que nunca se olvide el trabajo del otro lado. Si el proyecto tiene 2+ plataformas y ninguna tiene productKey (get_parity_summary → productGroups.configured=false), pregúntale al usuario cuáles son el mismo producto y configúralo con update_distribution -- nunca lo infieras solo del tipo de plataforma.
|
|
96
101
|
- Al crear o editar una tarea (o un módulo), llena TODO campo para el que tengas un dato real, no solo title/moduleId/dueDate/comment: type (no lo dejes en el default "feature" si en realidad es un bug/mejora/doc/etc.), tags, stack (tecnologías que genuinamente tocaste), scope (paridad multiplataforma, si aplica), y los campos de código (branch/prNumber/prUrl/prStatus/commitCount/resolvedCommitSha/resolvedCommitMessage/resolvedCommitUrl/resolvedCommitAt) cuando de verdad sepas esos valores (el branch en el que estás trabajando, el PR que abriste, el commit que resolvió la tarea). No dejes un campo en blanco solo porque no es obligatorio -- pero esto no es licencia para inventar: si no tenés el dato real (ej. no hay branch/PR porque el proyecto commitea directo a main), dejalo vacío en vez de rellenarlo con algo plausible pero falso -- mismo criterio que ya se pedía para resolvedCommitSha.
|
|
97
102
|
- Si una tarea tiene más de una actividad o paso concreto, no los amontones como texto corrido en description -- usa el checklist (add_checklist_item, un ítem por actividad, opcionalmente con responsable) para que cada paso se pueda marcar independientemente. description queda para el contexto/propósito general de la tarea (el qué y el por qué), no como lista de pasos. Si estás editando una tarea existente cuya description ya creció así, migra esos puntos a checklist en vez de seguir agregando ahí.
|
|
98
103
|
- Al cerrar una tarea en la que trabajaste de verdad (o al final de una sesión de trabajo real sobre ella), registrá las horas con log_time -- el tiempo REAL que llevó ese trabajo en esta sesión (aproximalo con honestidad: minutos de trabajo real, no la duración del chat ni la estimación de la tarea), con una nota corta de qué se hizo. Ese registro alimenta "Horas del equipo" en Inversión de Contenido y es la única forma de que el costo real del proyecto no dependa de que el usuario lo cargue a mano. No lo inventes ni lo infles; si genuinamente no podés estimar el tiempo de la sesión, no registres nada.
|
|
@@ -103,6 +108,7 @@ Si el usuario pide "sincronizar"/"revisar que todo esté al día"/"verificar el
|
|
|
103
108
|
2. Para cada tarea en tasksMissingModule: buscá con list_modules si hay uno que aplique de verdad; si no, create_module antes de asignarlo -- nunca dejes una sin módulo (ver moduleId obligatorio en create_task, esto es limpiar deuda vieja de antes de esa regla).
|
|
104
109
|
3. Para CADA tarea de activeTasksSnapshot (no solo las que tienen dueDate/priority en blanco -- una prioridad "medium" puesta por default nunca se distingue de una elegida a propósito): revisá el contexto real (código, conversación, changelog, dependencias vía relatedTaskId) y asigná una fecha límite realista y un nivel de urgencia real con update_task si el valor actual no refleja la urgencia/plazo real -- no inventes una fecha arbitraria sin ninguna base ("en 3 días" porque sí); si genuinamente no hay forma de estimar una fecha con la información disponible, dejala en blanco en vez de inventar una.
|
|
105
110
|
4. Las referencias huérfanas (tasksWithOrphanModuleId/CategoryId/RelatedTaskId/StatusId) casi nunca se pueden arreglar solas con criterio -- no adivines a qué debería apuntar. Marcalas para el resumen final, y si es obvio por contexto a qué debió apuntar, proponéselo al usuario en vez de aplicarlo directo.
|
|
111
|
+
4b. Paridad (solo si productGroups.configured): tasksClosedWithParityPending son tareas ya cerradas con trabajo pendiente en una plataforma hermana (pendingDistNames). Para cada una decidí con el usuario: si en realidad YA se hizo ahí, marcá done:true en ese scope con update_task; si no se hizo, creá la tarea de esa plataforma (mismo módulo, relatedTaskId opcional) -- nunca marques done sin evidencia real. tasksMissingSiblingScope son tareas activas que tocan una hermana sin declarar a las demás: confirmá si aplica y extendé el scope, o dejalo si es trabajo de una sola plataforma.
|
|
106
112
|
5. Cerrá SIEMPRE con un resumen estructurado en 3 grupos, aunque algún grupo quede vacío: **No tiene sentido / necesita tu decisión** (referencias huérfanas, contradicciones que encontraste), **Se llenó** (campos que estaban vacíos y ahora tienen un valor real, con qué tarea y qué campo), **Se completó** (lo que quedó totalmente resuelto en esta pasada -- ej. una tarea que ya tenía todo en orden, o un hueco que se cerró del todo). Si tocaste tareas de verdad (no solo leíste el reporte), dejá rastro con un comment en cada una vía update_task explicando qué cambiaste y por qué -- mismo criterio que un cambio de statusId, no debería quedar invisible.
|
|
107
113
|
|
|
108
114
|
No le preguntes al usuario por workspaceId ni projectId -- ya están configurados. Solo pregúntale por el proyecto si tiene más de uno y no queda claro a cuál te refieres.
|
|
@@ -115,7 +121,7 @@ Si el usuario pregunta explícito qué Claude Skills de terceros le faltan (o pi
|
|
|
115
121
|
|
|
116
122
|
export function createServer() {
|
|
117
123
|
const config = loadConfig()
|
|
118
|
-
const server = new McpServer({ name: 'orquestra-mcp', version:
|
|
124
|
+
const server = new McpServer({ name: 'orquestra-mcp', version: PKG_VERSION }, { instructions: SERVER_INSTRUCTIONS })
|
|
119
125
|
|
|
120
126
|
function resolveProjectId(projectId) {
|
|
121
127
|
if (config.defaultProjectId) return config.defaultProjectId
|
|
@@ -246,7 +252,7 @@ export function createServer() {
|
|
|
246
252
|
registerRead(
|
|
247
253
|
'get_parity_summary',
|
|
248
254
|
'/v1/parity',
|
|
249
|
-
'Desfases de paridad multiplataforma: tareas y módulos cuyo scope avanza en una distribución pero sigue pendiente en otra.',
|
|
255
|
+
'Desfases de paridad multiplataforma: tareas y módulos cuyo scope avanza en una distribución pero sigue pendiente en otra HERMANA (mismo productKey -- ver productGroups en la respuesta; si configured=false, el proyecto nunca marcó qué plataformas son el mismo producto y todas se comparan entre sí: sugiérele al usuario configurarlo con update_distribution/productKey). singleDoneItems trae las candidatas a portar con missingDistIds concretos.',
|
|
250
256
|
{},
|
|
251
257
|
(args, projectId) => ({ projectId })
|
|
252
258
|
)
|
|
@@ -505,7 +511,8 @@ export function createServer() {
|
|
|
505
511
|
assignedTo: z.string().optional().describe('uid del miembro asignado'),
|
|
506
512
|
tags: z.array(z.string()).optional(),
|
|
507
513
|
scope: z.array(z.object({ distId: z.string(), layer: z.string().optional(), done: z.boolean() })).optional()
|
|
508
|
-
.describe('Alcance por distribución (paridad multiplataforma) -- para setearlo desde la creación en vez de crear y después update_task. Usa get_parity_summary/list_distributions para ver qué distId existen.'),
|
|
514
|
+
.describe('Alcance por distribución (paridad multiplataforma) -- para setearlo desde la creación en vez de crear y después update_task. Usa get_parity_summary/list_distributions para ver qué distId existen. Si una distId tiene hermanas (mismo productKey), el server suma las que falten solo, con done:false -- la respuesta trae parityAddedDistIds con lo que agregó: avísale al usuario que la tarea también quedó pendiente en esas plataformas.'),
|
|
515
|
+
skipParity: z.boolean().optional().describe('true = NO sumar las plataformas hermanas al scope aunque tengan el mismo productKey. Solo cuando el trabajo es genuinamente de UNA plataforma (ej. un ajuste de Gradle que no tiene contraparte en iOS) -- no lo mandes por default. Las tareas type="bug" nunca propagan, sin necesidad de esto.'),
|
|
509
516
|
relatedTaskId: z.string().optional().describe('"Bloqueada por" -- id de otra tarea. Esta tarea se muestra como bloqueada mientras esa otra no llegue a un estatus final (isFinal). Úsalo cuando el trabajo real depende de que otra tarea termine primero.'),
|
|
510
517
|
location: z.string().optional().describe('Solo relevante para type "meeting"/"call" (plataforma o lugar, ej. "Zoom", "Oficina") o "followup"/"business" (contexto libre) -- ignóralo para el resto de los tipos.'),
|
|
511
518
|
estimatedDays: z.number().optional().describe('Estimación en días de trabajo.'),
|
|
@@ -613,10 +620,10 @@ export function createServer() {
|
|
|
613
620
|
server.registerTool(
|
|
614
621
|
'connect_postproxy_channel',
|
|
615
622
|
{
|
|
616
|
-
description: 'Inicia la conexión de un canal (facebook/instagram/tiktok) a Postproxy. Devuelve UNA de dos formas: {url} -- OAuth hosteado por Postproxy, el usuario tiene que abrirlo y completarlo a mano (el agente no puede terminar un OAuth por su cuenta), pásale esa URL tal cual; o {needsPageSelection, profileId, pages} --
|
|
623
|
+
description: 'Inicia la conexión de un canal (facebook/instagram/tiktok/linkedin) a Postproxy. Devuelve UNA de dos formas: {url} -- OAuth hosteado por Postproxy, el usuario tiene que abrirlo y completarlo a mano (el agente no puede terminar un OAuth por su cuenta), pásale esa URL tal cual; o {needsPageSelection, profileId, pages} -- pasa con facebook y linkedin, cuando ya hay un login de esa red conectado en la cuenta (un solo login da acceso a varias Pages de Facebook, o al perfil personal y las Organization Pages de LinkedIn, no hace falta repetir el OAuth) y hace falta elegir cuál corresponde a este canal. Esa elección hoy es un flujo de la web (Cuentas conectadas) -- si te llega `needsPageSelection`, dile al usuario que complete la selección ahí, esta tool no tiene una contraparte para elegir la página. Solo para los tipos que soporta Postproxy -- un canal newsletter (Buttondown) se conecta desde la web, no con esta tool.',
|
|
617
624
|
inputSchema: {
|
|
618
625
|
projectId: z.string().optional().describe(PROJECT_ID_DESC),
|
|
619
|
-
channelId: z.string().describe('Canal a conectar (ver list_channels) -- su `type` tiene que ser facebook/instagram/tiktok'),
|
|
626
|
+
channelId: z.string().describe('Canal a conectar (ver list_channels) -- su `type` tiene que ser facebook/instagram/tiktok/linkedin'),
|
|
620
627
|
platform: z.string().describe('Plataforma tal cual la espera Postproxy (mismo valor que channel.type -- ej. "instagram")'),
|
|
621
628
|
},
|
|
622
629
|
},
|
|
@@ -1443,6 +1450,7 @@ export function createServer() {
|
|
|
1443
1450
|
label: z.string().describe('Nombre a mostrar por default'),
|
|
1444
1451
|
name: z.string().optional().describe('Nombre editable -- si no se manda, la UI usa label'),
|
|
1445
1452
|
categoryId: z.string().optional(),
|
|
1453
|
+
productKey: z.string().optional().describe('Paridad por producto: clave libre (ej. "app") que agrupa las distribuciones que son EL MISMO producto en distintas plataformas (Web/iOS/Android). Hermanas = misma clave. Con eso la paridad solo compara entre hermanas y create_task propone el scope de las demás solo. Landing/backend/MCP normalmente van sin clave. Solo asígnala si el usuario confirma qué plataformas son el mismo producto -- no la infieras del tipo.'),
|
|
1446
1454
|
status: z.enum(INFRA_STATUSES).optional().describe('Default: operational'),
|
|
1447
1455
|
phase: z.string().optional().describe('idea | design | alpha | beta | live | deprecated'),
|
|
1448
1456
|
identifier: z.string().optional().describe('Legado -- preferir bundleId (no-web) o domain (web)'),
|
|
@@ -1463,6 +1471,7 @@ export function createServer() {
|
|
|
1463
1471
|
label: z.string().optional(),
|
|
1464
1472
|
name: z.string().optional(),
|
|
1465
1473
|
categoryId: z.string().optional(),
|
|
1474
|
+
productKey: z.string().optional().describe('Paridad por producto -- misma clave en las distribuciones que son el mismo producto (ver create_distribution). "" la quita.'),
|
|
1466
1475
|
status: z.enum(INFRA_STATUSES).optional(),
|
|
1467
1476
|
phase: z.string().optional(),
|
|
1468
1477
|
identifier: z.string().optional(),
|
|
@@ -1518,7 +1527,7 @@ export function createServer() {
|
|
|
1518
1527
|
|
|
1519
1528
|
registerCreate('create_channel', '/v1/channels', 'Crea un canal (cuenta de contenido) en un proyecto -- ej. "LinkedIn", "Blog de Atlas". No conecta ninguna cuenta real todavía (eso es OAuth, fuera de alcance por ahora); solo registra el canal para poder programar contenido en él.', {
|
|
1520
1529
|
name: z.string().describe('Ej. "LinkedIn"'),
|
|
1521
|
-
type: z.string().optional().describe('linkedin | x | blog | newsletter | instagram
|
|
1530
|
+
type: z.string().optional().describe('facebook | instagram | tiktok | linkedin | x | blog | newsletter | other -- libre. facebook/instagram/tiktok/linkedin se conectan después con connect_postproxy_channel'),
|
|
1522
1531
|
handle: z.string().optional().describe('Ej. "@atlaspagos" o una URL/dominio'),
|
|
1523
1532
|
color: z.string().optional(),
|
|
1524
1533
|
cadenceCount: z.number().optional().describe('Ritmo objetivo de publicaciones, ej. 2'),
|
|
@@ -1632,24 +1641,26 @@ export function createServer() {
|
|
|
1632
1641
|
// Un agente tiene un `kind` atado a una máquina (runnerId); los 3 kinds de
|
|
1633
1642
|
// hoy (23 ago 2026: qa/security/performance) exigen stack+localPath (un
|
|
1634
1643
|
// checkout real en esa máquina), y performance además perfUrl (URL viva
|
|
1635
|
-
// contra la que corre Lighthouse).
|
|
1636
|
-
// stack="web" por ahora
|
|
1637
|
-
//
|
|
1638
|
-
//
|
|
1639
|
-
|
|
1644
|
+
// contra la que corre Lighthouse). qa/security/performance solo tienen
|
|
1645
|
+
// lógica real para stack="web" por ahora; screenshots es lo inverso, solo
|
|
1646
|
+
// stack="ios"|"android" (captura automática para el checklist de
|
|
1647
|
+
// publicación, ver ScreenshotChecklist.jsx en orquestra-web). "orquestra-qa-agent
|
|
1648
|
+
// setup" crea/actualiza solo agentes kind="qa" -- el resto se crean a
|
|
1649
|
+
// mano acá o desde la web.
|
|
1650
|
+
const AGENT_KINDS = ['qa', 'security', 'performance', 'screenshots']
|
|
1640
1651
|
const AGENT_STACKS = ['web', 'ios', 'android', 'node', 'nestjs']
|
|
1641
1652
|
|
|
1642
1653
|
registerRead('list_agents', '/v1/agents',
|
|
1643
1654
|
'Lista los agentes (kind+máquina+stack+ruta local) configurados en un proyecto. Úsala antes de create_agent o de create_agent_run con stack, para saber si ya existe uno.',
|
|
1644
|
-
{ kind: z.enum(AGENT_KINDS).optional().describe('Filtra por kind: "qa" (lint/test/build/E2E), "security" (npm audit + gitleaks)
|
|
1655
|
+
{ kind: z.enum(AGENT_KINDS).optional().describe('Filtra por kind: "qa" (lint/test/build/E2E), "security" (npm audit + gitleaks), "performance" (build size + Lighthouse) o "screenshots" (captura de pantallas para el checklist de publicación, solo ios/android)') },
|
|
1645
1656
|
(args, projectId) => ({ projectId }))
|
|
1646
1657
|
|
|
1647
|
-
registerCreate('create_agent', '/v1/agents', 'Crea un agente: asocia un kind ("qa" | "security" | "performance") a una máquina (runner, ver Workspace → Máquinas), un stack de este proyecto y una ruta de checkout en ESA máquina. kind="performance" además necesita perfUrl.', {
|
|
1658
|
+
registerCreate('create_agent', '/v1/agents', 'Crea un agente: asocia un kind ("qa" | "security" | "performance" | "screenshots") a una máquina (runner, ver Workspace → Máquinas), un stack de este proyecto y una ruta de checkout en ESA máquina. kind="performance" además necesita perfUrl.', {
|
|
1648
1659
|
name: z.string().describe('Nombre a mostrar, ej. "Agente web"'),
|
|
1649
|
-
kind: z.enum(AGENT_KINDS).default('qa').describe('"qa" (lint/test/build/E2E), "security" (npm audit + gitleaks)
|
|
1660
|
+
kind: z.enum(AGENT_KINDS).default('qa').describe('"qa" (lint/test/build/E2E), "security" (npm audit + gitleaks), "performance" (build size + Lighthouse) o "screenshots" (captura de pantallas para tiendas, solo stack ios/android) -- default "qa"'),
|
|
1650
1661
|
runnerId: z.string().describe('ID de la máquina emparejada -- ver list_agents o Workspace → Máquinas'),
|
|
1651
|
-
stack: z.enum(AGENT_STACKS).optional().describe('Requerido para los
|
|
1652
|
-
localPath: z.string().optional().describe('Requerido para los
|
|
1662
|
+
stack: z.enum(AGENT_STACKS).optional().describe('Requerido para los 4 kinds. security/performance solo tienen lógica real para "web" hoy; screenshots solo para "ios"/"android"'),
|
|
1663
|
+
localPath: z.string().optional().describe('Requerido para los 4 kinds -- ruta absoluta del checkout en esa máquina'),
|
|
1653
1664
|
branch: z.string().optional().describe('Rama de este agente -- default "main" si no se manda'),
|
|
1654
1665
|
distributionId: z.string().optional().describe('Distribución vinculada (repo/fuente de conocimiento)'),
|
|
1655
1666
|
enabled: z.boolean().optional(),
|
|
@@ -1684,7 +1695,7 @@ export function createServer() {
|
|
|
1684
1695
|
minPerfScore: z.number().optional(),
|
|
1685
1696
|
})
|
|
1686
1697
|
|
|
1687
|
-
registerCreate('create_agent_run', '/v1/agent-runs', 'Dispara una corrida de agente (qa: lint/tests/build/E2E; security: npm audit + gitleaks; performance: build size + Lighthouse) en la rama indicada. Necesita al menos un agente activo para el stack (o falla explícito -- ver list_agents/create_agent). La corrida queda "queued" -- nunca asumas que pasó, confirma con get_agent_run.', {
|
|
1698
|
+
registerCreate('create_agent_run', '/v1/agent-runs', 'Dispara una corrida de agente (qa: lint/tests/build/E2E; security: npm audit + gitleaks; performance: build size + Lighthouse; screenshots: captura de pantallas para el checklist de publicación) en la rama indicada. Necesita al menos un agente activo para el stack (o falla explícito -- ver list_agents/create_agent). La corrida queda "queued" -- nunca asumas que pasó, confirma con get_agent_run.', {
|
|
1688
1699
|
agentId: z.string().optional().describe('Agente específico -- si se manda, gana sobre stack/kind'),
|
|
1689
1700
|
branch: z.string().optional().describe('Rama a probar -- default: la del agente, o "main"'),
|
|
1690
1701
|
commit: z.string().optional(),
|
|
@@ -1692,7 +1703,7 @@ export function createServer() {
|
|
|
1692
1703
|
stack: z.string().optional().describe('Stack a probar (ej. "web", "ios", "android") -- resuelve contra los agentes activos de ese stack. Falla si hay 0 (créalo con create_agent) o más de 1 (usa agentId o suma kind para desambiguar).'),
|
|
1693
1704
|
kind: z.enum(AGENT_KINDS).optional().describe('Desambigua junto con stack cuando el proyecto tiene más de un agente para el mismo stack (ej. un "qa" y un "security", ambos "web") -- sin esto, resuelve por stack solo y falla explícito si hay más de uno.'),
|
|
1694
1705
|
runnerId: z.string().optional().describe('Máquina específica -- si se manda, gana sobre la del agente resuelto'),
|
|
1695
|
-
taskId: z.string().optional().describe('Acota la revisión con IA (si el agente la tiene activada) a esta tarea en vez de "revisa todo el proyecto" -- útil para pedir "corre QA de esto que acabo de hacer". Sin efecto en los pasos de script (lint/test/build corren igual siempre). No combinar con moduleId.'),
|
|
1706
|
+
taskId: z.string().optional().describe('Acota la revisión con IA (si el agente la tiene activada) a esta tarea en vez de "revisa todo el proyecto" -- útil para pedir "corre QA de esto que acabo de hacer". Sin efecto en los pasos de script (lint/test/build corren igual siempre). Para kind="screenshots" es además OBLIGATORIO en la práctica: es la tarea a la que se van a adjuntar solas las capturas al terminar la corrida -- sin taskId, las capturas se suben pero nadie las liga a nada. No combinar con moduleId.'),
|
|
1696
1707
|
moduleId: z.string().optional().describe('Igual que taskId pero acota a un módulo completo. No combinar con taskId.'),
|
|
1697
1708
|
})
|
|
1698
1709
|
|