orquestra-mcp 1.18.1 → 1.18.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orquestra-mcp",
3
- "version": "1.18.1",
3
+ "version": "1.18.2",
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": {
package/src/api.mjs CHANGED
@@ -4,19 +4,23 @@ const DEFAULT_API_BASE = 'https://api.orquestra.me'
4
4
 
5
5
  export function loadConfig() {
6
6
  const fileConfig = readConfigFile()
7
- const apiBase = process.env.ORQUESTRA_API_BASE || fileConfig?.apiBase || DEFAULT_API_BASE
8
- const apiToken = process.env.ORQUESTRA_API_TOKEN || fileConfig?.apiToken
9
- const workspaceId = process.env.ORQUESTRA_WORKSPACE_ID || fileConfig?.workspaceId
7
+ // Todo sale de la MISMA carpeta mapeada (ver resolveProjectForCwd) --
8
+ // apiToken/workspaceId/projectId siempre son de una sola cuenta, nunca
9
+ // el token de una carpeta con el proyecto de otra.
10
+ const folderConfig = resolveProjectForCwd(fileConfig?.projects, process.cwd())
11
+
12
+ const apiBase = process.env.ORQUESTRA_API_BASE || folderConfig?.apiBase || DEFAULT_API_BASE
13
+ const apiToken = process.env.ORQUESTRA_API_TOKEN || folderConfig?.apiToken
14
+ const workspaceId = process.env.ORQUESTRA_WORKSPACE_ID || folderConfig?.workspaceId
10
15
 
11
16
  // ORQUESTRA_DEFAULT_PROJECT_ID (env var, ej. desde un MCP config con
12
17
  // scope local/project de Claude Code) siempre gana -- es una anulación
13
- // explícita. Si no hay env var, se busca en el mapa carpeta->proyecto del
14
- // config file, subiendo desde cwd (ver resolveProjectForCwd). Si ninguna
15
- // carpeta ancestro está mapeada, defaultProjectId queda undefined a
16
- // propósito -- resolveProjectId() en server.mjs debe fallar explícito en
17
- // vez de usar el proyecto de otra carpeta.
18
- const defaultProjectId = process.env.ORQUESTRA_DEFAULT_PROJECT_ID
19
- || resolveProjectForCwd(fileConfig?.projects, process.cwd())
18
+ // explícita. Si no hay env var, se usa el projectId de la carpeta
19
+ // resuelta arriba. Si ninguna carpeta ancestro está mapeada,
20
+ // defaultProjectId queda undefined a propósito -- resolveProjectId() en
21
+ // server.mjs debe fallar explícito en vez de usar el proyecto de otra
22
+ // carpeta.
23
+ const defaultProjectId = process.env.ORQUESTRA_DEFAULT_PROJECT_ID || folderConfig?.projectId
20
24
 
21
25
  const missing = []
22
26
  if (!apiToken) missing.push('ORQUESTRA_API_TOKEN')
@@ -4,13 +4,40 @@ import { join, dirname, sep } from 'path'
4
4
 
5
5
  export const CONFIG_PATH = join(homedir(), '.orquestra', 'mcp-config.json')
6
6
 
7
+ // Formato viejo (hasta v1.18.1): apiBase/apiToken/workspaceId GLOBALES a
8
+ // nivel raíz, projects={folderPath: projectId}. Eso pisaba la cuenta de
9
+ // TODAS las carpetas cada vez que corrías "setup" con una cuenta distinta
10
+ // -- no había forma real de tener un proyecto de una cuenta y otro de otra
11
+ // cuenta al mismo tiempo. Migra en el momento a projects={folderPath:
12
+ // {apiBase, apiToken, workspaceId, projectId}}, reusando las credenciales
13
+ // globales viejas para cada carpeta ya mapeada (siguen apuntando a la
14
+ // cuenta con la que se logueó por última vez -- si eso ya está mal, hay
15
+ // que volver a correr "setup" en esa carpeta puntual).
16
+ function migrateLegacyConfig(raw) {
17
+ const entries = Object.entries(raw.projects || {})
18
+ if (!entries.some(([, value]) => typeof value === 'string')) return raw
19
+
20
+ const { apiBase, apiToken, workspaceId } = raw
21
+ const projects = {}
22
+ for (const [folderPath, value] of entries) {
23
+ projects[folderPath] = typeof value === 'string'
24
+ ? { apiBase, apiToken, workspaceId, projectId: value }
25
+ : value
26
+ }
27
+ return { projects }
28
+ }
29
+
7
30
  export function readConfigFile() {
8
31
  if (!existsSync(CONFIG_PATH)) return null
32
+ let raw
9
33
  try {
10
- return JSON.parse(readFileSync(CONFIG_PATH, 'utf8'))
34
+ raw = JSON.parse(readFileSync(CONFIG_PATH, 'utf8'))
11
35
  } catch {
12
36
  return null
13
37
  }
38
+ const migrated = migrateLegacyConfig(raw)
39
+ if (migrated !== raw) writeConfigFile(migrated)
40
+ return migrated
14
41
  }
15
42
 
16
43
  export function writeConfigFile(data) {
@@ -18,21 +45,24 @@ export function writeConfigFile(data) {
18
45
  writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2), { mode: 0o600 })
19
46
  }
20
47
 
21
- // Guarda/actualiza el projectId de UNA carpeta sin pisar las demás -- setup
22
- // se puede correr varias veces, una por cada carpeta contenedora de repos
23
- // (ver resolveProjectForCwd), y cada corrida solo debe tocar su propia
24
- // entrada.
48
+ // Guarda/actualiza la cuenta+proyecto de UNA carpeta sin pisar las demás --
49
+ // setup se puede correr varias veces, una por cada carpeta contenedora de
50
+ // repos (ver resolveProjectForCwd), y cada corrida solo debe tocar su
51
+ // propia entrada -- incluida la cuenta (apiToken/workspaceId), para poder
52
+ // tener una carpeta en una cuenta de Orquestra y otra carpeta en otra
53
+ // cuenta distinta al mismo tiempo.
25
54
  export function upsertProjectMapping({ apiBase, apiToken, workspaceId, folderPath, projectId }) {
26
- const existing = readConfigFile() || {}
55
+ const existing = readConfigFile() || { projects: {} }
27
56
  const projects = { ...(existing.projects || {}) }
28
- projects[folderPath] = projectId
29
- writeConfigFile({ apiBase, apiToken, workspaceId, projects })
57
+ projects[folderPath] = { apiBase, apiToken, workspaceId, projectId }
58
+ writeConfigFile({ projects })
30
59
  }
31
60
 
32
61
  // Busca, subiendo desde cwd hacia la raíz, la carpeta mapeada más específica
33
62
  // -- mismo criterio que .editorconfig/.gitconfig: el ancestro más cercano
34
- // gana, así que un repo individual con su propio mapeo puede sobreescribir
35
- // el de la carpeta contenedora que lo engloba.
63
+ // gana, así que un repo individual con su propio mapeo (y su propia cuenta)
64
+ // puede sobreescribir el de la carpeta contenedora que lo engloba. Devuelve
65
+ // el objeto {apiBase, apiToken, workspaceId, projectId} de esa carpeta.
36
66
  export function resolveProjectForCwd(projects, cwd) {
37
67
  if (!projects) return undefined
38
68
  let best = null