contract-driven-delivery 1.8.1 → 1.10.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/assets/CLAUDE.template.md +14 -203
- package/assets/agents/backend-engineer.md +6 -1
- package/assets/agents/change-classifier.md +36 -10
- package/assets/agents/contract-reviewer.md +2 -2
- package/assets/agents/dependency-security-reviewer.md +2 -2
- package/assets/agents/frontend-engineer.md +6 -1
- package/assets/agents/qa-reviewer.md +2 -2
- package/assets/agents/repo-context-scanner.md +5 -2
- package/assets/agents/spec-architect.md +28 -31
- package/assets/agents/spec-drift-auditor.md +22 -20
- package/assets/agents/test-strategist.md +25 -28
- package/assets/agents/ui-ux-reviewer.md +2 -2
- package/assets/agents/visual-reviewer.md +2 -2
- package/assets/ci-templates/conda.yml +1 -1
- package/assets/{ci/github-actions → github-workflows}/contract-driven-gates.yml +12 -17
- package/assets/skills/cdd-init/SKILL.md +6 -0
- package/assets/skills/cdd-new/SKILL.md +304 -42
- package/assets/skills/contract-driven-delivery/templates/change-classification.md +17 -11
- package/assets/skills/contract-driven-delivery/templates/design.md +16 -13
- package/assets/skills/contract-driven-delivery/templates/test-plan.md +17 -23
- package/assets/specs-templates/change-classification.md +17 -11
- package/assets/specs-templates/design.md +16 -13
- package/assets/specs-templates/test-plan.md +17 -23
- package/dist/cli/index.js +27 -2
- package/package.json +1 -1
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
change-id: <id>
|
|
3
|
+
schema-version: 0.1.0
|
|
4
|
+
last-changed: <date>
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
# Design: <change-id>
|
|
4
8
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
## API Design
|
|
9
|
+
## Summary
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
(1 paragraph: what changes architecturally and why)
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Affected Components
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
| component | file path(s) | nature of change |
|
|
16
|
+
|---|---|---|
|
|
14
17
|
|
|
15
|
-
##
|
|
18
|
+
## Key Decisions
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
- **Decision**: rationale — rejected alternative: reason rejected
|
|
18
21
|
|
|
19
|
-
##
|
|
22
|
+
## Migration / Rollback
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
(Prose description. SQL and code go in migration files, not here.)
|
|
22
25
|
|
|
23
|
-
##
|
|
26
|
+
## Open Risks
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
change-id: <id>
|
|
3
|
+
schema-version: 0.1.0
|
|
4
|
+
last-changed: <date>
|
|
5
|
+
risk: low | medium | high
|
|
6
|
+
tier: 0 | 1 | 2 | 3 | 4 | 5
|
|
7
|
+
---
|
|
2
8
|
|
|
3
|
-
|
|
4
|
-
| requirement | test family | planned file/spec | expected evidence |
|
|
5
|
-
|---|---|---|---|
|
|
6
|
-
|
|
7
|
-
## Unit Tests
|
|
8
|
-
|
|
9
|
-
## Contract Tests
|
|
10
|
-
|
|
11
|
-
## Integration Tests
|
|
9
|
+
# Test Plan: <change-id>
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Acceptance Criteria → Test Mapping
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
## Resilience Tests
|
|
20
|
-
|
|
21
|
-
## Fuzz / Monkey Operation Tests
|
|
13
|
+
| criterion id | test family | test file path | tier |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| AC-1 | unit | tests/unit/test_xxx.py | 0 |
|
|
22
16
|
|
|
23
|
-
##
|
|
17
|
+
## Test Families Required
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
Mark all that apply: unit / contract / integration / e2e / data-boundary / resilience / monkey / stress / soak
|
|
26
20
|
|
|
27
|
-
##
|
|
21
|
+
## Out of Scope
|
|
28
22
|
|
|
29
|
-
##
|
|
23
|
+
## Notes
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
(Keep this section under 10 lines. Implementation detail belongs in the test files themselves.)
|
package/dist/cli/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var ASSET = {
|
|
|
26
26
|
specsTemplates: join(ASSETS_DIR, "specs-templates"),
|
|
27
27
|
testsTemplates: join(ASSETS_DIR, "tests-templates"),
|
|
28
28
|
ci: join(ASSETS_DIR, "ci"),
|
|
29
|
+
githubWorkflows: join(ASSETS_DIR, "github-workflows"),
|
|
29
30
|
hooks: join(ASSETS_DIR, "hooks"),
|
|
30
31
|
claudeTemplate: join(ASSETS_DIR, "CLAUDE.template.md"),
|
|
31
32
|
agentsTemplate: join(ASSETS_DIR, "AGENTS.template.md")
|
|
@@ -224,6 +225,18 @@ function detectStack(repoRoot) {
|
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
// src/commands/init.ts
|
|
228
|
+
function readCondaEnvName(cwd) {
|
|
229
|
+
const envYml = join4(cwd, "environment.yml");
|
|
230
|
+
if (!existsSync3(envYml))
|
|
231
|
+
return "base";
|
|
232
|
+
try {
|
|
233
|
+
const content = readFileSync2(envYml, "utf8");
|
|
234
|
+
const match = content.match(/^name:\s*(.+)$/m);
|
|
235
|
+
return match ? match[1].trim() : "base";
|
|
236
|
+
} catch {
|
|
237
|
+
return "base";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
227
240
|
function loadCiTemplate(stack) {
|
|
228
241
|
const templatePath = join4(ASSETS_DIR, "ci-templates", `${stack}.yml`);
|
|
229
242
|
if (!existsSync3(templatePath))
|
|
@@ -326,6 +339,13 @@ async function init(opts) {
|
|
|
326
339
|
);
|
|
327
340
|
track(ciCreated);
|
|
328
341
|
log.ok(`ci/ \u2014 ${ciCount} file(s) written.`);
|
|
342
|
+
const { count: wfCount, created: wfCreated } = copyDirTracked(
|
|
343
|
+
ASSET.githubWorkflows,
|
|
344
|
+
join4(cwd, ".github", "workflows"),
|
|
345
|
+
{ overwrite: opts.force, label: ".github/workflows" }
|
|
346
|
+
);
|
|
347
|
+
track(wfCreated);
|
|
348
|
+
log.ok(`.github/workflows/ \u2014 ${wfCount} file(s) written.`);
|
|
329
349
|
const detection = detectStack(cwd);
|
|
330
350
|
if (detection.polyglot) {
|
|
331
351
|
const PYTHON_STACKS = ["conda", "poetry", "uv", "pip"];
|
|
@@ -345,12 +365,17 @@ async function init(opts) {
|
|
|
345
365
|
} else {
|
|
346
366
|
log.warn("Could not detect stack \u2014 CI placeholder left in place.");
|
|
347
367
|
}
|
|
348
|
-
const ciYmlDest = join4(cwd, "
|
|
368
|
+
const ciYmlDest = join4(cwd, ".github", "workflows", "contract-driven-gates.yml");
|
|
349
369
|
if (existsSync3(ciYmlDest)) {
|
|
350
370
|
const template = loadCiTemplate(detection.primary);
|
|
351
371
|
if (template) {
|
|
352
372
|
const original = readFileSync2(ciYmlDest, "utf8");
|
|
353
|
-
|
|
373
|
+
let patched = patchFastGateYml(original, template, detection.primary);
|
|
374
|
+
if (detection.primary === "conda" && patched.includes("{{conda-env-name}}")) {
|
|
375
|
+
const envName = readCondaEnvName(cwd);
|
|
376
|
+
patched = patched.replace(/\{\{conda-env-name\}\}/g, envName);
|
|
377
|
+
log.ok(`Conda environment name set to: ${envName}`);
|
|
378
|
+
}
|
|
354
379
|
if (patched !== original) {
|
|
355
380
|
writeFileSync(ciYmlDest, patched, "utf8");
|
|
356
381
|
log.ok(`CI fast-gate patched for stack: ${detection.primary}`);
|
package/package.json
CHANGED