delimit-cli 3.14.0 → 3.14.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.
Files changed (2) hide show
  1. package/bin/delimit-cli.js +204 -0
  2. package/package.json +1 -1
@@ -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');
@@ -1331,7 +1332,210 @@ jobs:
1331
1332
  }
1332
1333
  console.log(` ${chalk.bold('delimit doctor')} — verify setup`);
1333
1334
  console.log(` ${chalk.bold('delimit explain')} — human-readable report`);
1335
+
1336
+ // Beta capture after init (LED-263)
1337
+ if (!options.yes) {
1338
+ try {
1339
+ const betaAns = await inquirer.prompt([{
1340
+ type: 'input',
1341
+ name: 'email',
1342
+ message: chalk.blue(' Join the beta? Enter your email (or press Enter to skip):'),
1343
+ }]);
1344
+ if (betaAns.email && betaAns.email.includes('@')) {
1345
+ try {
1346
+ await axios.post('https://delimit.ai/api/subscribe', { email: betaAns.email, source: 'cli-init' });
1347
+ console.log(chalk.green(' Thanks! You\'re on the list.\n'));
1348
+ } catch {
1349
+ console.log(chalk.green(' Thanks! Visit https://delimit.ai to stay updated.\n'));
1350
+ }
1351
+ } else {
1352
+ console.log('');
1353
+ }
1354
+ } catch {}
1355
+ } else {
1356
+ console.log('');
1357
+ }
1358
+ });
1359
+
1360
+ // Demo command — prove governance value in 5 minutes (LED-262)
1361
+ program
1362
+ .command('demo')
1363
+ .description('Run a self-contained governance demo — proves value in under 5 minutes')
1364
+ .action(async () => {
1365
+ const tmpDir = path.join(os.tmpdir(), `delimit-demo-${Date.now()}`);
1366
+ fs.mkdirSync(tmpDir, { recursive: true });
1367
+
1368
+ console.log(chalk.bold('\n Delimit Governance Demo\n'));
1369
+ console.log(chalk.gray(` Working in ${tmpDir}\n`));
1370
+
1371
+ // Step 1: Create a sample API spec
1372
+ console.log(chalk.bold(' Step 1: Creating sample API spec...'));
1373
+ const baseSpec = {
1374
+ openapi: '3.0.3',
1375
+ info: { title: 'Pet Store API', version: '1.0.0' },
1376
+ paths: {
1377
+ '/pets': {
1378
+ get: {
1379
+ summary: 'List all pets',
1380
+ operationId: 'listPets',
1381
+ parameters: [
1382
+ { name: 'limit', in: 'query', required: false, schema: { type: 'integer' } },
1383
+ ],
1384
+ responses: { '200': { description: 'A list of pets', content: { 'application/json': { schema: { type: 'array', items: { '$ref': '#/components/schemas/Pet' } } } } } },
1385
+ },
1386
+ post: {
1387
+ summary: 'Create a pet',
1388
+ operationId: 'createPet',
1389
+ requestBody: { content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } },
1390
+ responses: { '201': { description: 'Pet created' } },
1391
+ },
1392
+ },
1393
+ '/pets/{petId}': {
1394
+ get: {
1395
+ summary: 'Get a pet by ID',
1396
+ operationId: 'showPetById',
1397
+ parameters: [{ name: 'petId', in: 'path', required: true, schema: { type: 'string' } }],
1398
+ responses: { '200': { description: 'A pet', content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } } },
1399
+ },
1400
+ },
1401
+ },
1402
+ components: {
1403
+ schemas: {
1404
+ Pet: {
1405
+ type: 'object',
1406
+ required: ['id', 'name'],
1407
+ properties: {
1408
+ id: { type: 'integer', format: 'int64' },
1409
+ name: { type: 'string' },
1410
+ tag: { type: 'string' },
1411
+ },
1412
+ },
1413
+ },
1414
+ },
1415
+ };
1416
+
1417
+ const baseSpecPath = path.join(tmpDir, 'openapi-v1.yaml');
1418
+ fs.writeFileSync(baseSpecPath, yaml.dump(baseSpec));
1419
+ console.log(chalk.green(' Created openapi-v1.yaml (3 endpoints, 1 schema)\n'));
1420
+
1421
+ // Step 2: Introduce breaking changes
1422
+ console.log(chalk.bold(' Step 2: Introducing breaking changes...'));
1423
+ const changedSpec = JSON.parse(JSON.stringify(baseSpec));
1424
+ changedSpec.info.version = '2.0.0';
1425
+
1426
+ // Breaking: remove endpoint
1427
+ delete changedSpec.paths['/pets/{petId}'];
1428
+ // Breaking: add required parameter
1429
+ changedSpec.paths['/pets'].get.parameters.push(
1430
+ { name: 'owner_id', in: 'query', required: true, schema: { type: 'string' } }
1431
+ );
1432
+ // Breaking: remove response field
1433
+ delete changedSpec.components.schemas.Pet.properties.tag;
1434
+ // Non-breaking: add endpoint
1435
+ changedSpec.paths['/pets/search'] = {
1436
+ get: {
1437
+ summary: 'Search pets',
1438
+ operationId: 'searchPets',
1439
+ parameters: [{ name: 'q', in: 'query', required: true, schema: { type: 'string' } }],
1440
+ responses: { '200': { description: 'Search results' } },
1441
+ },
1442
+ };
1443
+
1444
+ const changedSpecPath = path.join(tmpDir, 'openapi-v2.yaml');
1445
+ fs.writeFileSync(changedSpecPath, yaml.dump(changedSpec));
1446
+ console.log(chalk.red(' Removed: GET /pets/{petId}'));
1447
+ console.log(chalk.red(' Added required param: owner_id on GET /pets'));
1448
+ console.log(chalk.red(' Removed field: Pet.tag'));
1449
+ console.log(chalk.green(' Added: GET /pets/search'));
1334
1450
  console.log('');
1451
+
1452
+ // Step 3: Run Delimit lint
1453
+ console.log(chalk.bold(' Step 3: Running governance check...\n'));
1454
+ try {
1455
+ const result = apiEngine.lint(baseSpecPath, changedSpecPath, { policy: 'strict' });
1456
+
1457
+ if (result && result.summary) {
1458
+ const s = result.summary;
1459
+ const breaking = s.breaking || s.breaking_changes || 0;
1460
+ const total = s.total || s.total_changes || 0;
1461
+ const safe = total - breaking;
1462
+
1463
+ if (breaking > 0) {
1464
+ console.log(chalk.red.bold(` BLOCKED — ${breaking} breaking change(s) detected\n`));
1465
+ } else {
1466
+ console.log(chalk.green.bold(` PASSED — No breaking changes\n`));
1467
+ }
1468
+
1469
+ // Show violations
1470
+ const violations = result.violations || [];
1471
+ if (violations.length > 0) {
1472
+ console.log(chalk.bold(' Violations:'));
1473
+ violations.forEach((v, i) => {
1474
+ const icon = v.severity === 'error' ? chalk.red(' BLOCK') : chalk.yellow(' WARN ');
1475
+ console.log(` ${icon} ${v.message}`);
1476
+ if (v.path) console.log(chalk.gray(` ${v.path}`));
1477
+ });
1478
+ console.log('');
1479
+ }
1480
+
1481
+ // Semver
1482
+ if (result.semver) {
1483
+ console.log(` Semver: ${chalk.bold(result.semver.bump?.toUpperCase() || 'MAJOR')}`);
1484
+ if (result.semver.next_version) {
1485
+ console.log(` Next version: ${chalk.bold(result.semver.next_version)}`);
1486
+ }
1487
+ }
1488
+
1489
+ // Show safe changes
1490
+ if (safe > 0) {
1491
+ console.log(chalk.green(`\n ${safe} additive change(s) also detected`));
1492
+ }
1493
+ }
1494
+ } catch (err) {
1495
+ console.log(chalk.yellow(` Lint error: ${err.message}`));
1496
+ }
1497
+
1498
+ // Step 4: Show governance gates
1499
+ console.log(chalk.bold('\n Governance Gates:'));
1500
+ console.log(` ${chalk.red('X')} API Lint ${chalk.gray('→ semver → gov_evaluate')}`);
1501
+ console.log(` ${chalk.red('X')} Policy Compliance ${chalk.gray('→ evidence_collect')}`);
1502
+ console.log(` ${chalk.green('+')} Security Audit ${chalk.gray('→ evidence_collect → notify')}`);
1503
+ console.log(` ${chalk.red('X')} Deploy Readiness ${chalk.gray('→ deploy_plan → security_audit')}`);
1504
+ console.log(chalk.red.bold('\n Deploy BLOCKED until all gates pass.\n'));
1505
+
1506
+ // Step 5: Show what would happen with the fix
1507
+ console.log(chalk.bold(' What Delimit does:'));
1508
+ console.log(chalk.gray(' 1. Detects the 3 breaking changes automatically'));
1509
+ console.log(chalk.gray(' 2. Evaluates against your policy (strict/default/relaxed)'));
1510
+ console.log(chalk.gray(' 3. Blocks the deploy via governance gates'));
1511
+ console.log(chalk.gray(' 4. Records evidence for audit trail'));
1512
+ console.log(chalk.gray(' 5. Posts remediation guide on the PR'));
1513
+ console.log(chalk.gray(' 6. Tracks in the ledger for cross-model continuity'));
1514
+
1515
+ console.log(chalk.bold('\n Try it on your project:'));
1516
+ console.log(` ${chalk.green('npx delimit-cli init')} — set up governance`);
1517
+ console.log(` ${chalk.green('npx delimit-cli lint')} — lint your API spec`);
1518
+ console.log(` ${chalk.green('npx delimit-cli setup')} — configure AI assistants\n`);
1519
+
1520
+ // Beta capture (LED-263)
1521
+ try {
1522
+ const betaAns = await inquirer.prompt([{
1523
+ type: 'input',
1524
+ name: 'email',
1525
+ message: chalk.blue('Join the beta? Enter your email (or press Enter to skip):'),
1526
+ }]);
1527
+ if (betaAns.email && betaAns.email.includes('@')) {
1528
+ try {
1529
+ await axios.post('https://delimit.ai/api/subscribe', { email: betaAns.email, source: 'cli-demo' });
1530
+ console.log(chalk.green('\n Thanks! You\'re on the list. We\'ll keep you in the loop.\n'));
1531
+ } catch {
1532
+ console.log(chalk.green('\n Thanks! Visit https://delimit.ai to stay updated.\n'));
1533
+ }
1534
+ }
1535
+ } catch {}
1536
+
1537
+ // Cleanup
1538
+ try { fs.rmSync(tmpDir, { recursive: true }); } catch {}
1335
1539
  });
1336
1540
 
1337
1541
  // Doctor command — verify setup is correct
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.0",
4
+ "version": "3.14.2",
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": [