contract-driven-delivery 2.1.3 → 2.2.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/CHANGELOG.md +175 -0
- package/README.md +124 -1
- package/assets/CLAUDE.template.md +13 -0
- package/assets/agents/backend-engineer.md +3 -1
- package/assets/agents/frontend-engineer.md +3 -2
- package/assets/cdd/conformance.json +16 -0
- package/assets/cdd/tier-policy.json +35 -0
- package/assets/contracts/api/api-contract.md +26 -0
- package/assets/hooks/pre-tool-use-graph-first.sh +65 -0
- package/assets/skills/contract-driven-delivery/scripts/validate_api_conformance.py +543 -0
- package/assets/skills/contract-driven-delivery/scripts/validate_api_semantic.py +8 -1
- package/assets/skills/contract-driven-delivery/scripts/validate_contract_versions.py +4 -0
- package/dist/cli/index.js +2118 -491
- package/docs/adr/0001-contract-to-openapi-export.md +142 -0
- package/docs/adr/0002-schema-carrying-contract-format.md +277 -0
- package/docs/adr/0003-code-intelligence-indexing-strategy.md +110 -0
- package/docs/api-conformance.md +108 -0
- package/docs/openapi-export.md +157 -0
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# OpenAPI export
|
|
2
|
+
|
|
3
|
+
`cdd-kit openapi export` projects `contracts/api/api-contract.md` (the source of
|
|
4
|
+
truth) into a minimal **OpenAPI 3.1** skeleton for tooling. The markdown contract
|
|
5
|
+
stays authoritative; the OpenAPI document is a one-way, regenerable projection.
|
|
6
|
+
|
|
7
|
+
See `docs/adr/0001-contract-to-openapi-export.md` and
|
|
8
|
+
`docs/adr/0002-schema-carrying-contract-format.md` for the design rationale.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cdd-kit openapi export # JSON to stdout
|
|
14
|
+
cdd-kit openapi export --yaml # YAML to stdout
|
|
15
|
+
cdd-kit openapi export --out build/openapi.json # write to a file
|
|
16
|
+
cdd-kit openapi export --yaml --out openapi.yaml
|
|
17
|
+
cdd-kit openapi export --contract path/to/api-contract.md
|
|
18
|
+
cdd-kit openapi export --check --out build/openapi.json # sync gate
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## The sync gate: `--check`
|
|
22
|
+
|
|
23
|
+
A regenerable artifact is only safe if it is actually regenerated. `--check`
|
|
24
|
+
makes that mechanical instead of a habit:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cdd-kit openapi export --check --out build/openapi.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It does **not** write. It compares the committed artifact at `--out` against what
|
|
31
|
+
the contract produces right now and exits:
|
|
32
|
+
|
|
33
|
+
- `0` - in sync.
|
|
34
|
+
- `1` - the artifact is missing, or the contract changed but the export was not
|
|
35
|
+
regenerated. The command prints the exact `openapi export --out ...` command
|
|
36
|
+
to fix it.
|
|
37
|
+
|
|
38
|
+
Wire it into CI or a pre-commit hook so a contract edit that forgets to
|
|
39
|
+
regenerate the export, and therefore the typed client downstream, fails the
|
|
40
|
+
build. `--check` honors `--yaml`, so check the same format you committed.
|
|
41
|
+
|
|
42
|
+
## What it derives
|
|
43
|
+
|
|
44
|
+
From the endpoint table (`| method | path | auth | request schema | response schema | errors | tests |`):
|
|
45
|
+
|
|
46
|
+
| Contract column | OpenAPI output |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `method` + `path` | operation under `paths`, with `:id`/`{id}` normalized to `{id}` |
|
|
49
|
+
| path templates | `parameters` (`in: path`, `required: true`, `type: string`) |
|
|
50
|
+
| `auth` | `security` (`bearerAuth`) for `required`/`admin`, optional+anonymous for `optional`, none for `none`/`public` |
|
|
51
|
+
| `method` | success status: `201` for `POST`, else `200` |
|
|
52
|
+
| `errors` | extra response entries for any explicit `4xx`/`5xx` codes listed |
|
|
53
|
+
| `response schema` | if it names a schema in `## Schemas`, emitted as response JSON Schema; otherwise recorded as `x-cdd-response-contract` prose |
|
|
54
|
+
| `request schema` | if it names a schema in `## Schemas`, emitted as request JSON Schema; otherwise `requestBody` is marked `x-cdd-unresolved: true` |
|
|
55
|
+
|
|
56
|
+
The exporter does not fabricate field-level schemas. Request/response cells that
|
|
57
|
+
do not resolve to a named schema remain prose. The unresolved markers are
|
|
58
|
+
deliberate: emitting a fake schema would be a new drift source. Add a
|
|
59
|
+
`## Schemas` section when a body shape should become machine-typed.
|
|
60
|
+
|
|
61
|
+
## Schema-carrying contracts
|
|
62
|
+
|
|
63
|
+
Add optional `### Name` subsections under `## Schemas`. Existing endpoint table
|
|
64
|
+
cells like `CreateUser`, `User`, or `User[]` become references when a matching
|
|
65
|
+
schema exists.
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
## Endpoint Requirements
|
|
69
|
+
| method | path | auth | request schema | response schema | errors | tests |
|
|
70
|
+
|---|---|---|---|---|---|---|
|
|
71
|
+
| POST | /api/users | admin | CreateUser | User | 400 | yes |
|
|
72
|
+
|
|
73
|
+
## Schemas
|
|
74
|
+
|
|
75
|
+
### CreateUser
|
|
76
|
+
| field | type | required | format | notes |
|
|
77
|
+
|---|---|---|---|---|
|
|
78
|
+
| email | string | yes | email | login identity |
|
|
79
|
+
| name | string | yes | | display name |
|
|
80
|
+
| role | enum(admin, member) | no | | |
|
|
81
|
+
|
|
82
|
+
### User
|
|
83
|
+
| field | type | required | notes |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| id | string | yes | |
|
|
86
|
+
| email | string | yes | |
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Field-table types are intentionally small and closed:
|
|
90
|
+
|
|
91
|
+
| Type cell | Output |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `string`, `integer`, `number`, `boolean` | primitive JSON Schema |
|
|
94
|
+
| `OtherSchema` | `$ref` to another named schema |
|
|
95
|
+
| `OtherSchema[]` or `string[]` | array wrapper |
|
|
96
|
+
| `enum(active, disabled)` | string enum |
|
|
97
|
+
|
|
98
|
+
`required: yes` adds the field to JSON Schema `required`. `notes` becomes
|
|
99
|
+
`description`. An optional `format` column is emitted as JSON Schema `format`
|
|
100
|
+
and may be enforced by downstream tooling.
|
|
101
|
+
|
|
102
|
+
For complex bodies, use a raw Tier B escape hatch:
|
|
103
|
+
|
|
104
|
+
````markdown
|
|
105
|
+
### Event
|
|
106
|
+
```json-schema
|
|
107
|
+
{
|
|
108
|
+
"type": "object",
|
|
109
|
+
"oneOf": [
|
|
110
|
+
{ "required": ["createdAt"] },
|
|
111
|
+
{ "required": ["deletedAt"] }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
````
|
|
116
|
+
|
|
117
|
+
The exporter fails instead of weakening types when a schema is ambiguous:
|
|
118
|
+
duplicate schema names, a section that mixes a field table and `json-schema`
|
|
119
|
+
block, invalid JSON, or an unknown field type all exit non-zero.
|
|
120
|
+
|
|
121
|
+
## Wiring a typed client in a consumer repo
|
|
122
|
+
|
|
123
|
+
The kit produces the OpenAPI seam; you generate the client with an existing,
|
|
124
|
+
well-maintained generator in your own CI. When a `package.json` is present,
|
|
125
|
+
`cdd-kit init` scaffolds this for you as two editable npm scripts:
|
|
126
|
+
|
|
127
|
+
```jsonc
|
|
128
|
+
"scripts": {
|
|
129
|
+
// regenerate the OpenAPI artifact + the typed client
|
|
130
|
+
"contract:client": "cdd-kit openapi export --out contracts/api/openapi.json && npx --yes openapi-typescript contracts/api/openapi.json -o src/api/types.ts",
|
|
131
|
+
// the sync gate - fails if the artifact drifted from the contract
|
|
132
|
+
"contract:client:check": "cdd-kit openapi export --check --out contracts/api/openapi.json"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
These are a starting point, not a hard dependency: the generator
|
|
137
|
+
(`openapi-typescript`) and the output path are yours to change. The kit owns the
|
|
138
|
+
generic contract-to-OpenAPI half (`openapi export` / `--check`); the
|
|
139
|
+
stack-specific codegen stays in your repo, which is why init writes an editable
|
|
140
|
+
script rather than hard-coding a tool. Run `npm run contract:client:check` in CI
|
|
141
|
+
as the gate.
|
|
142
|
+
|
|
143
|
+
Doing it by hand instead, for a TypeScript frontend:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# 1. Export the contract to OpenAPI (committed or generated in CI)
|
|
147
|
+
cdd-kit openapi export --yaml --out openapi.yaml
|
|
148
|
+
|
|
149
|
+
# 2. Generate types with openapi-typescript (or orval / openapi-generator)
|
|
150
|
+
npx openapi-typescript openapi.yaml -o src/api/schema.d.ts
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Now frontend calls typed against `schema.d.ts` make a divergent path, method, or
|
|
154
|
+
schema-resolved body shape a compile error. Run both generated clients and
|
|
155
|
+
`validate_api_conformance.py`: conformance stays the universal floor for code
|
|
156
|
+
that cannot be regenerated, generated types are the stronger path where the
|
|
157
|
+
stack allows it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contract-driven-delivery",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Contract-driven delivery kit for AI coding agents with deterministic context indexes, manifest-backed read-scope governance, and orchestrated contracts-first delivery.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contract-driven",
|