mcp-phase-gate 2.1.0 → 2.2.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 CHANGED
@@ -72,7 +72,7 @@ DOCUMENTATION/
72
72
  └── <task_name>/
73
73
  ```
74
74
 
75
- The `Proyectos` level is the tasks subfolder, and its name is configurable — see `ORQUESTADOR_TASKS_SUBDIR` below. The document names come from the phase prompts, which is why they are in Spanish by default.
75
+ The `Proyectos` level is the tasks subfolder, and its name is configurable — see `PHASE_GATE_TASKS_SUBDIR` below. The document names come from the phase prompts, which is why they are in Spanish by default.
76
76
 
77
77
  **Batches and receipts.** The phase 3 plan splits the work into batches (`L01`, `L02`…): each one is a change that can be reverted on its own and leaves the application working. Phase 4 runs them one at a time and closes each batch with a short **receipt** (what was done, what was verified, what is waiting for you) and a commit. With a single batch, the receipt is `04 - Ejecución.md` itself and there is no subfolder, unless that batch fails or is discarded: then its receipt goes in `04 - Ejecución/` and the phase isn't marked as closed. With several, the receipts go in `04 - Ejecución/` and `04 - Ejecución.md` is the index written when the last one closes: until then the phase doesn't show as finished. When you ask for phase 4 or 5, the server appends the list of existing receipts to the prompt, so a new chat can pick up without guessing their names.
78
78
 
@@ -101,7 +101,7 @@ The code is identical everywhere; the only thing that changes between machines i
101
101
 
102
102
  Nothing to install: `npx` fetches the package the first time and caches it. Everything is configured in your MCP client's file.
103
103
 
104
- **The key you give it is what identifies the server and prefixes its tools**, so you can name it whatever you like. The examples use `mcp-phase-gate`, the same as the npm package and the name the server reports for itself — one name in all three places, so there's nothing to remember.
104
+ **The key you give it is what identifies the server and prefixes its tools and commands**, so you can name it whatever you like. The examples use `mcp-phase-gate`, the same as the npm package and the name the server reports for itself. If you're registering it for the first time, a short key such as `pg` keeps the commands short (`/pg:f1` in Claude Code). **If it's already registered, keep your key**: changing it renames every tool and command, and you'd have to grant their permissions again.
105
105
 
106
106
  Remember that in JSON every `\` must be doubled as `\\`.
107
107
 
@@ -115,8 +115,8 @@ Remember that in JSON every `\` must be doubled as `\\`.
115
115
  "command": "npx",
116
116
  "args": ["-y", "mcp-phase-gate"],
117
117
  "env": {
118
- "ORQUESTADOR_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
119
- "ORQUESTADOR_REPOS_PATH": "C:\\projects"
118
+ "PHASE_GATE_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
119
+ "PHASE_GATE_REPOS_PATH": "C:\\projects"
120
120
  }
121
121
  }
122
122
  }
@@ -137,8 +137,8 @@ Two differences to watch: the top-level key is `servers`, not `mcpServers`, and
137
137
  "command": "npx",
138
138
  "args": ["-y", "mcp-phase-gate"],
139
139
  "env": {
140
- "ORQUESTADOR_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
141
- "ORQUESTADOR_REPOS_PATH": "C:\\projects"
140
+ "PHASE_GATE_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
141
+ "PHASE_GATE_REPOS_PATH": "C:\\projects"
142
142
  }
143
143
  }
144
144
  }
@@ -150,19 +150,21 @@ Two differences to watch: the top-level key is `servers`, not `mcpServers`, and
150
150
  <summary><b>Claude Code</b> — one line</summary>
151
151
 
152
152
  ```bash
153
- claude mcp add mcp-phase-gate --env ORQUESTADOR_DOCS_PATH="C:\Users\YOUR_USER\Documents\DOCUMENTATION" --env ORQUESTADOR_REPOS_PATH="C:\projects" -- npx -y mcp-phase-gate
153
+ claude mcp add mcp-phase-gate --env PHASE_GATE_DOCS_PATH="C:\Users\YOUR_USER\Documents\DOCUMENTATION" --env PHASE_GATE_REPOS_PATH="C:\projects" -- npx -y mcp-phase-gate
154
154
  ```
155
155
 
156
156
  Or by hand, in a `.mcp.json` at the project root, shaped like the Cursor one.
157
157
  </details>
158
158
 
159
- That `ORQUESTADOR_DOCS_PATH` is only an **example** using a OneDrive folder. `G:\My Drive\Documentation`, `D:\Dropbox\Docs` or plain `C:\Docs` with no cloud at all work just as well.
159
+ That `PHASE_GATE_DOCS_PATH` is only an **example** using a OneDrive folder. `G:\My Drive\Documentation`, `D:\Dropbox\Docs` or plain `C:\Docs` with no cloud at all work just as well.
160
160
 
161
161
  > **There is no `.env` on this route.** The package lives inside `node_modules`, which is no place to keep your configuration, so the paths go in the `"env"` block — that's the only option here. The `.env` file only exists on the route below.
162
162
 
163
163
  **Both variables are required and have no default value.** If one is missing, or points at a folder that doesn't exist, the tools that need it say so by name instead of failing later for some unrelated-looking reason.
164
164
 
165
- > Typing `npx mcp-phase-gate` straight into a terminal **looks like it hangs**, and nothing is broken: it's an MCP server waiting for messages on stdin. If you just want to check it's there, run `npx mcp-phase-gate --help`.
165
+ > **Already using it with `ORQUESTADOR_*`?** Those names keep working as aliases of `PHASE_GATE_*`; there's nothing to change. If you define both with different values, `PHASE_GATE_*` wins, and `doctor` and the server log tell you.
166
+
167
+ > Typing `npx mcp-phase-gate` straight into a terminal **looks like it hangs**, and nothing is broken: it's an MCP server waiting for messages on stdin. If you want to check your setup, run `npx mcp-phase-gate doctor` ([see below](#-check-your-setup-doctor)).
166
168
 
167
169
  ---
168
170
 
@@ -188,11 +190,11 @@ cp .env.example .env
188
190
  Single backslashes on Windows, no quotes:
189
191
 
190
192
  ```ini
191
- ORQUESTADOR_DOCS_PATH=C:\Users\YOUR_USER\OneDrive - YOUR ORGANISATION\Documents\DOCUMENTATION
192
- ORQUESTADOR_REPOS_PATH=C:\projects
193
+ PHASE_GATE_DOCS_PATH=C:\Users\YOUR_USER\OneDrive - YOUR ORGANISATION\Documents\DOCUMENTATION
194
+ PHASE_GATE_REPOS_PATH=C:\projects
193
195
  ```
194
196
 
195
- > On Windows, save `.env` as **UTF-8 without BOM**. Creating it from PowerShell with `>` produces UTF-16, accented characters arrive mangled, and the path "doesn't exist" even though it looks right.
197
+ > Save `.env` as **UTF-8** (with or without BOM, either works). Creating it from PowerShell with `>` produces UTF-16: the server detects it, doesn't load it, and tells you so — both in the missing-variable error and in `doctor`.
196
198
 
197
199
  **3. Register the server** as in route A, but swapping `command` and `args` for your clone's `build/index.js`, and dropping the `"env"` block (the paths come from `.env` now):
198
200
 
@@ -209,8 +211,20 @@ In **Claude Code**, a `.mcp.json` at this repo's root can use a **relative** pat
209
211
 
210
212
  ### ✅ Verify it works
211
213
  1. Restart the client, or toggle the server off and on in its MCP panel.
212
- 2. It should show up active with its 8 tools. In **Cursor** that's Settings → MCP; in **VS Code**, the extensions/MCP view; in **Claude Code**, `/mcp`.
213
- 3. Try it from the chat: *"Use the `get_active_task` tool from mcp-phase-gate"* — it should answer, even if only to say there's no active task yet.
214
+ 2. It should show up active with its 9 tools. In **Cursor** that's Settings → MCP; in **VS Code**, the extensions/MCP view; in **Claude Code**, `/mcp`.
215
+ 3. Try it from the chat: *"Use the `get_orchestrator_status` tool from mcp-phase-gate"* — it returns an X-ray of the installation: which variables it sees, which prompts it uses and which projects it finds.
216
+
217
+ ### 🔍 Check your setup: `doctor`
218
+
219
+ From a terminal, with the same variables you give the client:
220
+
221
+ ```bash
222
+ npx mcp-phase-gate doctor
223
+ ```
224
+
225
+ It tells you which version is running and from where (`npx`, global, a dependency or a clone), the value of each variable and where it came from (the environment or `.env`, and whether you used the new name or the alias), which prompt file wins for each phase, which projects exist with their active task, and a list of findings: a missing required variable, a UTF-16 `.env`, a custom `global-rules.md` missing sections the phases cite, a phase with no document… It exits with code `1` if there's any error, so it also works in a script. `doctor --json` gives the same thing as JSON.
226
+
227
+ It's the same information returned by the `get_orchestrator_status` tool and the `phase-gate://estado` resource; from the chat, it also includes which client is connected and which capabilities it announced.
214
228
 
215
229
  ---
216
230
 
@@ -238,23 +252,23 @@ You may want separate documentation sets that never mix — one for work and one
238
252
  ```jsonc
239
253
  {
240
254
  "mcpServers": {
241
- "orquestador-work": {
255
+ "pg-work": {
242
256
  "command": "npx",
243
257
  "args": ["-y", "mcp-phase-gate"],
244
258
  "env": {
245
- "ORQUESTADOR_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
246
- "ORQUESTADOR_REPOS_PATH": "C:\\projects",
247
- "ORQUESTADOR_STATE_PATH": "C:\\Users\\YOUR_USER\\.orquestador\\work"
259
+ "PHASE_GATE_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
260
+ "PHASE_GATE_REPOS_PATH": "C:\\projects",
261
+ "PHASE_GATE_STATE_PATH": "C:\\Users\\YOUR_USER\\.orquestador\\work"
248
262
  }
249
263
  },
250
- "orquestador-personal": {
264
+ "pg-personal": {
251
265
  "command": "npx",
252
266
  "args": ["-y", "mcp-phase-gate"],
253
267
  "env": {
254
- "ORQUESTADOR_DOCS_PATH": "G:\\My Drive\\Documentation",
255
- "ORQUESTADOR_REPOS_PATH": "D:\\dev",
256
- "ORQUESTADOR_TASKS_SUBDIR": "",
257
- "ORQUESTADOR_STATE_PATH": "C:\\Users\\YOUR_USER\\.orquestador\\personal"
268
+ "PHASE_GATE_DOCS_PATH": "G:\\My Drive\\Documentation",
269
+ "PHASE_GATE_REPOS_PATH": "D:\\dev",
270
+ "PHASE_GATE_TASKS_SUBDIR": "",
271
+ "PHASE_GATE_STATE_PATH": "C:\\Users\\YOUR_USER\\.orquestador\\personal"
258
272
  }
259
273
  }
260
274
  }
@@ -263,12 +277,12 @@ You may want separate documentation sets that never mix — one for work and one
263
277
 
264
278
  It's the same package in both — only the paths differ. Each registration can even have its own tasks subfolder; above, the personal one leaves it empty so tasks hang directly off the project.
265
279
 
266
- > ⚠️ **`ORQUESTADOR_STATE_PATH` must differ between registrations.** Share it and the active-task pointers clobber each other **silently**: the state is keyed by project name, so two documentation roots holding a project with the same name end up sharing one entry, and one answers for the other. No error is raised — you just get the wrong task back.
280
+ > ⚠️ **`PHASE_GATE_STATE_PATH` must differ between registrations.** Share it and the active-task pointers clobber each other **silently**: the state is keyed by project name, so two documentation roots holding a project with the same name end up sharing one entry, and one answers for the other. No error is raised — you just get the wrong task back.
267
281
 
268
282
  Two more things that bite and aren't obvious:
269
283
 
270
284
  - **Mirror mode, not streaming.** Google Drive in *streaming* mode and OneDrive with *Files On-Demand* leave files as placeholders until something opens them. This server lives on listing folders and checking whether files exist, so placeholders make it slow, or make it fail with no network. Keep the documentation folder **downloaded locally** if you can.
271
- - **Keep code repos out of the synced folder.** Documentation in the cloud is fine. Code isn't: sync competing with git over `.git/` corrupts repositories. Point `ORQUESTADOR_REPOS_PATH` at a local disk.
285
+ - **Keep code repos out of the synced folder.** Documentation in the cloud is fine. Code isn't: sync competing with git over `.git/` corrupts repositories. Point `PHASE_GATE_REPOS_PATH` at a local disk.
272
286
 
273
287
  ---
274
288
 
@@ -281,7 +295,7 @@ Two more things that bite and aren't obvious:
281
295
  | The compiled server | `build/` in your clone | It's gitignored. **After every `git pull` that touches `src/`, run `npm run build`** or the client keeps executing the previous version. |
282
296
  | This machine's paths | `.env` at the root ([route B](#-route-b--from-source), step 2) | The system user and the documentation folder differ per machine. |
283
297
  | The MCP registration | Your client's config ([route A](#-route-a--with-npx-recommended), or step 3 of [route B](#-route-b--from-source)) | In Cursor and VS Code it holds the absolute path to `build/index.js`, which depends on where you cloned and points into a gitignored folder. No single path can be right on every machine. See [`docs/decisiones.md`](docs/decisiones.md). The exception is Claude Code's `.mcp.json`, which uses a relative path. |
284
- | The `/f1`–`/f5` commands in **Cursor** | `~/.cursor/commands/f<N>.md` | Cursor only reads them from the user folder, so they're copied by hand on each machine. Not an issue in **Claude Code**: they're versioned in `.claude/commands/` and arrive with the pull. |
298
+ | The `/f1`–`/f5` commands as files, **only if your client doesn't show MCP Prompts well** | `~/.cursor/commands/f<N>.md` in Cursor | Since 2.2.0 the server offers them as MCP Prompts and they arrive with every version ([see below](#the-phase-commands)). The file copy is only a fallback; in **Claude Code** inside this repo it's already versioned in `.claude/commands/`. |
285
299
 
286
300
  ### The phase commands
287
301
 
@@ -297,15 +311,19 @@ You invoke them by typing `/f1`, `/f2`, etc. in the chat. **They are orchestrati
297
311
 
298
312
  No command names a file: the name is declared in each phase prompt's header and `get_phase_prompt` hands it to the model.
299
313
 
300
- `/f1` expects data after the command: project, task_name and the full requirement. `/f5` accepts a commit range; without one it audits the commits recorded in the phase 4 receipts, and only asks if there are no receipts. The rest start from `get_active_task`.
314
+ `/f1` needs project, task_name and the full requirement. `/f5` accepts a commit range; without one it audits the commits recorded in the phase 4 receipts, and only asks if there are no receipts. The rest start from `get_active_task`.
301
315
 
302
- **Where to put them, per client:**
316
+ **They arrive on their own, as MCP Prompts.** Since 2.2.0 the server offers each command as an MCP prompt (`f1`…`f5`), with its text in [`prompts/comandos/`](prompts/comandos). Nothing to copy into any folder, and they update with every package version. All their arguments are optional — `project`; in `/f1` also `task_name` and `contexto`; in `/f5`, `commits` —: whatever you don't pass, the command asks for, and a long context can be pasted after the command as plain chat text. A phase you add yourself (a `fase-6`) gets its own `/f6` with a generic text, and a `comandos/fN.md` in your own prompts folder wins over the packaged one.
303
317
 
304
- - **Claude Code:** already in [`.claude/commands/`](.claude/commands), versioned. They work when you open this repo, no setup. To use them from your other projects, copy them to `~/.claude/commands/`.
305
- - **Cursor:** copy them to `~/.cursor/commands/`. From there they work across all your projects.
306
- - **VS Code:** no slash commands of its own; paste the file contents into the chat.
318
+ How they look in each client:
307
319
 
308
- The exact contents of all five are also in [`docs/comandos-de-fase.md`](docs/comandos-de-fase.md) (Spanish).
320
+ | Client | `/f1`…`/f5` visible | Arguments with spaces | `@` resources | Direct confirmations | Notes |
321
+ |--------|---------------------|-----------------------|---------------|----------------------|-------|
322
+ | Claude Code | To be verified (per its docs: `/<key>:f1 (MCP)`, with `/mcp__<key>__f1` as an alias) | To be verified | To be verified | To be verified | |
323
+ | Cursor | To be verified (per its docs: in the MCP prompts menu) | To be verified | To be verified | To be verified | On Windows, `PHASE_GATE_ELICITATION=off` while the form bug stays open ([see below](#-protected-documents)) |
324
+ | VS Code | To be verified (its docs contradict themselves between `/<key>.f1` and `mcp.<key>.f1`) | To be verified | To be verified | To be verified | |
325
+
326
+ **If your client doesn't show them comfortably**, use the files: in this repo, Claude Code already reads them from [`.claude/commands/`](.claude/commands) (identical to `prompts/comandos/`); to use them in your other projects, copy them to `~/.claude/commands/`, or to `~/.cursor/commands/` in Cursor. More detail in [`docs/comandos-de-fase.md`](docs/comandos-de-fase.md) (Spanish).
309
327
 
310
328
  ---
311
329
 
@@ -332,6 +350,8 @@ Three things it deliberately does **not** do:
332
350
  - **It doesn't make you type anything extra.** You still type `/f4` and nothing else. Working out which task you mean is the server's job, using the pointer it already keeps — not the model asking you.
333
351
  - **It doesn't go quiet when it can't check.** If several projects have an active task and none was named, it says so instead of pretending everything is in order.
334
352
 
353
+ **It also flags what the previous phase left open.** If the previous phase's document has a `## Validaciones pendientes` section with something in it, or if, when asking for phase 5, some batch receipt ended up `con pendientes`, `fallido` or `descartado`, the prompt also arrives with a `## PENDIENTES HEREDADOS (detectados por el servidor)` block naming them, so the AI tells you before starting. A section that only says "Ninguna." doesn't count. It doesn't block anything either: it only points at what the prompt already required writing.
354
+
335
355
  ---
336
356
 
337
357
  ## 🔒 Protected documents
@@ -341,7 +361,16 @@ Each phase works on top of the previous phases' documents, so rewriting one that
341
361
  - **The initial context** (`00 - Contexto Inicial.md`), always, even to create it. Only `start_task` writes it without `force`.
342
362
  - **The document of a frozen phase.** A phase freezes as soon as a later phase's document exists, or as soon as phase 4 has any receipt in `04 - Ejecución/`. Receipts count as phase 4: they and `04 - Ejecución.md` are frozen only by phase 5.
343
363
 
344
- Creating a phase document that doesn't exist yet is never refused; a new receipt is, once phase 5 is present. Names are compared ignoring case and in the same Unicode form, so spelling them differently doesn't get around the protection. If a legitimate fix is needed — a typo in the analysis when the decisions are already written — the refusal message explains how to ask for it: the AI only uses `force` with your explicit confirmation in the chat, and the response warns that the document was overwritten (or created, if it didn't exist).
364
+ Creating a phase document that doesn't exist yet is never refused; a new receipt is, once phase 5 is present. Names are compared ignoring case and in the same Unicode form, so spelling them differently doesn't get around the protection.
365
+
366
+ **If a legitimate fix is needed** — a typo in the analysis when the decisions are already written — it depends on your client:
367
+
368
+ - **If your client supports direct confirmations** (MCP elicitation), the server **asks you**, in a form in your client with one checkbox: "Reescribir `01 - Análisis Técnico.md`". Tick it and accept, and it's written, with the response saying it was with your confirmation; say no or close the form, and nothing is written. Here `force` isn't enough: the AI sets it, and that's exactly what the question avoids.
369
+ - **If it doesn't**, it works as before: the refusal tells the AI it needs your explicit confirmation in the chat and `force: true`, and the response warns that the document was overwritten (or created, if it didn't exist).
370
+
371
+ The same goes for **starting a new project** with `crear_proyecto: true`: with direct confirmations, the server asks you before creating the folder.
372
+
373
+ If your client announces direct confirmations but the form never shows up, the server waits three minutes and writes nothing; the second time in a row it doesn't write either (even if the AI set `force`) and stops asking for the rest of the session: from then on `force` decides again, with your confirmation in the chat. If your client cancels the call before you answer, nothing is written. To avoid this from the start, register the server with `PHASE_GATE_ELICITATION=off`. **On Cursor for Windows, `off` is recommended** while the bug where the form doesn't appear stays open.
345
374
 
346
375
  On top of that, `write_central_doc` only writes **inside the folder of a task that already exists**: it doesn't create stray folders in the documentation.
347
376
 
@@ -351,18 +380,34 @@ On top of that, `write_central_doc` only writes **inside the folder of a task th
351
380
 
352
381
  | Tool | What it does |
353
382
  |------|--------------|
354
- | `start_task` | Creates the folder for a **new** task (`<PROJECT>/<tasks subfolder>/<task>`), saves the initial context and makes it the **active task of its project**. If the task already exists it refuses and points you at `switch_task`, so the initial context is never overwritten. |
383
+ | `start_task` | Creates the folder for a **new** task (`<PROJECT>/<tasks subfolder>/<task>`), saves the initial context and makes it the **active task of its project**. If the task already exists it refuses and points you at `switch_task`, so the initial context is never overwritten. Starting a new project takes `crear_proyecto: true` and, if your client can, your direct confirmation. |
355
384
  | `get_active_task` | Returns the active task and **which phase it's on**, derived from the documents it already has. Without `project` it answers for every project. Use it when opening a new chat or after losing track. |
356
385
  | `list_tasks` | Lists the tasks that exist and each one's phase, most recently touched first. For picking up something old or seeing what was left half-done. |
357
386
  | `switch_task` | Changes which task is active for a project. **Touches no files**: it's the correct way to resume an existing task. |
358
- | `get_phase_prompt` | Returns the behaviour rules for a phase (1–5), with the global rules prepended and the exact document filenames appended. The text lives in `prompts/`. It also checks the **gate**: pass `project` and, if you skipped a phase, the prompt arrives with the warning on top. |
387
+ | `get_phase_prompt` | Returns the behaviour rules for a phase (1–5), with the global rules prepended and the exact document filenames appended. The text lives in `prompts/`. It also checks the **gate**: pass `project` and, if you skipped a phase, the prompt arrives with the warning on top, followed by the inherited pending items if there are any. |
359
388
  | `read_central_doc` | Reads a file from the central documentation. **Recommended:** pass `project` + `task_name` + `file_name` and let the server build the path. It also accepts a relative `file_path`. |
360
- | `write_central_doc` | Writes/overwrites a file inside a task folder. Same parameters as `read_central_doc` plus `content`, and `force` for [protected documents](#-protected-documents). |
389
+ | `write_central_doc` | Writes/overwrites a file inside a task folder. Same parameters as `read_central_doc` plus `content`, and `force` for [protected documents](#-protected-documents) when your client doesn't support direct confirmations. |
361
390
  | `read_cross_repo` | Reads files from your other local repos, so you can check how another codebase solved something without switching windows. |
391
+ | `get_orchestrator_status` | The installation X-ray, same as [`doctor`](#-check-your-setup-doctor): package version and path, variables and where each came from, which prompt wins per phase, projects with their active task, and findings. Plus the connected client and its capabilities. Use it when something doesn't behave as you expect. |
392
+
393
+ They all declare their MCP annotations (read-only, destructive, idempotent), so a cautious client can let the read-only ones through without asking. Only `write_central_doc` is destructive.
394
+
395
+ ### `phase-gate://` resources
396
+
397
+ The server also exposes the documents as **read-only resources**, which compatible clients show when you type `@` in the chat, to attach them without asking the AI:
398
+
399
+ | Resource | What it is |
400
+ |----------|------------|
401
+ | `phase-gate://estado` | The `doctor` X-ray, in Markdown |
402
+ | `phase-gate://fases` | The available phases, with their document, receipts, and which prompt file wins |
403
+ | `phase-gate://tareas/{proyecto}/{tarea}/{documento}` | A task document |
404
+ | `phase-gate://tareas/{proyecto}/{tarea}/recibos/{recibo}` | A phase 4 batch receipt |
405
+
406
+ The list only includes the existing documents of **each project's active task**, so the picker doesn't drown; the rest is reachable through the template, which autocompletes project, task and document. They have the same defences as `read_central_doc`: they can't leave the task folder, don't expose dot-files, and don't read more than 1 MB.
362
407
 
363
408
  ### How the server builds paths
364
- - **Documentation:** `ORQUESTADOR_DOCS_PATH` / `<PROJECT>` / `ORQUESTADOR_TASKS_SUBDIR` / `<task>` / `<file>`
365
- - **Code repos:** `ORQUESTADOR_REPOS_PATH` / `<repo>` / `<file>`
409
+ - **Documentation:** `PHASE_GATE_DOCS_PATH` / `<PROJECT>` / `PHASE_GATE_TASKS_SUBDIR` / `<task>` / `<file>`
410
+ - **Code repos:** `PHASE_GATE_REPOS_PATH` / `<repo>` / `<file>`
366
411
 
367
412
  ### What counts as a project
368
413
 
@@ -370,7 +415,7 @@ There is no list of projects to maintain. **A project is any folder that contain
370
415
 
371
416
  A project that doesn't exist is rejected, showing the list of the ones that do, instead of silently creating a stray folder. To **start** a brand new project you have to ask on purpose: `start_task` accepts `crear_proyecto: true`, and without that flag a typo can't pollute your documentation.
372
417
 
373
- > If you leave `ORQUESTADOR_TASKS_SUBDIR` empty, the rule can't be applied and **any** folder counts as a project.
418
+ > If you leave `PHASE_GATE_TASKS_SUBDIR` empty, the rule can't be applied and **any** folder counts as a project.
374
419
 
375
420
  ---
376
421
 
@@ -385,7 +430,10 @@ prompts/
385
430
  ├── fase-2-decisiones.md
386
431
  ├── fase-3-plan-tecnico.md
387
432
  ├── fase-4-ejecucion.md
388
- └── fase-5-auditoria-pr.md ← includes the PR description contract
433
+ ├── fase-5-auditoria-pr.md ← includes the PR description contract
434
+ └── comandos/ ← the /f1…/f5 text, served by the server as MCP Prompts
435
+ ├── f1.md
436
+ └── …
389
437
  ```
390
438
 
391
439
  **They are read on every call.** Edit a `.md` and the next `get_phase_prompt` already returns the new version — no `npm run build`, no client restart. That's what makes it practical to tune a phase and test it immediately.
@@ -413,7 +461,7 @@ Format rules:
413
461
 
414
462
  ### Using your own prompts without losing the packaged ones
415
463
 
416
- `ORQUESTADOR_PROMPTS_PATH` points at a folder of yours that is **layered on top of** the packaged one. It does not replace it.
464
+ `PHASE_GATE_PROMPTS_PATH` points at a folder of yours that is **layered on top of** the packaged one. It does not replace it.
417
465
 
418
466
  To change only phase 2, your folder holds **one file**:
419
467
 
@@ -456,13 +504,16 @@ Loaded from the `.env` at the repo root, or from the `"env"` block in your clien
456
504
 
457
505
  The first two are **required and have no default**: they point at folders that only exist on your machine, so any default would be somebody else's path. If one is missing, or points at something that doesn't exist or isn't a folder, the tools that use it return the variable name and where to configure it. Tools that don't depend on it — like `get_phase_prompt` — keep working.
458
506
 
507
+ Each variable also has an **alias** with the old name, `ORQUESTADOR_*` (e.g. `ORQUESTADOR_DOCS_PATH`), which keeps working so no existing setup breaks. If you define both with different values, `PHASE_GATE_*` wins, and `doctor` and the server log tell you.
508
+
459
509
  | Variable | Default | Description |
460
510
  |----------|---------|-------------|
461
- | `ORQUESTADOR_DOCS_PATH` | **none, required** | Path to the root of your central documentation. **Different on each machine.** |
462
- | `ORQUESTADOR_REPOS_PATH` | **none, required** | Path to the folder holding your code repositories. |
463
- | `ORQUESTADOR_TASKS_SUBDIR` | `Proyectos` | Subfolder where tasks live inside each project. Empty means tasks hang directly off the project. It's also the rule that decides what counts as a project (see above). |
464
- | `ORQUESTADOR_PROMPTS_PATH` | none | Folder holding your own prompts. They are **layered on top of** the packaged ones rather than replacing them, so you only drop in the phases you want to change ([see above](#using-your-own-prompts-without-losing-the-packaged-ones)). |
465
- | `ORQUESTADOR_STATE_PATH` | Your user data folder (see above) | Where the active-task pointers are stored. Rarely needs touching; useful to isolate state in tests, and **required if you register the server more than once** (see [More than one documentation folder?](#-more-than-one-documentation-folder-optional)). |
511
+ | `PHASE_GATE_DOCS_PATH` | **none, required** | Path to the root of your central documentation. **Different on each machine.** |
512
+ | `PHASE_GATE_REPOS_PATH` | **none, required** | Path to the folder holding your code repositories. |
513
+ | `PHASE_GATE_TASKS_SUBDIR` | `Proyectos` | Subfolder where tasks live inside each project. Empty means tasks hang directly off the project. It's also the rule that decides what counts as a project (see above). |
514
+ | `PHASE_GATE_PROMPTS_PATH` | none | Folder holding your own prompts. They are **layered on top of** the packaged ones rather than replacing them, so you only drop in the phases you want to change ([see above](#using-your-own-prompts-without-losing-the-packaged-ones)). |
515
+ | `PHASE_GATE_STATE_PATH` | Your user data folder (see above) | Where the active-task pointers are stored. Rarely needs touching; useful to isolate state in tests, and **required if you register the server more than once** (see [More than one documentation folder?](#-more-than-one-documentation-folder-optional)). |
516
+ | `PHASE_GATE_ELICITATION` | none (enabled) | `off` (or `false`, `0`, `no`) so the server doesn't ask the client for [direct confirmations](#-protected-documents) and lets `force` decide, as before. Recommended on Cursor for Windows. No alias. |
466
517
 
467
518
  ---
468
519
 
@@ -474,11 +525,19 @@ The source lives in `src/`, split by responsibility:
474
525
 
475
526
  | File | What it handles |
476
527
  |------|-----------------|
477
- | `config.ts` | Environment paths, where state lives, server identity |
528
+ | `config.ts` | Environment variables and their aliases, reading `.env`, where state lives, server identity |
478
529
  | `paths.ts` | How every path is built, and the check that it stays inside its base |
479
530
  | `phases.ts` | Discovering the phases and assembling each one's prompt |
480
- | `tasks.ts` | Which tasks exist, which phase each is on, and which one is active |
481
- | `index.ts` | The server's tools. It computes nothing: it translates between the protocol and the above |
531
+ | `tasks.ts` | Which tasks exist, which phase each is on, which one is active, the gate and inherited pending items |
532
+ | `schemas.ts` | Each tool's arguments, with their description and error message |
533
+ | `servidor.ts` | The server's tools. It computes nothing: it translates between the protocol and the above |
534
+ | `recursos.ts` | The `phase-gate://` resources |
535
+ | `prompts-mcp.ts` | The `/f1`…`/fN` commands as MCP Prompts |
536
+ | `confirmacion.ts` | Direct confirmations to the user (elicitation) |
537
+ | `diagnostico.ts` | The X-ray shared by `doctor`, `get_orchestrator_status` and `phase-gate://estado` |
538
+ | `cli.ts` | The command line: `doctor`, `--help`, `--version` |
539
+ | `log.ts` | Logging: stderr and, with a client connected, MCP notifications |
540
+ | `index.ts` | The entry point: the command line, or the server over stdio |
482
541
 
483
542
  The client runs the compiled `build/index.js`, so after any change:
484
543
 
@@ -504,7 +563,7 @@ yours. CI runs them on every PR.
504
563
  |-------------------------|-------|
505
564
  | What the project does today | This README (and its Spanish twin, [`README.es.md`](README.es.md) — **change one, change the other**) |
506
565
  | Why it's designed this way | [`docs/decisiones.md`](docs/decisiones.md) (Spanish) |
507
- | The `/f1`–`/f5` commands, to recreate them elsewhere | [`docs/comandos-de-fase.md`](docs/comandos-de-fase.md) (Spanish) |
566
+ | The `/f1`–`/f5` commands | Their text in [`prompts/comandos/`](prompts/comandos); how they reach each client in [`docs/comandos-de-fase.md`](docs/comandos-de-fase.md) (Spanish) |
508
567
  | That a change broke nothing | [`test/`](test), via `npm test`. CI runs them on every PR |
509
568
  | What's still missing | [Issues](https://github.com/Montse2308/mcp-phase-gate/issues) — grouped under the `v1-uso-propio` and `v2-publico` labels |
510
569
  | What's already been done | The commit history and merged PRs |
package/build/cli.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export declare const AYUDA: string;
2
+ export declare const AVISO_TERMINAL = "Esperando un cliente MCP por stdin. Si quer\u00EDas revisar la instalaci\u00F3n: `npx mcp-phase-gate doctor`.";
3
+ export type Salida = {
4
+ out: (texto: string) => void;
5
+ err: (texto: string) => void;
6
+ };
7
+ export type ResultadoCli = {
8
+ accion: "servidor";
9
+ } | {
10
+ accion: "salir";
11
+ codigo: number;
12
+ };
13
+ export declare function ejecutarCli(argv: string[], salida?: Salida, esTerminal?: boolean): ResultadoCli;
14
+ //# sourceMappingURL=cli.d.ts.map
package/build/cli.js ADDED
@@ -0,0 +1,98 @@
1
+ // La línea de comandos del paquete. Sin argumentos, el binario es el servidor MCP que lanza el
2
+ // cliente; con argumentos, es una herramienta para la persona que lo instaló.
3
+ //
4
+ // Un servidor MCP habla JSON-RPC por stdin y no imprime nada por stdout. Ejecutado a mano en
5
+ // una terminal —que es exactamente lo que hace quien acaba de leer `npx mcp-phase-gate` en el
6
+ // README— se queda esperando entrada, sin señal de vida, y parece roto. Por eso existen la ayuda
7
+ // y `doctor`: el primero explica qué es esto, el segundo dice si está bien instalado.
8
+ import { parseArgs } from "util";
9
+ import { SERVER_NAME, SERVER_VERSION } from "./config.js";
10
+ import { diagnosticar, formatearDiagnostico } from "./diagnostico.js";
11
+ export const AYUDA = `${SERVER_NAME} v${SERVER_VERSION}
12
+
13
+ Servidor MCP que parte cada requerimiento en cinco fases con compuerta y obliga a que cada
14
+ una deje su documento en una documentación central.
15
+
16
+ El servidor NO se ejecuta a mano: lo lanza tu cliente MCP. Ejecutado directamente se queda
17
+ esperando mensajes JSON-RPC por stdin, que es lo que parece que se colgó.
18
+
19
+ Uso:
20
+ ${SERVER_NAME} Arranca el servidor MCP por stdio (lo hace tu cliente).
21
+ ${SERVER_NAME} doctor Revisa la instalación: variables, prompts, proyectos y avisos.
22
+ ${SERVER_NAME} doctor --json Lo mismo, como JSON.
23
+ ${SERVER_NAME} --version La versión.
24
+ ${SERVER_NAME} --help Esta ayuda.
25
+
26
+ Regístralo en tu cliente (Cursor, VS Code, Claude Code) así:
27
+
28
+ {
29
+ "mcpServers": {
30
+ "${SERVER_NAME}": {
31
+ "command": "npx",
32
+ "args": ["-y", "mcp-phase-gate"],
33
+ "env": {
34
+ "PHASE_GATE_DOCS_PATH": "<tu carpeta de documentación>",
35
+ "PHASE_GATE_REPOS_PATH": "<tu carpeta de repositorios>"
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ Variables de entorno (los nombres ORQUESTADOR_* de antes siguen valiendo como alias):
42
+ PHASE_GATE_DOCS_PATH Obligatoria. Raíz de la Documentación Central.
43
+ PHASE_GATE_REPOS_PATH Obligatoria. Carpeta con tus repositorios de código.
44
+ PHASE_GATE_TASKS_SUBDIR Subcarpeta de tareas dentro de cada proyecto. Por defecto "Proyectos".
45
+ PHASE_GATE_PROMPTS_PATH Carpeta de prompts propios, que se superponen a los del paquete.
46
+ PHASE_GATE_STATE_PATH Dónde guardar los punteros de tarea activa.
47
+ PHASE_GATE_ELICITATION "off" para que el servidor no pida confirmaciones al cliente.
48
+
49
+ Documentación: https://github.com/Montse2308/mcp-phase-gate`;
50
+ export const AVISO_TERMINAL = "Esperando un cliente MCP por stdin. Si querías revisar la instalación: `npx mcp-phase-gate doctor`.";
51
+ const SALIDA_DE_PROCESO = {
52
+ out: (texto) => process.stdout.write(`${texto}\n`),
53
+ err: (texto) => process.stderr.write(`${texto}\n`),
54
+ };
55
+ function invalido(salida) {
56
+ salida.err(AYUDA);
57
+ return { accion: "salir", codigo: 2 };
58
+ }
59
+ export function ejecutarCli(argv, salida = SALIDA_DE_PROCESO, esTerminal = Boolean(process.stdin.isTTY)) {
60
+ if (argv.length === 0) {
61
+ // stderr, no stdout: stdout es el canal del JSON-RPC aunque nadie esté escuchando.
62
+ if (esTerminal)
63
+ salida.err(AVISO_TERMINAL);
64
+ return { accion: "servidor" };
65
+ }
66
+ let valores;
67
+ let posicionales;
68
+ try {
69
+ ({ values: valores, positionals: posicionales } = parseArgs({
70
+ args: argv,
71
+ allowPositionals: true,
72
+ strict: true,
73
+ options: {
74
+ help: { type: "boolean", short: "h" },
75
+ version: { type: "boolean", short: "v" },
76
+ json: { type: "boolean" },
77
+ },
78
+ }));
79
+ }
80
+ catch {
81
+ return invalido(salida);
82
+ }
83
+ if (valores.help) {
84
+ salida.out(AYUDA);
85
+ return { accion: "salir", codigo: 0 };
86
+ }
87
+ if (valores.version) {
88
+ salida.out(SERVER_VERSION);
89
+ return { accion: "salir", codigo: 0 };
90
+ }
91
+ if (posicionales.length === 1 && posicionales[0] === "doctor") {
92
+ const diagnostico = diagnosticar();
93
+ salida.out(valores.json ? JSON.stringify(diagnostico, null, 2) : formatearDiagnostico(diagnostico, "texto"));
94
+ return { accion: "salir", codigo: diagnostico.hallazgos.some((h) => h.severidad === "error") ? 1 : 0 };
95
+ }
96
+ return invalido(salida);
97
+ }
98
+ //# sourceMappingURL=cli.js.map
package/build/config.d.ts CHANGED
@@ -1,11 +1,35 @@
1
1
  export declare const MODULE_DIR: string;
2
+ export declare function envPorDefecto(): string;
3
+ export declare function clavesDeEnv(): ReadonlySet<string>;
4
+ export declare function errorDeEnv(): string | null;
5
+ export declare function reiniciarEnv(): void;
6
+ export declare function cargarEnv(archivo?: string): void;
7
+ export type NombreLogico = "DOCS_PATH" | "REPOS_PATH" | "TASKS_SUBDIR" | "PROMPTS_PATH" | "STATE_PATH" | "ELICITATION";
8
+ type Nombres = {
9
+ principal: string;
10
+ alias: string | null;
11
+ esRuta: boolean;
12
+ };
13
+ export declare const VARIABLES: Record<NombreLogico, Nombres>;
14
+ export declare const NOMBRES_LOGICOS: NombreLogico[];
15
+ export type FuenteVariable = "entorno" | ".env" | "sin definir";
16
+ export type LecturaVariable = {
17
+ logica: NombreLogico;
18
+ valor: string | undefined;
19
+ usada: string | null;
20
+ fuente: FuenteVariable;
21
+ discrepancia: string | null;
22
+ };
23
+ export declare function leerVariable(logica: NombreLogico): LecturaVariable;
24
+ export declare function nombrarVariable(logica: NombreLogico): string;
2
25
  export type RutaRequerida = {
3
- variable: string;
26
+ logica: NombreLogico;
4
27
  apuntaA: string;
5
28
  };
6
29
  export declare const DOCS: RutaRequerida;
7
30
  export declare const REPOS: RutaRequerida;
8
- export declare function requireBasePath({ variable, apuntaA }: RutaRequerida): string;
31
+ export declare function requireBasePath({ logica, apuntaA }: RutaRequerida): string;
32
+ export declare const TASKS_SUBDIR_POR_DEFECTO = "Proyectos";
9
33
  export declare function tasksSubdir(): string;
10
34
  export declare function defaultPromptsPath(): string;
11
35
  export declare function promptsLayers(): string[];
@@ -14,4 +38,5 @@ export declare function stateDir(): string;
14
38
  export declare function stateFile(): string;
15
39
  export declare const SERVER_NAME = "mcp-phase-gate";
16
40
  export declare const SERVER_VERSION: string;
41
+ export {};
17
42
  //# sourceMappingURL=config.d.ts.map