sdd-gl 0.6.1 → 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 +1 -1
- package/README.md +1 -1
- package/bin/sdd.js +15 -3
- package/mcp/server.js +23 -5
- package/package.json +2 -2
package/README.es.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/sdd-gl)
|
|
6
|
-
[](CHANGELOG.md)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](mcp/sdd-gl-mcp-spec.md)
|
|
9
9
|
[](https://docs.claude.ai/code)
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/sdd-gl)
|
|
6
|
-
[](CHANGELOG.md)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](mcp/sdd-gl-mcp-spec.md)
|
|
9
9
|
[](https://docs.claude.ai/code)
|
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
|
-
|
|
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',
|
|
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 =
|
|
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 =
|
|
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
|
-
?
|
|
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.
|
|
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,7 +35,7 @@
|
|
|
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",
|
|
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
39
|
"prepublishOnly": "npm test && node scripts/release.js --check",
|
|
40
40
|
"release:check": "node scripts/release.js --check",
|
|
41
41
|
"release:prepare": "node scripts/release.js"
|