@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.
Files changed (183) hide show
  1. package/AGENTS.md +180 -0
  2. package/BMAD_ADAPTER_SPEC.md +489 -0
  3. package/LICENSE +14 -0
  4. package/README.md +500 -0
  5. package/dist/aps-markdown/adapter.d.ts +102 -0
  6. package/dist/aps-markdown/adapter.d.ts.map +1 -0
  7. package/dist/aps-markdown/adapter.js +351 -0
  8. package/dist/aps-markdown/index.d.ts +8 -0
  9. package/dist/aps-markdown/index.d.ts.map +1 -0
  10. package/dist/aps-markdown/index.js +7 -0
  11. package/dist/base/file-discovery.d.ts +63 -0
  12. package/dist/base/file-discovery.d.ts.map +1 -0
  13. package/dist/base/file-discovery.js +246 -0
  14. package/dist/base/index.d.ts +10 -0
  15. package/dist/base/index.d.ts.map +1 -0
  16. package/dist/base/index.js +9 -0
  17. package/dist/base/registry.d.ts +155 -0
  18. package/dist/base/registry.d.ts.map +1 -0
  19. package/dist/base/registry.js +227 -0
  20. package/dist/base/testing.d.ts +102 -0
  21. package/dist/base/testing.d.ts.map +1 -0
  22. package/dist/base/testing.js +221 -0
  23. package/dist/base/types.d.ts +255 -0
  24. package/dist/base/types.d.ts.map +1 -0
  25. package/dist/base/types.js +78 -0
  26. package/dist/base/utils.d.ts +127 -0
  27. package/dist/base/utils.d.ts.map +1 -0
  28. package/dist/base/utils.js +254 -0
  29. package/dist/bmad/format-adapter.d.ts +76 -0
  30. package/dist/bmad/format-adapter.d.ts.map +1 -0
  31. package/dist/bmad/format-adapter.js +186 -0
  32. package/dist/bmad/index.d.ts +12 -0
  33. package/dist/bmad/index.d.ts.map +1 -0
  34. package/dist/bmad/index.js +10 -0
  35. package/dist/bmad/parser.d.ts +12 -0
  36. package/dist/bmad/parser.d.ts.map +1 -0
  37. package/dist/bmad/parser.js +181 -0
  38. package/dist/bmad/serializer.d.ts +16 -0
  39. package/dist/bmad/serializer.d.ts.map +1 -0
  40. package/dist/bmad/serializer.js +170 -0
  41. package/dist/bmad/types.d.ts +127 -0
  42. package/dist/bmad/types.d.ts.map +1 -0
  43. package/dist/bmad/types.js +47 -0
  44. package/dist/bmad/utils.d.ts +120 -0
  45. package/dist/bmad/utils.d.ts.map +1 -0
  46. package/dist/bmad/utils.js +480 -0
  47. package/dist/common/index.d.ts +3 -0
  48. package/dist/common/index.d.ts.map +1 -0
  49. package/dist/common/index.js +2 -0
  50. package/dist/common/registry.d.ts +18 -0
  51. package/dist/common/registry.d.ts.map +1 -0
  52. package/dist/common/registry.js +58 -0
  53. package/dist/common/types.d.ts +68 -0
  54. package/dist/common/types.d.ts.map +1 -0
  55. package/dist/common/types.js +12 -0
  56. package/dist/generic/format-adapter.d.ts +64 -0
  57. package/dist/generic/format-adapter.d.ts.map +1 -0
  58. package/dist/generic/format-adapter.js +159 -0
  59. package/dist/generic/index.d.ts +10 -0
  60. package/dist/generic/index.d.ts.map +1 -0
  61. package/dist/generic/index.js +9 -0
  62. package/dist/generic/parser.d.ts +11 -0
  63. package/dist/generic/parser.d.ts.map +1 -0
  64. package/dist/generic/parser.js +106 -0
  65. package/dist/generic/serializer.d.ts +11 -0
  66. package/dist/generic/serializer.d.ts.map +1 -0
  67. package/dist/generic/serializer.js +118 -0
  68. package/dist/generic/types.d.ts +52 -0
  69. package/dist/generic/types.d.ts.map +1 -0
  70. package/dist/generic/types.js +6 -0
  71. package/dist/generic/utils.d.ts +51 -0
  72. package/dist/generic/utils.d.ts.map +1 -0
  73. package/dist/generic/utils.js +232 -0
  74. package/dist/index.d.ts +15 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +31 -0
  77. package/dist/speckit/export.d.ts +22 -0
  78. package/dist/speckit/export.d.ts.map +1 -0
  79. package/dist/speckit/export.js +384 -0
  80. package/dist/speckit/format-adapter.d.ts +104 -0
  81. package/dist/speckit/format-adapter.d.ts.map +1 -0
  82. package/dist/speckit/format-adapter.js +488 -0
  83. package/dist/speckit/import-v2.d.ts +33 -0
  84. package/dist/speckit/import-v2.d.ts.map +1 -0
  85. package/dist/speckit/import-v2.js +361 -0
  86. package/dist/speckit/import.d.ts +16 -0
  87. package/dist/speckit/import.d.ts.map +1 -0
  88. package/dist/speckit/import.js +247 -0
  89. package/dist/speckit/index.d.ts +5 -0
  90. package/dist/speckit/index.d.ts.map +1 -0
  91. package/dist/speckit/index.js +4 -0
  92. package/dist/speckit/parser.d.ts +28 -0
  93. package/dist/speckit/parser.d.ts.map +1 -0
  94. package/dist/speckit/parser.js +283 -0
  95. package/dist/speckit/parsers/plan-parser.d.ts +71 -0
  96. package/dist/speckit/parsers/plan-parser.d.ts.map +1 -0
  97. package/dist/speckit/parsers/plan-parser.js +216 -0
  98. package/dist/speckit/parsers/spec-parser.d.ts +67 -0
  99. package/dist/speckit/parsers/spec-parser.d.ts.map +1 -0
  100. package/dist/speckit/parsers/spec-parser.js +255 -0
  101. package/dist/speckit/parsers/tasks-parser.d.ts +57 -0
  102. package/dist/speckit/parsers/tasks-parser.d.ts.map +1 -0
  103. package/dist/speckit/parsers/tasks-parser.js +157 -0
  104. package/package.json +23 -0
  105. package/project.json +29 -0
  106. package/src/__tests__/adapter-edge-cases.test.ts +937 -0
  107. package/src/__tests__/bmad-format-adapter.test.ts +1470 -0
  108. package/src/__tests__/fixtures/aps/expected-output.json +83 -0
  109. package/src/__tests__/fixtures/bmad/invalid-malformed-yaml.md +16 -0
  110. package/src/__tests__/fixtures/bmad/invalid-no-requirements.md +23 -0
  111. package/src/__tests__/fixtures/bmad/invalid-only-yaml.md +16 -0
  112. package/src/__tests__/fixtures/bmad/invalid-too-short.md +3 -0
  113. package/src/__tests__/fixtures/bmad/invalid-wrong-format.md +40 -0
  114. package/src/__tests__/fixtures/bmad/valid-agent.md +27 -0
  115. package/src/__tests__/fixtures/bmad/valid-architecture.md +116 -0
  116. package/src/__tests__/fixtures/bmad/valid-complex-prd.md +161 -0
  117. package/src/__tests__/fixtures/bmad/valid-epic.md +73 -0
  118. package/src/__tests__/fixtures/bmad/valid-minimal-prd.md +19 -0
  119. package/src/__tests__/fixtures/bmad/valid-prd.md +107 -0
  120. package/src/__tests__/fixtures/bmad/valid-story.md +107 -0
  121. package/src/__tests__/fixtures/bmad/valid-task.md +79 -0
  122. package/src/__tests__/fixtures/bmad/valid-v6-prd.md +35 -0
  123. package/src/__tests__/fixtures/generic/plan-detailed.md +39 -0
  124. package/src/__tests__/fixtures/generic/prd-simple.md +27 -0
  125. package/src/__tests__/fixtures/generic/rfc-example.md +26 -0
  126. package/src/__tests__/fixtures/generic/todo-list.md +23 -0
  127. package/src/__tests__/fixtures/speckit/sample-plan.md +63 -0
  128. package/src/__tests__/fixtures/speckit/sample-spec-namespaced.md +50 -0
  129. package/src/__tests__/fixtures/speckit/sample-spec.md +105 -0
  130. package/src/__tests__/fixtures/speckit/sample-tasks.md +87 -0
  131. package/src/__tests__/fixtures/speckit-official/auth-feature/plan.md +272 -0
  132. package/src/__tests__/fixtures/speckit-official/auth-feature/spec.md +149 -0
  133. package/src/__tests__/fixtures/speckit-official/auth-feature/tasks.md +169 -0
  134. package/src/__tests__/generic-format-adapter.test.ts +398 -0
  135. package/src/__tests__/speckit-export.test.ts +233 -0
  136. package/src/__tests__/speckit-format-adapter.test.ts +832 -0
  137. package/src/__tests__/speckit-import-v2.test.ts +253 -0
  138. package/src/__tests__/speckit-import.test.ts +209 -0
  139. package/src/__tests__/speckit-parser.test.ts +219 -0
  140. package/src/__tests__/speckit-spec-parser.test.ts +120 -0
  141. package/src/aps-markdown/__tests__/__fixtures__/simple-leaf.aps.md +17 -0
  142. package/src/aps-markdown/__tests__/adapter.test.ts +393 -0
  143. package/src/aps-markdown/adapter.ts +455 -0
  144. package/src/aps-markdown/index.ts +8 -0
  145. package/src/base/__tests__/registry.test.ts +515 -0
  146. package/src/base/file-discovery.ts +305 -0
  147. package/src/base/index.ts +10 -0
  148. package/src/base/registry.ts +263 -0
  149. package/src/base/testing.ts +334 -0
  150. package/src/base/types.ts +342 -0
  151. package/src/base/utils.ts +306 -0
  152. package/src/bmad/format-adapter.ts +227 -0
  153. package/src/bmad/index.ts +21 -0
  154. package/src/bmad/parser.ts +224 -0
  155. package/src/bmad/serializer.ts +206 -0
  156. package/src/bmad/types.ts +135 -0
  157. package/src/bmad/utils.ts +575 -0
  158. package/src/common/index.ts +2 -0
  159. package/src/common/registry.ts +72 -0
  160. package/src/common/types.ts +84 -0
  161. package/src/generic/__tests__/serializer.test.ts +167 -0
  162. package/src/generic/format-adapter.ts +200 -0
  163. package/src/generic/index.ts +11 -0
  164. package/src/generic/parser.ts +129 -0
  165. package/src/generic/serializer.ts +134 -0
  166. package/src/generic/types.ts +53 -0
  167. package/src/generic/utils.ts +270 -0
  168. package/src/index.ts +48 -0
  169. package/src/speckit/export.ts +489 -0
  170. package/src/speckit/format-adapter.ts +595 -0
  171. package/src/speckit/import-v2.ts +445 -0
  172. package/src/speckit/import.ts +305 -0
  173. package/src/speckit/index.ts +4 -0
  174. package/src/speckit/parser.ts +351 -0
  175. package/src/speckit/parsers/plan-parser.ts +342 -0
  176. package/src/speckit/parsers/spec-parser.ts +379 -0
  177. package/src/speckit/parsers/tasks-parser.ts +246 -0
  178. package/tsconfig.json +26 -0
  179. package/tsconfig.lib.json +21 -0
  180. package/tsconfig.lib.tsbuildinfo +1 -0
  181. package/tsconfig.spec.json +9 -0
  182. package/tsconfig.tsbuildinfo +1 -0
  183. 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