delimit-cli 3.14.0 → 3.14.1
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/bin/delimit-cli.js +165 -0
- package/package.json +1 -1
package/bin/delimit-cli.js
CHANGED
|
@@ -5,6 +5,7 @@ const axios = require('axios');
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { execSync, spawn } = require('child_process');
|
|
8
|
+
const os = require('os');
|
|
8
9
|
const chalk = require('chalk');
|
|
9
10
|
const inquirer = require('inquirer');
|
|
10
11
|
const DelimitAuthSetup = require('../lib/auth-setup');
|
|
@@ -1334,6 +1335,170 @@ jobs:
|
|
|
1334
1335
|
console.log('');
|
|
1335
1336
|
});
|
|
1336
1337
|
|
|
1338
|
+
// Demo command — prove governance value in 5 minutes (LED-262)
|
|
1339
|
+
program
|
|
1340
|
+
.command('demo')
|
|
1341
|
+
.description('Run a self-contained governance demo — proves value in under 5 minutes')
|
|
1342
|
+
.action(async () => {
|
|
1343
|
+
const tmpDir = path.join(os.tmpdir(), `delimit-demo-${Date.now()}`);
|
|
1344
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
1345
|
+
|
|
1346
|
+
console.log(chalk.bold('\n Delimit Governance Demo\n'));
|
|
1347
|
+
console.log(chalk.gray(` Working in ${tmpDir}\n`));
|
|
1348
|
+
|
|
1349
|
+
// Step 1: Create a sample API spec
|
|
1350
|
+
console.log(chalk.bold(' Step 1: Creating sample API spec...'));
|
|
1351
|
+
const baseSpec = {
|
|
1352
|
+
openapi: '3.0.3',
|
|
1353
|
+
info: { title: 'Pet Store API', version: '1.0.0' },
|
|
1354
|
+
paths: {
|
|
1355
|
+
'/pets': {
|
|
1356
|
+
get: {
|
|
1357
|
+
summary: 'List all pets',
|
|
1358
|
+
operationId: 'listPets',
|
|
1359
|
+
parameters: [
|
|
1360
|
+
{ name: 'limit', in: 'query', required: false, schema: { type: 'integer' } },
|
|
1361
|
+
],
|
|
1362
|
+
responses: { '200': { description: 'A list of pets', content: { 'application/json': { schema: { type: 'array', items: { '$ref': '#/components/schemas/Pet' } } } } } },
|
|
1363
|
+
},
|
|
1364
|
+
post: {
|
|
1365
|
+
summary: 'Create a pet',
|
|
1366
|
+
operationId: 'createPet',
|
|
1367
|
+
requestBody: { content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } },
|
|
1368
|
+
responses: { '201': { description: 'Pet created' } },
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
'/pets/{petId}': {
|
|
1372
|
+
get: {
|
|
1373
|
+
summary: 'Get a pet by ID',
|
|
1374
|
+
operationId: 'showPetById',
|
|
1375
|
+
parameters: [{ name: 'petId', in: 'path', required: true, schema: { type: 'string' } }],
|
|
1376
|
+
responses: { '200': { description: 'A pet', content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } } },
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
components: {
|
|
1381
|
+
schemas: {
|
|
1382
|
+
Pet: {
|
|
1383
|
+
type: 'object',
|
|
1384
|
+
required: ['id', 'name'],
|
|
1385
|
+
properties: {
|
|
1386
|
+
id: { type: 'integer', format: 'int64' },
|
|
1387
|
+
name: { type: 'string' },
|
|
1388
|
+
tag: { type: 'string' },
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
},
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1395
|
+
const baseSpecPath = path.join(tmpDir, 'openapi-v1.yaml');
|
|
1396
|
+
fs.writeFileSync(baseSpecPath, yaml.dump(baseSpec));
|
|
1397
|
+
console.log(chalk.green(' Created openapi-v1.yaml (3 endpoints, 1 schema)\n'));
|
|
1398
|
+
|
|
1399
|
+
// Step 2: Introduce breaking changes
|
|
1400
|
+
console.log(chalk.bold(' Step 2: Introducing breaking changes...'));
|
|
1401
|
+
const changedSpec = JSON.parse(JSON.stringify(baseSpec));
|
|
1402
|
+
changedSpec.info.version = '2.0.0';
|
|
1403
|
+
|
|
1404
|
+
// Breaking: remove endpoint
|
|
1405
|
+
delete changedSpec.paths['/pets/{petId}'];
|
|
1406
|
+
// Breaking: add required parameter
|
|
1407
|
+
changedSpec.paths['/pets'].get.parameters.push(
|
|
1408
|
+
{ name: 'owner_id', in: 'query', required: true, schema: { type: 'string' } }
|
|
1409
|
+
);
|
|
1410
|
+
// Breaking: remove response field
|
|
1411
|
+
delete changedSpec.components.schemas.Pet.properties.tag;
|
|
1412
|
+
// Non-breaking: add endpoint
|
|
1413
|
+
changedSpec.paths['/pets/search'] = {
|
|
1414
|
+
get: {
|
|
1415
|
+
summary: 'Search pets',
|
|
1416
|
+
operationId: 'searchPets',
|
|
1417
|
+
parameters: [{ name: 'q', in: 'query', required: true, schema: { type: 'string' } }],
|
|
1418
|
+
responses: { '200': { description: 'Search results' } },
|
|
1419
|
+
},
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
const changedSpecPath = path.join(tmpDir, 'openapi-v2.yaml');
|
|
1423
|
+
fs.writeFileSync(changedSpecPath, yaml.dump(changedSpec));
|
|
1424
|
+
console.log(chalk.red(' Removed: GET /pets/{petId}'));
|
|
1425
|
+
console.log(chalk.red(' Added required param: owner_id on GET /pets'));
|
|
1426
|
+
console.log(chalk.red(' Removed field: Pet.tag'));
|
|
1427
|
+
console.log(chalk.green(' Added: GET /pets/search'));
|
|
1428
|
+
console.log('');
|
|
1429
|
+
|
|
1430
|
+
// Step 3: Run Delimit lint
|
|
1431
|
+
console.log(chalk.bold(' Step 3: Running governance check...\n'));
|
|
1432
|
+
try {
|
|
1433
|
+
const result = apiEngine.lint(baseSpecPath, changedSpecPath, { policy: 'strict' });
|
|
1434
|
+
|
|
1435
|
+
if (result && result.summary) {
|
|
1436
|
+
const s = result.summary;
|
|
1437
|
+
const breaking = s.breaking || s.breaking_changes || 0;
|
|
1438
|
+
const total = s.total || s.total_changes || 0;
|
|
1439
|
+
const safe = total - breaking;
|
|
1440
|
+
|
|
1441
|
+
if (breaking > 0) {
|
|
1442
|
+
console.log(chalk.red.bold(` BLOCKED — ${breaking} breaking change(s) detected\n`));
|
|
1443
|
+
} else {
|
|
1444
|
+
console.log(chalk.green.bold(` PASSED — No breaking changes\n`));
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Show violations
|
|
1448
|
+
const violations = result.violations || [];
|
|
1449
|
+
if (violations.length > 0) {
|
|
1450
|
+
console.log(chalk.bold(' Violations:'));
|
|
1451
|
+
violations.forEach((v, i) => {
|
|
1452
|
+
const icon = v.severity === 'error' ? chalk.red(' BLOCK') : chalk.yellow(' WARN ');
|
|
1453
|
+
console.log(` ${icon} ${v.message}`);
|
|
1454
|
+
if (v.path) console.log(chalk.gray(` ${v.path}`));
|
|
1455
|
+
});
|
|
1456
|
+
console.log('');
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// Semver
|
|
1460
|
+
if (result.semver) {
|
|
1461
|
+
console.log(` Semver: ${chalk.bold(result.semver.bump?.toUpperCase() || 'MAJOR')}`);
|
|
1462
|
+
if (result.semver.next_version) {
|
|
1463
|
+
console.log(` Next version: ${chalk.bold(result.semver.next_version)}`);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// Show safe changes
|
|
1468
|
+
if (safe > 0) {
|
|
1469
|
+
console.log(chalk.green(`\n ${safe} additive change(s) also detected`));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
console.log(chalk.yellow(` Lint error: ${err.message}`));
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// Step 4: Show governance gates
|
|
1477
|
+
console.log(chalk.bold('\n Governance Gates:'));
|
|
1478
|
+
console.log(` ${chalk.red('X')} API Lint ${chalk.gray('→ semver → gov_evaluate')}`);
|
|
1479
|
+
console.log(` ${chalk.red('X')} Policy Compliance ${chalk.gray('→ evidence_collect')}`);
|
|
1480
|
+
console.log(` ${chalk.green('+')} Security Audit ${chalk.gray('→ evidence_collect → notify')}`);
|
|
1481
|
+
console.log(` ${chalk.red('X')} Deploy Readiness ${chalk.gray('→ deploy_plan → security_audit')}`);
|
|
1482
|
+
console.log(chalk.red.bold('\n Deploy BLOCKED until all gates pass.\n'));
|
|
1483
|
+
|
|
1484
|
+
// Step 5: Show what would happen with the fix
|
|
1485
|
+
console.log(chalk.bold(' What Delimit does:'));
|
|
1486
|
+
console.log(chalk.gray(' 1. Detects the 3 breaking changes automatically'));
|
|
1487
|
+
console.log(chalk.gray(' 2. Evaluates against your policy (strict/default/relaxed)'));
|
|
1488
|
+
console.log(chalk.gray(' 3. Blocks the deploy via governance gates'));
|
|
1489
|
+
console.log(chalk.gray(' 4. Records evidence for audit trail'));
|
|
1490
|
+
console.log(chalk.gray(' 5. Posts remediation guide on the PR'));
|
|
1491
|
+
console.log(chalk.gray(' 6. Tracks in the ledger for cross-model continuity'));
|
|
1492
|
+
|
|
1493
|
+
console.log(chalk.bold('\n Try it on your project:'));
|
|
1494
|
+
console.log(` ${chalk.green('npx delimit-cli init')} — set up governance`);
|
|
1495
|
+
console.log(` ${chalk.green('npx delimit-cli lint')} — lint your API spec`);
|
|
1496
|
+
console.log(` ${chalk.green('npx delimit-cli setup')} — configure AI assistants\n`);
|
|
1497
|
+
|
|
1498
|
+
// Cleanup
|
|
1499
|
+
try { fs.rmSync(tmpDir, { recursive: true }); } catch {}
|
|
1500
|
+
});
|
|
1501
|
+
|
|
1337
1502
|
// Doctor command — verify setup is correct
|
|
1338
1503
|
program
|
|
1339
1504
|
.command('doctor')
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "delimit-cli",
|
|
3
3
|
"mcpName": "io.github.delimit-ai/delimit-mcp-server",
|
|
4
|
-
"version": "3.14.
|
|
4
|
+
"version": "3.14.1",
|
|
5
5
|
"description": "Unify Claude Code, Codex, Cursor, and Gemini CLI with persistent context, governance, and multi-model debate.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|