delimit-cli 2.2.0 → 2.3.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.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # delimit-cli
2
2
 
3
- **ESLint for API contracts** — detect breaking changes, enforce semver, and generate migration guides for OpenAPI specs.
3
+ **Prevent breaking API changes before they reach production.**
4
+
5
+ Deterministic diff engine + policy enforcement + semver classification for OpenAPI specs. The independent successor to Optic.
4
6
 
5
7
  [![npm](https://img.shields.io/npm/v/delimit-cli)](https://www.npmjs.com/package/delimit-cli)
6
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
@@ -11,46 +13,76 @@
11
13
  npm install -g delimit-cli
12
14
  ```
13
15
 
14
- This installs the `delimit` command globally.
15
-
16
- ## Quick Start
16
+ ## Quick Start (Under 5 Minutes)
17
17
 
18
18
  ```bash
19
- # Initialize a policy file in your repo
20
- delimit init
19
+ # 1. Initialize with a policy preset
20
+ delimit init --preset default
21
21
 
22
- # Detect breaking changes between two specs
22
+ # 2. Detect breaking changes
23
23
  delimit lint api/openapi-old.yaml api/openapi-new.yaml
24
24
 
25
- # See raw diff output
26
- delimit diff api/openapi-old.yaml api/openapi-new.yaml
27
-
28
- # Generate a human-readable explanation
29
- delimit explain api/openapi-old.yaml api/openapi-new.yaml
25
+ # 3. Add the GitHub Action for automated PR checks
26
+ # Copy .github/workflows/api-governance.yml (see CI section below)
30
27
  ```
31
28
 
29
+ ## What It Catches
30
+
31
+ Delimit deterministically detects 23 types of API changes, including 10 breaking patterns:
32
+
33
+ - Endpoint or method removal
34
+ - Required parameter addition
35
+ - Response field removal
36
+ - Type changes
37
+ - Enum value removal
38
+ - And more
39
+
40
+ Every change is classified as `MAJOR`, `MINOR`, `PATCH`, or `NONE` per semver.
41
+
32
42
  ## Commands
33
43
 
34
44
  | Command | Description |
35
45
  |---------|-------------|
36
- | `delimit init` | Create `.delimit/policies.yml` with default rules |
37
- | `delimit lint <old> <new>` | Diff + policy check with semver badge and violations |
46
+ | `delimit init` | Create `.delimit/policies.yml` with a policy preset |
47
+ | `delimit lint <old> <new>` | Diff + policy check returns exit code 1 on violations |
38
48
  | `delimit diff <old> <new>` | Raw diff with `[BREAKING]`/`[safe]` tags |
39
49
  | `delimit explain <old> <new>` | Human-readable change explanation |
40
50
 
41
- ### Options
51
+ ## Policy Presets
52
+
53
+ Choose a preset that fits your team:
54
+
55
+ ```bash
56
+ delimit init --preset strict # Public APIs, payments — zero tolerance
57
+ delimit init --preset default # Most teams — balanced rules
58
+ delimit init --preset relaxed # Internal APIs, startups — warnings only
59
+ ```
60
+
61
+ | Preset | Breaking changes | Type changes | Field removal |
62
+ |--------|-----------------|--------------|---------------|
63
+ | `strict` | Error (blocks) | Error (blocks) | Error (blocks) |
64
+ | `default` | Error (blocks) | Warning | Error (blocks) |
65
+ | `relaxed` | Warning | Warning | Info |
66
+
67
+ Pass a preset directly to lint:
68
+
69
+ ```bash
70
+ delimit lint --policy strict old.yaml new.yaml
71
+ ```
72
+
73
+ ## Options
42
74
 
43
75
  ```bash
44
- # Specify explainer template (default: developer)
76
+ # Semver classification with version bump
77
+ delimit lint old.yaml new.yaml --current-version 1.0.0
78
+
79
+ # Explainer templates
45
80
  delimit explain old.yaml new.yaml -t migration
46
81
  delimit explain old.yaml new.yaml -t pr_comment
47
82
  delimit explain old.yaml new.yaml -t changelog
48
83
 
49
- # Include semver classification
50
- delimit lint old.yaml new.yaml --current-version 1.0.0
51
-
52
- # Use custom policy file
53
- delimit lint old.yaml new.yaml -p .delimit/policies.yml
84
+ # JSON output for scripting
85
+ delimit lint old.yaml new.yaml --json
54
86
  ```
55
87
 
56
88
  ### Explainer Templates
@@ -67,34 +99,56 @@ delimit lint old.yaml new.yaml -p .delimit/policies.yml
67
99
 
68
100
  ## CI/CD Integration
69
101
 
70
- For automated PR checks, use the GitHub Action:
102
+ Add this workflow to `.github/workflows/api-governance.yml`:
71
103
 
72
104
  ```yaml
73
- - uses: delimit-ai/delimit-action@v1
74
- with:
75
- old_spec: base/api/openapi.yaml
76
- new_spec: api/openapi.yaml
105
+ name: API Governance
106
+ on:
107
+ pull_request:
108
+ paths:
109
+ - 'path/to/openapi.yaml' # adjust to your spec path
110
+ permissions:
111
+ contents: read
112
+ pull-requests: write
113
+ jobs:
114
+ api-governance:
115
+ runs-on: ubuntu-latest
116
+ steps:
117
+ - uses: actions/checkout@v4
118
+ - uses: actions/checkout@v4
119
+ with:
120
+ ref: ${{ github.event.pull_request.base.sha }}
121
+ path: _base
122
+ - uses: delimit-ai/delimit@v1
123
+ with:
124
+ old_spec: _base/path/to/openapi.yaml
125
+ new_spec: path/to/openapi.yaml
126
+ mode: advisory # or 'enforce' to block PRs
77
127
  ```
78
128
 
129
+ The action posts a PR comment with:
130
+ - Semver badge (`MAJOR` / `MINOR` / `PATCH`)
131
+ - Violation table with severity
132
+ - Expandable migration guide for breaking changes
133
+
79
134
  See [Delimit API Governance](https://github.com/marketplace/actions/delimit-api-governance) on the GitHub Marketplace.
80
135
 
81
136
  ## Custom Policies
82
137
 
83
- Create `.delimit/policies.yml`:
138
+ Create `.delimit/policies.yml` or start from a preset:
84
139
 
85
140
  ```yaml
141
+ override_defaults: false
142
+
86
143
  rules:
87
- - id: no_endpoint_removal
88
- change_types: [endpoint_removed]
144
+ - id: protect_v1
145
+ name: Protect V1 API
146
+ change_types: [endpoint_removed, method_removed, field_removed]
89
147
  severity: error
90
148
  action: forbid
91
- message: "Endpoints cannot be removed without deprecation"
92
-
93
- - id: warn_type_change
94
- change_types: [type_changed]
95
- severity: warning
96
- action: warn
97
- message: "Type change may break clients"
149
+ conditions:
150
+ path_pattern: "^/v1/.*"
151
+ message: "V1 API is frozen. Make changes in V2."
98
152
  ```
99
153
 
100
154
  ## Supported Specs
@@ -105,7 +159,7 @@ rules:
105
159
 
106
160
  ## Links
107
161
 
108
- - [GitHub Action](https://github.com/marketplace/actions/delimit-api-governance) — CI/CD integration
162
+ - [GitHub Action](https://github.com/marketplace/actions/delimit-api-governance) — Automated PR checks
109
163
  - [GitHub](https://github.com/delimit-ai/delimit) — Source code
110
164
  - [Issues](https://github.com/delimit-ai/delimit/issues) — Bug reports and feature requests
111
165
 
@@ -741,29 +741,72 @@ program
741
741
 
742
742
  const apiEngine = require('../lib/api-engine');
743
743
 
744
- // Init command — scaffold .delimit/ config
745
- program
746
- .command('init')
747
- .description('Initialize Delimit API governance in this project')
748
- .action(async () => {
749
- const configDir = path.join(process.cwd(), '.delimit');
750
- const policyFile = path.join(configDir, 'policies.yml');
744
+ // Policy preset templates
745
+ const POLICY_PRESETS = {
746
+ strict: `# Delimit Policy Preset: strict
747
+ # For public APIs, payment systems, and regulated environments.
748
+ # Zero tolerance for breaking changes.
751
749
 
752
- if (fs.existsSync(policyFile)) {
753
- console.log(chalk.yellow('Already initialized — .delimit/policies.yml exists'));
754
- return;
755
- }
750
+ override_defaults: true
756
751
 
757
- fs.mkdirSync(configDir, { recursive: true });
752
+ rules:
753
+ - id: no_endpoint_removal
754
+ name: Forbid Endpoint Removal
755
+ change_types: [endpoint_removed]
756
+ severity: error
757
+ action: forbid
758
+ message: "Endpoint {path} cannot be removed. Deprecate with Sunset header first."
759
+
760
+ - id: no_method_removal
761
+ name: Forbid Method Removal
762
+ change_types: [method_removed]
763
+ severity: error
764
+ action: forbid
765
+ message: "HTTP method removed from {path}. This breaks all clients."
766
+
767
+ - id: no_required_param_addition
768
+ name: Forbid Required Parameter Addition
769
+ change_types: [required_param_added]
770
+ severity: error
771
+ action: forbid
772
+ message: "Cannot add required parameter to {path}. Make it optional."
773
+
774
+ - id: no_field_removal
775
+ name: Forbid Response Field Removal
776
+ change_types: [field_removed]
777
+ severity: error
778
+ action: forbid
779
+ message: "Cannot remove field from {path}. Deprecate it first."
780
+
781
+ - id: no_type_change
782
+ name: Forbid Type Changes
783
+ change_types: [type_changed]
784
+ severity: error
785
+ action: forbid
786
+ message: "Type change at {path} breaks client deserialization."
787
+
788
+ - id: no_enum_removal
789
+ name: Forbid Enum Value Removal
790
+ change_types: [enum_value_removed]
791
+ severity: error
792
+ action: forbid
793
+ message: "Enum value removed at {path}."
758
794
 
759
- const template = `# Delimit API Governance Policy
760
- # https://github.com/delimit-ai/delimit
795
+ - id: no_param_removal
796
+ name: Forbid Parameter Removal
797
+ change_types: [param_removed]
798
+ severity: error
799
+ action: forbid
800
+ message: "Parameter removed from {path}."
801
+ `,
802
+ default: `# Delimit Policy Preset: default
803
+ # Balanced rules for most teams. Blocks destructive changes, warns on risky ones.
804
+ # Uses built-in defaults — customize by adding rules below.
761
805
 
762
- # Override built-in rules (default: false)
763
806
  override_defaults: false
764
807
 
765
808
  rules: []
766
- # Example:
809
+ # Add custom rules here. Example:
767
810
  # - id: protect_v1
768
811
  # name: Protect V1 API
769
812
  # change_types: [endpoint_removed, method_removed, field_removed]
@@ -772,9 +815,80 @@ rules: []
772
815
  # conditions:
773
816
  # path_pattern: "^/v1/.*"
774
817
  # message: "V1 API is frozen. Make changes in V2."
775
- `;
776
- fs.writeFileSync(policyFile, template);
777
- console.log(chalk.green('Created .delimit/policies.yml'));
818
+ `,
819
+ relaxed: `# Delimit Policy Preset: relaxed
820
+ # For internal APIs, early-stage startups, and rapid iteration.
821
+ # Only warns — never blocks CI.
822
+
823
+ override_defaults: true
824
+
825
+ rules:
826
+ - id: warn_endpoint_removal
827
+ name: Warn on Endpoint Removal
828
+ change_types: [endpoint_removed]
829
+ severity: warning
830
+ action: warn
831
+ message: "Endpoint {path} was removed. Check downstream consumers."
832
+
833
+ - id: warn_method_removal
834
+ name: Warn on Method Removal
835
+ change_types: [method_removed]
836
+ severity: warning
837
+ action: warn
838
+ message: "HTTP method removed from {path}."
839
+
840
+ - id: warn_required_param
841
+ name: Warn on Required Parameter Addition
842
+ change_types: [required_param_added]
843
+ severity: warning
844
+ action: warn
845
+ message: "New required parameter at {path}."
846
+
847
+ - id: warn_type_change
848
+ name: Warn on Type Changes
849
+ change_types: [type_changed]
850
+ severity: warning
851
+ action: warn
852
+ message: "Type changed at {path}."
853
+
854
+ - id: allow_field_removal
855
+ name: Allow Field Removal
856
+ change_types: [field_removed]
857
+ severity: info
858
+ action: allow
859
+ message: "Field removed from {path}."
860
+ `,
861
+ };
862
+
863
+ // Init command — scaffold .delimit/ config
864
+ program
865
+ .command('init')
866
+ .description('Initialize Delimit API governance in this project')
867
+ .option('--preset <name>', 'Policy preset: strict, default, or relaxed', 'default')
868
+ .action(async (options) => {
869
+ const configDir = path.join(process.cwd(), '.delimit');
870
+ const policyFile = path.join(configDir, 'policies.yml');
871
+
872
+ if (fs.existsSync(policyFile)) {
873
+ console.log(chalk.yellow('Already initialized — .delimit/policies.yml exists'));
874
+ return;
875
+ }
876
+
877
+ const preset = options.preset.toLowerCase();
878
+ if (!POLICY_PRESETS[preset]) {
879
+ console.log(chalk.red(`Unknown preset "${preset}". Choose: strict, default, or relaxed`));
880
+ return;
881
+ }
882
+
883
+ fs.mkdirSync(configDir, { recursive: true });
884
+ fs.writeFileSync(policyFile, POLICY_PRESETS[preset]);
885
+ console.log(chalk.green(`Created .delimit/policies.yml (preset: ${preset})`));
886
+ console.log('');
887
+ console.log(` ${chalk.bold('strict')} — zero tolerance, all breaking changes are errors`);
888
+ console.log(` ${chalk.bold('default')} — balanced, blocks destructive changes, warns on risky`);
889
+ console.log(` ${chalk.bold('relaxed')} — warnings only, never blocks CI`);
890
+ console.log('');
891
+ console.log(`Switch preset: ${chalk.bold('delimit init --preset strict')}`);
778
892
  console.log('');
779
893
  console.log('Next steps:');
780
894
  console.log(` ${chalk.bold('delimit lint')} old.yaml new.yaml — check for breaking changes`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "delimit-cli",
3
- "version": "2.2.0",
4
- "description": "ESLint for API contracts detect breaking changes, enforce semver, and generate migration guides for OpenAPI specs",
3
+ "version": "2.3.0",
4
+ "description": "Prevent breaking API changes before they reach production. Deterministic diff engine + policy enforcement + semver classification.",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "delimit": "./bin/delimit-cli.js"