sdd-gl 0.6.0 → 0.6.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/README.es.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  ![SDD-GL Portada](assets/sdd-gl-cover.png)
4
4
 
5
- [![Version](https://img.shields.io/badge/version-0.6.0-blue)](CHANGELOG.md)
5
+ [![npm](https://img.shields.io/npm/v/sdd-gl)](https://www.npmjs.com/package/sdd-gl)
6
+ [![Version](https://img.shields.io/badge/version-0.6.2-blue)](CHANGELOG.md)
6
7
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
8
  [![MCP Protocol](https://img.shields.io/badge/MCP-Protocol%20Ready-purple)](mcp/sdd-gl-mcp-spec.md)
8
9
  [![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-orange)](https://docs.claude.ai/code)
@@ -285,7 +286,30 @@ Sigue esta guía paso a paso para configurar y comenzar a utilizar SDD-GL en tu
285
286
 
286
287
  ### 2. Elige tu Método de Instalación
287
288
 
288
- #### 🌐 Método 1: Servidor MCP Universal (Cursor, Windsurf, OpenCode, Warp, Claude Desktop, VS Code)
289
+ #### 📦 Método 0: paquete npm (recomendado)
290
+ Publicado como **`sdd-gl`** en npm — sin clonar ni spec de GitHub:
291
+
292
+ ```bash
293
+ npm install -g sdd-gl # instala dos comandos: sdd (CLI) y sdd-gl-mcp (servidor)
294
+ sdd --help # verificar
295
+ ```
296
+
297
+ Para la configuración de un cliente MCP, apuntá al binario del servidor:
298
+
299
+ ```json
300
+ {
301
+ "mcpServers": {
302
+ "sdd-gl": {
303
+ "command": "npx",
304
+ "args": ["-y", "--package", "sdd-gl", "sdd-gl-mcp"]
305
+ }
306
+ }
307
+ }
308
+ ```
309
+
310
+ > Un paquete con dos binarios no se resuelve solo por el nombre del paquete, así que `npx` siempre nombra el binario: `--package sdd-gl sdd-gl-mcp`.
311
+
312
+ #### 🌐 Método 1: Servidor MCP Universal desde GitHub (Cursor, Windsurf, OpenCode, Warp, Claude Desktop, VS Code)
289
313
  Sin necesidad de clonar repositorios manualmente. Añade el servidor MCP directamente desde GitHub a la configuración de tu IDE o cliente de terminal (`~/.cursor/mcp.json`, `claude_desktop_config.json`, configuración de OpenCode o Cline MCP):
290
314
 
291
315
  ```json
@@ -780,6 +804,7 @@ sdd-gl/
780
804
  ├── docs/
781
805
  │ ├── index.html ← Dashboard público del showcase (solo examples/, nunca los contratos privados).
782
806
  │ ├── INSTALACION.md ← Instalación paso a paso por plataforma.
807
+ │ ├── DEPLOY.md ← Checklist de publicación para mantenedores.
783
808
  │ └── assets/
784
809
  │ └── dashboard-sample.png ← Captura real de un proyecto de ejemplo.
785
810
  ├── protocol/
@@ -801,6 +826,8 @@ sdd-gl/
801
826
  ├── examples/
802
827
  │ └── contracts/ ← Contratos showcase públicos (curados y resueltos).
803
828
  ├── contracts/ ← Specs de trabajo locales (gitignored — privadas).
829
+ ├── scripts/
830
+ │ └── release.js ← Sube la versión en manifiestos y badges, y verifica la deriva.
804
831
  ├── test-sandbox/ ← 15 suites: core, CLI, métricas, uso, CI, interop y fixtures.
805
832
  ├── .claude/
806
833
  │ ├── agents/ ← 6 adaptadores de agente (español).
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  ![SDD-GL Cover](assets/sdd-gl-cover.png)
4
4
 
5
- [![Version](https://img.shields.io/badge/version-0.6.0-blue)](CHANGELOG.md)
5
+ [![npm](https://img.shields.io/npm/v/sdd-gl)](https://www.npmjs.com/package/sdd-gl)
6
+ [![Version](https://img.shields.io/badge/version-0.6.2-blue)](CHANGELOG.md)
6
7
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
8
  [![MCP Protocol](https://img.shields.io/badge/MCP-Protocol%20Ready-purple)](mcp/sdd-gl-mcp-spec.md)
8
9
  [![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-orange)](https://docs.claude.ai/code)
@@ -284,7 +285,30 @@ Follow this step-by-step guide to configure and start using SDD-GL in your prefe
284
285
 
285
286
  ### 2. Choose Your Installation Method
286
287
 
287
- #### 🌐 Method 1: Universal MCP Server (Cursor, Windsurf, OpenCode, Warp, Claude Desktop, VS Code)
288
+ #### 📦 Method 0: npm package (recommended)
289
+ Published as **`sdd-gl`** on npm — no cloning, no GitHub spec:
290
+
291
+ ```bash
292
+ npm install -g sdd-gl # installs two commands: sdd (CLI) and sdd-gl-mcp (server)
293
+ sdd --help # verify
294
+ ```
295
+
296
+ For an MCP client configuration, point it at the server binary:
297
+
298
+ ```json
299
+ {
300
+ "mcpServers": {
301
+ "sdd-gl": {
302
+ "command": "npx",
303
+ "args": ["-y", "--package", "sdd-gl", "sdd-gl-mcp"]
304
+ }
305
+ }
306
+ }
307
+ ```
308
+
309
+ > A package with two binaries cannot be resolved by package name alone, so `npx` always names the binary: `--package sdd-gl sdd-gl-mcp`.
310
+
311
+ #### 🌐 Method 1: Universal MCP Server from GitHub (Cursor, Windsurf, OpenCode, Warp, Claude Desktop, VS Code)
288
312
  No repository cloning needed. Add the MCP server directly from GitHub to your IDE / terminal client configuration (`~/.cursor/mcp.json`, `claude_desktop_config.json`, OpenCode settings, or Cline MCP settings):
289
313
 
290
314
  ```json
@@ -779,6 +803,7 @@ sdd-gl/
779
803
  ├── docs/
780
804
  │ ├── index.html ← Public showcase dashboard (examples/ only, never the private contracts).
781
805
  │ ├── INSTALACION.md ← Step-by-step installation per platform.
806
+ │ ├── DEPLOY.md ← Release checklist for maintainers.
782
807
  │ └── assets/
783
808
  │ └── dashboard-sample.png ← Real capture of an example project.
784
809
  ├── protocol/
@@ -800,6 +825,8 @@ sdd-gl/
800
825
  ├── examples/
801
826
  │ └── contracts/ ← Public showcase contracts (curated and resolved).
802
827
  ├── contracts/ ← Local working specs (gitignored — private).
828
+ ├── scripts/
829
+ │ └── release.js ← Version bump across manifests and README badges, plus the drift check.
803
830
  ├── test-sandbox/ ← 15 suites: core, CLI, metrics, usage, CI, interop and fixtures.
804
831
  ├── .claude/
805
832
  │ ├── agents/ ← 6 agent adapters (Spanish).
package/bin/sdd.js CHANGED
@@ -32,7 +32,7 @@ const ROOT = rootFlag ? path.resolve(rootFlag) : process.cwd();
32
32
 
33
33
  process.env.SDD_PROJECT_ROOT = ROOT;
34
34
 
35
- const { handleToolCall, TOOLS } = require('../mcp/server.js');
35
+ const { handleToolCall, TOOLS, isContractText, looksLikeContract } = require('../mcp/server.js');
36
36
 
37
37
  // CLI usage is real usage of the methodology: it is counted and attributed to the
38
38
  // contract type it serves (feature/fix) when a contract is involved.
@@ -588,17 +588,28 @@ function commandDoctor() {
588
588
 
589
589
  const unreadable = [];
590
590
  const stalled = [];
591
+ const ignored = [];
592
+ let contracts = 0;
591
593
 
592
594
  if (fs.existsSync(contractsDir)) {
593
595
  for (const name of fs.readdirSync(contractsDir).filter(entry => entry.toLowerCase().endsWith('.md'))) {
594
596
  const text = fs.readFileSync(path.join(contractsDir, name), 'utf8');
595
- if (!/^#\s*ID:/m.test(text) || !/^#\s*Status:/m.test(text)) unreadable.push(name);
597
+
598
+ // `contracts/` may also hold a README or notes: only files with a contract
599
+ // header are counted, and only a broken contract header is a failure.
600
+ if (!isContractText(text)) {
601
+ if (looksLikeContract(text)) unreadable.push(name);
602
+ else ignored.push(name);
603
+ continue;
604
+ }
605
+
606
+ contracts += 1;
596
607
  if (/^\s*#.*\|\s*⏳\s*$/m.test(text)) stalled.push(name);
597
608
  }
598
609
  }
599
610
 
600
611
  if (unreadable.length > 0) add('contratos', 'FAIL', `encabezado ilegible: ${unreadable.join(', ')}`);
601
- else add('contratos', 'OK', 'todos los encabezados son legibles');
612
+ else add('contratos', 'OK', `${contracts} contrato(s) legibles${ignored.length ? ` · ignorados: ${ignored.join(', ')}` : ''}`);
602
613
 
603
614
  if (stalled.length > 0) add('en curso', 'WARN', `ítems en ⏳ (reanudar): ${stalled.join(', ')}`);
604
615
  else add('en curso', 'OK', 'sin ítems interrumpidos');
@@ -1320,6 +1331,7 @@ function commandReview() {
1320
1331
 
1321
1332
  for (const file of fs.readdirSync(contractsDir).filter(name => name.toLowerCase().endsWith('.md'))) {
1322
1333
  const text = fs.readFileSync(path.join(contractsDir, file), 'utf8');
1334
+ if (!isContractText(text)) continue;
1323
1335
  const id = (text.match(/^#\s*ID:\s*(\S+)\s*$/m) || [])[1] || file.replace(/\.md$/, '');
1324
1336
  const status = (text.match(/^#\s*Status:\s*(\w+)\s*$/m) || [])[1] || 'UNKNOWN';
1325
1337
  const criteria = readCriteria(text);
package/mcp/server.js CHANGED
@@ -327,12 +327,30 @@ function inferContractType(contractId, text, fileName) {
327
327
  return 'feature';
328
328
  }
329
329
 
330
+ // A contract is recognized by its header, not by its extension: `contracts/` may
331
+ // also hold a README or free-form notes that must be ignored.
332
+ function isContractText(text) {
333
+ return /^#\s*ID:/m.test(text) && /^#\s*Status:/m.test(text);
334
+ }
335
+
336
+ // Files that *look* like contracts but cannot be read as one are real errors.
337
+ function looksLikeContract(text) {
338
+ return /^#\s*CONTRACT:/m.test(text);
339
+ }
340
+
330
341
  function listContractFiles() {
331
342
  if (!fs.existsSync(CONTRACTS_DIR)) return [];
332
343
  return fs
333
344
  .readdirSync(CONTRACTS_DIR, { withFileTypes: true })
334
345
  .filter(entry => entry.isFile() && entry.name.toLowerCase().endsWith('.md'))
335
- .map(entry => entry.name);
346
+ .map(entry => entry.name)
347
+ .filter(name => {
348
+ try {
349
+ return isContractText(fs.readFileSync(path.join(CONTRACTS_DIR, name), 'utf8'));
350
+ } catch (error) {
351
+ return false;
352
+ }
353
+ });
336
354
  }
337
355
 
338
356
  // Finds a contract by ID regardless of the file naming convention
@@ -1483,7 +1501,7 @@ ${evidence}
1483
1501
 
1484
1502
  case 'sdd_get_status': {
1485
1503
  if (!fs.existsSync(CONTRACTS_DIR)) return { total_contracts: 0, contracts: [] };
1486
- const files = fs.readdirSync(CONTRACTS_DIR).filter(f => f.endsWith('.md'));
1504
+ const files = listContractFiles();
1487
1505
 
1488
1506
  const summary = files.map(file => {
1489
1507
  const content = fs.readFileSync(path.join(CONTRACTS_DIR, file), 'utf8');
@@ -1517,7 +1535,7 @@ ${evidence}
1517
1535
  const response = { ...metrics, source };
1518
1536
  if (warning) response.warning = warning;
1519
1537
  if (fs.existsSync(CONTRACTS_DIR)) {
1520
- response.total_contracts = fs.readdirSync(CONTRACTS_DIR).filter(f => f.endsWith('.md')).length;
1538
+ response.total_contracts = listContractFiles().length;
1521
1539
  } else {
1522
1540
  response.total_contracts = 0;
1523
1541
  }
@@ -1527,7 +1545,7 @@ ${evidence}
1527
1545
  case 'sdd_audit_traceability': {
1528
1546
  // BR-005: real coverage. Nothing here is a fixed value.
1529
1547
  const contractFiles = fs.existsSync(CONTRACTS_DIR)
1530
- ? fs.readdirSync(CONTRACTS_DIR).filter(file => file.endsWith('.md'))
1548
+ ? listContractFiles()
1531
1549
  : [];
1532
1550
 
1533
1551
  const specs = [];
@@ -1665,7 +1683,7 @@ function main() {
1665
1683
  });
1666
1684
  }
1667
1685
 
1668
- module.exports = { TOOLS, handleToolCall, computeNextContractId, reconcileContract, computeCriteriaHashes };
1686
+ module.exports = { TOOLS, handleToolCall, computeNextContractId, reconcileContract, computeCriteriaHashes, isContractText, looksLikeContract };
1669
1687
 
1670
1688
  if (require.main === module) {
1671
1689
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-gl",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Model Context Protocol (MCP) Server and CLI for Spec-Driven Development (SDD-GL)",
5
5
  "main": "mcp/server.js",
6
6
  "bin": {
@@ -35,8 +35,10 @@
35
35
  "dashboard": "node mcp/dashboard-gen.js",
36
36
  "dashboard:public": "node mcp/dashboard-gen.js --public",
37
37
  "fixture": "node test-sandbox/fixtures/demo-project.js",
38
- "test": "node test-sandbox/id-generation.test.js && node test-sandbox/step-loop.test.js && node test-sandbox/mcp-core.test.js && node test-sandbox/neutral-format.test.js && node test-sandbox/atomicity.test.js && node test-sandbox/metrics.test.js && node test-sandbox/usage.test.js && node test-sandbox/fix-0001-docs.test.js && node test-sandbox/ci-workflow.test.js && node test-sandbox/interop.test.js && node test-sandbox/cli.test.js && node test-sandbox/fixture-project.test.js && node test-sandbox/split.test.js && node test-sandbox/reconcile.test.js && node test-sandbox/review.test.js && node test-sandbox/publish.test.js && node test-sandbox/multilayer-verifier.test.js && node test-sandbox/escrow.test.js && node test-sandbox/mcp-client-e2e.js",
39
- "prepublishOnly": "npm test"
38
+ "test": "node test-sandbox/id-generation.test.js && node test-sandbox/step-loop.test.js && node test-sandbox/mcp-core.test.js && node test-sandbox/neutral-format.test.js && node test-sandbox/atomicity.test.js && node test-sandbox/metrics.test.js && node test-sandbox/usage.test.js && node test-sandbox/fix-0001-docs.test.js && node test-sandbox/ci-workflow.test.js && node test-sandbox/interop.test.js && node test-sandbox/cli.test.js && node test-sandbox/fixture-project.test.js && node test-sandbox/split.test.js && node test-sandbox/reconcile.test.js && node test-sandbox/review.test.js && node test-sandbox/publish.test.js && node test-sandbox/doctor.test.js && node test-sandbox/orchestrator-docs.test.js && node test-sandbox/multilayer-verifier.test.js && node test-sandbox/escrow.test.js && node test-sandbox/mcp-client-e2e.js",
39
+ "prepublishOnly": "npm test && node scripts/release.js --check",
40
+ "release:check": "node scripts/release.js --check",
41
+ "release:prepare": "node scripts/release.js"
40
42
  },
41
43
  "keywords": [
42
44
  "mcp",