specshield 3.3.1 → 3.3.3

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
@@ -55,6 +55,8 @@ OpenAPI diff + contract compatibility checks + HAR → consumer contract +
55
55
 
56
56
  No broker. No Pact DSL. Language-agnostic. Works in 30 seconds. Local mode never uploads your specs.
57
57
 
58
+ > 🤖 **Using an AI coding agent?** The [SpecShield MCP server](https://github.com/specshield26/specshield-mcp-server) brings the same `can-i-deploy` deploy gate into Claude, Cursor, and other MCP clients — ask *"is it safe to ship this API change to my consumers?"* right inside your agent. Same job, two entry points: this CLI for CI/CD, the MCP server for agents.
59
+
58
60
  ---
59
61
 
60
62
  ## The Problem
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specshield",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "description": "Contract compatibility testing for APIs — catch breaking OpenAPI changes before they reach your consumers, with can-i-deploy deploy gating and GitHub PR checks. (a.k.a. bidirectional contract testing.)",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * Compare two normalized specs and return a flat list of raw diffs.
5
- * Each diff: { type, path, method, field, oldValue, newValue, description }
5
+ * Each diff: { type, changeId, path, method, field, oldValue, newValue, description }
6
6
  */
7
7
  function diffSpecs(base, target) {
8
8
  const diffs = [];
@@ -10,9 +10,30 @@ function diffSpecs(base, target) {
10
10
  diffEndpoints(base.endpoints || {}, target.endpoints || {}, diffs);
11
11
  diffSchemas(base.schemas || {}, target.schemas || {}, diffs);
12
12
 
13
+ // Stamp the canonical, public change ID on every diff so this engine and the
14
+ // backend emit the SAME id for the same change class. See the shared catalog:
15
+ // Docs/specshield-change-catalog.md (mirrors backend ChangeType.canonicalId).
16
+ for (const d of diffs) {
17
+ d.changeId = changeIdFor(d.type);
18
+ }
19
+
13
20
  return diffs;
14
21
  }
15
22
 
23
+ // Only these CLI type names diverge from the canonical kebab; every other type
24
+ // (field-became-required, parameter-became-optional, constraint-tightened,
25
+ // schema-removed, request-type-changed, …) already kebab-cases to its canonical id.
26
+ const CANONICAL_ID = {
27
+ RESPONSE_REMOVED: 'response-status-removed',
28
+ RESPONSE_ADDED: 'response-status-added',
29
+ };
30
+
31
+ /** Canonical public change ID. ENDPOINT_REMOVED -> "endpoint-removed". */
32
+ function changeIdFor(type) {
33
+ if (!type) return null;
34
+ return CANONICAL_ID[type] || String(type).toLowerCase().replace(/_/g, '-');
35
+ }
36
+
16
37
  // ─── Endpoints ──────────────────────────────────────────────────────────────
17
38
 
18
39
  function diffEndpoints(baseEndpoints, targetEndpoints, diffs) {