mcp-phase-gate 2.0.1 → 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.es.md +146 -59
- package/README.md +130 -52
- package/build/cli.d.ts +14 -0
- package/build/cli.js +98 -0
- package/build/config.d.ts +27 -2
- package/build/config.js +151 -22
- package/build/confirmacion.d.ts +15 -0
- package/build/confirmacion.js +100 -0
- package/build/diagnostico.d.ts +83 -0
- package/build/diagnostico.js +394 -0
- package/build/index.js +28 -365
- package/build/log.d.ts +6 -0
- package/build/log.js +27 -0
- package/build/paths.d.ts +9 -0
- package/build/paths.js +71 -8
- package/build/phases.d.ts +13 -1
- package/build/phases.js +125 -17
- package/build/prompts-mcp.d.ts +33 -0
- package/build/prompts-mcp.js +194 -0
- package/build/recursos.d.ts +8 -0
- package/build/recursos.js +306 -0
- package/build/schemas.d.ts +106 -50
- package/build/schemas.js +151 -75
- package/build/servidor.d.ts +3 -0
- package/build/servidor.js +372 -0
- package/build/tasks.d.ts +8 -2
- package/build/tasks.js +218 -24
- package/package.json +1 -2
- package/prompts/comandos/f1.md +14 -0
- package/prompts/comandos/f2.md +12 -0
- package/prompts/comandos/f3.md +9 -0
- package/prompts/comandos/f4.md +10 -0
- package/prompts/comandos/f5.md +12 -0
- package/prompts/fase-1-descubrimiento.md +22 -6
- package/prompts/fase-2-decisiones.md +34 -5
- package/prompts/fase-3-plan-tecnico.md +77 -22
- package/prompts/fase-4-ejecucion.md +168 -34
- package/prompts/fase-5-auditoria-pr.md +24 -1
- package/prompts/global-rules.md +30 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ flowchart TD
|
|
|
34
34
|
|
|
35
35
|
And between one phase and the next there is a **gate**, which is what gives the server its name: ask for a phase while skipping the previous one and the server notices and warns you ([see below](#-the-gate-skipping-a-phase-stops-being-invisible)).
|
|
36
36
|
|
|
37
|
-
In phase
|
|
37
|
+
In phase 4 the AI commits each batch only with your OK; it never pushes or opens the PR. In phase 5 it only reads.
|
|
38
38
|
|
|
39
39
|
## Who it's for
|
|
40
40
|
|
|
@@ -59,7 +59,10 @@ DOCUMENTATION/
|
|
|
59
59
|
│ ├── 01 - Análisis Técnico.md ← Phase 1
|
|
60
60
|
│ ├── 02 - Decisiones.md ← Phase 2
|
|
61
61
|
│ ├── 03 - Plan Técnico.md ← Phase 3
|
|
62
|
-
│ ├── 04 - Ejecución
|
|
62
|
+
│ ├── 04 - Ejecución/ ← Phase 4, with more than one batch: one receipt each
|
|
63
|
+
│ │ ├── L01 - <slug>.md
|
|
64
|
+
│ │ └── L02 - <slug>.md
|
|
65
|
+
│ ├── 04 - Ejecución.md ← Phase 4: the receipt, or the index of receipts
|
|
63
66
|
│ └── 05 - Auditoría.md ← Phase 5
|
|
64
67
|
├── PROJECT-B/
|
|
65
68
|
│ └── Proyectos/
|
|
@@ -69,7 +72,9 @@ DOCUMENTATION/
|
|
|
69
72
|
└── <task_name>/
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
The `Proyectos` level is the tasks subfolder, and its name is configurable — see `
|
|
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
|
+
|
|
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.
|
|
73
78
|
|
|
74
79
|
> The server builds this path **automatically**. You (or the LLM) only supply `project`, `task_name` and `file_name`; nobody has to type a full path.
|
|
75
80
|
|
|
@@ -96,7 +101,7 @@ The code is identical everywhere; the only thing that changes between machines i
|
|
|
96
101
|
|
|
97
102
|
Nothing to install: `npx` fetches the package the first time and caches it. Everything is configured in your MCP client's file.
|
|
98
103
|
|
|
99
|
-
**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
|
|
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.
|
|
100
105
|
|
|
101
106
|
Remember that in JSON every `\` must be doubled as `\\`.
|
|
102
107
|
|
|
@@ -110,8 +115,8 @@ Remember that in JSON every `\` must be doubled as `\\`.
|
|
|
110
115
|
"command": "npx",
|
|
111
116
|
"args": ["-y", "mcp-phase-gate"],
|
|
112
117
|
"env": {
|
|
113
|
-
"
|
|
114
|
-
"
|
|
118
|
+
"PHASE_GATE_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
|
|
119
|
+
"PHASE_GATE_REPOS_PATH": "C:\\projects"
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
}
|
|
@@ -132,8 +137,8 @@ Two differences to watch: the top-level key is `servers`, not `mcpServers`, and
|
|
|
132
137
|
"command": "npx",
|
|
133
138
|
"args": ["-y", "mcp-phase-gate"],
|
|
134
139
|
"env": {
|
|
135
|
-
"
|
|
136
|
-
"
|
|
140
|
+
"PHASE_GATE_DOCS_PATH": "C:\\Users\\YOUR_USER\\OneDrive - YOUR ORGANISATION\\Documents\\DOCUMENTATION",
|
|
141
|
+
"PHASE_GATE_REPOS_PATH": "C:\\projects"
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
}
|
|
@@ -145,19 +150,21 @@ Two differences to watch: the top-level key is `servers`, not `mcpServers`, and
|
|
|
145
150
|
<summary><b>Claude Code</b> — one line</summary>
|
|
146
151
|
|
|
147
152
|
```bash
|
|
148
|
-
claude mcp add mcp-phase-gate --env
|
|
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
|
|
149
154
|
```
|
|
150
155
|
|
|
151
156
|
Or by hand, in a `.mcp.json` at the project root, shaped like the Cursor one.
|
|
152
157
|
</details>
|
|
153
158
|
|
|
154
|
-
That `
|
|
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.
|
|
155
160
|
|
|
156
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.
|
|
157
162
|
|
|
158
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.
|
|
159
164
|
|
|
160
|
-
>
|
|
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)).
|
|
161
168
|
|
|
162
169
|
---
|
|
163
170
|
|
|
@@ -183,11 +190,11 @@ cp .env.example .env
|
|
|
183
190
|
Single backslashes on Windows, no quotes:
|
|
184
191
|
|
|
185
192
|
```ini
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
PHASE_GATE_DOCS_PATH=C:\Users\YOUR_USER\OneDrive - YOUR ORGANISATION\Documents\DOCUMENTATION
|
|
194
|
+
PHASE_GATE_REPOS_PATH=C:\projects
|
|
188
195
|
```
|
|
189
196
|
|
|
190
|
-
>
|
|
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`.
|
|
191
198
|
|
|
192
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):
|
|
193
200
|
|
|
@@ -204,8 +211,20 @@ In **Claude Code**, a `.mcp.json` at this repo's root can use a **relative** pat
|
|
|
204
211
|
|
|
205
212
|
### ✅ Verify it works
|
|
206
213
|
1. Restart the client, or toggle the server off and on in its MCP panel.
|
|
207
|
-
2. It should show up active with its
|
|
208
|
-
3. Try it from the chat: *"Use the `
|
|
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.
|
|
209
228
|
|
|
210
229
|
---
|
|
211
230
|
|
|
@@ -233,23 +252,23 @@ You may want separate documentation sets that never mix — one for work and one
|
|
|
233
252
|
```jsonc
|
|
234
253
|
{
|
|
235
254
|
"mcpServers": {
|
|
236
|
-
"
|
|
255
|
+
"pg-work": {
|
|
237
256
|
"command": "npx",
|
|
238
257
|
"args": ["-y", "mcp-phase-gate"],
|
|
239
258
|
"env": {
|
|
240
|
-
"
|
|
241
|
-
"
|
|
242
|
-
"
|
|
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"
|
|
243
262
|
}
|
|
244
263
|
},
|
|
245
|
-
"
|
|
264
|
+
"pg-personal": {
|
|
246
265
|
"command": "npx",
|
|
247
266
|
"args": ["-y", "mcp-phase-gate"],
|
|
248
267
|
"env": {
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
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"
|
|
253
272
|
}
|
|
254
273
|
}
|
|
255
274
|
}
|
|
@@ -258,12 +277,12 @@ You may want separate documentation sets that never mix — one for work and one
|
|
|
258
277
|
|
|
259
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.
|
|
260
279
|
|
|
261
|
-
> ⚠️ **`
|
|
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.
|
|
262
281
|
|
|
263
282
|
Two more things that bite and aren't obvious:
|
|
264
283
|
|
|
265
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.
|
|
266
|
-
- **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 `
|
|
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.
|
|
267
286
|
|
|
268
287
|
---
|
|
269
288
|
|
|
@@ -276,7 +295,7 @@ Two more things that bite and aren't obvious:
|
|
|
276
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. |
|
|
277
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. |
|
|
278
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. |
|
|
279
|
-
| The `/f1`–`/f5` commands
|
|
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/`. |
|
|
280
299
|
|
|
281
300
|
### The phase commands
|
|
282
301
|
|
|
@@ -287,20 +306,24 @@ You invoke them by typing `/f1`, `/f2`, etc. in the chat. **They are orchestrati
|
|
|
287
306
|
| `/f1` | `start_task` + `get_phase_prompt(1)` | Phase 1's |
|
|
288
307
|
| `/f2` | `get_phase_prompt(2)`, reads phase 1's | Phase 2's, after you answer the questions |
|
|
289
308
|
| `/f3` | `get_phase_prompt(3)`, reads the previous ones | Phase 3's |
|
|
290
|
-
| `/f4` | `get_phase_prompt(4)`, reads the plan |
|
|
309
|
+
| `/f4` | `get_phase_prompt(4)`, reads the plan | One receipt per batch; the phase document when it closes |
|
|
291
310
|
| `/f5` | `get_phase_prompt(5)` | Phase 5's: the audit and the PR description, which also go in the chat |
|
|
292
311
|
|
|
293
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.
|
|
294
313
|
|
|
295
|
-
`/f1` and `/f5`
|
|
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`.
|
|
296
315
|
|
|
297
|
-
**
|
|
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.
|
|
298
317
|
|
|
299
|
-
|
|
300
|
-
- **Cursor:** copy them to `~/.cursor/commands/`. From there they work across all your projects.
|
|
301
|
-
- **VS Code:** no slash commands of its own; paste the file contents into the chat.
|
|
318
|
+
How they look in each client:
|
|
302
319
|
|
|
303
|
-
|
|
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).
|
|
304
327
|
|
|
305
328
|
---
|
|
306
329
|
|
|
@@ -327,24 +350,64 @@ Three things it deliberately does **not** do:
|
|
|
327
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.
|
|
328
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.
|
|
329
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
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 🔒 Protected documents
|
|
358
|
+
|
|
359
|
+
Each phase works on top of the previous phases' documents, so rewriting one that's already been passed silently changes the basis of everything that came after. That's why `write_central_doc` refuses, **without `force: true`**, to write:
|
|
360
|
+
|
|
361
|
+
- **The initial context** (`00 - Contexto Inicial.md`), always, even to create it. Only `start_task` writes it without `force`.
|
|
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.
|
|
363
|
+
|
|
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.
|
|
374
|
+
|
|
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.
|
|
376
|
+
|
|
330
377
|
---
|
|
331
378
|
|
|
332
379
|
## 🛠 Available tools
|
|
333
380
|
|
|
334
381
|
| Tool | What it does |
|
|
335
382
|
|------|--------------|
|
|
336
|
-
| `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. |
|
|
337
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. |
|
|
338
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. |
|
|
339
386
|
| `switch_task` | Changes which task is active for a project. **Touches no files**: it's the correct way to resume an existing task. |
|
|
340
|
-
| `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. |
|
|
341
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`. |
|
|
342
|
-
| `write_central_doc` | Writes/overwrites a file. Same parameters as `read_central_doc` plus `content
|
|
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. |
|
|
343
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.
|
|
344
407
|
|
|
345
408
|
### How the server builds paths
|
|
346
|
-
- **Documentation:** `
|
|
347
|
-
- **Code repos:** `
|
|
409
|
+
- **Documentation:** `PHASE_GATE_DOCS_PATH` / `<PROJECT>` / `PHASE_GATE_TASKS_SUBDIR` / `<task>` / `<file>`
|
|
410
|
+
- **Code repos:** `PHASE_GATE_REPOS_PATH` / `<repo>` / `<file>`
|
|
348
411
|
|
|
349
412
|
### What counts as a project
|
|
350
413
|
|
|
@@ -352,7 +415,7 @@ There is no list of projects to maintain. **A project is any folder that contain
|
|
|
352
415
|
|
|
353
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.
|
|
354
417
|
|
|
355
|
-
> If you leave `
|
|
418
|
+
> If you leave `PHASE_GATE_TASKS_SUBDIR` empty, the rule can't be applied and **any** folder counts as a project.
|
|
356
419
|
|
|
357
420
|
---
|
|
358
421
|
|
|
@@ -367,7 +430,10 @@ prompts/
|
|
|
367
430
|
├── fase-2-decisiones.md
|
|
368
431
|
├── fase-3-plan-tecnico.md
|
|
369
432
|
├── fase-4-ejecucion.md
|
|
370
|
-
|
|
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
|
+
└── …
|
|
371
437
|
```
|
|
372
438
|
|
|
373
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.
|
|
@@ -395,7 +461,7 @@ Format rules:
|
|
|
395
461
|
|
|
396
462
|
### Using your own prompts without losing the packaged ones
|
|
397
463
|
|
|
398
|
-
`
|
|
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.
|
|
399
465
|
|
|
400
466
|
To change only phase 2, your folder holds **one file**:
|
|
401
467
|
|
|
@@ -411,6 +477,7 @@ Three details that matter:
|
|
|
411
477
|
- **Layering is by phase number, not by filename.** Your `fase-2-my-way.md` overrides the package's `fase-2-decisiones.md`. You don't have to guess the original's name.
|
|
412
478
|
- **It also adds.** A `fase-6-deployment.md` in your folder creates phase 6, nothing else needed.
|
|
413
479
|
- **Your `global-rules.md` replaces the packaged one, it doesn't stack.** Concatenating two rule sets makes it impossible to tell which file an unwanted instruction came from, exactly when you need to know. If you want the packaged rules plus extras, copy them and add.
|
|
480
|
+
**Watch out:** the packaged rules include the `EVIDENCIA`, `BASE DE CADA DECISIÓN` and `PENDIENTES HEREDADOS` sections, which the phases refer to. A `global-rules.md` of your own without them leaves the phases pointing at rules that don't exist; copy them into your file.
|
|
414
481
|
|
|
415
482
|
On the `npx` route this is the **only** way to customise: the packaged prompts live inside `node_modules`, where editing them achieves nothing because the next install wipes them.
|
|
416
483
|
|
|
@@ -437,13 +504,16 @@ Loaded from the `.env` at the repo root, or from the `"env"` block in your clien
|
|
|
437
504
|
|
|
438
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.
|
|
439
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
|
+
|
|
440
509
|
| Variable | Default | Description |
|
|
441
510
|
|----------|---------|-------------|
|
|
442
|
-
| `
|
|
443
|
-
| `
|
|
444
|
-
| `
|
|
445
|
-
| `
|
|
446
|
-
| `
|
|
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. |
|
|
447
517
|
|
|
448
518
|
---
|
|
449
519
|
|
|
@@ -455,11 +525,19 @@ The source lives in `src/`, split by responsibility:
|
|
|
455
525
|
|
|
456
526
|
| File | What it handles |
|
|
457
527
|
|------|-----------------|
|
|
458
|
-
| `config.ts` | Environment
|
|
528
|
+
| `config.ts` | Environment variables and their aliases, reading `.env`, where state lives, server identity |
|
|
459
529
|
| `paths.ts` | How every path is built, and the check that it stays inside its base |
|
|
460
530
|
| `phases.ts` | Discovering the phases and assembling each one's prompt |
|
|
461
|
-
| `tasks.ts` | Which tasks exist, which phase each is on,
|
|
462
|
-
| `
|
|
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 |
|
|
463
541
|
|
|
464
542
|
The client runs the compiled `build/index.js`, so after any change:
|
|
465
543
|
|
|
@@ -485,7 +563,7 @@ yours. CI runs them on every PR.
|
|
|
485
563
|
|-------------------------|-------|
|
|
486
564
|
| What the project does today | This README (and its Spanish twin, [`README.es.md`](README.es.md) — **change one, change the other**) |
|
|
487
565
|
| Why it's designed this way | [`docs/decisiones.md`](docs/decisiones.md) (Spanish) |
|
|
488
|
-
| The `/f1`–`/f5` commands
|
|
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) |
|
|
489
567
|
| That a change broke nothing | [`test/`](test), via `npm test`. CI runs them on every PR |
|
|
490
568
|
| What's still missing | [Issues](https://github.com/Montse2308/mcp-phase-gate/issues) — grouped under the `v1-uso-propio` and `v2-publico` labels |
|
|
491
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
|
-
|
|
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({
|
|
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
|