@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
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Adapter Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for parsing generic markdown documents.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Extract document title from first heading
|
|
8
|
+
*/
|
|
9
|
+
export function extractTitle(content) {
|
|
10
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
11
|
+
return match ? match[1].trim() : undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract intent from common sections
|
|
15
|
+
*/
|
|
16
|
+
export function extractIntent(content) {
|
|
17
|
+
// Look for sections like: Purpose, Intent, Objective, Goal, Summary
|
|
18
|
+
const patterns = [
|
|
19
|
+
/##\s+(?:Purpose|Intent|Objective|Goal)\s*\n+([^\n#]+)/i,
|
|
20
|
+
/##\s+(?:Executive\s+)?Summary\s*\n+([^\n#]+)/i,
|
|
21
|
+
/^([^#\n]+?)(?=\n##|\n#|$)/m, // First paragraph as fallback
|
|
22
|
+
];
|
|
23
|
+
for (const pattern of patterns) {
|
|
24
|
+
const match = content.match(pattern);
|
|
25
|
+
if (match && match[1]) {
|
|
26
|
+
return match[1].trim().substring(0, 500); // Limit length
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extract overview/description
|
|
33
|
+
*/
|
|
34
|
+
export function extractOverview(content) {
|
|
35
|
+
const patterns = [/##\s+(?:Overview|Description|Background|Context)\s*\n+([\s\S]+?)(?=\n##|$)/i];
|
|
36
|
+
for (const pattern of patterns) {
|
|
37
|
+
const match = content.match(pattern);
|
|
38
|
+
if (match && match[1]) {
|
|
39
|
+
return match[1].trim();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extract goals from lists under Goals/Objectives sections
|
|
46
|
+
*/
|
|
47
|
+
export function extractGoals(content) {
|
|
48
|
+
const goals = [];
|
|
49
|
+
// Match Goals/Objectives section
|
|
50
|
+
const sectionMatch = content.match(/##\s+(?:Goals?|Objectives?)\s*\n+([\s\S]+?)(?=\n##|$)/i);
|
|
51
|
+
if (sectionMatch) {
|
|
52
|
+
const section = sectionMatch[1];
|
|
53
|
+
// Extract list items
|
|
54
|
+
const listItems = section.match(/^[-*]\s+(.+)$/gm);
|
|
55
|
+
if (listItems) {
|
|
56
|
+
goals.push(...listItems.map((item) => item.replace(/^[-*]\s+/, '').trim()));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return goals;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Extract requirements from various sections
|
|
63
|
+
*/
|
|
64
|
+
export function extractRequirements(content) {
|
|
65
|
+
const requirements = [];
|
|
66
|
+
// Match Requirements/Needs/Must Have sections
|
|
67
|
+
const patterns = [
|
|
68
|
+
/##\s+(?:Requirements?|Needs?|Must\s+Have)\s*\n+([\s\S]+?)(?=\n##|$)/i,
|
|
69
|
+
/##\s+(?:Functional\s+)?Requirements?\s*\n+([\s\S]+?)(?=\n##|$)/i,
|
|
70
|
+
];
|
|
71
|
+
for (const pattern of patterns) {
|
|
72
|
+
const match = content.match(pattern);
|
|
73
|
+
if (match) {
|
|
74
|
+
const section = match[1];
|
|
75
|
+
// Extract list items
|
|
76
|
+
const listItems = section.match(/^[-*]\s+(.+)$/gm);
|
|
77
|
+
if (listItems) {
|
|
78
|
+
requirements.push(...listItems.map((item) => item.replace(/^[-*]\s+/, '').trim()));
|
|
79
|
+
}
|
|
80
|
+
// Extract numbered items
|
|
81
|
+
const numberedItems = section.match(/^\d+\.\s+(.+)$/gm);
|
|
82
|
+
if (numberedItems) {
|
|
83
|
+
requirements.push(...numberedItems.map((item) => item.replace(/^\d+\.\s+/, '').trim()));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return requirements;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Extract tasks from Tasks/Action Items sections
|
|
91
|
+
*/
|
|
92
|
+
export function extractTasks(content) {
|
|
93
|
+
const tasks = [];
|
|
94
|
+
const patterns = [/##\s+(?:Tasks?|Action\s+Items?|To\s+Do|TODO)\s*\n+([\s\S]+?)(?=\n##|$)/i];
|
|
95
|
+
for (const pattern of patterns) {
|
|
96
|
+
const match = content.match(pattern);
|
|
97
|
+
if (match) {
|
|
98
|
+
const section = match[1];
|
|
99
|
+
// Extract list items (including checkboxes)
|
|
100
|
+
const listItems = section.match(/^[-*]\s+(?:\[[ x]\]\s+)?(.+)$/gm);
|
|
101
|
+
if (listItems) {
|
|
102
|
+
tasks.push(...listItems.map((item) => item.replace(/^[-*]\s+(?:\[[ x]\]\s+)?/, '').trim()));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return tasks;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Extract features from Features/Capabilities sections
|
|
110
|
+
*/
|
|
111
|
+
export function extractFeatures(content) {
|
|
112
|
+
const features = [];
|
|
113
|
+
const patterns = [/##\s+(?:Features?|Capabilities?|Functionality)\s*\n+([\s\S]+?)(?=\n##|$)/i];
|
|
114
|
+
for (const pattern of patterns) {
|
|
115
|
+
const match = content.match(pattern);
|
|
116
|
+
if (match) {
|
|
117
|
+
const section = match[1];
|
|
118
|
+
const listItems = section.match(/^[-*]\s+(.+)$/gm);
|
|
119
|
+
if (listItems) {
|
|
120
|
+
features.push(...listItems.map((item) => item.replace(/^[-*]\s+/, '').trim()));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return features;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Analyze content for generic markdown indicators
|
|
128
|
+
*/
|
|
129
|
+
export function analyzeContent(content) {
|
|
130
|
+
const headings = content.match(/^#{1,6}\s+.+$/gm) || [];
|
|
131
|
+
const listItems = content.match(/^[-*]\s+.+$/gm) || [];
|
|
132
|
+
const words = content.split(/\s+/).filter((w) => w.length > 0);
|
|
133
|
+
return {
|
|
134
|
+
hasHeadings: headings.length > 0,
|
|
135
|
+
hasLists: listItems.length > 0,
|
|
136
|
+
hasRequirementsSection: /##\s+(?:Requirements?|Needs?)/i.test(content),
|
|
137
|
+
hasGoalsSection: /##\s+(?:Goals?|Objectives?)/i.test(content),
|
|
138
|
+
hasTasksSection: /##\s+(?:Tasks?|Action\s+Items?|To\s+Do)/i.test(content),
|
|
139
|
+
hasFeaturesSection: /##\s+(?:Features?|Capabilities?)/i.test(content),
|
|
140
|
+
hasOverviewSection: /##\s+(?:Overview|Description|Background)/i.test(content),
|
|
141
|
+
wordCount: words.length,
|
|
142
|
+
listItemCount: listItems.length,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Calculate confidence score for generic markdown detection
|
|
147
|
+
*/
|
|
148
|
+
export function calculateConfidenceScore(indicators) {
|
|
149
|
+
let score = 0;
|
|
150
|
+
// Basic markdown structure (10 points)
|
|
151
|
+
if (indicators.hasHeadings) {
|
|
152
|
+
score += 10;
|
|
153
|
+
}
|
|
154
|
+
// Has lists (10 points)
|
|
155
|
+
if (indicators.hasLists) {
|
|
156
|
+
score += 10;
|
|
157
|
+
}
|
|
158
|
+
// Planning-related sections (5 points each)
|
|
159
|
+
if (indicators.hasRequirementsSection) {
|
|
160
|
+
score += 5;
|
|
161
|
+
}
|
|
162
|
+
if (indicators.hasGoalsSection) {
|
|
163
|
+
score += 5;
|
|
164
|
+
}
|
|
165
|
+
if (indicators.hasTasksSection) {
|
|
166
|
+
score += 5;
|
|
167
|
+
}
|
|
168
|
+
if (indicators.hasFeaturesSection) {
|
|
169
|
+
score += 5;
|
|
170
|
+
}
|
|
171
|
+
if (indicators.hasOverviewSection) {
|
|
172
|
+
score += 5;
|
|
173
|
+
}
|
|
174
|
+
// Content density (up to 10 points)
|
|
175
|
+
if (indicators.wordCount >= 100) {
|
|
176
|
+
score += 5;
|
|
177
|
+
}
|
|
178
|
+
if (indicators.wordCount >= 500) {
|
|
179
|
+
score += 5;
|
|
180
|
+
}
|
|
181
|
+
// List items (up to 5 points)
|
|
182
|
+
if (indicators.listItemCount >= 3) {
|
|
183
|
+
score += 3;
|
|
184
|
+
}
|
|
185
|
+
if (indicators.listItemCount >= 10) {
|
|
186
|
+
score += 2;
|
|
187
|
+
}
|
|
188
|
+
return Math.min(100, score);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Build detection reason string
|
|
192
|
+
*/
|
|
193
|
+
export function buildDetectionReason(indicators) {
|
|
194
|
+
const reasons = [];
|
|
195
|
+
if (indicators.hasHeadings) {
|
|
196
|
+
reasons.push('markdown-headings');
|
|
197
|
+
}
|
|
198
|
+
if (indicators.hasLists) {
|
|
199
|
+
reasons.push(`${indicators.listItemCount} list-items`);
|
|
200
|
+
}
|
|
201
|
+
if (indicators.hasRequirementsSection) {
|
|
202
|
+
reasons.push('requirements-section');
|
|
203
|
+
}
|
|
204
|
+
if (indicators.hasGoalsSection) {
|
|
205
|
+
reasons.push('goals-section');
|
|
206
|
+
}
|
|
207
|
+
if (indicators.hasTasksSection) {
|
|
208
|
+
reasons.push('tasks-section');
|
|
209
|
+
}
|
|
210
|
+
if (indicators.hasFeaturesSection) {
|
|
211
|
+
reasons.push('features-section');
|
|
212
|
+
}
|
|
213
|
+
if (indicators.hasOverviewSection) {
|
|
214
|
+
reasons.push('overview-section');
|
|
215
|
+
}
|
|
216
|
+
return reasons.length > 0 ? reasons.join(', ') : 'generic-markdown';
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Parse generic markdown document
|
|
220
|
+
*/
|
|
221
|
+
export function parseGenericDocument(content) {
|
|
222
|
+
return {
|
|
223
|
+
title: extractTitle(content),
|
|
224
|
+
intent: extractIntent(content),
|
|
225
|
+
overview: extractOverview(content),
|
|
226
|
+
goals: extractGoals(content),
|
|
227
|
+
requirements: extractRequirements(content),
|
|
228
|
+
tasks: extractTasks(content),
|
|
229
|
+
features: extractFeatures(content),
|
|
230
|
+
raw: content,
|
|
231
|
+
};
|
|
232
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anvil Adapters Package
|
|
3
|
+
*
|
|
4
|
+
* Provides format adapters for converting between external planning formats
|
|
5
|
+
* (SpecKit, BMAD, etc.) and the Anvil Plan Spec (APS).
|
|
6
|
+
*/
|
|
7
|
+
export * from './base/index.js';
|
|
8
|
+
export * from './aps-markdown/index.js';
|
|
9
|
+
export * from './speckit/index.js';
|
|
10
|
+
export * from './bmad/index.js';
|
|
11
|
+
export * from './generic/index.js';
|
|
12
|
+
export type { SpecContext, ExternalSpec, ConversionResult, ConversionError, ConversionWarning, } from './common/types.js';
|
|
13
|
+
import { registry as baseRegistry } from './base/index.js';
|
|
14
|
+
export { baseRegistry as registry };
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,iBAAiB,CAAC;AAGhC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,oBAAoB,CAAC;AAGnC,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe3D,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anvil Adapters Package
|
|
3
|
+
*
|
|
4
|
+
* Provides format adapters for converting between external planning formats
|
|
5
|
+
* (SpecKit, BMAD, etc.) and the Anvil Plan Spec (APS).
|
|
6
|
+
*/
|
|
7
|
+
// Export base framework (types, registry, utils)
|
|
8
|
+
export * from './base/index.js';
|
|
9
|
+
// Export APS Markdown adapter (native format)
|
|
10
|
+
export * from './aps-markdown/index.js';
|
|
11
|
+
// Export SpecKit adapter
|
|
12
|
+
export * from './speckit/index.js';
|
|
13
|
+
// Export BMAD adapter
|
|
14
|
+
export * from './bmad/index.js';
|
|
15
|
+
// Export Generic adapter
|
|
16
|
+
export * from './generic/index.js';
|
|
17
|
+
// Auto-register adapters when module is imported
|
|
18
|
+
import { registry as baseRegistry } from './base/index.js';
|
|
19
|
+
import { APSMarkdownAdapter } from './aps-markdown/index.js';
|
|
20
|
+
import { BMADFormatAdapter } from './bmad/index.js';
|
|
21
|
+
import { SpecKitFormatAdapter } from './speckit/index.js';
|
|
22
|
+
import { GenericMarkdownAdapter } from './generic/index.js';
|
|
23
|
+
// Register adapters in priority order
|
|
24
|
+
// APS adapter first (native format), then specific external formats
|
|
25
|
+
// Generic adapter is registered last as fallback
|
|
26
|
+
baseRegistry.register(new APSMarkdownAdapter());
|
|
27
|
+
baseRegistry.register(new BMADFormatAdapter());
|
|
28
|
+
baseRegistry.register(new SpecKitFormatAdapter());
|
|
29
|
+
baseRegistry.register(new GenericMarkdownAdapter());
|
|
30
|
+
// Export the registry instance as default export
|
|
31
|
+
export { baseRegistry as registry };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { APSPlan, ValidationResult } from '@eddacraft/anvil-core';
|
|
2
|
+
import type { ConversionResult, ExternalSpec, SpecContext } from '../common/types.js';
|
|
3
|
+
import { BaseAdapter } from '../common/types.js';
|
|
4
|
+
export declare class SpecKitExportAdapter extends BaseAdapter {
|
|
5
|
+
readonly name = "speckit-export";
|
|
6
|
+
readonly version = "1.0.0";
|
|
7
|
+
readonly supportedFormats: readonly ["speckit", "spec.md"];
|
|
8
|
+
generateSpec(_intent: string, _context: SpecContext): Promise<APSPlan>;
|
|
9
|
+
validateSpec(spec: APSPlan): Promise<ValidationResult>;
|
|
10
|
+
convertToAPS(_spec: ExternalSpec): Promise<ConversionResult<APSPlan>>;
|
|
11
|
+
convertFromAPS(spec: APSPlan): Promise<ConversionResult<ExternalSpec>>;
|
|
12
|
+
private generateSpecMarkdown;
|
|
13
|
+
private generatePlanMarkdown;
|
|
14
|
+
private generateTasksMarkdown;
|
|
15
|
+
private groupChangesByType;
|
|
16
|
+
private formatChangeType;
|
|
17
|
+
private getFileExtension;
|
|
18
|
+
private filterCustomMetadata;
|
|
19
|
+
private convertChangesToSteps;
|
|
20
|
+
private convertChangesToTasks;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/speckit/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAU,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAEV,gBAAgB,EAEhB,YAAY,EACZ,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,qBAAa,oBAAqB,SAAQ,WAAW;IACnD,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,OAAO,WAAW;IAC3B,QAAQ,CAAC,gBAAgB,kCAAmC;IAEtD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAItE,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCtD,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAYrE,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAyC5E,OAAO,CAAC,oBAAoB;IA0F5B,OAAO,CAAC,oBAAoB;IA0C5B,OAAO,CAAC,qBAAqB;IAsE7B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,gBAAgB;IAwCxB,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,qBAAqB;IAmC7B,OAAO,CAAC,qBAAqB;CAyD9B"}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { BaseAdapter } from '../common/types.js';
|
|
2
|
+
export class SpecKitExportAdapter extends BaseAdapter {
|
|
3
|
+
name = 'speckit-export';
|
|
4
|
+
version = '1.0.0';
|
|
5
|
+
supportedFormats = ['speckit', 'spec.md'];
|
|
6
|
+
async generateSpec(_intent, _context) {
|
|
7
|
+
throw new Error('Use speckit-import adapter for generating new specs');
|
|
8
|
+
}
|
|
9
|
+
async validateSpec(spec) {
|
|
10
|
+
const issues = [];
|
|
11
|
+
if (!spec.intent || spec.intent.length < 10) {
|
|
12
|
+
issues.push({
|
|
13
|
+
path: 'intent',
|
|
14
|
+
message: 'Intent is required and must be at least 10 characters',
|
|
15
|
+
code: 'INVALID_INTENT',
|
|
16
|
+
severity: 'error',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (spec.proposed_changes.length === 0) {
|
|
20
|
+
issues.push({
|
|
21
|
+
path: 'proposed_changes',
|
|
22
|
+
message: 'No changes to export',
|
|
23
|
+
code: 'EMPTY_CHANGES',
|
|
24
|
+
severity: 'warning',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Only errors make validation invalid, warnings are ok
|
|
28
|
+
const hasErrors = issues.some((issue) => issue.severity === 'error');
|
|
29
|
+
return {
|
|
30
|
+
valid: !hasErrors,
|
|
31
|
+
data: spec,
|
|
32
|
+
issues: issues.length > 0 ? issues : undefined,
|
|
33
|
+
summary: hasErrors
|
|
34
|
+
? `Found ${issues.filter((i) => i.severity === 'error').length} error(s)`
|
|
35
|
+
: issues.length > 0
|
|
36
|
+
? `Validation passed with ${issues.length} warning(s)`
|
|
37
|
+
: 'Validation passed',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async convertToAPS(_spec) {
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
errors: [
|
|
44
|
+
{
|
|
45
|
+
code: 'NOT_IMPLEMENTED',
|
|
46
|
+
message: 'Import from SpecKit format is handled by speckit-import adapter',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async convertFromAPS(spec) {
|
|
52
|
+
const errors = [];
|
|
53
|
+
const warnings = [];
|
|
54
|
+
try {
|
|
55
|
+
const specContent = this.generateSpecMarkdown(spec);
|
|
56
|
+
const planContent = this.generatePlanMarkdown(spec);
|
|
57
|
+
const tasksContent = this.generateTasksMarkdown(spec);
|
|
58
|
+
const result = {
|
|
59
|
+
format: 'speckit',
|
|
60
|
+
version: '1.0.0',
|
|
61
|
+
content: {
|
|
62
|
+
specContent,
|
|
63
|
+
planContent,
|
|
64
|
+
tasksContent,
|
|
65
|
+
metadata: spec.metadata,
|
|
66
|
+
},
|
|
67
|
+
metadata: {
|
|
68
|
+
generated_at: new Date().toISOString(),
|
|
69
|
+
generator: this.name,
|
|
70
|
+
generator_version: this.version,
|
|
71
|
+
aps_id: spec.id,
|
|
72
|
+
aps_hash: spec.hash,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
data: result,
|
|
78
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
errors.push({
|
|
83
|
+
code: 'EXPORT_ERROR',
|
|
84
|
+
message: error instanceof Error ? error.message : 'Failed to export to SpecKit format',
|
|
85
|
+
});
|
|
86
|
+
return { success: false, errors };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
generateSpecMarkdown(spec) {
|
|
90
|
+
const sections = [];
|
|
91
|
+
sections.push(`# Specification`);
|
|
92
|
+
sections.push('');
|
|
93
|
+
sections.push(`## Intent`);
|
|
94
|
+
sections.push('');
|
|
95
|
+
sections.push(spec.intent);
|
|
96
|
+
sections.push('');
|
|
97
|
+
if (spec.metadata?.['overview']) {
|
|
98
|
+
sections.push(`## Overview`);
|
|
99
|
+
sections.push('');
|
|
100
|
+
sections.push(spec.metadata['overview']);
|
|
101
|
+
sections.push('');
|
|
102
|
+
}
|
|
103
|
+
if (spec.metadata?.['goals'] && Array.isArray(spec.metadata['goals'])) {
|
|
104
|
+
sections.push(`## Goals`);
|
|
105
|
+
sections.push('');
|
|
106
|
+
for (const goal of spec.metadata['goals']) {
|
|
107
|
+
sections.push(`- ${goal}`);
|
|
108
|
+
}
|
|
109
|
+
sections.push('');
|
|
110
|
+
}
|
|
111
|
+
if (spec.metadata?.['requirements'] && Array.isArray(spec.metadata['requirements'])) {
|
|
112
|
+
sections.push(`## Requirements`);
|
|
113
|
+
sections.push('');
|
|
114
|
+
for (const req of spec.metadata['requirements']) {
|
|
115
|
+
sections.push(`- ${req}`);
|
|
116
|
+
}
|
|
117
|
+
sections.push('');
|
|
118
|
+
}
|
|
119
|
+
if (spec.proposed_changes.length > 0) {
|
|
120
|
+
sections.push(`## Changes`);
|
|
121
|
+
sections.push('');
|
|
122
|
+
const changesByType = this.groupChangesByType(spec.proposed_changes);
|
|
123
|
+
for (const [type, changes] of Object.entries(changesByType)) {
|
|
124
|
+
if (changes.length > 0) {
|
|
125
|
+
sections.push(`### ${this.formatChangeType(type)}`);
|
|
126
|
+
sections.push('');
|
|
127
|
+
for (const change of changes) {
|
|
128
|
+
sections.push(`#### ${change.description}`);
|
|
129
|
+
sections.push('');
|
|
130
|
+
if (change.path) {
|
|
131
|
+
sections.push(`Path: \`${change.path}\``);
|
|
132
|
+
sections.push('');
|
|
133
|
+
}
|
|
134
|
+
if (change.content) {
|
|
135
|
+
const extension = this.getFileExtension(change.path || '');
|
|
136
|
+
sections.push(`\`\`\`${extension}`);
|
|
137
|
+
sections.push(change.content);
|
|
138
|
+
sections.push(`\`\`\``);
|
|
139
|
+
sections.push('');
|
|
140
|
+
}
|
|
141
|
+
if (change.diff) {
|
|
142
|
+
sections.push(`\`\`\`diff`);
|
|
143
|
+
sections.push(change.diff);
|
|
144
|
+
sections.push(`\`\`\``);
|
|
145
|
+
sections.push('');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (spec.metadata) {
|
|
152
|
+
const customMetadata = this.filterCustomMetadata(spec.metadata);
|
|
153
|
+
if (Object.keys(customMetadata).length > 0) {
|
|
154
|
+
sections.push(`## Metadata`);
|
|
155
|
+
sections.push('');
|
|
156
|
+
sections.push(`\`\`\`json`);
|
|
157
|
+
sections.push(JSON.stringify(customMetadata, null, 2));
|
|
158
|
+
sections.push(`\`\`\``);
|
|
159
|
+
sections.push('');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return sections.join('\n');
|
|
163
|
+
}
|
|
164
|
+
generatePlanMarkdown(spec) {
|
|
165
|
+
const sections = [];
|
|
166
|
+
sections.push(`# Implementation Plan`);
|
|
167
|
+
sections.push('');
|
|
168
|
+
sections.push(`Generated from APS: ${spec.id}`);
|
|
169
|
+
sections.push('');
|
|
170
|
+
sections.push(`## Summary`);
|
|
171
|
+
sections.push('');
|
|
172
|
+
sections.push(spec.intent);
|
|
173
|
+
sections.push('');
|
|
174
|
+
sections.push(`## Implementation Steps`);
|
|
175
|
+
sections.push('');
|
|
176
|
+
const steps = this.convertChangesToSteps(spec.proposed_changes);
|
|
177
|
+
for (let i = 0; i < steps.length; i++) {
|
|
178
|
+
const step = steps[i];
|
|
179
|
+
sections.push(`${i + 1}. **${step.title}**`);
|
|
180
|
+
if (step.details) {
|
|
181
|
+
sections.push(` - ${step.details}`);
|
|
182
|
+
}
|
|
183
|
+
if (step.dependencies.length > 0) {
|
|
184
|
+
sections.push(` - Dependencies: ${step.dependencies.join(', ')}`);
|
|
185
|
+
}
|
|
186
|
+
sections.push('');
|
|
187
|
+
}
|
|
188
|
+
if (spec.validations) {
|
|
189
|
+
sections.push(`## Validation Requirements`);
|
|
190
|
+
sections.push('');
|
|
191
|
+
sections.push(`- Required checks: ${spec.validations.required_checks.join(', ')}`);
|
|
192
|
+
if (spec.validations.skip_checks.length > 0) {
|
|
193
|
+
sections.push(`- Skipped checks: ${spec.validations.skip_checks.join(', ')}`);
|
|
194
|
+
}
|
|
195
|
+
sections.push('');
|
|
196
|
+
}
|
|
197
|
+
return sections.join('\n');
|
|
198
|
+
}
|
|
199
|
+
generateTasksMarkdown(spec) {
|
|
200
|
+
const sections = [];
|
|
201
|
+
sections.push(`# Tasks`);
|
|
202
|
+
sections.push('');
|
|
203
|
+
sections.push(`Generated from APS: ${spec.id}`);
|
|
204
|
+
sections.push(`Last updated: ${new Date().toISOString()}`);
|
|
205
|
+
sections.push('');
|
|
206
|
+
sections.push(`## Task List`);
|
|
207
|
+
sections.push('');
|
|
208
|
+
const tasks = this.convertChangesToTasks(spec.proposed_changes);
|
|
209
|
+
let completedCount = 0;
|
|
210
|
+
for (const task of tasks) {
|
|
211
|
+
const status = task.completed ? 'x' : ' ';
|
|
212
|
+
const statusEmoji = task.completed ? '✅' : '⏳';
|
|
213
|
+
sections.push(`- [${status}] ${statusEmoji} ${task.description}`);
|
|
214
|
+
if (task.subtasks.length > 0) {
|
|
215
|
+
for (const subtask of task.subtasks) {
|
|
216
|
+
const subStatus = subtask.completed ? 'x' : ' ';
|
|
217
|
+
sections.push(` - [${subStatus}] ${subtask.description}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (task.completed) {
|
|
221
|
+
completedCount++;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
sections.push('');
|
|
225
|
+
sections.push(`## Progress`);
|
|
226
|
+
sections.push('');
|
|
227
|
+
sections.push(`- Total tasks: ${tasks.length}`);
|
|
228
|
+
sections.push(`- Completed: ${completedCount}`);
|
|
229
|
+
sections.push(`- Remaining: ${tasks.length - completedCount}`);
|
|
230
|
+
sections.push(`- Progress: ${Math.round((completedCount / tasks.length) * 100)}%`);
|
|
231
|
+
sections.push('');
|
|
232
|
+
if (spec.executions && spec.executions.length > 0) {
|
|
233
|
+
sections.push(`## Execution History`);
|
|
234
|
+
sections.push('');
|
|
235
|
+
for (const execution of spec.executions) {
|
|
236
|
+
sections.push(`### ${new Date(execution.timestamp).toLocaleString()}`);
|
|
237
|
+
sections.push(`- Operation: ${execution.operation}`);
|
|
238
|
+
sections.push(`- Status: ${execution.status}`);
|
|
239
|
+
if (execution.executed_by) {
|
|
240
|
+
sections.push(`- Executed by: ${execution.executed_by}`);
|
|
241
|
+
}
|
|
242
|
+
if (execution.changes_applied && execution.changes_applied.length > 0) {
|
|
243
|
+
sections.push(`- Applied changes: ${execution.changes_applied.join(', ')}`);
|
|
244
|
+
}
|
|
245
|
+
if (execution.changes_failed && execution.changes_failed.length > 0) {
|
|
246
|
+
sections.push(`- Failed changes: ${execution.changes_failed.join(', ')}`);
|
|
247
|
+
}
|
|
248
|
+
if (execution.logs && execution.logs.length > 0) {
|
|
249
|
+
for (const log of execution.logs) {
|
|
250
|
+
sections.push(`- ${log}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
sections.push('');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return sections.join('\n');
|
|
257
|
+
}
|
|
258
|
+
groupChangesByType(changes) {
|
|
259
|
+
const groups = {};
|
|
260
|
+
for (const change of changes) {
|
|
261
|
+
if (!groups[change.type]) {
|
|
262
|
+
groups[change.type] = [];
|
|
263
|
+
}
|
|
264
|
+
groups[change.type].push(change);
|
|
265
|
+
}
|
|
266
|
+
return groups;
|
|
267
|
+
}
|
|
268
|
+
formatChangeType(type) {
|
|
269
|
+
const typeMap = {
|
|
270
|
+
file_create: 'Files to Create',
|
|
271
|
+
file_update: 'Files to Update',
|
|
272
|
+
file_delete: 'Files to Delete',
|
|
273
|
+
config_update: 'Configuration Changes',
|
|
274
|
+
dependency_add: 'Dependencies to Add',
|
|
275
|
+
dependency_remove: 'Dependencies to Remove',
|
|
276
|
+
dependency_update: 'Dependencies to Update',
|
|
277
|
+
script_execute: 'Scripts to Execute',
|
|
278
|
+
};
|
|
279
|
+
return typeMap[type] || type.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
|
|
280
|
+
}
|
|
281
|
+
getFileExtension(path) {
|
|
282
|
+
const ext = path.split('.').pop()?.toLowerCase();
|
|
283
|
+
const extMap = {
|
|
284
|
+
js: 'javascript',
|
|
285
|
+
ts: 'typescript',
|
|
286
|
+
jsx: 'javascript',
|
|
287
|
+
tsx: 'typescript',
|
|
288
|
+
py: 'python',
|
|
289
|
+
rb: 'ruby',
|
|
290
|
+
go: 'go',
|
|
291
|
+
rs: 'rust',
|
|
292
|
+
java: 'java',
|
|
293
|
+
cpp: 'cpp',
|
|
294
|
+
c: 'c',
|
|
295
|
+
h: 'c',
|
|
296
|
+
hpp: 'cpp',
|
|
297
|
+
cs: 'csharp',
|
|
298
|
+
php: 'php',
|
|
299
|
+
swift: 'swift',
|
|
300
|
+
kt: 'kotlin',
|
|
301
|
+
scala: 'scala',
|
|
302
|
+
r: 'r',
|
|
303
|
+
m: 'matlab',
|
|
304
|
+
sh: 'bash',
|
|
305
|
+
ps1: 'powershell',
|
|
306
|
+
sql: 'sql',
|
|
307
|
+
md: 'markdown',
|
|
308
|
+
yml: 'yaml',
|
|
309
|
+
yaml: 'yaml',
|
|
310
|
+
json: 'json',
|
|
311
|
+
xml: 'xml',
|
|
312
|
+
html: 'html',
|
|
313
|
+
css: 'css',
|
|
314
|
+
scss: 'scss',
|
|
315
|
+
less: 'less',
|
|
316
|
+
};
|
|
317
|
+
return extMap[ext || ''] || ext || 'text';
|
|
318
|
+
}
|
|
319
|
+
filterCustomMetadata(metadata) {
|
|
320
|
+
const standardKeys = ['overview', 'goals', 'requirements', 'source_format'];
|
|
321
|
+
const custom = {};
|
|
322
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
323
|
+
if (!standardKeys.includes(key)) {
|
|
324
|
+
custom[key] = value;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return custom;
|
|
328
|
+
}
|
|
329
|
+
convertChangesToSteps(changes) {
|
|
330
|
+
const steps = [];
|
|
331
|
+
const pathDependencies = new Map();
|
|
332
|
+
for (let i = 0; i < changes.length; i++) {
|
|
333
|
+
const change = changes[i];
|
|
334
|
+
const deps = [];
|
|
335
|
+
if (change.path) {
|
|
336
|
+
const previousIndex = pathDependencies.get(change.path);
|
|
337
|
+
if (previousIndex !== undefined) {
|
|
338
|
+
deps.push(`Step ${previousIndex + 1}`);
|
|
339
|
+
}
|
|
340
|
+
pathDependencies.set(change.path, i);
|
|
341
|
+
}
|
|
342
|
+
steps.push({
|
|
343
|
+
title: change.description,
|
|
344
|
+
details: change.path ? `Target: ${change.path}` : '',
|
|
345
|
+
dependencies: deps,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return steps;
|
|
349
|
+
}
|
|
350
|
+
convertChangesToTasks(changes) {
|
|
351
|
+
const tasks = [];
|
|
352
|
+
for (const change of changes) {
|
|
353
|
+
const task = {
|
|
354
|
+
description: change.description,
|
|
355
|
+
completed: false,
|
|
356
|
+
subtasks: [],
|
|
357
|
+
};
|
|
358
|
+
if (change.type === 'file_create' || change.type === 'file_update') {
|
|
359
|
+
task.subtasks.push({
|
|
360
|
+
description: `Edit ${change.path || 'file'}`,
|
|
361
|
+
completed: false,
|
|
362
|
+
});
|
|
363
|
+
if (this.config.preserveMetadata) {
|
|
364
|
+
task.subtasks.push({
|
|
365
|
+
description: 'Add file metadata',
|
|
366
|
+
completed: false,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (change.type.startsWith('dependency_')) {
|
|
371
|
+
task.subtasks.push({
|
|
372
|
+
description: 'Update package manifest',
|
|
373
|
+
completed: false,
|
|
374
|
+
});
|
|
375
|
+
task.subtasks.push({
|
|
376
|
+
description: 'Run package manager',
|
|
377
|
+
completed: false,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
tasks.push(task);
|
|
381
|
+
}
|
|
382
|
+
return tasks;
|
|
383
|
+
}
|
|
384
|
+
}
|