orquestra-mcp 1.29.0 → 1.31.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/package.json +1 -1
- package/src/server.mjs +42 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orquestra-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.0",
|
|
4
4
|
"description": "Servidor MCP de Orquestra -- 115 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
|
@@ -301,9 +301,9 @@ export function createServer() {
|
|
|
301
301
|
registerRead(
|
|
302
302
|
'get_parity_summary',
|
|
303
303
|
'/v1/parity',
|
|
304
|
-
'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.',
|
|
304
|
+
'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. Solo cuentan tareas de producto: se excluyen bugs, tareas fusionadas, canceladas/archivadas y las marcadas parityExempt; las candidatas a portar son solo feature/improvement/design (nunca módulos). Un gap es una señal, no un veredicto: el done por plataforma es un flag manual y el trabajo móvil suele existir ya bajo otra tarea -- verifica en el código real de esa plataforma antes de decir que falta algo o de crear una tarea. La respuesta viene compacta: el detalle de gapItems/singleDoneItems está en combined; tasks y modules solo traen totales.',
|
|
305
305
|
{},
|
|
306
|
-
(args, projectId) => ({ projectId })
|
|
306
|
+
(args, projectId) => ({ projectId, compact: '1' })
|
|
307
307
|
)
|
|
308
308
|
|
|
309
309
|
registerRead(
|
|
@@ -1224,7 +1224,7 @@ export function createServer() {
|
|
|
1224
1224
|
server.registerTool(
|
|
1225
1225
|
'add_attachment',
|
|
1226
1226
|
{
|
|
1227
|
-
description: 'Adjunta evidencia (una imagen, un video o un pedazo de código) a una task/note/idea/doc/content de Orquestra. Manda EXACTAMENTE uno de filePath (ruta local -- una imagen png/jpg/jpeg/gif/webp o un video mp4/mov/webm se sube a S3, cualquier otra extensión se lee como texto/código) o content (texto/código directo, sin tocar el filesystem). Nunca mandes bytes de imagen/video en base64 dentro de content -- usa filePath para que este server los suba él mismo.',
|
|
1227
|
+
description: 'Adjunta evidencia (una imagen, un video o un pedazo de código) a una task/note/idea/doc/content de Orquestra. OJO: en una pieza de Contenido esto NO la deja como media (no se ve ni se publica) -- para eso usa add_content_media. Manda EXACTAMENTE uno de filePath (ruta local -- una imagen png/jpg/jpeg/gif/webp o un video mp4/mov/webm se sube a S3, cualquier otra extensión se lee como texto/código) o content (texto/código directo, sin tocar el filesystem). Nunca mandes bytes de imagen/video en base64 dentro de content -- usa filePath para que este server los suba él mismo.',
|
|
1228
1228
|
inputSchema: {
|
|
1229
1229
|
projectId: z.string().optional().describe(PROJECT_ID_DESC),
|
|
1230
1230
|
entityType: z.enum(ATTACHMENT_ENTITY_TYPES).describe('Tipo de entidad a la que se adjunta'),
|
|
@@ -1286,6 +1286,45 @@ export function createServer() {
|
|
|
1286
1286
|
}
|
|
1287
1287
|
)
|
|
1288
1288
|
|
|
1289
|
+
// Media de una pieza de Contenido (ORQ-283) -- distinto de add_attachment:
|
|
1290
|
+
// un adjunto es evidencia privada, esto es el mediaFiles que Contenido
|
|
1291
|
+
// muestra y Postproxy publica. Mismo criterio de bytes: este server lee el
|
|
1292
|
+
// archivo y lo sube él mismo, nunca base64 por el input.
|
|
1293
|
+
server.registerTool(
|
|
1294
|
+
'add_content_media',
|
|
1295
|
+
{
|
|
1296
|
+
description: 'Pone una imagen o video como MEDIA de una pieza de Contenido (lo que se ve en la pieza y lo que se publica en redes) -- usa esto y NO add_attachment para contenido; add_attachment solo guarda evidencia privada que Contenido no muestra. Sube el archivo local (png/jpg/jpeg/gif/webp/mp4/mov/webm) y lo agrega al mediaFiles sin pisar el que ya haya. Sin channelId lo agrega a todos los canales de la pieza; con channelId solo a esa variante.',
|
|
1297
|
+
inputSchema: {
|
|
1298
|
+
projectId: z.string().optional().describe(PROJECT_ID_DESC),
|
|
1299
|
+
contentId: z.string().describe('ID de la pieza (list_content)'),
|
|
1300
|
+
filePath: z.string().describe('Ruta local a la imagen o video'),
|
|
1301
|
+
channelId: z.string().optional().describe('Solo si quieres el archivo en un canal específico de una pieza multi-canal'),
|
|
1302
|
+
fileName: z.string().optional().describe('Nombre a mostrar -- default: el del archivo'),
|
|
1303
|
+
},
|
|
1304
|
+
},
|
|
1305
|
+
async ({ projectId, contentId, filePath, channelId, fileName }) => {
|
|
1306
|
+
try {
|
|
1307
|
+
const resolvedProjectId = resolveProjectId(projectId)
|
|
1308
|
+
const stat = statSync(filePath)
|
|
1309
|
+
const ext = path.extname(filePath).slice(1).toLowerCase()
|
|
1310
|
+
const mime = ATTACHMENT_IMAGE_MIME_BY_EXT[ext] || ATTACHMENT_VIDEO_MIME_BY_EXT[ext]
|
|
1311
|
+
if (!mime) throw new Error('Solo imágenes (png/jpg/jpeg/gif/webp) o videos (mp4/mov/webm)')
|
|
1312
|
+
if (stat.size > MAX_ATTACHMENT_VIDEO_BYTES) throw new Error(`El archivo supera el máximo de ${MAX_ATTACHMENT_VIDEO_BYTES / 1024 / 1024}MB`)
|
|
1313
|
+
const name = fileName || path.basename(filePath)
|
|
1314
|
+
const { uploadUrl, key } = await apiPost(config, '/v1/content/media-upload-url', {
|
|
1315
|
+
projectId: resolvedProjectId, fileName: name, fileType: mime, fileSize: stat.size,
|
|
1316
|
+
})
|
|
1317
|
+
await putToPresignedUrl(uploadUrl, readFileSync(filePath), mime)
|
|
1318
|
+
const data = await apiPost(config, `/v1/content/${contentId}/media`, {
|
|
1319
|
+
projectId: resolvedProjectId, key, name, type: mime, size: stat.size, ...(channelId ? { channelId } : {}),
|
|
1320
|
+
})
|
|
1321
|
+
return textResult(data)
|
|
1322
|
+
} catch (err) {
|
|
1323
|
+
return errorResult(err)
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
)
|
|
1327
|
+
|
|
1289
1328
|
// Segunda excepción real a "creación + edición, nunca borrado" (junto a
|
|
1290
1329
|
// delete_checklist_item, ver CLAUDE.md) -- decisión consciente de José:
|
|
1291
1330
|
// un agente puede subir evidencia equivocada (screenshot que no era,
|