@specsafe/core 0.5.0 → 0.6.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/dist/elicitation/engine.d.ts +75 -0
- package/dist/elicitation/engine.d.ts.map +1 -0
- package/dist/elicitation/engine.js +174 -0
- package/dist/elicitation/engine.js.map +1 -0
- package/dist/elicitation/flows.d.ts +18 -0
- package/dist/elicitation/flows.d.ts.map +1 -0
- package/dist/elicitation/flows.js +331 -0
- package/dist/elicitation/flows.js.map +1 -0
- package/dist/elicitation/generator.d.ts +20 -0
- package/dist/elicitation/generator.d.ts.map +1 -0
- package/dist/elicitation/generator.js +260 -0
- package/dist/elicitation/generator.js.map +1 -0
- package/dist/elicitation/index.d.ts +27 -0
- package/dist/elicitation/index.d.ts.map +1 -0
- package/dist/elicitation/index.js +29 -0
- package/dist/elicitation/index.js.map +1 -0
- package/dist/elicitation/types.d.ts +69 -0
- package/dist/elicitation/types.d.ts.map +1 -0
- package/dist/elicitation/types.js +6 -0
- package/dist/elicitation/types.js.map +1 -0
- package/dist/extensions/builtins/complexity.d.ts +7 -0
- package/dist/extensions/builtins/complexity.d.ts.map +1 -0
- package/dist/extensions/builtins/complexity.js +97 -0
- package/dist/extensions/builtins/complexity.js.map +1 -0
- package/dist/extensions/builtins/owasp.d.ts +7 -0
- package/dist/extensions/builtins/owasp.d.ts.map +1 -0
- package/dist/extensions/builtins/owasp.js +76 -0
- package/dist/extensions/builtins/owasp.js.map +1 -0
- package/dist/extensions/index.d.ts +54 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +72 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/loader.d.ts +28 -0
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/extensions/loader.js +62 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/extensions/registry.d.ts +74 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/extensions/registry.js +159 -0
- package/dist/extensions/registry.js.map +1 -0
- package/dist/extensions/types.d.ts +70 -0
- package/dist/extensions/types.d.ts.map +1 -0
- package/dist/extensions/types.js +2 -0
- package/dist/extensions/types.js.map +1 -0
- package/dist/governance/builtins.d.ts +7 -0
- package/dist/governance/builtins.d.ts.map +1 -0
- package/dist/governance/builtins.js +105 -0
- package/dist/governance/builtins.js.map +1 -0
- package/dist/governance/constitution.d.ts +23 -0
- package/dist/governance/constitution.d.ts.map +1 -0
- package/dist/governance/constitution.js +245 -0
- package/dist/governance/constitution.js.map +1 -0
- package/dist/governance/index.d.ts +3 -0
- package/dist/governance/index.d.ts.map +1 -0
- package/dist/governance/index.js +2 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/governance/template.d.ts +12 -0
- package/dist/governance/template.d.ts.map +1 -0
- package/dist/governance/template.js +84 -0
- package/dist/governance/template.js.map +1 -0
- package/dist/governance/types.d.ts +64 -0
- package/dist/governance/types.d.ts.map +1 -0
- package/dist/governance/types.js +2 -0
- package/dist/governance/types.js.map +1 -0
- package/dist/index.d.ts +15 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -18
- package/dist/index.js.map +1 -1
- package/dist/templates/checklist.d.ts +7 -0
- package/dist/templates/checklist.d.ts.map +1 -0
- package/dist/templates/checklist.js +131 -0
- package/dist/templates/checklist.js.map +1 -0
- package/dist/templates/engine.d.ts +20 -0
- package/dist/templates/engine.d.ts.map +1 -0
- package/dist/templates/engine.js +187 -0
- package/dist/templates/engine.js.map +1 -0
- package/dist/templates/types.d.ts +67 -0
- package/dist/templates/types.d.ts.map +1 -0
- package/dist/templates/types.js +5 -0
- package/dist/templates/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specification Generator
|
|
3
|
+
* Converts elicitation results into SpecSafe-formatted markdown specs
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate a SpecSafe-formatted specification from elicitation results
|
|
7
|
+
*
|
|
8
|
+
* @param result The completed elicitation result
|
|
9
|
+
* @returns Markdown-formatted specification
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const result = engine.getResult();
|
|
14
|
+
* const spec = generateSpec(result);
|
|
15
|
+
* await writeFile('specs/SPEC-001.md', spec);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function generateSpec(result) {
|
|
19
|
+
const { flowId, answers } = result;
|
|
20
|
+
switch (flowId) {
|
|
21
|
+
case 'quick':
|
|
22
|
+
return generateQuickSpec(answers);
|
|
23
|
+
case 'full':
|
|
24
|
+
return generateFullSpec(answers);
|
|
25
|
+
case 'ears':
|
|
26
|
+
return generateEARSSpec(answers);
|
|
27
|
+
default:
|
|
28
|
+
throw new Error(`Unknown flow ID: ${flowId}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate spec from quick flow
|
|
33
|
+
*/
|
|
34
|
+
function generateQuickSpec(answers) {
|
|
35
|
+
const specId = generateSpecId();
|
|
36
|
+
const date = new Date().toISOString().split('T')[0];
|
|
37
|
+
const requirementsValue = answers.requirements;
|
|
38
|
+
if (typeof requirementsValue !== 'string') {
|
|
39
|
+
throw new Error('Missing required field: requirements');
|
|
40
|
+
}
|
|
41
|
+
const requirements = requirementsValue
|
|
42
|
+
.split('\n')
|
|
43
|
+
.filter(line => line.trim().length > 0)
|
|
44
|
+
.map(req => `- ${req.trim()}`)
|
|
45
|
+
.join('\n');
|
|
46
|
+
return `# ${answers.name}
|
|
47
|
+
|
|
48
|
+
## Metadata
|
|
49
|
+
- **Spec ID**: ${specId}
|
|
50
|
+
- **Created**: ${date}
|
|
51
|
+
- **Type**: ${answers.type}
|
|
52
|
+
- **Priority**: ${answers.priority}
|
|
53
|
+
- **Status**: draft
|
|
54
|
+
|
|
55
|
+
## Description
|
|
56
|
+
|
|
57
|
+
${answers.description}
|
|
58
|
+
|
|
59
|
+
## Requirements
|
|
60
|
+
|
|
61
|
+
${requirements}
|
|
62
|
+
|
|
63
|
+
## Testing Strategy
|
|
64
|
+
|
|
65
|
+
- [ ] Unit tests for core functionality
|
|
66
|
+
- [ ] Integration tests for workflows
|
|
67
|
+
- [ ] End-to-end tests for user scenarios
|
|
68
|
+
|
|
69
|
+
## Acceptance Criteria
|
|
70
|
+
|
|
71
|
+
- All requirements implemented
|
|
72
|
+
- All tests passing
|
|
73
|
+
- Code reviewed and approved
|
|
74
|
+
|
|
75
|
+
## Notes
|
|
76
|
+
|
|
77
|
+
Created via SpecSafe quick flow elicitation.
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate spec from full flow
|
|
82
|
+
*/
|
|
83
|
+
function generateFullSpec(answers) {
|
|
84
|
+
const specId = generateSpecId();
|
|
85
|
+
const date = new Date().toISOString().split('T')[0];
|
|
86
|
+
const requirementsValue = answers.requirements;
|
|
87
|
+
if (typeof requirementsValue !== 'string') {
|
|
88
|
+
throw new Error('Missing required field: requirements');
|
|
89
|
+
}
|
|
90
|
+
const requirements = requirementsValue
|
|
91
|
+
.split('\n')
|
|
92
|
+
.filter(line => line.trim().length > 0)
|
|
93
|
+
.map(req => `- ${req.trim()}`)
|
|
94
|
+
.join('\n');
|
|
95
|
+
let spec = `# ${answers.name}
|
|
96
|
+
|
|
97
|
+
## Metadata
|
|
98
|
+
- **Spec ID**: ${specId}
|
|
99
|
+
- **Created**: ${date}
|
|
100
|
+
- **Type**: ${answers.type}
|
|
101
|
+
- **Priority**: ${answers.priority}
|
|
102
|
+
- **Status**: draft
|
|
103
|
+
|
|
104
|
+
## Description
|
|
105
|
+
|
|
106
|
+
${answers.description}
|
|
107
|
+
`;
|
|
108
|
+
if (answers.scope) {
|
|
109
|
+
spec += `\n## Scope\n\n${answers.scope}\n`;
|
|
110
|
+
}
|
|
111
|
+
if (answers.stakeholders) {
|
|
112
|
+
const stakeholdersValue = answers.stakeholders;
|
|
113
|
+
if (typeof stakeholdersValue === 'string') {
|
|
114
|
+
const stakeholderList = stakeholdersValue
|
|
115
|
+
.split(',')
|
|
116
|
+
.map(s => `- ${s.trim()}`)
|
|
117
|
+
.join('\n');
|
|
118
|
+
spec += `\n## Stakeholders\n\n${stakeholderList}\n`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
spec += `\n## Requirements\n\n${requirements}\n`;
|
|
122
|
+
if (answers.has_security && answers.security_considerations) {
|
|
123
|
+
spec += `\n## Security Considerations\n\n${answers.security_considerations}\n`;
|
|
124
|
+
}
|
|
125
|
+
spec += `\n## Testing Strategy\n\n${answers.testing_strategy}\n`;
|
|
126
|
+
if (answers.has_performance && answers.performance_requirements) {
|
|
127
|
+
spec += `\n## Performance Requirements\n\n${answers.performance_requirements}\n`;
|
|
128
|
+
}
|
|
129
|
+
if (answers.dependencies) {
|
|
130
|
+
const dependenciesValue = answers.dependencies;
|
|
131
|
+
if (typeof dependenciesValue === 'string') {
|
|
132
|
+
const depList = dependenciesValue
|
|
133
|
+
.split('\n')
|
|
134
|
+
.filter(line => line.trim().length > 0)
|
|
135
|
+
.map(dep => `- ${dep.trim()}`)
|
|
136
|
+
.join('\n');
|
|
137
|
+
spec += `\n## Dependencies\n\n${depList}\n`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (answers.timeline) {
|
|
141
|
+
spec += `\n## Timeline\n\n${answers.timeline}\n`;
|
|
142
|
+
}
|
|
143
|
+
if (answers.risks) {
|
|
144
|
+
const risksValue = answers.risks;
|
|
145
|
+
if (typeof risksValue === 'string') {
|
|
146
|
+
const riskList = risksValue
|
|
147
|
+
.split('\n')
|
|
148
|
+
.filter(line => line.trim().length > 0)
|
|
149
|
+
.map(risk => `- ${risk.trim()}`)
|
|
150
|
+
.join('\n');
|
|
151
|
+
spec += `\n## Risks\n\n${riskList}\n`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
spec += `\n## Acceptance Criteria\n\n${answers.acceptance_criteria}\n`;
|
|
155
|
+
if (answers.notes) {
|
|
156
|
+
spec += `\n## Notes\n\n${answers.notes}\n`;
|
|
157
|
+
}
|
|
158
|
+
spec += `\n---\n\nCreated via SpecSafe full flow elicitation.\n`;
|
|
159
|
+
return spec;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate spec from EARS flow
|
|
163
|
+
*/
|
|
164
|
+
function generateEARSSpec(answers) {
|
|
165
|
+
const specId = generateSpecId();
|
|
166
|
+
const date = new Date().toISOString().split('T')[0];
|
|
167
|
+
const reqCountValue = answers.req_count;
|
|
168
|
+
if (typeof reqCountValue !== 'string') {
|
|
169
|
+
throw new Error('Missing required field: req_count');
|
|
170
|
+
}
|
|
171
|
+
const reqCount = parseInt(reqCountValue, 10);
|
|
172
|
+
if (isNaN(reqCount) || reqCount < 1) {
|
|
173
|
+
throw new Error('Invalid req_count value');
|
|
174
|
+
}
|
|
175
|
+
let spec = `# ${answers.name}
|
|
176
|
+
|
|
177
|
+
## Metadata
|
|
178
|
+
- **Spec ID**: ${specId}
|
|
179
|
+
- **Created**: ${date}
|
|
180
|
+
- **Type**: feature
|
|
181
|
+
- **Format**: EARS
|
|
182
|
+
- **Status**: draft
|
|
183
|
+
|
|
184
|
+
## Description
|
|
185
|
+
|
|
186
|
+
${answers.description}
|
|
187
|
+
|
|
188
|
+
## Requirements (EARS Format)
|
|
189
|
+
|
|
190
|
+
`;
|
|
191
|
+
for (let i = 1; i <= reqCount; i++) {
|
|
192
|
+
const typeKey = `req_${i}_type`;
|
|
193
|
+
const triggerKey = `req_${i}_trigger`;
|
|
194
|
+
const preconditionKey = `req_${i}_precondition`;
|
|
195
|
+
const responseKey = `req_${i}_response`;
|
|
196
|
+
const type = answers[typeKey];
|
|
197
|
+
const response = answers[responseKey];
|
|
198
|
+
if (!response || typeof response !== 'string')
|
|
199
|
+
continue;
|
|
200
|
+
spec += `### REQ-${i.toString().padStart(3, '0')}\n\n`;
|
|
201
|
+
switch (type) {
|
|
202
|
+
case 'ubiquitous':
|
|
203
|
+
spec += `**Type**: Ubiquitous\n\n`;
|
|
204
|
+
spec += `The system shall ${response}\n\n`;
|
|
205
|
+
break;
|
|
206
|
+
case 'event': {
|
|
207
|
+
const trigger = answers[triggerKey];
|
|
208
|
+
spec += `**Type**: Event-driven\n\n`;
|
|
209
|
+
spec += `WHEN ${trigger}, the system shall ${response}\n\n`;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case 'state': {
|
|
213
|
+
const statePrecondition = answers[preconditionKey];
|
|
214
|
+
spec += `**Type**: State-driven\n\n`;
|
|
215
|
+
spec += `WHILE ${statePrecondition}, the system shall ${response}\n\n`;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case 'optional': {
|
|
219
|
+
const optionalPrecondition = answers[preconditionKey];
|
|
220
|
+
spec += `**Type**: Optional\n\n`;
|
|
221
|
+
spec += `WHERE ${optionalPrecondition}, the system shall ${response}\n\n`;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case 'unwanted':
|
|
225
|
+
spec += `**Type**: Unwanted behavior\n\n`;
|
|
226
|
+
spec += `IF [unwanted condition], then the system shall ${response}\n\n`;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
spec += `## Testing Strategy
|
|
231
|
+
|
|
232
|
+
- [ ] Validate each EARS requirement with specific test cases
|
|
233
|
+
- [ ] Test trigger conditions for event-driven requirements
|
|
234
|
+
- [ ] Test state conditions for state-driven requirements
|
|
235
|
+
- [ ] Verify optional requirements under specified conditions
|
|
236
|
+
|
|
237
|
+
## Acceptance Criteria
|
|
238
|
+
|
|
239
|
+
- All EARS requirements implemented and tested
|
|
240
|
+
- Requirements follow EARS syntax properly
|
|
241
|
+
- All tests passing with >80% coverage
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
Created via SpecSafe EARS flow elicitation.
|
|
246
|
+
`;
|
|
247
|
+
return spec;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Generate a unique spec ID
|
|
251
|
+
*/
|
|
252
|
+
function generateSpecId() {
|
|
253
|
+
const date = new Date();
|
|
254
|
+
const year = date.getFullYear();
|
|
255
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
256
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
257
|
+
const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
|
|
258
|
+
return `SPEC-${year}${month}${day}-${random}`;
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/elicitation/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elicitation System
|
|
3
|
+
*
|
|
4
|
+
* Interactive specification elicitation workflows for SpecSafe.
|
|
5
|
+
* Guides users through structured question flows to create well-formed specs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ElicitationEngine, quickFlow, generateSpec } from '@specsafe/core';
|
|
10
|
+
*
|
|
11
|
+
* const engine = new ElicitationEngine(quickFlow);
|
|
12
|
+
* let step = engine.start();
|
|
13
|
+
*
|
|
14
|
+
* while (step) {
|
|
15
|
+
* const answer = await promptUser(step);
|
|
16
|
+
* step = engine.answer(step.id, answer);
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const result = engine.getResult();
|
|
20
|
+
* const spec = generateSpec(result);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export type { StepType, ValidateFn, ConditionFn, ElicitationStep, ElicitationFlow, ElicitationResult, } from './types.js';
|
|
24
|
+
export { ElicitationEngine } from './engine.js';
|
|
25
|
+
export { quickFlow, fullFlow, earsFlow } from './flows.js';
|
|
26
|
+
export { generateSpec } from './generator.js';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/elicitation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,YAAY,EACV,QAAQ,EACR,UAAU,EACV,WAAW,EACX,eAAe,EACf,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elicitation System
|
|
3
|
+
*
|
|
4
|
+
* Interactive specification elicitation workflows for SpecSafe.
|
|
5
|
+
* Guides users through structured question flows to create well-formed specs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ElicitationEngine, quickFlow, generateSpec } from '@specsafe/core';
|
|
10
|
+
*
|
|
11
|
+
* const engine = new ElicitationEngine(quickFlow);
|
|
12
|
+
* let step = engine.start();
|
|
13
|
+
*
|
|
14
|
+
* while (step) {
|
|
15
|
+
* const answer = await promptUser(step);
|
|
16
|
+
* step = engine.answer(step.id, answer);
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const result = engine.getResult();
|
|
20
|
+
* const spec = generateSpec(result);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
// Export engine
|
|
24
|
+
export { ElicitationEngine } from './engine.js';
|
|
25
|
+
// Export built-in flows
|
|
26
|
+
export { quickFlow, fullFlow, earsFlow } from './flows.js';
|
|
27
|
+
// Export generator
|
|
28
|
+
export { generateSpec } from './generator.js';
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/elicitation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAYH,gBAAgB;AAChB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAwB;AACxB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3D,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elicitation System Types
|
|
3
|
+
* Defines interactive specification elicitation workflows
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Step types for elicitation flows
|
|
7
|
+
*/
|
|
8
|
+
export type StepType = 'text' | 'choice' | 'multi-choice' | 'confirm' | 'conditional';
|
|
9
|
+
/**
|
|
10
|
+
* Validation function for step answers
|
|
11
|
+
*/
|
|
12
|
+
export type ValidateFn = (value: any) => boolean | string;
|
|
13
|
+
/**
|
|
14
|
+
* Condition function to determine if step should be shown
|
|
15
|
+
*/
|
|
16
|
+
export type ConditionFn = (answers: Record<string, any>) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Individual step in an elicitation flow
|
|
19
|
+
*/
|
|
20
|
+
export interface ElicitationStep {
|
|
21
|
+
/** Unique step identifier */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Prompt text to display to user */
|
|
24
|
+
prompt: string;
|
|
25
|
+
/** Step type */
|
|
26
|
+
type: StepType;
|
|
27
|
+
/** Available choices (for choice/multi-choice types) */
|
|
28
|
+
choices?: string[];
|
|
29
|
+
/** Default value */
|
|
30
|
+
default?: any;
|
|
31
|
+
/** Whether this step is required */
|
|
32
|
+
required?: boolean;
|
|
33
|
+
/** Validation function */
|
|
34
|
+
validate?: ValidateFn;
|
|
35
|
+
/** Condition function to determine if step should be shown */
|
|
36
|
+
condition?: ConditionFn;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Complete elicitation flow definition
|
|
40
|
+
*/
|
|
41
|
+
export interface ElicitationFlow {
|
|
42
|
+
/** Unique flow identifier */
|
|
43
|
+
id: string;
|
|
44
|
+
/** Human-readable flow name */
|
|
45
|
+
name: string;
|
|
46
|
+
/** Flow description */
|
|
47
|
+
description: string;
|
|
48
|
+
/** Steps in the flow */
|
|
49
|
+
steps: ElicitationStep[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Result of completed elicitation flow
|
|
53
|
+
*/
|
|
54
|
+
export interface ElicitationResult {
|
|
55
|
+
/** ID of the flow that was completed */
|
|
56
|
+
flowId: string;
|
|
57
|
+
/** User answers keyed by step ID */
|
|
58
|
+
answers: Record<string, any>;
|
|
59
|
+
/** Metadata about the elicitation session */
|
|
60
|
+
metadata: {
|
|
61
|
+
/** When the elicitation started */
|
|
62
|
+
startedAt: Date;
|
|
63
|
+
/** When the elicitation completed */
|
|
64
|
+
completedAt: Date;
|
|
65
|
+
/** Step IDs that were skipped */
|
|
66
|
+
skipped: string[];
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/elicitation/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,QAAQ,GACR,cAAc,GACd,SAAS,GACT,aAAa,CAAC;AAElB;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,EAAE,EAAE,MAAM,CAAC;IAEX,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IAEf,gBAAgB;IAChB,IAAI,EAAE,QAAQ,CAAC;IAEf,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,GAAG,CAAC;IAEd,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,UAAU,CAAC;IAEtB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,EAAE,EAAE,MAAM,CAAC;IAEX,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IAEb,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IAEpB,wBAAwB;IACxB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IAEf,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE7B,6CAA6C;IAC7C,QAAQ,EAAE;QACR,mCAAmC;QACnC,SAAS,EAAE,IAAI,CAAC;QAEhB,qCAAqC;QACrC,WAAW,EAAE,IAAI,CAAC;QAElB,iCAAiC;QACjC,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/elicitation/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity.d.ts","sourceRoot":"","sources":["../../../src/extensions/builtins/complexity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAqC,MAAM,aAAa,CAAC;AAShF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAwGjC,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape special regex characters
|
|
3
|
+
*/
|
|
4
|
+
function escapeRegex(str) {
|
|
5
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Complexity Scorer Extension
|
|
9
|
+
* Analyzes spec complexity based on various factors
|
|
10
|
+
*/
|
|
11
|
+
export const complexityExtension = {
|
|
12
|
+
id: 'complexity-scorer',
|
|
13
|
+
name: 'Complexity Scorer',
|
|
14
|
+
description: 'Analyzes and scores spec complexity',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
author: 'SpecSafe Team',
|
|
17
|
+
enabled: true,
|
|
18
|
+
hooks: {
|
|
19
|
+
'post-validate': (context) => {
|
|
20
|
+
const { spec } = context;
|
|
21
|
+
const warnings = [];
|
|
22
|
+
const suggestions = [];
|
|
23
|
+
// Calculate complexity factors
|
|
24
|
+
const requirementCount = spec.requirements.length;
|
|
25
|
+
const scenarioCount = spec.requirements.reduce((sum, req) => sum + (req.scenarios?.length || 0), 0);
|
|
26
|
+
// Count integration points (mentions of external systems)
|
|
27
|
+
const descLower = spec.description.toLowerCase();
|
|
28
|
+
const integrationKeywords = ['api', 'service', 'integration', 'external', 'third-party', 'webhook'];
|
|
29
|
+
const integrationPoints = integrationKeywords.filter(keyword => new RegExp(`\\b${escapeRegex(keyword)}\\b`, 'i').test(descLower)).length;
|
|
30
|
+
// Count dependencies (mentions of other systems/modules)
|
|
31
|
+
const dependencyKeywords = ['depends', 'requires', 'dependency', 'module', 'component'];
|
|
32
|
+
const dependencies = dependencyKeywords.filter(keyword => new RegExp(`\\b${escapeRegex(keyword)}\\b`, 'i').test(descLower)).length;
|
|
33
|
+
// Calculate complexity score (0-100)
|
|
34
|
+
let complexityScore = 0;
|
|
35
|
+
// Requirements contribute up to 40 points
|
|
36
|
+
complexityScore += Math.min(requirementCount * 4, 40);
|
|
37
|
+
// Scenarios contribute up to 30 points
|
|
38
|
+
complexityScore += Math.min(scenarioCount * 2, 30);
|
|
39
|
+
// Integration points contribute up to 15 points
|
|
40
|
+
complexityScore += Math.min(integrationPoints * 5, 15);
|
|
41
|
+
// Dependencies contribute up to 15 points
|
|
42
|
+
complexityScore += Math.min(dependencies * 5, 15);
|
|
43
|
+
// Determine complexity level
|
|
44
|
+
let complexityLevel;
|
|
45
|
+
if (complexityScore < 25) {
|
|
46
|
+
complexityLevel = 'low';
|
|
47
|
+
}
|
|
48
|
+
else if (complexityScore < 50) {
|
|
49
|
+
complexityLevel = 'medium';
|
|
50
|
+
}
|
|
51
|
+
else if (complexityScore < 75) {
|
|
52
|
+
complexityLevel = 'high';
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
complexityLevel = 'very-high';
|
|
56
|
+
}
|
|
57
|
+
// Generate warnings and suggestions
|
|
58
|
+
if (requirementCount > 10) {
|
|
59
|
+
warnings.push(`High requirement count: ${requirementCount}`);
|
|
60
|
+
suggestions.push('Consider breaking this spec into smaller, focused specs');
|
|
61
|
+
}
|
|
62
|
+
if (scenarioCount > 20) {
|
|
63
|
+
warnings.push(`High scenario count: ${scenarioCount}`);
|
|
64
|
+
suggestions.push('Review if all scenarios are necessary or can be simplified');
|
|
65
|
+
}
|
|
66
|
+
if (integrationPoints > 3) {
|
|
67
|
+
warnings.push(`Many integration points detected: ${integrationPoints}`);
|
|
68
|
+
suggestions.push('Consider documenting integration architecture separately');
|
|
69
|
+
}
|
|
70
|
+
if (complexityLevel === 'very-high') {
|
|
71
|
+
warnings.push('Very high complexity detected');
|
|
72
|
+
suggestions.push('Break this spec into multiple smaller specs for better maintainability');
|
|
73
|
+
}
|
|
74
|
+
const message = `Complexity: ${complexityLevel} (score: ${complexityScore}/100)`;
|
|
75
|
+
const emoji = complexityLevel === 'low' ? '✓' :
|
|
76
|
+
complexityLevel === 'medium' ? '⚡' :
|
|
77
|
+
complexityLevel === 'high' ? '⚠️' : '🔴';
|
|
78
|
+
return {
|
|
79
|
+
success: complexityLevel !== 'very-high',
|
|
80
|
+
message: `${emoji} ${message}`,
|
|
81
|
+
warnings,
|
|
82
|
+
suggestions,
|
|
83
|
+
data: {
|
|
84
|
+
complexityScore,
|
|
85
|
+
complexityLevel,
|
|
86
|
+
metrics: {
|
|
87
|
+
requirementCount,
|
|
88
|
+
scenarioCount,
|
|
89
|
+
integrationPoints,
|
|
90
|
+
dependencies,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=complexity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity.js","sourceRoot":"","sources":["../../../src/extensions/builtins/complexity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owasp.d.ts","sourceRoot":"","sources":["../../../src/extensions/builtins/owasp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAqC,MAAM,aAAa,CAAC;AAEhF;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,SA6E5B,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OWASP Security Extension
|
|
3
|
+
* Checks specs for security requirements and flags missing considerations
|
|
4
|
+
*/
|
|
5
|
+
export const owaspExtension = {
|
|
6
|
+
id: 'owasp-security',
|
|
7
|
+
name: 'OWASP Security Checker',
|
|
8
|
+
description: 'Validates spec against OWASP security best practices',
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
author: 'SpecSafe Team',
|
|
11
|
+
enabled: true,
|
|
12
|
+
hooks: {
|
|
13
|
+
'post-validate': (context) => {
|
|
14
|
+
const { spec } = context;
|
|
15
|
+
const warnings = [];
|
|
16
|
+
const suggestions = [];
|
|
17
|
+
const errors = [];
|
|
18
|
+
// Convert spec description and requirements to lowercase for checking
|
|
19
|
+
const descLower = (spec.description || '').toLowerCase();
|
|
20
|
+
const reqTexts = Array.isArray(spec.requirements)
|
|
21
|
+
? spec.requirements.map(r => `${r.text || ''} ${(r.scenarios || []).map(s => s.when).join(' ')}`.toLowerCase())
|
|
22
|
+
: [];
|
|
23
|
+
const allText = [descLower, ...reqTexts].join(' ');
|
|
24
|
+
// Security keywords to check
|
|
25
|
+
const securityChecks = {
|
|
26
|
+
authentication: ['authentication', 'login', 'signin', 'auth'],
|
|
27
|
+
authorization: ['authorization', 'permission', 'access control', 'role'],
|
|
28
|
+
inputValidation: ['validation', 'sanitize', 'input', 'escape'],
|
|
29
|
+
encryption: ['encryption', 'encrypt', 'ssl', 'tls', 'https'],
|
|
30
|
+
dataProtection: ['data protection', 'privacy', 'gdpr', 'sensitive data'],
|
|
31
|
+
};
|
|
32
|
+
let foundCount = 0;
|
|
33
|
+
// Check for each security aspect
|
|
34
|
+
for (const [aspect, keywords] of Object.entries(securityChecks)) {
|
|
35
|
+
const found = keywords.some(keyword => allText.includes(keyword));
|
|
36
|
+
if (!found) {
|
|
37
|
+
warnings.push(`No mention of ${aspect} found`);
|
|
38
|
+
suggestions.push(`Consider adding ${aspect} requirements`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
foundCount++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Determine result
|
|
45
|
+
const totalChecks = Object.keys(securityChecks).length;
|
|
46
|
+
const coverage = (foundCount / totalChecks) * 100;
|
|
47
|
+
let message = `Security coverage: ${foundCount}/${totalChecks} aspects (${Math.round(coverage)}%)`;
|
|
48
|
+
let success = true;
|
|
49
|
+
if (foundCount === 0) {
|
|
50
|
+
errors.push('No security considerations found in spec');
|
|
51
|
+
message = '⚠️ Critical: No security requirements detected';
|
|
52
|
+
success = false;
|
|
53
|
+
}
|
|
54
|
+
else if (foundCount < 3) {
|
|
55
|
+
warnings.push('Low security coverage detected');
|
|
56
|
+
message = `⚠️ Warning: ${message}`;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
message = `✓ ${message}`;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success,
|
|
63
|
+
message,
|
|
64
|
+
warnings,
|
|
65
|
+
suggestions,
|
|
66
|
+
errors,
|
|
67
|
+
data: {
|
|
68
|
+
coverage,
|
|
69
|
+
foundCount,
|
|
70
|
+
totalChecks,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=owasp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owasp.js","sourceRoot":"","sources":["../../../src/extensions/builtins/owasp.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EAAE,sDAAsD;IACnE,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,IAAI;IACb,KAAK,EAAE;QACL,eAAe,EAAE,CAAC,OAAyB,EAAmB,EAAE;YAC9D,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;YACzB,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAa,EAAE,CAAC;YACjC,MAAM,MAAM,GAAa,EAAE,CAAC;YAE5B,sEAAsE;YACtE,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;gBAC/C,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CACxB,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,CAClF;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEnD,6BAA6B;YAC7B,MAAM,cAAc,GAAG;gBACrB,cAAc,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC;gBAC7D,aAAa,EAAE,CAAC,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,CAAC;gBACxE,eAAe,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC;gBAC9D,UAAU,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC;gBAC5D,cAAc,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC;aACzE,CAAC;YAEF,IAAI,UAAU,GAAG,CAAC,CAAC;YAEnB,iCAAiC;YACjC,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBAChE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClE,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,QAAQ,CAAC,IAAI,CAAC,iBAAiB,MAAM,QAAQ,CAAC,CAAC;oBAC/C,WAAW,CAAC,IAAI,CAAC,mBAAmB,MAAM,eAAe,CAAC,CAAC;gBAC7D,CAAC;qBAAM,CAAC;oBACN,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;YAED,mBAAmB;YACnB,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;YACvD,MAAM,QAAQ,GAAG,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC;YAElD,IAAI,OAAO,GAAG,sBAAsB,UAAU,IAAI,WAAW,aAAa,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YACnG,IAAI,OAAO,GAAG,IAAI,CAAC;YAEnB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;gBACxD,OAAO,GAAG,gDAAgD,CAAC;gBAC3D,OAAO,GAAG,KAAK,CAAC;YAClB,CAAC;iBAAM,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;gBAChD,OAAO,GAAG,eAAe,OAAO,EAAE,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,KAAK,OAAO,EAAE,CAAC;YAC3B,CAAC;YAED,OAAO;gBACL,OAAO;gBACP,OAAO;gBACP,QAAQ;gBACR,WAAW;gBACX,MAAM;gBACN,IAAI,EAAE;oBACJ,QAAQ;oBACR,UAAU;oBACV,WAAW;iBACZ;aACF,CAAC;QACJ,CAAC;KACF;CACF,CAAC"}
|