@eddacraft/anvil-adapters 0.1.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/AGENTS.md +180 -0
- package/BMAD_ADAPTER_SPEC.md +489 -0
- package/LICENSE +14 -0
- package/README.md +500 -0
- package/dist/aps-markdown/adapter.d.ts +102 -0
- package/dist/aps-markdown/adapter.d.ts.map +1 -0
- package/dist/aps-markdown/adapter.js +351 -0
- package/dist/aps-markdown/index.d.ts +8 -0
- package/dist/aps-markdown/index.d.ts.map +1 -0
- package/dist/aps-markdown/index.js +7 -0
- package/dist/base/file-discovery.d.ts +63 -0
- package/dist/base/file-discovery.d.ts.map +1 -0
- package/dist/base/file-discovery.js +246 -0
- package/dist/base/index.d.ts +10 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +9 -0
- package/dist/base/registry.d.ts +155 -0
- package/dist/base/registry.d.ts.map +1 -0
- package/dist/base/registry.js +227 -0
- package/dist/base/testing.d.ts +102 -0
- package/dist/base/testing.d.ts.map +1 -0
- package/dist/base/testing.js +221 -0
- package/dist/base/types.d.ts +255 -0
- package/dist/base/types.d.ts.map +1 -0
- package/dist/base/types.js +78 -0
- package/dist/base/utils.d.ts +127 -0
- package/dist/base/utils.d.ts.map +1 -0
- package/dist/base/utils.js +254 -0
- package/dist/bmad/format-adapter.d.ts +76 -0
- package/dist/bmad/format-adapter.d.ts.map +1 -0
- package/dist/bmad/format-adapter.js +186 -0
- package/dist/bmad/index.d.ts +12 -0
- package/dist/bmad/index.d.ts.map +1 -0
- package/dist/bmad/index.js +10 -0
- package/dist/bmad/parser.d.ts +12 -0
- package/dist/bmad/parser.d.ts.map +1 -0
- package/dist/bmad/parser.js +181 -0
- package/dist/bmad/serializer.d.ts +16 -0
- package/dist/bmad/serializer.d.ts.map +1 -0
- package/dist/bmad/serializer.js +170 -0
- package/dist/bmad/types.d.ts +127 -0
- package/dist/bmad/types.d.ts.map +1 -0
- package/dist/bmad/types.js +47 -0
- package/dist/bmad/utils.d.ts +120 -0
- package/dist/bmad/utils.d.ts.map +1 -0
- package/dist/bmad/utils.js +480 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +2 -0
- package/dist/common/registry.d.ts +18 -0
- package/dist/common/registry.d.ts.map +1 -0
- package/dist/common/registry.js +58 -0
- package/dist/common/types.d.ts +68 -0
- package/dist/common/types.d.ts.map +1 -0
- package/dist/common/types.js +12 -0
- package/dist/generic/format-adapter.d.ts +64 -0
- package/dist/generic/format-adapter.d.ts.map +1 -0
- package/dist/generic/format-adapter.js +159 -0
- package/dist/generic/index.d.ts +10 -0
- package/dist/generic/index.d.ts.map +1 -0
- package/dist/generic/index.js +9 -0
- package/dist/generic/parser.d.ts +11 -0
- package/dist/generic/parser.d.ts.map +1 -0
- package/dist/generic/parser.js +106 -0
- package/dist/generic/serializer.d.ts +11 -0
- package/dist/generic/serializer.d.ts.map +1 -0
- package/dist/generic/serializer.js +118 -0
- package/dist/generic/types.d.ts +52 -0
- package/dist/generic/types.d.ts.map +1 -0
- package/dist/generic/types.js +6 -0
- package/dist/generic/utils.d.ts +51 -0
- package/dist/generic/utils.d.ts.map +1 -0
- package/dist/generic/utils.js +232 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/speckit/export.d.ts +22 -0
- package/dist/speckit/export.d.ts.map +1 -0
- package/dist/speckit/export.js +384 -0
- package/dist/speckit/format-adapter.d.ts +104 -0
- package/dist/speckit/format-adapter.d.ts.map +1 -0
- package/dist/speckit/format-adapter.js +488 -0
- package/dist/speckit/import-v2.d.ts +33 -0
- package/dist/speckit/import-v2.d.ts.map +1 -0
- package/dist/speckit/import-v2.js +361 -0
- package/dist/speckit/import.d.ts +16 -0
- package/dist/speckit/import.d.ts.map +1 -0
- package/dist/speckit/import.js +247 -0
- package/dist/speckit/index.d.ts +5 -0
- package/dist/speckit/index.d.ts.map +1 -0
- package/dist/speckit/index.js +4 -0
- package/dist/speckit/parser.d.ts +28 -0
- package/dist/speckit/parser.d.ts.map +1 -0
- package/dist/speckit/parser.js +283 -0
- package/dist/speckit/parsers/plan-parser.d.ts +71 -0
- package/dist/speckit/parsers/plan-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/plan-parser.js +216 -0
- package/dist/speckit/parsers/spec-parser.d.ts +67 -0
- package/dist/speckit/parsers/spec-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/spec-parser.js +255 -0
- package/dist/speckit/parsers/tasks-parser.d.ts +57 -0
- package/dist/speckit/parsers/tasks-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/tasks-parser.js +157 -0
- package/package.json +23 -0
- package/project.json +29 -0
- package/src/__tests__/adapter-edge-cases.test.ts +937 -0
- package/src/__tests__/bmad-format-adapter.test.ts +1470 -0
- package/src/__tests__/fixtures/aps/expected-output.json +83 -0
- package/src/__tests__/fixtures/bmad/invalid-malformed-yaml.md +16 -0
- package/src/__tests__/fixtures/bmad/invalid-no-requirements.md +23 -0
- package/src/__tests__/fixtures/bmad/invalid-only-yaml.md +16 -0
- package/src/__tests__/fixtures/bmad/invalid-too-short.md +3 -0
- package/src/__tests__/fixtures/bmad/invalid-wrong-format.md +40 -0
- package/src/__tests__/fixtures/bmad/valid-agent.md +27 -0
- package/src/__tests__/fixtures/bmad/valid-architecture.md +116 -0
- package/src/__tests__/fixtures/bmad/valid-complex-prd.md +161 -0
- package/src/__tests__/fixtures/bmad/valid-epic.md +73 -0
- package/src/__tests__/fixtures/bmad/valid-minimal-prd.md +19 -0
- package/src/__tests__/fixtures/bmad/valid-prd.md +107 -0
- package/src/__tests__/fixtures/bmad/valid-story.md +107 -0
- package/src/__tests__/fixtures/bmad/valid-task.md +79 -0
- package/src/__tests__/fixtures/bmad/valid-v6-prd.md +35 -0
- package/src/__tests__/fixtures/generic/plan-detailed.md +39 -0
- package/src/__tests__/fixtures/generic/prd-simple.md +27 -0
- package/src/__tests__/fixtures/generic/rfc-example.md +26 -0
- package/src/__tests__/fixtures/generic/todo-list.md +23 -0
- package/src/__tests__/fixtures/speckit/sample-plan.md +63 -0
- package/src/__tests__/fixtures/speckit/sample-spec-namespaced.md +50 -0
- package/src/__tests__/fixtures/speckit/sample-spec.md +105 -0
- package/src/__tests__/fixtures/speckit/sample-tasks.md +87 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/plan.md +272 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/spec.md +149 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/tasks.md +169 -0
- package/src/__tests__/generic-format-adapter.test.ts +398 -0
- package/src/__tests__/speckit-export.test.ts +233 -0
- package/src/__tests__/speckit-format-adapter.test.ts +832 -0
- package/src/__tests__/speckit-import-v2.test.ts +253 -0
- package/src/__tests__/speckit-import.test.ts +209 -0
- package/src/__tests__/speckit-parser.test.ts +219 -0
- package/src/__tests__/speckit-spec-parser.test.ts +120 -0
- package/src/aps-markdown/__tests__/__fixtures__/simple-leaf.aps.md +17 -0
- package/src/aps-markdown/__tests__/adapter.test.ts +393 -0
- package/src/aps-markdown/adapter.ts +455 -0
- package/src/aps-markdown/index.ts +8 -0
- package/src/base/__tests__/registry.test.ts +515 -0
- package/src/base/file-discovery.ts +305 -0
- package/src/base/index.ts +10 -0
- package/src/base/registry.ts +263 -0
- package/src/base/testing.ts +334 -0
- package/src/base/types.ts +342 -0
- package/src/base/utils.ts +306 -0
- package/src/bmad/format-adapter.ts +227 -0
- package/src/bmad/index.ts +21 -0
- package/src/bmad/parser.ts +224 -0
- package/src/bmad/serializer.ts +206 -0
- package/src/bmad/types.ts +135 -0
- package/src/bmad/utils.ts +575 -0
- package/src/common/index.ts +2 -0
- package/src/common/registry.ts +72 -0
- package/src/common/types.ts +84 -0
- package/src/generic/__tests__/serializer.test.ts +167 -0
- package/src/generic/format-adapter.ts +200 -0
- package/src/generic/index.ts +11 -0
- package/src/generic/parser.ts +129 -0
- package/src/generic/serializer.ts +134 -0
- package/src/generic/types.ts +53 -0
- package/src/generic/utils.ts +270 -0
- package/src/index.ts +48 -0
- package/src/speckit/export.ts +489 -0
- package/src/speckit/format-adapter.ts +595 -0
- package/src/speckit/import-v2.ts +445 -0
- package/src/speckit/import.ts +305 -0
- package/src/speckit/index.ts +4 -0
- package/src/speckit/parser.ts +351 -0
- package/src/speckit/parsers/plan-parser.ts +342 -0
- package/src/speckit/parsers/spec-parser.ts +379 -0
- package/src/speckit/parsers/tasks-parser.ts +246 -0
- package/tsconfig.json +26 -0
- package/tsconfig.lib.json +21 -0
- package/tsconfig.lib.tsbuildinfo +1 -0
- package/tsconfig.spec.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +14 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Adapters Package (@eddacraft/anvil-adapters)
|
|
2
|
+
|
|
3
|
+
> Format conversion framework: SpecKit, BMAD, Generic Markdown → APS
|
|
4
|
+
|
|
5
|
+
**Parent**: See root `AGENTS.md` for project-wide conventions.
|
|
6
|
+
|
|
7
|
+
## Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
packages/adapters/src/
|
|
11
|
+
├── base/ # Framework foundation
|
|
12
|
+
│ ├── types.ts # FormatAdapter interface (313 lines)
|
|
13
|
+
│ ├── registry.ts # AdapterRegistry singleton (231 lines)
|
|
14
|
+
│ ├── utils.ts # Helper functions
|
|
15
|
+
│ └── file-discovery.ts # Auto-find planning documents
|
|
16
|
+
├── speckit/ # GitHub SpecKit adapter (538 lines)
|
|
17
|
+
│ └── format-adapter.ts
|
|
18
|
+
├── bmad/ # BMAD PRD/architecture adapter (188 lines)
|
|
19
|
+
│ └── format-adapter.ts
|
|
20
|
+
├── generic/ # Generic markdown fallback (198 lines)
|
|
21
|
+
│ └── format-adapter.ts
|
|
22
|
+
└── index.ts # Auto-registers all adapters on import
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Where to Look
|
|
26
|
+
|
|
27
|
+
| Task | Location | Notes |
|
|
28
|
+
| ---------------- | ------------------------------------- | ---------------------------- |
|
|
29
|
+
| Add new adapter | Create `src/{name}/format-adapter.ts` | Implement FormatAdapter |
|
|
30
|
+
| Modify detection | Adapter's `detect()` method | Adjust confidence weights |
|
|
31
|
+
| Add utility | `base/utils.ts` | Shared across adapters |
|
|
32
|
+
| Change registry | `base/registry.ts` | Singleton, priority ordering |
|
|
33
|
+
|
|
34
|
+
## FormatAdapter Interface
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
interface FormatAdapter {
|
|
38
|
+
readonly metadata: AdapterMetadata; // name, version, formats, extensions
|
|
39
|
+
|
|
40
|
+
// Confidence-based format detection (0-100)
|
|
41
|
+
detect(content: string): DetectionResult;
|
|
42
|
+
|
|
43
|
+
// External format → APS
|
|
44
|
+
parse(
|
|
45
|
+
content: string,
|
|
46
|
+
context?: ParseContext,
|
|
47
|
+
options?: ParseOptions
|
|
48
|
+
): Promise<ParseResult>;
|
|
49
|
+
|
|
50
|
+
// APS → External format
|
|
51
|
+
serialize(
|
|
52
|
+
plan: APSPlan,
|
|
53
|
+
options?: SerializeOptions
|
|
54
|
+
): Promise<SerializeResult>;
|
|
55
|
+
|
|
56
|
+
// Fast validation without full conversion
|
|
57
|
+
validate(
|
|
58
|
+
content: string,
|
|
59
|
+
options?: ValidateOptions
|
|
60
|
+
): Promise<ValidationResult>;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Creating a New Adapter
|
|
65
|
+
|
|
66
|
+
1. Create directory: `src/{name}/`
|
|
67
|
+
2. Implement adapter:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { BaseFormatAdapter } from '../base/types.js';
|
|
71
|
+
import type {
|
|
72
|
+
DetectionResult,
|
|
73
|
+
ParseResult,
|
|
74
|
+
SerializeResult,
|
|
75
|
+
} from '../base/types.js';
|
|
76
|
+
|
|
77
|
+
export class MyFormatAdapter extends BaseFormatAdapter {
|
|
78
|
+
readonly metadata = {
|
|
79
|
+
name: 'my-format',
|
|
80
|
+
version: '1.0.0',
|
|
81
|
+
formats: ['my-format'],
|
|
82
|
+
extensions: ['.myf.md'],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
detect(content: string): DetectionResult {
|
|
86
|
+
let confidence = 0;
|
|
87
|
+
|
|
88
|
+
// Check for format-specific markers
|
|
89
|
+
if (content.includes('# My Format Header')) confidence += 30;
|
|
90
|
+
if (/^---\nformat: my-format/m.test(content)) confidence += 40;
|
|
91
|
+
|
|
92
|
+
return this.createDetection(confidence, {
|
|
93
|
+
hasHeader: confidence > 0,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async parse(content: string): Promise<ParseResult> {
|
|
98
|
+
// Convert to APS...
|
|
99
|
+
return { success: true, plan: apsPlan, warnings: [] };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async serialize(plan: APSPlan): Promise<SerializeResult> {
|
|
103
|
+
// Convert from APS...
|
|
104
|
+
return { success: true, content: markdown };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
3. Register in `index.ts`:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { MyFormatAdapter } from './my-format/format-adapter.js';
|
|
113
|
+
baseRegistry.register(new MyFormatAdapter());
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Detection Strategy
|
|
117
|
+
|
|
118
|
+
**Confidence Scoring** (0-100, threshold 50%):
|
|
119
|
+
|
|
120
|
+
| Indicator | Weight | Example |
|
|
121
|
+
| ----------------- | ------ | -------------------------------- |
|
|
122
|
+
| Format header | 30 | `# Specification` |
|
|
123
|
+
| YAML front-matter | 30 | `---\nformat: speckit\n---` |
|
|
124
|
+
| Section markers | 15-20 | `## Intent`, `## Changes` |
|
|
125
|
+
| ID patterns | 20-25 | `REQ-001`, `TASK-001` |
|
|
126
|
+
| Keywords | 10-15 | `proposed_changes`, `provenance` |
|
|
127
|
+
|
|
128
|
+
**Priority Order**: SpecKit (100) > BMAD (90) > Generic (10)
|
|
129
|
+
|
|
130
|
+
Generic adapter has 30% threshold as fallback.
|
|
131
|
+
|
|
132
|
+
## AdapterRegistry
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Get singleton instance
|
|
136
|
+
const registry = AdapterRegistry.getInstance();
|
|
137
|
+
|
|
138
|
+
// Auto-detect format (returns best match above threshold)
|
|
139
|
+
const detected = registry.detectAdapter(content, 0.5);
|
|
140
|
+
if (detected) {
|
|
141
|
+
const { adapter, detection } = detected;
|
|
142
|
+
const result = await adapter.parse(content);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Get specific adapter
|
|
146
|
+
const speckit = registry.getAdapterForFormat('speckit');
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Utility Functions
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import {
|
|
153
|
+
createDetection, // Build DetectionResult
|
|
154
|
+
createError, // Build AdapterError
|
|
155
|
+
createWarning, // Build AdapterWarning
|
|
156
|
+
calculateConfidence, // Normalise to 0-100
|
|
157
|
+
mergeParseResults, // Combine multiple results
|
|
158
|
+
} from './base/utils.js';
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Scripts
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
nx test adapters # All adapter tests
|
|
165
|
+
nx test adapters --testNamePattern="BMAD" # BMAD tests only
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Anti-Patterns (This Package)
|
|
169
|
+
|
|
170
|
+
- Never hardcode confidence thresholds - use constants
|
|
171
|
+
- Never skip detection step before parsing
|
|
172
|
+
- Always return structured errors (AdapterError), never throw
|
|
173
|
+
- Always preserve unknown fields during round-trip
|
|
174
|
+
|
|
175
|
+
## Testing
|
|
176
|
+
|
|
177
|
+
- 114+ SpecKit tests, 86+ BMAD tests, 32+ Generic tests
|
|
178
|
+
- Fixture-based with real document samples
|
|
179
|
+
- Test detection, parsing, serialisation, and round-trip fidelity
|
|
180
|
+
- Test files in `__tests__/fixtures/`
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
# BMAD Adapter Specification
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
BMAD (Breakthrough Method for Agile AI-Driven Development) adapter for
|
|
6
|
+
converting BMAD format documents (PRDs, Architecture docs, Epics, Stories)
|
|
7
|
+
to/from Anvil Plan Specification (APS).
|
|
8
|
+
|
|
9
|
+
**Version**: 1.0.0 **Status**: Design Phase (Week 8) **Target**: FormatAdapter
|
|
10
|
+
interface compliance from the start
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## BMAD Format Research Summary
|
|
15
|
+
|
|
16
|
+
### Document Types
|
|
17
|
+
|
|
18
|
+
BMAD uses structured markdown documents with YAML front-matter:
|
|
19
|
+
|
|
20
|
+
1. **PRD (Product Requirements Document)** - `docs/prd.md`
|
|
21
|
+
- Functional Requirements (FRs) - numbered FR-01, FR-02, etc.
|
|
22
|
+
- Non-Functional Requirements (NFRs) - numbered NFR-01, NFR-02, etc.
|
|
23
|
+
- Epics
|
|
24
|
+
- User Stories (US-01, US-02, etc.)
|
|
25
|
+
|
|
26
|
+
2. **Architecture Document** - `docs/architecture.md`
|
|
27
|
+
- Technical Summary
|
|
28
|
+
- High Level Architecture
|
|
29
|
+
- System Components
|
|
30
|
+
- Tech Stack
|
|
31
|
+
- API Specifications
|
|
32
|
+
|
|
33
|
+
3. **Epic Documents** - `docs/epics/*.md`
|
|
34
|
+
- Epic title and goal
|
|
35
|
+
- Related stories
|
|
36
|
+
- Success criteria
|
|
37
|
+
|
|
38
|
+
4. **Story Documents** - `docs/stories/*.md`
|
|
39
|
+
- User story format: "As a... I want... so that..."
|
|
40
|
+
- Acceptance criteria (numbered list)
|
|
41
|
+
- Implementation details
|
|
42
|
+
|
|
43
|
+
### Common Structural Elements
|
|
44
|
+
|
|
45
|
+
**YAML Front-Matter**:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
---
|
|
49
|
+
name: 'Product Requirements Document'
|
|
50
|
+
version: '4.44.0'
|
|
51
|
+
description: 'Scale-adaptive PRD template'
|
|
52
|
+
output_file: 'PRD.md'
|
|
53
|
+
variables:
|
|
54
|
+
project_name: '{{user_input}}'
|
|
55
|
+
author: '{{from_config}}'
|
|
56
|
+
date: '{{system_date}}'
|
|
57
|
+
---
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Change Log Table**:
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
| Date | Version | Description | Author |
|
|
64
|
+
| :--- | :------ | :---------- | :----- |
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Requirement Format**:
|
|
68
|
+
|
|
69
|
+
- `FR-01: Description` (Functional Requirements)
|
|
70
|
+
- `NFR-01: Description` (Non-Functional Requirements)
|
|
71
|
+
- `US-01: Story Title` (User Stories)
|
|
72
|
+
|
|
73
|
+
**Story Format**:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
As a {{user_type}}, I want {{action}}, so that {{benefit}}.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Acceptance Criteria**:
|
|
80
|
+
|
|
81
|
+
```markdown
|
|
82
|
+
1. Criterion 1
|
|
83
|
+
2. Criterion 2
|
|
84
|
+
3. Criterion 3
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Adapter Design
|
|
90
|
+
|
|
91
|
+
### FormatAdapter Implementation
|
|
92
|
+
|
|
93
|
+
The BMAD adapter will correctly implement `FormatAdapter` interface from
|
|
94
|
+
`packages/adapters/src/base/types.ts`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
export class BMADFormatAdapter implements FormatAdapter {
|
|
98
|
+
readonly metadata: AdapterMetadata = {
|
|
99
|
+
name: 'bmad',
|
|
100
|
+
version: '1.0.0',
|
|
101
|
+
displayName: 'BMAD (Breakthrough Method for Agile AI-Driven Development)',
|
|
102
|
+
description: 'BMAD PRD and architecture document adapter',
|
|
103
|
+
formats: ['bmad', 'prd', 'architecture'],
|
|
104
|
+
extensions: ['.md'],
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
detect(content: string): DetectionResult;
|
|
108
|
+
parse(content: string, context?: ParseContext): Promise<ParseResult>;
|
|
109
|
+
serialize(plan: APSPlan): Promise<SerializeResult>;
|
|
110
|
+
validate(content: string): Promise<ValidationResult>;
|
|
111
|
+
canImport(format: string): boolean;
|
|
112
|
+
canExport(format: string): boolean;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Format Detection Strategy
|
|
117
|
+
|
|
118
|
+
**Detection Indicators** (confidence scoring):
|
|
119
|
+
|
|
120
|
+
High confidence (90-100%):
|
|
121
|
+
|
|
122
|
+
- YAML front-matter with BMAD template metadata
|
|
123
|
+
- "Product Requirements Document" or "Architecture Document" in title
|
|
124
|
+
- Presence of FR-01, NFR-01, US-01 identifiers
|
|
125
|
+
- "As a... I want... so that..." story format
|
|
126
|
+
- Change log table with exact column structure
|
|
127
|
+
|
|
128
|
+
Medium confidence (70-89%):
|
|
129
|
+
|
|
130
|
+
- Multiple numbered requirements (FR-_, NFR-_, US-\*)
|
|
131
|
+
- Acceptance Criteria sections
|
|
132
|
+
- Epic/Story terminology
|
|
133
|
+
|
|
134
|
+
Low confidence (50-69%):
|
|
135
|
+
|
|
136
|
+
- Generic markdown with "Requirements" section
|
|
137
|
+
- User story format without other indicators
|
|
138
|
+
|
|
139
|
+
**Detection Algorithm**:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
detect(content: string): DetectionResult {
|
|
143
|
+
let score = 0;
|
|
144
|
+
const indicators = [];
|
|
145
|
+
|
|
146
|
+
// YAML front-matter (30 points)
|
|
147
|
+
if (/^---\s*\n.*template:/ms.test(content)) {
|
|
148
|
+
score += 30;
|
|
149
|
+
indicators.push('yaml-frontmatter');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Requirement identifiers (25 points)
|
|
153
|
+
const frMatches = content.match(/\bFR-\d{2}/g);
|
|
154
|
+
const nfrMatches = content.match(/\bNFR-\d{2}/g);
|
|
155
|
+
const usMatches = content.match(/\bUS-\d{2}/g);
|
|
156
|
+
|
|
157
|
+
if (frMatches || nfrMatches || usMatches) {
|
|
158
|
+
score += 25;
|
|
159
|
+
indicators.push('requirement-identifiers');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// User story format (20 points)
|
|
163
|
+
if (/As a .+,\s*\nI want .+,\s*\nso that .+\./mi.test(content)) {
|
|
164
|
+
score += 20;
|
|
165
|
+
indicators.push('user-story-format');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Change log table (15 points)
|
|
169
|
+
if (/\|\s*Date\s*\|\s*Version\s*\|\s*Description\s*\|\s*Author\s*\|/i.test(content)) {
|
|
170
|
+
score += 15;
|
|
171
|
+
indicators.push('change-log-table');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// PRD/Architecture title (10 points)
|
|
175
|
+
if (/(Product Requirements|Architecture) Document/i.test(content)) {
|
|
176
|
+
score += 10;
|
|
177
|
+
indicators.push('document-title');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return createDetection(score >= 50, score, indicators.join(', '));
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Parse Strategy
|
|
185
|
+
|
|
186
|
+
**Input**: BMAD markdown document (PRD, Architecture, Epic, or Story)
|
|
187
|
+
**Output**: APS plan with converted changes
|
|
188
|
+
|
|
189
|
+
**Parsing Steps**:
|
|
190
|
+
|
|
191
|
+
1. **Extract YAML Front-Matter** (if present)
|
|
192
|
+
- Parse metadata (name, version, author, date)
|
|
193
|
+
- Use for APS provenance
|
|
194
|
+
|
|
195
|
+
2. **Identify Document Type**
|
|
196
|
+
- PRD: Contains FR/NFR sections
|
|
197
|
+
- Architecture: Contains Technical Summary, High Level Architecture
|
|
198
|
+
- Epic: Contains Epic goal and stories
|
|
199
|
+
- Story: Contains "As a... I want... so that..."
|
|
200
|
+
|
|
201
|
+
3. **Extract Requirements → APS Changes**
|
|
202
|
+
- FR-01 → `file_create` or `file_update` change
|
|
203
|
+
- NFR-01 → `config_change` or validation requirement
|
|
204
|
+
- US-01 → `file_create` with acceptance criteria as description
|
|
205
|
+
|
|
206
|
+
4. **Extract Intent**
|
|
207
|
+
- PRD: Use Executive Summary or Product Vision
|
|
208
|
+
- Architecture: Use Technical Summary
|
|
209
|
+
- Epic: Use Epic Goal
|
|
210
|
+
- Story: Use Story description
|
|
211
|
+
|
|
212
|
+
5. **Generate APS Plan**
|
|
213
|
+
```typescript
|
|
214
|
+
const plan = createPlan({
|
|
215
|
+
id: generatePlanId(),
|
|
216
|
+
intent: extractedIntent,
|
|
217
|
+
provenance: {
|
|
218
|
+
timestamp: yamlDate || new Date().toISOString(),
|
|
219
|
+
author: yamlAuthor || context?.author || 'unknown',
|
|
220
|
+
source: 'cli',
|
|
221
|
+
version: this.metadata.version,
|
|
222
|
+
repository: context?.repositoryPath,
|
|
223
|
+
},
|
|
224
|
+
changes: extractedChanges,
|
|
225
|
+
validations: {
|
|
226
|
+
required_checks: ['lint', 'test', 'coverage'],
|
|
227
|
+
skip_checks: [],
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Serialize Strategy
|
|
233
|
+
|
|
234
|
+
**Input**: APS plan **Output**: BMAD markdown document
|
|
235
|
+
|
|
236
|
+
**Serialization Steps**:
|
|
237
|
+
|
|
238
|
+
1. **Generate YAML Front-Matter**
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
---
|
|
242
|
+
name: 'Product Requirements Document'
|
|
243
|
+
version: '1.0.0'
|
|
244
|
+
date: '{{provenance.timestamp}}'
|
|
245
|
+
author: '{{provenance.author}}'
|
|
246
|
+
---
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
2. **Create Document Header**
|
|
250
|
+
|
|
251
|
+
```markdown
|
|
252
|
+
# {{project_name}} - Product Requirements Document
|
|
253
|
+
|
|
254
|
+
**Author:** {{provenance.author}} **Date:** {{provenance.timestamp}}
|
|
255
|
+
**Version:** 1.0
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
3. **Generate Change Log**
|
|
259
|
+
|
|
260
|
+
```markdown
|
|
261
|
+
## Change Log
|
|
262
|
+
|
|
263
|
+
| Date | Version | Description | Author |
|
|
264
|
+
| :------- | :------ | :-------------- | :--------- |
|
|
265
|
+
| {{date}} | 1.0 | Initial version | {{author}} |
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
4. **Convert APS Changes → Requirements**
|
|
269
|
+
- `file_create` → FR-01: Create {{path}} - {{description}}
|
|
270
|
+
- `file_update` → FR-02: Update {{path}} - {{description}}
|
|
271
|
+
- `config_change` → NFR-01: {{description}}
|
|
272
|
+
|
|
273
|
+
5. **Generate Sections**
|
|
274
|
+
|
|
275
|
+
```markdown
|
|
276
|
+
## Functional Requirements
|
|
277
|
+
|
|
278
|
+
FR-01: {{change.description}} ({{change.path}}) FR-02: {{change.description}}
|
|
279
|
+
({{change.path}})
|
|
280
|
+
|
|
281
|
+
## Non-Functional Requirements
|
|
282
|
+
|
|
283
|
+
NFR-01: {{validation.required_checks}}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Implementation Plan
|
|
289
|
+
|
|
290
|
+
### File Structure
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
packages/adapters/src/bmad/
|
|
294
|
+
├── format-adapter.ts # Main FormatAdapter implementation
|
|
295
|
+
├── parser.ts # Document parsing logic
|
|
296
|
+
├── serializer.ts # Document generation logic
|
|
297
|
+
├── types.ts # BMAD-specific types
|
|
298
|
+
├── utils.ts # Helper utilities
|
|
299
|
+
└── __tests__/
|
|
300
|
+
├── bmad-format-adapter.test.ts
|
|
301
|
+
├── bmad-parser.test.ts
|
|
302
|
+
├── bmad-serializer.test.ts
|
|
303
|
+
└── fixtures/
|
|
304
|
+
├── valid-prd.md
|
|
305
|
+
├── valid-architecture.md
|
|
306
|
+
├── valid-epic.md
|
|
307
|
+
├── valid-story.md
|
|
308
|
+
└── invalid-documents/
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Test Strategy
|
|
312
|
+
|
|
313
|
+
**Target**: 50+ tests (match SpecKit coverage)
|
|
314
|
+
|
|
315
|
+
**Test Categories**:
|
|
316
|
+
|
|
317
|
+
1. **Format Detection Tests** (15 tests)
|
|
318
|
+
- Valid PRD detection (high confidence)
|
|
319
|
+
- Valid Architecture doc detection
|
|
320
|
+
- User story format detection
|
|
321
|
+
- Edge cases (partial matches, false positives)
|
|
322
|
+
- Confidence scoring accuracy
|
|
323
|
+
|
|
324
|
+
2. **Parser Tests** (20 tests)
|
|
325
|
+
- Parse PRD with FRs/NFRs
|
|
326
|
+
- Parse Architecture document
|
|
327
|
+
- Parse Epic document
|
|
328
|
+
- Parse Story document
|
|
329
|
+
- YAML front-matter extraction
|
|
330
|
+
- Requirement identifier extraction
|
|
331
|
+
- User story format parsing
|
|
332
|
+
- Change log parsing
|
|
333
|
+
- Invalid document handling
|
|
334
|
+
- Missing sections handling
|
|
335
|
+
|
|
336
|
+
3. **Serializer Tests** (10 tests)
|
|
337
|
+
- Generate PRD from APS
|
|
338
|
+
- Generate Architecture doc from APS
|
|
339
|
+
- YAML front-matter generation
|
|
340
|
+
- Requirement numbering
|
|
341
|
+
- Change log generation
|
|
342
|
+
- Round-trip fidelity
|
|
343
|
+
|
|
344
|
+
4. **Integration Tests** (5 tests)
|
|
345
|
+
- canImport/canExport
|
|
346
|
+
- Full parse → serialize → parse cycle
|
|
347
|
+
- Multiple document types
|
|
348
|
+
- Edge cases
|
|
349
|
+
|
|
350
|
+
### Fixtures Required
|
|
351
|
+
|
|
352
|
+
**Valid Documents**:
|
|
353
|
+
|
|
354
|
+
- `valid-prd.md` - Complete PRD with FRs, NFRs, Epics, Stories
|
|
355
|
+
- `valid-architecture.md` - Architecture doc with all sections
|
|
356
|
+
- `valid-epic.md` - Epic with goal and stories
|
|
357
|
+
- `valid-story.md` - User story with acceptance criteria
|
|
358
|
+
|
|
359
|
+
**Invalid Documents**:
|
|
360
|
+
|
|
361
|
+
- `invalid-no-requirements.md` - Missing FR/NFR sections
|
|
362
|
+
- `invalid-malformed-yaml.md` - Bad YAML front-matter
|
|
363
|
+
- `invalid-generic-markdown.md` - Regular markdown
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Registration
|
|
368
|
+
|
|
369
|
+
Update `packages/adapters/src/index.ts`:
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// Auto-register adapters when module is imported
|
|
373
|
+
import { registry as baseRegistry } from './base/index.js';
|
|
374
|
+
import { BMADFormatAdapter } from './bmad/index.js';
|
|
375
|
+
|
|
376
|
+
// Register BMAD adapter
|
|
377
|
+
baseRegistry.register(new BMADFormatAdapter());
|
|
378
|
+
|
|
379
|
+
export { baseRegistry as registry };
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## CLI Integration Testing
|
|
385
|
+
|
|
386
|
+
Once implemented, test with CLI:
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
# Test format detection
|
|
390
|
+
anvil validate docs/prd.md
|
|
391
|
+
# Expected: ✓ Detected format: bmad (95% confidence)
|
|
392
|
+
|
|
393
|
+
# Test gate command
|
|
394
|
+
anvil gate docs/architecture.md
|
|
395
|
+
# Expected: Runs all quality gates on BMAD architecture doc
|
|
396
|
+
|
|
397
|
+
# Test export
|
|
398
|
+
anvil export docs/prd.md --to aps
|
|
399
|
+
# Expected: Converts BMAD PRD to APS JSON
|
|
400
|
+
|
|
401
|
+
# Test reverse (APS → BMAD)
|
|
402
|
+
anvil export plan.json --to bmad --output docs/
|
|
403
|
+
# Expected: Generates docs/prd.md in BMAD format
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Success Criteria
|
|
409
|
+
|
|
410
|
+
- [ ] Implements `FormatAdapter` interface correctly
|
|
411
|
+
- [ ] Registered with `AdapterRegistry` on module import
|
|
412
|
+
- [ ] `anvil validate docs/prd.md` works with auto-detection
|
|
413
|
+
- [ ] `anvil gate docs/architecture.md` works with auto-detection
|
|
414
|
+
- [ ] `anvil export docs/prd.md --to=aps` works
|
|
415
|
+
- [ ] `anvil export plan.json --to=bmad` works
|
|
416
|
+
- [ ] All 50+ tests passing
|
|
417
|
+
- [ ] Format detection confidence >80% for valid BMAD docs
|
|
418
|
+
- [ ] Round-trip fidelity preserved (PRD → APS → PRD)
|
|
419
|
+
- [ ] Serves as reference for SpecKit FormatAdapter migration
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Timeline
|
|
424
|
+
|
|
425
|
+
- **Week 8 Day 1-2**: Implementation (format-adapter.ts, parser.ts,
|
|
426
|
+
serializer.ts)
|
|
427
|
+
- **Week 8 Day 3**: Tests and fixtures
|
|
428
|
+
- **Week 8 Day 4**: CLI integration testing
|
|
429
|
+
- **Week 8 Day 5**: Documentation and cleanup
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## BMAD v6 Compatibility (ADAPTUP)
|
|
434
|
+
|
|
435
|
+
**Added**: 2026-02-09 **Module**:
|
|
436
|
+
`plans/modules/adapter-upstream-updates.aps.md`
|
|
437
|
+
|
|
438
|
+
### Breaking Changes in v6.0.0-alpha.23
|
|
439
|
+
|
|
440
|
+
| Change | Old | New | Adapter Support |
|
|
441
|
+
| --------------- | ---------------- | ---------------- | ---------------- |
|
|
442
|
+
| Project folder | `.bmad` | `_bmad` | Both detected |
|
|
443
|
+
| Config folder | `_cfg` | `_config` | Both detected |
|
|
444
|
+
| Variable syntax | `{project_root}` | `{project-root}` | Both expanded |
|
|
445
|
+
| Module config | Various | `module.yaml` | Constant defined |
|
|
446
|
+
|
|
447
|
+
### New Features
|
|
448
|
+
|
|
449
|
+
**Path-aware detection** — `detectWithPath(content, hint)` uses folder structure
|
|
450
|
+
to boost confidence when files are inside `_bmad/` or `.bmad/` directories.
|
|
451
|
+
|
|
452
|
+
**`hasSidecar` field** — Agent documents can declare `hasSidecar: true` in YAML
|
|
453
|
+
front-matter. The adapter parses YAML boolean values (`true`/`false`,
|
|
454
|
+
`yes`/`no`, `on`/`off`) and warns when agent documents are missing this field.
|
|
455
|
+
|
|
456
|
+
**AGENT document type** — `BMADDocumentType.AGENT` identifies agent
|
|
457
|
+
persona/configuration documents, detected via `hasSidecar` field or front-matter
|
|
458
|
+
name containing "agent".
|
|
459
|
+
|
|
460
|
+
**Variable expansion** — `expandVariables()` handles both underscore
|
|
461
|
+
(`{project_root}`) and hyphenated (`{project-root}`) syntax, normalising keys in
|
|
462
|
+
either direction.
|
|
463
|
+
|
|
464
|
+
**`BMAD_FOLDERS` constants** — Exported from `bmad/types.ts`:
|
|
465
|
+
|
|
466
|
+
- `PROJECT` = `_bmad` / `PROJECT_LEGACY` = `.bmad`
|
|
467
|
+
- `CONFIG` = `_config` / `CONFIG_LEGACY` = `_cfg`
|
|
468
|
+
- `MEMORY` = `_memory`
|
|
469
|
+
- `MODULE_CONFIG` = `module.yaml`
|
|
470
|
+
|
|
471
|
+
### Backward Compatibility
|
|
472
|
+
|
|
473
|
+
All v5 documents continue to work. Legacy folder paths (`.bmad`, `_cfg`) and
|
|
474
|
+
underscore variable syntax (`{project_root}`) are detected and processed
|
|
475
|
+
alongside their v6 equivalents.
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## References
|
|
480
|
+
|
|
481
|
+
- **Context7**: `/bmad-code-org/bmad-method` - 3001 code snippets
|
|
482
|
+
- **GitHub**: https://github.com/bmad-code-org/BMAD-METHOD
|
|
483
|
+
- **FormatAdapter Interface**: `packages/adapters/src/base/types.ts`
|
|
484
|
+
- **SpecKit Reference**: `packages/adapters/src/speckit/` (69 tests)
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
**Created**: 2025-10-23 **Author**: Anvil Team **Sprint**: Week 8 - BMAD Adapter
|
|
489
|
+
Implementation
|
package/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Copyright (c) 2026 EddaCraft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
PROPRIETARY AND CONFIDENTIAL
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
exclusive property of EddaCraft. Unauthorised copying, modification,
|
|
7
|
+
distribution, or use of this Software, via any medium, is strictly prohibited
|
|
8
|
+
without the express written permission of EddaCraft.
|
|
9
|
+
|
|
10
|
+
The Software is provided for evaluation and testing purposes only to authorised
|
|
11
|
+
beta testers. No licence is granted to use, copy, modify, or distribute the
|
|
12
|
+
Software for any other purpose.
|
|
13
|
+
|
|
14
|
+
For licensing enquiries, contact: legal@eddacraft.com
|