orquestra-mcp 1.51.0 → 1.52.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.mjs +5 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orquestra-mcp",
3
- "version": "1.51.0",
3
+ "version": "1.52.1",
4
4
  "description": "Servidor MCP de Orquestra -- 135 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": {
package/src/server.mjs CHANGED
@@ -134,6 +134,7 @@ Durante el trabajo normal de código, sin que el usuario te lo pida explícitame
134
134
  - 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; cuando un commit o PR del repo de otra plataforma menciona el código de la tarea (ej. "(ORQ-123)"), el servidor propone solo una sugerencia scope_done_proposal (list_suggestions) para marcar esa plataforma como hecha: si la ves, confirma con el código real y acéptala con accept_suggestion en vez de editar el scope a mano. Si el trabajo de otra plataforma ya vive en OTRA tarea (una tarea gemela, ej. "[iOS] ..." y "[Android] ..."), no dupliques scope: liga la hermana con update_task parityOf=<id de la tarea origen> y en paridad cuentan como un solo item; al cerrar la hermana su plataforma queda hecha sola. 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.
135
135
  - 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.
136
136
  - 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í.
137
+ - Una tarea = UN entregable; un ítem del checklist = UN paso corto de ese entregable. Si el título junta varias cosas con comas o "y" ("X, Y y Z"), o un ítem del checklist tendría su propio deploy, commits, pruebas o alertas (es una integración/función entera, no un paso), son tareas separadas: créalas aparte en el mismo módulo (si son muchas del mismo tema, ese tema es un módulo, no una tarea con 14 ítems). Lo que depende de algo externo o futuro (un contrato, un proveedor, una versión que todavía no sale, la respuesta de una tienda) va en su propia tarea -- en Bloqueado o con reviewDate --, nunca dentro de una tarea que ya está lista, porque la deja abierta indefinidamente. El texto de un ítem es la acción ("Configurar cron diario de la CSL"), no la bitácora: commits, "probado en vivo", tiempos y tamaños van en un comment de la tarea, en resolvedCommitSha o en el changelog. Algo que ya no aplica no se deja como ítem pendiente con "ya no hace falta" en el texto: díselo al usuario y bórralo con delete_checklist_item (con un comment en la tarea explicando por qué). No reorganices tareas que ya existen así salvo que el usuario lo pida -- la regla es para lo nuevo.
137
138
  - 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.
138
139
  - No todas las tareas necesitan una corrida de QA -- clasifica antes de disparar una: cambios que afectan comportamiento real (features, bugs, UI, lógica de negocio, endpoints/API) sí la necesitan; cambios que no alteran comportamiento (docs, comentarios, refactors sin cambio funcional, config/tooling interno, notas/reuniones/ideas) no. Si decides que sí, revisa primero con list_agents que exista un agente (kind="qa") para el stack que tocaste (si no hay ninguno, créalo con create_agent -- necesita una máquina ya emparejada, ver Workspace → Máquinas) y llama a create_agent_run en la rama real de ese trabajo (manda taskId si el trabajo era de una tarea puntual -- si el agente tiene la revisión con IA activada, la acota a eso en vez de "revisa todo el proyecto"), dejando la tarea en "En revisión" -- NUNCA la muevas a "Listo" ni digas que "QA lo revisó" sin haber confirmado con get_agent_run un estatus terminal "passed" de verdad (las corridas son asíncronas, tardan minutos en otra máquina). Si tarda, dile al usuario que quedó en cola (con el runId) y que confirmas cuando termine -- no lo des por hecho nunca.
139
140
 
@@ -759,7 +760,7 @@ export function createServer() {
759
760
  registerCreate(
760
761
  'create_task',
761
762
  '/v1/tasks',
762
- 'Crea una tarea en un proyecto de Orquestra. moduleId y dueDate son OBLIGATORIOS -- revisa list_modules primero (si ninguno aplica, creá uno con create_module antes de crear la tarea, nunca la dejes sin agrupar); dueDate se calcula con criterio real (prioridad/tamaño del trabajo), nunca un valor arbitrario. Una reunión, llamada o seguimiento NO es tarea: usa log_activity (type "business" sí es tarea: entregable no-código).',
763
+ 'Crea una tarea en un proyecto de Orquestra. moduleId y dueDate son OBLIGATORIOS -- revisa list_modules primero (si ninguno aplica, creá uno con create_module antes de crear la tarea, nunca la dejes sin agrupar); dueDate se calcula con criterio real (prioridad/tamaño del trabajo), nunca un valor arbitrario. Una reunión, llamada o seguimiento NO es tarea: usa log_activity (type "business" sí es tarea: entregable no-código). Una tarea = UN entregable: si el título junta varias cosas con comas o "y", crea una tarea por cada una (mismo módulo); lo que espera algo externo o futuro va en su propia tarea, no dentro de otra.',
763
764
  {
764
765
  relatedTo: RELATED_TO,
765
766
  title: z.string().describe('Título de la tarea'),
@@ -1588,7 +1589,7 @@ export function createServer() {
1588
1589
  server.registerTool(
1589
1590
  'add_checklist_item',
1590
1591
  {
1591
- description: 'Agrega un ítem al checklist de una tarea de Orquestra, opcionalmente con un responsable.',
1592
+ description: 'Agrega un ítem al checklist de una tarea de Orquestra, opcionalmente con un responsable. Un ítem es UN paso corto del entregable de la tarea, escrito como acción. Si lleva su propio deploy, commits, pruebas o alertas, o depende de algo externo (contrato, proveedor, versión futura), es una tarea aparte (create_task), no un ítem. Commits y "probado en vivo" van en un comment de la tarea, no en el texto del ítem.',
1592
1593
  inputSchema: {
1593
1594
  projectId: z.string().optional().describe(PROJECT_ID_DESC),
1594
1595
  taskId: z.string().describe('ID de la tarea'),
@@ -2748,9 +2749,9 @@ export function createServer() {
2748
2749
  translationOf: z.string().optional().describe('Si esta pieza es una traducción, id del content original'),
2749
2750
  })
2750
2751
 
2751
- registerUpdate('update_content', '/v1/content', 'Edita una pieza de contenido existente. Al pasar status a "approved" o "published" el server estampa quién/cuándo solo -- no lo mandes tú (mismo estampado por variante si mandás channels[]). Para patchear un solo canal de una pieza multi-canal, mandá el array `channels` COMPLETO con esa variante modificada -- Firestore no puede editar un campo adentro de un elemento de array, así que reemplaza el array entero.', {
2752
+ registerUpdate('update_content', '/v1/content', 'Edita una pieza de contenido existente. Al pasar status a "approved" o "published" el server estampa quién/cuándo solo -- no lo mandes tú (mismo estampado por variante si mandás channels[]). Para patchear un solo canal de una pieza multi-canal, mandá el array `channels` con TODAS las variantes (la que falte se quita de la pieza); dentro de cada variante basta con channelId + lo que cambia -- el server mezcla con la variante guardada y conserva lo que no mandes (mediaFiles, externalGuid, approvedAt...). Para vaciar un campo mandalo explícito (null o []).', {
2752
2753
  channelId: z.string().optional(),
2753
- channels: z.array(CONTENT_VARIANT_SCHEMA).optional().describe('Reemplaza el array de variantes completo -- mandá TODAS las variantes (las que cambian y las que no), no solo la que estás editando.'),
2754
+ channels: z.array(CONTENT_VARIANT_SCHEMA).optional().describe('Array de variantes completo -- mandá TODAS (la que falte se quita). Cada una se mezcla con la guardada por channelId: lo que no mandes (mediaFiles, externalGuid...) se conserva.'),
2754
2755
  title: z.string().optional(),
2755
2756
  format: z.string().optional(),
2756
2757
  status: z.enum(CONTENT_STATUSES).optional(),